diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml deleted file mode 100644 index 660053a36..000000000 --- a/.github/workflows/create-release.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This is a basic workflow that is manually triggered - -name: Create Release - -# Controls when the action will run. Workflow runs when manually triggered using the UI -# or API. -on: - workflow_dispatch: - # Inputs the workflow accepts. - inputs: - release: - description: 'Release Version' - required: true - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - create_release: - # The type of runner that the job will run on - runs-on: ubuntu-latest - env: - GH_TOKEN: ${{ github.token }} - RELEASE: ${{ github.event.inputs.release || github.ref_name }} - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - with: - ref: gh-pages - - - name: Zip Release - uses: TheDoctor0/zip-release@0.7.0 - with: - filename: ui-grid-${{ env.RELEASE }}.zip - path: ./release/${{ env.RELEASE }}/* - - - name: Publish Release - run: gh release create v${{ env.RELEASE }} ./ui-grid-${{ env.RELEASE }}.zip - diff --git a/.gitignore b/.gitignore index de9383995..d8a17729a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.sublime-* \ No newline at end of file +*.sublime-* +node_modules \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..ed509de49 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +ui-grid.info diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 000000000..75a496104 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,59 @@ +/*global module:false*/ +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + shell: { + hexogen: { + command: 'hexo generate', + options: { + execOptions: { + cwd: '_blog_src' + } + } + } + }, + + stylus: { + compile: { + options: { + compress: true + }, + files: { + 'blog/css/style.css': '_blog_src/themes/casper_custom/source/css/style.styl' + } + } + }, + + connect: { + server: { + options: { + port: 4000, + base: '.', + livereload: true + } + } + }, + + watch: { + hexo: { + files: ['_blog_src/_config.yml', '_blog_src/themes/**', '_blog_src/scaffolds/**', '_blog_src/scripts/**', '_blog_src/source/**'], + tasks: ['shell:hexogen'] + }, + livereload: { + options: { livereload: true }, + files: ['blog/**'], + } + } + }); + + // These plugins provide necessary tasks. + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-stylus'); + grunt.loadNpmTasks('grunt-shell'); + + // Default task. + grunt.registerTask('dev', ['shell:hexogen', 'connect', 'watch']); + grunt.registerTask('default', ['shell:hexogen']); +}; diff --git a/README.md b/README.md index 55d15a3c1..67b21ce63 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ui-grid.info ============ -Website for ui-grid: http://ui-grid.info. +Website for ui-grid -The source code in gh-pages is created from https://github.com/angular-ui/ui-grid during the build process. The actual source is located on https://github.com/angular-ui/ui-grid so any issues should be raised in that repository. +[Using the blog system](_blog_src/Blogging.md) \ No newline at end of file diff --git a/_blog_src/.gitignore b/_blog_src/.gitignore new file mode 100644 index 000000000..a7640be62 --- /dev/null +++ b/_blog_src/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +Thumbs.db +db.json +debug.log +node_modules/ +public/ +.deploy/ \ No newline at end of file diff --git a/_blog_src/Blogging.md b/_blog_src/Blogging.md new file mode 100644 index 000000000..b415c6869 --- /dev/null +++ b/_blog_src/Blogging.md @@ -0,0 +1,27 @@ + +# UI-Grid.info Blog + +The "blog" uses [hexo](http://hexo.io) to generate a pretty simple static site. + +## Installing + +To use it you need to install hexo: + + npm install -g hexo@2.8.3 + +Then install dependencies in both the parent and _blog_src directories. This needs to be done bcause hexo's cwd needs to be the blog source directory. + + npm install + cd _blog_src + npm install + +Then go back up and run the dev task: + + cd .. + grund dev + +You'll get a server running on [http://localhost:4000](http://localhost:4000) with auto-watch on the blog directory to rebuild when you change files. + +## Creating Posts + +New posts can be created in `_blog_src/source/_posts` or by running `hexo new` in _blog_src. You can find further documentation on hexo's site: http://hexo.io \ No newline at end of file diff --git a/_blog_src/Gruntfile.js b/_blog_src/Gruntfile.js new file mode 100644 index 000000000..9a1a5447a --- /dev/null +++ b/_blog_src/Gruntfile.js @@ -0,0 +1,54 @@ +/*global module:false*/ +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + shell: { + hexogen: { + command: 'hexo generate' + } + }, + + stylus: { + compile: { + options: { + compress: true + }, + files: { + 'public/css/style.css': 'themes/landscape/source/css/style.styl' + } + } + }, + + connect: { + server: { + options: { + port: 4000, + base: 'public', + livereload: true + } + } + }, + + watch: { + hexo: { + files: ['_config.yml', 'themes/**', 'scaffolds/**', 'scripts/**', 'source/**'], + tasks: ['shell:hexogen'] + }, + livereload: { + options: { livereload: true }, + files: ['public/**'], + } + } + }); + + // These plugins provide necessary tasks. + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-stylus'); + grunt.loadNpmTasks('grunt-shell'); + + // Default task. + grunt.registerTask('dev', ['shell:hexogen', 'connect', 'watch']); + +}; diff --git a/_blog_src/_config.yml b/_blog_src/_config.yml new file mode 100644 index 000000000..c0e000a99 --- /dev/null +++ b/_blog_src/_config.yml @@ -0,0 +1,109 @@ +# Hexo Configuration +## Docs: http://hexo.io/docs/configuration.html +## Source: https://github.com/tommy351/hexo/ + +# Site +# UI-Grid Blog +title: UI Grid +subtitle: An AngularJS data grid +description: "Tips, tricks and news for UI Grid" +author: UI Grid Team +email: uigridteam@gmail.com +language: + +# URL +## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' +url: http://ui-grid.info/blog +root: /blog/ +permalink: :title/ +tag_dir: tags +archive_dir: archives +category_dir: categories +code_dir: downloads/code + +# Directory +source_dir: source +public_dir: ../blog + +# Writing +new_post_name: :title.md # File name of new posts +default_layout: post +auto_spacing: false # Add spaces between asian characters and western characters +titlecase: false # Transform title into titlecase +external_link: true # Open external links in new tab +max_open_file: 100 +multi_thread: true +filename_case: 0 +render_drafts: false +post_asset_folder: false +highlight: + enable: true + line_number: true + tab_replace: + +# Category & Tag +default_category: uncategorized +category_map: +tag_map: + +# Archives +## 2: Enable pagination +## 1: Disable pagination +## 0: Fully Disable +archive: 2 +category: 1 +tag: 1 + +# Server +## Hexo uses Connect as a server +## You can customize the logger format as defined in +## http://www.senchalabs.org/connect/logger.html +port: 4000 +server_ip: 0.0.0.0 +logger: false +logger_format: + +# Date / Time format +## Hexo uses Moment.js to parse and display date +## You can customize the date format as defined in +## http://momentjs.com/docs/#/displaying/format/ +date_format: MMM D YYYY +time_format: H:mm:ss + +# Pagination +## Set per_page to 0 to disable pagination +per_page: 10 +pagination_dir: page + +# Disqus +disqus_shortname: + +# Extensions +## Plugins: https://github.com/tommy351/hexo/wiki/Plugins +## Themes: https://github.com/tommy351/hexo/wiki/Themes +theme: casper_custom +exclude_generator: + +# Deployment +## Docs: http://hexo.io/docs/deployment.html +deploy: + type: + +sitemap: + path: ../sitemap.xml + +# casper theme config +cover: +logo: +bio: + +# Content +excerpt_link: Read More + +# Miscellaneous +rss: + +feed: + type: atom + path: atom.xml + limit: 20 diff --git a/_blog_src/package.json b/_blog_src/package.json new file mode 100644 index 000000000..b35b8ba1d --- /dev/null +++ b/_blog_src/package.json @@ -0,0 +1,12 @@ +{ + "name": "ui-grid.info.blog", + "version": "2.8.3", + "private": true, + "dependencies": { + "hexo-renderer-ejs": "*", + "hexo-renderer-stylus": "0.1.x", + "hexo-renderer-marked": "0.1.x", + "hexo-generator-cherrypick": "https://github.com/c0bra/hexo-generator-cherrypick/tarball/0.0.1", + "hexo-generator-feed": "^0.2.1" + } +} diff --git a/_blog_src/scaffolds/draft.md b/_blog_src/scaffolds/draft.md new file mode 100644 index 000000000..45b1bb754 --- /dev/null +++ b/_blog_src/scaffolds/draft.md @@ -0,0 +1,3 @@ +title: {{ title }} +tags: +--- diff --git a/_blog_src/scaffolds/page.md b/_blog_src/scaffolds/page.md new file mode 100644 index 000000000..f484b7615 --- /dev/null +++ b/_blog_src/scaffolds/page.md @@ -0,0 +1,3 @@ +title: {{ title }} +date: {{ date }} +--- diff --git a/_blog_src/scaffolds/photo.md b/_blog_src/scaffolds/photo.md new file mode 100644 index 000000000..5aba0db62 --- /dev/null +++ b/_blog_src/scaffolds/photo.md @@ -0,0 +1,5 @@ +layout: {{ layout }} +title: {{ title }} +date: {{ date }} +tags: +--- diff --git a/_blog_src/scaffolds/post.md b/_blog_src/scaffolds/post.md new file mode 100644 index 000000000..c590d7a77 --- /dev/null +++ b/_blog_src/scaffolds/post.md @@ -0,0 +1,4 @@ +title: {{ title }} +date: {{ date }} +tags: +--- diff --git a/_blog_src/source/_posts/6_ways_to_take_control_of_how_your_grid_data_is_displayed.md b/_blog_src/source/_posts/6_ways_to_take_control_of_how_your_grid_data_is_displayed.md new file mode 100644 index 000000000..add58ae69 --- /dev/null +++ b/_blog_src/source/_posts/6_ways_to_take_control_of_how_your_grid_data_is_displayed.md @@ -0,0 +1,132 @@ +author: Brian +title: 6 Ways to Take Control of How Your Grid Data is Displayed +date: 2015-02-27 10:55:01 +tags: + - customize + - display +--- + + + +Getting your data displayed just right can be a huge pain. + +You might just want to format some numbers, or you might want to embed something complex like a chart or custom directive. + +In this post outline six different methods you can use to get your data **just the way you want it**: + +* Bindings +* Cell Filters +* Cell Templates + * Links + * Buttons + * Custom directives + +## Bindings + +UI Grid columns can be bound to any sort of Angular expression, as well as property names that would normally break an expression: + +{% codeblock lang:js %} +var columnDefs = [ + { field: 'name' }, + { field: 'addresses[0]' }, + + /* + Yes, you can use hyphens, plus signs, etc. + + Normally something like {% raw %}{{ row.entity.first-name }}{% endraw %} would + bomb but UI Grid pre-processes your bindings to make sure they work correctly. + */ + { field: 'first-name' }, + + /* Function expressions work too */ + { field: 'getCurrency()' }, + { field: 'transformValue(row.entity.myField)' }, + + /* Plain old functions are also an option */ + { field: function () { return this.address.zip; } } +]; +{% endcodeblock %} + +## Cell Filters + +Cell filters can transform the displayed value for a column while leaving the model intact. In this plunker the amount column contains floating point values, but we only want to display the integer part. A simple cellFilter that uses `.toFixed()` will alter the displayed value the way we want. + +{% iframe http://embed.plnkr.co/BjLqXGiUI8nQFwvijduh/preview %} + +### Passing Arguments ### + +In the third column I am using two different fields. The column itself is bound to the same field as the second column, but on the filter I am passing the scope like so: `cellFilter: 'currencyFilter:this'`. Using the `this` argument on your filter will pass the scope. + +Then I can lookup the currency symbol I want using the currency field from the row. + +If you double-click a cell in the Currency column you'll see that the raw value is still available to be edited. Cell filters only change your displayed value! + +## Cell Templates ## + +Column definitions take a `cellTemplate` argument you can use to give your cells a custom template. You can specify it a few different ways, with a url (relative or absolute), an Angular template ID, a string/Angular element, or a promise. + +{% codeblock lang:js %} +var columnDefs = [ + { field: 'name', cellTemplate: 'name-template.html' }, + { field: 'name', cellTemplate: 'myTemplateId' }, + { field: 'name', cellTemplate: $.get('url-to-your-template.html') } +]; +{% endcodeblock %} + +### Bindings in Cell Templates ### + +There are a couple options for your binding your row's data in your template. You can access the `row` object which is in the local scope; `row.entity` will contain the reference to your object, so if you want the "name" field, you can bind like so: {{ row.entity.name }}. + +If you've *already* defined your binding in your column definition you can use one of UI Grid's placeholders: `{% raw %}{{ COL_FIELD }}{% endraw %}`. UI Grid will automatically replace COL_FIELD with the appropriate binding. If you need to two-way bind to your row, like when you're using the edit feature, you'll need to use the `MODEL_COL_FIELD` placeholder. + +{% codeblock lang:js %} +var columnDefs = [ + { + field: 'image_url', + cellTemplate: '
' + } +]; +{% endcodeblock %} + +### Links and Buttons ### + +Links are simple, just use regular old HTML. Wrapping your cell in an element using the class `.ui-grid-cell-contents` will apply the proper CSS settings like padding, overflow, etc., and make sure your cell fits in its space nicely. + +{% codeblock lang:js %} +var columnDefs = [ + { + field: 'email', + cellTemplate: '
Send E-Mail
' + } +]; +{% endcodeblock %} + +In the plunker below I'm using a basic cellTemplate to bind both the first and last name fields into one column. On the second column I'm using a simple link like above (note: none of these emails are real). + +On the third one, I'm using a template that's referenced in index.html. If you check the bottom of that file you'll see the template inside a ` + + + + +<% if (theme.google_analytics) { %> + +<% } %> +<% if (config.disqus_shortname){ %> + +<% } %> +<% if (theme.fancybox){ %> + + + +<% } %> + diff --git a/_blog_src/themes/casper_custom/layout/casper/footer.ejs b/_blog_src/themes/casper_custom/layout/casper/footer.ejs new file mode 100644 index 000000000..842f5d805 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/footer.ejs @@ -0,0 +1,9 @@ + + diff --git a/_blog_src/themes/casper_custom/layout/casper/head.ejs b/_blog_src/themes/casper_custom/layout/casper/head.ejs new file mode 100644 index 000000000..e62eb44f3 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/head.ejs @@ -0,0 +1,48 @@ +<% + var title = page.title; + + if (is_archive()){ + title = 'Archives'; + + if (is_month()){ + title += ': ' + page.year + '/' + page.month; + } else if (is_year()){ + title += ': ' + page.year; + } + } else if (is_category()){ + title = 'Category: ' + page.category; + } else if (is_tag()){ + title = 'Tag: ' + page.tag; + } +%> + + + + <% if (title){ %><%= title %> | <% } %><%= config.title %> + + + + + + + + + + + <% if (config.rss) { %> + + <% } %> + <% if (config.feed && config.feed.type == 'atom') { %> + + <% } %> + <% if (config.feed && config.feed.type == 'rss') { %> + + <% } %> + + <% if (config.cloudfrontanalytics) { %> + + <% } %> + diff --git a/_blog_src/themes/casper_custom/layout/casper/header.ejs b/_blog_src/themes/casper_custom/layout/casper/header.ejs new file mode 100644 index 000000000..558dc1c4d --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/header.ejs @@ -0,0 +1,9 @@ +
style="background-image: url(<%- theme.cover %>)" <% } %>> +
+
+ <% if (theme.logo) { %> <% } %> +

<%- config.title %>

+

<%- config.subtitle %>

+
+
+
\ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/casper/index.ejs b/_blog_src/themes/casper_custom/layout/casper/index.ejs new file mode 100644 index 000000000..ea70accb0 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/index.ejs @@ -0,0 +1,30 @@ + +
+ <% page.posts.each(function(post) { %> +
+
+ <%- partial('post/meta', {post: post}) %> +

<%- post.title %>

+
+
+

+ <% if (post.excerpt){ %> + <%- post.excerpt %> + <% } else { %> + <%- post.content.replace(/<(?:.|\n)*?>/gm, '').substr(0, 220) %> + <% } %> +

+ <% if (theme.excerpt_link) { %> +

+ <%= theme.excerpt_link %>... +

+ <% } %> +
+
+ <% }); %> + +
diff --git a/_blog_src/themes/casper_custom/layout/casper/post.ejs b/_blog_src/themes/casper_custom/layout/casper/post.ejs new file mode 100644 index 000000000..0c75d7937 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post.ejs @@ -0,0 +1,17 @@ + +<% permalink = config.url + config.root + post.path %> +
+
+ <%- partial('post/meta') %> +

<%- post.title %>

+
+ <%- post.content %> +
+ +
+ <%- partial('post/navigation') %> + <%- partial('post/comments') %> +
diff --git a/_blog_src/themes/casper_custom/layout/casper/post/author.ejs b/_blog_src/themes/casper_custom/layout/casper/post/author.ejs new file mode 100644 index 000000000..5fe2f0036 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post/author.ejs @@ -0,0 +1,4 @@ +
+

<%- post.author || config.author %>

+

<%- config.bio %>

+
\ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/casper/post/comments.ejs b/_blog_src/themes/casper_custom/layout/casper/post/comments.ejs new file mode 100644 index 000000000..9031e180d --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post/comments.ejs @@ -0,0 +1,8 @@ +<% if(config.disqus_shortname) { %> +
+

Comments

+
+ +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/casper/post/meta.ejs b/_blog_src/themes/casper_custom/layout/casper/post/meta.ejs new file mode 100644 index 000000000..be1843df4 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post/meta.ejs @@ -0,0 +1,11 @@ + + + <% if (post.tags && post.tags.length){ %> + <% count = post.tags.length %> + | <% post.tags.forEach(function(tag, index) { %> + <%= tag.name %><% if (count !== index+1) { %>,<% } %> + <% }); %> + <% } %> + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/casper/post/navigation.ejs b/_blog_src/themes/casper_custom/layout/casper/post/navigation.ejs new file mode 100644 index 000000000..697b571f1 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post/navigation.ejs @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/casper/post/share.ejs b/_blog_src/themes/casper_custom/layout/casper/post/share.ejs new file mode 100644 index 000000000..4cee062cd --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/casper/post/share.ejs @@ -0,0 +1,15 @@ +
+

Share this post

+ + + + + + + + + +
\ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/category.ejs b/_blog_src/themes/casper_custom/layout/category.ejs new file mode 100644 index 000000000..868de2063 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/category.ejs @@ -0,0 +1 @@ +<%- partial('casper/index') %> diff --git a/_blog_src/themes/casper_custom/layout/index.ejs b/_blog_src/themes/casper_custom/layout/index.ejs new file mode 100644 index 000000000..a5e689260 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/index.ejs @@ -0,0 +1 @@ +<%- partial('ui-grid/index') %> diff --git a/_blog_src/themes/casper_custom/layout/layout.ejs b/_blog_src/themes/casper_custom/layout/layout.ejs new file mode 100644 index 000000000..b85475677 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/layout.ejs @@ -0,0 +1,14 @@ + + +<%- partial('ui-grid/head') %> +<% if (typeof page.title == 'undefined') { %> + +<% } else { %> + +<% } %> + <%- partial('ui-grid/header') %> + <%- body %> + <%- partial('ui-grid/footer') %> + <%- partial('ui-grid/after_all') %> + + diff --git a/_blog_src/themes/casper_custom/layout/layout.ejs.bak b/_blog_src/themes/casper_custom/layout/layout.ejs.bak new file mode 100644 index 000000000..091004f21 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/layout.ejs.bak @@ -0,0 +1,14 @@ + + +<%- partial('casper/head') %> +<% if (typeof page.title == 'undefined') { %> + +<% } else { %> + +<% } %> + <%- partial('casper/header') %> + <%- body %> + <%- partial('casper/footer') %> + <%- partial('casper/after_all') %> + + diff --git a/_blog_src/themes/casper_custom/layout/page.ejs b/_blog_src/themes/casper_custom/layout/page.ejs new file mode 100644 index 000000000..12b341f38 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/page.ejs @@ -0,0 +1 @@ +<%- partial('casper/post', {post: page}) %> diff --git a/_blog_src/themes/casper_custom/layout/post.ejs b/_blog_src/themes/casper_custom/layout/post.ejs new file mode 100644 index 000000000..8d5c1dd97 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/post.ejs @@ -0,0 +1 @@ +<%- partial('ui-grid/post', {post: page}) %> diff --git a/_blog_src/themes/casper_custom/layout/tag.ejs b/_blog_src/themes/casper_custom/layout/tag.ejs new file mode 100644 index 000000000..868de2063 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/tag.ejs @@ -0,0 +1 @@ +<%- partial('casper/index') %> diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/after_all.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/after_all.ejs new file mode 100644 index 000000000..1b34b1360 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/after_all.ejs @@ -0,0 +1,63 @@ + + + + + + + + + + +<% if (theme.google_analytics) { %> + +<% } %> +<% if (config.disqus_shortname){ %> + +<% } %> +<% if (theme.fancybox){ %> + + + +<% } %> + diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/footer.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/footer.ejs new file mode 100644 index 000000000..7bfcc2eb6 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/footer.ejs @@ -0,0 +1,33 @@ +
+ + + + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/head.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/head.ejs new file mode 100644 index 000000000..7f74e805e --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/head.ejs @@ -0,0 +1,48 @@ +<% + var title = page.title; + + if (is_archive()){ + title = 'Archives'; + + if (is_month()){ + title += ': ' + page.year + '/' + page.month; + } else if (is_year()){ + title += ': ' + page.year; + } + } else if (is_category()){ + title = 'Category: ' + page.category; + } else if (is_tag()){ + title = 'Tag: ' + page.tag; + } +%> + + + + + + + + + <% if (title){ %><%= title %> | <% } %><%= config.title %> + + + + + + + + + + + + + <% if (config.rss) { %> + + <% } %> + <% if (config.feed && config.feed.type == 'atom') { %> + + <% } %> + <% if (config.feed && config.feed.type == 'rss') { %> + + <% } %> + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/header.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/header.ejs new file mode 100644 index 000000000..ffdbf8949 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/header.ejs @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/index.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/index.ejs new file mode 100644 index 000000000..a28b597f3 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/index.ejs @@ -0,0 +1,63 @@ +
+
+
Posts
+
+ + +
+
+ + <% page.posts.each(function(post) { %> + <% author = post.author || config.author %> +
+
+
+ <%- partial('post/meta', {post: post}) %> +

<%- post.title %>

+
+
+

+ <% if (post.excerpt){ %> + <%- post.excerpt %> + <% } else { %> + <%- truncate(post.content, { length: 220, separator: ' '}) %> + <% } %> +

+

+ <% if (author) { %> + Posted by <%= author %> on <%= post.date.format('MMMM Do YYYY') %> + <% } %> + <% if (theme.excerpt_link) { %> + + <% } %> +

+
+
+
+ +
+
+ + <% }); %> + + +
+ + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post.ejs new file mode 100644 index 000000000..9759fa1d3 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post.ejs @@ -0,0 +1,31 @@ + +<% permalink = config.url + config.root + post.path %> +<% author = post.author || config.author %> + +
+
+
+
+ <%- partial('post/meta') %> +

<%- post.title %>

+ +
+ +
+ <%- post.content %> + + <% if (page.mailchimp_tag) { %> + <%- partial('post/mailchimp') %> + <% } %> +
+ + +
+
+
+ <%- partial('post/navigation') %> + <%- partial('post/comments') %> +
diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/author.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/author.ejs new file mode 100644 index 000000000..db7a62116 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/author.ejs @@ -0,0 +1,4 @@ +
+

<%- post.author || config.author %>

+

<%- post.bio || config.bio %>

+
\ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/comments.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/comments.ejs new file mode 100644 index 000000000..9031e180d --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/comments.ejs @@ -0,0 +1,8 @@ +<% if(config.disqus_shortname) { %> +
+

Comments

+
+ +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/mailchimp.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/mailchimp.ejs new file mode 100644 index 000000000..1470c5314 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/mailchimp.ejs @@ -0,0 +1,22 @@ + + + +<% mailchimp_title = page.mailchimp_title || 'Enter your email address to sign up:' %> + +
+
+
+ +
+ + + + +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/meta.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/meta.ejs new file mode 100644 index 000000000..2b757d375 --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/meta.ejs @@ -0,0 +1,20 @@ +<% if (is_post()) { %> + + + + <% if (false && post.tags && post.tags.length){ %> + <% count = post.tags.length %> + | <% post.tags.forEach(function(tag, index) { %> + <%= tag.name %><% if (count !== index+1) { %>,<% } %> + <% }); %> + <% } %> + + + + + Back to main page + + +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/navigation.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/navigation.ejs new file mode 100644 index 000000000..3994aa97f --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/navigation.ejs @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/layout/ui-grid/post/share.ejs b/_blog_src/themes/casper_custom/layout/ui-grid/post/share.ejs new file mode 100644 index 000000000..167063e8b --- /dev/null +++ b/_blog_src/themes/casper_custom/layout/ui-grid/post/share.ejs @@ -0,0 +1,15 @@ +
+

Share this post

+ + + + + + + + + +
\ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/css/normalize.css b/_blog_src/themes/casper_custom/source/css/normalize.css new file mode 100644 index 000000000..562891ab8 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/css/normalize.css @@ -0,0 +1,406 @@ +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined in IE 8/9. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +/** + * Correct `inline-block` display not defined in IE 8/9. + */ + +audio, +canvas, +video { + display: inline-block; +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9. + * Hide the `template` element in IE, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background: transparent; +} + +/** + * Address `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari 5, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Correct font family set oddly in Safari 5 and Chrome. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +/** + * Improve readability of pre-formatted text in all browsers. + */ + +pre { + white-space: pre-wrap; +} + +/** + * Set consistent quote types. + */ + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9. + */ + +img { + border: 0; +} + +/** + * Correct overflow displayed oddly in IE 9. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari 5. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Correct font family not being inherited in all browsers. + * 2. Correct font size not being inherited in all browsers. + * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + */ + +button, +input, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * 1. Remove default vertical scrollbar in IE 8/9. + * 2. Improve readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/css/screen.css b/_blog_src/themes/casper_custom/source/css/screen.css new file mode 100644 index 000000000..8968be558 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/css/screen.css @@ -0,0 +1,1135 @@ +/* ========================================================================== + Table of Contents + ========================================================================== */ + +/* + + 0. Includes + 1. Icons + 2. General + 3. Utilities + 4. General + 5. Single Post + 6. Third Party Elements + 7. Pagination + 8. Footer + 9. Media Queries (Tablet) + 10. Media Queries (Mobile) + + */ + +/* ========================================================================== + 0. Includes - Ground zero + ========================================================================== */ + +@import url(normalize.css); + + +/* ========================================================================== + 1. Icons - Sets up the icon font and respective classes + ========================================================================== */ + +/* Import the font file with the icons in it */ +@font-face { + font-family: 'icons'; + src:url('../fonts/icons.eot'); + src:url('../fonts/icons.eot?#iefix') format('embedded-opentype'), + url('../fonts/icons.woff') format('woff'), + url('../fonts/icons.ttf') format('truetype'), + url('../fonts/icons.svg#icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +/* Apply these base styles to all icons */ +.icon-ghost:before, +.icon-feed:before, +.icon-twitter:before, +.icon-google-plus:before, +.icon-facebook:before { + font-family: 'icons'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + text-decoration: none; +} + +/* Each icon is created by inserting the corret character into the + content of the :before pseudo element. Like a boss. */ +.icon-ghost:before { + content: "\e000"; +} +.icon-feed:before { + content: "\e001"; +} +.icon-twitter:before { + content: "\e002"; + font-size: 1.1em; +} +.icon-google-plus:before { + content: "\e003"; +} +.icon-facebook:before { + content: "\e004"; +} + + +/* ========================================================================== + 2. General - Setting up some base styles + ========================================================================== */ + +html { + height: 100%; + max-height: 100%; + font-size: 62.5%; +} + +body { + height: 100%; + max-height: 100%; + font-family: 'Noto Serif', serif; + font-size: 2.0rem; + line-height: 1.6em; + color: #3A4145; +} + +::-moz-selection { + color: #222; + background: #D6EDFF; + text-shadow: none; +} + +::selection { + color: #222; + background: #D6EDFF; + text-shadow: none; +} + +h1, h2, h3, +h4, h5, h6 { + text-rendering: optimizeLegibility; + line-height: 1; + margin-top: 0; + font-family: 'Open Sans', sans-serif; +} + +h1 { + font-size: 5rem; + line-height: 1.2em; + letter-spacing: -2px; + text-indent: -3px; +} + +h2 { + font-size: 4rem; + line-height: 1.2em; + letter-spacing: -1px; + text-indent: -2px; +} + +h3 { + font-size: 3.5rem; +} + +h4 { + font-size: 3rem; +} + +h5 { + font-size: 2.5rem; +} + +h6 { + font-size: 2rem; +} + +a { + color: #4a4a4a; + transition: color ease 0.3s; +} + +a:hover { + color: #57A3E8; +} + +h1 a, h2 a, h3 a, +h4 a, h5 a, h6 a { + color: #50585D; +} + + +p, ul, ol, dl { + margin: 1.6em 0; +} + +ol ol, ul ul, +ul ol, ol ul { + margin: 0.4em 0; +} + +dl dt { + float: left; + width: 180px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: bold; + margin-bottom: 1em +} + +dl dd { + margin-left: 200px; + margin-bottom: 1em +} + +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #efefef; + margin: 3.2em 0; + padding: 0; +} + +blockquote { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0 1.6em -2.2em; + padding: 0 0 0 1.6em; + border-left: #4a4a4a 0.4em solid; +} + +blockquote p { + margin: 0.8em 0; + font-style: italic; +} + +blockquote small { + display: inline-block; + margin: 0.8em 0 0.8em 1.5em; + font-size:0.9em; + color: #ccc; +} + +blockquote small:before { content: '\2014 \00A0'; } + +blockquote cite { + font-weight:bold; +} + +blockquote cite a { font-weight: normal; } + +mark { + background-color: #ffc336; +} + +code, tt { + padding: 1px 3px; + font-family: Inconsolata, monospace, sans-serif; + font-size: 0.85em; + white-space: pre-wrap; + border: 1px solid #E3EDF3; + background: #F7FAFB; + border-radius: 2px; +} + +pre { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0; + border: 1px solid #E3EDF3; + width: 100%; + padding: 10px; + font-family: Inconsolata, monospace, sans-serif; + font-size: 0.9em; + white-space: pre; + overflow: auto; + background: #F7FAFB; + border-radius: 3px; +} + +pre code, tt { + font-size: inherit; + white-space: -moz-pre-wrap; + white-space: pre-wrap; + background: transparent; + border: none; + padding: 0; +} + +kbd { + display: inline-block; + margin-bottom: 0.4em; + padding: 1px 8px; + border: #ccc 1px solid; + color: #666; + text-shadow: #fff 0 1px 0; + font-size: 0.9em; + font-weight: bold; + background: #f4f4f4; + border-radius: 4px; + box-shadow: + 0 1px 0 rgba(0, 0, 0, 0.2), + 0 1px 0 0 #fff inset; +} + +table { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0; + width:100%; + max-width: 100%; + background-color: transparent; +} + +table th, +table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #efefef; +} + +table th { color: #000; } + +table caption + thead tr:first-child th, +table caption + thead tr:first-child td, +table colgroup + thead tr:first-child th, +table colgroup + thead tr:first-child td, +table thead:first-child tr:first-child th, +table thead:first-child tr:first-child td { + border-top: 0; +} + +table tbody + tbody { border-top: 2px solid #efefef; } + +table table table { background-color: #fff; } + +table tbody > tr:nth-child(odd) > td, +table tbody > tr:nth-child(odd) > th { + background-color: #f6f6f6; +} + +table.plain tbody > tr:nth-child(odd) > td, +table.plain tbody > tr:nth-child(odd) > th { + background: transparent; +} + +iframe, .fluid-width-video-wrapper { + display: block; + margin: 1.6em 0; +} + +/* When a video is inside the fitvids wrapper, drop the +margin on the iframe, cause it breaks stuff. */ +.fluid-width-video-wrapper iframe { + margin: 0; +} + + +/* ========================================================================== + 3. Utilities - These things get used a lot + ========================================================================== */ + +/* Hides shit */ +.hidden { + text-indent: -9999px; + visibility: hidden; + display: none; +} + +/* Creates a responsive wrapper that makes our content scale nicely */ +.inner { + position: relative; + width: 80%; + max-width: 700px; + margin: 0 auto; +} + +/* Centres vertically yo. (IE8+) */ +.vertical { + display: table-cell; + vertical-align: middle; +} + + +/* ========================================================================== + 4. General - The main styles for the the theme + ========================================================================== */ + +/* Big cover image on the home page */ +.site-head { + position: relative; + display: table; + width: 100%; + height: 60%; + margin-bottom: 5rem; + text-align: center; + color: #fff; + background: #303538 no-repeat center center; + background-size: cover; +} + +.blog-logo { + text-decoration: none; +} + +/* Yo-logo. Yolo-go. Upload one in ghost/settings/ */ +.blog-logo img { + display: block; + max-height: 100px; + width: auto; + margin: 0 auto; + line-height: 0; +} + +/* The details of your blog. Defined in ghost/settings/ */ +.blog-title { + margin: 10px 0 10px 0; + font-size: 5rem; + letter-spacing: -1px; + font-weight: bold; + font-family: 'Open Sans', sans-serif; + text-shadow: 0 1px 6px rgba(0,0,0,0.1); +} + +.blog-description { + margin: 0; + font-size: 1.8rem; + line-height: 1.5em; + font-weight: 300; + font-family: 'Noto Serif', serif; + letter-spacing: 0; + text-shadow: 0 1px 3px rgba(0,0,0,0.15); +} + +/* Every post, on every page, gets this style on its
tag */ +.post { + position: relative; + width:80%; + max-width: 700px; + margin: 4rem auto; + padding-bottom: 4rem; + border-bottom: #EBF2F6 1px solid; + word-break: break-word; + hyphens: auto; +} + +/* Add a little circle in the middle of the border-bottom on our .post + just for the lolz and stylepoints. */ +.post:after { + display: block; + content: ""; + width: 7px; + height: 7px; + border: #E7EEF2 1px solid; + position: absolute; + bottom: -5px; + left: 50%; + margin-left: -5px; + background: #fff; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + box-shadow: #fff 0 0 0 5px; +} + +.post-title { + margin:0; +} + +.post-title a { + text-decoration: none; +} + +.post-excerpt p { + margin: 1.6rem 0 0 0; + font-size: 0.9em; + line-height: 1.6em; +} + +.post-meta { + display: inline-block; + margin: 0 0 5px 0; + font-family: 'Open Sans', sans-serif; + font-size: 1.5rem; + color: #9EABB3; +} + +.post-meta a { + color: #9EABB3; + text-decoration: none; +} + +.post-meta a:hover { + text-decoration: underline; +} + +.user-meta { + position: relative; + padding: 0.3rem 40px 0 100px; + min-height: 77px; +} + +.user-image { + position: absolute; + top: 0; + left: 0; +} + +.user-name { + display: block; + font-weight: bold; +} + +.user-bio { + display: block; + max-width: 440px; + font-size: 1.4rem; + line-height: 1.5em; +} + +.publish-meta { + position: absolute; + top: 0; + right: 0; + padding: 4.3rem 0 4rem 0; + text-align: right; +} + +.publish-heading { + display: block; + font-weight: bold; +} + +.publish-date { + display: block; + font-size: 1.4rem; + line-height: 1.5em; +} + +.comments-area { + width: 80%; + max-width: 700px; + margin: 4rem auto; +} + +#comment h1 a { + text-decoration: none; +} + +/* ========================================================================== + 5. Single Post - When you click on an individual post + ========================================================================== */ + +/* Insert some mad padding up in the header for better spacing */ +.post-template .post-header { + padding: 60px 0; + text-align: center; +} + +.post-template .site-head { + color: #303538; + border-bottom: #ebf2f6 1px solid; + background: none !important; +} + +.post-template .site-head:after { + position: absolute; + bottom: -5px; + left: 50%; + display: block; + width: 7px; + height: 7px; + margin-left: -5px; + content: ''; + border: #e7eef2 1px solid; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + background: #fff; + box-shadow: #fff 0 0 0 5px; +} + +/* Keep large images within the bounds of the post-width */ +.post-content img { + display: block; + max-width: 100%; + margin: 0 auto; + height: auto; +} + +/* The author credit area after the post */ +.post-footer { + position: relative; + margin: 4rem 0 0 0; + padding: 4rem 0 0 0; + border-top: #EBF2F6 1px solid; +} + +.post-footer h4 { + font-size: 1.8rem; + margin: 0; +} + +.post-footer p { + margin: 1rem 0; + font-size: 1.4rem; + line-height: 1.6em; +} + +/* Create some space to the right for the share links */ +.post-footer .author { + margin-right: 180px; +} + +/* Drop the share links in the space to the right. + Doing it like this means it's easier for the author bio + to be flexible at smaller screen sizes while the share + links remain at a fixed width the whole time */ +.post-footer .share { + position: absolute; + top: 4rem; + right: 0; + width: 140px; +} + +.post-footer .share a { + font-size: 1.8rem; + display: inline-block; + margin: 1.4rem 1.6rem 1.6rem 0; + color: #BBC7CC; + text-decoration: none; +} + +.post-footer .share a:hover { + color: #50585D; +} + + +/* ========================================================================== + 6. Third Party Elements - Embeds from other services + ========================================================================== */ + +/* Hexo: Youtube, other video container */ + +.video-container { + position: relative; + padding-top: 56.25%; + height: 0; + overflow: hidden; +} +.video-container iframe, +.video-container object, +.video-container embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin-top: 0; +} + +/* Hexo: Syntax Highlighter */ + +figure.highlight { + background:#fff; + border-radius:0.3em; + border:1px solid #e1e1e1; + line-height:1.45em; + font-size:.9em; + margin-bottom:2.1em; + color:#222; + overflow:auto; + white-space:pre; + word-wrap:normal; +} +figure.highlight figcaption { + padding: 7px 10px; + font-size: .8em; +} +figure.highlight table { + margin: 0; +} +figure.highlight table > tbody > tr > td { + padding: 0; + background: #fff !important; +} +figure.highlight table > tbody > tr > td.gutter { + max-width: 40px; + text-align: right; +} +figure.highlight pre { + border: none; + margin: 0; +} + +/* Theme: Solarized - Github + * More theme here: http://softwaremaniacs.org/media/soft/highlight/test.html + */ +pre .comment, +pre .template_comment, +.diff pre .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +.css .rule pre .keyword, +pre .winutils, +.javascript pre .title, +.nginx pre .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +.ruby pre .constant { + color: #099; +} + +pre .string, +pre .tag pre .value, +pre .phpdoc, +.tex pre .formula { + color: #d14 +} + +pre .title, +pre .id, +.coffeescript pre .params, +.scss pre .preprocessor { + color: #900; + font-weight: bold +} + +.javascript pre .title, +.lisp pre .title, +.clojure pre .title, +pre .subst { + font-weight: normal +} + +pre .class pre .title, +.haskell pre .type, +.vhdl pre .literal, +.tex pre .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag pre .title, +pre .rules pre .property, +.django pre .tag pre .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +.lisp pre .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .symbol, +.ruby pre .symbol pre .string, +.lisp pre .keyword, +.tex pre .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +.lisp pre .title, +.clojure pre .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pragma, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +.diff pre .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} + + +/* Github */ + +.gist table { + margin: 0; + font-size: 1.4rem; +} + +.gist .line-number { + min-width: 25px; + font-size: 1.1rem; +} + + +/* ========================================================================== + 7. Pagination - Tools to let you flick between pages + ========================================================================== */ + +/* The main wrapper for our pagination links */ +.pagination { + position: relative; + width: 80%; + max-width: 700px; + margin: 4rem auto; + font-family: 'Open Sans', sans-serif; + font-size: 1.3rem; + color: #9EABB3; + text-align: center; +} + +.pagination a { + color: #9EABB3; +} + +/* Push the previous/next links out to the left/right */ +.older-posts, +.newer-posts { + position: absolute; + display: inline-block; + padding: 0 15px; + border: #EBF2F6 2px solid; + text-decoration: none; + border-radius: 30px; + transition: border ease 0.3s; +} + +.older-posts { + right: 0; +} + +.page-number { + display: inline-block; + padding: 2px 0; +} + +.newer-posts { + left: 0; +} + +.older-posts:hover, +.newer-posts:hover { + border-color: #9EABB3; +} + + +/* ========================================================================== + 8. Footer - The bottom of every page + ========================================================================== */ + +.site-footer { + position: relative; + margin: 8rem 0 0 0; + padding: 4rem 0; + border-top: #EBF2F6 1px solid; + font-family: 'Open Sans', sans-serif; + font-size: 1.3rem; + line-height: 1.7em; + color: #BBC7CC; + text-align: center; + background: #F7FAFB; +} + +.site-footer a { + color: #BBC7CC; + text-decoration: underline; +} + +.site-footer a:hover { + color: #50585D; +} + +.poweredby .icon-ghost { + font-weight: 700; + text-decoration: none; +} + +.poweredby .icon-ghost:hover { + text-decoration: none; +} + +.poweredby .icon-ghost:before { + font-size: 1rem; + margin-right: 0.2em; +} + +/* The subscribe icon on the footer */ +.subscribe { + width: 28px; + height: 28px; + position: absolute; + top: -14px; + left: 50%; + margin-left: -15px; + border: #EBF2F6 1px solid; + text-align: center; + line-height: 2.4rem; + border-radius: 50px; + background: #fff; + transition: box-shadow 0.5s; +} + +/* The RSS icon, inserted via icon font */ +.subscribe:before { + color: #D2DEE3; + font-size: 10px; + position: absolute; + top: 9px; + left: 9px; + font-weight: bold; + transition: color 0.5s ease; +} + +/* Add a box shadow to on hover */ +.subscribe:hover { + box-shadow: rgba(0,0,0,0.05) 0 0 0 3px; + transition: box-shadow 0.25s; +} + +.subscribe:hover:before { + color: #50585D; +} + +/* CSS tooltip saying "Subscribe!" - initially hidden */ +.tooltip { + opacity:0; + display: inline-block; + padding: 4px 8px 5px 8px; + position:absolute; + top: -23px; + left: -21px; + color: rgba(255,255,255,0.9); + font-size: 1.1rem; + line-height: 1em; + text-align: center; + background: #50585D; + border-radius:20px; + box-shadow: 0 1px 4px rgba(0,0,0,0.1); + transition: opacity 0.3s ease, top 0.3s ease; +} + +/* The little chiclet arrow under the tooltip, pointing down */ +.tooltip:after { + content:""; + border-width:5px 5px 0 5px; + border-style:solid; + border-color: #50585D transparent; + display:block; + position:absolute; + bottom:-4px; + left:50%; + margin-left:-5px; + z-index: 220; + width:0; +} + +/* On hover, show the tooltip! */ +.subscribe:hover .tooltip { + opacity: 1; + top: -33px; +} + + +/* ========================================================================== + 9. Media Queries - Smaller than 900px + ========================================================================== */ + +@media only screen and (max-width: 900px) { + + blockquote { + margin-left: 0; + } + + .site-head { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + height: auto; + min-height: 240px; + padding: 15% 0; + } + + .blog-title { + font-size: 4rem; + letter-spacing: -1px; + } + + .blog-description { + font-size: 1.7rem; + line-height: 1.5em; + } + + .post { + font-size: 0.9em; + line-height: 1.6em; + } + + .post-template .post { + padding-bottom: 1rem; + } + + .post-template .post-header { + padding: 40px 0; + } + + h1 { + font-size: 4.8rem; + text-indent: -2px; + } + + h2 { + font-size: 3.8rem; + } + + h3 { + font-size: 3.3rem; + } + + h4 { + font-size: 2.8rem; + } + +} + +/* ========================================================================== + 10. Media Queries - Smaller than 500px + ========================================================================== */ + + +@media only screen and (max-width: 500px) { + + .blog-logo img { + max-height: 80px; + } + + .inner, + .pagination { + width: auto; + margin-left: 16px; + margin-right: 16px; + } + + .post { + width:auto; + margin-left: 16px; + margin-right: 16px; + font-size: 0.8em; + line-height: 1.6em; + } + + .site-head { + padding: 10% 0; + } + + .blog-title { + font-size: 3rem; + } + + .blog-description { + font-size: 1.5rem; + } + + + h1, h2 { + font-size: 3rem; + line-height: 1.1em; + letter-spacing: -1px; + } + + h3 { + font-size: 2.8rem; + } + + h4 { + font-size: 2.3rem; + } + + .post-template .post-header { + padding: 30px 0; + } + + .post-meta { + font-size: 1.3rem; + } + + .post-footer { + padding: 4rem 0; + text-align: center; + } + + .post-footer .author { + margin: 0 0 2rem 0; + padding: 0 0 1.6rem 0; + border-bottom: #EBF2F6 1px dashed; + } + + .post-footer .share { + position: static; + width: auto; + } + + .post-footer .share a { + margin: 1.4rem 0.8rem 0 0.8rem; + } + + .older-posts, + .newer-posts { + position: static; + margin: 10px 0; + } + + .page-number { + display: block; + } + + .site-footer { + margin-top: 6rem; + font-size: 1.1rem; + } + +} + +/* ========================================================================== + End of file. Media queries should be the last thing here. Do not add stuff + below this point, or it will probably fuck everything up. + ========================================================================== */ diff --git a/_blog_src/themes/casper_custom/source/css/site.css b/_blog_src/themes/casper_custom/source/css/site.css new file mode 100644 index 000000000..f2a1de693 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/css/site.css @@ -0,0 +1,352 @@ + +body { + padding-top: 0px; +} + +/*------------------------------------------ + Posts +--------------------------------------------*/ + +.posts-header { + text-transform: uppercase; +} + +.post-content { + font-size: 18px; +} + +.post-content p { + margin: 1em; +} + +.post-content h1, +.post-content h2, +.post-content h3, +.post-content h4, +.post-content h5, +.post-content h6 { + margin-top: 60px; +} + +.post-content ul { + margin-left: 20px; +} + +/* The author credit area after the post */ +.post-footer { + position: relative; + margin: 4rem 0 0 0; + padding: 4rem 0 0 0; + border-top: #EBF2F6 1px solid; +} + +.post-footer h4 { + font-size: 1.8rem; + margin: 0; +} + +.post-footer p { + margin: 1rem 0; + font-size: 1.4rem; + line-height: 1.6em; +} + +/* Create some space to the right for the share links */ +.post-footer .author { + margin-right: 180px; +} + +/* Drop the share links in the space to the right. + Doing it like this means it's easier for the author bio + to be flexible at smaller screen sizes while the share + links remain at a fixed width the whole time */ +.post-footer .share { + position: absolute; + top: 4rem; + right: 0; + width: 140px; +} + +.post-footer .share a { + font-size: 1.8rem; + display: inline-block; + margin: 1.4rem 1.6rem 1.6rem 0; + color: #BBC7CC; + text-decoration: none; +} + +.post-footer .share a:hover { + color: #50585D; +} + +/* Mailchimp form */ + +.mailchimp-form-container { + margin-top: 50px; +} + +.mailchimp-form { + border: 2px solid #dce4ec; + border-radius: 4px; + float: left; + padding: 20px; +} + +/*------------------------------------------ + Google search form +--------------------------------------------*/ + +input.gsc-input, .gsc-input-box, .gsc-input-box-hover, .gsc-input-box-focus, .gsc-search-button +{ + box-sizing: content-box; + line-height: normal; +} + +.post-search-form input.gsc-search-button.gsc-search-button-v2 { + background-color: #18bc9c; + border-color: #2ca78f; +} + +/*------------------------------------------ + Footer +--------------------------------------------*/ + +.site-footer { + padding: 50px 0 65px; +} + +.site-footer .list-inline { + margin: 0; + padding: 0; +} + +.site-footer .list-inline a { + color: #2c3e50; +} + +.site-footer .copyright { + font-size: 14px; + text-align: center; + margin-top: 30px; + margin-bottom: 0; +} + +/*------------------------------------------ + Pagination +--------------------------------------------*/ + +/* The main wrapper for our pagination links */ +.paging { + text-align: center; + /*position: relative;*/ + /*width: 80%; + max-width: 700px; + margin: 4rem auto;*/ + /*font-family: 'Open Sans', sans-serif;*/ + /*font-size: 1.3rem;*/ + color: #9EABB3; + margin-top: 4rem; +} + +.paging a { + color: #9EABB3; +} + +/* Push the previous/next links out to the left/right */ +.older-posts, +.newer-posts { + /*position: absolute; + display: inline-block;*/ + padding: 0 15px; + border: #EBF2F6 2px solid; + text-decoration: none; + border-radius: 30px; + transition: border ease 0.3s; +} + +.page-number { + display: inline-block; + padding: 2px 0; +} + +.older-posts:hover, +.newer-posts:hover { + border-color: #9EABB3; +} + + +/* Hexo: Syntax Highlighter */ + +figure.highlight { + background: #23241f; + border-radius:0.3em; + border:1px solid #e1e1e1; + line-height:1.45em; + font-size:.9em; + margin-bottom:2.1em; + /*color:#222;*/ + overflow:auto; + white-space:pre; + word-wrap:normal; +} +figure.highlight figcaption { + padding: 7px 10px; + font-size: .8em; +} +figure.highlight table { + width:100%; + margin: 0; +} +figure.highlight table > tbody > tr > td, figure.highlight table > tbody > tr > td { + padding: 0; + background: #23241f !important; +} +figure.highlight table > tbody > tr > td, figure.highlight table > tbody > tr > td > pre { + background: #23241f !important; +} +figure.highlight table > tbody > tr > td.gutter { + max-width: 40px; + text-align: right; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +figure.highlight pre { + border: none; + margin: 0; +} + + +/* Theme: Solarized - Github + * More theme here: http://softwaremaniacs.org/media/soft/highlight/test.html + */ +/*pre .comment, +pre .template_comment, +.diff pre .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +.css .rule pre .keyword, +pre .winutils, +.javascript pre .title, +.nginx pre .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +.ruby pre .constant { + color: #099; +} + +pre .string, +pre .tag pre .value, +pre .phpdoc, +.tex pre .formula { + color: #d14 +} + +pre .title, +pre .id, +.coffeescript pre .params, +.scss pre .preprocessor { + color: #900; + font-weight: bold +} + +.javascript pre .title, +.lisp pre .title, +.clojure pre .title, +pre .subst { + font-weight: normal +} + +pre .class pre .title, +.haskell pre .type, +.vhdl pre .literal, +.tex pre .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag pre .title, +pre .rules pre .property, +.django pre .tag pre .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +.lisp pre .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .symbol, +.ruby pre .symbol pre .string, +.lisp pre .keyword, +.tex pre .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +.lisp pre .title, +.clojure pre .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pragma, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +.diff pre .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} +*/ + + +/* Github */ + +/*.gist table { + margin: 0; + font-size: 1.4rem; +} + +.gist .line-number { + min-width: 25px; + font-size: 1.1rem; +}*/ \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/fonts/icons.dev.svg b/_blog_src/themes/casper_custom/source/fonts/icons.dev.svg new file mode 100644 index 000000000..dac6a13a4 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/fonts/icons.dev.svg @@ -0,0 +1,41 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/fonts/icons.eot b/_blog_src/themes/casper_custom/source/fonts/icons.eot new file mode 100644 index 000000000..68c968db6 Binary files /dev/null and b/_blog_src/themes/casper_custom/source/fonts/icons.eot differ diff --git a/_blog_src/themes/casper_custom/source/fonts/icons.svg b/_blog_src/themes/casper_custom/source/fonts/icons.svg new file mode 100644 index 000000000..182aa87c5 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/fonts/icons.svg @@ -0,0 +1,41 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/fonts/icons.ttf b/_blog_src/themes/casper_custom/source/fonts/icons.ttf new file mode 100644 index 000000000..12b247613 Binary files /dev/null and b/_blog_src/themes/casper_custom/source/fonts/icons.ttf differ diff --git a/_blog_src/themes/casper_custom/source/fonts/icons.woff b/_blog_src/themes/casper_custom/source/fonts/icons.woff new file mode 100644 index 000000000..0127877de Binary files /dev/null and b/_blog_src/themes/casper_custom/source/fonts/icons.woff differ diff --git a/_blog_src/themes/casper_custom/source/js/index.js b/_blog_src/themes/casper_custom/source/js/index.js new file mode 100644 index 000000000..c015cb44e --- /dev/null +++ b/_blog_src/themes/casper_custom/source/js/index.js @@ -0,0 +1,15 @@ +/** + * Main JS file for Casper behaviours + */ + +/*globals jQuery, document */ +(function ($) { + "use strict"; + + $(document).ready(function(){ + + $(".post-content").fitVids(); + + }); + +}(jQuery)); \ No newline at end of file diff --git a/_blog_src/themes/casper_custom/source/js/jquery.fitvids.js b/_blog_src/themes/casper_custom/source/js/jquery.fitvids.js new file mode 100644 index 000000000..a8551f6e1 --- /dev/null +++ b/_blog_src/themes/casper_custom/source/js/jquery.fitvids.js @@ -0,0 +1,74 @@ +/*global jQuery */ +/*jshint multistr:true browser:true */ +/*! +* FitVids 1.0.3 +* +* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com +* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ +* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ +* +* Date: Thu Sept 01 18:00:00 2011 -0500 +*/ + +(function( $ ){ + + "use strict"; + + $.fn.fitVids = function( options ) { + var settings = { + customSelector: null + }; + + if(!document.getElementById('fit-vids-style')) { + + var div = document.createElement('div'), + ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0], + cssStyles = '­'; + + div.className = 'fit-vids-style'; + div.id = 'fit-vids-style'; + div.style.display = 'none'; + div.innerHTML = cssStyles; + + ref.parentNode.insertBefore(div,ref); + + } + + if ( options ) { + $.extend( settings, options ); + } + + return this.each(function(){ + var selectors = [ + "iframe[src*='player.vimeo.com']", + "iframe[src*='youtube.com']", + "iframe[src*='youtube-nocookie.com']", + "iframe[src*='kickstarter.com'][src*='video.html']", + "object", + "embed" + ]; + + if (settings.customSelector) { + selectors.push(settings.customSelector); + } + + var $allVideos = $(this).find(selectors.join(',')); + $allVideos = $allVideos.not("object object"); // SwfObj conflict patch + + $allVideos.each(function(){ + var $this = $(this); + if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } + var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), + width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), + aspectRatio = height / width; + if(!$this.attr('id')){ + var videoID = 'fitvid' + Math.floor(Math.random()*999999); + $this.attr('id', videoID); + } + $this.wrap('
').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); + $this.removeAttr('height').removeAttr('width'); + }); + }); + }; +// Works with either jQuery or Zepto +})( window.jQuery || window.Zepto ); diff --git a/_blog_src/themes/landscape/Gruntfile.js b/_blog_src/themes/landscape/Gruntfile.js new file mode 100644 index 000000000..59fd5df35 --- /dev/null +++ b/_blog_src/themes/landscape/Gruntfile.js @@ -0,0 +1,46 @@ +module.exports = function(grunt){ + grunt.initConfig({ + gitclone: { + fontawesome: { + options: { + repository: 'https://github.com/FortAwesome/Font-Awesome.git', + directory: 'tmp/fontawesome' + }, + }, + fancybox: { + options: { + repository: 'https://github.com/fancyapps/fancyBox.git', + directory: 'tmp/fancybox' + } + } + }, + copy: { + fontawesome: { + expand: true, + cwd: 'tmp/fontawesome/fonts/', + src: ['**'], + dest: 'source/css/fonts/' + }, + fancybox: { + expand: true, + cwd: 'tmp/fancybox/source/', + src: ['**'], + dest: 'source/fancybox/' + } + }, + _clean: { + tmp: ['tmp'], + fontawesome: ['source/css/fonts'], + fancybox: ['source/fancybox'] + } + }); + + require('load-grunt-tasks')(grunt); + + grunt.renameTask('clean', '_clean'); + + grunt.registerTask('fontawesome', ['gitclone:fontawesome', 'copy:fontawesome', '_clean:tmp']); + grunt.registerTask('fancybox', ['gitclone:fancybox', 'copy:fancybox', '_clean:tmp']); + grunt.registerTask('default', ['gitclone', 'copy', '_clean:tmp']); + grunt.registerTask('clean', ['_clean']); +}; \ No newline at end of file diff --git a/_blog_src/themes/landscape/LICENSE b/_blog_src/themes/landscape/LICENSE new file mode 100644 index 000000000..9ce4d329b --- /dev/null +++ b/_blog_src/themes/landscape/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2013 Tommy Chen + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/_blog_src/themes/landscape/README.md b/_blog_src/themes/landscape/README.md new file mode 100644 index 000000000..65671044d --- /dev/null +++ b/_blog_src/themes/landscape/README.md @@ -0,0 +1,111 @@ +# Landscape + +A brand new default theme for [Hexo]. + +- [Preview](http://hexo.io/hexo-theme-landscape/) + +## Installation + +### Install + +``` bash +$ git clone https://github.com/tommy351/hexo-theme-landscape.git themes/landscape +``` + +**Landscape requires Hexo 2.4 and above.** + +### Enable + +Modify `theme` setting in `_config.yml` to `landscape`. + +### Update + +``` bash +cd themes/landscape +git pull +``` + +## Configuration + +``` yml +# Header +menu: + Home: / + Archives: /archives +rss: /atom.xml + +# Content +excerpt_link: Read More +fancybox: true + +# Sidebar +sidebar: right +widgets: +- category +- tag +- tagcloud +- archives +- recent_posts + +# Miscellaneous +google_analytics: +favicon: /favicon.png +twitter: +google_plus: +``` + +- **menu** - Navigation menu +- **rss** - RSS link +- **excerpt_link** - "Read More" link at the bottom of excerpted articles. `false` to hide the link. +- **fancybox** - Enable [Fancybox] +- **sidebar** - Sidebar style. You can choose `left`, `right`, `bottom` or `false`. +- **widgets** - Widgets displaying in sidebar +- **google_analytics** - Google Analytics ID +- **favicon** - Favicon path +- **twitter** - Twiiter ID +- **google_plus** - Google+ ID + +## Features + +### Fancybox + +Landscape uses [Fancybox] to showcase your photos. You can use Markdown syntax or fancybox tag plugin to add your photos. + +``` +![img caption](img url) + +{% fancybox img_url [img_thumbnail] [img_caption] %} +``` + +### Sidebar + +You can put your sidebar in left side, right side or bottom of your site by editing `sidebar` setting. + +Landscape provides 5 built-in widgets: + +- category +- tag +- tagcloud +- archives +- recent_posts + +All of them are enabled by default. You can edit them in `widget` setting. + +## Development + +### Requirements + +- [Grunt] 0.4+ +- Hexo 2.4+ + +### Grunt tasks + +- **default** - Download [Fancybox] and [Font Awesome]. +- **fontawesome** - Only download [Font Awesome]. +- **fancybox** - Only download [Fancybox]. +- **clean** - Clean temporarily files and downloaded files. + +[Hexo]: http://zespia.tw/hexo/ +[Fancybox]: http://fancyapps.com/fancybox/ +[Font Awesome]: http://fontawesome.io/ +[Grunt]: http://gruntjs.com/ diff --git a/_blog_src/themes/landscape/_config.yml b/_blog_src/themes/landscape/_config.yml new file mode 100644 index 000000000..85a1ccf09 --- /dev/null +++ b/_blog_src/themes/landscape/_config.yml @@ -0,0 +1,26 @@ +# Header +menu: + Home: / + Archives: /archives +rss: /atom.xml + +# Content +excerpt_link: Read More +fancybox: true + +# Sidebar +sidebar: right +widgets: +- category +- tag +- tagcloud +- archive +- recent_posts + +# Miscellaneous +google_analytics: +favicon: /favicon.png +twitter: +google_plus: +fb_admins: +fb_app_id: \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/after-footer.ejs b/_blog_src/themes/landscape/layout/_partial/after-footer.ejs new file mode 100644 index 000000000..fdb297086 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/after-footer.ejs @@ -0,0 +1,24 @@ +<% if (config.disqus_shortname){ %> + +<% } %> + + + +<% if (theme.fancybox){ %> + + +<% } %> + +<%- js('js/script') %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/archive-post.ejs b/_blog_src/themes/landscape/layout/_partial/archive-post.ejs new file mode 100644 index 000000000..36f2cc31f --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/archive-post.ejs @@ -0,0 +1,8 @@ +
+
+
+ <%- partial('post/date', {class_name: 'archive-article-date', date_format: 'MMM D'}) %> + <%- partial('post/title', {class_name: 'archive-article-title'}) %> +
+
+
\ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/archive.ejs b/_blog_src/themes/landscape/layout/_partial/archive.ejs new file mode 100644 index 000000000..8401769f8 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/archive.ejs @@ -0,0 +1,33 @@ +<% if (pagination == 2){ %> + <% page.posts.each(function(post){ %> + <%- partial('article', {post: post, index: true}) %> + <% }) %> + <% if (page.total > 1){ %> + + <% } %> +<% } else { %> + <% var last; %> + <% page.posts.each(function(post, i){ %> + <% var year = post.date.year(); %> + <% if (last != year){ %> + <% if (last != null){ %> + + <% } %> + <% last = year; %> +
+ +
+ <% } %> + <%- partial('archive-post', {post: post, even: i % 2 == 0}) %> + <% }) %> + <% if (page.posts.length){ %> +
+ <% } %> +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/article.ejs b/_blog_src/themes/landscape/layout/_partial/article.ejs new file mode 100644 index 000000000..404b0659e --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/article.ejs @@ -0,0 +1,44 @@ +
+ +
+ <%- partial('post/gallery') %> + <% if (post.link || post.title){ %> +
+ <%- partial('post/title', {class_name: 'article-title'}) %> +
+ <% } %> +
+ <% if (post.excerpt && index){ %> + <%- post.excerpt %> + <% if (theme.excerpt_link){ %> +

+ <%= theme.excerpt_link %> +

+ <% } %> + <% } else { %> + <%- post.content %> + <% } %> +
+
+ Share + <% if (post.comments && config.disqus_shortname){ %> + Comments + <% } %> + <%- partial('post/tag') %> +
+
+ <% if (!index){ %> + <%- partial('post/nav') %> + <% } %> +
+ +<% if (!index && post.comments && config.disqus_shortname){ %> +
+
+ +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/footer.ejs b/_blog_src/themes/landscape/layout/_partial/footer.ejs new file mode 100644 index 000000000..b7fa5e21d --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/footer.ejs @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/google-analytics.ejs b/_blog_src/themes/landscape/layout/_partial/google-analytics.ejs new file mode 100644 index 000000000..8f23d4628 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/google-analytics.ejs @@ -0,0 +1,13 @@ +<% if (theme.google_analytics){ %> + +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/head.ejs b/_blog_src/themes/landscape/layout/_partial/head.ejs new file mode 100644 index 000000000..261952c8e --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/head.ejs @@ -0,0 +1,35 @@ + + + + + <% + var title = page.title; + + if (is_archive()){ + title = 'Archives'; + + if (is_month()){ + title += ': ' + page.year + '/' + page.month; + } else if (is_year()){ + title += ': ' + page.year; + } + } else if (is_category()){ + title = 'Category: ' + page.category; + } else if (is_tag()){ + title = 'Tag: ' + page.tag; + } + %> + <% if (title){ %><%= title %> | <% } %><%= config.title %> + + <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id}) %> + <% if (theme.rss){ %> + + <% } %> + <% if (theme.favicon){ %> + + <% } %> + + <%- css('css/style') %> + + <%- partial('google-analytics') %> + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/header.ejs b/_blog_src/themes/landscape/layout/_partial/header.ejs new file mode 100644 index 000000000..107f5b105 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/header.ejs @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/mobile-nav.ejs b/_blog_src/themes/landscape/layout/_partial/mobile-nav.ejs new file mode 100644 index 000000000..3e1c5bd49 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/mobile-nav.ejs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/category.ejs b/_blog_src/themes/landscape/layout/_partial/post/category.ejs new file mode 100644 index 000000000..db2ed4842 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/category.ejs @@ -0,0 +1,10 @@ +<% if (post.categories && post.categories.length){ %> +
+ <%- list_categories(post.categories, { + show_count: false, + class: 'article-category', + style: 'none', + separator: '►' + }) %> +
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/date.ejs b/_blog_src/themes/landscape/layout/_partial/post/date.ejs new file mode 100644 index 000000000..99470c8d3 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/date.ejs @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/gallery.ejs b/_blog_src/themes/landscape/layout/_partial/post/gallery.ejs new file mode 100644 index 000000000..ac264cc0e --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/gallery.ejs @@ -0,0 +1,11 @@ +<% if (post.photos && post.photos.length){ %> +
+
+ <% post.photos.forEach(function(photo, i){ %> + + + + <% }) %> +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/nav.ejs b/_blog_src/themes/landscape/layout/_partial/post/nav.ejs new file mode 100644 index 000000000..da272e06c --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/nav.ejs @@ -0,0 +1,22 @@ +<% if (post.prev || post.next){ %> + +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/tag.ejs b/_blog_src/themes/landscape/layout/_partial/post/tag.ejs new file mode 100644 index 000000000..e0f327f62 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/tag.ejs @@ -0,0 +1,6 @@ +<% if (post.tags && post.tags.length){ %> + <%- list_tags(post.tags, { + show_count: false, + class: 'article-tag' + }) %> +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/post/title.ejs b/_blog_src/themes/landscape/layout/_partial/post/title.ejs new file mode 100644 index 000000000..6a792c2b0 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/post/title.ejs @@ -0,0 +1,15 @@ +<% if (post.link){ %> +

+ +

+<% } else if (post.title){ %> + <% if (index){ %> +

+ <%= post.title %> +

+ <% } else { %> +

+ <%= post.title %> +

+ <% } %> +<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_partial/sidebar.ejs b/_blog_src/themes/landscape/layout/_partial/sidebar.ejs new file mode 100644 index 000000000..c1e48e53c --- /dev/null +++ b/_blog_src/themes/landscape/layout/_partial/sidebar.ejs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_widget/archive.ejs b/_blog_src/themes/landscape/layout/_widget/archive.ejs new file mode 100644 index 000000000..9a428bae3 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_widget/archive.ejs @@ -0,0 +1,8 @@ +<% if (site.posts.length){ %> +
+

Archives

+
+ <%- list_archives() %> +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_widget/category.ejs b/_blog_src/themes/landscape/layout/_widget/category.ejs new file mode 100644 index 000000000..7836a2794 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_widget/category.ejs @@ -0,0 +1,8 @@ +<% if (site.categories.length){ %> +
+

Categories

+
+ <%- list_categories() %> +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_widget/recent_posts.ejs b/_blog_src/themes/landscape/layout/_widget/recent_posts.ejs new file mode 100644 index 000000000..3986ffb94 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_widget/recent_posts.ejs @@ -0,0 +1,14 @@ +<% if (site.posts.length){ %> +
+

Recents

+
+ +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_widget/tag.ejs b/_blog_src/themes/landscape/layout/_widget/tag.ejs new file mode 100644 index 000000000..c163c4192 --- /dev/null +++ b/_blog_src/themes/landscape/layout/_widget/tag.ejs @@ -0,0 +1,8 @@ +<% if (site.tags.length){ %> +
+

Tags

+
+ <%- list_tags() %> +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/_widget/tagcloud.ejs b/_blog_src/themes/landscape/layout/_widget/tagcloud.ejs new file mode 100644 index 000000000..4b822835c --- /dev/null +++ b/_blog_src/themes/landscape/layout/_widget/tagcloud.ejs @@ -0,0 +1,8 @@ +<% if (site.tags.length){ %> +
+

Tag Cloud

+
+ <%- tagcloud() %> +
+
+<% } %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/archive.ejs b/_blog_src/themes/landscape/layout/archive.ejs new file mode 100644 index 000000000..52f9b2105 --- /dev/null +++ b/_blog_src/themes/landscape/layout/archive.ejs @@ -0,0 +1 @@ +<%- partial('_partial/archive', {pagination: config.archive, index: true}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/category.ejs b/_blog_src/themes/landscape/layout/category.ejs new file mode 100644 index 000000000..3ffe25271 --- /dev/null +++ b/_blog_src/themes/landscape/layout/category.ejs @@ -0,0 +1 @@ +<%- partial('_partial/archive', {pagination: config.category, index: true}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/index.ejs b/_blog_src/themes/landscape/layout/index.ejs new file mode 100644 index 000000000..60a2c6884 --- /dev/null +++ b/_blog_src/themes/landscape/layout/index.ejs @@ -0,0 +1 @@ +<%- partial('_partial/archive', {pagination: 2, index: true}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/layout.ejs b/_blog_src/themes/landscape/layout/layout.ejs new file mode 100644 index 000000000..1524a6273 --- /dev/null +++ b/_blog_src/themes/landscape/layout/layout.ejs @@ -0,0 +1,18 @@ +<%- partial('_partial/head') %> + +
+
+ <%- partial('_partial/header') %> +
+
<%- body %>
+ <% if (theme.sidebar && theme.sidebar !== 'bottom'){ %> + <%- partial('_partial/sidebar') %> + <% } %> +
+ <%- partial('_partial/footer') %> +
+ <%- partial('_partial/mobile-nav') %> + <%- partial('_partial/after-footer') %> +
+ + \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/page.ejs b/_blog_src/themes/landscape/layout/page.ejs new file mode 100644 index 000000000..bea631879 --- /dev/null +++ b/_blog_src/themes/landscape/layout/page.ejs @@ -0,0 +1 @@ +<%- partial('_partial/article', {post: page, index: false}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/post.ejs b/_blog_src/themes/landscape/layout/post.ejs new file mode 100644 index 000000000..bea631879 --- /dev/null +++ b/_blog_src/themes/landscape/layout/post.ejs @@ -0,0 +1 @@ +<%- partial('_partial/article', {post: page, index: false}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/layout/tag.ejs b/_blog_src/themes/landscape/layout/tag.ejs new file mode 100644 index 000000000..048cdb0ec --- /dev/null +++ b/_blog_src/themes/landscape/layout/tag.ejs @@ -0,0 +1 @@ +<%- partial('_partial/archive', {pagination: config.tag, index: true}) %> \ No newline at end of file diff --git a/_blog_src/themes/landscape/package.json b/_blog_src/themes/landscape/package.json new file mode 100644 index 000000000..a11e9f661 --- /dev/null +++ b/_blog_src/themes/landscape/package.json @@ -0,0 +1,12 @@ +{ + "name": "hexo-theme-landscape", + "version": "0.0.1", + "private": true, + "devDependencies": { + "grunt": "~0.4.2", + "load-grunt-tasks": "~0.2.0", + "grunt-git": "~0.2.2", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-copy": "~0.4.1" + } +} diff --git a/_blog_src/themes/landscape/scripts/fancybox.js b/_blog_src/themes/landscape/scripts/fancybox.js new file mode 100644 index 000000000..83f1fdc32 --- /dev/null +++ b/_blog_src/themes/landscape/scripts/fancybox.js @@ -0,0 +1,24 @@ +var rUrl = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[.\!\/\\w]*))?)/; + +/** +* Fancybox tag +* +* Syntax: +* {% fancybox /path/to/image [/path/to/thumbnail] [title] %} +*/ + +hexo.extend.tag.register('fancybox', function(args){ + var original = args.shift(), + thumbnail = ''; + + if (args.length && rUrl.test(args[0])){ + thumbnail = args.shift(); + } + + var title = args.join(' '); + + return '' + + '' + title + '' + '' + + (title ? '' + title + '' : ''); +}); \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_extend.styl b/_blog_src/themes/landscape/source/css/_extend.styl new file mode 100644 index 000000000..96a181799 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_extend.styl @@ -0,0 +1,63 @@ +$block-caption + text-decoration: none + text-transform: uppercase + letter-spacing: 2px + color: color-grey + margin-bottom: 1em + margin-left: 5px + line-height: 1em + text-shadow: 0 1px #fff + font-weight: bold + +$block + background: #fff + box-shadow: 1px 2px 3px #ddd + border: 1px solid color-border + border-radius: 3px + +$base-style + h1 + font-size: 2em + h2 + font-size: 1.5em + h3 + font-size: 1.3em + h4 + font-size: 1.2em + h5 + font-size: 1em + h6 + font-size: 1em + color: color-grey + hr + border: 1px dashed color-border + strong + font-weight: bold + em, cite + font-style: italic + sup, sub + font-size: 0.75em + line-height: 0 + position: relative + vertical-align: baseline + sup + top: -0.5em + sub + bottom: -0.2em + small + font-size: 0.85em + acronym, abbr + border-bottom: 1px dotted + ul, ol, dl + margin: 0 20px + line-height: line-height + ul, ol + ul, ol + margin-top: 0 + margin-bottom: 0 + ul + list-style: disc + ol + list-style: decimal + dt + font-weight: bold \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/archive.styl b/_blog_src/themes/landscape/source/css/_partial/archive.styl new file mode 100644 index 000000000..165b6781d --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/archive.styl @@ -0,0 +1,78 @@ +.archives-wrap + margin: block-margin 0 + +.archives + clearfix() + +.archive-year-wrap + margin-bottom: 1em + +.archive-year + @extend $block-caption + +.archives + column-gap: 10px + @media mq-tablet + column-count: 2 + @media mq-normal + column-count: 3 + +.archive-article + avoid-column-break() + +.archive-article-inner + @extend $block + padding: 10px + margin-bottom: 15px + +.archive-article-title + text-decoration: none + font-weight: bold + color: color-default + transition: color 0.2s + line-height: line-height + &:hover + color: color-link + +.archive-article-footer + margin-top: 1em + +.archive-article-date + color: color-grey + text-decoration: none + font-size: 0.85em + line-height: 1em + margin-bottom: 0.5em + display: block + +#page-nav + clearfix() + margin: block-margin auto + background: #fff + box-shadow: 1px 2px 3px #ddd + border: 1px solid color-border + border-radius: 3px + text-align: center + color: color-grey + overflow: hidden + a, span + padding: 10px 20px + a + color: color-grey + text-decoration: none + &:hover + background: color-grey + color: #fff + .prev + float: left + .next + float: right + .page-number + display: inline-block + @media mq-mobile + display: none + .current + color: color-default + font-weight: bold + .space + color: color-border \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/article.styl b/_blog_src/themes/landscape/source/css/_partial/article.styl new file mode 100644 index 000000000..46094f9fa --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/article.styl @@ -0,0 +1,357 @@ +.article + margin: block-margin 0 + +.article-inner + @extend $block + overflow: hidden + +.article-meta + clearfix() + +.article-date + @extend $block-caption + float: left + +.article-category + float: left + line-height: 1em + color: #ccc + text-shadow: 0 1px #fff + margin-left: 8px + &:before + content: "\2022" + +.article-category-link + @extend $block-caption + margin: 0 12px 1em + +.article-header + padding: article-padding article-padding 0 + +.article-title + text-decoration: none + font-size: 2em + font-weight: bold + color: color-default + line-height: line-height-title + transition: color 0.2s + a&:hover + color: color-link + +.article-entry + @extend $base-style + clearfix() + color: color-default + padding: 0 article-padding + p, table + line-height: line-height + margin: line-height 0 + h1, h2, h3, h4, h5, h6 + font-weight: bold + h1, h2, h3, h4, h5, h6 + line-height: line-height-title + margin: line-height-title 0 + a + color: color-link + text-decoration: none + &:hover + text-decoration: underline + ul, ol, dl + margin-top: line-height + margin-bottom: line-height + img, video + max-width: 100% + height: auto + display: block + margin: auto + iframe + border: none + table + width: 100% + border-collapse: collapse + border-spacing: 0 + th + font-weight: bold + border-bottom: 3px solid color-border + padding-bottom: 0.5em + td + border-bottom: 1px solid color-border + padding: 10px 0 + blockquote + font-family: font-serif + font-size: 1.4em + margin: line-height 20px + text-align: center + footer + font-size: font-size + margin: line-height 0 + font-family: font-sans + cite + &:before + content: "—" + padding: 0 0.5em + .pullquote + text-align: left + width: 45% + margin: 0 + &.left + margin-left: 0.5em + margin-right: 1em + &.right + margin-right: 0.5em + margin-left: 1em + .caption + color: color-grey + display: block + font-size: 0.9em + margin-top: 0.5em + position: relative + text-align: center + // http://webdesignerwall.com/tutorials/css-elastic-videos + .video-container + position: relative + padding-top: (9 / 16 * 100)% // 16:9 ratio + height: 0 + overflow: hidden + iframe, object, embed + position: absolute + top: 0 + left: 0 + width: 100% + height: 100% + margin-top: 0 + +.article-more-link a + display: inline-block + line-height: 1em + padding: 6px 15px + border-radius: 15px + background: color-background + color: color-grey + text-shadow: 0 1px #fff + text-decoration: none + &:hover + background: color-link + color: #fff + text-decoration: none + text-shadow: 0 1px darken(color-link, 20%) + +.article-footer + clearfix() + font-size: 0.85em + line-height: line-height + border-top: 1px solid color-border + padding-top: line-height + margin: 0 article-padding article-padding + a + color: color-grey + text-decoration: none + &:hover + color: color-default + +.article-tag-list-item + float: left + margin-right: 10px + +.article-tag-list-link + &:before + content: "#" + +.article-comment-link + float: right + &:before + content: "\f075" + font-family: font-icon + padding-right: 8px + +.article-share-link + cursor: pointer + float: right + margin-left: 20px + &:before + content: "\f064" + font-family: font-icon + padding-right: 6px + +#article-nav + clearfix() + position: relative + @media mq-normal + margin: block-margin 0 + &:before + absolute-center(8px) + content: "" + border-radius: 50% + background: color-border + box-shadow: 0 1px 2px #fff + +.article-nav-link-wrap + text-decoration: none + text-shadow: 0 1px #fff + color: color-grey + box-sizing: border-box + margin-top: block-margin + text-align: center + display: block + &:hover + color: color-default + @media mq-normal + width: 50% + margin-top: 0 + +#article-nav-newer + @media mq-normal + float: left + text-align: right + padding-right: 20px + +#article-nav-older + @media mq-normal + float: right + text-align: left + padding-left: 20px + +.article-nav-caption + text-transform: uppercase + letter-spacing: 2px + color: color-border + line-height: 1em + font-weight: bold + #article-nav-newer & + margin-right: -2px + +.article-nav-title + font-size: 0.85em + line-height: line-height + margin-top: 0.5em + +.article-share-box + position: absolute + display: none + background: #fff + box-shadow: 1px 2px 10px rgba(0, 0, 0, 0.2) + border-radius: 3px + margin-left: -145px + overflow: hidden + z-index: 1 + &.on + display: block + +.article-share-input + width: 100% + background: none + box-sizing: border-box + font: 14px font-sans + padding: 0 15px + color: color-default + outline: none + border: 1px solid color-border + border-radius: 3px 3px 0 0 + height: 36px + line-height: 36px + +.article-share-links + clearfix() + background: color-background + +$article-share-link + width: 50px + height: 36px + display: block + float: left + position: relative + color: #999 + text-shadow: 0 1px #fff + &:before + font-size: 20px + font-family: font-icon + absolute-center(@font-size) + text-align: center + &:hover + color: #fff + +.article-share-twitter + @extend $article-share-link + &:before + content: "\f099" + &:hover + background: color-twitter + text-shadow: 0 1px darken(color-twitter, 20%) + +.article-share-facebook + @extend $article-share-link + &:before + content: "\f09a" + &:hover + background: color-facebook + text-shadow: 0 1px darken(color-facebook, 20%) + +.article-share-pinterest + @extend $article-share-link + &:before + content: "\f0d2" + &:hover + background: color-pinterest + text-shadow: 0 1px darken(color-pinterest, 20%) + +.article-share-google + @extend $article-share-link + &:before + content: "\f0d5" + &:hover + background: color-google + text-shadow: 0 1px darken(color-google, 20%) + +.article-gallery + background: #000 + position: relative + +.article-gallery-photos + position: relative + overflow: hidden + +.article-gallery-img + display: none + max-width: 100% + &:first-child + display: block + &.loaded + position: absolute + display: block + img + display: block + max-width: 100% + margin: 0 auto +/* +$article-gallery-ctrl + position: absolute + top: 0 + height: 100% + width: 60px + color: #fff + text-shadow: 0 0 3px rgba(0, 0, 0, 0.3) + opacity: 0.3 + transition: opacity 0.2s + cursor: pointer + &:hover + opacity: 0.8 + &:before + font-size: 30px + font-family: font-icon + position: absolute + top: 50% + margin-top: @font-size * -0.5 + +.article-gallery-prev + @extend $article-gallery-ctrl + left: 0 + &:before + content: "\f053" + left: 15px + +.article-gallery-next + @extend $article-gallery-ctrl + right: 0 + &:before + content: "\f054" + right: 15px*/ \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/comment.styl b/_blog_src/themes/landscape/source/css/_partial/comment.styl new file mode 100644 index 000000000..296b7dd6b --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/comment.styl @@ -0,0 +1,9 @@ +#comments + background: #fff + box-shadow: 1px 2px 3px #ddd + padding: article-padding + border: 1px solid color-border + border-radius: 3px + margin: block-margin 0 + a + color: color-link \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/footer.styl b/_blog_src/themes/landscape/source/css/_partial/footer.styl new file mode 100644 index 000000000..fe2fd2462 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/footer.styl @@ -0,0 +1,14 @@ +#footer + background: color-footer-background + padding: 50px 0 + border-top: 1px solid color-border + color: color-grey + a + color: color-link + text-decoration: none + &:hover + text-decoration: underline + +#footer-info + line-height: line-height + font-size: 0.85em \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/header.styl b/_blog_src/themes/landscape/source/css/_partial/header.styl new file mode 100644 index 000000000..d18ebc8d5 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/header.styl @@ -0,0 +1,165 @@ +#header + height: banner-height + position: relative + border-bottom: 1px solid color-border + &:before, &:after + content: "" + position: absolute + left: 0 + right: 0 + height: 40px + &:before + top: 0 + background: linear-gradient(rgba(0, 0, 0, 0.2), transparent) + &:after + bottom: 0 + background: linear-gradient(transparent, rgba(0, 0, 0, 0.2)) + +#header-outer + height: 100% + position: relative + +#header-inner + position: relative + overflow: hidden + +#banner + position: absolute + top: 0 + left: 0 + width: 100% + height: 100% + background: url(banner-url) center #000 + background-size: cover + z-index: -1 + +#header-title + text-align: center + height: logo-size + position: absolute + top: 50% + left: 0 + margin-top: logo-size * -0.5 + +$logo-text + text-decoration: none + color: #fff + font-weight: 300 + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) + +#logo + @extend $logo-text + font-size: logo-size + line-height: logo-size + letter-spacing: 2px + +#subtitle + @extend $logo-text + font-size: subtitle-size + line-height: subtitle-size + letter-spacing: 1px + +#subtitle-wrap + margin-top: subtitle-size + +#main-nav + float: left + margin-left: -15px + +$nav-link + float: left + color: #fff + opacity: 0.6 + text-decoration: none + text-shadow: 0 1px rgba(0, 0, 0, 0.2) + transition: opacity 0.2s + display: block + padding: 20px 15px + &:hover + opacity: 1 + +.nav-icon + @extend $nav-link + font-family: font-icon + text-align: center + font-size: font-size + width: font-size + height: font-size + padding: 20px 15px + position: relative + cursor: pointer + +.main-nav-link + @extend $nav-link + font-weight: 300 + letter-spacing: 1px + @media mq-mobile + display: none + +#main-nav-toggle + display: none + &:before + content: "\f0c9" + @media mq-mobile + display: block + +#sub-nav + float: right + margin-right: -15px + +#nav-rss-link + &:before + content: "\f09e" + +#nav-search-btn + &:before + content: "\f002" + +#search-form-wrap + position: absolute + top: 15px + width: 150px + height: 30px + right: -150px + opacity: 0 + transition: 0.2s ease-out + &.on + opacity: 1 + right: 0 + @media mq-mobile + width: 100% + right: -100% + +.search-form + position: absolute + top: 0 + left: 0 + right: 0 + background: #fff + padding: 5px 15px + border-radius: 15px + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) + +.search-form-input + border: none + background: none + color: color-default + width: 100% + font: 13px font-sans + outline: none + &::-webkit-search-results-decoration + &::-webkit-search-cancel-button + -webkit-appearance: none + +.search-form-submit + position: absolute + top: 50% + right: 10px + margin-top: -7px + font: 13px font-icon + border: none + background: none + color: #bbb + cursor: pointer + &:hover, &:focus + color: #777 \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/highlight.styl b/_blog_src/themes/landscape/source/css/_partial/highlight.styl new file mode 100644 index 000000000..9151638a0 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/highlight.styl @@ -0,0 +1,154 @@ +// https://github.com/chriskempson/tomorrow-theme +highlight-background = #2d2d2d +highlight-current-line = #393939 +highlight-selection = #515151 +highlight-foreground = #cccccc +highlight-comment = #999999 +highlight-red = #f2777a +highlight-orange = #f99157 +highlight-yellow = #ffcc66 +highlight-green = #99cc99 +highlight-aqua = #66cccc +highlight-blue = #6699cc +highlight-purple = #cc99cc + +$code-block + background: highlight-background + margin: 0 article-padding * -1 + padding: 15px article-padding + border-style: solid + border-color: color-border + border-width: 1px 0 + overflow: auto + color: highlight-foreground + line-height: font-size * line-height + +$line-numbers + color: #666 + font-size: 0.85em + +.article-entry + pre, code + font-family: font-mono + code + background: color-background + text-shadow: 0 1px #fff + padding: 0 0.3em + pre + @extend $code-block + code + background: none + text-shadow: none + padding: 0 + .highlight + @extend $code-block + pre + border: none + margin: 0 + padding: 0 + table + margin: 0 + width: auto + td + border: none + padding: 0 + figcaption + clearfix() + font-size: 0.85em + color: highlight-comment + line-height: 1em + margin-bottom: 1em + a + float: right + .gutter pre + @extend $line-numbers + text-align: right + padding-right: 20px + .gist + margin: 0 article-padding * -1 + border-style: solid + border-color: color-border + border-width: 1px 0 + background: highlight-background + padding: 15px article-padding 15px 0 + .gist-file + border: none + font-family: font-mono + margin: 0 + .gist-data + background: none + border: none + .line-numbers + @extend $line-numbers + background: none + border: none + padding: 0 20px 0 0 + .line-data + padding: 0 !important + .highlight + margin: 0 + padding: 0 + border: none + .gist-meta + background: highlight-background + color: highlight-comment + font: 0.85em font-sans + text-shadow: 0 0 + padding: 0 + margin-top: 1em + margin-left: article-padding + a + color: color-link + font-weight: normal + &:hover + text-decoration: underline + +pre + .comment + .title + color: highlight-comment + .variable + .attribute + .tag + .regexp + .ruby .constant + .xml .tag .title + .xml .pi + .xml .doctype + .html .doctype + .css .id + .css .class + .css .pseudo + color: highlight-red + .number + .preprocessor + .built_in + .literal + .params + .constant + color: highlight-orange + .class + .ruby .class .title + .css .rules .attribute + color: highlight-green + .string + .value + .inheritance + .header + .ruby .symbol + .xml .cdata + color: highlight-green + .css .hexcolor + color: highlight-aqua + .function + .python .decorator + .python .title + .ruby .function .title + .ruby .title .keyword + .perl .sub + .javascript .title + .coffeescript .title + color: highlight-blue + .keyword + .javascript .function + color: highlight-purple \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/mobile.styl b/_blog_src/themes/landscape/source/css/_partial/mobile.styl new file mode 100644 index 000000000..eb68b3a2d --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/mobile.styl @@ -0,0 +1,19 @@ +@media mq-mobile + #mobile-nav + position: absolute + top: 0 + left: 0 + width: mobile-nav-width + height: 100% + background: color-mobile-nav-background + border-right: 1px solid #fff + +@media mq-mobile + .mobile-nav-link + display: block + color: color-grey + text-decoration: none + padding: 15px 20px + font-weight: bold + &:hover + color: #fff diff --git a/_blog_src/themes/landscape/source/css/_partial/sidebar-aside.styl b/_blog_src/themes/landscape/source/css/_partial/sidebar-aside.styl new file mode 100644 index 000000000..838b1675b --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/sidebar-aside.styl @@ -0,0 +1,27 @@ +#sidebar + @media mq-normal + column(sidebar-column) + +.widget-wrap + margin: block-margin 0 + +.widget-title + @extend $block-caption + +.widget + color: color-sidebar-text + text-shadow: 0 1px #fff + background: color-widget-background + box-shadow: 0 -1px 4px color-widget-border inset + border: 1px solid color-widget-border + padding: 15px + border-radius: 3px + a + color: color-link + text-decoration: none + &:hover + text-decoration: underline + ul, ol, dl + ul, ol, dl + margin-left: 15px + list-style: disc \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/sidebar-bottom.styl b/_blog_src/themes/landscape/source/css/_partial/sidebar-bottom.styl new file mode 100644 index 000000000..b3852753c --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/sidebar-bottom.styl @@ -0,0 +1,15 @@ +.widget-wrap + margin-bottom: block-margin !important + @media mq-normal + column(sidebar-column) + +.widget-title + color: #ccc + text-transform: uppercase + letter-spacing: 2px + margin-bottom: 1em + line-height: 1em + font-weight: bold + +.widget + color: color-grey \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_partial/sidebar.styl b/_blog_src/themes/landscape/source/css/_partial/sidebar.styl new file mode 100644 index 000000000..0c12b4c4d --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_partial/sidebar.styl @@ -0,0 +1,34 @@ +if sidebar is bottom + @import "sidebar-bottom" +else + @import "sidebar-aside" + +.widget + @extend $base-style + line-height: line-height + word-wrap: break-word + font-size: 0.9em + ul, ol + list-style: none + margin: 0 + ul, ol + margin: 0 20px + ul + list-style: disc + ol + list-style: decimal + +.category-list-count +.tag-list-count +.archive-list-count + padding-left: 5px + color: color-grey + font-size: 0.85em + &:before + content: "(" + &:after + content: ")" + +.tagcloud + a + margin-right: 5px \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_util/grid.styl b/_blog_src/themes/landscape/source/css/_util/grid.styl new file mode 100644 index 000000000..2a14dd238 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_util/grid.styl @@ -0,0 +1,38 @@ +///////////////// +// Semantic.gs // for Stylus: http://learnboost.github.com/stylus/ +///////////////// + +// Utility function — you should never need to modify this +// _gridsystem-width = (column-width + gutter-width) * columns +gridsystem-width(_columns = columns) + (column-width + gutter-width) * _columns + +// Set @total-width to 100% for a fluid layout +// total-width = gridsystem-width(columns) +total-width = 100% + +////////// +// GRID // +////////// + +body + clearfix() + width: 100% + +row(_columns = columns) + clearfix() + display: block + width: total-width * ((gutter-width + gridsystem-width(_columns)) / gridsystem-width(_columns)) + margin: 0 total-width * (((gutter-width * .5) / gridsystem-width(_columns)) * -1) + +column(x, _columns = columns) + display: inline + float: left + width: total-width * ((((gutter-width + column-width) * x) - gutter-width) / gridsystem-width(_columns)) + margin: 0 total-width * ((gutter-width * .5) / gridsystem-width(_columns)) + +push(offset = 1) + margin-left: total-width * (((gutter-width + column-width) * offset) / gridsystem-width(columns)) + +pull(offset = 1) + margin-right: total-width * (((gutter-width + column-width) * offset) / gridsystem-width(columns)) \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/_util/mixin.styl b/_blog_src/themes/landscape/source/css/_util/mixin.styl new file mode 100644 index 000000000..b56f03778 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_util/mixin.styl @@ -0,0 +1,31 @@ +// http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/ +hide-text() + text-indent: 100% + white-space: nowrap + overflow: hidden + +// http://codepen.io/shshaw/full/gEiDt +absolute-center(width, height = width) + // margin: auto + // position: absolute + // top: 50% + // top: 0 + // left: 0 + // bottom: 0 + // right: 0 + // width: width + // height: height + // overflow: auto + width: width + height: height + position: absolute + top: 50% + left: 50% + margin-top: width * -0.5 + margin-left: height * -0.5 + +avoid-column-break() + vendor("column-break-inside", avoid, only: webkit) + page-break-inside: avoid // for firefox + overflow: hidden // fix for firefox + break-inside: avoid-column diff --git a/_blog_src/themes/landscape/source/css/_variables.styl b/_blog_src/themes/landscape/source/css/_variables.styl new file mode 100644 index 000000000..054ffaf60 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/_variables.styl @@ -0,0 +1,56 @@ +// Colors +color-default = #555 +color-grey = #999 +color-border = #ddd +color-link = #258fb8 +color-background = #eee +color-sidebar-text = #777 +color-widget-background = #ddd +color-widget-border = #ccc +color-footer-background = #262a30 +color-mobile-nav-background = #191919 +color-twitter = #00aced +color-facebook = #3b5998 +color-pinterest = #cb2027 +color-google = #dd4b39 + +// Fonts +font-sans = "Helvetica Neue", Helvetica, Arial, sans-serif +font-serif = Georgia, "Times New Roman", serif +font-mono = "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace +font-icon = FontAwesome +font-icon-path = "fonts/fontawesome-webfont" +font-icon-version = "4.0.3" +font-size = 14px +line-height = 1.6em +line-height-title = 1.1em + +// Header +logo-size = 40px +subtitle-size = 16px +banner-height = 300px +banner-url = "images/banner.jpg" + +sidebar = hexo-config("sidebar") + +// Layout +block-margin = 50px +article-padding = 20px +mobile-nav-width = 280px +main-column = 9 +sidebar-column = 3 + +if sidebar and sidebar isnt bottom + _sidebar-column = sidebar-column +else + _sidebar-column = 0 + +// Grids +column-width = 80px +gutter-width = 20px +columns = main-column + _sidebar-column + +// Media queries +mq-mobile = "screen and (max-width: 479px)" +mq-tablet = "screen and (min-width: 480px) and (max-width: 767px)" +mq-normal = "screen and (min-width: 768px)" \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/fonts/FontAwesome.otf b/_blog_src/themes/landscape/source/css/fonts/FontAwesome.otf new file mode 100644 index 000000000..8b0f54e47 Binary files /dev/null and b/_blog_src/themes/landscape/source/css/fonts/FontAwesome.otf differ diff --git a/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.eot b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..7c79c6a6b Binary files /dev/null and b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.eot differ diff --git a/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.svg b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..45fdf3383 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.ttf b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..e89738de5 Binary files /dev/null and b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.ttf differ diff --git a/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.woff b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..8c1748aab Binary files /dev/null and b/_blog_src/themes/landscape/source/css/fonts/fontawesome-webfont.woff differ diff --git a/_blog_src/themes/landscape/source/css/images/banner.jpg b/_blog_src/themes/landscape/source/css/images/banner.jpg new file mode 100644 index 000000000..c1bd998f7 Binary files /dev/null and b/_blog_src/themes/landscape/source/css/images/banner.jpg differ diff --git a/_blog_src/themes/landscape/source/css/style.styl b/_blog_src/themes/landscape/source/css/style.styl new file mode 100644 index 000000000..ffb0e2a73 --- /dev/null +++ b/_blog_src/themes/landscape/source/css/style.styl @@ -0,0 +1,88 @@ +@import "nib" +@import "_variables" +@import "_util/mixin" +@import "_util/grid" + +global-reset() + +input, button + margin: 0 + padding: 0 + &::-moz-focus-inner + border: 0 + padding: 0 + +@font-face + font-family: FontAwesome + font-style: normal + font-weight: normal + src: url(font-icon-path + ".eot?v=#" + font-icon-version) + src: url(font-icon-path + ".eot?#iefix&v=#" + font-icon-version) format("embedded-opentype"), + url(font-icon-path + ".woff?v=#" + font-icon-version) format("woff"), + url(font-icon-path + ".ttf?v=#" + font-icon-version) format("truetype"), + url(font-icon-path + ".svg#fontawesomeregular?v=#" + font-icon-version) format("svg") + +html, body, #container + height: 100% + +body + background: color-background + font: font-size font-sans + -webkit-text-size-adjust: 100% + +.outer + clearfix() + max-width: (column-width + gutter-width) * columns + gutter-width + margin: 0 auto + padding: 0 gutter-width + +.inner + column(columns) + +.left, .alignleft + float: left + +.right, .alignright + float: right + +.clear + clear: both + +#container + position: relative + +.mobile-nav-on + overflow: hidden + +#wrap + height: 100% + width: 100% + position: absolute + top: 0 + left: 0 + transition: 0.2s ease-out + z-index: 1 + background: color-background + .mobile-nav-on & + left: mobile-nav-width + +if sidebar and sidebar isnt bottom + #main + @media mq-normal + column(main-column) + +if sidebar is left + #main + float: right + +@import "_extend" +@import "_partial/header" +@import "_partial/article" +@import "_partial/comment" +@import "_partial/archive" +@import "_partial/footer" +@import "_partial/highlight" +@import "_partial/mobile" + +if sidebar + @import "_partial/sidebar" \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/blank.gif b/_blog_src/themes/landscape/source/fancybox/blank.gif new file mode 100644 index 000000000..35d42e808 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/blank.gif differ diff --git a/_blog_src/themes/landscape/source/fancybox/fancybox_loading.gif b/_blog_src/themes/landscape/source/fancybox/fancybox_loading.gif new file mode 100644 index 000000000..a03a40c09 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/fancybox_loading.gif differ diff --git a/_blog_src/themes/landscape/source/fancybox/fancybox_loading@2x.gif b/_blog_src/themes/landscape/source/fancybox/fancybox_loading@2x.gif new file mode 100644 index 000000000..9205aeb09 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/fancybox_loading@2x.gif differ diff --git a/_blog_src/themes/landscape/source/fancybox/fancybox_overlay.png b/_blog_src/themes/landscape/source/fancybox/fancybox_overlay.png new file mode 100644 index 000000000..a4391396a Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/fancybox_overlay.png differ diff --git a/_blog_src/themes/landscape/source/fancybox/fancybox_sprite.png b/_blog_src/themes/landscape/source/fancybox/fancybox_sprite.png new file mode 100644 index 000000000..fd8d5ca56 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/fancybox_sprite.png differ diff --git a/_blog_src/themes/landscape/source/fancybox/fancybox_sprite@2x.png b/_blog_src/themes/landscape/source/fancybox/fancybox_sprite@2x.png new file mode 100644 index 000000000..d0e4779f4 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/fancybox_sprite@2x.png differ diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/fancybox_buttons.png b/_blog_src/themes/landscape/source/fancybox/helpers/fancybox_buttons.png new file mode 100644 index 000000000..078720727 Binary files /dev/null and b/_blog_src/themes/landscape/source/fancybox/helpers/fancybox_buttons.png differ diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.css b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.css new file mode 100644 index 000000000..a26273af2 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.css @@ -0,0 +1,97 @@ +#fancybox-buttons { + position: fixed; + left: 0; + width: 100%; + z-index: 8050; +} + +#fancybox-buttons.top { + top: 10px; +} + +#fancybox-buttons.bottom { + bottom: 10px; +} + +#fancybox-buttons ul { + display: block; + width: 166px; + height: 30px; + margin: 0 auto; + padding: 0; + list-style: none; + border: 1px solid #111; + border-radius: 3px; + -webkit-box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); + -moz-box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); + box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); + background: rgb(50,50,50); + background: -moz-linear-gradient(top, rgb(68,68,68) 0%, rgb(52,52,52) 50%, rgb(41,41,41) 50%, rgb(51,51,51) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgb(68,68,68)), color-stop(50%,rgb(52,52,52)), color-stop(50%,rgb(41,41,41)), color-stop(100%,rgb(51,51,51))); + background: -webkit-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); + background: -o-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); + background: -ms-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); + background: linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#444444', endColorstr='#222222',GradientType=0 ); +} + +#fancybox-buttons ul li { + float: left; + margin: 0; + padding: 0; +} + +#fancybox-buttons a { + display: block; + width: 30px; + height: 30px; + text-indent: -9999px; + background-color: transparent; + background-image: url('fancybox_buttons.png'); + background-repeat: no-repeat; + outline: none; + opacity: 0.8; +} + +#fancybox-buttons a:hover { + opacity: 1; +} + +#fancybox-buttons a.btnPrev { + background-position: 5px 0; +} + +#fancybox-buttons a.btnNext { + background-position: -33px 0; + border-right: 1px solid #3e3e3e; +} + +#fancybox-buttons a.btnPlay { + background-position: 0 -30px; +} + +#fancybox-buttons a.btnPlayOn { + background-position: -30px -30px; +} + +#fancybox-buttons a.btnToggle { + background-position: 3px -60px; + border-left: 1px solid #111; + border-right: 1px solid #3e3e3e; + width: 35px +} + +#fancybox-buttons a.btnToggleOn { + background-position: -27px -60px; +} + +#fancybox-buttons a.btnClose { + border-left: 1px solid #111; + width: 35px; + background-position: -56px 0px; +} + +#fancybox-buttons a.btnDisabled { + opacity : 0.4; + cursor: default; +} \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.js b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.js new file mode 100644 index 000000000..352bb5f0d --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-buttons.js @@ -0,0 +1,122 @@ + /*! + * Buttons helper for fancyBox + * version: 1.0.5 (Mon, 15 Oct 2012) + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * helpers : { + * buttons: { + * position : 'top' + * } + * } + * }); + * + */ +;(function ($) { + //Shortcut for fancyBox object + var F = $.fancybox; + + //Add helper object + F.helpers.buttons = { + defaults : { + skipSingle : false, // disables if gallery contains single image + position : 'top', // 'top' or 'bottom' + tpl : '
' + }, + + list : null, + buttons: null, + + beforeLoad: function (opts, obj) { + //Remove self if gallery do not have at least two items + + if (opts.skipSingle && obj.group.length < 2) { + obj.helpers.buttons = false; + obj.closeBtn = true; + + return; + } + + //Increase top margin to give space for buttons + obj.margin[ opts.position === 'bottom' ? 2 : 0 ] += 30; + }, + + onPlayStart: function () { + if (this.buttons) { + this.buttons.play.attr('title', 'Pause slideshow').addClass('btnPlayOn'); + } + }, + + onPlayEnd: function () { + if (this.buttons) { + this.buttons.play.attr('title', 'Start slideshow').removeClass('btnPlayOn'); + } + }, + + afterShow: function (opts, obj) { + var buttons = this.buttons; + + if (!buttons) { + this.list = $(opts.tpl).addClass(opts.position).appendTo('body'); + + buttons = { + prev : this.list.find('.btnPrev').click( F.prev ), + next : this.list.find('.btnNext').click( F.next ), + play : this.list.find('.btnPlay').click( F.play ), + toggle : this.list.find('.btnToggle').click( F.toggle ), + close : this.list.find('.btnClose').click( F.close ) + } + } + + //Prev + if (obj.index > 0 || obj.loop) { + buttons.prev.removeClass('btnDisabled'); + } else { + buttons.prev.addClass('btnDisabled'); + } + + //Next / Play + if (obj.loop || obj.index < obj.group.length - 1) { + buttons.next.removeClass('btnDisabled'); + buttons.play.removeClass('btnDisabled'); + + } else { + buttons.next.addClass('btnDisabled'); + buttons.play.addClass('btnDisabled'); + } + + this.buttons = buttons; + + this.onUpdate(opts, obj); + }, + + onUpdate: function (opts, obj) { + var toggle; + + if (!this.buttons) { + return; + } + + toggle = this.buttons.toggle.removeClass('btnDisabled btnToggleOn'); + + //Size toggle button + if (obj.canShrink) { + toggle.addClass('btnToggleOn'); + + } else if (!obj.canExpand) { + toggle.addClass('btnDisabled'); + } + }, + + beforeClose: function () { + if (this.list) { + this.list.remove(); + } + + this.list = null; + this.buttons = null; + } + }; + +}(jQuery)); diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-media.js b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-media.js new file mode 100644 index 000000000..62737a517 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-media.js @@ -0,0 +1,199 @@ +/*! + * Media helper for fancyBox + * version: 1.0.6 (Fri, 14 Jun 2013) + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * helpers : { + * media: true + * } + * }); + * + * Set custom URL parameters: + * $(".fancybox").fancybox({ + * helpers : { + * media: { + * youtube : { + * params : { + * autoplay : 0 + * } + * } + * } + * } + * }); + * + * Or: + * $(".fancybox").fancybox({, + * helpers : { + * media: true + * }, + * youtube : { + * autoplay: 0 + * } + * }); + * + * Supports: + * + * Youtube + * http://www.youtube.com/watch?v=opj24KnzrWo + * http://www.youtube.com/embed/opj24KnzrWo + * http://youtu.be/opj24KnzrWo + * http://www.youtube-nocookie.com/embed/opj24KnzrWo + * Vimeo + * http://vimeo.com/40648169 + * http://vimeo.com/channels/staffpicks/38843628 + * http://vimeo.com/groups/surrealism/videos/36516384 + * http://player.vimeo.com/video/45074303 + * Metacafe + * http://www.metacafe.com/watch/7635964/dr_seuss_the_lorax_movie_trailer/ + * http://www.metacafe.com/watch/7635964/ + * Dailymotion + * http://www.dailymotion.com/video/xoytqh_dr-seuss-the-lorax-premiere_people + * Twitvid + * http://twitvid.com/QY7MD + * Twitpic + * http://twitpic.com/7p93st + * Instagram + * http://instagr.am/p/IejkuUGxQn/ + * http://instagram.com/p/IejkuUGxQn/ + * Google maps + * http://maps.google.com/maps?q=Eiffel+Tower,+Avenue+Gustave+Eiffel,+Paris,+France&t=h&z=17 + * http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16 + * http://maps.google.com/?ll=48.859463,2.292626&spn=0.000965,0.002642&t=m&z=19&layer=c&cbll=48.859524,2.292532&panoid=YJ0lq28OOy3VT2IqIuVY0g&cbp=12,151.58,,0,-15.56 + */ +;(function ($) { + "use strict"; + + //Shortcut for fancyBox object + var F = $.fancybox, + format = function( url, rez, params ) { + params = params || ''; + + if ( $.type( params ) === "object" ) { + params = $.param(params, true); + } + + $.each(rez, function(key, value) { + url = url.replace( '$' + key, value || '' ); + }); + + if (params.length) { + url += ( url.indexOf('?') > 0 ? '&' : '?' ) + params; + } + + return url; + }; + + //Add helper object + F.helpers.media = { + defaults : { + youtube : { + matcher : /(youtube\.com|youtu\.be|youtube-nocookie\.com)\/(watch\?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*)).*/i, + params : { + autoplay : 1, + autohide : 1, + fs : 1, + rel : 0, + hd : 1, + wmode : 'opaque', + enablejsapi : 1 + }, + type : 'iframe', + url : '//www.youtube.com/embed/$3' + }, + vimeo : { + matcher : /(?:vimeo(?:pro)?.com)\/(?:[^\d]+)?(\d+)(?:.*)/, + params : { + autoplay : 1, + hd : 1, + show_title : 1, + show_byline : 1, + show_portrait : 0, + fullscreen : 1 + }, + type : 'iframe', + url : '//player.vimeo.com/video/$1' + }, + metacafe : { + matcher : /metacafe.com\/(?:watch|fplayer)\/([\w\-]{1,10})/, + params : { + autoPlay : 'yes' + }, + type : 'swf', + url : function( rez, params, obj ) { + obj.swf.flashVars = 'playerVars=' + $.param( params, true ); + + return '//www.metacafe.com/fplayer/' + rez[1] + '/.swf'; + } + }, + dailymotion : { + matcher : /dailymotion.com\/video\/(.*)\/?(.*)/, + params : { + additionalInfos : 0, + autoStart : 1 + }, + type : 'swf', + url : '//www.dailymotion.com/swf/video/$1' + }, + twitvid : { + matcher : /twitvid\.com\/([a-zA-Z0-9_\-\?\=]+)/i, + params : { + autoplay : 0 + }, + type : 'iframe', + url : '//www.twitvid.com/embed.php?guid=$1' + }, + twitpic : { + matcher : /twitpic\.com\/(?!(?:place|photos|events)\/)([a-zA-Z0-9\?\=\-]+)/i, + type : 'image', + url : '//twitpic.com/show/full/$1/' + }, + instagram : { + matcher : /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i, + type : 'image', + url : '//$1/p/$2/media/?size=l' + }, + google_maps : { + matcher : /maps\.google\.([a-z]{2,3}(\.[a-z]{2})?)\/(\?ll=|maps\?)(.*)/i, + type : 'iframe', + url : function( rez ) { + return '//maps.google.' + rez[1] + '/' + rez[3] + '' + rez[4] + '&output=' + (rez[4].indexOf('layer=c') > 0 ? 'svembed' : 'embed'); + } + } + }, + + beforeLoad : function(opts, obj) { + var url = obj.href || '', + type = false, + what, + item, + rez, + params; + + for (what in opts) { + if (opts.hasOwnProperty(what)) { + item = opts[ what ]; + rez = url.match( item.matcher ); + + if (rez) { + type = item.type; + params = $.extend(true, {}, item.params, obj[ what ] || ($.isPlainObject(opts[ what ]) ? opts[ what ].params : null)); + + url = $.type( item.url ) === "function" ? item.url.call( this, rez, params, obj ) : format( item.url, rez, params ); + + break; + } + } + } + + if (type) { + obj.href = url; + obj.type = type; + + obj.autoHeight = false; + } + } + }; + +}(jQuery)); \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.css b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.css new file mode 100644 index 000000000..63d294368 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.css @@ -0,0 +1,55 @@ +#fancybox-thumbs { + position: fixed; + left: 0; + width: 100%; + overflow: hidden; + z-index: 8050; +} + +#fancybox-thumbs.bottom { + bottom: 2px; +} + +#fancybox-thumbs.top { + top: 2px; +} + +#fancybox-thumbs ul { + position: relative; + list-style: none; + margin: 0; + padding: 0; +} + +#fancybox-thumbs ul li { + float: left; + padding: 1px; + opacity: 0.5; +} + +#fancybox-thumbs ul li.active { + opacity: 0.75; + padding: 0; + border: 1px solid #fff; +} + +#fancybox-thumbs ul li:hover { + opacity: 1; +} + +#fancybox-thumbs ul li a { + display: block; + position: relative; + overflow: hidden; + border: 1px solid #222; + background: #111; + outline: none; +} + +#fancybox-thumbs ul li img { + display: block; + position: relative; + border: 0; + padding: 0; + max-width: none; +} \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.js b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.js new file mode 100644 index 000000000..58c971943 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/helpers/jquery.fancybox-thumbs.js @@ -0,0 +1,165 @@ + /*! + * Thumbnail helper for fancyBox + * version: 1.0.7 (Mon, 01 Oct 2012) + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * helpers : { + * thumbs: { + * width : 50, + * height : 50 + * } + * } + * }); + * + */ +;(function ($) { + //Shortcut for fancyBox object + var F = $.fancybox; + + //Add helper object + F.helpers.thumbs = { + defaults : { + width : 50, // thumbnail width + height : 50, // thumbnail height + position : 'bottom', // 'top' or 'bottom' + source : function ( item ) { // function to obtain the URL of the thumbnail image + var href; + + if (item.element) { + href = $(item.element).find('img').attr('src'); + } + + if (!href && item.type === 'image' && item.href) { + href = item.href; + } + + return href; + } + }, + + wrap : null, + list : null, + width : 0, + + init: function (opts, obj) { + var that = this, + list, + thumbWidth = opts.width, + thumbHeight = opts.height, + thumbSource = opts.source; + + //Build list structure + list = ''; + + for (var n = 0; n < obj.group.length; n++) { + list += '
  • '; + } + + this.wrap = $('
    ').addClass(opts.position).appendTo('body'); + this.list = $('').appendTo(this.wrap); + + //Load each thumbnail + $.each(obj.group, function (i) { + var el = obj.group[ i ], + href = thumbSource( el ); + + if (!href) { + return; + } + + $("").load(function () { + var width = this.width, + height = this.height, + widthRatio, heightRatio, parent; + + if (!that.list || !width || !height) { + return; + } + + //Calculate thumbnail width/height and center it + widthRatio = width / thumbWidth; + heightRatio = height / thumbHeight; + + parent = that.list.children().eq(i).find('a'); + + if (widthRatio >= 1 && heightRatio >= 1) { + if (widthRatio > heightRatio) { + width = Math.floor(width / heightRatio); + height = thumbHeight; + + } else { + width = thumbWidth; + height = Math.floor(height / widthRatio); + } + } + + $(this).css({ + width : width, + height : height, + top : Math.floor(thumbHeight / 2 - height / 2), + left : Math.floor(thumbWidth / 2 - width / 2) + }); + + parent.width(thumbWidth).height(thumbHeight); + + $(this).hide().appendTo(parent).fadeIn(300); + + }) + .attr('src', href) + .attr('title', el.title); + }); + + //Set initial width + this.width = this.list.children().eq(0).outerWidth(true); + + this.list.width(this.width * (obj.group.length + 1)).css('left', Math.floor($(window).width() * 0.5 - (obj.index * this.width + this.width * 0.5))); + }, + + beforeLoad: function (opts, obj) { + //Remove self if gallery do not have at least two items + if (obj.group.length < 2) { + obj.helpers.thumbs = false; + + return; + } + + //Increase bottom margin to give space for thumbs + obj.margin[ opts.position === 'top' ? 0 : 2 ] += ((opts.height) + 15); + }, + + afterShow: function (opts, obj) { + //Check if exists and create or update list + if (this.list) { + this.onUpdate(opts, obj); + + } else { + this.init(opts, obj); + } + + //Set active element + this.list.children().removeClass('active').eq(obj.index).addClass('active'); + }, + + //Center list + onUpdate: function (opts, obj) { + if (this.list) { + this.list.stop(true).animate({ + 'left': Math.floor($(window).width() * 0.5 - (obj.index * this.width + this.width * 0.5)) + }, 150); + } + }, + + beforeClose: function () { + if (this.wrap) { + this.wrap.remove(); + } + + this.wrap = null; + this.list = null; + this.width = 0; + } + } + +}(jQuery)); \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.css b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.css new file mode 100644 index 000000000..c75d05135 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.css @@ -0,0 +1,273 @@ +/*! fancyBox v2.1.5 fancyapps.com | fancyapps.com/fancybox/#license */ +.fancybox-wrap, +.fancybox-skin, +.fancybox-outer, +.fancybox-inner, +.fancybox-image, +.fancybox-wrap iframe, +.fancybox-wrap object, +.fancybox-nav, +.fancybox-nav span, +.fancybox-tmp +{ + padding: 0; + margin: 0; + border: 0; + outline: none; + vertical-align: top; +} + +.fancybox-wrap { + position: absolute; + top: 0; + left: 0; + z-index: 8020; +} + +.fancybox-skin { + position: relative; + background: #f9f9f9; + color: #444; + text-shadow: none; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.fancybox-opened { + z-index: 8030; +} + +.fancybox-opened .fancybox-skin { + -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); +} + +.fancybox-outer, .fancybox-inner { + position: relative; +} + +.fancybox-inner { + overflow: hidden; +} + +.fancybox-type-iframe .fancybox-inner { + -webkit-overflow-scrolling: touch; +} + +.fancybox-error { + color: #444; + font: 14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; + margin: 0; + padding: 15px; + white-space: nowrap; +} + +.fancybox-image, .fancybox-iframe { + display: block; + width: 100%; + height: 100%; +} + +.fancybox-image { + max-width: 100%; + max-height: 100%; +} + +#fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span { + background-image: url(fancybox_sprite.png); +} + +#fancybox-loading { + position: fixed; + top: 50%; + left: 50%; + margin-top: -22px; + margin-left: -22px; + background-position: 0 -108px; + opacity: 0.8; + cursor: pointer; + z-index: 8060; +} + +#fancybox-loading div { + width: 44px; + height: 44px; + background: url(fancybox_loading.gif) center center no-repeat; +} + +.fancybox-close { + position: absolute; + top: -18px; + right: -18px; + width: 36px; + height: 36px; + cursor: pointer; + z-index: 8040; +} + +.fancybox-nav { + position: absolute; + top: 0; + width: 40%; + height: 100%; + cursor: pointer; + text-decoration: none; + background: transparent url(blank.gif); /* helps IE */ + -webkit-tap-highlight-color: rgba(0,0,0,0); + z-index: 8040; +} + +.fancybox-prev { + left: 0; +} + +.fancybox-next { + right: 0; +} + +.fancybox-nav span { + position: absolute; + top: 50%; + width: 36px; + height: 34px; + margin-top: -18px; + cursor: pointer; + z-index: 8040; + visibility: hidden; +} + +.fancybox-prev span { + left: 10px; + background-position: 0 -36px; +} + +.fancybox-next span { + right: 10px; + background-position: 0 -72px; +} + +.fancybox-nav:hover span { + visibility: visible; +} + +.fancybox-tmp { + position: absolute; + top: -99999px; + left: -99999px; + max-width: 99999px; + max-height: 99999px; + overflow: visible !important; +} + +/* Overlay helper */ + +.fancybox-lock { + overflow: visible !important; + width: auto; +} + +.fancybox-lock body { + overflow: hidden !important; +} + +.fancybox-lock-test { + overflow-y: hidden !important; +} + +.fancybox-overlay { + position: absolute; + top: 0; + left: 0; + overflow: hidden; + display: none; + z-index: 8010; + background: url(fancybox_overlay.png); +} + +.fancybox-overlay-fixed { + position: fixed; + bottom: 0; + right: 0; +} + +.fancybox-lock .fancybox-overlay { + overflow: auto; + overflow-y: scroll; +} + +/* Title helper */ + +.fancybox-title { + visibility: hidden; + font: normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; + position: relative; + text-shadow: none; + z-index: 8050; +} + +.fancybox-opened .fancybox-title { + visibility: visible; +} + +.fancybox-title-float-wrap { + position: absolute; + bottom: 0; + right: 50%; + margin-bottom: -35px; + z-index: 8050; + text-align: center; +} + +.fancybox-title-float-wrap .child { + display: inline-block; + margin-right: -100%; + padding: 2px 20px; + background: transparent; /* Fallback for web browsers that doesn't support RGBa */ + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + text-shadow: 0 1px 2px #222; + color: #FFF; + font-weight: bold; + line-height: 24px; + white-space: nowrap; +} + +.fancybox-title-outside-wrap { + position: relative; + margin-top: 10px; + color: #fff; +} + +.fancybox-title-inside-wrap { + padding-top: 10px; +} + +.fancybox-title-over-wrap { + position: absolute; + bottom: 0; + left: 0; + color: #fff; + padding: 10px; + background: #000; + background: rgba(0, 0, 0, .8); +} + +/*Retina graphics!*/ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (min--moz-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5){ + + #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span { + background-image: url(fancybox_sprite@2x.png); + background-size: 44px 152px; /*The size of the normal image, half the size of the hi-res image*/ + } + + #fancybox-loading div { + background-image: url(fancybox_loading@2x.gif); + background-size: 24px 24px; /*The size of the normal image, half the size of the hi-res image*/ + } +} \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.js b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.js new file mode 100644 index 000000000..7a0f8acb0 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.js @@ -0,0 +1,2017 @@ +/*! + * fancyBox - jQuery Plugin + * version: 2.1.5 (Fri, 14 Jun 2013) + * requires jQuery v1.6 or later + * + * Examples at http://fancyapps.com/fancybox/ + * License: www.fancyapps.com/fancybox/#license + * + * Copyright 2012 Janis Skarnelis - janis@fancyapps.com + * + */ + +;(function (window, document, $, undefined) { + "use strict"; + + var H = $("html"), + W = $(window), + D = $(document), + F = $.fancybox = function () { + F.open.apply( this, arguments ); + }, + IE = navigator.userAgent.match(/msie/i), + didUpdate = null, + isTouch = document.createTouch !== undefined, + + isQuery = function(obj) { + return obj && obj.hasOwnProperty && obj instanceof $; + }, + isString = function(str) { + return str && $.type(str) === "string"; + }, + isPercentage = function(str) { + return isString(str) && str.indexOf('%') > 0; + }, + isScrollable = function(el) { + return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight))); + }, + getScalar = function(orig, dim) { + var value = parseInt(orig, 10) || 0; + + if (dim && isPercentage(orig)) { + value = F.getViewport()[ dim ] / 100 * value; + } + + return Math.ceil(value); + }, + getValue = function(value, dim) { + return getScalar(value, dim) + 'px'; + }; + + $.extend(F, { + // The current version of fancyBox + version: '2.1.5', + + defaults: { + padding : 15, + margin : 20, + + width : 800, + height : 600, + minWidth : 100, + minHeight : 100, + maxWidth : 9999, + maxHeight : 9999, + pixelRatio: 1, // Set to 2 for retina display support + + autoSize : true, + autoHeight : false, + autoWidth : false, + + autoResize : true, + autoCenter : !isTouch, + fitToView : true, + aspectRatio : false, + topRatio : 0.5, + leftRatio : 0.5, + + scrolling : 'auto', // 'auto', 'yes' or 'no' + wrapCSS : '', + + arrows : true, + closeBtn : true, + closeClick : false, + nextClick : false, + mouseWheel : true, + autoPlay : false, + playSpeed : 3000, + preload : 3, + modal : false, + loop : true, + + ajax : { + dataType : 'html', + headers : { 'X-fancyBox': true } + }, + iframe : { + scrolling : 'auto', + preload : true + }, + swf : { + wmode: 'transparent', + allowfullscreen : 'true', + allowscriptaccess : 'always' + }, + + keys : { + next : { + 13 : 'left', // enter + 34 : 'up', // page down + 39 : 'left', // right arrow + 40 : 'up' // down arrow + }, + prev : { + 8 : 'right', // backspace + 33 : 'down', // page up + 37 : 'right', // left arrow + 38 : 'down' // up arrow + }, + close : [27], // escape key + play : [32], // space - start/stop slideshow + toggle : [70] // letter "f" - toggle fullscreen + }, + + direction : { + next : 'left', + prev : 'right' + }, + + scrollOutside : true, + + // Override some properties + index : 0, + type : null, + href : null, + content : null, + title : null, + + // HTML templates + tpl: { + wrap : '
    ', + image : '', + iframe : '', + error : '

    The requested content cannot be loaded.
    Please try again later.

    ', + closeBtn : '', + next : '', + prev : '' + }, + + // Properties for each animation type + // Opening fancyBox + openEffect : 'fade', // 'elastic', 'fade' or 'none' + openSpeed : 250, + openEasing : 'swing', + openOpacity : true, + openMethod : 'zoomIn', + + // Closing fancyBox + closeEffect : 'fade', // 'elastic', 'fade' or 'none' + closeSpeed : 250, + closeEasing : 'swing', + closeOpacity : true, + closeMethod : 'zoomOut', + + // Changing next gallery item + nextEffect : 'elastic', // 'elastic', 'fade' or 'none' + nextSpeed : 250, + nextEasing : 'swing', + nextMethod : 'changeIn', + + // Changing previous gallery item + prevEffect : 'elastic', // 'elastic', 'fade' or 'none' + prevSpeed : 250, + prevEasing : 'swing', + prevMethod : 'changeOut', + + // Enable default helpers + helpers : { + overlay : true, + title : true + }, + + // Callbacks + onCancel : $.noop, // If canceling + beforeLoad : $.noop, // Before loading + afterLoad : $.noop, // After loading + beforeShow : $.noop, // Before changing in current item + afterShow : $.noop, // After opening + beforeChange : $.noop, // Before changing gallery item + beforeClose : $.noop, // Before closing + afterClose : $.noop // After closing + }, + + //Current state + group : {}, // Selected group + opts : {}, // Group options + previous : null, // Previous element + coming : null, // Element being loaded + current : null, // Currently loaded element + isActive : false, // Is activated + isOpen : false, // Is currently open + isOpened : false, // Have been fully opened at least once + + wrap : null, + skin : null, + outer : null, + inner : null, + + player : { + timer : null, + isActive : false + }, + + // Loaders + ajaxLoad : null, + imgPreload : null, + + // Some collections + transitions : {}, + helpers : {}, + + /* + * Static methods + */ + + open: function (group, opts) { + if (!group) { + return; + } + + if (!$.isPlainObject(opts)) { + opts = {}; + } + + // Close if already active + if (false === F.close(true)) { + return; + } + + // Normalize group + if (!$.isArray(group)) { + group = isQuery(group) ? $(group).get() : [group]; + } + + // Recheck if the type of each element is `object` and set content type (image, ajax, etc) + $.each(group, function(i, element) { + var obj = {}, + href, + title, + content, + type, + rez, + hrefParts, + selector; + + if ($.type(element) === "object") { + // Check if is DOM element + if (element.nodeType) { + element = $(element); + } + + if (isQuery(element)) { + obj = { + href : element.data('fancybox-href') || element.attr('href'), + title : $('
    ').text( element.data('fancybox-title') || element.attr('title') ).html(), + isDom : true, + element : element + }; + + if ($.metadata) { + $.extend(true, obj, element.metadata()); + } + + } else { + obj = element; + } + } + + href = opts.href || obj.href || (isString(element) ? element : null); + title = opts.title !== undefined ? opts.title : obj.title || ''; + + content = opts.content || obj.content; + type = content ? 'html' : (opts.type || obj.type); + + if (!type && obj.isDom) { + type = element.data('fancybox-type'); + + if (!type) { + rez = element.prop('class').match(/fancybox\.(\w+)/); + type = rez ? rez[1] : null; + } + } + + if (isString(href)) { + // Try to guess the content type + if (!type) { + if (F.isImage(href)) { + type = 'image'; + + } else if (F.isSWF(href)) { + type = 'swf'; + + } else if (href.charAt(0) === '#') { + type = 'inline'; + + } else if (isString(element)) { + type = 'html'; + content = element; + } + } + + // Split url into two pieces with source url and content selector, e.g, + // "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id" + if (type === 'ajax') { + hrefParts = href.split(/\s+/, 2); + href = hrefParts.shift(); + selector = hrefParts.shift(); + } + } + + if (!content) { + if (type === 'inline') { + if (href) { + content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 + + } else if (obj.isDom) { + content = element; + } + + } else if (type === 'html') { + content = href; + + } else if (!type && !href && obj.isDom) { + type = 'inline'; + content = element; + } + } + + $.extend(obj, { + href : href, + type : type, + content : content, + title : title, + selector : selector + }); + + group[ i ] = obj; + }); + + // Extend the defaults + F.opts = $.extend(true, {}, F.defaults, opts); + + // All options are merged recursive except keys + if (opts.keys !== undefined) { + F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; + } + + F.group = group; + + return F._start(F.opts.index); + }, + + // Cancel image loading or abort ajax request + cancel: function () { + var coming = F.coming; + + if (coming && false === F.trigger('onCancel')) { + return; + } + + F.hideLoading(); + + if (!coming) { + return; + } + + if (F.ajaxLoad) { + F.ajaxLoad.abort(); + } + + F.ajaxLoad = null; + + if (F.imgPreload) { + F.imgPreload.onload = F.imgPreload.onerror = null; + } + + if (coming.wrap) { + coming.wrap.stop(true, true).trigger('onReset').remove(); + } + + F.coming = null; + + // If the first item has been canceled, then clear everything + if (!F.current) { + F._afterZoomOut( coming ); + } + }, + + // Start closing animation if is open; remove immediately if opening/closing + close: function (event) { + F.cancel(); + + if (false === F.trigger('beforeClose')) { + return; + } + + F.unbindEvents(); + + if (!F.isActive) { + return; + } + + if (!F.isOpen || event === true) { + $('.fancybox-wrap').stop(true).trigger('onReset').remove(); + + F._afterZoomOut(); + + } else { + F.isOpen = F.isOpened = false; + F.isClosing = true; + + $('.fancybox-item, .fancybox-nav').remove(); + + F.wrap.stop(true, true).removeClass('fancybox-opened'); + + F.transitions[ F.current.closeMethod ](); + } + }, + + // Manage slideshow: + // $.fancybox.play(); - toggle slideshow + // $.fancybox.play( true ); - start + // $.fancybox.play( false ); - stop + play: function ( action ) { + var clear = function () { + clearTimeout(F.player.timer); + }, + set = function () { + clear(); + + if (F.current && F.player.isActive) { + F.player.timer = setTimeout(F.next, F.current.playSpeed); + } + }, + stop = function () { + clear(); + + D.unbind('.player'); + + F.player.isActive = false; + + F.trigger('onPlayEnd'); + }, + start = function () { + if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { + F.player.isActive = true; + + D.bind({ + 'onCancel.player beforeClose.player' : stop, + 'onUpdate.player' : set, + 'beforeLoad.player' : clear + }); + + set(); + + F.trigger('onPlayStart'); + } + }; + + if (action === true || (!F.player.isActive && action !== false)) { + start(); + } else { + stop(); + } + }, + + // Navigate to next gallery item + next: function ( direction ) { + var current = F.current; + + if (current) { + if (!isString(direction)) { + direction = current.direction.next; + } + + F.jumpto(current.index + 1, direction, 'next'); + } + }, + + // Navigate to previous gallery item + prev: function ( direction ) { + var current = F.current; + + if (current) { + if (!isString(direction)) { + direction = current.direction.prev; + } + + F.jumpto(current.index - 1, direction, 'prev'); + } + }, + + // Navigate to gallery item by index + jumpto: function ( index, direction, router ) { + var current = F.current; + + if (!current) { + return; + } + + index = getScalar(index); + + F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ]; + F.router = router || 'jumpto'; + + if (current.loop) { + if (index < 0) { + index = current.group.length + (index % current.group.length); + } + + index = index % current.group.length; + } + + if (current.group[ index ] !== undefined) { + F.cancel(); + + F._start(index); + } + }, + + // Center inside viewport and toggle position type to fixed or absolute if needed + reposition: function (e, onlyAbsolute) { + var current = F.current, + wrap = current ? current.wrap : null, + pos; + + if (wrap) { + pos = F._getPosition(onlyAbsolute); + + if (e && e.type === 'scroll') { + delete pos.position; + + wrap.stop(true, true).animate(pos, 200); + + } else { + wrap.css(pos); + + current.pos = $.extend({}, current.dim, pos); + } + } + }, + + update: function (e) { + var type = (e && e.originalEvent && e.originalEvent.type), + anyway = !type || type === 'orientationchange'; + + if (anyway) { + clearTimeout(didUpdate); + + didUpdate = null; + } + + if (!F.isOpen || didUpdate) { + return; + } + + didUpdate = setTimeout(function() { + var current = F.current; + + if (!current || F.isClosing) { + return; + } + + F.wrap.removeClass('fancybox-tmp'); + + if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) { + F._setDimension(); + } + + if (!(type === 'scroll' && current.canShrink)) { + F.reposition(e); + } + + F.trigger('onUpdate'); + + didUpdate = null; + + }, (anyway && !isTouch ? 0 : 300)); + }, + + // Shrink content to fit inside viewport or restore if resized + toggle: function ( action ) { + if (F.isOpen) { + F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView; + + // Help browser to restore document dimensions + if (isTouch) { + F.wrap.removeAttr('style').addClass('fancybox-tmp'); + + F.trigger('onUpdate'); + } + + F.update(); + } + }, + + hideLoading: function () { + D.unbind('.loading'); + + $('#fancybox-loading').remove(); + }, + + showLoading: function () { + var el, viewport; + + F.hideLoading(); + + el = $('
    ').click(F.cancel).appendTo('body'); + + // If user will press the escape-button, the request will be canceled + D.bind('keydown.loading', function(e) { + if ((e.which || e.keyCode) === 27) { + e.preventDefault(); + + F.cancel(); + } + }); + + if (!F.defaults.fixed) { + viewport = F.getViewport(); + + el.css({ + position : 'absolute', + top : (viewport.h * 0.5) + viewport.y, + left : (viewport.w * 0.5) + viewport.x + }); + } + + F.trigger('onLoading'); + }, + + getViewport: function () { + var locked = (F.current && F.current.locked) || false, + rez = { + x: W.scrollLeft(), + y: W.scrollTop() + }; + + if (locked && locked.length) { + rez.w = locked[0].clientWidth; + rez.h = locked[0].clientHeight; + + } else { + // See http://bugs.jquery.com/ticket/6724 + rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width(); + rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height(); + } + + return rez; + }, + + // Unbind the keyboard / clicking actions + unbindEvents: function () { + if (F.wrap && isQuery(F.wrap)) { + F.wrap.unbind('.fb'); + } + + D.unbind('.fb'); + W.unbind('.fb'); + }, + + bindEvents: function () { + var current = F.current, + keys; + + if (!current) { + return; + } + + // Changing document height on iOS devices triggers a 'resize' event, + // that can change document height... repeating infinitely + W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update); + + keys = current.keys; + + if (keys) { + D.bind('keydown.fb', function (e) { + var code = e.which || e.keyCode, + target = e.target || e.srcElement; + + // Skip esc key if loading, because showLoading will cancel preloading + if (code === 27 && F.coming) { + return false; + } + + // Ignore key combinations and key events within form elements + if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { + $.each(keys, function(i, val) { + if (current.group.length > 1 && val[ code ] !== undefined) { + F[ i ]( val[ code ] ); + + e.preventDefault(); + return false; + } + + if ($.inArray(code, val) > -1) { + F[ i ] (); + + e.preventDefault(); + return false; + } + }); + } + }); + } + + if ($.fn.mousewheel && current.mouseWheel) { + F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) { + var target = e.target || null, + parent = $(target), + canScroll = false; + + while (parent.length) { + if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) { + break; + } + + canScroll = isScrollable( parent[0] ); + parent = $(parent).parent(); + } + + if (delta !== 0 && !canScroll) { + if (F.group.length > 1 && !current.canShrink) { + if (deltaY > 0 || deltaX > 0) { + F.prev( deltaY > 0 ? 'down' : 'left' ); + + } else if (deltaY < 0 || deltaX < 0) { + F.next( deltaY < 0 ? 'up' : 'right' ); + } + + e.preventDefault(); + } + } + }); + } + }, + + trigger: function (event, o) { + var ret, obj = o || F.coming || F.current; + + if (obj) { + if ($.isFunction( obj[event] )) { + ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); + } + + if (ret === false) { + return false; + } + + if (obj.helpers) { + $.each(obj.helpers, function (helper, opts) { + if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) { + F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj); + } + }); + } + } + + D.trigger(event); + }, + + isImage: function (str) { + return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); + }, + + isSWF: function (str) { + return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); + }, + + _start: function (index) { + var coming = {}, + obj, + href, + type, + margin, + padding; + + index = getScalar( index ); + obj = F.group[ index ] || null; + + if (!obj) { + return false; + } + + coming = $.extend(true, {}, F.opts, obj); + + // Convert margin and padding properties to array - top, right, bottom, left + margin = coming.margin; + padding = coming.padding; + + if ($.type(margin) === 'number') { + coming.margin = [margin, margin, margin, margin]; + } + + if ($.type(padding) === 'number') { + coming.padding = [padding, padding, padding, padding]; + } + + // 'modal' propery is just a shortcut + if (coming.modal) { + $.extend(true, coming, { + closeBtn : false, + closeClick : false, + nextClick : false, + arrows : false, + mouseWheel : false, + keys : null, + helpers: { + overlay : { + closeClick : false + } + } + }); + } + + // 'autoSize' property is a shortcut, too + if (coming.autoSize) { + coming.autoWidth = coming.autoHeight = true; + } + + if (coming.width === 'auto') { + coming.autoWidth = true; + } + + if (coming.height === 'auto') { + coming.autoHeight = true; + } + + /* + * Add reference to the group, so it`s possible to access from callbacks, example: + * afterLoad : function() { + * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); + * } + */ + + coming.group = F.group; + coming.index = index; + + // Give a chance for callback or helpers to update coming item (type, title, etc) + F.coming = coming; + + if (false === F.trigger('beforeLoad')) { + F.coming = null; + + return; + } + + type = coming.type; + href = coming.href; + + if (!type) { + F.coming = null; + + //If we can not determine content type then drop silently or display next/prev item if looping through gallery + if (F.current && F.router && F.router !== 'jumpto') { + F.current.index = index; + + return F[ F.router ]( F.direction ); + } + + return false; + } + + F.isActive = true; + + if (type === 'image' || type === 'swf') { + coming.autoHeight = coming.autoWidth = false; + coming.scrolling = 'visible'; + } + + if (type === 'image') { + coming.aspectRatio = true; + } + + if (type === 'iframe' && isTouch) { + coming.scrolling = 'scroll'; + } + + // Build the neccessary markup + coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' ); + + $.extend(coming, { + skin : $('.fancybox-skin', coming.wrap), + outer : $('.fancybox-outer', coming.wrap), + inner : $('.fancybox-inner', coming.wrap) + }); + + $.each(["Top", "Right", "Bottom", "Left"], function(i, v) { + coming.skin.css('padding' + v, getValue(coming.padding[ i ])); + }); + + F.trigger('onReady'); + + // Check before try to load; 'inline' and 'html' types need content, others - href + if (type === 'inline' || type === 'html') { + if (!coming.content || !coming.content.length) { + return F._error( 'content' ); + } + + } else if (!href) { + return F._error( 'href' ); + } + + if (type === 'image') { + F._loadImage(); + + } else if (type === 'ajax') { + F._loadAjax(); + + } else if (type === 'iframe') { + F._loadIframe(); + + } else { + F._afterLoad(); + } + }, + + _error: function ( type ) { + $.extend(F.coming, { + type : 'html', + autoWidth : true, + autoHeight : true, + minWidth : 0, + minHeight : 0, + scrolling : 'no', + hasError : type, + content : F.coming.tpl.error + }); + + F._afterLoad(); + }, + + _loadImage: function () { + // Reset preload image so it is later possible to check "complete" property + var img = F.imgPreload = new Image(); + + img.onload = function () { + this.onload = this.onerror = null; + + F.coming.width = this.width / F.opts.pixelRatio; + F.coming.height = this.height / F.opts.pixelRatio; + + F._afterLoad(); + }; + + img.onerror = function () { + this.onload = this.onerror = null; + + F._error( 'image' ); + }; + + img.src = F.coming.href; + + if (img.complete !== true) { + F.showLoading(); + } + }, + + _loadAjax: function () { + var coming = F.coming; + + F.showLoading(); + + F.ajaxLoad = $.ajax($.extend({}, coming.ajax, { + url: coming.href, + error: function (jqXHR, textStatus) { + if (F.coming && textStatus !== 'abort') { + F._error( 'ajax', jqXHR ); + + } else { + F.hideLoading(); + } + }, + success: function (data, textStatus) { + if (textStatus === 'success') { + coming.content = data; + + F._afterLoad(); + } + } + })); + }, + + _loadIframe: function() { + var coming = F.coming, + iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime())) + .attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling) + .attr('src', coming.href); + + // This helps IE + $(coming.wrap).bind('onReset', function () { + try { + $(this).find('iframe').hide().attr('src', '//about:blank').end().empty(); + } catch (e) {} + }); + + if (coming.iframe.preload) { + F.showLoading(); + + iframe.one('load', function() { + $(this).data('ready', 1); + + // iOS will lose scrolling if we resize + if (!isTouch) { + $(this).bind('load.fb', F.update); + } + + // Without this trick: + // - iframe won't scroll on iOS devices + // - IE7 sometimes displays empty iframe + $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show(); + + F._afterLoad(); + }); + } + + coming.content = iframe.appendTo( coming.inner ); + + if (!coming.iframe.preload) { + F._afterLoad(); + } + }, + + _preloadImages: function() { + var group = F.group, + current = F.current, + len = group.length, + cnt = current.preload ? Math.min(current.preload, len - 1) : 0, + item, + i; + + for (i = 1; i <= cnt; i += 1) { + item = group[ (current.index + i ) % len ]; + + if (item.type === 'image' && item.href) { + new Image().src = item.href; + } + } + }, + + _afterLoad: function () { + var coming = F.coming, + previous = F.current, + placeholder = 'fancybox-placeholder', + current, + content, + type, + scrolling, + href, + embed; + + F.hideLoading(); + + if (!coming || F.isActive === false) { + return; + } + + if (false === F.trigger('afterLoad', coming, previous)) { + coming.wrap.stop(true).trigger('onReset').remove(); + + F.coming = null; + + return; + } + + if (previous) { + F.trigger('beforeChange', previous); + + previous.wrap.stop(true).removeClass('fancybox-opened') + .find('.fancybox-item, .fancybox-nav') + .remove(); + } + + F.unbindEvents(); + + current = coming; + content = coming.content; + type = coming.type; + scrolling = coming.scrolling; + + $.extend(F, { + wrap : current.wrap, + skin : current.skin, + outer : current.outer, + inner : current.inner, + current : current, + previous : previous + }); + + href = current.href; + + switch (type) { + case 'inline': + case 'ajax': + case 'html': + if (current.selector) { + content = $('
    ').html(content).find(current.selector); + + } else if (isQuery(content)) { + if (!content.data(placeholder)) { + content.data(placeholder, $('
    ').insertAfter( content ).hide() ); + } + + content = content.show().detach(); + + current.wrap.bind('onReset', function () { + if ($(this).find(content).length) { + content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false); + } + }); + } + break; + + case 'image': + content = current.tpl.image.replace(/\{href\}/g, href); + break; + + case 'swf': + content = ''; + embed = ''; + + $.each(current.swf, function(name, val) { + content += ''; + embed += ' ' + name + '="' + val + '"'; + }); + + content += ''; + break; + } + + if (!(isQuery(content) && content.parent().is(current.inner))) { + current.inner.append( content ); + } + + // Give a chance for helpers or callbacks to update elements + F.trigger('beforeShow'); + + // Set scrolling before calculating dimensions + current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); + + // Set initial dimensions and start position + F._setDimension(); + + F.reposition(); + + F.isOpen = false; + F.coming = null; + + F.bindEvents(); + + if (!F.isOpened) { + $('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove(); + + } else if (previous.prevMethod) { + F.transitions[ previous.prevMethod ](); + } + + F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ](); + + F._preloadImages(); + }, + + _setDimension: function () { + var viewport = F.getViewport(), + steps = 0, + canShrink = false, + canExpand = false, + wrap = F.wrap, + skin = F.skin, + inner = F.inner, + current = F.current, + width = current.width, + height = current.height, + minWidth = current.minWidth, + minHeight = current.minHeight, + maxWidth = current.maxWidth, + maxHeight = current.maxHeight, + scrolling = current.scrolling, + scrollOut = current.scrollOutside ? current.scrollbarWidth : 0, + margin = current.margin, + wMargin = getScalar(margin[1] + margin[3]), + hMargin = getScalar(margin[0] + margin[2]), + wPadding, + hPadding, + wSpace, + hSpace, + origWidth, + origHeight, + origMaxWidth, + origMaxHeight, + ratio, + width_, + height_, + maxWidth_, + maxHeight_, + iframe, + body; + + // Reset dimensions so we could re-check actual size + wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp'); + + wPadding = getScalar(skin.outerWidth(true) - skin.width()); + hPadding = getScalar(skin.outerHeight(true) - skin.height()); + + // Any space between content and viewport (margin, padding, border, title) + wSpace = wMargin + wPadding; + hSpace = hMargin + hPadding; + + origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width; + origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height; + + if (current.type === 'iframe') { + iframe = current.content; + + if (current.autoHeight && iframe.data('ready') === 1) { + try { + if (iframe[0].contentWindow.document.location) { + inner.width( origWidth ).height(9999); + + body = iframe.contents().find('body'); + + if (scrollOut) { + body.css('overflow-x', 'hidden'); + } + + origHeight = body.outerHeight(true); + } + + } catch (e) {} + } + + } else if (current.autoWidth || current.autoHeight) { + inner.addClass( 'fancybox-tmp' ); + + // Set width or height in case we need to calculate only one dimension + if (!current.autoWidth) { + inner.width( origWidth ); + } + + if (!current.autoHeight) { + inner.height( origHeight ); + } + + if (current.autoWidth) { + origWidth = inner.width(); + } + + if (current.autoHeight) { + origHeight = inner.height(); + } + + inner.removeClass( 'fancybox-tmp' ); + } + + width = getScalar( origWidth ); + height = getScalar( origHeight ); + + ratio = origWidth / origHeight; + + // Calculations for the content + minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth); + maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth); + + minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight); + maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight); + + // These will be used to determine if wrap can fit in the viewport + origMaxWidth = maxWidth; + origMaxHeight = maxHeight; + + if (current.fitToView) { + maxWidth = Math.min(viewport.w - wSpace, maxWidth); + maxHeight = Math.min(viewport.h - hSpace, maxHeight); + } + + maxWidth_ = viewport.w - wMargin; + maxHeight_ = viewport.h - hMargin; + + if (current.aspectRatio) { + if (width > maxWidth) { + width = maxWidth; + height = getScalar(width / ratio); + } + + if (height > maxHeight) { + height = maxHeight; + width = getScalar(height * ratio); + } + + if (width < minWidth) { + width = minWidth; + height = getScalar(width / ratio); + } + + if (height < minHeight) { + height = minHeight; + width = getScalar(height * ratio); + } + + } else { + width = Math.max(minWidth, Math.min(width, maxWidth)); + + if (current.autoHeight && current.type !== 'iframe') { + inner.width( width ); + + height = inner.height(); + } + + height = Math.max(minHeight, Math.min(height, maxHeight)); + } + + // Try to fit inside viewport (including the title) + if (current.fitToView) { + inner.width( width ).height( height ); + + wrap.width( width + wPadding ); + + // Real wrap dimensions + width_ = wrap.width(); + height_ = wrap.height(); + + if (current.aspectRatio) { + while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) { + if (steps++ > 19) { + break; + } + + height = Math.max(minHeight, Math.min(maxHeight, height - 10)); + width = getScalar(height * ratio); + + if (width < minWidth) { + width = minWidth; + height = getScalar(width / ratio); + } + + if (width > maxWidth) { + width = maxWidth; + height = getScalar(width / ratio); + } + + inner.width( width ).height( height ); + + wrap.width( width + wPadding ); + + width_ = wrap.width(); + height_ = wrap.height(); + } + + } else { + width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_))); + height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_))); + } + } + + if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) { + width += scrollOut; + } + + inner.width( width ).height( height ); + + wrap.width( width + wPadding ); + + width_ = wrap.width(); + height_ = wrap.height(); + + canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight; + canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight)); + + $.extend(current, { + dim : { + width : getValue( width_ ), + height : getValue( height_ ) + }, + origWidth : origWidth, + origHeight : origHeight, + canShrink : canShrink, + canExpand : canExpand, + wPadding : wPadding, + hPadding : hPadding, + wrapSpace : height_ - skin.outerHeight(true), + skinSpace : skin.height() - height + }); + + if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) { + inner.height('auto'); + } + }, + + _getPosition: function (onlyAbsolute) { + var current = F.current, + viewport = F.getViewport(), + margin = current.margin, + width = F.wrap.width() + margin[1] + margin[3], + height = F.wrap.height() + margin[0] + margin[2], + rez = { + position: 'absolute', + top : margin[0], + left : margin[3] + }; + + if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { + rez.position = 'fixed'; + + } else if (!current.locked) { + rez.top += viewport.y; + rez.left += viewport.x; + } + + rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); + rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * current.leftRatio))); + + return rez; + }, + + _afterZoomIn: function () { + var current = F.current; + + if (!current) { + return; + } + + F.isOpen = F.isOpened = true; + + F.wrap.css('overflow', 'visible').addClass('fancybox-opened').hide().show(0); + + F.update(); + + // Assign a click event + if ( current.closeClick || (current.nextClick && F.group.length > 1) ) { + F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { + if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { + e.preventDefault(); + + F[ current.closeClick ? 'close' : 'next' ](); + } + }); + } + + // Create a close button + if (current.closeBtn) { + $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) { + e.preventDefault(); + + F.close(); + }); + } + + // Create navigation arrows + if (current.arrows && F.group.length > 1) { + if (current.loop || current.index > 0) { + $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); + } + + if (current.loop || current.index < F.group.length - 1) { + $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); + } + } + + F.trigger('afterShow'); + + // Stop the slideshow if this is the last item + if (!current.loop && current.index === current.group.length - 1) { + + F.play( false ); + + } else if (F.opts.autoPlay && !F.player.isActive) { + F.opts.autoPlay = false; + + F.play(true); + } + }, + + _afterZoomOut: function ( obj ) { + obj = obj || F.current; + + $('.fancybox-wrap').trigger('onReset').remove(); + + $.extend(F, { + group : {}, + opts : {}, + router : false, + current : null, + isActive : false, + isOpened : false, + isOpen : false, + isClosing : false, + wrap : null, + skin : null, + outer : null, + inner : null + }); + + F.trigger('afterClose', obj); + } + }); + + /* + * Default transitions + */ + + F.transitions = { + getOrigPosition: function () { + var current = F.current, + element = current.element, + orig = current.orig, + pos = {}, + width = 50, + height = 50, + hPadding = current.hPadding, + wPadding = current.wPadding, + viewport = F.getViewport(); + + if (!orig && current.isDom && element.is(':visible')) { + orig = element.find('img:first'); + + if (!orig.length) { + orig = element; + } + } + + if (isQuery(orig)) { + pos = orig.offset(); + + if (orig.is('img')) { + width = orig.outerWidth(); + height = orig.outerHeight(); + } + + } else { + pos.top = viewport.y + (viewport.h - height) * current.topRatio; + pos.left = viewport.x + (viewport.w - width) * current.leftRatio; + } + + if (F.wrap.css('position') === 'fixed' || current.locked) { + pos.top -= viewport.y; + pos.left -= viewport.x; + } + + pos = { + top : getValue(pos.top - hPadding * current.topRatio), + left : getValue(pos.left - wPadding * current.leftRatio), + width : getValue(width + wPadding), + height : getValue(height + hPadding) + }; + + return pos; + }, + + step: function (now, fx) { + var ratio, + padding, + value, + prop = fx.prop, + current = F.current, + wrapSpace = current.wrapSpace, + skinSpace = current.skinSpace; + + if (prop === 'width' || prop === 'height') { + ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start); + + if (F.isClosing) { + ratio = 1 - ratio; + } + + padding = prop === 'width' ? current.wPadding : current.hPadding; + value = now - padding; + + F.skin[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) ) ); + F.inner[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) ); + } + }, + + zoomIn: function () { + var current = F.current, + startPos = current.pos, + effect = current.openEffect, + elastic = effect === 'elastic', + endPos = $.extend({opacity : 1}, startPos); + + // Remove "position" property that breaks older IE + delete endPos.position; + + if (elastic) { + startPos = this.getOrigPosition(); + + if (current.openOpacity) { + startPos.opacity = 0.1; + } + + } else if (effect === 'fade') { + startPos.opacity = 0.1; + } + + F.wrap.css(startPos).animate(endPos, { + duration : effect === 'none' ? 0 : current.openSpeed, + easing : current.openEasing, + step : elastic ? this.step : null, + complete : F._afterZoomIn + }); + }, + + zoomOut: function () { + var current = F.current, + effect = current.closeEffect, + elastic = effect === 'elastic', + endPos = {opacity : 0.1}; + + if (elastic) { + endPos = this.getOrigPosition(); + + if (current.closeOpacity) { + endPos.opacity = 0.1; + } + } + + F.wrap.animate(endPos, { + duration : effect === 'none' ? 0 : current.closeSpeed, + easing : current.closeEasing, + step : elastic ? this.step : null, + complete : F._afterZoomOut + }); + }, + + changeIn: function () { + var current = F.current, + effect = current.nextEffect, + startPos = current.pos, + endPos = { opacity : 1 }, + direction = F.direction, + distance = 200, + field; + + startPos.opacity = 0.1; + + if (effect === 'elastic') { + field = direction === 'down' || direction === 'up' ? 'top' : 'left'; + + if (direction === 'down' || direction === 'right') { + startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance); + endPos[ field ] = '+=' + distance + 'px'; + + } else { + startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance); + endPos[ field ] = '-=' + distance + 'px'; + } + } + + // Workaround for http://bugs.jquery.com/ticket/12273 + if (effect === 'none') { + F._afterZoomIn(); + + } else { + F.wrap.css(startPos).animate(endPos, { + duration : current.nextSpeed, + easing : current.nextEasing, + complete : F._afterZoomIn + }); + } + }, + + changeOut: function () { + var previous = F.previous, + effect = previous.prevEffect, + endPos = { opacity : 0.1 }, + direction = F.direction, + distance = 200; + + if (effect === 'elastic') { + endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px'; + } + + previous.wrap.animate(endPos, { + duration : effect === 'none' ? 0 : previous.prevSpeed, + easing : previous.prevEasing, + complete : function () { + $(this).trigger('onReset').remove(); + } + }); + } + }; + + /* + * Overlay helper + */ + + F.helpers.overlay = { + defaults : { + closeClick : true, // if true, fancyBox will be closed when user clicks on the overlay + speedOut : 200, // duration of fadeOut animation + showEarly : true, // indicates if should be opened immediately or wait until the content is ready + css : {}, // custom CSS properties + locked : !isTouch, // if true, the content will be locked into overlay + fixed : true // if false, the overlay CSS position property will not be set to "fixed" + }, + + overlay : null, // current handle + fixed : false, // indicates if the overlay has position "fixed" + el : $('html'), // element that contains "the lock" + + // Public methods + create : function(opts) { + var parent; + + opts = $.extend({}, this.defaults, opts); + + if (this.overlay) { + this.close(); + } + + parent = F.coming ? F.coming.parent : opts.parent; + + this.overlay = $('
    ').appendTo( parent && parent.lenth ? parent : 'body' ); + this.fixed = false; + + if (opts.fixed && F.defaults.fixed) { + this.overlay.addClass('fancybox-overlay-fixed'); + + this.fixed = true; + } + }, + + open : function(opts) { + var that = this; + + opts = $.extend({}, this.defaults, opts); + + if (this.overlay) { + this.overlay.unbind('.overlay').width('auto').height('auto'); + + } else { + this.create(opts); + } + + if (!this.fixed) { + W.bind('resize.overlay', $.proxy( this.update, this) ); + + this.update(); + } + + if (opts.closeClick) { + this.overlay.bind('click.overlay', function(e) { + if ($(e.target).hasClass('fancybox-overlay')) { + if (F.isActive) { + F.close(); + } else { + that.close(); + } + + return false; + } + }); + } + + this.overlay.css( opts.css ).show(); + }, + + close : function() { + W.unbind('resize.overlay'); + + if (this.el.hasClass('fancybox-lock')) { + $('.fancybox-margin').removeClass('fancybox-margin'); + + this.el.removeClass('fancybox-lock'); + + W.scrollTop( this.scrollV ).scrollLeft( this.scrollH ); + } + + $('.fancybox-overlay').remove().hide(); + + $.extend(this, { + overlay : null, + fixed : false + }); + }, + + // Private, callbacks + + update : function () { + var width = '100%', offsetWidth; + + // Reset width/height so it will not mess + this.overlay.width(width).height('100%'); + + // jQuery does not return reliable result for IE + if (IE) { + offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); + + if (D.width() > offsetWidth) { + width = D.width(); + } + + } else if (D.width() > W.width()) { + width = D.width(); + } + + this.overlay.width(width).height(D.height()); + }, + + // This is where we can manipulate DOM, because later it would cause iframes to reload + onReady : function (opts, obj) { + var overlay = this.overlay; + + $('.fancybox-overlay').stop(true, true); + + if (!overlay) { + this.create(opts); + } + + if (opts.locked && this.fixed && obj.fixed) { + obj.locked = this.overlay.append( obj.wrap ); + obj.fixed = false; + } + + if (opts.showEarly === true) { + this.beforeShow.apply(this, arguments); + } + }, + + beforeShow : function(opts, obj) { + if (obj.locked && !this.el.hasClass('fancybox-lock')) { + if (this.fixPosition !== false) { + $('*').filter(function(){ + return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") ); + }).addClass('fancybox-margin'); + } + + this.el.addClass('fancybox-margin'); + + this.scrollV = W.scrollTop(); + this.scrollH = W.scrollLeft(); + + this.el.addClass('fancybox-lock'); + + W.scrollTop( this.scrollV ).scrollLeft( this.scrollH ); + } + + this.open(opts); + }, + + onUpdate : function() { + if (!this.fixed) { + this.update(); + } + }, + + afterClose: function (opts) { + // Remove overlay if exists and fancyBox is not opening + // (e.g., it is not being open using afterClose callback) + if (this.overlay && !F.coming) { + this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this )); + } + } + }; + + /* + * Title helper + */ + + F.helpers.title = { + defaults : { + type : 'float', // 'float', 'inside', 'outside' or 'over', + position : 'bottom' // 'top' or 'bottom' + }, + + beforeShow: function (opts) { + var current = F.current, + text = current.title, + type = opts.type, + title, + target; + + if ($.isFunction(text)) { + text = text.call(current.element, current); + } + + if (!isString(text) || $.trim(text) === '') { + return; + } + + title = $('
    ' + text + '
    '); + + switch (type) { + case 'inside': + target = F.skin; + break; + + case 'outside': + target = F.wrap; + break; + + case 'over': + target = F.inner; + break; + + default: // 'float' + target = F.skin; + + title.appendTo('body'); + + if (IE) { + title.width( title.width() ); + } + + title.wrapInner(''); + + //Increase bottom margin so this title will also fit into viewport + F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) ); + break; + } + + title[ (opts.position === 'top' ? 'prependTo' : 'appendTo') ](target); + } + }; + + // jQuery plugin initialization + $.fn.fancybox = function (options) { + var index, + that = $(this), + selector = this.selector || '', + run = function(e) { + var what = $(this).blur(), idx = index, relType, relVal; + + if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) { + relType = options.groupAttr || 'data-fancybox-group'; + relVal = what.attr(relType); + + if (!relVal) { + relType = 'rel'; + relVal = what.get(0)[ relType ]; + } + + if (relVal && relVal !== '' && relVal !== 'nofollow') { + what = selector.length ? $(selector) : that; + what = what.filter('[' + relType + '="' + relVal + '"]'); + idx = what.index(this); + } + + options.index = idx; + + // Stop an event from bubbling if everything is fine + if (F.open(what, options) !== false) { + e.preventDefault(); + } + } + }; + + options = options || {}; + index = options.index || 0; + + if (!selector || options.live === false) { + that.unbind('click.fb-start').bind('click.fb-start', run); + + } else { + D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run); + } + + this.filter('[data-fancybox-start=1]').trigger('click'); + + return this; + }; + + // Tests that need a body at doc ready + D.ready(function() { + var w1, w2; + + if ( $.scrollbarWidth === undefined ) { + // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth + $.scrollbarWidth = function() { + var parent = $('
    ').appendTo('body'), + child = parent.children(), + width = child.innerWidth() - child.height( 99 ).innerWidth(); + + parent.remove(); + + return width; + }; + } + + if ( $.support.fixedPosition === undefined ) { + $.support.fixedPosition = (function() { + var elem = $('
    ').appendTo('body'), + fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 ); + + elem.remove(); + + return fixed; + }()); + } + + $.extend(F.defaults, { + scrollbarWidth : $.scrollbarWidth(), + fixed : $.support.fixedPosition, + parent : $('body') + }); + + //Get real width of page scroll-bar + w1 = $(window).width(); + + H.addClass('fancybox-lock-test'); + + w2 = $(window).width(); + + H.removeClass('fancybox-lock-test'); + + $("").appendTo("head"); + }); + +}(window, document, jQuery)); \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.pack.js b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.pack.js new file mode 100644 index 000000000..2db128084 --- /dev/null +++ b/_blog_src/themes/landscape/source/fancybox/jquery.fancybox.pack.js @@ -0,0 +1,46 @@ +/*! fancyBox v2.1.5 fancyapps.com | fancyapps.com/fancybox/#license */ +(function(s,H,f,w){var K=f("html"),q=f(s),p=f(H),b=f.fancybox=function(){b.open.apply(this,arguments)},J=navigator.userAgent.match(/msie/i),C=null,t=H.createTouch!==w,u=function(a){return a&&a.hasOwnProperty&&a instanceof f},r=function(a){return a&&"string"===f.type(a)},F=function(a){return r(a)&&0
    ',image:'',iframe:'",error:'

    The requested content cannot be loaded.
    Please try again later.

    ',closeBtn:'',next:'',prev:''},openEffect:"fade",openSpeed:250,openEasing:"swing",openOpacity:!0, +openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:250,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",prevSpeed:250,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:!0,title:!0},onCancel:f.noop,beforeLoad:f.noop,afterLoad:f.noop,beforeShow:f.noop,afterShow:f.noop,beforeChange:f.noop,beforeClose:f.noop,afterClose:f.noop},group:{},opts:{},previous:null,coming:null,current:null,isActive:!1, +isOpen:!1,isOpened:!1,wrap:null,skin:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(a,d){if(a&&(f.isPlainObject(d)||(d={}),!1!==b.close(!0)))return f.isArray(a)||(a=u(a)?f(a).get():[a]),f.each(a,function(e,c){var l={},g,h,k,n,m;"object"===f.type(c)&&(c.nodeType&&(c=f(c)),u(c)?(l={href:c.data("fancybox-href")||c.attr("href"),title:f("
    ").text(c.data("fancybox-title")||c.attr("title")).html(),isDom:!0,element:c}, +f.metadata&&f.extend(!0,l,c.metadata())):l=c);g=d.href||l.href||(r(c)?c:null);h=d.title!==w?d.title:l.title||"";n=(k=d.content||l.content)?"html":d.type||l.type;!n&&l.isDom&&(n=c.data("fancybox-type"),n||(n=(n=c.prop("class").match(/fancybox\.(\w+)/))?n[1]:null));r(g)&&(n||(b.isImage(g)?n="image":b.isSWF(g)?n="swf":"#"===g.charAt(0)?n="inline":r(c)&&(n="html",k=c)),"ajax"===n&&(m=g.split(/\s+/,2),g=m.shift(),m=m.shift()));k||("inline"===n?g?k=f(r(g)?g.replace(/.*(?=#[^\s]+$)/,""):g):l.isDom&&(k=c): +"html"===n?k=g:n||g||!l.isDom||(n="inline",k=c));f.extend(l,{href:g,type:n,content:k,title:h,selector:m});a[e]=l}),b.opts=f.extend(!0,{},b.defaults,d),d.keys!==w&&(b.opts.keys=d.keys?f.extend({},b.defaults.keys,d.keys):!1),b.group=a,b._start(b.opts.index)},cancel:function(){var a=b.coming;a&&!1===b.trigger("onCancel")||(b.hideLoading(),a&&(b.ajaxLoad&&b.ajaxLoad.abort(),b.ajaxLoad=null,b.imgPreload&&(b.imgPreload.onload=b.imgPreload.onerror=null),a.wrap&&a.wrap.stop(!0,!0).trigger("onReset").remove(), +b.coming=null,b.current||b._afterZoomOut(a)))},close:function(a){b.cancel();!1!==b.trigger("beforeClose")&&(b.unbindEvents(),b.isActive&&(b.isOpen&&!0!==a?(b.isOpen=b.isOpened=!1,b.isClosing=!0,f(".fancybox-item, .fancybox-nav").remove(),b.wrap.stop(!0,!0).removeClass("fancybox-opened"),b.transitions[b.current.closeMethod]()):(f(".fancybox-wrap").stop(!0).trigger("onReset").remove(),b._afterZoomOut())))},play:function(a){var d=function(){clearTimeout(b.player.timer)},e=function(){d();b.current&&b.player.isActive&& +(b.player.timer=setTimeout(b.next,b.current.playSpeed))},c=function(){d();p.unbind(".player");b.player.isActive=!1;b.trigger("onPlayEnd")};!0===a||!b.player.isActive&&!1!==a?b.current&&(b.current.loop||b.current.index=c.index?"next":"prev"],b.router=e||"jumpto",c.loop&&(0>a&&(a=c.group.length+a%c.group.length),a%=c.group.length),c.group[a]!==w&&(b.cancel(),b._start(a)))},reposition:function(a,d){var e=b.current,c=e?e.wrap:null,l;c&&(l=b._getPosition(d),a&&"scroll"===a.type?(delete l.position,c.stop(!0,!0).animate(l,200)):(c.css(l),e.pos=f.extend({},e.dim,l)))}, +update:function(a){var d=a&&a.originalEvent&&a.originalEvent.type,e=!d||"orientationchange"===d;e&&(clearTimeout(C),C=null);b.isOpen&&!C&&(C=setTimeout(function(){var c=b.current;c&&!b.isClosing&&(b.wrap.removeClass("fancybox-tmp"),(e||"load"===d||"resize"===d&&c.autoResize)&&b._setDimension(),"scroll"===d&&c.canShrink||b.reposition(a),b.trigger("onUpdate"),C=null)},e&&!t?0:300))},toggle:function(a){b.isOpen&&(b.current.fitToView="boolean"===f.type(a)?a:!b.current.fitToView,t&&(b.wrap.removeAttr("style").addClass("fancybox-tmp"), +b.trigger("onUpdate")),b.update())},hideLoading:function(){p.unbind(".loading");f("#fancybox-loading").remove()},showLoading:function(){var a,d;b.hideLoading();a=f('
    ').click(b.cancel).appendTo("body");p.bind("keydown.loading",function(a){27===(a.which||a.keyCode)&&(a.preventDefault(),b.cancel())});b.defaults.fixed||(d=b.getViewport(),a.css({position:"absolute",top:0.5*d.h+d.y,left:0.5*d.w+d.x}));b.trigger("onLoading")},getViewport:function(){var a=b.current&& +b.current.locked||!1,d={x:q.scrollLeft(),y:q.scrollTop()};a&&a.length?(d.w=a[0].clientWidth,d.h=a[0].clientHeight):(d.w=t&&s.innerWidth?s.innerWidth:q.width(),d.h=t&&s.innerHeight?s.innerHeight:q.height());return d},unbindEvents:function(){b.wrap&&u(b.wrap)&&b.wrap.unbind(".fb");p.unbind(".fb");q.unbind(".fb")},bindEvents:function(){var a=b.current,d;a&&(q.bind("orientationchange.fb"+(t?"":" resize.fb")+(a.autoCenter&&!a.locked?" scroll.fb":""),b.update),(d=a.keys)&&p.bind("keydown.fb",function(e){var c= +e.which||e.keyCode,l=e.target||e.srcElement;if(27===c&&b.coming)return!1;e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||l&&(l.type||f(l).is("[contenteditable]"))||f.each(d,function(d,l){if(1h[0].clientWidth||h[0].clientHeight&&h[0].scrollHeight>h[0].clientHeight),h=f(h).parent();0!==c&&!k&&1g||0>l)&&b.next(0>g?"up":"right"),d.preventDefault())}))},trigger:function(a,d){var e,c=d||b.coming||b.current;if(c){f.isFunction(c[a])&&(e=c[a].apply(c,Array.prototype.slice.call(arguments,1)));if(!1===e)return!1;c.helpers&&f.each(c.helpers,function(d,e){if(e&& +b.helpers[d]&&f.isFunction(b.helpers[d][a]))b.helpers[d][a](f.extend(!0,{},b.helpers[d].defaults,e),c)})}p.trigger(a)},isImage:function(a){return r(a)&&a.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i)},isSWF:function(a){return r(a)&&a.match(/\.(swf)((\?|#).*)?$/i)},_start:function(a){var d={},e,c;a=m(a);e=b.group[a]||null;if(!e)return!1;d=f.extend(!0,{},b.opts,e);e=d.margin;c=d.padding;"number"===f.type(e)&&(d.margin=[e,e,e,e]);"number"===f.type(c)&&(d.padding=[c,c, +c,c]);d.modal&&f.extend(!0,d,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{closeClick:!1}}});d.autoSize&&(d.autoWidth=d.autoHeight=!0);"auto"===d.width&&(d.autoWidth=!0);"auto"===d.height&&(d.autoHeight=!0);d.group=b.group;d.index=a;b.coming=d;if(!1===b.trigger("beforeLoad"))b.coming=null;else{c=d.type;e=d.href;if(!c)return b.coming=null,b.current&&b.router&&"jumpto"!==b.router?(b.current.index=a,b[b.router](b.direction)):!1;b.isActive=!0;if("image"=== +c||"swf"===c)d.autoHeight=d.autoWidth=!1,d.scrolling="visible";"image"===c&&(d.aspectRatio=!0);"iframe"===c&&t&&(d.scrolling="scroll");d.wrap=f(d.tpl.wrap).addClass("fancybox-"+(t?"mobile":"desktop")+" fancybox-type-"+c+" fancybox-tmp "+d.wrapCSS).appendTo(d.parent||"body");f.extend(d,{skin:f(".fancybox-skin",d.wrap),outer:f(".fancybox-outer",d.wrap),inner:f(".fancybox-inner",d.wrap)});f.each(["Top","Right","Bottom","Left"],function(a,b){d.skin.css("padding"+b,x(d.padding[a]))});b.trigger("onReady"); +if("inline"===c||"html"===c){if(!d.content||!d.content.length)return b._error("content")}else if(!e)return b._error("href");"image"===c?b._loadImage():"ajax"===c?b._loadAjax():"iframe"===c?b._loadIframe():b._afterLoad()}},_error:function(a){f.extend(b.coming,{type:"html",autoWidth:!0,autoHeight:!0,minWidth:0,minHeight:0,scrolling:"no",hasError:a,content:b.coming.tpl.error});b._afterLoad()},_loadImage:function(){var a=b.imgPreload=new Image;a.onload=function(){this.onload=this.onerror=null;b.coming.width= +this.width/b.opts.pixelRatio;b.coming.height=this.height/b.opts.pixelRatio;b._afterLoad()};a.onerror=function(){this.onload=this.onerror=null;b._error("image")};a.src=b.coming.href;!0!==a.complete&&b.showLoading()},_loadAjax:function(){var a=b.coming;b.showLoading();b.ajaxLoad=f.ajax(f.extend({},a.ajax,{url:a.href,error:function(a,e){b.coming&&"abort"!==e?b._error("ajax",a):b.hideLoading()},success:function(d,e){"success"===e&&(a.content=d,b._afterLoad())}}))},_loadIframe:function(){var a=b.coming, +d=f(a.tpl.iframe.replace(/\{rnd\}/g,(new Date).getTime())).attr("scrolling",t?"auto":a.iframe.scrolling).attr("src",a.href);f(a.wrap).bind("onReset",function(){try{f(this).find("iframe").hide().attr("src","//about:blank").end().empty()}catch(a){}});a.iframe.preload&&(b.showLoading(),d.one("load",function(){f(this).data("ready",1);t||f(this).bind("load.fb",b.update);f(this).parents(".fancybox-wrap").width("100%").removeClass("fancybox-tmp").show();b._afterLoad()}));a.content=d.appendTo(a.inner);a.iframe.preload|| +b._afterLoad()},_preloadImages:function(){var a=b.group,d=b.current,e=a.length,c=d.preload?Math.min(d.preload,e-1):0,f,g;for(g=1;g<=c;g+=1)f=a[(d.index+g)%e],"image"===f.type&&f.href&&((new Image).src=f.href)},_afterLoad:function(){var a=b.coming,d=b.current,e,c,l,g,h;b.hideLoading();if(a&&!1!==b.isActive)if(!1===b.trigger("afterLoad",a,d))a.wrap.stop(!0).trigger("onReset").remove(),b.coming=null;else{d&&(b.trigger("beforeChange",d),d.wrap.stop(!0).removeClass("fancybox-opened").find(".fancybox-item, .fancybox-nav").remove()); +b.unbindEvents();e=a.content;c=a.type;l=a.scrolling;f.extend(b,{wrap:a.wrap,skin:a.skin,outer:a.outer,inner:a.inner,current:a,previous:d});g=a.href;switch(c){case "inline":case "ajax":case "html":a.selector?e=f("
    ").html(e).find(a.selector):u(e)&&(e.data("fancybox-placeholder")||e.data("fancybox-placeholder",f('
    ').insertAfter(e).hide()),e=e.show().detach(),a.wrap.bind("onReset",function(){f(this).find(e).length&&e.hide().replaceAll(e.data("fancybox-placeholder")).data("fancybox-placeholder", +!1)}));break;case "image":e=a.tpl.image.replace(/\{href\}/g,g);break;case "swf":e='',h="",f.each(a.swf,function(a,b){e+='';h+=" "+a+'="'+b+'"'}),e+='"}u(e)&&e.parent().is(a.inner)||a.inner.append(e);b.trigger("beforeShow"); +a.inner.css("overflow","yes"===l?"scroll":"no"===l?"hidden":l);b._setDimension();b.reposition();b.isOpen=!1;b.coming=null;b.bindEvents();if(!b.isOpened)f(".fancybox-wrap").not(a.wrap).stop(!0).trigger("onReset").remove();else if(d.prevMethod)b.transitions[d.prevMethod]();b.transitions[b.isOpened?a.nextMethod:a.openMethod]();b._preloadImages()}},_setDimension:function(){var a=b.getViewport(),d=0,e=!1,c=!1,e=b.wrap,l=b.skin,g=b.inner,h=b.current,c=h.width,k=h.height,n=h.minWidth,v=h.minHeight,p=h.maxWidth, +q=h.maxHeight,t=h.scrolling,r=h.scrollOutside?h.scrollbarWidth:0,y=h.margin,z=m(y[1]+y[3]),s=m(y[0]+y[2]),w,A,u,D,B,G,C,E,I;e.add(l).add(g).width("auto").height("auto").removeClass("fancybox-tmp");y=m(l.outerWidth(!0)-l.width());w=m(l.outerHeight(!0)-l.height());A=z+y;u=s+w;D=F(c)?(a.w-A)*m(c)/100:c;B=F(k)?(a.h-u)*m(k)/100:k;if("iframe"===h.type){if(I=h.content,h.autoHeight&&1===I.data("ready"))try{I[0].contentWindow.document.location&&(g.width(D).height(9999),G=I.contents().find("body"),r&&G.css("overflow-x", +"hidden"),B=G.outerHeight(!0))}catch(H){}}else if(h.autoWidth||h.autoHeight)g.addClass("fancybox-tmp"),h.autoWidth||g.width(D),h.autoHeight||g.height(B),h.autoWidth&&(D=g.width()),h.autoHeight&&(B=g.height()),g.removeClass("fancybox-tmp");c=m(D);k=m(B);E=D/B;n=m(F(n)?m(n,"w")-A:n);p=m(F(p)?m(p,"w")-A:p);v=m(F(v)?m(v,"h")-u:v);q=m(F(q)?m(q,"h")-u:q);G=p;C=q;h.fitToView&&(p=Math.min(a.w-A,p),q=Math.min(a.h-u,q));A=a.w-z;s=a.h-s;h.aspectRatio?(c>p&&(c=p,k=m(c/E)),k>q&&(k=q,c=m(k*E)),cA||z>s)&&c>n&&k>v&&!(19p&&(c=p,k=m(c/E)),g.width(c).height(k),e.width(c+y),a=e.width(),z=e.height();else c=Math.max(n,Math.min(c,c-(a-A))),k=Math.max(v,Math.min(k,k-(z-s)));r&&"auto"===t&&kA||z>s)&&c>n&&k>v;c=h.aspectRatio?cv&&k
    ').appendTo(d&&d.lenth?d:"body");this.fixed=!1;a.fixed&&b.defaults.fixed&&(this.overlay.addClass("fancybox-overlay-fixed"),this.fixed=!0)},open:function(a){var d=this;a=f.extend({},this.defaults,a);this.overlay?this.overlay.unbind(".overlay").width("auto").height("auto"):this.create(a);this.fixed||(q.bind("resize.overlay",f.proxy(this.update,this)),this.update());a.closeClick&&this.overlay.bind("click.overlay", +function(a){if(f(a.target).hasClass("fancybox-overlay"))return b.isActive?b.close():d.close(),!1});this.overlay.css(a.css).show()},close:function(){q.unbind("resize.overlay");this.el.hasClass("fancybox-lock")&&(f(".fancybox-margin").removeClass("fancybox-margin"),this.el.removeClass("fancybox-lock"),q.scrollTop(this.scrollV).scrollLeft(this.scrollH));f(".fancybox-overlay").remove().hide();f.extend(this,{overlay:null,fixed:!1})},update:function(){var a="100%",b;this.overlay.width(a).height("100%"); +J?(b=Math.max(H.documentElement.offsetWidth,H.body.offsetWidth),p.width()>b&&(a=p.width())):p.width()>q.width()&&(a=p.width());this.overlay.width(a).height(p.height())},onReady:function(a,b){var e=this.overlay;f(".fancybox-overlay").stop(!0,!0);e||this.create(a);a.locked&&this.fixed&&b.fixed&&(b.locked=this.overlay.append(b.wrap),b.fixed=!1);!0===a.showEarly&&this.beforeShow.apply(this,arguments)},beforeShow:function(a,b){b.locked&&!this.el.hasClass("fancybox-lock")&&(!1!==this.fixPosition&&f("*").filter(function(){return"fixed"=== +f(this).css("position")&&!f(this).hasClass("fancybox-overlay")&&!f(this).hasClass("fancybox-wrap")}).addClass("fancybox-margin"),this.el.addClass("fancybox-margin"),this.scrollV=q.scrollTop(),this.scrollH=q.scrollLeft(),this.el.addClass("fancybox-lock"),q.scrollTop(this.scrollV).scrollLeft(this.scrollH));this.open(a)},onUpdate:function(){this.fixed||this.update()},afterClose:function(a){this.overlay&&!b.coming&&this.overlay.fadeOut(a.speedOut,f.proxy(this.close,this))}};b.helpers.title={defaults:{type:"float", +position:"bottom"},beforeShow:function(a){var d=b.current,e=d.title,c=a.type;f.isFunction(e)&&(e=e.call(d.element,d));if(r(e)&&""!==f.trim(e)){d=f('
    '+e+"
    ");switch(c){case "inside":c=b.skin;break;case "outside":c=b.wrap;break;case "over":c=b.inner;break;default:c=b.skin,d.appendTo("body"),J&&d.width(d.width()),d.wrapInner(''),b.current.margin[2]+=Math.abs(m(d.css("margin-bottom")))}d["top"===a.position?"prependTo": +"appendTo"](c)}}};f.fn.fancybox=function(a){var d,e=f(this),c=this.selector||"",l=function(g){var h=f(this).blur(),k=d,l,m;g.ctrlKey||g.altKey||g.shiftKey||g.metaKey||h.is(".fancybox-wrap")||(l=a.groupAttr||"data-fancybox-group",m=h.attr(l),m||(l="rel",m=h.get(0)[l]),m&&""!==m&&"nofollow"!==m&&(h=c.length?f(c):e,h=h.filter("["+l+'="'+m+'"]'),k=h.index(this)),a.index=k,!1!==b.open(h,a)&&g.preventDefault())};a=a||{};d=a.index||0;c&&!1!==a.live?p.undelegate(c,"click.fb-start").delegate(c+":not('.fancybox-item, .fancybox-nav')", +"click.fb-start",l):e.unbind("click.fb-start").bind("click.fb-start",l);this.filter("[data-fancybox-start=1]").trigger("click");return this};p.ready(function(){var a,d;f.scrollbarWidth===w&&(f.scrollbarWidth=function(){var a=f('
    ').appendTo("body"),b=a.children(),b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});f.support.fixedPosition===w&&(f.support.fixedPosition=function(){var a=f('
    ').appendTo("body"), +b=20===a[0].offsetTop||15===a[0].offsetTop;a.remove();return b}());f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")});a=f(s).width();K.addClass("fancybox-lock-test");d=f(s).width();K.removeClass("fancybox-lock-test");f("").appendTo("head")})})(window,document,jQuery); \ No newline at end of file diff --git a/_blog_src/themes/landscape/source/js/script.js b/_blog_src/themes/landscape/source/js/script.js new file mode 100644 index 000000000..1e5876745 --- /dev/null +++ b/_blog_src/themes/landscape/source/js/script.js @@ -0,0 +1,137 @@ +(function($){ + // Search + var $searchWrap = $('#search-form-wrap'), + isSearchAnim = false, + searchAnimDuration = 200; + + var startSearchAnim = function(){ + isSearchAnim = true; + }; + + var stopSearchAnim = function(callback){ + setTimeout(function(){ + isSearchAnim = false; + callback && callback(); + }, searchAnimDuration); + }; + + $('#nav-search-btn').on('click', function(){ + if (isSearchAnim) return; + + startSearchAnim(); + $searchWrap.addClass('on'); + stopSearchAnim(function(){ + $('.search-form-input').focus(); + }); + }); + + $('.search-form-input').on('blur', function(){ + startSearchAnim(); + $searchWrap.removeClass('on'); + stopSearchAnim(); + }); + + // Share + $('body').on('click', function(){ + $('.article-share-box.on').removeClass('on'); + }).on('click', '.article-share-link', function(e){ + e.stopPropagation(); + + var $this = $(this), + url = $this.attr('data-url'), + encodedUrl = encodeURIComponent(url), + id = 'article-share-box-' + $this.attr('data-id'), + offset = $this.offset(); + + if ($('#' + id).length){ + var box = $('#' + id); + + if (box.hasClass('on')){ + box.removeClass('on'); + return; + } + } else { + var html = [ + '
    ', + '', + '
    ', + '', + '', + '', + '', + '
    ', + '
    ' + ].join(''); + + var box = $(html); + + $('body').append(box); + } + + $('.article-share-box.on').hide(); + + box.css({ + top: offset.top + 25, + left: offset.left + }).addClass('on'); + }).on('click', '.article-share-box', function(e){ + e.stopPropagation(); + }).on('click', '.article-share-box-input', function(){ + $(this).select(); + }).on('click', '.article-share-box-link', function(e){ + e.preventDefault(); + e.stopPropagation(); + + window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450'); + }); + + // Caption + $('.article-entry').each(function(i){ + $(this).find('img').each(function(){ + if ($(this).parent().hasClass('fancybox')) return; + + var alt = this.alt; + + if (alt) $(this).after('' + alt + ''); + + $(this).wrap(''); + }); + + $(this).find('.fancybox').each(function(){ + $(this).attr('rel', 'article' + i); + }); + }); + + if ($.fancybox){ + $('.fancybox').fancybox(); + } + + // Mobile nav + var $container = $('#container'), + isMobileNavAnim = false, + mobileNavAnimDuration = 200; + + var startMobileNavAnim = function(){ + isMobileNavAnim = true; + }; + + var stopMobileNavAnim = function(){ + setTimeout(function(){ + isMobileNavAnim = false; + }, mobileNavAnimDuration); + } + + $('#main-nav-toggle').on('click', function(){ + if (isMobileNavAnim) return; + + startMobileNavAnim(); + $container.toggleClass('mobile-nav-on'); + stopMobileNavAnim(); + }); + + $('#wrap').on('click', function(){ + if (isMobileNavAnim || !$container.hasClass('mobile-nav-on')) return; + + $container.removeClass('mobile-nav-on'); + }); +})(jQuery); \ No newline at end of file diff --git a/blog/6_ways_to_take_control_of_how_your_grid_data_is_displayed/index.html b/blog/6_ways_to_take_control_of_how_your_grid_data_is_displayed/index.html new file mode 100644 index 000000000..bdfc0c6d3 --- /dev/null +++ b/blog/6_ways_to_take_control_of_how_your_grid_data_is_displayed/index.html @@ -0,0 +1,249 @@ + + + + + + + + + + + + 6 Ways to Take Control of How Your Grid Data is Displayed | UI Grid + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + + + + Back to main page + + + +

    6 Ways to Take Control of How Your Grid Data is Displayed

    + +
    + +
    + +

    Getting your data displayed just right can be a huge pain.

    +

    You might just want to format some numbers, or you might want to embed something complex like a chart or custom directive.

    +

    In this post outline six different methods you can use to get your data just the way you want it:

    +
      +
    • Bindings
    • +
    • Cell Filters
    • +
    • Cell Templates
        +
      • Links
      • +
      • Buttons
      • +
      • Custom directives
      • +
      +
    • +
    +

    Bindings

    +

    UI Grid columns can be bound to any sort of Angular expression, as well as property names that would normally break an expression:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var columnDefs = [
    { field: 'name' },
    { field: 'addresses[0]' },
    /*
    Yes, you can use hyphens, plus signs, etc.
    Normally something like {{ row.entity.first-name }} would
    bomb but UI Grid pre-processes your bindings to make sure they work correctly.
    */
    { field: 'first-name' },
    /* Function expressions work too */
    { field: 'getCurrency()' },
    { field: 'transformValue(row.entity.myField)' },
    /* Plain old functions are also an option */
    { field: function () { return this.address.zip; } }
    ];
    + +

    Cell Filters

    +

    Cell filters can transform the displayed value for a column while leaving the model intact. In this plunker the amount column contains floating point values, but we only want to display the integer part. A simple cellFilter that uses .toFixed() will alter the displayed value the way we want.

    + + +

    Passing Arguments

    +

    In the third column I am using two different fields. The column itself is bound to the same field as the second column, but on the filter I am passing the scope like so: cellFilter: 'currencyFilter:this'. Using the this argument on your filter will pass the scope.

    +

    Then I can lookup the currency symbol I want using the currency field from the row.

    +

    If you double-click a cell in the Currency column you’ll see that the raw value is still available to be edited. Cell filters only change your displayed value!

    +

    Cell Templates

    +

    Column definitions take a cellTemplate argument you can use to give your cells a custom template. You can specify it a few different ways, with a url (relative or absolute), an Angular template ID, a string/Angular element, or a promise.

    +
    1
    2
    3
    4
    5
    var columnDefs = [
    { field: 'name', cellTemplate: 'name-template.html' },
    { field: 'name', cellTemplate: 'myTemplateId' },
    { field: 'name', cellTemplate: $.get('url-to-your-template.html') }
    ];
    + +

    Bindings in Cell Templates

    +

    There are a couple options for your binding your row’s data in your template. You can access the row object which is in the local scope; row.entity will contain the reference to your object, so if you want the “name” field, you can bind like so: .

    +

    If you’ve already defined your binding in your column definition you can use one of UI Grid’s placeholders: {{ COL_FIELD }}. UI Grid will automatically replace COL_FIELD with the appropriate binding. If you need to two-way bind to your row, like when you’re using the edit feature, you’ll need to use the MODEL_COL_FIELD placeholder.

    +
    1
    2
    3
    4
    5
    6
    var columnDefs = [
    {
    field: 'image_url',
    cellTemplate: '<div class="ui-grid-cell-contents"><img src="{{ COL_FIELD }}" /></div>'
    }
    ];
    + + +

    Links are simple, just use regular old HTML. Wrapping your cell in an element using the class .ui-grid-cell-contents will apply the proper CSS settings like padding, overflow, etc., and make sure your cell fits in its space nicely.

    +
    1
    2
    3
    4
    5
    6
    var columnDefs = [
    {
    field: 'email',
    cellTemplate: '<div class="ui-grid-cell-contents"><a href="mailto:{{ COL_FIELD }}">Send E-Mail</a></div>'
    }
    ];
    + +

    In the plunker below I’m using a basic cellTemplate to bind both the first and last name fields into one column. On the second column I’m using a simple link like above (note: none of these emails are real).

    +

    On the third one, I’m using a template that’s referenced in index.html. If you check the bottom of that file you’ll see the template inside a <script type="text/ng-template"> tag. Any tags of that type will put automatically put into the template cache ($templateCache) by Angular, with the id you specify.

    +

    Also in the third column template you can see I’m using a variable called grid.appScope. Anywhere in your templates, grid.appScope will be bound to the parent scope of your grid. I use it to bind my button to a function in my controller that will open a new window with a url to google maps with the address in it (note: most if not all of these address will not exist).

    + + +

    Tooltips

    +

    Tooltips are a little bit different because they float over your content. By default the grid’s cells are set to hide any overflow, so if you just pop a tooltip in there it won’t show up and you’ll probably be very confused. If you just add some custom overflow CSS it should fix your problem.

    +

    Hover over the names in the plunker below:

    + + +

    Tooltips cannot overflow beyond the constraints of the viewport, so they won’t show above the first row or below the bottom row, for example.

    +

    Custom Directives

    +

    You can put absolutely anything in your cell templates, just remember to use .ui-grid-cell-contents if you’re not applying your own custom cell CSS.

    + + +

    Here I’ve used d3.js, nvd3.js, and angular-nvd3.js to create sparkline charts in my cells.

    +

    Summin’ it up

    +

    You should be able to do the vast majority of what you want with your data using these six methods. If you have questions, suggestions, or just want to say hi, drop in to our gitter channel; we’d love to meet you!

    + + + +
    + + +
    +
    +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/archives/2015/02/index.html b/blog/archives/2015/02/index.html new file mode 100644 index 000000000..894d4417d --- /dev/null +++ b/blog/archives/2015/02/index.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + Archives: 2015/2 | UI Grid + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/archives/2015/index.html b/blog/archives/2015/index.html new file mode 100644 index 000000000..66b8eccd7 --- /dev/null +++ b/blog/archives/2015/index.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + Archives: 2015 | UI Grid + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/archives/index.html b/blog/archives/index.html new file mode 100644 index 000000000..a4dd6d436 --- /dev/null +++ b/blog/archives/index.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + Archives | UI Grid + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/atom.xml b/blog/atom.xml new file mode 100644 index 000000000..e43a63169 --- /dev/null +++ b/blog/atom.xml @@ -0,0 +1,93 @@ + + + <![CDATA[UI Grid]]> + + + + 2015-03-10T02:33:43.176Z + http://ui-grid.info/blog/ + + + + + + + Hexo + + + <![CDATA[6 Ways to Take Control of How Your Grid Data is Displayed]]> + + http://ui-grid.info/blog/6_ways_to_take_control_of_how_your_grid_data_is_displayed/ + 2015-02-27T16:55:01.000Z + 2015-03-10T02:18:34.000Z + +

    Getting your data displayed just right can be a huge pain.

    +

    You might just want to format some numbers, or you might want to embed something complex like a chart or custom directive.

    +

    In this post outline six different methods you can use to get your data just the way you want it:

    +
      +
    • Bindings
    • +
    • Cell Filters
    • +
    • Cell Templates
        +
      • Links
      • +
      • Buttons
      • +
      • Custom directives
      • +
      +
    • +
    +

    Bindings

    +

    UI Grid columns can be bound to any sort of Angular expression, as well as property names that would normally break an expression:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var columnDefs = [
    { field: 'name' },
    { field: 'addresses[0]' },
    /*
    Yes, you can use hyphens, plus signs, etc.
    Normally something like {{ row.entity.first-name }} would
    bomb but UI Grid pre-processes your bindings to make sure they work correctly.
    */
    { field: 'first-name' },
    /* Function expressions work too */
    { field: 'getCurrency()' },
    { field: 'transformValue(row.entity.myField)' },
    /* Plain old functions are also an option */
    { field: function () { return this.address.zip; } }
    ];
    + +

    Cell Filters

    +

    Cell filters can transform the displayed value for a column while leaving the model intact. In this plunker the amount column contains floating point values, but we only want to display the integer part. A simple cellFilter that uses .toFixed() will alter the displayed value the way we want.

    + + +

    Passing Arguments

    +

    In the third column I am using two different fields. The column itself is bound to the same field as the second column, but on the filter I am passing the scope like so: cellFilter: 'currencyFilter:this'. Using the this argument on your filter will pass the scope.

    +

    Then I can lookup the currency symbol I want using the currency field from the row.

    +

    If you double-click a cell in the Currency column you’ll see that the raw value is still available to be edited. Cell filters only change your displayed value!

    +

    Cell Templates

    +

    Column definitions take a cellTemplate argument you can use to give your cells a custom template. You can specify it a few different ways, with a url (relative or absolute), an Angular template ID, a string/Angular element, or a promise.

    +
    1
    2
    3
    4
    5
    var columnDefs = [
    { field: 'name', cellTemplate: 'name-template.html' },
    { field: 'name', cellTemplate: 'myTemplateId' },
    { field: 'name', cellTemplate: $.get('url-to-your-template.html') }
    ];
    + +

    Bindings in Cell Templates

    +

    There are a couple options for your binding your row’s data in your template. You can access the row object which is in the local scope; row.entity will contain the reference to your object, so if you want the “name” field, you can bind like so: .

    +

    If you’ve already defined your binding in your column definition you can use one of UI Grid’s placeholders: {{ COL_FIELD }}. UI Grid will automatically replace COL_FIELD with the appropriate binding. If you need to two-way bind to your row, like when you’re using the edit feature, you’ll need to use the MODEL_COL_FIELD placeholder.

    +
    1
    2
    3
    4
    5
    6
    var columnDefs = [
    {
    field: 'image_url',
    cellTemplate: '<div class="ui-grid-cell-contents"><img src="{{ COL_FIELD }}" /></div>'
    }
    ];
    + + +

    Links are simple, just use regular old HTML. Wrapping your cell in an element using the class .ui-grid-cell-contents will apply the proper CSS settings like padding, overflow, etc., and make sure your cell fits in its space nicely.

    +
    1
    2
    3
    4
    5
    6
    var columnDefs = [
    {
    field: 'email',
    cellTemplate: '<div class="ui-grid-cell-contents"><a href="mailto:{{ COL_FIELD }}">Send E-Mail</a></div>'
    }
    ];
    + +

    In the plunker below I’m using a basic cellTemplate to bind both the first and last name fields into one column. On the second column I’m using a simple link like above (note: none of these emails are real).

    +

    On the third one, I’m using a template that’s referenced in index.html. If you check the bottom of that file you’ll see the template inside a <script type="text/ng-template"> tag. Any tags of that type will put automatically put into the template cache ($templateCache) by Angular, with the id you specify.

    +

    Also in the third column template you can see I’m using a variable called grid.appScope. Anywhere in your templates, grid.appScope will be bound to the parent scope of your grid. I use it to bind my button to a function in my controller that will open a new window with a url to google maps with the address in it (note: most if not all of these address will not exist).

    + + +

    Tooltips

    +

    Tooltips are a little bit different because they float over your content. By default the grid’s cells are set to hide any overflow, so if you just pop a tooltip in there it won’t show up and you’ll probably be very confused. If you just add some custom overflow CSS it should fix your problem.

    +

    Hover over the names in the plunker below:

    + + +

    Tooltips cannot overflow beyond the constraints of the viewport, so they won’t show above the first row or below the bottom row, for example.

    +

    Custom Directives

    +

    You can put absolutely anything in your cell templates, just remember to use .ui-grid-cell-contents if you’re not applying your own custom cell CSS.

    + + +

    Here I’ve used d3.js, nvd3.js, and angular-nvd3.js to create sparkline charts in my cells.

    +

    Summin’ it up

    +

    You should be able to do the vast majority of what you want with your data using these six methods. If you have questions, suggestions, or just want to say hi, drop in to our gitter channel; we’d love to meet you!

    +]]>
    + + +

    Getting your data displayed just right can be a huge pain.

    +

    You might just want to]]> +

    + + + + + +
    + +
    diff --git a/blog/cp/blah.html b/blog/cp/blah.html new file mode 100644 index 000000000..dd0500071 --- /dev/null +++ b/blog/cp/blah.html @@ -0,0 +1,22 @@ + +
    +
    + +

    6 Ways to Take Control of How Your Grid Data is Displayed

    +
    +
    +

    + + +Getting your data displayed just right can be a huge pain. +You might just want to format some numbers, or you might want to embed something complex like a chart or custom directive. +In this post outline six different me + +

    + +
    +
    diff --git a/blog/css/normalize.css b/blog/css/normalize.css new file mode 100644 index 000000000..562891ab8 --- /dev/null +++ b/blog/css/normalize.css @@ -0,0 +1,406 @@ +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined in IE 8/9. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +/** + * Correct `inline-block` display not defined in IE 8/9. + */ + +audio, +canvas, +video { + display: inline-block; +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9. + * Hide the `template` element in IE, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background: transparent; +} + +/** + * Address `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari 5, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Correct font family set oddly in Safari 5 and Chrome. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +/** + * Improve readability of pre-formatted text in all browsers. + */ + +pre { + white-space: pre-wrap; +} + +/** + * Set consistent quote types. + */ + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9. + */ + +img { + border: 0; +} + +/** + * Correct overflow displayed oddly in IE 9. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari 5. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Correct font family not being inherited in all browsers. + * 2. Correct font size not being inherited in all browsers. + * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + */ + +button, +input, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * 1. Remove default vertical scrollbar in IE 8/9. + * 2. Improve readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/blog/css/screen.css b/blog/css/screen.css new file mode 100644 index 000000000..8968be558 --- /dev/null +++ b/blog/css/screen.css @@ -0,0 +1,1135 @@ +/* ========================================================================== + Table of Contents + ========================================================================== */ + +/* + + 0. Includes + 1. Icons + 2. General + 3. Utilities + 4. General + 5. Single Post + 6. Third Party Elements + 7. Pagination + 8. Footer + 9. Media Queries (Tablet) + 10. Media Queries (Mobile) + + */ + +/* ========================================================================== + 0. Includes - Ground zero + ========================================================================== */ + +@import url(normalize.css); + + +/* ========================================================================== + 1. Icons - Sets up the icon font and respective classes + ========================================================================== */ + +/* Import the font file with the icons in it */ +@font-face { + font-family: 'icons'; + src:url('../fonts/icons.eot'); + src:url('../fonts/icons.eot?#iefix') format('embedded-opentype'), + url('../fonts/icons.woff') format('woff'), + url('../fonts/icons.ttf') format('truetype'), + url('../fonts/icons.svg#icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +/* Apply these base styles to all icons */ +.icon-ghost:before, +.icon-feed:before, +.icon-twitter:before, +.icon-google-plus:before, +.icon-facebook:before { + font-family: 'icons'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + text-decoration: none; +} + +/* Each icon is created by inserting the corret character into the + content of the :before pseudo element. Like a boss. */ +.icon-ghost:before { + content: "\e000"; +} +.icon-feed:before { + content: "\e001"; +} +.icon-twitter:before { + content: "\e002"; + font-size: 1.1em; +} +.icon-google-plus:before { + content: "\e003"; +} +.icon-facebook:before { + content: "\e004"; +} + + +/* ========================================================================== + 2. General - Setting up some base styles + ========================================================================== */ + +html { + height: 100%; + max-height: 100%; + font-size: 62.5%; +} + +body { + height: 100%; + max-height: 100%; + font-family: 'Noto Serif', serif; + font-size: 2.0rem; + line-height: 1.6em; + color: #3A4145; +} + +::-moz-selection { + color: #222; + background: #D6EDFF; + text-shadow: none; +} + +::selection { + color: #222; + background: #D6EDFF; + text-shadow: none; +} + +h1, h2, h3, +h4, h5, h6 { + text-rendering: optimizeLegibility; + line-height: 1; + margin-top: 0; + font-family: 'Open Sans', sans-serif; +} + +h1 { + font-size: 5rem; + line-height: 1.2em; + letter-spacing: -2px; + text-indent: -3px; +} + +h2 { + font-size: 4rem; + line-height: 1.2em; + letter-spacing: -1px; + text-indent: -2px; +} + +h3 { + font-size: 3.5rem; +} + +h4 { + font-size: 3rem; +} + +h5 { + font-size: 2.5rem; +} + +h6 { + font-size: 2rem; +} + +a { + color: #4a4a4a; + transition: color ease 0.3s; +} + +a:hover { + color: #57A3E8; +} + +h1 a, h2 a, h3 a, +h4 a, h5 a, h6 a { + color: #50585D; +} + + +p, ul, ol, dl { + margin: 1.6em 0; +} + +ol ol, ul ul, +ul ol, ol ul { + margin: 0.4em 0; +} + +dl dt { + float: left; + width: 180px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: bold; + margin-bottom: 1em +} + +dl dd { + margin-left: 200px; + margin-bottom: 1em +} + +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #efefef; + margin: 3.2em 0; + padding: 0; +} + +blockquote { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0 1.6em -2.2em; + padding: 0 0 0 1.6em; + border-left: #4a4a4a 0.4em solid; +} + +blockquote p { + margin: 0.8em 0; + font-style: italic; +} + +blockquote small { + display: inline-block; + margin: 0.8em 0 0.8em 1.5em; + font-size:0.9em; + color: #ccc; +} + +blockquote small:before { content: '\2014 \00A0'; } + +blockquote cite { + font-weight:bold; +} + +blockquote cite a { font-weight: normal; } + +mark { + background-color: #ffc336; +} + +code, tt { + padding: 1px 3px; + font-family: Inconsolata, monospace, sans-serif; + font-size: 0.85em; + white-space: pre-wrap; + border: 1px solid #E3EDF3; + background: #F7FAFB; + border-radius: 2px; +} + +pre { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0; + border: 1px solid #E3EDF3; + width: 100%; + padding: 10px; + font-family: Inconsolata, monospace, sans-serif; + font-size: 0.9em; + white-space: pre; + overflow: auto; + background: #F7FAFB; + border-radius: 3px; +} + +pre code, tt { + font-size: inherit; + white-space: -moz-pre-wrap; + white-space: pre-wrap; + background: transparent; + border: none; + padding: 0; +} + +kbd { + display: inline-block; + margin-bottom: 0.4em; + padding: 1px 8px; + border: #ccc 1px solid; + color: #666; + text-shadow: #fff 0 1px 0; + font-size: 0.9em; + font-weight: bold; + background: #f4f4f4; + border-radius: 4px; + box-shadow: + 0 1px 0 rgba(0, 0, 0, 0.2), + 0 1px 0 0 #fff inset; +} + +table { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1.6em 0; + width:100%; + max-width: 100%; + background-color: transparent; +} + +table th, +table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #efefef; +} + +table th { color: #000; } + +table caption + thead tr:first-child th, +table caption + thead tr:first-child td, +table colgroup + thead tr:first-child th, +table colgroup + thead tr:first-child td, +table thead:first-child tr:first-child th, +table thead:first-child tr:first-child td { + border-top: 0; +} + +table tbody + tbody { border-top: 2px solid #efefef; } + +table table table { background-color: #fff; } + +table tbody > tr:nth-child(odd) > td, +table tbody > tr:nth-child(odd) > th { + background-color: #f6f6f6; +} + +table.plain tbody > tr:nth-child(odd) > td, +table.plain tbody > tr:nth-child(odd) > th { + background: transparent; +} + +iframe, .fluid-width-video-wrapper { + display: block; + margin: 1.6em 0; +} + +/* When a video is inside the fitvids wrapper, drop the +margin on the iframe, cause it breaks stuff. */ +.fluid-width-video-wrapper iframe { + margin: 0; +} + + +/* ========================================================================== + 3. Utilities - These things get used a lot + ========================================================================== */ + +/* Hides shit */ +.hidden { + text-indent: -9999px; + visibility: hidden; + display: none; +} + +/* Creates a responsive wrapper that makes our content scale nicely */ +.inner { + position: relative; + width: 80%; + max-width: 700px; + margin: 0 auto; +} + +/* Centres vertically yo. (IE8+) */ +.vertical { + display: table-cell; + vertical-align: middle; +} + + +/* ========================================================================== + 4. General - The main styles for the the theme + ========================================================================== */ + +/* Big cover image on the home page */ +.site-head { + position: relative; + display: table; + width: 100%; + height: 60%; + margin-bottom: 5rem; + text-align: center; + color: #fff; + background: #303538 no-repeat center center; + background-size: cover; +} + +.blog-logo { + text-decoration: none; +} + +/* Yo-logo. Yolo-go. Upload one in ghost/settings/ */ +.blog-logo img { + display: block; + max-height: 100px; + width: auto; + margin: 0 auto; + line-height: 0; +} + +/* The details of your blog. Defined in ghost/settings/ */ +.blog-title { + margin: 10px 0 10px 0; + font-size: 5rem; + letter-spacing: -1px; + font-weight: bold; + font-family: 'Open Sans', sans-serif; + text-shadow: 0 1px 6px rgba(0,0,0,0.1); +} + +.blog-description { + margin: 0; + font-size: 1.8rem; + line-height: 1.5em; + font-weight: 300; + font-family: 'Noto Serif', serif; + letter-spacing: 0; + text-shadow: 0 1px 3px rgba(0,0,0,0.15); +} + +/* Every post, on every page, gets this style on its
    tag */ +.post { + position: relative; + width:80%; + max-width: 700px; + margin: 4rem auto; + padding-bottom: 4rem; + border-bottom: #EBF2F6 1px solid; + word-break: break-word; + hyphens: auto; +} + +/* Add a little circle in the middle of the border-bottom on our .post + just for the lolz and stylepoints. */ +.post:after { + display: block; + content: ""; + width: 7px; + height: 7px; + border: #E7EEF2 1px solid; + position: absolute; + bottom: -5px; + left: 50%; + margin-left: -5px; + background: #fff; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + box-shadow: #fff 0 0 0 5px; +} + +.post-title { + margin:0; +} + +.post-title a { + text-decoration: none; +} + +.post-excerpt p { + margin: 1.6rem 0 0 0; + font-size: 0.9em; + line-height: 1.6em; +} + +.post-meta { + display: inline-block; + margin: 0 0 5px 0; + font-family: 'Open Sans', sans-serif; + font-size: 1.5rem; + color: #9EABB3; +} + +.post-meta a { + color: #9EABB3; + text-decoration: none; +} + +.post-meta a:hover { + text-decoration: underline; +} + +.user-meta { + position: relative; + padding: 0.3rem 40px 0 100px; + min-height: 77px; +} + +.user-image { + position: absolute; + top: 0; + left: 0; +} + +.user-name { + display: block; + font-weight: bold; +} + +.user-bio { + display: block; + max-width: 440px; + font-size: 1.4rem; + line-height: 1.5em; +} + +.publish-meta { + position: absolute; + top: 0; + right: 0; + padding: 4.3rem 0 4rem 0; + text-align: right; +} + +.publish-heading { + display: block; + font-weight: bold; +} + +.publish-date { + display: block; + font-size: 1.4rem; + line-height: 1.5em; +} + +.comments-area { + width: 80%; + max-width: 700px; + margin: 4rem auto; +} + +#comment h1 a { + text-decoration: none; +} + +/* ========================================================================== + 5. Single Post - When you click on an individual post + ========================================================================== */ + +/* Insert some mad padding up in the header for better spacing */ +.post-template .post-header { + padding: 60px 0; + text-align: center; +} + +.post-template .site-head { + color: #303538; + border-bottom: #ebf2f6 1px solid; + background: none !important; +} + +.post-template .site-head:after { + position: absolute; + bottom: -5px; + left: 50%; + display: block; + width: 7px; + height: 7px; + margin-left: -5px; + content: ''; + border: #e7eef2 1px solid; + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + background: #fff; + box-shadow: #fff 0 0 0 5px; +} + +/* Keep large images within the bounds of the post-width */ +.post-content img { + display: block; + max-width: 100%; + margin: 0 auto; + height: auto; +} + +/* The author credit area after the post */ +.post-footer { + position: relative; + margin: 4rem 0 0 0; + padding: 4rem 0 0 0; + border-top: #EBF2F6 1px solid; +} + +.post-footer h4 { + font-size: 1.8rem; + margin: 0; +} + +.post-footer p { + margin: 1rem 0; + font-size: 1.4rem; + line-height: 1.6em; +} + +/* Create some space to the right for the share links */ +.post-footer .author { + margin-right: 180px; +} + +/* Drop the share links in the space to the right. + Doing it like this means it's easier for the author bio + to be flexible at smaller screen sizes while the share + links remain at a fixed width the whole time */ +.post-footer .share { + position: absolute; + top: 4rem; + right: 0; + width: 140px; +} + +.post-footer .share a { + font-size: 1.8rem; + display: inline-block; + margin: 1.4rem 1.6rem 1.6rem 0; + color: #BBC7CC; + text-decoration: none; +} + +.post-footer .share a:hover { + color: #50585D; +} + + +/* ========================================================================== + 6. Third Party Elements - Embeds from other services + ========================================================================== */ + +/* Hexo: Youtube, other video container */ + +.video-container { + position: relative; + padding-top: 56.25%; + height: 0; + overflow: hidden; +} +.video-container iframe, +.video-container object, +.video-container embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin-top: 0; +} + +/* Hexo: Syntax Highlighter */ + +figure.highlight { + background:#fff; + border-radius:0.3em; + border:1px solid #e1e1e1; + line-height:1.45em; + font-size:.9em; + margin-bottom:2.1em; + color:#222; + overflow:auto; + white-space:pre; + word-wrap:normal; +} +figure.highlight figcaption { + padding: 7px 10px; + font-size: .8em; +} +figure.highlight table { + margin: 0; +} +figure.highlight table > tbody > tr > td { + padding: 0; + background: #fff !important; +} +figure.highlight table > tbody > tr > td.gutter { + max-width: 40px; + text-align: right; +} +figure.highlight pre { + border: none; + margin: 0; +} + +/* Theme: Solarized - Github + * More theme here: http://softwaremaniacs.org/media/soft/highlight/test.html + */ +pre .comment, +pre .template_comment, +.diff pre .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +.css .rule pre .keyword, +pre .winutils, +.javascript pre .title, +.nginx pre .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +.ruby pre .constant { + color: #099; +} + +pre .string, +pre .tag pre .value, +pre .phpdoc, +.tex pre .formula { + color: #d14 +} + +pre .title, +pre .id, +.coffeescript pre .params, +.scss pre .preprocessor { + color: #900; + font-weight: bold +} + +.javascript pre .title, +.lisp pre .title, +.clojure pre .title, +pre .subst { + font-weight: normal +} + +pre .class pre .title, +.haskell pre .type, +.vhdl pre .literal, +.tex pre .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag pre .title, +pre .rules pre .property, +.django pre .tag pre .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +.lisp pre .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .symbol, +.ruby pre .symbol pre .string, +.lisp pre .keyword, +.tex pre .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +.lisp pre .title, +.clojure pre .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pragma, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +.diff pre .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} + + +/* Github */ + +.gist table { + margin: 0; + font-size: 1.4rem; +} + +.gist .line-number { + min-width: 25px; + font-size: 1.1rem; +} + + +/* ========================================================================== + 7. Pagination - Tools to let you flick between pages + ========================================================================== */ + +/* The main wrapper for our pagination links */ +.pagination { + position: relative; + width: 80%; + max-width: 700px; + margin: 4rem auto; + font-family: 'Open Sans', sans-serif; + font-size: 1.3rem; + color: #9EABB3; + text-align: center; +} + +.pagination a { + color: #9EABB3; +} + +/* Push the previous/next links out to the left/right */ +.older-posts, +.newer-posts { + position: absolute; + display: inline-block; + padding: 0 15px; + border: #EBF2F6 2px solid; + text-decoration: none; + border-radius: 30px; + transition: border ease 0.3s; +} + +.older-posts { + right: 0; +} + +.page-number { + display: inline-block; + padding: 2px 0; +} + +.newer-posts { + left: 0; +} + +.older-posts:hover, +.newer-posts:hover { + border-color: #9EABB3; +} + + +/* ========================================================================== + 8. Footer - The bottom of every page + ========================================================================== */ + +.site-footer { + position: relative; + margin: 8rem 0 0 0; + padding: 4rem 0; + border-top: #EBF2F6 1px solid; + font-family: 'Open Sans', sans-serif; + font-size: 1.3rem; + line-height: 1.7em; + color: #BBC7CC; + text-align: center; + background: #F7FAFB; +} + +.site-footer a { + color: #BBC7CC; + text-decoration: underline; +} + +.site-footer a:hover { + color: #50585D; +} + +.poweredby .icon-ghost { + font-weight: 700; + text-decoration: none; +} + +.poweredby .icon-ghost:hover { + text-decoration: none; +} + +.poweredby .icon-ghost:before { + font-size: 1rem; + margin-right: 0.2em; +} + +/* The subscribe icon on the footer */ +.subscribe { + width: 28px; + height: 28px; + position: absolute; + top: -14px; + left: 50%; + margin-left: -15px; + border: #EBF2F6 1px solid; + text-align: center; + line-height: 2.4rem; + border-radius: 50px; + background: #fff; + transition: box-shadow 0.5s; +} + +/* The RSS icon, inserted via icon font */ +.subscribe:before { + color: #D2DEE3; + font-size: 10px; + position: absolute; + top: 9px; + left: 9px; + font-weight: bold; + transition: color 0.5s ease; +} + +/* Add a box shadow to on hover */ +.subscribe:hover { + box-shadow: rgba(0,0,0,0.05) 0 0 0 3px; + transition: box-shadow 0.25s; +} + +.subscribe:hover:before { + color: #50585D; +} + +/* CSS tooltip saying "Subscribe!" - initially hidden */ +.tooltip { + opacity:0; + display: inline-block; + padding: 4px 8px 5px 8px; + position:absolute; + top: -23px; + left: -21px; + color: rgba(255,255,255,0.9); + font-size: 1.1rem; + line-height: 1em; + text-align: center; + background: #50585D; + border-radius:20px; + box-shadow: 0 1px 4px rgba(0,0,0,0.1); + transition: opacity 0.3s ease, top 0.3s ease; +} + +/* The little chiclet arrow under the tooltip, pointing down */ +.tooltip:after { + content:""; + border-width:5px 5px 0 5px; + border-style:solid; + border-color: #50585D transparent; + display:block; + position:absolute; + bottom:-4px; + left:50%; + margin-left:-5px; + z-index: 220; + width:0; +} + +/* On hover, show the tooltip! */ +.subscribe:hover .tooltip { + opacity: 1; + top: -33px; +} + + +/* ========================================================================== + 9. Media Queries - Smaller than 900px + ========================================================================== */ + +@media only screen and (max-width: 900px) { + + blockquote { + margin-left: 0; + } + + .site-head { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + height: auto; + min-height: 240px; + padding: 15% 0; + } + + .blog-title { + font-size: 4rem; + letter-spacing: -1px; + } + + .blog-description { + font-size: 1.7rem; + line-height: 1.5em; + } + + .post { + font-size: 0.9em; + line-height: 1.6em; + } + + .post-template .post { + padding-bottom: 1rem; + } + + .post-template .post-header { + padding: 40px 0; + } + + h1 { + font-size: 4.8rem; + text-indent: -2px; + } + + h2 { + font-size: 3.8rem; + } + + h3 { + font-size: 3.3rem; + } + + h4 { + font-size: 2.8rem; + } + +} + +/* ========================================================================== + 10. Media Queries - Smaller than 500px + ========================================================================== */ + + +@media only screen and (max-width: 500px) { + + .blog-logo img { + max-height: 80px; + } + + .inner, + .pagination { + width: auto; + margin-left: 16px; + margin-right: 16px; + } + + .post { + width:auto; + margin-left: 16px; + margin-right: 16px; + font-size: 0.8em; + line-height: 1.6em; + } + + .site-head { + padding: 10% 0; + } + + .blog-title { + font-size: 3rem; + } + + .blog-description { + font-size: 1.5rem; + } + + + h1, h2 { + font-size: 3rem; + line-height: 1.1em; + letter-spacing: -1px; + } + + h3 { + font-size: 2.8rem; + } + + h4 { + font-size: 2.3rem; + } + + .post-template .post-header { + padding: 30px 0; + } + + .post-meta { + font-size: 1.3rem; + } + + .post-footer { + padding: 4rem 0; + text-align: center; + } + + .post-footer .author { + margin: 0 0 2rem 0; + padding: 0 0 1.6rem 0; + border-bottom: #EBF2F6 1px dashed; + } + + .post-footer .share { + position: static; + width: auto; + } + + .post-footer .share a { + margin: 1.4rem 0.8rem 0 0.8rem; + } + + .older-posts, + .newer-posts { + position: static; + margin: 10px 0; + } + + .page-number { + display: block; + } + + .site-footer { + margin-top: 6rem; + font-size: 1.1rem; + } + +} + +/* ========================================================================== + End of file. Media queries should be the last thing here. Do not add stuff + below this point, or it will probably fuck everything up. + ========================================================================== */ diff --git a/blog/css/site.css b/blog/css/site.css new file mode 100644 index 000000000..f2a1de693 --- /dev/null +++ b/blog/css/site.css @@ -0,0 +1,352 @@ + +body { + padding-top: 0px; +} + +/*------------------------------------------ + Posts +--------------------------------------------*/ + +.posts-header { + text-transform: uppercase; +} + +.post-content { + font-size: 18px; +} + +.post-content p { + margin: 1em; +} + +.post-content h1, +.post-content h2, +.post-content h3, +.post-content h4, +.post-content h5, +.post-content h6 { + margin-top: 60px; +} + +.post-content ul { + margin-left: 20px; +} + +/* The author credit area after the post */ +.post-footer { + position: relative; + margin: 4rem 0 0 0; + padding: 4rem 0 0 0; + border-top: #EBF2F6 1px solid; +} + +.post-footer h4 { + font-size: 1.8rem; + margin: 0; +} + +.post-footer p { + margin: 1rem 0; + font-size: 1.4rem; + line-height: 1.6em; +} + +/* Create some space to the right for the share links */ +.post-footer .author { + margin-right: 180px; +} + +/* Drop the share links in the space to the right. + Doing it like this means it's easier for the author bio + to be flexible at smaller screen sizes while the share + links remain at a fixed width the whole time */ +.post-footer .share { + position: absolute; + top: 4rem; + right: 0; + width: 140px; +} + +.post-footer .share a { + font-size: 1.8rem; + display: inline-block; + margin: 1.4rem 1.6rem 1.6rem 0; + color: #BBC7CC; + text-decoration: none; +} + +.post-footer .share a:hover { + color: #50585D; +} + +/* Mailchimp form */ + +.mailchimp-form-container { + margin-top: 50px; +} + +.mailchimp-form { + border: 2px solid #dce4ec; + border-radius: 4px; + float: left; + padding: 20px; +} + +/*------------------------------------------ + Google search form +--------------------------------------------*/ + +input.gsc-input, .gsc-input-box, .gsc-input-box-hover, .gsc-input-box-focus, .gsc-search-button +{ + box-sizing: content-box; + line-height: normal; +} + +.post-search-form input.gsc-search-button.gsc-search-button-v2 { + background-color: #18bc9c; + border-color: #2ca78f; +} + +/*------------------------------------------ + Footer +--------------------------------------------*/ + +.site-footer { + padding: 50px 0 65px; +} + +.site-footer .list-inline { + margin: 0; + padding: 0; +} + +.site-footer .list-inline a { + color: #2c3e50; +} + +.site-footer .copyright { + font-size: 14px; + text-align: center; + margin-top: 30px; + margin-bottom: 0; +} + +/*------------------------------------------ + Pagination +--------------------------------------------*/ + +/* The main wrapper for our pagination links */ +.paging { + text-align: center; + /*position: relative;*/ + /*width: 80%; + max-width: 700px; + margin: 4rem auto;*/ + /*font-family: 'Open Sans', sans-serif;*/ + /*font-size: 1.3rem;*/ + color: #9EABB3; + margin-top: 4rem; +} + +.paging a { + color: #9EABB3; +} + +/* Push the previous/next links out to the left/right */ +.older-posts, +.newer-posts { + /*position: absolute; + display: inline-block;*/ + padding: 0 15px; + border: #EBF2F6 2px solid; + text-decoration: none; + border-radius: 30px; + transition: border ease 0.3s; +} + +.page-number { + display: inline-block; + padding: 2px 0; +} + +.older-posts:hover, +.newer-posts:hover { + border-color: #9EABB3; +} + + +/* Hexo: Syntax Highlighter */ + +figure.highlight { + background: #23241f; + border-radius:0.3em; + border:1px solid #e1e1e1; + line-height:1.45em; + font-size:.9em; + margin-bottom:2.1em; + /*color:#222;*/ + overflow:auto; + white-space:pre; + word-wrap:normal; +} +figure.highlight figcaption { + padding: 7px 10px; + font-size: .8em; +} +figure.highlight table { + width:100%; + margin: 0; +} +figure.highlight table > tbody > tr > td, figure.highlight table > tbody > tr > td { + padding: 0; + background: #23241f !important; +} +figure.highlight table > tbody > tr > td, figure.highlight table > tbody > tr > td > pre { + background: #23241f !important; +} +figure.highlight table > tbody > tr > td.gutter { + max-width: 40px; + text-align: right; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +figure.highlight pre { + border: none; + margin: 0; +} + + +/* Theme: Solarized - Github + * More theme here: http://softwaremaniacs.org/media/soft/highlight/test.html + */ +/*pre .comment, +pre .template_comment, +.diff pre .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +.css .rule pre .keyword, +pre .winutils, +.javascript pre .title, +.nginx pre .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +.ruby pre .constant { + color: #099; +} + +pre .string, +pre .tag pre .value, +pre .phpdoc, +.tex pre .formula { + color: #d14 +} + +pre .title, +pre .id, +.coffeescript pre .params, +.scss pre .preprocessor { + color: #900; + font-weight: bold +} + +.javascript pre .title, +.lisp pre .title, +.clojure pre .title, +pre .subst { + font-weight: normal +} + +pre .class pre .title, +.haskell pre .type, +.vhdl pre .literal, +.tex pre .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag pre .title, +pre .rules pre .property, +.django pre .tag pre .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +.lisp pre .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .symbol, +.ruby pre .symbol pre .string, +.lisp pre .keyword, +.tex pre .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +.lisp pre .title, +.clojure pre .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pragma, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +.diff pre .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} +*/ + + +/* Github */ + +/*.gist table { + margin: 0; + font-size: 1.4rem; +} + +.gist .line-number { + min-width: 25px; + font-size: 1.1rem; +}*/ \ No newline at end of file diff --git a/blog/fonts/icons.dev.svg b/blog/fonts/icons.dev.svg new file mode 100644 index 000000000..dac6a13a4 --- /dev/null +++ b/blog/fonts/icons.dev.svg @@ -0,0 +1,41 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/blog/fonts/icons.eot b/blog/fonts/icons.eot new file mode 100644 index 000000000..68c968db6 Binary files /dev/null and b/blog/fonts/icons.eot differ diff --git a/blog/fonts/icons.svg b/blog/fonts/icons.svg new file mode 100644 index 000000000..182aa87c5 --- /dev/null +++ b/blog/fonts/icons.svg @@ -0,0 +1,41 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/blog/fonts/icons.ttf b/blog/fonts/icons.ttf new file mode 100644 index 000000000..12b247613 Binary files /dev/null and b/blog/fonts/icons.ttf differ diff --git a/blog/fonts/icons.woff b/blog/fonts/icons.woff new file mode 100644 index 000000000..0127877de Binary files /dev/null and b/blog/fonts/icons.woff differ diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 000000000..07ba69cc2 --- /dev/null +++ b/blog/index.html @@ -0,0 +1,182 @@ + + + + + + + + + + + + UI Grid + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    Posts
    +
    + + +
    +
    + + + +
    +
    +
    + +

    6 Ways to Take Control of How Your Grid Data is Displayed

    +
    +
    +

    + + +

    Getting your data displayed just right can be a huge pain.

    +

    You might just want to format some numbers, or you might want to embed something complex like a... + +

    +

    + + Posted by Brian on February 27th 2015 + + + + +

    +
    +
    +
    + +
    +
    + + + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/js/index.js b/blog/js/index.js new file mode 100644 index 000000000..c015cb44e --- /dev/null +++ b/blog/js/index.js @@ -0,0 +1,15 @@ +/** + * Main JS file for Casper behaviours + */ + +/*globals jQuery, document */ +(function ($) { + "use strict"; + + $(document).ready(function(){ + + $(".post-content").fitVids(); + + }); + +}(jQuery)); \ No newline at end of file diff --git a/blog/js/jquery.fitvids.js b/blog/js/jquery.fitvids.js new file mode 100644 index 000000000..a8551f6e1 --- /dev/null +++ b/blog/js/jquery.fitvids.js @@ -0,0 +1,74 @@ +/*global jQuery */ +/*jshint multistr:true browser:true */ +/*! +* FitVids 1.0.3 +* +* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com +* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ +* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ +* +* Date: Thu Sept 01 18:00:00 2011 -0500 +*/ + +(function( $ ){ + + "use strict"; + + $.fn.fitVids = function( options ) { + var settings = { + customSelector: null + }; + + if(!document.getElementById('fit-vids-style')) { + + var div = document.createElement('div'), + ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0], + cssStyles = '­'; + + div.className = 'fit-vids-style'; + div.id = 'fit-vids-style'; + div.style.display = 'none'; + div.innerHTML = cssStyles; + + ref.parentNode.insertBefore(div,ref); + + } + + if ( options ) { + $.extend( settings, options ); + } + + return this.each(function(){ + var selectors = [ + "iframe[src*='player.vimeo.com']", + "iframe[src*='youtube.com']", + "iframe[src*='youtube-nocookie.com']", + "iframe[src*='kickstarter.com'][src*='video.html']", + "object", + "embed" + ]; + + if (settings.customSelector) { + selectors.push(settings.customSelector); + } + + var $allVideos = $(this).find(selectors.join(',')); + $allVideos = $allVideos.not("object object"); // SwfObj conflict patch + + $allVideos.each(function(){ + var $this = $(this); + if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } + var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), + width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), + aspectRatio = height / width; + if(!$this.attr('id')){ + var videoID = 'fitvid' + Math.floor(Math.random()*999999); + $this.attr('id', videoID); + } + $this.wrap('
    ').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); + $this.removeAttr('height').removeAttr('width'); + }); + }); + }; +// Works with either jQuery or Zepto +})( window.jQuery || window.Zepto ); diff --git a/blog/tags/customize/index.html b/blog/tags/customize/index.html new file mode 100644 index 000000000..898c851dd --- /dev/null +++ b/blog/tags/customize/index.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + Tag: customize | UI Grid + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/blog/tags/display/index.html b/blog/tags/display/index.html new file mode 100644 index 000000000..ce35639b8 --- /dev/null +++ b/blog/tags/display/index.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + Tag: display | UI Grid + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/css/bootstrap-responsive.min.css b/css/bootstrap-responsive.min.css new file mode 100644 index 000000000..96a435be9 --- /dev/null +++ b/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/css/site.css b/css/site.css new file mode 100644 index 000000000..0e5d0bffc --- /dev/null +++ b/css/site.css @@ -0,0 +1,220 @@ +body { + padding-top: 50px; +} + +.jumbotron { + padding: 30px 20px; + margin-bottom: 30px; + font-size: 21px; + font-weight: 200; + line-height: 2.1428571435; + color: inherit; + /*background-color: #eeeeee;*/ + background-image: -webkit-gradient( + linear, + left bottom, + right bottom, + color-stop(0.38, #D1F1FF), + color-stop(1, #EDFCF9) + ); + background-image: -o-linear-gradient(right, #D1F1FF 38%, #EDFCF9 100%); + background-image: -moz-linear-gradient(right, #D1F1FF 38%, #EDFCF9 100%); + background-image: -webkit-linear-gradient(right, #D1F1FF 38%, #EDFCF9 100%); + background-image: -ms-linear-gradient(right, #D1F1FF 38%, #EDFCF9 100%); + background-image: linear-gradient(to right, #D1F1FF 38%, #EDFCF9 100%); +} + +.jumbotron h1, +.jumbotron .h1 { + line-height: 1; + color: inherit; +} + +.lead { + line-height: 1.4; + margin: 0 0 12px; +} + +.description { + line-height: 1; + font-size: 16px; + margin: 0 8px; +} + +.container .jumbotron { + border-radius: 6px; +} + +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 40px; + } +} + +.intro { + display: table; + width: 100%; + margin-right: 0; + margin-left: 0; +} + +.jumbotron { + width: 100%; + display: table-cell; + text-align: center; +} + +.description { + display: inline-block; + text-align: left; +} +.benefits li:before { + content: '✓'; + margin-left: -1em; + margin-right: .300em; + color: green; +} + +.benefits li { + list-style: none; + line-height: 30px; +} + + +@media (min-width: 768px) { + .navbar-brand { + padding: 15px 20px; + } +} + +@media (min-width: 768px) { + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } +} + +@media (min-width: 768px) { + .navbar-text { + float: left; + margin: 15px; + } +} + +.space-before { + padding-top: 8px; +} + +.grid { + height: 250px; +} +.pink { + color: pink; +} +.blue { + color: blue; +} + +.btn-large { + margin: 5px 10px; +} + +.btn-group2 { + margin-top: 30px; +} + + +.benefits { + font-size: 18px; +} + +.intro-body { + display: table; + width: 100%; +} + +.feature { + display: block; + text-align: left; + padding-top: 10px; +} + +.feature-heading { + padding-top 30px; + text-align: center; + min-width: 100%; +} +/* From Bootstrap Responsive */ + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +.modal { + display: block; +} +.modal-body:before, +.modal-body:after { + display: table; + content: " "; +} +.modal-header:before, +.modal-header:after { + display: table; + content: " "; +} +p.modal-message { + margin: 10px 0; +} +.compiled-css { + margin-bottom: 10px; +} diff --git a/customizer.html b/customizer.html new file mode 100644 index 000000000..cdfb9ebbb --- /dev/null +++ b/customizer.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + +
    + +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    {{ cssErr }}
    + +
    +
    + + +
    + + + + + + + + + + \ No newline at end of file diff --git a/customizer/index.html b/customizer/index.html new file mode 100644 index 000000000..2e136afd1 --- /dev/null +++ b/customizer/index.html @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + +
    +
    + +

    Grid Customizer

    + +
    + +
    +
    + +   +   + + + +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + + +
    +
    +
    +
    + +
    {{ cssErr }}
    + +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/customizer/themes/autumn.json b/customizer/themes/autumn.json new file mode 100644 index 000000000..ba54f11fb --- /dev/null +++ b/customizer/themes/autumn.json @@ -0,0 +1,24 @@ +{ + "variables": { + "@borderColor": "darken(@rowColorEven, 15%)", + "@rowColorOdd": "#FDFFE3", + "@rowColorEven": "#E6E3BB", + "@verticalBarColor": "@borderColor", + "@selectedColor": "darken(#D3741C, 8%)", + + "@headerBackgroundColor": "#D3741C", + "@headerGradientStart": "@headerBackgroundColor", + "@headerGradientStop": "lighten(@headerGradientStart, 15%)", + "@headerVerticalBarColor": "darken(@headerBackgroundColor, 5%)", + + "@scrollbarBackground": "darken(@rowColorEven, 15%)", + "@scrollbarBackgroundHover": "darken(@scrollbarBackground, 15%)", + "@scrollbarBackgroundScrolling": "darken(@scrollbarBackgroundHover, 15%)", + "@scrollbarWidth": "10px", + "@scrollbarBorderRadius": "2px", + "@scrollbarShadow": "0 0 0px #fff", + "@scrollbarBorder": "1px solid darken(@scrollbarBackground, 15%)", + "@scrollbarBorderScrolling": "1px solid darken(@scrollbarBackground, 15%)" + }, + "customLess": ".ui-grid { color: #242729; }\n\n.ui-grid-header, .ui-grid-column-menu { color: lighten(@headerBackgroundColor, 45%); }" +} \ No newline at end of file diff --git a/customizer/themes/sky.json b/customizer/themes/sky.json new file mode 100644 index 000000000..56cd8e453 --- /dev/null +++ b/customizer/themes/sky.json @@ -0,0 +1,21 @@ +{ + "variables": { + "@borderColor": "rgb(148, 192, 210)", + "@rowColorOdd": "#fff", + "@rowColorEven": "rgb(234, 244, 249)", + + "@headerBackgroundColor": "rgb(218, 236, 244)", + "@headerGradientStart": "rgb(218, 236, 244)", + "@headerGradientStop": "#fff", + + "@scrollbarBackground": "darken(@rowColorEven, 15%)", + "@scrollbarBackgroundHover": "darken(@scrollbarBackground, 15%)", + "@scrollbarBackgroundScrolling": "darken(@scrollbarBackgroundHover, 15%)", + "@scrollbarWidth": "10px", + "@scrollbarBorderRadius": "2px", + "@scrollbarShadow": "0 0 0px #fff", + "@scrollbarBorder": "1px solid darken(@scrollbarBackground, 15%)", + "@scrollbarBorderScrolling": "1px solid darken(@scrollbarBackground, 15%)" + }, + "customLess": ".ui-grid { color: rgb(0, 63, 89); }" +} \ No newline at end of file diff --git a/customizer/themes/themes.json b/customizer/themes/themes.json new file mode 100644 index 000000000..680d393e0 --- /dev/null +++ b/customizer/themes/themes.json @@ -0,0 +1,4 @@ +[ + "autumn", + "sky" +] \ No newline at end of file diff --git a/data/100.json b/data/100.json new file mode 100644 index 000000000..898453222 --- /dev/null +++ b/data/100.json @@ -0,0 +1,502 @@ +[ + { + "name": "Ethel Price", + "gender": "female", + "company": "Enersol" + }, + { + "name": "Claudine Neal", + "gender": "female", + "company": "Sealoud" + }, + { + "name": "Beryl Rice", + "gender": "female", + "company": "Velity" + }, + { + "name": "Wilder Gonzales", + "gender": "male", + "company": "Geekko" + }, + { + "name": "Georgina Schultz", + "gender": "female", + "company": "Suretech" + }, + { + "name": "Carroll Buchanan", + "gender": "male", + "company": "Ecosys" + }, + { + "name": "Valarie Atkinson", + "gender": "female", + "company": "Hopeli" + }, + { + "name": "Schroeder Mathews", + "gender": "male", + "company": "Polarium" + }, + { + "name": "Lynda Mendoza", + "gender": "female", + "company": "Dogspa" + }, + { + "name": "Sarah Massey", + "gender": "female", + "company": "Bisba" + }, + { + "name": "Robles Boyle", + "gender": "male", + "company": "Comtract" + }, + { + "name": "Evans Hickman", + "gender": "male", + "company": "Parleynet" + }, + { + "name": "Dawson Barber", + "gender": "male", + "company": "Dymi" + }, + { + "name": "Bruce Strong", + "gender": "male", + "company": "Xyqag" + }, + { + "name": "Nellie Whitfield", + "gender": "female", + "company": "Exospace" + }, + { + "name": "Jackson Macias", + "gender": "male", + "company": "Aquamate" + }, + { + "name": "Pena Pena", + "gender": "male", + "company": "Quarx" + }, + { + "name": "Lelia Gates", + "gender": "female", + "company": "Proxsoft" + }, + { + "name": "Letitia Vasquez", + "gender": "female", + "company": "Slumberia" + }, + { + "name": "Trevino Moreno", + "gender": "male", + "company": "Conjurica" + }, + { + "name": "Barr Page", + "gender": "male", + "company": "Apex" + }, + { + "name": "Kirkland Merrill", + "gender": "male", + "company": "Utara" + }, + { + "name": "Blanche Conley", + "gender": "female", + "company": "Imkan" + }, + { + "name": "Atkins Dunlap", + "gender": "male", + "company": "Comveyor" + }, + { + "name": "Everett Foreman", + "gender": "male", + "company": "Maineland" + }, + { + "name": "Gould Randolph", + "gender": "male", + "company": "Intergeek" + }, + { + "name": "Kelli Leon", + "gender": "female", + "company": "Verbus" + }, + { + "name": "Freda Mason", + "gender": "female", + "company": "Accidency" + }, + { + "name": "Tucker Maxwell", + "gender": "male", + "company": "Lumbrex" + }, + { + "name": "Yvonne Parsons", + "gender": "female", + "company": "Zolar" + }, + { + "name": "Woods Key", + "gender": "male", + "company": "Bedder" + }, + { + "name": "Stephens Reilly", + "gender": "male", + "company": "Acusage" + }, + { + "name": "Mcfarland Sparks", + "gender": "male", + "company": "Comvey" + }, + { + "name": "Jocelyn Sawyer", + "gender": "female", + "company": "Fortean" + }, + { + "name": "Renee Barr", + "gender": "female", + "company": "Kiggle" + }, + { + "name": "Gaines Beck", + "gender": "male", + "company": "Sequitur" + }, + { + "name": "Luisa Farrell", + "gender": "female", + "company": "Cinesanct" + }, + { + "name": "Robyn Strickland", + "gender": "female", + "company": "Obones" + }, + { + "name": "Roseann Jarvis", + "gender": "female", + "company": "Aquazure" + }, + { + "name": "Johnston Park", + "gender": "male", + "company": "Netur" + }, + { + "name": "Wong Craft", + "gender": "male", + "company": "Opticall" + }, + { + "name": "Merritt Cole", + "gender": "male", + "company": "Techtrix" + }, + { + "name": "Dale Byrd", + "gender": "female", + "company": "Kneedles" + }, + { + "name": "Sara Delgado", + "gender": "female", + "company": "Netagy" + }, + { + "name": "Alisha Myers", + "gender": "female", + "company": "Intradisk" + }, + { + "name": "Felecia Smith", + "gender": "female", + "company": "Futurity" + }, + { + "name": "Neal Harvey", + "gender": "male", + "company": "Pyramax" + }, + { + "name": "Nola Miles", + "gender": "female", + "company": "Sonique" + }, + { + "name": "Herring Pierce", + "gender": "male", + "company": "Geeketron" + }, + { + "name": "Shelley Rodriquez", + "gender": "female", + "company": "Bostonic" + }, + { + "name": "Cora Chase", + "gender": "female", + "company": "Isonus" + }, + { + "name": "Mckay Santos", + "gender": "male", + "company": "Amtas" + }, + { + "name": "Hilda Crane", + "gender": "female", + "company": "Jumpstack" + }, + { + "name": "Jeanne Lindsay", + "gender": "female", + "company": "Genesynk" + }, + { + "name": "Frye Sharpe", + "gender": "male", + "company": "Eplode" + }, + { + "name": "Velma Fry", + "gender": "female", + "company": "Ronelon" + }, + { + "name": "Reyna Espinoza", + "gender": "female", + "company": "Prismatic" + }, + { + "name": "Spencer Sloan", + "gender": "male", + "company": "Comverges" + }, + { + "name": "Graham Marsh", + "gender": "male", + "company": "Medifax" + }, + { + "name": "Hale Boone", + "gender": "male", + "company": "Digial" + }, + { + "name": "Wiley Hubbard", + "gender": "male", + "company": "Zensus" + }, + { + "name": "Blackburn Drake", + "gender": "male", + "company": "Frenex" + }, + { + "name": "Franco Hunter", + "gender": "male", + "company": "Rockabye" + }, + { + "name": "Barnett Case", + "gender": "male", + "company": "Norali" + }, + { + "name": "Alexander Foley", + "gender": "male", + "company": "Geekosis" + }, + { + "name": "Lynette Stein", + "gender": "female", + "company": "Macronaut" + }, + { + "name": "Anthony Joyner", + "gender": "male", + "company": "Senmei" + }, + { + "name": "Garrett Brennan", + "gender": "male", + "company": "Bluegrain" + }, + { + "name": "Betsy Horton", + "gender": "female", + "company": "Zilla" + }, + { + "name": "Patton Small", + "gender": "male", + "company": "Genmex" + }, + { + "name": "Lakisha Huber", + "gender": "female", + "company": "Insource" + }, + { + "name": "Lindsay Avery", + "gender": "female", + "company": "Unq" + }, + { + "name": "Ayers Hood", + "gender": "male", + "company": "Accuprint" + }, + { + "name": "Torres Durham", + "gender": "male", + "company": "Uplinx" + }, + { + "name": "Vincent Hernandez", + "gender": "male", + "company": "Talendula" + }, + { + "name": "Baird Ryan", + "gender": "male", + "company": "Aquasseur" + }, + { + "name": "Georgia Mercer", + "gender": "female", + "company": "Skyplex" + }, + { + "name": "Francesca Elliott", + "gender": "female", + "company": "Nspire" + }, + { + "name": "Lyons Peters", + "gender": "male", + "company": "Quinex" + }, + { + "name": "Kristi Brewer", + "gender": "female", + "company": "Oronoko" + }, + { + "name": "Tonya Bray", + "gender": "female", + "company": "Insuron" + }, + { + "name": "Valenzuela Huff", + "gender": "male", + "company": "Applideck" + }, + { + "name": "Tiffany Anderson", + "gender": "female", + "company": "Zanymax" + }, + { + "name": "Jerri King", + "gender": "female", + "company": "Eventex" + }, + { + "name": "Rocha Meadows", + "gender": "male", + "company": "Goko" + }, + { + "name": "Marcy Green", + "gender": "female", + "company": "Pharmex" + }, + { + "name": "Kirk Cross", + "gender": "male", + "company": "Portico" + }, + { + "name": "Hattie Mullen", + "gender": "female", + "company": "Zilencio" + }, + { + "name": "Deann Bridges", + "gender": "female", + "company": "Equitox" + }, + { + "name": "Chaney Roach", + "gender": "male", + "company": "Qualitern" + }, + { + "name": "Consuelo Dickson", + "gender": "female", + "company": "Poshome" + }, + { + "name": "Billie Rowe", + "gender": "female", + "company": "Cemention" + }, + { + "name": "Bean Donovan", + "gender": "male", + "company": "Mantro" + }, + { + "name": "Lancaster Patel", + "gender": "male", + "company": "Krog" + }, + { + "name": "Rosa Dyer", + "gender": "female", + "company": "Netility" + }, + { + "name": "Christine Compton", + "gender": "female", + "company": "Bleeko" + }, + { + "name": "Milagros Finch", + "gender": "female", + "company": "Handshake" + }, + { + "name": "Ericka Alvarado", + "gender": "female", + "company": "Lyrichord" + }, + { + "name": "Sylvia Sosa", + "gender": "female", + "company": "Circum" + }, + { + "name": "Humphrey Curtis", + "gender": "male", + "company": "Corepan" + } +] \ No newline at end of file diff --git a/data/10000.json b/data/10000.json new file mode 100644 index 000000000..af53c1323 --- /dev/null +++ b/data/10000.json @@ -0,0 +1,60002 @@ +[ + { + "firstName": "Brianna", + "lastName": "Wiggins", + "company": "Helixo", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Fry", + "company": "Zialactic", + "employed": true + }, + { + "firstName": "Brock", + "lastName": "Brennan", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Turner", + "lastName": "Stone", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Cristina", + "lastName": "Mayo", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Petersen", + "lastName": "Benson", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Avery", + "lastName": "Gray", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Jessie", + "lastName": "Knox", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Foley", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Nunez", + "lastName": "Cole", + "company": "Orbean", + "employed": true + }, + { + "firstName": "Ramsey", + "lastName": "Gomez", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Duncan", + "lastName": "Parsons", + "company": "Enersave", + "employed": false + }, + { + "firstName": "Briana", + "lastName": "Rodriquez", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Maxine", + "lastName": "Watts", + "company": "Qimonk", + "employed": true + }, + { + "firstName": "Bender", + "lastName": "Bullock", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Mooney", + "lastName": "Nielsen", + "company": "Quailcom", + "employed": false + }, + { + "firstName": "Terri", + "lastName": "Kent", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Leonor", + "lastName": "Velasquez", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Isabelle", + "lastName": "Logan", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Ewing", + "lastName": "Ortega", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Gill", + "lastName": "Nixon", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Ramirez", + "lastName": "Weeks", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Camacho", + "lastName": "Parker", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Latasha", + "lastName": "Vincent", + "company": "Zillidium", + "employed": true + }, + { + "firstName": "Mcguire", + "lastName": "Monroe", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Santos", + "lastName": "Duran", + "company": "Corecom", + "employed": false + }, + { + "firstName": "Dickson", + "lastName": "Miller", + "company": "Cujo", + "employed": true + }, + { + "firstName": "Floyd", + "lastName": "Lee", + "company": "Optique", + "employed": true + }, + { + "firstName": "Celeste", + "lastName": "Madden", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Reed", + "lastName": "Garrison", + "company": "Medalert", + "employed": false + }, + { + "firstName": "Joyce", + "lastName": "Mayer", + "company": "Multron", + "employed": true + }, + { + "firstName": "Johnson", + "lastName": "Robertson", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Frank", + "lastName": "Glenn", + "company": "Deepends", + "employed": true + }, + { + "firstName": "Owens", + "lastName": "Thornton", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Fern", + "lastName": "Stevens", + "company": "Printspan", + "employed": false + }, + { + "firstName": "Minerva", + "lastName": "West", + "company": "Comcur", + "employed": false + }, + { + "firstName": "Brittney", + "lastName": "Reid", + "company": "Zilodyne", + "employed": false + }, + { + "firstName": "Evans", + "lastName": "Neal", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Carrie", + "lastName": "Barrett", + "company": "Cemention", + "employed": true + }, + { + "firstName": "Myrna", + "lastName": "Hobbs", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Cora", + "lastName": "Knight", + "company": "Firewax", + "employed": false + }, + { + "firstName": "Nadine", + "lastName": "Fleming", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Leola", + "lastName": "Goodwin", + "company": "Kengen", + "employed": false + }, + { + "firstName": "Keller", + "lastName": "Smith", + "company": "Enomen", + "employed": true + }, + { + "firstName": "Hardin", + "lastName": "Oliver", + "company": "Extragen", + "employed": false + }, + { + "firstName": "Taylor", + "lastName": "Arnold", + "company": "Speedbolt", + "employed": true + }, + { + "firstName": "Knox", + "lastName": "Zimmerman", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Newton", + "lastName": "Wise", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Lula", + "lastName": "Ortiz", + "company": "Centree", + "employed": true + }, + { + "firstName": "Natasha", + "lastName": "Mcneil", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Malinda", + "lastName": "Humphrey", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "June", + "lastName": "Cruz", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Leblanc", + "lastName": "Banks", + "company": "Memora", + "employed": false + }, + { + "firstName": "Nettie", + "lastName": "Huber", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Louise", + "lastName": "Navarro", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Pamela", + "lastName": "Blankenship", + "company": "Geekology", + "employed": false + }, + { + "firstName": "Weiss", + "lastName": "Whitney", + "company": "Cytrek", + "employed": false + }, + { + "firstName": "Barr", + "lastName": "Pena", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Sosa", + "company": "Digique", + "employed": true + }, + { + "firstName": "Shannon", + "lastName": "Harrell", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Whitaker", + "lastName": "Burris", + "company": "Limage", + "employed": false + }, + { + "firstName": "Cole", + "lastName": "Carroll", + "company": "Inrt", + "employed": false + }, + { + "firstName": "Earnestine", + "lastName": "Conley", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Diana", + "lastName": "Lester", + "company": "Insuresys", + "employed": true + }, + { + "firstName": "Mcdonald", + "lastName": "Rosa", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Reyna", + "lastName": "Small", + "company": "Kage", + "employed": true + }, + { + "firstName": "Jerry", + "lastName": "Morton", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Beard", + "lastName": "Gentry", + "company": "Zaphire", + "employed": false + }, + { + "firstName": "Amy", + "lastName": "Byrd", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "Rivas", + "lastName": "Pittman", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Mckee", + "lastName": "Hubbard", + "company": "Blurrybus", + "employed": false + }, + { + "firstName": "Stafford", + "lastName": "Berry", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Suzanne", + "lastName": "Powers", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Houston", + "lastName": "Wooten", + "company": "Isbol", + "employed": false + }, + { + "firstName": "Dorthy", + "lastName": "Murray", + "company": "Medesign", + "employed": true + }, + { + "firstName": "Hewitt", + "lastName": "Conrad", + "company": "Crustatia", + "employed": false + }, + { + "firstName": "Ochoa", + "lastName": "Harrison", + "company": "Kegular", + "employed": false + }, + { + "firstName": "Gray", + "lastName": "Kaufman", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Miranda", + "lastName": "Boone", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Rita", + "lastName": "Hardin", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Richmond", + "company": "Manufact", + "employed": true + }, + { + "firstName": "Phoebe", + "lastName": "Mcfadden", + "company": "Luxuria", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Beasley", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Goodwin", + "lastName": "Franks", + "company": "Insource", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Farrell", + "company": "Blanet", + "employed": true + }, + { + "firstName": "Veronica", + "lastName": "Jackson", + "company": "Rameon", + "employed": true + }, + { + "firstName": "Marissa", + "lastName": "Lang", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Curry", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Beck", + "lastName": "Gaines", + "company": "Sultrax", + "employed": false + }, + { + "firstName": "Walter", + "lastName": "Wong", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Finley", + "lastName": "Wolf", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Terry", + "lastName": "Salinas", + "company": "Assistia", + "employed": true + }, + { + "firstName": "Mae", + "lastName": "Roy", + "company": "Qnekt", + "employed": true + }, + { + "firstName": "Burt", + "lastName": "Barrera", + "company": "Entality", + "employed": true + }, + { + "firstName": "Burton", + "lastName": "Lindsay", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Shawn", + "lastName": "Kerr", + "company": "Visualix", + "employed": true + }, + { + "firstName": "Nieves", + "lastName": "Bauer", + "company": "Fuelworks", + "employed": false + }, + { + "firstName": "Dena", + "lastName": "Kramer", + "company": "Orbalix", + "employed": true + }, + { + "firstName": "Alissa", + "lastName": "Morgan", + "company": "Ramjob", + "employed": false + }, + { + "firstName": "Dixon", + "lastName": "Lamb", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Bird", + "lastName": "Sykes", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Justice", + "lastName": "Horton", + "company": "Phuel", + "employed": false + }, + { + "firstName": "Shelly", + "lastName": "Mueller", + "company": "Macronaut", + "employed": false + }, + { + "firstName": "Kinney", + "lastName": "Terrell", + "company": "Knowlysis", + "employed": false + }, + { + "firstName": "Rosalind", + "lastName": "Rogers", + "company": "Cincyr", + "employed": false + }, + { + "firstName": "Harding", + "lastName": "Dominguez", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Orr", + "lastName": "Fox", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Helena", + "lastName": "Sloan", + "company": "Translink", + "employed": false + }, + { + "firstName": "Daugherty", + "lastName": "Green", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Baker", + "lastName": "Cote", + "company": "Austech", + "employed": false + }, + { + "firstName": "Weeks", + "lastName": "Hutchinson", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Gretchen", + "lastName": "Herring", + "company": "Rodemco", + "employed": true + }, + { + "firstName": "Ramos", + "lastName": "Greer", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "James", + "lastName": "Blevins", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Melanie", + "lastName": "Douglas", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Langley", + "company": "Zoid", + "employed": false + }, + { + "firstName": "Magdalena", + "lastName": "Floyd", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "Craft", + "lastName": "Rutledge", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Nell", + "lastName": "Goodman", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Carney", + "lastName": "Joyce", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Hood", + "lastName": "Melendez", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Pollard", + "lastName": "Clark", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Pearson", + "lastName": "Juarez", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Noemi", + "lastName": "Mcclain", + "company": "Zilla", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Cummings", + "company": "Gonkle", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Barlow", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Eula", + "lastName": "Moore", + "company": "Comtrail", + "employed": true + }, + { + "firstName": "Beach", + "lastName": "Clements", + "company": "Sureplex", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Blackwell", + "company": "Omatom", + "employed": false + }, + { + "firstName": "Mathis", + "lastName": "Perkins", + "company": "Zanity", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "Bowen", + "company": "Aquamate", + "employed": false + }, + { + "firstName": "Mindy", + "lastName": "Hendricks", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Marcy", + "lastName": "Frost", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Dianne", + "lastName": "Dillard", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Casandra", + "lastName": "Mendoza", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Fisher", + "lastName": "Randolph", + "company": "Spherix", + "employed": false + }, + { + "firstName": "Gwen", + "lastName": "Mcmillan", + "company": "Straloy", + "employed": false + }, + { + "firstName": "Bailey", + "lastName": "Roberson", + "company": "Songlines", + "employed": true + }, + { + "firstName": "Janice", + "lastName": "Hensley", + "company": "Imaginart", + "employed": true + }, + { + "firstName": "Ayers", + "lastName": "Atkins", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Best", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Pate", + "lastName": "Justice", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Dixie", + "lastName": "Zamora", + "company": "Amril", + "employed": true + }, + { + "firstName": "Jean", + "lastName": "Lucas", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Everett", + "lastName": "Bryant", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Levine", + "lastName": "Thomas", + "company": "Geekular", + "employed": false + }, + { + "firstName": "Julianne", + "lastName": "Mcmahon", + "company": "Magneato", + "employed": false + }, + { + "firstName": "Ernestine", + "lastName": "Patterson", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Willis", + "lastName": "Le", + "company": "Isonus", + "employed": true + }, + { + "firstName": "Frederick", + "lastName": "Walters", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Black", + "lastName": "Mckay", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Rosalinda", + "lastName": "Meadows", + "company": "Ecrater", + "employed": true + }, + { + "firstName": "Rachel", + "lastName": "Reeves", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Estelle", + "lastName": "Marks", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Mosley", + "lastName": "Alston", + "company": "Deminimum", + "employed": false + }, + { + "firstName": "Mcfarland", + "lastName": "Yang", + "company": "Maineland", + "employed": true + }, + { + "firstName": "Harris", + "lastName": "Mckinney", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Lesa", + "lastName": "Sweeney", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Rebecca", + "lastName": "Griffin", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Lara", + "lastName": "Buckner", + "company": "Cinaster", + "employed": true + }, + { + "firstName": "Kerry", + "lastName": "Rodgers", + "company": "Quinex", + "employed": true + }, + { + "firstName": "Constance", + "lastName": "Morris", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "John", + "lastName": "Odom", + "company": "Musix", + "employed": false + }, + { + "firstName": "Sheena", + "lastName": "Bass", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Fox", + "lastName": "Davis", + "company": "Melbacor", + "employed": true + }, + { + "firstName": "White", + "lastName": "Sawyer", + "company": "Isoternia", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Lowery", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Noelle", + "lastName": "Moon", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Yesenia", + "lastName": "Hogan", + "company": "Exiand", + "employed": true + }, + { + "firstName": "Potter", + "lastName": "Walter", + "company": "Acrodance", + "employed": false + }, + { + "firstName": "Brandi", + "lastName": "Avery", + "company": "Assurity", + "employed": true + }, + { + "firstName": "Shauna", + "lastName": "Lewis", + "company": "Comvoy", + "employed": true + }, + { + "firstName": "Kaitlin", + "lastName": "Case", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Paige", + "lastName": "Martinez", + "company": "Genmy", + "employed": false + }, + { + "firstName": "Stacie", + "lastName": "Holt", + "company": "Neptide", + "employed": false + }, + { + "firstName": "Alice", + "lastName": "Hart", + "company": "Acusage", + "employed": false + }, + { + "firstName": "Gillespie", + "lastName": "Trujillo", + "company": "Thredz", + "employed": false + }, + { + "firstName": "Bridget", + "lastName": "Palmer", + "company": "Vidto", + "employed": false + }, + { + "firstName": "Joy", + "lastName": "Lawson", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Catalina", + "lastName": "Hickman", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Gladys", + "lastName": "Wilkins", + "company": "Columella", + "employed": false + }, + { + "firstName": "Mcdowell", + "lastName": "Mills", + "company": "Icology", + "employed": false + }, + { + "firstName": "Perry", + "lastName": "Rosales", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Ferguson", + "lastName": "Stephenson", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Serena", + "lastName": "Perry", + "company": "Kneedles", + "employed": false + }, + { + "firstName": "Concetta", + "lastName": "Porter", + "company": "Elita", + "employed": false + }, + { + "firstName": "Woods", + "lastName": "Mcintosh", + "company": "Cytrak", + "employed": false + }, + { + "firstName": "Richmond", + "lastName": "Henson", + "company": "Limozen", + "employed": false + }, + { + "firstName": "Abby", + "lastName": "Armstrong", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Sweet", + "lastName": "Lyons", + "company": "Sustenza", + "employed": false + }, + { + "firstName": "Katy", + "lastName": "Woods", + "company": "Dyno", + "employed": true + }, + { + "firstName": "Nona", + "lastName": "Mcdonald", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Lenore", + "lastName": "Noble", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Conway", + "lastName": "Christensen", + "company": "Zisis", + "employed": true + }, + { + "firstName": "Murphy", + "lastName": "Melton", + "company": "Microluxe", + "employed": false + }, + { + "firstName": "Nikki", + "lastName": "Hodges", + "company": "Jimbies", + "employed": false + }, + { + "firstName": "Doris", + "lastName": "Barton", + "company": "Apex", + "employed": false + }, + { + "firstName": "Myra", + "lastName": "Whitfield", + "company": "Geekosis", + "employed": true + }, + { + "firstName": "Debbie", + "lastName": "Decker", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Lakisha", + "lastName": "Swanson", + "company": "Syntac", + "employed": true + }, + { + "firstName": "Katelyn", + "lastName": "Sears", + "company": "Playce", + "employed": false + }, + { + "firstName": "Perkins", + "lastName": "Gallagher", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Roy", + "lastName": "Holland", + "company": "Perkle", + "employed": true + }, + { + "firstName": "Duran", + "lastName": "Lane", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Navarro", + "lastName": "Brady", + "company": "Ziggles", + "employed": false + }, + { + "firstName": "Day", + "lastName": "Trevino", + "company": "Norali", + "employed": true + }, + { + "firstName": "Robertson", + "lastName": "Spencer", + "company": "Neteria", + "employed": true + }, + { + "firstName": "Lorie", + "lastName": "Massey", + "company": "Automon", + "employed": true + }, + { + "firstName": "Langley", + "lastName": "Oneil", + "company": "Cuizine", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Blake", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Hatfield", + "lastName": "Erickson", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Michael", + "lastName": "Austin", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "Daphne", + "lastName": "Chan", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Summer", + "lastName": "Haley", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Lesley", + "lastName": "Blackburn", + "company": "Centuria", + "employed": false + }, + { + "firstName": "James", + "lastName": "Greene", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Meghan", + "lastName": "Wyatt", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Woodard", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Jones", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Henson", + "lastName": "Haney", + "company": "Waab", + "employed": true + }, + { + "firstName": "Johns", + "lastName": "Henderson", + "company": "Codax", + "employed": true + }, + { + "firstName": "Mitzi", + "lastName": "Howe", + "company": "Pawnagra", + "employed": false + }, + { + "firstName": "Gale", + "lastName": "Wells", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Kristy", + "lastName": "Vang", + "company": "Sarasonic", + "employed": true + }, + { + "firstName": "Leigh", + "lastName": "Carey", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Eaton", + "lastName": "Gill", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Fernandez", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Wilda", + "lastName": "Rowland", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Peggy", + "lastName": "Kline", + "company": "Qualitex", + "employed": true + }, + { + "firstName": "Valentine", + "lastName": "Key", + "company": "Candecor", + "employed": false + }, + { + "firstName": "Fowler", + "lastName": "Phillips", + "company": "Extro", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Stark", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Antonia", + "lastName": "Dalton", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Paul", + "lastName": "Boyle", + "company": "Grupoli", + "employed": true + }, + { + "firstName": "Clarissa", + "lastName": "Stephens", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Burgess", + "lastName": "Levine", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Wheeler", + "lastName": "Farley", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Edwina", + "lastName": "Campbell", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Neva", + "lastName": "Stout", + "company": "Kongle", + "employed": false + }, + { + "firstName": "Simon", + "lastName": "Lloyd", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Elva", + "lastName": "Cox", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Velez", + "lastName": "Johns", + "company": "Oceanica", + "employed": true + }, + { + "firstName": "Helga", + "lastName": "Kelly", + "company": "Radiantix", + "employed": false + }, + { + "firstName": "Cannon", + "lastName": "Frazier", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Hawkins", + "lastName": "Hopkins", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Evangeline", + "lastName": "Mitchell", + "company": "Netropic", + "employed": true + }, + { + "firstName": "Hartman", + "lastName": "Young", + "company": "Toyletry", + "employed": false + }, + { + "firstName": "Moses", + "lastName": "House", + "company": "Kog", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Wood", + "company": "Accuprint", + "employed": true + }, + { + "firstName": "Rosanna", + "lastName": "Rojas", + "company": "Nspire", + "employed": false + }, + { + "firstName": "Clark", + "lastName": "Hinton", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Mable", + "lastName": "Miles", + "company": "Zenolux", + "employed": false + }, + { + "firstName": "Hayes", + "lastName": "Fuentes", + "company": "Handshake", + "employed": true + }, + { + "firstName": "Diaz", + "lastName": "Munoz", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Clay", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Torres", + "lastName": "Dickerson", + "company": "Rubadub", + "employed": false + }, + { + "firstName": "Paula", + "lastName": "Stein", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Pratt", + "lastName": "Sanders", + "company": "Bezal", + "employed": true + }, + { + "firstName": "Deborah", + "lastName": "Curtis", + "company": "Filodyne", + "employed": true + }, + { + "firstName": "Celina", + "lastName": "Acevedo", + "company": "Corporana", + "employed": true + }, + { + "firstName": "Boone", + "lastName": "Snider", + "company": "Assistix", + "employed": false + }, + { + "firstName": "Walsh", + "lastName": "Wagner", + "company": "Hyplex", + "employed": false + }, + { + "firstName": "Stevenson", + "lastName": "Hahn", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Robbins", + "lastName": "Bender", + "company": "Krag", + "employed": false + }, + { + "firstName": "Fitzpatrick", + "lastName": "Shaw", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Strong", + "lastName": "Garrett", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Odom", + "lastName": "Blanchard", + "company": "Concility", + "employed": false + }, + { + "firstName": "Monica", + "lastName": "Stevenson", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Kara", + "lastName": "Browning", + "company": "Netility", + "employed": false + }, + { + "firstName": "Colette", + "lastName": "Abbott", + "company": "Datagene", + "employed": false + }, + { + "firstName": "Benjamin", + "lastName": "Spence", + "company": "Velos", + "employed": true + }, + { + "firstName": "Whitfield", + "lastName": "Sweet", + "company": "Isologica", + "employed": true + }, + { + "firstName": "Elba", + "lastName": "Adkins", + "company": "Zeam", + "employed": true + }, + { + "firstName": "Bartlett", + "lastName": "Buck", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Luella", + "lastName": "Dorsey", + "company": "Renovize", + "employed": true + }, + { + "firstName": "Gross", + "lastName": "Elliott", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Jennifer", + "lastName": "Anderson", + "company": "Electonic", + "employed": false + }, + { + "firstName": "Jasmine", + "lastName": "Bond", + "company": "Flumbo", + "employed": true + }, + { + "firstName": "Hoover", + "lastName": "Charles", + "company": "Twiggery", + "employed": false + }, + { + "firstName": "Bianca", + "lastName": "Walsh", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Lorrie", + "lastName": "Bean", + "company": "Realmo", + "employed": true + }, + { + "firstName": "Lolita", + "lastName": "Brewer", + "company": "Nebulean", + "employed": false + }, + { + "firstName": "Allyson", + "lastName": "Cantu", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Monique", + "lastName": "Mcclure", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Fanny", + "lastName": "Puckett", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Adeline", + "lastName": "Schmidt", + "company": "Exoblue", + "employed": false + }, + { + "firstName": "Stein", + "lastName": "Moreno", + "company": "Isologics", + "employed": false + }, + { + "firstName": "Yates", + "lastName": "Cline", + "company": "Steelfab", + "employed": true + }, + { + "firstName": "Lois", + "lastName": "Wilder", + "company": "Securia", + "employed": true + }, + { + "firstName": "Imogene", + "lastName": "Sheppard", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Tommie", + "lastName": "Gonzales", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Nixon", + "lastName": "Shannon", + "company": "Insuron", + "employed": true + }, + { + "firstName": "Ortiz", + "lastName": "Vinson", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Vilma", + "lastName": "Spears", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Kline", + "lastName": "Hampton", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Bean", + "lastName": "Peters", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Ebony", + "lastName": "Lancaster", + "company": "Terrago", + "employed": true + }, + { + "firstName": "House", + "lastName": "Chambers", + "company": "Temorak", + "employed": true + }, + { + "firstName": "Tammi", + "lastName": "Hoffman", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Adele", + "lastName": "Walker", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Wise", + "lastName": "Montgomery", + "company": "Ozean", + "employed": false + }, + { + "firstName": "Bennett", + "lastName": "Hunter", + "company": "Tripsch", + "employed": false + }, + { + "firstName": "Heidi", + "lastName": "Lambert", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Parrish", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Owen", + "lastName": "Malone", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Barnett", + "lastName": "Craft", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Newton", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Barker", + "lastName": "Mckenzie", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Jordan", + "lastName": "Bruce", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Cardenas", + "lastName": "Cortez", + "company": "Kozgene", + "employed": true + }, + { + "firstName": "Todd", + "lastName": "Mathews", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Thompson", + "lastName": "French", + "company": "Beadzza", + "employed": false + }, + { + "firstName": "Castro", + "lastName": "Copeland", + "company": "Callflex", + "employed": true + }, + { + "firstName": "Ball", + "lastName": "Chang", + "company": "Enaut", + "employed": true + }, + { + "firstName": "Tracie", + "lastName": "Fields", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Solomon", + "lastName": "White", + "company": "Combot", + "employed": false + }, + { + "firstName": "Talley", + "lastName": "Serrano", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Ford", + "company": "Motovate", + "employed": true + }, + { + "firstName": "Guerra", + "lastName": "Livingston", + "company": "Accruex", + "employed": false + }, + { + "firstName": "Avila", + "lastName": "Randall", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Wilcox", + "lastName": "Leonard", + "company": "Bleeko", + "employed": false + }, + { + "firstName": "Phillips", + "lastName": "Barber", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Bowman", + "lastName": "Larson", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Deana", + "lastName": "Herman", + "company": "Velity", + "employed": false + }, + { + "firstName": "Lynne", + "lastName": "Tyler", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Espinoza", + "company": "Gink", + "employed": false + }, + { + "firstName": "Claudia", + "lastName": "Tran", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Merritt", + "lastName": "Page", + "company": "Pathways", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Beard", + "company": "Intergeek", + "employed": false + }, + { + "firstName": "Maude", + "lastName": "Mcknight", + "company": "Techade", + "employed": false + }, + { + "firstName": "Molly", + "lastName": "Marquez", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Gibbs", + "lastName": "Battle", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Mcgowan", + "lastName": "Payne", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Bessie", + "lastName": "Faulkner", + "company": "Volax", + "employed": false + }, + { + "firstName": "Dotson", + "lastName": "Ashley", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Alyssa", + "lastName": "Webster", + "company": "Bluegrain", + "employed": false + }, + { + "firstName": "Mendez", + "lastName": "Ballard", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Jan", + "lastName": "Eaton", + "company": "Photobin", + "employed": false + }, + { + "firstName": "Chasity", + "lastName": "Meyers", + "company": "Intradisk", + "employed": false + }, + { + "firstName": "Maldonado", + "lastName": "Baxter", + "company": "Accusage", + "employed": true + }, + { + "firstName": "Curry", + "lastName": "Ayala", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Tonya", + "lastName": "Richards", + "company": "Quordate", + "employed": true + }, + { + "firstName": "Bobbie", + "lastName": "Shields", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Gallegos", + "lastName": "Moody", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Allie", + "lastName": "Tyson", + "company": "Talae", + "employed": false + }, + { + "firstName": "Winifred", + "lastName": "Vasquez", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Ashley", + "lastName": "Diaz", + "company": "Obliq", + "employed": true + }, + { + "firstName": "Kimberly", + "lastName": "Evans", + "company": "Ultrimax", + "employed": false + }, + { + "firstName": "Shelia", + "lastName": "Boyer", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Hansen", + "lastName": "Cooley", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Carroll", + "lastName": "Hunt", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Daisy", + "lastName": "Olsen", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Judith", + "lastName": "Petersen", + "company": "Digiprint", + "employed": false + }, + { + "firstName": "Kim", + "lastName": "Wilkinson", + "company": "Slax", + "employed": true + }, + { + "firstName": "Horn", + "lastName": "Carrillo", + "company": "Furnitech", + "employed": false + }, + { + "firstName": "Robert", + "lastName": "Mullins", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Norma", + "lastName": "Nelson", + "company": "Futuris", + "employed": true + }, + { + "firstName": "April", + "lastName": "Simon", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Sawyer", + "lastName": "Figueroa", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Michelle", + "lastName": "Harris", + "company": "Powernet", + "employed": true + }, + { + "firstName": "Judy", + "lastName": "Guthrie", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Keisha", + "lastName": "Ryan", + "company": "Netbook", + "employed": true + }, + { + "firstName": "Josie", + "lastName": "Todd", + "company": "Geekus", + "employed": true + }, + { + "firstName": "Riley", + "lastName": "Washington", + "company": "Vixo", + "employed": true + }, + { + "firstName": "Audrey", + "lastName": "Wolfe", + "company": "Waretel", + "employed": true + }, + { + "firstName": "Suzette", + "lastName": "Maynard", + "company": "Olucore", + "employed": true + }, + { + "firstName": "Holloway", + "lastName": "Mcguire", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Geneva", + "lastName": "Harding", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Tricia", + "lastName": "Fletcher", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Lynn", + "lastName": "Cantrell", + "company": "Protodyne", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Rose", + "company": "Digitalus", + "employed": false + }, + { + "firstName": "Tabitha", + "lastName": "Lopez", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Peck", + "lastName": "Fischer", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Tiffany", + "lastName": "Woodward", + "company": "Hawkster", + "employed": false + }, + { + "firstName": "Allen", + "lastName": "Cash", + "company": "Mitroc", + "employed": false + }, + { + "firstName": "Sandoval", + "lastName": "Burt", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Hull", + "company": "Olympix", + "employed": true + }, + { + "firstName": "Harrington", + "lastName": "Berg", + "company": "Coash", + "employed": false + }, + { + "firstName": "Mcmahon", + "lastName": "Hays", + "company": "Comvex", + "employed": false + }, + { + "firstName": "Preston", + "lastName": "Hansen", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Rodriquez", + "lastName": "Herrera", + "company": "Qot", + "employed": false + }, + { + "firstName": "Darla", + "lastName": "Davenport", + "company": "Keengen", + "employed": false + }, + { + "firstName": "Pam", + "lastName": "Cunningham", + "company": "Infotrips", + "employed": false + }, + { + "firstName": "Spence", + "lastName": "Wade", + "company": "Isostream", + "employed": true + }, + { + "firstName": "Gabrielle", + "lastName": "Moss", + "company": "Newcube", + "employed": false + }, + { + "firstName": "Emma", + "lastName": "Quinn", + "company": "Scenty", + "employed": true + }, + { + "firstName": "Gloria", + "lastName": "Albert", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Best", + "lastName": "Castillo", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Janet", + "lastName": "Fuller", + "company": "Obones", + "employed": true + }, + { + "firstName": "Hanson", + "lastName": "Dudley", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Jensen", + "lastName": "Schwartz", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Duke", + "lastName": "Flores", + "company": "Turnling", + "employed": false + }, + { + "firstName": "Gail", + "lastName": "Sutton", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Love", + "lastName": "Whitehead", + "company": "Exotechno", + "employed": true + }, + { + "firstName": "Cara", + "lastName": "Hodge", + "company": "Octocore", + "employed": false + }, + { + "firstName": "Morrison", + "lastName": "Lynn", + "company": "Circum", + "employed": false + }, + { + "firstName": "Kemp", + "lastName": "Pitts", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Guthrie", + "lastName": "Villarreal", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Estrada", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Snider", + "lastName": "Drake", + "company": "Cubicide", + "employed": false + }, + { + "firstName": "Morse", + "lastName": "Bolton", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Tammy", + "lastName": "Summers", + "company": "Daisu", + "employed": false + }, + { + "firstName": "Amber", + "lastName": "Mercado", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Dawn", + "lastName": "Conway", + "company": "Telpod", + "employed": false + }, + { + "firstName": "Reese", + "lastName": "Soto", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Hudson", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Craig", + "lastName": "Hartman", + "company": "Tubalum", + "employed": false + }, + { + "firstName": "Suarez", + "lastName": "Guzman", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Charity", + "lastName": "Alexander", + "company": "Portica", + "employed": false + }, + { + "firstName": "Delores", + "lastName": "Conner", + "company": "Magmina", + "employed": false + }, + { + "firstName": "Stephanie", + "lastName": "Nash", + "company": "Digial", + "employed": true + }, + { + "firstName": "Willa", + "lastName": "Roberts", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Burris", + "lastName": "Finch", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Warren", + "company": "Biflex", + "employed": true + }, + { + "firstName": "Rebekah", + "lastName": "Wheeler", + "company": "Eternis", + "employed": false + }, + { + "firstName": "Winnie", + "lastName": "Salas", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Maribel", + "lastName": "Gould", + "company": "Poshome", + "employed": true + }, + { + "firstName": "Wagner", + "lastName": "Burke", + "company": "Progenex", + "employed": false + }, + { + "firstName": "Kirk", + "lastName": "Franco", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Louella", + "lastName": "Chase", + "company": "Xplor", + "employed": true + }, + { + "firstName": "Christie", + "lastName": "Mendez", + "company": "Flum", + "employed": false + }, + { + "firstName": "Alford", + "lastName": "Willis", + "company": "Zytrax", + "employed": false + }, + { + "firstName": "Mattie", + "lastName": "Weaver", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Margaret", + "lastName": "Coleman", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Abigail", + "lastName": "Sampson", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Burnett", + "lastName": "Reyes", + "company": "Applideck", + "employed": false + }, + { + "firstName": "Arlene", + "lastName": "Knapp", + "company": "Euron", + "employed": true + }, + { + "firstName": "Jewel", + "lastName": "Long", + "company": "Myopium", + "employed": false + }, + { + "firstName": "Victoria", + "lastName": "Meyer", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Mary", + "lastName": "Ross", + "company": "Bovis", + "employed": true + }, + { + "firstName": "Weber", + "lastName": "Orr", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Frye", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Whitaker", + "company": "Eargo", + "employed": true + }, + { + "firstName": "Mccray", + "lastName": "Gates", + "company": "Ohmnet", + "employed": false + }, + { + "firstName": "Figueroa", + "lastName": "Barr", + "company": "Enquility", + "employed": false + }, + { + "firstName": "Chapman", + "lastName": "Huff", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Cortez", + "lastName": "Hawkins", + "company": "Centice", + "employed": false + }, + { + "firstName": "Loraine", + "lastName": "Bridges", + "company": "Applidec", + "employed": true + }, + { + "firstName": "Jannie", + "lastName": "Mcgee", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Long", + "lastName": "Baker", + "company": "Brainquil", + "employed": true + }, + { + "firstName": "Griffith", + "lastName": "Combs", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Freda", + "lastName": "Osborn", + "company": "Confrenzy", + "employed": false + }, + { + "firstName": "Wall", + "lastName": "Rich", + "company": "Fleetmix", + "employed": true + }, + { + "firstName": "Barrett", + "lastName": "Thompson", + "company": "Ronbert", + "employed": false + }, + { + "firstName": "Dolly", + "lastName": "Keller", + "company": "Krog", + "employed": true + }, + { + "firstName": "Ellison", + "lastName": "Gonzalez", + "company": "Oulu", + "employed": true + }, + { + "firstName": "Grace", + "lastName": "Taylor", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Hannah", + "lastName": "Graves", + "company": "Plasto", + "employed": true + }, + { + "firstName": "Becker", + "lastName": "Guerra", + "company": "Prosely", + "employed": false + }, + { + "firstName": "Oneill", + "lastName": "Mcdowell", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Potts", + "lastName": "Delgado", + "company": "Dentrex", + "employed": false + }, + { + "firstName": "Vicky", + "lastName": "Bradshaw", + "company": "Gynko", + "employed": false + }, + { + "firstName": "Abbott", + "lastName": "Jenkins", + "company": "Spacewax", + "employed": false + }, + { + "firstName": "Jolene", + "lastName": "Chapman", + "company": "Austex", + "employed": true + }, + { + "firstName": "Francesca", + "lastName": "Pratt", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Dunn", + "lastName": "Bishop", + "company": "Geostele", + "employed": false + }, + { + "firstName": "Cote", + "lastName": "Cleveland", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Horton", + "lastName": "Oneill", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Mollie", + "lastName": "Oconnor", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Frances", + "lastName": "Mcpherson", + "company": "Quilch", + "employed": false + }, + { + "firstName": "Rena", + "lastName": "Clemons", + "company": "Softmicro", + "employed": true + }, + { + "firstName": "Massey", + "lastName": "Rice", + "company": "Comstar", + "employed": false + }, + { + "firstName": "Lela", + "lastName": "Rhodes", + "company": "Jetsilk", + "employed": false + }, + { + "firstName": "Haney", + "lastName": "Hatfield", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Christina", + "lastName": "Ball", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Jenny", + "lastName": "Bernard", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Moore", + "lastName": "Kinney", + "company": "Glasstep", + "employed": true + }, + { + "firstName": "Bonita", + "lastName": "Marsh", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Lindsey", + "lastName": "Mooney", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Lucille", + "lastName": "Mccarty", + "company": "Bedlam", + "employed": true + }, + { + "firstName": "Castillo", + "lastName": "Britt", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Erin", + "lastName": "Church", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Latonya", + "lastName": "Reese", + "company": "Imant", + "employed": false + }, + { + "firstName": "Short", + "lastName": "Dodson", + "company": "Quility", + "employed": true + }, + { + "firstName": "Elsie", + "lastName": "Skinner", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Holden", + "lastName": "Carson", + "company": "Bulljuice", + "employed": false + }, + { + "firstName": "Tracy", + "lastName": "Sexton", + "company": "Portico", + "employed": false + }, + { + "firstName": "Krista", + "lastName": "Harvey", + "company": "Coriander", + "employed": false + }, + { + "firstName": "Concepcion", + "lastName": "Heath", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Barry", + "lastName": "Cross", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Gilda", + "lastName": "Vance", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Jackson", + "lastName": "Valenzuela", + "company": "Greeker", + "employed": false + }, + { + "firstName": "Madeleine", + "lastName": "Briggs", + "company": "Virva", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Cooper", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Mia", + "lastName": "Daniels", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Fuentes", + "lastName": "Wiley", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Beryl", + "lastName": "Bird", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Alyson", + "lastName": "Potts", + "company": "Namegen", + "employed": false + }, + { + "firstName": "Arline", + "lastName": "Alford", + "company": "Acium", + "employed": true + }, + { + "firstName": "Tameka", + "lastName": "Gay", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Mcgee", + "lastName": "Peck", + "company": "Ovium", + "employed": false + }, + { + "firstName": "Peterson", + "lastName": "Weiss", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Stokes", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Rodgers", + "lastName": "Mathis", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Short", + "company": "Furnafix", + "employed": true + }, + { + "firstName": "Lucinda", + "lastName": "Mcbride", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Ingram", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Kathleen", + "lastName": "Parks", + "company": "Nutralab", + "employed": false + }, + { + "firstName": "Baird", + "lastName": "Mann", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Callie", + "lastName": "Pierce", + "company": "Utara", + "employed": false + }, + { + "firstName": "Guzman", + "lastName": "Chandler", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Galloway", + "lastName": "Cain", + "company": "Pyrami", + "employed": true + }, + { + "firstName": "Trina", + "lastName": "Sharp", + "company": "Namebox", + "employed": true + }, + { + "firstName": "Avis", + "lastName": "Cook", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Tia", + "lastName": "Riley", + "company": "Comtours", + "employed": true + }, + { + "firstName": "Vaughan", + "lastName": "Hall", + "company": "Fiberox", + "employed": false + }, + { + "firstName": "Ingrid", + "lastName": "Chaney", + "company": "Orboid", + "employed": false + }, + { + "firstName": "Amparo", + "lastName": "Brock", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Benita", + "lastName": "Booker", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Green", + "lastName": "Leblanc", + "company": "Unia", + "employed": false + }, + { + "firstName": "Rollins", + "lastName": "Durham", + "company": "Geoforma", + "employed": true + }, + { + "firstName": "Lauri", + "lastName": "Santana", + "company": "Emtrac", + "employed": true + }, + { + "firstName": "Juana", + "lastName": "Powell", + "company": "Dogspa", + "employed": true + }, + { + "firstName": "Aisha", + "lastName": "Morin", + "company": "Franscene", + "employed": true + }, + { + "firstName": "Laverne", + "lastName": "Snow", + "company": "Zogak", + "employed": false + }, + { + "firstName": "Thomas", + "lastName": "Salazar", + "company": "Inear", + "employed": true + }, + { + "firstName": "Petty", + "lastName": "Kane", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Carpenter", + "lastName": "Noel", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Richard", + "company": "Snips", + "employed": false + }, + { + "firstName": "Mckay", + "lastName": "Finley", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Knight", + "lastName": "Crosby", + "company": "Maxemia", + "employed": true + }, + { + "firstName": "Kerr", + "lastName": "Mcgowan", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Mcclain", + "lastName": "Roach", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Tara", + "lastName": "Gilliam", + "company": "Codact", + "employed": false + }, + { + "firstName": "Dina", + "lastName": "Landry", + "company": "Imageflow", + "employed": false + }, + { + "firstName": "Gracie", + "lastName": "Riggs", + "company": "Papricut", + "employed": true + }, + { + "firstName": "Marie", + "lastName": "Nieves", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Mcfadden", + "lastName": "Henry", + "company": "Mantro", + "employed": false + }, + { + "firstName": "Deirdre", + "lastName": "Fitzgerald", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Reilly", + "lastName": "Calderon", + "company": "Elemantra", + "employed": true + }, + { + "firstName": "Blackwell", + "lastName": "Raymond", + "company": "Furnigeer", + "employed": false + }, + { + "firstName": "Sonia", + "lastName": "Rollins", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Morgan", + "lastName": "English", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Lorene", + "lastName": "Santiago", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Marshall", + "lastName": "Avila", + "company": "Architax", + "employed": true + }, + { + "firstName": "Jody", + "lastName": "Carpenter", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Kristina", + "lastName": "Robbins", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Munoz", + "lastName": "Wilson", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Collier", + "lastName": "Jacobs", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Salazar", + "lastName": "Benjamin", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Cassie", + "lastName": "Russo", + "company": "Besto", + "employed": false + }, + { + "firstName": "Mcpherson", + "lastName": "Jefferson", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Wolfe", + "lastName": "Gordon", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Grant", + "lastName": "Simmons", + "company": "Snorus", + "employed": true + }, + { + "firstName": "Greene", + "lastName": "Duncan", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Garner", + "lastName": "Michael", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Pittman", + "lastName": "Valencia", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Lidia", + "lastName": "Pace", + "company": "Anarco", + "employed": true + }, + { + "firstName": "Hebert", + "lastName": "Edwards", + "company": "Jamnation", + "employed": true + }, + { + "firstName": "Romero", + "lastName": "Snyder", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Florence", + "lastName": "Ayers", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Irene", + "lastName": "Mejia", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Good", + "lastName": "Price", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Espinoza", + "lastName": "Hurst", + "company": "Zoarere", + "employed": true + }, + { + "firstName": "Osborn", + "lastName": "Morales", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Flores", + "lastName": "Winters", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Barron", + "lastName": "Fowler", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Kristie", + "lastName": "Black", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Mayo", + "lastName": "Lara", + "company": "Petigems", + "employed": false + }, + { + "firstName": "Pena", + "lastName": "Turner", + "company": "Envire", + "employed": true + }, + { + "firstName": "Wolf", + "lastName": "Hancock", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Sharron", + "lastName": "Schultz", + "company": "Zenco", + "employed": true + }, + { + "firstName": "Emilia", + "lastName": "Carver", + "company": "Quizka", + "employed": false + }, + { + "firstName": "Carver", + "lastName": "Barker", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Clayton", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Wilma", + "lastName": "Johnson", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Juanita", + "lastName": "Pruitt", + "company": "Bitendrex", + "employed": false + }, + { + "firstName": "Bonner", + "lastName": "Deleon", + "company": "Geeky", + "employed": false + }, + { + "firstName": "Ruby", + "lastName": "Pope", + "company": "Signity", + "employed": true + }, + { + "firstName": "Melva", + "lastName": "Jarvis", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Mona", + "lastName": "Stanton", + "company": "Nexgene", + "employed": true + }, + { + "firstName": "Jennings", + "lastName": "Burnett", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Zimmerman", + "lastName": "Bowers", + "company": "Iplax", + "employed": false + }, + { + "firstName": "Monroe", + "lastName": "Vaughan", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Hollie", + "lastName": "Hayes", + "company": "Updat", + "employed": false + }, + { + "firstName": "Julie", + "lastName": "Pearson", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Anderson", + "lastName": "Campos", + "company": "Teraprene", + "employed": true + }, + { + "firstName": "Aguirre", + "lastName": "Holder", + "company": "Quadeebo", + "employed": true + }, + { + "firstName": "Catherine", + "lastName": "Waller", + "company": "Isologia", + "employed": false + }, + { + "firstName": "Olivia", + "lastName": "Fulton", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Sheree", + "lastName": "Ruiz", + "company": "Providco", + "employed": true + }, + { + "firstName": "Candace", + "lastName": "Irwin", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Alberta", + "lastName": "Freeman", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Mckinney", + "lastName": "Francis", + "company": "Ecraze", + "employed": true + }, + { + "firstName": "Mcclure", + "lastName": "Adams", + "company": "Isis", + "employed": false + }, + { + "firstName": "Irwin", + "lastName": "Warner", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Leann", + "lastName": "Hayden", + "company": "Synkgen", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Santos", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Witt", + "lastName": "Watson", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Puckett", + "lastName": "Duke", + "company": "Zensure", + "employed": false + }, + { + "firstName": "Hahn", + "lastName": "Carter", + "company": "Hotcakes", + "employed": true + }, + { + "firstName": "Lorna", + "lastName": "Workman", + "company": "Pyramia", + "employed": false + }, + { + "firstName": "Hale", + "lastName": "Alvarez", + "company": "Bristo", + "employed": false + }, + { + "firstName": "Estella", + "lastName": "William", + "company": "Nipaz", + "employed": false + }, + { + "firstName": "Jessica", + "lastName": "Glover", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Stone", + "lastName": "Riddle", + "company": "Idealis", + "employed": true + }, + { + "firstName": "Susanne", + "lastName": "Griffith", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Etta", + "lastName": "Gardner", + "company": "Panzent", + "employed": false + }, + { + "firstName": "Pruitt", + "lastName": "Morrow", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Leila", + "lastName": "Sellers", + "company": "Equitax", + "employed": false + }, + { + "firstName": "Manning", + "lastName": "Manning", + "company": "Proxsoft", + "employed": false + }, + { + "firstName": "Lynnette", + "lastName": "Mccullough", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Kirk", + "company": "Fibrodyne", + "employed": true + }, + { + "firstName": "Bryan", + "lastName": "Norman", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "West", + "lastName": "Wilcox", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Key", + "lastName": "Shaffer", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Klein", + "lastName": "Hale", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Wanda", + "lastName": "Strickland", + "company": "Enersol", + "employed": false + }, + { + "firstName": "Virginia", + "lastName": "Reed", + "company": "Ultrasure", + "employed": false + }, + { + "firstName": "Georgia", + "lastName": "Hernandez", + "company": "Xinware", + "employed": false + }, + { + "firstName": "Patel", + "lastName": "Pollard", + "company": "Gynk", + "employed": true + }, + { + "firstName": "Sutton", + "lastName": "Silva", + "company": "Unq", + "employed": true + }, + { + "firstName": "Sophie", + "lastName": "Shepard", + "company": "Mantrix", + "employed": false + }, + { + "firstName": "Elsa", + "lastName": "Bates", + "company": "Zork", + "employed": false + }, + { + "firstName": "Flossie", + "lastName": "Grimes", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Trudy", + "lastName": "Dawson", + "company": "Delphide", + "employed": false + }, + { + "firstName": "Emerson", + "lastName": "Jordan", + "company": "Organica", + "employed": true + }, + { + "firstName": "Maricela", + "lastName": "Booth", + "company": "Techmania", + "employed": true + }, + { + "firstName": "Maryann", + "lastName": "Jimenez", + "company": "Lovepad", + "employed": true + }, + { + "firstName": "Ronda", + "lastName": "Boyd", + "company": "Combogen", + "employed": true + }, + { + "firstName": "Tamara", + "lastName": "Wallace", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Brooks", + "lastName": "Kemp", + "company": "Zilidium", + "employed": false + }, + { + "firstName": "Atkins", + "lastName": "Daniel", + "company": "Hopeli", + "employed": true + }, + { + "firstName": "Sparks", + "lastName": "Stafford", + "company": "Pholio", + "employed": false + }, + { + "firstName": "Alisa", + "lastName": "Solomon", + "company": "Tropoli", + "employed": false + }, + { + "firstName": "Edith", + "lastName": "Pate", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Silvia", + "lastName": "Klein", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Josefa", + "lastName": "Pickett", + "company": "Talkalot", + "employed": true + }, + { + "firstName": "Nicole", + "lastName": "Holman", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Jami", + "lastName": "Dean", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Misty", + "lastName": "Ochoa", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Shaw", + "lastName": "Castro", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Vaughn", + "company": "Tourmania", + "employed": false + }, + { + "firstName": "Blevins", + "lastName": "Kim", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Sondra", + "lastName": "Sullivan", + "company": "Zoxy", + "employed": true + }, + { + "firstName": "Louisa", + "lastName": "Hanson", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Valentine", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Teresa", + "lastName": "Cameron", + "company": "Applica", + "employed": true + }, + { + "firstName": "Theresa", + "lastName": "Blair", + "company": "Rodeomad", + "employed": true + }, + { + "firstName": "Angeline", + "lastName": "Carr", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Callahan", + "lastName": "Larsen", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Mccullough", + "lastName": "Scott", + "company": "Biotica", + "employed": true + }, + { + "firstName": "Olson", + "lastName": "Crawford", + "company": "Slambda", + "employed": true + }, + { + "firstName": "Wilson", + "lastName": "Cooke", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Moreno", + "lastName": "Weber", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Lucas", + "lastName": "Caldwell", + "company": "Retrack", + "employed": false + }, + { + "firstName": "Lowery", + "lastName": "Baldwin", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Hilda", + "lastName": "Paul", + "company": "Entogrok", + "employed": false + }, + { + "firstName": "Jeannine", + "lastName": "Horne", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Tabatha", + "lastName": "Gibbs", + "company": "Dreamia", + "employed": true + }, + { + "firstName": "Julia", + "lastName": "Brown", + "company": "Pharmex", + "employed": true + }, + { + "firstName": "Pearl", + "lastName": "Huffman", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Raymond", + "lastName": "Bradford", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Melisa", + "lastName": "Robinson", + "company": "Reversus", + "employed": true + }, + { + "firstName": "Mays", + "lastName": "Rivas", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Mallory", + "lastName": "Rasmussen", + "company": "Enerforce", + "employed": true + }, + { + "firstName": "Gates", + "lastName": "Gillespie", + "company": "Zorromop", + "employed": true + }, + { + "firstName": "Aline", + "lastName": "Burch", + "company": "Boink", + "employed": false + }, + { + "firstName": "Nichols", + "lastName": "Mosley", + "company": "Amtap", + "employed": true + }, + { + "firstName": "Marquita", + "lastName": "Myers", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Alexandra", + "lastName": "Harmon", + "company": "Verton", + "employed": true + }, + { + "firstName": "Laura", + "lastName": "Beach", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Rosemary", + "lastName": "Foreman", + "company": "Metroz", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Dale", + "company": "Urbanshee", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Walton", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Juliet", + "lastName": "Dennis", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Dee", + "lastName": "Aguirre", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "Compton", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Adriana", + "lastName": "Leon", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Deann", + "lastName": "Gilbert", + "company": "Suremax", + "employed": true + }, + { + "firstName": "Foster", + "lastName": "Matthews", + "company": "Squish", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Rios", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Berta", + "lastName": "Dejesus", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Hays", + "lastName": "Coffey", + "company": "Waterbaby", + "employed": false + }, + { + "firstName": "Jodi", + "lastName": "Ferrell", + "company": "Dadabase", + "employed": true + }, + { + "firstName": "Fleming", + "lastName": "Ramos", + "company": "Geekwagon", + "employed": false + }, + { + "firstName": "Holmes", + "lastName": "Moran", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Padilla", + "lastName": "Cannon", + "company": "Futurize", + "employed": true + }, + { + "firstName": "Lynch", + "lastName": "Mcdaniel", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Ortega", + "lastName": "Bush", + "company": "Idego", + "employed": true + }, + { + "firstName": "Camille", + "lastName": "Velazquez", + "company": "Gorganic", + "employed": true + }, + { + "firstName": "Cunningham", + "lastName": "Cohen", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Janie", + "lastName": "Carlson", + "company": "Buzzopia", + "employed": false + }, + { + "firstName": "Althea", + "lastName": "Collins", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Mercedes", + "lastName": "Levy", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Booth", + "lastName": "Galloway", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Saunders", + "company": "Zyple", + "employed": false + }, + { + "firstName": "Boyer", + "lastName": "Tillman", + "company": "Rodeology", + "employed": true + }, + { + "firstName": "Amelia", + "lastName": "Miranda", + "company": "Interloo", + "employed": true + }, + { + "firstName": "Mayra", + "lastName": "Tate", + "company": "Zolarity", + "employed": true + }, + { + "firstName": "Freeman", + "lastName": "Nichols", + "company": "Ezent", + "employed": true + }, + { + "firstName": "Banks", + "lastName": "Farmer", + "company": "Fitcore", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Marshall", + "company": "Xeronk", + "employed": true + }, + { + "firstName": "Nancy", + "lastName": "Branch", + "company": "Mixers", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Dickson", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Gayle", + "lastName": "Hill", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Beatriz", + "lastName": "Hardy", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Fernandez", + "lastName": "Sargent", + "company": "Tropolis", + "employed": true + }, + { + "firstName": "Annette", + "lastName": "Holmes", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Coffey", + "lastName": "Ellis", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Sarah", + "lastName": "Osborne", + "company": "Exostream", + "employed": true + }, + { + "firstName": "Tasha", + "lastName": "Gilmore", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Forbes", + "lastName": "Butler", + "company": "Terrasys", + "employed": false + }, + { + "firstName": "Crosby", + "lastName": "Hines", + "company": "Grok", + "employed": false + }, + { + "firstName": "Underwood", + "lastName": "Beck", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Harriett", + "lastName": "Nicholson", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Esther", + "lastName": "Tucker", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "Viola", + "lastName": "Howell", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Camacho", + "company": "Kangle", + "employed": false + }, + { + "firstName": "Ester", + "lastName": "Merritt", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Patrice", + "lastName": "Chen", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Margo", + "lastName": "Collier", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Sexton", + "lastName": "Graham", + "company": "Freakin", + "employed": true + }, + { + "firstName": "Janette", + "lastName": "Holloway", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Trujillo", + "lastName": "Maddox", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Ilene", + "lastName": "Bennett", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Briggs", + "lastName": "Sparks", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Albert", + "lastName": "Flynn", + "company": "Navir", + "employed": true + }, + { + "firstName": "Brenda", + "lastName": "Hess", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Olsen", + "lastName": "Schroeder", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Curtis", + "lastName": "Guy", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Polly", + "lastName": "Nguyen", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Bass", + "lastName": "Macias", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Williams", + "lastName": "Reynolds", + "company": "Vetron", + "employed": true + }, + { + "firstName": "Head", + "lastName": "George", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Noble", + "lastName": "Maldonado", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Wilkerson", + "lastName": "Luna", + "company": "Everest", + "employed": true + }, + { + "firstName": "Agnes", + "lastName": "Franklin", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Lawrence", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Wiggins", + "lastName": "Hendrix", + "company": "Netplax", + "employed": false + }, + { + "firstName": "Lydia", + "lastName": "Mays", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Renee", + "lastName": "Owen", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Ada", + "lastName": "Vega", + "company": "Matrixity", + "employed": true + }, + { + "firstName": "Crawford", + "lastName": "Ferguson", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Vargas", + "lastName": "Underwood", + "company": "Magnemo", + "employed": false + }, + { + "firstName": "Gertrude", + "lastName": "Hammond", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Schneider", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Carter", + "lastName": "Garcia", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Farrell", + "lastName": "Lott", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Richards", + "lastName": "Delaney", + "company": "Maximind", + "employed": false + }, + { + "firstName": "Christine", + "lastName": "Mccarthy", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Deanne", + "lastName": "Horn", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Aurelia", + "lastName": "York", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Elvira", + "lastName": "Chavez", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Cervantes", + "company": "Corpulse", + "employed": true + }, + { + "firstName": "Pope", + "lastName": "Mccoy", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Willie", + "lastName": "Petty", + "company": "Arctiq", + "employed": false + }, + { + "firstName": "Esperanza", + "lastName": "Cochran", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Macdonald", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Vicki", + "lastName": "Richardson", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Therese", + "lastName": "Solis", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Randolph", + "lastName": "Robles", + "company": "Injoy", + "employed": false + }, + { + "firstName": "Christi", + "lastName": "Craig", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Oneil", + "lastName": "Hopper", + "company": "Evidends", + "employed": true + }, + { + "firstName": "Lisa", + "lastName": "Dixon", + "company": "Kenegy", + "employed": true + }, + { + "firstName": "Lucy", + "lastName": "Benton", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Hardy", + "lastName": "Little", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Jocelyn", + "lastName": "Nolan", + "company": "Zentia", + "employed": true + }, + { + "firstName": "Shelley", + "lastName": "Wall", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Flora", + "lastName": "Burton", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Rivers", + "lastName": "Maxwell", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Cathleen", + "lastName": "Houston", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Stuart", + "lastName": "Lynch", + "company": "Miracula", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Welch", + "company": "Buzzworks", + "employed": true + }, + { + "firstName": "Jane", + "lastName": "Mcintyre", + "company": "Zounds", + "employed": false + }, + { + "firstName": "Daniels", + "lastName": "Mcfarland", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Joyce", + "lastName": "Cardenas", + "company": "Oronoko", + "employed": false + }, + { + "firstName": "Roseann", + "lastName": "Hicks", + "company": "Geekko", + "employed": true + }, + { + "firstName": "Marietta", + "lastName": "Cobb", + "company": "Gology", + "employed": true + }, + { + "firstName": "Landry", + "lastName": "Bailey", + "company": "Pheast", + "employed": false + }, + { + "firstName": "Maddox", + "lastName": "Valdez", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Le", + "lastName": "Anthony", + "company": "Zipak", + "employed": false + }, + { + "firstName": "Frankie", + "lastName": "Shelton", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Mari", + "lastName": "Moses", + "company": "Minga", + "employed": false + }, + { + "firstName": "Diane", + "lastName": "Harrington", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Kitty", + "lastName": "Dyer", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Tessa", + "lastName": "Obrien", + "company": "Halap", + "employed": true + }, + { + "firstName": "Billie", + "lastName": "Goff", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Tania", + "lastName": "Dunn", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Cervantes", + "lastName": "Watkins", + "company": "Sunclipse", + "employed": false + }, + { + "firstName": "Lena", + "lastName": "Fitzpatrick", + "company": "Zillactic", + "employed": true + }, + { + "firstName": "Sargent", + "lastName": "Olson", + "company": "Exodoc", + "employed": true + }, + { + "firstName": "Britt", + "lastName": "Rodriguez", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Oliver", + "lastName": "Mason", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Yvonne", + "lastName": "Jennings", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Vivian", + "lastName": "Williams", + "company": "Elentrix", + "employed": false + }, + { + "firstName": "Nelda", + "lastName": "Townsend", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Virgie", + "lastName": "Carney", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Patsy", + "lastName": "Callahan", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Vanessa", + "lastName": "Norton", + "company": "Earbang", + "employed": false + }, + { + "firstName": "Donna", + "lastName": "Middleton", + "company": "Caxt", + "employed": false + }, + { + "firstName": "George", + "lastName": "Stuart", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Snow", + "lastName": "Bradley", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Betsy", + "lastName": "Crane", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Lynette", + "lastName": "Gallegos", + "company": "Naxdis", + "employed": false + }, + { + "firstName": "Johnnie", + "lastName": "Rivers", + "company": "Verbus", + "employed": false + }, + { + "firstName": "Montoya", + "lastName": "Acosta", + "company": "Remold", + "employed": true + }, + { + "firstName": "Barnes", + "lastName": "Aguilar", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Elma", + "lastName": "Waters", + "company": "Avenetro", + "employed": false + }, + { + "firstName": "Brown", + "lastName": "Mclean", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Esmeralda", + "lastName": "Potter", + "company": "Eclipto", + "employed": true + }, + { + "firstName": "Sheryl", + "lastName": "Barnes", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Marina", + "lastName": "Peterson", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Aida", + "lastName": "Murphy", + "company": "Ersum", + "employed": true + }, + { + "firstName": "Addie", + "lastName": "Haynes", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Beverly", + "lastName": "Velez", + "company": "Zaj", + "employed": false + }, + { + "firstName": "Casey", + "lastName": "Merrill", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Mccall", + "lastName": "Strong", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Gena", + "lastName": "Daugherty", + "company": "Adornica", + "employed": false + }, + { + "firstName": "Hoffman", + "lastName": "Ray", + "company": "Farmage", + "employed": true + }, + { + "firstName": "Eloise", + "lastName": "Patrick", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Fields", + "lastName": "Atkinson", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Coleman", + "lastName": "Ware", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Terra", + "lastName": "Medina", + "company": "Sulfax", + "employed": false + }, + { + "firstName": "Emily", + "lastName": "Brooks", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Finch", + "lastName": "Hebert", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Chandra", + "lastName": "Barron", + "company": "Goko", + "employed": false + }, + { + "firstName": "Yang", + "lastName": "Allison", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Martinez", + "lastName": "Odonnell", + "company": "Puria", + "employed": false + }, + { + "firstName": "Fuller", + "lastName": "Kirby", + "company": "Golistic", + "employed": true + }, + { + "firstName": "Rosario", + "lastName": "Colon", + "company": "Zentix", + "employed": true + }, + { + "firstName": "Elinor", + "lastName": "Stewart", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Mara", + "lastName": "Kelley", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Dorsey", + "lastName": "Buchanan", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Nicholson", + "lastName": "Hurley", + "company": "Telepark", + "employed": false + }, + { + "firstName": "Rene", + "lastName": "Martin", + "company": "Tri@Tribalog", + "employed": true + }, + { + "firstName": "Buchanan", + "lastName": "Grant", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Mccray", + "company": "Poochies", + "employed": true + }, + { + "firstName": "Phelps", + "lastName": "Good", + "company": "Sybixtex", + "employed": true + }, + { + "firstName": "Flowers", + "lastName": "Donaldson", + "company": "Gushkool", + "employed": true + }, + { + "firstName": "Fulton", + "lastName": "Steele", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Earlene", + "lastName": "Rivera", + "company": "Quantasis", + "employed": true + }, + { + "firstName": "Tonia", + "lastName": "Newman", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Iva", + "lastName": "Casey", + "company": "Surelogic", + "employed": false + }, + { + "firstName": "Dolores", + "lastName": "Hyde", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Mcmillan", + "lastName": "Garza", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Lynn", + "lastName": "Ramsey", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Knowles", + "lastName": "Pennington", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Noel", + "lastName": "Glass", + "company": "Bitrex", + "employed": false + }, + { + "firstName": "Verna", + "lastName": "Pacheco", + "company": "Eyeris", + "employed": false + }, + { + "firstName": "Roberson", + "lastName": "Tanner", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Claire", + "lastName": "Preston", + "company": "Isoswitch", + "employed": false + }, + { + "firstName": "Collins", + "lastName": "Downs", + "company": "Plasmosis", + "employed": true + }, + { + "firstName": "Sanders", + "lastName": "James", + "company": "Marvane", + "employed": false + }, + { + "firstName": "Schneider", + "lastName": "Sims", + "company": "Interfind", + "employed": false + }, + { + "firstName": "Waller", + "lastName": "Dillon", + "company": "Senmao", + "employed": true + }, + { + "firstName": "Harvey", + "lastName": "Travis", + "company": "Uberlux", + "employed": false + }, + { + "firstName": "Lynda", + "lastName": "Yates", + "company": "Daido", + "employed": false + }, + { + "firstName": "Kasey", + "lastName": "Perez", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Hampton", + "lastName": "Alvarado", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Martin", + "lastName": "Fisher", + "company": "Gadtron", + "employed": true + }, + { + "firstName": "Morton", + "lastName": "Mcleod", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Joseph", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Kirkland", + "company": "Fanfare", + "employed": false + }, + { + "firstName": "Sabrina", + "lastName": "Poole", + "company": "Talkola", + "employed": true + }, + { + "firstName": "Marcia", + "lastName": "Lowe", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Barlow", + "lastName": "Rowe", + "company": "Strozen", + "employed": false + }, + { + "firstName": "Prince", + "lastName": "Duffy", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Jacobs", + "lastName": "Golden", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Goodman", + "lastName": "Sandoval", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Rae", + "lastName": "Guerrero", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Wells", + "lastName": "Flowers", + "company": "Imkan", + "employed": true + }, + { + "firstName": "Dickerson", + "lastName": "King", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Haynes", + "lastName": "Forbes", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Lilly", + "lastName": "Williamson", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Roman", + "lastName": "Oneal", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Stark", + "lastName": "Holden", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Buckley", + "lastName": "Garner", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Glenn", + "lastName": "Joyner", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Wilkins", + "lastName": "Berger", + "company": "Digigen", + "employed": false + }, + { + "firstName": "Cindy", + "lastName": "Ramirez", + "company": "Zentry", + "employed": false + }, + { + "firstName": "King", + "lastName": "Cotton", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Kathrine", + "lastName": "Mack", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Yolanda", + "lastName": "Bell", + "company": "Artworlds", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Day", + "company": "Acruex", + "employed": true + }, + { + "firstName": "Branch", + "lastName": "Contreras", + "company": "Zerbina", + "employed": true + }, + { + "firstName": "Lloyd", + "lastName": "Dotson", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Zamora", + "lastName": "Frank", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Middleton", + "lastName": "Park", + "company": "Paragonia", + "employed": false + }, + { + "firstName": "Lindsay", + "lastName": "Suarez", + "company": "Aquoavo", + "employed": true + }, + { + "firstName": "Tamra", + "lastName": "Ewing", + "company": "Xth", + "employed": true + }, + { + "firstName": "Maria", + "lastName": "Holcomb", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Hernandez", + "lastName": "Gutierrez", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Tammie", + "lastName": "Andrews", + "company": "Megall", + "employed": false + }, + { + "firstName": "Vinson", + "lastName": "Wright", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Whitney", + "lastName": "Mullen", + "company": "Zomboid", + "employed": false + }, + { + "firstName": "Marsha", + "lastName": "Barry", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Sonja", + "lastName": "Byers", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Knowles", + "company": "Deviltoe", + "employed": true + }, + { + "firstName": "Nolan", + "lastName": "Mccall", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Perez", + "lastName": "Bright", + "company": "Locazone", + "employed": true + }, + { + "firstName": "Terrie", + "lastName": "Mccormick", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Rosario", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Annmarie", + "lastName": "Sanchez", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Danielle", + "lastName": "Wilkerson", + "company": "Keeg", + "employed": true + }, + { + "firstName": "Cobb", + "lastName": "Molina", + "company": "Viagreat", + "employed": false + }, + { + "firstName": "Letha", + "lastName": "Russell", + "company": "Xiix", + "employed": true + }, + { + "firstName": "Malone", + "lastName": "May", + "company": "Avit", + "employed": false + }, + { + "firstName": "Mcknight", + "lastName": "Whitley", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Welch", + "lastName": "Sanford", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Cathy", + "lastName": "Roman", + "company": "Quilm", + "employed": false + }, + { + "firstName": "Mercado", + "lastName": "Hood", + "company": "Talendula", + "employed": true + }, + { + "firstName": "Sandra", + "lastName": "Allen", + "company": "Quilk", + "employed": true + }, + { + "firstName": "Carly", + "lastName": "Ellison", + "company": "Sportan", + "employed": false + }, + { + "firstName": "Nannie", + "lastName": "Bentley", + "company": "Shopabout", + "employed": false + }, + { + "firstName": "Elaine", + "lastName": "Davidson", + "company": "Cormoran", + "employed": false + }, + { + "firstName": "Letitia", + "lastName": "Mclaughlin", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Lelia", + "lastName": "David", + "company": "Recrisys", + "employed": true + }, + { + "firstName": "Ola", + "lastName": "Talley", + "company": "Terragen", + "employed": false + }, + { + "firstName": "Kelli", + "lastName": "Owens", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "England", + "company": "Omnigog", + "employed": false + }, + { + "firstName": "French", + "lastName": "Witt", + "company": "Enthaze", + "employed": false + }, + { + "firstName": "Boyd", + "lastName": "Estes", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Tami", + "lastName": "Burks", + "company": "Momentia", + "employed": true + }, + { + "firstName": "York", + "lastName": "Webb", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Poole", + "lastName": "Mercer", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Lorena", + "lastName": "Gamble", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Weaver", + "lastName": "Dunlap", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Vonda", + "lastName": "Jacobson", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Mcintosh", + "lastName": "Delacruz", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Rocha", + "lastName": "Foster", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Velazquez", + "lastName": "Frederick", + "company": "Tsunamia", + "employed": true + }, + { + "firstName": "Compton", + "lastName": "Hooper", + "company": "Netur", + "employed": false + }, + { + "firstName": "Mills", + "lastName": "Harper", + "company": "Centregy", + "employed": false + }, + { + "firstName": "Elizabeth", + "lastName": "Lindsey", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Lupe", + "lastName": "Jensen", + "company": "Klugger", + "employed": false + }, + { + "firstName": "Karla", + "lastName": "Emerson", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Burks", + "lastName": "Donovan", + "company": "Colaire", + "employed": true + }, + { + "firstName": "Raquel", + "lastName": "Savage", + "company": "Comtrek", + "employed": false + }, + { + "firstName": "Reynolds", + "lastName": "Patel", + "company": "Genesynk", + "employed": false + }, + { + "firstName": "Benson", + "lastName": "Becker", + "company": "Pyramax", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Patton", + "company": "Vortexaco", + "employed": false + }, + { + "firstName": "Francine", + "lastName": "Norris", + "company": "Medcom", + "employed": true + }, + { + "firstName": "Regina", + "lastName": "Howard", + "company": "Multiflex", + "employed": true + }, + { + "firstName": "Erika", + "lastName": "Buckley", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Adela", + "lastName": "Keith", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Cooke", + "lastName": "Walls", + "company": "Wrapture", + "employed": true + }, + { + "firstName": "Britney", + "lastName": "Hoover", + "company": "Comtest", + "employed": true + }, + { + "firstName": "Cassandra", + "lastName": "Ratliff", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Bernadine", + "lastName": "Simpson", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Davis", + "lastName": "Rocha", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Roth", + "lastName": "Hester", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Betty", + "lastName": "Shepherd", + "company": "Accel", + "employed": false + }, + { + "firstName": "Jeanne", + "lastName": "Morrison", + "company": "Zytrek", + "employed": true + }, + { + "firstName": "Justine", + "lastName": "Torres", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Nellie", + "lastName": "Head", + "company": "Danja", + "employed": true + }, + { + "firstName": "Carrillo", + "lastName": "Barnett", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Smith", + "lastName": "Burns", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Nita", + "lastName": "Prince", + "company": "Zosis", + "employed": false + }, + { + "firstName": "Lilian", + "lastName": "Pugh", + "company": "Vendblend", + "employed": true + }, + { + "firstName": "Tanya", + "lastName": "Bowman", + "company": "Pharmacon", + "employed": false + }, + { + "firstName": "Carolina", + "lastName": "Kennedy", + "company": "Jumpstack", + "employed": true + }, + { + "firstName": "Vance", + "lastName": "Singleton", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Josefina", + "lastName": "Leach", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Jacquelyn", + "lastName": "Gibson", + "company": "Tersanki", + "employed": true + }, + { + "firstName": "Ray", + "lastName": "Sherman", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Lavonne", + "lastName": "Mcconnell", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Roxie", + "lastName": "Morse", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Terry", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Bonnie", + "lastName": "Bonner", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Mccarty", + "lastName": "Bray", + "company": "Magnina", + "employed": false + }, + { + "firstName": "Miriam", + "lastName": "Montoya", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Joseph", + "lastName": "Cherry", + "company": "Zillatide", + "employed": true + }, + { + "firstName": "Diann", + "lastName": "Hamilton", + "company": "Uni", + "employed": true + }, + { + "firstName": "Elisa", + "lastName": "Calhoun", + "company": "Overfork", + "employed": false + }, + { + "firstName": "Reid", + "lastName": "Stanley", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Jimmie", + "lastName": "Nunez", + "company": "Shadease", + "employed": false + }, + { + "firstName": "Dean", + "lastName": "Reilly", + "company": "Duoflex", + "employed": false + }, + { + "firstName": "Ayala", + "lastName": "Padilla", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Beatrice", + "lastName": "Castaneda", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Drake", + "lastName": "Vazquez", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Katheryn", + "lastName": "Everett", + "company": "Genmex", + "employed": true + }, + { + "firstName": "Rose", + "lastName": "Kidd", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "Marianne", + "lastName": "Koch", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Yvette", + "lastName": "Gross", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Luna", + "lastName": "Love", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Angelique", + "lastName": "Christian", + "company": "Cyclonica", + "employed": true + }, + { + "firstName": "Leanne", + "lastName": "Higgins", + "company": "Geoform", + "employed": false + }, + { + "firstName": "Shawna", + "lastName": "Ward", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Debra", + "lastName": "Giles", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Anna", + "lastName": "Romero", + "company": "Endicil", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Baird", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Jacklyn", + "lastName": "Clarke", + "company": "Flexigen", + "employed": true + }, + { + "firstName": "Maureen", + "lastName": "Hewitt", + "company": "Irack", + "employed": true + }, + { + "firstName": "Bertie", + "lastName": "Hughes", + "company": "Zboo", + "employed": true + }, + { + "firstName": "Santiago", + "lastName": "Roth", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Palmer", + "lastName": "Bartlett", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Guadalupe", + "lastName": "Doyle", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Wooten", + "lastName": "Rush", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Henrietta", + "lastName": "Vargas", + "company": "Elpro", + "employed": false + }, + { + "firstName": "Fry", + "lastName": "Gregory", + "company": "Enjola", + "employed": true + }, + { + "firstName": "Corinne", + "lastName": "Wynn", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Millicent", + "lastName": "Slater", + "company": "Utarian", + "employed": true + }, + { + "firstName": "Corine", + "lastName": "Sharpe", + "company": "Xumonk", + "employed": true + }, + { + "firstName": "Valerie", + "lastName": "Bryan", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Newman", + "lastName": "Mckee", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Bullock", + "lastName": "Phelps", + "company": "Plexia", + "employed": true + }, + { + "firstName": "Francis", + "lastName": "Johnston", + "company": "Zillar", + "employed": true + }, + { + "firstName": "Stokes", + "lastName": "Cabrera", + "company": "Isoplex", + "employed": true + }, + { + "firstName": "Alvarez", + "lastName": "Clark", + "company": "Reversus", + "employed": true + }, + { + "firstName": "Dunn", + "lastName": "Mueller", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Brenda", + "lastName": "Moses", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Kellie", + "lastName": "Wheeler", + "company": "Tubalum", + "employed": true + }, + { + "firstName": "Audrey", + "lastName": "House", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Doris", + "lastName": "Gonzalez", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Leola", + "lastName": "Jones", + "company": "Naxdis", + "employed": true + }, + { + "firstName": "Ladonna", + "lastName": "Foley", + "company": "Sarasonic", + "employed": false + }, + { + "firstName": "Brandie", + "lastName": "White", + "company": "Glukgluk", + "employed": false + }, + { + "firstName": "Holly", + "lastName": "Hart", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Darla", + "lastName": "Hooper", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Ella", + "lastName": "Golden", + "company": "Stelaecor", + "employed": false + }, + { + "firstName": "Bertha", + "lastName": "Ballard", + "company": "Avit", + "employed": true + }, + { + "firstName": "Dorthy", + "lastName": "Wilcox", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Whitfield", + "lastName": "Lawrence", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Florine", + "lastName": "Hurst", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Olivia", + "lastName": "Kirk", + "company": "Retrack", + "employed": false + }, + { + "firstName": "Carissa", + "lastName": "Moore", + "company": "Kiggle", + "employed": false + }, + { + "firstName": "Jeanette", + "lastName": "Harrell", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Roy", + "lastName": "Baldwin", + "company": "Jetsilk", + "employed": true + }, + { + "firstName": "Peters", + "lastName": "Hays", + "company": "Zolar", + "employed": true + }, + { + "firstName": "Joyner", + "lastName": "Hartman", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Wilcox", + "lastName": "Mcdaniel", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Stuart", + "company": "Codact", + "employed": false + }, + { + "firstName": "Navarro", + "lastName": "Bender", + "company": "Puria", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Davidson", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Milagros", + "lastName": "Whitehead", + "company": "Isis", + "employed": true + }, + { + "firstName": "Riddle", + "lastName": "Carr", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Hope", + "lastName": "Sims", + "company": "Fangold", + "employed": true + }, + { + "firstName": "York", + "lastName": "Nguyen", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Lorie", + "lastName": "Johnston", + "company": "Endipine", + "employed": true + }, + { + "firstName": "Wiggins", + "lastName": "Webster", + "company": "Mixers", + "employed": true + }, + { + "firstName": "Hewitt", + "lastName": "Stanton", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Tara", + "lastName": "Young", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Holcomb", + "lastName": "Wright", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Nannie", + "lastName": "Castro", + "company": "Inrt", + "employed": true + }, + { + "firstName": "Tia", + "lastName": "Tillman", + "company": "Zork", + "employed": true + }, + { + "firstName": "Duran", + "lastName": "Gregory", + "company": "Rodeology", + "employed": false + }, + { + "firstName": "Bruce", + "lastName": "Curtis", + "company": "Waab", + "employed": false + }, + { + "firstName": "Beulah", + "lastName": "Maxwell", + "company": "Amril", + "employed": false + }, + { + "firstName": "Luella", + "lastName": "Stewart", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Marsha", + "lastName": "Sutton", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Daphne", + "lastName": "Rich", + "company": "Exoblue", + "employed": false + }, + { + "firstName": "Waller", + "lastName": "Soto", + "company": "Codax", + "employed": true + }, + { + "firstName": "Mason", + "lastName": "Russell", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Nguyen", + "lastName": "Sharpe", + "company": "Xeronk", + "employed": true + }, + { + "firstName": "Robbins", + "lastName": "Bryan", + "company": "Vurbo", + "employed": true + }, + { + "firstName": "Banks", + "lastName": "Sweeney", + "company": "Otherside", + "employed": false + }, + { + "firstName": "Fry", + "lastName": "Snow", + "company": "Optyk", + "employed": true + }, + { + "firstName": "Duncan", + "lastName": "Sawyer", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Veronica", + "lastName": "Mcfarland", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Davis", + "lastName": "Madden", + "company": "Geekol", + "employed": false + }, + { + "firstName": "Douglas", + "lastName": "Velazquez", + "company": "Keengen", + "employed": false + }, + { + "firstName": "Lakisha", + "lastName": "Riddle", + "company": "Tetratrex", + "employed": false + }, + { + "firstName": "Gomez", + "lastName": "Ware", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Elvira", + "lastName": "Castaneda", + "company": "Krag", + "employed": false + }, + { + "firstName": "Floyd", + "lastName": "Oneil", + "company": "Talae", + "employed": true + }, + { + "firstName": "Barbra", + "lastName": "Williamson", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Wolfe", + "company": "Viagrand", + "employed": true + }, + { + "firstName": "Rebecca", + "lastName": "Strickland", + "company": "Neteria", + "employed": true + }, + { + "firstName": "Fitzpatrick", + "lastName": "Guzman", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Sullivan", + "lastName": "Tanner", + "company": "Datagene", + "employed": true + }, + { + "firstName": "Garner", + "lastName": "Henson", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Richmond", + "lastName": "Petty", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Hammond", + "lastName": "Heath", + "company": "Prosely", + "employed": true + }, + { + "firstName": "Keith", + "lastName": "Contreras", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Dickson", + "lastName": "Mendoza", + "company": "Poochies", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Hendricks", + "company": "Comstar", + "employed": false + }, + { + "firstName": "Robyn", + "lastName": "Mcmahon", + "company": "Intergeek", + "employed": false + }, + { + "firstName": "Vaughan", + "lastName": "Sanford", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Hardy", + "lastName": "Lang", + "company": "Zaphire", + "employed": true + }, + { + "firstName": "Pace", + "lastName": "Mosley", + "company": "Cinesanct", + "employed": false + }, + { + "firstName": "Concetta", + "lastName": "Hancock", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Deirdre", + "lastName": "Olson", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Brittney", + "lastName": "Davis", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Gail", + "lastName": "Richmond", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Noel", + "company": "Jumpstack", + "employed": true + }, + { + "firstName": "Belinda", + "lastName": "Oneill", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Solomon", + "lastName": "Simon", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Emilia", + "lastName": "Livingston", + "company": "Filodyne", + "employed": true + }, + { + "firstName": "Manuela", + "lastName": "Berger", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Alisa", + "lastName": "Cruz", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Beth", + "lastName": "Huber", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Griffith", + "lastName": "Curry", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Schwartz", + "lastName": "Edwards", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Antoinette", + "lastName": "Patton", + "company": "Perkle", + "employed": true + }, + { + "firstName": "Lowery", + "lastName": "Massey", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Nadia", + "lastName": "Thompson", + "company": "Emoltra", + "employed": false + }, + { + "firstName": "Lana", + "lastName": "Herrera", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Sosa", + "lastName": "Craft", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Key", + "lastName": "Bishop", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Effie", + "lastName": "Hewitt", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Carmen", + "lastName": "English", + "company": "Nimon", + "employed": true + }, + { + "firstName": "Delores", + "lastName": "Bates", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Wolf", + "lastName": "Hampton", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Witt", + "lastName": "Hess", + "company": "Frosnex", + "employed": false + }, + { + "firstName": "Irma", + "lastName": "Boone", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Caitlin", + "lastName": "Spencer", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Concepcion", + "lastName": "Clay", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Tonya", + "lastName": "Collins", + "company": "Synkgen", + "employed": false + }, + { + "firstName": "Hattie", + "lastName": "Mccormick", + "company": "Austech", + "employed": true + }, + { + "firstName": "Summers", + "lastName": "Buchanan", + "company": "Assistix", + "employed": true + }, + { + "firstName": "Butler", + "lastName": "Nash", + "company": "Centree", + "employed": true + }, + { + "firstName": "Velez", + "lastName": "Francis", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Jami", + "lastName": "Yang", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Guy", + "lastName": "Fernandez", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Lester", + "lastName": "Banks", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Rojas", + "lastName": "Fitzgerald", + "company": "Omatom", + "employed": false + }, + { + "firstName": "Angel", + "lastName": "Beck", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Louise", + "lastName": "Douglas", + "company": "Gazak", + "employed": false + }, + { + "firstName": "Kimberly", + "lastName": "Levy", + "company": "Zipak", + "employed": true + }, + { + "firstName": "Gaines", + "lastName": "Padilla", + "company": "Sureplex", + "employed": false + }, + { + "firstName": "Ronda", + "lastName": "Cole", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Courtney", + "lastName": "Dunlap", + "company": "Enersave", + "employed": false + }, + { + "firstName": "Bridget", + "lastName": "Mullen", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Doyle", + "company": "Illumity", + "employed": false + }, + { + "firstName": "Herminia", + "lastName": "Greene", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Townsend", + "lastName": "Fleming", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Richard", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Angelina", + "lastName": "Leach", + "company": "Rodemco", + "employed": true + }, + { + "firstName": "Lloyd", + "lastName": "Washington", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Fanny", + "lastName": "Keller", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Deloris", + "lastName": "Wade", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Blankenship", + "lastName": "Medina", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Bell", + "lastName": "Mcgee", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Santos", + "lastName": "Marquez", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Hoffman", + "company": "Medesign", + "employed": true + }, + { + "firstName": "Nixon", + "lastName": "Lott", + "company": "Icology", + "employed": true + }, + { + "firstName": "Natalie", + "lastName": "Mason", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Tanner", + "lastName": "Juarez", + "company": "Enersol", + "employed": false + }, + { + "firstName": "Battle", + "lastName": "Delaney", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Maddox", + "lastName": "Bentley", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Baird", + "lastName": "Whitaker", + "company": "Zounds", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Moran", + "company": "Voratak", + "employed": false + }, + { + "firstName": "Nikki", + "lastName": "Drake", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Mendez", + "lastName": "Stevens", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Mckee", + "lastName": "Mcdowell", + "company": "Dadabase", + "employed": true + }, + { + "firstName": "Dalton", + "lastName": "James", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Kayla", + "lastName": "Stone", + "company": "Overfork", + "employed": false + }, + { + "firstName": "Maricela", + "lastName": "Clements", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Delacruz", + "company": "Insuresys", + "employed": true + }, + { + "firstName": "Mia", + "lastName": "Henry", + "company": "Gology", + "employed": true + }, + { + "firstName": "Amparo", + "lastName": "Perkins", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Ellis", + "lastName": "Wilder", + "company": "Jimbies", + "employed": false + }, + { + "firstName": "Sonya", + "lastName": "Cooley", + "company": "Ontality", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Suarez", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Ilene", + "lastName": "Randolph", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Christian", + "lastName": "Merrill", + "company": "Netbook", + "employed": true + }, + { + "firstName": "Tanisha", + "lastName": "Meyer", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Beck", + "lastName": "Klein", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Decker", + "lastName": "Dillard", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Hamilton", + "lastName": "Saunders", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Montgomery", + "lastName": "Blackburn", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Owen", + "lastName": "Bullock", + "company": "Kyaguru", + "employed": false + }, + { + "firstName": "Marissa", + "lastName": "Gould", + "company": "Imageflow", + "employed": false + }, + { + "firstName": "Mona", + "lastName": "Solis", + "company": "Xoggle", + "employed": false + }, + { + "firstName": "Vilma", + "lastName": "Ball", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Daniels", + "lastName": "Strong", + "company": "Exodoc", + "employed": true + }, + { + "firstName": "Paula", + "lastName": "Walsh", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Mitzi", + "lastName": "Watson", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Juanita", + "lastName": "Dawson", + "company": "Biotica", + "employed": true + }, + { + "firstName": "Casey", + "lastName": "Sanchez", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Byers", + "lastName": "Robertson", + "company": "Ginkle", + "employed": true + }, + { + "firstName": "Noemi", + "lastName": "Brady", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Vicky", + "lastName": "Mooney", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Burt", + "lastName": "Solomon", + "company": "Zaya", + "employed": false + }, + { + "firstName": "Miles", + "lastName": "Molina", + "company": "Digique", + "employed": false + }, + { + "firstName": "Roach", + "lastName": "Shannon", + "company": "Goko", + "employed": false + }, + { + "firstName": "Haney", + "lastName": "Mathis", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Aline", + "lastName": "Phelps", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Delaney", + "lastName": "Cobb", + "company": "Corepan", + "employed": false + }, + { + "firstName": "Brittany", + "lastName": "Griffith", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Stuart", + "lastName": "Mccray", + "company": "Kozgene", + "employed": true + }, + { + "firstName": "Corinne", + "lastName": "Summers", + "company": "Quonk", + "employed": false + }, + { + "firstName": "Shanna", + "lastName": "Kline", + "company": "Isologics", + "employed": false + }, + { + "firstName": "Kenya", + "lastName": "Mendez", + "company": "Digial", + "employed": true + }, + { + "firstName": "Pollard", + "lastName": "Thomas", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Janelle", + "lastName": "Lancaster", + "company": "Collaire", + "employed": false + }, + { + "firstName": "Tate", + "lastName": "Jefferson", + "company": "Roboid", + "employed": false + }, + { + "firstName": "Nellie", + "lastName": "Owens", + "company": "Liquicom", + "employed": false + }, + { + "firstName": "Winters", + "lastName": "Lester", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Carson", + "lastName": "Hobbs", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Curtis", + "lastName": "Vasquez", + "company": "Comtour", + "employed": false + }, + { + "firstName": "Lillie", + "lastName": "Battle", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Roseann", + "lastName": "Chavez", + "company": "Zillidium", + "employed": true + }, + { + "firstName": "Matthews", + "lastName": "Mathews", + "company": "Columella", + "employed": true + }, + { + "firstName": "Figueroa", + "lastName": "Middleton", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Luz", + "lastName": "Downs", + "company": "Cytrek", + "employed": false + }, + { + "firstName": "Greene", + "lastName": "Sampson", + "company": "Kegular", + "employed": false + }, + { + "firstName": "Blanca", + "lastName": "Everett", + "company": "Euron", + "employed": true + }, + { + "firstName": "Vega", + "lastName": "Kelley", + "company": "Gink", + "employed": false + }, + { + "firstName": "Sanford", + "lastName": "Goodman", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Faye", + "lastName": "William", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Lynda", + "lastName": "Carlson", + "company": "Locazone", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Dudley", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Stacey", + "lastName": "Cantu", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Glover", + "lastName": "Lambert", + "company": "Insectus", + "employed": false + }, + { + "firstName": "Calhoun", + "lastName": "Bowen", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Williams", + "lastName": "Chapman", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Nolan", + "lastName": "Spears", + "company": "Miracula", + "employed": true + }, + { + "firstName": "Jody", + "lastName": "Baird", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Cole", + "lastName": "Rivera", + "company": "Acruex", + "employed": false + }, + { + "firstName": "Leticia", + "lastName": "Hall", + "company": "Comfirm", + "employed": true + }, + { + "firstName": "Booker", + "lastName": "Wilkins", + "company": "Inquala", + "employed": false + }, + { + "firstName": "Glenna", + "lastName": "Crosby", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Alexander", + "lastName": "Colon", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Myers", + "company": "Cuizine", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Glass", + "company": "Enormo", + "employed": false + }, + { + "firstName": "Ana", + "lastName": "Wong", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Patel", + "lastName": "Kelly", + "company": "Unq", + "employed": true + }, + { + "firstName": "Patrica", + "lastName": "Atkins", + "company": "Gogol", + "employed": false + }, + { + "firstName": "Eddie", + "lastName": "Reeves", + "company": "Prismatic", + "employed": false + }, + { + "firstName": "Lucas", + "lastName": "Orr", + "company": "Snips", + "employed": true + }, + { + "firstName": "Bridgett", + "lastName": "Allison", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Patty", + "lastName": "Schmidt", + "company": "Songbird", + "employed": false + }, + { + "firstName": "Summer", + "lastName": "Carroll", + "company": "Zentry", + "employed": false + }, + { + "firstName": "Mercedes", + "lastName": "Valentine", + "company": "Zappix", + "employed": false + }, + { + "firstName": "Kathy", + "lastName": "Mcguire", + "company": "Olympix", + "employed": false + }, + { + "firstName": "Hampton", + "lastName": "Richards", + "company": "Techade", + "employed": true + }, + { + "firstName": "Dennis", + "lastName": "Potter", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Randall", + "lastName": "Holman", + "company": "Accruex", + "employed": false + }, + { + "firstName": "Harriet", + "lastName": "Frederick", + "company": "Danja", + "employed": true + }, + { + "firstName": "Kennedy", + "lastName": "Mckay", + "company": "Updat", + "employed": true + }, + { + "firstName": "Raymond", + "lastName": "Mullins", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Nichols", + "lastName": "Kinney", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Alexandra", + "lastName": "Barnett", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Priscilla", + "lastName": "Rhodes", + "company": "Vitricomp", + "employed": false + }, + { + "firstName": "Duke", + "lastName": "Cunningham", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Regina", + "lastName": "Abbott", + "company": "Zisis", + "employed": true + }, + { + "firstName": "Cheryl", + "lastName": "Knox", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "Delacruz", + "lastName": "Roy", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Palmer", + "lastName": "Shaffer", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Romero", + "lastName": "Savage", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Harrison", + "lastName": "Gilmore", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Mccarty", + "lastName": "Brewer", + "company": "Escenta", + "employed": false + }, + { + "firstName": "Bethany", + "lastName": "Osborne", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Thelma", + "lastName": "Andrews", + "company": "Snorus", + "employed": true + }, + { + "firstName": "Lupe", + "lastName": "May", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Blanchard", + "lastName": "Mcgowan", + "company": "Automon", + "employed": false + }, + { + "firstName": "Nelson", + "lastName": "Adkins", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Deana", + "lastName": "Lloyd", + "company": "Enerforce", + "employed": true + }, + { + "firstName": "Marquez", + "lastName": "Cameron", + "company": "Centuria", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Fowler", + "company": "Soprano", + "employed": true + }, + { + "firstName": "Holder", + "lastName": "Castillo", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Snyder", + "lastName": "Salas", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Burns", + "company": "Circum", + "employed": true + }, + { + "firstName": "Davidson", + "lastName": "Daniels", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Shaw", + "lastName": "Holden", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Cook", + "lastName": "Ingram", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Deborah", + "lastName": "Acevedo", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Hurley", + "lastName": "Flynn", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Combs", + "lastName": "Fletcher", + "company": "Cubicide", + "employed": false + }, + { + "firstName": "Shari", + "lastName": "Garcia", + "company": "Blanet", + "employed": true + }, + { + "firstName": "Katrina", + "lastName": "Welch", + "company": "Austex", + "employed": true + }, + { + "firstName": "Joni", + "lastName": "Parrish", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Barnes", + "lastName": "Silva", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Roslyn", + "lastName": "Carson", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Anne", + "lastName": "Chaney", + "company": "Urbanshee", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Barry", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Ericka", + "lastName": "Knight", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Corine", + "lastName": "Snyder", + "company": "Verbus", + "employed": true + }, + { + "firstName": "Vang", + "lastName": "Jensen", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Herrera", + "lastName": "Reid", + "company": "Kongle", + "employed": true + }, + { + "firstName": "Greta", + "lastName": "Vinson", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Marshall", + "lastName": "Tate", + "company": "Elemantra", + "employed": false + }, + { + "firstName": "Norris", + "lastName": "Tran", + "company": "Memora", + "employed": true + }, + { + "firstName": "Dianne", + "lastName": "Mcknight", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Guzman", + "lastName": "Hodges", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Donaldson", + "lastName": "Christensen", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Franks", + "lastName": "Austin", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Rios", + "lastName": "Schwartz", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Jackson", + "lastName": "Peterson", + "company": "Netility", + "employed": true + }, + { + "firstName": "Dudley", + "lastName": "Weber", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Susanna", + "lastName": "Holmes", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Suarez", + "lastName": "Phillips", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Hahn", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Singleton", + "lastName": "Brennan", + "company": "Bittor", + "employed": false + }, + { + "firstName": "Frank", + "lastName": "Lowery", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Patti", + "lastName": "Rojas", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Toni", + "lastName": "Gilbert", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Blair", + "lastName": "Vance", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Morgan", + "lastName": "Cherry", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Klein", + "lastName": "Barton", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Terrie", + "lastName": "Gardner", + "company": "Enjola", + "employed": true + }, + { + "firstName": "Foley", + "lastName": "Alvarez", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Hurley", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Gonzales", + "lastName": "Duran", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Horton", + "lastName": "Bailey", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Jackie", + "lastName": "Pennington", + "company": "Freakin", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Benton", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Maritza", + "lastName": "Petersen", + "company": "Equicom", + "employed": true + }, + { + "firstName": "Elinor", + "lastName": "Morales", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Lynch", + "lastName": "Horne", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Patsy", + "lastName": "Le", + "company": "Geoform", + "employed": false + }, + { + "firstName": "Josefina", + "lastName": "Eaton", + "company": "Panzent", + "employed": false + }, + { + "firstName": "Jordan", + "lastName": "Kirkland", + "company": "Limage", + "employed": false + }, + { + "firstName": "Moss", + "lastName": "Hill", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Dollie", + "lastName": "Hogan", + "company": "Qnekt", + "employed": true + }, + { + "firstName": "Tasha", + "lastName": "Ayers", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Kramer", + "lastName": "Mccoy", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "Margarita", + "lastName": "Burris", + "company": "Zytrek", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Macias", + "company": "Motovate", + "employed": true + }, + { + "firstName": "Alisha", + "lastName": "Blevins", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Verna", + "lastName": "Booker", + "company": "Injoy", + "employed": true + }, + { + "firstName": "Shields", + "lastName": "Wynn", + "company": "Marketoid", + "employed": true + }, + { + "firstName": "Anthony", + "lastName": "Moss", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Delgado", + "lastName": "Blackwell", + "company": "Squish", + "employed": true + }, + { + "firstName": "Beach", + "lastName": "Floyd", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Angelita", + "lastName": "Grimes", + "company": "Bunga", + "employed": true + }, + { + "firstName": "Joseph", + "lastName": "Gates", + "company": "Medicroix", + "employed": false + }, + { + "firstName": "Beatriz", + "lastName": "Peters", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Casandra", + "lastName": "Emerson", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Dominique", + "lastName": "Dunn", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Sara", + "lastName": "Gray", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Waters", + "lastName": "Hale", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Loretta", + "lastName": "Fulton", + "company": "Velity", + "employed": false + }, + { + "firstName": "Ruthie", + "lastName": "Conway", + "company": "Accel", + "employed": false + }, + { + "firstName": "Melba", + "lastName": "Mills", + "company": "Futuris", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Wilkinson", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Gallagher", + "lastName": "Goff", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Lilian", + "lastName": "Baxter", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Ware", + "lastName": "Wilkerson", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Burnett", + "company": "Mondicil", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Byrd", + "company": "Pushcart", + "employed": false + }, + { + "firstName": "Craft", + "lastName": "Hicks", + "company": "Zensus", + "employed": false + }, + { + "firstName": "James", + "lastName": "Meadows", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Paul", + "lastName": "Winters", + "company": "Quadeebo", + "employed": true + }, + { + "firstName": "Castaneda", + "lastName": "Lyons", + "company": "Opticom", + "employed": false + }, + { + "firstName": "Cynthia", + "lastName": "Hebert", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Forbes", + "lastName": "Dyer", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Mai", + "lastName": "Cohen", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Johanna", + "lastName": "Foster", + "company": "Zensor", + "employed": false + }, + { + "firstName": "Melissa", + "lastName": "Donovan", + "company": "Schoolio", + "employed": false + }, + { + "firstName": "Green", + "lastName": "Pena", + "company": "Cemention", + "employed": true + }, + { + "firstName": "Melendez", + "lastName": "Steele", + "company": "Flotonic", + "employed": false + }, + { + "firstName": "Marisol", + "lastName": "Compton", + "company": "Wrapture", + "employed": false + }, + { + "firstName": "Montoya", + "lastName": "Bradford", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Heath", + "lastName": "Bradley", + "company": "Progenex", + "employed": false + }, + { + "firstName": "Giles", + "lastName": "Hawkins", + "company": "Zolavo", + "employed": true + }, + { + "firstName": "Kirkland", + "lastName": "Horn", + "company": "Biohab", + "employed": true + }, + { + "firstName": "Yesenia", + "lastName": "Larsen", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Penelope", + "lastName": "Poole", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Avila", + "lastName": "Gallegos", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Vasquez", + "lastName": "Mclaughlin", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Velma", + "lastName": "Giles", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Lily", + "lastName": "Estrada", + "company": "Sultraxin", + "employed": false + }, + { + "firstName": "Peck", + "lastName": "Wiggins", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Tracey", + "lastName": "Key", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Johnston", + "lastName": "Cortez", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Greer", + "lastName": "Gentry", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Bolton", + "company": "Providco", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "Santiago", + "company": "Utarian", + "employed": true + }, + { + "firstName": "Preston", + "lastName": "Booth", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Hollie", + "lastName": "Best", + "company": "Eclipsent", + "employed": false + }, + { + "firstName": "Thornton", + "lastName": "Herman", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Angelia", + "lastName": "Woodard", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Silva", + "lastName": "Craig", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Latonya", + "lastName": "Chan", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Ebony", + "lastName": "Hughes", + "company": "Callflex", + "employed": true + }, + { + "firstName": "Pearson", + "lastName": "Murphy", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Lindsey", + "lastName": "Farmer", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Lorrie", + "lastName": "Levine", + "company": "Medifax", + "employed": false + }, + { + "firstName": "Janna", + "lastName": "Collier", + "company": "Surelogic", + "employed": false + }, + { + "firstName": "Lynne", + "lastName": "Reed", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Burch", + "lastName": "Nichols", + "company": "Quizka", + "employed": true + }, + { + "firstName": "Horne", + "lastName": "Sweet", + "company": "Vidto", + "employed": true + }, + { + "firstName": "Rosario", + "lastName": "Delgado", + "company": "Powernet", + "employed": false + }, + { + "firstName": "Huffman", + "lastName": "Ayala", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Kirsten", + "lastName": "Ryan", + "company": "Turnling", + "employed": false + }, + { + "firstName": "Kelli", + "lastName": "Anthony", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Chasity", + "lastName": "Crane", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Rosemary", + "lastName": "Villarreal", + "company": "Zialactic", + "employed": true + }, + { + "firstName": "Corina", + "lastName": "Bass", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Tina", + "lastName": "Cardenas", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Rae", + "lastName": "Thornton", + "company": "Genesynk", + "employed": false + }, + { + "firstName": "Dominguez", + "lastName": "Hernandez", + "company": "Imaginart", + "employed": true + }, + { + "firstName": "Shannon", + "lastName": "Ochoa", + "company": "Virva", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Mclean", + "company": "Ohmnet", + "employed": false + }, + { + "firstName": "Whitehead", + "lastName": "Holcomb", + "company": "Zenolux", + "employed": false + }, + { + "firstName": "Wendi", + "lastName": "Ortega", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Acevedo", + "lastName": "Dale", + "company": "Sustenza", + "employed": false + }, + { + "firstName": "Mcclain", + "lastName": "Callahan", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Leona", + "lastName": "Gross", + "company": "Combot", + "employed": true + }, + { + "firstName": "Baldwin", + "lastName": "Kirby", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Lane", + "lastName": "Osborn", + "company": "Intrawear", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "Vargas", + "company": "Overplex", + "employed": true + }, + { + "firstName": "Janet", + "lastName": "Woodward", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Socorro", + "lastName": "Roth", + "company": "Coash", + "employed": false + }, + { + "firstName": "Betty", + "lastName": "Ramirez", + "company": "Emtrak", + "employed": true + }, + { + "firstName": "Trudy", + "lastName": "Roberson", + "company": "Extrawear", + "employed": true + }, + { + "firstName": "Tabatha", + "lastName": "Faulkner", + "company": "Electonic", + "employed": false + }, + { + "firstName": "Cornelia", + "lastName": "Parsons", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Juliana", + "lastName": "Patrick", + "company": "Navir", + "employed": false + }, + { + "firstName": "Hunt", + "lastName": "Page", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Ofelia", + "lastName": "Wood", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "West", + "lastName": "Becker", + "company": "Pulze", + "employed": false + }, + { + "firstName": "Phelps", + "lastName": "Dodson", + "company": "Daido", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "Boyle", + "company": "Ecosys", + "employed": true + }, + { + "firstName": "Suzanne", + "lastName": "Stein", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Avis", + "lastName": "Morin", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Willis", + "lastName": "Townsend", + "company": "Zillar", + "employed": true + }, + { + "firstName": "Morrow", + "lastName": "Gutierrez", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Phyllis", + "lastName": "Mcclure", + "company": "Pyramax", + "employed": true + }, + { + "firstName": "Madeline", + "lastName": "Johns", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Payne", + "lastName": "Ferguson", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Pam", + "lastName": "Payne", + "company": "Skybold", + "employed": true + }, + { + "firstName": "Erica", + "lastName": "Flowers", + "company": "Velos", + "employed": true + }, + { + "firstName": "Eliza", + "lastName": "Wallace", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Cherie", + "lastName": "Witt", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Russo", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Mariana", + "lastName": "Dominguez", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Debora", + "lastName": "Haley", + "company": "Ezentia", + "employed": true + }, + { + "firstName": "Gross", + "lastName": "Mcmillan", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Solis", + "lastName": "Brock", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Bobbie", + "lastName": "Miranda", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Holland", + "lastName": "Torres", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Angelica", + "lastName": "Hamilton", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "French", + "lastName": "Benson", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Lenore", + "lastName": "Slater", + "company": "Balooba", + "employed": true + }, + { + "firstName": "Abbott", + "lastName": "Duke", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Jessica", + "lastName": "Mccullough", + "company": "Securia", + "employed": false + }, + { + "firstName": "Fuller", + "lastName": "Carver", + "company": "Proflex", + "employed": false + }, + { + "firstName": "Gray", + "lastName": "Mercado", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Burke", + "lastName": "Rivas", + "company": "Kog", + "employed": false + }, + { + "firstName": "Harvey", + "lastName": "Rollins", + "company": "Netplax", + "employed": true + }, + { + "firstName": "Eleanor", + "lastName": "Hubbard", + "company": "Pyramia", + "employed": false + }, + { + "firstName": "Pittman", + "lastName": "Caldwell", + "company": "Maximind", + "employed": true + }, + { + "firstName": "Aguirre", + "lastName": "Keith", + "company": "Omnigog", + "employed": false + }, + { + "firstName": "Madelyn", + "lastName": "Manning", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Hallie", + "lastName": "Daugherty", + "company": "Zilidium", + "employed": false + }, + { + "firstName": "Cecelia", + "lastName": "Walton", + "company": "Remold", + "employed": false + }, + { + "firstName": "Mcguire", + "lastName": "Hayes", + "company": "Utara", + "employed": true + }, + { + "firstName": "Sherrie", + "lastName": "Moon", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Leila", + "lastName": "Wells", + "company": "Comvene", + "employed": false + }, + { + "firstName": "Burgess", + "lastName": "Oneal", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Mayo", + "lastName": "Finley", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Magdalena", + "lastName": "Taylor", + "company": "Cogentry", + "employed": false + }, + { + "firstName": "Cohen", + "lastName": "Norris", + "company": "Hotcakes", + "employed": true + }, + { + "firstName": "Tamika", + "lastName": "Luna", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Lillian", + "lastName": "Frank", + "company": "Gorganic", + "employed": true + }, + { + "firstName": "Adele", + "lastName": "Marks", + "company": "Hydrocom", + "employed": true + }, + { + "firstName": "Alyssa", + "lastName": "Webb", + "company": "Isbol", + "employed": false + }, + { + "firstName": "Luisa", + "lastName": "Knowles", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Schultz", + "lastName": "Small", + "company": "Centrexin", + "employed": true + }, + { + "firstName": "Mccray", + "lastName": "Weiss", + "company": "Xiix", + "employed": true + }, + { + "firstName": "Patrice", + "lastName": "Kim", + "company": "Decratex", + "employed": false + }, + { + "firstName": "Case", + "lastName": "Gilliam", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Pearlie", + "lastName": "Calhoun", + "company": "Multron", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Gibbs", + "company": "Bitrex", + "employed": false + }, + { + "firstName": "Melva", + "lastName": "Todd", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Fuller", + "company": "Matrixity", + "employed": false + }, + { + "firstName": "Oneill", + "lastName": "Albert", + "company": "Zilla", + "employed": false + }, + { + "firstName": "Wallace", + "lastName": "Ramos", + "company": "Ecrater", + "employed": true + }, + { + "firstName": "Kathrine", + "lastName": "Erickson", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Sheppard", + "lastName": "Cook", + "company": "Koffee", + "employed": false + }, + { + "firstName": "Muriel", + "lastName": "Swanson", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Rosie", + "lastName": "Fuentes", + "company": "Comtest", + "employed": true + }, + { + "firstName": "Tammi", + "lastName": "Franco", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Marquita", + "lastName": "Sexton", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Hunt", + "company": "Lotron", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Robles", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Kendra", + "lastName": "Kidd", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Minerva", + "lastName": "Riggs", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Brandi", + "lastName": "Sargent", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Alexander", + "company": "Quilch", + "employed": true + }, + { + "firstName": "Wade", + "lastName": "Justice", + "company": "Idego", + "employed": false + }, + { + "firstName": "Santiago", + "lastName": "Figueroa", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Rhea", + "lastName": "Lynch", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Gould", + "lastName": "Wilson", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Cervantes", + "lastName": "Bird", + "company": "Edecine", + "employed": false + }, + { + "firstName": "Jacqueline", + "lastName": "Ellis", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Ava", + "lastName": "Bean", + "company": "Canopoly", + "employed": true + }, + { + "firstName": "Tillman", + "lastName": "Ortiz", + "company": "Acrodance", + "employed": false + }, + { + "firstName": "Hayden", + "lastName": "Nolan", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Mendoza", + "lastName": "Chen", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Wyatt", + "lastName": "Waters", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Dejesus", + "lastName": "Rush", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Chapman", + "lastName": "Burt", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Chandler", + "lastName": "Jordan", + "company": "Zidox", + "employed": false + }, + { + "firstName": "Powers", + "lastName": "Leon", + "company": "Qot", + "employed": false + }, + { + "firstName": "Fischer", + "lastName": "Elliott", + "company": "Conferia", + "employed": true + }, + { + "firstName": "Woodard", + "lastName": "Maddox", + "company": "Hivedom", + "employed": false + }, + { + "firstName": "Rivera", + "lastName": "Warner", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Petra", + "lastName": "Shields", + "company": "Manufact", + "employed": false + }, + { + "firstName": "Tameka", + "lastName": "Macdonald", + "company": "Octocore", + "employed": false + }, + { + "firstName": "Hanson", + "lastName": "Weaver", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Merritt", + "lastName": "Rutledge", + "company": "Asimiline", + "employed": false + }, + { + "firstName": "Mullins", + "lastName": "Schneider", + "company": "Gronk", + "employed": true + }, + { + "firstName": "Rich", + "lastName": "Hodge", + "company": "Geeketron", + "employed": true + }, + { + "firstName": "Cunningham", + "lastName": "Gonzales", + "company": "Zogak", + "employed": false + }, + { + "firstName": "Annie", + "lastName": "Parks", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Lawson", + "lastName": "Barr", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Angela", + "lastName": "Underwood", + "company": "Comtrak", + "employed": true + }, + { + "firstName": "Kate", + "lastName": "Sykes", + "company": "Zilladyne", + "employed": true + }, + { + "firstName": "Rosales", + "lastName": "Meyers", + "company": "Rooforia", + "employed": true + }, + { + "firstName": "Best", + "lastName": "Lowe", + "company": "Exozent", + "employed": true + }, + { + "firstName": "Knight", + "lastName": "Pate", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Edwina", + "lastName": "Santos", + "company": "Satiance", + "employed": true + }, + { + "firstName": "Karla", + "lastName": "York", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Mccall", + "company": "Zizzle", + "employed": false + }, + { + "firstName": "Jordan", + "lastName": "Salazar", + "company": "Translink", + "employed": false + }, + { + "firstName": "Wright", + "lastName": "George", + "company": "Yogasm", + "employed": false + }, + { + "firstName": "Nora", + "lastName": "Holt", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Delia", + "lastName": "Aguilar", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Hernandez", + "lastName": "Olsen", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Vivian", + "lastName": "Goodwin", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Manning", + "lastName": "Michael", + "company": "Deepends", + "employed": true + }, + { + "firstName": "Carr", + "lastName": "Price", + "company": "Nipaz", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Hopper", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Augusta", + "lastName": "Garner", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Soto", + "lastName": "Tyler", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Vonda", + "lastName": "Hunter", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Rhonda", + "lastName": "Sherman", + "company": "Flexigen", + "employed": false + }, + { + "firstName": "Benton", + "lastName": "Hoover", + "company": "Rameon", + "employed": true + }, + { + "firstName": "Underwood", + "lastName": "Wooten", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Vaughn", + "company": "Netplode", + "employed": true + }, + { + "firstName": "Mcgee", + "lastName": "Bruce", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Levine", + "lastName": "Vaughan", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Mitchell", + "lastName": "Kent", + "company": "Bulljuice", + "employed": false + }, + { + "firstName": "Judy", + "lastName": "Vega", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Jill", + "lastName": "Green", + "company": "Insource", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Koch", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Ophelia", + "lastName": "Miller", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Joseph", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Stephanie", + "lastName": "Trevino", + "company": "Geekwagon", + "employed": false + }, + { + "firstName": "Arnold", + "lastName": "Powell", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Susie", + "lastName": "Pruitt", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Kristie", + "lastName": "Guy", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Pearl", + "lastName": "Murray", + "company": "Helixo", + "employed": false + }, + { + "firstName": "Hardin", + "lastName": "Kane", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Bobbi", + "lastName": "Wolf", + "company": "Quiltigen", + "employed": false + }, + { + "firstName": "Jacquelyn", + "lastName": "Maldonado", + "company": "Rodeocean", + "employed": false + }, + { + "firstName": "Galloway", + "lastName": "Guerra", + "company": "Zilodyne", + "employed": true + }, + { + "firstName": "Rodgers", + "lastName": "Montoya", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Christina", + "lastName": "Johnson", + "company": "Krog", + "employed": true + }, + { + "firstName": "Amie", + "lastName": "Navarro", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Vicki", + "lastName": "Hayden", + "company": "Volax", + "employed": true + }, + { + "firstName": "Marylou", + "lastName": "Boyer", + "company": "Isoternia", + "employed": true + }, + { + "firstName": "Kidd", + "lastName": "Kaufman", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Gwen", + "lastName": "Valdez", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Patton", + "lastName": "Oconnor", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Bass", + "lastName": "Ford", + "company": "Orboid", + "employed": false + }, + { + "firstName": "Earnestine", + "lastName": "Lewis", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Mcleod", + "lastName": "Prince", + "company": "Entroflex", + "employed": false + }, + { + "firstName": "Tanya", + "lastName": "Farley", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Hendrix", + "lastName": "Willis", + "company": "Flyboyz", + "employed": false + }, + { + "firstName": "Madden", + "lastName": "Weeks", + "company": "Everest", + "employed": true + }, + { + "firstName": "Mcmillan", + "lastName": "Gibson", + "company": "Centice", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Dotson", + "company": "Hinway", + "employed": true + }, + { + "firstName": "Kerry", + "lastName": "Lucas", + "company": "Spacewax", + "employed": false + }, + { + "firstName": "Kristy", + "lastName": "Sosa", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Rodriguez", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Ethel", + "lastName": "Bradshaw", + "company": "Miraclis", + "employed": false + }, + { + "firstName": "Sondra", + "lastName": "Cantrell", + "company": "Grok", + "employed": true + }, + { + "firstName": "Rosanne", + "lastName": "Smith", + "company": "Andryx", + "employed": false + }, + { + "firstName": "Stanley", + "lastName": "Dixon", + "company": "Nexgene", + "employed": true + }, + { + "firstName": "Lula", + "lastName": "Vang", + "company": "Andershun", + "employed": true + }, + { + "firstName": "Sasha", + "lastName": "Branch", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Berry", + "lastName": "Norton", + "company": "Gadtron", + "employed": true + }, + { + "firstName": "Wood", + "lastName": "Pearson", + "company": "Klugger", + "employed": false + }, + { + "firstName": "Austin", + "lastName": "Cervantes", + "company": "Protodyne", + "employed": true + }, + { + "firstName": "Cameron", + "lastName": "Graham", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Schroeder", + "lastName": "Coffey", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Morton", + "lastName": "Rowe", + "company": "Vendblend", + "employed": false + }, + { + "firstName": "Fannie", + "lastName": "Butler", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Duffy", + "lastName": "Palmer", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Leanne", + "lastName": "Britt", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Henrietta", + "lastName": "Atkinson", + "company": "Sultrax", + "employed": false + }, + { + "firstName": "Mays", + "lastName": "Harvey", + "company": "Plasmosis", + "employed": true + }, + { + "firstName": "Crawford", + "lastName": "Newton", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Bowman", + "company": "Rocklogic", + "employed": true + }, + { + "firstName": "Claudia", + "lastName": "Ellison", + "company": "Opticon", + "employed": true + }, + { + "firstName": "Kaufman", + "lastName": "Berry", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Haynes", + "lastName": "Velez", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Virgie", + "lastName": "Hansen", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Emma", + "lastName": "Black", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Griffin", + "lastName": "Mckee", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Eloise", + "lastName": "Ratliff", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Bernice", + "lastName": "Duffy", + "company": "Waterbaby", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Valenzuela", + "company": "Pyramis", + "employed": false + }, + { + "firstName": "Britney", + "lastName": "Oliver", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Marks", + "lastName": "Freeman", + "company": "Wazzu", + "employed": true + }, + { + "firstName": "Robert", + "lastName": "Watkins", + "company": "Quizmo", + "employed": false + }, + { + "firstName": "Marcia", + "lastName": "Bridges", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Sandra", + "lastName": "Case", + "company": "Eventix", + "employed": false + }, + { + "firstName": "Bonita", + "lastName": "Harmon", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Roberts", + "lastName": "Mayo", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Lang", + "lastName": "Ross", + "company": "Assistia", + "employed": true + }, + { + "firstName": "Franklin", + "lastName": "Buck", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Alta", + "lastName": "Bray", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Rowland", + "lastName": "Farrell", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Justice", + "lastName": "Mcneil", + "company": "Prosure", + "employed": false + }, + { + "firstName": "Odom", + "lastName": "Ward", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Margery", + "lastName": "Leonard", + "company": "Corporana", + "employed": false + }, + { + "firstName": "Boyle", + "lastName": "Armstrong", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Martin", + "company": "Accufarm", + "employed": false + }, + { + "firstName": "Freda", + "lastName": "Beach", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Darlene", + "lastName": "Carney", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Rena", + "lastName": "Rodriquez", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "Nola", + "lastName": "Burch", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Park", + "lastName": "Turner", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Maynard", + "lastName": "Graves", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Meagan", + "lastName": "Yates", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Tommie", + "lastName": "Brooks", + "company": "Pigzart", + "employed": true + }, + { + "firstName": "Hilary", + "lastName": "Mays", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Garza", + "lastName": "Hyde", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Cummings", + "lastName": "Cooke", + "company": "Ecolight", + "employed": false + }, + { + "firstName": "Ellison", + "lastName": "Burgess", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Casey", + "lastName": "Mitchell", + "company": "Firewax", + "employed": false + }, + { + "firstName": "Gardner", + "lastName": "Williams", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Moody", + "lastName": "Shaw", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Ellen", + "lastName": "Roman", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Lauren", + "lastName": "Aguirre", + "company": "Colaire", + "employed": false + }, + { + "firstName": "Atkinson", + "lastName": "Forbes", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Melinda", + "lastName": "Cotton", + "company": "Zidant", + "employed": false + }, + { + "firstName": "Sloan", + "lastName": "Browning", + "company": "Netropic", + "employed": false + }, + { + "firstName": "Mcintosh", + "lastName": "Hester", + "company": "Extremo", + "employed": true + }, + { + "firstName": "Harmon", + "lastName": "Glover", + "company": "Spherix", + "employed": true + }, + { + "firstName": "Fran", + "lastName": "Charles", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Pitts", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Rosalinda", + "lastName": "Dean", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Alissa", + "lastName": "Gay", + "company": "Aquoavo", + "employed": true + }, + { + "firstName": "Larson", + "lastName": "Montgomery", + "company": "Farmage", + "employed": true + }, + { + "firstName": "Dunlap", + "lastName": "Hood", + "company": "Idealis", + "employed": true + }, + { + "firstName": "Francis", + "lastName": "Lynn", + "company": "Tasmania", + "employed": false + }, + { + "firstName": "Eva", + "lastName": "Terrell", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Blanche", + "lastName": "Cleveland", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Colleen", + "lastName": "Fry", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Wynn", + "lastName": "Frye", + "company": "Kneedles", + "employed": false + }, + { + "firstName": "Maggie", + "lastName": "Stephenson", + "company": "Katakana", + "employed": false + }, + { + "firstName": "Stokes", + "lastName": "Crawford", + "company": "Solaren", + "employed": false + }, + { + "firstName": "Annmarie", + "lastName": "Estes", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Jenny", + "lastName": "Franklin", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Perry", + "lastName": "Hopkins", + "company": "Pharmex", + "employed": false + }, + { + "firstName": "Tyler", + "lastName": "Evans", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Jo", + "lastName": "Powers", + "company": "Aclima", + "employed": false + }, + { + "firstName": "Saunders", + "lastName": "Fisher", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Audra", + "lastName": "Nelson", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Mattie", + "lastName": "Camacho", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Abigail", + "lastName": "Mcintyre", + "company": "Exiand", + "employed": true + }, + { + "firstName": "Jeri", + "lastName": "Dennis", + "company": "Imkan", + "employed": true + }, + { + "firstName": "Dora", + "lastName": "Clemons", + "company": "Namegen", + "employed": false + }, + { + "firstName": "Cristina", + "lastName": "Rose", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Mccullough", + "lastName": "Combs", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Tammy", + "lastName": "Martinez", + "company": "Pawnagra", + "employed": false + }, + { + "firstName": "Hodge", + "lastName": "Espinoza", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Rice", + "company": "Digifad", + "employed": false + }, + { + "firstName": "King", + "lastName": "Calderon", + "company": "Amtap", + "employed": true + }, + { + "firstName": "Erin", + "lastName": "Blake", + "company": "Obones", + "employed": false + }, + { + "firstName": "Marcie", + "lastName": "Kemp", + "company": "Duoflex", + "employed": false + }, + { + "firstName": "Johns", + "lastName": "Landry", + "company": "Verton", + "employed": true + }, + { + "firstName": "Sheila", + "lastName": "Davenport", + "company": "Centregy", + "employed": false + }, + { + "firstName": "Bentley", + "lastName": "Roberts", + "company": "Bluegrain", + "employed": false + }, + { + "firstName": "Meyer", + "lastName": "Matthews", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Oneal", + "lastName": "Brown", + "company": "Glasstep", + "employed": true + }, + { + "firstName": "Betsy", + "lastName": "Reilly", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Lilia", + "lastName": "Donaldson", + "company": "Genmy", + "employed": true + }, + { + "firstName": "Moses", + "lastName": "Hardy", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Roman", + "lastName": "Harrison", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Jenkins", + "lastName": "Lane", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Inez", + "lastName": "Herring", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Gamble", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Macdonald", + "lastName": "Pierce", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Lindsay", + "lastName": "Harris", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Hoover", + "lastName": "Daniel", + "company": "Fitcore", + "employed": true + }, + { + "firstName": "Carol", + "lastName": "Nieves", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Chris", + "lastName": "Barker", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Adela", + "lastName": "Travis", + "company": "Stucco", + "employed": true + }, + { + "firstName": "Sears", + "lastName": "Melendez", + "company": "Pearlessa", + "employed": true + }, + { + "firstName": "Deidre", + "lastName": "Morton", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Ernestine", + "lastName": "Barber", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Prince", + "lastName": "Maynard", + "company": "Sealoud", + "employed": false + }, + { + "firstName": "Imelda", + "lastName": "Conner", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Martha", + "lastName": "Puckett", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Kris", + "lastName": "Newman", + "company": "Bicol", + "employed": true + }, + { + "firstName": "Steele", + "lastName": "Alston", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Haynes", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Buckley", + "lastName": "Hickman", + "company": "Isosphere", + "employed": true + }, + { + "firstName": "Ball", + "lastName": "Jennings", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Mcknight", + "lastName": "Bartlett", + "company": "Zerbina", + "employed": true + }, + { + "firstName": "Bertie", + "lastName": "Burton", + "company": "Unisure", + "employed": true + }, + { + "firstName": "Hensley", + "lastName": "Dickerson", + "company": "Zanymax", + "employed": false + }, + { + "firstName": "Jefferson", + "lastName": "Mcdonald", + "company": "Flumbo", + "employed": true + }, + { + "firstName": "Sims", + "lastName": "Owen", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Swanson", + "lastName": "Deleon", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Brady", + "lastName": "Nicholson", + "company": "Kidgrease", + "employed": false + }, + { + "firstName": "Price", + "lastName": "Bauer", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Cooper", + "lastName": "Lee", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Jewell", + "lastName": "Lawson", + "company": "Quonata", + "employed": true + }, + { + "firstName": "Flossie", + "lastName": "Garrison", + "company": "Oatfarm", + "employed": false + }, + { + "firstName": "Jessie", + "lastName": "Whitfield", + "company": "Snowpoke", + "employed": true + }, + { + "firstName": "Wong", + "lastName": "Durham", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Darcy", + "lastName": "Whitney", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Sutton", + "lastName": "Wagner", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Mclaughlin", + "lastName": "Frost", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Sallie", + "lastName": "Pugh", + "company": "Pearlesex", + "employed": true + }, + { + "firstName": "Frances", + "lastName": "Pickett", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Terra", + "lastName": "Sharp", + "company": "Vortexaco", + "employed": true + }, + { + "firstName": "Estela", + "lastName": "Nixon", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Mae", + "lastName": "Holland", + "company": "Endipin", + "employed": true + }, + { + "firstName": "Angeline", + "lastName": "Holder", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Gabrielle", + "lastName": "Hendrix", + "company": "Comcur", + "employed": false + }, + { + "firstName": "Weaver", + "lastName": "Rosales", + "company": "Aquamate", + "employed": false + }, + { + "firstName": "Fulton", + "lastName": "Harding", + "company": "Sulfax", + "employed": false + }, + { + "firstName": "Le", + "lastName": "Mcleod", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Alba", + "lastName": "Lopez", + "company": "Autograte", + "employed": false + }, + { + "firstName": "Camille", + "lastName": "Duncan", + "company": "Deviltoe", + "employed": false + }, + { + "firstName": "Lydia", + "lastName": "Shepherd", + "company": "Slax", + "employed": true + }, + { + "firstName": "Elena", + "lastName": "Cain", + "company": "Obliq", + "employed": true + }, + { + "firstName": "Jeanie", + "lastName": "Horton", + "company": "Strozen", + "employed": true + }, + { + "firstName": "Mcgowan", + "lastName": "Workman", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Tran", + "lastName": "Mcpherson", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Clara", + "lastName": "Walters", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Elisabeth", + "lastName": "Gaines", + "company": "Acusage", + "employed": true + }, + { + "firstName": "Marlene", + "lastName": "Blair", + "company": "Shadease", + "employed": true + }, + { + "firstName": "Downs", + "lastName": "Adams", + "company": "Xymonk", + "employed": true + }, + { + "firstName": "Roberta", + "lastName": "Beard", + "company": "Terragen", + "employed": true + }, + { + "firstName": "Chelsea", + "lastName": "Lara", + "company": "Zosis", + "employed": false + }, + { + "firstName": "Fields", + "lastName": "Kennedy", + "company": "Sunclipse", + "employed": false + }, + { + "firstName": "Stafford", + "lastName": "Cox", + "company": "Telpod", + "employed": true + }, + { + "firstName": "Tracie", + "lastName": "Blanchard", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Laurie", + "lastName": "Moreno", + "company": "Kage", + "employed": false + }, + { + "firstName": "Kristina", + "lastName": "Day", + "company": "Apex", + "employed": false + }, + { + "firstName": "Theresa", + "lastName": "Skinner", + "company": "Gynko", + "employed": false + }, + { + "firstName": "Erna", + "lastName": "Greer", + "company": "Straloy", + "employed": false + }, + { + "firstName": "Bowers", + "lastName": "Ruiz", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Amanda", + "lastName": "Harper", + "company": "Macronaut", + "employed": false + }, + { + "firstName": "Atkins", + "lastName": "Pollard", + "company": "Dancerity", + "employed": true + }, + { + "firstName": "Reyna", + "lastName": "Jacobs", + "company": "Xinware", + "employed": false + }, + { + "firstName": "Margo", + "lastName": "Ramsey", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Grant", + "lastName": "Houston", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Cote", + "lastName": "Barrera", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Crystal", + "lastName": "Guerrero", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Joan", + "lastName": "Mckinney", + "company": "Pyrami", + "employed": true + }, + { + "firstName": "Natalia", + "lastName": "Serrano", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Dawn", + "lastName": "Hinton", + "company": "Applideck", + "employed": false + }, + { + "firstName": "Trina", + "lastName": "Gill", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Odessa", + "lastName": "West", + "company": "Interfind", + "employed": true + }, + { + "firstName": "Kristine", + "lastName": "Boyd", + "company": "Toyletry", + "employed": false + }, + { + "firstName": "Iris", + "lastName": "Head", + "company": "Netur", + "employed": true + }, + { + "firstName": "Wise", + "lastName": "Finch", + "company": "Radiantix", + "employed": false + }, + { + "firstName": "Strickland", + "lastName": "Sears", + "company": "Inear", + "employed": true + }, + { + "firstName": "Mercer", + "lastName": "Church", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Rose", + "lastName": "Campbell", + "company": "Strezzo", + "employed": false + }, + { + "firstName": "Francisca", + "lastName": "Noble", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Erika", + "lastName": "David", + "company": "Malathion", + "employed": true + }, + { + "firstName": "Amalia", + "lastName": "Langley", + "company": "Zillacon", + "employed": true + }, + { + "firstName": "Livingston", + "lastName": "Munoz", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Dotson", + "lastName": "Ewing", + "company": "Minga", + "employed": true + }, + { + "firstName": "Jillian", + "lastName": "Robinson", + "company": "Signity", + "employed": true + }, + { + "firstName": "Shana", + "lastName": "Simpson", + "company": "Enomen", + "employed": true + }, + { + "firstName": "Mckenzie", + "lastName": "Henderson", + "company": "Assitia", + "employed": true + }, + { + "firstName": "Marcy", + "lastName": "Walter", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Stone", + "lastName": "Patterson", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Kathie", + "lastName": "Stanley", + "company": "Ramjob", + "employed": false + }, + { + "firstName": "Shelly", + "lastName": "Chandler", + "company": "Nurplex", + "employed": true + }, + { + "firstName": "Strong", + "lastName": "Wall", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Nona", + "lastName": "Rocha", + "company": "Endicil", + "employed": true + }, + { + "firstName": "Johnson", + "lastName": "Baker", + "company": "Architax", + "employed": false + }, + { + "firstName": "Cline", + "lastName": "Salinas", + "company": "Comveyor", + "employed": false + }, + { + "firstName": "Esperanza", + "lastName": "Rivers", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Massey", + "lastName": "Coleman", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Petersen", + "lastName": "Ashley", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Houston", + "lastName": "Dillon", + "company": "Nixelt", + "employed": false + }, + { + "firstName": "Pate", + "lastName": "Whitley", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Carolina", + "lastName": "Spence", + "company": "Orbaxter", + "employed": true + }, + { + "firstName": "Wells", + "lastName": "Nunez", + "company": "Qaboos", + "employed": true + }, + { + "firstName": "Mcmahon", + "lastName": "Sheppard", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Sabrina", + "lastName": "Quinn", + "company": "Biflex", + "employed": true + }, + { + "firstName": "Enid", + "lastName": "Sloan", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Dorothea", + "lastName": "Alvarado", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Jimmie", + "lastName": "Chang", + "company": "Uberlux", + "employed": true + }, + { + "firstName": "Christi", + "lastName": "Odonnell", + "company": "Dogtown", + "employed": true + }, + { + "firstName": "James", + "lastName": "Morris", + "company": "Comdom", + "employed": false + }, + { + "firstName": "Fowler", + "lastName": "Cash", + "company": "Premiant", + "employed": true + }, + { + "firstName": "Perez", + "lastName": "Valencia", + "company": "Kineticut", + "employed": true + }, + { + "firstName": "Cash", + "lastName": "Snider", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Carey", + "lastName": "Patel", + "company": "Fanfare", + "employed": false + }, + { + "firstName": "Middleton", + "lastName": "Carrillo", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Clarke", + "lastName": "Mckenzie", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Simpson", + "lastName": "Glenn", + "company": "Zytrac", + "employed": false + }, + { + "firstName": "Staci", + "lastName": "Pratt", + "company": "Atgen", + "employed": false + }, + { + "firstName": "Addie", + "lastName": "Cross", + "company": "Geeknet", + "employed": true + }, + { + "firstName": "Lambert", + "lastName": "Mcclain", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Guthrie", + "lastName": "Clarke", + "company": "Gracker", + "employed": true + }, + { + "firstName": "Bradford", + "lastName": "Barrett", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Good", + "lastName": "Galloway", + "company": "Fleetmix", + "employed": false + }, + { + "firstName": "Brigitte", + "lastName": "French", + "company": "Comtours", + "employed": false + }, + { + "firstName": "Espinoza", + "lastName": "Cummings", + "company": "Immunics", + "employed": true + }, + { + "firstName": "Katherine", + "lastName": "Schultz", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Farley", + "lastName": "Romero", + "company": "Applica", + "employed": true + }, + { + "firstName": "Gibbs", + "lastName": "Cooper", + "company": "Viagreat", + "employed": false + }, + { + "firstName": "Lynn", + "lastName": "Robbins", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Hazel", + "lastName": "Reyes", + "company": "Envire", + "employed": true + }, + { + "firstName": "Frye", + "lastName": "Huffman", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Mccarthy", + "lastName": "Moody", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Cardenas", + "lastName": "Jackson", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Alma", + "lastName": "Warren", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Brennan", + "lastName": "Rogers", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Neal", + "lastName": "Barlow", + "company": "Pathways", + "employed": true + }, + { + "firstName": "Foster", + "lastName": "Bowers", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Caldwell", + "lastName": "Bernard", + "company": "Techtrix", + "employed": false + }, + { + "firstName": "Anna", + "lastName": "Mercer", + "company": "Xylar", + "employed": true + }, + { + "firstName": "Barker", + "lastName": "Pacheco", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Marina", + "lastName": "Sullivan", + "company": "Golistic", + "employed": true + }, + { + "firstName": "Tania", + "lastName": "Mccarty", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Cecile", + "lastName": "Hanson", + "company": "Plasto", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Frazier", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Marva", + "lastName": "Terry", + "company": "Fibrodyne", + "employed": false + }, + { + "firstName": "Henson", + "lastName": "Stephens", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Sweet", + "lastName": "Fischer", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Beatrice", + "lastName": "Stokes", + "company": "Unia", + "employed": true + }, + { + "firstName": "Cain", + "lastName": "Clayton", + "company": "Cedward", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Fox", + "company": "Crustatia", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Neal", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Sharon", + "lastName": "Obrien", + "company": "Megall", + "employed": false + }, + { + "firstName": "Lucille", + "lastName": "Howell", + "company": "Cormoran", + "employed": false + }, + { + "firstName": "Beverly", + "lastName": "Stevenson", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Baxter", + "lastName": "Buckner", + "company": "Imant", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Harrington", + "company": "Mantrix", + "employed": true + }, + { + "firstName": "Mooney", + "lastName": "Rodgers", + "company": "Quilk", + "employed": true + }, + { + "firstName": "Selena", + "lastName": "Bell", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Olsen", + "lastName": "Peck", + "company": "Sloganaut", + "employed": true + }, + { + "firstName": "Cross", + "lastName": "Mcconnell", + "company": "Virxo", + "employed": true + }, + { + "firstName": "Wolfe", + "lastName": "Fields", + "company": "Boink", + "employed": false + }, + { + "firstName": "Aileen", + "lastName": "Campos", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Myrtle", + "lastName": "Berg", + "company": "Eschoir", + "employed": true + }, + { + "firstName": "Ramsey", + "lastName": "Talley", + "company": "Ovolo", + "employed": false + }, + { + "firstName": "Oliver", + "lastName": "Zamora", + "company": "Trollery", + "employed": true + }, + { + "firstName": "Ivy", + "lastName": "Randall", + "company": "Frolix", + "employed": true + }, + { + "firstName": "Pauline", + "lastName": "Rosario", + "company": "Beadzza", + "employed": false + }, + { + "firstName": "Trisha", + "lastName": "Riley", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Rowland", + "company": "Franscene", + "employed": false + }, + { + "firstName": "Rene", + "lastName": "Carey", + "company": "Roughies", + "employed": false + }, + { + "firstName": "Bolton", + "lastName": "Howard", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Drake", + "lastName": "Garrett", + "company": "Podunk", + "employed": true + }, + { + "firstName": "Frederick", + "lastName": "Gallagher", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Sonia", + "lastName": "Joyce", + "company": "Uni", + "employed": true + }, + { + "firstName": "Erickson", + "lastName": "Briggs", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Jacobson", + "lastName": "Reynolds", + "company": "Geoforma", + "employed": false + }, + { + "firstName": "Campbell", + "lastName": "Paul", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Lolita", + "lastName": "Long", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Wanda", + "lastName": "Wyatt", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Christa", + "lastName": "Foreman", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Berger", + "lastName": "Bryant", + "company": "Xth", + "employed": true + }, + { + "firstName": "Mills", + "lastName": "Velasquez", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Jacklyn", + "lastName": "Richardson", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Dyer", + "lastName": "Hammond", + "company": "Speedbolt", + "employed": true + }, + { + "firstName": "Gamble", + "lastName": "Morgan", + "company": "Phormula", + "employed": false + }, + { + "firstName": "Sofia", + "lastName": "Mcbride", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Torres", + "lastName": "Cochran", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Cox", + "lastName": "Walker", + "company": "Terrago", + "employed": true + }, + { + "firstName": "Avery", + "lastName": "Fitzpatrick", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Acosta", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Julianne", + "lastName": "Watts", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Gina", + "lastName": "Blankenship", + "company": "Teraprene", + "employed": false + }, + { + "firstName": "Lenora", + "lastName": "Norman", + "company": "Eclipto", + "employed": false + }, + { + "firstName": "Reba", + "lastName": "Parker", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Day", + "lastName": "Porter", + "company": "Comtext", + "employed": true + }, + { + "firstName": "Mccall", + "lastName": "Arnold", + "company": "Gynk", + "employed": false + }, + { + "firstName": "Iva", + "lastName": "Schroeder", + "company": "Luxuria", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Sparks", + "company": "Comtract", + "employed": false + }, + { + "firstName": "Maxwell", + "lastName": "Rios", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Skinner", + "lastName": "Good", + "company": "Neptide", + "employed": true + }, + { + "firstName": "Page", + "lastName": "Christian", + "company": "Zytrax", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Mccarthy", + "company": "Petigems", + "employed": true + }, + { + "firstName": "Byrd", + "lastName": "Lamb", + "company": "Quinex", + "employed": false + }, + { + "firstName": "Gertrude", + "lastName": "Knapp", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Jodi", + "lastName": "Jarvis", + "company": "Extro", + "employed": false + }, + { + "firstName": "Nell", + "lastName": "Jimenez", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Phillips", + "lastName": "Kerr", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Judith", + "lastName": "Simmons", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Barrera", + "lastName": "Avery", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Holloway", + "lastName": "Miles", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Hannah", + "lastName": "Bonner", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Tisha", + "lastName": "Perry", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Durham", + "lastName": "Raymond", + "company": "Optique", + "employed": false + }, + { + "firstName": "Carla", + "lastName": "Love", + "company": "Avenetro", + "employed": false + }, + { + "firstName": "Millicent", + "lastName": "Merritt", + "company": "Geekosis", + "employed": true + }, + { + "firstName": "Victoria", + "lastName": "Logan", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Gretchen", + "lastName": "Stark", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Snider", + "lastName": "Byers", + "company": "Kyagoro", + "employed": true + }, + { + "firstName": "Tabitha", + "lastName": "Sellers", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Glass", + "lastName": "Hatfield", + "company": "Combogene", + "employed": true + }, + { + "firstName": "Yang", + "lastName": "Chase", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Francesca", + "lastName": "Morrow", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Josie", + "lastName": "Lindsay", + "company": "Senmei", + "employed": false + }, + { + "firstName": "Lorena", + "lastName": "King", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Flowers", + "lastName": "Flores", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Dillon", + "lastName": "Hudson", + "company": "Halap", + "employed": false + }, + { + "firstName": "Brooke", + "lastName": "Ferrell", + "company": "Isologix", + "employed": false + }, + { + "firstName": "Marcella", + "lastName": "Bush", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Roxanne", + "lastName": "Woods", + "company": "Diginetic", + "employed": false + }, + { + "firstName": "Hopper", + "lastName": "Guthrie", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Colon", + "lastName": "Stout", + "company": "Portica", + "employed": false + }, + { + "firstName": "Newton", + "lastName": "Mann", + "company": "Xplor", + "employed": true + }, + { + "firstName": "Fitzgerald", + "lastName": "Rosa", + "company": "Vetron", + "employed": true + }, + { + "firstName": "Boone", + "lastName": "Little", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Maryanne", + "lastName": "Conley", + "company": "Evidends", + "employed": true + }, + { + "firstName": "Mcclure", + "lastName": "Hardin", + "company": "Earbang", + "employed": false + }, + { + "firstName": "Mercado", + "lastName": "Lindsey", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Nichole", + "lastName": "Wiley", + "company": "Accusage", + "employed": true + }, + { + "firstName": "Britt", + "lastName": "Hines", + "company": "Cyclonica", + "employed": false + }, + { + "firstName": "Kay", + "lastName": "Morse", + "company": "Songlines", + "employed": false + }, + { + "firstName": "Jewel", + "lastName": "Griffin", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Zelma", + "lastName": "Tyson", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Frost", + "lastName": "Howe", + "company": "Comverges", + "employed": false + }, + { + "firstName": "Julia", + "lastName": "Pope", + "company": "Quility", + "employed": false + }, + { + "firstName": "Maura", + "lastName": "Preston", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Spence", + "lastName": "Roach", + "company": "Genmex", + "employed": false + }, + { + "firstName": "Chase", + "lastName": "Marshall", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Dianna", + "lastName": "Garza", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Freida", + "lastName": "Hutchinson", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Davenport", + "lastName": "Holloway", + "company": "Magnina", + "employed": false + }, + { + "firstName": "Sherry", + "lastName": "Decker", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Donna", + "lastName": "Dickson", + "company": "Temorak", + "employed": false + }, + { + "firstName": "Hatfield", + "lastName": "Huff", + "company": "Playce", + "employed": false + }, + { + "firstName": "Elise", + "lastName": "Vazquez", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Isabella", + "lastName": "Barron", + "company": "Opticall", + "employed": false + }, + { + "firstName": "Helga", + "lastName": "Shelton", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Beard", + "lastName": "Pace", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Burke", + "company": "Portalis", + "employed": false + }, + { + "firstName": "Villarreal", + "lastName": "Jacobson", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Gilliam", + "lastName": "Gordon", + "company": "Musaphics", + "employed": true + }, + { + "firstName": "Sandy", + "lastName": "Casey", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Peterson", + "lastName": "Anderson", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Sophia", + "lastName": "Walls", + "company": "Zinca", + "employed": false + }, + { + "firstName": "Howe", + "lastName": "Bennett", + "company": "Tersanki", + "employed": true + }, + { + "firstName": "Burton", + "lastName": "Kramer", + "company": "Digigene", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Cabrera", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Riggs", + "lastName": "Reese", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Juana", + "lastName": "Dejesus", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Kristen", + "lastName": "Cannon", + "company": "Interodeo", + "employed": false + }, + { + "firstName": "Eve", + "lastName": "Odom", + "company": "Photobin", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Wise", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Calderon", + "lastName": "Dorsey", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Mueller", + "lastName": "Mejia", + "company": "Shopabout", + "employed": false + }, + { + "firstName": "Penny", + "lastName": "Morrison", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Maureen", + "lastName": "Waller", + "company": "Besto", + "employed": true + }, + { + "firstName": "Kerri", + "lastName": "Gillespie", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Craig", + "lastName": "Joyner", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Hopkins", + "lastName": "Potts", + "company": "Empirica", + "employed": true + }, + { + "firstName": "Yolanda", + "lastName": "Jenkins", + "company": "Concility", + "employed": true + }, + { + "firstName": "Celia", + "lastName": "Singleton", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Rollins", + "lastName": "Beasley", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Melisa", + "lastName": "Nielsen", + "company": "Housedown", + "employed": true + }, + { + "firstName": "Rosetta", + "lastName": "Shepard", + "company": "Iplax", + "employed": true + }, + { + "firstName": "Pansy", + "lastName": "Bond", + "company": "Irack", + "employed": true + }, + { + "firstName": "Hubbard", + "lastName": "Irwin", + "company": "Billmed", + "employed": false + }, + { + "firstName": "Mayra", + "lastName": "Higgins", + "company": "Magnemo", + "employed": false + }, + { + "firstName": "Vickie", + "lastName": "Sanders", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Campos", + "lastName": "Sandoval", + "company": "Furnafix", + "employed": false + }, + { + "firstName": "Sharp", + "lastName": "Benjamin", + "company": "Tourmania", + "employed": false + }, + { + "firstName": "Roxie", + "lastName": "Mayer", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Sparks", + "lastName": "Allen", + "company": "Tropoli", + "employed": false + }, + { + "firstName": "Gates", + "lastName": "Carpenter", + "company": "Portico", + "employed": false + }, + { + "firstName": "Lelia", + "lastName": "Vincent", + "company": "Hairport", + "employed": true + }, + { + "firstName": "Helen", + "lastName": "Hull", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Nita", + "lastName": "Ray", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Georgette", + "lastName": "Short", + "company": "Darwinium", + "employed": false + }, + { + "firstName": "Crosby", + "lastName": "Marsh", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Elaine", + "lastName": "Franks", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Lorraine", + "lastName": "Leblanc", + "company": "Eplode", + "employed": true + }, + { + "firstName": "Willa", + "lastName": "Bright", + "company": "Furnitech", + "employed": true + }, + { + "firstName": "Serrano", + "lastName": "Park", + "company": "Hopeli", + "employed": true + }, + { + "firstName": "Clark", + "lastName": "Mcfadden", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Lauri", + "lastName": "Avila", + "company": "Musix", + "employed": true + }, + { + "firstName": "Cochran", + "lastName": "Trujillo", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Cheri", + "lastName": "Monroe", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Zimmerman", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Ross", + "lastName": "Larson", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Alvarez", + "lastName": "Stafford", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Russell", + "lastName": "Cline", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Nina", + "lastName": "Barnes", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Crane", + "lastName": "Rasmussen", + "company": "Acium", + "employed": true + }, + { + "firstName": "Brooks", + "lastName": "Tucker", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Jensen", + "lastName": "Hensley", + "company": "Flum", + "employed": false + }, + { + "firstName": "Faith", + "lastName": "Carter", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Heather", + "lastName": "Conrad", + "company": "Norali", + "employed": true + }, + { + "firstName": "Janis", + "lastName": "Cote", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Naomi", + "lastName": "Malone", + "company": "Quintity", + "employed": true + }, + { + "firstName": "Alice", + "lastName": "Melton", + "company": "Izzby", + "employed": true + }, + { + "firstName": "Mable", + "lastName": "Perez", + "company": "Elita", + "employed": false + }, + { + "firstName": "Burnett", + "lastName": "Santana", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Merrill", + "lastName": "Burks", + "company": "Entality", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "England", + "company": "Isologia", + "employed": false + }, + { + "firstName": "Wilson", + "lastName": "Haney", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Ramos", + "lastName": "Chambers", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Shelby", + "lastName": "Diaz", + "company": "Organica", + "employed": false + }, + { + "firstName": "Stout", + "lastName": "Copeland", + "company": "Earthmark", + "employed": false + }, + { + "firstName": "Frazier", + "lastName": "Alford", + "company": "Typhonica", + "employed": false + }, + { + "firstName": "Knowles", + "lastName": "Humphrey", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Gabriela", + "lastName": "Mack", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Valdez", + "lastName": "Gomez", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Dolly", + "lastName": "Buckley", + "company": "Brainclip", + "employed": true + }, + { + "firstName": "Charles", + "lastName": "Scott", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "Rita", + "lastName": "Grant", + "company": "Moreganic", + "employed": true + }, + { + "firstName": "Evangelina", + "lastName": "Mcintosh", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Kaye", + "lastName": "Pittman", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Everett", + "lastName": "Peterson", + "company": "Squish", + "employed": true + }, + { + "firstName": "Colon", + "lastName": "Morgan", + "company": "Velity", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Dunn", + "company": "Eclipto", + "employed": false + }, + { + "firstName": "Reyna", + "lastName": "Simpson", + "company": "Knowlysis", + "employed": false + }, + { + "firstName": "Josefa", + "lastName": "Hodge", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Carroll", + "lastName": "Clark", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Nunez", + "lastName": "Koch", + "company": "Aquoavo", + "employed": false + }, + { + "firstName": "Fannie", + "lastName": "Noel", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Salazar", + "lastName": "Petersen", + "company": "Translink", + "employed": false + }, + { + "firstName": "Cindy", + "lastName": "Wyatt", + "company": "Exospace", + "employed": true + }, + { + "firstName": "Austin", + "lastName": "Le", + "company": "Nitracyr", + "employed": true + }, + { + "firstName": "Frances", + "lastName": "Dickson", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Wagner", + "lastName": "Velazquez", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Antoinette", + "lastName": "Hendricks", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Shelly", + "lastName": "Mullins", + "company": "Firewax", + "employed": true + }, + { + "firstName": "Stephanie", + "lastName": "Palmer", + "company": "Extro", + "employed": true + }, + { + "firstName": "Penelope", + "lastName": "Mccormick", + "company": "Krag", + "employed": true + }, + { + "firstName": "Helga", + "lastName": "Cantrell", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Kent", + "lastName": "Joseph", + "company": "Sportan", + "employed": false + }, + { + "firstName": "Janis", + "lastName": "Dillard", + "company": "Primordia", + "employed": false + }, + { + "firstName": "Barr", + "lastName": "Fulton", + "company": "Securia", + "employed": true + }, + { + "firstName": "Leah", + "lastName": "Gregory", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Connie", + "lastName": "Chavez", + "company": "Hydrocom", + "employed": true + }, + { + "firstName": "Megan", + "lastName": "Dyer", + "company": "Magnafone", + "employed": false + }, + { + "firstName": "Charity", + "lastName": "Klein", + "company": "Comdom", + "employed": false + }, + { + "firstName": "Mcpherson", + "lastName": "Martin", + "company": "Eyeris", + "employed": false + }, + { + "firstName": "Shields", + "lastName": "Owen", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Cox", + "lastName": "Hartman", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Brigitte", + "lastName": "Hatfield", + "company": "Pyramax", + "employed": false + }, + { + "firstName": "Alvarado", + "lastName": "Wynn", + "company": "Fossiel", + "employed": false + }, + { + "firstName": "Suarez", + "lastName": "Heath", + "company": "Extragene", + "employed": true + }, + { + "firstName": "Rosemary", + "lastName": "Joyce", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Fay", + "lastName": "Quinn", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Eileen", + "lastName": "Maldonado", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Blanchard", + "lastName": "Mueller", + "company": "Centree", + "employed": true + }, + { + "firstName": "Herrera", + "lastName": "Gardner", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Ashley", + "lastName": "Mosley", + "company": "Honotron", + "employed": false + }, + { + "firstName": "Foley", + "lastName": "Scott", + "company": "Lumbrex", + "employed": true + }, + { + "firstName": "Robinson", + "lastName": "Medina", + "company": "Gonkle", + "employed": true + }, + { + "firstName": "Hannah", + "lastName": "Hunt", + "company": "Playce", + "employed": true + }, + { + "firstName": "Harris", + "lastName": "Pacheco", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Dunn", + "lastName": "Evans", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Fisher", + "lastName": "Pruitt", + "company": "Autograte", + "employed": false + }, + { + "firstName": "Rush", + "lastName": "Gutierrez", + "company": "Zedalis", + "employed": true + }, + { + "firstName": "Socorro", + "lastName": "Travis", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Allyson", + "lastName": "Stevenson", + "company": "Kiosk", + "employed": false + }, + { + "firstName": "Rachel", + "lastName": "Mcclure", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Fry", + "lastName": "Foley", + "company": "Prowaste", + "employed": true + }, + { + "firstName": "Elvira", + "lastName": "Myers", + "company": "Frolix", + "employed": true + }, + { + "firstName": "Dillon", + "lastName": "Dudley", + "company": "Turnling", + "employed": false + }, + { + "firstName": "Pruitt", + "lastName": "Clemons", + "company": "Accufarm", + "employed": false + }, + { + "firstName": "Mcdonald", + "lastName": "Bates", + "company": "Matrixity", + "employed": true + }, + { + "firstName": "Mcguire", + "lastName": "Burke", + "company": "Kage", + "employed": false + }, + { + "firstName": "Tommie", + "lastName": "Brewer", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Cardenas", + "lastName": "Mcconnell", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Chan", + "lastName": "Hebert", + "company": "Comtours", + "employed": true + }, + { + "firstName": "Peters", + "lastName": "Bray", + "company": "Nurplex", + "employed": true + }, + { + "firstName": "Campos", + "lastName": "Collier", + "company": "Pearlessa", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Black", + "company": "Earthmark", + "employed": false + }, + { + "firstName": "Mcgee", + "lastName": "Cline", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Flossie", + "lastName": "Cervantes", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Pitts", + "lastName": "French", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Cameron", + "lastName": "Short", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Ginger", + "lastName": "Copeland", + "company": "Fleetmix", + "employed": false + }, + { + "firstName": "Sallie", + "lastName": "Weiss", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Marjorie", + "lastName": "Peters", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Dawn", + "lastName": "Tanner", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Mcdaniel", + "lastName": "Chan", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Deloris", + "lastName": "Cotton", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Hardy", + "lastName": "Hurst", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Chandler", + "lastName": "Pace", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Jamie", + "lastName": "Harrison", + "company": "Boink", + "employed": true + }, + { + "firstName": "Chelsea", + "lastName": "Fletcher", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Mcdaniel", + "company": "Lunchpod", + "employed": false + }, + { + "firstName": "Bettye", + "lastName": "Price", + "company": "Verbus", + "employed": false + }, + { + "firstName": "Brady", + "lastName": "Bolton", + "company": "Terrago", + "employed": false + }, + { + "firstName": "Buck", + "lastName": "Britt", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Nguyen", + "lastName": "Jenkins", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Janie", + "lastName": "Bradley", + "company": "Columella", + "employed": true + }, + { + "firstName": "Darlene", + "lastName": "Cunningham", + "company": "Portico", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Finley", + "company": "Frosnex", + "employed": false + }, + { + "firstName": "Byers", + "lastName": "Marquez", + "company": "Goko", + "employed": false + }, + { + "firstName": "Thornton", + "lastName": "Gallagher", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Ella", + "lastName": "Austin", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Alexander", + "lastName": "Becker", + "company": "Locazone", + "employed": false + }, + { + "firstName": "Whitley", + "lastName": "Gamble", + "company": "Repetwire", + "employed": false + }, + { + "firstName": "Stokes", + "lastName": "Walters", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Russell", + "lastName": "Fitzgerald", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Lula", + "lastName": "Savage", + "company": "Austech", + "employed": true + }, + { + "firstName": "Katy", + "lastName": "Lawson", + "company": "Zoinage", + "employed": false + }, + { + "firstName": "Rebekah", + "lastName": "Calderon", + "company": "Comtract", + "employed": false + }, + { + "firstName": "Myrna", + "lastName": "Macias", + "company": "Idealis", + "employed": false + }, + { + "firstName": "Barker", + "lastName": "Boyd", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Jeanne", + "lastName": "Good", + "company": "Undertap", + "employed": false + }, + { + "firstName": "Raymond", + "lastName": "Mccarthy", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Pace", + "lastName": "Warner", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Leticia", + "lastName": "Vargas", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Andrews", + "lastName": "Herrera", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Holloway", + "lastName": "Jarvis", + "company": "Glukgluk", + "employed": false + }, + { + "firstName": "Latoya", + "lastName": "Lawrence", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Bennett", + "lastName": "Marks", + "company": "Digigene", + "employed": true + }, + { + "firstName": "Donna", + "lastName": "Bailey", + "company": "Kongle", + "employed": false + }, + { + "firstName": "Mona", + "lastName": "Gilmore", + "company": "Hivedom", + "employed": false + }, + { + "firstName": "Kasey", + "lastName": "Adkins", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Melinda", + "lastName": "Richardson", + "company": "Bytrex", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Sexton", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Potter", + "lastName": "Jacobson", + "company": "Anarco", + "employed": true + }, + { + "firstName": "Wilda", + "lastName": "Reyes", + "company": "Panzent", + "employed": true + }, + { + "firstName": "Booker", + "lastName": "Davidson", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Maggie", + "lastName": "Dunlap", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Odessa", + "lastName": "Brock", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Lamb", + "lastName": "Torres", + "company": "Mediot", + "employed": false + }, + { + "firstName": "Lynda", + "lastName": "Mendoza", + "company": "Comvey", + "employed": false + }, + { + "firstName": "Collier", + "lastName": "Leblanc", + "company": "Applidec", + "employed": true + }, + { + "firstName": "Leta", + "lastName": "Rice", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Annie", + "lastName": "Talley", + "company": "Cablam", + "employed": false + }, + { + "firstName": "Deborah", + "lastName": "Tillman", + "company": "Isologics", + "employed": false + }, + { + "firstName": "Medina", + "lastName": "Acosta", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Aileen", + "lastName": "Sanford", + "company": "Memora", + "employed": false + }, + { + "firstName": "Maude", + "lastName": "Franklin", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Arnold", + "lastName": "Foster", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Duffy", + "lastName": "Valentine", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Jerry", + "lastName": "Ratliff", + "company": "Isotronic", + "employed": true + }, + { + "firstName": "Beach", + "lastName": "Romero", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Brandie", + "lastName": "Sheppard", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Willa", + "lastName": "Hampton", + "company": "Kindaloo", + "employed": true + }, + { + "firstName": "Cantu", + "lastName": "Glover", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Roy", + "lastName": "Franks", + "company": "Zaya", + "employed": false + }, + { + "firstName": "Rivera", + "lastName": "Harding", + "company": "Straloy", + "employed": false + }, + { + "firstName": "Darcy", + "lastName": "Soto", + "company": "Zipak", + "employed": false + }, + { + "firstName": "Lara", + "lastName": "Rivera", + "company": "Speedbolt", + "employed": true + }, + { + "firstName": "Wilma", + "lastName": "Miranda", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Jenny", + "lastName": "Booker", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Paulette", + "lastName": "Burnett", + "company": "Songlines", + "employed": true + }, + { + "firstName": "Kitty", + "lastName": "Compton", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Strong", + "lastName": "Cross", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "Gould", + "company": "Danja", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Deleon", + "company": "Polaria", + "employed": false + }, + { + "firstName": "Eunice", + "lastName": "Preston", + "company": "Accel", + "employed": true + }, + { + "firstName": "Michael", + "lastName": "Finch", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Stephenson", + "lastName": "Ortega", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Claudette", + "lastName": "Cardenas", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Randall", + "lastName": "Small", + "company": "Prismatic", + "employed": false + }, + { + "firstName": "Warner", + "lastName": "Stout", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Estrada", + "lastName": "Figueroa", + "company": "Unia", + "employed": false + }, + { + "firstName": "Kris", + "lastName": "Patrick", + "company": "Chorizon", + "employed": true + }, + { + "firstName": "Katheryn", + "lastName": "Morrow", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Carpenter", + "lastName": "Gonzales", + "company": "Tasmania", + "employed": false + }, + { + "firstName": "Ilene", + "lastName": "Beach", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Donaldson", + "lastName": "Casey", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Lora", + "lastName": "Mcdowell", + "company": "Volax", + "employed": true + }, + { + "firstName": "Carney", + "lastName": "Vinson", + "company": "Sultrax", + "employed": false + }, + { + "firstName": "Chang", + "lastName": "Sanders", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Darla", + "lastName": "Rosario", + "company": "Xoggle", + "employed": false + }, + { + "firstName": "Schwartz", + "lastName": "Nieves", + "company": "Biospan", + "employed": true + }, + { + "firstName": "Kaye", + "lastName": "Mccoy", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Flores", + "company": "Halap", + "employed": false + }, + { + "firstName": "Santiago", + "lastName": "Chaney", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Lynette", + "lastName": "Jefferson", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Dollie", + "lastName": "Suarez", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Janell", + "lastName": "Sullivan", + "company": "Genesynk", + "employed": true + }, + { + "firstName": "Guerra", + "lastName": "Winters", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Elizabeth", + "lastName": "Conrad", + "company": "Bostonic", + "employed": true + }, + { + "firstName": "Norton", + "lastName": "Leach", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Callie", + "lastName": "Hood", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Wright", + "lastName": "Craig", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Lorrie", + "lastName": "Andrews", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Nelda", + "lastName": "Jackson", + "company": "Enersol", + "employed": false + }, + { + "firstName": "Walker", + "lastName": "Monroe", + "company": "Austex", + "employed": true + }, + { + "firstName": "Ebony", + "lastName": "Mclaughlin", + "company": "Exerta", + "employed": false + }, + { + "firstName": "Joni", + "lastName": "Mcgowan", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Richmond", + "lastName": "Mathews", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Katharine", + "lastName": "Key", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Grimes", + "company": "Elemantra", + "employed": false + }, + { + "firstName": "Benton", + "lastName": "Church", + "company": "Insource", + "employed": false + }, + { + "firstName": "Jody", + "lastName": "Moses", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Alberta", + "lastName": "Farrell", + "company": "Qot", + "employed": true + }, + { + "firstName": "Chrystal", + "lastName": "Fleming", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Eva", + "lastName": "Walker", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Kimberly", + "lastName": "Bean", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Weaver", + "lastName": "Atkins", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Short", + "lastName": "Dotson", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Alana", + "lastName": "Hale", + "company": "Mondicil", + "employed": true + }, + { + "firstName": "Jodi", + "lastName": "Washington", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Petty", + "lastName": "Saunders", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Holman", + "lastName": "Watts", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Dominique", + "lastName": "Decker", + "company": "Plasmox", + "employed": false + }, + { + "firstName": "Mayer", + "lastName": "Beard", + "company": "Zaggles", + "employed": false + }, + { + "firstName": "Reid", + "lastName": "Nixon", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Castillo", + "lastName": "Dalton", + "company": "Comfirm", + "employed": true + }, + { + "firstName": "Rosella", + "lastName": "Baker", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Paige", + "lastName": "Gomez", + "company": "Navir", + "employed": true + }, + { + "firstName": "Rosemarie", + "lastName": "Holman", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Hattie", + "lastName": "Fields", + "company": "Kyaguru", + "employed": false + }, + { + "firstName": "Rosanna", + "lastName": "Horne", + "company": "Netbook", + "employed": false + }, + { + "firstName": "Mitchell", + "lastName": "Crosby", + "company": "Quinex", + "employed": false + }, + { + "firstName": "Helene", + "lastName": "Berg", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Roseann", + "lastName": "Head", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Holmes", + "lastName": "Jacobs", + "company": "Magnemo", + "employed": true + }, + { + "firstName": "Roberson", + "lastName": "Sutton", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Luann", + "lastName": "Terrell", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Peterson", + "lastName": "Estrada", + "company": "Crustatia", + "employed": true + }, + { + "firstName": "Edith", + "lastName": "Fitzpatrick", + "company": "Dognosis", + "employed": true + }, + { + "firstName": "Glass", + "lastName": "Thornton", + "company": "Koogle", + "employed": true + }, + { + "firstName": "Margaret", + "lastName": "Wall", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Castro", + "lastName": "Hines", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Bethany", + "lastName": "Rosa", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Sharron", + "lastName": "Diaz", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Lancaster", + "lastName": "Harrington", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Anthony", + "lastName": "Riley", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Joanna", + "lastName": "Noble", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Therese", + "lastName": "Trujillo", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Deirdre", + "lastName": "Lowery", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Bender", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Doreen", + "lastName": "Kline", + "company": "Geeknet", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Simon", + "company": "Amtas", + "employed": false + }, + { + "firstName": "Stacy", + "lastName": "Haley", + "company": "Fuelworks", + "employed": false + }, + { + "firstName": "York", + "lastName": "Glass", + "company": "Comstar", + "employed": false + }, + { + "firstName": "Robbie", + "lastName": "Shaffer", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Phelps", + "lastName": "Newton", + "company": "Biflex", + "employed": true + }, + { + "firstName": "Velasquez", + "lastName": "Robinson", + "company": "Naxdis", + "employed": false + }, + { + "firstName": "Jill", + "lastName": "Hopkins", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Corina", + "lastName": "Wilcox", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Hernandez", + "lastName": "Hayden", + "company": "Zuvy", + "employed": true + }, + { + "firstName": "Rhea", + "lastName": "Farmer", + "company": "Temorak", + "employed": false + }, + { + "firstName": "Janna", + "lastName": "Walter", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Robyn", + "lastName": "Curtis", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Traci", + "lastName": "Ferrell", + "company": "Cubicide", + "employed": false + }, + { + "firstName": "Lindsey", + "lastName": "English", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Gracie", + "lastName": "Duncan", + "company": "Comtest", + "employed": true + }, + { + "firstName": "Sharon", + "lastName": "Solomon", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Jeannine", + "lastName": "Cannon", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Mollie", + "lastName": "Glenn", + "company": "Emtrac", + "employed": true + }, + { + "firstName": "Ana", + "lastName": "Blankenship", + "company": "Nimon", + "employed": true + }, + { + "firstName": "Cathy", + "lastName": "Santos", + "company": "Digifad", + "employed": false + }, + { + "firstName": "Mills", + "lastName": "Morris", + "company": "Supremia", + "employed": false + }, + { + "firstName": "Faye", + "lastName": "Camacho", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Munoz", + "lastName": "Hyde", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Cooper", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Juliette", + "lastName": "Schwartz", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Christian", + "lastName": "Salinas", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Marcia", + "lastName": "Patterson", + "company": "Euron", + "employed": true + }, + { + "firstName": "Angelica", + "lastName": "Haynes", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Lauren", + "lastName": "Berry", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Elisa", + "lastName": "Harvey", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Underwood", + "company": "Injoy", + "employed": false + }, + { + "firstName": "Rojas", + "lastName": "Burris", + "company": "Techade", + "employed": false + }, + { + "firstName": "Rena", + "lastName": "Lopez", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Lilia", + "lastName": "Sharpe", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Santana", + "lastName": "Moody", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Marissa", + "lastName": "Wade", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Mallory", + "lastName": "Bradshaw", + "company": "Minga", + "employed": false + }, + { + "firstName": "Lopez", + "lastName": "Parsons", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Hanson", + "company": "Cipromox", + "employed": true + }, + { + "firstName": "Pearl", + "lastName": "Bass", + "company": "Colaire", + "employed": false + }, + { + "firstName": "Cheryl", + "lastName": "Farley", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Bates", + "lastName": "Nguyen", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Johnston", + "lastName": "Pitts", + "company": "Animalia", + "employed": true + }, + { + "firstName": "Monroe", + "lastName": "Summers", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Burks", + "lastName": "Hancock", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Deleon", + "lastName": "Haney", + "company": "Unq", + "employed": true + }, + { + "firstName": "Clark", + "lastName": "Maddox", + "company": "Avit", + "employed": false + }, + { + "firstName": "Kristine", + "lastName": "May", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Michelle", + "lastName": "Hughes", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Sharp", + "lastName": "Wright", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Cunningham", + "lastName": "Whitehead", + "company": "Geekol", + "employed": false + }, + { + "firstName": "Salinas", + "lastName": "Kirkland", + "company": "Optique", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Taylor", + "company": "Cosmetex", + "employed": true + }, + { + "firstName": "Katelyn", + "lastName": "Curry", + "company": "Enomen", + "employed": true + }, + { + "firstName": "Hilda", + "lastName": "Ross", + "company": "Otherway", + "employed": false + }, + { + "firstName": "Iva", + "lastName": "Lloyd", + "company": "Quilch", + "employed": false + }, + { + "firstName": "Holly", + "lastName": "Battle", + "company": "Harmoney", + "employed": false + }, + { + "firstName": "Valarie", + "lastName": "Graham", + "company": "Cujo", + "employed": true + }, + { + "firstName": "Celia", + "lastName": "Cole", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Marva", + "lastName": "Kirby", + "company": "Entroflex", + "employed": false + }, + { + "firstName": "Hood", + "lastName": "Richards", + "company": "Comveyor", + "employed": false + }, + { + "firstName": "Langley", + "lastName": "Davis", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Patti", + "lastName": "Russell", + "company": "Zilodyne", + "employed": true + }, + { + "firstName": "Keri", + "lastName": "Bird", + "company": "Entropix", + "employed": false + }, + { + "firstName": "Blanche", + "lastName": "Wiley", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Horne", + "lastName": "Huffman", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Myrtle", + "lastName": "Sargent", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Barron", + "lastName": "James", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Roxanne", + "lastName": "Howell", + "company": "Petigems", + "employed": false + }, + { + "firstName": "Florine", + "lastName": "Cortez", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Celeste", + "lastName": "Flynn", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Case", + "lastName": "Mccullough", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Noelle", + "lastName": "Christensen", + "company": "Aquafire", + "employed": false + }, + { + "firstName": "Madeline", + "lastName": "Brown", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Dean", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Angeline", + "lastName": "Anthony", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Edwina", + "lastName": "Shepard", + "company": "Beadzza", + "employed": false + }, + { + "firstName": "Ayers", + "lastName": "Holloway", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Ava", + "lastName": "Fuentes", + "company": "Emoltra", + "employed": false + }, + { + "firstName": "Maribel", + "lastName": "Clayton", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Jacqueline", + "lastName": "Schultz", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Jane", + "lastName": "Harrell", + "company": "Gronk", + "employed": true + }, + { + "firstName": "Randolph", + "lastName": "Morton", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Maryanne", + "lastName": "Rasmussen", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Elva", + "lastName": "Holmes", + "company": "Marqet", + "employed": false + }, + { + "firstName": "Matthews", + "lastName": "Merrill", + "company": "Motovate", + "employed": true + }, + { + "firstName": "Small", + "lastName": "Weaver", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Jennie", + "lastName": "Oliver", + "company": "Snips", + "employed": true + }, + { + "firstName": "Geneva", + "lastName": "Mclean", + "company": "Senmei", + "employed": false + }, + { + "firstName": "Susan", + "lastName": "Eaton", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Lori", + "lastName": "Hendrix", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Denise", + "lastName": "Gibbs", + "company": "Zerbina", + "employed": false + }, + { + "firstName": "Leona", + "lastName": "Riddle", + "company": "Gynko", + "employed": true + }, + { + "firstName": "Beatrice", + "lastName": "Crawford", + "company": "Quility", + "employed": false + }, + { + "firstName": "Sharlene", + "lastName": "Santiago", + "company": "Futuris", + "employed": true + }, + { + "firstName": "Dolly", + "lastName": "Ferguson", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Sheppard", + "lastName": "Ward", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Battle", + "lastName": "Buckley", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Guy", + "lastName": "Holden", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Cox", + "company": "Roughies", + "employed": false + }, + { + "firstName": "Sheena", + "lastName": "Yang", + "company": "Recritube", + "employed": false + }, + { + "firstName": "Acevedo", + "lastName": "Randall", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Knapp", + "lastName": "Booth", + "company": "Acumentor", + "employed": true + }, + { + "firstName": "Phyllis", + "lastName": "Anderson", + "company": "Wrapture", + "employed": false + }, + { + "firstName": "Everett", + "lastName": "Lindsey", + "company": "Chillium", + "employed": true + }, + { + "firstName": "Whitaker", + "lastName": "Baxter", + "company": "Applica", + "employed": false + }, + { + "firstName": "Sanford", + "lastName": "Dickerson", + "company": "Futurize", + "employed": true + }, + { + "firstName": "Simpson", + "lastName": "Hutchinson", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Kristen", + "lastName": "Dorsey", + "company": "Quizmo", + "employed": false + }, + { + "firstName": "Wilkins", + "lastName": "Snow", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Washington", + "lastName": "Navarro", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Aida", + "lastName": "Mullen", + "company": "Genmy", + "employed": true + }, + { + "firstName": "Shepard", + "lastName": "Higgins", + "company": "Talae", + "employed": true + }, + { + "firstName": "Burns", + "lastName": "Melendez", + "company": "Quizka", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Sloan", + "company": "Scenty", + "employed": true + }, + { + "firstName": "Duke", + "lastName": "Stephenson", + "company": "Netility", + "employed": true + }, + { + "firstName": "Rodriquez", + "lastName": "Baird", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Sanchez", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Katie", + "lastName": "Guerrero", + "company": "Koffee", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Mcguire", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Kirk", + "lastName": "Franco", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Lena", + "lastName": "Prince", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Harvey", + "lastName": "Conner", + "company": "Orbin", + "employed": false + }, + { + "firstName": "Deann", + "lastName": "Owens", + "company": "Multron", + "employed": true + }, + { + "firstName": "Mattie", + "lastName": "Mccray", + "company": "Candecor", + "employed": false + }, + { + "firstName": "Huff", + "lastName": "Walsh", + "company": "Sustenza", + "employed": false + }, + { + "firstName": "Laverne", + "lastName": "Cooley", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Stevenson", + "lastName": "Galloway", + "company": "Musix", + "employed": true + }, + { + "firstName": "Gena", + "lastName": "Guerra", + "company": "Zensus", + "employed": false + }, + { + "firstName": "Lucile", + "lastName": "Aguirre", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Reeves", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Lorena", + "lastName": "Mckay", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Trina", + "lastName": "Hardin", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Claudia", + "lastName": "Kerr", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Tina", + "lastName": "Michael", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Ora", + "lastName": "Willis", + "company": "Rocklogic", + "employed": true + }, + { + "firstName": "Chaney", + "lastName": "Meyer", + "company": "Soprano", + "employed": true + }, + { + "firstName": "Addie", + "lastName": "Wilkerson", + "company": "Ludak", + "employed": false + }, + { + "firstName": "Mccullough", + "lastName": "Harper", + "company": "Ecrater", + "employed": false + }, + { + "firstName": "Winifred", + "lastName": "Crane", + "company": "Surelogic", + "employed": false + }, + { + "firstName": "Sophie", + "lastName": "Welch", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Leigh", + "lastName": "Perry", + "company": "Aquacine", + "employed": true + }, + { + "firstName": "Hammond", + "lastName": "Pate", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Goodwin", + "lastName": "Cabrera", + "company": "Gink", + "employed": true + }, + { + "firstName": "Barber", + "lastName": "Sweeney", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Terry", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Inez", + "lastName": "Hill", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Harrington", + "lastName": "Vincent", + "company": "Digirang", + "employed": false + }, + { + "firstName": "Earline", + "lastName": "Knapp", + "company": "Moreganic", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Gross", + "company": "Envire", + "employed": false + }, + { + "firstName": "Kari", + "lastName": "Smith", + "company": "Isosure", + "employed": true + }, + { + "firstName": "Cornelia", + "lastName": "Ball", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Effie", + "lastName": "Simmons", + "company": "Sensate", + "employed": false + }, + { + "firstName": "Mcclure", + "lastName": "Larsen", + "company": "Amtap", + "employed": false + }, + { + "firstName": "Suzanne", + "lastName": "Witt", + "company": "Flumbo", + "employed": true + }, + { + "firstName": "Annmarie", + "lastName": "Knight", + "company": "Urbanshee", + "employed": true + }, + { + "firstName": "Higgins", + "lastName": "Skinner", + "company": "Equitax", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Delaney", + "company": "Aquazure", + "employed": false + }, + { + "firstName": "Tracey", + "lastName": "Ballard", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Susanne", + "lastName": "Garrett", + "company": "Aquasure", + "employed": true + }, + { + "firstName": "Anastasia", + "lastName": "Grant", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Bonnie", + "lastName": "Dejesus", + "company": "Pyrami", + "employed": true + }, + { + "firstName": "Dionne", + "lastName": "Campbell", + "company": "Affluex", + "employed": false + }, + { + "firstName": "Bowman", + "lastName": "Bullock", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Compton", + "lastName": "Gordon", + "company": "Quonata", + "employed": true + }, + { + "firstName": "Morrison", + "lastName": "Dale", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Hurst", + "lastName": "Buchanan", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Ward", + "lastName": "Cooke", + "company": "Dreamia", + "employed": true + }, + { + "firstName": "Rosalinda", + "lastName": "Campos", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Cantrell", + "lastName": "Obrien", + "company": "Frenex", + "employed": true + }, + { + "firstName": "Caitlin", + "lastName": "Park", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Bianca", + "lastName": "Delgado", + "company": "Exoswitch", + "employed": true + }, + { + "firstName": "Adela", + "lastName": "Hodges", + "company": "Xerex", + "employed": true + }, + { + "firstName": "Moss", + "lastName": "Shields", + "company": "Slax", + "employed": true + }, + { + "firstName": "Kerri", + "lastName": "Carney", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Floyd", + "lastName": "Barrera", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Marguerite", + "lastName": "Oneil", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Burke", + "lastName": "Woodard", + "company": "Sequitur", + "employed": false + }, + { + "firstName": "Gill", + "lastName": "Petty", + "company": "Zillan", + "employed": true + }, + { + "firstName": "Johnson", + "lastName": "Dominguez", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Latisha", + "lastName": "Henderson", + "company": "Prosely", + "employed": false + }, + { + "firstName": "Tanya", + "lastName": "Ray", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Wong", + "lastName": "Griffin", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Crystal", + "lastName": "Stark", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Davidson", + "lastName": "Reynolds", + "company": "Entogrok", + "employed": false + }, + { + "firstName": "Caldwell", + "lastName": "Mcintosh", + "company": "Boilcat", + "employed": true + }, + { + "firstName": "Milagros", + "lastName": "House", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "William", + "lastName": "Blevins", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Madelyn", + "lastName": "Castro", + "company": "Buzzmaker", + "employed": false + }, + { + "firstName": "Liza", + "lastName": "Orr", + "company": "Ovolo", + "employed": false + }, + { + "firstName": "Mendoza", + "lastName": "Harris", + "company": "Furnafix", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Goodwin", + "company": "Neocent", + "employed": true + }, + { + "firstName": "Pennington", + "lastName": "Todd", + "company": "Assistia", + "employed": true + }, + { + "firstName": "Marion", + "lastName": "Massey", + "company": "Visualix", + "employed": true + }, + { + "firstName": "Rodriguez", + "lastName": "Kelley", + "company": "Xth", + "employed": false + }, + { + "firstName": "Harriett", + "lastName": "Shepherd", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Cabrera", + "lastName": "Morrison", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Donovan", + "lastName": "Wells", + "company": "Helixo", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Blair", + "company": "Comcur", + "employed": true + }, + { + "firstName": "Caroline", + "lastName": "Tran", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Morgan", + "lastName": "Thompson", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Rosario", + "lastName": "Rowland", + "company": "Genmex", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Richard", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Harper", + "lastName": "Keller", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Hester", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Hubbard", + "lastName": "Schmidt", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Elinor", + "lastName": "Hansen", + "company": "Luxuria", + "employed": true + }, + { + "firstName": "Pratt", + "lastName": "Williams", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Stephens", + "lastName": "Mcintyre", + "company": "Bovis", + "employed": true + }, + { + "firstName": "Jimenez", + "lastName": "Hammond", + "company": "Vidto", + "employed": true + }, + { + "firstName": "Lydia", + "lastName": "Cameron", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Virginia", + "lastName": "Lyons", + "company": "Zilphur", + "employed": false + }, + { + "firstName": "Fran", + "lastName": "Young", + "company": "Centice", + "employed": false + }, + { + "firstName": "Maura", + "lastName": "Morse", + "company": "Amril", + "employed": true + }, + { + "firstName": "West", + "lastName": "Edwards", + "company": "Spherix", + "employed": true + }, + { + "firstName": "Stuart", + "lastName": "Randolph", + "company": "Signity", + "employed": false + }, + { + "firstName": "Drake", + "lastName": "Roy", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Ray", + "lastName": "Shannon", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Dawson", + "lastName": "Fry", + "company": "Besto", + "employed": false + }, + { + "firstName": "Noemi", + "lastName": "Wolfe", + "company": "Netplax", + "employed": true + }, + { + "firstName": "Bernadette", + "lastName": "Bradford", + "company": "Concility", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Donovan", + "company": "Applideck", + "employed": false + }, + { + "firstName": "Simone", + "lastName": "Blake", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Helena", + "lastName": "Long", + "company": "Zaj", + "employed": false + }, + { + "firstName": "Madeleine", + "lastName": "Tyler", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Dyer", + "lastName": "Hernandez", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Lloyd", + "lastName": "Russo", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Cobb", + "lastName": "Hart", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Avery", + "lastName": "Ayers", + "company": "Uberlux", + "employed": false + }, + { + "firstName": "Benson", + "lastName": "Dawson", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Jodie", + "lastName": "Barnes", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Vega", + "company": "Zappix", + "employed": false + }, + { + "firstName": "Carmen", + "lastName": "Rose", + "company": "Medmex", + "employed": false + }, + { + "firstName": "Mclaughlin", + "lastName": "Burt", + "company": "Vantage", + "employed": true + }, + { + "firstName": "Christy", + "lastName": "Flowers", + "company": "Deepends", + "employed": true + }, + { + "firstName": "Maynard", + "lastName": "Perez", + "company": "Nikuda", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Mejia", + "company": "Vurbo", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Phelps", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Montgomery", + "lastName": "Everett", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Mckenzie", + "lastName": "Lester", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Tyson", + "lastName": "Logan", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Rutledge", + "lastName": "Garza", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Cassie", + "lastName": "Conway", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Angelita", + "lastName": "Salazar", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Tabitha", + "lastName": "Doyle", + "company": "Assistix", + "employed": false + }, + { + "firstName": "Valdez", + "lastName": "Mason", + "company": "Opticon", + "employed": true + }, + { + "firstName": "Marisa", + "lastName": "Morin", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Britney", + "lastName": "Sawyer", + "company": "Geekola", + "employed": true + }, + { + "firstName": "Noreen", + "lastName": "Sykes", + "company": "Gallaxia", + "employed": true + }, + { + "firstName": "Courtney", + "lastName": "Nichols", + "company": "Micronaut", + "employed": true + }, + { + "firstName": "Hopkins", + "lastName": "Gillespie", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Dorothea", + "lastName": "Hewitt", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Sweet", + "lastName": "Bowen", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Audrey", + "lastName": "Wood", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Burns", + "company": "Exoplode", + "employed": false + }, + { + "firstName": "Carson", + "lastName": "Burch", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Cochran", + "lastName": "Munoz", + "company": "Veraq", + "employed": false + }, + { + "firstName": "Hoover", + "lastName": "Hoover", + "company": "Orbalix", + "employed": true + }, + { + "firstName": "Marisol", + "lastName": "Collins", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Deanna", + "lastName": "Brennan", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Brennan", + "lastName": "Ayala", + "company": "Zentury", + "employed": true + }, + { + "firstName": "Tia", + "lastName": "Sosa", + "company": "Tubalum", + "employed": true + }, + { + "firstName": "Roach", + "lastName": "Albert", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "White", + "lastName": "Riggs", + "company": "Circum", + "employed": true + }, + { + "firstName": "Baird", + "lastName": "Gray", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Norman", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Christine", + "lastName": "Johnson", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Garner", + "lastName": "Little", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Chris", + "lastName": "Stone", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Chasity", + "lastName": "Reed", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Valencia", + "lastName": "Horton", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Carolina", + "lastName": "Lynch", + "company": "Earthplex", + "employed": false + }, + { + "firstName": "Loretta", + "lastName": "Fernandez", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Abigail", + "lastName": "Duffy", + "company": "Idego", + "employed": false + }, + { + "firstName": "Moreno", + "lastName": "Snyder", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Nina", + "lastName": "Bryan", + "company": "Telpod", + "employed": true + }, + { + "firstName": "Delores", + "lastName": "Hunter", + "company": "Snacktion", + "employed": false + }, + { + "firstName": "Nelson", + "lastName": "Daniels", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Kathy", + "lastName": "Hubbard", + "company": "Geekko", + "employed": true + }, + { + "firstName": "Mcmillan", + "lastName": "Duke", + "company": "Comverges", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Francis", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Ethel", + "lastName": "Golden", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Beverly", + "lastName": "Waller", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Meyers", + "lastName": "Powers", + "company": "Sulfax", + "employed": false + }, + { + "firstName": "Ofelia", + "lastName": "Bond", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Kennedy", + "company": "Uplinx", + "employed": false + }, + { + "firstName": "Maxwell", + "lastName": "Barton", + "company": "Eventex", + "employed": false + }, + { + "firstName": "Farrell", + "lastName": "Mcgee", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Gaines", + "lastName": "Puckett", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Mcknight", + "lastName": "Abbott", + "company": "Quadeebo", + "employed": false + }, + { + "firstName": "Sutton", + "lastName": "Lang", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Bush", + "lastName": "Whitaker", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Edna", + "lastName": "Potts", + "company": "Katakana", + "employed": false + }, + { + "firstName": "Richards", + "lastName": "Contreras", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Garrison", + "lastName": "Charles", + "company": "Inear", + "employed": false + }, + { + "firstName": "Flynn", + "lastName": "Moon", + "company": "Cemention", + "employed": false + }, + { + "firstName": "Harrison", + "lastName": "Emerson", + "company": "Magnina", + "employed": false + }, + { + "firstName": "Sheila", + "lastName": "Gibson", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Mckinney", + "lastName": "Bauer", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Jeri", + "lastName": "Fuller", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Colette", + "lastName": "Zamora", + "company": "Caxt", + "employed": false + }, + { + "firstName": "Mcfadden", + "lastName": "Callahan", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Bonita", + "lastName": "Kramer", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Hampton", + "lastName": "Porter", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Weiss", + "lastName": "Kelly", + "company": "Fishland", + "employed": false + }, + { + "firstName": "Sandoval", + "lastName": "Guthrie", + "company": "Corporana", + "employed": true + }, + { + "firstName": "Marsh", + "lastName": "Parrish", + "company": "Acusage", + "employed": false + }, + { + "firstName": "Bray", + "lastName": "King", + "company": "Thredz", + "employed": false + }, + { + "firstName": "Kathryn", + "lastName": "Webb", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Madge", + "lastName": "Donaldson", + "company": "Opticall", + "employed": false + }, + { + "firstName": "Myers", + "lastName": "Cantu", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Alston", + "company": "Updat", + "employed": false + }, + { + "firstName": "Velazquez", + "lastName": "Nash", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Ruby", + "lastName": "Kemp", + "company": "Dyno", + "employed": true + }, + { + "firstName": "Carlene", + "lastName": "Watkins", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Schmidt", + "lastName": "Woods", + "company": "Comstruct", + "employed": true + }, + { + "firstName": "Karina", + "lastName": "Whitley", + "company": "Endicil", + "employed": true + }, + { + "firstName": "Sherrie", + "lastName": "Jones", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Lucia", + "lastName": "Page", + "company": "Steelfab", + "employed": true + }, + { + "firstName": "Shelton", + "lastName": "Neal", + "company": "Incubus", + "employed": false + }, + { + "firstName": "Guadalupe", + "lastName": "Whitfield", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Atkins", + "lastName": "Green", + "company": "Namebox", + "employed": true + }, + { + "firstName": "Colleen", + "lastName": "Lane", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Guzman", + "lastName": "Mays", + "company": "Rameon", + "employed": true + }, + { + "firstName": "Adriana", + "lastName": "Howard", + "company": "Zillanet", + "employed": true + }, + { + "firstName": "Wells", + "lastName": "Herring", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Dean", + "lastName": "Stanley", + "company": "Grok", + "employed": false + }, + { + "firstName": "Oliver", + "lastName": "Zimmerman", + "company": "Bedder", + "employed": true + }, + { + "firstName": "Howe", + "lastName": "Ware", + "company": "Confrenzy", + "employed": false + }, + { + "firstName": "Rollins", + "lastName": "Knowles", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Ila", + "lastName": "Gill", + "company": "Fibrodyne", + "employed": false + }, + { + "firstName": "Gwen", + "lastName": "Garcia", + "company": "Norsup", + "employed": true + }, + { + "firstName": "Gina", + "lastName": "Browning", + "company": "Zboo", + "employed": true + }, + { + "firstName": "Nell", + "lastName": "Fischer", + "company": "Retrack", + "employed": true + }, + { + "firstName": "Berta", + "lastName": "Love", + "company": "Blurrybus", + "employed": false + }, + { + "firstName": "Katherine", + "lastName": "Carver", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Kinney", + "lastName": "Turner", + "company": "Mangelica", + "employed": false + }, + { + "firstName": "Cleveland", + "lastName": "Woodward", + "company": "Visalia", + "employed": false + }, + { + "firstName": "Shanna", + "lastName": "Henry", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Riddle", + "lastName": "Graves", + "company": "Genekom", + "employed": false + }, + { + "firstName": "Aisha", + "lastName": "Bell", + "company": "Eyewax", + "employed": true + }, + { + "firstName": "Minnie", + "lastName": "Beck", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Blackwell", + "lastName": "Rosales", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Mildred", + "lastName": "Reese", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "Melendez", + "lastName": "Duran", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Angelina", + "lastName": "Cain", + "company": "Orbaxter", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Mccarty", + "company": "Xyqag", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Wilkins", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Evelyn", + "lastName": "Bowers", + "company": "Geologix", + "employed": true + }, + { + "firstName": "Franks", + "lastName": "Gonzalez", + "company": "Xinware", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Maynard", + "company": "Flexigen", + "employed": true + }, + { + "firstName": "Janette", + "lastName": "Warren", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Diaz", + "lastName": "Hoffman", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Marina", + "lastName": "Oconnor", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Malinda", + "lastName": "Mcfarland", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Gonzalez", + "lastName": "Nicholson", + "company": "Homelux", + "employed": true + }, + { + "firstName": "Dominguez", + "lastName": "Payne", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Victoria", + "lastName": "Bush", + "company": "Zytrek", + "employed": true + }, + { + "firstName": "Mcmahon", + "lastName": "Whitney", + "company": "Isologica", + "employed": true + }, + { + "firstName": "Powers", + "lastName": "Humphrey", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Phillips", + "company": "Extremo", + "employed": true + }, + { + "firstName": "Elisabeth", + "lastName": "Buckner", + "company": "Combot", + "employed": false + }, + { + "firstName": "Linda", + "lastName": "Alvarado", + "company": "Interfind", + "employed": false + }, + { + "firstName": "Grace", + "lastName": "White", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Lauri", + "lastName": "Sims", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Wendy", + "lastName": "Boyer", + "company": "Kneedles", + "employed": false + }, + { + "firstName": "Jacquelyn", + "lastName": "Wise", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Renee", + "lastName": "Chase", + "company": "Earthwax", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Gates", + "company": "Iplax", + "employed": true + }, + { + "firstName": "Robert", + "lastName": "Morales", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Noble", + "lastName": "Hays", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "Hendrix", + "lastName": "Shelton", + "company": "Mantrix", + "employed": true + }, + { + "firstName": "Leonard", + "lastName": "Cleveland", + "company": "Qualitex", + "employed": true + }, + { + "firstName": "Shawn", + "lastName": "Ramirez", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Jacobson", + "lastName": "Hurley", + "company": "Bisba", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Durham", + "company": "Waab", + "employed": true + }, + { + "firstName": "Wynn", + "lastName": "Dixon", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Mckay", + "lastName": "Alford", + "company": "Liquicom", + "employed": false + }, + { + "firstName": "Bean", + "lastName": "Stein", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Irene", + "lastName": "Rojas", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Perkins", + "lastName": "Ruiz", + "company": "Pasturia", + "employed": true + }, + { + "firstName": "Turner", + "lastName": "Ashley", + "company": "Oceanica", + "employed": true + }, + { + "firstName": "Sanders", + "lastName": "Gay", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Ruthie", + "lastName": "Horn", + "company": "Zenco", + "employed": true + }, + { + "firstName": "Blake", + "lastName": "Bennett", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Spencer", + "lastName": "Castaneda", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Berry", + "lastName": "Luna", + "company": "Vetron", + "employed": true + }, + { + "firstName": "Knowles", + "lastName": "Richmond", + "company": "Keeg", + "employed": true + }, + { + "firstName": "Rachael", + "lastName": "Huber", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Mccarthy", + "lastName": "Henson", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Dixon", + "lastName": "Holt", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Cathryn", + "lastName": "Nolan", + "company": "Strozen", + "employed": false + }, + { + "firstName": "Dorothy", + "lastName": "Madden", + "company": "Futurity", + "employed": true + }, + { + "firstName": "Vaughan", + "lastName": "Sherman", + "company": "Codact", + "employed": false + }, + { + "firstName": "Rosa", + "lastName": "Kidd", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Lawrence", + "lastName": "Allison", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Violet", + "lastName": "Combs", + "company": "Pholio", + "employed": false + }, + { + "firstName": "Edwards", + "lastName": "Acevedo", + "company": "Quantasis", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Day", + "company": "Datagene", + "employed": false + }, + { + "firstName": "Elsie", + "lastName": "Ford", + "company": "Supportal", + "employed": false + }, + { + "firstName": "Frost", + "lastName": "Walton", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Luella", + "lastName": "Brooks", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Georgia", + "lastName": "Santana", + "company": "Pheast", + "employed": false + }, + { + "firstName": "Barrett", + "lastName": "Macdonald", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "Sybil", + "lastName": "Rodgers", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Debora", + "lastName": "Middleton", + "company": "Hatology", + "employed": false + }, + { + "firstName": "Lane", + "lastName": "Hensley", + "company": "Geekmosis", + "employed": true + }, + { + "firstName": "Alexandria", + "lastName": "Moore", + "company": "Limage", + "employed": false + }, + { + "firstName": "Lara", + "lastName": "Leon", + "company": "Daido", + "employed": true + }, + { + "firstName": "Walsh", + "lastName": "Elliott", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Nikki", + "lastName": "Lewis", + "company": "Polarax", + "employed": false + }, + { + "firstName": "Ramsey", + "lastName": "Rich", + "company": "Inrt", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Conley", + "company": "Gynk", + "employed": false + }, + { + "firstName": "Beasley", + "lastName": "Wilson", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Daphne", + "lastName": "Hinton", + "company": "Codax", + "employed": true + }, + { + "firstName": "Figueroa", + "lastName": "Raymond", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Estella", + "lastName": "Chang", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Tricia", + "lastName": "Castillo", + "company": "Opportech", + "employed": false + }, + { + "firstName": "Toni", + "lastName": "Spears", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Mccarty", + "lastName": "Cherry", + "company": "Aquasseur", + "employed": true + }, + { + "firstName": "Antonia", + "lastName": "Keith", + "company": "Glasstep", + "employed": true + }, + { + "firstName": "Teresa", + "lastName": "Chapman", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Osborn", + "lastName": "Powell", + "company": "Delphide", + "employed": false + }, + { + "firstName": "Hickman", + "lastName": "Mcpherson", + "company": "Enthaze", + "employed": false + }, + { + "firstName": "Wyatt", + "lastName": "Stephens", + "company": "Olympix", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Floyd", + "company": "Remold", + "employed": false + }, + { + "firstName": "Manning", + "lastName": "Wooten", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Mckee", + "lastName": "Robles", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Holt", + "lastName": "Watson", + "company": "Conjurica", + "employed": false + }, + { + "firstName": "Santos", + "lastName": "Stevens", + "company": "Insurity", + "employed": false + }, + { + "firstName": "April", + "lastName": "Wallace", + "company": "Marvane", + "employed": false + }, + { + "firstName": "Gillespie", + "lastName": "Vang", + "company": "Papricut", + "employed": true + }, + { + "firstName": "Sparks", + "lastName": "Jimenez", + "company": "Moltonic", + "employed": false + }, + { + "firstName": "Gale", + "lastName": "Mercer", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Calhoun", + "lastName": "Mckenzie", + "company": "Zentia", + "employed": true + }, + { + "firstName": "Peggy", + "lastName": "Daniel", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Manuela", + "lastName": "Schneider", + "company": "Qnekt", + "employed": false + }, + { + "firstName": "Elvia", + "lastName": "Hawkins", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Diane", + "lastName": "Kent", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Candice", + "lastName": "Branch", + "company": "Acruex", + "employed": true + }, + { + "firstName": "Mccoy", + "lastName": "Davenport", + "company": "Zialactic", + "employed": true + }, + { + "firstName": "Jocelyn", + "lastName": "Aguilar", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Emerson", + "lastName": "Dennis", + "company": "Terragen", + "employed": true + }, + { + "firstName": "Kristie", + "lastName": "Coffey", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Suzette", + "lastName": "Townsend", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Carver", + "lastName": "Clarke", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Wolf", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Chambers", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Rhoda", + "lastName": "Carter", + "company": "Plasmosis", + "employed": false + }, + { + "firstName": "Swanson", + "lastName": "Nielsen", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Sondra", + "lastName": "Ellison", + "company": "Accruex", + "employed": false + }, + { + "firstName": "Solis", + "lastName": "Spencer", + "company": "Techmania", + "employed": true + }, + { + "firstName": "Rae", + "lastName": "Moran", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Yolanda", + "lastName": "Mcdonald", + "company": "Magneato", + "employed": false + }, + { + "firstName": "Alfreda", + "lastName": "Robertson", + "company": "Hairport", + "employed": true + }, + { + "firstName": "Mabel", + "lastName": "Tyson", + "company": "Gracker", + "employed": true + }, + { + "firstName": "Guerrero", + "lastName": "Mcclain", + "company": "Endipin", + "employed": true + }, + { + "firstName": "Bonner", + "lastName": "Pierce", + "company": "Equitox", + "employed": true + }, + { + "firstName": "George", + "lastName": "Justice", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Marks", + "lastName": "Huff", + "company": "Acium", + "employed": true + }, + { + "firstName": "Stark", + "lastName": "Cruz", + "company": "Rodeocean", + "employed": false + }, + { + "firstName": "Mays", + "lastName": "Faulkner", + "company": "Megall", + "employed": true + }, + { + "firstName": "Mavis", + "lastName": "Trevino", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Lou", + "lastName": "Carrillo", + "company": "Ginkogene", + "employed": true + }, + { + "firstName": "Viola", + "lastName": "Bowman", + "company": "Netropic", + "employed": false + }, + { + "firstName": "Tonia", + "lastName": "Manning", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Marlene", + "lastName": "Pope", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Reeves", + "lastName": "Vance", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Flores", + "lastName": "Poole", + "company": "Furnitech", + "employed": false + }, + { + "firstName": "Sloan", + "lastName": "Miller", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Georgette", + "lastName": "Spence", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Marylou", + "lastName": "Levine", + "company": "Coash", + "employed": false + }, + { + "firstName": "Little", + "lastName": "Armstrong", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Gamble", + "lastName": "Gaines", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Jessica", + "lastName": "York", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Mindy", + "lastName": "Johnston", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Franklin", + "lastName": "Rogers", + "company": "Illumity", + "employed": false + }, + { + "firstName": "Vilma", + "lastName": "Velez", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Randi", + "lastName": "Cobb", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Owens", + "lastName": "Rutledge", + "company": "Architax", + "employed": true + }, + { + "firstName": "Beverley", + "lastName": "Fox", + "company": "Recognia", + "employed": false + }, + { + "firstName": "Bertie", + "lastName": "Patton", + "company": "Zilla", + "employed": false + }, + { + "firstName": "Clarissa", + "lastName": "Pena", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Gallagher", + "lastName": "Rhodes", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Glover", + "lastName": "Delacruz", + "company": "Fitcore", + "employed": true + }, + { + "firstName": "Tabatha", + "lastName": "Clay", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Melody", + "lastName": "Holder", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Klein", + "lastName": "Weber", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Mcknight", + "company": "Norali", + "employed": false + }, + { + "firstName": "Alexandra", + "lastName": "Knox", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Deana", + "lastName": "Pittman", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Mullins", + "lastName": "Martinez", + "company": "Cyclonica", + "employed": true + }, + { + "firstName": "Fuller", + "lastName": "Nunez", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Dorthy", + "lastName": "Garner", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Brandi", + "lastName": "Oneill", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Hayes", + "lastName": "Roberson", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Pollard", + "lastName": "Tucker", + "company": "Shepard", + "employed": false + }, + { + "firstName": "Annabelle", + "lastName": "Fowler", + "company": "Cuizine", + "employed": false + }, + { + "firstName": "Curry", + "lastName": "Schroeder", + "company": "Jumpstack", + "employed": false + }, + { + "firstName": "Bradford", + "lastName": "Roberts", + "company": "Aeora", + "employed": false + }, + { + "firstName": "Merrill", + "lastName": "Gallegos", + "company": "Parleynet", + "employed": false + }, + { + "firstName": "Tammi", + "lastName": "Barlow", + "company": "Netur", + "employed": false + }, + { + "firstName": "Kelley", + "lastName": "Wiggins", + "company": "Zillidium", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Hull", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Cynthia", + "lastName": "Reilly", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Martina", + "lastName": "Garrison", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Mathis", + "lastName": "Rocha", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Ramos", + "company": "Pushcart", + "employed": false + }, + { + "firstName": "Fox", + "lastName": "Miles", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Maryellen", + "lastName": "Sampson", + "company": "Sarasonic", + "employed": false + }, + { + "firstName": "Lois", + "lastName": "David", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Humphrey", + "lastName": "Steele", + "company": "Tingles", + "employed": false + }, + { + "firstName": "Concetta", + "lastName": "Johns", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Morgan", + "lastName": "Dillon", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Reva", + "lastName": "Marsh", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Sasha", + "lastName": "Carpenter", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Horn", + "lastName": "Mcmahon", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Erica", + "lastName": "Perkins", + "company": "Pathways", + "employed": true + }, + { + "firstName": "Cortez", + "lastName": "Shaw", + "company": "Elita", + "employed": true + }, + { + "firstName": "Goff", + "lastName": "Rowe", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Burnett", + "lastName": "Hogan", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Mcconnell", + "lastName": "Cohen", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Nadine", + "lastName": "Vasquez", + "company": "Tsunamia", + "employed": true + }, + { + "firstName": "Barlow", + "lastName": "Berger", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Verna", + "lastName": "Wilkinson", + "company": "Rodemco", + "employed": false + }, + { + "firstName": "Bridges", + "lastName": "Carey", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Brandy", + "lastName": "Meadows", + "company": "Synkgen", + "employed": true + }, + { + "firstName": "Best", + "lastName": "Holcomb", + "company": "Apex", + "employed": true + }, + { + "firstName": "Justine", + "lastName": "Bernard", + "company": "Ronelon", + "employed": false + }, + { + "firstName": "Rios", + "lastName": "Lancaster", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Tessa", + "lastName": "Gilbert", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Meyer", + "lastName": "Hickman", + "company": "Flum", + "employed": false + }, + { + "firstName": "Butler", + "lastName": "Barrett", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Natalie", + "lastName": "Webster", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Kathleen", + "lastName": "Pickett", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Benita", + "lastName": "Blackwell", + "company": "Providco", + "employed": false + }, + { + "firstName": "Jasmine", + "lastName": "Jensen", + "company": "Medesign", + "employed": false + }, + { + "firstName": "Mcfarland", + "lastName": "Barry", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Danielle", + "lastName": "Salas", + "company": "Irack", + "employed": false + }, + { + "firstName": "Oneill", + "lastName": "Norton", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Noel", + "lastName": "Gilliam", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Irma", + "lastName": "Kirk", + "company": "Omatom", + "employed": true + }, + { + "firstName": "Porter", + "lastName": "Briggs", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Kristy", + "lastName": "Bryant", + "company": "Radiantix", + "employed": true + }, + { + "firstName": "Macdonald", + "lastName": "Atkinson", + "company": "Schoolio", + "employed": false + }, + { + "firstName": "Wade", + "lastName": "Mcneil", + "company": "Rodeology", + "employed": false + }, + { + "firstName": "Merle", + "lastName": "Dodson", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Riggs", + "lastName": "Cash", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Maria", + "lastName": "England", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Richardson", + "lastName": "Hayes", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Wall", + "lastName": "Kinney", + "company": "Buzzopia", + "employed": false + }, + { + "firstName": "Odom", + "lastName": "Roth", + "company": "Krog", + "employed": true + }, + { + "firstName": "Virgie", + "lastName": "Odom", + "company": "Billmed", + "employed": false + }, + { + "firstName": "Bishop", + "lastName": "Freeman", + "company": "Renovize", + "employed": true + }, + { + "firstName": "Spence", + "lastName": "Silva", + "company": "Snowpoke", + "employed": true + }, + { + "firstName": "Cora", + "lastName": "Matthews", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Mason", + "lastName": "Hobbs", + "company": "Organica", + "employed": false + }, + { + "firstName": "Sullivan", + "lastName": "Rush", + "company": "Isis", + "employed": true + }, + { + "firstName": "Davenport", + "lastName": "Kim", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Boyer", + "lastName": "Herman", + "company": "Spacewax", + "employed": true + }, + { + "firstName": "Earlene", + "lastName": "Malone", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Benjamin", + "lastName": "Carr", + "company": "Velos", + "employed": true + }, + { + "firstName": "Moore", + "lastName": "Mcmillan", + "company": "Shadease", + "employed": false + }, + { + "firstName": "Mooney", + "lastName": "Stewart", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Perry", + "lastName": "Sparks", + "company": "Macronaut", + "employed": false + }, + { + "firstName": "James", + "lastName": "Benjamin", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Vang", + "lastName": "Gentry", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Natalia", + "lastName": "Blanchard", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Cotton", + "lastName": "Velasquez", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Joy", + "lastName": "Giles", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Finch", + "lastName": "Leonard", + "company": "Entality", + "employed": false + }, + { + "firstName": "Rasmussen", + "lastName": "Jordan", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Katina", + "lastName": "Clements", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Rosalyn", + "lastName": "Reid", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Deanne", + "lastName": "Alexander", + "company": "Maximind", + "employed": false + }, + { + "firstName": "Mable", + "lastName": "Pratt", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Ortiz", + "lastName": "Houston", + "company": "Viasia", + "employed": true + }, + { + "firstName": "Ellis", + "lastName": "Osborne", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Sandy", + "lastName": "Greer", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Briana", + "lastName": "Bartlett", + "company": "Gadtron", + "employed": true + }, + { + "firstName": "Araceli", + "lastName": "Mooney", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Byrd", + "lastName": "Norris", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Olive", + "lastName": "Howe", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Burks", + "company": "Insuron", + "employed": true + }, + { + "firstName": "Jeannette", + "lastName": "Carson", + "company": "Zytrac", + "employed": false + }, + { + "firstName": "Taylor", + "lastName": "Sharp", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Jordan", + "lastName": "Frye", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Vargas", + "lastName": "Jennings", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Bridgett", + "lastName": "Baldwin", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Green", + "lastName": "Stafford", + "company": "Zytrax", + "employed": true + }, + { + "firstName": "Russo", + "lastName": "Byers", + "company": "Imkan", + "employed": true + }, + { + "firstName": "Carrillo", + "lastName": "Goodman", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Rosales", + "lastName": "Hess", + "company": "Bristo", + "employed": false + }, + { + "firstName": "Tara", + "lastName": "Mcleod", + "company": "Manufact", + "employed": true + }, + { + "firstName": "Lenora", + "lastName": "Hall", + "company": "Puria", + "employed": false + }, + { + "firstName": "Prince", + "lastName": "Patel", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Duran", + "lastName": "Alvarez", + "company": "Quarmony", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Mayo", + "company": "Equicom", + "employed": true + }, + { + "firstName": "Velez", + "lastName": "Barr", + "company": "Viagreat", + "employed": false + }, + { + "firstName": "Rachelle", + "lastName": "Rivers", + "company": "Sonique", + "employed": false + }, + { + "firstName": "Latasha", + "lastName": "Pennington", + "company": "Coriander", + "employed": false + }, + { + "firstName": "Savage", + "lastName": "Kane", + "company": "Lyria", + "employed": false + }, + { + "firstName": "Williams", + "lastName": "Pearson", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Krista", + "lastName": "Mills", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Perez", + "lastName": "Vaughan", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Foreman", + "lastName": "Blackburn", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Dickerson", + "lastName": "Wheeler", + "company": "Icology", + "employed": true + }, + { + "firstName": "Sheryl", + "lastName": "Burton", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Yesenia", + "lastName": "Irwin", + "company": "Bulljuice", + "employed": false + }, + { + "firstName": "Lakeisha", + "lastName": "Thomas", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Roach", + "company": "Isbol", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Moreno", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Owen", + "lastName": "Mendez", + "company": "Bicol", + "employed": true + }, + { + "firstName": "Gilmore", + "lastName": "Barnett", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Joyner", + "lastName": "Valencia", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Alisha", + "lastName": "George", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Montoya", + "company": "Lexicondo", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Marshall", + "company": "Zaphire", + "employed": true + }, + { + "firstName": "Haley", + "lastName": "Burgess", + "company": "Teraprene", + "employed": true + }, + { + "firstName": "Huber", + "lastName": "Barber", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Pugh", + "lastName": "Larson", + "company": "Geekwagon", + "employed": false + }, + { + "firstName": "Price", + "lastName": "Lynn", + "company": "Franscene", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Mathis", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Nichols", + "lastName": "Boone", + "company": "Automon", + "employed": true + }, + { + "firstName": "Etta", + "lastName": "Banks", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Kathrine", + "lastName": "Cote", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Catherine", + "lastName": "Allen", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Kate", + "lastName": "Lucas", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Mcleod", + "lastName": "Wilder", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Cathleen", + "lastName": "Coleman", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Robles", + "lastName": "Bruce", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Lesa", + "lastName": "Murray", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Wallace", + "lastName": "Butler", + "company": "Accidency", + "employed": true + }, + { + "firstName": "Wilson", + "lastName": "Wong", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Tamika", + "lastName": "William", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Irwin", + "lastName": "Strickland", + "company": "Digial", + "employed": false + }, + { + "firstName": "Tanner", + "lastName": "Espinoza", + "company": "Zilencio", + "employed": true + }, + { + "firstName": "Sherman", + "lastName": "Guzman", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Lowe", + "company": "Zomboid", + "employed": false + }, + { + "firstName": "Ochoa", + "lastName": "Vazquez", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Morse", + "lastName": "Roman", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Juarez", + "company": "Comvene", + "employed": false + }, + { + "firstName": "Kerr", + "lastName": "Hudson", + "company": "Powernet", + "employed": false + }, + { + "firstName": "Orr", + "lastName": "Mitchell", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Sexton", + "lastName": "Villarreal", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Polly", + "lastName": "Lambert", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Colon", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Jannie", + "lastName": "Frank", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Desiree", + "lastName": "Newman", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Meredith", + "lastName": "Sears", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Murphy", + "company": "Singavera", + "employed": false + }, + { + "firstName": "Lester", + "lastName": "Vaughn", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Olivia", + "lastName": "Olson", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Muriel", + "lastName": "Beasley", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Carmela", + "lastName": "Pollard", + "company": "Bitrex", + "employed": true + }, + { + "firstName": "Rhodes", + "lastName": "Daugherty", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Velma", + "lastName": "Padilla", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Felicia", + "lastName": "Best", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Lizzie", + "lastName": "Rollins", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Pauline", + "lastName": "Bonner", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "Flowers", + "lastName": "Sandoval", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Lindsay", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Hatfield", + "lastName": "Chen", + "company": "Techtrix", + "employed": false + }, + { + "firstName": "Mary", + "lastName": "Ellis", + "company": "Typhonica", + "employed": false + }, + { + "firstName": "Lucy", + "lastName": "Mcfadden", + "company": "Comveyer", + "employed": false + }, + { + "firstName": "Cristina", + "lastName": "Ingram", + "company": "Uncorp", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Foreman", + "company": "Uni", + "employed": false + }, + { + "firstName": "Sargent", + "lastName": "Barker", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Ryan", + "lastName": "Slater", + "company": "Virva", + "employed": false + }, + { + "firstName": "Griffith", + "lastName": "Frost", + "company": "Vortexaco", + "employed": true + }, + { + "firstName": "Mejia", + "lastName": "Mccall", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Delia", + "lastName": "Mack", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Bauer", + "lastName": "Swanson", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Graves", + "lastName": "Griffith", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Bruce", + "lastName": "Singleton", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Jeanie", + "lastName": "Stuart", + "company": "Utarian", + "employed": true + }, + { + "firstName": "Dejesus", + "lastName": "Workman", + "company": "Imant", + "employed": false + }, + { + "firstName": "Alexis", + "lastName": "Solis", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Mercado", + "company": "Cytrek", + "employed": false + }, + { + "firstName": "Dodson", + "lastName": "Case", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Maureen", + "lastName": "Molina", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Sofia", + "lastName": "Frederick", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Herminia", + "lastName": "Craft", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Mercado", + "lastName": "Williamson", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Kathie", + "lastName": "Lott", + "company": "Waterbaby", + "employed": true + }, + { + "firstName": "Fernandez", + "lastName": "Brady", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Avery", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Jacobs", + "lastName": "Pugh", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Jami", + "lastName": "Benson", + "company": "Datacator", + "employed": true + }, + { + "firstName": "Fleming", + "lastName": "Benton", + "company": "Stelaecor", + "employed": false + }, + { + "firstName": "Earnestine", + "lastName": "Holland", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Greene", + "lastName": "Guy", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Kayla", + "lastName": "Nelson", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Murphy", + "lastName": "Goff", + "company": "Exosis", + "employed": true + }, + { + "firstName": "Lourdes", + "lastName": "Ramsey", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Solomon", + "lastName": "Harmon", + "company": "Noralex", + "employed": false + }, + { + "firstName": "Burch", + "lastName": "Cook", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Robin", + "lastName": "Stokes", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Ester", + "lastName": "Landry", + "company": "Recrisys", + "employed": true + }, + { + "firstName": "Wiley", + "lastName": "Parker", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Berger", + "lastName": "Joyner", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Buckner", + "lastName": "Calhoun", + "company": "Zork", + "employed": true + }, + { + "firstName": "Zamora", + "lastName": "Melton", + "company": "Obliq", + "employed": false + }, + { + "firstName": "Ophelia", + "lastName": "Ochoa", + "company": "Virxo", + "employed": true + }, + { + "firstName": "Elise", + "lastName": "Mayer", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Scott", + "lastName": "Hahn", + "company": "Deviltoe", + "employed": false + }, + { + "firstName": "Chavez", + "lastName": "Ortiz", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Richard", + "lastName": "Adams", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Stanley", + "lastName": "Mckee", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Gilbert", + "lastName": "Fisher", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "Barbra", + "lastName": "Carlson", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Beryl", + "lastName": "Parks", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Kristina", + "lastName": "Maxwell", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Louella", + "lastName": "Snider", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Hanson", + "lastName": "West", + "company": "Maineland", + "employed": true + }, + { + "firstName": "Barbara", + "lastName": "Rivas", + "company": "Gorganic", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Yates", + "company": "Portica", + "employed": true + }, + { + "firstName": "Jan", + "lastName": "Bishop", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Lessie", + "lastName": "Ryan", + "company": "Neptide", + "employed": false + }, + { + "firstName": "Kendra", + "lastName": "Weeks", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Downs", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Stacey", + "lastName": "Moss", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Eugenia", + "lastName": "Buck", + "company": "Kog", + "employed": true + }, + { + "firstName": "Alyssa", + "lastName": "Lamb", + "company": "Edecine", + "employed": false + }, + { + "firstName": "Carly", + "lastName": "Caldwell", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Hilary", + "lastName": "Byrd", + "company": "Solgan", + "employed": true + }, + { + "firstName": "Long", + "lastName": "Sellers", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Maritza", + "lastName": "Tate", + "company": "Verton", + "employed": false + }, + { + "firstName": "Jillian", + "lastName": "Oneal", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Webb", + "lastName": "Cummings", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Laura", + "lastName": "Mckinney", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Valerie", + "lastName": "Bridges", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Roberts", + "lastName": "Montgomery", + "company": "Pharmex", + "employed": true + }, + { + "firstName": "Giles", + "lastName": "Hicks", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Kay", + "lastName": "Forbes", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Villarreal", + "lastName": "Cochran", + "company": "Zogak", + "employed": true + }, + { + "firstName": "Hays", + "lastName": "Robbins", + "company": "Freakin", + "employed": true + }, + { + "firstName": "Ursula", + "lastName": "Wagner", + "company": "Zanity", + "employed": false + }, + { + "firstName": "Carol", + "lastName": "Rodriquez", + "company": "Vitricomp", + "employed": false + }, + { + "firstName": "Christian", + "lastName": "Stanton", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Baldwin", + "lastName": "Christian", + "company": "Golistic", + "employed": false + }, + { + "firstName": "Hunt", + "lastName": "Avila", + "company": "Vendblend", + "employed": false + }, + { + "firstName": "Knight", + "lastName": "Boyle", + "company": "Gology", + "employed": false + }, + { + "firstName": "Jeanette", + "lastName": "Odonnell", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Kim", + "lastName": "Peck", + "company": "Yurture", + "employed": true + }, + { + "firstName": "Estela", + "lastName": "Lee", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Bowers", + "lastName": "Estes", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Dorsey", + "lastName": "Meyers", + "company": "Nipaz", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Arnold", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Chase", + "lastName": "Livingston", + "company": "Digique", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Mcbride", + "company": "Momentia", + "employed": false + }, + { + "firstName": "Foster", + "lastName": "Frazier", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Mcneil", + "lastName": "Erickson", + "company": "Everest", + "employed": false + }, + { + "firstName": "Ellison", + "lastName": "Serrano", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Marta", + "lastName": "Waters", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Park", + "lastName": "Potter", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Ware", + "lastName": "Greene", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Waters", + "lastName": "Rodriguez", + "company": "Earthpure", + "employed": true + }, + { + "firstName": "Elsa", + "lastName": "Carroll", + "company": "Cytrex", + "employed": true + }, + { + "firstName": "Bass", + "lastName": "Merritt", + "company": "Xelegyl", + "employed": false + }, + { + "firstName": "Pearlie", + "lastName": "Olsen", + "company": "Obones", + "employed": true + }, + { + "firstName": "Bernice", + "lastName": "Douglas", + "company": "Datagen", + "employed": true + }, + { + "firstName": "Smith", + "lastName": "Mann", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Norman", + "lastName": "Sweet", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Young", + "lastName": "Bentley", + "company": "Xleen", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Levy", + "company": "Jetsilk", + "employed": false + }, + { + "firstName": "Gilliam", + "lastName": "Osborn", + "company": "Geeketron", + "employed": true + }, + { + "firstName": "Berg", + "lastName": "Kaufman", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Ferguson", + "lastName": "Lara", + "company": "Geekosis", + "employed": false + }, + { + "firstName": "Goodman", + "lastName": "Paul", + "company": "Namegen", + "employed": false + }, + { + "firstName": "May", + "lastName": "Valenzuela", + "company": "Hotcakes", + "employed": false + }, + { + "firstName": "Meadows", + "lastName": "Rios", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Lindsay", + "lastName": "Barron", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Knox", + "lastName": "Ewing", + "company": "Duflex", + "employed": true + }, + { + "firstName": "Miles", + "lastName": "Bright", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Simmons", + "lastName": "Langley", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Charles", + "lastName": "Hamilton", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Isabel", + "lastName": "Strong", + "company": "Artworlds", + "employed": true + }, + { + "firstName": "Marsha", + "lastName": "Chandler", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Avila", + "lastName": "Valdez", + "company": "Geoforma", + "employed": false + }, + { + "firstName": "Marcy", + "lastName": "Walls", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Bridgette", + "lastName": "Hopper", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Guthrie", + "lastName": "Hooper", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Jones", + "lastName": "Hardy", + "company": "Utara", + "employed": false + }, + { + "firstName": "Lila", + "lastName": "Stevenson", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Ethel", + "lastName": "Carroll", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Louella", + "lastName": "Hendrix", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Velazquez", + "company": "Maineland", + "employed": true + }, + { + "firstName": "Marietta", + "lastName": "Kirby", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "James", + "lastName": "Morse", + "company": "Biotica", + "employed": true + }, + { + "firstName": "Jefferson", + "lastName": "Snow", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Duke", + "lastName": "Oneil", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Cook", + "lastName": "Golden", + "company": "Naxdis", + "employed": false + }, + { + "firstName": "Perry", + "lastName": "Roth", + "company": "Obliq", + "employed": true + }, + { + "firstName": "Charity", + "lastName": "Mcknight", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Peck", + "company": "Frolix", + "employed": true + }, + { + "firstName": "Mcbride", + "lastName": "Gregory", + "company": "Genmex", + "employed": true + }, + { + "firstName": "Lauren", + "lastName": "Clayton", + "company": "Gynk", + "employed": true + }, + { + "firstName": "Buchanan", + "lastName": "Ellis", + "company": "Genmom", + "employed": false + }, + { + "firstName": "Charmaine", + "lastName": "Padilla", + "company": "Idealis", + "employed": true + }, + { + "firstName": "Jacqueline", + "lastName": "Craig", + "company": "Acusage", + "employed": true + }, + { + "firstName": "Alicia", + "lastName": "Parrish", + "company": "Iplax", + "employed": true + }, + { + "firstName": "Laurel", + "lastName": "Dickson", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "Kirkland", + "lastName": "Cotton", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Nadia", + "lastName": "Sharpe", + "company": "Valreda", + "employed": true + }, + { + "firstName": "Hoover", + "lastName": "Hatfield", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Harrell", + "lastName": "Santos", + "company": "Menbrain", + "employed": true + }, + { + "firstName": "Lola", + "lastName": "Talley", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Marquez", + "company": "Dadabase", + "employed": true + }, + { + "firstName": "Bolton", + "lastName": "Payne", + "company": "Zerology", + "employed": false + }, + { + "firstName": "Charlene", + "lastName": "Joseph", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Sally", + "lastName": "Jenkins", + "company": "Bittor", + "employed": false + }, + { + "firstName": "Benton", + "lastName": "Conley", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Josefa", + "lastName": "Patrick", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Betty", + "lastName": "Flynn", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Tanisha", + "lastName": "Graves", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Trudy", + "lastName": "Wilder", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Courtney", + "lastName": "Solis", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Nikki", + "lastName": "Lowe", + "company": "Capscreen", + "employed": true + }, + { + "firstName": "Mathews", + "lastName": "Acosta", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Loraine", + "lastName": "Shepherd", + "company": "Comcubine", + "employed": true + }, + { + "firstName": "May", + "lastName": "Macias", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Bianca", + "lastName": "Bennett", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Deloris", + "lastName": "Briggs", + "company": "Zidant", + "employed": false + }, + { + "firstName": "Saunders", + "lastName": "Travis", + "company": "Isbol", + "employed": false + }, + { + "firstName": "Tara", + "lastName": "Stevens", + "company": "Verton", + "employed": false + }, + { + "firstName": "Rivas", + "lastName": "Mcintyre", + "company": "Namegen", + "employed": true + }, + { + "firstName": "Mcdowell", + "lastName": "Bowers", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Helene", + "lastName": "Fernandez", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Hutchinson", + "lastName": "Mueller", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Sexton", + "lastName": "Goodman", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Shelley", + "lastName": "Sheppard", + "company": "Nurali", + "employed": true + }, + { + "firstName": "Bertha", + "lastName": "Chambers", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Tania", + "lastName": "Morales", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Lynette", + "lastName": "Bell", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Blanca", + "lastName": "Burt", + "company": "Netbook", + "employed": false + }, + { + "firstName": "Gayle", + "lastName": "Keller", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Guerra", + "lastName": "Harrell", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Barlow", + "lastName": "Gutierrez", + "company": "Zilidium", + "employed": false + }, + { + "firstName": "Beard", + "lastName": "Hodges", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Kimberley", + "lastName": "Nichols", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Yolanda", + "lastName": "Townsend", + "company": "Qualitern", + "employed": true + }, + { + "firstName": "Ava", + "lastName": "Henry", + "company": "Katakana", + "employed": false + }, + { + "firstName": "Jodi", + "lastName": "Thompson", + "company": "Maxemia", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Gross", + "company": "Cormoran", + "employed": false + }, + { + "firstName": "Sofia", + "lastName": "Hewitt", + "company": "Konnect", + "employed": false + }, + { + "firstName": "James", + "lastName": "Booth", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Pansy", + "lastName": "Barker", + "company": "Koogle", + "employed": true + }, + { + "firstName": "Olive", + "lastName": "Holmes", + "company": "Inventure", + "employed": false + }, + { + "firstName": "Hurley", + "lastName": "Mercado", + "company": "Combogene", + "employed": true + }, + { + "firstName": "Gibbs", + "lastName": "Landry", + "company": "Unq", + "employed": true + }, + { + "firstName": "Silva", + "lastName": "Stokes", + "company": "Isosphere", + "employed": true + }, + { + "firstName": "Clayton", + "lastName": "Fry", + "company": "Conjurica", + "employed": false + }, + { + "firstName": "Lynnette", + "lastName": "Gilliam", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Dean", + "lastName": "Hartman", + "company": "Cubicide", + "employed": true + }, + { + "firstName": "Mcclure", + "lastName": "Silva", + "company": "Voratak", + "employed": false + }, + { + "firstName": "Hendrix", + "lastName": "Mccoy", + "company": "Utara", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Buckley", + "company": "Hometown", + "employed": false + }, + { + "firstName": "Susana", + "lastName": "Winters", + "company": "Uniworld", + "employed": true + }, + { + "firstName": "Mari", + "lastName": "Day", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Pope", + "lastName": "Rich", + "company": "Furnitech", + "employed": false + }, + { + "firstName": "Stevens", + "lastName": "Gonzales", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Tucker", + "company": "Caxt", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Duran", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Gillespie", + "lastName": "Phelps", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Head", + "lastName": "Bird", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Goodman", + "lastName": "Maldonado", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Sonya", + "lastName": "Everett", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Kathrine", + "lastName": "Bowman", + "company": "Lumbrex", + "employed": true + }, + { + "firstName": "Bailey", + "lastName": "Bates", + "company": "Comtest", + "employed": false + }, + { + "firstName": "Angelita", + "lastName": "Schroeder", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "Lizzie", + "lastName": "Madden", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Petersen", + "lastName": "Kim", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Kline", + "lastName": "Powell", + "company": "Medesign", + "employed": true + }, + { + "firstName": "Carmella", + "lastName": "Pickett", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Carlene", + "lastName": "Monroe", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Flores", + "lastName": "Cox", + "company": "Netility", + "employed": true + }, + { + "firstName": "Pickett", + "lastName": "Mcneil", + "company": "Polarax", + "employed": false + }, + { + "firstName": "Jannie", + "lastName": "Drake", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Mccray", + "lastName": "Thornton", + "company": "Quotezart", + "employed": true + }, + { + "firstName": "Aurora", + "lastName": "Terry", + "company": "Slax", + "employed": true + }, + { + "firstName": "Wade", + "lastName": "Beck", + "company": "Nexgene", + "employed": true + }, + { + "firstName": "Noelle", + "lastName": "Haney", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Brooke", + "lastName": "Woods", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Chambers", + "lastName": "Jacobs", + "company": "Tripsch", + "employed": false + }, + { + "firstName": "Fowler", + "lastName": "Skinner", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Downs", + "lastName": "Hinton", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Hollie", + "lastName": "Strong", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Mayra", + "lastName": "Smith", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Lenora", + "lastName": "Cooley", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Sharpe", + "lastName": "Kerr", + "company": "Bristo", + "employed": false + }, + { + "firstName": "Vaughn", + "lastName": "Merrill", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Chen", + "lastName": "Schneider", + "company": "Mantro", + "employed": false + }, + { + "firstName": "Cleo", + "lastName": "Kelley", + "company": "Otherway", + "employed": false + }, + { + "firstName": "Hardy", + "lastName": "Mcpherson", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Beulah", + "lastName": "Howell", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Whitley", + "lastName": "Schwartz", + "company": "Xinware", + "employed": false + }, + { + "firstName": "Mason", + "lastName": "Faulkner", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Letha", + "lastName": "Hobbs", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Bullock", + "lastName": "Keith", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Inez", + "lastName": "Franks", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Kristi", + "lastName": "Beasley", + "company": "Cyclonica", + "employed": false + }, + { + "firstName": "Paige", + "lastName": "Kemp", + "company": "Flum", + "employed": false + }, + { + "firstName": "Logan", + "lastName": "Delgado", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Foster", + "lastName": "Holcomb", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Velasquez", + "lastName": "Rodriquez", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Cortez", + "lastName": "Park", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Todd", + "lastName": "Owen", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Tonia", + "lastName": "Greene", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Gross", + "lastName": "Gamble", + "company": "Medcom", + "employed": true + }, + { + "firstName": "Edith", + "lastName": "Hamilton", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Lynne", + "lastName": "Pearson", + "company": "Animalia", + "employed": true + }, + { + "firstName": "Kris", + "lastName": "Walter", + "company": "Virva", + "employed": false + }, + { + "firstName": "Verna", + "lastName": "Leach", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Naomi", + "lastName": "Quinn", + "company": "Springbee", + "employed": false + }, + { + "firstName": "Roxanne", + "lastName": "Macdonald", + "company": "Eyeris", + "employed": false + }, + { + "firstName": "Atkinson", + "lastName": "Hubbard", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Ruby", + "lastName": "Bass", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Daniel", + "lastName": "Hunter", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Florence", + "lastName": "Kelly", + "company": "Boink", + "employed": true + }, + { + "firstName": "Taylor", + "lastName": "Hawkins", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Manuela", + "lastName": "Norton", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Colette", + "lastName": "Ewing", + "company": "Retrack", + "employed": true + }, + { + "firstName": "Snow", + "lastName": "Witt", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Agnes", + "lastName": "Cooper", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Hurst", + "lastName": "Murray", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Luella", + "lastName": "Snider", + "company": "Comvex", + "employed": false + }, + { + "firstName": "Gill", + "lastName": "Petersen", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Sellers", + "lastName": "Harvey", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Gibson", + "lastName": "Potts", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Freeman", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Queen", + "lastName": "Hull", + "company": "Sulfax", + "employed": true + }, + { + "firstName": "Gamble", + "lastName": "Melton", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Bass", + "lastName": "Valencia", + "company": "Isostream", + "employed": true + }, + { + "firstName": "Erma", + "lastName": "Marsh", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Daniels", + "lastName": "Head", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Baldwin", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Payne", + "lastName": "Holloway", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Cynthia", + "lastName": "Wagner", + "company": "Hairport", + "employed": true + }, + { + "firstName": "Roseann", + "lastName": "Peters", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Sosa", + "lastName": "Robbins", + "company": "Gynko", + "employed": true + }, + { + "firstName": "Mcmillan", + "lastName": "Norman", + "company": "Acruex", + "employed": false + }, + { + "firstName": "Lucas", + "lastName": "Harrison", + "company": "Exozent", + "employed": true + }, + { + "firstName": "Margret", + "lastName": "Howe", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Lesley", + "lastName": "Curtis", + "company": "Assistix", + "employed": true + }, + { + "firstName": "Merrill", + "lastName": "Dalton", + "company": "Glasstep", + "employed": false + }, + { + "firstName": "Byers", + "lastName": "Blevins", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Morrow", + "lastName": "Beard", + "company": "Digique", + "employed": false + }, + { + "firstName": "Woodward", + "lastName": "Prince", + "company": "Centrexin", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Combs", + "company": "Goko", + "employed": false + }, + { + "firstName": "Fry", + "lastName": "Ray", + "company": "Furnafix", + "employed": true + }, + { + "firstName": "Brigitte", + "lastName": "Wise", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Eunice", + "lastName": "Blair", + "company": "Polarium", + "employed": false + }, + { + "firstName": "Aguilar", + "lastName": "Wilkinson", + "company": "Deviltoe", + "employed": true + }, + { + "firstName": "Vang", + "lastName": "Lester", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Jennings", + "lastName": "Boyle", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Mindy", + "lastName": "King", + "company": "Zillatide", + "employed": true + }, + { + "firstName": "Gladys", + "lastName": "York", + "company": "Strozen", + "employed": true + }, + { + "firstName": "Liliana", + "lastName": "Wiley", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Mcguire", + "lastName": "Sawyer", + "company": "Besto", + "employed": false + }, + { + "firstName": "Lavonne", + "lastName": "Jefferson", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Raymond", + "lastName": "Coffey", + "company": "Xeronk", + "employed": true + }, + { + "firstName": "Pearson", + "lastName": "Richmond", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Barry", + "lastName": "Ferguson", + "company": "Viagreat", + "employed": false + }, + { + "firstName": "Elsie", + "lastName": "Bolton", + "company": "Quilch", + "employed": true + }, + { + "firstName": "Wendi", + "lastName": "May", + "company": "Genmy", + "employed": false + }, + { + "firstName": "Valeria", + "lastName": "Good", + "company": "Renovize", + "employed": true + }, + { + "firstName": "Maynard", + "lastName": "Long", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Jenny", + "lastName": "Mcfarland", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Sheryl", + "lastName": "Pate", + "company": "Amtap", + "employed": true + }, + { + "firstName": "Melisa", + "lastName": "Hampton", + "company": "Calcu", + "employed": false + }, + { + "firstName": "Juliet", + "lastName": "Davidson", + "company": "Snowpoke", + "employed": true + }, + { + "firstName": "Dionne", + "lastName": "Ruiz", + "company": "Snacktion", + "employed": false + }, + { + "firstName": "Macdonald", + "lastName": "Browning", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Amelia", + "lastName": "Goff", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Sue", + "lastName": "Vega", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Natasha", + "lastName": "Fulton", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Johnston", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Osborne", + "lastName": "Odonnell", + "company": "Anixang", + "employed": true + }, + { + "firstName": "Johnnie", + "lastName": "Daugherty", + "company": "Thredz", + "employed": false + }, + { + "firstName": "Marquita", + "lastName": "Moody", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Lakeisha", + "lastName": "Green", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Roach", + "lastName": "Meyer", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Mildred", + "lastName": "Wade", + "company": "Insectus", + "employed": false + }, + { + "firstName": "Weber", + "lastName": "Eaton", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Pena", + "lastName": "Cobb", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Oliver", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Rachelle", + "lastName": "Kent", + "company": "Pigzart", + "employed": true + }, + { + "firstName": "Jackson", + "lastName": "Lara", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Mathis", + "lastName": "Rutledge", + "company": "Elita", + "employed": true + }, + { + "firstName": "Lynda", + "lastName": "Burns", + "company": "Waretel", + "employed": true + }, + { + "firstName": "Marcia", + "lastName": "Shaw", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Rollins", + "lastName": "Baker", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Boyd", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Iris", + "lastName": "Mccullough", + "company": "Idego", + "employed": true + }, + { + "firstName": "Allen", + "lastName": "Ferrell", + "company": "Wazzu", + "employed": true + }, + { + "firstName": "Francisca", + "lastName": "Sellers", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Whitney", + "lastName": "Cardenas", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Cole", + "lastName": "Olson", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Brittany", + "lastName": "Trujillo", + "company": "Rockabye", + "employed": false + }, + { + "firstName": "Preston", + "lastName": "Fuentes", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Farmer", + "lastName": "Serrano", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Susie", + "lastName": "Harmon", + "company": "Digitalus", + "employed": false + }, + { + "firstName": "Church", + "lastName": "Gilmore", + "company": "Futuris", + "employed": true + }, + { + "firstName": "Melton", + "lastName": "Finch", + "company": "Vidto", + "employed": true + }, + { + "firstName": "Sargent", + "lastName": "Jarvis", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Owens", + "lastName": "Hurst", + "company": "Krog", + "employed": true + }, + { + "firstName": "Mercer", + "lastName": "Sweeney", + "company": "Rameon", + "employed": false + }, + { + "firstName": "Bradford", + "lastName": "James", + "company": "Pharmex", + "employed": true + }, + { + "firstName": "Marina", + "lastName": "Mccarty", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Medina", + "lastName": "Abbott", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Polly", + "lastName": "Berger", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Crosby", + "lastName": "Lambert", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Evangelina", + "lastName": "Woodard", + "company": "Zentia", + "employed": true + }, + { + "firstName": "Reid", + "lastName": "Rosa", + "company": "Bitrex", + "employed": true + }, + { + "firstName": "Kristina", + "lastName": "Koch", + "company": "Quadeebo", + "employed": false + }, + { + "firstName": "Combs", + "lastName": "Cummings", + "company": "Amril", + "employed": true + }, + { + "firstName": "Diana", + "lastName": "Wolf", + "company": "Opticon", + "employed": true + }, + { + "firstName": "Nicole", + "lastName": "Berg", + "company": "Temorak", + "employed": true + }, + { + "firstName": "Maxine", + "lastName": "Martinez", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Jeannine", + "lastName": "White", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Bean", + "lastName": "Chase", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Carroll", + "lastName": "Mendoza", + "company": "Insource", + "employed": false + }, + { + "firstName": "Gail", + "lastName": "Stanley", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Mamie", + "lastName": "Chen", + "company": "Tropoli", + "employed": false + }, + { + "firstName": "Noble", + "lastName": "Cochran", + "company": "Qnekt", + "employed": true + }, + { + "firstName": "Clara", + "lastName": "Hanson", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Nanette", + "lastName": "Johns", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Sosa", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Warner", + "lastName": "Stephenson", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Kay", + "lastName": "Mckay", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Baxter", + "lastName": "Johnson", + "company": "Rotodyne", + "employed": true + }, + { + "firstName": "Booth", + "lastName": "Slater", + "company": "Pharmacon", + "employed": false + }, + { + "firstName": "Norton", + "lastName": "Reese", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Ina", + "lastName": "Boone", + "company": "Genesynk", + "employed": true + }, + { + "firstName": "Jeanette", + "lastName": "Suarez", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Rowena", + "lastName": "Petty", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Marquez", + "lastName": "Pugh", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Moore", + "lastName": "Herring", + "company": "Isologics", + "employed": false + }, + { + "firstName": "Aida", + "lastName": "Downs", + "company": "Cytrex", + "employed": true + }, + { + "firstName": "Darlene", + "lastName": "Pittman", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Tina", + "lastName": "Alvarez", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Brady", + "lastName": "Mooney", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Chandra", + "lastName": "Ashley", + "company": "Daido", + "employed": true + }, + { + "firstName": "Hughes", + "lastName": "Cantu", + "company": "Kaggle", + "employed": true + }, + { + "firstName": "Beryl", + "lastName": "Ochoa", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Ursula", + "lastName": "Valenzuela", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Vinson", + "lastName": "Horn", + "company": "Puria", + "employed": true + }, + { + "firstName": "Yates", + "lastName": "Alvarado", + "company": "Eplosion", + "employed": true + }, + { + "firstName": "Chang", + "lastName": "Patterson", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Vicky", + "lastName": "Sampson", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "Hayes", + "lastName": "Waller", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Elnora", + "lastName": "Yang", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Brown", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Estelle", + "lastName": "Price", + "company": "Omatom", + "employed": true + }, + { + "firstName": "Conley", + "lastName": "Glenn", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Wong", + "lastName": "Jacobson", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Shawna", + "lastName": "Spence", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Mia", + "lastName": "Dickerson", + "company": "Farmex", + "employed": false + }, + { + "firstName": "Lucia", + "lastName": "Dudley", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Tessa", + "lastName": "Knight", + "company": "Zaggles", + "employed": false + }, + { + "firstName": "Winnie", + "lastName": "Curry", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Palmer", + "lastName": "Tyson", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Renee", + "lastName": "Fischer", + "company": "Kengen", + "employed": false + }, + { + "firstName": "Levy", + "lastName": "Yates", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Ramirez", + "lastName": "Wood", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Hernandez", + "lastName": "Vaughan", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Robin", + "lastName": "Reid", + "company": "Lyrichord", + "employed": true + }, + { + "firstName": "Christensen", + "lastName": "Bradley", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Olivia", + "lastName": "Benjamin", + "company": "Codact", + "employed": true + }, + { + "firstName": "Ingram", + "lastName": "Montgomery", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Lenore", + "lastName": "Boyer", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Barbara", + "lastName": "Austin", + "company": "Hawkster", + "employed": false + }, + { + "firstName": "Rowe", + "lastName": "Bender", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Rae", + "lastName": "Duncan", + "company": "Accel", + "employed": false + }, + { + "firstName": "Nguyen", + "lastName": "Mann", + "company": "Quinex", + "employed": true + }, + { + "firstName": "Jessie", + "lastName": "Cannon", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Beck", + "lastName": "Dominguez", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Tamra", + "lastName": "Little", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Cabrera", + "lastName": "Bruce", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Moses", + "lastName": "Crosby", + "company": "Grainspot", + "employed": true + }, + { + "firstName": "Jacklyn", + "lastName": "Reeves", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Griffith", + "lastName": "Berry", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Galloway", + "lastName": "Bernard", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Terri", + "lastName": "Roberson", + "company": "Geekosis", + "employed": false + }, + { + "firstName": "Sharon", + "lastName": "Campbell", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Britt", + "lastName": "Owens", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Tyson", + "lastName": "Sweet", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Mcneil", + "lastName": "Schmidt", + "company": "Cipromox", + "employed": true + }, + { + "firstName": "Marilyn", + "lastName": "Palmer", + "company": "Prowaste", + "employed": true + }, + { + "firstName": "Vera", + "lastName": "Blackburn", + "company": "Parleynet", + "employed": false + }, + { + "firstName": "Francine", + "lastName": "Chavez", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Erna", + "lastName": "Hardin", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Bender", + "lastName": "Brady", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Rhoda", + "lastName": "Hudson", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Jocelyn", + "lastName": "Pena", + "company": "Nipaz", + "employed": false + }, + { + "firstName": "Dillard", + "lastName": "Bartlett", + "company": "Buzzness", + "employed": false + }, + { + "firstName": "Hartman", + "lastName": "Stuart", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Lidia", + "lastName": "Lowery", + "company": "Canopoly", + "employed": true + }, + { + "firstName": "Charlotte", + "lastName": "Vinson", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Rosie", + "lastName": "Cervantes", + "company": "Apex", + "employed": false + }, + { + "firstName": "Matilda", + "lastName": "Moss", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Morgan", + "lastName": "Mclaughlin", + "company": "Eschoir", + "employed": true + }, + { + "firstName": "Webster", + "lastName": "Patton", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Brittney", + "lastName": "Hernandez", + "company": "Luxuria", + "employed": false + }, + { + "firstName": "Jana", + "lastName": "Dorsey", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Neal", + "lastName": "Glover", + "company": "Sensate", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Burks", + "company": "Sarasonic", + "employed": true + }, + { + "firstName": "Josefina", + "lastName": "Lynn", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Allison", + "lastName": "Flores", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Maryanne", + "lastName": "Hodge", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "George", + "company": "Callflex", + "employed": true + }, + { + "firstName": "Muriel", + "lastName": "Rivas", + "company": "Zentime", + "employed": true + }, + { + "firstName": "Corrine", + "lastName": "Peterson", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Fay", + "lastName": "David", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Christi", + "lastName": "Velez", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Harrison", + "lastName": "Stein", + "company": "Bleendot", + "employed": true + }, + { + "firstName": "Kara", + "lastName": "Rowe", + "company": "Keeg", + "employed": true + }, + { + "firstName": "Tommie", + "lastName": "Moreno", + "company": "Norali", + "employed": false + }, + { + "firstName": "Bradshaw", + "lastName": "Dunn", + "company": "Plasto", + "employed": true + }, + { + "firstName": "Beach", + "lastName": "Hancock", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Mendez", + "lastName": "Garcia", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Bernard", + "lastName": "Paul", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Jerri", + "lastName": "Barry", + "company": "Kneedles", + "employed": true + }, + { + "firstName": "Hillary", + "lastName": "Weeks", + "company": "Petigems", + "employed": true + }, + { + "firstName": "Staci", + "lastName": "Donaldson", + "company": "Neurocell", + "employed": true + }, + { + "firstName": "Kaye", + "lastName": "Phillips", + "company": "Applica", + "employed": true + }, + { + "firstName": "Morris", + "lastName": "Durham", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Vanessa", + "lastName": "Tate", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Atkins", + "lastName": "Pitts", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Marsha", + "lastName": "Ward", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Alissa", + "lastName": "Whitley", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Selena", + "lastName": "Whitehead", + "company": "Xsports", + "employed": true + }, + { + "firstName": "Mcknight", + "lastName": "Gaines", + "company": "Realmo", + "employed": true + }, + { + "firstName": "Sophie", + "lastName": "Fletcher", + "company": "Noralex", + "employed": false + }, + { + "firstName": "Penelope", + "lastName": "Wong", + "company": "Stucco", + "employed": true + }, + { + "firstName": "Latonya", + "lastName": "Joyce", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Hobbs", + "lastName": "Hill", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Ericka", + "lastName": "Burke", + "company": "Peticular", + "employed": true + }, + { + "firstName": "Camille", + "lastName": "Frank", + "company": "Providco", + "employed": false + }, + { + "firstName": "Cassandra", + "lastName": "Cash", + "company": "Digial", + "employed": false + }, + { + "firstName": "Robbins", + "lastName": "Garrison", + "company": "Megall", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Mcgowan", + "company": "Portico", + "employed": false + }, + { + "firstName": "Kinney", + "lastName": "Roman", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Price", + "lastName": "Orr", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Dolores", + "lastName": "Burris", + "company": "Everest", + "employed": false + }, + { + "firstName": "Nona", + "lastName": "Farley", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Sherman", + "lastName": "Mccormick", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Tamara", + "lastName": "Mejia", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Terry", + "lastName": "Farrell", + "company": "Powernet", + "employed": true + }, + { + "firstName": "Velma", + "lastName": "Morris", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Katheryn", + "lastName": "Dejesus", + "company": "Corpulse", + "employed": true + }, + { + "firstName": "Leta", + "lastName": "Webb", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Ross", + "lastName": "Foreman", + "company": "Fleetmix", + "employed": true + }, + { + "firstName": "Sara", + "lastName": "Battle", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Hensley", + "lastName": "Bush", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Briggs", + "lastName": "Dale", + "company": "Cognicode", + "employed": false + }, + { + "firstName": "Melba", + "lastName": "Conner", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Mae", + "lastName": "Nicholson", + "company": "Sustenza", + "employed": false + }, + { + "firstName": "Robbie", + "lastName": "Woodward", + "company": "Viasia", + "employed": true + }, + { + "firstName": "Cervantes", + "lastName": "Chandler", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Donaldson", + "lastName": "Sanford", + "company": "Mobildata", + "employed": false + }, + { + "firstName": "Evelyn", + "lastName": "Mays", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Cecelia", + "lastName": "Horton", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Meyers", + "lastName": "Roberts", + "company": "Euron", + "employed": false + }, + { + "firstName": "Shelia", + "lastName": "Finley", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Little", + "lastName": "Rollins", + "company": "Uberlux", + "employed": true + }, + { + "firstName": "Yvonne", + "lastName": "Molina", + "company": "Emergent", + "employed": true + }, + { + "firstName": "Ophelia", + "lastName": "Bridges", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Reed", + "lastName": "Roach", + "company": "Jumpstack", + "employed": true + }, + { + "firstName": "Tanya", + "lastName": "Langley", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Rodgers", + "lastName": "Holman", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Lourdes", + "lastName": "Riley", + "company": "Aeora", + "employed": false + }, + { + "firstName": "Adele", + "lastName": "Calhoun", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Lana", + "lastName": "Cruz", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Stanton", + "lastName": "Foster", + "company": "Shepard", + "employed": false + }, + { + "firstName": "Caitlin", + "lastName": "Hardy", + "company": "Hotcakes", + "employed": false + }, + { + "firstName": "Justine", + "lastName": "Marshall", + "company": "Geeky", + "employed": false + }, + { + "firstName": "Stafford", + "lastName": "Duke", + "company": "Baluba", + "employed": false + }, + { + "firstName": "Vance", + "lastName": "Dillard", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Hensley", + "company": "Zappix", + "employed": false + }, + { + "firstName": "Nolan", + "lastName": "Jennings", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Jeanine", + "lastName": "Salas", + "company": "Stelaecor", + "employed": false + }, + { + "firstName": "Lucile", + "lastName": "Gillespie", + "company": "Comtext", + "employed": true + }, + { + "firstName": "Levine", + "lastName": "Bryan", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Nelda", + "lastName": "Wilson", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Janis", + "lastName": "Guerra", + "company": "Remotion", + "employed": true + }, + { + "firstName": "Wilma", + "lastName": "Lee", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Ernestine", + "lastName": "Shields", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Kerry", + "lastName": "Reilly", + "company": "Extragen", + "employed": false + }, + { + "firstName": "Avis", + "lastName": "Collier", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Carlson", + "lastName": "Edwards", + "company": "Grok", + "employed": false + }, + { + "firstName": "Oneill", + "lastName": "Montoya", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Cathy", + "lastName": "William", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Winifred", + "lastName": "Holt", + "company": "Zogak", + "employed": false + }, + { + "firstName": "Erin", + "lastName": "Wolfe", + "company": "Permadyne", + "employed": true + }, + { + "firstName": "Solis", + "lastName": "Robertson", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Isabella", + "lastName": "Noble", + "company": "Proxsoft", + "employed": false + }, + { + "firstName": "Lea", + "lastName": "Estes", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Grimes", + "lastName": "Hart", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Holcomb", + "lastName": "Hansen", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Cooke", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Love", + "lastName": "Whitney", + "company": "Endicil", + "employed": false + }, + { + "firstName": "Samantha", + "lastName": "Rosales", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Marva", + "lastName": "Ramsey", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Bobbi", + "lastName": "Kane", + "company": "Dyno", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Noel", + "company": "Waterbaby", + "employed": false + }, + { + "firstName": "Fisher", + "lastName": "Lindsay", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Alford", + "lastName": "Shannon", + "company": "Metroz", + "employed": false + }, + { + "firstName": "Mosley", + "lastName": "Key", + "company": "Boilcat", + "employed": true + }, + { + "firstName": "Nettie", + "lastName": "Christian", + "company": "Deminimum", + "employed": false + }, + { + "firstName": "Blanchard", + "lastName": "Jimenez", + "company": "Plasmosis", + "employed": false + }, + { + "firstName": "Billie", + "lastName": "Floyd", + "company": "Shadease", + "employed": false + }, + { + "firstName": "Janelle", + "lastName": "Osborn", + "company": "Genekom", + "employed": false + }, + { + "firstName": "Denise", + "lastName": "Walls", + "company": "Aquoavo", + "employed": true + }, + { + "firstName": "Hopper", + "lastName": "Pierce", + "company": "Zialactic", + "employed": false + }, + { + "firstName": "Faye", + "lastName": "Hopkins", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Rita", + "lastName": "Emerson", + "company": "Parcoe", + "employed": true + }, + { + "firstName": "Cara", + "lastName": "Joyner", + "company": "Organica", + "employed": true + }, + { + "firstName": "Humphrey", + "lastName": "Wallace", + "company": "Plasmox", + "employed": false + }, + { + "firstName": "Kemp", + "lastName": "Heath", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Saunders", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "Ellison", + "lastName": "Olsen", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Alice", + "lastName": "Walton", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Hood", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Silvia", + "lastName": "Bullock", + "company": "Interloo", + "employed": true + }, + { + "firstName": "Poole", + "lastName": "Cain", + "company": "Zilla", + "employed": false + }, + { + "firstName": "Ladonna", + "lastName": "Wheeler", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Essie", + "lastName": "Britt", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Shelton", + "lastName": "Forbes", + "company": "Infotrips", + "employed": false + }, + { + "firstName": "Garza", + "lastName": "Estrada", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Johnson", + "lastName": "Erickson", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Britney", + "lastName": "Tillman", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Riddle", + "lastName": "Shepard", + "company": "Comtrak", + "employed": true + }, + { + "firstName": "Arnold", + "lastName": "Aguirre", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Page", + "lastName": "Hurley", + "company": "Flexigen", + "employed": true + }, + { + "firstName": "Sawyer", + "lastName": "Cleveland", + "company": "Anocha", + "employed": false + }, + { + "firstName": "Pugh", + "lastName": "Small", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Christy", + "lastName": "Stout", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Imogene", + "lastName": "Calderon", + "company": "Zillacom", + "employed": true + }, + { + "firstName": "Kathleen", + "lastName": "Blake", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Willa", + "lastName": "Jones", + "company": "Helixo", + "employed": true + }, + { + "firstName": "June", + "lastName": "Wilkerson", + "company": "Halap", + "employed": false + }, + { + "firstName": "Ebony", + "lastName": "Garner", + "company": "Spherix", + "employed": false + }, + { + "firstName": "Anna", + "lastName": "Allen", + "company": "Cuizine", + "employed": true + }, + { + "firstName": "Gilmore", + "lastName": "Stewart", + "company": "Quizka", + "employed": false + }, + { + "firstName": "Tonya", + "lastName": "Watkins", + "company": "Velity", + "employed": true + }, + { + "firstName": "Deanne", + "lastName": "Cote", + "company": "Tubalum", + "employed": true + }, + { + "firstName": "Mills", + "lastName": "Turner", + "company": "Recritube", + "employed": false + }, + { + "firstName": "Lynch", + "lastName": "Wilkins", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Marisa", + "lastName": "Donovan", + "company": "Duflex", + "employed": true + }, + { + "firstName": "Allie", + "lastName": "Castro", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Emily", + "lastName": "Kirk", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Dunlap", + "lastName": "Elliott", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Cash", + "lastName": "Vargas", + "company": "Calcula", + "employed": true + }, + { + "firstName": "Wooten", + "lastName": "Kirkland", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Pate", + "lastName": "Barnett", + "company": "Golistic", + "employed": false + }, + { + "firstName": "Merritt", + "lastName": "Clark", + "company": "Emtrac", + "employed": true + }, + { + "firstName": "Lopez", + "lastName": "Maddox", + "company": "Kongle", + "employed": true + }, + { + "firstName": "Santana", + "lastName": "Hays", + "company": "Unia", + "employed": true + }, + { + "firstName": "Cotton", + "lastName": "Franklin", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Lucille", + "lastName": "Stone", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Hester", + "lastName": "Charles", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Johns", + "lastName": "Lang", + "company": "Zillidium", + "employed": false + }, + { + "firstName": "Morse", + "lastName": "Huffman", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Hull", + "lastName": "Frazier", + "company": "Mondicil", + "employed": true + }, + { + "firstName": "Larson", + "lastName": "Ramirez", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Chris", + "lastName": "Alston", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Madeline", + "lastName": "Church", + "company": "Panzent", + "employed": false + }, + { + "firstName": "Riley", + "lastName": "Morin", + "company": "Jasper", + "employed": false + }, + { + "firstName": "Greer", + "lastName": "Clements", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Frieda", + "lastName": "Nieves", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Knowles", + "lastName": "Hoffman", + "company": "Ozean", + "employed": false + }, + { + "firstName": "Blevins", + "lastName": "Kaufman", + "company": "Gink", + "employed": true + }, + { + "firstName": "Alston", + "lastName": "Hickman", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Mara", + "lastName": "Carpenter", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Ortega", + "lastName": "Giles", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Leanna", + "lastName": "Knapp", + "company": "Interfind", + "employed": true + }, + { + "firstName": "Thompson", + "lastName": "Thomas", + "company": "Keengen", + "employed": false + }, + { + "firstName": "Dona", + "lastName": "Mcclain", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Fletcher", + "lastName": "Hendricks", + "company": "Mantrix", + "employed": true + }, + { + "firstName": "Giles", + "lastName": "Hooper", + "company": "Circum", + "employed": false + }, + { + "firstName": "Zamora", + "lastName": "Contreras", + "company": "Zanilla", + "employed": true + }, + { + "firstName": "Fran", + "lastName": "Clarke", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Leila", + "lastName": "Rhodes", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Frederick", + "lastName": "Haley", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Holly", + "lastName": "Cortez", + "company": "Comstruct", + "employed": true + }, + { + "firstName": "Anita", + "lastName": "Becker", + "company": "Rodemco", + "employed": true + }, + { + "firstName": "Earline", + "lastName": "Bradshaw", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Kerr", + "lastName": "Andrews", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Leigh", + "lastName": "Hester", + "company": "Atomica", + "employed": false + }, + { + "firstName": "Bauer", + "lastName": "Reyes", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Bowman", + "lastName": "French", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Judith", + "lastName": "Gray", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Huff", + "lastName": "Coleman", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "Ratliff", + "lastName": "Valdez", + "company": "Immunics", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Neal", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Solomon", + "company": "Songlines", + "employed": true + }, + { + "firstName": "Morin", + "lastName": "Pope", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Kari", + "lastName": "Davis", + "company": "Biflex", + "employed": true + }, + { + "firstName": "Koch", + "lastName": "Hunt", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Vaughan", + "lastName": "Nunez", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Casey", + "lastName": "Miller", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Eleanor", + "lastName": "Klein", + "company": "Injoy", + "employed": false + }, + { + "firstName": "Brenda", + "lastName": "Lucas", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Murphy", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Louisa", + "lastName": "Mason", + "company": "Inrt", + "employed": true + }, + { + "firstName": "Sarah", + "lastName": "Bowen", + "company": "Translink", + "employed": true + }, + { + "firstName": "Douglas", + "lastName": "Gay", + "company": "Ovation", + "employed": true + }, + { + "firstName": "Diann", + "lastName": "Crawford", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Maria", + "lastName": "Odom", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Annmarie", + "lastName": "Carlson", + "company": "Aquafire", + "employed": false + }, + { + "firstName": "Weaver", + "lastName": "Whitaker", + "company": "Ziore", + "employed": false + }, + { + "firstName": "Malone", + "lastName": "Baird", + "company": "Indexia", + "employed": false + }, + { + "firstName": "Mable", + "lastName": "Beach", + "company": "Prosely", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Jensen", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Millie", + "lastName": "Cantrell", + "company": "Radiantix", + "employed": true + }, + { + "firstName": "Priscilla", + "lastName": "Miles", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Nellie", + "lastName": "Mcintosh", + "company": "Solaren", + "employed": false + }, + { + "firstName": "Wendy", + "lastName": "Goodwin", + "company": "Xanide", + "employed": true + }, + { + "firstName": "Consuelo", + "lastName": "Pace", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Sherri", + "lastName": "Vazquez", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Gardner", + "lastName": "Parsons", + "company": "Moreganic", + "employed": true + }, + { + "firstName": "Crystal", + "lastName": "Singleton", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Carmela", + "lastName": "Fitzpatrick", + "company": "Skyplex", + "employed": false + }, + { + "firstName": "Howell", + "lastName": "Blanchard", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Finley", + "lastName": "Castillo", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Jeanie", + "lastName": "Steele", + "company": "Atgen", + "employed": false + }, + { + "firstName": "Rosemarie", + "lastName": "Burch", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Burton", + "lastName": "Willis", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Benjamin", + "lastName": "Carter", + "company": "Danja", + "employed": false + }, + { + "firstName": "Parks", + "lastName": "Lyons", + "company": "Navir", + "employed": true + }, + { + "firstName": "Gale", + "lastName": "Reed", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Robles", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Blake", + "lastName": "Todd", + "company": "Manglo", + "employed": false + }, + { + "firstName": "Nielsen", + "lastName": "Watts", + "company": "Liquidoc", + "employed": false + }, + { + "firstName": "Simone", + "lastName": "Arnold", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Lilly", + "lastName": "Melendez", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Trevino", + "company": "Rodeology", + "employed": false + }, + { + "firstName": "May", + "lastName": "Moses", + "company": "Fitcore", + "employed": false + }, + { + "firstName": "Holman", + "lastName": "Mullins", + "company": "Quility", + "employed": true + }, + { + "firstName": "Earnestine", + "lastName": "Avery", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Violet", + "lastName": "Evans", + "company": "Gronk", + "employed": true + }, + { + "firstName": "Rosario", + "lastName": "Cunningham", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Rasmussen", + "lastName": "Brennan", + "company": "Exovent", + "employed": false + }, + { + "firstName": "Josie", + "lastName": "Watson", + "company": "Frenex", + "employed": true + }, + { + "firstName": "Pamela", + "lastName": "Wells", + "company": "Yurture", + "employed": true + }, + { + "firstName": "Keith", + "lastName": "Luna", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Sims", + "lastName": "Francis", + "company": "Colaire", + "employed": true + }, + { + "firstName": "Teri", + "lastName": "Lamb", + "company": "Zytrax", + "employed": true + }, + { + "firstName": "Susanna", + "lastName": "Meyers", + "company": "Verbus", + "employed": false + }, + { + "firstName": "Hall", + "lastName": "Mckee", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Kelli", + "lastName": "Franco", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Jacobs", + "lastName": "Hebert", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Berg", + "lastName": "Byers", + "company": "Globoil", + "employed": false + }, + { + "firstName": "Whitehead", + "lastName": "Harrington", + "company": "Exoswitch", + "employed": true + }, + { + "firstName": "Beatriz", + "lastName": "Morrow", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Janna", + "lastName": "Greer", + "company": "Kangle", + "employed": false + }, + { + "firstName": "Leanne", + "lastName": "Barlow", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Pacheco", + "lastName": "Sharp", + "company": "Avit", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Santana", + "company": "Datacator", + "employed": true + }, + { + "firstName": "Villarreal", + "lastName": "Levine", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Oneil", + "lastName": "Robinson", + "company": "Imkan", + "employed": true + }, + { + "firstName": "Mejia", + "lastName": "Chang", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "Vincent", + "lastName": "Clemons", + "company": "Centice", + "employed": false + }, + { + "firstName": "Annabelle", + "lastName": "Gentry", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Diaz", + "lastName": "Lott", + "company": "Columella", + "employed": false + }, + { + "firstName": "Hammond", + "lastName": "Carr", + "company": "Isis", + "employed": false + }, + { + "firstName": "Merle", + "lastName": "Dunlap", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Irma", + "lastName": "Reynolds", + "company": "Icology", + "employed": false + }, + { + "firstName": "Joan", + "lastName": "Jordan", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Sweet", + "lastName": "Sims", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Eloise", + "lastName": "Mcmillan", + "company": "Emtrak", + "employed": true + }, + { + "firstName": "Maddox", + "lastName": "Torres", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Adriana", + "lastName": "Scott", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Lou", + "lastName": "Schultz", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Alyssa", + "lastName": "Armstrong", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Jeanne", + "lastName": "Pacheco", + "company": "Wrapture", + "employed": true + }, + { + "firstName": "Velazquez", + "lastName": "Fisher", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Glenn", + "lastName": "Hines", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Callahan", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Virgie", + "lastName": "Cook", + "company": "Qimonk", + "employed": true + }, + { + "firstName": "Holmes", + "lastName": "Richard", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Antonia", + "lastName": "Bailey", + "company": "Quarmony", + "employed": true + }, + { + "firstName": "Chan", + "lastName": "Bishop", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Emerson", + "lastName": "Gilbert", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Kristie", + "lastName": "Anthony", + "company": "Andershun", + "employed": true + }, + { + "firstName": "Susan", + "lastName": "Soto", + "company": "Automon", + "employed": false + }, + { + "firstName": "Hale", + "lastName": "Dixon", + "company": "Firewax", + "employed": false + }, + { + "firstName": "Pauline", + "lastName": "Randall", + "company": "Telpod", + "employed": false + }, + { + "firstName": "Blair", + "lastName": "Carrillo", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Williams", + "lastName": "Perez", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Sonia", + "lastName": "Aguilar", + "company": "Eclipto", + "employed": true + }, + { + "firstName": "Trujillo", + "lastName": "Bonner", + "company": "Sunclipse", + "employed": false + }, + { + "firstName": "Obrien", + "lastName": "Vaughn", + "company": "Comtours", + "employed": true + }, + { + "firstName": "Fitzpatrick", + "lastName": "Morton", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Grace", + "lastName": "Cherry", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Audra", + "lastName": "Hughes", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Campbell", + "lastName": "Sparks", + "company": "Xelegyl", + "employed": false + }, + { + "firstName": "Hardin", + "lastName": "Walker", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Kasey", + "lastName": "Fields", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Gonzalez", + "lastName": "Mendez", + "company": "Netropic", + "employed": false + }, + { + "firstName": "Brown", + "lastName": "Griffith", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Julie", + "lastName": "Sutton", + "company": "Geoform", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Burnett", + "company": "Bunga", + "employed": true + }, + { + "firstName": "Freeman", + "lastName": "Poole", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Jewell", + "lastName": "Humphrey", + "company": "Bedder", + "employed": true + }, + { + "firstName": "Araceli", + "lastName": "Harper", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Haney", + "lastName": "Nelson", + "company": "Zolarity", + "employed": true + }, + { + "firstName": "Ruthie", + "lastName": "Foley", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Sybil", + "lastName": "Guthrie", + "company": "Vortexaco", + "employed": true + }, + { + "firstName": "Bonner", + "lastName": "Howard", + "company": "Visualix", + "employed": true + }, + { + "firstName": "Lancaster", + "lastName": "Mclean", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Janice", + "lastName": "Sexton", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Dee", + "lastName": "Stafford", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Lang", + "lastName": "Rosario", + "company": "Vertide", + "employed": false + }, + { + "firstName": "Collier", + "lastName": "Meadows", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Schwartz", + "lastName": "Salazar", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Dawson", + "lastName": "Glass", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Oconnor", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Debora", + "lastName": "Obrien", + "company": "Volax", + "employed": false + }, + { + "firstName": "Odonnell", + "lastName": "Gallagher", + "company": "Intrawear", + "employed": false + }, + { + "firstName": "Hannah", + "lastName": "Gibson", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Angeline", + "lastName": "Lloyd", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Brianna", + "lastName": "Sykes", + "company": "Virxo", + "employed": true + }, + { + "firstName": "Hansen", + "lastName": "Alexander", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Annette", + "lastName": "Dawson", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Juliette", + "lastName": "Mcclure", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Mandy", + "lastName": "Norris", + "company": "Cedward", + "employed": false + }, + { + "firstName": "Mooney", + "lastName": "Branch", + "company": "Securia", + "employed": false + }, + { + "firstName": "Cathryn", + "lastName": "Avila", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Peters", + "lastName": "Fox", + "company": "Undertap", + "employed": false + }, + { + "firstName": "Ramona", + "lastName": "Villarreal", + "company": "Turnling", + "employed": true + }, + { + "firstName": "Jennifer", + "lastName": "Buchanan", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Nancy", + "lastName": "Shaffer", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Harrington", + "lastName": "Atkinson", + "company": "Empirica", + "employed": true + }, + { + "firstName": "Patel", + "lastName": "Ryan", + "company": "Rubadub", + "employed": false + }, + { + "firstName": "Horton", + "lastName": "House", + "company": "Zerbina", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Zamora", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Holland", + "company": "Viagrand", + "employed": true + }, + { + "firstName": "Dennis", + "lastName": "Rivera", + "company": "Corporana", + "employed": false + }, + { + "firstName": "Blankenship", + "lastName": "Lynch", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Yesenia", + "lastName": "Lawrence", + "company": "Bisba", + "employed": false + }, + { + "firstName": "Talley", + "lastName": "Allison", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Adams", + "lastName": "Knox", + "company": "Arctiq", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Nixon", + "company": "Portica", + "employed": false + }, + { + "firstName": "Holloway", + "lastName": "Stephens", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Hayden", + "lastName": "Daniel", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Edna", + "lastName": "Dean", + "company": "Talae", + "employed": true + }, + { + "firstName": "Shaw", + "lastName": "Williamson", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Lena", + "lastName": "Nguyen", + "company": "Architax", + "employed": true + }, + { + "firstName": "Powell", + "lastName": "Medina", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Santiago", + "lastName": "Dodson", + "company": "Zentility", + "employed": true + }, + { + "firstName": "Madelyn", + "lastName": "Middleton", + "company": "Veraq", + "employed": false + }, + { + "firstName": "Knight", + "lastName": "Dillon", + "company": "Lingoage", + "employed": true + }, + { + "firstName": "Margaret", + "lastName": "Frederick", + "company": "Remold", + "employed": true + }, + { + "firstName": "Marianne", + "lastName": "Burton", + "company": "Progenex", + "employed": false + }, + { + "firstName": "Cooley", + "lastName": "Ingram", + "company": "Techmania", + "employed": true + }, + { + "firstName": "William", + "lastName": "Gordon", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Kent", + "lastName": "Bond", + "company": "Cemention", + "employed": true + }, + { + "firstName": "Washington", + "lastName": "Mccray", + "company": "Isopop", + "employed": true + }, + { + "firstName": "Dudley", + "lastName": "Leon", + "company": "Hyplex", + "employed": false + }, + { + "firstName": "Michele", + "lastName": "Warren", + "company": "Cinesanct", + "employed": false + }, + { + "firstName": "Desiree", + "lastName": "Rodgers", + "company": "Ohmnet", + "employed": false + }, + { + "firstName": "Warren", + "lastName": "Russo", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Brandie", + "lastName": "Chan", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Effie", + "lastName": "Espinoza", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Vicki", + "lastName": "Fleming", + "company": "Franscene", + "employed": true + }, + { + "firstName": "Richards", + "lastName": "Lopez", + "company": "Zytrek", + "employed": false + }, + { + "firstName": "Lindsay", + "lastName": "Brooks", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Chaney", + "lastName": "Spencer", + "company": "Maximind", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Conrad", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Bryan", + "lastName": "Nolan", + "company": "Matrixity", + "employed": true + }, + { + "firstName": "Amparo", + "lastName": "Nielsen", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Rivera", + "lastName": "Collins", + "company": "Krag", + "employed": false + }, + { + "firstName": "Margery", + "lastName": "Dotson", + "company": "Frosnex", + "employed": false + }, + { + "firstName": "Austin", + "lastName": "Black", + "company": "Entality", + "employed": true + }, + { + "firstName": "Lessie", + "lastName": "Hogan", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Guerrero", + "lastName": "Guerrero", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Marion", + "lastName": "Conway", + "company": "Inear", + "employed": false + }, + { + "firstName": "Florine", + "lastName": "Wall", + "company": "Repetwire", + "employed": false + }, + { + "firstName": "Bridget", + "lastName": "Vasquez", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Colleen", + "lastName": "Barrett", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Perkins", + "company": "Exostream", + "employed": true + }, + { + "firstName": "Castaneda", + "lastName": "Adkins", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Hyde", + "lastName": "Cohen", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Blackburn", + "lastName": "Colon", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Floyd", + "lastName": "Marks", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Jill", + "lastName": "Young", + "company": "Bezal", + "employed": true + }, + { + "firstName": "Deann", + "lastName": "Manning", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Frye", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Acosta", + "lastName": "England", + "company": "Ecrater", + "employed": false + }, + { + "firstName": "Neva", + "lastName": "Christensen", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Jo", + "lastName": "Mathews", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Booker", + "lastName": "Farmer", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Janet", + "lastName": "Wiggins", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Boyle", + "lastName": "Benson", + "company": "Eventex", + "employed": false + }, + { + "firstName": "Ward", + "lastName": "Bright", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Henderson", + "company": "Ziggles", + "employed": false + }, + { + "firstName": "Noreen", + "lastName": "Wynn", + "company": "Entogrok", + "employed": false + }, + { + "firstName": "Graham", + "lastName": "Deleon", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Angela", + "lastName": "Tran", + "company": "Scentric", + "employed": true + }, + { + "firstName": "Mallory", + "lastName": "Chapman", + "company": "Geekwagon", + "employed": false + }, + { + "firstName": "Ballard", + "lastName": "Ayala", + "company": "Tasmania", + "employed": false + }, + { + "firstName": "Singleton", + "lastName": "Bradford", + "company": "Extro", + "employed": false + }, + { + "firstName": "Arline", + "lastName": "Gomez", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Mattie", + "lastName": "Simmons", + "company": "Biospan", + "employed": true + }, + { + "firstName": "Marissa", + "lastName": "Baxter", + "company": "Playce", + "employed": false + }, + { + "firstName": "Justice", + "lastName": "Frost", + "company": "Comvoy", + "employed": true + }, + { + "firstName": "Evans", + "lastName": "Navarro", + "company": "Hinway", + "employed": true + }, + { + "firstName": "Stone", + "lastName": "Carney", + "company": "Olympix", + "employed": true + }, + { + "firstName": "Lila", + "lastName": "Hicks", + "company": "Locazone", + "employed": false + }, + { + "firstName": "Matthews", + "lastName": "Booker", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Elena", + "lastName": "Rodriguez", + "company": "Dogtown", + "employed": true + }, + { + "firstName": "Callie", + "lastName": "Spears", + "company": "Zytrac", + "employed": false + }, + { + "firstName": "Bertie", + "lastName": "Hall", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Mclean", + "lastName": "Salinas", + "company": "Netplax", + "employed": false + }, + { + "firstName": "Fannie", + "lastName": "Mills", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Wells", + "lastName": "Santiago", + "company": "Autograte", + "employed": false + }, + { + "firstName": "Bowers", + "lastName": "Irwin", + "company": "Comfirm", + "employed": true + }, + { + "firstName": "Kirsten", + "lastName": "Moon", + "company": "Neptide", + "employed": true + }, + { + "firstName": "Michael", + "lastName": "Hyde", + "company": "Corecom", + "employed": false + }, + { + "firstName": "Gonzales", + "lastName": "Douglas", + "company": "Synkgen", + "employed": false + }, + { + "firstName": "Thornton", + "lastName": "Barnes", + "company": "Quintity", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Hoover", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Cherry", + "lastName": "Leonard", + "company": "Portaline", + "employed": true + }, + { + "firstName": "Banks", + "lastName": "Mcbride", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Rojas", + "lastName": "Higgins", + "company": "Plasmos", + "employed": false + }, + { + "firstName": "Nina", + "lastName": "Pollard", + "company": "Exotechno", + "employed": true + }, + { + "firstName": "Valencia", + "lastName": "Garza", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Baker", + "lastName": "Davenport", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Gordon", + "lastName": "Mullen", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Fitzgerald", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Lorna", + "lastName": "Larsen", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Elva", + "lastName": "Stark", + "company": "Uneeq", + "employed": false + }, + { + "firstName": "Frost", + "lastName": "Blackwell", + "company": "Phuel", + "employed": false + }, + { + "firstName": "Mccarthy", + "lastName": "Kline", + "company": "Paprikut", + "employed": true + }, + { + "firstName": "Bridges", + "lastName": "Guzman", + "company": "Magnina", + "employed": true + }, + { + "firstName": "Megan", + "lastName": "Sanders", + "company": "Imant", + "employed": false + }, + { + "firstName": "Mcdaniel", + "lastName": "Rowland", + "company": "Martgo", + "employed": true + }, + { + "firstName": "Rachael", + "lastName": "Livingston", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Figueroa", + "company": "Signity", + "employed": false + }, + { + "firstName": "Aisha", + "lastName": "Knowles", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Anthony", + "lastName": "Ramos", + "company": "Zisis", + "employed": true + }, + { + "firstName": "Joy", + "lastName": "Camacho", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Maryellen", + "lastName": "Mcconnell", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Jodie", + "lastName": "Sears", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Rosalinda", + "lastName": "Banks", + "company": "Intradisk", + "employed": false + }, + { + "firstName": "Karina", + "lastName": "Castaneda", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Mckinney", + "company": "Manufact", + "employed": false + }, + { + "firstName": "Twila", + "lastName": "Mosley", + "company": "Pyramax", + "employed": true + }, + { + "firstName": "Lela", + "lastName": "Ross", + "company": "Oulu", + "employed": true + }, + { + "firstName": "Adela", + "lastName": "Williams", + "company": "Comstar", + "employed": true + }, + { + "firstName": "April", + "lastName": "Delacruz", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Kerri", + "lastName": "Delaney", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Leslie", + "lastName": "Mcdowell", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Sanders", + "lastName": "Ratliff", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Gloria", + "lastName": "Gould", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Rasmussen", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Brandi", + "lastName": "Richardson", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Stewart", + "lastName": "Wright", + "company": "Musix", + "employed": false + }, + { + "firstName": "Thomas", + "lastName": "Carver", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Graciela", + "lastName": "Hale", + "company": "Squish", + "employed": false + }, + { + "firstName": "Erica", + "lastName": "Love", + "company": "Gology", + "employed": false + }, + { + "firstName": "Copeland", + "lastName": "Vance", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Earlene", + "lastName": "Malone", + "company": "Comvene", + "employed": false + }, + { + "firstName": "Mavis", + "lastName": "Mckenzie", + "company": "Crustatia", + "employed": true + }, + { + "firstName": "Sharron", + "lastName": "Harding", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Heath", + "lastName": "Lancaster", + "company": "Memora", + "employed": false + }, + { + "firstName": "Russell", + "lastName": "Galloway", + "company": "Opportech", + "employed": false + }, + { + "firstName": "Sandoval", + "lastName": "Oneill", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Randall", + "lastName": "Atkins", + "company": "Zoinage", + "employed": false + }, + { + "firstName": "Mann", + "lastName": "Weaver", + "company": "Uni", + "employed": true + }, + { + "firstName": "Gertrude", + "lastName": "Ballard", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Tameka", + "lastName": "Massey", + "company": "Jetsilk", + "employed": false + }, + { + "firstName": "Kate", + "lastName": "Puckett", + "company": "Datagene", + "employed": false + }, + { + "firstName": "Gilbert", + "lastName": "Ball", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Shelly", + "lastName": "Copeland", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Johnston", + "lastName": "Ortega", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Millicent", + "lastName": "Cline", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Marjorie", + "lastName": "Mcdaniel", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Mercado", + "lastName": "Hahn", + "company": "Isologia", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Shelton", + "company": "Hydrocom", + "employed": true + }, + { + "firstName": "Ball", + "lastName": "Weber", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Patrica", + "lastName": "Albert", + "company": "Fortean", + "employed": true + }, + { + "firstName": "Regina", + "lastName": "Ellison", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Harvey", + "lastName": "Weiss", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Miranda", + "lastName": "Wilcox", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Wiley", + "lastName": "Riddle", + "company": "Fuelton", + "employed": false + }, + { + "firstName": "Oconnor", + "lastName": "Mcleod", + "company": "Printspan", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Chaney", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Lowe", + "lastName": "Rivers", + "company": "Futurize", + "employed": true + }, + { + "firstName": "Fanny", + "lastName": "Merritt", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Cardenas", + "lastName": "Rice", + "company": "Multron", + "employed": true + }, + { + "firstName": "Wilson", + "lastName": "Sullivan", + "company": "Terrago", + "employed": true + }, + { + "firstName": "Randi", + "lastName": "Mitchell", + "company": "Stockpost", + "employed": true + }, + { + "firstName": "Delia", + "lastName": "Flowers", + "company": "Fangold", + "employed": true + }, + { + "firstName": "Rosalyn", + "lastName": "Hammond", + "company": "Quiltigen", + "employed": false + }, + { + "firstName": "Alana", + "lastName": "Munoz", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Maggie", + "lastName": "Pennington", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Michelle", + "lastName": "Preston", + "company": "Combot", + "employed": false + }, + { + "firstName": "Lillie", + "lastName": "Fowler", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Hays", + "lastName": "Whitfield", + "company": "Dymi", + "employed": false + }, + { + "firstName": "Hilda", + "lastName": "Newman", + "company": "Vetron", + "employed": false + }, + { + "firstName": "Herrera", + "lastName": "Larson", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Aline", + "lastName": "Newton", + "company": "Uncorp", + "employed": false + }, + { + "firstName": "Ines", + "lastName": "Griffin", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Ewing", + "lastName": "Powers", + "company": "Opticom", + "employed": false + }, + { + "firstName": "Ester", + "lastName": "Logan", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Macias", + "lastName": "Webster", + "company": "Pivitol", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Velasquez", + "company": "Magnemo", + "employed": false + }, + { + "firstName": "Kristine", + "lastName": "Stanton", + "company": "Waab", + "employed": false + }, + { + "firstName": "Carey", + "lastName": "Riggs", + "company": "Bostonic", + "employed": true + }, + { + "firstName": "Carpenter", + "lastName": "Welch", + "company": "Honotron", + "employed": false + }, + { + "firstName": "Diane", + "lastName": "Best", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Julia", + "lastName": "Randolph", + "company": "Netur", + "employed": false + }, + { + "firstName": "Shauna", + "lastName": "Clay", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Hodge", + "lastName": "Vincent", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Fields", + "lastName": "Snyder", + "company": "Terragen", + "employed": false + }, + { + "firstName": "Lacey", + "lastName": "Grant", + "company": "Limage", + "employed": true + }, + { + "firstName": "Janell", + "lastName": "Alford", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Anderson", + "lastName": "Barron", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Bright", + "lastName": "Hayden", + "company": "Jamnation", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Herrera", + "company": "Zytrex", + "employed": false + }, + { + "firstName": "Henry", + "lastName": "Buckner", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Cummings", + "lastName": "Workman", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Corinne", + "lastName": "Gill", + "company": "Qot", + "employed": false + }, + { + "firstName": "Hoffman", + "lastName": "Summers", + "company": "Elemantra", + "employed": true + }, + { + "firstName": "Travis", + "lastName": "Ford", + "company": "Darwinium", + "employed": false + }, + { + "firstName": "Rene", + "lastName": "Harris", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Clarke", + "lastName": "Savage", + "company": "Gallaxia", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Bryant", + "company": "Updat", + "employed": false + }, + { + "firstName": "Watkins", + "lastName": "Walters", + "company": "Acumentor", + "employed": true + }, + { + "firstName": "Cline", + "lastName": "Michael", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Ayers", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Sharlene", + "lastName": "Barrera", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Holden", + "lastName": "Mcguire", + "company": "Optyk", + "employed": true + }, + { + "firstName": "Kimberly", + "lastName": "Rocha", + "company": "Optique", + "employed": false + }, + { + "firstName": "Catherine", + "lastName": "Caldwell", + "company": "Codax", + "employed": false + }, + { + "firstName": "Marshall", + "lastName": "Maxwell", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Bryant", + "lastName": "Miranda", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Leonor", + "lastName": "Mcfadden", + "company": "Soprano", + "employed": true + }, + { + "firstName": "Lewis", + "lastName": "Moore", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Mercedes", + "lastName": "Bean", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Mueller", + "lastName": "Burgess", + "company": "Ovium", + "employed": false + }, + { + "firstName": "Sheila", + "lastName": "Bentley", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Tanner", + "lastName": "Mcmahon", + "company": "Austex", + "employed": false + }, + { + "firstName": "Jewel", + "lastName": "Horne", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Murphy", + "lastName": "Hayes", + "company": "Acium", + "employed": false + }, + { + "firstName": "Rosanna", + "lastName": "Lawson", + "company": "Gorganic", + "employed": false + }, + { + "firstName": "Cooper", + "lastName": "Justice", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Huffman", + "lastName": "Potter", + "company": "Amtas", + "employed": false + }, + { + "firstName": "Phyllis", + "lastName": "Valentine", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Diaz", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Sadie", + "lastName": "Mayo", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Ferrell", + "lastName": "Carey", + "company": "Minga", + "employed": false + }, + { + "firstName": "Barron", + "lastName": "Simon", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Byrd", + "lastName": "Dyer", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Zelma", + "lastName": "Matthews", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Mcleod", + "lastName": "Levy", + "company": "Irack", + "employed": true + }, + { + "firstName": "Jennie", + "lastName": "Kramer", + "company": "Zboo", + "employed": true + }, + { + "firstName": "Woods", + "lastName": "Herman", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Simpson", + "lastName": "Moran", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Eva", + "lastName": "Rush", + "company": "Buzzmaker", + "employed": false + }, + { + "firstName": "Johanna", + "lastName": "Grimes", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Compton", + "company": "Centree", + "employed": true + }, + { + "firstName": "Marks", + "lastName": "Gallegos", + "company": "Cytrak", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Maynard", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Washington", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Burke", + "lastName": "Acevedo", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Ayers", + "lastName": "Mathis", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Ochoa", + "lastName": "Mcdonald", + "company": "Junipoor", + "employed": false + }, + { + "firstName": "Pollard", + "lastName": "Guy", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Maxwell", + "lastName": "Cole", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Corine", + "lastName": "Carson", + "company": "Fuelworks", + "employed": false + }, + { + "firstName": "Peck", + "lastName": "Strickland", + "company": "Zork", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Jackson", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Hood", + "lastName": "Garrett", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Reilly", + "lastName": "Sandoval", + "company": "Techade", + "employed": false + }, + { + "firstName": "Alexander", + "lastName": "Gates", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Barber", + "lastName": "Pruitt", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Knapp", + "lastName": "Brock", + "company": "Envire", + "employed": true + }, + { + "firstName": "Jeri", + "lastName": "Wyatt", + "company": "Zuvy", + "employed": true + }, + { + "firstName": "Juarez", + "lastName": "Mccarthy", + "company": "Kongene", + "employed": true + }, + { + "firstName": "Forbes", + "lastName": "Hopper", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Reyes", + "lastName": "Kinney", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Chelsea", + "lastName": "Warner", + "company": "Vendblend", + "employed": true + }, + { + "firstName": "Walton", + "lastName": "Dennis", + "company": "Rooforia", + "employed": true + }, + { + "firstName": "Cunningham", + "lastName": "Patel", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Pace", + "lastName": "Blankenship", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Genevieve", + "lastName": "Decker", + "company": "Gluid", + "employed": false + }, + { + "firstName": "Dina", + "lastName": "Ortiz", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Tran", + "lastName": "Richards", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Elvira", + "lastName": "Myers", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Reyna", + "lastName": "Buck", + "company": "Kage", + "employed": true + }, + { + "firstName": "Phoebe", + "lastName": "English", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Ford", + "lastName": "Cameron", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Tricia", + "lastName": "Brewer", + "company": "Vinch", + "employed": true + }, + { + "firstName": "Ware", + "lastName": "West", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Miller", + "lastName": "Duffy", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Glass", + "lastName": "Anderson", + "company": "Zizzle", + "employed": false + }, + { + "firstName": "Rhodes", + "lastName": "Lewis", + "company": "Ronbert", + "employed": false + }, + { + "firstName": "Walls", + "lastName": "Gardner", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Pat", + "lastName": "Juarez", + "company": "Suremax", + "employed": true + }, + { + "firstName": "Hatfield", + "lastName": "Huff", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Marla", + "lastName": "Bray", + "company": "Assistia", + "employed": false + }, + { + "firstName": "Deborah", + "lastName": "Doyle", + "company": "Kog", + "employed": false + }, + { + "firstName": "Alba", + "lastName": "Mack", + "company": "Teraprene", + "employed": false + }, + { + "firstName": "Josephine", + "lastName": "Craft", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Middleton", + "lastName": "Hutchinson", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Jaime", + "lastName": "Byrd", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Montgomery", + "lastName": "Kidd", + "company": "Oronoko", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Parker", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Clarissa", + "lastName": "Nash", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Hicks", + "lastName": "Page", + "company": "Concility", + "employed": true + }, + { + "firstName": "Prince", + "lastName": "Rojas", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Franco", + "lastName": "Kennedy", + "company": "Suretech", + "employed": false + }, + { + "firstName": "Beverly", + "lastName": "Short", + "company": "Elpro", + "employed": false + }, + { + "firstName": "Norris", + "lastName": "Case", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Clarice", + "lastName": "Tanner", + "company": "Pyrami", + "employed": true + }, + { + "firstName": "Rich", + "lastName": "Barber", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Jody", + "lastName": "Russell", + "company": "Austech", + "employed": true + }, + { + "firstName": "Reese", + "lastName": "Sherman", + "company": "Isonus", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Holden", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Maryann", + "lastName": "Leblanc", + "company": "Xth", + "employed": false + }, + { + "firstName": "Amber", + "lastName": "Sargent", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Ellen", + "lastName": "Adams", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Theresa", + "lastName": "Cross", + "company": "Zoxy", + "employed": true + }, + { + "firstName": "Lindsay", + "lastName": "Henson", + "company": "Comcur", + "employed": false + }, + { + "firstName": "Nell", + "lastName": "Ware", + "company": "Comdom", + "employed": false + }, + { + "firstName": "Tabitha", + "lastName": "Morrison", + "company": "Zidox", + "employed": false + }, + { + "firstName": "Larsen", + "lastName": "Parks", + "company": "Snips", + "employed": true + }, + { + "firstName": "Vega", + "lastName": "Vang", + "company": "Zanity", + "employed": false + }, + { + "firstName": "Lisa", + "lastName": "Tyler", + "company": "Aquacine", + "employed": true + }, + { + "firstName": "Beasley", + "lastName": "Rose", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Alison", + "lastName": "Underwood", + "company": "Fibrodyne", + "employed": true + }, + { + "firstName": "Opal", + "lastName": "Roy", + "company": "Zoid", + "employed": false + }, + { + "firstName": "Natalie", + "lastName": "Perry", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Livingston", + "lastName": "Gibbs", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Marlene", + "lastName": "Morgan", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Jacquelyn", + "lastName": "Swanson", + "company": "Xymonk", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Lindsey", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Georgina", + "lastName": "Cabrera", + "company": "Skybold", + "employed": true + }, + { + "firstName": "Keller", + "lastName": "Houston", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Robyn", + "lastName": "Holder", + "company": "Realysis", + "employed": false + }, + { + "firstName": "Perez", + "lastName": "Sanchez", + "company": "Spacewax", + "employed": false + }, + { + "firstName": "Kim", + "lastName": "Wooten", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Gates", + "lastName": "Mercer", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Felicia", + "lastName": "Taylor", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Rosa", + "lastName": "Oneal", + "company": "Singavera", + "employed": false + }, + { + "firstName": "Clare", + "lastName": "Mcgee", + "company": "Apexia", + "employed": false + }, + { + "firstName": "Boone", + "lastName": "Raymond", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Leona", + "lastName": "Benton", + "company": "Ersum", + "employed": true + }, + { + "firstName": "Barnes", + "lastName": "Sloan", + "company": "Dancity", + "employed": false + }, + { + "firstName": "English", + "lastName": "Porter", + "company": "Nitracyr", + "employed": true + }, + { + "firstName": "Cobb", + "lastName": "Haynes", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Cheryl", + "lastName": "Rogers", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Odessa", + "lastName": "Campos", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Cruz", + "lastName": "Crane", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Velez", + "lastName": "Waters", + "company": "Zipak", + "employed": false + }, + { + "firstName": "Leah", + "lastName": "Le", + "company": "Urbanshee", + "employed": false + }, + { + "firstName": "Stark", + "lastName": "Barr", + "company": "Aquazure", + "employed": false + }, + { + "firstName": "Griffin", + "lastName": "Graham", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Brooks", + "lastName": "Butler", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Minerva", + "lastName": "Osborne", + "company": "Geoforma", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Martin", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Ronda", + "lastName": "Daniels", + "company": "Viocular", + "employed": false + }, + { + "firstName": "Montoya", + "lastName": "Casey", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Deana", + "lastName": "Romero", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Tracey", + "lastName": "Barton", + "company": "Velos", + "employed": true + }, + { + "firstName": "Welch", + "lastName": "Mayer", + "company": "Cogentry", + "employed": false + }, + { + "firstName": "Dodson", + "lastName": "Mccall", + "company": "Harmoney", + "employed": false + }, + { + "firstName": "Casandra", + "lastName": "Fuller", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Margo", + "lastName": "Lane", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Martin", + "lastName": "Huber", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Sears", + "lastName": "Simpson", + "company": "Mangelica", + "employed": false + }, + { + "firstName": "Debra", + "lastName": "Terrell", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Porter", + "lastName": "Gonzalez", + "company": "Zilodyne", + "employed": false + }, + { + "firstName": "Buckley", + "lastName": "Hess", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Walsh", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Lora", + "lastName": "Rios", + "company": "Coash", + "employed": true + }, + { + "firstName": "Nadine", + "lastName": "Pratt", + "company": "Zaphire", + "employed": false + }, + { + "firstName": "Wilkinson", + "lastName": "Zimmerman", + "company": "Bleeko", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Russell", + "company": "Apex", + "employed": false + }, + { + "firstName": "Francesca", + "lastName": "Randolph", + "company": "Amril", + "employed": false + }, + { + "firstName": "Sullivan", + "lastName": "Bradshaw", + "company": "Acium", + "employed": false + }, + { + "firstName": "Lucy", + "lastName": "Melendez", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Addie", + "lastName": "Nunez", + "company": "Corporana", + "employed": false + }, + { + "firstName": "Logan", + "lastName": "Hart", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Leona", + "lastName": "Sexton", + "company": "Zilla", + "employed": false + }, + { + "firstName": "Duncan", + "lastName": "Sykes", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Flynn", + "lastName": "Gonzales", + "company": "Xumonk", + "employed": true + }, + { + "firstName": "Jayne", + "lastName": "Kirby", + "company": "Jetsilk", + "employed": true + }, + { + "firstName": "Kelli", + "lastName": "Bradley", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Esmeralda", + "lastName": "Durham", + "company": "Assistix", + "employed": false + }, + { + "firstName": "Teresa", + "lastName": "Hopkins", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Bradford", + "lastName": "Campbell", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Higgins", + "lastName": "Obrien", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Annmarie", + "lastName": "Mueller", + "company": "Imant", + "employed": true + }, + { + "firstName": "Massey", + "lastName": "Crane", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Ina", + "lastName": "Camacho", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Leach", + "lastName": "Pope", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Brandie", + "lastName": "Walker", + "company": "Ohmnet", + "employed": false + }, + { + "firstName": "Gabriela", + "lastName": "Foster", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Montoya", + "lastName": "Christian", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Mcgee", + "company": "Aquacine", + "employed": true + }, + { + "firstName": "Annette", + "lastName": "Conway", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Cassandra", + "lastName": "Sandoval", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Lang", + "lastName": "Vincent", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Cathleen", + "lastName": "Porter", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Davis", + "lastName": "Blackwell", + "company": "Retrack", + "employed": true + }, + { + "firstName": "Mary", + "lastName": "Calhoun", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Annie", + "lastName": "Holmes", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Woods", + "lastName": "Wilder", + "company": "Quantalia", + "employed": false + }, + { + "firstName": "Beulah", + "lastName": "Farmer", + "company": "Eargo", + "employed": true + }, + { + "firstName": "Lawrence", + "lastName": "Beard", + "company": "Hometown", + "employed": false + }, + { + "firstName": "Ashley", + "lastName": "Chaney", + "company": "Kinetica", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Holman", + "company": "Primordia", + "employed": false + }, + { + "firstName": "Aline", + "lastName": "Dillard", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Petersen", + "lastName": "Estrada", + "company": "Soprano", + "employed": true + }, + { + "firstName": "Margaret", + "lastName": "Kramer", + "company": "Arctiq", + "employed": false + }, + { + "firstName": "Tara", + "lastName": "Gamble", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Rhea", + "lastName": "Harris", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Harris", + "lastName": "Sellers", + "company": "Uberlux", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Williams", + "company": "Spacewax", + "employed": true + }, + { + "firstName": "Angelina", + "lastName": "Sutton", + "company": "Acusage", + "employed": false + }, + { + "firstName": "Carrillo", + "lastName": "Santos", + "company": "Eyeris", + "employed": false + }, + { + "firstName": "Bullock", + "lastName": "Mclean", + "company": "Snacktion", + "employed": false + }, + { + "firstName": "Bridgett", + "lastName": "Bryan", + "company": "Turnling", + "employed": true + }, + { + "firstName": "Harper", + "lastName": "Koch", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "Madelyn", + "lastName": "Calderon", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Callahan", + "lastName": "Church", + "company": "Remotion", + "employed": true + }, + { + "firstName": "Neva", + "lastName": "Hendrix", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Bobbi", + "lastName": "Stout", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Dillard", + "lastName": "Padilla", + "company": "Synkgen", + "employed": true + }, + { + "firstName": "Roberson", + "lastName": "Rush", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Spears", + "lastName": "Mckinney", + "company": "Oatfarm", + "employed": false + }, + { + "firstName": "Glenn", + "lastName": "Cleveland", + "company": "Kozgene", + "employed": true + }, + { + "firstName": "Ewing", + "lastName": "Contreras", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Lolita", + "lastName": "Hardy", + "company": "Accruex", + "employed": false + }, + { + "firstName": "Collier", + "lastName": "Patton", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Corina", + "lastName": "Aguilar", + "company": "Xanide", + "employed": true + }, + { + "firstName": "Francis", + "lastName": "Hester", + "company": "Kiggle", + "employed": false + }, + { + "firstName": "Cantu", + "lastName": "Mitchell", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Hampton", + "lastName": "Donovan", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Tonya", + "lastName": "King", + "company": "Imkan", + "employed": true + }, + { + "firstName": "Beard", + "lastName": "Craig", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Leanna", + "lastName": "Griffin", + "company": "Buzzmaker", + "employed": false + }, + { + "firstName": "Good", + "lastName": "Goodwin", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Lauren", + "lastName": "Ellison", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Marisa", + "lastName": "Vasquez", + "company": "Ronbert", + "employed": false + }, + { + "firstName": "Thomas", + "lastName": "Flowers", + "company": "Rodemco", + "employed": false + }, + { + "firstName": "Merrill", + "lastName": "Henry", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Potts", + "lastName": "Page", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Burton", + "lastName": "Delgado", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Marks", + "lastName": "Mccormick", + "company": "Venoflex", + "employed": true + }, + { + "firstName": "Anne", + "lastName": "Weeks", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Alyssa", + "lastName": "Galloway", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Blanche", + "lastName": "Summers", + "company": "Plasto", + "employed": true + }, + { + "firstName": "Serena", + "lastName": "Hernandez", + "company": "Olucore", + "employed": true + }, + { + "firstName": "Grace", + "lastName": "Carson", + "company": "Endipine", + "employed": true + }, + { + "firstName": "Jacqueline", + "lastName": "Murray", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Mcdonald", + "lastName": "Burke", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Karina", + "lastName": "Humphrey", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Moore", + "lastName": "William", + "company": "Idetica", + "employed": true + }, + { + "firstName": "York", + "lastName": "Ramos", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Sellers", + "lastName": "Cameron", + "company": "Printspan", + "employed": false + }, + { + "firstName": "Holt", + "lastName": "Kennedy", + "company": "Utara", + "employed": false + }, + { + "firstName": "Leigh", + "lastName": "Puckett", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Christine", + "lastName": "Callahan", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Williams", + "lastName": "Hardin", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Lindsay", + "lastName": "Stafford", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Valentine", + "lastName": "Hanson", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Frank", + "lastName": "Hunt", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Patrick", + "lastName": "Holloway", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Howard", + "lastName": "Watkins", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Tammie", + "lastName": "Franco", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Miller", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Nettie", + "lastName": "Dalton", + "company": "Quilk", + "employed": true + }, + { + "firstName": "Meghan", + "lastName": "Garcia", + "company": "Phormula", + "employed": false + }, + { + "firstName": "Alisha", + "lastName": "Dodson", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Love", + "lastName": "Valenzuela", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Kari", + "lastName": "Sheppard", + "company": "Rocklogic", + "employed": true + }, + { + "firstName": "Noel", + "lastName": "Rich", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Fern", + "lastName": "Haney", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Kellie", + "lastName": "Reese", + "company": "Wrapture", + "employed": true + }, + { + "firstName": "Denise", + "lastName": "Kelley", + "company": "Zytrek", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Savage", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Stewart", + "lastName": "Hickman", + "company": "Plasmox", + "employed": false + }, + { + "firstName": "Foley", + "lastName": "Sampson", + "company": "Zensor", + "employed": false + }, + { + "firstName": "Maude", + "lastName": "Nielsen", + "company": "Slofast", + "employed": true + }, + { + "firstName": "Madge", + "lastName": "Butler", + "company": "Turnabout", + "employed": false + }, + { + "firstName": "Aguirre", + "lastName": "Mercer", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Sweeney", + "lastName": "Alston", + "company": "Avit", + "employed": false + }, + { + "firstName": "Miles", + "lastName": "Rosa", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Decker", + "lastName": "Buck", + "company": "Digigen", + "employed": false + }, + { + "firstName": "Elnora", + "lastName": "Jennings", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Villarreal", + "lastName": "Romero", + "company": "Everest", + "employed": false + }, + { + "firstName": "Greer", + "lastName": "Rios", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Marian", + "lastName": "Wood", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Ruby", + "lastName": "Dunn", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Joseph", + "lastName": "Harmon", + "company": "Dognosis", + "employed": true + }, + { + "firstName": "Duran", + "lastName": "Farrell", + "company": "Bugsall", + "employed": false + }, + { + "firstName": "Geraldine", + "lastName": "Parker", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Jefferson", + "lastName": "Lang", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Ortega", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Whitehead", + "lastName": "Dillon", + "company": "Xyqag", + "employed": false + }, + { + "firstName": "Chapman", + "lastName": "Albert", + "company": "Illumity", + "employed": false + }, + { + "firstName": "Jean", + "lastName": "Mcclure", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Concetta", + "lastName": "Hess", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Page", + "lastName": "Palmer", + "company": "Xinware", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Ayala", + "company": "Escenta", + "employed": false + }, + { + "firstName": "Morse", + "lastName": "Townsend", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Dyer", + "lastName": "Bass", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Melanie", + "lastName": "Lynch", + "company": "Moltonic", + "employed": false + }, + { + "firstName": "Dolores", + "lastName": "Trujillo", + "company": "Aquasure", + "employed": true + }, + { + "firstName": "Sandoval", + "lastName": "Hughes", + "company": "Furnafix", + "employed": false + }, + { + "firstName": "Bentley", + "lastName": "Reynolds", + "company": "Norsul", + "employed": false + }, + { + "firstName": "Howell", + "lastName": "Gay", + "company": "Codax", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Guerrero", + "company": "Genmy", + "employed": false + }, + { + "firstName": "Mcpherson", + "lastName": "Powell", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Mcknight", + "lastName": "Compton", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Rutledge", + "lastName": "Spears", + "company": "Viagreat", + "employed": true + }, + { + "firstName": "Foster", + "lastName": "Craft", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Bryan", + "lastName": "Vang", + "company": "Concility", + "employed": false + }, + { + "firstName": "Ferrell", + "lastName": "Raymond", + "company": "Exodoc", + "employed": true + }, + { + "firstName": "Linda", + "lastName": "Peters", + "company": "Kyaguru", + "employed": false + }, + { + "firstName": "Stein", + "lastName": "Lambert", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Reyes", + "lastName": "Mcpherson", + "company": "Comcur", + "employed": true + }, + { + "firstName": "Torres", + "lastName": "Ramsey", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Patrice", + "lastName": "Long", + "company": "Hatology", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Cochran", + "company": "Cuizine", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Walters", + "company": "Accel", + "employed": true + }, + { + "firstName": "Julie", + "lastName": "Pugh", + "company": "Xylar", + "employed": true + }, + { + "firstName": "Madden", + "lastName": "Pitts", + "company": "Isotronic", + "employed": true + }, + { + "firstName": "Petty", + "lastName": "Mcmahon", + "company": "Extragen", + "employed": false + }, + { + "firstName": "Elise", + "lastName": "Rosales", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Marcie", + "lastName": "Snyder", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Gamble", + "lastName": "Schneider", + "company": "Ovation", + "employed": true + }, + { + "firstName": "Ray", + "lastName": "Roberts", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Maxwell", + "lastName": "Richard", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Coleman", + "lastName": "Edwards", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Carissa", + "lastName": "Castro", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Bertie", + "lastName": "Sparks", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Autumn", + "lastName": "Sharp", + "company": "Conferia", + "employed": true + }, + { + "firstName": "Anthony", + "lastName": "Grant", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Bernice", + "lastName": "Morse", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Walton", + "lastName": "Mathews", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Knowles", + "lastName": "Coffey", + "company": "Equitox", + "employed": false + }, + { + "firstName": "Harding", + "lastName": "Horton", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Adrienne", + "lastName": "Phillips", + "company": "Poochies", + "employed": true + }, + { + "firstName": "Wood", + "lastName": "Jenkins", + "company": "Petigems", + "employed": true + }, + { + "firstName": "Powell", + "lastName": "Fry", + "company": "Accidency", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Reeves", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Parrish", + "lastName": "Harvey", + "company": "Applidec", + "employed": true + }, + { + "firstName": "Dudley", + "lastName": "Macias", + "company": "Enjola", + "employed": true + }, + { + "firstName": "Meyer", + "lastName": "Meyers", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "Diaz", + "lastName": "Delacruz", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Eleanor", + "lastName": "Hodges", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Tillman", + "lastName": "Casey", + "company": "Manufact", + "employed": false + }, + { + "firstName": "Natasha", + "lastName": "Day", + "company": "Jumpstack", + "employed": false + }, + { + "firstName": "Sondra", + "lastName": "Davenport", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Neal", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Cline", + "company": "Ecstasia", + "employed": true + }, + { + "firstName": "Alexandria", + "lastName": "Lyons", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Franco", + "lastName": "Willis", + "company": "Geeky", + "employed": false + }, + { + "firstName": "Hunter", + "lastName": "Cooper", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Caroline", + "lastName": "Ellis", + "company": "Cemention", + "employed": false + }, + { + "firstName": "Riley", + "lastName": "Kane", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Mcintyre", + "lastName": "Wright", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Sears", + "company": "Rockyard", + "employed": true + }, + { + "firstName": "Doris", + "lastName": "Noel", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Little", + "lastName": "Kaufman", + "company": "Sustenza", + "employed": true + }, + { + "firstName": "Estrada", + "lastName": "Graham", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Sanford", + "lastName": "Wilkins", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Nelson", + "lastName": "Mcbride", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Trudy", + "lastName": "Lindsey", + "company": "Rodeocean", + "employed": false + }, + { + "firstName": "Maynard", + "lastName": "Wall", + "company": "Essensia", + "employed": true + }, + { + "firstName": "Quinn", + "lastName": "Bates", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Blackwell", + "lastName": "Howe", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Flossie", + "lastName": "Barrett", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Benjamin", + "lastName": "Henson", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Gallegos", + "lastName": "Holt", + "company": "Bluplanet", + "employed": true + }, + { + "firstName": "Rowe", + "lastName": "Carpenter", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Robbie", + "lastName": "Knapp", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Shepard", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Munoz", + "lastName": "Mcclain", + "company": "Duoflex", + "employed": false + }, + { + "firstName": "Vonda", + "lastName": "Valdez", + "company": "Springbee", + "employed": false + }, + { + "firstName": "Janie", + "lastName": "Marshall", + "company": "Netbook", + "employed": false + }, + { + "firstName": "Prince", + "lastName": "Pollard", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Cortez", + "lastName": "Decker", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Goodman", + "lastName": "Harrison", + "company": "Furnitech", + "employed": false + }, + { + "firstName": "Castro", + "lastName": "Levy", + "company": "Fleetmix", + "employed": true + }, + { + "firstName": "Sheppard", + "lastName": "Fox", + "company": "Namebox", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Parsons", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Saundra", + "lastName": "Bowers", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Hess", + "lastName": "Ryan", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Conway", + "lastName": "Ewing", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Head", + "lastName": "Salazar", + "company": "Baluba", + "employed": false + }, + { + "firstName": "Madeline", + "lastName": "Hodge", + "company": "Quonata", + "employed": true + }, + { + "firstName": "Odom", + "lastName": "Patel", + "company": "Gink", + "employed": true + }, + { + "firstName": "Alta", + "lastName": "Fleming", + "company": "Biospan", + "employed": true + }, + { + "firstName": "Virgie", + "lastName": "Moody", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Blevins", + "lastName": "Norton", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Beasley", + "lastName": "Tanner", + "company": "Empirica", + "employed": true + }, + { + "firstName": "Zamora", + "lastName": "Ruiz", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Rocha", + "lastName": "Everett", + "company": "Comstar", + "employed": false + }, + { + "firstName": "Henson", + "lastName": "Morrow", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Janna", + "lastName": "Salinas", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Perry", + "lastName": "Mathis", + "company": "Sensate", + "employed": false + }, + { + "firstName": "Short", + "lastName": "Dennis", + "company": "Zolarex", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Oneill", + "company": "Zillidium", + "employed": false + }, + { + "firstName": "Anita", + "lastName": "George", + "company": "Insource", + "employed": true + }, + { + "firstName": "Traci", + "lastName": "Byers", + "company": "Irack", + "employed": true + }, + { + "firstName": "Patterson", + "lastName": "Sharpe", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Dee", + "lastName": "Hall", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Constance", + "lastName": "Guthrie", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Lowe", + "lastName": "Hurley", + "company": "Megall", + "employed": false + }, + { + "firstName": "Hickman", + "lastName": "Fuentes", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Hernandez", + "lastName": "Walton", + "company": "Comtext", + "employed": true + }, + { + "firstName": "Sheena", + "lastName": "Logan", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Luz", + "lastName": "Goodman", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Aileen", + "lastName": "Pruitt", + "company": "Anivet", + "employed": false + }, + { + "firstName": "Hammond", + "lastName": "Nieves", + "company": "Memora", + "employed": true + }, + { + "firstName": "Nancy", + "lastName": "Smith", + "company": "Protodyne", + "employed": true + }, + { + "firstName": "Rogers", + "lastName": "Thomas", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Phillips", + "lastName": "Hinton", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Dorothy", + "lastName": "Sullivan", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Kinney", + "company": "Tubalum", + "employed": false + }, + { + "firstName": "Cantrell", + "lastName": "Arnold", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Humphrey", + "lastName": "Santana", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Ross", + "lastName": "Paul", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Wong", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Serrano", + "lastName": "Blankenship", + "company": "Uniworld", + "employed": true + }, + { + "firstName": "Warner", + "lastName": "Valencia", + "company": "Retrotex", + "employed": true + }, + { + "firstName": "Silvia", + "lastName": "Mcneil", + "company": "Luxuria", + "employed": true + }, + { + "firstName": "Buchanan", + "lastName": "Frank", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Catherine", + "lastName": "Holder", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Leta", + "lastName": "Lara", + "company": "Gleamink", + "employed": true + }, + { + "firstName": "Salazar", + "lastName": "Nguyen", + "company": "Isis", + "employed": true + }, + { + "firstName": "Marietta", + "lastName": "Navarro", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Joanne", + "lastName": "Cox", + "company": "Unq", + "employed": false + }, + { + "firstName": "Bauer", + "lastName": "Jarvis", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Chaney", + "lastName": "Beck", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Johanna", + "lastName": "Bentley", + "company": "Plutorque", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Copeland", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Navarro", + "lastName": "Browning", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Estelle", + "lastName": "Boyd", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Staci", + "lastName": "Mendoza", + "company": "Stralum", + "employed": false + }, + { + "firstName": "Sonya", + "lastName": "Gates", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Daphne", + "lastName": "Juarez", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Foley", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Maritza", + "lastName": "Burnett", + "company": "Netility", + "employed": true + }, + { + "firstName": "Vivian", + "lastName": "Bennett", + "company": "Powernet", + "employed": false + }, + { + "firstName": "Veronica", + "lastName": "Barton", + "company": "Proflex", + "employed": false + }, + { + "firstName": "Mari", + "lastName": "Martin", + "company": "Tubesys", + "employed": false + }, + { + "firstName": "David", + "lastName": "Gallagher", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Buck", + "lastName": "Garrison", + "company": "Optique", + "employed": true + }, + { + "firstName": "Tamera", + "lastName": "Blevins", + "company": "Pyrami", + "employed": false + }, + { + "firstName": "Wendy", + "lastName": "Meyer", + "company": "Interfind", + "employed": false + }, + { + "firstName": "Wynn", + "lastName": "Pearson", + "company": "Lunchpod", + "employed": false + }, + { + "firstName": "Berger", + "lastName": "Lowery", + "company": "Krog", + "employed": false + }, + { + "firstName": "Gilda", + "lastName": "Solomon", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Latisha", + "lastName": "Duran", + "company": "Terragen", + "employed": true + }, + { + "firstName": "Pearlie", + "lastName": "Charles", + "company": "Orbiflex", + "employed": false + }, + { + "firstName": "Floyd", + "lastName": "Stone", + "company": "Zerology", + "employed": false + }, + { + "firstName": "Yvonne", + "lastName": "Pickett", + "company": "Jasper", + "employed": false + }, + { + "firstName": "Jewel", + "lastName": "Cook", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Jo", + "lastName": "Sanchez", + "company": "Quarex", + "employed": true + }, + { + "firstName": "Acosta", + "lastName": "Harding", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Cross", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Mullins", + "lastName": "Molina", + "company": "Flum", + "employed": false + }, + { + "firstName": "Schroeder", + "lastName": "Leon", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Kenya", + "lastName": "Livingston", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Maria", + "lastName": "Roman", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Blake", + "lastName": "Stanton", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Trevino", + "lastName": "Riggs", + "company": "Iplax", + "employed": false + }, + { + "firstName": "Clemons", + "lastName": "Houston", + "company": "Zilodyne", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Horn", + "company": "Xoggle", + "employed": false + }, + { + "firstName": "Long", + "lastName": "Berry", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Colette", + "lastName": "Oneal", + "company": "Medmex", + "employed": false + }, + { + "firstName": "Erickson", + "lastName": "Landry", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Wilkins", + "lastName": "Fernandez", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Paul", + "lastName": "Pena", + "company": "Pharmex", + "employed": false + }, + { + "firstName": "Gentry", + "lastName": "Gilliam", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Tyson", + "lastName": "Pittman", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Donna", + "lastName": "Massey", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Bell", + "lastName": "Klein", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Cabrera", + "lastName": "Mccoy", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Clara", + "lastName": "Barry", + "company": "Limage", + "employed": true + }, + { + "firstName": "Green", + "lastName": "Mccall", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Goodwin", + "lastName": "Wise", + "company": "Isbol", + "employed": true + }, + { + "firstName": "Connie", + "lastName": "Perez", + "company": "Digifad", + "employed": false + }, + { + "firstName": "Florence", + "lastName": "Small", + "company": "Entality", + "employed": true + }, + { + "firstName": "Mallory", + "lastName": "Joseph", + "company": "Isoternia", + "employed": true + }, + { + "firstName": "Tanisha", + "lastName": "Espinoza", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Carla", + "lastName": "Ward", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Lamb", + "company": "Valreda", + "employed": true + }, + { + "firstName": "Marion", + "lastName": "Stuart", + "company": "Assistia", + "employed": false + }, + { + "firstName": "Erna", + "lastName": "Avila", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Belinda", + "lastName": "Taylor", + "company": "Filodyne", + "employed": true + }, + { + "firstName": "Joann", + "lastName": "Benton", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Mendoza", + "lastName": "Madden", + "company": "Musaphics", + "employed": true + }, + { + "firstName": "Ivy", + "lastName": "Hatfield", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Cooley", + "lastName": "Maynard", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Angeline", + "lastName": "Emerson", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Sparks", + "lastName": "Webb", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Eddie", + "lastName": "Reyes", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Francine", + "lastName": "Lindsay", + "company": "Isosure", + "employed": true + }, + { + "firstName": "Jaclyn", + "lastName": "Garza", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Randall", + "lastName": "Hebert", + "company": "Prosure", + "employed": false + }, + { + "firstName": "Delores", + "lastName": "Franklin", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Kristen", + "lastName": "Fisher", + "company": "Grok", + "employed": false + }, + { + "firstName": "Hardy", + "lastName": "Downs", + "company": "Voipa", + "employed": false + }, + { + "firstName": "Boyd", + "lastName": "Flynn", + "company": "Snips", + "employed": true + }, + { + "firstName": "Eula", + "lastName": "Myers", + "company": "Goko", + "employed": true + }, + { + "firstName": "Hansen", + "lastName": "Scott", + "company": "Liquidoc", + "employed": false + }, + { + "firstName": "Waller", + "lastName": "Bartlett", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Mona", + "lastName": "Simpson", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Jeanine", + "lastName": "Hays", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Nicholson", + "lastName": "Bruce", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Willie", + "lastName": "Huff", + "company": "Netur", + "employed": true + }, + { + "firstName": "Jensen", + "lastName": "Rojas", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Meyers", + "lastName": "Vaughan", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Anastasia", + "lastName": "Gilmore", + "company": "Zilencio", + "employed": true + }, + { + "firstName": "Nadia", + "lastName": "Glenn", + "company": "Dancerity", + "employed": true + }, + { + "firstName": "Celia", + "lastName": "Moreno", + "company": "Plasmosis", + "employed": false + }, + { + "firstName": "Myra", + "lastName": "Aguirre", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Salas", + "lastName": "Lynn", + "company": "Datagene", + "employed": true + }, + { + "firstName": "Erika", + "lastName": "Mcgowan", + "company": "Helixo", + "employed": true + }, + { + "firstName": "Nellie", + "lastName": "French", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Janine", + "lastName": "Beasley", + "company": "Telepark", + "employed": false + }, + { + "firstName": "Harmon", + "lastName": "Mullen", + "company": "Ontagene", + "employed": false + }, + { + "firstName": "Lynn", + "lastName": "Hahn", + "company": "Quinex", + "employed": true + }, + { + "firstName": "Essie", + "lastName": "Clarke", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Foreman", + "lastName": "Herman", + "company": "Eventix", + "employed": false + }, + { + "firstName": "Barr", + "lastName": "Barrera", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Holman", + "lastName": "Caldwell", + "company": "Exotechno", + "employed": true + }, + { + "firstName": "Newton", + "lastName": "Hartman", + "company": "Panzent", + "employed": true + }, + { + "firstName": "Austin", + "lastName": "Riley", + "company": "Norali", + "employed": true + }, + { + "firstName": "Frieda", + "lastName": "Kerr", + "company": "Ecrater", + "employed": true + }, + { + "firstName": "Mathis", + "lastName": "Fletcher", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Alisa", + "lastName": "Love", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Phyllis", + "lastName": "Hensley", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Katy", + "lastName": "Wade", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Claire", + "lastName": "Greene", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Robert", + "lastName": "Rowe", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Hollie", + "lastName": "Finch", + "company": "Avenetro", + "employed": false + }, + { + "firstName": "Lela", + "lastName": "Daniels", + "company": "Enervate", + "employed": false + }, + { + "firstName": "Lindsey", + "lastName": "Anderson", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Joyner", + "lastName": "Payne", + "company": "Neteria", + "employed": true + }, + { + "firstName": "Britney", + "lastName": "Swanson", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Bean", + "lastName": "Malone", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Curry", + "lastName": "Welch", + "company": "Enormo", + "employed": false + }, + { + "firstName": "Knox", + "lastName": "Tyson", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Hudson", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Rhonda", + "lastName": "Perkins", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Rodriquez", + "lastName": "Matthews", + "company": "Tetak", + "employed": true + }, + { + "firstName": "Mcdaniel", + "lastName": "Hyde", + "company": "Xelegyl", + "employed": false + }, + { + "firstName": "Conley", + "lastName": "Lester", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Deirdre", + "lastName": "Singleton", + "company": "Verton", + "employed": false + }, + { + "firstName": "Lakeisha", + "lastName": "Jimenez", + "company": "Shopabout", + "employed": false + }, + { + "firstName": "Rodgers", + "lastName": "Castillo", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Silva", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Karen", + "lastName": "Drake", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Grant", + "lastName": "Cote", + "company": "Ezentia", + "employed": true + }, + { + "firstName": "Pamela", + "lastName": "Dunlap", + "company": "Ceprene", + "employed": true + }, + { + "firstName": "Inez", + "lastName": "Gross", + "company": "Ultrasure", + "employed": false + }, + { + "firstName": "Deleon", + "lastName": "Dominguez", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Matthews", + "lastName": "Ball", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Eileen", + "lastName": "Medina", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Carpenter", + "lastName": "Moran", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Polly", + "lastName": "Rhodes", + "company": "Magnemo", + "employed": true + }, + { + "firstName": "Susan", + "lastName": "Mccarty", + "company": "Austex", + "employed": false + }, + { + "firstName": "Justine", + "lastName": "Mccullough", + "company": "Exostream", + "employed": true + }, + { + "firstName": "Mccormick", + "lastName": "Holden", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Aisha", + "lastName": "Walls", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Tameka", + "lastName": "Haley", + "company": "Gynk", + "employed": false + }, + { + "firstName": "Candice", + "lastName": "Nolan", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Juliet", + "lastName": "Clayton", + "company": "Accufarm", + "employed": false + }, + { + "firstName": "Tracie", + "lastName": "Pace", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Ruthie", + "lastName": "Stewart", + "company": "Senmao", + "employed": true + }, + { + "firstName": "Sophia", + "lastName": "Talley", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Sally", + "lastName": "Adkins", + "company": "Savvy", + "employed": true + }, + { + "firstName": "Lawson", + "lastName": "Evans", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Chen", + "company": "Boink", + "employed": true + }, + { + "firstName": "Shauna", + "lastName": "Herring", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Laverne", + "lastName": "Hood", + "company": "Prismatic", + "employed": false + }, + { + "firstName": "Turner", + "lastName": "Ashley", + "company": "Vetron", + "employed": true + }, + { + "firstName": "Spencer", + "lastName": "Horne", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Oliver", + "lastName": "Burt", + "company": "Geekosis", + "employed": true + }, + { + "firstName": "Miller", + "lastName": "Conley", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Porter", + "lastName": "Baker", + "company": "Fitcore", + "employed": true + }, + { + "firstName": "Brianna", + "lastName": "Tyler", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Mildred", + "lastName": "Faulkner", + "company": "Ginkogene", + "employed": true + }, + { + "firstName": "Delacruz", + "lastName": "Robles", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Dennis", + "lastName": "Stephenson", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Yates", + "lastName": "Gardner", + "company": "Digial", + "employed": true + }, + { + "firstName": "Brooke", + "lastName": "Brooks", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Davenport", + "lastName": "Bond", + "company": "Accuprint", + "employed": true + }, + { + "firstName": "Nichols", + "lastName": "Gutierrez", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Henry", + "lastName": "Battle", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Ortiz", + "lastName": "Allison", + "company": "Zedalis", + "employed": true + }, + { + "firstName": "Jennifer", + "lastName": "Owens", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Hatfield", + "lastName": "Chase", + "company": "Micronaut", + "employed": true + }, + { + "firstName": "Katelyn", + "lastName": "Combs", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Vaughn", + "lastName": "Schroeder", + "company": "Spherix", + "employed": false + }, + { + "firstName": "Terra", + "lastName": "Morton", + "company": "Zolavo", + "employed": true + }, + { + "firstName": "Arline", + "lastName": "Key", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Barlow", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Lynda", + "lastName": "Mack", + "company": "Codact", + "employed": true + }, + { + "firstName": "Ingram", + "lastName": "Sims", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Paige", + "lastName": "Hurst", + "company": "Acruex", + "employed": true + }, + { + "firstName": "Adeline", + "lastName": "Terrell", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Pam", + "lastName": "Jones", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Hope", + "lastName": "Eaton", + "company": "Inrt", + "employed": true + }, + { + "firstName": "James", + "lastName": "Dickson", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Nash", + "lastName": "Walsh", + "company": "Puria", + "employed": false + }, + { + "firstName": "Sloan", + "lastName": "Jefferson", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Church", + "lastName": "Freeman", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Bridget", + "lastName": "Garrett", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Robinson", + "company": "Telpod", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Carlson", + "company": "Yogasm", + "employed": false + }, + { + "firstName": "Lavonne", + "lastName": "Nelson", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Mable", + "lastName": "Terry", + "company": "Fibrodyne", + "employed": true + }, + { + "firstName": "Elba", + "lastName": "Sloan", + "company": "Qiao", + "employed": false + }, + { + "firstName": "Alford", + "lastName": "Gould", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Clarissa", + "lastName": "Crawford", + "company": "Vendblend", + "employed": false + }, + { + "firstName": "Lea", + "lastName": "Quinn", + "company": "Franscene", + "employed": false + }, + { + "firstName": "Jamie", + "lastName": "May", + "company": "Golistic", + "employed": true + }, + { + "firstName": "Marsh", + "lastName": "Reilly", + "company": "Comdom", + "employed": false + }, + { + "firstName": "Mcdowell", + "lastName": "Peterson", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Parker", + "lastName": "Munoz", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Mae", + "lastName": "Wilson", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Lucile", + "lastName": "Gray", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Bennett", + "lastName": "Witt", + "company": "Verbus", + "employed": true + }, + { + "firstName": "Sherman", + "lastName": "Mckenzie", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Donaldson", + "lastName": "Bell", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Bonner", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Conrad", + "lastName": "Waller", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Edith", + "lastName": "Peck", + "company": "Netagy", + "employed": true + }, + { + "firstName": "Galloway", + "lastName": "Chavez", + "company": "Quordate", + "employed": true + }, + { + "firstName": "Noreen", + "lastName": "Warren", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Tammi", + "lastName": "Cotton", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Claudia", + "lastName": "Pacheco", + "company": "Corpulse", + "employed": true + }, + { + "firstName": "Bonita", + "lastName": "Stevenson", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Christensen", + "company": "Zilphur", + "employed": false + }, + { + "firstName": "Rita", + "lastName": "Burch", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "York", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Jocelyn", + "lastName": "Keith", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Pate", + "lastName": "Whitehead", + "company": "Zisis", + "employed": true + }, + { + "firstName": "Cole", + "lastName": "Langley", + "company": "Olympix", + "employed": true + }, + { + "firstName": "Lorraine", + "lastName": "Gilbert", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Hurley", + "lastName": "Parks", + "company": "Genmom", + "employed": false + }, + { + "firstName": "Schultz", + "lastName": "Guerra", + "company": "Multron", + "employed": true + }, + { + "firstName": "Susanna", + "lastName": "Herrera", + "company": "Centree", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Glover", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Hilary", + "lastName": "Whitfield", + "company": "Combot", + "employed": false + }, + { + "firstName": "Rena", + "lastName": "Hancock", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "Roberta", + "lastName": "Morgan", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Lesley", + "lastName": "Roy", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Schmidt", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Snow", + "lastName": "David", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Walsh", + "lastName": "Stevens", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Tia", + "lastName": "Slater", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Etta", + "lastName": "Travis", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Olive", + "lastName": "Grimes", + "company": "Handshake", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Brennan", + "company": "Shadease", + "employed": true + }, + { + "firstName": "Dawson", + "lastName": "Ramirez", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Stark", + "company": "Accusage", + "employed": true + }, + { + "firstName": "Moss", + "lastName": "Carr", + "company": "Navir", + "employed": false + }, + { + "firstName": "Mills", + "lastName": "Curtis", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Charlotte", + "lastName": "Francis", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Marquita", + "lastName": "Randall", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Kirsten", + "lastName": "Buchanan", + "company": "Telequiet", + "employed": false + }, + { + "firstName": "Dawn", + "lastName": "Campos", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Norris", + "lastName": "Bush", + "company": "Radiantix", + "employed": true + }, + { + "firstName": "Iris", + "lastName": "Hawkins", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Cornelia", + "lastName": "Atkinson", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Rivers", + "lastName": "Conner", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Cohen", + "lastName": "Pate", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Raquel", + "lastName": "Tran", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Schmidt", + "lastName": "Wiggins", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Carney", + "lastName": "Alexander", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Rush", + "lastName": "Flores", + "company": "Opticall", + "employed": false + }, + { + "firstName": "Nieves", + "lastName": "Richardson", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Sanchez", + "lastName": "Mullins", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Hallie", + "lastName": "Cantrell", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Dunn", + "lastName": "Acevedo", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Brewer", + "lastName": "Dawson", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Flora", + "lastName": "Michael", + "company": "Portica", + "employed": true + }, + { + "firstName": "Mayer", + "lastName": "Lewis", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Lesa", + "lastName": "Hayden", + "company": "Aquoavo", + "employed": false + }, + { + "firstName": "Watts", + "lastName": "Allen", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Angela", + "lastName": "Douglas", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Dolly", + "lastName": "Brewer", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Jenkins", + "lastName": "Frost", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Carolyn", + "lastName": "Brown", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Stephens", + "lastName": "Rowland", + "company": "Eventex", + "employed": false + }, + { + "firstName": "Bridges", + "lastName": "Harrell", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Burch", + "lastName": "Booth", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Irwin", + "lastName": "Snow", + "company": "Slax", + "employed": true + }, + { + "firstName": "Dean", + "lastName": "Barnes", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Noble", + "lastName": "Riddle", + "company": "Twiist", + "employed": false + }, + { + "firstName": "Hoffman", + "lastName": "Lowe", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Wade", + "lastName": "Tillman", + "company": "Medesign", + "employed": false + }, + { + "firstName": "Lakisha", + "lastName": "Hale", + "company": "Remold", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "Vance", + "company": "Extremo", + "employed": true + }, + { + "firstName": "Levy", + "lastName": "Odom", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Conner", + "lastName": "Abbott", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Sylvia", + "lastName": "Guzman", + "company": "Songlines", + "employed": false + }, + { + "firstName": "Mariana", + "lastName": "Mays", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Louisa", + "lastName": "Potter", + "company": "Overplex", + "employed": true + }, + { + "firstName": "Holden", + "lastName": "Hampton", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Ella", + "lastName": "Zimmerman", + "company": "Quadeebo", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Sanders", + "company": "Grainspot", + "employed": true + }, + { + "firstName": "Ellison", + "lastName": "Richmond", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Robles", + "lastName": "Acosta", + "company": "Comtrail", + "employed": true + }, + { + "firstName": "Sharon", + "lastName": "Williamson", + "company": "Zaggle", + "employed": true + }, + { + "firstName": "Melendez", + "lastName": "Wolfe", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Hooper", + "lastName": "Frazier", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Dionne", + "lastName": "Keller", + "company": "Cinaster", + "employed": true + }, + { + "firstName": "Johns", + "lastName": "Justice", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Norma", + "lastName": "Young", + "company": "Aquasseur", + "employed": true + }, + { + "firstName": "Hutchinson", + "lastName": "Cannon", + "company": "Incubus", + "employed": false + }, + { + "firstName": "Melissa", + "lastName": "Donaldson", + "company": "Velity", + "employed": true + }, + { + "firstName": "Rosario", + "lastName": "Solis", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Carrie", + "lastName": "Merrill", + "company": "Teraprene", + "employed": false + }, + { + "firstName": "Poole", + "lastName": "White", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Lynette", + "lastName": "Larson", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Weber", + "lastName": "Strickland", + "company": "Eclipto", + "employed": false + }, + { + "firstName": "Wheeler", + "lastName": "Little", + "company": "Musanpoly", + "employed": true + }, + { + "firstName": "Pace", + "lastName": "Lopez", + "company": "Poshome", + "employed": true + }, + { + "firstName": "Casandra", + "lastName": "Mcfadden", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Bruce", + "lastName": "Kent", + "company": "Techade", + "employed": false + }, + { + "firstName": "Everett", + "lastName": "Hubbard", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Howell", + "company": "Neptide", + "employed": false + }, + { + "firstName": "Lawanda", + "lastName": "Bradford", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Michael", + "lastName": "Erickson", + "company": "Sureplex", + "employed": false + }, + { + "firstName": "Millicent", + "lastName": "Hunter", + "company": "Geekwagon", + "employed": true + }, + { + "firstName": "Fran", + "lastName": "Ray", + "company": "Krag", + "employed": true + }, + { + "firstName": "Rosalyn", + "lastName": "Mckay", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Larson", + "lastName": "James", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Nannie", + "lastName": "Kirkland", + "company": "Elemantra", + "employed": true + }, + { + "firstName": "Melva", + "lastName": "Bauer", + "company": "Ewaves", + "employed": true + }, + { + "firstName": "Workman", + "lastName": "Schultz", + "company": "Rameon", + "employed": false + }, + { + "firstName": "Gillespie", + "lastName": "Santiago", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Gonzalez", + "company": "Vantage", + "employed": true + }, + { + "firstName": "Hamilton", + "lastName": "Mccarthy", + "company": "Gorganic", + "employed": false + }, + { + "firstName": "Weeks", + "lastName": "Carney", + "company": "Bleeko", + "employed": false + }, + { + "firstName": "Malone", + "lastName": "Sargent", + "company": "Kage", + "employed": false + }, + { + "firstName": "Barbra", + "lastName": "Banks", + "company": "Undertap", + "employed": false + }, + { + "firstName": "Emily", + "lastName": "Rollins", + "company": "Skinserve", + "employed": false + }, + { + "firstName": "Wilder", + "lastName": "England", + "company": "Omatom", + "employed": true + }, + { + "firstName": "Wolf", + "lastName": "Hoover", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Glover", + "lastName": "Leblanc", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Tate", + "lastName": "Mclaughlin", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Kaitlin", + "lastName": "Mcmillan", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Alissa", + "lastName": "Clay", + "company": "Buzzness", + "employed": false + }, + { + "firstName": "Yvette", + "lastName": "Knowles", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Chelsea", + "lastName": "Weiss", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Hattie", + "lastName": "Atkins", + "company": "Fishland", + "employed": false + }, + { + "firstName": "Chang", + "lastName": "Crosby", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Benson", + "lastName": "Alvarez", + "company": "Otherside", + "employed": false + }, + { + "firstName": "Reynolds", + "lastName": "Torres", + "company": "Ludak", + "employed": false + }, + { + "firstName": "Washington", + "lastName": "Washington", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Abbott", + "lastName": "Davis", + "company": "Biflex", + "employed": false + }, + { + "firstName": "Hicks", + "lastName": "Huffman", + "company": "Ginkle", + "employed": true + }, + { + "firstName": "Gibbs", + "lastName": "Baxter", + "company": "Roboid", + "employed": false + }, + { + "firstName": "Rosanna", + "lastName": "Bray", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Bishop", + "lastName": "Mills", + "company": "Cosmetex", + "employed": true + }, + { + "firstName": "Miranda", + "lastName": "Woodward", + "company": "Volax", + "employed": false + }, + { + "firstName": "Kinney", + "lastName": "Heath", + "company": "Rockabye", + "employed": false + }, + { + "firstName": "Faith", + "lastName": "Reed", + "company": "Ecratic", + "employed": true + }, + { + "firstName": "Baxter", + "lastName": "Finley", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Cain", + "lastName": "Gillespie", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Dianna", + "lastName": "Soto", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Mcclain", + "lastName": "Gibson", + "company": "Combogen", + "employed": true + }, + { + "firstName": "Phelps", + "lastName": "Whitaker", + "company": "Microluxe", + "employed": false + }, + { + "firstName": "Vargas", + "lastName": "Rice", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Mays", + "lastName": "Vargas", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Myrna", + "lastName": "Kim", + "company": "Cormoran", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Montgomery", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Evans", + "lastName": "Becker", + "company": "Jimbies", + "employed": false + }, + { + "firstName": "Karin", + "lastName": "Daugherty", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Brady", + "lastName": "Elliott", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Doyle", + "lastName": "Rivas", + "company": "Dancity", + "employed": true + }, + { + "firstName": "Fanny", + "lastName": "Murphy", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Berg", + "lastName": "Tate", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Gale", + "lastName": "Cardenas", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Deana", + "lastName": "Burgess", + "company": "Qualitern", + "employed": true + }, + { + "firstName": "Wolfe", + "lastName": "Mercado", + "company": "Xymonk", + "employed": true + }, + { + "firstName": "Lelia", + "lastName": "Knox", + "company": "Zialactic", + "employed": true + }, + { + "firstName": "Gloria", + "lastName": "Adams", + "company": "Zipak", + "employed": true + }, + { + "firstName": "Steele", + "lastName": "Thornton", + "company": "Plexia", + "employed": true + }, + { + "firstName": "Fulton", + "lastName": "Leonard", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Angelia", + "lastName": "Ford", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Bright", + "lastName": "Skinner", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Dickerson", + "lastName": "Mejia", + "company": "Repetwire", + "employed": false + }, + { + "firstName": "Lopez", + "lastName": "Ortiz", + "company": "Vidto", + "employed": true + }, + { + "firstName": "Barrett", + "lastName": "Simon", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Joni", + "lastName": "Shelton", + "company": "Firewax", + "employed": true + }, + { + "firstName": "Christie", + "lastName": "Mcguire", + "company": "Circum", + "employed": true + }, + { + "firstName": "Shana", + "lastName": "Nichols", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Mccullough", + "lastName": "Hopper", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Wanda", + "lastName": "Cobb", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Roth", + "lastName": "Nicholson", + "company": "Deviltoe", + "employed": true + }, + { + "firstName": "Martina", + "lastName": "Lawson", + "company": "Reversus", + "employed": true + }, + { + "firstName": "Hood", + "lastName": "Ross", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Bailey", + "lastName": "Bailey", + "company": "Zillacon", + "employed": true + }, + { + "firstName": "Cherry", + "lastName": "Hoffman", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Kemp", + "lastName": "Robertson", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Margarita", + "lastName": "Chandler", + "company": "Columella", + "employed": false + }, + { + "firstName": "Rosemarie", + "lastName": "Ochoa", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Allyson", + "lastName": "Richards", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Jerri", + "lastName": "Mooney", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Murphy", + "lastName": "Dotson", + "company": "Gazak", + "employed": false + }, + { + "firstName": "Macias", + "lastName": "Wolf", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Ericka", + "lastName": "Todd", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "George", + "lastName": "Marsh", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Mccarty", + "lastName": "Lee", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Darla", + "lastName": "Burns", + "company": "Futuris", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Hamilton", + "company": "Zogak", + "employed": true + }, + { + "firstName": "Webb", + "lastName": "Gregory", + "company": "Fangold", + "employed": true + }, + { + "firstName": "Graves", + "lastName": "Mcconnell", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Cathy", + "lastName": "Bender", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Meredith", + "lastName": "Trevino", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Buckner", + "lastName": "Maddox", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Edna", + "lastName": "Ratliff", + "company": "Danja", + "employed": true + }, + { + "firstName": "Odonnell", + "lastName": "Dorsey", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Davidson", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Marie", + "lastName": "Waters", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Amber", + "lastName": "Carroll", + "company": "Medalert", + "employed": false + }, + { + "firstName": "England", + "lastName": "Kirk", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Hayes", + "company": "Quility", + "employed": true + }, + { + "firstName": "Katina", + "lastName": "Figueroa", + "company": "Sloganaut", + "employed": true + }, + { + "firstName": "Farrell", + "lastName": "Odonnell", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Peggy", + "lastName": "Haynes", + "company": "Slumberia", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Cruz", + "company": "Obones", + "employed": true + }, + { + "firstName": "Audrey", + "lastName": "Bright", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Velma", + "lastName": "Joyner", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Mattie", + "lastName": "Lloyd", + "company": "Architax", + "employed": true + }, + { + "firstName": "Mosley", + "lastName": "Cervantes", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Esperanza", + "lastName": "Hull", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Roach", + "lastName": "Johnson", + "company": "Quilch", + "employed": false + }, + { + "firstName": "Durham", + "lastName": "Gomez", + "company": "Signity", + "employed": true + }, + { + "firstName": "Castaneda", + "lastName": "Benjamin", + "company": "Centice", + "employed": false + }, + { + "firstName": "Magdalena", + "lastName": "Howard", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Potter", + "lastName": "Diaz", + "company": "Kenegy", + "employed": true + }, + { + "firstName": "Tracy", + "lastName": "Cooke", + "company": "Flexigen", + "employed": false + }, + { + "firstName": "Fernandez", + "lastName": "Olson", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Shelly", + "lastName": "Lott", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Finley", + "lastName": "Hobbs", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Townsend", + "lastName": "Leach", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Hewitt", + "lastName": "Wiley", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Marylou", + "lastName": "Gallegos", + "company": "Zerbina", + "employed": true + }, + { + "firstName": "Barron", + "lastName": "Vazquez", + "company": "Cogentry", + "employed": false + }, + { + "firstName": "Pat", + "lastName": "Underwood", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Cardenas", + "lastName": "Barber", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Mejia", + "lastName": "Booker", + "company": "Melbacor", + "employed": true + }, + { + "firstName": "Scott", + "lastName": "Miles", + "company": "Comvoy", + "employed": true + }, + { + "firstName": "Estela", + "lastName": "Jackson", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Marla", + "lastName": "Buckner", + "company": "Slambda", + "employed": true + }, + { + "firstName": "Cash", + "lastName": "Berger", + "company": "Hotcakes", + "employed": true + }, + { + "firstName": "Lessie", + "lastName": "Ayers", + "company": "Quilm", + "employed": false + }, + { + "firstName": "Crawford", + "lastName": "Cummings", + "company": "Providco", + "employed": true + }, + { + "firstName": "Fields", + "lastName": "Sweeney", + "company": "Emoltra", + "employed": false + }, + { + "firstName": "Geneva", + "lastName": "Roberson", + "company": "Eplosion", + "employed": true + }, + { + "firstName": "Snider", + "lastName": "Woods", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Latoya", + "lastName": "Winters", + "company": "Extro", + "employed": true + }, + { + "firstName": "Butler", + "lastName": "Johns", + "company": "Apextri", + "employed": false + }, + { + "firstName": "Hawkins", + "lastName": "Meadows", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Burgess", + "lastName": "Frye", + "company": "Glasstep", + "employed": false + }, + { + "firstName": "Jan", + "lastName": "Johnston", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Jasmine", + "lastName": "Perry", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Ramsey", + "lastName": "Vaughn", + "company": "Zytrex", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Graves", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Atkins", + "lastName": "Alford", + "company": "Qnekt", + "employed": true + }, + { + "firstName": "Forbes", + "lastName": "Ferguson", + "company": "Ovium", + "employed": false + }, + { + "firstName": "Viola", + "lastName": "Barr", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Levine", + "lastName": "Shannon", + "company": "Skyplex", + "employed": false + }, + { + "firstName": "Russo", + "lastName": "Harper", + "company": "Securia", + "employed": false + }, + { + "firstName": "Bryant", + "lastName": "Saunders", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Christian", + "lastName": "Best", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Betsy", + "lastName": "Fowler", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Pierce", + "lastName": "Powers", + "company": "Diginetic", + "employed": false + }, + { + "firstName": "Hayes", + "lastName": "Melton", + "company": "Strozen", + "employed": true + }, + { + "firstName": "Claudette", + "lastName": "Knight", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Burt", + "lastName": "Bolton", + "company": "Kneedles", + "employed": true + }, + { + "firstName": "Kristine", + "lastName": "Coleman", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Dixie", + "lastName": "Wynn", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Lenora", + "lastName": "Burris", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Lara", + "lastName": "Dejesus", + "company": "Pyramax", + "employed": false + }, + { + "firstName": "Mcclure", + "lastName": "Cole", + "company": "Vixo", + "employed": true + }, + { + "firstName": "Harrison", + "lastName": "Wells", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Rosalie", + "lastName": "Deleon", + "company": "Nipaz", + "employed": true + }, + { + "firstName": "Milagros", + "lastName": "Mann", + "company": "Neocent", + "employed": true + }, + { + "firstName": "Pruitt", + "lastName": "Dean", + "company": "Zillanet", + "employed": true + }, + { + "firstName": "Mayra", + "lastName": "Collins", + "company": "Zytrac", + "employed": false + }, + { + "firstName": "Lamb", + "lastName": "Byrd", + "company": "Izzby", + "employed": true + }, + { + "firstName": "Harriet", + "lastName": "Wyatt", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Brennan", + "lastName": "Benson", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Crane", + "lastName": "Pennington", + "company": "Marketoid", + "employed": true + }, + { + "firstName": "Ortega", + "lastName": "Alvarado", + "company": "Obliq", + "employed": true + }, + { + "firstName": "Maldonado", + "lastName": "Sherman", + "company": "Daycore", + "employed": false + }, + { + "firstName": "Leah", + "lastName": "Bernard", + "company": "Xurban", + "employed": false + }, + { + "firstName": "Wyatt", + "lastName": "Austin", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Schneider", + "lastName": "Blackburn", + "company": "Bulljuice", + "employed": false + }, + { + "firstName": "Le", + "lastName": "Mayer", + "company": "Magnina", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Hogan", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Daisy", + "lastName": "Middleton", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Kimberley", + "lastName": "Price", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Boyle", + "lastName": "Potts", + "company": "Kog", + "employed": false + }, + { + "firstName": "Mara", + "lastName": "Jordan", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Toni", + "lastName": "English", + "company": "Waterbaby", + "employed": false + }, + { + "firstName": "Luella", + "lastName": "Bowen", + "company": "Idego", + "employed": true + }, + { + "firstName": "Hoover", + "lastName": "Dixon", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Tucker", + "company": "Strezzo", + "employed": false + }, + { + "firstName": "Judith", + "lastName": "Pierce", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Booth", + "lastName": "Roth", + "company": "Genmex", + "employed": false + }, + { + "firstName": "Melba", + "lastName": "Velazquez", + "company": "Lunchpad", + "employed": true + }, + { + "firstName": "Vinson", + "lastName": "Osborne", + "company": "Zuvy", + "employed": true + }, + { + "firstName": "Sharp", + "lastName": "Jacobs", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Williamson", + "lastName": "Hammond", + "company": "Euron", + "employed": false + }, + { + "firstName": "Velez", + "lastName": "Stanley", + "company": "Exospeed", + "employed": true + }, + { + "firstName": "Lester", + "lastName": "Moss", + "company": "Sarasonic", + "employed": false + }, + { + "firstName": "Witt", + "lastName": "Dickerson", + "company": "Lumbrex", + "employed": true + }, + { + "firstName": "Monroe", + "lastName": "Park", + "company": "Letpro", + "employed": true + }, + { + "firstName": "Barbara", + "lastName": "Bishop", + "company": "Maximind", + "employed": false + }, + { + "firstName": "Brandi", + "lastName": "Shaffer", + "company": "Quarx", + "employed": false + }, + { + "firstName": "Martha", + "lastName": "Cantu", + "company": "Enaut", + "employed": true + }, + { + "firstName": "Ronda", + "lastName": "Mcknight", + "company": "Unia", + "employed": false + }, + { + "firstName": "Sanders", + "lastName": "Wilkerson", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Tracey", + "lastName": "Nixon", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Vega", + "lastName": "Brady", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Alexandra", + "lastName": "Spencer", + "company": "Ersum", + "employed": true + }, + { + "firstName": "Jeanne", + "lastName": "Mcintyre", + "company": "Playce", + "employed": false + }, + { + "firstName": "Bettye", + "lastName": "Britt", + "company": "Exoblue", + "employed": false + }, + { + "firstName": "Harvey", + "lastName": "Vega", + "company": "Sulfax", + "employed": true + }, + { + "firstName": "Savage", + "lastName": "Martinez", + "company": "Tropoli", + "employed": false + }, + { + "firstName": "Misty", + "lastName": "Marquez", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Melisa", + "lastName": "Rose", + "company": "Locazone", + "employed": false + }, + { + "firstName": "Trina", + "lastName": "Salas", + "company": "Organica", + "employed": false + }, + { + "firstName": "Martinez", + "lastName": "Bridges", + "company": "Chillium", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Larsen", + "company": "Matrixity", + "employed": true + }, + { + "firstName": "Cheri", + "lastName": "Pratt", + "company": "Asimiline", + "employed": false + }, + { + "firstName": "Christian", + "lastName": "Gaines", + "company": "Geologix", + "employed": true + }, + { + "firstName": "Marsha", + "lastName": "Dudley", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Elinor", + "lastName": "Poole", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Bette", + "lastName": "Strong", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Angelique", + "lastName": "Bird", + "company": "Nikuda", + "employed": true + }, + { + "firstName": "Moody", + "lastName": "Forbes", + "company": "Stockpost", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Good", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Day", + "lastName": "Lane", + "company": "Xleen", + "employed": false + }, + { + "firstName": "Ayala", + "lastName": "Rodriquez", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Ball", + "lastName": "Mcleod", + "company": "Qot", + "employed": false + }, + { + "firstName": "Klein", + "lastName": "Duncan", + "company": "Globoil", + "employed": false + }, + { + "firstName": "Rivas", + "lastName": "Sawyer", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Travis", + "lastName": "Workman", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Chasity", + "lastName": "Hewitt", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Lynch", + "lastName": "Maxwell", + "company": "Comtours", + "employed": false + }, + { + "firstName": "Janice", + "lastName": "Shaw", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Marks", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Clark", + "lastName": "Rivera", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Sheila", + "lastName": "Patrick", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Rose", + "lastName": "Parrish", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Ginger", + "lastName": "Glass", + "company": "Barkarama", + "employed": false + }, + { + "firstName": "Hayden", + "lastName": "Whitley", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Verna", + "lastName": "Fields", + "company": "Comcubine", + "employed": true + }, + { + "firstName": "Daugherty", + "lastName": "Carrillo", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Leblanc", + "lastName": "Hansen", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Ila", + "lastName": "Rodriguez", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Darcy", + "lastName": "Wheeler", + "company": "Sultraxin", + "employed": false + }, + { + "firstName": "Davidson", + "lastName": "Chan", + "company": "Squish", + "employed": true + }, + { + "firstName": "Ester", + "lastName": "Boone", + "company": "Parcoe", + "employed": true + }, + { + "firstName": "Gracie", + "lastName": "Turner", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Selena", + "lastName": "Duke", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Guy", + "lastName": "Miranda", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Louise", + "lastName": "Russo", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Lucia", + "lastName": "Fitzpatrick", + "company": "Cubicide", + "employed": false + }, + { + "firstName": "Shepard", + "lastName": "Lawrence", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Atkinson", + "lastName": "Rodgers", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Lacy", + "lastName": "Valentine", + "company": "Halap", + "employed": false + }, + { + "firstName": "Dianne", + "lastName": "Monroe", + "company": "Naxdis", + "employed": true + }, + { + "firstName": "William", + "lastName": "Mason", + "company": "Sybixtex", + "employed": true + }, + { + "firstName": "Lindsey", + "lastName": "Rogers", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Socorro", + "lastName": "Fulton", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Mccarthy", + "lastName": "Morales", + "company": "Prosely", + "employed": true + }, + { + "firstName": "Meagan", + "lastName": "Hines", + "company": "Netplax", + "employed": true + }, + { + "firstName": "Dorsey", + "lastName": "Guy", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Macdonald", + "lastName": "Dale", + "company": "Rodeology", + "employed": true + }, + { + "firstName": "Katrina", + "lastName": "Curry", + "company": "Amtap", + "employed": true + }, + { + "firstName": "Calhoun", + "lastName": "Golden", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Guerrero", + "lastName": "Beach", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Odessa", + "lastName": "Shields", + "company": "Geekko", + "employed": true + }, + { + "firstName": "Sharron", + "lastName": "Armstrong", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Sheryl", + "lastName": "Morrison", + "company": "Tellifly", + "employed": true + }, + { + "firstName": "Winnie", + "lastName": "Phelps", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Delgado", + "lastName": "Brock", + "company": "Parleynet", + "employed": false + }, + { + "firstName": "Alice", + "lastName": "Webster", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Kennedy", + "lastName": "Baird", + "company": "Imaginart", + "employed": true + }, + { + "firstName": "Fleming", + "lastName": "Barker", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Singleton", + "lastName": "Newman", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Rachel", + "lastName": "Reid", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Bird", + "lastName": "Orr", + "company": "Buzzworks", + "employed": true + }, + { + "firstName": "Castillo", + "lastName": "Hicks", + "company": "Veraq", + "employed": false + }, + { + "firstName": "Mccoy", + "lastName": "Clemons", + "company": "Maxemia", + "employed": true + }, + { + "firstName": "Shawna", + "lastName": "Mcfarland", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Sears", + "lastName": "Kline", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Blanchard", + "lastName": "Sanford", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Natalie", + "lastName": "Lucas", + "company": "Lexicondo", + "employed": true + }, + { + "firstName": "Neal", + "lastName": "Thompson", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Ann", + "lastName": "Owen", + "company": "Pawnagra", + "employed": false + }, + { + "firstName": "Terrell", + "lastName": "Barnett", + "company": "Buzzopia", + "employed": false + }, + { + "firstName": "Kris", + "lastName": "Oconnor", + "company": "Applica", + "employed": false + }, + { + "firstName": "Bonnie", + "lastName": "Yates", + "company": "Crustatia", + "employed": true + }, + { + "firstName": "White", + "lastName": "Cash", + "company": "Roughies", + "employed": false + }, + { + "firstName": "Ramos", + "lastName": "Green", + "company": "Uni", + "employed": true + }, + { + "firstName": "Melody", + "lastName": "Mckee", + "company": "Multiflex", + "employed": true + }, + { + "firstName": "Patrica", + "lastName": "Patterson", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Wise", + "lastName": "Merritt", + "company": "Atomica", + "employed": false + }, + { + "firstName": "Karla", + "lastName": "Schwartz", + "company": "Songbird", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Wilcox", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Susie", + "lastName": "Weaver", + "company": "Imperium", + "employed": true + }, + { + "firstName": "Marissa", + "lastName": "Velasquez", + "company": "Flyboyz", + "employed": false + }, + { + "firstName": "Ward", + "lastName": "Holcomb", + "company": "Icology", + "employed": false + }, + { + "firstName": "Susanne", + "lastName": "Oneil", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Morrow", + "lastName": "Higgins", + "company": "Portico", + "employed": false + }, + { + "firstName": "Joan", + "lastName": "Snider", + "company": "Kongle", + "employed": true + }, + { + "firstName": "Stacey", + "lastName": "Baldwin", + "company": "Velos", + "employed": true + }, + { + "firstName": "Larsen", + "lastName": "Whitney", + "company": "Combogene", + "employed": true + }, + { + "firstName": "Donovan", + "lastName": "Burton", + "company": "Billmed", + "employed": false + }, + { + "firstName": "Browning", + "lastName": "West", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Charmaine", + "lastName": "Suarez", + "company": "Twiggery", + "employed": false + }, + { + "firstName": "Banks", + "lastName": "Weber", + "company": "Furnigeer", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Spence", + "company": "Idealis", + "employed": false + }, + { + "firstName": "Janette", + "lastName": "Short", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Madeleine", + "lastName": "Cooley", + "company": "Xiix", + "employed": true + }, + { + "firstName": "Bowen", + "lastName": "Boyle", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Rice", + "lastName": "Watson", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Gilbert", + "lastName": "Serrano", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Nicole", + "lastName": "Fuller", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Sharpe", + "lastName": "Hendricks", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Barton", + "lastName": "Castaneda", + "company": "Daido", + "employed": false + }, + { + "firstName": "Barber", + "lastName": "Sweet", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Rich", + "lastName": "Watts", + "company": "Gaptec", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Mcintosh", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Casey", + "lastName": "Doyle", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Terri", + "lastName": "Blake", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Kasey", + "lastName": "House", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Monique", + "lastName": "Cherry", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Juanita", + "lastName": "Chambers", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Gertrude", + "lastName": "Huber", + "company": "Zaggles", + "employed": false + }, + { + "firstName": "Mollie", + "lastName": "Macdonald", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Jody", + "lastName": "Prince", + "company": "Austech", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Kelly", + "company": "Musix", + "employed": true + }, + { + "firstName": "Henrietta", + "lastName": "Joyce", + "company": "Endicil", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Head", + "company": "Comtest", + "employed": true + }, + { + "firstName": "Kristi", + "lastName": "Warner", + "company": "Motovate", + "employed": true + }, + { + "firstName": "Curtis", + "lastName": "Manning", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Swanson", + "lastName": "Norris", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Burks", + "lastName": "Rocha", + "company": "Xth", + "employed": false + }, + { + "firstName": "Latasha", + "lastName": "Kemp", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Lorna", + "lastName": "Hill", + "company": "Envire", + "employed": false + }, + { + "firstName": "Lynnette", + "lastName": "Shepherd", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Tamara", + "lastName": "Hutchinson", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Vang", + "lastName": "Vinson", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Stephenson", + "lastName": "Newton", + "company": "Candecor", + "employed": false + }, + { + "firstName": "Robbins", + "lastName": "Morris", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Gallagher", + "lastName": "Cabrera", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Rhodes", + "lastName": "Cortez", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Cassie", + "lastName": "Morin", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Tiffany", + "lastName": "Mccray", + "company": "Zenolux", + "employed": false + }, + { + "firstName": "Carol", + "lastName": "Carey", + "company": "Martgo", + "employed": true + }, + { + "firstName": "Morrison", + "lastName": "Zamora", + "company": "Comvene", + "employed": false + }, + { + "firstName": "Johnston", + "lastName": "Osborn", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Sandra", + "lastName": "Moore", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Dyer", + "company": "Comveyer", + "employed": false + }, + { + "firstName": "Susana", + "lastName": "Case", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Josephine", + "lastName": "Avery", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Ernestine", + "lastName": "Duffy", + "company": "Besto", + "employed": false + }, + { + "firstName": "Shelley", + "lastName": "Gordon", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Regina", + "lastName": "Mcdonald", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Fuentes", + "lastName": "Harrington", + "company": "Supportal", + "employed": false + }, + { + "firstName": "Coleen", + "lastName": "Griffith", + "company": "Zytrax", + "employed": true + }, + { + "firstName": "Riddle", + "lastName": "Chang", + "company": "Zork", + "employed": false + }, + { + "firstName": "Montgomery", + "lastName": "Giles", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Vicky", + "lastName": "Wilkinson", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Luisa", + "lastName": "Henderson", + "company": "Minga", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Garner", + "company": "Waab", + "employed": false + }, + { + "firstName": "Osborne", + "lastName": "Simmons", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Summer", + "lastName": "Clark", + "company": "Interodeo", + "employed": false + }, + { + "firstName": "Valerie", + "lastName": "Stein", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Gilmore", + "lastName": "Buckley", + "company": "Translink", + "employed": true + }, + { + "firstName": "Sophie", + "lastName": "Mayo", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Caldwell", + "lastName": "Wagner", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Sutton", + "lastName": "Andrews", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Reilly", + "lastName": "Steele", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Valdez", + "lastName": "Jensen", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Spence", + "lastName": "Robbins", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Elena", + "lastName": "Luna", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Holly", + "lastName": "Collier", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Mccray", + "lastName": "Roach", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Willa", + "lastName": "Estes", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Deloris", + "lastName": "Briggs", + "company": "Ecosys", + "employed": true + }, + { + "firstName": "Cochran", + "lastName": "Petersen", + "company": "Futurity", + "employed": true + }, + { + "firstName": "Celina", + "lastName": "Gibbs", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Mercedes", + "lastName": "Wooten", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Jacobs", + "lastName": "Montoya", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Delia", + "lastName": "Bowman", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Santos", + "lastName": "Black", + "company": "Earthmark", + "employed": false + }, + { + "firstName": "Imelda", + "lastName": "Conrad", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Lupe", + "lastName": "Branch", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Hughes", + "lastName": "Blanchard", + "company": "Utarian", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Floyd", + "company": "Vortexaco", + "employed": false + }, + { + "firstName": "Joanna", + "lastName": "Cohen", + "company": "Gynko", + "employed": true + }, + { + "firstName": "Chen", + "lastName": "Petty", + "company": "Zentury", + "employed": true + }, + { + "firstName": "Jill", + "lastName": "Ware", + "company": "Terrago", + "employed": true + }, + { + "firstName": "Carver", + "lastName": "Moses", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Sandy", + "lastName": "Lancaster", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Victoria", + "lastName": "Foreman", + "company": "Tropolis", + "employed": true + }, + { + "firstName": "Ayers", + "lastName": "Fischer", + "company": "Andryx", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Nash", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Callie", + "lastName": "Burks", + "company": "Medcom", + "employed": true + }, + { + "firstName": "Farley", + "lastName": "Cunningham", + "company": "Cofine", + "employed": true + }, + { + "firstName": "Mckinney", + "lastName": "Sosa", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Freida", + "lastName": "Hooper", + "company": "Colaire", + "employed": true + }, + { + "firstName": "Carter", + "lastName": "Blair", + "company": "Earwax", + "employed": false + }, + { + "firstName": "Rosanne", + "lastName": "Yang", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Christi", + "lastName": "Rivers", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Riggs", + "lastName": "Oliver", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Hunt", + "lastName": "Fitzgerald", + "company": "Coash", + "employed": true + }, + { + "firstName": "Billie", + "lastName": "Norman", + "company": "Updat", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Woodard", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Eva", + "lastName": "Irwin", + "company": "Housedown", + "employed": false + }, + { + "firstName": "John", + "lastName": "Levine", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Lacey", + "lastName": "Boyer", + "company": "Quizka", + "employed": false + }, + { + "firstName": "Cobb", + "lastName": "Jacobson", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Sherrie", + "lastName": "Gentry", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Fay", + "lastName": "Cain", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Minnie", + "lastName": "Walter", + "company": "Inear", + "employed": false + }, + { + "firstName": "Bond", + "lastName": "Colon", + "company": "Genesynk", + "employed": true + }, + { + "firstName": "Gill", + "lastName": "Villarreal", + "company": "Bitrex", + "employed": true + }, + { + "firstName": "Norton", + "lastName": "Ballard", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Kathleen", + "lastName": "Mendez", + "company": "Mantrix", + "employed": false + }, + { + "firstName": "Byers", + "lastName": "Barron", + "company": "Virva", + "employed": true + }, + { + "firstName": "Alfreda", + "lastName": "Rutledge", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Bradshaw", + "lastName": "Stokes", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Ballard", + "lastName": "Chapman", + "company": "Glukgluk", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Holland", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Lenore", + "lastName": "Le", + "company": "Netropic", + "employed": false + }, + { + "firstName": "Julianne", + "lastName": "Clements", + "company": "Urbanshee", + "employed": false + }, + { + "firstName": "Nelda", + "lastName": "Kidd", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Maryanne", + "lastName": "Bryant", + "company": "Acrodance", + "employed": false + }, + { + "firstName": "Gutierrez", + "lastName": "Bullock", + "company": "Namegen", + "employed": false + }, + { + "firstName": "Wong", + "lastName": "Carter", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Mercado", + "lastName": "Berg", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Mcguire", + "lastName": "Maldonado", + "company": "Geeketron", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Frederick", + "company": "Zaphire", + "employed": true + }, + { + "firstName": "Santiago", + "lastName": "Ingram", + "company": "Gology", + "employed": true + }, + { + "firstName": "Welch", + "lastName": "Mcdaniel", + "company": "Elita", + "employed": false + }, + { + "firstName": "Colon", + "lastName": "Olsen", + "company": "Permadyne", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Anthony", + "company": "Xsports", + "employed": true + }, + { + "firstName": "Tonia", + "lastName": "Daniel", + "company": "Geoforma", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Preston", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Maura", + "lastName": "Delaney", + "company": "Temorak", + "employed": false + }, + { + "firstName": "Dejesus", + "lastName": "Goff", + "company": "Digique", + "employed": true + }, + { + "firstName": "Horne", + "lastName": "Stephens", + "company": "Rodeomad", + "employed": true + }, + { + "firstName": "Carly", + "lastName": "Noble", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Antonia", + "lastName": "Bean", + "company": "Hinway", + "employed": true + }, + { + "firstName": "Goff", + "lastName": "Franks", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Gill", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Jolene", + "lastName": "Rosario", + "company": "Automon", + "employed": false + }, + { + "firstName": "Hazel", + "lastName": "Farley", + "company": "Injoy", + "employed": true + }, + { + "firstName": "Reid", + "lastName": "Rasmussen", + "company": "Entropix", + "employed": false + }, + { + "firstName": "Merritt", + "lastName": "Wallace", + "company": "Terrasys", + "employed": false + }, + { + "firstName": "Hodges", + "lastName": "Carver", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Stafford", + "lastName": "Greer", + "company": "Cyclonica", + "employed": true + }, + { + "firstName": "Sasha", + "lastName": "Ferrell", + "company": "Comvex", + "employed": false + }, + { + "firstName": "Preston", + "lastName": "Mosley", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Moon", + "company": "Kengen", + "employed": false + }, + { + "firstName": "Evangeline", + "lastName": "Mcdowell", + "company": "Anocha", + "employed": false + }, + { + "firstName": "Mcintosh", + "lastName": "Mckee", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Evans", + "lastName": "Mitchell", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Alma", + "lastName": "Chapman", + "company": "Kidstock", + "employed": true + }, + { + "firstName": "Margret", + "lastName": "Franks", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Billie", + "lastName": "Collins", + "company": "Verton", + "employed": true + }, + { + "firstName": "Ginger", + "lastName": "Barr", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Delia", + "lastName": "Delacruz", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Ferguson", + "lastName": "Atkinson", + "company": "Cinaster", + "employed": true + }, + { + "firstName": "Barbara", + "lastName": "Carroll", + "company": "Biotica", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Richmond", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Cristina", + "lastName": "Graves", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Melissa", + "lastName": "Miranda", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Morse", + "lastName": "Albert", + "company": "Squish", + "employed": true + }, + { + "firstName": "Kristine", + "lastName": "Leblanc", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "George", + "lastName": "England", + "company": "Kraggle", + "employed": true + }, + { + "firstName": "Della", + "lastName": "Ramos", + "company": "Oulu", + "employed": true + }, + { + "firstName": "Gamble", + "lastName": "Bauer", + "company": "Prosely", + "employed": false + }, + { + "firstName": "Cheri", + "lastName": "Farley", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Deidre", + "lastName": "Eaton", + "company": "Entality", + "employed": true + }, + { + "firstName": "Hancock", + "lastName": "Johns", + "company": "Uni", + "employed": false + }, + { + "firstName": "Andrews", + "lastName": "Soto", + "company": "Extro", + "employed": false + }, + { + "firstName": "Cleo", + "lastName": "Riggs", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Margaret", + "lastName": "Bennett", + "company": "Netility", + "employed": false + }, + { + "firstName": "Gwendolyn", + "lastName": "Romero", + "company": "Extrawear", + "employed": true + }, + { + "firstName": "Donovan", + "lastName": "Simpson", + "company": "Mantrix", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "Young", + "company": "Ecstasia", + "employed": true + }, + { + "firstName": "Marla", + "lastName": "Byers", + "company": "Panzent", + "employed": false + }, + { + "firstName": "Cochran", + "lastName": "Hatfield", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Garner", + "lastName": "Mercer", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Doyle", + "lastName": "Winters", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "French", + "lastName": "Turner", + "company": "Puria", + "employed": true + }, + { + "firstName": "Carolina", + "lastName": "Reilly", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Pugh", + "lastName": "Jacobs", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Patrick", + "lastName": "Roberson", + "company": "Luxuria", + "employed": false + }, + { + "firstName": "Head", + "lastName": "Hicks", + "company": "Rockabye", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "White", + "company": "Quadeebo", + "employed": false + }, + { + "firstName": "Roberta", + "lastName": "Wade", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Kellie", + "lastName": "Cantrell", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Kline", + "lastName": "Powell", + "company": "Utara", + "employed": true + }, + { + "firstName": "Talley", + "lastName": "Crawford", + "company": "Plasmosis", + "employed": true + }, + { + "firstName": "Margarita", + "lastName": "Rogers", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Deborah", + "lastName": "Vincent", + "company": "Vinch", + "employed": true + }, + { + "firstName": "Lowe", + "lastName": "Townsend", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Maricela", + "lastName": "Waters", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Imogene", + "lastName": "Mcconnell", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Roy", + "lastName": "Mcneil", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Gould", + "lastName": "Hill", + "company": "Viagreat", + "employed": true + }, + { + "firstName": "Carson", + "lastName": "Monroe", + "company": "Animalia", + "employed": true + }, + { + "firstName": "Horton", + "lastName": "Sharpe", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Sykes", + "lastName": "Gray", + "company": "Ovolo", + "employed": false + }, + { + "firstName": "Burks", + "lastName": "Mendez", + "company": "Hopeli", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Pennington", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Laverne", + "lastName": "Hayden", + "company": "Olympix", + "employed": false + }, + { + "firstName": "Park", + "lastName": "Farmer", + "company": "Rodemco", + "employed": false + }, + { + "firstName": "Erma", + "lastName": "Marks", + "company": "Rameon", + "employed": true + }, + { + "firstName": "Dennis", + "lastName": "Martin", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Mcguire", + "lastName": "Mathews", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Fischer", + "lastName": "Cash", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Copeland", + "lastName": "Yates", + "company": "Bristo", + "employed": false + }, + { + "firstName": "Lesley", + "lastName": "Berry", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Natalia", + "lastName": "Bush", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Letha", + "lastName": "Suarez", + "company": "Darwinium", + "employed": false + }, + { + "firstName": "Bettye", + "lastName": "Frederick", + "company": "Futuris", + "employed": false + }, + { + "firstName": "Janell", + "lastName": "Pollard", + "company": "Comverges", + "employed": false + }, + { + "firstName": "Roxanne", + "lastName": "Dickerson", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Cunningham", + "lastName": "Copeland", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Stacey", + "lastName": "Cook", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Briggs", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Robyn", + "lastName": "Giles", + "company": "Viagrand", + "employed": true + }, + { + "firstName": "Emma", + "lastName": "Stevens", + "company": "Centice", + "employed": true + }, + { + "firstName": "Polly", + "lastName": "Estes", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Arnold", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Orr", + "lastName": "Becker", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Phelps", + "lastName": "Guy", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Augusta", + "lastName": "Contreras", + "company": "Ludak", + "employed": false + }, + { + "firstName": "Roberson", + "lastName": "Sanchez", + "company": "Cytrex", + "employed": true + }, + { + "firstName": "Curtis", + "lastName": "Clarke", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Theresa", + "lastName": "Baldwin", + "company": "Mitroc", + "employed": false + }, + { + "firstName": "Mai", + "lastName": "Michael", + "company": "Flotonic", + "employed": false + }, + { + "firstName": "Patti", + "lastName": "Peters", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Mejia", + "lastName": "Ramirez", + "company": "Konnect", + "employed": false + }, + { + "firstName": "Quinn", + "lastName": "Coffey", + "company": "Radiantix", + "employed": false + }, + { + "firstName": "Alice", + "lastName": "Harmon", + "company": "Premiant", + "employed": true + }, + { + "firstName": "Jean", + "lastName": "Sweeney", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Mabel", + "lastName": "Peterson", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Judy", + "lastName": "Dickson", + "company": "Anixang", + "employed": true + }, + { + "firstName": "Henry", + "lastName": "Perry", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Cecelia", + "lastName": "Day", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Robbins", + "lastName": "Kirby", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Patsy", + "lastName": "Hobbs", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Loretta", + "lastName": "Mcmahon", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Anita", + "lastName": "Gibson", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Fuentes", + "lastName": "Harris", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Reid", + "lastName": "Ortiz", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Angelica", + "lastName": "Sears", + "company": "Powernet", + "employed": true + }, + { + "firstName": "Christi", + "lastName": "Rodriguez", + "company": "Insurity", + "employed": false + }, + { + "firstName": "Anderson", + "lastName": "Bolton", + "company": "Phormula", + "employed": false + }, + { + "firstName": "Mccullough", + "lastName": "Palmer", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Alexander", + "lastName": "Perez", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Luann", + "lastName": "Rush", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Villarreal", + "lastName": "Avila", + "company": "Undertap", + "employed": false + }, + { + "firstName": "Parks", + "lastName": "Morse", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Jeannine", + "lastName": "Mullins", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Ester", + "lastName": "Levine", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Harvey", + "company": "Applidec", + "employed": true + }, + { + "firstName": "Deleon", + "lastName": "Hunt", + "company": "Imkan", + "employed": false + }, + { + "firstName": "Wood", + "lastName": "Moreno", + "company": "Codact", + "employed": true + }, + { + "firstName": "Forbes", + "lastName": "Craft", + "company": "Sarasonic", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Padilla", + "company": "Gynko", + "employed": false + }, + { + "firstName": "Thornton", + "lastName": "Sparks", + "company": "Extragene", + "employed": true + }, + { + "firstName": "Sheppard", + "lastName": "Barlow", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Violet", + "lastName": "Dodson", + "company": "Netur", + "employed": true + }, + { + "firstName": "Buckley", + "lastName": "Salas", + "company": "Oceanica", + "employed": true + }, + { + "firstName": "Rosales", + "lastName": "Clements", + "company": "Apexia", + "employed": false + }, + { + "firstName": "Monique", + "lastName": "Alvarado", + "company": "Spacewax", + "employed": true + }, + { + "firstName": "Mack", + "lastName": "Phelps", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Genevieve", + "lastName": "Munoz", + "company": "Gaptec", + "employed": false + }, + { + "firstName": "Eaton", + "lastName": "Anderson", + "company": "Interfind", + "employed": true + }, + { + "firstName": "England", + "lastName": "Mccoy", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Russell", + "lastName": "Harrington", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Sargent", + "lastName": "Lowery", + "company": "Sealoud", + "employed": false + }, + { + "firstName": "Gail", + "lastName": "Barton", + "company": "Coash", + "employed": false + }, + { + "firstName": "Juliette", + "lastName": "Guerra", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Travis", + "lastName": "Hopkins", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Jill", + "lastName": "Burris", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Rios", + "lastName": "Aguilar", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Mays", + "lastName": "Booker", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Sheila", + "lastName": "Duncan", + "company": "Acruex", + "employed": false + }, + { + "firstName": "Hobbs", + "lastName": "Cox", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Sharpe", + "lastName": "Barker", + "company": "Qot", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Simmons", + "company": "Genesynk", + "employed": false + }, + { + "firstName": "Clarke", + "lastName": "Merrill", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Jerry", + "lastName": "Mclaughlin", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Dominguez", + "lastName": "Stark", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Conway", + "lastName": "May", + "company": "Zillacon", + "employed": true + }, + { + "firstName": "Tiffany", + "lastName": "Mayo", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Carmella", + "lastName": "Humphrey", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Casandra", + "lastName": "Goodwin", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Francine", + "lastName": "Emerson", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Gallagher", + "lastName": "Trevino", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Hunter", + "lastName": "Terrell", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Janis", + "lastName": "Garrett", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Holmes", + "lastName": "Wright", + "company": "Tingles", + "employed": false + }, + { + "firstName": "Lois", + "lastName": "Ware", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Misty", + "lastName": "Velez", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Huffman", + "lastName": "Mcfadden", + "company": "Nurplex", + "employed": true + }, + { + "firstName": "Mara", + "lastName": "Atkins", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Earnestine", + "lastName": "Wheeler", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Hunt", + "lastName": "Lloyd", + "company": "Sustenza", + "employed": true + }, + { + "firstName": "Esther", + "lastName": "Travis", + "company": "Nixelt", + "employed": false + }, + { + "firstName": "Maddox", + "lastName": "Jefferson", + "company": "Quiltigen", + "employed": false + }, + { + "firstName": "Conley", + "lastName": "Maldonado", + "company": "Tellifly", + "employed": true + }, + { + "firstName": "Julia", + "lastName": "Spencer", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Franklin", + "lastName": "Donaldson", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Blackwell", + "lastName": "Booth", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Elva", + "lastName": "Gilbert", + "company": "Imaginart", + "employed": true + }, + { + "firstName": "Berger", + "lastName": "Moran", + "company": "Tasmania", + "employed": false + }, + { + "firstName": "Stokes", + "lastName": "Patton", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Caroline", + "lastName": "Bell", + "company": "Geeky", + "employed": false + }, + { + "firstName": "Rutledge", + "lastName": "Jordan", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Stephens", + "lastName": "Orr", + "company": "Comstruct", + "employed": true + }, + { + "firstName": "Giles", + "lastName": "Kennedy", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Cain", + "lastName": "Davidson", + "company": "Zilodyne", + "employed": false + }, + { + "firstName": "Graves", + "lastName": "Hester", + "company": "Xurban", + "employed": false + }, + { + "firstName": "Jenny", + "lastName": "Kane", + "company": "Updat", + "employed": false + }, + { + "firstName": "Silvia", + "lastName": "Wilcox", + "company": "Kage", + "employed": true + }, + { + "firstName": "Valentine", + "lastName": "Kirkland", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "David", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Hinton", + "lastName": "Irwin", + "company": "Magnafone", + "employed": false + }, + { + "firstName": "Suzanne", + "lastName": "Garrison", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Bernadette", + "lastName": "Duffy", + "company": "Kangle", + "employed": false + }, + { + "firstName": "Madden", + "lastName": "Curry", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Mcconnell", + "lastName": "Mcclure", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Fanny", + "lastName": "Moon", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Holly", + "lastName": "Le", + "company": "Zilla", + "employed": false + }, + { + "firstName": "Campbell", + "lastName": "Weeks", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Lott", + "lastName": "Cooke", + "company": "Magneato", + "employed": false + }, + { + "firstName": "Wilkins", + "lastName": "Valdez", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Tanya", + "lastName": "Stephenson", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Nash", + "lastName": "Watkins", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Lorena", + "lastName": "Chaney", + "company": "Krog", + "employed": false + }, + { + "firstName": "Hallie", + "lastName": "Nelson", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Judith", + "lastName": "Whitaker", + "company": "Matrixity", + "employed": false + }, + { + "firstName": "Waters", + "lastName": "Lester", + "company": "Ecolight", + "employed": false + }, + { + "firstName": "Carmen", + "lastName": "Taylor", + "company": "Marketoid", + "employed": true + }, + { + "firstName": "Oliver", + "lastName": "Greer", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Allen", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Wagner", + "lastName": "Moss", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Cortez", + "lastName": "Heath", + "company": "Zytrek", + "employed": false + }, + { + "firstName": "Best", + "lastName": "Ramsey", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Vang", + "lastName": "Bullock", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Nancy", + "lastName": "Talley", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Jaclyn", + "lastName": "Wood", + "company": "Fuelton", + "employed": false + }, + { + "firstName": "Glenna", + "lastName": "Campos", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Tessa", + "lastName": "Jenkins", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Molly", + "lastName": "Huff", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Mcmahon", + "lastName": "Crosby", + "company": "Daido", + "employed": true + }, + { + "firstName": "Dorothea", + "lastName": "Bean", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Penelope", + "lastName": "Carpenter", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Terri", + "lastName": "Christian", + "company": "Unia", + "employed": false + }, + { + "firstName": "Lidia", + "lastName": "Garza", + "company": "Terrago", + "employed": false + }, + { + "firstName": "Klein", + "lastName": "Ford", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Jeanie", + "lastName": "Fry", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Leonor", + "lastName": "Stokes", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Evelyn", + "lastName": "Harrison", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Adams", + "lastName": "Sanford", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Monica", + "lastName": "Powers", + "company": "Glasstep", + "employed": false + }, + { + "firstName": "Nieves", + "lastName": "Mccarty", + "company": "Xyqag", + "employed": false + }, + { + "firstName": "Brandie", + "lastName": "Gordon", + "company": "Miraclis", + "employed": false + }, + { + "firstName": "Alexis", + "lastName": "Hunter", + "company": "Quilm", + "employed": false + }, + { + "firstName": "Lynne", + "lastName": "Morris", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "Conway", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Justice", + "lastName": "Parker", + "company": "Corporana", + "employed": false + }, + { + "firstName": "Harmon", + "lastName": "Hayes", + "company": "Songlines", + "employed": true + }, + { + "firstName": "Massey", + "lastName": "Walters", + "company": "Fanfare", + "employed": false + }, + { + "firstName": "Gabriela", + "lastName": "Edwards", + "company": "Medcom", + "employed": true + }, + { + "firstName": "Alberta", + "lastName": "Stout", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Traci", + "lastName": "Vega", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Saundra", + "lastName": "Mcleod", + "company": "Nikuda", + "employed": true + }, + { + "firstName": "Sonia", + "lastName": "Gillespie", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Rosie", + "lastName": "Potter", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "Isabel", + "lastName": "Bradford", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Battle", + "lastName": "Serrano", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Jolene", + "lastName": "Schroeder", + "company": "Artworlds", + "employed": true + }, + { + "firstName": "Whitehead", + "lastName": "Vaughan", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Barker", + "lastName": "Keller", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Armstrong", + "lastName": "Reyes", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Althea", + "lastName": "Hooper", + "company": "Geekmosis", + "employed": true + }, + { + "firstName": "Dalton", + "lastName": "Lindsay", + "company": "Gushkool", + "employed": true + }, + { + "firstName": "Parsons", + "lastName": "Carey", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Frye", + "lastName": "Gardner", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Fisher", + "lastName": "Carr", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Goodman", + "lastName": "Rose", + "company": "Daisu", + "employed": false + }, + { + "firstName": "Cassie", + "lastName": "Henderson", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Bridgett", + "lastName": "Hampton", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Bruce", + "lastName": "Pearson", + "company": "Furnafix", + "employed": false + }, + { + "firstName": "May", + "lastName": "Fulton", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Maribel", + "lastName": "Weaver", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Robert", + "lastName": "Russell", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Webb", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Lawrence", + "lastName": "Nguyen", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Boyle", + "lastName": "Blackwell", + "company": "Genmy", + "employed": true + }, + { + "firstName": "Kathie", + "lastName": "Bray", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Hayden", + "lastName": "Marsh", + "company": "Quizka", + "employed": true + }, + { + "firstName": "Vance", + "lastName": "Calhoun", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Kasey", + "lastName": "Ayers", + "company": "Temorak", + "employed": false + }, + { + "firstName": "Leticia", + "lastName": "Buckner", + "company": "Quinex", + "employed": false + }, + { + "firstName": "Lola", + "lastName": "Lynch", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Marquez", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Carole", + "lastName": "Gonzales", + "company": "Xinware", + "employed": false + }, + { + "firstName": "Moody", + "lastName": "Greene", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Michael", + "lastName": "Ray", + "company": "Vurbo", + "employed": true + }, + { + "firstName": "Charles", + "lastName": "Lamb", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Iris", + "lastName": "Gilliam", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Lora", + "lastName": "Silva", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Betty", + "lastName": "Kline", + "company": "Zytrax", + "employed": false + }, + { + "firstName": "Mccarthy", + "lastName": "Figueroa", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Kerri", + "lastName": "Workman", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Taylor", + "lastName": "Jennings", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Benson", + "lastName": "Kidd", + "company": "Enthaze", + "employed": false + }, + { + "firstName": "Hutchinson", + "lastName": "Price", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Etta", + "lastName": "Ochoa", + "company": "Mantro", + "employed": false + }, + { + "firstName": "Ashlee", + "lastName": "Cleveland", + "company": "Indexia", + "employed": false + }, + { + "firstName": "Ellis", + "lastName": "Lucas", + "company": "Avit", + "employed": false + }, + { + "firstName": "Lawson", + "lastName": "Stanton", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Joanne", + "lastName": "Pace", + "company": "Bolax", + "employed": false + }, + { + "firstName": "Spencer", + "lastName": "Fischer", + "company": "Silodyne", + "employed": false + }, + { + "firstName": "Mae", + "lastName": "Bernard", + "company": "Euron", + "employed": true + }, + { + "firstName": "Kaufman", + "lastName": "Waller", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "May", + "lastName": "Bailey", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Fry", + "lastName": "Short", + "company": "Isis", + "employed": false + }, + { + "firstName": "Elisa", + "lastName": "Strong", + "company": "Perkle", + "employed": true + }, + { + "firstName": "Barron", + "lastName": "Long", + "company": "Magnemo", + "employed": true + }, + { + "firstName": "Dixon", + "lastName": "Fitzpatrick", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Katheryn", + "lastName": "Maddox", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Welch", + "lastName": "Delaney", + "company": "Micronaut", + "employed": true + }, + { + "firstName": "Kate", + "lastName": "Wall", + "company": "Telpod", + "employed": true + }, + { + "firstName": "Jessica", + "lastName": "Maynard", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Elba", + "lastName": "Thornton", + "company": "Cofine", + "employed": true + }, + { + "firstName": "Abbott", + "lastName": "Dominguez", + "company": "Netbook", + "employed": false + }, + { + "firstName": "Paulette", + "lastName": "Horton", + "company": "Turnling", + "employed": false + }, + { + "firstName": "Susanne", + "lastName": "Bentley", + "company": "Turnabout", + "employed": false + }, + { + "firstName": "Tamra", + "lastName": "Thomas", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Ophelia", + "lastName": "Lopez", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Alyson", + "lastName": "Hawkins", + "company": "Ozean", + "employed": false + }, + { + "firstName": "Ila", + "lastName": "Riley", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Francisca", + "lastName": "Mckinney", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Mann", + "lastName": "Owens", + "company": "Digigene", + "employed": true + }, + { + "firstName": "Torres", + "lastName": "Kerr", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Padilla", + "lastName": "Dillon", + "company": "Imageflow", + "employed": false + }, + { + "firstName": "Beasley", + "lastName": "Warren", + "company": "Megall", + "employed": true + }, + { + "firstName": "Castillo", + "lastName": "Bruce", + "company": "Stucco", + "employed": true + }, + { + "firstName": "Magdalena", + "lastName": "Santos", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Desiree", + "lastName": "Cardenas", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Kirby", + "lastName": "Hancock", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Hart", + "lastName": "Lane", + "company": "Bostonic", + "employed": true + }, + { + "firstName": "Poole", + "lastName": "Mullen", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Caitlin", + "lastName": "Vaughn", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Mcknight", + "lastName": "Kirk", + "company": "Geoforma", + "employed": true + }, + { + "firstName": "Phyllis", + "lastName": "Mccormick", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Reyes", + "lastName": "Valenzuela", + "company": "Boink", + "employed": true + }, + { + "firstName": "Leanne", + "lastName": "Bass", + "company": "Enquility", + "employed": false + }, + { + "firstName": "Flynn", + "lastName": "Oliver", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Katy", + "lastName": "Schultz", + "company": "Zillacom", + "employed": true + }, + { + "firstName": "Ruthie", + "lastName": "Grimes", + "company": "Strozen", + "employed": true + }, + { + "firstName": "Chelsea", + "lastName": "Berger", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Camille", + "lastName": "Fleming", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Helene", + "lastName": "Meadows", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Jodi", + "lastName": "Mcintosh", + "company": "Emergent", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Keith", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Lamb", + "lastName": "Mcguire", + "company": "Flum", + "employed": true + }, + { + "firstName": "Strong", + "lastName": "Bates", + "company": "Quility", + "employed": true + }, + { + "firstName": "Krista", + "lastName": "Hyde", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Thomas", + "lastName": "Smith", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Beatrice", + "lastName": "Spears", + "company": "Exposa", + "employed": false + }, + { + "firstName": "Tabatha", + "lastName": "Nichols", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Dee", + "lastName": "Dixon", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Brewer", + "lastName": "Bowen", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Soto", + "lastName": "Whitehead", + "company": "Aquacine", + "employed": true + }, + { + "firstName": "Walters", + "lastName": "Nunez", + "company": "Endicil", + "employed": true + }, + { + "firstName": "Nelson", + "lastName": "Kinney", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Donna", + "lastName": "Weiss", + "company": "Datagene", + "employed": true + }, + { + "firstName": "Neva", + "lastName": "Rosales", + "company": "Terascape", + "employed": false + }, + { + "firstName": "Flores", + "lastName": "Sweet", + "company": "Pigzart", + "employed": true + }, + { + "firstName": "Kim", + "lastName": "Manning", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Crosby", + "lastName": "Russo", + "company": "Xleen", + "employed": false + }, + { + "firstName": "Hester", + "lastName": "Rhodes", + "company": "Zisis", + "employed": true + }, + { + "firstName": "Allison", + "lastName": "Sexton", + "company": "Iplax", + "employed": true + }, + { + "firstName": "Leola", + "lastName": "Owen", + "company": "Sonique", + "employed": false + }, + { + "firstName": "Patty", + "lastName": "Randolph", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Laurel", + "lastName": "Cohen", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Rhodes", + "lastName": "Holman", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Angelita", + "lastName": "Browning", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Chase", + "lastName": "Dillard", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Graciela", + "lastName": "Santiago", + "company": "Nexgene", + "employed": true + }, + { + "firstName": "Louise", + "lastName": "Richards", + "company": "Ginkogene", + "employed": true + }, + { + "firstName": "Pate", + "lastName": "Huffman", + "company": "Mobildata", + "employed": false + }, + { + "firstName": "Richmond", + "lastName": "Castro", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Cassandra", + "lastName": "Lyons", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Porter", + "lastName": "Combs", + "company": "Xth", + "employed": true + }, + { + "firstName": "Norman", + "lastName": "Meyers", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Fletcher", + "lastName": "Lindsey", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Harriet", + "lastName": "Justice", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Mcleod", + "lastName": "Summers", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Debora", + "lastName": "Obrien", + "company": "Stockpost", + "employed": true + }, + { + "firstName": "Moreno", + "lastName": "Watson", + "company": "Idego", + "employed": true + }, + { + "firstName": "Tommie", + "lastName": "Carney", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Wooten", + "lastName": "Fox", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Higgins", + "lastName": "Pate", + "company": "Securia", + "employed": false + }, + { + "firstName": "Sampson", + "lastName": "Dunn", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Dona", + "lastName": "Dorsey", + "company": "Digial", + "employed": false + }, + { + "firstName": "Erna", + "lastName": "Rodriquez", + "company": "Essensia", + "employed": true + }, + { + "firstName": "Daugherty", + "lastName": "Stevenson", + "company": "Waretel", + "employed": true + }, + { + "firstName": "Hodges", + "lastName": "Hull", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Whitley", + "lastName": "Brock", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Crystal", + "lastName": "Coleman", + "company": "Menbrain", + "employed": true + }, + { + "firstName": "Jacobson", + "lastName": "Bowman", + "company": "Synkgen", + "employed": true + }, + { + "firstName": "Dotson", + "lastName": "Hudson", + "company": "Comtours", + "employed": true + }, + { + "firstName": "Hilda", + "lastName": "Hale", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Lenora", + "lastName": "Holder", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Cooley", + "lastName": "Burns", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Shannon", + "lastName": "Collier", + "company": "Elita", + "employed": true + }, + { + "firstName": "Sparks", + "lastName": "Singleton", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Beck", + "lastName": "Olson", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Glenn", + "company": "Verbus", + "employed": true + }, + { + "firstName": "Beverley", + "lastName": "Pena", + "company": "Niquent", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Kramer", + "company": "Velity", + "employed": true + }, + { + "firstName": "Valarie", + "lastName": "Rosa", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Mason", + "lastName": "Hubbard", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Juanita", + "lastName": "Cooper", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Eugenia", + "lastName": "Stanley", + "company": "Geekko", + "employed": true + }, + { + "firstName": "Trujillo", + "lastName": "Mcgee", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Kendra", + "lastName": "Freeman", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Wyatt", + "lastName": "Baker", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Blevins", + "lastName": "Montoya", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Morrow", + "lastName": "Murphy", + "company": "Vertide", + "employed": false + }, + { + "firstName": "Mathis", + "lastName": "French", + "company": "Qnekt", + "employed": false + }, + { + "firstName": "Bertie", + "lastName": "Sampson", + "company": "Vidto", + "employed": false + }, + { + "firstName": "Mildred", + "lastName": "Duran", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Bianca", + "lastName": "Little", + "company": "Tubalum", + "employed": false + }, + { + "firstName": "Davis", + "lastName": "Abbott", + "company": "Steelfab", + "employed": true + }, + { + "firstName": "Crawford", + "lastName": "Mueller", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Estela", + "lastName": "Robertson", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Dodson", + "lastName": "Wise", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Holman", + "lastName": "Pratt", + "company": "Kenegy", + "employed": true + }, + { + "firstName": "Tillman", + "lastName": "Davis", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Adrienne", + "lastName": "Osborne", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Margery", + "lastName": "Snow", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Meadows", + "lastName": "Acosta", + "company": "Xumonk", + "employed": true + }, + { + "firstName": "Deann", + "lastName": "Mack", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Tia", + "lastName": "Baird", + "company": "Koffee", + "employed": false + }, + { + "firstName": "Webb", + "lastName": "Macias", + "company": "Combogen", + "employed": true + }, + { + "firstName": "Concetta", + "lastName": "Skinner", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Adriana", + "lastName": "Cole", + "company": "Zaj", + "employed": false + }, + { + "firstName": "Carrie", + "lastName": "Preston", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Luella", + "lastName": "Armstrong", + "company": "Comstar", + "employed": true + }, + { + "firstName": "Wells", + "lastName": "Daniel", + "company": "Maximind", + "employed": true + }, + { + "firstName": "Helen", + "lastName": "Ashley", + "company": "Fleetmix", + "employed": true + }, + { + "firstName": "Murray", + "lastName": "Walter", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Sharlene", + "lastName": "Roth", + "company": "Volax", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Harding", + "company": "Translink", + "employed": true + }, + { + "firstName": "Carr", + "lastName": "Walsh", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Candace", + "lastName": "Hart", + "company": "Digique", + "employed": true + }, + { + "firstName": "Randi", + "lastName": "Durham", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Dawn", + "lastName": "Cote", + "company": "Yurture", + "employed": true + }, + { + "firstName": "Jackie", + "lastName": "Casey", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Mcmillan", + "company": "Orbalix", + "employed": true + }, + { + "firstName": "Vicky", + "lastName": "Middleton", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Jennie", + "lastName": "Macdonald", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Mavis", + "lastName": "Hammond", + "company": "Elemantra", + "employed": true + }, + { + "firstName": "Mueller", + "lastName": "Sheppard", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Emily", + "lastName": "Davenport", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Christensen", + "lastName": "Mann", + "company": "Incubus", + "employed": false + }, + { + "firstName": "Cantrell", + "lastName": "Moses", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Lancaster", + "lastName": "Mills", + "company": "Assistix", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Santana", + "company": "Uxmox", + "employed": true + }, + { + "firstName": "Pollard", + "lastName": "Bryan", + "company": "Deviltoe", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Mcbride", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Sonya", + "lastName": "Espinoza", + "company": "Goko", + "employed": false + }, + { + "firstName": "Hansen", + "lastName": "Glover", + "company": "Columella", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Calderon", + "company": "Wrapture", + "employed": true + }, + { + "firstName": "Aileen", + "lastName": "Rich", + "company": "Architax", + "employed": false + }, + { + "firstName": "Brady", + "lastName": "Pope", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Hammond", + "lastName": "Cherry", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Frieda", + "lastName": "Trujillo", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Gordon", + "lastName": "Benson", + "company": "Providco", + "employed": false + }, + { + "firstName": "Beach", + "lastName": "Dale", + "company": "Makingway", + "employed": false + }, + { + "firstName": "Guerra", + "lastName": "Sandoval", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Arlene", + "lastName": "Golden", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Jami", + "lastName": "Ellis", + "company": "Gorganic", + "employed": true + }, + { + "firstName": "Brennan", + "lastName": "Sanders", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Shari", + "lastName": "Craig", + "company": "Krag", + "employed": true + }, + { + "firstName": "Jody", + "lastName": "Gates", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Erickson", + "lastName": "Gomez", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Harriett", + "lastName": "Gutierrez", + "company": "Minga", + "employed": true + }, + { + "firstName": "Goodwin", + "lastName": "Galloway", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Pacheco", + "lastName": "Cruz", + "company": "Reversus", + "employed": true + }, + { + "firstName": "June", + "lastName": "Peck", + "company": "Grok", + "employed": false + }, + { + "firstName": "Navarro", + "lastName": "Burch", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Irwin", + "lastName": "Bender", + "company": "Codax", + "employed": false + }, + { + "firstName": "Alba", + "lastName": "Gay", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Patrica", + "lastName": "Deleon", + "company": "Xanide", + "employed": true + }, + { + "firstName": "Shields", + "lastName": "Finch", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Selena", + "lastName": "Mcclain", + "company": "Izzby", + "employed": true + }, + { + "firstName": "Tyler", + "lastName": "Garner", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Dina", + "lastName": "Mercado", + "company": "Virva", + "employed": true + }, + { + "firstName": "Mcdowell", + "lastName": "Tran", + "company": "Cuizine", + "employed": false + }, + { + "firstName": "Stephanie", + "lastName": "Norman", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Gamble", + "company": "Comvoy", + "employed": true + }, + { + "firstName": "Clayton", + "lastName": "Ward", + "company": "Everest", + "employed": true + }, + { + "firstName": "Angelique", + "lastName": "Nieves", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Eileen", + "lastName": "Livingston", + "company": "Gleamink", + "employed": true + }, + { + "firstName": "Paul", + "lastName": "Carter", + "company": "Klugger", + "employed": false + }, + { + "firstName": "Pearlie", + "lastName": "Austin", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Flora", + "lastName": "Mcdowell", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Daniels", + "lastName": "Tanner", + "company": "Inventure", + "employed": false + }, + { + "firstName": "Jackson", + "lastName": "Chavez", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Benita", + "lastName": "Ballard", + "company": "Retrotex", + "employed": true + }, + { + "firstName": "Franks", + "lastName": "Pitts", + "company": "Envire", + "employed": true + }, + { + "firstName": "Cynthia", + "lastName": "Ortega", + "company": "Zerology", + "employed": false + }, + { + "firstName": "Rice", + "lastName": "Haley", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Peggy", + "lastName": "Rivers", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Payne", + "lastName": "Beck", + "company": "Sulfax", + "employed": false + }, + { + "firstName": "Socorro", + "lastName": "Underwood", + "company": "Mediot", + "employed": false + }, + { + "firstName": "Frazier", + "lastName": "Patterson", + "company": "Cablam", + "employed": false + }, + { + "firstName": "Janie", + "lastName": "Frank", + "company": "Flexigen", + "employed": false + }, + { + "firstName": "Hood", + "lastName": "Vinson", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Nolan", + "lastName": "Sloan", + "company": "Geekwagon", + "employed": true + }, + { + "firstName": "Gomez", + "lastName": "Quinn", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Shanna", + "lastName": "Beard", + "company": "Multron", + "employed": false + }, + { + "firstName": "Dora", + "lastName": "Blanchard", + "company": "Quailcom", + "employed": false + }, + { + "firstName": "Roxie", + "lastName": "Jacobson", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Addie", + "lastName": "Goodman", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Humphrey", + "lastName": "Tyler", + "company": "Enjola", + "employed": true + }, + { + "firstName": "Page", + "lastName": "Valencia", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Davenport", + "lastName": "Slater", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Mcpherson", + "lastName": "Bradley", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Hendricks", + "lastName": "Carson", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Oconnor", + "lastName": "Dotson", + "company": "Aquoavo", + "employed": true + }, + { + "firstName": "Preston", + "lastName": "Flowers", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Morgan", + "lastName": "Griffith", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Corinne", + "lastName": "Avery", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Hyde", + "lastName": "Glass", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Samantha", + "lastName": "Barrett", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Gregory", + "lastName": "Shelton", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "Walls", + "lastName": "Ewing", + "company": "Anocha", + "employed": false + }, + { + "firstName": "Jodie", + "lastName": "Wilkins", + "company": "Atomica", + "employed": false + }, + { + "firstName": "Branch", + "lastName": "Alston", + "company": "Photobin", + "employed": false + }, + { + "firstName": "Carol", + "lastName": "Joyner", + "company": "Supremia", + "employed": false + }, + { + "firstName": "Parker", + "lastName": "Wiley", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Vonda", + "lastName": "Pugh", + "company": "Sentia", + "employed": true + }, + { + "firstName": "Betsy", + "lastName": "Benjamin", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Milagros", + "lastName": "Langley", + "company": "Savvy", + "employed": true + }, + { + "firstName": "Bird", + "lastName": "Huber", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Pearl", + "lastName": "Bartlett", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Sherry", + "lastName": "Hamilton", + "company": "Comveyor", + "employed": false + }, + { + "firstName": "Jo", + "lastName": "Reed", + "company": "Quarex", + "employed": true + }, + { + "firstName": "Clarice", + "lastName": "Potts", + "company": "Crustatia", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Howell", + "company": "Memora", + "employed": false + }, + { + "firstName": "Summers", + "lastName": "Cummings", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Newman", + "lastName": "Carrillo", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Jennings", + "lastName": "Warner", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Hines", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Haynes", + "lastName": "Wong", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Mayo", + "lastName": "Garcia", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Kara", + "lastName": "Sosa", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Herring", + "company": "Tropolis", + "employed": true + }, + { + "firstName": "Olson", + "lastName": "Frye", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Brittney", + "lastName": "Diaz", + "company": "Xoggle", + "employed": false + }, + { + "firstName": "Vickie", + "lastName": "Rutledge", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Ann", + "lastName": "Mays", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Elinor", + "lastName": "Rojas", + "company": "Zyple", + "employed": false + }, + { + "firstName": "Bartlett", + "lastName": "Rivera", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Marjorie", + "lastName": "Alford", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Hoffman", + "lastName": "Wiggins", + "company": "Stralum", + "employed": false + }, + { + "firstName": "Amparo", + "lastName": "Henson", + "company": "Acium", + "employed": true + }, + { + "firstName": "Melisa", + "lastName": "Boyle", + "company": "Talae", + "employed": false + }, + { + "firstName": "Bass", + "lastName": "Cochran", + "company": "Voratak", + "employed": false + }, + { + "firstName": "Jones", + "lastName": "Parsons", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Lucy", + "lastName": "Myers", + "company": "Naxdis", + "employed": true + }, + { + "firstName": "Calhoun", + "lastName": "Donovan", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Twila", + "lastName": "Gonzalez", + "company": "Jetsilk", + "employed": true + }, + { + "firstName": "Brittany", + "lastName": "Stein", + "company": "Eplode", + "employed": true + }, + { + "firstName": "Maritza", + "lastName": "Rice", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Jannie", + "lastName": "Cunningham", + "company": "Zentix", + "employed": true + }, + { + "firstName": "Leila", + "lastName": "Leonard", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Riley", + "lastName": "Navarro", + "company": "Quizmo", + "employed": false + }, + { + "firstName": "Johanna", + "lastName": "Swanson", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Fran", + "lastName": "Baxter", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Jimmie", + "lastName": "Guzman", + "company": "Hotcakes", + "employed": true + }, + { + "firstName": "Mariana", + "lastName": "Howard", + "company": "Optique", + "employed": true + }, + { + "firstName": "Hickman", + "lastName": "Lynn", + "company": "Qimonk", + "employed": true + }, + { + "firstName": "Sandy", + "lastName": "Rowe", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Tonya", + "lastName": "Massey", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Ruby", + "lastName": "Morrison", + "company": "Ecrater", + "employed": true + }, + { + "firstName": "Brandy", + "lastName": "Wolf", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Christie", + "lastName": "Hughes", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Pitts", + "lastName": "Drake", + "company": "Austex", + "employed": false + }, + { + "firstName": "Lambert", + "lastName": "Everett", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Bonita", + "lastName": "Wolfe", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Owen", + "lastName": "Hood", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Lorraine", + "lastName": "Hartman", + "company": "Digirang", + "employed": false + }, + { + "firstName": "Jensen", + "lastName": "Morgan", + "company": "Geekular", + "employed": false + }, + { + "firstName": "Hubbard", + "lastName": "Noel", + "company": "Apex", + "employed": false + }, + { + "firstName": "Ruiz", + "lastName": "Knox", + "company": "Cemention", + "employed": false + }, + { + "firstName": "West", + "lastName": "Blevins", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Gale", + "lastName": "Joyce", + "company": "Glukgluk", + "employed": false + }, + { + "firstName": "Cara", + "lastName": "Salinas", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Mable", + "lastName": "Boyd", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Mooney", + "lastName": "Thompson", + "company": "Zilencio", + "employed": true + }, + { + "firstName": "Landry", + "lastName": "Wilson", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Gallagher", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Kinney", + "lastName": "Juarez", + "company": "Manufact", + "employed": true + }, + { + "firstName": "Araceli", + "lastName": "Graham", + "company": "Assistia", + "employed": true + }, + { + "firstName": "Cox", + "lastName": "Ellison", + "company": "Surelogic", + "employed": false + }, + { + "firstName": "Bertha", + "lastName": "Villarreal", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Jessie", + "lastName": "Gibbs", + "company": "Isosphere", + "employed": true + }, + { + "firstName": "Jana", + "lastName": "Richard", + "company": "Aeora", + "employed": false + }, + { + "firstName": "Noelle", + "lastName": "Delgado", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Perez", + "lastName": "Cameron", + "company": "Telepark", + "employed": false + }, + { + "firstName": "Constance", + "lastName": "Snider", + "company": "Cubicide", + "employed": true + }, + { + "firstName": "Campos", + "lastName": "Foreman", + "company": "Microluxe", + "employed": false + }, + { + "firstName": "Pena", + "lastName": "Berg", + "company": "Dentrex", + "employed": false + }, + { + "firstName": "Glover", + "lastName": "Green", + "company": "Overplex", + "employed": true + }, + { + "firstName": "Jocelyn", + "lastName": "Mcintyre", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Miriam", + "lastName": "Nash", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Vinson", + "lastName": "Fuller", + "company": "Kegular", + "employed": false + }, + { + "firstName": "Downs", + "lastName": "Rodgers", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Lessie", + "lastName": "Acevedo", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Richardson", + "lastName": "Mckenzie", + "company": "Concility", + "employed": true + }, + { + "firstName": "Lela", + "lastName": "Walls", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Beth", + "lastName": "Wallace", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Britney", + "lastName": "Burnett", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Adkins", + "lastName": "Fuentes", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Lynn", + "lastName": "Barnett", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Lambert", + "company": "Organica", + "employed": true + }, + { + "firstName": "Beryl", + "lastName": "Prince", + "company": "Zilphur", + "employed": false + }, + { + "firstName": "Witt", + "lastName": "Gentry", + "company": "Furnitech", + "employed": true + }, + { + "firstName": "Burt", + "lastName": "Bright", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Koch", + "lastName": "Rasmussen", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Kristy", + "lastName": "Hendricks", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Oneil", + "lastName": "Cortez", + "company": "Halap", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Tate", + "company": "Lotron", + "employed": false + }, + { + "firstName": "Lisa", + "lastName": "Page", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "George", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Deloris", + "lastName": "Black", + "company": "Geekosis", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Guthrie", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Carmela", + "lastName": "Hahn", + "company": "Zolarex", + "employed": true + }, + { + "firstName": "Winifred", + "lastName": "Scott", + "company": "Applica", + "employed": true + }, + { + "firstName": "Yesenia", + "lastName": "Luna", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Colon", + "lastName": "Fisher", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Weber", + "lastName": "Burke", + "company": "Phuel", + "employed": false + }, + { + "firstName": "Holder", + "lastName": "Wyatt", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Rosetta", + "lastName": "Lewis", + "company": "Digiprint", + "employed": false + }, + { + "firstName": "Angie", + "lastName": "Foley", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Guy", + "lastName": "Burt", + "company": "Fossiel", + "employed": false + }, + { + "firstName": "Hicks", + "lastName": "Hensley", + "company": "Cowtown", + "employed": false + }, + { + "firstName": "Tamara", + "lastName": "Mccullough", + "company": "Kyagoro", + "employed": true + }, + { + "firstName": "Allyson", + "lastName": "Roy", + "company": "Centree", + "employed": true + }, + { + "firstName": "Roach", + "lastName": "Puckett", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Johns", + "lastName": "Mathis", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Kelli", + "lastName": "Washington", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Tonia", + "lastName": "Dejesus", + "company": "Stelaecor", + "employed": false + }, + { + "firstName": "Lowery", + "lastName": "Adams", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Brooke", + "lastName": "Sutton", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Miller", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Minnie", + "lastName": "Hopper", + "company": "Slax", + "employed": false + }, + { + "firstName": "Nikki", + "lastName": "Patel", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Osborn", + "lastName": "Johnson", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Scott", + "lastName": "Fields", + "company": "Biflex", + "employed": false + }, + { + "firstName": "Cooper", + "lastName": "Norris", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Amber", + "lastName": "Brown", + "company": "Lunchpod", + "employed": false + }, + { + "firstName": "Hooper", + "lastName": "Holland", + "company": "Podunk", + "employed": true + }, + { + "firstName": "Elaine", + "lastName": "Patrick", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Wendi", + "lastName": "Farrell", + "company": "Amril", + "employed": false + }, + { + "firstName": "Carey", + "lastName": "Maxwell", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Grant", + "lastName": "Moore", + "company": "Zerbina", + "employed": false + }, + { + "firstName": "Sweet", + "lastName": "Woodard", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Briana", + "lastName": "Mayer", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Ballard", + "lastName": "Love", + "company": "Isoswitch", + "employed": false + }, + { + "firstName": "Kimberley", + "lastName": "Herrera", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Anna", + "lastName": "Fitzgerald", + "company": "Futurity", + "employed": true + }, + { + "firstName": "Edith", + "lastName": "Erickson", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Leta", + "lastName": "Anthony", + "company": "Omatom", + "employed": false + }, + { + "firstName": "Burton", + "lastName": "Andrews", + "company": "Unisure", + "employed": true + }, + { + "firstName": "Patton", + "lastName": "Doyle", + "company": "Nipaz", + "employed": false + }, + { + "firstName": "Dollie", + "lastName": "Dawson", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Estella", + "lastName": "Clark", + "company": "Equitox", + "employed": false + }, + { + "firstName": "Burch", + "lastName": "Wynn", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Joni", + "lastName": "Oconnor", + "company": "Obones", + "employed": false + }, + { + "firstName": "Muriel", + "lastName": "Hoover", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Booth", + "lastName": "Blackburn", + "company": "Golistic", + "employed": false + }, + { + "firstName": "Mercado", + "lastName": "Woodward", + "company": "Exerta", + "employed": false + }, + { + "firstName": "Romero", + "lastName": "Rollins", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Lucinda", + "lastName": "Pruitt", + "company": "Uberlux", + "employed": false + }, + { + "firstName": "Raymond", + "lastName": "Downs", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Garrett", + "lastName": "Salazar", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Acosta", + "lastName": "Zamora", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Maryann", + "lastName": "Roach", + "company": "Zedalis", + "employed": true + }, + { + "firstName": "Bettie", + "lastName": "Jarvis", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Mattie", + "lastName": "Forbes", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Megan", + "lastName": "House", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Welch", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Roberts", + "lastName": "Stuart", + "company": "Artiq", + "employed": false + }, + { + "firstName": "Washington", + "lastName": "Willis", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Gardner", + "lastName": "Walker", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Rose", + "lastName": "Vance", + "company": "Isbol", + "employed": true + }, + { + "firstName": "Huff", + "lastName": "Hickman", + "company": "Accel", + "employed": false + }, + { + "firstName": "Jeri", + "lastName": "Mooney", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Knowles", + "lastName": "Holmes", + "company": "Magnina", + "employed": true + }, + { + "firstName": "Gayle", + "lastName": "Hodge", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Paul", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Saunders", + "lastName": "Chen", + "company": "Vortexaco", + "employed": true + }, + { + "firstName": "Latoya", + "lastName": "Petty", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Rhoda", + "lastName": "Boyer", + "company": "Techade", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Shepard", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Alston", + "lastName": "Ayala", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Lindsey", + "lastName": "Velasquez", + "company": "Inrt", + "employed": false + }, + { + "firstName": "Brigitte", + "lastName": "Mccray", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Fitzpatrick", + "lastName": "Cervantes", + "company": "Eclipto", + "employed": false + }, + { + "firstName": "Chandler", + "lastName": "Ross", + "company": "Navir", + "employed": false + }, + { + "firstName": "Britt", + "lastName": "Hogan", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Regina", + "lastName": "Steele", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Esmeralda", + "lastName": "Sykes", + "company": "Rodeology", + "employed": true + }, + { + "firstName": "Marva", + "lastName": "Conner", + "company": "Comtent", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Neal", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Bradford", + "lastName": "Camacho", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Morton", + "lastName": "Carver", + "company": "Techmania", + "employed": true + }, + { + "firstName": "James", + "lastName": "Barber", + "company": "Slofast", + "employed": true + }, + { + "firstName": "Jeanne", + "lastName": "Roberts", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Keisha", + "lastName": "Mccall", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Strickland", + "lastName": "Morales", + "company": "Sequitur", + "employed": false + }, + { + "firstName": "House", + "lastName": "Franklin", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Williams", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Yvette", + "lastName": "Ball", + "company": "Isosure", + "employed": true + }, + { + "firstName": "Ortiz", + "lastName": "Lawrence", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Ball", + "lastName": "Barnes", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Colon", + "company": "Comcur", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Bonner", + "company": "Medesign", + "employed": true + }, + { + "firstName": "Elena", + "lastName": "Hardin", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Buckner", + "lastName": "Shepherd", + "company": "Petigems", + "employed": true + }, + { + "firstName": "Tracie", + "lastName": "Bishop", + "company": "Waterbaby", + "employed": false + }, + { + "firstName": "Marianne", + "lastName": "Larsen", + "company": "Portico", + "employed": true + }, + { + "firstName": "Hurley", + "lastName": "Torres", + "company": "Asimiline", + "employed": false + }, + { + "firstName": "Hazel", + "lastName": "Small", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Olivia", + "lastName": "Odom", + "company": "Zounds", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Estrada", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Faulkner", + "company": "Polarium", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Hinton", + "company": "Typhonica", + "employed": false + }, + { + "firstName": "Kathrine", + "lastName": "Hurley", + "company": "Farmex", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Hess", + "company": "Liquidoc", + "employed": false + }, + { + "firstName": "Katherine", + "lastName": "Yang", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Darla", + "lastName": "Butler", + "company": "Octocore", + "employed": false + }, + { + "firstName": "Willa", + "lastName": "Strickland", + "company": "Comtrak", + "employed": true + }, + { + "firstName": "Enid", + "lastName": "Cobb", + "company": "Dancity", + "employed": true + }, + { + "firstName": "Fields", + "lastName": "Norton", + "company": "Zanymax", + "employed": false + }, + { + "firstName": "Tamera", + "lastName": "Gallegos", + "company": "Netplax", + "employed": false + }, + { + "firstName": "Alyssa", + "lastName": "Chandler", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Merle", + "lastName": "Buchanan", + "company": "Webiotic", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Molina", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Petty", + "lastName": "Sawyer", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Abigail", + "lastName": "Koch", + "company": "Zialactic", + "employed": false + }, + { + "firstName": "Ofelia", + "lastName": "Mckay", + "company": "Mazuda", + "employed": true + }, + { + "firstName": "Schultz", + "lastName": "Lowe", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Lottie", + "lastName": "Poole", + "company": "Bisba", + "employed": false + }, + { + "firstName": "Hopper", + "lastName": "Merritt", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Espinoza", + "lastName": "Dunlap", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Chasity", + "lastName": "Frost", + "company": "Besto", + "employed": false + }, + { + "firstName": "Hardin", + "lastName": "Oneil", + "company": "Mangelica", + "employed": false + }, + { + "firstName": "Cross", + "lastName": "Martinez", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Rosario", + "lastName": "Dudley", + "company": "Signity", + "employed": false + }, + { + "firstName": "Naomi", + "lastName": "Newton", + "company": "Urbanshee", + "employed": false + }, + { + "firstName": "Amalia", + "lastName": "Joseph", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Harrison", + "lastName": "Floyd", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Foreman", + "lastName": "Church", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Blankenship", + "lastName": "Hendrix", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Hines", + "lastName": "Chambers", + "company": "Kog", + "employed": false + }, + { + "firstName": "Marietta", + "lastName": "Morrow", + "company": "Exosis", + "employed": true + }, + { + "firstName": "Nicholson", + "lastName": "Medina", + "company": "Nurali", + "employed": true + }, + { + "firstName": "Maude", + "lastName": "Hebert", + "company": "Geostele", + "employed": false + }, + { + "firstName": "Natalie", + "lastName": "Zimmerman", + "company": "Locazone", + "employed": true + }, + { + "firstName": "Herring", + "lastName": "Whitfield", + "company": "Poshome", + "employed": true + }, + { + "firstName": "Phoebe", + "lastName": "Saunders", + "company": "Automon", + "employed": true + }, + { + "firstName": "Priscilla", + "lastName": "Dean", + "company": "Netagy", + "employed": true + }, + { + "firstName": "Shirley", + "lastName": "Barrera", + "company": "Mondicil", + "employed": true + }, + { + "firstName": "Daisy", + "lastName": "Branch", + "company": "Neptide", + "employed": false + }, + { + "firstName": "Lorie", + "lastName": "Cannon", + "company": "Datagen", + "employed": true + }, + { + "firstName": "Edwards", + "lastName": "Case", + "company": "Zipak", + "employed": false + }, + { + "firstName": "Avis", + "lastName": "Landry", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Millie", + "lastName": "Rios", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Lindsey", + "lastName": "Cantu", + "company": "Solaren", + "employed": false + }, + { + "firstName": "Thelma", + "lastName": "Valentine", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Potts", + "lastName": "Holloway", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Caldwell", + "lastName": "Adkins", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Hannah", + "lastName": "Mosley", + "company": "Exostream", + "employed": true + }, + { + "firstName": "Gabrielle", + "lastName": "Walton", + "company": "Fishland", + "employed": false + }, + { + "firstName": "Madelyn", + "lastName": "Dennis", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Lilian", + "lastName": "Stone", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Neal", + "lastName": "Schneider", + "company": "Zillidium", + "employed": false + }, + { + "firstName": "Jayne", + "lastName": "Brewer", + "company": "Dogtown", + "employed": true + }, + { + "firstName": "Craft", + "lastName": "Callahan", + "company": "Zillatide", + "employed": true + }, + { + "firstName": "Chaney", + "lastName": "Cross", + "company": "Accusage", + "employed": true + }, + { + "firstName": "Wendy", + "lastName": "Robles", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Decker", + "company": "Ginkle", + "employed": true + }, + { + "firstName": "Burns", + "lastName": "Mcdaniel", + "company": "Elentrix", + "employed": false + }, + { + "firstName": "Douglas", + "lastName": "Elliott", + "company": "Gallaxia", + "employed": true + }, + { + "firstName": "Mullins", + "lastName": "Mcfarland", + "company": "Gology", + "employed": true + }, + { + "firstName": "Felicia", + "lastName": "Rowland", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Sullivan", + "company": "Comtest", + "employed": false + }, + { + "firstName": "Aisha", + "lastName": "Buckley", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Katie", + "lastName": "Larson", + "company": "Pharmex", + "employed": false + }, + { + "firstName": "Lily", + "lastName": "Stephens", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Ramona", + "lastName": "Montgomery", + "company": "Amtap", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Riddle", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Emerson", + "lastName": "Cabrera", + "company": "Waab", + "employed": false + }, + { + "firstName": "Helena", + "lastName": "Beach", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Johnston", + "lastName": "Schwartz", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Louisa", + "lastName": "Hall", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Collier", + "lastName": "Bryant", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Harding", + "lastName": "Terry", + "company": "Danja", + "employed": false + }, + { + "firstName": "Clarissa", + "lastName": "Wilder", + "company": "Nimon", + "employed": true + }, + { + "firstName": "Morrison", + "lastName": "Reid", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Aurora", + "lastName": "Webster", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Maldonado", + "lastName": "Shaw", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Phillips", + "lastName": "Tillman", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Maryellen", + "lastName": "Sherman", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Justine", + "lastName": "Fletcher", + "company": "Realmo", + "employed": true + }, + { + "firstName": "Finch", + "lastName": "Weber", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Dickerson", + "lastName": "Rosario", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Riggs", + "lastName": "Raymond", + "company": "Honotron", + "employed": false + }, + { + "firstName": "Effie", + "lastName": "Head", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Moss", + "lastName": "Richardson", + "company": "Orboid", + "employed": false + }, + { + "firstName": "Ella", + "lastName": "Nixon", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Blair", + "company": "Blurrybus", + "employed": false + }, + { + "firstName": "Cathryn", + "lastName": "Beasley", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Bowers", + "lastName": "Bird", + "company": "Apextri", + "employed": false + }, + { + "firstName": "Peck", + "lastName": "Stewart", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Pittman", + "lastName": "Parrish", + "company": "Fortean", + "employed": true + }, + { + "firstName": "Darcy", + "lastName": "Gilmore", + "company": "Gynk", + "employed": true + }, + { + "firstName": "Lara", + "lastName": "Pickett", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Joy", + "lastName": "Johnston", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Berg", + "lastName": "Shaffer", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Mcmillan", + "lastName": "Hoffman", + "company": "Nspire", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Reeves", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Harris", + "lastName": "Christensen", + "company": "Pyramax", + "employed": true + }, + { + "firstName": "Bridgette", + "lastName": "Compton", + "company": "Inear", + "employed": false + }, + { + "firstName": "Mclaughlin", + "lastName": "Ratliff", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Riddle", + "lastName": "Pacheco", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Levine", + "lastName": "Griffin", + "company": "Obliq", + "employed": false + }, + { + "firstName": "Jasmine", + "lastName": "Wells", + "company": "Colaire", + "employed": false + }, + { + "firstName": "Virginia", + "lastName": "Frazier", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Lloyd", + "lastName": "Noble", + "company": "Franscene", + "employed": false + }, + { + "firstName": "Leonard", + "lastName": "Blake", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Tyson", + "company": "Zeam", + "employed": true + }, + { + "firstName": "April", + "lastName": "Holden", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Melton", + "company": "Strezzo", + "employed": false + }, + { + "firstName": "Chambers", + "lastName": "Cooley", + "company": "Bleeko", + "employed": false + }, + { + "firstName": "Mcclain", + "lastName": "Conley", + "company": "Assurity", + "employed": true + }, + { + "firstName": "Cabrera", + "lastName": "William", + "company": "Solgan", + "employed": true + }, + { + "firstName": "Lucia", + "lastName": "Stafford", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Danielle", + "lastName": "Klein", + "company": "Zogak", + "employed": true + }, + { + "firstName": "Contreras", + "lastName": "Nielsen", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Chang", + "company": "Gink", + "employed": true + }, + { + "firstName": "Gwen", + "lastName": "Goff", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Carrillo", + "lastName": "Wilkerson", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Sasha", + "lastName": "Simon", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Bessie", + "lastName": "Holcomb", + "company": "Plasmox", + "employed": false + }, + { + "firstName": "Tammi", + "lastName": "Kim", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Houston", + "lastName": "English", + "company": "Suremax", + "employed": true + }, + { + "firstName": "Hattie", + "lastName": "Harrell", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Carla", + "lastName": "Guerrero", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Deena", + "lastName": "Porter", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Hays", + "lastName": "Boone", + "company": "Inquala", + "employed": false + }, + { + "firstName": "Swanson", + "lastName": "Vang", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Maura", + "lastName": "Dalton", + "company": "Filodyne", + "employed": true + }, + { + "firstName": "Harrington", + "lastName": "Park", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Cruz", + "lastName": "Duke", + "company": "Qaboos", + "employed": true + }, + { + "firstName": "Chavez", + "lastName": "Lara", + "company": "Toyletry", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Fowler", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Pam", + "lastName": "Britt", + "company": "Enormo", + "employed": false + }, + { + "firstName": "Figueroa", + "lastName": "Jensen", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Duncan", + "lastName": "Herman", + "company": "Imant", + "employed": true + }, + { + "firstName": "Jacquelyn", + "lastName": "Mcknight", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Dorthy", + "lastName": "Levy", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Minerva", + "lastName": "Clayton", + "company": "Teraprene", + "employed": true + }, + { + "firstName": "Shauna", + "lastName": "Hodges", + "company": "Empirica", + "employed": true + }, + { + "firstName": "Molina", + "lastName": "Holt", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Barr", + "lastName": "Hutchinson", + "company": "Ultrimax", + "employed": false + }, + { + "firstName": "Mercedes", + "lastName": "Todd", + "company": "Canopoly", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Knowles", + "company": "Eternis", + "employed": false + }, + { + "firstName": "Silva", + "lastName": "Morton", + "company": "Fiberox", + "employed": false + }, + { + "firstName": "Myrtle", + "lastName": "Barry", + "company": "Trasola", + "employed": false + }, + { + "firstName": "Eleanor", + "lastName": "Alexander", + "company": "Isotrack", + "employed": true + }, + { + "firstName": "David", + "lastName": "Velazquez", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Josephine", + "lastName": "Spence", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Mathews", + "lastName": "Jones", + "company": "Nebulean", + "employed": false + }, + { + "firstName": "Morris", + "lastName": "Schmidt", + "company": "Geekus", + "employed": true + }, + { + "firstName": "Claire", + "lastName": "Sargent", + "company": "Unq", + "employed": false + }, + { + "firstName": "Deirdre", + "lastName": "Whitney", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Duffy", + "lastName": "Mcdonald", + "company": "Zoid", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Robinson", + "company": "Vicon", + "employed": false + }, + { + "firstName": "Ingram", + "lastName": "Byrd", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Lillian", + "lastName": "Crane", + "company": "Snips", + "employed": false + }, + { + "firstName": "Melody", + "lastName": "Dyer", + "company": "Quilch", + "employed": false + }, + { + "firstName": "Allison", + "lastName": "Castaneda", + "company": "Coriander", + "employed": false + }, + { + "firstName": "Noreen", + "lastName": "Gill", + "company": "Namegen", + "employed": true + }, + { + "firstName": "Mcgowan", + "lastName": "Sellers", + "company": "Orbean", + "employed": true + }, + { + "firstName": "Michele", + "lastName": "Gregory", + "company": "Uneeq", + "employed": false + }, + { + "firstName": "Alana", + "lastName": "Mejia", + "company": "Extremo", + "employed": true + }, + { + "firstName": "Elsie", + "lastName": "Burks", + "company": "Katakana", + "employed": false + }, + { + "firstName": "Ayers", + "lastName": "Daniels", + "company": "Retrack", + "employed": true + }, + { + "firstName": "Jacqueline", + "lastName": "Gould", + "company": "Isodrive", + "employed": true + }, + { + "firstName": "Conner", + "lastName": "Burton", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Abby", + "lastName": "Carlson", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Melba", + "lastName": "Cline", + "company": "Jumpstack", + "employed": false + }, + { + "firstName": "Rebekah", + "lastName": "Hanson", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Cash", + "lastName": "Malone", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Agnes", + "lastName": "Randall", + "company": "Portica", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Mcpherson", + "company": "Tourmania", + "employed": false + }, + { + "firstName": "Eloise", + "lastName": "Jimenez", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Lucille", + "lastName": "Gaines", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Munoz", + "lastName": "Knapp", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Gloria", + "lastName": "Alvarez", + "company": "Thredz", + "employed": false + }, + { + "firstName": "Price", + "lastName": "Hewitt", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Myra", + "lastName": "Bradshaw", + "company": "Kindaloo", + "employed": true + }, + { + "firstName": "Dudley", + "lastName": "Lancaster", + "company": "Netropic", + "employed": true + }, + { + "firstName": "Jefferson", + "lastName": "Miles", + "company": "Skybold", + "employed": true + }, + { + "firstName": "Jeannie", + "lastName": "Hansen", + "company": "Acusage", + "employed": false + }, + { + "firstName": "Waller", + "lastName": "Witt", + "company": "Playce", + "employed": false + }, + { + "firstName": "Lavonne", + "lastName": "Shannon", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Evangelina", + "lastName": "Kemp", + "company": "Irack", + "employed": true + }, + { + "firstName": "Wanda", + "lastName": "Williamson", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Karen", + "lastName": "Vasquez", + "company": "Rugstars", + "employed": false + }, + { + "firstName": "Julie", + "lastName": "Oneal", + "company": "Zenthall", + "employed": false + }, + { + "firstName": "Tanisha", + "lastName": "Bowers", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Olive", + "lastName": "Brooks", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Noemi", + "lastName": "Key", + "company": "Shadease", + "employed": false + }, + { + "firstName": "Short", + "lastName": "Mason", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Heidi", + "lastName": "Cain", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Pauline", + "lastName": "Good", + "company": "Musix", + "employed": true + }, + { + "firstName": "Carly", + "lastName": "Gross", + "company": "Austech", + "employed": true + }, + { + "firstName": "Earline", + "lastName": "Higgins", + "company": "Fitcore", + "employed": false + }, + { + "firstName": "Eliza", + "lastName": "Haney", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Diane", + "lastName": "Murray", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Schneider", + "lastName": "Aguirre", + "company": "Elpro", + "employed": false + }, + { + "firstName": "Sue", + "lastName": "Lott", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Marcy", + "lastName": "Ferrell", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Rowland", + "lastName": "Matthews", + "company": "Zork", + "employed": false + }, + { + "firstName": "Virgie", + "lastName": "Banks", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Lesa", + "lastName": "James", + "company": "Dognosis", + "employed": true + }, + { + "firstName": "Helga", + "lastName": "Houston", + "company": "Terragen", + "employed": true + }, + { + "firstName": "Casey", + "lastName": "Wagner", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Sweeney", + "lastName": "Conrad", + "company": "Pyrami", + "employed": true + }, + { + "firstName": "Rita", + "lastName": "Best", + "company": "Lyria", + "employed": false + }, + { + "firstName": "Sylvia", + "lastName": "Barron", + "company": "Comvey", + "employed": false + }, + { + "firstName": "Nola", + "lastName": "Snyder", + "company": "Exozent", + "employed": true + }, + { + "firstName": "Nadia", + "lastName": "Benton", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Bates", + "lastName": "Logan", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Marie", + "lastName": "Clemons", + "company": "Firewax", + "employed": false + }, + { + "firstName": "Kristina", + "lastName": "Melendez", + "company": "Buzzmaker", + "employed": false + }, + { + "firstName": "Elvira", + "lastName": "Woods", + "company": "Decratex", + "employed": false + }, + { + "firstName": "Stone", + "lastName": "Shields", + "company": "Scentric", + "employed": true + }, + { + "firstName": "Farmer", + "lastName": "Knight", + "company": "Comtrek", + "employed": false + }, + { + "firstName": "Bernard", + "lastName": "Lang", + "company": "Cyclonica", + "employed": false + }, + { + "firstName": "Sullivan", + "lastName": "Howe", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Boone", + "lastName": "Horne", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Tara", + "lastName": "Tucker", + "company": "Idealis", + "employed": false + }, + { + "firstName": "Jillian", + "lastName": "Sims", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Watts", + "lastName": "King", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Coleman", + "lastName": "Vargas", + "company": "Comtour", + "employed": false + }, + { + "firstName": "Sexton", + "lastName": "Flores", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Adela", + "lastName": "Curtis", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Elise", + "lastName": "Sharp", + "company": "Bitrex", + "employed": false + }, + { + "firstName": "Marisa", + "lastName": "Ingram", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Candice", + "lastName": "Nolan", + "company": "Zentility", + "employed": true + }, + { + "firstName": "Juliana", + "lastName": "Oneill", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Alyce", + "lastName": "Leon", + "company": "Ewaves", + "employed": true + }, + { + "firstName": "Kemp", + "lastName": "Hurst", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Ferrell", + "lastName": "Petersen", + "company": "Kneedles", + "employed": false + }, + { + "firstName": "Leach", + "lastName": "Hardy", + "company": "Fibrodyne", + "employed": true + }, + { + "firstName": "Estrada", + "lastName": "Douglas", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Hudson", + "lastName": "Nicholson", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Holcomb", + "lastName": "Evans", + "company": "Norali", + "employed": true + }, + { + "firstName": "Nelda", + "lastName": "Hernandez", + "company": "Recrisys", + "employed": true + }, + { + "firstName": "Rosalyn", + "lastName": "Francis", + "company": "Koogle", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Wilkinson", + "company": "Vetron", + "employed": false + }, + { + "firstName": "Clements", + "lastName": "Jackson", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Small", + "lastName": "Buck", + "company": "Circum", + "employed": false + }, + { + "firstName": "Cantu", + "lastName": "Kelley", + "company": "Xsports", + "employed": true + }, + { + "firstName": "Lydia", + "lastName": "Savage", + "company": "Spherix", + "employed": true + }, + { + "firstName": "Camacho", + "lastName": "Marshall", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Martha", + "lastName": "Wooten", + "company": "Ezentia", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Harper", + "company": "Bluplanet", + "employed": true + }, + { + "firstName": "Letitia", + "lastName": "Ruiz", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Schmidt", + "lastName": "Mccarthy", + "company": "Dogspa", + "employed": true + }, + { + "firstName": "Lou", + "lastName": "Kelly", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Cummings", + "lastName": "Lawson", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Lynch", + "lastName": "Olsen", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Tabitha", + "lastName": "Clay", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Bell", + "lastName": "Reynolds", + "company": "Affluex", + "employed": false + }, + { + "firstName": "Tamika", + "lastName": "Flynn", + "company": "Digigen", + "employed": false + }, + { + "firstName": "Maggie", + "lastName": "Phillips", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Gonzales", + "lastName": "Newman", + "company": "Newcube", + "employed": false + }, + { + "firstName": "Rowena", + "lastName": "York", + "company": "Musaphics", + "employed": true + }, + { + "firstName": "Rich", + "lastName": "Rivas", + "company": "Calcula", + "employed": true + }, + { + "firstName": "Juana", + "lastName": "Madden", + "company": "Flumbo", + "employed": true + }, + { + "firstName": "Mendoza", + "lastName": "Parks", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Mclean", + "company": "Intradisk", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Bridges", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Mccray", + "lastName": "West", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Charmaine", + "lastName": "Battle", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Consuelo", + "lastName": "Chan", + "company": "Endipin", + "employed": true + }, + { + "firstName": "Little", + "lastName": "Meyer", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Melendez", + "lastName": "Solis", + "company": "Ebidco", + "employed": true + }, + { + "firstName": "Dickson", + "lastName": "Daugherty", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Spears", + "lastName": "Finley", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Serrano", + "lastName": "Chase", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Iva", + "lastName": "Ferguson", + "company": "Genmex", + "employed": false + }, + { + "firstName": "Viola", + "lastName": "Whitley", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Gilmore", + "lastName": "Ryan", + "company": "Remold", + "employed": true + }, + { + "firstName": "Cornelia", + "lastName": "Allison", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Knight", + "lastName": "Castillo", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Walsh", + "lastName": "Campbell", + "company": "Zaphire", + "employed": false + }, + { + "firstName": "Leslie", + "lastName": "Watts", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Rosalinda", + "lastName": "Bond", + "company": "Equicom", + "employed": true + }, + { + "firstName": "Luz", + "lastName": "Burgess", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Hale", + "lastName": "Brennan", + "company": "Vendblend", + "employed": true + }, + { + "firstName": "Barrett", + "lastName": "Lee", + "company": "Assitia", + "employed": true + }, + { + "firstName": "Buck", + "lastName": "Pittman", + "company": "Syntac", + "employed": true + }, + { + "firstName": "Marguerite", + "lastName": "Brady", + "company": "Kongle", + "employed": false + }, + { + "firstName": "Kelsey", + "lastName": "Kaufman", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Lauri", + "lastName": "Payne", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Barber", + "lastName": "Rocha", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Amy", + "lastName": "Solomon", + "company": "Combot", + "employed": false + }, + { + "firstName": "Tameka", + "lastName": "Caldwell", + "company": "Overfork", + "employed": false + }, + { + "firstName": "Lillie", + "lastName": "Henry", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Paige", + "lastName": "Horn", + "company": "Helixo", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Fernandez", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Roth", + "lastName": "Mendoza", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Perkins", + "company": "Limage", + "employed": true + }, + { + "firstName": "Rosanna", + "lastName": "Reese", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Georgia", + "lastName": "Morin", + "company": "Icology", + "employed": false + }, + { + "firstName": "Davidson", + "lastName": "Pierce", + "company": "Injoy", + "employed": true + }, + { + "firstName": "Newton", + "lastName": "Blankenship", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Griffith", + "lastName": "Charles", + "company": "Accufarm", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Odonnell", + "company": "Eargo", + "employed": true + }, + { + "firstName": "Berry", + "lastName": "Franco", + "company": "Slambda", + "employed": true + }, + { + "firstName": "Lopez", + "lastName": "Foster", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Pope", + "lastName": "Roman", + "company": "Zensure", + "employed": false + }, + { + "firstName": "Blanca", + "lastName": "Moody", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Alison", + "lastName": "Grant", + "company": "Musanpoly", + "employed": true + }, + { + "firstName": "William", + "lastName": "Osborn", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Willis", + "lastName": "Leach", + "company": "Velos", + "employed": true + }, + { + "firstName": "Lupe", + "lastName": "Robbins", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Opal", + "lastName": "Mcgowan", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Fern", + "lastName": "Kent", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Richards", + "lastName": "Haynes", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Cotton", + "company": "Insource", + "employed": true + }, + { + "firstName": "Robinson", + "lastName": "Hays", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Bauer", + "lastName": "Vincent", + "company": "Quiltigen", + "employed": false + }, + { + "firstName": "Dyer", + "lastName": "Francis", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Acevedo", + "lastName": "Mcdaniel", + "company": "Lyrichord", + "employed": true + }, + { + "firstName": "Hubbard", + "lastName": "House", + "company": "Jasper", + "employed": false + }, + { + "firstName": "Edith", + "lastName": "Rios", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Park", + "lastName": "Jones", + "company": "Egypto", + "employed": false + }, + { + "firstName": "Clarice", + "lastName": "Colon", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Janet", + "lastName": "Carter", + "company": "Solaren", + "employed": false + }, + { + "firstName": "Socorro", + "lastName": "Avery", + "company": "Icology", + "employed": false + }, + { + "firstName": "Stuart", + "lastName": "Gibson", + "company": "Amtap", + "employed": false + }, + { + "firstName": "Kristina", + "lastName": "Vazquez", + "company": "Motovate", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Hoffman", + "company": "Petigems", + "employed": false + }, + { + "firstName": "Jordan", + "lastName": "Gay", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Susanna", + "lastName": "Clark", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Fulton", + "lastName": "Franklin", + "company": "Corporana", + "employed": false + }, + { + "firstName": "Glenna", + "lastName": "Shaffer", + "company": "Gynko", + "employed": false + }, + { + "firstName": "Pitts", + "lastName": "Monroe", + "company": "Bitrex", + "employed": true + }, + { + "firstName": "Sara", + "lastName": "Howell", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Lea", + "lastName": "Mendez", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Chan", + "lastName": "Mejia", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Aurelia", + "lastName": "Townsend", + "company": "Uni", + "employed": true + }, + { + "firstName": "Louisa", + "lastName": "Cox", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Kitty", + "lastName": "Hayden", + "company": "Austex", + "employed": false + }, + { + "firstName": "Alana", + "lastName": "Kirby", + "company": "Bedlam", + "employed": true + }, + { + "firstName": "Moreno", + "lastName": "Boone", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Tamika", + "lastName": "Farmer", + "company": "Maroptic", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Singleton", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Adeline", + "lastName": "Cummings", + "company": "Namegen", + "employed": false + }, + { + "firstName": "Silva", + "lastName": "Mclaughlin", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Emilia", + "lastName": "Pugh", + "company": "Zillactic", + "employed": true + }, + { + "firstName": "Mitchell", + "lastName": "Chen", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Huber", + "lastName": "Roy", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Michele", + "lastName": "Trevino", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Bentley", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Rosie", + "lastName": "Buckley", + "company": "Enomen", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Wong", + "company": "Malathion", + "employed": true + }, + { + "firstName": "Jarvis", + "lastName": "Ingram", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Maricela", + "lastName": "Perkins", + "company": "Biflex", + "employed": true + }, + { + "firstName": "Avery", + "lastName": "Daniels", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Cynthia", + "lastName": "Osborne", + "company": "Genmex", + "employed": true + }, + { + "firstName": "Lucas", + "lastName": "Lyons", + "company": "Verbus", + "employed": false + }, + { + "firstName": "Franklin", + "lastName": "Dickerson", + "company": "Kineticut", + "employed": true + }, + { + "firstName": "Georgina", + "lastName": "Duffy", + "company": "Futurity", + "employed": true + }, + { + "firstName": "Nell", + "lastName": "Sexton", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Rich", + "lastName": "Woodard", + "company": "Zerbina", + "employed": false + }, + { + "firstName": "Adrienne", + "lastName": "Washington", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Jackie", + "lastName": "Maxwell", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Ellis", + "lastName": "Wolfe", + "company": "Combogene", + "employed": true + }, + { + "firstName": "Adela", + "lastName": "Sawyer", + "company": "Podunk", + "employed": true + }, + { + "firstName": "Audrey", + "lastName": "Watts", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Lisa", + "lastName": "Spence", + "company": "Twiggery", + "employed": false + }, + { + "firstName": "Freida", + "lastName": "Decker", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Underwood", + "lastName": "Miles", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Guy", + "lastName": "Langley", + "company": "Tourmania", + "employed": false + }, + { + "firstName": "Rebekah", + "lastName": "Pate", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Toni", + "lastName": "Navarro", + "company": "Krog", + "employed": false + }, + { + "firstName": "Katharine", + "lastName": "Baird", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Maura", + "lastName": "Montoya", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Deena", + "lastName": "Conley", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Boyle", + "lastName": "English", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Connie", + "lastName": "Marquez", + "company": "Talkola", + "employed": true + }, + { + "firstName": "Flynn", + "lastName": "Camacho", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Patrice", + "lastName": "Kerr", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Osborne", + "lastName": "Cooper", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Bond", + "lastName": "Johns", + "company": "Geoform", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Ware", + "company": "Voratak", + "employed": false + }, + { + "firstName": "Romero", + "lastName": "Clay", + "company": "Accuprint", + "employed": true + }, + { + "firstName": "Celeste", + "lastName": "Fowler", + "company": "Idetica", + "employed": false + }, + { + "firstName": "Hardy", + "lastName": "Lamb", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Peck", + "lastName": "Keller", + "company": "Lotron", + "employed": false + }, + { + "firstName": "Kent", + "lastName": "Shaw", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Lupe", + "lastName": "Kent", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Tommie", + "lastName": "Valentine", + "company": "Zanity", + "employed": false + }, + { + "firstName": "Butler", + "lastName": "Jackson", + "company": "Bullzone", + "employed": false + }, + { + "firstName": "Terri", + "lastName": "Mason", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Cabrera", + "lastName": "Oneil", + "company": "Enersave", + "employed": false + }, + { + "firstName": "Jewel", + "lastName": "Ray", + "company": "Zillan", + "employed": true + }, + { + "firstName": "Therese", + "lastName": "Buchanan", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Chase", + "lastName": "Morgan", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Padilla", + "lastName": "Alvarez", + "company": "Rodeomad", + "employed": true + }, + { + "firstName": "George", + "lastName": "Hewitt", + "company": "Otherside", + "employed": false + }, + { + "firstName": "Burke", + "lastName": "Pickett", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Madelyn", + "lastName": "Sandoval", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Corrine", + "lastName": "Sargent", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Mullins", + "lastName": "Trujillo", + "company": "Extrawear", + "employed": true + }, + { + "firstName": "Lott", + "lastName": "Wilkins", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Brady", + "lastName": "Payne", + "company": "Geekfarm", + "employed": true + }, + { + "firstName": "Le", + "lastName": "Fernandez", + "company": "Strezzo", + "employed": false + }, + { + "firstName": "Katy", + "lastName": "Riley", + "company": "Acium", + "employed": false + }, + { + "firstName": "Bridges", + "lastName": "Battle", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Sharpe", + "lastName": "Bradley", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Mcpherson", + "lastName": "Anthony", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Jolene", + "lastName": "Lott", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Galloway", + "lastName": "Steele", + "company": "Minga", + "employed": false + }, + { + "firstName": "Matthews", + "lastName": "Chavez", + "company": "Genekom", + "employed": false + }, + { + "firstName": "Kidd", + "lastName": "Cunningham", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Cameron", + "lastName": "West", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Valencia", + "lastName": "Roth", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Bobbie", + "lastName": "Clarke", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Crosby", + "lastName": "Morton", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Barker", + "lastName": "Larson", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Davenport", + "lastName": "Lowery", + "company": "Calcu", + "employed": false + }, + { + "firstName": "Lynette", + "lastName": "Blackburn", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Jacobs", + "lastName": "Chase", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Quinn", + "company": "Senmei", + "employed": false + }, + { + "firstName": "Charmaine", + "lastName": "Dominguez", + "company": "Optyk", + "employed": true + }, + { + "firstName": "Karina", + "lastName": "Wall", + "company": "Aquacine", + "employed": true + }, + { + "firstName": "Gracie", + "lastName": "Mercado", + "company": "Idego", + "employed": false + }, + { + "firstName": "Beatriz", + "lastName": "Andrews", + "company": "Insuresys", + "employed": true + }, + { + "firstName": "Perry", + "lastName": "Branch", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Everett", + "lastName": "Mcfadden", + "company": "Xelegyl", + "employed": false + }, + { + "firstName": "Eula", + "lastName": "Garrison", + "company": "Sentia", + "employed": true + }, + { + "firstName": "Fleming", + "lastName": "Guy", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Carmella", + "lastName": "Martin", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Rosalinda", + "lastName": "Lowe", + "company": "Vinch", + "employed": true + }, + { + "firstName": "Geraldine", + "lastName": "Campos", + "company": "Opticom", + "employed": false + }, + { + "firstName": "Richard", + "lastName": "Daniel", + "company": "Geekosis", + "employed": true + }, + { + "firstName": "Serena", + "lastName": "Parker", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Wendy", + "lastName": "Wilcox", + "company": "Lumbrex", + "employed": true + }, + { + "firstName": "Fuentes", + "lastName": "Sanders", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Schultz", + "lastName": "Scott", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Hayes", + "lastName": "Brady", + "company": "Gallaxia", + "employed": true + }, + { + "firstName": "Finch", + "lastName": "Raymond", + "company": "Bedder", + "employed": true + }, + { + "firstName": "Suarez", + "lastName": "Zamora", + "company": "Unia", + "employed": false + }, + { + "firstName": "Hollie", + "lastName": "Byrd", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Clarke", + "lastName": "Durham", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Cole", + "lastName": "Mccall", + "company": "Extro", + "employed": true + }, + { + "firstName": "Holloway", + "lastName": "Taylor", + "company": "Dymi", + "employed": false + }, + { + "firstName": "Helen", + "lastName": "Gilbert", + "company": "Kaggle", + "employed": true + }, + { + "firstName": "Thomas", + "lastName": "Wooten", + "company": "Datagene", + "employed": false + }, + { + "firstName": "House", + "lastName": "Hopper", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Erickson", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Pamela", + "lastName": "Carey", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Juliet", + "lastName": "Solomon", + "company": "Premiant", + "employed": true + }, + { + "firstName": "Grimes", + "lastName": "Watkins", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Carrillo", + "lastName": "Pacheco", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Cindy", + "lastName": "Mullen", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Battle", + "lastName": "Obrien", + "company": "Furnafix", + "employed": true + }, + { + "firstName": "Marci", + "lastName": "Puckett", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Lola", + "lastName": "Pace", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Sexton", + "lastName": "Miller", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "White", + "lastName": "Frye", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Paul", + "lastName": "Brock", + "company": "Securia", + "employed": false + }, + { + "firstName": "Tracie", + "lastName": "Carney", + "company": "Uxmox", + "employed": true + }, + { + "firstName": "Jewell", + "lastName": "Roberts", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Robyn", + "lastName": "Peterson", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Schwartz", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Elaine", + "lastName": "Norman", + "company": "Teraprene", + "employed": false + }, + { + "firstName": "Jane", + "lastName": "Suarez", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "John", + "lastName": "Kane", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Farrell", + "lastName": "Mack", + "company": "Polaria", + "employed": false + }, + { + "firstName": "Foreman", + "lastName": "Lawson", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Pace", + "lastName": "Terry", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Jamie", + "lastName": "Nelson", + "company": "Shadease", + "employed": true + }, + { + "firstName": "Gallegos", + "lastName": "Santiago", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Pollard", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Keisha", + "lastName": "Short", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Letitia", + "lastName": "Hensley", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Sherman", + "lastName": "Combs", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Hoffman", + "lastName": "Stephens", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Tamara", + "lastName": "Edwards", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Anthony", + "lastName": "Rodriquez", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Allie", + "lastName": "Sharp", + "company": "Daido", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Mcgee", + "company": "Techtrix", + "employed": false + }, + { + "firstName": "Kathy", + "lastName": "Black", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Ewing", + "lastName": "Wilder", + "company": "Avit", + "employed": true + }, + { + "firstName": "Minnie", + "lastName": "Cortez", + "company": "Pulze", + "employed": false + }, + { + "firstName": "Betsy", + "lastName": "Reese", + "company": "Maximind", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Workman", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Joyce", + "lastName": "Salinas", + "company": "Columella", + "employed": true + }, + { + "firstName": "Good", + "lastName": "Roach", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Margaret", + "lastName": "Rasmussen", + "company": "Futuris", + "employed": false + }, + { + "firstName": "Gaines", + "lastName": "Gilmore", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Michael", + "lastName": "Fitzgerald", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Weaver", + "lastName": "Alvarado", + "company": "Trollery", + "employed": true + }, + { + "firstName": "Burns", + "lastName": "Webb", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "April", + "lastName": "Duran", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "Valenzuela", + "company": "Ludak", + "employed": false + }, + { + "firstName": "Maude", + "lastName": "Ballard", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Martina", + "lastName": "Mckay", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Ophelia", + "lastName": "Walls", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Rachel", + "lastName": "Macdonald", + "company": "Zanymax", + "employed": false + }, + { + "firstName": "Rodgers", + "lastName": "Mccullough", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Evelyn", + "lastName": "Berry", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Mckay", + "lastName": "Hatfield", + "company": "Terrago", + "employed": true + }, + { + "firstName": "Fran", + "lastName": "Rojas", + "company": "Kage", + "employed": false + }, + { + "firstName": "Chavez", + "lastName": "Hicks", + "company": "Cowtown", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Fisher", + "company": "Squish", + "employed": true + }, + { + "firstName": "Holmes", + "lastName": "Oconnor", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Rowe", + "lastName": "Robles", + "company": "Comtrak", + "employed": true + }, + { + "firstName": "Christa", + "lastName": "Horton", + "company": "Portica", + "employed": true + }, + { + "firstName": "Martin", + "lastName": "Justice", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Witt", + "lastName": "Odom", + "company": "Bunga", + "employed": true + }, + { + "firstName": "Evangeline", + "lastName": "Gates", + "company": "Zentry", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Stout", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Shauna", + "lastName": "Page", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Mcdonald", + "lastName": "Estrada", + "company": "Deviltoe", + "employed": false + }, + { + "firstName": "Yang", + "lastName": "Stevenson", + "company": "Volax", + "employed": false + }, + { + "firstName": "Mclaughlin", + "lastName": "Beach", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Lynn", + "lastName": "Blackwell", + "company": "Plasmosis", + "employed": true + }, + { + "firstName": "Figueroa", + "lastName": "Mccarthy", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Hale", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Gretchen", + "lastName": "Fields", + "company": "Zillidium", + "employed": false + }, + { + "firstName": "Benton", + "lastName": "Mckenzie", + "company": "Utara", + "employed": false + }, + { + "firstName": "Audra", + "lastName": "Cooley", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Deanne", + "lastName": "Witt", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Mendoza", + "company": "Exospace", + "employed": true + }, + { + "firstName": "Victoria", + "lastName": "Yang", + "company": "Eventage", + "employed": false + }, + { + "firstName": "Luisa", + "lastName": "Lewis", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Landry", + "lastName": "Villarreal", + "company": "Accel", + "employed": true + }, + { + "firstName": "Riggs", + "lastName": "Hart", + "company": "Songlines", + "employed": false + }, + { + "firstName": "Cantrell", + "lastName": "Kelley", + "company": "Fibrodyne", + "employed": true + }, + { + "firstName": "Mcdowell", + "lastName": "Knapp", + "company": "Jumpstack", + "employed": false + }, + { + "firstName": "Maribel", + "lastName": "Torres", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Higgins", + "company": "Organica", + "employed": false + }, + { + "firstName": "Farmer", + "lastName": "Hood", + "company": "Inear", + "employed": false + }, + { + "firstName": "Katrina", + "lastName": "Stein", + "company": "Architax", + "employed": false + }, + { + "firstName": "Barton", + "lastName": "Bruce", + "company": "Spacewax", + "employed": false + }, + { + "firstName": "Fanny", + "lastName": "Zimmerman", + "company": "Quilch", + "employed": true + }, + { + "firstName": "Laurel", + "lastName": "Melendez", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Angelina", + "lastName": "Allison", + "company": "Comtext", + "employed": true + }, + { + "firstName": "Cora", + "lastName": "Burris", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Medina", + "lastName": "Leach", + "company": "Recognia", + "employed": false + }, + { + "firstName": "Walsh", + "lastName": "Gaines", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Faye", + "lastName": "Lawrence", + "company": "Greeker", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Molina", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Claudia", + "lastName": "Sparks", + "company": "Snorus", + "employed": true + }, + { + "firstName": "Lou", + "lastName": "Hyde", + "company": "Exposa", + "employed": false + }, + { + "firstName": "Sallie", + "lastName": "Crawford", + "company": "Codax", + "employed": false + }, + { + "firstName": "Stout", + "lastName": "Mccormick", + "company": "Comvex", + "employed": false + }, + { + "firstName": "Rosa", + "lastName": "Boyd", + "company": "Splinx", + "employed": true + }, + { + "firstName": "Winnie", + "lastName": "Larsen", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Livingston", + "lastName": "Wolf", + "company": "Marqet", + "employed": false + }, + { + "firstName": "Jeannine", + "lastName": "Ferrell", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Wilkins", + "lastName": "Richmond", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Mason", + "lastName": "Carrillo", + "company": "Eschoir", + "employed": true + }, + { + "firstName": "Mendoza", + "lastName": "Phelps", + "company": "Isologica", + "employed": true + }, + { + "firstName": "Craig", + "lastName": "Bowman", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Roberson", + "lastName": "Wood", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Penelope", + "lastName": "Davidson", + "company": "Keengen", + "employed": false + }, + { + "firstName": "Ferguson", + "lastName": "Osborn", + "company": "Digitalus", + "employed": false + }, + { + "firstName": "Cecilia", + "lastName": "Castro", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Bowers", + "lastName": "Oneal", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Strickland", + "lastName": "Harrell", + "company": "Harmoney", + "employed": false + }, + { + "firstName": "Carlene", + "lastName": "Floyd", + "company": "Tripsch", + "employed": false + }, + { + "firstName": "Middleton", + "lastName": "Dillon", + "company": "Mazuda", + "employed": true + }, + { + "firstName": "Janis", + "lastName": "Hogan", + "company": "Irack", + "employed": false + }, + { + "firstName": "Dolly", + "lastName": "Albert", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Adriana", + "lastName": "Holman", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Gertrude", + "lastName": "Castaneda", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Shields", + "lastName": "Nichols", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Frye", + "lastName": "Goodman", + "company": "Kongle", + "employed": false + }, + { + "firstName": "Benita", + "lastName": "Chandler", + "company": "Danja", + "employed": true + }, + { + "firstName": "Nolan", + "lastName": "Miranda", + "company": "Netropic", + "employed": true + }, + { + "firstName": "Dixie", + "lastName": "Nixon", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Hahn", + "lastName": "Lang", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Janette", + "lastName": "Glass", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Stanton", + "lastName": "Stafford", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Miranda", + "lastName": "Moon", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Rasmussen", + "lastName": "Odonnell", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Combs", + "lastName": "Olsen", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Florence", + "lastName": "Williamson", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Shanna", + "lastName": "Welch", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Lourdes", + "lastName": "Vance", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Barron", + "lastName": "Orr", + "company": "Waterbaby", + "employed": true + }, + { + "firstName": "Franco", + "lastName": "Howard", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Bette", + "lastName": "Browning", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Phelps", + "lastName": "Baldwin", + "company": "Snips", + "employed": true + }, + { + "firstName": "Sylvia", + "lastName": "Howe", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Herrera", + "lastName": "Serrano", + "company": "Primordia", + "employed": false + }, + { + "firstName": "Karen", + "lastName": "Grimes", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Turner", + "lastName": "Barnes", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Herman", + "lastName": "Rosario", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Stacie", + "lastName": "Nielsen", + "company": "Geekola", + "employed": true + }, + { + "firstName": "Kinney", + "lastName": "Reynolds", + "company": "Netbook", + "employed": false + }, + { + "firstName": "Renee", + "lastName": "Graves", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Dorothea", + "lastName": "Hendrix", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Dona", + "lastName": "Madden", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Ivy", + "lastName": "Ford", + "company": "Zentility", + "employed": true + }, + { + "firstName": "Maxine", + "lastName": "Garrett", + "company": "Zilodyne", + "employed": false + }, + { + "firstName": "Cash", + "lastName": "Bryan", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Marion", + "lastName": "Booker", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Melva", + "lastName": "Davis", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Ella", + "lastName": "Simon", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Vicky", + "lastName": "Patel", + "company": "Joviold", + "employed": false + }, + { + "firstName": "Judy", + "lastName": "Santana", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Gwen", + "lastName": "Mcknight", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Colon", + "lastName": "Chambers", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Yvette", + "lastName": "Hess", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Terrie", + "lastName": "Holder", + "company": "Geekology", + "employed": false + }, + { + "firstName": "Riddle", + "lastName": "Barker", + "company": "Earthplex", + "employed": false + }, + { + "firstName": "Hansen", + "lastName": "Henderson", + "company": "Rameon", + "employed": false + }, + { + "firstName": "Hutchinson", + "lastName": "Dorsey", + "company": "Matrixity", + "employed": false + }, + { + "firstName": "Stone", + "lastName": "Powers", + "company": "Updat", + "employed": false + }, + { + "firstName": "Church", + "lastName": "Spencer", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Guerra", + "lastName": "Collins", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Hancock", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "Sutton", + "lastName": "Atkins", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Elliott", + "lastName": "Becker", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Fox", + "lastName": "Glover", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Cross", + "lastName": "Mcguire", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Shelia", + "lastName": "Pierce", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Salas", + "lastName": "Barr", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Ramsey", + "company": "Spherix", + "employed": true + }, + { + "firstName": "Bauer", + "lastName": "Hughes", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Gilda", + "lastName": "Rosa", + "company": "Acusage", + "employed": true + }, + { + "firstName": "Gonzalez", + "lastName": "Maddox", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Mathews", + "company": "Kiosk", + "employed": true + }, + { + "firstName": "Lizzie", + "lastName": "Rivera", + "company": "Imperium", + "employed": false + }, + { + "firstName": "Kristie", + "lastName": "Roberson", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Jillian", + "lastName": "Cochran", + "company": "Bovis", + "employed": true + }, + { + "firstName": "Pauline", + "lastName": "Alford", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Michael", + "company": "Qnekt", + "employed": true + }, + { + "firstName": "Gina", + "lastName": "Pitts", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Mcintosh", + "lastName": "Lester", + "company": "Talendula", + "employed": true + }, + { + "firstName": "Marjorie", + "lastName": "Mccray", + "company": "Codact", + "employed": false + }, + { + "firstName": "Mcleod", + "lastName": "Lindsey", + "company": "Waretel", + "employed": true + }, + { + "firstName": "Cain", + "lastName": "Juarez", + "company": "Netility", + "employed": true + }, + { + "firstName": "Kathleen", + "lastName": "Coffey", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Elena", + "lastName": "Griffith", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Watts", + "lastName": "Strong", + "company": "Gynk", + "employed": false + }, + { + "firstName": "Bernice", + "lastName": "Humphrey", + "company": "Musix", + "employed": false + }, + { + "firstName": "Lenora", + "lastName": "Brown", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Virginia", + "lastName": "Wilkinson", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Hines", + "lastName": "Bradford", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Farley", + "lastName": "Craft", + "company": "Satiance", + "employed": true + }, + { + "firstName": "Glenn", + "lastName": "Bauer", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Eugenia", + "lastName": "Vaughan", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Duncan", + "lastName": "Golden", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Joan", + "lastName": "Garcia", + "company": "Helixo", + "employed": true + }, + { + "firstName": "Pearlie", + "lastName": "Gill", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Ana", + "lastName": "Horn", + "company": "Cosmosis", + "employed": true + }, + { + "firstName": "Lucile", + "lastName": "Holloway", + "company": "Elentrix", + "employed": false + }, + { + "firstName": "Cara", + "lastName": "Holt", + "company": "Sybixtex", + "employed": true + }, + { + "firstName": "Bryant", + "lastName": "Gordon", + "company": "Kog", + "employed": false + }, + { + "firstName": "Fields", + "lastName": "Macias", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "York", + "lastName": "Neal", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Terra", + "lastName": "Gould", + "company": "Capscreen", + "employed": true + }, + { + "firstName": "Addie", + "lastName": "Lee", + "company": "Cofine", + "employed": true + }, + { + "firstName": "Gutierrez", + "lastName": "Emerson", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Buck", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Rogers", + "lastName": "Hayes", + "company": "Enerforce", + "employed": true + }, + { + "firstName": "Rocha", + "lastName": "Dawson", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Houston", + "lastName": "Dickson", + "company": "Permadyne", + "employed": true + }, + { + "firstName": "Duke", + "lastName": "Schroeder", + "company": "Velity", + "employed": false + }, + { + "firstName": "Burt", + "lastName": "Bennett", + "company": "Magmina", + "employed": false + }, + { + "firstName": "Melanie", + "lastName": "Blankenship", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Alexander", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Erickson", + "lastName": "George", + "company": "Vendblend", + "employed": false + }, + { + "firstName": "Mccormick", + "lastName": "Eaton", + "company": "Gology", + "employed": true + }, + { + "firstName": "Courtney", + "lastName": "Joyce", + "company": "Zaya", + "employed": false + }, + { + "firstName": "Tabatha", + "lastName": "Rodgers", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Knox", + "lastName": "Soto", + "company": "Elemantra", + "employed": true + }, + { + "firstName": "Constance", + "lastName": "Chapman", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Trujillo", + "lastName": "Avila", + "company": "Skinserve", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "Crosby", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Christy", + "lastName": "Guzman", + "company": "Providco", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Savage", + "company": "Zytrek", + "employed": false + }, + { + "firstName": "Burch", + "lastName": "Morrow", + "company": "Fortean", + "employed": true + }, + { + "firstName": "Sophie", + "lastName": "Harrington", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Shepherd", + "lastName": "Jacobson", + "company": "Powernet", + "employed": false + }, + { + "firstName": "Bowen", + "lastName": "Vargas", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Tammi", + "lastName": "Whitley", + "company": "Interfind", + "employed": true + }, + { + "firstName": "Hood", + "lastName": "Barron", + "company": "Everest", + "employed": false + }, + { + "firstName": "Patrica", + "lastName": "Summers", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Randall", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Rosella", + "lastName": "Clemons", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Carla", + "lastName": "Hebert", + "company": "Eclipsent", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Haley", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Kristi", + "lastName": "Potts", + "company": "Roughies", + "employed": false + }, + { + "firstName": "Marcy", + "lastName": "Graham", + "company": "Viasia", + "employed": true + }, + { + "firstName": "Lila", + "lastName": "Hendricks", + "company": "Zidant", + "employed": false + }, + { + "firstName": "Page", + "lastName": "Harrison", + "company": "Trasola", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Mueller", + "company": "Radiantix", + "employed": false + }, + { + "firstName": "Erma", + "lastName": "Vega", + "company": "Portico", + "employed": false + }, + { + "firstName": "Caldwell", + "lastName": "Cannon", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Juliana", + "lastName": "Gamble", + "company": "Flum", + "employed": true + }, + { + "firstName": "Maryellen", + "lastName": "Patton", + "company": "Anivet", + "employed": false + }, + { + "firstName": "Lucille", + "lastName": "Manning", + "company": "Microluxe", + "employed": false + }, + { + "firstName": "Latonya", + "lastName": "Potter", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Selena", + "lastName": "Everett", + "company": "Isoplex", + "employed": false + }, + { + "firstName": "Cathryn", + "lastName": "Gregory", + "company": "Techade", + "employed": true + }, + { + "firstName": "Estella", + "lastName": "Dillard", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Black", + "lastName": "Sanchez", + "company": "Handshake", + "employed": true + }, + { + "firstName": "Curtis", + "lastName": "Mitchell", + "company": "Digique", + "employed": true + }, + { + "firstName": "Dora", + "lastName": "Glenn", + "company": "Jetsilk", + "employed": false + }, + { + "firstName": "Alford", + "lastName": "Dodson", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Rodriquez", + "lastName": "Tate", + "company": "Gink", + "employed": false + }, + { + "firstName": "Ola", + "lastName": "Jensen", + "company": "Geostele", + "employed": false + }, + { + "firstName": "Sanders", + "lastName": "Mosley", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Wiggins", + "lastName": "Anderson", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Tran", + "lastName": "Weber", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Howell", + "lastName": "Wiley", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Leticia", + "lastName": "Burke", + "company": "Bytrex", + "employed": false + }, + { + "firstName": "Delores", + "lastName": "Berg", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Pennington", + "lastName": "Mayer", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Tania", + "lastName": "Valdez", + "company": "Memora", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Yates", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Rita", + "lastName": "Lopez", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Freda", + "lastName": "Hutchinson", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "French", + "company": "Exiand", + "employed": true + }, + { + "firstName": "Hunt", + "lastName": "Klein", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Alexis", + "lastName": "Munoz", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Meredith", + "lastName": "Wagner", + "company": "Polarax", + "employed": false + }, + { + "firstName": "Louise", + "lastName": "Barrett", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Katina", + "lastName": "Kinney", + "company": "Enersol", + "employed": false + }, + { + "firstName": "Leta", + "lastName": "Salazar", + "company": "Brainquil", + "employed": true + }, + { + "firstName": "Peterson", + "lastName": "Russell", + "company": "Papricut", + "employed": true + }, + { + "firstName": "Maureen", + "lastName": "Mercer", + "company": "Menbrain", + "employed": true + }, + { + "firstName": "Bullock", + "lastName": "Carroll", + "company": "Sloganaut", + "employed": true + }, + { + "firstName": "Carly", + "lastName": "Irwin", + "company": "Buzzworks", + "employed": true + }, + { + "firstName": "Casey", + "lastName": "Brewer", + "company": "Springbee", + "employed": false + }, + { + "firstName": "Jones", + "lastName": "Small", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Latasha", + "lastName": "Flynn", + "company": "Mantrix", + "employed": false + }, + { + "firstName": "Macias", + "lastName": "Leonard", + "company": "Zilla", + "employed": true + }, + { + "firstName": "Desiree", + "lastName": "Simpson", + "company": "Andryx", + "employed": false + }, + { + "firstName": "Wright", + "lastName": "Johnson", + "company": "Comtent", + "employed": false + }, + { + "firstName": "Rochelle", + "lastName": "Porter", + "company": "Cogentry", + "employed": false + }, + { + "firstName": "Reeves", + "lastName": "Huff", + "company": "Pyramia", + "employed": false + }, + { + "firstName": "Harriett", + "lastName": "Fischer", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Theresa", + "lastName": "Cohen", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Carissa", + "lastName": "Compton", + "company": "Slax", + "employed": false + }, + { + "firstName": "Austin", + "lastName": "Goodwin", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Gabriela", + "lastName": "Beard", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Chasity", + "lastName": "Burnett", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Cox", + "lastName": "Hudson", + "company": "Sustenza", + "employed": true + }, + { + "firstName": "Kara", + "lastName": "Powell", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Hooper", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Workman", + "lastName": "Stevens", + "company": "Combot", + "employed": true + }, + { + "firstName": "Flora", + "lastName": "White", + "company": "Artiq", + "employed": false + }, + { + "firstName": "Cannon", + "lastName": "Davenport", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Amanda", + "lastName": "Dunlap", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Leah", + "lastName": "Benton", + "company": "Biohab", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Sellers", + "company": "Uberlux", + "employed": true + }, + { + "firstName": "Kellie", + "lastName": "Holcomb", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Mcbride", + "lastName": "Hurley", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Tucker", + "company": "Aquoavo", + "employed": true + }, + { + "firstName": "Marla", + "lastName": "Smith", + "company": "Retrack", + "employed": false + }, + { + "firstName": "Camacho", + "lastName": "Herring", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Graham", + "lastName": "Burton", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Laverne", + "lastName": "Mcfarland", + "company": "Krag", + "employed": false + }, + { + "firstName": "Sharron", + "lastName": "Kramer", + "company": "Supportal", + "employed": false + }, + { + "firstName": "Clay", + "lastName": "Jefferson", + "company": "Digiprint", + "employed": false + }, + { + "firstName": "Brandy", + "lastName": "Foster", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Pearl", + "lastName": "Rowland", + "company": "Electonic", + "employed": false + }, + { + "firstName": "James", + "lastName": "Doyle", + "company": "Endicil", + "employed": false + }, + { + "firstName": "Lamb", + "lastName": "Heath", + "company": "Softmicro", + "employed": true + }, + { + "firstName": "Hurley", + "lastName": "Boyer", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Faulkner", + "lastName": "Moody", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Mayo", + "lastName": "Dennis", + "company": "Telequiet", + "employed": false + }, + { + "firstName": "Lori", + "lastName": "Leon", + "company": "Isosphere", + "employed": true + }, + { + "firstName": "Raquel", + "lastName": "Martinez", + "company": "Strozen", + "employed": false + }, + { + "firstName": "Loraine", + "lastName": "Cross", + "company": "Cubicide", + "employed": true + }, + { + "firstName": "Gallagher", + "lastName": "Finch", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Bessie", + "lastName": "Sears", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Rosemarie", + "lastName": "Lucas", + "company": "Silodyne", + "employed": false + }, + { + "firstName": "Susanne", + "lastName": "Benson", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Burris", + "lastName": "Stark", + "company": "Magnemo", + "employed": true + }, + { + "firstName": "Marcie", + "lastName": "Pruitt", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "Hayden", + "lastName": "Holmes", + "company": "Gorganic", + "employed": true + }, + { + "firstName": "Melissa", + "lastName": "Woodward", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Greer", + "lastName": "Frank", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Bettye", + "lastName": "Carson", + "company": "Vortexaco", + "employed": false + }, + { + "firstName": "Ernestine", + "lastName": "Greer", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Myrna", + "lastName": "Wheeler", + "company": "Terragen", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Tran", + "company": "Xinware", + "employed": true + }, + { + "firstName": "Sosa", + "lastName": "Tanner", + "company": "Boilcat", + "employed": true + }, + { + "firstName": "Estelle", + "lastName": "Velez", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Jenkins", + "lastName": "Levine", + "company": "Orbaxter", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Lane", + "company": "Hatology", + "employed": false + }, + { + "firstName": "Ortega", + "lastName": "Palmer", + "company": "Ontality", + "employed": true + }, + { + "firstName": "Delgado", + "lastName": "Cotton", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Duran", + "lastName": "York", + "company": "Sealoud", + "employed": false + }, + { + "firstName": "Annabelle", + "lastName": "Noel", + "company": "Rodeology", + "employed": false + }, + { + "firstName": "Hickman", + "lastName": "Koch", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Lois", + "lastName": "Kirkland", + "company": "Insource", + "employed": false + }, + { + "firstName": "Shelby", + "lastName": "Farley", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Ray", + "lastName": "Solis", + "company": "Acruex", + "employed": true + }, + { + "firstName": "Lindsey", + "lastName": "Franks", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Elise", + "lastName": "Poole", + "company": "Nipaz", + "employed": true + }, + { + "firstName": "Lloyd", + "lastName": "Herrera", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Gonzales", + "lastName": "Greene", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Estela", + "lastName": "Henry", + "company": "Quility", + "employed": false + }, + { + "firstName": "Dee", + "lastName": "Foreman", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Myrtle", + "lastName": "Holland", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Michael", + "lastName": "Hawkins", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Huff", + "lastName": "Weeks", + "company": "Naxdis", + "employed": true + }, + { + "firstName": "Ayers", + "lastName": "Gonzalez", + "company": "Qaboos", + "employed": true + }, + { + "firstName": "Grant", + "lastName": "Perez", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Letha", + "lastName": "Robertson", + "company": "Crustatia", + "employed": true + }, + { + "firstName": "Calhoun", + "lastName": "Johnston", + "company": "Fleetmix", + "employed": false + }, + { + "firstName": "Erika", + "lastName": "Ellis", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Randolph", + "company": "Firewax", + "employed": false + }, + { + "firstName": "Teresa", + "lastName": "Garner", + "company": "Moltonic", + "employed": false + }, + { + "firstName": "Isabella", + "lastName": "Ramos", + "company": "Comtours", + "employed": false + }, + { + "firstName": "Sharon", + "lastName": "Houston", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Wilson", + "company": "Portalis", + "employed": false + }, + { + "firstName": "Floyd", + "lastName": "Gentry", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Glenda", + "lastName": "Donovan", + "company": "Vitricomp", + "employed": false + }, + { + "firstName": "Chapman", + "lastName": "Walter", + "company": "Circum", + "employed": true + }, + { + "firstName": "Kline", + "lastName": "Gomez", + "company": "Isologics", + "employed": false + }, + { + "firstName": "Marsha", + "lastName": "Walton", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Hoover", + "lastName": "Bates", + "company": "Bitendrex", + "employed": false + }, + { + "firstName": "Holt", + "lastName": "Baxter", + "company": "Lexicondo", + "employed": true + }, + { + "firstName": "Guadalupe", + "lastName": "Bryant", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Darla", + "lastName": "Snyder", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Debra", + "lastName": "Shepherd", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Marcia", + "lastName": "Bolton", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Avis", + "lastName": "Mcconnell", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Dean", + "lastName": "Jennings", + "company": "Omatom", + "employed": false + }, + { + "firstName": "Gibson", + "lastName": "Bell", + "company": "Aquasseur", + "employed": true + }, + { + "firstName": "Camille", + "lastName": "Griffin", + "company": "Translink", + "employed": true + }, + { + "firstName": "Cooley", + "lastName": "Turner", + "company": "Magnina", + "employed": false + }, + { + "firstName": "Lynn", + "lastName": "Jimenez", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Paige", + "lastName": "Blair", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Sonia", + "lastName": "Nolan", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Mindy", + "lastName": "Parks", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Kris", + "lastName": "Mclean", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Jackson", + "lastName": "Cline", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Hinton", + "lastName": "Kidd", + "company": "Quarex", + "employed": true + }, + { + "firstName": "Compton", + "lastName": "Bowen", + "company": "Xth", + "employed": false + }, + { + "firstName": "Hannah", + "lastName": "Donaldson", + "company": "Imant", + "employed": false + }, + { + "firstName": "Anita", + "lastName": "Hodge", + "company": "Goko", + "employed": true + }, + { + "firstName": "Rhodes", + "lastName": "Barnett", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Beth", + "lastName": "Parrish", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Buckner", + "lastName": "Elliott", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Bates", + "lastName": "Charles", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Martha", + "lastName": "Sharpe", + "company": "Zork", + "employed": true + }, + { + "firstName": "Acosta", + "lastName": "Whitfield", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Weeks", + "lastName": "Shelton", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Hammond", + "lastName": "Peck", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Betty", + "lastName": "Daugherty", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Preston", + "lastName": "Paul", + "company": "Snowpoke", + "employed": true + }, + { + "firstName": "Velma", + "lastName": "Christian", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Lolita", + "lastName": "Peters", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Donovan", + "lastName": "Mcmillan", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Rose", + "lastName": "Kemp", + "company": "Locazone", + "employed": true + }, + { + "firstName": "Gale", + "lastName": "Maldonado", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Stephens", + "lastName": "Newton", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Elma", + "lastName": "Harper", + "company": "Kneedles", + "employed": false + }, + { + "firstName": "Nguyen", + "lastName": "Underwood", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Rosalie", + "lastName": "Hall", + "company": "Assistix", + "employed": false + }, + { + "firstName": "Alfreda", + "lastName": "Bird", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Latoya", + "lastName": "Kennedy", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Katelyn", + "lastName": "Tyler", + "company": "Ultrasure", + "employed": false + }, + { + "firstName": "Dawson", + "lastName": "David", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Adkins", + "lastName": "Cote", + "company": "Genesynk", + "employed": false + }, + { + "firstName": "Franks", + "lastName": "Barrera", + "company": "Euron", + "employed": false + }, + { + "firstName": "Esmeralda", + "lastName": "Long", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Dennis", + "lastName": "Fitzpatrick", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Jerri", + "lastName": "Castillo", + "company": "Virva", + "employed": false + }, + { + "firstName": "Rosario", + "lastName": "Valencia", + "company": "Zialactic", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Mckee", + "company": "Flexigen", + "employed": true + }, + { + "firstName": "Hartman", + "lastName": "Estes", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Felecia", + "lastName": "Stephenson", + "company": "Orbiflex", + "employed": false + }, + { + "firstName": "Robertson", + "lastName": "Delaney", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Lorena", + "lastName": "Forbes", + "company": "Dreamia", + "employed": true + }, + { + "firstName": "Elisabeth", + "lastName": "Bass", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Rhea", + "lastName": "Curtis", + "company": "Duflex", + "employed": true + }, + { + "firstName": "Sarah", + "lastName": "Wiggins", + "company": "Ronbert", + "employed": false + }, + { + "firstName": "Perkins", + "lastName": "Guerrero", + "company": "Medifax", + "employed": false + }, + { + "firstName": "Hicks", + "lastName": "Olson", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Clare", + "lastName": "Dyer", + "company": "Hotcakes", + "employed": false + }, + { + "firstName": "Neal", + "lastName": "Mcgowan", + "company": "Centice", + "employed": false + }, + { + "firstName": "Etta", + "lastName": "Curry", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Paulette", + "lastName": "Matthews", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Buck", + "lastName": "Rush", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Christie", + "lastName": "Fletcher", + "company": "Biolive", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Reed", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Vaughn", + "lastName": "Acosta", + "company": "Signidyne", + "employed": true + }, + { + "firstName": "Nita", + "lastName": "Frost", + "company": "Fishland", + "employed": false + }, + { + "firstName": "Curry", + "lastName": "Oneill", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Solomon", + "lastName": "Warren", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Mccoy", + "lastName": "Armstrong", + "company": "Ramjob", + "employed": false + }, + { + "firstName": "Hester", + "lastName": "Benjamin", + "company": "Telpod", + "employed": false + }, + { + "firstName": "Sondra", + "lastName": "Jarvis", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Howard", + "lastName": "Morin", + "company": "Wrapture", + "employed": false + }, + { + "firstName": "Davidson", + "lastName": "Velasquez", + "company": "Limozen", + "employed": false + }, + { + "firstName": "Bean", + "lastName": "Reeves", + "company": "Assistia", + "employed": false + }, + { + "firstName": "Powers", + "lastName": "Holden", + "company": "Furnitech", + "employed": true + }, + { + "firstName": "Simpson", + "lastName": "Richards", + "company": "Cuizine", + "employed": true + }, + { + "firstName": "Thornton", + "lastName": "Flowers", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Dionne", + "lastName": "Kaufman", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Berg", + "lastName": "Cain", + "company": "Sonique", + "employed": false + }, + { + "firstName": "Angelique", + "lastName": "Douglas", + "company": "Pharmex", + "employed": false + }, + { + "firstName": "Dejesus", + "lastName": "Duke", + "company": "Fanfare", + "employed": false + }, + { + "firstName": "Ross", + "lastName": "Luna", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Dunn", + "lastName": "Tillman", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Francisca", + "lastName": "Cantu", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Traci", + "lastName": "Cabrera", + "company": "Conferia", + "employed": true + }, + { + "firstName": "Cooper", + "lastName": "Flores", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Evangelina", + "lastName": "Rosales", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Roth", + "lastName": "Lynch", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Lorna", + "lastName": "Dalton", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Booth", + "lastName": "Perry", + "company": "Talae", + "employed": true + }, + { + "firstName": "Gabrielle", + "lastName": "Slater", + "company": "Senmao", + "employed": true + }, + { + "firstName": "Whitley", + "lastName": "Hines", + "company": "Asimiline", + "employed": false + }, + { + "firstName": "Christi", + "lastName": "Spears", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Meagan", + "lastName": "Love", + "company": "Emergent", + "employed": true + }, + { + "firstName": "Castillo", + "lastName": "Rivas", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Rollins", + "company": "Xeronk", + "employed": true + }, + { + "firstName": "Dickson", + "lastName": "King", + "company": "Remold", + "employed": false + }, + { + "firstName": "Marianne", + "lastName": "Aguilar", + "company": "Xurban", + "employed": false + }, + { + "firstName": "Ronda", + "lastName": "Nieves", + "company": "Optique", + "employed": false + }, + { + "firstName": "Hawkins", + "lastName": "Bender", + "company": "Nimon", + "employed": true + }, + { + "firstName": "Jacquelyn", + "lastName": "Bright", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Lina", + "lastName": "Meyer", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Cleveland", + "lastName": "Sutton", + "company": "Intergeek", + "employed": false + }, + { + "firstName": "Abbott", + "lastName": "Cash", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Debora", + "lastName": "Shepard", + "company": "Apex", + "employed": false + }, + { + "firstName": "Phillips", + "lastName": "Barry", + "company": "Viagrand", + "employed": true + }, + { + "firstName": "Millie", + "lastName": "Morris", + "company": "Inrt", + "employed": false + }, + { + "firstName": "Sparks", + "lastName": "Delacruz", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Coleman", + "lastName": "Snow", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Doreen", + "lastName": "Rice", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Estes", + "lastName": "Whitney", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Jeannie", + "lastName": "Ayers", + "company": "Puria", + "employed": true + }, + { + "firstName": "Bender", + "lastName": "Good", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Castaneda", + "lastName": "Fulton", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Bridget", + "lastName": "Harding", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Juana", + "lastName": "Hamilton", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Ramona", + "lastName": "Bullock", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Evans", + "company": "Affluex", + "employed": false + }, + { + "firstName": "Mabel", + "lastName": "Bray", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Carmela", + "lastName": "Pittman", + "company": "Shepard", + "employed": false + }, + { + "firstName": "Luella", + "lastName": "Oliver", + "company": "Verton", + "employed": false + }, + { + "firstName": "Craft", + "lastName": "Mcdonald", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Mathis", + "lastName": "Richardson", + "company": "Orbixtar", + "employed": true + }, + { + "firstName": "Dunlap", + "lastName": "Mooney", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Mcconnell", + "lastName": "Montgomery", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Gibbs", + "lastName": "Drake", + "company": "Cinaster", + "employed": true + }, + { + "firstName": "Puckett", + "lastName": "Sherman", + "company": "Automon", + "employed": true + }, + { + "firstName": "Henry", + "lastName": "Owens", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Long", + "lastName": "Collier", + "company": "Comtest", + "employed": false + }, + { + "firstName": "Susie", + "lastName": "Beck", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Trudy", + "lastName": "Cervantes", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Pearson", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Lucinda", + "lastName": "Lindsay", + "company": "Tersanki", + "employed": true + }, + { + "firstName": "Tabitha", + "lastName": "Pena", + "company": "Maxemia", + "employed": true + }, + { + "firstName": "Nikki", + "lastName": "Riggs", + "company": "Elpro", + "employed": false + }, + { + "firstName": "Hallie", + "lastName": "Frazier", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Rosalyn", + "lastName": "Robinson", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Sloan", + "lastName": "Huber", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Rivas", + "lastName": "Cherry", + "company": "Pasturia", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Sims", + "company": "Oceanica", + "employed": true + }, + { + "firstName": "Sophia", + "lastName": "Sanford", + "company": "Olympix", + "employed": false + }, + { + "firstName": "Valarie", + "lastName": "Haney", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Hopkins", + "lastName": "Sosa", + "company": "Isbol", + "employed": false + }, + { + "firstName": "Robinson", + "lastName": "Gilliam", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Gillespie", + "lastName": "Reyes", + "company": "Cyclonica", + "employed": true + }, + { + "firstName": "Barry", + "lastName": "Adams", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Meyers", + "lastName": "Blanchard", + "company": "Zolarity", + "employed": true + }, + { + "firstName": "Justice", + "lastName": "Moreno", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Casandra", + "lastName": "Cooke", + "company": "Pholio", + "employed": false + }, + { + "firstName": "Spencer", + "lastName": "Faulkner", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Linda", + "lastName": "Sheppard", + "company": "Xiix", + "employed": true + }, + { + "firstName": "Doris", + "lastName": "Lancaster", + "company": "Scentric", + "employed": true + }, + { + "firstName": "Eloise", + "lastName": "Finley", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Penny", + "lastName": "Hartman", + "company": "Ziore", + "employed": false + }, + { + "firstName": "Anderson", + "lastName": "Bishop", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Ava", + "lastName": "Ball", + "company": "Comverges", + "employed": false + }, + { + "firstName": "Pat", + "lastName": "Barlow", + "company": "Fiberox", + "employed": false + }, + { + "firstName": "Ellison", + "lastName": "Adkins", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Knowles", + "lastName": "Grant", + "company": "Applica", + "employed": false + }, + { + "firstName": "May", + "lastName": "Ellison", + "company": "Hinway", + "employed": true + }, + { + "firstName": "Cassie", + "lastName": "Mcintyre", + "company": "Aquamate", + "employed": false + }, + { + "firstName": "Reed", + "lastName": "Bernard", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Natalia", + "lastName": "Burgess", + "company": "Cemention", + "employed": false + }, + { + "firstName": "Hyde", + "lastName": "Banks", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Oneal", + "lastName": "Rogers", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Robert", + "lastName": "Mcneil", + "company": "Ezent", + "employed": true + }, + { + "firstName": "Mcmahon", + "lastName": "Coleman", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Robbins", + "lastName": "Mathis", + "company": "Isis", + "employed": true + }, + { + "firstName": "Concetta", + "lastName": "Gallagher", + "company": "Norali", + "employed": true + }, + { + "firstName": "Mckinney", + "lastName": "Mullins", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Briana", + "lastName": "Case", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Liz", + "lastName": "Owen", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Hooper", + "lastName": "Santos", + "company": "Grok", + "employed": false + }, + { + "firstName": "Marguerite", + "lastName": "Woods", + "company": "Luxuria", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Velazquez", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Coffey", + "lastName": "Bean", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Shawna", + "lastName": "Hammond", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Raymond", + "lastName": "Mcclain", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Enid", + "lastName": "Carr", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Vasquez", + "lastName": "Landry", + "company": "Franscene", + "employed": false + }, + { + "firstName": "Ina", + "lastName": "Hampton", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Carolyn", + "lastName": "Gillespie", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Hester", + "lastName": "Bonner", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Valeria", + "lastName": "Logan", + "company": "Sportan", + "employed": false + }, + { + "firstName": "Maria", + "lastName": "Schmidt", + "company": "Synkgen", + "employed": false + }, + { + "firstName": "Lane", + "lastName": "Russo", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Thelma", + "lastName": "Britt", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Barrett", + "lastName": "Guthrie", + "company": "Waab", + "employed": false + }, + { + "firstName": "Tanya", + "lastName": "Romero", + "company": "Insurity", + "employed": false + }, + { + "firstName": "Hull", + "lastName": "Day", + "company": "Extragene", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Franco", + "company": "Neptide", + "employed": true + }, + { + "firstName": "Marina", + "lastName": "Baker", + "company": "Nurplex", + "employed": true + }, + { + "firstName": "Jo", + "lastName": "Vang", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Joseph", + "lastName": "Dejesus", + "company": "Pyrami", + "employed": false + }, + { + "firstName": "Dominique", + "lastName": "Rich", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Priscilla", + "lastName": "Sweet", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Gates", + "lastName": "Stewart", + "company": "Injoy", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Garza", + "company": "Zaphire", + "employed": false + }, + { + "firstName": "Tanisha", + "lastName": "Weaver", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Carroll", + "lastName": "Joseph", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Lacey", + "lastName": "Ochoa", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Ford", + "lastName": "Burch", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Josefa", + "lastName": "Harris", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Davis", + "lastName": "Jordan", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Mccray", + "lastName": "Wright", + "company": "Cujo", + "employed": true + }, + { + "firstName": "Jenny", + "lastName": "Hernandez", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Chang", + "lastName": "Hunt", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Jennifer", + "lastName": "Bailey", + "company": "Candecor", + "employed": false + }, + { + "firstName": "Vickie", + "lastName": "Cobb", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Clara", + "lastName": "Hester", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Mayra", + "lastName": "Meyers", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Walker", + "lastName": "Kim", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Foley", + "lastName": "Sykes", + "company": "Exoteric", + "employed": false + }, + { + "firstName": "Ochoa", + "lastName": "Stone", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Sheena", + "lastName": "Fry", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Terrell", + "lastName": "Ashley", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Harrison", + "lastName": "Nguyen", + "company": "Lyria", + "employed": false + }, + { + "firstName": "Mcfarland", + "lastName": "Hardin", + "company": "Zilch", + "employed": true + }, + { + "firstName": "Phoebe", + "lastName": "Mccoy", + "company": "Dentrex", + "employed": false + }, + { + "firstName": "Vilma", + "lastName": "Melton", + "company": "Xymonk", + "employed": true + }, + { + "firstName": "Wooten", + "lastName": "Ruiz", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Tessa", + "lastName": "Stanton", + "company": "Avenetro", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Skinner", + "company": "Zogak", + "employed": true + }, + { + "firstName": "Roy", + "lastName": "Livingston", + "company": "Amril", + "employed": true + }, + { + "firstName": "Monique", + "lastName": "Jenkins", + "company": "Imkan", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Snider", + "company": "Dognost", + "employed": true + }, + { + "firstName": "Rutledge", + "lastName": "Terrell", + "company": "Nutralab", + "employed": false + }, + { + "firstName": "Jenna", + "lastName": "Harmon", + "company": "Netplax", + "employed": false + }, + { + "firstName": "Bass", + "lastName": "Church", + "company": "Navir", + "employed": true + }, + { + "firstName": "Arnold", + "lastName": "Wise", + "company": "Velos", + "employed": false + }, + { + "firstName": "Kathrine", + "lastName": "Ferguson", + "company": "Tetak", + "employed": false + }, + { + "firstName": "Queen", + "lastName": "Gonzales", + "company": "Centree", + "employed": false + }, + { + "firstName": "Carmen", + "lastName": "Todd", + "company": "Ecrater", + "employed": false + }, + { + "firstName": "Roach", + "lastName": "Kline", + "company": "Netplode", + "employed": true + }, + { + "firstName": "Tami", + "lastName": "Boyle", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Bruce", + "lastName": "Reid", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Ward", + "lastName": "Chang", + "company": "Interloo", + "employed": true + }, + { + "firstName": "Alexandra", + "lastName": "Brooks", + "company": "Flotonic", + "employed": false + }, + { + "firstName": "Joy", + "lastName": "Craig", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Trisha", + "lastName": "Silva", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Cline", + "lastName": "Rowe", + "company": "Geekwagon", + "employed": true + }, + { + "firstName": "Bush", + "lastName": "Stokes", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Mavis", + "lastName": "Galloway", + "company": "Besto", + "employed": true + }, + { + "firstName": "Kari", + "lastName": "Wells", + "company": "Digial", + "employed": false + }, + { + "firstName": "Mathews", + "lastName": "Mills", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Wilma", + "lastName": "Calderon", + "company": "Tubesys", + "employed": false + }, + { + "firstName": "Talley", + "lastName": "Moses", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Chandler", + "lastName": "Herman", + "company": "Gazak", + "employed": false + }, + { + "firstName": "Wells", + "lastName": "Waters", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Gomez", + "lastName": "Parsons", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Vega", + "lastName": "William", + "company": "Sulfax", + "employed": true + }, + { + "firstName": "Amelia", + "lastName": "May", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Georgia", + "lastName": "Hunter", + "company": "Pyramax", + "employed": true + }, + { + "firstName": "Steele", + "lastName": "Caldwell", + "company": "Zillar", + "employed": true + }, + { + "firstName": "Alicia", + "lastName": "James", + "company": "Eclipto", + "employed": true + }, + { + "firstName": "Drake", + "lastName": "Vasquez", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Mitzi", + "lastName": "Dotson", + "company": "Veraq", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Preston", + "company": "Tubalum", + "employed": true + }, + { + "firstName": "Tricia", + "lastName": "Watson", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Alison", + "lastName": "Stuart", + "company": "Envire", + "employed": true + }, + { + "firstName": "Schroeder", + "lastName": "Morse", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Walker", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Lavonne", + "lastName": "Mcintosh", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Hatfield", + "lastName": "Copeland", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Young", + "lastName": "Burt", + "company": "Zytrax", + "employed": false + }, + { + "firstName": "Yvonne", + "lastName": "Mcpherson", + "company": "Amtas", + "employed": false + }, + { + "firstName": "Bernadine", + "lastName": "Frederick", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Alissa", + "lastName": "Malone", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Earline", + "lastName": "Ratliff", + "company": "Megall", + "employed": true + }, + { + "firstName": "Kerr", + "lastName": "Cantrell", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Lauri", + "lastName": "Keith", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Daniels", + "lastName": "Cardenas", + "company": "Viocular", + "employed": false + }, + { + "firstName": "Tiffany", + "lastName": "Sweeney", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Flores", + "lastName": "Schneider", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Josephine", + "lastName": "Clements", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Laurie", + "lastName": "Fox", + "company": "Pheast", + "employed": false + }, + { + "firstName": "Lilia", + "lastName": "Medina", + "company": "Sarasonic", + "employed": true + }, + { + "firstName": "Mcguire", + "lastName": "Mcbride", + "company": "Isologia", + "employed": false + }, + { + "firstName": "Carney", + "lastName": "Morales", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Iris", + "lastName": "Buckner", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Augusta", + "lastName": "Mcmahon", + "company": "Golistic", + "employed": false + }, + { + "firstName": "Noreen", + "lastName": "Deleon", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Tamera", + "lastName": "Wynn", + "company": "Jamnation", + "employed": true + }, + { + "firstName": "Madden", + "lastName": "Mccarty", + "company": "Rubadub", + "employed": false + }, + { + "firstName": "Conway", + "lastName": "Richard", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Elvia", + "lastName": "Figueroa", + "company": "Medicroix", + "employed": false + }, + { + "firstName": "Brooks", + "lastName": "Roman", + "company": "Comcur", + "employed": true + }, + { + "firstName": "Arline", + "lastName": "Marks", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Amber", + "lastName": "Mcdowell", + "company": "Poshome", + "employed": true + }, + { + "firstName": "Melendez", + "lastName": "Hanson", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Ethel", + "lastName": "Ryan", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Jeannette", + "lastName": "Nunez", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Stephanie", + "lastName": "Aguirre", + "company": "Grupoli", + "employed": false + }, + { + "firstName": "Marquita", + "lastName": "Brennan", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Warner", + "company": "Quizka", + "employed": false + }, + { + "firstName": "Freeman", + "lastName": "Moss", + "company": "Rockyard", + "employed": true + }, + { + "firstName": "Lakisha", + "lastName": "Sullivan", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Valdez", + "lastName": "Kirk", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Naomi", + "lastName": "Dixon", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Randolph", + "lastName": "Murphy", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Holland", + "lastName": "Ramirez", + "company": "Rodeocean", + "employed": false + }, + { + "firstName": "Reyna", + "lastName": "Rutledge", + "company": "Fitcore", + "employed": true + }, + { + "firstName": "Juanita", + "lastName": "Callahan", + "company": "Liquicom", + "employed": false + }, + { + "firstName": "Greene", + "lastName": "Strickland", + "company": "Colaire", + "employed": false + }, + { + "firstName": "Lewis", + "lastName": "Bond", + "company": "Zinca", + "employed": false + }, + { + "firstName": "Dina", + "lastName": "Murray", + "company": "Eventix", + "employed": false + }, + { + "firstName": "Paula", + "lastName": "Webster", + "company": "Zoid", + "employed": false + }, + { + "firstName": "Bernadette", + "lastName": "Cameron", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Richards", + "lastName": "Williams", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Nettie", + "lastName": "Jacobs", + "company": "Nebulean", + "employed": false + }, + { + "firstName": "Mcgee", + "lastName": "Byers", + "company": "Webiotic", + "employed": true + }, + { + "firstName": "Glover", + "lastName": "Levy", + "company": "Boink", + "employed": true + }, + { + "firstName": "Cherry", + "lastName": "Lloyd", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Huffman", + "lastName": "Petersen", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Jennie", + "lastName": "Carlson", + "company": "Coash", + "employed": false + }, + { + "firstName": "Charlotte", + "lastName": "Salas", + "company": "Netur", + "employed": false + }, + { + "firstName": "Mcgowan", + "lastName": "Tyson", + "company": "Gushkool", + "employed": true + }, + { + "firstName": "Kirk", + "lastName": "Hickman", + "company": "Tellifly", + "employed": true + }, + { + "firstName": "Jill", + "lastName": "Mayo", + "company": "Eweville", + "employed": false + }, + { + "firstName": "Stevens", + "lastName": "Huffman", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Aline", + "lastName": "Lynn", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Levy", + "lastName": "Bradshaw", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Heather", + "lastName": "Horne", + "company": "Ecolight", + "employed": false + }, + { + "firstName": "Joann", + "lastName": "Little", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Rivers", + "lastName": "Best", + "company": "Austech", + "employed": true + }, + { + "firstName": "Mueller", + "lastName": "Hinton", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Cortez", + "lastName": "Saunders", + "company": "Temorak", + "employed": false + }, + { + "firstName": "Maddox", + "lastName": "Wyatt", + "company": "Kidstock", + "employed": true + }, + { + "firstName": "Lorie", + "lastName": "Middleton", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Walls", + "lastName": "Vaughn", + "company": "Plasmox", + "employed": false + }, + { + "firstName": "Erna", + "lastName": "Massey", + "company": "Halap", + "employed": false + }, + { + "firstName": "Florine", + "lastName": "Willis", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Lela", + "lastName": "Swanson", + "company": "Vetron", + "employed": true + }, + { + "firstName": "Twila", + "lastName": "Myers", + "company": "Quailcom", + "employed": false + }, + { + "firstName": "Noel", + "lastName": "Whitehead", + "company": "Terascape", + "employed": false + }, + { + "firstName": "Carolina", + "lastName": "Cruz", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Goodman", + "lastName": "Atkinson", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Sonja", + "lastName": "Berger", + "company": "Rodemco", + "employed": true + }, + { + "firstName": "Keith", + "lastName": "Hoover", + "company": "Iplax", + "employed": false + }, + { + "firstName": "Leila", + "lastName": "Hurst", + "company": "Multron", + "employed": true + }, + { + "firstName": "Forbes", + "lastName": "Cook", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Bishop", + "lastName": "Conrad", + "company": "Digigene", + "employed": true + }, + { + "firstName": "Reva", + "lastName": "Rocha", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Gross", + "lastName": "Merrill", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Tracy", + "lastName": "Bowers", + "company": "Panzent", + "employed": true + }, + { + "firstName": "Eliza", + "lastName": "Thomas", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Whitfield", + "lastName": "Mcleod", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Hull", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Maynard", + "company": "Suretech", + "employed": false + }, + { + "firstName": "Patsy", + "lastName": "Bartlett", + "company": "Zipak", + "employed": true + }, + { + "firstName": "Mae", + "lastName": "Gross", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Nichols", + "lastName": "Beasley", + "company": "Enaut", + "employed": true + }, + { + "firstName": "Aguilar", + "lastName": "Harvey", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Cardenas", + "lastName": "Prince", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Newman", + "company": "Exerta", + "employed": false + }, + { + "firstName": "Debbie", + "lastName": "Winters", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Mays", + "company": "Katakana", + "employed": false + }, + { + "firstName": "Gregory", + "lastName": "Blevins", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Gardner", + "company": "Barkarama", + "employed": true + }, + { + "firstName": "William", + "lastName": "Mckinney", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Carr", + "lastName": "Casey", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Berry", + "lastName": "Moore", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Key", + "lastName": "Knight", + "company": "Comstar", + "employed": true + }, + { + "firstName": "Natalie", + "lastName": "Ewing", + "company": "Gronk", + "employed": true + }, + { + "firstName": "Sally", + "lastName": "Henson", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Celia", + "lastName": "Noble", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Collier", + "lastName": "Patterson", + "company": "Exoplode", + "employed": true + }, + { + "firstName": "Hamilton", + "lastName": "Duncan", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Lowe", + "lastName": "Christensen", + "company": "Niquent", + "employed": false + }, + { + "firstName": "Ebony", + "lastName": "Reilly", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Tyler", + "lastName": "Talley", + "company": "Quonata", + "employed": true + }, + { + "firstName": "Swanson", + "lastName": "Mann", + "company": "Rugstars", + "employed": false + }, + { + "firstName": "Callie", + "lastName": "Hobbs", + "company": "Unq", + "employed": true + }, + { + "firstName": "Lambert", + "lastName": "Nash", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Decker", + "lastName": "Hardy", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Hopper", + "lastName": "Phillips", + "company": "Twiist", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Lambert", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Caroline", + "lastName": "Rodriguez", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Johnston", + "lastName": "Hubbard", + "company": "Fuelton", + "employed": false + }, + { + "firstName": "Elvira", + "lastName": "Pratt", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Eunice", + "lastName": "Merritt", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Peggy", + "lastName": "Green", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Wanda", + "lastName": "Pope", + "company": "Isodrive", + "employed": true + }, + { + "firstName": "Kimberly", + "lastName": "Dean", + "company": "Medesign", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Dudley", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Staci", + "lastName": "Hopkins", + "company": "Exotechno", + "employed": true + }, + { + "firstName": "Buckley", + "lastName": "Clayton", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Janell", + "lastName": "Dale", + "company": "Qot", + "employed": true + }, + { + "firstName": "Cecile", + "lastName": "Ayala", + "company": "Zilladyne", + "employed": true + }, + { + "firstName": "Francesca", + "lastName": "Travis", + "company": "Entropix", + "employed": false + }, + { + "firstName": "Schmidt", + "lastName": "Joyner", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Leanne", + "lastName": "Espinoza", + "company": "Zaggles", + "employed": false + }, + { + "firstName": "Wagner", + "lastName": "Shields", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Johanna", + "lastName": "Downs", + "company": "Entroflex", + "employed": false + }, + { + "firstName": "Vaughan", + "lastName": "Marshall", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Jacobson", + "lastName": "Rivers", + "company": "Zentia", + "employed": true + }, + { + "firstName": "Eaton", + "lastName": "Bush", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Mosley", + "lastName": "Shannon", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Atkins", + "lastName": "Fuentes", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Cheri", + "lastName": "Mcclure", + "company": "Visalia", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "Goff", + "company": "Uneeq", + "employed": false + }, + { + "firstName": "Diann", + "lastName": "Nicholson", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Brandi", + "lastName": "Walters", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Krista", + "lastName": "Conway", + "company": "Tingles", + "employed": false + }, + { + "firstName": "Burnett", + "lastName": "Rhodes", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Dotson", + "lastName": "Gibbs", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Gordon", + "lastName": "Ortega", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Guerrero", + "lastName": "Freeman", + "company": "Comveyor", + "employed": false + }, + { + "firstName": "Atkinson", + "lastName": "Rose", + "company": "Knowlysis", + "employed": false + }, + { + "firstName": "Merrill", + "lastName": "Briggs", + "company": "Signity", + "employed": false + }, + { + "firstName": "Langley", + "lastName": "Whitaker", + "company": "Genmy", + "employed": false + }, + { + "firstName": "Boone", + "lastName": "Cleveland", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Scott", + "lastName": "Acevedo", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Roberts", + "lastName": "Thornton", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Fry", + "lastName": "Padilla", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Roseann", + "lastName": "Head", + "company": "Exoswitch", + "employed": true + }, + { + "firstName": "Suzette", + "lastName": "Campbell", + "company": "Opportech", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Marsh", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Summers", + "lastName": "Walsh", + "company": "Concility", + "employed": false + }, + { + "firstName": "Beck", + "lastName": "Giles", + "company": "Stralum", + "employed": false + }, + { + "firstName": "Dominguez", + "lastName": "Simmons", + "company": "Glasstep", + "employed": true + }, + { + "firstName": "Leanna", + "lastName": "Riddle", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Ann", + "lastName": "Chaney", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Patton", + "lastName": "Gray", + "company": "Peticular", + "employed": false + }, + { + "firstName": "Campos", + "lastName": "Weiss", + "company": "Realmo", + "employed": true + }, + { + "firstName": "Maritza", + "lastName": "Austin", + "company": "Ecraze", + "employed": true + }, + { + "firstName": "Stevenson", + "lastName": "Cole", + "company": "Assurity", + "employed": true + }, + { + "firstName": "Dodson", + "lastName": "Kelly", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Jefferson", + "lastName": "Carver", + "company": "Quinex", + "employed": true + }, + { + "firstName": "Dollie", + "lastName": "Alston", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Wilkinson", + "lastName": "Waller", + "company": "Turnling", + "employed": true + }, + { + "firstName": "Regina", + "lastName": "Burks", + "company": "Parcoe", + "employed": true + }, + { + "firstName": "Rosetta", + "lastName": "Schultz", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Kristine", + "lastName": "Robbins", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Concepcion", + "lastName": "Crane", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Mercer", + "lastName": "Ortiz", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Leigh", + "lastName": "Hansen", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Larsen", + "lastName": "Butler", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Cummings", + "lastName": "Farrell", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Chan", + "company": "Prosely", + "employed": false + }, + { + "firstName": "Jerry", + "lastName": "Wallace", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "Whitney", + "lastName": "Moran", + "company": "Obones", + "employed": false + }, + { + "firstName": "Mollie", + "lastName": "Wilkerson", + "company": "Idealis", + "employed": true + }, + { + "firstName": "Short", + "lastName": "Fuller", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Kramer", + "lastName": "Thompson", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Wheeler", + "lastName": "Gallegos", + "company": "Quotezart", + "employed": true + }, + { + "firstName": "Cecelia", + "lastName": "Booth", + "company": "Entality", + "employed": true + }, + { + "firstName": "Vera", + "lastName": "Knox", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Liza", + "lastName": "Knowles", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Owen", + "lastName": "Lara", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Wood", + "lastName": "Guerra", + "company": "Playce", + "employed": true + }, + { + "firstName": "Milagros", + "lastName": "Conner", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Myra", + "lastName": "Burns", + "company": "Urbanshee", + "employed": true + }, + { + "firstName": "Gloria", + "lastName": "Leblanc", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Ingram", + "lastName": "Contreras", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Brandie", + "lastName": "Petty", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Brooke", + "lastName": "Bridges", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Willis", + "lastName": "Sloan", + "company": "Supremia", + "employed": false + }, + { + "firstName": "Brittney", + "lastName": "Diaz", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Marian", + "lastName": "Morrison", + "company": "Liquidoc", + "employed": false + }, + { + "firstName": "Cathy", + "lastName": "Price", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Leonard", + "lastName": "Ross", + "company": "Atgen", + "employed": false + }, + { + "firstName": "Ratliff", + "lastName": "Abbott", + "company": "Dancerity", + "employed": true + }, + { + "firstName": "Rosanna", + "lastName": "Foley", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Wilder", + "lastName": "Wade", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Claudine", + "lastName": "Barber", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Booker", + "lastName": "Hahn", + "company": "Comtract", + "employed": false + }, + { + "firstName": "Manuela", + "lastName": "Allen", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Luna", + "lastName": "Sampson", + "company": "Vidto", + "employed": false + }, + { + "firstName": "Pam", + "lastName": "Arnold", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Blake", + "company": "Norsup", + "employed": true + }, + { + "firstName": "Oneil", + "lastName": "Dunn", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Graves", + "lastName": "Ward", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Collins", + "lastName": "Hays", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Tracey", + "lastName": "Delgado", + "company": "Bizmatic", + "employed": true + }, + { + "firstName": "Rosanne", + "lastName": "Hill", + "company": "Slambda", + "employed": true + }, + { + "firstName": "Lucy", + "lastName": "Hodges", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Newman", + "lastName": "Barton", + "company": "Elita", + "employed": false + }, + { + "firstName": "Beatrice", + "lastName": "Calhoun", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Kelli", + "lastName": "Stanley", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Consuelo", + "lastName": "Park", + "company": "Manufact", + "employed": true + }, + { + "firstName": "Sandy", + "lastName": "Young", + "company": "Quadeebo", + "employed": true + }, + { + "firstName": "Robbie", + "lastName": "Norton", + "company": "Limage", + "employed": false + }, + { + "firstName": "Allison", + "lastName": "Le", + "company": "Viagreat", + "employed": true + }, + { + "firstName": "Elnora", + "lastName": "Patrick", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Dena", + "lastName": "Gutierrez", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Pansy", + "lastName": "Norris", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Woods", + "lastName": "Key", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Dianne", + "lastName": "Fleming", + "company": "Hyplex", + "employed": false + }, + { + "firstName": "Strong", + "lastName": "Pennington", + "company": "Obliq", + "employed": false + }, + { + "firstName": "Mclean", + "lastName": "Carpenter", + "company": "Wazzu", + "employed": true + }, + { + "firstName": "Esther", + "lastName": "England", + "company": "Zolavo", + "employed": true + }, + { + "firstName": "Parks", + "lastName": "Meadows", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "James", + "lastName": "Vinson", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Rowland", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Lawrence", + "lastName": "Marsh", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Mcfarland", + "lastName": "Larson", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Theresa", + "lastName": "Chan", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Gates", + "lastName": "Hudson", + "company": "Terrago", + "employed": true + }, + { + "firstName": "Erna", + "lastName": "Tyler", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Mann", + "lastName": "Hanson", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Ivy", + "lastName": "Fields", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Eliza", + "lastName": "Boone", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Hewitt", + "lastName": "Dodson", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Clemons", + "lastName": "Hunter", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Pugh", + "lastName": "Allen", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Cooper", + "lastName": "Pruitt", + "company": "Furnitech", + "employed": false + }, + { + "firstName": "Koch", + "lastName": "Yates", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Gould", + "lastName": "Woodward", + "company": "Cyclonica", + "employed": true + }, + { + "firstName": "Priscilla", + "lastName": "Howe", + "company": "Makingway", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Davidson", + "company": "Sustenza", + "employed": false + }, + { + "firstName": "Josefina", + "lastName": "Dominguez", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Lynda", + "lastName": "Barker", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Gena", + "lastName": "Ryan", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Woodard", + "lastName": "Warren", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Fay", + "lastName": "Stevens", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Roberts", + "lastName": "Lowery", + "company": "Talendula", + "employed": true + }, + { + "firstName": "Peters", + "lastName": "Barnett", + "company": "Hometown", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "Raymond", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Clements", + "lastName": "House", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Brittany", + "lastName": "Gay", + "company": "Quizka", + "employed": true + }, + { + "firstName": "Ewing", + "lastName": "Waters", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Santana", + "lastName": "Stanley", + "company": "Exoplode", + "employed": false + }, + { + "firstName": "Yvette", + "lastName": "Holt", + "company": "Danja", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Pratt", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Ayala", + "lastName": "Spears", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Anderson", + "lastName": "Black", + "company": "Springbee", + "employed": false + }, + { + "firstName": "Earlene", + "lastName": "Alvarado", + "company": "Senmei", + "employed": false + }, + { + "firstName": "Clarke", + "lastName": "Pickett", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Jaime", + "lastName": "Duke", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Marsha", + "lastName": "Kirby", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Angelita", + "lastName": "Morgan", + "company": "Zilphur", + "employed": false + }, + { + "firstName": "Johnson", + "lastName": "Noel", + "company": "Vetron", + "employed": false + }, + { + "firstName": "Valarie", + "lastName": "Erickson", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Felicia", + "lastName": "Lawson", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Bobbie", + "lastName": "Herman", + "company": "Gology", + "employed": true + }, + { + "firstName": "Griffin", + "lastName": "Guerra", + "company": "Remotion", + "employed": true + }, + { + "firstName": "Queen", + "lastName": "Morales", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Osborne", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Pacheco", + "lastName": "Barry", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Bridgette", + "lastName": "Barton", + "company": "Limage", + "employed": true + }, + { + "firstName": "Finley", + "lastName": "Robertson", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Kathie", + "lastName": "Camacho", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Lynnette", + "lastName": "Stafford", + "company": "Comvey", + "employed": false + }, + { + "firstName": "Tamera", + "lastName": "Gentry", + "company": "Utara", + "employed": false + }, + { + "firstName": "Brady", + "lastName": "Lindsey", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Twila", + "lastName": "Vargas", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Lara", + "lastName": "Duran", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Thompson", + "lastName": "Vincent", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Macias", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Jensen", + "lastName": "Cook", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Annette", + "lastName": "Kline", + "company": "Miracula", + "employed": true + }, + { + "firstName": "Sweet", + "lastName": "Morrow", + "company": "Geoforma", + "employed": false + }, + { + "firstName": "Humphrey", + "lastName": "Heath", + "company": "Brainclip", + "employed": true + }, + { + "firstName": "Stark", + "lastName": "Hamilton", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Mcfadden", + "lastName": "Burgess", + "company": "Kineticut", + "employed": true + }, + { + "firstName": "Bradshaw", + "lastName": "Ward", + "company": "Earthpure", + "employed": false + }, + { + "firstName": "Stewart", + "lastName": "Freeman", + "company": "Supremia", + "employed": false + }, + { + "firstName": "Alissa", + "lastName": "Lee", + "company": "Locazone", + "employed": false + }, + { + "firstName": "Le", + "lastName": "Parker", + "company": "Providco", + "employed": true + }, + { + "firstName": "Marshall", + "lastName": "Hatfield", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Bernadette", + "lastName": "Barber", + "company": "Enthaze", + "employed": false + }, + { + "firstName": "Guerra", + "lastName": "Sherman", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Mullins", + "lastName": "Foster", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Valdez", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Delaney", + "lastName": "Thompson", + "company": "Isodrive", + "employed": false + }, + { + "firstName": "Heath", + "lastName": "Crane", + "company": "Exoswitch", + "employed": true + }, + { + "firstName": "Grant", + "lastName": "Pitts", + "company": "Terragen", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Rios", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Nancy", + "lastName": "Alston", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Barker", + "lastName": "Church", + "company": "Matrixity", + "employed": true + }, + { + "firstName": "Alma", + "lastName": "Simmons", + "company": "Talkalot", + "employed": true + }, + { + "firstName": "Pickett", + "lastName": "Cantu", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Alexis", + "lastName": "Dean", + "company": "Quantalia", + "employed": false + }, + { + "firstName": "Arnold", + "lastName": "Dixon", + "company": "Codact", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Brennan", + "company": "Jimbies", + "employed": false + }, + { + "firstName": "Cline", + "lastName": "Nicholson", + "company": "Isoswitch", + "employed": false + }, + { + "firstName": "Levy", + "lastName": "Maxwell", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Frost", + "lastName": "Davis", + "company": "Playce", + "employed": false + }, + { + "firstName": "Dean", + "lastName": "Stanton", + "company": "Radiantix", + "employed": true + }, + { + "firstName": "Tanisha", + "lastName": "Cannon", + "company": "Trasola", + "employed": false + }, + { + "firstName": "Christie", + "lastName": "Ramos", + "company": "Slofast", + "employed": true + }, + { + "firstName": "Jackson", + "lastName": "Santos", + "company": "Metroz", + "employed": false + }, + { + "firstName": "May", + "lastName": "Rodriguez", + "company": "Datacator", + "employed": false + }, + { + "firstName": "Carole", + "lastName": "Henson", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Trisha", + "lastName": "Hampton", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Schultz", + "lastName": "Rogers", + "company": "Stucco", + "employed": true + }, + { + "firstName": "April", + "lastName": "Snow", + "company": "Acusage", + "employed": false + }, + { + "firstName": "Carroll", + "lastName": "Finley", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Smith", + "lastName": "Leblanc", + "company": "Kyagoro", + "employed": true + }, + { + "firstName": "Ratliff", + "lastName": "Giles", + "company": "Codax", + "employed": true + }, + { + "firstName": "Hughes", + "lastName": "Finch", + "company": "Ecstasia", + "employed": false + }, + { + "firstName": "Rivera", + "lastName": "Mccall", + "company": "Nixelt", + "employed": false + }, + { + "firstName": "Harrison", + "lastName": "Wynn", + "company": "Olympix", + "employed": false + }, + { + "firstName": "Parsons", + "lastName": "Parsons", + "company": "Bitrex", + "employed": true + }, + { + "firstName": "Blanchard", + "lastName": "Marquez", + "company": "Centice", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Lyons", + "company": "Maineland", + "employed": true + }, + { + "firstName": "Cantu", + "lastName": "Cooke", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Ferguson", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Sims", + "company": "Assistia", + "employed": true + }, + { + "firstName": "French", + "lastName": "Jenkins", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Tiffany", + "lastName": "Hodges", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Althea", + "lastName": "Blake", + "company": "Kage", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Richmond", + "company": "Apextri", + "employed": false + }, + { + "firstName": "Velazquez", + "lastName": "Lane", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Mcneil", + "lastName": "Massey", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Vega", + "lastName": "Good", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Kathy", + "lastName": "Hernandez", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Glass", + "lastName": "Wiley", + "company": "Injoy", + "employed": false + }, + { + "firstName": "Gretchen", + "lastName": "Robles", + "company": "Medifax", + "employed": false + }, + { + "firstName": "Maynard", + "lastName": "Castaneda", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Wilson", + "lastName": "Russo", + "company": "Kinetica", + "employed": true + }, + { + "firstName": "Potter", + "lastName": "Brewer", + "company": "Flum", + "employed": false + }, + { + "firstName": "Benton", + "lastName": "Mccarty", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Whitfield", + "lastName": "Mcbride", + "company": "Plasmos", + "employed": false + }, + { + "firstName": "Haney", + "lastName": "Mcconnell", + "company": "Isotronic", + "employed": true + }, + { + "firstName": "Harriet", + "lastName": "Beck", + "company": "Concility", + "employed": true + }, + { + "firstName": "Meyers", + "lastName": "Cameron", + "company": "Optique", + "employed": true + }, + { + "firstName": "Mcgee", + "lastName": "Mccullough", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Graham", + "lastName": "Levine", + "company": "Kyaguru", + "employed": false + }, + { + "firstName": "Booker", + "lastName": "Alvarez", + "company": "Bostonic", + "employed": true + }, + { + "firstName": "Jacquelyn", + "lastName": "Burton", + "company": "Entality", + "employed": true + }, + { + "firstName": "Trujillo", + "lastName": "Velasquez", + "company": "Automon", + "employed": true + }, + { + "firstName": "Wilcox", + "lastName": "Strickland", + "company": "Isoplex", + "employed": true + }, + { + "firstName": "Cook", + "lastName": "Talley", + "company": "Eventix", + "employed": false + }, + { + "firstName": "Kristine", + "lastName": "Chavez", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Spears", + "lastName": "Estrada", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Beulah", + "lastName": "Glover", + "company": "Proxsoft", + "employed": false + }, + { + "firstName": "Stein", + "lastName": "Roberts", + "company": "Pyramax", + "employed": false + }, + { + "firstName": "Mavis", + "lastName": "Porter", + "company": "Hydrocom", + "employed": true + }, + { + "firstName": "Soto", + "lastName": "Blair", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Herminia", + "lastName": "Owens", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Scott", + "lastName": "Morrison", + "company": "Myopium", + "employed": true + }, + { + "firstName": "Lola", + "lastName": "Parrish", + "company": "Biohab", + "employed": true + }, + { + "firstName": "Corinne", + "lastName": "Goff", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Alyssa", + "lastName": "Gonzalez", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Cabrera", + "lastName": "Townsend", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Eula", + "lastName": "Solis", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Gamble", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Todd", + "lastName": "Oneal", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Luisa", + "lastName": "Conway", + "company": "Nipaz", + "employed": true + }, + { + "firstName": "Renee", + "lastName": "Randall", + "company": "Turnling", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Bentley", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Leola", + "lastName": "Dalton", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Jones", + "lastName": "Nash", + "company": "Evidends", + "employed": true + }, + { + "firstName": "Marla", + "lastName": "Reyes", + "company": "Magnina", + "employed": true + }, + { + "firstName": "Virginia", + "lastName": "Haley", + "company": "Qnekt", + "employed": false + }, + { + "firstName": "Holloway", + "lastName": "Strong", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Elisa", + "lastName": "Anderson", + "company": "Parleynet", + "employed": false + }, + { + "firstName": "Enid", + "lastName": "Nunez", + "company": "Lovepad", + "employed": true + }, + { + "firstName": "Mccoy", + "lastName": "Cote", + "company": "Velos", + "employed": false + }, + { + "firstName": "Sloan", + "lastName": "Frye", + "company": "Zillidium", + "employed": true + }, + { + "firstName": "Holden", + "lastName": "Vang", + "company": "Oceanica", + "employed": true + }, + { + "firstName": "Craft", + "lastName": "Ingram", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Mcdowell", + "lastName": "Gates", + "company": "Deminimum", + "employed": false + }, + { + "firstName": "Edith", + "lastName": "Cleveland", + "company": "Zentility", + "employed": true + }, + { + "firstName": "Kane", + "lastName": "Francis", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Hammond", + "company": "Quarx", + "employed": true + }, + { + "firstName": "Autumn", + "lastName": "Lopez", + "company": "Entroflex", + "employed": false + }, + { + "firstName": "Kathrine", + "lastName": "Cabrera", + "company": "Vendblend", + "employed": true + }, + { + "firstName": "Townsend", + "lastName": "Oneill", + "company": "Gluid", + "employed": false + }, + { + "firstName": "Britt", + "lastName": "Sullivan", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Wagner", + "lastName": "Norris", + "company": "Eweville", + "employed": true + }, + { + "firstName": "Quinn", + "lastName": "Vega", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Dillard", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Gibson", + "lastName": "Thornton", + "company": "Xerex", + "employed": true + }, + { + "firstName": "Carrillo", + "lastName": "Aguirre", + "company": "Interodeo", + "employed": true + }, + { + "firstName": "Johnnie", + "lastName": "Vazquez", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Foreman", + "company": "Gynk", + "employed": true + }, + { + "firstName": "Pittman", + "lastName": "Allison", + "company": "Primordia", + "employed": false + }, + { + "firstName": "Landry", + "lastName": "Leonard", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Shelley", + "lastName": "Weiss", + "company": "Centregy", + "employed": false + }, + { + "firstName": "Compton", + "lastName": "Zamora", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Sandra", + "lastName": "Hubbard", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Sexton", + "lastName": "Petty", + "company": "Kenegy", + "employed": true + }, + { + "firstName": "Richmond", + "lastName": "Duffy", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Nichols", + "lastName": "Mitchell", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Frye", + "lastName": "Kent", + "company": "Helixo", + "employed": false + }, + { + "firstName": "Phoebe", + "lastName": "Simpson", + "company": "Vicon", + "employed": false + }, + { + "firstName": "Claudine", + "lastName": "Carr", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Caitlin", + "lastName": "Dudley", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Santos", + "lastName": "Matthews", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Alice", + "lastName": "Knowles", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Nunez", + "lastName": "Hawkins", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Kristen", + "lastName": "Cole", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Zamora", + "lastName": "Franks", + "company": "Digigen", + "employed": false + }, + { + "firstName": "Byrd", + "lastName": "Hutchinson", + "company": "Bitendrex", + "employed": true + }, + { + "firstName": "Fitzgerald", + "lastName": "Bryan", + "company": "Slax", + "employed": true + }, + { + "firstName": "Catherine", + "lastName": "Hewitt", + "company": "Qualitern", + "employed": true + }, + { + "firstName": "Stout", + "lastName": "Benson", + "company": "Gaptec", + "employed": false + }, + { + "firstName": "Lelia", + "lastName": "Cooley", + "company": "Cosmosis", + "employed": false + }, + { + "firstName": "Alicia", + "lastName": "Daniels", + "company": "Corepan", + "employed": false + }, + { + "firstName": "Millie", + "lastName": "Gill", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Vicky", + "lastName": "Cortez", + "company": "Adornica", + "employed": false + }, + { + "firstName": "Blevins", + "lastName": "Henry", + "company": "Applica", + "employed": true + }, + { + "firstName": "Lambert", + "lastName": "Decker", + "company": "Xixan", + "employed": true + }, + { + "firstName": "Kerry", + "lastName": "Bird", + "company": "Globoil", + "employed": false + }, + { + "firstName": "Wong", + "lastName": "Kinney", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Ryan", + "lastName": "Malone", + "company": "Zepitope", + "employed": false + }, + { + "firstName": "Gladys", + "lastName": "Jordan", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Blake", + "lastName": "Fisher", + "company": "Zensure", + "employed": false + }, + { + "firstName": "Waters", + "lastName": "Mathews", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Faye", + "lastName": "Bryant", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Head", + "lastName": "Scott", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Morris", + "lastName": "Travis", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Jackie", + "lastName": "Everett", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Robyn", + "lastName": "Pennington", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Olsen", + "lastName": "Kelley", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Alvarez", + "lastName": "Potts", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Riddle", + "lastName": "Ramsey", + "company": "Polaria", + "employed": false + }, + { + "firstName": "Abbott", + "lastName": "Sanford", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Luna", + "lastName": "Carey", + "company": "Ovation", + "employed": true + }, + { + "firstName": "Keith", + "lastName": "Frost", + "company": "Cemention", + "employed": false + }, + { + "firstName": "Amy", + "lastName": "Holman", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Rutledge", + "lastName": "Campos", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Sanchez", + "lastName": "Beach", + "company": "Genmom", + "employed": true + }, + { + "firstName": "Bertie", + "lastName": "York", + "company": "Pharmex", + "employed": false + }, + { + "firstName": "Cruz", + "lastName": "Grant", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Bailey", + "lastName": "Stevenson", + "company": "Xth", + "employed": true + }, + { + "firstName": "Ophelia", + "lastName": "Waller", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Dionne", + "lastName": "Walsh", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Blair", + "lastName": "Hopkins", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Summer", + "lastName": "Shelton", + "company": "Paragonia", + "employed": true + }, + { + "firstName": "Kris", + "lastName": "Puckett", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Weeks", + "lastName": "Hester", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Robertson", + "lastName": "Carpenter", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Forbes", + "lastName": "Avila", + "company": "Cincyr", + "employed": false + }, + { + "firstName": "Mae", + "lastName": "Rosales", + "company": "Bleendot", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Perry", + "company": "Bedlam", + "employed": true + }, + { + "firstName": "Carrie", + "lastName": "Dale", + "company": "Cedward", + "employed": false + }, + { + "firstName": "Goodwin", + "lastName": "Hardin", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Tommie", + "lastName": "Chang", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Edwards", + "lastName": "Soto", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Angelia", + "lastName": "Warner", + "company": "Ontality", + "employed": true + }, + { + "firstName": "Mcdaniel", + "lastName": "Griffith", + "company": "Insectus", + "employed": false + }, + { + "firstName": "Sweeney", + "lastName": "Richardson", + "company": "Handshake", + "employed": true + }, + { + "firstName": "Beatrice", + "lastName": "Wells", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Letha", + "lastName": "Barnes", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Nell", + "lastName": "Lloyd", + "company": "Zinca", + "employed": false + }, + { + "firstName": "Christian", + "lastName": "Hansen", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Dee", + "lastName": "Nielsen", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Harmon", + "lastName": "Rivers", + "company": "Melbacor", + "employed": true + }, + { + "firstName": "Leanna", + "lastName": "Nieves", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Sutton", + "lastName": "Rutledge", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Cara", + "lastName": "Ferrell", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Marcia", + "lastName": "Park", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Kellie", + "lastName": "Valenzuela", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Holman", + "lastName": "Bridges", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Bond", + "lastName": "Bernard", + "company": "Crustatia", + "employed": false + }, + { + "firstName": "Slater", + "lastName": "Hunt", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Esperanza", + "lastName": "Tucker", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Casey", + "lastName": "Pearson", + "company": "Scentric", + "employed": true + }, + { + "firstName": "Porter", + "lastName": "Cox", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Howard", + "lastName": "Knapp", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Deana", + "lastName": "May", + "company": "Norsup", + "employed": true + }, + { + "firstName": "Morrison", + "lastName": "Patton", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Morgan", + "lastName": "Klein", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Whitley", + "lastName": "Garner", + "company": "Oronoko", + "employed": false + }, + { + "firstName": "Ava", + "lastName": "Haynes", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Jane", + "lastName": "Albert", + "company": "Turnabout", + "employed": false + }, + { + "firstName": "Hattie", + "lastName": "Benjamin", + "company": "Satiance", + "employed": true + }, + { + "firstName": "Richardson", + "lastName": "Woodard", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Kerr", + "lastName": "Palmer", + "company": "Recognia", + "employed": false + }, + { + "firstName": "Patti", + "lastName": "Solomon", + "company": "Pushcart", + "employed": false + }, + { + "firstName": "Brown", + "lastName": "Pena", + "company": "Retrack", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Harding", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Mejia", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Diann", + "lastName": "Burke", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Patsy", + "lastName": "Salinas", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Rita", + "lastName": "Joyce", + "company": "Apex", + "employed": true + }, + { + "firstName": "Chandra", + "lastName": "Vasquez", + "company": "Entropix", + "employed": false + }, + { + "firstName": "Betsy", + "lastName": "Acosta", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Pratt", + "lastName": "Graham", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Miranda", + "lastName": "Sweet", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Burns", + "lastName": "Murray", + "company": "Miraclis", + "employed": false + }, + { + "firstName": "Thelma", + "lastName": "Blackwell", + "company": "Songlines", + "employed": true + }, + { + "firstName": "Hensley", + "lastName": "Madden", + "company": "Aclima", + "employed": false + }, + { + "firstName": "Pat", + "lastName": "Hahn", + "company": "Datagene", + "employed": true + }, + { + "firstName": "Iva", + "lastName": "Fischer", + "company": "Hawkster", + "employed": false + }, + { + "firstName": "Estela", + "lastName": "Terrell", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Frances", + "lastName": "Lindsay", + "company": "Aquoavo", + "employed": false + }, + { + "firstName": "Dominguez", + "lastName": "Randolph", + "company": "Namebox", + "employed": true + }, + { + "firstName": "Lucile", + "lastName": "Snyder", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Holder", + "lastName": "Preston", + "company": "Fleetmix", + "employed": false + }, + { + "firstName": "Sosa", + "lastName": "Rush", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Frazier", + "lastName": "Hendrix", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Huffman", + "lastName": "Curry", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Wilkins", + "lastName": "Gross", + "company": "Waab", + "employed": false + }, + { + "firstName": "Monroe", + "lastName": "Poole", + "company": "Tsunamia", + "employed": true + }, + { + "firstName": "Graves", + "lastName": "Brock", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Garner", + "lastName": "Forbes", + "company": "Glasstep", + "employed": true + }, + { + "firstName": "Powell", + "lastName": "Rice", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Jana", + "lastName": "Harmon", + "company": "Kiggle", + "employed": false + }, + { + "firstName": "Jeanie", + "lastName": "Bruce", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Lana", + "lastName": "Gregory", + "company": "Speedbolt", + "employed": true + }, + { + "firstName": "Mccarty", + "lastName": "Washington", + "company": "Amril", + "employed": true + }, + { + "firstName": "Verna", + "lastName": "Peterson", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Morse", + "lastName": "Butler", + "company": "Futuris", + "employed": false + }, + { + "firstName": "Wolfe", + "lastName": "Barron", + "company": "Squish", + "employed": true + }, + { + "firstName": "Estrada", + "lastName": "Schroeder", + "company": "Imant", + "employed": false + }, + { + "firstName": "Nicholson", + "lastName": "Watts", + "company": "Skybold", + "employed": true + }, + { + "firstName": "Cheri", + "lastName": "Price", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Mccarthy", + "lastName": "Rose", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Jenny", + "lastName": "Payne", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Tania", + "lastName": "Zimmerman", + "company": "Bicol", + "employed": true + }, + { + "firstName": "Phelps", + "lastName": "Haney", + "company": "Kongle", + "employed": true + }, + { + "firstName": "Santiago", + "lastName": "Mercado", + "company": "Zilch", + "employed": false + }, + { + "firstName": "Angie", + "lastName": "Holmes", + "company": "Niquent", + "employed": false + }, + { + "firstName": "Melisa", + "lastName": "Weaver", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Natalie", + "lastName": "Delaney", + "company": "Omatom", + "employed": false + }, + { + "firstName": "Cecilia", + "lastName": "Henderson", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Blankenship", + "lastName": "Wall", + "company": "Lingoage", + "employed": true + }, + { + "firstName": "Evans", + "lastName": "Mcguire", + "company": "Zipak", + "employed": true + }, + { + "firstName": "Kristy", + "lastName": "Berg", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Dotson", + "lastName": "Molina", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Shauna", + "lastName": "Norton", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Kari", + "lastName": "Welch", + "company": "Daido", + "employed": true + }, + { + "firstName": "Daniels", + "lastName": "Rasmussen", + "company": "Eyewax", + "employed": true + }, + { + "firstName": "Stokes", + "lastName": "Chen", + "company": "Capscreen", + "employed": true + }, + { + "firstName": "Maldonado", + "lastName": "Harper", + "company": "Earbang", + "employed": false + }, + { + "firstName": "Lawanda", + "lastName": "Bonner", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Saunders", + "company": "Cuizine", + "employed": true + }, + { + "firstName": "Wilder", + "lastName": "Landry", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Andrews", + "lastName": "Petersen", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Solis", + "lastName": "Goodwin", + "company": "Halap", + "employed": false + }, + { + "firstName": "Reid", + "lastName": "Bradley", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Kidd", + "lastName": "Boyer", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Wallace", + "lastName": "Ballard", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Goff", + "lastName": "Salazar", + "company": "Geekular", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "Gaines", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Hendricks", + "lastName": "Mcgowan", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Essie", + "lastName": "Curtis", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Jennings", + "lastName": "Jackson", + "company": "Golistic", + "employed": true + }, + { + "firstName": "Robbie", + "lastName": "Gilmore", + "company": "Exosis", + "employed": true + }, + { + "firstName": "Rowland", + "lastName": "Wallace", + "company": "Combot", + "employed": true + }, + { + "firstName": "Sarah", + "lastName": "Ray", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Wall", + "lastName": "Love", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Kaufman", + "lastName": "Dotson", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Mcconnell", + "lastName": "Small", + "company": "Comtract", + "employed": false + }, + { + "firstName": "Nelson", + "lastName": "Skinner", + "company": "Liquidoc", + "employed": false + }, + { + "firstName": "Zelma", + "lastName": "Velazquez", + "company": "Exposa", + "employed": false + }, + { + "firstName": "Hallie", + "lastName": "Nelson", + "company": "Zosis", + "employed": false + }, + { + "firstName": "Gentry", + "lastName": "Bass", + "company": "Uniworld", + "employed": false + }, + { + "firstName": "Susana", + "lastName": "Whitehead", + "company": "Thredz", + "employed": false + }, + { + "firstName": "Marguerite", + "lastName": "Myers", + "company": "Orbaxter", + "employed": true + }, + { + "firstName": "Rodriquez", + "lastName": "Buckner", + "company": "Comtour", + "employed": false + }, + { + "firstName": "Rodriguez", + "lastName": "Patterson", + "company": "Netplax", + "employed": false + }, + { + "firstName": "Cora", + "lastName": "Herring", + "company": "Liquicom", + "employed": false + }, + { + "firstName": "Ramona", + "lastName": "Parks", + "company": "Megall", + "employed": false + }, + { + "firstName": "Diaz", + "lastName": "Melendez", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Green", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Christy", + "lastName": "Mcgee", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Stanley", + "lastName": "Sharp", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Evangeline", + "lastName": "Pope", + "company": "Viagreat", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Garza", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Cantrell", + "company": "Bizmatic", + "employed": true + }, + { + "firstName": "Valenzuela", + "lastName": "Shepard", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Jillian", + "lastName": "Whitney", + "company": "Boilicon", + "employed": true + }, + { + "firstName": "Josie", + "lastName": "Stark", + "company": "Inrt", + "employed": true + }, + { + "firstName": "Terrie", + "lastName": "Ochoa", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Nina", + "lastName": "Ball", + "company": "Elita", + "employed": false + }, + { + "firstName": "Jan", + "lastName": "Chambers", + "company": "Zerbina", + "employed": true + }, + { + "firstName": "Gomez", + "lastName": "Andrews", + "company": "Comcubine", + "employed": true + }, + { + "firstName": "Kristina", + "lastName": "Spencer", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Mayer", + "lastName": "Glass", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Davis", + "lastName": "Fleming", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Sheena", + "lastName": "Rollins", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Jennifer", + "lastName": "Bray", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Nicole", + "lastName": "Chaney", + "company": "Quordate", + "employed": true + }, + { + "firstName": "Tanya", + "lastName": "Walter", + "company": "Ecraze", + "employed": false + }, + { + "firstName": "Reynolds", + "lastName": "Atkinson", + "company": "Signidyne", + "employed": true + }, + { + "firstName": "Meyer", + "lastName": "Luna", + "company": "Fibrodyne", + "employed": false + }, + { + "firstName": "Lauri", + "lastName": "Shannon", + "company": "Strozen", + "employed": false + }, + { + "firstName": "Helena", + "lastName": "Blevins", + "company": "Blanet", + "employed": true + }, + { + "firstName": "Ilene", + "lastName": "Rhodes", + "company": "Sarasonic", + "employed": false + }, + { + "firstName": "Mildred", + "lastName": "Page", + "company": "Austex", + "employed": true + }, + { + "firstName": "Mclaughlin", + "lastName": "Clay", + "company": "Luxuria", + "employed": true + }, + { + "firstName": "Blanche", + "lastName": "Jimenez", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Beasley", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Nettie", + "lastName": "Sanchez", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Wood", + "lastName": "Rivas", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Freeman", + "lastName": "Bender", + "company": "Everest", + "employed": true + }, + { + "firstName": "Katina", + "lastName": "Goodman", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Jessie", + "lastName": "Conley", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Hall", + "lastName": "Gardner", + "company": "Buzzworks", + "employed": true + }, + { + "firstName": "Erin", + "lastName": "Alford", + "company": "Circum", + "employed": false + }, + { + "firstName": "Rachael", + "lastName": "Underwood", + "company": "Bullzone", + "employed": false + }, + { + "firstName": "Richards", + "lastName": "Clarke", + "company": "Signity", + "employed": false + }, + { + "firstName": "Kemp", + "lastName": "Mueller", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Samantha", + "lastName": "Quinn", + "company": "Norali", + "employed": false + }, + { + "firstName": "Nelda", + "lastName": "Hood", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Schmidt", + "lastName": "Drake", + "company": "Sureplex", + "employed": false + }, + { + "firstName": "Tricia", + "lastName": "Wagner", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Amparo", + "lastName": "Schwartz", + "company": "Acruex", + "employed": false + }, + { + "firstName": "Shari", + "lastName": "Nichols", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Lancaster", + "lastName": "Little", + "company": "Prowaste", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Bush", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Raymond", + "lastName": "Gibbs", + "company": "Ecratic", + "employed": false + }, + { + "firstName": "Josephine", + "lastName": "Jacobs", + "company": "Accidency", + "employed": false + }, + { + "firstName": "Hopper", + "lastName": "Emerson", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Stevens", + "lastName": "Hoover", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Mcdonald", + "lastName": "Sweeney", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Salas", + "lastName": "Sellers", + "company": "Gorganic", + "employed": true + }, + { + "firstName": "Dunn", + "lastName": "Osborn", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Reed", + "company": "Unia", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "Hoffman", + "company": "Hotcakes", + "employed": true + }, + { + "firstName": "Phyllis", + "lastName": "Abbott", + "company": "Zyple", + "employed": false + }, + { + "firstName": "Odom", + "lastName": "Buck", + "company": "Digial", + "employed": true + }, + { + "firstName": "Rogers", + "lastName": "Burns", + "company": "Obones", + "employed": false + }, + { + "firstName": "Elva", + "lastName": "Mccray", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Jean", + "lastName": "Rowe", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Frederick", + "lastName": "Kirkland", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Harper", + "lastName": "Castillo", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Haley", + "lastName": "Eaton", + "company": "Velity", + "employed": true + }, + { + "firstName": "Beverly", + "lastName": "Sanders", + "company": "Conjurica", + "employed": false + }, + { + "firstName": "Hatfield", + "lastName": "Franco", + "company": "Ecrater", + "employed": false + }, + { + "firstName": "Jeannette", + "lastName": "Odom", + "company": "Emtrak", + "employed": true + }, + { + "firstName": "Leann", + "lastName": "Turner", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Marva", + "lastName": "Hodge", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Perry", + "lastName": "Mckenzie", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Knapp", + "lastName": "Carney", + "company": "Sulfax", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Bishop", + "company": "Gleamink", + "employed": false + }, + { + "firstName": "Hodges", + "lastName": "Durham", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Jody", + "lastName": "Cobb", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Manning", + "lastName": "Wade", + "company": "Ziggles", + "employed": true + }, + { + "firstName": "Barnes", + "lastName": "Holcomb", + "company": "Martgo", + "employed": true + }, + { + "firstName": "Mckenzie", + "lastName": "Rojas", + "company": "Zytrax", + "employed": false + }, + { + "firstName": "Jeanine", + "lastName": "Donovan", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Espinoza", + "lastName": "Cummings", + "company": "Dymi", + "employed": true + }, + { + "firstName": "Elba", + "lastName": "Stokes", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Wise", + "lastName": "Woods", + "company": "Elemantra", + "employed": false + }, + { + "firstName": "Katrina", + "lastName": "Mullen", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Kent", + "lastName": "Marshall", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Glenn", + "lastName": "Noble", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Alyson", + "lastName": "Riggs", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Key", + "lastName": "Peck", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Sanford", + "lastName": "Murphy", + "company": "Comcur", + "employed": false + }, + { + "firstName": "Best", + "lastName": "Workman", + "company": "Securia", + "employed": false + }, + { + "firstName": "Rhonda", + "lastName": "Reilly", + "company": "Netbook", + "employed": true + }, + { + "firstName": "Esmeralda", + "lastName": "Guthrie", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Emerson", + "lastName": "Maldonado", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Knowles", + "lastName": "Clemons", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Mabel", + "lastName": "Cohen", + "company": "Teraprene", + "employed": true + }, + { + "firstName": "Carpenter", + "lastName": "Herrera", + "company": "Insuron", + "employed": true + }, + { + "firstName": "Middleton", + "lastName": "Velez", + "company": "Sybixtex", + "employed": true + }, + { + "firstName": "Loretta", + "lastName": "Britt", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Greta", + "lastName": "Cherry", + "company": "Eclipto", + "employed": false + }, + { + "firstName": "Aguilar", + "lastName": "Ellis", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Meredith", + "lastName": "Cash", + "company": "Sequitur", + "employed": false + }, + { + "firstName": "Evangelina", + "lastName": "Hart", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Bobbi", + "lastName": "Thomas", + "company": "Franscene", + "employed": false + }, + { + "firstName": "Neal", + "lastName": "Martinez", + "company": "Neocent", + "employed": false + }, + { + "firstName": "Vaughn", + "lastName": "Wilson", + "company": "Dancerity", + "employed": true + }, + { + "firstName": "Susanna", + "lastName": "Snider", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Odonnell", + "lastName": "Ware", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Tucker", + "lastName": "Weeks", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Maritza", + "lastName": "Hayes", + "company": "Portico", + "employed": true + }, + { + "firstName": "Madelyn", + "lastName": "Carroll", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Sofia", + "lastName": "Hobbs", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Mable", + "lastName": "Byers", + "company": "Geekfarm", + "employed": true + }, + { + "firstName": "Dawn", + "lastName": "Hicks", + "company": "Quadeebo", + "employed": false + }, + { + "firstName": "Kirsten", + "lastName": "Vaughn", + "company": "Eternis", + "employed": false + }, + { + "firstName": "Mcintosh", + "lastName": "Cross", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Tonia", + "lastName": "Harris", + "company": "Quantasis", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Schultz", + "company": "Techade", + "employed": false + }, + { + "firstName": "Georgina", + "lastName": "Hays", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Pitts", + "lastName": "Dorsey", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Browning", + "lastName": "Terry", + "company": "Artworlds", + "employed": true + }, + { + "firstName": "Martina", + "lastName": "Foley", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Angelina", + "lastName": "Grimes", + "company": "Qot", + "employed": true + }, + { + "firstName": "Deanna", + "lastName": "Williams", + "company": "Talae", + "employed": true + }, + { + "firstName": "Joan", + "lastName": "Shepherd", + "company": "Kog", + "employed": true + }, + { + "firstName": "Watts", + "lastName": "Callahan", + "company": "Kneedles", + "employed": true + }, + { + "firstName": "Oconnor", + "lastName": "Browning", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Rasmussen", + "lastName": "Deleon", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Ball", + "lastName": "Peters", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Noemi", + "lastName": "Melton", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Ellison", + "lastName": "Ross", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Salinas", + "lastName": "Holloway", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Audra", + "lastName": "Christensen", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Alba", + "lastName": "Larsen", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Wanda", + "lastName": "Le", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Barton", + "lastName": "James", + "company": "Iplax", + "employed": false + }, + { + "firstName": "Jarvis", + "lastName": "French", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Ashley", + "lastName": "Ratliff", + "company": "Goko", + "employed": true + }, + { + "firstName": "Rosanna", + "lastName": "Johnson", + "company": "Artiq", + "employed": false + }, + { + "firstName": "Wolf", + "lastName": "Elliott", + "company": "Microluxe", + "employed": false + }, + { + "firstName": "Jill", + "lastName": "Horn", + "company": "Singavera", + "employed": false + }, + { + "firstName": "Helene", + "lastName": "Higgins", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Brandie", + "lastName": "Calderon", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Dixon", + "lastName": "Singleton", + "company": "Freakin", + "employed": true + }, + { + "firstName": "Monica", + "lastName": "Fitzgerald", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Elise", + "lastName": "Riley", + "company": "Cablam", + "employed": false + }, + { + "firstName": "Trina", + "lastName": "Douglas", + "company": "Nebulean", + "employed": false + }, + { + "firstName": "Cochran", + "lastName": "Trevino", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Lewis", + "lastName": "Harvey", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Ruby", + "lastName": "Miles", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Mills", + "lastName": "Booker", + "company": "Imperium", + "employed": true + }, + { + "firstName": "Puckett", + "lastName": "Langley", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Hill", + "lastName": "Koch", + "company": "Geekwagon", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Meyer", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Moreno", + "lastName": "Moore", + "company": "Rugstars", + "employed": false + }, + { + "firstName": "Estes", + "lastName": "Sykes", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Donna", + "lastName": "Williamson", + "company": "Pigzart", + "employed": true + }, + { + "firstName": "Suzette", + "lastName": "Davenport", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Cohen", + "lastName": "Acevedo", + "company": "Anixang", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Howell", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Finch", + "lastName": "Mercer", + "company": "Pasturia", + "employed": true + }, + { + "firstName": "Berta", + "lastName": "Guerrero", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Chelsea", + "lastName": "Wooten", + "company": "Isosure", + "employed": true + }, + { + "firstName": "Marks", + "lastName": "Tanner", + "company": "Musanpoly", + "employed": false + }, + { + "firstName": "Roman", + "lastName": "Watkins", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Murphy", + "lastName": "Fuller", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Mckee", + "lastName": "Aguilar", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Mays", + "lastName": "Cain", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Sally", + "lastName": "Walters", + "company": "Toyletry", + "employed": false + }, + { + "firstName": "Marion", + "lastName": "Sears", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Jacobs", + "lastName": "Perkins", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Riley", + "lastName": "Brady", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Tammi", + "lastName": "Becker", + "company": "Spherix", + "employed": false + }, + { + "firstName": "Marietta", + "lastName": "Cruz", + "company": "Volax", + "employed": false + }, + { + "firstName": "Megan", + "lastName": "Wilcox", + "company": "Rodeology", + "employed": true + }, + { + "firstName": "Tessa", + "lastName": "Wolf", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Blankenship", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Howe", + "lastName": "Holland", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Sondra", + "lastName": "Humphrey", + "company": "Biflex", + "employed": false + }, + { + "firstName": "Madge", + "lastName": "Baxter", + "company": "Brainquil", + "employed": true + }, + { + "firstName": "Burch", + "lastName": "Obrien", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Concetta", + "lastName": "Day", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Veronica", + "lastName": "Patel", + "company": "Papricut", + "employed": true + }, + { + "firstName": "Hardin", + "lastName": "Harrell", + "company": "Telpod", + "employed": false + }, + { + "firstName": "Katherine", + "lastName": "Ashley", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Weber", + "lastName": "Holden", + "company": "Vidto", + "employed": true + }, + { + "firstName": "Dunlap", + "lastName": "Morin", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Lenora", + "lastName": "Roth", + "company": "Datagen", + "employed": true + }, + { + "firstName": "Bird", + "lastName": "Sampson", + "company": "Pathways", + "employed": true + }, + { + "firstName": "Felecia", + "lastName": "Atkins", + "company": "Naxdis", + "employed": false + }, + { + "firstName": "John", + "lastName": "Figueroa", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Bonita", + "lastName": "Bell", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Dianne", + "lastName": "Dennis", + "company": "Geeknet", + "employed": true + }, + { + "firstName": "Meadows", + "lastName": "Evans", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Burt", + "lastName": "Knox", + "company": "Gadtron", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Doyle", + "company": "Opticom", + "employed": false + }, + { + "firstName": "Faulkner", + "lastName": "Casey", + "company": "Kongene", + "employed": true + }, + { + "firstName": "Franco", + "lastName": "Cochran", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Tammie", + "lastName": "Austin", + "company": "Zilla", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Tyson", + "company": "Malathion", + "employed": true + }, + { + "firstName": "Henson", + "lastName": "Berger", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Cooke", + "lastName": "Stout", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Kimberly", + "lastName": "Wiggins", + "company": "Zogak", + "employed": false + }, + { + "firstName": "Carolyn", + "lastName": "Rodriquez", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Duran", + "lastName": "Fox", + "company": "Snorus", + "employed": true + }, + { + "firstName": "Luella", + "lastName": "Hale", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Lillian", + "lastName": "Bartlett", + "company": "Assitia", + "employed": true + }, + { + "firstName": "Kirby", + "lastName": "Hurst", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Horne", + "lastName": "Battle", + "company": "Isis", + "employed": false + }, + { + "firstName": "Mcpherson", + "lastName": "Garcia", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Janelle", + "lastName": "Spence", + "company": "Interfind", + "employed": true + }, + { + "firstName": "Chapman", + "lastName": "Robbins", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Misty", + "lastName": "Holder", + "company": "Geofarm", + "employed": true + }, + { + "firstName": "Susan", + "lastName": "Beard", + "company": "Kegular", + "employed": false + }, + { + "firstName": "Keller", + "lastName": "Wilkerson", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Banks", + "lastName": "Olson", + "company": "Prosure", + "employed": false + }, + { + "firstName": "Gibbs", + "lastName": "Odonnell", + "company": "Acrodance", + "employed": false + }, + { + "firstName": "Terrell", + "lastName": "Burnett", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Coleman", + "lastName": "Valencia", + "company": "Corecom", + "employed": true + }, + { + "firstName": "Barr", + "lastName": "Brooks", + "company": "Ozean", + "employed": false + }, + { + "firstName": "Florence", + "lastName": "Hooper", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Rivas", + "lastName": "Dejesus", + "company": "Netur", + "employed": false + }, + { + "firstName": "Trevino", + "lastName": "Jensen", + "company": "Gushkool", + "employed": true + }, + { + "firstName": "Garza", + "lastName": "Orr", + "company": "Magnafone", + "employed": false + }, + { + "firstName": "Elma", + "lastName": "Gray", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Edna", + "lastName": "Barr", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Drake", + "lastName": "Lewis", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Whitney", + "lastName": "Middleton", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Tabatha", + "lastName": "Kemp", + "company": "Isologica", + "employed": true + }, + { + "firstName": "Lilian", + "lastName": "Fowler", + "company": "Krag", + "employed": true + }, + { + "firstName": "Hyde", + "lastName": "Perez", + "company": "Biospan", + "employed": true + }, + { + "firstName": "Anne", + "lastName": "Miller", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Greene", + "lastName": "Mcclure", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Marissa", + "lastName": "Lara", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Meagan", + "lastName": "Gordon", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Jerri", + "lastName": "Baldwin", + "company": "Comtours", + "employed": false + }, + { + "firstName": "Short", + "lastName": "Hayden", + "company": "Manglo", + "employed": false + }, + { + "firstName": "Pauline", + "lastName": "Nguyen", + "company": "Wrapture", + "employed": true + }, + { + "firstName": "Maxine", + "lastName": "Mason", + "company": "Powernet", + "employed": true + }, + { + "firstName": "Olivia", + "lastName": "Hendricks", + "company": "Printspan", + "employed": false + }, + { + "firstName": "Helen", + "lastName": "Sloan", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Pamela", + "lastName": "Reese", + "company": "Furnafix", + "employed": true + }, + { + "firstName": "Powers", + "lastName": "Wise", + "company": "Immunics", + "employed": true + }, + { + "firstName": "Etta", + "lastName": "Houston", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Ofelia", + "lastName": "Carver", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Nieves", + "lastName": "Hill", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Sharpe", + "lastName": "Donaldson", + "company": "Besto", + "employed": true + }, + { + "firstName": "Collins", + "lastName": "Wright", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Stone", + "lastName": "Huffman", + "company": "Suretech", + "employed": false + }, + { + "firstName": "Tonya", + "lastName": "Mills", + "company": "Zialactic", + "employed": false + }, + { + "firstName": "Miriam", + "lastName": "Meyers", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Bridget", + "lastName": "Romero", + "company": "Ceprene", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Pittman", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Jeanette", + "lastName": "Cunningham", + "company": "Waterbaby", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Dunn", + "company": "Plexia", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Gilbert", + "company": "Grainspot", + "employed": true + }, + { + "firstName": "Weaver", + "lastName": "Sargent", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Key", + "company": "Recritube", + "employed": false + }, + { + "firstName": "Caldwell", + "lastName": "Cotton", + "company": "Eventex", + "employed": false + }, + { + "firstName": "Rosemarie", + "lastName": "Powers", + "company": "Knowlysis", + "employed": false + }, + { + "firstName": "Tammy", + "lastName": "Lawrence", + "company": "Acium", + "employed": true + }, + { + "firstName": "Burnett", + "lastName": "England", + "company": "Ebidco", + "employed": true + }, + { + "firstName": "Lucas", + "lastName": "Stephenson", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Green", + "lastName": "Lucas", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Jenifer", + "lastName": "Chase", + "company": "Songbird", + "employed": false + }, + { + "firstName": "Workman", + "lastName": "Arnold", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Woodward", + "lastName": "Dickerson", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Stevenson", + "lastName": "Mosley", + "company": "Steeltab", + "employed": true + }, + { + "firstName": "Claudette", + "lastName": "Jarvis", + "company": "Andershun", + "employed": false + }, + { + "firstName": "Ortiz", + "lastName": "Powell", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Long", + "lastName": "Mcfadden", + "company": "Quinex", + "employed": false + }, + { + "firstName": "Black", + "lastName": "Cervantes", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Ila", + "lastName": "Collier", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Ingrid", + "lastName": "Wood", + "company": "Virva", + "employed": true + }, + { + "firstName": "Cooley", + "lastName": "Kim", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Strong", + "lastName": "Yang", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Aisha", + "lastName": "Fry", + "company": "Electonic", + "employed": false + }, + { + "firstName": "Cathy", + "lastName": "Oconnor", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Naomi", + "lastName": "Hebert", + "company": "Uni", + "employed": true + }, + { + "firstName": "Sherrie", + "lastName": "Guzman", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Massey", + "lastName": "Newton", + "company": "Zork", + "employed": true + }, + { + "firstName": "Lauren", + "lastName": "Winters", + "company": "Qimonk", + "employed": true + }, + { + "firstName": "Teri", + "lastName": "Logan", + "company": "Twiist", + "employed": false + }, + { + "firstName": "Augusta", + "lastName": "Mack", + "company": "Noralex", + "employed": false + }, + { + "firstName": "Fox", + "lastName": "Alexander", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Fuller", + "lastName": "Keller", + "company": "Cubicide", + "employed": true + }, + { + "firstName": "Hazel", + "lastName": "Flores", + "company": "Remold", + "employed": false + }, + { + "firstName": "Alta", + "lastName": "Bean", + "company": "Vitricomp", + "employed": false + }, + { + "firstName": "Effie", + "lastName": "Mcpherson", + "company": "Greeker", + "employed": true + }, + { + "firstName": "Campos", + "lastName": "Pace", + "company": "Jumpstack", + "employed": true + }, + { + "firstName": "Randi", + "lastName": "Suarez", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Payne", + "lastName": "Hardy", + "company": "Zorromop", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Kaufman", + "company": "Escenta", + "employed": false + }, + { + "firstName": "Simon", + "lastName": "Copeland", + "company": "Viocular", + "employed": false + }, + { + "firstName": "Stacey", + "lastName": "Ayers", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Copeland", + "lastName": "Lynch", + "company": "Dognost", + "employed": true + }, + { + "firstName": "Darla", + "lastName": "Tate", + "company": "Bittor", + "employed": false + }, + { + "firstName": "Brock", + "lastName": "Kramer", + "company": "Isbol", + "employed": true + }, + { + "firstName": "Kelli", + "lastName": "Brown", + "company": "Corpulse", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Sparks", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Keri", + "lastName": "Hull", + "company": "Daisu", + "employed": false + }, + { + "firstName": "Shields", + "lastName": "Flynn", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Deidre", + "lastName": "Bates", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Carter", + "company": "Kiosk", + "employed": false + }, + { + "firstName": "Baxter", + "lastName": "Macdonald", + "company": "Isopop", + "employed": true + }, + { + "firstName": "Camille", + "lastName": "English", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Laurie", + "lastName": "Cooper", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Joyner", + "lastName": "Serrano", + "company": "Valreda", + "employed": true + }, + { + "firstName": "Bean", + "lastName": "Rosario", + "company": "Amtap", + "employed": false + }, + { + "firstName": "Sophie", + "lastName": "Mcfarland", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Hodge", + "lastName": "White", + "company": "Zaphire", + "employed": true + }, + { + "firstName": "Clarice", + "lastName": "Prince", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Pam", + "lastName": "Greer", + "company": "Organica", + "employed": true + }, + { + "firstName": "Adkins", + "lastName": "Galloway", + "company": "Columella", + "employed": true + }, + { + "firstName": "Navarro", + "lastName": "Lamb", + "company": "Vortexaco", + "employed": true + }, + { + "firstName": "Reyna", + "lastName": "William", + "company": "Exospace", + "employed": true + }, + { + "firstName": "Consuelo", + "lastName": "Conner", + "company": "Zolavo", + "employed": true + }, + { + "firstName": "Janie", + "lastName": "Rodgers", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Mathis", + "lastName": "Bennett", + "company": "Trollery", + "employed": true + }, + { + "firstName": "Bradley", + "lastName": "Horton", + "company": "Updat", + "employed": true + }, + { + "firstName": "Juliana", + "lastName": "Young", + "company": "Duoflex", + "employed": false + }, + { + "firstName": "Chris", + "lastName": "Mullins", + "company": "Calcu", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Levy", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Cindy", + "lastName": "Neal", + "company": "Zensus", + "employed": false + }, + { + "firstName": "Macdonald", + "lastName": "Contreras", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Lily", + "lastName": "Harrison", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Sophia", + "lastName": "Bowen", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Rosanne", + "lastName": "Stewart", + "company": "Tripsch", + "employed": false + }, + { + "firstName": "Guy", + "lastName": "Mendez", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Alexandra", + "lastName": "Long", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Peggy", + "lastName": "Case", + "company": "Panzent", + "employed": true + }, + { + "firstName": "Clare", + "lastName": "Padilla", + "company": "Deepends", + "employed": true + }, + { + "firstName": "Luz", + "lastName": "Crawford", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Jacqueline", + "lastName": "Newman", + "company": "Genmy", + "employed": true + }, + { + "firstName": "Maxwell", + "lastName": "Rivera", + "company": "Idealis", + "employed": false + }, + { + "firstName": "Bettye", + "lastName": "Maddox", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Mitchell", + "lastName": "Wilder", + "company": "Ovolo", + "employed": false + }, + { + "firstName": "Kelley", + "lastName": "Mathis", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Gail", + "lastName": "Hopper", + "company": "Lunchpod", + "employed": false + }, + { + "firstName": "Marcella", + "lastName": "Bailey", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Winifred", + "lastName": "Head", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Boone", + "lastName": "Briggs", + "company": "Comtest", + "employed": true + }, + { + "firstName": "Mercedes", + "lastName": "Schmidt", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Pennington", + "lastName": "Sharpe", + "company": "Exoteric", + "employed": false + }, + { + "firstName": "Lorraine", + "lastName": "Fuentes", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Janice", + "lastName": "Kirk", + "company": "Magnemo", + "employed": false + }, + { + "firstName": "Terry", + "lastName": "Pugh", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Martin", + "lastName": "Mccoy", + "company": "Mobildata", + "employed": false + }, + { + "firstName": "Underwood", + "lastName": "Collins", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Camacho", + "lastName": "Mcleod", + "company": "Ultrimax", + "employed": false + }, + { + "firstName": "Emma", + "lastName": "Livingston", + "company": "Coash", + "employed": true + }, + { + "firstName": "Elaine", + "lastName": "Conrad", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Duncan", + "lastName": "Reynolds", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Conway", + "lastName": "Joseph", + "company": "Zoarere", + "employed": true + }, + { + "firstName": "Gonzalez", + "lastName": "Silva", + "company": "Zillan", + "employed": false + }, + { + "firstName": "June", + "lastName": "Gould", + "company": "Avit", + "employed": false + }, + { + "firstName": "Natalia", + "lastName": "Graves", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Mollie", + "lastName": "Craig", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "Winters", + "lastName": "Paul", + "company": "Kidstock", + "employed": true + }, + { + "firstName": "Marquez", + "lastName": "Calhoun", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "Melissa", + "lastName": "Bolton", + "company": "Norsul", + "employed": false + }, + { + "firstName": "Faith", + "lastName": "Maynard", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Barrera", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Meadows", + "company": "Frenex", + "employed": true + }, + { + "firstName": "Daugherty", + "lastName": "Tillman", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Leah", + "lastName": "Mckay", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Jodi", + "lastName": "Nixon", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Luann", + "lastName": "Garrett", + "company": "Qaboos", + "employed": true + }, + { + "firstName": "Jewell", + "lastName": "Mcknight", + "company": "Exozent", + "employed": true + }, + { + "firstName": "Valerie", + "lastName": "Gallegos", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Sybil", + "lastName": "Avery", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "King", + "lastName": "Merritt", + "company": "Multiflex", + "employed": true + }, + { + "firstName": "Hogan", + "lastName": "Fulton", + "company": "Manufact", + "employed": false + }, + { + "firstName": "Dolly", + "lastName": "Martin", + "company": "Euron", + "employed": true + }, + { + "firstName": "Casandra", + "lastName": "Michael", + "company": "Neteria", + "employed": true + }, + { + "firstName": "Lila", + "lastName": "Johns", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Delgado", + "lastName": "Burks", + "company": "Gracker", + "employed": true + }, + { + "firstName": "Hood", + "lastName": "Horne", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Eleanor", + "lastName": "Mendoza", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Savage", + "lastName": "Moss", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Shelia", + "lastName": "Tran", + "company": "Insurity", + "employed": false + }, + { + "firstName": "Wiley", + "lastName": "Owen", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Elena", + "lastName": "Colon", + "company": "Deviltoe", + "employed": false + }, + { + "firstName": "Mai", + "lastName": "Ortega", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Millicent", + "lastName": "Hughes", + "company": "Plasmosis", + "employed": false + }, + { + "firstName": "Liz", + "lastName": "Whitfield", + "company": "Assistix", + "employed": true + }, + { + "firstName": "Fern", + "lastName": "Webster", + "company": "Optyk", + "employed": true + }, + { + "firstName": "Molly", + "lastName": "Vaughan", + "company": "Colaire", + "employed": true + }, + { + "firstName": "Joseph", + "lastName": "Faulkner", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Crystal", + "lastName": "Delacruz", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Maude", + "lastName": "Sawyer", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Ashlee", + "lastName": "Smith", + "company": "Atgen", + "employed": false + }, + { + "firstName": "Lillie", + "lastName": "Wilkinson", + "company": "Inear", + "employed": false + }, + { + "firstName": "Bonner", + "lastName": "Hall", + "company": "Tubalum", + "employed": false + }, + { + "firstName": "Castaneda", + "lastName": "Trujillo", + "company": "Krog", + "employed": false + }, + { + "firstName": "Cash", + "lastName": "Bowers", + "company": "Genekom", + "employed": false + }, + { + "firstName": "Rosario", + "lastName": "Lott", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Ramsey", + "lastName": "Lang", + "company": "Neptide", + "employed": false + }, + { + "firstName": "May", + "lastName": "Blackburn", + "company": "Zytrek", + "employed": true + }, + { + "firstName": "Dillard", + "lastName": "Mcclain", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Rachelle", + "lastName": "Willis", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Lorena", + "lastName": "Gutierrez", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Melendez", + "lastName": "Ewing", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Ellen", + "lastName": "Johnston", + "company": "Sealoud", + "employed": false + }, + { + "firstName": "Christina", + "lastName": "Schneider", + "company": "Chorizon", + "employed": true + }, + { + "firstName": "Fulton", + "lastName": "Monroe", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Frank", + "lastName": "Mcintyre", + "company": "Xinware", + "employed": true + }, + { + "firstName": "Oneal", + "lastName": "Ramirez", + "company": "Netility", + "employed": true + }, + { + "firstName": "Lynn", + "lastName": "Boyd", + "company": "Pholio", + "employed": false + }, + { + "firstName": "Anastasia", + "lastName": "Kidd", + "company": "Enquility", + "employed": true + }, + { + "firstName": "Byers", + "lastName": "Gonzales", + "company": "Namegen", + "employed": true + }, + { + "firstName": "Bowen", + "lastName": "Fernandez", + "company": "Memora", + "employed": false + }, + { + "firstName": "Harrell", + "lastName": "Lester", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Araceli", + "lastName": "Shaffer", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Jasmine", + "lastName": "Roman", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Clara", + "lastName": "Adkins", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Ramirez", + "lastName": "Charles", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Guadalupe", + "lastName": "Gillespie", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Rochelle", + "lastName": "Medina", + "company": "Savvy", + "employed": true + }, + { + "firstName": "Wendi", + "lastName": "Moody", + "company": "Centree", + "employed": false + }, + { + "firstName": "Chrystal", + "lastName": "Mckee", + "company": "Exostream", + "employed": true + }, + { + "firstName": "Marsh", + "lastName": "Whitaker", + "company": "Accuprint", + "employed": true + }, + { + "firstName": "Silva", + "lastName": "Baird", + "company": "Barkarama", + "employed": false + }, + { + "firstName": "Selma", + "lastName": "Walton", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Roslyn", + "lastName": "Glenn", + "company": "Rodemco", + "employed": true + }, + { + "firstName": "Staci", + "lastName": "Ruiz", + "company": "Shadease", + "employed": false + }, + { + "firstName": "Melton", + "lastName": "Moran", + "company": "Imkan", + "employed": false + }, + { + "firstName": "Cain", + "lastName": "Gomez", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Mejia", + "lastName": "Walls", + "company": "Accel", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Lynn", + "company": "Boink", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Castro", + "company": "Idego", + "employed": false + }, + { + "firstName": "Mindy", + "lastName": "Harrington", + "company": "Assurity", + "employed": true + }, + { + "firstName": "Tracey", + "lastName": "Sutton", + "company": "Irack", + "employed": false + }, + { + "firstName": "Ramos", + "lastName": "Flowers", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Bush", + "lastName": "Huff", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "Agnes", + "lastName": "Joyner", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Leach", + "lastName": "Gilliam", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Raquel", + "lastName": "Bullock", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Jo", + "lastName": "Pate", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Owen", + "lastName": "Bowman", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Holland", + "lastName": "Montoya", + "company": "Grupoli", + "employed": true + }, + { + "firstName": "Lorie", + "lastName": "Moses", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Rose", + "lastName": "Mckinney", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Stephens", + "lastName": "Whitley", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Hardy", + "lastName": "Dawson", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Colon", + "lastName": "Irwin", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Flores", + "lastName": "Branch", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Gabrielle", + "lastName": "Webb", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Geneva", + "lastName": "Campbell", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Marie", + "lastName": "Leach", + "company": "Voipa", + "employed": false + }, + { + "firstName": "Sullivan", + "lastName": "Fitzpatrick", + "company": "Enormo", + "employed": false + }, + { + "firstName": "Vera", + "lastName": "Olsen", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Gilliam", + "lastName": "Frederick", + "company": "Maximind", + "employed": false + }, + { + "firstName": "Jacobson", + "lastName": "Moreno", + "company": "Marvane", + "employed": true + }, + { + "firstName": "Rhea", + "lastName": "Boyle", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Darlene", + "lastName": "Munoz", + "company": "Mantrix", + "employed": false + }, + { + "firstName": "Lorna", + "lastName": "Nolan", + "company": "Unq", + "employed": true + }, + { + "firstName": "Bray", + "lastName": "Bond", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Harvey", + "lastName": "Floyd", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Genevieve", + "lastName": "Kane", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Aurelia", + "lastName": "Mclaughlin", + "company": "Envire", + "employed": true + }, + { + "firstName": "Vance", + "lastName": "Coleman", + "company": "Netropic", + "employed": true + }, + { + "firstName": "Ida", + "lastName": "Ayala", + "company": "Minga", + "employed": true + }, + { + "firstName": "Baldwin", + "lastName": "Hess", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Margaret", + "lastName": "Mccormick", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Mcdaniel", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Linda", + "lastName": "Gibson", + "company": "Comveyor", + "employed": false + }, + { + "firstName": "Mcbride", + "lastName": "Santana", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Vaughan", + "lastName": "George", + "company": "Xylar", + "employed": true + }, + { + "firstName": "Rosemary", + "lastName": "Simon", + "company": "Endipine", + "employed": false + }, + { + "firstName": "Lindsay", + "lastName": "Estes", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Connie", + "lastName": "Morris", + "company": "Zomboid", + "employed": false + }, + { + "firstName": "Angel", + "lastName": "Watson", + "company": "Zoxy", + "employed": true + }, + { + "firstName": "Atkinson", + "lastName": "Robinson", + "company": "Corporana", + "employed": true + }, + { + "firstName": "Hoover", + "lastName": "Howard", + "company": "Gink", + "employed": false + }, + { + "firstName": "Rhodes", + "lastName": "Mcmahon", + "company": "Sentia", + "employed": true + }, + { + "firstName": "Dora", + "lastName": "Clayton", + "company": "Solgan", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Byrd", + "company": "Verton", + "employed": true + }, + { + "firstName": "Jaclyn", + "lastName": "Dyer", + "company": "Prosely", + "employed": true + }, + { + "firstName": "Shaw", + "lastName": "Weber", + "company": "Fossiel", + "employed": false + }, + { + "firstName": "Roberson", + "lastName": "Wilkins", + "company": "Geekosis", + "employed": false + }, + { + "firstName": "Nixon", + "lastName": "Caldwell", + "company": "Tetak", + "employed": true + }, + { + "firstName": "Lucinda", + "lastName": "Buchanan", + "company": "Flexigen", + "employed": true + }, + { + "firstName": "Lena", + "lastName": "Rich", + "company": "Overplex", + "employed": true + }, + { + "firstName": "Moses", + "lastName": "Mayer", + "company": "Zounds", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Walker", + "company": "Unisure", + "employed": true + }, + { + "firstName": "Estella", + "lastName": "Todd", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Chavez", + "lastName": "Guy", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Anita", + "lastName": "Knight", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Annmarie", + "lastName": "Roach", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Allison", + "lastName": "Combs", + "company": "Anarco", + "employed": true + }, + { + "firstName": "Orr", + "lastName": "Bright", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Marilyn", + "lastName": "Bradshaw", + "company": "Balooba", + "employed": true + }, + { + "firstName": "Valeria", + "lastName": "Navarro", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Sheryl", + "lastName": "Edwards", + "company": "Urbanshee", + "employed": true + }, + { + "firstName": "Jefferson", + "lastName": "Oneil", + "company": "Combogen", + "employed": true + }, + { + "firstName": "Bette", + "lastName": "Ford", + "company": "Multron", + "employed": true + }, + { + "firstName": "Clarissa", + "lastName": "Kelly", + "company": "Otherway", + "employed": false + }, + { + "firstName": "Jennie", + "lastName": "Dunlap", + "company": "Architax", + "employed": false + }, + { + "firstName": "Alisa", + "lastName": "Summers", + "company": "Extro", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Dickson", + "company": "Retrotex", + "employed": true + }, + { + "firstName": "Cummings", + "lastName": "Pacheco", + "company": "Bolax", + "employed": false + }, + { + "firstName": "Dillon", + "lastName": "Carlson", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Potts", + "lastName": "Phelps", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Melva", + "lastName": "Franklin", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Ross", + "lastName": "Hinton", + "company": "Ecosys", + "employed": true + }, + { + "firstName": "Isabelle", + "lastName": "Cardenas", + "company": "Rockabye", + "employed": false + }, + { + "firstName": "Vasquez", + "lastName": "Chandler", + "company": "Dognosis", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Sheppard", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Elnora", + "lastName": "Mooney", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Pena", + "lastName": "Craft", + "company": "Softmicro", + "employed": true + }, + { + "firstName": "Conner", + "lastName": "West", + "company": "Synkgen", + "employed": true + }, + { + "firstName": "Michelle", + "lastName": "Fletcher", + "company": "Genesynk", + "employed": true + }, + { + "firstName": "Decker", + "lastName": "Vinson", + "company": "Idetica", + "employed": true + }, + { + "firstName": "Gaines", + "lastName": "Crosby", + "company": "Netagy", + "employed": true + }, + { + "firstName": "Irma", + "lastName": "Benton", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Webb", + "lastName": "Mclean", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Farrell", + "company": "Zilodyne", + "employed": true + }, + { + "firstName": "Rhoda", + "lastName": "Mays", + "company": "Quility", + "employed": false + }, + { + "firstName": "Roth", + "lastName": "Merrill", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Morgan", + "lastName": "Swanson", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Ericka", + "lastName": "Downs", + "company": "Qualitex", + "employed": false + }, + { + "firstName": "Wendy", + "lastName": "Norman", + "company": "Mitroc", + "employed": false + }, + { + "firstName": "Angelica", + "lastName": "Booth", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Kimberley", + "lastName": "Roy", + "company": "Enaut", + "employed": true + }, + { + "firstName": "Gross", + "lastName": "Bauer", + "company": "Spacewax", + "employed": true + }, + { + "firstName": "Baird", + "lastName": "Best", + "company": "Silodyne", + "employed": false + }, + { + "firstName": "Kathryn", + "lastName": "Miranda", + "company": "Verbus", + "employed": true + }, + { + "firstName": "Janis", + "lastName": "Griffin", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Marci", + "lastName": "Salas", + "company": "Temorak", + "employed": true + }, + { + "firstName": "Kaitlin", + "lastName": "Gallagher", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Kirkland", + "lastName": "Espinoza", + "company": "Xyqag", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Morton", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Robinson", + "lastName": "Hyde", + "company": "Fitcore", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Golden", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Travis", + "lastName": "Baker", + "company": "Splinx", + "employed": true + }, + { + "firstName": "Sasha", + "lastName": "Wyatt", + "company": "Zaya", + "employed": false + }, + { + "firstName": "Traci", + "lastName": "Leon", + "company": "Uberlux", + "employed": false + }, + { + "firstName": "Avila", + "lastName": "Jennings", + "company": "Anocha", + "employed": false + }, + { + "firstName": "Vickie", + "lastName": "Hines", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Gill", + "lastName": "Richard", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Mccormick", + "lastName": "Huber", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Adrienne", + "lastName": "Jones", + "company": "Pivitol", + "employed": false + }, + { + "firstName": "Harrington", + "lastName": "Berry", + "company": "Aquafire", + "employed": false + }, + { + "firstName": "Courtney", + "lastName": "Short", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Mcguire", + "lastName": "Anthony", + "company": "Zoinage", + "employed": false + }, + { + "firstName": "Gilda", + "lastName": "Villarreal", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Buckley", + "lastName": "Patrick", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Arline", + "lastName": "Riddle", + "company": "Endicil", + "employed": false + }, + { + "firstName": "Barrett", + "lastName": "Reid", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Cleo", + "lastName": "Ellison", + "company": "Inquala", + "employed": false + }, + { + "firstName": "Ronda", + "lastName": "Jefferson", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Curry", + "lastName": "Banks", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Georgette", + "lastName": "King", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Karina", + "lastName": "Torres", + "company": "Grok", + "employed": true + }, + { + "firstName": "Brewer", + "lastName": "Coffey", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Preston", + "lastName": "Stone", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Bernadine", + "lastName": "Diaz", + "company": "Earthwax", + "employed": false + }, + { + "firstName": "Simmons", + "lastName": "Hurley", + "company": "Peticular", + "employed": true + }, + { + "firstName": "Goodman", + "lastName": "Carson", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Robert", + "lastName": "Slater", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Dorothea", + "lastName": "Cline", + "company": "Junipoor", + "employed": false + }, + { + "firstName": "Petty", + "lastName": "Burt", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Silvia", + "lastName": "Hancock", + "company": "Comtrail", + "employed": true + }, + { + "firstName": "Morin", + "lastName": "Daugherty", + "company": "Extragen", + "employed": false + }, + { + "firstName": "Muriel", + "lastName": "Farmer", + "company": "Quilch", + "employed": true + }, + { + "firstName": "Burgess", + "lastName": "Frazier", + "company": "Medcom", + "employed": true + }, + { + "firstName": "Margo", + "lastName": "Farley", + "company": "Comstar", + "employed": true + }, + { + "firstName": "Montgomery", + "lastName": "Christian", + "company": "Portica", + "employed": true + }, + { + "firstName": "Toni", + "lastName": "Kennedy", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Jacklyn", + "lastName": "Compton", + "company": "Digique", + "employed": false + }, + { + "firstName": "Briggs", + "lastName": "Marks", + "company": "Gynko", + "employed": true + }, + { + "firstName": "Lacy", + "lastName": "Savage", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Lyons", + "lastName": "Mcmillan", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Hubbard", + "lastName": "Bradford", + "company": "Cubix", + "employed": false + }, + { + "firstName": "Merritt", + "lastName": "Sexton", + "company": "Navir", + "employed": false + }, + { + "firstName": "Prince", + "lastName": "Delgado", + "company": "Translink", + "employed": true + }, + { + "firstName": "Shepherd", + "lastName": "Lowe", + "company": "Progenex", + "employed": false + }, + { + "firstName": "Ballard", + "lastName": "Mccarthy", + "company": "Orbean", + "employed": true + }, + { + "firstName": "Davidson", + "lastName": "Mayo", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Melinda", + "lastName": "Manning", + "company": "Rooforia", + "employed": true + }, + { + "firstName": "Frieda", + "lastName": "Phillips", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Bradford", + "lastName": "Shaw", + "company": "Uplinx", + "employed": false + }, + { + "firstName": "Reilly", + "lastName": "Armstrong", + "company": "Musix", + "employed": false + }, + { + "firstName": "Burks", + "lastName": "Hogan", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Riggs", + "lastName": "Richards", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Dorothy", + "lastName": "Chapman", + "company": "Jetsilk", + "employed": false + }, + { + "firstName": "Lessie", + "lastName": "Taylor", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Gloria", + "lastName": "Keith", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Schneider", + "lastName": "Garrison", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Klein", + "lastName": "Santiago", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Sawyer", + "lastName": "Lambert", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Pearlie", + "lastName": "Burris", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Mariana", + "lastName": "Lancaster", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Viola", + "lastName": "Carrillo", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Velma", + "lastName": "Blanchard", + "company": "Bytrex", + "employed": false + }, + { + "firstName": "Christi", + "lastName": "Sosa", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Allen", + "lastName": "Morse", + "company": "Lexicondo", + "employed": true + }, + { + "firstName": "Brooks", + "lastName": "Daniel", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Martinez", + "lastName": "Shields", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Bernice", + "lastName": "Frank", + "company": "Petigems", + "employed": false + }, + { + "firstName": "Katie", + "lastName": "Jacobson", + "company": "Obliq", + "employed": false + }, + { + "firstName": "Sherry", + "lastName": "Roberson", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Rivers", + "lastName": "Hickman", + "company": "Genmex", + "employed": true + }, + { + "firstName": "Margret", + "lastName": "Wheeler", + "company": "Moltonic", + "employed": false + }, + { + "firstName": "Casey", + "lastName": "Burch", + "company": "Austech", + "employed": true + }, + { + "firstName": "Taylor", + "lastName": "Pollard", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Flynn", + "lastName": "Wolfe", + "company": "Acumentor", + "employed": true + }, + { + "firstName": "Lorrie", + "lastName": "Montgomery", + "company": "Medesign", + "employed": true + }, + { + "firstName": "Delacruz", + "lastName": "Hartman", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Simpson", + "lastName": "Stuart", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Fanny", + "lastName": "Rocha", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Foreman", + "lastName": "Steele", + "company": "Quintity", + "employed": true + }, + { + "firstName": "Cleveland", + "lastName": "Pierce", + "company": "Mazuda", + "employed": true + }, + { + "firstName": "Lott", + "lastName": "Moon", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Randall", + "lastName": "Barlow", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Rich", + "lastName": "Juarez", + "company": "Premiant", + "employed": true + }, + { + "firstName": "Eunice", + "lastName": "Reeves", + "company": "Diginetic", + "employed": true + }, + { + "firstName": "Heidi", + "lastName": "Mcintosh", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Herrera", + "lastName": "Oliver", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Coleen", + "lastName": "Vance", + "company": "Firewax", + "employed": true + }, + { + "firstName": "Dyer", + "lastName": "Dillon", + "company": "Gogol", + "employed": false + }, + { + "firstName": "Bessie", + "lastName": "Hensley", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Emilia", + "lastName": "Greene", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Carter", + "lastName": "Valentine", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Rena", + "lastName": "Potter", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Lina", + "lastName": "Stein", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Eileen", + "lastName": "Barrett", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Liliana", + "lastName": "David", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Karen", + "lastName": "Stephens", + "company": "Biolive", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Mcdonald", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Carissa", + "lastName": "Russell", + "company": "Puria", + "employed": true + }, + { + "firstName": "Taylor", + "lastName": "Sandoval", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Ollie", + "lastName": "Mann", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Kinney", + "lastName": "Adams", + "company": "Pyrami", + "employed": false + }, + { + "firstName": "Marta", + "lastName": "Kerr", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Whitney", + "lastName": "Justice", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Gillespie", + "lastName": "Mcdowell", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Nolan", + "lastName": "Wong", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Allison", + "lastName": "Clements", + "company": "Insource", + "employed": false + }, + { + "firstName": "Melanie", + "lastName": "Witt", + "company": "Calcula", + "employed": true + }, + { + "firstName": "Figueroa", + "lastName": "Mcneil", + "company": "Portalis", + "employed": true + }, + { + "firstName": "Perez", + "lastName": "Clark", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Ortiz", + "company": "Snips", + "employed": false + }, + { + "firstName": "Skinner", + "lastName": "Buckley", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Serrano", + "lastName": "Rosa", + "company": "Icology", + "employed": false + }, + { + "firstName": "Gardner", + "lastName": "Holloway", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Jill", + "lastName": "Snow", + "company": "Equicom", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Buckner", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Barnes", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Candice", + "lastName": "Pugh", + "company": "Dognost", + "employed": true + }, + { + "firstName": "Manning", + "lastName": "Park", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "Minerva", + "lastName": "Weber", + "company": "Slax", + "employed": true + }, + { + "firstName": "Kelli", + "lastName": "Ramsey", + "company": "Recrisys", + "employed": false + }, + { + "firstName": "Blackwell", + "lastName": "French", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Toni", + "lastName": "Graves", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Holder", + "lastName": "Mack", + "company": "Eventix", + "employed": false + }, + { + "firstName": "Garner", + "lastName": "Kaufman", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Debra", + "lastName": "Mercer", + "company": "Polarium", + "employed": false + }, + { + "firstName": "Lacy", + "lastName": "Macias", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Lorna", + "lastName": "Meyer", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Pollard", + "company": "Quizmo", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Potter", + "company": "Elentrix", + "employed": true + }, + { + "firstName": "Hartman", + "lastName": "Rivers", + "company": "Pharmex", + "employed": true + }, + { + "firstName": "Rosetta", + "lastName": "Boyer", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Margo", + "lastName": "Wood", + "company": "Vortexaco", + "employed": false + }, + { + "firstName": "Coleman", + "lastName": "Tran", + "company": "Netropic", + "employed": true + }, + { + "firstName": "Iris", + "lastName": "Doyle", + "company": "Quintity", + "employed": true + }, + { + "firstName": "Diaz", + "lastName": "Anthony", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Bowen", + "lastName": "Wong", + "company": "Iplax", + "employed": false + }, + { + "firstName": "Lucy", + "lastName": "Mcmahon", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Mcpherson", + "lastName": "Fernandez", + "company": "Kiggle", + "employed": true + }, + { + "firstName": "Carson", + "lastName": "Whitney", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Reilly", + "lastName": "Vega", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Jennie", + "lastName": "Williams", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Coffey", + "lastName": "Hansen", + "company": "Slofast", + "employed": true + }, + { + "firstName": "Genevieve", + "lastName": "Carrillo", + "company": "Bristo", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Peck", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Kathryn", + "lastName": "Sanchez", + "company": "Enerforce", + "employed": true + }, + { + "firstName": "Rosie", + "lastName": "Vincent", + "company": "Zytrek", + "employed": false + }, + { + "firstName": "Yates", + "lastName": "Gates", + "company": "Codact", + "employed": true + }, + { + "firstName": "Knox", + "lastName": "Joyner", + "company": "Exospace", + "employed": false + }, + { + "firstName": "Nellie", + "lastName": "Allen", + "company": "Turnling", + "employed": false + }, + { + "firstName": "Vance", + "lastName": "Rollins", + "company": "Vinch", + "employed": true + }, + { + "firstName": "Shanna", + "lastName": "Hendrix", + "company": "Diginetic", + "employed": false + }, + { + "firstName": "Patrica", + "lastName": "Byrd", + "company": "Krog", + "employed": true + }, + { + "firstName": "Bright", + "lastName": "Chambers", + "company": "Gogol", + "employed": true + }, + { + "firstName": "Drake", + "lastName": "Rice", + "company": "Sarasonic", + "employed": true + }, + { + "firstName": "Valarie", + "lastName": "Berry", + "company": "Enervate", + "employed": true + }, + { + "firstName": "Jessica", + "lastName": "Cervantes", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Curtis", + "lastName": "Herring", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Schultz", + "lastName": "Holmes", + "company": "Mantro", + "employed": true + }, + { + "firstName": "Deirdre", + "lastName": "Ratliff", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Marietta", + "lastName": "Lee", + "company": "Telpod", + "employed": true + }, + { + "firstName": "Silva", + "lastName": "Lynch", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Kennedy", + "lastName": "Vasquez", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Vanessa", + "lastName": "Mclaughlin", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Hopkins", + "company": "Printspan", + "employed": false + }, + { + "firstName": "Ortiz", + "lastName": "Martinez", + "company": "Songbird", + "employed": false + }, + { + "firstName": "Moreno", + "lastName": "Osborne", + "company": "Arctiq", + "employed": true + }, + { + "firstName": "Carter", + "lastName": "Warren", + "company": "Isologica", + "employed": true + }, + { + "firstName": "Paulette", + "lastName": "Kline", + "company": "Apex", + "employed": true + }, + { + "firstName": "Cline", + "lastName": "Sherman", + "company": "Repetwire", + "employed": true + }, + { + "firstName": "Aurelia", + "lastName": "Powers", + "company": "Obones", + "employed": false + }, + { + "firstName": "Burt", + "lastName": "Wilkinson", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Lancaster", + "lastName": "Benson", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Hawkins", + "lastName": "Albert", + "company": "Aquafire", + "employed": true + }, + { + "firstName": "Deidre", + "lastName": "Cherry", + "company": "Waretel", + "employed": true + }, + { + "firstName": "Shelton", + "lastName": "Pope", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "Jaime", + "lastName": "Bush", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Mable", + "lastName": "Mendez", + "company": "Furnafix", + "employed": false + }, + { + "firstName": "Jeri", + "lastName": "Tyson", + "company": "Ezentia", + "employed": false + }, + { + "firstName": "Wells", + "lastName": "Moody", + "company": "Indexia", + "employed": true + }, + { + "firstName": "Olson", + "lastName": "Golden", + "company": "Geostele", + "employed": true + }, + { + "firstName": "Valerie", + "lastName": "Olsen", + "company": "Miracula", + "employed": true + }, + { + "firstName": "Kristine", + "lastName": "Patel", + "company": "Orbixtar", + "employed": false + }, + { + "firstName": "Shana", + "lastName": "Chang", + "company": "Jetsilk", + "employed": true + }, + { + "firstName": "Mcleod", + "lastName": "Walter", + "company": "Magnina", + "employed": false + }, + { + "firstName": "Cotton", + "lastName": "Cash", + "company": "Biohab", + "employed": true + }, + { + "firstName": "Olivia", + "lastName": "Byers", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Mccoy", + "lastName": "Hartman", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Letha", + "lastName": "Kidd", + "company": "Multiflex", + "employed": true + }, + { + "firstName": "Raquel", + "lastName": "Sexton", + "company": "Utara", + "employed": false + }, + { + "firstName": "Freeman", + "lastName": "Richards", + "company": "Quility", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Wiley", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Beatrice", + "lastName": "Mccray", + "company": "Plasmosis", + "employed": true + }, + { + "firstName": "Essie", + "lastName": "Irwin", + "company": "Solaren", + "employed": false + }, + { + "firstName": "Robertson", + "lastName": "Carpenter", + "company": "Opticon", + "employed": true + }, + { + "firstName": "Tanya", + "lastName": "Wiggins", + "company": "Kog", + "employed": false + }, + { + "firstName": "Noemi", + "lastName": "Maddox", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Kline", + "lastName": "Reyes", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Mariana", + "lastName": "Warner", + "company": "Prosely", + "employed": false + }, + { + "firstName": "Wood", + "lastName": "Hawkins", + "company": "Idego", + "employed": false + }, + { + "firstName": "Le", + "lastName": "David", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Mcfarland", + "lastName": "Campbell", + "company": "Housedown", + "employed": true + }, + { + "firstName": "Tasha", + "lastName": "Valencia", + "company": "Ecolight", + "employed": true + }, + { + "firstName": "Nikki", + "lastName": "Gill", + "company": "Lingoage", + "employed": true + }, + { + "firstName": "Georgia", + "lastName": "Beck", + "company": "Yogasm", + "employed": true + }, + { + "firstName": "Kathy", + "lastName": "Sweet", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Jana", + "lastName": "Huffman", + "company": "Zillan", + "employed": true + }, + { + "firstName": "Norma", + "lastName": "Dean", + "company": "Escenta", + "employed": true + }, + { + "firstName": "Matilda", + "lastName": "Levy", + "company": "Bovis", + "employed": true + }, + { + "firstName": "Shirley", + "lastName": "Moreno", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Holman", + "lastName": "Navarro", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Lora", + "lastName": "Hahn", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Patel", + "lastName": "Aguirre", + "company": "Kiosk", + "employed": false + }, + { + "firstName": "Prince", + "lastName": "Blevins", + "company": "Snips", + "employed": true + }, + { + "firstName": "Kelley", + "lastName": "Gregory", + "company": "Avit", + "employed": true + }, + { + "firstName": "Campos", + "lastName": "Dalton", + "company": "Mediot", + "employed": false + }, + { + "firstName": "Massey", + "lastName": "Kirby", + "company": "Volax", + "employed": true + }, + { + "firstName": "Navarro", + "lastName": "Sharp", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Sykes", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Frances", + "lastName": "Lyons", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "William", + "lastName": "Blackburn", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Blanchard", + "company": "Inventure", + "employed": true + }, + { + "firstName": "Luann", + "lastName": "Herrera", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Althea", + "lastName": "Davenport", + "company": "Megall", + "employed": true + }, + { + "firstName": "Stanley", + "lastName": "Pickett", + "company": "Zenthall", + "employed": false + }, + { + "firstName": "Dina", + "lastName": "Hodge", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Cain", + "lastName": "Aguilar", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Powell", + "lastName": "Watts", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Mallory", + "lastName": "Mcfadden", + "company": "Parleynet", + "employed": false + }, + { + "firstName": "Harriet", + "lastName": "Larsen", + "company": "Fiberox", + "employed": true + }, + { + "firstName": "Tamika", + "lastName": "Vaughan", + "company": "Dyno", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Johnson", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Corinne", + "lastName": "Parrish", + "company": "Panzent", + "employed": false + }, + { + "firstName": "Rosario", + "lastName": "Nieves", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Riggs", + "company": "Unia", + "employed": false + }, + { + "firstName": "Graciela", + "lastName": "Tucker", + "company": "Entogrok", + "employed": false + }, + { + "firstName": "Ingram", + "lastName": "Hampton", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Lottie", + "lastName": "Rojas", + "company": "Sultrax", + "employed": true + }, + { + "firstName": "Mccormick", + "lastName": "Rivera", + "company": "Pathways", + "employed": true + }, + { + "firstName": "Bryant", + "lastName": "Mcleod", + "company": "Sunclipse", + "employed": false + }, + { + "firstName": "Nanette", + "lastName": "Gillespie", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Roseann", + "lastName": "Pacheco", + "company": "Cemention", + "employed": true + }, + { + "firstName": "Doreen", + "lastName": "Dejesus", + "company": "Kindaloo", + "employed": false + }, + { + "firstName": "Kim", + "lastName": "Sosa", + "company": "Multron", + "employed": false + }, + { + "firstName": "Rebekah", + "lastName": "Lang", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Chapman", + "lastName": "Leon", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Kirk", + "lastName": "Malone", + "company": "Capscreen", + "employed": false + }, + { + "firstName": "Goodwin", + "lastName": "Wheeler", + "company": "Senmei", + "employed": false + }, + { + "firstName": "Debora", + "lastName": "Tyler", + "company": "Danja", + "employed": false + }, + { + "firstName": "Jacklyn", + "lastName": "Burton", + "company": "Inrt", + "employed": true + }, + { + "firstName": "Tammie", + "lastName": "Shepard", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Jane", + "lastName": "Acevedo", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Augusta", + "lastName": "Curtis", + "company": "Decratex", + "employed": false + }, + { + "firstName": "Wendy", + "lastName": "Bauer", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Rice", + "lastName": "Benton", + "company": "Maroptic", + "employed": false + }, + { + "firstName": "England", + "lastName": "Hess", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Lenore", + "lastName": "Goodwin", + "company": "Kage", + "employed": true + }, + { + "firstName": "Duke", + "lastName": "Glover", + "company": "Centrexin", + "employed": true + }, + { + "firstName": "Vinson", + "lastName": "Bolton", + "company": "Yurture", + "employed": true + }, + { + "firstName": "Fowler", + "lastName": "Bright", + "company": "Geekwagon", + "employed": false + }, + { + "firstName": "Sweet", + "lastName": "Gay", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Ronda", + "lastName": "Hewitt", + "company": "Rodeology", + "employed": false + }, + { + "firstName": "Russell", + "lastName": "Day", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Elise", + "lastName": "Sampson", + "company": "Skinserve", + "employed": true + }, + { + "firstName": "Mollie", + "lastName": "Wilson", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Hallie", + "lastName": "Velazquez", + "company": "Phuel", + "employed": true + }, + { + "firstName": "Fitzpatrick", + "lastName": "Bruce", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Wooten", + "lastName": "Morse", + "company": "Geekol", + "employed": false + }, + { + "firstName": "Kari", + "lastName": "Maynard", + "company": "Zanilla", + "employed": true + }, + { + "firstName": "Shawn", + "lastName": "Frank", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Lorrie", + "lastName": "Workman", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Simpson", + "lastName": "Cruz", + "company": "Sulfax", + "employed": true + }, + { + "firstName": "Ewing", + "lastName": "Lawson", + "company": "Comcubine", + "employed": true + }, + { + "firstName": "Winnie", + "lastName": "Vang", + "company": "Zialactic", + "employed": false + }, + { + "firstName": "Cochran", + "lastName": "Spencer", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Tate", + "lastName": "Woodard", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Pollard", + "lastName": "Dillard", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Wilkins", + "lastName": "Reese", + "company": "Keeg", + "employed": true + }, + { + "firstName": "Burton", + "lastName": "Boyle", + "company": "Viasia", + "employed": true + }, + { + "firstName": "Misty", + "lastName": "Durham", + "company": "Cincyr", + "employed": true + }, + { + "firstName": "Juliette", + "lastName": "Slater", + "company": "Geekular", + "employed": true + }, + { + "firstName": "Randall", + "lastName": "Castro", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Daugherty", + "lastName": "Cochran", + "company": "Techtrix", + "employed": false + }, + { + "firstName": "Marguerite", + "lastName": "Spears", + "company": "Talae", + "employed": false + }, + { + "firstName": "Shelly", + "lastName": "Guy", + "company": "Exovent", + "employed": true + }, + { + "firstName": "Ward", + "lastName": "Barton", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Jerri", + "lastName": "Holden", + "company": "Satiance", + "employed": true + }, + { + "firstName": "Janell", + "lastName": "Oneal", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Rosalie", + "lastName": "Curry", + "company": "Ebidco", + "employed": true + }, + { + "firstName": "Aurora", + "lastName": "Nielsen", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Booker", + "lastName": "Cross", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Marva", + "lastName": "Grimes", + "company": "Combogen", + "employed": true + }, + { + "firstName": "Larsen", + "lastName": "Glass", + "company": "Applica", + "employed": false + }, + { + "firstName": "Kasey", + "lastName": "Kent", + "company": "Orbiflex", + "employed": false + }, + { + "firstName": "Katrina", + "lastName": "Kelly", + "company": "Boink", + "employed": true + }, + { + "firstName": "Howard", + "lastName": "Ashley", + "company": "Rubadub", + "employed": true + }, + { + "firstName": "Melody", + "lastName": "Shannon", + "company": "Maximind", + "employed": false + }, + { + "firstName": "Stein", + "lastName": "Mann", + "company": "Slumberia", + "employed": true + }, + { + "firstName": "Nicole", + "lastName": "Ellis", + "company": "Qot", + "employed": true + }, + { + "firstName": "Lela", + "lastName": "Peterson", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Ester", + "lastName": "Strong", + "company": "Eweville", + "employed": false + }, + { + "firstName": "Pearl", + "lastName": "Wooten", + "company": "Xsports", + "employed": true + }, + { + "firstName": "Adrienne", + "lastName": "Cantrell", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Lillian", + "lastName": "Jarvis", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Griffith", + "lastName": "Garrett", + "company": "Cowtown", + "employed": false + }, + { + "firstName": "Jocelyn", + "lastName": "Ramos", + "company": "Quailcom", + "employed": true + }, + { + "firstName": "Joanna", + "lastName": "Rhodes", + "company": "Grupoli", + "employed": true + }, + { + "firstName": "Joseph", + "lastName": "Hobbs", + "company": "Earthwax", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Hayes", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Lee", + "lastName": "Koch", + "company": "Ecraze", + "employed": true + }, + { + "firstName": "Pace", + "lastName": "Juarez", + "company": "Architax", + "employed": true + }, + { + "firstName": "Lott", + "lastName": "Blankenship", + "company": "Moreganic", + "employed": true + }, + { + "firstName": "Ann", + "lastName": "Wilkerson", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Dena", + "lastName": "Madden", + "company": "Qnekt", + "employed": false + }, + { + "firstName": "Larson", + "lastName": "Potts", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Roth", + "lastName": "Brady", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Ursula", + "lastName": "Conway", + "company": "Trollery", + "employed": true + }, + { + "firstName": "Liliana", + "lastName": "Johns", + "company": "Endicil", + "employed": false + }, + { + "firstName": "Walters", + "lastName": "Hurley", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Lucia", + "lastName": "Weeks", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Elena", + "lastName": "Patterson", + "company": "Cubix", + "employed": true + }, + { + "firstName": "Walsh", + "lastName": "Snyder", + "company": "Mantrix", + "employed": true + }, + { + "firstName": "Gaines", + "lastName": "Alston", + "company": "Poochies", + "employed": true + }, + { + "firstName": "Carole", + "lastName": "Blair", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Melendez", + "lastName": "Miles", + "company": "Irack", + "employed": true + }, + { + "firstName": "Hancock", + "lastName": "Russell", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Mclean", + "lastName": "Middleton", + "company": "Ultrimax", + "employed": false + }, + { + "firstName": "Sofia", + "lastName": "Harris", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Melissa", + "lastName": "Wright", + "company": "Kozgene", + "employed": false + }, + { + "firstName": "Castaneda", + "lastName": "Pena", + "company": "Exospeed", + "employed": false + }, + { + "firstName": "Stephanie", + "lastName": "Cantu", + "company": "Coriander", + "employed": false + }, + { + "firstName": "Kay", + "lastName": "Stewart", + "company": "Talendula", + "employed": false + }, + { + "firstName": "Cecile", + "lastName": "Rios", + "company": "Exiand", + "employed": false + }, + { + "firstName": "Marquita", + "lastName": "Page", + "company": "Spacewax", + "employed": false + }, + { + "firstName": "Cross", + "lastName": "Dudley", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Patrice", + "lastName": "Nichols", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Murray", + "lastName": "Buchanan", + "company": "Handshake", + "employed": true + }, + { + "firstName": "Silvia", + "lastName": "Hart", + "company": "Jumpstack", + "employed": true + }, + { + "firstName": "Lou", + "lastName": "Whitfield", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Kerry", + "lastName": "Floyd", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Estela", + "lastName": "Beach", + "company": "Rodemco", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Baird", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Gabrielle", + "lastName": "Hudson", + "company": "Comvey", + "employed": false + }, + { + "firstName": "Owen", + "lastName": "Mendoza", + "company": "Manufact", + "employed": false + }, + { + "firstName": "Moody", + "lastName": "Downs", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Corine", + "lastName": "Foley", + "company": "Portaline", + "employed": true + }, + { + "firstName": "Maynard", + "lastName": "Frederick", + "company": "Malathion", + "employed": true + }, + { + "firstName": "Bishop", + "lastName": "Marks", + "company": "Memora", + "employed": true + }, + { + "firstName": "Etta", + "lastName": "Solomon", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Reva", + "lastName": "Calderon", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Cornelia", + "lastName": "Stevens", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Marquez", + "lastName": "Witt", + "company": "Flum", + "employed": false + }, + { + "firstName": "Shelby", + "lastName": "Hill", + "company": "Ozean", + "employed": false + }, + { + "firstName": "Lacey", + "lastName": "Riddle", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Wilda", + "lastName": "Dickson", + "company": "Exoblue", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Soto", + "company": "Biflex", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Ewing", + "company": "Comstar", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "Ferguson", + "company": "Aquasure", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Greene", + "company": "Pearlesex", + "employed": false + }, + { + "firstName": "Blanca", + "lastName": "Frost", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Janie", + "lastName": "Briggs", + "company": "Pulze", + "employed": false + }, + { + "firstName": "Brooke", + "lastName": "Hebert", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Katheryn", + "lastName": "Hooper", + "company": "Endipin", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Hancock", + "company": "Portico", + "employed": true + }, + { + "firstName": "Gallagher", + "lastName": "Jennings", + "company": "Realysis", + "employed": false + }, + { + "firstName": "Townsend", + "lastName": "Estrada", + "company": "Futurize", + "employed": true + }, + { + "firstName": "Benson", + "lastName": "Bates", + "company": "Urbanshee", + "employed": false + }, + { + "firstName": "Mack", + "lastName": "Valdez", + "company": "Sequitur", + "employed": false + }, + { + "firstName": "Tamra", + "lastName": "Miranda", + "company": "Magneato", + "employed": false + }, + { + "firstName": "Paula", + "lastName": "Barber", + "company": "Firewax", + "employed": true + }, + { + "firstName": "Solis", + "lastName": "Gilliam", + "company": "Neptide", + "employed": false + }, + { + "firstName": "Evans", + "lastName": "Gamble", + "company": "Geekosis", + "employed": true + }, + { + "firstName": "Millie", + "lastName": "Mccoy", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Knight", + "lastName": "Baxter", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Sweeney", + "company": "Olucore", + "employed": true + }, + { + "firstName": "Judith", + "lastName": "Stephenson", + "company": "Neocent", + "employed": true + }, + { + "firstName": "Tracy", + "lastName": "Perry", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Sargent", + "lastName": "Wilcox", + "company": "Rocklogic", + "employed": true + }, + { + "firstName": "Victoria", + "lastName": "Preston", + "company": "Vixo", + "employed": true + }, + { + "firstName": "Diann", + "lastName": "Baker", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Stefanie", + "lastName": "Head", + "company": "Honotron", + "employed": true + }, + { + "firstName": "Christian", + "lastName": "Le", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Cummings", + "lastName": "Figueroa", + "company": "Portica", + "employed": false + }, + { + "firstName": "Guerrero", + "lastName": "Horton", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Hinton", + "lastName": "Webster", + "company": "Rugstars", + "employed": true + }, + { + "firstName": "Adrian", + "lastName": "Leblanc", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Alexander", + "lastName": "Hunt", + "company": "Liquicom", + "employed": false + }, + { + "firstName": "Pate", + "lastName": "Mcfarland", + "company": "Bitrex", + "employed": false + }, + { + "firstName": "Rogers", + "lastName": "Tate", + "company": "Daido", + "employed": true + }, + { + "firstName": "Tran", + "lastName": "Ford", + "company": "Pushcart", + "employed": false + }, + { + "firstName": "Claudine", + "lastName": "Salinas", + "company": "Permadyne", + "employed": true + }, + { + "firstName": "Rodgers", + "lastName": "Wagner", + "company": "Ontagene", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Rodriguez", + "company": "Glasstep", + "employed": false + }, + { + "firstName": "Monica", + "lastName": "Wilder", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Patsy", + "lastName": "Parsons", + "company": "Xumonk", + "employed": true + }, + { + "firstName": "Mann", + "lastName": "Lane", + "company": "Mobildata", + "employed": false + }, + { + "firstName": "Butler", + "lastName": "Kim", + "company": "Hairport", + "employed": true + }, + { + "firstName": "Stephens", + "lastName": "Small", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Luna", + "lastName": "Blake", + "company": "Comstruct", + "employed": true + }, + { + "firstName": "Wiggins", + "lastName": "Flores", + "company": "Intradisk", + "employed": false + }, + { + "firstName": "Carrillo", + "lastName": "Cook", + "company": "Puria", + "employed": false + }, + { + "firstName": "Weber", + "lastName": "Banks", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Shelley", + "lastName": "House", + "company": "Uneeq", + "employed": true + }, + { + "firstName": "Levine", + "lastName": "Huff", + "company": "Fuelworks", + "employed": false + }, + { + "firstName": "Cathleen", + "lastName": "Huber", + "company": "Accupharm", + "employed": false + }, + { + "firstName": "Delacruz", + "lastName": "Hurst", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Cecilia", + "lastName": "Snider", + "company": "Equitox", + "employed": false + }, + { + "firstName": "Tammi", + "lastName": "Guzman", + "company": "Barkarama", + "employed": false + }, + { + "firstName": "Petra", + "lastName": "Watkins", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Stanton", + "lastName": "Castillo", + "company": "Tropoli", + "employed": false + }, + { + "firstName": "Courtney", + "lastName": "Rowe", + "company": "Ginkle", + "employed": false + }, + { + "firstName": "Mayra", + "lastName": "Sutton", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Jodi", + "lastName": "Burke", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Neal", + "lastName": "Palmer", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Hensley", + "lastName": "Rosales", + "company": "Dogspa", + "employed": true + }, + { + "firstName": "Claudia", + "lastName": "Ferrell", + "company": "Combot", + "employed": true + }, + { + "firstName": "Marsh", + "lastName": "Delgado", + "company": "Frenex", + "employed": false + }, + { + "firstName": "Peck", + "lastName": "Dixon", + "company": "Hotcakes", + "employed": false + }, + { + "firstName": "Mcbride", + "lastName": "Morales", + "company": "Ovation", + "employed": true + }, + { + "firstName": "Underwood", + "lastName": "Rodriquez", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Jannie", + "lastName": "Salas", + "company": "Deviltoe", + "employed": true + }, + { + "firstName": "Esperanza", + "lastName": "Clayton", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Agnes", + "lastName": "Maldonado", + "company": "Digiprint", + "employed": false + }, + { + "firstName": "Ellen", + "lastName": "Oneill", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Soto", + "lastName": "Cotton", + "company": "Savvy", + "employed": false + }, + { + "firstName": "Craft", + "lastName": "Moss", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Benjamin", + "lastName": "Drake", + "company": "Joviold", + "employed": true + }, + { + "firstName": "Loretta", + "lastName": "Walker", + "company": "Unq", + "employed": false + }, + { + "firstName": "Deena", + "lastName": "Langley", + "company": "Verbus", + "employed": false + }, + { + "firstName": "Ida", + "lastName": "Odonnell", + "company": "Oulu", + "employed": false + }, + { + "firstName": "Rachelle", + "lastName": "Cain", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Slater", + "lastName": "Lindsay", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Bethany", + "lastName": "King", + "company": "Zillidium", + "employed": false + }, + { + "firstName": "Copeland", + "lastName": "Robles", + "company": "Pyrami", + "employed": false + }, + { + "firstName": "Taylor", + "lastName": "Solis", + "company": "Netbook", + "employed": true + }, + { + "firstName": "Myrtle", + "lastName": "Contreras", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Allison", + "lastName": "Dominguez", + "company": "Eternis", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Best", + "company": "Cytrak", + "employed": true + }, + { + "firstName": "Leon", + "lastName": "Swanson", + "company": "Isoplex", + "employed": true + }, + { + "firstName": "Potter", + "lastName": "Terry", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Nash", + "lastName": "Alvarado", + "company": "Ginkogene", + "employed": true + }, + { + "firstName": "Beard", + "lastName": "Alexander", + "company": "Quordate", + "employed": true + }, + { + "firstName": "Katherine", + "lastName": "Barlow", + "company": "Delphide", + "employed": false + }, + { + "firstName": "Zelma", + "lastName": "Nguyen", + "company": "Shadease", + "employed": true + }, + { + "firstName": "Josefa", + "lastName": "Mckinney", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Rutledge", + "lastName": "Chandler", + "company": "Hawkster", + "employed": true + }, + { + "firstName": "Abbott", + "lastName": "Fletcher", + "company": "Zillanet", + "employed": true + }, + { + "firstName": "Fox", + "lastName": "Duncan", + "company": "Comtest", + "employed": false + }, + { + "firstName": "Gloria", + "lastName": "Travis", + "company": "Norali", + "employed": true + }, + { + "firstName": "Crystal", + "lastName": "Mullins", + "company": "Velity", + "employed": true + }, + { + "firstName": "Reba", + "lastName": "Lowe", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Susie", + "lastName": "Cote", + "company": "Visualix", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Weaver", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "Bridges", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Wilkinson", + "lastName": "Hull", + "company": "Protodyne", + "employed": true + }, + { + "firstName": "Acosta", + "lastName": "Norman", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Carly", + "lastName": "Hopper", + "company": "Uberlux", + "employed": false + }, + { + "firstName": "Patti", + "lastName": "Patton", + "company": "Virva", + "employed": false + }, + { + "firstName": "Susanna", + "lastName": "Morris", + "company": "Zedalis", + "employed": true + }, + { + "firstName": "Bertha", + "lastName": "Lloyd", + "company": "Goko", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Smith", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Hendricks", + "lastName": "Meadows", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Carolyn", + "lastName": "Daniel", + "company": "Cinesanct", + "employed": true + }, + { + "firstName": "Michele", + "lastName": "Singleton", + "company": "Nimon", + "employed": true + }, + { + "firstName": "Flossie", + "lastName": "Barrett", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Jewel", + "lastName": "Graham", + "company": "Xth", + "employed": true + }, + { + "firstName": "Crane", + "lastName": "Bennett", + "company": "Cytrek", + "employed": false + }, + { + "firstName": "Snow", + "lastName": "Duran", + "company": "Centice", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Rosa", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Tessa", + "lastName": "Thornton", + "company": "Xoggle", + "employed": false + }, + { + "firstName": "Tabitha", + "lastName": "Yates", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Malinda", + "lastName": "Hodges", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Skinner", + "lastName": "Mckee", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Mullen", + "lastName": "Ross", + "company": "Billmed", + "employed": true + }, + { + "firstName": "Leola", + "lastName": "Ochoa", + "company": "Kinetica", + "employed": false + }, + { + "firstName": "Bolton", + "lastName": "Jones", + "company": "Endipine", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Whitley", + "company": "Photobin", + "employed": true + }, + { + "firstName": "Flora", + "lastName": "Mays", + "company": "Paragonia", + "employed": false + }, + { + "firstName": "Brittney", + "lastName": "Church", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Adeline", + "lastName": "Hunter", + "company": "Amtap", + "employed": true + }, + { + "firstName": "Bradshaw", + "lastName": "Lester", + "company": "Klugger", + "employed": true + }, + { + "firstName": "Lewis", + "lastName": "Owen", + "company": "Digitalus", + "employed": true + }, + { + "firstName": "Kim", + "lastName": "Schneider", + "company": "Kineticut", + "employed": true + }, + { + "firstName": "Jenna", + "lastName": "Casey", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Margery", + "lastName": "Burris", + "company": "Idetica", + "employed": false + }, + { + "firstName": "Tracey", + "lastName": "Morgan", + "company": "Softmicro", + "employed": true + }, + { + "firstName": "Booth", + "lastName": "Griffin", + "company": "Teraprene", + "employed": false + }, + { + "firstName": "Phoebe", + "lastName": "Crosby", + "company": "Isbol", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Reed", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Elizabeth", + "lastName": "Murray", + "company": "Bunga", + "employed": true + }, + { + "firstName": "Dana", + "lastName": "Santana", + "company": "Isopop", + "employed": true + }, + { + "firstName": "Ingrid", + "lastName": "Reeves", + "company": "Callflex", + "employed": true + }, + { + "firstName": "Edwards", + "lastName": "Townsend", + "company": "Farmage", + "employed": true + }, + { + "firstName": "Montoya", + "lastName": "Jenkins", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Susanne", + "lastName": "Vance", + "company": "Codax", + "employed": true + }, + { + "firstName": "Pickett", + "lastName": "Mckenzie", + "company": "Zilla", + "employed": true + }, + { + "firstName": "Leigh", + "lastName": "Ball", + "company": "Quarmony", + "employed": false + }, + { + "firstName": "Gladys", + "lastName": "Herman", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Elsie", + "lastName": "Delaney", + "company": "Organica", + "employed": false + }, + { + "firstName": "Deana", + "lastName": "Burgess", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Claire", + "lastName": "Dorsey", + "company": "Applideck", + "employed": false + }, + { + "firstName": "Kimberly", + "lastName": "Chan", + "company": "Kraggle", + "employed": false + }, + { + "firstName": "Albert", + "lastName": "Cooper", + "company": "Imkan", + "employed": false + }, + { + "firstName": "Nadia", + "lastName": "Dale", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Sarah", + "lastName": "Montoya", + "company": "Icology", + "employed": false + }, + { + "firstName": "Tamera", + "lastName": "Phillips", + "company": "Vetron", + "employed": false + }, + { + "firstName": "Osborn", + "lastName": "Cooley", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Ingram", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Erna", + "lastName": "Mcintyre", + "company": "Singavera", + "employed": true + }, + { + "firstName": "Quinn", + "lastName": "Murphy", + "company": "Overfork", + "employed": false + }, + { + "firstName": "Ramona", + "lastName": "Brock", + "company": "Medesign", + "employed": false + }, + { + "firstName": "Schneider", + "lastName": "Gomez", + "company": "Exoplode", + "employed": false + }, + { + "firstName": "Darlene", + "lastName": "Rocha", + "company": "Concility", + "employed": true + }, + { + "firstName": "Maryann", + "lastName": "Lopez", + "company": "Accidency", + "employed": true + }, + { + "firstName": "Clarissa", + "lastName": "Wall", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Dolores", + "lastName": "Boyd", + "company": "Helixo", + "employed": false + }, + { + "firstName": "Margarita", + "lastName": "Newton", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Alvarez", + "lastName": "Sawyer", + "company": "Freakin", + "employed": true + }, + { + "firstName": "Lena", + "lastName": "Gray", + "company": "Gynk", + "employed": false + }, + { + "firstName": "Pugh", + "lastName": "Henderson", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Carrie", + "lastName": "Griffith", + "company": "Prowaste", + "employed": true + }, + { + "firstName": "Frye", + "lastName": "Nolan", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Hebert", + "lastName": "Henson", + "company": "Xerex", + "employed": true + }, + { + "firstName": "Cardenas", + "lastName": "Melendez", + "company": "Duflex", + "employed": false + }, + { + "firstName": "Aileen", + "lastName": "Stanton", + "company": "Mitroc", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Adams", + "company": "Emoltra", + "employed": false + }, + { + "firstName": "Waters", + "lastName": "Woods", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Rivas", + "lastName": "Harvey", + "company": "Zentime", + "employed": true + }, + { + "firstName": "Cara", + "lastName": "Mcdaniel", + "company": "Frolix", + "employed": true + }, + { + "firstName": "Ortega", + "lastName": "Zimmerman", + "company": "Medalert", + "employed": false + }, + { + "firstName": "Kaufman", + "lastName": "Bowman", + "company": "Miraclis", + "employed": true + }, + { + "firstName": "Burns", + "lastName": "Beard", + "company": "Strozen", + "employed": false + }, + { + "firstName": "Ila", + "lastName": "Reid", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Allison", + "lastName": "Gonzalez", + "company": "Gonkle", + "employed": true + }, + { + "firstName": "Pacheco", + "lastName": "Talley", + "company": "Hopeli", + "employed": false + }, + { + "firstName": "Roxanne", + "lastName": "Price", + "company": "Baluba", + "employed": true + }, + { + "firstName": "Harris", + "lastName": "York", + "company": "Buzzness", + "employed": true + }, + { + "firstName": "Santana", + "lastName": "Gonzales", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Lindsey", + "lastName": "Crane", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Rosa", + "lastName": "Camacho", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Carney", + "lastName": "Castaneda", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Faulkner", + "lastName": "Whitaker", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Susan", + "lastName": "Baldwin", + "company": "Zilodyne", + "employed": true + }, + { + "firstName": "Gutierrez", + "lastName": "Noble", + "company": "Roboid", + "employed": false + }, + { + "firstName": "Lowe", + "lastName": "Fuentes", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Pena", + "lastName": "Blackwell", + "company": "Earthpure", + "employed": true + }, + { + "firstName": "Mcmahon", + "lastName": "Sanford", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Suzanne", + "lastName": "Francis", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Melba", + "lastName": "Walton", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Black", + "lastName": "Clarke", + "company": "Futuris", + "employed": false + }, + { + "firstName": "Ware", + "lastName": "Hardin", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Winters", + "lastName": "Fitzgerald", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Mills", + "lastName": "Bray", + "company": "Skyplex", + "employed": false + }, + { + "firstName": "Betsy", + "lastName": "Willis", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Eva", + "lastName": "Torres", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Kerr", + "lastName": "Hyde", + "company": "Radiantix", + "employed": true + }, + { + "firstName": "Spencer", + "lastName": "Jacobson", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Frank", + "lastName": "Mckay", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Angel", + "lastName": "Haynes", + "company": "Ovium", + "employed": false + }, + { + "firstName": "Johnnie", + "lastName": "Bailey", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Holland", + "company": "Flyboyz", + "employed": false + }, + { + "firstName": "Lauren", + "lastName": "Coleman", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Little", + "lastName": "Kemp", + "company": "Voipa", + "employed": true + }, + { + "firstName": "Ofelia", + "lastName": "Hamilton", + "company": "Musanpoly", + "employed": true + }, + { + "firstName": "Irma", + "lastName": "Larson", + "company": "Eargo", + "employed": true + }, + { + "firstName": "Avery", + "lastName": "Richard", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Ina", + "lastName": "Mcgee", + "company": "Talkalot", + "employed": false + }, + { + "firstName": "Angelique", + "lastName": "Mccarty", + "company": "Zoxy", + "employed": true + }, + { + "firstName": "Valentine", + "lastName": "Harrington", + "company": "Limage", + "employed": false + }, + { + "firstName": "Herring", + "lastName": "Mcdowell", + "company": "Squish", + "employed": true + }, + { + "firstName": "Hubbard", + "lastName": "Booth", + "company": "Egypto", + "employed": true + }, + { + "firstName": "Torres", + "lastName": "Kennedy", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Alexandra", + "lastName": "Richardson", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Spence", + "lastName": "Macdonald", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Kaye", + "lastName": "Hardy", + "company": "Zillar", + "employed": false + }, + { + "firstName": "Barbra", + "lastName": "Summers", + "company": "Cuizine", + "employed": false + }, + { + "firstName": "Sexton", + "lastName": "Carroll", + "company": "Koogle", + "employed": false + }, + { + "firstName": "Herrera", + "lastName": "Humphrey", + "company": "Omnigog", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Galloway", + "company": "Eclipsent", + "employed": true + }, + { + "firstName": "Casandra", + "lastName": "Myers", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Gwendolyn", + "lastName": "Haney", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Graves", + "lastName": "Zamora", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Chelsea", + "lastName": "Mccarthy", + "company": "Cosmosis", + "employed": true + }, + { + "firstName": "Chandra", + "lastName": "Chavez", + "company": "Centree", + "employed": false + }, + { + "firstName": "Britney", + "lastName": "Vaughn", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Valenzuela", + "lastName": "Haley", + "company": "Vitricomp", + "employed": false + }, + { + "firstName": "Felecia", + "lastName": "Christensen", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Rowe", + "lastName": "Knight", + "company": "Comfirm", + "employed": true + }, + { + "firstName": "Karen", + "lastName": "Hanson", + "company": "Locazone", + "employed": false + }, + { + "firstName": "Earline", + "lastName": "Sheppard", + "company": "Hatology", + "employed": true + }, + { + "firstName": "Claudette", + "lastName": "Shields", + "company": "Genesynk", + "employed": true + }, + { + "firstName": "Dixie", + "lastName": "Coffey", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Christi", + "lastName": "Butler", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Bobbie", + "lastName": "Wolfe", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Malone", + "lastName": "Henry", + "company": "Terrago", + "employed": false + }, + { + "firstName": "Garza", + "lastName": "Rosario", + "company": "Circum", + "employed": false + }, + { + "firstName": "Reyes", + "lastName": "Rogers", + "company": "Zenolux", + "employed": false + }, + { + "firstName": "Jasmine", + "lastName": "Mcpherson", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Gail", + "lastName": "Sears", + "company": "Viagreat", + "employed": true + }, + { + "firstName": "Arlene", + "lastName": "Gaines", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Jerry", + "lastName": "Parks", + "company": "Comtrek", + "employed": false + }, + { + "firstName": "Rowena", + "lastName": "Crawford", + "company": "Columella", + "employed": false + }, + { + "firstName": "Kate", + "lastName": "Pate", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Katina", + "lastName": "Fox", + "company": "Uplinx", + "employed": false + }, + { + "firstName": "Nell", + "lastName": "Lott", + "company": "Gynko", + "employed": true + }, + { + "firstName": "Kelsey", + "lastName": "Clark", + "company": "Zentility", + "employed": true + }, + { + "firstName": "Ashlee", + "lastName": "Vinson", + "company": "Pyramax", + "employed": false + }, + { + "firstName": "Palmer", + "lastName": "Santiago", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Lolita", + "lastName": "Browning", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Delaney", + "lastName": "Roach", + "company": "Tingles", + "employed": false + }, + { + "firstName": "Alexandria", + "lastName": "Fulton", + "company": "Bisba", + "employed": false + }, + { + "firstName": "Shaffer", + "lastName": "Maxwell", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Meredith", + "lastName": "Stark", + "company": "Cyclonica", + "employed": false + }, + { + "firstName": "Ruthie", + "lastName": "Barker", + "company": "Quinex", + "employed": false + }, + { + "firstName": "Muriel", + "lastName": "Joseph", + "company": "Assitia", + "employed": true + }, + { + "firstName": "Mattie", + "lastName": "Welch", + "company": "Securia", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Mercado", + "company": "Comtext", + "employed": true + }, + { + "firstName": "Cantu", + "lastName": "Marquez", + "company": "Glukgluk", + "employed": false + }, + { + "firstName": "Macdonald", + "lastName": "Farmer", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Arline", + "lastName": "Scott", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Winifred", + "lastName": "West", + "company": "Lovepad", + "employed": true + }, + { + "firstName": "Hays", + "lastName": "Dennis", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Tommie", + "lastName": "Hughes", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Carey", + "lastName": "Sanders", + "company": "Intergeek", + "employed": true + }, + { + "firstName": "Marjorie", + "lastName": "Quinn", + "company": "Zolarex", + "employed": true + }, + { + "firstName": "Meghan", + "lastName": "Glenn", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Tracie", + "lastName": "Fischer", + "company": "Digirang", + "employed": false + }, + { + "firstName": "Helga", + "lastName": "Hoffman", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Fischer", + "lastName": "Harmon", + "company": "Zolavo", + "employed": true + }, + { + "firstName": "Ava", + "lastName": "Burt", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Cassandra", + "lastName": "Stephens", + "company": "Uni", + "employed": false + }, + { + "firstName": "Isabel", + "lastName": "Nelson", + "company": "Orbalix", + "employed": true + }, + { + "firstName": "Natasha", + "lastName": "Daniels", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Adams", + "lastName": "Garner", + "company": "Limozen", + "employed": false + }, + { + "firstName": "Hayes", + "lastName": "Roman", + "company": "Valreda", + "employed": true + }, + { + "firstName": "Inez", + "lastName": "Cleveland", + "company": "Acruex", + "employed": false + }, + { + "firstName": "Salinas", + "lastName": "Brooks", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Mercado", + "lastName": "Jefferson", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Sellers", + "lastName": "Harper", + "company": "Coash", + "employed": true + }, + { + "firstName": "Helen", + "lastName": "Decker", + "company": "Waab", + "employed": false + }, + { + "firstName": "Ana", + "lastName": "Savage", + "company": "Venoflex", + "employed": false + }, + { + "firstName": "Chan", + "lastName": "Cunningham", + "company": "Spherix", + "employed": true + }, + { + "firstName": "Francis", + "lastName": "Berger", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Boone", + "lastName": "Collier", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Hopkins", + "lastName": "Martin", + "company": "Tropolis", + "employed": true + }, + { + "firstName": "Reid", + "lastName": "Garza", + "company": "Songlines", + "employed": false + }, + { + "firstName": "Lois", + "lastName": "Clements", + "company": "Austech", + "employed": true + }, + { + "firstName": "Allen", + "lastName": "Franks", + "company": "Zytrax", + "employed": true + }, + { + "firstName": "Brock", + "lastName": "Pennington", + "company": "Entality", + "employed": false + }, + { + "firstName": "Nielsen", + "lastName": "Perez", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Rowland", + "lastName": "Gilbert", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Opal", + "lastName": "Thomas", + "company": "Assistia", + "employed": false + }, + { + "firstName": "Maddox", + "lastName": "Bartlett", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Tillman", + "lastName": "Cameron", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Gena", + "lastName": "Booker", + "company": "Amtas", + "employed": true + }, + { + "firstName": "Jeannette", + "lastName": "Ballard", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Elvira", + "lastName": "Dotson", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Robyn", + "lastName": "Calhoun", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Rocha", + "lastName": "Moon", + "company": "Providco", + "employed": true + }, + { + "firstName": "Lakisha", + "lastName": "Freeman", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Singleton", + "lastName": "Massey", + "company": "Amril", + "employed": true + }, + { + "firstName": "Maureen", + "lastName": "Newman", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Lawanda", + "lastName": "Mcintosh", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Alyson", + "lastName": "Prince", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Yvonne", + "lastName": "Garrison", + "company": "Geekfarm", + "employed": true + }, + { + "firstName": "Gwen", + "lastName": "Bullock", + "company": "Isodrive", + "employed": true + }, + { + "firstName": "Beasley", + "lastName": "Spence", + "company": "Genmom", + "employed": false + }, + { + "firstName": "Dianne", + "lastName": "Acosta", + "company": "Genmy", + "employed": true + }, + { + "firstName": "Ramos", + "lastName": "Rutledge", + "company": "Bitendrex", + "employed": false + }, + { + "firstName": "Strickland", + "lastName": "Grant", + "company": "Calcula", + "employed": false + }, + { + "firstName": "Hoffman", + "lastName": "Valentine", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Stout", + "company": "Quilk", + "employed": false + }, + { + "firstName": "Davidson", + "lastName": "Hatfield", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Harvey", + "lastName": "Mcguire", + "company": "Nutralab", + "employed": false + }, + { + "firstName": "Velasquez", + "lastName": "Finley", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Leona", + "lastName": "Allison", + "company": "Applidec", + "employed": true + }, + { + "firstName": "Cathy", + "lastName": "Mathews", + "company": "Zerology", + "employed": true + }, + { + "firstName": "Estrada", + "lastName": "Sargent", + "company": "Aquasseur", + "employed": true + }, + { + "firstName": "Powers", + "lastName": "Caldwell", + "company": "Daisu", + "employed": false + }, + { + "firstName": "Sonja", + "lastName": "England", + "company": "Nipaz", + "employed": true + }, + { + "firstName": "Benita", + "lastName": "Berg", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Madeline", + "lastName": "Flowers", + "company": "Isologix", + "employed": true + }, + { + "firstName": "Angelica", + "lastName": "Jordan", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Pope", + "lastName": "Bell", + "company": "Marqet", + "employed": false + }, + { + "firstName": "Banks", + "lastName": "Hester", + "company": "Fuelton", + "employed": true + }, + { + "firstName": "Vazquez", + "lastName": "Craft", + "company": "Ultrasure", + "employed": true + }, + { + "firstName": "Alison", + "lastName": "Lindsey", + "company": "Parcoe", + "employed": false + }, + { + "firstName": "Carissa", + "lastName": "Bonner", + "company": "Proxsoft", + "employed": true + }, + { + "firstName": "Letitia", + "lastName": "Espinoza", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Walls", + "lastName": "Roberts", + "company": "Acusage", + "employed": true + }, + { + "firstName": "Cervantes", + "lastName": "Rush", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Clements", + "lastName": "Key", + "company": "Emtrac", + "employed": true + }, + { + "firstName": "Brenda", + "lastName": "Diaz", + "company": "Zerbina", + "employed": false + }, + { + "firstName": "Robles", + "lastName": "Carter", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Julianne", + "lastName": "Montgomery", + "company": "Fitcore", + "employed": false + }, + { + "firstName": "Rios", + "lastName": "Ryan", + "company": "Pharmacon", + "employed": true + }, + { + "firstName": "Maryellen", + "lastName": "Arnold", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Fletcher", + "lastName": "Roy", + "company": "Centuria", + "employed": false + }, + { + "firstName": "Weeks", + "lastName": "Munoz", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Dionne", + "lastName": "Lawrence", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Fuentes", + "lastName": "Kirk", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Jessie", + "lastName": "Simon", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Jillian", + "lastName": "Bass", + "company": "Ziggles", + "employed": false + }, + { + "firstName": "Arnold", + "lastName": "Robinson", + "company": "Zolarity", + "employed": true + }, + { + "firstName": "Elma", + "lastName": "Hinton", + "company": "Datacator", + "employed": true + }, + { + "firstName": "Catalina", + "lastName": "Franco", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Vaughn", + "lastName": "Wise", + "company": "Artiq", + "employed": true + }, + { + "firstName": "Mckee", + "lastName": "Cummings", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Donaldson", + "company": "Essensia", + "employed": true + }, + { + "firstName": "Evelyn", + "lastName": "Little", + "company": "Zepitope", + "employed": true + }, + { + "firstName": "Salas", + "lastName": "Roberson", + "company": "Signity", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Pratt", + "company": "Frosnex", + "employed": true + }, + { + "firstName": "Jensen", + "lastName": "Pierce", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Britt", + "lastName": "Ward", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Benton", + "lastName": "Estes", + "company": "Suremax", + "employed": false + }, + { + "firstName": "Kristy", + "lastName": "Logan", + "company": "Andryx", + "employed": true + }, + { + "firstName": "Mcdaniel", + "lastName": "Webb", + "company": "Viocular", + "employed": true + }, + { + "firstName": "Sylvia", + "lastName": "Erickson", + "company": "Marketoid", + "employed": false + }, + { + "firstName": "Barry", + "lastName": "Neal", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Dominguez", + "lastName": "Randall", + "company": "Rameon", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Cardenas", + "company": "Snacktion", + "employed": false + }, + { + "firstName": "Sadie", + "lastName": "Mccall", + "company": "Quizka", + "employed": true + }, + { + "firstName": "Betty", + "lastName": "Cabrera", + "company": "Zentry", + "employed": false + }, + { + "firstName": "Fern", + "lastName": "May", + "company": "Myopium", + "employed": false + }, + { + "firstName": "Dawson", + "lastName": "Mitchell", + "company": "Obliq", + "employed": true + }, + { + "firstName": "Therese", + "lastName": "Burnett", + "company": "Ramjob", + "employed": false + }, + { + "firstName": "Lidia", + "lastName": "Foreman", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Ferrell", + "lastName": "Bender", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Lisa", + "lastName": "Cline", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Howe", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Marylou", + "lastName": "Washington", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Mayer", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Odonnell", + "lastName": "Gross", + "company": "Gology", + "employed": false + }, + { + "firstName": "Morales", + "lastName": "Poole", + "company": "Nspire", + "employed": true + }, + { + "firstName": "Baker", + "lastName": "Barry", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Mclaughlin", + "lastName": "Bradford", + "company": "Velos", + "employed": true + }, + { + "firstName": "Ericka", + "lastName": "Barrera", + "company": "Stockpost", + "employed": true + }, + { + "firstName": "Dejesus", + "lastName": "Watson", + "company": "Nexgene", + "employed": true + }, + { + "firstName": "Brianna", + "lastName": "Wallace", + "company": "Evidends", + "employed": true + }, + { + "firstName": "Hogan", + "lastName": "Dawson", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Delgado", + "lastName": "Mason", + "company": "Schoolio", + "employed": false + }, + { + "firstName": "Evangelina", + "lastName": "Norris", + "company": "Remotion", + "employed": true + }, + { + "firstName": "Clara", + "lastName": "Heath", + "company": "Retrack", + "employed": false + }, + { + "firstName": "Corina", + "lastName": "Buckley", + "company": "Confrenzy", + "employed": true + }, + { + "firstName": "Mercer", + "lastName": "Stanley", + "company": "Kyagoro", + "employed": true + }, + { + "firstName": "Daphne", + "lastName": "Simmons", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Ginger", + "lastName": "Bird", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Nettie", + "lastName": "Conley", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Yvette", + "lastName": "Gilmore", + "company": "Golistic", + "employed": true + }, + { + "firstName": "Bridgett", + "lastName": "Jacobs", + "company": "Brainquil", + "employed": true + }, + { + "firstName": "Stacey", + "lastName": "Bond", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Mathis", + "lastName": "Fuller", + "company": "Perkle", + "employed": false + }, + { + "firstName": "Kristen", + "lastName": "Gardner", + "company": "Luxuria", + "employed": false + }, + { + "firstName": "Jodie", + "lastName": "Short", + "company": "Anivet", + "employed": false + }, + { + "firstName": "Norman", + "lastName": "Hays", + "company": "Envire", + "employed": false + }, + { + "firstName": "Willie", + "lastName": "Stein", + "company": "Rooforia", + "employed": false + }, + { + "firstName": "Goldie", + "lastName": "Underwood", + "company": "Twiist", + "employed": false + }, + { + "firstName": "Kidd", + "lastName": "Cohen", + "company": "Euron", + "employed": false + }, + { + "firstName": "Anita", + "lastName": "Skinner", + "company": "Fleetmix", + "employed": false + }, + { + "firstName": "Abigail", + "lastName": "Mooney", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Leonard", + "lastName": "Stuart", + "company": "Earthplex", + "employed": false + }, + { + "firstName": "Bernadette", + "lastName": "Orr", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Jordan", + "lastName": "Pittman", + "company": "Macronaut", + "employed": false + }, + { + "firstName": "Harrington", + "lastName": "Patrick", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Perry", + "lastName": "Waters", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Mia", + "lastName": "Gibson", + "company": "Injoy", + "employed": true + }, + { + "firstName": "Tanner", + "lastName": "Pruitt", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Chrystal", + "lastName": "Williamson", + "company": "Furnitech", + "employed": true + }, + { + "firstName": "Dorthy", + "lastName": "Sellers", + "company": "Peticular", + "employed": true + }, + { + "firstName": "Dianna", + "lastName": "Beasley", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Lang", + "lastName": "Eaton", + "company": "Inear", + "employed": true + }, + { + "firstName": "Georgette", + "lastName": "Merrill", + "company": "Corpulse", + "employed": true + }, + { + "firstName": "Walker", + "lastName": "Manning", + "company": "Rodeomad", + "employed": true + }, + { + "firstName": "Glenda", + "lastName": "Hall", + "company": "Translink", + "employed": false + }, + { + "firstName": "Billie", + "lastName": "Gallegos", + "company": "Vendblend", + "employed": false + }, + { + "firstName": "Roberta", + "lastName": "Brown", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Tisha", + "lastName": "Davis", + "company": "Pivitol", + "employed": false + }, + { + "firstName": "Dolly", + "lastName": "Wynn", + "company": "Zensus", + "employed": true + }, + { + "firstName": "Stewart", + "lastName": "Noel", + "company": "Zidox", + "employed": true + }, + { + "firstName": "Castillo", + "lastName": "Green", + "company": "Petigems", + "employed": true + }, + { + "firstName": "Day", + "lastName": "Sparks", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Foley", + "lastName": "Avery", + "company": "Sentia", + "employed": false + }, + { + "firstName": "Doyle", + "lastName": "Landry", + "company": "Corecom", + "employed": false + }, + { + "firstName": "Martinez", + "lastName": "William", + "company": "Comveyer", + "employed": false + }, + { + "firstName": "Jan", + "lastName": "Burns", + "company": "Zillatide", + "employed": true + }, + { + "firstName": "Julie", + "lastName": "Higgins", + "company": "Elita", + "employed": true + }, + { + "firstName": "Leslie", + "lastName": "Knapp", + "company": "Affluex", + "employed": false + }, + { + "firstName": "Dorothea", + "lastName": "Andrews", + "company": "Interfind", + "employed": true + }, + { + "firstName": "Wanda", + "lastName": "Becker", + "company": "Emergent", + "employed": true + }, + { + "firstName": "Marlene", + "lastName": "Christian", + "company": "Acium", + "employed": true + }, + { + "firstName": "Logan", + "lastName": "Hendricks", + "company": "Bedder", + "employed": true + }, + { + "firstName": "Gretchen", + "lastName": "Owens", + "company": "Insource", + "employed": true + }, + { + "firstName": "Priscilla", + "lastName": "Conrad", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Dora", + "lastName": "Silva", + "company": "Digifad", + "employed": true + }, + { + "firstName": "Solomon", + "lastName": "Hoover", + "company": "Colaire", + "employed": false + }, + { + "firstName": "Eloise", + "lastName": "Barr", + "company": "Gink", + "employed": true + }, + { + "firstName": "Imelda", + "lastName": "Nash", + "company": "Digial", + "employed": true + }, + { + "firstName": "Blair", + "lastName": "Whitehead", + "company": "Pasturia", + "employed": true + }, + { + "firstName": "King", + "lastName": "Bradley", + "company": "Insurety", + "employed": false + }, + { + "firstName": "Langley", + "lastName": "Holder", + "company": "Zillactic", + "employed": true + }, + { + "firstName": "Sampson", + "lastName": "Shepherd", + "company": "Greeker", + "employed": false + }, + { + "firstName": "Juliana", + "lastName": "Ellison", + "company": "Quonk", + "employed": false + }, + { + "firstName": "Marina", + "lastName": "Russo", + "company": "Twiggery", + "employed": true + }, + { + "firstName": "Robinson", + "lastName": "Mclean", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Wilcox", + "lastName": "Bradshaw", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Sharron", + "lastName": "Knox", + "company": "Updat", + "employed": false + }, + { + "firstName": "Shelia", + "lastName": "Waller", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Hyde", + "lastName": "Livingston", + "company": "Sultraxin", + "employed": true + }, + { + "firstName": "Savage", + "lastName": "Carney", + "company": "Zipak", + "employed": false + }, + { + "firstName": "Lina", + "lastName": "Emerson", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Gracie", + "lastName": "Dunn", + "company": "Octocore", + "employed": false + }, + { + "firstName": "Bullock", + "lastName": "Tillman", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Juarez", + "lastName": "Barnett", + "company": "Qualitex", + "employed": true + }, + { + "firstName": "Lynnette", + "lastName": "Hicks", + "company": "Otherway", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Shaw", + "company": "Naxdis", + "employed": false + }, + { + "firstName": "Gentry", + "lastName": "Battle", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Frost", + "lastName": "Pearson", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Meagan", + "lastName": "Olson", + "company": "Dadabase", + "employed": true + }, + { + "firstName": "Maxwell", + "lastName": "Chapman", + "company": "Blurrybus", + "employed": false + }, + { + "firstName": "Ilene", + "lastName": "Edwards", + "company": "Quadeebo", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Woodward", + "company": "Zorromop", + "employed": false + }, + { + "firstName": "Trevino", + "lastName": "Mcneil", + "company": "Imant", + "employed": true + }, + { + "firstName": "Latonya", + "lastName": "Todd", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Hillary", + "lastName": "Ray", + "company": "Zaya", + "employed": false + }, + { + "firstName": "Dorsey", + "lastName": "Petersen", + "company": "Lunchpod", + "employed": false + }, + { + "firstName": "Melva", + "lastName": "Abbott", + "company": "Nitracyr", + "employed": false + }, + { + "firstName": "Gallegos", + "lastName": "Hammond", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Mckenzie", + "lastName": "Powell", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Sykes", + "lastName": "Tanner", + "company": "Aquoavo", + "employed": false + }, + { + "firstName": "Nicholson", + "lastName": "Mccullough", + "company": "Cedward", + "employed": false + }, + { + "firstName": "Maribel", + "lastName": "Greer", + "company": "Comverges", + "employed": false + }, + { + "firstName": "Woods", + "lastName": "Cannon", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Austin", + "lastName": "Keith", + "company": "Norsup", + "employed": true + }, + { + "firstName": "Heidi", + "lastName": "Saunders", + "company": "Oatfarm", + "employed": false + }, + { + "firstName": "Elliott", + "lastName": "Charles", + "company": "Tsunamia", + "employed": false + }, + { + "firstName": "Howell", + "lastName": "Harding", + "company": "Ceprene", + "employed": false + }, + { + "firstName": "Calderon", + "lastName": "Marsh", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Melinda", + "lastName": "Mcmillan", + "company": "Isotronic", + "employed": false + }, + { + "firstName": "Richardson", + "lastName": "Chen", + "company": "Automon", + "employed": true + }, + { + "firstName": "Stuart", + "lastName": "Moses", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Bowers", + "lastName": "Rose", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Moses", + "lastName": "Howell", + "company": "Interloo", + "employed": false + }, + { + "firstName": "Mooney", + "lastName": "Burks", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Gordon", + "lastName": "Avila", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Fitzgerald", + "lastName": "Garcia", + "company": "Dentrex", + "employed": true + }, + { + "firstName": "Beth", + "lastName": "Burch", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Leann", + "lastName": "Salazar", + "company": "Dogtown", + "employed": false + }, + { + "firstName": "Lilian", + "lastName": "Clay", + "company": "Xinware", + "employed": true + }, + { + "firstName": "Maritza", + "lastName": "Austin", + "company": "Boilicon", + "employed": true + }, + { + "firstName": "Owens", + "lastName": "Duke", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Mosley", + "lastName": "Sullivan", + "company": "Extro", + "employed": true + }, + { + "firstName": "Connie", + "lastName": "Collins", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Krista", + "lastName": "Evans", + "company": "Austex", + "employed": false + }, + { + "firstName": "Nina", + "lastName": "Obrien", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Guzman", + "lastName": "Chaney", + "company": "Brainclip", + "employed": false + }, + { + "firstName": "Sara", + "lastName": "Kerr", + "company": "Apexia", + "employed": false + }, + { + "firstName": "Mcintosh", + "lastName": "Horne", + "company": "Exodoc", + "employed": true + }, + { + "firstName": "Latasha", + "lastName": "Pace", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Best", + "lastName": "Robertson", + "company": "Sustenza", + "employed": true + }, + { + "firstName": "Hopper", + "lastName": "Petty", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Christensen", + "lastName": "Strickland", + "company": "Zappix", + "employed": true + }, + { + "firstName": "Barnett", + "lastName": "Ayala", + "company": "Zilidium", + "employed": true + }, + { + "firstName": "Cox", + "lastName": "English", + "company": "Chorizon", + "employed": true + }, + { + "firstName": "Barnes", + "lastName": "Fisher", + "company": "Flotonic", + "employed": false + }, + { + "firstName": "Stone", + "lastName": "Stokes", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Briana", + "lastName": "Harrison", + "company": "Lotron", + "employed": true + }, + { + "firstName": "Flowers", + "lastName": "Mathis", + "company": "Gluid", + "employed": false + }, + { + "firstName": "Patton", + "lastName": "George", + "company": "Orbean", + "employed": false + }, + { + "firstName": "Holt", + "lastName": "Meyers", + "company": "Vidto", + "employed": false + }, + { + "firstName": "Willa", + "lastName": "Stevenson", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Tami", + "lastName": "Daugherty", + "company": "Besto", + "employed": false + }, + { + "firstName": "Barbara", + "lastName": "Randolph", + "company": "Idealis", + "employed": false + }, + { + "firstName": "Merle", + "lastName": "Anderson", + "company": "Comcur", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Melton", + "company": "Optique", + "employed": true + }, + { + "firstName": "Glass", + "lastName": "Hogan", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Floyd", + "lastName": "Trujillo", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Bonnie", + "lastName": "Nixon", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "Georgina", + "lastName": "Copeland", + "company": "Kongle", + "employed": false + }, + { + "firstName": "Wynn", + "lastName": "Forbes", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Rosemarie", + "lastName": "Wolf", + "company": "Shopabout", + "employed": false + }, + { + "firstName": "Louise", + "lastName": "Valenzuela", + "company": "Letpro", + "employed": true + }, + { + "firstName": "Greta", + "lastName": "Kirkland", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Magdalena", + "lastName": "Fleming", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Elisa", + "lastName": "Mejia", + "company": "Geekmosis", + "employed": false + }, + { + "firstName": "Karina", + "lastName": "Gordon", + "company": "Datagen", + "employed": false + }, + { + "firstName": "Sophia", + "lastName": "Peters", + "company": "Temorak", + "employed": true + }, + { + "firstName": "Atkins", + "lastName": "Mcbride", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Delia", + "lastName": "Sandoval", + "company": "Shepard", + "employed": true + }, + { + "firstName": "Geneva", + "lastName": "Shelton", + "company": "Dymi", + "employed": false + }, + { + "firstName": "Osborne", + "lastName": "Puckett", + "company": "Uniworld", + "employed": true + }, + { + "firstName": "Anastasia", + "lastName": "Goodman", + "company": "Franscene", + "employed": true + }, + { + "firstName": "Payne", + "lastName": "Giles", + "company": "Gleamink", + "employed": true + }, + { + "firstName": "Regina", + "lastName": "Elliott", + "company": "Isostream", + "employed": true + }, + { + "firstName": "Terra", + "lastName": "Cobb", + "company": "Kneedles", + "employed": true + }, + { + "firstName": "Joann", + "lastName": "Dickerson", + "company": "Scenty", + "employed": true + }, + { + "firstName": "Holloway", + "lastName": "Leach", + "company": "Cubicide", + "employed": false + }, + { + "firstName": "Barrett", + "lastName": "Mcclure", + "company": "Gaptec", + "employed": false + }, + { + "firstName": "Juanita", + "lastName": "Matthews", + "company": "Netility", + "employed": false + }, + { + "firstName": "Deloris", + "lastName": "Barron", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Schroeder", + "company": "Bittor", + "employed": false + }, + { + "firstName": "York", + "lastName": "Schmidt", + "company": "Comtours", + "employed": false + }, + { + "firstName": "Byrd", + "lastName": "Jimenez", + "company": "Namegen", + "employed": false + }, + { + "firstName": "Danielle", + "lastName": "Gould", + "company": "Flexigen", + "employed": false + }, + { + "firstName": "Sharp", + "lastName": "Ramirez", + "company": "Eplosion", + "employed": true + }, + { + "firstName": "Mccarthy", + "lastName": "Steele", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Alford", + "lastName": "Keller", + "company": "Assistix", + "employed": true + }, + { + "firstName": "Zamora", + "lastName": "Merritt", + "company": "Geoforma", + "employed": false + }, + { + "firstName": "Jefferson", + "lastName": "Brennan", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Mcneil", + "lastName": "Walsh", + "company": "Everest", + "employed": false + }, + { + "firstName": "Dominique", + "lastName": "Trevino", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Lucas", + "lastName": "Bentley", + "company": "Opportech", + "employed": false + }, + { + "firstName": "Saundra", + "lastName": "Gentry", + "company": "Darwinium", + "employed": true + }, + { + "firstName": "Harrell", + "lastName": "Farley", + "company": "Zoinage", + "employed": true + }, + { + "firstName": "Warren", + "lastName": "Rich", + "company": "Zaggle", + "employed": true + }, + { + "firstName": "Donovan", + "lastName": "Douglas", + "company": "Koffee", + "employed": false + }, + { + "firstName": "Yesenia", + "lastName": "Kramer", + "company": "Xixan", + "employed": true + }, + { + "firstName": "Frankie", + "lastName": "Brewer", + "company": "Blanet", + "employed": false + }, + { + "firstName": "Mary", + "lastName": "Lancaster", + "company": "Omatom", + "employed": true + }, + { + "firstName": "Carla", + "lastName": "Parker", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Colon", + "lastName": "Mills", + "company": "Bezal", + "employed": true + }, + { + "firstName": "Rosemary", + "lastName": "Duffy", + "company": "Netplax", + "employed": true + }, + { + "firstName": "Mari", + "lastName": "Villarreal", + "company": "Waterbaby", + "employed": true + }, + { + "firstName": "Cristina", + "lastName": "Thompson", + "company": "Vertide", + "employed": false + }, + { + "firstName": "Brooks", + "lastName": "Dodson", + "company": "Tubalum", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Atkinson", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Barker", + "lastName": "Howard", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Sue", + "lastName": "Craig", + "company": "Krag", + "employed": true + }, + { + "firstName": "Lola", + "lastName": "Morton", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Sanford", + "lastName": "Rowland", + "company": "Andershun", + "employed": true + }, + { + "firstName": "Francine", + "lastName": "Cox", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Bobbi", + "lastName": "Holcomb", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Morin", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Lelia", + "lastName": "Morrow", + "company": "Netplode", + "employed": false + }, + { + "firstName": "Christian", + "lastName": "Wells", + "company": "Neteria", + "employed": true + }, + { + "firstName": "Hammond", + "lastName": "Carver", + "company": "Melbacor", + "employed": true + }, + { + "firstName": "Oliver", + "lastName": "Chase", + "company": "Zork", + "employed": false + }, + { + "firstName": "Angelia", + "lastName": "Mcdonald", + "company": "Zilch", + "employed": false + }, + { + "firstName": "Dudley", + "lastName": "Michael", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Estes", + "lastName": "Carlson", + "company": "Jamnation", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Bishop", + "company": "Imperium", + "employed": true + }, + { + "firstName": "Keri", + "lastName": "Mayo", + "company": "Makingway", + "employed": false + }, + { + "firstName": "Phelps", + "lastName": "Combs", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Carlene", + "lastName": "Mcknight", + "company": "Portalis", + "employed": false + }, + { + "firstName": "Chaney", + "lastName": "Gutierrez", + "company": "Pyramia", + "employed": true + }, + { + "firstName": "Carroll", + "lastName": "Payne", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Gill", + "lastName": "Simpson", + "company": "Quarx", + "employed": false + }, + { + "firstName": "Martin", + "lastName": "Lucas", + "company": "Hometown", + "employed": false + }, + { + "firstName": "Bell", + "lastName": "Hood", + "company": "Enquility", + "employed": false + }, + { + "firstName": "Suarez", + "lastName": "James", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Leila", + "lastName": "Mosley", + "company": "Elpro", + "employed": false + }, + { + "firstName": "Eugenia", + "lastName": "Schultz", + "company": "Nixelt", + "employed": true + }, + { + "firstName": "Queen", + "lastName": "Alford", + "company": "Quantalia", + "employed": false + }, + { + "firstName": "Burgess", + "lastName": "Joyce", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Nola", + "lastName": "Terrell", + "company": "Ecstasia", + "employed": true + }, + { + "firstName": "Norris", + "lastName": "Roth", + "company": "Calcu", + "employed": false + }, + { + "firstName": "Joy", + "lastName": "Goff", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Gibbs", + "lastName": "Walls", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Doris", + "lastName": "Nicholson", + "company": "Earthmark", + "employed": false + }, + { + "firstName": "Bettie", + "lastName": "Deleon", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Greer", + "lastName": "Sloan", + "company": "Nurali", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Fields", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Emily", + "lastName": "Ruiz", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Laurel", + "lastName": "Houston", + "company": "Medifax", + "employed": false + }, + { + "firstName": "Cortez", + "lastName": "Kelley", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Marisa", + "lastName": "Shaffer", + "company": "Halap", + "employed": false + }, + { + "firstName": "Graham", + "lastName": "Armstrong", + "company": "Verton", + "employed": true + }, + { + "firstName": "Dollie", + "lastName": "Horn", + "company": "Gorganic", + "employed": false + }, + { + "firstName": "Ellis", + "lastName": "Buck", + "company": "Wrapture", + "employed": false + }, + { + "firstName": "Henderson", + "lastName": "Franklin", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Celeste", + "lastName": "Mueller", + "company": "Silodyne", + "employed": false + }, + { + "firstName": "Buchanan", + "lastName": "Britt", + "company": "Marvane", + "employed": false + }, + { + "firstName": "Paul", + "lastName": "Foster", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Monique", + "lastName": "Bryan", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Cote", + "lastName": "Bowen", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "Nannie", + "lastName": "Klein", + "company": "Wazzu", + "employed": true + }, + { + "firstName": "Lambert", + "lastName": "Hernandez", + "company": "Trasola", + "employed": true + }, + { + "firstName": "Sandoval", + "lastName": "Holman", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Elsa", + "lastName": "Lewis", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Franco", + "lastName": "Guerra", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Melisa", + "lastName": "Robbins", + "company": "Exoteric", + "employed": false + }, + { + "firstName": "Rivers", + "lastName": "Good", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Ross", + "lastName": "Justice", + "company": "Synkgen", + "employed": false + }, + { + "firstName": "Dunn", + "lastName": "Paul", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Fleming", + "lastName": "Mullen", + "company": "Extragen", + "employed": false + }, + { + "firstName": "Ivy", + "lastName": "Flynn", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Maggie", + "lastName": "Dunlap", + "company": "Homelux", + "employed": true + }, + { + "firstName": "Russo", + "lastName": "Cole", + "company": "Niquent", + "employed": false + }, + { + "firstName": "Mai", + "lastName": "Winters", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Dean", + "lastName": "Oliver", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Macias", + "lastName": "Frye", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Santiago", + "lastName": "Benjamin", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Araceli", + "lastName": "Hines", + "company": "Izzby", + "employed": true + }, + { + "firstName": "Lorene", + "lastName": "Hutchinson", + "company": "Fibrodyne", + "employed": false + }, + { + "firstName": "Mathews", + "lastName": "Vazquez", + "company": "Interodeo", + "employed": false + }, + { + "firstName": "Nichols", + "lastName": "Richmond", + "company": "Datagene", + "employed": false + }, + { + "firstName": "Giles", + "lastName": "Gallagher", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Cecelia", + "lastName": "Molina", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Rivera", + "lastName": "Atkins", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Alexis", + "lastName": "Mcgowan", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Antonia", + "lastName": "Moran", + "company": "Farmex", + "employed": false + }, + { + "firstName": "Durham", + "lastName": "Alvarez", + "company": "Furnigeer", + "employed": true + }, + { + "firstName": "Ayers", + "lastName": "Levine", + "company": "Genmex", + "employed": false + }, + { + "firstName": "Nona", + "lastName": "Dyer", + "company": "Centregy", + "employed": false + }, + { + "firstName": "Frederick", + "lastName": "Perkins", + "company": "Minga", + "employed": false + }, + { + "firstName": "Summer", + "lastName": "Hickman", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Duffy", + "lastName": "Fry", + "company": "Zyple", + "employed": false + }, + { + "firstName": "May", + "lastName": "Pitts", + "company": "Webiotic", + "employed": true + }, + { + "firstName": "Glenna", + "lastName": "Yang", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Pearson", + "lastName": "Everett", + "company": "Polarax", + "employed": false + }, + { + "firstName": "Marla", + "lastName": "Farrell", + "company": "Corporana", + "employed": true + }, + { + "firstName": "Vasquez", + "lastName": "Case", + "company": "Stralum", + "employed": true + }, + { + "firstName": "Battle", + "lastName": "Bryant", + "company": "Pyramis", + "employed": false + }, + { + "firstName": "Landry", + "lastName": "Lynn", + "company": "Geofarm", + "employed": true + }, + { + "firstName": "Marion", + "lastName": "Holt", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Velazquez", + "lastName": "Guerrero", + "company": "Biolive", + "employed": false + }, + { + "firstName": "Haney", + "lastName": "Lambert", + "company": "Musaphics", + "employed": true + }, + { + "firstName": "Wong", + "lastName": "Ware", + "company": "Terragen", + "employed": false + }, + { + "firstName": "Aisha", + "lastName": "Odom", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Trina", + "lastName": "Medina", + "company": "Navir", + "employed": true + }, + { + "firstName": "Short", + "lastName": "Lamb", + "company": "Zogak", + "employed": false + }, + { + "firstName": "Harriett", + "lastName": "Wyatt", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Fry", + "lastName": "Cooke", + "company": "Digique", + "employed": false + }, + { + "firstName": "Trujillo", + "lastName": "Bowers", + "company": "Ecrater", + "employed": true + }, + { + "firstName": "Romero", + "lastName": "Harrell", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Hayden", + "lastName": "Johnston", + "company": "Vurbo", + "employed": true + }, + { + "firstName": "Gale", + "lastName": "Padilla", + "company": "Signidyne", + "employed": true + }, + { + "firstName": "Rollins", + "lastName": "Love", + "company": "Remold", + "employed": true + }, + { + "firstName": "Hernandez", + "lastName": "Vargas", + "company": "Ecratic", + "employed": true + }, + { + "firstName": "Sallie", + "lastName": "Serrano", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Kirkland", + "lastName": "Lowery", + "company": "Kidgrease", + "employed": true + }, + { + "firstName": "Charity", + "lastName": "Carey", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Gonzalez", + "lastName": "Fowler", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Lydia", + "lastName": "Reilly", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Wendi", + "lastName": "Cortez", + "company": "Sportan", + "employed": false + }, + { + "firstName": "Virginia", + "lastName": "Frazier", + "company": "Netur", + "employed": true + }, + { + "firstName": "Naomi", + "lastName": "Carr", + "company": "Equitax", + "employed": false + }, + { + "firstName": "Harding", + "lastName": "Long", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Stacy", + "lastName": "Morrison", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Parrish", + "lastName": "Ayers", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Young", + "lastName": "Bean", + "company": "Eclipto", + "employed": true + }, + { + "firstName": "Gregory", + "lastName": "Turner", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Alice", + "lastName": "Mcclain", + "company": "Prosure", + "employed": false + }, + { + "firstName": "Hazel", + "lastName": "Rasmussen", + "company": "Prismatic", + "employed": true + }, + { + "firstName": "Higgins", + "lastName": "Suarez", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Howe", + "lastName": "Oconnor", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Patrick", + "lastName": "Sharpe", + "company": "Accel", + "employed": false + }, + { + "firstName": "Vonda", + "lastName": "Nunez", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Herman", + "lastName": "Velasquez", + "company": "Olympix", + "employed": true + }, + { + "firstName": "Munoz", + "lastName": "Rodgers", + "company": "Powernet", + "employed": true + }, + { + "firstName": "Todd", + "lastName": "Velez", + "company": "Magnemo", + "employed": true + }, + { + "firstName": "Emma", + "lastName": "Kinney", + "company": "Orbin", + "employed": false + }, + { + "firstName": "Concepcion", + "lastName": "Rivas", + "company": "Musix", + "employed": true + }, + { + "firstName": "Wiley", + "lastName": "Moore", + "company": "Zentury", + "employed": true + }, + { + "firstName": "Sharon", + "lastName": "Osborn", + "company": "Infotrips", + "employed": false + }, + { + "firstName": "Sally", + "lastName": "Black", + "company": "Norsul", + "employed": false + }, + { + "firstName": "Jewell", + "lastName": "Young", + "company": "Zensure", + "employed": false + }, + { + "firstName": "Sasha", + "lastName": "Weiss", + "company": "Cablam", + "employed": false + }, + { + "firstName": "Lila", + "lastName": "Sims", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Juana", + "lastName": "Branch", + "company": "Qiao", + "employed": false + }, + { + "firstName": "Sandy", + "lastName": "Faulkner", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Luisa", + "lastName": "Norton", + "company": "Hyplex", + "employed": false + }, + { + "firstName": "Anthony", + "lastName": "Conner", + "company": "Anixang", + "employed": false + }, + { + "firstName": "Shaw", + "lastName": "Jackson", + "company": "Playce", + "employed": true + }, + { + "firstName": "Linda", + "lastName": "Luna", + "company": "Comtent", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Leonard", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Eaton", + "lastName": "Hayden", + "company": "Straloy", + "employed": true + }, + { + "firstName": "Andrea", + "lastName": "Delacruz", + "company": "Zaphire", + "employed": false + }, + { + "firstName": "Gonzales", + "lastName": "Carson", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Berger", + "lastName": "Boone", + "company": "Tri@Tribalog", + "employed": true + }, + { + "firstName": "Hope", + "lastName": "Wade", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Hewitt", + "lastName": "Adkins", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Medina", + "lastName": "Mcconnell", + "company": "Isis", + "employed": true + }, + { + "firstName": "Norton", + "lastName": "Romero", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Lynda", + "lastName": "Dillon", + "company": "Plexia", + "employed": true + }, + { + "firstName": "Angie", + "lastName": "Kane", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Roxie", + "lastName": "White", + "company": "Quarex", + "employed": false + }, + { + "firstName": "Gilda", + "lastName": "Donovan", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Miller", + "lastName": "Stone", + "company": "Sonique", + "employed": true + }, + { + "firstName": "Mckinney", + "lastName": "Fitzpatrick", + "company": "Metroz", + "employed": false + }, + { + "firstName": "Hobbs", + "lastName": "Davidson", + "company": "Autograte", + "employed": false + }, + { + "firstName": "Alyce", + "lastName": "Miller", + "company": "Aeora", + "employed": false + }, + { + "firstName": "Bette", + "lastName": "Callahan", + "company": "Techade", + "employed": true + }, + { + "firstName": "Katie", + "lastName": "Campos", + "company": "Adornica", + "employed": false + }, + { + "firstName": "Joyner", + "lastName": "Schwartz", + "company": "Elemantra", + "employed": false + }, + { + "firstName": "Hall", + "lastName": "Wilkins", + "company": "Atomica", + "employed": true + }, + { + "firstName": "Jamie", + "lastName": "Monroe", + "company": "Earbang", + "employed": false + }, + { + "firstName": "Audra", + "lastName": "Taylor", + "company": "Tetak", + "employed": true + }, + { + "firstName": "Pamela", + "lastName": "Hale", + "company": "Grok", + "employed": false + }, + { + "firstName": "Bray", + "lastName": "Hensley", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Anne", + "lastName": "Guthrie", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Susana", + "lastName": "Colon", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Buckner", + "lastName": "Hubbard", + "company": "Aclima", + "employed": false + }, + { + "firstName": "Head", + "lastName": "Compton", + "company": "Mazuda", + "employed": false + }, + { + "firstName": "Cash", + "lastName": "Knowles", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Eunice", + "lastName": "Stafford", + "company": "Crustatia", + "employed": false + }, + { + "firstName": "Wise", + "lastName": "Finch", + "company": "Phormula", + "employed": false + }, + { + "firstName": "Kristie", + "lastName": "Santos", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Roy", + "lastName": "Reynolds", + "company": "Isonus", + "employed": false + }, + { + "firstName": "Henry", + "lastName": "Clemons", + "company": "Daycore", + "employed": false + }, + { + "firstName": "Rich", + "lastName": "Jensen", + "company": "Bullzone", + "employed": true + }, + { + "firstName": "Aline", + "lastName": "Phelps", + "company": "Matrixity", + "employed": false + }, + { + "firstName": "Colette", + "lastName": "Lara", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Janet", + "lastName": "Riley", + "company": "Eyewax", + "employed": false + }, + { + "firstName": "Warner", + "lastName": "Marshall", + "company": "Emtrak", + "employed": true + }, + { + "firstName": "Alicia", + "lastName": "Bernard", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Kitty", + "lastName": "Raymond", + "company": "Typhonica", + "employed": false + }, + { + "firstName": "Oneill", + "lastName": "Mccormick", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Colleen", + "lastName": "Ortega", + "company": "Buzzopia", + "employed": true + }, + { + "firstName": "Finley", + "lastName": "Porter", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Johanna", + "lastName": "Walters", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Olive", + "lastName": "Ortiz", + "company": "Zuvy", + "employed": true + }, + { + "firstName": "Koch", + "lastName": "Gibbs", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Katelyn", + "lastName": "Castro", + "company": "Accupharm", + "employed": true + }, + { + "firstName": "Duncan", + "lastName": "Vega", + "company": "Hopeli", + "employed": true + }, + { + "firstName": "Melinda", + "lastName": "Manning", + "company": "Springbee", + "employed": true + }, + { + "firstName": "Serena", + "lastName": "Salazar", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Clayton", + "lastName": "Pate", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Maude", + "lastName": "Bullock", + "company": "Coriander", + "employed": false + }, + { + "firstName": "Emma", + "lastName": "Noel", + "company": "Atomica", + "employed": false + }, + { + "firstName": "Gibbs", + "lastName": "Carey", + "company": "Caxt", + "employed": true + }, + { + "firstName": "Bean", + "lastName": "Travis", + "company": "Parcoe", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Frye", + "company": "Pharmacon", + "employed": false + }, + { + "firstName": "Poole", + "lastName": "Ortiz", + "company": "Comvoy", + "employed": false + }, + { + "firstName": "Cleo", + "lastName": "Carney", + "company": "Quarx", + "employed": false + }, + { + "firstName": "Mcconnell", + "lastName": "Conner", + "company": "Datagene", + "employed": true + }, + { + "firstName": "Wilcox", + "lastName": "Marks", + "company": "Fuelton", + "employed": false + }, + { + "firstName": "Sargent", + "lastName": "Barron", + "company": "Zipak", + "employed": true + }, + { + "firstName": "Molly", + "lastName": "Bray", + "company": "Centree", + "employed": true + }, + { + "firstName": "Nina", + "lastName": "Carver", + "company": "Slax", + "employed": true + }, + { + "firstName": "Grace", + "lastName": "Mosley", + "company": "Stucco", + "employed": false + }, + { + "firstName": "Hilary", + "lastName": "Gilbert", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Gallegos", + "lastName": "Nelson", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Laura", + "lastName": "Ewing", + "company": "Voipa", + "employed": false + }, + { + "firstName": "Oliver", + "lastName": "Conley", + "company": "Nipaz", + "employed": false + }, + { + "firstName": "Ramirez", + "lastName": "Russo", + "company": "Supremia", + "employed": true + }, + { + "firstName": "Holland", + "lastName": "Tran", + "company": "Codax", + "employed": false + }, + { + "firstName": "Edna", + "lastName": "Callahan", + "company": "Codact", + "employed": true + }, + { + "firstName": "Jessie", + "lastName": "Roberson", + "company": "Telpod", + "employed": true + }, + { + "firstName": "Glenn", + "lastName": "Daniel", + "company": "Geofarm", + "employed": true + }, + { + "firstName": "Riley", + "lastName": "Gentry", + "company": "Enjola", + "employed": false + }, + { + "firstName": "Judy", + "lastName": "Skinner", + "company": "Eplosion", + "employed": false + }, + { + "firstName": "Kaitlin", + "lastName": "Morin", + "company": "Marvane", + "employed": false + }, + { + "firstName": "Flores", + "lastName": "Hodges", + "company": "Ecosys", + "employed": true + }, + { + "firstName": "Mcneil", + "lastName": "Pratt", + "company": "Artiq", + "employed": false + }, + { + "firstName": "Mcmillan", + "lastName": "Alvarez", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Craig", + "lastName": "Dejesus", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Lois", + "lastName": "Rhodes", + "company": "Elemantra", + "employed": false + }, + { + "firstName": "Tabitha", + "lastName": "Burton", + "company": "Vinch", + "employed": true + }, + { + "firstName": "Dianna", + "lastName": "Berger", + "company": "Inear", + "employed": true + }, + { + "firstName": "Pace", + "lastName": "Leon", + "company": "Surelogic", + "employed": false + }, + { + "firstName": "Klein", + "lastName": "Figueroa", + "company": "Cosmosis", + "employed": true + }, + { + "firstName": "Castaneda", + "lastName": "Allison", + "company": "Kyaguru", + "employed": true + }, + { + "firstName": "Madden", + "lastName": "Lang", + "company": "Pholio", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Burns", + "company": "Portico", + "employed": true + }, + { + "firstName": "Romero", + "lastName": "Holland", + "company": "Zensus", + "employed": false + }, + { + "firstName": "Moran", + "lastName": "Faulkner", + "company": "Comtrek", + "employed": true + }, + { + "firstName": "Kellie", + "lastName": "Crawford", + "company": "Fiberox", + "employed": false + }, + { + "firstName": "Figueroa", + "lastName": "Schmidt", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Bernadine", + "lastName": "Gregory", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Padilla", + "lastName": "Rocha", + "company": "Velity", + "employed": true + }, + { + "firstName": "Murray", + "lastName": "Sellers", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Gardner", + "lastName": "Weber", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Ernestine", + "lastName": "Miranda", + "company": "Rugstars", + "employed": false + }, + { + "firstName": "Kristen", + "lastName": "Noble", + "company": "Fuelworks", + "employed": true + }, + { + "firstName": "Lana", + "lastName": "Davidson", + "company": "Lexicondo", + "employed": false + }, + { + "firstName": "Chrystal", + "lastName": "Merrill", + "company": "Interloo", + "employed": true + }, + { + "firstName": "Rae", + "lastName": "Anthony", + "company": "Pulze", + "employed": true + }, + { + "firstName": "Hannah", + "lastName": "Hogan", + "company": "Filodyne", + "employed": false + }, + { + "firstName": "Schmidt", + "lastName": "Black", + "company": "Hawkster", + "employed": false + }, + { + "firstName": "Estes", + "lastName": "Barr", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Carlson", + "lastName": "Copeland", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Beck", + "lastName": "Rosa", + "company": "Pyramia", + "employed": false + }, + { + "firstName": "Laurie", + "lastName": "Osborne", + "company": "Enquility", + "employed": false + }, + { + "firstName": "Villarreal", + "lastName": "Velazquez", + "company": "Digifad", + "employed": false + }, + { + "firstName": "Arline", + "lastName": "Mayer", + "company": "Digitalus", + "employed": false + }, + { + "firstName": "Kelley", + "lastName": "Boone", + "company": "Insurety", + "employed": true + }, + { + "firstName": "Lou", + "lastName": "Rose", + "company": "Ovation", + "employed": false + }, + { + "firstName": "Iva", + "lastName": "Slater", + "company": "Manglo", + "employed": true + }, + { + "firstName": "Mccall", + "lastName": "Bond", + "company": "Harmoney", + "employed": true + }, + { + "firstName": "Lawson", + "lastName": "Kirby", + "company": "Geekus", + "employed": false + }, + { + "firstName": "Kayla", + "lastName": "Barrett", + "company": "Enormo", + "employed": false + }, + { + "firstName": "Gilmore", + "lastName": "Spears", + "company": "Flum", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Shannon", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Marcie", + "lastName": "Silva", + "company": "Kengen", + "employed": true + }, + { + "firstName": "Daniel", + "lastName": "Cotton", + "company": "Jasper", + "employed": true + }, + { + "firstName": "Bobbi", + "lastName": "Tanner", + "company": "Paprikut", + "employed": true + }, + { + "firstName": "Lang", + "lastName": "Dale", + "company": "Danja", + "employed": false + }, + { + "firstName": "Allyson", + "lastName": "Woodward", + "company": "Grainspot", + "employed": false + }, + { + "firstName": "Savage", + "lastName": "Hensley", + "company": "Locazone", + "employed": true + }, + { + "firstName": "Hopper", + "lastName": "Lancaster", + "company": "Zaj", + "employed": true + }, + { + "firstName": "Baxter", + "lastName": "Ayers", + "company": "Zerology", + "employed": false + }, + { + "firstName": "Letha", + "lastName": "Reese", + "company": "Exiand", + "employed": true + }, + { + "firstName": "Clay", + "lastName": "Love", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Guerra", + "lastName": "Hines", + "company": "Primordia", + "employed": false + }, + { + "firstName": "Consuelo", + "lastName": "Fitzgerald", + "company": "Magnafone", + "employed": false + }, + { + "firstName": "Crane", + "lastName": "Crane", + "company": "Musaphics", + "employed": false + }, + { + "firstName": "Love", + "lastName": "Dean", + "company": "Pyramax", + "employed": true + }, + { + "firstName": "Valencia", + "lastName": "Munoz", + "company": "Konnect", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Mclean", + "company": "Opportech", + "employed": true + }, + { + "firstName": "Patricia", + "lastName": "Galloway", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Glass", + "lastName": "Rosario", + "company": "Biohab", + "employed": true + }, + { + "firstName": "Margie", + "lastName": "Talley", + "company": "Insource", + "employed": true + }, + { + "firstName": "Barton", + "lastName": "Hammond", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Deana", + "lastName": "Hewitt", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Stanley", + "lastName": "Hampton", + "company": "Bovis", + "employed": false + }, + { + "firstName": "Rhodes", + "lastName": "Carson", + "company": "Pearlesex", + "employed": true + }, + { + "firstName": "Rollins", + "lastName": "Walsh", + "company": "Andershun", + "employed": true + }, + { + "firstName": "Blake", + "lastName": "Aguirre", + "company": "Bleendot", + "employed": false + }, + { + "firstName": "Patsy", + "lastName": "Steele", + "company": "Dognosis", + "employed": false + }, + { + "firstName": "Calderon", + "lastName": "Bruce", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Merritt", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Mcfarland", + "lastName": "Lawson", + "company": "Telequiet", + "employed": false + }, + { + "firstName": "Ewing", + "lastName": "Harmon", + "company": "Zaphire", + "employed": true + }, + { + "firstName": "Amanda", + "lastName": "Richards", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Griffith", + "lastName": "Vance", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Felecia", + "lastName": "Bentley", + "company": "Apextri", + "employed": false + }, + { + "firstName": "Carpenter", + "lastName": "Guerrero", + "company": "Zytrek", + "employed": true + }, + { + "firstName": "Conrad", + "lastName": "Snyder", + "company": "Gink", + "employed": true + }, + { + "firstName": "Delaney", + "lastName": "Barker", + "company": "Podunk", + "employed": false + }, + { + "firstName": "Bolton", + "lastName": "Andrews", + "company": "Comstruct", + "employed": false + }, + { + "firstName": "Swanson", + "lastName": "Huffman", + "company": "Geoform", + "employed": true + }, + { + "firstName": "Jaime", + "lastName": "Waller", + "company": "Inrt", + "employed": false + }, + { + "firstName": "Karen", + "lastName": "Collins", + "company": "Helixo", + "employed": false + }, + { + "firstName": "Marie", + "lastName": "Joyner", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Jerry", + "lastName": "Reed", + "company": "Neocent", + "employed": true + }, + { + "firstName": "Stella", + "lastName": "Clark", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Bette", + "lastName": "Rogers", + "company": "Zaggle", + "employed": false + }, + { + "firstName": "Velasquez", + "lastName": "Fletcher", + "company": "Zilla", + "employed": true + }, + { + "firstName": "Sheri", + "lastName": "Gamble", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Cristina", + "lastName": "Deleon", + "company": "Savvy", + "employed": true + }, + { + "firstName": "Jimenez", + "lastName": "Maynard", + "company": "Kog", + "employed": false + }, + { + "firstName": "Bernice", + "lastName": "Sandoval", + "company": "Techtrix", + "employed": true + }, + { + "firstName": "Allie", + "lastName": "Horn", + "company": "Beadzza", + "employed": true + }, + { + "firstName": "Jodie", + "lastName": "Cole", + "company": "Bytrex", + "employed": true + }, + { + "firstName": "Burgess", + "lastName": "Chang", + "company": "Vertide", + "employed": true + }, + { + "firstName": "Bradford", + "lastName": "Flores", + "company": "Luxuria", + "employed": false + }, + { + "firstName": "Agnes", + "lastName": "Mathis", + "company": "Undertap", + "employed": true + }, + { + "firstName": "Terry", + "lastName": "Carter", + "company": "Illumity", + "employed": false + }, + { + "firstName": "Decker", + "lastName": "Sanford", + "company": "Boink", + "employed": false + }, + { + "firstName": "Lambert", + "lastName": "Cote", + "company": "Scentric", + "employed": false + }, + { + "firstName": "Kendra", + "lastName": "Stanley", + "company": "Krog", + "employed": true + }, + { + "firstName": "Karina", + "lastName": "Drake", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Cornelia", + "lastName": "Cash", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Latisha", + "lastName": "Schroeder", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Sloan", + "lastName": "Martinez", + "company": "Lotron", + "employed": false + }, + { + "firstName": "Leona", + "lastName": "Christian", + "company": "Zorromop", + "employed": true + }, + { + "firstName": "Naomi", + "lastName": "Harrell", + "company": "Isis", + "employed": true + }, + { + "firstName": "Bender", + "lastName": "Hicks", + "company": "Spherix", + "employed": false + }, + { + "firstName": "Ingrid", + "lastName": "Clemons", + "company": "Futurize", + "employed": false + }, + { + "firstName": "Neva", + "lastName": "Higgins", + "company": "Comtest", + "employed": false + }, + { + "firstName": "Ballard", + "lastName": "Graham", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Concetta", + "lastName": "Chapman", + "company": "Uberlux", + "employed": true + }, + { + "firstName": "Mullins", + "lastName": "Butler", + "company": "Biflex", + "employed": true + }, + { + "firstName": "West", + "lastName": "James", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Molina", + "lastName": "Duncan", + "company": "Zepitope", + "employed": false + }, + { + "firstName": "Lindsey", + "lastName": "Gallagher", + "company": "Animalia", + "employed": true + }, + { + "firstName": "Wynn", + "lastName": "Raymond", + "company": "Buzzness", + "employed": false + }, + { + "firstName": "Shannon", + "lastName": "Christensen", + "company": "Zork", + "employed": true + }, + { + "firstName": "Araceli", + "lastName": "Henderson", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Boyd", + "lastName": "Rivers", + "company": "Candecor", + "employed": true + }, + { + "firstName": "Hunt", + "lastName": "Peters", + "company": "Unisure", + "employed": false + }, + { + "firstName": "Salas", + "lastName": "Haynes", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Candice", + "lastName": "Pittman", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Jerri", + "lastName": "Lee", + "company": "Geekular", + "employed": false + }, + { + "firstName": "Kramer", + "lastName": "Kinney", + "company": "Norali", + "employed": false + }, + { + "firstName": "Emilia", + "lastName": "Norton", + "company": "Datacator", + "employed": true + }, + { + "firstName": "Trujillo", + "lastName": "Tyler", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Donaldson", + "lastName": "Ryan", + "company": "Egypto", + "employed": false + }, + { + "firstName": "Amparo", + "lastName": "Contreras", + "company": "Quadeebo", + "employed": true + }, + { + "firstName": "Alvarez", + "lastName": "Meadows", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Baker", + "lastName": "Ware", + "company": "Accidency", + "employed": true + }, + { + "firstName": "Mcgowan", + "lastName": "Knapp", + "company": "Megall", + "employed": true + }, + { + "firstName": "Harrington", + "lastName": "Baird", + "company": "Injoy", + "employed": false + }, + { + "firstName": "Mclean", + "lastName": "Booker", + "company": "Talendula", + "employed": true + }, + { + "firstName": "Goodman", + "lastName": "Newman", + "company": "Kneedles", + "employed": true + }, + { + "firstName": "Theresa", + "lastName": "Lindsey", + "company": "Deepends", + "employed": true + }, + { + "firstName": "Kirsten", + "lastName": "Wright", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Doris", + "lastName": "Mcdonald", + "company": "Manufact", + "employed": true + }, + { + "firstName": "Brock", + "lastName": "Harrington", + "company": "Barkarama", + "employed": false + }, + { + "firstName": "Sherrie", + "lastName": "Griffin", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Helena", + "lastName": "Wall", + "company": "Waterbaby", + "employed": true + }, + { + "firstName": "Farmer", + "lastName": "Hoover", + "company": "Martgo", + "employed": true + }, + { + "firstName": "Beatriz", + "lastName": "Kent", + "company": "Incubus", + "employed": true + }, + { + "firstName": "Imelda", + "lastName": "Hayden", + "company": "Zilencio", + "employed": false + }, + { + "firstName": "Hancock", + "lastName": "Romero", + "company": "Bleeko", + "employed": true + }, + { + "firstName": "Rena", + "lastName": "Bush", + "company": "Homelux", + "employed": false + }, + { + "firstName": "Ina", + "lastName": "Melton", + "company": "Bittor", + "employed": true + }, + { + "firstName": "Washington", + "lastName": "Webb", + "company": "Poshome", + "employed": true + }, + { + "firstName": "Gretchen", + "lastName": "Buckner", + "company": "Intergeek", + "employed": false + }, + { + "firstName": "Brigitte", + "lastName": "Downs", + "company": "Quordate", + "employed": false + }, + { + "firstName": "Cheryl", + "lastName": "Sparks", + "company": "Quonata", + "employed": false + }, + { + "firstName": "Carole", + "lastName": "Odom", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Knowles", + "lastName": "Ayala", + "company": "Namegen", + "employed": true + }, + { + "firstName": "Adrian", + "lastName": "Simpson", + "company": "Remold", + "employed": false + }, + { + "firstName": "Sheryl", + "lastName": "Marsh", + "company": "Geostele", + "employed": false + }, + { + "firstName": "Pauline", + "lastName": "Shaw", + "company": "Geekwagon", + "employed": true + }, + { + "firstName": "Gutierrez", + "lastName": "Matthews", + "company": "Exospeed", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Gross", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Milagros", + "lastName": "Murray", + "company": "Stelaecor", + "employed": true + }, + { + "firstName": "Galloway", + "lastName": "Mann", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Elsie", + "lastName": "Soto", + "company": "Envire", + "employed": true + }, + { + "firstName": "Blanchard", + "lastName": "Woods", + "company": "Biospan", + "employed": false + }, + { + "firstName": "Sheppard", + "lastName": "Smith", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Lula", + "lastName": "Sims", + "company": "Olucore", + "employed": false + }, + { + "firstName": "Zimmerman", + "lastName": "Buck", + "company": "Digigen", + "employed": false + }, + { + "firstName": "Cabrera", + "lastName": "Hardin", + "company": "Accusage", + "employed": false + }, + { + "firstName": "Emerson", + "lastName": "Barrera", + "company": "Apex", + "employed": true + }, + { + "firstName": "Teresa", + "lastName": "Pennington", + "company": "Slumberia", + "employed": false + }, + { + "firstName": "Hill", + "lastName": "Potter", + "company": "Musix", + "employed": true + }, + { + "firstName": "Reilly", + "lastName": "Edwards", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Sawyer", + "lastName": "Roy", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Desiree", + "lastName": "Chen", + "company": "Qualitex", + "employed": true + }, + { + "firstName": "Letitia", + "lastName": "Lott", + "company": "Geekfarm", + "employed": false + }, + { + "firstName": "Marisa", + "lastName": "Jennings", + "company": "Boilicon", + "employed": false + }, + { + "firstName": "Brewer", + "lastName": "Doyle", + "company": "Irack", + "employed": false + }, + { + "firstName": "Ingram", + "lastName": "Serrano", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Linda", + "lastName": "Little", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Myrtle", + "lastName": "Valenzuela", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Booth", + "lastName": "Jensen", + "company": "Dentrex", + "employed": false + }, + { + "firstName": "Heather", + "lastName": "Blackwell", + "company": "Crustatia", + "employed": true + }, + { + "firstName": "Ava", + "lastName": "Velez", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Leanne", + "lastName": "Dunlap", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Adkins", + "lastName": "Washington", + "company": "Zentury", + "employed": false + }, + { + "firstName": "Lindsay", + "lastName": "Strickland", + "company": "Datagen", + "employed": true + }, + { + "firstName": "James", + "lastName": "Hunter", + "company": "Orbixtar", + "employed": true + }, + { + "firstName": "Jacklyn", + "lastName": "Hooper", + "company": "Halap", + "employed": false + }, + { + "firstName": "Martina", + "lastName": "Hebert", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Deborah", + "lastName": "Garcia", + "company": "Calcu", + "employed": false + }, + { + "firstName": "Viola", + "lastName": "Petty", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Craft", + "lastName": "Patterson", + "company": "Multron", + "employed": true + }, + { + "firstName": "Tina", + "lastName": "Henry", + "company": "Furnigeer", + "employed": false + }, + { + "firstName": "Caitlin", + "lastName": "Buckley", + "company": "Dancity", + "employed": false + }, + { + "firstName": "Louisa", + "lastName": "Kelly", + "company": "Apexia", + "employed": true + }, + { + "firstName": "Michele", + "lastName": "May", + "company": "Isosure", + "employed": true + }, + { + "firstName": "Mcbride", + "lastName": "Frank", + "company": "Maxemia", + "employed": true + }, + { + "firstName": "Stewart", + "lastName": "Benson", + "company": "Geekola", + "employed": false + }, + { + "firstName": "Charlene", + "lastName": "Barnes", + "company": "Cognicode", + "employed": true + }, + { + "firstName": "Olga", + "lastName": "Walker", + "company": "Deminimum", + "employed": false + }, + { + "firstName": "Gina", + "lastName": "Owen", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Melba", + "lastName": "Jacobson", + "company": "Isonus", + "employed": true + }, + { + "firstName": "Richmond", + "lastName": "Cherry", + "company": "Anarco", + "employed": true + }, + { + "firstName": "Brianna", + "lastName": "Boyd", + "company": "Stralum", + "employed": false + }, + { + "firstName": "Payne", + "lastName": "Macdonald", + "company": "Affluex", + "employed": true + }, + { + "firstName": "Ella", + "lastName": "Blankenship", + "company": "Zyple", + "employed": false + }, + { + "firstName": "Juliana", + "lastName": "Benjamin", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Ericka", + "lastName": "Harvey", + "company": "Centuria", + "employed": true + }, + { + "firstName": "Bonnie", + "lastName": "Mcclain", + "company": "Corecom", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Horton", + "company": "Applica", + "employed": true + }, + { + "firstName": "Maynard", + "lastName": "Wyatt", + "company": "Marqet", + "employed": true + }, + { + "firstName": "Tara", + "lastName": "Casey", + "company": "Lyrichord", + "employed": false + }, + { + "firstName": "Robles", + "lastName": "Meyer", + "company": "Corporana", + "employed": true + }, + { + "firstName": "English", + "lastName": "English", + "company": "Ovolo", + "employed": false + }, + { + "firstName": "Mendoza", + "lastName": "Bright", + "company": "Premiant", + "employed": false + }, + { + "firstName": "Burnett", + "lastName": "Strong", + "company": "Zaggles", + "employed": true + }, + { + "firstName": "Pope", + "lastName": "Lewis", + "company": "Updat", + "employed": false + }, + { + "firstName": "Elsa", + "lastName": "Jefferson", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Carson", + "lastName": "Cameron", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Lakisha", + "lastName": "Franco", + "company": "Skinserve", + "employed": false + }, + { + "firstName": "Laurel", + "lastName": "Reid", + "company": "Niquent", + "employed": false + }, + { + "firstName": "Lorena", + "lastName": "Hopkins", + "company": "Ziore", + "employed": true + }, + { + "firstName": "Knight", + "lastName": "Cantrell", + "company": "Klugger", + "employed": false + }, + { + "firstName": "Johnson", + "lastName": "Guerra", + "company": "Flotonic", + "employed": true + }, + { + "firstName": "Rosemary", + "lastName": "Cross", + "company": "Ludak", + "employed": true + }, + { + "firstName": "Anastasia", + "lastName": "Diaz", + "company": "Grok", + "employed": true + }, + { + "firstName": "Delores", + "lastName": "Martin", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Hughes", + "lastName": "Good", + "company": "Zinca", + "employed": true + }, + { + "firstName": "England", + "lastName": "Maldonado", + "company": "Snacktion", + "employed": true + }, + { + "firstName": "Blackburn", + "lastName": "Mccarthy", + "company": "Firewax", + "employed": true + }, + { + "firstName": "Joy", + "lastName": "Mcclure", + "company": "Acumentor", + "employed": false + }, + { + "firstName": "Mann", + "lastName": "Lucas", + "company": "Velos", + "employed": false + }, + { + "firstName": "Gallagher", + "lastName": "Stokes", + "company": "Panzent", + "employed": true + }, + { + "firstName": "Mia", + "lastName": "Spencer", + "company": "Geekology", + "employed": true + }, + { + "firstName": "Nielsen", + "lastName": "Boyer", + "company": "Isotronic", + "employed": true + }, + { + "firstName": "Joanne", + "lastName": "Franklin", + "company": "Comtrak", + "employed": false + }, + { + "firstName": "Riddle", + "lastName": "Mcleod", + "company": "Norsup", + "employed": false + }, + { + "firstName": "Dina", + "lastName": "Bird", + "company": "Icology", + "employed": false + }, + { + "firstName": "Powers", + "lastName": "Fischer", + "company": "Orbean", + "employed": true + }, + { + "firstName": "Constance", + "lastName": "Poole", + "company": "Quonk", + "employed": true + }, + { + "firstName": "Faulkner", + "lastName": "Chase", + "company": "Kage", + "employed": true + }, + { + "firstName": "Twila", + "lastName": "Dudley", + "company": "Portalis", + "employed": false + }, + { + "firstName": "Justine", + "lastName": "Odonnell", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Travis", + "lastName": "Sampson", + "company": "Mantrix", + "employed": true + }, + { + "firstName": "Esmeralda", + "lastName": "Atkins", + "company": "Biolive", + "employed": true + }, + { + "firstName": "Hickman", + "lastName": "Landry", + "company": "Ohmnet", + "employed": true + }, + { + "firstName": "Autumn", + "lastName": "Santana", + "company": "Zboo", + "employed": false + }, + { + "firstName": "Celina", + "lastName": "Sutton", + "company": "Quarex", + "employed": true + }, + { + "firstName": "Tyler", + "lastName": "Olson", + "company": "Zillactic", + "employed": true + }, + { + "firstName": "Jacobs", + "lastName": "Workman", + "company": "Enersol", + "employed": true + }, + { + "firstName": "Antoinette", + "lastName": "Randolph", + "company": "Calcula", + "employed": true + }, + { + "firstName": "Fields", + "lastName": "Cohen", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Essie", + "lastName": "Mason", + "company": "Eventex", + "employed": true + }, + { + "firstName": "Cole", + "lastName": "Compton", + "company": "Jumpstack", + "employed": false + }, + { + "firstName": "Page", + "lastName": "Bartlett", + "company": "Gorganic", + "employed": false + }, + { + "firstName": "Geraldine", + "lastName": "Booth", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Rocha", + "lastName": "Williams", + "company": "Polarax", + "employed": true + }, + { + "firstName": "Sweeney", + "lastName": "Case", + "company": "Translink", + "employed": false + }, + { + "firstName": "Haney", + "lastName": "Pugh", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Meagan", + "lastName": "Keller", + "company": "Pawnagra", + "employed": true + }, + { + "firstName": "Kristie", + "lastName": "Jordan", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Minnie", + "lastName": "Trujillo", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Bowers", + "lastName": "Watts", + "company": "Flexigen", + "employed": false + }, + { + "firstName": "Ellis", + "lastName": "Cochran", + "company": "Isoswitch", + "employed": true + }, + { + "firstName": "Dominguez", + "lastName": "Moody", + "company": "Columella", + "employed": true + }, + { + "firstName": "Middleton", + "lastName": "Glover", + "company": "Austex", + "employed": false + }, + { + "firstName": "Parker", + "lastName": "Moon", + "company": "Orbin", + "employed": false + }, + { + "firstName": "Merritt", + "lastName": "Becker", + "company": "Recrisys", + "employed": true + }, + { + "firstName": "House", + "lastName": "Mack", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Forbes", + "lastName": "Kidd", + "company": "Earthplex", + "employed": true + }, + { + "firstName": "Cynthia", + "lastName": "Richardson", + "company": "Venoflex", + "employed": true + }, + { + "firstName": "Anderson", + "lastName": "Dickson", + "company": "Powernet", + "employed": false + }, + { + "firstName": "Kirkland", + "lastName": "Walls", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Frieda", + "lastName": "Ochoa", + "company": "Cytrek", + "employed": false + }, + { + "firstName": "Mcdaniel", + "lastName": "Hood", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Marilyn", + "lastName": "Vazquez", + "company": "Assistix", + "employed": true + }, + { + "firstName": "Noreen", + "lastName": "Ortega", + "company": "Zidox", + "employed": false + }, + { + "firstName": "Maritza", + "lastName": "Rutledge", + "company": "Cablam", + "employed": false + }, + { + "firstName": "Kidd", + "lastName": "Gonzales", + "company": "Viagreat", + "employed": true + }, + { + "firstName": "Corinne", + "lastName": "Willis", + "company": "Elita", + "employed": true + }, + { + "firstName": "Abbott", + "lastName": "Tate", + "company": "Flyboyz", + "employed": true + }, + { + "firstName": "Edwina", + "lastName": "Parrish", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Lori", + "lastName": "Riddle", + "company": "Anocha", + "employed": true + }, + { + "firstName": "Ware", + "lastName": "Duffy", + "company": "Limage", + "employed": true + }, + { + "firstName": "Gray", + "lastName": "Lyons", + "company": "Memora", + "employed": true + }, + { + "firstName": "Lelia", + "lastName": "Avery", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Cindy", + "lastName": "Duran", + "company": "Kegular", + "employed": true + }, + { + "firstName": "Richards", + "lastName": "Lane", + "company": "Rooforia", + "employed": true + }, + { + "firstName": "Erika", + "lastName": "Whitfield", + "company": "Uniworld", + "employed": true + }, + { + "firstName": "Bridges", + "lastName": "Sloan", + "company": "Acruex", + "employed": true + }, + { + "firstName": "Ford", + "lastName": "Puckett", + "company": "Metroz", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Decker", + "company": "Zillidium", + "employed": true + }, + { + "firstName": "Katharine", + "lastName": "Obrien", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Mckinney", + "lastName": "Kline", + "company": "Maximind", + "employed": true + }, + { + "firstName": "Janis", + "lastName": "Finley", + "company": "Gynk", + "employed": true + }, + { + "firstName": "Richardson", + "lastName": "Larsen", + "company": "Virva", + "employed": true + }, + { + "firstName": "Alexandra", + "lastName": "Prince", + "company": "Unia", + "employed": true + }, + { + "firstName": "Rosanna", + "lastName": "Sargent", + "company": "Zappix", + "employed": false + }, + { + "firstName": "Suarez", + "lastName": "Sullivan", + "company": "Eyeris", + "employed": true + }, + { + "firstName": "Huffman", + "lastName": "Richmond", + "company": "Unq", + "employed": false + }, + { + "firstName": "Montoya", + "lastName": "Gray", + "company": "Amtap", + "employed": false + }, + { + "firstName": "Janie", + "lastName": "Savage", + "company": "Canopoly", + "employed": false + }, + { + "firstName": "Selena", + "lastName": "Gaines", + "company": "Aquoavo", + "employed": false + }, + { + "firstName": "Aida", + "lastName": "Olsen", + "company": "Stockpost", + "employed": false + }, + { + "firstName": "Rosa", + "lastName": "Chambers", + "company": "Medifax", + "employed": false + }, + { + "firstName": "Gertrude", + "lastName": "Dunn", + "company": "Buzzworks", + "employed": false + }, + { + "firstName": "Kay", + "lastName": "Best", + "company": "Cujo", + "employed": true + }, + { + "firstName": "Shanna", + "lastName": "Wilkins", + "company": "Zanity", + "employed": true + }, + { + "firstName": "Cathryn", + "lastName": "Rosales", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Connie", + "lastName": "Russell", + "company": "Supportal", + "employed": true + }, + { + "firstName": "Ofelia", + "lastName": "Cook", + "company": "Petigems", + "employed": false + }, + { + "firstName": "Pierce", + "lastName": "Calhoun", + "company": "Terragen", + "employed": false + }, + { + "firstName": "Bernard", + "lastName": "Phillips", + "company": "Telepark", + "employed": true + }, + { + "firstName": "Ora", + "lastName": "Shields", + "company": "Newcube", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Goff", + "company": "Snips", + "employed": true + }, + { + "firstName": "Adele", + "lastName": "Valdez", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Kari", + "lastName": "Paul", + "company": "Emtrac", + "employed": false + }, + { + "firstName": "Latonya", + "lastName": "Levy", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Diann", + "lastName": "Wells", + "company": "Zoid", + "employed": true + }, + { + "firstName": "Angelia", + "lastName": "Woodard", + "company": "Tourmania", + "employed": true + }, + { + "firstName": "Ruthie", + "lastName": "Dyer", + "company": "Accuprint", + "employed": true + }, + { + "firstName": "Avis", + "lastName": "Mendoza", + "company": "Tellifly", + "employed": false + }, + { + "firstName": "Penny", + "lastName": "Hickman", + "company": "Ceprene", + "employed": true + }, + { + "firstName": "Susanna", + "lastName": "Everett", + "company": "Squish", + "employed": true + }, + { + "firstName": "Marva", + "lastName": "Frost", + "company": "Iplax", + "employed": true + }, + { + "firstName": "Olson", + "lastName": "Coleman", + "company": "Buzzopia", + "employed": false + }, + { + "firstName": "Berta", + "lastName": "Dodson", + "company": "Kangle", + "employed": true + }, + { + "firstName": "Gilliam", + "lastName": "Ray", + "company": "Signity", + "employed": false + }, + { + "firstName": "Mcdowell", + "lastName": "Hansen", + "company": "Exozent", + "employed": false + }, + { + "firstName": "Warren", + "lastName": "Blair", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Noel", + "lastName": "Nichols", + "company": "Kidstock", + "employed": true + }, + { + "firstName": "Vicki", + "lastName": "Brennan", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Sasha", + "lastName": "Price", + "company": "Trasola", + "employed": false + }, + { + "firstName": "Alexandria", + "lastName": "Beasley", + "company": "Solgan", + "employed": false + }, + { + "firstName": "Marcy", + "lastName": "Lloyd", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Natalie", + "lastName": "Delacruz", + "company": "Zoxy", + "employed": true + }, + { + "firstName": "Wilkins", + "lastName": "Branch", + "company": "Papricut", + "employed": false + }, + { + "firstName": "Hollie", + "lastName": "Douglas", + "company": "Viasia", + "employed": false + }, + { + "firstName": "Gay", + "lastName": "Nielsen", + "company": "Architax", + "employed": true + }, + { + "firstName": "Bradley", + "lastName": "Dillon", + "company": "Pyramis", + "employed": false + }, + { + "firstName": "Terrell", + "lastName": "Mccall", + "company": "Verbus", + "employed": true + }, + { + "firstName": "Coleman", + "lastName": "Nunez", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Gail", + "lastName": "Reyes", + "company": "Webiotic", + "employed": false + }, + { + "firstName": "Kate", + "lastName": "Curry", + "company": "Signidyne", + "employed": true + }, + { + "firstName": "Imogene", + "lastName": "Atkinson", + "company": "Vicon", + "employed": true + }, + { + "firstName": "Tamera", + "lastName": "Townsend", + "company": "Qimonk", + "employed": false + }, + { + "firstName": "Leonor", + "lastName": "Beard", + "company": "Imperium", + "employed": true + }, + { + "firstName": "Sykes", + "lastName": "Solomon", + "company": "Cormoran", + "employed": true + }, + { + "firstName": "Waters", + "lastName": "Phelps", + "company": "Cosmetex", + "employed": false + }, + { + "firstName": "Karin", + "lastName": "Wiggins", + "company": "Navir", + "employed": false + }, + { + "firstName": "Jeanie", + "lastName": "Holcomb", + "company": "Bizmatic", + "employed": false + }, + { + "firstName": "Kelley", + "lastName": "Fisher", + "company": "Comtrail", + "employed": false + }, + { + "firstName": "Lopez", + "lastName": "Estes", + "company": "Straloy", + "employed": false + }, + { + "firstName": "Francis", + "lastName": "Bryant", + "company": "Ronbert", + "employed": true + }, + { + "firstName": "Maddox", + "lastName": "Alexander", + "company": "Uncorp", + "employed": true + }, + { + "firstName": "Bray", + "lastName": "Livingston", + "company": "Bullzone", + "employed": false + }, + { + "firstName": "King", + "lastName": "Small", + "company": "Bitrex", + "employed": false + }, + { + "firstName": "Ryan", + "lastName": "Dixon", + "company": "Sultraxin", + "employed": false + }, + { + "firstName": "Lauren", + "lastName": "Roman", + "company": "Golistic", + "employed": true + }, + { + "firstName": "May", + "lastName": "Hill", + "company": "Hometown", + "employed": true + }, + { + "firstName": "Johanna", + "lastName": "Bolton", + "company": "Magnina", + "employed": true + }, + { + "firstName": "Harper", + "lastName": "Burks", + "company": "Anivet", + "employed": true + }, + { + "firstName": "Audra", + "lastName": "Donovan", + "company": "Gonkle", + "employed": false + }, + { + "firstName": "Margret", + "lastName": "Schneider", + "company": "Aquafire", + "employed": false + }, + { + "firstName": "Hartman", + "lastName": "Brooks", + "company": "Rodeocean", + "employed": true + }, + { + "firstName": "Sue", + "lastName": "Craft", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Josefina", + "lastName": "Hubbard", + "company": "Repetwire", + "employed": false + }, + { + "firstName": "Stacie", + "lastName": "Jones", + "company": "Xyqag", + "employed": true + }, + { + "firstName": "Jami", + "lastName": "Robinson", + "company": "Frenex", + "employed": true + }, + { + "firstName": "Joan", + "lastName": "Short", + "company": "Darwinium", + "employed": false + }, + { + "firstName": "Shepard", + "lastName": "Chaney", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Simone", + "lastName": "Hull", + "company": "Kongene", + "employed": false + }, + { + "firstName": "Brandy", + "lastName": "Moreno", + "company": "Accruex", + "employed": true + }, + { + "firstName": "Madge", + "lastName": "Wilkerson", + "company": "Duflex", + "employed": true + }, + { + "firstName": "Annmarie", + "lastName": "Perkins", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Mcpherson", + "lastName": "Oliver", + "company": "Eargo", + "employed": false + }, + { + "firstName": "Joann", + "lastName": "Banks", + "company": "Eyewax", + "employed": true + }, + { + "firstName": "Greene", + "lastName": "Thornton", + "company": "Acium", + "employed": true + }, + { + "firstName": "Marta", + "lastName": "Lowe", + "company": "Comfirm", + "employed": false + }, + { + "firstName": "Amie", + "lastName": "Hahn", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Allison", + "lastName": "Herring", + "company": "Greeker", + "employed": false + }, + { + "firstName": "Tracie", + "lastName": "Stark", + "company": "Cinesanct", + "employed": false + }, + { + "firstName": "Suzanne", + "lastName": "Ruiz", + "company": "Cedward", + "employed": true + }, + { + "firstName": "Perkins", + "lastName": "Gardner", + "company": "Omatom", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Gallegos", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Elena", + "lastName": "Justice", + "company": "Enersave", + "employed": true + }, + { + "firstName": "Lidia", + "lastName": "Burgess", + "company": "Knowlysis", + "employed": true + }, + { + "firstName": "Mable", + "lastName": "Acosta", + "company": "Futuris", + "employed": false + }, + { + "firstName": "Gross", + "lastName": "Long", + "company": "Multiflex", + "employed": true + }, + { + "firstName": "Morales", + "lastName": "Wilder", + "company": "Playce", + "employed": false + }, + { + "firstName": "Raymond", + "lastName": "Britt", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Janine", + "lastName": "Gay", + "company": "Quilm", + "employed": true + }, + { + "firstName": "Vivian", + "lastName": "Guzman", + "company": "Momentia", + "employed": true + }, + { + "firstName": "Holman", + "lastName": "Byers", + "company": "Geekol", + "employed": false + }, + { + "firstName": "Lewis", + "lastName": "Berg", + "company": "Dymi", + "employed": false + }, + { + "firstName": "Herman", + "lastName": "Reeves", + "company": "Zytrac", + "employed": true + }, + { + "firstName": "Henderson", + "lastName": "Howell", + "company": "Krag", + "employed": true + }, + { + "firstName": "Julianne", + "lastName": "Preston", + "company": "Vendblend", + "employed": true + }, + { + "firstName": "Blanche", + "lastName": "Wheeler", + "company": "Zenolux", + "employed": true + }, + { + "firstName": "Ines", + "lastName": "Snider", + "company": "Fitcore", + "employed": false + }, + { + "firstName": "Fran", + "lastName": "Summers", + "company": "Quailcom", + "employed": false + }, + { + "firstName": "Coleen", + "lastName": "Tyson", + "company": "Ecraze", + "employed": true + }, + { + "firstName": "Berger", + "lastName": "Rich", + "company": "Netagy", + "employed": true + }, + { + "firstName": "Barrera", + "lastName": "Michael", + "company": "Nixelt", + "employed": false + }, + { + "firstName": "Marcella", + "lastName": "Nieves", + "company": "Emtrak", + "employed": true + }, + { + "firstName": "Gloria", + "lastName": "Rasmussen", + "company": "Vidto", + "employed": false + }, + { + "firstName": "Eileen", + "lastName": "Battle", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Rosario", + "lastName": "Hays", + "company": "Enerforce", + "employed": true + }, + { + "firstName": "Angeline", + "lastName": "Kane", + "company": "Quantalia", + "employed": false + }, + { + "firstName": "Weiss", + "lastName": "Durham", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Prince", + "lastName": "Forbes", + "company": "Entroflex", + "employed": true + }, + { + "firstName": "Wooten", + "lastName": "Adkins", + "company": "Extremo", + "employed": false + }, + { + "firstName": "Garcia", + "lastName": "Larson", + "company": "Eventage", + "employed": true + }, + { + "firstName": "Christie", + "lastName": "Sheppard", + "company": "Buzzmaker", + "employed": false + }, + { + "firstName": "Bobbie", + "lastName": "Kim", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Hewitt", + "lastName": "Nicholson", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Bertha", + "lastName": "Burnett", + "company": "Portaline", + "employed": false + }, + { + "firstName": "Leta", + "lastName": "Vaughan", + "company": "Cowtown", + "employed": true + }, + { + "firstName": "Leanna", + "lastName": "Thomas", + "company": "Organica", + "employed": true + }, + { + "firstName": "Stevenson", + "lastName": "Allen", + "company": "Netplode", + "employed": true + }, + { + "firstName": "Melissa", + "lastName": "Bowman", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Bethany", + "lastName": "Bauer", + "company": "Brainclip", + "employed": true + }, + { + "firstName": "Manning", + "lastName": "Dominguez", + "company": "Hydrocom", + "employed": false + }, + { + "firstName": "Rebecca", + "lastName": "Stevenson", + "company": "Xsports", + "employed": true + }, + { + "firstName": "Dollie", + "lastName": "Mccray", + "company": "Sybixtex", + "employed": false + }, + { + "firstName": "Rachael", + "lastName": "Abbott", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Gibbs", + "company": "Nurali", + "employed": true + }, + { + "firstName": "Christy", + "lastName": "Barlow", + "company": "Medesign", + "employed": false + }, + { + "firstName": "Bowman", + "lastName": "Farrell", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Diana", + "lastName": "Cardenas", + "company": "Providco", + "employed": false + }, + { + "firstName": "Levy", + "lastName": "Goodwin", + "company": "Bezal", + "employed": true + }, + { + "firstName": "Lorrie", + "lastName": "Horne", + "company": "Valpreal", + "employed": true + }, + { + "firstName": "Cochran", + "lastName": "Barnett", + "company": "Portica", + "employed": false + }, + { + "firstName": "Holt", + "lastName": "Green", + "company": "Entogrok", + "employed": true + }, + { + "firstName": "Simon", + "lastName": "Anderson", + "company": "Scenty", + "employed": false + }, + { + "firstName": "Fernandez", + "lastName": "Baxter", + "company": "Puria", + "employed": true + }, + { + "firstName": "Reynolds", + "lastName": "Powell", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Little", + "lastName": "Baldwin", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Rosalyn", + "lastName": "Holt", + "company": "Skyplex", + "employed": false + }, + { + "firstName": "Garrison", + "lastName": "Daniels", + "company": "Vantage", + "employed": true + }, + { + "firstName": "Wiley", + "lastName": "Beach", + "company": "Sonique", + "employed": false + }, + { + "firstName": "Hicks", + "lastName": "Knowles", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Wheeler", + "lastName": "Marquez", + "company": "Bicol", + "employed": false + }, + { + "firstName": "Gregory", + "lastName": "Carr", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Doyle", + "lastName": "Trevino", + "company": "Techade", + "employed": false + }, + { + "firstName": "Janell", + "lastName": "Garrison", + "company": "Viagrand", + "employed": false + }, + { + "firstName": "Ray", + "lastName": "Wolf", + "company": "Farmage", + "employed": false + }, + { + "firstName": "Baldwin", + "lastName": "Francis", + "company": "Suremax", + "employed": true + }, + { + "firstName": "Long", + "lastName": "Harrison", + "company": "Dogtown", + "employed": true + }, + { + "firstName": "Socorro", + "lastName": "Lynch", + "company": "Isodrive", + "employed": true + }, + { + "firstName": "Marsha", + "lastName": "Hartman", + "company": "Assistia", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Gill", + "company": "Magnemo", + "employed": false + }, + { + "firstName": "Barnett", + "lastName": "Young", + "company": "Volax", + "employed": true + }, + { + "firstName": "Higgins", + "lastName": "Buchanan", + "company": "Interfind", + "employed": false + }, + { + "firstName": "Leigh", + "lastName": "Rush", + "company": "Veraq", + "employed": true + }, + { + "firstName": "Sosa", + "lastName": "Sweet", + "company": "Realmo", + "employed": false + }, + { + "firstName": "Copeland", + "lastName": "Jackson", + "company": "Zilodyne", + "employed": true + }, + { + "firstName": "Nolan", + "lastName": "Morton", + "company": "Izzby", + "employed": true + }, + { + "firstName": "Tamra", + "lastName": "Mccullough", + "company": "Ersum", + "employed": true + }, + { + "firstName": "Welch", + "lastName": "Bell", + "company": "Amril", + "employed": true + }, + { + "firstName": "Rochelle", + "lastName": "Witt", + "company": "Avit", + "employed": false + }, + { + "firstName": "Burks", + "lastName": "Navarro", + "company": "Splinx", + "employed": false + }, + { + "firstName": "Jasmine", + "lastName": "Espinoza", + "company": "Koffee", + "employed": true + }, + { + "firstName": "Hester", + "lastName": "Hess", + "company": "Isoplex", + "employed": true + }, + { + "firstName": "Rodriguez", + "lastName": "Monroe", + "company": "Melbacor", + "employed": false + }, + { + "firstName": "Blackwell", + "lastName": "Foreman", + "company": "Bedlam", + "employed": false + }, + { + "firstName": "Ashley", + "lastName": "Huff", + "company": "Oulu", + "employed": true + }, + { + "firstName": "Erna", + "lastName": "Morgan", + "company": "Retrack", + "employed": true + }, + { + "firstName": "Rachelle", + "lastName": "Moses", + "company": "Austech", + "employed": true + }, + { + "firstName": "Lynda", + "lastName": "Cruz", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Stephens", + "lastName": "Farley", + "company": "Qot", + "employed": false + }, + { + "firstName": "Evans", + "lastName": "Stanton", + "company": "Biotica", + "employed": false + }, + { + "firstName": "Petty", + "lastName": "Fuller", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Latasha", + "lastName": "Hurst", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Concepcion", + "lastName": "Bennett", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Stout", + "lastName": "Chavez", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Dianne", + "lastName": "Cain", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Mcdonald", + "lastName": "Ballard", + "company": "Bluegrain", + "employed": true + }, + { + "firstName": "Samantha", + "lastName": "Johnson", + "company": "Comtract", + "employed": true + }, + { + "firstName": "Dale", + "lastName": "Osborn", + "company": "Imant", + "employed": false + }, + { + "firstName": "Juliette", + "lastName": "Mejia", + "company": "Zenthall", + "employed": true + }, + { + "firstName": "Watts", + "lastName": "Carpenter", + "company": "Inventure", + "employed": false + }, + { + "firstName": "Wilkerson", + "lastName": "Howard", + "company": "Enervate", + "employed": false + }, + { + "firstName": "Clements", + "lastName": "Cleveland", + "company": "Strozen", + "employed": true + }, + { + "firstName": "Mckenzie", + "lastName": "Wooten", + "company": "Cytrex", + "employed": false + }, + { + "firstName": "Boyle", + "lastName": "Mayo", + "company": "Realysis", + "employed": true + }, + { + "firstName": "Margarita", + "lastName": "Ramsey", + "company": "Comvene", + "employed": true + }, + { + "firstName": "Rush", + "lastName": "Joyce", + "company": "Menbrain", + "employed": false + }, + { + "firstName": "Terrie", + "lastName": "Mcfarland", + "company": "Lingoage", + "employed": false + }, + { + "firstName": "Dickson", + "lastName": "Mccarty", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Earlene", + "lastName": "Randall", + "company": "Nitracyr", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Hurley", + "company": "Genmex", + "employed": true + }, + { + "firstName": "Foster", + "lastName": "Moss", + "company": "Radiantix", + "employed": false + }, + { + "firstName": "Janice", + "lastName": "Haley", + "company": "Uxmox", + "employed": false + }, + { + "firstName": "Alyce", + "lastName": "Burris", + "company": "Andryx", + "employed": false + }, + { + "firstName": "Drake", + "lastName": "Robbins", + "company": "Eschoir", + "employed": true + }, + { + "firstName": "Misty", + "lastName": "Franks", + "company": "Plasmosis", + "employed": false + }, + { + "firstName": "Nelda", + "lastName": "Pace", + "company": "Anixang", + "employed": true + }, + { + "firstName": "Myers", + "lastName": "Quinn", + "company": "Cemention", + "employed": true + }, + { + "firstName": "Inez", + "lastName": "Koch", + "company": "Junipoor", + "employed": true + }, + { + "firstName": "Underwood", + "lastName": "Kelley", + "company": "Zanilla", + "employed": false + }, + { + "firstName": "Rich", + "lastName": "Leblanc", + "company": "Kiosk", + "employed": false + }, + { + "firstName": "Irene", + "lastName": "Velasquez", + "company": "Prosely", + "employed": true + }, + { + "firstName": "Reeves", + "lastName": "Salinas", + "company": "Xerex", + "employed": true + }, + { + "firstName": "Denise", + "lastName": "Chandler", + "company": "Orbalix", + "employed": false + }, + { + "firstName": "Peterson", + "lastName": "Blanchard", + "company": "Eclipsent", + "employed": false + }, + { + "firstName": "Melody", + "lastName": "Walters", + "company": "Ebidco", + "employed": false + }, + { + "firstName": "Darcy", + "lastName": "Underwood", + "company": "Netplax", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Cooke", + "company": "Comdom", + "employed": true + }, + { + "firstName": "Hodges", + "lastName": "Padilla", + "company": "Strezzo", + "employed": false + }, + { + "firstName": "Morton", + "lastName": "Rowland", + "company": "Idetica", + "employed": false + }, + { + "firstName": "French", + "lastName": "Lambert", + "company": "Brainquil", + "employed": false + }, + { + "firstName": "Blanca", + "lastName": "Finch", + "company": "Gushkool", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Shepard", + "company": "Honotron", + "employed": false + }, + { + "firstName": "Powell", + "lastName": "Jarvis", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Madeline", + "lastName": "Hunt", + "company": "Ecolight", + "employed": false + }, + { + "firstName": "Hinton", + "lastName": "Tillman", + "company": "Phuel", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Fernandez", + "company": "Gogol", + "employed": false + }, + { + "firstName": "Vazquez", + "lastName": "Levine", + "company": "Talkola", + "employed": false + }, + { + "firstName": "Stafford", + "lastName": "Malone", + "company": "Makingway", + "employed": false + }, + { + "firstName": "Harriet", + "lastName": "Peterson", + "company": "Blurrybus", + "employed": true + }, + { + "firstName": "Jefferson", + "lastName": "Elliott", + "company": "Insuresys", + "employed": true + }, + { + "firstName": "Holden", + "lastName": "Macias", + "company": "Dognost", + "employed": false + }, + { + "firstName": "Jocelyn", + "lastName": "Bridges", + "company": "Gleamink", + "employed": true + }, + { + "firstName": "Acosta", + "lastName": "Mays", + "company": "Qnekt", + "employed": false + }, + { + "firstName": "Cathy", + "lastName": "Oconnor", + "company": "Xumonk", + "employed": true + }, + { + "firstName": "Rhoda", + "lastName": "Duke", + "company": "Orbiflex", + "employed": true + }, + { + "firstName": "Lacey", + "lastName": "Bender", + "company": "Waab", + "employed": true + }, + { + "firstName": "Felicia", + "lastName": "Owens", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Gwen", + "lastName": "Miller", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Sabrina", + "lastName": "Moore", + "company": "Extro", + "employed": false + }, + { + "firstName": "Yvonne", + "lastName": "Mitchell", + "company": "Deviltoe", + "employed": false + }, + { + "firstName": "Vickie", + "lastName": "Orr", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Gena", + "lastName": "Brock", + "company": "Softmicro", + "employed": false + }, + { + "firstName": "Dorothy", + "lastName": "Ferguson", + "company": "Amtas", + "employed": false + }, + { + "firstName": "Mollie", + "lastName": "Grant", + "company": "Billmed", + "employed": false + }, + { + "firstName": "Stone", + "lastName": "Nolan", + "company": "Sealoud", + "employed": true + }, + { + "firstName": "Acevedo", + "lastName": "Boyle", + "company": "Uni", + "employed": true + }, + { + "firstName": "Ward", + "lastName": "Parsons", + "company": "Exovent", + "employed": false + }, + { + "firstName": "Munoz", + "lastName": "Armstrong", + "company": "Isbol", + "employed": true + }, + { + "firstName": "Leslie", + "lastName": "Medina", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Navarro", + "lastName": "Benton", + "company": "Avenetro", + "employed": true + }, + { + "firstName": "Sears", + "lastName": "Pacheco", + "company": "Exosis", + "employed": false + }, + { + "firstName": "Marissa", + "lastName": "Cunningham", + "company": "Bostonic", + "employed": false + }, + { + "firstName": "Brown", + "lastName": "Klein", + "company": "Mediot", + "employed": true + }, + { + "firstName": "Mills", + "lastName": "Palmer", + "company": "Sarasonic", + "employed": true + }, + { + "firstName": "Stephenson", + "lastName": "Valentine", + "company": "Automon", + "employed": false + }, + { + "firstName": "Baird", + "lastName": "Juarez", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Tracey", + "lastName": "Nash", + "company": "Genmy", + "employed": false + }, + { + "firstName": "Christa", + "lastName": "Peck", + "company": "Mantro", + "employed": false + }, + { + "firstName": "Leila", + "lastName": "Hester", + "company": "Optique", + "employed": false + }, + { + "firstName": "Kathrine", + "lastName": "Sweeney", + "company": "Sequitur", + "employed": false + }, + { + "firstName": "Cherry", + "lastName": "Charles", + "company": "Obliq", + "employed": false + }, + { + "firstName": "Eaton", + "lastName": "Hayes", + "company": "Musanpoly", + "employed": true + }, + { + "firstName": "Ginger", + "lastName": "Gilliam", + "company": "Concility", + "employed": true + }, + { + "firstName": "Harding", + "lastName": "William", + "company": "Elentrix", + "employed": false + }, + { + "firstName": "Rodriquez", + "lastName": "Dalton", + "company": "Exoswitch", + "employed": false + }, + { + "firstName": "Rita", + "lastName": "Carrillo", + "company": "Gazak", + "employed": true + }, + { + "firstName": "Florine", + "lastName": "Brewer", + "company": "Rubadub", + "employed": false + }, + { + "firstName": "Claudia", + "lastName": "Patrick", + "company": "Zillanet", + "employed": false + }, + { + "firstName": "Chavez", + "lastName": "Mckay", + "company": "Confrenzy", + "employed": false + }, + { + "firstName": "Kenya", + "lastName": "Clements", + "company": "Endipine", + "employed": true + }, + { + "firstName": "Gonzales", + "lastName": "Stevens", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Stokes", + "lastName": "White", + "company": "Xelegyl", + "employed": true + }, + { + "firstName": "Therese", + "lastName": "Stuart", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Jamie", + "lastName": "Sawyer", + "company": "Mitroc", + "employed": false + }, + { + "firstName": "Briana", + "lastName": "Kirk", + "company": "Bitendrex", + "employed": false + }, + { + "firstName": "Mullen", + "lastName": "Freeman", + "company": "Hotcakes", + "employed": false + }, + { + "firstName": "Dean", + "lastName": "Weeks", + "company": "Exoblue", + "employed": false + }, + { + "firstName": "Jo", + "lastName": "Aguilar", + "company": "Geekmosis", + "employed": true + }, + { + "firstName": "Barr", + "lastName": "Bryan", + "company": "Conjurica", + "employed": true + }, + { + "firstName": "Leon", + "lastName": "Wagner", + "company": "Lyria", + "employed": false + }, + { + "firstName": "Benson", + "lastName": "Cannon", + "company": "Nspire", + "employed": false + }, + { + "firstName": "Mays", + "lastName": "Watson", + "company": "Cogentry", + "employed": false + }, + { + "firstName": "Parsons", + "lastName": "Burke", + "company": "Isologia", + "employed": true + }, + { + "firstName": "Mcintyre", + "lastName": "Mcintyre", + "company": "Satiance", + "employed": false + }, + { + "firstName": "Lynch", + "lastName": "Santiago", + "company": "Daido", + "employed": false + }, + { + "firstName": "Clarke", + "lastName": "Lara", + "company": "Kozgene", + "employed": true + }, + { + "firstName": "Janna", + "lastName": "Byrd", + "company": "Arctiq", + "employed": false + }, + { + "firstName": "June", + "lastName": "Lamb", + "company": "Frolix", + "employed": false + }, + { + "firstName": "Corine", + "lastName": "Foster", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Cleveland", + "lastName": "Frazier", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Burris", + "lastName": "Marshall", + "company": "Marketoid", + "employed": true + }, + { + "firstName": "Corina", + "lastName": "Johnston", + "company": "Entality", + "employed": true + }, + { + "firstName": "Alston", + "lastName": "Eaton", + "company": "Cipromox", + "employed": false + }, + { + "firstName": "Clark", + "lastName": "Wilkinson", + "company": "Koogle", + "employed": true + }, + { + "firstName": "Lowe", + "lastName": "Harper", + "company": "Bolax", + "employed": true + }, + { + "firstName": "Mallory", + "lastName": "Ramirez", + "company": "Lumbrex", + "employed": true + }, + { + "firstName": "Alissa", + "lastName": "Mcfadden", + "company": "Comtours", + "employed": true + }, + { + "firstName": "Zamora", + "lastName": "Berry", + "company": "Extrawear", + "employed": false + }, + { + "firstName": "Polly", + "lastName": "Mendez", + "company": "Zillan", + "employed": false + }, + { + "firstName": "Joyner", + "lastName": "Gomez", + "company": "Gracker", + "employed": false + }, + { + "firstName": "Dionne", + "lastName": "Simmons", + "company": "Genesynk", + "employed": false + }, + { + "firstName": "Alta", + "lastName": "Saunders", + "company": "Gadtron", + "employed": false + }, + { + "firstName": "Heidi", + "lastName": "Alvarado", + "company": "Cubicide", + "employed": true + }, + { + "firstName": "Mayo", + "lastName": "Hyde", + "company": "Dreamia", + "employed": false + }, + { + "firstName": "Burt", + "lastName": "Blevins", + "company": "Quility", + "employed": true + }, + { + "firstName": "Mccoy", + "lastName": "Dawson", + "company": "Enaut", + "employed": true + }, + { + "firstName": "Dennis", + "lastName": "Holmes", + "company": "Bedder", + "employed": true + }, + { + "firstName": "Neal", + "lastName": "Herman", + "company": "Visalia", + "employed": true + }, + { + "firstName": "Ellen", + "lastName": "Bernard", + "company": "Zoinage", + "employed": false + }, + { + "firstName": "Nora", + "lastName": "Powers", + "company": "Ezent", + "employed": false + }, + { + "firstName": "Deidre", + "lastName": "Dennis", + "company": "Nebulean", + "employed": true + }, + { + "firstName": "Saunders", + "lastName": "Mueller", + "company": "Kiggle", + "employed": false + }, + { + "firstName": "Mccullough", + "lastName": "Yang", + "company": "Euron", + "employed": true + }, + { + "firstName": "Nanette", + "lastName": "Waters", + "company": "Qiao", + "employed": true + }, + { + "firstName": "Jane", + "lastName": "Ward", + "company": "Pushcart", + "employed": true + }, + { + "firstName": "Johnston", + "lastName": "Roth", + "company": "Diginetic", + "employed": false + }, + { + "firstName": "Bonner", + "lastName": "Dorsey", + "company": "Peticular", + "employed": true + }, + { + "firstName": "Griffin", + "lastName": "Robles", + "company": "Ultrasure", + "employed": false + }, + { + "firstName": "Clare", + "lastName": "Frederick", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Conway", + "lastName": "Morrison", + "company": "Proxsoft", + "employed": false + }, + { + "firstName": "Hanson", + "lastName": "Oneal", + "company": "Steelfab", + "employed": false + }, + { + "firstName": "Cunningham", + "lastName": "Wong", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Spears", + "lastName": "Campos", + "company": "Skybold", + "employed": false + }, + { + "firstName": "Benita", + "lastName": "Greer", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Dyer", + "lastName": "Morse", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Phyllis", + "lastName": "Glass", + "company": "Voratak", + "employed": false + }, + { + "firstName": "Daisy", + "lastName": "Kirkland", + "company": "Slofast", + "employed": false + }, + { + "firstName": "Candy", + "lastName": "Meyers", + "company": "Qaboos", + "employed": false + }, + { + "firstName": "Valdez", + "lastName": "Mcneil", + "company": "Rodemco", + "employed": false + }, + { + "firstName": "Mueller", + "lastName": "Bailey", + "company": "Exposa", + "employed": true + }, + { + "firstName": "Jeanne", + "lastName": "Rodriquez", + "company": "Essensia", + "employed": false + }, + { + "firstName": "Patterson", + "lastName": "George", + "company": "Zilch", + "employed": false + }, + { + "firstName": "Warner", + "lastName": "Hale", + "company": "Cinaster", + "employed": false + }, + { + "firstName": "Mcguire", + "lastName": "Mccormick", + "company": "Isotrack", + "employed": false + }, + { + "firstName": "Reid", + "lastName": "Mcpherson", + "company": "Shadease", + "employed": true + }, + { + "firstName": "Golden", + "lastName": "Donaldson", + "company": "Combogene", + "employed": true + }, + { + "firstName": "Melanie", + "lastName": "Ford", + "company": "Evidends", + "employed": false + }, + { + "firstName": "Shaffer", + "lastName": "Stein", + "company": "Callflex", + "employed": false + }, + { + "firstName": "Tiffany", + "lastName": "Ross", + "company": "Tasmania", + "employed": true + }, + { + "firstName": "Nichole", + "lastName": "Mckenzie", + "company": "Cytrak", + "employed": false + }, + { + "firstName": "Flossie", + "lastName": "Dickerson", + "company": "Myopium", + "employed": false + }, + { + "firstName": "Beverly", + "lastName": "Petersen", + "company": "Plexia", + "employed": false + }, + { + "firstName": "Shawna", + "lastName": "Alston", + "company": "Xplor", + "employed": false + }, + { + "firstName": "Norma", + "lastName": "King", + "company": "Imkan", + "employed": false + }, + { + "firstName": "Beryl", + "lastName": "Hardy", + "company": "Talae", + "employed": false + }, + { + "firstName": "Renee", + "lastName": "Terry", + "company": "Tubesys", + "employed": true + }, + { + "firstName": "Jana", + "lastName": "Delaney", + "company": "Zillar", + "employed": true + }, + { + "firstName": "Wyatt", + "lastName": "Shelton", + "company": "Ecstasia", + "employed": true + }, + { + "firstName": "Annette", + "lastName": "Robertson", + "company": "Gluid", + "employed": true + }, + { + "firstName": "Paul", + "lastName": "Harris", + "company": "Exodoc", + "employed": false + }, + { + "firstName": "Louise", + "lastName": "Bass", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Mary", + "lastName": "Collier", + "company": "Digirang", + "employed": false + }, + { + "firstName": "Frank", + "lastName": "Fleming", + "company": "Permadyne", + "employed": false + }, + { + "firstName": "Elinor", + "lastName": "Whitaker", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Elisabeth", + "lastName": "Combs", + "company": "Slambda", + "employed": false + }, + { + "firstName": "Jeannette", + "lastName": "Vang", + "company": "Exospace", + "employed": true + }, + { + "firstName": "Katie", + "lastName": "Reynolds", + "company": "Everest", + "employed": true + }, + { + "firstName": "Jillian", + "lastName": "Coffey", + "company": "Digial", + "employed": false + }, + { + "firstName": "Britt", + "lastName": "Myers", + "company": "Idealis", + "employed": true + }, + { + "firstName": "Kaufman", + "lastName": "Browning", + "company": "Exoplode", + "employed": false + }, + { + "firstName": "Celeste", + "lastName": "Pope", + "company": "Ziggles", + "employed": false + }, + { + "firstName": "Dena", + "lastName": "Fulton", + "company": "Senmao", + "employed": false + }, + { + "firstName": "Guadalupe", + "lastName": "Luna", + "company": "Eternis", + "employed": false + }, + { + "firstName": "Rhea", + "lastName": "Whitehead", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Whitfield", + "lastName": "Cabrera", + "company": "Kidgrease", + "employed": false + }, + { + "firstName": "Larson", + "lastName": "Wilcox", + "company": "Eweville", + "employed": false + }, + { + "firstName": "Ramona", + "lastName": "Wallace", + "company": "Accel", + "employed": true + }, + { + "firstName": "Valeria", + "lastName": "Rios", + "company": "Collaire", + "employed": true + }, + { + "firstName": "Dickerson", + "lastName": "Scott", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Soto", + "lastName": "Lindsay", + "company": "Norsul", + "employed": true + }, + { + "firstName": "Watson", + "lastName": "Brown", + "company": "Micronaut", + "employed": false + }, + { + "firstName": "Juana", + "lastName": "Hopper", + "company": "Flumbo", + "employed": true + }, + { + "firstName": "Caldwell", + "lastName": "Melendez", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Heath", + "company": "Zytrex", + "employed": true + }, + { + "firstName": "Lynne", + "lastName": "Gates", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Kim", + "lastName": "Logan", + "company": "Steeltab", + "employed": true + }, + { + "firstName": "Carroll", + "lastName": "Tucker", + "company": "Circum", + "employed": true + }, + { + "firstName": "Pruitt", + "lastName": "Bonner", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Chris", + "lastName": "Davenport", + "company": "Maroptic", + "employed": true + }, + { + "firstName": "Branch", + "lastName": "Glenn", + "company": "Polaria", + "employed": true + }, + { + "firstName": "Millicent", + "lastName": "Wolfe", + "company": "Equitax", + "employed": true + }, + { + "firstName": "Wilkinson", + "lastName": "Lowery", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Dunn", + "lastName": "Schultz", + "company": "Edecine", + "employed": true + }, + { + "firstName": "Morse", + "lastName": "Church", + "company": "Entropix", + "employed": true + }, + { + "firstName": "Shelia", + "lastName": "Gilmore", + "company": "Fortean", + "employed": true + }, + { + "firstName": "Bridgett", + "lastName": "Emerson", + "company": "Speedbolt", + "employed": false + }, + { + "firstName": "Bates", + "lastName": "Cummings", + "company": "Techmania", + "employed": false + }, + { + "firstName": "Avila", + "lastName": "Pruitt", + "company": "Terrago", + "employed": false + }, + { + "firstName": "Angela", + "lastName": "Fuentes", + "company": "Comcur", + "employed": false + }, + { + "firstName": "Lawanda", + "lastName": "Caldwell", + "company": "Malathion", + "employed": false + }, + { + "firstName": "Rosella", + "lastName": "Holloway", + "company": "Rodeology", + "employed": true + }, + { + "firstName": "Burke", + "lastName": "Cox", + "company": "Exoteric", + "employed": true + }, + { + "firstName": "Snow", + "lastName": "Reilly", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Frances", + "lastName": "Mcguire", + "company": "Netur", + "employed": false + }, + { + "firstName": "Coffey", + "lastName": "Morales", + "company": "Baluba", + "employed": false + }, + { + "firstName": "Hooper", + "lastName": "Stephens", + "company": "Furnitech", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Gibson", + "company": "Fleetmix", + "employed": true + }, + { + "firstName": "Howard", + "lastName": "Thompson", + "company": "Fossiel", + "employed": true + }, + { + "firstName": "Oneil", + "lastName": "Villarreal", + "company": "Olympix", + "employed": true + }, + { + "firstName": "Harrison", + "lastName": "Barton", + "company": "Recognia", + "employed": false + }, + { + "firstName": "Keisha", + "lastName": "Weaver", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Tucker", + "lastName": "Pearson", + "company": "Vetron", + "employed": false + }, + { + "firstName": "Wallace", + "lastName": "Schwartz", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Mack", + "lastName": "Humphrey", + "company": "Furnafix", + "employed": true + }, + { + "firstName": "Robyn", + "lastName": "Zimmerman", + "company": "Miracula", + "employed": false + }, + { + "firstName": "Kelli", + "lastName": "Cantu", + "company": "Coash", + "employed": false + }, + { + "firstName": "Langley", + "lastName": "Sears", + "company": "Plasto", + "employed": false + }, + { + "firstName": "Elaine", + "lastName": "Mcconnell", + "company": "Xth", + "employed": false + }, + { + "firstName": "Odom", + "lastName": "Mckee", + "company": "Earthpure", + "employed": true + }, + { + "firstName": "Maryellen", + "lastName": "Pollard", + "company": "Zizzle", + "employed": true + }, + { + "firstName": "Slater", + "lastName": "Morrow", + "company": "Yogasm", + "employed": false + }, + { + "firstName": "Guzman", + "lastName": "Ashley", + "company": "Twiist", + "employed": true + }, + { + "firstName": "Elise", + "lastName": "Perry", + "company": "Pharmex", + "employed": true + }, + { + "firstName": "Mccormick", + "lastName": "Suarez", + "company": "Naxdis", + "employed": true + }, + { + "firstName": "Mercado", + "lastName": "Ellis", + "company": "Quilch", + "employed": true + }, + { + "firstName": "Luella", + "lastName": "Riggs", + "company": "Isopop", + "employed": false + }, + { + "firstName": "Maryanne", + "lastName": "Turner", + "company": "Kongle", + "employed": true + }, + { + "firstName": "Estela", + "lastName": "Hernandez", + "company": "Cyclonica", + "employed": false + }, + { + "firstName": "Joni", + "lastName": "Sherman", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Claudine", + "lastName": "Mathews", + "company": "Rotodyne", + "employed": false + }, + { + "firstName": "Gayle", + "lastName": "Lawrence", + "company": "Earthwax", + "employed": false + }, + { + "firstName": "Becky", + "lastName": "Blake", + "company": "Zilladyne", + "employed": false + }, + { + "firstName": "David", + "lastName": "Mcgowan", + "company": "Indexia", + "employed": false + }, + { + "firstName": "Livingston", + "lastName": "Rodriguez", + "company": "Colaire", + "employed": true + }, + { + "firstName": "Williamson", + "lastName": "Giles", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Burch", + "lastName": "Rojas", + "company": "Centice", + "employed": false + }, + { + "firstName": "Carolyn", + "lastName": "Hall", + "company": "Plutorque", + "employed": true + }, + { + "firstName": "Garrett", + "lastName": "Kaufman", + "company": "Utarian", + "employed": false + }, + { + "firstName": "Johnnie", + "lastName": "Vaughn", + "company": "Netropic", + "employed": false + }, + { + "firstName": "Clara", + "lastName": "Mcdowell", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Willie", + "lastName": "Hudson", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Humphrey", + "lastName": "Erickson", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Augusta", + "lastName": "Wood", + "company": "Netbook", + "employed": true + }, + { + "firstName": "Mara", + "lastName": "Patton", + "company": "Acrodance", + "employed": false + }, + { + "firstName": "Nell", + "lastName": "Jacobs", + "company": "Medmex", + "employed": false + }, + { + "firstName": "Wood", + "lastName": "Hutchinson", + "company": "Zensor", + "employed": true + }, + { + "firstName": "Maria", + "lastName": "Calderon", + "company": "Goko", + "employed": false + }, + { + "firstName": "Byrd", + "lastName": "Mills", + "company": "Electonic", + "employed": false + }, + { + "firstName": "Georgia", + "lastName": "Rodgers", + "company": "Comtent", + "employed": false + }, + { + "firstName": "Graciela", + "lastName": "Camacho", + "company": "Orbaxter", + "employed": true + }, + { + "firstName": "Belinda", + "lastName": "Jimenez", + "company": "Mobildata", + "employed": true + }, + { + "firstName": "Sanders", + "lastName": "Ball", + "company": "Frosnex", + "employed": false + }, + { + "firstName": "Hernandez", + "lastName": "Kennedy", + "company": "Tubalum", + "employed": false + }, + { + "firstName": "Robert", + "lastName": "Mccoy", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Sophia", + "lastName": "Torres", + "company": "Ultrimax", + "employed": true + }, + { + "firstName": "Collins", + "lastName": "Hinton", + "company": "Sultrax", + "employed": false + }, + { + "firstName": "Garza", + "lastName": "Newton", + "company": "Polarium", + "employed": false + }, + { + "firstName": "Shari", + "lastName": "Neal", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Webb", + "lastName": "Bates", + "company": "Equicom", + "employed": false + }, + { + "firstName": "Petra", + "lastName": "Norris", + "company": "Rameon", + "employed": false + }, + { + "firstName": "Rebekah", + "lastName": "Blackburn", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Haynes", + "lastName": "Foley", + "company": "Zanymax", + "employed": true + }, + { + "firstName": "Duffy", + "lastName": "Stewart", + "company": "Genekom", + "employed": true + }, + { + "firstName": "Collier", + "lastName": "Estrada", + "company": "Futurity", + "employed": true + }, + { + "firstName": "Bradshaw", + "lastName": "Bradshaw", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Hines", + "lastName": "Baker", + "company": "Macronaut", + "employed": false + }, + { + "firstName": "Carmella", + "lastName": "Mercado", + "company": "Ecratic", + "employed": true + }, + { + "firstName": "Lucia", + "lastName": "Delgado", + "company": "Ontality", + "employed": true + }, + { + "firstName": "Millie", + "lastName": "Stafford", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Ola", + "lastName": "Whitley", + "company": "Omnigog", + "employed": true + }, + { + "firstName": "Alana", + "lastName": "Oneil", + "company": "Nikuda", + "employed": true + }, + { + "firstName": "Georgina", + "lastName": "Mullen", + "company": "Qualitern", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Pitts", + "company": "Medicroix", + "employed": true + }, + { + "firstName": "Woods", + "lastName": "Montgomery", + "company": "Nutralab", + "employed": true + }, + { + "firstName": "Schroeder", + "lastName": "Bowers", + "company": "Mondicil", + "employed": false + }, + { + "firstName": "Margery", + "lastName": "Sosa", + "company": "Digique", + "employed": false + }, + { + "firstName": "Chandra", + "lastName": "Mclaughlin", + "company": "Obones", + "employed": true + }, + { + "firstName": "Erma", + "lastName": "Walter", + "company": "Zentry", + "employed": true + }, + { + "firstName": "Cohen", + "lastName": "Wise", + "company": "Kaggle", + "employed": true + }, + { + "firstName": "Jewell", + "lastName": "Porter", + "company": "Quilk", + "employed": true + }, + { + "firstName": "Nannie", + "lastName": "Vargas", + "company": "Quarmony", + "employed": true + }, + { + "firstName": "Kris", + "lastName": "Crosby", + "company": "Chillium", + "employed": false + }, + { + "firstName": "Lila", + "lastName": "Kramer", + "company": "Typhonica", + "employed": true + }, + { + "firstName": "Ethel", + "lastName": "Davis", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Norris", + "lastName": "Holman", + "company": "Sustenza", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Mcmahon", + "company": "Lunchpad", + "employed": false + }, + { + "firstName": "Wiggins", + "lastName": "Day", + "company": "Zosis", + "employed": true + }, + { + "firstName": "Davis", + "lastName": "Vasquez", + "company": "Verton", + "employed": true + }, + { + "firstName": "Barron", + "lastName": "Gould", + "company": "Aquamate", + "employed": false + }, + { + "firstName": "Shelly", + "lastName": "Gillespie", + "company": "Jamnation", + "employed": true + }, + { + "firstName": "Mathis", + "lastName": "Castaneda", + "company": "Zedalis", + "employed": true + }, + { + "firstName": "Black", + "lastName": "Dotson", + "company": "Zillatide", + "employed": true + }, + { + "firstName": "Elba", + "lastName": "Welch", + "company": "Tsunamia", + "employed": true + }, + { + "firstName": "Jones", + "lastName": "Solis", + "company": "Kraggle", + "employed": true + }, + { + "firstName": "Russell", + "lastName": "Carlson", + "company": "Idego", + "employed": false + }, + { + "firstName": "Petersen", + "lastName": "Golden", + "company": "Sloganaut", + "employed": false + }, + { + "firstName": "Ruth", + "lastName": "Rivas", + "company": "Twiggery", + "employed": false + }, + { + "firstName": "Anna", + "lastName": "Garner", + "company": "Utara", + "employed": true + }, + { + "firstName": "Holloway", + "lastName": "Todd", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Santiago", + "lastName": "Mckinney", + "company": "Geoforma", + "employed": false + }, + { + "firstName": "Tamara", + "lastName": "Conway", + "company": "Hivedom", + "employed": true + }, + { + "firstName": "Owens", + "lastName": "Riley", + "company": "Songlines", + "employed": false + }, + { + "firstName": "Carter", + "lastName": "Wade", + "company": "Maineland", + "employed": false + }, + { + "firstName": "Perez", + "lastName": "Roberts", + "company": "Isosphere", + "employed": false + }, + { + "firstName": "Garner", + "lastName": "Floyd", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Witt", + "lastName": "Webster", + "company": "Ronelon", + "employed": false + }, + { + "firstName": "Burton", + "lastName": "Cobb", + "company": "Letpro", + "employed": false + }, + { + "firstName": "Rachel", + "lastName": "Briggs", + "company": "Quizka", + "employed": false + }, + { + "firstName": "Martin", + "lastName": "Griffith", + "company": "Chorizon", + "employed": false + }, + { + "firstName": "Tania", + "lastName": "Bishop", + "company": "Dragbot", + "employed": true + }, + { + "firstName": "Mitzi", + "lastName": "Arnold", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Shawn", + "lastName": "David", + "company": "Decratex", + "employed": true + }, + { + "firstName": "Victoria", + "lastName": "Castillo", + "company": "Earwax", + "employed": true + }, + { + "firstName": "Jenifer", + "lastName": "Valencia", + "company": "Oatfarm", + "employed": true + }, + { + "firstName": "Alvarado", + "lastName": "Simon", + "company": "Paragonia", + "employed": false + }, + { + "firstName": "Bullock", + "lastName": "Moran", + "company": "Ecrater", + "employed": false + }, + { + "firstName": "Sheila", + "lastName": "Walton", + "company": "Digiprint", + "employed": true + }, + { + "firstName": "Shana", + "lastName": "Stout", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Thornton", + "lastName": "Flynn", + "company": "Interodeo", + "employed": false + }, + { + "firstName": "Kerry", + "lastName": "Molina", + "company": "Zogak", + "employed": true + }, + { + "firstName": "Schneider", + "lastName": "Irwin", + "company": "Assurity", + "employed": false + }, + { + "firstName": "Willis", + "lastName": "Mcintosh", + "company": "Gronk", + "employed": false + }, + { + "firstName": "Sarah", + "lastName": "Santos", + "company": "Moltonic", + "employed": true + }, + { + "firstName": "Cherie", + "lastName": "Roach", + "company": "Perkle", + "employed": true + }, + { + "firstName": "Nichols", + "lastName": "Hancock", + "company": "Hairport", + "employed": false + }, + { + "firstName": "Helene", + "lastName": "Craig", + "company": "Pigzart", + "employed": false + }, + { + "firstName": "Kristine", + "lastName": "Henson", + "company": "Escenta", + "employed": false + }, + { + "firstName": "Eve", + "lastName": "Dillard", + "company": "Sensate", + "employed": false + }, + { + "firstName": "Ila", + "lastName": "Leach", + "company": "Temorak", + "employed": true + }, + { + "firstName": "Angelina", + "lastName": "Hodge", + "company": "Spacewax", + "employed": true + }, + { + "firstName": "Carr", + "lastName": "Pierce", + "company": "Zillacom", + "employed": false + }, + { + "firstName": "Corrine", + "lastName": "Austin", + "company": "Turnling", + "employed": true + }, + { + "firstName": "Booker", + "lastName": "Richard", + "company": "Tetak", + "employed": true + }, + { + "firstName": "Hardy", + "lastName": "Swanson", + "company": "Capscreen", + "employed": true + }, + { + "firstName": "Shelton", + "lastName": "Gonzalez", + "company": "Neptide", + "employed": true + }, + { + "firstName": "Young", + "lastName": "Singleton", + "company": "Xleen", + "employed": false + }, + { + "firstName": "Cook", + "lastName": "Brady", + "company": "Aclima", + "employed": true + }, + { + "firstName": "Luisa", + "lastName": "Williamson", + "company": "Snorus", + "employed": true + }, + { + "firstName": "Bettie", + "lastName": "Rollins", + "company": "Recritube", + "employed": true + }, + { + "firstName": "Colon", + "lastName": "Potts", + "company": "Zilidium", + "employed": false + }, + { + "firstName": "Frankie", + "lastName": "Cervantes", + "company": "Zialactic", + "employed": false + }, + { + "firstName": "Thompson", + "lastName": "Avila", + "company": "Cubix", + "employed": false + }, + { + "firstName": "Krista", + "lastName": "Spence", + "company": "Geeketron", + "employed": false + }, + { + "firstName": "Angelica", + "lastName": "York", + "company": "Limozen", + "employed": false + }, + { + "firstName": "Vicky", + "lastName": "Mercer", + "company": "Eclipto", + "employed": true + }, + { + "firstName": "Rosalie", + "lastName": "Burch", + "company": "Gaptec", + "employed": true + }, + { + "firstName": "Durham", + "lastName": "Rowe", + "company": "Isologix", + "employed": false + }, + { + "firstName": "Kinney", + "lastName": "Norman", + "company": "Fishland", + "employed": false + }, + { + "firstName": "Holder", + "lastName": "Barber", + "company": "Joviold", + "employed": false + }, + { + "firstName": "Mitchell", + "lastName": "Sanders", + "company": "Centrexin", + "employed": false + }, + { + "firstName": "Kristi", + "lastName": "Pickett", + "company": "Comtour", + "employed": true + }, + { + "firstName": "Martha", + "lastName": "Mcgee", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Hopkins", + "lastName": "Rice", + "company": "Intradisk", + "employed": true + }, + { + "firstName": "Tanisha", + "lastName": "Johns", + "company": "Teraprene", + "employed": true + }, + { + "firstName": "Nita", + "lastName": "Guy", + "company": "Quinex", + "employed": true + }, + { + "firstName": "Arnold", + "lastName": "Watkins", + "company": "Talkalot", + "employed": true + }, + { + "firstName": "Harriett", + "lastName": "Wiley", + "company": "Matrixity", + "employed": false + }, + { + "firstName": "Kane", + "lastName": "Ellison", + "company": "Comvey", + "employed": true + }, + { + "firstName": "Hatfield", + "lastName": "Vincent", + "company": "Minga", + "employed": false + }, + { + "firstName": "Leonard", + "lastName": "Alford", + "company": "Xurban", + "employed": false + }, + { + "firstName": "Shelby", + "lastName": "Knight", + "company": "Insuron", + "employed": false + }, + { + "firstName": "Winnie", + "lastName": "Ratliff", + "company": "Noralex", + "employed": true + }, + { + "firstName": "Anthony", + "lastName": "Warner", + "company": "Cuizine", + "employed": false + }, + { + "firstName": "Gates", + "lastName": "Houston", + "company": "Isoternia", + "employed": false + }, + { + "firstName": "Beth", + "lastName": "Joseph", + "company": "Tripsch", + "employed": false + }, + { + "firstName": "Michael", + "lastName": "Murphy", + "company": "Viocular", + "employed": false + }, + { + "firstName": "Sharpe", + "lastName": "Clarke", + "company": "Schoolio", + "employed": true + }, + { + "firstName": "Singleton", + "lastName": "Kerr", + "company": "Kinetica", + "employed": false + }, + { + "firstName": "Dunlap", + "lastName": "Farmer", + "company": "Asimiline", + "employed": true + }, + { + "firstName": "Serrano", + "lastName": "Evans", + "company": "Geekosis", + "employed": false + }, + { + "firstName": "Sonja", + "lastName": "Fox", + "company": "Zeam", + "employed": false + }, + { + "firstName": "Casandra", + "lastName": "Conrad", + "company": "Pheast", + "employed": false + }, + { + "firstName": "Melva", + "lastName": "Patel", + "company": "Hatology", + "employed": false + }, + { + "firstName": "Katy", + "lastName": "Hughes", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Virginia", + "lastName": "Cooper", + "company": "Keengen", + "employed": true + }, + { + "firstName": "Angie", + "lastName": "Clayton", + "company": "Synkgen", + "employed": false + }, + { + "firstName": "Latoya", + "lastName": "Colon", + "company": "Pasturia", + "employed": false + }, + { + "firstName": "Cecilia", + "lastName": "Herrera", + "company": "Pyrami", + "employed": false + }, + { + "firstName": "Hess", + "lastName": "Burt", + "company": "Balooba", + "employed": false + }, + { + "firstName": "Alice", + "lastName": "Parks", + "company": "Ontagene", + "employed": false + }, + { + "firstName": "Della", + "lastName": "Howe", + "company": "Acusage", + "employed": true + }, + { + "firstName": "Jodi", + "lastName": "Mooney", + "company": "Anacho", + "employed": false + }, + { + "firstName": "Dudley", + "lastName": "Hanson", + "company": "Mangelica", + "employed": true + }, + { + "firstName": "Buckner", + "lastName": "Ingram", + "company": "Comvex", + "employed": true + }, + { + "firstName": "Ana", + "lastName": "Miles", + "company": "Miraclis", + "employed": false + }, + { + "firstName": "Vasquez", + "lastName": "Park", + "company": "Fibrodyne", + "employed": false + }, + { + "firstName": "Miranda", + "lastName": "Bean", + "company": "Tri@Tribalog", + "employed": true + }, + { + "firstName": "Kathy", + "lastName": "Ferrell", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Goff", + "lastName": "Fry", + "company": "Eplode", + "employed": false + }, + { + "firstName": "Deann", + "lastName": "Gutierrez", + "company": "Yurture", + "employed": true + }, + { + "firstName": "Wade", + "lastName": "Taylor", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Rojas", + "lastName": "Barry", + "company": "Zolarity", + "employed": true + }, + { + "firstName": "Mai", + "lastName": "Hart", + "company": "Dyno", + "employed": false + }, + { + "firstName": "Audrey", + "lastName": "Flowers", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Robertson", + "lastName": "French", + "company": "Progenex", + "employed": false + }, + { + "firstName": "Velazquez", + "lastName": "Hatfield", + "company": "Geekko", + "employed": false + }, + { + "firstName": "Hope", + "lastName": "Cortez", + "company": "Urbanshee", + "employed": false + }, + { + "firstName": "Manuela", + "lastName": "Montoya", + "company": "Prismatic", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Acevedo", + "company": "Singavera", + "employed": false + }, + { + "firstName": "Faith", + "lastName": "West", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Carolina", + "lastName": "Campbell", + "company": "Namebox", + "employed": false + }, + { + "firstName": "Allison", + "lastName": "Parker", + "company": "Shepard", + "employed": false + }, + { + "firstName": "Melisa", + "lastName": "Curtis", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Salinas", + "lastName": "Snow", + "company": "Aquasure", + "employed": false + }, + { + "firstName": "Monica", + "lastName": "Key", + "company": "Rockyard", + "employed": false + }, + { + "firstName": "Florence", + "lastName": "Warren", + "company": "Ginkle", + "employed": true + }, + { + "firstName": "Nunez", + "lastName": "Mcmillan", + "company": "Xanide", + "employed": false + }, + { + "firstName": "Reyna", + "lastName": "Sharpe", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Kerr", + "lastName": "Goodman", + "company": "Overfork", + "employed": true + }, + { + "firstName": "Carla", + "lastName": "Huber", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Downs", + "lastName": "Head", + "company": "Gynko", + "employed": false + }, + { + "firstName": "Roxie", + "lastName": "Graves", + "company": "Autograte", + "employed": false + }, + { + "firstName": "Katrina", + "lastName": "House", + "company": "Endicil", + "employed": true + }, + { + "firstName": "Patty", + "lastName": "Holder", + "company": "Imageflow", + "employed": true + }, + { + "firstName": "Schwartz", + "lastName": "Maddox", + "company": "Visualix", + "employed": true + }, + { + "firstName": "Morgan", + "lastName": "Rivera", + "company": "Dadabase", + "employed": false + }, + { + "firstName": "Anita", + "lastName": "Hendricks", + "company": "Photobin", + "employed": false + }, + { + "firstName": "Bright", + "lastName": "Jenkins", + "company": "Securia", + "employed": true + }, + { + "firstName": "Franklin", + "lastName": "England", + "company": "Grupoli", + "employed": true + }, + { + "firstName": "Lesa", + "lastName": "Fitzpatrick", + "company": "Ginkogene", + "employed": false + }, + { + "firstName": "Hudson", + "lastName": "Kemp", + "company": "Comstar", + "employed": true + }, + { + "firstName": "Holmes", + "lastName": "Yates", + "company": "Plasmos", + "employed": true + }, + { + "firstName": "Mckay", + "lastName": "Gordon", + "company": "Blanet", + "employed": false + }, + { + "firstName": "May", + "lastName": "Lopez", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Robbins", + "lastName": "Bowen", + "company": "Assitia", + "employed": false + }, + { + "firstName": "Dixie", + "lastName": "Payne", + "company": "Comcubine", + "employed": false + }, + { + "firstName": "Megan", + "lastName": "Mcbride", + "company": "Kyagoro", + "employed": false + }, + { + "firstName": "Cain", + "lastName": "Hobbs", + "company": "Zolar", + "employed": false + }, + { + "firstName": "Gaines", + "lastName": "Sykes", + "company": "Protodyne", + "employed": false + }, + { + "firstName": "Fletcher", + "lastName": "Keith", + "company": "Daisu", + "employed": true + }, + { + "firstName": "Robin", + "lastName": "Knox", + "company": "Zytrax", + "employed": false + }, + { + "firstName": "Erickson", + "lastName": "Stephenson", + "company": "Sentia", + "employed": true + }, + { + "firstName": "Franks", + "lastName": "Massey", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Mona", + "lastName": "Hendrix", + "company": "Zentia", + "employed": false + }, + { + "firstName": "Kathryn", + "lastName": "Adams", + "company": "Ezentia", + "employed": true + }, + { + "firstName": "Joanna", + "lastName": "Vinson", + "company": "Accufarm", + "employed": false + }, + { + "firstName": "Farrell", + "lastName": "Holden", + "company": "Nurplex", + "employed": false + }, + { + "firstName": "Patton", + "lastName": "Mcknight", + "company": "Xixan", + "employed": false + }, + { + "firstName": "Vera", + "lastName": "Wilson", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Finley", + "lastName": "Clay", + "company": "Zuvy", + "employed": false + }, + { + "firstName": "Karla", + "lastName": "Sexton", + "company": "Applideck", + "employed": true + }, + { + "firstName": "Cora", + "lastName": "Ramos", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Henrietta", + "lastName": "Oneill", + "company": "Delphide", + "employed": false + }, + { + "firstName": "Ball", + "lastName": "Weiss", + "company": "Terascape", + "employed": false + }, + { + "firstName": "Eunice", + "lastName": "Hawkins", + "company": "Trollery", + "employed": true + }, + { + "firstName": "Stacy", + "lastName": "Beck", + "company": "Empirica", + "employed": true + }, + { + "firstName": "Charity", + "lastName": "Sanchez", + "company": "Gology", + "employed": true + }, + { + "firstName": "Phelps", + "lastName": "Hoffman", + "company": "Prowaste", + "employed": false + }, + { + "firstName": "Lilian", + "lastName": "Perez", + "company": "Rocklogic", + "employed": false + }, + { + "firstName": "Rivas", + "lastName": "Morris", + "company": "Geeky", + "employed": false + }, + { + "firstName": "Buckley", + "lastName": "Nixon", + "company": "Mazuda", + "employed": true + }, + { + "firstName": "Becker", + "lastName": "Pena", + "company": "Rockabye", + "employed": true + }, + { + "firstName": "Rogers", + "lastName": "Daugherty", + "company": "Jetsilk", + "employed": true + }, + { + "firstName": "Sondra", + "lastName": "Leonard", + "company": "Xinware", + "employed": true + }, + { + "firstName": "Hurley", + "lastName": "Fields", + "company": "Duoflex", + "employed": true + }, + { + "firstName": "Aisha", + "lastName": "Shaffer", + "company": "Genmom", + "employed": false + }, + { + "firstName": "Marisol", + "lastName": "Le", + "company": "Franscene", + "employed": true + }, + { + "firstName": "Webster", + "lastName": "Grimes", + "company": "Besto", + "employed": true + }, + { + "firstName": "Macdonald", + "lastName": "Bradford", + "company": "Opticon", + "employed": false + }, + { + "firstName": "Marietta", + "lastName": "Garrett", + "company": "Opticall", + "employed": true + }, + { + "firstName": "Hebert", + "lastName": "Haney", + "company": "Geologix", + "employed": false + }, + { + "firstName": "Mclaughlin", + "lastName": "Salas", + "company": "Sulfax", + "employed": false + }, + { + "firstName": "Fuentes", + "lastName": "Lester", + "company": "Glasstep", + "employed": false + }, + { + "firstName": "Casey", + "lastName": "Shepherd", + "company": "Zolarex", + "employed": false + }, + { + "firstName": "Whitley", + "lastName": "Albert", + "company": "Mixers", + "employed": false + }, + { + "firstName": "Dolly", + "lastName": "Madden", + "company": "Magneato", + "employed": true + }, + { + "firstName": "Buck", + "lastName": "Cline", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Mabel", + "lastName": "Stone", + "company": "Turnabout", + "employed": true + }, + { + "firstName": "Carlene", + "lastName": "Mcdaniel", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Leah", + "lastName": "Lynn", + "company": "Kindaloo", + "employed": true + }, + { + "firstName": "Zelma", + "lastName": "Chan", + "company": "Wrapture", + "employed": false + }, + { + "firstName": "Gonzalez", + "lastName": "Fowler", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Sellers", + "lastName": "Greene", + "company": "Enomen", + "employed": false + }, + { + "firstName": "Alison", + "lastName": "Winters", + "company": "Earthmark", + "employed": true + }, + { + "firstName": "Pitts", + "lastName": "Bradley", + "company": "Gallaxia", + "employed": false + }, + { + "firstName": "Haley", + "lastName": "Cooley", + "company": "Zerbina", + "employed": false + }, + { + "firstName": "Ladonna", + "lastName": "Garza", + "company": "Soprano", + "employed": false + }, + { + "firstName": "Hull", + "lastName": "Middleton", + "company": "Cincyr", + "employed": false + }, + { + "firstName": "Valarie", + "lastName": "Mullins", + "company": "Emoltra", + "employed": true + }, + { + "firstName": "Davenport", + "lastName": "Wynn", + "company": "Quantasis", + "employed": false + }, + { + "firstName": "Patrica", + "lastName": "Terrell", + "company": "Netility", + "employed": false + }, + { + "firstName": "Lena", + "lastName": "Maxwell", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Charmaine", + "lastName": "Nguyen", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Dorsey", + "lastName": "Whitney", + "company": "Vortexaco", + "employed": false + }, + { + "firstName": "Chen", + "lastName": "Zamora", + "company": "Uneeq", + "employed": false + }, + { + "firstName": "Pacheco", + "lastName": "Page", + "company": "Combot", + "employed": false + }, + { + "firstName": "Lacy", + "lastName": "Guthrie", + "company": "Atgen", + "employed": true + }, + { + "firstName": "Olsen", + "lastName": "Langley", + "company": "Ewaves", + "employed": false + }, + { + "firstName": "Sybil", + "lastName": "Carroll", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Lott", + "lastName": "Hamilton", + "company": "Phormula", + "employed": true + }, + { + "firstName": "Foley", + "lastName": "Harding", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Julie", + "lastName": "Guthrie", + "company": "Zytrex", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Flores", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Donaldson", + "lastName": "Chandler", + "company": "Quiltigen", + "employed": true + }, + { + "firstName": "Rochelle", + "lastName": "Craft", + "company": "Prismatic", + "employed": false + }, + { + "firstName": "Debbie", + "lastName": "Barnett", + "company": "Gology", + "employed": false + }, + { + "firstName": "Katherine", + "lastName": "Ramos", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Sears", + "lastName": "Thomas", + "company": "Exotechno", + "employed": false + }, + { + "firstName": "Robin", + "lastName": "Wilkerson", + "company": "Prosure", + "employed": true + }, + { + "firstName": "Amparo", + "lastName": "Rios", + "company": "Uneeq", + "employed": false + }, + { + "firstName": "Cline", + "lastName": "Jefferson", + "company": "Frenex", + "employed": true + } +] \ No newline at end of file diff --git a/data/10000_complex.json b/data/10000_complex.json new file mode 100644 index 000000000..1d6908340 --- /dev/null +++ b/data/10000_complex.json @@ -0,0 +1,100002 @@ +[ + { + "id": 0, + "name": "Ramsey Cummings", + "gender": "male", + "age": 52, + "address": { + "state": "South Carolina", + "city": "Glendale" + } + }, + { + "id": 1, + "name": "Stefanie Huff", + "gender": "female", + "age": 70, + "address": { + "state": "Arizona", + "city": "Beaverdale" + } + }, + { + "id": 2, + "name": "Mabel David", + "gender": "female", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Grazierville" + } + }, + { + "id": 3, + "name": "Frank Bradford", + "gender": "male", + "age": 61, + "address": { + "state": "Wisconsin", + "city": "Saranap" + } + }, + { + "id": 4, + "name": "Forbes Levine", + "gender": "male", + "age": 34, + "address": { + "state": "Vermont", + "city": "Norris" + } + }, + { + "id": 5, + "name": "Santiago Mcclain", + "gender": "male", + "age": 38, + "address": { + "state": "Montana", + "city": "Bordelonville" + } + }, + { + "id": 6, + "name": "Merritt Booker", + "gender": "male", + "age": 33, + "address": { + "state": "New Jersey", + "city": "Aguila" + } + }, + { + "id": 7, + "name": "Oconnor Wade", + "gender": "male", + "age": 18, + "address": { + "state": "Virginia", + "city": "Kenmar" + } + }, + { + "id": 8, + "name": "Leigh Beasley", + "gender": "female", + "age": 53, + "address": { + "state": "Texas", + "city": "Alfarata" + } + }, + { + "id": 9, + "name": "Johns Wood", + "gender": "male", + "age": 52, + "address": { + "state": "Maine", + "city": "Witmer" + } + }, + { + "id": 10, + "name": "Thompson Hays", + "gender": "male", + "age": 38, + "address": { + "state": "Nevada", + "city": "Kipp" + } + }, + { + "id": 11, + "name": "Hallie Mack", + "gender": "female", + "age": 19, + "address": { + "state": "Minnesota", + "city": "Darrtown" + } + }, + { + "id": 12, + "name": "Houston Santos", + "gender": "male", + "age": 24, + "address": { + "state": "Georgia", + "city": "Crucible" + } + }, + { + "id": 13, + "name": "Brandy Savage", + "gender": "female", + "age": 65, + "address": { + "state": "Idaho", + "city": "Nord" + } + }, + { + "id": 14, + "name": "Finch Barnett", + "gender": "male", + "age": 22, + "address": { + "state": "Ohio", + "city": "Osmond" + } + }, + { + "id": 15, + "name": "Nicole Crosby", + "gender": "female", + "age": 77, + "address": { + "state": "Kentucky", + "city": "Fairfield" + } + }, + { + "id": 16, + "name": "Carrie Mcconnell", + "gender": "female", + "age": 26, + "address": { + "state": "South Dakota", + "city": "Waikele" + } + }, + { + "id": 17, + "name": "Ann James", + "gender": "female", + "age": 37, + "address": { + "state": "North Dakota", + "city": "Siglerville" + } + }, + { + "id": 18, + "name": "Becky Sanford", + "gender": "female", + "age": 48, + "address": { + "state": "Massachusetts", + "city": "Celeryville" + } + }, + { + "id": 19, + "name": "Kathryn Rios", + "gender": "female", + "age": 39, + "address": { + "state": "Delaware", + "city": "Kylertown" + } + }, + { + "id": 20, + "name": "Dotson Vaughn", + "gender": "male", + "age": 68, + "address": { + "state": "Arkansas", + "city": "Monument" + } + }, + { + "id": 21, + "name": "Wright Kline", + "gender": "male", + "age": 41, + "address": { + "state": "Missouri", + "city": "Bynum" + } + }, + { + "id": 22, + "name": "Lula Morgan", + "gender": "female", + "age": 52, + "address": { + "state": "Oregon", + "city": "Mapletown" + } + }, + { + "id": 23, + "name": "Kay Mendez", + "gender": "female", + "age": 50, + "address": { + "state": "Michigan", + "city": "Twilight" + } + }, + { + "id": 24, + "name": "Mona Maddox", + "gender": "female", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Wilmington" + } + }, + { + "id": 25, + "name": "Fulton Velez", + "gender": "male", + "age": 66, + "address": { + "state": "Colorado", + "city": "Loretto" + } + }, + { + "id": 26, + "name": "Ericka Craft", + "gender": "female", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Beaulieu" + } + }, + { + "id": 27, + "name": "Richmond Rodriguez", + "gender": "male", + "age": 62, + "address": { + "state": "Rhode Island", + "city": "Vallonia" + } + }, + { + "id": 28, + "name": "Olsen Farmer", + "gender": "male", + "age": 45, + "address": { + "state": "Connecticut", + "city": "Romeville" + } + }, + { + "id": 29, + "name": "Sophie Austin", + "gender": "female", + "age": 59, + "address": { + "state": "New Hampshire", + "city": "Gorst" + } + }, + { + "id": 30, + "name": "Alta Olsen", + "gender": "female", + "age": 58, + "address": { + "state": "Florida", + "city": "Drytown" + } + }, + { + "id": 31, + "name": "Katherine Chavez", + "gender": "female", + "age": 20, + "address": { + "state": "Mississippi", + "city": "Trucksville" + } + }, + { + "id": 32, + "name": "Yvette Myers", + "gender": "female", + "age": 69, + "address": { + "state": "Washington", + "city": "Bangor" + } + }, + { + "id": 33, + "name": "Nguyen Dean", + "gender": "male", + "age": 58, + "address": { + "state": "Alaska", + "city": "Caroline" + } + }, + { + "id": 34, + "name": "Lauri Irwin", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Takilma" + } + }, + { + "id": 35, + "name": "David Mclean", + "gender": "male", + "age": 49, + "address": { + "state": "Louisiana", + "city": "Harviell" + } + }, + { + "id": 36, + "name": "Tisha Cotton", + "gender": "female", + "age": 78, + "address": { + "state": "Illinois", + "city": "Camas" + } + }, + { + "id": 37, + "name": "Eliza Conrad", + "gender": "female", + "age": 82, + "address": { + "state": "Utah", + "city": "Gwynn" + } + }, + { + "id": 38, + "name": "Bolton Cooley", + "gender": "male", + "age": 44, + "address": { + "state": "Oklahoma", + "city": "Glidden" + } + }, + { + "id": 39, + "name": "Crosby Osborn", + "gender": "male", + "age": 44, + "address": { + "state": "Alabama", + "city": "Buxton" + } + }, + { + "id": 40, + "name": "Reese Tran", + "gender": "male", + "age": 53, + "address": { + "state": "Maryland", + "city": "Kempton" + } + }, + { + "id": 41, + "name": "Evangeline Larson", + "gender": "female", + "age": 49, + "address": { + "state": "Pennsylvania", + "city": "Mayfair" + } + }, + { + "id": 42, + "name": "Jimenez Frazier", + "gender": "male", + "age": 23, + "address": { + "state": "California", + "city": "Ronco" + } + }, + { + "id": 43, + "name": "Conner Tate", + "gender": "male", + "age": 39, + "address": { + "state": "West Virginia", + "city": "Eastvale" + } + }, + { + "id": 44, + "name": "Avery Rosales", + "gender": "male", + "age": 71, + "address": { + "state": "Tennessee", + "city": "Cascades" + } + }, + { + "id": 45, + "name": "Burris Marquez", + "gender": "male", + "age": 32, + "address": { + "state": "North Carolina", + "city": "Chamizal" + } + }, + { + "id": 46, + "name": "Hoover Cardenas", + "gender": "male", + "age": 65, + "address": { + "state": "Kansas", + "city": "Joes" + } + }, + { + "id": 47, + "name": "Moran Gomez", + "gender": "male", + "age": 40, + "address": { + "state": "New York", + "city": "Knowlton" + } + }, + { + "id": 48, + "name": "Boyd Juarez", + "gender": "male", + "age": 33, + "address": { + "state": "Iowa", + "city": "Hemlock" + } + }, + { + "id": 49, + "name": "John Mooney", + "gender": "female", + "age": 73, + "address": { + "state": "Rhode Island", + "city": "Gardners" + } + }, + { + "id": 50, + "name": "Avery Crawford", + "gender": "male", + "age": 39, + "address": { + "state": "Hawaii", + "city": "Woodruff" + } + }, + { + "id": 51, + "name": "Hudson Manning", + "gender": "male", + "age": 27, + "address": { + "state": "New York", + "city": "Bakersville" + } + }, + { + "id": 52, + "name": "Claudia Haney", + "gender": "female", + "age": 62, + "address": { + "state": "Massachusetts", + "city": "Worton" + } + }, + { + "id": 53, + "name": "Barlow Harding", + "gender": "male", + "age": 80, + "address": { + "state": "New Jersey", + "city": "Bentley" + } + }, + { + "id": 54, + "name": "Carolyn Castro", + "gender": "female", + "age": 64, + "address": { + "state": "Wyoming", + "city": "Kingstowne" + } + }, + { + "id": 55, + "name": "Bridges Stokes", + "gender": "male", + "age": 25, + "address": { + "state": "Utah", + "city": "Eagleville" + } + }, + { + "id": 56, + "name": "William Yates", + "gender": "male", + "age": 56, + "address": { + "state": "Maryland", + "city": "Loretto" + } + }, + { + "id": 57, + "name": "Doyle Shaw", + "gender": "male", + "age": 52, + "address": { + "state": "Delaware", + "city": "Evergreen" + } + }, + { + "id": 58, + "name": "Becker Schmidt", + "gender": "male", + "age": 68, + "address": { + "state": "Minnesota", + "city": "Nescatunga" + } + }, + { + "id": 59, + "name": "Karla Good", + "gender": "female", + "age": 47, + "address": { + "state": "Oregon", + "city": "Balm" + } + }, + { + "id": 60, + "name": "Shepard Massey", + "gender": "male", + "age": 61, + "address": { + "state": "Kansas", + "city": "Deputy" + } + }, + { + "id": 61, + "name": "Ellison Lara", + "gender": "male", + "age": 73, + "address": { + "state": "Michigan", + "city": "Marne" + } + }, + { + "id": 62, + "name": "Jodi Horton", + "gender": "female", + "age": 60, + "address": { + "state": "Maine", + "city": "Cumberland" + } + }, + { + "id": 63, + "name": "Santana Beasley", + "gender": "male", + "age": 55, + "address": { + "state": "Iowa", + "city": "Ticonderoga" + } + }, + { + "id": 64, + "name": "Atkins Mcintyre", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Robinette" + } + }, + { + "id": 65, + "name": "Margie Lang", + "gender": "female", + "age": 47, + "address": { + "state": "Mississippi", + "city": "Silkworth" + } + }, + { + "id": 66, + "name": "Effie Morales", + "gender": "female", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Wyoming" + } + }, + { + "id": 67, + "name": "Merritt Marshall", + "gender": "male", + "age": 70, + "address": { + "state": "Alaska", + "city": "Hackneyville" + } + }, + { + "id": 68, + "name": "Nikki Valentine", + "gender": "female", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Dana" + } + }, + { + "id": 69, + "name": "Whitaker Suarez", + "gender": "male", + "age": 42, + "address": { + "state": "Colorado", + "city": "Edgewater" + } + }, + { + "id": 70, + "name": "Mendez Ramsey", + "gender": "male", + "age": 82, + "address": { + "state": "Washington", + "city": "Terlingua" + } + }, + { + "id": 71, + "name": "Latasha Guthrie", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Moraida" + } + }, + { + "id": 72, + "name": "Penelope Diaz", + "gender": "female", + "age": 24, + "address": { + "state": "Louisiana", + "city": "Umapine" + } + }, + { + "id": 73, + "name": "Gomez Chaney", + "gender": "male", + "age": 23, + "address": { + "state": "Virginia", + "city": "Nelson" + } + }, + { + "id": 74, + "name": "Wilma Morris", + "gender": "female", + "age": 47, + "address": { + "state": "Vermont", + "city": "Draper" + } + }, + { + "id": 75, + "name": "Jimenez Randall", + "gender": "male", + "age": 19, + "address": { + "state": "Texas", + "city": "Elizaville" + } + }, + { + "id": 76, + "name": "Greta Barry", + "gender": "female", + "age": 27, + "address": { + "state": "Arkansas", + "city": "Bellfountain" + } + }, + { + "id": 77, + "name": "Pam Wilder", + "gender": "female", + "age": 24, + "address": { + "state": "Georgia", + "city": "Hannasville" + } + }, + { + "id": 78, + "name": "Brittney Serrano", + "gender": "female", + "age": 61, + "address": { + "state": "Kentucky", + "city": "Fairview" + } + }, + { + "id": 79, + "name": "Hernandez Zamora", + "gender": "male", + "age": 42, + "address": { + "state": "Illinois", + "city": "Bethpage" + } + }, + { + "id": 80, + "name": "Teri Butler", + "gender": "female", + "age": 59, + "address": { + "state": "Oklahoma", + "city": "Ruffin" + } + }, + { + "id": 81, + "name": "Mercedes Glover", + "gender": "female", + "age": 30, + "address": { + "state": "Tennessee", + "city": "Darrtown" + } + }, + { + "id": 82, + "name": "Simone Burns", + "gender": "female", + "age": 65, + "address": { + "state": "South Carolina", + "city": "Idamay" + } + }, + { + "id": 83, + "name": "Herrera Norman", + "gender": "male", + "age": 54, + "address": { + "state": "North Dakota", + "city": "Tibbie" + } + }, + { + "id": 84, + "name": "Lea Hunter", + "gender": "female", + "age": 39, + "address": { + "state": "Montana", + "city": "Cedarville" + } + }, + { + "id": 85, + "name": "Briana Mckay", + "gender": "female", + "age": 18, + "address": { + "state": "Idaho", + "city": "Ona" + } + }, + { + "id": 86, + "name": "Letha Kirk", + "gender": "female", + "age": 75, + "address": { + "state": "Pennsylvania", + "city": "Bayview" + } + }, + { + "id": 87, + "name": "Head Finch", + "gender": "male", + "age": 60, + "address": { + "state": "Alabama", + "city": "Ruckersville" + } + }, + { + "id": 88, + "name": "Lauri Bates", + "gender": "female", + "age": 40, + "address": { + "state": "Missouri", + "city": "Skyland" + } + }, + { + "id": 89, + "name": "Corine Reyes", + "gender": "female", + "age": 49, + "address": { + "state": "Nebraska", + "city": "Fredericktown" + } + }, + { + "id": 90, + "name": "Hattie Powell", + "gender": "female", + "age": 36, + "address": { + "state": "Nevada", + "city": "Remington" + } + }, + { + "id": 91, + "name": "Coffey Wolf", + "gender": "male", + "age": 40, + "address": { + "state": "North Carolina", + "city": "Stagecoach" + } + }, + { + "id": 92, + "name": "Knowles Rowe", + "gender": "male", + "age": 77, + "address": { + "state": "California", + "city": "Hardyville" + } + }, + { + "id": 93, + "name": "Leona Blair", + "gender": "female", + "age": 35, + "address": { + "state": "Indiana", + "city": "Crayne" + } + }, + { + "id": 94, + "name": "Meadows Hebert", + "gender": "male", + "age": 42, + "address": { + "state": "Wisconsin", + "city": "Levant" + } + }, + { + "id": 95, + "name": "Francis Becker", + "gender": "female", + "age": 63, + "address": { + "state": "Florida", + "city": "Rehrersburg" + } + }, + { + "id": 96, + "name": "Huber Wilcox", + "gender": "male", + "age": 57, + "address": { + "state": "Ohio", + "city": "Hessville" + } + }, + { + "id": 97, + "name": "Jeanie Graham", + "gender": "female", + "age": 37, + "address": { + "state": "Arizona", + "city": "Foxworth" + } + }, + { + "id": 98, + "name": "Genevieve Barr", + "gender": "female", + "age": 40, + "address": { + "state": "Oklahoma", + "city": "Greenbackville" + } + }, + { + "id": 99, + "name": "Leonard Randolph", + "gender": "male", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Bath" + } + }, + { + "id": 100, + "name": "Hartman Mcgowan", + "gender": "male", + "age": 66, + "address": { + "state": "Wyoming", + "city": "Veyo" + } + }, + { + "id": 101, + "name": "Aline Maxwell", + "gender": "female", + "age": 66, + "address": { + "state": "California", + "city": "Curtice" + } + }, + { + "id": 102, + "name": "Maldonado Conway", + "gender": "male", + "age": 42, + "address": { + "state": "Michigan", + "city": "Montura" + } + }, + { + "id": 103, + "name": "Shari Reyes", + "gender": "female", + "age": 47, + "address": { + "state": "Rhode Island", + "city": "Ellerslie" + } + }, + { + "id": 104, + "name": "Lidia Conner", + "gender": "female", + "age": 42, + "address": { + "state": "West Virginia", + "city": "Cawood" + } + }, + { + "id": 105, + "name": "Murphy Wiley", + "gender": "male", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Mappsville" + } + }, + { + "id": 106, + "name": "Frye Hendricks", + "gender": "male", + "age": 33, + "address": { + "state": "South Dakota", + "city": "Coultervillle" + } + }, + { + "id": 107, + "name": "Torres Mcclure", + "gender": "male", + "age": 82, + "address": { + "state": "Kentucky", + "city": "Wacissa" + } + }, + { + "id": 108, + "name": "Leblanc Schneider", + "gender": "male", + "age": 64, + "address": { + "state": "Montana", + "city": "Glenshaw" + } + }, + { + "id": 109, + "name": "Stevenson Arnold", + "gender": "male", + "age": 19, + "address": { + "state": "Mississippi", + "city": "Joes" + } + }, + { + "id": 110, + "name": "Hogan Ortiz", + "gender": "male", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Watchtower" + } + }, + { + "id": 111, + "name": "Colleen Herman", + "gender": "female", + "age": 59, + "address": { + "state": "Tennessee", + "city": "Edgar" + } + }, + { + "id": 112, + "name": "Casandra Wolfe", + "gender": "female", + "age": 18, + "address": { + "state": "New Mexico", + "city": "Alderpoint" + } + }, + { + "id": 113, + "name": "Laverne Powell", + "gender": "female", + "age": 29, + "address": { + "state": "Iowa", + "city": "Hanover" + } + }, + { + "id": 114, + "name": "Solis Pitts", + "gender": "male", + "age": 52, + "address": { + "state": "Alaska", + "city": "Sparkill" + } + }, + { + "id": 115, + "name": "Young Drake", + "gender": "male", + "age": 77, + "address": { + "state": "Arizona", + "city": "Venice" + } + }, + { + "id": 116, + "name": "Vaughan Boone", + "gender": "male", + "age": 80, + "address": { + "state": "Illinois", + "city": "Fannett" + } + }, + { + "id": 117, + "name": "Meyers Bonner", + "gender": "male", + "age": 27, + "address": { + "state": "Minnesota", + "city": "Echo" + } + }, + { + "id": 118, + "name": "Marian Sweeney", + "gender": "female", + "age": 30, + "address": { + "state": "Massachusetts", + "city": "Haring" + } + }, + { + "id": 119, + "name": "Mary Bowen", + "gender": "female", + "age": 41, + "address": { + "state": "Nebraska", + "city": "Staples" + } + }, + { + "id": 120, + "name": "Beryl Coffey", + "gender": "female", + "age": 29, + "address": { + "state": "Ohio", + "city": "Cowiche" + } + }, + { + "id": 121, + "name": "Ewing Garcia", + "gender": "male", + "age": 68, + "address": { + "state": "Alabama", + "city": "Enoree" + } + }, + { + "id": 122, + "name": "Jan Mason", + "gender": "female", + "age": 35, + "address": { + "state": "Washington", + "city": "Itmann" + } + }, + { + "id": 123, + "name": "Mallory Byrd", + "gender": "female", + "age": 75, + "address": { + "state": "Indiana", + "city": "Worcester" + } + }, + { + "id": 124, + "name": "Terry Rosales", + "gender": "male", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Twilight" + } + }, + { + "id": 125, + "name": "Mcclure Barlow", + "gender": "male", + "age": 62, + "address": { + "state": "Wisconsin", + "city": "Diaperville" + } + }, + { + "id": 126, + "name": "Melton Hunt", + "gender": "male", + "age": 34, + "address": { + "state": "Louisiana", + "city": "Stollings" + } + }, + { + "id": 127, + "name": "Cathy Berger", + "gender": "female", + "age": 56, + "address": { + "state": "New York", + "city": "Bonanza" + } + }, + { + "id": 128, + "name": "Porter Rosa", + "gender": "male", + "age": 74, + "address": { + "state": "Georgia", + "city": "Moquino" + } + }, + { + "id": 129, + "name": "Harvey Bradley", + "gender": "male", + "age": 23, + "address": { + "state": "Maine", + "city": "Santel" + } + }, + { + "id": 130, + "name": "Cornelia Barron", + "gender": "female", + "age": 66, + "address": { + "state": "Nevada", + "city": "Finzel" + } + }, + { + "id": 131, + "name": "Hallie Reynolds", + "gender": "female", + "age": 25, + "address": { + "state": "Delaware", + "city": "Sidman" + } + }, + { + "id": 132, + "name": "Key Dillon", + "gender": "male", + "age": 17, + "address": { + "state": "New Hampshire", + "city": "Siglerville" + } + }, + { + "id": 133, + "name": "Hale Howell", + "gender": "male", + "age": 57, + "address": { + "state": "Texas", + "city": "Stonybrook" + } + }, + { + "id": 134, + "name": "Hester Glass", + "gender": "male", + "age": 22, + "address": { + "state": "Oregon", + "city": "Dalton" + } + }, + { + "id": 135, + "name": "Winnie Chen", + "gender": "female", + "age": 30, + "address": { + "state": "Missouri", + "city": "Cassel" + } + }, + { + "id": 136, + "name": "Ladonna Hooper", + "gender": "female", + "age": 80, + "address": { + "state": "Kansas", + "city": "Ryderwood" + } + }, + { + "id": 137, + "name": "Phillips Mays", + "gender": "male", + "age": 77, + "address": { + "state": "Florida", + "city": "Nanafalia" + } + }, + { + "id": 138, + "name": "Rivera Nguyen", + "gender": "male", + "age": 67, + "address": { + "state": "Virginia", + "city": "Gadsden" + } + }, + { + "id": 139, + "name": "Mckinney Walton", + "gender": "male", + "age": 41, + "address": { + "state": "Connecticut", + "city": "Nogal" + } + }, + { + "id": 140, + "name": "Pickett Patton", + "gender": "male", + "age": 71, + "address": { + "state": "Vermont", + "city": "Boling" + } + }, + { + "id": 141, + "name": "Stevens Chavez", + "gender": "male", + "age": 21, + "address": { + "state": "Arkansas", + "city": "Snelling" + } + }, + { + "id": 142, + "name": "Wilkins Duncan", + "gender": "male", + "age": 19, + "address": { + "state": "Idaho", + "city": "Gerber" + } + }, + { + "id": 143, + "name": "Ellis Jacobson", + "gender": "male", + "age": 54, + "address": { + "state": "Hawaii", + "city": "Chamizal" + } + }, + { + "id": 144, + "name": "Cristina Scott", + "gender": "female", + "age": 81, + "address": { + "state": "Colorado", + "city": "Waterview" + } + }, + { + "id": 145, + "name": "Huff Navarro", + "gender": "male", + "age": 33, + "address": { + "state": "Maryland", + "city": "Mammoth" + } + }, + { + "id": 146, + "name": "Reynolds Humphrey", + "gender": "male", + "age": 72, + "address": { + "state": "New Jersey", + "city": "Williamson" + } + }, + { + "id": 147, + "name": "Gay Grant", + "gender": "male", + "age": 53, + "address": { + "state": "Vermont", + "city": "Frystown" + } + }, + { + "id": 148, + "name": "Kim Martin", + "gender": "female", + "age": 64, + "address": { + "state": "Florida", + "city": "Tioga" + } + }, + { + "id": 149, + "name": "Mccormick Turner", + "gender": "male", + "age": 68, + "address": { + "state": "Mississippi", + "city": "Yukon" + } + }, + { + "id": 150, + "name": "Mcdowell Emerson", + "gender": "male", + "age": 60, + "address": { + "state": "Indiana", + "city": "Dorneyville" + } + }, + { + "id": 151, + "name": "Maritza Hardin", + "gender": "female", + "age": 63, + "address": { + "state": "Arkansas", + "city": "Keller" + } + }, + { + "id": 152, + "name": "Hess Richardson", + "gender": "male", + "age": 23, + "address": { + "state": "Kentucky", + "city": "Clarksburg" + } + }, + { + "id": 153, + "name": "Rhonda Faulkner", + "gender": "female", + "age": 23, + "address": { + "state": "Minnesota", + "city": "Wheatfields" + } + }, + { + "id": 154, + "name": "Morgan Wade", + "gender": "female", + "age": 51, + "address": { + "state": "Wisconsin", + "city": "Chamberino" + } + }, + { + "id": 155, + "name": "Clarice Morales", + "gender": "female", + "age": 47, + "address": { + "state": "North Dakota", + "city": "Hobucken" + } + }, + { + "id": 156, + "name": "Mayo Silva", + "gender": "male", + "age": 47, + "address": { + "state": "Ohio", + "city": "Beaulieu" + } + }, + { + "id": 157, + "name": "Sullivan Bryan", + "gender": "male", + "age": 74, + "address": { + "state": "Oregon", + "city": "Darbydale" + } + }, + { + "id": 158, + "name": "Kristin Carrillo", + "gender": "female", + "age": 78, + "address": { + "state": "California", + "city": "Brooktrails" + } + }, + { + "id": 159, + "name": "Gallagher Tillman", + "gender": "male", + "age": 34, + "address": { + "state": "Illinois", + "city": "Ypsilanti" + } + }, + { + "id": 160, + "name": "Aimee Mathews", + "gender": "female", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Reno" + } + }, + { + "id": 161, + "name": "Maura Meyers", + "gender": "female", + "age": 38, + "address": { + "state": "Arizona", + "city": "Yardville" + } + }, + { + "id": 162, + "name": "Slater Wilder", + "gender": "male", + "age": 28, + "address": { + "state": "South Dakota", + "city": "Celeryville" + } + }, + { + "id": 163, + "name": "Tameka Ochoa", + "gender": "female", + "age": 38, + "address": { + "state": "Iowa", + "city": "Winchester" + } + }, + { + "id": 164, + "name": "Roth Hammond", + "gender": "male", + "age": 29, + "address": { + "state": "Maine", + "city": "Bergoo" + } + }, + { + "id": 165, + "name": "Durham Higgins", + "gender": "male", + "age": 65, + "address": { + "state": "Oklahoma", + "city": "Jessie" + } + }, + { + "id": 166, + "name": "Janice Carey", + "gender": "female", + "age": 36, + "address": { + "state": "Georgia", + "city": "Shaft" + } + }, + { + "id": 167, + "name": "Elva Downs", + "gender": "female", + "age": 24, + "address": { + "state": "Delaware", + "city": "Stagecoach" + } + }, + { + "id": 168, + "name": "Emerson Wolf", + "gender": "male", + "age": 72, + "address": { + "state": "Montana", + "city": "Toftrees" + } + }, + { + "id": 169, + "name": "Mitchell Greene", + "gender": "male", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Mulberry" + } + }, + { + "id": 170, + "name": "Pope Poole", + "gender": "male", + "age": 45, + "address": { + "state": "Rhode Island", + "city": "Nicholson" + } + }, + { + "id": 171, + "name": "Bradford Montgomery", + "gender": "male", + "age": 74, + "address": { + "state": "Virginia", + "city": "Sandston" + } + }, + { + "id": 172, + "name": "Lakeisha Joseph", + "gender": "female", + "age": 27, + "address": { + "state": "Colorado", + "city": "Tedrow" + } + }, + { + "id": 173, + "name": "Shari Boyle", + "gender": "female", + "age": 21, + "address": { + "state": "Kansas", + "city": "Freeburn" + } + }, + { + "id": 174, + "name": "Kathleen Newman", + "gender": "female", + "age": 76, + "address": { + "state": "Nevada", + "city": "Fairfield" + } + }, + { + "id": 175, + "name": "Rosanna Merritt", + "gender": "female", + "age": 40, + "address": { + "state": "Idaho", + "city": "Oretta" + } + }, + { + "id": 176, + "name": "Betsy Jacobs", + "gender": "female", + "age": 55, + "address": { + "state": "Nebraska", + "city": "Geyserville" + } + }, + { + "id": 177, + "name": "Rae Cox", + "gender": "female", + "age": 74, + "address": { + "state": "North Carolina", + "city": "Klagetoh" + } + }, + { + "id": 178, + "name": "Dodson Delacruz", + "gender": "male", + "age": 24, + "address": { + "state": "Maryland", + "city": "Thermal" + } + }, + { + "id": 179, + "name": "Anastasia Monroe", + "gender": "female", + "age": 54, + "address": { + "state": "Connecticut", + "city": "Oley" + } + }, + { + "id": 180, + "name": "Goldie Reid", + "gender": "female", + "age": 72, + "address": { + "state": "Alaska", + "city": "Kohatk" + } + }, + { + "id": 181, + "name": "Dillard Fox", + "gender": "male", + "age": 32, + "address": { + "state": "Utah", + "city": "Churchill" + } + }, + { + "id": 182, + "name": "Moses Evans", + "gender": "male", + "age": 65, + "address": { + "state": "Alabama", + "city": "Kimmell" + } + }, + { + "id": 183, + "name": "Pace Fitzgerald", + "gender": "male", + "age": 31, + "address": { + "state": "Wyoming", + "city": "Germanton" + } + }, + { + "id": 184, + "name": "Shawn Martinez", + "gender": "female", + "age": 33, + "address": { + "state": "New Jersey", + "city": "Castleton" + } + }, + { + "id": 185, + "name": "Lawson Hanson", + "gender": "male", + "age": 60, + "address": { + "state": "Missouri", + "city": "Sattley" + } + }, + { + "id": 186, + "name": "Imelda Rogers", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Ruffin" + } + }, + { + "id": 187, + "name": "Gretchen Dodson", + "gender": "female", + "age": 52, + "address": { + "state": "Louisiana", + "city": "Indio" + } + }, + { + "id": 188, + "name": "Tasha Stevens", + "gender": "female", + "age": 77, + "address": { + "state": "Pennsylvania", + "city": "Staples" + } + }, + { + "id": 189, + "name": "Yvette Chang", + "gender": "female", + "age": 73, + "address": { + "state": "New York", + "city": "Fairhaven" + } + }, + { + "id": 190, + "name": "Sadie Duffy", + "gender": "female", + "age": 46, + "address": { + "state": "Michigan", + "city": "Hessville" + } + }, + { + "id": 191, + "name": "Savage Smith", + "gender": "male", + "age": 71, + "address": { + "state": "Tennessee", + "city": "Mansfield" + } + }, + { + "id": 192, + "name": "Monica Dunn", + "gender": "female", + "age": 53, + "address": { + "state": "New Hampshire", + "city": "Gracey" + } + }, + { + "id": 193, + "name": "Terrell Coffey", + "gender": "male", + "age": 75, + "address": { + "state": "Massachusetts", + "city": "Boonville" + } + }, + { + "id": 194, + "name": "Walsh Waller", + "gender": "male", + "age": 63, + "address": { + "state": "Hawaii", + "city": "Richville" + } + }, + { + "id": 195, + "name": "Bonnie Lamb", + "gender": "female", + "age": 22, + "address": { + "state": "South Carolina", + "city": "Finzel" + } + }, + { + "id": 196, + "name": "Frederick Hall", + "gender": "male", + "age": 56, + "address": { + "state": "West Virginia", + "city": "Kenvil" + } + }, + { + "id": 197, + "name": "Lana King", + "gender": "female", + "age": 40, + "address": { + "state": "Arizona", + "city": "Elrama" + } + }, + { + "id": 198, + "name": "Millie Boyer", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Blanford" + } + }, + { + "id": 199, + "name": "Daniels Ward", + "gender": "male", + "age": 38, + "address": { + "state": "Texas", + "city": "Coalmont" + } + }, + { + "id": 200, + "name": "Jeanie Baird", + "gender": "female", + "age": 25, + "address": { + "state": "New Jersey", + "city": "Fannett" + } + }, + { + "id": 201, + "name": "Paige White", + "gender": "female", + "age": 74, + "address": { + "state": "Kentucky", + "city": "Oneida" + } + }, + { + "id": 202, + "name": "Estes Robertson", + "gender": "male", + "age": 25, + "address": { + "state": "South Carolina", + "city": "Kirk" + } + }, + { + "id": 203, + "name": "Bernadine Pittman", + "gender": "female", + "age": 29, + "address": { + "state": "Alabama", + "city": "Magnolia" + } + }, + { + "id": 204, + "name": "Walton Sears", + "gender": "male", + "age": 27, + "address": { + "state": "Montana", + "city": "Groton" + } + }, + { + "id": 205, + "name": "Mayra Blevins", + "gender": "female", + "age": 48, + "address": { + "state": "Wisconsin", + "city": "Helen" + } + }, + { + "id": 206, + "name": "Tia Pacheco", + "gender": "female", + "age": 74, + "address": { + "state": "Missouri", + "city": "Brantleyville" + } + }, + { + "id": 207, + "name": "Sheena Stevenson", + "gender": "female", + "age": 75, + "address": { + "state": "Delaware", + "city": "Juntura" + } + }, + { + "id": 208, + "name": "Pearlie Raymond", + "gender": "female", + "age": 20, + "address": { + "state": "Tennessee", + "city": "Frizzleburg" + } + }, + { + "id": 209, + "name": "Daisy Hodge", + "gender": "female", + "age": 44, + "address": { + "state": "Connecticut", + "city": "Maplewood" + } + }, + { + "id": 210, + "name": "Anderson Hinton", + "gender": "male", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Orin" + } + }, + { + "id": 211, + "name": "Parsons Mcfadden", + "gender": "male", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Veyo" + } + }, + { + "id": 212, + "name": "Hood Carey", + "gender": "male", + "age": 33, + "address": { + "state": "Indiana", + "city": "Freetown" + } + }, + { + "id": 213, + "name": "Riley Lindsay", + "gender": "male", + "age": 53, + "address": { + "state": "Oregon", + "city": "Loretto" + } + }, + { + "id": 214, + "name": "Lenora Navarro", + "gender": "female", + "age": 22, + "address": { + "state": "Minnesota", + "city": "Vandiver" + } + }, + { + "id": 215, + "name": "Alba Donovan", + "gender": "female", + "age": 42, + "address": { + "state": "Nebraska", + "city": "Thatcher" + } + }, + { + "id": 216, + "name": "Lowery Mullen", + "gender": "male", + "age": 56, + "address": { + "state": "Iowa", + "city": "Lorraine" + } + }, + { + "id": 217, + "name": "Chaney Figueroa", + "gender": "male", + "age": 59, + "address": { + "state": "North Dakota", + "city": "Waterview" + } + }, + { + "id": 218, + "name": "Bruce Stein", + "gender": "male", + "age": 65, + "address": { + "state": "Michigan", + "city": "Grantville" + } + }, + { + "id": 219, + "name": "Tucker Pierce", + "gender": "male", + "age": 82, + "address": { + "state": "Colorado", + "city": "Zeba" + } + }, + { + "id": 220, + "name": "Isabelle Frederick", + "gender": "female", + "age": 64, + "address": { + "state": "Wyoming", + "city": "Snowville" + } + }, + { + "id": 221, + "name": "Terrie Sherman", + "gender": "female", + "age": 81, + "address": { + "state": "Maine", + "city": "Morgandale" + } + }, + { + "id": 222, + "name": "Rosario Henry", + "gender": "female", + "age": 75, + "address": { + "state": "New York", + "city": "Camas" + } + }, + { + "id": 223, + "name": "Francine Lester", + "gender": "female", + "age": 19, + "address": { + "state": "Virginia", + "city": "Inkerman" + } + }, + { + "id": 224, + "name": "Prince Melendez", + "gender": "male", + "age": 39, + "address": { + "state": "Idaho", + "city": "Marion" + } + }, + { + "id": 225, + "name": "Rice Lara", + "gender": "male", + "age": 21, + "address": { + "state": "Maryland", + "city": "Lindisfarne" + } + }, + { + "id": 226, + "name": "Elise Mckinney", + "gender": "female", + "age": 58, + "address": { + "state": "Alaska", + "city": "Madrid" + } + }, + { + "id": 227, + "name": "Jerri Kirby", + "gender": "female", + "age": 64, + "address": { + "state": "Georgia", + "city": "Chicopee" + } + }, + { + "id": 228, + "name": "Rene Leon", + "gender": "female", + "age": 43, + "address": { + "state": "Florida", + "city": "Bascom" + } + }, + { + "id": 229, + "name": "Karin Dennis", + "gender": "female", + "age": 46, + "address": { + "state": "Rhode Island", + "city": "Byrnedale" + } + }, + { + "id": 230, + "name": "Walter Craft", + "gender": "male", + "age": 45, + "address": { + "state": "Washington", + "city": "Sardis" + } + }, + { + "id": 231, + "name": "Morton Hunter", + "gender": "male", + "age": 32, + "address": { + "state": "Mississippi", + "city": "Twilight" + } + }, + { + "id": 232, + "name": "Beverley Shelton", + "gender": "female", + "age": 17, + "address": { + "state": "Ohio", + "city": "Gallina" + } + }, + { + "id": 233, + "name": "Kimberly Barnett", + "gender": "female", + "age": 54, + "address": { + "state": "Vermont", + "city": "Goldfield" + } + }, + { + "id": 234, + "name": "Esmeralda Randolph", + "gender": "female", + "age": 44, + "address": { + "state": "Louisiana", + "city": "Soham" + } + }, + { + "id": 235, + "name": "Lawrence Calderon", + "gender": "male", + "age": 57, + "address": { + "state": "Massachusetts", + "city": "Brady" + } + }, + { + "id": 236, + "name": "Monroe Olsen", + "gender": "male", + "age": 64, + "address": { + "state": "Utah", + "city": "Titanic" + } + }, + { + "id": 237, + "name": "Jolene Scott", + "gender": "female", + "age": 68, + "address": { + "state": "Arkansas", + "city": "Joes" + } + }, + { + "id": 238, + "name": "Herman Norman", + "gender": "male", + "age": 82, + "address": { + "state": "Hawaii", + "city": "Ferney" + } + }, + { + "id": 239, + "name": "Carpenter Larsen", + "gender": "male", + "age": 23, + "address": { + "state": "Pennsylvania", + "city": "Edgar" + } + }, + { + "id": 240, + "name": "Jaclyn Grant", + "gender": "female", + "age": 23, + "address": { + "state": "New Mexico", + "city": "Baden" + } + }, + { + "id": 241, + "name": "Doris Griffith", + "gender": "female", + "age": 46, + "address": { + "state": "South Dakota", + "city": "Barronett" + } + }, + { + "id": 242, + "name": "Bentley Booth", + "gender": "male", + "age": 26, + "address": { + "state": "Nevada", + "city": "Waukeenah" + } + }, + { + "id": 243, + "name": "Candy Strong", + "gender": "female", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Beaulieu" + } + }, + { + "id": 244, + "name": "Milagros Wooten", + "gender": "female", + "age": 18, + "address": { + "state": "Kansas", + "city": "Coldiron" + } + }, + { + "id": 245, + "name": "Dolores Jarvis", + "gender": "female", + "age": 56, + "address": { + "state": "Colorado", + "city": "Windsor" + } + }, + { + "id": 246, + "name": "Raymond Savage", + "gender": "male", + "age": 42, + "address": { + "state": "Indiana", + "city": "Dawn" + } + }, + { + "id": 247, + "name": "Wolfe Duran", + "gender": "male", + "age": 20, + "address": { + "state": "Michigan", + "city": "Crenshaw" + } + }, + { + "id": 248, + "name": "Gina Hampton", + "gender": "female", + "age": 26, + "address": { + "state": "Minnesota", + "city": "Taft" + } + }, + { + "id": 249, + "name": "Hodges Baldwin", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Dennard" + } + }, + { + "id": 250, + "name": "Duke Leon", + "gender": "male", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Groveville" + } + }, + { + "id": 251, + "name": "Sparks Bryan", + "gender": "male", + "age": 55, + "address": { + "state": "Idaho", + "city": "Rockingham" + } + }, + { + "id": 252, + "name": "Bobbi Mueller", + "gender": "female", + "age": 66, + "address": { + "state": "Maine", + "city": "Moquino" + } + }, + { + "id": 253, + "name": "Geneva Sargent", + "gender": "female", + "age": 74, + "address": { + "state": "Vermont", + "city": "Loyalhanna" + } + }, + { + "id": 254, + "name": "Lela Garner", + "gender": "female", + "age": 58, + "address": { + "state": "Arizona", + "city": "Sexton" + } + }, + { + "id": 255, + "name": "Yvette Navarro", + "gender": "female", + "age": 60, + "address": { + "state": "Alaska", + "city": "Hachita" + } + }, + { + "id": 256, + "name": "Cheryl Foley", + "gender": "female", + "age": 57, + "address": { + "state": "Tennessee", + "city": "Allison" + } + }, + { + "id": 257, + "name": "Amanda Wilkinson", + "gender": "female", + "age": 64, + "address": { + "state": "Missouri", + "city": "Cornucopia" + } + }, + { + "id": 258, + "name": "Hansen Hall", + "gender": "male", + "age": 53, + "address": { + "state": "Texas", + "city": "Logan" + } + }, + { + "id": 259, + "name": "Amalia Ingram", + "gender": "female", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Gouglersville" + } + }, + { + "id": 260, + "name": "Gross Valencia", + "gender": "male", + "age": 47, + "address": { + "state": "South Carolina", + "city": "Allentown" + } + }, + { + "id": 261, + "name": "Herminia Larson", + "gender": "female", + "age": 57, + "address": { + "state": "New York", + "city": "Longoria" + } + }, + { + "id": 262, + "name": "Rebecca Simon", + "gender": "female", + "age": 56, + "address": { + "state": "Ohio", + "city": "Calpine" + } + }, + { + "id": 263, + "name": "Lynne Callahan", + "gender": "female", + "age": 54, + "address": { + "state": "North Carolina", + "city": "Avalon" + } + }, + { + "id": 264, + "name": "Carolina Cherry", + "gender": "female", + "age": 36, + "address": { + "state": "West Virginia", + "city": "Russellville" + } + }, + { + "id": 265, + "name": "Jensen Mcfarland", + "gender": "male", + "age": 24, + "address": { + "state": "Arkansas", + "city": "Felt" + } + }, + { + "id": 266, + "name": "Chandler Patterson", + "gender": "male", + "age": 61, + "address": { + "state": "Pennsylvania", + "city": "Maxville" + } + }, + { + "id": 267, + "name": "Celeste Leblanc", + "gender": "female", + "age": 20, + "address": { + "state": "Oregon", + "city": "Lowell" + } + }, + { + "id": 268, + "name": "Jacklyn Erickson", + "gender": "female", + "age": 71, + "address": { + "state": "Kansas", + "city": "Aurora" + } + }, + { + "id": 269, + "name": "Frank Cooley", + "gender": "male", + "age": 71, + "address": { + "state": "Rhode Island", + "city": "Machias" + } + }, + { + "id": 270, + "name": "Sheri Maddox", + "gender": "female", + "age": 20, + "address": { + "state": "South Dakota", + "city": "Lutsen" + } + }, + { + "id": 271, + "name": "Pam Blanchard", + "gender": "female", + "age": 71, + "address": { + "state": "Mississippi", + "city": "Mahtowa" + } + }, + { + "id": 272, + "name": "Louisa David", + "gender": "female", + "age": 58, + "address": { + "state": "California", + "city": "Cloverdale" + } + }, + { + "id": 273, + "name": "Harper Higgins", + "gender": "male", + "age": 50, + "address": { + "state": "Utah", + "city": "Watrous" + } + }, + { + "id": 274, + "name": "Crosby Rojas", + "gender": "male", + "age": 62, + "address": { + "state": "Virginia", + "city": "Echo" + } + }, + { + "id": 275, + "name": "Mavis Petersen", + "gender": "female", + "age": 59, + "address": { + "state": "Montana", + "city": "Conway" + } + }, + { + "id": 276, + "name": "Daphne Forbes", + "gender": "female", + "age": 19, + "address": { + "state": "Georgia", + "city": "Topaz" + } + }, + { + "id": 277, + "name": "Trudy Moreno", + "gender": "female", + "age": 47, + "address": { + "state": "Nevada", + "city": "Carbonville" + } + }, + { + "id": 278, + "name": "Katy Kirby", + "gender": "female", + "age": 38, + "address": { + "state": "Louisiana", + "city": "Rodanthe" + } + }, + { + "id": 279, + "name": "Soto Moses", + "gender": "male", + "age": 17, + "address": { + "state": "Alabama", + "city": "Croom" + } + }, + { + "id": 280, + "name": "Lindsay Camacho", + "gender": "female", + "age": 44, + "address": { + "state": "Wisconsin", + "city": "Dellview" + } + }, + { + "id": 281, + "name": "Priscilla Lott", + "gender": "female", + "age": 72, + "address": { + "state": "Washington", + "city": "Galesville" + } + }, + { + "id": 282, + "name": "Luann Schneider", + "gender": "female", + "age": 71, + "address": { + "state": "New Jersey", + "city": "Geyserville" + } + }, + { + "id": 283, + "name": "Walls Suarez", + "gender": "male", + "age": 39, + "address": { + "state": "Iowa", + "city": "Davenport" + } + }, + { + "id": 284, + "name": "Blanca Mack", + "gender": "female", + "age": 36, + "address": { + "state": "Kentucky", + "city": "Clayville" + } + }, + { + "id": 285, + "name": "Bettye Riley", + "gender": "female", + "age": 82, + "address": { + "state": "New Mexico", + "city": "Shrewsbury" + } + }, + { + "id": 286, + "name": "Pratt Foster", + "gender": "male", + "age": 44, + "address": { + "state": "Massachusetts", + "city": "Marbury" + } + }, + { + "id": 287, + "name": "Crane Crane", + "gender": "male", + "age": 64, + "address": { + "state": "Delaware", + "city": "Matheny" + } + }, + { + "id": 288, + "name": "Velasquez Patel", + "gender": "male", + "age": 41, + "address": { + "state": "Florida", + "city": "Sugartown" + } + }, + { + "id": 289, + "name": "Burns Shaffer", + "gender": "male", + "age": 42, + "address": { + "state": "Hawaii", + "city": "Homestead" + } + }, + { + "id": 290, + "name": "Norton Villarreal", + "gender": "male", + "age": 50, + "address": { + "state": "North Dakota", + "city": "Gorst" + } + }, + { + "id": 291, + "name": "Berger Ratliff", + "gender": "male", + "age": 27, + "address": { + "state": "New Hampshire", + "city": "Ivanhoe" + } + }, + { + "id": 292, + "name": "Jessie Willis", + "gender": "female", + "age": 73, + "address": { + "state": "Maryland", + "city": "Drytown" + } + }, + { + "id": 293, + "name": "Lottie Salazar", + "gender": "female", + "age": 71, + "address": { + "state": "Connecticut", + "city": "Templeton" + } + }, + { + "id": 294, + "name": "Hays Abbott", + "gender": "male", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Cloverdale" + } + }, + { + "id": 295, + "name": "Webb Hamilton", + "gender": "male", + "age": 69, + "address": { + "state": "Nevada", + "city": "Allamuchy" + } + }, + { + "id": 296, + "name": "Renee York", + "gender": "female", + "age": 82, + "address": { + "state": "Ohio", + "city": "Bladensburg" + } + }, + { + "id": 297, + "name": "Ellis Davis", + "gender": "male", + "age": 72, + "address": { + "state": "Virginia", + "city": "Comptche" + } + }, + { + "id": 298, + "name": "Beard Patterson", + "gender": "male", + "age": 63, + "address": { + "state": "Texas", + "city": "Chamizal" + } + }, + { + "id": 299, + "name": "Fletcher Walters", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Morgandale" + } + }, + { + "id": 300, + "name": "Eddie Reid", + "gender": "female", + "age": 59, + "address": { + "state": "Mississippi", + "city": "Chautauqua" + } + }, + { + "id": 301, + "name": "Gilmore Wolfe", + "gender": "male", + "age": 44, + "address": { + "state": "Kansas", + "city": "Denio" + } + }, + { + "id": 302, + "name": "Jannie Wooten", + "gender": "female", + "age": 40, + "address": { + "state": "Missouri", + "city": "Golconda" + } + }, + { + "id": 303, + "name": "Etta Paul", + "gender": "female", + "age": 69, + "address": { + "state": "Wyoming", + "city": "Naomi" + } + }, + { + "id": 304, + "name": "Mcintyre Duffy", + "gender": "male", + "age": 52, + "address": { + "state": "Vermont", + "city": "Wanship" + } + }, + { + "id": 305, + "name": "Mai Talley", + "gender": "female", + "age": 26, + "address": { + "state": "Washington", + "city": "Whipholt" + } + }, + { + "id": 306, + "name": "Hodge Solomon", + "gender": "male", + "age": 52, + "address": { + "state": "Maryland", + "city": "Yettem" + } + }, + { + "id": 307, + "name": "Patricia Dominguez", + "gender": "female", + "age": 22, + "address": { + "state": "New Hampshire", + "city": "Graball" + } + }, + { + "id": 308, + "name": "Jaime Noel", + "gender": "female", + "age": 24, + "address": { + "state": "North Carolina", + "city": "Manchester" + } + }, + { + "id": 309, + "name": "Bailey Gross", + "gender": "male", + "age": 78, + "address": { + "state": "Georgia", + "city": "Orovada" + } + }, + { + "id": 310, + "name": "Davidson Dunn", + "gender": "male", + "age": 24, + "address": { + "state": "North Dakota", + "city": "Heil" + } + }, + { + "id": 311, + "name": "Velez Stokes", + "gender": "male", + "age": 42, + "address": { + "state": "Iowa", + "city": "Gilmore" + } + }, + { + "id": 312, + "name": "Pearlie Garcia", + "gender": "female", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Beyerville" + } + }, + { + "id": 313, + "name": "Lena Park", + "gender": "female", + "age": 47, + "address": { + "state": "South Dakota", + "city": "Innsbrook" + } + }, + { + "id": 314, + "name": "England Nixon", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Allison" + } + }, + { + "id": 315, + "name": "Carolina Golden", + "gender": "female", + "age": 36, + "address": { + "state": "Arizona", + "city": "Kraemer" + } + }, + { + "id": 316, + "name": "Holmes Nash", + "gender": "male", + "age": 25, + "address": { + "state": "New York", + "city": "Yorklyn" + } + }, + { + "id": 317, + "name": "Rosanne Neal", + "gender": "female", + "age": 64, + "address": { + "state": "Arkansas", + "city": "Glasgow" + } + }, + { + "id": 318, + "name": "Chase Walls", + "gender": "male", + "age": 42, + "address": { + "state": "Connecticut", + "city": "Skyland" + } + }, + { + "id": 319, + "name": "Casandra Mitchell", + "gender": "female", + "age": 69, + "address": { + "state": "Wisconsin", + "city": "Hoagland" + } + }, + { + "id": 320, + "name": "Phelps Barrera", + "gender": "male", + "age": 31, + "address": { + "state": "Tennessee", + "city": "Guthrie" + } + }, + { + "id": 321, + "name": "Haley Macias", + "gender": "female", + "age": 71, + "address": { + "state": "New Jersey", + "city": "Hoehne" + } + }, + { + "id": 322, + "name": "Darlene Lara", + "gender": "female", + "age": 72, + "address": { + "state": "Minnesota", + "city": "Stonybrook" + } + }, + { + "id": 323, + "name": "Rasmussen Hyde", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Ruffin" + } + }, + { + "id": 324, + "name": "Mayo Garrison", + "gender": "male", + "age": 38, + "address": { + "state": "Idaho", + "city": "Forestburg" + } + }, + { + "id": 325, + "name": "Wilder Bentley", + "gender": "male", + "age": 53, + "address": { + "state": "Montana", + "city": "Masthope" + } + }, + { + "id": 326, + "name": "Tammy Charles", + "gender": "female", + "age": 76, + "address": { + "state": "Hawaii", + "city": "Leming" + } + }, + { + "id": 327, + "name": "Lizzie Gardner", + "gender": "female", + "age": 42, + "address": { + "state": "South Carolina", + "city": "National" + } + }, + { + "id": 328, + "name": "York Hampton", + "gender": "male", + "age": 75, + "address": { + "state": "Illinois", + "city": "Rossmore" + } + }, + { + "id": 329, + "name": "Hays Leonard", + "gender": "male", + "age": 70, + "address": { + "state": "Maine", + "city": "Kipp" + } + }, + { + "id": 330, + "name": "Calderon Nolan", + "gender": "male", + "age": 26, + "address": { + "state": "Alaska", + "city": "Drytown" + } + }, + { + "id": 331, + "name": "Alisha Clarke", + "gender": "female", + "age": 20, + "address": { + "state": "Pennsylvania", + "city": "Welch" + } + }, + { + "id": 332, + "name": "Deidre Vaughn", + "gender": "female", + "age": 32, + "address": { + "state": "California", + "city": "Cucumber" + } + }, + { + "id": 333, + "name": "Colon Fox", + "gender": "male", + "age": 19, + "address": { + "state": "Oregon", + "city": "Tuttle" + } + }, + { + "id": 334, + "name": "Marshall Vang", + "gender": "male", + "age": 46, + "address": { + "state": "Utah", + "city": "Lund" + } + }, + { + "id": 335, + "name": "Ayala Rhodes", + "gender": "male", + "age": 62, + "address": { + "state": "Michigan", + "city": "Bradenville" + } + }, + { + "id": 336, + "name": "Morrow Garrett", + "gender": "male", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Rivers" + } + }, + { + "id": 337, + "name": "Brenda Carey", + "gender": "female", + "age": 69, + "address": { + "state": "Oklahoma", + "city": "Westwood" + } + }, + { + "id": 338, + "name": "Abby Collins", + "gender": "female", + "age": 80, + "address": { + "state": "Indiana", + "city": "Westerville" + } + }, + { + "id": 339, + "name": "Whitney Hays", + "gender": "male", + "age": 51, + "address": { + "state": "Delaware", + "city": "Crisman" + } + }, + { + "id": 340, + "name": "Faulkner Aguirre", + "gender": "male", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Mulino" + } + }, + { + "id": 341, + "name": "Angelina Dickson", + "gender": "female", + "age": 55, + "address": { + "state": "Kentucky", + "city": "Verdi" + } + }, + { + "id": 342, + "name": "Skinner Rivera", + "gender": "male", + "age": 23, + "address": { + "state": "Massachusetts", + "city": "Greenbackville" + } + }, + { + "id": 343, + "name": "Natasha Cochran", + "gender": "female", + "age": 80, + "address": { + "state": "North Dakota", + "city": "Forbestown" + } + }, + { + "id": 344, + "name": "Carol Ellison", + "gender": "female", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Calvary" + } + }, + { + "id": 345, + "name": "Emma Best", + "gender": "female", + "age": 21, + "address": { + "state": "Alabama", + "city": "Statenville" + } + }, + { + "id": 346, + "name": "Sharpe Murphy", + "gender": "male", + "age": 78, + "address": { + "state": "Washington", + "city": "Moraida" + } + }, + { + "id": 347, + "name": "Knight Valentine", + "gender": "male", + "age": 22, + "address": { + "state": "Iowa", + "city": "Loretto" + } + }, + { + "id": 348, + "name": "Padilla Tanner", + "gender": "male", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Grill" + } + }, + { + "id": 349, + "name": "Elena Oliver", + "gender": "female", + "age": 51, + "address": { + "state": "Utah", + "city": "Fannett" + } + }, + { + "id": 350, + "name": "Ana Acevedo", + "gender": "female", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Gibbsville" + } + }, + { + "id": 351, + "name": "Dejesus Rogers", + "gender": "male", + "age": 39, + "address": { + "state": "Maine", + "city": "Lowell" + } + }, + { + "id": 352, + "name": "Ware Wolf", + "gender": "male", + "age": 69, + "address": { + "state": "Arizona", + "city": "Reinerton" + } + }, + { + "id": 353, + "name": "Gutierrez Dennis", + "gender": "male", + "age": 58, + "address": { + "state": "Montana", + "city": "Jardine" + } + }, + { + "id": 354, + "name": "Elsie Nguyen", + "gender": "female", + "age": 46, + "address": { + "state": "Nebraska", + "city": "Eggertsville" + } + }, + { + "id": 355, + "name": "Nelda Cline", + "gender": "female", + "age": 68, + "address": { + "state": "Nevada", + "city": "Carlos" + } + }, + { + "id": 356, + "name": "Ina Beard", + "gender": "female", + "age": 77, + "address": { + "state": "Delaware", + "city": "Edmund" + } + }, + { + "id": 357, + "name": "Gould Velez", + "gender": "male", + "age": 48, + "address": { + "state": "California", + "city": "Kennedyville" + } + }, + { + "id": 358, + "name": "Mamie Lee", + "gender": "female", + "age": 66, + "address": { + "state": "Rhode Island", + "city": "Brazos" + } + }, + { + "id": 359, + "name": "Adele Mcconnell", + "gender": "female", + "age": 66, + "address": { + "state": "Tennessee", + "city": "Springhill" + } + }, + { + "id": 360, + "name": "Susan Moran", + "gender": "female", + "age": 72, + "address": { + "state": "Arkansas", + "city": "Floris" + } + }, + { + "id": 361, + "name": "Shauna Slater", + "gender": "female", + "age": 18, + "address": { + "state": "Mississippi", + "city": "Norris" + } + }, + { + "id": 362, + "name": "Blevins Jacobson", + "gender": "male", + "age": 79, + "address": { + "state": "Michigan", + "city": "Stockwell" + } + }, + { + "id": 363, + "name": "Janie Yates", + "gender": "female", + "age": 73, + "address": { + "state": "South Carolina", + "city": "Chelsea" + } + }, + { + "id": 364, + "name": "Horton Hancock", + "gender": "male", + "age": 71, + "address": { + "state": "Missouri", + "city": "Bagtown" + } + }, + { + "id": 365, + "name": "Juarez Miles", + "gender": "male", + "age": 18, + "address": { + "state": "Indiana", + "city": "Brookfield" + } + }, + { + "id": 366, + "name": "Winifred Vaughn", + "gender": "female", + "age": 57, + "address": { + "state": "Colorado", + "city": "Fresno" + } + }, + { + "id": 367, + "name": "Harrison Mendez", + "gender": "male", + "age": 62, + "address": { + "state": "Wyoming", + "city": "Riviera" + } + }, + { + "id": 368, + "name": "Anthony Patterson", + "gender": "male", + "age": 69, + "address": { + "state": "New Hampshire", + "city": "Weedville" + } + }, + { + "id": 369, + "name": "Roxie Rhodes", + "gender": "female", + "age": 58, + "address": { + "state": "Pennsylvania", + "city": "Buxton" + } + }, + { + "id": 370, + "name": "Maddox Marshall", + "gender": "male", + "age": 20, + "address": { + "state": "New Jersey", + "city": "Marshall" + } + }, + { + "id": 371, + "name": "Ashley Lawson", + "gender": "male", + "age": 60, + "address": { + "state": "Wisconsin", + "city": "Wanship" + } + }, + { + "id": 372, + "name": "Shelby Bray", + "gender": "female", + "age": 24, + "address": { + "state": "Kentucky", + "city": "Wakarusa" + } + }, + { + "id": 373, + "name": "Olive Hutchinson", + "gender": "female", + "age": 42, + "address": { + "state": "Texas", + "city": "Beaulieu" + } + }, + { + "id": 374, + "name": "Lora Summers", + "gender": "female", + "age": 18, + "address": { + "state": "Illinois", + "city": "Keyport" + } + }, + { + "id": 375, + "name": "Dixie Hogan", + "gender": "female", + "age": 64, + "address": { + "state": "Alaska", + "city": "Takilma" + } + }, + { + "id": 376, + "name": "Steele Sanford", + "gender": "male", + "age": 76, + "address": { + "state": "Ohio", + "city": "Kipp" + } + }, + { + "id": 377, + "name": "Josephine Todd", + "gender": "female", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Durham" + } + }, + { + "id": 378, + "name": "George Blair", + "gender": "male", + "age": 61, + "address": { + "state": "Idaho", + "city": "Marne" + } + }, + { + "id": 379, + "name": "Ramirez Hansen", + "gender": "male", + "age": 62, + "address": { + "state": "Georgia", + "city": "Carrizo" + } + }, + { + "id": 380, + "name": "Weeks Murray", + "gender": "male", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Esmont" + } + }, + { + "id": 381, + "name": "Yang Trujillo", + "gender": "male", + "age": 66, + "address": { + "state": "Massachusetts", + "city": "Wanamie" + } + }, + { + "id": 382, + "name": "Clarissa Christian", + "gender": "female", + "age": 40, + "address": { + "state": "Connecticut", + "city": "Whipholt" + } + }, + { + "id": 383, + "name": "Milagros Gross", + "gender": "female", + "age": 22, + "address": { + "state": "Maryland", + "city": "Leroy" + } + }, + { + "id": 384, + "name": "Carlene Walter", + "gender": "female", + "age": 40, + "address": { + "state": "North Carolina", + "city": "Dellview" + } + }, + { + "id": 385, + "name": "Alexandra Rice", + "gender": "female", + "age": 81, + "address": { + "state": "New York", + "city": "Faxon" + } + }, + { + "id": 386, + "name": "Underwood Pratt", + "gender": "male", + "age": 61, + "address": { + "state": "Virginia", + "city": "Elizaville" + } + }, + { + "id": 387, + "name": "Moore Caldwell", + "gender": "male", + "age": 66, + "address": { + "state": "Hawaii", + "city": "Newkirk" + } + }, + { + "id": 388, + "name": "Simpson Flowers", + "gender": "male", + "age": 22, + "address": { + "state": "Vermont", + "city": "Levant" + } + }, + { + "id": 389, + "name": "Wilma Hawkins", + "gender": "female", + "age": 82, + "address": { + "state": "Florida", + "city": "Hasty" + } + }, + { + "id": 390, + "name": "Griffin Wolfe", + "gender": "male", + "age": 82, + "address": { + "state": "Kansas", + "city": "Caln" + } + }, + { + "id": 391, + "name": "Sallie Marquez", + "gender": "female", + "age": 58, + "address": { + "state": "Oregon", + "city": "Berwind" + } + }, + { + "id": 392, + "name": "Thelma Bolton", + "gender": "female", + "age": 34, + "address": { + "state": "Indiana", + "city": "Cumminsville" + } + }, + { + "id": 393, + "name": "Stacy Sherman", + "gender": "female", + "age": 70, + "address": { + "state": "Massachusetts", + "city": "Newry" + } + }, + { + "id": 394, + "name": "Lauren Rodriquez", + "gender": "female", + "age": 34, + "address": { + "state": "New York", + "city": "Springhill" + } + }, + { + "id": 395, + "name": "Nelson Duffy", + "gender": "male", + "age": 60, + "address": { + "state": "South Carolina", + "city": "Bawcomville" + } + }, + { + "id": 396, + "name": "James Mercado", + "gender": "female", + "age": 43, + "address": { + "state": "New Mexico", + "city": "Shindler" + } + }, + { + "id": 397, + "name": "Marguerite Nielsen", + "gender": "female", + "age": 57, + "address": { + "state": "Kansas", + "city": "Hillsboro" + } + }, + { + "id": 398, + "name": "Mindy Carver", + "gender": "female", + "age": 58, + "address": { + "state": "Minnesota", + "city": "Gratton" + } + }, + { + "id": 399, + "name": "Darla Page", + "gender": "female", + "age": 61, + "address": { + "state": "Illinois", + "city": "Ribera" + } + }, + { + "id": 400, + "name": "Willa Booker", + "gender": "female", + "age": 46, + "address": { + "state": "Oklahoma", + "city": "Gracey" + } + }, + { + "id": 401, + "name": "Dee Cantrell", + "gender": "female", + "age": 21, + "address": { + "state": "West Virginia", + "city": "Bodega" + } + }, + { + "id": 402, + "name": "Trudy Kinney", + "gender": "female", + "age": 82, + "address": { + "state": "Texas", + "city": "Axis" + } + }, + { + "id": 403, + "name": "Nguyen Mills", + "gender": "male", + "age": 51, + "address": { + "state": "Georgia", + "city": "Lawrence" + } + }, + { + "id": 404, + "name": "Williams Davidson", + "gender": "male", + "age": 19, + "address": { + "state": "Alabama", + "city": "Jacumba" + } + }, + { + "id": 405, + "name": "Banks Flores", + "gender": "male", + "age": 46, + "address": { + "state": "Delaware", + "city": "Emerald" + } + }, + { + "id": 406, + "name": "Polly Merritt", + "gender": "female", + "age": 46, + "address": { + "state": "Maine", + "city": "Cawood" + } + }, + { + "id": 407, + "name": "Gillespie Kemp", + "gender": "male", + "age": 75, + "address": { + "state": "Arkansas", + "city": "Oceola" + } + }, + { + "id": 408, + "name": "Velma Hobbs", + "gender": "female", + "age": 39, + "address": { + "state": "Louisiana", + "city": "Hollins" + } + }, + { + "id": 409, + "name": "Lena Rice", + "gender": "female", + "age": 66, + "address": { + "state": "Ohio", + "city": "Oretta" + } + }, + { + "id": 410, + "name": "Nieves Reeves", + "gender": "male", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Urbana" + } + }, + { + "id": 411, + "name": "Misty Barry", + "gender": "female", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Shepardsville" + } + }, + { + "id": 412, + "name": "Jeanette Vang", + "gender": "female", + "age": 24, + "address": { + "state": "Tennessee", + "city": "Derwood" + } + }, + { + "id": 413, + "name": "Emily Berg", + "gender": "female", + "age": 43, + "address": { + "state": "New Hampshire", + "city": "Eagletown" + } + }, + { + "id": 414, + "name": "Esmeralda Foreman", + "gender": "female", + "age": 31, + "address": { + "state": "South Dakota", + "city": "Chamberino" + } + }, + { + "id": 415, + "name": "Downs Walter", + "gender": "male", + "age": 36, + "address": { + "state": "Nevada", + "city": "Newkirk" + } + }, + { + "id": 416, + "name": "Santos Morse", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Whitestone" + } + }, + { + "id": 417, + "name": "Nicole Martin", + "gender": "female", + "age": 68, + "address": { + "state": "Colorado", + "city": "Orick" + } + }, + { + "id": 418, + "name": "Jensen Snow", + "gender": "male", + "age": 49, + "address": { + "state": "Kentucky", + "city": "Coldiron" + } + }, + { + "id": 419, + "name": "Anna Patterson", + "gender": "female", + "age": 20, + "address": { + "state": "North Carolina", + "city": "Blandburg" + } + }, + { + "id": 420, + "name": "Newton Ware", + "gender": "male", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Mooresburg" + } + }, + { + "id": 421, + "name": "Farmer Kirby", + "gender": "male", + "age": 70, + "address": { + "state": "California", + "city": "Highland" + } + }, + { + "id": 422, + "name": "Morin Soto", + "gender": "male", + "age": 25, + "address": { + "state": "North Dakota", + "city": "Finderne" + } + }, + { + "id": 423, + "name": "Barrett Small", + "gender": "male", + "age": 34, + "address": { + "state": "Virginia", + "city": "Cassel" + } + }, + { + "id": 424, + "name": "Rutledge Suarez", + "gender": "male", + "age": 21, + "address": { + "state": "Arizona", + "city": "Defiance" + } + }, + { + "id": 425, + "name": "Harvey Salinas", + "gender": "male", + "age": 80, + "address": { + "state": "Montana", + "city": "Colton" + } + }, + { + "id": 426, + "name": "Norman Hansen", + "gender": "male", + "age": 33, + "address": { + "state": "Wyoming", + "city": "Chemung" + } + }, + { + "id": 427, + "name": "Alba Potter", + "gender": "female", + "age": 80, + "address": { + "state": "Utah", + "city": "Hachita" + } + }, + { + "id": 428, + "name": "Bates Petty", + "gender": "male", + "age": 68, + "address": { + "state": "Oregon", + "city": "Williamson" + } + }, + { + "id": 429, + "name": "Mays Shepherd", + "gender": "male", + "age": 63, + "address": { + "state": "Rhode Island", + "city": "Islandia" + } + }, + { + "id": 430, + "name": "Marisol Carr", + "gender": "female", + "age": 33, + "address": { + "state": "Iowa", + "city": "Imperial" + } + }, + { + "id": 431, + "name": "Michael Murphy", + "gender": "male", + "age": 71, + "address": { + "state": "Maryland", + "city": "Garberville" + } + }, + { + "id": 432, + "name": "Chan Mercer", + "gender": "male", + "age": 73, + "address": { + "state": "Idaho", + "city": "Kiskimere" + } + }, + { + "id": 433, + "name": "Ida Hunter", + "gender": "female", + "age": 50, + "address": { + "state": "Washington", + "city": "Warren" + } + }, + { + "id": 434, + "name": "Muriel Walsh", + "gender": "female", + "age": 48, + "address": { + "state": "New Jersey", + "city": "Mathews" + } + }, + { + "id": 435, + "name": "Navarro Case", + "gender": "male", + "age": 35, + "address": { + "state": "Missouri", + "city": "Kenwood" + } + }, + { + "id": 436, + "name": "Carlson Glover", + "gender": "male", + "age": 70, + "address": { + "state": "Alaska", + "city": "Alleghenyville" + } + }, + { + "id": 437, + "name": "Osborne Diaz", + "gender": "male", + "age": 62, + "address": { + "state": "Nebraska", + "city": "Gadsden" + } + }, + { + "id": 438, + "name": "Clare Pruitt", + "gender": "female", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Freelandville" + } + }, + { + "id": 439, + "name": "Miranda Chaney", + "gender": "female", + "age": 62, + "address": { + "state": "Mississippi", + "city": "Trail" + } + }, + { + "id": 440, + "name": "Emilia Hess", + "gender": "female", + "age": 62, + "address": { + "state": "Florida", + "city": "Cuylerville" + } + }, + { + "id": 441, + "name": "Monique Johnston", + "gender": "female", + "age": 65, + "address": { + "state": "Colorado", + "city": "Fillmore" + } + }, + { + "id": 442, + "name": "Sanford Golden", + "gender": "male", + "age": 31, + "address": { + "state": "Pennsylvania", + "city": "Belva" + } + }, + { + "id": 443, + "name": "Estrada Phelps", + "gender": "male", + "age": 34, + "address": { + "state": "Hawaii", + "city": "Emerald" + } + }, + { + "id": 444, + "name": "Ellen Heath", + "gender": "female", + "age": 50, + "address": { + "state": "Nevada", + "city": "Gorham" + } + }, + { + "id": 445, + "name": "Charles Floyd", + "gender": "male", + "age": 27, + "address": { + "state": "Minnesota", + "city": "Starks" + } + }, + { + "id": 446, + "name": "Vilma Tyler", + "gender": "female", + "age": 40, + "address": { + "state": "Louisiana", + "city": "Roland" + } + }, + { + "id": 447, + "name": "Stacy Melendez", + "gender": "female", + "age": 20, + "address": { + "state": "New York", + "city": "Blackgum" + } + }, + { + "id": 448, + "name": "Coffey Callahan", + "gender": "male", + "age": 63, + "address": { + "state": "North Dakota", + "city": "Carrsville" + } + }, + { + "id": 449, + "name": "Vicky Hood", + "gender": "female", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Brewster" + } + }, + { + "id": 450, + "name": "Maryann Harding", + "gender": "female", + "age": 33, + "address": { + "state": "New Jersey", + "city": "Heil" + } + }, + { + "id": 451, + "name": "Willis Pitts", + "gender": "male", + "age": 51, + "address": { + "state": "Kansas", + "city": "Winesburg" + } + }, + { + "id": 452, + "name": "Daphne Reilly", + "gender": "female", + "age": 68, + "address": { + "state": "Kentucky", + "city": "Wawona" + } + }, + { + "id": 453, + "name": "Morton English", + "gender": "male", + "age": 79, + "address": { + "state": "Iowa", + "city": "Cumberland" + } + }, + { + "id": 454, + "name": "Chavez Harper", + "gender": "male", + "age": 62, + "address": { + "state": "Arkansas", + "city": "Blanford" + } + }, + { + "id": 455, + "name": "Vicki Mosley", + "gender": "female", + "age": 38, + "address": { + "state": "Delaware", + "city": "Walland" + } + }, + { + "id": 456, + "name": "Love Sims", + "gender": "male", + "age": 26, + "address": { + "state": "South Dakota", + "city": "Kylertown" + } + }, + { + "id": 457, + "name": "Dickson Warren", + "gender": "male", + "age": 61, + "address": { + "state": "Oregon", + "city": "Dalton" + } + }, + { + "id": 458, + "name": "Mack Palmer", + "gender": "male", + "age": 79, + "address": { + "state": "Texas", + "city": "Lafferty" + } + }, + { + "id": 459, + "name": "Anna Bradshaw", + "gender": "female", + "age": 72, + "address": { + "state": "Alabama", + "city": "Saddlebrooke" + } + }, + { + "id": 460, + "name": "Petersen Butler", + "gender": "male", + "age": 78, + "address": { + "state": "Rhode Island", + "city": "Caspar" + } + }, + { + "id": 461, + "name": "Briana Tanner", + "gender": "female", + "age": 73, + "address": { + "state": "Illinois", + "city": "Cresaptown" + } + }, + { + "id": 462, + "name": "Mason England", + "gender": "male", + "age": 75, + "address": { + "state": "Maryland", + "city": "Romeville" + } + }, + { + "id": 463, + "name": "Cotton Bowman", + "gender": "male", + "age": 19, + "address": { + "state": "South Carolina", + "city": "Hemlock" + } + }, + { + "id": 464, + "name": "Morin Hayden", + "gender": "male", + "age": 40, + "address": { + "state": "Indiana", + "city": "Worcester" + } + }, + { + "id": 465, + "name": "Natasha Humphrey", + "gender": "female", + "age": 59, + "address": { + "state": "Virginia", + "city": "Weedville" + } + }, + { + "id": 466, + "name": "Joyner Velasquez", + "gender": "male", + "age": 22, + "address": { + "state": "Florida", + "city": "Greenwich" + } + }, + { + "id": 467, + "name": "Charlene Gutierrez", + "gender": "female", + "age": 70, + "address": { + "state": "Arizona", + "city": "Hiko" + } + }, + { + "id": 468, + "name": "Chan Hubbard", + "gender": "male", + "age": 39, + "address": { + "state": "Maine", + "city": "Boling" + } + }, + { + "id": 469, + "name": "Kristen Knapp", + "gender": "female", + "age": 49, + "address": { + "state": "Oklahoma", + "city": "Vale" + } + }, + { + "id": 470, + "name": "Preston Chapman", + "gender": "male", + "age": 73, + "address": { + "state": "Vermont", + "city": "Kenmar" + } + }, + { + "id": 471, + "name": "Aguilar Singleton", + "gender": "male", + "age": 40, + "address": { + "state": "New Mexico", + "city": "Gratton" + } + }, + { + "id": 472, + "name": "Berry Montoya", + "gender": "male", + "age": 36, + "address": { + "state": "Tennessee", + "city": "Dowling" + } + }, + { + "id": 473, + "name": "Terrie Rowland", + "gender": "female", + "age": 72, + "address": { + "state": "Connecticut", + "city": "Catherine" + } + }, + { + "id": 474, + "name": "Nichole Holland", + "gender": "female", + "age": 63, + "address": { + "state": "Nebraska", + "city": "Wintersburg" + } + }, + { + "id": 475, + "name": "Stevens Lee", + "gender": "male", + "age": 66, + "address": { + "state": "Georgia", + "city": "Berlin" + } + }, + { + "id": 476, + "name": "Florine Dunlap", + "gender": "female", + "age": 75, + "address": { + "state": "Montana", + "city": "Bancroft" + } + }, + { + "id": 477, + "name": "Bartlett Diaz", + "gender": "male", + "age": 78, + "address": { + "state": "Utah", + "city": "Ahwahnee" + } + }, + { + "id": 478, + "name": "Kasey Mendoza", + "gender": "female", + "age": 19, + "address": { + "state": "North Carolina", + "city": "Roulette" + } + }, + { + "id": 479, + "name": "Lakisha Eaton", + "gender": "female", + "age": 47, + "address": { + "state": "Ohio", + "city": "Statenville" + } + }, + { + "id": 480, + "name": "Flores Mills", + "gender": "male", + "age": 76, + "address": { + "state": "Missouri", + "city": "Adelino" + } + }, + { + "id": 481, + "name": "Pat Hardy", + "gender": "female", + "age": 20, + "address": { + "state": "California", + "city": "Somerset" + } + }, + { + "id": 482, + "name": "Esther Stafford", + "gender": "female", + "age": 45, + "address": { + "state": "Idaho", + "city": "Hackneyville" + } + }, + { + "id": 483, + "name": "Reeves Gonzales", + "gender": "male", + "age": 41, + "address": { + "state": "Alaska", + "city": "Boomer" + } + }, + { + "id": 484, + "name": "Pamela Abbott", + "gender": "female", + "age": 36, + "address": { + "state": "Michigan", + "city": "Cumminsville" + } + }, + { + "id": 485, + "name": "Tamra Cash", + "gender": "female", + "age": 32, + "address": { + "state": "Washington", + "city": "Norfolk" + } + }, + { + "id": 486, + "name": "Haley Park", + "gender": "female", + "age": 69, + "address": { + "state": "New Hampshire", + "city": "Holcombe" + } + }, + { + "id": 487, + "name": "Chapman Cook", + "gender": "male", + "age": 54, + "address": { + "state": "Wisconsin", + "city": "Brethren" + } + }, + { + "id": 488, + "name": "Mitchell Pugh", + "gender": "male", + "age": 71, + "address": { + "state": "West Virginia", + "city": "Ogema" + } + }, + { + "id": 489, + "name": "Hess Lynch", + "gender": "male", + "age": 20, + "address": { + "state": "Mississippi", + "city": "Wedgewood" + } + }, + { + "id": 490, + "name": "Dorthy Doyle", + "gender": "female", + "age": 31, + "address": { + "state": "Kansas", + "city": "Gwynn" + } + }, + { + "id": 491, + "name": "Cobb Merritt", + "gender": "male", + "age": 65, + "address": { + "state": "Nebraska", + "city": "Leeper" + } + }, + { + "id": 492, + "name": "Joy Horn", + "gender": "female", + "age": 56, + "address": { + "state": "Connecticut", + "city": "Turpin" + } + }, + { + "id": 493, + "name": "Earlene Castaneda", + "gender": "female", + "age": 36, + "address": { + "state": "Delaware", + "city": "Temperanceville" + } + }, + { + "id": 494, + "name": "Hodges Vang", + "gender": "male", + "age": 53, + "address": { + "state": "Florida", + "city": "Jessie" + } + }, + { + "id": 495, + "name": "Kenya Soto", + "gender": "female", + "age": 73, + "address": { + "state": "Colorado", + "city": "Eureka" + } + }, + { + "id": 496, + "name": "Lidia Santos", + "gender": "female", + "age": 52, + "address": { + "state": "Arkansas", + "city": "Stevens" + } + }, + { + "id": 497, + "name": "Suzanne Barrera", + "gender": "female", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Advance" + } + }, + { + "id": 498, + "name": "Daniel Reyes", + "gender": "male", + "age": 57, + "address": { + "state": "Alaska", + "city": "Churchill" + } + }, + { + "id": 499, + "name": "Maura Osborn", + "gender": "female", + "age": 68, + "address": { + "state": "Tennessee", + "city": "Hartsville/Hartley" + } + }, + { + "id": 500, + "name": "Beryl Ball", + "gender": "female", + "age": 28, + "address": { + "state": "Michigan", + "city": "Savage" + } + }, + { + "id": 501, + "name": "Ada Pena", + "gender": "female", + "age": 68, + "address": { + "state": "New York", + "city": "Lynn" + } + }, + { + "id": 502, + "name": "Kris Mccoy", + "gender": "female", + "age": 40, + "address": { + "state": "Utah", + "city": "Centerville" + } + }, + { + "id": 503, + "name": "Juliet Orr", + "gender": "female", + "age": 45, + "address": { + "state": "Montana", + "city": "Richmond" + } + }, + { + "id": 504, + "name": "Bettye Mckay", + "gender": "female", + "age": 60, + "address": { + "state": "South Dakota", + "city": "Spokane" + } + }, + { + "id": 505, + "name": "Hardin Witt", + "gender": "male", + "age": 44, + "address": { + "state": "Arizona", + "city": "Devon" + } + }, + { + "id": 506, + "name": "Josefa Kaufman", + "gender": "female", + "age": 72, + "address": { + "state": "Missouri", + "city": "Villarreal" + } + }, + { + "id": 507, + "name": "Schwartz Dean", + "gender": "male", + "age": 58, + "address": { + "state": "Oklahoma", + "city": "Hendersonville" + } + }, + { + "id": 508, + "name": "Rose Mercado", + "gender": "female", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Clara" + } + }, + { + "id": 509, + "name": "Lesa Pace", + "gender": "female", + "age": 24, + "address": { + "state": "Hawaii", + "city": "Wintersburg" + } + }, + { + "id": 510, + "name": "Wagner Dunlap", + "gender": "male", + "age": 55, + "address": { + "state": "Wyoming", + "city": "Oneida" + } + }, + { + "id": 511, + "name": "Arnold Dotson", + "gender": "male", + "age": 69, + "address": { + "state": "Kentucky", + "city": "Bonanza" + } + }, + { + "id": 512, + "name": "Michele Duke", + "gender": "female", + "age": 38, + "address": { + "state": "Washington", + "city": "Bend" + } + }, + { + "id": 513, + "name": "Floyd Walters", + "gender": "male", + "age": 41, + "address": { + "state": "New Mexico", + "city": "Hebron" + } + }, + { + "id": 514, + "name": "Pierce Hopkins", + "gender": "male", + "age": 36, + "address": { + "state": "New Hampshire", + "city": "Beechmont" + } + }, + { + "id": 515, + "name": "Delaney Perez", + "gender": "male", + "age": 74, + "address": { + "state": "North Carolina", + "city": "Crenshaw" + } + }, + { + "id": 516, + "name": "Romero Hester", + "gender": "male", + "age": 58, + "address": { + "state": "Iowa", + "city": "Abiquiu" + } + }, + { + "id": 517, + "name": "Brewer Heath", + "gender": "male", + "age": 53, + "address": { + "state": "West Virginia", + "city": "Sterling" + } + }, + { + "id": 518, + "name": "Shaw Carver", + "gender": "male", + "age": 81, + "address": { + "state": "Idaho", + "city": "Gorst" + } + }, + { + "id": 519, + "name": "Morgan Richards", + "gender": "female", + "age": 65, + "address": { + "state": "Louisiana", + "city": "Aurora" + } + }, + { + "id": 520, + "name": "Josephine Coleman", + "gender": "female", + "age": 57, + "address": { + "state": "California", + "city": "Kieler" + } + }, + { + "id": 521, + "name": "Pope Weber", + "gender": "male", + "age": 46, + "address": { + "state": "Vermont", + "city": "Cashtown" + } + }, + { + "id": 522, + "name": "Boyer Henderson", + "gender": "male", + "age": 37, + "address": { + "state": "Wisconsin", + "city": "Welda" + } + }, + { + "id": 523, + "name": "Naomi Osborne", + "gender": "female", + "age": 45, + "address": { + "state": "Maine", + "city": "Eastmont" + } + }, + { + "id": 524, + "name": "Lucille Riggs", + "gender": "female", + "age": 17, + "address": { + "state": "North Dakota", + "city": "Byrnedale" + } + }, + { + "id": 525, + "name": "Louisa Quinn", + "gender": "female", + "age": 23, + "address": { + "state": "Nevada", + "city": "Veguita" + } + }, + { + "id": 526, + "name": "Webster Oneill", + "gender": "male", + "age": 70, + "address": { + "state": "Maryland", + "city": "Baker" + } + }, + { + "id": 527, + "name": "Wilkins Summers", + "gender": "male", + "age": 35, + "address": { + "state": "Massachusetts", + "city": "Warren" + } + }, + { + "id": 528, + "name": "Tanya Savage", + "gender": "female", + "age": 57, + "address": { + "state": "Virginia", + "city": "Greenock" + } + }, + { + "id": 529, + "name": "Lenora May", + "gender": "female", + "age": 58, + "address": { + "state": "Minnesota", + "city": "Edinburg" + } + }, + { + "id": 530, + "name": "Beulah Holden", + "gender": "female", + "age": 31, + "address": { + "state": "Ohio", + "city": "Fostoria" + } + }, + { + "id": 531, + "name": "Leslie Boone", + "gender": "female", + "age": 29, + "address": { + "state": "Georgia", + "city": "Ivanhoe" + } + }, + { + "id": 532, + "name": "Yates Hartman", + "gender": "male", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Deputy" + } + }, + { + "id": 533, + "name": "Chelsea Hull", + "gender": "female", + "age": 42, + "address": { + "state": "Oregon", + "city": "Dale" + } + }, + { + "id": 534, + "name": "Benson Small", + "gender": "male", + "age": 74, + "address": { + "state": "Alabama", + "city": "Westboro" + } + }, + { + "id": 535, + "name": "Jacobs Lott", + "gender": "male", + "age": 64, + "address": { + "state": "Rhode Island", + "city": "Woodlands" + } + }, + { + "id": 536, + "name": "Selena Preston", + "gender": "female", + "age": 45, + "address": { + "state": "Illinois", + "city": "Westwood" + } + }, + { + "id": 537, + "name": "Gates Britt", + "gender": "male", + "age": 22, + "address": { + "state": "Texas", + "city": "Downsville" + } + }, + { + "id": 538, + "name": "Caroline Cabrera", + "gender": "female", + "age": 75, + "address": { + "state": "Indiana", + "city": "Makena" + } + }, + { + "id": 539, + "name": "Carmen Cooke", + "gender": "female", + "age": 51, + "address": { + "state": "Kentucky", + "city": "Dowling" + } + }, + { + "id": 540, + "name": "Jaime Webster", + "gender": "female", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Ada" + } + }, + { + "id": 541, + "name": "Mary Porter", + "gender": "female", + "age": 30, + "address": { + "state": "North Dakota", + "city": "Gilgo" + } + }, + { + "id": 542, + "name": "Phillips Bell", + "gender": "male", + "age": 76, + "address": { + "state": "Nebraska", + "city": "Rowe" + } + }, + { + "id": 543, + "name": "Moss Foley", + "gender": "male", + "age": 18, + "address": { + "state": "Alaska", + "city": "Gallina" + } + }, + { + "id": 544, + "name": "Solomon Nicholson", + "gender": "male", + "age": 19, + "address": { + "state": "Delaware", + "city": "Rossmore" + } + }, + { + "id": 545, + "name": "Dianna Bennett", + "gender": "female", + "age": 63, + "address": { + "state": "Alabama", + "city": "Hampstead" + } + }, + { + "id": 546, + "name": "Maude King", + "gender": "female", + "age": 54, + "address": { + "state": "South Dakota", + "city": "Sunwest" + } + }, + { + "id": 547, + "name": "Anastasia Chaney", + "gender": "female", + "age": 57, + "address": { + "state": "New Hampshire", + "city": "Clara" + } + }, + { + "id": 548, + "name": "Virginia Allen", + "gender": "female", + "age": 28, + "address": { + "state": "New Jersey", + "city": "Kempton" + } + }, + { + "id": 549, + "name": "Conway Allison", + "gender": "male", + "age": 76, + "address": { + "state": "Florida", + "city": "Allensworth" + } + }, + { + "id": 550, + "name": "Shields Key", + "gender": "male", + "age": 29, + "address": { + "state": "Montana", + "city": "Sultana" + } + }, + { + "id": 551, + "name": "Sonia Brock", + "gender": "female", + "age": 39, + "address": { + "state": "Rhode Island", + "city": "Leroy" + } + }, + { + "id": 552, + "name": "Mitzi Klein", + "gender": "female", + "age": 65, + "address": { + "state": "North Carolina", + "city": "Waukeenah" + } + }, + { + "id": 553, + "name": "Torres Montoya", + "gender": "male", + "age": 59, + "address": { + "state": "Kansas", + "city": "Homeworth" + } + }, + { + "id": 554, + "name": "Estelle Butler", + "gender": "female", + "age": 42, + "address": { + "state": "Mississippi", + "city": "Woodlands" + } + }, + { + "id": 555, + "name": "Vargas Wise", + "gender": "male", + "age": 73, + "address": { + "state": "Pennsylvania", + "city": "Dargan" + } + }, + { + "id": 556, + "name": "Annabelle Mason", + "gender": "female", + "age": 53, + "address": { + "state": "Oklahoma", + "city": "Allamuchy" + } + }, + { + "id": 557, + "name": "Helene Frank", + "gender": "female", + "age": 38, + "address": { + "state": "Maine", + "city": "Iberia" + } + }, + { + "id": 558, + "name": "Susanne Travis", + "gender": "female", + "age": 77, + "address": { + "state": "Utah", + "city": "Fairfield" + } + }, + { + "id": 559, + "name": "Howell Mejia", + "gender": "male", + "age": 37, + "address": { + "state": "Washington", + "city": "Marion" + } + }, + { + "id": 560, + "name": "Melva Oneil", + "gender": "female", + "age": 18, + "address": { + "state": "Vermont", + "city": "Norvelt" + } + }, + { + "id": 561, + "name": "Bernice Romero", + "gender": "female", + "age": 41, + "address": { + "state": "Oregon", + "city": "Brantleyville" + } + }, + { + "id": 562, + "name": "Ana Duke", + "gender": "female", + "age": 25, + "address": { + "state": "South Carolina", + "city": "Nanafalia" + } + }, + { + "id": 563, + "name": "Mariana Pate", + "gender": "female", + "age": 18, + "address": { + "state": "Massachusetts", + "city": "Deltaville" + } + }, + { + "id": 564, + "name": "Holland Rogers", + "gender": "male", + "age": 46, + "address": { + "state": "Iowa", + "city": "Bodega" + } + }, + { + "id": 565, + "name": "Mullins Pacheco", + "gender": "male", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Clarence" + } + }, + { + "id": 566, + "name": "Margaret Bolton", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Tyhee" + } + }, + { + "id": 567, + "name": "Vilma Lott", + "gender": "female", + "age": 30, + "address": { + "state": "Missouri", + "city": "Tetherow" + } + }, + { + "id": 568, + "name": "Deana Grant", + "gender": "female", + "age": 82, + "address": { + "state": "Idaho", + "city": "Jeff" + } + }, + { + "id": 569, + "name": "Francisca Thornton", + "gender": "female", + "age": 34, + "address": { + "state": "West Virginia", + "city": "Avalon" + } + }, + { + "id": 570, + "name": "Lauren Griffin", + "gender": "female", + "age": 60, + "address": { + "state": "Ohio", + "city": "Fingerville" + } + }, + { + "id": 571, + "name": "Bridget Strickland", + "gender": "female", + "age": 66, + "address": { + "state": "New York", + "city": "Nicholson" + } + }, + { + "id": 572, + "name": "Petra Pugh", + "gender": "female", + "age": 37, + "address": { + "state": "Indiana", + "city": "Stonybrook" + } + }, + { + "id": 573, + "name": "Ruby Burris", + "gender": "female", + "age": 64, + "address": { + "state": "Georgia", + "city": "Bergoo" + } + }, + { + "id": 574, + "name": "Whitney Yates", + "gender": "female", + "age": 28, + "address": { + "state": "New Mexico", + "city": "Bluffview" + } + }, + { + "id": 575, + "name": "Ellen Steele", + "gender": "female", + "age": 22, + "address": { + "state": "Colorado", + "city": "Windsor" + } + }, + { + "id": 576, + "name": "Lesa Ortega", + "gender": "female", + "age": 34, + "address": { + "state": "Tennessee", + "city": "Laurelton" + } + }, + { + "id": 577, + "name": "Aguirre Decker", + "gender": "male", + "age": 40, + "address": { + "state": "Virginia", + "city": "Eureka" + } + }, + { + "id": 578, + "name": "Ray Moss", + "gender": "male", + "age": 32, + "address": { + "state": "Maryland", + "city": "Cucumber" + } + }, + { + "id": 579, + "name": "Letha Head", + "gender": "female", + "age": 43, + "address": { + "state": "Arizona", + "city": "Mathews" + } + }, + { + "id": 580, + "name": "Davis Hahn", + "gender": "male", + "age": 67, + "address": { + "state": "Michigan", + "city": "Kilbourne" + } + }, + { + "id": 581, + "name": "Jeannette Velasquez", + "gender": "female", + "age": 20, + "address": { + "state": "Hawaii", + "city": "Hebron" + } + }, + { + "id": 582, + "name": "Lamb Jarvis", + "gender": "male", + "age": 17, + "address": { + "state": "Wisconsin", + "city": "Frizzleburg" + } + }, + { + "id": 583, + "name": "Keri Dunlap", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Marbury" + } + }, + { + "id": 584, + "name": "Sharpe Sharpe", + "gender": "male", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Stagecoach" + } + }, + { + "id": 585, + "name": "Olivia Garrett", + "gender": "female", + "age": 47, + "address": { + "state": "Arkansas", + "city": "Dexter" + } + }, + { + "id": 586, + "name": "Ava Graham", + "gender": "female", + "age": 61, + "address": { + "state": "Texas", + "city": "Calpine" + } + }, + { + "id": 587, + "name": "Doris Horton", + "gender": "female", + "age": 21, + "address": { + "state": "Nevada", + "city": "Goodville" + } + }, + { + "id": 588, + "name": "Jimenez Abbott", + "gender": "male", + "age": 45, + "address": { + "state": "California", + "city": "Tuskahoma" + } + }, + { + "id": 589, + "name": "Michele Branch", + "gender": "female", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Lavalette" + } + }, + { + "id": 590, + "name": "Reva Parks", + "gender": "female", + "age": 74, + "address": { + "state": "Wisconsin", + "city": "Springville" + } + }, + { + "id": 591, + "name": "Burch Hewitt", + "gender": "male", + "age": 21, + "address": { + "state": "New Mexico", + "city": "Dunlo" + } + }, + { + "id": 592, + "name": "Small Haney", + "gender": "male", + "age": 33, + "address": { + "state": "Utah", + "city": "Groton" + } + }, + { + "id": 593, + "name": "Lee Nolan", + "gender": "female", + "age": 20, + "address": { + "state": "New Jersey", + "city": "Canoochee" + } + }, + { + "id": 594, + "name": "Montoya Suarez", + "gender": "male", + "age": 25, + "address": { + "state": "Texas", + "city": "Guilford" + } + }, + { + "id": 595, + "name": "Jolene Todd", + "gender": "female", + "age": 33, + "address": { + "state": "Delaware", + "city": "Witmer" + } + }, + { + "id": 596, + "name": "Robert Compton", + "gender": "female", + "age": 24, + "address": { + "state": "Minnesota", + "city": "Bynum" + } + }, + { + "id": 597, + "name": "Mueller Velez", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Walker" + } + }, + { + "id": 598, + "name": "Bruce Davidson", + "gender": "male", + "age": 18, + "address": { + "state": "Michigan", + "city": "Caln" + } + }, + { + "id": 599, + "name": "Yesenia Burnett", + "gender": "female", + "age": 80, + "address": { + "state": "Virginia", + "city": "Noblestown" + } + }, + { + "id": 600, + "name": "Vasquez Carson", + "gender": "male", + "age": 76, + "address": { + "state": "Indiana", + "city": "Lindisfarne" + } + }, + { + "id": 601, + "name": "Selena Newton", + "gender": "female", + "age": 41, + "address": { + "state": "Illinois", + "city": "Grenelefe" + } + }, + { + "id": 602, + "name": "Anne Molina", + "gender": "female", + "age": 20, + "address": { + "state": "Wyoming", + "city": "Greensburg" + } + }, + { + "id": 603, + "name": "Jacklyn Burris", + "gender": "female", + "age": 42, + "address": { + "state": "South Dakota", + "city": "Tooleville" + } + }, + { + "id": 604, + "name": "Guadalupe Cortez", + "gender": "female", + "age": 40, + "address": { + "state": "New Hampshire", + "city": "Moscow" + } + }, + { + "id": 605, + "name": "Marissa Howell", + "gender": "female", + "age": 68, + "address": { + "state": "South Carolina", + "city": "Matheny" + } + }, + { + "id": 606, + "name": "Sandy Mathews", + "gender": "female", + "age": 68, + "address": { + "state": "Oregon", + "city": "Marysville" + } + }, + { + "id": 607, + "name": "Chang Bowen", + "gender": "male", + "age": 45, + "address": { + "state": "New York", + "city": "Jacumba" + } + }, + { + "id": 608, + "name": "Concepcion Sexton", + "gender": "female", + "age": 60, + "address": { + "state": "Vermont", + "city": "Lydia" + } + }, + { + "id": 609, + "name": "Sophie Carlson", + "gender": "female", + "age": 35, + "address": { + "state": "Kansas", + "city": "Hannasville" + } + }, + { + "id": 610, + "name": "Henry Bean", + "gender": "male", + "age": 58, + "address": { + "state": "Oklahoma", + "city": "Kingstowne" + } + }, + { + "id": 611, + "name": "Teresa Figueroa", + "gender": "female", + "age": 52, + "address": { + "state": "Maine", + "city": "Canby" + } + }, + { + "id": 612, + "name": "Little Gates", + "gender": "male", + "age": 23, + "address": { + "state": "Mississippi", + "city": "Bartonsville" + } + }, + { + "id": 613, + "name": "Hamilton Barnett", + "gender": "male", + "age": 73, + "address": { + "state": "Kentucky", + "city": "Sunbury" + } + }, + { + "id": 614, + "name": "Marquez Durham", + "gender": "male", + "age": 67, + "address": { + "state": "Washington", + "city": "Barstow" + } + }, + { + "id": 615, + "name": "Gonzalez Glover", + "gender": "male", + "age": 31, + "address": { + "state": "North Dakota", + "city": "Elrama" + } + }, + { + "id": 616, + "name": "Campbell Dixon", + "gender": "male", + "age": 51, + "address": { + "state": "Colorado", + "city": "Succasunna" + } + }, + { + "id": 617, + "name": "Todd Oliver", + "gender": "male", + "age": 50, + "address": { + "state": "Pennsylvania", + "city": "Choctaw" + } + }, + { + "id": 618, + "name": "Middleton Landry", + "gender": "male", + "age": 57, + "address": { + "state": "Massachusetts", + "city": "Kenmar" + } + }, + { + "id": 619, + "name": "Mcguire Bender", + "gender": "male", + "age": 22, + "address": { + "state": "Arizona", + "city": "Camptown" + } + }, + { + "id": 620, + "name": "Reeves Terrell", + "gender": "male", + "age": 36, + "address": { + "state": "Maryland", + "city": "Why" + } + }, + { + "id": 621, + "name": "Jennings Townsend", + "gender": "male", + "age": 57, + "address": { + "state": "Rhode Island", + "city": "Fredericktown" + } + }, + { + "id": 622, + "name": "Nettie Shaw", + "gender": "female", + "age": 27, + "address": { + "state": "Georgia", + "city": "Robinson" + } + }, + { + "id": 623, + "name": "Phillips Sloan", + "gender": "male", + "age": 74, + "address": { + "state": "Iowa", + "city": "Nicholson" + } + }, + { + "id": 624, + "name": "Mona Webster", + "gender": "female", + "age": 75, + "address": { + "state": "Tennessee", + "city": "Kanauga" + } + }, + { + "id": 625, + "name": "Ball Powell", + "gender": "male", + "age": 59, + "address": { + "state": "Hawaii", + "city": "Sunriver" + } + }, + { + "id": 626, + "name": "Douglas Austin", + "gender": "male", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Gratton" + } + }, + { + "id": 627, + "name": "Howe Murray", + "gender": "male", + "age": 57, + "address": { + "state": "Ohio", + "city": "Hemlock" + } + }, + { + "id": 628, + "name": "Wood Nielsen", + "gender": "male", + "age": 65, + "address": { + "state": "Alabama", + "city": "Blandburg" + } + }, + { + "id": 629, + "name": "Donna Frost", + "gender": "female", + "age": 33, + "address": { + "state": "Alaska", + "city": "Staples" + } + }, + { + "id": 630, + "name": "Louella Sullivan", + "gender": "female", + "age": 59, + "address": { + "state": "North Carolina", + "city": "Flintville" + } + }, + { + "id": 631, + "name": "Hilda Mayo", + "gender": "female", + "age": 18, + "address": { + "state": "Nevada", + "city": "Barrelville" + } + }, + { + "id": 632, + "name": "Rosario Perry", + "gender": "male", + "age": 69, + "address": { + "state": "Missouri", + "city": "Day" + } + }, + { + "id": 633, + "name": "Elliott Kane", + "gender": "male", + "age": 43, + "address": { + "state": "Idaho", + "city": "Stewart" + } + }, + { + "id": 634, + "name": "Sara Olsen", + "gender": "female", + "age": 79, + "address": { + "state": "Louisiana", + "city": "Nettie" + } + }, + { + "id": 635, + "name": "Lawrence Pickett", + "gender": "male", + "age": 45, + "address": { + "state": "Montana", + "city": "Fidelis" + } + }, + { + "id": 636, + "name": "Julia Price", + "gender": "female", + "age": 62, + "address": { + "state": "Florida", + "city": "Longoria" + } + }, + { + "id": 637, + "name": "Emily Williams", + "gender": "female", + "age": 18, + "address": { + "state": "Oregon", + "city": "Blende" + } + }, + { + "id": 638, + "name": "Mcfadden Williams", + "gender": "male", + "age": 73, + "address": { + "state": "Wyoming", + "city": "Bloomington" + } + }, + { + "id": 639, + "name": "Josefa Dyer", + "gender": "female", + "age": 41, + "address": { + "state": "Ohio", + "city": "Takilma" + } + }, + { + "id": 640, + "name": "Sharpe Charles", + "gender": "male", + "age": 36, + "address": { + "state": "Iowa", + "city": "Bennett" + } + }, + { + "id": 641, + "name": "Odom Steele", + "gender": "male", + "age": 22, + "address": { + "state": "Idaho", + "city": "Kennedyville" + } + }, + { + "id": 642, + "name": "Kristine Hopper", + "gender": "female", + "age": 24, + "address": { + "state": "Utah", + "city": "Indio" + } + }, + { + "id": 643, + "name": "Harris Norton", + "gender": "male", + "age": 62, + "address": { + "state": "California", + "city": "Grandview" + } + }, + { + "id": 644, + "name": "Wagner Ellison", + "gender": "male", + "age": 53, + "address": { + "state": "North Dakota", + "city": "Katonah" + } + }, + { + "id": 645, + "name": "Michael Dickson", + "gender": "male", + "age": 33, + "address": { + "state": "Oklahoma", + "city": "Grantville" + } + }, + { + "id": 646, + "name": "Celina Arnold", + "gender": "female", + "age": 26, + "address": { + "state": "Kansas", + "city": "Bakersville" + } + }, + { + "id": 647, + "name": "Bruce Stark", + "gender": "male", + "age": 79, + "address": { + "state": "Vermont", + "city": "Marion" + } + }, + { + "id": 648, + "name": "Collins Hudson", + "gender": "male", + "age": 36, + "address": { + "state": "Nebraska", + "city": "Wauhillau" + } + }, + { + "id": 649, + "name": "Mcgowan Leon", + "gender": "male", + "age": 34, + "address": { + "state": "Alaska", + "city": "Farmington" + } + }, + { + "id": 650, + "name": "Myrna Hodges", + "gender": "female", + "age": 32, + "address": { + "state": "Nevada", + "city": "Wollochet" + } + }, + { + "id": 651, + "name": "Thelma Koch", + "gender": "female", + "age": 52, + "address": { + "state": "Georgia", + "city": "Cassel" + } + }, + { + "id": 652, + "name": "Lucille Reynolds", + "gender": "female", + "age": 78, + "address": { + "state": "Maine", + "city": "Weedville" + } + }, + { + "id": 653, + "name": "Noemi Mcdaniel", + "gender": "female", + "age": 59, + "address": { + "state": "Mississippi", + "city": "Sunwest" + } + }, + { + "id": 654, + "name": "Morin Rojas", + "gender": "male", + "age": 61, + "address": { + "state": "Maryland", + "city": "Cleary" + } + }, + { + "id": 655, + "name": "Herring Price", + "gender": "male", + "age": 60, + "address": { + "state": "Indiana", + "city": "Orason" + } + }, + { + "id": 656, + "name": "Collier Santos", + "gender": "male", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Alleghenyville" + } + }, + { + "id": 657, + "name": "Macdonald Jefferson", + "gender": "male", + "age": 81, + "address": { + "state": "Washington", + "city": "Falconaire" + } + }, + { + "id": 658, + "name": "Rich Gentry", + "gender": "male", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Ruckersville" + } + }, + { + "id": 659, + "name": "Frank Martin", + "gender": "male", + "age": 48, + "address": { + "state": "Wisconsin", + "city": "Trucksville" + } + }, + { + "id": 660, + "name": "Shelton Lamb", + "gender": "male", + "age": 33, + "address": { + "state": "Hawaii", + "city": "Somerset" + } + }, + { + "id": 661, + "name": "Todd Moore", + "gender": "male", + "age": 46, + "address": { + "state": "Florida", + "city": "Darrtown" + } + }, + { + "id": 662, + "name": "Conner Young", + "gender": "male", + "age": 72, + "address": { + "state": "Arizona", + "city": "Marienthal" + } + }, + { + "id": 663, + "name": "Rosie Macias", + "gender": "female", + "age": 64, + "address": { + "state": "South Carolina", + "city": "Graniteville" + } + }, + { + "id": 664, + "name": "Gross Schultz", + "gender": "male", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Bergoo" + } + }, + { + "id": 665, + "name": "Albert Santana", + "gender": "male", + "age": 30, + "address": { + "state": "Colorado", + "city": "Bladensburg" + } + }, + { + "id": 666, + "name": "Jewell Burt", + "gender": "female", + "age": 69, + "address": { + "state": "Michigan", + "city": "Callaghan" + } + }, + { + "id": 667, + "name": "Haley Bass", + "gender": "female", + "age": 70, + "address": { + "state": "Illinois", + "city": "Florence" + } + }, + { + "id": 668, + "name": "Elise Shepard", + "gender": "female", + "age": 64, + "address": { + "state": "Montana", + "city": "Lemoyne" + } + }, + { + "id": 669, + "name": "Marsha Everett", + "gender": "female", + "age": 50, + "address": { + "state": "Missouri", + "city": "Nord" + } + }, + { + "id": 670, + "name": "Bean Pace", + "gender": "male", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Johnsonburg" + } + }, + { + "id": 671, + "name": "Daugherty Peterson", + "gender": "male", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Dahlen" + } + }, + { + "id": 672, + "name": "Dorsey Anderson", + "gender": "male", + "age": 25, + "address": { + "state": "Texas", + "city": "Guthrie" + } + }, + { + "id": 673, + "name": "Ernestine Howell", + "gender": "female", + "age": 33, + "address": { + "state": "Virginia", + "city": "Summerset" + } + }, + { + "id": 674, + "name": "Gay Vargas", + "gender": "male", + "age": 57, + "address": { + "state": "Minnesota", + "city": "Hiseville" + } + }, + { + "id": 675, + "name": "Muriel Wynn", + "gender": "female", + "age": 32, + "address": { + "state": "Pennsylvania", + "city": "Healy" + } + }, + { + "id": 676, + "name": "Mckee Gallagher", + "gender": "male", + "age": 31, + "address": { + "state": "Delaware", + "city": "Camino" + } + }, + { + "id": 677, + "name": "Lelia Parrish", + "gender": "female", + "age": 75, + "address": { + "state": "New York", + "city": "Gadsden" + } + }, + { + "id": 678, + "name": "Julianne Kane", + "gender": "female", + "age": 54, + "address": { + "state": "Kentucky", + "city": "Ladera" + } + }, + { + "id": 679, + "name": "Travis Combs", + "gender": "male", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Cliffside" + } + }, + { + "id": 680, + "name": "Mary Huffman", + "gender": "female", + "age": 28, + "address": { + "state": "New Hampshire", + "city": "Ryderwood" + } + }, + { + "id": 681, + "name": "Charity Delacruz", + "gender": "female", + "age": 49, + "address": { + "state": "Alabama", + "city": "Salix" + } + }, + { + "id": 682, + "name": "Selena Mcleod", + "gender": "female", + "age": 17, + "address": { + "state": "Louisiana", + "city": "Harold" + } + }, + { + "id": 683, + "name": "Mallory Hoffman", + "gender": "female", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Graball" + } + }, + { + "id": 684, + "name": "Vanessa Rosario", + "gender": "female", + "age": 63, + "address": { + "state": "New Jersey", + "city": "Kenmar" + } + }, + { + "id": 685, + "name": "Blanche Jordan", + "gender": "female", + "age": 21, + "address": { + "state": "Arkansas", + "city": "Virgie" + } + }, + { + "id": 686, + "name": "Brandy Hardy", + "gender": "female", + "age": 66, + "address": { + "state": "Kansas", + "city": "Gibbsville" + } + }, + { + "id": 687, + "name": "Rosanne Walton", + "gender": "female", + "age": 44, + "address": { + "state": "South Carolina", + "city": "Turpin" + } + }, + { + "id": 688, + "name": "Aurora Hickman", + "gender": "female", + "age": 30, + "address": { + "state": "Maryland", + "city": "Rockingham" + } + }, + { + "id": 689, + "name": "Duke Cline", + "gender": "male", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Imperial" + } + }, + { + "id": 690, + "name": "Madeline Slater", + "gender": "female", + "age": 51, + "address": { + "state": "Alaska", + "city": "Roulette" + } + }, + { + "id": 691, + "name": "Eddie Glenn", + "gender": "female", + "age": 33, + "address": { + "state": "New Jersey", + "city": "Roland" + } + }, + { + "id": 692, + "name": "Valentine Talley", + "gender": "male", + "age": 18, + "address": { + "state": "Georgia", + "city": "Waterloo" + } + }, + { + "id": 693, + "name": "Carney Morrison", + "gender": "male", + "age": 53, + "address": { + "state": "Pennsylvania", + "city": "Esmont" + } + }, + { + "id": 694, + "name": "Stout Lowe", + "gender": "male", + "age": 51, + "address": { + "state": "Wisconsin", + "city": "Brandywine" + } + }, + { + "id": 695, + "name": "Candy Lawrence", + "gender": "female", + "age": 73, + "address": { + "state": "Arkansas", + "city": "Morningside" + } + }, + { + "id": 696, + "name": "Curtis Sherman", + "gender": "male", + "age": 43, + "address": { + "state": "Connecticut", + "city": "Soudan" + } + }, + { + "id": 697, + "name": "Christensen Dickerson", + "gender": "male", + "age": 60, + "address": { + "state": "Mississippi", + "city": "Mammoth" + } + }, + { + "id": 698, + "name": "Hilary Yang", + "gender": "female", + "age": 69, + "address": { + "state": "Ohio", + "city": "Gouglersville" + } + }, + { + "id": 699, + "name": "Charlene Mclaughlin", + "gender": "female", + "age": 62, + "address": { + "state": "Delaware", + "city": "Romeville" + } + }, + { + "id": 700, + "name": "Massey Nash", + "gender": "male", + "age": 55, + "address": { + "state": "Tennessee", + "city": "Kylertown" + } + }, + { + "id": 701, + "name": "Randi Gay", + "gender": "female", + "age": 33, + "address": { + "state": "Illinois", + "city": "Silkworth" + } + }, + { + "id": 702, + "name": "Melva Mcgee", + "gender": "female", + "age": 72, + "address": { + "state": "Louisiana", + "city": "Conestoga" + } + }, + { + "id": 703, + "name": "Hyde Wilder", + "gender": "male", + "age": 34, + "address": { + "state": "Utah", + "city": "Rutherford" + } + }, + { + "id": 704, + "name": "Aisha Lane", + "gender": "female", + "age": 34, + "address": { + "state": "Michigan", + "city": "Frank" + } + }, + { + "id": 705, + "name": "Jan Kirk", + "gender": "female", + "age": 71, + "address": { + "state": "West Virginia", + "city": "Cavalero" + } + }, + { + "id": 706, + "name": "Dionne Becker", + "gender": "female", + "age": 82, + "address": { + "state": "Montana", + "city": "Brady" + } + }, + { + "id": 707, + "name": "Lorraine Hernandez", + "gender": "female", + "age": 53, + "address": { + "state": "Virginia", + "city": "Lydia" + } + }, + { + "id": 708, + "name": "Juana Gomez", + "gender": "female", + "age": 69, + "address": { + "state": "Colorado", + "city": "Ahwahnee" + } + }, + { + "id": 709, + "name": "Desiree King", + "gender": "female", + "age": 55, + "address": { + "state": "Texas", + "city": "Golconda" + } + }, + { + "id": 710, + "name": "Delaney Copeland", + "gender": "male", + "age": 34, + "address": { + "state": "Washington", + "city": "Ruffin" + } + }, + { + "id": 711, + "name": "Gabriela Hubbard", + "gender": "female", + "age": 33, + "address": { + "state": "Kentucky", + "city": "Fedora" + } + }, + { + "id": 712, + "name": "Kimberley Fernandez", + "gender": "female", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Axis" + } + }, + { + "id": 713, + "name": "Warner Wong", + "gender": "male", + "age": 57, + "address": { + "state": "Nebraska", + "city": "Chesterfield" + } + }, + { + "id": 714, + "name": "Frances Goodwin", + "gender": "female", + "age": 20, + "address": { + "state": "North Carolina", + "city": "Albany" + } + }, + { + "id": 715, + "name": "Roth Harrell", + "gender": "male", + "age": 27, + "address": { + "state": "Missouri", + "city": "Cawood" + } + }, + { + "id": 716, + "name": "Ester Romero", + "gender": "female", + "age": 18, + "address": { + "state": "Arizona", + "city": "Martell" + } + }, + { + "id": 717, + "name": "Wood Brewer", + "gender": "male", + "age": 38, + "address": { + "state": "Oregon", + "city": "Topanga" + } + }, + { + "id": 718, + "name": "Becky Haley", + "gender": "female", + "age": 71, + "address": { + "state": "Vermont", + "city": "Kohatk" + } + }, + { + "id": 719, + "name": "Cecelia Reilly", + "gender": "female", + "age": 25, + "address": { + "state": "New Hampshire", + "city": "Orason" + } + }, + { + "id": 720, + "name": "Amparo Harris", + "gender": "female", + "age": 24, + "address": { + "state": "Alabama", + "city": "Indio" + } + }, + { + "id": 721, + "name": "Joan Lucas", + "gender": "female", + "age": 80, + "address": { + "state": "Florida", + "city": "Thermal" + } + }, + { + "id": 722, + "name": "Campos Farrell", + "gender": "male", + "age": 27, + "address": { + "state": "Iowa", + "city": "Forestburg" + } + }, + { + "id": 723, + "name": "Mabel Martin", + "gender": "female", + "age": 79, + "address": { + "state": "North Dakota", + "city": "Yardville" + } + }, + { + "id": 724, + "name": "Sheppard Battle", + "gender": "male", + "age": 74, + "address": { + "state": "Hawaii", + "city": "Harold" + } + }, + { + "id": 725, + "name": "Holcomb Chan", + "gender": "male", + "age": 36, + "address": { + "state": "South Dakota", + "city": "Gibsonia" + } + }, + { + "id": 726, + "name": "Madden Wade", + "gender": "male", + "age": 33, + "address": { + "state": "New York", + "city": "Retsof" + } + }, + { + "id": 727, + "name": "Sheree Pennington", + "gender": "female", + "age": 80, + "address": { + "state": "Massachusetts", + "city": "Guilford" + } + }, + { + "id": 728, + "name": "Bright Long", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Barronett" + } + }, + { + "id": 729, + "name": "Jerry Melton", + "gender": "female", + "age": 29, + "address": { + "state": "Idaho", + "city": "Oberlin" + } + }, + { + "id": 730, + "name": "Kent Lara", + "gender": "male", + "age": 44, + "address": { + "state": "California", + "city": "Germanton" + } + }, + { + "id": 731, + "name": "Randolph Tyson", + "gender": "male", + "age": 30, + "address": { + "state": "Rhode Island", + "city": "Sunbury" + } + }, + { + "id": 732, + "name": "Flores Gilliam", + "gender": "male", + "age": 23, + "address": { + "state": "Oklahoma", + "city": "Steinhatchee" + } + }, + { + "id": 733, + "name": "Hayden Delaney", + "gender": "male", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Johnsonburg" + } + }, + { + "id": 734, + "name": "Nash Deleon", + "gender": "male", + "age": 64, + "address": { + "state": "Maine", + "city": "Wakarusa" + } + }, + { + "id": 735, + "name": "Paul Carpenter", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Chicopee" + } + }, + { + "id": 736, + "name": "Kirk Knapp", + "gender": "male", + "age": 22, + "address": { + "state": "Alabama", + "city": "Tibbie" + } + }, + { + "id": 737, + "name": "Courtney Brown", + "gender": "female", + "age": 47, + "address": { + "state": "Pennsylvania", + "city": "Ernstville" + } + }, + { + "id": 738, + "name": "Merle Hickman", + "gender": "female", + "age": 73, + "address": { + "state": "Maine", + "city": "Eagleville" + } + }, + { + "id": 739, + "name": "Evangelina Maldonado", + "gender": "female", + "age": 79, + "address": { + "state": "Vermont", + "city": "Kilbourne" + } + }, + { + "id": 740, + "name": "Avery Cardenas", + "gender": "male", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Strykersville" + } + }, + { + "id": 741, + "name": "Robertson Page", + "gender": "male", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Chase" + } + }, + { + "id": 742, + "name": "Pollard Brennan", + "gender": "male", + "age": 34, + "address": { + "state": "Montana", + "city": "Ruffin" + } + }, + { + "id": 743, + "name": "Shana Blackburn", + "gender": "female", + "age": 76, + "address": { + "state": "Maryland", + "city": "Coral" + } + }, + { + "id": 744, + "name": "Althea Carney", + "gender": "female", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Chilton" + } + }, + { + "id": 745, + "name": "Whitley Tyler", + "gender": "male", + "age": 28, + "address": { + "state": "Delaware", + "city": "Wiscon" + } + }, + { + "id": 746, + "name": "Clark Wilkinson", + "gender": "male", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Marbury" + } + }, + { + "id": 747, + "name": "Hester Hardy", + "gender": "female", + "age": 28, + "address": { + "state": "Oklahoma", + "city": "Herald" + } + }, + { + "id": 748, + "name": "Rose Hogan", + "gender": "female", + "age": 62, + "address": { + "state": "Illinois", + "city": "Herlong" + } + }, + { + "id": 749, + "name": "Sadie Larson", + "gender": "female", + "age": 59, + "address": { + "state": "Georgia", + "city": "Tedrow" + } + }, + { + "id": 750, + "name": "Whitney Valdez", + "gender": "female", + "age": 18, + "address": { + "state": "Colorado", + "city": "Bradenville" + } + }, + { + "id": 751, + "name": "Christy Calhoun", + "gender": "female", + "age": 52, + "address": { + "state": "Ohio", + "city": "Hartsville/Hartley" + } + }, + { + "id": 752, + "name": "Warren Hopkins", + "gender": "male", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Lisco" + } + }, + { + "id": 753, + "name": "Manuela Ball", + "gender": "female", + "age": 81, + "address": { + "state": "Utah", + "city": "Adelino" + } + }, + { + "id": 754, + "name": "Dale Rosales", + "gender": "female", + "age": 72, + "address": { + "state": "New Hampshire", + "city": "Charco" + } + }, + { + "id": 755, + "name": "Melody Mcbride", + "gender": "female", + "age": 24, + "address": { + "state": "Michigan", + "city": "Williams" + } + }, + { + "id": 756, + "name": "Alba English", + "gender": "female", + "age": 60, + "address": { + "state": "New Mexico", + "city": "Trinway" + } + }, + { + "id": 757, + "name": "Sharpe Rush", + "gender": "male", + "age": 49, + "address": { + "state": "North Carolina", + "city": "Fedora" + } + }, + { + "id": 758, + "name": "Candice Leach", + "gender": "female", + "age": 71, + "address": { + "state": "Missouri", + "city": "Monument" + } + }, + { + "id": 759, + "name": "Hollie Woods", + "gender": "female", + "age": 52, + "address": { + "state": "Wisconsin", + "city": "Allendale" + } + }, + { + "id": 760, + "name": "Gray Ashley", + "gender": "male", + "age": 34, + "address": { + "state": "Alaska", + "city": "Worcester" + } + }, + { + "id": 761, + "name": "Kline Bartlett", + "gender": "male", + "age": 75, + "address": { + "state": "Iowa", + "city": "Beaulieu" + } + }, + { + "id": 762, + "name": "Cooke Mcclain", + "gender": "male", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Brandywine" + } + }, + { + "id": 763, + "name": "Erica Stevenson", + "gender": "female", + "age": 43, + "address": { + "state": "Virginia", + "city": "Cliff" + } + }, + { + "id": 764, + "name": "Ophelia Richard", + "gender": "female", + "age": 31, + "address": { + "state": "New Jersey", + "city": "Nutrioso" + } + }, + { + "id": 765, + "name": "Hester Bonner", + "gender": "male", + "age": 28, + "address": { + "state": "Arkansas", + "city": "Churchill" + } + }, + { + "id": 766, + "name": "Richardson Mullen", + "gender": "male", + "age": 25, + "address": { + "state": "Nevada", + "city": "Elfrida" + } + }, + { + "id": 767, + "name": "Gayle Richmond", + "gender": "female", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Valmy" + } + }, + { + "id": 768, + "name": "Claudine Burgess", + "gender": "female", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Suitland" + } + }, + { + "id": 769, + "name": "Mavis Watson", + "gender": "female", + "age": 32, + "address": { + "state": "Connecticut", + "city": "Downsville" + } + }, + { + "id": 770, + "name": "Bowers Buchanan", + "gender": "male", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Bloomington" + } + }, + { + "id": 771, + "name": "Leah Ramsey", + "gender": "female", + "age": 82, + "address": { + "state": "Arizona", + "city": "Catherine" + } + }, + { + "id": 772, + "name": "Lenora Mcdaniel", + "gender": "female", + "age": 53, + "address": { + "state": "Kansas", + "city": "Cutter" + } + }, + { + "id": 773, + "name": "Burks Cole", + "gender": "male", + "age": 58, + "address": { + "state": "Massachusetts", + "city": "Hatteras" + } + }, + { + "id": 774, + "name": "Parrish Grimes", + "gender": "male", + "age": 28, + "address": { + "state": "Florida", + "city": "Oberlin" + } + }, + { + "id": 775, + "name": "Ramos Martinez", + "gender": "male", + "age": 32, + "address": { + "state": "Oregon", + "city": "Greensburg" + } + }, + { + "id": 776, + "name": "Stanton Jarvis", + "gender": "male", + "age": 18, + "address": { + "state": "California", + "city": "Wollochet" + } + }, + { + "id": 777, + "name": "Kaye Mosley", + "gender": "female", + "age": 71, + "address": { + "state": "Idaho", + "city": "Ferney" + } + }, + { + "id": 778, + "name": "Carlene Pugh", + "gender": "female", + "age": 43, + "address": { + "state": "New York", + "city": "Leola" + } + }, + { + "id": 779, + "name": "Malinda Webb", + "gender": "female", + "age": 21, + "address": { + "state": "Washington", + "city": "Wawona" + } + }, + { + "id": 780, + "name": "Lillian Short", + "gender": "female", + "age": 68, + "address": { + "state": "South Dakota", + "city": "Allentown" + } + }, + { + "id": 781, + "name": "Jordan Donaldson", + "gender": "male", + "age": 56, + "address": { + "state": "North Dakota", + "city": "Grill" + } + }, + { + "id": 782, + "name": "Aimee Turner", + "gender": "female", + "age": 67, + "address": { + "state": "Texas", + "city": "Fairlee" + } + }, + { + "id": 783, + "name": "Marci Robbins", + "gender": "female", + "age": 23, + "address": { + "state": "Indiana", + "city": "Blanco" + } + }, + { + "id": 784, + "name": "Gomez Hoover", + "gender": "male", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Gratton" + } + }, + { + "id": 785, + "name": "Osborn Long", + "gender": "male", + "age": 27, + "address": { + "state": "Georgia", + "city": "Chalfant" + } + }, + { + "id": 786, + "name": "Donaldson Day", + "gender": "male", + "age": 64, + "address": { + "state": "Montana", + "city": "Williamson" + } + }, + { + "id": 787, + "name": "Noreen Mcdaniel", + "gender": "female", + "age": 61, + "address": { + "state": "Indiana", + "city": "Gasquet" + } + }, + { + "id": 788, + "name": "Rose Woodward", + "gender": "female", + "age": 76, + "address": { + "state": "Oklahoma", + "city": "Tivoli" + } + }, + { + "id": 789, + "name": "Lewis Hooper", + "gender": "male", + "age": 56, + "address": { + "state": "Ohio", + "city": "Brantleyville" + } + }, + { + "id": 790, + "name": "Kathrine Simon", + "gender": "female", + "age": 64, + "address": { + "state": "Missouri", + "city": "Salvo" + } + }, + { + "id": 791, + "name": "Maggie Albert", + "gender": "female", + "age": 59, + "address": { + "state": "Delaware", + "city": "Kylertown" + } + }, + { + "id": 792, + "name": "Joanna Sears", + "gender": "female", + "age": 32, + "address": { + "state": "Washington", + "city": "Kirk" + } + }, + { + "id": 793, + "name": "Dora Holman", + "gender": "female", + "age": 22, + "address": { + "state": "Kentucky", + "city": "Bartonsville" + } + }, + { + "id": 794, + "name": "Lynch Cline", + "gender": "male", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Balm" + } + }, + { + "id": 795, + "name": "Dale Mitchell", + "gender": "male", + "age": 64, + "address": { + "state": "Alaska", + "city": "Maybell" + } + }, + { + "id": 796, + "name": "Lizzie Juarez", + "gender": "female", + "age": 29, + "address": { + "state": "Oregon", + "city": "Snowville" + } + }, + { + "id": 797, + "name": "Fernandez Briggs", + "gender": "male", + "age": 69, + "address": { + "state": "Wisconsin", + "city": "Yardville" + } + }, + { + "id": 798, + "name": "Beatrice Macias", + "gender": "female", + "age": 35, + "address": { + "state": "Nevada", + "city": "Norwood" + } + }, + { + "id": 799, + "name": "Small Sharp", + "gender": "male", + "age": 50, + "address": { + "state": "Kansas", + "city": "Crucible" + } + }, + { + "id": 800, + "name": "Rosemary Ryan", + "gender": "female", + "age": 60, + "address": { + "state": "Hawaii", + "city": "Crawfordsville" + } + }, + { + "id": 801, + "name": "Sellers Bradford", + "gender": "male", + "age": 48, + "address": { + "state": "North Carolina", + "city": "Alfarata" + } + }, + { + "id": 802, + "name": "Collier Barron", + "gender": "male", + "age": 62, + "address": { + "state": "Tennessee", + "city": "Noblestown" + } + }, + { + "id": 803, + "name": "Baldwin Dominguez", + "gender": "male", + "age": 42, + "address": { + "state": "North Dakota", + "city": "Epworth" + } + }, + { + "id": 804, + "name": "Debora Mcbride", + "gender": "female", + "age": 21, + "address": { + "state": "Iowa", + "city": "Campo" + } + }, + { + "id": 805, + "name": "Sexton Farmer", + "gender": "male", + "age": 29, + "address": { + "state": "Louisiana", + "city": "Herald" + } + }, + { + "id": 806, + "name": "Gail Lynn", + "gender": "female", + "age": 29, + "address": { + "state": "West Virginia", + "city": "Herbster" + } + }, + { + "id": 807, + "name": "Pollard Foley", + "gender": "male", + "age": 26, + "address": { + "state": "Arizona", + "city": "Hackneyville" + } + }, + { + "id": 808, + "name": "Georgette Kline", + "gender": "female", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Eden" + } + }, + { + "id": 809, + "name": "Imelda Lucas", + "gender": "female", + "age": 32, + "address": { + "state": "Texas", + "city": "Ilchester" + } + }, + { + "id": 810, + "name": "Jackson Michael", + "gender": "male", + "age": 33, + "address": { + "state": "Michigan", + "city": "Axis" + } + }, + { + "id": 811, + "name": "Stark Fernandez", + "gender": "male", + "age": 22, + "address": { + "state": "Utah", + "city": "Sugartown" + } + }, + { + "id": 812, + "name": "Marylou Townsend", + "gender": "female", + "age": 36, + "address": { + "state": "Arkansas", + "city": "Delwood" + } + }, + { + "id": 813, + "name": "Avis Mathews", + "gender": "female", + "age": 39, + "address": { + "state": "Maine", + "city": "Clarktown" + } + }, + { + "id": 814, + "name": "Faye Hall", + "gender": "female", + "age": 69, + "address": { + "state": "California", + "city": "Yonah" + } + }, + { + "id": 815, + "name": "Brigitte Stephens", + "gender": "female", + "age": 32, + "address": { + "state": "Vermont", + "city": "Brogan" + } + }, + { + "id": 816, + "name": "Lena Odom", + "gender": "female", + "age": 62, + "address": { + "state": "Rhode Island", + "city": "Wawona" + } + }, + { + "id": 817, + "name": "Noel Burke", + "gender": "male", + "age": 55, + "address": { + "state": "Connecticut", + "city": "Steinhatchee" + } + }, + { + "id": 818, + "name": "Norman Bradley", + "gender": "male", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Noxen" + } + }, + { + "id": 819, + "name": "Marva Rivera", + "gender": "female", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Clarksburg" + } + }, + { + "id": 820, + "name": "Lawrence Allen", + "gender": "male", + "age": 82, + "address": { + "state": "Massachusetts", + "city": "Cornfields" + } + }, + { + "id": 821, + "name": "Singleton Huff", + "gender": "male", + "age": 35, + "address": { + "state": "Virginia", + "city": "Morgandale" + } + }, + { + "id": 822, + "name": "Teresa Merrill", + "gender": "female", + "age": 42, + "address": { + "state": "New Jersey", + "city": "Waterview" + } + }, + { + "id": 823, + "name": "Berry Frank", + "gender": "male", + "age": 82, + "address": { + "state": "Alabama", + "city": "Rivers" + } + }, + { + "id": 824, + "name": "Alisha Cobb", + "gender": "female", + "age": 31, + "address": { + "state": "Colorado", + "city": "Odessa" + } + }, + { + "id": 825, + "name": "Clara Mccarty", + "gender": "female", + "age": 49, + "address": { + "state": "Idaho", + "city": "Alden" + } + }, + { + "id": 826, + "name": "Golden Barton", + "gender": "male", + "age": 40, + "address": { + "state": "South Dakota", + "city": "Hickory" + } + }, + { + "id": 827, + "name": "Leanna Glover", + "gender": "female", + "age": 26, + "address": { + "state": "Florida", + "city": "Rodman" + } + }, + { + "id": 828, + "name": "Drake Houston", + "gender": "male", + "age": 40, + "address": { + "state": "Minnesota", + "city": "Hoehne" + } + }, + { + "id": 829, + "name": "Woodard Valencia", + "gender": "male", + "age": 31, + "address": { + "state": "Maryland", + "city": "Hayden" + } + }, + { + "id": 830, + "name": "Jaclyn Jackson", + "gender": "female", + "age": 29, + "address": { + "state": "Illinois", + "city": "Farmers" + } + }, + { + "id": 831, + "name": "Erin Noel", + "gender": "female", + "age": 74, + "address": { + "state": "South Carolina", + "city": "Bergoo" + } + }, + { + "id": 832, + "name": "Anna Stein", + "gender": "female", + "age": 76, + "address": { + "state": "New York", + "city": "Biehle" + } + }, + { + "id": 833, + "name": "Daphne Hartman", + "gender": "female", + "age": 61, + "address": { + "state": "Alabama", + "city": "Tilden" + } + }, + { + "id": 834, + "name": "Tiffany Moore", + "gender": "female", + "age": 64, + "address": { + "state": "Utah", + "city": "Enoree" + } + }, + { + "id": 835, + "name": "May Rasmussen", + "gender": "female", + "age": 43, + "address": { + "state": "Connecticut", + "city": "Sultana" + } + }, + { + "id": 836, + "name": "Iris Delacruz", + "gender": "female", + "age": 23, + "address": { + "state": "Virginia", + "city": "Beechmont" + } + }, + { + "id": 837, + "name": "Luella Ward", + "gender": "female", + "age": 21, + "address": { + "state": "Missouri", + "city": "Madrid" + } + }, + { + "id": 838, + "name": "Riggs Sosa", + "gender": "male", + "age": 39, + "address": { + "state": "Oklahoma", + "city": "Harviell" + } + }, + { + "id": 839, + "name": "Kramer Brennan", + "gender": "male", + "age": 40, + "address": { + "state": "New York", + "city": "Baker" + } + }, + { + "id": 840, + "name": "Fowler Mays", + "gender": "male", + "age": 72, + "address": { + "state": "Colorado", + "city": "Hatteras" + } + }, + { + "id": 841, + "name": "Ernestine Moody", + "gender": "female", + "age": 63, + "address": { + "state": "Maine", + "city": "Rosine" + } + }, + { + "id": 842, + "name": "Fischer Gibbs", + "gender": "male", + "age": 67, + "address": { + "state": "Illinois", + "city": "Idamay" + } + }, + { + "id": 843, + "name": "Moran Pate", + "gender": "male", + "age": 34, + "address": { + "state": "Nebraska", + "city": "Condon" + } + }, + { + "id": 844, + "name": "Sophie Wilkerson", + "gender": "female", + "age": 21, + "address": { + "state": "Delaware", + "city": "Spelter" + } + }, + { + "id": 845, + "name": "Myrtle Murphy", + "gender": "female", + "age": 65, + "address": { + "state": "New Hampshire", + "city": "Bradenville" + } + }, + { + "id": 846, + "name": "Rosalind Tyler", + "gender": "female", + "age": 19, + "address": { + "state": "Iowa", + "city": "Floris" + } + }, + { + "id": 847, + "name": "Hanson French", + "gender": "male", + "age": 23, + "address": { + "state": "Pennsylvania", + "city": "Warren" + } + }, + { + "id": 848, + "name": "Karin Shepard", + "gender": "female", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Glasgow" + } + }, + { + "id": 849, + "name": "Esther Burke", + "gender": "female", + "age": 39, + "address": { + "state": "Massachusetts", + "city": "Magnolia" + } + }, + { + "id": 850, + "name": "Ronda Copeland", + "gender": "female", + "age": 30, + "address": { + "state": "Idaho", + "city": "Dexter" + } + }, + { + "id": 851, + "name": "Brittney Walsh", + "gender": "female", + "age": 59, + "address": { + "state": "New Mexico", + "city": "Wilmington" + } + }, + { + "id": 852, + "name": "Strickland Lindsey", + "gender": "male", + "age": 49, + "address": { + "state": "Nevada", + "city": "Garberville" + } + }, + { + "id": 853, + "name": "Constance Weaver", + "gender": "female", + "age": 82, + "address": { + "state": "Louisiana", + "city": "Bodega" + } + }, + { + "id": 854, + "name": "Velez Johnston", + "gender": "male", + "age": 63, + "address": { + "state": "Texas", + "city": "Curtice" + } + }, + { + "id": 855, + "name": "Robles Lang", + "gender": "male", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Rodman" + } + }, + { + "id": 856, + "name": "Estes Willis", + "gender": "male", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Southmont" + } + }, + { + "id": 857, + "name": "Boyd Bolton", + "gender": "male", + "age": 72, + "address": { + "state": "Ohio", + "city": "Tyhee" + } + }, + { + "id": 858, + "name": "Rosetta Webster", + "gender": "female", + "age": 54, + "address": { + "state": "Tennessee", + "city": "Gardners" + } + }, + { + "id": 859, + "name": "Rosella Peck", + "gender": "female", + "age": 41, + "address": { + "state": "Arizona", + "city": "Retsof" + } + }, + { + "id": 860, + "name": "Dalton Gilliam", + "gender": "male", + "age": 70, + "address": { + "state": "Rhode Island", + "city": "Ezel" + } + }, + { + "id": 861, + "name": "Lucas Wolf", + "gender": "male", + "age": 24, + "address": { + "state": "Vermont", + "city": "Washington" + } + }, + { + "id": 862, + "name": "Merritt Petty", + "gender": "male", + "age": 29, + "address": { + "state": "Maryland", + "city": "Skyland" + } + }, + { + "id": 863, + "name": "Brewer Koch", + "gender": "male", + "age": 20, + "address": { + "state": "Minnesota", + "city": "Bellfountain" + } + }, + { + "id": 864, + "name": "Lily Winters", + "gender": "female", + "age": 42, + "address": { + "state": "Washington", + "city": "Kula" + } + }, + { + "id": 865, + "name": "Elena Valencia", + "gender": "female", + "age": 60, + "address": { + "state": "South Dakota", + "city": "Hegins" + } + }, + { + "id": 866, + "name": "Solis Mckinney", + "gender": "male", + "age": 29, + "address": { + "state": "Kansas", + "city": "Stagecoach" + } + }, + { + "id": 867, + "name": "Eddie Atkinson", + "gender": "female", + "age": 79, + "address": { + "state": "Florida", + "city": "Canby" + } + }, + { + "id": 868, + "name": "Madelyn Estrada", + "gender": "female", + "age": 17, + "address": { + "state": "Indiana", + "city": "Wells" + } + }, + { + "id": 869, + "name": "Merle Stewart", + "gender": "female", + "age": 18, + "address": { + "state": "Alaska", + "city": "Singer" + } + }, + { + "id": 870, + "name": "Vivian Tyson", + "gender": "female", + "age": 47, + "address": { + "state": "Michigan", + "city": "Abrams" + } + }, + { + "id": 871, + "name": "Allison Booker", + "gender": "female", + "age": 80, + "address": { + "state": "Wisconsin", + "city": "Inkerman" + } + }, + { + "id": 872, + "name": "Tucker Hutchinson", + "gender": "male", + "age": 47, + "address": { + "state": "Arkansas", + "city": "Sisquoc" + } + }, + { + "id": 873, + "name": "Herman Conway", + "gender": "male", + "age": 79, + "address": { + "state": "Georgia", + "city": "Oceola" + } + }, + { + "id": 874, + "name": "Singleton Bauer", + "gender": "male", + "age": 57, + "address": { + "state": "Wyoming", + "city": "Boomer" + } + }, + { + "id": 875, + "name": "Bass James", + "gender": "male", + "age": 81, + "address": { + "state": "Oregon", + "city": "Cornfields" + } + }, + { + "id": 876, + "name": "Hogan Garrett", + "gender": "male", + "age": 21, + "address": { + "state": "Montana", + "city": "Bainbridge" + } + }, + { + "id": 877, + "name": "Marcella Cardenas", + "gender": "female", + "age": 45, + "address": { + "state": "Kentucky", + "city": "Darrtown" + } + }, + { + "id": 878, + "name": "Robyn Wall", + "gender": "female", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Fairacres" + } + }, + { + "id": 879, + "name": "Rosales Meyers", + "gender": "male", + "age": 42, + "address": { + "state": "South Carolina", + "city": "Brady" + } + }, + { + "id": 880, + "name": "Baird Rodgers", + "gender": "male", + "age": 74, + "address": { + "state": "Hawaii", + "city": "Hiseville" + } + }, + { + "id": 881, + "name": "Angelica Chase", + "gender": "female", + "age": 76, + "address": { + "state": "California", + "city": "Siglerville" + } + }, + { + "id": 882, + "name": "Lorrie Rich", + "gender": "female", + "age": 21, + "address": { + "state": "Vermont", + "city": "Riceville" + } + }, + { + "id": 883, + "name": "Cherie Alvarado", + "gender": "female", + "age": 72, + "address": { + "state": "Indiana", + "city": "Groveville" + } + }, + { + "id": 884, + "name": "Kemp Gonzalez", + "gender": "male", + "age": 58, + "address": { + "state": "Arizona", + "city": "Hanover" + } + }, + { + "id": 885, + "name": "Thomas Lawrence", + "gender": "male", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Coldiron" + } + }, + { + "id": 886, + "name": "Leila Barrera", + "gender": "female", + "age": 81, + "address": { + "state": "New Jersey", + "city": "Kansas" + } + }, + { + "id": 887, + "name": "Sandoval Bass", + "gender": "male", + "age": 28, + "address": { + "state": "Idaho", + "city": "Elrama" + } + }, + { + "id": 888, + "name": "Kari Reyes", + "gender": "female", + "age": 45, + "address": { + "state": "Delaware", + "city": "Moraida" + } + }, + { + "id": 889, + "name": "Candace Bush", + "gender": "female", + "age": 64, + "address": { + "state": "New Hampshire", + "city": "Whitmer" + } + }, + { + "id": 890, + "name": "Mona Benson", + "gender": "female", + "age": 57, + "address": { + "state": "South Dakota", + "city": "Silkworth" + } + }, + { + "id": 891, + "name": "Santiago Vincent", + "gender": "male", + "age": 76, + "address": { + "state": "Kentucky", + "city": "Fidelis" + } + }, + { + "id": 892, + "name": "Elvia Richardson", + "gender": "female", + "age": 38, + "address": { + "state": "Alabama", + "city": "Devon" + } + }, + { + "id": 893, + "name": "Meghan King", + "gender": "female", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Enetai" + } + }, + { + "id": 894, + "name": "Prince Crane", + "gender": "male", + "age": 81, + "address": { + "state": "California", + "city": "Rockingham" + } + }, + { + "id": 895, + "name": "Catherine Lewis", + "gender": "female", + "age": 42, + "address": { + "state": "Michigan", + "city": "Spelter" + } + }, + { + "id": 896, + "name": "Mandy Mckee", + "gender": "female", + "age": 59, + "address": { + "state": "Arkansas", + "city": "Carlos" + } + }, + { + "id": 897, + "name": "Lewis Hale", + "gender": "male", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Zortman" + } + }, + { + "id": 898, + "name": "Willie Doyle", + "gender": "female", + "age": 50, + "address": { + "state": "Kansas", + "city": "Avoca" + } + }, + { + "id": 899, + "name": "Eula Carver", + "gender": "female", + "age": 59, + "address": { + "state": "Oklahoma", + "city": "Cavalero" + } + }, + { + "id": 900, + "name": "Patty Mcclure", + "gender": "female", + "age": 52, + "address": { + "state": "Nebraska", + "city": "Guthrie" + } + }, + { + "id": 901, + "name": "Goodwin Wade", + "gender": "male", + "age": 43, + "address": { + "state": "Virginia", + "city": "Venice" + } + }, + { + "id": 902, + "name": "Allen Cole", + "gender": "male", + "age": 51, + "address": { + "state": "Montana", + "city": "Dodge" + } + }, + { + "id": 903, + "name": "Nancy Bishop", + "gender": "female", + "age": 80, + "address": { + "state": "North Dakota", + "city": "Darlington" + } + }, + { + "id": 904, + "name": "Georgia Acosta", + "gender": "female", + "age": 21, + "address": { + "state": "New Mexico", + "city": "Tilleda" + } + }, + { + "id": 905, + "name": "Maritza Osborn", + "gender": "female", + "age": 78, + "address": { + "state": "Pennsylvania", + "city": "Wedgewood" + } + }, + { + "id": 906, + "name": "Mavis Fulton", + "gender": "female", + "age": 40, + "address": { + "state": "Maryland", + "city": "Rew" + } + }, + { + "id": 907, + "name": "Millie Mcintosh", + "gender": "female", + "age": 32, + "address": { + "state": "Missouri", + "city": "Kenmar" + } + }, + { + "id": 908, + "name": "Audrey Houston", + "gender": "female", + "age": 69, + "address": { + "state": "Florida", + "city": "Hall" + } + }, + { + "id": 909, + "name": "Frederick Vasquez", + "gender": "male", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Wildwood" + } + }, + { + "id": 910, + "name": "Erica Shepard", + "gender": "female", + "age": 75, + "address": { + "state": "Massachusetts", + "city": "Lupton" + } + }, + { + "id": 911, + "name": "Ruby Castaneda", + "gender": "female", + "age": 37, + "address": { + "state": "Oregon", + "city": "Cuylerville" + } + }, + { + "id": 912, + "name": "Snyder Fischer", + "gender": "male", + "age": 62, + "address": { + "state": "Colorado", + "city": "Hasty" + } + }, + { + "id": 913, + "name": "Rose Sweet", + "gender": "female", + "age": 71, + "address": { + "state": "North Carolina", + "city": "Crenshaw" + } + }, + { + "id": 914, + "name": "Walker Benton", + "gender": "male", + "age": 45, + "address": { + "state": "Nevada", + "city": "Deercroft" + } + }, + { + "id": 915, + "name": "Bianca Jacobs", + "gender": "female", + "age": 28, + "address": { + "state": "Connecticut", + "city": "Kanauga" + } + }, + { + "id": 916, + "name": "Bridgett Hamilton", + "gender": "female", + "age": 21, + "address": { + "state": "Rhode Island", + "city": "Caron" + } + }, + { + "id": 917, + "name": "Edwards Goodman", + "gender": "male", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Edneyville" + } + }, + { + "id": 918, + "name": "Perkins Black", + "gender": "male", + "age": 33, + "address": { + "state": "Alaska", + "city": "Tilden" + } + }, + { + "id": 919, + "name": "Hickman Hickman", + "gender": "male", + "age": 76, + "address": { + "state": "Maine", + "city": "Chilton" + } + }, + { + "id": 920, + "name": "Lakisha Valencia", + "gender": "female", + "age": 61, + "address": { + "state": "South Carolina", + "city": "Rockbridge" + } + }, + { + "id": 921, + "name": "Schneider Wilkinson", + "gender": "male", + "age": 60, + "address": { + "state": "Georgia", + "city": "Glenbrook" + } + }, + { + "id": 922, + "name": "Marjorie Hoffman", + "gender": "female", + "age": 70, + "address": { + "state": "Ohio", + "city": "Conestoga" + } + }, + { + "id": 923, + "name": "Madge Hunt", + "gender": "female", + "age": 33, + "address": { + "state": "Texas", + "city": "Marbury" + } + }, + { + "id": 924, + "name": "Joyce Gordon", + "gender": "male", + "age": 24, + "address": { + "state": "Washington", + "city": "Ellerslie" + } + }, + { + "id": 925, + "name": "Rena Lott", + "gender": "female", + "age": 46, + "address": { + "state": "West Virginia", + "city": "Greenwich" + } + }, + { + "id": 926, + "name": "Mathis Hicks", + "gender": "male", + "age": 66, + "address": { + "state": "New York", + "city": "Grandview" + } + }, + { + "id": 927, + "name": "Yvonne Torres", + "gender": "female", + "age": 42, + "address": { + "state": "Tennessee", + "city": "Bergoo" + } + }, + { + "id": 928, + "name": "Manning Kidd", + "gender": "male", + "age": 72, + "address": { + "state": "Iowa", + "city": "Marne" + } + }, + { + "id": 929, + "name": "Freda Marsh", + "gender": "female", + "age": 45, + "address": { + "state": "Illinois", + "city": "Belmont" + } + }, + { + "id": 930, + "name": "Teresa Guzman", + "gender": "female", + "age": 67, + "address": { + "state": "Hawaii", + "city": "Jacksonburg" + } + }, + { + "id": 931, + "name": "Stanley Nieves", + "gender": "male", + "age": 40, + "address": { + "state": "Connecticut", + "city": "Worton" + } + }, + { + "id": 932, + "name": "Dora Copeland", + "gender": "female", + "age": 63, + "address": { + "state": "Ohio", + "city": "Hickory" + } + }, + { + "id": 933, + "name": "Lessie Rice", + "gender": "female", + "age": 50, + "address": { + "state": "Indiana", + "city": "Benson" + } + }, + { + "id": 934, + "name": "Stephanie Taylor", + "gender": "female", + "age": 55, + "address": { + "state": "Colorado", + "city": "Talpa" + } + }, + { + "id": 935, + "name": "Bowman Howard", + "gender": "male", + "age": 24, + "address": { + "state": "Iowa", + "city": "Norris" + } + }, + { + "id": 936, + "name": "Cherie Reid", + "gender": "female", + "age": 35, + "address": { + "state": "Arizona", + "city": "Keyport" + } + }, + { + "id": 937, + "name": "Maude Wallace", + "gender": "female", + "age": 60, + "address": { + "state": "Texas", + "city": "Cashtown" + } + }, + { + "id": 938, + "name": "Yesenia Shaffer", + "gender": "female", + "age": 53, + "address": { + "state": "Montana", + "city": "Valle" + } + }, + { + "id": 939, + "name": "Battle Boyle", + "gender": "male", + "age": 29, + "address": { + "state": "Oregon", + "city": "Chautauqua" + } + }, + { + "id": 940, + "name": "Sharron Greene", + "gender": "female", + "age": 29, + "address": { + "state": "Maryland", + "city": "Herbster" + } + }, + { + "id": 941, + "name": "Estrada Hull", + "gender": "male", + "age": 47, + "address": { + "state": "Nebraska", + "city": "Clara" + } + }, + { + "id": 942, + "name": "Grace Cervantes", + "gender": "female", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Coalmont" + } + }, + { + "id": 943, + "name": "Velazquez Lucas", + "gender": "male", + "age": 57, + "address": { + "state": "New Jersey", + "city": "Mulberry" + } + }, + { + "id": 944, + "name": "Porter Rowland", + "gender": "male", + "age": 75, + "address": { + "state": "Wisconsin", + "city": "Wikieup" + } + }, + { + "id": 945, + "name": "Fulton Jacobson", + "gender": "male", + "age": 57, + "address": { + "state": "Kansas", + "city": "Forbestown" + } + }, + { + "id": 946, + "name": "Gina Sanders", + "gender": "female", + "age": 17, + "address": { + "state": "Michigan", + "city": "Gratton" + } + }, + { + "id": 947, + "name": "Horton Cox", + "gender": "male", + "age": 57, + "address": { + "state": "West Virginia", + "city": "Concho" + } + }, + { + "id": 948, + "name": "Brittany Harding", + "gender": "female", + "age": 72, + "address": { + "state": "North Dakota", + "city": "Reinerton" + } + }, + { + "id": 949, + "name": "Jayne Castillo", + "gender": "female", + "age": 35, + "address": { + "state": "Alabama", + "city": "Rockbridge" + } + }, + { + "id": 950, + "name": "Collins West", + "gender": "male", + "age": 49, + "address": { + "state": "North Carolina", + "city": "Walland" + } + }, + { + "id": 951, + "name": "Krista Waters", + "gender": "female", + "age": 71, + "address": { + "state": "Maine", + "city": "Vallonia" + } + }, + { + "id": 952, + "name": "Boyle Sargent", + "gender": "male", + "age": 82, + "address": { + "state": "Mississippi", + "city": "Wakarusa" + } + }, + { + "id": 953, + "name": "Sabrina Clayton", + "gender": "female", + "age": 41, + "address": { + "state": "Rhode Island", + "city": "Klondike" + } + }, + { + "id": 954, + "name": "Beulah Cameron", + "gender": "female", + "age": 78, + "address": { + "state": "Tennessee", + "city": "Graball" + } + }, + { + "id": 955, + "name": "Lynda Solis", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Matthews" + } + }, + { + "id": 956, + "name": "Marta Owen", + "gender": "female", + "age": 62, + "address": { + "state": "Massachusetts", + "city": "Garberville" + } + }, + { + "id": 957, + "name": "Duffy Lawrence", + "gender": "male", + "age": 28, + "address": { + "state": "New York", + "city": "Gulf" + } + }, + { + "id": 958, + "name": "Turner Schmidt", + "gender": "male", + "age": 71, + "address": { + "state": "Oklahoma", + "city": "Mahtowa" + } + }, + { + "id": 959, + "name": "Lynch Foreman", + "gender": "male", + "age": 73, + "address": { + "state": "Kentucky", + "city": "Callaghan" + } + }, + { + "id": 960, + "name": "Hendricks Kidd", + "gender": "male", + "age": 43, + "address": { + "state": "Idaho", + "city": "Virgie" + } + }, + { + "id": 961, + "name": "Gomez Lara", + "gender": "male", + "age": 42, + "address": { + "state": "Nevada", + "city": "Idamay" + } + }, + { + "id": 962, + "name": "Alexandra Church", + "gender": "female", + "age": 54, + "address": { + "state": "Georgia", + "city": "Hatteras" + } + }, + { + "id": 963, + "name": "Day Bass", + "gender": "male", + "age": 46, + "address": { + "state": "California", + "city": "Caspar" + } + }, + { + "id": 964, + "name": "Marisa Montoya", + "gender": "female", + "age": 81, + "address": { + "state": "New Mexico", + "city": "Robbins" + } + }, + { + "id": 965, + "name": "Beasley Rosa", + "gender": "male", + "age": 41, + "address": { + "state": "Wyoming", + "city": "Farmington" + } + }, + { + "id": 966, + "name": "Acevedo Strickland", + "gender": "male", + "age": 62, + "address": { + "state": "South Carolina", + "city": "Gardiner" + } + }, + { + "id": 967, + "name": "Ochoa Gamble", + "gender": "male", + "age": 48, + "address": { + "state": "Alaska", + "city": "Catharine" + } + }, + { + "id": 968, + "name": "Dalton Rush", + "gender": "male", + "age": 32, + "address": { + "state": "South Dakota", + "city": "Mappsville" + } + }, + { + "id": 969, + "name": "Patrica Spears", + "gender": "female", + "age": 70, + "address": { + "state": "New Hampshire", + "city": "Bagtown" + } + }, + { + "id": 970, + "name": "Sherrie Ellis", + "gender": "female", + "age": 73, + "address": { + "state": "Illinois", + "city": "Belgreen" + } + }, + { + "id": 971, + "name": "Franks Brady", + "gender": "male", + "age": 25, + "address": { + "state": "Utah", + "city": "Ripley" + } + }, + { + "id": 972, + "name": "Rita Wise", + "gender": "female", + "age": 52, + "address": { + "state": "Minnesota", + "city": "Tedrow" + } + }, + { + "id": 973, + "name": "Theresa Harrell", + "gender": "female", + "age": 34, + "address": { + "state": "Washington", + "city": "Morriston" + } + }, + { + "id": 974, + "name": "Savage Chambers", + "gender": "male", + "age": 64, + "address": { + "state": "Hawaii", + "city": "Roeville" + } + }, + { + "id": 975, + "name": "Eliza Miranda", + "gender": "female", + "age": 26, + "address": { + "state": "Delaware", + "city": "Maybell" + } + }, + { + "id": 976, + "name": "Pugh Mcintosh", + "gender": "male", + "age": 20, + "address": { + "state": "Virginia", + "city": "Kimmell" + } + }, + { + "id": 977, + "name": "Stacey Roach", + "gender": "female", + "age": 21, + "address": { + "state": "Pennsylvania", + "city": "Draper" + } + }, + { + "id": 978, + "name": "Rosanna Herman", + "gender": "female", + "age": 72, + "address": { + "state": "Missouri", + "city": "Fairmount" + } + }, + { + "id": 979, + "name": "Enid Snow", + "gender": "female", + "age": 49, + "address": { + "state": "Louisiana", + "city": "Wilmington" + } + }, + { + "id": 980, + "name": "Aurelia Lloyd", + "gender": "female", + "age": 60, + "address": { + "state": "New York", + "city": "Gordon" + } + }, + { + "id": 981, + "name": "Mcfadden Puckett", + "gender": "male", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Tilleda" + } + }, + { + "id": 982, + "name": "Snider Hall", + "gender": "male", + "age": 58, + "address": { + "state": "Illinois", + "city": "Romeville" + } + }, + { + "id": 983, + "name": "Hansen Hunt", + "gender": "male", + "age": 38, + "address": { + "state": "New Hampshire", + "city": "Lorraine" + } + }, + { + "id": 984, + "name": "Hebert Dyer", + "gender": "male", + "age": 80, + "address": { + "state": "Delaware", + "city": "Wanship" + } + }, + { + "id": 985, + "name": "Bowen Barron", + "gender": "male", + "age": 67, + "address": { + "state": "Oklahoma", + "city": "Tolu" + } + }, + { + "id": 986, + "name": "Holly Porter", + "gender": "female", + "age": 39, + "address": { + "state": "Iowa", + "city": "Munjor" + } + }, + { + "id": 987, + "name": "Sanford Hayden", + "gender": "male", + "age": 79, + "address": { + "state": "Missouri", + "city": "Kilbourne" + } + }, + { + "id": 988, + "name": "Byers Perez", + "gender": "male", + "age": 66, + "address": { + "state": "Louisiana", + "city": "Chicopee" + } + }, + { + "id": 989, + "name": "Valerie Reilly", + "gender": "female", + "age": 39, + "address": { + "state": "Montana", + "city": "Worcester" + } + }, + { + "id": 990, + "name": "Renee Barnes", + "gender": "female", + "age": 46, + "address": { + "state": "Idaho", + "city": "Brantleyville" + } + }, + { + "id": 991, + "name": "Deanne Rios", + "gender": "female", + "age": 54, + "address": { + "state": "Ohio", + "city": "Cumminsville" + } + }, + { + "id": 992, + "name": "Alfreda Adkins", + "gender": "female", + "age": 81, + "address": { + "state": "Alabama", + "city": "Gilgo" + } + }, + { + "id": 993, + "name": "Bradford Cline", + "gender": "male", + "age": 20, + "address": { + "state": "South Dakota", + "city": "Juarez" + } + }, + { + "id": 994, + "name": "Sharpe Grant", + "gender": "male", + "age": 38, + "address": { + "state": "Maryland", + "city": "Santel" + } + }, + { + "id": 995, + "name": "Amelia Carpenter", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Advance" + } + }, + { + "id": 996, + "name": "Fox Ayers", + "gender": "male", + "age": 71, + "address": { + "state": "Arizona", + "city": "Enlow" + } + }, + { + "id": 997, + "name": "Kerry Raymond", + "gender": "female", + "age": 34, + "address": { + "state": "Nevada", + "city": "Fredericktown" + } + }, + { + "id": 998, + "name": "Valentine Roman", + "gender": "male", + "age": 59, + "address": { + "state": "New Mexico", + "city": "Terlingua" + } + }, + { + "id": 999, + "name": "Macias Collier", + "gender": "male", + "age": 30, + "address": { + "state": "North Carolina", + "city": "Shepardsville" + } + }, + { + "id": 1000, + "name": "Delia Gaines", + "gender": "female", + "age": 82, + "address": { + "state": "Florida", + "city": "Malott" + } + }, + { + "id": 1001, + "name": "Julie Ware", + "gender": "female", + "age": 27, + "address": { + "state": "Washington", + "city": "Trail" + } + }, + { + "id": 1002, + "name": "Newman Ross", + "gender": "male", + "age": 70, + "address": { + "state": "Mississippi", + "city": "Curtice" + } + }, + { + "id": 1003, + "name": "Nona Kirkland", + "gender": "female", + "age": 48, + "address": { + "state": "Massachusetts", + "city": "Innsbrook" + } + }, + { + "id": 1004, + "name": "Vicky Dickerson", + "gender": "female", + "age": 48, + "address": { + "state": "Rhode Island", + "city": "Roderfield" + } + }, + { + "id": 1005, + "name": "Kaitlin Sharpe", + "gender": "female", + "age": 81, + "address": { + "state": "Indiana", + "city": "Efland" + } + }, + { + "id": 1006, + "name": "Figueroa George", + "gender": "male", + "age": 24, + "address": { + "state": "New Jersey", + "city": "Noxen" + } + }, + { + "id": 1007, + "name": "Bullock Dunlap", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Hickory" + } + }, + { + "id": 1008, + "name": "Everett Washington", + "gender": "male", + "age": 64, + "address": { + "state": "Pennsylvania", + "city": "Freelandville" + } + }, + { + "id": 1009, + "name": "Tamra Allen", + "gender": "female", + "age": 44, + "address": { + "state": "Nebraska", + "city": "Jenkinsville" + } + }, + { + "id": 1010, + "name": "Gretchen Solis", + "gender": "female", + "age": 44, + "address": { + "state": "Wyoming", + "city": "Cochranville" + } + }, + { + "id": 1011, + "name": "Sherri Craft", + "gender": "female", + "age": 52, + "address": { + "state": "California", + "city": "Dexter" + } + }, + { + "id": 1012, + "name": "Kendra Durham", + "gender": "female", + "age": 26, + "address": { + "state": "Hawaii", + "city": "Winston" + } + }, + { + "id": 1013, + "name": "Nunez Holcomb", + "gender": "male", + "age": 21, + "address": { + "state": "South Carolina", + "city": "Glasgow" + } + }, + { + "id": 1014, + "name": "Eileen Park", + "gender": "female", + "age": 48, + "address": { + "state": "Kentucky", + "city": "Cliff" + } + }, + { + "id": 1015, + "name": "Katheryn Duncan", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Dellview" + } + }, + { + "id": 1016, + "name": "Becky Church", + "gender": "female", + "age": 62, + "address": { + "state": "Connecticut", + "city": "Aberdeen" + } + }, + { + "id": 1017, + "name": "David Fletcher", + "gender": "male", + "age": 51, + "address": { + "state": "North Dakota", + "city": "Coyote" + } + }, + { + "id": 1018, + "name": "Rowland Rogers", + "gender": "male", + "age": 57, + "address": { + "state": "Kansas", + "city": "Montura" + } + }, + { + "id": 1019, + "name": "Crystal Kane", + "gender": "female", + "age": 52, + "address": { + "state": "Virginia", + "city": "Rosedale" + } + }, + { + "id": 1020, + "name": "Rodriquez Mercer", + "gender": "male", + "age": 51, + "address": { + "state": "Tennessee", + "city": "Brambleton" + } + }, + { + "id": 1021, + "name": "Laverne Larson", + "gender": "female", + "age": 36, + "address": { + "state": "Wisconsin", + "city": "Roberts" + } + }, + { + "id": 1022, + "name": "Oliver Lowery", + "gender": "male", + "age": 70, + "address": { + "state": "Colorado", + "city": "Tedrow" + } + }, + { + "id": 1023, + "name": "Herring Newton", + "gender": "male", + "age": 25, + "address": { + "state": "Oregon", + "city": "Frank" + } + }, + { + "id": 1024, + "name": "Cross Whitney", + "gender": "male", + "age": 73, + "address": { + "state": "Alaska", + "city": "Inkerman" + } + }, + { + "id": 1025, + "name": "Mcneil Barber", + "gender": "male", + "age": 45, + "address": { + "state": "Texas", + "city": "Colton" + } + }, + { + "id": 1026, + "name": "Barbra Morton", + "gender": "female", + "age": 31, + "address": { + "state": "Arkansas", + "city": "Holcombe" + } + }, + { + "id": 1027, + "name": "Jasmine Lee", + "gender": "female", + "age": 28, + "address": { + "state": "Vermont", + "city": "Broadlands" + } + }, + { + "id": 1028, + "name": "Cooke Key", + "gender": "male", + "age": 64, + "address": { + "state": "Maine", + "city": "Sunbury" + } + }, + { + "id": 1029, + "name": "Holcomb Tate", + "gender": "male", + "age": 48, + "address": { + "state": "Vermont", + "city": "Sussex" + } + }, + { + "id": 1030, + "name": "Saundra Richards", + "gender": "female", + "age": 49, + "address": { + "state": "Tennessee", + "city": "Zarephath" + } + }, + { + "id": 1031, + "name": "Tania Snyder", + "gender": "female", + "age": 36, + "address": { + "state": "Maryland", + "city": "Avalon" + } + }, + { + "id": 1032, + "name": "Dalton Tate", + "gender": "male", + "age": 32, + "address": { + "state": "Delaware", + "city": "Greenock" + } + }, + { + "id": 1033, + "name": "Holcomb Castillo", + "gender": "male", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Leyner" + } + }, + { + "id": 1034, + "name": "Figueroa Santiago", + "gender": "male", + "age": 32, + "address": { + "state": "Massachusetts", + "city": "Leroy" + } + }, + { + "id": 1035, + "name": "Steele Copeland", + "gender": "male", + "age": 43, + "address": { + "state": "Montana", + "city": "Dargan" + } + }, + { + "id": 1036, + "name": "Eleanor Hernandez", + "gender": "female", + "age": 62, + "address": { + "state": "Arkansas", + "city": "Dundee" + } + }, + { + "id": 1037, + "name": "Leah Hurley", + "gender": "female", + "age": 81, + "address": { + "state": "Texas", + "city": "Oley" + } + }, + { + "id": 1038, + "name": "Mccray Franks", + "gender": "male", + "age": 55, + "address": { + "state": "California", + "city": "Gorham" + } + }, + { + "id": 1039, + "name": "Sanders Osborne", + "gender": "male", + "age": 27, + "address": { + "state": "Wisconsin", + "city": "Sabillasville" + } + }, + { + "id": 1040, + "name": "Gabrielle Landry", + "gender": "female", + "age": 29, + "address": { + "state": "Alaska", + "city": "Ladera" + } + }, + { + "id": 1041, + "name": "Garrett Morrison", + "gender": "male", + "age": 75, + "address": { + "state": "South Carolina", + "city": "Leola" + } + }, + { + "id": 1042, + "name": "Christy Watts", + "gender": "female", + "age": 40, + "address": { + "state": "South Dakota", + "city": "Dixie" + } + }, + { + "id": 1043, + "name": "Atkins Clarke", + "gender": "male", + "age": 57, + "address": { + "state": "Kentucky", + "city": "Fairmount" + } + }, + { + "id": 1044, + "name": "Wiley Odonnell", + "gender": "male", + "age": 54, + "address": { + "state": "Georgia", + "city": "Snelling" + } + }, + { + "id": 1045, + "name": "Thomas Carney", + "gender": "male", + "age": 30, + "address": { + "state": "New York", + "city": "Forestburg" + } + }, + { + "id": 1046, + "name": "Barker Rowland", + "gender": "male", + "age": 44, + "address": { + "state": "Arizona", + "city": "Kiskimere" + } + }, + { + "id": 1047, + "name": "Campos Deleon", + "gender": "male", + "age": 63, + "address": { + "state": "Connecticut", + "city": "Brutus" + } + }, + { + "id": 1048, + "name": "Marisol Fuller", + "gender": "female", + "age": 80, + "address": { + "state": "Virginia", + "city": "Munjor" + } + }, + { + "id": 1049, + "name": "Barrera Morgan", + "gender": "male", + "age": 27, + "address": { + "state": "Alabama", + "city": "Vicksburg" + } + }, + { + "id": 1050, + "name": "Trudy Baird", + "gender": "female", + "age": 80, + "address": { + "state": "West Virginia", + "city": "Allamuchy" + } + }, + { + "id": 1051, + "name": "Carney Richmond", + "gender": "male", + "age": 62, + "address": { + "state": "Missouri", + "city": "Cumminsville" + } + }, + { + "id": 1052, + "name": "Brooke Garrison", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Matheny" + } + }, + { + "id": 1053, + "name": "Jacquelyn Raymond", + "gender": "female", + "age": 43, + "address": { + "state": "Minnesota", + "city": "Hollymead" + } + }, + { + "id": 1054, + "name": "Doyle Hoffman", + "gender": "male", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Murillo" + } + }, + { + "id": 1055, + "name": "Summer Bright", + "gender": "female", + "age": 18, + "address": { + "state": "Rhode Island", + "city": "Trexlertown" + } + }, + { + "id": 1056, + "name": "Burch Vincent", + "gender": "male", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Edgewater" + } + }, + { + "id": 1057, + "name": "Viola Kirby", + "gender": "female", + "age": 72, + "address": { + "state": "Florida", + "city": "Jardine" + } + }, + { + "id": 1058, + "name": "Traci Wolfe", + "gender": "female", + "age": 24, + "address": { + "state": "Michigan", + "city": "Highland" + } + }, + { + "id": 1059, + "name": "Cobb Bruce", + "gender": "male", + "age": 82, + "address": { + "state": "Washington", + "city": "Clay" + } + }, + { + "id": 1060, + "name": "Esperanza Robles", + "gender": "female", + "age": 33, + "address": { + "state": "Colorado", + "city": "Shepardsville" + } + }, + { + "id": 1061, + "name": "Willis Barnes", + "gender": "male", + "age": 50, + "address": { + "state": "Illinois", + "city": "Beyerville" + } + }, + { + "id": 1062, + "name": "Susan Santana", + "gender": "female", + "age": 77, + "address": { + "state": "Utah", + "city": "Coaldale" + } + }, + { + "id": 1063, + "name": "Guadalupe Frederick", + "gender": "female", + "age": 39, + "address": { + "state": "Hawaii", + "city": "Takilma" + } + }, + { + "id": 1064, + "name": "Anne Giles", + "gender": "female", + "age": 25, + "address": { + "state": "North Carolina", + "city": "Osmond" + } + }, + { + "id": 1065, + "name": "Jennifer Frye", + "gender": "female", + "age": 58, + "address": { + "state": "Louisiana", + "city": "Ilchester" + } + }, + { + "id": 1066, + "name": "Pugh Roberson", + "gender": "male", + "age": 61, + "address": { + "state": "Iowa", + "city": "Siglerville" + } + }, + { + "id": 1067, + "name": "Sandra Pace", + "gender": "female", + "age": 49, + "address": { + "state": "Pennsylvania", + "city": "Kipp" + } + }, + { + "id": 1068, + "name": "Jeannine Kaufman", + "gender": "female", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Elliott" + } + }, + { + "id": 1069, + "name": "Lenore Lamb", + "gender": "female", + "age": 67, + "address": { + "state": "Wyoming", + "city": "Loretto" + } + }, + { + "id": 1070, + "name": "Ida Dotson", + "gender": "female", + "age": 21, + "address": { + "state": "Ohio", + "city": "Manitou" + } + }, + { + "id": 1071, + "name": "Cannon Dale", + "gender": "male", + "age": 37, + "address": { + "state": "Indiana", + "city": "Hayden" + } + }, + { + "id": 1072, + "name": "Reese Simmons", + "gender": "male", + "age": 54, + "address": { + "state": "Maine", + "city": "Haring" + } + }, + { + "id": 1073, + "name": "Trujillo Owens", + "gender": "male", + "age": 63, + "address": { + "state": "Kansas", + "city": "Ivanhoe" + } + }, + { + "id": 1074, + "name": "Sloan Travis", + "gender": "male", + "age": 20, + "address": { + "state": "New Mexico", + "city": "Swartzville" + } + }, + { + "id": 1075, + "name": "Jacklyn Pacheco", + "gender": "female", + "age": 38, + "address": { + "state": "Idaho", + "city": "Bainbridge" + } + }, + { + "id": 1076, + "name": "Sofia Meyer", + "gender": "female", + "age": 45, + "address": { + "state": "Oregon", + "city": "Newkirk" + } + }, + { + "id": 1077, + "name": "Mavis Olsen", + "gender": "female", + "age": 67, + "address": { + "state": "Nevada", + "city": "Websterville" + } + }, + { + "id": 1078, + "name": "Estes Murray", + "gender": "male", + "age": 20, + "address": { + "state": "New York", + "city": "Kylertown" + } + }, + { + "id": 1079, + "name": "Bates Dixon", + "gender": "male", + "age": 50, + "address": { + "state": "Vermont", + "city": "Virgie" + } + }, + { + "id": 1080, + "name": "Nielsen Haynes", + "gender": "male", + "age": 49, + "address": { + "state": "Mississippi", + "city": "Castleton" + } + }, + { + "id": 1081, + "name": "Alana Nixon", + "gender": "female", + "age": 64, + "address": { + "state": "New Hampshire", + "city": "Chestnut" + } + }, + { + "id": 1082, + "name": "Delacruz Beard", + "gender": "male", + "age": 66, + "address": { + "state": "New Jersey", + "city": "Conway" + } + }, + { + "id": 1083, + "name": "Dickson Rios", + "gender": "male", + "age": 68, + "address": { + "state": "Connecticut", + "city": "Sutton" + } + }, + { + "id": 1084, + "name": "Meagan Hicks", + "gender": "female", + "age": 47, + "address": { + "state": "Kansas", + "city": "Aberdeen" + } + }, + { + "id": 1085, + "name": "Hampton Clemons", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Mulino" + } + }, + { + "id": 1086, + "name": "Glover Bush", + "gender": "male", + "age": 79, + "address": { + "state": "Delaware", + "city": "Lynn" + } + }, + { + "id": 1087, + "name": "Caitlin Hooper", + "gender": "female", + "age": 31, + "address": { + "state": "Texas", + "city": "Ferney" + } + }, + { + "id": 1088, + "name": "Kelly Byrd", + "gender": "male", + "age": 35, + "address": { + "state": "Tennessee", + "city": "Gloucester" + } + }, + { + "id": 1089, + "name": "Carmela Gentry", + "gender": "female", + "age": 81, + "address": { + "state": "Colorado", + "city": "Bennett" + } + }, + { + "id": 1090, + "name": "Bobbi Jimenez", + "gender": "female", + "age": 21, + "address": { + "state": "Rhode Island", + "city": "Kennedyville" + } + }, + { + "id": 1091, + "name": "Rice Herrera", + "gender": "male", + "age": 48, + "address": { + "state": "Massachusetts", + "city": "Smeltertown" + } + }, + { + "id": 1092, + "name": "Karin Haney", + "gender": "female", + "age": 44, + "address": { + "state": "Iowa", + "city": "Wakarusa" + } + }, + { + "id": 1093, + "name": "Elvia Harper", + "gender": "female", + "age": 24, + "address": { + "state": "Arkansas", + "city": "Sunriver" + } + }, + { + "id": 1094, + "name": "Maggie Mcclure", + "gender": "female", + "age": 55, + "address": { + "state": "Idaho", + "city": "Nicholson" + } + }, + { + "id": 1095, + "name": "Hyde Smith", + "gender": "male", + "age": 31, + "address": { + "state": "Nebraska", + "city": "Cornucopia" + } + }, + { + "id": 1096, + "name": "Meyer Emerson", + "gender": "male", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Wescosville" + } + }, + { + "id": 1097, + "name": "Jill Moses", + "gender": "female", + "age": 55, + "address": { + "state": "Montana", + "city": "Alleghenyville" + } + }, + { + "id": 1098, + "name": "Morrow Boone", + "gender": "male", + "age": 37, + "address": { + "state": "Oklahoma", + "city": "Onton" + } + }, + { + "id": 1099, + "name": "Michael Bowman", + "gender": "female", + "age": 32, + "address": { + "state": "Indiana", + "city": "Eastvale" + } + }, + { + "id": 1100, + "name": "Lott Walker", + "gender": "male", + "age": 55, + "address": { + "state": "Minnesota", + "city": "Garnet" + } + }, + { + "id": 1101, + "name": "Robles Oneal", + "gender": "male", + "age": 59, + "address": { + "state": "Arizona", + "city": "Riegelwood" + } + }, + { + "id": 1102, + "name": "Cathleen Coffey", + "gender": "female", + "age": 38, + "address": { + "state": "New Mexico", + "city": "Wyoming" + } + }, + { + "id": 1103, + "name": "Eileen Wooten", + "gender": "female", + "age": 23, + "address": { + "state": "Michigan", + "city": "Macdona" + } + }, + { + "id": 1104, + "name": "Barry Stein", + "gender": "male", + "age": 30, + "address": { + "state": "Pennsylvania", + "city": "Roeville" + } + }, + { + "id": 1105, + "name": "Harriet Sandoval", + "gender": "female", + "age": 75, + "address": { + "state": "California", + "city": "Rodanthe" + } + }, + { + "id": 1106, + "name": "Ward Stout", + "gender": "male", + "age": 67, + "address": { + "state": "Missouri", + "city": "Brady" + } + }, + { + "id": 1107, + "name": "Helga Mays", + "gender": "female", + "age": 43, + "address": { + "state": "Georgia", + "city": "Wanamie" + } + }, + { + "id": 1108, + "name": "Lena Solis", + "gender": "female", + "age": 23, + "address": { + "state": "Illinois", + "city": "Floriston" + } + }, + { + "id": 1109, + "name": "Farrell Yates", + "gender": "male", + "age": 82, + "address": { + "state": "Hawaii", + "city": "Belfair" + } + }, + { + "id": 1110, + "name": "Hogan Ewing", + "gender": "male", + "age": 25, + "address": { + "state": "Nevada", + "city": "Day" + } + }, + { + "id": 1111, + "name": "Zimmerman Morales", + "gender": "male", + "age": 67, + "address": { + "state": "Maine", + "city": "Brantleyville" + } + }, + { + "id": 1112, + "name": "Kristy Hayden", + "gender": "female", + "age": 64, + "address": { + "state": "Maryland", + "city": "Germanton" + } + }, + { + "id": 1113, + "name": "Jennifer Nielsen", + "gender": "female", + "age": 23, + "address": { + "state": "North Carolina", + "city": "Silkworth" + } + }, + { + "id": 1114, + "name": "Clare Finch", + "gender": "female", + "age": 17, + "address": { + "state": "Wisconsin", + "city": "Stagecoach" + } + }, + { + "id": 1115, + "name": "Cox Vang", + "gender": "male", + "age": 25, + "address": { + "state": "Virginia", + "city": "Ballico" + } + }, + { + "id": 1116, + "name": "Dona Trevino", + "gender": "female", + "age": 46, + "address": { + "state": "Ohio", + "city": "Finzel" + } + }, + { + "id": 1117, + "name": "Tina Chang", + "gender": "female", + "age": 22, + "address": { + "state": "Florida", + "city": "Loveland" + } + }, + { + "id": 1118, + "name": "Felecia Roth", + "gender": "female", + "age": 51, + "address": { + "state": "Wyoming", + "city": "Noblestown" + } + }, + { + "id": 1119, + "name": "Hall Warren", + "gender": "male", + "age": 21, + "address": { + "state": "Utah", + "city": "Foxworth" + } + }, + { + "id": 1120, + "name": "Odonnell Scott", + "gender": "male", + "age": 24, + "address": { + "state": "Kentucky", + "city": "Mayfair" + } + }, + { + "id": 1121, + "name": "Turner Vinson", + "gender": "male", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Remington" + } + }, + { + "id": 1122, + "name": "Wright Powell", + "gender": "male", + "age": 24, + "address": { + "state": "Alaska", + "city": "Oberlin" + } + }, + { + "id": 1123, + "name": "White Adkins", + "gender": "male", + "age": 17, + "address": { + "state": "Oregon", + "city": "Allentown" + } + }, + { + "id": 1124, + "name": "Edwards Glover", + "gender": "male", + "age": 53, + "address": { + "state": "Alabama", + "city": "Jeff" + } + }, + { + "id": 1125, + "name": "Camille Goodwin", + "gender": "female", + "age": 76, + "address": { + "state": "Louisiana", + "city": "Brazos" + } + }, + { + "id": 1126, + "name": "Agnes Sargent", + "gender": "female", + "age": 34, + "address": { + "state": "North Dakota", + "city": "Stollings" + } + }, + { + "id": 1127, + "name": "Chapman Mcconnell", + "gender": "male", + "age": 60, + "address": { + "state": "Kansas", + "city": "Canby" + } + }, + { + "id": 1128, + "name": "Tate Freeman", + "gender": "male", + "age": 58, + "address": { + "state": "Iowa", + "city": "Fidelis" + } + }, + { + "id": 1129, + "name": "Kate Crane", + "gender": "female", + "age": 49, + "address": { + "state": "Virginia", + "city": "Alafaya" + } + }, + { + "id": 1130, + "name": "Effie Campbell", + "gender": "female", + "age": 17, + "address": { + "state": "Oregon", + "city": "Oasis" + } + }, + { + "id": 1131, + "name": "Duran Walls", + "gender": "male", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Shawmut" + } + }, + { + "id": 1132, + "name": "Mckay Burke", + "gender": "male", + "age": 52, + "address": { + "state": "New York", + "city": "Frank" + } + }, + { + "id": 1133, + "name": "Tina Houston", + "gender": "female", + "age": 53, + "address": { + "state": "Delaware", + "city": "Needmore" + } + }, + { + "id": 1134, + "name": "Underwood Roy", + "gender": "male", + "age": 20, + "address": { + "state": "New Mexico", + "city": "Starks" + } + }, + { + "id": 1135, + "name": "Abby Sanders", + "gender": "female", + "age": 45, + "address": { + "state": "Oklahoma", + "city": "Somerset" + } + }, + { + "id": 1136, + "name": "Mcdaniel Hays", + "gender": "male", + "age": 22, + "address": { + "state": "Maine", + "city": "Tecolotito" + } + }, + { + "id": 1137, + "name": "Levine Larsen", + "gender": "male", + "age": 38, + "address": { + "state": "Arkansas", + "city": "Adamstown" + } + }, + { + "id": 1138, + "name": "Pickett Stein", + "gender": "male", + "age": 49, + "address": { + "state": "Maryland", + "city": "Movico" + } + }, + { + "id": 1139, + "name": "Charlene Fletcher", + "gender": "female", + "age": 52, + "address": { + "state": "Mississippi", + "city": "Fulford" + } + }, + { + "id": 1140, + "name": "Florine Jones", + "gender": "female", + "age": 34, + "address": { + "state": "New Hampshire", + "city": "Bowmansville" + } + }, + { + "id": 1141, + "name": "Vivian Greer", + "gender": "female", + "age": 53, + "address": { + "state": "Connecticut", + "city": "Cumminsville" + } + }, + { + "id": 1142, + "name": "Myers Ramsey", + "gender": "male", + "age": 73, + "address": { + "state": "Indiana", + "city": "Wanamie" + } + }, + { + "id": 1143, + "name": "Rocha Hammond", + "gender": "male", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Byrnedale" + } + }, + { + "id": 1144, + "name": "Magdalena Blair", + "gender": "female", + "age": 57, + "address": { + "state": "Louisiana", + "city": "Orason" + } + }, + { + "id": 1145, + "name": "Cantu Gordon", + "gender": "male", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Chapin" + } + }, + { + "id": 1146, + "name": "Booth Morton", + "gender": "male", + "age": 46, + "address": { + "state": "New Jersey", + "city": "Boyd" + } + }, + { + "id": 1147, + "name": "Sharlene Shepherd", + "gender": "female", + "age": 59, + "address": { + "state": "Tennessee", + "city": "Matheny" + } + }, + { + "id": 1148, + "name": "Merle Wilkins", + "gender": "female", + "age": 26, + "address": { + "state": "Michigan", + "city": "Lafferty" + } + }, + { + "id": 1149, + "name": "Krista Moody", + "gender": "female", + "age": 34, + "address": { + "state": "Florida", + "city": "Bayview" + } + }, + { + "id": 1150, + "name": "Peggy Eaton", + "gender": "female", + "age": 82, + "address": { + "state": "Georgia", + "city": "Twilight" + } + }, + { + "id": 1151, + "name": "Tameka Patrick", + "gender": "female", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Sena" + } + }, + { + "id": 1152, + "name": "Claudia Berry", + "gender": "female", + "age": 34, + "address": { + "state": "Ohio", + "city": "Fowlerville" + } + }, + { + "id": 1153, + "name": "Snider Mckinney", + "gender": "male", + "age": 32, + "address": { + "state": "Washington", + "city": "Noblestown" + } + }, + { + "id": 1154, + "name": "Horton Glover", + "gender": "male", + "age": 60, + "address": { + "state": "Vermont", + "city": "Nash" + } + }, + { + "id": 1155, + "name": "Mae Vinson", + "gender": "female", + "age": 47, + "address": { + "state": "Rhode Island", + "city": "Foxworth" + } + }, + { + "id": 1156, + "name": "Faith Palmer", + "gender": "female", + "age": 66, + "address": { + "state": "Alabama", + "city": "Groton" + } + }, + { + "id": 1157, + "name": "Savage Brady", + "gender": "male", + "age": 24, + "address": { + "state": "West Virginia", + "city": "Lewis" + } + }, + { + "id": 1158, + "name": "Belinda Moss", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Curtice" + } + }, + { + "id": 1159, + "name": "Durham Thomas", + "gender": "male", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Felt" + } + }, + { + "id": 1160, + "name": "Ginger Bowen", + "gender": "female", + "age": 60, + "address": { + "state": "Montana", + "city": "Deltaville" + } + }, + { + "id": 1161, + "name": "Maxwell Wyatt", + "gender": "male", + "age": 63, + "address": { + "state": "Arizona", + "city": "Mulberry" + } + }, + { + "id": 1162, + "name": "Campos Levy", + "gender": "male", + "age": 44, + "address": { + "state": "Wisconsin", + "city": "Turah" + } + }, + { + "id": 1163, + "name": "Elizabeth Copeland", + "gender": "female", + "age": 54, + "address": { + "state": "Utah", + "city": "Carrsville" + } + }, + { + "id": 1164, + "name": "Herminia Hartman", + "gender": "female", + "age": 28, + "address": { + "state": "Massachusetts", + "city": "Cobbtown" + } + }, + { + "id": 1165, + "name": "Beth Marshall", + "gender": "female", + "age": 17, + "address": { + "state": "Nevada", + "city": "Morriston" + } + }, + { + "id": 1166, + "name": "Lorna Burnett", + "gender": "female", + "age": 34, + "address": { + "state": "Illinois", + "city": "Bartonsville" + } + }, + { + "id": 1167, + "name": "Mable Hull", + "gender": "female", + "age": 33, + "address": { + "state": "North Carolina", + "city": "Forestburg" + } + }, + { + "id": 1168, + "name": "Kayla Mcbride", + "gender": "female", + "age": 58, + "address": { + "state": "Wyoming", + "city": "Stewart" + } + }, + { + "id": 1169, + "name": "Skinner Barlow", + "gender": "male", + "age": 58, + "address": { + "state": "Colorado", + "city": "Rockingham" + } + }, + { + "id": 1170, + "name": "Bass Brennan", + "gender": "male", + "age": 37, + "address": { + "state": "Kentucky", + "city": "Healy" + } + }, + { + "id": 1171, + "name": "Esther Patton", + "gender": "female", + "age": 61, + "address": { + "state": "Alaska", + "city": "Gilgo" + } + }, + { + "id": 1172, + "name": "Edwards Cabrera", + "gender": "male", + "age": 34, + "address": { + "state": "Missouri", + "city": "Teasdale" + } + }, + { + "id": 1173, + "name": "Moody Morrison", + "gender": "male", + "age": 36, + "address": { + "state": "Idaho", + "city": "Croom" + } + }, + { + "id": 1174, + "name": "Castillo Gray", + "gender": "male", + "age": 62, + "address": { + "state": "Pennsylvania", + "city": "Roland" + } + }, + { + "id": 1175, + "name": "Evans Pitts", + "gender": "male", + "age": 39, + "address": { + "state": "North Dakota", + "city": "Leeper" + } + }, + { + "id": 1176, + "name": "Kaufman Kirby", + "gender": "male", + "age": 25, + "address": { + "state": "Vermont", + "city": "Brenton" + } + }, + { + "id": 1177, + "name": "Wallace Justice", + "gender": "male", + "age": 73, + "address": { + "state": "New York", + "city": "Hasty" + } + }, + { + "id": 1178, + "name": "Robertson Merrill", + "gender": "male", + "age": 30, + "address": { + "state": "Iowa", + "city": "Rodanthe" + } + }, + { + "id": 1179, + "name": "Patterson Holman", + "gender": "male", + "age": 54, + "address": { + "state": "Wisconsin", + "city": "Leola" + } + }, + { + "id": 1180, + "name": "Garcia Delacruz", + "gender": "male", + "age": 18, + "address": { + "state": "Colorado", + "city": "Homeworth" + } + }, + { + "id": 1181, + "name": "Valeria Compton", + "gender": "female", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Oretta" + } + }, + { + "id": 1182, + "name": "Renee Landry", + "gender": "female", + "age": 43, + "address": { + "state": "New Hampshire", + "city": "Bergoo" + } + }, + { + "id": 1183, + "name": "Noel Thompson", + "gender": "male", + "age": 20, + "address": { + "state": "Mississippi", + "city": "Ebro" + } + }, + { + "id": 1184, + "name": "Elisabeth Johnston", + "gender": "female", + "age": 31, + "address": { + "state": "Virginia", + "city": "Graniteville" + } + }, + { + "id": 1185, + "name": "Wagner Holder", + "gender": "male", + "age": 28, + "address": { + "state": "West Virginia", + "city": "Hannasville" + } + }, + { + "id": 1186, + "name": "Molina Holt", + "gender": "male", + "age": 69, + "address": { + "state": "Massachusetts", + "city": "Hayes" + } + }, + { + "id": 1187, + "name": "Payne Deleon", + "gender": "male", + "age": 66, + "address": { + "state": "Minnesota", + "city": "Klondike" + } + }, + { + "id": 1188, + "name": "Curry Sherman", + "gender": "male", + "age": 39, + "address": { + "state": "Illinois", + "city": "Trinway" + } + }, + { + "id": 1189, + "name": "Velasquez Valdez", + "gender": "male", + "age": 28, + "address": { + "state": "Utah", + "city": "Hillsboro" + } + }, + { + "id": 1190, + "name": "Hilda Chapman", + "gender": "female", + "age": 32, + "address": { + "state": "Oregon", + "city": "Edgewater" + } + }, + { + "id": 1191, + "name": "Evans Adkins", + "gender": "male", + "age": 67, + "address": { + "state": "South Dakota", + "city": "Darlington" + } + }, + { + "id": 1192, + "name": "Lois Woodward", + "gender": "female", + "age": 68, + "address": { + "state": "Missouri", + "city": "Oberlin" + } + }, + { + "id": 1193, + "name": "Lily Meadows", + "gender": "female", + "age": 66, + "address": { + "state": "Maryland", + "city": "Centerville" + } + }, + { + "id": 1194, + "name": "Carney Lambert", + "gender": "male", + "age": 20, + "address": { + "state": "Florida", + "city": "Klagetoh" + } + }, + { + "id": 1195, + "name": "Gross Hebert", + "gender": "male", + "age": 69, + "address": { + "state": "Maine", + "city": "Chalfant" + } + }, + { + "id": 1196, + "name": "Nola Page", + "gender": "female", + "age": 43, + "address": { + "state": "California", + "city": "Brazos" + } + }, + { + "id": 1197, + "name": "Cleveland Fletcher", + "gender": "male", + "age": 24, + "address": { + "state": "Indiana", + "city": "Rivers" + } + }, + { + "id": 1198, + "name": "Rasmussen Gallagher", + "gender": "male", + "age": 33, + "address": { + "state": "Michigan", + "city": "Retsof" + } + }, + { + "id": 1199, + "name": "Nelda Terry", + "gender": "female", + "age": 19, + "address": { + "state": "Washington", + "city": "Waumandee" + } + }, + { + "id": 1200, + "name": "Maria Lindsay", + "gender": "female", + "age": 65, + "address": { + "state": "Montana", + "city": "Sheatown" + } + }, + { + "id": 1201, + "name": "Deirdre Washington", + "gender": "female", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Shindler" + } + }, + { + "id": 1202, + "name": "Shelly Beasley", + "gender": "female", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Lowell" + } + }, + { + "id": 1203, + "name": "Porter Schmidt", + "gender": "male", + "age": 75, + "address": { + "state": "Nevada", + "city": "Carbonville" + } + }, + { + "id": 1204, + "name": "Consuelo Shepard", + "gender": "female", + "age": 61, + "address": { + "state": "Idaho", + "city": "Sunnyside" + } + }, + { + "id": 1205, + "name": "Carey Lopez", + "gender": "female", + "age": 19, + "address": { + "state": "North Dakota", + "city": "Utting" + } + }, + { + "id": 1206, + "name": "Bush Ellis", + "gender": "male", + "age": 59, + "address": { + "state": "Arkansas", + "city": "Groveville" + } + }, + { + "id": 1207, + "name": "June Schwartz", + "gender": "female", + "age": 52, + "address": { + "state": "Louisiana", + "city": "Drytown" + } + }, + { + "id": 1208, + "name": "Wilkinson Baldwin", + "gender": "male", + "age": 36, + "address": { + "state": "Texas", + "city": "Clarksburg" + } + }, + { + "id": 1209, + "name": "Kim Bailey", + "gender": "male", + "age": 27, + "address": { + "state": "Nebraska", + "city": "Munjor" + } + }, + { + "id": 1210, + "name": "Katie Parsons", + "gender": "female", + "age": 68, + "address": { + "state": "North Carolina", + "city": "Coloma" + } + }, + { + "id": 1211, + "name": "Velez Barlow", + "gender": "male", + "age": 23, + "address": { + "state": "Alaska", + "city": "Robbins" + } + }, + { + "id": 1212, + "name": "Schmidt Rojas", + "gender": "male", + "age": 31, + "address": { + "state": "Tennessee", + "city": "Hoagland" + } + }, + { + "id": 1213, + "name": "Duffy Gill", + "gender": "male", + "age": 27, + "address": { + "state": "South Carolina", + "city": "Bluffview" + } + }, + { + "id": 1214, + "name": "Noble Cunningham", + "gender": "male", + "age": 45, + "address": { + "state": "Oklahoma", + "city": "Florence" + } + }, + { + "id": 1215, + "name": "Vang Figueroa", + "gender": "male", + "age": 81, + "address": { + "state": "Georgia", + "city": "Zarephath" + } + }, + { + "id": 1216, + "name": "West Velazquez", + "gender": "male", + "age": 66, + "address": { + "state": "Delaware", + "city": "Springville" + } + }, + { + "id": 1217, + "name": "Key Sexton", + "gender": "male", + "age": 65, + "address": { + "state": "Alabama", + "city": "Caledonia" + } + }, + { + "id": 1218, + "name": "Cassandra Rios", + "gender": "female", + "age": 79, + "address": { + "state": "Wyoming", + "city": "Whitehaven" + } + }, + { + "id": 1219, + "name": "Kayla Slater", + "gender": "female", + "age": 67, + "address": { + "state": "Kentucky", + "city": "Lutsen" + } + }, + { + "id": 1220, + "name": "Booker Davidson", + "gender": "male", + "age": 34, + "address": { + "state": "Hawaii", + "city": "Wacissa" + } + }, + { + "id": 1221, + "name": "Beard Melton", + "gender": "male", + "age": 47, + "address": { + "state": "Ohio", + "city": "Jeff" + } + }, + { + "id": 1222, + "name": "Dona Rush", + "gender": "female", + "age": 17, + "address": { + "state": "Kansas", + "city": "Joppa" + } + }, + { + "id": 1223, + "name": "Maggie Waller", + "gender": "female", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Clarktown" + } + }, + { + "id": 1224, + "name": "Rene Thornton", + "gender": "female", + "age": 32, + "address": { + "state": "New Jersey", + "city": "Vale" + } + }, + { + "id": 1225, + "name": "Hudson Holloway", + "gender": "male", + "age": 62, + "address": { + "state": "Alaska", + "city": "Glendale" + } + }, + { + "id": 1226, + "name": "Kristin Bryant", + "gender": "female", + "age": 31, + "address": { + "state": "Indiana", + "city": "Tuttle" + } + }, + { + "id": 1227, + "name": "Jeanette Shaffer", + "gender": "female", + "age": 22, + "address": { + "state": "Virginia", + "city": "Tooleville" + } + }, + { + "id": 1228, + "name": "Katelyn Boyd", + "gender": "female", + "age": 44, + "address": { + "state": "Illinois", + "city": "Allison" + } + }, + { + "id": 1229, + "name": "Latoya Odonnell", + "gender": "female", + "age": 41, + "address": { + "state": "Missouri", + "city": "Grahamtown" + } + }, + { + "id": 1230, + "name": "Acosta Barlow", + "gender": "male", + "age": 30, + "address": { + "state": "Arkansas", + "city": "Greenfields" + } + }, + { + "id": 1231, + "name": "Catherine Campbell", + "gender": "female", + "age": 40, + "address": { + "state": "South Carolina", + "city": "Darrtown" + } + }, + { + "id": 1232, + "name": "Hunt Delacruz", + "gender": "male", + "age": 49, + "address": { + "state": "Nebraska", + "city": "Stonybrook" + } + }, + { + "id": 1233, + "name": "Duran Strickland", + "gender": "male", + "age": 51, + "address": { + "state": "Massachusetts", + "city": "Sunnyside" + } + }, + { + "id": 1234, + "name": "Boyle Rogers", + "gender": "male", + "age": 51, + "address": { + "state": "New Hampshire", + "city": "Efland" + } + }, + { + "id": 1235, + "name": "Horton Ray", + "gender": "male", + "age": 82, + "address": { + "state": "Alabama", + "city": "Tampico" + } + }, + { + "id": 1236, + "name": "Christian Nelson", + "gender": "female", + "age": 17, + "address": { + "state": "Utah", + "city": "Bayview" + } + }, + { + "id": 1237, + "name": "Leola Michael", + "gender": "female", + "age": 71, + "address": { + "state": "Arizona", + "city": "Barclay" + } + }, + { + "id": 1238, + "name": "Katherine Middleton", + "gender": "female", + "age": 35, + "address": { + "state": "Connecticut", + "city": "Healy" + } + }, + { + "id": 1239, + "name": "Sara Gilliam", + "gender": "female", + "age": 80, + "address": { + "state": "Mississippi", + "city": "Bergoo" + } + }, + { + "id": 1240, + "name": "Fleming Page", + "gender": "male", + "age": 64, + "address": { + "state": "Texas", + "city": "Mayfair" + } + }, + { + "id": 1241, + "name": "Ochoa Koch", + "gender": "male", + "age": 79, + "address": { + "state": "Vermont", + "city": "Osmond" + } + }, + { + "id": 1242, + "name": "Pollard Frye", + "gender": "male", + "age": 31, + "address": { + "state": "Florida", + "city": "Klondike" + } + }, + { + "id": 1243, + "name": "Rosalyn Glass", + "gender": "female", + "age": 71, + "address": { + "state": "Louisiana", + "city": "Maxville" + } + }, + { + "id": 1244, + "name": "Stein Hanson", + "gender": "male", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Nelson" + } + }, + { + "id": 1245, + "name": "Bauer Solomon", + "gender": "male", + "age": 60, + "address": { + "state": "Montana", + "city": "Nadine" + } + }, + { + "id": 1246, + "name": "Morton Alexander", + "gender": "male", + "age": 46, + "address": { + "state": "California", + "city": "Robinson" + } + }, + { + "id": 1247, + "name": "Mullen Ware", + "gender": "male", + "age": 31, + "address": { + "state": "Maryland", + "city": "Kenvil" + } + }, + { + "id": 1248, + "name": "Hammond Albert", + "gender": "male", + "age": 55, + "address": { + "state": "Oregon", + "city": "Garberville" + } + }, + { + "id": 1249, + "name": "Rogers Parrish", + "gender": "male", + "age": 61, + "address": { + "state": "Delaware", + "city": "Edneyville" + } + }, + { + "id": 1250, + "name": "Hewitt Case", + "gender": "male", + "age": 44, + "address": { + "state": "South Dakota", + "city": "Leland" + } + }, + { + "id": 1251, + "name": "Brooke Phelps", + "gender": "female", + "age": 30, + "address": { + "state": "Colorado", + "city": "Santel" + } + }, + { + "id": 1252, + "name": "Kimberley Coffey", + "gender": "female", + "age": 45, + "address": { + "state": "West Virginia", + "city": "Haena" + } + }, + { + "id": 1253, + "name": "Buckley Schmidt", + "gender": "male", + "age": 55, + "address": { + "state": "Maine", + "city": "Graball" + } + }, + { + "id": 1254, + "name": "Christa Foster", + "gender": "female", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Belfair" + } + }, + { + "id": 1255, + "name": "Lola Sears", + "gender": "female", + "age": 81, + "address": { + "state": "Kansas", + "city": "Florence" + } + }, + { + "id": 1256, + "name": "Hobbs Tyson", + "gender": "male", + "age": 32, + "address": { + "state": "New York", + "city": "Kingstowne" + } + }, + { + "id": 1257, + "name": "Young Greene", + "gender": "male", + "age": 44, + "address": { + "state": "North Dakota", + "city": "Crisman" + } + }, + { + "id": 1258, + "name": "Christian Schneider", + "gender": "male", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Salvo" + } + }, + { + "id": 1259, + "name": "Lakisha Gill", + "gender": "female", + "age": 52, + "address": { + "state": "Minnesota", + "city": "Enetai" + } + }, + { + "id": 1260, + "name": "Susana Ross", + "gender": "female", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Calvary" + } + }, + { + "id": 1261, + "name": "Shelton Hernandez", + "gender": "male", + "age": 59, + "address": { + "state": "Nevada", + "city": "Drummond" + } + }, + { + "id": 1262, + "name": "Sheppard Murphy", + "gender": "male", + "age": 20, + "address": { + "state": "Iowa", + "city": "Elliston" + } + }, + { + "id": 1263, + "name": "Bettie Vaughan", + "gender": "female", + "age": 70, + "address": { + "state": "North Carolina", + "city": "Washington" + } + }, + { + "id": 1264, + "name": "Casandra Whitehead", + "gender": "female", + "age": 49, + "address": { + "state": "Ohio", + "city": "Twilight" + } + }, + { + "id": 1265, + "name": "Booker Jennings", + "gender": "male", + "age": 18, + "address": { + "state": "Georgia", + "city": "Swartzville" + } + }, + { + "id": 1266, + "name": "Morse Mueller", + "gender": "male", + "age": 58, + "address": { + "state": "Michigan", + "city": "Caberfae" + } + }, + { + "id": 1267, + "name": "Joyce Franklin", + "gender": "male", + "age": 75, + "address": { + "state": "Tennessee", + "city": "Newcastle" + } + }, + { + "id": 1268, + "name": "Kate Chang", + "gender": "female", + "age": 53, + "address": { + "state": "Kentucky", + "city": "Leeper" + } + }, + { + "id": 1269, + "name": "Stephens Powell", + "gender": "male", + "age": 28, + "address": { + "state": "Idaho", + "city": "Elliott" + } + }, + { + "id": 1270, + "name": "Milagros Cooke", + "gender": "female", + "age": 82, + "address": { + "state": "Wyoming", + "city": "Greenbackville" + } + }, + { + "id": 1271, + "name": "Humphrey Conner", + "gender": "male", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Graniteville" + } + }, + { + "id": 1272, + "name": "Bertie Cote", + "gender": "female", + "age": 48, + "address": { + "state": "Rhode Island", + "city": "Vienna" + } + }, + { + "id": 1273, + "name": "Bell Mooney", + "gender": "male", + "age": 29, + "address": { + "state": "Wisconsin", + "city": "Jamestown" + } + }, + { + "id": 1274, + "name": "Whitehead Johnston", + "gender": "male", + "age": 41, + "address": { + "state": "Alabama", + "city": "Bayview" + } + }, + { + "id": 1275, + "name": "Cobb Hays", + "gender": "male", + "age": 75, + "address": { + "state": "Michigan", + "city": "Wells" + } + }, + { + "id": 1276, + "name": "Fern Buchanan", + "gender": "female", + "age": 61, + "address": { + "state": "North Carolina", + "city": "Accoville" + } + }, + { + "id": 1277, + "name": "Tracey Meadows", + "gender": "female", + "age": 72, + "address": { + "state": "Tennessee", + "city": "Longoria" + } + }, + { + "id": 1278, + "name": "Stevenson Talley", + "gender": "male", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Murillo" + } + }, + { + "id": 1279, + "name": "Cherry Kirby", + "gender": "male", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Belva" + } + }, + { + "id": 1280, + "name": "Howell Maynard", + "gender": "male", + "age": 56, + "address": { + "state": "Minnesota", + "city": "Hebron" + } + }, + { + "id": 1281, + "name": "Ethel Richards", + "gender": "female", + "age": 19, + "address": { + "state": "Massachusetts", + "city": "Felt" + } + }, + { + "id": 1282, + "name": "Ida Holt", + "gender": "female", + "age": 46, + "address": { + "state": "Mississippi", + "city": "Wright" + } + }, + { + "id": 1283, + "name": "Heather Chaney", + "gender": "female", + "age": 38, + "address": { + "state": "New Mexico", + "city": "Fairlee" + } + }, + { + "id": 1284, + "name": "Erickson Terrell", + "gender": "male", + "age": 25, + "address": { + "state": "Kentucky", + "city": "Rodman" + } + }, + { + "id": 1285, + "name": "Nora Hurley", + "gender": "female", + "age": 63, + "address": { + "state": "Indiana", + "city": "Takilma" + } + }, + { + "id": 1286, + "name": "Stephenson Guy", + "gender": "male", + "age": 57, + "address": { + "state": "Iowa", + "city": "Northchase" + } + }, + { + "id": 1287, + "name": "Johnnie Schmidt", + "gender": "female", + "age": 29, + "address": { + "state": "South Carolina", + "city": "Davenport" + } + }, + { + "id": 1288, + "name": "Terry Schneider", + "gender": "male", + "age": 17, + "address": { + "state": "Oregon", + "city": "Savage" + } + }, + { + "id": 1289, + "name": "Daniel Mcbride", + "gender": "male", + "age": 49, + "address": { + "state": "Oklahoma", + "city": "Fidelis" + } + }, + { + "id": 1290, + "name": "Conrad Finley", + "gender": "male", + "age": 67, + "address": { + "state": "Maine", + "city": "Sutton" + } + }, + { + "id": 1291, + "name": "Iris Delacruz", + "gender": "female", + "age": 80, + "address": { + "state": "Florida", + "city": "Utting" + } + }, + { + "id": 1292, + "name": "Amie Franklin", + "gender": "female", + "age": 79, + "address": { + "state": "New Jersey", + "city": "Lemoyne" + } + }, + { + "id": 1293, + "name": "Wall Walter", + "gender": "male", + "age": 80, + "address": { + "state": "New York", + "city": "Sharon" + } + }, + { + "id": 1294, + "name": "Trujillo Davidson", + "gender": "male", + "age": 67, + "address": { + "state": "Colorado", + "city": "Motley" + } + }, + { + "id": 1295, + "name": "Kara Cox", + "gender": "female", + "age": 41, + "address": { + "state": "Washington", + "city": "Wanamie" + } + }, + { + "id": 1296, + "name": "Shelley Nash", + "gender": "female", + "age": 41, + "address": { + "state": "Illinois", + "city": "Chase" + } + }, + { + "id": 1297, + "name": "Kaitlin Cherry", + "gender": "female", + "age": 40, + "address": { + "state": "Ohio", + "city": "Springdale" + } + }, + { + "id": 1298, + "name": "Hannah Anderson", + "gender": "female", + "age": 55, + "address": { + "state": "Pennsylvania", + "city": "Crown" + } + }, + { + "id": 1299, + "name": "Mack Huff", + "gender": "male", + "age": 76, + "address": { + "state": "Maryland", + "city": "Rew" + } + }, + { + "id": 1300, + "name": "Rhodes Shepherd", + "gender": "male", + "age": 58, + "address": { + "state": "Kansas", + "city": "Lafferty" + } + }, + { + "id": 1301, + "name": "Kathleen Marks", + "gender": "female", + "age": 35, + "address": { + "state": "Alaska", + "city": "Faxon" + } + }, + { + "id": 1302, + "name": "Elena Hood", + "gender": "female", + "age": 46, + "address": { + "state": "Arkansas", + "city": "Waukeenah" + } + }, + { + "id": 1303, + "name": "Dana Mcgee", + "gender": "female", + "age": 34, + "address": { + "state": "Virginia", + "city": "Forestburg" + } + }, + { + "id": 1304, + "name": "Frances Rivers", + "gender": "female", + "age": 45, + "address": { + "state": "Missouri", + "city": "Cobbtown" + } + }, + { + "id": 1305, + "name": "Essie Ford", + "gender": "female", + "age": 65, + "address": { + "state": "Georgia", + "city": "Bodega" + } + }, + { + "id": 1306, + "name": "Priscilla Bean", + "gender": "female", + "age": 67, + "address": { + "state": "Connecticut", + "city": "Libertytown" + } + }, + { + "id": 1307, + "name": "Brenda Walker", + "gender": "female", + "age": 49, + "address": { + "state": "California", + "city": "Yorklyn" + } + }, + { + "id": 1308, + "name": "Levine William", + "gender": "male", + "age": 17, + "address": { + "state": "Texas", + "city": "Katonah" + } + }, + { + "id": 1309, + "name": "Mattie Hopper", + "gender": "female", + "age": 49, + "address": { + "state": "North Dakota", + "city": "Guilford" + } + }, + { + "id": 1310, + "name": "Opal Becker", + "gender": "female", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Hillsboro" + } + }, + { + "id": 1311, + "name": "Katina King", + "gender": "female", + "age": 24, + "address": { + "state": "New Hampshire", + "city": "Orviston" + } + }, + { + "id": 1312, + "name": "Clay Nunez", + "gender": "male", + "age": 48, + "address": { + "state": "Hawaii", + "city": "Buxton" + } + }, + { + "id": 1313, + "name": "Eloise Mclaughlin", + "gender": "female", + "age": 37, + "address": { + "state": "Utah", + "city": "Devon" + } + }, + { + "id": 1314, + "name": "Gail Ramos", + "gender": "female", + "age": 23, + "address": { + "state": "Idaho", + "city": "Chaparrito" + } + }, + { + "id": 1315, + "name": "Ruth Campbell", + "gender": "female", + "age": 19, + "address": { + "state": "Louisiana", + "city": "Nord" + } + }, + { + "id": 1316, + "name": "Yvonne Finch", + "gender": "female", + "age": 47, + "address": { + "state": "Nevada", + "city": "Hollymead" + } + }, + { + "id": 1317, + "name": "Pena Little", + "gender": "male", + "age": 18, + "address": { + "state": "Wisconsin", + "city": "Oretta" + } + }, + { + "id": 1318, + "name": "Munoz Shelton", + "gender": "male", + "age": 20, + "address": { + "state": "Rhode Island", + "city": "Holtville" + } + }, + { + "id": 1319, + "name": "Wong Sargent", + "gender": "male", + "age": 79, + "address": { + "state": "Delaware", + "city": "Umapine" + } + }, + { + "id": 1320, + "name": "Hoover Moss", + "gender": "male", + "age": 77, + "address": { + "state": "Montana", + "city": "Bartley" + } + }, + { + "id": 1321, + "name": "Jones Baldwin", + "gender": "male", + "age": 72, + "address": { + "state": "South Dakota", + "city": "Winfred" + } + }, + { + "id": 1322, + "name": "Nina Rich", + "gender": "female", + "age": 56, + "address": { + "state": "Arizona", + "city": "Dixonville" + } + }, + { + "id": 1323, + "name": "Meyers Wilcox", + "gender": "male", + "age": 35, + "address": { + "state": "Alaska", + "city": "Juntura" + } + }, + { + "id": 1324, + "name": "Haney Randall", + "gender": "male", + "age": 22, + "address": { + "state": "Ohio", + "city": "Urbana" + } + }, + { + "id": 1325, + "name": "Durham Alford", + "gender": "male", + "age": 21, + "address": { + "state": "Michigan", + "city": "Worcester" + } + }, + { + "id": 1326, + "name": "Stefanie Becker", + "gender": "female", + "age": 54, + "address": { + "state": "Minnesota", + "city": "Stockdale" + } + }, + { + "id": 1327, + "name": "Gutierrez Allison", + "gender": "male", + "age": 18, + "address": { + "state": "Vermont", + "city": "Rosewood" + } + }, + { + "id": 1328, + "name": "Georgina Hunter", + "gender": "female", + "age": 33, + "address": { + "state": "Washington", + "city": "Teasdale" + } + }, + { + "id": 1329, + "name": "Strong Garrett", + "gender": "male", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Fairview" + } + }, + { + "id": 1330, + "name": "Watson Richard", + "gender": "male", + "age": 54, + "address": { + "state": "Nebraska", + "city": "Sattley" + } + }, + { + "id": 1331, + "name": "Maritza Singleton", + "gender": "female", + "age": 76, + "address": { + "state": "South Dakota", + "city": "Waterford" + } + }, + { + "id": 1332, + "name": "Felecia Simon", + "gender": "female", + "age": 20, + "address": { + "state": "Virginia", + "city": "Cedarville" + } + }, + { + "id": 1333, + "name": "Brandi Dunn", + "gender": "female", + "age": 58, + "address": { + "state": "Wyoming", + "city": "Garfield" + } + }, + { + "id": 1334, + "name": "Dianna Hutchinson", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Falconaire" + } + }, + { + "id": 1335, + "name": "Kathy Downs", + "gender": "female", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Alamo" + } + }, + { + "id": 1336, + "name": "Holder Ochoa", + "gender": "male", + "age": 25, + "address": { + "state": "Illinois", + "city": "Dorneyville" + } + }, + { + "id": 1337, + "name": "Molly Crawford", + "gender": "female", + "age": 29, + "address": { + "state": "Oklahoma", + "city": "Keyport" + } + }, + { + "id": 1338, + "name": "Mccarthy Savage", + "gender": "male", + "age": 29, + "address": { + "state": "Rhode Island", + "city": "Romeville" + } + }, + { + "id": 1339, + "name": "Snyder Rocha", + "gender": "male", + "age": 36, + "address": { + "state": "Colorado", + "city": "Cotopaxi" + } + }, + { + "id": 1340, + "name": "Lang Serrano", + "gender": "male", + "age": 73, + "address": { + "state": "New Mexico", + "city": "Homeworth" + } + }, + { + "id": 1341, + "name": "Lilly Mann", + "gender": "female", + "age": 36, + "address": { + "state": "Arizona", + "city": "Denio" + } + }, + { + "id": 1342, + "name": "Rojas Finch", + "gender": "male", + "age": 47, + "address": { + "state": "New York", + "city": "Brenton" + } + }, + { + "id": 1343, + "name": "Walls Lindsey", + "gender": "male", + "age": 34, + "address": { + "state": "South Carolina", + "city": "Wilmington" + } + }, + { + "id": 1344, + "name": "Suzette Tate", + "gender": "female", + "age": 36, + "address": { + "state": "Maryland", + "city": "Aurora" + } + }, + { + "id": 1345, + "name": "Salinas Mathis", + "gender": "male", + "age": 58, + "address": { + "state": "North Dakota", + "city": "Deercroft" + } + }, + { + "id": 1346, + "name": "Tricia Bennett", + "gender": "female", + "age": 52, + "address": { + "state": "Idaho", + "city": "Longoria" + } + }, + { + "id": 1347, + "name": "Maxine Hyde", + "gender": "female", + "age": 39, + "address": { + "state": "Nevada", + "city": "Kenmar" + } + }, + { + "id": 1348, + "name": "Marcia Shaw", + "gender": "female", + "age": 49, + "address": { + "state": "Pennsylvania", + "city": "Cade" + } + }, + { + "id": 1349, + "name": "Craft Carey", + "gender": "male", + "age": 56, + "address": { + "state": "New Jersey", + "city": "Rowe" + } + }, + { + "id": 1350, + "name": "Caitlin Hobbs", + "gender": "female", + "age": 24, + "address": { + "state": "Missouri", + "city": "Hampstead" + } + }, + { + "id": 1351, + "name": "Castillo Riley", + "gender": "male", + "age": 81, + "address": { + "state": "Wisconsin", + "city": "Babb" + } + }, + { + "id": 1352, + "name": "Hutchinson Crane", + "gender": "male", + "age": 21, + "address": { + "state": "Iowa", + "city": "Dola" + } + }, + { + "id": 1353, + "name": "April Caldwell", + "gender": "female", + "age": 50, + "address": { + "state": "Montana", + "city": "Worton" + } + }, + { + "id": 1354, + "name": "Love Silva", + "gender": "male", + "age": 52, + "address": { + "state": "Maine", + "city": "Joes" + } + }, + { + "id": 1355, + "name": "Betty Nielsen", + "gender": "female", + "age": 30, + "address": { + "state": "North Carolina", + "city": "Hackneyville" + } + }, + { + "id": 1356, + "name": "Lynette Dillon", + "gender": "female", + "age": 20, + "address": { + "state": "Kentucky", + "city": "Lopezo" + } + }, + { + "id": 1357, + "name": "Melisa Freeman", + "gender": "female", + "age": 35, + "address": { + "state": "Tennessee", + "city": "Tolu" + } + }, + { + "id": 1358, + "name": "Stark Davis", + "gender": "male", + "age": 27, + "address": { + "state": "Alabama", + "city": "Rivereno" + } + }, + { + "id": 1359, + "name": "John Dillard", + "gender": "female", + "age": 39, + "address": { + "state": "Hawaii", + "city": "Marysville" + } + }, + { + "id": 1360, + "name": "Clements Solis", + "gender": "male", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Derwood" + } + }, + { + "id": 1361, + "name": "Fletcher Sims", + "gender": "male", + "age": 58, + "address": { + "state": "Kansas", + "city": "Ticonderoga" + } + }, + { + "id": 1362, + "name": "Hopper Shepherd", + "gender": "male", + "age": 20, + "address": { + "state": "West Virginia", + "city": "Boonville" + } + }, + { + "id": 1363, + "name": "Holden Santana", + "gender": "male", + "age": 34, + "address": { + "state": "Utah", + "city": "Marshall" + } + }, + { + "id": 1364, + "name": "Lambert Gay", + "gender": "male", + "age": 27, + "address": { + "state": "New Hampshire", + "city": "Fairhaven" + } + }, + { + "id": 1365, + "name": "Lacey Dean", + "gender": "female", + "age": 59, + "address": { + "state": "Delaware", + "city": "Limestone" + } + }, + { + "id": 1366, + "name": "Adrian Roman", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Norvelt" + } + }, + { + "id": 1367, + "name": "Faye Boyle", + "gender": "female", + "age": 31, + "address": { + "state": "Mississippi", + "city": "Utting" + } + }, + { + "id": 1368, + "name": "Howell Gonzales", + "gender": "male", + "age": 18, + "address": { + "state": "Oregon", + "city": "Whipholt" + } + }, + { + "id": 1369, + "name": "Phelps Hardin", + "gender": "male", + "age": 73, + "address": { + "state": "Georgia", + "city": "Shaft" + } + }, + { + "id": 1370, + "name": "Weaver Wilkinson", + "gender": "male", + "age": 56, + "address": { + "state": "California", + "city": "Rehrersburg" + } + }, + { + "id": 1371, + "name": "Berry Mendoza", + "gender": "male", + "age": 46, + "address": { + "state": "Texas", + "city": "Noblestown" + } + }, + { + "id": 1372, + "name": "Katina Mason", + "gender": "female", + "age": 62, + "address": { + "state": "Utah", + "city": "Freelandville" + } + }, + { + "id": 1373, + "name": "Gabrielle Martinez", + "gender": "female", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Chamberino" + } + }, + { + "id": 1374, + "name": "Meredith Carey", + "gender": "female", + "age": 63, + "address": { + "state": "Maryland", + "city": "Delco" + } + }, + { + "id": 1375, + "name": "Tucker Wilder", + "gender": "male", + "age": 57, + "address": { + "state": "Florida", + "city": "Kenwood" + } + }, + { + "id": 1376, + "name": "Cruz Wallace", + "gender": "male", + "age": 63, + "address": { + "state": "New York", + "city": "Vandiver" + } + }, + { + "id": 1377, + "name": "Banks Hayes", + "gender": "male", + "age": 81, + "address": { + "state": "Alabama", + "city": "Tilden" + } + }, + { + "id": 1378, + "name": "Amparo Dotson", + "gender": "female", + "age": 32, + "address": { + "state": "Montana", + "city": "Wescosville" + } + }, + { + "id": 1379, + "name": "Guthrie Sears", + "gender": "male", + "age": 74, + "address": { + "state": "Ohio", + "city": "Rivereno" + } + }, + { + "id": 1380, + "name": "Boyle Ramos", + "gender": "male", + "age": 26, + "address": { + "state": "Arkansas", + "city": "Jugtown" + } + }, + { + "id": 1381, + "name": "Sharon Conley", + "gender": "female", + "age": 18, + "address": { + "state": "Michigan", + "city": "Delshire" + } + }, + { + "id": 1382, + "name": "Branch Ball", + "gender": "male", + "age": 49, + "address": { + "state": "Kentucky", + "city": "Greenbush" + } + }, + { + "id": 1383, + "name": "Mildred Rodriguez", + "gender": "female", + "age": 77, + "address": { + "state": "Mississippi", + "city": "Calvary" + } + }, + { + "id": 1384, + "name": "Isabel Preston", + "gender": "female", + "age": 20, + "address": { + "state": "North Dakota", + "city": "Bascom" + } + }, + { + "id": 1385, + "name": "Erica Castillo", + "gender": "female", + "age": 30, + "address": { + "state": "Washington", + "city": "Bethany" + } + }, + { + "id": 1386, + "name": "Lindsey Burgess", + "gender": "female", + "age": 22, + "address": { + "state": "New Mexico", + "city": "Broadlands" + } + }, + { + "id": 1387, + "name": "Forbes Ferrell", + "gender": "male", + "age": 40, + "address": { + "state": "New Jersey", + "city": "Greenfields" + } + }, + { + "id": 1388, + "name": "Campos Walsh", + "gender": "male", + "age": 67, + "address": { + "state": "South Dakota", + "city": "Lydia" + } + }, + { + "id": 1389, + "name": "Debra Justice", + "gender": "female", + "age": 23, + "address": { + "state": "Nebraska", + "city": "Canoochee" + } + }, + { + "id": 1390, + "name": "Blevins Gibbs", + "gender": "male", + "age": 19, + "address": { + "state": "Texas", + "city": "Kapowsin" + } + }, + { + "id": 1391, + "name": "Odessa Bowers", + "gender": "female", + "age": 18, + "address": { + "state": "Connecticut", + "city": "Loretto" + } + }, + { + "id": 1392, + "name": "Ola Vaughan", + "gender": "female", + "age": 63, + "address": { + "state": "Nevada", + "city": "Soudan" + } + }, + { + "id": 1393, + "name": "Josephine Hines", + "gender": "female", + "age": 20, + "address": { + "state": "Delaware", + "city": "Mulberry" + } + }, + { + "id": 1394, + "name": "Weiss Leonard", + "gender": "male", + "age": 58, + "address": { + "state": "North Carolina", + "city": "Konterra" + } + }, + { + "id": 1395, + "name": "Spencer Vazquez", + "gender": "male", + "age": 50, + "address": { + "state": "Idaho", + "city": "Como" + } + }, + { + "id": 1396, + "name": "Sharpe Leon", + "gender": "male", + "age": 65, + "address": { + "state": "Arizona", + "city": "Fannett" + } + }, + { + "id": 1397, + "name": "Cole Baxter", + "gender": "male", + "age": 53, + "address": { + "state": "Minnesota", + "city": "Florence" + } + }, + { + "id": 1398, + "name": "Nichols Mclean", + "gender": "male", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Lowell" + } + }, + { + "id": 1399, + "name": "Holland Bowman", + "gender": "male", + "age": 73, + "address": { + "state": "Rhode Island", + "city": "Belmont" + } + }, + { + "id": 1400, + "name": "Burch Duke", + "gender": "male", + "age": 17, + "address": { + "state": "Indiana", + "city": "Trona" + } + }, + { + "id": 1401, + "name": "Crystal Dean", + "gender": "female", + "age": 67, + "address": { + "state": "Oregon", + "city": "Shindler" + } + }, + { + "id": 1402, + "name": "Juliana Griffith", + "gender": "female", + "age": 69, + "address": { + "state": "California", + "city": "Gadsden" + } + }, + { + "id": 1403, + "name": "Webb Marquez", + "gender": "male", + "age": 62, + "address": { + "state": "Colorado", + "city": "Waumandee" + } + }, + { + "id": 1404, + "name": "Myrtle Gross", + "gender": "female", + "age": 19, + "address": { + "state": "Iowa", + "city": "Knowlton" + } + }, + { + "id": 1405, + "name": "Jana House", + "gender": "female", + "age": 69, + "address": { + "state": "Illinois", + "city": "Navarre" + } + }, + { + "id": 1406, + "name": "Graciela Kerr", + "gender": "female", + "age": 34, + "address": { + "state": "Massachusetts", + "city": "Cliffside" + } + }, + { + "id": 1407, + "name": "Carrie Fox", + "gender": "female", + "age": 57, + "address": { + "state": "Maine", + "city": "Boykin" + } + }, + { + "id": 1408, + "name": "Gallegos Snyder", + "gender": "male", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Manchester" + } + }, + { + "id": 1409, + "name": "Sargent Ware", + "gender": "male", + "age": 20, + "address": { + "state": "Wisconsin", + "city": "Verdi" + } + }, + { + "id": 1410, + "name": "Gena Mason", + "gender": "female", + "age": 24, + "address": { + "state": "Oklahoma", + "city": "Leming" + } + }, + { + "id": 1411, + "name": "Marian Cooke", + "gender": "female", + "age": 37, + "address": { + "state": "Alaska", + "city": "Clinton" + } + }, + { + "id": 1412, + "name": "Hayden Norris", + "gender": "male", + "age": 65, + "address": { + "state": "Virginia", + "city": "Fedora" + } + }, + { + "id": 1413, + "name": "Roberts Gillespie", + "gender": "male", + "age": 57, + "address": { + "state": "Georgia", + "city": "Limestone" + } + }, + { + "id": 1414, + "name": "Walters Nolan", + "gender": "male", + "age": 46, + "address": { + "state": "South Carolina", + "city": "Bowmansville" + } + }, + { + "id": 1415, + "name": "Dunn Raymond", + "gender": "male", + "age": 48, + "address": { + "state": "West Virginia", + "city": "Ventress" + } + }, + { + "id": 1416, + "name": "Faith Fuentes", + "gender": "female", + "age": 72, + "address": { + "state": "New Hampshire", + "city": "Waterview" + } + }, + { + "id": 1417, + "name": "Walker Leach", + "gender": "male", + "age": 37, + "address": { + "state": "Louisiana", + "city": "Madrid" + } + }, + { + "id": 1418, + "name": "Allen Nicholson", + "gender": "male", + "age": 19, + "address": { + "state": "Missouri", + "city": "Zortman" + } + }, + { + "id": 1419, + "name": "Belinda Nguyen", + "gender": "female", + "age": 66, + "address": { + "state": "Pennsylvania", + "city": "Fingerville" + } + }, + { + "id": 1420, + "name": "Koch Lott", + "gender": "male", + "age": 73, + "address": { + "state": "Kansas", + "city": "Cetronia" + } + }, + { + "id": 1421, + "name": "Rosetta Chapman", + "gender": "female", + "age": 25, + "address": { + "state": "Florida", + "city": "Saddlebrooke" + } + }, + { + "id": 1422, + "name": "Maude Ayala", + "gender": "female", + "age": 64, + "address": { + "state": "Idaho", + "city": "Goochland" + } + }, + { + "id": 1423, + "name": "Josefa Holcomb", + "gender": "female", + "age": 46, + "address": { + "state": "Vermont", + "city": "Bloomington" + } + }, + { + "id": 1424, + "name": "Angie Carson", + "gender": "female", + "age": 70, + "address": { + "state": "Mississippi", + "city": "Lafferty" + } + }, + { + "id": 1425, + "name": "Ruthie Conner", + "gender": "female", + "age": 24, + "address": { + "state": "Iowa", + "city": "Maury" + } + }, + { + "id": 1426, + "name": "Annie Castro", + "gender": "female", + "age": 18, + "address": { + "state": "New Jersey", + "city": "Conway" + } + }, + { + "id": 1427, + "name": "Gibbs Sandoval", + "gender": "male", + "age": 67, + "address": { + "state": "Utah", + "city": "Ivanhoe" + } + }, + { + "id": 1428, + "name": "Carolyn Shelton", + "gender": "female", + "age": 56, + "address": { + "state": "Hawaii", + "city": "Makena" + } + }, + { + "id": 1429, + "name": "Helena Reed", + "gender": "female", + "age": 20, + "address": { + "state": "Wyoming", + "city": "Elrama" + } + }, + { + "id": 1430, + "name": "Melinda Guthrie", + "gender": "female", + "age": 76, + "address": { + "state": "Kansas", + "city": "Guthrie" + } + }, + { + "id": 1431, + "name": "Short Dickson", + "gender": "male", + "age": 58, + "address": { + "state": "Nevada", + "city": "Fostoria" + } + }, + { + "id": 1432, + "name": "Montoya Parsons", + "gender": "male", + "age": 51, + "address": { + "state": "Connecticut", + "city": "Ahwahnee" + } + }, + { + "id": 1433, + "name": "Stefanie Mcdonald", + "gender": "female", + "age": 66, + "address": { + "state": "Illinois", + "city": "Westphalia" + } + }, + { + "id": 1434, + "name": "Heidi Craft", + "gender": "female", + "age": 28, + "address": { + "state": "Oklahoma", + "city": "Chalfant" + } + }, + { + "id": 1435, + "name": "Munoz Pitts", + "gender": "male", + "age": 68, + "address": { + "state": "South Carolina", + "city": "Lithium" + } + }, + { + "id": 1436, + "name": "Bauer Caldwell", + "gender": "male", + "age": 61, + "address": { + "state": "Delaware", + "city": "Yettem" + } + }, + { + "id": 1437, + "name": "Griffin Douglas", + "gender": "male", + "age": 23, + "address": { + "state": "Michigan", + "city": "Chloride" + } + }, + { + "id": 1438, + "name": "Marsha Estrada", + "gender": "female", + "age": 71, + "address": { + "state": "Louisiana", + "city": "Norvelt" + } + }, + { + "id": 1439, + "name": "Rene Hammond", + "gender": "female", + "age": 42, + "address": { + "state": "California", + "city": "Celeryville" + } + }, + { + "id": 1440, + "name": "Buck Berg", + "gender": "male", + "age": 31, + "address": { + "state": "Washington", + "city": "Dixonville" + } + }, + { + "id": 1441, + "name": "Tucker Mcfarland", + "gender": "male", + "age": 70, + "address": { + "state": "Arizona", + "city": "Belfair" + } + }, + { + "id": 1442, + "name": "Morton Mcintyre", + "gender": "male", + "age": 53, + "address": { + "state": "Alaska", + "city": "Dupuyer" + } + }, + { + "id": 1443, + "name": "Robbins Woods", + "gender": "male", + "age": 39, + "address": { + "state": "Ohio", + "city": "Hailesboro" + } + }, + { + "id": 1444, + "name": "Ivy Blevins", + "gender": "female", + "age": 73, + "address": { + "state": "Montana", + "city": "Chelsea" + } + }, + { + "id": 1445, + "name": "Stone Colon", + "gender": "male", + "age": 68, + "address": { + "state": "Alabama", + "city": "Campo" + } + }, + { + "id": 1446, + "name": "Tamika Hensley", + "gender": "female", + "age": 22, + "address": { + "state": "Missouri", + "city": "Idamay" + } + }, + { + "id": 1447, + "name": "Ortega Roy", + "gender": "male", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Winesburg" + } + }, + { + "id": 1448, + "name": "Norton Ferrell", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Sunbury" + } + }, + { + "id": 1449, + "name": "Sellers Hewitt", + "gender": "male", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Bowmansville" + } + }, + { + "id": 1450, + "name": "Hayes Kennedy", + "gender": "male", + "age": 21, + "address": { + "state": "Rhode Island", + "city": "Weedville" + } + }, + { + "id": 1451, + "name": "Lopez Ortega", + "gender": "male", + "age": 33, + "address": { + "state": "South Dakota", + "city": "Collins" + } + }, + { + "id": 1452, + "name": "Sexton Everett", + "gender": "male", + "age": 40, + "address": { + "state": "Maine", + "city": "Elizaville" + } + }, + { + "id": 1453, + "name": "Marie Watts", + "gender": "female", + "age": 81, + "address": { + "state": "Georgia", + "city": "Kiskimere" + } + }, + { + "id": 1454, + "name": "Melva Whitley", + "gender": "female", + "age": 75, + "address": { + "state": "Minnesota", + "city": "Aberdeen" + } + }, + { + "id": 1455, + "name": "Rosella Peck", + "gender": "female", + "age": 43, + "address": { + "state": "Indiana", + "city": "Dowling" + } + }, + { + "id": 1456, + "name": "Brigitte Mcbride", + "gender": "female", + "age": 69, + "address": { + "state": "Arkansas", + "city": "Avoca" + } + }, + { + "id": 1457, + "name": "Collier Patton", + "gender": "male", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Dixie" + } + }, + { + "id": 1458, + "name": "Janna Decker", + "gender": "female", + "age": 23, + "address": { + "state": "Wisconsin", + "city": "Kenvil" + } + }, + { + "id": 1459, + "name": "Billie Kramer", + "gender": "female", + "age": 26, + "address": { + "state": "North Dakota", + "city": "Vallonia" + } + }, + { + "id": 1460, + "name": "Dorothea Spence", + "gender": "female", + "age": 45, + "address": { + "state": "West Virginia", + "city": "Deercroft" + } + }, + { + "id": 1461, + "name": "Robertson Mercado", + "gender": "male", + "age": 50, + "address": { + "state": "Maryland", + "city": "Toftrees" + } + }, + { + "id": 1462, + "name": "Bethany Merritt", + "gender": "female", + "age": 37, + "address": { + "state": "Colorado", + "city": "Elliott" + } + }, + { + "id": 1463, + "name": "Cathy Sampson", + "gender": "female", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Nescatunga" + } + }, + { + "id": 1464, + "name": "Trisha Adkins", + "gender": "female", + "age": 41, + "address": { + "state": "Texas", + "city": "Grenelefe" + } + }, + { + "id": 1465, + "name": "Sophia Navarro", + "gender": "female", + "age": 42, + "address": { + "state": "Oregon", + "city": "Ada" + } + }, + { + "id": 1466, + "name": "Franks Austin", + "gender": "male", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Waterford" + } + }, + { + "id": 1467, + "name": "Johanna Thompson", + "gender": "female", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Richford" + } + }, + { + "id": 1468, + "name": "Hendricks Nicholson", + "gender": "male", + "age": 48, + "address": { + "state": "New York", + "city": "Templeton" + } + }, + { + "id": 1469, + "name": "Chrystal Cruz", + "gender": "female", + "age": 62, + "address": { + "state": "New Hampshire", + "city": "Eureka" + } + }, + { + "id": 1470, + "name": "Clarissa Snider", + "gender": "female", + "age": 54, + "address": { + "state": "Oregon", + "city": "Seymour" + } + }, + { + "id": 1471, + "name": "Warren Waller", + "gender": "male", + "age": 71, + "address": { + "state": "Kansas", + "city": "Bartley" + } + }, + { + "id": 1472, + "name": "Milagros Parrish", + "gender": "female", + "age": 77, + "address": { + "state": "Utah", + "city": "Crawfordsville" + } + }, + { + "id": 1473, + "name": "Madden Holmes", + "gender": "male", + "age": 39, + "address": { + "state": "West Virginia", + "city": "Brookfield" + } + }, + { + "id": 1474, + "name": "Elsie Armstrong", + "gender": "female", + "age": 58, + "address": { + "state": "Maryland", + "city": "Turah" + } + }, + { + "id": 1475, + "name": "Rowland Hyde", + "gender": "male", + "age": 40, + "address": { + "state": "Missouri", + "city": "Coral" + } + }, + { + "id": 1476, + "name": "Solis Cummings", + "gender": "male", + "age": 64, + "address": { + "state": "Arkansas", + "city": "Lemoyne" + } + }, + { + "id": 1477, + "name": "Mindy Steele", + "gender": "female", + "age": 79, + "address": { + "state": "Wisconsin", + "city": "Deputy" + } + }, + { + "id": 1478, + "name": "Emerson Valentine", + "gender": "male", + "age": 73, + "address": { + "state": "Colorado", + "city": "Rodanthe" + } + }, + { + "id": 1479, + "name": "Wallace Roman", + "gender": "male", + "age": 75, + "address": { + "state": "Texas", + "city": "Crisman" + } + }, + { + "id": 1480, + "name": "Carey Hopkins", + "gender": "male", + "age": 17, + "address": { + "state": "Nebraska", + "city": "Genoa" + } + }, + { + "id": 1481, + "name": "Boyer Russell", + "gender": "male", + "age": 33, + "address": { + "state": "Massachusetts", + "city": "Bartonsville" + } + }, + { + "id": 1482, + "name": "Cooke Mckay", + "gender": "male", + "age": 54, + "address": { + "state": "North Dakota", + "city": "Kenvil" + } + }, + { + "id": 1483, + "name": "Janis Stanton", + "gender": "female", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Walker" + } + }, + { + "id": 1484, + "name": "Bobbie Mayer", + "gender": "female", + "age": 49, + "address": { + "state": "Iowa", + "city": "Joppa" + } + }, + { + "id": 1485, + "name": "April Lawrence", + "gender": "female", + "age": 71, + "address": { + "state": "Illinois", + "city": "Dubois" + } + }, + { + "id": 1486, + "name": "Dionne Day", + "gender": "female", + "age": 53, + "address": { + "state": "Georgia", + "city": "Riegelwood" + } + }, + { + "id": 1487, + "name": "Roman Hayden", + "gender": "male", + "age": 81, + "address": { + "state": "Hawaii", + "city": "Datil" + } + }, + { + "id": 1488, + "name": "Yvonne Casey", + "gender": "female", + "age": 40, + "address": { + "state": "New Jersey", + "city": "Dowling" + } + }, + { + "id": 1489, + "name": "Graciela Kerr", + "gender": "female", + "age": 27, + "address": { + "state": "Washington", + "city": "Rutherford" + } + }, + { + "id": 1490, + "name": "Margie Everett", + "gender": "female", + "age": 39, + "address": { + "state": "Montana", + "city": "Tetherow" + } + }, + { + "id": 1491, + "name": "Ramirez Williams", + "gender": "male", + "age": 51, + "address": { + "state": "New Hampshire", + "city": "Ironton" + } + }, + { + "id": 1492, + "name": "Jordan Blanchard", + "gender": "male", + "age": 81, + "address": { + "state": "Rhode Island", + "city": "Gasquet" + } + }, + { + "id": 1493, + "name": "Sanchez Rosa", + "gender": "male", + "age": 56, + "address": { + "state": "Michigan", + "city": "Fidelis" + } + }, + { + "id": 1494, + "name": "Bridges Jordan", + "gender": "male", + "age": 32, + "address": { + "state": "Alaska", + "city": "Elbert" + } + }, + { + "id": 1495, + "name": "Kari Martinez", + "gender": "female", + "age": 21, + "address": { + "state": "Ohio", + "city": "Grahamtown" + } + }, + { + "id": 1496, + "name": "Fran Wynn", + "gender": "female", + "age": 52, + "address": { + "state": "Louisiana", + "city": "Machias" + } + }, + { + "id": 1497, + "name": "Evans Nicholson", + "gender": "male", + "age": 26, + "address": { + "state": "Mississippi", + "city": "Windsor" + } + }, + { + "id": 1498, + "name": "Mabel Gardner", + "gender": "female", + "age": 58, + "address": { + "state": "Wyoming", + "city": "Golconda" + } + }, + { + "id": 1499, + "name": "Sheppard Delacruz", + "gender": "male", + "age": 41, + "address": { + "state": "Alabama", + "city": "Topanga" + } + }, + { + "id": 1500, + "name": "Chavez Warren", + "gender": "male", + "age": 59, + "address": { + "state": "Idaho", + "city": "Nadine" + } + }, + { + "id": 1501, + "name": "Cummings Witt", + "gender": "male", + "age": 18, + "address": { + "state": "New York", + "city": "Durham" + } + }, + { + "id": 1502, + "name": "Odom Oneil", + "gender": "male", + "age": 70, + "address": { + "state": "Florida", + "city": "Driftwood" + } + }, + { + "id": 1503, + "name": "Robertson Moon", + "gender": "male", + "age": 40, + "address": { + "state": "Connecticut", + "city": "Bangor" + } + }, + { + "id": 1504, + "name": "Townsend Foster", + "gender": "male", + "age": 65, + "address": { + "state": "Delaware", + "city": "Urie" + } + }, + { + "id": 1505, + "name": "Bender Adams", + "gender": "male", + "age": 61, + "address": { + "state": "Vermont", + "city": "Valmy" + } + }, + { + "id": 1506, + "name": "Sonia Ingram", + "gender": "female", + "age": 77, + "address": { + "state": "Nevada", + "city": "Forestburg" + } + }, + { + "id": 1507, + "name": "Mccall Woodward", + "gender": "male", + "age": 38, + "address": { + "state": "California", + "city": "Marion" + } + }, + { + "id": 1508, + "name": "Bridgett Lynn", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Churchill" + } + }, + { + "id": 1509, + "name": "Arnold Gamble", + "gender": "male", + "age": 61, + "address": { + "state": "Indiana", + "city": "Hampstead" + } + }, + { + "id": 1510, + "name": "Maddox Frost", + "gender": "male", + "age": 31, + "address": { + "state": "North Carolina", + "city": "Hilltop" + } + }, + { + "id": 1511, + "name": "Loraine Diaz", + "gender": "female", + "age": 44, + "address": { + "state": "Minnesota", + "city": "Ronco" + } + }, + { + "id": 1512, + "name": "Bernice Alexander", + "gender": "female", + "age": 79, + "address": { + "state": "Kentucky", + "city": "Valle" + } + }, + { + "id": 1513, + "name": "Atkins Frank", + "gender": "male", + "age": 57, + "address": { + "state": "Maine", + "city": "Twilight" + } + }, + { + "id": 1514, + "name": "Lorie Olson", + "gender": "female", + "age": 38, + "address": { + "state": "Virginia", + "city": "Broadlands" + } + }, + { + "id": 1515, + "name": "Ewing Myers", + "gender": "male", + "age": 24, + "address": { + "state": "Tennessee", + "city": "Gerber" + } + }, + { + "id": 1516, + "name": "Chaney Perkins", + "gender": "male", + "age": 78, + "address": { + "state": "Pennsylvania", + "city": "Cartwright" + } + }, + { + "id": 1517, + "name": "Nita Franco", + "gender": "female", + "age": 54, + "address": { + "state": "New Mexico", + "city": "Bascom" + } + }, + { + "id": 1518, + "name": "Doyle Golden", + "gender": "male", + "age": 52, + "address": { + "state": "South Dakota", + "city": "Bellamy" + } + }, + { + "id": 1519, + "name": "Vonda Boone", + "gender": "female", + "age": 49, + "address": { + "state": "Washington", + "city": "Wyano" + } + }, + { + "id": 1520, + "name": "Gena Solomon", + "gender": "female", + "age": 61, + "address": { + "state": "Oklahoma", + "city": "Wakulla" + } + }, + { + "id": 1521, + "name": "Colon Bruce", + "gender": "male", + "age": 78, + "address": { + "state": "Michigan", + "city": "Oneida" + } + }, + { + "id": 1522, + "name": "Boyd Sampson", + "gender": "male", + "age": 25, + "address": { + "state": "Wisconsin", + "city": "Brewster" + } + }, + { + "id": 1523, + "name": "Mckee Potter", + "gender": "male", + "age": 70, + "address": { + "state": "Minnesota", + "city": "Barronett" + } + }, + { + "id": 1524, + "name": "Hoover Weeks", + "gender": "male", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Belmont" + } + }, + { + "id": 1525, + "name": "Brennan Christensen", + "gender": "male", + "age": 45, + "address": { + "state": "Tennessee", + "city": "Fairmount" + } + }, + { + "id": 1526, + "name": "Corina Hurley", + "gender": "female", + "age": 68, + "address": { + "state": "North Dakota", + "city": "Belva" + } + }, + { + "id": 1527, + "name": "Lucia Yang", + "gender": "female", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Ernstville" + } + }, + { + "id": 1528, + "name": "Angie Young", + "gender": "female", + "age": 44, + "address": { + "state": "Kansas", + "city": "Columbus" + } + }, + { + "id": 1529, + "name": "Loretta Frye", + "gender": "female", + "age": 44, + "address": { + "state": "Arizona", + "city": "Camptown" + } + }, + { + "id": 1530, + "name": "Mildred Browning", + "gender": "female", + "age": 44, + "address": { + "state": "Alaska", + "city": "Murillo" + } + }, + { + "id": 1531, + "name": "Riddle Lynch", + "gender": "male", + "age": 43, + "address": { + "state": "Illinois", + "city": "Flintville" + } + }, + { + "id": 1532, + "name": "Cohen Mercer", + "gender": "male", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Chemung" + } + }, + { + "id": 1533, + "name": "Bernice Wolfe", + "gender": "female", + "age": 75, + "address": { + "state": "Iowa", + "city": "Bison" + } + }, + { + "id": 1534, + "name": "Cobb Sheppard", + "gender": "male", + "age": 43, + "address": { + "state": "Texas", + "city": "Cartwright" + } + }, + { + "id": 1535, + "name": "Rosalie Hines", + "gender": "female", + "age": 79, + "address": { + "state": "New Hampshire", + "city": "Rivers" + } + }, + { + "id": 1536, + "name": "Norma Copeland", + "gender": "female", + "age": 28, + "address": { + "state": "New York", + "city": "Babb" + } + }, + { + "id": 1537, + "name": "Roslyn Quinn", + "gender": "female", + "age": 47, + "address": { + "state": "Virginia", + "city": "Devon" + } + }, + { + "id": 1538, + "name": "Ramirez Jacobs", + "gender": "male", + "age": 42, + "address": { + "state": "Ohio", + "city": "Roderfield" + } + }, + { + "id": 1539, + "name": "Yvonne Lara", + "gender": "female", + "age": 76, + "address": { + "state": "Florida", + "city": "Springhill" + } + }, + { + "id": 1540, + "name": "Carey Carr", + "gender": "male", + "age": 80, + "address": { + "state": "Montana", + "city": "Calpine" + } + }, + { + "id": 1541, + "name": "Nona Leblanc", + "gender": "female", + "age": 23, + "address": { + "state": "Pennsylvania", + "city": "Leland" + } + }, + { + "id": 1542, + "name": "Neva Brennan", + "gender": "female", + "age": 31, + "address": { + "state": "Delaware", + "city": "Calverton" + } + }, + { + "id": 1543, + "name": "Brandy Schwartz", + "gender": "female", + "age": 48, + "address": { + "state": "North Carolina", + "city": "Sheatown" + } + }, + { + "id": 1544, + "name": "Amalia Stein", + "gender": "female", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Graniteville" + } + }, + { + "id": 1545, + "name": "Daniel Schroeder", + "gender": "male", + "age": 50, + "address": { + "state": "California", + "city": "Topanga" + } + }, + { + "id": 1546, + "name": "Torres Dickerson", + "gender": "male", + "age": 79, + "address": { + "state": "West Virginia", + "city": "Newcastle" + } + }, + { + "id": 1547, + "name": "Norris Park", + "gender": "male", + "age": 73, + "address": { + "state": "Vermont", + "city": "Villarreal" + } + }, + { + "id": 1548, + "name": "Julia Battle", + "gender": "female", + "age": 61, + "address": { + "state": "Mississippi", + "city": "Lorraine" + } + }, + { + "id": 1549, + "name": "Pat Diaz", + "gender": "female", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Harrison" + } + }, + { + "id": 1550, + "name": "Rutledge Strickland", + "gender": "male", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Concho" + } + }, + { + "id": 1551, + "name": "Tia Mckinney", + "gender": "female", + "age": 42, + "address": { + "state": "Nebraska", + "city": "Wilmington" + } + }, + { + "id": 1552, + "name": "Sherman Watson", + "gender": "male", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Rehrersburg" + } + }, + { + "id": 1553, + "name": "Mcconnell Rutledge", + "gender": "male", + "age": 75, + "address": { + "state": "Kentucky", + "city": "Deseret" + } + }, + { + "id": 1554, + "name": "Jackie Pruitt", + "gender": "female", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Sehili" + } + }, + { + "id": 1555, + "name": "Benjamin Hensley", + "gender": "male", + "age": 19, + "address": { + "state": "Alabama", + "city": "Finderne" + } + }, + { + "id": 1556, + "name": "Sharon Klein", + "gender": "female", + "age": 52, + "address": { + "state": "Maine", + "city": "Drytown" + } + }, + { + "id": 1557, + "name": "Hunt Moss", + "gender": "male", + "age": 67, + "address": { + "state": "Utah", + "city": "Rockbridge" + } + }, + { + "id": 1558, + "name": "Fuentes Morton", + "gender": "male", + "age": 75, + "address": { + "state": "Georgia", + "city": "Hollins" + } + }, + { + "id": 1559, + "name": "Vaughan Wilkinson", + "gender": "male", + "age": 52, + "address": { + "state": "Nevada", + "city": "Manila" + } + }, + { + "id": 1560, + "name": "Emily Leon", + "gender": "female", + "age": 42, + "address": { + "state": "Colorado", + "city": "Dellview" + } + }, + { + "id": 1561, + "name": "Gill Mccall", + "gender": "male", + "age": 56, + "address": { + "state": "Maryland", + "city": "Delco" + } + }, + { + "id": 1562, + "name": "Cathryn Mcintosh", + "gender": "female", + "age": 27, + "address": { + "state": "Connecticut", + "city": "Austinburg" + } + }, + { + "id": 1563, + "name": "Carson Pacheco", + "gender": "male", + "age": 69, + "address": { + "state": "Indiana", + "city": "Derwood" + } + }, + { + "id": 1564, + "name": "Harrison Roberts", + "gender": "male", + "age": 28, + "address": { + "state": "Rhode Island", + "city": "Rodman" + } + }, + { + "id": 1565, + "name": "Tamera Duke", + "gender": "female", + "age": 36, + "address": { + "state": "Arkansas", + "city": "Beason" + } + }, + { + "id": 1566, + "name": "Carlene Waters", + "gender": "female", + "age": 80, + "address": { + "state": "Oregon", + "city": "Wanship" + } + }, + { + "id": 1567, + "name": "Miranda Barnes", + "gender": "female", + "age": 63, + "address": { + "state": "Missouri", + "city": "Heil" + } + }, + { + "id": 1568, + "name": "Whitfield Matthews", + "gender": "male", + "age": 36, + "address": { + "state": "Arizona", + "city": "Sunbury" + } + }, + { + "id": 1569, + "name": "Hays Hendrix", + "gender": "male", + "age": 72, + "address": { + "state": "Kansas", + "city": "Chilton" + } + }, + { + "id": 1570, + "name": "Joy Fitzgerald", + "gender": "female", + "age": 48, + "address": { + "state": "Iowa", + "city": "Bloomington" + } + }, + { + "id": 1571, + "name": "Goff Vincent", + "gender": "male", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Bluffview" + } + }, + { + "id": 1572, + "name": "Gordon Bryan", + "gender": "male", + "age": 59, + "address": { + "state": "Louisiana", + "city": "Alden" + } + }, + { + "id": 1573, + "name": "Hood Mccoy", + "gender": "male", + "age": 59, + "address": { + "state": "Rhode Island", + "city": "Seymour" + } + }, + { + "id": 1574, + "name": "Franklin Whitley", + "gender": "male", + "age": 73, + "address": { + "state": "Utah", + "city": "Eastvale" + } + }, + { + "id": 1575, + "name": "Alyson Kaufman", + "gender": "female", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Farmington" + } + }, + { + "id": 1576, + "name": "Summer Hughes", + "gender": "female", + "age": 82, + "address": { + "state": "Colorado", + "city": "Ezel" + } + }, + { + "id": 1577, + "name": "Allison Page", + "gender": "male", + "age": 79, + "address": { + "state": "Ohio", + "city": "Templeton" + } + }, + { + "id": 1578, + "name": "Latisha Ortiz", + "gender": "female", + "age": 29, + "address": { + "state": "Wisconsin", + "city": "Levant" + } + }, + { + "id": 1579, + "name": "Frank Ferrell", + "gender": "male", + "age": 66, + "address": { + "state": "Vermont", + "city": "Cotopaxi" + } + }, + { + "id": 1580, + "name": "Beck Knapp", + "gender": "male", + "age": 64, + "address": { + "state": "Delaware", + "city": "Brogan" + } + }, + { + "id": 1581, + "name": "Kenya Callahan", + "gender": "female", + "age": 75, + "address": { + "state": "New Hampshire", + "city": "Glenshaw" + } + }, + { + "id": 1582, + "name": "Marian Herman", + "gender": "female", + "age": 64, + "address": { + "state": "Maryland", + "city": "Wells" + } + }, + { + "id": 1583, + "name": "Olson Neal", + "gender": "male", + "age": 47, + "address": { + "state": "Oklahoma", + "city": "Iberia" + } + }, + { + "id": 1584, + "name": "Macias Hyde", + "gender": "male", + "age": 29, + "address": { + "state": "Oregon", + "city": "Omar" + } + }, + { + "id": 1585, + "name": "Jessie Arnold", + "gender": "female", + "age": 26, + "address": { + "state": "Texas", + "city": "Freeburn" + } + }, + { + "id": 1586, + "name": "Rasmussen Perry", + "gender": "male", + "age": 77, + "address": { + "state": "New Mexico", + "city": "Hegins" + } + }, + { + "id": 1587, + "name": "Alma Eaton", + "gender": "female", + "age": 36, + "address": { + "state": "Minnesota", + "city": "Healy" + } + }, + { + "id": 1588, + "name": "Leigh Townsend", + "gender": "female", + "age": 42, + "address": { + "state": "Idaho", + "city": "Crown" + } + }, + { + "id": 1589, + "name": "Francisca Cabrera", + "gender": "female", + "age": 64, + "address": { + "state": "Connecticut", + "city": "Bascom" + } + }, + { + "id": 1590, + "name": "Maritza Frost", + "gender": "female", + "age": 54, + "address": { + "state": "Florida", + "city": "Utting" + } + }, + { + "id": 1591, + "name": "Curry Terrell", + "gender": "male", + "age": 26, + "address": { + "state": "Georgia", + "city": "Deltaville" + } + }, + { + "id": 1592, + "name": "Sweet Sheppard", + "gender": "male", + "age": 37, + "address": { + "state": "Nevada", + "city": "Manitou" + } + }, + { + "id": 1593, + "name": "Alberta Bates", + "gender": "female", + "age": 73, + "address": { + "state": "Indiana", + "city": "Kula" + } + }, + { + "id": 1594, + "name": "Nona Mcknight", + "gender": "female", + "age": 71, + "address": { + "state": "California", + "city": "Camino" + } + }, + { + "id": 1595, + "name": "Adams Reid", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Masthope" + } + }, + { + "id": 1596, + "name": "Sheree Velez", + "gender": "female", + "age": 50, + "address": { + "state": "West Virginia", + "city": "Day" + } + }, + { + "id": 1597, + "name": "Gonzalez Oneal", + "gender": "male", + "age": 38, + "address": { + "state": "South Dakota", + "city": "Calverton" + } + }, + { + "id": 1598, + "name": "Hardin Nelson", + "gender": "male", + "age": 22, + "address": { + "state": "Washington", + "city": "Wilsonia" + } + }, + { + "id": 1599, + "name": "Bradshaw Collier", + "gender": "male", + "age": 31, + "address": { + "state": "Mississippi", + "city": "Brownsville" + } + }, + { + "id": 1600, + "name": "Ella Spears", + "gender": "female", + "age": 78, + "address": { + "state": "Illinois", + "city": "Holcombe" + } + }, + { + "id": 1601, + "name": "Diann Sullivan", + "gender": "female", + "age": 30, + "address": { + "state": "Alaska", + "city": "Coleville" + } + }, + { + "id": 1602, + "name": "Galloway Blankenship", + "gender": "male", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Graball" + } + }, + { + "id": 1603, + "name": "Pugh Day", + "gender": "male", + "age": 43, + "address": { + "state": "Arkansas", + "city": "Fedora" + } + }, + { + "id": 1604, + "name": "Donaldson Mcguire", + "gender": "male", + "age": 67, + "address": { + "state": "North Carolina", + "city": "Greensburg" + } + }, + { + "id": 1605, + "name": "Aurelia Conway", + "gender": "female", + "age": 42, + "address": { + "state": "Michigan", + "city": "Sterling" + } + }, + { + "id": 1606, + "name": "Lottie Hancock", + "gender": "female", + "age": 52, + "address": { + "state": "Tennessee", + "city": "Sanborn" + } + }, + { + "id": 1607, + "name": "Patsy Schroeder", + "gender": "female", + "age": 48, + "address": { + "state": "Alabama", + "city": "Courtland" + } + }, + { + "id": 1608, + "name": "Robbins Kirkland", + "gender": "male", + "age": 19, + "address": { + "state": "New York", + "city": "Lowgap" + } + }, + { + "id": 1609, + "name": "Pamela Romero", + "gender": "female", + "age": 47, + "address": { + "state": "Hawaii", + "city": "Volta" + } + }, + { + "id": 1610, + "name": "Reilly Vinson", + "gender": "male", + "age": 30, + "address": { + "state": "Montana", + "city": "Carlos" + } + }, + { + "id": 1611, + "name": "Hooper Atkinson", + "gender": "male", + "age": 52, + "address": { + "state": "Wyoming", + "city": "Sabillasville" + } + }, + { + "id": 1612, + "name": "Carissa Waters", + "gender": "female", + "age": 78, + "address": { + "state": "South Carolina", + "city": "Neibert" + } + }, + { + "id": 1613, + "name": "Fry Schultz", + "gender": "male", + "age": 40, + "address": { + "state": "Kentucky", + "city": "Taycheedah" + } + }, + { + "id": 1614, + "name": "Guthrie Humphrey", + "gender": "male", + "age": 31, + "address": { + "state": "Missouri", + "city": "Vandiver" + } + }, + { + "id": 1615, + "name": "Higgins Shelton", + "gender": "male", + "age": 47, + "address": { + "state": "Maine", + "city": "Movico" + } + }, + { + "id": 1616, + "name": "Hattie Chan", + "gender": "female", + "age": 75, + "address": { + "state": "Virginia", + "city": "Belfair" + } + }, + { + "id": 1617, + "name": "Katrina Harrington", + "gender": "female", + "age": 68, + "address": { + "state": "Tennessee", + "city": "Kieler" + } + }, + { + "id": 1618, + "name": "Ratliff Valentine", + "gender": "male", + "age": 47, + "address": { + "state": "Oregon", + "city": "Beaverdale" + } + }, + { + "id": 1619, + "name": "Myrtle Carrillo", + "gender": "female", + "age": 53, + "address": { + "state": "California", + "city": "Watchtower" + } + }, + { + "id": 1620, + "name": "Carla Riddle", + "gender": "female", + "age": 77, + "address": { + "state": "Kansas", + "city": "Clarksburg" + } + }, + { + "id": 1621, + "name": "Obrien Mcclure", + "gender": "male", + "age": 77, + "address": { + "state": "Louisiana", + "city": "Lumberton" + } + }, + { + "id": 1622, + "name": "Bradford Lambert", + "gender": "male", + "age": 17, + "address": { + "state": "Montana", + "city": "Waverly" + } + }, + { + "id": 1623, + "name": "Walls Orr", + "gender": "male", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Greensburg" + } + }, + { + "id": 1624, + "name": "Oconnor Donovan", + "gender": "male", + "age": 32, + "address": { + "state": "Illinois", + "city": "Chaparrito" + } + }, + { + "id": 1625, + "name": "Glenda West", + "gender": "female", + "age": 44, + "address": { + "state": "South Carolina", + "city": "Datil" + } + }, + { + "id": 1626, + "name": "Finley Clark", + "gender": "male", + "age": 75, + "address": { + "state": "Iowa", + "city": "Leyner" + } + }, + { + "id": 1627, + "name": "Macias Henderson", + "gender": "male", + "age": 50, + "address": { + "state": "New Hampshire", + "city": "Bellamy" + } + }, + { + "id": 1628, + "name": "Soto Garrison", + "gender": "male", + "age": 54, + "address": { + "state": "Mississippi", + "city": "Roeville" + } + }, + { + "id": 1629, + "name": "Mary Sellers", + "gender": "female", + "age": 77, + "address": { + "state": "Kentucky", + "city": "Woodburn" + } + }, + { + "id": 1630, + "name": "Jeanette Payne", + "gender": "female", + "age": 68, + "address": { + "state": "New York", + "city": "Caberfae" + } + }, + { + "id": 1631, + "name": "Aline Dawson", + "gender": "female", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Rosburg" + } + }, + { + "id": 1632, + "name": "Osborn Crawford", + "gender": "male", + "age": 39, + "address": { + "state": "Nevada", + "city": "Rockingham" + } + }, + { + "id": 1633, + "name": "Jeannette Peters", + "gender": "female", + "age": 30, + "address": { + "state": "North Carolina", + "city": "Nettie" + } + }, + { + "id": 1634, + "name": "Christie Neal", + "gender": "female", + "age": 81, + "address": { + "state": "Washington", + "city": "Ilchester" + } + }, + { + "id": 1635, + "name": "Tisha Wyatt", + "gender": "female", + "age": 17, + "address": { + "state": "Indiana", + "city": "Loma" + } + }, + { + "id": 1636, + "name": "Mia Velasquez", + "gender": "female", + "age": 30, + "address": { + "state": "Connecticut", + "city": "Grayhawk" + } + }, + { + "id": 1637, + "name": "Snider Pickett", + "gender": "male", + "age": 50, + "address": { + "state": "Arkansas", + "city": "Coral" + } + }, + { + "id": 1638, + "name": "Luna Nelson", + "gender": "male", + "age": 73, + "address": { + "state": "Virginia", + "city": "Valle" + } + }, + { + "id": 1639, + "name": "Marisol Jensen", + "gender": "female", + "age": 17, + "address": { + "state": "Nebraska", + "city": "Westerville" + } + }, + { + "id": 1640, + "name": "Bolton Porter", + "gender": "male", + "age": 36, + "address": { + "state": "New Jersey", + "city": "Eden" + } + }, + { + "id": 1641, + "name": "White Lindsey", + "gender": "male", + "age": 28, + "address": { + "state": "Alabama", + "city": "Stockwell" + } + }, + { + "id": 1642, + "name": "Erika Hoffman", + "gender": "female", + "age": 42, + "address": { + "state": "Massachusetts", + "city": "Brule" + } + }, + { + "id": 1643, + "name": "Schwartz Logan", + "gender": "male", + "age": 75, + "address": { + "state": "Florida", + "city": "Faxon" + } + }, + { + "id": 1644, + "name": "Trudy Schneider", + "gender": "female", + "age": 61, + "address": { + "state": "Colorado", + "city": "Golconda" + } + }, + { + "id": 1645, + "name": "Glenn Spears", + "gender": "male", + "age": 51, + "address": { + "state": "Wyoming", + "city": "Fannett" + } + }, + { + "id": 1646, + "name": "Valarie Gregory", + "gender": "female", + "age": 24, + "address": { + "state": "South Dakota", + "city": "Oasis" + } + }, + { + "id": 1647, + "name": "Marsh Mcdaniel", + "gender": "male", + "age": 66, + "address": { + "state": "Idaho", + "city": "Jacumba" + } + }, + { + "id": 1648, + "name": "Hilda Mcdowell", + "gender": "female", + "age": 68, + "address": { + "state": "Oklahoma", + "city": "Ellerslie" + } + }, + { + "id": 1649, + "name": "Hanson Jefferson", + "gender": "male", + "age": 49, + "address": { + "state": "Minnesota", + "city": "Temperanceville" + } + }, + { + "id": 1650, + "name": "Sarah Thompson", + "gender": "female", + "age": 48, + "address": { + "state": "Ohio", + "city": "Delco" + } + }, + { + "id": 1651, + "name": "Harriett Griffith", + "gender": "female", + "age": 64, + "address": { + "state": "Pennsylvania", + "city": "Herald" + } + }, + { + "id": 1652, + "name": "Emily Knowles", + "gender": "female", + "age": 75, + "address": { + "state": "Hawaii", + "city": "Nord" + } + }, + { + "id": 1653, + "name": "Esmeralda Case", + "gender": "female", + "age": 78, + "address": { + "state": "Rhode Island", + "city": "Allensworth" + } + }, + { + "id": 1654, + "name": "Bailey Tate", + "gender": "male", + "age": 30, + "address": { + "state": "Vermont", + "city": "Kilbourne" + } + }, + { + "id": 1655, + "name": "Russo Kent", + "gender": "male", + "age": 78, + "address": { + "state": "Alaska", + "city": "Oretta" + } + }, + { + "id": 1656, + "name": "Goodwin Sullivan", + "gender": "male", + "age": 41, + "address": { + "state": "Maine", + "city": "Bath" + } + }, + { + "id": 1657, + "name": "Cox Chen", + "gender": "male", + "age": 64, + "address": { + "state": "Maryland", + "city": "Byrnedale" + } + }, + { + "id": 1658, + "name": "Levine Alston", + "gender": "male", + "age": 39, + "address": { + "state": "Georgia", + "city": "Soham" + } + }, + { + "id": 1659, + "name": "Dale Monroe", + "gender": "male", + "age": 44, + "address": { + "state": "Missouri", + "city": "Murillo" + } + }, + { + "id": 1660, + "name": "Kellie Mcpherson", + "gender": "female", + "age": 65, + "address": { + "state": "Michigan", + "city": "Century" + } + }, + { + "id": 1661, + "name": "Mckay Hays", + "gender": "male", + "age": 80, + "address": { + "state": "Delaware", + "city": "Lawrence" + } + }, + { + "id": 1662, + "name": "Hurley Thornton", + "gender": "male", + "age": 39, + "address": { + "state": "Utah", + "city": "Foxworth" + } + }, + { + "id": 1663, + "name": "Wilcox Bowers", + "gender": "male", + "age": 74, + "address": { + "state": "Arizona", + "city": "Woodlands" + } + }, + { + "id": 1664, + "name": "Hodges Wade", + "gender": "male", + "age": 26, + "address": { + "state": "New Mexico", + "city": "Twilight" + } + }, + { + "id": 1665, + "name": "Wagner Butler", + "gender": "male", + "age": 19, + "address": { + "state": "Texas", + "city": "Dunlo" + } + }, + { + "id": 1666, + "name": "Curtis Reid", + "gender": "male", + "age": 77, + "address": { + "state": "Wisconsin", + "city": "Byrnedale" + } + }, + { + "id": 1667, + "name": "Rosa Patterson", + "gender": "female", + "age": 60, + "address": { + "state": "Alabama", + "city": "Sultana" + } + }, + { + "id": 1668, + "name": "Hughes Mclaughlin", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Westmoreland" + } + }, + { + "id": 1669, + "name": "Kirsten Pacheco", + "gender": "female", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Belleview" + } + }, + { + "id": 1670, + "name": "Vicky Ortiz", + "gender": "female", + "age": 54, + "address": { + "state": "Minnesota", + "city": "Mooresburg" + } + }, + { + "id": 1671, + "name": "Luna Collins", + "gender": "male", + "age": 34, + "address": { + "state": "Florida", + "city": "Sheatown" + } + }, + { + "id": 1672, + "name": "Donovan Gates", + "gender": "male", + "age": 40, + "address": { + "state": "Tennessee", + "city": "Gordon" + } + }, + { + "id": 1673, + "name": "Stella Park", + "gender": "female", + "age": 64, + "address": { + "state": "Louisiana", + "city": "Dale" + } + }, + { + "id": 1674, + "name": "Helena Wood", + "gender": "female", + "age": 51, + "address": { + "state": "Arkansas", + "city": "Lindcove" + } + }, + { + "id": 1675, + "name": "Valdez Douglas", + "gender": "male", + "age": 44, + "address": { + "state": "West Virginia", + "city": "Loveland" + } + }, + { + "id": 1676, + "name": "Greta Mullins", + "gender": "female", + "age": 67, + "address": { + "state": "Texas", + "city": "Neahkahnie" + } + }, + { + "id": 1677, + "name": "Weaver Rodgers", + "gender": "male", + "age": 77, + "address": { + "state": "Arizona", + "city": "Roland" + } + }, + { + "id": 1678, + "name": "Sharron Lloyd", + "gender": "female", + "age": 48, + "address": { + "state": "Connecticut", + "city": "Faywood" + } + }, + { + "id": 1679, + "name": "Barnett Moses", + "gender": "male", + "age": 27, + "address": { + "state": "South Dakota", + "city": "Wakulla" + } + }, + { + "id": 1680, + "name": "Britt Berry", + "gender": "male", + "age": 37, + "address": { + "state": "Michigan", + "city": "Harleigh" + } + }, + { + "id": 1681, + "name": "Jacquelyn Ellison", + "gender": "female", + "age": 78, + "address": { + "state": "Maine", + "city": "Clarksburg" + } + }, + { + "id": 1682, + "name": "Inez Ferrell", + "gender": "female", + "age": 21, + "address": { + "state": "Colorado", + "city": "Hollymead" + } + }, + { + "id": 1683, + "name": "Latoya Craig", + "gender": "female", + "age": 63, + "address": { + "state": "Utah", + "city": "Manchester" + } + }, + { + "id": 1684, + "name": "Shelley Reed", + "gender": "female", + "age": 38, + "address": { + "state": "Iowa", + "city": "Beaulieu" + } + }, + { + "id": 1685, + "name": "Landry Macias", + "gender": "male", + "age": 43, + "address": { + "state": "Alaska", + "city": "Stewart" + } + }, + { + "id": 1686, + "name": "Simpson Huff", + "gender": "male", + "age": 73, + "address": { + "state": "Vermont", + "city": "Tioga" + } + }, + { + "id": 1687, + "name": "Mooney Bray", + "gender": "male", + "age": 54, + "address": { + "state": "Idaho", + "city": "Blairstown" + } + }, + { + "id": 1688, + "name": "Hollie Chambers", + "gender": "female", + "age": 79, + "address": { + "state": "Mississippi", + "city": "Gardners" + } + }, + { + "id": 1689, + "name": "Alfreda Carr", + "gender": "female", + "age": 18, + "address": { + "state": "Oregon", + "city": "Berlin" + } + }, + { + "id": 1690, + "name": "Barker Robbins", + "gender": "male", + "age": 63, + "address": { + "state": "Nebraska", + "city": "Itmann" + } + }, + { + "id": 1691, + "name": "Valarie Kirby", + "gender": "female", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Williston" + } + }, + { + "id": 1692, + "name": "Cooley Blackburn", + "gender": "male", + "age": 25, + "address": { + "state": "Virginia", + "city": "Wheaton" + } + }, + { + "id": 1693, + "name": "Miriam Ellis", + "gender": "female", + "age": 68, + "address": { + "state": "New Mexico", + "city": "Oasis" + } + }, + { + "id": 1694, + "name": "Hallie Page", + "gender": "female", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Bangor" + } + }, + { + "id": 1695, + "name": "Becker Tyler", + "gender": "male", + "age": 34, + "address": { + "state": "Washington", + "city": "Waiohinu" + } + }, + { + "id": 1696, + "name": "Debbie Swanson", + "gender": "female", + "age": 48, + "address": { + "state": "Hawaii", + "city": "Robbins" + } + }, + { + "id": 1697, + "name": "Naomi Livingston", + "gender": "female", + "age": 33, + "address": { + "state": "Wyoming", + "city": "Bourg" + } + }, + { + "id": 1698, + "name": "Whitfield Franco", + "gender": "male", + "age": 59, + "address": { + "state": "Massachusetts", + "city": "Lloyd" + } + }, + { + "id": 1699, + "name": "Summers Caldwell", + "gender": "male", + "age": 79, + "address": { + "state": "Nevada", + "city": "Brecon" + } + }, + { + "id": 1700, + "name": "Ortiz Stuart", + "gender": "male", + "age": 82, + "address": { + "state": "Kentucky", + "city": "Saranap" + } + }, + { + "id": 1701, + "name": "Jewel Eaton", + "gender": "female", + "age": 54, + "address": { + "state": "Maryland", + "city": "Emerald" + } + }, + { + "id": 1702, + "name": "Thompson Holland", + "gender": "male", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Lodoga" + } + }, + { + "id": 1703, + "name": "Carey Burt", + "gender": "male", + "age": 65, + "address": { + "state": "Georgia", + "city": "Iola" + } + }, + { + "id": 1704, + "name": "Pollard Kim", + "gender": "male", + "age": 54, + "address": { + "state": "Rhode Island", + "city": "Kieler" + } + }, + { + "id": 1705, + "name": "Monique Kane", + "gender": "female", + "age": 78, + "address": { + "state": "South Carolina", + "city": "Norwood" + } + }, + { + "id": 1706, + "name": "Mayra Velazquez", + "gender": "female", + "age": 40, + "address": { + "state": "Indiana", + "city": "Enlow" + } + }, + { + "id": 1707, + "name": "Craig Blanchard", + "gender": "male", + "age": 75, + "address": { + "state": "North Dakota", + "city": "Foscoe" + } + }, + { + "id": 1708, + "name": "Adeline Brown", + "gender": "female", + "age": 82, + "address": { + "state": "Montana", + "city": "Hailesboro" + } + }, + { + "id": 1709, + "name": "Gloria Barry", + "gender": "female", + "age": 66, + "address": { + "state": "Ohio", + "city": "Wildwood" + } + }, + { + "id": 1710, + "name": "West Rose", + "gender": "male", + "age": 25, + "address": { + "state": "Oklahoma", + "city": "Charco" + } + }, + { + "id": 1711, + "name": "Coffey Kent", + "gender": "male", + "age": 31, + "address": { + "state": "Kansas", + "city": "Leland" + } + }, + { + "id": 1712, + "name": "Deanna Black", + "gender": "female", + "age": 76, + "address": { + "state": "California", + "city": "Chumuckla" + } + }, + { + "id": 1713, + "name": "Baird Sanchez", + "gender": "male", + "age": 75, + "address": { + "state": "Missouri", + "city": "Ladera" + } + }, + { + "id": 1714, + "name": "Sheri Munoz", + "gender": "female", + "age": 45, + "address": { + "state": "New York", + "city": "Bedias" + } + }, + { + "id": 1715, + "name": "Knox Martinez", + "gender": "male", + "age": 60, + "address": { + "state": "South Carolina", + "city": "Lawrence" + } + }, + { + "id": 1716, + "name": "Ester Tran", + "gender": "female", + "age": 17, + "address": { + "state": "Indiana", + "city": "Belmont" + } + }, + { + "id": 1717, + "name": "Malinda Barker", + "gender": "female", + "age": 75, + "address": { + "state": "Georgia", + "city": "Falmouth" + } + }, + { + "id": 1718, + "name": "Meghan Kinney", + "gender": "female", + "age": 32, + "address": { + "state": "Virginia", + "city": "Coaldale" + } + }, + { + "id": 1719, + "name": "Sherry Carroll", + "gender": "female", + "age": 28, + "address": { + "state": "New Hampshire", + "city": "Hendersonville" + } + }, + { + "id": 1720, + "name": "Lane Patton", + "gender": "male", + "age": 79, + "address": { + "state": "South Dakota", + "city": "Wakarusa" + } + }, + { + "id": 1721, + "name": "Selena Bailey", + "gender": "female", + "age": 53, + "address": { + "state": "Tennessee", + "city": "Sattley" + } + }, + { + "id": 1722, + "name": "Francine Haney", + "gender": "female", + "age": 75, + "address": { + "state": "Delaware", + "city": "Hiko" + } + }, + { + "id": 1723, + "name": "Hoffman Bird", + "gender": "male", + "age": 34, + "address": { + "state": "Montana", + "city": "Brantleyville" + } + }, + { + "id": 1724, + "name": "Ochoa Page", + "gender": "male", + "age": 51, + "address": { + "state": "Idaho", + "city": "Eggertsville" + } + }, + { + "id": 1725, + "name": "Jeannette Washington", + "gender": "female", + "age": 56, + "address": { + "state": "New York", + "city": "Thomasville" + } + }, + { + "id": 1726, + "name": "Hancock Banks", + "gender": "male", + "age": 19, + "address": { + "state": "Florida", + "city": "Coral" + } + }, + { + "id": 1727, + "name": "Griffith Sims", + "gender": "male", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Marion" + } + }, + { + "id": 1728, + "name": "Daisy Brady", + "gender": "female", + "age": 49, + "address": { + "state": "Minnesota", + "city": "Lowgap" + } + }, + { + "id": 1729, + "name": "Wooten Vargas", + "gender": "male", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Berlin" + } + }, + { + "id": 1730, + "name": "Cecilia Strong", + "gender": "female", + "age": 72, + "address": { + "state": "Arizona", + "city": "Balm" + } + }, + { + "id": 1731, + "name": "Rivas Rice", + "gender": "male", + "age": 58, + "address": { + "state": "Maine", + "city": "Murillo" + } + }, + { + "id": 1732, + "name": "Alexis Suarez", + "gender": "female", + "age": 27, + "address": { + "state": "West Virginia", + "city": "Clarence" + } + }, + { + "id": 1733, + "name": "Koch Phelps", + "gender": "male", + "age": 63, + "address": { + "state": "Iowa", + "city": "Sparkill" + } + }, + { + "id": 1734, + "name": "Maritza Holman", + "gender": "female", + "age": 46, + "address": { + "state": "California", + "city": "Magnolia" + } + }, + { + "id": 1735, + "name": "Cobb Ward", + "gender": "male", + "age": 30, + "address": { + "state": "Alaska", + "city": "Crenshaw" + } + }, + { + "id": 1736, + "name": "Rice Jarvis", + "gender": "male", + "age": 47, + "address": { + "state": "Oklahoma", + "city": "Hardyville" + } + }, + { + "id": 1737, + "name": "Bowers Warner", + "gender": "male", + "age": 35, + "address": { + "state": "Oregon", + "city": "Selma" + } + }, + { + "id": 1738, + "name": "Crosby Rojas", + "gender": "male", + "age": 53, + "address": { + "state": "Kentucky", + "city": "Fostoria" + } + }, + { + "id": 1739, + "name": "Mariana Sweeney", + "gender": "female", + "age": 55, + "address": { + "state": "Hawaii", + "city": "Katonah" + } + }, + { + "id": 1740, + "name": "Snider Malone", + "gender": "male", + "age": 55, + "address": { + "state": "Nebraska", + "city": "Westphalia" + } + }, + { + "id": 1741, + "name": "Valarie Landry", + "gender": "female", + "age": 41, + "address": { + "state": "Massachusetts", + "city": "Sanford" + } + }, + { + "id": 1742, + "name": "Marilyn Meyer", + "gender": "female", + "age": 73, + "address": { + "state": "Connecticut", + "city": "Columbus" + } + }, + { + "id": 1743, + "name": "Cara Garza", + "gender": "female", + "age": 36, + "address": { + "state": "Utah", + "city": "Waterford" + } + }, + { + "id": 1744, + "name": "Cameron Ford", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Cassel" + } + }, + { + "id": 1745, + "name": "Marks Farmer", + "gender": "male", + "age": 25, + "address": { + "state": "Colorado", + "city": "Maxville" + } + }, + { + "id": 1746, + "name": "Joyce Herrera", + "gender": "male", + "age": 47, + "address": { + "state": "North Dakota", + "city": "Robinson" + } + }, + { + "id": 1747, + "name": "Alyssa Buckner", + "gender": "female", + "age": 43, + "address": { + "state": "Wisconsin", + "city": "Vincent" + } + }, + { + "id": 1748, + "name": "Jody West", + "gender": "female", + "age": 23, + "address": { + "state": "Vermont", + "city": "Whitewater" + } + }, + { + "id": 1749, + "name": "Hallie King", + "gender": "female", + "age": 38, + "address": { + "state": "Louisiana", + "city": "Greenbackville" + } + }, + { + "id": 1750, + "name": "Yesenia Singleton", + "gender": "female", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Mulberry" + } + }, + { + "id": 1751, + "name": "Fulton Hill", + "gender": "male", + "age": 51, + "address": { + "state": "Washington", + "city": "Mayfair" + } + }, + { + "id": 1752, + "name": "Opal Vang", + "gender": "female", + "age": 74, + "address": { + "state": "Texas", + "city": "Kansas" + } + }, + { + "id": 1753, + "name": "Simpson Parker", + "gender": "male", + "age": 81, + "address": { + "state": "Mississippi", + "city": "Hartsville/Hartley" + } + }, + { + "id": 1754, + "name": "Aurelia Lynch", + "gender": "female", + "age": 64, + "address": { + "state": "Maryland", + "city": "Makena" + } + }, + { + "id": 1755, + "name": "Bobbi Hamilton", + "gender": "female", + "age": 62, + "address": { + "state": "Rhode Island", + "city": "Topanga" + } + }, + { + "id": 1756, + "name": "Kirby Crawford", + "gender": "male", + "age": 52, + "address": { + "state": "Ohio", + "city": "Sylvanite" + } + }, + { + "id": 1757, + "name": "Merrill Mcdonald", + "gender": "male", + "age": 24, + "address": { + "state": "Alabama", + "city": "Gorham" + } + }, + { + "id": 1758, + "name": "Fitzgerald Huber", + "gender": "male", + "age": 19, + "address": { + "state": "Missouri", + "city": "Cuylerville" + } + }, + { + "id": 1759, + "name": "Dora Becker", + "gender": "female", + "age": 55, + "address": { + "state": "Illinois", + "city": "Croom" + } + }, + { + "id": 1760, + "name": "Colette Andrews", + "gender": "female", + "age": 81, + "address": { + "state": "Nevada", + "city": "Snowville" + } + }, + { + "id": 1761, + "name": "Ashley Santos", + "gender": "female", + "age": 74, + "address": { + "state": "Michigan", + "city": "Davenport" + } + }, + { + "id": 1762, + "name": "Keisha Hodge", + "gender": "female", + "age": 63, + "address": { + "state": "Wyoming", + "city": "Babb" + } + }, + { + "id": 1763, + "name": "Kirsten Oneal", + "gender": "female", + "age": 72, + "address": { + "state": "Kansas", + "city": "Wescosville" + } + }, + { + "id": 1764, + "name": "Meyers Workman", + "gender": "male", + "age": 55, + "address": { + "state": "Kentucky", + "city": "Sidman" + } + }, + { + "id": 1765, + "name": "Elnora Warren", + "gender": "female", + "age": 68, + "address": { + "state": "Connecticut", + "city": "Chloride" + } + }, + { + "id": 1766, + "name": "Christy Robinson", + "gender": "female", + "age": 21, + "address": { + "state": "Arizona", + "city": "Russellville" + } + }, + { + "id": 1767, + "name": "Maura Ware", + "gender": "female", + "age": 80, + "address": { + "state": "South Carolina", + "city": "Dyckesville" + } + }, + { + "id": 1768, + "name": "Swanson Winters", + "gender": "male", + "age": 26, + "address": { + "state": "Alaska", + "city": "Devon" + } + }, + { + "id": 1769, + "name": "Margie Hebert", + "gender": "female", + "age": 75, + "address": { + "state": "Michigan", + "city": "Albrightsville" + } + }, + { + "id": 1770, + "name": "Carrie Blackwell", + "gender": "female", + "age": 35, + "address": { + "state": "Georgia", + "city": "Allendale" + } + }, + { + "id": 1771, + "name": "Conley Cash", + "gender": "male", + "age": 43, + "address": { + "state": "South Dakota", + "city": "Virgie" + } + }, + { + "id": 1772, + "name": "Woodward Drake", + "gender": "male", + "age": 43, + "address": { + "state": "New Jersey", + "city": "Laurelton" + } + }, + { + "id": 1773, + "name": "Crane Rivas", + "gender": "male", + "age": 30, + "address": { + "state": "Missouri", + "city": "Roeville" + } + }, + { + "id": 1774, + "name": "Kaye Reed", + "gender": "female", + "age": 56, + "address": { + "state": "Alabama", + "city": "Jenkinsville" + } + }, + { + "id": 1775, + "name": "Marylou Brown", + "gender": "female", + "age": 30, + "address": { + "state": "California", + "city": "Watrous" + } + }, + { + "id": 1776, + "name": "Norris Bauer", + "gender": "male", + "age": 23, + "address": { + "state": "Virginia", + "city": "Blodgett" + } + }, + { + "id": 1777, + "name": "Lupe Solis", + "gender": "female", + "age": 19, + "address": { + "state": "Ohio", + "city": "Williamson" + } + }, + { + "id": 1778, + "name": "Martinez Sheppard", + "gender": "male", + "age": 45, + "address": { + "state": "Florida", + "city": "Colton" + } + }, + { + "id": 1779, + "name": "Hardy Wilson", + "gender": "male", + "age": 17, + "address": { + "state": "Nevada", + "city": "Freeburn" + } + }, + { + "id": 1780, + "name": "Velazquez Wilcox", + "gender": "male", + "age": 58, + "address": { + "state": "Nebraska", + "city": "Golconda" + } + }, + { + "id": 1781, + "name": "Harmon Sparks", + "gender": "male", + "age": 32, + "address": { + "state": "Maryland", + "city": "Eden" + } + }, + { + "id": 1782, + "name": "Rios Grimes", + "gender": "male", + "age": 62, + "address": { + "state": "Washington", + "city": "Maxville" + } + }, + { + "id": 1783, + "name": "Maggie Browning", + "gender": "female", + "age": 45, + "address": { + "state": "Louisiana", + "city": "Tuttle" + } + }, + { + "id": 1784, + "name": "Pollard Wallace", + "gender": "male", + "age": 53, + "address": { + "state": "Idaho", + "city": "Catherine" + } + }, + { + "id": 1785, + "name": "Sonya Ayers", + "gender": "female", + "age": 41, + "address": { + "state": "New York", + "city": "Wawona" + } + }, + { + "id": 1786, + "name": "Lila Lamb", + "gender": "female", + "age": 82, + "address": { + "state": "Rhode Island", + "city": "Columbus" + } + }, + { + "id": 1787, + "name": "Wheeler Macdonald", + "gender": "male", + "age": 74, + "address": { + "state": "Vermont", + "city": "Lowell" + } + }, + { + "id": 1788, + "name": "Guerrero Brady", + "gender": "male", + "age": 65, + "address": { + "state": "Hawaii", + "city": "Matheny" + } + }, + { + "id": 1789, + "name": "Summer Dixon", + "gender": "female", + "age": 64, + "address": { + "state": "Pennsylvania", + "city": "Bainbridge" + } + }, + { + "id": 1790, + "name": "Alma Reilly", + "gender": "female", + "age": 54, + "address": { + "state": "West Virginia", + "city": "Whitestone" + } + }, + { + "id": 1791, + "name": "Hebert Delacruz", + "gender": "male", + "age": 52, + "address": { + "state": "Minnesota", + "city": "Belvoir" + } + }, + { + "id": 1792, + "name": "Muriel Knight", + "gender": "female", + "age": 32, + "address": { + "state": "Utah", + "city": "Falmouth" + } + }, + { + "id": 1793, + "name": "Janice Kline", + "gender": "female", + "age": 39, + "address": { + "state": "Indiana", + "city": "Stouchsburg" + } + }, + { + "id": 1794, + "name": "Gabriela Kelley", + "gender": "female", + "age": 31, + "address": { + "state": "Iowa", + "city": "Tuskahoma" + } + }, + { + "id": 1795, + "name": "Queen Whitaker", + "gender": "female", + "age": 31, + "address": { + "state": "Texas", + "city": "Witmer" + } + }, + { + "id": 1796, + "name": "Reid Caldwell", + "gender": "male", + "age": 79, + "address": { + "state": "North Carolina", + "city": "Riviera" + } + }, + { + "id": 1797, + "name": "Paul Noel", + "gender": "male", + "age": 64, + "address": { + "state": "Oregon", + "city": "Enetai" + } + }, + { + "id": 1798, + "name": "Jo Dyer", + "gender": "female", + "age": 25, + "address": { + "state": "Mississippi", + "city": "Wilsonia" + } + }, + { + "id": 1799, + "name": "Dorthy Hall", + "gender": "female", + "age": 67, + "address": { + "state": "Oklahoma", + "city": "Enlow" + } + }, + { + "id": 1800, + "name": "Nancy Combs", + "gender": "female", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Martell" + } + }, + { + "id": 1801, + "name": "Ebony Buchanan", + "gender": "female", + "age": 30, + "address": { + "state": "Maine", + "city": "Ribera" + } + }, + { + "id": 1802, + "name": "Prince Rivera", + "gender": "male", + "age": 47, + "address": { + "state": "Montana", + "city": "Freetown" + } + }, + { + "id": 1803, + "name": "Ruiz Wiggins", + "gender": "male", + "age": 47, + "address": { + "state": "Colorado", + "city": "Turah" + } + }, + { + "id": 1804, + "name": "Bryant Bryan", + "gender": "male", + "age": 20, + "address": { + "state": "Kansas", + "city": "Harrison" + } + }, + { + "id": 1805, + "name": "Cline Hughes", + "gender": "male", + "age": 50, + "address": { + "state": "New Mexico", + "city": "Kingstowne" + } + }, + { + "id": 1806, + "name": "Rosario Humphrey", + "gender": "female", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Vernon" + } + }, + { + "id": 1807, + "name": "Joy Neal", + "gender": "female", + "age": 22, + "address": { + "state": "Wisconsin", + "city": "Urbana" + } + }, + { + "id": 1808, + "name": "Hobbs Dickson", + "gender": "male", + "age": 80, + "address": { + "state": "North Dakota", + "city": "Delwood" + } + }, + { + "id": 1809, + "name": "Mccormick Downs", + "gender": "male", + "age": 43, + "address": { + "state": "Delaware", + "city": "Highland" + } + }, + { + "id": 1810, + "name": "Leann Black", + "gender": "female", + "age": 19, + "address": { + "state": "Illinois", + "city": "Elliott" + } + }, + { + "id": 1811, + "name": "Jacobson Lester", + "gender": "male", + "age": 17, + "address": { + "state": "Tennessee", + "city": "Holtville" + } + }, + { + "id": 1812, + "name": "Yesenia Nolan", + "gender": "female", + "age": 75, + "address": { + "state": "Wyoming", + "city": "Templeton" + } + }, + { + "id": 1813, + "name": "Bernice Chang", + "gender": "female", + "age": 26, + "address": { + "state": "Montana", + "city": "Walland" + } + }, + { + "id": 1814, + "name": "Shelly Pickett", + "gender": "female", + "age": 24, + "address": { + "state": "Oklahoma", + "city": "Heil" + } + }, + { + "id": 1815, + "name": "Lorene Reynolds", + "gender": "female", + "age": 49, + "address": { + "state": "West Virginia", + "city": "Kapowsin" + } + }, + { + "id": 1816, + "name": "Bentley Roberson", + "gender": "male", + "age": 72, + "address": { + "state": "Minnesota", + "city": "Ladera" + } + }, + { + "id": 1817, + "name": "Leblanc Hancock", + "gender": "male", + "age": 73, + "address": { + "state": "Hawaii", + "city": "Sardis" + } + }, + { + "id": 1818, + "name": "Christina Hooper", + "gender": "female", + "age": 52, + "address": { + "state": "Indiana", + "city": "Magnolia" + } + }, + { + "id": 1819, + "name": "Schultz Foster", + "gender": "male", + "age": 79, + "address": { + "state": "Delaware", + "city": "Hendersonville" + } + }, + { + "id": 1820, + "name": "Nannie Whitley", + "gender": "female", + "age": 74, + "address": { + "state": "Vermont", + "city": "Maybell" + } + }, + { + "id": 1821, + "name": "Maddox Russo", + "gender": "male", + "age": 57, + "address": { + "state": "Kentucky", + "city": "Vowinckel" + } + }, + { + "id": 1822, + "name": "Kerr Johns", + "gender": "male", + "age": 50, + "address": { + "state": "Alabama", + "city": "Leola" + } + }, + { + "id": 1823, + "name": "Caitlin Dorsey", + "gender": "female", + "age": 68, + "address": { + "state": "Florida", + "city": "Why" + } + }, + { + "id": 1824, + "name": "Alisha Ross", + "gender": "female", + "age": 59, + "address": { + "state": "Oregon", + "city": "Wyano" + } + }, + { + "id": 1825, + "name": "Hinton Boyd", + "gender": "male", + "age": 82, + "address": { + "state": "Utah", + "city": "Fostoria" + } + }, + { + "id": 1826, + "name": "May Davidson", + "gender": "male", + "age": 45, + "address": { + "state": "Georgia", + "city": "Macdona" + } + }, + { + "id": 1827, + "name": "Gould Lara", + "gender": "male", + "age": 77, + "address": { + "state": "Kansas", + "city": "Sylvanite" + } + }, + { + "id": 1828, + "name": "Black Dunn", + "gender": "male", + "age": 36, + "address": { + "state": "Alaska", + "city": "Dale" + } + }, + { + "id": 1829, + "name": "Lillie Bray", + "gender": "female", + "age": 33, + "address": { + "state": "Maine", + "city": "Suitland" + } + }, + { + "id": 1830, + "name": "Blankenship Spencer", + "gender": "male", + "age": 38, + "address": { + "state": "North Dakota", + "city": "Wright" + } + }, + { + "id": 1831, + "name": "Dean Howe", + "gender": "male", + "age": 25, + "address": { + "state": "Missouri", + "city": "Kanauga" + } + }, + { + "id": 1832, + "name": "Leslie Haynes", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Rivera" + } + }, + { + "id": 1833, + "name": "Jill Norman", + "gender": "female", + "age": 78, + "address": { + "state": "Illinois", + "city": "Fairmount" + } + }, + { + "id": 1834, + "name": "Kasey Gilmore", + "gender": "female", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Benson" + } + }, + { + "id": 1835, + "name": "Pam Harper", + "gender": "female", + "age": 72, + "address": { + "state": "California", + "city": "Calpine" + } + }, + { + "id": 1836, + "name": "Meadows Emerson", + "gender": "male", + "age": 65, + "address": { + "state": "Louisiana", + "city": "Stewart" + } + }, + { + "id": 1837, + "name": "Whitehead Brewer", + "gender": "male", + "age": 66, + "address": { + "state": "Connecticut", + "city": "Keyport" + } + }, + { + "id": 1838, + "name": "Russo Salazar", + "gender": "male", + "age": 62, + "address": { + "state": "South Dakota", + "city": "Dalton" + } + }, + { + "id": 1839, + "name": "Long Randall", + "gender": "male", + "age": 73, + "address": { + "state": "Virginia", + "city": "Deseret" + } + }, + { + "id": 1840, + "name": "Kelli Macias", + "gender": "female", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Fairview" + } + }, + { + "id": 1841, + "name": "Kathrine Cole", + "gender": "female", + "age": 22, + "address": { + "state": "Washington", + "city": "Thomasville" + } + }, + { + "id": 1842, + "name": "Hardy Cleveland", + "gender": "male", + "age": 40, + "address": { + "state": "Michigan", + "city": "Robbins" + } + }, + { + "id": 1843, + "name": "Helene Avila", + "gender": "female", + "age": 30, + "address": { + "state": "South Carolina", + "city": "Canby" + } + }, + { + "id": 1844, + "name": "Madeline Bonner", + "gender": "female", + "age": 53, + "address": { + "state": "Idaho", + "city": "Virgie" + } + }, + { + "id": 1845, + "name": "Grimes Tanner", + "gender": "male", + "age": 70, + "address": { + "state": "Arkansas", + "city": "Kerby" + } + }, + { + "id": 1846, + "name": "Marisa Peck", + "gender": "female", + "age": 29, + "address": { + "state": "Mississippi", + "city": "Albrightsville" + } + }, + { + "id": 1847, + "name": "Odessa Carter", + "gender": "female", + "age": 39, + "address": { + "state": "Massachusetts", + "city": "Lodoga" + } + }, + { + "id": 1848, + "name": "Marion Paul", + "gender": "female", + "age": 70, + "address": { + "state": "New York", + "city": "Lewis" + } + }, + { + "id": 1849, + "name": "Kelly Torres", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Salvo" + } + }, + { + "id": 1850, + "name": "Nona Mitchell", + "gender": "female", + "age": 65, + "address": { + "state": "Iowa", + "city": "Ironton" + } + }, + { + "id": 1851, + "name": "Hensley Hebert", + "gender": "male", + "age": 56, + "address": { + "state": "New Jersey", + "city": "Sterling" + } + }, + { + "id": 1852, + "name": "White Frank", + "gender": "male", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Crayne" + } + }, + { + "id": 1853, + "name": "Clarissa Larson", + "gender": "female", + "age": 27, + "address": { + "state": "Colorado", + "city": "Noxen" + } + }, + { + "id": 1854, + "name": "Ruiz Potts", + "gender": "male", + "age": 53, + "address": { + "state": "Wisconsin", + "city": "Dola" + } + }, + { + "id": 1855, + "name": "Wilkins Dominguez", + "gender": "male", + "age": 41, + "address": { + "state": "Maryland", + "city": "Clarksburg" + } + }, + { + "id": 1856, + "name": "Stephens Blackwell", + "gender": "male", + "age": 80, + "address": { + "state": "Texas", + "city": "Sheatown" + } + }, + { + "id": 1857, + "name": "Lucille Chavez", + "gender": "female", + "age": 53, + "address": { + "state": "Arizona", + "city": "Lookingglass" + } + }, + { + "id": 1858, + "name": "Chaney Snider", + "gender": "male", + "age": 53, + "address": { + "state": "Wyoming", + "city": "Camptown" + } + }, + { + "id": 1859, + "name": "Constance Solomon", + "gender": "female", + "age": 79, + "address": { + "state": "Nevada", + "city": "Saranap" + } + }, + { + "id": 1860, + "name": "Walters Cherry", + "gender": "male", + "age": 36, + "address": { + "state": "Nebraska", + "city": "Delshire" + } + }, + { + "id": 1861, + "name": "Florine Martin", + "gender": "female", + "age": 32, + "address": { + "state": "Ohio", + "city": "Oceola" + } + }, + { + "id": 1862, + "name": "Cabrera Burnett", + "gender": "male", + "age": 52, + "address": { + "state": "North Carolina", + "city": "Bend" + } + }, + { + "id": 1863, + "name": "Oconnor Tate", + "gender": "male", + "age": 67, + "address": { + "state": "Hawaii", + "city": "Hoagland" + } + }, + { + "id": 1864, + "name": "Effie Ballard", + "gender": "female", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Russellville" + } + }, + { + "id": 1865, + "name": "Whitley Pope", + "gender": "male", + "age": 60, + "address": { + "state": "Nevada", + "city": "Wyano" + } + }, + { + "id": 1866, + "name": "Hardy Salas", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Delshire" + } + }, + { + "id": 1867, + "name": "Hooper Leonard", + "gender": "male", + "age": 35, + "address": { + "state": "Arkansas", + "city": "Springhill" + } + }, + { + "id": 1868, + "name": "Selena Mccormick", + "gender": "female", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Fairforest" + } + }, + { + "id": 1869, + "name": "Hester Conley", + "gender": "male", + "age": 72, + "address": { + "state": "Illinois", + "city": "Fairhaven" + } + }, + { + "id": 1870, + "name": "Alice Valentine", + "gender": "female", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Wescosville" + } + }, + { + "id": 1871, + "name": "Robinson Barnes", + "gender": "male", + "age": 33, + "address": { + "state": "Iowa", + "city": "Maybell" + } + }, + { + "id": 1872, + "name": "Marguerite Smith", + "gender": "female", + "age": 60, + "address": { + "state": "Arizona", + "city": "Whitewater" + } + }, + { + "id": 1873, + "name": "Katharine French", + "gender": "female", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Virgie" + } + }, + { + "id": 1874, + "name": "Shauna Whitley", + "gender": "female", + "age": 58, + "address": { + "state": "Oklahoma", + "city": "Cucumber" + } + }, + { + "id": 1875, + "name": "Prince Leon", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Norwood" + } + }, + { + "id": 1876, + "name": "Benita Barron", + "gender": "female", + "age": 49, + "address": { + "state": "California", + "city": "Belva" + } + }, + { + "id": 1877, + "name": "Erma Hughes", + "gender": "female", + "age": 49, + "address": { + "state": "Maryland", + "city": "Moscow" + } + }, + { + "id": 1878, + "name": "Kendra Mercer", + "gender": "female", + "age": 26, + "address": { + "state": "North Dakota", + "city": "Yorklyn" + } + }, + { + "id": 1879, + "name": "Kate Ruiz", + "gender": "female", + "age": 55, + "address": { + "state": "Washington", + "city": "Belleview" + } + }, + { + "id": 1880, + "name": "Adrian Cole", + "gender": "female", + "age": 22, + "address": { + "state": "Virginia", + "city": "Felt" + } + }, + { + "id": 1881, + "name": "Maribel Edwards", + "gender": "female", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Caspar" + } + }, + { + "id": 1882, + "name": "Mullen Woods", + "gender": "male", + "age": 64, + "address": { + "state": "Florida", + "city": "Grapeview" + } + }, + { + "id": 1883, + "name": "Mason Briggs", + "gender": "male", + "age": 71, + "address": { + "state": "Connecticut", + "city": "Berwind" + } + }, + { + "id": 1884, + "name": "Elisabeth David", + "gender": "female", + "age": 54, + "address": { + "state": "Maine", + "city": "Crayne" + } + }, + { + "id": 1885, + "name": "Reba Cameron", + "gender": "female", + "age": 77, + "address": { + "state": "Wyoming", + "city": "Temperanceville" + } + }, + { + "id": 1886, + "name": "Rachael Pace", + "gender": "female", + "age": 55, + "address": { + "state": "Kentucky", + "city": "Munjor" + } + }, + { + "id": 1887, + "name": "Acevedo Stafford", + "gender": "male", + "age": 42, + "address": { + "state": "Vermont", + "city": "Machias" + } + }, + { + "id": 1888, + "name": "Myrtle Berry", + "gender": "female", + "age": 37, + "address": { + "state": "Indiana", + "city": "Kent" + } + }, + { + "id": 1889, + "name": "Ratliff Beard", + "gender": "male", + "age": 80, + "address": { + "state": "Missouri", + "city": "Riceville" + } + }, + { + "id": 1890, + "name": "Nina Ashley", + "gender": "female", + "age": 59, + "address": { + "state": "Georgia", + "city": "Eggertsville" + } + }, + { + "id": 1891, + "name": "Benton Best", + "gender": "male", + "age": 48, + "address": { + "state": "Utah", + "city": "Kennedyville" + } + }, + { + "id": 1892, + "name": "Annie Wallace", + "gender": "female", + "age": 58, + "address": { + "state": "Mississippi", + "city": "Chalfant" + } + }, + { + "id": 1893, + "name": "Shepard Travis", + "gender": "male", + "age": 32, + "address": { + "state": "New Hampshire", + "city": "Irwin" + } + }, + { + "id": 1894, + "name": "Cathy Neal", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Linwood" + } + }, + { + "id": 1895, + "name": "Carole Foley", + "gender": "female", + "age": 76, + "address": { + "state": "Ohio", + "city": "Omar" + } + }, + { + "id": 1896, + "name": "Madeleine Russo", + "gender": "female", + "age": 42, + "address": { + "state": "Montana", + "city": "Torboy" + } + }, + { + "id": 1897, + "name": "Bessie Coleman", + "gender": "female", + "age": 18, + "address": { + "state": "Louisiana", + "city": "Coyote" + } + }, + { + "id": 1898, + "name": "Guzman Nicholson", + "gender": "male", + "age": 38, + "address": { + "state": "West Virginia", + "city": "Herlong" + } + }, + { + "id": 1899, + "name": "Marietta Sanders", + "gender": "female", + "age": 20, + "address": { + "state": "Colorado", + "city": "Churchill" + } + }, + { + "id": 1900, + "name": "Nunez Phelps", + "gender": "male", + "age": 50, + "address": { + "state": "Massachusetts", + "city": "Kraemer" + } + }, + { + "id": 1901, + "name": "Hallie Wilkinson", + "gender": "female", + "age": 52, + "address": { + "state": "Delaware", + "city": "Williston" + } + }, + { + "id": 1902, + "name": "Haley Chavez", + "gender": "female", + "age": 31, + "address": { + "state": "Oregon", + "city": "Lewis" + } + }, + { + "id": 1903, + "name": "Holmes Dawson", + "gender": "male", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Makena" + } + }, + { + "id": 1904, + "name": "Houston Mueller", + "gender": "male", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Chical" + } + }, + { + "id": 1905, + "name": "Atkinson Barrera", + "gender": "male", + "age": 63, + "address": { + "state": "Idaho", + "city": "Hendersonville" + } + }, + { + "id": 1906, + "name": "Ina Bartlett", + "gender": "female", + "age": 52, + "address": { + "state": "Alaska", + "city": "Jessie" + } + }, + { + "id": 1907, + "name": "Lindsey Alvarado", + "gender": "male", + "age": 65, + "address": { + "state": "Kansas", + "city": "Cornucopia" + } + }, + { + "id": 1908, + "name": "Yang Richmond", + "gender": "male", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Deseret" + } + }, + { + "id": 1909, + "name": "Darlene Maynard", + "gender": "female", + "age": 22, + "address": { + "state": "Texas", + "city": "Enoree" + } + }, + { + "id": 1910, + "name": "Burton Hopkins", + "gender": "male", + "age": 62, + "address": { + "state": "Alabama", + "city": "Outlook" + } + }, + { + "id": 1911, + "name": "Dillard Weaver", + "gender": "male", + "age": 21, + "address": { + "state": "Maine", + "city": "Sugartown" + } + }, + { + "id": 1912, + "name": "Cassandra Blackburn", + "gender": "female", + "age": 19, + "address": { + "state": "Missouri", + "city": "Loomis" + } + }, + { + "id": 1913, + "name": "Caitlin Herman", + "gender": "female", + "age": 22, + "address": { + "state": "Idaho", + "city": "Osmond" + } + }, + { + "id": 1914, + "name": "Hopkins Wall", + "gender": "male", + "age": 19, + "address": { + "state": "New York", + "city": "Bethpage" + } + }, + { + "id": 1915, + "name": "Bethany Solis", + "gender": "female", + "age": 31, + "address": { + "state": "Alaska", + "city": "Detroit" + } + }, + { + "id": 1916, + "name": "Sims Delacruz", + "gender": "male", + "age": 58, + "address": { + "state": "Montana", + "city": "Churchill" + } + }, + { + "id": 1917, + "name": "Clarke Dotson", + "gender": "male", + "age": 77, + "address": { + "state": "Louisiana", + "city": "Waterford" + } + }, + { + "id": 1918, + "name": "Herminia Booker", + "gender": "female", + "age": 35, + "address": { + "state": "Ohio", + "city": "Boyd" + } + }, + { + "id": 1919, + "name": "Michael Fitzpatrick", + "gender": "male", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Stockwell" + } + }, + { + "id": 1920, + "name": "Conley Alston", + "gender": "male", + "age": 56, + "address": { + "state": "Wyoming", + "city": "Snyderville" + } + }, + { + "id": 1921, + "name": "Katie Kirkland", + "gender": "female", + "age": 23, + "address": { + "state": "New Hampshire", + "city": "Fredericktown" + } + }, + { + "id": 1922, + "name": "Therese Gay", + "gender": "female", + "age": 21, + "address": { + "state": "Washington", + "city": "Elrama" + } + }, + { + "id": 1923, + "name": "Cindy Bailey", + "gender": "female", + "age": 56, + "address": { + "state": "Iowa", + "city": "Gardiner" + } + }, + { + "id": 1924, + "name": "Cherie Stevens", + "gender": "female", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Comptche" + } + }, + { + "id": 1925, + "name": "Linda Schultz", + "gender": "female", + "age": 75, + "address": { + "state": "California", + "city": "Cotopaxi" + } + }, + { + "id": 1926, + "name": "Cara Brooks", + "gender": "female", + "age": 49, + "address": { + "state": "Florida", + "city": "Yettem" + } + }, + { + "id": 1927, + "name": "Erica Green", + "gender": "female", + "age": 31, + "address": { + "state": "New Mexico", + "city": "Hachita" + } + }, + { + "id": 1928, + "name": "Glass Humphrey", + "gender": "male", + "age": 60, + "address": { + "state": "Mississippi", + "city": "Lupton" + } + }, + { + "id": 1929, + "name": "Harriett Payne", + "gender": "female", + "age": 22, + "address": { + "state": "North Carolina", + "city": "Starks" + } + }, + { + "id": 1930, + "name": "Mckenzie Osborne", + "gender": "male", + "age": 66, + "address": { + "state": "Kansas", + "city": "Deercroft" + } + }, + { + "id": 1931, + "name": "Kristen Giles", + "gender": "female", + "age": 51, + "address": { + "state": "Tennessee", + "city": "Rockhill" + } + }, + { + "id": 1932, + "name": "Conrad Roth", + "gender": "male", + "age": 32, + "address": { + "state": "Utah", + "city": "Brooktrails" + } + }, + { + "id": 1933, + "name": "Flossie Vaughn", + "gender": "female", + "age": 52, + "address": { + "state": "Oklahoma", + "city": "Marshall" + } + }, + { + "id": 1934, + "name": "Mcmahon House", + "gender": "male", + "age": 26, + "address": { + "state": "Alabama", + "city": "Coalmont" + } + }, + { + "id": 1935, + "name": "Margaret Massey", + "gender": "female", + "age": 67, + "address": { + "state": "New Jersey", + "city": "Waterloo" + } + }, + { + "id": 1936, + "name": "Kaitlin Ingram", + "gender": "female", + "age": 21, + "address": { + "state": "Wisconsin", + "city": "Ernstville" + } + }, + { + "id": 1937, + "name": "Daisy Burns", + "gender": "female", + "age": 28, + "address": { + "state": "Hawaii", + "city": "Imperial" + } + }, + { + "id": 1938, + "name": "Charmaine Gutierrez", + "gender": "female", + "age": 27, + "address": { + "state": "Vermont", + "city": "Edinburg" + } + }, + { + "id": 1939, + "name": "Garza Blair", + "gender": "male", + "age": 69, + "address": { + "state": "Virginia", + "city": "Morgandale" + } + }, + { + "id": 1940, + "name": "Celina Rios", + "gender": "female", + "age": 45, + "address": { + "state": "Nevada", + "city": "Keyport" + } + }, + { + "id": 1941, + "name": "Cameron Kidd", + "gender": "male", + "age": 47, + "address": { + "state": "Maryland", + "city": "Charco" + } + }, + { + "id": 1942, + "name": "Tillman Rush", + "gender": "male", + "age": 81, + "address": { + "state": "Kentucky", + "city": "Highland" + } + }, + { + "id": 1943, + "name": "Sabrina Carson", + "gender": "female", + "age": 53, + "address": { + "state": "North Dakota", + "city": "Gouglersville" + } + }, + { + "id": 1944, + "name": "Lucile Goodwin", + "gender": "female", + "age": 72, + "address": { + "state": "Colorado", + "city": "Muir" + } + }, + { + "id": 1945, + "name": "Murphy Hill", + "gender": "male", + "age": 55, + "address": { + "state": "Oregon", + "city": "Loma" + } + }, + { + "id": 1946, + "name": "Callie Hogan", + "gender": "female", + "age": 51, + "address": { + "state": "Michigan", + "city": "Movico" + } + }, + { + "id": 1947, + "name": "Bette Gould", + "gender": "female", + "age": 23, + "address": { + "state": "Nebraska", + "city": "Chase" + } + }, + { + "id": 1948, + "name": "Rachelle Wyatt", + "gender": "female", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Glidden" + } + }, + { + "id": 1949, + "name": "Kirk Frye", + "gender": "male", + "age": 37, + "address": { + "state": "Rhode Island", + "city": "Sehili" + } + }, + { + "id": 1950, + "name": "Carey Bradford", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Bedias" + } + }, + { + "id": 1951, + "name": "Elaine Miranda", + "gender": "female", + "age": 37, + "address": { + "state": "South Carolina", + "city": "Hoagland" + } + }, + { + "id": 1952, + "name": "Ellen Parks", + "gender": "female", + "age": 69, + "address": { + "state": "Connecticut", + "city": "Libertytown" + } + }, + { + "id": 1953, + "name": "Selma Henson", + "gender": "female", + "age": 39, + "address": { + "state": "Arizona", + "city": "Motley" + } + }, + { + "id": 1954, + "name": "Kelly Brady", + "gender": "male", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Kilbourne" + } + }, + { + "id": 1955, + "name": "Sonja Ruiz", + "gender": "female", + "age": 57, + "address": { + "state": "Delaware", + "city": "Aguila" + } + }, + { + "id": 1956, + "name": "Albert Hayes", + "gender": "male", + "age": 38, + "address": { + "state": "Indiana", + "city": "Marne" + } + }, + { + "id": 1957, + "name": "Lottie Potts", + "gender": "female", + "age": 60, + "address": { + "state": "Texas", + "city": "Rossmore" + } + }, + { + "id": 1958, + "name": "Jones Holden", + "gender": "male", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Rose" + } + }, + { + "id": 1959, + "name": "Mccormick Barr", + "gender": "male", + "age": 45, + "address": { + "state": "Georgia", + "city": "Fowlerville" + } + }, + { + "id": 1960, + "name": "Cain Austin", + "gender": "male", + "age": 35, + "address": { + "state": "Massachusetts", + "city": "Maplewood" + } + }, + { + "id": 1961, + "name": "Mitchell Harvey", + "gender": "male", + "age": 62, + "address": { + "state": "Virginia", + "city": "Warren" + } + }, + { + "id": 1962, + "name": "Prince Charles", + "gender": "male", + "age": 20, + "address": { + "state": "Mississippi", + "city": "Aguila" + } + }, + { + "id": 1963, + "name": "Leon Horton", + "gender": "male", + "age": 76, + "address": { + "state": "Nevada", + "city": "Grahamtown" + } + }, + { + "id": 1964, + "name": "Victoria Sanders", + "gender": "female", + "age": 64, + "address": { + "state": "California", + "city": "Clarktown" + } + }, + { + "id": 1965, + "name": "Theresa Pugh", + "gender": "female", + "age": 82, + "address": { + "state": "Minnesota", + "city": "Soudan" + } + }, + { + "id": 1966, + "name": "Lott Shields", + "gender": "male", + "age": 30, + "address": { + "state": "Hawaii", + "city": "Kidder" + } + }, + { + "id": 1967, + "name": "Gould Villarreal", + "gender": "male", + "age": 71, + "address": { + "state": "Texas", + "city": "Dixie" + } + }, + { + "id": 1968, + "name": "Marci Rowland", + "gender": "female", + "age": 29, + "address": { + "state": "South Carolina", + "city": "Orviston" + } + }, + { + "id": 1969, + "name": "Martha Cummings", + "gender": "female", + "age": 79, + "address": { + "state": "Michigan", + "city": "Alden" + } + }, + { + "id": 1970, + "name": "Leann Stanton", + "gender": "female", + "age": 59, + "address": { + "state": "Delaware", + "city": "Virgie" + } + }, + { + "id": 1971, + "name": "Stuart Massey", + "gender": "male", + "age": 55, + "address": { + "state": "Maryland", + "city": "Mapletown" + } + }, + { + "id": 1972, + "name": "Chavez Christensen", + "gender": "male", + "age": 64, + "address": { + "state": "Alabama", + "city": "Imperial" + } + }, + { + "id": 1973, + "name": "Rachelle Fox", + "gender": "female", + "age": 32, + "address": { + "state": "Kentucky", + "city": "Fairlee" + } + }, + { + "id": 1974, + "name": "Terra Jacobs", + "gender": "female", + "age": 73, + "address": { + "state": "North Carolina", + "city": "Laurelton" + } + }, + { + "id": 1975, + "name": "Hillary Mccarty", + "gender": "female", + "age": 27, + "address": { + "state": "Illinois", + "city": "Bowmansville" + } + }, + { + "id": 1976, + "name": "Kelly Barrera", + "gender": "male", + "age": 21, + "address": { + "state": "New Mexico", + "city": "Berwind" + } + }, + { + "id": 1977, + "name": "Greene Alston", + "gender": "male", + "age": 68, + "address": { + "state": "Nebraska", + "city": "Rosedale" + } + }, + { + "id": 1978, + "name": "Ortiz Ruiz", + "gender": "male", + "age": 19, + "address": { + "state": "New York", + "city": "Ballico" + } + }, + { + "id": 1979, + "name": "Shannon Sutton", + "gender": "male", + "age": 35, + "address": { + "state": "Utah", + "city": "Venice" + } + }, + { + "id": 1980, + "name": "Case Vaughn", + "gender": "male", + "age": 43, + "address": { + "state": "Rhode Island", + "city": "Unionville" + } + }, + { + "id": 1981, + "name": "Coleen Taylor", + "gender": "female", + "age": 30, + "address": { + "state": "Indiana", + "city": "Templeton" + } + }, + { + "id": 1982, + "name": "Polly Obrien", + "gender": "female", + "age": 61, + "address": { + "state": "Kansas", + "city": "Fairhaven" + } + }, + { + "id": 1983, + "name": "Gutierrez Mcintosh", + "gender": "male", + "age": 53, + "address": { + "state": "Colorado", + "city": "Darbydale" + } + }, + { + "id": 1984, + "name": "Potter Terrell", + "gender": "male", + "age": 34, + "address": { + "state": "Oregon", + "city": "Axis" + } + }, + { + "id": 1985, + "name": "Conway Pickett", + "gender": "male", + "age": 56, + "address": { + "state": "Oklahoma", + "city": "Singer" + } + }, + { + "id": 1986, + "name": "Letitia Gonzales", + "gender": "female", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Keller" + } + }, + { + "id": 1987, + "name": "Lucile Macias", + "gender": "female", + "age": 58, + "address": { + "state": "Maine", + "city": "Gardners" + } + }, + { + "id": 1988, + "name": "Angeline Miranda", + "gender": "female", + "age": 63, + "address": { + "state": "New Hampshire", + "city": "Jugtown" + } + }, + { + "id": 1989, + "name": "Foster Rocha", + "gender": "male", + "age": 27, + "address": { + "state": "Missouri", + "city": "Stewartville" + } + }, + { + "id": 1990, + "name": "Phelps Bullock", + "gender": "male", + "age": 36, + "address": { + "state": "Idaho", + "city": "Hackneyville" + } + }, + { + "id": 1991, + "name": "Howell Blake", + "gender": "male", + "age": 82, + "address": { + "state": "Wyoming", + "city": "Ebro" + } + }, + { + "id": 1992, + "name": "Chen Stark", + "gender": "male", + "age": 30, + "address": { + "state": "Florida", + "city": "Edinburg" + } + }, + { + "id": 1993, + "name": "Pat Spence", + "gender": "female", + "age": 27, + "address": { + "state": "West Virginia", + "city": "Cleary" + } + }, + { + "id": 1994, + "name": "Lily William", + "gender": "female", + "age": 31, + "address": { + "state": "Washington", + "city": "Como" + } + }, + { + "id": 1995, + "name": "Sheila Webster", + "gender": "female", + "age": 63, + "address": { + "state": "Arkansas", + "city": "Loyalhanna" + } + }, + { + "id": 1996, + "name": "Christy Langley", + "gender": "female", + "age": 71, + "address": { + "state": "Iowa", + "city": "Hegins" + } + }, + { + "id": 1997, + "name": "Queen Savage", + "gender": "female", + "age": 80, + "address": { + "state": "Arizona", + "city": "Freelandville" + } + }, + { + "id": 1998, + "name": "Denise Mayo", + "gender": "female", + "age": 24, + "address": { + "state": "Tennessee", + "city": "Lowell" + } + }, + { + "id": 1999, + "name": "Terry Zamora", + "gender": "male", + "age": 21, + "address": { + "state": "Alaska", + "city": "Deputy" + } + }, + { + "id": 2000, + "name": "Sonia Norton", + "gender": "female", + "age": 43, + "address": { + "state": "Ohio", + "city": "Brogan" + } + }, + { + "id": 2001, + "name": "Sadie Snow", + "gender": "female", + "age": 81, + "address": { + "state": "Montana", + "city": "Dola" + } + }, + { + "id": 2002, + "name": "Leola Cameron", + "gender": "female", + "age": 76, + "address": { + "state": "Pennsylvania", + "city": "Kerby" + } + }, + { + "id": 2003, + "name": "Olga Heath", + "gender": "female", + "age": 28, + "address": { + "state": "Louisiana", + "city": "Valle" + } + }, + { + "id": 2004, + "name": "Guerrero Logan", + "gender": "male", + "age": 72, + "address": { + "state": "Georgia", + "city": "Grill" + } + }, + { + "id": 2005, + "name": "Zelma Haley", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Saticoy" + } + }, + { + "id": 2006, + "name": "Cheryl Warren", + "gender": "female", + "age": 61, + "address": { + "state": "Vermont", + "city": "Winston" + } + }, + { + "id": 2007, + "name": "Frazier Carey", + "gender": "male", + "age": 61, + "address": { + "state": "North Dakota", + "city": "Epworth" + } + }, + { + "id": 2008, + "name": "Mccarthy Nieves", + "gender": "male", + "age": 62, + "address": { + "state": "New Jersey", + "city": "Grazierville" + } + }, + { + "id": 2009, + "name": "Ivy Reed", + "gender": "female", + "age": 50, + "address": { + "state": "Utah", + "city": "Avalon" + } + }, + { + "id": 2010, + "name": "Manning Kirby", + "gender": "male", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Gallina" + } + }, + { + "id": 2011, + "name": "Michael Barry", + "gender": "male", + "age": 32, + "address": { + "state": "Illinois", + "city": "Grahamtown" + } + }, + { + "id": 2012, + "name": "Dorthy Marquez", + "gender": "female", + "age": 74, + "address": { + "state": "Florida", + "city": "Bluetown" + } + }, + { + "id": 2013, + "name": "Mccarthy Rich", + "gender": "male", + "age": 29, + "address": { + "state": "North Carolina", + "city": "Murillo" + } + }, + { + "id": 2014, + "name": "Atkinson Taylor", + "gender": "male", + "age": 37, + "address": { + "state": "Massachusetts", + "city": "Draper" + } + }, + { + "id": 2015, + "name": "Wilcox Bolton", + "gender": "male", + "age": 23, + "address": { + "state": "Virginia", + "city": "Croom" + } + }, + { + "id": 2016, + "name": "Guthrie Mooney", + "gender": "male", + "age": 20, + "address": { + "state": "Colorado", + "city": "Jacumba" + } + }, + { + "id": 2017, + "name": "Vazquez Bauer", + "gender": "male", + "age": 18, + "address": { + "state": "Montana", + "city": "Brantleyville" + } + }, + { + "id": 2018, + "name": "Alston Franklin", + "gender": "male", + "age": 36, + "address": { + "state": "Pennsylvania", + "city": "Sexton" + } + }, + { + "id": 2019, + "name": "Richmond Morgan", + "gender": "male", + "age": 68, + "address": { + "state": "Kansas", + "city": "Gardners" + } + }, + { + "id": 2020, + "name": "Julie Jenkins", + "gender": "female", + "age": 61, + "address": { + "state": "Hawaii", + "city": "Oceola" + } + }, + { + "id": 2021, + "name": "Vaughan Mays", + "gender": "male", + "age": 63, + "address": { + "state": "Missouri", + "city": "Kent" + } + }, + { + "id": 2022, + "name": "Deena Holden", + "gender": "female", + "age": 77, + "address": { + "state": "Nevada", + "city": "Durham" + } + }, + { + "id": 2023, + "name": "Hinton Keith", + "gender": "male", + "age": 63, + "address": { + "state": "Delaware", + "city": "Trexlertown" + } + }, + { + "id": 2024, + "name": "Jimmie Porter", + "gender": "female", + "age": 58, + "address": { + "state": "Connecticut", + "city": "Terlingua" + } + }, + { + "id": 2025, + "name": "Ellen Conway", + "gender": "female", + "age": 81, + "address": { + "state": "South Dakota", + "city": "Laurelton" + } + }, + { + "id": 2026, + "name": "Johnston Richards", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Derwood" + } + }, + { + "id": 2027, + "name": "Alberta King", + "gender": "female", + "age": 24, + "address": { + "state": "Tennessee", + "city": "Catherine" + } + }, + { + "id": 2028, + "name": "Berg Hubbard", + "gender": "male", + "age": 77, + "address": { + "state": "Rhode Island", + "city": "Finzel" + } + }, + { + "id": 2029, + "name": "Franco Clay", + "gender": "male", + "age": 55, + "address": { + "state": "Iowa", + "city": "Fairhaven" + } + }, + { + "id": 2030, + "name": "Becky Head", + "gender": "female", + "age": 42, + "address": { + "state": "Ohio", + "city": "Harrison" + } + }, + { + "id": 2031, + "name": "Brianna Burt", + "gender": "female", + "age": 45, + "address": { + "state": "Alaska", + "city": "Riegelwood" + } + }, + { + "id": 2032, + "name": "Elnora Burch", + "gender": "female", + "age": 41, + "address": { + "state": "Maryland", + "city": "Belfair" + } + }, + { + "id": 2033, + "name": "Deann Morin", + "gender": "female", + "age": 69, + "address": { + "state": "California", + "city": "Hoagland" + } + }, + { + "id": 2034, + "name": "Augusta Hudson", + "gender": "female", + "age": 54, + "address": { + "state": "Minnesota", + "city": "Springdale" + } + }, + { + "id": 2035, + "name": "Alexandria Bowman", + "gender": "female", + "age": 82, + "address": { + "state": "Michigan", + "city": "Tyhee" + } + }, + { + "id": 2036, + "name": "Meghan French", + "gender": "female", + "age": 57, + "address": { + "state": "Arkansas", + "city": "Torboy" + } + }, + { + "id": 2037, + "name": "Sloan Buckley", + "gender": "male", + "age": 61, + "address": { + "state": "New Hampshire", + "city": "Elliott" + } + }, + { + "id": 2038, + "name": "Robbins Simon", + "gender": "male", + "age": 63, + "address": { + "state": "Washington", + "city": "Brandywine" + } + }, + { + "id": 2039, + "name": "Carey Foreman", + "gender": "male", + "age": 61, + "address": { + "state": "Vermont", + "city": "Cornucopia" + } + }, + { + "id": 2040, + "name": "Brock Cunningham", + "gender": "male", + "age": 64, + "address": { + "state": "Oregon", + "city": "Chical" + } + }, + { + "id": 2041, + "name": "Galloway Mack", + "gender": "male", + "age": 78, + "address": { + "state": "South Carolina", + "city": "Kingstowne" + } + }, + { + "id": 2042, + "name": "Camille Joyner", + "gender": "female", + "age": 66, + "address": { + "state": "New Mexico", + "city": "Gibsonia" + } + }, + { + "id": 2043, + "name": "Reyna Moran", + "gender": "female", + "age": 82, + "address": { + "state": "Kentucky", + "city": "Matthews" + } + }, + { + "id": 2044, + "name": "Willis Garza", + "gender": "male", + "age": 71, + "address": { + "state": "Maine", + "city": "Dunbar" + } + }, + { + "id": 2045, + "name": "Vang Kemp", + "gender": "male", + "age": 36, + "address": { + "state": "Wyoming", + "city": "Loveland" + } + }, + { + "id": 2046, + "name": "Shanna Riley", + "gender": "female", + "age": 75, + "address": { + "state": "Arizona", + "city": "Sehili" + } + }, + { + "id": 2047, + "name": "Lewis Rosa", + "gender": "male", + "age": 49, + "address": { + "state": "Mississippi", + "city": "Freeburn" + } + }, + { + "id": 2048, + "name": "Penelope Ferrell", + "gender": "female", + "age": 52, + "address": { + "state": "New York", + "city": "Hollins" + } + }, + { + "id": 2049, + "name": "Rebekah Gardner", + "gender": "female", + "age": 40, + "address": { + "state": "North Dakota", + "city": "Manchester" + } + }, + { + "id": 2050, + "name": "Selma Fernandez", + "gender": "female", + "age": 31, + "address": { + "state": "Louisiana", + "city": "Suitland" + } + }, + { + "id": 2051, + "name": "Logan Key", + "gender": "male", + "age": 55, + "address": { + "state": "Texas", + "city": "Guilford" + } + }, + { + "id": 2052, + "name": "Marquez Hatfield", + "gender": "male", + "age": 26, + "address": { + "state": "Wisconsin", + "city": "Allamuchy" + } + }, + { + "id": 2053, + "name": "Debra Willis", + "gender": "female", + "age": 30, + "address": { + "state": "New Jersey", + "city": "Flintville" + } + }, + { + "id": 2054, + "name": "Serrano Britt", + "gender": "male", + "age": 68, + "address": { + "state": "Indiana", + "city": "Allentown" + } + }, + { + "id": 2055, + "name": "Sonia Schultz", + "gender": "female", + "age": 59, + "address": { + "state": "Oklahoma", + "city": "Wildwood" + } + }, + { + "id": 2056, + "name": "Gonzales Richmond", + "gender": "male", + "age": 67, + "address": { + "state": "Georgia", + "city": "Lawrence" + } + }, + { + "id": 2057, + "name": "Brandi Perez", + "gender": "female", + "age": 28, + "address": { + "state": "Alabama", + "city": "Fontanelle" + } + }, + { + "id": 2058, + "name": "Briggs Chan", + "gender": "male", + "age": 58, + "address": { + "state": "Pennsylvania", + "city": "Wacissa" + } + }, + { + "id": 2059, + "name": "Leonard Morgan", + "gender": "male", + "age": 32, + "address": { + "state": "New Jersey", + "city": "Ironton" + } + }, + { + "id": 2060, + "name": "Morin Lynn", + "gender": "male", + "age": 45, + "address": { + "state": "Texas", + "city": "Cecilia" + } + }, + { + "id": 2061, + "name": "Mildred Hess", + "gender": "female", + "age": 34, + "address": { + "state": "Utah", + "city": "Farmers" + } + }, + { + "id": 2062, + "name": "Rowe Brennan", + "gender": "male", + "age": 68, + "address": { + "state": "Idaho", + "city": "Knowlton" + } + }, + { + "id": 2063, + "name": "Chris Church", + "gender": "female", + "age": 55, + "address": { + "state": "Ohio", + "city": "Canoochee" + } + }, + { + "id": 2064, + "name": "Toni Hayden", + "gender": "female", + "age": 73, + "address": { + "state": "Wyoming", + "city": "Biddle" + } + }, + { + "id": 2065, + "name": "Harmon Hickman", + "gender": "male", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Camino" + } + }, + { + "id": 2066, + "name": "Butler Pace", + "gender": "male", + "age": 29, + "address": { + "state": "Kentucky", + "city": "Yettem" + } + }, + { + "id": 2067, + "name": "Rebekah Kennedy", + "gender": "female", + "age": 61, + "address": { + "state": "Delaware", + "city": "Thermal" + } + }, + { + "id": 2068, + "name": "Torres Mckenzie", + "gender": "male", + "age": 36, + "address": { + "state": "South Carolina", + "city": "Greensburg" + } + }, + { + "id": 2069, + "name": "Rosie Russell", + "gender": "female", + "age": 21, + "address": { + "state": "Michigan", + "city": "Bascom" + } + }, + { + "id": 2070, + "name": "Velez Roberts", + "gender": "male", + "age": 44, + "address": { + "state": "Colorado", + "city": "Rivereno" + } + }, + { + "id": 2071, + "name": "Harrington Key", + "gender": "male", + "age": 21, + "address": { + "state": "Maryland", + "city": "Norris" + } + }, + { + "id": 2072, + "name": "Espinoza Sullivan", + "gender": "male", + "age": 66, + "address": { + "state": "Kansas", + "city": "Bannock" + } + }, + { + "id": 2073, + "name": "Elsa Rivers", + "gender": "female", + "age": 78, + "address": { + "state": "New York", + "city": "Flintville" + } + }, + { + "id": 2074, + "name": "Tamika Newton", + "gender": "female", + "age": 24, + "address": { + "state": "Wisconsin", + "city": "Wedgewood" + } + }, + { + "id": 2075, + "name": "Cobb Duncan", + "gender": "male", + "age": 54, + "address": { + "state": "Massachusetts", + "city": "Caln" + } + }, + { + "id": 2076, + "name": "Lora Drake", + "gender": "female", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Bainbridge" + } + }, + { + "id": 2077, + "name": "Castro Rodgers", + "gender": "male", + "age": 37, + "address": { + "state": "Arkansas", + "city": "Welda" + } + }, + { + "id": 2078, + "name": "Campbell Romero", + "gender": "male", + "age": 58, + "address": { + "state": "Indiana", + "city": "Highland" + } + }, + { + "id": 2079, + "name": "Peterson Gordon", + "gender": "male", + "age": 32, + "address": { + "state": "South Dakota", + "city": "Chesapeake" + } + }, + { + "id": 2080, + "name": "Maribel King", + "gender": "female", + "age": 59, + "address": { + "state": "Vermont", + "city": "Belvoir" + } + }, + { + "id": 2081, + "name": "Riddle Donovan", + "gender": "male", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Brooktrails" + } + }, + { + "id": 2082, + "name": "Marianne Foley", + "gender": "female", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Downsville" + } + }, + { + "id": 2083, + "name": "Tanisha Rivera", + "gender": "female", + "age": 21, + "address": { + "state": "California", + "city": "Florence" + } + }, + { + "id": 2084, + "name": "Leanne Soto", + "gender": "female", + "age": 41, + "address": { + "state": "Georgia", + "city": "Inkerman" + } + }, + { + "id": 2085, + "name": "Miranda Bray", + "gender": "female", + "age": 31, + "address": { + "state": "Oklahoma", + "city": "Oceola" + } + }, + { + "id": 2086, + "name": "Mitchell Bradshaw", + "gender": "male", + "age": 46, + "address": { + "state": "New Mexico", + "city": "Berlin" + } + }, + { + "id": 2087, + "name": "Lorie Goff", + "gender": "female", + "age": 74, + "address": { + "state": "Illinois", + "city": "Eastvale" + } + }, + { + "id": 2088, + "name": "Melody Roberson", + "gender": "female", + "age": 21, + "address": { + "state": "North Carolina", + "city": "Bartonsville" + } + }, + { + "id": 2089, + "name": "Lorrie West", + "gender": "female", + "age": 35, + "address": { + "state": "Missouri", + "city": "Wakulla" + } + }, + { + "id": 2090, + "name": "Aurelia Walters", + "gender": "female", + "age": 46, + "address": { + "state": "Alabama", + "city": "Oley" + } + }, + { + "id": 2091, + "name": "Lula Dyer", + "gender": "female", + "age": 58, + "address": { + "state": "Minnesota", + "city": "Maury" + } + }, + { + "id": 2092, + "name": "Farley Holmes", + "gender": "male", + "age": 75, + "address": { + "state": "Arizona", + "city": "Bentley" + } + }, + { + "id": 2093, + "name": "Ramirez Leach", + "gender": "male", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Bentonville" + } + }, + { + "id": 2094, + "name": "Gardner Cherry", + "gender": "male", + "age": 77, + "address": { + "state": "Alaska", + "city": "Montura" + } + }, + { + "id": 2095, + "name": "Mckee Hanson", + "gender": "male", + "age": 45, + "address": { + "state": "Maine", + "city": "Chilton" + } + }, + { + "id": 2096, + "name": "Carolina Lynch", + "gender": "female", + "age": 77, + "address": { + "state": "Florida", + "city": "Bordelonville" + } + }, + { + "id": 2097, + "name": "May Melton", + "gender": "male", + "age": 66, + "address": { + "state": "Washington", + "city": "Dante" + } + }, + { + "id": 2098, + "name": "Willa Sanders", + "gender": "female", + "age": 25, + "address": { + "state": "Tennessee", + "city": "Sparkill" + } + }, + { + "id": 2099, + "name": "Latoya Stuart", + "gender": "female", + "age": 73, + "address": { + "state": "West Virginia", + "city": "Marbury" + } + }, + { + "id": 2100, + "name": "Snider Vasquez", + "gender": "male", + "age": 48, + "address": { + "state": "Nevada", + "city": "Coinjock" + } + }, + { + "id": 2101, + "name": "Kenya Ferguson", + "gender": "female", + "age": 69, + "address": { + "state": "Mississippi", + "city": "Collins" + } + }, + { + "id": 2102, + "name": "Guadalupe Puckett", + "gender": "female", + "age": 21, + "address": { + "state": "Oregon", + "city": "Drytown" + } + }, + { + "id": 2103, + "name": "Nicholson Ellis", + "gender": "male", + "age": 51, + "address": { + "state": "Iowa", + "city": "Nipinnawasee" + } + }, + { + "id": 2104, + "name": "Letitia Merrill", + "gender": "female", + "age": 53, + "address": { + "state": "Montana", + "city": "Bend" + } + }, + { + "id": 2105, + "name": "Avery Neal", + "gender": "male", + "age": 17, + "address": { + "state": "North Dakota", + "city": "Boling" + } + }, + { + "id": 2106, + "name": "Beach Valenzuela", + "gender": "male", + "age": 62, + "address": { + "state": "Virginia", + "city": "Blodgett" + } + }, + { + "id": 2107, + "name": "Aileen Gallagher", + "gender": "female", + "age": 28, + "address": { + "state": "Iowa", + "city": "Whitewater" + } + }, + { + "id": 2108, + "name": "Mueller Mayo", + "gender": "male", + "age": 51, + "address": { + "state": "North Dakota", + "city": "Woodlake" + } + }, + { + "id": 2109, + "name": "Johns Gill", + "gender": "male", + "age": 53, + "address": { + "state": "New York", + "city": "Lund" + } + }, + { + "id": 2110, + "name": "Zelma Middleton", + "gender": "female", + "age": 52, + "address": { + "state": "Ohio", + "city": "Bergoo" + } + }, + { + "id": 2111, + "name": "Vonda Horne", + "gender": "female", + "age": 55, + "address": { + "state": "Tennessee", + "city": "Broadlands" + } + }, + { + "id": 2112, + "name": "Jerry French", + "gender": "female", + "age": 43, + "address": { + "state": "Texas", + "city": "Eastvale" + } + }, + { + "id": 2113, + "name": "Larsen Frazier", + "gender": "male", + "age": 75, + "address": { + "state": "Montana", + "city": "Grapeview" + } + }, + { + "id": 2114, + "name": "Winnie Graham", + "gender": "female", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Hall" + } + }, + { + "id": 2115, + "name": "Sweeney Ware", + "gender": "male", + "age": 45, + "address": { + "state": "South Carolina", + "city": "Mammoth" + } + }, + { + "id": 2116, + "name": "Preston Mcgowan", + "gender": "male", + "age": 54, + "address": { + "state": "Arizona", + "city": "Bonanza" + } + }, + { + "id": 2117, + "name": "Keller Carson", + "gender": "male", + "age": 53, + "address": { + "state": "West Virginia", + "city": "Cavalero" + } + }, + { + "id": 2118, + "name": "Stephens Webb", + "gender": "male", + "age": 25, + "address": { + "state": "Mississippi", + "city": "Oasis" + } + }, + { + "id": 2119, + "name": "Simmons Hardin", + "gender": "male", + "age": 69, + "address": { + "state": "Colorado", + "city": "Trinway" + } + }, + { + "id": 2120, + "name": "Durham Barnes", + "gender": "male", + "age": 81, + "address": { + "state": "Wisconsin", + "city": "Gardners" + } + }, + { + "id": 2121, + "name": "Horn Roberson", + "gender": "male", + "age": 40, + "address": { + "state": "Virginia", + "city": "Hayes" + } + }, + { + "id": 2122, + "name": "Lawson Nunez", + "gender": "male", + "age": 27, + "address": { + "state": "Indiana", + "city": "Sultana" + } + }, + { + "id": 2123, + "name": "Bradshaw Gibson", + "gender": "male", + "age": 43, + "address": { + "state": "South Dakota", + "city": "Wildwood" + } + }, + { + "id": 2124, + "name": "Lynette Pugh", + "gender": "female", + "age": 51, + "address": { + "state": "Louisiana", + "city": "Jacumba" + } + }, + { + "id": 2125, + "name": "Bowman Cooper", + "gender": "male", + "age": 69, + "address": { + "state": "Pennsylvania", + "city": "Mahtowa" + } + }, + { + "id": 2126, + "name": "Kathy Shields", + "gender": "female", + "age": 31, + "address": { + "state": "Delaware", + "city": "Waterford" + } + }, + { + "id": 2127, + "name": "Jenny Hampton", + "gender": "female", + "age": 34, + "address": { + "state": "Massachusetts", + "city": "Guilford" + } + }, + { + "id": 2128, + "name": "Fields Schroeder", + "gender": "male", + "age": 72, + "address": { + "state": "Maine", + "city": "Clayville" + } + }, + { + "id": 2129, + "name": "Lopez Meadows", + "gender": "male", + "age": 58, + "address": { + "state": "New Jersey", + "city": "Vincent" + } + }, + { + "id": 2130, + "name": "Levine Burnett", + "gender": "male", + "age": 20, + "address": { + "state": "Nebraska", + "city": "Frierson" + } + }, + { + "id": 2131, + "name": "Hogan Garcia", + "gender": "male", + "age": 78, + "address": { + "state": "Utah", + "city": "Heil" + } + }, + { + "id": 2132, + "name": "Cole Hood", + "gender": "male", + "age": 36, + "address": { + "state": "Missouri", + "city": "Tyro" + } + }, + { + "id": 2133, + "name": "Mcgowan Cleveland", + "gender": "male", + "age": 57, + "address": { + "state": "Illinois", + "city": "Soudan" + } + }, + { + "id": 2134, + "name": "Becky Wong", + "gender": "female", + "age": 21, + "address": { + "state": "Washington", + "city": "Rosedale" + } + }, + { + "id": 2135, + "name": "Natasha Gentry", + "gender": "female", + "age": 32, + "address": { + "state": "Hawaii", + "city": "Whitmer" + } + }, + { + "id": 2136, + "name": "Sargent Collier", + "gender": "male", + "age": 62, + "address": { + "state": "Kentucky", + "city": "Klagetoh" + } + }, + { + "id": 2137, + "name": "Fleming Johnston", + "gender": "male", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Chase" + } + }, + { + "id": 2138, + "name": "Pate Stewart", + "gender": "male", + "age": 66, + "address": { + "state": "Vermont", + "city": "Elizaville" + } + }, + { + "id": 2139, + "name": "Heidi Hahn", + "gender": "female", + "age": 69, + "address": { + "state": "Maryland", + "city": "Camptown" + } + }, + { + "id": 2140, + "name": "Darcy Neal", + "gender": "female", + "age": 57, + "address": { + "state": "New Hampshire", + "city": "Canoochee" + } + }, + { + "id": 2141, + "name": "Branch Calhoun", + "gender": "male", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Sugartown" + } + }, + { + "id": 2142, + "name": "Sonja Lawson", + "gender": "female", + "age": 66, + "address": { + "state": "Alabama", + "city": "Boyd" + } + }, + { + "id": 2143, + "name": "Webster Bender", + "gender": "male", + "age": 26, + "address": { + "state": "Idaho", + "city": "Umapine" + } + }, + { + "id": 2144, + "name": "Freida Williams", + "gender": "female", + "age": 53, + "address": { + "state": "Georgia", + "city": "Keller" + } + }, + { + "id": 2145, + "name": "Cain Harrington", + "gender": "male", + "age": 71, + "address": { + "state": "Florida", + "city": "Wheatfields" + } + }, + { + "id": 2146, + "name": "Bonita Hatfield", + "gender": "female", + "age": 65, + "address": { + "state": "Nevada", + "city": "Maybell" + } + }, + { + "id": 2147, + "name": "Leigh Ford", + "gender": "female", + "age": 50, + "address": { + "state": "Oregon", + "city": "Bend" + } + }, + { + "id": 2148, + "name": "Sanchez Hendricks", + "gender": "male", + "age": 31, + "address": { + "state": "Kansas", + "city": "Gordon" + } + }, + { + "id": 2149, + "name": "Ursula Atkinson", + "gender": "female", + "age": 57, + "address": { + "state": "Alaska", + "city": "Beason" + } + }, + { + "id": 2150, + "name": "Lottie Christian", + "gender": "female", + "age": 46, + "address": { + "state": "Connecticut", + "city": "Shaft" + } + }, + { + "id": 2151, + "name": "Hatfield Cain", + "gender": "male", + "age": 79, + "address": { + "state": "New Mexico", + "city": "Iola" + } + }, + { + "id": 2152, + "name": "Delacruz Barry", + "gender": "male", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Elliott" + } + }, + { + "id": 2153, + "name": "Velez Barrett", + "gender": "male", + "age": 79, + "address": { + "state": "Michigan", + "city": "Lookingglass" + } + }, + { + "id": 2154, + "name": "Roberson Jones", + "gender": "male", + "age": 69, + "address": { + "state": "Rhode Island", + "city": "Centerville" + } + }, + { + "id": 2155, + "name": "Erickson Long", + "gender": "male", + "age": 75, + "address": { + "state": "California", + "city": "Worcester" + } + }, + { + "id": 2156, + "name": "Molina Dickson", + "gender": "male", + "age": 69, + "address": { + "state": "Minnesota", + "city": "Dyckesville" + } + }, + { + "id": 2157, + "name": "Billie Cardenas", + "gender": "female", + "age": 77, + "address": { + "state": "New Jersey", + "city": "Goodville" + } + }, + { + "id": 2158, + "name": "Patrica Smith", + "gender": "female", + "age": 50, + "address": { + "state": "Connecticut", + "city": "Rivera" + } + }, + { + "id": 2159, + "name": "Peggy Haynes", + "gender": "female", + "age": 57, + "address": { + "state": "Arkansas", + "city": "Lookingglass" + } + }, + { + "id": 2160, + "name": "Moreno Rodgers", + "gender": "male", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Day" + } + }, + { + "id": 2161, + "name": "Lottie Carroll", + "gender": "female", + "age": 80, + "address": { + "state": "Iowa", + "city": "Floriston" + } + }, + { + "id": 2162, + "name": "Tanya Cantrell", + "gender": "female", + "age": 66, + "address": { + "state": "California", + "city": "Albany" + } + }, + { + "id": 2163, + "name": "Simone Calhoun", + "gender": "female", + "age": 76, + "address": { + "state": "Utah", + "city": "Elliston" + } + }, + { + "id": 2164, + "name": "Angelia Horton", + "gender": "female", + "age": 59, + "address": { + "state": "Massachusetts", + "city": "Charco" + } + }, + { + "id": 2165, + "name": "Vilma Barnes", + "gender": "female", + "age": 82, + "address": { + "state": "New Mexico", + "city": "Trona" + } + }, + { + "id": 2166, + "name": "Kristine Cobb", + "gender": "female", + "age": 69, + "address": { + "state": "Ohio", + "city": "Ebro" + } + }, + { + "id": 2167, + "name": "Agnes Simmons", + "gender": "female", + "age": 28, + "address": { + "state": "Alaska", + "city": "Lindisfarne" + } + }, + { + "id": 2168, + "name": "Abby Baxter", + "gender": "female", + "age": 20, + "address": { + "state": "New Hampshire", + "city": "Rosewood" + } + }, + { + "id": 2169, + "name": "Barlow Benjamin", + "gender": "male", + "age": 45, + "address": { + "state": "Michigan", + "city": "Farmers" + } + }, + { + "id": 2170, + "name": "Townsend Holloway", + "gender": "male", + "age": 59, + "address": { + "state": "Illinois", + "city": "Homestead" + } + }, + { + "id": 2171, + "name": "Marie Delacruz", + "gender": "female", + "age": 76, + "address": { + "state": "Colorado", + "city": "Rosine" + } + }, + { + "id": 2172, + "name": "Bray Dillon", + "gender": "male", + "age": 54, + "address": { + "state": "South Dakota", + "city": "Summerfield" + } + }, + { + "id": 2173, + "name": "Huffman Curry", + "gender": "male", + "age": 43, + "address": { + "state": "North Carolina", + "city": "Jamestown" + } + }, + { + "id": 2174, + "name": "Foley Harrison", + "gender": "male", + "age": 79, + "address": { + "state": "Maryland", + "city": "Fairmount" + } + }, + { + "id": 2175, + "name": "Sawyer Forbes", + "gender": "male", + "age": 63, + "address": { + "state": "Wisconsin", + "city": "Durham" + } + }, + { + "id": 2176, + "name": "Dana Cummings", + "gender": "female", + "age": 50, + "address": { + "state": "Louisiana", + "city": "Deputy" + } + }, + { + "id": 2177, + "name": "Sabrina Cervantes", + "gender": "female", + "age": 18, + "address": { + "state": "Nevada", + "city": "Alderpoint" + } + }, + { + "id": 2178, + "name": "Alford Winters", + "gender": "male", + "age": 17, + "address": { + "state": "Kentucky", + "city": "Toftrees" + } + }, + { + "id": 2179, + "name": "Soto Buckley", + "gender": "male", + "age": 47, + "address": { + "state": "Vermont", + "city": "Lopezo" + } + }, + { + "id": 2180, + "name": "Holmes Wynn", + "gender": "male", + "age": 55, + "address": { + "state": "Oregon", + "city": "Vowinckel" + } + }, + { + "id": 2181, + "name": "Glass Quinn", + "gender": "male", + "age": 47, + "address": { + "state": "Hawaii", + "city": "Wanship" + } + }, + { + "id": 2182, + "name": "Bonner Nicholson", + "gender": "male", + "age": 42, + "address": { + "state": "Idaho", + "city": "Madaket" + } + }, + { + "id": 2183, + "name": "Lillie Adams", + "gender": "female", + "age": 46, + "address": { + "state": "Florida", + "city": "Highland" + } + }, + { + "id": 2184, + "name": "Lynn Dawson", + "gender": "female", + "age": 69, + "address": { + "state": "Pennsylvania", + "city": "Grill" + } + }, + { + "id": 2185, + "name": "Ramos Garrison", + "gender": "male", + "age": 38, + "address": { + "state": "Maine", + "city": "Salix" + } + }, + { + "id": 2186, + "name": "Susanne Holcomb", + "gender": "female", + "age": 47, + "address": { + "state": "Kansas", + "city": "Sims" + } + }, + { + "id": 2187, + "name": "Cain Pruitt", + "gender": "male", + "age": 22, + "address": { + "state": "Arizona", + "city": "Smock" + } + }, + { + "id": 2188, + "name": "Mcbride Harper", + "gender": "male", + "age": 41, + "address": { + "state": "Montana", + "city": "Muir" + } + }, + { + "id": 2189, + "name": "Weiss Benson", + "gender": "male", + "age": 19, + "address": { + "state": "New York", + "city": "Neibert" + } + }, + { + "id": 2190, + "name": "Estella Figueroa", + "gender": "female", + "age": 54, + "address": { + "state": "Delaware", + "city": "Aberdeen" + } + }, + { + "id": 2191, + "name": "Roxie Rosales", + "gender": "female", + "age": 25, + "address": { + "state": "Washington", + "city": "Katonah" + } + }, + { + "id": 2192, + "name": "Tracey Foreman", + "gender": "female", + "age": 27, + "address": { + "state": "West Virginia", + "city": "Montura" + } + }, + { + "id": 2193, + "name": "Sweet Noble", + "gender": "male", + "age": 29, + "address": { + "state": "Alabama", + "city": "Keller" + } + }, + { + "id": 2194, + "name": "Walter Mcclure", + "gender": "male", + "age": 77, + "address": { + "state": "Rhode Island", + "city": "Faxon" + } + }, + { + "id": 2195, + "name": "Hutchinson Rowland", + "gender": "male", + "age": 69, + "address": { + "state": "Oklahoma", + "city": "Gerton" + } + }, + { + "id": 2196, + "name": "Jaime Levine", + "gender": "female", + "age": 51, + "address": { + "state": "South Carolina", + "city": "Eagleville" + } + }, + { + "id": 2197, + "name": "Murray Porter", + "gender": "male", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Morningside" + } + }, + { + "id": 2198, + "name": "Ashley Beasley", + "gender": "male", + "age": 18, + "address": { + "state": "Nebraska", + "city": "Sugartown" + } + }, + { + "id": 2199, + "name": "Brandi Calderon", + "gender": "female", + "age": 28, + "address": { + "state": "Virginia", + "city": "Eureka" + } + }, + { + "id": 2200, + "name": "Baird Swanson", + "gender": "male", + "age": 28, + "address": { + "state": "Georgia", + "city": "Grantville" + } + }, + { + "id": 2201, + "name": "Nguyen Kirkland", + "gender": "male", + "age": 20, + "address": { + "state": "Tennessee", + "city": "Carbonville" + } + }, + { + "id": 2202, + "name": "Macias Martinez", + "gender": "male", + "age": 68, + "address": { + "state": "Missouri", + "city": "Northridge" + } + }, + { + "id": 2203, + "name": "Sophie Morales", + "gender": "female", + "age": 62, + "address": { + "state": "Texas", + "city": "Vale" + } + }, + { + "id": 2204, + "name": "Augusta Haley", + "gender": "female", + "age": 53, + "address": { + "state": "Indiana", + "city": "Wiscon" + } + }, + { + "id": 2205, + "name": "Buchanan Wolfe", + "gender": "male", + "age": 48, + "address": { + "state": "North Carolina", + "city": "Draper" + } + }, + { + "id": 2206, + "name": "Bass Graham", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Blairstown" + } + }, + { + "id": 2207, + "name": "Lawrence Webb", + "gender": "male", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Morriston" + } + }, + { + "id": 2208, + "name": "Earline Guy", + "gender": "female", + "age": 76, + "address": { + "state": "Wisconsin", + "city": "Siglerville" + } + }, + { + "id": 2209, + "name": "Ray Barrett", + "gender": "male", + "age": 79, + "address": { + "state": "Michigan", + "city": "Choctaw" + } + }, + { + "id": 2210, + "name": "Watson Odom", + "gender": "male", + "age": 31, + "address": { + "state": "Delaware", + "city": "Harviell" + } + }, + { + "id": 2211, + "name": "Eileen Stephenson", + "gender": "female", + "age": 60, + "address": { + "state": "Louisiana", + "city": "Tetherow" + } + }, + { + "id": 2212, + "name": "Jacqueline Weaver", + "gender": "female", + "age": 70, + "address": { + "state": "Texas", + "city": "Hardyville" + } + }, + { + "id": 2213, + "name": "Jenkins Sweeney", + "gender": "male", + "age": 33, + "address": { + "state": "Kentucky", + "city": "Greenwich" + } + }, + { + "id": 2214, + "name": "Stokes Petty", + "gender": "male", + "age": 70, + "address": { + "state": "Illinois", + "city": "Brookfield" + } + }, + { + "id": 2215, + "name": "Queen Randall", + "gender": "female", + "age": 30, + "address": { + "state": "Hawaii", + "city": "Ezel" + } + }, + { + "id": 2216, + "name": "Ward Gregory", + "gender": "male", + "age": 43, + "address": { + "state": "New York", + "city": "Idamay" + } + }, + { + "id": 2217, + "name": "Luisa Rosario", + "gender": "female", + "age": 30, + "address": { + "state": "Maine", + "city": "Dotsero" + } + }, + { + "id": 2218, + "name": "Loraine Melendez", + "gender": "female", + "age": 50, + "address": { + "state": "Pennsylvania", + "city": "Chesterfield" + } + }, + { + "id": 2219, + "name": "Pace Clements", + "gender": "male", + "age": 67, + "address": { + "state": "South Dakota", + "city": "Imperial" + } + }, + { + "id": 2220, + "name": "Amanda Erickson", + "gender": "female", + "age": 78, + "address": { + "state": "Washington", + "city": "Ola" + } + }, + { + "id": 2221, + "name": "Fannie Sexton", + "gender": "female", + "age": 52, + "address": { + "state": "Alabama", + "city": "Glendale" + } + }, + { + "id": 2222, + "name": "Glenn Noble", + "gender": "male", + "age": 41, + "address": { + "state": "Utah", + "city": "Delco" + } + }, + { + "id": 2223, + "name": "Marcy Jensen", + "gender": "female", + "age": 61, + "address": { + "state": "Tennessee", + "city": "Lowgap" + } + }, + { + "id": 2224, + "name": "Gladys Wiggins", + "gender": "female", + "age": 68, + "address": { + "state": "Minnesota", + "city": "Hillsboro" + } + }, + { + "id": 2225, + "name": "Amalia Thornton", + "gender": "female", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Ladera" + } + }, + { + "id": 2226, + "name": "Ila Mckinney", + "gender": "female", + "age": 32, + "address": { + "state": "Virginia", + "city": "Staples" + } + }, + { + "id": 2227, + "name": "Mcclain Mcfadden", + "gender": "male", + "age": 54, + "address": { + "state": "Indiana", + "city": "Escondida" + } + }, + { + "id": 2228, + "name": "Woodward Levine", + "gender": "male", + "age": 40, + "address": { + "state": "North Dakota", + "city": "Needmore" + } + }, + { + "id": 2229, + "name": "Dickson Fox", + "gender": "male", + "age": 36, + "address": { + "state": "Colorado", + "city": "Vienna" + } + }, + { + "id": 2230, + "name": "Wendi Blackburn", + "gender": "female", + "age": 36, + "address": { + "state": "Wyoming", + "city": "Evergreen" + } + }, + { + "id": 2231, + "name": "Vera Lopez", + "gender": "female", + "age": 40, + "address": { + "state": "New Jersey", + "city": "Clara" + } + }, + { + "id": 2232, + "name": "Therese Walsh", + "gender": "female", + "age": 21, + "address": { + "state": "Connecticut", + "city": "Henrietta" + } + }, + { + "id": 2233, + "name": "Hilda Russo", + "gender": "female", + "age": 42, + "address": { + "state": "Vermont", + "city": "Wheaton" + } + }, + { + "id": 2234, + "name": "Elena Norman", + "gender": "female", + "age": 41, + "address": { + "state": "California", + "city": "Spokane" + } + }, + { + "id": 2235, + "name": "Neva Mack", + "gender": "female", + "age": 71, + "address": { + "state": "Arkansas", + "city": "Dennard" + } + }, + { + "id": 2236, + "name": "Singleton Manning", + "gender": "male", + "age": 29, + "address": { + "state": "Idaho", + "city": "Elrama" + } + }, + { + "id": 2237, + "name": "Cheryl Whitehead", + "gender": "female", + "age": 17, + "address": { + "state": "Kansas", + "city": "Jennings" + } + }, + { + "id": 2238, + "name": "Kemp Mckay", + "gender": "male", + "age": 51, + "address": { + "state": "Alaska", + "city": "Campo" + } + }, + { + "id": 2239, + "name": "Fran Jarvis", + "gender": "female", + "age": 37, + "address": { + "state": "South Carolina", + "city": "Crayne" + } + }, + { + "id": 2240, + "name": "Buchanan Boyd", + "gender": "male", + "age": 21, + "address": { + "state": "Nevada", + "city": "Hiwasse" + } + }, + { + "id": 2241, + "name": "Jamie England", + "gender": "female", + "age": 48, + "address": { + "state": "Maryland", + "city": "Marshall" + } + }, + { + "id": 2242, + "name": "Hudson Hughes", + "gender": "male", + "age": 81, + "address": { + "state": "Montana", + "city": "Bagtown" + } + }, + { + "id": 2243, + "name": "Kris Barron", + "gender": "female", + "age": 42, + "address": { + "state": "Oregon", + "city": "Saranap" + } + }, + { + "id": 2244, + "name": "Gallegos Mcdowell", + "gender": "male", + "age": 51, + "address": { + "state": "Georgia", + "city": "Nicholson" + } + }, + { + "id": 2245, + "name": "Rochelle Travis", + "gender": "female", + "age": 30, + "address": { + "state": "Arizona", + "city": "Gardiner" + } + }, + { + "id": 2246, + "name": "Brewer Koch", + "gender": "male", + "age": 51, + "address": { + "state": "Iowa", + "city": "Dale" + } + }, + { + "id": 2247, + "name": "Eve Nicholson", + "gender": "female", + "age": 80, + "address": { + "state": "Massachusetts", + "city": "Magnolia" + } + }, + { + "id": 2248, + "name": "Valenzuela Underwood", + "gender": "male", + "age": 22, + "address": { + "state": "Oklahoma", + "city": "Homeworth" + } + }, + { + "id": 2249, + "name": "Gwen Bird", + "gender": "female", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Wescosville" + } + }, + { + "id": 2250, + "name": "Shaw Simpson", + "gender": "male", + "age": 82, + "address": { + "state": "New Hampshire", + "city": "Vallonia" + } + }, + { + "id": 2251, + "name": "William King", + "gender": "male", + "age": 53, + "address": { + "state": "Ohio", + "city": "Santel" + } + }, + { + "id": 2252, + "name": "Nolan Hernandez", + "gender": "male", + "age": 78, + "address": { + "state": "Missouri", + "city": "Shindler" + } + }, + { + "id": 2253, + "name": "Aurora Gross", + "gender": "female", + "age": 78, + "address": { + "state": "Rhode Island", + "city": "Mathews" + } + }, + { + "id": 2254, + "name": "Duncan Singleton", + "gender": "male", + "age": 23, + "address": { + "state": "Alaska", + "city": "Layhill" + } + }, + { + "id": 2255, + "name": "Rollins Gonzales", + "gender": "male", + "age": 68, + "address": { + "state": "Georgia", + "city": "Dorneyville" + } + }, + { + "id": 2256, + "name": "Drake Russell", + "gender": "male", + "age": 71, + "address": { + "state": "Rhode Island", + "city": "Homeworth" + } + }, + { + "id": 2257, + "name": "Lucinda Alston", + "gender": "female", + "age": 20, + "address": { + "state": "Kentucky", + "city": "Chamberino" + } + }, + { + "id": 2258, + "name": "Trevino Ward", + "gender": "male", + "age": 70, + "address": { + "state": "Connecticut", + "city": "Summerset" + } + }, + { + "id": 2259, + "name": "Duffy Dean", + "gender": "male", + "age": 25, + "address": { + "state": "Colorado", + "city": "Bison" + } + }, + { + "id": 2260, + "name": "Salazar Burks", + "gender": "male", + "age": 43, + "address": { + "state": "California", + "city": "Blairstown" + } + }, + { + "id": 2261, + "name": "Mckenzie Harrell", + "gender": "male", + "age": 23, + "address": { + "state": "Tennessee", + "city": "Graniteville" + } + }, + { + "id": 2262, + "name": "Cash Garrett", + "gender": "male", + "age": 26, + "address": { + "state": "New York", + "city": "Garfield" + } + }, + { + "id": 2263, + "name": "Montoya Nguyen", + "gender": "male", + "age": 32, + "address": { + "state": "Missouri", + "city": "Stewartville" + } + }, + { + "id": 2264, + "name": "Sophia Sexton", + "gender": "female", + "age": 52, + "address": { + "state": "Wisconsin", + "city": "Falmouth" + } + }, + { + "id": 2265, + "name": "Josephine Mercer", + "gender": "female", + "age": 49, + "address": { + "state": "Arkansas", + "city": "Bakersville" + } + }, + { + "id": 2266, + "name": "Nina Sullivan", + "gender": "female", + "age": 63, + "address": { + "state": "New Jersey", + "city": "Manitou" + } + }, + { + "id": 2267, + "name": "Orr Robinson", + "gender": "male", + "age": 73, + "address": { + "state": "Oregon", + "city": "Blende" + } + }, + { + "id": 2268, + "name": "Cristina Hernandez", + "gender": "female", + "age": 22, + "address": { + "state": "Alabama", + "city": "Glendale" + } + }, + { + "id": 2269, + "name": "Madge Foley", + "gender": "female", + "age": 51, + "address": { + "state": "New Mexico", + "city": "Williston" + } + }, + { + "id": 2270, + "name": "Roberson Owen", + "gender": "male", + "age": 34, + "address": { + "state": "Maryland", + "city": "Delshire" + } + }, + { + "id": 2271, + "name": "Savage Ferguson", + "gender": "male", + "age": 26, + "address": { + "state": "Mississippi", + "city": "Darrtown" + } + }, + { + "id": 2272, + "name": "Juliana Stout", + "gender": "female", + "age": 45, + "address": { + "state": "North Carolina", + "city": "Soudan" + } + }, + { + "id": 2273, + "name": "Tamra Alexander", + "gender": "female", + "age": 57, + "address": { + "state": "Michigan", + "city": "Caspar" + } + }, + { + "id": 2274, + "name": "Polly Abbott", + "gender": "female", + "age": 66, + "address": { + "state": "Montana", + "city": "Hegins" + } + }, + { + "id": 2275, + "name": "Antonia Rhodes", + "gender": "female", + "age": 69, + "address": { + "state": "Nevada", + "city": "Lookingglass" + } + }, + { + "id": 2276, + "name": "Tia Alvarez", + "gender": "female", + "age": 46, + "address": { + "state": "Wyoming", + "city": "Sunriver" + } + }, + { + "id": 2277, + "name": "Marta Wilkins", + "gender": "female", + "age": 26, + "address": { + "state": "West Virginia", + "city": "Barstow" + } + }, + { + "id": 2278, + "name": "Katheryn Kim", + "gender": "female", + "age": 38, + "address": { + "state": "Massachusetts", + "city": "Rivereno" + } + }, + { + "id": 2279, + "name": "Chambers Garrison", + "gender": "male", + "age": 65, + "address": { + "state": "North Dakota", + "city": "Valmy" + } + }, + { + "id": 2280, + "name": "Poole Mcgowan", + "gender": "male", + "age": 31, + "address": { + "state": "Washington", + "city": "Fannett" + } + }, + { + "id": 2281, + "name": "Belinda Pratt", + "gender": "female", + "age": 35, + "address": { + "state": "Utah", + "city": "Bynum" + } + }, + { + "id": 2282, + "name": "Schneider Graves", + "gender": "male", + "age": 70, + "address": { + "state": "Hawaii", + "city": "Chestnut" + } + }, + { + "id": 2283, + "name": "Bonita Crawford", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Omar" + } + }, + { + "id": 2284, + "name": "Cochran Rollins", + "gender": "male", + "age": 81, + "address": { + "state": "Pennsylvania", + "city": "Bodega" + } + }, + { + "id": 2285, + "name": "Collier Maynard", + "gender": "male", + "age": 23, + "address": { + "state": "Texas", + "city": "Singer" + } + }, + { + "id": 2286, + "name": "Espinoza Newman", + "gender": "male", + "age": 80, + "address": { + "state": "Vermont", + "city": "Rockingham" + } + }, + { + "id": 2287, + "name": "Petty Pearson", + "gender": "male", + "age": 81, + "address": { + "state": "New Hampshire", + "city": "Toftrees" + } + }, + { + "id": 2288, + "name": "Suzette Workman", + "gender": "female", + "age": 77, + "address": { + "state": "Delaware", + "city": "Chalfant" + } + }, + { + "id": 2289, + "name": "Logan Hampton", + "gender": "male", + "age": 35, + "address": { + "state": "Kansas", + "city": "Bentonville" + } + }, + { + "id": 2290, + "name": "Carla Kelly", + "gender": "female", + "age": 75, + "address": { + "state": "Florida", + "city": "Hall" + } + }, + { + "id": 2291, + "name": "Nadia Tanner", + "gender": "female", + "age": 72, + "address": { + "state": "Illinois", + "city": "Marshall" + } + }, + { + "id": 2292, + "name": "Marci Sandoval", + "gender": "female", + "age": 59, + "address": { + "state": "Louisiana", + "city": "Matheny" + } + }, + { + "id": 2293, + "name": "Marietta Herman", + "gender": "female", + "age": 56, + "address": { + "state": "Iowa", + "city": "Whitehaven" + } + }, + { + "id": 2294, + "name": "Lawanda Bauer", + "gender": "female", + "age": 45, + "address": { + "state": "Arizona", + "city": "Hobucken" + } + }, + { + "id": 2295, + "name": "Marylou Phelps", + "gender": "female", + "age": 34, + "address": { + "state": "Nebraska", + "city": "Saranap" + } + }, + { + "id": 2296, + "name": "Nancy Hamilton", + "gender": "female", + "age": 42, + "address": { + "state": "Minnesota", + "city": "Topaz" + } + }, + { + "id": 2297, + "name": "Lizzie Callahan", + "gender": "female", + "age": 20, + "address": { + "state": "Ohio", + "city": "Sparkill" + } + }, + { + "id": 2298, + "name": "Callie Bond", + "gender": "female", + "age": 74, + "address": { + "state": "Idaho", + "city": "Winfred" + } + }, + { + "id": 2299, + "name": "Bush Spears", + "gender": "male", + "age": 23, + "address": { + "state": "Indiana", + "city": "Marenisco" + } + }, + { + "id": 2300, + "name": "Zelma Maldonado", + "gender": "female", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Babb" + } + }, + { + "id": 2301, + "name": "Marie Cleveland", + "gender": "female", + "age": 59, + "address": { + "state": "Maine", + "city": "Drytown" + } + }, + { + "id": 2302, + "name": "Lina Santana", + "gender": "female", + "age": 70, + "address": { + "state": "Virginia", + "city": "Thynedale" + } + }, + { + "id": 2303, + "name": "Barnes Fischer", + "gender": "male", + "age": 19, + "address": { + "state": "New Jersey", + "city": "Convent" + } + }, + { + "id": 2304, + "name": "Ethel Sears", + "gender": "female", + "age": 25, + "address": { + "state": "Kentucky", + "city": "Yettem" + } + }, + { + "id": 2305, + "name": "Dawson West", + "gender": "male", + "age": 63, + "address": { + "state": "Arkansas", + "city": "Muir" + } + }, + { + "id": 2306, + "name": "Katina Nguyen", + "gender": "female", + "age": 80, + "address": { + "state": "Virginia", + "city": "Kempton" + } + }, + { + "id": 2307, + "name": "Benjamin Coffey", + "gender": "male", + "age": 18, + "address": { + "state": "Tennessee", + "city": "Malott" + } + }, + { + "id": 2308, + "name": "Roberta Boyle", + "gender": "female", + "age": 56, + "address": { + "state": "Georgia", + "city": "Nadine" + } + }, + { + "id": 2309, + "name": "Hester Case", + "gender": "female", + "age": 41, + "address": { + "state": "Maine", + "city": "Belva" + } + }, + { + "id": 2310, + "name": "Stacy Gaines", + "gender": "female", + "age": 57, + "address": { + "state": "Wisconsin", + "city": "Dotsero" + } + }, + { + "id": 2311, + "name": "Bailey English", + "gender": "male", + "age": 24, + "address": { + "state": "South Dakota", + "city": "Coalmont" + } + }, + { + "id": 2312, + "name": "Dawn Murphy", + "gender": "female", + "age": 49, + "address": { + "state": "Alabama", + "city": "Avoca" + } + }, + { + "id": 2313, + "name": "Harriett Hinton", + "gender": "female", + "age": 65, + "address": { + "state": "Montana", + "city": "Brady" + } + }, + { + "id": 2314, + "name": "Suzette Mercer", + "gender": "female", + "age": 18, + "address": { + "state": "Connecticut", + "city": "Lydia" + } + }, + { + "id": 2315, + "name": "Christa Stevens", + "gender": "female", + "age": 44, + "address": { + "state": "Florida", + "city": "Kraemer" + } + }, + { + "id": 2316, + "name": "Diaz Bonner", + "gender": "male", + "age": 50, + "address": { + "state": "Washington", + "city": "Geyserville" + } + }, + { + "id": 2317, + "name": "Mcpherson Keller", + "gender": "male", + "age": 26, + "address": { + "state": "Rhode Island", + "city": "Alafaya" + } + }, + { + "id": 2318, + "name": "Isabel Dodson", + "gender": "female", + "age": 41, + "address": { + "state": "Massachusetts", + "city": "Wolcott" + } + }, + { + "id": 2319, + "name": "Keith Kerr", + "gender": "male", + "age": 75, + "address": { + "state": "Louisiana", + "city": "Thatcher" + } + }, + { + "id": 2320, + "name": "Jefferson Jones", + "gender": "male", + "age": 26, + "address": { + "state": "Pennsylvania", + "city": "Lloyd" + } + }, + { + "id": 2321, + "name": "Tucker Winters", + "gender": "male", + "age": 38, + "address": { + "state": "Oregon", + "city": "Osmond" + } + }, + { + "id": 2322, + "name": "Della Cannon", + "gender": "female", + "age": 27, + "address": { + "state": "Minnesota", + "city": "Iola" + } + }, + { + "id": 2323, + "name": "Ayers Acevedo", + "gender": "male", + "age": 24, + "address": { + "state": "Kansas", + "city": "Shelby" + } + }, + { + "id": 2324, + "name": "Wells Webster", + "gender": "male", + "age": 71, + "address": { + "state": "Vermont", + "city": "Flintville" + } + }, + { + "id": 2325, + "name": "Whitley Cruz", + "gender": "male", + "age": 70, + "address": { + "state": "South Carolina", + "city": "Gwynn" + } + }, + { + "id": 2326, + "name": "Lynne Fuentes", + "gender": "female", + "age": 42, + "address": { + "state": "Arizona", + "city": "Vernon" + } + }, + { + "id": 2327, + "name": "Morin May", + "gender": "male", + "age": 34, + "address": { + "state": "Idaho", + "city": "Morningside" + } + }, + { + "id": 2328, + "name": "Kristie Ramos", + "gender": "female", + "age": 27, + "address": { + "state": "Michigan", + "city": "Chloride" + } + }, + { + "id": 2329, + "name": "Eva Brennan", + "gender": "female", + "age": 70, + "address": { + "state": "Maryland", + "city": "Witmer" + } + }, + { + "id": 2330, + "name": "Griffin Silva", + "gender": "male", + "age": 81, + "address": { + "state": "Delaware", + "city": "Bayview" + } + }, + { + "id": 2331, + "name": "Alisha Mcguire", + "gender": "female", + "age": 45, + "address": { + "state": "New Mexico", + "city": "Makena" + } + }, + { + "id": 2332, + "name": "Marisol Vargas", + "gender": "female", + "age": 54, + "address": { + "state": "Wyoming", + "city": "Nelson" + } + }, + { + "id": 2333, + "name": "Randall Pruitt", + "gender": "male", + "age": 53, + "address": { + "state": "Missouri", + "city": "Loretto" + } + }, + { + "id": 2334, + "name": "Good Gallagher", + "gender": "male", + "age": 28, + "address": { + "state": "Texas", + "city": "Echo" + } + }, + { + "id": 2335, + "name": "Jacobs Peters", + "gender": "male", + "age": 82, + "address": { + "state": "New York", + "city": "Edenburg" + } + }, + { + "id": 2336, + "name": "Bridges Huber", + "gender": "male", + "age": 23, + "address": { + "state": "Mississippi", + "city": "Caledonia" + } + }, + { + "id": 2337, + "name": "Nolan Lester", + "gender": "male", + "age": 46, + "address": { + "state": "Indiana", + "city": "Jackpot" + } + }, + { + "id": 2338, + "name": "Ochoa Mcconnell", + "gender": "male", + "age": 82, + "address": { + "state": "California", + "city": "Morriston" + } + }, + { + "id": 2339, + "name": "Matthews Barron", + "gender": "male", + "age": 24, + "address": { + "state": "Utah", + "city": "Gadsden" + } + }, + { + "id": 2340, + "name": "Tamika Crane", + "gender": "female", + "age": 70, + "address": { + "state": "Iowa", + "city": "Wilmington" + } + }, + { + "id": 2341, + "name": "Fannie Moody", + "gender": "female", + "age": 21, + "address": { + "state": "North Dakota", + "city": "Camino" + } + }, + { + "id": 2342, + "name": "Tommie Barnes", + "gender": "female", + "age": 45, + "address": { + "state": "Hawaii", + "city": "Maury" + } + }, + { + "id": 2343, + "name": "Jaime Ball", + "gender": "female", + "age": 74, + "address": { + "state": "North Carolina", + "city": "Urie" + } + }, + { + "id": 2344, + "name": "Mullins Carroll", + "gender": "male", + "age": 24, + "address": { + "state": "New Hampshire", + "city": "Warsaw" + } + }, + { + "id": 2345, + "name": "Aimee Rosario", + "gender": "female", + "age": 19, + "address": { + "state": "Nebraska", + "city": "Zarephath" + } + }, + { + "id": 2346, + "name": "Peterson Robbins", + "gender": "male", + "age": 61, + "address": { + "state": "West Virginia", + "city": "Grayhawk" + } + }, + { + "id": 2347, + "name": "Lina Koch", + "gender": "female", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Finzel" + } + }, + { + "id": 2348, + "name": "Hutchinson Oneill", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Groton" + } + }, + { + "id": 2349, + "name": "Ward Hopkins", + "gender": "male", + "age": 73, + "address": { + "state": "Ohio", + "city": "Freeburn" + } + }, + { + "id": 2350, + "name": "Albert Contreras", + "gender": "male", + "age": 31, + "address": { + "state": "Nevada", + "city": "Orovada" + } + }, + { + "id": 2351, + "name": "Schneider Holt", + "gender": "male", + "age": 38, + "address": { + "state": "Colorado", + "city": "Chelsea" + } + }, + { + "id": 2352, + "name": "Jackson Kane", + "gender": "male", + "age": 46, + "address": { + "state": "Ohio", + "city": "Devon" + } + }, + { + "id": 2353, + "name": "Fran Mcmillan", + "gender": "female", + "age": 59, + "address": { + "state": "Maine", + "city": "Garfield" + } + }, + { + "id": 2354, + "name": "Vargas Keller", + "gender": "male", + "age": 44, + "address": { + "state": "Texas", + "city": "Draper" + } + }, + { + "id": 2355, + "name": "Darla Barlow", + "gender": "female", + "age": 18, + "address": { + "state": "California", + "city": "Elliott" + } + }, + { + "id": 2356, + "name": "Jody Coffey", + "gender": "female", + "age": 65, + "address": { + "state": "Minnesota", + "city": "Detroit" + } + }, + { + "id": 2357, + "name": "Fuller Boone", + "gender": "male", + "age": 82, + "address": { + "state": "Washington", + "city": "Esmont" + } + }, + { + "id": 2358, + "name": "Lavonne Emerson", + "gender": "female", + "age": 49, + "address": { + "state": "Oregon", + "city": "Taft" + } + }, + { + "id": 2359, + "name": "Sellers Calderon", + "gender": "male", + "age": 54, + "address": { + "state": "Pennsylvania", + "city": "Delwood" + } + }, + { + "id": 2360, + "name": "Mason Duncan", + "gender": "male", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Nicut" + } + }, + { + "id": 2361, + "name": "Haney Cobb", + "gender": "male", + "age": 30, + "address": { + "state": "Wyoming", + "city": "Toftrees" + } + }, + { + "id": 2362, + "name": "Penelope Stafford", + "gender": "female", + "age": 31, + "address": { + "state": "Alaska", + "city": "Rosburg" + } + }, + { + "id": 2363, + "name": "Bridgette Lyons", + "gender": "female", + "age": 64, + "address": { + "state": "Nevada", + "city": "Johnsonburg" + } + }, + { + "id": 2364, + "name": "Joseph Odonnell", + "gender": "male", + "age": 21, + "address": { + "state": "West Virginia", + "city": "Cressey" + } + }, + { + "id": 2365, + "name": "Marquez Holt", + "gender": "male", + "age": 48, + "address": { + "state": "Alabama", + "city": "Maxville" + } + }, + { + "id": 2366, + "name": "Stacey Pearson", + "gender": "female", + "age": 26, + "address": { + "state": "Mississippi", + "city": "Chase" + } + }, + { + "id": 2367, + "name": "Holden Collier", + "gender": "male", + "age": 31, + "address": { + "state": "Hawaii", + "city": "Strong" + } + }, + { + "id": 2368, + "name": "Eddie Salas", + "gender": "female", + "age": 47, + "address": { + "state": "Connecticut", + "city": "Lacomb" + } + }, + { + "id": 2369, + "name": "Caldwell Vasquez", + "gender": "male", + "age": 51, + "address": { + "state": "Tennessee", + "city": "Oley" + } + }, + { + "id": 2370, + "name": "Ward Mack", + "gender": "male", + "age": 28, + "address": { + "state": "Iowa", + "city": "Trinway" + } + }, + { + "id": 2371, + "name": "Vinson Boyer", + "gender": "male", + "age": 66, + "address": { + "state": "Virginia", + "city": "Bannock" + } + }, + { + "id": 2372, + "name": "Mindy Guthrie", + "gender": "female", + "age": 47, + "address": { + "state": "Missouri", + "city": "Goochland" + } + }, + { + "id": 2373, + "name": "Meadows Dodson", + "gender": "male", + "age": 28, + "address": { + "state": "Colorado", + "city": "Brethren" + } + }, + { + "id": 2374, + "name": "Suarez Johnston", + "gender": "male", + "age": 70, + "address": { + "state": "New Hampshire", + "city": "Caroline" + } + }, + { + "id": 2375, + "name": "Potts Snider", + "gender": "male", + "age": 49, + "address": { + "state": "Florida", + "city": "Tioga" + } + }, + { + "id": 2376, + "name": "Lorrie Finley", + "gender": "female", + "age": 22, + "address": { + "state": "Montana", + "city": "Finderne" + } + }, + { + "id": 2377, + "name": "April Blackburn", + "gender": "female", + "age": 72, + "address": { + "state": "Louisiana", + "city": "Emison" + } + }, + { + "id": 2378, + "name": "Douglas Cash", + "gender": "male", + "age": 73, + "address": { + "state": "Delaware", + "city": "Eastmont" + } + }, + { + "id": 2379, + "name": "Franks Fuentes", + "gender": "male", + "age": 81, + "address": { + "state": "Maryland", + "city": "Leeper" + } + }, + { + "id": 2380, + "name": "Schroeder Michael", + "gender": "male", + "age": 57, + "address": { + "state": "New York", + "city": "Tilden" + } + }, + { + "id": 2381, + "name": "Sosa Welch", + "gender": "male", + "age": 49, + "address": { + "state": "New Jersey", + "city": "Kieler" + } + }, + { + "id": 2382, + "name": "Baldwin Solis", + "gender": "male", + "age": 62, + "address": { + "state": "Illinois", + "city": "Tyhee" + } + }, + { + "id": 2383, + "name": "Rodriquez Doyle", + "gender": "male", + "age": 59, + "address": { + "state": "Michigan", + "city": "Ruffin" + } + }, + { + "id": 2384, + "name": "Amelia Keith", + "gender": "female", + "age": 66, + "address": { + "state": "Rhode Island", + "city": "Catherine" + } + }, + { + "id": 2385, + "name": "Geraldine Graves", + "gender": "female", + "age": 20, + "address": { + "state": "Utah", + "city": "Greenfields" + } + }, + { + "id": 2386, + "name": "Randall Pratt", + "gender": "male", + "age": 37, + "address": { + "state": "Oklahoma", + "city": "Winesburg" + } + }, + { + "id": 2387, + "name": "Concepcion Guerra", + "gender": "female", + "age": 18, + "address": { + "state": "New Mexico", + "city": "Gordon" + } + }, + { + "id": 2388, + "name": "Lewis Romero", + "gender": "male", + "age": 39, + "address": { + "state": "Arkansas", + "city": "Ada" + } + }, + { + "id": 2389, + "name": "Blake Cooley", + "gender": "male", + "age": 68, + "address": { + "state": "Idaho", + "city": "Osmond" + } + }, + { + "id": 2390, + "name": "Kristy Perez", + "gender": "female", + "age": 76, + "address": { + "state": "Nebraska", + "city": "Blairstown" + } + }, + { + "id": 2391, + "name": "Enid Ramirez", + "gender": "female", + "age": 31, + "address": { + "state": "Arizona", + "city": "Bonanza" + } + }, + { + "id": 2392, + "name": "Tanisha Peterson", + "gender": "female", + "age": 23, + "address": { + "state": "Georgia", + "city": "Westboro" + } + }, + { + "id": 2393, + "name": "Blair Padilla", + "gender": "male", + "age": 74, + "address": { + "state": "Vermont", + "city": "Madrid" + } + }, + { + "id": 2394, + "name": "Nellie Daugherty", + "gender": "female", + "age": 32, + "address": { + "state": "North Dakota", + "city": "Dexter" + } + }, + { + "id": 2395, + "name": "Simone Salazar", + "gender": "female", + "age": 67, + "address": { + "state": "Kansas", + "city": "Bynum" + } + }, + { + "id": 2396, + "name": "Payne Ramos", + "gender": "male", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Nicholson" + } + }, + { + "id": 2397, + "name": "Sheri Roy", + "gender": "female", + "age": 73, + "address": { + "state": "Kentucky", + "city": "Cumminsville" + } + }, + { + "id": 2398, + "name": "Leticia Cortez", + "gender": "female", + "age": 50, + "address": { + "state": "South Dakota", + "city": "Geyserville" + } + }, + { + "id": 2399, + "name": "Finch Gregory", + "gender": "male", + "age": 24, + "address": { + "state": "Massachusetts", + "city": "Stockwell" + } + }, + { + "id": 2400, + "name": "Trujillo Harvey", + "gender": "male", + "age": 32, + "address": { + "state": "Indiana", + "city": "Slovan" + } + }, + { + "id": 2401, + "name": "Yvonne Lamb", + "gender": "female", + "age": 58, + "address": { + "state": "Texas", + "city": "Fulford" + } + }, + { + "id": 2402, + "name": "Kelli Mcdonald", + "gender": "female", + "age": 18, + "address": { + "state": "Wisconsin", + "city": "Vernon" + } + }, + { + "id": 2403, + "name": "Carey Young", + "gender": "female", + "age": 41, + "address": { + "state": "Mississippi", + "city": "Topaz" + } + }, + { + "id": 2404, + "name": "Oneill Mcclain", + "gender": "male", + "age": 25, + "address": { + "state": "Oklahoma", + "city": "Watrous" + } + }, + { + "id": 2405, + "name": "Dale Merrill", + "gender": "male", + "age": 66, + "address": { + "state": "Ohio", + "city": "Strykersville" + } + }, + { + "id": 2406, + "name": "Amalia Rosa", + "gender": "female", + "age": 18, + "address": { + "state": "Delaware", + "city": "Bradenville" + } + }, + { + "id": 2407, + "name": "Ellison Stout", + "gender": "male", + "age": 81, + "address": { + "state": "New Hampshire", + "city": "Orin" + } + }, + { + "id": 2408, + "name": "Burke Monroe", + "gender": "male", + "age": 69, + "address": { + "state": "Arizona", + "city": "Rockbridge" + } + }, + { + "id": 2409, + "name": "Mccoy Carver", + "gender": "male", + "age": 42, + "address": { + "state": "West Virginia", + "city": "Waterford" + } + }, + { + "id": 2410, + "name": "Britt Hoffman", + "gender": "male", + "age": 68, + "address": { + "state": "New York", + "city": "Gardners" + } + }, + { + "id": 2411, + "name": "Padilla Manning", + "gender": "male", + "age": 76, + "address": { + "state": "Kentucky", + "city": "Coinjock" + } + }, + { + "id": 2412, + "name": "Heath Green", + "gender": "male", + "age": 52, + "address": { + "state": "Rhode Island", + "city": "Roland" + } + }, + { + "id": 2413, + "name": "Carrie Martin", + "gender": "female", + "age": 39, + "address": { + "state": "California", + "city": "Darbydale" + } + }, + { + "id": 2414, + "name": "Aguilar Branch", + "gender": "male", + "age": 48, + "address": { + "state": "Georgia", + "city": "Newry" + } + }, + { + "id": 2415, + "name": "Kirkland Hurst", + "gender": "male", + "age": 52, + "address": { + "state": "Montana", + "city": "Yogaville" + } + }, + { + "id": 2416, + "name": "Levine Brown", + "gender": "male", + "age": 63, + "address": { + "state": "Illinois", + "city": "Lodoga" + } + }, + { + "id": 2417, + "name": "Rhonda Watts", + "gender": "female", + "age": 48, + "address": { + "state": "Minnesota", + "city": "Sunwest" + } + }, + { + "id": 2418, + "name": "Bertie Jones", + "gender": "female", + "age": 22, + "address": { + "state": "North Dakota", + "city": "Lopezo" + } + }, + { + "id": 2419, + "name": "Loraine Hester", + "gender": "female", + "age": 37, + "address": { + "state": "Nevada", + "city": "Verdi" + } + }, + { + "id": 2420, + "name": "England Odom", + "gender": "male", + "age": 26, + "address": { + "state": "Alaska", + "city": "Rockhill" + } + }, + { + "id": 2421, + "name": "Concepcion Wolf", + "gender": "female", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Hilltop" + } + }, + { + "id": 2422, + "name": "Richard Ingram", + "gender": "male", + "age": 47, + "address": { + "state": "Florida", + "city": "Frystown" + } + }, + { + "id": 2423, + "name": "Stone Gonzales", + "gender": "male", + "age": 28, + "address": { + "state": "Massachusetts", + "city": "Diaperville" + } + }, + { + "id": 2424, + "name": "Stanton Cobb", + "gender": "male", + "age": 52, + "address": { + "state": "New Jersey", + "city": "Shelby" + } + }, + { + "id": 2425, + "name": "Morin Brock", + "gender": "male", + "age": 49, + "address": { + "state": "Connecticut", + "city": "Websterville" + } + }, + { + "id": 2426, + "name": "Cunningham Alvarez", + "gender": "male", + "age": 40, + "address": { + "state": "Oregon", + "city": "Lupton" + } + }, + { + "id": 2427, + "name": "Watts Gibson", + "gender": "male", + "age": 46, + "address": { + "state": "Wyoming", + "city": "Lawrence" + } + }, + { + "id": 2428, + "name": "Rosario Rose", + "gender": "male", + "age": 18, + "address": { + "state": "Nebraska", + "city": "Stewartville" + } + }, + { + "id": 2429, + "name": "Isabelle Pollard", + "gender": "female", + "age": 73, + "address": { + "state": "Virginia", + "city": "Sheatown" + } + }, + { + "id": 2430, + "name": "Debora Saunders", + "gender": "female", + "age": 68, + "address": { + "state": "North Carolina", + "city": "Cobbtown" + } + }, + { + "id": 2431, + "name": "Frank Riddle", + "gender": "male", + "age": 17, + "address": { + "state": "Idaho", + "city": "Kersey" + } + }, + { + "id": 2432, + "name": "Mcknight Knight", + "gender": "male", + "age": 43, + "address": { + "state": "Vermont", + "city": "Cresaptown" + } + }, + { + "id": 2433, + "name": "Letha Burt", + "gender": "female", + "age": 37, + "address": { + "state": "Louisiana", + "city": "Lithium" + } + }, + { + "id": 2434, + "name": "Gwen Travis", + "gender": "female", + "age": 64, + "address": { + "state": "Alabama", + "city": "Bordelonville" + } + }, + { + "id": 2435, + "name": "Velma Sullivan", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Coventry" + } + }, + { + "id": 2436, + "name": "Ethel Wilder", + "gender": "female", + "age": 32, + "address": { + "state": "Kansas", + "city": "Accoville" + } + }, + { + "id": 2437, + "name": "Hunter Conley", + "gender": "male", + "age": 50, + "address": { + "state": "New Mexico", + "city": "Sultana" + } + }, + { + "id": 2438, + "name": "Kristy Weaver", + "gender": "female", + "age": 44, + "address": { + "state": "Pennsylvania", + "city": "Callaghan" + } + }, + { + "id": 2439, + "name": "Kim Jennings", + "gender": "female", + "age": 30, + "address": { + "state": "Indiana", + "city": "Frizzleburg" + } + }, + { + "id": 2440, + "name": "Ingrid Middleton", + "gender": "female", + "age": 24, + "address": { + "state": "Washington", + "city": "Cliff" + } + }, + { + "id": 2441, + "name": "Shelly Hurley", + "gender": "female", + "age": 36, + "address": { + "state": "Maine", + "city": "Goodville" + } + }, + { + "id": 2442, + "name": "Iris Mckee", + "gender": "female", + "age": 48, + "address": { + "state": "Maryland", + "city": "Hampstead" + } + }, + { + "id": 2443, + "name": "House Clarke", + "gender": "male", + "age": 21, + "address": { + "state": "Arkansas", + "city": "Cashtown" + } + }, + { + "id": 2444, + "name": "Josephine Howell", + "gender": "female", + "age": 36, + "address": { + "state": "Missouri", + "city": "Cochranville" + } + }, + { + "id": 2445, + "name": "Fowler Bray", + "gender": "male", + "age": 42, + "address": { + "state": "Iowa", + "city": "Dixie" + } + }, + { + "id": 2446, + "name": "Tammi French", + "gender": "female", + "age": 37, + "address": { + "state": "Michigan", + "city": "Islandia" + } + }, + { + "id": 2447, + "name": "Anastasia Mullins", + "gender": "female", + "age": 60, + "address": { + "state": "Colorado", + "city": "Oberlin" + } + }, + { + "id": 2448, + "name": "Maxine Salazar", + "gender": "female", + "age": 63, + "address": { + "state": "South Carolina", + "city": "Winesburg" + } + }, + { + "id": 2449, + "name": "Delaney Fernandez", + "gender": "male", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Clinton" + } + }, + { + "id": 2450, + "name": "Tami Mason", + "gender": "female", + "age": 32, + "address": { + "state": "Illinois", + "city": "Strong" + } + }, + { + "id": 2451, + "name": "Jean Baker", + "gender": "female", + "age": 32, + "address": { + "state": "Indiana", + "city": "Homeland" + } + }, + { + "id": 2452, + "name": "Harper Vincent", + "gender": "male", + "age": 70, + "address": { + "state": "North Carolina", + "city": "Gallina" + } + }, + { + "id": 2453, + "name": "Cherie Cantrell", + "gender": "female", + "age": 71, + "address": { + "state": "Michigan", + "city": "Brady" + } + }, + { + "id": 2454, + "name": "Doris Donovan", + "gender": "female", + "age": 41, + "address": { + "state": "South Carolina", + "city": "Innsbrook" + } + }, + { + "id": 2455, + "name": "Stanton Morgan", + "gender": "male", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Coyote" + } + }, + { + "id": 2456, + "name": "Jeri Barnett", + "gender": "female", + "age": 67, + "address": { + "state": "Arkansas", + "city": "Coalmont" + } + }, + { + "id": 2457, + "name": "Moses Cline", + "gender": "male", + "age": 42, + "address": { + "state": "Georgia", + "city": "Marienthal" + } + }, + { + "id": 2458, + "name": "Boyer Bishop", + "gender": "male", + "age": 25, + "address": { + "state": "New Hampshire", + "city": "Waterview" + } + }, + { + "id": 2459, + "name": "Burke Estrada", + "gender": "male", + "age": 70, + "address": { + "state": "Massachusetts", + "city": "Edneyville" + } + }, + { + "id": 2460, + "name": "Monroe Potts", + "gender": "male", + "age": 77, + "address": { + "state": "Oklahoma", + "city": "Stewart" + } + }, + { + "id": 2461, + "name": "Mckenzie Hodges", + "gender": "male", + "age": 18, + "address": { + "state": "Virginia", + "city": "Axis" + } + }, + { + "id": 2462, + "name": "Levy Bradshaw", + "gender": "male", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Vaughn" + } + }, + { + "id": 2463, + "name": "Mcgowan Shepard", + "gender": "male", + "age": 81, + "address": { + "state": "Tennessee", + "city": "Clarksburg" + } + }, + { + "id": 2464, + "name": "Marion Murray", + "gender": "female", + "age": 59, + "address": { + "state": "Hawaii", + "city": "Rossmore" + } + }, + { + "id": 2465, + "name": "Louella Fitzgerald", + "gender": "female", + "age": 36, + "address": { + "state": "Texas", + "city": "Elfrida" + } + }, + { + "id": 2466, + "name": "Lora Maxwell", + "gender": "female", + "age": 71, + "address": { + "state": "Missouri", + "city": "Nadine" + } + }, + { + "id": 2467, + "name": "Meagan Daniels", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Belleview" + } + }, + { + "id": 2468, + "name": "Mathis Sweeney", + "gender": "male", + "age": 49, + "address": { + "state": "West Virginia", + "city": "Savage" + } + }, + { + "id": 2469, + "name": "Oliver Mueller", + "gender": "male", + "age": 53, + "address": { + "state": "Arizona", + "city": "Knowlton" + } + }, + { + "id": 2470, + "name": "Terra Crosby", + "gender": "female", + "age": 49, + "address": { + "state": "Alabama", + "city": "Lacomb" + } + }, + { + "id": 2471, + "name": "Charlotte Blair", + "gender": "female", + "age": 37, + "address": { + "state": "New Mexico", + "city": "Bowie" + } + }, + { + "id": 2472, + "name": "Fry Dejesus", + "gender": "male", + "age": 53, + "address": { + "state": "Iowa", + "city": "Saddlebrooke" + } + }, + { + "id": 2473, + "name": "Maria Ross", + "gender": "female", + "age": 38, + "address": { + "state": "Oregon", + "city": "Fontanelle" + } + }, + { + "id": 2474, + "name": "Fran Haley", + "gender": "female", + "age": 76, + "address": { + "state": "Kentucky", + "city": "Shelby" + } + }, + { + "id": 2475, + "name": "Guadalupe Meyer", + "gender": "female", + "age": 43, + "address": { + "state": "Kansas", + "city": "Hall" + } + }, + { + "id": 2476, + "name": "Iva Kirk", + "gender": "female", + "age": 56, + "address": { + "state": "Pennsylvania", + "city": "Valle" + } + }, + { + "id": 2477, + "name": "Snider Park", + "gender": "male", + "age": 40, + "address": { + "state": "Idaho", + "city": "Kraemer" + } + }, + { + "id": 2478, + "name": "Contreras Mcneil", + "gender": "male", + "age": 54, + "address": { + "state": "New York", + "city": "Tilleda" + } + }, + { + "id": 2479, + "name": "Justine Hines", + "gender": "female", + "age": 61, + "address": { + "state": "Delaware", + "city": "Ballico" + } + }, + { + "id": 2480, + "name": "Rita Bean", + "gender": "female", + "age": 42, + "address": { + "state": "Wyoming", + "city": "Whitehaven" + } + }, + { + "id": 2481, + "name": "Lang Wallace", + "gender": "male", + "age": 24, + "address": { + "state": "Louisiana", + "city": "Otranto" + } + }, + { + "id": 2482, + "name": "Pat Griffin", + "gender": "female", + "age": 50, + "address": { + "state": "Utah", + "city": "Strykersville" + } + }, + { + "id": 2483, + "name": "Verna Adkins", + "gender": "female", + "age": 35, + "address": { + "state": "Nevada", + "city": "Hendersonville" + } + }, + { + "id": 2484, + "name": "Carver Peters", + "gender": "male", + "age": 22, + "address": { + "state": "Montana", + "city": "Slovan" + } + }, + { + "id": 2485, + "name": "Bauer Calhoun", + "gender": "male", + "age": 68, + "address": { + "state": "Rhode Island", + "city": "Babb" + } + }, + { + "id": 2486, + "name": "Head Townsend", + "gender": "male", + "age": 79, + "address": { + "state": "Maryland", + "city": "Carbonville" + } + }, + { + "id": 2487, + "name": "Callie Bartlett", + "gender": "female", + "age": 32, + "address": { + "state": "South Dakota", + "city": "Joes" + } + }, + { + "id": 2488, + "name": "Francine Garza", + "gender": "female", + "age": 23, + "address": { + "state": "Nebraska", + "city": "Logan" + } + }, + { + "id": 2489, + "name": "Tamika Tate", + "gender": "female", + "age": 73, + "address": { + "state": "Ohio", + "city": "Statenville" + } + }, + { + "id": 2490, + "name": "Vega Spencer", + "gender": "male", + "age": 74, + "address": { + "state": "Washington", + "city": "Tetherow" + } + }, + { + "id": 2491, + "name": "Stella Snow", + "gender": "female", + "age": 60, + "address": { + "state": "New Jersey", + "city": "Detroit" + } + }, + { + "id": 2492, + "name": "Bullock Juarez", + "gender": "male", + "age": 82, + "address": { + "state": "Colorado", + "city": "Nicholson" + } + }, + { + "id": 2493, + "name": "Bryant Hodge", + "gender": "male", + "age": 66, + "address": { + "state": "Maine", + "city": "Marne" + } + }, + { + "id": 2494, + "name": "Blanche Clements", + "gender": "female", + "age": 26, + "address": { + "state": "Alaska", + "city": "Needmore" + } + }, + { + "id": 2495, + "name": "Mitchell Kirkland", + "gender": "male", + "age": 62, + "address": { + "state": "Minnesota", + "city": "Choctaw" + } + }, + { + "id": 2496, + "name": "Mosley Mcfarland", + "gender": "male", + "age": 21, + "address": { + "state": "Florida", + "city": "Muir" + } + }, + { + "id": 2497, + "name": "April Williams", + "gender": "female", + "age": 46, + "address": { + "state": "Vermont", + "city": "Bedias" + } + }, + { + "id": 2498, + "name": "Ladonna Jensen", + "gender": "female", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Darlington" + } + }, + { + "id": 2499, + "name": "Holland Prince", + "gender": "male", + "age": 57, + "address": { + "state": "Missouri", + "city": "Maybell" + } + }, + { + "id": 2500, + "name": "Mary Franco", + "gender": "female", + "age": 25, + "address": { + "state": "Delaware", + "city": "Crown" + } + }, + { + "id": 2501, + "name": "Bruce Hampton", + "gender": "male", + "age": 22, + "address": { + "state": "Florida", + "city": "Chamizal" + } + }, + { + "id": 2502, + "name": "Bethany West", + "gender": "female", + "age": 76, + "address": { + "state": "Alaska", + "city": "Durham" + } + }, + { + "id": 2503, + "name": "Garcia Vaughan", + "gender": "male", + "age": 68, + "address": { + "state": "Louisiana", + "city": "Riverton" + } + }, + { + "id": 2504, + "name": "Lena Nichols", + "gender": "female", + "age": 45, + "address": { + "state": "Colorado", + "city": "Fivepointville" + } + }, + { + "id": 2505, + "name": "Thelma Gilbert", + "gender": "female", + "age": 78, + "address": { + "state": "Michigan", + "city": "Roosevelt" + } + }, + { + "id": 2506, + "name": "Floyd Huff", + "gender": "male", + "age": 29, + "address": { + "state": "Indiana", + "city": "Clay" + } + }, + { + "id": 2507, + "name": "Ellis Cooke", + "gender": "male", + "age": 18, + "address": { + "state": "Maryland", + "city": "Sattley" + } + }, + { + "id": 2508, + "name": "Noreen Sharp", + "gender": "female", + "age": 55, + "address": { + "state": "Nevada", + "city": "Moquino" + } + }, + { + "id": 2509, + "name": "Lorie Nelson", + "gender": "female", + "age": 34, + "address": { + "state": "Wyoming", + "city": "Centerville" + } + }, + { + "id": 2510, + "name": "Margery Watts", + "gender": "female", + "age": 22, + "address": { + "state": "Maine", + "city": "Edenburg" + } + }, + { + "id": 2511, + "name": "Tia Mccray", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Hachita" + } + }, + { + "id": 2512, + "name": "Letha Mcpherson", + "gender": "female", + "age": 32, + "address": { + "state": "North Carolina", + "city": "Zortman" + } + }, + { + "id": 2513, + "name": "Berta Townsend", + "gender": "female", + "age": 25, + "address": { + "state": "Idaho", + "city": "Ladera" + } + }, + { + "id": 2514, + "name": "Ruiz Sutton", + "gender": "male", + "age": 81, + "address": { + "state": "Montana", + "city": "Stockdale" + } + }, + { + "id": 2515, + "name": "Elena Gallegos", + "gender": "female", + "age": 33, + "address": { + "state": "Virginia", + "city": "Fresno" + } + }, + { + "id": 2516, + "name": "Brittany Mullins", + "gender": "female", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Knowlton" + } + }, + { + "id": 2517, + "name": "Carney Barlow", + "gender": "male", + "age": 44, + "address": { + "state": "Pennsylvania", + "city": "Marshall" + } + }, + { + "id": 2518, + "name": "Osborne Combs", + "gender": "male", + "age": 43, + "address": { + "state": "South Carolina", + "city": "Derwood" + } + }, + { + "id": 2519, + "name": "Rowena Knox", + "gender": "female", + "age": 74, + "address": { + "state": "Kentucky", + "city": "Norvelt" + } + }, + { + "id": 2520, + "name": "Mccullough Riley", + "gender": "male", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Trucksville" + } + }, + { + "id": 2521, + "name": "Bolton Jarvis", + "gender": "male", + "age": 23, + "address": { + "state": "North Dakota", + "city": "Broadlands" + } + }, + { + "id": 2522, + "name": "Marietta Cash", + "gender": "female", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Robinette" + } + }, + { + "id": 2523, + "name": "Beth Hickman", + "gender": "female", + "age": 77, + "address": { + "state": "Ohio", + "city": "Roulette" + } + }, + { + "id": 2524, + "name": "Rodriguez Bowers", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Wyano" + } + }, + { + "id": 2525, + "name": "Hester Hancock", + "gender": "male", + "age": 56, + "address": { + "state": "Mississippi", + "city": "Farmers" + } + }, + { + "id": 2526, + "name": "Maritza Roberts", + "gender": "female", + "age": 82, + "address": { + "state": "Iowa", + "city": "Deercroft" + } + }, + { + "id": 2527, + "name": "Singleton Floyd", + "gender": "male", + "age": 46, + "address": { + "state": "Tennessee", + "city": "Salunga" + } + }, + { + "id": 2528, + "name": "Collins Lambert", + "gender": "male", + "age": 71, + "address": { + "state": "Kansas", + "city": "Tibbie" + } + }, + { + "id": 2529, + "name": "Sellers Barron", + "gender": "male", + "age": 20, + "address": { + "state": "New York", + "city": "Carrsville" + } + }, + { + "id": 2530, + "name": "Ortiz Luna", + "gender": "male", + "age": 34, + "address": { + "state": "Illinois", + "city": "Kula" + } + }, + { + "id": 2531, + "name": "Lina Stout", + "gender": "female", + "age": 75, + "address": { + "state": "Washington", + "city": "Delco" + } + }, + { + "id": 2532, + "name": "Brock Mcconnell", + "gender": "male", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Day" + } + }, + { + "id": 2533, + "name": "Stanton Galloway", + "gender": "male", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Garnet" + } + }, + { + "id": 2534, + "name": "Adrian Sanford", + "gender": "female", + "age": 54, + "address": { + "state": "South Dakota", + "city": "Bath" + } + }, + { + "id": 2535, + "name": "Gaines Montgomery", + "gender": "male", + "age": 61, + "address": { + "state": "Oregon", + "city": "Fontanelle" + } + }, + { + "id": 2536, + "name": "Cooper Webb", + "gender": "male", + "age": 61, + "address": { + "state": "Georgia", + "city": "Crenshaw" + } + }, + { + "id": 2537, + "name": "Dalton Hendricks", + "gender": "male", + "age": 17, + "address": { + "state": "Alabama", + "city": "Mansfield" + } + }, + { + "id": 2538, + "name": "Angelita Hammond", + "gender": "female", + "age": 64, + "address": { + "state": "Hawaii", + "city": "Calpine" + } + }, + { + "id": 2539, + "name": "Vaughn Mcdaniel", + "gender": "male", + "age": 17, + "address": { + "state": "Arizona", + "city": "Sanford" + } + }, + { + "id": 2540, + "name": "Jocelyn Sims", + "gender": "female", + "age": 77, + "address": { + "state": "Minnesota", + "city": "Enetai" + } + }, + { + "id": 2541, + "name": "Holly Sherman", + "gender": "female", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Rosine" + } + }, + { + "id": 2542, + "name": "Owen Hanson", + "gender": "male", + "age": 67, + "address": { + "state": "Texas", + "city": "Teasdale" + } + }, + { + "id": 2543, + "name": "Melendez Pearson", + "gender": "male", + "age": 44, + "address": { + "state": "California", + "city": "Kaka" + } + }, + { + "id": 2544, + "name": "Wagner Woodward", + "gender": "male", + "age": 65, + "address": { + "state": "Connecticut", + "city": "Sabillasville" + } + }, + { + "id": 2545, + "name": "Kramer Ratliff", + "gender": "male", + "age": 74, + "address": { + "state": "Utah", + "city": "Bluetown" + } + }, + { + "id": 2546, + "name": "Sally Fox", + "gender": "female", + "age": 81, + "address": { + "state": "Nebraska", + "city": "Winchester" + } + }, + { + "id": 2547, + "name": "Jody Monroe", + "gender": "female", + "age": 66, + "address": { + "state": "Wisconsin", + "city": "Tuskahoma" + } + }, + { + "id": 2548, + "name": "Marva Mack", + "gender": "female", + "age": 36, + "address": { + "state": "Rhode Island", + "city": "Muir" + } + }, + { + "id": 2549, + "name": "Henry Vincent", + "gender": "male", + "age": 80, + "address": { + "state": "Oklahoma", + "city": "Coultervillle" + } + }, + { + "id": 2550, + "name": "Leila Marshall", + "gender": "female", + "age": 27, + "address": { + "state": "New York", + "city": "Levant" + } + }, + { + "id": 2551, + "name": "Daphne Jensen", + "gender": "female", + "age": 67, + "address": { + "state": "Connecticut", + "city": "Needmore" + } + }, + { + "id": 2552, + "name": "Fuller Keith", + "gender": "male", + "age": 48, + "address": { + "state": "New Jersey", + "city": "Kylertown" + } + }, + { + "id": 2553, + "name": "Gibson Bridges", + "gender": "male", + "age": 21, + "address": { + "state": "Kansas", + "city": "Bath" + } + }, + { + "id": 2554, + "name": "Alejandra Rios", + "gender": "female", + "age": 37, + "address": { + "state": "Maine", + "city": "Century" + } + }, + { + "id": 2555, + "name": "Benson Gaines", + "gender": "male", + "age": 41, + "address": { + "state": "New Hampshire", + "city": "Keller" + } + }, + { + "id": 2556, + "name": "Juliet Cherry", + "gender": "female", + "age": 27, + "address": { + "state": "Tennessee", + "city": "Worcester" + } + }, + { + "id": 2557, + "name": "Holmes Parrish", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Catharine" + } + }, + { + "id": 2558, + "name": "Boone Casey", + "gender": "male", + "age": 39, + "address": { + "state": "Wyoming", + "city": "Washington" + } + }, + { + "id": 2559, + "name": "Angelita Ray", + "gender": "female", + "age": 67, + "address": { + "state": "Oregon", + "city": "Oceola" + } + }, + { + "id": 2560, + "name": "Hardin Sutton", + "gender": "male", + "age": 58, + "address": { + "state": "South Dakota", + "city": "Leroy" + } + }, + { + "id": 2561, + "name": "Chasity Dennis", + "gender": "female", + "age": 76, + "address": { + "state": "North Carolina", + "city": "Holtville" + } + }, + { + "id": 2562, + "name": "Ramsey Randall", + "gender": "male", + "age": 72, + "address": { + "state": "Massachusetts", + "city": "Lithium" + } + }, + { + "id": 2563, + "name": "Merritt Stevenson", + "gender": "male", + "age": 77, + "address": { + "state": "Mississippi", + "city": "Glasgow" + } + }, + { + "id": 2564, + "name": "Lancaster Gilmore", + "gender": "male", + "age": 34, + "address": { + "state": "Arkansas", + "city": "Franklin" + } + }, + { + "id": 2565, + "name": "Katy Hewitt", + "gender": "female", + "age": 27, + "address": { + "state": "Texas", + "city": "Fairlee" + } + }, + { + "id": 2566, + "name": "Marcy Clark", + "gender": "female", + "age": 67, + "address": { + "state": "Virginia", + "city": "Westmoreland" + } + }, + { + "id": 2567, + "name": "Penelope England", + "gender": "female", + "age": 26, + "address": { + "state": "Iowa", + "city": "Castleton" + } + }, + { + "id": 2568, + "name": "Mayo Gamble", + "gender": "male", + "age": 78, + "address": { + "state": "Illinois", + "city": "Drummond" + } + }, + { + "id": 2569, + "name": "Kelli Carney", + "gender": "female", + "age": 66, + "address": { + "state": "Pennsylvania", + "city": "Veyo" + } + }, + { + "id": 2570, + "name": "Colon Howe", + "gender": "male", + "age": 54, + "address": { + "state": "North Dakota", + "city": "Sattley" + } + }, + { + "id": 2571, + "name": "Underwood Long", + "gender": "male", + "age": 34, + "address": { + "state": "Nevada", + "city": "Cliff" + } + }, + { + "id": 2572, + "name": "Conway Gentry", + "gender": "male", + "age": 35, + "address": { + "state": "Alaska", + "city": "Trail" + } + }, + { + "id": 2573, + "name": "Audra Bradley", + "gender": "female", + "age": 39, + "address": { + "state": "Montana", + "city": "Steinhatchee" + } + }, + { + "id": 2574, + "name": "Elliott Butler", + "gender": "male", + "age": 74, + "address": { + "state": "Ohio", + "city": "Macdona" + } + }, + { + "id": 2575, + "name": "Maura Hale", + "gender": "female", + "age": 51, + "address": { + "state": "Missouri", + "city": "Joppa" + } + }, + { + "id": 2576, + "name": "Berry Rosa", + "gender": "male", + "age": 74, + "address": { + "state": "Arizona", + "city": "Hilltop" + } + }, + { + "id": 2577, + "name": "Rosanne Pace", + "gender": "female", + "age": 59, + "address": { + "state": "Indiana", + "city": "Chase" + } + }, + { + "id": 2578, + "name": "Margo Sosa", + "gender": "female", + "age": 55, + "address": { + "state": "Utah", + "city": "Kraemer" + } + }, + { + "id": 2579, + "name": "Dale Heath", + "gender": "female", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Mayfair" + } + }, + { + "id": 2580, + "name": "Stevens Cain", + "gender": "male", + "age": 71, + "address": { + "state": "California", + "city": "Onton" + } + }, + { + "id": 2581, + "name": "Patel Lloyd", + "gender": "male", + "age": 69, + "address": { + "state": "Nebraska", + "city": "Hegins" + } + }, + { + "id": 2582, + "name": "Rowland Sanders", + "gender": "male", + "age": 73, + "address": { + "state": "Louisiana", + "city": "Dunlo" + } + }, + { + "id": 2583, + "name": "Vazquez Maddox", + "gender": "male", + "age": 73, + "address": { + "state": "South Carolina", + "city": "Mappsville" + } + }, + { + "id": 2584, + "name": "Stephanie Reeves", + "gender": "female", + "age": 54, + "address": { + "state": "Wisconsin", + "city": "Emison" + } + }, + { + "id": 2585, + "name": "Slater Chapman", + "gender": "male", + "age": 50, + "address": { + "state": "Kentucky", + "city": "Camptown" + } + }, + { + "id": 2586, + "name": "Lindsay Gardner", + "gender": "male", + "age": 35, + "address": { + "state": "Georgia", + "city": "Faxon" + } + }, + { + "id": 2587, + "name": "Sheree Barber", + "gender": "female", + "age": 20, + "address": { + "state": "New Mexico", + "city": "Hasty" + } + }, + { + "id": 2588, + "name": "Diana Albert", + "gender": "female", + "age": 42, + "address": { + "state": "Vermont", + "city": "Ripley" + } + }, + { + "id": 2589, + "name": "Ortiz Perry", + "gender": "male", + "age": 70, + "address": { + "state": "Delaware", + "city": "Bakersville" + } + }, + { + "id": 2590, + "name": "Bradley Clayton", + "gender": "male", + "age": 70, + "address": { + "state": "Alabama", + "city": "Shaft" + } + }, + { + "id": 2591, + "name": "Adela Hahn", + "gender": "female", + "age": 70, + "address": { + "state": "Michigan", + "city": "Gratton" + } + }, + { + "id": 2592, + "name": "Gilliam Luna", + "gender": "male", + "age": 23, + "address": { + "state": "Maryland", + "city": "Cumminsville" + } + }, + { + "id": 2593, + "name": "Natalie Hudson", + "gender": "female", + "age": 45, + "address": { + "state": "Washington", + "city": "Eureka" + } + }, + { + "id": 2594, + "name": "Lucille French", + "gender": "female", + "age": 68, + "address": { + "state": "Florida", + "city": "Hendersonville" + } + }, + { + "id": 2595, + "name": "Larsen Wiggins", + "gender": "male", + "age": 55, + "address": { + "state": "West Virginia", + "city": "Vernon" + } + }, + { + "id": 2596, + "name": "Dolores Adkins", + "gender": "female", + "age": 73, + "address": { + "state": "Hawaii", + "city": "Rote" + } + }, + { + "id": 2597, + "name": "Stuart Allen", + "gender": "male", + "age": 38, + "address": { + "state": "Connecticut", + "city": "Smock" + } + }, + { + "id": 2598, + "name": "Perez Howard", + "gender": "male", + "age": 71, + "address": { + "state": "New York", + "city": "Como" + } + }, + { + "id": 2599, + "name": "Rollins Powers", + "gender": "male", + "age": 34, + "address": { + "state": "South Carolina", + "city": "Ryderwood" + } + }, + { + "id": 2600, + "name": "Moore Cook", + "gender": "male", + "age": 42, + "address": { + "state": "Colorado", + "city": "Snowville" + } + }, + { + "id": 2601, + "name": "Humphrey Macias", + "gender": "male", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Hatteras" + } + }, + { + "id": 2602, + "name": "Benton Weber", + "gender": "male", + "age": 42, + "address": { + "state": "Wisconsin", + "city": "Guilford" + } + }, + { + "id": 2603, + "name": "Pate Gutierrez", + "gender": "male", + "age": 41, + "address": { + "state": "Massachusetts", + "city": "Brecon" + } + }, + { + "id": 2604, + "name": "Jarvis Sampson", + "gender": "male", + "age": 77, + "address": { + "state": "Indiana", + "city": "Blairstown" + } + }, + { + "id": 2605, + "name": "Nelda Davis", + "gender": "female", + "age": 30, + "address": { + "state": "Ohio", + "city": "Gerton" + } + }, + { + "id": 2606, + "name": "Odonnell Newman", + "gender": "male", + "age": 46, + "address": { + "state": "Kentucky", + "city": "Hampstead" + } + }, + { + "id": 2607, + "name": "Kara Ramirez", + "gender": "female", + "age": 69, + "address": { + "state": "South Dakota", + "city": "Sabillasville" + } + }, + { + "id": 2608, + "name": "Jacobson Robbins", + "gender": "male", + "age": 47, + "address": { + "state": "Arizona", + "city": "Thermal" + } + }, + { + "id": 2609, + "name": "Randall Hess", + "gender": "male", + "age": 22, + "address": { + "state": "Louisiana", + "city": "Bison" + } + }, + { + "id": 2610, + "name": "Gould Wolf", + "gender": "male", + "age": 38, + "address": { + "state": "Vermont", + "city": "Grapeview" + } + }, + { + "id": 2611, + "name": "Jeannette Battle", + "gender": "female", + "age": 59, + "address": { + "state": "Tennessee", + "city": "Bowie" + } + }, + { + "id": 2612, + "name": "Ivy Maldonado", + "gender": "female", + "age": 21, + "address": { + "state": "Illinois", + "city": "Lynn" + } + }, + { + "id": 2613, + "name": "Tia Odom", + "gender": "female", + "age": 24, + "address": { + "state": "West Virginia", + "city": "Hendersonville" + } + }, + { + "id": 2614, + "name": "Margie Noel", + "gender": "female", + "age": 55, + "address": { + "state": "Oregon", + "city": "Caspar" + } + }, + { + "id": 2615, + "name": "Marianne Lancaster", + "gender": "female", + "age": 40, + "address": { + "state": "Delaware", + "city": "Trexlertown" + } + }, + { + "id": 2616, + "name": "Avila Pruitt", + "gender": "male", + "age": 21, + "address": { + "state": "Iowa", + "city": "Lafferty" + } + }, + { + "id": 2617, + "name": "Gilmore Curtis", + "gender": "male", + "age": 49, + "address": { + "state": "Montana", + "city": "Hessville" + } + }, + { + "id": 2618, + "name": "Dale Morse", + "gender": "male", + "age": 56, + "address": { + "state": "California", + "city": "Bascom" + } + }, + { + "id": 2619, + "name": "Victoria Kidd", + "gender": "female", + "age": 54, + "address": { + "state": "Wyoming", + "city": "Belvoir" + } + }, + { + "id": 2620, + "name": "Graciela Sexton", + "gender": "female", + "age": 45, + "address": { + "state": "Maine", + "city": "Dodge" + } + }, + { + "id": 2621, + "name": "Lester Maddox", + "gender": "male", + "age": 55, + "address": { + "state": "North Carolina", + "city": "Neahkahnie" + } + }, + { + "id": 2622, + "name": "Cherie Cotton", + "gender": "female", + "age": 47, + "address": { + "state": "Nevada", + "city": "Magnolia" + } + }, + { + "id": 2623, + "name": "Joann Crosby", + "gender": "female", + "age": 20, + "address": { + "state": "New Hampshire", + "city": "Stewart" + } + }, + { + "id": 2624, + "name": "Kelley Hartman", + "gender": "female", + "age": 28, + "address": { + "state": "North Dakota", + "city": "Malo" + } + }, + { + "id": 2625, + "name": "Freeman Casey", + "gender": "male", + "age": 76, + "address": { + "state": "Idaho", + "city": "Townsend" + } + }, + { + "id": 2626, + "name": "Brenda Paul", + "gender": "female", + "age": 71, + "address": { + "state": "Virginia", + "city": "Somerset" + } + }, + { + "id": 2627, + "name": "Chan Fitzpatrick", + "gender": "male", + "age": 39, + "address": { + "state": "Alabama", + "city": "Cressey" + } + }, + { + "id": 2628, + "name": "Oconnor Richmond", + "gender": "male", + "age": 20, + "address": { + "state": "Michigan", + "city": "Coleville" + } + }, + { + "id": 2629, + "name": "Alvarado Lopez", + "gender": "male", + "age": 67, + "address": { + "state": "Florida", + "city": "Bridgetown" + } + }, + { + "id": 2630, + "name": "Lindsay Merritt", + "gender": "female", + "age": 44, + "address": { + "state": "Kansas", + "city": "Loveland" + } + }, + { + "id": 2631, + "name": "Gloria Wilkerson", + "gender": "female", + "age": 38, + "address": { + "state": "Maryland", + "city": "Lydia" + } + }, + { + "id": 2632, + "name": "Bentley Blankenship", + "gender": "male", + "age": 67, + "address": { + "state": "Texas", + "city": "Snyderville" + } + }, + { + "id": 2633, + "name": "Gill Mathews", + "gender": "male", + "age": 67, + "address": { + "state": "Minnesota", + "city": "Emory" + } + }, + { + "id": 2634, + "name": "Gilliam Jenkins", + "gender": "male", + "age": 32, + "address": { + "state": "Alaska", + "city": "Rowe" + } + }, + { + "id": 2635, + "name": "Figueroa Puckett", + "gender": "male", + "age": 50, + "address": { + "state": "Nebraska", + "city": "Woodlands" + } + }, + { + "id": 2636, + "name": "Cindy Wilder", + "gender": "female", + "age": 59, + "address": { + "state": "Pennsylvania", + "city": "Fairview" + } + }, + { + "id": 2637, + "name": "Knapp Ortega", + "gender": "male", + "age": 19, + "address": { + "state": "Washington", + "city": "Germanton" + } + }, + { + "id": 2638, + "name": "Lorene Lowe", + "gender": "female", + "age": 25, + "address": { + "state": "Hawaii", + "city": "Woodburn" + } + }, + { + "id": 2639, + "name": "Freda Clark", + "gender": "female", + "age": 66, + "address": { + "state": "Missouri", + "city": "Martell" + } + }, + { + "id": 2640, + "name": "Kasey Wiley", + "gender": "female", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Coldiron" + } + }, + { + "id": 2641, + "name": "Carmen Brooks", + "gender": "female", + "age": 61, + "address": { + "state": "Arkansas", + "city": "Englevale" + } + }, + { + "id": 2642, + "name": "Elsie Hewitt", + "gender": "female", + "age": 49, + "address": { + "state": "Georgia", + "city": "Tonopah" + } + }, + { + "id": 2643, + "name": "Lula Simpson", + "gender": "female", + "age": 74, + "address": { + "state": "Oklahoma", + "city": "Hillsboro" + } + }, + { + "id": 2644, + "name": "Booth Lyons", + "gender": "male", + "age": 55, + "address": { + "state": "Mississippi", + "city": "Croom" + } + }, + { + "id": 2645, + "name": "Knox Willis", + "gender": "male", + "age": 67, + "address": { + "state": "Utah", + "city": "Wadsworth" + } + }, + { + "id": 2646, + "name": "Barbra Pena", + "gender": "female", + "age": 24, + "address": { + "state": "Hawaii", + "city": "Navarre" + } + }, + { + "id": 2647, + "name": "Dyer Harmon", + "gender": "male", + "age": 40, + "address": { + "state": "Louisiana", + "city": "Sussex" + } + }, + { + "id": 2648, + "name": "Katheryn Farrell", + "gender": "female", + "age": 43, + "address": { + "state": "New York", + "city": "Vale" + } + }, + { + "id": 2649, + "name": "Rosanne Savage", + "gender": "female", + "age": 82, + "address": { + "state": "Vermont", + "city": "Boling" + } + }, + { + "id": 2650, + "name": "Katrina Madden", + "gender": "female", + "age": 51, + "address": { + "state": "Ohio", + "city": "Morgandale" + } + }, + { + "id": 2651, + "name": "Shaw Mosley", + "gender": "male", + "age": 51, + "address": { + "state": "Rhode Island", + "city": "Bendon" + } + }, + { + "id": 2652, + "name": "Elsa Rush", + "gender": "female", + "age": 71, + "address": { + "state": "Iowa", + "city": "Harmon" + } + }, + { + "id": 2653, + "name": "Jacklyn Strong", + "gender": "female", + "age": 23, + "address": { + "state": "South Carolina", + "city": "Dragoon" + } + }, + { + "id": 2654, + "name": "Monroe Dixon", + "gender": "male", + "age": 44, + "address": { + "state": "Michigan", + "city": "Elrama" + } + }, + { + "id": 2655, + "name": "Lottie Olson", + "gender": "female", + "age": 81, + "address": { + "state": "Texas", + "city": "Ahwahnee" + } + }, + { + "id": 2656, + "name": "Love Pickett", + "gender": "male", + "age": 41, + "address": { + "state": "North Dakota", + "city": "Alamo" + } + }, + { + "id": 2657, + "name": "Gina Merritt", + "gender": "female", + "age": 82, + "address": { + "state": "Illinois", + "city": "Dixie" + } + }, + { + "id": 2658, + "name": "Fox Byrd", + "gender": "male", + "age": 81, + "address": { + "state": "Oklahoma", + "city": "Dante" + } + }, + { + "id": 2659, + "name": "Mcfadden Vinson", + "gender": "male", + "age": 31, + "address": { + "state": "Delaware", + "city": "Lupton" + } + }, + { + "id": 2660, + "name": "Dona Cannon", + "gender": "female", + "age": 27, + "address": { + "state": "New Jersey", + "city": "Aurora" + } + }, + { + "id": 2661, + "name": "Holmes Franklin", + "gender": "male", + "age": 44, + "address": { + "state": "Georgia", + "city": "Loma" + } + }, + { + "id": 2662, + "name": "Bean Ochoa", + "gender": "male", + "age": 40, + "address": { + "state": "Arizona", + "city": "Leland" + } + }, + { + "id": 2663, + "name": "Tran Cash", + "gender": "male", + "age": 71, + "address": { + "state": "Tennessee", + "city": "Fairfield" + } + }, + { + "id": 2664, + "name": "Dean Mendez", + "gender": "male", + "age": 69, + "address": { + "state": "Kentucky", + "city": "Cetronia" + } + }, + { + "id": 2665, + "name": "Wolfe Pate", + "gender": "male", + "age": 33, + "address": { + "state": "Oregon", + "city": "Hessville" + } + }, + { + "id": 2666, + "name": "Anita Vega", + "gender": "female", + "age": 78, + "address": { + "state": "South Dakota", + "city": "Dixonville" + } + }, + { + "id": 2667, + "name": "Talley Wilkinson", + "gender": "male", + "age": 69, + "address": { + "state": "Florida", + "city": "Selma" + } + }, + { + "id": 2668, + "name": "Sutton Lang", + "gender": "male", + "age": 46, + "address": { + "state": "Massachusetts", + "city": "Clarktown" + } + }, + { + "id": 2669, + "name": "Oliver Hunt", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Warsaw" + } + }, + { + "id": 2670, + "name": "Florine Hayden", + "gender": "female", + "age": 74, + "address": { + "state": "Wisconsin", + "city": "Barrelville" + } + }, + { + "id": 2671, + "name": "Bennett Ramsey", + "gender": "male", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Strykersville" + } + }, + { + "id": 2672, + "name": "Mcmahon Mendoza", + "gender": "male", + "age": 71, + "address": { + "state": "Kansas", + "city": "Faxon" + } + }, + { + "id": 2673, + "name": "Mamie Lewis", + "gender": "female", + "age": 30, + "address": { + "state": "Mississippi", + "city": "Elfrida" + } + }, + { + "id": 2674, + "name": "Kramer Puckett", + "gender": "male", + "age": 63, + "address": { + "state": "Colorado", + "city": "Santel" + } + }, + { + "id": 2675, + "name": "Hopkins Vincent", + "gender": "male", + "age": 65, + "address": { + "state": "West Virginia", + "city": "Topaz" + } + }, + { + "id": 2676, + "name": "Stephanie Munoz", + "gender": "female", + "age": 82, + "address": { + "state": "New Hampshire", + "city": "Bannock" + } + }, + { + "id": 2677, + "name": "Clemons Roach", + "gender": "male", + "age": 79, + "address": { + "state": "Montana", + "city": "Rivera" + } + }, + { + "id": 2678, + "name": "Watson Campos", + "gender": "male", + "age": 24, + "address": { + "state": "Utah", + "city": "Tioga" + } + }, + { + "id": 2679, + "name": "Espinoza Tanner", + "gender": "male", + "age": 28, + "address": { + "state": "Wyoming", + "city": "Cleary" + } + }, + { + "id": 2680, + "name": "Lessie Hogan", + "gender": "female", + "age": 29, + "address": { + "state": "Alabama", + "city": "Kanauga" + } + }, + { + "id": 2681, + "name": "Dominguez York", + "gender": "male", + "age": 32, + "address": { + "state": "Pennsylvania", + "city": "Grandview" + } + }, + { + "id": 2682, + "name": "Earlene Weeks", + "gender": "female", + "age": 34, + "address": { + "state": "Alaska", + "city": "Dunnavant" + } + }, + { + "id": 2683, + "name": "Odom Booth", + "gender": "male", + "age": 17, + "address": { + "state": "Arkansas", + "city": "Taycheedah" + } + }, + { + "id": 2684, + "name": "Simmons Dunlap", + "gender": "male", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Hasty" + } + }, + { + "id": 2685, + "name": "Camille Maynard", + "gender": "female", + "age": 43, + "address": { + "state": "Virginia", + "city": "Riegelwood" + } + }, + { + "id": 2686, + "name": "Marion Decker", + "gender": "female", + "age": 81, + "address": { + "state": "Washington", + "city": "Martinsville" + } + }, + { + "id": 2687, + "name": "Mitzi Farmer", + "gender": "female", + "age": 35, + "address": { + "state": "Nevada", + "city": "Wheaton" + } + }, + { + "id": 2688, + "name": "Hall Wall", + "gender": "male", + "age": 81, + "address": { + "state": "Missouri", + "city": "Keller" + } + }, + { + "id": 2689, + "name": "Hewitt Higgins", + "gender": "male", + "age": 35, + "address": { + "state": "North Carolina", + "city": "Movico" + } + }, + { + "id": 2690, + "name": "Winnie Montoya", + "gender": "female", + "age": 41, + "address": { + "state": "Indiana", + "city": "Inkerman" + } + }, + { + "id": 2691, + "name": "Payne Bradley", + "gender": "male", + "age": 63, + "address": { + "state": "Connecticut", + "city": "Forestburg" + } + }, + { + "id": 2692, + "name": "Olivia Simmons", + "gender": "female", + "age": 65, + "address": { + "state": "Maine", + "city": "Shasta" + } + }, + { + "id": 2693, + "name": "Aguilar Mclean", + "gender": "male", + "age": 25, + "address": { + "state": "Maryland", + "city": "Greenock" + } + }, + { + "id": 2694, + "name": "Rene Walker", + "gender": "female", + "age": 69, + "address": { + "state": "Nebraska", + "city": "Abiquiu" + } + }, + { + "id": 2695, + "name": "Eva Rowe", + "gender": "female", + "age": 26, + "address": { + "state": "Maine", + "city": "Bedias" + } + }, + { + "id": 2696, + "name": "Gillespie Decker", + "gender": "male", + "age": 54, + "address": { + "state": "Pennsylvania", + "city": "Weeksville" + } + }, + { + "id": 2697, + "name": "Leonor Mcdonald", + "gender": "female", + "age": 54, + "address": { + "state": "Missouri", + "city": "Bethany" + } + }, + { + "id": 2698, + "name": "Megan Dillon", + "gender": "female", + "age": 52, + "address": { + "state": "Connecticut", + "city": "Coinjock" + } + }, + { + "id": 2699, + "name": "Oneal Bryant", + "gender": "male", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Murillo" + } + }, + { + "id": 2700, + "name": "Lorene Mcclain", + "gender": "female", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Whitewater" + } + }, + { + "id": 2701, + "name": "Thelma Cochran", + "gender": "female", + "age": 67, + "address": { + "state": "West Virginia", + "city": "Layhill" + } + }, + { + "id": 2702, + "name": "Nichols Jacobson", + "gender": "male", + "age": 47, + "address": { + "state": "Wyoming", + "city": "Sylvanite" + } + }, + { + "id": 2703, + "name": "Maryann Kelly", + "gender": "female", + "age": 71, + "address": { + "state": "California", + "city": "Gilgo" + } + }, + { + "id": 2704, + "name": "Hubbard Santana", + "gender": "male", + "age": 28, + "address": { + "state": "Maryland", + "city": "Cedarville" + } + }, + { + "id": 2705, + "name": "Louisa Rodriquez", + "gender": "female", + "age": 76, + "address": { + "state": "Arizona", + "city": "Laurelton" + } + }, + { + "id": 2706, + "name": "Dina Brewer", + "gender": "female", + "age": 42, + "address": { + "state": "Minnesota", + "city": "Collins" + } + }, + { + "id": 2707, + "name": "Vicky Flynn", + "gender": "female", + "age": 58, + "address": { + "state": "Utah", + "city": "Lisco" + } + }, + { + "id": 2708, + "name": "Clarissa Reese", + "gender": "female", + "age": 51, + "address": { + "state": "Montana", + "city": "Oceola" + } + }, + { + "id": 2709, + "name": "Baldwin Hodge", + "gender": "male", + "age": 35, + "address": { + "state": "Washington", + "city": "Indio" + } + }, + { + "id": 2710, + "name": "Sawyer Weaver", + "gender": "male", + "age": 57, + "address": { + "state": "Nevada", + "city": "Gerber" + } + }, + { + "id": 2711, + "name": "Lowery Holloway", + "gender": "male", + "age": 32, + "address": { + "state": "Iowa", + "city": "Magnolia" + } + }, + { + "id": 2712, + "name": "Julie Rice", + "gender": "female", + "age": 80, + "address": { + "state": "Colorado", + "city": "Hall" + } + }, + { + "id": 2713, + "name": "Alvarez James", + "gender": "male", + "age": 82, + "address": { + "state": "New Hampshire", + "city": "Homeworth" + } + }, + { + "id": 2714, + "name": "Gretchen Fischer", + "gender": "female", + "age": 18, + "address": { + "state": "Rhode Island", + "city": "Wells" + } + }, + { + "id": 2715, + "name": "Magdalena Hartman", + "gender": "female", + "age": 65, + "address": { + "state": "Georgia", + "city": "Austinburg" + } + }, + { + "id": 2716, + "name": "Cain Juarez", + "gender": "male", + "age": 79, + "address": { + "state": "Kentucky", + "city": "Sanders" + } + }, + { + "id": 2717, + "name": "Gonzales Bowers", + "gender": "male", + "age": 45, + "address": { + "state": "Oklahoma", + "city": "National" + } + }, + { + "id": 2718, + "name": "Frost Berry", + "gender": "male", + "age": 19, + "address": { + "state": "Tennessee", + "city": "Veguita" + } + }, + { + "id": 2719, + "name": "Freda Gibson", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Genoa" + } + }, + { + "id": 2720, + "name": "Lessie Le", + "gender": "female", + "age": 63, + "address": { + "state": "Kansas", + "city": "Garfield" + } + }, + { + "id": 2721, + "name": "Conrad Merritt", + "gender": "male", + "age": 52, + "address": { + "state": "Illinois", + "city": "Belfair" + } + }, + { + "id": 2722, + "name": "Susan Buck", + "gender": "female", + "age": 41, + "address": { + "state": "Alabama", + "city": "Sidman" + } + }, + { + "id": 2723, + "name": "Lilly Horne", + "gender": "female", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Deputy" + } + }, + { + "id": 2724, + "name": "Mia Sampson", + "gender": "female", + "age": 30, + "address": { + "state": "Michigan", + "city": "Toftrees" + } + }, + { + "id": 2725, + "name": "House Stone", + "gender": "male", + "age": 59, + "address": { + "state": "Alaska", + "city": "Goldfield" + } + }, + { + "id": 2726, + "name": "Karyn Underwood", + "gender": "female", + "age": 25, + "address": { + "state": "North Dakota", + "city": "Baden" + } + }, + { + "id": 2727, + "name": "Reese Henson", + "gender": "male", + "age": 64, + "address": { + "state": "North Carolina", + "city": "Bakersville" + } + }, + { + "id": 2728, + "name": "Bowen Cameron", + "gender": "male", + "age": 35, + "address": { + "state": "South Carolina", + "city": "Russellville" + } + }, + { + "id": 2729, + "name": "Hughes Ayers", + "gender": "male", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Cascades" + } + }, + { + "id": 2730, + "name": "Moses Barr", + "gender": "male", + "age": 53, + "address": { + "state": "Ohio", + "city": "Cade" + } + }, + { + "id": 2731, + "name": "Duran Reynolds", + "gender": "male", + "age": 60, + "address": { + "state": "New York", + "city": "Vandiver" + } + }, + { + "id": 2732, + "name": "Jaclyn Baker", + "gender": "female", + "age": 53, + "address": { + "state": "Oregon", + "city": "Glasgow" + } + }, + { + "id": 2733, + "name": "Millie Erickson", + "gender": "female", + "age": 25, + "address": { + "state": "Idaho", + "city": "Juntura" + } + }, + { + "id": 2734, + "name": "Juliet Flowers", + "gender": "female", + "age": 21, + "address": { + "state": "Wisconsin", + "city": "Century" + } + }, + { + "id": 2735, + "name": "Brigitte Garrett", + "gender": "female", + "age": 49, + "address": { + "state": "Vermont", + "city": "Barclay" + } + }, + { + "id": 2736, + "name": "Watson Donovan", + "gender": "male", + "age": 81, + "address": { + "state": "Arkansas", + "city": "Jenkinsville" + } + }, + { + "id": 2737, + "name": "Golden Johns", + "gender": "male", + "age": 53, + "address": { + "state": "Florida", + "city": "Groton" + } + }, + { + "id": 2738, + "name": "Allie Carroll", + "gender": "female", + "age": 70, + "address": { + "state": "Hawaii", + "city": "Thermal" + } + }, + { + "id": 2739, + "name": "Craft Gould", + "gender": "male", + "age": 47, + "address": { + "state": "Nebraska", + "city": "Berwind" + } + }, + { + "id": 2740, + "name": "Kirby Boyd", + "gender": "male", + "age": 55, + "address": { + "state": "Delaware", + "city": "Eastmont" + } + }, + { + "id": 2741, + "name": "Parrish Luna", + "gender": "male", + "age": 40, + "address": { + "state": "Mississippi", + "city": "Catherine" + } + }, + { + "id": 2742, + "name": "Patterson Pugh", + "gender": "male", + "age": 31, + "address": { + "state": "New Mexico", + "city": "Beaulieu" + } + }, + { + "id": 2743, + "name": "Morris Harding", + "gender": "male", + "age": 26, + "address": { + "state": "Virginia", + "city": "Goochland" + } + }, + { + "id": 2744, + "name": "Cohen Welch", + "gender": "male", + "age": 66, + "address": { + "state": "South Carolina", + "city": "Marshall" + } + }, + { + "id": 2745, + "name": "Collier Scott", + "gender": "male", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Farmington" + } + }, + { + "id": 2746, + "name": "Ruby Klein", + "gender": "female", + "age": 38, + "address": { + "state": "North Dakota", + "city": "Chautauqua" + } + }, + { + "id": 2747, + "name": "Newman Mills", + "gender": "male", + "age": 71, + "address": { + "state": "North Carolina", + "city": "Dennard" + } + }, + { + "id": 2748, + "name": "Janis Fleming", + "gender": "female", + "age": 23, + "address": { + "state": "Rhode Island", + "city": "Driftwood" + } + }, + { + "id": 2749, + "name": "Hogan Sears", + "gender": "male", + "age": 38, + "address": { + "state": "Virginia", + "city": "Eagleville" + } + }, + { + "id": 2750, + "name": "Joann Oconnor", + "gender": "female", + "age": 74, + "address": { + "state": "Hawaii", + "city": "Camas" + } + }, + { + "id": 2751, + "name": "Chapman Good", + "gender": "male", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Belleview" + } + }, + { + "id": 2752, + "name": "Fitzgerald Benjamin", + "gender": "male", + "age": 17, + "address": { + "state": "Oregon", + "city": "Ogema" + } + }, + { + "id": 2753, + "name": "Elva Mueller", + "gender": "female", + "age": 58, + "address": { + "state": "New Mexico", + "city": "Chalfant" + } + }, + { + "id": 2754, + "name": "Concetta Warner", + "gender": "female", + "age": 60, + "address": { + "state": "Indiana", + "city": "Yorklyn" + } + }, + { + "id": 2755, + "name": "Gale Greer", + "gender": "female", + "age": 20, + "address": { + "state": "Texas", + "city": "Derwood" + } + }, + { + "id": 2756, + "name": "Janie Flowers", + "gender": "female", + "age": 27, + "address": { + "state": "Arizona", + "city": "Retsof" + } + }, + { + "id": 2757, + "name": "Lynn Jefferson", + "gender": "male", + "age": 47, + "address": { + "state": "Maine", + "city": "Vincent" + } + }, + { + "id": 2758, + "name": "Latoya Phillips", + "gender": "female", + "age": 49, + "address": { + "state": "Louisiana", + "city": "Hasty" + } + }, + { + "id": 2759, + "name": "Ray Henson", + "gender": "male", + "age": 70, + "address": { + "state": "New Jersey", + "city": "Bentley" + } + }, + { + "id": 2760, + "name": "Foley Perry", + "gender": "male", + "age": 64, + "address": { + "state": "Wyoming", + "city": "Bainbridge" + } + }, + { + "id": 2761, + "name": "Margaret Solomon", + "gender": "female", + "age": 36, + "address": { + "state": "Michigan", + "city": "Jacksonburg" + } + }, + { + "id": 2762, + "name": "Trevino Vinson", + "gender": "male", + "age": 82, + "address": { + "state": "West Virginia", + "city": "Fairlee" + } + }, + { + "id": 2763, + "name": "Bartlett Graves", + "gender": "male", + "age": 63, + "address": { + "state": "Illinois", + "city": "Noblestown" + } + }, + { + "id": 2764, + "name": "Cain Pitts", + "gender": "male", + "age": 60, + "address": { + "state": "Washington", + "city": "Ivanhoe" + } + }, + { + "id": 2765, + "name": "Consuelo Bruce", + "gender": "female", + "age": 68, + "address": { + "state": "Alaska", + "city": "Westmoreland" + } + }, + { + "id": 2766, + "name": "Ava Montgomery", + "gender": "female", + "age": 53, + "address": { + "state": "Vermont", + "city": "Williston" + } + }, + { + "id": 2767, + "name": "Polly Giles", + "gender": "female", + "age": 18, + "address": { + "state": "Arkansas", + "city": "Kennedyville" + } + }, + { + "id": 2768, + "name": "Mari Simon", + "gender": "female", + "age": 54, + "address": { + "state": "Delaware", + "city": "Smock" + } + }, + { + "id": 2769, + "name": "Lisa Rollins", + "gender": "female", + "age": 20, + "address": { + "state": "Wisconsin", + "city": "Orick" + } + }, + { + "id": 2770, + "name": "Booker Schwartz", + "gender": "male", + "age": 47, + "address": { + "state": "New Hampshire", + "city": "Mammoth" + } + }, + { + "id": 2771, + "name": "Janelle Rodgers", + "gender": "female", + "age": 33, + "address": { + "state": "New York", + "city": "Elwood" + } + }, + { + "id": 2772, + "name": "Benita Logan", + "gender": "female", + "age": 24, + "address": { + "state": "Kentucky", + "city": "Roeville" + } + }, + { + "id": 2773, + "name": "Beverley Atkins", + "gender": "female", + "age": 71, + "address": { + "state": "Kansas", + "city": "Osage" + } + }, + { + "id": 2774, + "name": "Paula Webster", + "gender": "female", + "age": 25, + "address": { + "state": "Missouri", + "city": "Lynn" + } + }, + { + "id": 2775, + "name": "Summers Landry", + "gender": "male", + "age": 79, + "address": { + "state": "Alabama", + "city": "Enoree" + } + }, + { + "id": 2776, + "name": "Rodriguez Hart", + "gender": "male", + "age": 57, + "address": { + "state": "South Dakota", + "city": "Datil" + } + }, + { + "id": 2777, + "name": "Jean Daniel", + "gender": "female", + "age": 57, + "address": { + "state": "Utah", + "city": "Babb" + } + }, + { + "id": 2778, + "name": "Avila Schneider", + "gender": "male", + "age": 70, + "address": { + "state": "Minnesota", + "city": "Cliff" + } + }, + { + "id": 2779, + "name": "Meghan Hester", + "gender": "female", + "age": 30, + "address": { + "state": "Georgia", + "city": "Hollins" + } + }, + { + "id": 2780, + "name": "Pearson Harper", + "gender": "male", + "age": 24, + "address": { + "state": "California", + "city": "Harrodsburg" + } + }, + { + "id": 2781, + "name": "Penny Benson", + "gender": "female", + "age": 20, + "address": { + "state": "Oklahoma", + "city": "Joppa" + } + }, + { + "id": 2782, + "name": "Melva Solis", + "gender": "female", + "age": 41, + "address": { + "state": "Iowa", + "city": "Hiwasse" + } + }, + { + "id": 2783, + "name": "Doreen Benton", + "gender": "female", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Walker" + } + }, + { + "id": 2784, + "name": "Jocelyn Gregory", + "gender": "female", + "age": 21, + "address": { + "state": "Nevada", + "city": "Leyner" + } + }, + { + "id": 2785, + "name": "Tommie Hughes", + "gender": "female", + "age": 56, + "address": { + "state": "Idaho", + "city": "Wells" + } + }, + { + "id": 2786, + "name": "Mcneil Shaw", + "gender": "male", + "age": 72, + "address": { + "state": "Mississippi", + "city": "Bath" + } + }, + { + "id": 2787, + "name": "Casandra Douglas", + "gender": "female", + "age": 18, + "address": { + "state": "Ohio", + "city": "Homeland" + } + }, + { + "id": 2788, + "name": "Gilda Walters", + "gender": "female", + "age": 18, + "address": { + "state": "Tennessee", + "city": "Nicut" + } + }, + { + "id": 2789, + "name": "Lizzie Hopkins", + "gender": "female", + "age": 69, + "address": { + "state": "Maryland", + "city": "Wescosville" + } + }, + { + "id": 2790, + "name": "Rosalind Barrera", + "gender": "female", + "age": 81, + "address": { + "state": "Pennsylvania", + "city": "Bannock" + } + }, + { + "id": 2791, + "name": "Tami Schmidt", + "gender": "female", + "age": 43, + "address": { + "state": "Florida", + "city": "Brecon" + } + }, + { + "id": 2792, + "name": "Maura Sanders", + "gender": "female", + "age": 29, + "address": { + "state": "Colorado", + "city": "Cressey" + } + }, + { + "id": 2793, + "name": "Robles Carney", + "gender": "male", + "age": 51, + "address": { + "state": "Louisiana", + "city": "Churchill" + } + }, + { + "id": 2794, + "name": "Reed Pugh", + "gender": "male", + "age": 60, + "address": { + "state": "Florida", + "city": "Chaparrito" + } + }, + { + "id": 2795, + "name": "Patel Dunlap", + "gender": "male", + "age": 54, + "address": { + "state": "Illinois", + "city": "Fannett" + } + }, + { + "id": 2796, + "name": "Hess Foreman", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Dana" + } + }, + { + "id": 2797, + "name": "Maggie Melendez", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Riegelwood" + } + }, + { + "id": 2798, + "name": "Estes Pitts", + "gender": "male", + "age": 21, + "address": { + "state": "Ohio", + "city": "Singer" + } + }, + { + "id": 2799, + "name": "Stuart Galloway", + "gender": "male", + "age": 37, + "address": { + "state": "Tennessee", + "city": "Kent" + } + }, + { + "id": 2800, + "name": "Callie Santana", + "gender": "female", + "age": 20, + "address": { + "state": "Arizona", + "city": "Matheny" + } + }, + { + "id": 2801, + "name": "Franks Jordan", + "gender": "male", + "age": 30, + "address": { + "state": "Mississippi", + "city": "Romeville" + } + }, + { + "id": 2802, + "name": "Hayes Scott", + "gender": "male", + "age": 57, + "address": { + "state": "Vermont", + "city": "Camptown" + } + }, + { + "id": 2803, + "name": "Arlene Henderson", + "gender": "female", + "age": 65, + "address": { + "state": "Colorado", + "city": "Flintville" + } + }, + { + "id": 2804, + "name": "Moreno Farmer", + "gender": "male", + "age": 18, + "address": { + "state": "Alabama", + "city": "Bison" + } + }, + { + "id": 2805, + "name": "Dalton Norris", + "gender": "male", + "age": 29, + "address": { + "state": "Alaska", + "city": "Strong" + } + }, + { + "id": 2806, + "name": "Brianna Koch", + "gender": "female", + "age": 81, + "address": { + "state": "South Carolina", + "city": "Needmore" + } + }, + { + "id": 2807, + "name": "Goldie Peters", + "gender": "female", + "age": 36, + "address": { + "state": "Hawaii", + "city": "Williston" + } + }, + { + "id": 2808, + "name": "Moran Holloway", + "gender": "male", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Kersey" + } + }, + { + "id": 2809, + "name": "Beatriz Cervantes", + "gender": "female", + "age": 35, + "address": { + "state": "Pennsylvania", + "city": "Freeburn" + } + }, + { + "id": 2810, + "name": "Kendra Hebert", + "gender": "female", + "age": 51, + "address": { + "state": "South Dakota", + "city": "Watchtower" + } + }, + { + "id": 2811, + "name": "Judith Bowen", + "gender": "female", + "age": 18, + "address": { + "state": "Delaware", + "city": "Ypsilanti" + } + }, + { + "id": 2812, + "name": "Aida Meadows", + "gender": "female", + "age": 75, + "address": { + "state": "Oklahoma", + "city": "Mammoth" + } + }, + { + "id": 2813, + "name": "Finley Sweet", + "gender": "male", + "age": 44, + "address": { + "state": "Maryland", + "city": "Goldfield" + } + }, + { + "id": 2814, + "name": "Belinda Fischer", + "gender": "female", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Bend" + } + }, + { + "id": 2815, + "name": "Gail Aguirre", + "gender": "female", + "age": 28, + "address": { + "state": "West Virginia", + "city": "Oasis" + } + }, + { + "id": 2816, + "name": "Georgette Davis", + "gender": "female", + "age": 32, + "address": { + "state": "Kentucky", + "city": "Roosevelt" + } + }, + { + "id": 2817, + "name": "Erna Hood", + "gender": "female", + "age": 17, + "address": { + "state": "Rhode Island", + "city": "Boykin" + } + }, + { + "id": 2818, + "name": "Jerri Dyer", + "gender": "female", + "age": 37, + "address": { + "state": "Iowa", + "city": "Wakulla" + } + }, + { + "id": 2819, + "name": "Berg Alston", + "gender": "male", + "age": 38, + "address": { + "state": "Indiana", + "city": "Blackgum" + } + }, + { + "id": 2820, + "name": "Swanson Sawyer", + "gender": "male", + "age": 50, + "address": { + "state": "North Dakota", + "city": "Fontanelle" + } + }, + { + "id": 2821, + "name": "Lindsay Huffman", + "gender": "female", + "age": 82, + "address": { + "state": "Virginia", + "city": "Waterford" + } + }, + { + "id": 2822, + "name": "Harrington Durham", + "gender": "male", + "age": 32, + "address": { + "state": "New York", + "city": "Elrama" + } + }, + { + "id": 2823, + "name": "Alana Stone", + "gender": "female", + "age": 29, + "address": { + "state": "Kansas", + "city": "Kenvil" + } + }, + { + "id": 2824, + "name": "Velez Lopez", + "gender": "male", + "age": 17, + "address": { + "state": "Missouri", + "city": "Hilltop" + } + }, + { + "id": 2825, + "name": "Mcdowell Peck", + "gender": "male", + "age": 65, + "address": { + "state": "Massachusetts", + "city": "Vernon" + } + }, + { + "id": 2826, + "name": "Chan Cleveland", + "gender": "male", + "age": 56, + "address": { + "state": "North Carolina", + "city": "Rowe" + } + }, + { + "id": 2827, + "name": "Vargas Puckett", + "gender": "male", + "age": 52, + "address": { + "state": "Michigan", + "city": "Abiquiu" + } + }, + { + "id": 2828, + "name": "Juliette Hatfield", + "gender": "female", + "age": 64, + "address": { + "state": "Washington", + "city": "Nadine" + } + }, + { + "id": 2829, + "name": "Joanna Guerra", + "gender": "female", + "age": 70, + "address": { + "state": "California", + "city": "Dawn" + } + }, + { + "id": 2830, + "name": "Kelly Ramos", + "gender": "female", + "age": 61, + "address": { + "state": "Arkansas", + "city": "Shelby" + } + }, + { + "id": 2831, + "name": "Polly Lowery", + "gender": "female", + "age": 33, + "address": { + "state": "Oregon", + "city": "Calverton" + } + }, + { + "id": 2832, + "name": "Shari Wade", + "gender": "female", + "age": 50, + "address": { + "state": "Wyoming", + "city": "Roderfield" + } + }, + { + "id": 2833, + "name": "Ryan Contreras", + "gender": "male", + "age": 52, + "address": { + "state": "Nevada", + "city": "Williams" + } + }, + { + "id": 2834, + "name": "Small Delacruz", + "gender": "male", + "age": 26, + "address": { + "state": "Nebraska", + "city": "Sunnyside" + } + }, + { + "id": 2835, + "name": "Jannie Simpson", + "gender": "female", + "age": 38, + "address": { + "state": "Wisconsin", + "city": "Macdona" + } + }, + { + "id": 2836, + "name": "Bonnie Huber", + "gender": "female", + "age": 22, + "address": { + "state": "New Mexico", + "city": "Broadlands" + } + }, + { + "id": 2837, + "name": "Marilyn Moreno", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Sunwest" + } + }, + { + "id": 2838, + "name": "Riggs Blackburn", + "gender": "male", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Caberfae" + } + }, + { + "id": 2839, + "name": "Twila Marks", + "gender": "female", + "age": 31, + "address": { + "state": "Montana", + "city": "Gila" + } + }, + { + "id": 2840, + "name": "Kaitlin Vincent", + "gender": "female", + "age": 23, + "address": { + "state": "New Jersey", + "city": "Marshall" + } + }, + { + "id": 2841, + "name": "Phoebe Newton", + "gender": "female", + "age": 42, + "address": { + "state": "Utah", + "city": "Hickory" + } + }, + { + "id": 2842, + "name": "Bianca Duran", + "gender": "female", + "age": 59, + "address": { + "state": "Vermont", + "city": "Rossmore" + } + }, + { + "id": 2843, + "name": "Morrow Bean", + "gender": "male", + "age": 53, + "address": { + "state": "Mississippi", + "city": "Shindler" + } + }, + { + "id": 2844, + "name": "House Boyle", + "gender": "male", + "age": 56, + "address": { + "state": "Delaware", + "city": "Dixonville" + } + }, + { + "id": 2845, + "name": "Mcpherson Phelps", + "gender": "male", + "age": 74, + "address": { + "state": "Montana", + "city": "Deputy" + } + }, + { + "id": 2846, + "name": "Francis Mcneil", + "gender": "female", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Gorst" + } + }, + { + "id": 2847, + "name": "Baldwin Morse", + "gender": "male", + "age": 53, + "address": { + "state": "Nebraska", + "city": "Baker" + } + }, + { + "id": 2848, + "name": "Rich Rich", + "gender": "male", + "age": 22, + "address": { + "state": "Wyoming", + "city": "Alamo" + } + }, + { + "id": 2849, + "name": "Mccormick Head", + "gender": "male", + "age": 78, + "address": { + "state": "New Jersey", + "city": "Vowinckel" + } + }, + { + "id": 2850, + "name": "Lynn Young", + "gender": "female", + "age": 25, + "address": { + "state": "Idaho", + "city": "Ogema" + } + }, + { + "id": 2851, + "name": "Terri Kerr", + "gender": "female", + "age": 45, + "address": { + "state": "Kentucky", + "city": "Durham" + } + }, + { + "id": 2852, + "name": "Robyn Joyner", + "gender": "female", + "age": 30, + "address": { + "state": "Rhode Island", + "city": "Nelson" + } + }, + { + "id": 2853, + "name": "Suzanne Bradley", + "gender": "female", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Zortman" + } + }, + { + "id": 2854, + "name": "Fowler Carlson", + "gender": "male", + "age": 74, + "address": { + "state": "Minnesota", + "city": "Marion" + } + }, + { + "id": 2855, + "name": "Casey Douglas", + "gender": "female", + "age": 81, + "address": { + "state": "Arkansas", + "city": "Allensworth" + } + }, + { + "id": 2856, + "name": "Boyle Rivers", + "gender": "male", + "age": 43, + "address": { + "state": "Nevada", + "city": "Dotsero" + } + }, + { + "id": 2857, + "name": "French Romero", + "gender": "male", + "age": 34, + "address": { + "state": "Missouri", + "city": "Blandburg" + } + }, + { + "id": 2858, + "name": "Diana Webb", + "gender": "female", + "age": 65, + "address": { + "state": "Indiana", + "city": "Websterville" + } + }, + { + "id": 2859, + "name": "Calderon Mooney", + "gender": "male", + "age": 40, + "address": { + "state": "California", + "city": "Konterra" + } + }, + { + "id": 2860, + "name": "Dorothea Vance", + "gender": "female", + "age": 18, + "address": { + "state": "Alabama", + "city": "Edmund" + } + }, + { + "id": 2861, + "name": "Tanner Good", + "gender": "male", + "age": 54, + "address": { + "state": "North Dakota", + "city": "Westwood" + } + }, + { + "id": 2862, + "name": "Lenora Bishop", + "gender": "female", + "age": 36, + "address": { + "state": "Maine", + "city": "Williams" + } + }, + { + "id": 2863, + "name": "Adeline Hodge", + "gender": "female", + "age": 31, + "address": { + "state": "Louisiana", + "city": "Itmann" + } + }, + { + "id": 2864, + "name": "Henderson Cash", + "gender": "male", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Beechmont" + } + }, + { + "id": 2865, + "name": "Diane Green", + "gender": "female", + "age": 73, + "address": { + "state": "Arizona", + "city": "Trail" + } + }, + { + "id": 2866, + "name": "Pollard Huff", + "gender": "male", + "age": 73, + "address": { + "state": "Kansas", + "city": "Cliff" + } + }, + { + "id": 2867, + "name": "Sadie Gould", + "gender": "female", + "age": 76, + "address": { + "state": "Alaska", + "city": "Roland" + } + }, + { + "id": 2868, + "name": "Kari Preston", + "gender": "female", + "age": 53, + "address": { + "state": "Utah", + "city": "Freetown" + } + }, + { + "id": 2869, + "name": "Roy Noel", + "gender": "male", + "age": 76, + "address": { + "state": "Texas", + "city": "Sims" + } + }, + { + "id": 2870, + "name": "Marla Salinas", + "gender": "female", + "age": 70, + "address": { + "state": "Virginia", + "city": "Bodega" + } + }, + { + "id": 2871, + "name": "Bridget Dean", + "gender": "female", + "age": 55, + "address": { + "state": "Georgia", + "city": "Caberfae" + } + }, + { + "id": 2872, + "name": "Celina Odom", + "gender": "female", + "age": 69, + "address": { + "state": "Colorado", + "city": "Caledonia" + } + }, + { + "id": 2873, + "name": "Shelby Howe", + "gender": "female", + "age": 79, + "address": { + "state": "Ohio", + "city": "Avoca" + } + }, + { + "id": 2874, + "name": "Jeanette Myers", + "gender": "female", + "age": 41, + "address": { + "state": "Florida", + "city": "Woodburn" + } + }, + { + "id": 2875, + "name": "Elaine Pearson", + "gender": "female", + "age": 69, + "address": { + "state": "Hawaii", + "city": "Manila" + } + }, + { + "id": 2876, + "name": "Meyer Roth", + "gender": "male", + "age": 29, + "address": { + "state": "Iowa", + "city": "Alleghenyville" + } + }, + { + "id": 2877, + "name": "Nixon Casey", + "gender": "male", + "age": 60, + "address": { + "state": "Illinois", + "city": "Highland" + } + }, + { + "id": 2878, + "name": "Conley Olsen", + "gender": "male", + "age": 57, + "address": { + "state": "New York", + "city": "Lindisfarne" + } + }, + { + "id": 2879, + "name": "Guthrie Burnett", + "gender": "male", + "age": 63, + "address": { + "state": "Pennsylvania", + "city": "Yorklyn" + } + }, + { + "id": 2880, + "name": "Mack Hamilton", + "gender": "male", + "age": 65, + "address": { + "state": "South Dakota", + "city": "Gorham" + } + }, + { + "id": 2881, + "name": "Griffith Macias", + "gender": "male", + "age": 44, + "address": { + "state": "Wisconsin", + "city": "Zarephath" + } + }, + { + "id": 2882, + "name": "Bettie Pugh", + "gender": "female", + "age": 39, + "address": { + "state": "Connecticut", + "city": "Grantville" + } + }, + { + "id": 2883, + "name": "Reid Berg", + "gender": "male", + "age": 41, + "address": { + "state": "Maryland", + "city": "Reno" + } + }, + { + "id": 2884, + "name": "Le Walton", + "gender": "male", + "age": 37, + "address": { + "state": "New Mexico", + "city": "Dawn" + } + }, + { + "id": 2885, + "name": "Diaz Schwartz", + "gender": "male", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Cowiche" + } + }, + { + "id": 2886, + "name": "Fannie Fuentes", + "gender": "female", + "age": 71, + "address": { + "state": "Oregon", + "city": "Muir" + } + }, + { + "id": 2887, + "name": "Juliet Schmidt", + "gender": "female", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Glenshaw" + } + }, + { + "id": 2888, + "name": "Ellen Diaz", + "gender": "female", + "age": 36, + "address": { + "state": "Washington", + "city": "Linwood" + } + }, + { + "id": 2889, + "name": "Avis Owen", + "gender": "female", + "age": 79, + "address": { + "state": "Michigan", + "city": "Lumberton" + } + }, + { + "id": 2890, + "name": "Victoria Hardy", + "gender": "female", + "age": 30, + "address": { + "state": "South Carolina", + "city": "Dana" + } + }, + { + "id": 2891, + "name": "Candice Maxwell", + "gender": "female", + "age": 19, + "address": { + "state": "Alabama", + "city": "Clara" + } + }, + { + "id": 2892, + "name": "Silva Waller", + "gender": "male", + "age": 26, + "address": { + "state": "Montana", + "city": "Lisco" + } + }, + { + "id": 2893, + "name": "Glenn Fleming", + "gender": "male", + "age": 31, + "address": { + "state": "Ohio", + "city": "Sanford" + } + }, + { + "id": 2894, + "name": "Thelma Bass", + "gender": "female", + "age": 44, + "address": { + "state": "South Carolina", + "city": "Nutrioso" + } + }, + { + "id": 2895, + "name": "Hendricks Harmon", + "gender": "male", + "age": 71, + "address": { + "state": "Tennessee", + "city": "Tilden" + } + }, + { + "id": 2896, + "name": "Freeman Delgado", + "gender": "male", + "age": 70, + "address": { + "state": "Colorado", + "city": "Fairlee" + } + }, + { + "id": 2897, + "name": "Dominique Gallegos", + "gender": "female", + "age": 80, + "address": { + "state": "Indiana", + "city": "Trinway" + } + }, + { + "id": 2898, + "name": "Glenna Green", + "gender": "female", + "age": 64, + "address": { + "state": "Washington", + "city": "Catharine" + } + }, + { + "id": 2899, + "name": "Page Pope", + "gender": "male", + "age": 25, + "address": { + "state": "Florida", + "city": "Madrid" + } + }, + { + "id": 2900, + "name": "Lakeisha Ramsey", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Canterwood" + } + }, + { + "id": 2901, + "name": "Sanders Guerra", + "gender": "male", + "age": 28, + "address": { + "state": "Hawaii", + "city": "Newry" + } + }, + { + "id": 2902, + "name": "Jamie Harris", + "gender": "female", + "age": 33, + "address": { + "state": "Alaska", + "city": "Lowell" + } + }, + { + "id": 2903, + "name": "Fuentes Beck", + "gender": "male", + "age": 78, + "address": { + "state": "Wyoming", + "city": "Florence" + } + }, + { + "id": 2904, + "name": "Higgins Velez", + "gender": "male", + "age": 54, + "address": { + "state": "Iowa", + "city": "Woodruff" + } + }, + { + "id": 2905, + "name": "Carmen Mcgee", + "gender": "female", + "age": 70, + "address": { + "state": "Utah", + "city": "Kanauga" + } + }, + { + "id": 2906, + "name": "Dorsey Cook", + "gender": "male", + "age": 48, + "address": { + "state": "Nevada", + "city": "Hollins" + } + }, + { + "id": 2907, + "name": "Coffey Mcpherson", + "gender": "male", + "age": 71, + "address": { + "state": "New Hampshire", + "city": "Canoochee" + } + }, + { + "id": 2908, + "name": "Love Jennings", + "gender": "male", + "age": 23, + "address": { + "state": "Rhode Island", + "city": "Vaughn" + } + }, + { + "id": 2909, + "name": "Mary Rocha", + "gender": "female", + "age": 41, + "address": { + "state": "West Virginia", + "city": "Cutter" + } + }, + { + "id": 2910, + "name": "Nadine Langley", + "gender": "female", + "age": 79, + "address": { + "state": "Connecticut", + "city": "Troy" + } + }, + { + "id": 2911, + "name": "Adele Fuentes", + "gender": "female", + "age": 56, + "address": { + "state": "New Jersey", + "city": "Beaulieu" + } + }, + { + "id": 2912, + "name": "Alford Norman", + "gender": "male", + "age": 52, + "address": { + "state": "Virginia", + "city": "Delshire" + } + }, + { + "id": 2913, + "name": "Roseann Hensley", + "gender": "female", + "age": 68, + "address": { + "state": "North Dakota", + "city": "Wolcott" + } + }, + { + "id": 2914, + "name": "Beryl Knox", + "gender": "female", + "age": 55, + "address": { + "state": "Maryland", + "city": "Bynum" + } + }, + { + "id": 2915, + "name": "Dorthy Austin", + "gender": "female", + "age": 29, + "address": { + "state": "Delaware", + "city": "Ahwahnee" + } + }, + { + "id": 2916, + "name": "Kemp Stone", + "gender": "male", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Cavalero" + } + }, + { + "id": 2917, + "name": "Carole Santos", + "gender": "female", + "age": 42, + "address": { + "state": "Mississippi", + "city": "Greenbackville" + } + }, + { + "id": 2918, + "name": "Hudson Colon", + "gender": "male", + "age": 36, + "address": { + "state": "South Dakota", + "city": "Carbonville" + } + }, + { + "id": 2919, + "name": "Jean Rojas", + "gender": "female", + "age": 17, + "address": { + "state": "Idaho", + "city": "Bethpage" + } + }, + { + "id": 2920, + "name": "Lynn Peterson", + "gender": "male", + "age": 62, + "address": { + "state": "Kentucky", + "city": "Riviera" + } + }, + { + "id": 2921, + "name": "Tisha Rivera", + "gender": "female", + "age": 65, + "address": { + "state": "Missouri", + "city": "Juarez" + } + }, + { + "id": 2922, + "name": "Fry Romero", + "gender": "male", + "age": 43, + "address": { + "state": "Arizona", + "city": "Volta" + } + }, + { + "id": 2923, + "name": "Tina Russo", + "gender": "female", + "age": 63, + "address": { + "state": "Arkansas", + "city": "Sidman" + } + }, + { + "id": 2924, + "name": "Rowland Mcguire", + "gender": "male", + "age": 30, + "address": { + "state": "Georgia", + "city": "Brooktrails" + } + }, + { + "id": 2925, + "name": "Mosley Baker", + "gender": "male", + "age": 49, + "address": { + "state": "New York", + "city": "Bennett" + } + }, + { + "id": 2926, + "name": "Sarah Trevino", + "gender": "female", + "age": 59, + "address": { + "state": "California", + "city": "Teasdale" + } + }, + { + "id": 2927, + "name": "Wright Garrison", + "gender": "male", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Suitland" + } + }, + { + "id": 2928, + "name": "Tessa Collier", + "gender": "female", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Veyo" + } + }, + { + "id": 2929, + "name": "Tameka Jimenez", + "gender": "female", + "age": 58, + "address": { + "state": "Vermont", + "city": "Dyckesville" + } + }, + { + "id": 2930, + "name": "Perkins Atkins", + "gender": "male", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Nogal" + } + }, + { + "id": 2931, + "name": "Vera Gilliam", + "gender": "female", + "age": 32, + "address": { + "state": "Oklahoma", + "city": "Cataract" + } + }, + { + "id": 2932, + "name": "Blankenship Ballard", + "gender": "male", + "age": 81, + "address": { + "state": "Oregon", + "city": "Chumuckla" + } + }, + { + "id": 2933, + "name": "Gonzalez Levy", + "gender": "male", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Greensburg" + } + }, + { + "id": 2934, + "name": "Jeannie Meyer", + "gender": "female", + "age": 42, + "address": { + "state": "Illinois", + "city": "Juntura" + } + }, + { + "id": 2935, + "name": "Caroline Serrano", + "gender": "female", + "age": 23, + "address": { + "state": "Nebraska", + "city": "Summerset" + } + }, + { + "id": 2936, + "name": "Mcneil Salinas", + "gender": "male", + "age": 50, + "address": { + "state": "Michigan", + "city": "Stonybrook" + } + }, + { + "id": 2937, + "name": "Mathews Robertson", + "gender": "male", + "age": 33, + "address": { + "state": "Kansas", + "city": "Driftwood" + } + }, + { + "id": 2938, + "name": "Sofia Ortiz", + "gender": "female", + "age": 17, + "address": { + "state": "Texas", + "city": "Ruckersville" + } + }, + { + "id": 2939, + "name": "Kristine Howard", + "gender": "female", + "age": 78, + "address": { + "state": "Wisconsin", + "city": "Evergreen" + } + }, + { + "id": 2940, + "name": "Mara Myers", + "gender": "female", + "age": 70, + "address": { + "state": "Alaska", + "city": "Smeltertown" + } + }, + { + "id": 2941, + "name": "Shana Burgess", + "gender": "female", + "age": 50, + "address": { + "state": "Mississippi", + "city": "Bendon" + } + }, + { + "id": 2942, + "name": "Lynda Hamilton", + "gender": "female", + "age": 45, + "address": { + "state": "Nevada", + "city": "Sanders" + } + }, + { + "id": 2943, + "name": "Mable Day", + "gender": "female", + "age": 56, + "address": { + "state": "Maine", + "city": "Summerfield" + } + }, + { + "id": 2944, + "name": "Gonzales Justice", + "gender": "male", + "age": 17, + "address": { + "state": "Colorado", + "city": "Maury" + } + }, + { + "id": 2945, + "name": "Beck Mccullough", + "gender": "male", + "age": 18, + "address": { + "state": "New Hampshire", + "city": "Caroleen" + } + }, + { + "id": 2946, + "name": "Huff Mullen", + "gender": "male", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Tooleville" + } + }, + { + "id": 2947, + "name": "Rachelle Yang", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Saranap" + } + }, + { + "id": 2948, + "name": "Rhonda Brady", + "gender": "female", + "age": 68, + "address": { + "state": "Alabama", + "city": "Frank" + } + }, + { + "id": 2949, + "name": "Gonzalez Dunlap", + "gender": "male", + "age": 41, + "address": { + "state": "Illinois", + "city": "Kingstowne" + } + }, + { + "id": 2950, + "name": "Noemi Carroll", + "gender": "female", + "age": 33, + "address": { + "state": "South Dakota", + "city": "Coldiron" + } + }, + { + "id": 2951, + "name": "Smith Jacobson", + "gender": "male", + "age": 20, + "address": { + "state": "New Jersey", + "city": "Rosine" + } + }, + { + "id": 2952, + "name": "Patty Burton", + "gender": "female", + "age": 68, + "address": { + "state": "Washington", + "city": "Byrnedale" + } + }, + { + "id": 2953, + "name": "Ford Pearson", + "gender": "male", + "age": 65, + "address": { + "state": "Arizona", + "city": "Grahamtown" + } + }, + { + "id": 2954, + "name": "Fleming Clements", + "gender": "male", + "age": 52, + "address": { + "state": "South Carolina", + "city": "Keyport" + } + }, + { + "id": 2955, + "name": "Morton Lowe", + "gender": "male", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Buxton" + } + }, + { + "id": 2956, + "name": "Jennie Hobbs", + "gender": "female", + "age": 37, + "address": { + "state": "New York", + "city": "Westmoreland" + } + }, + { + "id": 2957, + "name": "Dale Ortega", + "gender": "female", + "age": 69, + "address": { + "state": "Missouri", + "city": "Finzel" + } + }, + { + "id": 2958, + "name": "Kent Abbott", + "gender": "male", + "age": 30, + "address": { + "state": "West Virginia", + "city": "Sultana" + } + }, + { + "id": 2959, + "name": "Patterson Levy", + "gender": "male", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Dubois" + } + }, + { + "id": 2960, + "name": "Buck Whitley", + "gender": "male", + "age": 58, + "address": { + "state": "North Dakota", + "city": "Bison" + } + }, + { + "id": 2961, + "name": "Tabatha Cherry", + "gender": "female", + "age": 76, + "address": { + "state": "Nebraska", + "city": "Diaperville" + } + }, + { + "id": 2962, + "name": "Jayne Hatfield", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Klagetoh" + } + }, + { + "id": 2963, + "name": "Hood Hernandez", + "gender": "male", + "age": 53, + "address": { + "state": "Texas", + "city": "Avalon" + } + }, + { + "id": 2964, + "name": "Hill Delacruz", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Sunbury" + } + }, + { + "id": 2965, + "name": "Alison Myers", + "gender": "female", + "age": 40, + "address": { + "state": "North Carolina", + "city": "Salix" + } + }, + { + "id": 2966, + "name": "Lynne Skinner", + "gender": "female", + "age": 75, + "address": { + "state": "Kansas", + "city": "Jacksonburg" + } + }, + { + "id": 2967, + "name": "Levine Schultz", + "gender": "male", + "age": 37, + "address": { + "state": "Wyoming", + "city": "Townsend" + } + }, + { + "id": 2968, + "name": "Lester Arnold", + "gender": "male", + "age": 30, + "address": { + "state": "Delaware", + "city": "Olney" + } + }, + { + "id": 2969, + "name": "Kristie Hurst", + "gender": "female", + "age": 18, + "address": { + "state": "Virginia", + "city": "Caberfae" + } + }, + { + "id": 2970, + "name": "Carolyn Guerra", + "gender": "female", + "age": 56, + "address": { + "state": "Indiana", + "city": "Vernon" + } + }, + { + "id": 2971, + "name": "Kathrine Mccall", + "gender": "female", + "age": 30, + "address": { + "state": "Georgia", + "city": "Hackneyville" + } + }, + { + "id": 2972, + "name": "Schneider Stone", + "gender": "male", + "age": 44, + "address": { + "state": "Utah", + "city": "Benson" + } + }, + { + "id": 2973, + "name": "Juanita Romero", + "gender": "female", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Wauhillau" + } + }, + { + "id": 2974, + "name": "Lott Molina", + "gender": "male", + "age": 42, + "address": { + "state": "Iowa", + "city": "Chamberino" + } + }, + { + "id": 2975, + "name": "Blevins May", + "gender": "male", + "age": 54, + "address": { + "state": "Rhode Island", + "city": "Roeville" + } + }, + { + "id": 2976, + "name": "Doreen Bowen", + "gender": "female", + "age": 77, + "address": { + "state": "Florida", + "city": "Fontanelle" + } + }, + { + "id": 2977, + "name": "Iris Mitchell", + "gender": "female", + "age": 50, + "address": { + "state": "New Mexico", + "city": "Tryon" + } + }, + { + "id": 2978, + "name": "Madden Vazquez", + "gender": "male", + "age": 38, + "address": { + "state": "Montana", + "city": "Brandermill" + } + }, + { + "id": 2979, + "name": "Hannah Bolton", + "gender": "female", + "age": 38, + "address": { + "state": "Maryland", + "city": "Harborton" + } + }, + { + "id": 2980, + "name": "Dionne Bright", + "gender": "female", + "age": 46, + "address": { + "state": "Vermont", + "city": "Harmon" + } + }, + { + "id": 2981, + "name": "Francine Mcclure", + "gender": "female", + "age": 20, + "address": { + "state": "Oregon", + "city": "Urie" + } + }, + { + "id": 2982, + "name": "Dorothea Padilla", + "gender": "female", + "age": 51, + "address": { + "state": "Wisconsin", + "city": "Kerby" + } + }, + { + "id": 2983, + "name": "Danielle Moody", + "gender": "female", + "age": 60, + "address": { + "state": "Michigan", + "city": "Chical" + } + }, + { + "id": 2984, + "name": "Lamb Simmons", + "gender": "male", + "age": 28, + "address": { + "state": "Arkansas", + "city": "Kenvil" + } + }, + { + "id": 2985, + "name": "Martinez Montgomery", + "gender": "male", + "age": 78, + "address": { + "state": "Ohio", + "city": "Defiance" + } + }, + { + "id": 2986, + "name": "Emilia Buckley", + "gender": "female", + "age": 28, + "address": { + "state": "Connecticut", + "city": "Sardis" + } + }, + { + "id": 2987, + "name": "Lily Gray", + "gender": "female", + "age": 21, + "address": { + "state": "Tennessee", + "city": "Trona" + } + }, + { + "id": 2988, + "name": "Evangelina Allison", + "gender": "female", + "age": 74, + "address": { + "state": "Minnesota", + "city": "Whitmer" + } + }, + { + "id": 2989, + "name": "Corine Hurley", + "gender": "female", + "age": 77, + "address": { + "state": "New Hampshire", + "city": "Blue" + } + }, + { + "id": 2990, + "name": "Sheri Whitney", + "gender": "female", + "age": 80, + "address": { + "state": "Rhode Island", + "city": "Roderfield" + } + }, + { + "id": 2991, + "name": "Hazel Sullivan", + "gender": "female", + "age": 29, + "address": { + "state": "Utah", + "city": "Staples" + } + }, + { + "id": 2992, + "name": "Joanna Schroeder", + "gender": "female", + "age": 53, + "address": { + "state": "Texas", + "city": "Neibert" + } + }, + { + "id": 2993, + "name": "Sofia Knox", + "gender": "female", + "age": 81, + "address": { + "state": "Minnesota", + "city": "Tibbie" + } + }, + { + "id": 2994, + "name": "Roy Duke", + "gender": "male", + "age": 22, + "address": { + "state": "Oregon", + "city": "Kirk" + } + }, + { + "id": 2995, + "name": "Walls Delgado", + "gender": "male", + "age": 20, + "address": { + "state": "Maryland", + "city": "Sandston" + } + }, + { + "id": 2996, + "name": "Thomas Brewer", + "gender": "male", + "age": 53, + "address": { + "state": "Indiana", + "city": "Richville" + } + }, + { + "id": 2997, + "name": "Walter Roman", + "gender": "male", + "age": 32, + "address": { + "state": "Ohio", + "city": "Felt" + } + }, + { + "id": 2998, + "name": "Mccullough Ashley", + "gender": "male", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Ronco" + } + }, + { + "id": 2999, + "name": "Winnie Donovan", + "gender": "female", + "age": 50, + "address": { + "state": "Arizona", + "city": "Matthews" + } + }, + { + "id": 3000, + "name": "Cantu Solomon", + "gender": "male", + "age": 80, + "address": { + "state": "Missouri", + "city": "Trexlertown" + } + }, + { + "id": 3001, + "name": "Tamera Bailey", + "gender": "female", + "age": 37, + "address": { + "state": "Virginia", + "city": "Stouchsburg" + } + }, + { + "id": 3002, + "name": "Letha Hurst", + "gender": "female", + "age": 72, + "address": { + "state": "Alabama", + "city": "Datil" + } + }, + { + "id": 3003, + "name": "Villarreal Willis", + "gender": "male", + "age": 21, + "address": { + "state": "Connecticut", + "city": "Hardyville" + } + }, + { + "id": 3004, + "name": "Regina Lynn", + "gender": "female", + "age": 43, + "address": { + "state": "South Carolina", + "city": "Cucumber" + } + }, + { + "id": 3005, + "name": "Baldwin Rosario", + "gender": "male", + "age": 74, + "address": { + "state": "California", + "city": "Cobbtown" + } + }, + { + "id": 3006, + "name": "Talley Weiss", + "gender": "male", + "age": 59, + "address": { + "state": "Delaware", + "city": "Vale" + } + }, + { + "id": 3007, + "name": "Elinor Knowles", + "gender": "female", + "age": 25, + "address": { + "state": "Michigan", + "city": "Teasdale" + } + }, + { + "id": 3008, + "name": "Nannie Beach", + "gender": "female", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Rowe" + } + }, + { + "id": 3009, + "name": "Gomez Rose", + "gender": "male", + "age": 31, + "address": { + "state": "South Dakota", + "city": "Adelino" + } + }, + { + "id": 3010, + "name": "Crosby Ford", + "gender": "male", + "age": 19, + "address": { + "state": "New Jersey", + "city": "Rose" + } + }, + { + "id": 3011, + "name": "Renee Lawson", + "gender": "female", + "age": 34, + "address": { + "state": "Maine", + "city": "Yorklyn" + } + }, + { + "id": 3012, + "name": "Osborn Andrews", + "gender": "male", + "age": 67, + "address": { + "state": "Oklahoma", + "city": "Klondike" + } + }, + { + "id": 3013, + "name": "Bright Copeland", + "gender": "male", + "age": 69, + "address": { + "state": "West Virginia", + "city": "Selma" + } + }, + { + "id": 3014, + "name": "Wallace Bradford", + "gender": "male", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Lutsen" + } + }, + { + "id": 3015, + "name": "Lindsay Watson", + "gender": "male", + "age": 49, + "address": { + "state": "Montana", + "city": "Gorham" + } + }, + { + "id": 3016, + "name": "Acosta Ray", + "gender": "male", + "age": 19, + "address": { + "state": "Nebraska", + "city": "Summertown" + } + }, + { + "id": 3017, + "name": "Little Mann", + "gender": "male", + "age": 60, + "address": { + "state": "Mississippi", + "city": "Gulf" + } + }, + { + "id": 3018, + "name": "Rowe Koch", + "gender": "male", + "age": 32, + "address": { + "state": "Georgia", + "city": "Neahkahnie" + } + }, + { + "id": 3019, + "name": "Mcdonald Barrera", + "gender": "male", + "age": 37, + "address": { + "state": "Florida", + "city": "Brewster" + } + }, + { + "id": 3020, + "name": "Sweeney Sweeney", + "gender": "male", + "age": 38, + "address": { + "state": "New York", + "city": "Chalfant" + } + }, + { + "id": 3021, + "name": "Lelia Lowe", + "gender": "female", + "age": 77, + "address": { + "state": "Illinois", + "city": "Westmoreland" + } + }, + { + "id": 3022, + "name": "Janis Moody", + "gender": "female", + "age": 78, + "address": { + "state": "Tennessee", + "city": "Biehle" + } + }, + { + "id": 3023, + "name": "George Gonzalez", + "gender": "male", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Martell" + } + }, + { + "id": 3024, + "name": "Robbie Hays", + "gender": "female", + "age": 60, + "address": { + "state": "Kentucky", + "city": "Wyoming" + } + }, + { + "id": 3025, + "name": "Pope Doyle", + "gender": "male", + "age": 62, + "address": { + "state": "Iowa", + "city": "Calpine" + } + }, + { + "id": 3026, + "name": "Vaughan Maddox", + "gender": "male", + "age": 55, + "address": { + "state": "New Mexico", + "city": "Edenburg" + } + }, + { + "id": 3027, + "name": "Hoover Black", + "gender": "male", + "age": 60, + "address": { + "state": "Alaska", + "city": "Durham" + } + }, + { + "id": 3028, + "name": "Kathrine Hatfield", + "gender": "female", + "age": 42, + "address": { + "state": "Colorado", + "city": "Ladera" + } + }, + { + "id": 3029, + "name": "Carroll Finch", + "gender": "male", + "age": 38, + "address": { + "state": "Vermont", + "city": "Gardners" + } + }, + { + "id": 3030, + "name": "Deirdre Marshall", + "gender": "female", + "age": 45, + "address": { + "state": "North Dakota", + "city": "Kohatk" + } + }, + { + "id": 3031, + "name": "Alvarez Martinez", + "gender": "male", + "age": 62, + "address": { + "state": "Nevada", + "city": "Shasta" + } + }, + { + "id": 3032, + "name": "Kelley Shepherd", + "gender": "female", + "age": 59, + "address": { + "state": "Wisconsin", + "city": "Woodruff" + } + }, + { + "id": 3033, + "name": "Lou Beard", + "gender": "female", + "age": 57, + "address": { + "state": "Kansas", + "city": "Bradenville" + } + }, + { + "id": 3034, + "name": "Lambert Lowery", + "gender": "male", + "age": 71, + "address": { + "state": "Massachusetts", + "city": "Yardville" + } + }, + { + "id": 3035, + "name": "Jamie Alvarado", + "gender": "female", + "age": 63, + "address": { + "state": "Wyoming", + "city": "Moscow" + } + }, + { + "id": 3036, + "name": "Cole Peters", + "gender": "male", + "age": 25, + "address": { + "state": "Idaho", + "city": "Sanders" + } + }, + { + "id": 3037, + "name": "Hobbs Horton", + "gender": "male", + "age": 67, + "address": { + "state": "Washington", + "city": "Marbury" + } + }, + { + "id": 3038, + "name": "Estrada Lott", + "gender": "male", + "age": 60, + "address": { + "state": "Arkansas", + "city": "Brutus" + } + }, + { + "id": 3039, + "name": "Jeanie Walter", + "gender": "female", + "age": 46, + "address": { + "state": "Vermont", + "city": "Waiohinu" + } + }, + { + "id": 3040, + "name": "Patel Oneal", + "gender": "male", + "age": 28, + "address": { + "state": "Illinois", + "city": "Loomis" + } + }, + { + "id": 3041, + "name": "Rosa Morgan", + "gender": "female", + "age": 66, + "address": { + "state": "New Jersey", + "city": "Lloyd" + } + }, + { + "id": 3042, + "name": "Mildred Horne", + "gender": "female", + "age": 46, + "address": { + "state": "Maine", + "city": "Gardiner" + } + }, + { + "id": 3043, + "name": "Kramer Wagner", + "gender": "male", + "age": 31, + "address": { + "state": "Ohio", + "city": "Crawfordsville" + } + }, + { + "id": 3044, + "name": "Montoya David", + "gender": "male", + "age": 36, + "address": { + "state": "Maryland", + "city": "Levant" + } + }, + { + "id": 3045, + "name": "Cummings Parsons", + "gender": "male", + "age": 39, + "address": { + "state": "Pennsylvania", + "city": "Grapeview" + } + }, + { + "id": 3046, + "name": "Kay Buckner", + "gender": "female", + "age": 53, + "address": { + "state": "Utah", + "city": "Dargan" + } + }, + { + "id": 3047, + "name": "Latonya Schultz", + "gender": "female", + "age": 73, + "address": { + "state": "Connecticut", + "city": "Riegelwood" + } + }, + { + "id": 3048, + "name": "Carla Owens", + "gender": "female", + "age": 66, + "address": { + "state": "Oregon", + "city": "Linganore" + } + }, + { + "id": 3049, + "name": "Cantrell Lindsay", + "gender": "male", + "age": 60, + "address": { + "state": "Texas", + "city": "Fairhaven" + } + }, + { + "id": 3050, + "name": "Haynes Stafford", + "gender": "male", + "age": 61, + "address": { + "state": "Oklahoma", + "city": "Osage" + } + }, + { + "id": 3051, + "name": "English Dickson", + "gender": "male", + "age": 74, + "address": { + "state": "Alabama", + "city": "Churchill" + } + }, + { + "id": 3052, + "name": "May Elliott", + "gender": "male", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Fostoria" + } + }, + { + "id": 3053, + "name": "Estelle Heath", + "gender": "female", + "age": 27, + "address": { + "state": "Nebraska", + "city": "Ona" + } + }, + { + "id": 3054, + "name": "Shepherd Craig", + "gender": "male", + "age": 30, + "address": { + "state": "Minnesota", + "city": "Cumminsville" + } + }, + { + "id": 3055, + "name": "Blanchard Velazquez", + "gender": "male", + "age": 35, + "address": { + "state": "West Virginia", + "city": "Dunnavant" + } + }, + { + "id": 3056, + "name": "Leta Hunter", + "gender": "female", + "age": 73, + "address": { + "state": "South Dakota", + "city": "Durham" + } + }, + { + "id": 3057, + "name": "Kemp Villarreal", + "gender": "male", + "age": 32, + "address": { + "state": "New Mexico", + "city": "Whitehaven" + } + }, + { + "id": 3058, + "name": "Vazquez Williams", + "gender": "male", + "age": 52, + "address": { + "state": "Massachusetts", + "city": "Lithium" + } + }, + { + "id": 3059, + "name": "Shelby Massey", + "gender": "female", + "age": 66, + "address": { + "state": "New York", + "city": "Takilma" + } + }, + { + "id": 3060, + "name": "Hayden Parrish", + "gender": "male", + "age": 53, + "address": { + "state": "Louisiana", + "city": "Belleview" + } + }, + { + "id": 3061, + "name": "Freeman Hinton", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Brookfield" + } + }, + { + "id": 3062, + "name": "Maryellen Salazar", + "gender": "female", + "age": 49, + "address": { + "state": "Kentucky", + "city": "Tonopah" + } + }, + { + "id": 3063, + "name": "Pearl Harding", + "gender": "female", + "age": 70, + "address": { + "state": "Idaho", + "city": "Bedias" + } + }, + { + "id": 3064, + "name": "Stacie Bentley", + "gender": "female", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Greenwich" + } + }, + { + "id": 3065, + "name": "Roxanne Wells", + "gender": "female", + "age": 44, + "address": { + "state": "Missouri", + "city": "Bellamy" + } + }, + { + "id": 3066, + "name": "Vanessa Santana", + "gender": "female", + "age": 30, + "address": { + "state": "Kansas", + "city": "Finderne" + } + }, + { + "id": 3067, + "name": "Marsh Mcfadden", + "gender": "male", + "age": 81, + "address": { + "state": "Colorado", + "city": "Beaverdale" + } + }, + { + "id": 3068, + "name": "Colon Murphy", + "gender": "male", + "age": 26, + "address": { + "state": "Nevada", + "city": "Kula" + } + }, + { + "id": 3069, + "name": "Kristen Kirk", + "gender": "female", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Reno" + } + }, + { + "id": 3070, + "name": "Watkins Chapman", + "gender": "male", + "age": 36, + "address": { + "state": "Washington", + "city": "Drytown" + } + }, + { + "id": 3071, + "name": "Britney Brown", + "gender": "female", + "age": 80, + "address": { + "state": "Delaware", + "city": "Southmont" + } + }, + { + "id": 3072, + "name": "Florence Callahan", + "gender": "female", + "age": 40, + "address": { + "state": "Michigan", + "city": "Basye" + } + }, + { + "id": 3073, + "name": "Sherman Miranda", + "gender": "male", + "age": 40, + "address": { + "state": "Mississippi", + "city": "Ladera" + } + }, + { + "id": 3074, + "name": "Ray Hogan", + "gender": "male", + "age": 63, + "address": { + "state": "New Hampshire", + "city": "Marion" + } + }, + { + "id": 3075, + "name": "Cristina Wise", + "gender": "female", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Chapin" + } + }, + { + "id": 3076, + "name": "Zimmerman Webster", + "gender": "male", + "age": 79, + "address": { + "state": "Arizona", + "city": "Glidden" + } + }, + { + "id": 3077, + "name": "Beatrice Frye", + "gender": "female", + "age": 26, + "address": { + "state": "North Carolina", + "city": "Edneyville" + } + }, + { + "id": 3078, + "name": "Robbins Riddle", + "gender": "male", + "age": 29, + "address": { + "state": "Indiana", + "city": "Greer" + } + }, + { + "id": 3079, + "name": "Mcdowell Davis", + "gender": "male", + "age": 38, + "address": { + "state": "Rhode Island", + "city": "Golconda" + } + }, + { + "id": 3080, + "name": "Deleon Harrell", + "gender": "male", + "age": 79, + "address": { + "state": "Tennessee", + "city": "Hendersonville" + } + }, + { + "id": 3081, + "name": "Carmen Gilliam", + "gender": "female", + "age": 33, + "address": { + "state": "Montana", + "city": "Blende" + } + }, + { + "id": 3082, + "name": "Hammond Harvey", + "gender": "male", + "age": 65, + "address": { + "state": "North Dakota", + "city": "Orviston" + } + }, + { + "id": 3083, + "name": "Middleton Schroeder", + "gender": "male", + "age": 47, + "address": { + "state": "Iowa", + "city": "Robinette" + } + }, + { + "id": 3084, + "name": "Aline Harrison", + "gender": "female", + "age": 42, + "address": { + "state": "Alaska", + "city": "Gilmore" + } + }, + { + "id": 3085, + "name": "Shawn Ramsey", + "gender": "female", + "age": 34, + "address": { + "state": "Virginia", + "city": "Stagecoach" + } + }, + { + "id": 3086, + "name": "Jacquelyn Hyde", + "gender": "female", + "age": 68, + "address": { + "state": "California", + "city": "Guthrie" + } + }, + { + "id": 3087, + "name": "Bradford Gallagher", + "gender": "male", + "age": 67, + "address": { + "state": "Colorado", + "city": "Holtville" + } + }, + { + "id": 3088, + "name": "Davenport Blackwell", + "gender": "male", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Wattsville" + } + }, + { + "id": 3089, + "name": "Blankenship Kerr", + "gender": "male", + "age": 46, + "address": { + "state": "Pennsylvania", + "city": "Barclay" + } + }, + { + "id": 3090, + "name": "Constance Kidd", + "gender": "female", + "age": 80, + "address": { + "state": "Montana", + "city": "Eastmont" + } + }, + { + "id": 3091, + "name": "Schroeder Pacheco", + "gender": "male", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Reinerton" + } + }, + { + "id": 3092, + "name": "Bird Padilla", + "gender": "male", + "age": 44, + "address": { + "state": "Kansas", + "city": "Fairforest" + } + }, + { + "id": 3093, + "name": "Selena Knight", + "gender": "female", + "age": 59, + "address": { + "state": "Missouri", + "city": "Conway" + } + }, + { + "id": 3094, + "name": "Araceli Dominguez", + "gender": "female", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Chicopee" + } + }, + { + "id": 3095, + "name": "Burris Rasmussen", + "gender": "male", + "age": 31, + "address": { + "state": "North Dakota", + "city": "Cliffside" + } + }, + { + "id": 3096, + "name": "Trisha Vega", + "gender": "female", + "age": 48, + "address": { + "state": "Ohio", + "city": "Chesterfield" + } + }, + { + "id": 3097, + "name": "Simpson Grant", + "gender": "male", + "age": 18, + "address": { + "state": "Iowa", + "city": "Warren" + } + }, + { + "id": 3098, + "name": "Katharine Mcguire", + "gender": "female", + "age": 62, + "address": { + "state": "Oklahoma", + "city": "Orviston" + } + }, + { + "id": 3099, + "name": "Mcconnell Sharpe", + "gender": "male", + "age": 78, + "address": { + "state": "Wyoming", + "city": "Darrtown" + } + }, + { + "id": 3100, + "name": "Carey Wilkins", + "gender": "male", + "age": 39, + "address": { + "state": "Hawaii", + "city": "Falmouth" + } + }, + { + "id": 3101, + "name": "Ayala Tran", + "gender": "male", + "age": 23, + "address": { + "state": "Delaware", + "city": "Highland" + } + }, + { + "id": 3102, + "name": "Abigail Burnett", + "gender": "female", + "age": 47, + "address": { + "state": "New York", + "city": "Wildwood" + } + }, + { + "id": 3103, + "name": "Shelton Hicks", + "gender": "male", + "age": 24, + "address": { + "state": "Florida", + "city": "Day" + } + }, + { + "id": 3104, + "name": "Willis Welch", + "gender": "male", + "age": 75, + "address": { + "state": "South Carolina", + "city": "Loma" + } + }, + { + "id": 3105, + "name": "Diana Forbes", + "gender": "female", + "age": 60, + "address": { + "state": "California", + "city": "Grantville" + } + }, + { + "id": 3106, + "name": "Anita Spears", + "gender": "female", + "age": 50, + "address": { + "state": "North Carolina", + "city": "Faxon" + } + }, + { + "id": 3107, + "name": "Whitney Watson", + "gender": "male", + "age": 35, + "address": { + "state": "Arkansas", + "city": "Orovada" + } + }, + { + "id": 3108, + "name": "Bobbie Griffith", + "gender": "female", + "age": 81, + "address": { + "state": "Michigan", + "city": "Moraida" + } + }, + { + "id": 3109, + "name": "Simmons Ford", + "gender": "male", + "age": 38, + "address": { + "state": "South Dakota", + "city": "Westerville" + } + }, + { + "id": 3110, + "name": "Gina Sullivan", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Denio" + } + }, + { + "id": 3111, + "name": "Adrienne Holman", + "gender": "female", + "age": 69, + "address": { + "state": "Nevada", + "city": "Ogema" + } + }, + { + "id": 3112, + "name": "Boyle Livingston", + "gender": "male", + "age": 54, + "address": { + "state": "Texas", + "city": "Vandiver" + } + }, + { + "id": 3113, + "name": "Pennington Rosales", + "gender": "male", + "age": 70, + "address": { + "state": "Tennessee", + "city": "Villarreal" + } + }, + { + "id": 3114, + "name": "Clare Dejesus", + "gender": "female", + "age": 71, + "address": { + "state": "New Jersey", + "city": "Fairlee" + } + }, + { + "id": 3115, + "name": "Ellen Sanchez", + "gender": "female", + "age": 22, + "address": { + "state": "New Mexico", + "city": "Hackneyville" + } + }, + { + "id": 3116, + "name": "Ana Roy", + "gender": "female", + "age": 31, + "address": { + "state": "Washington", + "city": "Bowden" + } + }, + { + "id": 3117, + "name": "Watts Bryant", + "gender": "male", + "age": 79, + "address": { + "state": "New Hampshire", + "city": "Whitmer" + } + }, + { + "id": 3118, + "name": "Josefa May", + "gender": "female", + "age": 59, + "address": { + "state": "Alaska", + "city": "Veguita" + } + }, + { + "id": 3119, + "name": "Jolene Oneal", + "gender": "female", + "age": 40, + "address": { + "state": "Utah", + "city": "Nadine" + } + }, + { + "id": 3120, + "name": "Helene Bonner", + "gender": "female", + "age": 70, + "address": { + "state": "West Virginia", + "city": "Saticoy" + } + }, + { + "id": 3121, + "name": "Kimberley Russo", + "gender": "female", + "age": 40, + "address": { + "state": "Arizona", + "city": "Bladensburg" + } + }, + { + "id": 3122, + "name": "Bettye Stevenson", + "gender": "female", + "age": 56, + "address": { + "state": "Oregon", + "city": "Rodman" + } + }, + { + "id": 3123, + "name": "Bray Alston", + "gender": "male", + "age": 68, + "address": { + "state": "Georgia", + "city": "Franklin" + } + }, + { + "id": 3124, + "name": "Rosalinda Adams", + "gender": "female", + "age": 23, + "address": { + "state": "Vermont", + "city": "Guthrie" + } + }, + { + "id": 3125, + "name": "Heather Caldwell", + "gender": "female", + "age": 40, + "address": { + "state": "Louisiana", + "city": "Sena" + } + }, + { + "id": 3126, + "name": "Hogan Byers", + "gender": "male", + "age": 18, + "address": { + "state": "Virginia", + "city": "Fillmore" + } + }, + { + "id": 3127, + "name": "Clements Whitney", + "gender": "male", + "age": 62, + "address": { + "state": "Alabama", + "city": "Smock" + } + }, + { + "id": 3128, + "name": "Brandie Steele", + "gender": "female", + "age": 49, + "address": { + "state": "Massachusetts", + "city": "Ventress" + } + }, + { + "id": 3129, + "name": "Elise Hendrix", + "gender": "female", + "age": 18, + "address": { + "state": "Kentucky", + "city": "Cartwright" + } + }, + { + "id": 3130, + "name": "Robertson York", + "gender": "male", + "age": 54, + "address": { + "state": "Rhode Island", + "city": "Rose" + } + }, + { + "id": 3131, + "name": "Hansen Rosario", + "gender": "male", + "age": 64, + "address": { + "state": "Maine", + "city": "Rote" + } + }, + { + "id": 3132, + "name": "Sharlene Ochoa", + "gender": "female", + "age": 22, + "address": { + "state": "Connecticut", + "city": "Mooresburg" + } + }, + { + "id": 3133, + "name": "Ross Sykes", + "gender": "male", + "age": 33, + "address": { + "state": "Illinois", + "city": "Kerby" + } + }, + { + "id": 3134, + "name": "Katelyn Frost", + "gender": "female", + "age": 57, + "address": { + "state": "Maryland", + "city": "Northridge" + } + }, + { + "id": 3135, + "name": "Stevens White", + "gender": "male", + "age": 51, + "address": { + "state": "Mississippi", + "city": "Wescosville" + } + }, + { + "id": 3136, + "name": "Pollard Butler", + "gender": "male", + "age": 32, + "address": { + "state": "Florida", + "city": "Rockhill" + } + }, + { + "id": 3137, + "name": "Bowers Nichols", + "gender": "male", + "age": 31, + "address": { + "state": "Nevada", + "city": "Klondike" + } + }, + { + "id": 3138, + "name": "Ivy Gonzalez", + "gender": "female", + "age": 34, + "address": { + "state": "New York", + "city": "Bethpage" + } + }, + { + "id": 3139, + "name": "Kristina Holden", + "gender": "female", + "age": 40, + "address": { + "state": "Rhode Island", + "city": "Falmouth" + } + }, + { + "id": 3140, + "name": "Minnie Goodwin", + "gender": "female", + "age": 23, + "address": { + "state": "North Dakota", + "city": "Waukeenah" + } + }, + { + "id": 3141, + "name": "Wiggins Burnett", + "gender": "male", + "age": 45, + "address": { + "state": "Tennessee", + "city": "Loveland" + } + }, + { + "id": 3142, + "name": "Faith Weiss", + "gender": "female", + "age": 20, + "address": { + "state": "Minnesota", + "city": "Independence" + } + }, + { + "id": 3143, + "name": "Farley Schneider", + "gender": "male", + "age": 76, + "address": { + "state": "Delaware", + "city": "Sisquoc" + } + }, + { + "id": 3144, + "name": "Sophia Townsend", + "gender": "female", + "age": 17, + "address": { + "state": "New Hampshire", + "city": "Crucible" + } + }, + { + "id": 3145, + "name": "Michael Kirby", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Cherokee" + } + }, + { + "id": 3146, + "name": "Hattie Estrada", + "gender": "female", + "age": 35, + "address": { + "state": "Virginia", + "city": "Nile" + } + }, + { + "id": 3147, + "name": "Carr Workman", + "gender": "male", + "age": 37, + "address": { + "state": "Kansas", + "city": "Callaghan" + } + }, + { + "id": 3148, + "name": "Annette Mcfadden", + "gender": "female", + "age": 24, + "address": { + "state": "Arkansas", + "city": "Gloucester" + } + }, + { + "id": 3149, + "name": "Cole Bailey", + "gender": "male", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Garnet" + } + }, + { + "id": 3150, + "name": "Roy Gallagher", + "gender": "male", + "age": 70, + "address": { + "state": "Pennsylvania", + "city": "Wheatfields" + } + }, + { + "id": 3151, + "name": "Herrera Dyer", + "gender": "male", + "age": 69, + "address": { + "state": "Missouri", + "city": "Farmers" + } + }, + { + "id": 3152, + "name": "Keller Osborn", + "gender": "male", + "age": 51, + "address": { + "state": "Wisconsin", + "city": "Gardiner" + } + }, + { + "id": 3153, + "name": "Brennan Park", + "gender": "male", + "age": 51, + "address": { + "state": "Maine", + "city": "Ventress" + } + }, + { + "id": 3154, + "name": "Fleming Hess", + "gender": "male", + "age": 22, + "address": { + "state": "Nebraska", + "city": "Eastmont" + } + }, + { + "id": 3155, + "name": "Foster Henry", + "gender": "male", + "age": 20, + "address": { + "state": "Colorado", + "city": "Greenbackville" + } + }, + { + "id": 3156, + "name": "Lauri Conrad", + "gender": "female", + "age": 35, + "address": { + "state": "Alaska", + "city": "Heil" + } + }, + { + "id": 3157, + "name": "Payne Avila", + "gender": "male", + "age": 23, + "address": { + "state": "Kentucky", + "city": "Rosedale" + } + }, + { + "id": 3158, + "name": "Tracy Harmon", + "gender": "female", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Celeryville" + } + }, + { + "id": 3159, + "name": "Lucinda Waller", + "gender": "female", + "age": 59, + "address": { + "state": "North Carolina", + "city": "Ada" + } + }, + { + "id": 3160, + "name": "Joyner Morrison", + "gender": "male", + "age": 72, + "address": { + "state": "New Mexico", + "city": "Cumberland" + } + }, + { + "id": 3161, + "name": "Joyce Petersen", + "gender": "female", + "age": 23, + "address": { + "state": "Georgia", + "city": "Freeburn" + } + }, + { + "id": 3162, + "name": "Wilson Anthony", + "gender": "male", + "age": 21, + "address": { + "state": "Louisiana", + "city": "Stouchsburg" + } + }, + { + "id": 3163, + "name": "Camille Pollard", + "gender": "female", + "age": 21, + "address": { + "state": "Utah", + "city": "Goodville" + } + }, + { + "id": 3164, + "name": "Hunt Garner", + "gender": "male", + "age": 20, + "address": { + "state": "Ohio", + "city": "Stonybrook" + } + }, + { + "id": 3165, + "name": "Morse Hamilton", + "gender": "male", + "age": 72, + "address": { + "state": "West Virginia", + "city": "Kersey" + } + }, + { + "id": 3166, + "name": "Aguirre Caldwell", + "gender": "male", + "age": 29, + "address": { + "state": "Oregon", + "city": "Tyro" + } + }, + { + "id": 3167, + "name": "Frankie Lambert", + "gender": "female", + "age": 32, + "address": { + "state": "New Jersey", + "city": "Holcombe" + } + }, + { + "id": 3168, + "name": "Fowler Rasmussen", + "gender": "male", + "age": 48, + "address": { + "state": "Iowa", + "city": "Boyd" + } + }, + { + "id": 3169, + "name": "Beatrice Bowen", + "gender": "female", + "age": 22, + "address": { + "state": "California", + "city": "Zarephath" + } + }, + { + "id": 3170, + "name": "Cameron Cohen", + "gender": "male", + "age": 58, + "address": { + "state": "Oklahoma", + "city": "Lopezo" + } + }, + { + "id": 3171, + "name": "Caroline Flynn", + "gender": "female", + "age": 54, + "address": { + "state": "Washington", + "city": "Lutsen" + } + }, + { + "id": 3172, + "name": "Rowe Mccarthy", + "gender": "male", + "age": 71, + "address": { + "state": "Idaho", + "city": "Adelino" + } + }, + { + "id": 3173, + "name": "Sullivan Carlson", + "gender": "male", + "age": 58, + "address": { + "state": "Montana", + "city": "Winesburg" + } + }, + { + "id": 3174, + "name": "Carolina Sweet", + "gender": "female", + "age": 35, + "address": { + "state": "Indiana", + "city": "Lawrence" + } + }, + { + "id": 3175, + "name": "Claudette Serrano", + "gender": "female", + "age": 57, + "address": { + "state": "Illinois", + "city": "Gibbsville" + } + }, + { + "id": 3176, + "name": "Florence Baker", + "gender": "female", + "age": 62, + "address": { + "state": "Arizona", + "city": "Walton" + } + }, + { + "id": 3177, + "name": "Joanna Powell", + "gender": "female", + "age": 67, + "address": { + "state": "Vermont", + "city": "Coalmont" + } + }, + { + "id": 3178, + "name": "Mosley Guerrero", + "gender": "male", + "age": 38, + "address": { + "state": "Hawaii", + "city": "Magnolia" + } + }, + { + "id": 3179, + "name": "Rocha Gay", + "gender": "male", + "age": 49, + "address": { + "state": "Maryland", + "city": "Noblestown" + } + }, + { + "id": 3180, + "name": "Dawn England", + "gender": "female", + "age": 78, + "address": { + "state": "Wyoming", + "city": "Rutherford" + } + }, + { + "id": 3181, + "name": "Inez Riley", + "gender": "female", + "age": 43, + "address": { + "state": "South Dakota", + "city": "Terlingua" + } + }, + { + "id": 3182, + "name": "Joyce Crane", + "gender": "male", + "age": 54, + "address": { + "state": "Connecticut", + "city": "Rivera" + } + }, + { + "id": 3183, + "name": "Kendra Tanner", + "gender": "female", + "age": 64, + "address": { + "state": "Michigan", + "city": "Hoehne" + } + }, + { + "id": 3184, + "name": "Allison Randolph", + "gender": "female", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Marshall" + } + }, + { + "id": 3185, + "name": "Hogan Morton", + "gender": "male", + "age": 40, + "address": { + "state": "New Mexico", + "city": "Sutton" + } + }, + { + "id": 3186, + "name": "Hansen Phelps", + "gender": "male", + "age": 30, + "address": { + "state": "Kentucky", + "city": "Dunbar" + } + }, + { + "id": 3187, + "name": "Rose Haynes", + "gender": "female", + "age": 60, + "address": { + "state": "Nevada", + "city": "Frank" + } + }, + { + "id": 3188, + "name": "Richards Terrell", + "gender": "male", + "age": 60, + "address": { + "state": "Maine", + "city": "Freetown" + } + }, + { + "id": 3189, + "name": "Enid Kirk", + "gender": "female", + "age": 61, + "address": { + "state": "Missouri", + "city": "Holtville" + } + }, + { + "id": 3190, + "name": "Stephens Edwards", + "gender": "male", + "age": 65, + "address": { + "state": "Idaho", + "city": "Talpa" + } + }, + { + "id": 3191, + "name": "Vicki Finley", + "gender": "female", + "age": 74, + "address": { + "state": "Delaware", + "city": "Mapletown" + } + }, + { + "id": 3192, + "name": "Nguyen Huffman", + "gender": "male", + "age": 61, + "address": { + "state": "North Carolina", + "city": "Ypsilanti" + } + }, + { + "id": 3193, + "name": "Sharp Levine", + "gender": "male", + "age": 35, + "address": { + "state": "Wisconsin", + "city": "Glenshaw" + } + }, + { + "id": 3194, + "name": "Sarah Berger", + "gender": "female", + "age": 52, + "address": { + "state": "Colorado", + "city": "Cresaptown" + } + }, + { + "id": 3195, + "name": "Nora Dotson", + "gender": "female", + "age": 69, + "address": { + "state": "South Carolina", + "city": "Clarktown" + } + }, + { + "id": 3196, + "name": "Hall Potts", + "gender": "male", + "age": 47, + "address": { + "state": "Oregon", + "city": "Edgar" + } + }, + { + "id": 3197, + "name": "Lara Norris", + "gender": "male", + "age": 35, + "address": { + "state": "Florida", + "city": "Osage" + } + }, + { + "id": 3198, + "name": "Tanisha Charles", + "gender": "female", + "age": 33, + "address": { + "state": "Maryland", + "city": "Sperryville" + } + }, + { + "id": 3199, + "name": "Rosemary Stevenson", + "gender": "female", + "age": 46, + "address": { + "state": "Alabama", + "city": "Veyo" + } + }, + { + "id": 3200, + "name": "Luella Bauer", + "gender": "female", + "age": 43, + "address": { + "state": "Utah", + "city": "Reno" + } + }, + { + "id": 3201, + "name": "Green Wise", + "gender": "male", + "age": 72, + "address": { + "state": "Illinois", + "city": "Kraemer" + } + }, + { + "id": 3202, + "name": "Chen Castro", + "gender": "male", + "age": 74, + "address": { + "state": "New York", + "city": "Kenvil" + } + }, + { + "id": 3203, + "name": "Huff Herrera", + "gender": "male", + "age": 59, + "address": { + "state": "Kansas", + "city": "Chase" + } + }, + { + "id": 3204, + "name": "Cynthia Buckley", + "gender": "female", + "age": 22, + "address": { + "state": "Rhode Island", + "city": "Avalon" + } + }, + { + "id": 3205, + "name": "Forbes Stanley", + "gender": "male", + "age": 20, + "address": { + "state": "Indiana", + "city": "Concho" + } + }, + { + "id": 3206, + "name": "Ila Herman", + "gender": "female", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Darlington" + } + }, + { + "id": 3207, + "name": "Brooks Kinney", + "gender": "male", + "age": 36, + "address": { + "state": "Washington", + "city": "Saranap" + } + }, + { + "id": 3208, + "name": "Fuentes Byrd", + "gender": "male", + "age": 81, + "address": { + "state": "Arkansas", + "city": "Allendale" + } + }, + { + "id": 3209, + "name": "Leanna Clements", + "gender": "female", + "age": 35, + "address": { + "state": "South Dakota", + "city": "Mathews" + } + }, + { + "id": 3210, + "name": "Gilmore Reeves", + "gender": "male", + "age": 75, + "address": { + "state": "Virginia", + "city": "Onton" + } + }, + { + "id": 3211, + "name": "Marla Riddle", + "gender": "female", + "age": 33, + "address": { + "state": "Vermont", + "city": "Grill" + } + }, + { + "id": 3212, + "name": "Cannon Ellison", + "gender": "male", + "age": 68, + "address": { + "state": "Arizona", + "city": "Logan" + } + }, + { + "id": 3213, + "name": "Nichols Peck", + "gender": "male", + "age": 66, + "address": { + "state": "Texas", + "city": "Eggertsville" + } + }, + { + "id": 3214, + "name": "Flowers Vang", + "gender": "male", + "age": 26, + "address": { + "state": "Massachusetts", + "city": "Titanic" + } + }, + { + "id": 3215, + "name": "Kelley Walker", + "gender": "female", + "age": 33, + "address": { + "state": "Louisiana", + "city": "Falmouth" + } + }, + { + "id": 3216, + "name": "Esther Estrada", + "gender": "female", + "age": 63, + "address": { + "state": "Alaska", + "city": "Biddle" + } + }, + { + "id": 3217, + "name": "Lindsay Maxwell", + "gender": "male", + "age": 76, + "address": { + "state": "New Jersey", + "city": "Byrnedale" + } + }, + { + "id": 3218, + "name": "Marion Padilla", + "gender": "female", + "age": 73, + "address": { + "state": "Iowa", + "city": "Diaperville" + } + }, + { + "id": 3219, + "name": "Schmidt Bean", + "gender": "male", + "age": 34, + "address": { + "state": "West Virginia", + "city": "Castleton" + } + }, + { + "id": 3220, + "name": "Lowery Shaw", + "gender": "male", + "age": 61, + "address": { + "state": "Nebraska", + "city": "Coleville" + } + }, + { + "id": 3221, + "name": "Herring Owen", + "gender": "male", + "age": 58, + "address": { + "state": "Connecticut", + "city": "Cowiche" + } + }, + { + "id": 3222, + "name": "Wilcox Pierce", + "gender": "male", + "age": 61, + "address": { + "state": "Pennsylvania", + "city": "Ada" + } + }, + { + "id": 3223, + "name": "Spence Dillon", + "gender": "male", + "age": 52, + "address": { + "state": "Montana", + "city": "Marienthal" + } + }, + { + "id": 3224, + "name": "Blanchard Wilkinson", + "gender": "male", + "age": 65, + "address": { + "state": "California", + "city": "Ola" + } + }, + { + "id": 3225, + "name": "Evelyn Galloway", + "gender": "female", + "age": 43, + "address": { + "state": "Tennessee", + "city": "Cetronia" + } + }, + { + "id": 3226, + "name": "Hooper Chen", + "gender": "male", + "age": 60, + "address": { + "state": "Wyoming", + "city": "Yettem" + } + }, + { + "id": 3227, + "name": "Lucy Casey", + "gender": "female", + "age": 23, + "address": { + "state": "Michigan", + "city": "Finderne" + } + }, + { + "id": 3228, + "name": "Pamela Mcdaniel", + "gender": "female", + "age": 29, + "address": { + "state": "Ohio", + "city": "Biehle" + } + }, + { + "id": 3229, + "name": "Paige Ware", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Goldfield" + } + }, + { + "id": 3230, + "name": "Sofia Perez", + "gender": "female", + "age": 64, + "address": { + "state": "Minnesota", + "city": "Craig" + } + }, + { + "id": 3231, + "name": "Blankenship Saunders", + "gender": "male", + "age": 82, + "address": { + "state": "New Hampshire", + "city": "Fruitdale" + } + }, + { + "id": 3232, + "name": "Slater Wiley", + "gender": "male", + "age": 21, + "address": { + "state": "North Dakota", + "city": "Marbury" + } + }, + { + "id": 3233, + "name": "Barbra Boone", + "gender": "female", + "age": 40, + "address": { + "state": "Hawaii", + "city": "Norwood" + } + }, + { + "id": 3234, + "name": "Ofelia Martin", + "gender": "female", + "age": 20, + "address": { + "state": "Wyoming", + "city": "Rockingham" + } + }, + { + "id": 3235, + "name": "Wood Kennedy", + "gender": "male", + "age": 51, + "address": { + "state": "Tennessee", + "city": "Deercroft" + } + }, + { + "id": 3236, + "name": "Ford Luna", + "gender": "male", + "age": 35, + "address": { + "state": "Minnesota", + "city": "Weogufka" + } + }, + { + "id": 3237, + "name": "Beryl Gilbert", + "gender": "female", + "age": 45, + "address": { + "state": "Connecticut", + "city": "Statenville" + } + }, + { + "id": 3238, + "name": "Caldwell Potter", + "gender": "male", + "age": 63, + "address": { + "state": "Vermont", + "city": "Cliff" + } + }, + { + "id": 3239, + "name": "Alisha Price", + "gender": "female", + "age": 27, + "address": { + "state": "Colorado", + "city": "Cassel" + } + }, + { + "id": 3240, + "name": "Weeks Gay", + "gender": "male", + "age": 25, + "address": { + "state": "Texas", + "city": "Kirk" + } + }, + { + "id": 3241, + "name": "Carol Jefferson", + "gender": "female", + "age": 61, + "address": { + "state": "Ohio", + "city": "Guthrie" + } + }, + { + "id": 3242, + "name": "Harper Bass", + "gender": "male", + "age": 61, + "address": { + "state": "Indiana", + "city": "Manitou" + } + }, + { + "id": 3243, + "name": "Benjamin Wooten", + "gender": "male", + "age": 57, + "address": { + "state": "Georgia", + "city": "Nicut" + } + }, + { + "id": 3244, + "name": "Christy Nieves", + "gender": "female", + "age": 72, + "address": { + "state": "New Jersey", + "city": "Chesapeake" + } + }, + { + "id": 3245, + "name": "Elliott Rowe", + "gender": "male", + "age": 52, + "address": { + "state": "Nevada", + "city": "Belgreen" + } + }, + { + "id": 3246, + "name": "Mcclain Copeland", + "gender": "male", + "age": 69, + "address": { + "state": "Florida", + "city": "Vowinckel" + } + }, + { + "id": 3247, + "name": "Lott Shields", + "gender": "male", + "age": 17, + "address": { + "state": "Kentucky", + "city": "Connerton" + } + }, + { + "id": 3248, + "name": "Hanson Barrera", + "gender": "male", + "age": 78, + "address": { + "state": "New York", + "city": "Golconda" + } + }, + { + "id": 3249, + "name": "Brandie Richard", + "gender": "female", + "age": 78, + "address": { + "state": "Oregon", + "city": "Marne" + } + }, + { + "id": 3250, + "name": "Ella Ramos", + "gender": "female", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Williams" + } + }, + { + "id": 3251, + "name": "Josephine Mcfarland", + "gender": "female", + "age": 72, + "address": { + "state": "New Hampshire", + "city": "Welch" + } + }, + { + "id": 3252, + "name": "Adams Randall", + "gender": "male", + "age": 77, + "address": { + "state": "Alabama", + "city": "Thynedale" + } + }, + { + "id": 3253, + "name": "Barlow Downs", + "gender": "male", + "age": 44, + "address": { + "state": "Washington", + "city": "Stonybrook" + } + }, + { + "id": 3254, + "name": "Roach Marsh", + "gender": "male", + "age": 50, + "address": { + "state": "Nebraska", + "city": "Grantville" + } + }, + { + "id": 3255, + "name": "Juliana Lowery", + "gender": "female", + "age": 79, + "address": { + "state": "Illinois", + "city": "Levant" + } + }, + { + "id": 3256, + "name": "Oconnor Jensen", + "gender": "male", + "age": 75, + "address": { + "state": "Louisiana", + "city": "Waukeenah" + } + }, + { + "id": 3257, + "name": "Pamela Saunders", + "gender": "female", + "age": 25, + "address": { + "state": "Delaware", + "city": "Omar" + } + }, + { + "id": 3258, + "name": "Blackburn Williamson", + "gender": "male", + "age": 30, + "address": { + "state": "Michigan", + "city": "Indio" + } + }, + { + "id": 3259, + "name": "Bell Coffey", + "gender": "male", + "age": 20, + "address": { + "state": "Massachusetts", + "city": "Motley" + } + }, + { + "id": 3260, + "name": "Norma Jenkins", + "gender": "female", + "age": 46, + "address": { + "state": "South Carolina", + "city": "Lindcove" + } + }, + { + "id": 3261, + "name": "Polly Mooney", + "gender": "female", + "age": 20, + "address": { + "state": "Idaho", + "city": "Herbster" + } + }, + { + "id": 3262, + "name": "Allen Welch", + "gender": "male", + "age": 72, + "address": { + "state": "Pennsylvania", + "city": "Escondida" + } + }, + { + "id": 3263, + "name": "Lorrie Freeman", + "gender": "female", + "age": 80, + "address": { + "state": "Maryland", + "city": "Whitmer" + } + }, + { + "id": 3264, + "name": "Julie Duke", + "gender": "female", + "age": 30, + "address": { + "state": "Maine", + "city": "Nicholson" + } + }, + { + "id": 3265, + "name": "Tasha Fuller", + "gender": "female", + "age": 71, + "address": { + "state": "North Dakota", + "city": "Williston" + } + }, + { + "id": 3266, + "name": "Josefina Shaw", + "gender": "female", + "age": 49, + "address": { + "state": "Wisconsin", + "city": "Sattley" + } + }, + { + "id": 3267, + "name": "Autumn Neal", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Madrid" + } + }, + { + "id": 3268, + "name": "House Daniels", + "gender": "male", + "age": 73, + "address": { + "state": "Kansas", + "city": "Naomi" + } + }, + { + "id": 3269, + "name": "Ellen Mendez", + "gender": "female", + "age": 42, + "address": { + "state": "West Virginia", + "city": "Lithium" + } + }, + { + "id": 3270, + "name": "Young Frye", + "gender": "female", + "age": 40, + "address": { + "state": "California", + "city": "Orviston" + } + }, + { + "id": 3271, + "name": "Dickson Valdez", + "gender": "male", + "age": 46, + "address": { + "state": "Mississippi", + "city": "Cartwright" + } + }, + { + "id": 3272, + "name": "Marian Oneill", + "gender": "female", + "age": 41, + "address": { + "state": "South Dakota", + "city": "Floris" + } + }, + { + "id": 3273, + "name": "Rowland Salazar", + "gender": "male", + "age": 44, + "address": { + "state": "Utah", + "city": "Slovan" + } + }, + { + "id": 3274, + "name": "Meyer Bentley", + "gender": "male", + "age": 45, + "address": { + "state": "Iowa", + "city": "Darlington" + } + }, + { + "id": 3275, + "name": "Petty Stanton", + "gender": "male", + "age": 74, + "address": { + "state": "Virginia", + "city": "Waumandee" + } + }, + { + "id": 3276, + "name": "Deena Crosby", + "gender": "female", + "age": 74, + "address": { + "state": "Montana", + "city": "Martell" + } + }, + { + "id": 3277, + "name": "Marcella Knapp", + "gender": "female", + "age": 22, + "address": { + "state": "Arizona", + "city": "Babb" + } + }, + { + "id": 3278, + "name": "Evans Myers", + "gender": "male", + "age": 26, + "address": { + "state": "Arkansas", + "city": "Shelby" + } + }, + { + "id": 3279, + "name": "Pansy Pearson", + "gender": "female", + "age": 51, + "address": { + "state": "Missouri", + "city": "Hilltop" + } + }, + { + "id": 3280, + "name": "Oneill Simmons", + "gender": "male", + "age": 17, + "address": { + "state": "Rhode Island", + "city": "Crown" + } + }, + { + "id": 3281, + "name": "Lizzie Carson", + "gender": "female", + "age": 61, + "address": { + "state": "Alaska", + "city": "Chase" + } + }, + { + "id": 3282, + "name": "Mildred Aguilar", + "gender": "female", + "age": 75, + "address": { + "state": "New Mexico", + "city": "Leroy" + } + }, + { + "id": 3283, + "name": "Lottie Burch", + "gender": "female", + "age": 27, + "address": { + "state": "Illinois", + "city": "Lawrence" + } + }, + { + "id": 3284, + "name": "Queen Sheppard", + "gender": "female", + "age": 28, + "address": { + "state": "Connecticut", + "city": "Klondike" + } + }, + { + "id": 3285, + "name": "Marquita Paul", + "gender": "female", + "age": 64, + "address": { + "state": "Michigan", + "city": "Brooktrails" + } + }, + { + "id": 3286, + "name": "Roberts Moses", + "gender": "male", + "age": 43, + "address": { + "state": "Hawaii", + "city": "Mulberry" + } + }, + { + "id": 3287, + "name": "Wilder Joyce", + "gender": "male", + "age": 65, + "address": { + "state": "Massachusetts", + "city": "Mathews" + } + }, + { + "id": 3288, + "name": "Garner Hensley", + "gender": "male", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Rushford" + } + }, + { + "id": 3289, + "name": "Monica Owen", + "gender": "female", + "age": 66, + "address": { + "state": "New York", + "city": "Mapletown" + } + }, + { + "id": 3290, + "name": "Effie Gibson", + "gender": "female", + "age": 33, + "address": { + "state": "Arizona", + "city": "Brookfield" + } + }, + { + "id": 3291, + "name": "Watson Gordon", + "gender": "male", + "age": 36, + "address": { + "state": "Delaware", + "city": "Logan" + } + }, + { + "id": 3292, + "name": "Vega Conley", + "gender": "male", + "age": 43, + "address": { + "state": "Nevada", + "city": "Tonopah" + } + }, + { + "id": 3293, + "name": "Townsend Decker", + "gender": "male", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Enoree" + } + }, + { + "id": 3294, + "name": "Tia Freeman", + "gender": "female", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Kenmar" + } + }, + { + "id": 3295, + "name": "Mccormick Mann", + "gender": "male", + "age": 74, + "address": { + "state": "Iowa", + "city": "Murillo" + } + }, + { + "id": 3296, + "name": "Juanita Wolf", + "gender": "female", + "age": 42, + "address": { + "state": "Mississippi", + "city": "Dyckesville" + } + }, + { + "id": 3297, + "name": "Catherine Foreman", + "gender": "female", + "age": 19, + "address": { + "state": "North Carolina", + "city": "Hobucken" + } + }, + { + "id": 3298, + "name": "Rosemarie Blevins", + "gender": "female", + "age": 76, + "address": { + "state": "Utah", + "city": "Hoagland" + } + }, + { + "id": 3299, + "name": "Williamson Barry", + "gender": "male", + "age": 61, + "address": { + "state": "Idaho", + "city": "Graniteville" + } + }, + { + "id": 3300, + "name": "Young Kramer", + "gender": "female", + "age": 20, + "address": { + "state": "Alaska", + "city": "Watchtower" + } + }, + { + "id": 3301, + "name": "Jimenez Wynn", + "gender": "male", + "age": 41, + "address": { + "state": "New Jersey", + "city": "Russellville" + } + }, + { + "id": 3302, + "name": "Robertson Boyd", + "gender": "male", + "age": 24, + "address": { + "state": "Minnesota", + "city": "Coral" + } + }, + { + "id": 3303, + "name": "Lauri Curtis", + "gender": "female", + "age": 79, + "address": { + "state": "Kansas", + "city": "Convent" + } + }, + { + "id": 3304, + "name": "Hess Cotton", + "gender": "male", + "age": 18, + "address": { + "state": "Florida", + "city": "Rivers" + } + }, + { + "id": 3305, + "name": "Nettie Grimes", + "gender": "female", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Allensworth" + } + }, + { + "id": 3306, + "name": "Hays Collins", + "gender": "male", + "age": 43, + "address": { + "state": "Virginia", + "city": "Hachita" + } + }, + { + "id": 3307, + "name": "Pansy Buchanan", + "gender": "female", + "age": 53, + "address": { + "state": "Oklahoma", + "city": "Alafaya" + } + }, + { + "id": 3308, + "name": "Melton Gentry", + "gender": "male", + "age": 29, + "address": { + "state": "Missouri", + "city": "Terlingua" + } + }, + { + "id": 3309, + "name": "Harrell Murray", + "gender": "male", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Gila" + } + }, + { + "id": 3310, + "name": "Clarke Gaines", + "gender": "male", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Rosine" + } + }, + { + "id": 3311, + "name": "Abigail Parrish", + "gender": "female", + "age": 21, + "address": { + "state": "Maine", + "city": "Moraida" + } + }, + { + "id": 3312, + "name": "Aguirre Fleming", + "gender": "male", + "age": 73, + "address": { + "state": "Louisiana", + "city": "Snelling" + } + }, + { + "id": 3313, + "name": "Patrice Osborn", + "gender": "female", + "age": 49, + "address": { + "state": "California", + "city": "Moquino" + } + }, + { + "id": 3314, + "name": "Conley Brennan", + "gender": "male", + "age": 38, + "address": { + "state": "Texas", + "city": "Newcastle" + } + }, + { + "id": 3315, + "name": "Luisa Rowland", + "gender": "female", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Emison" + } + }, + { + "id": 3316, + "name": "Lang Stone", + "gender": "male", + "age": 28, + "address": { + "state": "Colorado", + "city": "Gorst" + } + }, + { + "id": 3317, + "name": "Bruce Rodriguez", + "gender": "male", + "age": 35, + "address": { + "state": "Oregon", + "city": "Bradenville" + } + }, + { + "id": 3318, + "name": "Cruz Craft", + "gender": "male", + "age": 43, + "address": { + "state": "Kentucky", + "city": "Bluffview" + } + }, + { + "id": 3319, + "name": "Ronda Walter", + "gender": "female", + "age": 40, + "address": { + "state": "Washington", + "city": "Johnsonburg" + } + }, + { + "id": 3320, + "name": "Wright Bates", + "gender": "male", + "age": 52, + "address": { + "state": "Georgia", + "city": "Canterwood" + } + }, + { + "id": 3321, + "name": "Lester Reilly", + "gender": "male", + "age": 20, + "address": { + "state": "Wisconsin", + "city": "Southview" + } + }, + { + "id": 3322, + "name": "Araceli Marks", + "gender": "female", + "age": 67, + "address": { + "state": "New Mexico", + "city": "Nanafalia" + } + }, + { + "id": 3323, + "name": "Lucinda Wilkerson", + "gender": "female", + "age": 30, + "address": { + "state": "Indiana", + "city": "Chilton" + } + }, + { + "id": 3324, + "name": "Celia Britt", + "gender": "female", + "age": 73, + "address": { + "state": "Montana", + "city": "Waterview" + } + }, + { + "id": 3325, + "name": "Weiss Arnold", + "gender": "male", + "age": 57, + "address": { + "state": "Alabama", + "city": "Martell" + } + }, + { + "id": 3326, + "name": "Sosa Mcneil", + "gender": "male", + "age": 44, + "address": { + "state": "New Hampshire", + "city": "Allentown" + } + }, + { + "id": 3327, + "name": "Erika Beard", + "gender": "female", + "age": 27, + "address": { + "state": "Maryland", + "city": "Dragoon" + } + }, + { + "id": 3328, + "name": "Stephens Bray", + "gender": "male", + "age": 64, + "address": { + "state": "Pennsylvania", + "city": "Ripley" + } + }, + { + "id": 3329, + "name": "Katina Baldwin", + "gender": "female", + "age": 69, + "address": { + "state": "North Dakota", + "city": "Whitestone" + } + }, + { + "id": 3330, + "name": "Irwin Villarreal", + "gender": "male", + "age": 46, + "address": { + "state": "Ohio", + "city": "Glenville" + } + }, + { + "id": 3331, + "name": "Sarah Carey", + "gender": "female", + "age": 32, + "address": { + "state": "Vermont", + "city": "Eureka" + } + }, + { + "id": 3332, + "name": "Marianne Washington", + "gender": "female", + "age": 57, + "address": { + "state": "Kentucky", + "city": "Blanford" + } + }, + { + "id": 3333, + "name": "Tillman Powers", + "gender": "male", + "age": 81, + "address": { + "state": "Minnesota", + "city": "Nicholson" + } + }, + { + "id": 3334, + "name": "Poole Newman", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Movico" + } + }, + { + "id": 3335, + "name": "Kaufman Anthony", + "gender": "male", + "age": 56, + "address": { + "state": "Colorado", + "city": "Wolcott" + } + }, + { + "id": 3336, + "name": "Audra Peterson", + "gender": "female", + "age": 63, + "address": { + "state": "Alabama", + "city": "Edneyville" + } + }, + { + "id": 3337, + "name": "Estrada Grimes", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Sparkill" + } + }, + { + "id": 3338, + "name": "Robles Walter", + "gender": "male", + "age": 30, + "address": { + "state": "Wisconsin", + "city": "Dola" + } + }, + { + "id": 3339, + "name": "Mcfarland Diaz", + "gender": "male", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Accoville" + } + }, + { + "id": 3340, + "name": "Rachael Madden", + "gender": "female", + "age": 58, + "address": { + "state": "Massachusetts", + "city": "Chemung" + } + }, + { + "id": 3341, + "name": "Celeste Melton", + "gender": "female", + "age": 37, + "address": { + "state": "Michigan", + "city": "Adamstown" + } + }, + { + "id": 3342, + "name": "Isabella Wilcox", + "gender": "female", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Otranto" + } + }, + { + "id": 3343, + "name": "Sears Roach", + "gender": "male", + "age": 22, + "address": { + "state": "Arkansas", + "city": "Mapletown" + } + }, + { + "id": 3344, + "name": "Ester Hatfield", + "gender": "female", + "age": 23, + "address": { + "state": "Tennessee", + "city": "Detroit" + } + }, + { + "id": 3345, + "name": "Alford Moon", + "gender": "male", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Denio" + } + }, + { + "id": 3346, + "name": "Anastasia Delaney", + "gender": "female", + "age": 82, + "address": { + "state": "Vermont", + "city": "Ballico" + } + }, + { + "id": 3347, + "name": "Mccoy Dale", + "gender": "male", + "age": 49, + "address": { + "state": "Connecticut", + "city": "Valmy" + } + }, + { + "id": 3348, + "name": "Bond Byers", + "gender": "male", + "age": 63, + "address": { + "state": "Idaho", + "city": "Sabillasville" + } + }, + { + "id": 3349, + "name": "Connie Underwood", + "gender": "female", + "age": 41, + "address": { + "state": "South Dakota", + "city": "Macdona" + } + }, + { + "id": 3350, + "name": "Deirdre Glover", + "gender": "female", + "age": 69, + "address": { + "state": "New York", + "city": "Thynedale" + } + }, + { + "id": 3351, + "name": "Garza Rhodes", + "gender": "male", + "age": 36, + "address": { + "state": "Iowa", + "city": "Cawood" + } + }, + { + "id": 3352, + "name": "Earnestine Hartman", + "gender": "female", + "age": 20, + "address": { + "state": "Pennsylvania", + "city": "Chalfant" + } + }, + { + "id": 3353, + "name": "Alma Mills", + "gender": "female", + "age": 66, + "address": { + "state": "South Carolina", + "city": "Orviston" + } + }, + { + "id": 3354, + "name": "Dianne Hoffman", + "gender": "female", + "age": 27, + "address": { + "state": "New Jersey", + "city": "Brenton" + } + }, + { + "id": 3355, + "name": "Maxine Clay", + "gender": "female", + "age": 51, + "address": { + "state": "Georgia", + "city": "Deseret" + } + }, + { + "id": 3356, + "name": "Lina Rogers", + "gender": "female", + "age": 24, + "address": { + "state": "Maine", + "city": "Belfair" + } + }, + { + "id": 3357, + "name": "Nicholson Pittman", + "gender": "male", + "age": 61, + "address": { + "state": "California", + "city": "Waumandee" + } + }, + { + "id": 3358, + "name": "Shepard Gentry", + "gender": "male", + "age": 32, + "address": { + "state": "Nevada", + "city": "Vallonia" + } + }, + { + "id": 3359, + "name": "Denise Kirkland", + "gender": "female", + "age": 55, + "address": { + "state": "Hawaii", + "city": "Bath" + } + }, + { + "id": 3360, + "name": "Malone Everett", + "gender": "male", + "age": 77, + "address": { + "state": "Arizona", + "city": "Barclay" + } + }, + { + "id": 3361, + "name": "Mays Herman", + "gender": "male", + "age": 61, + "address": { + "state": "Missouri", + "city": "Allensworth" + } + }, + { + "id": 3362, + "name": "Sophia Mitchell", + "gender": "female", + "age": 62, + "address": { + "state": "North Dakota", + "city": "Eggertsville" + } + }, + { + "id": 3363, + "name": "Bennett Nichols", + "gender": "male", + "age": 76, + "address": { + "state": "North Carolina", + "city": "Bowden" + } + }, + { + "id": 3364, + "name": "Luna Mathews", + "gender": "male", + "age": 39, + "address": { + "state": "Delaware", + "city": "Osage" + } + }, + { + "id": 3365, + "name": "Schneider Olsen", + "gender": "male", + "age": 63, + "address": { + "state": "Oklahoma", + "city": "Newcastle" + } + }, + { + "id": 3366, + "name": "Ware Valentine", + "gender": "male", + "age": 27, + "address": { + "state": "Louisiana", + "city": "Ilchester" + } + }, + { + "id": 3367, + "name": "Francis Bonner", + "gender": "female", + "age": 57, + "address": { + "state": "Washington", + "city": "Fedora" + } + }, + { + "id": 3368, + "name": "Brown Beck", + "gender": "male", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Mulino" + } + }, + { + "id": 3369, + "name": "Leblanc Hendricks", + "gender": "male", + "age": 49, + "address": { + "state": "Utah", + "city": "Noblestown" + } + }, + { + "id": 3370, + "name": "Susie Middleton", + "gender": "female", + "age": 53, + "address": { + "state": "Maryland", + "city": "Catharine" + } + }, + { + "id": 3371, + "name": "Mendez Norman", + "gender": "male", + "age": 73, + "address": { + "state": "Illinois", + "city": "Urbana" + } + }, + { + "id": 3372, + "name": "Gentry Noel", + "gender": "male", + "age": 28, + "address": { + "state": "Florida", + "city": "Roy" + } + }, + { + "id": 3373, + "name": "Vance Rose", + "gender": "male", + "age": 21, + "address": { + "state": "Rhode Island", + "city": "Hinsdale" + } + }, + { + "id": 3374, + "name": "Marquita Vaughn", + "gender": "female", + "age": 38, + "address": { + "state": "Kansas", + "city": "Berwind" + } + }, + { + "id": 3375, + "name": "Ernestine Harrington", + "gender": "female", + "age": 67, + "address": { + "state": "Alaska", + "city": "National" + } + }, + { + "id": 3376, + "name": "Robbins Langley", + "gender": "male", + "age": 54, + "address": { + "state": "Texas", + "city": "Sutton" + } + }, + { + "id": 3377, + "name": "Frances Mccullough", + "gender": "female", + "age": 75, + "address": { + "state": "Ohio", + "city": "Dixonville" + } + }, + { + "id": 3378, + "name": "Bryan Henderson", + "gender": "male", + "age": 79, + "address": { + "state": "Montana", + "city": "Websterville" + } + }, + { + "id": 3379, + "name": "Sofia Peters", + "gender": "female", + "age": 42, + "address": { + "state": "Virginia", + "city": "Valle" + } + }, + { + "id": 3380, + "name": "Wright Mckee", + "gender": "male", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Dundee" + } + }, + { + "id": 3381, + "name": "Leticia Vasquez", + "gender": "female", + "age": 64, + "address": { + "state": "West Virginia", + "city": "Hall" + } + }, + { + "id": 3382, + "name": "Rice Avila", + "gender": "male", + "age": 45, + "address": { + "state": "Michigan", + "city": "Nipinnawasee" + } + }, + { + "id": 3383, + "name": "Valenzuela Peterson", + "gender": "male", + "age": 78, + "address": { + "state": "Massachusetts", + "city": "Ruffin" + } + }, + { + "id": 3384, + "name": "Anne Shields", + "gender": "female", + "age": 17, + "address": { + "state": "Hawaii", + "city": "Thatcher" + } + }, + { + "id": 3385, + "name": "Madelyn Cochran", + "gender": "female", + "age": 62, + "address": { + "state": "Iowa", + "city": "Carbonville" + } + }, + { + "id": 3386, + "name": "Casey Raymond", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Stockwell" + } + }, + { + "id": 3387, + "name": "Ollie Schultz", + "gender": "female", + "age": 33, + "address": { + "state": "Mississippi", + "city": "Foscoe" + } + }, + { + "id": 3388, + "name": "Goodwin Fields", + "gender": "male", + "age": 61, + "address": { + "state": "Ohio", + "city": "Tryon" + } + }, + { + "id": 3389, + "name": "Alissa Murphy", + "gender": "female", + "age": 47, + "address": { + "state": "North Dakota", + "city": "Brady" + } + }, + { + "id": 3390, + "name": "Antoinette Rose", + "gender": "female", + "age": 44, + "address": { + "state": "New Mexico", + "city": "Clayville" + } + }, + { + "id": 3391, + "name": "Erika Spencer", + "gender": "female", + "age": 60, + "address": { + "state": "Alaska", + "city": "Lafferty" + } + }, + { + "id": 3392, + "name": "Mallory Fox", + "gender": "female", + "age": 20, + "address": { + "state": "Idaho", + "city": "Canterwood" + } + }, + { + "id": 3393, + "name": "Hensley Mooney", + "gender": "male", + "age": 80, + "address": { + "state": "New York", + "city": "Matheny" + } + }, + { + "id": 3394, + "name": "Ann Curtis", + "gender": "female", + "age": 47, + "address": { + "state": "California", + "city": "Boonville" + } + }, + { + "id": 3395, + "name": "Melinda Erickson", + "gender": "female", + "age": 18, + "address": { + "state": "Rhode Island", + "city": "Riceville" + } + }, + { + "id": 3396, + "name": "Esmeralda Nunez", + "gender": "female", + "age": 44, + "address": { + "state": "Utah", + "city": "Loyalhanna" + } + }, + { + "id": 3397, + "name": "Sheryl Gamble", + "gender": "female", + "age": 52, + "address": { + "state": "Louisiana", + "city": "Succasunna" + } + }, + { + "id": 3398, + "name": "Rowena Haney", + "gender": "female", + "age": 76, + "address": { + "state": "Pennsylvania", + "city": "Sharon" + } + }, + { + "id": 3399, + "name": "Concetta Beck", + "gender": "female", + "age": 70, + "address": { + "state": "Nevada", + "city": "Mansfield" + } + }, + { + "id": 3400, + "name": "Sherrie Hansen", + "gender": "female", + "age": 66, + "address": { + "state": "Colorado", + "city": "Masthope" + } + }, + { + "id": 3401, + "name": "Marla Woods", + "gender": "female", + "age": 63, + "address": { + "state": "Oklahoma", + "city": "Yogaville" + } + }, + { + "id": 3402, + "name": "Latonya Holt", + "gender": "female", + "age": 19, + "address": { + "state": "South Dakota", + "city": "Innsbrook" + } + }, + { + "id": 3403, + "name": "Bright Leblanc", + "gender": "male", + "age": 75, + "address": { + "state": "Oregon", + "city": "Craig" + } + }, + { + "id": 3404, + "name": "Kelsey Castro", + "gender": "female", + "age": 41, + "address": { + "state": "Georgia", + "city": "Cassel" + } + }, + { + "id": 3405, + "name": "Shelly Solis", + "gender": "female", + "age": 55, + "address": { + "state": "Nebraska", + "city": "Cetronia" + } + }, + { + "id": 3406, + "name": "Rutledge Ewing", + "gender": "male", + "age": 39, + "address": { + "state": "Florida", + "city": "Robinette" + } + }, + { + "id": 3407, + "name": "Julia Cote", + "gender": "female", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Basye" + } + }, + { + "id": 3408, + "name": "Janet Tyler", + "gender": "female", + "age": 70, + "address": { + "state": "Delaware", + "city": "Detroit" + } + }, + { + "id": 3409, + "name": "Carolyn Rollins", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Coloma" + } + }, + { + "id": 3410, + "name": "Ingrid Manning", + "gender": "female", + "age": 73, + "address": { + "state": "Connecticut", + "city": "Bayview" + } + }, + { + "id": 3411, + "name": "Elaine Pate", + "gender": "female", + "age": 73, + "address": { + "state": "Virginia", + "city": "Newcastle" + } + }, + { + "id": 3412, + "name": "Nixon Pierce", + "gender": "male", + "age": 57, + "address": { + "state": "New Hampshire", + "city": "Glidden" + } + }, + { + "id": 3413, + "name": "Johnston Fitzpatrick", + "gender": "male", + "age": 28, + "address": { + "state": "Illinois", + "city": "Garfield" + } + }, + { + "id": 3414, + "name": "Gonzalez Mills", + "gender": "male", + "age": 80, + "address": { + "state": "Indiana", + "city": "Jennings" + } + }, + { + "id": 3415, + "name": "Berger Santos", + "gender": "male", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Brutus" + } + }, + { + "id": 3416, + "name": "Angie Saunders", + "gender": "female", + "age": 18, + "address": { + "state": "Tennessee", + "city": "Vowinckel" + } + }, + { + "id": 3417, + "name": "Sargent Oneill", + "gender": "male", + "age": 72, + "address": { + "state": "Vermont", + "city": "Riverton" + } + }, + { + "id": 3418, + "name": "Gibbs Reyes", + "gender": "male", + "age": 27, + "address": { + "state": "Kansas", + "city": "Montura" + } + }, + { + "id": 3419, + "name": "Reese Nichols", + "gender": "male", + "age": 70, + "address": { + "state": "Arizona", + "city": "Barstow" + } + }, + { + "id": 3420, + "name": "Holder Mcmahon", + "gender": "male", + "age": 66, + "address": { + "state": "Alabama", + "city": "Dubois" + } + }, + { + "id": 3421, + "name": "Sheppard Emerson", + "gender": "male", + "age": 81, + "address": { + "state": "Maine", + "city": "Elizaville" + } + }, + { + "id": 3422, + "name": "Garrett Castillo", + "gender": "male", + "age": 47, + "address": { + "state": "Kentucky", + "city": "Boyd" + } + }, + { + "id": 3423, + "name": "Sears Levy", + "gender": "male", + "age": 56, + "address": { + "state": "Wyoming", + "city": "Datil" + } + }, + { + "id": 3424, + "name": "Wagner Joyner", + "gender": "male", + "age": 60, + "address": { + "state": "Texas", + "city": "Elbert" + } + }, + { + "id": 3425, + "name": "Young Lambert", + "gender": "female", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Dundee" + } + }, + { + "id": 3426, + "name": "Sofia Britt", + "gender": "female", + "age": 20, + "address": { + "state": "Washington", + "city": "Goochland" + } + }, + { + "id": 3427, + "name": "Caroline Johns", + "gender": "female", + "age": 58, + "address": { + "state": "Montana", + "city": "Sims" + } + }, + { + "id": 3428, + "name": "Stacie Reynolds", + "gender": "female", + "age": 62, + "address": { + "state": "Arkansas", + "city": "Mathews" + } + }, + { + "id": 3429, + "name": "Hatfield Bishop", + "gender": "male", + "age": 26, + "address": { + "state": "Missouri", + "city": "Mooresburg" + } + }, + { + "id": 3430, + "name": "Rodriguez Maddox", + "gender": "male", + "age": 64, + "address": { + "state": "Iowa", + "city": "Wolcott" + } + }, + { + "id": 3431, + "name": "Frieda Carpenter", + "gender": "female", + "age": 54, + "address": { + "state": "Maine", + "city": "Escondida" + } + }, + { + "id": 3432, + "name": "Concetta Williamson", + "gender": "female", + "age": 33, + "address": { + "state": "Alaska", + "city": "Churchill" + } + }, + { + "id": 3433, + "name": "Amie Holloway", + "gender": "female", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Maury" + } + }, + { + "id": 3434, + "name": "Powell Heath", + "gender": "male", + "age": 55, + "address": { + "state": "Washington", + "city": "Omar" + } + }, + { + "id": 3435, + "name": "Mccarthy Nelson", + "gender": "male", + "age": 29, + "address": { + "state": "Pennsylvania", + "city": "Wyano" + } + }, + { + "id": 3436, + "name": "Mcgee Tanner", + "gender": "male", + "age": 24, + "address": { + "state": "Kansas", + "city": "Juntura" + } + }, + { + "id": 3437, + "name": "Berta Christian", + "gender": "female", + "age": 21, + "address": { + "state": "Oklahoma", + "city": "Cassel" + } + }, + { + "id": 3438, + "name": "Maxine Johnston", + "gender": "female", + "age": 41, + "address": { + "state": "Florida", + "city": "Freeburn" + } + }, + { + "id": 3439, + "name": "Bender Marsh", + "gender": "male", + "age": 76, + "address": { + "state": "Nevada", + "city": "Glenshaw" + } + }, + { + "id": 3440, + "name": "Neva Stafford", + "gender": "female", + "age": 54, + "address": { + "state": "Maryland", + "city": "Wright" + } + }, + { + "id": 3441, + "name": "Kate Clements", + "gender": "female", + "age": 32, + "address": { + "state": "Idaho", + "city": "Avoca" + } + }, + { + "id": 3442, + "name": "Aida Glass", + "gender": "female", + "age": 59, + "address": { + "state": "Missouri", + "city": "Clarktown" + } + }, + { + "id": 3443, + "name": "Heath Durham", + "gender": "male", + "age": 41, + "address": { + "state": "Hawaii", + "city": "Lisco" + } + }, + { + "id": 3444, + "name": "Dixon Hampton", + "gender": "male", + "age": 46, + "address": { + "state": "Illinois", + "city": "Tolu" + } + }, + { + "id": 3445, + "name": "Giles Ayala", + "gender": "male", + "age": 67, + "address": { + "state": "Virginia", + "city": "Manchester" + } + }, + { + "id": 3446, + "name": "Lila Bridges", + "gender": "female", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Verdi" + } + }, + { + "id": 3447, + "name": "Hale Potts", + "gender": "male", + "age": 26, + "address": { + "state": "Minnesota", + "city": "Brantleyville" + } + }, + { + "id": 3448, + "name": "Allison Munoz", + "gender": "female", + "age": 73, + "address": { + "state": "Montana", + "city": "Chaparrito" + } + }, + { + "id": 3449, + "name": "Allen Cunningham", + "gender": "male", + "age": 23, + "address": { + "state": "Texas", + "city": "Russellville" + } + }, + { + "id": 3450, + "name": "Callie Conrad", + "gender": "female", + "age": 48, + "address": { + "state": "New Mexico", + "city": "Hollins" + } + }, + { + "id": 3451, + "name": "Jeanine Salazar", + "gender": "female", + "age": 47, + "address": { + "state": "Ohio", + "city": "Bascom" + } + }, + { + "id": 3452, + "name": "West Mclaughlin", + "gender": "male", + "age": 56, + "address": { + "state": "Arizona", + "city": "Itmann" + } + }, + { + "id": 3453, + "name": "Burnett Hughes", + "gender": "male", + "age": 36, + "address": { + "state": "North Dakota", + "city": "Freetown" + } + }, + { + "id": 3454, + "name": "Simone Reese", + "gender": "female", + "age": 59, + "address": { + "state": "Oregon", + "city": "Watrous" + } + }, + { + "id": 3455, + "name": "Sheila Mcfarland", + "gender": "female", + "age": 57, + "address": { + "state": "Delaware", + "city": "Needmore" + } + }, + { + "id": 3456, + "name": "Chapman Sanford", + "gender": "male", + "age": 23, + "address": { + "state": "New Jersey", + "city": "Fingerville" + } + }, + { + "id": 3457, + "name": "Marcella Massey", + "gender": "female", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Thatcher" + } + }, + { + "id": 3458, + "name": "Mckay Delgado", + "gender": "male", + "age": 34, + "address": { + "state": "Utah", + "city": "Chamizal" + } + }, + { + "id": 3459, + "name": "Davenport Sherman", + "gender": "male", + "age": 31, + "address": { + "state": "Kentucky", + "city": "Sidman" + } + }, + { + "id": 3460, + "name": "Hernandez Craft", + "gender": "male", + "age": 19, + "address": { + "state": "New Hampshire", + "city": "Marion" + } + }, + { + "id": 3461, + "name": "Letitia Rodriguez", + "gender": "female", + "age": 61, + "address": { + "state": "Alabama", + "city": "Bridgetown" + } + }, + { + "id": 3462, + "name": "Jarvis Riggs", + "gender": "male", + "age": 18, + "address": { + "state": "Wisconsin", + "city": "Delwood" + } + }, + { + "id": 3463, + "name": "Mcfarland Walsh", + "gender": "male", + "age": 19, + "address": { + "state": "West Virginia", + "city": "Blue" + } + }, + { + "id": 3464, + "name": "Lott Bartlett", + "gender": "male", + "age": 56, + "address": { + "state": "Indiana", + "city": "Salix" + } + }, + { + "id": 3465, + "name": "Atkinson Velazquez", + "gender": "male", + "age": 65, + "address": { + "state": "South Carolina", + "city": "Frank" + } + }, + { + "id": 3466, + "name": "Felecia Craig", + "gender": "female", + "age": 33, + "address": { + "state": "New York", + "city": "Shasta" + } + }, + { + "id": 3467, + "name": "Tammy Guzman", + "gender": "female", + "age": 53, + "address": { + "state": "Connecticut", + "city": "Nipinnawasee" + } + }, + { + "id": 3468, + "name": "Salas Patel", + "gender": "male", + "age": 18, + "address": { + "state": "South Dakota", + "city": "Wyoming" + } + }, + { + "id": 3469, + "name": "Chase Phillips", + "gender": "male", + "age": 28, + "address": { + "state": "Michigan", + "city": "Trail" + } + }, + { + "id": 3470, + "name": "Sylvia Dalton", + "gender": "female", + "age": 29, + "address": { + "state": "Colorado", + "city": "National" + } + }, + { + "id": 3471, + "name": "Ruby Fischer", + "gender": "female", + "age": 30, + "address": { + "state": "Massachusetts", + "city": "Jacksonburg" + } + }, + { + "id": 3472, + "name": "Kelli William", + "gender": "female", + "age": 60, + "address": { + "state": "California", + "city": "Calvary" + } + }, + { + "id": 3473, + "name": "Raymond Carlson", + "gender": "male", + "age": 29, + "address": { + "state": "Georgia", + "city": "Sims" + } + }, + { + "id": 3474, + "name": "Christensen Manning", + "gender": "male", + "age": 29, + "address": { + "state": "Mississippi", + "city": "Boonville" + } + }, + { + "id": 3475, + "name": "Howard Valencia", + "gender": "male", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Leyner" + } + }, + { + "id": 3476, + "name": "Mavis Berger", + "gender": "female", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Kansas" + } + }, + { + "id": 3477, + "name": "Joanne Snow", + "gender": "female", + "age": 60, + "address": { + "state": "Arkansas", + "city": "Glenville" + } + }, + { + "id": 3478, + "name": "Christian Faulkner", + "gender": "male", + "age": 23, + "address": { + "state": "Vermont", + "city": "Marbury" + } + }, + { + "id": 3479, + "name": "Arline Campos", + "gender": "female", + "age": 24, + "address": { + "state": "Georgia", + "city": "Stouchsburg" + } + }, + { + "id": 3480, + "name": "Davidson Conrad", + "gender": "male", + "age": 44, + "address": { + "state": "New Jersey", + "city": "Chesapeake" + } + }, + { + "id": 3481, + "name": "Gay Moore", + "gender": "female", + "age": 62, + "address": { + "state": "Vermont", + "city": "Coaldale" + } + }, + { + "id": 3482, + "name": "Rosemarie Peck", + "gender": "female", + "age": 32, + "address": { + "state": "Ohio", + "city": "Emory" + } + }, + { + "id": 3483, + "name": "Marie Lindsay", + "gender": "female", + "age": 82, + "address": { + "state": "South Dakota", + "city": "Westphalia" + } + }, + { + "id": 3484, + "name": "Anderson Wilson", + "gender": "male", + "age": 31, + "address": { + "state": "New York", + "city": "Lindisfarne" + } + }, + { + "id": 3485, + "name": "Guerrero Meyer", + "gender": "male", + "age": 48, + "address": { + "state": "Missouri", + "city": "Brantleyville" + } + }, + { + "id": 3486, + "name": "Maynard Mcfadden", + "gender": "male", + "age": 65, + "address": { + "state": "North Carolina", + "city": "Condon" + } + }, + { + "id": 3487, + "name": "Lucas Wheeler", + "gender": "male", + "age": 35, + "address": { + "state": "Arizona", + "city": "Germanton" + } + }, + { + "id": 3488, + "name": "Mayo Gentry", + "gender": "male", + "age": 65, + "address": { + "state": "Delaware", + "city": "Sehili" + } + }, + { + "id": 3489, + "name": "Hilary Davis", + "gender": "female", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Cascades" + } + }, + { + "id": 3490, + "name": "Josie Noble", + "gender": "female", + "age": 17, + "address": { + "state": "Utah", + "city": "Crayne" + } + }, + { + "id": 3491, + "name": "Carpenter Conner", + "gender": "male", + "age": 25, + "address": { + "state": "Nevada", + "city": "Gloucester" + } + }, + { + "id": 3492, + "name": "Estella Washington", + "gender": "female", + "age": 80, + "address": { + "state": "Florida", + "city": "Williston" + } + }, + { + "id": 3493, + "name": "Anastasia Hopper", + "gender": "female", + "age": 19, + "address": { + "state": "Kansas", + "city": "Sussex" + } + }, + { + "id": 3494, + "name": "Maricela Ware", + "gender": "female", + "age": 54, + "address": { + "state": "Idaho", + "city": "Weogufka" + } + }, + { + "id": 3495, + "name": "Morton Chaney", + "gender": "male", + "age": 48, + "address": { + "state": "Maine", + "city": "Como" + } + }, + { + "id": 3496, + "name": "Coleman Sykes", + "gender": "male", + "age": 81, + "address": { + "state": "Rhode Island", + "city": "Otranto" + } + }, + { + "id": 3497, + "name": "Jerri Reed", + "gender": "female", + "age": 47, + "address": { + "state": "Texas", + "city": "Naomi" + } + }, + { + "id": 3498, + "name": "Mccray Atkins", + "gender": "male", + "age": 36, + "address": { + "state": "Alabama", + "city": "Bison" + } + }, + { + "id": 3499, + "name": "Herrera Duke", + "gender": "male", + "age": 20, + "address": { + "state": "New Hampshire", + "city": "Spokane" + } + }, + { + "id": 3500, + "name": "Graciela Perry", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Homeland" + } + }, + { + "id": 3501, + "name": "Herring Maldonado", + "gender": "male", + "age": 22, + "address": { + "state": "Minnesota", + "city": "Homeworth" + } + }, + { + "id": 3502, + "name": "Cohen Acosta", + "gender": "male", + "age": 57, + "address": { + "state": "South Carolina", + "city": "Vaughn" + } + }, + { + "id": 3503, + "name": "Evelyn Glover", + "gender": "female", + "age": 49, + "address": { + "state": "Wisconsin", + "city": "Konterra" + } + }, + { + "id": 3504, + "name": "Clarissa Hawkins", + "gender": "female", + "age": 40, + "address": { + "state": "Michigan", + "city": "Carlton" + } + }, + { + "id": 3505, + "name": "Mcintyre Petersen", + "gender": "male", + "age": 46, + "address": { + "state": "Maryland", + "city": "Dennard" + } + }, + { + "id": 3506, + "name": "Blair Mcguire", + "gender": "male", + "age": 75, + "address": { + "state": "Kentucky", + "city": "Sandston" + } + }, + { + "id": 3507, + "name": "Kelley Wells", + "gender": "male", + "age": 21, + "address": { + "state": "Massachusetts", + "city": "Driftwood" + } + }, + { + "id": 3508, + "name": "Jill Vang", + "gender": "female", + "age": 51, + "address": { + "state": "Connecticut", + "city": "Nescatunga" + } + }, + { + "id": 3509, + "name": "Rose Dillon", + "gender": "female", + "age": 56, + "address": { + "state": "California", + "city": "Urbana" + } + }, + { + "id": 3510, + "name": "Silvia Blair", + "gender": "female", + "age": 53, + "address": { + "state": "Illinois", + "city": "Kimmell" + } + }, + { + "id": 3511, + "name": "Dale Camacho", + "gender": "female", + "age": 42, + "address": { + "state": "Washington", + "city": "Trona" + } + }, + { + "id": 3512, + "name": "Pacheco Delacruz", + "gender": "male", + "age": 32, + "address": { + "state": "Arkansas", + "city": "Eggertsville" + } + }, + { + "id": 3513, + "name": "Ward Ayala", + "gender": "male", + "age": 30, + "address": { + "state": "West Virginia", + "city": "Byrnedale" + } + }, + { + "id": 3514, + "name": "Carter Hewitt", + "gender": "male", + "age": 20, + "address": { + "state": "Oregon", + "city": "Tryon" + } + }, + { + "id": 3515, + "name": "Lolita Flynn", + "gender": "female", + "age": 61, + "address": { + "state": "Wyoming", + "city": "Kidder" + } + }, + { + "id": 3516, + "name": "Isabel Howell", + "gender": "female", + "age": 35, + "address": { + "state": "New Mexico", + "city": "Cornucopia" + } + }, + { + "id": 3517, + "name": "Lorraine Preston", + "gender": "female", + "age": 42, + "address": { + "state": "North Dakota", + "city": "Madrid" + } + }, + { + "id": 3518, + "name": "Davis Frye", + "gender": "male", + "age": 24, + "address": { + "state": "Montana", + "city": "Turpin" + } + }, + { + "id": 3519, + "name": "Harriet Crane", + "gender": "female", + "age": 21, + "address": { + "state": "Tennessee", + "city": "Gerton" + } + }, + { + "id": 3520, + "name": "Atkins Bradshaw", + "gender": "male", + "age": 19, + "address": { + "state": "Pennsylvania", + "city": "Riviera" + } + }, + { + "id": 3521, + "name": "Kinney Alexander", + "gender": "male", + "age": 47, + "address": { + "state": "Alaska", + "city": "Saranap" + } + }, + { + "id": 3522, + "name": "Savage Goodwin", + "gender": "male", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Rosburg" + } + }, + { + "id": 3523, + "name": "Boone Hart", + "gender": "male", + "age": 24, + "address": { + "state": "Virginia", + "city": "Winfred" + } + }, + { + "id": 3524, + "name": "Mcbride Banks", + "gender": "male", + "age": 59, + "address": { + "state": "Iowa", + "city": "Ferney" + } + }, + { + "id": 3525, + "name": "Whitney Kelley", + "gender": "male", + "age": 22, + "address": { + "state": "Louisiana", + "city": "Navarre" + } + }, + { + "id": 3526, + "name": "Jo Bauer", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Clarktown" + } + }, + { + "id": 3527, + "name": "Lacy Day", + "gender": "female", + "age": 49, + "address": { + "state": "Colorado", + "city": "Klagetoh" + } + }, + { + "id": 3528, + "name": "Rena Bryant", + "gender": "female", + "age": 26, + "address": { + "state": "Delaware", + "city": "Cliff" + } + }, + { + "id": 3529, + "name": "Ingrid Bailey", + "gender": "female", + "age": 53, + "address": { + "state": "Rhode Island", + "city": "Brutus" + } + }, + { + "id": 3530, + "name": "Nichole Davis", + "gender": "female", + "age": 68, + "address": { + "state": "Arkansas", + "city": "Dahlen" + } + }, + { + "id": 3531, + "name": "Patsy Maddox", + "gender": "female", + "age": 57, + "address": { + "state": "North Carolina", + "city": "Cornfields" + } + }, + { + "id": 3532, + "name": "Johns Holland", + "gender": "male", + "age": 46, + "address": { + "state": "Illinois", + "city": "Stevens" + } + }, + { + "id": 3533, + "name": "Thornton Pearson", + "gender": "male", + "age": 44, + "address": { + "state": "Hawaii", + "city": "Dunnavant" + } + }, + { + "id": 3534, + "name": "Fisher Wynn", + "gender": "male", + "age": 57, + "address": { + "state": "North Dakota", + "city": "Nadine" + } + }, + { + "id": 3535, + "name": "Blackburn Lambert", + "gender": "male", + "age": 62, + "address": { + "state": "Ohio", + "city": "Wadsworth" + } + }, + { + "id": 3536, + "name": "Terra Carey", + "gender": "female", + "age": 59, + "address": { + "state": "Wyoming", + "city": "Hickory" + } + }, + { + "id": 3537, + "name": "Jackson Morales", + "gender": "male", + "age": 71, + "address": { + "state": "Vermont", + "city": "Alfarata" + } + }, + { + "id": 3538, + "name": "Avila Rogers", + "gender": "male", + "age": 25, + "address": { + "state": "West Virginia", + "city": "Lowell" + } + }, + { + "id": 3539, + "name": "Paul Collins", + "gender": "male", + "age": 73, + "address": { + "state": "South Carolina", + "city": "Nelson" + } + }, + { + "id": 3540, + "name": "Ingram Cantu", + "gender": "male", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Greenbush" + } + }, + { + "id": 3541, + "name": "Tran Avila", + "gender": "male", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Swartzville" + } + }, + { + "id": 3542, + "name": "Suzette Maxwell", + "gender": "female", + "age": 44, + "address": { + "state": "Kansas", + "city": "Eggertsville" + } + }, + { + "id": 3543, + "name": "Carpenter Gardner", + "gender": "male", + "age": 29, + "address": { + "state": "Idaho", + "city": "Vicksburg" + } + }, + { + "id": 3544, + "name": "Reba Duffy", + "gender": "female", + "age": 67, + "address": { + "state": "Michigan", + "city": "Kidder" + } + }, + { + "id": 3545, + "name": "Maddox Myers", + "gender": "male", + "age": 43, + "address": { + "state": "Florida", + "city": "Leyner" + } + }, + { + "id": 3546, + "name": "Bruce Valenzuela", + "gender": "male", + "age": 24, + "address": { + "state": "Georgia", + "city": "Glenshaw" + } + }, + { + "id": 3547, + "name": "Barbra Boyle", + "gender": "female", + "age": 69, + "address": { + "state": "Louisiana", + "city": "Waumandee" + } + }, + { + "id": 3548, + "name": "Gloria Villarreal", + "gender": "female", + "age": 67, + "address": { + "state": "Maryland", + "city": "Norwood" + } + }, + { + "id": 3549, + "name": "Melody Kirby", + "gender": "female", + "age": 20, + "address": { + "state": "Washington", + "city": "Coyote" + } + }, + { + "id": 3550, + "name": "Puckett Best", + "gender": "male", + "age": 57, + "address": { + "state": "Minnesota", + "city": "Roeville" + } + }, + { + "id": 3551, + "name": "Madeleine Schmidt", + "gender": "female", + "age": 82, + "address": { + "state": "Indiana", + "city": "Alafaya" + } + }, + { + "id": 3552, + "name": "Elizabeth Callahan", + "gender": "female", + "age": 70, + "address": { + "state": "Colorado", + "city": "Adelino" + } + }, + { + "id": 3553, + "name": "Celia Morse", + "gender": "female", + "age": 80, + "address": { + "state": "Virginia", + "city": "Chumuckla" + } + }, + { + "id": 3554, + "name": "Acosta Fitzgerald", + "gender": "male", + "age": 28, + "address": { + "state": "Missouri", + "city": "Edenburg" + } + }, + { + "id": 3555, + "name": "Wheeler Camacho", + "gender": "male", + "age": 19, + "address": { + "state": "Alabama", + "city": "Yardville" + } + }, + { + "id": 3556, + "name": "Sybil Torres", + "gender": "female", + "age": 70, + "address": { + "state": "California", + "city": "Brandywine" + } + }, + { + "id": 3557, + "name": "Maribel Franklin", + "gender": "female", + "age": 51, + "address": { + "state": "Arizona", + "city": "Walker" + } + }, + { + "id": 3558, + "name": "Yvette Chen", + "gender": "female", + "age": 36, + "address": { + "state": "Nevada", + "city": "Hampstead" + } + }, + { + "id": 3559, + "name": "Carey Ellis", + "gender": "male", + "age": 43, + "address": { + "state": "Oklahoma", + "city": "Westboro" + } + }, + { + "id": 3560, + "name": "Booth Arnold", + "gender": "male", + "age": 30, + "address": { + "state": "Wisconsin", + "city": "Wells" + } + }, + { + "id": 3561, + "name": "Britney Mcleod", + "gender": "female", + "age": 44, + "address": { + "state": "New Mexico", + "city": "Wikieup" + } + }, + { + "id": 3562, + "name": "Mae Peterson", + "gender": "female", + "age": 44, + "address": { + "state": "Maine", + "city": "Rose" + } + }, + { + "id": 3563, + "name": "Underwood Reynolds", + "gender": "male", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Roulette" + } + }, + { + "id": 3564, + "name": "Yesenia Henson", + "gender": "female", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Freetown" + } + }, + { + "id": 3565, + "name": "Angela Durham", + "gender": "female", + "age": 51, + "address": { + "state": "New York", + "city": "Winfred" + } + }, + { + "id": 3566, + "name": "Carson Livingston", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Kent" + } + }, + { + "id": 3567, + "name": "Hamilton Lindsay", + "gender": "male", + "age": 55, + "address": { + "state": "Tennessee", + "city": "Gracey" + } + }, + { + "id": 3568, + "name": "Terri Sawyer", + "gender": "female", + "age": 75, + "address": { + "state": "Utah", + "city": "Kraemer" + } + }, + { + "id": 3569, + "name": "Clay Olson", + "gender": "male", + "age": 81, + "address": { + "state": "South Dakota", + "city": "Darlington" + } + }, + { + "id": 3570, + "name": "Berta Roberson", + "gender": "female", + "age": 29, + "address": { + "state": "Mississippi", + "city": "Skyland" + } + }, + { + "id": 3571, + "name": "Chelsea Everett", + "gender": "female", + "age": 76, + "address": { + "state": "Texas", + "city": "Coaldale" + } + }, + { + "id": 3572, + "name": "Sabrina Noble", + "gender": "female", + "age": 21, + "address": { + "state": "Alaska", + "city": "Newcastle" + } + }, + { + "id": 3573, + "name": "Sanchez Valentine", + "gender": "male", + "age": 78, + "address": { + "state": "Iowa", + "city": "Nicut" + } + }, + { + "id": 3574, + "name": "Ashley Talley", + "gender": "female", + "age": 44, + "address": { + "state": "Oregon", + "city": "Falmouth" + } + }, + { + "id": 3575, + "name": "Mcknight Washington", + "gender": "male", + "age": 50, + "address": { + "state": "Pennsylvania", + "city": "Williamson" + } + }, + { + "id": 3576, + "name": "Carver Herring", + "gender": "male", + "age": 36, + "address": { + "state": "Connecticut", + "city": "Cowiche" + } + }, + { + "id": 3577, + "name": "Dianne Mercer", + "gender": "female", + "age": 82, + "address": { + "state": "Rhode Island", + "city": "Hondah" + } + }, + { + "id": 3578, + "name": "Buckley Mclaughlin", + "gender": "male", + "age": 33, + "address": { + "state": "Virginia", + "city": "Grenelefe" + } + }, + { + "id": 3579, + "name": "Rogers Mcleod", + "gender": "male", + "age": 41, + "address": { + "state": "Indiana", + "city": "Kidder" + } + }, + { + "id": 3580, + "name": "Kristy Estrada", + "gender": "female", + "age": 50, + "address": { + "state": "Nebraska", + "city": "Coloma" + } + }, + { + "id": 3581, + "name": "Lora Hyde", + "gender": "female", + "age": 68, + "address": { + "state": "Wisconsin", + "city": "Silkworth" + } + }, + { + "id": 3582, + "name": "Cathleen Chandler", + "gender": "female", + "age": 52, + "address": { + "state": "Iowa", + "city": "Lorraine" + } + }, + { + "id": 3583, + "name": "Isabel Tucker", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Lowgap" + } + }, + { + "id": 3584, + "name": "Hale Stevenson", + "gender": "male", + "age": 39, + "address": { + "state": "South Dakota", + "city": "Coldiron" + } + }, + { + "id": 3585, + "name": "Lacy Haynes", + "gender": "female", + "age": 75, + "address": { + "state": "Alaska", + "city": "Shepardsville" + } + }, + { + "id": 3586, + "name": "Noble Cotton", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Riviera" + } + }, + { + "id": 3587, + "name": "Little Mccoy", + "gender": "male", + "age": 30, + "address": { + "state": "Wyoming", + "city": "Succasunna" + } + }, + { + "id": 3588, + "name": "Erin Cox", + "gender": "female", + "age": 49, + "address": { + "state": "Arkansas", + "city": "Onton" + } + }, + { + "id": 3589, + "name": "Jacqueline Reilly", + "gender": "female", + "age": 38, + "address": { + "state": "Missouri", + "city": "Breinigsville" + } + }, + { + "id": 3590, + "name": "Melba Griffith", + "gender": "female", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Loomis" + } + }, + { + "id": 3591, + "name": "Candice Blackwell", + "gender": "female", + "age": 28, + "address": { + "state": "Louisiana", + "city": "Bascom" + } + }, + { + "id": 3592, + "name": "Thomas Hopkins", + "gender": "male", + "age": 76, + "address": { + "state": "Oklahoma", + "city": "Babb" + } + }, + { + "id": 3593, + "name": "Billie Rivers", + "gender": "female", + "age": 45, + "address": { + "state": "Delaware", + "city": "Homeland" + } + }, + { + "id": 3594, + "name": "Barnes Shepard", + "gender": "male", + "age": 63, + "address": { + "state": "Georgia", + "city": "Geyserville" + } + }, + { + "id": 3595, + "name": "Rodgers Nelson", + "gender": "male", + "age": 28, + "address": { + "state": "Massachusetts", + "city": "Driftwood" + } + }, + { + "id": 3596, + "name": "Kaye Foster", + "gender": "female", + "age": 29, + "address": { + "state": "Tennessee", + "city": "Nelson" + } + }, + { + "id": 3597, + "name": "Walsh Watson", + "gender": "male", + "age": 79, + "address": { + "state": "Ohio", + "city": "Yonah" + } + }, + { + "id": 3598, + "name": "Schultz Floyd", + "gender": "male", + "age": 47, + "address": { + "state": "Pennsylvania", + "city": "Whitewater" + } + }, + { + "id": 3599, + "name": "Ramirez Young", + "gender": "male", + "age": 69, + "address": { + "state": "Connecticut", + "city": "Glasgow" + } + }, + { + "id": 3600, + "name": "Jacobs Hall", + "gender": "male", + "age": 25, + "address": { + "state": "Texas", + "city": "Warsaw" + } + }, + { + "id": 3601, + "name": "Katina Romero", + "gender": "female", + "age": 73, + "address": { + "state": "Kentucky", + "city": "Newry" + } + }, + { + "id": 3602, + "name": "Cindy Lloyd", + "gender": "female", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Welda" + } + }, + { + "id": 3603, + "name": "Genevieve Delaney", + "gender": "female", + "age": 75, + "address": { + "state": "Utah", + "city": "Belva" + } + }, + { + "id": 3604, + "name": "Ashley Pennington", + "gender": "female", + "age": 45, + "address": { + "state": "Washington", + "city": "Rew" + } + }, + { + "id": 3605, + "name": "Hahn Harrison", + "gender": "male", + "age": 44, + "address": { + "state": "Montana", + "city": "Madaket" + } + }, + { + "id": 3606, + "name": "Kim Witt", + "gender": "male", + "age": 58, + "address": { + "state": "North Dakota", + "city": "Florence" + } + }, + { + "id": 3607, + "name": "Allie Elliott", + "gender": "female", + "age": 44, + "address": { + "state": "Nevada", + "city": "Roberts" + } + }, + { + "id": 3608, + "name": "Atkinson Wolfe", + "gender": "male", + "age": 37, + "address": { + "state": "Maryland", + "city": "Convent" + } + }, + { + "id": 3609, + "name": "Beasley Powell", + "gender": "male", + "age": 28, + "address": { + "state": "New Jersey", + "city": "Cannondale" + } + }, + { + "id": 3610, + "name": "Zimmerman Fisher", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Homeworth" + } + }, + { + "id": 3611, + "name": "Ollie Pearson", + "gender": "female", + "age": 53, + "address": { + "state": "Colorado", + "city": "Tilden" + } + }, + { + "id": 3612, + "name": "Ruth Palmer", + "gender": "female", + "age": 27, + "address": { + "state": "Kansas", + "city": "Norris" + } + }, + { + "id": 3613, + "name": "Rosario Boyd", + "gender": "female", + "age": 17, + "address": { + "state": "New Hampshire", + "city": "Cliff" + } + }, + { + "id": 3614, + "name": "Levy Robinson", + "gender": "male", + "age": 63, + "address": { + "state": "Oregon", + "city": "Biddle" + } + }, + { + "id": 3615, + "name": "Monroe Maldonado", + "gender": "male", + "age": 72, + "address": { + "state": "Mississippi", + "city": "Santel" + } + }, + { + "id": 3616, + "name": "Shaffer Aguirre", + "gender": "male", + "age": 66, + "address": { + "state": "Maine", + "city": "Eastmont" + } + }, + { + "id": 3617, + "name": "Flynn Bush", + "gender": "male", + "age": 35, + "address": { + "state": "New York", + "city": "Ladera" + } + }, + { + "id": 3618, + "name": "Hallie Terry", + "gender": "female", + "age": 18, + "address": { + "state": "South Carolina", + "city": "Sylvanite" + } + }, + { + "id": 3619, + "name": "James Curry", + "gender": "female", + "age": 29, + "address": { + "state": "North Carolina", + "city": "Linwood" + } + }, + { + "id": 3620, + "name": "Nichols Fowler", + "gender": "male", + "age": 63, + "address": { + "state": "California", + "city": "Fairhaven" + } + }, + { + "id": 3621, + "name": "Beulah Shaw", + "gender": "female", + "age": 37, + "address": { + "state": "Michigan", + "city": "Spokane" + } + }, + { + "id": 3622, + "name": "Chen Richards", + "gender": "male", + "age": 32, + "address": { + "state": "Arizona", + "city": "Martinez" + } + }, + { + "id": 3623, + "name": "Kelsey Valenzuela", + "gender": "female", + "age": 61, + "address": { + "state": "Idaho", + "city": "Chelsea" + } + }, + { + "id": 3624, + "name": "Chan Everett", + "gender": "male", + "age": 18, + "address": { + "state": "Florida", + "city": "Coultervillle" + } + }, + { + "id": 3625, + "name": "Adrienne Kelly", + "gender": "female", + "age": 64, + "address": { + "state": "West Virginia", + "city": "Aberdeen" + } + }, + { + "id": 3626, + "name": "Renee Hood", + "gender": "female", + "age": 68, + "address": { + "state": "Utah", + "city": "Bawcomville" + } + }, + { + "id": 3627, + "name": "Crane Rush", + "gender": "male", + "age": 66, + "address": { + "state": "Minnesota", + "city": "Rowe" + } + }, + { + "id": 3628, + "name": "Fleming Mendez", + "gender": "male", + "age": 64, + "address": { + "state": "Colorado", + "city": "Topaz" + } + }, + { + "id": 3629, + "name": "Susanne Osborn", + "gender": "female", + "age": 42, + "address": { + "state": "Alabama", + "city": "Brenton" + } + }, + { + "id": 3630, + "name": "Jaclyn Mccoy", + "gender": "female", + "age": 76, + "address": { + "state": "Pennsylvania", + "city": "Camino" + } + }, + { + "id": 3631, + "name": "Espinoza Fowler", + "gender": "male", + "age": 60, + "address": { + "state": "Idaho", + "city": "Thatcher" + } + }, + { + "id": 3632, + "name": "Mcmahon Sullivan", + "gender": "male", + "age": 64, + "address": { + "state": "Iowa", + "city": "Homeworth" + } + }, + { + "id": 3633, + "name": "Mari Giles", + "gender": "female", + "age": 34, + "address": { + "state": "Connecticut", + "city": "Groveville" + } + }, + { + "id": 3634, + "name": "Hardy Kramer", + "gender": "male", + "age": 62, + "address": { + "state": "Maine", + "city": "Klagetoh" + } + }, + { + "id": 3635, + "name": "Cooke Heath", + "gender": "male", + "age": 41, + "address": { + "state": "Maryland", + "city": "Grazierville" + } + }, + { + "id": 3636, + "name": "Judy Cameron", + "gender": "female", + "age": 36, + "address": { + "state": "Illinois", + "city": "Bakersville" + } + }, + { + "id": 3637, + "name": "Jacklyn Ryan", + "gender": "female", + "age": 54, + "address": { + "state": "Arkansas", + "city": "Hannasville" + } + }, + { + "id": 3638, + "name": "Church Wynn", + "gender": "male", + "age": 18, + "address": { + "state": "Michigan", + "city": "Beason" + } + }, + { + "id": 3639, + "name": "Holmes Kline", + "gender": "male", + "age": 76, + "address": { + "state": "Kentucky", + "city": "Emison" + } + }, + { + "id": 3640, + "name": "Austin Garcia", + "gender": "male", + "age": 73, + "address": { + "state": "Delaware", + "city": "Herbster" + } + }, + { + "id": 3641, + "name": "Jodi Thornton", + "gender": "female", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Rivers" + } + }, + { + "id": 3642, + "name": "Terri Talley", + "gender": "female", + "age": 66, + "address": { + "state": "South Dakota", + "city": "Falconaire" + } + }, + { + "id": 3643, + "name": "Solomon Hudson", + "gender": "male", + "age": 49, + "address": { + "state": "Oklahoma", + "city": "Alden" + } + }, + { + "id": 3644, + "name": "Tammi Alexander", + "gender": "female", + "age": 76, + "address": { + "state": "New Mexico", + "city": "Goochland" + } + }, + { + "id": 3645, + "name": "Campbell Nelson", + "gender": "male", + "age": 31, + "address": { + "state": "New Jersey", + "city": "Springville" + } + }, + { + "id": 3646, + "name": "Hudson Finley", + "gender": "male", + "age": 49, + "address": { + "state": "Arizona", + "city": "Fidelis" + } + }, + { + "id": 3647, + "name": "Goodman Underwood", + "gender": "male", + "age": 66, + "address": { + "state": "Ohio", + "city": "Manila" + } + }, + { + "id": 3648, + "name": "Whitfield Sherman", + "gender": "male", + "age": 30, + "address": { + "state": "Alaska", + "city": "Mapletown" + } + }, + { + "id": 3649, + "name": "Karla Herman", + "gender": "female", + "age": 64, + "address": { + "state": "Montana", + "city": "Rushford" + } + }, + { + "id": 3650, + "name": "Patel Rodriquez", + "gender": "male", + "age": 42, + "address": { + "state": "Nevada", + "city": "Richford" + } + }, + { + "id": 3651, + "name": "Tammy Smith", + "gender": "female", + "age": 53, + "address": { + "state": "North Dakota", + "city": "Dupuyer" + } + }, + { + "id": 3652, + "name": "Lynne Coleman", + "gender": "female", + "age": 23, + "address": { + "state": "Louisiana", + "city": "Elliott" + } + }, + { + "id": 3653, + "name": "Janelle Dominguez", + "gender": "female", + "age": 33, + "address": { + "state": "Vermont", + "city": "Emory" + } + }, + { + "id": 3654, + "name": "Belinda Carey", + "gender": "female", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Nettie" + } + }, + { + "id": 3655, + "name": "Spencer Finch", + "gender": "male", + "age": 56, + "address": { + "state": "Virginia", + "city": "Chelsea" + } + }, + { + "id": 3656, + "name": "Mcneil Murray", + "gender": "male", + "age": 60, + "address": { + "state": "Mississippi", + "city": "Baker" + } + }, + { + "id": 3657, + "name": "Mercado Levy", + "gender": "male", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Deercroft" + } + }, + { + "id": 3658, + "name": "Hardin Short", + "gender": "male", + "age": 49, + "address": { + "state": "West Virginia", + "city": "Rodman" + } + }, + { + "id": 3659, + "name": "Ivy Villarreal", + "gender": "female", + "age": 33, + "address": { + "state": "California", + "city": "Vivian" + } + }, + { + "id": 3660, + "name": "Wolf Gould", + "gender": "male", + "age": 20, + "address": { + "state": "Georgia", + "city": "Westphalia" + } + }, + { + "id": 3661, + "name": "Lopez Buchanan", + "gender": "male", + "age": 36, + "address": { + "state": "Hawaii", + "city": "Shelby" + } + }, + { + "id": 3662, + "name": "Mercedes Benton", + "gender": "female", + "age": 23, + "address": { + "state": "Tennessee", + "city": "Caroline" + } + }, + { + "id": 3663, + "name": "Watkins Landry", + "gender": "male", + "age": 21, + "address": { + "state": "Texas", + "city": "Shaft" + } + }, + { + "id": 3664, + "name": "Pearl Bates", + "gender": "female", + "age": 60, + "address": { + "state": "Missouri", + "city": "Salvo" + } + }, + { + "id": 3665, + "name": "Daugherty Joyner", + "gender": "male", + "age": 58, + "address": { + "state": "North Carolina", + "city": "Sultana" + } + }, + { + "id": 3666, + "name": "Aida Farmer", + "gender": "female", + "age": 22, + "address": { + "state": "Oregon", + "city": "Levant" + } + }, + { + "id": 3667, + "name": "Kara Mcdonald", + "gender": "female", + "age": 70, + "address": { + "state": "Massachusetts", + "city": "Dalton" + } + }, + { + "id": 3668, + "name": "Dominique Mack", + "gender": "female", + "age": 64, + "address": { + "state": "Nebraska", + "city": "Crumpler" + } + }, + { + "id": 3669, + "name": "Whitehead Medina", + "gender": "male", + "age": 60, + "address": { + "state": "Wisconsin", + "city": "Rivereno" + } + }, + { + "id": 3670, + "name": "Lillie May", + "gender": "female", + "age": 50, + "address": { + "state": "Florida", + "city": "Edgar" + } + }, + { + "id": 3671, + "name": "Aurelia Gibbs", + "gender": "female", + "age": 59, + "address": { + "state": "Washington", + "city": "Torboy" + } + }, + { + "id": 3672, + "name": "Socorro Donaldson", + "gender": "female", + "age": 81, + "address": { + "state": "South Carolina", + "city": "Calverton" + } + }, + { + "id": 3673, + "name": "Consuelo Wiley", + "gender": "female", + "age": 18, + "address": { + "state": "Kansas", + "city": "Lacomb" + } + }, + { + "id": 3674, + "name": "Justine Gilmore", + "gender": "female", + "age": 56, + "address": { + "state": "New York", + "city": "Stouchsburg" + } + }, + { + "id": 3675, + "name": "Rivera Conway", + "gender": "male", + "age": 53, + "address": { + "state": "Hawaii", + "city": "Kraemer" + } + }, + { + "id": 3676, + "name": "Jenny Carlson", + "gender": "female", + "age": 73, + "address": { + "state": "New Mexico", + "city": "Hillsboro" + } + }, + { + "id": 3677, + "name": "Stafford Sheppard", + "gender": "male", + "age": 29, + "address": { + "state": "Idaho", + "city": "Crown" + } + }, + { + "id": 3678, + "name": "Deena Barker", + "gender": "female", + "age": 57, + "address": { + "state": "Maine", + "city": "Robinette" + } + }, + { + "id": 3679, + "name": "Lara Solis", + "gender": "female", + "age": 36, + "address": { + "state": "Tennessee", + "city": "Greer" + } + }, + { + "id": 3680, + "name": "Alyssa Kerr", + "gender": "female", + "age": 51, + "address": { + "state": "Maryland", + "city": "Wilsonia" + } + }, + { + "id": 3681, + "name": "Mckay Wiley", + "gender": "male", + "age": 64, + "address": { + "state": "Louisiana", + "city": "Wattsville" + } + }, + { + "id": 3682, + "name": "Kasey Howard", + "gender": "female", + "age": 53, + "address": { + "state": "California", + "city": "Nadine" + } + }, + { + "id": 3683, + "name": "Holman Turner", + "gender": "male", + "age": 34, + "address": { + "state": "Michigan", + "city": "Blanford" + } + }, + { + "id": 3684, + "name": "Fowler Hardy", + "gender": "male", + "age": 44, + "address": { + "state": "Oklahoma", + "city": "Garnet" + } + }, + { + "id": 3685, + "name": "Hurst Osborne", + "gender": "male", + "age": 81, + "address": { + "state": "Kansas", + "city": "Lodoga" + } + }, + { + "id": 3686, + "name": "Clay Vaughn", + "gender": "male", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Woodlake" + } + }, + { + "id": 3687, + "name": "Rose Adkins", + "gender": "female", + "age": 45, + "address": { + "state": "New Jersey", + "city": "Breinigsville" + } + }, + { + "id": 3688, + "name": "Myrtle Wyatt", + "gender": "female", + "age": 69, + "address": { + "state": "Wyoming", + "city": "Succasunna" + } + }, + { + "id": 3689, + "name": "Tracey Kirby", + "gender": "female", + "age": 72, + "address": { + "state": "Nebraska", + "city": "Chase" + } + }, + { + "id": 3690, + "name": "Lori Terrell", + "gender": "female", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Roeville" + } + }, + { + "id": 3691, + "name": "Jacobs Cox", + "gender": "male", + "age": 28, + "address": { + "state": "Oregon", + "city": "Allison" + } + }, + { + "id": 3692, + "name": "Villarreal Miles", + "gender": "male", + "age": 34, + "address": { + "state": "Vermont", + "city": "Bedias" + } + }, + { + "id": 3693, + "name": "Cheryl Gilliam", + "gender": "female", + "age": 41, + "address": { + "state": "Rhode Island", + "city": "Taft" + } + }, + { + "id": 3694, + "name": "Sharp Cohen", + "gender": "male", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Ballico" + } + }, + { + "id": 3695, + "name": "Steele Whitfield", + "gender": "male", + "age": 21, + "address": { + "state": "Pennsylvania", + "city": "Bethpage" + } + }, + { + "id": 3696, + "name": "Debora Perkins", + "gender": "female", + "age": 53, + "address": { + "state": "Illinois", + "city": "Glenbrook" + } + }, + { + "id": 3697, + "name": "Small Sykes", + "gender": "male", + "age": 28, + "address": { + "state": "Alaska", + "city": "Century" + } + }, + { + "id": 3698, + "name": "Delia Velasquez", + "gender": "female", + "age": 55, + "address": { + "state": "Texas", + "city": "Woodruff" + } + }, + { + "id": 3699, + "name": "Clara Emerson", + "gender": "female", + "age": 74, + "address": { + "state": "Iowa", + "city": "Boyd" + } + }, + { + "id": 3700, + "name": "Huffman Fisher", + "gender": "male", + "age": 24, + "address": { + "state": "Florida", + "city": "Durham" + } + }, + { + "id": 3701, + "name": "Bentley Ball", + "gender": "male", + "age": 33, + "address": { + "state": "Georgia", + "city": "Volta" + } + }, + { + "id": 3702, + "name": "Neva Daniel", + "gender": "female", + "age": 57, + "address": { + "state": "Wisconsin", + "city": "Oretta" + } + }, + { + "id": 3703, + "name": "Ware Harper", + "gender": "male", + "age": 59, + "address": { + "state": "Nevada", + "city": "Springhill" + } + }, + { + "id": 3704, + "name": "Hensley Foreman", + "gender": "male", + "age": 55, + "address": { + "state": "West Virginia", + "city": "Bawcomville" + } + }, + { + "id": 3705, + "name": "Baxter Christensen", + "gender": "male", + "age": 74, + "address": { + "state": "Washington", + "city": "Deercroft" + } + }, + { + "id": 3706, + "name": "Elisa Cortez", + "gender": "female", + "age": 23, + "address": { + "state": "Colorado", + "city": "Islandia" + } + }, + { + "id": 3707, + "name": "Roman Patel", + "gender": "male", + "age": 49, + "address": { + "state": "Massachusetts", + "city": "Fairlee" + } + }, + { + "id": 3708, + "name": "Janell Ortega", + "gender": "female", + "age": 30, + "address": { + "state": "Montana", + "city": "Rivera" + } + }, + { + "id": 3709, + "name": "Lindsey Bradshaw", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Roland" + } + }, + { + "id": 3710, + "name": "Winters James", + "gender": "male", + "age": 57, + "address": { + "state": "Indiana", + "city": "Boykin" + } + }, + { + "id": 3711, + "name": "Tamika Mcclure", + "gender": "female", + "age": 30, + "address": { + "state": "Delaware", + "city": "Edinburg" + } + }, + { + "id": 3712, + "name": "Allison Galloway", + "gender": "male", + "age": 31, + "address": { + "state": "Missouri", + "city": "Duryea" + } + }, + { + "id": 3713, + "name": "Lawrence Preston", + "gender": "male", + "age": 66, + "address": { + "state": "Arizona", + "city": "Wyoming" + } + }, + { + "id": 3714, + "name": "Kinney Cash", + "gender": "male", + "age": 80, + "address": { + "state": "Connecticut", + "city": "Moscow" + } + }, + { + "id": 3715, + "name": "Kirkland Montgomery", + "gender": "male", + "age": 31, + "address": { + "state": "Kentucky", + "city": "Cazadero" + } + }, + { + "id": 3716, + "name": "Ines Valdez", + "gender": "female", + "age": 80, + "address": { + "state": "Alabama", + "city": "National" + } + }, + { + "id": 3717, + "name": "Roy Rojas", + "gender": "male", + "age": 55, + "address": { + "state": "Virginia", + "city": "Sehili" + } + }, + { + "id": 3718, + "name": "Roth Holloway", + "gender": "male", + "age": 52, + "address": { + "state": "Ohio", + "city": "Wyano" + } + }, + { + "id": 3719, + "name": "Coffey Wilkerson", + "gender": "male", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Hanover" + } + }, + { + "id": 3720, + "name": "Reyes Smith", + "gender": "male", + "age": 74, + "address": { + "state": "Utah", + "city": "Leyner" + } + }, + { + "id": 3721, + "name": "Harrison Carey", + "gender": "male", + "age": 38, + "address": { + "state": "New York", + "city": "Glendale" + } + }, + { + "id": 3722, + "name": "Hilda Atkinson", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Saticoy" + } + }, + { + "id": 3723, + "name": "Nellie Wilder", + "gender": "female", + "age": 74, + "address": { + "state": "Mississippi", + "city": "Vienna" + } + }, + { + "id": 3724, + "name": "Elvia Knowles", + "gender": "female", + "age": 48, + "address": { + "state": "Illinois", + "city": "Robinson" + } + }, + { + "id": 3725, + "name": "Kenya Wall", + "gender": "female", + "age": 65, + "address": { + "state": "Mississippi", + "city": "Loretto" + } + }, + { + "id": 3726, + "name": "Dickerson Vincent", + "gender": "male", + "age": 36, + "address": { + "state": "Rhode Island", + "city": "Navarre" + } + }, + { + "id": 3727, + "name": "Santos Underwood", + "gender": "male", + "age": 50, + "address": { + "state": "Connecticut", + "city": "Cleary" + } + }, + { + "id": 3728, + "name": "York Ingram", + "gender": "male", + "age": 64, + "address": { + "state": "Virginia", + "city": "Chaparrito" + } + }, + { + "id": 3729, + "name": "Gamble Perry", + "gender": "male", + "age": 23, + "address": { + "state": "Maine", + "city": "Richville" + } + }, + { + "id": 3730, + "name": "Cline Coffey", + "gender": "male", + "age": 33, + "address": { + "state": "Washington", + "city": "Nicholson" + } + }, + { + "id": 3731, + "name": "Blanchard Serrano", + "gender": "male", + "age": 46, + "address": { + "state": "Iowa", + "city": "Kraemer" + } + }, + { + "id": 3732, + "name": "Cathy Dean", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Edneyville" + } + }, + { + "id": 3733, + "name": "Hebert Alexander", + "gender": "male", + "age": 55, + "address": { + "state": "Missouri", + "city": "Snelling" + } + }, + { + "id": 3734, + "name": "Roach Jennings", + "gender": "male", + "age": 50, + "address": { + "state": "West Virginia", + "city": "Sexton" + } + }, + { + "id": 3735, + "name": "Larson Manning", + "gender": "male", + "age": 27, + "address": { + "state": "South Dakota", + "city": "Henrietta" + } + }, + { + "id": 3736, + "name": "Lawson Wiley", + "gender": "male", + "age": 28, + "address": { + "state": "Georgia", + "city": "Trona" + } + }, + { + "id": 3737, + "name": "Lawrence Bush", + "gender": "male", + "age": 69, + "address": { + "state": "Wisconsin", + "city": "Enlow" + } + }, + { + "id": 3738, + "name": "Yates Webster", + "gender": "male", + "age": 61, + "address": { + "state": "New Hampshire", + "city": "Warsaw" + } + }, + { + "id": 3739, + "name": "Acosta Yates", + "gender": "male", + "age": 44, + "address": { + "state": "Indiana", + "city": "Salvo" + } + }, + { + "id": 3740, + "name": "Carlson Shepard", + "gender": "male", + "age": 76, + "address": { + "state": "Arizona", + "city": "Loveland" + } + }, + { + "id": 3741, + "name": "Byrd Ochoa", + "gender": "male", + "age": 54, + "address": { + "state": "Utah", + "city": "Sattley" + } + }, + { + "id": 3742, + "name": "Dixie Goff", + "gender": "female", + "age": 54, + "address": { + "state": "Hawaii", + "city": "Dale" + } + }, + { + "id": 3743, + "name": "Corrine Jimenez", + "gender": "female", + "age": 36, + "address": { + "state": "Alaska", + "city": "Tampico" + } + }, + { + "id": 3744, + "name": "Fuentes Christensen", + "gender": "male", + "age": 72, + "address": { + "state": "Delaware", + "city": "Martinez" + } + }, + { + "id": 3745, + "name": "Kristen Reilly", + "gender": "female", + "age": 19, + "address": { + "state": "Florida", + "city": "Libertytown" + } + }, + { + "id": 3746, + "name": "Kerry Gallegos", + "gender": "female", + "age": 33, + "address": { + "state": "Massachusetts", + "city": "Riviera" + } + }, + { + "id": 3747, + "name": "Bates Cooke", + "gender": "male", + "age": 42, + "address": { + "state": "Kansas", + "city": "Linganore" + } + }, + { + "id": 3748, + "name": "Earnestine Kemp", + "gender": "female", + "age": 75, + "address": { + "state": "Montana", + "city": "Chamberino" + } + }, + { + "id": 3749, + "name": "Patrica Pearson", + "gender": "female", + "age": 52, + "address": { + "state": "Tennessee", + "city": "Floriston" + } + }, + { + "id": 3750, + "name": "Peters Lucas", + "gender": "male", + "age": 25, + "address": { + "state": "New York", + "city": "Lookingglass" + } + }, + { + "id": 3751, + "name": "Christa Cole", + "gender": "female", + "age": 35, + "address": { + "state": "Pennsylvania", + "city": "Neahkahnie" + } + }, + { + "id": 3752, + "name": "Roxie Pope", + "gender": "female", + "age": 45, + "address": { + "state": "Colorado", + "city": "Websterville" + } + }, + { + "id": 3753, + "name": "Santiago King", + "gender": "male", + "age": 32, + "address": { + "state": "Idaho", + "city": "Chemung" + } + }, + { + "id": 3754, + "name": "Juliette Weaver", + "gender": "female", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Urbana" + } + }, + { + "id": 3755, + "name": "Annette Beck", + "gender": "female", + "age": 77, + "address": { + "state": "Michigan", + "city": "Carlos" + } + }, + { + "id": 3756, + "name": "Taylor Burns", + "gender": "male", + "age": 18, + "address": { + "state": "North Carolina", + "city": "Grandview" + } + }, + { + "id": 3757, + "name": "Doris Alston", + "gender": "female", + "age": 75, + "address": { + "state": "South Carolina", + "city": "Kula" + } + }, + { + "id": 3758, + "name": "Cheri Rowland", + "gender": "female", + "age": 74, + "address": { + "state": "New Jersey", + "city": "Wintersburg" + } + }, + { + "id": 3759, + "name": "Millie Griffin", + "gender": "female", + "age": 53, + "address": { + "state": "California", + "city": "Collins" + } + }, + { + "id": 3760, + "name": "Christie Adams", + "gender": "female", + "age": 77, + "address": { + "state": "Nebraska", + "city": "Orick" + } + }, + { + "id": 3761, + "name": "Jacqueline Valentine", + "gender": "female", + "age": 46, + "address": { + "state": "Nevada", + "city": "Statenville" + } + }, + { + "id": 3762, + "name": "Hawkins Hyde", + "gender": "male", + "age": 37, + "address": { + "state": "Alabama", + "city": "Nash" + } + }, + { + "id": 3763, + "name": "Valeria Brock", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Vivian" + } + }, + { + "id": 3764, + "name": "Oliver Swanson", + "gender": "male", + "age": 37, + "address": { + "state": "Vermont", + "city": "Troy" + } + }, + { + "id": 3765, + "name": "May Chavez", + "gender": "male", + "age": 78, + "address": { + "state": "Oregon", + "city": "Berlin" + } + }, + { + "id": 3766, + "name": "Lynn Kim", + "gender": "male", + "age": 75, + "address": { + "state": "Oklahoma", + "city": "Needmore" + } + }, + { + "id": 3767, + "name": "Dodson Suarez", + "gender": "male", + "age": 46, + "address": { + "state": "Kentucky", + "city": "Bentley" + } + }, + { + "id": 3768, + "name": "Joanne Young", + "gender": "female", + "age": 62, + "address": { + "state": "Arkansas", + "city": "Sunriver" + } + }, + { + "id": 3769, + "name": "Howard Hill", + "gender": "male", + "age": 56, + "address": { + "state": "Ohio", + "city": "Stouchsburg" + } + }, + { + "id": 3770, + "name": "Battle Wyatt", + "gender": "male", + "age": 65, + "address": { + "state": "Maryland", + "city": "Adamstown" + } + }, + { + "id": 3771, + "name": "Jill Acevedo", + "gender": "female", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Jugtown" + } + }, + { + "id": 3772, + "name": "Leah Shaw", + "gender": "female", + "age": 66, + "address": { + "state": "New Mexico", + "city": "Ernstville" + } + }, + { + "id": 3773, + "name": "Chris Hooper", + "gender": "female", + "age": 35, + "address": { + "state": "California", + "city": "Oley" + } + }, + { + "id": 3774, + "name": "Barrera Hubbard", + "gender": "male", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Emory" + } + }, + { + "id": 3775, + "name": "Mildred Browning", + "gender": "female", + "age": 63, + "address": { + "state": "Nevada", + "city": "Weeksville" + } + }, + { + "id": 3776, + "name": "Kinney Blair", + "gender": "male", + "age": 66, + "address": { + "state": "Colorado", + "city": "Innsbrook" + } + }, + { + "id": 3777, + "name": "Lowe Chan", + "gender": "male", + "age": 81, + "address": { + "state": "Tennessee", + "city": "Coinjock" + } + }, + { + "id": 3778, + "name": "Banks Gregory", + "gender": "male", + "age": 31, + "address": { + "state": "Nebraska", + "city": "Eden" + } + }, + { + "id": 3779, + "name": "Magdalena Bruce", + "gender": "female", + "age": 29, + "address": { + "state": "Arizona", + "city": "Crisman" + } + }, + { + "id": 3780, + "name": "Sharp Leblanc", + "gender": "male", + "age": 29, + "address": { + "state": "Illinois", + "city": "Savannah" + } + }, + { + "id": 3781, + "name": "Ina Brooks", + "gender": "female", + "age": 34, + "address": { + "state": "Missouri", + "city": "Olney" + } + }, + { + "id": 3782, + "name": "Angelina Chandler", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Columbus" + } + }, + { + "id": 3783, + "name": "Laurel Dunlap", + "gender": "female", + "age": 26, + "address": { + "state": "Hawaii", + "city": "Greenwich" + } + }, + { + "id": 3784, + "name": "Hood Whitehead", + "gender": "male", + "age": 65, + "address": { + "state": "Delaware", + "city": "Maplewood" + } + }, + { + "id": 3785, + "name": "Price Cleveland", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Beaverdale" + } + }, + { + "id": 3786, + "name": "Barker England", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Caroline" + } + }, + { + "id": 3787, + "name": "Beasley Chapman", + "gender": "male", + "age": 45, + "address": { + "state": "Mississippi", + "city": "Hachita" + } + }, + { + "id": 3788, + "name": "Claudine Elliott", + "gender": "female", + "age": 68, + "address": { + "state": "Michigan", + "city": "Southview" + } + }, + { + "id": 3789, + "name": "Nolan Mullen", + "gender": "male", + "age": 82, + "address": { + "state": "Alaska", + "city": "Maybell" + } + }, + { + "id": 3790, + "name": "Martinez Ortiz", + "gender": "male", + "age": 29, + "address": { + "state": "New Mexico", + "city": "Fowlerville" + } + }, + { + "id": 3791, + "name": "Robin Lowe", + "gender": "female", + "age": 27, + "address": { + "state": "Arkansas", + "city": "Wilsonia" + } + }, + { + "id": 3792, + "name": "Ruthie Boyle", + "gender": "female", + "age": 52, + "address": { + "state": "Kansas", + "city": "Malo" + } + }, + { + "id": 3793, + "name": "Kathy Mclaughlin", + "gender": "female", + "age": 24, + "address": { + "state": "Georgia", + "city": "Frank" + } + }, + { + "id": 3794, + "name": "Bertha Bush", + "gender": "female", + "age": 55, + "address": { + "state": "Vermont", + "city": "Yonah" + } + }, + { + "id": 3795, + "name": "Pierce Sharpe", + "gender": "male", + "age": 65, + "address": { + "state": "Montana", + "city": "Bodega" + } + }, + { + "id": 3796, + "name": "Montoya Cross", + "gender": "male", + "age": 63, + "address": { + "state": "Connecticut", + "city": "Avoca" + } + }, + { + "id": 3797, + "name": "Stephenson Yates", + "gender": "male", + "age": 48, + "address": { + "state": "Kentucky", + "city": "Valmy" + } + }, + { + "id": 3798, + "name": "Hawkins Holder", + "gender": "male", + "age": 32, + "address": { + "state": "Idaho", + "city": "Gasquet" + } + }, + { + "id": 3799, + "name": "Herminia Trevino", + "gender": "female", + "age": 66, + "address": { + "state": "Louisiana", + "city": "Russellville" + } + }, + { + "id": 3800, + "name": "Kenya Spears", + "gender": "female", + "age": 37, + "address": { + "state": "Massachusetts", + "city": "Orick" + } + }, + { + "id": 3801, + "name": "Rosetta Owens", + "gender": "female", + "age": 52, + "address": { + "state": "Virginia", + "city": "Beyerville" + } + }, + { + "id": 3802, + "name": "Mckay Cannon", + "gender": "male", + "age": 40, + "address": { + "state": "Oregon", + "city": "Statenville" + } + }, + { + "id": 3803, + "name": "Maryellen Sweet", + "gender": "female", + "age": 49, + "address": { + "state": "New York", + "city": "Nettie" + } + }, + { + "id": 3804, + "name": "Michael Snyder", + "gender": "female", + "age": 18, + "address": { + "state": "Iowa", + "city": "Nescatunga" + } + }, + { + "id": 3805, + "name": "Norton Lamb", + "gender": "male", + "age": 48, + "address": { + "state": "Maryland", + "city": "Enetai" + } + }, + { + "id": 3806, + "name": "Ines Buckley", + "gender": "female", + "age": 50, + "address": { + "state": "Rhode Island", + "city": "Galesville" + } + }, + { + "id": 3807, + "name": "Wade Buckner", + "gender": "male", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Conway" + } + }, + { + "id": 3808, + "name": "Snyder Boyd", + "gender": "male", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Woodburn" + } + }, + { + "id": 3809, + "name": "Lenore Guzman", + "gender": "female", + "age": 60, + "address": { + "state": "North Dakota", + "city": "Barrelville" + } + }, + { + "id": 3810, + "name": "Koch Bailey", + "gender": "male", + "age": 56, + "address": { + "state": "Indiana", + "city": "Dotsero" + } + }, + { + "id": 3811, + "name": "Denise Britt", + "gender": "female", + "age": 21, + "address": { + "state": "Maine", + "city": "Machias" + } + }, + { + "id": 3812, + "name": "Tanisha Everett", + "gender": "female", + "age": 69, + "address": { + "state": "Washington", + "city": "Tivoli" + } + }, + { + "id": 3813, + "name": "Raquel Holcomb", + "gender": "female", + "age": 57, + "address": { + "state": "Minnesota", + "city": "Lavalette" + } + }, + { + "id": 3814, + "name": "Harriett Riggs", + "gender": "female", + "age": 36, + "address": { + "state": "Florida", + "city": "Martell" + } + }, + { + "id": 3815, + "name": "Strickland Kirby", + "gender": "male", + "age": 77, + "address": { + "state": "Alabama", + "city": "Taft" + } + }, + { + "id": 3816, + "name": "Amber Perry", + "gender": "female", + "age": 35, + "address": { + "state": "South Dakota", + "city": "Baker" + } + }, + { + "id": 3817, + "name": "Kara Day", + "gender": "female", + "age": 44, + "address": { + "state": "Ohio", + "city": "Shawmut" + } + }, + { + "id": 3818, + "name": "Dee Finley", + "gender": "female", + "age": 53, + "address": { + "state": "Wyoming", + "city": "Camino" + } + }, + { + "id": 3819, + "name": "Barr Humphrey", + "gender": "male", + "age": 17, + "address": { + "state": "Texas", + "city": "Weedville" + } + }, + { + "id": 3820, + "name": "Jamie Walters", + "gender": "female", + "age": 31, + "address": { + "state": "Wisconsin", + "city": "Marienthal" + } + }, + { + "id": 3821, + "name": "Valarie Rush", + "gender": "female", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Caberfae" + } + }, + { + "id": 3822, + "name": "Carolina Fields", + "gender": "female", + "age": 39, + "address": { + "state": "Kansas", + "city": "Hailesboro" + } + }, + { + "id": 3823, + "name": "Casey Robles", + "gender": "male", + "age": 24, + "address": { + "state": "Nebraska", + "city": "Chemung" + } + }, + { + "id": 3824, + "name": "Sears Dennis", + "gender": "male", + "age": 47, + "address": { + "state": "Georgia", + "city": "Finzel" + } + }, + { + "id": 3825, + "name": "Marianne Buchanan", + "gender": "female", + "age": 54, + "address": { + "state": "Florida", + "city": "Callaghan" + } + }, + { + "id": 3826, + "name": "Shepherd Weeks", + "gender": "male", + "age": 19, + "address": { + "state": "Michigan", + "city": "Germanton" + } + }, + { + "id": 3827, + "name": "Anderson Rhodes", + "gender": "male", + "age": 38, + "address": { + "state": "Colorado", + "city": "Movico" + } + }, + { + "id": 3828, + "name": "Irma Hardin", + "gender": "female", + "age": 19, + "address": { + "state": "Iowa", + "city": "Bordelonville" + } + }, + { + "id": 3829, + "name": "Carrillo Bass", + "gender": "male", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Gratton" + } + }, + { + "id": 3830, + "name": "Ronda Bradley", + "gender": "female", + "age": 44, + "address": { + "state": "Arkansas", + "city": "Leroy" + } + }, + { + "id": 3831, + "name": "Pearl Oliver", + "gender": "female", + "age": 75, + "address": { + "state": "West Virginia", + "city": "Yonah" + } + }, + { + "id": 3832, + "name": "Dillard Beach", + "gender": "male", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Lupton" + } + }, + { + "id": 3833, + "name": "Graham Wilder", + "gender": "male", + "age": 80, + "address": { + "state": "Alabama", + "city": "Breinigsville" + } + }, + { + "id": 3834, + "name": "Sharlene Shelton", + "gender": "female", + "age": 80, + "address": { + "state": "Hawaii", + "city": "Levant" + } + }, + { + "id": 3835, + "name": "Autumn Cobb", + "gender": "female", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Leming" + } + }, + { + "id": 3836, + "name": "Blackburn Benson", + "gender": "male", + "age": 44, + "address": { + "state": "Oregon", + "city": "Outlook" + } + }, + { + "id": 3837, + "name": "Imelda Vega", + "gender": "female", + "age": 23, + "address": { + "state": "California", + "city": "Bluetown" + } + }, + { + "id": 3838, + "name": "Giles Spencer", + "gender": "male", + "age": 40, + "address": { + "state": "Pennsylvania", + "city": "Bartley" + } + }, + { + "id": 3839, + "name": "Butler Jensen", + "gender": "male", + "age": 70, + "address": { + "state": "Missouri", + "city": "Wescosville" + } + }, + { + "id": 3840, + "name": "Rutledge Lang", + "gender": "male", + "age": 54, + "address": { + "state": "Washington", + "city": "Fairmount" + } + }, + { + "id": 3841, + "name": "Elisabeth Buckley", + "gender": "female", + "age": 38, + "address": { + "state": "New Jersey", + "city": "Kula" + } + }, + { + "id": 3842, + "name": "Daniel Haynes", + "gender": "male", + "age": 22, + "address": { + "state": "Indiana", + "city": "Frierson" + } + }, + { + "id": 3843, + "name": "Elba Burks", + "gender": "female", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Shasta" + } + }, + { + "id": 3844, + "name": "Farrell Sanford", + "gender": "male", + "age": 46, + "address": { + "state": "New York", + "city": "Joes" + } + }, + { + "id": 3845, + "name": "Amber Waller", + "gender": "female", + "age": 69, + "address": { + "state": "Arizona", + "city": "Allendale" + } + }, + { + "id": 3846, + "name": "Rosario Tyler", + "gender": "male", + "age": 77, + "address": { + "state": "Montana", + "city": "Oneida" + } + }, + { + "id": 3847, + "name": "Henrietta Reynolds", + "gender": "female", + "age": 53, + "address": { + "state": "Virginia", + "city": "Kipp" + } + }, + { + "id": 3848, + "name": "Tamara Kennedy", + "gender": "female", + "age": 30, + "address": { + "state": "Connecticut", + "city": "Hamilton" + } + }, + { + "id": 3849, + "name": "Wells Sanders", + "gender": "male", + "age": 59, + "address": { + "state": "Vermont", + "city": "Hendersonville" + } + }, + { + "id": 3850, + "name": "Booth Curry", + "gender": "male", + "age": 40, + "address": { + "state": "Texas", + "city": "Troy" + } + }, + { + "id": 3851, + "name": "Greer Kramer", + "gender": "male", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Edinburg" + } + }, + { + "id": 3852, + "name": "Jean Pate", + "gender": "female", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Canterwood" + } + }, + { + "id": 3853, + "name": "Gregory Serrano", + "gender": "male", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Nile" + } + }, + { + "id": 3854, + "name": "Avila Cervantes", + "gender": "male", + "age": 25, + "address": { + "state": "Utah", + "city": "Madaket" + } + }, + { + "id": 3855, + "name": "Wynn Barrera", + "gender": "male", + "age": 72, + "address": { + "state": "South Dakota", + "city": "Collins" + } + }, + { + "id": 3856, + "name": "Sonja Fox", + "gender": "female", + "age": 74, + "address": { + "state": "Alaska", + "city": "Allensworth" + } + }, + { + "id": 3857, + "name": "Britt Mcclain", + "gender": "male", + "age": 50, + "address": { + "state": "Massachusetts", + "city": "Templeton" + } + }, + { + "id": 3858, + "name": "Mcleod Pace", + "gender": "male", + "age": 75, + "address": { + "state": "Idaho", + "city": "Frystown" + } + }, + { + "id": 3859, + "name": "Mary Holloway", + "gender": "female", + "age": 18, + "address": { + "state": "Ohio", + "city": "Jessie" + } + }, + { + "id": 3860, + "name": "Hill Merritt", + "gender": "male", + "age": 22, + "address": { + "state": "Wyoming", + "city": "Jeff" + } + }, + { + "id": 3861, + "name": "Deidre Wolfe", + "gender": "female", + "age": 78, + "address": { + "state": "Delaware", + "city": "Weeksville" + } + }, + { + "id": 3862, + "name": "May Chaney", + "gender": "male", + "age": 60, + "address": { + "state": "Maine", + "city": "Lutsen" + } + }, + { + "id": 3863, + "name": "Ladonna Blake", + "gender": "female", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Rivera" + } + }, + { + "id": 3864, + "name": "Wilder Schwartz", + "gender": "male", + "age": 21, + "address": { + "state": "South Carolina", + "city": "Cloverdale" + } + }, + { + "id": 3865, + "name": "Ferguson Huber", + "gender": "male", + "age": 56, + "address": { + "state": "Nevada", + "city": "Williston" + } + }, + { + "id": 3866, + "name": "Delacruz Anderson", + "gender": "male", + "age": 33, + "address": { + "state": "Mississippi", + "city": "Smock" + } + }, + { + "id": 3867, + "name": "Mcmillan Holcomb", + "gender": "male", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Salix" + } + }, + { + "id": 3868, + "name": "Millicent Coffey", + "gender": "female", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Delwood" + } + }, + { + "id": 3869, + "name": "Nina Rush", + "gender": "female", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Jugtown" + } + }, + { + "id": 3870, + "name": "Dorsey Cote", + "gender": "male", + "age": 43, + "address": { + "state": "Maryland", + "city": "Jackpot" + } + }, + { + "id": 3871, + "name": "Clarke Moran", + "gender": "male", + "age": 47, + "address": { + "state": "Colorado", + "city": "Calverton" + } + }, + { + "id": 3872, + "name": "Maura Berg", + "gender": "female", + "age": 82, + "address": { + "state": "Delaware", + "city": "Teasdale" + } + }, + { + "id": 3873, + "name": "Holcomb Mccormick", + "gender": "male", + "age": 36, + "address": { + "state": "Oklahoma", + "city": "Tonopah" + } + }, + { + "id": 3874, + "name": "Clarissa Sparks", + "gender": "female", + "age": 41, + "address": { + "state": "Arizona", + "city": "Cashtown" + } + }, + { + "id": 3875, + "name": "Lillian Cochran", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Murillo" + } + }, + { + "id": 3876, + "name": "Angelita Sears", + "gender": "female", + "age": 76, + "address": { + "state": "Rhode Island", + "city": "Hardyville" + } + }, + { + "id": 3877, + "name": "Kristi Rodriquez", + "gender": "female", + "age": 60, + "address": { + "state": "Arkansas", + "city": "Frierson" + } + }, + { + "id": 3878, + "name": "Rollins Ross", + "gender": "male", + "age": 62, + "address": { + "state": "Idaho", + "city": "Beason" + } + }, + { + "id": 3879, + "name": "Gilda Shepherd", + "gender": "female", + "age": 33, + "address": { + "state": "Texas", + "city": "Linwood" + } + }, + { + "id": 3880, + "name": "Yolanda Porter", + "gender": "female", + "age": 47, + "address": { + "state": "Nevada", + "city": "Frizzleburg" + } + }, + { + "id": 3881, + "name": "Erin Terrell", + "gender": "female", + "age": 27, + "address": { + "state": "California", + "city": "Tivoli" + } + }, + { + "id": 3882, + "name": "Vinson Bowers", + "gender": "male", + "age": 45, + "address": { + "state": "Florida", + "city": "Dale" + } + }, + { + "id": 3883, + "name": "Dixon Anderson", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Condon" + } + }, + { + "id": 3884, + "name": "Chelsea Carlson", + "gender": "female", + "age": 58, + "address": { + "state": "Kansas", + "city": "Shrewsbury" + } + }, + { + "id": 3885, + "name": "Lawanda Turner", + "gender": "female", + "age": 77, + "address": { + "state": "Utah", + "city": "Berlin" + } + }, + { + "id": 3886, + "name": "Ofelia Ayala", + "gender": "female", + "age": 72, + "address": { + "state": "Michigan", + "city": "Topaz" + } + }, + { + "id": 3887, + "name": "Garza Buck", + "gender": "male", + "age": 18, + "address": { + "state": "Wyoming", + "city": "Bagtown" + } + }, + { + "id": 3888, + "name": "Lynn Gardner", + "gender": "male", + "age": 20, + "address": { + "state": "Ohio", + "city": "Chelsea" + } + }, + { + "id": 3889, + "name": "John Christian", + "gender": "female", + "age": 34, + "address": { + "state": "North Carolina", + "city": "Enetai" + } + }, + { + "id": 3890, + "name": "Snow Gentry", + "gender": "male", + "age": 29, + "address": { + "state": "Massachusetts", + "city": "Topanga" + } + }, + { + "id": 3891, + "name": "Hardin Knox", + "gender": "male", + "age": 72, + "address": { + "state": "Washington", + "city": "Fredericktown" + } + }, + { + "id": 3892, + "name": "Tina Blanchard", + "gender": "female", + "age": 54, + "address": { + "state": "Minnesota", + "city": "Caspar" + } + }, + { + "id": 3893, + "name": "Cassie Herring", + "gender": "female", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Whipholt" + } + }, + { + "id": 3894, + "name": "Caldwell Kent", + "gender": "male", + "age": 51, + "address": { + "state": "North Dakota", + "city": "Castleton" + } + }, + { + "id": 3895, + "name": "Schultz Avery", + "gender": "male", + "age": 44, + "address": { + "state": "New Jersey", + "city": "Virgie" + } + }, + { + "id": 3896, + "name": "Jaclyn Barrera", + "gender": "female", + "age": 50, + "address": { + "state": "Virginia", + "city": "Vernon" + } + }, + { + "id": 3897, + "name": "Owens Woods", + "gender": "male", + "age": 32, + "address": { + "state": "Louisiana", + "city": "Bonanza" + } + }, + { + "id": 3898, + "name": "Janna Simon", + "gender": "female", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Cuylerville" + } + }, + { + "id": 3899, + "name": "Anastasia Kirby", + "gender": "female", + "age": 29, + "address": { + "state": "Indiana", + "city": "Leland" + } + }, + { + "id": 3900, + "name": "Rocha Ayers", + "gender": "male", + "age": 17, + "address": { + "state": "Missouri", + "city": "Monument" + } + }, + { + "id": 3901, + "name": "Figueroa Curtis", + "gender": "male", + "age": 52, + "address": { + "state": "Tennessee", + "city": "Coalmont" + } + }, + { + "id": 3902, + "name": "Kristine Vaughn", + "gender": "female", + "age": 57, + "address": { + "state": "Georgia", + "city": "Kiskimere" + } + }, + { + "id": 3903, + "name": "Mejia Larson", + "gender": "male", + "age": 63, + "address": { + "state": "South Carolina", + "city": "Highland" + } + }, + { + "id": 3904, + "name": "Dejesus Hawkins", + "gender": "male", + "age": 71, + "address": { + "state": "Alaska", + "city": "Orviston" + } + }, + { + "id": 3905, + "name": "Dickson Bradley", + "gender": "male", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Fowlerville" + } + }, + { + "id": 3906, + "name": "Ramsey Acosta", + "gender": "male", + "age": 53, + "address": { + "state": "Wisconsin", + "city": "Clinton" + } + }, + { + "id": 3907, + "name": "Stacie Moses", + "gender": "female", + "age": 50, + "address": { + "state": "New York", + "city": "Byrnedale" + } + }, + { + "id": 3908, + "name": "Terry Gregory", + "gender": "female", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Fivepointville" + } + }, + { + "id": 3909, + "name": "Joyner Villarreal", + "gender": "male", + "age": 33, + "address": { + "state": "Nebraska", + "city": "Wolcott" + } + }, + { + "id": 3910, + "name": "Sanford Daugherty", + "gender": "male", + "age": 53, + "address": { + "state": "Maryland", + "city": "Waterloo" + } + }, + { + "id": 3911, + "name": "Padilla Morrison", + "gender": "male", + "age": 48, + "address": { + "state": "Maine", + "city": "Dupuyer" + } + }, + { + "id": 3912, + "name": "Britney Stout", + "gender": "female", + "age": 30, + "address": { + "state": "Montana", + "city": "Turpin" + } + }, + { + "id": 3913, + "name": "Minerva Buchanan", + "gender": "female", + "age": 32, + "address": { + "state": "Illinois", + "city": "Utting" + } + }, + { + "id": 3914, + "name": "Martinez Alston", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Newry" + } + }, + { + "id": 3915, + "name": "Esmeralda Schroeder", + "gender": "female", + "age": 39, + "address": { + "state": "Vermont", + "city": "Singer" + } + }, + { + "id": 3916, + "name": "Gena Carey", + "gender": "female", + "age": 68, + "address": { + "state": "Kentucky", + "city": "Cloverdale" + } + }, + { + "id": 3917, + "name": "Juliana Stephens", + "gender": "female", + "age": 69, + "address": { + "state": "Mississippi", + "city": "Elliott" + } + }, + { + "id": 3918, + "name": "Small Weiss", + "gender": "male", + "age": 31, + "address": { + "state": "Hawaii", + "city": "Bourg" + } + }, + { + "id": 3919, + "name": "Liza Perry", + "gender": "female", + "age": 39, + "address": { + "state": "Oregon", + "city": "Ernstville" + } + }, + { + "id": 3920, + "name": "Helen Marquez", + "gender": "female", + "age": 57, + "address": { + "state": "Arkansas", + "city": "Loyalhanna" + } + }, + { + "id": 3921, + "name": "Snyder Hardy", + "gender": "male", + "age": 42, + "address": { + "state": "Utah", + "city": "Elliston" + } + }, + { + "id": 3922, + "name": "Eileen Clay", + "gender": "female", + "age": 44, + "address": { + "state": "New Mexico", + "city": "Courtland" + } + }, + { + "id": 3923, + "name": "Rivers Ewing", + "gender": "male", + "age": 43, + "address": { + "state": "Nevada", + "city": "Fruitdale" + } + }, + { + "id": 3924, + "name": "Reese Myers", + "gender": "male", + "age": 53, + "address": { + "state": "New York", + "city": "Nicut" + } + }, + { + "id": 3925, + "name": "Linda Adams", + "gender": "female", + "age": 35, + "address": { + "state": "South Carolina", + "city": "Ferney" + } + }, + { + "id": 3926, + "name": "Ruth Caldwell", + "gender": "female", + "age": 71, + "address": { + "state": "Maryland", + "city": "Steinhatchee" + } + }, + { + "id": 3927, + "name": "Karina Camacho", + "gender": "female", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Bangor" + } + }, + { + "id": 3928, + "name": "Parks Castro", + "gender": "male", + "age": 71, + "address": { + "state": "New Jersey", + "city": "Ticonderoga" + } + }, + { + "id": 3929, + "name": "Lily Bentley", + "gender": "female", + "age": 44, + "address": { + "state": "Idaho", + "city": "Clarence" + } + }, + { + "id": 3930, + "name": "Stuart Landry", + "gender": "male", + "age": 42, + "address": { + "state": "Mississippi", + "city": "Logan" + } + }, + { + "id": 3931, + "name": "Elba Navarro", + "gender": "female", + "age": 43, + "address": { + "state": "Illinois", + "city": "Babb" + } + }, + { + "id": 3932, + "name": "Ballard Huff", + "gender": "male", + "age": 27, + "address": { + "state": "Iowa", + "city": "Bartley" + } + }, + { + "id": 3933, + "name": "Estrada Preston", + "gender": "male", + "age": 37, + "address": { + "state": "Wisconsin", + "city": "Strykersville" + } + }, + { + "id": 3934, + "name": "Shirley Gillespie", + "gender": "female", + "age": 63, + "address": { + "state": "West Virginia", + "city": "Alfarata" + } + }, + { + "id": 3935, + "name": "Owen Wells", + "gender": "male", + "age": 71, + "address": { + "state": "Virginia", + "city": "Hobucken" + } + }, + { + "id": 3936, + "name": "Warren Willis", + "gender": "male", + "age": 27, + "address": { + "state": "Pennsylvania", + "city": "Takilma" + } + }, + { + "id": 3937, + "name": "Laurie Dotson", + "gender": "female", + "age": 55, + "address": { + "state": "North Carolina", + "city": "Caroleen" + } + }, + { + "id": 3938, + "name": "Sykes Dalton", + "gender": "male", + "age": 27, + "address": { + "state": "Arizona", + "city": "Catherine" + } + }, + { + "id": 3939, + "name": "Kent Flores", + "gender": "male", + "age": 69, + "address": { + "state": "Delaware", + "city": "Escondida" + } + }, + { + "id": 3940, + "name": "Ashlee Solis", + "gender": "female", + "age": 62, + "address": { + "state": "Colorado", + "city": "Summertown" + } + }, + { + "id": 3941, + "name": "Lawrence Cote", + "gender": "male", + "age": 64, + "address": { + "state": "South Dakota", + "city": "Tuttle" + } + }, + { + "id": 3942, + "name": "Lola Hodges", + "gender": "female", + "age": 39, + "address": { + "state": "Georgia", + "city": "Urbana" + } + }, + { + "id": 3943, + "name": "Ray Kinney", + "gender": "male", + "age": 76, + "address": { + "state": "Wyoming", + "city": "Carbonville" + } + }, + { + "id": 3944, + "name": "Carey Young", + "gender": "female", + "age": 71, + "address": { + "state": "Hawaii", + "city": "Highland" + } + }, + { + "id": 3945, + "name": "Davenport Grant", + "gender": "male", + "age": 28, + "address": { + "state": "Florida", + "city": "Harrodsburg" + } + }, + { + "id": 3946, + "name": "Jocelyn Carrillo", + "gender": "female", + "age": 43, + "address": { + "state": "Texas", + "city": "Caberfae" + } + }, + { + "id": 3947, + "name": "Jennie Lindsay", + "gender": "female", + "age": 81, + "address": { + "state": "Ohio", + "city": "Deercroft" + } + }, + { + "id": 3948, + "name": "Harris Neal", + "gender": "male", + "age": 34, + "address": { + "state": "Kansas", + "city": "Rutherford" + } + }, + { + "id": 3949, + "name": "Stokes Molina", + "gender": "male", + "age": 82, + "address": { + "state": "Oklahoma", + "city": "Fairacres" + } + }, + { + "id": 3950, + "name": "Johnson Richards", + "gender": "male", + "age": 36, + "address": { + "state": "Vermont", + "city": "Corinne" + } + }, + { + "id": 3951, + "name": "Carter Dyer", + "gender": "male", + "age": 82, + "address": { + "state": "North Dakota", + "city": "Goochland" + } + }, + { + "id": 3952, + "name": "Summers Larson", + "gender": "male", + "age": 28, + "address": { + "state": "Alaska", + "city": "Silkworth" + } + }, + { + "id": 3953, + "name": "Alison Malone", + "gender": "female", + "age": 65, + "address": { + "state": "Minnesota", + "city": "Gardiner" + } + }, + { + "id": 3954, + "name": "Marla Cruz", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Urie" + } + }, + { + "id": 3955, + "name": "Rita Benjamin", + "gender": "female", + "age": 80, + "address": { + "state": "Maine", + "city": "Loveland" + } + }, + { + "id": 3956, + "name": "Sharron Robertson", + "gender": "female", + "age": 50, + "address": { + "state": "Oregon", + "city": "Brookfield" + } + }, + { + "id": 3957, + "name": "Dejesus Mcpherson", + "gender": "male", + "age": 68, + "address": { + "state": "Michigan", + "city": "Morriston" + } + }, + { + "id": 3958, + "name": "Brennan Murray", + "gender": "male", + "age": 23, + "address": { + "state": "Missouri", + "city": "Muse" + } + }, + { + "id": 3959, + "name": "Catherine Thomas", + "gender": "female", + "age": 45, + "address": { + "state": "Montana", + "city": "Bennett" + } + }, + { + "id": 3960, + "name": "Robert Marsh", + "gender": "female", + "age": 22, + "address": { + "state": "Nebraska", + "city": "Chase" + } + }, + { + "id": 3961, + "name": "Melva Martin", + "gender": "female", + "age": 79, + "address": { + "state": "Kentucky", + "city": "Stagecoach" + } + }, + { + "id": 3962, + "name": "Ellison Mcgee", + "gender": "male", + "age": 26, + "address": { + "state": "Washington", + "city": "Blairstown" + } + }, + { + "id": 3963, + "name": "Lacy Webb", + "gender": "female", + "age": 54, + "address": { + "state": "Indiana", + "city": "Bluetown" + } + }, + { + "id": 3964, + "name": "Lydia Cleveland", + "gender": "female", + "age": 61, + "address": { + "state": "Alabama", + "city": "Chamberino" + } + }, + { + "id": 3965, + "name": "Foster Howell", + "gender": "male", + "age": 63, + "address": { + "state": "Rhode Island", + "city": "Wanamie" + } + }, + { + "id": 3966, + "name": "Jasmine Wallace", + "gender": "female", + "age": 29, + "address": { + "state": "Massachusetts", + "city": "Canoochee" + } + }, + { + "id": 3967, + "name": "Serrano Jones", + "gender": "male", + "age": 59, + "address": { + "state": "New Hampshire", + "city": "Caln" + } + }, + { + "id": 3968, + "name": "Pollard Harrell", + "gender": "male", + "age": 31, + "address": { + "state": "California", + "city": "Vowinckel" + } + }, + { + "id": 3969, + "name": "Alana Gaines", + "gender": "female", + "age": 77, + "address": { + "state": "Alaska", + "city": "Bellamy" + } + }, + { + "id": 3970, + "name": "Olga Atkinson", + "gender": "female", + "age": 63, + "address": { + "state": "Rhode Island", + "city": "Gambrills" + } + }, + { + "id": 3971, + "name": "Lucas George", + "gender": "male", + "age": 45, + "address": { + "state": "Tennessee", + "city": "Eastvale" + } + }, + { + "id": 3972, + "name": "Norton Stanley", + "gender": "male", + "age": 53, + "address": { + "state": "Oklahoma", + "city": "Alleghenyville" + } + }, + { + "id": 3973, + "name": "Bernadine Gill", + "gender": "female", + "age": 73, + "address": { + "state": "Nevada", + "city": "Kilbourne" + } + }, + { + "id": 3974, + "name": "Ayers Ferguson", + "gender": "male", + "age": 73, + "address": { + "state": "New York", + "city": "Imperial" + } + }, + { + "id": 3975, + "name": "Rosalie Winters", + "gender": "female", + "age": 72, + "address": { + "state": "Utah", + "city": "Siglerville" + } + }, + { + "id": 3976, + "name": "Osborn Griffith", + "gender": "male", + "age": 74, + "address": { + "state": "Delaware", + "city": "Mansfield" + } + }, + { + "id": 3977, + "name": "Mckenzie Norton", + "gender": "male", + "age": 69, + "address": { + "state": "Virginia", + "city": "Caron" + } + }, + { + "id": 3978, + "name": "Stella Copeland", + "gender": "female", + "age": 40, + "address": { + "state": "Florida", + "city": "Leroy" + } + }, + { + "id": 3979, + "name": "Lorie Hatfield", + "gender": "female", + "age": 32, + "address": { + "state": "South Carolina", + "city": "Gibsonia" + } + }, + { + "id": 3980, + "name": "Burch Pace", + "gender": "male", + "age": 78, + "address": { + "state": "West Virginia", + "city": "Brandermill" + } + }, + { + "id": 3981, + "name": "Potter Shelton", + "gender": "male", + "age": 56, + "address": { + "state": "Nebraska", + "city": "Succasunna" + } + }, + { + "id": 3982, + "name": "Regina Whitley", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Longoria" + } + }, + { + "id": 3983, + "name": "Patsy Tucker", + "gender": "female", + "age": 39, + "address": { + "state": "Arizona", + "city": "Lowgap" + } + }, + { + "id": 3984, + "name": "Dominguez Stephens", + "gender": "male", + "age": 30, + "address": { + "state": "North Dakota", + "city": "Albrightsville" + } + }, + { + "id": 3985, + "name": "Dana Maynard", + "gender": "female", + "age": 52, + "address": { + "state": "Ohio", + "city": "Diaperville" + } + }, + { + "id": 3986, + "name": "Wells Willis", + "gender": "male", + "age": 76, + "address": { + "state": "Kentucky", + "city": "Sena" + } + }, + { + "id": 3987, + "name": "Brenda Kent", + "gender": "female", + "age": 17, + "address": { + "state": "Missouri", + "city": "Lookingglass" + } + }, + { + "id": 3988, + "name": "Jami Riddle", + "gender": "female", + "age": 22, + "address": { + "state": "California", + "city": "Fidelis" + } + }, + { + "id": 3989, + "name": "Gretchen Andrews", + "gender": "female", + "age": 74, + "address": { + "state": "Connecticut", + "city": "Katonah" + } + }, + { + "id": 3990, + "name": "Tommie Harrington", + "gender": "female", + "age": 51, + "address": { + "state": "Montana", + "city": "Canoochee" + } + }, + { + "id": 3991, + "name": "Augusta Sharpe", + "gender": "female", + "age": 36, + "address": { + "state": "Wyoming", + "city": "Derwood" + } + }, + { + "id": 3992, + "name": "Graham Lester", + "gender": "male", + "age": 22, + "address": { + "state": "Maryland", + "city": "Spelter" + } + }, + { + "id": 3993, + "name": "Gamble Burch", + "gender": "male", + "age": 59, + "address": { + "state": "Louisiana", + "city": "Kapowsin" + } + }, + { + "id": 3994, + "name": "Solis Richmond", + "gender": "male", + "age": 66, + "address": { + "state": "Idaho", + "city": "Olney" + } + }, + { + "id": 3995, + "name": "Kirsten Galloway", + "gender": "female", + "age": 47, + "address": { + "state": "Hawaii", + "city": "Talpa" + } + }, + { + "id": 3996, + "name": "Rosemarie Crane", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Spokane" + } + }, + { + "id": 3997, + "name": "Latasha Randolph", + "gender": "female", + "age": 29, + "address": { + "state": "Washington", + "city": "Hollymead" + } + }, + { + "id": 3998, + "name": "Ferrell Levine", + "gender": "male", + "age": 20, + "address": { + "state": "Kansas", + "city": "Salix" + } + }, + { + "id": 3999, + "name": "Mitchell Gregory", + "gender": "male", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Century" + } + }, + { + "id": 4000, + "name": "Lila Shields", + "gender": "female", + "age": 36, + "address": { + "state": "Iowa", + "city": "Mathews" + } + }, + { + "id": 4001, + "name": "Rebecca Torres", + "gender": "female", + "age": 73, + "address": { + "state": "New Hampshire", + "city": "Bartonsville" + } + }, + { + "id": 4002, + "name": "Debora Paul", + "gender": "female", + "age": 28, + "address": { + "state": "Maine", + "city": "Konterra" + } + }, + { + "id": 4003, + "name": "Katheryn Small", + "gender": "female", + "age": 35, + "address": { + "state": "Arkansas", + "city": "Brandywine" + } + }, + { + "id": 4004, + "name": "Baxter Horn", + "gender": "male", + "age": 59, + "address": { + "state": "Mississippi", + "city": "Remington" + } + }, + { + "id": 4005, + "name": "Katina Welch", + "gender": "female", + "age": 65, + "address": { + "state": "Colorado", + "city": "Chautauqua" + } + }, + { + "id": 4006, + "name": "Hanson Santiago", + "gender": "male", + "age": 31, + "address": { + "state": "Texas", + "city": "Goldfield" + } + }, + { + "id": 4007, + "name": "Tessa Gallagher", + "gender": "female", + "age": 35, + "address": { + "state": "Minnesota", + "city": "Glenbrook" + } + }, + { + "id": 4008, + "name": "Jarvis Short", + "gender": "male", + "age": 17, + "address": { + "state": "Illinois", + "city": "Fairforest" + } + }, + { + "id": 4009, + "name": "Jane Bell", + "gender": "female", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Wawona" + } + }, + { + "id": 4010, + "name": "Miriam Monroe", + "gender": "female", + "age": 38, + "address": { + "state": "Massachusetts", + "city": "Gulf" + } + }, + { + "id": 4011, + "name": "Barr Gardner", + "gender": "male", + "age": 25, + "address": { + "state": "Michigan", + "city": "Marne" + } + }, + { + "id": 4012, + "name": "Jan Velez", + "gender": "female", + "age": 24, + "address": { + "state": "Alabama", + "city": "Thynedale" + } + }, + { + "id": 4013, + "name": "Dalton Finley", + "gender": "male", + "age": 78, + "address": { + "state": "New Jersey", + "city": "Alafaya" + } + }, + { + "id": 4014, + "name": "Peterson Allison", + "gender": "male", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Chloride" + } + }, + { + "id": 4015, + "name": "Goff Slater", + "gender": "male", + "age": 54, + "address": { + "state": "Oregon", + "city": "Joppa" + } + }, + { + "id": 4016, + "name": "Ewing Koch", + "gender": "male", + "age": 61, + "address": { + "state": "Wisconsin", + "city": "Germanton" + } + }, + { + "id": 4017, + "name": "Morgan Hunt", + "gender": "female", + "age": 17, + "address": { + "state": "Pennsylvania", + "city": "Robbins" + } + }, + { + "id": 4018, + "name": "Gonzalez Ewing", + "gender": "male", + "age": 48, + "address": { + "state": "Minnesota", + "city": "Durham" + } + }, + { + "id": 4019, + "name": "Wilkerson Ashley", + "gender": "male", + "age": 32, + "address": { + "state": "Wisconsin", + "city": "Watchtower" + } + }, + { + "id": 4020, + "name": "Levy Cline", + "gender": "male", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Hanover" + } + }, + { + "id": 4021, + "name": "Maribel Rich", + "gender": "female", + "age": 64, + "address": { + "state": "Rhode Island", + "city": "Shindler" + } + }, + { + "id": 4022, + "name": "Medina Bender", + "gender": "male", + "age": 58, + "address": { + "state": "Maryland", + "city": "Fivepointville" + } + }, + { + "id": 4023, + "name": "Concetta Hull", + "gender": "female", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Harborton" + } + }, + { + "id": 4024, + "name": "Bowen Kemp", + "gender": "male", + "age": 80, + "address": { + "state": "Utah", + "city": "Wauhillau" + } + }, + { + "id": 4025, + "name": "Taylor Soto", + "gender": "male", + "age": 19, + "address": { + "state": "Maine", + "city": "Nettie" + } + }, + { + "id": 4026, + "name": "Galloway Ball", + "gender": "male", + "age": 17, + "address": { + "state": "New Mexico", + "city": "Day" + } + }, + { + "id": 4027, + "name": "Clare Guerra", + "gender": "female", + "age": 63, + "address": { + "state": "Kansas", + "city": "Beaverdale" + } + }, + { + "id": 4028, + "name": "Osborne Sykes", + "gender": "male", + "age": 53, + "address": { + "state": "California", + "city": "Geyserville" + } + }, + { + "id": 4029, + "name": "Elvira Oneal", + "gender": "female", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Roderfield" + } + }, + { + "id": 4030, + "name": "Jones Hood", + "gender": "male", + "age": 66, + "address": { + "state": "Michigan", + "city": "National" + } + }, + { + "id": 4031, + "name": "Hammond Reyes", + "gender": "male", + "age": 29, + "address": { + "state": "Iowa", + "city": "Noblestown" + } + }, + { + "id": 4032, + "name": "Aguirre Bird", + "gender": "male", + "age": 32, + "address": { + "state": "Arkansas", + "city": "Lacomb" + } + }, + { + "id": 4033, + "name": "Barker Workman", + "gender": "male", + "age": 59, + "address": { + "state": "Oregon", + "city": "Bennett" + } + }, + { + "id": 4034, + "name": "Snow Hunt", + "gender": "male", + "age": 73, + "address": { + "state": "Texas", + "city": "Savage" + } + }, + { + "id": 4035, + "name": "Lizzie Howell", + "gender": "female", + "age": 41, + "address": { + "state": "Florida", + "city": "Byrnedale" + } + }, + { + "id": 4036, + "name": "Genevieve Ward", + "gender": "female", + "age": 34, + "address": { + "state": "Indiana", + "city": "Ruffin" + } + }, + { + "id": 4037, + "name": "Casey Parks", + "gender": "male", + "age": 27, + "address": { + "state": "Pennsylvania", + "city": "Lafferty" + } + }, + { + "id": 4038, + "name": "Glenn Justice", + "gender": "male", + "age": 46, + "address": { + "state": "Colorado", + "city": "Skyland" + } + }, + { + "id": 4039, + "name": "Kathleen Deleon", + "gender": "female", + "age": 67, + "address": { + "state": "New York", + "city": "Carrizo" + } + }, + { + "id": 4040, + "name": "Carissa Blankenship", + "gender": "female", + "age": 82, + "address": { + "state": "Nevada", + "city": "Alfarata" + } + }, + { + "id": 4041, + "name": "Mia Vargas", + "gender": "female", + "age": 45, + "address": { + "state": "Arizona", + "city": "Needmore" + } + }, + { + "id": 4042, + "name": "Wells Wright", + "gender": "male", + "age": 17, + "address": { + "state": "Oklahoma", + "city": "Floris" + } + }, + { + "id": 4043, + "name": "Duffy Blackburn", + "gender": "male", + "age": 68, + "address": { + "state": "Louisiana", + "city": "Wikieup" + } + }, + { + "id": 4044, + "name": "Roberta Mooney", + "gender": "female", + "age": 32, + "address": { + "state": "Mississippi", + "city": "Dundee" + } + }, + { + "id": 4045, + "name": "Beulah Walter", + "gender": "female", + "age": 64, + "address": { + "state": "South Carolina", + "city": "Hendersonville" + } + }, + { + "id": 4046, + "name": "Barbra Santos", + "gender": "female", + "age": 76, + "address": { + "state": "New Hampshire", + "city": "Magnolia" + } + }, + { + "id": 4047, + "name": "Wynn Fox", + "gender": "male", + "age": 57, + "address": { + "state": "Idaho", + "city": "Boykin" + } + }, + { + "id": 4048, + "name": "Meadows Rollins", + "gender": "male", + "age": 68, + "address": { + "state": "Vermont", + "city": "Downsville" + } + }, + { + "id": 4049, + "name": "Earnestine Ellison", + "gender": "female", + "age": 22, + "address": { + "state": "Missouri", + "city": "Clay" + } + }, + { + "id": 4050, + "name": "Leona Lang", + "gender": "female", + "age": 73, + "address": { + "state": "North Dakota", + "city": "Nile" + } + }, + { + "id": 4051, + "name": "Bethany Hanson", + "gender": "female", + "age": 46, + "address": { + "state": "Georgia", + "city": "Bynum" + } + }, + { + "id": 4052, + "name": "Cobb Meadows", + "gender": "male", + "age": 74, + "address": { + "state": "Wyoming", + "city": "Clara" + } + }, + { + "id": 4053, + "name": "Alejandra Vega", + "gender": "female", + "age": 55, + "address": { + "state": "Ohio", + "city": "Warren" + } + }, + { + "id": 4054, + "name": "Cardenas Sharpe", + "gender": "male", + "age": 52, + "address": { + "state": "Nebraska", + "city": "Walton" + } + }, + { + "id": 4055, + "name": "Barbara Gonzales", + "gender": "female", + "age": 61, + "address": { + "state": "Illinois", + "city": "Bison" + } + }, + { + "id": 4056, + "name": "Tyler Howe", + "gender": "male", + "age": 28, + "address": { + "state": "Montana", + "city": "Abrams" + } + }, + { + "id": 4057, + "name": "Nadine Kinney", + "gender": "female", + "age": 80, + "address": { + "state": "Alaska", + "city": "Sanders" + } + }, + { + "id": 4058, + "name": "Bobbi Chase", + "gender": "female", + "age": 58, + "address": { + "state": "North Carolina", + "city": "Naomi" + } + }, + { + "id": 4059, + "name": "Rivera Conway", + "gender": "male", + "age": 17, + "address": { + "state": "South Dakota", + "city": "Somerset" + } + }, + { + "id": 4060, + "name": "Foster Warner", + "gender": "male", + "age": 58, + "address": { + "state": "Virginia", + "city": "Ebro" + } + }, + { + "id": 4061, + "name": "Mcclure Stokes", + "gender": "male", + "age": 31, + "address": { + "state": "Delaware", + "city": "Marienthal" + } + }, + { + "id": 4062, + "name": "Thornton Washington", + "gender": "male", + "age": 76, + "address": { + "state": "Alabama", + "city": "Carlos" + } + }, + { + "id": 4063, + "name": "Gena Hardin", + "gender": "female", + "age": 26, + "address": { + "state": "Washington", + "city": "Marshall" + } + }, + { + "id": 4064, + "name": "Roth Conner", + "gender": "male", + "age": 42, + "address": { + "state": "Tennessee", + "city": "Allamuchy" + } + }, + { + "id": 4065, + "name": "Liza Nieves", + "gender": "female", + "age": 56, + "address": { + "state": "Kentucky", + "city": "Williston" + } + }, + { + "id": 4066, + "name": "Alexandra Garrison", + "gender": "female", + "age": 30, + "address": { + "state": "West Virginia", + "city": "Duryea" + } + }, + { + "id": 4067, + "name": "Beasley Robbins", + "gender": "male", + "age": 27, + "address": { + "state": "Delaware", + "city": "Nogal" + } + }, + { + "id": 4068, + "name": "Erma Fox", + "gender": "female", + "age": 61, + "address": { + "state": "West Virginia", + "city": "Brookfield" + } + }, + { + "id": 4069, + "name": "Alyssa Ewing", + "gender": "female", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Mayfair" + } + }, + { + "id": 4070, + "name": "Estella Cote", + "gender": "female", + "age": 23, + "address": { + "state": "Utah", + "city": "Hemlock" + } + }, + { + "id": 4071, + "name": "Doris Holt", + "gender": "female", + "age": 18, + "address": { + "state": "Minnesota", + "city": "Topaz" + } + }, + { + "id": 4072, + "name": "Atkins Carpenter", + "gender": "male", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Cornfields" + } + }, + { + "id": 4073, + "name": "Sylvia Wooten", + "gender": "female", + "age": 47, + "address": { + "state": "Louisiana", + "city": "Disautel" + } + }, + { + "id": 4074, + "name": "Perez Bird", + "gender": "male", + "age": 81, + "address": { + "state": "Kansas", + "city": "Unionville" + } + }, + { + "id": 4075, + "name": "Shawn Bryant", + "gender": "female", + "age": 41, + "address": { + "state": "Michigan", + "city": "Emerald" + } + }, + { + "id": 4076, + "name": "Kidd Barton", + "gender": "male", + "age": 58, + "address": { + "state": "Massachusetts", + "city": "Deseret" + } + }, + { + "id": 4077, + "name": "Christy Hogan", + "gender": "female", + "age": 74, + "address": { + "state": "Rhode Island", + "city": "Islandia" + } + }, + { + "id": 4078, + "name": "Marjorie George", + "gender": "female", + "age": 61, + "address": { + "state": "California", + "city": "Epworth" + } + }, + { + "id": 4079, + "name": "Fletcher Boyer", + "gender": "male", + "age": 60, + "address": { + "state": "Indiana", + "city": "Worcester" + } + }, + { + "id": 4080, + "name": "Wilson Wallace", + "gender": "male", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Cartwright" + } + }, + { + "id": 4081, + "name": "Lilian Jones", + "gender": "female", + "age": 32, + "address": { + "state": "Texas", + "city": "Klagetoh" + } + }, + { + "id": 4082, + "name": "Savannah Lucas", + "gender": "female", + "age": 44, + "address": { + "state": "Nevada", + "city": "Nipinnawasee" + } + }, + { + "id": 4083, + "name": "Vasquez Gross", + "gender": "male", + "age": 33, + "address": { + "state": "South Carolina", + "city": "Dragoon" + } + }, + { + "id": 4084, + "name": "Morrison Webster", + "gender": "male", + "age": 24, + "address": { + "state": "Alabama", + "city": "Finderne" + } + }, + { + "id": 4085, + "name": "Yesenia Anderson", + "gender": "female", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Thynedale" + } + }, + { + "id": 4086, + "name": "Tabatha Barnett", + "gender": "female", + "age": 44, + "address": { + "state": "Mississippi", + "city": "Malo" + } + }, + { + "id": 4087, + "name": "Antoinette Hebert", + "gender": "female", + "age": 76, + "address": { + "state": "Tennessee", + "city": "Sexton" + } + }, + { + "id": 4088, + "name": "Rene Rivera", + "gender": "female", + "age": 78, + "address": { + "state": "North Dakota", + "city": "Groton" + } + }, + { + "id": 4089, + "name": "Reyes Holden", + "gender": "male", + "age": 44, + "address": { + "state": "Connecticut", + "city": "Elliston" + } + }, + { + "id": 4090, + "name": "Janna Armstrong", + "gender": "female", + "age": 44, + "address": { + "state": "Idaho", + "city": "Ladera" + } + }, + { + "id": 4091, + "name": "James Dickson", + "gender": "male", + "age": 41, + "address": { + "state": "New York", + "city": "Gouglersville" + } + }, + { + "id": 4092, + "name": "Kerry Melton", + "gender": "female", + "age": 63, + "address": { + "state": "Colorado", + "city": "Bradenville" + } + }, + { + "id": 4093, + "name": "Owen Colon", + "gender": "male", + "age": 70, + "address": { + "state": "Oklahoma", + "city": "Lumberton" + } + }, + { + "id": 4094, + "name": "Cynthia Robles", + "gender": "female", + "age": 37, + "address": { + "state": "South Dakota", + "city": "Leming" + } + }, + { + "id": 4095, + "name": "Cross Flores", + "gender": "male", + "age": 51, + "address": { + "state": "Virginia", + "city": "Gerton" + } + }, + { + "id": 4096, + "name": "Cole Ware", + "gender": "male", + "age": 23, + "address": { + "state": "Ohio", + "city": "Umapine" + } + }, + { + "id": 4097, + "name": "Battle Huber", + "gender": "male", + "age": 64, + "address": { + "state": "Florida", + "city": "Hartsville/Hartley" + } + }, + { + "id": 4098, + "name": "Browning Finch", + "gender": "male", + "age": 61, + "address": { + "state": "Illinois", + "city": "Kiskimere" + } + }, + { + "id": 4099, + "name": "Klein Spencer", + "gender": "male", + "age": 39, + "address": { + "state": "Nebraska", + "city": "Clarktown" + } + }, + { + "id": 4100, + "name": "Trevino Perez", + "gender": "male", + "age": 39, + "address": { + "state": "Georgia", + "city": "Como" + } + }, + { + "id": 4101, + "name": "Cherry Park", + "gender": "female", + "age": 70, + "address": { + "state": "Oregon", + "city": "Tedrow" + } + }, + { + "id": 4102, + "name": "Fry Bowers", + "gender": "male", + "age": 62, + "address": { + "state": "Washington", + "city": "Indio" + } + }, + { + "id": 4103, + "name": "Santos Caldwell", + "gender": "male", + "age": 80, + "address": { + "state": "Maryland", + "city": "Rossmore" + } + }, + { + "id": 4104, + "name": "Franco Clements", + "gender": "male", + "age": 69, + "address": { + "state": "Arkansas", + "city": "Summertown" + } + }, + { + "id": 4105, + "name": "Ana Cline", + "gender": "female", + "age": 75, + "address": { + "state": "Missouri", + "city": "Elrama" + } + }, + { + "id": 4106, + "name": "Magdalena Neal", + "gender": "female", + "age": 78, + "address": { + "state": "Maine", + "city": "Bayview" + } + }, + { + "id": 4107, + "name": "Lacy Peterson", + "gender": "female", + "age": 18, + "address": { + "state": "Iowa", + "city": "Barclay" + } + }, + { + "id": 4108, + "name": "Bonnie Mccarthy", + "gender": "female", + "age": 49, + "address": { + "state": "Arizona", + "city": "Glenville" + } + }, + { + "id": 4109, + "name": "Holden Carlson", + "gender": "male", + "age": 75, + "address": { + "state": "Alaska", + "city": "Charco" + } + }, + { + "id": 4110, + "name": "Ursula Parsons", + "gender": "female", + "age": 79, + "address": { + "state": "Vermont", + "city": "Caspar" + } + }, + { + "id": 4111, + "name": "Hickman Howard", + "gender": "male", + "age": 34, + "address": { + "state": "Montana", + "city": "Takilma" + } + }, + { + "id": 4112, + "name": "George Cantrell", + "gender": "male", + "age": 58, + "address": { + "state": "Kentucky", + "city": "Talpa" + } + }, + { + "id": 4113, + "name": "Connie Hughes", + "gender": "female", + "age": 21, + "address": { + "state": "Hawaii", + "city": "Brecon" + } + }, + { + "id": 4114, + "name": "Monica Harrell", + "gender": "female", + "age": 67, + "address": { + "state": "Wyoming", + "city": "Brady" + } + }, + { + "id": 4115, + "name": "Brock Todd", + "gender": "male", + "age": 17, + "address": { + "state": "New Mexico", + "city": "Iberia" + } + }, + { + "id": 4116, + "name": "Gabrielle Blackburn", + "gender": "female", + "age": 37, + "address": { + "state": "New Jersey", + "city": "Courtland" + } + }, + { + "id": 4117, + "name": "Adrienne Bishop", + "gender": "female", + "age": 74, + "address": { + "state": "Missouri", + "city": "Tecolotito" + } + }, + { + "id": 4118, + "name": "Lina Simpson", + "gender": "female", + "age": 48, + "address": { + "state": "Georgia", + "city": "Jugtown" + } + }, + { + "id": 4119, + "name": "Maddox Gordon", + "gender": "male", + "age": 47, + "address": { + "state": "Louisiana", + "city": "Hendersonville" + } + }, + { + "id": 4120, + "name": "Pope Juarez", + "gender": "male", + "age": 81, + "address": { + "state": "Washington", + "city": "Sanders" + } + }, + { + "id": 4121, + "name": "Lambert Mccullough", + "gender": "male", + "age": 41, + "address": { + "state": "Montana", + "city": "Waumandee" + } + }, + { + "id": 4122, + "name": "Agnes English", + "gender": "female", + "age": 40, + "address": { + "state": "Utah", + "city": "Martinez" + } + }, + { + "id": 4123, + "name": "Hood Perez", + "gender": "male", + "age": 36, + "address": { + "state": "South Carolina", + "city": "Villarreal" + } + }, + { + "id": 4124, + "name": "Serrano Lawrence", + "gender": "male", + "age": 50, + "address": { + "state": "Illinois", + "city": "Urie" + } + }, + { + "id": 4125, + "name": "Macias Larson", + "gender": "male", + "age": 54, + "address": { + "state": "Virginia", + "city": "Grayhawk" + } + }, + { + "id": 4126, + "name": "Aline Wyatt", + "gender": "female", + "age": 78, + "address": { + "state": "Oregon", + "city": "Echo" + } + }, + { + "id": 4127, + "name": "Jeanette Gonzales", + "gender": "female", + "age": 35, + "address": { + "state": "Hawaii", + "city": "Belva" + } + }, + { + "id": 4128, + "name": "Doris Pacheco", + "gender": "female", + "age": 24, + "address": { + "state": "Texas", + "city": "Chapin" + } + }, + { + "id": 4129, + "name": "Bettye Hickman", + "gender": "female", + "age": 33, + "address": { + "state": "Arkansas", + "city": "Berwind" + } + }, + { + "id": 4130, + "name": "Snow Atkins", + "gender": "male", + "age": 79, + "address": { + "state": "Delaware", + "city": "Cascades" + } + }, + { + "id": 4131, + "name": "Evelyn Shelton", + "gender": "female", + "age": 30, + "address": { + "state": "Rhode Island", + "city": "Williams" + } + }, + { + "id": 4132, + "name": "Wyatt Lott", + "gender": "male", + "age": 65, + "address": { + "state": "Kansas", + "city": "Robinette" + } + }, + { + "id": 4133, + "name": "Dale Hampton", + "gender": "female", + "age": 29, + "address": { + "state": "Indiana", + "city": "Yettem" + } + }, + { + "id": 4134, + "name": "Darlene Pearson", + "gender": "female", + "age": 81, + "address": { + "state": "Arizona", + "city": "Noxen" + } + }, + { + "id": 4135, + "name": "Humphrey Ryan", + "gender": "male", + "age": 19, + "address": { + "state": "North Carolina", + "city": "Lewis" + } + }, + { + "id": 4136, + "name": "Rena Boyd", + "gender": "female", + "age": 82, + "address": { + "state": "Idaho", + "city": "Oasis" + } + }, + { + "id": 4137, + "name": "Lucinda Austin", + "gender": "female", + "age": 76, + "address": { + "state": "Massachusetts", + "city": "Hartsville/Hartley" + } + }, + { + "id": 4138, + "name": "Clarice Fulton", + "gender": "female", + "age": 35, + "address": { + "state": "Wisconsin", + "city": "Roosevelt" + } + }, + { + "id": 4139, + "name": "Heather Buck", + "gender": "female", + "age": 47, + "address": { + "state": "Iowa", + "city": "Dubois" + } + }, + { + "id": 4140, + "name": "Gordon Bowers", + "gender": "male", + "age": 20, + "address": { + "state": "Colorado", + "city": "Longoria" + } + }, + { + "id": 4141, + "name": "Franks Parsons", + "gender": "male", + "age": 42, + "address": { + "state": "California", + "city": "Englevale" + } + }, + { + "id": 4142, + "name": "Irene French", + "gender": "female", + "age": 19, + "address": { + "state": "New York", + "city": "Nogal" + } + }, + { + "id": 4143, + "name": "Myra Stevens", + "gender": "female", + "age": 48, + "address": { + "state": "Oklahoma", + "city": "Bannock" + } + }, + { + "id": 4144, + "name": "Holcomb Donaldson", + "gender": "male", + "age": 61, + "address": { + "state": "Maine", + "city": "Bedias" + } + }, + { + "id": 4145, + "name": "Jacqueline Barry", + "gender": "female", + "age": 20, + "address": { + "state": "Wyoming", + "city": "Blanco" + } + }, + { + "id": 4146, + "name": "Adkins Shannon", + "gender": "male", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Valmy" + } + }, + { + "id": 4147, + "name": "Deidre Slater", + "gender": "female", + "age": 49, + "address": { + "state": "Minnesota", + "city": "Dixie" + } + }, + { + "id": 4148, + "name": "Graves Horne", + "gender": "male", + "age": 43, + "address": { + "state": "Nebraska", + "city": "Madaket" + } + }, + { + "id": 4149, + "name": "Josie Mccall", + "gender": "female", + "age": 52, + "address": { + "state": "Pennsylvania", + "city": "Albrightsville" + } + }, + { + "id": 4150, + "name": "Gilda George", + "gender": "female", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Cade" + } + }, + { + "id": 4151, + "name": "Laverne Cervantes", + "gender": "female", + "age": 27, + "address": { + "state": "North Dakota", + "city": "Kersey" + } + }, + { + "id": 4152, + "name": "Weaver Erickson", + "gender": "male", + "age": 79, + "address": { + "state": "Ohio", + "city": "Guthrie" + } + }, + { + "id": 4153, + "name": "Bridgett Key", + "gender": "female", + "age": 62, + "address": { + "state": "Tennessee", + "city": "Blue" + } + }, + { + "id": 4154, + "name": "Wright Holder", + "gender": "male", + "age": 63, + "address": { + "state": "South Dakota", + "city": "Holcombe" + } + }, + { + "id": 4155, + "name": "Eleanor Byrd", + "gender": "female", + "age": 80, + "address": { + "state": "Vermont", + "city": "Bordelonville" + } + }, + { + "id": 4156, + "name": "Alta Snyder", + "gender": "female", + "age": 23, + "address": { + "state": "Alabama", + "city": "Biehle" + } + }, + { + "id": 4157, + "name": "Mills Clay", + "gender": "male", + "age": 60, + "address": { + "state": "New Mexico", + "city": "Bakersville" + } + }, + { + "id": 4158, + "name": "Montoya Michael", + "gender": "male", + "age": 67, + "address": { + "state": "Florida", + "city": "Harrodsburg" + } + }, + { + "id": 4159, + "name": "Haynes Figueroa", + "gender": "male", + "age": 19, + "address": { + "state": "Michigan", + "city": "Brambleton" + } + }, + { + "id": 4160, + "name": "Petra Ware", + "gender": "female", + "age": 54, + "address": { + "state": "Kentucky", + "city": "Veguita" + } + }, + { + "id": 4161, + "name": "Fitzpatrick Lamb", + "gender": "male", + "age": 18, + "address": { + "state": "Alaska", + "city": "Motley" + } + }, + { + "id": 4162, + "name": "Hale Clemons", + "gender": "male", + "age": 80, + "address": { + "state": "West Virginia", + "city": "Ebro" + } + }, + { + "id": 4163, + "name": "Harriett Pena", + "gender": "female", + "age": 34, + "address": { + "state": "Maryland", + "city": "Bynum" + } + }, + { + "id": 4164, + "name": "Luella Williams", + "gender": "female", + "age": 41, + "address": { + "state": "Nevada", + "city": "Fairforest" + } + }, + { + "id": 4165, + "name": "Bass Huff", + "gender": "male", + "age": 43, + "address": { + "state": "Iowa", + "city": "Leming" + } + }, + { + "id": 4166, + "name": "Carmela Walker", + "gender": "female", + "age": 62, + "address": { + "state": "Mississippi", + "city": "Tibbie" + } + }, + { + "id": 4167, + "name": "Graham Leach", + "gender": "male", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Bowmansville" + } + }, + { + "id": 4168, + "name": "Poole Mcfarland", + "gender": "male", + "age": 68, + "address": { + "state": "Missouri", + "city": "Cumberland" + } + }, + { + "id": 4169, + "name": "Chambers Hood", + "gender": "male", + "age": 81, + "address": { + "state": "Nebraska", + "city": "Ola" + } + }, + { + "id": 4170, + "name": "Rasmussen Crosby", + "gender": "male", + "age": 75, + "address": { + "state": "Nevada", + "city": "Efland" + } + }, + { + "id": 4171, + "name": "Kris Orr", + "gender": "female", + "age": 54, + "address": { + "state": "Arkansas", + "city": "Vallonia" + } + }, + { + "id": 4172, + "name": "Nona Kirkland", + "gender": "female", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Day" + } + }, + { + "id": 4173, + "name": "Lora Alvarez", + "gender": "female", + "age": 43, + "address": { + "state": "Louisiana", + "city": "Corinne" + } + }, + { + "id": 4174, + "name": "Greta Benton", + "gender": "female", + "age": 22, + "address": { + "state": "Vermont", + "city": "Hardyville" + } + }, + { + "id": 4175, + "name": "Church Whitehead", + "gender": "male", + "age": 55, + "address": { + "state": "North Dakota", + "city": "Neibert" + } + }, + { + "id": 4176, + "name": "Hatfield Newman", + "gender": "male", + "age": 75, + "address": { + "state": "California", + "city": "Reinerton" + } + }, + { + "id": 4177, + "name": "Twila Burt", + "gender": "female", + "age": 38, + "address": { + "state": "New York", + "city": "Ruffin" + } + }, + { + "id": 4178, + "name": "Mullins Donovan", + "gender": "male", + "age": 27, + "address": { + "state": "Alaska", + "city": "Blanford" + } + }, + { + "id": 4179, + "name": "Dixie Mcclure", + "gender": "female", + "age": 80, + "address": { + "state": "South Dakota", + "city": "Edgewater" + } + }, + { + "id": 4180, + "name": "Cecelia Moore", + "gender": "female", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Ladera" + } + }, + { + "id": 4181, + "name": "Kelly Mitchell", + "gender": "male", + "age": 47, + "address": { + "state": "Montana", + "city": "Cresaptown" + } + }, + { + "id": 4182, + "name": "Beck Scott", + "gender": "male", + "age": 37, + "address": { + "state": "Washington", + "city": "Hayes" + } + }, + { + "id": 4183, + "name": "King Head", + "gender": "male", + "age": 56, + "address": { + "state": "Illinois", + "city": "Cade" + } + }, + { + "id": 4184, + "name": "Montoya Cobb", + "gender": "male", + "age": 74, + "address": { + "state": "Maryland", + "city": "Dexter" + } + }, + { + "id": 4185, + "name": "Louise Trujillo", + "gender": "female", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Fannett" + } + }, + { + "id": 4186, + "name": "Shelton Sullivan", + "gender": "male", + "age": 27, + "address": { + "state": "Oregon", + "city": "Eden" + } + }, + { + "id": 4187, + "name": "Alford Pickett", + "gender": "male", + "age": 32, + "address": { + "state": "New Hampshire", + "city": "Driftwood" + } + }, + { + "id": 4188, + "name": "Kidd Bell", + "gender": "male", + "age": 24, + "address": { + "state": "Maine", + "city": "Lafferty" + } + }, + { + "id": 4189, + "name": "Rhodes Dorsey", + "gender": "male", + "age": 40, + "address": { + "state": "New Jersey", + "city": "Joppa" + } + }, + { + "id": 4190, + "name": "Rollins Cox", + "gender": "male", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Needmore" + } + }, + { + "id": 4191, + "name": "Jean Stone", + "gender": "female", + "age": 63, + "address": { + "state": "Hawaii", + "city": "Clarktown" + } + }, + { + "id": 4192, + "name": "Knapp Carney", + "gender": "male", + "age": 59, + "address": { + "state": "Utah", + "city": "Omar" + } + }, + { + "id": 4193, + "name": "Alexandra Hamilton", + "gender": "female", + "age": 60, + "address": { + "state": "Idaho", + "city": "Sena" + } + }, + { + "id": 4194, + "name": "Imelda Lawson", + "gender": "female", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Canterwood" + } + }, + { + "id": 4195, + "name": "Booth Witt", + "gender": "male", + "age": 20, + "address": { + "state": "Texas", + "city": "Marysville" + } + }, + { + "id": 4196, + "name": "Jenny Bird", + "gender": "female", + "age": 36, + "address": { + "state": "Michigan", + "city": "Herlong" + } + }, + { + "id": 4197, + "name": "Stacy Galloway", + "gender": "female", + "age": 33, + "address": { + "state": "Florida", + "city": "Southview" + } + }, + { + "id": 4198, + "name": "Boyd Duncan", + "gender": "male", + "age": 19, + "address": { + "state": "Rhode Island", + "city": "Skyland" + } + }, + { + "id": 4199, + "name": "Wilkinson Schneider", + "gender": "male", + "age": 79, + "address": { + "state": "Indiana", + "city": "Suitland" + } + }, + { + "id": 4200, + "name": "Mcfadden Herman", + "gender": "male", + "age": 23, + "address": { + "state": "Colorado", + "city": "Grayhawk" + } + }, + { + "id": 4201, + "name": "Vinson Adams", + "gender": "male", + "age": 61, + "address": { + "state": "Alabama", + "city": "Dargan" + } + }, + { + "id": 4202, + "name": "Wall Wolfe", + "gender": "male", + "age": 52, + "address": { + "state": "Virginia", + "city": "Duryea" + } + }, + { + "id": 4203, + "name": "Mamie Murphy", + "gender": "female", + "age": 21, + "address": { + "state": "Kentucky", + "city": "Sunbury" + } + }, + { + "id": 4204, + "name": "Hamilton Parks", + "gender": "male", + "age": 70, + "address": { + "state": "Oklahoma", + "city": "Forestburg" + } + }, + { + "id": 4205, + "name": "Caldwell Farrell", + "gender": "male", + "age": 71, + "address": { + "state": "Arizona", + "city": "Wollochet" + } + }, + { + "id": 4206, + "name": "Reeves Faulkner", + "gender": "male", + "age": 22, + "address": { + "state": "Georgia", + "city": "Bannock" + } + }, + { + "id": 4207, + "name": "Laurel Lloyd", + "gender": "female", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Fulford" + } + }, + { + "id": 4208, + "name": "Walsh Murray", + "gender": "male", + "age": 49, + "address": { + "state": "Delaware", + "city": "Jacksonburg" + } + }, + { + "id": 4209, + "name": "Clarke Ross", + "gender": "male", + "age": 35, + "address": { + "state": "West Virginia", + "city": "Thynedale" + } + }, + { + "id": 4210, + "name": "Corinne Stanley", + "gender": "female", + "age": 40, + "address": { + "state": "Wisconsin", + "city": "Makena" + } + }, + { + "id": 4211, + "name": "Wilda Chan", + "gender": "female", + "age": 78, + "address": { + "state": "Kansas", + "city": "Wildwood" + } + }, + { + "id": 4212, + "name": "Johnnie Massey", + "gender": "female", + "age": 50, + "address": { + "state": "Connecticut", + "city": "Grantville" + } + }, + { + "id": 4213, + "name": "Amber Ellison", + "gender": "female", + "age": 79, + "address": { + "state": "Tennessee", + "city": "Cannondale" + } + }, + { + "id": 4214, + "name": "Summer Romero", + "gender": "female", + "age": 43, + "address": { + "state": "Arkansas", + "city": "Savannah" + } + }, + { + "id": 4215, + "name": "Janis Mosley", + "gender": "female", + "age": 72, + "address": { + "state": "Michigan", + "city": "Alleghenyville" + } + }, + { + "id": 4216, + "name": "Holly Knapp", + "gender": "female", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Bonanza" + } + }, + { + "id": 4217, + "name": "Davis Peterson", + "gender": "male", + "age": 76, + "address": { + "state": "Illinois", + "city": "Shasta" + } + }, + { + "id": 4218, + "name": "Carolina Best", + "gender": "female", + "age": 50, + "address": { + "state": "Louisiana", + "city": "Clarksburg" + } + }, + { + "id": 4219, + "name": "Kate Sampson", + "gender": "female", + "age": 23, + "address": { + "state": "Rhode Island", + "city": "Chautauqua" + } + }, + { + "id": 4220, + "name": "Salazar Singleton", + "gender": "male", + "age": 57, + "address": { + "state": "Kentucky", + "city": "Dante" + } + }, + { + "id": 4221, + "name": "Blackburn Davis", + "gender": "male", + "age": 57, + "address": { + "state": "Idaho", + "city": "Winston" + } + }, + { + "id": 4222, + "name": "Wilkins Sloan", + "gender": "male", + "age": 75, + "address": { + "state": "Texas", + "city": "Gracey" + } + }, + { + "id": 4223, + "name": "Cardenas Durham", + "gender": "male", + "age": 52, + "address": { + "state": "Iowa", + "city": "Greenbackville" + } + }, + { + "id": 4224, + "name": "Stanley Mayo", + "gender": "male", + "age": 17, + "address": { + "state": "Arizona", + "city": "Foxworth" + } + }, + { + "id": 4225, + "name": "Carey Horne", + "gender": "female", + "age": 31, + "address": { + "state": "Missouri", + "city": "Ballico" + } + }, + { + "id": 4226, + "name": "Smith Morrow", + "gender": "male", + "age": 40, + "address": { + "state": "South Dakota", + "city": "Welda" + } + }, + { + "id": 4227, + "name": "Lauri Chapman", + "gender": "female", + "age": 46, + "address": { + "state": "South Carolina", + "city": "Norvelt" + } + }, + { + "id": 4228, + "name": "Rice Parrish", + "gender": "male", + "age": 62, + "address": { + "state": "New Jersey", + "city": "Barclay" + } + }, + { + "id": 4229, + "name": "Lawson Carr", + "gender": "male", + "age": 79, + "address": { + "state": "Nebraska", + "city": "Cuylerville" + } + }, + { + "id": 4230, + "name": "Cecile Holmes", + "gender": "female", + "age": 33, + "address": { + "state": "Ohio", + "city": "Sanford" + } + }, + { + "id": 4231, + "name": "Lucia May", + "gender": "female", + "age": 43, + "address": { + "state": "California", + "city": "Bennett" + } + }, + { + "id": 4232, + "name": "Gladys Dominguez", + "gender": "female", + "age": 22, + "address": { + "state": "New Mexico", + "city": "Lookingglass" + } + }, + { + "id": 4233, + "name": "Hale Vazquez", + "gender": "male", + "age": 81, + "address": { + "state": "Pennsylvania", + "city": "Disautel" + } + }, + { + "id": 4234, + "name": "Rush Boone", + "gender": "male", + "age": 69, + "address": { + "state": "Kansas", + "city": "Twilight" + } + }, + { + "id": 4235, + "name": "Joyce Powers", + "gender": "male", + "age": 52, + "address": { + "state": "Georgia", + "city": "Imperial" + } + }, + { + "id": 4236, + "name": "Julie Nunez", + "gender": "female", + "age": 72, + "address": { + "state": "Nevada", + "city": "Villarreal" + } + }, + { + "id": 4237, + "name": "Ora Sweet", + "gender": "female", + "age": 56, + "address": { + "state": "Tennessee", + "city": "Axis" + } + }, + { + "id": 4238, + "name": "Katelyn Simon", + "gender": "female", + "age": 34, + "address": { + "state": "Colorado", + "city": "Laurelton" + } + }, + { + "id": 4239, + "name": "Crosby Beasley", + "gender": "male", + "age": 49, + "address": { + "state": "Oregon", + "city": "Coleville" + } + }, + { + "id": 4240, + "name": "Janette Alston", + "gender": "female", + "age": 65, + "address": { + "state": "Indiana", + "city": "Ypsilanti" + } + }, + { + "id": 4241, + "name": "Quinn Conway", + "gender": "male", + "age": 77, + "address": { + "state": "Hawaii", + "city": "Whitmer" + } + }, + { + "id": 4242, + "name": "Horton Nixon", + "gender": "male", + "age": 29, + "address": { + "state": "Maine", + "city": "Helen" + } + }, + { + "id": 4243, + "name": "Veronica Ford", + "gender": "female", + "age": 36, + "address": { + "state": "Utah", + "city": "Ruffin" + } + }, + { + "id": 4244, + "name": "Latoya Wilcox", + "gender": "female", + "age": 65, + "address": { + "state": "Massachusetts", + "city": "Williams" + } + }, + { + "id": 4245, + "name": "Catalina Hogan", + "gender": "female", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Kenwood" + } + }, + { + "id": 4246, + "name": "Ella Drake", + "gender": "female", + "age": 48, + "address": { + "state": "Vermont", + "city": "Floris" + } + }, + { + "id": 4247, + "name": "Christy Baker", + "gender": "female", + "age": 20, + "address": { + "state": "Wisconsin", + "city": "Hannasville" + } + }, + { + "id": 4248, + "name": "Annmarie Velazquez", + "gender": "female", + "age": 24, + "address": { + "state": "North Carolina", + "city": "Freeburn" + } + }, + { + "id": 4249, + "name": "Concetta Flowers", + "gender": "female", + "age": 81, + "address": { + "state": "North Dakota", + "city": "Abiquiu" + } + }, + { + "id": 4250, + "name": "Debra Lane", + "gender": "female", + "age": 47, + "address": { + "state": "Virginia", + "city": "Cawood" + } + }, + { + "id": 4251, + "name": "Curry Walters", + "gender": "male", + "age": 47, + "address": { + "state": "Wyoming", + "city": "Richmond" + } + }, + { + "id": 4252, + "name": "Nadia Bruce", + "gender": "female", + "age": 31, + "address": { + "state": "Montana", + "city": "Kaka" + } + }, + { + "id": 4253, + "name": "Norris Snyder", + "gender": "male", + "age": 31, + "address": { + "state": "Maryland", + "city": "Bagtown" + } + }, + { + "id": 4254, + "name": "Marianne Barron", + "gender": "female", + "age": 73, + "address": { + "state": "Florida", + "city": "Bison" + } + }, + { + "id": 4255, + "name": "Erickson King", + "gender": "male", + "age": 33, + "address": { + "state": "Connecticut", + "city": "Levant" + } + }, + { + "id": 4256, + "name": "Carol Cooke", + "gender": "female", + "age": 52, + "address": { + "state": "Washington", + "city": "Kenvil" + } + }, + { + "id": 4257, + "name": "Katheryn Koch", + "gender": "female", + "age": 58, + "address": { + "state": "New York", + "city": "Norwood" + } + }, + { + "id": 4258, + "name": "Letha Baird", + "gender": "female", + "age": 18, + "address": { + "state": "New Hampshire", + "city": "Chloride" + } + }, + { + "id": 4259, + "name": "Kidd Fitzpatrick", + "gender": "male", + "age": 81, + "address": { + "state": "West Virginia", + "city": "Hailesboro" + } + }, + { + "id": 4260, + "name": "Chase Weaver", + "gender": "male", + "age": 20, + "address": { + "state": "Alaska", + "city": "Winesburg" + } + }, + { + "id": 4261, + "name": "Lacy Pacheco", + "gender": "female", + "age": 69, + "address": { + "state": "Delaware", + "city": "Leroy" + } + }, + { + "id": 4262, + "name": "Stephanie Ryan", + "gender": "female", + "age": 36, + "address": { + "state": "Alabama", + "city": "Ada" + } + }, + { + "id": 4263, + "name": "Alexandria Payne", + "gender": "female", + "age": 18, + "address": { + "state": "Nevada", + "city": "Groton" + } + }, + { + "id": 4264, + "name": "Mercer Mckee", + "gender": "male", + "age": 43, + "address": { + "state": "Alaska", + "city": "Morriston" + } + }, + { + "id": 4265, + "name": "William Nguyen", + "gender": "male", + "age": 64, + "address": { + "state": "South Dakota", + "city": "Osmond" + } + }, + { + "id": 4266, + "name": "Loretta Grant", + "gender": "female", + "age": 29, + "address": { + "state": "Minnesota", + "city": "Enetai" + } + }, + { + "id": 4267, + "name": "Monique Finley", + "gender": "female", + "age": 74, + "address": { + "state": "Georgia", + "city": "Canoochee" + } + }, + { + "id": 4268, + "name": "Tucker Jackson", + "gender": "male", + "age": 61, + "address": { + "state": "Kansas", + "city": "Chloride" + } + }, + { + "id": 4269, + "name": "Mason Mcconnell", + "gender": "male", + "age": 19, + "address": { + "state": "Vermont", + "city": "Selma" + } + }, + { + "id": 4270, + "name": "Dalton House", + "gender": "male", + "age": 53, + "address": { + "state": "South Carolina", + "city": "Vowinckel" + } + }, + { + "id": 4271, + "name": "Joyce Jones", + "gender": "female", + "age": 59, + "address": { + "state": "Alabama", + "city": "Ruckersville" + } + }, + { + "id": 4272, + "name": "Irene Mejia", + "gender": "female", + "age": 54, + "address": { + "state": "Utah", + "city": "Woodruff" + } + }, + { + "id": 4273, + "name": "York Fowler", + "gender": "male", + "age": 36, + "address": { + "state": "Washington", + "city": "Hillsboro" + } + }, + { + "id": 4274, + "name": "Patrick Velazquez", + "gender": "male", + "age": 20, + "address": { + "state": "Illinois", + "city": "Noxen" + } + }, + { + "id": 4275, + "name": "Coleen Suarez", + "gender": "female", + "age": 49, + "address": { + "state": "Maine", + "city": "Monument" + } + }, + { + "id": 4276, + "name": "West Barnett", + "gender": "male", + "age": 78, + "address": { + "state": "Florida", + "city": "Cavalero" + } + }, + { + "id": 4277, + "name": "Ruthie Sanders", + "gender": "female", + "age": 79, + "address": { + "state": "Virginia", + "city": "Chumuckla" + } + }, + { + "id": 4278, + "name": "Aurelia Conner", + "gender": "female", + "age": 41, + "address": { + "state": "Hawaii", + "city": "Joes" + } + }, + { + "id": 4279, + "name": "Osborn Henry", + "gender": "male", + "age": 39, + "address": { + "state": "California", + "city": "Statenville" + } + }, + { + "id": 4280, + "name": "Eunice Blair", + "gender": "female", + "age": 38, + "address": { + "state": "New Mexico", + "city": "Sunriver" + } + }, + { + "id": 4281, + "name": "Agnes Pope", + "gender": "female", + "age": 51, + "address": { + "state": "Louisiana", + "city": "Belgreen" + } + }, + { + "id": 4282, + "name": "Gillespie Guerrero", + "gender": "male", + "age": 67, + "address": { + "state": "Oregon", + "city": "Brooktrails" + } + }, + { + "id": 4283, + "name": "Trudy Gardner", + "gender": "female", + "age": 68, + "address": { + "state": "New York", + "city": "Rodanthe" + } + }, + { + "id": 4284, + "name": "Wolfe Peck", + "gender": "male", + "age": 18, + "address": { + "state": "Iowa", + "city": "Rote" + } + }, + { + "id": 4285, + "name": "Mckee George", + "gender": "male", + "age": 62, + "address": { + "state": "Missouri", + "city": "Gasquet" + } + }, + { + "id": 4286, + "name": "Kline Patterson", + "gender": "male", + "age": 82, + "address": { + "state": "Arkansas", + "city": "Thatcher" + } + }, + { + "id": 4287, + "name": "Janna Walls", + "gender": "female", + "age": 53, + "address": { + "state": "Idaho", + "city": "Stockwell" + } + }, + { + "id": 4288, + "name": "Alyson Gonzales", + "gender": "female", + "age": 69, + "address": { + "state": "Connecticut", + "city": "Savage" + } + }, + { + "id": 4289, + "name": "Mercedes Ayala", + "gender": "female", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Helen" + } + }, + { + "id": 4290, + "name": "Mcfadden Cotton", + "gender": "male", + "age": 34, + "address": { + "state": "New Hampshire", + "city": "Roulette" + } + }, + { + "id": 4291, + "name": "Nelson Clark", + "gender": "male", + "age": 79, + "address": { + "state": "Arizona", + "city": "Greenbush" + } + }, + { + "id": 4292, + "name": "Gray Dickson", + "gender": "male", + "age": 46, + "address": { + "state": "Montana", + "city": "Tuskahoma" + } + }, + { + "id": 4293, + "name": "Denise Farrell", + "gender": "female", + "age": 68, + "address": { + "state": "Indiana", + "city": "Hiko" + } + }, + { + "id": 4294, + "name": "Gilda Mays", + "gender": "female", + "age": 40, + "address": { + "state": "Colorado", + "city": "Spelter" + } + }, + { + "id": 4295, + "name": "Gonzalez King", + "gender": "male", + "age": 47, + "address": { + "state": "Nebraska", + "city": "Marienthal" + } + }, + { + "id": 4296, + "name": "Liz Rosa", + "gender": "female", + "age": 36, + "address": { + "state": "Maryland", + "city": "Dorneyville" + } + }, + { + "id": 4297, + "name": "Cynthia Dotson", + "gender": "female", + "age": 68, + "address": { + "state": "Ohio", + "city": "Derwood" + } + }, + { + "id": 4298, + "name": "Ruiz Albert", + "gender": "male", + "age": 22, + "address": { + "state": "Michigan", + "city": "Falmouth" + } + }, + { + "id": 4299, + "name": "Tia Guzman", + "gender": "female", + "age": 19, + "address": { + "state": "Wisconsin", + "city": "Lookingglass" + } + }, + { + "id": 4300, + "name": "Cristina Mcdowell", + "gender": "female", + "age": 59, + "address": { + "state": "West Virginia", + "city": "Talpa" + } + }, + { + "id": 4301, + "name": "Ramos Cervantes", + "gender": "male", + "age": 46, + "address": { + "state": "Pennsylvania", + "city": "Downsville" + } + }, + { + "id": 4302, + "name": "Wall Caldwell", + "gender": "male", + "age": 59, + "address": { + "state": "Mississippi", + "city": "Olney" + } + }, + { + "id": 4303, + "name": "Ballard Mills", + "gender": "male", + "age": 29, + "address": { + "state": "North Carolina", + "city": "Biddle" + } + }, + { + "id": 4304, + "name": "Stone Barrera", + "gender": "male", + "age": 33, + "address": { + "state": "Massachusetts", + "city": "Madrid" + } + }, + { + "id": 4305, + "name": "Foster Raymond", + "gender": "male", + "age": 51, + "address": { + "state": "North Dakota", + "city": "Lacomb" + } + }, + { + "id": 4306, + "name": "Eileen Stark", + "gender": "female", + "age": 82, + "address": { + "state": "Delaware", + "city": "Bergoo" + } + }, + { + "id": 4307, + "name": "Dorothea Kirk", + "gender": "female", + "age": 37, + "address": { + "state": "Kentucky", + "city": "Gadsden" + } + }, + { + "id": 4308, + "name": "Hahn Sweeney", + "gender": "male", + "age": 52, + "address": { + "state": "Oklahoma", + "city": "Cotopaxi" + } + }, + { + "id": 4309, + "name": "Mcclure Kline", + "gender": "male", + "age": 55, + "address": { + "state": "Tennessee", + "city": "Boomer" + } + }, + { + "id": 4310, + "name": "Aisha Best", + "gender": "female", + "age": 44, + "address": { + "state": "Texas", + "city": "Jackpot" + } + }, + { + "id": 4311, + "name": "Bond Ratliff", + "gender": "male", + "age": 29, + "address": { + "state": "Wyoming", + "city": "Kraemer" + } + }, + { + "id": 4312, + "name": "Hillary Stone", + "gender": "female", + "age": 30, + "address": { + "state": "Arizona", + "city": "Groveville" + } + }, + { + "id": 4313, + "name": "Daniel Jensen", + "gender": "male", + "age": 19, + "address": { + "state": "Arkansas", + "city": "Castleton" + } + }, + { + "id": 4314, + "name": "Yesenia Morgan", + "gender": "female", + "age": 41, + "address": { + "state": "California", + "city": "Sperryville" + } + }, + { + "id": 4315, + "name": "Mcfarland Mccullough", + "gender": "male", + "age": 34, + "address": { + "state": "Minnesota", + "city": "Groton" + } + }, + { + "id": 4316, + "name": "Lavonne Richard", + "gender": "female", + "age": 58, + "address": { + "state": "Vermont", + "city": "Websterville" + } + }, + { + "id": 4317, + "name": "Tina Day", + "gender": "female", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Brooktrails" + } + }, + { + "id": 4318, + "name": "Gross Howe", + "gender": "male", + "age": 59, + "address": { + "state": "Oklahoma", + "city": "Jacksonburg" + } + }, + { + "id": 4319, + "name": "Rosella Matthews", + "gender": "female", + "age": 73, + "address": { + "state": "Pennsylvania", + "city": "Russellville" + } + }, + { + "id": 4320, + "name": "Krystal Morales", + "gender": "female", + "age": 62, + "address": { + "state": "Maine", + "city": "Monument" + } + }, + { + "id": 4321, + "name": "Mcdowell Diaz", + "gender": "male", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Morningside" + } + }, + { + "id": 4322, + "name": "Cara Fields", + "gender": "female", + "age": 78, + "address": { + "state": "West Virginia", + "city": "Kenmar" + } + }, + { + "id": 4323, + "name": "Brittany Parsons", + "gender": "female", + "age": 71, + "address": { + "state": "Delaware", + "city": "Enetai" + } + }, + { + "id": 4324, + "name": "Karyn Sandoval", + "gender": "female", + "age": 54, + "address": { + "state": "Massachusetts", + "city": "Weogufka" + } + }, + { + "id": 4325, + "name": "Yang Gomez", + "gender": "male", + "age": 62, + "address": { + "state": "Texas", + "city": "Bonanza" + } + }, + { + "id": 4326, + "name": "Shanna Benjamin", + "gender": "female", + "age": 49, + "address": { + "state": "Alabama", + "city": "Cherokee" + } + }, + { + "id": 4327, + "name": "Patrica Salas", + "gender": "female", + "age": 64, + "address": { + "state": "South Dakota", + "city": "Calvary" + } + }, + { + "id": 4328, + "name": "Brigitte Cervantes", + "gender": "female", + "age": 69, + "address": { + "state": "Utah", + "city": "Westmoreland" + } + }, + { + "id": 4329, + "name": "Adrienne Bolton", + "gender": "female", + "age": 52, + "address": { + "state": "Georgia", + "city": "Suitland" + } + }, + { + "id": 4330, + "name": "Jeannie Bartlett", + "gender": "female", + "age": 32, + "address": { + "state": "Oregon", + "city": "Shepardsville" + } + }, + { + "id": 4331, + "name": "Greene Rios", + "gender": "male", + "age": 44, + "address": { + "state": "Colorado", + "city": "Flintville" + } + }, + { + "id": 4332, + "name": "Mccall Stevens", + "gender": "male", + "age": 64, + "address": { + "state": "Illinois", + "city": "Ticonderoga" + } + }, + { + "id": 4333, + "name": "Barry Burgess", + "gender": "male", + "age": 22, + "address": { + "state": "North Carolina", + "city": "Sheatown" + } + }, + { + "id": 4334, + "name": "English Valentine", + "gender": "male", + "age": 60, + "address": { + "state": "New Jersey", + "city": "Hasty" + } + }, + { + "id": 4335, + "name": "Katy Waters", + "gender": "female", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Gulf" + } + }, + { + "id": 4336, + "name": "Reid Malone", + "gender": "male", + "age": 68, + "address": { + "state": "Wisconsin", + "city": "Ivanhoe" + } + }, + { + "id": 4337, + "name": "Justine Glenn", + "gender": "female", + "age": 26, + "address": { + "state": "Hawaii", + "city": "Yogaville" + } + }, + { + "id": 4338, + "name": "Rosemarie Byrd", + "gender": "female", + "age": 45, + "address": { + "state": "Ohio", + "city": "Kersey" + } + }, + { + "id": 4339, + "name": "Roberson Kinney", + "gender": "male", + "age": 38, + "address": { + "state": "Florida", + "city": "Wolcott" + } + }, + { + "id": 4340, + "name": "Victoria May", + "gender": "female", + "age": 82, + "address": { + "state": "Kansas", + "city": "Chesapeake" + } + }, + { + "id": 4341, + "name": "Schultz Olson", + "gender": "male", + "age": 39, + "address": { + "state": "Missouri", + "city": "Downsville" + } + }, + { + "id": 4342, + "name": "Bray Wolf", + "gender": "male", + "age": 20, + "address": { + "state": "Iowa", + "city": "Ronco" + } + }, + { + "id": 4343, + "name": "Jolene Bauer", + "gender": "female", + "age": 70, + "address": { + "state": "Mississippi", + "city": "Highland" + } + }, + { + "id": 4344, + "name": "Tia Kelly", + "gender": "female", + "age": 52, + "address": { + "state": "Indiana", + "city": "Tooleville" + } + }, + { + "id": 4345, + "name": "Phyllis Deleon", + "gender": "female", + "age": 54, + "address": { + "state": "Alaska", + "city": "Alafaya" + } + }, + { + "id": 4346, + "name": "Garcia Tucker", + "gender": "male", + "age": 45, + "address": { + "state": "Kentucky", + "city": "Graniteville" + } + }, + { + "id": 4347, + "name": "Brandy Ross", + "gender": "female", + "age": 52, + "address": { + "state": "Wyoming", + "city": "Century" + } + }, + { + "id": 4348, + "name": "Galloway Patrick", + "gender": "male", + "age": 78, + "address": { + "state": "New York", + "city": "Riegelwood" + } + }, + { + "id": 4349, + "name": "Mercedes Gutierrez", + "gender": "female", + "age": 18, + "address": { + "state": "Rhode Island", + "city": "Caspar" + } + }, + { + "id": 4350, + "name": "Dorthy Hart", + "gender": "female", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Elrama" + } + }, + { + "id": 4351, + "name": "Hazel Odonnell", + "gender": "female", + "age": 75, + "address": { + "state": "Nevada", + "city": "Stouchsburg" + } + }, + { + "id": 4352, + "name": "Tessa Alexander", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Alleghenyville" + } + }, + { + "id": 4353, + "name": "Celina Vaughan", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Vernon" + } + }, + { + "id": 4354, + "name": "Emilia Mccray", + "gender": "female", + "age": 82, + "address": { + "state": "North Dakota", + "city": "Trinway" + } + }, + { + "id": 4355, + "name": "Carmen Griffith", + "gender": "female", + "age": 39, + "address": { + "state": "Idaho", + "city": "Lund" + } + }, + { + "id": 4356, + "name": "Anderson Singleton", + "gender": "male", + "age": 69, + "address": { + "state": "Washington", + "city": "Gloucester" + } + }, + { + "id": 4357, + "name": "Gibbs Clemons", + "gender": "male", + "age": 29, + "address": { + "state": "Montana", + "city": "Nutrioso" + } + }, + { + "id": 4358, + "name": "Thornton Wiley", + "gender": "male", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Hollymead" + } + }, + { + "id": 4359, + "name": "Kaufman Alvarado", + "gender": "male", + "age": 32, + "address": { + "state": "Michigan", + "city": "Rutherford" + } + }, + { + "id": 4360, + "name": "Herman Bender", + "gender": "male", + "age": 22, + "address": { + "state": "Virginia", + "city": "Limestone" + } + }, + { + "id": 4361, + "name": "Jacobs English", + "gender": "male", + "age": 22, + "address": { + "state": "Oklahoma", + "city": "Brule" + } + }, + { + "id": 4362, + "name": "Vinson Vaughan", + "gender": "male", + "age": 70, + "address": { + "state": "Maine", + "city": "Wintersburg" + } + }, + { + "id": 4363, + "name": "Janie Donovan", + "gender": "female", + "age": 37, + "address": { + "state": "Delaware", + "city": "Wilmington" + } + }, + { + "id": 4364, + "name": "Leblanc Dawson", + "gender": "male", + "age": 64, + "address": { + "state": "Georgia", + "city": "Savannah" + } + }, + { + "id": 4365, + "name": "Jane Jefferson", + "gender": "female", + "age": 29, + "address": { + "state": "Utah", + "city": "Canby" + } + }, + { + "id": 4366, + "name": "Michelle Mcclain", + "gender": "female", + "age": 73, + "address": { + "state": "New Mexico", + "city": "Cumberland" + } + }, + { + "id": 4367, + "name": "Trina Armstrong", + "gender": "female", + "age": 23, + "address": { + "state": "Alaska", + "city": "Herlong" + } + }, + { + "id": 4368, + "name": "Patel Strickland", + "gender": "male", + "age": 78, + "address": { + "state": "Rhode Island", + "city": "Manitou" + } + }, + { + "id": 4369, + "name": "Johnnie Briggs", + "gender": "female", + "age": 59, + "address": { + "state": "Missouri", + "city": "Orason" + } + }, + { + "id": 4370, + "name": "Keri Thomas", + "gender": "female", + "age": 53, + "address": { + "state": "Arizona", + "city": "Newcastle" + } + }, + { + "id": 4371, + "name": "Stuart Spears", + "gender": "male", + "age": 23, + "address": { + "state": "Vermont", + "city": "Berwind" + } + }, + { + "id": 4372, + "name": "Becky Beck", + "gender": "female", + "age": 25, + "address": { + "state": "West Virginia", + "city": "Baden" + } + }, + { + "id": 4373, + "name": "Sybil Stephens", + "gender": "female", + "age": 54, + "address": { + "state": "Michigan", + "city": "Marysville" + } + }, + { + "id": 4374, + "name": "Vasquez Newton", + "gender": "male", + "age": 34, + "address": { + "state": "California", + "city": "Aberdeen" + } + }, + { + "id": 4375, + "name": "Lessie Burton", + "gender": "female", + "age": 73, + "address": { + "state": "Kentucky", + "city": "Grayhawk" + } + }, + { + "id": 4376, + "name": "Magdalena Dalton", + "gender": "female", + "age": 61, + "address": { + "state": "South Dakota", + "city": "Gibbsville" + } + }, + { + "id": 4377, + "name": "Meghan Malone", + "gender": "female", + "age": 68, + "address": { + "state": "Idaho", + "city": "Idamay" + } + }, + { + "id": 4378, + "name": "Duran Mueller", + "gender": "male", + "age": 65, + "address": { + "state": "Washington", + "city": "Holcombe" + } + }, + { + "id": 4379, + "name": "Gwendolyn Webster", + "gender": "female", + "age": 39, + "address": { + "state": "Arkansas", + "city": "Woodruff" + } + }, + { + "id": 4380, + "name": "Willie Bowen", + "gender": "female", + "age": 68, + "address": { + "state": "Kansas", + "city": "Avalon" + } + }, + { + "id": 4381, + "name": "Marsha Hart", + "gender": "female", + "age": 63, + "address": { + "state": "Ohio", + "city": "Belvoir" + } + }, + { + "id": 4382, + "name": "Vonda Reid", + "gender": "female", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Neahkahnie" + } + }, + { + "id": 4383, + "name": "Kristie Gilliam", + "gender": "female", + "age": 81, + "address": { + "state": "North Carolina", + "city": "Harviell" + } + }, + { + "id": 4384, + "name": "Velma Cabrera", + "gender": "female", + "age": 28, + "address": { + "state": "Maryland", + "city": "Elfrida" + } + }, + { + "id": 4385, + "name": "Crystal Hardin", + "gender": "female", + "age": 57, + "address": { + "state": "Virginia", + "city": "Stewart" + } + }, + { + "id": 4386, + "name": "Alvarez Peterson", + "gender": "male", + "age": 28, + "address": { + "state": "Tennessee", + "city": "Edgar" + } + }, + { + "id": 4387, + "name": "Meredith Mccormick", + "gender": "female", + "age": 60, + "address": { + "state": "Illinois", + "city": "Datil" + } + }, + { + "id": 4388, + "name": "Tamera Pate", + "gender": "female", + "age": 70, + "address": { + "state": "South Carolina", + "city": "Innsbrook" + } + }, + { + "id": 4389, + "name": "Brenda Pratt", + "gender": "female", + "age": 17, + "address": { + "state": "Montana", + "city": "Why" + } + }, + { + "id": 4390, + "name": "Osborne Meyer", + "gender": "male", + "age": 65, + "address": { + "state": "North Dakota", + "city": "Wildwood" + } + }, + { + "id": 4391, + "name": "Calhoun Huff", + "gender": "male", + "age": 75, + "address": { + "state": "Pennsylvania", + "city": "Coloma" + } + }, + { + "id": 4392, + "name": "Nina Parks", + "gender": "female", + "age": 39, + "address": { + "state": "Nevada", + "city": "Murillo" + } + }, + { + "id": 4393, + "name": "Judith Prince", + "gender": "female", + "age": 44, + "address": { + "state": "Iowa", + "city": "Gardiner" + } + }, + { + "id": 4394, + "name": "Sherry Witt", + "gender": "female", + "age": 82, + "address": { + "state": "Indiana", + "city": "Newry" + } + }, + { + "id": 4395, + "name": "Josefina Rowland", + "gender": "female", + "age": 41, + "address": { + "state": "Hawaii", + "city": "Bennett" + } + }, + { + "id": 4396, + "name": "Norton Lyons", + "gender": "male", + "age": 50, + "address": { + "state": "Texas", + "city": "Homeworth" + } + }, + { + "id": 4397, + "name": "Avery Stout", + "gender": "male", + "age": 60, + "address": { + "state": "Louisiana", + "city": "Matheny" + } + }, + { + "id": 4398, + "name": "Conley Coleman", + "gender": "male", + "age": 45, + "address": { + "state": "Connecticut", + "city": "Englevale" + } + }, + { + "id": 4399, + "name": "Leonor Edwards", + "gender": "female", + "age": 67, + "address": { + "state": "Nebraska", + "city": "Conway" + } + }, + { + "id": 4400, + "name": "Brigitte Hines", + "gender": "female", + "age": 44, + "address": { + "state": "New York", + "city": "Nadine" + } + }, + { + "id": 4401, + "name": "Rosemarie Warner", + "gender": "female", + "age": 56, + "address": { + "state": "Mississippi", + "city": "Eagleville" + } + }, + { + "id": 4402, + "name": "Tammie Ferguson", + "gender": "female", + "age": 44, + "address": { + "state": "Wisconsin", + "city": "Davenport" + } + }, + { + "id": 4403, + "name": "Lindsay Gardner", + "gender": "male", + "age": 77, + "address": { + "state": "Colorado", + "city": "Ryderwood" + } + }, + { + "id": 4404, + "name": "Henry Mckay", + "gender": "male", + "age": 17, + "address": { + "state": "Massachusetts", + "city": "Eureka" + } + }, + { + "id": 4405, + "name": "Cecelia Norman", + "gender": "female", + "age": 18, + "address": { + "state": "Minnesota", + "city": "Bison" + } + }, + { + "id": 4406, + "name": "Oconnor Stark", + "gender": "male", + "age": 70, + "address": { + "state": "Alabama", + "city": "Warren" + } + }, + { + "id": 4407, + "name": "Suzanne Love", + "gender": "female", + "age": 27, + "address": { + "state": "Oregon", + "city": "Dubois" + } + }, + { + "id": 4408, + "name": "Jeannine Reeves", + "gender": "female", + "age": 19, + "address": { + "state": "Wyoming", + "city": "Torboy" + } + }, + { + "id": 4409, + "name": "Landry Camacho", + "gender": "male", + "age": 34, + "address": { + "state": "New Hampshire", + "city": "Bodega" + } + }, + { + "id": 4410, + "name": "William Vincent", + "gender": "male", + "age": 25, + "address": { + "state": "Indiana", + "city": "Coultervillle" + } + }, + { + "id": 4411, + "name": "Jarvis Cain", + "gender": "male", + "age": 65, + "address": { + "state": "Tennessee", + "city": "Wawona" + } + }, + { + "id": 4412, + "name": "Warren Ferrell", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Cobbtown" + } + }, + { + "id": 4413, + "name": "Atkinson Alston", + "gender": "male", + "age": 42, + "address": { + "state": "Illinois", + "city": "Sultana" + } + }, + { + "id": 4414, + "name": "Jacobs Rice", + "gender": "male", + "age": 48, + "address": { + "state": "Wyoming", + "city": "Deercroft" + } + }, + { + "id": 4415, + "name": "Wolfe Roach", + "gender": "male", + "age": 20, + "address": { + "state": "Missouri", + "city": "Beaverdale" + } + }, + { + "id": 4416, + "name": "Viola Avery", + "gender": "female", + "age": 37, + "address": { + "state": "California", + "city": "Vale" + } + }, + { + "id": 4417, + "name": "Wiley Lang", + "gender": "male", + "age": 49, + "address": { + "state": "Kansas", + "city": "Washington" + } + }, + { + "id": 4418, + "name": "Welch Young", + "gender": "male", + "age": 68, + "address": { + "state": "New Hampshire", + "city": "Barronett" + } + }, + { + "id": 4419, + "name": "Juarez Valenzuela", + "gender": "male", + "age": 64, + "address": { + "state": "Mississippi", + "city": "Dundee" + } + }, + { + "id": 4420, + "name": "Morse Cooley", + "gender": "male", + "age": 60, + "address": { + "state": "Colorado", + "city": "Fresno" + } + }, + { + "id": 4421, + "name": "Gilda Bryan", + "gender": "female", + "age": 78, + "address": { + "state": "Rhode Island", + "city": "Macdona" + } + }, + { + "id": 4422, + "name": "Wall Mccarty", + "gender": "male", + "age": 57, + "address": { + "state": "Nebraska", + "city": "Kenvil" + } + }, + { + "id": 4423, + "name": "Hurley Bass", + "gender": "male", + "age": 27, + "address": { + "state": "Ohio", + "city": "Umapine" + } + }, + { + "id": 4424, + "name": "Jessie Ayala", + "gender": "female", + "age": 22, + "address": { + "state": "Georgia", + "city": "Verdi" + } + }, + { + "id": 4425, + "name": "Tiffany Mcgowan", + "gender": "female", + "age": 68, + "address": { + "state": "Kentucky", + "city": "Sunriver" + } + }, + { + "id": 4426, + "name": "Nita Baird", + "gender": "female", + "age": 32, + "address": { + "state": "Florida", + "city": "Kula" + } + }, + { + "id": 4427, + "name": "Becky Fowler", + "gender": "female", + "age": 52, + "address": { + "state": "Virginia", + "city": "Hall" + } + }, + { + "id": 4428, + "name": "Clements Hodge", + "gender": "male", + "age": 55, + "address": { + "state": "Utah", + "city": "Cornucopia" + } + }, + { + "id": 4429, + "name": "Daisy Ortega", + "gender": "female", + "age": 72, + "address": { + "state": "Nevada", + "city": "Cazadero" + } + }, + { + "id": 4430, + "name": "Rowland Griffith", + "gender": "male", + "age": 58, + "address": { + "state": "Massachusetts", + "city": "Vallonia" + } + }, + { + "id": 4431, + "name": "Hull Conway", + "gender": "male", + "age": 18, + "address": { + "state": "Hawaii", + "city": "Joppa" + } + }, + { + "id": 4432, + "name": "Ophelia Bond", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Jacksonburg" + } + }, + { + "id": 4433, + "name": "Rocha Hayes", + "gender": "male", + "age": 62, + "address": { + "state": "Alabama", + "city": "Bynum" + } + }, + { + "id": 4434, + "name": "Hewitt Carpenter", + "gender": "male", + "age": 76, + "address": { + "state": "North Carolina", + "city": "Leland" + } + }, + { + "id": 4435, + "name": "Turner Oconnor", + "gender": "male", + "age": 46, + "address": { + "state": "West Virginia", + "city": "Martinsville" + } + }, + { + "id": 4436, + "name": "Mills Mcknight", + "gender": "male", + "age": 65, + "address": { + "state": "New Jersey", + "city": "Delshire" + } + }, + { + "id": 4437, + "name": "Lara Norton", + "gender": "female", + "age": 24, + "address": { + "state": "South Carolina", + "city": "Rockhill" + } + }, + { + "id": 4438, + "name": "Karla Finley", + "gender": "female", + "age": 58, + "address": { + "state": "Pennsylvania", + "city": "Bordelonville" + } + }, + { + "id": 4439, + "name": "Virginia Blake", + "gender": "female", + "age": 44, + "address": { + "state": "Wisconsin", + "city": "Tuskahoma" + } + }, + { + "id": 4440, + "name": "Levy Herrera", + "gender": "male", + "age": 60, + "address": { + "state": "Washington", + "city": "Osmond" + } + }, + { + "id": 4441, + "name": "Patti Fitzgerald", + "gender": "female", + "age": 39, + "address": { + "state": "New York", + "city": "Innsbrook" + } + }, + { + "id": 4442, + "name": "Dotson Bean", + "gender": "male", + "age": 56, + "address": { + "state": "Oregon", + "city": "Swartzville" + } + }, + { + "id": 4443, + "name": "Rachael Schneider", + "gender": "female", + "age": 44, + "address": { + "state": "Iowa", + "city": "Broadlands" + } + }, + { + "id": 4444, + "name": "Aurora Roth", + "gender": "female", + "age": 75, + "address": { + "state": "Alaska", + "city": "Berlin" + } + }, + { + "id": 4445, + "name": "Villarreal Shepard", + "gender": "male", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Sisquoc" + } + }, + { + "id": 4446, + "name": "Irene Odonnell", + "gender": "female", + "age": 46, + "address": { + "state": "Oklahoma", + "city": "Ogema" + } + }, + { + "id": 4447, + "name": "Gillespie Dalton", + "gender": "male", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Lindcove" + } + }, + { + "id": 4448, + "name": "Sheryl Melendez", + "gender": "female", + "age": 50, + "address": { + "state": "South Dakota", + "city": "Aurora" + } + }, + { + "id": 4449, + "name": "Schroeder Guerra", + "gender": "male", + "age": 57, + "address": { + "state": "Idaho", + "city": "Frierson" + } + }, + { + "id": 4450, + "name": "Marjorie Wade", + "gender": "female", + "age": 65, + "address": { + "state": "Montana", + "city": "Mapletown" + } + }, + { + "id": 4451, + "name": "Ellis Dominguez", + "gender": "male", + "age": 70, + "address": { + "state": "Texas", + "city": "Chesterfield" + } + }, + { + "id": 4452, + "name": "Noemi Mcleod", + "gender": "female", + "age": 26, + "address": { + "state": "New Mexico", + "city": "Edgewater" + } + }, + { + "id": 4453, + "name": "Nadine Skinner", + "gender": "female", + "age": 55, + "address": { + "state": "North Dakota", + "city": "Gloucester" + } + }, + { + "id": 4454, + "name": "Toni Francis", + "gender": "female", + "age": 33, + "address": { + "state": "Louisiana", + "city": "Bison" + } + }, + { + "id": 4455, + "name": "Decker Myers", + "gender": "male", + "age": 41, + "address": { + "state": "Vermont", + "city": "Marbury" + } + }, + { + "id": 4456, + "name": "Nola Newman", + "gender": "female", + "age": 80, + "address": { + "state": "Maine", + "city": "Retsof" + } + }, + { + "id": 4457, + "name": "Freida Townsend", + "gender": "female", + "age": 25, + "address": { + "state": "Maryland", + "city": "Turah" + } + }, + { + "id": 4458, + "name": "Monroe Floyd", + "gender": "male", + "age": 31, + "address": { + "state": "Minnesota", + "city": "Dixonville" + } + }, + { + "id": 4459, + "name": "Charity Clemons", + "gender": "female", + "age": 76, + "address": { + "state": "New Jersey", + "city": "Foxworth" + } + }, + { + "id": 4460, + "name": "Wise Velez", + "gender": "male", + "age": 27, + "address": { + "state": "Alabama", + "city": "Ruckersville" + } + }, + { + "id": 4461, + "name": "Alvarez Madden", + "gender": "male", + "age": 24, + "address": { + "state": "Georgia", + "city": "Cliffside" + } + }, + { + "id": 4462, + "name": "Rutledge Silva", + "gender": "male", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Crayne" + } + }, + { + "id": 4463, + "name": "Isabelle Mayo", + "gender": "female", + "age": 59, + "address": { + "state": "Michigan", + "city": "Bordelonville" + } + }, + { + "id": 4464, + "name": "Smith Washington", + "gender": "male", + "age": 50, + "address": { + "state": "West Virginia", + "city": "Glasgow" + } + }, + { + "id": 4465, + "name": "Ann Hansen", + "gender": "female", + "age": 46, + "address": { + "state": "California", + "city": "Flintville" + } + }, + { + "id": 4466, + "name": "York Navarro", + "gender": "male", + "age": 20, + "address": { + "state": "Maryland", + "city": "Aurora" + } + }, + { + "id": 4467, + "name": "Leila Randall", + "gender": "female", + "age": 52, + "address": { + "state": "Connecticut", + "city": "Lowell" + } + }, + { + "id": 4468, + "name": "Roberson Cleveland", + "gender": "male", + "age": 63, + "address": { + "state": "New Hampshire", + "city": "Efland" + } + }, + { + "id": 4469, + "name": "Ramirez Waters", + "gender": "male", + "age": 20, + "address": { + "state": "Tennessee", + "city": "Eagletown" + } + }, + { + "id": 4470, + "name": "Foreman Ruiz", + "gender": "male", + "age": 26, + "address": { + "state": "Kentucky", + "city": "Garnet" + } + }, + { + "id": 4471, + "name": "Hartman Harvey", + "gender": "male", + "age": 56, + "address": { + "state": "Wyoming", + "city": "Helen" + } + }, + { + "id": 4472, + "name": "Jeri Acosta", + "gender": "female", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Sunbury" + } + }, + { + "id": 4473, + "name": "Erika Decker", + "gender": "female", + "age": 52, + "address": { + "state": "North Dakota", + "city": "Dixie" + } + }, + { + "id": 4474, + "name": "Petty Morgan", + "gender": "male", + "age": 45, + "address": { + "state": "Arizona", + "city": "Lorraine" + } + }, + { + "id": 4475, + "name": "Hurley Mckee", + "gender": "male", + "age": 46, + "address": { + "state": "South Dakota", + "city": "Celeryville" + } + }, + { + "id": 4476, + "name": "Gabrielle Woodward", + "gender": "female", + "age": 48, + "address": { + "state": "North Carolina", + "city": "Edinburg" + } + }, + { + "id": 4477, + "name": "Lenora Gallegos", + "gender": "female", + "age": 64, + "address": { + "state": "New York", + "city": "Belva" + } + }, + { + "id": 4478, + "name": "Pitts Kelley", + "gender": "male", + "age": 76, + "address": { + "state": "Nevada", + "city": "Hollins" + } + }, + { + "id": 4479, + "name": "Mclean Warner", + "gender": "male", + "age": 42, + "address": { + "state": "Colorado", + "city": "Zeba" + } + }, + { + "id": 4480, + "name": "Brenda Mccoy", + "gender": "female", + "age": 46, + "address": { + "state": "Missouri", + "city": "Benson" + } + }, + { + "id": 4481, + "name": "Carrie Carey", + "gender": "female", + "age": 20, + "address": { + "state": "Illinois", + "city": "Byrnedale" + } + }, + { + "id": 4482, + "name": "Valarie Diaz", + "gender": "female", + "age": 19, + "address": { + "state": "Idaho", + "city": "Selma" + } + }, + { + "id": 4483, + "name": "Juliana Lewis", + "gender": "female", + "age": 34, + "address": { + "state": "Utah", + "city": "Nipinnawasee" + } + }, + { + "id": 4484, + "name": "Mckay Welch", + "gender": "male", + "age": 70, + "address": { + "state": "Rhode Island", + "city": "Roberts" + } + }, + { + "id": 4485, + "name": "Carmella Reilly", + "gender": "female", + "age": 80, + "address": { + "state": "Kansas", + "city": "Oberlin" + } + }, + { + "id": 4486, + "name": "Briggs Hayden", + "gender": "male", + "age": 75, + "address": { + "state": "Florida", + "city": "Ellerslie" + } + }, + { + "id": 4487, + "name": "Bean Grimes", + "gender": "male", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Shaft" + } + }, + { + "id": 4488, + "name": "Daniels Hogan", + "gender": "male", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Rockhill" + } + }, + { + "id": 4489, + "name": "Kerri Wolf", + "gender": "female", + "age": 40, + "address": { + "state": "Delaware", + "city": "Brownlee" + } + }, + { + "id": 4490, + "name": "Dejesus Franco", + "gender": "male", + "age": 74, + "address": { + "state": "South Carolina", + "city": "Edmund" + } + }, + { + "id": 4491, + "name": "Middleton Morrison", + "gender": "male", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Driftwood" + } + }, + { + "id": 4492, + "name": "Sharon Gardner", + "gender": "female", + "age": 38, + "address": { + "state": "Maine", + "city": "Sidman" + } + }, + { + "id": 4493, + "name": "Lula Bonner", + "gender": "female", + "age": 66, + "address": { + "state": "Mississippi", + "city": "Homestead" + } + }, + { + "id": 4494, + "name": "Randall Mclean", + "gender": "male", + "age": 76, + "address": { + "state": "Oregon", + "city": "Mathews" + } + }, + { + "id": 4495, + "name": "Jewell Contreras", + "gender": "female", + "age": 58, + "address": { + "state": "Texas", + "city": "Cumberland" + } + }, + { + "id": 4496, + "name": "Francesca Cummings", + "gender": "female", + "age": 66, + "address": { + "state": "New Mexico", + "city": "Whitehaven" + } + }, + { + "id": 4497, + "name": "Susana Delaney", + "gender": "female", + "age": 20, + "address": { + "state": "Iowa", + "city": "Mapletown" + } + }, + { + "id": 4498, + "name": "Stephens Logan", + "gender": "male", + "age": 55, + "address": { + "state": "Alaska", + "city": "Sutton" + } + }, + { + "id": 4499, + "name": "Blair Pope", + "gender": "male", + "age": 24, + "address": { + "state": "Wisconsin", + "city": "Ogema" + } + }, + { + "id": 4500, + "name": "Wanda Ramsey", + "gender": "female", + "age": 81, + "address": { + "state": "Hawaii", + "city": "Darrtown" + } + }, + { + "id": 4501, + "name": "Murphy Robertson", + "gender": "male", + "age": 65, + "address": { + "state": "Virginia", + "city": "Matthews" + } + }, + { + "id": 4502, + "name": "Freeman Carver", + "gender": "male", + "age": 53, + "address": { + "state": "Indiana", + "city": "Nelson" + } + }, + { + "id": 4503, + "name": "Lang Gilbert", + "gender": "male", + "age": 78, + "address": { + "state": "Vermont", + "city": "Chamberino" + } + }, + { + "id": 4504, + "name": "Elvira Petersen", + "gender": "female", + "age": 17, + "address": { + "state": "Ohio", + "city": "Accoville" + } + }, + { + "id": 4505, + "name": "Mclaughlin Zimmerman", + "gender": "male", + "age": 57, + "address": { + "state": "Massachusetts", + "city": "Winfred" + } + }, + { + "id": 4506, + "name": "Lavonne Harper", + "gender": "female", + "age": 22, + "address": { + "state": "Arkansas", + "city": "Cashtown" + } + }, + { + "id": 4507, + "name": "Charlene Crosby", + "gender": "female", + "age": 51, + "address": { + "state": "Washington", + "city": "Turpin" + } + }, + { + "id": 4508, + "name": "Beard Oneal", + "gender": "male", + "age": 20, + "address": { + "state": "Connecticut", + "city": "Gouglersville" + } + }, + { + "id": 4509, + "name": "Stephanie Huffman", + "gender": "female", + "age": 17, + "address": { + "state": "Alaska", + "city": "Soudan" + } + }, + { + "id": 4510, + "name": "Baldwin Hanson", + "gender": "male", + "age": 35, + "address": { + "state": "Minnesota", + "city": "Blackgum" + } + }, + { + "id": 4511, + "name": "Parsons Nieves", + "gender": "male", + "age": 72, + "address": { + "state": "Missouri", + "city": "Murillo" + } + }, + { + "id": 4512, + "name": "Carissa Lindsay", + "gender": "female", + "age": 76, + "address": { + "state": "Wisconsin", + "city": "Detroit" + } + }, + { + "id": 4513, + "name": "Everett Blackwell", + "gender": "male", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Balm" + } + }, + { + "id": 4514, + "name": "Penelope Bullock", + "gender": "female", + "age": 64, + "address": { + "state": "Kansas", + "city": "Lumberton" + } + }, + { + "id": 4515, + "name": "Cheryl Montoya", + "gender": "female", + "age": 56, + "address": { + "state": "Iowa", + "city": "Bowmansville" + } + }, + { + "id": 4516, + "name": "Clarke Page", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Enlow" + } + }, + { + "id": 4517, + "name": "Camacho Henson", + "gender": "male", + "age": 27, + "address": { + "state": "Hawaii", + "city": "Beechmont" + } + }, + { + "id": 4518, + "name": "Vickie Boyer", + "gender": "female", + "age": 61, + "address": { + "state": "Nebraska", + "city": "Singer" + } + }, + { + "id": 4519, + "name": "Benita Henry", + "gender": "female", + "age": 75, + "address": { + "state": "West Virginia", + "city": "Worcester" + } + }, + { + "id": 4520, + "name": "Eugenia Dean", + "gender": "female", + "age": 65, + "address": { + "state": "Mississippi", + "city": "Morriston" + } + }, + { + "id": 4521, + "name": "Carole Maddox", + "gender": "female", + "age": 54, + "address": { + "state": "Illinois", + "city": "Ola" + } + }, + { + "id": 4522, + "name": "Weaver Walsh", + "gender": "male", + "age": 34, + "address": { + "state": "North Dakota", + "city": "Needmore" + } + }, + { + "id": 4523, + "name": "Mcclain Irwin", + "gender": "male", + "age": 62, + "address": { + "state": "Idaho", + "city": "Machias" + } + }, + { + "id": 4524, + "name": "Rhea Key", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Cedarville" + } + }, + { + "id": 4525, + "name": "Matthews Clements", + "gender": "male", + "age": 76, + "address": { + "state": "Michigan", + "city": "Macdona" + } + }, + { + "id": 4526, + "name": "Glenna Langley", + "gender": "female", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Cobbtown" + } + }, + { + "id": 4527, + "name": "Barbara Sweeney", + "gender": "female", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Reno" + } + }, + { + "id": 4528, + "name": "Robyn Mcclain", + "gender": "female", + "age": 20, + "address": { + "state": "Maine", + "city": "Wildwood" + } + }, + { + "id": 4529, + "name": "Hawkins Day", + "gender": "male", + "age": 63, + "address": { + "state": "New Mexico", + "city": "Santel" + } + }, + { + "id": 4530, + "name": "Small Raymond", + "gender": "male", + "age": 67, + "address": { + "state": "Utah", + "city": "Ruckersville" + } + }, + { + "id": 4531, + "name": "Faye Whitehead", + "gender": "female", + "age": 60, + "address": { + "state": "Rhode Island", + "city": "Fairview" + } + }, + { + "id": 4532, + "name": "Gray Humphrey", + "gender": "male", + "age": 55, + "address": { + "state": "New York", + "city": "Vandiver" + } + }, + { + "id": 4533, + "name": "Salazar Mccullough", + "gender": "male", + "age": 33, + "address": { + "state": "Kentucky", + "city": "Harrison" + } + }, + { + "id": 4534, + "name": "Elba Alford", + "gender": "female", + "age": 28, + "address": { + "state": "Wyoming", + "city": "Sabillasville" + } + }, + { + "id": 4535, + "name": "Mccullough Norman", + "gender": "male", + "age": 18, + "address": { + "state": "Virginia", + "city": "Ticonderoga" + } + }, + { + "id": 4536, + "name": "Annabelle Workman", + "gender": "female", + "age": 57, + "address": { + "state": "Montana", + "city": "Cumberland" + } + }, + { + "id": 4537, + "name": "Carey Santiago", + "gender": "female", + "age": 25, + "address": { + "state": "Ohio", + "city": "Allentown" + } + }, + { + "id": 4538, + "name": "Mullins Henderson", + "gender": "male", + "age": 73, + "address": { + "state": "Oregon", + "city": "Caron" + } + }, + { + "id": 4539, + "name": "Minnie Wilder", + "gender": "female", + "age": 73, + "address": { + "state": "California", + "city": "Bowie" + } + }, + { + "id": 4540, + "name": "Traci Weiss", + "gender": "female", + "age": 58, + "address": { + "state": "Colorado", + "city": "Dubois" + } + }, + { + "id": 4541, + "name": "Deann Clay", + "gender": "female", + "age": 38, + "address": { + "state": "Alabama", + "city": "Choctaw" + } + }, + { + "id": 4542, + "name": "Juanita Logan", + "gender": "female", + "age": 25, + "address": { + "state": "Vermont", + "city": "Bath" + } + }, + { + "id": 4543, + "name": "Joy Marquez", + "gender": "female", + "age": 71, + "address": { + "state": "Texas", + "city": "Belmont" + } + }, + { + "id": 4544, + "name": "Garrett Middleton", + "gender": "male", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Hackneyville" + } + }, + { + "id": 4545, + "name": "Gallegos Graves", + "gender": "male", + "age": 33, + "address": { + "state": "Georgia", + "city": "Barclay" + } + }, + { + "id": 4546, + "name": "Smith Conway", + "gender": "male", + "age": 62, + "address": { + "state": "Delaware", + "city": "Falconaire" + } + }, + { + "id": 4547, + "name": "Flores Bryan", + "gender": "male", + "age": 57, + "address": { + "state": "Nevada", + "city": "Klondike" + } + }, + { + "id": 4548, + "name": "Contreras Brock", + "gender": "male", + "age": 30, + "address": { + "state": "New Jersey", + "city": "Lewis" + } + }, + { + "id": 4549, + "name": "Baker Horne", + "gender": "male", + "age": 57, + "address": { + "state": "North Carolina", + "city": "Shaft" + } + }, + { + "id": 4550, + "name": "Bruce Sharpe", + "gender": "male", + "age": 54, + "address": { + "state": "Oklahoma", + "city": "Witmer" + } + }, + { + "id": 4551, + "name": "Abbott Blake", + "gender": "male", + "age": 76, + "address": { + "state": "Arizona", + "city": "Tivoli" + } + }, + { + "id": 4552, + "name": "Edna Cruz", + "gender": "female", + "age": 23, + "address": { + "state": "Maryland", + "city": "Elbert" + } + }, + { + "id": 4553, + "name": "Anne Walton", + "gender": "female", + "age": 69, + "address": { + "state": "New Hampshire", + "city": "Linwood" + } + }, + { + "id": 4554, + "name": "Corine Parrish", + "gender": "female", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Haring" + } + }, + { + "id": 4555, + "name": "Casey Moreno", + "gender": "female", + "age": 65, + "address": { + "state": "Florida", + "city": "Bonanza" + } + }, + { + "id": 4556, + "name": "Susana Davis", + "gender": "female", + "age": 50, + "address": { + "state": "South Dakota", + "city": "Vowinckel" + } + }, + { + "id": 4557, + "name": "Deanna Cantrell", + "gender": "female", + "age": 56, + "address": { + "state": "Virginia", + "city": "Celeryville" + } + }, + { + "id": 4558, + "name": "Millicent Sullivan", + "gender": "female", + "age": 18, + "address": { + "state": "Colorado", + "city": "Wattsville" + } + }, + { + "id": 4559, + "name": "Katy Duke", + "gender": "female", + "age": 31, + "address": { + "state": "Illinois", + "city": "Rosburg" + } + }, + { + "id": 4560, + "name": "Polly Cain", + "gender": "female", + "age": 56, + "address": { + "state": "New Jersey", + "city": "Kersey" + } + }, + { + "id": 4561, + "name": "Cristina Mejia", + "gender": "female", + "age": 32, + "address": { + "state": "Arizona", + "city": "Belvoir" + } + }, + { + "id": 4562, + "name": "Angelica Rivers", + "gender": "female", + "age": 47, + "address": { + "state": "Louisiana", + "city": "Bangor" + } + }, + { + "id": 4563, + "name": "Rene Joyner", + "gender": "female", + "age": 68, + "address": { + "state": "Oregon", + "city": "Bowie" + } + }, + { + "id": 4564, + "name": "Milagros Delaney", + "gender": "female", + "age": 19, + "address": { + "state": "Utah", + "city": "Shasta" + } + }, + { + "id": 4565, + "name": "Iva Walsh", + "gender": "female", + "age": 54, + "address": { + "state": "Iowa", + "city": "Nile" + } + }, + { + "id": 4566, + "name": "Wilma Roberson", + "gender": "female", + "age": 61, + "address": { + "state": "Washington", + "city": "Bethpage" + } + }, + { + "id": 4567, + "name": "Deborah Gray", + "gender": "female", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Bellamy" + } + }, + { + "id": 4568, + "name": "Adriana Sherman", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Williams" + } + }, + { + "id": 4569, + "name": "Tanner Vega", + "gender": "male", + "age": 72, + "address": { + "state": "Rhode Island", + "city": "Manchester" + } + }, + { + "id": 4570, + "name": "Sonja Wilder", + "gender": "female", + "age": 35, + "address": { + "state": "Arkansas", + "city": "Clarence" + } + }, + { + "id": 4571, + "name": "Julia Howell", + "gender": "female", + "age": 37, + "address": { + "state": "Idaho", + "city": "Springdale" + } + }, + { + "id": 4572, + "name": "Bobbi Ewing", + "gender": "female", + "age": 80, + "address": { + "state": "Alaska", + "city": "Manila" + } + }, + { + "id": 4573, + "name": "Conway Wade", + "gender": "male", + "age": 36, + "address": { + "state": "Nebraska", + "city": "Keyport" + } + }, + { + "id": 4574, + "name": "Durham Whitehead", + "gender": "male", + "age": 78, + "address": { + "state": "South Carolina", + "city": "Linganore" + } + }, + { + "id": 4575, + "name": "Karen Olson", + "gender": "female", + "age": 73, + "address": { + "state": "Kansas", + "city": "Zarephath" + } + }, + { + "id": 4576, + "name": "Reese Maddox", + "gender": "male", + "age": 52, + "address": { + "state": "Mississippi", + "city": "Bridgetown" + } + }, + { + "id": 4577, + "name": "Autumn Lee", + "gender": "female", + "age": 69, + "address": { + "state": "Maryland", + "city": "Websterville" + } + }, + { + "id": 4578, + "name": "Haney Moore", + "gender": "male", + "age": 58, + "address": { + "state": "Missouri", + "city": "Calpine" + } + }, + { + "id": 4579, + "name": "Annie Doyle", + "gender": "female", + "age": 25, + "address": { + "state": "Florida", + "city": "Neibert" + } + }, + { + "id": 4580, + "name": "Ladonna Irwin", + "gender": "female", + "age": 22, + "address": { + "state": "Massachusetts", + "city": "Hanover" + } + }, + { + "id": 4581, + "name": "Hess Vasquez", + "gender": "male", + "age": 70, + "address": { + "state": "Tennessee", + "city": "Cade" + } + }, + { + "id": 4582, + "name": "Lowe Dotson", + "gender": "male", + "age": 46, + "address": { + "state": "New York", + "city": "Yogaville" + } + }, + { + "id": 4583, + "name": "Jolene Rosa", + "gender": "female", + "age": 66, + "address": { + "state": "Connecticut", + "city": "Escondida" + } + }, + { + "id": 4584, + "name": "Lois Buck", + "gender": "female", + "age": 45, + "address": { + "state": "North Dakota", + "city": "Taft" + } + }, + { + "id": 4585, + "name": "Mcmahon William", + "gender": "male", + "age": 80, + "address": { + "state": "West Virginia", + "city": "Abrams" + } + }, + { + "id": 4586, + "name": "Hardin Spencer", + "gender": "male", + "age": 25, + "address": { + "state": "Wisconsin", + "city": "Crown" + } + }, + { + "id": 4587, + "name": "Ursula Hyde", + "gender": "female", + "age": 35, + "address": { + "state": "North Carolina", + "city": "Maplewood" + } + }, + { + "id": 4588, + "name": "Rivers Merritt", + "gender": "male", + "age": 60, + "address": { + "state": "Nevada", + "city": "Allensworth" + } + }, + { + "id": 4589, + "name": "Kathleen Kaufman", + "gender": "female", + "age": 23, + "address": { + "state": "Georgia", + "city": "Saticoy" + } + }, + { + "id": 4590, + "name": "Jamie Tillman", + "gender": "female", + "age": 81, + "address": { + "state": "New Mexico", + "city": "Chumuckla" + } + }, + { + "id": 4591, + "name": "Holland Hogan", + "gender": "male", + "age": 77, + "address": { + "state": "Maine", + "city": "Darlington" + } + }, + { + "id": 4592, + "name": "Misty Dillard", + "gender": "female", + "age": 42, + "address": { + "state": "Delaware", + "city": "Richmond" + } + }, + { + "id": 4593, + "name": "Debra Savage", + "gender": "female", + "age": 60, + "address": { + "state": "Montana", + "city": "Drummond" + } + }, + { + "id": 4594, + "name": "Olson Perez", + "gender": "male", + "age": 32, + "address": { + "state": "Kentucky", + "city": "Machias" + } + }, + { + "id": 4595, + "name": "Rowland Burton", + "gender": "male", + "age": 17, + "address": { + "state": "California", + "city": "Emison" + } + }, + { + "id": 4596, + "name": "Kayla Hoffman", + "gender": "female", + "age": 57, + "address": { + "state": "Texas", + "city": "Rosine" + } + }, + { + "id": 4597, + "name": "Latasha Howe", + "gender": "female", + "age": 76, + "address": { + "state": "Ohio", + "city": "Eagleville" + } + }, + { + "id": 4598, + "name": "Callahan Barnett", + "gender": "male", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Rockhill" + } + }, + { + "id": 4599, + "name": "Lesley Manning", + "gender": "female", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Omar" + } + }, + { + "id": 4600, + "name": "Krista Snow", + "gender": "female", + "age": 59, + "address": { + "state": "Alabama", + "city": "Homeland" + } + }, + { + "id": 4601, + "name": "Agnes West", + "gender": "female", + "age": 24, + "address": { + "state": "Indiana", + "city": "Lawrence" + } + }, + { + "id": 4602, + "name": "Holder Blackwell", + "gender": "male", + "age": 58, + "address": { + "state": "Michigan", + "city": "Sedley" + } + }, + { + "id": 4603, + "name": "Darlene Camacho", + "gender": "female", + "age": 73, + "address": { + "state": "New Hampshire", + "city": "Kohatk" + } + }, + { + "id": 4604, + "name": "Leticia Booth", + "gender": "female", + "age": 28, + "address": { + "state": "Vermont", + "city": "Orin" + } + }, + { + "id": 4605, + "name": "Travis Michael", + "gender": "male", + "age": 26, + "address": { + "state": "Wyoming", + "city": "Grimsley" + } + }, + { + "id": 4606, + "name": "Brewer Cochran", + "gender": "male", + "age": 67, + "address": { + "state": "Minnesota", + "city": "Sylvanite" + } + }, + { + "id": 4607, + "name": "Tami Hurst", + "gender": "female", + "age": 65, + "address": { + "state": "Arkansas", + "city": "Marshall" + } + }, + { + "id": 4608, + "name": "Kathy Holman", + "gender": "female", + "age": 27, + "address": { + "state": "New Jersey", + "city": "Ribera" + } + }, + { + "id": 4609, + "name": "Cherie Short", + "gender": "female", + "age": 64, + "address": { + "state": "Texas", + "city": "Walker" + } + }, + { + "id": 4610, + "name": "Kent Kennedy", + "gender": "male", + "age": 32, + "address": { + "state": "Indiana", + "city": "Bethpage" + } + }, + { + "id": 4611, + "name": "Jackie Summers", + "gender": "female", + "age": 65, + "address": { + "state": "Kentucky", + "city": "Rosewood" + } + }, + { + "id": 4612, + "name": "Trujillo Mcconnell", + "gender": "male", + "age": 35, + "address": { + "state": "Oregon", + "city": "Bedias" + } + }, + { + "id": 4613, + "name": "Terrell Duncan", + "gender": "male", + "age": 36, + "address": { + "state": "Alaska", + "city": "Rushford" + } + }, + { + "id": 4614, + "name": "Riggs White", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Allamuchy" + } + }, + { + "id": 4615, + "name": "Caldwell Casey", + "gender": "male", + "age": 72, + "address": { + "state": "Connecticut", + "city": "Jacksonwald" + } + }, + { + "id": 4616, + "name": "Jean Pugh", + "gender": "female", + "age": 75, + "address": { + "state": "North Dakota", + "city": "Mathews" + } + }, + { + "id": 4617, + "name": "Baldwin Holt", + "gender": "male", + "age": 39, + "address": { + "state": "Nebraska", + "city": "Joppa" + } + }, + { + "id": 4618, + "name": "English Vance", + "gender": "male", + "age": 36, + "address": { + "state": "Washington", + "city": "Mappsville" + } + }, + { + "id": 4619, + "name": "Maryanne Stout", + "gender": "female", + "age": 72, + "address": { + "state": "Maryland", + "city": "Richford" + } + }, + { + "id": 4620, + "name": "Whitehead Smith", + "gender": "male", + "age": 67, + "address": { + "state": "Pennsylvania", + "city": "Worcester" + } + }, + { + "id": 4621, + "name": "Fleming Nunez", + "gender": "male", + "age": 46, + "address": { + "state": "Louisiana", + "city": "Iberia" + } + }, + { + "id": 4622, + "name": "Sherri Simon", + "gender": "female", + "age": 61, + "address": { + "state": "Maine", + "city": "Evergreen" + } + }, + { + "id": 4623, + "name": "Smith Glass", + "gender": "male", + "age": 25, + "address": { + "state": "Rhode Island", + "city": "Ernstville" + } + }, + { + "id": 4624, + "name": "Mcintyre Zamora", + "gender": "male", + "age": 25, + "address": { + "state": "Vermont", + "city": "Mulberry" + } + }, + { + "id": 4625, + "name": "Spencer Patton", + "gender": "male", + "age": 26, + "address": { + "state": "Hawaii", + "city": "Kilbourne" + } + }, + { + "id": 4626, + "name": "Snider Banks", + "gender": "male", + "age": 56, + "address": { + "state": "South Carolina", + "city": "Blanford" + } + }, + { + "id": 4627, + "name": "Sophia Cannon", + "gender": "female", + "age": 80, + "address": { + "state": "Georgia", + "city": "Berwind" + } + }, + { + "id": 4628, + "name": "Brandie Mcdaniel", + "gender": "female", + "age": 76, + "address": { + "state": "Illinois", + "city": "Innsbrook" + } + }, + { + "id": 4629, + "name": "Nielsen Vazquez", + "gender": "male", + "age": 73, + "address": { + "state": "Oklahoma", + "city": "Durham" + } + }, + { + "id": 4630, + "name": "Rosalie Rowe", + "gender": "female", + "age": 24, + "address": { + "state": "Nevada", + "city": "Deltaville" + } + }, + { + "id": 4631, + "name": "Emily Santos", + "gender": "female", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Teasdale" + } + }, + { + "id": 4632, + "name": "Reva Davenport", + "gender": "female", + "age": 64, + "address": { + "state": "Alabama", + "city": "Williamson" + } + }, + { + "id": 4633, + "name": "Paula Lester", + "gender": "female", + "age": 56, + "address": { + "state": "Montana", + "city": "Bagtown" + } + }, + { + "id": 4634, + "name": "Margaret Bradford", + "gender": "female", + "age": 61, + "address": { + "state": "Tennessee", + "city": "Northridge" + } + }, + { + "id": 4635, + "name": "Rodriquez Hood", + "gender": "male", + "age": 47, + "address": { + "state": "Massachusetts", + "city": "Cleary" + } + }, + { + "id": 4636, + "name": "Gentry Mccall", + "gender": "male", + "age": 70, + "address": { + "state": "Kansas", + "city": "Fairlee" + } + }, + { + "id": 4637, + "name": "Calderon Mercer", + "gender": "male", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Forestburg" + } + }, + { + "id": 4638, + "name": "Martin Brock", + "gender": "male", + "age": 42, + "address": { + "state": "Colorado", + "city": "National" + } + }, + { + "id": 4639, + "name": "Kelsey Bush", + "gender": "female", + "age": 18, + "address": { + "state": "Florida", + "city": "Wadsworth" + } + }, + { + "id": 4640, + "name": "Castro Myers", + "gender": "male", + "age": 35, + "address": { + "state": "Delaware", + "city": "Elwood" + } + }, + { + "id": 4641, + "name": "Amie Colon", + "gender": "female", + "age": 25, + "address": { + "state": "South Dakota", + "city": "Vandiver" + } + }, + { + "id": 4642, + "name": "Nina Burch", + "gender": "female", + "age": 43, + "address": { + "state": "Mississippi", + "city": "Dundee" + } + }, + { + "id": 4643, + "name": "Cecile Ball", + "gender": "female", + "age": 74, + "address": { + "state": "Virginia", + "city": "Valmy" + } + }, + { + "id": 4644, + "name": "Melba Vincent", + "gender": "female", + "age": 46, + "address": { + "state": "Wisconsin", + "city": "Clarence" + } + }, + { + "id": 4645, + "name": "Pratt Cameron", + "gender": "male", + "age": 59, + "address": { + "state": "Utah", + "city": "Westphalia" + } + }, + { + "id": 4646, + "name": "Hays Wood", + "gender": "male", + "age": 51, + "address": { + "state": "Idaho", + "city": "Bowden" + } + }, + { + "id": 4647, + "name": "Callie Justice", + "gender": "female", + "age": 35, + "address": { + "state": "New Hampshire", + "city": "Linwood" + } + }, + { + "id": 4648, + "name": "Estes Mayer", + "gender": "male", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Navarre" + } + }, + { + "id": 4649, + "name": "Justice Barlow", + "gender": "male", + "age": 34, + "address": { + "state": "Michigan", + "city": "Chical" + } + }, + { + "id": 4650, + "name": "Solis Savage", + "gender": "male", + "age": 69, + "address": { + "state": "Ohio", + "city": "Caledonia" + } + }, + { + "id": 4651, + "name": "Bell Austin", + "gender": "male", + "age": 53, + "address": { + "state": "Missouri", + "city": "Crumpler" + } + }, + { + "id": 4652, + "name": "Sheree Foley", + "gender": "female", + "age": 25, + "address": { + "state": "New York", + "city": "Gouglersville" + } + }, + { + "id": 4653, + "name": "Curtis Conway", + "gender": "male", + "age": 79, + "address": { + "state": "Arizona", + "city": "Nogal" + } + }, + { + "id": 4654, + "name": "Nunez Solis", + "gender": "male", + "age": 62, + "address": { + "state": "Iowa", + "city": "Grayhawk" + } + }, + { + "id": 4655, + "name": "Jewell Huff", + "gender": "female", + "age": 34, + "address": { + "state": "Indiana", + "city": "Avalon" + } + }, + { + "id": 4656, + "name": "Velasquez Simmons", + "gender": "male", + "age": 46, + "address": { + "state": "Delaware", + "city": "Stewartville" + } + }, + { + "id": 4657, + "name": "Lou Bullock", + "gender": "female", + "age": 23, + "address": { + "state": "Michigan", + "city": "Vivian" + } + }, + { + "id": 4658, + "name": "Mcclain Bridges", + "gender": "male", + "age": 21, + "address": { + "state": "Washington", + "city": "Terlingua" + } + }, + { + "id": 4659, + "name": "Louise Barrera", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Brandywine" + } + }, + { + "id": 4660, + "name": "Mendez Zimmerman", + "gender": "male", + "age": 40, + "address": { + "state": "South Carolina", + "city": "Belgreen" + } + }, + { + "id": 4661, + "name": "Snider Ramos", + "gender": "male", + "age": 39, + "address": { + "state": "Missouri", + "city": "Warsaw" + } + }, + { + "id": 4662, + "name": "Levy Carpenter", + "gender": "male", + "age": 35, + "address": { + "state": "Florida", + "city": "Woodlands" + } + }, + { + "id": 4663, + "name": "Francisca Ayala", + "gender": "female", + "age": 73, + "address": { + "state": "Colorado", + "city": "Leming" + } + }, + { + "id": 4664, + "name": "Norman Santos", + "gender": "male", + "age": 78, + "address": { + "state": "Maryland", + "city": "Leroy" + } + }, + { + "id": 4665, + "name": "Lakeisha Reid", + "gender": "female", + "age": 32, + "address": { + "state": "Alaska", + "city": "Nile" + } + }, + { + "id": 4666, + "name": "Stella Kinney", + "gender": "female", + "age": 74, + "address": { + "state": "Minnesota", + "city": "Martinez" + } + }, + { + "id": 4667, + "name": "Ernestine Farmer", + "gender": "female", + "age": 21, + "address": { + "state": "Connecticut", + "city": "Gibbsville" + } + }, + { + "id": 4668, + "name": "Maddox Mann", + "gender": "male", + "age": 57, + "address": { + "state": "Louisiana", + "city": "Fairforest" + } + }, + { + "id": 4669, + "name": "Joyce Guzman", + "gender": "male", + "age": 23, + "address": { + "state": "Pennsylvania", + "city": "Harleigh" + } + }, + { + "id": 4670, + "name": "Adriana May", + "gender": "female", + "age": 41, + "address": { + "state": "Kentucky", + "city": "Mayfair" + } + }, + { + "id": 4671, + "name": "Bradford Morrison", + "gender": "male", + "age": 44, + "address": { + "state": "Montana", + "city": "Marienthal" + } + }, + { + "id": 4672, + "name": "Obrien Harrison", + "gender": "male", + "age": 80, + "address": { + "state": "New Mexico", + "city": "Nicut" + } + }, + { + "id": 4673, + "name": "Kate Navarro", + "gender": "female", + "age": 18, + "address": { + "state": "Nevada", + "city": "Titanic" + } + }, + { + "id": 4674, + "name": "Estela Barber", + "gender": "female", + "age": 69, + "address": { + "state": "Virginia", + "city": "Caberfae" + } + }, + { + "id": 4675, + "name": "Newton Gay", + "gender": "male", + "age": 62, + "address": { + "state": "New York", + "city": "Bowie" + } + }, + { + "id": 4676, + "name": "Parker Boyer", + "gender": "male", + "age": 67, + "address": { + "state": "Iowa", + "city": "Savage" + } + }, + { + "id": 4677, + "name": "Joyce Chambers", + "gender": "female", + "age": 72, + "address": { + "state": "New Jersey", + "city": "Springhill" + } + }, + { + "id": 4678, + "name": "Jimenez Lynn", + "gender": "male", + "age": 60, + "address": { + "state": "California", + "city": "Saticoy" + } + }, + { + "id": 4679, + "name": "Meagan Morris", + "gender": "female", + "age": 37, + "address": { + "state": "Wyoming", + "city": "Nadine" + } + }, + { + "id": 4680, + "name": "Jill Farrell", + "gender": "female", + "age": 39, + "address": { + "state": "Oregon", + "city": "Silkworth" + } + }, + { + "id": 4681, + "name": "Emma Shelton", + "gender": "female", + "age": 61, + "address": { + "state": "Mississippi", + "city": "Lafferty" + } + }, + { + "id": 4682, + "name": "Robert Marquez", + "gender": "female", + "age": 73, + "address": { + "state": "Oklahoma", + "city": "Hasty" + } + }, + { + "id": 4683, + "name": "Myrna Conley", + "gender": "female", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Bedias" + } + }, + { + "id": 4684, + "name": "Hensley Rivers", + "gender": "male", + "age": 68, + "address": { + "state": "Alabama", + "city": "Savannah" + } + }, + { + "id": 4685, + "name": "Miranda Hardin", + "gender": "male", + "age": 59, + "address": { + "state": "North Dakota", + "city": "Salvo" + } + }, + { + "id": 4686, + "name": "Berger Bishop", + "gender": "male", + "age": 67, + "address": { + "state": "Hawaii", + "city": "Weeksville" + } + }, + { + "id": 4687, + "name": "Dejesus Mckee", + "gender": "male", + "age": 23, + "address": { + "state": "North Carolina", + "city": "Venice" + } + }, + { + "id": 4688, + "name": "Corina Garcia", + "gender": "female", + "age": 75, + "address": { + "state": "Texas", + "city": "Makena" + } + }, + { + "id": 4689, + "name": "Florine Whitney", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Epworth" + } + }, + { + "id": 4690, + "name": "Travis Olsen", + "gender": "male", + "age": 60, + "address": { + "state": "Wisconsin", + "city": "Witmer" + } + }, + { + "id": 4691, + "name": "Toni Downs", + "gender": "female", + "age": 66, + "address": { + "state": "Ohio", + "city": "Sparkill" + } + }, + { + "id": 4692, + "name": "Liliana Price", + "gender": "female", + "age": 52, + "address": { + "state": "Kansas", + "city": "Chalfant" + } + }, + { + "id": 4693, + "name": "Peggy Bowers", + "gender": "female", + "age": 26, + "address": { + "state": "Rhode Island", + "city": "Blackgum" + } + }, + { + "id": 4694, + "name": "Ayala Peters", + "gender": "male", + "age": 56, + "address": { + "state": "Utah", + "city": "Taycheedah" + } + }, + { + "id": 4695, + "name": "Cohen Johnson", + "gender": "male", + "age": 46, + "address": { + "state": "Nebraska", + "city": "Chical" + } + }, + { + "id": 4696, + "name": "Shana Lambert", + "gender": "female", + "age": 29, + "address": { + "state": "Idaho", + "city": "Lacomb" + } + }, + { + "id": 4697, + "name": "Nadia Rollins", + "gender": "female", + "age": 82, + "address": { + "state": "New Hampshire", + "city": "Adamstown" + } + }, + { + "id": 4698, + "name": "Jeannine Brady", + "gender": "female", + "age": 78, + "address": { + "state": "South Dakota", + "city": "Cleary" + } + }, + { + "id": 4699, + "name": "Alison Skinner", + "gender": "female", + "age": 78, + "address": { + "state": "Vermont", + "city": "Idamay" + } + }, + { + "id": 4700, + "name": "Belinda Meyers", + "gender": "female", + "age": 61, + "address": { + "state": "Maine", + "city": "Marion" + } + }, + { + "id": 4701, + "name": "Hartman William", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Swartzville" + } + }, + { + "id": 4702, + "name": "Viola Marks", + "gender": "female", + "age": 21, + "address": { + "state": "Illinois", + "city": "Floriston" + } + }, + { + "id": 4703, + "name": "Lidia Chaney", + "gender": "female", + "age": 27, + "address": { + "state": "West Virginia", + "city": "Wadsworth" + } + }, + { + "id": 4704, + "name": "Erma Campos", + "gender": "female", + "age": 46, + "address": { + "state": "Kansas", + "city": "Gouglersville" + } + }, + { + "id": 4705, + "name": "Penny Martin", + "gender": "female", + "age": 27, + "address": { + "state": "Michigan", + "city": "Harrison" + } + }, + { + "id": 4706, + "name": "Shields Tate", + "gender": "male", + "age": 64, + "address": { + "state": "Tennessee", + "city": "Northridge" + } + }, + { + "id": 4707, + "name": "Maude Willis", + "gender": "female", + "age": 43, + "address": { + "state": "New Hampshire", + "city": "Wyoming" + } + }, + { + "id": 4708, + "name": "Iva Hoffman", + "gender": "female", + "age": 70, + "address": { + "state": "Delaware", + "city": "Bellamy" + } + }, + { + "id": 4709, + "name": "Riddle Carter", + "gender": "male", + "age": 35, + "address": { + "state": "Montana", + "city": "Noblestown" + } + }, + { + "id": 4710, + "name": "Kenya Hale", + "gender": "female", + "age": 50, + "address": { + "state": "Ohio", + "city": "Warren" + } + }, + { + "id": 4711, + "name": "Doris Stark", + "gender": "female", + "age": 43, + "address": { + "state": "Idaho", + "city": "Nipinnawasee" + } + }, + { + "id": 4712, + "name": "Griffith Webb", + "gender": "male", + "age": 33, + "address": { + "state": "Nebraska", + "city": "Trona" + } + }, + { + "id": 4713, + "name": "Christie Hood", + "gender": "female", + "age": 65, + "address": { + "state": "Oklahoma", + "city": "Accoville" + } + }, + { + "id": 4714, + "name": "Eula Carpenter", + "gender": "female", + "age": 33, + "address": { + "state": "Mississippi", + "city": "Kylertown" + } + }, + { + "id": 4715, + "name": "Odom Weber", + "gender": "male", + "age": 38, + "address": { + "state": "New Jersey", + "city": "Leland" + } + }, + { + "id": 4716, + "name": "Townsend Pacheco", + "gender": "male", + "age": 42, + "address": { + "state": "Wyoming", + "city": "Tecolotito" + } + }, + { + "id": 4717, + "name": "Meyers Ratliff", + "gender": "male", + "age": 34, + "address": { + "state": "Texas", + "city": "Inkerman" + } + }, + { + "id": 4718, + "name": "Reba Hickman", + "gender": "female", + "age": 43, + "address": { + "state": "Alaska", + "city": "Clarktown" + } + }, + { + "id": 4719, + "name": "Knapp Bradley", + "gender": "male", + "age": 25, + "address": { + "state": "Iowa", + "city": "Ona" + } + }, + { + "id": 4720, + "name": "Vaughn Bowen", + "gender": "male", + "age": 50, + "address": { + "state": "Hawaii", + "city": "Waterford" + } + }, + { + "id": 4721, + "name": "Faith Bruce", + "gender": "female", + "age": 76, + "address": { + "state": "Florida", + "city": "Orin" + } + }, + { + "id": 4722, + "name": "Carmella King", + "gender": "female", + "age": 45, + "address": { + "state": "Alabama", + "city": "Nogal" + } + }, + { + "id": 4723, + "name": "Estrada Duran", + "gender": "male", + "age": 68, + "address": { + "state": "Missouri", + "city": "Somerset" + } + }, + { + "id": 4724, + "name": "Concepcion Suarez", + "gender": "female", + "age": 27, + "address": { + "state": "North Dakota", + "city": "Elliston" + } + }, + { + "id": 4725, + "name": "Reese Reynolds", + "gender": "male", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Mappsville" + } + }, + { + "id": 4726, + "name": "Lowery Tanner", + "gender": "male", + "age": 65, + "address": { + "state": "Rhode Island", + "city": "Beaverdale" + } + }, + { + "id": 4727, + "name": "Catherine Potts", + "gender": "female", + "age": 66, + "address": { + "state": "Arkansas", + "city": "Alafaya" + } + }, + { + "id": 4728, + "name": "Natasha Decker", + "gender": "female", + "age": 31, + "address": { + "state": "Washington", + "city": "Bancroft" + } + }, + { + "id": 4729, + "name": "Cynthia Mccray", + "gender": "female", + "age": 35, + "address": { + "state": "Vermont", + "city": "Hartsville/Hartley" + } + }, + { + "id": 4730, + "name": "Nellie Cummings", + "gender": "female", + "age": 55, + "address": { + "state": "West Virginia", + "city": "Ticonderoga" + } + }, + { + "id": 4731, + "name": "Brown Singleton", + "gender": "male", + "age": 19, + "address": { + "state": "Maine", + "city": "Turah" + } + }, + { + "id": 4732, + "name": "Selma Heath", + "gender": "female", + "age": 37, + "address": { + "state": "Colorado", + "city": "Utting" + } + }, + { + "id": 4733, + "name": "Bullock Joyce", + "gender": "male", + "age": 18, + "address": { + "state": "South Dakota", + "city": "Wakarusa" + } + }, + { + "id": 4734, + "name": "Marcy Williams", + "gender": "female", + "age": 22, + "address": { + "state": "Indiana", + "city": "Tyro" + } + }, + { + "id": 4735, + "name": "Swanson Callahan", + "gender": "male", + "age": 39, + "address": { + "state": "Pennsylvania", + "city": "Falconaire" + } + }, + { + "id": 4736, + "name": "Alexandria Valentine", + "gender": "female", + "age": 71, + "address": { + "state": "Virginia", + "city": "Olney" + } + }, + { + "id": 4737, + "name": "Higgins Murray", + "gender": "male", + "age": 67, + "address": { + "state": "Wisconsin", + "city": "Cobbtown" + } + }, + { + "id": 4738, + "name": "Kaufman Contreras", + "gender": "male", + "age": 55, + "address": { + "state": "Louisiana", + "city": "Derwood" + } + }, + { + "id": 4739, + "name": "Jessica Knight", + "gender": "female", + "age": 38, + "address": { + "state": "South Carolina", + "city": "Chautauqua" + } + }, + { + "id": 4740, + "name": "Sophia Ortega", + "gender": "female", + "age": 30, + "address": { + "state": "Arizona", + "city": "Ribera" + } + }, + { + "id": 4741, + "name": "Rivers Beach", + "gender": "male", + "age": 62, + "address": { + "state": "Nevada", + "city": "Brenton" + } + }, + { + "id": 4742, + "name": "Callahan Stone", + "gender": "male", + "age": 57, + "address": { + "state": "Illinois", + "city": "Smock" + } + }, + { + "id": 4743, + "name": "Morgan Prince", + "gender": "female", + "age": 32, + "address": { + "state": "Minnesota", + "city": "Lawrence" + } + }, + { + "id": 4744, + "name": "Sharpe Sharpe", + "gender": "male", + "age": 20, + "address": { + "state": "Kentucky", + "city": "Warsaw" + } + }, + { + "id": 4745, + "name": "Aida Witt", + "gender": "female", + "age": 31, + "address": { + "state": "Georgia", + "city": "Advance" + } + }, + { + "id": 4746, + "name": "Tania Mcclure", + "gender": "female", + "age": 23, + "address": { + "state": "Massachusetts", + "city": "Tibbie" + } + }, + { + "id": 4747, + "name": "Rosalinda Rowland", + "gender": "female", + "age": 71, + "address": { + "state": "Utah", + "city": "Ola" + } + }, + { + "id": 4748, + "name": "Young Merrill", + "gender": "male", + "age": 17, + "address": { + "state": "North Carolina", + "city": "Marienthal" + } + }, + { + "id": 4749, + "name": "Celeste Maddox", + "gender": "female", + "age": 48, + "address": { + "state": "California", + "city": "Trucksville" + } + }, + { + "id": 4750, + "name": "Beth Acevedo", + "gender": "female", + "age": 32, + "address": { + "state": "Maryland", + "city": "Eagletown" + } + }, + { + "id": 4751, + "name": "Morrison Coffey", + "gender": "male", + "age": 33, + "address": { + "state": "Connecticut", + "city": "Harviell" + } + }, + { + "id": 4752, + "name": "Alisha Berger", + "gender": "female", + "age": 38, + "address": { + "state": "Oregon", + "city": "Bagtown" + } + }, + { + "id": 4753, + "name": "Lenore Snider", + "gender": "female", + "age": 55, + "address": { + "state": "Texas", + "city": "Wedgewood" + } + }, + { + "id": 4754, + "name": "Bernadine Bailey", + "gender": "female", + "age": 33, + "address": { + "state": "North Dakota", + "city": "Norwood" + } + }, + { + "id": 4755, + "name": "Whitney Pate", + "gender": "male", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Coral" + } + }, + { + "id": 4756, + "name": "Daisy Barry", + "gender": "female", + "age": 59, + "address": { + "state": "Indiana", + "city": "Allamuchy" + } + }, + { + "id": 4757, + "name": "Aileen Stafford", + "gender": "female", + "age": 57, + "address": { + "state": "New York", + "city": "Fredericktown" + } + }, + { + "id": 4758, + "name": "Teri Burns", + "gender": "female", + "age": 47, + "address": { + "state": "New Mexico", + "city": "Calverton" + } + }, + { + "id": 4759, + "name": "Jimenez Pacheco", + "gender": "male", + "age": 41, + "address": { + "state": "Montana", + "city": "Soudan" + } + }, + { + "id": 4760, + "name": "Mcgee Figueroa", + "gender": "male", + "age": 66, + "address": { + "state": "Kentucky", + "city": "Allentown" + } + }, + { + "id": 4761, + "name": "Tonia Savage", + "gender": "female", + "age": 40, + "address": { + "state": "Vermont", + "city": "Maybell" + } + }, + { + "id": 4762, + "name": "Forbes Bowen", + "gender": "male", + "age": 76, + "address": { + "state": "Missouri", + "city": "Clayville" + } + }, + { + "id": 4763, + "name": "Hardy Page", + "gender": "male", + "age": 43, + "address": { + "state": "South Dakota", + "city": "Hartsville/Hartley" + } + }, + { + "id": 4764, + "name": "Fulton Bishop", + "gender": "male", + "age": 68, + "address": { + "state": "Washington", + "city": "Bourg" + } + }, + { + "id": 4765, + "name": "John Delgado", + "gender": "female", + "age": 32, + "address": { + "state": "Ohio", + "city": "Dellview" + } + }, + { + "id": 4766, + "name": "Leah Erickson", + "gender": "female", + "age": 47, + "address": { + "state": "Maine", + "city": "Johnsonburg" + } + }, + { + "id": 4767, + "name": "Wilda Compton", + "gender": "female", + "age": 58, + "address": { + "state": "Arkansas", + "city": "Rivera" + } + }, + { + "id": 4768, + "name": "Watts Kirkland", + "gender": "male", + "age": 45, + "address": { + "state": "South Carolina", + "city": "Esmont" + } + }, + { + "id": 4769, + "name": "Mckay Boyd", + "gender": "male", + "age": 44, + "address": { + "state": "Georgia", + "city": "Winchester" + } + }, + { + "id": 4770, + "name": "Katherine Collier", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Hackneyville" + } + }, + { + "id": 4771, + "name": "Tania Shepard", + "gender": "female", + "age": 47, + "address": { + "state": "Alaska", + "city": "Kenwood" + } + }, + { + "id": 4772, + "name": "Saundra Powers", + "gender": "female", + "age": 17, + "address": { + "state": "Florida", + "city": "Wildwood" + } + }, + { + "id": 4773, + "name": "Briana Walters", + "gender": "female", + "age": 22, + "address": { + "state": "West Virginia", + "city": "Grazierville" + } + }, + { + "id": 4774, + "name": "Ramos Moore", + "gender": "male", + "age": 66, + "address": { + "state": "Louisiana", + "city": "Jenkinsville" + } + }, + { + "id": 4775, + "name": "Charity Slater", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Sylvanite" + } + }, + { + "id": 4776, + "name": "Marcie Mcguire", + "gender": "female", + "age": 27, + "address": { + "state": "Iowa", + "city": "Hoagland" + } + }, + { + "id": 4777, + "name": "Cote Lowery", + "gender": "male", + "age": 65, + "address": { + "state": "Michigan", + "city": "Whitewater" + } + }, + { + "id": 4778, + "name": "Savannah Merrill", + "gender": "female", + "age": 78, + "address": { + "state": "Illinois", + "city": "Springville" + } + }, + { + "id": 4779, + "name": "Darla Brown", + "gender": "female", + "age": 18, + "address": { + "state": "Rhode Island", + "city": "Fannett" + } + }, + { + "id": 4780, + "name": "Boyd Gamble", + "gender": "male", + "age": 67, + "address": { + "state": "Kansas", + "city": "Bowden" + } + }, + { + "id": 4781, + "name": "Pitts Marquez", + "gender": "male", + "age": 19, + "address": { + "state": "Wyoming", + "city": "Kohatk" + } + }, + { + "id": 4782, + "name": "Kristine Rodriguez", + "gender": "female", + "age": 63, + "address": { + "state": "Tennessee", + "city": "Urie" + } + }, + { + "id": 4783, + "name": "Mosley Best", + "gender": "male", + "age": 62, + "address": { + "state": "Idaho", + "city": "Brooktrails" + } + }, + { + "id": 4784, + "name": "Rocha Taylor", + "gender": "male", + "age": 53, + "address": { + "state": "Maryland", + "city": "Belvoir" + } + }, + { + "id": 4785, + "name": "Roslyn Deleon", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Sultana" + } + }, + { + "id": 4786, + "name": "Erna Fox", + "gender": "female", + "age": 45, + "address": { + "state": "Nevada", + "city": "Taycheedah" + } + }, + { + "id": 4787, + "name": "Mccoy Bryan", + "gender": "male", + "age": 58, + "address": { + "state": "New Jersey", + "city": "Robbins" + } + }, + { + "id": 4788, + "name": "Janie Michael", + "gender": "female", + "age": 48, + "address": { + "state": "Arizona", + "city": "Rockhill" + } + }, + { + "id": 4789, + "name": "Fitzpatrick Fry", + "gender": "male", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Accoville" + } + }, + { + "id": 4790, + "name": "Clayton Myers", + "gender": "male", + "age": 66, + "address": { + "state": "Utah", + "city": "Defiance" + } + }, + { + "id": 4791, + "name": "Leann Holland", + "gender": "female", + "age": 27, + "address": { + "state": "Oklahoma", + "city": "Caledonia" + } + }, + { + "id": 4792, + "name": "Angel Le", + "gender": "female", + "age": 31, + "address": { + "state": "North Carolina", + "city": "Vicksburg" + } + }, + { + "id": 4793, + "name": "Doyle Maddox", + "gender": "male", + "age": 64, + "address": { + "state": "Connecticut", + "city": "Lupton" + } + }, + { + "id": 4794, + "name": "Gail Tran", + "gender": "female", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Roland" + } + }, + { + "id": 4795, + "name": "Reba Riddle", + "gender": "female", + "age": 57, + "address": { + "state": "Colorado", + "city": "Coaldale" + } + }, + { + "id": 4796, + "name": "Lawson Knapp", + "gender": "male", + "age": 39, + "address": { + "state": "Hawaii", + "city": "Cobbtown" + } + }, + { + "id": 4797, + "name": "Araceli Fitzgerald", + "gender": "female", + "age": 80, + "address": { + "state": "Massachusetts", + "city": "Hendersonville" + } + }, + { + "id": 4798, + "name": "Dudley Matthews", + "gender": "male", + "age": 21, + "address": { + "state": "Mississippi", + "city": "Cade" + } + }, + { + "id": 4799, + "name": "Neal Brooks", + "gender": "male", + "age": 25, + "address": { + "state": "Oregon", + "city": "Warsaw" + } + }, + { + "id": 4800, + "name": "Taylor Brennan", + "gender": "female", + "age": 46, + "address": { + "state": "Virginia", + "city": "Sattley" + } + }, + { + "id": 4801, + "name": "Mcdowell William", + "gender": "male", + "age": 30, + "address": { + "state": "California", + "city": "Stonybrook" + } + }, + { + "id": 4802, + "name": "Love Gill", + "gender": "male", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Gasquet" + } + }, + { + "id": 4803, + "name": "Knowles Whitney", + "gender": "male", + "age": 28, + "address": { + "state": "Vermont", + "city": "Nord" + } + }, + { + "id": 4804, + "name": "Downs Copeland", + "gender": "male", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Hoagland" + } + }, + { + "id": 4805, + "name": "Maria Murray", + "gender": "female", + "age": 61, + "address": { + "state": "Iowa", + "city": "Sandston" + } + }, + { + "id": 4806, + "name": "Grant Simpson", + "gender": "male", + "age": 80, + "address": { + "state": "Connecticut", + "city": "Websterville" + } + }, + { + "id": 4807, + "name": "Robinson Stanley", + "gender": "male", + "age": 26, + "address": { + "state": "Hawaii", + "city": "Felt" + } + }, + { + "id": 4808, + "name": "Franks Hewitt", + "gender": "male", + "age": 56, + "address": { + "state": "Ohio", + "city": "Wauhillau" + } + }, + { + "id": 4809, + "name": "Schroeder Barrera", + "gender": "male", + "age": 23, + "address": { + "state": "California", + "city": "Aguila" + } + }, + { + "id": 4810, + "name": "Madden Fulton", + "gender": "male", + "age": 72, + "address": { + "state": "Utah", + "city": "Cade" + } + }, + { + "id": 4811, + "name": "Christensen Perry", + "gender": "male", + "age": 20, + "address": { + "state": "South Dakota", + "city": "Buxton" + } + }, + { + "id": 4812, + "name": "Mamie Stokes", + "gender": "female", + "age": 36, + "address": { + "state": "Tennessee", + "city": "Boykin" + } + }, + { + "id": 4813, + "name": "Whitney Henry", + "gender": "female", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Sunbury" + } + }, + { + "id": 4814, + "name": "Sallie Delgado", + "gender": "female", + "age": 42, + "address": { + "state": "Alaska", + "city": "Kraemer" + } + }, + { + "id": 4815, + "name": "Wilkins Mays", + "gender": "male", + "age": 53, + "address": { + "state": "Montana", + "city": "Tivoli" + } + }, + { + "id": 4816, + "name": "Holden Santana", + "gender": "male", + "age": 44, + "address": { + "state": "Indiana", + "city": "Hampstead" + } + }, + { + "id": 4817, + "name": "Valerie Rich", + "gender": "female", + "age": 48, + "address": { + "state": "Georgia", + "city": "Conway" + } + }, + { + "id": 4818, + "name": "Sawyer Espinoza", + "gender": "male", + "age": 59, + "address": { + "state": "Minnesota", + "city": "Roberts" + } + }, + { + "id": 4819, + "name": "Stacey House", + "gender": "female", + "age": 49, + "address": { + "state": "Colorado", + "city": "Elfrida" + } + }, + { + "id": 4820, + "name": "Betty Ayala", + "gender": "female", + "age": 57, + "address": { + "state": "Kansas", + "city": "Outlook" + } + }, + { + "id": 4821, + "name": "Jenny Morrison", + "gender": "female", + "age": 46, + "address": { + "state": "Louisiana", + "city": "Aberdeen" + } + }, + { + "id": 4822, + "name": "Sherman Adams", + "gender": "male", + "age": 52, + "address": { + "state": "North Dakota", + "city": "Munjor" + } + }, + { + "id": 4823, + "name": "Harvey Fry", + "gender": "male", + "age": 44, + "address": { + "state": "Idaho", + "city": "Columbus" + } + }, + { + "id": 4824, + "name": "Erickson Mcgowan", + "gender": "male", + "age": 54, + "address": { + "state": "Illinois", + "city": "Fostoria" + } + }, + { + "id": 4825, + "name": "Becker Knight", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Sanborn" + } + }, + { + "id": 4826, + "name": "Roach Trujillo", + "gender": "male", + "age": 71, + "address": { + "state": "Kentucky", + "city": "Gardners" + } + }, + { + "id": 4827, + "name": "Ellen Mitchell", + "gender": "female", + "age": 74, + "address": { + "state": "West Virginia", + "city": "Iola" + } + }, + { + "id": 4828, + "name": "Dominguez Baldwin", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Denio" + } + }, + { + "id": 4829, + "name": "Marci Lynch", + "gender": "female", + "age": 65, + "address": { + "state": "New Mexico", + "city": "Kylertown" + } + }, + { + "id": 4830, + "name": "Mayer Figueroa", + "gender": "male", + "age": 79, + "address": { + "state": "Nevada", + "city": "Temperanceville" + } + }, + { + "id": 4831, + "name": "Benita Ortega", + "gender": "female", + "age": 64, + "address": { + "state": "Rhode Island", + "city": "Whitewater" + } + }, + { + "id": 4832, + "name": "Craft Richards", + "gender": "male", + "age": 22, + "address": { + "state": "Wisconsin", + "city": "Lindisfarne" + } + }, + { + "id": 4833, + "name": "Jordan Glass", + "gender": "female", + "age": 69, + "address": { + "state": "New Jersey", + "city": "Elbert" + } + }, + { + "id": 4834, + "name": "Gillespie Bentley", + "gender": "male", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Weogufka" + } + }, + { + "id": 4835, + "name": "Underwood Lester", + "gender": "male", + "age": 63, + "address": { + "state": "Maine", + "city": "Nicut" + } + }, + { + "id": 4836, + "name": "Abby Shepherd", + "gender": "female", + "age": 56, + "address": { + "state": "Arizona", + "city": "Hamilton" + } + }, + { + "id": 4837, + "name": "Kari Smith", + "gender": "female", + "age": 49, + "address": { + "state": "Oregon", + "city": "Kohatk" + } + }, + { + "id": 4838, + "name": "Tate Mcguire", + "gender": "male", + "age": 63, + "address": { + "state": "Missouri", + "city": "Caledonia" + } + }, + { + "id": 4839, + "name": "Reese Miles", + "gender": "male", + "age": 49, + "address": { + "state": "Texas", + "city": "Needmore" + } + }, + { + "id": 4840, + "name": "Carter Mcconnell", + "gender": "male", + "age": 25, + "address": { + "state": "Delaware", + "city": "Otranto" + } + }, + { + "id": 4841, + "name": "Tania Sanchez", + "gender": "female", + "age": 24, + "address": { + "state": "Washington", + "city": "Devon" + } + }, + { + "id": 4842, + "name": "Gabriela Russo", + "gender": "female", + "age": 17, + "address": { + "state": "Arkansas", + "city": "Rockbridge" + } + }, + { + "id": 4843, + "name": "Marcie Campbell", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Kilbourne" + } + }, + { + "id": 4844, + "name": "Ila Schroeder", + "gender": "female", + "age": 78, + "address": { + "state": "Wyoming", + "city": "Logan" + } + }, + { + "id": 4845, + "name": "Donaldson Chase", + "gender": "male", + "age": 28, + "address": { + "state": "Virginia", + "city": "Witmer" + } + }, + { + "id": 4846, + "name": "Elaine Wright", + "gender": "female", + "age": 68, + "address": { + "state": "Florida", + "city": "Warren" + } + }, + { + "id": 4847, + "name": "Leah Macdonald", + "gender": "female", + "age": 47, + "address": { + "state": "Maryland", + "city": "Berlin" + } + }, + { + "id": 4848, + "name": "Colette Fowler", + "gender": "female", + "age": 82, + "address": { + "state": "Oklahoma", + "city": "Harrodsburg" + } + }, + { + "id": 4849, + "name": "Lowe Battle", + "gender": "male", + "age": 28, + "address": { + "state": "North Carolina", + "city": "Leyner" + } + }, + { + "id": 4850, + "name": "Elba Hyde", + "gender": "female", + "age": 78, + "address": { + "state": "New York", + "city": "Cotopaxi" + } + }, + { + "id": 4851, + "name": "Wendy Marks", + "gender": "female", + "age": 64, + "address": { + "state": "West Virginia", + "city": "Thomasville" + } + }, + { + "id": 4852, + "name": "Daugherty Hunt", + "gender": "male", + "age": 53, + "address": { + "state": "Massachusetts", + "city": "Dawn" + } + }, + { + "id": 4853, + "name": "Lina Baird", + "gender": "female", + "age": 67, + "address": { + "state": "Vermont", + "city": "Bancroft" + } + }, + { + "id": 4854, + "name": "Estela Miles", + "gender": "female", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Craig" + } + }, + { + "id": 4855, + "name": "Tillman Logan", + "gender": "male", + "age": 71, + "address": { + "state": "Michigan", + "city": "Tuskahoma" + } + }, + { + "id": 4856, + "name": "English Knight", + "gender": "male", + "age": 37, + "address": { + "state": "Louisiana", + "city": "Sutton" + } + }, + { + "id": 4857, + "name": "Robertson Dodson", + "gender": "male", + "age": 28, + "address": { + "state": "Montana", + "city": "Sims" + } + }, + { + "id": 4858, + "name": "Luz Douglas", + "gender": "female", + "age": 47, + "address": { + "state": "New Jersey", + "city": "Nord" + } + }, + { + "id": 4859, + "name": "Matthews Alvarez", + "gender": "male", + "age": 39, + "address": { + "state": "Rhode Island", + "city": "Mulino" + } + }, + { + "id": 4860, + "name": "Olive Rasmussen", + "gender": "female", + "age": 75, + "address": { + "state": "Virginia", + "city": "Longbranch" + } + }, + { + "id": 4861, + "name": "Mitzi Kirkland", + "gender": "female", + "age": 58, + "address": { + "state": "Delaware", + "city": "Dotsero" + } + }, + { + "id": 4862, + "name": "Meagan Garrett", + "gender": "female", + "age": 31, + "address": { + "state": "Maine", + "city": "Denio" + } + }, + { + "id": 4863, + "name": "Rowe Gray", + "gender": "male", + "age": 25, + "address": { + "state": "Tennessee", + "city": "Wright" + } + }, + { + "id": 4864, + "name": "Lynch Dale", + "gender": "male", + "age": 47, + "address": { + "state": "Mississippi", + "city": "Bison" + } + }, + { + "id": 4865, + "name": "Workman Owen", + "gender": "male", + "age": 64, + "address": { + "state": "Maryland", + "city": "Motley" + } + }, + { + "id": 4866, + "name": "Odessa Simon", + "gender": "female", + "age": 77, + "address": { + "state": "Washington", + "city": "Wyano" + } + }, + { + "id": 4867, + "name": "Yang Gould", + "gender": "male", + "age": 54, + "address": { + "state": "Nebraska", + "city": "Holcombe" + } + }, + { + "id": 4868, + "name": "Jane Hatfield", + "gender": "female", + "age": 30, + "address": { + "state": "New Hampshire", + "city": "Mahtowa" + } + }, + { + "id": 4869, + "name": "Peggy Fry", + "gender": "female", + "age": 19, + "address": { + "state": "Nevada", + "city": "Malo" + } + }, + { + "id": 4870, + "name": "Quinn Guerra", + "gender": "male", + "age": 48, + "address": { + "state": "Texas", + "city": "Kent" + } + }, + { + "id": 4871, + "name": "Guerrero Acosta", + "gender": "male", + "age": 33, + "address": { + "state": "Idaho", + "city": "Henrietta" + } + }, + { + "id": 4872, + "name": "Cervantes Mcfadden", + "gender": "male", + "age": 73, + "address": { + "state": "Illinois", + "city": "Springdale" + } + }, + { + "id": 4873, + "name": "Burch Hines", + "gender": "male", + "age": 22, + "address": { + "state": "Alabama", + "city": "Beaverdale" + } + }, + { + "id": 4874, + "name": "Elvia Lynn", + "gender": "female", + "age": 33, + "address": { + "state": "South Dakota", + "city": "Tibbie" + } + }, + { + "id": 4875, + "name": "Carolyn Holder", + "gender": "female", + "age": 79, + "address": { + "state": "Minnesota", + "city": "Blodgett" + } + }, + { + "id": 4876, + "name": "Kimberley Harrison", + "gender": "female", + "age": 41, + "address": { + "state": "Georgia", + "city": "Boonville" + } + }, + { + "id": 4877, + "name": "Vickie Reyes", + "gender": "female", + "age": 47, + "address": { + "state": "North Dakota", + "city": "Dixie" + } + }, + { + "id": 4878, + "name": "Keith Woods", + "gender": "male", + "age": 81, + "address": { + "state": "Oklahoma", + "city": "Orovada" + } + }, + { + "id": 4879, + "name": "Lara Stanley", + "gender": "male", + "age": 62, + "address": { + "state": "Alaska", + "city": "Saranap" + } + }, + { + "id": 4880, + "name": "Sadie Foster", + "gender": "female", + "age": 40, + "address": { + "state": "Arizona", + "city": "Forestburg" + } + }, + { + "id": 4881, + "name": "Richards Hewitt", + "gender": "male", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Grapeview" + } + }, + { + "id": 4882, + "name": "Nora Ochoa", + "gender": "female", + "age": 76, + "address": { + "state": "New York", + "city": "Dola" + } + }, + { + "id": 4883, + "name": "Viola Riggs", + "gender": "female", + "age": 20, + "address": { + "state": "Colorado", + "city": "Clarksburg" + } + }, + { + "id": 4884, + "name": "Anderson Cameron", + "gender": "male", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Norfolk" + } + }, + { + "id": 4885, + "name": "Ferrell Shields", + "gender": "male", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Naomi" + } + }, + { + "id": 4886, + "name": "Ladonna Cole", + "gender": "female", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Cawood" + } + }, + { + "id": 4887, + "name": "Clarissa Maddox", + "gender": "female", + "age": 79, + "address": { + "state": "South Carolina", + "city": "Alleghenyville" + } + }, + { + "id": 4888, + "name": "Galloway Walsh", + "gender": "male", + "age": 27, + "address": { + "state": "Missouri", + "city": "Brooktrails" + } + }, + { + "id": 4889, + "name": "Turner Meyers", + "gender": "male", + "age": 39, + "address": { + "state": "Utah", + "city": "Rockingham" + } + }, + { + "id": 4890, + "name": "Livingston Preston", + "gender": "male", + "age": 19, + "address": { + "state": "Indiana", + "city": "Lowgap" + } + }, + { + "id": 4891, + "name": "Lora Freeman", + "gender": "female", + "age": 36, + "address": { + "state": "California", + "city": "Suitland" + } + }, + { + "id": 4892, + "name": "Andrea Craig", + "gender": "female", + "age": 69, + "address": { + "state": "Kansas", + "city": "Waterford" + } + }, + { + "id": 4893, + "name": "Tabitha Middleton", + "gender": "female", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Wilmington" + } + }, + { + "id": 4894, + "name": "Lott Kramer", + "gender": "male", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Summertown" + } + }, + { + "id": 4895, + "name": "Kim Morrison", + "gender": "male", + "age": 33, + "address": { + "state": "Ohio", + "city": "Venice" + } + }, + { + "id": 4896, + "name": "Magdalena Buchanan", + "gender": "female", + "age": 36, + "address": { + "state": "Wyoming", + "city": "Joes" + } + }, + { + "id": 4897, + "name": "Rochelle Butler", + "gender": "female", + "age": 53, + "address": { + "state": "Oregon", + "city": "Kanauga" + } + }, + { + "id": 4898, + "name": "Millicent Mckenzie", + "gender": "female", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Marbury" + } + }, + { + "id": 4899, + "name": "Morse Lindsay", + "gender": "male", + "age": 71, + "address": { + "state": "Iowa", + "city": "Manchester" + } + }, + { + "id": 4900, + "name": "Becker Marsh", + "gender": "male", + "age": 23, + "address": { + "state": "Illinois", + "city": "Hollymead" + } + }, + { + "id": 4901, + "name": "Steele Ellis", + "gender": "male", + "age": 81, + "address": { + "state": "North Dakota", + "city": "Walland" + } + }, + { + "id": 4902, + "name": "Luna Hobbs", + "gender": "male", + "age": 37, + "address": { + "state": "Washington", + "city": "Falconaire" + } + }, + { + "id": 4903, + "name": "Fisher Brewer", + "gender": "male", + "age": 24, + "address": { + "state": "Mississippi", + "city": "Chelsea" + } + }, + { + "id": 4904, + "name": "White Cline", + "gender": "male", + "age": 54, + "address": { + "state": "Massachusetts", + "city": "Coleville" + } + }, + { + "id": 4905, + "name": "Connie Miranda", + "gender": "female", + "age": 78, + "address": { + "state": "Nevada", + "city": "Floriston" + } + }, + { + "id": 4906, + "name": "Millicent Alexander", + "gender": "female", + "age": 42, + "address": { + "state": "Idaho", + "city": "Berwind" + } + }, + { + "id": 4907, + "name": "Bean Whitaker", + "gender": "male", + "age": 64, + "address": { + "state": "New Jersey", + "city": "Hemlock" + } + }, + { + "id": 4908, + "name": "Pamela Pacheco", + "gender": "female", + "age": 45, + "address": { + "state": "Wyoming", + "city": "Basye" + } + }, + { + "id": 4909, + "name": "Carole Grant", + "gender": "female", + "age": 70, + "address": { + "state": "Michigan", + "city": "Ivanhoe" + } + }, + { + "id": 4910, + "name": "Ellison Vinson", + "gender": "male", + "age": 48, + "address": { + "state": "Colorado", + "city": "Valle" + } + }, + { + "id": 4911, + "name": "Daugherty Holland", + "gender": "male", + "age": 78, + "address": { + "state": "New York", + "city": "Kerby" + } + }, + { + "id": 4912, + "name": "Joan Lancaster", + "gender": "female", + "age": 59, + "address": { + "state": "California", + "city": "Bath" + } + }, + { + "id": 4913, + "name": "Vilma Crane", + "gender": "female", + "age": 66, + "address": { + "state": "Minnesota", + "city": "Caledonia" + } + }, + { + "id": 4914, + "name": "Greer Cotton", + "gender": "male", + "age": 31, + "address": { + "state": "Virginia", + "city": "Whitehaven" + } + }, + { + "id": 4915, + "name": "Bartlett Booth", + "gender": "male", + "age": 77, + "address": { + "state": "New Mexico", + "city": "Chloride" + } + }, + { + "id": 4916, + "name": "Ella Massey", + "gender": "female", + "age": 19, + "address": { + "state": "Florida", + "city": "Kent" + } + }, + { + "id": 4917, + "name": "Tina Atkins", + "gender": "female", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Snelling" + } + }, + { + "id": 4918, + "name": "Mcdaniel Becker", + "gender": "male", + "age": 70, + "address": { + "state": "Maine", + "city": "Harborton" + } + }, + { + "id": 4919, + "name": "Wise Pruitt", + "gender": "male", + "age": 69, + "address": { + "state": "Texas", + "city": "Waverly" + } + }, + { + "id": 4920, + "name": "Nannie Albert", + "gender": "female", + "age": 38, + "address": { + "state": "Alabama", + "city": "Dawn" + } + }, + { + "id": 4921, + "name": "Hinton Barnes", + "gender": "male", + "age": 38, + "address": { + "state": "Delaware", + "city": "Rehrersburg" + } + }, + { + "id": 4922, + "name": "Karin Buchanan", + "gender": "female", + "age": 53, + "address": { + "state": "Wisconsin", + "city": "Strykersville" + } + }, + { + "id": 4923, + "name": "Frost Holcomb", + "gender": "male", + "age": 55, + "address": { + "state": "Arizona", + "city": "Maury" + } + }, + { + "id": 4924, + "name": "Good Thornton", + "gender": "male", + "age": 64, + "address": { + "state": "Montana", + "city": "Kanauga" + } + }, + { + "id": 4925, + "name": "Mara Sweeney", + "gender": "female", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Mulino" + } + }, + { + "id": 4926, + "name": "Jocelyn Stewart", + "gender": "female", + "age": 71, + "address": { + "state": "Maryland", + "city": "Convent" + } + }, + { + "id": 4927, + "name": "Bonita Stafford", + "gender": "female", + "age": 33, + "address": { + "state": "Tennessee", + "city": "Cowiche" + } + }, + { + "id": 4928, + "name": "Taylor Fisher", + "gender": "female", + "age": 78, + "address": { + "state": "Missouri", + "city": "Concho" + } + }, + { + "id": 4929, + "name": "Beatriz White", + "gender": "female", + "age": 46, + "address": { + "state": "Pennsylvania", + "city": "Mathews" + } + }, + { + "id": 4930, + "name": "Delaney Morgan", + "gender": "male", + "age": 43, + "address": { + "state": "West Virginia", + "city": "Harviell" + } + }, + { + "id": 4931, + "name": "Woods Snyder", + "gender": "male", + "age": 28, + "address": { + "state": "South Dakota", + "city": "Wedgewood" + } + }, + { + "id": 4932, + "name": "Clara Lamb", + "gender": "female", + "age": 76, + "address": { + "state": "Kansas", + "city": "Itmann" + } + }, + { + "id": 4933, + "name": "Charlotte Cameron", + "gender": "female", + "age": 54, + "address": { + "state": "Iowa", + "city": "Navarre" + } + }, + { + "id": 4934, + "name": "Tricia Joyce", + "gender": "female", + "age": 82, + "address": { + "state": "Louisiana", + "city": "Greenock" + } + }, + { + "id": 4935, + "name": "Mariana Pierce", + "gender": "female", + "age": 52, + "address": { + "state": "Indiana", + "city": "Durham" + } + }, + { + "id": 4936, + "name": "Aileen Head", + "gender": "female", + "age": 82, + "address": { + "state": "Alaska", + "city": "Wauhillau" + } + }, + { + "id": 4937, + "name": "Watson Bridges", + "gender": "male", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Ripley" + } + }, + { + "id": 4938, + "name": "Fanny Stanton", + "gender": "female", + "age": 18, + "address": { + "state": "Georgia", + "city": "Williston" + } + }, + { + "id": 4939, + "name": "Lloyd Zamora", + "gender": "male", + "age": 29, + "address": { + "state": "Vermont", + "city": "Stouchsburg" + } + }, + { + "id": 4940, + "name": "Julie Emerson", + "gender": "female", + "age": 69, + "address": { + "state": "Ohio", + "city": "Reinerton" + } + }, + { + "id": 4941, + "name": "Cathleen Gilliam", + "gender": "female", + "age": 22, + "address": { + "state": "Utah", + "city": "Shindler" + } + }, + { + "id": 4942, + "name": "Dickerson Monroe", + "gender": "male", + "age": 21, + "address": { + "state": "New Hampshire", + "city": "Slovan" + } + }, + { + "id": 4943, + "name": "Stewart Lawrence", + "gender": "male", + "age": 20, + "address": { + "state": "Rhode Island", + "city": "Brookfield" + } + }, + { + "id": 4944, + "name": "Mann Estes", + "gender": "male", + "age": 22, + "address": { + "state": "Connecticut", + "city": "Ironton" + } + }, + { + "id": 4945, + "name": "Danielle Knowles", + "gender": "female", + "age": 47, + "address": { + "state": "Oklahoma", + "city": "Henrietta" + } + }, + { + "id": 4946, + "name": "Everett Hancock", + "gender": "male", + "age": 67, + "address": { + "state": "Oregon", + "city": "Edmund" + } + }, + { + "id": 4947, + "name": "Haney Mayo", + "gender": "male", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Wanamie" + } + }, + { + "id": 4948, + "name": "Lindsey Pickett", + "gender": "female", + "age": 50, + "address": { + "state": "Hawaii", + "city": "Joes" + } + }, + { + "id": 4949, + "name": "Imogene Hartman", + "gender": "female", + "age": 79, + "address": { + "state": "Ohio", + "city": "Kimmell" + } + }, + { + "id": 4950, + "name": "Gretchen Jimenez", + "gender": "female", + "age": 73, + "address": { + "state": "Oregon", + "city": "Albrightsville" + } + }, + { + "id": 4951, + "name": "Savage Blair", + "gender": "male", + "age": 32, + "address": { + "state": "Nevada", + "city": "Saranap" + } + }, + { + "id": 4952, + "name": "Kimberley Bender", + "gender": "female", + "age": 49, + "address": { + "state": "California", + "city": "Homeworth" + } + }, + { + "id": 4953, + "name": "Elena Cain", + "gender": "female", + "age": 45, + "address": { + "state": "Kansas", + "city": "Unionville" + } + }, + { + "id": 4954, + "name": "Keller Ochoa", + "gender": "male", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Kiskimere" + } + }, + { + "id": 4955, + "name": "Rasmussen Clemons", + "gender": "male", + "age": 81, + "address": { + "state": "Rhode Island", + "city": "Watrous" + } + }, + { + "id": 4956, + "name": "Nguyen Santiago", + "gender": "male", + "age": 26, + "address": { + "state": "Arkansas", + "city": "Northridge" + } + }, + { + "id": 4957, + "name": "Blake Gamble", + "gender": "male", + "age": 53, + "address": { + "state": "Montana", + "city": "Belmont" + } + }, + { + "id": 4958, + "name": "Polly Mathews", + "gender": "female", + "age": 35, + "address": { + "state": "South Dakota", + "city": "Iberia" + } + }, + { + "id": 4959, + "name": "Mai Young", + "gender": "female", + "age": 32, + "address": { + "state": "Hawaii", + "city": "Chical" + } + }, + { + "id": 4960, + "name": "Rivera Terrell", + "gender": "male", + "age": 25, + "address": { + "state": "Kentucky", + "city": "Bentonville" + } + }, + { + "id": 4961, + "name": "Barr Fletcher", + "gender": "male", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Cornucopia" + } + }, + { + "id": 4962, + "name": "Nelson Gilliam", + "gender": "male", + "age": 46, + "address": { + "state": "Indiana", + "city": "Emory" + } + }, + { + "id": 4963, + "name": "Henrietta Woods", + "gender": "female", + "age": 30, + "address": { + "state": "Washington", + "city": "Austinburg" + } + }, + { + "id": 4964, + "name": "Twila Langley", + "gender": "female", + "age": 54, + "address": { + "state": "Idaho", + "city": "Chaparrito" + } + }, + { + "id": 4965, + "name": "Shelton Moody", + "gender": "male", + "age": 59, + "address": { + "state": "Pennsylvania", + "city": "Wyoming" + } + }, + { + "id": 4966, + "name": "Catherine Vang", + "gender": "female", + "age": 79, + "address": { + "state": "Illinois", + "city": "Sutton" + } + }, + { + "id": 4967, + "name": "Gould Collier", + "gender": "male", + "age": 49, + "address": { + "state": "New York", + "city": "Albany" + } + }, + { + "id": 4968, + "name": "Megan Jennings", + "gender": "female", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Oneida" + } + }, + { + "id": 4969, + "name": "Morrison Nunez", + "gender": "male", + "age": 80, + "address": { + "state": "Iowa", + "city": "Lawrence" + } + }, + { + "id": 4970, + "name": "Washington Stafford", + "gender": "male", + "age": 61, + "address": { + "state": "Delaware", + "city": "Clinton" + } + }, + { + "id": 4971, + "name": "Mcclure Wright", + "gender": "male", + "age": 47, + "address": { + "state": "Wyoming", + "city": "Hegins" + } + }, + { + "id": 4972, + "name": "Mcleod Sims", + "gender": "male", + "age": 35, + "address": { + "state": "New Hampshire", + "city": "Greenfields" + } + }, + { + "id": 4973, + "name": "Paulette Scott", + "gender": "female", + "age": 60, + "address": { + "state": "Maine", + "city": "Loveland" + } + }, + { + "id": 4974, + "name": "Cline Wolf", + "gender": "male", + "age": 76, + "address": { + "state": "Connecticut", + "city": "Windsor" + } + }, + { + "id": 4975, + "name": "Irwin Cox", + "gender": "male", + "age": 36, + "address": { + "state": "Oklahoma", + "city": "Konterra" + } + }, + { + "id": 4976, + "name": "Mathews Pacheco", + "gender": "male", + "age": 38, + "address": { + "state": "Missouri", + "city": "National" + } + }, + { + "id": 4977, + "name": "Iva Gallagher", + "gender": "female", + "age": 18, + "address": { + "state": "West Virginia", + "city": "Connerton" + } + }, + { + "id": 4978, + "name": "Stephenson Bradshaw", + "gender": "male", + "age": 35, + "address": { + "state": "Colorado", + "city": "Keyport" + } + }, + { + "id": 4979, + "name": "Aline Mejia", + "gender": "female", + "age": 75, + "address": { + "state": "Texas", + "city": "Bradenville" + } + }, + { + "id": 4980, + "name": "Daniel Farley", + "gender": "male", + "age": 33, + "address": { + "state": "Alabama", + "city": "Hatteras" + } + }, + { + "id": 4981, + "name": "Vaughan Ball", + "gender": "male", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Roulette" + } + }, + { + "id": 4982, + "name": "Rita Freeman", + "gender": "female", + "age": 52, + "address": { + "state": "Alaska", + "city": "Stollings" + } + }, + { + "id": 4983, + "name": "Mccall Farrell", + "gender": "male", + "age": 81, + "address": { + "state": "Utah", + "city": "Caroline" + } + }, + { + "id": 4984, + "name": "Alissa Goodman", + "gender": "female", + "age": 82, + "address": { + "state": "Arizona", + "city": "Dubois" + } + }, + { + "id": 4985, + "name": "Branch Nieves", + "gender": "male", + "age": 40, + "address": { + "state": "Georgia", + "city": "Greenock" + } + }, + { + "id": 4986, + "name": "Chasity Andrews", + "gender": "female", + "age": 78, + "address": { + "state": "Florida", + "city": "Fedora" + } + }, + { + "id": 4987, + "name": "Ollie Hardy", + "gender": "female", + "age": 42, + "address": { + "state": "Virginia", + "city": "Shasta" + } + }, + { + "id": 4988, + "name": "Noel Lambert", + "gender": "male", + "age": 59, + "address": { + "state": "Michigan", + "city": "Muse" + } + }, + { + "id": 4989, + "name": "Torres Mcgowan", + "gender": "male", + "age": 27, + "address": { + "state": "Tennessee", + "city": "Nescatunga" + } + }, + { + "id": 4990, + "name": "Nicholson Mcclain", + "gender": "male", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Bourg" + } + }, + { + "id": 4991, + "name": "Allison Whitfield", + "gender": "female", + "age": 22, + "address": { + "state": "Vermont", + "city": "Sardis" + } + }, + { + "id": 4992, + "name": "Kathrine Lamb", + "gender": "female", + "age": 48, + "address": { + "state": "South Carolina", + "city": "Orick" + } + }, + { + "id": 4993, + "name": "Mckee Goodwin", + "gender": "male", + "age": 60, + "address": { + "state": "New Jersey", + "city": "Wheatfields" + } + }, + { + "id": 4994, + "name": "Callie Boyle", + "gender": "female", + "age": 75, + "address": { + "state": "Wisconsin", + "city": "Ypsilanti" + } + }, + { + "id": 4995, + "name": "Farmer Garner", + "gender": "male", + "age": 71, + "address": { + "state": "North Carolina", + "city": "Columbus" + } + }, + { + "id": 4996, + "name": "Serrano Justice", + "gender": "male", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Glenville" + } + }, + { + "id": 4997, + "name": "Horne Curry", + "gender": "male", + "age": 19, + "address": { + "state": "Maryland", + "city": "Volta" + } + }, + { + "id": 4998, + "name": "Michelle Gentry", + "gender": "female", + "age": 72, + "address": { + "state": "Delaware", + "city": "Wolcott" + } + }, + { + "id": 4999, + "name": "Odom Kelly", + "gender": "male", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Beechmont" + } + }, + { + "id": 5000, + "name": "Martinez Duran", + "gender": "male", + "age": 67, + "address": { + "state": "Wisconsin", + "city": "Wawona" + } + }, + { + "id": 5001, + "name": "Terry Pate", + "gender": "female", + "age": 48, + "address": { + "state": "Indiana", + "city": "Germanton" + } + }, + { + "id": 5002, + "name": "Araceli Puckett", + "gender": "female", + "age": 64, + "address": { + "state": "South Carolina", + "city": "Retsof" + } + }, + { + "id": 5003, + "name": "Evans Christensen", + "gender": "male", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Sultana" + } + }, + { + "id": 5004, + "name": "Payne Booker", + "gender": "male", + "age": 62, + "address": { + "state": "Missouri", + "city": "Wollochet" + } + }, + { + "id": 5005, + "name": "Gay Mcconnell", + "gender": "male", + "age": 52, + "address": { + "state": "Rhode Island", + "city": "Veguita" + } + }, + { + "id": 5006, + "name": "Alyssa Simon", + "gender": "female", + "age": 77, + "address": { + "state": "Colorado", + "city": "Bergoo" + } + }, + { + "id": 5007, + "name": "Lillian Chan", + "gender": "female", + "age": 60, + "address": { + "state": "Mississippi", + "city": "Magnolia" + } + }, + { + "id": 5008, + "name": "Miranda Davenport", + "gender": "female", + "age": 48, + "address": { + "state": "Maine", + "city": "Mathews" + } + }, + { + "id": 5009, + "name": "Betsy Montoya", + "gender": "female", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Alden" + } + }, + { + "id": 5010, + "name": "Ila Knapp", + "gender": "female", + "age": 38, + "address": { + "state": "Arizona", + "city": "Genoa" + } + }, + { + "id": 5011, + "name": "Suzanne Wynn", + "gender": "female", + "age": 80, + "address": { + "state": "Texas", + "city": "Kenvil" + } + }, + { + "id": 5012, + "name": "Simon Stanton", + "gender": "male", + "age": 66, + "address": { + "state": "Florida", + "city": "Allensworth" + } + }, + { + "id": 5013, + "name": "Aimee Scott", + "gender": "female", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Dellview" + } + }, + { + "id": 5014, + "name": "Freida Valencia", + "gender": "female", + "age": 27, + "address": { + "state": "Maryland", + "city": "Iberia" + } + }, + { + "id": 5015, + "name": "Melanie Haley", + "gender": "female", + "age": 44, + "address": { + "state": "West Virginia", + "city": "Norwood" + } + }, + { + "id": 5016, + "name": "Nadia Morin", + "gender": "female", + "age": 55, + "address": { + "state": "North Carolina", + "city": "Coloma" + } + }, + { + "id": 5017, + "name": "Casey Peck", + "gender": "female", + "age": 54, + "address": { + "state": "Iowa", + "city": "Gloucester" + } + }, + { + "id": 5018, + "name": "Merle Cole", + "gender": "female", + "age": 23, + "address": { + "state": "Illinois", + "city": "Freetown" + } + }, + { + "id": 5019, + "name": "Curtis Guthrie", + "gender": "male", + "age": 41, + "address": { + "state": "South Dakota", + "city": "Slovan" + } + }, + { + "id": 5020, + "name": "Oneal Garrison", + "gender": "male", + "age": 81, + "address": { + "state": "Oregon", + "city": "Vivian" + } + }, + { + "id": 5021, + "name": "Juliana Butler", + "gender": "female", + "age": 51, + "address": { + "state": "Idaho", + "city": "Greenbackville" + } + }, + { + "id": 5022, + "name": "Earline Mays", + "gender": "female", + "age": 53, + "address": { + "state": "California", + "city": "Tedrow" + } + }, + { + "id": 5023, + "name": "Cox Merritt", + "gender": "male", + "age": 79, + "address": { + "state": "New York", + "city": "Biddle" + } + }, + { + "id": 5024, + "name": "Schwartz Graham", + "gender": "male", + "age": 43, + "address": { + "state": "New Hampshire", + "city": "Spokane" + } + }, + { + "id": 5025, + "name": "Natalia Myers", + "gender": "female", + "age": 53, + "address": { + "state": "Ohio", + "city": "Dixie" + } + }, + { + "id": 5026, + "name": "Sherri Gillespie", + "gender": "female", + "age": 45, + "address": { + "state": "Utah", + "city": "Riner" + } + }, + { + "id": 5027, + "name": "Traci Collins", + "gender": "female", + "age": 67, + "address": { + "state": "Virginia", + "city": "Watchtower" + } + }, + { + "id": 5028, + "name": "West Glenn", + "gender": "male", + "age": 70, + "address": { + "state": "Georgia", + "city": "Woodlake" + } + }, + { + "id": 5029, + "name": "Nannie Blackburn", + "gender": "female", + "age": 75, + "address": { + "state": "Washington", + "city": "Cumminsville" + } + }, + { + "id": 5030, + "name": "Leigh Brewer", + "gender": "female", + "age": 37, + "address": { + "state": "Michigan", + "city": "Zortman" + } + }, + { + "id": 5031, + "name": "Vance Riddle", + "gender": "male", + "age": 66, + "address": { + "state": "Louisiana", + "city": "Ferney" + } + }, + { + "id": 5032, + "name": "Lara Terrell", + "gender": "female", + "age": 18, + "address": { + "state": "Alaska", + "city": "Ebro" + } + }, + { + "id": 5033, + "name": "Lee Blair", + "gender": "male", + "age": 79, + "address": { + "state": "Montana", + "city": "Bartley" + } + }, + { + "id": 5034, + "name": "Blackburn Montgomery", + "gender": "male", + "age": 49, + "address": { + "state": "Nevada", + "city": "Brambleton" + } + }, + { + "id": 5035, + "name": "Esperanza Robertson", + "gender": "female", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Worton" + } + }, + { + "id": 5036, + "name": "Chase Shields", + "gender": "male", + "age": 65, + "address": { + "state": "Connecticut", + "city": "Clinton" + } + }, + { + "id": 5037, + "name": "Mavis Oneill", + "gender": "female", + "age": 52, + "address": { + "state": "Vermont", + "city": "Dennard" + } + }, + { + "id": 5038, + "name": "Conner Rasmussen", + "gender": "male", + "age": 42, + "address": { + "state": "Oklahoma", + "city": "Hannasville" + } + }, + { + "id": 5039, + "name": "Morrison Hebert", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Newkirk" + } + }, + { + "id": 5040, + "name": "Ratliff Kerr", + "gender": "male", + "age": 23, + "address": { + "state": "New Mexico", + "city": "Venice" + } + }, + { + "id": 5041, + "name": "House Chandler", + "gender": "male", + "age": 42, + "address": { + "state": "Kansas", + "city": "Finzel" + } + }, + { + "id": 5042, + "name": "Ashlee Small", + "gender": "female", + "age": 82, + "address": { + "state": "North Dakota", + "city": "Benson" + } + }, + { + "id": 5043, + "name": "Faye Davis", + "gender": "female", + "age": 27, + "address": { + "state": "Alabama", + "city": "Roulette" + } + }, + { + "id": 5044, + "name": "Hebert Clarke", + "gender": "male", + "age": 72, + "address": { + "state": "Arkansas", + "city": "Nipinnawasee" + } + }, + { + "id": 5045, + "name": "Dolores Mcguire", + "gender": "female", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Jamestown" + } + }, + { + "id": 5046, + "name": "Oneill Macias", + "gender": "male", + "age": 56, + "address": { + "state": "Tennessee", + "city": "Garfield" + } + }, + { + "id": 5047, + "name": "Blanche Orr", + "gender": "female", + "age": 24, + "address": { + "state": "Wyoming", + "city": "Goodville" + } + }, + { + "id": 5048, + "name": "Gilmore French", + "gender": "male", + "age": 55, + "address": { + "state": "Georgia", + "city": "Oceola" + } + }, + { + "id": 5049, + "name": "Chavez Jimenez", + "gender": "male", + "age": 80, + "address": { + "state": "Maine", + "city": "Tyhee" + } + }, + { + "id": 5050, + "name": "Eunice Andrews", + "gender": "female", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Elliston" + } + }, + { + "id": 5051, + "name": "Atkins Vincent", + "gender": "male", + "age": 80, + "address": { + "state": "Delaware", + "city": "Ogema" + } + }, + { + "id": 5052, + "name": "Massey Combs", + "gender": "male", + "age": 26, + "address": { + "state": "Rhode Island", + "city": "Rodman" + } + }, + { + "id": 5053, + "name": "Vega Nielsen", + "gender": "male", + "age": 26, + "address": { + "state": "Texas", + "city": "Kipp" + } + }, + { + "id": 5054, + "name": "Rowe Roach", + "gender": "male", + "age": 63, + "address": { + "state": "South Dakota", + "city": "Orviston" + } + }, + { + "id": 5055, + "name": "Mccarthy Myers", + "gender": "male", + "age": 38, + "address": { + "state": "Illinois", + "city": "Conway" + } + }, + { + "id": 5056, + "name": "Jennings Flynn", + "gender": "male", + "age": 70, + "address": { + "state": "Hawaii", + "city": "Albany" + } + }, + { + "id": 5057, + "name": "Sandra Matthews", + "gender": "female", + "age": 68, + "address": { + "state": "Florida", + "city": "Mammoth" + } + }, + { + "id": 5058, + "name": "Peck Woodward", + "gender": "male", + "age": 29, + "address": { + "state": "North Carolina", + "city": "Greensburg" + } + }, + { + "id": 5059, + "name": "Dionne Gill", + "gender": "female", + "age": 75, + "address": { + "state": "Massachusetts", + "city": "Trail" + } + }, + { + "id": 5060, + "name": "Elisa Simpson", + "gender": "female", + "age": 75, + "address": { + "state": "Oregon", + "city": "Haena" + } + }, + { + "id": 5061, + "name": "Minerva Huff", + "gender": "female", + "age": 28, + "address": { + "state": "North Dakota", + "city": "Canterwood" + } + }, + { + "id": 5062, + "name": "Susana Sloan", + "gender": "female", + "age": 65, + "address": { + "state": "Mississippi", + "city": "Maxville" + } + }, + { + "id": 5063, + "name": "Terry Brown", + "gender": "female", + "age": 60, + "address": { + "state": "Nevada", + "city": "Statenville" + } + }, + { + "id": 5064, + "name": "Carrillo Grant", + "gender": "male", + "age": 58, + "address": { + "state": "Pennsylvania", + "city": "Garnet" + } + }, + { + "id": 5065, + "name": "Howard Wilkinson", + "gender": "male", + "age": 75, + "address": { + "state": "New York", + "city": "Marne" + } + }, + { + "id": 5066, + "name": "Richards Hernandez", + "gender": "male", + "age": 79, + "address": { + "state": "Wisconsin", + "city": "Advance" + } + }, + { + "id": 5067, + "name": "Millicent Dickerson", + "gender": "female", + "age": 72, + "address": { + "state": "Louisiana", + "city": "Nettie" + } + }, + { + "id": 5068, + "name": "Kate Benton", + "gender": "female", + "age": 79, + "address": { + "state": "South Carolina", + "city": "Summertown" + } + }, + { + "id": 5069, + "name": "Rojas Ward", + "gender": "male", + "age": 58, + "address": { + "state": "Kentucky", + "city": "Biddle" + } + }, + { + "id": 5070, + "name": "Bessie Branch", + "gender": "female", + "age": 50, + "address": { + "state": "Tennessee", + "city": "Abiquiu" + } + }, + { + "id": 5071, + "name": "April Noel", + "gender": "female", + "age": 63, + "address": { + "state": "Utah", + "city": "Noxen" + } + }, + { + "id": 5072, + "name": "Bonnie Baxter", + "gender": "female", + "age": 20, + "address": { + "state": "Idaho", + "city": "Marenisco" + } + }, + { + "id": 5073, + "name": "Carolina Acosta", + "gender": "female", + "age": 63, + "address": { + "state": "Connecticut", + "city": "Fingerville" + } + }, + { + "id": 5074, + "name": "Katina Buckley", + "gender": "female", + "age": 37, + "address": { + "state": "Virginia", + "city": "Ada" + } + }, + { + "id": 5075, + "name": "Estrada Barrett", + "gender": "male", + "age": 18, + "address": { + "state": "Kansas", + "city": "Edneyville" + } + }, + { + "id": 5076, + "name": "Kane Tran", + "gender": "male", + "age": 72, + "address": { + "state": "Arizona", + "city": "Cawood" + } + }, + { + "id": 5077, + "name": "Christina Riddle", + "gender": "female", + "age": 65, + "address": { + "state": "New Mexico", + "city": "Camas" + } + }, + { + "id": 5078, + "name": "Winifred Parks", + "gender": "female", + "age": 31, + "address": { + "state": "Missouri", + "city": "Dunnavant" + } + }, + { + "id": 5079, + "name": "Tania Marshall", + "gender": "female", + "age": 72, + "address": { + "state": "Iowa", + "city": "Ladera" + } + }, + { + "id": 5080, + "name": "Ivy Valentine", + "gender": "female", + "age": 63, + "address": { + "state": "Vermont", + "city": "Kohatk" + } + }, + { + "id": 5081, + "name": "Mooney Huber", + "gender": "male", + "age": 67, + "address": { + "state": "Washington", + "city": "Galesville" + } + }, + { + "id": 5082, + "name": "Marissa Tanner", + "gender": "female", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Slovan" + } + }, + { + "id": 5083, + "name": "Clayton Wright", + "gender": "male", + "age": 26, + "address": { + "state": "Maryland", + "city": "Waterloo" + } + }, + { + "id": 5084, + "name": "Lynette Bowen", + "gender": "female", + "age": 70, + "address": { + "state": "Michigan", + "city": "Rosine" + } + }, + { + "id": 5085, + "name": "Mcbride Fleming", + "gender": "male", + "age": 35, + "address": { + "state": "New Hampshire", + "city": "Chloride" + } + }, + { + "id": 5086, + "name": "Lawanda Rose", + "gender": "female", + "age": 51, + "address": { + "state": "Indiana", + "city": "Robbins" + } + }, + { + "id": 5087, + "name": "Aisha Webb", + "gender": "female", + "age": 75, + "address": { + "state": "Montana", + "city": "Broadlands" + } + }, + { + "id": 5088, + "name": "Stacey Fuentes", + "gender": "female", + "age": 18, + "address": { + "state": "Arkansas", + "city": "Bannock" + } + }, + { + "id": 5089, + "name": "Sue Downs", + "gender": "female", + "age": 19, + "address": { + "state": "New Jersey", + "city": "Blende" + } + }, + { + "id": 5090, + "name": "Carmela Pierce", + "gender": "female", + "age": 18, + "address": { + "state": "West Virginia", + "city": "Lavalette" + } + }, + { + "id": 5091, + "name": "Constance Willis", + "gender": "female", + "age": 82, + "address": { + "state": "California", + "city": "Nadine" + } + }, + { + "id": 5092, + "name": "Darcy Dotson", + "gender": "female", + "age": 55, + "address": { + "state": "Alabama", + "city": "Greenwich" + } + }, + { + "id": 5093, + "name": "Julianne Holder", + "gender": "female", + "age": 39, + "address": { + "state": "Ohio", + "city": "Beechmont" + } + }, + { + "id": 5094, + "name": "Cynthia Mejia", + "gender": "female", + "age": 71, + "address": { + "state": "Minnesota", + "city": "Valle" + } + }, + { + "id": 5095, + "name": "Kristi Irwin", + "gender": "female", + "age": 21, + "address": { + "state": "Alaska", + "city": "Katonah" + } + }, + { + "id": 5096, + "name": "Herrera Kemp", + "gender": "male", + "age": 70, + "address": { + "state": "California", + "city": "Fostoria" + } + }, + { + "id": 5097, + "name": "Sexton Hurley", + "gender": "male", + "age": 35, + "address": { + "state": "Colorado", + "city": "Fairacres" + } + }, + { + "id": 5098, + "name": "Vonda Faulkner", + "gender": "female", + "age": 63, + "address": { + "state": "Maine", + "city": "Swartzville" + } + }, + { + "id": 5099, + "name": "Leonor Lynn", + "gender": "female", + "age": 49, + "address": { + "state": "Michigan", + "city": "Tuskahoma" + } + }, + { + "id": 5100, + "name": "Madeleine Mclaughlin", + "gender": "female", + "age": 63, + "address": { + "state": "Maryland", + "city": "Norfolk" + } + }, + { + "id": 5101, + "name": "Armstrong Gomez", + "gender": "male", + "age": 18, + "address": { + "state": "Mississippi", + "city": "Klondike" + } + }, + { + "id": 5102, + "name": "Alvarado Hoover", + "gender": "male", + "age": 59, + "address": { + "state": "Virginia", + "city": "Westwood" + } + }, + { + "id": 5103, + "name": "Britt Marsh", + "gender": "male", + "age": 23, + "address": { + "state": "North Dakota", + "city": "Forbestown" + } + }, + { + "id": 5104, + "name": "Helene William", + "gender": "female", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Ladera" + } + }, + { + "id": 5105, + "name": "Jacqueline Carter", + "gender": "female", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Emerald" + } + }, + { + "id": 5106, + "name": "Kelley Allen", + "gender": "female", + "age": 59, + "address": { + "state": "Connecticut", + "city": "Tolu" + } + }, + { + "id": 5107, + "name": "Laura Collier", + "gender": "female", + "age": 22, + "address": { + "state": "Illinois", + "city": "Germanton" + } + }, + { + "id": 5108, + "name": "Buckley Parrish", + "gender": "male", + "age": 36, + "address": { + "state": "Kentucky", + "city": "Freeburn" + } + }, + { + "id": 5109, + "name": "Fry Hunt", + "gender": "male", + "age": 55, + "address": { + "state": "Delaware", + "city": "Nelson" + } + }, + { + "id": 5110, + "name": "Casey Booker", + "gender": "female", + "age": 17, + "address": { + "state": "New Mexico", + "city": "Flintville" + } + }, + { + "id": 5111, + "name": "Stark Charles", + "gender": "male", + "age": 21, + "address": { + "state": "Alaska", + "city": "Chase" + } + }, + { + "id": 5112, + "name": "Christensen Mercer", + "gender": "male", + "age": 19, + "address": { + "state": "Idaho", + "city": "Wawona" + } + }, + { + "id": 5113, + "name": "Silva Shannon", + "gender": "male", + "age": 66, + "address": { + "state": "Arizona", + "city": "Fulford" + } + }, + { + "id": 5114, + "name": "Pierce Alston", + "gender": "male", + "age": 61, + "address": { + "state": "Oklahoma", + "city": "Wadsworth" + } + }, + { + "id": 5115, + "name": "Mendoza Maynard", + "gender": "male", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Statenville" + } + }, + { + "id": 5116, + "name": "Jannie Jordan", + "gender": "female", + "age": 57, + "address": { + "state": "Nevada", + "city": "Hiseville" + } + }, + { + "id": 5117, + "name": "Kayla Crosby", + "gender": "female", + "age": 45, + "address": { + "state": "North Carolina", + "city": "Enetai" + } + }, + { + "id": 5118, + "name": "Addie Solomon", + "gender": "female", + "age": 23, + "address": { + "state": "Vermont", + "city": "Hessville" + } + }, + { + "id": 5119, + "name": "Ferguson Levine", + "gender": "male", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Foxworth" + } + }, + { + "id": 5120, + "name": "Cain Kline", + "gender": "male", + "age": 74, + "address": { + "state": "South Dakota", + "city": "Harleigh" + } + }, + { + "id": 5121, + "name": "Hancock Hernandez", + "gender": "male", + "age": 31, + "address": { + "state": "Missouri", + "city": "Jenkinsville" + } + }, + { + "id": 5122, + "name": "Rosalinda Ashley", + "gender": "female", + "age": 73, + "address": { + "state": "Texas", + "city": "Tampico" + } + }, + { + "id": 5123, + "name": "Ester Chapman", + "gender": "female", + "age": 54, + "address": { + "state": "Louisiana", + "city": "Sandston" + } + }, + { + "id": 5124, + "name": "Bowen Mcgowan", + "gender": "male", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Ellerslie" + } + }, + { + "id": 5125, + "name": "Alma Deleon", + "gender": "female", + "age": 17, + "address": { + "state": "Ohio", + "city": "Laurelton" + } + }, + { + "id": 5126, + "name": "Mcdonald Cummings", + "gender": "male", + "age": 34, + "address": { + "state": "Utah", + "city": "Stockdale" + } + }, + { + "id": 5127, + "name": "Small Morin", + "gender": "male", + "age": 18, + "address": { + "state": "West Virginia", + "city": "Konterra" + } + }, + { + "id": 5128, + "name": "Puckett Craft", + "gender": "male", + "age": 57, + "address": { + "state": "Iowa", + "city": "Crumpler" + } + }, + { + "id": 5129, + "name": "Angelia Avila", + "gender": "female", + "age": 71, + "address": { + "state": "Oregon", + "city": "Bannock" + } + }, + { + "id": 5130, + "name": "Melanie Wilson", + "gender": "female", + "age": 58, + "address": { + "state": "Montana", + "city": "Dola" + } + }, + { + "id": 5131, + "name": "William Lyons", + "gender": "male", + "age": 72, + "address": { + "state": "Wyoming", + "city": "Allison" + } + }, + { + "id": 5132, + "name": "Pitts Bowen", + "gender": "male", + "age": 27, + "address": { + "state": "Tennessee", + "city": "Boling" + } + }, + { + "id": 5133, + "name": "Rush Herring", + "gender": "male", + "age": 21, + "address": { + "state": "Indiana", + "city": "Terlingua" + } + }, + { + "id": 5134, + "name": "Bernadine Blackburn", + "gender": "female", + "age": 82, + "address": { + "state": "Florida", + "city": "Freelandville" + } + }, + { + "id": 5135, + "name": "Pearlie Nieves", + "gender": "female", + "age": 79, + "address": { + "state": "Kansas", + "city": "Dorneyville" + } + }, + { + "id": 5136, + "name": "Tracie Padilla", + "gender": "female", + "age": 74, + "address": { + "state": "Pennsylvania", + "city": "Cascades" + } + }, + { + "id": 5137, + "name": "Workman Leonard", + "gender": "male", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Geyserville" + } + }, + { + "id": 5138, + "name": "Mcintosh Cain", + "gender": "male", + "age": 22, + "address": { + "state": "New Hampshire", + "city": "Deltaville" + } + }, + { + "id": 5139, + "name": "Jones Richardson", + "gender": "male", + "age": 37, + "address": { + "state": "Alabama", + "city": "Dupuyer" + } + }, + { + "id": 5140, + "name": "Scott Huber", + "gender": "male", + "age": 74, + "address": { + "state": "Hawaii", + "city": "Vienna" + } + }, + { + "id": 5141, + "name": "Eliza Anthony", + "gender": "female", + "age": 47, + "address": { + "state": "Massachusetts", + "city": "Homeland" + } + }, + { + "id": 5142, + "name": "Margie Mccarthy", + "gender": "female", + "age": 21, + "address": { + "state": "New York", + "city": "Forestburg" + } + }, + { + "id": 5143, + "name": "Thornton Lee", + "gender": "male", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Ironton" + } + }, + { + "id": 5144, + "name": "Morgan Rivers", + "gender": "female", + "age": 69, + "address": { + "state": "Washington", + "city": "Clayville" + } + }, + { + "id": 5145, + "name": "Casandra Farmer", + "gender": "female", + "age": 44, + "address": { + "state": "Kentucky", + "city": "Dunlo" + } + }, + { + "id": 5146, + "name": "Helena Knox", + "gender": "female", + "age": 47, + "address": { + "state": "Kansas", + "city": "Woodlands" + } + }, + { + "id": 5147, + "name": "Hewitt Britt", + "gender": "male", + "age": 55, + "address": { + "state": "Hawaii", + "city": "Wyano" + } + }, + { + "id": 5148, + "name": "Emilia Keller", + "gender": "female", + "age": 19, + "address": { + "state": "Texas", + "city": "Malott" + } + }, + { + "id": 5149, + "name": "Gardner Avila", + "gender": "male", + "age": 26, + "address": { + "state": "Minnesota", + "city": "Vandiver" + } + }, + { + "id": 5150, + "name": "Meyer Gilbert", + "gender": "male", + "age": 64, + "address": { + "state": "Vermont", + "city": "Carlos" + } + }, + { + "id": 5151, + "name": "Marks Garrison", + "gender": "male", + "age": 79, + "address": { + "state": "Utah", + "city": "Idledale" + } + }, + { + "id": 5152, + "name": "Priscilla Bradford", + "gender": "female", + "age": 58, + "address": { + "state": "Mississippi", + "city": "Cliff" + } + }, + { + "id": 5153, + "name": "Camille Kelley", + "gender": "female", + "age": 80, + "address": { + "state": "Massachusetts", + "city": "Caroline" + } + }, + { + "id": 5154, + "name": "Rosalinda Meadows", + "gender": "female", + "age": 47, + "address": { + "state": "Arizona", + "city": "Berlin" + } + }, + { + "id": 5155, + "name": "Trina Hayes", + "gender": "female", + "age": 28, + "address": { + "state": "Michigan", + "city": "Kennedyville" + } + }, + { + "id": 5156, + "name": "Leah Weiss", + "gender": "female", + "age": 31, + "address": { + "state": "Maine", + "city": "Belleview" + } + }, + { + "id": 5157, + "name": "Delores Hines", + "gender": "female", + "age": 80, + "address": { + "state": "South Dakota", + "city": "Kansas" + } + }, + { + "id": 5158, + "name": "Robert Giles", + "gender": "female", + "age": 17, + "address": { + "state": "Montana", + "city": "Wintersburg" + } + }, + { + "id": 5159, + "name": "Drake Ruiz", + "gender": "male", + "age": 34, + "address": { + "state": "Washington", + "city": "Homeland" + } + }, + { + "id": 5160, + "name": "Fitzgerald Conway", + "gender": "male", + "age": 64, + "address": { + "state": "North Dakota", + "city": "Catharine" + } + }, + { + "id": 5161, + "name": "Wilder Horn", + "gender": "male", + "age": 28, + "address": { + "state": "Maryland", + "city": "Wauhillau" + } + }, + { + "id": 5162, + "name": "Sloan Brewer", + "gender": "male", + "age": 76, + "address": { + "state": "Alaska", + "city": "Juntura" + } + }, + { + "id": 5163, + "name": "Brown Kelly", + "gender": "male", + "age": 34, + "address": { + "state": "Missouri", + "city": "Delshire" + } + }, + { + "id": 5164, + "name": "Talley Johnston", + "gender": "male", + "age": 49, + "address": { + "state": "Idaho", + "city": "Saddlebrooke" + } + }, + { + "id": 5165, + "name": "Mitzi Wheeler", + "gender": "female", + "age": 45, + "address": { + "state": "New Hampshire", + "city": "Dola" + } + }, + { + "id": 5166, + "name": "Natalie Terrell", + "gender": "female", + "age": 24, + "address": { + "state": "Connecticut", + "city": "Hinsdale" + } + }, + { + "id": 5167, + "name": "Mccarty Rios", + "gender": "male", + "age": 66, + "address": { + "state": "Nebraska", + "city": "Adamstown" + } + }, + { + "id": 5168, + "name": "Sullivan Bernard", + "gender": "male", + "age": 77, + "address": { + "state": "Illinois", + "city": "Brookfield" + } + }, + { + "id": 5169, + "name": "Pat French", + "gender": "female", + "age": 38, + "address": { + "state": "Delaware", + "city": "Lupton" + } + }, + { + "id": 5170, + "name": "Shields Holcomb", + "gender": "male", + "age": 22, + "address": { + "state": "Pennsylvania", + "city": "Bagtown" + } + }, + { + "id": 5171, + "name": "Aguilar Crawford", + "gender": "male", + "age": 58, + "address": { + "state": "Louisiana", + "city": "Sidman" + } + }, + { + "id": 5172, + "name": "Morin Stewart", + "gender": "male", + "age": 49, + "address": { + "state": "Rhode Island", + "city": "Volta" + } + }, + { + "id": 5173, + "name": "Espinoza Ramos", + "gender": "male", + "age": 72, + "address": { + "state": "Nevada", + "city": "Morningside" + } + }, + { + "id": 5174, + "name": "Jackson Woodard", + "gender": "male", + "age": 21, + "address": { + "state": "Ohio", + "city": "Coral" + } + }, + { + "id": 5175, + "name": "Curry Huff", + "gender": "male", + "age": 32, + "address": { + "state": "Georgia", + "city": "Whitmer" + } + }, + { + "id": 5176, + "name": "Wilda Newton", + "gender": "female", + "age": 60, + "address": { + "state": "Tennessee", + "city": "Odessa" + } + }, + { + "id": 5177, + "name": "Terry Sheppard", + "gender": "male", + "age": 38, + "address": { + "state": "Florida", + "city": "Iberia" + } + }, + { + "id": 5178, + "name": "Sherrie Bryan", + "gender": "female", + "age": 49, + "address": { + "state": "Wisconsin", + "city": "Brewster" + } + }, + { + "id": 5179, + "name": "Hester Mclaughlin", + "gender": "female", + "age": 74, + "address": { + "state": "Wyoming", + "city": "Sanford" + } + }, + { + "id": 5180, + "name": "Alexandra Tyler", + "gender": "female", + "age": 44, + "address": { + "state": "California", + "city": "Roland" + } + }, + { + "id": 5181, + "name": "Janet Hewitt", + "gender": "female", + "age": 64, + "address": { + "state": "North Carolina", + "city": "Englevale" + } + }, + { + "id": 5182, + "name": "Eve Nixon", + "gender": "female", + "age": 75, + "address": { + "state": "South Carolina", + "city": "Corriganville" + } + }, + { + "id": 5183, + "name": "Reba Erickson", + "gender": "female", + "age": 65, + "address": { + "state": "Indiana", + "city": "Choctaw" + } + }, + { + "id": 5184, + "name": "Ross Buckner", + "gender": "male", + "age": 76, + "address": { + "state": "New York", + "city": "Lithium" + } + }, + { + "id": 5185, + "name": "Betsy Bartlett", + "gender": "female", + "age": 54, + "address": { + "state": "Arkansas", + "city": "Fontanelle" + } + }, + { + "id": 5186, + "name": "Riggs Abbott", + "gender": "male", + "age": 45, + "address": { + "state": "New Mexico", + "city": "Shindler" + } + }, + { + "id": 5187, + "name": "Adams Hardin", + "gender": "male", + "age": 63, + "address": { + "state": "Alabama", + "city": "Strong" + } + }, + { + "id": 5188, + "name": "Hart Preston", + "gender": "male", + "age": 33, + "address": { + "state": "Colorado", + "city": "National" + } + }, + { + "id": 5189, + "name": "Tessa Weeks", + "gender": "female", + "age": 47, + "address": { + "state": "Oregon", + "city": "Idamay" + } + }, + { + "id": 5190, + "name": "Todd Houston", + "gender": "male", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Hoagland" + } + }, + { + "id": 5191, + "name": "Cindy Dalton", + "gender": "female", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Bartonsville" + } + }, + { + "id": 5192, + "name": "Langley Sharpe", + "gender": "male", + "age": 24, + "address": { + "state": "Virginia", + "city": "Herald" + } + }, + { + "id": 5193, + "name": "Eleanor Sexton", + "gender": "female", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Woodlake" + } + }, + { + "id": 5194, + "name": "Lawson Walker", + "gender": "male", + "age": 77, + "address": { + "state": "Georgia", + "city": "Axis" + } + }, + { + "id": 5195, + "name": "Vonda Sanford", + "gender": "female", + "age": 70, + "address": { + "state": "Texas", + "city": "Wheatfields" + } + }, + { + "id": 5196, + "name": "Katherine Sawyer", + "gender": "female", + "age": 18, + "address": { + "state": "Oklahoma", + "city": "Delshire" + } + }, + { + "id": 5197, + "name": "Glenda Bowman", + "gender": "female", + "age": 33, + "address": { + "state": "Michigan", + "city": "Inkerman" + } + }, + { + "id": 5198, + "name": "Nell Anderson", + "gender": "female", + "age": 79, + "address": { + "state": "Maryland", + "city": "Fivepointville" + } + }, + { + "id": 5199, + "name": "Rowena Osborne", + "gender": "female", + "age": 19, + "address": { + "state": "Ohio", + "city": "Urie" + } + }, + { + "id": 5200, + "name": "Chavez Finley", + "gender": "male", + "age": 71, + "address": { + "state": "Montana", + "city": "Foscoe" + } + }, + { + "id": 5201, + "name": "Jayne Crosby", + "gender": "female", + "age": 42, + "address": { + "state": "Nebraska", + "city": "Conway" + } + }, + { + "id": 5202, + "name": "Teri George", + "gender": "female", + "age": 32, + "address": { + "state": "Hawaii", + "city": "Beaverdale" + } + }, + { + "id": 5203, + "name": "Rodgers Delacruz", + "gender": "male", + "age": 78, + "address": { + "state": "Missouri", + "city": "Imperial" + } + }, + { + "id": 5204, + "name": "Christie Day", + "gender": "female", + "age": 22, + "address": { + "state": "Illinois", + "city": "Cotopaxi" + } + }, + { + "id": 5205, + "name": "Rose Love", + "gender": "female", + "age": 81, + "address": { + "state": "Alabama", + "city": "Jacksonburg" + } + }, + { + "id": 5206, + "name": "Moran Mcclain", + "gender": "male", + "age": 21, + "address": { + "state": "Utah", + "city": "Disautel" + } + }, + { + "id": 5207, + "name": "Barbra Ferguson", + "gender": "female", + "age": 59, + "address": { + "state": "Indiana", + "city": "Itmann" + } + }, + { + "id": 5208, + "name": "Potter Montgomery", + "gender": "male", + "age": 38, + "address": { + "state": "Alaska", + "city": "Belmont" + } + }, + { + "id": 5209, + "name": "Valentine Knapp", + "gender": "male", + "age": 45, + "address": { + "state": "Florida", + "city": "Murillo" + } + }, + { + "id": 5210, + "name": "Emma Mcintosh", + "gender": "female", + "age": 28, + "address": { + "state": "North Dakota", + "city": "Richford" + } + }, + { + "id": 5211, + "name": "Zelma Solis", + "gender": "female", + "age": 43, + "address": { + "state": "Idaho", + "city": "Chaparrito" + } + }, + { + "id": 5212, + "name": "Avila Stone", + "gender": "male", + "age": 65, + "address": { + "state": "Nevada", + "city": "Kirk" + } + }, + { + "id": 5213, + "name": "Marilyn Calhoun", + "gender": "female", + "age": 81, + "address": { + "state": "Wisconsin", + "city": "Elrama" + } + }, + { + "id": 5214, + "name": "Webb Freeman", + "gender": "male", + "age": 35, + "address": { + "state": "New Jersey", + "city": "Eagletown" + } + }, + { + "id": 5215, + "name": "Aurelia Murphy", + "gender": "female", + "age": 81, + "address": { + "state": "South Dakota", + "city": "Rew" + } + }, + { + "id": 5216, + "name": "Hinton Mullins", + "gender": "male", + "age": 18, + "address": { + "state": "Louisiana", + "city": "Blairstown" + } + }, + { + "id": 5217, + "name": "Payne Santos", + "gender": "male", + "age": 66, + "address": { + "state": "West Virginia", + "city": "Caberfae" + } + }, + { + "id": 5218, + "name": "Tammy Newman", + "gender": "female", + "age": 22, + "address": { + "state": "New Mexico", + "city": "Vaughn" + } + }, + { + "id": 5219, + "name": "Cole Burris", + "gender": "male", + "age": 67, + "address": { + "state": "Vermont", + "city": "Outlook" + } + }, + { + "id": 5220, + "name": "Maura Johns", + "gender": "female", + "age": 64, + "address": { + "state": "New York", + "city": "Century" + } + }, + { + "id": 5221, + "name": "Arlene Cote", + "gender": "female", + "age": 42, + "address": { + "state": "North Carolina", + "city": "Biehle" + } + }, + { + "id": 5222, + "name": "Shanna Tillman", + "gender": "female", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Advance" + } + }, + { + "id": 5223, + "name": "Wood Velazquez", + "gender": "male", + "age": 81, + "address": { + "state": "Arizona", + "city": "Watrous" + } + }, + { + "id": 5224, + "name": "Jeanine Fields", + "gender": "female", + "age": 52, + "address": { + "state": "Washington", + "city": "Allamuchy" + } + }, + { + "id": 5225, + "name": "Myra Hunter", + "gender": "female", + "age": 50, + "address": { + "state": "Rhode Island", + "city": "Babb" + } + }, + { + "id": 5226, + "name": "Hillary Gardner", + "gender": "female", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Brenton" + } + }, + { + "id": 5227, + "name": "Caroline Foley", + "gender": "female", + "age": 72, + "address": { + "state": "Kentucky", + "city": "Colton" + } + }, + { + "id": 5228, + "name": "Waters Obrien", + "gender": "male", + "age": 18, + "address": { + "state": "Connecticut", + "city": "Boling" + } + }, + { + "id": 5229, + "name": "Mallory Johnson", + "gender": "female", + "age": 66, + "address": { + "state": "Iowa", + "city": "Waterloo" + } + }, + { + "id": 5230, + "name": "Lessie Duran", + "gender": "female", + "age": 24, + "address": { + "state": "California", + "city": "Kanauga" + } + }, + { + "id": 5231, + "name": "Selena Oconnor", + "gender": "female", + "age": 23, + "address": { + "state": "New Hampshire", + "city": "Chumuckla" + } + }, + { + "id": 5232, + "name": "Parsons Haley", + "gender": "male", + "age": 71, + "address": { + "state": "Oregon", + "city": "Zortman" + } + }, + { + "id": 5233, + "name": "Reynolds Chase", + "gender": "male", + "age": 28, + "address": { + "state": "Maine", + "city": "Orviston" + } + }, + { + "id": 5234, + "name": "Pena Yang", + "gender": "male", + "age": 64, + "address": { + "state": "Colorado", + "city": "Websterville" + } + }, + { + "id": 5235, + "name": "Eileen Giles", + "gender": "female", + "age": 25, + "address": { + "state": "South Carolina", + "city": "Canby" + } + }, + { + "id": 5236, + "name": "Mari Wall", + "gender": "female", + "age": 55, + "address": { + "state": "Delaware", + "city": "Newkirk" + } + }, + { + "id": 5237, + "name": "Norman Douglas", + "gender": "male", + "age": 20, + "address": { + "state": "Massachusetts", + "city": "Greenbush" + } + }, + { + "id": 5238, + "name": "Sondra Alston", + "gender": "female", + "age": 62, + "address": { + "state": "Virginia", + "city": "Alamo" + } + }, + { + "id": 5239, + "name": "Esther Palmer", + "gender": "female", + "age": 77, + "address": { + "state": "Pennsylvania", + "city": "Wiscon" + } + }, + { + "id": 5240, + "name": "Delacruz Whitley", + "gender": "male", + "age": 74, + "address": { + "state": "Tennessee", + "city": "Jackpot" + } + }, + { + "id": 5241, + "name": "Ford Hester", + "gender": "male", + "age": 55, + "address": { + "state": "Kansas", + "city": "Rivera" + } + }, + { + "id": 5242, + "name": "Dickerson Blanchard", + "gender": "male", + "age": 38, + "address": { + "state": "Wyoming", + "city": "Lawrence" + } + }, + { + "id": 5243, + "name": "Janine Buchanan", + "gender": "female", + "age": 52, + "address": { + "state": "Washington", + "city": "Eureka" + } + }, + { + "id": 5244, + "name": "Nicholson Hinton", + "gender": "male", + "age": 67, + "address": { + "state": "Georgia", + "city": "Jeff" + } + }, + { + "id": 5245, + "name": "Danielle Olsen", + "gender": "female", + "age": 62, + "address": { + "state": "Alaska", + "city": "Crucible" + } + }, + { + "id": 5246, + "name": "Rosemary Richards", + "gender": "female", + "age": 23, + "address": { + "state": "Florida", + "city": "Bedias" + } + }, + { + "id": 5247, + "name": "Wells Pennington", + "gender": "male", + "age": 61, + "address": { + "state": "North Carolina", + "city": "Wilsonia" + } + }, + { + "id": 5248, + "name": "Tucker Robles", + "gender": "male", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Nile" + } + }, + { + "id": 5249, + "name": "Marcie Acosta", + "gender": "female", + "age": 45, + "address": { + "state": "Texas", + "city": "Guthrie" + } + }, + { + "id": 5250, + "name": "Loretta Terry", + "gender": "female", + "age": 42, + "address": { + "state": "Wisconsin", + "city": "Gibsonia" + } + }, + { + "id": 5251, + "name": "Roseann Watkins", + "gender": "female", + "age": 41, + "address": { + "state": "Rhode Island", + "city": "Trucksville" + } + }, + { + "id": 5252, + "name": "Pat Fletcher", + "gender": "female", + "age": 27, + "address": { + "state": "Vermont", + "city": "Gwynn" + } + }, + { + "id": 5253, + "name": "Sheena Guthrie", + "gender": "female", + "age": 22, + "address": { + "state": "Michigan", + "city": "Fredericktown" + } + }, + { + "id": 5254, + "name": "Linda Best", + "gender": "female", + "age": 36, + "address": { + "state": "Iowa", + "city": "Munjor" + } + }, + { + "id": 5255, + "name": "Susanna Bright", + "gender": "female", + "age": 43, + "address": { + "state": "New Jersey", + "city": "Dupuyer" + } + }, + { + "id": 5256, + "name": "Donna Medina", + "gender": "female", + "age": 74, + "address": { + "state": "Minnesota", + "city": "Coleville" + } + }, + { + "id": 5257, + "name": "Marta Beach", + "gender": "female", + "age": 21, + "address": { + "state": "New Hampshire", + "city": "Seymour" + } + }, + { + "id": 5258, + "name": "Josephine Moon", + "gender": "female", + "age": 76, + "address": { + "state": "California", + "city": "Morriston" + } + }, + { + "id": 5259, + "name": "Meadows Owen", + "gender": "male", + "age": 71, + "address": { + "state": "Arkansas", + "city": "Sanborn" + } + }, + { + "id": 5260, + "name": "Kari Fulton", + "gender": "female", + "age": 59, + "address": { + "state": "Illinois", + "city": "Cleary" + } + }, + { + "id": 5261, + "name": "Kristine Castillo", + "gender": "female", + "age": 18, + "address": { + "state": "Louisiana", + "city": "Tryon" + } + }, + { + "id": 5262, + "name": "Marshall Padilla", + "gender": "male", + "age": 70, + "address": { + "state": "Utah", + "city": "Cecilia" + } + }, + { + "id": 5263, + "name": "Rosanna Gallagher", + "gender": "female", + "age": 70, + "address": { + "state": "Alabama", + "city": "Lawrence" + } + }, + { + "id": 5264, + "name": "Lucille Miller", + "gender": "female", + "age": 49, + "address": { + "state": "Tennessee", + "city": "Marenisco" + } + }, + { + "id": 5265, + "name": "Aimee Levine", + "gender": "female", + "age": 19, + "address": { + "state": "Maryland", + "city": "Dixonville" + } + }, + { + "id": 5266, + "name": "Hines Munoz", + "gender": "male", + "age": 64, + "address": { + "state": "Hawaii", + "city": "Graniteville" + } + }, + { + "id": 5267, + "name": "Rosalinda Nunez", + "gender": "female", + "age": 26, + "address": { + "state": "Virginia", + "city": "Townsend" + } + }, + { + "id": 5268, + "name": "Martinez Patton", + "gender": "male", + "age": 64, + "address": { + "state": "Idaho", + "city": "Edgar" + } + }, + { + "id": 5269, + "name": "Calhoun Clark", + "gender": "male", + "age": 60, + "address": { + "state": "Colorado", + "city": "Rockingham" + } + }, + { + "id": 5270, + "name": "Audra Pollard", + "gender": "female", + "age": 24, + "address": { + "state": "Mississippi", + "city": "Wescosville" + } + }, + { + "id": 5271, + "name": "Mccarty Gay", + "gender": "male", + "age": 80, + "address": { + "state": "Nevada", + "city": "Hampstead" + } + }, + { + "id": 5272, + "name": "Teri King", + "gender": "female", + "age": 72, + "address": { + "state": "Nebraska", + "city": "Stockdale" + } + }, + { + "id": 5273, + "name": "Stacey Combs", + "gender": "female", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Kimmell" + } + }, + { + "id": 5274, + "name": "Alvarado Byrd", + "gender": "male", + "age": 41, + "address": { + "state": "Massachusetts", + "city": "Bath" + } + }, + { + "id": 5275, + "name": "Galloway Lloyd", + "gender": "male", + "age": 31, + "address": { + "state": "New Mexico", + "city": "Eastvale" + } + }, + { + "id": 5276, + "name": "Williamson Obrien", + "gender": "male", + "age": 38, + "address": { + "state": "Kentucky", + "city": "Falmouth" + } + }, + { + "id": 5277, + "name": "Floyd Russell", + "gender": "male", + "age": 33, + "address": { + "state": "Ohio", + "city": "Stewartville" + } + }, + { + "id": 5278, + "name": "Carr Cote", + "gender": "male", + "age": 36, + "address": { + "state": "Missouri", + "city": "Temperanceville" + } + }, + { + "id": 5279, + "name": "Charmaine Mercado", + "gender": "female", + "age": 31, + "address": { + "state": "Oregon", + "city": "Diaperville" + } + }, + { + "id": 5280, + "name": "Curtis Fisher", + "gender": "male", + "age": 24, + "address": { + "state": "West Virginia", + "city": "Konterra" + } + }, + { + "id": 5281, + "name": "Tonia Odonnell", + "gender": "female", + "age": 32, + "address": { + "state": "Delaware", + "city": "Beyerville" + } + }, + { + "id": 5282, + "name": "Shaw Osborne", + "gender": "male", + "age": 50, + "address": { + "state": "Arizona", + "city": "Greenwich" + } + }, + { + "id": 5283, + "name": "Rojas Moore", + "gender": "male", + "age": 52, + "address": { + "state": "South Dakota", + "city": "Iola" + } + }, + { + "id": 5284, + "name": "Cook Anderson", + "gender": "male", + "age": 71, + "address": { + "state": "Montana", + "city": "Ryderwood" + } + }, + { + "id": 5285, + "name": "Randall Jacobs", + "gender": "male", + "age": 18, + "address": { + "state": "Pennsylvania", + "city": "Gordon" + } + }, + { + "id": 5286, + "name": "Erma Wright", + "gender": "female", + "age": 30, + "address": { + "state": "Indiana", + "city": "Bellfountain" + } + }, + { + "id": 5287, + "name": "Leila Wade", + "gender": "female", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Jenkinsville" + } + }, + { + "id": 5288, + "name": "Perry Byers", + "gender": "male", + "age": 40, + "address": { + "state": "Kansas", + "city": "Edenburg" + } + }, + { + "id": 5289, + "name": "Murray Howard", + "gender": "male", + "age": 48, + "address": { + "state": "New York", + "city": "Singer" + } + }, + { + "id": 5290, + "name": "Lindsey Williams", + "gender": "female", + "age": 80, + "address": { + "state": "Maine", + "city": "Norwood" + } + }, + { + "id": 5291, + "name": "Albert Oconnor", + "gender": "male", + "age": 22, + "address": { + "state": "Connecticut", + "city": "Greenfields" + } + }, + { + "id": 5292, + "name": "Knapp Horn", + "gender": "male", + "age": 81, + "address": { + "state": "Indiana", + "city": "Cliffside" + } + }, + { + "id": 5293, + "name": "Bolton Goff", + "gender": "male", + "age": 76, + "address": { + "state": "Texas", + "city": "Spokane" + } + }, + { + "id": 5294, + "name": "Dixon Humphrey", + "gender": "male", + "age": 28, + "address": { + "state": "Maryland", + "city": "Roeville" + } + }, + { + "id": 5295, + "name": "Michael Case", + "gender": "male", + "age": 54, + "address": { + "state": "Washington", + "city": "Silkworth" + } + }, + { + "id": 5296, + "name": "Darla Day", + "gender": "female", + "age": 82, + "address": { + "state": "Pennsylvania", + "city": "Defiance" + } + }, + { + "id": 5297, + "name": "Rhonda Whitley", + "gender": "female", + "age": 21, + "address": { + "state": "Alaska", + "city": "Gracey" + } + }, + { + "id": 5298, + "name": "Adams Rios", + "gender": "male", + "age": 36, + "address": { + "state": "Kansas", + "city": "Elizaville" + } + }, + { + "id": 5299, + "name": "Cobb Stanton", + "gender": "male", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Chloride" + } + }, + { + "id": 5300, + "name": "Mccarthy Rogers", + "gender": "male", + "age": 20, + "address": { + "state": "West Virginia", + "city": "Keyport" + } + }, + { + "id": 5301, + "name": "Frost Pennington", + "gender": "male", + "age": 63, + "address": { + "state": "Georgia", + "city": "Navarre" + } + }, + { + "id": 5302, + "name": "Sheree Dyer", + "gender": "female", + "age": 33, + "address": { + "state": "Montana", + "city": "Matheny" + } + }, + { + "id": 5303, + "name": "Lott Clayton", + "gender": "male", + "age": 31, + "address": { + "state": "Hawaii", + "city": "Dubois" + } + }, + { + "id": 5304, + "name": "Tanner Hall", + "gender": "male", + "age": 69, + "address": { + "state": "New Hampshire", + "city": "Kanauga" + } + }, + { + "id": 5305, + "name": "Candice Arnold", + "gender": "female", + "age": 80, + "address": { + "state": "California", + "city": "Madrid" + } + }, + { + "id": 5306, + "name": "Vasquez Cummings", + "gender": "male", + "age": 71, + "address": { + "state": "New York", + "city": "Blodgett" + } + }, + { + "id": 5307, + "name": "Leonor Hendrix", + "gender": "female", + "age": 62, + "address": { + "state": "Idaho", + "city": "Wescosville" + } + }, + { + "id": 5308, + "name": "Mollie Norman", + "gender": "female", + "age": 57, + "address": { + "state": "Connecticut", + "city": "Joes" + } + }, + { + "id": 5309, + "name": "Leon Cain", + "gender": "male", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Rockhill" + } + }, + { + "id": 5310, + "name": "Rosalie Curry", + "gender": "female", + "age": 81, + "address": { + "state": "Michigan", + "city": "Sharon" + } + }, + { + "id": 5311, + "name": "Rosella Chambers", + "gender": "female", + "age": 26, + "address": { + "state": "Louisiana", + "city": "Wollochet" + } + }, + { + "id": 5312, + "name": "Sheppard Lindsey", + "gender": "male", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Detroit" + } + }, + { + "id": 5313, + "name": "Karina Mcmillan", + "gender": "female", + "age": 44, + "address": { + "state": "Florida", + "city": "Maury" + } + }, + { + "id": 5314, + "name": "Vaughn Vasquez", + "gender": "male", + "age": 46, + "address": { + "state": "Nebraska", + "city": "Glidden" + } + }, + { + "id": 5315, + "name": "Kristie Velez", + "gender": "female", + "age": 74, + "address": { + "state": "Arizona", + "city": "Springdale" + } + }, + { + "id": 5316, + "name": "Judith Blackburn", + "gender": "female", + "age": 57, + "address": { + "state": "Delaware", + "city": "Waiohinu" + } + }, + { + "id": 5317, + "name": "Marylou Donovan", + "gender": "female", + "age": 77, + "address": { + "state": "Kentucky", + "city": "Blende" + } + }, + { + "id": 5318, + "name": "Celina Torres", + "gender": "female", + "age": 33, + "address": { + "state": "Wisconsin", + "city": "Edenburg" + } + }, + { + "id": 5319, + "name": "Gloria Espinoza", + "gender": "female", + "age": 78, + "address": { + "state": "Alabama", + "city": "Boonville" + } + }, + { + "id": 5320, + "name": "Osborn Mckinney", + "gender": "male", + "age": 74, + "address": { + "state": "Oklahoma", + "city": "Wakarusa" + } + }, + { + "id": 5321, + "name": "Ellison James", + "gender": "male", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Delwood" + } + }, + { + "id": 5322, + "name": "Gwendolyn Montgomery", + "gender": "female", + "age": 41, + "address": { + "state": "Illinois", + "city": "Nash" + } + }, + { + "id": 5323, + "name": "Ayers Russell", + "gender": "male", + "age": 65, + "address": { + "state": "Oregon", + "city": "Shelby" + } + }, + { + "id": 5324, + "name": "Roxie Reilly", + "gender": "female", + "age": 56, + "address": { + "state": "North Carolina", + "city": "Chamizal" + } + }, + { + "id": 5325, + "name": "Lawson Estes", + "gender": "male", + "age": 50, + "address": { + "state": "Massachusetts", + "city": "Cochranville" + } + }, + { + "id": 5326, + "name": "Shari Calhoun", + "gender": "female", + "age": 75, + "address": { + "state": "Iowa", + "city": "Albany" + } + }, + { + "id": 5327, + "name": "Jewel Forbes", + "gender": "female", + "age": 18, + "address": { + "state": "Utah", + "city": "Bonanza" + } + }, + { + "id": 5328, + "name": "Gail Decker", + "gender": "female", + "age": 26, + "address": { + "state": "South Carolina", + "city": "Juntura" + } + }, + { + "id": 5329, + "name": "Slater Larsen", + "gender": "male", + "age": 62, + "address": { + "state": "Mississippi", + "city": "Outlook" + } + }, + { + "id": 5330, + "name": "Dejesus Blankenship", + "gender": "male", + "age": 77, + "address": { + "state": "Virginia", + "city": "Vale" + } + }, + { + "id": 5331, + "name": "Corine Bean", + "gender": "female", + "age": 66, + "address": { + "state": "Maine", + "city": "Roberts" + } + }, + { + "id": 5332, + "name": "Ewing Wilcox", + "gender": "male", + "age": 62, + "address": { + "state": "Vermont", + "city": "Coloma" + } + }, + { + "id": 5333, + "name": "Patrice Sutton", + "gender": "female", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Austinburg" + } + }, + { + "id": 5334, + "name": "Rivera Williams", + "gender": "male", + "age": 59, + "address": { + "state": "Colorado", + "city": "Jessie" + } + }, + { + "id": 5335, + "name": "Francisca Giles", + "gender": "female", + "age": 69, + "address": { + "state": "Minnesota", + "city": "Urie" + } + }, + { + "id": 5336, + "name": "Rosemary Macdonald", + "gender": "female", + "age": 27, + "address": { + "state": "Ohio", + "city": "Why" + } + }, + { + "id": 5337, + "name": "Conley Gross", + "gender": "male", + "age": 67, + "address": { + "state": "Arkansas", + "city": "Bluffview" + } + }, + { + "id": 5338, + "name": "Delgado Calderon", + "gender": "male", + "age": 29, + "address": { + "state": "Nevada", + "city": "Guthrie" + } + }, + { + "id": 5339, + "name": "Ronda Henson", + "gender": "female", + "age": 24, + "address": { + "state": "North Dakota", + "city": "Vallonia" + } + }, + { + "id": 5340, + "name": "Noel Mcgowan", + "gender": "male", + "age": 26, + "address": { + "state": "Missouri", + "city": "Guilford" + } + }, + { + "id": 5341, + "name": "Sims Saunders", + "gender": "male", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Bascom" + } + }, + { + "id": 5342, + "name": "Taylor Sosa", + "gender": "female", + "age": 82, + "address": { + "state": "Massachusetts", + "city": "Wikieup" + } + }, + { + "id": 5343, + "name": "Leach Porter", + "gender": "male", + "age": 58, + "address": { + "state": "South Dakota", + "city": "Wheaton" + } + }, + { + "id": 5344, + "name": "Marisol Foley", + "gender": "female", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Lutsen" + } + }, + { + "id": 5345, + "name": "Howe Jones", + "gender": "male", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Dubois" + } + }, + { + "id": 5346, + "name": "Kidd Pugh", + "gender": "male", + "age": 35, + "address": { + "state": "Wisconsin", + "city": "Sharon" + } + }, + { + "id": 5347, + "name": "Anderson Heath", + "gender": "male", + "age": 49, + "address": { + "state": "Indiana", + "city": "Groton" + } + }, + { + "id": 5348, + "name": "Tamara Greer", + "gender": "female", + "age": 77, + "address": { + "state": "Wyoming", + "city": "Yukon" + } + }, + { + "id": 5349, + "name": "Waters Vasquez", + "gender": "male", + "age": 63, + "address": { + "state": "California", + "city": "Bellfountain" + } + }, + { + "id": 5350, + "name": "Richardson Mcdaniel", + "gender": "male", + "age": 74, + "address": { + "state": "Missouri", + "city": "Marion" + } + }, + { + "id": 5351, + "name": "Haynes Frazier", + "gender": "male", + "age": 64, + "address": { + "state": "Maryland", + "city": "Robinette" + } + }, + { + "id": 5352, + "name": "Lara Myers", + "gender": "male", + "age": 57, + "address": { + "state": "New Mexico", + "city": "Allensworth" + } + }, + { + "id": 5353, + "name": "Ward Bauer", + "gender": "male", + "age": 57, + "address": { + "state": "Oregon", + "city": "Cliffside" + } + }, + { + "id": 5354, + "name": "Madeleine Alvarez", + "gender": "female", + "age": 78, + "address": { + "state": "Utah", + "city": "Tooleville" + } + }, + { + "id": 5355, + "name": "Marianne Guerrero", + "gender": "female", + "age": 31, + "address": { + "state": "Iowa", + "city": "Camino" + } + }, + { + "id": 5356, + "name": "Solis Chandler", + "gender": "male", + "age": 22, + "address": { + "state": "Louisiana", + "city": "Coaldale" + } + }, + { + "id": 5357, + "name": "Tillman Stevens", + "gender": "male", + "age": 45, + "address": { + "state": "Hawaii", + "city": "Lynn" + } + }, + { + "id": 5358, + "name": "Buck Valenzuela", + "gender": "male", + "age": 75, + "address": { + "state": "Arizona", + "city": "Tuttle" + } + }, + { + "id": 5359, + "name": "Mccarthy Fletcher", + "gender": "male", + "age": 77, + "address": { + "state": "Nebraska", + "city": "Kerby" + } + }, + { + "id": 5360, + "name": "Abbott Zimmerman", + "gender": "male", + "age": 72, + "address": { + "state": "Alabama", + "city": "Nipinnawasee" + } + }, + { + "id": 5361, + "name": "Mcfarland Maxwell", + "gender": "male", + "age": 65, + "address": { + "state": "Alaska", + "city": "Greenwich" + } + }, + { + "id": 5362, + "name": "Merritt Delaney", + "gender": "male", + "age": 29, + "address": { + "state": "Pennsylvania", + "city": "Bend" + } + }, + { + "id": 5363, + "name": "Hayden Willis", + "gender": "male", + "age": 23, + "address": { + "state": "Ohio", + "city": "Chesterfield" + } + }, + { + "id": 5364, + "name": "Sylvia Carey", + "gender": "female", + "age": 42, + "address": { + "state": "Nevada", + "city": "Enoree" + } + }, + { + "id": 5365, + "name": "Joyce Evans", + "gender": "male", + "age": 66, + "address": { + "state": "South Carolina", + "city": "Saranap" + } + }, + { + "id": 5366, + "name": "Wilkerson Dixon", + "gender": "male", + "age": 34, + "address": { + "state": "Montana", + "city": "Marne" + } + }, + { + "id": 5367, + "name": "Anastasia Beach", + "gender": "female", + "age": 66, + "address": { + "state": "New Hampshire", + "city": "Tuskahoma" + } + }, + { + "id": 5368, + "name": "Soto Stevenson", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Keller" + } + }, + { + "id": 5369, + "name": "Latisha Neal", + "gender": "female", + "age": 23, + "address": { + "state": "North Dakota", + "city": "Nogal" + } + }, + { + "id": 5370, + "name": "Reva Gonzales", + "gender": "female", + "age": 75, + "address": { + "state": "Idaho", + "city": "Spokane" + } + }, + { + "id": 5371, + "name": "Chavez Preston", + "gender": "male", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Temperanceville" + } + }, + { + "id": 5372, + "name": "Berg Haynes", + "gender": "male", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Ironton" + } + }, + { + "id": 5373, + "name": "Roslyn Key", + "gender": "female", + "age": 62, + "address": { + "state": "Kansas", + "city": "Columbus" + } + }, + { + "id": 5374, + "name": "Tia Fernandez", + "gender": "female", + "age": 23, + "address": { + "state": "Texas", + "city": "Villarreal" + } + }, + { + "id": 5375, + "name": "Hays Johnson", + "gender": "male", + "age": 52, + "address": { + "state": "Washington", + "city": "Coldiron" + } + }, + { + "id": 5376, + "name": "Rasmussen Nieves", + "gender": "male", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Carrsville" + } + }, + { + "id": 5377, + "name": "Goff Duke", + "gender": "male", + "age": 31, + "address": { + "state": "Maine", + "city": "Monument" + } + }, + { + "id": 5378, + "name": "Vasquez Mayo", + "gender": "male", + "age": 50, + "address": { + "state": "Colorado", + "city": "Grayhawk" + } + }, + { + "id": 5379, + "name": "John Mccullough", + "gender": "female", + "age": 40, + "address": { + "state": "Virginia", + "city": "Sanford" + } + }, + { + "id": 5380, + "name": "Mcleod Bentley", + "gender": "male", + "age": 42, + "address": { + "state": "New York", + "city": "Dola" + } + }, + { + "id": 5381, + "name": "Hartman Goodman", + "gender": "male", + "age": 74, + "address": { + "state": "Delaware", + "city": "Tetherow" + } + }, + { + "id": 5382, + "name": "Myers Nunez", + "gender": "male", + "age": 41, + "address": { + "state": "Michigan", + "city": "Sena" + } + }, + { + "id": 5383, + "name": "Hopper Kelley", + "gender": "male", + "age": 71, + "address": { + "state": "Connecticut", + "city": "Fidelis" + } + }, + { + "id": 5384, + "name": "Gill Ray", + "gender": "male", + "age": 79, + "address": { + "state": "Florida", + "city": "Thynedale" + } + }, + { + "id": 5385, + "name": "Henson Kennedy", + "gender": "male", + "age": 72, + "address": { + "state": "Illinois", + "city": "Rosedale" + } + }, + { + "id": 5386, + "name": "Gale Reid", + "gender": "female", + "age": 19, + "address": { + "state": "Kentucky", + "city": "Corinne" + } + }, + { + "id": 5387, + "name": "Thompson Barnett", + "gender": "male", + "age": 35, + "address": { + "state": "Rhode Island", + "city": "Bedias" + } + }, + { + "id": 5388, + "name": "Erika Kirk", + "gender": "female", + "age": 80, + "address": { + "state": "North Carolina", + "city": "Suitland" + } + }, + { + "id": 5389, + "name": "Bonita Hendrix", + "gender": "female", + "age": 19, + "address": { + "state": "Vermont", + "city": "Tampico" + } + }, + { + "id": 5390, + "name": "Sasha Calhoun", + "gender": "female", + "age": 35, + "address": { + "state": "New York", + "city": "Roosevelt" + } + }, + { + "id": 5391, + "name": "Christi Morales", + "gender": "female", + "age": 34, + "address": { + "state": "Arkansas", + "city": "Springville" + } + }, + { + "id": 5392, + "name": "Nichole Lowery", + "gender": "female", + "age": 38, + "address": { + "state": "Oklahoma", + "city": "Brambleton" + } + }, + { + "id": 5393, + "name": "Gardner Guzman", + "gender": "male", + "age": 46, + "address": { + "state": "Louisiana", + "city": "Ferney" + } + }, + { + "id": 5394, + "name": "Jerry Evans", + "gender": "female", + "age": 43, + "address": { + "state": "Tennessee", + "city": "Weeksville" + } + }, + { + "id": 5395, + "name": "Baldwin Bryant", + "gender": "male", + "age": 60, + "address": { + "state": "Georgia", + "city": "Cutter" + } + }, + { + "id": 5396, + "name": "Hamilton Drake", + "gender": "male", + "age": 21, + "address": { + "state": "South Carolina", + "city": "Darlington" + } + }, + { + "id": 5397, + "name": "Leila Carver", + "gender": "female", + "age": 30, + "address": { + "state": "Vermont", + "city": "Otranto" + } + }, + { + "id": 5398, + "name": "Figueroa Mckenzie", + "gender": "male", + "age": 46, + "address": { + "state": "Nevada", + "city": "Cetronia" + } + }, + { + "id": 5399, + "name": "Malone Knapp", + "gender": "male", + "age": 54, + "address": { + "state": "New Mexico", + "city": "Stewartville" + } + }, + { + "id": 5400, + "name": "Bryan Brooks", + "gender": "male", + "age": 43, + "address": { + "state": "Utah", + "city": "Boomer" + } + }, + { + "id": 5401, + "name": "Shepherd Mcbride", + "gender": "male", + "age": 39, + "address": { + "state": "Indiana", + "city": "Virgie" + } + }, + { + "id": 5402, + "name": "Whitfield Holloway", + "gender": "male", + "age": 45, + "address": { + "state": "North Dakota", + "city": "Dexter" + } + }, + { + "id": 5403, + "name": "Leanna Emerson", + "gender": "female", + "age": 75, + "address": { + "state": "West Virginia", + "city": "Convent" + } + }, + { + "id": 5404, + "name": "Rebecca Pena", + "gender": "female", + "age": 80, + "address": { + "state": "Washington", + "city": "Roland" + } + }, + { + "id": 5405, + "name": "Lynn Black", + "gender": "male", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Clarence" + } + }, + { + "id": 5406, + "name": "Janie Holmes", + "gender": "female", + "age": 54, + "address": { + "state": "Kansas", + "city": "Garnet" + } + }, + { + "id": 5407, + "name": "Alba Cooley", + "gender": "female", + "age": 80, + "address": { + "state": "Maine", + "city": "Summerset" + } + }, + { + "id": 5408, + "name": "Ava Flores", + "gender": "female", + "age": 68, + "address": { + "state": "Arizona", + "city": "Bison" + } + }, + { + "id": 5409, + "name": "Moreno Larsen", + "gender": "male", + "age": 81, + "address": { + "state": "Connecticut", + "city": "Dupuyer" + } + }, + { + "id": 5410, + "name": "Hilary Sawyer", + "gender": "female", + "age": 43, + "address": { + "state": "Idaho", + "city": "Bridgetown" + } + }, + { + "id": 5411, + "name": "Mariana Salazar", + "gender": "female", + "age": 65, + "address": { + "state": "Maryland", + "city": "Chamizal" + } + }, + { + "id": 5412, + "name": "Holman Williams", + "gender": "male", + "age": 76, + "address": { + "state": "Alaska", + "city": "Katonah" + } + }, + { + "id": 5413, + "name": "Maddox Ellis", + "gender": "male", + "age": 72, + "address": { + "state": "Illinois", + "city": "Lydia" + } + }, + { + "id": 5414, + "name": "Barry Gates", + "gender": "male", + "age": 60, + "address": { + "state": "Nebraska", + "city": "Newry" + } + }, + { + "id": 5415, + "name": "Vonda Dillard", + "gender": "female", + "age": 27, + "address": { + "state": "Delaware", + "city": "Kempton" + } + }, + { + "id": 5416, + "name": "Wells Curtis", + "gender": "male", + "age": 68, + "address": { + "state": "Colorado", + "city": "Sultana" + } + }, + { + "id": 5417, + "name": "Coffey Bush", + "gender": "male", + "age": 36, + "address": { + "state": "Texas", + "city": "Basye" + } + }, + { + "id": 5418, + "name": "Claudia Hobbs", + "gender": "female", + "age": 18, + "address": { + "state": "Hawaii", + "city": "Avalon" + } + }, + { + "id": 5419, + "name": "Stacey Thomas", + "gender": "female", + "age": 34, + "address": { + "state": "Missouri", + "city": "Harrison" + } + }, + { + "id": 5420, + "name": "Graves Dawson", + "gender": "male", + "age": 53, + "address": { + "state": "California", + "city": "Wyano" + } + }, + { + "id": 5421, + "name": "Marlene Acevedo", + "gender": "female", + "age": 39, + "address": { + "state": "Virginia", + "city": "Westwood" + } + }, + { + "id": 5422, + "name": "Barbra Mcmillan", + "gender": "female", + "age": 82, + "address": { + "state": "Rhode Island", + "city": "Dahlen" + } + }, + { + "id": 5423, + "name": "Jenny Parks", + "gender": "female", + "age": 17, + "address": { + "state": "Oregon", + "city": "Starks" + } + }, + { + "id": 5424, + "name": "Chandler Mays", + "gender": "male", + "age": 59, + "address": { + "state": "Kentucky", + "city": "Bendon" + } + }, + { + "id": 5425, + "name": "Laurel Donaldson", + "gender": "female", + "age": 67, + "address": { + "state": "New Jersey", + "city": "Tampico" + } + }, + { + "id": 5426, + "name": "Carrillo Davidson", + "gender": "male", + "age": 44, + "address": { + "state": "Alabama", + "city": "Reno" + } + }, + { + "id": 5427, + "name": "Benita Lester", + "gender": "female", + "age": 75, + "address": { + "state": "Minnesota", + "city": "Magnolia" + } + }, + { + "id": 5428, + "name": "Christina Morin", + "gender": "female", + "age": 21, + "address": { + "state": "New Hampshire", + "city": "Chemung" + } + }, + { + "id": 5429, + "name": "Hester York", + "gender": "male", + "age": 68, + "address": { + "state": "Iowa", + "city": "Wadsworth" + } + }, + { + "id": 5430, + "name": "Bartlett Day", + "gender": "male", + "age": 81, + "address": { + "state": "Wyoming", + "city": "Flintville" + } + }, + { + "id": 5431, + "name": "Tabitha Boyd", + "gender": "female", + "age": 24, + "address": { + "state": "Florida", + "city": "Buxton" + } + }, + { + "id": 5432, + "name": "Frederick Lynn", + "gender": "male", + "age": 48, + "address": { + "state": "Wisconsin", + "city": "Cade" + } + }, + { + "id": 5433, + "name": "Jeanine Park", + "gender": "female", + "age": 70, + "address": { + "state": "Michigan", + "city": "Bannock" + } + }, + { + "id": 5434, + "name": "Sanford Brennan", + "gender": "male", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Spokane" + } + }, + { + "id": 5435, + "name": "Hunt Frederick", + "gender": "male", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Manchester" + } + }, + { + "id": 5436, + "name": "Edwards Monroe", + "gender": "male", + "age": 32, + "address": { + "state": "Montana", + "city": "Oneida" + } + }, + { + "id": 5437, + "name": "Jackie Delacruz", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Groveville" + } + }, + { + "id": 5438, + "name": "Heidi Campbell", + "gender": "female", + "age": 67, + "address": { + "state": "North Carolina", + "city": "Blende" + } + }, + { + "id": 5439, + "name": "Marietta Bentley", + "gender": "female", + "age": 28, + "address": { + "state": "Missouri", + "city": "Bartonsville" + } + }, + { + "id": 5440, + "name": "Chambers Witt", + "gender": "male", + "age": 67, + "address": { + "state": "Louisiana", + "city": "Linwood" + } + }, + { + "id": 5441, + "name": "Celina Hill", + "gender": "female", + "age": 60, + "address": { + "state": "Nevada", + "city": "Rivera" + } + }, + { + "id": 5442, + "name": "Richardson Huff", + "gender": "male", + "age": 77, + "address": { + "state": "Vermont", + "city": "Echo" + } + }, + { + "id": 5443, + "name": "Clarice Duke", + "gender": "female", + "age": 81, + "address": { + "state": "Ohio", + "city": "Sparkill" + } + }, + { + "id": 5444, + "name": "Williamson Mayo", + "gender": "male", + "age": 46, + "address": { + "state": "Minnesota", + "city": "Conestoga" + } + }, + { + "id": 5445, + "name": "Lela Tucker", + "gender": "female", + "age": 46, + "address": { + "state": "Alabama", + "city": "Calvary" + } + }, + { + "id": 5446, + "name": "May Love", + "gender": "male", + "age": 45, + "address": { + "state": "Oregon", + "city": "Unionville" + } + }, + { + "id": 5447, + "name": "Kirby Puckett", + "gender": "male", + "age": 61, + "address": { + "state": "West Virginia", + "city": "Osage" + } + }, + { + "id": 5448, + "name": "Larsen Day", + "gender": "male", + "age": 75, + "address": { + "state": "New Hampshire", + "city": "Jacksonwald" + } + }, + { + "id": 5449, + "name": "Dianna Wiley", + "gender": "female", + "age": 28, + "address": { + "state": "North Carolina", + "city": "Southview" + } + }, + { + "id": 5450, + "name": "Tessa Alvarado", + "gender": "female", + "age": 50, + "address": { + "state": "Alaska", + "city": "Wiscon" + } + }, + { + "id": 5451, + "name": "Dillard Gregory", + "gender": "male", + "age": 30, + "address": { + "state": "Florida", + "city": "Navarre" + } + }, + { + "id": 5452, + "name": "Sadie Castro", + "gender": "female", + "age": 62, + "address": { + "state": "Kansas", + "city": "Wanship" + } + }, + { + "id": 5453, + "name": "Beth Crosby", + "gender": "female", + "age": 48, + "address": { + "state": "Pennsylvania", + "city": "Caroleen" + } + }, + { + "id": 5454, + "name": "Reilly Miller", + "gender": "male", + "age": 33, + "address": { + "state": "Montana", + "city": "Waiohinu" + } + }, + { + "id": 5455, + "name": "Powers Duran", + "gender": "male", + "age": 48, + "address": { + "state": "South Carolina", + "city": "Chalfant" + } + }, + { + "id": 5456, + "name": "Barbra Craig", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Ivanhoe" + } + }, + { + "id": 5457, + "name": "Herman Moreno", + "gender": "male", + "age": 32, + "address": { + "state": "Maryland", + "city": "Craig" + } + }, + { + "id": 5458, + "name": "Bush Daugherty", + "gender": "male", + "age": 75, + "address": { + "state": "New Mexico", + "city": "Strykersville" + } + }, + { + "id": 5459, + "name": "Kimberly Martinez", + "gender": "female", + "age": 59, + "address": { + "state": "Wyoming", + "city": "Johnsonburg" + } + }, + { + "id": 5460, + "name": "Bishop Welch", + "gender": "male", + "age": 34, + "address": { + "state": "Kentucky", + "city": "Waterford" + } + }, + { + "id": 5461, + "name": "Nina Sykes", + "gender": "female", + "age": 50, + "address": { + "state": "Tennessee", + "city": "Kraemer" + } + }, + { + "id": 5462, + "name": "Barnett Fitzpatrick", + "gender": "male", + "age": 72, + "address": { + "state": "Colorado", + "city": "Leola" + } + }, + { + "id": 5463, + "name": "Sosa Craft", + "gender": "male", + "age": 72, + "address": { + "state": "Iowa", + "city": "Wattsville" + } + }, + { + "id": 5464, + "name": "Marguerite Griffith", + "gender": "female", + "age": 17, + "address": { + "state": "South Dakota", + "city": "Lavalette" + } + }, + { + "id": 5465, + "name": "Vang Mosley", + "gender": "male", + "age": 43, + "address": { + "state": "Georgia", + "city": "Walland" + } + }, + { + "id": 5466, + "name": "Dorthy Farrell", + "gender": "female", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Morgandale" + } + }, + { + "id": 5467, + "name": "Minerva Mccarthy", + "gender": "female", + "age": 25, + "address": { + "state": "Wisconsin", + "city": "Tioga" + } + }, + { + "id": 5468, + "name": "Ashley Gallegos", + "gender": "female", + "age": 24, + "address": { + "state": "Illinois", + "city": "Bowie" + } + }, + { + "id": 5469, + "name": "Eliza Kerr", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Townsend" + } + }, + { + "id": 5470, + "name": "Copeland Velazquez", + "gender": "male", + "age": 34, + "address": { + "state": "Rhode Island", + "city": "Jeff" + } + }, + { + "id": 5471, + "name": "Long Merrill", + "gender": "male", + "age": 21, + "address": { + "state": "Utah", + "city": "Stouchsburg" + } + }, + { + "id": 5472, + "name": "Mona Watson", + "gender": "female", + "age": 33, + "address": { + "state": "Indiana", + "city": "Homeland" + } + }, + { + "id": 5473, + "name": "Gina Mccall", + "gender": "female", + "age": 37, + "address": { + "state": "Washington", + "city": "Edneyville" + } + }, + { + "id": 5474, + "name": "Pamela Dudley", + "gender": "female", + "age": 65, + "address": { + "state": "Maine", + "city": "Camptown" + } + }, + { + "id": 5475, + "name": "Sawyer Moses", + "gender": "male", + "age": 72, + "address": { + "state": "Texas", + "city": "Juntura" + } + }, + { + "id": 5476, + "name": "Palmer Rocha", + "gender": "male", + "age": 60, + "address": { + "state": "New York", + "city": "Noblestown" + } + }, + { + "id": 5477, + "name": "Leta Anthony", + "gender": "female", + "age": 65, + "address": { + "state": "North Dakota", + "city": "Glenbrook" + } + }, + { + "id": 5478, + "name": "Millie Massey", + "gender": "female", + "age": 71, + "address": { + "state": "Connecticut", + "city": "Topaz" + } + }, + { + "id": 5479, + "name": "Dominguez Bush", + "gender": "male", + "age": 28, + "address": { + "state": "Arizona", + "city": "Fingerville" + } + }, + { + "id": 5480, + "name": "Hutchinson Stuart", + "gender": "male", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Herbster" + } + }, + { + "id": 5481, + "name": "Lucille Rosa", + "gender": "female", + "age": 76, + "address": { + "state": "Oklahoma", + "city": "Joppa" + } + }, + { + "id": 5482, + "name": "Corrine Justice", + "gender": "female", + "age": 54, + "address": { + "state": "Delaware", + "city": "Wakulla" + } + }, + { + "id": 5483, + "name": "Keisha Gibbs", + "gender": "female", + "age": 68, + "address": { + "state": "Mississippi", + "city": "Salunga" + } + }, + { + "id": 5484, + "name": "Cooper Barnes", + "gender": "male", + "age": 67, + "address": { + "state": "Idaho", + "city": "Convent" + } + }, + { + "id": 5485, + "name": "Melisa Heath", + "gender": "female", + "age": 36, + "address": { + "state": "Hawaii", + "city": "Eagletown" + } + }, + { + "id": 5486, + "name": "Michelle Greene", + "gender": "female", + "age": 42, + "address": { + "state": "Michigan", + "city": "Interlochen" + } + }, + { + "id": 5487, + "name": "Horton Richards", + "gender": "male", + "age": 57, + "address": { + "state": "New Jersey", + "city": "Starks" + } + }, + { + "id": 5488, + "name": "Rowe Waller", + "gender": "male", + "age": 39, + "address": { + "state": "South Carolina", + "city": "Dante" + } + }, + { + "id": 5489, + "name": "Bolton Cash", + "gender": "male", + "age": 57, + "address": { + "state": "Oregon", + "city": "Gambrills" + } + }, + { + "id": 5490, + "name": "Herring Cooke", + "gender": "male", + "age": 73, + "address": { + "state": "Pennsylvania", + "city": "Spokane" + } + }, + { + "id": 5491, + "name": "Angelica Walls", + "gender": "female", + "age": 62, + "address": { + "state": "New York", + "city": "Cochranville" + } + }, + { + "id": 5492, + "name": "Sharpe Calderon", + "gender": "male", + "age": 68, + "address": { + "state": "Alaska", + "city": "Monument" + } + }, + { + "id": 5493, + "name": "Barton Hayes", + "gender": "male", + "age": 52, + "address": { + "state": "Rhode Island", + "city": "Cashtown" + } + }, + { + "id": 5494, + "name": "Farley Vinson", + "gender": "male", + "age": 18, + "address": { + "state": "Missouri", + "city": "Delco" + } + }, + { + "id": 5495, + "name": "Mack Burns", + "gender": "male", + "age": 79, + "address": { + "state": "Wisconsin", + "city": "Ezel" + } + }, + { + "id": 5496, + "name": "Leanne Hammond", + "gender": "female", + "age": 23, + "address": { + "state": "New Hampshire", + "city": "Belvoir" + } + }, + { + "id": 5497, + "name": "Nunez Ware", + "gender": "male", + "age": 66, + "address": { + "state": "North Dakota", + "city": "Fairforest" + } + }, + { + "id": 5498, + "name": "Mcmillan Simon", + "gender": "male", + "age": 47, + "address": { + "state": "Arkansas", + "city": "Allamuchy" + } + }, + { + "id": 5499, + "name": "Schultz Norman", + "gender": "male", + "age": 21, + "address": { + "state": "Alabama", + "city": "Bangor" + } + }, + { + "id": 5500, + "name": "Figueroa West", + "gender": "male", + "age": 27, + "address": { + "state": "Wyoming", + "city": "Riegelwood" + } + }, + { + "id": 5501, + "name": "Elaine Witt", + "gender": "female", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Collins" + } + }, + { + "id": 5502, + "name": "Guy Williamson", + "gender": "male", + "age": 50, + "address": { + "state": "Iowa", + "city": "Jardine" + } + }, + { + "id": 5503, + "name": "Edwina Wong", + "gender": "female", + "age": 34, + "address": { + "state": "Virginia", + "city": "Nipinnawasee" + } + }, + { + "id": 5504, + "name": "Huffman Cameron", + "gender": "male", + "age": 63, + "address": { + "state": "Oklahoma", + "city": "Marbury" + } + }, + { + "id": 5505, + "name": "Rebekah Roy", + "gender": "female", + "age": 24, + "address": { + "state": "Louisiana", + "city": "Reno" + } + }, + { + "id": 5506, + "name": "Karla Copeland", + "gender": "female", + "age": 47, + "address": { + "state": "Arizona", + "city": "Chumuckla" + } + }, + { + "id": 5507, + "name": "Jill Hays", + "gender": "female", + "age": 78, + "address": { + "state": "South Dakota", + "city": "Fostoria" + } + }, + { + "id": 5508, + "name": "Lynch Sutton", + "gender": "male", + "age": 68, + "address": { + "state": "Mississippi", + "city": "Williamson" + } + }, + { + "id": 5509, + "name": "Virginia Gould", + "gender": "female", + "age": 42, + "address": { + "state": "Nebraska", + "city": "Chamizal" + } + }, + { + "id": 5510, + "name": "Luann Romero", + "gender": "female", + "age": 20, + "address": { + "state": "Maine", + "city": "Woodburn" + } + }, + { + "id": 5511, + "name": "Johns Lyons", + "gender": "male", + "age": 40, + "address": { + "state": "Indiana", + "city": "Caroleen" + } + }, + { + "id": 5512, + "name": "Dollie Blackburn", + "gender": "female", + "age": 23, + "address": { + "state": "California", + "city": "Weeksville" + } + }, + { + "id": 5513, + "name": "Weiss Berg", + "gender": "male", + "age": 29, + "address": { + "state": "Maryland", + "city": "Sharon" + } + }, + { + "id": 5514, + "name": "Georgette Osborn", + "gender": "female", + "age": 52, + "address": { + "state": "Delaware", + "city": "Caroline" + } + }, + { + "id": 5515, + "name": "Knapp Stephenson", + "gender": "male", + "age": 68, + "address": { + "state": "Michigan", + "city": "Savannah" + } + }, + { + "id": 5516, + "name": "Willie Allison", + "gender": "female", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Glidden" + } + }, + { + "id": 5517, + "name": "Kristen Hyde", + "gender": "female", + "age": 66, + "address": { + "state": "Texas", + "city": "Beason" + } + }, + { + "id": 5518, + "name": "Mcdowell Allen", + "gender": "male", + "age": 76, + "address": { + "state": "Vermont", + "city": "Naomi" + } + }, + { + "id": 5519, + "name": "Hines Wheeler", + "gender": "male", + "age": 23, + "address": { + "state": "Kansas", + "city": "Edgewater" + } + }, + { + "id": 5520, + "name": "Ellis Benjamin", + "gender": "male", + "age": 18, + "address": { + "state": "Montana", + "city": "Verdi" + } + }, + { + "id": 5521, + "name": "Bridgett Stone", + "gender": "female", + "age": 17, + "address": { + "state": "Utah", + "city": "Ladera" + } + }, + { + "id": 5522, + "name": "Amber Wolf", + "gender": "female", + "age": 48, + "address": { + "state": "Tennessee", + "city": "Yonah" + } + }, + { + "id": 5523, + "name": "Klein Mayer", + "gender": "male", + "age": 70, + "address": { + "state": "West Virginia", + "city": "Caln" + } + }, + { + "id": 5524, + "name": "Meyer Dunlap", + "gender": "male", + "age": 79, + "address": { + "state": "Hawaii", + "city": "Cotopaxi" + } + }, + { + "id": 5525, + "name": "Shepard Frederick", + "gender": "male", + "age": 18, + "address": { + "state": "Colorado", + "city": "Brethren" + } + }, + { + "id": 5526, + "name": "Levy Gutierrez", + "gender": "male", + "age": 48, + "address": { + "state": "Washington", + "city": "Dunbar" + } + }, + { + "id": 5527, + "name": "Lacey Aguilar", + "gender": "female", + "age": 43, + "address": { + "state": "Connecticut", + "city": "Greensburg" + } + }, + { + "id": 5528, + "name": "Santiago Cummings", + "gender": "male", + "age": 43, + "address": { + "state": "Nevada", + "city": "Chase" + } + }, + { + "id": 5529, + "name": "Brewer Pratt", + "gender": "male", + "age": 18, + "address": { + "state": "Ohio", + "city": "Cornfields" + } + }, + { + "id": 5530, + "name": "Angel Andrews", + "gender": "female", + "age": 26, + "address": { + "state": "Florida", + "city": "Sunriver" + } + }, + { + "id": 5531, + "name": "Goff Snider", + "gender": "male", + "age": 73, + "address": { + "state": "Minnesota", + "city": "Bladensburg" + } + }, + { + "id": 5532, + "name": "Hughes William", + "gender": "male", + "age": 38, + "address": { + "state": "Idaho", + "city": "Advance" + } + }, + { + "id": 5533, + "name": "William Buck", + "gender": "male", + "age": 74, + "address": { + "state": "New Mexico", + "city": "Catharine" + } + }, + { + "id": 5534, + "name": "Sims Joyner", + "gender": "male", + "age": 57, + "address": { + "state": "Georgia", + "city": "Gwynn" + } + }, + { + "id": 5535, + "name": "Terra Mack", + "gender": "female", + "age": 42, + "address": { + "state": "Kentucky", + "city": "Stevens" + } + }, + { + "id": 5536, + "name": "Lorna Rhodes", + "gender": "female", + "age": 41, + "address": { + "state": "Illinois", + "city": "Lawrence" + } + }, + { + "id": 5537, + "name": "Sheppard Stanton", + "gender": "male", + "age": 52, + "address": { + "state": "Arizona", + "city": "Whitestone" + } + }, + { + "id": 5538, + "name": "Shelia Oconnor", + "gender": "female", + "age": 71, + "address": { + "state": "South Dakota", + "city": "Walland" + } + }, + { + "id": 5539, + "name": "Bowers Bolton", + "gender": "male", + "age": 39, + "address": { + "state": "Kansas", + "city": "Remington" + } + }, + { + "id": 5540, + "name": "Tanisha Maldonado", + "gender": "female", + "age": 75, + "address": { + "state": "Kentucky", + "city": "Vicksburg" + } + }, + { + "id": 5541, + "name": "Sloan Wilkerson", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Emison" + } + }, + { + "id": 5542, + "name": "Delia Bass", + "gender": "female", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Dahlen" + } + }, + { + "id": 5543, + "name": "Victoria Guy", + "gender": "female", + "age": 58, + "address": { + "state": "Alabama", + "city": "Tryon" + } + }, + { + "id": 5544, + "name": "Gregory Miranda", + "gender": "male", + "age": 33, + "address": { + "state": "Maine", + "city": "Ballico" + } + }, + { + "id": 5545, + "name": "Leigh Mayer", + "gender": "female", + "age": 62, + "address": { + "state": "Montana", + "city": "Roeville" + } + }, + { + "id": 5546, + "name": "Julie Forbes", + "gender": "female", + "age": 43, + "address": { + "state": "Colorado", + "city": "Bloomington" + } + }, + { + "id": 5547, + "name": "Hutchinson Robinson", + "gender": "male", + "age": 65, + "address": { + "state": "Maryland", + "city": "Columbus" + } + }, + { + "id": 5548, + "name": "Morales Walton", + "gender": "male", + "age": 58, + "address": { + "state": "Vermont", + "city": "Camptown" + } + }, + { + "id": 5549, + "name": "Socorro Bradford", + "gender": "female", + "age": 27, + "address": { + "state": "New York", + "city": "Bodega" + } + }, + { + "id": 5550, + "name": "Burt Knight", + "gender": "male", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Coleville" + } + }, + { + "id": 5551, + "name": "Helga Duncan", + "gender": "female", + "age": 36, + "address": { + "state": "Nevada", + "city": "Baden" + } + }, + { + "id": 5552, + "name": "Angelina Cox", + "gender": "female", + "age": 19, + "address": { + "state": "Rhode Island", + "city": "Sanders" + } + }, + { + "id": 5553, + "name": "Beatrice Whitehead", + "gender": "female", + "age": 24, + "address": { + "state": "Iowa", + "city": "Statenville" + } + }, + { + "id": 5554, + "name": "Herring Wright", + "gender": "male", + "age": 34, + "address": { + "state": "South Carolina", + "city": "Brutus" + } + }, + { + "id": 5555, + "name": "Dona Howard", + "gender": "female", + "age": 79, + "address": { + "state": "Texas", + "city": "Kansas" + } + }, + { + "id": 5556, + "name": "Henry Bullock", + "gender": "male", + "age": 82, + "address": { + "state": "Alaska", + "city": "Franklin" + } + }, + { + "id": 5557, + "name": "Chandra Bryant", + "gender": "female", + "age": 26, + "address": { + "state": "New Jersey", + "city": "Drummond" + } + }, + { + "id": 5558, + "name": "Trujillo Bishop", + "gender": "male", + "age": 24, + "address": { + "state": "Indiana", + "city": "Clay" + } + }, + { + "id": 5559, + "name": "Nora Wolf", + "gender": "female", + "age": 64, + "address": { + "state": "Delaware", + "city": "Bison" + } + }, + { + "id": 5560, + "name": "Moss Small", + "gender": "male", + "age": 73, + "address": { + "state": "Arkansas", + "city": "Oneida" + } + }, + { + "id": 5561, + "name": "Booth Thornton", + "gender": "male", + "age": 33, + "address": { + "state": "North Dakota", + "city": "Balm" + } + }, + { + "id": 5562, + "name": "Clarissa Dawson", + "gender": "female", + "age": 40, + "address": { + "state": "Ohio", + "city": "Leroy" + } + }, + { + "id": 5563, + "name": "Cherry Tucker", + "gender": "male", + "age": 81, + "address": { + "state": "Tennessee", + "city": "Flintville" + } + }, + { + "id": 5564, + "name": "Irene Poole", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Bordelonville" + } + }, + { + "id": 5565, + "name": "Hodge Morton", + "gender": "male", + "age": 74, + "address": { + "state": "Oklahoma", + "city": "Allendale" + } + }, + { + "id": 5566, + "name": "Alba Lucas", + "gender": "female", + "age": 72, + "address": { + "state": "Illinois", + "city": "Brambleton" + } + }, + { + "id": 5567, + "name": "Roberson Dennis", + "gender": "male", + "age": 64, + "address": { + "state": "Florida", + "city": "Dexter" + } + }, + { + "id": 5568, + "name": "Pamela Dodson", + "gender": "female", + "age": 66, + "address": { + "state": "Mississippi", + "city": "Teasdale" + } + }, + { + "id": 5569, + "name": "Rachael Mathis", + "gender": "female", + "age": 58, + "address": { + "state": "Hawaii", + "city": "Derwood" + } + }, + { + "id": 5570, + "name": "Tran Raymond", + "gender": "male", + "age": 64, + "address": { + "state": "Virginia", + "city": "Ypsilanti" + } + }, + { + "id": 5571, + "name": "Rosanna Nieves", + "gender": "female", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Groton" + } + }, + { + "id": 5572, + "name": "Monica Macias", + "gender": "female", + "age": 41, + "address": { + "state": "Utah", + "city": "Ola" + } + }, + { + "id": 5573, + "name": "Debra Wong", + "gender": "female", + "age": 36, + "address": { + "state": "Missouri", + "city": "Dunnavant" + } + }, + { + "id": 5574, + "name": "Suzanne Skinner", + "gender": "female", + "age": 62, + "address": { + "state": "Nebraska", + "city": "Cashtown" + } + }, + { + "id": 5575, + "name": "Marie Allison", + "gender": "female", + "age": 21, + "address": { + "state": "West Virginia", + "city": "Tilden" + } + }, + { + "id": 5576, + "name": "Latoya Ryan", + "gender": "female", + "age": 25, + "address": { + "state": "Wyoming", + "city": "Rodanthe" + } + }, + { + "id": 5577, + "name": "Briggs Kim", + "gender": "male", + "age": 51, + "address": { + "state": "New Hampshire", + "city": "Dorneyville" + } + }, + { + "id": 5578, + "name": "Ruthie Finch", + "gender": "female", + "age": 29, + "address": { + "state": "California", + "city": "Hackneyville" + } + }, + { + "id": 5579, + "name": "Cantrell Campbell", + "gender": "male", + "age": 64, + "address": { + "state": "Washington", + "city": "Leland" + } + }, + { + "id": 5580, + "name": "Payne Spencer", + "gender": "male", + "age": 55, + "address": { + "state": "Georgia", + "city": "Sanford" + } + }, + { + "id": 5581, + "name": "Pacheco Mcbride", + "gender": "male", + "age": 74, + "address": { + "state": "Louisiana", + "city": "Brownlee" + } + }, + { + "id": 5582, + "name": "Mosley Moody", + "gender": "male", + "age": 80, + "address": { + "state": "Oregon", + "city": "Gadsden" + } + }, + { + "id": 5583, + "name": "Mckay Duke", + "gender": "male", + "age": 47, + "address": { + "state": "North Carolina", + "city": "Kennedyville" + } + }, + { + "id": 5584, + "name": "Meredith Wade", + "gender": "female", + "age": 32, + "address": { + "state": "Connecticut", + "city": "Brethren" + } + }, + { + "id": 5585, + "name": "Alston Ford", + "gender": "male", + "age": 60, + "address": { + "state": "New Mexico", + "city": "Gila" + } + }, + { + "id": 5586, + "name": "Cote Noel", + "gender": "male", + "age": 20, + "address": { + "state": "Hawaii", + "city": "Vale" + } + }, + { + "id": 5587, + "name": "Belinda Lara", + "gender": "female", + "age": 63, + "address": { + "state": "Washington", + "city": "Johnsonburg" + } + }, + { + "id": 5588, + "name": "Swanson Cooper", + "gender": "male", + "age": 79, + "address": { + "state": "Alaska", + "city": "Nogal" + } + }, + { + "id": 5589, + "name": "Eugenia Herring", + "gender": "female", + "age": 26, + "address": { + "state": "Nebraska", + "city": "Hiwasse" + } + }, + { + "id": 5590, + "name": "Maureen Coleman", + "gender": "female", + "age": 65, + "address": { + "state": "Louisiana", + "city": "Tyro" + } + }, + { + "id": 5591, + "name": "Guerrero Rose", + "gender": "male", + "age": 17, + "address": { + "state": "Oregon", + "city": "Conway" + } + }, + { + "id": 5592, + "name": "Aguirre Floyd", + "gender": "male", + "age": 41, + "address": { + "state": "Tennessee", + "city": "Herald" + } + }, + { + "id": 5593, + "name": "Bridges Wolfe", + "gender": "male", + "age": 20, + "address": { + "state": "Ohio", + "city": "Calpine" + } + }, + { + "id": 5594, + "name": "Camacho Newman", + "gender": "male", + "age": 81, + "address": { + "state": "North Dakota", + "city": "Aberdeen" + } + }, + { + "id": 5595, + "name": "Russo Kramer", + "gender": "male", + "age": 25, + "address": { + "state": "Delaware", + "city": "Klondike" + } + }, + { + "id": 5596, + "name": "Cortez Solis", + "gender": "male", + "age": 50, + "address": { + "state": "Michigan", + "city": "Northridge" + } + }, + { + "id": 5597, + "name": "Barlow Boone", + "gender": "male", + "age": 82, + "address": { + "state": "New Mexico", + "city": "Chical" + } + }, + { + "id": 5598, + "name": "Benson Sawyer", + "gender": "male", + "age": 37, + "address": { + "state": "Arkansas", + "city": "Sims" + } + }, + { + "id": 5599, + "name": "Erica Mueller", + "gender": "female", + "age": 33, + "address": { + "state": "Colorado", + "city": "Kenmar" + } + }, + { + "id": 5600, + "name": "Hensley Morse", + "gender": "male", + "age": 35, + "address": { + "state": "New Jersey", + "city": "Bethany" + } + }, + { + "id": 5601, + "name": "Shannon Lane", + "gender": "female", + "age": 74, + "address": { + "state": "Maine", + "city": "Sultana" + } + }, + { + "id": 5602, + "name": "Bianca Fleming", + "gender": "female", + "age": 23, + "address": { + "state": "West Virginia", + "city": "Tedrow" + } + }, + { + "id": 5603, + "name": "Vickie Salas", + "gender": "female", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Ticonderoga" + } + }, + { + "id": 5604, + "name": "Chaney Watson", + "gender": "male", + "age": 57, + "address": { + "state": "Kansas", + "city": "Waterloo" + } + }, + { + "id": 5605, + "name": "Bonner Soto", + "gender": "male", + "age": 61, + "address": { + "state": "Oklahoma", + "city": "Neibert" + } + }, + { + "id": 5606, + "name": "Lynnette Schroeder", + "gender": "female", + "age": 71, + "address": { + "state": "Nevada", + "city": "Keyport" + } + }, + { + "id": 5607, + "name": "Millicent Pope", + "gender": "female", + "age": 43, + "address": { + "state": "Missouri", + "city": "Springville" + } + }, + { + "id": 5608, + "name": "Rita Eaton", + "gender": "female", + "age": 34, + "address": { + "state": "New Hampshire", + "city": "Shrewsbury" + } + }, + { + "id": 5609, + "name": "Burgess Knowles", + "gender": "male", + "age": 27, + "address": { + "state": "South Dakota", + "city": "Williston" + } + }, + { + "id": 5610, + "name": "Jamie Lester", + "gender": "female", + "age": 32, + "address": { + "state": "Mississippi", + "city": "Tonopah" + } + }, + { + "id": 5611, + "name": "Monroe Pruitt", + "gender": "male", + "age": 74, + "address": { + "state": "Florida", + "city": "Rivereno" + } + }, + { + "id": 5612, + "name": "Benjamin William", + "gender": "male", + "age": 61, + "address": { + "state": "Illinois", + "city": "Westphalia" + } + }, + { + "id": 5613, + "name": "Jaclyn Simon", + "gender": "female", + "age": 64, + "address": { + "state": "Massachusetts", + "city": "Cawood" + } + }, + { + "id": 5614, + "name": "Hope Berg", + "gender": "female", + "age": 33, + "address": { + "state": "Alabama", + "city": "Gordon" + } + }, + { + "id": 5615, + "name": "Johanna Powers", + "gender": "female", + "age": 36, + "address": { + "state": "Texas", + "city": "Blende" + } + }, + { + "id": 5616, + "name": "Nash Shepherd", + "gender": "male", + "age": 77, + "address": { + "state": "Virginia", + "city": "Mansfield" + } + }, + { + "id": 5617, + "name": "Joy Gibson", + "gender": "female", + "age": 82, + "address": { + "state": "Maryland", + "city": "Montura" + } + }, + { + "id": 5618, + "name": "Golden Levy", + "gender": "male", + "age": 26, + "address": { + "state": "Wisconsin", + "city": "Delshire" + } + }, + { + "id": 5619, + "name": "Alvarado Walls", + "gender": "male", + "age": 60, + "address": { + "state": "Utah", + "city": "Smock" + } + }, + { + "id": 5620, + "name": "Herminia Wong", + "gender": "female", + "age": 66, + "address": { + "state": "Vermont", + "city": "Benson" + } + }, + { + "id": 5621, + "name": "Morgan Whitfield", + "gender": "female", + "age": 59, + "address": { + "state": "Iowa", + "city": "Waiohinu" + } + }, + { + "id": 5622, + "name": "Kemp Arnold", + "gender": "male", + "age": 59, + "address": { + "state": "Minnesota", + "city": "Edenburg" + } + }, + { + "id": 5623, + "name": "Durham Ferrell", + "gender": "male", + "age": 57, + "address": { + "state": "Arizona", + "city": "Logan" + } + }, + { + "id": 5624, + "name": "Katina Gallegos", + "gender": "female", + "age": 41, + "address": { + "state": "Wyoming", + "city": "Detroit" + } + }, + { + "id": 5625, + "name": "Joyce Durham", + "gender": "female", + "age": 35, + "address": { + "state": "California", + "city": "Berlin" + } + }, + { + "id": 5626, + "name": "Kerry Barnes", + "gender": "female", + "age": 66, + "address": { + "state": "Idaho", + "city": "Gambrills" + } + }, + { + "id": 5627, + "name": "Britt Carver", + "gender": "male", + "age": 39, + "address": { + "state": "Pennsylvania", + "city": "Wollochet" + } + }, + { + "id": 5628, + "name": "Blair Glover", + "gender": "male", + "age": 21, + "address": { + "state": "New York", + "city": "Sunbury" + } + }, + { + "id": 5629, + "name": "Savage Middleton", + "gender": "male", + "age": 40, + "address": { + "state": "Georgia", + "city": "Colton" + } + }, + { + "id": 5630, + "name": "Copeland Burgess", + "gender": "male", + "age": 29, + "address": { + "state": "South Carolina", + "city": "Wolcott" + } + }, + { + "id": 5631, + "name": "Irwin Haley", + "gender": "male", + "age": 27, + "address": { + "state": "Indiana", + "city": "Derwood" + } + }, + { + "id": 5632, + "name": "Carla Saunders", + "gender": "female", + "age": 73, + "address": { + "state": "Rhode Island", + "city": "Brewster" + } + }, + { + "id": 5633, + "name": "Amanda Ward", + "gender": "female", + "age": 71, + "address": { + "state": "Kentucky", + "city": "Dola" + } + }, + { + "id": 5634, + "name": "Wilda Roberson", + "gender": "female", + "age": 81, + "address": { + "state": "Montana", + "city": "Wawona" + } + }, + { + "id": 5635, + "name": "Staci Petty", + "gender": "female", + "age": 79, + "address": { + "state": "North Carolina", + "city": "Enetai" + } + }, + { + "id": 5636, + "name": "Marva Murphy", + "gender": "female", + "age": 18, + "address": { + "state": "Mississippi", + "city": "Seymour" + } + }, + { + "id": 5637, + "name": "Hazel Vance", + "gender": "female", + "age": 24, + "address": { + "state": "Nevada", + "city": "Allentown" + } + }, + { + "id": 5638, + "name": "Brock Cleveland", + "gender": "male", + "age": 55, + "address": { + "state": "Texas", + "city": "Fidelis" + } + }, + { + "id": 5639, + "name": "Walls Holloway", + "gender": "male", + "age": 17, + "address": { + "state": "Alaska", + "city": "Hondah" + } + }, + { + "id": 5640, + "name": "Kemp Wolfe", + "gender": "male", + "age": 19, + "address": { + "state": "Rhode Island", + "city": "Floriston" + } + }, + { + "id": 5641, + "name": "Green Walters", + "gender": "male", + "age": 64, + "address": { + "state": "New York", + "city": "Kilbourne" + } + }, + { + "id": 5642, + "name": "Melton Burks", + "gender": "male", + "age": 62, + "address": { + "state": "Louisiana", + "city": "Interlochen" + } + }, + { + "id": 5643, + "name": "Crosby Beck", + "gender": "male", + "age": 69, + "address": { + "state": "Virginia", + "city": "Belfair" + } + }, + { + "id": 5644, + "name": "Cecelia Kim", + "gender": "female", + "age": 61, + "address": { + "state": "Delaware", + "city": "Moquino" + } + }, + { + "id": 5645, + "name": "Clay Duran", + "gender": "male", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Bethpage" + } + }, + { + "id": 5646, + "name": "Morton Mays", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Camas" + } + }, + { + "id": 5647, + "name": "Ryan Bush", + "gender": "male", + "age": 71, + "address": { + "state": "Ohio", + "city": "Wright" + } + }, + { + "id": 5648, + "name": "Cora Goodwin", + "gender": "female", + "age": 52, + "address": { + "state": "Connecticut", + "city": "Nord" + } + }, + { + "id": 5649, + "name": "Bell Yang", + "gender": "male", + "age": 72, + "address": { + "state": "Florida", + "city": "Eastmont" + } + }, + { + "id": 5650, + "name": "Medina Tillman", + "gender": "male", + "age": 59, + "address": { + "state": "Vermont", + "city": "Hilltop" + } + }, + { + "id": 5651, + "name": "Petra Bauer", + "gender": "female", + "age": 77, + "address": { + "state": "Colorado", + "city": "Clarence" + } + }, + { + "id": 5652, + "name": "Holloway Sloan", + "gender": "male", + "age": 43, + "address": { + "state": "Hawaii", + "city": "Thomasville" + } + }, + { + "id": 5653, + "name": "Ora Hopkins", + "gender": "female", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Epworth" + } + }, + { + "id": 5654, + "name": "Antonia Pate", + "gender": "female", + "age": 42, + "address": { + "state": "Georgia", + "city": "Martinez" + } + }, + { + "id": 5655, + "name": "Baird Wagner", + "gender": "male", + "age": 82, + "address": { + "state": "Tennessee", + "city": "Wintersburg" + } + }, + { + "id": 5656, + "name": "Stokes Moses", + "gender": "male", + "age": 78, + "address": { + "state": "Montana", + "city": "Cataract" + } + }, + { + "id": 5657, + "name": "Wheeler Castillo", + "gender": "male", + "age": 60, + "address": { + "state": "Kentucky", + "city": "Leming" + } + }, + { + "id": 5658, + "name": "Danielle Ballard", + "gender": "female", + "age": 65, + "address": { + "state": "Arizona", + "city": "Hampstead" + } + }, + { + "id": 5659, + "name": "Loretta Pollard", + "gender": "female", + "age": 49, + "address": { + "state": "Kansas", + "city": "Saticoy" + } + }, + { + "id": 5660, + "name": "Hodge Barnes", + "gender": "male", + "age": 37, + "address": { + "state": "North Dakota", + "city": "Kraemer" + } + }, + { + "id": 5661, + "name": "Jerri Lara", + "gender": "female", + "age": 26, + "address": { + "state": "Alabama", + "city": "Coalmont" + } + }, + { + "id": 5662, + "name": "Gallagher Meyer", + "gender": "male", + "age": 63, + "address": { + "state": "Oklahoma", + "city": "Crown" + } + }, + { + "id": 5663, + "name": "Josefina Macias", + "gender": "female", + "age": 19, + "address": { + "state": "South Carolina", + "city": "Delshire" + } + }, + { + "id": 5664, + "name": "Lolita Velazquez", + "gender": "female", + "age": 37, + "address": { + "state": "Arkansas", + "city": "Adamstown" + } + }, + { + "id": 5665, + "name": "Elvia Lyons", + "gender": "female", + "age": 43, + "address": { + "state": "Wisconsin", + "city": "Townsend" + } + }, + { + "id": 5666, + "name": "Bettye Cantu", + "gender": "female", + "age": 51, + "address": { + "state": "Wyoming", + "city": "Frystown" + } + }, + { + "id": 5667, + "name": "Burns Norman", + "gender": "male", + "age": 55, + "address": { + "state": "Utah", + "city": "Moscow" + } + }, + { + "id": 5668, + "name": "Carly Fry", + "gender": "female", + "age": 50, + "address": { + "state": "Oregon", + "city": "Elrama" + } + }, + { + "id": 5669, + "name": "Kendra Fuller", + "gender": "female", + "age": 56, + "address": { + "state": "Maine", + "city": "Nutrioso" + } + }, + { + "id": 5670, + "name": "Hendrix Martinez", + "gender": "male", + "age": 26, + "address": { + "state": "Nebraska", + "city": "Dola" + } + }, + { + "id": 5671, + "name": "Velma Dunlap", + "gender": "female", + "age": 25, + "address": { + "state": "Michigan", + "city": "Ypsilanti" + } + }, + { + "id": 5672, + "name": "Donaldson Conrad", + "gender": "male", + "age": 31, + "address": { + "state": "Maryland", + "city": "Weedville" + } + }, + { + "id": 5673, + "name": "Mcclure Merrill", + "gender": "male", + "age": 43, + "address": { + "state": "Pennsylvania", + "city": "Keyport" + } + }, + { + "id": 5674, + "name": "Lillie Lloyd", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Olney" + } + }, + { + "id": 5675, + "name": "Carol Manning", + "gender": "female", + "age": 43, + "address": { + "state": "Missouri", + "city": "Fruitdale" + } + }, + { + "id": 5676, + "name": "Trudy Howell", + "gender": "female", + "age": 63, + "address": { + "state": "New Jersey", + "city": "Draper" + } + }, + { + "id": 5677, + "name": "Ayers Emerson", + "gender": "male", + "age": 47, + "address": { + "state": "South Dakota", + "city": "Brownsville" + } + }, + { + "id": 5678, + "name": "Cox Parker", + "gender": "male", + "age": 27, + "address": { + "state": "Iowa", + "city": "Cloverdale" + } + }, + { + "id": 5679, + "name": "Nadine Warner", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Shepardsville" + } + }, + { + "id": 5680, + "name": "Mamie Blackwell", + "gender": "female", + "age": 62, + "address": { + "state": "Massachusetts", + "city": "Sena" + } + }, + { + "id": 5681, + "name": "Dora Hays", + "gender": "female", + "age": 78, + "address": { + "state": "California", + "city": "Wollochet" + } + }, + { + "id": 5682, + "name": "Bradshaw Steele", + "gender": "male", + "age": 46, + "address": { + "state": "Washington", + "city": "Craig" + } + }, + { + "id": 5683, + "name": "Gwen Salazar", + "gender": "female", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Calpine" + } + }, + { + "id": 5684, + "name": "Bobbi Caldwell", + "gender": "female", + "age": 71, + "address": { + "state": "Minnesota", + "city": "Gasquet" + } + }, + { + "id": 5685, + "name": "Ramona Nelson", + "gender": "female", + "age": 22, + "address": { + "state": "North Carolina", + "city": "Gardners" + } + }, + { + "id": 5686, + "name": "West Best", + "gender": "male", + "age": 59, + "address": { + "state": "Indiana", + "city": "Falconaire" + } + }, + { + "id": 5687, + "name": "Booker Mullen", + "gender": "male", + "age": 18, + "address": { + "state": "Arkansas", + "city": "Rossmore" + } + }, + { + "id": 5688, + "name": "Prince Suarez", + "gender": "male", + "age": 63, + "address": { + "state": "Rhode Island", + "city": "Beyerville" + } + }, + { + "id": 5689, + "name": "Wolfe Chambers", + "gender": "male", + "age": 36, + "address": { + "state": "Iowa", + "city": "Convent" + } + }, + { + "id": 5690, + "name": "Erika Briggs", + "gender": "female", + "age": 22, + "address": { + "state": "Louisiana", + "city": "Joes" + } + }, + { + "id": 5691, + "name": "Page Alexander", + "gender": "male", + "age": 33, + "address": { + "state": "Utah", + "city": "Idledale" + } + }, + { + "id": 5692, + "name": "Lillie Fowler", + "gender": "female", + "age": 53, + "address": { + "state": "New Hampshire", + "city": "Neibert" + } + }, + { + "id": 5693, + "name": "Chen Sargent", + "gender": "male", + "age": 72, + "address": { + "state": "South Dakota", + "city": "Hessville" + } + }, + { + "id": 5694, + "name": "Carroll Allen", + "gender": "male", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Beechmont" + } + }, + { + "id": 5695, + "name": "Hannah Spears", + "gender": "female", + "age": 68, + "address": { + "state": "West Virginia", + "city": "Broadlands" + } + }, + { + "id": 5696, + "name": "Reva Alvarez", + "gender": "female", + "age": 78, + "address": { + "state": "Oklahoma", + "city": "Richmond" + } + }, + { + "id": 5697, + "name": "Barry Ford", + "gender": "male", + "age": 17, + "address": { + "state": "Delaware", + "city": "Salix" + } + }, + { + "id": 5698, + "name": "Vaughn Riddle", + "gender": "male", + "age": 66, + "address": { + "state": "Maryland", + "city": "Summerfield" + } + }, + { + "id": 5699, + "name": "Mona Schmidt", + "gender": "female", + "age": 75, + "address": { + "state": "Illinois", + "city": "Chestnut" + } + }, + { + "id": 5700, + "name": "Callie Taylor", + "gender": "female", + "age": 35, + "address": { + "state": "New Mexico", + "city": "Davenport" + } + }, + { + "id": 5701, + "name": "Whitley Gallagher", + "gender": "male", + "age": 37, + "address": { + "state": "Alabama", + "city": "Alleghenyville" + } + }, + { + "id": 5702, + "name": "Weiss Davis", + "gender": "male", + "age": 33, + "address": { + "state": "Alaska", + "city": "Twilight" + } + }, + { + "id": 5703, + "name": "Elise Britt", + "gender": "female", + "age": 31, + "address": { + "state": "Montana", + "city": "Rosedale" + } + }, + { + "id": 5704, + "name": "Lila Andrews", + "gender": "female", + "age": 66, + "address": { + "state": "Vermont", + "city": "Mooresburg" + } + }, + { + "id": 5705, + "name": "Joann Burch", + "gender": "female", + "age": 27, + "address": { + "state": "New York", + "city": "Harleigh" + } + }, + { + "id": 5706, + "name": "Hahn Ferrell", + "gender": "male", + "age": 69, + "address": { + "state": "Arizona", + "city": "Brewster" + } + }, + { + "id": 5707, + "name": "Elva Knight", + "gender": "female", + "age": 78, + "address": { + "state": "Ohio", + "city": "Breinigsville" + } + }, + { + "id": 5708, + "name": "Melissa Porter", + "gender": "female", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Chesapeake" + } + }, + { + "id": 5709, + "name": "Meadows Swanson", + "gender": "male", + "age": 52, + "address": { + "state": "Mississippi", + "city": "Stagecoach" + } + }, + { + "id": 5710, + "name": "Lauren Mcmillan", + "gender": "female", + "age": 31, + "address": { + "state": "Hawaii", + "city": "Ladera" + } + }, + { + "id": 5711, + "name": "Adrian Cooper", + "gender": "female", + "age": 24, + "address": { + "state": "Idaho", + "city": "Fairview" + } + }, + { + "id": 5712, + "name": "Rosemary Schultz", + "gender": "female", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Selma" + } + }, + { + "id": 5713, + "name": "Hodge Yates", + "gender": "male", + "age": 39, + "address": { + "state": "Texas", + "city": "Emory" + } + }, + { + "id": 5714, + "name": "Melva Rojas", + "gender": "female", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Sidman" + } + }, + { + "id": 5715, + "name": "Dona Davenport", + "gender": "female", + "age": 46, + "address": { + "state": "Wisconsin", + "city": "Caroleen" + } + }, + { + "id": 5716, + "name": "Ernestine Pate", + "gender": "female", + "age": 52, + "address": { + "state": "Maine", + "city": "Albrightsville" + } + }, + { + "id": 5717, + "name": "Harvey Alvarado", + "gender": "male", + "age": 47, + "address": { + "state": "California", + "city": "Saranap" + } + }, + { + "id": 5718, + "name": "Rasmussen Cotton", + "gender": "male", + "age": 51, + "address": { + "state": "Wyoming", + "city": "Vincent" + } + }, + { + "id": 5719, + "name": "Mcneil Buchanan", + "gender": "male", + "age": 48, + "address": { + "state": "Pennsylvania", + "city": "Wedgewood" + } + }, + { + "id": 5720, + "name": "Gregory Boyer", + "gender": "male", + "age": 55, + "address": { + "state": "Kentucky", + "city": "Englevale" + } + }, + { + "id": 5721, + "name": "Willie Hinton", + "gender": "female", + "age": 73, + "address": { + "state": "Washington", + "city": "Abiquiu" + } + }, + { + "id": 5722, + "name": "Lorie Bean", + "gender": "female", + "age": 31, + "address": { + "state": "Oregon", + "city": "Chilton" + } + }, + { + "id": 5723, + "name": "Caitlin Leon", + "gender": "female", + "age": 43, + "address": { + "state": "Missouri", + "city": "Cliffside" + } + }, + { + "id": 5724, + "name": "Cherie Decker", + "gender": "female", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Sims" + } + }, + { + "id": 5725, + "name": "Silva Parks", + "gender": "male", + "age": 44, + "address": { + "state": "Michigan", + "city": "Jacksonwald" + } + }, + { + "id": 5726, + "name": "Debora Hobbs", + "gender": "female", + "age": 51, + "address": { + "state": "Nevada", + "city": "Nutrioso" + } + }, + { + "id": 5727, + "name": "Summer Coffey", + "gender": "female", + "age": 51, + "address": { + "state": "Massachusetts", + "city": "Osage" + } + }, + { + "id": 5728, + "name": "Bush Morrow", + "gender": "male", + "age": 77, + "address": { + "state": "North Dakota", + "city": "Longoria" + } + }, + { + "id": 5729, + "name": "Natalia Cox", + "gender": "female", + "age": 26, + "address": { + "state": "Georgia", + "city": "Hachita" + } + }, + { + "id": 5730, + "name": "Mccarty Blanchard", + "gender": "male", + "age": 49, + "address": { + "state": "Colorado", + "city": "Hebron" + } + }, + { + "id": 5731, + "name": "Francine Nguyen", + "gender": "female", + "age": 51, + "address": { + "state": "Kansas", + "city": "Lafferty" + } + }, + { + "id": 5732, + "name": "Karina Cummings", + "gender": "female", + "age": 31, + "address": { + "state": "Florida", + "city": "Ona" + } + }, + { + "id": 5733, + "name": "Bettie Rosa", + "gender": "female", + "age": 69, + "address": { + "state": "Pennsylvania", + "city": "Goodville" + } + }, + { + "id": 5734, + "name": "Bernadette Armstrong", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Bellamy" + } + }, + { + "id": 5735, + "name": "Mann Parsons", + "gender": "male", + "age": 19, + "address": { + "state": "Delaware", + "city": "Needmore" + } + }, + { + "id": 5736, + "name": "Corrine May", + "gender": "female", + "age": 55, + "address": { + "state": "Alabama", + "city": "Fidelis" + } + }, + { + "id": 5737, + "name": "Shana Gill", + "gender": "female", + "age": 41, + "address": { + "state": "Montana", + "city": "Fulford" + } + }, + { + "id": 5738, + "name": "Carroll Arnold", + "gender": "male", + "age": 61, + "address": { + "state": "Hawaii", + "city": "Flintville" + } + }, + { + "id": 5739, + "name": "Carmela Fowler", + "gender": "female", + "age": 77, + "address": { + "state": "Wisconsin", + "city": "Tolu" + } + }, + { + "id": 5740, + "name": "Levy Goff", + "gender": "male", + "age": 23, + "address": { + "state": "Oklahoma", + "city": "Venice" + } + }, + { + "id": 5741, + "name": "Geraldine Schmidt", + "gender": "female", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Austinburg" + } + }, + { + "id": 5742, + "name": "Strong Hamilton", + "gender": "male", + "age": 35, + "address": { + "state": "Idaho", + "city": "Sultana" + } + }, + { + "id": 5743, + "name": "Hodge Wilcox", + "gender": "male", + "age": 39, + "address": { + "state": "Texas", + "city": "Taycheedah" + } + }, + { + "id": 5744, + "name": "Hawkins Burch", + "gender": "male", + "age": 74, + "address": { + "state": "Oregon", + "city": "Rosburg" + } + }, + { + "id": 5745, + "name": "Sallie Warner", + "gender": "female", + "age": 61, + "address": { + "state": "Wyoming", + "city": "Reinerton" + } + }, + { + "id": 5746, + "name": "Summers Lloyd", + "gender": "male", + "age": 37, + "address": { + "state": "Rhode Island", + "city": "Linganore" + } + }, + { + "id": 5747, + "name": "Christensen French", + "gender": "male", + "age": 49, + "address": { + "state": "Tennessee", + "city": "Hartsville/Hartley" + } + }, + { + "id": 5748, + "name": "Bethany Rodriquez", + "gender": "female", + "age": 28, + "address": { + "state": "New Mexico", + "city": "Ebro" + } + }, + { + "id": 5749, + "name": "Black Finley", + "gender": "male", + "age": 38, + "address": { + "state": "Illinois", + "city": "Newry" + } + }, + { + "id": 5750, + "name": "Angelia Sweeney", + "gender": "female", + "age": 79, + "address": { + "state": "Colorado", + "city": "Gallina" + } + }, + { + "id": 5751, + "name": "Charity Mccarthy", + "gender": "female", + "age": 34, + "address": { + "state": "Utah", + "city": "Islandia" + } + }, + { + "id": 5752, + "name": "Dianna Melendez", + "gender": "female", + "age": 28, + "address": { + "state": "Minnesota", + "city": "Hannasville" + } + }, + { + "id": 5753, + "name": "Valeria Harper", + "gender": "female", + "age": 30, + "address": { + "state": "Alaska", + "city": "Keller" + } + }, + { + "id": 5754, + "name": "Hewitt Avery", + "gender": "male", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Foscoe" + } + }, + { + "id": 5755, + "name": "Brooke Decker", + "gender": "female", + "age": 35, + "address": { + "state": "Ohio", + "city": "Idledale" + } + }, + { + "id": 5756, + "name": "Bernadine Dickerson", + "gender": "female", + "age": 26, + "address": { + "state": "Nevada", + "city": "Westwood" + } + }, + { + "id": 5757, + "name": "Kris Dotson", + "gender": "female", + "age": 81, + "address": { + "state": "New York", + "city": "Wadsworth" + } + }, + { + "id": 5758, + "name": "Meghan Ramsey", + "gender": "female", + "age": 46, + "address": { + "state": "California", + "city": "Bath" + } + }, + { + "id": 5759, + "name": "Huffman Knox", + "gender": "male", + "age": 43, + "address": { + "state": "Michigan", + "city": "Jamestown" + } + }, + { + "id": 5760, + "name": "Glenda Schroeder", + "gender": "female", + "age": 77, + "address": { + "state": "Mississippi", + "city": "Chapin" + } + }, + { + "id": 5761, + "name": "Latisha Dillard", + "gender": "female", + "age": 80, + "address": { + "state": "South Dakota", + "city": "Kenvil" + } + }, + { + "id": 5762, + "name": "Ingrid Cobb", + "gender": "female", + "age": 63, + "address": { + "state": "Arkansas", + "city": "Otranto" + } + }, + { + "id": 5763, + "name": "Fernandez Chambers", + "gender": "male", + "age": 17, + "address": { + "state": "Nebraska", + "city": "Rote" + } + }, + { + "id": 5764, + "name": "Aimee Fry", + "gender": "female", + "age": 30, + "address": { + "state": "Connecticut", + "city": "Diaperville" + } + }, + { + "id": 5765, + "name": "Kirsten Sawyer", + "gender": "female", + "age": 21, + "address": { + "state": "Kentucky", + "city": "Sunwest" + } + }, + { + "id": 5766, + "name": "Wise Rosales", + "gender": "male", + "age": 68, + "address": { + "state": "Maine", + "city": "Roulette" + } + }, + { + "id": 5767, + "name": "Brady Ware", + "gender": "male", + "age": 18, + "address": { + "state": "Washington", + "city": "Slovan" + } + }, + { + "id": 5768, + "name": "Jeannette Peters", + "gender": "female", + "age": 37, + "address": { + "state": "Iowa", + "city": "Templeton" + } + }, + { + "id": 5769, + "name": "Olson Fisher", + "gender": "male", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Salunga" + } + }, + { + "id": 5770, + "name": "Acosta Mathews", + "gender": "male", + "age": 40, + "address": { + "state": "Florida", + "city": "Hayes" + } + }, + { + "id": 5771, + "name": "Strickland Thomas", + "gender": "male", + "age": 50, + "address": { + "state": "Georgia", + "city": "Savage" + } + }, + { + "id": 5772, + "name": "Albert Ewing", + "gender": "male", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Crucible" + } + }, + { + "id": 5773, + "name": "Mcpherson Blair", + "gender": "male", + "age": 72, + "address": { + "state": "Arizona", + "city": "Worcester" + } + }, + { + "id": 5774, + "name": "Mccarty Bowen", + "gender": "male", + "age": 23, + "address": { + "state": "Indiana", + "city": "Valle" + } + }, + { + "id": 5775, + "name": "Deana Collier", + "gender": "female", + "age": 65, + "address": { + "state": "Virginia", + "city": "Norwood" + } + }, + { + "id": 5776, + "name": "Lawanda Galloway", + "gender": "female", + "age": 57, + "address": { + "state": "Kansas", + "city": "Coaldale" + } + }, + { + "id": 5777, + "name": "Loretta Gilliam", + "gender": "female", + "age": 66, + "address": { + "state": "North Carolina", + "city": "Macdona" + } + }, + { + "id": 5778, + "name": "Annette Kramer", + "gender": "female", + "age": 61, + "address": { + "state": "Missouri", + "city": "Mulino" + } + }, + { + "id": 5779, + "name": "Raymond Shannon", + "gender": "male", + "age": 21, + "address": { + "state": "Maryland", + "city": "Comptche" + } + }, + { + "id": 5780, + "name": "Booth Hill", + "gender": "male", + "age": 31, + "address": { + "state": "South Carolina", + "city": "Yorklyn" + } + }, + { + "id": 5781, + "name": "Debora Kline", + "gender": "female", + "age": 41, + "address": { + "state": "North Dakota", + "city": "Hailesboro" + } + }, + { + "id": 5782, + "name": "Simmons Gray", + "gender": "male", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Gulf" + } + }, + { + "id": 5783, + "name": "Cash Cook", + "gender": "male", + "age": 66, + "address": { + "state": "Kentucky", + "city": "Fedora" + } + }, + { + "id": 5784, + "name": "Lara Rosales", + "gender": "male", + "age": 23, + "address": { + "state": "Georgia", + "city": "Rew" + } + }, + { + "id": 5785, + "name": "Bryant Lawrence", + "gender": "male", + "age": 49, + "address": { + "state": "Mississippi", + "city": "Torboy" + } + }, + { + "id": 5786, + "name": "Agnes Patterson", + "gender": "female", + "age": 56, + "address": { + "state": "Delaware", + "city": "Villarreal" + } + }, + { + "id": 5787, + "name": "Sadie Swanson", + "gender": "female", + "age": 62, + "address": { + "state": "Tennessee", + "city": "Maplewood" + } + }, + { + "id": 5788, + "name": "Crosby Wyatt", + "gender": "male", + "age": 41, + "address": { + "state": "Vermont", + "city": "Jenkinsville" + } + }, + { + "id": 5789, + "name": "Shannon Silva", + "gender": "female", + "age": 20, + "address": { + "state": "Oklahoma", + "city": "Lavalette" + } + }, + { + "id": 5790, + "name": "Mandy Forbes", + "gender": "female", + "age": 74, + "address": { + "state": "Michigan", + "city": "Snyderville" + } + }, + { + "id": 5791, + "name": "Laurie Holden", + "gender": "female", + "age": 37, + "address": { + "state": "Utah", + "city": "Walton" + } + }, + { + "id": 5792, + "name": "Downs Weaver", + "gender": "male", + "age": 66, + "address": { + "state": "Indiana", + "city": "Waterloo" + } + }, + { + "id": 5793, + "name": "Ana Figueroa", + "gender": "female", + "age": 23, + "address": { + "state": "New Mexico", + "city": "Broadlands" + } + }, + { + "id": 5794, + "name": "Hooper Pacheco", + "gender": "male", + "age": 56, + "address": { + "state": "South Carolina", + "city": "Matthews" + } + }, + { + "id": 5795, + "name": "Clarissa Dawson", + "gender": "female", + "age": 75, + "address": { + "state": "New York", + "city": "Vandiver" + } + }, + { + "id": 5796, + "name": "Levine Randall", + "gender": "male", + "age": 62, + "address": { + "state": "California", + "city": "Ruckersville" + } + }, + { + "id": 5797, + "name": "Pickett Cooley", + "gender": "male", + "age": 58, + "address": { + "state": "Colorado", + "city": "Chamberino" + } + }, + { + "id": 5798, + "name": "Gates Gates", + "gender": "male", + "age": 57, + "address": { + "state": "Washington", + "city": "Nile" + } + }, + { + "id": 5799, + "name": "Peterson Clemons", + "gender": "male", + "age": 52, + "address": { + "state": "Massachusetts", + "city": "Chloride" + } + }, + { + "id": 5800, + "name": "Perez Knight", + "gender": "male", + "age": 79, + "address": { + "state": "Virginia", + "city": "Brownlee" + } + }, + { + "id": 5801, + "name": "Alison Tucker", + "gender": "female", + "age": 20, + "address": { + "state": "Ohio", + "city": "Kieler" + } + }, + { + "id": 5802, + "name": "Bond Alexander", + "gender": "male", + "age": 80, + "address": { + "state": "Hawaii", + "city": "Byrnedale" + } + }, + { + "id": 5803, + "name": "Annette Haynes", + "gender": "female", + "age": 38, + "address": { + "state": "Alaska", + "city": "Detroit" + } + }, + { + "id": 5804, + "name": "Beverly Ballard", + "gender": "female", + "age": 71, + "address": { + "state": "Montana", + "city": "Orviston" + } + }, + { + "id": 5805, + "name": "Fitzpatrick Ryan", + "gender": "male", + "age": 63, + "address": { + "state": "Iowa", + "city": "Jacumba" + } + }, + { + "id": 5806, + "name": "Contreras Yang", + "gender": "male", + "age": 53, + "address": { + "state": "Idaho", + "city": "Gallina" + } + }, + { + "id": 5807, + "name": "Compton Allen", + "gender": "male", + "age": 70, + "address": { + "state": "Oregon", + "city": "Moraida" + } + }, + { + "id": 5808, + "name": "Parrish Romero", + "gender": "male", + "age": 33, + "address": { + "state": "Connecticut", + "city": "Fostoria" + } + }, + { + "id": 5809, + "name": "Jackson Wilkinson", + "gender": "male", + "age": 48, + "address": { + "state": "Texas", + "city": "Delco" + } + }, + { + "id": 5810, + "name": "Boone Anthony", + "gender": "male", + "age": 82, + "address": { + "state": "Florida", + "city": "Fillmore" + } + }, + { + "id": 5811, + "name": "Farrell Hernandez", + "gender": "male", + "age": 44, + "address": { + "state": "Alabama", + "city": "Herlong" + } + }, + { + "id": 5812, + "name": "Cathryn Harding", + "gender": "female", + "age": 78, + "address": { + "state": "Pennsylvania", + "city": "Saranap" + } + }, + { + "id": 5813, + "name": "Dolores Zamora", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Keyport" + } + }, + { + "id": 5814, + "name": "Aida Henson", + "gender": "female", + "age": 41, + "address": { + "state": "Illinois", + "city": "Haring" + } + }, + { + "id": 5815, + "name": "Sofia Parsons", + "gender": "female", + "age": 71, + "address": { + "state": "Minnesota", + "city": "Rose" + } + }, + { + "id": 5816, + "name": "Puckett Payne", + "gender": "male", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Bethany" + } + }, + { + "id": 5817, + "name": "Rebecca Calhoun", + "gender": "female", + "age": 56, + "address": { + "state": "New Hampshire", + "city": "Hollymead" + } + }, + { + "id": 5818, + "name": "Swanson English", + "gender": "male", + "age": 47, + "address": { + "state": "Missouri", + "city": "Crawfordsville" + } + }, + { + "id": 5819, + "name": "Elvira Mullen", + "gender": "female", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Konterra" + } + }, + { + "id": 5820, + "name": "Case Molina", + "gender": "male", + "age": 23, + "address": { + "state": "Nevada", + "city": "Wanship" + } + }, + { + "id": 5821, + "name": "Hilary Ellis", + "gender": "female", + "age": 81, + "address": { + "state": "Wyoming", + "city": "Yardville" + } + }, + { + "id": 5822, + "name": "Dale Dejesus", + "gender": "male", + "age": 21, + "address": { + "state": "Arizona", + "city": "Chaparrito" + } + }, + { + "id": 5823, + "name": "Opal Sweet", + "gender": "female", + "age": 69, + "address": { + "state": "South Dakota", + "city": "Dyckesville" + } + }, + { + "id": 5824, + "name": "Maxine Maldonado", + "gender": "female", + "age": 59, + "address": { + "state": "North Dakota", + "city": "Olney" + } + }, + { + "id": 5825, + "name": "Karina Haley", + "gender": "female", + "age": 24, + "address": { + "state": "Wisconsin", + "city": "Marshall" + } + }, + { + "id": 5826, + "name": "Glenda Frederick", + "gender": "female", + "age": 19, + "address": { + "state": "Maryland", + "city": "Fairview" + } + }, + { + "id": 5827, + "name": "Manning Wilkins", + "gender": "male", + "age": 67, + "address": { + "state": "Maine", + "city": "Boonville" + } + }, + { + "id": 5828, + "name": "Sondra Hudson", + "gender": "female", + "age": 77, + "address": { + "state": "Kansas", + "city": "Eastvale" + } + }, + { + "id": 5829, + "name": "Muriel Goodwin", + "gender": "female", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Lithium" + } + }, + { + "id": 5830, + "name": "Chen Shepherd", + "gender": "male", + "age": 58, + "address": { + "state": "West Virginia", + "city": "Eastmont" + } + }, + { + "id": 5831, + "name": "Susan Evans", + "gender": "female", + "age": 20, + "address": { + "state": "Missouri", + "city": "Zarephath" + } + }, + { + "id": 5832, + "name": "Esther Terrell", + "gender": "female", + "age": 50, + "address": { + "state": "Maryland", + "city": "Imperial" + } + }, + { + "id": 5833, + "name": "Grace Skinner", + "gender": "female", + "age": 74, + "address": { + "state": "New Mexico", + "city": "Cleary" + } + }, + { + "id": 5834, + "name": "Malone Burke", + "gender": "male", + "age": 24, + "address": { + "state": "Michigan", + "city": "Wyoming" + } + }, + { + "id": 5835, + "name": "Tonya Bennett", + "gender": "female", + "age": 78, + "address": { + "state": "West Virginia", + "city": "Groveville" + } + }, + { + "id": 5836, + "name": "Little Woodard", + "gender": "male", + "age": 31, + "address": { + "state": "South Carolina", + "city": "Fairmount" + } + }, + { + "id": 5837, + "name": "Rosalie Rosales", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Carrsville" + } + }, + { + "id": 5838, + "name": "Bray Lowe", + "gender": "male", + "age": 64, + "address": { + "state": "New York", + "city": "Oceola" + } + }, + { + "id": 5839, + "name": "Manuela Potter", + "gender": "female", + "age": 78, + "address": { + "state": "New Hampshire", + "city": "Statenville" + } + }, + { + "id": 5840, + "name": "Dejesus Gross", + "gender": "male", + "age": 69, + "address": { + "state": "Washington", + "city": "Takilma" + } + }, + { + "id": 5841, + "name": "Hayden Bean", + "gender": "male", + "age": 59, + "address": { + "state": "Indiana", + "city": "Freeburn" + } + }, + { + "id": 5842, + "name": "Berta Payne", + "gender": "female", + "age": 38, + "address": { + "state": "Maine", + "city": "Marne" + } + }, + { + "id": 5843, + "name": "Hawkins Glass", + "gender": "male", + "age": 75, + "address": { + "state": "Iowa", + "city": "Woodruff" + } + }, + { + "id": 5844, + "name": "House Gutierrez", + "gender": "male", + "age": 78, + "address": { + "state": "Tennessee", + "city": "Bowie" + } + }, + { + "id": 5845, + "name": "Roach Booth", + "gender": "male", + "age": 49, + "address": { + "state": "New Jersey", + "city": "Riner" + } + }, + { + "id": 5846, + "name": "Chan Freeman", + "gender": "male", + "age": 77, + "address": { + "state": "Colorado", + "city": "Rosewood" + } + }, + { + "id": 5847, + "name": "Paige Sanchez", + "gender": "female", + "age": 59, + "address": { + "state": "Nebraska", + "city": "Finderne" + } + }, + { + "id": 5848, + "name": "Maryellen Dominguez", + "gender": "female", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Gloucester" + } + }, + { + "id": 5849, + "name": "Potts Avery", + "gender": "male", + "age": 58, + "address": { + "state": "Oregon", + "city": "Cassel" + } + }, + { + "id": 5850, + "name": "Irwin Castro", + "gender": "male", + "age": 55, + "address": { + "state": "Virginia", + "city": "Clinton" + } + }, + { + "id": 5851, + "name": "Allison Townsend", + "gender": "male", + "age": 37, + "address": { + "state": "Oklahoma", + "city": "Layhill" + } + }, + { + "id": 5852, + "name": "Dixie Duffy", + "gender": "female", + "age": 60, + "address": { + "state": "Wyoming", + "city": "Beaverdale" + } + }, + { + "id": 5853, + "name": "Alisa Ballard", + "gender": "female", + "age": 23, + "address": { + "state": "Texas", + "city": "Wikieup" + } + }, + { + "id": 5854, + "name": "Shelley Mcbride", + "gender": "female", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Nicholson" + } + }, + { + "id": 5855, + "name": "White Leonard", + "gender": "male", + "age": 30, + "address": { + "state": "California", + "city": "Deercroft" + } + }, + { + "id": 5856, + "name": "Patrica Mercado", + "gender": "female", + "age": 52, + "address": { + "state": "Utah", + "city": "Kula" + } + }, + { + "id": 5857, + "name": "Lyons Howard", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Leroy" + } + }, + { + "id": 5858, + "name": "Hudson Alexander", + "gender": "male", + "age": 30, + "address": { + "state": "Delaware", + "city": "Belgreen" + } + }, + { + "id": 5859, + "name": "Mattie Blair", + "gender": "female", + "age": 66, + "address": { + "state": "Mississippi", + "city": "Vale" + } + }, + { + "id": 5860, + "name": "Pace Frederick", + "gender": "male", + "age": 52, + "address": { + "state": "Pennsylvania", + "city": "Westmoreland" + } + }, + { + "id": 5861, + "name": "Casey Knight", + "gender": "male", + "age": 41, + "address": { + "state": "Louisiana", + "city": "Forbestown" + } + }, + { + "id": 5862, + "name": "Vicky Pitts", + "gender": "female", + "age": 31, + "address": { + "state": "Kentucky", + "city": "Loma" + } + }, + { + "id": 5863, + "name": "Bender Good", + "gender": "male", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Walton" + } + }, + { + "id": 5864, + "name": "Melanie Wallace", + "gender": "female", + "age": 21, + "address": { + "state": "Georgia", + "city": "Chaparrito" + } + }, + { + "id": 5865, + "name": "Thompson Byrd", + "gender": "male", + "age": 70, + "address": { + "state": "North Carolina", + "city": "Dellview" + } + }, + { + "id": 5866, + "name": "Faith Page", + "gender": "female", + "age": 54, + "address": { + "state": "Florida", + "city": "Homeland" + } + }, + { + "id": 5867, + "name": "Ramsey Shields", + "gender": "male", + "age": 50, + "address": { + "state": "Idaho", + "city": "Sanford" + } + }, + { + "id": 5868, + "name": "Meyer Hernandez", + "gender": "male", + "age": 30, + "address": { + "state": "Arizona", + "city": "Mansfield" + } + }, + { + "id": 5869, + "name": "Jodie Sanders", + "gender": "female", + "age": 37, + "address": { + "state": "Massachusetts", + "city": "Knowlton" + } + }, + { + "id": 5870, + "name": "Shari Newton", + "gender": "female", + "age": 33, + "address": { + "state": "Montana", + "city": "Konterra" + } + }, + { + "id": 5871, + "name": "Rosario Compton", + "gender": "male", + "age": 69, + "address": { + "state": "Alaska", + "city": "Byrnedale" + } + }, + { + "id": 5872, + "name": "Barker Maxwell", + "gender": "male", + "age": 78, + "address": { + "state": "Alabama", + "city": "Reno" + } + }, + { + "id": 5873, + "name": "Amie Cervantes", + "gender": "female", + "age": 21, + "address": { + "state": "Illinois", + "city": "Machias" + } + }, + { + "id": 5874, + "name": "Frieda Rowland", + "gender": "female", + "age": 27, + "address": { + "state": "Ohio", + "city": "Jacksonwald" + } + }, + { + "id": 5875, + "name": "Gould Hubbard", + "gender": "male", + "age": 49, + "address": { + "state": "Kansas", + "city": "Hall" + } + }, + { + "id": 5876, + "name": "Lucas Poole", + "gender": "male", + "age": 37, + "address": { + "state": "Vermont", + "city": "Stagecoach" + } + }, + { + "id": 5877, + "name": "Ava Oneill", + "gender": "female", + "age": 56, + "address": { + "state": "South Dakota", + "city": "Moscow" + } + }, + { + "id": 5878, + "name": "Gay Justice", + "gender": "male", + "age": 28, + "address": { + "state": "Wisconsin", + "city": "Bentonville" + } + }, + { + "id": 5879, + "name": "Monroe Rojas", + "gender": "male", + "age": 40, + "address": { + "state": "Rhode Island", + "city": "Haring" + } + }, + { + "id": 5880, + "name": "Angel Clements", + "gender": "female", + "age": 47, + "address": { + "state": "Kansas", + "city": "Grantville" + } + }, + { + "id": 5881, + "name": "Marion Mays", + "gender": "female", + "age": 42, + "address": { + "state": "Montana", + "city": "Evergreen" + } + }, + { + "id": 5882, + "name": "Dominique Foster", + "gender": "female", + "age": 48, + "address": { + "state": "Nevada", + "city": "Clara" + } + }, + { + "id": 5883, + "name": "Huber Watts", + "gender": "male", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Freetown" + } + }, + { + "id": 5884, + "name": "Jacobson Dean", + "gender": "male", + "age": 24, + "address": { + "state": "Indiana", + "city": "Retsof" + } + }, + { + "id": 5885, + "name": "Mullen Bryan", + "gender": "male", + "age": 27, + "address": { + "state": "West Virginia", + "city": "Allamuchy" + } + }, + { + "id": 5886, + "name": "James Marks", + "gender": "female", + "age": 72, + "address": { + "state": "Ohio", + "city": "Holcombe" + } + }, + { + "id": 5887, + "name": "Ilene Dyer", + "gender": "female", + "age": 42, + "address": { + "state": "California", + "city": "Lookingglass" + } + }, + { + "id": 5888, + "name": "Vance Pope", + "gender": "male", + "age": 47, + "address": { + "state": "Utah", + "city": "Ladera" + } + }, + { + "id": 5889, + "name": "Corina Paul", + "gender": "female", + "age": 38, + "address": { + "state": "Oklahoma", + "city": "Layhill" + } + }, + { + "id": 5890, + "name": "Phoebe Rasmussen", + "gender": "female", + "age": 31, + "address": { + "state": "Hawaii", + "city": "Drummond" + } + }, + { + "id": 5891, + "name": "Kirsten Russo", + "gender": "female", + "age": 60, + "address": { + "state": "Wyoming", + "city": "Gouglersville" + } + }, + { + "id": 5892, + "name": "Willa Ferguson", + "gender": "female", + "age": 45, + "address": { + "state": "Arkansas", + "city": "Yogaville" + } + }, + { + "id": 5893, + "name": "Bentley Tillman", + "gender": "male", + "age": 80, + "address": { + "state": "Missouri", + "city": "Adamstown" + } + }, + { + "id": 5894, + "name": "Pickett Guerra", + "gender": "male", + "age": 49, + "address": { + "state": "Massachusetts", + "city": "Osage" + } + }, + { + "id": 5895, + "name": "Kent Bowman", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Chloride" + } + }, + { + "id": 5896, + "name": "Battle Rodriquez", + "gender": "male", + "age": 20, + "address": { + "state": "Oregon", + "city": "Taycheedah" + } + }, + { + "id": 5897, + "name": "Holt Baker", + "gender": "male", + "age": 53, + "address": { + "state": "South Carolina", + "city": "Newkirk" + } + }, + { + "id": 5898, + "name": "Alyce Hawkins", + "gender": "female", + "age": 71, + "address": { + "state": "Rhode Island", + "city": "Beyerville" + } + }, + { + "id": 5899, + "name": "Orr Dejesus", + "gender": "male", + "age": 55, + "address": { + "state": "Minnesota", + "city": "Dale" + } + }, + { + "id": 5900, + "name": "Jenkins Dixon", + "gender": "male", + "age": 17, + "address": { + "state": "Mississippi", + "city": "Dunlo" + } + }, + { + "id": 5901, + "name": "Bird Maddox", + "gender": "male", + "age": 29, + "address": { + "state": "Virginia", + "city": "Stonybrook" + } + }, + { + "id": 5902, + "name": "Darcy Wiley", + "gender": "female", + "age": 48, + "address": { + "state": "Tennessee", + "city": "Camino" + } + }, + { + "id": 5903, + "name": "Irene Dunn", + "gender": "female", + "age": 68, + "address": { + "state": "Texas", + "city": "Salvo" + } + }, + { + "id": 5904, + "name": "Graciela Williams", + "gender": "female", + "age": 46, + "address": { + "state": "Pennsylvania", + "city": "Healy" + } + }, + { + "id": 5905, + "name": "Summer Harris", + "gender": "female", + "age": 45, + "address": { + "state": "Illinois", + "city": "Shaft" + } + }, + { + "id": 5906, + "name": "Collier Odonnell", + "gender": "male", + "age": 31, + "address": { + "state": "Michigan", + "city": "Crown" + } + }, + { + "id": 5907, + "name": "Freda Lancaster", + "gender": "female", + "age": 17, + "address": { + "state": "New Hampshire", + "city": "Saticoy" + } + }, + { + "id": 5908, + "name": "Boyd Copeland", + "gender": "male", + "age": 19, + "address": { + "state": "Maine", + "city": "Aguila" + } + }, + { + "id": 5909, + "name": "Antoinette Bass", + "gender": "female", + "age": 33, + "address": { + "state": "Vermont", + "city": "Groton" + } + }, + { + "id": 5910, + "name": "Mcmahon Robinson", + "gender": "male", + "age": 82, + "address": { + "state": "Alaska", + "city": "Chestnut" + } + }, + { + "id": 5911, + "name": "Lowery Dillard", + "gender": "male", + "age": 36, + "address": { + "state": "Kentucky", + "city": "Lawrence" + } + }, + { + "id": 5912, + "name": "James Rice", + "gender": "male", + "age": 38, + "address": { + "state": "Colorado", + "city": "Turah" + } + }, + { + "id": 5913, + "name": "Janine Hudson", + "gender": "female", + "age": 47, + "address": { + "state": "Washington", + "city": "Westwood" + } + }, + { + "id": 5914, + "name": "Russell Christensen", + "gender": "male", + "age": 18, + "address": { + "state": "Wisconsin", + "city": "Hemlock" + } + }, + { + "id": 5915, + "name": "Hewitt Hodge", + "gender": "male", + "age": 64, + "address": { + "state": "New Mexico", + "city": "Hardyville" + } + }, + { + "id": 5916, + "name": "Rivera Clayton", + "gender": "male", + "age": 64, + "address": { + "state": "South Dakota", + "city": "Loyalhanna" + } + }, + { + "id": 5917, + "name": "Heather Nguyen", + "gender": "female", + "age": 50, + "address": { + "state": "Alabama", + "city": "Grandview" + } + }, + { + "id": 5918, + "name": "Brigitte Bartlett", + "gender": "female", + "age": 74, + "address": { + "state": "Georgia", + "city": "Cliff" + } + }, + { + "id": 5919, + "name": "Rodriguez Phelps", + "gender": "male", + "age": 41, + "address": { + "state": "Maryland", + "city": "Watrous" + } + }, + { + "id": 5920, + "name": "Frazier Lucas", + "gender": "male", + "age": 70, + "address": { + "state": "Idaho", + "city": "Gibbsville" + } + }, + { + "id": 5921, + "name": "Horne Roberson", + "gender": "male", + "age": 23, + "address": { + "state": "New York", + "city": "Bellamy" + } + }, + { + "id": 5922, + "name": "Evangelina Ware", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Garberville" + } + }, + { + "id": 5923, + "name": "Simon Whitney", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Foscoe" + } + }, + { + "id": 5924, + "name": "Janie Mclaughlin", + "gender": "female", + "age": 57, + "address": { + "state": "New Jersey", + "city": "Lavalette" + } + }, + { + "id": 5925, + "name": "Mari Conley", + "gender": "female", + "age": 22, + "address": { + "state": "Connecticut", + "city": "Crenshaw" + } + }, + { + "id": 5926, + "name": "Mcbride Frederick", + "gender": "male", + "age": 69, + "address": { + "state": "Iowa", + "city": "Tuskahoma" + } + }, + { + "id": 5927, + "name": "Mccall Peters", + "gender": "male", + "age": 44, + "address": { + "state": "Florida", + "city": "Moscow" + } + }, + { + "id": 5928, + "name": "Greer Powers", + "gender": "male", + "age": 21, + "address": { + "state": "Louisiana", + "city": "Rivereno" + } + }, + { + "id": 5929, + "name": "Eliza Colon", + "gender": "female", + "age": 29, + "address": { + "state": "Connecticut", + "city": "Glenbrook" + } + }, + { + "id": 5930, + "name": "Jeannette Ayala", + "gender": "female", + "age": 54, + "address": { + "state": "Arkansas", + "city": "Lowgap" + } + }, + { + "id": 5931, + "name": "Sasha Mcdaniel", + "gender": "female", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Monument" + } + }, + { + "id": 5932, + "name": "Lolita Baxter", + "gender": "female", + "age": 26, + "address": { + "state": "Idaho", + "city": "Roosevelt" + } + }, + { + "id": 5933, + "name": "Watkins Leonard", + "gender": "male", + "age": 54, + "address": { + "state": "Ohio", + "city": "Bawcomville" + } + }, + { + "id": 5934, + "name": "Allison Pruitt", + "gender": "male", + "age": 71, + "address": { + "state": "Alabama", + "city": "Cazadero" + } + }, + { + "id": 5935, + "name": "Davenport Hobbs", + "gender": "male", + "age": 21, + "address": { + "state": "West Virginia", + "city": "Curtice" + } + }, + { + "id": 5936, + "name": "Lola Long", + "gender": "female", + "age": 45, + "address": { + "state": "South Dakota", + "city": "Glasgow" + } + }, + { + "id": 5937, + "name": "Ochoa Sullivan", + "gender": "male", + "age": 42, + "address": { + "state": "Virginia", + "city": "Sanborn" + } + }, + { + "id": 5938, + "name": "Penelope Mays", + "gender": "female", + "age": 64, + "address": { + "state": "Florida", + "city": "Rosine" + } + }, + { + "id": 5939, + "name": "Lorena Nolan", + "gender": "female", + "age": 26, + "address": { + "state": "New Hampshire", + "city": "Abrams" + } + }, + { + "id": 5940, + "name": "Lorraine Doyle", + "gender": "female", + "age": 70, + "address": { + "state": "Kentucky", + "city": "Witmer" + } + }, + { + "id": 5941, + "name": "Michele Blevins", + "gender": "female", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Springhill" + } + }, + { + "id": 5942, + "name": "Lucinda Herman", + "gender": "female", + "age": 37, + "address": { + "state": "South Carolina", + "city": "Centerville" + } + }, + { + "id": 5943, + "name": "Danielle Payne", + "gender": "female", + "age": 17, + "address": { + "state": "Louisiana", + "city": "Durham" + } + }, + { + "id": 5944, + "name": "Avis Nichols", + "gender": "female", + "age": 27, + "address": { + "state": "Nebraska", + "city": "Crawfordsville" + } + }, + { + "id": 5945, + "name": "Frederick Sharp", + "gender": "male", + "age": 29, + "address": { + "state": "Michigan", + "city": "Herbster" + } + }, + { + "id": 5946, + "name": "Ruthie Ortega", + "gender": "female", + "age": 22, + "address": { + "state": "Maryland", + "city": "Boling" + } + }, + { + "id": 5947, + "name": "Celina Gordon", + "gender": "female", + "age": 44, + "address": { + "state": "Iowa", + "city": "Calvary" + } + }, + { + "id": 5948, + "name": "Alvarez Prince", + "gender": "male", + "age": 59, + "address": { + "state": "Wisconsin", + "city": "Lisco" + } + }, + { + "id": 5949, + "name": "Lorna Aguilar", + "gender": "female", + "age": 25, + "address": { + "state": "Georgia", + "city": "Wolcott" + } + }, + { + "id": 5950, + "name": "Dominique Lowe", + "gender": "female", + "age": 40, + "address": { + "state": "North Dakota", + "city": "Thynedale" + } + }, + { + "id": 5951, + "name": "Roberta Castillo", + "gender": "female", + "age": 52, + "address": { + "state": "Nevada", + "city": "Irwin" + } + }, + { + "id": 5952, + "name": "Deena Crosby", + "gender": "female", + "age": 77, + "address": { + "state": "Texas", + "city": "Topanga" + } + }, + { + "id": 5953, + "name": "Marcie Odonnell", + "gender": "female", + "age": 64, + "address": { + "state": "New Mexico", + "city": "Maury" + } + }, + { + "id": 5954, + "name": "Oneil Blair", + "gender": "male", + "age": 70, + "address": { + "state": "Oregon", + "city": "Soudan" + } + }, + { + "id": 5955, + "name": "Melba Schwartz", + "gender": "female", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Dawn" + } + }, + { + "id": 5956, + "name": "Chan Booker", + "gender": "male", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Norfolk" + } + }, + { + "id": 5957, + "name": "Jamie Combs", + "gender": "female", + "age": 18, + "address": { + "state": "Colorado", + "city": "Driftwood" + } + }, + { + "id": 5958, + "name": "Craig Peters", + "gender": "male", + "age": 75, + "address": { + "state": "Alaska", + "city": "Bagtown" + } + }, + { + "id": 5959, + "name": "Lorie Shepherd", + "gender": "female", + "age": 41, + "address": { + "state": "New York", + "city": "Trail" + } + }, + { + "id": 5960, + "name": "Celeste Torres", + "gender": "female", + "age": 36, + "address": { + "state": "Arizona", + "city": "Dundee" + } + }, + { + "id": 5961, + "name": "Alma Houston", + "gender": "female", + "age": 43, + "address": { + "state": "California", + "city": "Boonville" + } + }, + { + "id": 5962, + "name": "Carney Terrell", + "gender": "male", + "age": 59, + "address": { + "state": "Hawaii", + "city": "Enetai" + } + }, + { + "id": 5963, + "name": "Kristy Branch", + "gender": "female", + "age": 35, + "address": { + "state": "Maine", + "city": "Masthope" + } + }, + { + "id": 5964, + "name": "Turner Lloyd", + "gender": "male", + "age": 24, + "address": { + "state": "Montana", + "city": "Sedley" + } + }, + { + "id": 5965, + "name": "Sanchez Mercado", + "gender": "male", + "age": 57, + "address": { + "state": "Kansas", + "city": "Gasquet" + } + }, + { + "id": 5966, + "name": "Roth Burton", + "gender": "male", + "age": 65, + "address": { + "state": "Washington", + "city": "Churchill" + } + }, + { + "id": 5967, + "name": "Mcintyre Hull", + "gender": "male", + "age": 23, + "address": { + "state": "Rhode Island", + "city": "Williams" + } + }, + { + "id": 5968, + "name": "Grace Tillman", + "gender": "female", + "age": 19, + "address": { + "state": "New Jersey", + "city": "Jacksonwald" + } + }, + { + "id": 5969, + "name": "Langley Merrill", + "gender": "male", + "age": 82, + "address": { + "state": "Delaware", + "city": "Bergoo" + } + }, + { + "id": 5970, + "name": "Natasha Nelson", + "gender": "female", + "age": 81, + "address": { + "state": "Indiana", + "city": "Kieler" + } + }, + { + "id": 5971, + "name": "Leach Mcdonald", + "gender": "male", + "age": 24, + "address": { + "state": "Wyoming", + "city": "Kohatk" + } + }, + { + "id": 5972, + "name": "Lindsay Landry", + "gender": "male", + "age": 73, + "address": { + "state": "Vermont", + "city": "Orason" + } + }, + { + "id": 5973, + "name": "Rosemarie Waters", + "gender": "female", + "age": 39, + "address": { + "state": "Massachusetts", + "city": "Salix" + } + }, + { + "id": 5974, + "name": "Wilkins Jensen", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Madaket" + } + }, + { + "id": 5975, + "name": "Jewell Benson", + "gender": "female", + "age": 31, + "address": { + "state": "Illinois", + "city": "Odessa" + } + }, + { + "id": 5976, + "name": "Della Mclaughlin", + "gender": "female", + "age": 78, + "address": { + "state": "Utah", + "city": "Cressey" + } + }, + { + "id": 5977, + "name": "Bowman Flores", + "gender": "male", + "age": 47, + "address": { + "state": "Missouri", + "city": "Blairstown" + } + }, + { + "id": 5978, + "name": "Baird Woodward", + "gender": "male", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Zeba" + } + }, + { + "id": 5979, + "name": "Odom Burgess", + "gender": "male", + "age": 64, + "address": { + "state": "Illinois", + "city": "Beason" + } + }, + { + "id": 5980, + "name": "Audrey Gilbert", + "gender": "female", + "age": 53, + "address": { + "state": "Arkansas", + "city": "Allison" + } + }, + { + "id": 5981, + "name": "Angelica Mooney", + "gender": "female", + "age": 76, + "address": { + "state": "Wisconsin", + "city": "Windsor" + } + }, + { + "id": 5982, + "name": "Lois Eaton", + "gender": "female", + "age": 58, + "address": { + "state": "Nevada", + "city": "Ruckersville" + } + }, + { + "id": 5983, + "name": "Briggs Guerrero", + "gender": "male", + "age": 18, + "address": { + "state": "Kentucky", + "city": "Veyo" + } + }, + { + "id": 5984, + "name": "Mable Richards", + "gender": "female", + "age": 46, + "address": { + "state": "California", + "city": "Delwood" + } + }, + { + "id": 5985, + "name": "Ruthie Farmer", + "gender": "female", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Loretto" + } + }, + { + "id": 5986, + "name": "Klein Garza", + "gender": "male", + "age": 52, + "address": { + "state": "Alabama", + "city": "Healy" + } + }, + { + "id": 5987, + "name": "Stewart Roy", + "gender": "male", + "age": 20, + "address": { + "state": "Michigan", + "city": "Osmond" + } + }, + { + "id": 5988, + "name": "Hahn Hartman", + "gender": "male", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Kilbourne" + } + }, + { + "id": 5989, + "name": "Vazquez Chandler", + "gender": "male", + "age": 24, + "address": { + "state": "Georgia", + "city": "Northridge" + } + }, + { + "id": 5990, + "name": "Day Tran", + "gender": "male", + "age": 28, + "address": { + "state": "New York", + "city": "Sehili" + } + }, + { + "id": 5991, + "name": "Lynnette Hurst", + "gender": "female", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Terlingua" + } + }, + { + "id": 5992, + "name": "Chaney Spears", + "gender": "male", + "age": 53, + "address": { + "state": "North Dakota", + "city": "Boling" + } + }, + { + "id": 5993, + "name": "Albert Hopkins", + "gender": "male", + "age": 78, + "address": { + "state": "West Virginia", + "city": "Edgewater" + } + }, + { + "id": 5994, + "name": "Antoinette Travis", + "gender": "female", + "age": 31, + "address": { + "state": "Rhode Island", + "city": "Ezel" + } + }, + { + "id": 5995, + "name": "York Medina", + "gender": "male", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Brewster" + } + }, + { + "id": 5996, + "name": "Polly Potter", + "gender": "female", + "age": 29, + "address": { + "state": "Connecticut", + "city": "Lumberton" + } + }, + { + "id": 5997, + "name": "Patton Sharp", + "gender": "male", + "age": 82, + "address": { + "state": "Arizona", + "city": "Marshall" + } + }, + { + "id": 5998, + "name": "Loretta Valencia", + "gender": "female", + "age": 68, + "address": { + "state": "Massachusetts", + "city": "Rosburg" + } + }, + { + "id": 5999, + "name": "Margaret Jennings", + "gender": "female", + "age": 82, + "address": { + "state": "Colorado", + "city": "Allamuchy" + } + }, + { + "id": 6000, + "name": "Suarez Glass", + "gender": "male", + "age": 27, + "address": { + "state": "New Mexico", + "city": "Dale" + } + }, + { + "id": 6001, + "name": "Alexandria Maynard", + "gender": "female", + "age": 69, + "address": { + "state": "Delaware", + "city": "Sidman" + } + }, + { + "id": 6002, + "name": "Wendy Wooten", + "gender": "female", + "age": 49, + "address": { + "state": "Virginia", + "city": "Cotopaxi" + } + }, + { + "id": 6003, + "name": "Gamble Levy", + "gender": "male", + "age": 76, + "address": { + "state": "Montana", + "city": "Dixie" + } + }, + { + "id": 6004, + "name": "Black Richmond", + "gender": "male", + "age": 63, + "address": { + "state": "Texas", + "city": "Dexter" + } + }, + { + "id": 6005, + "name": "Schroeder Robbins", + "gender": "male", + "age": 33, + "address": { + "state": "North Carolina", + "city": "Nutrioso" + } + }, + { + "id": 6006, + "name": "Nora Gutierrez", + "gender": "female", + "age": 30, + "address": { + "state": "New Hampshire", + "city": "Linganore" + } + }, + { + "id": 6007, + "name": "Nina Emerson", + "gender": "female", + "age": 68, + "address": { + "state": "Ohio", + "city": "Durham" + } + }, + { + "id": 6008, + "name": "Francis Williamson", + "gender": "female", + "age": 62, + "address": { + "state": "Nebraska", + "city": "Dahlen" + } + }, + { + "id": 6009, + "name": "Mccarty Hill", + "gender": "male", + "age": 77, + "address": { + "state": "Florida", + "city": "Eureka" + } + }, + { + "id": 6010, + "name": "Patti Bryan", + "gender": "female", + "age": 75, + "address": { + "state": "Kansas", + "city": "Thynedale" + } + }, + { + "id": 6011, + "name": "Pennington Tate", + "gender": "male", + "age": 36, + "address": { + "state": "Utah", + "city": "Floriston" + } + }, + { + "id": 6012, + "name": "Melton Burnett", + "gender": "male", + "age": 64, + "address": { + "state": "Iowa", + "city": "Mooresburg" + } + }, + { + "id": 6013, + "name": "Baldwin Reed", + "gender": "male", + "age": 20, + "address": { + "state": "Oklahoma", + "city": "Garnet" + } + }, + { + "id": 6014, + "name": "Jones Sanford", + "gender": "male", + "age": 39, + "address": { + "state": "Pennsylvania", + "city": "Elfrida" + } + }, + { + "id": 6015, + "name": "Katy Church", + "gender": "female", + "age": 63, + "address": { + "state": "Indiana", + "city": "Herald" + } + }, + { + "id": 6016, + "name": "Langley Case", + "gender": "male", + "age": 23, + "address": { + "state": "Alaska", + "city": "Alafaya" + } + }, + { + "id": 6017, + "name": "Rosa Heath", + "gender": "female", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Hemlock" + } + }, + { + "id": 6018, + "name": "Garrison Johnson", + "gender": "male", + "age": 62, + "address": { + "state": "Washington", + "city": "Maxville" + } + }, + { + "id": 6019, + "name": "Burton Green", + "gender": "male", + "age": 59, + "address": { + "state": "Vermont", + "city": "Marienthal" + } + }, + { + "id": 6020, + "name": "Patterson Charles", + "gender": "male", + "age": 25, + "address": { + "state": "Maine", + "city": "Springhill" + } + }, + { + "id": 6021, + "name": "Leona Berry", + "gender": "female", + "age": 60, + "address": { + "state": "Missouri", + "city": "Waverly" + } + }, + { + "id": 6022, + "name": "Clarke Trevino", + "gender": "male", + "age": 43, + "address": { + "state": "Idaho", + "city": "Stockdale" + } + }, + { + "id": 6023, + "name": "Franklin Brewer", + "gender": "male", + "age": 43, + "address": { + "state": "South Carolina", + "city": "Manila" + } + }, + { + "id": 6024, + "name": "Murray Walter", + "gender": "male", + "age": 52, + "address": { + "state": "Maryland", + "city": "Berlin" + } + }, + { + "id": 6025, + "name": "Ester Rogers", + "gender": "female", + "age": 52, + "address": { + "state": "Minnesota", + "city": "Sheatown" + } + }, + { + "id": 6026, + "name": "Solomon Acevedo", + "gender": "male", + "age": 80, + "address": { + "state": "Oregon", + "city": "Camas" + } + }, + { + "id": 6027, + "name": "Gill Douglas", + "gender": "male", + "age": 76, + "address": { + "state": "Oklahoma", + "city": "Brooktrails" + } + }, + { + "id": 6028, + "name": "Melton Harper", + "gender": "male", + "age": 29, + "address": { + "state": "Iowa", + "city": "Trail" + } + }, + { + "id": 6029, + "name": "Horne Boyer", + "gender": "male", + "age": 24, + "address": { + "state": "Missouri", + "city": "Helen" + } + }, + { + "id": 6030, + "name": "Jimenez Harding", + "gender": "male", + "age": 31, + "address": { + "state": "Ohio", + "city": "Machias" + } + }, + { + "id": 6031, + "name": "Mcclain Navarro", + "gender": "male", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Sussex" + } + }, + { + "id": 6032, + "name": "Acosta Cochran", + "gender": "male", + "age": 80, + "address": { + "state": "Alabama", + "city": "Chesterfield" + } + }, + { + "id": 6033, + "name": "Anderson Hernandez", + "gender": "male", + "age": 77, + "address": { + "state": "Michigan", + "city": "Tyhee" + } + }, + { + "id": 6034, + "name": "Tracey Perkins", + "gender": "female", + "age": 74, + "address": { + "state": "Maine", + "city": "Summerset" + } + }, + { + "id": 6035, + "name": "Gallegos Mcneil", + "gender": "male", + "age": 74, + "address": { + "state": "Washington", + "city": "Gerber" + } + }, + { + "id": 6036, + "name": "Genevieve Stark", + "gender": "female", + "age": 34, + "address": { + "state": "Oregon", + "city": "Jessie" + } + }, + { + "id": 6037, + "name": "Hunter Nunez", + "gender": "male", + "age": 77, + "address": { + "state": "Maryland", + "city": "Cobbtown" + } + }, + { + "id": 6038, + "name": "Shelia Rosa", + "gender": "female", + "age": 59, + "address": { + "state": "South Dakota", + "city": "Kent" + } + }, + { + "id": 6039, + "name": "Sheree Puckett", + "gender": "female", + "age": 25, + "address": { + "state": "California", + "city": "Tuttle" + } + }, + { + "id": 6040, + "name": "Estrada Hamilton", + "gender": "male", + "age": 66, + "address": { + "state": "Vermont", + "city": "Wanship" + } + }, + { + "id": 6041, + "name": "Whitley Mccray", + "gender": "male", + "age": 44, + "address": { + "state": "Minnesota", + "city": "Urbana" + } + }, + { + "id": 6042, + "name": "Aida Chen", + "gender": "female", + "age": 68, + "address": { + "state": "North Dakota", + "city": "Manila" + } + }, + { + "id": 6043, + "name": "Casey Jacobson", + "gender": "female", + "age": 53, + "address": { + "state": "Illinois", + "city": "Onton" + } + }, + { + "id": 6044, + "name": "Kaitlin Griffin", + "gender": "female", + "age": 72, + "address": { + "state": "Mississippi", + "city": "Brutus" + } + }, + { + "id": 6045, + "name": "Daugherty Dominguez", + "gender": "male", + "age": 62, + "address": { + "state": "Nebraska", + "city": "Yogaville" + } + }, + { + "id": 6046, + "name": "Randolph Butler", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Coyote" + } + }, + { + "id": 6047, + "name": "Tammy Cortez", + "gender": "female", + "age": 66, + "address": { + "state": "New Jersey", + "city": "Clara" + } + }, + { + "id": 6048, + "name": "Parsons Hooper", + "gender": "male", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Bluetown" + } + }, + { + "id": 6049, + "name": "Sophia Ayala", + "gender": "female", + "age": 27, + "address": { + "state": "Wisconsin", + "city": "Alamo" + } + }, + { + "id": 6050, + "name": "Montgomery Sosa", + "gender": "male", + "age": 82, + "address": { + "state": "Utah", + "city": "Biddle" + } + }, + { + "id": 6051, + "name": "Lloyd Melton", + "gender": "male", + "age": 22, + "address": { + "state": "West Virginia", + "city": "Dowling" + } + }, + { + "id": 6052, + "name": "Nadine Taylor", + "gender": "female", + "age": 24, + "address": { + "state": "Tennessee", + "city": "Manitou" + } + }, + { + "id": 6053, + "name": "Jaclyn Horton", + "gender": "female", + "age": 82, + "address": { + "state": "Florida", + "city": "Lavalette" + } + }, + { + "id": 6054, + "name": "Andrews Hopkins", + "gender": "male", + "age": 65, + "address": { + "state": "Hawaii", + "city": "Greensburg" + } + }, + { + "id": 6055, + "name": "Robinson Rocha", + "gender": "male", + "age": 38, + "address": { + "state": "Massachusetts", + "city": "Malo" + } + }, + { + "id": 6056, + "name": "Natasha Mcgowan", + "gender": "female", + "age": 75, + "address": { + "state": "Nevada", + "city": "Bordelonville" + } + }, + { + "id": 6057, + "name": "Sharpe Dotson", + "gender": "male", + "age": 32, + "address": { + "state": "Kentucky", + "city": "Roeville" + } + }, + { + "id": 6058, + "name": "Anthony Delacruz", + "gender": "male", + "age": 47, + "address": { + "state": "Arkansas", + "city": "Blue" + } + }, + { + "id": 6059, + "name": "Cecile Coffey", + "gender": "female", + "age": 37, + "address": { + "state": "Indiana", + "city": "Orason" + } + }, + { + "id": 6060, + "name": "Sophie Conley", + "gender": "female", + "age": 41, + "address": { + "state": "New Hampshire", + "city": "Buxton" + } + }, + { + "id": 6061, + "name": "Berg Crane", + "gender": "male", + "age": 66, + "address": { + "state": "Arizona", + "city": "Rutherford" + } + }, + { + "id": 6062, + "name": "Marissa Lott", + "gender": "female", + "age": 28, + "address": { + "state": "Connecticut", + "city": "Fairmount" + } + }, + { + "id": 6063, + "name": "Washington Obrien", + "gender": "male", + "age": 41, + "address": { + "state": "Texas", + "city": "Mahtowa" + } + }, + { + "id": 6064, + "name": "Patrica Kennedy", + "gender": "female", + "age": 52, + "address": { + "state": "Montana", + "city": "Hampstead" + } + }, + { + "id": 6065, + "name": "Rosalind Parsons", + "gender": "female", + "age": 82, + "address": { + "state": "New York", + "city": "Cliff" + } + }, + { + "id": 6066, + "name": "Bond Reese", + "gender": "male", + "age": 72, + "address": { + "state": "Pennsylvania", + "city": "Echo" + } + }, + { + "id": 6067, + "name": "Maryann Bolton", + "gender": "female", + "age": 72, + "address": { + "state": "Idaho", + "city": "Steinhatchee" + } + }, + { + "id": 6068, + "name": "Simpson Munoz", + "gender": "male", + "age": 73, + "address": { + "state": "Colorado", + "city": "Volta" + } + }, + { + "id": 6069, + "name": "Noemi Fletcher", + "gender": "female", + "age": 44, + "address": { + "state": "New Mexico", + "city": "Haena" + } + }, + { + "id": 6070, + "name": "Suzanne Cantu", + "gender": "female", + "age": 43, + "address": { + "state": "Georgia", + "city": "Saranap" + } + }, + { + "id": 6071, + "name": "Padilla Owens", + "gender": "male", + "age": 50, + "address": { + "state": "Louisiana", + "city": "Blandburg" + } + }, + { + "id": 6072, + "name": "Brandi Turner", + "gender": "female", + "age": 43, + "address": { + "state": "Rhode Island", + "city": "Cashtown" + } + }, + { + "id": 6073, + "name": "Cooke Bird", + "gender": "male", + "age": 50, + "address": { + "state": "Virginia", + "city": "Mathews" + } + }, + { + "id": 6074, + "name": "Lillie Avila", + "gender": "female", + "age": 46, + "address": { + "state": "North Carolina", + "city": "Cannondale" + } + }, + { + "id": 6075, + "name": "Dolly Stevenson", + "gender": "female", + "age": 61, + "address": { + "state": "Kansas", + "city": "Lutsen" + } + }, + { + "id": 6076, + "name": "Strong Nolan", + "gender": "male", + "age": 76, + "address": { + "state": "Missouri", + "city": "Lowgap" + } + }, + { + "id": 6077, + "name": "Frazier Shaffer", + "gender": "male", + "age": 17, + "address": { + "state": "Maine", + "city": "Walker" + } + }, + { + "id": 6078, + "name": "Munoz Leon", + "gender": "male", + "age": 33, + "address": { + "state": "Oklahoma", + "city": "Brandermill" + } + }, + { + "id": 6079, + "name": "Abigail Kent", + "gender": "female", + "age": 71, + "address": { + "state": "California", + "city": "Jacumba" + } + }, + { + "id": 6080, + "name": "Carmella Pratt", + "gender": "female", + "age": 65, + "address": { + "state": "New York", + "city": "Holcombe" + } + }, + { + "id": 6081, + "name": "May Sawyer", + "gender": "female", + "age": 40, + "address": { + "state": "Virginia", + "city": "Succasunna" + } + }, + { + "id": 6082, + "name": "Cortez Perez", + "gender": "male", + "age": 68, + "address": { + "state": "New Hampshire", + "city": "Vivian" + } + }, + { + "id": 6083, + "name": "Mcmillan Mejia", + "gender": "male", + "age": 49, + "address": { + "state": "Arizona", + "city": "Washington" + } + }, + { + "id": 6084, + "name": "Brown Lowery", + "gender": "male", + "age": 26, + "address": { + "state": "Oregon", + "city": "Sterling" + } + }, + { + "id": 6085, + "name": "Robbie Terrell", + "gender": "female", + "age": 55, + "address": { + "state": "Texas", + "city": "Hegins" + } + }, + { + "id": 6086, + "name": "Janell Chambers", + "gender": "female", + "age": 62, + "address": { + "state": "Kansas", + "city": "Ruffin" + } + }, + { + "id": 6087, + "name": "Ashlee Valenzuela", + "gender": "female", + "age": 80, + "address": { + "state": "Wyoming", + "city": "Bannock" + } + }, + { + "id": 6088, + "name": "Bradley Rasmussen", + "gender": "male", + "age": 44, + "address": { + "state": "Tennessee", + "city": "Dundee" + } + }, + { + "id": 6089, + "name": "Tamera Sloan", + "gender": "female", + "age": 31, + "address": { + "state": "North Dakota", + "city": "Fairacres" + } + }, + { + "id": 6090, + "name": "Hopkins Burt", + "gender": "male", + "age": 42, + "address": { + "state": "Michigan", + "city": "Gardners" + } + }, + { + "id": 6091, + "name": "Frank Mack", + "gender": "male", + "age": 51, + "address": { + "state": "Rhode Island", + "city": "Beaulieu" + } + }, + { + "id": 6092, + "name": "Farmer Jimenez", + "gender": "male", + "age": 29, + "address": { + "state": "New Jersey", + "city": "Manchester" + } + }, + { + "id": 6093, + "name": "Horton Haney", + "gender": "male", + "age": 26, + "address": { + "state": "Colorado", + "city": "Lydia" + } + }, + { + "id": 6094, + "name": "Livingston Rojas", + "gender": "male", + "age": 32, + "address": { + "state": "Washington", + "city": "Advance" + } + }, + { + "id": 6095, + "name": "Rosa Hodges", + "gender": "male", + "age": 73, + "address": { + "state": "Georgia", + "city": "Vincent" + } + }, + { + "id": 6096, + "name": "Candice Waters", + "gender": "female", + "age": 29, + "address": { + "state": "South Carolina", + "city": "Lafferty" + } + }, + { + "id": 6097, + "name": "Jewell Yates", + "gender": "female", + "age": 32, + "address": { + "state": "Minnesota", + "city": "Loyalhanna" + } + }, + { + "id": 6098, + "name": "Pratt Gomez", + "gender": "male", + "age": 65, + "address": { + "state": "Illinois", + "city": "Twilight" + } + }, + { + "id": 6099, + "name": "Dena Armstrong", + "gender": "female", + "age": 77, + "address": { + "state": "Iowa", + "city": "Itmann" + } + }, + { + "id": 6100, + "name": "Shanna Whitaker", + "gender": "female", + "age": 60, + "address": { + "state": "New Mexico", + "city": "Yukon" + } + }, + { + "id": 6101, + "name": "Carissa Barnes", + "gender": "female", + "age": 74, + "address": { + "state": "Kentucky", + "city": "Imperial" + } + }, + { + "id": 6102, + "name": "Paige Winters", + "gender": "female", + "age": 78, + "address": { + "state": "Mississippi", + "city": "Salix" + } + }, + { + "id": 6103, + "name": "Angel Franklin", + "gender": "female", + "age": 52, + "address": { + "state": "Arkansas", + "city": "Elfrida" + } + }, + { + "id": 6104, + "name": "Estella Morrow", + "gender": "female", + "age": 39, + "address": { + "state": "Connecticut", + "city": "Thornport" + } + }, + { + "id": 6105, + "name": "Diane Hatfield", + "gender": "female", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Forbestown" + } + }, + { + "id": 6106, + "name": "Angelina Richard", + "gender": "female", + "age": 58, + "address": { + "state": "Wisconsin", + "city": "Tivoli" + } + }, + { + "id": 6107, + "name": "Mccall Santiago", + "gender": "male", + "age": 70, + "address": { + "state": "Delaware", + "city": "Hoagland" + } + }, + { + "id": 6108, + "name": "West Knight", + "gender": "male", + "age": 26, + "address": { + "state": "North Carolina", + "city": "Westboro" + } + }, + { + "id": 6109, + "name": "Deann Davidson", + "gender": "female", + "age": 44, + "address": { + "state": "Alaska", + "city": "Stewart" + } + }, + { + "id": 6110, + "name": "Estela Mercado", + "gender": "female", + "age": 69, + "address": { + "state": "Maryland", + "city": "Summertown" + } + }, + { + "id": 6111, + "name": "Harvey Meyer", + "gender": "male", + "age": 67, + "address": { + "state": "Ohio", + "city": "Needmore" + } + }, + { + "id": 6112, + "name": "Mullen Mendez", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Spelter" + } + }, + { + "id": 6113, + "name": "Austin Powell", + "gender": "male", + "age": 70, + "address": { + "state": "Vermont", + "city": "Goldfield" + } + }, + { + "id": 6114, + "name": "Marylou Bridges", + "gender": "female", + "age": 39, + "address": { + "state": "South Dakota", + "city": "Sussex" + } + }, + { + "id": 6115, + "name": "Dorsey Pugh", + "gender": "male", + "age": 49, + "address": { + "state": "Alabama", + "city": "Frierson" + } + }, + { + "id": 6116, + "name": "Parsons Wynn", + "gender": "male", + "age": 19, + "address": { + "state": "Florida", + "city": "Hiko" + } + }, + { + "id": 6117, + "name": "Frankie Vinson", + "gender": "female", + "age": 18, + "address": { + "state": "Hawaii", + "city": "Grenelefe" + } + }, + { + "id": 6118, + "name": "Leila Cabrera", + "gender": "female", + "age": 27, + "address": { + "state": "Indiana", + "city": "Sanborn" + } + }, + { + "id": 6119, + "name": "Tammy Roth", + "gender": "female", + "age": 22, + "address": { + "state": "Massachusetts", + "city": "Waiohinu" + } + }, + { + "id": 6120, + "name": "Mcneil Mcbride", + "gender": "male", + "age": 42, + "address": { + "state": "Nevada", + "city": "Brookfield" + } + }, + { + "id": 6121, + "name": "Mavis Yang", + "gender": "female", + "age": 71, + "address": { + "state": "Utah", + "city": "Kimmell" + } + }, + { + "id": 6122, + "name": "Foley Trujillo", + "gender": "male", + "age": 52, + "address": { + "state": "Idaho", + "city": "Independence" + } + }, + { + "id": 6123, + "name": "Hendricks Livingston", + "gender": "male", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Esmont" + } + }, + { + "id": 6124, + "name": "Nikki Osborne", + "gender": "female", + "age": 19, + "address": { + "state": "Montana", + "city": "Kersey" + } + }, + { + "id": 6125, + "name": "Genevieve Rush", + "gender": "female", + "age": 52, + "address": { + "state": "Missouri", + "city": "Madaket" + } + }, + { + "id": 6126, + "name": "Lily Velazquez", + "gender": "female", + "age": 32, + "address": { + "state": "Vermont", + "city": "Winston" + } + }, + { + "id": 6127, + "name": "Sylvia Paul", + "gender": "female", + "age": 80, + "address": { + "state": "Georgia", + "city": "Wyano" + } + }, + { + "id": 6128, + "name": "Earlene Morton", + "gender": "female", + "age": 41, + "address": { + "state": "California", + "city": "Curtice" + } + }, + { + "id": 6129, + "name": "Avila Beard", + "gender": "male", + "age": 79, + "address": { + "state": "Connecticut", + "city": "Dawn" + } + }, + { + "id": 6130, + "name": "Benton Vance", + "gender": "male", + "age": 68, + "address": { + "state": "New Hampshire", + "city": "Hackneyville" + } + }, + { + "id": 6131, + "name": "Stacey Gallegos", + "gender": "female", + "age": 18, + "address": { + "state": "Minnesota", + "city": "Johnsonburg" + } + }, + { + "id": 6132, + "name": "Leona Salazar", + "gender": "female", + "age": 45, + "address": { + "state": "Maine", + "city": "Allendale" + } + }, + { + "id": 6133, + "name": "Eleanor Rutledge", + "gender": "female", + "age": 72, + "address": { + "state": "Alaska", + "city": "Churchill" + } + }, + { + "id": 6134, + "name": "Hale Steele", + "gender": "male", + "age": 67, + "address": { + "state": "South Carolina", + "city": "Muse" + } + }, + { + "id": 6135, + "name": "Townsend Pace", + "gender": "male", + "age": 57, + "address": { + "state": "Illinois", + "city": "Nash" + } + }, + { + "id": 6136, + "name": "Allison Combs", + "gender": "male", + "age": 32, + "address": { + "state": "Idaho", + "city": "Loomis" + } + }, + { + "id": 6137, + "name": "Moore Santana", + "gender": "male", + "age": 64, + "address": { + "state": "Delaware", + "city": "Mathews" + } + }, + { + "id": 6138, + "name": "Hensley Torres", + "gender": "male", + "age": 73, + "address": { + "state": "North Dakota", + "city": "Siglerville" + } + }, + { + "id": 6139, + "name": "Gail Alford", + "gender": "female", + "age": 59, + "address": { + "state": "Virginia", + "city": "Wildwood" + } + }, + { + "id": 6140, + "name": "Hess Bartlett", + "gender": "male", + "age": 33, + "address": { + "state": "Texas", + "city": "Shelby" + } + }, + { + "id": 6141, + "name": "Kristie Cole", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Rivereno" + } + }, + { + "id": 6142, + "name": "Althea Blair", + "gender": "female", + "age": 23, + "address": { + "state": "Ohio", + "city": "Odessa" + } + }, + { + "id": 6143, + "name": "Brigitte Watson", + "gender": "female", + "age": 21, + "address": { + "state": "Washington", + "city": "Fredericktown" + } + }, + { + "id": 6144, + "name": "Rosa Huff", + "gender": "female", + "age": 79, + "address": { + "state": "New Mexico", + "city": "Durham" + } + }, + { + "id": 6145, + "name": "Frazier Park", + "gender": "male", + "age": 25, + "address": { + "state": "Colorado", + "city": "Wakarusa" + } + }, + { + "id": 6146, + "name": "Lina Berger", + "gender": "female", + "age": 46, + "address": { + "state": "Wisconsin", + "city": "Wadsworth" + } + }, + { + "id": 6147, + "name": "Cannon Rodriguez", + "gender": "male", + "age": 62, + "address": { + "state": "Rhode Island", + "city": "Winfred" + } + }, + { + "id": 6148, + "name": "Salazar Baker", + "gender": "male", + "age": 23, + "address": { + "state": "North Carolina", + "city": "Freelandville" + } + }, + { + "id": 6149, + "name": "Darlene Cohen", + "gender": "female", + "age": 72, + "address": { + "state": "Iowa", + "city": "Boyd" + } + }, + { + "id": 6150, + "name": "Trisha Hancock", + "gender": "female", + "age": 30, + "address": { + "state": "Florida", + "city": "Movico" + } + }, + { + "id": 6151, + "name": "Acevedo Porter", + "gender": "male", + "age": 62, + "address": { + "state": "Tennessee", + "city": "Loretto" + } + }, + { + "id": 6152, + "name": "Trina Mccarthy", + "gender": "female", + "age": 59, + "address": { + "state": "Hawaii", + "city": "Greenbackville" + } + }, + { + "id": 6153, + "name": "Mercado Fry", + "gender": "male", + "age": 43, + "address": { + "state": "Mississippi", + "city": "Coaldale" + } + }, + { + "id": 6154, + "name": "Therese Neal", + "gender": "female", + "age": 18, + "address": { + "state": "Maryland", + "city": "Farmington" + } + }, + { + "id": 6155, + "name": "Sybil Daniels", + "gender": "female", + "age": 37, + "address": { + "state": "Nevada", + "city": "Troy" + } + }, + { + "id": 6156, + "name": "Josie Holman", + "gender": "female", + "age": 68, + "address": { + "state": "Louisiana", + "city": "Geyserville" + } + }, + { + "id": 6157, + "name": "Woods Hinton", + "gender": "male", + "age": 33, + "address": { + "state": "Oklahoma", + "city": "Lemoyne" + } + }, + { + "id": 6158, + "name": "Tran Buckner", + "gender": "male", + "age": 46, + "address": { + "state": "Alabama", + "city": "Deltaville" + } + }, + { + "id": 6159, + "name": "Hutchinson Olsen", + "gender": "male", + "age": 74, + "address": { + "state": "Oregon", + "city": "Jacksonwald" + } + }, + { + "id": 6160, + "name": "Powell Craft", + "gender": "male", + "age": 45, + "address": { + "state": "Massachusetts", + "city": "Skyland" + } + }, + { + "id": 6161, + "name": "Floyd Quinn", + "gender": "male", + "age": 33, + "address": { + "state": "Arizona", + "city": "Blende" + } + }, + { + "id": 6162, + "name": "Salas Cunningham", + "gender": "male", + "age": 57, + "address": { + "state": "Montana", + "city": "Alafaya" + } + }, + { + "id": 6163, + "name": "Gilbert Owen", + "gender": "male", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Glasgow" + } + }, + { + "id": 6164, + "name": "May Carver", + "gender": "female", + "age": 81, + "address": { + "state": "Michigan", + "city": "Cliffside" + } + }, + { + "id": 6165, + "name": "Alma Weeks", + "gender": "female", + "age": 55, + "address": { + "state": "New Jersey", + "city": "Thornport" + } + }, + { + "id": 6166, + "name": "Colette Garrison", + "gender": "female", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Snyderville" + } + }, + { + "id": 6167, + "name": "Mathis Fisher", + "gender": "male", + "age": 64, + "address": { + "state": "Kentucky", + "city": "Elizaville" + } + }, + { + "id": 6168, + "name": "Ayala Rosa", + "gender": "male", + "age": 39, + "address": { + "state": "Arkansas", + "city": "Draper" + } + }, + { + "id": 6169, + "name": "Goodwin Page", + "gender": "male", + "age": 46, + "address": { + "state": "Kansas", + "city": "Wikieup" + } + }, + { + "id": 6170, + "name": "Marcella Williams", + "gender": "female", + "age": 30, + "address": { + "state": "New York", + "city": "Elliston" + } + }, + { + "id": 6171, + "name": "Dunlap Moon", + "gender": "male", + "age": 27, + "address": { + "state": "Utah", + "city": "Riegelwood" + } + }, + { + "id": 6172, + "name": "George Dodson", + "gender": "male", + "age": 41, + "address": { + "state": "Wyoming", + "city": "Hasty" + } + }, + { + "id": 6173, + "name": "Caitlin Waters", + "gender": "female", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Dahlen" + } + }, + { + "id": 6174, + "name": "Casey Michael", + "gender": "male", + "age": 82, + "address": { + "state": "Rhode Island", + "city": "Ellerslie" + } + }, + { + "id": 6175, + "name": "Deanna Greene", + "gender": "female", + "age": 61, + "address": { + "state": "Montana", + "city": "Waterview" + } + }, + { + "id": 6176, + "name": "Alyssa Wise", + "gender": "female", + "age": 53, + "address": { + "state": "Wyoming", + "city": "Veyo" + } + }, + { + "id": 6177, + "name": "Esperanza Cain", + "gender": "female", + "age": 59, + "address": { + "state": "Idaho", + "city": "Condon" + } + }, + { + "id": 6178, + "name": "Ericka Gonzalez", + "gender": "female", + "age": 58, + "address": { + "state": "Indiana", + "city": "Needmore" + } + }, + { + "id": 6179, + "name": "Concetta Hood", + "gender": "female", + "age": 28, + "address": { + "state": "Alaska", + "city": "Oberlin" + } + }, + { + "id": 6180, + "name": "Debbie Randolph", + "gender": "female", + "age": 29, + "address": { + "state": "Arizona", + "city": "Ronco" + } + }, + { + "id": 6181, + "name": "Cathy Berg", + "gender": "female", + "age": 62, + "address": { + "state": "South Dakota", + "city": "Foxworth" + } + }, + { + "id": 6182, + "name": "Schneider Jordan", + "gender": "male", + "age": 20, + "address": { + "state": "Minnesota", + "city": "Chamizal" + } + }, + { + "id": 6183, + "name": "Rivers Schmidt", + "gender": "male", + "age": 47, + "address": { + "state": "West Virginia", + "city": "Dennard" + } + }, + { + "id": 6184, + "name": "Jennie Bell", + "gender": "female", + "age": 78, + "address": { + "state": "North Dakota", + "city": "Matthews" + } + }, + { + "id": 6185, + "name": "Hughes Hayden", + "gender": "male", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Leming" + } + }, + { + "id": 6186, + "name": "Patrice Keith", + "gender": "female", + "age": 68, + "address": { + "state": "Virginia", + "city": "Farmington" + } + }, + { + "id": 6187, + "name": "Baird Odom", + "gender": "male", + "age": 58, + "address": { + "state": "Massachusetts", + "city": "Bluetown" + } + }, + { + "id": 6188, + "name": "Lorrie Short", + "gender": "female", + "age": 27, + "address": { + "state": "Hawaii", + "city": "Freelandville" + } + }, + { + "id": 6189, + "name": "Hope Rojas", + "gender": "female", + "age": 26, + "address": { + "state": "Mississippi", + "city": "Ona" + } + }, + { + "id": 6190, + "name": "Lenora Lawrence", + "gender": "female", + "age": 20, + "address": { + "state": "Delaware", + "city": "Wakarusa" + } + }, + { + "id": 6191, + "name": "Clemons Casey", + "gender": "male", + "age": 29, + "address": { + "state": "Louisiana", + "city": "Enoree" + } + }, + { + "id": 6192, + "name": "Marcy Vincent", + "gender": "female", + "age": 47, + "address": { + "state": "Kentucky", + "city": "Blodgett" + } + }, + { + "id": 6193, + "name": "Ferrell Curry", + "gender": "male", + "age": 65, + "address": { + "state": "Texas", + "city": "Ahwahnee" + } + }, + { + "id": 6194, + "name": "Rush Morin", + "gender": "male", + "age": 74, + "address": { + "state": "Vermont", + "city": "Centerville" + } + }, + { + "id": 6195, + "name": "Adkins Leach", + "gender": "male", + "age": 74, + "address": { + "state": "Oregon", + "city": "Caledonia" + } + }, + { + "id": 6196, + "name": "Weeks Watkins", + "gender": "male", + "age": 30, + "address": { + "state": "Kansas", + "city": "Caln" + } + }, + { + "id": 6197, + "name": "Alston Talley", + "gender": "male", + "age": 38, + "address": { + "state": "Washington", + "city": "Concho" + } + }, + { + "id": 6198, + "name": "Carole Burks", + "gender": "female", + "age": 54, + "address": { + "state": "Illinois", + "city": "Hickory" + } + }, + { + "id": 6199, + "name": "Sheila Rasmussen", + "gender": "female", + "age": 82, + "address": { + "state": "Michigan", + "city": "Warren" + } + }, + { + "id": 6200, + "name": "Branch Banks", + "gender": "male", + "age": 42, + "address": { + "state": "New York", + "city": "Bethany" + } + }, + { + "id": 6201, + "name": "Juliette Camacho", + "gender": "female", + "age": 26, + "address": { + "state": "Florida", + "city": "Cherokee" + } + }, + { + "id": 6202, + "name": "Cindy Best", + "gender": "female", + "age": 40, + "address": { + "state": "Colorado", + "city": "Fostoria" + } + }, + { + "id": 6203, + "name": "Lucas Ortiz", + "gender": "male", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Longbranch" + } + }, + { + "id": 6204, + "name": "Strong England", + "gender": "male", + "age": 39, + "address": { + "state": "Maryland", + "city": "Sharon" + } + }, + { + "id": 6205, + "name": "Hale Ruiz", + "gender": "male", + "age": 60, + "address": { + "state": "Wisconsin", + "city": "Somerset" + } + }, + { + "id": 6206, + "name": "Carpenter Alford", + "gender": "male", + "age": 35, + "address": { + "state": "Ohio", + "city": "Hilltop" + } + }, + { + "id": 6207, + "name": "Erma Weber", + "gender": "female", + "age": 29, + "address": { + "state": "North Carolina", + "city": "Gracey" + } + }, + { + "id": 6208, + "name": "Louise Clarke", + "gender": "female", + "age": 78, + "address": { + "state": "Iowa", + "city": "Hiwasse" + } + }, + { + "id": 6209, + "name": "Colette Cruz", + "gender": "female", + "age": 37, + "address": { + "state": "California", + "city": "Remington" + } + }, + { + "id": 6210, + "name": "Cassie Jensen", + "gender": "female", + "age": 32, + "address": { + "state": "New Hampshire", + "city": "Cornucopia" + } + }, + { + "id": 6211, + "name": "Douglas Sellers", + "gender": "male", + "age": 35, + "address": { + "state": "Connecticut", + "city": "Hardyville" + } + }, + { + "id": 6212, + "name": "Joyner Dudley", + "gender": "male", + "age": 79, + "address": { + "state": "Arkansas", + "city": "Frank" + } + }, + { + "id": 6213, + "name": "Mullen Davidson", + "gender": "male", + "age": 46, + "address": { + "state": "Oklahoma", + "city": "Snyderville" + } + }, + { + "id": 6214, + "name": "Edwards Gaines", + "gender": "male", + "age": 69, + "address": { + "state": "Pennsylvania", + "city": "Brogan" + } + }, + { + "id": 6215, + "name": "Espinoza Summers", + "gender": "male", + "age": 68, + "address": { + "state": "Nebraska", + "city": "Clara" + } + }, + { + "id": 6216, + "name": "Norris Schroeder", + "gender": "male", + "age": 30, + "address": { + "state": "New Jersey", + "city": "Caron" + } + }, + { + "id": 6217, + "name": "Gay Wood", + "gender": "female", + "age": 37, + "address": { + "state": "Maine", + "city": "Brethren" + } + }, + { + "id": 6218, + "name": "Mercer Wilkinson", + "gender": "male", + "age": 34, + "address": { + "state": "Missouri", + "city": "Twilight" + } + }, + { + "id": 6219, + "name": "Casey Bullock", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Falmouth" + } + }, + { + "id": 6220, + "name": "Fitzpatrick Ayala", + "gender": "male", + "age": 22, + "address": { + "state": "Nevada", + "city": "Dexter" + } + }, + { + "id": 6221, + "name": "Burke Justice", + "gender": "male", + "age": 17, + "address": { + "state": "Georgia", + "city": "Roland" + } + }, + { + "id": 6222, + "name": "Sophia George", + "gender": "female", + "age": 19, + "address": { + "state": "Tennessee", + "city": "Haena" + } + }, + { + "id": 6223, + "name": "Valencia Ewing", + "gender": "male", + "age": 28, + "address": { + "state": "Delaware", + "city": "Soham" + } + }, + { + "id": 6224, + "name": "Rochelle Brooks", + "gender": "female", + "age": 32, + "address": { + "state": "Arizona", + "city": "Benson" + } + }, + { + "id": 6225, + "name": "Kirkland Hudson", + "gender": "male", + "age": 53, + "address": { + "state": "Vermont", + "city": "Drummond" + } + }, + { + "id": 6226, + "name": "Shepherd Cabrera", + "gender": "male", + "age": 22, + "address": { + "state": "Minnesota", + "city": "Dupuyer" + } + }, + { + "id": 6227, + "name": "Stewart Price", + "gender": "male", + "age": 28, + "address": { + "state": "Kentucky", + "city": "Bladensburg" + } + }, + { + "id": 6228, + "name": "Mable Webster", + "gender": "female", + "age": 37, + "address": { + "state": "New Jersey", + "city": "Belmont" + } + }, + { + "id": 6229, + "name": "Marguerite Delaney", + "gender": "female", + "age": 30, + "address": { + "state": "South Dakota", + "city": "Hollins" + } + }, + { + "id": 6230, + "name": "Maldonado Rivas", + "gender": "male", + "age": 65, + "address": { + "state": "Texas", + "city": "Chesapeake" + } + }, + { + "id": 6231, + "name": "Gross Walter", + "gender": "male", + "age": 28, + "address": { + "state": "Virginia", + "city": "Loretto" + } + }, + { + "id": 6232, + "name": "Wolf Perkins", + "gender": "male", + "age": 64, + "address": { + "state": "Hawaii", + "city": "Highland" + } + }, + { + "id": 6233, + "name": "Jeanne Noel", + "gender": "female", + "age": 57, + "address": { + "state": "California", + "city": "Wacissa" + } + }, + { + "id": 6234, + "name": "Watts Le", + "gender": "male", + "age": 29, + "address": { + "state": "New Hampshire", + "city": "Newry" + } + }, + { + "id": 6235, + "name": "Amalia Williams", + "gender": "female", + "age": 79, + "address": { + "state": "Michigan", + "city": "Glenville" + } + }, + { + "id": 6236, + "name": "Edna Cunningham", + "gender": "female", + "age": 51, + "address": { + "state": "Iowa", + "city": "Iola" + } + }, + { + "id": 6237, + "name": "Amie Jefferson", + "gender": "female", + "age": 59, + "address": { + "state": "North Carolina", + "city": "Calverton" + } + }, + { + "id": 6238, + "name": "Mays Vinson", + "gender": "male", + "age": 47, + "address": { + "state": "Mississippi", + "city": "Graball" + } + }, + { + "id": 6239, + "name": "Middleton Steele", + "gender": "male", + "age": 78, + "address": { + "state": "Massachusetts", + "city": "Deseret" + } + }, + { + "id": 6240, + "name": "Hartman Sears", + "gender": "male", + "age": 32, + "address": { + "state": "Kansas", + "city": "Dyckesville" + } + }, + { + "id": 6241, + "name": "Meyers Doyle", + "gender": "male", + "age": 57, + "address": { + "state": "Indiana", + "city": "Aguila" + } + }, + { + "id": 6242, + "name": "Cynthia Pacheco", + "gender": "female", + "age": 79, + "address": { + "state": "Connecticut", + "city": "Sedley" + } + }, + { + "id": 6243, + "name": "Dyer Simmons", + "gender": "male", + "age": 56, + "address": { + "state": "Nevada", + "city": "Smeltertown" + } + }, + { + "id": 6244, + "name": "Hawkins Ramsey", + "gender": "male", + "age": 28, + "address": { + "state": "New Mexico", + "city": "Clarksburg" + } + }, + { + "id": 6245, + "name": "Isabelle Hurst", + "gender": "female", + "age": 51, + "address": { + "state": "North Dakota", + "city": "Holcombe" + } + }, + { + "id": 6246, + "name": "Saundra England", + "gender": "female", + "age": 26, + "address": { + "state": "Nebraska", + "city": "Courtland" + } + }, + { + "id": 6247, + "name": "Hannah Shepherd", + "gender": "female", + "age": 82, + "address": { + "state": "Montana", + "city": "Rossmore" + } + }, + { + "id": 6248, + "name": "Fischer Yang", + "gender": "male", + "age": 82, + "address": { + "state": "South Carolina", + "city": "Wheaton" + } + }, + { + "id": 6249, + "name": "Carrie Lambert", + "gender": "female", + "age": 75, + "address": { + "state": "Colorado", + "city": "Grandview" + } + }, + { + "id": 6250, + "name": "Mabel Deleon", + "gender": "female", + "age": 63, + "address": { + "state": "Illinois", + "city": "Bendon" + } + }, + { + "id": 6251, + "name": "Alison Kemp", + "gender": "female", + "age": 65, + "address": { + "state": "Alabama", + "city": "Olney" + } + }, + { + "id": 6252, + "name": "Tyson Shannon", + "gender": "male", + "age": 30, + "address": { + "state": "Maine", + "city": "Bennett" + } + }, + { + "id": 6253, + "name": "Lilly Potts", + "gender": "female", + "age": 48, + "address": { + "state": "Oregon", + "city": "Hickory" + } + }, + { + "id": 6254, + "name": "Adela Williamson", + "gender": "female", + "age": 60, + "address": { + "state": "Florida", + "city": "Hoagland" + } + }, + { + "id": 6255, + "name": "Jolene Snider", + "gender": "female", + "age": 17, + "address": { + "state": "West Virginia", + "city": "Sims" + } + }, + { + "id": 6256, + "name": "Anthony Sullivan", + "gender": "male", + "age": 48, + "address": { + "state": "Wyoming", + "city": "Welda" + } + }, + { + "id": 6257, + "name": "Clarice Baxter", + "gender": "female", + "age": 77, + "address": { + "state": "Washington", + "city": "Boling" + } + }, + { + "id": 6258, + "name": "Clemons Church", + "gender": "male", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Mulberry" + } + }, + { + "id": 6259, + "name": "Cora Ayers", + "gender": "female", + "age": 67, + "address": { + "state": "Georgia", + "city": "Tampico" + } + }, + { + "id": 6260, + "name": "Frieda English", + "gender": "female", + "age": 74, + "address": { + "state": "Rhode Island", + "city": "Dahlen" + } + }, + { + "id": 6261, + "name": "Amparo Rollins", + "gender": "female", + "age": 25, + "address": { + "state": "Ohio", + "city": "Gwynn" + } + }, + { + "id": 6262, + "name": "Ryan Ryan", + "gender": "male", + "age": 35, + "address": { + "state": "Arkansas", + "city": "Stagecoach" + } + }, + { + "id": 6263, + "name": "Huffman Chase", + "gender": "male", + "age": 66, + "address": { + "state": "Idaho", + "city": "Magnolia" + } + }, + { + "id": 6264, + "name": "Hazel Lynn", + "gender": "female", + "age": 36, + "address": { + "state": "Louisiana", + "city": "Coldiron" + } + }, + { + "id": 6265, + "name": "Carlson Hill", + "gender": "male", + "age": 71, + "address": { + "state": "Alaska", + "city": "Cliff" + } + }, + { + "id": 6266, + "name": "Heath Rosa", + "gender": "male", + "age": 45, + "address": { + "state": "Missouri", + "city": "Kersey" + } + }, + { + "id": 6267, + "name": "Catalina Tyler", + "gender": "female", + "age": 71, + "address": { + "state": "Oklahoma", + "city": "Greenwich" + } + }, + { + "id": 6268, + "name": "Hurley Dillon", + "gender": "male", + "age": 24, + "address": { + "state": "Maryland", + "city": "Dargan" + } + }, + { + "id": 6269, + "name": "Hansen Shepard", + "gender": "male", + "age": 78, + "address": { + "state": "New York", + "city": "Duryea" + } + }, + { + "id": 6270, + "name": "Moses Mooney", + "gender": "male", + "age": 63, + "address": { + "state": "Wisconsin", + "city": "Marienthal" + } + }, + { + "id": 6271, + "name": "Ginger Roman", + "gender": "female", + "age": 34, + "address": { + "state": "Utah", + "city": "Coral" + } + }, + { + "id": 6272, + "name": "Butler Holland", + "gender": "male", + "age": 48, + "address": { + "state": "Delaware", + "city": "Maplewood" + } + }, + { + "id": 6273, + "name": "Roach Garza", + "gender": "male", + "age": 44, + "address": { + "state": "Indiana", + "city": "Brantleyville" + } + }, + { + "id": 6274, + "name": "Stone Terry", + "gender": "male", + "age": 21, + "address": { + "state": "Mississippi", + "city": "Dupuyer" + } + }, + { + "id": 6275, + "name": "Hope Eaton", + "gender": "female", + "age": 50, + "address": { + "state": "North Dakota", + "city": "Greenock" + } + }, + { + "id": 6276, + "name": "Mcneil Everett", + "gender": "male", + "age": 71, + "address": { + "state": "Maine", + "city": "Springhill" + } + }, + { + "id": 6277, + "name": "Allyson Stephens", + "gender": "female", + "age": 26, + "address": { + "state": "Colorado", + "city": "Caspar" + } + }, + { + "id": 6278, + "name": "Ollie Lawrence", + "gender": "female", + "age": 23, + "address": { + "state": "New Mexico", + "city": "Brutus" + } + }, + { + "id": 6279, + "name": "Nola Johns", + "gender": "female", + "age": 22, + "address": { + "state": "Oregon", + "city": "Gibsonia" + } + }, + { + "id": 6280, + "name": "Caroline Colon", + "gender": "female", + "age": 56, + "address": { + "state": "Utah", + "city": "Dargan" + } + }, + { + "id": 6281, + "name": "Denise Bowen", + "gender": "female", + "age": 45, + "address": { + "state": "Kansas", + "city": "Loma" + } + }, + { + "id": 6282, + "name": "Pierce Rogers", + "gender": "male", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Warsaw" + } + }, + { + "id": 6283, + "name": "Bertie Rodgers", + "gender": "female", + "age": 35, + "address": { + "state": "Michigan", + "city": "Disautel" + } + }, + { + "id": 6284, + "name": "Helen Marquez", + "gender": "female", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Witmer" + } + }, + { + "id": 6285, + "name": "Carmela Sheppard", + "gender": "female", + "age": 69, + "address": { + "state": "Nebraska", + "city": "Valmy" + } + }, + { + "id": 6286, + "name": "Mcdonald Knight", + "gender": "male", + "age": 70, + "address": { + "state": "South Dakota", + "city": "Faywood" + } + }, + { + "id": 6287, + "name": "Crystal King", + "gender": "female", + "age": 77, + "address": { + "state": "Rhode Island", + "city": "Stockwell" + } + }, + { + "id": 6288, + "name": "Sylvia Livingston", + "gender": "female", + "age": 71, + "address": { + "state": "Louisiana", + "city": "Interlochen" + } + }, + { + "id": 6289, + "name": "Villarreal Hester", + "gender": "male", + "age": 28, + "address": { + "state": "Missouri", + "city": "Rockhill" + } + }, + { + "id": 6290, + "name": "Michael Castro", + "gender": "male", + "age": 32, + "address": { + "state": "Washington", + "city": "Graniteville" + } + }, + { + "id": 6291, + "name": "Jacquelyn Keith", + "gender": "female", + "age": 31, + "address": { + "state": "Arizona", + "city": "Concho" + } + }, + { + "id": 6292, + "name": "Hale Hunt", + "gender": "male", + "age": 61, + "address": { + "state": "West Virginia", + "city": "Fresno" + } + }, + { + "id": 6293, + "name": "Blackburn Ortiz", + "gender": "male", + "age": 79, + "address": { + "state": "Idaho", + "city": "Wiscon" + } + }, + { + "id": 6294, + "name": "Koch Lindsay", + "gender": "male", + "age": 23, + "address": { + "state": "Vermont", + "city": "Clara" + } + }, + { + "id": 6295, + "name": "Juana Becker", + "gender": "female", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Gallina" + } + }, + { + "id": 6296, + "name": "Petersen Hicks", + "gender": "male", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Holcombe" + } + }, + { + "id": 6297, + "name": "Rivers Carson", + "gender": "male", + "age": 38, + "address": { + "state": "Massachusetts", + "city": "Seymour" + } + }, + { + "id": 6298, + "name": "Fischer Bradshaw", + "gender": "male", + "age": 55, + "address": { + "state": "New Jersey", + "city": "Garnet" + } + }, + { + "id": 6299, + "name": "Knapp Mclaughlin", + "gender": "male", + "age": 79, + "address": { + "state": "Maryland", + "city": "Chesapeake" + } + }, + { + "id": 6300, + "name": "Rice Gardner", + "gender": "male", + "age": 39, + "address": { + "state": "Illinois", + "city": "Loomis" + } + }, + { + "id": 6301, + "name": "Bates Baird", + "gender": "male", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Crumpler" + } + }, + { + "id": 6302, + "name": "Bryant Lott", + "gender": "male", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Brandermill" + } + }, + { + "id": 6303, + "name": "Alice Tyson", + "gender": "female", + "age": 27, + "address": { + "state": "Arkansas", + "city": "Robinson" + } + }, + { + "id": 6304, + "name": "Virginia Bryan", + "gender": "female", + "age": 61, + "address": { + "state": "Alaska", + "city": "Yettem" + } + }, + { + "id": 6305, + "name": "Tyson Lester", + "gender": "male", + "age": 55, + "address": { + "state": "Florida", + "city": "Bordelonville" + } + }, + { + "id": 6306, + "name": "Armstrong Evans", + "gender": "male", + "age": 28, + "address": { + "state": "Tennessee", + "city": "Fontanelle" + } + }, + { + "id": 6307, + "name": "Lakeisha Barber", + "gender": "female", + "age": 31, + "address": { + "state": "Iowa", + "city": "Romeville" + } + }, + { + "id": 6308, + "name": "Letitia Mathews", + "gender": "female", + "age": 50, + "address": { + "state": "New York", + "city": "Omar" + } + }, + { + "id": 6309, + "name": "Sonja Hardy", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Harviell" + } + }, + { + "id": 6310, + "name": "Kathie Holt", + "gender": "female", + "age": 79, + "address": { + "state": "Georgia", + "city": "Sunriver" + } + }, + { + "id": 6311, + "name": "Lara Shepard", + "gender": "female", + "age": 32, + "address": { + "state": "Texas", + "city": "Williams" + } + }, + { + "id": 6312, + "name": "John David", + "gender": "female", + "age": 78, + "address": { + "state": "Nevada", + "city": "Kennedyville" + } + }, + { + "id": 6313, + "name": "Savage Hampton", + "gender": "male", + "age": 26, + "address": { + "state": "California", + "city": "Wescosville" + } + }, + { + "id": 6314, + "name": "Sanchez Carver", + "gender": "male", + "age": 22, + "address": { + "state": "Alabama", + "city": "Lutsen" + } + }, + { + "id": 6315, + "name": "Nolan Dalton", + "gender": "male", + "age": 79, + "address": { + "state": "Connecticut", + "city": "Castleton" + } + }, + { + "id": 6316, + "name": "Paulette Sellers", + "gender": "female", + "age": 54, + "address": { + "state": "Kentucky", + "city": "Glidden" + } + }, + { + "id": 6317, + "name": "Craig Sexton", + "gender": "male", + "age": 69, + "address": { + "state": "Wisconsin", + "city": "Southmont" + } + }, + { + "id": 6318, + "name": "Lee Greene", + "gender": "female", + "age": 51, + "address": { + "state": "Ohio", + "city": "Bentley" + } + }, + { + "id": 6319, + "name": "Constance Dixon", + "gender": "female", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Savage" + } + }, + { + "id": 6320, + "name": "Erna Brewer", + "gender": "female", + "age": 46, + "address": { + "state": "Montana", + "city": "Gwynn" + } + }, + { + "id": 6321, + "name": "Oliver Church", + "gender": "male", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Jacksonwald" + } + }, + { + "id": 6322, + "name": "Barnett Mercer", + "gender": "male", + "age": 27, + "address": { + "state": "North Dakota", + "city": "Wadsworth" + } + }, + { + "id": 6323, + "name": "Ines Harper", + "gender": "female", + "age": 23, + "address": { + "state": "Wisconsin", + "city": "Fairforest" + } + }, + { + "id": 6324, + "name": "Foley Wheeler", + "gender": "male", + "age": 22, + "address": { + "state": "Oregon", + "city": "Lowgap" + } + }, + { + "id": 6325, + "name": "Durham Cortez", + "gender": "male", + "age": 49, + "address": { + "state": "Michigan", + "city": "Dundee" + } + }, + { + "id": 6326, + "name": "Leah Williamson", + "gender": "female", + "age": 28, + "address": { + "state": "Indiana", + "city": "Terlingua" + } + }, + { + "id": 6327, + "name": "Barton Mcmahon", + "gender": "male", + "age": 79, + "address": { + "state": "Nevada", + "city": "Edenburg" + } + }, + { + "id": 6328, + "name": "Bertie Garza", + "gender": "female", + "age": 65, + "address": { + "state": "West Virginia", + "city": "Woodburn" + } + }, + { + "id": 6329, + "name": "Lesa Mullen", + "gender": "female", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Ola" + } + }, + { + "id": 6330, + "name": "Decker Welch", + "gender": "male", + "age": 29, + "address": { + "state": "Kansas", + "city": "Tuskahoma" + } + }, + { + "id": 6331, + "name": "Hess Lindsay", + "gender": "male", + "age": 44, + "address": { + "state": "Virginia", + "city": "Manitou" + } + }, + { + "id": 6332, + "name": "Malinda Hess", + "gender": "female", + "age": 72, + "address": { + "state": "Montana", + "city": "Gambrills" + } + }, + { + "id": 6333, + "name": "Hallie Langley", + "gender": "female", + "age": 46, + "address": { + "state": "Oklahoma", + "city": "Templeton" + } + }, + { + "id": 6334, + "name": "Silva Stafford", + "gender": "male", + "age": 53, + "address": { + "state": "Rhode Island", + "city": "Wheatfields" + } + }, + { + "id": 6335, + "name": "Dianna Suarez", + "gender": "female", + "age": 56, + "address": { + "state": "New Jersey", + "city": "Lowell" + } + }, + { + "id": 6336, + "name": "Berger Rice", + "gender": "male", + "age": 27, + "address": { + "state": "New York", + "city": "Mathews" + } + }, + { + "id": 6337, + "name": "Eloise Mccray", + "gender": "female", + "age": 24, + "address": { + "state": "Kentucky", + "city": "Sabillasville" + } + }, + { + "id": 6338, + "name": "Barbara Lindsey", + "gender": "female", + "age": 73, + "address": { + "state": "Washington", + "city": "Osage" + } + }, + { + "id": 6339, + "name": "Doris Weeks", + "gender": "female", + "age": 47, + "address": { + "state": "Utah", + "city": "Venice" + } + }, + { + "id": 6340, + "name": "Betty Christian", + "gender": "female", + "age": 68, + "address": { + "state": "Colorado", + "city": "Trona" + } + }, + { + "id": 6341, + "name": "Erin Shannon", + "gender": "female", + "age": 34, + "address": { + "state": "Alabama", + "city": "Ruckersville" + } + }, + { + "id": 6342, + "name": "Jenny Horn", + "gender": "female", + "age": 23, + "address": { + "state": "Delaware", + "city": "Walker" + } + }, + { + "id": 6343, + "name": "Hurley Trevino", + "gender": "male", + "age": 45, + "address": { + "state": "Mississippi", + "city": "Lumberton" + } + }, + { + "id": 6344, + "name": "Cherry Holmes", + "gender": "male", + "age": 25, + "address": { + "state": "Pennsylvania", + "city": "Bend" + } + }, + { + "id": 6345, + "name": "Marissa Williams", + "gender": "female", + "age": 79, + "address": { + "state": "Tennessee", + "city": "Norvelt" + } + }, + { + "id": 6346, + "name": "Addie Osborne", + "gender": "female", + "age": 17, + "address": { + "state": "Texas", + "city": "Alamo" + } + }, + { + "id": 6347, + "name": "Key Navarro", + "gender": "male", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Hall" + } + }, + { + "id": 6348, + "name": "Jeannie Pruitt", + "gender": "female", + "age": 76, + "address": { + "state": "Illinois", + "city": "Hardyville" + } + }, + { + "id": 6349, + "name": "Dominguez Bolton", + "gender": "male", + "age": 20, + "address": { + "state": "South Dakota", + "city": "Belfair" + } + }, + { + "id": 6350, + "name": "Imelda Lara", + "gender": "female", + "age": 63, + "address": { + "state": "Georgia", + "city": "Newcastle" + } + }, + { + "id": 6351, + "name": "Delacruz Middleton", + "gender": "male", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Coventry" + } + }, + { + "id": 6352, + "name": "Espinoza Rojas", + "gender": "male", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Foxworth" + } + }, + { + "id": 6353, + "name": "Charlotte Hays", + "gender": "female", + "age": 55, + "address": { + "state": "Vermont", + "city": "Hegins" + } + }, + { + "id": 6354, + "name": "Laura Goff", + "gender": "female", + "age": 34, + "address": { + "state": "Maine", + "city": "Manila" + } + }, + { + "id": 6355, + "name": "England Huffman", + "gender": "male", + "age": 46, + "address": { + "state": "Idaho", + "city": "Chumuckla" + } + }, + { + "id": 6356, + "name": "Neva Calderon", + "gender": "female", + "age": 50, + "address": { + "state": "North Carolina", + "city": "Marienthal" + } + }, + { + "id": 6357, + "name": "Moses Mccullough", + "gender": "male", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Bethpage" + } + }, + { + "id": 6358, + "name": "Shari Reese", + "gender": "female", + "age": 39, + "address": { + "state": "Florida", + "city": "Ogema" + } + }, + { + "id": 6359, + "name": "Weeks White", + "gender": "male", + "age": 76, + "address": { + "state": "Maryland", + "city": "Hondah" + } + }, + { + "id": 6360, + "name": "Cabrera Kennedy", + "gender": "male", + "age": 75, + "address": { + "state": "California", + "city": "Virgie" + } + }, + { + "id": 6361, + "name": "Cardenas Holt", + "gender": "male", + "age": 74, + "address": { + "state": "Wyoming", + "city": "Sardis" + } + }, + { + "id": 6362, + "name": "Jimmie Stanton", + "gender": "female", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Beechmont" + } + }, + { + "id": 6363, + "name": "Noreen Allen", + "gender": "female", + "age": 40, + "address": { + "state": "Arkansas", + "city": "Moquino" + } + }, + { + "id": 6364, + "name": "Carr Payne", + "gender": "male", + "age": 33, + "address": { + "state": "Minnesota", + "city": "Duryea" + } + }, + { + "id": 6365, + "name": "Sandra Pena", + "gender": "female", + "age": 19, + "address": { + "state": "Arizona", + "city": "Marysville" + } + }, + { + "id": 6366, + "name": "Hahn Lamb", + "gender": "male", + "age": 70, + "address": { + "state": "New Mexico", + "city": "Wacissa" + } + }, + { + "id": 6367, + "name": "Irma Berg", + "gender": "female", + "age": 78, + "address": { + "state": "Alaska", + "city": "Wilmington" + } + }, + { + "id": 6368, + "name": "Beard Preston", + "gender": "male", + "age": 27, + "address": { + "state": "Missouri", + "city": "Summerfield" + } + }, + { + "id": 6369, + "name": "Keri Harding", + "gender": "female", + "age": 40, + "address": { + "state": "Iowa", + "city": "Kennedyville" + } + }, + { + "id": 6370, + "name": "Leanna Mclaughlin", + "gender": "female", + "age": 24, + "address": { + "state": "New Jersey", + "city": "Urie" + } + }, + { + "id": 6371, + "name": "Sharp Jimenez", + "gender": "male", + "age": 77, + "address": { + "state": "Utah", + "city": "Manila" + } + }, + { + "id": 6372, + "name": "Juanita Henry", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Craig" + } + }, + { + "id": 6373, + "name": "Marie Simpson", + "gender": "female", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Abiquiu" + } + }, + { + "id": 6374, + "name": "Francesca Livingston", + "gender": "female", + "age": 28, + "address": { + "state": "Rhode Island", + "city": "Barrelville" + } + }, + { + "id": 6375, + "name": "Lori Salas", + "gender": "female", + "age": 46, + "address": { + "state": "Nevada", + "city": "Sharon" + } + }, + { + "id": 6376, + "name": "Rodriquez Lawson", + "gender": "male", + "age": 79, + "address": { + "state": "Virginia", + "city": "Helen" + } + }, + { + "id": 6377, + "name": "Jamie Jenkins", + "gender": "female", + "age": 44, + "address": { + "state": "Florida", + "city": "Clarksburg" + } + }, + { + "id": 6378, + "name": "Edwards Duffy", + "gender": "male", + "age": 59, + "address": { + "state": "Michigan", + "city": "Kohatk" + } + }, + { + "id": 6379, + "name": "Roberta Hodge", + "gender": "female", + "age": 26, + "address": { + "state": "Georgia", + "city": "Evergreen" + } + }, + { + "id": 6380, + "name": "Dominguez Mcgee", + "gender": "male", + "age": 65, + "address": { + "state": "New York", + "city": "Thornport" + } + }, + { + "id": 6381, + "name": "Alvarado Burton", + "gender": "male", + "age": 42, + "address": { + "state": "Arkansas", + "city": "Kenmar" + } + }, + { + "id": 6382, + "name": "Randi Mendoza", + "gender": "female", + "age": 51, + "address": { + "state": "Tennessee", + "city": "Hiwasse" + } + }, + { + "id": 6383, + "name": "Macias Scott", + "gender": "male", + "age": 19, + "address": { + "state": "Vermont", + "city": "Drytown" + } + }, + { + "id": 6384, + "name": "Iris King", + "gender": "female", + "age": 68, + "address": { + "state": "New Hampshire", + "city": "Ribera" + } + }, + { + "id": 6385, + "name": "Sharpe Nieves", + "gender": "male", + "age": 33, + "address": { + "state": "Iowa", + "city": "Durham" + } + }, + { + "id": 6386, + "name": "Hatfield Keith", + "gender": "male", + "age": 41, + "address": { + "state": "Washington", + "city": "Stevens" + } + }, + { + "id": 6387, + "name": "Maureen Kline", + "gender": "female", + "age": 26, + "address": { + "state": "Delaware", + "city": "Imperial" + } + }, + { + "id": 6388, + "name": "Esperanza Albert", + "gender": "female", + "age": 29, + "address": { + "state": "South Dakota", + "city": "Cumberland" + } + }, + { + "id": 6389, + "name": "Andrea Cooley", + "gender": "female", + "age": 57, + "address": { + "state": "Wisconsin", + "city": "Hall" + } + }, + { + "id": 6390, + "name": "Krista Valentine", + "gender": "female", + "age": 22, + "address": { + "state": "Ohio", + "city": "Hartsville/Hartley" + } + }, + { + "id": 6391, + "name": "Tillman Dunn", + "gender": "male", + "age": 55, + "address": { + "state": "Mississippi", + "city": "Grahamtown" + } + }, + { + "id": 6392, + "name": "Christine Johnston", + "gender": "female", + "age": 50, + "address": { + "state": "Texas", + "city": "Beechmont" + } + }, + { + "id": 6393, + "name": "Potts Conley", + "gender": "male", + "age": 64, + "address": { + "state": "California", + "city": "Laurelton" + } + }, + { + "id": 6394, + "name": "Maggie Stout", + "gender": "female", + "age": 36, + "address": { + "state": "South Carolina", + "city": "Disautel" + } + }, + { + "id": 6395, + "name": "Goodman Blackwell", + "gender": "male", + "age": 50, + "address": { + "state": "Indiana", + "city": "Lowgap" + } + }, + { + "id": 6396, + "name": "Stacy Contreras", + "gender": "female", + "age": 49, + "address": { + "state": "Oklahoma", + "city": "Slovan" + } + }, + { + "id": 6397, + "name": "Carmela Wiggins", + "gender": "female", + "age": 40, + "address": { + "state": "Hawaii", + "city": "Cade" + } + }, + { + "id": 6398, + "name": "Joseph Powell", + "gender": "male", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Allamuchy" + } + }, + { + "id": 6399, + "name": "Crawford Guerrero", + "gender": "male", + "age": 79, + "address": { + "state": "Missouri", + "city": "Bison" + } + }, + { + "id": 6400, + "name": "Moran Talley", + "gender": "male", + "age": 19, + "address": { + "state": "Alabama", + "city": "Esmont" + } + }, + { + "id": 6401, + "name": "Lowe Fields", + "gender": "male", + "age": 53, + "address": { + "state": "Kansas", + "city": "Bethany" + } + }, + { + "id": 6402, + "name": "Audra Ramirez", + "gender": "female", + "age": 63, + "address": { + "state": "Kentucky", + "city": "Grapeview" + } + }, + { + "id": 6403, + "name": "Ophelia Bartlett", + "gender": "female", + "age": 77, + "address": { + "state": "Maryland", + "city": "Tonopah" + } + }, + { + "id": 6404, + "name": "Haley Buckley", + "gender": "male", + "age": 65, + "address": { + "state": "Pennsylvania", + "city": "Templeton" + } + }, + { + "id": 6405, + "name": "Guy Hart", + "gender": "male", + "age": 34, + "address": { + "state": "Wyoming", + "city": "Eureka" + } + }, + { + "id": 6406, + "name": "Twila Howard", + "gender": "female", + "age": 38, + "address": { + "state": "North Dakota", + "city": "Idledale" + } + }, + { + "id": 6407, + "name": "Ellis Strickland", + "gender": "male", + "age": 72, + "address": { + "state": "Alaska", + "city": "Machias" + } + }, + { + "id": 6408, + "name": "Christi Page", + "gender": "female", + "age": 72, + "address": { + "state": "Massachusetts", + "city": "Courtland" + } + }, + { + "id": 6409, + "name": "Schwartz Cole", + "gender": "male", + "age": 79, + "address": { + "state": "Louisiana", + "city": "Comptche" + } + }, + { + "id": 6410, + "name": "Marks Walter", + "gender": "male", + "age": 53, + "address": { + "state": "Maine", + "city": "Rockingham" + } + }, + { + "id": 6411, + "name": "Oneil Sutton", + "gender": "male", + "age": 33, + "address": { + "state": "Arizona", + "city": "Steinhatchee" + } + }, + { + "id": 6412, + "name": "Cochran Robbins", + "gender": "male", + "age": 72, + "address": { + "state": "Idaho", + "city": "Malott" + } + }, + { + "id": 6413, + "name": "Alston Mercer", + "gender": "male", + "age": 28, + "address": { + "state": "Illinois", + "city": "Bancroft" + } + }, + { + "id": 6414, + "name": "Woods Coffey", + "gender": "male", + "age": 34, + "address": { + "state": "Connecticut", + "city": "Kieler" + } + }, + { + "id": 6415, + "name": "Gates Burgess", + "gender": "male", + "age": 75, + "address": { + "state": "West Virginia", + "city": "Delco" + } + }, + { + "id": 6416, + "name": "Mae Carson", + "gender": "female", + "age": 74, + "address": { + "state": "Montana", + "city": "Jacumba" + } + }, + { + "id": 6417, + "name": "Estella French", + "gender": "female", + "age": 17, + "address": { + "state": "New Mexico", + "city": "Yorklyn" + } + }, + { + "id": 6418, + "name": "Kim Marquez", + "gender": "female", + "age": 56, + "address": { + "state": "Colorado", + "city": "Gloucester" + } + }, + { + "id": 6419, + "name": "Angeline Allison", + "gender": "female", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Cliff" + } + }, + { + "id": 6420, + "name": "Rogers Bradley", + "gender": "male", + "age": 77, + "address": { + "state": "Wisconsin", + "city": "Taft" + } + }, + { + "id": 6421, + "name": "Jeri Calderon", + "gender": "female", + "age": 56, + "address": { + "state": "Iowa", + "city": "Enoree" + } + }, + { + "id": 6422, + "name": "Mcfarland Allison", + "gender": "male", + "age": 25, + "address": { + "state": "West Virginia", + "city": "Hilltop" + } + }, + { + "id": 6423, + "name": "Shelton Douglas", + "gender": "male", + "age": 26, + "address": { + "state": "Wyoming", + "city": "Cresaptown" + } + }, + { + "id": 6424, + "name": "Melba Poole", + "gender": "female", + "age": 32, + "address": { + "state": "Maryland", + "city": "Norfolk" + } + }, + { + "id": 6425, + "name": "Mcclure Cook", + "gender": "male", + "age": 28, + "address": { + "state": "South Carolina", + "city": "Hollins" + } + }, + { + "id": 6426, + "name": "Nanette Horne", + "gender": "female", + "age": 70, + "address": { + "state": "Idaho", + "city": "Itmann" + } + }, + { + "id": 6427, + "name": "Nettie Clements", + "gender": "female", + "age": 73, + "address": { + "state": "Hawaii", + "city": "Gardners" + } + }, + { + "id": 6428, + "name": "Dillard Foster", + "gender": "male", + "age": 38, + "address": { + "state": "Colorado", + "city": "Wright" + } + }, + { + "id": 6429, + "name": "Conway Grant", + "gender": "male", + "age": 63, + "address": { + "state": "California", + "city": "Lindisfarne" + } + }, + { + "id": 6430, + "name": "Kerri Cherry", + "gender": "female", + "age": 81, + "address": { + "state": "New Hampshire", + "city": "Fillmore" + } + }, + { + "id": 6431, + "name": "Cleo Hood", + "gender": "female", + "age": 80, + "address": { + "state": "Illinois", + "city": "Kerby" + } + }, + { + "id": 6432, + "name": "Flores Conway", + "gender": "male", + "age": 29, + "address": { + "state": "Virginia", + "city": "Nescatunga" + } + }, + { + "id": 6433, + "name": "Briggs Buchanan", + "gender": "male", + "age": 21, + "address": { + "state": "Montana", + "city": "Garfield" + } + }, + { + "id": 6434, + "name": "Manuela Rutledge", + "gender": "female", + "age": 32, + "address": { + "state": "North Carolina", + "city": "Wyoming" + } + }, + { + "id": 6435, + "name": "Curtis Bartlett", + "gender": "male", + "age": 55, + "address": { + "state": "North Dakota", + "city": "Beechmont" + } + }, + { + "id": 6436, + "name": "Mallory Richard", + "gender": "female", + "age": 82, + "address": { + "state": "New Mexico", + "city": "Mulberry" + } + }, + { + "id": 6437, + "name": "Malinda Church", + "gender": "female", + "age": 81, + "address": { + "state": "Ohio", + "city": "Oceola" + } + }, + { + "id": 6438, + "name": "David Mitchell", + "gender": "male", + "age": 40, + "address": { + "state": "Connecticut", + "city": "Gorst" + } + }, + { + "id": 6439, + "name": "Katherine Flowers", + "gender": "female", + "age": 69, + "address": { + "state": "Massachusetts", + "city": "Kirk" + } + }, + { + "id": 6440, + "name": "Becker Marsh", + "gender": "male", + "age": 52, + "address": { + "state": "South Dakota", + "city": "Saticoy" + } + }, + { + "id": 6441, + "name": "Dona Battle", + "gender": "female", + "age": 70, + "address": { + "state": "Washington", + "city": "Groton" + } + }, + { + "id": 6442, + "name": "Hardy Mills", + "gender": "male", + "age": 28, + "address": { + "state": "Missouri", + "city": "Tibbie" + } + }, + { + "id": 6443, + "name": "Katrina Nichols", + "gender": "female", + "age": 48, + "address": { + "state": "Nevada", + "city": "Westboro" + } + }, + { + "id": 6444, + "name": "Preston Herring", + "gender": "male", + "age": 19, + "address": { + "state": "Oklahoma", + "city": "Caln" + } + }, + { + "id": 6445, + "name": "Annabelle Gillespie", + "gender": "female", + "age": 66, + "address": { + "state": "Kentucky", + "city": "Brazos" + } + }, + { + "id": 6446, + "name": "Valarie Lewis", + "gender": "female", + "age": 42, + "address": { + "state": "Utah", + "city": "Delshire" + } + }, + { + "id": 6447, + "name": "Wilder Phillips", + "gender": "male", + "age": 64, + "address": { + "state": "Arkansas", + "city": "Hamilton" + } + }, + { + "id": 6448, + "name": "Althea Hopkins", + "gender": "female", + "age": 47, + "address": { + "state": "Maine", + "city": "Jackpot" + } + }, + { + "id": 6449, + "name": "Shaw Booker", + "gender": "male", + "age": 23, + "address": { + "state": "Minnesota", + "city": "Belmont" + } + }, + { + "id": 6450, + "name": "Waller Melton", + "gender": "male", + "age": 65, + "address": { + "state": "Indiana", + "city": "Tuskahoma" + } + }, + { + "id": 6451, + "name": "Trisha Carson", + "gender": "female", + "age": 53, + "address": { + "state": "Nebraska", + "city": "Nogal" + } + }, + { + "id": 6452, + "name": "Skinner Franco", + "gender": "male", + "age": 26, + "address": { + "state": "Michigan", + "city": "Why" + } + }, + { + "id": 6453, + "name": "Leila Mcneil", + "gender": "female", + "age": 32, + "address": { + "state": "Florida", + "city": "Cherokee" + } + }, + { + "id": 6454, + "name": "Carolyn Clark", + "gender": "female", + "age": 29, + "address": { + "state": "New York", + "city": "Concho" + } + }, + { + "id": 6455, + "name": "Parker Mcguire", + "gender": "male", + "age": 43, + "address": { + "state": "Alabama", + "city": "Walton" + } + }, + { + "id": 6456, + "name": "Jacquelyn Garner", + "gender": "female", + "age": 40, + "address": { + "state": "Delaware", + "city": "Stonybrook" + } + }, + { + "id": 6457, + "name": "Aileen Webb", + "gender": "female", + "age": 64, + "address": { + "state": "Arizona", + "city": "Tyhee" + } + }, + { + "id": 6458, + "name": "Spence Odonnell", + "gender": "male", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Rockingham" + } + }, + { + "id": 6459, + "name": "Claudette Avila", + "gender": "female", + "age": 26, + "address": { + "state": "Oregon", + "city": "Sandston" + } + }, + { + "id": 6460, + "name": "Alston Bird", + "gender": "male", + "age": 73, + "address": { + "state": "Tennessee", + "city": "Wells" + } + }, + { + "id": 6461, + "name": "Sophia Fuentes", + "gender": "female", + "age": 82, + "address": { + "state": "Rhode Island", + "city": "Chesapeake" + } + }, + { + "id": 6462, + "name": "Riley Richards", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Suitland" + } + }, + { + "id": 6463, + "name": "Lamb Taylor", + "gender": "male", + "age": 32, + "address": { + "state": "Alaska", + "city": "Cleary" + } + }, + { + "id": 6464, + "name": "Whitney Hooper", + "gender": "female", + "age": 68, + "address": { + "state": "Texas", + "city": "Konterra" + } + }, + { + "id": 6465, + "name": "Blanche Moody", + "gender": "female", + "age": 49, + "address": { + "state": "Georgia", + "city": "Allison" + } + }, + { + "id": 6466, + "name": "Little Bauer", + "gender": "male", + "age": 53, + "address": { + "state": "Kansas", + "city": "Shaft" + } + }, + { + "id": 6467, + "name": "Beasley Bass", + "gender": "male", + "age": 26, + "address": { + "state": "Vermont", + "city": "Carlton" + } + }, + { + "id": 6468, + "name": "Dejesus Roach", + "gender": "male", + "age": 39, + "address": { + "state": "Illinois", + "city": "Centerville" + } + }, + { + "id": 6469, + "name": "Ernestine Rasmussen", + "gender": "female", + "age": 30, + "address": { + "state": "Vermont", + "city": "Lumberton" + } + }, + { + "id": 6470, + "name": "Salazar Justice", + "gender": "male", + "age": 47, + "address": { + "state": "Iowa", + "city": "Ruckersville" + } + }, + { + "id": 6471, + "name": "Jessie Short", + "gender": "female", + "age": 56, + "address": { + "state": "Kansas", + "city": "Guthrie" + } + }, + { + "id": 6472, + "name": "Massey Lambert", + "gender": "male", + "age": 59, + "address": { + "state": "Louisiana", + "city": "Gadsden" + } + }, + { + "id": 6473, + "name": "Kelsey Valdez", + "gender": "female", + "age": 64, + "address": { + "state": "North Carolina", + "city": "Skyland" + } + }, + { + "id": 6474, + "name": "Lindsay Burns", + "gender": "female", + "age": 70, + "address": { + "state": "New Jersey", + "city": "Smock" + } + }, + { + "id": 6475, + "name": "Haley Foreman", + "gender": "female", + "age": 74, + "address": { + "state": "Connecticut", + "city": "Soudan" + } + }, + { + "id": 6476, + "name": "Aida Fischer", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Navarre" + } + }, + { + "id": 6477, + "name": "Ratliff Oliver", + "gender": "male", + "age": 65, + "address": { + "state": "West Virginia", + "city": "Macdona" + } + }, + { + "id": 6478, + "name": "Florence Rutledge", + "gender": "female", + "age": 55, + "address": { + "state": "Wisconsin", + "city": "Chloride" + } + }, + { + "id": 6479, + "name": "Neva Trujillo", + "gender": "female", + "age": 49, + "address": { + "state": "Idaho", + "city": "Strong" + } + }, + { + "id": 6480, + "name": "Gilmore Sosa", + "gender": "male", + "age": 61, + "address": { + "state": "Minnesota", + "city": "Holcombe" + } + }, + { + "id": 6481, + "name": "Austin Duffy", + "gender": "male", + "age": 59, + "address": { + "state": "Colorado", + "city": "Orovada" + } + }, + { + "id": 6482, + "name": "Kelley Booker", + "gender": "female", + "age": 17, + "address": { + "state": "Kentucky", + "city": "Edneyville" + } + }, + { + "id": 6483, + "name": "Heath Reilly", + "gender": "male", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Walland" + } + }, + { + "id": 6484, + "name": "Beard Perez", + "gender": "male", + "age": 54, + "address": { + "state": "Indiana", + "city": "Vicksburg" + } + }, + { + "id": 6485, + "name": "Carpenter Jacobson", + "gender": "male", + "age": 76, + "address": { + "state": "Maryland", + "city": "Tuskahoma" + } + }, + { + "id": 6486, + "name": "Shirley Rodriguez", + "gender": "female", + "age": 64, + "address": { + "state": "Tennessee", + "city": "Snyderville" + } + }, + { + "id": 6487, + "name": "Gaines Monroe", + "gender": "male", + "age": 58, + "address": { + "state": "Delaware", + "city": "Suitland" + } + }, + { + "id": 6488, + "name": "Kemp Morris", + "gender": "male", + "age": 53, + "address": { + "state": "Utah", + "city": "Grimsley" + } + }, + { + "id": 6489, + "name": "Dudley Baxter", + "gender": "male", + "age": 32, + "address": { + "state": "California", + "city": "Vincent" + } + }, + { + "id": 6490, + "name": "Hendricks House", + "gender": "male", + "age": 79, + "address": { + "state": "New Hampshire", + "city": "Lutsen" + } + }, + { + "id": 6491, + "name": "Cote Henderson", + "gender": "male", + "age": 64, + "address": { + "state": "Oregon", + "city": "Hachita" + } + }, + { + "id": 6492, + "name": "Ellison Crosby", + "gender": "male", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Rehrersburg" + } + }, + { + "id": 6493, + "name": "Morton Lancaster", + "gender": "male", + "age": 63, + "address": { + "state": "Missouri", + "city": "Turah" + } + }, + { + "id": 6494, + "name": "Hernandez Hudson", + "gender": "male", + "age": 49, + "address": { + "state": "Michigan", + "city": "Thornport" + } + }, + { + "id": 6495, + "name": "Manuela Kelly", + "gender": "female", + "age": 58, + "address": { + "state": "Virginia", + "city": "Robinson" + } + }, + { + "id": 6496, + "name": "Georgia Soto", + "gender": "female", + "age": 37, + "address": { + "state": "Florida", + "city": "Galesville" + } + }, + { + "id": 6497, + "name": "Malinda Flores", + "gender": "female", + "age": 27, + "address": { + "state": "Rhode Island", + "city": "Beason" + } + }, + { + "id": 6498, + "name": "Lisa Craft", + "gender": "female", + "age": 31, + "address": { + "state": "Texas", + "city": "Mulino" + } + }, + { + "id": 6499, + "name": "Ferguson Gilliam", + "gender": "male", + "age": 31, + "address": { + "state": "Mississippi", + "city": "Allamuchy" + } + }, + { + "id": 6500, + "name": "House Dixon", + "gender": "male", + "age": 27, + "address": { + "state": "Arkansas", + "city": "Charco" + } + }, + { + "id": 6501, + "name": "Franklin Barron", + "gender": "male", + "age": 21, + "address": { + "state": "Montana", + "city": "Caspar" + } + }, + { + "id": 6502, + "name": "Wilson Harrington", + "gender": "male", + "age": 79, + "address": { + "state": "South Dakota", + "city": "Groton" + } + }, + { + "id": 6503, + "name": "Esmeralda Moses", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Movico" + } + }, + { + "id": 6504, + "name": "Deena Carroll", + "gender": "female", + "age": 58, + "address": { + "state": "Georgia", + "city": "Sperryville" + } + }, + { + "id": 6505, + "name": "Dorothea Gonzales", + "gender": "female", + "age": 44, + "address": { + "state": "Alaska", + "city": "Boykin" + } + }, + { + "id": 6506, + "name": "Eaton Pruitt", + "gender": "male", + "age": 49, + "address": { + "state": "Nevada", + "city": "Leland" + } + }, + { + "id": 6507, + "name": "Tammi Rivera", + "gender": "female", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Dennard" + } + }, + { + "id": 6508, + "name": "Darcy Rojas", + "gender": "female", + "age": 74, + "address": { + "state": "Oklahoma", + "city": "Sultana" + } + }, + { + "id": 6509, + "name": "Bauer Copeland", + "gender": "male", + "age": 21, + "address": { + "state": "Maine", + "city": "Chesterfield" + } + }, + { + "id": 6510, + "name": "Mcmillan Taylor", + "gender": "male", + "age": 49, + "address": { + "state": "Alabama", + "city": "Rockingham" + } + }, + { + "id": 6511, + "name": "Abigail Langley", + "gender": "female", + "age": 26, + "address": { + "state": "Ohio", + "city": "Siglerville" + } + }, + { + "id": 6512, + "name": "Oconnor Mejia", + "gender": "male", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Elrama" + } + }, + { + "id": 6513, + "name": "Claire Estes", + "gender": "female", + "age": 33, + "address": { + "state": "South Carolina", + "city": "Waiohinu" + } + }, + { + "id": 6514, + "name": "Steele Ashley", + "gender": "male", + "age": 73, + "address": { + "state": "Arizona", + "city": "Yonah" + } + }, + { + "id": 6515, + "name": "Carson England", + "gender": "male", + "age": 17, + "address": { + "state": "New York", + "city": "Lupton" + } + }, + { + "id": 6516, + "name": "Inez Munoz", + "gender": "female", + "age": 64, + "address": { + "state": "Washington", + "city": "Eastmont" + } + }, + { + "id": 6517, + "name": "Ola Robbins", + "gender": "female", + "age": 80, + "address": { + "state": "New Jersey", + "city": "Fresno" + } + }, + { + "id": 6518, + "name": "Delores Gross", + "gender": "female", + "age": 69, + "address": { + "state": "California", + "city": "Devon" + } + }, + { + "id": 6519, + "name": "Julianne Henson", + "gender": "female", + "age": 26, + "address": { + "state": "New Hampshire", + "city": "Sparkill" + } + }, + { + "id": 6520, + "name": "Frederick Levine", + "gender": "male", + "age": 24, + "address": { + "state": "Oregon", + "city": "Freeburn" + } + }, + { + "id": 6521, + "name": "Teresa Whitfield", + "gender": "female", + "age": 72, + "address": { + "state": "New Mexico", + "city": "Holtville" + } + }, + { + "id": 6522, + "name": "Tamara Waller", + "gender": "female", + "age": 51, + "address": { + "state": "Louisiana", + "city": "Cartwright" + } + }, + { + "id": 6523, + "name": "Obrien Baldwin", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Bath" + } + }, + { + "id": 6524, + "name": "Leola Maynard", + "gender": "female", + "age": 50, + "address": { + "state": "Maine", + "city": "Singer" + } + }, + { + "id": 6525, + "name": "Holland Spears", + "gender": "male", + "age": 54, + "address": { + "state": "Kansas", + "city": "Hiseville" + } + }, + { + "id": 6526, + "name": "Browning Cline", + "gender": "male", + "age": 48, + "address": { + "state": "Connecticut", + "city": "Marshall" + } + }, + { + "id": 6527, + "name": "Margery Stephens", + "gender": "female", + "age": 70, + "address": { + "state": "Virginia", + "city": "Clarktown" + } + }, + { + "id": 6528, + "name": "Charmaine Donovan", + "gender": "female", + "age": 57, + "address": { + "state": "Utah", + "city": "Warsaw" + } + }, + { + "id": 6529, + "name": "Clarice Stephenson", + "gender": "female", + "age": 54, + "address": { + "state": "North Carolina", + "city": "Herald" + } + }, + { + "id": 6530, + "name": "Amanda Sutton", + "gender": "female", + "age": 61, + "address": { + "state": "Missouri", + "city": "Hannasville" + } + }, + { + "id": 6531, + "name": "Heather Stone", + "gender": "female", + "age": 65, + "address": { + "state": "Illinois", + "city": "Bellfountain" + } + }, + { + "id": 6532, + "name": "Sharp Hughes", + "gender": "male", + "age": 40, + "address": { + "state": "Alaska", + "city": "Moraida" + } + }, + { + "id": 6533, + "name": "Dixon Burns", + "gender": "male", + "age": 19, + "address": { + "state": "North Dakota", + "city": "Foxworth" + } + }, + { + "id": 6534, + "name": "Meadows Daniels", + "gender": "male", + "age": 48, + "address": { + "state": "Washington", + "city": "Torboy" + } + }, + { + "id": 6535, + "name": "Sharpe Price", + "gender": "male", + "age": 58, + "address": { + "state": "Michigan", + "city": "Terlingua" + } + }, + { + "id": 6536, + "name": "Becky Pena", + "gender": "female", + "age": 39, + "address": { + "state": "Minnesota", + "city": "Saticoy" + } + }, + { + "id": 6537, + "name": "Orr Newton", + "gender": "male", + "age": 47, + "address": { + "state": "Alabama", + "city": "Shawmut" + } + }, + { + "id": 6538, + "name": "Erma Smith", + "gender": "female", + "age": 28, + "address": { + "state": "Texas", + "city": "Cochranville" + } + }, + { + "id": 6539, + "name": "Rodgers Travis", + "gender": "male", + "age": 44, + "address": { + "state": "Arizona", + "city": "Durham" + } + }, + { + "id": 6540, + "name": "Mari Eaton", + "gender": "female", + "age": 51, + "address": { + "state": "Iowa", + "city": "Greenwich" + } + }, + { + "id": 6541, + "name": "Ingram Glass", + "gender": "male", + "age": 80, + "address": { + "state": "Oklahoma", + "city": "Utting" + } + }, + { + "id": 6542, + "name": "Margaret Peck", + "gender": "female", + "age": 29, + "address": { + "state": "South Dakota", + "city": "Hayden" + } + }, + { + "id": 6543, + "name": "Michael Riddle", + "gender": "male", + "age": 46, + "address": { + "state": "Nevada", + "city": "Choctaw" + } + }, + { + "id": 6544, + "name": "Randolph Aguilar", + "gender": "male", + "age": 49, + "address": { + "state": "Wisconsin", + "city": "Mapletown" + } + }, + { + "id": 6545, + "name": "Nell Turner", + "gender": "female", + "age": 64, + "address": { + "state": "Tennessee", + "city": "Shaft" + } + }, + { + "id": 6546, + "name": "Vincent Fowler", + "gender": "male", + "age": 44, + "address": { + "state": "Idaho", + "city": "Onton" + } + }, + { + "id": 6547, + "name": "Lane Cooke", + "gender": "male", + "age": 27, + "address": { + "state": "Indiana", + "city": "Dola" + } + }, + { + "id": 6548, + "name": "Amparo Hodges", + "gender": "female", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Byrnedale" + } + }, + { + "id": 6549, + "name": "Inez Kerr", + "gender": "female", + "age": 39, + "address": { + "state": "Maryland", + "city": "Northchase" + } + }, + { + "id": 6550, + "name": "Mcmahon Castillo", + "gender": "male", + "age": 23, + "address": { + "state": "West Virginia", + "city": "Olney" + } + }, + { + "id": 6551, + "name": "Brittany Branch", + "gender": "female", + "age": 62, + "address": { + "state": "Wyoming", + "city": "Sheatown" + } + }, + { + "id": 6552, + "name": "Mollie Barnett", + "gender": "female", + "age": 54, + "address": { + "state": "Montana", + "city": "Corinne" + } + }, + { + "id": 6553, + "name": "White Carrillo", + "gender": "male", + "age": 46, + "address": { + "state": "Colorado", + "city": "Forbestown" + } + }, + { + "id": 6554, + "name": "Yang Moore", + "gender": "male", + "age": 50, + "address": { + "state": "Pennsylvania", + "city": "Hollymead" + } + }, + { + "id": 6555, + "name": "Katharine Calhoun", + "gender": "female", + "age": 82, + "address": { + "state": "Nebraska", + "city": "Jeff" + } + }, + { + "id": 6556, + "name": "Olive Oliver", + "gender": "female", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Jennings" + } + }, + { + "id": 6557, + "name": "Mendoza Swanson", + "gender": "male", + "age": 38, + "address": { + "state": "New York", + "city": "Orin" + } + }, + { + "id": 6558, + "name": "Jewell Baker", + "gender": "female", + "age": 79, + "address": { + "state": "Hawaii", + "city": "Fidelis" + } + }, + { + "id": 6559, + "name": "Clemons Knox", + "gender": "male", + "age": 43, + "address": { + "state": "Georgia", + "city": "Idamay" + } + }, + { + "id": 6560, + "name": "Kris Kemp", + "gender": "female", + "age": 17, + "address": { + "state": "Kentucky", + "city": "Shrewsbury" + } + }, + { + "id": 6561, + "name": "Alexander Dillon", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Coldiron" + } + }, + { + "id": 6562, + "name": "Kramer Galloway", + "gender": "male", + "age": 70, + "address": { + "state": "South Carolina", + "city": "Statenville" + } + }, + { + "id": 6563, + "name": "Long Garrett", + "gender": "male", + "age": 26, + "address": { + "state": "Arkansas", + "city": "Lindisfarne" + } + }, + { + "id": 6564, + "name": "Marissa Sloan", + "gender": "female", + "age": 63, + "address": { + "state": "Mississippi", + "city": "Blanco" + } + }, + { + "id": 6565, + "name": "Miller Horn", + "gender": "male", + "age": 37, + "address": { + "state": "Vermont", + "city": "Townsend" + } + }, + { + "id": 6566, + "name": "Erika Logan", + "gender": "female", + "age": 67, + "address": { + "state": "South Carolina", + "city": "Wescosville" + } + }, + { + "id": 6567, + "name": "Beulah Hendrix", + "gender": "female", + "age": 80, + "address": { + "state": "New Mexico", + "city": "Wright" + } + }, + { + "id": 6568, + "name": "Nielsen Hahn", + "gender": "male", + "age": 81, + "address": { + "state": "Wyoming", + "city": "Elliston" + } + }, + { + "id": 6569, + "name": "Aguirre Young", + "gender": "male", + "age": 46, + "address": { + "state": "North Carolina", + "city": "Elfrida" + } + }, + { + "id": 6570, + "name": "Hattie Tillman", + "gender": "female", + "age": 44, + "address": { + "state": "New Jersey", + "city": "Greensburg" + } + }, + { + "id": 6571, + "name": "David Frye", + "gender": "male", + "age": 82, + "address": { + "state": "Missouri", + "city": "Blanco" + } + }, + { + "id": 6572, + "name": "Maldonado Alexander", + "gender": "male", + "age": 67, + "address": { + "state": "Washington", + "city": "Baden" + } + }, + { + "id": 6573, + "name": "John Wilson", + "gender": "female", + "age": 55, + "address": { + "state": "Rhode Island", + "city": "Summertown" + } + }, + { + "id": 6574, + "name": "Merritt Villarreal", + "gender": "male", + "age": 37, + "address": { + "state": "Alaska", + "city": "Efland" + } + }, + { + "id": 6575, + "name": "Pate Sawyer", + "gender": "male", + "age": 57, + "address": { + "state": "Illinois", + "city": "Martell" + } + }, + { + "id": 6576, + "name": "Brittney Burch", + "gender": "female", + "age": 60, + "address": { + "state": "Indiana", + "city": "Dowling" + } + }, + { + "id": 6577, + "name": "Johanna Fry", + "gender": "female", + "age": 39, + "address": { + "state": "Texas", + "city": "Brecon" + } + }, + { + "id": 6578, + "name": "Rodgers Patel", + "gender": "male", + "age": 80, + "address": { + "state": "Nebraska", + "city": "Idledale" + } + }, + { + "id": 6579, + "name": "Margarita Ayala", + "gender": "female", + "age": 67, + "address": { + "state": "Virginia", + "city": "Clara" + } + }, + { + "id": 6580, + "name": "Briana Wagner", + "gender": "female", + "age": 62, + "address": { + "state": "Montana", + "city": "Westwood" + } + }, + { + "id": 6581, + "name": "Church Velez", + "gender": "male", + "age": 20, + "address": { + "state": "Mississippi", + "city": "Levant" + } + }, + { + "id": 6582, + "name": "Lorena Peters", + "gender": "female", + "age": 26, + "address": { + "state": "California", + "city": "Carbonville" + } + }, + { + "id": 6583, + "name": "Mcknight Hood", + "gender": "male", + "age": 47, + "address": { + "state": "Idaho", + "city": "Lemoyne" + } + }, + { + "id": 6584, + "name": "Hewitt Tran", + "gender": "male", + "age": 60, + "address": { + "state": "Michigan", + "city": "Wacissa" + } + }, + { + "id": 6585, + "name": "Stanton Wall", + "gender": "male", + "age": 56, + "address": { + "state": "Florida", + "city": "Carlton" + } + }, + { + "id": 6586, + "name": "Iva Boyer", + "gender": "female", + "age": 27, + "address": { + "state": "Utah", + "city": "Canoochee" + } + }, + { + "id": 6587, + "name": "Cara Dixon", + "gender": "female", + "age": 66, + "address": { + "state": "West Virginia", + "city": "Edneyville" + } + }, + { + "id": 6588, + "name": "Kelley Strong", + "gender": "female", + "age": 30, + "address": { + "state": "Minnesota", + "city": "Kimmell" + } + }, + { + "id": 6589, + "name": "Krystal Reese", + "gender": "female", + "age": 59, + "address": { + "state": "South Dakota", + "city": "Bowie" + } + }, + { + "id": 6590, + "name": "Webster Stone", + "gender": "male", + "age": 63, + "address": { + "state": "Tennessee", + "city": "Wyano" + } + }, + { + "id": 6591, + "name": "Letha Espinoza", + "gender": "female", + "age": 36, + "address": { + "state": "Nevada", + "city": "Beyerville" + } + }, + { + "id": 6592, + "name": "Gail Joseph", + "gender": "female", + "age": 79, + "address": { + "state": "Maryland", + "city": "Juarez" + } + }, + { + "id": 6593, + "name": "Mable Wells", + "gender": "female", + "age": 42, + "address": { + "state": "Ohio", + "city": "Benson" + } + }, + { + "id": 6594, + "name": "Lawrence Bird", + "gender": "male", + "age": 66, + "address": { + "state": "Arkansas", + "city": "Homestead" + } + }, + { + "id": 6595, + "name": "Bonnie Gould", + "gender": "female", + "age": 36, + "address": { + "state": "Arizona", + "city": "Frank" + } + }, + { + "id": 6596, + "name": "Albert Bentley", + "gender": "male", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Broadlands" + } + }, + { + "id": 6597, + "name": "Owen Chambers", + "gender": "male", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Floris" + } + }, + { + "id": 6598, + "name": "Massey Parks", + "gender": "male", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Boykin" + } + }, + { + "id": 6599, + "name": "Robles Everett", + "gender": "male", + "age": 61, + "address": { + "state": "Massachusetts", + "city": "Dunnavant" + } + }, + { + "id": 6600, + "name": "Colon Rojas", + "gender": "male", + "age": 72, + "address": { + "state": "Iowa", + "city": "Volta" + } + }, + { + "id": 6601, + "name": "Atkins Duffy", + "gender": "male", + "age": 49, + "address": { + "state": "Oregon", + "city": "Chaparrito" + } + }, + { + "id": 6602, + "name": "Ilene Farrell", + "gender": "female", + "age": 50, + "address": { + "state": "Georgia", + "city": "Waverly" + } + }, + { + "id": 6603, + "name": "Cameron Newman", + "gender": "male", + "age": 41, + "address": { + "state": "Vermont", + "city": "Grapeview" + } + }, + { + "id": 6604, + "name": "Petersen Bender", + "gender": "male", + "age": 41, + "address": { + "state": "Alabama", + "city": "Emison" + } + }, + { + "id": 6605, + "name": "Julie Whitaker", + "gender": "female", + "age": 62, + "address": { + "state": "Kansas", + "city": "Hasty" + } + }, + { + "id": 6606, + "name": "Bernadine Ross", + "gender": "female", + "age": 40, + "address": { + "state": "Delaware", + "city": "Waumandee" + } + }, + { + "id": 6607, + "name": "Heidi Welch", + "gender": "female", + "age": 44, + "address": { + "state": "New York", + "city": "Wattsville" + } + }, + { + "id": 6608, + "name": "Jordan Bray", + "gender": "female", + "age": 35, + "address": { + "state": "North Dakota", + "city": "Tecolotito" + } + }, + { + "id": 6609, + "name": "Weaver Schwartz", + "gender": "male", + "age": 21, + "address": { + "state": "Connecticut", + "city": "Warren" + } + }, + { + "id": 6610, + "name": "Elise Pugh", + "gender": "female", + "age": 82, + "address": { + "state": "Colorado", + "city": "Kingstowne" + } + }, + { + "id": 6611, + "name": "Marquita Stevenson", + "gender": "female", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Itmann" + } + }, + { + "id": 6612, + "name": "Rene Daniels", + "gender": "female", + "age": 56, + "address": { + "state": "Oklahoma", + "city": "Chesterfield" + } + }, + { + "id": 6613, + "name": "Edwards Ferrell", + "gender": "male", + "age": 63, + "address": { + "state": "Hawaii", + "city": "Worton" + } + }, + { + "id": 6614, + "name": "Brooks Roach", + "gender": "male", + "age": 77, + "address": { + "state": "Louisiana", + "city": "Wanship" + } + }, + { + "id": 6615, + "name": "Alvarez Langley", + "gender": "male", + "age": 48, + "address": { + "state": "South Carolina", + "city": "Connerton" + } + }, + { + "id": 6616, + "name": "Maude Carpenter", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Villarreal" + } + }, + { + "id": 6617, + "name": "Andrea Chambers", + "gender": "female", + "age": 37, + "address": { + "state": "Delaware", + "city": "Riverton" + } + }, + { + "id": 6618, + "name": "Smith Booth", + "gender": "male", + "age": 44, + "address": { + "state": "Wyoming", + "city": "Columbus" + } + }, + { + "id": 6619, + "name": "Vivian Watkins", + "gender": "female", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Brooktrails" + } + }, + { + "id": 6620, + "name": "Sweeney Brock", + "gender": "male", + "age": 53, + "address": { + "state": "Virginia", + "city": "Germanton" + } + }, + { + "id": 6621, + "name": "Suzanne Massey", + "gender": "female", + "age": 65, + "address": { + "state": "New Jersey", + "city": "Barstow" + } + }, + { + "id": 6622, + "name": "Pamela Foster", + "gender": "female", + "age": 57, + "address": { + "state": "Alaska", + "city": "Wawona" + } + }, + { + "id": 6623, + "name": "Katrina Sutton", + "gender": "female", + "age": 55, + "address": { + "state": "Minnesota", + "city": "Freeburn" + } + }, + { + "id": 6624, + "name": "Summer Patton", + "gender": "female", + "age": 46, + "address": { + "state": "Idaho", + "city": "Lafferty" + } + }, + { + "id": 6625, + "name": "Terri Gray", + "gender": "female", + "age": 49, + "address": { + "state": "Kansas", + "city": "Axis" + } + }, + { + "id": 6626, + "name": "Kathrine Anthony", + "gender": "female", + "age": 19, + "address": { + "state": "Colorado", + "city": "Kenwood" + } + }, + { + "id": 6627, + "name": "Witt Steele", + "gender": "male", + "age": 54, + "address": { + "state": "Illinois", + "city": "Newcastle" + } + }, + { + "id": 6628, + "name": "Ola Roberson", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Deercroft" + } + }, + { + "id": 6629, + "name": "Agnes Turner", + "gender": "female", + "age": 57, + "address": { + "state": "North Carolina", + "city": "Bluetown" + } + }, + { + "id": 6630, + "name": "Irma Chaney", + "gender": "female", + "age": 56, + "address": { + "state": "Indiana", + "city": "Alderpoint" + } + }, + { + "id": 6631, + "name": "Patricia Ray", + "gender": "female", + "age": 73, + "address": { + "state": "New York", + "city": "Imperial" + } + }, + { + "id": 6632, + "name": "Carlene Spears", + "gender": "female", + "age": 26, + "address": { + "state": "Maryland", + "city": "Hoagland" + } + }, + { + "id": 6633, + "name": "Bonita Wright", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Warsaw" + } + }, + { + "id": 6634, + "name": "Toni Reed", + "gender": "female", + "age": 38, + "address": { + "state": "Iowa", + "city": "Frizzleburg" + } + }, + { + "id": 6635, + "name": "Joyce Santiago", + "gender": "female", + "age": 42, + "address": { + "state": "Ohio", + "city": "Watchtower" + } + }, + { + "id": 6636, + "name": "Minnie Olsen", + "gender": "female", + "age": 25, + "address": { + "state": "Louisiana", + "city": "Odessa" + } + }, + { + "id": 6637, + "name": "William Baldwin", + "gender": "male", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Foxworth" + } + }, + { + "id": 6638, + "name": "Florine Pearson", + "gender": "female", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Cloverdale" + } + }, + { + "id": 6639, + "name": "Cardenas Reyes", + "gender": "male", + "age": 55, + "address": { + "state": "Mississippi", + "city": "Baden" + } + }, + { + "id": 6640, + "name": "Benson Mcneil", + "gender": "male", + "age": 38, + "address": { + "state": "Hawaii", + "city": "Roberts" + } + }, + { + "id": 6641, + "name": "Ramona Fowler", + "gender": "female", + "age": 39, + "address": { + "state": "Vermont", + "city": "Salvo" + } + }, + { + "id": 6642, + "name": "Blake Rowe", + "gender": "male", + "age": 24, + "address": { + "state": "Texas", + "city": "Englevale" + } + }, + { + "id": 6643, + "name": "Gamble Moore", + "gender": "male", + "age": 53, + "address": { + "state": "Pennsylvania", + "city": "Westmoreland" + } + }, + { + "id": 6644, + "name": "Ericka Burris", + "gender": "female", + "age": 27, + "address": { + "state": "South Dakota", + "city": "Edgewater" + } + }, + { + "id": 6645, + "name": "Megan Pope", + "gender": "female", + "age": 80, + "address": { + "state": "Oregon", + "city": "Newkirk" + } + }, + { + "id": 6646, + "name": "Garrison Kline", + "gender": "male", + "age": 72, + "address": { + "state": "Kentucky", + "city": "Whitestone" + } + }, + { + "id": 6647, + "name": "Wilkinson Erickson", + "gender": "male", + "age": 40, + "address": { + "state": "Maine", + "city": "Woodruff" + } + }, + { + "id": 6648, + "name": "Munoz Petersen", + "gender": "male", + "age": 82, + "address": { + "state": "Tennessee", + "city": "Wanamie" + } + }, + { + "id": 6649, + "name": "Angelia Middleton", + "gender": "female", + "age": 81, + "address": { + "state": "Washington", + "city": "Hanover" + } + }, + { + "id": 6650, + "name": "Griffin Avery", + "gender": "male", + "age": 80, + "address": { + "state": "Utah", + "city": "Wyano" + } + }, + { + "id": 6651, + "name": "Meghan Winters", + "gender": "female", + "age": 40, + "address": { + "state": "Florida", + "city": "Albrightsville" + } + }, + { + "id": 6652, + "name": "Trudy Meyer", + "gender": "female", + "age": 50, + "address": { + "state": "Wisconsin", + "city": "Freelandville" + } + }, + { + "id": 6653, + "name": "Peterson Patrick", + "gender": "male", + "age": 48, + "address": { + "state": "Nebraska", + "city": "Herlong" + } + }, + { + "id": 6654, + "name": "Alma Mcconnell", + "gender": "female", + "age": 49, + "address": { + "state": "New Mexico", + "city": "Yogaville" + } + }, + { + "id": 6655, + "name": "Christina Rosa", + "gender": "female", + "age": 73, + "address": { + "state": "Arkansas", + "city": "Shawmut" + } + }, + { + "id": 6656, + "name": "Malinda Gordon", + "gender": "female", + "age": 53, + "address": { + "state": "West Virginia", + "city": "Terlingua" + } + }, + { + "id": 6657, + "name": "Tamra Roth", + "gender": "female", + "age": 57, + "address": { + "state": "Montana", + "city": "Summerset" + } + }, + { + "id": 6658, + "name": "Kathy Dickson", + "gender": "female", + "age": 23, + "address": { + "state": "Missouri", + "city": "Bowie" + } + }, + { + "id": 6659, + "name": "Perry Powers", + "gender": "male", + "age": 17, + "address": { + "state": "Alabama", + "city": "Sunwest" + } + }, + { + "id": 6660, + "name": "Hudson Blankenship", + "gender": "male", + "age": 69, + "address": { + "state": "Connecticut", + "city": "Fairacres" + } + }, + { + "id": 6661, + "name": "Leigh Hewitt", + "gender": "female", + "age": 30, + "address": { + "state": "Rhode Island", + "city": "Lydia" + } + }, + { + "id": 6662, + "name": "Evangeline Morin", + "gender": "female", + "age": 48, + "address": { + "state": "Georgia", + "city": "Swartzville" + } + }, + { + "id": 6663, + "name": "Orr Snow", + "gender": "male", + "age": 21, + "address": { + "state": "Michigan", + "city": "Croom" + } + }, + { + "id": 6664, + "name": "Heather Stein", + "gender": "female", + "age": 24, + "address": { + "state": "Colorado", + "city": "Zeba" + } + }, + { + "id": 6665, + "name": "Gabriela Hicks", + "gender": "female", + "age": 78, + "address": { + "state": "Massachusetts", + "city": "Marshall" + } + }, + { + "id": 6666, + "name": "Constance Santana", + "gender": "female", + "age": 47, + "address": { + "state": "California", + "city": "Smeltertown" + } + }, + { + "id": 6667, + "name": "Huffman Holmes", + "gender": "male", + "age": 71, + "address": { + "state": "Maryland", + "city": "Durham" + } + }, + { + "id": 6668, + "name": "Allie Blair", + "gender": "female", + "age": 46, + "address": { + "state": "Delaware", + "city": "Chalfant" + } + }, + { + "id": 6669, + "name": "Becky Mack", + "gender": "female", + "age": 40, + "address": { + "state": "Mississippi", + "city": "Shawmut" + } + }, + { + "id": 6670, + "name": "Parks Mcfadden", + "gender": "male", + "age": 36, + "address": { + "state": "Connecticut", + "city": "Needmore" + } + }, + { + "id": 6671, + "name": "Lawrence Padilla", + "gender": "male", + "age": 68, + "address": { + "state": "Florida", + "city": "Sandston" + } + }, + { + "id": 6672, + "name": "Nina Gill", + "gender": "female", + "age": 52, + "address": { + "state": "Alaska", + "city": "Kanauga" + } + }, + { + "id": 6673, + "name": "Helene Kirby", + "gender": "female", + "age": 63, + "address": { + "state": "Minnesota", + "city": "Russellville" + } + }, + { + "id": 6674, + "name": "Lang Austin", + "gender": "male", + "age": 28, + "address": { + "state": "Kentucky", + "city": "Coleville" + } + }, + { + "id": 6675, + "name": "Victoria Valdez", + "gender": "female", + "age": 81, + "address": { + "state": "Oregon", + "city": "Wakarusa" + } + }, + { + "id": 6676, + "name": "Duke Mccarthy", + "gender": "male", + "age": 18, + "address": { + "state": "Montana", + "city": "Trexlertown" + } + }, + { + "id": 6677, + "name": "Bullock Obrien", + "gender": "male", + "age": 33, + "address": { + "state": "West Virginia", + "city": "Idledale" + } + }, + { + "id": 6678, + "name": "Jessie Vang", + "gender": "female", + "age": 80, + "address": { + "state": "Nevada", + "city": "Allison" + } + }, + { + "id": 6679, + "name": "Claudette Daniels", + "gender": "female", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Twilight" + } + }, + { + "id": 6680, + "name": "Warner Elliott", + "gender": "male", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Itmann" + } + }, + { + "id": 6681, + "name": "Simmons Maynard", + "gender": "male", + "age": 35, + "address": { + "state": "Oklahoma", + "city": "Saranap" + } + }, + { + "id": 6682, + "name": "Kerri Erickson", + "gender": "female", + "age": 80, + "address": { + "state": "New Mexico", + "city": "Chapin" + } + }, + { + "id": 6683, + "name": "Hines Blankenship", + "gender": "male", + "age": 44, + "address": { + "state": "Texas", + "city": "Bowden" + } + }, + { + "id": 6684, + "name": "Ann Cantu", + "gender": "female", + "age": 35, + "address": { + "state": "Idaho", + "city": "Fruitdale" + } + }, + { + "id": 6685, + "name": "Carol Johnson", + "gender": "female", + "age": 26, + "address": { + "state": "South Carolina", + "city": "Caln" + } + }, + { + "id": 6686, + "name": "Annette Howe", + "gender": "female", + "age": 44, + "address": { + "state": "Illinois", + "city": "Chase" + } + }, + { + "id": 6687, + "name": "Coleen Mueller", + "gender": "female", + "age": 72, + "address": { + "state": "Alabama", + "city": "Vale" + } + }, + { + "id": 6688, + "name": "Sasha Snider", + "gender": "female", + "age": 54, + "address": { + "state": "Nebraska", + "city": "Chelsea" + } + }, + { + "id": 6689, + "name": "Reese Alvarado", + "gender": "male", + "age": 65, + "address": { + "state": "Rhode Island", + "city": "Hoehne" + } + }, + { + "id": 6690, + "name": "Chrystal Stout", + "gender": "female", + "age": 72, + "address": { + "state": "Iowa", + "city": "Disautel" + } + }, + { + "id": 6691, + "name": "Marcella Bridges", + "gender": "female", + "age": 26, + "address": { + "state": "Indiana", + "city": "Welch" + } + }, + { + "id": 6692, + "name": "Ellis Hoffman", + "gender": "male", + "age": 66, + "address": { + "state": "South Dakota", + "city": "Ogema" + } + }, + { + "id": 6693, + "name": "Dolly Mcclure", + "gender": "female", + "age": 43, + "address": { + "state": "Utah", + "city": "Chesapeake" + } + }, + { + "id": 6694, + "name": "Melinda Swanson", + "gender": "female", + "age": 46, + "address": { + "state": "Hawaii", + "city": "Brule" + } + }, + { + "id": 6695, + "name": "Nikki Barron", + "gender": "female", + "age": 34, + "address": { + "state": "Pennsylvania", + "city": "Cataract" + } + }, + { + "id": 6696, + "name": "Boyd Carrillo", + "gender": "male", + "age": 57, + "address": { + "state": "North Dakota", + "city": "Morriston" + } + }, + { + "id": 6697, + "name": "Clare Foley", + "gender": "female", + "age": 45, + "address": { + "state": "New Hampshire", + "city": "Logan" + } + }, + { + "id": 6698, + "name": "Church Cobb", + "gender": "male", + "age": 43, + "address": { + "state": "Wisconsin", + "city": "Forbestown" + } + }, + { + "id": 6699, + "name": "Wyatt Mcknight", + "gender": "male", + "age": 63, + "address": { + "state": "Missouri", + "city": "Statenville" + } + }, + { + "id": 6700, + "name": "Leonard Cameron", + "gender": "male", + "age": 75, + "address": { + "state": "Arkansas", + "city": "Colton" + } + }, + { + "id": 6701, + "name": "Hamilton Bell", + "gender": "male", + "age": 64, + "address": { + "state": "Kansas", + "city": "Churchill" + } + }, + { + "id": 6702, + "name": "Mcdaniel Welch", + "gender": "male", + "age": 81, + "address": { + "state": "New York", + "city": "Crawfordsville" + } + }, + { + "id": 6703, + "name": "Schultz Carter", + "gender": "male", + "age": 52, + "address": { + "state": "Vermont", + "city": "Emory" + } + }, + { + "id": 6704, + "name": "Corina Manning", + "gender": "female", + "age": 59, + "address": { + "state": "Tennessee", + "city": "Longoria" + } + }, + { + "id": 6705, + "name": "Lillian Bishop", + "gender": "female", + "age": 21, + "address": { + "state": "Louisiana", + "city": "Salvo" + } + }, + { + "id": 6706, + "name": "Laurie Burns", + "gender": "female", + "age": 71, + "address": { + "state": "Wyoming", + "city": "Berlin" + } + }, + { + "id": 6707, + "name": "Sonja Strickland", + "gender": "female", + "age": 76, + "address": { + "state": "Arizona", + "city": "Ypsilanti" + } + }, + { + "id": 6708, + "name": "Lorraine Aguilar", + "gender": "female", + "age": 68, + "address": { + "state": "Georgia", + "city": "Broadlands" + } + }, + { + "id": 6709, + "name": "Bradshaw Charles", + "gender": "male", + "age": 34, + "address": { + "state": "Washington", + "city": "Darlington" + } + }, + { + "id": 6710, + "name": "Patricia Lester", + "gender": "female", + "age": 53, + "address": { + "state": "Maine", + "city": "Gilmore" + } + }, + { + "id": 6711, + "name": "Myra Miranda", + "gender": "female", + "age": 23, + "address": { + "state": "Michigan", + "city": "Independence" + } + }, + { + "id": 6712, + "name": "Russell Reilly", + "gender": "male", + "age": 68, + "address": { + "state": "Virginia", + "city": "Spelter" + } + }, + { + "id": 6713, + "name": "Mann Baldwin", + "gender": "male", + "age": 26, + "address": { + "state": "Washington", + "city": "Interlochen" + } + }, + { + "id": 6714, + "name": "Jewel Williams", + "gender": "female", + "age": 61, + "address": { + "state": "Missouri", + "city": "Herlong" + } + }, + { + "id": 6715, + "name": "Howell Bruce", + "gender": "male", + "age": 77, + "address": { + "state": "Iowa", + "city": "Haring" + } + }, + { + "id": 6716, + "name": "Nieves Foreman", + "gender": "male", + "age": 64, + "address": { + "state": "North Dakota", + "city": "Aguila" + } + }, + { + "id": 6717, + "name": "Le Langley", + "gender": "male", + "age": 71, + "address": { + "state": "Rhode Island", + "city": "Cuylerville" + } + }, + { + "id": 6718, + "name": "Valdez Hurst", + "gender": "male", + "age": 33, + "address": { + "state": "California", + "city": "Hayes" + } + }, + { + "id": 6719, + "name": "Clarice Figueroa", + "gender": "female", + "age": 48, + "address": { + "state": "Kentucky", + "city": "Springhill" + } + }, + { + "id": 6720, + "name": "Lydia Patton", + "gender": "female", + "age": 71, + "address": { + "state": "New Jersey", + "city": "Alafaya" + } + }, + { + "id": 6721, + "name": "Weeks Lucas", + "gender": "male", + "age": 49, + "address": { + "state": "Alabama", + "city": "Haena" + } + }, + { + "id": 6722, + "name": "Little Glover", + "gender": "male", + "age": 17, + "address": { + "state": "Kansas", + "city": "Advance" + } + }, + { + "id": 6723, + "name": "Yvette Mcdonald", + "gender": "female", + "age": 34, + "address": { + "state": "Colorado", + "city": "Carrizo" + } + }, + { + "id": 6724, + "name": "Osborn Giles", + "gender": "male", + "age": 67, + "address": { + "state": "Oregon", + "city": "Nanafalia" + } + }, + { + "id": 6725, + "name": "Deidre Kelly", + "gender": "female", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Fivepointville" + } + }, + { + "id": 6726, + "name": "Bullock Petty", + "gender": "male", + "age": 43, + "address": { + "state": "Indiana", + "city": "Camptown" + } + }, + { + "id": 6727, + "name": "Abbott Kaufman", + "gender": "male", + "age": 44, + "address": { + "state": "Mississippi", + "city": "Bynum" + } + }, + { + "id": 6728, + "name": "Wilder Collier", + "gender": "male", + "age": 21, + "address": { + "state": "Michigan", + "city": "Ferney" + } + }, + { + "id": 6729, + "name": "Gwendolyn Holden", + "gender": "female", + "age": 43, + "address": { + "state": "Wyoming", + "city": "Winfred" + } + }, + { + "id": 6730, + "name": "Rhonda Mayer", + "gender": "female", + "age": 21, + "address": { + "state": "Delaware", + "city": "Vicksburg" + } + }, + { + "id": 6731, + "name": "Imelda Aguirre", + "gender": "female", + "age": 78, + "address": { + "state": "Virginia", + "city": "Rosine" + } + }, + { + "id": 6732, + "name": "Stacie Winters", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Alfarata" + } + }, + { + "id": 6733, + "name": "Talley Carney", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Deputy" + } + }, + { + "id": 6734, + "name": "Conrad Richmond", + "gender": "male", + "age": 30, + "address": { + "state": "Nevada", + "city": "Cannondale" + } + }, + { + "id": 6735, + "name": "Jimenez Fletcher", + "gender": "male", + "age": 25, + "address": { + "state": "Idaho", + "city": "Nutrioso" + } + }, + { + "id": 6736, + "name": "Lottie Hartman", + "gender": "female", + "age": 27, + "address": { + "state": "Connecticut", + "city": "Foxworth" + } + }, + { + "id": 6737, + "name": "Shannon Maldonado", + "gender": "male", + "age": 34, + "address": { + "state": "New Mexico", + "city": "Cashtown" + } + }, + { + "id": 6738, + "name": "Lloyd Goodman", + "gender": "male", + "age": 27, + "address": { + "state": "Florida", + "city": "Cucumber" + } + }, + { + "id": 6739, + "name": "Marshall Gay", + "gender": "male", + "age": 63, + "address": { + "state": "Pennsylvania", + "city": "Loomis" + } + }, + { + "id": 6740, + "name": "Nichols Chen", + "gender": "male", + "age": 40, + "address": { + "state": "Maryland", + "city": "Eastvale" + } + }, + { + "id": 6741, + "name": "Mooney Walters", + "gender": "male", + "age": 59, + "address": { + "state": "Alaska", + "city": "Dixonville" + } + }, + { + "id": 6742, + "name": "Irma Foley", + "gender": "female", + "age": 47, + "address": { + "state": "Utah", + "city": "Gardiner" + } + }, + { + "id": 6743, + "name": "Alicia Burns", + "gender": "female", + "age": 42, + "address": { + "state": "South Dakota", + "city": "Gilmore" + } + }, + { + "id": 6744, + "name": "Emilia Beard", + "gender": "female", + "age": 73, + "address": { + "state": "Texas", + "city": "Coultervillle" + } + }, + { + "id": 6745, + "name": "Hahn Sloan", + "gender": "male", + "age": 72, + "address": { + "state": "Ohio", + "city": "Richford" + } + }, + { + "id": 6746, + "name": "Candy Rasmussen", + "gender": "female", + "age": 34, + "address": { + "state": "North Carolina", + "city": "Glendale" + } + }, + { + "id": 6747, + "name": "Neva Mullins", + "gender": "female", + "age": 31, + "address": { + "state": "South Carolina", + "city": "Ronco" + } + }, + { + "id": 6748, + "name": "Diann Justice", + "gender": "female", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Stouchsburg" + } + }, + { + "id": 6749, + "name": "Casey Stephenson", + "gender": "male", + "age": 57, + "address": { + "state": "New York", + "city": "Gila" + } + }, + { + "id": 6750, + "name": "Laurel Wade", + "gender": "female", + "age": 82, + "address": { + "state": "Arizona", + "city": "Chapin" + } + }, + { + "id": 6751, + "name": "Dominguez Hinton", + "gender": "male", + "age": 39, + "address": { + "state": "Arkansas", + "city": "Vallonia" + } + }, + { + "id": 6752, + "name": "Meghan Browning", + "gender": "female", + "age": 61, + "address": { + "state": "Wisconsin", + "city": "Homestead" + } + }, + { + "id": 6753, + "name": "Walters Clark", + "gender": "male", + "age": 30, + "address": { + "state": "Maine", + "city": "Beechmont" + } + }, + { + "id": 6754, + "name": "Bradley Prince", + "gender": "male", + "age": 64, + "address": { + "state": "Montana", + "city": "Chilton" + } + }, + { + "id": 6755, + "name": "Franco Dudley", + "gender": "male", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Bourg" + } + }, + { + "id": 6756, + "name": "Elma Drake", + "gender": "female", + "age": 77, + "address": { + "state": "Minnesota", + "city": "Alden" + } + }, + { + "id": 6757, + "name": "Tucker Guerrero", + "gender": "male", + "age": 81, + "address": { + "state": "Oklahoma", + "city": "Malo" + } + }, + { + "id": 6758, + "name": "Sandy Griffith", + "gender": "female", + "age": 43, + "address": { + "state": "Louisiana", + "city": "Trinway" + } + }, + { + "id": 6759, + "name": "Helena Nicholson", + "gender": "female", + "age": 38, + "address": { + "state": "Georgia", + "city": "Greensburg" + } + }, + { + "id": 6760, + "name": "Henry Peterson", + "gender": "male", + "age": 52, + "address": { + "state": "Tennessee", + "city": "Ebro" + } + }, + { + "id": 6761, + "name": "Mercer Sawyer", + "gender": "male", + "age": 37, + "address": { + "state": "New Hampshire", + "city": "Soudan" + } + }, + { + "id": 6762, + "name": "Briggs Knox", + "gender": "male", + "age": 19, + "address": { + "state": "Washington", + "city": "Hall" + } + }, + { + "id": 6763, + "name": "Jordan Yates", + "gender": "male", + "age": 45, + "address": { + "state": "Indiana", + "city": "Rote" + } + }, + { + "id": 6764, + "name": "Tanisha Page", + "gender": "female", + "age": 70, + "address": { + "state": "California", + "city": "Vienna" + } + }, + { + "id": 6765, + "name": "Deana Norris", + "gender": "female", + "age": 82, + "address": { + "state": "Texas", + "city": "Skyland" + } + }, + { + "id": 6766, + "name": "Dianna Hyde", + "gender": "female", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Graniteville" + } + }, + { + "id": 6767, + "name": "Lola Morse", + "gender": "female", + "age": 49, + "address": { + "state": "Virginia", + "city": "Wilmington" + } + }, + { + "id": 6768, + "name": "Caldwell Garner", + "gender": "male", + "age": 51, + "address": { + "state": "New Jersey", + "city": "Alleghenyville" + } + }, + { + "id": 6769, + "name": "Jacklyn Knapp", + "gender": "female", + "age": 27, + "address": { + "state": "New York", + "city": "Croom" + } + }, + { + "id": 6770, + "name": "York Guzman", + "gender": "male", + "age": 40, + "address": { + "state": "Iowa", + "city": "Temperanceville" + } + }, + { + "id": 6771, + "name": "Jeannette Padilla", + "gender": "female", + "age": 73, + "address": { + "state": "Arizona", + "city": "Masthope" + } + }, + { + "id": 6772, + "name": "Liza Singleton", + "gender": "female", + "age": 79, + "address": { + "state": "Utah", + "city": "Silkworth" + } + }, + { + "id": 6773, + "name": "Herman Riley", + "gender": "male", + "age": 42, + "address": { + "state": "New Mexico", + "city": "Lloyd" + } + }, + { + "id": 6774, + "name": "Reyna Burch", + "gender": "female", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Lavalette" + } + }, + { + "id": 6775, + "name": "Mona Hart", + "gender": "female", + "age": 28, + "address": { + "state": "North Carolina", + "city": "Newcastle" + } + }, + { + "id": 6776, + "name": "Tracey Ellison", + "gender": "female", + "age": 54, + "address": { + "state": "Tennessee", + "city": "Greenfields" + } + }, + { + "id": 6777, + "name": "Coleman Albert", + "gender": "male", + "age": 45, + "address": { + "state": "Montana", + "city": "Edenburg" + } + }, + { + "id": 6778, + "name": "Clarke Oneil", + "gender": "male", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Lopezo" + } + }, + { + "id": 6779, + "name": "Gillespie Berger", + "gender": "male", + "age": 63, + "address": { + "state": "South Carolina", + "city": "Selma" + } + }, + { + "id": 6780, + "name": "Boyd Cook", + "gender": "male", + "age": 29, + "address": { + "state": "Oklahoma", + "city": "Hartsville/Hartley" + } + }, + { + "id": 6781, + "name": "May Phillips", + "gender": "female", + "age": 81, + "address": { + "state": "Kentucky", + "city": "Lindisfarne" + } + }, + { + "id": 6782, + "name": "Weeks Chase", + "gender": "male", + "age": 29, + "address": { + "state": "Vermont", + "city": "Fontanelle" + } + }, + { + "id": 6783, + "name": "Barrera Spears", + "gender": "male", + "age": 82, + "address": { + "state": "West Virginia", + "city": "Grazierville" + } + }, + { + "id": 6784, + "name": "Hopper Travis", + "gender": "male", + "age": 78, + "address": { + "state": "Colorado", + "city": "Mahtowa" + } + }, + { + "id": 6785, + "name": "Reynolds Stephenson", + "gender": "male", + "age": 50, + "address": { + "state": "Idaho", + "city": "Bagtown" + } + }, + { + "id": 6786, + "name": "Jenifer Brady", + "gender": "female", + "age": 51, + "address": { + "state": "Mississippi", + "city": "Groton" + } + }, + { + "id": 6787, + "name": "Catherine Erickson", + "gender": "female", + "age": 46, + "address": { + "state": "Wyoming", + "city": "Tuttle" + } + }, + { + "id": 6788, + "name": "Margie Golden", + "gender": "female", + "age": 47, + "address": { + "state": "Kansas", + "city": "Springdale" + } + }, + { + "id": 6789, + "name": "Esther Hopkins", + "gender": "female", + "age": 68, + "address": { + "state": "Maine", + "city": "Fruitdale" + } + }, + { + "id": 6790, + "name": "Collins Moreno", + "gender": "male", + "age": 29, + "address": { + "state": "Michigan", + "city": "Eggertsville" + } + }, + { + "id": 6791, + "name": "Claudia Glass", + "gender": "female", + "age": 72, + "address": { + "state": "Alabama", + "city": "Brecon" + } + }, + { + "id": 6792, + "name": "Jennifer Vega", + "gender": "female", + "age": 21, + "address": { + "state": "Wisconsin", + "city": "Rivereno" + } + }, + { + "id": 6793, + "name": "Koch Leon", + "gender": "male", + "age": 79, + "address": { + "state": "Alaska", + "city": "Grandview" + } + }, + { + "id": 6794, + "name": "Jane Hubbard", + "gender": "female", + "age": 60, + "address": { + "state": "Nevada", + "city": "Riverton" + } + }, + { + "id": 6795, + "name": "Paula Gregory", + "gender": "female", + "age": 32, + "address": { + "state": "South Dakota", + "city": "Teasdale" + } + }, + { + "id": 6796, + "name": "Sarah Burris", + "gender": "female", + "age": 35, + "address": { + "state": "Illinois", + "city": "Terlingua" + } + }, + { + "id": 6797, + "name": "Livingston Anthony", + "gender": "male", + "age": 36, + "address": { + "state": "Pennsylvania", + "city": "Tilleda" + } + }, + { + "id": 6798, + "name": "Santana Tran", + "gender": "male", + "age": 80, + "address": { + "state": "Louisiana", + "city": "Carlos" + } + }, + { + "id": 6799, + "name": "Celina Kane", + "gender": "female", + "age": 73, + "address": { + "state": "Delaware", + "city": "Ruffin" + } + }, + { + "id": 6800, + "name": "Wilkinson Neal", + "gender": "male", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Waiohinu" + } + }, + { + "id": 6801, + "name": "Rhoda Donovan", + "gender": "female", + "age": 71, + "address": { + "state": "North Dakota", + "city": "Germanton" + } + }, + { + "id": 6802, + "name": "Lavonne Avery", + "gender": "female", + "age": 25, + "address": { + "state": "New Hampshire", + "city": "Glasgow" + } + }, + { + "id": 6803, + "name": "Dominguez Morgan", + "gender": "male", + "age": 19, + "address": { + "state": "Missouri", + "city": "Emory" + } + }, + { + "id": 6804, + "name": "Stafford Mckenzie", + "gender": "male", + "age": 19, + "address": { + "state": "Oregon", + "city": "Hoagland" + } + }, + { + "id": 6805, + "name": "Ora Klein", + "gender": "female", + "age": 50, + "address": { + "state": "Maryland", + "city": "Williamson" + } + }, + { + "id": 6806, + "name": "Elliott Tyler", + "gender": "male", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Forestburg" + } + }, + { + "id": 6807, + "name": "Earline Velez", + "gender": "female", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Laurelton" + } + }, + { + "id": 6808, + "name": "Brigitte Parsons", + "gender": "female", + "age": 52, + "address": { + "state": "Georgia", + "city": "Fresno" + } + }, + { + "id": 6809, + "name": "Miles Graham", + "gender": "male", + "age": 73, + "address": { + "state": "Arkansas", + "city": "Avalon" + } + }, + { + "id": 6810, + "name": "Maryellen Mendoza", + "gender": "female", + "age": 27, + "address": { + "state": "Florida", + "city": "Savannah" + } + }, + { + "id": 6811, + "name": "Ericka Chan", + "gender": "female", + "age": 60, + "address": { + "state": "Florida", + "city": "Frierson" + } + }, + { + "id": 6812, + "name": "Luna Daugherty", + "gender": "male", + "age": 57, + "address": { + "state": "North Carolina", + "city": "Kanauga" + } + }, + { + "id": 6813, + "name": "Lynn Greer", + "gender": "male", + "age": 70, + "address": { + "state": "Utah", + "city": "Watrous" + } + }, + { + "id": 6814, + "name": "Francine Mccarty", + "gender": "female", + "age": 62, + "address": { + "state": "Alaska", + "city": "Virgie" + } + }, + { + "id": 6815, + "name": "Meghan Gonzales", + "gender": "female", + "age": 30, + "address": { + "state": "Montana", + "city": "Foxworth" + } + }, + { + "id": 6816, + "name": "Ross Roy", + "gender": "male", + "age": 64, + "address": { + "state": "California", + "city": "Winesburg" + } + }, + { + "id": 6817, + "name": "Hart Gamble", + "gender": "male", + "age": 22, + "address": { + "state": "Ohio", + "city": "Bloomington" + } + }, + { + "id": 6818, + "name": "Riggs Lynch", + "gender": "male", + "age": 42, + "address": { + "state": "Wyoming", + "city": "Williston" + } + }, + { + "id": 6819, + "name": "Lana Bridges", + "gender": "female", + "age": 67, + "address": { + "state": "Colorado", + "city": "Weedville" + } + }, + { + "id": 6820, + "name": "Sullivan Gibson", + "gender": "male", + "age": 40, + "address": { + "state": "Michigan", + "city": "Lowgap" + } + }, + { + "id": 6821, + "name": "Christine Carter", + "gender": "female", + "age": 53, + "address": { + "state": "Alabama", + "city": "Baden" + } + }, + { + "id": 6822, + "name": "Johns Sargent", + "gender": "male", + "age": 32, + "address": { + "state": "Tennessee", + "city": "Roulette" + } + }, + { + "id": 6823, + "name": "Villarreal Simmons", + "gender": "male", + "age": 26, + "address": { + "state": "Vermont", + "city": "Tolu" + } + }, + { + "id": 6824, + "name": "Margie Giles", + "gender": "female", + "age": 76, + "address": { + "state": "New Jersey", + "city": "Emerald" + } + }, + { + "id": 6825, + "name": "Mitchell Bartlett", + "gender": "male", + "age": 68, + "address": { + "state": "Virginia", + "city": "Wakulla" + } + }, + { + "id": 6826, + "name": "Krista Wiley", + "gender": "female", + "age": 31, + "address": { + "state": "Massachusetts", + "city": "Kersey" + } + }, + { + "id": 6827, + "name": "Lucile Jones", + "gender": "female", + "age": 38, + "address": { + "state": "South Carolina", + "city": "Fedora" + } + }, + { + "id": 6828, + "name": "Bishop Hensley", + "gender": "male", + "age": 46, + "address": { + "state": "Illinois", + "city": "Orovada" + } + }, + { + "id": 6829, + "name": "Cherry Joyce", + "gender": "female", + "age": 54, + "address": { + "state": "Indiana", + "city": "Tonopah" + } + }, + { + "id": 6830, + "name": "Tisha Glenn", + "gender": "female", + "age": 76, + "address": { + "state": "Louisiana", + "city": "Downsville" + } + }, + { + "id": 6831, + "name": "Annette Church", + "gender": "female", + "age": 39, + "address": { + "state": "Arkansas", + "city": "Sexton" + } + }, + { + "id": 6832, + "name": "Laura Frederick", + "gender": "female", + "age": 81, + "address": { + "state": "Connecticut", + "city": "Marne" + } + }, + { + "id": 6833, + "name": "Lester Wyatt", + "gender": "male", + "age": 22, + "address": { + "state": "Delaware", + "city": "Waterloo" + } + }, + { + "id": 6834, + "name": "Maddox Padilla", + "gender": "male", + "age": 28, + "address": { + "state": "Nevada", + "city": "Valle" + } + }, + { + "id": 6835, + "name": "Ester Simpson", + "gender": "female", + "age": 35, + "address": { + "state": "Maryland", + "city": "Harborton" + } + }, + { + "id": 6836, + "name": "Julianne Mays", + "gender": "female", + "age": 54, + "address": { + "state": "Oregon", + "city": "Tuttle" + } + }, + { + "id": 6837, + "name": "Beck Pacheco", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Rivereno" + } + }, + { + "id": 6838, + "name": "Vonda Solomon", + "gender": "female", + "age": 37, + "address": { + "state": "New Hampshire", + "city": "Taycheedah" + } + }, + { + "id": 6839, + "name": "Charmaine Pickett", + "gender": "female", + "age": 32, + "address": { + "state": "Mississippi", + "city": "Grazierville" + } + }, + { + "id": 6840, + "name": "Cox Holman", + "gender": "male", + "age": 19, + "address": { + "state": "Kansas", + "city": "Manila" + } + }, + { + "id": 6841, + "name": "Walker Buckner", + "gender": "male", + "age": 27, + "address": { + "state": "Hawaii", + "city": "Alafaya" + } + }, + { + "id": 6842, + "name": "Freda Ochoa", + "gender": "female", + "age": 62, + "address": { + "state": "Maine", + "city": "Coaldale" + } + }, + { + "id": 6843, + "name": "Kent Waller", + "gender": "male", + "age": 17, + "address": { + "state": "Rhode Island", + "city": "Craig" + } + }, + { + "id": 6844, + "name": "Snider Schultz", + "gender": "male", + "age": 68, + "address": { + "state": "Oklahoma", + "city": "Bainbridge" + } + }, + { + "id": 6845, + "name": "Megan Erickson", + "gender": "female", + "age": 67, + "address": { + "state": "South Dakota", + "city": "Como" + } + }, + { + "id": 6846, + "name": "Spence Tucker", + "gender": "male", + "age": 27, + "address": { + "state": "Texas", + "city": "Trail" + } + }, + { + "id": 6847, + "name": "Ora Cline", + "gender": "female", + "age": 67, + "address": { + "state": "North Dakota", + "city": "Kenmar" + } + }, + { + "id": 6848, + "name": "Crosby Rodgers", + "gender": "male", + "age": 40, + "address": { + "state": "Iowa", + "city": "Elbert" + } + }, + { + "id": 6849, + "name": "Ramos Quinn", + "gender": "male", + "age": 26, + "address": { + "state": "Idaho", + "city": "Cataract" + } + }, + { + "id": 6850, + "name": "Stuart Kelley", + "gender": "male", + "age": 51, + "address": { + "state": "Georgia", + "city": "Jugtown" + } + }, + { + "id": 6851, + "name": "Dolores Faulkner", + "gender": "female", + "age": 20, + "address": { + "state": "Kentucky", + "city": "Barclay" + } + }, + { + "id": 6852, + "name": "Latisha Fletcher", + "gender": "female", + "age": 44, + "address": { + "state": "Missouri", + "city": "Ripley" + } + }, + { + "id": 6853, + "name": "Betsy Vaughan", + "gender": "female", + "age": 33, + "address": { + "state": "Nebraska", + "city": "Iberia" + } + }, + { + "id": 6854, + "name": "Strickland Ramsey", + "gender": "male", + "age": 26, + "address": { + "state": "New York", + "city": "Ezel" + } + }, + { + "id": 6855, + "name": "Gabrielle Mayer", + "gender": "female", + "age": 42, + "address": { + "state": "West Virginia", + "city": "Dorneyville" + } + }, + { + "id": 6856, + "name": "Valdez Decker", + "gender": "male", + "age": 73, + "address": { + "state": "New Mexico", + "city": "Blanco" + } + }, + { + "id": 6857, + "name": "Henry Barlow", + "gender": "male", + "age": 19, + "address": { + "state": "Arizona", + "city": "Rockingham" + } + }, + { + "id": 6858, + "name": "Rodriguez Short", + "gender": "male", + "age": 31, + "address": { + "state": "Minnesota", + "city": "Malott" + } + }, + { + "id": 6859, + "name": "Tabitha Campbell", + "gender": "female", + "age": 29, + "address": { + "state": "Washington", + "city": "Walker" + } + }, + { + "id": 6860, + "name": "Tania Burke", + "gender": "female", + "age": 20, + "address": { + "state": "Kentucky", + "city": "Macdona" + } + }, + { + "id": 6861, + "name": "Silva Lang", + "gender": "male", + "age": 59, + "address": { + "state": "Tennessee", + "city": "Bladensburg" + } + }, + { + "id": 6862, + "name": "Walls Knox", + "gender": "male", + "age": 72, + "address": { + "state": "Illinois", + "city": "Inkerman" + } + }, + { + "id": 6863, + "name": "Leblanc Daniel", + "gender": "male", + "age": 62, + "address": { + "state": "Washington", + "city": "Tampico" + } + }, + { + "id": 6864, + "name": "Earnestine Fletcher", + "gender": "female", + "age": 76, + "address": { + "state": "Nevada", + "city": "Newcastle" + } + }, + { + "id": 6865, + "name": "Henderson Warren", + "gender": "male", + "age": 62, + "address": { + "state": "New Jersey", + "city": "Eastmont" + } + }, + { + "id": 6866, + "name": "Andrea Wiley", + "gender": "female", + "age": 42, + "address": { + "state": "Alabama", + "city": "Roy" + } + }, + { + "id": 6867, + "name": "Bentley Houston", + "gender": "male", + "age": 38, + "address": { + "state": "Florida", + "city": "Hasty" + } + }, + { + "id": 6868, + "name": "Charlotte Warner", + "gender": "female", + "age": 49, + "address": { + "state": "Maryland", + "city": "Interlochen" + } + }, + { + "id": 6869, + "name": "Huff Gregory", + "gender": "male", + "age": 53, + "address": { + "state": "Ohio", + "city": "Stonybrook" + } + }, + { + "id": 6870, + "name": "Carter May", + "gender": "male", + "age": 21, + "address": { + "state": "Hawaii", + "city": "Bethany" + } + }, + { + "id": 6871, + "name": "Regina Valencia", + "gender": "female", + "age": 76, + "address": { + "state": "Nebraska", + "city": "Lund" + } + }, + { + "id": 6872, + "name": "Maricela Casey", + "gender": "female", + "age": 43, + "address": { + "state": "Iowa", + "city": "Moraida" + } + }, + { + "id": 6873, + "name": "Todd Rice", + "gender": "male", + "age": 22, + "address": { + "state": "Kansas", + "city": "Stouchsburg" + } + }, + { + "id": 6874, + "name": "Collins Acevedo", + "gender": "male", + "age": 71, + "address": { + "state": "Delaware", + "city": "Dubois" + } + }, + { + "id": 6875, + "name": "Conrad Stephenson", + "gender": "male", + "age": 24, + "address": { + "state": "Mississippi", + "city": "Chemung" + } + }, + { + "id": 6876, + "name": "Fitzpatrick Gibson", + "gender": "male", + "age": 80, + "address": { + "state": "Idaho", + "city": "Slovan" + } + }, + { + "id": 6877, + "name": "Saundra Murray", + "gender": "female", + "age": 58, + "address": { + "state": "Maine", + "city": "Hebron" + } + }, + { + "id": 6878, + "name": "Lorrie Howell", + "gender": "female", + "age": 40, + "address": { + "state": "Indiana", + "city": "Stevens" + } + }, + { + "id": 6879, + "name": "Blake Thornton", + "gender": "male", + "age": 59, + "address": { + "state": "Massachusetts", + "city": "Efland" + } + }, + { + "id": 6880, + "name": "Milagros Burt", + "gender": "female", + "age": 30, + "address": { + "state": "Rhode Island", + "city": "Cliff" + } + }, + { + "id": 6881, + "name": "Watson Robbins", + "gender": "male", + "age": 33, + "address": { + "state": "Vermont", + "city": "Mayfair" + } + }, + { + "id": 6882, + "name": "Lamb Hayden", + "gender": "male", + "age": 29, + "address": { + "state": "Missouri", + "city": "Osage" + } + }, + { + "id": 6883, + "name": "Carla Stout", + "gender": "female", + "age": 56, + "address": { + "state": "North Carolina", + "city": "Sparkill" + } + }, + { + "id": 6884, + "name": "Ruth Neal", + "gender": "female", + "age": 79, + "address": { + "state": "Oregon", + "city": "Robinette" + } + }, + { + "id": 6885, + "name": "Angelina Flowers", + "gender": "female", + "age": 44, + "address": { + "state": "Colorado", + "city": "Bodega" + } + }, + { + "id": 6886, + "name": "Boyd Lowery", + "gender": "male", + "age": 44, + "address": { + "state": "Utah", + "city": "Reinerton" + } + }, + { + "id": 6887, + "name": "Stout Hensley", + "gender": "male", + "age": 31, + "address": { + "state": "North Dakota", + "city": "Gracey" + } + }, + { + "id": 6888, + "name": "Murphy Oneill", + "gender": "male", + "age": 73, + "address": { + "state": "South Carolina", + "city": "Gardners" + } + }, + { + "id": 6889, + "name": "May Richard", + "gender": "female", + "age": 62, + "address": { + "state": "Wisconsin", + "city": "Iberia" + } + }, + { + "id": 6890, + "name": "Marina Compton", + "gender": "female", + "age": 74, + "address": { + "state": "Wyoming", + "city": "Duryea" + } + }, + { + "id": 6891, + "name": "Lawanda Decker", + "gender": "female", + "age": 48, + "address": { + "state": "Connecticut", + "city": "Elliott" + } + }, + { + "id": 6892, + "name": "Velma Stevens", + "gender": "female", + "age": 36, + "address": { + "state": "Minnesota", + "city": "Comptche" + } + }, + { + "id": 6893, + "name": "Arnold Rojas", + "gender": "male", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Utting" + } + }, + { + "id": 6894, + "name": "Barrett Frost", + "gender": "male", + "age": 58, + "address": { + "state": "Texas", + "city": "Gambrills" + } + }, + { + "id": 6895, + "name": "Hughes Cotton", + "gender": "male", + "age": 81, + "address": { + "state": "Michigan", + "city": "Oceola" + } + }, + { + "id": 6896, + "name": "Nichole Prince", + "gender": "female", + "age": 28, + "address": { + "state": "New Hampshire", + "city": "Lynn" + } + }, + { + "id": 6897, + "name": "Deleon Rivers", + "gender": "male", + "age": 38, + "address": { + "state": "Alaska", + "city": "Chilton" + } + }, + { + "id": 6898, + "name": "Jennie Richardson", + "gender": "female", + "age": 73, + "address": { + "state": "Louisiana", + "city": "Accoville" + } + }, + { + "id": 6899, + "name": "Edna Holloway", + "gender": "female", + "age": 67, + "address": { + "state": "Virginia", + "city": "Wollochet" + } + }, + { + "id": 6900, + "name": "Jannie Mcdaniel", + "gender": "female", + "age": 77, + "address": { + "state": "Oklahoma", + "city": "Thermal" + } + }, + { + "id": 6901, + "name": "Renee Barrera", + "gender": "female", + "age": 67, + "address": { + "state": "West Virginia", + "city": "Maplewood" + } + }, + { + "id": 6902, + "name": "Dorsey Hurst", + "gender": "male", + "age": 33, + "address": { + "state": "Montana", + "city": "Lithium" + } + }, + { + "id": 6903, + "name": "Karen Shelton", + "gender": "female", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Murillo" + } + }, + { + "id": 6904, + "name": "Teri Baker", + "gender": "female", + "age": 71, + "address": { + "state": "Pennsylvania", + "city": "Kenmar" + } + }, + { + "id": 6905, + "name": "Penelope Cole", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Westmoreland" + } + }, + { + "id": 6906, + "name": "Shields Weeks", + "gender": "male", + "age": 74, + "address": { + "state": "New York", + "city": "Strong" + } + }, + { + "id": 6907, + "name": "Mathews Schwartz", + "gender": "male", + "age": 25, + "address": { + "state": "California", + "city": "Greer" + } + }, + { + "id": 6908, + "name": "Pruitt Ashley", + "gender": "male", + "age": 34, + "address": { + "state": "Arizona", + "city": "Kenvil" + } + }, + { + "id": 6909, + "name": "Adrienne Bradshaw", + "gender": "female", + "age": 29, + "address": { + "state": "Mississippi", + "city": "Comptche" + } + }, + { + "id": 6910, + "name": "Kerry Melton", + "gender": "female", + "age": 56, + "address": { + "state": "Minnesota", + "city": "Rivera" + } + }, + { + "id": 6911, + "name": "Matthews Wooten", + "gender": "male", + "age": 22, + "address": { + "state": "Kentucky", + "city": "Valmy" + } + }, + { + "id": 6912, + "name": "Laverne Howe", + "gender": "female", + "age": 60, + "address": { + "state": "Massachusetts", + "city": "Singer" + } + }, + { + "id": 6913, + "name": "Aisha Castillo", + "gender": "female", + "age": 17, + "address": { + "state": "Michigan", + "city": "Troy" + } + }, + { + "id": 6914, + "name": "Alexis Huber", + "gender": "female", + "age": 62, + "address": { + "state": "Missouri", + "city": "Newry" + } + }, + { + "id": 6915, + "name": "Bernadine Woodward", + "gender": "female", + "age": 49, + "address": { + "state": "Wyoming", + "city": "Stewartville" + } + }, + { + "id": 6916, + "name": "Terrie Owen", + "gender": "female", + "age": 39, + "address": { + "state": "Georgia", + "city": "Ivanhoe" + } + }, + { + "id": 6917, + "name": "Daniel Sanford", + "gender": "male", + "age": 65, + "address": { + "state": "Colorado", + "city": "Kingstowne" + } + }, + { + "id": 6918, + "name": "Bethany Terrell", + "gender": "female", + "age": 81, + "address": { + "state": "Idaho", + "city": "Carrsville" + } + }, + { + "id": 6919, + "name": "Constance Higgins", + "gender": "female", + "age": 36, + "address": { + "state": "Montana", + "city": "Bartonsville" + } + }, + { + "id": 6920, + "name": "Corinne Hood", + "gender": "female", + "age": 48, + "address": { + "state": "Kansas", + "city": "Hebron" + } + }, + { + "id": 6921, + "name": "Margarita Ballard", + "gender": "female", + "age": 19, + "address": { + "state": "Nebraska", + "city": "Buxton" + } + }, + { + "id": 6922, + "name": "Neva Bradshaw", + "gender": "female", + "age": 48, + "address": { + "state": "Vermont", + "city": "Jacksonburg" + } + }, + { + "id": 6923, + "name": "Betty Morrow", + "gender": "female", + "age": 63, + "address": { + "state": "Nevada", + "city": "Juntura" + } + }, + { + "id": 6924, + "name": "Goodman Dyer", + "gender": "male", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Kenvil" + } + }, + { + "id": 6925, + "name": "Patrick Woodard", + "gender": "male", + "age": 78, + "address": { + "state": "California", + "city": "Sterling" + } + }, + { + "id": 6926, + "name": "Kaye Cannon", + "gender": "female", + "age": 36, + "address": { + "state": "South Dakota", + "city": "Babb" + } + }, + { + "id": 6927, + "name": "Kidd Mckenzie", + "gender": "male", + "age": 53, + "address": { + "state": "Pennsylvania", + "city": "Brookfield" + } + }, + { + "id": 6928, + "name": "Velma Harvey", + "gender": "female", + "age": 58, + "address": { + "state": "Virginia", + "city": "Edenburg" + } + }, + { + "id": 6929, + "name": "Terri Holloway", + "gender": "female", + "age": 23, + "address": { + "state": "Oklahoma", + "city": "Blairstown" + } + }, + { + "id": 6930, + "name": "Ray Everett", + "gender": "male", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Chical" + } + }, + { + "id": 6931, + "name": "Eve Weaver", + "gender": "female", + "age": 71, + "address": { + "state": "Hawaii", + "city": "Curtice" + } + }, + { + "id": 6932, + "name": "Madelyn Justice", + "gender": "female", + "age": 73, + "address": { + "state": "Illinois", + "city": "Winesburg" + } + }, + { + "id": 6933, + "name": "Aguirre Mathis", + "gender": "male", + "age": 69, + "address": { + "state": "Texas", + "city": "Libertytown" + } + }, + { + "id": 6934, + "name": "Gay Conrad", + "gender": "female", + "age": 42, + "address": { + "state": "Alaska", + "city": "Freelandville" + } + }, + { + "id": 6935, + "name": "Dianna Alston", + "gender": "female", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Coldiron" + } + }, + { + "id": 6936, + "name": "Gilliam Hunt", + "gender": "male", + "age": 50, + "address": { + "state": "Delaware", + "city": "Laurelton" + } + }, + { + "id": 6937, + "name": "Etta Yates", + "gender": "female", + "age": 52, + "address": { + "state": "Alabama", + "city": "Homeworth" + } + }, + { + "id": 6938, + "name": "Terry Leach", + "gender": "female", + "age": 55, + "address": { + "state": "Iowa", + "city": "Strong" + } + }, + { + "id": 6939, + "name": "Kate Simon", + "gender": "female", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Coleville" + } + }, + { + "id": 6940, + "name": "Savage Callahan", + "gender": "male", + "age": 37, + "address": { + "state": "Indiana", + "city": "Templeton" + } + }, + { + "id": 6941, + "name": "Dollie Martin", + "gender": "female", + "age": 23, + "address": { + "state": "Maine", + "city": "Macdona" + } + }, + { + "id": 6942, + "name": "Woods Pruitt", + "gender": "male", + "age": 24, + "address": { + "state": "New Jersey", + "city": "Crucible" + } + }, + { + "id": 6943, + "name": "Frank Garrett", + "gender": "male", + "age": 58, + "address": { + "state": "Rhode Island", + "city": "Forestburg" + } + }, + { + "id": 6944, + "name": "Holman Richardson", + "gender": "male", + "age": 58, + "address": { + "state": "New Hampshire", + "city": "Thatcher" + } + }, + { + "id": 6945, + "name": "Soto Wiley", + "gender": "male", + "age": 57, + "address": { + "state": "Tennessee", + "city": "Vowinckel" + } + }, + { + "id": 6946, + "name": "Chris Rich", + "gender": "female", + "age": 18, + "address": { + "state": "Oregon", + "city": "Eagleville" + } + }, + { + "id": 6947, + "name": "Hodges Morris", + "gender": "male", + "age": 53, + "address": { + "state": "West Virginia", + "city": "Darrtown" + } + }, + { + "id": 6948, + "name": "Ramona Meadows", + "gender": "female", + "age": 29, + "address": { + "state": "Washington", + "city": "Sisquoc" + } + }, + { + "id": 6949, + "name": "Hays Parsons", + "gender": "male", + "age": 25, + "address": { + "state": "Utah", + "city": "Manchester" + } + }, + { + "id": 6950, + "name": "Rosales Giles", + "gender": "male", + "age": 70, + "address": { + "state": "Florida", + "city": "Biddle" + } + }, + { + "id": 6951, + "name": "Jeannette Young", + "gender": "female", + "age": 47, + "address": { + "state": "Ohio", + "city": "Why" + } + }, + { + "id": 6952, + "name": "Manning Mcleod", + "gender": "male", + "age": 27, + "address": { + "state": "Wisconsin", + "city": "Conestoga" + } + }, + { + "id": 6953, + "name": "Bridges Riggs", + "gender": "male", + "age": 71, + "address": { + "state": "Arizona", + "city": "Blanford" + } + }, + { + "id": 6954, + "name": "Clarissa Nelson", + "gender": "female", + "age": 17, + "address": { + "state": "New York", + "city": "Rose" + } + }, + { + "id": 6955, + "name": "May Burnett", + "gender": "male", + "age": 21, + "address": { + "state": "New Mexico", + "city": "Defiance" + } + }, + { + "id": 6956, + "name": "Frances Vazquez", + "gender": "female", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Delshire" + } + }, + { + "id": 6957, + "name": "Holder Flynn", + "gender": "male", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Darlington" + } + }, + { + "id": 6958, + "name": "Norton Guerra", + "gender": "male", + "age": 56, + "address": { + "state": "Missouri", + "city": "Rowe" + } + }, + { + "id": 6959, + "name": "Debora Robles", + "gender": "female", + "age": 22, + "address": { + "state": "Pennsylvania", + "city": "Bellamy" + } + }, + { + "id": 6960, + "name": "Tania Rivas", + "gender": "female", + "age": 67, + "address": { + "state": "Minnesota", + "city": "Elwood" + } + }, + { + "id": 6961, + "name": "Marcella Case", + "gender": "female", + "age": 59, + "address": { + "state": "Ohio", + "city": "Basye" + } + }, + { + "id": 6962, + "name": "Frye Harrison", + "gender": "male", + "age": 53, + "address": { + "state": "South Dakota", + "city": "Chemung" + } + }, + { + "id": 6963, + "name": "Cara Hess", + "gender": "female", + "age": 79, + "address": { + "state": "Mississippi", + "city": "Hiwasse" + } + }, + { + "id": 6964, + "name": "Gloria Mcgee", + "gender": "female", + "age": 80, + "address": { + "state": "Oklahoma", + "city": "Bend" + } + }, + { + "id": 6965, + "name": "Jana Charles", + "gender": "female", + "age": 22, + "address": { + "state": "South Carolina", + "city": "Drytown" + } + }, + { + "id": 6966, + "name": "Lottie Stafford", + "gender": "female", + "age": 55, + "address": { + "state": "Hawaii", + "city": "Fulford" + } + }, + { + "id": 6967, + "name": "Angela Henderson", + "gender": "female", + "age": 26, + "address": { + "state": "North Dakota", + "city": "Durham" + } + }, + { + "id": 6968, + "name": "Stephenson Duncan", + "gender": "male", + "age": 81, + "address": { + "state": "Kansas", + "city": "Cochranville" + } + }, + { + "id": 6969, + "name": "Edith Donovan", + "gender": "female", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Summerset" + } + }, + { + "id": 6970, + "name": "Howard Guy", + "gender": "male", + "age": 19, + "address": { + "state": "Wisconsin", + "city": "Beason" + } + }, + { + "id": 6971, + "name": "Kristine Nixon", + "gender": "female", + "age": 46, + "address": { + "state": "Louisiana", + "city": "Gardners" + } + }, + { + "id": 6972, + "name": "Steele Carson", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Maplewood" + } + }, + { + "id": 6973, + "name": "Barbra Woodard", + "gender": "female", + "age": 47, + "address": { + "state": "Florida", + "city": "Whitewater" + } + }, + { + "id": 6974, + "name": "Janelle Odom", + "gender": "female", + "age": 52, + "address": { + "state": "Nevada", + "city": "Day" + } + }, + { + "id": 6975, + "name": "Lakeisha Pierce", + "gender": "female", + "age": 60, + "address": { + "state": "New York", + "city": "Hasty" + } + }, + { + "id": 6976, + "name": "Galloway Chang", + "gender": "male", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Alafaya" + } + }, + { + "id": 6977, + "name": "Viola Berry", + "gender": "female", + "age": 39, + "address": { + "state": "Alabama", + "city": "Allensworth" + } + }, + { + "id": 6978, + "name": "Bean Durham", + "gender": "male", + "age": 22, + "address": { + "state": "Montana", + "city": "Wheatfields" + } + }, + { + "id": 6979, + "name": "Lynnette Martinez", + "gender": "female", + "age": 61, + "address": { + "state": "Virginia", + "city": "Stockwell" + } + }, + { + "id": 6980, + "name": "Holt Miller", + "gender": "male", + "age": 64, + "address": { + "state": "New Mexico", + "city": "Rutherford" + } + }, + { + "id": 6981, + "name": "Woods Jarvis", + "gender": "male", + "age": 38, + "address": { + "state": "North Carolina", + "city": "Lumberton" + } + }, + { + "id": 6982, + "name": "Kristy Bennett", + "gender": "female", + "age": 50, + "address": { + "state": "Alaska", + "city": "Kieler" + } + }, + { + "id": 6983, + "name": "Bowen Calhoun", + "gender": "male", + "age": 37, + "address": { + "state": "Connecticut", + "city": "Craig" + } + }, + { + "id": 6984, + "name": "Klein Prince", + "gender": "male", + "age": 64, + "address": { + "state": "Massachusetts", + "city": "Mulberry" + } + }, + { + "id": 6985, + "name": "Lidia Raymond", + "gender": "female", + "age": 24, + "address": { + "state": "Washington", + "city": "Bendon" + } + }, + { + "id": 6986, + "name": "Rosales Justice", + "gender": "male", + "age": 23, + "address": { + "state": "Maryland", + "city": "Holcombe" + } + }, + { + "id": 6987, + "name": "Schroeder Vazquez", + "gender": "male", + "age": 50, + "address": { + "state": "California", + "city": "Malo" + } + }, + { + "id": 6988, + "name": "Martina Hull", + "gender": "female", + "age": 23, + "address": { + "state": "Idaho", + "city": "Hachita" + } + }, + { + "id": 6989, + "name": "Flynn Berg", + "gender": "male", + "age": 26, + "address": { + "state": "Illinois", + "city": "Cherokee" + } + }, + { + "id": 6990, + "name": "Hollie Noble", + "gender": "female", + "age": 70, + "address": { + "state": "Nebraska", + "city": "Jeff" + } + }, + { + "id": 6991, + "name": "Alejandra Cannon", + "gender": "female", + "age": 57, + "address": { + "state": "Oregon", + "city": "Shrewsbury" + } + }, + { + "id": 6992, + "name": "Maura Holcomb", + "gender": "female", + "age": 48, + "address": { + "state": "Georgia", + "city": "Kerby" + } + }, + { + "id": 6993, + "name": "Patty Christian", + "gender": "female", + "age": 37, + "address": { + "state": "Vermont", + "city": "Oasis" + } + }, + { + "id": 6994, + "name": "Dianna Shelton", + "gender": "female", + "age": 55, + "address": { + "state": "Texas", + "city": "Cecilia" + } + }, + { + "id": 6995, + "name": "Nelson George", + "gender": "male", + "age": 38, + "address": { + "state": "Michigan", + "city": "Soham" + } + }, + { + "id": 6996, + "name": "Lang Lott", + "gender": "male", + "age": 45, + "address": { + "state": "New Hampshire", + "city": "Corinne" + } + }, + { + "id": 6997, + "name": "Boone Romero", + "gender": "male", + "age": 33, + "address": { + "state": "Delaware", + "city": "Homeworth" + } + }, + { + "id": 6998, + "name": "Villarreal Richards", + "gender": "male", + "age": 18, + "address": { + "state": "New Jersey", + "city": "Wacissa" + } + }, + { + "id": 6999, + "name": "Thompson Melendez", + "gender": "male", + "age": 73, + "address": { + "state": "Indiana", + "city": "Canby" + } + }, + { + "id": 7000, + "name": "Fuentes Wilkerson", + "gender": "male", + "age": 49, + "address": { + "state": "Colorado", + "city": "Harold" + } + }, + { + "id": 7001, + "name": "Gomez Hubbard", + "gender": "male", + "age": 47, + "address": { + "state": "Arizona", + "city": "Linganore" + } + }, + { + "id": 7002, + "name": "Alvarez Burch", + "gender": "male", + "age": 63, + "address": { + "state": "Wyoming", + "city": "Virgie" + } + }, + { + "id": 7003, + "name": "Bass Davidson", + "gender": "male", + "age": 31, + "address": { + "state": "Iowa", + "city": "Winfred" + } + }, + { + "id": 7004, + "name": "Geneva Contreras", + "gender": "female", + "age": 41, + "address": { + "state": "Maine", + "city": "Bonanza" + } + }, + { + "id": 7005, + "name": "Aimee Russell", + "gender": "female", + "age": 44, + "address": { + "state": "Utah", + "city": "Richmond" + } + }, + { + "id": 7006, + "name": "Susan Watts", + "gender": "female", + "age": 59, + "address": { + "state": "Rhode Island", + "city": "Unionville" + } + }, + { + "id": 7007, + "name": "Farmer Bradford", + "gender": "male", + "age": 33, + "address": { + "state": "Utah", + "city": "Lutsen" + } + }, + { + "id": 7008, + "name": "Taylor Hawkins", + "gender": "male", + "age": 74, + "address": { + "state": "Texas", + "city": "Riegelwood" + } + }, + { + "id": 7009, + "name": "Watts Frederick", + "gender": "male", + "age": 81, + "address": { + "state": "New York", + "city": "Delco" + } + }, + { + "id": 7010, + "name": "Tina Cantrell", + "gender": "female", + "age": 68, + "address": { + "state": "Michigan", + "city": "Datil" + } + }, + { + "id": 7011, + "name": "Louise Decker", + "gender": "female", + "age": 39, + "address": { + "state": "Wyoming", + "city": "Gwynn" + } + }, + { + "id": 7012, + "name": "Corina Spencer", + "gender": "female", + "age": 26, + "address": { + "state": "Rhode Island", + "city": "Felt" + } + }, + { + "id": 7013, + "name": "Zelma Mcknight", + "gender": "female", + "age": 61, + "address": { + "state": "Ohio", + "city": "Mayfair" + } + }, + { + "id": 7014, + "name": "Lucile Clark", + "gender": "female", + "age": 63, + "address": { + "state": "North Dakota", + "city": "Oceola" + } + }, + { + "id": 7015, + "name": "Sheri Dunn", + "gender": "female", + "age": 60, + "address": { + "state": "Vermont", + "city": "Loma" + } + }, + { + "id": 7016, + "name": "York Zimmerman", + "gender": "male", + "age": 35, + "address": { + "state": "California", + "city": "Herlong" + } + }, + { + "id": 7017, + "name": "Berry Lott", + "gender": "male", + "age": 71, + "address": { + "state": "Kentucky", + "city": "Cherokee" + } + }, + { + "id": 7018, + "name": "Kim Atkins", + "gender": "male", + "age": 41, + "address": { + "state": "West Virginia", + "city": "Hasty" + } + }, + { + "id": 7019, + "name": "Toni Young", + "gender": "female", + "age": 29, + "address": { + "state": "South Dakota", + "city": "Dorneyville" + } + }, + { + "id": 7020, + "name": "Robles Simpson", + "gender": "male", + "age": 53, + "address": { + "state": "Wisconsin", + "city": "Glenbrook" + } + }, + { + "id": 7021, + "name": "Mallory Francis", + "gender": "female", + "age": 32, + "address": { + "state": "Montana", + "city": "Robinette" + } + }, + { + "id": 7022, + "name": "Miranda Jennings", + "gender": "male", + "age": 80, + "address": { + "state": "Massachusetts", + "city": "Hickory" + } + }, + { + "id": 7023, + "name": "Diaz Rollins", + "gender": "male", + "age": 17, + "address": { + "state": "Florida", + "city": "Disautel" + } + }, + { + "id": 7024, + "name": "Hardy Lamb", + "gender": "male", + "age": 53, + "address": { + "state": "Tennessee", + "city": "Fidelis" + } + }, + { + "id": 7025, + "name": "Lamb Gibbs", + "gender": "male", + "age": 18, + "address": { + "state": "Iowa", + "city": "Dexter" + } + }, + { + "id": 7026, + "name": "Bonnie Leonard", + "gender": "female", + "age": 34, + "address": { + "state": "New Jersey", + "city": "Moraida" + } + }, + { + "id": 7027, + "name": "Janelle Dalton", + "gender": "female", + "age": 55, + "address": { + "state": "South Carolina", + "city": "Hayden" + } + }, + { + "id": 7028, + "name": "Bryan Workman", + "gender": "male", + "age": 43, + "address": { + "state": "Colorado", + "city": "Cade" + } + }, + { + "id": 7029, + "name": "Glenn Carrillo", + "gender": "male", + "age": 25, + "address": { + "state": "Maine", + "city": "Bridgetown" + } + }, + { + "id": 7030, + "name": "Greta Cash", + "gender": "female", + "age": 17, + "address": { + "state": "Kansas", + "city": "Carlos" + } + }, + { + "id": 7031, + "name": "Tabatha Meadows", + "gender": "female", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Vallonia" + } + }, + { + "id": 7032, + "name": "Hays Moran", + "gender": "male", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Cotopaxi" + } + }, + { + "id": 7033, + "name": "Cantu Graves", + "gender": "male", + "age": 23, + "address": { + "state": "Minnesota", + "city": "Tyhee" + } + }, + { + "id": 7034, + "name": "Lara Mueller", + "gender": "male", + "age": 67, + "address": { + "state": "Georgia", + "city": "Chamberino" + } + }, + { + "id": 7035, + "name": "Lesley Harmon", + "gender": "female", + "age": 53, + "address": { + "state": "Alaska", + "city": "Noblestown" + } + }, + { + "id": 7036, + "name": "Combs Kidd", + "gender": "male", + "age": 80, + "address": { + "state": "New Hampshire", + "city": "Oley" + } + }, + { + "id": 7037, + "name": "Jacqueline Weber", + "gender": "female", + "age": 71, + "address": { + "state": "Hawaii", + "city": "Grazierville" + } + }, + { + "id": 7038, + "name": "Hatfield Davis", + "gender": "male", + "age": 38, + "address": { + "state": "Nebraska", + "city": "Edgar" + } + }, + { + "id": 7039, + "name": "Reyes Lopez", + "gender": "male", + "age": 37, + "address": { + "state": "New Mexico", + "city": "Florence" + } + }, + { + "id": 7040, + "name": "Savannah Rios", + "gender": "female", + "age": 27, + "address": { + "state": "Arizona", + "city": "Gracey" + } + }, + { + "id": 7041, + "name": "Vaughn Webb", + "gender": "male", + "age": 80, + "address": { + "state": "Maryland", + "city": "Flintville" + } + }, + { + "id": 7042, + "name": "Ollie Dominguez", + "gender": "female", + "age": 72, + "address": { + "state": "Missouri", + "city": "Dalton" + } + }, + { + "id": 7043, + "name": "Augusta Hurley", + "gender": "female", + "age": 55, + "address": { + "state": "Mississippi", + "city": "Lumberton" + } + }, + { + "id": 7044, + "name": "Gallagher Russell", + "gender": "male", + "age": 60, + "address": { + "state": "Connecticut", + "city": "Bluffview" + } + }, + { + "id": 7045, + "name": "Gonzalez Baxter", + "gender": "male", + "age": 44, + "address": { + "state": "North Carolina", + "city": "Orason" + } + }, + { + "id": 7046, + "name": "Shannon Odom", + "gender": "male", + "age": 33, + "address": { + "state": "Pennsylvania", + "city": "Convent" + } + }, + { + "id": 7047, + "name": "Ashley Paul", + "gender": "male", + "age": 43, + "address": { + "state": "Arkansas", + "city": "Valle" + } + }, + { + "id": 7048, + "name": "Olson Curry", + "gender": "male", + "age": 19, + "address": { + "state": "Washington", + "city": "Kirk" + } + }, + { + "id": 7049, + "name": "Minerva Benton", + "gender": "female", + "age": 39, + "address": { + "state": "Alabama", + "city": "Moscow" + } + }, + { + "id": 7050, + "name": "Landry Ellis", + "gender": "male", + "age": 70, + "address": { + "state": "Indiana", + "city": "Manitou" + } + }, + { + "id": 7051, + "name": "Gilbert Bush", + "gender": "male", + "age": 73, + "address": { + "state": "Delaware", + "city": "Dahlen" + } + }, + { + "id": 7052, + "name": "Enid Hodges", + "gender": "female", + "age": 17, + "address": { + "state": "Nevada", + "city": "Brandermill" + } + }, + { + "id": 7053, + "name": "Sylvia Harper", + "gender": "female", + "age": 18, + "address": { + "state": "Illinois", + "city": "Alamo" + } + }, + { + "id": 7054, + "name": "Wolfe Branch", + "gender": "male", + "age": 37, + "address": { + "state": "Oregon", + "city": "Keyport" + } + }, + { + "id": 7055, + "name": "Tanner Larsen", + "gender": "male", + "age": 76, + "address": { + "state": "Virginia", + "city": "Barrelville" + } + }, + { + "id": 7056, + "name": "Cervantes Pearson", + "gender": "male", + "age": 38, + "address": { + "state": "Alaska", + "city": "Allison" + } + }, + { + "id": 7057, + "name": "English Morin", + "gender": "male", + "age": 73, + "address": { + "state": "California", + "city": "Sidman" + } + }, + { + "id": 7058, + "name": "Goodwin Roach", + "gender": "male", + "age": 45, + "address": { + "state": "Idaho", + "city": "Camas" + } + }, + { + "id": 7059, + "name": "Diann Pennington", + "gender": "female", + "age": 58, + "address": { + "state": "Kansas", + "city": "Reinerton" + } + }, + { + "id": 7060, + "name": "Eileen Shepherd", + "gender": "female", + "age": 28, + "address": { + "state": "Maryland", + "city": "Matheny" + } + }, + { + "id": 7061, + "name": "Marsha Roberts", + "gender": "female", + "age": 44, + "address": { + "state": "New Jersey", + "city": "Gardners" + } + }, + { + "id": 7062, + "name": "Sheryl Reeves", + "gender": "female", + "age": 47, + "address": { + "state": "Colorado", + "city": "Rivera" + } + }, + { + "id": 7063, + "name": "Katy Brewer", + "gender": "female", + "age": 57, + "address": { + "state": "Arizona", + "city": "Cetronia" + } + }, + { + "id": 7064, + "name": "Gay Armstrong", + "gender": "female", + "age": 59, + "address": { + "state": "Delaware", + "city": "Kilbourne" + } + }, + { + "id": 7065, + "name": "Pierce Schwartz", + "gender": "male", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Roeville" + } + }, + { + "id": 7066, + "name": "Glenna Vasquez", + "gender": "female", + "age": 72, + "address": { + "state": "Florida", + "city": "Chelsea" + } + }, + { + "id": 7067, + "name": "Bethany Bauer", + "gender": "female", + "age": 51, + "address": { + "state": "South Dakota", + "city": "Chase" + } + }, + { + "id": 7068, + "name": "Natasha Kramer", + "gender": "female", + "age": 34, + "address": { + "state": "Wyoming", + "city": "Independence" + } + }, + { + "id": 7069, + "name": "Church Washington", + "gender": "male", + "age": 28, + "address": { + "state": "Minnesota", + "city": "Caspar" + } + }, + { + "id": 7070, + "name": "Pat Bond", + "gender": "female", + "age": 18, + "address": { + "state": "Oregon", + "city": "Chestnut" + } + }, + { + "id": 7071, + "name": "Charlotte Compton", + "gender": "female", + "age": 65, + "address": { + "state": "Missouri", + "city": "Bainbridge" + } + }, + { + "id": 7072, + "name": "Flynn Haley", + "gender": "male", + "age": 47, + "address": { + "state": "Vermont", + "city": "Churchill" + } + }, + { + "id": 7073, + "name": "Audrey Floyd", + "gender": "female", + "age": 55, + "address": { + "state": "Iowa", + "city": "Aurora" + } + }, + { + "id": 7074, + "name": "Wheeler Rivers", + "gender": "male", + "age": 44, + "address": { + "state": "Utah", + "city": "Oceola" + } + }, + { + "id": 7075, + "name": "Jefferson Mercer", + "gender": "male", + "age": 44, + "address": { + "state": "West Virginia", + "city": "Williamson" + } + }, + { + "id": 7076, + "name": "Booth Hurst", + "gender": "male", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Mansfield" + } + }, + { + "id": 7077, + "name": "Yesenia Huber", + "gender": "female", + "age": 49, + "address": { + "state": "Ohio", + "city": "Davenport" + } + }, + { + "id": 7078, + "name": "Acevedo Robbins", + "gender": "male", + "age": 54, + "address": { + "state": "Nebraska", + "city": "Macdona" + } + }, + { + "id": 7079, + "name": "Peggy Forbes", + "gender": "female", + "age": 74, + "address": { + "state": "Maine", + "city": "Fowlerville" + } + }, + { + "id": 7080, + "name": "Millie Cote", + "gender": "female", + "age": 60, + "address": { + "state": "Rhode Island", + "city": "Montura" + } + }, + { + "id": 7081, + "name": "Duke Joseph", + "gender": "male", + "age": 64, + "address": { + "state": "Kentucky", + "city": "Leola" + } + }, + { + "id": 7082, + "name": "Hoover Mullins", + "gender": "male", + "age": 57, + "address": { + "state": "North Carolina", + "city": "Wells" + } + }, + { + "id": 7083, + "name": "Oliver Park", + "gender": "male", + "age": 28, + "address": { + "state": "New York", + "city": "Gerber" + } + }, + { + "id": 7084, + "name": "Snyder Farley", + "gender": "male", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Saddlebrooke" + } + }, + { + "id": 7085, + "name": "Clay Walton", + "gender": "male", + "age": 33, + "address": { + "state": "Alabama", + "city": "Ribera" + } + }, + { + "id": 7086, + "name": "Ebony James", + "gender": "female", + "age": 55, + "address": { + "state": "Nevada", + "city": "Wadsworth" + } + }, + { + "id": 7087, + "name": "Rosalind Hanson", + "gender": "female", + "age": 41, + "address": { + "state": "Mississippi", + "city": "Clayville" + } + }, + { + "id": 7088, + "name": "Brenda Wolfe", + "gender": "female", + "age": 77, + "address": { + "state": "Louisiana", + "city": "Allensworth" + } + }, + { + "id": 7089, + "name": "Shawna Chandler", + "gender": "female", + "age": 59, + "address": { + "state": "Oklahoma", + "city": "Felt" + } + }, + { + "id": 7090, + "name": "Graciela Baird", + "gender": "female", + "age": 31, + "address": { + "state": "Montana", + "city": "Movico" + } + }, + { + "id": 7091, + "name": "Stacie Salazar", + "gender": "female", + "age": 41, + "address": { + "state": "Virginia", + "city": "Sperryville" + } + }, + { + "id": 7092, + "name": "Lang Martinez", + "gender": "male", + "age": 34, + "address": { + "state": "Michigan", + "city": "Inkerman" + } + }, + { + "id": 7093, + "name": "Bobbi Mathews", + "gender": "female", + "age": 70, + "address": { + "state": "Tennessee", + "city": "Crenshaw" + } + }, + { + "id": 7094, + "name": "Beverly Vincent", + "gender": "female", + "age": 42, + "address": { + "state": "Georgia", + "city": "Ebro" + } + }, + { + "id": 7095, + "name": "Autumn Petty", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Beechmont" + } + }, + { + "id": 7096, + "name": "Rachelle Spencer", + "gender": "female", + "age": 75, + "address": { + "state": "Indiana", + "city": "Klondike" + } + }, + { + "id": 7097, + "name": "Beatriz Dillon", + "gender": "female", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Mulberry" + } + }, + { + "id": 7098, + "name": "Luella Cantrell", + "gender": "female", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Hessville" + } + }, + { + "id": 7099, + "name": "Ayers Golden", + "gender": "male", + "age": 65, + "address": { + "state": "New Hampshire", + "city": "Mayfair" + } + }, + { + "id": 7100, + "name": "Webb Frederick", + "gender": "male", + "age": 52, + "address": { + "state": "South Carolina", + "city": "Santel" + } + }, + { + "id": 7101, + "name": "Winifred Sweeney", + "gender": "female", + "age": 35, + "address": { + "state": "Washington", + "city": "Barclay" + } + }, + { + "id": 7102, + "name": "Carney Rodriguez", + "gender": "male", + "age": 27, + "address": { + "state": "Wisconsin", + "city": "Singer" + } + }, + { + "id": 7103, + "name": "Cora Hardin", + "gender": "female", + "age": 82, + "address": { + "state": "Texas", + "city": "Linwood" + } + }, + { + "id": 7104, + "name": "Short Barnes", + "gender": "male", + "age": 80, + "address": { + "state": "North Dakota", + "city": "Broadlands" + } + }, + { + "id": 7105, + "name": "Terry Webb", + "gender": "female", + "age": 59, + "address": { + "state": "Utah", + "city": "Limestone" + } + }, + { + "id": 7106, + "name": "Sasha Howell", + "gender": "female", + "age": 69, + "address": { + "state": "Florida", + "city": "Tilleda" + } + }, + { + "id": 7107, + "name": "Yang Mathews", + "gender": "male", + "age": 45, + "address": { + "state": "Rhode Island", + "city": "Alfarata" + } + }, + { + "id": 7108, + "name": "Valdez Sellers", + "gender": "male", + "age": 24, + "address": { + "state": "Delaware", + "city": "Leland" + } + }, + { + "id": 7109, + "name": "Lolita Wade", + "gender": "female", + "age": 19, + "address": { + "state": "Nebraska", + "city": "Richville" + } + }, + { + "id": 7110, + "name": "Kristine Irwin", + "gender": "female", + "age": 31, + "address": { + "state": "New York", + "city": "Chase" + } + }, + { + "id": 7111, + "name": "Nettie Ellison", + "gender": "female", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Draper" + } + }, + { + "id": 7112, + "name": "Pierce Koch", + "gender": "male", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Cherokee" + } + }, + { + "id": 7113, + "name": "Linda Morrison", + "gender": "female", + "age": 65, + "address": { + "state": "Indiana", + "city": "Caln" + } + }, + { + "id": 7114, + "name": "Thompson Spears", + "gender": "male", + "age": 82, + "address": { + "state": "Maine", + "city": "Coinjock" + } + }, + { + "id": 7115, + "name": "Kristi Phelps", + "gender": "female", + "age": 65, + "address": { + "state": "New Hampshire", + "city": "Garfield" + } + }, + { + "id": 7116, + "name": "Cervantes Copeland", + "gender": "male", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Gerber" + } + }, + { + "id": 7117, + "name": "Leona Griffith", + "gender": "female", + "age": 29, + "address": { + "state": "Idaho", + "city": "Coventry" + } + }, + { + "id": 7118, + "name": "Faulkner Hall", + "gender": "male", + "age": 41, + "address": { + "state": "Arizona", + "city": "Broadlands" + } + }, + { + "id": 7119, + "name": "Sandoval Branch", + "gender": "male", + "age": 55, + "address": { + "state": "South Dakota", + "city": "Colton" + } + }, + { + "id": 7120, + "name": "Vicky Rocha", + "gender": "female", + "age": 40, + "address": { + "state": "Connecticut", + "city": "Wakulla" + } + }, + { + "id": 7121, + "name": "Carla Mcintosh", + "gender": "female", + "age": 58, + "address": { + "state": "Washington", + "city": "Enlow" + } + }, + { + "id": 7122, + "name": "Welch Hodge", + "gender": "male", + "age": 47, + "address": { + "state": "New Jersey", + "city": "Dyckesville" + } + }, + { + "id": 7123, + "name": "York Allen", + "gender": "male", + "age": 37, + "address": { + "state": "South Carolina", + "city": "Bodega" + } + }, + { + "id": 7124, + "name": "Dollie Baldwin", + "gender": "female", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Independence" + } + }, + { + "id": 7125, + "name": "Douglas Duran", + "gender": "male", + "age": 61, + "address": { + "state": "Alaska", + "city": "Wanamie" + } + }, + { + "id": 7126, + "name": "Andrea Davis", + "gender": "female", + "age": 68, + "address": { + "state": "Montana", + "city": "Brenton" + } + }, + { + "id": 7127, + "name": "Mills Cherry", + "gender": "male", + "age": 47, + "address": { + "state": "Illinois", + "city": "Kohatk" + } + }, + { + "id": 7128, + "name": "Victoria Terry", + "gender": "female", + "age": 22, + "address": { + "state": "Maryland", + "city": "Byrnedale" + } + }, + { + "id": 7129, + "name": "Paul Mcleod", + "gender": "male", + "age": 66, + "address": { + "state": "Kentucky", + "city": "Salvo" + } + }, + { + "id": 7130, + "name": "Eleanor Bell", + "gender": "female", + "age": 37, + "address": { + "state": "Mississippi", + "city": "Condon" + } + }, + { + "id": 7131, + "name": "Adriana Bright", + "gender": "female", + "age": 68, + "address": { + "state": "Colorado", + "city": "Trail" + } + }, + { + "id": 7132, + "name": "Mccormick Gallagher", + "gender": "male", + "age": 39, + "address": { + "state": "Michigan", + "city": "Felt" + } + }, + { + "id": 7133, + "name": "Robbie Preston", + "gender": "female", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Alafaya" + } + }, + { + "id": 7134, + "name": "Kathleen Montgomery", + "gender": "female", + "age": 38, + "address": { + "state": "Wisconsin", + "city": "Boling" + } + }, + { + "id": 7135, + "name": "Livingston Mcconnell", + "gender": "male", + "age": 64, + "address": { + "state": "Georgia", + "city": "Churchill" + } + }, + { + "id": 7136, + "name": "Mooney Lindsay", + "gender": "male", + "age": 78, + "address": { + "state": "Ohio", + "city": "Rockhill" + } + }, + { + "id": 7137, + "name": "Darlene Hess", + "gender": "female", + "age": 21, + "address": { + "state": "Iowa", + "city": "Woodlake" + } + }, + { + "id": 7138, + "name": "Compton Albert", + "gender": "male", + "age": 48, + "address": { + "state": "Massachusetts", + "city": "Sanborn" + } + }, + { + "id": 7139, + "name": "Lucy Lowery", + "gender": "female", + "age": 31, + "address": { + "state": "Vermont", + "city": "Grapeview" + } + }, + { + "id": 7140, + "name": "Dorthy Hale", + "gender": "female", + "age": 56, + "address": { + "state": "Alabama", + "city": "Naomi" + } + }, + { + "id": 7141, + "name": "Wyatt Mcgowan", + "gender": "male", + "age": 51, + "address": { + "state": "Virginia", + "city": "Belleview" + } + }, + { + "id": 7142, + "name": "Roy Orr", + "gender": "male", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Allensworth" + } + }, + { + "id": 7143, + "name": "Spence Poole", + "gender": "male", + "age": 75, + "address": { + "state": "North Dakota", + "city": "Murillo" + } + }, + { + "id": 7144, + "name": "Stacie Moreno", + "gender": "female", + "age": 38, + "address": { + "state": "Missouri", + "city": "Fruitdale" + } + }, + { + "id": 7145, + "name": "Perez Serrano", + "gender": "male", + "age": 33, + "address": { + "state": "Oregon", + "city": "Starks" + } + }, + { + "id": 7146, + "name": "Vance Mitchell", + "gender": "male", + "age": 80, + "address": { + "state": "Texas", + "city": "Umapine" + } + }, + { + "id": 7147, + "name": "Stacy Garrett", + "gender": "female", + "age": 78, + "address": { + "state": "California", + "city": "Villarreal" + } + }, + { + "id": 7148, + "name": "Cora Brady", + "gender": "female", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Madaket" + } + }, + { + "id": 7149, + "name": "Bernard Fowler", + "gender": "male", + "age": 29, + "address": { + "state": "Kansas", + "city": "Foscoe" + } + }, + { + "id": 7150, + "name": "Hickman Alston", + "gender": "male", + "age": 18, + "address": { + "state": "Wyoming", + "city": "Dawn" + } + }, + { + "id": 7151, + "name": "Brady Fulton", + "gender": "male", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Camas" + } + }, + { + "id": 7152, + "name": "Jacqueline Nielsen", + "gender": "female", + "age": 26, + "address": { + "state": "West Virginia", + "city": "Kanauga" + } + }, + { + "id": 7153, + "name": "Phelps Roth", + "gender": "male", + "age": 82, + "address": { + "state": "Tennessee", + "city": "Crucible" + } + }, + { + "id": 7154, + "name": "Adrienne Tyson", + "gender": "female", + "age": 33, + "address": { + "state": "Rhode Island", + "city": "Sanders" + } + }, + { + "id": 7155, + "name": "Hurst Gordon", + "gender": "male", + "age": 79, + "address": { + "state": "Wyoming", + "city": "Idamay" + } + }, + { + "id": 7156, + "name": "Noel Sims", + "gender": "male", + "age": 77, + "address": { + "state": "Colorado", + "city": "Bonanza" + } + }, + { + "id": 7157, + "name": "Janna Estrada", + "gender": "female", + "age": 57, + "address": { + "state": "Arizona", + "city": "Bawcomville" + } + }, + { + "id": 7158, + "name": "Ina Albert", + "gender": "female", + "age": 54, + "address": { + "state": "Nevada", + "city": "Ronco" + } + }, + { + "id": 7159, + "name": "Gale Glenn", + "gender": "female", + "age": 75, + "address": { + "state": "New Jersey", + "city": "Caberfae" + } + }, + { + "id": 7160, + "name": "Nichole Vance", + "gender": "female", + "age": 39, + "address": { + "state": "Missouri", + "city": "Manila" + } + }, + { + "id": 7161, + "name": "Clarice Boone", + "gender": "female", + "age": 65, + "address": { + "state": "Florida", + "city": "Wright" + } + }, + { + "id": 7162, + "name": "Hillary Hull", + "gender": "female", + "age": 34, + "address": { + "state": "Massachusetts", + "city": "Wilsonia" + } + }, + { + "id": 7163, + "name": "Madelyn Barr", + "gender": "female", + "age": 75, + "address": { + "state": "Oklahoma", + "city": "Freelandville" + } + }, + { + "id": 7164, + "name": "Russo Warner", + "gender": "male", + "age": 29, + "address": { + "state": "Vermont", + "city": "Fresno" + } + }, + { + "id": 7165, + "name": "Manuela Duke", + "gender": "female", + "age": 17, + "address": { + "state": "North Dakota", + "city": "Vale" + } + }, + { + "id": 7166, + "name": "Pacheco Ferrell", + "gender": "male", + "age": 51, + "address": { + "state": "Alaska", + "city": "Fairview" + } + }, + { + "id": 7167, + "name": "Foley Tillman", + "gender": "male", + "age": 38, + "address": { + "state": "Louisiana", + "city": "Hondah" + } + }, + { + "id": 7168, + "name": "Keri Jenkins", + "gender": "female", + "age": 74, + "address": { + "state": "Iowa", + "city": "Trucksville" + } + }, + { + "id": 7169, + "name": "Harrington Yang", + "gender": "male", + "age": 64, + "address": { + "state": "Ohio", + "city": "Kanauga" + } + }, + { + "id": 7170, + "name": "Rosalyn Delgado", + "gender": "female", + "age": 60, + "address": { + "state": "Illinois", + "city": "Kylertown" + } + }, + { + "id": 7171, + "name": "Jacquelyn Hoover", + "gender": "female", + "age": 24, + "address": { + "state": "Kentucky", + "city": "Harrison" + } + }, + { + "id": 7172, + "name": "Shaw Daniels", + "gender": "male", + "age": 80, + "address": { + "state": "Washington", + "city": "Blanford" + } + }, + { + "id": 7173, + "name": "Myers Becker", + "gender": "male", + "age": 51, + "address": { + "state": "Kansas", + "city": "Woodlake" + } + }, + { + "id": 7174, + "name": "Yang Neal", + "gender": "male", + "age": 65, + "address": { + "state": "South Dakota", + "city": "Olney" + } + }, + { + "id": 7175, + "name": "Consuelo Malone", + "gender": "female", + "age": 42, + "address": { + "state": "Indiana", + "city": "Conestoga" + } + }, + { + "id": 7176, + "name": "Kaitlin Adams", + "gender": "female", + "age": 74, + "address": { + "state": "Connecticut", + "city": "Rivers" + } + }, + { + "id": 7177, + "name": "Cherry Cooper", + "gender": "male", + "age": 79, + "address": { + "state": "Texas", + "city": "Wheaton" + } + }, + { + "id": 7178, + "name": "Ewing Olsen", + "gender": "male", + "age": 54, + "address": { + "state": "Alabama", + "city": "Freetown" + } + }, + { + "id": 7179, + "name": "Brittney Mclean", + "gender": "female", + "age": 80, + "address": { + "state": "Tennessee", + "city": "Waiohinu" + } + }, + { + "id": 7180, + "name": "Key Duncan", + "gender": "male", + "age": 55, + "address": { + "state": "West Virginia", + "city": "Rivera" + } + }, + { + "id": 7181, + "name": "Charmaine Skinner", + "gender": "female", + "age": 36, + "address": { + "state": "Maryland", + "city": "Trail" + } + }, + { + "id": 7182, + "name": "Deidre Brooks", + "gender": "female", + "age": 73, + "address": { + "state": "Oregon", + "city": "Iola" + } + }, + { + "id": 7183, + "name": "Hanson Raymond", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Hannasville" + } + }, + { + "id": 7184, + "name": "Jo Hutchinson", + "gender": "female", + "age": 58, + "address": { + "state": "New Mexico", + "city": "Sugartown" + } + }, + { + "id": 7185, + "name": "Madden Cruz", + "gender": "male", + "age": 73, + "address": { + "state": "Virginia", + "city": "Ironton" + } + }, + { + "id": 7186, + "name": "Church Hancock", + "gender": "male", + "age": 82, + "address": { + "state": "New York", + "city": "Neahkahnie" + } + }, + { + "id": 7187, + "name": "Nicholson Sanford", + "gender": "male", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Emerald" + } + }, + { + "id": 7188, + "name": "Fulton Padilla", + "gender": "male", + "age": 47, + "address": { + "state": "Mississippi", + "city": "Gasquet" + } + }, + { + "id": 7189, + "name": "Beverly Fields", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Chilton" + } + }, + { + "id": 7190, + "name": "Ball Blankenship", + "gender": "male", + "age": 34, + "address": { + "state": "Minnesota", + "city": "Haring" + } + }, + { + "id": 7191, + "name": "Penelope Tanner", + "gender": "female", + "age": 37, + "address": { + "state": "Nebraska", + "city": "Caspar" + } + }, + { + "id": 7192, + "name": "Terra Hurley", + "gender": "female", + "age": 33, + "address": { + "state": "North Carolina", + "city": "Gardners" + } + }, + { + "id": 7193, + "name": "Kim Andrews", + "gender": "male", + "age": 71, + "address": { + "state": "Arkansas", + "city": "Alden" + } + }, + { + "id": 7194, + "name": "Cantrell Russell", + "gender": "male", + "age": 71, + "address": { + "state": "New Hampshire", + "city": "Germanton" + } + }, + { + "id": 7195, + "name": "Mejia Booker", + "gender": "male", + "age": 65, + "address": { + "state": "Georgia", + "city": "Fairhaven" + } + }, + { + "id": 7196, + "name": "Violet Norris", + "gender": "female", + "age": 72, + "address": { + "state": "Michigan", + "city": "Chapin" + } + }, + { + "id": 7197, + "name": "Lynda Stone", + "gender": "female", + "age": 82, + "address": { + "state": "California", + "city": "Walker" + } + }, + { + "id": 7198, + "name": "Estrada Cook", + "gender": "male", + "age": 35, + "address": { + "state": "Utah", + "city": "Kidder" + } + }, + { + "id": 7199, + "name": "Cooper Gill", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Boykin" + } + }, + { + "id": 7200, + "name": "Owens Ross", + "gender": "male", + "age": 44, + "address": { + "state": "Maine", + "city": "Valle" + } + }, + { + "id": 7201, + "name": "Mason Deleon", + "gender": "male", + "age": 39, + "address": { + "state": "Idaho", + "city": "Enetai" + } + }, + { + "id": 7202, + "name": "Mcclain Butler", + "gender": "male", + "age": 67, + "address": { + "state": "Montana", + "city": "Avalon" + } + }, + { + "id": 7203, + "name": "Britney Macias", + "gender": "female", + "age": 40, + "address": { + "state": "West Virginia", + "city": "Davenport" + } + }, + { + "id": 7204, + "name": "Sandra Bruce", + "gender": "female", + "age": 39, + "address": { + "state": "Ohio", + "city": "Cashtown" + } + }, + { + "id": 7205, + "name": "Wagner Dodson", + "gender": "male", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Barstow" + } + }, + { + "id": 7206, + "name": "Marcie Short", + "gender": "female", + "age": 76, + "address": { + "state": "Pennsylvania", + "city": "Fairview" + } + }, + { + "id": 7207, + "name": "Callie Pitts", + "gender": "female", + "age": 47, + "address": { + "state": "Maryland", + "city": "Crenshaw" + } + }, + { + "id": 7208, + "name": "Ellis Larsen", + "gender": "male", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Macdona" + } + }, + { + "id": 7209, + "name": "Rene Powell", + "gender": "female", + "age": 34, + "address": { + "state": "Oklahoma", + "city": "Trexlertown" + } + }, + { + "id": 7210, + "name": "Salinas Cote", + "gender": "male", + "age": 31, + "address": { + "state": "Texas", + "city": "Weeksville" + } + }, + { + "id": 7211, + "name": "Emma Alexander", + "gender": "female", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Aurora" + } + }, + { + "id": 7212, + "name": "Orr Knapp", + "gender": "male", + "age": 76, + "address": { + "state": "Missouri", + "city": "Jacumba" + } + }, + { + "id": 7213, + "name": "Bullock Gutierrez", + "gender": "male", + "age": 46, + "address": { + "state": "Illinois", + "city": "Rew" + } + }, + { + "id": 7214, + "name": "Ester Horton", + "gender": "female", + "age": 26, + "address": { + "state": "South Carolina", + "city": "Cassel" + } + }, + { + "id": 7215, + "name": "Pena Langley", + "gender": "male", + "age": 38, + "address": { + "state": "California", + "city": "Canterwood" + } + }, + { + "id": 7216, + "name": "Wendi Glover", + "gender": "female", + "age": 66, + "address": { + "state": "Washington", + "city": "Kohatk" + } + }, + { + "id": 7217, + "name": "Meyers Sellers", + "gender": "male", + "age": 65, + "address": { + "state": "Nebraska", + "city": "Cherokee" + } + }, + { + "id": 7218, + "name": "Sherman Carter", + "gender": "male", + "age": 37, + "address": { + "state": "Michigan", + "city": "Strykersville" + } + }, + { + "id": 7219, + "name": "Guthrie Rose", + "gender": "male", + "age": 30, + "address": { + "state": "Utah", + "city": "Dahlen" + } + }, + { + "id": 7220, + "name": "Armstrong Sweet", + "gender": "male", + "age": 72, + "address": { + "state": "New York", + "city": "Wyano" + } + }, + { + "id": 7221, + "name": "Ingrid Madden", + "gender": "female", + "age": 30, + "address": { + "state": "North Carolina", + "city": "Lutsen" + } + }, + { + "id": 7222, + "name": "Cobb Jordan", + "gender": "male", + "age": 79, + "address": { + "state": "Connecticut", + "city": "Gilmore" + } + }, + { + "id": 7223, + "name": "Erin Anthony", + "gender": "female", + "age": 70, + "address": { + "state": "Minnesota", + "city": "Utting" + } + }, + { + "id": 7224, + "name": "Bartlett Harding", + "gender": "male", + "age": 42, + "address": { + "state": "Arkansas", + "city": "Matheny" + } + }, + { + "id": 7225, + "name": "Serena Deleon", + "gender": "female", + "age": 72, + "address": { + "state": "Alaska", + "city": "Murillo" + } + }, + { + "id": 7226, + "name": "Decker Jarvis", + "gender": "male", + "age": 56, + "address": { + "state": "Massachusetts", + "city": "Elbert" + } + }, + { + "id": 7227, + "name": "Hooper Brennan", + "gender": "male", + "age": 17, + "address": { + "state": "Arizona", + "city": "Thatcher" + } + }, + { + "id": 7228, + "name": "Lindsey Sawyer", + "gender": "female", + "age": 28, + "address": { + "state": "Mississippi", + "city": "Eden" + } + }, + { + "id": 7229, + "name": "Glover Lewis", + "gender": "male", + "age": 17, + "address": { + "state": "Delaware", + "city": "Dunnavant" + } + }, + { + "id": 7230, + "name": "Lee Molina", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Iberia" + } + }, + { + "id": 7231, + "name": "Sheryl Pope", + "gender": "female", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Toftrees" + } + }, + { + "id": 7232, + "name": "Brennan Case", + "gender": "male", + "age": 43, + "address": { + "state": "Colorado", + "city": "Dargan" + } + }, + { + "id": 7233, + "name": "Dianna Odonnell", + "gender": "female", + "age": 62, + "address": { + "state": "Maine", + "city": "Gerber" + } + }, + { + "id": 7234, + "name": "Cox Serrano", + "gender": "male", + "age": 22, + "address": { + "state": "Indiana", + "city": "Bodega" + } + }, + { + "id": 7235, + "name": "Ivy Nichols", + "gender": "female", + "age": 17, + "address": { + "state": "Idaho", + "city": "Rodanthe" + } + }, + { + "id": 7236, + "name": "Jillian Richards", + "gender": "female", + "age": 52, + "address": { + "state": "Nevada", + "city": "Gibsonia" + } + }, + { + "id": 7237, + "name": "Patsy Barber", + "gender": "female", + "age": 81, + "address": { + "state": "Vermont", + "city": "Coral" + } + }, + { + "id": 7238, + "name": "Tran Woodward", + "gender": "male", + "age": 72, + "address": { + "state": "Kentucky", + "city": "Delwood" + } + }, + { + "id": 7239, + "name": "Abby Chase", + "gender": "female", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Farmers" + } + }, + { + "id": 7240, + "name": "Gracie Riggs", + "gender": "female", + "age": 57, + "address": { + "state": "Florida", + "city": "Garfield" + } + }, + { + "id": 7241, + "name": "Mabel Nguyen", + "gender": "female", + "age": 31, + "address": { + "state": "South Dakota", + "city": "Juarez" + } + }, + { + "id": 7242, + "name": "Erickson Osborne", + "gender": "male", + "age": 74, + "address": { + "state": "Montana", + "city": "Dundee" + } + }, + { + "id": 7243, + "name": "Wooten Wright", + "gender": "male", + "age": 26, + "address": { + "state": "Georgia", + "city": "Bartonsville" + } + }, + { + "id": 7244, + "name": "Edwina Gilmore", + "gender": "female", + "age": 69, + "address": { + "state": "North Dakota", + "city": "Shaft" + } + }, + { + "id": 7245, + "name": "Sabrina Gallagher", + "gender": "female", + "age": 31, + "address": { + "state": "Iowa", + "city": "Fairacres" + } + }, + { + "id": 7246, + "name": "Tonya Booth", + "gender": "female", + "age": 29, + "address": { + "state": "Alabama", + "city": "Abrams" + } + }, + { + "id": 7247, + "name": "May Holcomb", + "gender": "male", + "age": 33, + "address": { + "state": "Hawaii", + "city": "Blackgum" + } + }, + { + "id": 7248, + "name": "Clements Burch", + "gender": "male", + "age": 79, + "address": { + "state": "New Mexico", + "city": "Salix" + } + }, + { + "id": 7249, + "name": "Vivian Barker", + "gender": "female", + "age": 59, + "address": { + "state": "Kansas", + "city": "Verdi" + } + }, + { + "id": 7250, + "name": "Fowler Bass", + "gender": "male", + "age": 56, + "address": { + "state": "Virginia", + "city": "Coloma" + } + }, + { + "id": 7251, + "name": "Buchanan Horn", + "gender": "male", + "age": 24, + "address": { + "state": "Oregon", + "city": "Coleville" + } + }, + { + "id": 7252, + "name": "Delacruz Bradford", + "gender": "male", + "age": 78, + "address": { + "state": "Michigan", + "city": "Ruffin" + } + }, + { + "id": 7253, + "name": "Matthews May", + "gender": "male", + "age": 58, + "address": { + "state": "Rhode Island", + "city": "Tecolotito" + } + }, + { + "id": 7254, + "name": "Evans Hoffman", + "gender": "male", + "age": 25, + "address": { + "state": "Oregon", + "city": "Vienna" + } + }, + { + "id": 7255, + "name": "Flowers Huff", + "gender": "male", + "age": 67, + "address": { + "state": "Illinois", + "city": "Hebron" + } + }, + { + "id": 7256, + "name": "Ellis Turner", + "gender": "male", + "age": 73, + "address": { + "state": "Vermont", + "city": "Aurora" + } + }, + { + "id": 7257, + "name": "Cannon Singleton", + "gender": "male", + "age": 42, + "address": { + "state": "Washington", + "city": "Wattsville" + } + }, + { + "id": 7258, + "name": "Mary Glover", + "gender": "female", + "age": 68, + "address": { + "state": "South Dakota", + "city": "Wawona" + } + }, + { + "id": 7259, + "name": "Johns Carney", + "gender": "male", + "age": 81, + "address": { + "state": "Montana", + "city": "Soham" + } + }, + { + "id": 7260, + "name": "Martina Warren", + "gender": "female", + "age": 20, + "address": { + "state": "Florida", + "city": "Cetronia" + } + }, + { + "id": 7261, + "name": "Shawn Chambers", + "gender": "female", + "age": 19, + "address": { + "state": "Texas", + "city": "Rosine" + } + }, + { + "id": 7262, + "name": "Brandy Suarez", + "gender": "female", + "age": 42, + "address": { + "state": "Kansas", + "city": "Norwood" + } + }, + { + "id": 7263, + "name": "Sharon Villarreal", + "gender": "female", + "age": 26, + "address": { + "state": "Louisiana", + "city": "Sexton" + } + }, + { + "id": 7264, + "name": "Carlene Bennett", + "gender": "female", + "age": 22, + "address": { + "state": "Kentucky", + "city": "Blanford" + } + }, + { + "id": 7265, + "name": "Carey Palmer", + "gender": "female", + "age": 38, + "address": { + "state": "Wyoming", + "city": "Hardyville" + } + }, + { + "id": 7266, + "name": "Bradford Hardy", + "gender": "male", + "age": 77, + "address": { + "state": "Wisconsin", + "city": "Lynn" + } + }, + { + "id": 7267, + "name": "Jennie Rojas", + "gender": "female", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Kersey" + } + }, + { + "id": 7268, + "name": "Polly Payne", + "gender": "female", + "age": 46, + "address": { + "state": "Indiana", + "city": "Worton" + } + }, + { + "id": 7269, + "name": "Conrad Knowles", + "gender": "male", + "age": 55, + "address": { + "state": "Alabama", + "city": "Dahlen" + } + }, + { + "id": 7270, + "name": "Rebecca Sampson", + "gender": "female", + "age": 63, + "address": { + "state": "South Carolina", + "city": "Woodlands" + } + }, + { + "id": 7271, + "name": "Mcintosh King", + "gender": "male", + "age": 79, + "address": { + "state": "New York", + "city": "Kraemer" + } + }, + { + "id": 7272, + "name": "Pope Hughes", + "gender": "male", + "age": 42, + "address": { + "state": "Hawaii", + "city": "Venice" + } + }, + { + "id": 7273, + "name": "Bridgett Bright", + "gender": "female", + "age": 57, + "address": { + "state": "Maine", + "city": "Edmund" + } + }, + { + "id": 7274, + "name": "Michael Banks", + "gender": "female", + "age": 53, + "address": { + "state": "Virginia", + "city": "Katonah" + } + }, + { + "id": 7275, + "name": "Evangelina Harrison", + "gender": "female", + "age": 76, + "address": { + "state": "Georgia", + "city": "Needmore" + } + }, + { + "id": 7276, + "name": "Mullen Rodgers", + "gender": "male", + "age": 32, + "address": { + "state": "Alaska", + "city": "Snelling" + } + }, + { + "id": 7277, + "name": "Henderson Kemp", + "gender": "male", + "age": 27, + "address": { + "state": "North Carolina", + "city": "Dennard" + } + }, + { + "id": 7278, + "name": "Joyce Meyer", + "gender": "female", + "age": 64, + "address": { + "state": "Iowa", + "city": "Jamestown" + } + }, + { + "id": 7279, + "name": "Corine Nolan", + "gender": "female", + "age": 30, + "address": { + "state": "Pennsylvania", + "city": "Fairmount" + } + }, + { + "id": 7280, + "name": "Petty Macdonald", + "gender": "male", + "age": 56, + "address": { + "state": "Maryland", + "city": "Gardners" + } + }, + { + "id": 7281, + "name": "Workman Bowen", + "gender": "male", + "age": 38, + "address": { + "state": "Missouri", + "city": "Trona" + } + }, + { + "id": 7282, + "name": "Millicent Moses", + "gender": "female", + "age": 21, + "address": { + "state": "Idaho", + "city": "Trexlertown" + } + }, + { + "id": 7283, + "name": "Lang Rush", + "gender": "male", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Blairstown" + } + }, + { + "id": 7284, + "name": "Olive Foley", + "gender": "female", + "age": 73, + "address": { + "state": "Colorado", + "city": "Riceville" + } + }, + { + "id": 7285, + "name": "Kasey Buckley", + "gender": "female", + "age": 81, + "address": { + "state": "North Dakota", + "city": "Bison" + } + }, + { + "id": 7286, + "name": "Sara Gardner", + "gender": "female", + "age": 59, + "address": { + "state": "New Jersey", + "city": "Deputy" + } + }, + { + "id": 7287, + "name": "Delacruz Wood", + "gender": "male", + "age": 42, + "address": { + "state": "Minnesota", + "city": "Gracey" + } + }, + { + "id": 7288, + "name": "Kristen Duffy", + "gender": "female", + "age": 69, + "address": { + "state": "Connecticut", + "city": "Breinigsville" + } + }, + { + "id": 7289, + "name": "Jamie Mcdonald", + "gender": "female", + "age": 17, + "address": { + "state": "Delaware", + "city": "Caledonia" + } + }, + { + "id": 7290, + "name": "Kelley Whitehead", + "gender": "female", + "age": 57, + "address": { + "state": "New Mexico", + "city": "Hachita" + } + }, + { + "id": 7291, + "name": "Newman Hyde", + "gender": "male", + "age": 33, + "address": { + "state": "Mississippi", + "city": "Curtice" + } + }, + { + "id": 7292, + "name": "Wolf Velasquez", + "gender": "male", + "age": 53, + "address": { + "state": "Arkansas", + "city": "Mansfield" + } + }, + { + "id": 7293, + "name": "Wood Bird", + "gender": "male", + "age": 24, + "address": { + "state": "Ohio", + "city": "Fivepointville" + } + }, + { + "id": 7294, + "name": "Staci Cleveland", + "gender": "female", + "age": 40, + "address": { + "state": "Utah", + "city": "Nanafalia" + } + }, + { + "id": 7295, + "name": "Smith Mcmahon", + "gender": "male", + "age": 30, + "address": { + "state": "West Virginia", + "city": "Watchtower" + } + }, + { + "id": 7296, + "name": "Tanya Kline", + "gender": "female", + "age": 45, + "address": { + "state": "Nevada", + "city": "Efland" + } + }, + { + "id": 7297, + "name": "Andrews Riggs", + "gender": "male", + "age": 41, + "address": { + "state": "Massachusetts", + "city": "Oasis" + } + }, + { + "id": 7298, + "name": "Underwood Aguirre", + "gender": "male", + "age": 82, + "address": { + "state": "Arizona", + "city": "Crayne" + } + }, + { + "id": 7299, + "name": "Macias Alexander", + "gender": "male", + "age": 73, + "address": { + "state": "California", + "city": "Westerville" + } + }, + { + "id": 7300, + "name": "Abby Mccarthy", + "gender": "female", + "age": 24, + "address": { + "state": "Nebraska", + "city": "Cuylerville" + } + }, + { + "id": 7301, + "name": "Leach Huber", + "gender": "male", + "age": 25, + "address": { + "state": "Illinois", + "city": "Fairforest" + } + }, + { + "id": 7302, + "name": "Penny Duffy", + "gender": "female", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Germanton" + } + }, + { + "id": 7303, + "name": "Collins Trujillo", + "gender": "male", + "age": 43, + "address": { + "state": "Oregon", + "city": "Bethpage" + } + }, + { + "id": 7304, + "name": "Ursula Osborne", + "gender": "female", + "age": 67, + "address": { + "state": "Louisiana", + "city": "Ferney" + } + }, + { + "id": 7305, + "name": "Warner Jordan", + "gender": "male", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Blue" + } + }, + { + "id": 7306, + "name": "Becky Randall", + "gender": "female", + "age": 54, + "address": { + "state": "West Virginia", + "city": "Snelling" + } + }, + { + "id": 7307, + "name": "Norma Ortega", + "gender": "female", + "age": 49, + "address": { + "state": "Hawaii", + "city": "Deercroft" + } + }, + { + "id": 7308, + "name": "Donovan Nicholson", + "gender": "male", + "age": 32, + "address": { + "state": "Minnesota", + "city": "Rushford" + } + }, + { + "id": 7309, + "name": "May Tanner", + "gender": "female", + "age": 35, + "address": { + "state": "Missouri", + "city": "Wacissa" + } + }, + { + "id": 7310, + "name": "Pickett Black", + "gender": "male", + "age": 54, + "address": { + "state": "Michigan", + "city": "Thatcher" + } + }, + { + "id": 7311, + "name": "Best Tyson", + "gender": "male", + "age": 51, + "address": { + "state": "Florida", + "city": "Grantville" + } + }, + { + "id": 7312, + "name": "Lewis Talley", + "gender": "male", + "age": 62, + "address": { + "state": "Indiana", + "city": "Grill" + } + }, + { + "id": 7313, + "name": "Araceli Cameron", + "gender": "female", + "age": 45, + "address": { + "state": "Oklahoma", + "city": "Allison" + } + }, + { + "id": 7314, + "name": "Beatriz Potts", + "gender": "female", + "age": 45, + "address": { + "state": "Maine", + "city": "Masthope" + } + }, + { + "id": 7315, + "name": "Lesley Baxter", + "gender": "female", + "age": 44, + "address": { + "state": "North Carolina", + "city": "Muse" + } + }, + { + "id": 7316, + "name": "Roach Dodson", + "gender": "male", + "age": 74, + "address": { + "state": "California", + "city": "Roosevelt" + } + }, + { + "id": 7317, + "name": "Casey Dudley", + "gender": "female", + "age": 55, + "address": { + "state": "New Hampshire", + "city": "Springville" + } + }, + { + "id": 7318, + "name": "Peters Odom", + "gender": "male", + "age": 19, + "address": { + "state": "Colorado", + "city": "Chesapeake" + } + }, + { + "id": 7319, + "name": "Ethel Lyons", + "gender": "female", + "age": 60, + "address": { + "state": "New Jersey", + "city": "Loomis" + } + }, + { + "id": 7320, + "name": "Oneil Christian", + "gender": "male", + "age": 47, + "address": { + "state": "Kentucky", + "city": "Lupton" + } + }, + { + "id": 7321, + "name": "Simon Turner", + "gender": "male", + "age": 40, + "address": { + "state": "Tennessee", + "city": "Snyderville" + } + }, + { + "id": 7322, + "name": "Darla Patterson", + "gender": "female", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Brooktrails" + } + }, + { + "id": 7323, + "name": "Calderon Morse", + "gender": "male", + "age": 58, + "address": { + "state": "Alaska", + "city": "Fruitdale" + } + }, + { + "id": 7324, + "name": "Harrell George", + "gender": "male", + "age": 60, + "address": { + "state": "North Dakota", + "city": "Ada" + } + }, + { + "id": 7325, + "name": "Jimenez Myers", + "gender": "male", + "age": 61, + "address": { + "state": "Wisconsin", + "city": "Sabillasville" + } + }, + { + "id": 7326, + "name": "Keisha Juarez", + "gender": "female", + "age": 18, + "address": { + "state": "Pennsylvania", + "city": "Lacomb" + } + }, + { + "id": 7327, + "name": "Little Hooper", + "gender": "male", + "age": 29, + "address": { + "state": "Georgia", + "city": "Bagtown" + } + }, + { + "id": 7328, + "name": "Ernestine Short", + "gender": "female", + "age": 25, + "address": { + "state": "Arizona", + "city": "Corinne" + } + }, + { + "id": 7329, + "name": "Rivers Franks", + "gender": "male", + "age": 53, + "address": { + "state": "Washington", + "city": "Glenbrook" + } + }, + { + "id": 7330, + "name": "Carey Vang", + "gender": "female", + "age": 24, + "address": { + "state": "Ohio", + "city": "Romeville" + } + }, + { + "id": 7331, + "name": "Betty Valdez", + "gender": "female", + "age": 57, + "address": { + "state": "New Mexico", + "city": "Gilgo" + } + }, + { + "id": 7332, + "name": "Natasha Stein", + "gender": "female", + "age": 39, + "address": { + "state": "South Carolina", + "city": "Klagetoh" + } + }, + { + "id": 7333, + "name": "Monica Phillips", + "gender": "female", + "age": 54, + "address": { + "state": "Rhode Island", + "city": "Comptche" + } + }, + { + "id": 7334, + "name": "Mollie Bates", + "gender": "female", + "age": 53, + "address": { + "state": "Nebraska", + "city": "Chalfant" + } + }, + { + "id": 7335, + "name": "Dale Pittman", + "gender": "male", + "age": 62, + "address": { + "state": "Idaho", + "city": "Goldfield" + } + }, + { + "id": 7336, + "name": "Karin Shannon", + "gender": "female", + "age": 74, + "address": { + "state": "Montana", + "city": "Bend" + } + }, + { + "id": 7337, + "name": "Wise Carrillo", + "gender": "male", + "age": 46, + "address": { + "state": "Arkansas", + "city": "Wheatfields" + } + }, + { + "id": 7338, + "name": "Aline Little", + "gender": "female", + "age": 22, + "address": { + "state": "Connecticut", + "city": "Whitehaven" + } + }, + { + "id": 7339, + "name": "Adkins Zamora", + "gender": "male", + "age": 49, + "address": { + "state": "Utah", + "city": "Inkerman" + } + }, + { + "id": 7340, + "name": "Sanders Jimenez", + "gender": "male", + "age": 51, + "address": { + "state": "Iowa", + "city": "Singer" + } + }, + { + "id": 7341, + "name": "Sims Francis", + "gender": "male", + "age": 23, + "address": { + "state": "Nevada", + "city": "Yogaville" + } + }, + { + "id": 7342, + "name": "Kemp Morton", + "gender": "male", + "age": 49, + "address": { + "state": "Virginia", + "city": "Bellfountain" + } + }, + { + "id": 7343, + "name": "Gibson Riley", + "gender": "male", + "age": 36, + "address": { + "state": "Maryland", + "city": "Osage" + } + }, + { + "id": 7344, + "name": "Tamera Schultz", + "gender": "female", + "age": 79, + "address": { + "state": "Alabama", + "city": "Mappsville" + } + }, + { + "id": 7345, + "name": "Cortez Hood", + "gender": "male", + "age": 70, + "address": { + "state": "Delaware", + "city": "Indio" + } + }, + { + "id": 7346, + "name": "Bell Pickett", + "gender": "male", + "age": 19, + "address": { + "state": "Kansas", + "city": "Faxon" + } + }, + { + "id": 7347, + "name": "Lawrence Richard", + "gender": "male", + "age": 37, + "address": { + "state": "Texas", + "city": "Bath" + } + }, + { + "id": 7348, + "name": "Corine Pope", + "gender": "female", + "age": 28, + "address": { + "state": "New York", + "city": "Thornport" + } + }, + { + "id": 7349, + "name": "Dorothea Whitaker", + "gender": "female", + "age": 25, + "address": { + "state": "Vermont", + "city": "Deputy" + } + }, + { + "id": 7350, + "name": "Grant Golden", + "gender": "male", + "age": 76, + "address": { + "state": "Montana", + "city": "Baden" + } + }, + { + "id": 7351, + "name": "Norton Contreras", + "gender": "male", + "age": 55, + "address": { + "state": "Nevada", + "city": "Hardyville" + } + }, + { + "id": 7352, + "name": "Bertha House", + "gender": "female", + "age": 77, + "address": { + "state": "Maryland", + "city": "Echo" + } + }, + { + "id": 7353, + "name": "Miranda Ashley", + "gender": "female", + "age": 43, + "address": { + "state": "Arizona", + "city": "Brutus" + } + }, + { + "id": 7354, + "name": "Romero Schultz", + "gender": "male", + "age": 30, + "address": { + "state": "Alaska", + "city": "Wakulla" + } + }, + { + "id": 7355, + "name": "Maude Cole", + "gender": "female", + "age": 36, + "address": { + "state": "Oregon", + "city": "Dalton" + } + }, + { + "id": 7356, + "name": "Rosalinda Moody", + "gender": "female", + "age": 29, + "address": { + "state": "Wisconsin", + "city": "Stevens" + } + }, + { + "id": 7357, + "name": "Alexis Mann", + "gender": "female", + "age": 68, + "address": { + "state": "Nebraska", + "city": "Juntura" + } + }, + { + "id": 7358, + "name": "Alvarado Andrews", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Broadlands" + } + }, + { + "id": 7359, + "name": "Isabel Ramos", + "gender": "female", + "age": 19, + "address": { + "state": "Missouri", + "city": "Rockhill" + } + }, + { + "id": 7360, + "name": "Kim Morrow", + "gender": "male", + "age": 78, + "address": { + "state": "Texas", + "city": "Dixie" + } + }, + { + "id": 7361, + "name": "Best May", + "gender": "male", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Denio" + } + }, + { + "id": 7362, + "name": "Duncan Gibbs", + "gender": "male", + "age": 54, + "address": { + "state": "California", + "city": "Dubois" + } + }, + { + "id": 7363, + "name": "Daugherty Kramer", + "gender": "male", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Waterloo" + } + }, + { + "id": 7364, + "name": "Wendy Oneal", + "gender": "female", + "age": 29, + "address": { + "state": "Oklahoma", + "city": "Kenvil" + } + }, + { + "id": 7365, + "name": "Brandy Bradford", + "gender": "female", + "age": 35, + "address": { + "state": "Washington", + "city": "Downsville" + } + }, + { + "id": 7366, + "name": "Ava Washington", + "gender": "female", + "age": 18, + "address": { + "state": "South Dakota", + "city": "Floriston" + } + }, + { + "id": 7367, + "name": "Bowers Bright", + "gender": "male", + "age": 29, + "address": { + "state": "Hawaii", + "city": "Delwood" + } + }, + { + "id": 7368, + "name": "Warner Holloway", + "gender": "male", + "age": 58, + "address": { + "state": "New Hampshire", + "city": "Blue" + } + }, + { + "id": 7369, + "name": "Sheppard Strickland", + "gender": "male", + "age": 38, + "address": { + "state": "West Virginia", + "city": "Lodoga" + } + }, + { + "id": 7370, + "name": "Aguilar Leblanc", + "gender": "male", + "age": 57, + "address": { + "state": "Louisiana", + "city": "Cutter" + } + }, + { + "id": 7371, + "name": "Avery Tate", + "gender": "male", + "age": 39, + "address": { + "state": "Colorado", + "city": "Cumminsville" + } + }, + { + "id": 7372, + "name": "Cantu Walsh", + "gender": "male", + "age": 71, + "address": { + "state": "Georgia", + "city": "Martinez" + } + }, + { + "id": 7373, + "name": "Thomas Singleton", + "gender": "male", + "age": 60, + "address": { + "state": "Vermont", + "city": "Linganore" + } + }, + { + "id": 7374, + "name": "Mai Sherman", + "gender": "female", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Chase" + } + }, + { + "id": 7375, + "name": "Twila Mckee", + "gender": "female", + "age": 74, + "address": { + "state": "Alabama", + "city": "Robinette" + } + }, + { + "id": 7376, + "name": "Alyssa Mcmahon", + "gender": "female", + "age": 75, + "address": { + "state": "New Mexico", + "city": "Rose" + } + }, + { + "id": 7377, + "name": "Darla Shields", + "gender": "female", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Harborton" + } + }, + { + "id": 7378, + "name": "Luna Durham", + "gender": "male", + "age": 81, + "address": { + "state": "New York", + "city": "Lindisfarne" + } + }, + { + "id": 7379, + "name": "Katelyn Oneil", + "gender": "female", + "age": 66, + "address": { + "state": "Iowa", + "city": "Carbonville" + } + }, + { + "id": 7380, + "name": "Merrill Flores", + "gender": "male", + "age": 20, + "address": { + "state": "Maine", + "city": "Wiscon" + } + }, + { + "id": 7381, + "name": "Petty Duke", + "gender": "male", + "age": 49, + "address": { + "state": "Arkansas", + "city": "Harviell" + } + }, + { + "id": 7382, + "name": "Trevino Mckay", + "gender": "male", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Benson" + } + }, + { + "id": 7383, + "name": "Sharpe Craig", + "gender": "male", + "age": 67, + "address": { + "state": "Mississippi", + "city": "Bagtown" + } + }, + { + "id": 7384, + "name": "Myers Pollard", + "gender": "male", + "age": 64, + "address": { + "state": "Massachusetts", + "city": "Winston" + } + }, + { + "id": 7385, + "name": "Gena Mcleod", + "gender": "female", + "age": 47, + "address": { + "state": "Connecticut", + "city": "Lavalette" + } + }, + { + "id": 7386, + "name": "Adkins Grant", + "gender": "male", + "age": 73, + "address": { + "state": "Idaho", + "city": "Dale" + } + }, + { + "id": 7387, + "name": "Lara Walton", + "gender": "male", + "age": 46, + "address": { + "state": "Delaware", + "city": "Rew" + } + }, + { + "id": 7388, + "name": "Ferrell Stanley", + "gender": "male", + "age": 59, + "address": { + "state": "Indiana", + "city": "Tioga" + } + }, + { + "id": 7389, + "name": "Eaton Morton", + "gender": "male", + "age": 25, + "address": { + "state": "Ohio", + "city": "Yardville" + } + }, + { + "id": 7390, + "name": "Sonya Rosa", + "gender": "female", + "age": 46, + "address": { + "state": "Utah", + "city": "Vernon" + } + }, + { + "id": 7391, + "name": "Kimberly Cohen", + "gender": "female", + "age": 43, + "address": { + "state": "Michigan", + "city": "Wedgewood" + } + }, + { + "id": 7392, + "name": "May Graham", + "gender": "male", + "age": 17, + "address": { + "state": "South Carolina", + "city": "Sexton" + } + }, + { + "id": 7393, + "name": "Priscilla Lawrence", + "gender": "female", + "age": 54, + "address": { + "state": "Virginia", + "city": "Maury" + } + }, + { + "id": 7394, + "name": "Morse Stafford", + "gender": "male", + "age": 82, + "address": { + "state": "Illinois", + "city": "Williston" + } + }, + { + "id": 7395, + "name": "Scott Santos", + "gender": "male", + "age": 51, + "address": { + "state": "Kentucky", + "city": "Hiwasse" + } + }, + { + "id": 7396, + "name": "Madeleine Moses", + "gender": "female", + "age": 42, + "address": { + "state": "Florida", + "city": "Bentonville" + } + }, + { + "id": 7397, + "name": "Maxine Pope", + "gender": "female", + "age": 66, + "address": { + "state": "North Dakota", + "city": "Dante" + } + }, + { + "id": 7398, + "name": "Alvarez Stout", + "gender": "male", + "age": 61, + "address": { + "state": "Kansas", + "city": "Carrizo" + } + }, + { + "id": 7399, + "name": "Gutierrez Mayo", + "gender": "male", + "age": 30, + "address": { + "state": "Oregon", + "city": "Cecilia" + } + }, + { + "id": 7400, + "name": "Frost Glover", + "gender": "male", + "age": 63, + "address": { + "state": "Idaho", + "city": "Tolu" + } + }, + { + "id": 7401, + "name": "Castro Goodman", + "gender": "male", + "age": 29, + "address": { + "state": "Kentucky", + "city": "Shaft" + } + }, + { + "id": 7402, + "name": "Arline Donovan", + "gender": "female", + "age": 50, + "address": { + "state": "Utah", + "city": "Moraida" + } + }, + { + "id": 7403, + "name": "Lindsay Butler", + "gender": "male", + "age": 70, + "address": { + "state": "New Jersey", + "city": "Temperanceville" + } + }, + { + "id": 7404, + "name": "Sheila King", + "gender": "female", + "age": 71, + "address": { + "state": "Pennsylvania", + "city": "Lawrence" + } + }, + { + "id": 7405, + "name": "Eve Barnett", + "gender": "female", + "age": 80, + "address": { + "state": "Maine", + "city": "Celeryville" + } + }, + { + "id": 7406, + "name": "Benita Brooks", + "gender": "female", + "age": 38, + "address": { + "state": "West Virginia", + "city": "Soham" + } + }, + { + "id": 7407, + "name": "Stafford Church", + "gender": "male", + "age": 41, + "address": { + "state": "Nevada", + "city": "Weeksville" + } + }, + { + "id": 7408, + "name": "Mcfarland Joseph", + "gender": "male", + "age": 46, + "address": { + "state": "Arkansas", + "city": "Maybell" + } + }, + { + "id": 7409, + "name": "Newman Cross", + "gender": "male", + "age": 19, + "address": { + "state": "Missouri", + "city": "Gilmore" + } + }, + { + "id": 7410, + "name": "Calhoun Gomez", + "gender": "male", + "age": 19, + "address": { + "state": "North Carolina", + "city": "Newkirk" + } + }, + { + "id": 7411, + "name": "Marta Chen", + "gender": "female", + "age": 24, + "address": { + "state": "Alaska", + "city": "Lithium" + } + }, + { + "id": 7412, + "name": "Corine Wells", + "gender": "female", + "age": 48, + "address": { + "state": "New Hampshire", + "city": "Ezel" + } + }, + { + "id": 7413, + "name": "Yang Myers", + "gender": "male", + "age": 57, + "address": { + "state": "New York", + "city": "Tooleville" + } + }, + { + "id": 7414, + "name": "Morgan Mccormick", + "gender": "male", + "age": 68, + "address": { + "state": "Ohio", + "city": "Stonybrook" + } + }, + { + "id": 7415, + "name": "Ashlee Thornton", + "gender": "female", + "age": 73, + "address": { + "state": "Wisconsin", + "city": "Richville" + } + }, + { + "id": 7416, + "name": "Carlson Crawford", + "gender": "male", + "age": 19, + "address": { + "state": "Hawaii", + "city": "Lafferty" + } + }, + { + "id": 7417, + "name": "Claudette Schmidt", + "gender": "female", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Baden" + } + }, + { + "id": 7418, + "name": "Mullen Valenzuela", + "gender": "male", + "age": 22, + "address": { + "state": "Michigan", + "city": "Zeba" + } + }, + { + "id": 7419, + "name": "Cervantes Simmons", + "gender": "male", + "age": 24, + "address": { + "state": "Delaware", + "city": "Fulford" + } + }, + { + "id": 7420, + "name": "Naomi Yates", + "gender": "female", + "age": 61, + "address": { + "state": "Washington", + "city": "Chapin" + } + }, + { + "id": 7421, + "name": "Hatfield Woods", + "gender": "male", + "age": 35, + "address": { + "state": "California", + "city": "Highland" + } + }, + { + "id": 7422, + "name": "Duke Wong", + "gender": "male", + "age": 69, + "address": { + "state": "South Dakota", + "city": "Cressey" + } + }, + { + "id": 7423, + "name": "Mills Conway", + "gender": "male", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Crumpler" + } + }, + { + "id": 7424, + "name": "Mcdaniel Hansen", + "gender": "male", + "age": 77, + "address": { + "state": "Florida", + "city": "Crown" + } + }, + { + "id": 7425, + "name": "Maritza Cote", + "gender": "female", + "age": 51, + "address": { + "state": "Rhode Island", + "city": "Sunnyside" + } + }, + { + "id": 7426, + "name": "Aida Mckinney", + "gender": "female", + "age": 56, + "address": { + "state": "Texas", + "city": "Oceola" + } + }, + { + "id": 7427, + "name": "Janie Dunn", + "gender": "female", + "age": 28, + "address": { + "state": "Maryland", + "city": "Naomi" + } + }, + { + "id": 7428, + "name": "Clements Huffman", + "gender": "male", + "age": 55, + "address": { + "state": "Minnesota", + "city": "Lemoyne" + } + }, + { + "id": 7429, + "name": "Irene Riddle", + "gender": "female", + "age": 77, + "address": { + "state": "Virginia", + "city": "Dellview" + } + }, + { + "id": 7430, + "name": "Ashley Meyer", + "gender": "male", + "age": 27, + "address": { + "state": "Georgia", + "city": "Cassel" + } + }, + { + "id": 7431, + "name": "Imogene Joyner", + "gender": "female", + "age": 32, + "address": { + "state": "Connecticut", + "city": "Bannock" + } + }, + { + "id": 7432, + "name": "Leola Prince", + "gender": "female", + "age": 77, + "address": { + "state": "North Dakota", + "city": "Kersey" + } + }, + { + "id": 7433, + "name": "Guzman Mueller", + "gender": "male", + "age": 67, + "address": { + "state": "Oklahoma", + "city": "Moquino" + } + }, + { + "id": 7434, + "name": "Leanne Warren", + "gender": "female", + "age": 60, + "address": { + "state": "Illinois", + "city": "Inkerman" + } + }, + { + "id": 7435, + "name": "Francis Hardy", + "gender": "female", + "age": 40, + "address": { + "state": "South Carolina", + "city": "Beyerville" + } + }, + { + "id": 7436, + "name": "Phillips Savage", + "gender": "male", + "age": 37, + "address": { + "state": "Arizona", + "city": "Gerton" + } + }, + { + "id": 7437, + "name": "Keisha Shaffer", + "gender": "female", + "age": 76, + "address": { + "state": "Montana", + "city": "Haring" + } + }, + { + "id": 7438, + "name": "Wallace Guy", + "gender": "male", + "age": 73, + "address": { + "state": "Wyoming", + "city": "Deseret" + } + }, + { + "id": 7439, + "name": "Meyers Rivers", + "gender": "male", + "age": 42, + "address": { + "state": "Alabama", + "city": "Wheatfields" + } + }, + { + "id": 7440, + "name": "Erna Dennis", + "gender": "female", + "age": 37, + "address": { + "state": "Kansas", + "city": "Enetai" + } + }, + { + "id": 7441, + "name": "Christi Lindsey", + "gender": "female", + "age": 29, + "address": { + "state": "Louisiana", + "city": "Mulberry" + } + }, + { + "id": 7442, + "name": "Peterson Haney", + "gender": "male", + "age": 61, + "address": { + "state": "Indiana", + "city": "Joes" + } + }, + { + "id": 7443, + "name": "Hardy Booker", + "gender": "male", + "age": 49, + "address": { + "state": "Massachusetts", + "city": "Verdi" + } + }, + { + "id": 7444, + "name": "Bowen Harris", + "gender": "male", + "age": 47, + "address": { + "state": "Vermont", + "city": "Davenport" + } + }, + { + "id": 7445, + "name": "Lindsey Duran", + "gender": "male", + "age": 39, + "address": { + "state": "Iowa", + "city": "Fredericktown" + } + }, + { + "id": 7446, + "name": "Horn Daniels", + "gender": "male", + "age": 25, + "address": { + "state": "Colorado", + "city": "Ladera" + } + }, + { + "id": 7447, + "name": "Saunders Harrell", + "gender": "male", + "age": 27, + "address": { + "state": "Tennessee", + "city": "Sexton" + } + }, + { + "id": 7448, + "name": "Lester Beard", + "gender": "male", + "age": 34, + "address": { + "state": "Louisiana", + "city": "Strykersville" + } + }, + { + "id": 7449, + "name": "Eunice Howe", + "gender": "female", + "age": 79, + "address": { + "state": "Iowa", + "city": "Alleghenyville" + } + }, + { + "id": 7450, + "name": "Tamara Mclean", + "gender": "female", + "age": 57, + "address": { + "state": "Hawaii", + "city": "Fowlerville" + } + }, + { + "id": 7451, + "name": "Zelma Cox", + "gender": "female", + "age": 18, + "address": { + "state": "Kentucky", + "city": "Gambrills" + } + }, + { + "id": 7452, + "name": "Maureen Sandoval", + "gender": "female", + "age": 37, + "address": { + "state": "Indiana", + "city": "Hiseville" + } + }, + { + "id": 7453, + "name": "Hester Flores", + "gender": "male", + "age": 81, + "address": { + "state": "North Carolina", + "city": "Tecolotito" + } + }, + { + "id": 7454, + "name": "Buckley Gilbert", + "gender": "male", + "age": 60, + "address": { + "state": "Virginia", + "city": "Newry" + } + }, + { + "id": 7455, + "name": "Amie Meyers", + "gender": "female", + "age": 77, + "address": { + "state": "South Dakota", + "city": "Kimmell" + } + }, + { + "id": 7456, + "name": "Michael Joyce", + "gender": "female", + "age": 33, + "address": { + "state": "Oklahoma", + "city": "Leola" + } + }, + { + "id": 7457, + "name": "Odonnell Adkins", + "gender": "male", + "age": 38, + "address": { + "state": "New Jersey", + "city": "Weeksville" + } + }, + { + "id": 7458, + "name": "Kane Copeland", + "gender": "male", + "age": 43, + "address": { + "state": "North Dakota", + "city": "Wacissa" + } + }, + { + "id": 7459, + "name": "Holcomb Ellis", + "gender": "male", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Clarktown" + } + }, + { + "id": 7460, + "name": "Delia Duffy", + "gender": "female", + "age": 44, + "address": { + "state": "Maine", + "city": "Orason" + } + }, + { + "id": 7461, + "name": "Mcknight Ruiz", + "gender": "male", + "age": 66, + "address": { + "state": "Massachusetts", + "city": "Grantville" + } + }, + { + "id": 7462, + "name": "Shaw Mason", + "gender": "male", + "age": 27, + "address": { + "state": "Mississippi", + "city": "Cumberland" + } + }, + { + "id": 7463, + "name": "Blackwell Salazar", + "gender": "male", + "age": 37, + "address": { + "state": "Arizona", + "city": "Barclay" + } + }, + { + "id": 7464, + "name": "Franks Mcintosh", + "gender": "male", + "age": 47, + "address": { + "state": "Nevada", + "city": "Movico" + } + }, + { + "id": 7465, + "name": "Iris Mcguire", + "gender": "female", + "age": 42, + "address": { + "state": "Washington", + "city": "Axis" + } + }, + { + "id": 7466, + "name": "Helga Reynolds", + "gender": "female", + "age": 56, + "address": { + "state": "West Virginia", + "city": "Joes" + } + }, + { + "id": 7467, + "name": "Margarita Wilkinson", + "gender": "female", + "age": 36, + "address": { + "state": "New Hampshire", + "city": "Wollochet" + } + }, + { + "id": 7468, + "name": "Erika Holland", + "gender": "female", + "age": 25, + "address": { + "state": "Wyoming", + "city": "Grapeview" + } + }, + { + "id": 7469, + "name": "Mcguire Bond", + "gender": "male", + "age": 60, + "address": { + "state": "New York", + "city": "Balm" + } + }, + { + "id": 7470, + "name": "Buchanan Hughes", + "gender": "male", + "age": 80, + "address": { + "state": "Wisconsin", + "city": "Tooleville" + } + }, + { + "id": 7471, + "name": "Aguirre Good", + "gender": "male", + "age": 21, + "address": { + "state": "Florida", + "city": "Kidder" + } + }, + { + "id": 7472, + "name": "Joann Bernard", + "gender": "female", + "age": 62, + "address": { + "state": "Rhode Island", + "city": "Brecon" + } + }, + { + "id": 7473, + "name": "Barry Mack", + "gender": "male", + "age": 56, + "address": { + "state": "Utah", + "city": "Nettie" + } + }, + { + "id": 7474, + "name": "Frye Chen", + "gender": "male", + "age": 59, + "address": { + "state": "Minnesota", + "city": "Elizaville" + } + }, + { + "id": 7475, + "name": "Good Stout", + "gender": "male", + "age": 25, + "address": { + "state": "Texas", + "city": "Drummond" + } + }, + { + "id": 7476, + "name": "Michele Baker", + "gender": "female", + "age": 56, + "address": { + "state": "Montana", + "city": "Gouglersville" + } + }, + { + "id": 7477, + "name": "Holland Herrera", + "gender": "male", + "age": 26, + "address": { + "state": "New Mexico", + "city": "Deseret" + } + }, + { + "id": 7478, + "name": "Bean Stark", + "gender": "male", + "age": 30, + "address": { + "state": "Michigan", + "city": "Elwood" + } + }, + { + "id": 7479, + "name": "Elinor Emerson", + "gender": "female", + "age": 28, + "address": { + "state": "Missouri", + "city": "Wildwood" + } + }, + { + "id": 7480, + "name": "Blake Hawkins", + "gender": "male", + "age": 77, + "address": { + "state": "South Carolina", + "city": "Beaulieu" + } + }, + { + "id": 7481, + "name": "Rhea Rogers", + "gender": "female", + "age": 46, + "address": { + "state": "Kansas", + "city": "Alfarata" + } + }, + { + "id": 7482, + "name": "Durham Lamb", + "gender": "male", + "age": 54, + "address": { + "state": "Vermont", + "city": "Oasis" + } + }, + { + "id": 7483, + "name": "Lorie Lara", + "gender": "female", + "age": 53, + "address": { + "state": "Georgia", + "city": "Emerald" + } + }, + { + "id": 7484, + "name": "Randi Suarez", + "gender": "female", + "age": 31, + "address": { + "state": "Delaware", + "city": "Unionville" + } + }, + { + "id": 7485, + "name": "Vang Frost", + "gender": "male", + "age": 34, + "address": { + "state": "Nebraska", + "city": "Gwynn" + } + }, + { + "id": 7486, + "name": "Julianne Ramirez", + "gender": "female", + "age": 32, + "address": { + "state": "Ohio", + "city": "Bladensburg" + } + }, + { + "id": 7487, + "name": "Tammy Walsh", + "gender": "female", + "age": 40, + "address": { + "state": "Arkansas", + "city": "Hamilton" + } + }, + { + "id": 7488, + "name": "Michelle Pollard", + "gender": "female", + "age": 42, + "address": { + "state": "Alabama", + "city": "Homeland" + } + }, + { + "id": 7489, + "name": "Ayers Sweet", + "gender": "male", + "age": 67, + "address": { + "state": "Idaho", + "city": "Riverton" + } + }, + { + "id": 7490, + "name": "Arnold Curtis", + "gender": "male", + "age": 64, + "address": { + "state": "Illinois", + "city": "Crucible" + } + }, + { + "id": 7491, + "name": "Jimmie Robertson", + "gender": "female", + "age": 43, + "address": { + "state": "Tennessee", + "city": "Floriston" + } + }, + { + "id": 7492, + "name": "Sharpe Jackson", + "gender": "male", + "age": 75, + "address": { + "state": "Alaska", + "city": "Mathews" + } + }, + { + "id": 7493, + "name": "Leach Ward", + "gender": "male", + "age": 69, + "address": { + "state": "Oregon", + "city": "Makena" + } + }, + { + "id": 7494, + "name": "Angeline Harris", + "gender": "female", + "age": 43, + "address": { + "state": "Connecticut", + "city": "Smeltertown" + } + }, + { + "id": 7495, + "name": "Langley Reyes", + "gender": "male", + "age": 71, + "address": { + "state": "California", + "city": "Dubois" + } + }, + { + "id": 7496, + "name": "Alejandra Humphrey", + "gender": "female", + "age": 38, + "address": { + "state": "Maryland", + "city": "Mapletown" + } + }, + { + "id": 7497, + "name": "Ray Grant", + "gender": "male", + "age": 44, + "address": { + "state": "Michigan", + "city": "Tilleda" + } + }, + { + "id": 7498, + "name": "Frederick Rojas", + "gender": "male", + "age": 62, + "address": { + "state": "Massachusetts", + "city": "Fresno" + } + }, + { + "id": 7499, + "name": "Ramona Kramer", + "gender": "female", + "age": 47, + "address": { + "state": "Oregon", + "city": "Riverton" + } + }, + { + "id": 7500, + "name": "Juanita Petty", + "gender": "female", + "age": 29, + "address": { + "state": "Missouri", + "city": "Escondida" + } + }, + { + "id": 7501, + "name": "Ochoa Best", + "gender": "male", + "age": 50, + "address": { + "state": "Wyoming", + "city": "Alfarata" + } + }, + { + "id": 7502, + "name": "Audrey Glover", + "gender": "female", + "age": 39, + "address": { + "state": "Louisiana", + "city": "Layhill" + } + }, + { + "id": 7503, + "name": "Small Camacho", + "gender": "male", + "age": 17, + "address": { + "state": "Virginia", + "city": "Falmouth" + } + }, + { + "id": 7504, + "name": "Bridges Holmes", + "gender": "male", + "age": 50, + "address": { + "state": "Washington", + "city": "Fontanelle" + } + }, + { + "id": 7505, + "name": "Hodges Hardy", + "gender": "male", + "age": 42, + "address": { + "state": "Hawaii", + "city": "Bison" + } + }, + { + "id": 7506, + "name": "Avila Wilder", + "gender": "male", + "age": 35, + "address": { + "state": "Connecticut", + "city": "Rutherford" + } + }, + { + "id": 7507, + "name": "Nannie Russell", + "gender": "female", + "age": 24, + "address": { + "state": "New York", + "city": "Churchill" + } + }, + { + "id": 7508, + "name": "Candace Mcgee", + "gender": "female", + "age": 74, + "address": { + "state": "New Jersey", + "city": "Dorneyville" + } + }, + { + "id": 7509, + "name": "Stokes Head", + "gender": "male", + "age": 44, + "address": { + "state": "Florida", + "city": "Kent" + } + }, + { + "id": 7510, + "name": "Fitzgerald Ingram", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Golconda" + } + }, + { + "id": 7511, + "name": "Rosie Ortega", + "gender": "female", + "age": 78, + "address": { + "state": "Kentucky", + "city": "Homeland" + } + }, + { + "id": 7512, + "name": "Nieves Sparks", + "gender": "male", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Edinburg" + } + }, + { + "id": 7513, + "name": "Gena Gillespie", + "gender": "female", + "age": 66, + "address": { + "state": "New Hampshire", + "city": "Winchester" + } + }, + { + "id": 7514, + "name": "Hutchinson Burris", + "gender": "male", + "age": 77, + "address": { + "state": "Indiana", + "city": "Linganore" + } + }, + { + "id": 7515, + "name": "Caroline Fitzgerald", + "gender": "female", + "age": 82, + "address": { + "state": "Alaska", + "city": "Cedarville" + } + }, + { + "id": 7516, + "name": "Ronda Watts", + "gender": "female", + "age": 70, + "address": { + "state": "Ohio", + "city": "Mulberry" + } + }, + { + "id": 7517, + "name": "Oconnor Howard", + "gender": "male", + "age": 27, + "address": { + "state": "California", + "city": "Linwood" + } + }, + { + "id": 7518, + "name": "House Mendoza", + "gender": "male", + "age": 31, + "address": { + "state": "Mississippi", + "city": "Deltaville" + } + }, + { + "id": 7519, + "name": "Queen Robbins", + "gender": "female", + "age": 30, + "address": { + "state": "New Mexico", + "city": "Brecon" + } + }, + { + "id": 7520, + "name": "Margie Guerrero", + "gender": "female", + "age": 49, + "address": { + "state": "South Dakota", + "city": "Ferney" + } + }, + { + "id": 7521, + "name": "Gaines Conner", + "gender": "male", + "age": 38, + "address": { + "state": "Kansas", + "city": "Stonybrook" + } + }, + { + "id": 7522, + "name": "Teresa Dejesus", + "gender": "female", + "age": 45, + "address": { + "state": "Vermont", + "city": "Nutrioso" + } + }, + { + "id": 7523, + "name": "Ebony Mayer", + "gender": "female", + "age": 71, + "address": { + "state": "Illinois", + "city": "Elfrida" + } + }, + { + "id": 7524, + "name": "Johnnie Roy", + "gender": "female", + "age": 24, + "address": { + "state": "Idaho", + "city": "Wilsonia" + } + }, + { + "id": 7525, + "name": "Alyssa Hutchinson", + "gender": "female", + "age": 49, + "address": { + "state": "Tennessee", + "city": "Hegins" + } + }, + { + "id": 7526, + "name": "Minerva Calderon", + "gender": "female", + "age": 80, + "address": { + "state": "Wisconsin", + "city": "Sidman" + } + }, + { + "id": 7527, + "name": "Beard Estes", + "gender": "male", + "age": 31, + "address": { + "state": "North Carolina", + "city": "Ogema" + } + }, + { + "id": 7528, + "name": "Olga Aguilar", + "gender": "female", + "age": 56, + "address": { + "state": "Delaware", + "city": "Chumuckla" + } + }, + { + "id": 7529, + "name": "Melva Fitzpatrick", + "gender": "female", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Wakulla" + } + }, + { + "id": 7530, + "name": "Hebert Mcmahon", + "gender": "male", + "age": 25, + "address": { + "state": "Rhode Island", + "city": "Ellerslie" + } + }, + { + "id": 7531, + "name": "Kate Simon", + "gender": "female", + "age": 74, + "address": { + "state": "Arizona", + "city": "Gerton" + } + }, + { + "id": 7532, + "name": "Fischer Savage", + "gender": "male", + "age": 44, + "address": { + "state": "Minnesota", + "city": "Soudan" + } + }, + { + "id": 7533, + "name": "Eve Mays", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Imperial" + } + }, + { + "id": 7534, + "name": "Rodriquez Keith", + "gender": "male", + "age": 79, + "address": { + "state": "Texas", + "city": "Durham" + } + }, + { + "id": 7535, + "name": "Ruthie Duran", + "gender": "female", + "age": 33, + "address": { + "state": "Georgia", + "city": "Cuylerville" + } + }, + { + "id": 7536, + "name": "Wood Burke", + "gender": "male", + "age": 48, + "address": { + "state": "Montana", + "city": "Lowgap" + } + }, + { + "id": 7537, + "name": "Guthrie Mcclain", + "gender": "male", + "age": 45, + "address": { + "state": "Colorado", + "city": "Chalfant" + } + }, + { + "id": 7538, + "name": "Travis Carson", + "gender": "male", + "age": 66, + "address": { + "state": "Utah", + "city": "Lisco" + } + }, + { + "id": 7539, + "name": "Liz Bradley", + "gender": "female", + "age": 17, + "address": { + "state": "Arkansas", + "city": "Salix" + } + }, + { + "id": 7540, + "name": "Cleveland Hines", + "gender": "male", + "age": 63, + "address": { + "state": "South Carolina", + "city": "Shawmut" + } + }, + { + "id": 7541, + "name": "Penelope Hays", + "gender": "female", + "age": 68, + "address": { + "state": "Maryland", + "city": "Vowinckel" + } + }, + { + "id": 7542, + "name": "Patti Beck", + "gender": "female", + "age": 60, + "address": { + "state": "Iowa", + "city": "Shindler" + } + }, + { + "id": 7543, + "name": "Peterson Paul", + "gender": "male", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Macdona" + } + }, + { + "id": 7544, + "name": "Ruth Mooney", + "gender": "female", + "age": 27, + "address": { + "state": "Maine", + "city": "Shasta" + } + }, + { + "id": 7545, + "name": "Patsy Lyons", + "gender": "female", + "age": 25, + "address": { + "state": "Nevada", + "city": "Summerfield" + } + }, + { + "id": 7546, + "name": "Obrien Robinson", + "gender": "male", + "age": 47, + "address": { + "state": "North Dakota", + "city": "Gambrills" + } + }, + { + "id": 7547, + "name": "Oneil Joyce", + "gender": "male", + "age": 46, + "address": { + "state": "West Virginia", + "city": "Tonopah" + } + }, + { + "id": 7548, + "name": "Emily Everett", + "gender": "female", + "age": 36, + "address": { + "state": "Indiana", + "city": "Cornfields" + } + }, + { + "id": 7549, + "name": "Monique Delgado", + "gender": "female", + "age": 31, + "address": { + "state": "Alaska", + "city": "Rossmore" + } + }, + { + "id": 7550, + "name": "Cabrera Bowers", + "gender": "male", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Olney" + } + }, + { + "id": 7551, + "name": "Davenport Miller", + "gender": "male", + "age": 60, + "address": { + "state": "Oregon", + "city": "Woodburn" + } + }, + { + "id": 7552, + "name": "Ola Kramer", + "gender": "female", + "age": 61, + "address": { + "state": "New York", + "city": "Crisman" + } + }, + { + "id": 7553, + "name": "Vance Shaw", + "gender": "male", + "age": 17, + "address": { + "state": "Washington", + "city": "Esmont" + } + }, + { + "id": 7554, + "name": "Mccarty Guthrie", + "gender": "male", + "age": 54, + "address": { + "state": "Mississippi", + "city": "Echo" + } + }, + { + "id": 7555, + "name": "Irma Berg", + "gender": "female", + "age": 68, + "address": { + "state": "New Hampshire", + "city": "Elbert" + } + }, + { + "id": 7556, + "name": "Tasha Sawyer", + "gender": "female", + "age": 81, + "address": { + "state": "Idaho", + "city": "Darbydale" + } + }, + { + "id": 7557, + "name": "Roslyn Knox", + "gender": "female", + "age": 81, + "address": { + "state": "Nevada", + "city": "Geyserville" + } + }, + { + "id": 7558, + "name": "Sasha Wheeler", + "gender": "female", + "age": 35, + "address": { + "state": "South Carolina", + "city": "Thermal" + } + }, + { + "id": 7559, + "name": "Terrie Waller", + "gender": "female", + "age": 21, + "address": { + "state": "Oklahoma", + "city": "Beaverdale" + } + }, + { + "id": 7560, + "name": "Espinoza Walls", + "gender": "male", + "age": 73, + "address": { + "state": "Minnesota", + "city": "Morningside" + } + }, + { + "id": 7561, + "name": "Carolina Hebert", + "gender": "female", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Whipholt" + } + }, + { + "id": 7562, + "name": "Shaw Ferrell", + "gender": "male", + "age": 63, + "address": { + "state": "North Carolina", + "city": "Elliston" + } + }, + { + "id": 7563, + "name": "Cunningham Gordon", + "gender": "male", + "age": 63, + "address": { + "state": "Rhode Island", + "city": "Gardiner" + } + }, + { + "id": 7564, + "name": "Webster Ortiz", + "gender": "male", + "age": 49, + "address": { + "state": "Texas", + "city": "Waverly" + } + }, + { + "id": 7565, + "name": "Levy Leach", + "gender": "male", + "age": 64, + "address": { + "state": "Michigan", + "city": "Savannah" + } + }, + { + "id": 7566, + "name": "Skinner Greene", + "gender": "male", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Tuskahoma" + } + }, + { + "id": 7567, + "name": "Maynard Thompson", + "gender": "male", + "age": 20, + "address": { + "state": "Arkansas", + "city": "Tooleville" + } + }, + { + "id": 7568, + "name": "Brooks Vang", + "gender": "male", + "age": 36, + "address": { + "state": "Maryland", + "city": "Nadine" + } + }, + { + "id": 7569, + "name": "Davidson Barber", + "gender": "male", + "age": 23, + "address": { + "state": "Kansas", + "city": "Cloverdale" + } + }, + { + "id": 7570, + "name": "Lily Powers", + "gender": "female", + "age": 42, + "address": { + "state": "Arizona", + "city": "Connerton" + } + }, + { + "id": 7571, + "name": "Paula Francis", + "gender": "female", + "age": 37, + "address": { + "state": "Kentucky", + "city": "Chical" + } + }, + { + "id": 7572, + "name": "Antoinette Buchanan", + "gender": "female", + "age": 35, + "address": { + "state": "Alabama", + "city": "Vallonia" + } + }, + { + "id": 7573, + "name": "Verna Mcmahon", + "gender": "female", + "age": 21, + "address": { + "state": "Illinois", + "city": "Boykin" + } + }, + { + "id": 7574, + "name": "Saunders Vaughan", + "gender": "male", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Caledonia" + } + }, + { + "id": 7575, + "name": "Lucile Slater", + "gender": "female", + "age": 30, + "address": { + "state": "Connecticut", + "city": "Homeworth" + } + }, + { + "id": 7576, + "name": "Spencer Ramos", + "gender": "male", + "age": 21, + "address": { + "state": "Wyoming", + "city": "Mapletown" + } + }, + { + "id": 7577, + "name": "Klein Gill", + "gender": "male", + "age": 54, + "address": { + "state": "Georgia", + "city": "Conway" + } + }, + { + "id": 7578, + "name": "Hendricks Hodge", + "gender": "male", + "age": 70, + "address": { + "state": "Vermont", + "city": "Freetown" + } + }, + { + "id": 7579, + "name": "Katrina Acosta", + "gender": "female", + "age": 42, + "address": { + "state": "California", + "city": "Weedville" + } + }, + { + "id": 7580, + "name": "Michelle Bowen", + "gender": "female", + "age": 40, + "address": { + "state": "Colorado", + "city": "Clay" + } + }, + { + "id": 7581, + "name": "Bruce Hansen", + "gender": "male", + "age": 44, + "address": { + "state": "Ohio", + "city": "Elrama" + } + }, + { + "id": 7582, + "name": "Battle Moreno", + "gender": "male", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Martinez" + } + }, + { + "id": 7583, + "name": "Huff Dillon", + "gender": "male", + "age": 24, + "address": { + "state": "Florida", + "city": "Kempton" + } + }, + { + "id": 7584, + "name": "Ashley Warren", + "gender": "male", + "age": 77, + "address": { + "state": "South Dakota", + "city": "Greensburg" + } + }, + { + "id": 7585, + "name": "Rowland Kent", + "gender": "male", + "age": 79, + "address": { + "state": "Maine", + "city": "Darrtown" + } + }, + { + "id": 7586, + "name": "Woods Stuart", + "gender": "male", + "age": 39, + "address": { + "state": "Iowa", + "city": "Levant" + } + }, + { + "id": 7587, + "name": "Gallegos Roberts", + "gender": "male", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Starks" + } + }, + { + "id": 7588, + "name": "Turner Stein", + "gender": "male", + "age": 81, + "address": { + "state": "Wisconsin", + "city": "Cutter" + } + }, + { + "id": 7589, + "name": "Blackwell Benton", + "gender": "male", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Townsend" + } + }, + { + "id": 7590, + "name": "Neal Bradley", + "gender": "male", + "age": 42, + "address": { + "state": "Hawaii", + "city": "Freelandville" + } + }, + { + "id": 7591, + "name": "Paulette Wong", + "gender": "female", + "age": 56, + "address": { + "state": "Virginia", + "city": "Jacumba" + } + }, + { + "id": 7592, + "name": "Nolan Trujillo", + "gender": "male", + "age": 63, + "address": { + "state": "Missouri", + "city": "Springdale" + } + }, + { + "id": 7593, + "name": "Debora Estes", + "gender": "female", + "age": 57, + "address": { + "state": "Delaware", + "city": "Leeper" + } + }, + { + "id": 7594, + "name": "Lindsay Davenport", + "gender": "male", + "age": 55, + "address": { + "state": "Utah", + "city": "Kimmell" + } + }, + { + "id": 7595, + "name": "Sandra Pate", + "gender": "female", + "age": 17, + "address": { + "state": "Wyoming", + "city": "Idamay" + } + }, + { + "id": 7596, + "name": "Georgette Ray", + "gender": "female", + "age": 48, + "address": { + "state": "California", + "city": "Waukeenah" + } + }, + { + "id": 7597, + "name": "Latoya Warner", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Efland" + } + }, + { + "id": 7598, + "name": "Wood Cummings", + "gender": "male", + "age": 61, + "address": { + "state": "Tennessee", + "city": "Jamestown" + } + }, + { + "id": 7599, + "name": "Reynolds Carter", + "gender": "male", + "age": 19, + "address": { + "state": "Delaware", + "city": "Fowlerville" + } + }, + { + "id": 7600, + "name": "Gabriela Chambers", + "gender": "female", + "age": 33, + "address": { + "state": "Alabama", + "city": "Romeville" + } + }, + { + "id": 7601, + "name": "Claudia Gibbs", + "gender": "female", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Tioga" + } + }, + { + "id": 7602, + "name": "Curtis Fry", + "gender": "male", + "age": 64, + "address": { + "state": "Maine", + "city": "Gambrills" + } + }, + { + "id": 7603, + "name": "Dillard Long", + "gender": "male", + "age": 80, + "address": { + "state": "Michigan", + "city": "Independence" + } + }, + { + "id": 7604, + "name": "Tasha Clemons", + "gender": "female", + "age": 26, + "address": { + "state": "West Virginia", + "city": "Hessville" + } + }, + { + "id": 7605, + "name": "Lola Sandoval", + "gender": "female", + "age": 54, + "address": { + "state": "Connecticut", + "city": "Thornport" + } + }, + { + "id": 7606, + "name": "Tabitha Puckett", + "gender": "female", + "age": 76, + "address": { + "state": "Illinois", + "city": "Tivoli" + } + }, + { + "id": 7607, + "name": "Candy Fitzgerald", + "gender": "female", + "age": 75, + "address": { + "state": "Florida", + "city": "Cornfields" + } + }, + { + "id": 7608, + "name": "Alisa Roach", + "gender": "female", + "age": 64, + "address": { + "state": "Wisconsin", + "city": "Aberdeen" + } + }, + { + "id": 7609, + "name": "Aileen Henderson", + "gender": "female", + "age": 41, + "address": { + "state": "Georgia", + "city": "Greer" + } + }, + { + "id": 7610, + "name": "Odom Burt", + "gender": "male", + "age": 17, + "address": { + "state": "Massachusetts", + "city": "Vicksburg" + } + }, + { + "id": 7611, + "name": "Tamika Lindsay", + "gender": "female", + "age": 39, + "address": { + "state": "New York", + "city": "Emison" + } + }, + { + "id": 7612, + "name": "Vega Huff", + "gender": "male", + "age": 43, + "address": { + "state": "Kansas", + "city": "Durham" + } + }, + { + "id": 7613, + "name": "Darla Macdonald", + "gender": "female", + "age": 53, + "address": { + "state": "Maryland", + "city": "Allentown" + } + }, + { + "id": 7614, + "name": "Chandler Fletcher", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Alleghenyville" + } + }, + { + "id": 7615, + "name": "Catalina Cobb", + "gender": "female", + "age": 56, + "address": { + "state": "Rhode Island", + "city": "Belvoir" + } + }, + { + "id": 7616, + "name": "Villarreal Morin", + "gender": "male", + "age": 72, + "address": { + "state": "Alaska", + "city": "Wright" + } + }, + { + "id": 7617, + "name": "Harriett Hodge", + "gender": "female", + "age": 36, + "address": { + "state": "New Jersey", + "city": "Dalton" + } + }, + { + "id": 7618, + "name": "Sweet Haley", + "gender": "male", + "age": 21, + "address": { + "state": "Missouri", + "city": "Enoree" + } + }, + { + "id": 7619, + "name": "Britt Wong", + "gender": "male", + "age": 42, + "address": { + "state": "South Dakota", + "city": "Sisquoc" + } + }, + { + "id": 7620, + "name": "Beasley Eaton", + "gender": "male", + "age": 40, + "address": { + "state": "Vermont", + "city": "Lowgap" + } + }, + { + "id": 7621, + "name": "Adeline Stanley", + "gender": "female", + "age": 48, + "address": { + "state": "Arizona", + "city": "Catherine" + } + }, + { + "id": 7622, + "name": "Valentine Sheppard", + "gender": "male", + "age": 76, + "address": { + "state": "Virginia", + "city": "Calvary" + } + }, + { + "id": 7623, + "name": "Lucile Villarreal", + "gender": "female", + "age": 47, + "address": { + "state": "South Carolina", + "city": "Cumminsville" + } + }, + { + "id": 7624, + "name": "Jerry Love", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Wakulla" + } + }, + { + "id": 7625, + "name": "Gail Beasley", + "gender": "female", + "age": 23, + "address": { + "state": "Mississippi", + "city": "Kipp" + } + }, + { + "id": 7626, + "name": "Karina Stone", + "gender": "female", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Vernon" + } + }, + { + "id": 7627, + "name": "Jones Clements", + "gender": "male", + "age": 67, + "address": { + "state": "Nevada", + "city": "Osmond" + } + }, + { + "id": 7628, + "name": "Holcomb Frank", + "gender": "male", + "age": 30, + "address": { + "state": "Idaho", + "city": "Alamo" + } + }, + { + "id": 7629, + "name": "Butler Massey", + "gender": "male", + "age": 32, + "address": { + "state": "Minnesota", + "city": "Westboro" + } + }, + { + "id": 7630, + "name": "Hart Adams", + "gender": "male", + "age": 31, + "address": { + "state": "Colorado", + "city": "Waumandee" + } + }, + { + "id": 7631, + "name": "Armstrong Burke", + "gender": "male", + "age": 19, + "address": { + "state": "Louisiana", + "city": "Nile" + } + }, + { + "id": 7632, + "name": "Alberta Nguyen", + "gender": "female", + "age": 27, + "address": { + "state": "Nebraska", + "city": "Gulf" + } + }, + { + "id": 7633, + "name": "Head Conway", + "gender": "male", + "age": 59, + "address": { + "state": "Indiana", + "city": "Veyo" + } + }, + { + "id": 7634, + "name": "Sweeney Wolfe", + "gender": "male", + "age": 57, + "address": { + "state": "Washington", + "city": "Hall" + } + }, + { + "id": 7635, + "name": "Elba Simon", + "gender": "female", + "age": 29, + "address": { + "state": "Oregon", + "city": "Norfolk" + } + }, + { + "id": 7636, + "name": "Sasha Berry", + "gender": "female", + "age": 49, + "address": { + "state": "Kentucky", + "city": "Taft" + } + }, + { + "id": 7637, + "name": "Susie Franco", + "gender": "female", + "age": 71, + "address": { + "state": "Iowa", + "city": "Greenwich" + } + }, + { + "id": 7638, + "name": "Lawrence Wood", + "gender": "male", + "age": 51, + "address": { + "state": "North Carolina", + "city": "Kent" + } + }, + { + "id": 7639, + "name": "Lewis Cline", + "gender": "male", + "age": 36, + "address": { + "state": "Texas", + "city": "Cannondale" + } + }, + { + "id": 7640, + "name": "Griffin Lindsey", + "gender": "male", + "age": 19, + "address": { + "state": "Ohio", + "city": "Cresaptown" + } + }, + { + "id": 7641, + "name": "Yvonne Lara", + "gender": "female", + "age": 35, + "address": { + "state": "North Dakota", + "city": "Cavalero" + } + }, + { + "id": 7642, + "name": "Herring Sutton", + "gender": "male", + "age": 42, + "address": { + "state": "Montana", + "city": "Dubois" + } + }, + { + "id": 7643, + "name": "Silva Justice", + "gender": "male", + "age": 22, + "address": { + "state": "Oklahoma", + "city": "Curtice" + } + }, + { + "id": 7644, + "name": "Adrian Wilkins", + "gender": "female", + "age": 66, + "address": { + "state": "Utah", + "city": "Eggertsville" + } + }, + { + "id": 7645, + "name": "Bentley Baker", + "gender": "male", + "age": 53, + "address": { + "state": "California", + "city": "Greer" + } + }, + { + "id": 7646, + "name": "Reid Hoffman", + "gender": "male", + "age": 22, + "address": { + "state": "New Jersey", + "city": "Dundee" + } + }, + { + "id": 7647, + "name": "Noelle Dillon", + "gender": "female", + "age": 73, + "address": { + "state": "Arkansas", + "city": "Watchtower" + } + }, + { + "id": 7648, + "name": "Dina Burt", + "gender": "female", + "age": 28, + "address": { + "state": "Texas", + "city": "Madaket" + } + }, + { + "id": 7649, + "name": "Casandra Martinez", + "gender": "female", + "age": 72, + "address": { + "state": "Georgia", + "city": "Caberfae" + } + }, + { + "id": 7650, + "name": "Rodgers Sears", + "gender": "male", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Darrtown" + } + }, + { + "id": 7651, + "name": "Katina Castro", + "gender": "female", + "age": 39, + "address": { + "state": "Maine", + "city": "National" + } + }, + { + "id": 7652, + "name": "Oconnor Williams", + "gender": "male", + "age": 66, + "address": { + "state": "Missouri", + "city": "Grandview" + } + }, + { + "id": 7653, + "name": "Leona Allen", + "gender": "female", + "age": 57, + "address": { + "state": "West Virginia", + "city": "Roosevelt" + } + }, + { + "id": 7654, + "name": "Vazquez Riggs", + "gender": "male", + "age": 66, + "address": { + "state": "Florida", + "city": "Eagleville" + } + }, + { + "id": 7655, + "name": "Margery Strong", + "gender": "female", + "age": 27, + "address": { + "state": "Kansas", + "city": "Vicksburg" + } + }, + { + "id": 7656, + "name": "Lorna Cruz", + "gender": "female", + "age": 31, + "address": { + "state": "Minnesota", + "city": "Groveville" + } + }, + { + "id": 7657, + "name": "Bolton Saunders", + "gender": "male", + "age": 27, + "address": { + "state": "Virginia", + "city": "Dorneyville" + } + }, + { + "id": 7658, + "name": "Eliza Malone", + "gender": "female", + "age": 42, + "address": { + "state": "Idaho", + "city": "Beechmont" + } + }, + { + "id": 7659, + "name": "Opal Fletcher", + "gender": "female", + "age": 23, + "address": { + "state": "Maryland", + "city": "Stonybrook" + } + }, + { + "id": 7660, + "name": "Tricia Manning", + "gender": "female", + "age": 46, + "address": { + "state": "Connecticut", + "city": "Broadlands" + } + }, + { + "id": 7661, + "name": "Drake Ortega", + "gender": "male", + "age": 49, + "address": { + "state": "Massachusetts", + "city": "Robinette" + } + }, + { + "id": 7662, + "name": "Shauna Lawson", + "gender": "female", + "age": 73, + "address": { + "state": "Louisiana", + "city": "Oneida" + } + }, + { + "id": 7663, + "name": "Lindsay Olson", + "gender": "female", + "age": 26, + "address": { + "state": "Rhode Island", + "city": "Dellview" + } + }, + { + "id": 7664, + "name": "Rollins Taylor", + "gender": "male", + "age": 34, + "address": { + "state": "Nebraska", + "city": "Gibsonia" + } + }, + { + "id": 7665, + "name": "Burns Briggs", + "gender": "male", + "age": 22, + "address": { + "state": "Mississippi", + "city": "Bowden" + } + }, + { + "id": 7666, + "name": "Hicks Holloway", + "gender": "male", + "age": 71, + "address": { + "state": "New Hampshire", + "city": "Leland" + } + }, + { + "id": 7667, + "name": "Patty Hunt", + "gender": "female", + "age": 45, + "address": { + "state": "South Dakota", + "city": "Chautauqua" + } + }, + { + "id": 7668, + "name": "Maude Burch", + "gender": "female", + "age": 18, + "address": { + "state": "Oklahoma", + "city": "Vandiver" + } + }, + { + "id": 7669, + "name": "Ware Mcbride", + "gender": "male", + "age": 43, + "address": { + "state": "Arizona", + "city": "Dale" + } + }, + { + "id": 7670, + "name": "Jessica Alvarado", + "gender": "female", + "age": 61, + "address": { + "state": "New York", + "city": "Herbster" + } + }, + { + "id": 7671, + "name": "Freda Drake", + "gender": "female", + "age": 41, + "address": { + "state": "Colorado", + "city": "Thynedale" + } + }, + { + "id": 7672, + "name": "Angelica Gregory", + "gender": "female", + "age": 34, + "address": { + "state": "New Mexico", + "city": "Hiko" + } + }, + { + "id": 7673, + "name": "Tyler Kane", + "gender": "male", + "age": 42, + "address": { + "state": "Iowa", + "city": "Robinson" + } + }, + { + "id": 7674, + "name": "Webster Hicks", + "gender": "male", + "age": 48, + "address": { + "state": "Alaska", + "city": "Limestone" + } + }, + { + "id": 7675, + "name": "Guadalupe Mathis", + "gender": "female", + "age": 55, + "address": { + "state": "Hawaii", + "city": "Waikele" + } + }, + { + "id": 7676, + "name": "Polly Gamble", + "gender": "female", + "age": 68, + "address": { + "state": "Nevada", + "city": "Dola" + } + }, + { + "id": 7677, + "name": "Black Marshall", + "gender": "male", + "age": 39, + "address": { + "state": "Vermont", + "city": "Blodgett" + } + }, + { + "id": 7678, + "name": "Stephanie Richmond", + "gender": "female", + "age": 30, + "address": { + "state": "Kentucky", + "city": "Forbestown" + } + }, + { + "id": 7679, + "name": "Lynch Miller", + "gender": "male", + "age": 73, + "address": { + "state": "Washington", + "city": "Geyserville" + } + }, + { + "id": 7680, + "name": "Bowen Davenport", + "gender": "male", + "age": 76, + "address": { + "state": "Wyoming", + "city": "Orviston" + } + }, + { + "id": 7681, + "name": "Mccarty Mayer", + "gender": "male", + "age": 59, + "address": { + "state": "Ohio", + "city": "Jamestown" + } + }, + { + "id": 7682, + "name": "Fry Patterson", + "gender": "male", + "age": 47, + "address": { + "state": "Michigan", + "city": "Cochranville" + } + }, + { + "id": 7683, + "name": "Norris Flynn", + "gender": "male", + "age": 55, + "address": { + "state": "Delaware", + "city": "Finderne" + } + }, + { + "id": 7684, + "name": "Tammy Kirkland", + "gender": "female", + "age": 64, + "address": { + "state": "Montana", + "city": "Walland" + } + }, + { + "id": 7685, + "name": "Roberson Golden", + "gender": "male", + "age": 26, + "address": { + "state": "North Dakota", + "city": "Chaparrito" + } + }, + { + "id": 7686, + "name": "Gonzalez Mcneil", + "gender": "male", + "age": 24, + "address": { + "state": "Wisconsin", + "city": "Saranap" + } + }, + { + "id": 7687, + "name": "Reese Wood", + "gender": "male", + "age": 30, + "address": { + "state": "Oregon", + "city": "Oretta" + } + }, + { + "id": 7688, + "name": "Wright Monroe", + "gender": "male", + "age": 57, + "address": { + "state": "Pennsylvania", + "city": "Epworth" + } + }, + { + "id": 7689, + "name": "Guy Cantu", + "gender": "male", + "age": 25, + "address": { + "state": "Tennessee", + "city": "Advance" + } + }, + { + "id": 7690, + "name": "Melissa Harmon", + "gender": "female", + "age": 81, + "address": { + "state": "Illinois", + "city": "Corriganville" + } + }, + { + "id": 7691, + "name": "Cannon Moon", + "gender": "male", + "age": 50, + "address": { + "state": "Indiana", + "city": "Waterloo" + } + }, + { + "id": 7692, + "name": "Benson Vincent", + "gender": "male", + "age": 49, + "address": { + "state": "South Carolina", + "city": "Summerset" + } + }, + { + "id": 7693, + "name": "Marci Davidson", + "gender": "female", + "age": 34, + "address": { + "state": "Utah", + "city": "Caron" + } + }, + { + "id": 7694, + "name": "Rhea Strickland", + "gender": "female", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Rivera" + } + }, + { + "id": 7695, + "name": "Holly Meadows", + "gender": "female", + "age": 64, + "address": { + "state": "Virginia", + "city": "Wescosville" + } + }, + { + "id": 7696, + "name": "Carson Hammond", + "gender": "male", + "age": 55, + "address": { + "state": "Missouri", + "city": "Kohatk" + } + }, + { + "id": 7697, + "name": "Adriana Fuller", + "gender": "female", + "age": 58, + "address": { + "state": "Delaware", + "city": "Canoochee" + } + }, + { + "id": 7698, + "name": "Wheeler Hernandez", + "gender": "male", + "age": 42, + "address": { + "state": "North Dakota", + "city": "Defiance" + } + }, + { + "id": 7699, + "name": "Wilma Mercer", + "gender": "female", + "age": 64, + "address": { + "state": "Massachusetts", + "city": "Curtice" + } + }, + { + "id": 7700, + "name": "Traci Glover", + "gender": "female", + "age": 49, + "address": { + "state": "Arkansas", + "city": "Wiscon" + } + }, + { + "id": 7701, + "name": "Tammy Stephens", + "gender": "female", + "age": 57, + "address": { + "state": "West Virginia", + "city": "Stevens" + } + }, + { + "id": 7702, + "name": "Kelley Mccormick", + "gender": "female", + "age": 29, + "address": { + "state": "Georgia", + "city": "Edenburg" + } + }, + { + "id": 7703, + "name": "Susan Gordon", + "gender": "female", + "age": 58, + "address": { + "state": "New Jersey", + "city": "Choctaw" + } + }, + { + "id": 7704, + "name": "Adeline Kemp", + "gender": "female", + "age": 80, + "address": { + "state": "Tennessee", + "city": "Interlochen" + } + }, + { + "id": 7705, + "name": "Coleman Farley", + "gender": "male", + "age": 37, + "address": { + "state": "New Mexico", + "city": "Thomasville" + } + }, + { + "id": 7706, + "name": "Sandy Bennett", + "gender": "female", + "age": 31, + "address": { + "state": "Florida", + "city": "Winston" + } + }, + { + "id": 7707, + "name": "Kathy Banks", + "gender": "female", + "age": 38, + "address": { + "state": "Alaska", + "city": "Skyland" + } + }, + { + "id": 7708, + "name": "Hanson Lancaster", + "gender": "male", + "age": 66, + "address": { + "state": "Texas", + "city": "Valle" + } + }, + { + "id": 7709, + "name": "Pittman Wiley", + "gender": "male", + "age": 68, + "address": { + "state": "Illinois", + "city": "Strong" + } + }, + { + "id": 7710, + "name": "Darlene Leach", + "gender": "female", + "age": 56, + "address": { + "state": "Colorado", + "city": "Madaket" + } + }, + { + "id": 7711, + "name": "Ida Sargent", + "gender": "female", + "age": 57, + "address": { + "state": "Indiana", + "city": "Foscoe" + } + }, + { + "id": 7712, + "name": "David Fernandez", + "gender": "male", + "age": 78, + "address": { + "state": "Nevada", + "city": "Fingerville" + } + }, + { + "id": 7713, + "name": "Bennett Kaufman", + "gender": "male", + "age": 57, + "address": { + "state": "Oregon", + "city": "Ruckersville" + } + }, + { + "id": 7714, + "name": "Twila Bean", + "gender": "female", + "age": 78, + "address": { + "state": "Wyoming", + "city": "Caroline" + } + }, + { + "id": 7715, + "name": "Nichols Dickerson", + "gender": "male", + "age": 35, + "address": { + "state": "Nebraska", + "city": "Day" + } + }, + { + "id": 7716, + "name": "Medina Richardson", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Wells" + } + }, + { + "id": 7717, + "name": "Julie Hays", + "gender": "female", + "age": 20, + "address": { + "state": "Vermont", + "city": "Trail" + } + }, + { + "id": 7718, + "name": "Carroll Morrow", + "gender": "male", + "age": 59, + "address": { + "state": "Connecticut", + "city": "Bynum" + } + }, + { + "id": 7719, + "name": "Consuelo Hurley", + "gender": "female", + "age": 74, + "address": { + "state": "Arizona", + "city": "Lupton" + } + }, + { + "id": 7720, + "name": "Everett Valenzuela", + "gender": "male", + "age": 40, + "address": { + "state": "Wisconsin", + "city": "Lopezo" + } + }, + { + "id": 7721, + "name": "Avila Rios", + "gender": "male", + "age": 72, + "address": { + "state": "New Hampshire", + "city": "Muir" + } + }, + { + "id": 7722, + "name": "Webb Odom", + "gender": "male", + "age": 52, + "address": { + "state": "New York", + "city": "Aberdeen" + } + }, + { + "id": 7723, + "name": "Monica Vazquez", + "gender": "female", + "age": 36, + "address": { + "state": "Mississippi", + "city": "Shindler" + } + }, + { + "id": 7724, + "name": "Brennan Chang", + "gender": "male", + "age": 47, + "address": { + "state": "Idaho", + "city": "Dexter" + } + }, + { + "id": 7725, + "name": "Josephine Lloyd", + "gender": "female", + "age": 52, + "address": { + "state": "Montana", + "city": "Goodville" + } + }, + { + "id": 7726, + "name": "Jacqueline Perez", + "gender": "female", + "age": 19, + "address": { + "state": "Maine", + "city": "Coral" + } + }, + { + "id": 7727, + "name": "Mcclure Pitts", + "gender": "male", + "age": 48, + "address": { + "state": "Oklahoma", + "city": "Courtland" + } + }, + { + "id": 7728, + "name": "Blanchard Ramos", + "gender": "male", + "age": 54, + "address": { + "state": "Ohio", + "city": "Rivers" + } + }, + { + "id": 7729, + "name": "Melody Howe", + "gender": "female", + "age": 52, + "address": { + "state": "South Dakota", + "city": "Winfred" + } + }, + { + "id": 7730, + "name": "Blake Burns", + "gender": "male", + "age": 63, + "address": { + "state": "Louisiana", + "city": "Grayhawk" + } + }, + { + "id": 7731, + "name": "Gloria Guerra", + "gender": "female", + "age": 72, + "address": { + "state": "Michigan", + "city": "Bowie" + } + }, + { + "id": 7732, + "name": "Stuart Rivera", + "gender": "male", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Salix" + } + }, + { + "id": 7733, + "name": "Blackburn Yates", + "gender": "male", + "age": 66, + "address": { + "state": "North Carolina", + "city": "Edmund" + } + }, + { + "id": 7734, + "name": "Lambert Owen", + "gender": "male", + "age": 27, + "address": { + "state": "Maryland", + "city": "Richford" + } + }, + { + "id": 7735, + "name": "Pate Montgomery", + "gender": "male", + "age": 18, + "address": { + "state": "Hawaii", + "city": "Otranto" + } + }, + { + "id": 7736, + "name": "Valencia Kirk", + "gender": "male", + "age": 17, + "address": { + "state": "Pennsylvania", + "city": "Elfrida" + } + }, + { + "id": 7737, + "name": "Spence Harrington", + "gender": "male", + "age": 41, + "address": { + "state": "California", + "city": "Russellville" + } + }, + { + "id": 7738, + "name": "Stevenson Haley", + "gender": "male", + "age": 75, + "address": { + "state": "Minnesota", + "city": "Dellview" + } + }, + { + "id": 7739, + "name": "Noemi Foley", + "gender": "female", + "age": 28, + "address": { + "state": "South Carolina", + "city": "Nipinnawasee" + } + }, + { + "id": 7740, + "name": "Irene Chandler", + "gender": "female", + "age": 70, + "address": { + "state": "Kansas", + "city": "Lindisfarne" + } + }, + { + "id": 7741, + "name": "Carmen Johns", + "gender": "female", + "age": 23, + "address": { + "state": "Iowa", + "city": "Albany" + } + }, + { + "id": 7742, + "name": "Massey Nieves", + "gender": "male", + "age": 64, + "address": { + "state": "Texas", + "city": "Kiskimere" + } + }, + { + "id": 7743, + "name": "Deirdre Reeves", + "gender": "female", + "age": 79, + "address": { + "state": "Michigan", + "city": "Hessville" + } + }, + { + "id": 7744, + "name": "Walsh Garza", + "gender": "male", + "age": 62, + "address": { + "state": "Delaware", + "city": "Morgandale" + } + }, + { + "id": 7745, + "name": "Harding Wiley", + "gender": "male", + "age": 49, + "address": { + "state": "Washington", + "city": "Frystown" + } + }, + { + "id": 7746, + "name": "Guadalupe Hopkins", + "gender": "female", + "age": 27, + "address": { + "state": "Hawaii", + "city": "Gila" + } + }, + { + "id": 7747, + "name": "Welch Todd", + "gender": "male", + "age": 80, + "address": { + "state": "Wyoming", + "city": "Grantville" + } + }, + { + "id": 7748, + "name": "Neal Carver", + "gender": "male", + "age": 26, + "address": { + "state": "Utah", + "city": "Bartley" + } + }, + { + "id": 7749, + "name": "Ruby Wood", + "gender": "female", + "age": 26, + "address": { + "state": "Oklahoma", + "city": "Motley" + } + }, + { + "id": 7750, + "name": "Beard Carlson", + "gender": "male", + "age": 80, + "address": { + "state": "North Dakota", + "city": "Slovan" + } + }, + { + "id": 7751, + "name": "Hutchinson Myers", + "gender": "male", + "age": 75, + "address": { + "state": "Illinois", + "city": "Masthope" + } + }, + { + "id": 7752, + "name": "Bettie Hill", + "gender": "female", + "age": 20, + "address": { + "state": "Montana", + "city": "Imperial" + } + }, + { + "id": 7753, + "name": "Vazquez Franks", + "gender": "male", + "age": 78, + "address": { + "state": "West Virginia", + "city": "Rosine" + } + }, + { + "id": 7754, + "name": "Enid Davidson", + "gender": "female", + "age": 33, + "address": { + "state": "New York", + "city": "Starks" + } + }, + { + "id": 7755, + "name": "Jolene Rodriquez", + "gender": "female", + "age": 49, + "address": { + "state": "Mississippi", + "city": "Robinson" + } + }, + { + "id": 7756, + "name": "Rosalyn Townsend", + "gender": "female", + "age": 50, + "address": { + "state": "Kansas", + "city": "Leyner" + } + }, + { + "id": 7757, + "name": "Jacklyn Shepherd", + "gender": "female", + "age": 20, + "address": { + "state": "Arkansas", + "city": "Hayes" + } + }, + { + "id": 7758, + "name": "Melissa Graham", + "gender": "female", + "age": 19, + "address": { + "state": "Massachusetts", + "city": "Barronett" + } + }, + { + "id": 7759, + "name": "Snow Doyle", + "gender": "male", + "age": 53, + "address": { + "state": "Missouri", + "city": "Dubois" + } + }, + { + "id": 7760, + "name": "Walker Christensen", + "gender": "male", + "age": 52, + "address": { + "state": "California", + "city": "Baden" + } + }, + { + "id": 7761, + "name": "Kay Short", + "gender": "female", + "age": 44, + "address": { + "state": "New Hampshire", + "city": "Dunbar" + } + }, + { + "id": 7762, + "name": "Sheri Tyler", + "gender": "female", + "age": 58, + "address": { + "state": "Rhode Island", + "city": "Trexlertown" + } + }, + { + "id": 7763, + "name": "Olsen Cervantes", + "gender": "male", + "age": 63, + "address": { + "state": "New Jersey", + "city": "Orovada" + } + }, + { + "id": 7764, + "name": "Holloway Burton", + "gender": "male", + "age": 82, + "address": { + "state": "Alaska", + "city": "Haring" + } + }, + { + "id": 7765, + "name": "Roy Cox", + "gender": "male", + "age": 70, + "address": { + "state": "Pennsylvania", + "city": "Ruckersville" + } + }, + { + "id": 7766, + "name": "Angela Burch", + "gender": "female", + "age": 24, + "address": { + "state": "Arizona", + "city": "Vincent" + } + }, + { + "id": 7767, + "name": "Charlotte Carroll", + "gender": "female", + "age": 75, + "address": { + "state": "Georgia", + "city": "Southview" + } + }, + { + "id": 7768, + "name": "Gonzales Chaney", + "gender": "male", + "age": 53, + "address": { + "state": "South Carolina", + "city": "Santel" + } + }, + { + "id": 7769, + "name": "Hattie Knapp", + "gender": "female", + "age": 25, + "address": { + "state": "Louisiana", + "city": "Cresaptown" + } + }, + { + "id": 7770, + "name": "Jeanine Hartman", + "gender": "female", + "age": 66, + "address": { + "state": "Wisconsin", + "city": "Chilton" + } + }, + { + "id": 7771, + "name": "Melba Cannon", + "gender": "female", + "age": 39, + "address": { + "state": "Oregon", + "city": "Chestnut" + } + }, + { + "id": 7772, + "name": "Toni Pearson", + "gender": "female", + "age": 32, + "address": { + "state": "Tennessee", + "city": "Wheaton" + } + }, + { + "id": 7773, + "name": "Franco Wilcox", + "gender": "male", + "age": 65, + "address": { + "state": "Ohio", + "city": "Fulford" + } + }, + { + "id": 7774, + "name": "Joseph Cote", + "gender": "male", + "age": 51, + "address": { + "state": "Florida", + "city": "Tilden" + } + }, + { + "id": 7775, + "name": "Patricia Burgess", + "gender": "female", + "age": 51, + "address": { + "state": "Maine", + "city": "Accoville" + } + }, + { + "id": 7776, + "name": "Stephanie Mills", + "gender": "female", + "age": 31, + "address": { + "state": "Connecticut", + "city": "Veyo" + } + }, + { + "id": 7777, + "name": "Michael Eaton", + "gender": "female", + "age": 21, + "address": { + "state": "Alabama", + "city": "Trinway" + } + }, + { + "id": 7778, + "name": "Bridget Walsh", + "gender": "female", + "age": 72, + "address": { + "state": "Nebraska", + "city": "Bannock" + } + }, + { + "id": 7779, + "name": "Millie Clarke", + "gender": "female", + "age": 59, + "address": { + "state": "Kentucky", + "city": "Tuskahoma" + } + }, + { + "id": 7780, + "name": "Franks Hebert", + "gender": "male", + "age": 59, + "address": { + "state": "Idaho", + "city": "Englevale" + } + }, + { + "id": 7781, + "name": "Cathy Nguyen", + "gender": "female", + "age": 68, + "address": { + "state": "Maryland", + "city": "Hartsville/Hartley" + } + }, + { + "id": 7782, + "name": "Kerri Riggs", + "gender": "female", + "age": 17, + "address": { + "state": "Vermont", + "city": "Camptown" + } + }, + { + "id": 7783, + "name": "Nanette Aguilar", + "gender": "female", + "age": 43, + "address": { + "state": "Virginia", + "city": "Crayne" + } + }, + { + "id": 7784, + "name": "Oliver Douglas", + "gender": "male", + "age": 82, + "address": { + "state": "South Dakota", + "city": "Bowie" + } + }, + { + "id": 7785, + "name": "Sherrie Page", + "gender": "female", + "age": 41, + "address": { + "state": "Iowa", + "city": "Longoria" + } + }, + { + "id": 7786, + "name": "Mckinney Kirkland", + "gender": "male", + "age": 56, + "address": { + "state": "Colorado", + "city": "Callaghan" + } + }, + { + "id": 7787, + "name": "Lilian Abbott", + "gender": "female", + "age": 20, + "address": { + "state": "Indiana", + "city": "Marbury" + } + }, + { + "id": 7788, + "name": "Mcgowan Cain", + "gender": "male", + "age": 78, + "address": { + "state": "New Mexico", + "city": "Alleghenyville" + } + }, + { + "id": 7789, + "name": "Celia Duke", + "gender": "female", + "age": 80, + "address": { + "state": "Minnesota", + "city": "Falconaire" + } + }, + { + "id": 7790, + "name": "Hunter Bright", + "gender": "male", + "age": 58, + "address": { + "state": "Nevada", + "city": "Kempton" + } + }, + { + "id": 7791, + "name": "Ursula Long", + "gender": "female", + "age": 67, + "address": { + "state": "Florida", + "city": "Chumuckla" + } + }, + { + "id": 7792, + "name": "Saundra Roberson", + "gender": "female", + "age": 52, + "address": { + "state": "Georgia", + "city": "Albany" + } + }, + { + "id": 7793, + "name": "Clarke Mills", + "gender": "male", + "age": 31, + "address": { + "state": "Ohio", + "city": "Holcombe" + } + }, + { + "id": 7794, + "name": "Fuller Flowers", + "gender": "male", + "age": 21, + "address": { + "state": "Illinois", + "city": "Lisco" + } + }, + { + "id": 7795, + "name": "Aileen Horton", + "gender": "female", + "age": 20, + "address": { + "state": "Oregon", + "city": "Kilbourne" + } + }, + { + "id": 7796, + "name": "Moody Gross", + "gender": "male", + "age": 34, + "address": { + "state": "South Carolina", + "city": "Idledale" + } + }, + { + "id": 7797, + "name": "Bullock Vazquez", + "gender": "male", + "age": 38, + "address": { + "state": "Missouri", + "city": "Joppa" + } + }, + { + "id": 7798, + "name": "Claudine Roman", + "gender": "female", + "age": 26, + "address": { + "state": "Iowa", + "city": "Trona" + } + }, + { + "id": 7799, + "name": "Cecile Sawyer", + "gender": "female", + "age": 66, + "address": { + "state": "Colorado", + "city": "Brule" + } + }, + { + "id": 7800, + "name": "Rosemarie Tillman", + "gender": "female", + "age": 21, + "address": { + "state": "Mississippi", + "city": "Guilford" + } + }, + { + "id": 7801, + "name": "Lakisha Browning", + "gender": "female", + "age": 75, + "address": { + "state": "Maryland", + "city": "Camino" + } + }, + { + "id": 7802, + "name": "Leonor Mcgowan", + "gender": "female", + "age": 52, + "address": { + "state": "Oklahoma", + "city": "Tivoli" + } + }, + { + "id": 7803, + "name": "Imelda Gilmore", + "gender": "female", + "age": 59, + "address": { + "state": "Kansas", + "city": "Welda" + } + }, + { + "id": 7804, + "name": "Mcknight Kline", + "gender": "male", + "age": 31, + "address": { + "state": "South Dakota", + "city": "Forestburg" + } + }, + { + "id": 7805, + "name": "Josefina Bates", + "gender": "female", + "age": 80, + "address": { + "state": "Washington", + "city": "Oneida" + } + }, + { + "id": 7806, + "name": "Sandra Hodges", + "gender": "female", + "age": 22, + "address": { + "state": "Montana", + "city": "Grayhawk" + } + }, + { + "id": 7807, + "name": "Byers Romero", + "gender": "male", + "age": 48, + "address": { + "state": "Alaska", + "city": "Nipinnawasee" + } + }, + { + "id": 7808, + "name": "Figueroa Montoya", + "gender": "male", + "age": 71, + "address": { + "state": "Minnesota", + "city": "Sunnyside" + } + }, + { + "id": 7809, + "name": "Glover Robbins", + "gender": "male", + "age": 23, + "address": { + "state": "Massachusetts", + "city": "Thermal" + } + }, + { + "id": 7810, + "name": "Todd Elliott", + "gender": "male", + "age": 50, + "address": { + "state": "North Carolina", + "city": "Hilltop" + } + }, + { + "id": 7811, + "name": "Lupe Day", + "gender": "female", + "age": 34, + "address": { + "state": "Wisconsin", + "city": "Wanship" + } + }, + { + "id": 7812, + "name": "Sallie Davidson", + "gender": "female", + "age": 40, + "address": { + "state": "New Mexico", + "city": "Bawcomville" + } + }, + { + "id": 7813, + "name": "Bass Carr", + "gender": "male", + "age": 27, + "address": { + "state": "California", + "city": "Sultana" + } + }, + { + "id": 7814, + "name": "Galloway Baird", + "gender": "male", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Brownlee" + } + }, + { + "id": 7815, + "name": "Alvarado Huffman", + "gender": "male", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Needmore" + } + }, + { + "id": 7816, + "name": "Ronda Robles", + "gender": "female", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Wauhillau" + } + }, + { + "id": 7817, + "name": "Bonner Greene", + "gender": "male", + "age": 25, + "address": { + "state": "Virginia", + "city": "Deputy" + } + }, + { + "id": 7818, + "name": "Blanche Blankenship", + "gender": "female", + "age": 32, + "address": { + "state": "Indiana", + "city": "Osage" + } + }, + { + "id": 7819, + "name": "Terrell Blair", + "gender": "male", + "age": 29, + "address": { + "state": "Idaho", + "city": "Ernstville" + } + }, + { + "id": 7820, + "name": "Pam Walls", + "gender": "female", + "age": 37, + "address": { + "state": "New York", + "city": "Fingerville" + } + }, + { + "id": 7821, + "name": "Earnestine Little", + "gender": "female", + "age": 66, + "address": { + "state": "Utah", + "city": "Freeburn" + } + }, + { + "id": 7822, + "name": "Herrera Good", + "gender": "male", + "age": 74, + "address": { + "state": "North Dakota", + "city": "Rivers" + } + }, + { + "id": 7823, + "name": "Robert Hawkins", + "gender": "female", + "age": 47, + "address": { + "state": "New Jersey", + "city": "Grill" + } + }, + { + "id": 7824, + "name": "Alexandria Shelton", + "gender": "female", + "age": 58, + "address": { + "state": "Arkansas", + "city": "Levant" + } + }, + { + "id": 7825, + "name": "Bradford Nixon", + "gender": "male", + "age": 22, + "address": { + "state": "Texas", + "city": "Tampico" + } + }, + { + "id": 7826, + "name": "Navarro Gallagher", + "gender": "male", + "age": 65, + "address": { + "state": "Arizona", + "city": "Logan" + } + }, + { + "id": 7827, + "name": "Osborn Hendrix", + "gender": "male", + "age": 63, + "address": { + "state": "Maine", + "city": "Belleview" + } + }, + { + "id": 7828, + "name": "Mckinney Schultz", + "gender": "male", + "age": 27, + "address": { + "state": "Pennsylvania", + "city": "Chalfant" + } + }, + { + "id": 7829, + "name": "Kari Campbell", + "gender": "female", + "age": 58, + "address": { + "state": "Nevada", + "city": "Lodoga" + } + }, + { + "id": 7830, + "name": "Antonia Mercer", + "gender": "female", + "age": 17, + "address": { + "state": "Louisiana", + "city": "Marenisco" + } + }, + { + "id": 7831, + "name": "Hays Eaton", + "gender": "male", + "age": 45, + "address": { + "state": "Alabama", + "city": "Lopezo" + } + }, + { + "id": 7832, + "name": "Alisha Vance", + "gender": "female", + "age": 31, + "address": { + "state": "Vermont", + "city": "Graniteville" + } + }, + { + "id": 7833, + "name": "Wise Mccray", + "gender": "male", + "age": 33, + "address": { + "state": "Kentucky", + "city": "Juarez" + } + }, + { + "id": 7834, + "name": "Beasley Cruz", + "gender": "male", + "age": 34, + "address": { + "state": "Rhode Island", + "city": "Buxton" + } + }, + { + "id": 7835, + "name": "Rachel Velasquez", + "gender": "female", + "age": 68, + "address": { + "state": "Delaware", + "city": "Williamson" + } + }, + { + "id": 7836, + "name": "Underwood Wilson", + "gender": "male", + "age": 28, + "address": { + "state": "Connecticut", + "city": "Basye" + } + }, + { + "id": 7837, + "name": "Barlow Mullen", + "gender": "male", + "age": 79, + "address": { + "state": "Michigan", + "city": "Cuylerville" + } + }, + { + "id": 7838, + "name": "Marianne Fox", + "gender": "female", + "age": 19, + "address": { + "state": "New Hampshire", + "city": "Bethany" + } + }, + { + "id": 7839, + "name": "Cecilia Dixon", + "gender": "female", + "age": 36, + "address": { + "state": "West Virginia", + "city": "Sanford" + } + }, + { + "id": 7840, + "name": "Antoinette Wilder", + "gender": "female", + "age": 38, + "address": { + "state": "Kentucky", + "city": "Brambleton" + } + }, + { + "id": 7841, + "name": "Bright Bird", + "gender": "male", + "age": 53, + "address": { + "state": "Pennsylvania", + "city": "Grimsley" + } + }, + { + "id": 7842, + "name": "Craig Hardin", + "gender": "male", + "age": 47, + "address": { + "state": "South Carolina", + "city": "Wauhillau" + } + }, + { + "id": 7843, + "name": "Jenna Sexton", + "gender": "female", + "age": 32, + "address": { + "state": "Utah", + "city": "Chapin" + } + }, + { + "id": 7844, + "name": "Bertie Mccormick", + "gender": "female", + "age": 39, + "address": { + "state": "Mississippi", + "city": "Ernstville" + } + }, + { + "id": 7845, + "name": "Gray Sherman", + "gender": "male", + "age": 36, + "address": { + "state": "Wisconsin", + "city": "Deltaville" + } + }, + { + "id": 7846, + "name": "Byrd Kirk", + "gender": "male", + "age": 52, + "address": { + "state": "Missouri", + "city": "Northchase" + } + }, + { + "id": 7847, + "name": "Mckinney Estes", + "gender": "male", + "age": 33, + "address": { + "state": "Texas", + "city": "Disautel" + } + }, + { + "id": 7848, + "name": "Monroe Thornton", + "gender": "male", + "age": 24, + "address": { + "state": "Hawaii", + "city": "Remington" + } + }, + { + "id": 7849, + "name": "Warren Moses", + "gender": "male", + "age": 62, + "address": { + "state": "Nevada", + "city": "Whitehaven" + } + }, + { + "id": 7850, + "name": "Chandler Carver", + "gender": "male", + "age": 77, + "address": { + "state": "Michigan", + "city": "Enlow" + } + }, + { + "id": 7851, + "name": "Bethany Lang", + "gender": "female", + "age": 28, + "address": { + "state": "Maine", + "city": "Rockbridge" + } + }, + { + "id": 7852, + "name": "Ora Patton", + "gender": "female", + "age": 55, + "address": { + "state": "Vermont", + "city": "Chase" + } + }, + { + "id": 7853, + "name": "Sophia Mccoy", + "gender": "female", + "age": 37, + "address": { + "state": "Maryland", + "city": "Efland" + } + }, + { + "id": 7854, + "name": "Conner Hendricks", + "gender": "male", + "age": 71, + "address": { + "state": "South Dakota", + "city": "Fairlee" + } + }, + { + "id": 7855, + "name": "Barber Wooten", + "gender": "male", + "age": 64, + "address": { + "state": "Virginia", + "city": "Adamstown" + } + }, + { + "id": 7856, + "name": "Vivian Moss", + "gender": "female", + "age": 82, + "address": { + "state": "Connecticut", + "city": "Waterford" + } + }, + { + "id": 7857, + "name": "Angelica Johnston", + "gender": "female", + "age": 36, + "address": { + "state": "Tennessee", + "city": "Gwynn" + } + }, + { + "id": 7858, + "name": "Jill Suarez", + "gender": "female", + "age": 17, + "address": { + "state": "Oklahoma", + "city": "Weogufka" + } + }, + { + "id": 7859, + "name": "Tiffany Davidson", + "gender": "female", + "age": 38, + "address": { + "state": "Wyoming", + "city": "Vallonia" + } + }, + { + "id": 7860, + "name": "Phillips Pierce", + "gender": "male", + "age": 48, + "address": { + "state": "Minnesota", + "city": "Wiscon" + } + }, + { + "id": 7861, + "name": "Nora Sargent", + "gender": "female", + "age": 68, + "address": { + "state": "Georgia", + "city": "Lavalette" + } + }, + { + "id": 7862, + "name": "Liliana Chandler", + "gender": "female", + "age": 51, + "address": { + "state": "Rhode Island", + "city": "Bayview" + } + }, + { + "id": 7863, + "name": "Charles Pennington", + "gender": "male", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Whitestone" + } + }, + { + "id": 7864, + "name": "Alvarado Wiley", + "gender": "male", + "age": 47, + "address": { + "state": "Florida", + "city": "Groton" + } + }, + { + "id": 7865, + "name": "Stuart Medina", + "gender": "male", + "age": 42, + "address": { + "state": "Oregon", + "city": "Caln" + } + }, + { + "id": 7866, + "name": "Acevedo Ferrell", + "gender": "male", + "age": 46, + "address": { + "state": "Iowa", + "city": "Hanover" + } + }, + { + "id": 7867, + "name": "Sharron Mccarthy", + "gender": "female", + "age": 48, + "address": { + "state": "Delaware", + "city": "Caroline" + } + }, + { + "id": 7868, + "name": "Donovan Clark", + "gender": "male", + "age": 56, + "address": { + "state": "Kansas", + "city": "Dyckesville" + } + }, + { + "id": 7869, + "name": "Ana Aguilar", + "gender": "female", + "age": 21, + "address": { + "state": "Louisiana", + "city": "Blandburg" + } + }, + { + "id": 7870, + "name": "Adrienne Marshall", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Springhill" + } + }, + { + "id": 7871, + "name": "Lucia Small", + "gender": "female", + "age": 70, + "address": { + "state": "Arkansas", + "city": "Rosewood" + } + }, + { + "id": 7872, + "name": "Butler Rowe", + "gender": "male", + "age": 67, + "address": { + "state": "New York", + "city": "Osage" + } + }, + { + "id": 7873, + "name": "Mcdowell Park", + "gender": "male", + "age": 43, + "address": { + "state": "New Jersey", + "city": "Clinton" + } + }, + { + "id": 7874, + "name": "Erin Peck", + "gender": "female", + "age": 17, + "address": { + "state": "Indiana", + "city": "Jackpot" + } + }, + { + "id": 7875, + "name": "Rochelle Osborn", + "gender": "female", + "age": 80, + "address": { + "state": "New Mexico", + "city": "Fillmore" + } + }, + { + "id": 7876, + "name": "Bailey Gilbert", + "gender": "male", + "age": 54, + "address": { + "state": "Montana", + "city": "Needmore" + } + }, + { + "id": 7877, + "name": "Miranda Reid", + "gender": "male", + "age": 27, + "address": { + "state": "North Carolina", + "city": "Soudan" + } + }, + { + "id": 7878, + "name": "Leticia Horne", + "gender": "female", + "age": 31, + "address": { + "state": "Nebraska", + "city": "Edgar" + } + }, + { + "id": 7879, + "name": "Merrill Walton", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Ada" + } + }, + { + "id": 7880, + "name": "Nichols Marquez", + "gender": "male", + "age": 19, + "address": { + "state": "Illinois", + "city": "Westwood" + } + }, + { + "id": 7881, + "name": "Judith Doyle", + "gender": "female", + "age": 22, + "address": { + "state": "Alaska", + "city": "Succasunna" + } + }, + { + "id": 7882, + "name": "Baldwin Vang", + "gender": "male", + "age": 24, + "address": { + "state": "Alabama", + "city": "Boling" + } + }, + { + "id": 7883, + "name": "Carter Petty", + "gender": "male", + "age": 81, + "address": { + "state": "Massachusetts", + "city": "Ezel" + } + }, + { + "id": 7884, + "name": "Taylor Whitaker", + "gender": "female", + "age": 25, + "address": { + "state": "Washington", + "city": "Rowe" + } + }, + { + "id": 7885, + "name": "Estes Richmond", + "gender": "male", + "age": 64, + "address": { + "state": "Idaho", + "city": "Calpine" + } + }, + { + "id": 7886, + "name": "Alba Howe", + "gender": "female", + "age": 80, + "address": { + "state": "Arizona", + "city": "Cumberland" + } + }, + { + "id": 7887, + "name": "Elsie Bowen", + "gender": "female", + "age": 65, + "address": { + "state": "Colorado", + "city": "Stevens" + } + }, + { + "id": 7888, + "name": "Mona Ramos", + "gender": "female", + "age": 81, + "address": { + "state": "West Virginia", + "city": "Kraemer" + } + }, + { + "id": 7889, + "name": "Dorothea Franklin", + "gender": "female", + "age": 77, + "address": { + "state": "Wisconsin", + "city": "Vallonia" + } + }, + { + "id": 7890, + "name": "Griffin Preston", + "gender": "male", + "age": 27, + "address": { + "state": "Idaho", + "city": "Fulford" + } + }, + { + "id": 7891, + "name": "Alyson Witt", + "gender": "female", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Crawfordsville" + } + }, + { + "id": 7892, + "name": "Olga Marquez", + "gender": "female", + "age": 46, + "address": { + "state": "Iowa", + "city": "Rivereno" + } + }, + { + "id": 7893, + "name": "Aguirre Abbott", + "gender": "male", + "age": 34, + "address": { + "state": "Michigan", + "city": "Greenfields" + } + }, + { + "id": 7894, + "name": "Alexandra Trujillo", + "gender": "female", + "age": 63, + "address": { + "state": "Illinois", + "city": "Mathews" + } + }, + { + "id": 7895, + "name": "Annette Riley", + "gender": "female", + "age": 35, + "address": { + "state": "Oregon", + "city": "Downsville" + } + }, + { + "id": 7896, + "name": "Jacobson Cooke", + "gender": "male", + "age": 80, + "address": { + "state": "Indiana", + "city": "Warsaw" + } + }, + { + "id": 7897, + "name": "Nona Cox", + "gender": "female", + "age": 38, + "address": { + "state": "Hawaii", + "city": "Lund" + } + }, + { + "id": 7898, + "name": "Peggy Lawson", + "gender": "female", + "age": 71, + "address": { + "state": "Vermont", + "city": "Calverton" + } + }, + { + "id": 7899, + "name": "Effie Jefferson", + "gender": "female", + "age": 60, + "address": { + "state": "Nevada", + "city": "Nescatunga" + } + }, + { + "id": 7900, + "name": "Hines Bartlett", + "gender": "male", + "age": 51, + "address": { + "state": "Maryland", + "city": "Fostoria" + } + }, + { + "id": 7901, + "name": "Joyce Guy", + "gender": "male", + "age": 20, + "address": { + "state": "Nebraska", + "city": "Lowell" + } + }, + { + "id": 7902, + "name": "Kelsey Jarvis", + "gender": "female", + "age": 79, + "address": { + "state": "North Carolina", + "city": "Leola" + } + }, + { + "id": 7903, + "name": "Melanie Gaines", + "gender": "female", + "age": 46, + "address": { + "state": "Kansas", + "city": "Brownsville" + } + }, + { + "id": 7904, + "name": "Wendy Hardy", + "gender": "female", + "age": 49, + "address": { + "state": "Louisiana", + "city": "Blanco" + } + }, + { + "id": 7905, + "name": "Witt Bullock", + "gender": "male", + "age": 22, + "address": { + "state": "New Hampshire", + "city": "Albany" + } + }, + { + "id": 7906, + "name": "French Morton", + "gender": "male", + "age": 17, + "address": { + "state": "Arizona", + "city": "Avalon" + } + }, + { + "id": 7907, + "name": "Benson Strickland", + "gender": "male", + "age": 66, + "address": { + "state": "South Dakota", + "city": "Jardine" + } + }, + { + "id": 7908, + "name": "Haley King", + "gender": "male", + "age": 75, + "address": { + "state": "Florida", + "city": "Ona" + } + }, + { + "id": 7909, + "name": "Carey Carey", + "gender": "female", + "age": 22, + "address": { + "state": "Mississippi", + "city": "Interlochen" + } + }, + { + "id": 7910, + "name": "Emilia Warren", + "gender": "female", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Shelby" + } + }, + { + "id": 7911, + "name": "Christy Daniels", + "gender": "female", + "age": 74, + "address": { + "state": "Virginia", + "city": "Bluffview" + } + }, + { + "id": 7912, + "name": "Stefanie Dickerson", + "gender": "female", + "age": 28, + "address": { + "state": "Washington", + "city": "Jeff" + } + }, + { + "id": 7913, + "name": "Graham Brooks", + "gender": "male", + "age": 29, + "address": { + "state": "South Carolina", + "city": "Sunriver" + } + }, + { + "id": 7914, + "name": "Hahn Parsons", + "gender": "male", + "age": 56, + "address": { + "state": "Missouri", + "city": "Washington" + } + }, + { + "id": 7915, + "name": "Davis Stein", + "gender": "male", + "age": 39, + "address": { + "state": "West Virginia", + "city": "Callaghan" + } + }, + { + "id": 7916, + "name": "Slater Gross", + "gender": "male", + "age": 60, + "address": { + "state": "Alabama", + "city": "Roulette" + } + }, + { + "id": 7917, + "name": "Bradley Barron", + "gender": "male", + "age": 43, + "address": { + "state": "Massachusetts", + "city": "Ezel" + } + }, + { + "id": 7918, + "name": "Wright Acosta", + "gender": "male", + "age": 50, + "address": { + "state": "Delaware", + "city": "Statenville" + } + }, + { + "id": 7919, + "name": "Singleton Poole", + "gender": "male", + "age": 25, + "address": { + "state": "Pennsylvania", + "city": "Summerset" + } + }, + { + "id": 7920, + "name": "Campbell Pruitt", + "gender": "male", + "age": 17, + "address": { + "state": "New York", + "city": "Mayfair" + } + }, + { + "id": 7921, + "name": "Silvia Kelly", + "gender": "female", + "age": 34, + "address": { + "state": "California", + "city": "Camas" + } + }, + { + "id": 7922, + "name": "Callie Olsen", + "gender": "female", + "age": 17, + "address": { + "state": "Minnesota", + "city": "Toftrees" + } + }, + { + "id": 7923, + "name": "Viola Dunlap", + "gender": "female", + "age": 32, + "address": { + "state": "Maine", + "city": "Gorham" + } + }, + { + "id": 7924, + "name": "Marjorie Heath", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Townsend" + } + }, + { + "id": 7925, + "name": "Craig Lowery", + "gender": "male", + "age": 34, + "address": { + "state": "Utah", + "city": "Drytown" + } + }, + { + "id": 7926, + "name": "Roberts Holman", + "gender": "male", + "age": 64, + "address": { + "state": "Arkansas", + "city": "Wildwood" + } + }, + { + "id": 7927, + "name": "Blankenship Callahan", + "gender": "male", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Rose" + } + }, + { + "id": 7928, + "name": "Hess Sellers", + "gender": "male", + "age": 70, + "address": { + "state": "Rhode Island", + "city": "Glendale" + } + }, + { + "id": 7929, + "name": "Emma Beard", + "gender": "female", + "age": 70, + "address": { + "state": "Kentucky", + "city": "Seymour" + } + }, + { + "id": 7930, + "name": "Orr Robles", + "gender": "male", + "age": 24, + "address": { + "state": "Colorado", + "city": "Cascades" + } + }, + { + "id": 7931, + "name": "Louise Donovan", + "gender": "female", + "age": 53, + "address": { + "state": "Tennessee", + "city": "Dahlen" + } + }, + { + "id": 7932, + "name": "Hull Mcdaniel", + "gender": "male", + "age": 52, + "address": { + "state": "Texas", + "city": "Darbydale" + } + }, + { + "id": 7933, + "name": "Lucile Charles", + "gender": "female", + "age": 26, + "address": { + "state": "Wyoming", + "city": "Cetronia" + } + }, + { + "id": 7934, + "name": "Isabella Cooper", + "gender": "female", + "age": 38, + "address": { + "state": "Ohio", + "city": "Derwood" + } + }, + { + "id": 7935, + "name": "Ballard Johnson", + "gender": "male", + "age": 58, + "address": { + "state": "North Dakota", + "city": "Courtland" + } + }, + { + "id": 7936, + "name": "Ava Roy", + "gender": "female", + "age": 59, + "address": { + "state": "Montana", + "city": "Grayhawk" + } + }, + { + "id": 7937, + "name": "Paige Sharpe", + "gender": "female", + "age": 46, + "address": { + "state": "Alaska", + "city": "Marshall" + } + }, + { + "id": 7938, + "name": "Carrillo Gregory", + "gender": "male", + "age": 17, + "address": { + "state": "Washington", + "city": "Bend" + } + }, + { + "id": 7939, + "name": "Mullins Foster", + "gender": "male", + "age": 41, + "address": { + "state": "Montana", + "city": "Bison" + } + }, + { + "id": 7940, + "name": "Vaughn Oneil", + "gender": "male", + "age": 40, + "address": { + "state": "Maryland", + "city": "Herald" + } + }, + { + "id": 7941, + "name": "Mcdaniel Townsend", + "gender": "male", + "age": 48, + "address": { + "state": "Connecticut", + "city": "Herbster" + } + }, + { + "id": 7942, + "name": "Vickie Fry", + "gender": "female", + "age": 78, + "address": { + "state": "Alaska", + "city": "Carlos" + } + }, + { + "id": 7943, + "name": "Tamara Grimes", + "gender": "female", + "age": 54, + "address": { + "state": "Oklahoma", + "city": "Welch" + } + }, + { + "id": 7944, + "name": "Wheeler Bradshaw", + "gender": "male", + "age": 73, + "address": { + "state": "Maine", + "city": "Croom" + } + }, + { + "id": 7945, + "name": "Rachel Holt", + "gender": "female", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Gibbsville" + } + }, + { + "id": 7946, + "name": "Tate Barr", + "gender": "male", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Walland" + } + }, + { + "id": 7947, + "name": "Bradford Richardson", + "gender": "male", + "age": 40, + "address": { + "state": "Vermont", + "city": "Marysville" + } + }, + { + "id": 7948, + "name": "Mclean Duncan", + "gender": "male", + "age": 58, + "address": { + "state": "Louisiana", + "city": "Sunriver" + } + }, + { + "id": 7949, + "name": "Morse Horton", + "gender": "male", + "age": 27, + "address": { + "state": "Indiana", + "city": "Mansfield" + } + }, + { + "id": 7950, + "name": "Nikki Riggs", + "gender": "female", + "age": 72, + "address": { + "state": "California", + "city": "Wescosville" + } + }, + { + "id": 7951, + "name": "Carla Hart", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Thomasville" + } + }, + { + "id": 7952, + "name": "Kristi Mcintyre", + "gender": "female", + "age": 61, + "address": { + "state": "South Carolina", + "city": "Rockbridge" + } + }, + { + "id": 7953, + "name": "Myrtle Brown", + "gender": "female", + "age": 20, + "address": { + "state": "Oregon", + "city": "Comptche" + } + }, + { + "id": 7954, + "name": "Bernard Massey", + "gender": "male", + "age": 75, + "address": { + "state": "New Jersey", + "city": "Cornucopia" + } + }, + { + "id": 7955, + "name": "Gibbs Roberson", + "gender": "male", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Hamilton" + } + }, + { + "id": 7956, + "name": "Velazquez Hogan", + "gender": "male", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Summertown" + } + }, + { + "id": 7957, + "name": "Roxie Daniel", + "gender": "female", + "age": 35, + "address": { + "state": "West Virginia", + "city": "Kula" + } + }, + { + "id": 7958, + "name": "Dennis Sandoval", + "gender": "male", + "age": 56, + "address": { + "state": "Wisconsin", + "city": "Fruitdale" + } + }, + { + "id": 7959, + "name": "Denise Pope", + "gender": "female", + "age": 41, + "address": { + "state": "Wyoming", + "city": "Bangor" + } + }, + { + "id": 7960, + "name": "Velma Farley", + "gender": "female", + "age": 72, + "address": { + "state": "North Dakota", + "city": "Riviera" + } + }, + { + "id": 7961, + "name": "Jeanne Coleman", + "gender": "female", + "age": 33, + "address": { + "state": "Tennessee", + "city": "Tooleville" + } + }, + { + "id": 7962, + "name": "Jodi Velez", + "gender": "female", + "age": 31, + "address": { + "state": "Mississippi", + "city": "Gorst" + } + }, + { + "id": 7963, + "name": "Morrison Russo", + "gender": "male", + "age": 33, + "address": { + "state": "Hawaii", + "city": "Idamay" + } + }, + { + "id": 7964, + "name": "Katheryn Fisher", + "gender": "female", + "age": 74, + "address": { + "state": "Missouri", + "city": "Woodlands" + } + }, + { + "id": 7965, + "name": "Carter Castro", + "gender": "male", + "age": 79, + "address": { + "state": "Arizona", + "city": "Sheatown" + } + }, + { + "id": 7966, + "name": "Tammy Huber", + "gender": "female", + "age": 27, + "address": { + "state": "Georgia", + "city": "Caron" + } + }, + { + "id": 7967, + "name": "Stacy Whitley", + "gender": "female", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Malott" + } + }, + { + "id": 7968, + "name": "Glover Valencia", + "gender": "male", + "age": 58, + "address": { + "state": "Nevada", + "city": "Oretta" + } + }, + { + "id": 7969, + "name": "Debora Crawford", + "gender": "female", + "age": 28, + "address": { + "state": "Rhode Island", + "city": "Cuylerville" + } + }, + { + "id": 7970, + "name": "Maureen Long", + "gender": "female", + "age": 42, + "address": { + "state": "Ohio", + "city": "Camino" + } + }, + { + "id": 7971, + "name": "Marilyn Lamb", + "gender": "female", + "age": 60, + "address": { + "state": "Kansas", + "city": "Santel" + } + }, + { + "id": 7972, + "name": "Kelley Parsons", + "gender": "female", + "age": 22, + "address": { + "state": "South Dakota", + "city": "Cavalero" + } + }, + { + "id": 7973, + "name": "Santana Floyd", + "gender": "male", + "age": 43, + "address": { + "state": "New York", + "city": "Alden" + } + }, + { + "id": 7974, + "name": "Hutchinson Lucas", + "gender": "male", + "age": 65, + "address": { + "state": "Colorado", + "city": "Trexlertown" + } + }, + { + "id": 7975, + "name": "Nadia Webb", + "gender": "female", + "age": 52, + "address": { + "state": "Utah", + "city": "Eggertsville" + } + }, + { + "id": 7976, + "name": "Adams Callahan", + "gender": "male", + "age": 23, + "address": { + "state": "Nebraska", + "city": "Kipp" + } + }, + { + "id": 7977, + "name": "Ollie Miles", + "gender": "female", + "age": 19, + "address": { + "state": "Texas", + "city": "Loretto" + } + }, + { + "id": 7978, + "name": "Margaret England", + "gender": "female", + "age": 66, + "address": { + "state": "Virginia", + "city": "Tivoli" + } + }, + { + "id": 7979, + "name": "Jimenez Galloway", + "gender": "male", + "age": 21, + "address": { + "state": "Kentucky", + "city": "Umapine" + } + }, + { + "id": 7980, + "name": "Fitzpatrick Stark", + "gender": "male", + "age": 62, + "address": { + "state": "Idaho", + "city": "Aberdeen" + } + }, + { + "id": 7981, + "name": "Ester Humphrey", + "gender": "female", + "age": 60, + "address": { + "state": "Delaware", + "city": "Haring" + } + }, + { + "id": 7982, + "name": "Mable Gray", + "gender": "female", + "age": 58, + "address": { + "state": "Alabama", + "city": "Barclay" + } + }, + { + "id": 7983, + "name": "Gladys Morrison", + "gender": "female", + "age": 70, + "address": { + "state": "Iowa", + "city": "Clinton" + } + }, + { + "id": 7984, + "name": "Mcmahon Juarez", + "gender": "male", + "age": 48, + "address": { + "state": "Illinois", + "city": "Yonah" + } + }, + { + "id": 7985, + "name": "Campos Preston", + "gender": "male", + "age": 59, + "address": { + "state": "Florida", + "city": "Bonanza" + } + }, + { + "id": 7986, + "name": "Donaldson Wilkerson", + "gender": "male", + "age": 65, + "address": { + "state": "New Hampshire", + "city": "Denio" + } + }, + { + "id": 7987, + "name": "Tran Hensley", + "gender": "male", + "age": 55, + "address": { + "state": "New Hampshire", + "city": "Croom" + } + }, + { + "id": 7988, + "name": "Teri Koch", + "gender": "female", + "age": 30, + "address": { + "state": "Mississippi", + "city": "Lafferty" + } + }, + { + "id": 7989, + "name": "Livingston Whitney", + "gender": "male", + "age": 59, + "address": { + "state": "Wyoming", + "city": "Chilton" + } + }, + { + "id": 7990, + "name": "Leonor Russell", + "gender": "female", + "age": 44, + "address": { + "state": "Florida", + "city": "Florence" + } + }, + { + "id": 7991, + "name": "Kayla Hayes", + "gender": "female", + "age": 33, + "address": { + "state": "Vermont", + "city": "Sunwest" + } + }, + { + "id": 7992, + "name": "Clara Daugherty", + "gender": "female", + "age": 18, + "address": { + "state": "Alabama", + "city": "Limestone" + } + }, + { + "id": 7993, + "name": "Curtis Black", + "gender": "male", + "age": 42, + "address": { + "state": "Georgia", + "city": "Oneida" + } + }, + { + "id": 7994, + "name": "Irene Orr", + "gender": "female", + "age": 39, + "address": { + "state": "Ohio", + "city": "Brutus" + } + }, + { + "id": 7995, + "name": "Wallace Grimes", + "gender": "male", + "age": 21, + "address": { + "state": "Illinois", + "city": "Ilchester" + } + }, + { + "id": 7996, + "name": "Beach Colon", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Osmond" + } + }, + { + "id": 7997, + "name": "Catalina Potts", + "gender": "female", + "age": 64, + "address": { + "state": "New York", + "city": "Tivoli" + } + }, + { + "id": 7998, + "name": "House Keller", + "gender": "male", + "age": 82, + "address": { + "state": "Virginia", + "city": "Tilden" + } + }, + { + "id": 7999, + "name": "Doreen Booth", + "gender": "female", + "age": 19, + "address": { + "state": "Maryland", + "city": "Lowgap" + } + }, + { + "id": 8000, + "name": "Ophelia Dickson", + "gender": "female", + "age": 59, + "address": { + "state": "New Jersey", + "city": "Lemoyne" + } + }, + { + "id": 8001, + "name": "Lela Warren", + "gender": "female", + "age": 32, + "address": { + "state": "Nevada", + "city": "Moraida" + } + }, + { + "id": 8002, + "name": "Leon Valencia", + "gender": "male", + "age": 21, + "address": { + "state": "Oregon", + "city": "Chelsea" + } + }, + { + "id": 8003, + "name": "Alisa Vaughn", + "gender": "female", + "age": 50, + "address": { + "state": "Wisconsin", + "city": "Graniteville" + } + }, + { + "id": 8004, + "name": "Morrison Blair", + "gender": "male", + "age": 58, + "address": { + "state": "Montana", + "city": "Nash" + } + }, + { + "id": 8005, + "name": "Ines Mercado", + "gender": "female", + "age": 52, + "address": { + "state": "North Dakota", + "city": "Eagletown" + } + }, + { + "id": 8006, + "name": "Ruth Stevenson", + "gender": "female", + "age": 59, + "address": { + "state": "Indiana", + "city": "Reno" + } + }, + { + "id": 8007, + "name": "Penny Douglas", + "gender": "female", + "age": 61, + "address": { + "state": "Iowa", + "city": "Nipinnawasee" + } + }, + { + "id": 8008, + "name": "Kemp Franklin", + "gender": "male", + "age": 66, + "address": { + "state": "Nebraska", + "city": "Jenkinsville" + } + }, + { + "id": 8009, + "name": "Mayo Gillespie", + "gender": "male", + "age": 77, + "address": { + "state": "Kentucky", + "city": "Delshire" + } + }, + { + "id": 8010, + "name": "Shauna Williamson", + "gender": "female", + "age": 65, + "address": { + "state": "Maine", + "city": "Conestoga" + } + }, + { + "id": 8011, + "name": "Tamika Flores", + "gender": "female", + "age": 33, + "address": { + "state": "Missouri", + "city": "Deercroft" + } + }, + { + "id": 8012, + "name": "Middleton Ramsey", + "gender": "male", + "age": 35, + "address": { + "state": "South Dakota", + "city": "Finzel" + } + }, + { + "id": 8013, + "name": "Kathrine Sloan", + "gender": "female", + "age": 42, + "address": { + "state": "California", + "city": "Taycheedah" + } + }, + { + "id": 8014, + "name": "Allyson Kirby", + "gender": "female", + "age": 79, + "address": { + "state": "South Carolina", + "city": "Harleigh" + } + }, + { + "id": 8015, + "name": "Bonner Kirkland", + "gender": "male", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Columbus" + } + }, + { + "id": 8016, + "name": "Reyna Cole", + "gender": "female", + "age": 74, + "address": { + "state": "North Carolina", + "city": "Zortman" + } + }, + { + "id": 8017, + "name": "Davis Klein", + "gender": "male", + "age": 78, + "address": { + "state": "Utah", + "city": "Beaverdale" + } + }, + { + "id": 8018, + "name": "Duke Mueller", + "gender": "male", + "age": 34, + "address": { + "state": "New Mexico", + "city": "Ferney" + } + }, + { + "id": 8019, + "name": "Skinner Mann", + "gender": "male", + "age": 68, + "address": { + "state": "Texas", + "city": "Rivers" + } + }, + { + "id": 8020, + "name": "Anthony Christian", + "gender": "male", + "age": 47, + "address": { + "state": "Colorado", + "city": "Farmington" + } + }, + { + "id": 8021, + "name": "Fran Ochoa", + "gender": "female", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Otranto" + } + }, + { + "id": 8022, + "name": "Wolf Carroll", + "gender": "male", + "age": 66, + "address": { + "state": "Oklahoma", + "city": "Dellview" + } + }, + { + "id": 8023, + "name": "Mercer Long", + "gender": "male", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Hemlock" + } + }, + { + "id": 8024, + "name": "Mona Lynn", + "gender": "female", + "age": 36, + "address": { + "state": "Minnesota", + "city": "Gilmore" + } + }, + { + "id": 8025, + "name": "Rasmussen Murray", + "gender": "male", + "age": 22, + "address": { + "state": "Delaware", + "city": "Clay" + } + }, + { + "id": 8026, + "name": "Zelma Yates", + "gender": "female", + "age": 20, + "address": { + "state": "Arkansas", + "city": "Mulberry" + } + }, + { + "id": 8027, + "name": "Dyer Lara", + "gender": "male", + "age": 20, + "address": { + "state": "Connecticut", + "city": "Boonville" + } + }, + { + "id": 8028, + "name": "Janice Stephens", + "gender": "female", + "age": 66, + "address": { + "state": "Kansas", + "city": "Utting" + } + }, + { + "id": 8029, + "name": "Christine Giles", + "gender": "female", + "age": 45, + "address": { + "state": "Rhode Island", + "city": "Bowden" + } + }, + { + "id": 8030, + "name": "Larsen Lowe", + "gender": "male", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Stevens" + } + }, + { + "id": 8031, + "name": "Wyatt Heath", + "gender": "male", + "age": 73, + "address": { + "state": "Alaska", + "city": "Callaghan" + } + }, + { + "id": 8032, + "name": "Mable Solis", + "gender": "female", + "age": 76, + "address": { + "state": "Michigan", + "city": "Woodlands" + } + }, + { + "id": 8033, + "name": "Katherine Snider", + "gender": "female", + "age": 18, + "address": { + "state": "Washington", + "city": "Bartley" + } + }, + { + "id": 8034, + "name": "Valentine Pratt", + "gender": "male", + "age": 70, + "address": { + "state": "Arizona", + "city": "Roberts" + } + }, + { + "id": 8035, + "name": "Kristine Clemons", + "gender": "female", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Coyote" + } + }, + { + "id": 8036, + "name": "Carla Leon", + "gender": "female", + "age": 75, + "address": { + "state": "Hawaii", + "city": "Gardiner" + } + }, + { + "id": 8037, + "name": "Griffin Vincent", + "gender": "male", + "age": 33, + "address": { + "state": "Pennsylvania", + "city": "Zarephath" + } + }, + { + "id": 8038, + "name": "Luella Knapp", + "gender": "female", + "age": 40, + "address": { + "state": "Maine", + "city": "Helen" + } + }, + { + "id": 8039, + "name": "Campos Morse", + "gender": "male", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Trona" + } + }, + { + "id": 8040, + "name": "Lindsay Garrett", + "gender": "male", + "age": 48, + "address": { + "state": "Oklahoma", + "city": "Kenvil" + } + }, + { + "id": 8041, + "name": "Tanisha Davenport", + "gender": "female", + "age": 29, + "address": { + "state": "Missouri", + "city": "Waiohinu" + } + }, + { + "id": 8042, + "name": "Patty Hopper", + "gender": "female", + "age": 63, + "address": { + "state": "Louisiana", + "city": "Teasdale" + } + }, + { + "id": 8043, + "name": "Virginia Barry", + "gender": "female", + "age": 24, + "address": { + "state": "Colorado", + "city": "Bordelonville" + } + }, + { + "id": 8044, + "name": "Lindsay Koch", + "gender": "female", + "age": 64, + "address": { + "state": "Idaho", + "city": "Onton" + } + }, + { + "id": 8045, + "name": "Lupe Martinez", + "gender": "female", + "age": 36, + "address": { + "state": "Michigan", + "city": "Waterview" + } + }, + { + "id": 8046, + "name": "Amanda Massey", + "gender": "female", + "age": 81, + "address": { + "state": "Kentucky", + "city": "Maplewood" + } + }, + { + "id": 8047, + "name": "Lara Oliver", + "gender": "female", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Sidman" + } + }, + { + "id": 8048, + "name": "Sherrie Mccarty", + "gender": "female", + "age": 59, + "address": { + "state": "Indiana", + "city": "Cliff" + } + }, + { + "id": 8049, + "name": "Jody Stewart", + "gender": "female", + "age": 53, + "address": { + "state": "Illinois", + "city": "Tyro" + } + }, + { + "id": 8050, + "name": "Myrna Flowers", + "gender": "female", + "age": 52, + "address": { + "state": "Georgia", + "city": "Vicksburg" + } + }, + { + "id": 8051, + "name": "Garrison Sharp", + "gender": "male", + "age": 68, + "address": { + "state": "Delaware", + "city": "Grimsley" + } + }, + { + "id": 8052, + "name": "Maxwell Bush", + "gender": "male", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Conestoga" + } + }, + { + "id": 8053, + "name": "Kelly Kerr", + "gender": "male", + "age": 26, + "address": { + "state": "Maryland", + "city": "Hanover" + } + }, + { + "id": 8054, + "name": "Hughes Warren", + "gender": "male", + "age": 77, + "address": { + "state": "Tennessee", + "city": "Bascom" + } + }, + { + "id": 8055, + "name": "Frieda Hall", + "gender": "female", + "age": 31, + "address": { + "state": "Florida", + "city": "Saticoy" + } + }, + { + "id": 8056, + "name": "Herman Whitaker", + "gender": "male", + "age": 62, + "address": { + "state": "Alabama", + "city": "Witmer" + } + }, + { + "id": 8057, + "name": "Rocha Velez", + "gender": "male", + "age": 25, + "address": { + "state": "South Carolina", + "city": "Duryea" + } + }, + { + "id": 8058, + "name": "Madge Conrad", + "gender": "female", + "age": 20, + "address": { + "state": "Oregon", + "city": "Bonanza" + } + }, + { + "id": 8059, + "name": "Rich Roberson", + "gender": "male", + "age": 52, + "address": { + "state": "Arizona", + "city": "Faywood" + } + }, + { + "id": 8060, + "name": "Lina Marsh", + "gender": "female", + "age": 21, + "address": { + "state": "Utah", + "city": "Bourg" + } + }, + { + "id": 8061, + "name": "Sawyer Perkins", + "gender": "male", + "age": 35, + "address": { + "state": "North Dakota", + "city": "Edgar" + } + }, + { + "id": 8062, + "name": "Rachael Dixon", + "gender": "female", + "age": 23, + "address": { + "state": "New Mexico", + "city": "Clara" + } + }, + { + "id": 8063, + "name": "Rogers Patton", + "gender": "male", + "age": 60, + "address": { + "state": "New Jersey", + "city": "Calpine" + } + }, + { + "id": 8064, + "name": "Leanna Levy", + "gender": "female", + "age": 54, + "address": { + "state": "California", + "city": "Joppa" + } + }, + { + "id": 8065, + "name": "Margaret Glover", + "gender": "female", + "age": 24, + "address": { + "state": "Minnesota", + "city": "Montura" + } + }, + { + "id": 8066, + "name": "Ward Duran", + "gender": "male", + "age": 18, + "address": { + "state": "Iowa", + "city": "Joes" + } + }, + { + "id": 8067, + "name": "Walls York", + "gender": "male", + "age": 35, + "address": { + "state": "Montana", + "city": "Defiance" + } + }, + { + "id": 8068, + "name": "Cook Ford", + "gender": "male", + "age": 71, + "address": { + "state": "Ohio", + "city": "Oceola" + } + }, + { + "id": 8069, + "name": "Lora Case", + "gender": "female", + "age": 61, + "address": { + "state": "Vermont", + "city": "Freetown" + } + }, + { + "id": 8070, + "name": "Rhoda Wilkerson", + "gender": "female", + "age": 57, + "address": { + "state": "South Dakota", + "city": "Wildwood" + } + }, + { + "id": 8071, + "name": "Edwards Mcconnell", + "gender": "male", + "age": 17, + "address": { + "state": "Texas", + "city": "Concho" + } + }, + { + "id": 8072, + "name": "Rosa Callahan", + "gender": "male", + "age": 76, + "address": { + "state": "New Hampshire", + "city": "Durham" + } + }, + { + "id": 8073, + "name": "Alvarez Roach", + "gender": "male", + "age": 73, + "address": { + "state": "Mississippi", + "city": "Ada" + } + }, + { + "id": 8074, + "name": "Leila Cohen", + "gender": "female", + "age": 38, + "address": { + "state": "Virginia", + "city": "Clinton" + } + }, + { + "id": 8075, + "name": "Thomas Owen", + "gender": "male", + "age": 58, + "address": { + "state": "Washington", + "city": "Eggertsville" + } + }, + { + "id": 8076, + "name": "Tillman Pace", + "gender": "male", + "age": 71, + "address": { + "state": "Nevada", + "city": "Rehrersburg" + } + }, + { + "id": 8077, + "name": "Burt Horton", + "gender": "male", + "age": 81, + "address": { + "state": "Connecticut", + "city": "Sattley" + } + }, + { + "id": 8078, + "name": "Mills Cabrera", + "gender": "male", + "age": 35, + "address": { + "state": "Wyoming", + "city": "Gwynn" + } + }, + { + "id": 8079, + "name": "Delacruz Gilliam", + "gender": "male", + "age": 32, + "address": { + "state": "North Carolina", + "city": "Edinburg" + } + }, + { + "id": 8080, + "name": "Nita Nicholson", + "gender": "female", + "age": 76, + "address": { + "state": "Arkansas", + "city": "Savannah" + } + }, + { + "id": 8081, + "name": "Oconnor Ewing", + "gender": "male", + "age": 38, + "address": { + "state": "New York", + "city": "Marysville" + } + }, + { + "id": 8082, + "name": "Mcintosh Campbell", + "gender": "male", + "age": 20, + "address": { + "state": "Massachusetts", + "city": "Elizaville" + } + }, + { + "id": 8083, + "name": "Sheena Meadows", + "gender": "female", + "age": 22, + "address": { + "state": "Kansas", + "city": "Frank" + } + }, + { + "id": 8084, + "name": "Burke Petersen", + "gender": "male", + "age": 73, + "address": { + "state": "Alaska", + "city": "Nettie" + } + }, + { + "id": 8085, + "name": "Fuller Stephenson", + "gender": "male", + "age": 73, + "address": { + "state": "Maine", + "city": "Topaz" + } + }, + { + "id": 8086, + "name": "Pope Weber", + "gender": "male", + "age": 53, + "address": { + "state": "Delaware", + "city": "Toftrees" + } + }, + { + "id": 8087, + "name": "Parrish Lamb", + "gender": "male", + "age": 23, + "address": { + "state": "Alaska", + "city": "Westwood" + } + }, + { + "id": 8088, + "name": "Kris Hawkins", + "gender": "female", + "age": 28, + "address": { + "state": "Montana", + "city": "Wolcott" + } + }, + { + "id": 8089, + "name": "Dudley Price", + "gender": "male", + "age": 39, + "address": { + "state": "Georgia", + "city": "Franklin" + } + }, + { + "id": 8090, + "name": "Jami Waters", + "gender": "female", + "age": 46, + "address": { + "state": "Wyoming", + "city": "Sunwest" + } + }, + { + "id": 8091, + "name": "Cortez Solomon", + "gender": "male", + "age": 57, + "address": { + "state": "Washington", + "city": "Como" + } + }, + { + "id": 8092, + "name": "Betsy Vang", + "gender": "female", + "age": 73, + "address": { + "state": "Michigan", + "city": "Dragoon" + } + }, + { + "id": 8093, + "name": "Ruthie Leach", + "gender": "female", + "age": 25, + "address": { + "state": "Ohio", + "city": "Castleton" + } + }, + { + "id": 8094, + "name": "Hannah Byrd", + "gender": "female", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Fostoria" + } + }, + { + "id": 8095, + "name": "Ochoa Conrad", + "gender": "male", + "age": 39, + "address": { + "state": "New York", + "city": "Buxton" + } + }, + { + "id": 8096, + "name": "Browning Joyner", + "gender": "male", + "age": 27, + "address": { + "state": "Nebraska", + "city": "Leming" + } + }, + { + "id": 8097, + "name": "Ray Rose", + "gender": "male", + "age": 44, + "address": { + "state": "Iowa", + "city": "Westmoreland" + } + }, + { + "id": 8098, + "name": "Cassie Estrada", + "gender": "female", + "age": 59, + "address": { + "state": "Virginia", + "city": "Orick" + } + }, + { + "id": 8099, + "name": "Trisha Stokes", + "gender": "female", + "age": 50, + "address": { + "state": "Maryland", + "city": "Layhill" + } + }, + { + "id": 8100, + "name": "Reid Carson", + "gender": "male", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Loyalhanna" + } + }, + { + "id": 8101, + "name": "Gonzales Dodson", + "gender": "male", + "age": 50, + "address": { + "state": "Arkansas", + "city": "Sunriver" + } + }, + { + "id": 8102, + "name": "Knox Mejia", + "gender": "male", + "age": 81, + "address": { + "state": "Oregon", + "city": "Townsend" + } + }, + { + "id": 8103, + "name": "Rosales Jarvis", + "gender": "male", + "age": 53, + "address": { + "state": "Minnesota", + "city": "Dawn" + } + }, + { + "id": 8104, + "name": "Latasha Le", + "gender": "female", + "age": 68, + "address": { + "state": "Indiana", + "city": "Bellfountain" + } + }, + { + "id": 8105, + "name": "Maldonado Swanson", + "gender": "male", + "age": 19, + "address": { + "state": "Wisconsin", + "city": "Sanford" + } + }, + { + "id": 8106, + "name": "May Bowen", + "gender": "female", + "age": 50, + "address": { + "state": "California", + "city": "Smock" + } + }, + { + "id": 8107, + "name": "Rose Wall", + "gender": "female", + "age": 53, + "address": { + "state": "Arizona", + "city": "Thermal" + } + }, + { + "id": 8108, + "name": "Eliza Monroe", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Cleary" + } + }, + { + "id": 8109, + "name": "Frankie Hinton", + "gender": "female", + "age": 45, + "address": { + "state": "Oklahoma", + "city": "Loma" + } + }, + { + "id": 8110, + "name": "Brown Tyler", + "gender": "male", + "age": 80, + "address": { + "state": "Utah", + "city": "Turpin" + } + }, + { + "id": 8111, + "name": "Ebony Gordon", + "gender": "female", + "age": 18, + "address": { + "state": "West Virginia", + "city": "Gerber" + } + }, + { + "id": 8112, + "name": "Franks Good", + "gender": "male", + "age": 48, + "address": { + "state": "Idaho", + "city": "Conway" + } + }, + { + "id": 8113, + "name": "Leanne Lang", + "gender": "female", + "age": 65, + "address": { + "state": "Florida", + "city": "Nogal" + } + }, + { + "id": 8114, + "name": "Rush Morales", + "gender": "male", + "age": 72, + "address": { + "state": "Alabama", + "city": "Cobbtown" + } + }, + { + "id": 8115, + "name": "Reed York", + "gender": "male", + "age": 67, + "address": { + "state": "Rhode Island", + "city": "Greenbush" + } + }, + { + "id": 8116, + "name": "Catalina Crosby", + "gender": "female", + "age": 40, + "address": { + "state": "North Carolina", + "city": "Brethren" + } + }, + { + "id": 8117, + "name": "Arnold Russell", + "gender": "male", + "age": 62, + "address": { + "state": "New Mexico", + "city": "Oasis" + } + }, + { + "id": 8118, + "name": "Britt Hogan", + "gender": "male", + "age": 30, + "address": { + "state": "South Carolina", + "city": "Hanover" + } + }, + { + "id": 8119, + "name": "Mccarthy Tucker", + "gender": "male", + "age": 45, + "address": { + "state": "South Dakota", + "city": "Venice" + } + }, + { + "id": 8120, + "name": "Bridgette Banks", + "gender": "female", + "age": 35, + "address": { + "state": "Colorado", + "city": "Gibbsville" + } + }, + { + "id": 8121, + "name": "Lelia Mueller", + "gender": "female", + "age": 50, + "address": { + "state": "North Dakota", + "city": "Naomi" + } + }, + { + "id": 8122, + "name": "Clark Browning", + "gender": "male", + "age": 73, + "address": { + "state": "Illinois", + "city": "Harrodsburg" + } + }, + { + "id": 8123, + "name": "Vasquez Mcfadden", + "gender": "male", + "age": 34, + "address": { + "state": "Vermont", + "city": "Watchtower" + } + }, + { + "id": 8124, + "name": "Sheppard Cannon", + "gender": "male", + "age": 81, + "address": { + "state": "Connecticut", + "city": "Wyoming" + } + }, + { + "id": 8125, + "name": "Lee Ratliff", + "gender": "female", + "age": 23, + "address": { + "state": "Texas", + "city": "Malo" + } + }, + { + "id": 8126, + "name": "Jewell Santana", + "gender": "female", + "age": 56, + "address": { + "state": "Massachusetts", + "city": "Teasdale" + } + }, + { + "id": 8127, + "name": "Katina Dawson", + "gender": "female", + "age": 79, + "address": { + "state": "Kentucky", + "city": "Snowville" + } + }, + { + "id": 8128, + "name": "Kaufman English", + "gender": "male", + "age": 78, + "address": { + "state": "Missouri", + "city": "Tilleda" + } + }, + { + "id": 8129, + "name": "Alicia Lindsey", + "gender": "female", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Cotopaxi" + } + }, + { + "id": 8130, + "name": "Haynes Clarke", + "gender": "male", + "age": 56, + "address": { + "state": "Kansas", + "city": "Cuylerville" + } + }, + { + "id": 8131, + "name": "Morrison Rojas", + "gender": "male", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Ticonderoga" + } + }, + { + "id": 8132, + "name": "Russell Church", + "gender": "male", + "age": 23, + "address": { + "state": "Nevada", + "city": "Hachita" + } + }, + { + "id": 8133, + "name": "Huber Diaz", + "gender": "male", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Woodruff" + } + }, + { + "id": 8134, + "name": "Mayra Mclean", + "gender": "female", + "age": 52, + "address": { + "state": "Alabama", + "city": "Odessa" + } + }, + { + "id": 8135, + "name": "Velazquez Whitley", + "gender": "male", + "age": 53, + "address": { + "state": "Minnesota", + "city": "Outlook" + } + }, + { + "id": 8136, + "name": "Candace Jackson", + "gender": "female", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Greenbackville" + } + }, + { + "id": 8137, + "name": "Frazier Britt", + "gender": "male", + "age": 53, + "address": { + "state": "Montana", + "city": "Cresaptown" + } + }, + { + "id": 8138, + "name": "Walsh Battle", + "gender": "male", + "age": 58, + "address": { + "state": "South Dakota", + "city": "Belfair" + } + }, + { + "id": 8139, + "name": "Cruz Perez", + "gender": "male", + "age": 80, + "address": { + "state": "California", + "city": "Stewartville" + } + }, + { + "id": 8140, + "name": "Guerra Lancaster", + "gender": "male", + "age": 57, + "address": { + "state": "Oregon", + "city": "Murillo" + } + }, + { + "id": 8141, + "name": "Reba Mayer", + "gender": "female", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Eastvale" + } + }, + { + "id": 8142, + "name": "Hoover Turner", + "gender": "male", + "age": 82, + "address": { + "state": "Vermont", + "city": "Rockbridge" + } + }, + { + "id": 8143, + "name": "Beck Valencia", + "gender": "male", + "age": 58, + "address": { + "state": "Arkansas", + "city": "Nescatunga" + } + }, + { + "id": 8144, + "name": "Nell Richmond", + "gender": "female", + "age": 57, + "address": { + "state": "Hawaii", + "city": "Genoa" + } + }, + { + "id": 8145, + "name": "Virgie Berger", + "gender": "female", + "age": 24, + "address": { + "state": "Florida", + "city": "Muir" + } + }, + { + "id": 8146, + "name": "Kirby Jarvis", + "gender": "male", + "age": 35, + "address": { + "state": "Tennessee", + "city": "Deseret" + } + }, + { + "id": 8147, + "name": "Jodie Mcmillan", + "gender": "female", + "age": 41, + "address": { + "state": "Kansas", + "city": "Nanafalia" + } + }, + { + "id": 8148, + "name": "Jessica Ware", + "gender": "female", + "age": 67, + "address": { + "state": "Mississippi", + "city": "Longbranch" + } + }, + { + "id": 8149, + "name": "Alta Velez", + "gender": "female", + "age": 41, + "address": { + "state": "Utah", + "city": "Dragoon" + } + }, + { + "id": 8150, + "name": "Sadie Medina", + "gender": "female", + "age": 75, + "address": { + "state": "Georgia", + "city": "Bedias" + } + }, + { + "id": 8151, + "name": "Keller Burton", + "gender": "male", + "age": 21, + "address": { + "state": "Louisiana", + "city": "Weeksville" + } + }, + { + "id": 8152, + "name": "Harrington Duran", + "gender": "male", + "age": 26, + "address": { + "state": "Missouri", + "city": "Coaldale" + } + }, + { + "id": 8153, + "name": "Ortiz Brewer", + "gender": "male", + "age": 38, + "address": { + "state": "West Virginia", + "city": "Lodoga" + } + }, + { + "id": 8154, + "name": "Veronica Mckinney", + "gender": "female", + "age": 54, + "address": { + "state": "Pennsylvania", + "city": "Marbury" + } + }, + { + "id": 8155, + "name": "Ophelia Mercado", + "gender": "female", + "age": 36, + "address": { + "state": "Virginia", + "city": "Itmann" + } + }, + { + "id": 8156, + "name": "Jeanne Stout", + "gender": "female", + "age": 40, + "address": { + "state": "Washington", + "city": "Ernstville" + } + }, + { + "id": 8157, + "name": "Cathleen Gregory", + "gender": "female", + "age": 34, + "address": { + "state": "Maine", + "city": "Collins" + } + }, + { + "id": 8158, + "name": "Garcia Bird", + "gender": "male", + "age": 40, + "address": { + "state": "South Carolina", + "city": "Freelandville" + } + }, + { + "id": 8159, + "name": "Rowe Raymond", + "gender": "male", + "age": 53, + "address": { + "state": "Indiana", + "city": "Morriston" + } + }, + { + "id": 8160, + "name": "Rush Delacruz", + "gender": "male", + "age": 57, + "address": { + "state": "Colorado", + "city": "Forestburg" + } + }, + { + "id": 8161, + "name": "Hester Reyes", + "gender": "female", + "age": 74, + "address": { + "state": "Kentucky", + "city": "Singer" + } + }, + { + "id": 8162, + "name": "Cora Freeman", + "gender": "female", + "age": 79, + "address": { + "state": "Delaware", + "city": "Santel" + } + }, + { + "id": 8163, + "name": "Faye Vincent", + "gender": "female", + "age": 66, + "address": { + "state": "New Jersey", + "city": "Faxon" + } + }, + { + "id": 8164, + "name": "Dalton Mcgee", + "gender": "male", + "age": 29, + "address": { + "state": "Alaska", + "city": "Orovada" + } + }, + { + "id": 8165, + "name": "Bettye Holloway", + "gender": "female", + "age": 34, + "address": { + "state": "Nevada", + "city": "Alden" + } + }, + { + "id": 8166, + "name": "Sears Rivas", + "gender": "male", + "age": 78, + "address": { + "state": "Arizona", + "city": "Moraida" + } + }, + { + "id": 8167, + "name": "Stevens Haney", + "gender": "male", + "age": 50, + "address": { + "state": "Michigan", + "city": "Chilton" + } + }, + { + "id": 8168, + "name": "Leann Miranda", + "gender": "female", + "age": 55, + "address": { + "state": "Maryland", + "city": "Waikele" + } + }, + { + "id": 8169, + "name": "Foreman Frye", + "gender": "male", + "age": 47, + "address": { + "state": "Wyoming", + "city": "Libertytown" + } + }, + { + "id": 8170, + "name": "Belinda Sutton", + "gender": "female", + "age": 45, + "address": { + "state": "Wisconsin", + "city": "Lemoyne" + } + }, + { + "id": 8171, + "name": "Morse Mcdonald", + "gender": "male", + "age": 22, + "address": { + "state": "Texas", + "city": "Snelling" + } + }, + { + "id": 8172, + "name": "Marian Bryant", + "gender": "female", + "age": 29, + "address": { + "state": "Massachusetts", + "city": "Sexton" + } + }, + { + "id": 8173, + "name": "Jennie Dickerson", + "gender": "female", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Ahwahnee" + } + }, + { + "id": 8174, + "name": "Lyons Mathews", + "gender": "male", + "age": 44, + "address": { + "state": "Ohio", + "city": "Northridge" + } + }, + { + "id": 8175, + "name": "Crane Glenn", + "gender": "male", + "age": 33, + "address": { + "state": "North Dakota", + "city": "Ruckersville" + } + }, + { + "id": 8176, + "name": "Cecile Clarke", + "gender": "female", + "age": 65, + "address": { + "state": "Rhode Island", + "city": "Hailesboro" + } + }, + { + "id": 8177, + "name": "Stuart Stewart", + "gender": "male", + "age": 53, + "address": { + "state": "Iowa", + "city": "Crenshaw" + } + }, + { + "id": 8178, + "name": "Nunez Callahan", + "gender": "male", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Carrsville" + } + }, + { + "id": 8179, + "name": "Burks English", + "gender": "male", + "age": 48, + "address": { + "state": "Oklahoma", + "city": "Westerville" + } + }, + { + "id": 8180, + "name": "Sandoval Kinney", + "gender": "male", + "age": 38, + "address": { + "state": "New York", + "city": "Wedgewood" + } + }, + { + "id": 8181, + "name": "Rivers Potts", + "gender": "male", + "age": 74, + "address": { + "state": "Idaho", + "city": "Winchester" + } + }, + { + "id": 8182, + "name": "Sally Humphrey", + "gender": "female", + "age": 20, + "address": { + "state": "Illinois", + "city": "Trinway" + } + }, + { + "id": 8183, + "name": "Campos Howard", + "gender": "male", + "age": 36, + "address": { + "state": "California", + "city": "Lacomb" + } + }, + { + "id": 8184, + "name": "Walker Foreman", + "gender": "male", + "age": 48, + "address": { + "state": "Oregon", + "city": "Clinton" + } + }, + { + "id": 8185, + "name": "Bell May", + "gender": "male", + "age": 38, + "address": { + "state": "Illinois", + "city": "Kohatk" + } + }, + { + "id": 8186, + "name": "Rosanne Mathis", + "gender": "female", + "age": 72, + "address": { + "state": "New York", + "city": "Dundee" + } + }, + { + "id": 8187, + "name": "Tricia Callahan", + "gender": "female", + "age": 28, + "address": { + "state": "Utah", + "city": "Fairlee" + } + }, + { + "id": 8188, + "name": "Stacey Mullen", + "gender": "female", + "age": 24, + "address": { + "state": "Nevada", + "city": "Bennett" + } + }, + { + "id": 8189, + "name": "Dianna Park", + "gender": "female", + "age": 38, + "address": { + "state": "Kansas", + "city": "Faxon" + } + }, + { + "id": 8190, + "name": "Soto Knowles", + "gender": "male", + "age": 78, + "address": { + "state": "Alaska", + "city": "Urie" + } + }, + { + "id": 8191, + "name": "Lorna Silva", + "gender": "female", + "age": 35, + "address": { + "state": "Maine", + "city": "Leola" + } + }, + { + "id": 8192, + "name": "Fitzpatrick Stark", + "gender": "male", + "age": 45, + "address": { + "state": "Maryland", + "city": "Lutsen" + } + }, + { + "id": 8193, + "name": "Sheppard Harrison", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Lookingglass" + } + }, + { + "id": 8194, + "name": "Powell Sawyer", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Sunnyside" + } + }, + { + "id": 8195, + "name": "Pate Ingram", + "gender": "male", + "age": 58, + "address": { + "state": "Colorado", + "city": "Macdona" + } + }, + { + "id": 8196, + "name": "Marsh Holland", + "gender": "male", + "age": 73, + "address": { + "state": "West Virginia", + "city": "Riviera" + } + }, + { + "id": 8197, + "name": "Tran Farrell", + "gender": "male", + "age": 24, + "address": { + "state": "Texas", + "city": "Blanford" + } + }, + { + "id": 8198, + "name": "Mcintyre Knight", + "gender": "male", + "age": 49, + "address": { + "state": "Michigan", + "city": "Datil" + } + }, + { + "id": 8199, + "name": "Richard Kirby", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Coral" + } + }, + { + "id": 8200, + "name": "Elena Morin", + "gender": "female", + "age": 40, + "address": { + "state": "Missouri", + "city": "Cliffside" + } + }, + { + "id": 8201, + "name": "Lorene Mcpherson", + "gender": "female", + "age": 60, + "address": { + "state": "Wisconsin", + "city": "Ahwahnee" + } + }, + { + "id": 8202, + "name": "Meadows Walsh", + "gender": "male", + "age": 42, + "address": { + "state": "New Jersey", + "city": "Ballico" + } + }, + { + "id": 8203, + "name": "Angelique Schmidt", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Bedias" + } + }, + { + "id": 8204, + "name": "Edith Cameron", + "gender": "female", + "age": 61, + "address": { + "state": "Idaho", + "city": "Floriston" + } + }, + { + "id": 8205, + "name": "Humphrey Nicholson", + "gender": "male", + "age": 27, + "address": { + "state": "Iowa", + "city": "Columbus" + } + }, + { + "id": 8206, + "name": "Powers Montgomery", + "gender": "male", + "age": 17, + "address": { + "state": "Delaware", + "city": "Robbins" + } + }, + { + "id": 8207, + "name": "Mays Owens", + "gender": "male", + "age": 76, + "address": { + "state": "Rhode Island", + "city": "Enlow" + } + }, + { + "id": 8208, + "name": "Kent Norton", + "gender": "male", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Klagetoh" + } + }, + { + "id": 8209, + "name": "Sellers Stanley", + "gender": "male", + "age": 54, + "address": { + "state": "Ohio", + "city": "Juarez" + } + }, + { + "id": 8210, + "name": "Lowery Vaughn", + "gender": "male", + "age": 21, + "address": { + "state": "New Hampshire", + "city": "Dixie" + } + }, + { + "id": 8211, + "name": "Hogan Burton", + "gender": "male", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Chamberino" + } + }, + { + "id": 8212, + "name": "Lindsay Davidson", + "gender": "male", + "age": 36, + "address": { + "state": "Washington", + "city": "Jacksonburg" + } + }, + { + "id": 8213, + "name": "Molina Marks", + "gender": "male", + "age": 38, + "address": { + "state": "Arizona", + "city": "Torboy" + } + }, + { + "id": 8214, + "name": "Peck Horne", + "gender": "male", + "age": 68, + "address": { + "state": "Arkansas", + "city": "Summertown" + } + }, + { + "id": 8215, + "name": "Moses Buchanan", + "gender": "male", + "age": 60, + "address": { + "state": "Kentucky", + "city": "Carlos" + } + }, + { + "id": 8216, + "name": "Brewer Doyle", + "gender": "male", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Evergreen" + } + }, + { + "id": 8217, + "name": "Kristie Dale", + "gender": "female", + "age": 53, + "address": { + "state": "North Carolina", + "city": "Fresno" + } + }, + { + "id": 8218, + "name": "Estelle Marshall", + "gender": "female", + "age": 26, + "address": { + "state": "Georgia", + "city": "Durham" + } + }, + { + "id": 8219, + "name": "Samantha Pittman", + "gender": "female", + "age": 21, + "address": { + "state": "Virginia", + "city": "Croom" + } + }, + { + "id": 8220, + "name": "Darcy Wooten", + "gender": "female", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Venice" + } + }, + { + "id": 8221, + "name": "Rivers Mathews", + "gender": "male", + "age": 82, + "address": { + "state": "South Dakota", + "city": "Statenville" + } + }, + { + "id": 8222, + "name": "Williamson Santos", + "gender": "male", + "age": 78, + "address": { + "state": "Hawaii", + "city": "Kerby" + } + }, + { + "id": 8223, + "name": "Jacklyn Spence", + "gender": "female", + "age": 35, + "address": { + "state": "Montana", + "city": "Courtland" + } + }, + { + "id": 8224, + "name": "Randolph Berg", + "gender": "male", + "age": 75, + "address": { + "state": "Wyoming", + "city": "Roberts" + } + }, + { + "id": 8225, + "name": "Christi Deleon", + "gender": "female", + "age": 36, + "address": { + "state": "Alabama", + "city": "Linganore" + } + }, + { + "id": 8226, + "name": "Lynn Anderson", + "gender": "female", + "age": 72, + "address": { + "state": "Vermont", + "city": "Bluffview" + } + }, + { + "id": 8227, + "name": "Bobbie Levy", + "gender": "female", + "age": 51, + "address": { + "state": "Nebraska", + "city": "Norwood" + } + }, + { + "id": 8228, + "name": "Roberson Mercer", + "gender": "male", + "age": 24, + "address": { + "state": "Mississippi", + "city": "Gambrills" + } + }, + { + "id": 8229, + "name": "May Griffin", + "gender": "female", + "age": 22, + "address": { + "state": "South Carolina", + "city": "Dalton" + } + }, + { + "id": 8230, + "name": "Pennington Stephens", + "gender": "male", + "age": 70, + "address": { + "state": "Connecticut", + "city": "Loretto" + } + }, + { + "id": 8231, + "name": "Paulette Richard", + "gender": "female", + "age": 71, + "address": { + "state": "Oklahoma", + "city": "Sena" + } + }, + { + "id": 8232, + "name": "Lamb Dillon", + "gender": "male", + "age": 17, + "address": { + "state": "Washington", + "city": "Hampstead" + } + }, + { + "id": 8233, + "name": "Figueroa Murray", + "gender": "male", + "age": 81, + "address": { + "state": "New Jersey", + "city": "Chumuckla" + } + }, + { + "id": 8234, + "name": "Olson Buckner", + "gender": "male", + "age": 53, + "address": { + "state": "Virginia", + "city": "Shelby" + } + }, + { + "id": 8235, + "name": "Grant Ingram", + "gender": "male", + "age": 76, + "address": { + "state": "Nevada", + "city": "Lund" + } + }, + { + "id": 8236, + "name": "Dickerson Mccarty", + "gender": "male", + "age": 73, + "address": { + "state": "Hawaii", + "city": "Oasis" + } + }, + { + "id": 8237, + "name": "Deanna Cobb", + "gender": "female", + "age": 78, + "address": { + "state": "Louisiana", + "city": "Kerby" + } + }, + { + "id": 8238, + "name": "Gonzales Kerr", + "gender": "male", + "age": 19, + "address": { + "state": "Utah", + "city": "Wyoming" + } + }, + { + "id": 8239, + "name": "Chandra Cook", + "gender": "female", + "age": 23, + "address": { + "state": "Iowa", + "city": "Beason" + } + }, + { + "id": 8240, + "name": "Penelope Vincent", + "gender": "female", + "age": 28, + "address": { + "state": "Illinois", + "city": "Greenbackville" + } + }, + { + "id": 8241, + "name": "Estrada Sparks", + "gender": "male", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Limestone" + } + }, + { + "id": 8242, + "name": "Lidia Lee", + "gender": "female", + "age": 34, + "address": { + "state": "Texas", + "city": "Sardis" + } + }, + { + "id": 8243, + "name": "Theresa Ayers", + "gender": "female", + "age": 51, + "address": { + "state": "Michigan", + "city": "Gracey" + } + }, + { + "id": 8244, + "name": "Isabella Roach", + "gender": "female", + "age": 44, + "address": { + "state": "Kentucky", + "city": "Yardville" + } + }, + { + "id": 8245, + "name": "Jodie Gates", + "gender": "female", + "age": 27, + "address": { + "state": "North Carolina", + "city": "Santel" + } + }, + { + "id": 8246, + "name": "Wilda Knight", + "gender": "female", + "age": 55, + "address": { + "state": "Delaware", + "city": "Conestoga" + } + }, + { + "id": 8247, + "name": "Carson Sweeney", + "gender": "male", + "age": 52, + "address": { + "state": "Arizona", + "city": "Walland" + } + }, + { + "id": 8248, + "name": "Mckenzie Soto", + "gender": "male", + "age": 47, + "address": { + "state": "Ohio", + "city": "Camino" + } + }, + { + "id": 8249, + "name": "Vasquez Horne", + "gender": "male", + "age": 42, + "address": { + "state": "Missouri", + "city": "Fruitdale" + } + }, + { + "id": 8250, + "name": "Curry Peck", + "gender": "male", + "age": 82, + "address": { + "state": "Maryland", + "city": "Hartsville/Hartley" + } + }, + { + "id": 8251, + "name": "Parks Pennington", + "gender": "male", + "age": 52, + "address": { + "state": "New Mexico", + "city": "Cresaptown" + } + }, + { + "id": 8252, + "name": "Moss Dorsey", + "gender": "male", + "age": 20, + "address": { + "state": "New Hampshire", + "city": "Trail" + } + }, + { + "id": 8253, + "name": "Norris Lewis", + "gender": "male", + "age": 50, + "address": { + "state": "New York", + "city": "Marysville" + } + }, + { + "id": 8254, + "name": "Michael Cochran", + "gender": "female", + "age": 35, + "address": { + "state": "Indiana", + "city": "Greenfields" + } + }, + { + "id": 8255, + "name": "Acevedo Burris", + "gender": "male", + "age": 21, + "address": { + "state": "Arkansas", + "city": "Ronco" + } + }, + { + "id": 8256, + "name": "Lindsey Gross", + "gender": "female", + "age": 43, + "address": { + "state": "Montana", + "city": "Shasta" + } + }, + { + "id": 8257, + "name": "Malinda Parsons", + "gender": "female", + "age": 45, + "address": { + "state": "Florida", + "city": "Vowinckel" + } + }, + { + "id": 8258, + "name": "Riddle Workman", + "gender": "male", + "age": 22, + "address": { + "state": "Wisconsin", + "city": "Odessa" + } + }, + { + "id": 8259, + "name": "Jenna Kemp", + "gender": "female", + "age": 70, + "address": { + "state": "California", + "city": "Savage" + } + }, + { + "id": 8260, + "name": "Lee Moreno", + "gender": "female", + "age": 50, + "address": { + "state": "Alaska", + "city": "Sattley" + } + }, + { + "id": 8261, + "name": "Walls Donovan", + "gender": "male", + "age": 45, + "address": { + "state": "Massachusetts", + "city": "Saranap" + } + }, + { + "id": 8262, + "name": "Annette Brewer", + "gender": "female", + "age": 76, + "address": { + "state": "Kansas", + "city": "Dennard" + } + }, + { + "id": 8263, + "name": "Christie Noel", + "gender": "female", + "age": 53, + "address": { + "state": "Oregon", + "city": "Williams" + } + }, + { + "id": 8264, + "name": "Ross Wilkerson", + "gender": "male", + "age": 27, + "address": { + "state": "Alabama", + "city": "Bodega" + } + }, + { + "id": 8265, + "name": "Dorothy Freeman", + "gender": "female", + "age": 59, + "address": { + "state": "North Dakota", + "city": "Veyo" + } + }, + { + "id": 8266, + "name": "Jill Rhodes", + "gender": "female", + "age": 72, + "address": { + "state": "Connecticut", + "city": "Bison" + } + }, + { + "id": 8267, + "name": "Guerrero Fisher", + "gender": "male", + "age": 53, + "address": { + "state": "Wyoming", + "city": "Highland" + } + }, + { + "id": 8268, + "name": "Stewart Lang", + "gender": "male", + "age": 28, + "address": { + "state": "Nebraska", + "city": "Russellville" + } + }, + { + "id": 8269, + "name": "Latoya Chapman", + "gender": "female", + "age": 78, + "address": { + "state": "Vermont", + "city": "Frystown" + } + }, + { + "id": 8270, + "name": "Ivy Jarvis", + "gender": "female", + "age": 41, + "address": { + "state": "Oklahoma", + "city": "Farmers" + } + }, + { + "id": 8271, + "name": "Kathryn Nielsen", + "gender": "female", + "age": 53, + "address": { + "state": "Idaho", + "city": "Hickory" + } + }, + { + "id": 8272, + "name": "Morrison Vinson", + "gender": "male", + "age": 69, + "address": { + "state": "West Virginia", + "city": "Chicopee" + } + }, + { + "id": 8273, + "name": "Booker Saunders", + "gender": "male", + "age": 60, + "address": { + "state": "Rhode Island", + "city": "Beaulieu" + } + }, + { + "id": 8274, + "name": "Edith Michael", + "gender": "female", + "age": 40, + "address": { + "state": "South Carolina", + "city": "Abiquiu" + } + }, + { + "id": 8275, + "name": "Dana Griffin", + "gender": "female", + "age": 18, + "address": { + "state": "Maine", + "city": "Whipholt" + } + }, + { + "id": 8276, + "name": "Richard Mcfadden", + "gender": "male", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Waukeenah" + } + }, + { + "id": 8277, + "name": "Jo Vaughn", + "gender": "female", + "age": 55, + "address": { + "state": "Minnesota", + "city": "Whitewater" + } + }, + { + "id": 8278, + "name": "Kirby Cardenas", + "gender": "male", + "age": 82, + "address": { + "state": "South Dakota", + "city": "Avoca" + } + }, + { + "id": 8279, + "name": "Clements Shepard", + "gender": "male", + "age": 34, + "address": { + "state": "Georgia", + "city": "Hondah" + } + }, + { + "id": 8280, + "name": "Mona Barron", + "gender": "female", + "age": 69, + "address": { + "state": "Mississippi", + "city": "Mayfair" + } + }, + { + "id": 8281, + "name": "Hurley Mullen", + "gender": "male", + "age": 52, + "address": { + "state": "New Jersey", + "city": "Vandiver" + } + }, + { + "id": 8282, + "name": "Gray William", + "gender": "male", + "age": 45, + "address": { + "state": "Maine", + "city": "Rosburg" + } + }, + { + "id": 8283, + "name": "Francine Kirk", + "gender": "female", + "age": 74, + "address": { + "state": "Alaska", + "city": "Bentley" + } + }, + { + "id": 8284, + "name": "Joanna Koch", + "gender": "female", + "age": 32, + "address": { + "state": "Wyoming", + "city": "Welch" + } + }, + { + "id": 8285, + "name": "Angelina Knowles", + "gender": "female", + "age": 23, + "address": { + "state": "Washington", + "city": "Escondida" + } + }, + { + "id": 8286, + "name": "Navarro Santana", + "gender": "male", + "age": 54, + "address": { + "state": "Virginia", + "city": "Brenton" + } + }, + { + "id": 8287, + "name": "Stacey Chase", + "gender": "female", + "age": 80, + "address": { + "state": "Ohio", + "city": "Wells" + } + }, + { + "id": 8288, + "name": "Pena Mclaughlin", + "gender": "male", + "age": 49, + "address": { + "state": "New York", + "city": "Noblestown" + } + }, + { + "id": 8289, + "name": "Lucia Mckenzie", + "gender": "female", + "age": 65, + "address": { + "state": "Texas", + "city": "Wildwood" + } + }, + { + "id": 8290, + "name": "Henson Goff", + "gender": "male", + "age": 31, + "address": { + "state": "New Hampshire", + "city": "Bourg" + } + }, + { + "id": 8291, + "name": "Robin Bradshaw", + "gender": "female", + "age": 80, + "address": { + "state": "Iowa", + "city": "Hiko" + } + }, + { + "id": 8292, + "name": "Fisher Gibbs", + "gender": "male", + "age": 76, + "address": { + "state": "North Dakota", + "city": "Avalon" + } + }, + { + "id": 8293, + "name": "Eunice Barnett", + "gender": "female", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Morgandale" + } + }, + { + "id": 8294, + "name": "Myrtle Richmond", + "gender": "female", + "age": 25, + "address": { + "state": "Nebraska", + "city": "Kimmell" + } + }, + { + "id": 8295, + "name": "Valeria Cole", + "gender": "female", + "age": 17, + "address": { + "state": "Louisiana", + "city": "Levant" + } + }, + { + "id": 8296, + "name": "Sasha Bryan", + "gender": "female", + "age": 69, + "address": { + "state": "Maryland", + "city": "Herlong" + } + }, + { + "id": 8297, + "name": "Vincent Douglas", + "gender": "male", + "age": 26, + "address": { + "state": "Georgia", + "city": "Hegins" + } + }, + { + "id": 8298, + "name": "Amelia Wall", + "gender": "female", + "age": 33, + "address": { + "state": "New Mexico", + "city": "Macdona" + } + }, + { + "id": 8299, + "name": "Jaclyn Duran", + "gender": "female", + "age": 31, + "address": { + "state": "Florida", + "city": "Madrid" + } + }, + { + "id": 8300, + "name": "Leona Wells", + "gender": "female", + "age": 19, + "address": { + "state": "Idaho", + "city": "Cornucopia" + } + }, + { + "id": 8301, + "name": "Contreras Dorsey", + "gender": "male", + "age": 22, + "address": { + "state": "Rhode Island", + "city": "Kent" + } + }, + { + "id": 8302, + "name": "Kristen Nicholson", + "gender": "female", + "age": 77, + "address": { + "state": "Utah", + "city": "Ypsilanti" + } + }, + { + "id": 8303, + "name": "Toni Fuller", + "gender": "female", + "age": 52, + "address": { + "state": "Alabama", + "city": "Ola" + } + }, + { + "id": 8304, + "name": "Jennifer Shaw", + "gender": "female", + "age": 44, + "address": { + "state": "Massachusetts", + "city": "Frierson" + } + }, + { + "id": 8305, + "name": "Leonor Phelps", + "gender": "female", + "age": 59, + "address": { + "state": "South Dakota", + "city": "Bellfountain" + } + }, + { + "id": 8306, + "name": "Johnnie Hubbard", + "gender": "female", + "age": 29, + "address": { + "state": "Nevada", + "city": "Whitmer" + } + }, + { + "id": 8307, + "name": "Hollie Nieves", + "gender": "female", + "age": 43, + "address": { + "state": "West Virginia", + "city": "Valle" + } + }, + { + "id": 8308, + "name": "Lorna Terry", + "gender": "female", + "age": 58, + "address": { + "state": "Hawaii", + "city": "Ironton" + } + }, + { + "id": 8309, + "name": "Lacy Hodges", + "gender": "female", + "age": 24, + "address": { + "state": "North Carolina", + "city": "Camino" + } + }, + { + "id": 8310, + "name": "Marissa Williams", + "gender": "female", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Bison" + } + }, + { + "id": 8311, + "name": "Brandie Espinoza", + "gender": "female", + "age": 20, + "address": { + "state": "Kansas", + "city": "Summerset" + } + }, + { + "id": 8312, + "name": "Elena England", + "gender": "female", + "age": 58, + "address": { + "state": "Arizona", + "city": "Finzel" + } + }, + { + "id": 8313, + "name": "Lora Garza", + "gender": "female", + "age": 27, + "address": { + "state": "Mississippi", + "city": "Wheatfields" + } + }, + { + "id": 8314, + "name": "Marsha Tucker", + "gender": "female", + "age": 69, + "address": { + "state": "Michigan", + "city": "Dargan" + } + }, + { + "id": 8315, + "name": "Camille Bauer", + "gender": "female", + "age": 26, + "address": { + "state": "Illinois", + "city": "Belleview" + } + }, + { + "id": 8316, + "name": "Weaver Gentry", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Cumberland" + } + }, + { + "id": 8317, + "name": "Janell Montgomery", + "gender": "female", + "age": 71, + "address": { + "state": "Tennessee", + "city": "Dixie" + } + }, + { + "id": 8318, + "name": "Beverley Blackwell", + "gender": "female", + "age": 77, + "address": { + "state": "Connecticut", + "city": "Warren" + } + }, + { + "id": 8319, + "name": "Garrison Craig", + "gender": "male", + "age": 51, + "address": { + "state": "California", + "city": "Salix" + } + }, + { + "id": 8320, + "name": "Wendi Burris", + "gender": "female", + "age": 58, + "address": { + "state": "Pennsylvania", + "city": "Idledale" + } + }, + { + "id": 8321, + "name": "Mason Morrison", + "gender": "male", + "age": 31, + "address": { + "state": "Minnesota", + "city": "Ribera" + } + }, + { + "id": 8322, + "name": "King Waller", + "gender": "male", + "age": 54, + "address": { + "state": "Colorado", + "city": "Snelling" + } + }, + { + "id": 8323, + "name": "Compton Ramos", + "gender": "male", + "age": 58, + "address": { + "state": "Oregon", + "city": "Echo" + } + }, + { + "id": 8324, + "name": "Mccoy Parrish", + "gender": "male", + "age": 57, + "address": { + "state": "Montana", + "city": "Bradenville" + } + }, + { + "id": 8325, + "name": "Phelps Jordan", + "gender": "male", + "age": 33, + "address": { + "state": "Wisconsin", + "city": "Durham" + } + }, + { + "id": 8326, + "name": "Debbie Shaffer", + "gender": "female", + "age": 19, + "address": { + "state": "Oklahoma", + "city": "Woodlake" + } + }, + { + "id": 8327, + "name": "Lester Pratt", + "gender": "male", + "age": 74, + "address": { + "state": "Missouri", + "city": "Martinez" + } + }, + { + "id": 8328, + "name": "Knight Deleon", + "gender": "male", + "age": 27, + "address": { + "state": "Arkansas", + "city": "Concho" + } + }, + { + "id": 8329, + "name": "Bonnie Parsons", + "gender": "female", + "age": 49, + "address": { + "state": "Vermont", + "city": "Bennett" + } + }, + { + "id": 8330, + "name": "Knox Bonner", + "gender": "male", + "age": 54, + "address": { + "state": "Mississippi", + "city": "Linganore" + } + }, + { + "id": 8331, + "name": "Everett Travis", + "gender": "male", + "age": 45, + "address": { + "state": "Minnesota", + "city": "Jeff" + } + }, + { + "id": 8332, + "name": "Herring Rogers", + "gender": "male", + "age": 21, + "address": { + "state": "South Dakota", + "city": "Diaperville" + } + }, + { + "id": 8333, + "name": "Carson Conrad", + "gender": "male", + "age": 75, + "address": { + "state": "Washington", + "city": "Gardiner" + } + }, + { + "id": 8334, + "name": "Cara Waller", + "gender": "female", + "age": 17, + "address": { + "state": "Kansas", + "city": "Belmont" + } + }, + { + "id": 8335, + "name": "Lawrence Pugh", + "gender": "male", + "age": 32, + "address": { + "state": "California", + "city": "Whitewater" + } + }, + { + "id": 8336, + "name": "Miranda Myers", + "gender": "female", + "age": 80, + "address": { + "state": "Hawaii", + "city": "Glenbrook" + } + }, + { + "id": 8337, + "name": "Amparo Dawson", + "gender": "female", + "age": 68, + "address": { + "state": "Ohio", + "city": "Hiko" + } + }, + { + "id": 8338, + "name": "Cruz Gentry", + "gender": "male", + "age": 68, + "address": { + "state": "New York", + "city": "Cawood" + } + }, + { + "id": 8339, + "name": "Shelby Richmond", + "gender": "female", + "age": 36, + "address": { + "state": "Kentucky", + "city": "Frank" + } + }, + { + "id": 8340, + "name": "Althea Tate", + "gender": "female", + "age": 49, + "address": { + "state": "Nevada", + "city": "Cornucopia" + } + }, + { + "id": 8341, + "name": "Mercado Long", + "gender": "male", + "age": 48, + "address": { + "state": "Alabama", + "city": "Coloma" + } + }, + { + "id": 8342, + "name": "Adriana Delacruz", + "gender": "female", + "age": 62, + "address": { + "state": "Connecticut", + "city": "Nescatunga" + } + }, + { + "id": 8343, + "name": "Baxter Wiggins", + "gender": "male", + "age": 81, + "address": { + "state": "Oklahoma", + "city": "Lund" + } + }, + { + "id": 8344, + "name": "Blanchard Young", + "gender": "male", + "age": 43, + "address": { + "state": "Tennessee", + "city": "Sunbury" + } + }, + { + "id": 8345, + "name": "Hubbard Murphy", + "gender": "male", + "age": 66, + "address": { + "state": "Massachusetts", + "city": "Ellerslie" + } + }, + { + "id": 8346, + "name": "Eliza Mcclure", + "gender": "female", + "age": 45, + "address": { + "state": "Arizona", + "city": "Cannondale" + } + }, + { + "id": 8347, + "name": "Tammie Fitzgerald", + "gender": "female", + "age": 64, + "address": { + "state": "Rhode Island", + "city": "Johnsonburg" + } + }, + { + "id": 8348, + "name": "Nanette Williams", + "gender": "female", + "age": 47, + "address": { + "state": "Missouri", + "city": "Glenville" + } + }, + { + "id": 8349, + "name": "Leta Todd", + "gender": "female", + "age": 32, + "address": { + "state": "Colorado", + "city": "Fillmore" + } + }, + { + "id": 8350, + "name": "Cortez Noble", + "gender": "male", + "age": 42, + "address": { + "state": "Louisiana", + "city": "Benson" + } + }, + { + "id": 8351, + "name": "Berger Baldwin", + "gender": "male", + "age": 19, + "address": { + "state": "Pennsylvania", + "city": "Allendale" + } + }, + { + "id": 8352, + "name": "Osborne Santiago", + "gender": "male", + "age": 21, + "address": { + "state": "Maryland", + "city": "Norfolk" + } + }, + { + "id": 8353, + "name": "Frances Sanchez", + "gender": "female", + "age": 65, + "address": { + "state": "Delaware", + "city": "Worton" + } + }, + { + "id": 8354, + "name": "Elisa Strong", + "gender": "female", + "age": 44, + "address": { + "state": "Texas", + "city": "Foxworth" + } + }, + { + "id": 8355, + "name": "Meyer Blackwell", + "gender": "male", + "age": 27, + "address": { + "state": "Illinois", + "city": "Bradenville" + } + }, + { + "id": 8356, + "name": "Blair Sellers", + "gender": "male", + "age": 40, + "address": { + "state": "Wisconsin", + "city": "Century" + } + }, + { + "id": 8357, + "name": "Mccall Valdez", + "gender": "male", + "age": 72, + "address": { + "state": "Georgia", + "city": "Outlook" + } + }, + { + "id": 8358, + "name": "Lori Daniel", + "gender": "female", + "age": 59, + "address": { + "state": "Nebraska", + "city": "Chapin" + } + }, + { + "id": 8359, + "name": "Diana Clarke", + "gender": "female", + "age": 44, + "address": { + "state": "Vermont", + "city": "Gwynn" + } + }, + { + "id": 8360, + "name": "Lesa Salinas", + "gender": "female", + "age": 66, + "address": { + "state": "Michigan", + "city": "Beechmont" + } + }, + { + "id": 8361, + "name": "Weeks Hendricks", + "gender": "male", + "age": 51, + "address": { + "state": "Wyoming", + "city": "Cumberland" + } + }, + { + "id": 8362, + "name": "Angeline Kidd", + "gender": "female", + "age": 26, + "address": { + "state": "South Carolina", + "city": "Oretta" + } + }, + { + "id": 8363, + "name": "Snyder Hebert", + "gender": "male", + "age": 48, + "address": { + "state": "West Virginia", + "city": "Coventry" + } + }, + { + "id": 8364, + "name": "Freida Freeman", + "gender": "female", + "age": 20, + "address": { + "state": "Arkansas", + "city": "Richmond" + } + }, + { + "id": 8365, + "name": "Solomon Lloyd", + "gender": "male", + "age": 41, + "address": { + "state": "New Jersey", + "city": "Ilchester" + } + }, + { + "id": 8366, + "name": "Luella Sosa", + "gender": "female", + "age": 48, + "address": { + "state": "Utah", + "city": "Brecon" + } + }, + { + "id": 8367, + "name": "Atkins Hobbs", + "gender": "male", + "age": 78, + "address": { + "state": "Indiana", + "city": "Forbestown" + } + }, + { + "id": 8368, + "name": "Marsh Morin", + "gender": "male", + "age": 20, + "address": { + "state": "Iowa", + "city": "Dellview" + } + }, + { + "id": 8369, + "name": "Rivers Coffey", + "gender": "male", + "age": 70, + "address": { + "state": "New Hampshire", + "city": "Nicholson" + } + }, + { + "id": 8370, + "name": "Merritt Burton", + "gender": "male", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Manitou" + } + }, + { + "id": 8371, + "name": "Marcie Holmes", + "gender": "female", + "age": 51, + "address": { + "state": "Alaska", + "city": "Ripley" + } + }, + { + "id": 8372, + "name": "Mclaughlin Barber", + "gender": "male", + "age": 62, + "address": { + "state": "Florida", + "city": "Darbydale" + } + }, + { + "id": 8373, + "name": "Charity Anthony", + "gender": "female", + "age": 43, + "address": { + "state": "Virginia", + "city": "Gambrills" + } + }, + { + "id": 8374, + "name": "Terrie Greene", + "gender": "female", + "age": 20, + "address": { + "state": "North Dakota", + "city": "Elwood" + } + }, + { + "id": 8375, + "name": "Patterson Reyes", + "gender": "male", + "age": 29, + "address": { + "state": "New Mexico", + "city": "Jackpot" + } + }, + { + "id": 8376, + "name": "Vicki Figueroa", + "gender": "female", + "age": 50, + "address": { + "state": "Maine", + "city": "Rutherford" + } + }, + { + "id": 8377, + "name": "Josefina Snyder", + "gender": "female", + "age": 67, + "address": { + "state": "Idaho", + "city": "Camptown" + } + }, + { + "id": 8378, + "name": "Barlow Burgess", + "gender": "male", + "age": 47, + "address": { + "state": "Oregon", + "city": "Bluffview" + } + }, + { + "id": 8379, + "name": "Curtis Kline", + "gender": "male", + "age": 44, + "address": { + "state": "Iowa", + "city": "Delwood" + } + }, + { + "id": 8380, + "name": "Ana Chase", + "gender": "female", + "age": 72, + "address": { + "state": "Wisconsin", + "city": "Gloucester" + } + }, + { + "id": 8381, + "name": "Kaitlin Sexton", + "gender": "female", + "age": 50, + "address": { + "state": "Alabama", + "city": "Kingstowne" + } + }, + { + "id": 8382, + "name": "Nielsen Gregory", + "gender": "male", + "age": 45, + "address": { + "state": "Illinois", + "city": "Mapletown" + } + }, + { + "id": 8383, + "name": "Jenny Wallace", + "gender": "female", + "age": 82, + "address": { + "state": "North Dakota", + "city": "Shrewsbury" + } + }, + { + "id": 8384, + "name": "Wheeler Bryant", + "gender": "male", + "age": 80, + "address": { + "state": "Pennsylvania", + "city": "Emerald" + } + }, + { + "id": 8385, + "name": "Patricia Barlow", + "gender": "female", + "age": 50, + "address": { + "state": "Vermont", + "city": "Guilford" + } + }, + { + "id": 8386, + "name": "Tran Zamora", + "gender": "male", + "age": 48, + "address": { + "state": "Rhode Island", + "city": "Stockdale" + } + }, + { + "id": 8387, + "name": "Pearl Wise", + "gender": "female", + "age": 30, + "address": { + "state": "Washington", + "city": "Wauhillau" + } + }, + { + "id": 8388, + "name": "Frye Kaufman", + "gender": "male", + "age": 28, + "address": { + "state": "Minnesota", + "city": "Hall" + } + }, + { + "id": 8389, + "name": "Catalina Villarreal", + "gender": "female", + "age": 60, + "address": { + "state": "Idaho", + "city": "Slovan" + } + }, + { + "id": 8390, + "name": "Maritza Winters", + "gender": "female", + "age": 56, + "address": { + "state": "Arkansas", + "city": "Jacksonwald" + } + }, + { + "id": 8391, + "name": "Alberta Huffman", + "gender": "female", + "age": 71, + "address": { + "state": "Michigan", + "city": "Bradenville" + } + }, + { + "id": 8392, + "name": "Elsa Perez", + "gender": "female", + "age": 80, + "address": { + "state": "Kentucky", + "city": "Walton" + } + }, + { + "id": 8393, + "name": "Opal Mcbride", + "gender": "female", + "age": 19, + "address": { + "state": "Maine", + "city": "Harborton" + } + }, + { + "id": 8394, + "name": "Lela Merrill", + "gender": "female", + "age": 45, + "address": { + "state": "Ohio", + "city": "Jardine" + } + }, + { + "id": 8395, + "name": "Nona Banks", + "gender": "female", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Cassel" + } + }, + { + "id": 8396, + "name": "Cote Ferguson", + "gender": "male", + "age": 51, + "address": { + "state": "South Carolina", + "city": "Edenburg" + } + }, + { + "id": 8397, + "name": "Burgess Mathis", + "gender": "male", + "age": 43, + "address": { + "state": "Colorado", + "city": "Orovada" + } + }, + { + "id": 8398, + "name": "Clara Richards", + "gender": "female", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Dunbar" + } + }, + { + "id": 8399, + "name": "Tina Joyce", + "gender": "female", + "age": 29, + "address": { + "state": "Indiana", + "city": "Whitmer" + } + }, + { + "id": 8400, + "name": "Elisa Peters", + "gender": "female", + "age": 46, + "address": { + "state": "Tennessee", + "city": "Gibbsville" + } + }, + { + "id": 8401, + "name": "Bernadine Stark", + "gender": "female", + "age": 25, + "address": { + "state": "New York", + "city": "Montura" + } + }, + { + "id": 8402, + "name": "Schmidt Cherry", + "gender": "male", + "age": 38, + "address": { + "state": "New Hampshire", + "city": "Epworth" + } + }, + { + "id": 8403, + "name": "Aisha Curtis", + "gender": "female", + "age": 66, + "address": { + "state": "North Carolina", + "city": "Como" + } + }, + { + "id": 8404, + "name": "Carissa Campos", + "gender": "female", + "age": 39, + "address": { + "state": "New Mexico", + "city": "Nord" + } + }, + { + "id": 8405, + "name": "Jewell Crane", + "gender": "female", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Kempton" + } + }, + { + "id": 8406, + "name": "Alisha Dean", + "gender": "female", + "age": 57, + "address": { + "state": "Louisiana", + "city": "Woodlake" + } + }, + { + "id": 8407, + "name": "Bruce Hanson", + "gender": "male", + "age": 22, + "address": { + "state": "Texas", + "city": "Wiscon" + } + }, + { + "id": 8408, + "name": "Clare Haney", + "gender": "female", + "age": 31, + "address": { + "state": "Kansas", + "city": "Matthews" + } + }, + { + "id": 8409, + "name": "Pope Albert", + "gender": "male", + "age": 72, + "address": { + "state": "Wyoming", + "city": "Bowden" + } + }, + { + "id": 8410, + "name": "Wood Mcdonald", + "gender": "male", + "age": 38, + "address": { + "state": "Missouri", + "city": "Bainbridge" + } + }, + { + "id": 8411, + "name": "Carson Knapp", + "gender": "male", + "age": 81, + "address": { + "state": "Arizona", + "city": "Sylvanite" + } + }, + { + "id": 8412, + "name": "Margaret Jenkins", + "gender": "female", + "age": 40, + "address": { + "state": "Delaware", + "city": "Cuylerville" + } + }, + { + "id": 8413, + "name": "Berry Phillips", + "gender": "male", + "age": 53, + "address": { + "state": "South Dakota", + "city": "Thatcher" + } + }, + { + "id": 8414, + "name": "Claudine Dillard", + "gender": "female", + "age": 69, + "address": { + "state": "Florida", + "city": "Chaparrito" + } + }, + { + "id": 8415, + "name": "Margret Hunt", + "gender": "female", + "age": 72, + "address": { + "state": "West Virginia", + "city": "Leroy" + } + }, + { + "id": 8416, + "name": "Cook Stout", + "gender": "male", + "age": 22, + "address": { + "state": "Georgia", + "city": "Glasgow" + } + }, + { + "id": 8417, + "name": "Griffin Cote", + "gender": "male", + "age": 53, + "address": { + "state": "Connecticut", + "city": "Lupton" + } + }, + { + "id": 8418, + "name": "Davis Horton", + "gender": "male", + "age": 69, + "address": { + "state": "Nevada", + "city": "Silkworth" + } + }, + { + "id": 8419, + "name": "Schultz Stanley", + "gender": "male", + "age": 73, + "address": { + "state": "Virginia", + "city": "Thermal" + } + }, + { + "id": 8420, + "name": "Larsen William", + "gender": "male", + "age": 57, + "address": { + "state": "Oklahoma", + "city": "Windsor" + } + }, + { + "id": 8421, + "name": "Magdalena Rasmussen", + "gender": "female", + "age": 49, + "address": { + "state": "California", + "city": "Herald" + } + }, + { + "id": 8422, + "name": "Rojas Noel", + "gender": "male", + "age": 61, + "address": { + "state": "Alaska", + "city": "Lafferty" + } + }, + { + "id": 8423, + "name": "Russell Randall", + "gender": "male", + "age": 47, + "address": { + "state": "New Jersey", + "city": "Chestnut" + } + }, + { + "id": 8424, + "name": "Park Cunningham", + "gender": "male", + "age": 46, + "address": { + "state": "Nebraska", + "city": "Bordelonville" + } + }, + { + "id": 8425, + "name": "Kim Kennedy", + "gender": "female", + "age": 71, + "address": { + "state": "Maryland", + "city": "Greer" + } + }, + { + "id": 8426, + "name": "Robin Bolton", + "gender": "female", + "age": 24, + "address": { + "state": "Utah", + "city": "Cherokee" + } + }, + { + "id": 8427, + "name": "Washington Gordon", + "gender": "male", + "age": 55, + "address": { + "state": "Oregon", + "city": "Whitestone" + } + }, + { + "id": 8428, + "name": "Blake Summers", + "gender": "male", + "age": 69, + "address": { + "state": "Indiana", + "city": "Carlton" + } + }, + { + "id": 8429, + "name": "Eve Dyer", + "gender": "female", + "age": 30, + "address": { + "state": "Colorado", + "city": "Croom" + } + }, + { + "id": 8430, + "name": "Keisha York", + "gender": "female", + "age": 78, + "address": { + "state": "Iowa", + "city": "Avalon" + } + }, + { + "id": 8431, + "name": "Dunlap James", + "gender": "male", + "age": 57, + "address": { + "state": "Texas", + "city": "Jacumba" + } + }, + { + "id": 8432, + "name": "Rowland Melton", + "gender": "male", + "age": 72, + "address": { + "state": "Alaska", + "city": "Allensworth" + } + }, + { + "id": 8433, + "name": "Corine Lamb", + "gender": "female", + "age": 60, + "address": { + "state": "Georgia", + "city": "Fairmount" + } + }, + { + "id": 8434, + "name": "Ester Washington", + "gender": "female", + "age": 80, + "address": { + "state": "California", + "city": "Hollymead" + } + }, + { + "id": 8435, + "name": "Laurel Sawyer", + "gender": "female", + "age": 62, + "address": { + "state": "Minnesota", + "city": "Coloma" + } + }, + { + "id": 8436, + "name": "Chrystal Frost", + "gender": "female", + "age": 48, + "address": { + "state": "West Virginia", + "city": "Ona" + } + }, + { + "id": 8437, + "name": "Jolene Miranda", + "gender": "female", + "age": 44, + "address": { + "state": "Maryland", + "city": "Foxworth" + } + }, + { + "id": 8438, + "name": "Angie Campbell", + "gender": "female", + "age": 38, + "address": { + "state": "Arkansas", + "city": "Madrid" + } + }, + { + "id": 8439, + "name": "Spears Castro", + "gender": "male", + "age": 64, + "address": { + "state": "Virginia", + "city": "Roberts" + } + }, + { + "id": 8440, + "name": "Marguerite Walls", + "gender": "female", + "age": 68, + "address": { + "state": "Kansas", + "city": "Gerber" + } + }, + { + "id": 8441, + "name": "Jenna Snider", + "gender": "female", + "age": 29, + "address": { + "state": "North Dakota", + "city": "Mayfair" + } + }, + { + "id": 8442, + "name": "Hall Buck", + "gender": "male", + "age": 35, + "address": { + "state": "Mississippi", + "city": "Sandston" + } + }, + { + "id": 8443, + "name": "Mcclain Holder", + "gender": "male", + "age": 30, + "address": { + "state": "Hawaii", + "city": "Fairacres" + } + }, + { + "id": 8444, + "name": "Avery Curry", + "gender": "male", + "age": 75, + "address": { + "state": "Montana", + "city": "Hondah" + } + }, + { + "id": 8445, + "name": "Jane Cannon", + "gender": "female", + "age": 19, + "address": { + "state": "Louisiana", + "city": "Islandia" + } + }, + { + "id": 8446, + "name": "Boone Franks", + "gender": "male", + "age": 17, + "address": { + "state": "Connecticut", + "city": "Vandiver" + } + }, + { + "id": 8447, + "name": "Reed Glass", + "gender": "male", + "age": 44, + "address": { + "state": "Ohio", + "city": "Kilbourne" + } + }, + { + "id": 8448, + "name": "Rosalyn Fry", + "gender": "female", + "age": 25, + "address": { + "state": "Kentucky", + "city": "Soham" + } + }, + { + "id": 8449, + "name": "James Jennings", + "gender": "male", + "age": 69, + "address": { + "state": "New York", + "city": "Takilma" + } + }, + { + "id": 8450, + "name": "Burton Henson", + "gender": "male", + "age": 38, + "address": { + "state": "Wisconsin", + "city": "Como" + } + }, + { + "id": 8451, + "name": "Corina Daniels", + "gender": "female", + "age": 56, + "address": { + "state": "Washington", + "city": "Lemoyne" + } + }, + { + "id": 8452, + "name": "Juliette Farmer", + "gender": "female", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Churchill" + } + }, + { + "id": 8453, + "name": "Huffman Pearson", + "gender": "male", + "age": 69, + "address": { + "state": "North Carolina", + "city": "Zarephath" + } + }, + { + "id": 8454, + "name": "Luisa Phillips", + "gender": "female", + "age": 44, + "address": { + "state": "Wyoming", + "city": "Muse" + } + }, + { + "id": 8455, + "name": "Virgie Woods", + "gender": "female", + "age": 49, + "address": { + "state": "New Jersey", + "city": "Utting" + } + }, + { + "id": 8456, + "name": "Georgina Owen", + "gender": "female", + "age": 53, + "address": { + "state": "Oregon", + "city": "Carbonville" + } + }, + { + "id": 8457, + "name": "Autumn Hubbard", + "gender": "female", + "age": 76, + "address": { + "state": "South Dakota", + "city": "Zeba" + } + }, + { + "id": 8458, + "name": "Bettie Fisher", + "gender": "female", + "age": 20, + "address": { + "state": "Tennessee", + "city": "Datil" + } + }, + { + "id": 8459, + "name": "Osborn Leblanc", + "gender": "male", + "age": 53, + "address": { + "state": "Alabama", + "city": "Vicksburg" + } + }, + { + "id": 8460, + "name": "Guzman Bell", + "gender": "male", + "age": 43, + "address": { + "state": "Oklahoma", + "city": "Virgie" + } + }, + { + "id": 8461, + "name": "Aileen Schneider", + "gender": "female", + "age": 41, + "address": { + "state": "Maine", + "city": "Tyhee" + } + }, + { + "id": 8462, + "name": "Roach Carroll", + "gender": "male", + "age": 30, + "address": { + "state": "Nebraska", + "city": "Abiquiu" + } + }, + { + "id": 8463, + "name": "Stokes Gordon", + "gender": "male", + "age": 60, + "address": { + "state": "Idaho", + "city": "Basye" + } + }, + { + "id": 8464, + "name": "Cameron Munoz", + "gender": "male", + "age": 32, + "address": { + "state": "Michigan", + "city": "Mulino" + } + }, + { + "id": 8465, + "name": "Barr Carson", + "gender": "male", + "age": 62, + "address": { + "state": "Vermont", + "city": "Gilgo" + } + }, + { + "id": 8466, + "name": "Contreras Mendoza", + "gender": "male", + "age": 73, + "address": { + "state": "Illinois", + "city": "Hasty" + } + }, + { + "id": 8467, + "name": "Kristie Yates", + "gender": "female", + "age": 35, + "address": { + "state": "Arizona", + "city": "Holcombe" + } + }, + { + "id": 8468, + "name": "Janell Jacobson", + "gender": "female", + "age": 74, + "address": { + "state": "Rhode Island", + "city": "Woodruff" + } + }, + { + "id": 8469, + "name": "Brooks Reyes", + "gender": "male", + "age": 18, + "address": { + "state": "Missouri", + "city": "Blandburg" + } + }, + { + "id": 8470, + "name": "Houston Gillespie", + "gender": "male", + "age": 19, + "address": { + "state": "New Hampshire", + "city": "Inkerman" + } + }, + { + "id": 8471, + "name": "Cortez Hester", + "gender": "male", + "age": 46, + "address": { + "state": "Florida", + "city": "Manila" + } + }, + { + "id": 8472, + "name": "Rosie Flynn", + "gender": "female", + "age": 47, + "address": { + "state": "South Carolina", + "city": "Whitewater" + } + }, + { + "id": 8473, + "name": "Patel Reese", + "gender": "male", + "age": 24, + "address": { + "state": "Utah", + "city": "Bethany" + } + }, + { + "id": 8474, + "name": "Hernandez Murphy", + "gender": "male", + "age": 38, + "address": { + "state": "Delaware", + "city": "Hoagland" + } + }, + { + "id": 8475, + "name": "Maritza Sosa", + "gender": "female", + "age": 32, + "address": { + "state": "Massachusetts", + "city": "Oneida" + } + }, + { + "id": 8476, + "name": "Gloria Pace", + "gender": "female", + "age": 79, + "address": { + "state": "Nevada", + "city": "Springville" + } + }, + { + "id": 8477, + "name": "Nannie Nicholson", + "gender": "female", + "age": 36, + "address": { + "state": "North Carolina", + "city": "Venice" + } + }, + { + "id": 8478, + "name": "William Rivers", + "gender": "male", + "age": 34, + "address": { + "state": "Connecticut", + "city": "Nicut" + } + }, + { + "id": 8479, + "name": "Morales Rivas", + "gender": "male", + "age": 40, + "address": { + "state": "Pennsylvania", + "city": "Stockdale" + } + }, + { + "id": 8480, + "name": "Katy Ware", + "gender": "female", + "age": 54, + "address": { + "state": "Vermont", + "city": "Cataract" + } + }, + { + "id": 8481, + "name": "Dyer Soto", + "gender": "male", + "age": 81, + "address": { + "state": "Kentucky", + "city": "Blanford" + } + }, + { + "id": 8482, + "name": "Mercedes Phelps", + "gender": "female", + "age": 73, + "address": { + "state": "Texas", + "city": "Alamo" + } + }, + { + "id": 8483, + "name": "Anita Mccall", + "gender": "female", + "age": 27, + "address": { + "state": "Georgia", + "city": "Choctaw" + } + }, + { + "id": 8484, + "name": "Brandie Joyce", + "gender": "female", + "age": 47, + "address": { + "state": "New Hampshire", + "city": "Tetherow" + } + }, + { + "id": 8485, + "name": "Ilene Cunningham", + "gender": "female", + "age": 18, + "address": { + "state": "Nevada", + "city": "Kilbourne" + } + }, + { + "id": 8486, + "name": "Suzanne Hester", + "gender": "female", + "age": 79, + "address": { + "state": "Mississippi", + "city": "Riviera" + } + }, + { + "id": 8487, + "name": "Danielle Morrow", + "gender": "female", + "age": 65, + "address": { + "state": "Rhode Island", + "city": "Marysville" + } + }, + { + "id": 8488, + "name": "Randolph Stafford", + "gender": "male", + "age": 32, + "address": { + "state": "Massachusetts", + "city": "Mappsville" + } + }, + { + "id": 8489, + "name": "Cora Mack", + "gender": "female", + "age": 66, + "address": { + "state": "Iowa", + "city": "Ezel" + } + }, + { + "id": 8490, + "name": "Sophia Cobb", + "gender": "female", + "age": 27, + "address": { + "state": "New York", + "city": "Hackneyville" + } + }, + { + "id": 8491, + "name": "Benson Allen", + "gender": "male", + "age": 40, + "address": { + "state": "Oklahoma", + "city": "Canoochee" + } + }, + { + "id": 8492, + "name": "Bradford Farmer", + "gender": "male", + "age": 62, + "address": { + "state": "Hawaii", + "city": "Turah" + } + }, + { + "id": 8493, + "name": "Gamble Arnold", + "gender": "male", + "age": 68, + "address": { + "state": "Florida", + "city": "Ypsilanti" + } + }, + { + "id": 8494, + "name": "Jaime Frost", + "gender": "female", + "age": 64, + "address": { + "state": "Wyoming", + "city": "Tedrow" + } + }, + { + "id": 8495, + "name": "Chandra Hull", + "gender": "female", + "age": 33, + "address": { + "state": "Colorado", + "city": "Colton" + } + }, + { + "id": 8496, + "name": "Lourdes Mcknight", + "gender": "female", + "age": 18, + "address": { + "state": "Illinois", + "city": "Gracey" + } + }, + { + "id": 8497, + "name": "Corinne Robertson", + "gender": "female", + "age": 52, + "address": { + "state": "Arkansas", + "city": "Cecilia" + } + }, + { + "id": 8498, + "name": "Clare Fitzpatrick", + "gender": "female", + "age": 48, + "address": { + "state": "Indiana", + "city": "Nutrioso" + } + }, + { + "id": 8499, + "name": "Pratt Nolan", + "gender": "male", + "age": 73, + "address": { + "state": "North Dakota", + "city": "Shrewsbury" + } + }, + { + "id": 8500, + "name": "Donaldson Powell", + "gender": "male", + "age": 68, + "address": { + "state": "California", + "city": "Marion" + } + }, + { + "id": 8501, + "name": "Ingram Fulton", + "gender": "male", + "age": 36, + "address": { + "state": "Delaware", + "city": "Ola" + } + }, + { + "id": 8502, + "name": "Lynda King", + "gender": "female", + "age": 72, + "address": { + "state": "New Jersey", + "city": "Stewartville" + } + }, + { + "id": 8503, + "name": "Rocha Mayo", + "gender": "male", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Springdale" + } + }, + { + "id": 8504, + "name": "Arline Hoffman", + "gender": "female", + "age": 48, + "address": { + "state": "Idaho", + "city": "Dorneyville" + } + }, + { + "id": 8505, + "name": "Amie Maddox", + "gender": "female", + "age": 49, + "address": { + "state": "Maryland", + "city": "Winchester" + } + }, + { + "id": 8506, + "name": "Mara Waller", + "gender": "female", + "age": 44, + "address": { + "state": "New Mexico", + "city": "Konterra" + } + }, + { + "id": 8507, + "name": "Rivera Russell", + "gender": "male", + "age": 43, + "address": { + "state": "Alabama", + "city": "Genoa" + } + }, + { + "id": 8508, + "name": "Kimberly Forbes", + "gender": "female", + "age": 71, + "address": { + "state": "Arizona", + "city": "Esmont" + } + }, + { + "id": 8509, + "name": "Merritt Landry", + "gender": "male", + "age": 66, + "address": { + "state": "Nebraska", + "city": "Advance" + } + }, + { + "id": 8510, + "name": "Deloris Gutierrez", + "gender": "female", + "age": 45, + "address": { + "state": "Washington", + "city": "Windsor" + } + }, + { + "id": 8511, + "name": "Virginia Guerrero", + "gender": "female", + "age": 50, + "address": { + "state": "Louisiana", + "city": "Chamberino" + } + }, + { + "id": 8512, + "name": "Kristine Hodges", + "gender": "female", + "age": 40, + "address": { + "state": "Tennessee", + "city": "Thornport" + } + }, + { + "id": 8513, + "name": "Preston Holder", + "gender": "male", + "age": 35, + "address": { + "state": "Minnesota", + "city": "Edinburg" + } + }, + { + "id": 8514, + "name": "Kristin Coffey", + "gender": "female", + "age": 82, + "address": { + "state": "Oregon", + "city": "Elrama" + } + }, + { + "id": 8515, + "name": "Bridgette Goodman", + "gender": "female", + "age": 57, + "address": { + "state": "Maine", + "city": "Bethany" + } + }, + { + "id": 8516, + "name": "Mckee Kramer", + "gender": "male", + "age": 32, + "address": { + "state": "South Carolina", + "city": "Eastvale" + } + }, + { + "id": 8517, + "name": "Guerrero Oliver", + "gender": "male", + "age": 49, + "address": { + "state": "Virginia", + "city": "Watchtower" + } + }, + { + "id": 8518, + "name": "Mcconnell Oconnor", + "gender": "male", + "age": 55, + "address": { + "state": "Ohio", + "city": "Biehle" + } + }, + { + "id": 8519, + "name": "Nikki Jones", + "gender": "female", + "age": 67, + "address": { + "state": "Utah", + "city": "Chesterfield" + } + }, + { + "id": 8520, + "name": "Hoffman Donaldson", + "gender": "male", + "age": 39, + "address": { + "state": "South Dakota", + "city": "Orovada" + } + }, + { + "id": 8521, + "name": "Hart Haley", + "gender": "male", + "age": 76, + "address": { + "state": "Alaska", + "city": "Groveville" + } + }, + { + "id": 8522, + "name": "Blanchard Henson", + "gender": "male", + "age": 29, + "address": { + "state": "Montana", + "city": "Ebro" + } + }, + { + "id": 8523, + "name": "Vang Wilkinson", + "gender": "male", + "age": 28, + "address": { + "state": "Michigan", + "city": "Urbana" + } + }, + { + "id": 8524, + "name": "Elnora Nelson", + "gender": "female", + "age": 45, + "address": { + "state": "Kansas", + "city": "Allamuchy" + } + }, + { + "id": 8525, + "name": "Dale Young", + "gender": "female", + "age": 55, + "address": { + "state": "Missouri", + "city": "Ballico" + } + }, + { + "id": 8526, + "name": "Aisha Weeks", + "gender": "female", + "age": 38, + "address": { + "state": "Maine", + "city": "Hinsdale" + } + }, + { + "id": 8527, + "name": "Humphrey Lyons", + "gender": "male", + "age": 56, + "address": { + "state": "Kentucky", + "city": "Lithium" + } + }, + { + "id": 8528, + "name": "Shannon Zamora", + "gender": "female", + "age": 70, + "address": { + "state": "Louisiana", + "city": "Darbydale" + } + }, + { + "id": 8529, + "name": "Abigail Harrington", + "gender": "female", + "age": 22, + "address": { + "state": "Idaho", + "city": "Madaket" + } + }, + { + "id": 8530, + "name": "Landry Clark", + "gender": "male", + "age": 72, + "address": { + "state": "Kansas", + "city": "Crucible" + } + }, + { + "id": 8531, + "name": "Susana Gamble", + "gender": "female", + "age": 37, + "address": { + "state": "Texas", + "city": "Hilltop" + } + }, + { + "id": 8532, + "name": "Valentine Taylor", + "gender": "male", + "age": 47, + "address": { + "state": "Montana", + "city": "Guilford" + } + }, + { + "id": 8533, + "name": "Holman Levine", + "gender": "male", + "age": 71, + "address": { + "state": "Minnesota", + "city": "Comptche" + } + }, + { + "id": 8534, + "name": "Ramos Buchanan", + "gender": "male", + "age": 71, + "address": { + "state": "Connecticut", + "city": "Greenfields" + } + }, + { + "id": 8535, + "name": "Henderson Shields", + "gender": "male", + "age": 65, + "address": { + "state": "Iowa", + "city": "Johnsonburg" + } + }, + { + "id": 8536, + "name": "Strickland Cobb", + "gender": "male", + "age": 38, + "address": { + "state": "New Jersey", + "city": "Abiquiu" + } + }, + { + "id": 8537, + "name": "Mccray Gray", + "gender": "male", + "age": 75, + "address": { + "state": "Pennsylvania", + "city": "Sardis" + } + }, + { + "id": 8538, + "name": "Rutledge Glass", + "gender": "male", + "age": 52, + "address": { + "state": "Nebraska", + "city": "Bagtown" + } + }, + { + "id": 8539, + "name": "Grant Kramer", + "gender": "male", + "age": 70, + "address": { + "state": "Colorado", + "city": "Kent" + } + }, + { + "id": 8540, + "name": "Lowe Carrillo", + "gender": "male", + "age": 76, + "address": { + "state": "Missouri", + "city": "Elbert" + } + }, + { + "id": 8541, + "name": "Brewer Hurst", + "gender": "male", + "age": 56, + "address": { + "state": "Tennessee", + "city": "Jenkinsville" + } + }, + { + "id": 8542, + "name": "Sasha Tucker", + "gender": "female", + "age": 25, + "address": { + "state": "Ohio", + "city": "Windsor" + } + }, + { + "id": 8543, + "name": "Doris Morgan", + "gender": "female", + "age": 19, + "address": { + "state": "Virginia", + "city": "Waikele" + } + }, + { + "id": 8544, + "name": "Love Gregory", + "gender": "male", + "age": 72, + "address": { + "state": "Massachusetts", + "city": "Bendon" + } + }, + { + "id": 8545, + "name": "Jacqueline Raymond", + "gender": "female", + "age": 30, + "address": { + "state": "Illinois", + "city": "Moscow" + } + }, + { + "id": 8546, + "name": "Dionne Hensley", + "gender": "female", + "age": 57, + "address": { + "state": "Vermont", + "city": "Tetherow" + } + }, + { + "id": 8547, + "name": "Estrada Irwin", + "gender": "male", + "age": 73, + "address": { + "state": "New Hampshire", + "city": "Newry" + } + }, + { + "id": 8548, + "name": "Sparks Golden", + "gender": "male", + "age": 53, + "address": { + "state": "Utah", + "city": "Wacissa" + } + }, + { + "id": 8549, + "name": "Burton Odom", + "gender": "male", + "age": 61, + "address": { + "state": "Arizona", + "city": "Crayne" + } + }, + { + "id": 8550, + "name": "Sheppard Joyner", + "gender": "male", + "age": 29, + "address": { + "state": "Rhode Island", + "city": "Martinez" + } + }, + { + "id": 8551, + "name": "Sherman Phelps", + "gender": "male", + "age": 23, + "address": { + "state": "California", + "city": "Riviera" + } + }, + { + "id": 8552, + "name": "Morales Albert", + "gender": "male", + "age": 58, + "address": { + "state": "Nevada", + "city": "Robbins" + } + }, + { + "id": 8553, + "name": "Lisa Wade", + "gender": "female", + "age": 73, + "address": { + "state": "New York", + "city": "Tivoli" + } + }, + { + "id": 8554, + "name": "Nora Chase", + "gender": "female", + "age": 18, + "address": { + "state": "Arkansas", + "city": "Tuskahoma" + } + }, + { + "id": 8555, + "name": "Maureen Charles", + "gender": "female", + "age": 49, + "address": { + "state": "North Carolina", + "city": "Lowgap" + } + }, + { + "id": 8556, + "name": "Galloway Yang", + "gender": "male", + "age": 61, + "address": { + "state": "South Dakota", + "city": "Navarre" + } + }, + { + "id": 8557, + "name": "Bentley Weeks", + "gender": "male", + "age": 27, + "address": { + "state": "North Dakota", + "city": "Rose" + } + }, + { + "id": 8558, + "name": "Carmella Castro", + "gender": "female", + "age": 61, + "address": { + "state": "Wisconsin", + "city": "Epworth" + } + }, + { + "id": 8559, + "name": "Beasley Reeves", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Sanford" + } + }, + { + "id": 8560, + "name": "Cecelia Arnold", + "gender": "female", + "age": 75, + "address": { + "state": "Michigan", + "city": "Farmers" + } + }, + { + "id": 8561, + "name": "Coleman Romero", + "gender": "male", + "age": 46, + "address": { + "state": "Oregon", + "city": "Stollings" + } + }, + { + "id": 8562, + "name": "Alba French", + "gender": "female", + "age": 38, + "address": { + "state": "Georgia", + "city": "Camino" + } + }, + { + "id": 8563, + "name": "Wolfe Mcdowell", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Boling" + } + }, + { + "id": 8564, + "name": "Marcie Langley", + "gender": "female", + "age": 80, + "address": { + "state": "Mississippi", + "city": "Yonah" + } + }, + { + "id": 8565, + "name": "Miranda Andrews", + "gender": "male", + "age": 23, + "address": { + "state": "Wyoming", + "city": "Rossmore" + } + }, + { + "id": 8566, + "name": "Deloris Bolton", + "gender": "female", + "age": 56, + "address": { + "state": "New Mexico", + "city": "Wilsonia" + } + }, + { + "id": 8567, + "name": "Monroe Hill", + "gender": "male", + "age": 79, + "address": { + "state": "Maryland", + "city": "Cucumber" + } + }, + { + "id": 8568, + "name": "Edith Ratliff", + "gender": "female", + "age": 44, + "address": { + "state": "Indiana", + "city": "Riner" + } + }, + { + "id": 8569, + "name": "Wilder Banks", + "gender": "male", + "age": 31, + "address": { + "state": "Alaska", + "city": "Williamson" + } + }, + { + "id": 8570, + "name": "Robinson Elliott", + "gender": "male", + "age": 63, + "address": { + "state": "Alabama", + "city": "Allamuchy" + } + }, + { + "id": 8571, + "name": "Beatrice Delaney", + "gender": "female", + "age": 70, + "address": { + "state": "South Carolina", + "city": "Garberville" + } + }, + { + "id": 8572, + "name": "Cain Wilcox", + "gender": "male", + "age": 46, + "address": { + "state": "Delaware", + "city": "Oceola" + } + }, + { + "id": 8573, + "name": "Contreras Sims", + "gender": "male", + "age": 50, + "address": { + "state": "Hawaii", + "city": "Downsville" + } + }, + { + "id": 8574, + "name": "Conley Baxter", + "gender": "male", + "age": 41, + "address": { + "state": "Washington", + "city": "Homestead" + } + }, + { + "id": 8575, + "name": "Mcmillan Contreras", + "gender": "male", + "age": 59, + "address": { + "state": "Arizona", + "city": "Stewart" + } + }, + { + "id": 8576, + "name": "Ronda Boyer", + "gender": "female", + "age": 33, + "address": { + "state": "Washington", + "city": "Tilden" + } + }, + { + "id": 8577, + "name": "Milagros Mckee", + "gender": "female", + "age": 56, + "address": { + "state": "Minnesota", + "city": "Coldiron" + } + }, + { + "id": 8578, + "name": "Pearl Vance", + "gender": "female", + "age": 80, + "address": { + "state": "New York", + "city": "Joppa" + } + }, + { + "id": 8579, + "name": "Solomon Oneal", + "gender": "male", + "age": 82, + "address": { + "state": "Michigan", + "city": "Esmont" + } + }, + { + "id": 8580, + "name": "Julia Murphy", + "gender": "female", + "age": 80, + "address": { + "state": "Oregon", + "city": "Vaughn" + } + }, + { + "id": 8581, + "name": "Branch Fischer", + "gender": "male", + "age": 68, + "address": { + "state": "Virginia", + "city": "Finderne" + } + }, + { + "id": 8582, + "name": "Briana Parker", + "gender": "female", + "age": 47, + "address": { + "state": "Indiana", + "city": "Glenshaw" + } + }, + { + "id": 8583, + "name": "Stark Good", + "gender": "male", + "age": 55, + "address": { + "state": "Tennessee", + "city": "Innsbrook" + } + }, + { + "id": 8584, + "name": "Lucille Gallegos", + "gender": "female", + "age": 39, + "address": { + "state": "South Dakota", + "city": "Rosburg" + } + }, + { + "id": 8585, + "name": "Brennan Stanley", + "gender": "male", + "age": 56, + "address": { + "state": "Maryland", + "city": "Soham" + } + }, + { + "id": 8586, + "name": "Adkins Villarreal", + "gender": "male", + "age": 30, + "address": { + "state": "Alaska", + "city": "Temperanceville" + } + }, + { + "id": 8587, + "name": "Lakeisha Alvarado", + "gender": "female", + "age": 20, + "address": { + "state": "Missouri", + "city": "Succasunna" + } + }, + { + "id": 8588, + "name": "Lauri Lamb", + "gender": "female", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Wheatfields" + } + }, + { + "id": 8589, + "name": "Claudette Rivera", + "gender": "female", + "age": 79, + "address": { + "state": "Louisiana", + "city": "Cresaptown" + } + }, + { + "id": 8590, + "name": "Nelson Gibbs", + "gender": "male", + "age": 71, + "address": { + "state": "Alabama", + "city": "Ezel" + } + }, + { + "id": 8591, + "name": "Sweet Ball", + "gender": "male", + "age": 32, + "address": { + "state": "Nebraska", + "city": "Bison" + } + }, + { + "id": 8592, + "name": "Noel Singleton", + "gender": "male", + "age": 79, + "address": { + "state": "Nevada", + "city": "Graniteville" + } + }, + { + "id": 8593, + "name": "Kent Leonard", + "gender": "male", + "age": 53, + "address": { + "state": "Utah", + "city": "Marienthal" + } + }, + { + "id": 8594, + "name": "Wendi Estes", + "gender": "female", + "age": 64, + "address": { + "state": "Colorado", + "city": "Chaparrito" + } + }, + { + "id": 8595, + "name": "Stacey Sanchez", + "gender": "female", + "age": 50, + "address": { + "state": "Georgia", + "city": "Rossmore" + } + }, + { + "id": 8596, + "name": "Cecilia Small", + "gender": "female", + "age": 63, + "address": { + "state": "Pennsylvania", + "city": "Hendersonville" + } + }, + { + "id": 8597, + "name": "Kerr Thornton", + "gender": "male", + "age": 25, + "address": { + "state": "Florida", + "city": "Rehrersburg" + } + }, + { + "id": 8598, + "name": "Myra Jackson", + "gender": "female", + "age": 23, + "address": { + "state": "Iowa", + "city": "Terlingua" + } + }, + { + "id": 8599, + "name": "Montoya Knight", + "gender": "male", + "age": 34, + "address": { + "state": "Delaware", + "city": "Strykersville" + } + }, + { + "id": 8600, + "name": "Brewer Ballard", + "gender": "male", + "age": 58, + "address": { + "state": "North Dakota", + "city": "Belmont" + } + }, + { + "id": 8601, + "name": "Edwina Henderson", + "gender": "female", + "age": 31, + "address": { + "state": "New Jersey", + "city": "Edinburg" + } + }, + { + "id": 8602, + "name": "Strickland Jenkins", + "gender": "male", + "age": 56, + "address": { + "state": "New Mexico", + "city": "Kaka" + } + }, + { + "id": 8603, + "name": "Burns Crawford", + "gender": "male", + "age": 54, + "address": { + "state": "Connecticut", + "city": "Crenshaw" + } + }, + { + "id": 8604, + "name": "Malone Rowe", + "gender": "male", + "age": 36, + "address": { + "state": "Illinois", + "city": "Richville" + } + }, + { + "id": 8605, + "name": "Baker Wolf", + "gender": "male", + "age": 54, + "address": { + "state": "Ohio", + "city": "Escondida" + } + }, + { + "id": 8606, + "name": "Vera Barry", + "gender": "female", + "age": 45, + "address": { + "state": "Vermont", + "city": "Lemoyne" + } + }, + { + "id": 8607, + "name": "Kate Rivers", + "gender": "female", + "age": 38, + "address": { + "state": "Wyoming", + "city": "Gallina" + } + }, + { + "id": 8608, + "name": "Hutchinson Bruce", + "gender": "male", + "age": 22, + "address": { + "state": "Maine", + "city": "Linwood" + } + }, + { + "id": 8609, + "name": "Cleveland Lancaster", + "gender": "male", + "age": 48, + "address": { + "state": "Texas", + "city": "Avoca" + } + }, + { + "id": 8610, + "name": "Katherine Franks", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Robinette" + } + }, + { + "id": 8611, + "name": "Jacobson Summers", + "gender": "male", + "age": 25, + "address": { + "state": "Wisconsin", + "city": "Cressey" + } + }, + { + "id": 8612, + "name": "Raquel Newton", + "gender": "female", + "age": 76, + "address": { + "state": "South Carolina", + "city": "Draper" + } + }, + { + "id": 8613, + "name": "Tina Langley", + "gender": "female", + "age": 23, + "address": { + "state": "Hawaii", + "city": "Grenelefe" + } + }, + { + "id": 8614, + "name": "Christina Hudson", + "gender": "female", + "age": 62, + "address": { + "state": "Kentucky", + "city": "Leyner" + } + }, + { + "id": 8615, + "name": "Greene Berry", + "gender": "male", + "age": 56, + "address": { + "state": "Kansas", + "city": "National" + } + }, + { + "id": 8616, + "name": "Janette Mccullough", + "gender": "female", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Sims" + } + }, + { + "id": 8617, + "name": "Reva Everett", + "gender": "female", + "age": 36, + "address": { + "state": "Idaho", + "city": "Englevale" + } + }, + { + "id": 8618, + "name": "Maryellen Wooten", + "gender": "female", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Dawn" + } + }, + { + "id": 8619, + "name": "Castillo Hood", + "gender": "male", + "age": 36, + "address": { + "state": "Mississippi", + "city": "Alderpoint" + } + }, + { + "id": 8620, + "name": "Golden Goodman", + "gender": "male", + "age": 43, + "address": { + "state": "West Virginia", + "city": "Byrnedale" + } + }, + { + "id": 8621, + "name": "Clay Davenport", + "gender": "male", + "age": 17, + "address": { + "state": "Montana", + "city": "Babb" + } + }, + { + "id": 8622, + "name": "Alyce Bond", + "gender": "female", + "age": 65, + "address": { + "state": "Massachusetts", + "city": "Gwynn" + } + }, + { + "id": 8623, + "name": "Tiffany Norman", + "gender": "female", + "age": 50, + "address": { + "state": "California", + "city": "Ruckersville" + } + }, + { + "id": 8624, + "name": "Burch Nolan", + "gender": "male", + "age": 50, + "address": { + "state": "Nevada", + "city": "Herlong" + } + }, + { + "id": 8625, + "name": "Olive Whitehead", + "gender": "female", + "age": 68, + "address": { + "state": "Indiana", + "city": "Omar" + } + }, + { + "id": 8626, + "name": "Latonya Cash", + "gender": "female", + "age": 57, + "address": { + "state": "Massachusetts", + "city": "Alafaya" + } + }, + { + "id": 8627, + "name": "Bridgett Weaver", + "gender": "female", + "age": 38, + "address": { + "state": "Ohio", + "city": "Blende" + } + }, + { + "id": 8628, + "name": "Burnett Thomas", + "gender": "male", + "age": 33, + "address": { + "state": "Pennsylvania", + "city": "Townsend" + } + }, + { + "id": 8629, + "name": "Craig Solis", + "gender": "male", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Marenisco" + } + }, + { + "id": 8630, + "name": "Mercedes Blair", + "gender": "female", + "age": 81, + "address": { + "state": "Arkansas", + "city": "Beaverdale" + } + }, + { + "id": 8631, + "name": "Colon Adkins", + "gender": "male", + "age": 50, + "address": { + "state": "Oklahoma", + "city": "Alfarata" + } + }, + { + "id": 8632, + "name": "Amie Branch", + "gender": "female", + "age": 82, + "address": { + "state": "North Carolina", + "city": "Elliston" + } + }, + { + "id": 8633, + "name": "Woodward Willis", + "gender": "male", + "age": 41, + "address": { + "state": "Montana", + "city": "Grayhawk" + } + }, + { + "id": 8634, + "name": "Catalina Stout", + "gender": "female", + "age": 23, + "address": { + "state": "Michigan", + "city": "Garfield" + } + }, + { + "id": 8635, + "name": "Wagner Burch", + "gender": "male", + "age": 61, + "address": { + "state": "California", + "city": "Loyalhanna" + } + }, + { + "id": 8636, + "name": "Gomez Christian", + "gender": "male", + "age": 81, + "address": { + "state": "Missouri", + "city": "Connerton" + } + }, + { + "id": 8637, + "name": "Lela Tanner", + "gender": "female", + "age": 58, + "address": { + "state": "Minnesota", + "city": "Norvelt" + } + }, + { + "id": 8638, + "name": "Robles Baxter", + "gender": "male", + "age": 80, + "address": { + "state": "New Mexico", + "city": "Umapine" + } + }, + { + "id": 8639, + "name": "Conley Reed", + "gender": "male", + "age": 33, + "address": { + "state": "North Dakota", + "city": "Freelandville" + } + }, + { + "id": 8640, + "name": "Kelsey Morris", + "gender": "female", + "age": 23, + "address": { + "state": "Alaska", + "city": "Barstow" + } + }, + { + "id": 8641, + "name": "Josefa Miller", + "gender": "female", + "age": 19, + "address": { + "state": "Illinois", + "city": "Bentley" + } + }, + { + "id": 8642, + "name": "Melanie Cabrera", + "gender": "female", + "age": 47, + "address": { + "state": "Colorado", + "city": "Trucksville" + } + }, + { + "id": 8643, + "name": "Mable Marks", + "gender": "female", + "age": 17, + "address": { + "state": "New Hampshire", + "city": "Darrtown" + } + }, + { + "id": 8644, + "name": "Figueroa Montoya", + "gender": "male", + "age": 61, + "address": { + "state": "Kansas", + "city": "Richford" + } + }, + { + "id": 8645, + "name": "Connie Burt", + "gender": "female", + "age": 49, + "address": { + "state": "Iowa", + "city": "Waterloo" + } + }, + { + "id": 8646, + "name": "Kathryn Allen", + "gender": "female", + "age": 40, + "address": { + "state": "Idaho", + "city": "Oasis" + } + }, + { + "id": 8647, + "name": "Valentine Sims", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Deercroft" + } + }, + { + "id": 8648, + "name": "Miranda Merritt", + "gender": "male", + "age": 53, + "address": { + "state": "Louisiana", + "city": "Onton" + } + }, + { + "id": 8649, + "name": "Cecelia Norman", + "gender": "female", + "age": 65, + "address": { + "state": "Wyoming", + "city": "Balm" + } + }, + { + "id": 8650, + "name": "Jarvis Salas", + "gender": "male", + "age": 17, + "address": { + "state": "Nebraska", + "city": "Robinson" + } + }, + { + "id": 8651, + "name": "Anita Heath", + "gender": "female", + "age": 37, + "address": { + "state": "Maine", + "city": "Chamizal" + } + }, + { + "id": 8652, + "name": "Michael Mccarty", + "gender": "male", + "age": 21, + "address": { + "state": "Utah", + "city": "Sims" + } + }, + { + "id": 8653, + "name": "Charles Rhodes", + "gender": "male", + "age": 61, + "address": { + "state": "Rhode Island", + "city": "Otranto" + } + }, + { + "id": 8654, + "name": "Anderson Olsen", + "gender": "male", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Brandermill" + } + }, + { + "id": 8655, + "name": "Luella Roth", + "gender": "female", + "age": 27, + "address": { + "state": "Wisconsin", + "city": "Vicksburg" + } + }, + { + "id": 8656, + "name": "Santiago Mcconnell", + "gender": "male", + "age": 78, + "address": { + "state": "Virginia", + "city": "Weeksville" + } + }, + { + "id": 8657, + "name": "Pierce Pitts", + "gender": "male", + "age": 26, + "address": { + "state": "Tennessee", + "city": "Herbster" + } + }, + { + "id": 8658, + "name": "Mayer Sykes", + "gender": "male", + "age": 17, + "address": { + "state": "Mississippi", + "city": "Washington" + } + }, + { + "id": 8659, + "name": "Durham Harvey", + "gender": "male", + "age": 78, + "address": { + "state": "Vermont", + "city": "Northchase" + } + }, + { + "id": 8660, + "name": "Ewing Brock", + "gender": "male", + "age": 43, + "address": { + "state": "New York", + "city": "Sutton" + } + }, + { + "id": 8661, + "name": "Snider Clay", + "gender": "male", + "age": 34, + "address": { + "state": "Texas", + "city": "Sabillasville" + } + }, + { + "id": 8662, + "name": "Acevedo Cooper", + "gender": "male", + "age": 45, + "address": { + "state": "New Jersey", + "city": "Campo" + } + }, + { + "id": 8663, + "name": "Cathryn Hood", + "gender": "female", + "age": 44, + "address": { + "state": "Arizona", + "city": "Blackgum" + } + }, + { + "id": 8664, + "name": "Stacey Crosby", + "gender": "female", + "age": 33, + "address": { + "state": "Oregon", + "city": "Mathews" + } + }, + { + "id": 8665, + "name": "Abbott Sparks", + "gender": "male", + "age": 61, + "address": { + "state": "Washington", + "city": "Murillo" + } + }, + { + "id": 8666, + "name": "Patty Montgomery", + "gender": "female", + "age": 43, + "address": { + "state": "Alabama", + "city": "Westerville" + } + }, + { + "id": 8667, + "name": "Jennings Baird", + "gender": "male", + "age": 54, + "address": { + "state": "South Dakota", + "city": "Craig" + } + }, + { + "id": 8668, + "name": "Perry Compton", + "gender": "male", + "age": 18, + "address": { + "state": "South Carolina", + "city": "Virgie" + } + }, + { + "id": 8669, + "name": "Kaufman Rutledge", + "gender": "male", + "age": 82, + "address": { + "state": "Georgia", + "city": "Itmann" + } + }, + { + "id": 8670, + "name": "Rivers Padilla", + "gender": "male", + "age": 59, + "address": { + "state": "Kentucky", + "city": "Walland" + } + }, + { + "id": 8671, + "name": "Harvey Shields", + "gender": "male", + "age": 32, + "address": { + "state": "Delaware", + "city": "Swartzville" + } + }, + { + "id": 8672, + "name": "Tammie Dillard", + "gender": "female", + "age": 43, + "address": { + "state": "Maryland", + "city": "Belfair" + } + }, + { + "id": 8673, + "name": "Mcfadden Mcgee", + "gender": "male", + "age": 20, + "address": { + "state": "Idaho", + "city": "Oneida" + } + }, + { + "id": 8674, + "name": "Wood Mckinney", + "gender": "male", + "age": 22, + "address": { + "state": "Louisiana", + "city": "Hasty" + } + }, + { + "id": 8675, + "name": "Bailey Joyner", + "gender": "male", + "age": 22, + "address": { + "state": "Hawaii", + "city": "Allison" + } + }, + { + "id": 8676, + "name": "Bishop Gutierrez", + "gender": "male", + "age": 28, + "address": { + "state": "Georgia", + "city": "Epworth" + } + }, + { + "id": 8677, + "name": "Lacey Potter", + "gender": "female", + "age": 40, + "address": { + "state": "Arkansas", + "city": "Gasquet" + } + }, + { + "id": 8678, + "name": "Staci Gould", + "gender": "female", + "age": 54, + "address": { + "state": "Maryland", + "city": "Yonah" + } + }, + { + "id": 8679, + "name": "Meadows Ware", + "gender": "male", + "age": 54, + "address": { + "state": "Texas", + "city": "Waikele" + } + }, + { + "id": 8680, + "name": "Sanchez Wright", + "gender": "male", + "age": 78, + "address": { + "state": "Wisconsin", + "city": "Morgandale" + } + }, + { + "id": 8681, + "name": "Gibson Frank", + "gender": "male", + "age": 59, + "address": { + "state": "Delaware", + "city": "Mulino" + } + }, + { + "id": 8682, + "name": "Sherman Berger", + "gender": "male", + "age": 40, + "address": { + "state": "New Jersey", + "city": "Lithium" + } + }, + { + "id": 8683, + "name": "Marlene Cooley", + "gender": "female", + "age": 63, + "address": { + "state": "Washington", + "city": "Geyserville" + } + }, + { + "id": 8684, + "name": "Mack Flores", + "gender": "male", + "age": 37, + "address": { + "state": "Alaska", + "city": "Jacumba" + } + }, + { + "id": 8685, + "name": "Preston Yates", + "gender": "male", + "age": 47, + "address": { + "state": "Nevada", + "city": "Avoca" + } + }, + { + "id": 8686, + "name": "Carlson Whitley", + "gender": "male", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Urie" + } + }, + { + "id": 8687, + "name": "Guerra Robinson", + "gender": "male", + "age": 44, + "address": { + "state": "Virginia", + "city": "Holcombe" + } + }, + { + "id": 8688, + "name": "Polly Lucas", + "gender": "female", + "age": 27, + "address": { + "state": "New Mexico", + "city": "Vallonia" + } + }, + { + "id": 8689, + "name": "Shana French", + "gender": "female", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Statenville" + } + }, + { + "id": 8690, + "name": "Young Mcintyre", + "gender": "male", + "age": 36, + "address": { + "state": "Michigan", + "city": "Suitland" + } + }, + { + "id": 8691, + "name": "Brooks Lopez", + "gender": "male", + "age": 61, + "address": { + "state": "Colorado", + "city": "Germanton" + } + }, + { + "id": 8692, + "name": "Horn Zimmerman", + "gender": "male", + "age": 63, + "address": { + "state": "Illinois", + "city": "Warsaw" + } + }, + { + "id": 8693, + "name": "Head Padilla", + "gender": "male", + "age": 44, + "address": { + "state": "Alabama", + "city": "Grandview" + } + }, + { + "id": 8694, + "name": "Savage Allen", + "gender": "male", + "age": 66, + "address": { + "state": "North Dakota", + "city": "Elbert" + } + }, + { + "id": 8695, + "name": "Petty Clay", + "gender": "male", + "age": 75, + "address": { + "state": "Vermont", + "city": "Crucible" + } + }, + { + "id": 8696, + "name": "Ortega Oconnor", + "gender": "male", + "age": 28, + "address": { + "state": "Oklahoma", + "city": "Keyport" + } + }, + { + "id": 8697, + "name": "Kelley Sweeney", + "gender": "female", + "age": 53, + "address": { + "state": "South Dakota", + "city": "Lupton" + } + }, + { + "id": 8698, + "name": "Rhoda Noble", + "gender": "female", + "age": 76, + "address": { + "state": "Mississippi", + "city": "Robbins" + } + }, + { + "id": 8699, + "name": "Erika Carney", + "gender": "female", + "age": 32, + "address": { + "state": "Montana", + "city": "Martell" + } + }, + { + "id": 8700, + "name": "Lizzie Santana", + "gender": "female", + "age": 20, + "address": { + "state": "Maine", + "city": "Harrison" + } + }, + { + "id": 8701, + "name": "Everett Wheeler", + "gender": "male", + "age": 50, + "address": { + "state": "New Hampshire", + "city": "Darbydale" + } + }, + { + "id": 8702, + "name": "Holman Hartman", + "gender": "male", + "age": 49, + "address": { + "state": "Nebraska", + "city": "Rossmore" + } + }, + { + "id": 8703, + "name": "Addie Adams", + "gender": "female", + "age": 82, + "address": { + "state": "Pennsylvania", + "city": "Canoochee" + } + }, + { + "id": 8704, + "name": "Duffy Contreras", + "gender": "male", + "age": 32, + "address": { + "state": "Oregon", + "city": "Stewart" + } + }, + { + "id": 8705, + "name": "Rosario Erickson", + "gender": "male", + "age": 52, + "address": { + "state": "California", + "city": "Ilchester" + } + }, + { + "id": 8706, + "name": "Charlene Boyer", + "gender": "female", + "age": 71, + "address": { + "state": "Arizona", + "city": "Winchester" + } + }, + { + "id": 8707, + "name": "Barrera Cook", + "gender": "male", + "age": 52, + "address": { + "state": "Ohio", + "city": "Caledonia" + } + }, + { + "id": 8708, + "name": "Vicki House", + "gender": "female", + "age": 58, + "address": { + "state": "South Carolina", + "city": "Sanborn" + } + }, + { + "id": 8709, + "name": "Rhodes Nelson", + "gender": "male", + "age": 60, + "address": { + "state": "Kansas", + "city": "Gardners" + } + }, + { + "id": 8710, + "name": "Conley Ferrell", + "gender": "male", + "age": 35, + "address": { + "state": "Kentucky", + "city": "Starks" + } + }, + { + "id": 8711, + "name": "Singleton Dalton", + "gender": "male", + "age": 58, + "address": { + "state": "West Virginia", + "city": "Kula" + } + }, + { + "id": 8712, + "name": "Walsh Blackwell", + "gender": "male", + "age": 64, + "address": { + "state": "Minnesota", + "city": "Concho" + } + }, + { + "id": 8713, + "name": "Noemi Horn", + "gender": "female", + "age": 34, + "address": { + "state": "Missouri", + "city": "Stockdale" + } + }, + { + "id": 8714, + "name": "Craft Atkins", + "gender": "male", + "age": 56, + "address": { + "state": "Utah", + "city": "Gibsonia" + } + }, + { + "id": 8715, + "name": "Alfreda Andrews", + "gender": "female", + "age": 19, + "address": { + "state": "Massachusetts", + "city": "Wadsworth" + } + }, + { + "id": 8716, + "name": "Pam Morales", + "gender": "female", + "age": 77, + "address": { + "state": "Iowa", + "city": "Waterford" + } + }, + { + "id": 8717, + "name": "Reeves Levy", + "gender": "male", + "age": 20, + "address": { + "state": "Rhode Island", + "city": "Glenshaw" + } + }, + { + "id": 8718, + "name": "Juarez Barlow", + "gender": "male", + "age": 58, + "address": { + "state": "Wyoming", + "city": "Marion" + } + }, + { + "id": 8719, + "name": "Paula Guerrero", + "gender": "female", + "age": 75, + "address": { + "state": "Tennessee", + "city": "Catherine" + } + }, + { + "id": 8720, + "name": "Joan Blanchard", + "gender": "female", + "age": 68, + "address": { + "state": "Florida", + "city": "Snowville" + } + }, + { + "id": 8721, + "name": "Whitaker Simmons", + "gender": "male", + "age": 71, + "address": { + "state": "Indiana", + "city": "Castleton" + } + }, + { + "id": 8722, + "name": "Sargent Berry", + "gender": "male", + "age": 61, + "address": { + "state": "Washington", + "city": "Nile" + } + }, + { + "id": 8723, + "name": "Compton Lindsay", + "gender": "male", + "age": 19, + "address": { + "state": "New Hampshire", + "city": "Watrous" + } + }, + { + "id": 8724, + "name": "Abbott Richard", + "gender": "male", + "age": 55, + "address": { + "state": "Wyoming", + "city": "Guthrie" + } + }, + { + "id": 8725, + "name": "Blankenship Frazier", + "gender": "male", + "age": 21, + "address": { + "state": "North Carolina", + "city": "Laurelton" + } + }, + { + "id": 8726, + "name": "Walters Stout", + "gender": "male", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Sexton" + } + }, + { + "id": 8727, + "name": "Serena Hopkins", + "gender": "female", + "age": 27, + "address": { + "state": "Massachusetts", + "city": "Nipinnawasee" + } + }, + { + "id": 8728, + "name": "Glenda Santos", + "gender": "female", + "age": 28, + "address": { + "state": "Iowa", + "city": "Deercroft" + } + }, + { + "id": 8729, + "name": "Stephanie Roach", + "gender": "female", + "age": 63, + "address": { + "state": "Nebraska", + "city": "Omar" + } + }, + { + "id": 8730, + "name": "Alexandra Alexander", + "gender": "female", + "age": 46, + "address": { + "state": "Alaska", + "city": "Northchase" + } + }, + { + "id": 8731, + "name": "Lee Bryan", + "gender": "male", + "age": 56, + "address": { + "state": "Tennessee", + "city": "Summerset" + } + }, + { + "id": 8732, + "name": "Lilly Sullivan", + "gender": "female", + "age": 33, + "address": { + "state": "Indiana", + "city": "Mansfield" + } + }, + { + "id": 8733, + "name": "Hoover Matthews", + "gender": "male", + "age": 47, + "address": { + "state": "Montana", + "city": "Disautel" + } + }, + { + "id": 8734, + "name": "Michael Goodman", + "gender": "female", + "age": 48, + "address": { + "state": "California", + "city": "Seymour" + } + }, + { + "id": 8735, + "name": "Bentley Conway", + "gender": "male", + "age": 18, + "address": { + "state": "Idaho", + "city": "Chautauqua" + } + }, + { + "id": 8736, + "name": "Vargas Bruce", + "gender": "male", + "age": 63, + "address": { + "state": "Kansas", + "city": "Wattsville" + } + }, + { + "id": 8737, + "name": "Downs Oneal", + "gender": "male", + "age": 17, + "address": { + "state": "Michigan", + "city": "Crown" + } + }, + { + "id": 8738, + "name": "Carpenter Cain", + "gender": "male", + "age": 57, + "address": { + "state": "Rhode Island", + "city": "Whitewater" + } + }, + { + "id": 8739, + "name": "Hughes Hickman", + "gender": "male", + "age": 52, + "address": { + "state": "Colorado", + "city": "Carrizo" + } + }, + { + "id": 8740, + "name": "Harmon Reyes", + "gender": "male", + "age": 51, + "address": { + "state": "Florida", + "city": "Kipp" + } + }, + { + "id": 8741, + "name": "Spencer Hardin", + "gender": "male", + "age": 36, + "address": { + "state": "Delaware", + "city": "Kennedyville" + } + }, + { + "id": 8742, + "name": "Lucia Spears", + "gender": "female", + "age": 74, + "address": { + "state": "New Mexico", + "city": "Edgewater" + } + }, + { + "id": 8743, + "name": "Wanda Greene", + "gender": "female", + "age": 21, + "address": { + "state": "Oregon", + "city": "Salunga" + } + }, + { + "id": 8744, + "name": "Gracie Austin", + "gender": "female", + "age": 77, + "address": { + "state": "Louisiana", + "city": "Klagetoh" + } + }, + { + "id": 8745, + "name": "Blair Burt", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Coaldale" + } + }, + { + "id": 8746, + "name": "Shelly Holmes", + "gender": "female", + "age": 23, + "address": { + "state": "West Virginia", + "city": "Fingerville" + } + }, + { + "id": 8747, + "name": "Solis Hatfield", + "gender": "male", + "age": 37, + "address": { + "state": "Connecticut", + "city": "Harborton" + } + }, + { + "id": 8748, + "name": "Alisa Harding", + "gender": "female", + "age": 34, + "address": { + "state": "New York", + "city": "Bluffview" + } + }, + { + "id": 8749, + "name": "Huffman Burris", + "gender": "male", + "age": 44, + "address": { + "state": "Georgia", + "city": "Benson" + } + }, + { + "id": 8750, + "name": "Kennedy Pittman", + "gender": "male", + "age": 78, + "address": { + "state": "North Dakota", + "city": "Northridge" + } + }, + { + "id": 8751, + "name": "Meyer Farley", + "gender": "male", + "age": 51, + "address": { + "state": "Pennsylvania", + "city": "Dyckesville" + } + }, + { + "id": 8752, + "name": "Holly Willis", + "gender": "female", + "age": 82, + "address": { + "state": "Missouri", + "city": "Templeton" + } + }, + { + "id": 8753, + "name": "Cash Carter", + "gender": "male", + "age": 62, + "address": { + "state": "Maryland", + "city": "Beason" + } + }, + { + "id": 8754, + "name": "Hardin Underwood", + "gender": "male", + "age": 21, + "address": { + "state": "Wisconsin", + "city": "Talpa" + } + }, + { + "id": 8755, + "name": "Hull Craig", + "gender": "male", + "age": 17, + "address": { + "state": "Kentucky", + "city": "Gambrills" + } + }, + { + "id": 8756, + "name": "Vaughn Gibbs", + "gender": "male", + "age": 41, + "address": { + "state": "Maine", + "city": "Independence" + } + }, + { + "id": 8757, + "name": "Bailey Hyde", + "gender": "male", + "age": 55, + "address": { + "state": "Nevada", + "city": "Stollings" + } + }, + { + "id": 8758, + "name": "Bridgette Fernandez", + "gender": "female", + "age": 42, + "address": { + "state": "Texas", + "city": "Garnet" + } + }, + { + "id": 8759, + "name": "Amy Mooney", + "gender": "female", + "age": 62, + "address": { + "state": "Oklahoma", + "city": "Macdona" + } + }, + { + "id": 8760, + "name": "Stanton Trujillo", + "gender": "male", + "age": 73, + "address": { + "state": "Ohio", + "city": "Urbana" + } + }, + { + "id": 8761, + "name": "Marietta Acevedo", + "gender": "female", + "age": 29, + "address": { + "state": "Arizona", + "city": "Kansas" + } + }, + { + "id": 8762, + "name": "Susanna House", + "gender": "female", + "age": 81, + "address": { + "state": "New Jersey", + "city": "Gila" + } + }, + { + "id": 8763, + "name": "Briggs Holman", + "gender": "male", + "age": 24, + "address": { + "state": "Vermont", + "city": "Eureka" + } + }, + { + "id": 8764, + "name": "Camille Osborne", + "gender": "female", + "age": 49, + "address": { + "state": "Illinois", + "city": "Evergreen" + } + }, + { + "id": 8765, + "name": "Lou Booker", + "gender": "female", + "age": 40, + "address": { + "state": "Arkansas", + "city": "Defiance" + } + }, + { + "id": 8766, + "name": "Mcdaniel Bell", + "gender": "male", + "age": 61, + "address": { + "state": "Mississippi", + "city": "Islandia" + } + }, + { + "id": 8767, + "name": "Kristina Pace", + "gender": "female", + "age": 52, + "address": { + "state": "South Dakota", + "city": "Bordelonville" + } + }, + { + "id": 8768, + "name": "Eddie Mathews", + "gender": "female", + "age": 25, + "address": { + "state": "Hawaii", + "city": "Rosine" + } + }, + { + "id": 8769, + "name": "Mooney Mccullough", + "gender": "male", + "age": 73, + "address": { + "state": "Utah", + "city": "Dexter" + } + }, + { + "id": 8770, + "name": "Addie Olsen", + "gender": "female", + "age": 52, + "address": { + "state": "Minnesota", + "city": "Centerville" + } + }, + { + "id": 8771, + "name": "Graham Koch", + "gender": "male", + "age": 56, + "address": { + "state": "North Dakota", + "city": "Buxton" + } + }, + { + "id": 8772, + "name": "Ginger Simpson", + "gender": "female", + "age": 72, + "address": { + "state": "Ohio", + "city": "Snyderville" + } + }, + { + "id": 8773, + "name": "Neva Gay", + "gender": "female", + "age": 20, + "address": { + "state": "Rhode Island", + "city": "Cashtown" + } + }, + { + "id": 8774, + "name": "Natalie Roberts", + "gender": "female", + "age": 52, + "address": { + "state": "Maryland", + "city": "Roland" + } + }, + { + "id": 8775, + "name": "Hamilton Zamora", + "gender": "male", + "age": 82, + "address": { + "state": "Minnesota", + "city": "Leland" + } + }, + { + "id": 8776, + "name": "Flora Collins", + "gender": "female", + "age": 69, + "address": { + "state": "New Hampshire", + "city": "Chautauqua" + } + }, + { + "id": 8777, + "name": "Ball Juarez", + "gender": "male", + "age": 80, + "address": { + "state": "Oregon", + "city": "Cliff" + } + }, + { + "id": 8778, + "name": "Alexander Acosta", + "gender": "male", + "age": 43, + "address": { + "state": "West Virginia", + "city": "Cascades" + } + }, + { + "id": 8779, + "name": "Sears Morgan", + "gender": "male", + "age": 30, + "address": { + "state": "Connecticut", + "city": "Zortman" + } + }, + { + "id": 8780, + "name": "Viola Shannon", + "gender": "female", + "age": 18, + "address": { + "state": "Nebraska", + "city": "Wyano" + } + }, + { + "id": 8781, + "name": "Bradshaw Warner", + "gender": "male", + "age": 40, + "address": { + "state": "Kansas", + "city": "Enoree" + } + }, + { + "id": 8782, + "name": "Weiss Rhodes", + "gender": "male", + "age": 81, + "address": { + "state": "Florida", + "city": "Taft" + } + }, + { + "id": 8783, + "name": "Leach Peterson", + "gender": "male", + "age": 54, + "address": { + "state": "Hawaii", + "city": "Statenville" + } + }, + { + "id": 8784, + "name": "Myra Nguyen", + "gender": "female", + "age": 59, + "address": { + "state": "New Mexico", + "city": "Tioga" + } + }, + { + "id": 8785, + "name": "Wilkerson Woodward", + "gender": "male", + "age": 66, + "address": { + "state": "Nevada", + "city": "Connerton" + } + }, + { + "id": 8786, + "name": "Dollie Charles", + "gender": "female", + "age": 60, + "address": { + "state": "Alabama", + "city": "Homeworth" + } + }, + { + "id": 8787, + "name": "Ora Powers", + "gender": "female", + "age": 30, + "address": { + "state": "Massachusetts", + "city": "Clay" + } + }, + { + "id": 8788, + "name": "Craig Conway", + "gender": "male", + "age": 53, + "address": { + "state": "Arkansas", + "city": "Blende" + } + }, + { + "id": 8789, + "name": "Sylvia Dotson", + "gender": "female", + "age": 76, + "address": { + "state": "Louisiana", + "city": "Glenbrook" + } + }, + { + "id": 8790, + "name": "William Duke", + "gender": "male", + "age": 25, + "address": { + "state": "Delaware", + "city": "Noblestown" + } + }, + { + "id": 8791, + "name": "Hansen Stevenson", + "gender": "male", + "age": 21, + "address": { + "state": "Vermont", + "city": "Grimsley" + } + }, + { + "id": 8792, + "name": "Caitlin Golden", + "gender": "female", + "age": 28, + "address": { + "state": "Oklahoma", + "city": "Mappsville" + } + }, + { + "id": 8793, + "name": "Geraldine Salas", + "gender": "female", + "age": 18, + "address": { + "state": "New Jersey", + "city": "Ilchester" + } + }, + { + "id": 8794, + "name": "Shelia Klein", + "gender": "female", + "age": 32, + "address": { + "state": "California", + "city": "Curtice" + } + }, + { + "id": 8795, + "name": "Moon Trujillo", + "gender": "male", + "age": 74, + "address": { + "state": "Michigan", + "city": "Wattsville" + } + }, + { + "id": 8796, + "name": "Cain King", + "gender": "male", + "age": 65, + "address": { + "state": "Wyoming", + "city": "Orin" + } + }, + { + "id": 8797, + "name": "Brittany Berger", + "gender": "female", + "age": 78, + "address": { + "state": "Arizona", + "city": "Snelling" + } + }, + { + "id": 8798, + "name": "Kristen Reeves", + "gender": "female", + "age": 36, + "address": { + "state": "New York", + "city": "Limestone" + } + }, + { + "id": 8799, + "name": "Hayes Nash", + "gender": "male", + "age": 35, + "address": { + "state": "South Dakota", + "city": "Jessie" + } + }, + { + "id": 8800, + "name": "Walters Lewis", + "gender": "male", + "age": 77, + "address": { + "state": "Alaska", + "city": "Naomi" + } + }, + { + "id": 8801, + "name": "Catalina Gould", + "gender": "female", + "age": 45, + "address": { + "state": "Colorado", + "city": "Moraida" + } + }, + { + "id": 8802, + "name": "Renee Gross", + "gender": "female", + "age": 58, + "address": { + "state": "Tennessee", + "city": "Ona" + } + }, + { + "id": 8803, + "name": "Rene Branch", + "gender": "female", + "age": 52, + "address": { + "state": "Iowa", + "city": "Enlow" + } + }, + { + "id": 8804, + "name": "Beard Garcia", + "gender": "male", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Greenwich" + } + }, + { + "id": 8805, + "name": "Lindsay Marks", + "gender": "female", + "age": 69, + "address": { + "state": "Wisconsin", + "city": "Waumandee" + } + }, + { + "id": 8806, + "name": "Shaffer Marsh", + "gender": "male", + "age": 62, + "address": { + "state": "Illinois", + "city": "Idledale" + } + }, + { + "id": 8807, + "name": "Spencer Garrett", + "gender": "male", + "age": 70, + "address": { + "state": "Mississippi", + "city": "Hiseville" + } + }, + { + "id": 8808, + "name": "Morgan Bruce", + "gender": "female", + "age": 43, + "address": { + "state": "Georgia", + "city": "Hinsdale" + } + }, + { + "id": 8809, + "name": "Stacy Banks", + "gender": "female", + "age": 46, + "address": { + "state": "Indiana", + "city": "Fivepointville" + } + }, + { + "id": 8810, + "name": "Ophelia Daugherty", + "gender": "female", + "age": 22, + "address": { + "state": "Pennsylvania", + "city": "Graball" + } + }, + { + "id": 8811, + "name": "Willa Spence", + "gender": "female", + "age": 80, + "address": { + "state": "Texas", + "city": "Northridge" + } + }, + { + "id": 8812, + "name": "Joan Garrison", + "gender": "female", + "age": 49, + "address": { + "state": "Virginia", + "city": "Whipholt" + } + }, + { + "id": 8813, + "name": "Beverley Maxwell", + "gender": "female", + "age": 26, + "address": { + "state": "Kentucky", + "city": "Camptown" + } + }, + { + "id": 8814, + "name": "Dominguez Johns", + "gender": "male", + "age": 72, + "address": { + "state": "Utah", + "city": "Rivera" + } + }, + { + "id": 8815, + "name": "Helga Jimenez", + "gender": "female", + "age": 58, + "address": { + "state": "Idaho", + "city": "Westerville" + } + }, + { + "id": 8816, + "name": "Hooper Wilson", + "gender": "male", + "age": 41, + "address": { + "state": "Maine", + "city": "Trail" + } + }, + { + "id": 8817, + "name": "Clayton Weber", + "gender": "male", + "age": 55, + "address": { + "state": "Washington", + "city": "Oley" + } + }, + { + "id": 8818, + "name": "Wong Wells", + "gender": "male", + "age": 28, + "address": { + "state": "Missouri", + "city": "Staples" + } + }, + { + "id": 8819, + "name": "Casey Dudley", + "gender": "female", + "age": 51, + "address": { + "state": "Montana", + "city": "Bridgetown" + } + }, + { + "id": 8820, + "name": "Wendi Campbell", + "gender": "female", + "age": 21, + "address": { + "state": "Kansas", + "city": "Cliff" + } + }, + { + "id": 8821, + "name": "Mckee Martin", + "gender": "male", + "age": 56, + "address": { + "state": "North Carolina", + "city": "Derwood" + } + }, + { + "id": 8822, + "name": "Mia Schwartz", + "gender": "female", + "age": 75, + "address": { + "state": "Mississippi", + "city": "Allentown" + } + }, + { + "id": 8823, + "name": "Levine Walters", + "gender": "male", + "age": 80, + "address": { + "state": "Minnesota", + "city": "Somerset" + } + }, + { + "id": 8824, + "name": "Cara Woodard", + "gender": "female", + "age": 55, + "address": { + "state": "Utah", + "city": "Ola" + } + }, + { + "id": 8825, + "name": "Dickson Clark", + "gender": "male", + "age": 30, + "address": { + "state": "Louisiana", + "city": "Odessa" + } + }, + { + "id": 8826, + "name": "Clara Holt", + "gender": "female", + "age": 77, + "address": { + "state": "Florida", + "city": "Elliott" + } + }, + { + "id": 8827, + "name": "House Terry", + "gender": "male", + "age": 36, + "address": { + "state": "Wisconsin", + "city": "Jacksonburg" + } + }, + { + "id": 8828, + "name": "Shawn Ferrell", + "gender": "female", + "age": 73, + "address": { + "state": "Missouri", + "city": "Rivers" + } + }, + { + "id": 8829, + "name": "Fry Barber", + "gender": "male", + "age": 74, + "address": { + "state": "New York", + "city": "Statenville" + } + }, + { + "id": 8830, + "name": "Jones Floyd", + "gender": "male", + "age": 29, + "address": { + "state": "New Hampshire", + "city": "Clarktown" + } + }, + { + "id": 8831, + "name": "Lula Shelton", + "gender": "female", + "age": 45, + "address": { + "state": "Pennsylvania", + "city": "Skyland" + } + }, + { + "id": 8832, + "name": "Nelda Stuart", + "gender": "female", + "age": 34, + "address": { + "state": "Washington", + "city": "Lund" + } + }, + { + "id": 8833, + "name": "Maryanne Webster", + "gender": "female", + "age": 25, + "address": { + "state": "New Jersey", + "city": "Garnet" + } + }, + { + "id": 8834, + "name": "Richmond Velasquez", + "gender": "male", + "age": 30, + "address": { + "state": "Hawaii", + "city": "Websterville" + } + }, + { + "id": 8835, + "name": "Pickett Booth", + "gender": "male", + "age": 41, + "address": { + "state": "Colorado", + "city": "Neahkahnie" + } + }, + { + "id": 8836, + "name": "Curtis Fields", + "gender": "male", + "age": 44, + "address": { + "state": "Arizona", + "city": "Fostoria" + } + }, + { + "id": 8837, + "name": "Moss Wade", + "gender": "male", + "age": 37, + "address": { + "state": "Arkansas", + "city": "Worton" + } + }, + { + "id": 8838, + "name": "Everett Perkins", + "gender": "male", + "age": 78, + "address": { + "state": "Massachusetts", + "city": "Knowlton" + } + }, + { + "id": 8839, + "name": "Angeline Chandler", + "gender": "female", + "age": 68, + "address": { + "state": "Montana", + "city": "Riner" + } + }, + { + "id": 8840, + "name": "Lindsay Adkins", + "gender": "female", + "age": 33, + "address": { + "state": "Maine", + "city": "Wollochet" + } + }, + { + "id": 8841, + "name": "Juliette Mcintosh", + "gender": "female", + "age": 81, + "address": { + "state": "Oklahoma", + "city": "Needmore" + } + }, + { + "id": 8842, + "name": "Lessie Castaneda", + "gender": "female", + "age": 23, + "address": { + "state": "Ohio", + "city": "Navarre" + } + }, + { + "id": 8843, + "name": "Joseph Dudley", + "gender": "male", + "age": 31, + "address": { + "state": "Georgia", + "city": "Slovan" + } + }, + { + "id": 8844, + "name": "Francesca Small", + "gender": "female", + "age": 54, + "address": { + "state": "West Virginia", + "city": "Why" + } + }, + { + "id": 8845, + "name": "Dunn Cantu", + "gender": "male", + "age": 44, + "address": { + "state": "Michigan", + "city": "Gila" + } + }, + { + "id": 8846, + "name": "Rochelle Webb", + "gender": "female", + "age": 40, + "address": { + "state": "Indiana", + "city": "Abiquiu" + } + }, + { + "id": 8847, + "name": "Ayala George", + "gender": "male", + "age": 65, + "address": { + "state": "South Dakota", + "city": "Crumpler" + } + }, + { + "id": 8848, + "name": "Whitley Dixon", + "gender": "male", + "age": 59, + "address": { + "state": "Vermont", + "city": "Jessie" + } + }, + { + "id": 8849, + "name": "Lizzie Wong", + "gender": "female", + "age": 56, + "address": { + "state": "Nevada", + "city": "Helen" + } + }, + { + "id": 8850, + "name": "Terri Delgado", + "gender": "female", + "age": 54, + "address": { + "state": "Idaho", + "city": "Blairstown" + } + }, + { + "id": 8851, + "name": "Holloway Albert", + "gender": "male", + "age": 42, + "address": { + "state": "Rhode Island", + "city": "Shrewsbury" + } + }, + { + "id": 8852, + "name": "Hewitt Bean", + "gender": "male", + "age": 24, + "address": { + "state": "Virginia", + "city": "Tecolotito" + } + }, + { + "id": 8853, + "name": "Bowen Klein", + "gender": "male", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Breinigsville" + } + }, + { + "id": 8854, + "name": "White Pierce", + "gender": "male", + "age": 49, + "address": { + "state": "Maryland", + "city": "Gorst" + } + }, + { + "id": 8855, + "name": "Oconnor Todd", + "gender": "male", + "age": 59, + "address": { + "state": "California", + "city": "Duryea" + } + }, + { + "id": 8856, + "name": "Kellie Wilder", + "gender": "female", + "age": 30, + "address": { + "state": "Kentucky", + "city": "Glasgow" + } + }, + { + "id": 8857, + "name": "Debora Whitley", + "gender": "female", + "age": 52, + "address": { + "state": "Oregon", + "city": "Jeff" + } + }, + { + "id": 8858, + "name": "Rutledge Ford", + "gender": "male", + "age": 49, + "address": { + "state": "Tennessee", + "city": "Otranto" + } + }, + { + "id": 8859, + "name": "Manuela Valentine", + "gender": "female", + "age": 21, + "address": { + "state": "South Carolina", + "city": "Cazadero" + } + }, + { + "id": 8860, + "name": "Larson Hill", + "gender": "male", + "age": 42, + "address": { + "state": "Texas", + "city": "Deercroft" + } + }, + { + "id": 8861, + "name": "Barton Potts", + "gender": "male", + "age": 37, + "address": { + "state": "Alabama", + "city": "Biddle" + } + }, + { + "id": 8862, + "name": "Rivas Hester", + "gender": "male", + "age": 60, + "address": { + "state": "Delaware", + "city": "Machias" + } + }, + { + "id": 8863, + "name": "Espinoza Pickett", + "gender": "male", + "age": 37, + "address": { + "state": "Alaska", + "city": "Cashtown" + } + }, + { + "id": 8864, + "name": "Vazquez Wheeler", + "gender": "male", + "age": 28, + "address": { + "state": "Iowa", + "city": "Frank" + } + }, + { + "id": 8865, + "name": "Glenn Mooney", + "gender": "male", + "age": 42, + "address": { + "state": "Connecticut", + "city": "Cumberland" + } + }, + { + "id": 8866, + "name": "Chaney Ramsey", + "gender": "male", + "age": 23, + "address": { + "state": "North Dakota", + "city": "Driftwood" + } + }, + { + "id": 8867, + "name": "Rowena Bender", + "gender": "female", + "age": 26, + "address": { + "state": "Illinois", + "city": "Efland" + } + }, + { + "id": 8868, + "name": "Jenkins Berg", + "gender": "male", + "age": 65, + "address": { + "state": "Wyoming", + "city": "Bordelonville" + } + }, + { + "id": 8869, + "name": "Candice Ware", + "gender": "female", + "age": 42, + "address": { + "state": "Maryland", + "city": "Norvelt" + } + }, + { + "id": 8870, + "name": "Kaitlin Mcintosh", + "gender": "female", + "age": 32, + "address": { + "state": "Oregon", + "city": "Sharon" + } + }, + { + "id": 8871, + "name": "Annmarie Fulton", + "gender": "female", + "age": 33, + "address": { + "state": "Kansas", + "city": "Worcester" + } + }, + { + "id": 8872, + "name": "Nixon Cherry", + "gender": "male", + "age": 32, + "address": { + "state": "Massachusetts", + "city": "Osage" + } + }, + { + "id": 8873, + "name": "Elaine Kim", + "gender": "female", + "age": 26, + "address": { + "state": "Montana", + "city": "Eggertsville" + } + }, + { + "id": 8874, + "name": "Margery Quinn", + "gender": "female", + "age": 52, + "address": { + "state": "Vermont", + "city": "Crayne" + } + }, + { + "id": 8875, + "name": "Atkins Whitney", + "gender": "male", + "age": 32, + "address": { + "state": "Indiana", + "city": "Lowgap" + } + }, + { + "id": 8876, + "name": "Walker Cannon", + "gender": "male", + "age": 69, + "address": { + "state": "Ohio", + "city": "Rosewood" + } + }, + { + "id": 8877, + "name": "Janet Drake", + "gender": "female", + "age": 35, + "address": { + "state": "New Hampshire", + "city": "Blanco" + } + }, + { + "id": 8878, + "name": "Guzman Reeves", + "gender": "male", + "age": 61, + "address": { + "state": "Iowa", + "city": "Whitehaven" + } + }, + { + "id": 8879, + "name": "Rocha Sandoval", + "gender": "male", + "age": 20, + "address": { + "state": "Alaska", + "city": "Farmers" + } + }, + { + "id": 8880, + "name": "Smith Baker", + "gender": "male", + "age": 17, + "address": { + "state": "New York", + "city": "Robbins" + } + }, + { + "id": 8881, + "name": "Booker Newman", + "gender": "male", + "age": 36, + "address": { + "state": "Virginia", + "city": "Imperial" + } + }, + { + "id": 8882, + "name": "Marcie Eaton", + "gender": "female", + "age": 52, + "address": { + "state": "Wyoming", + "city": "Longoria" + } + }, + { + "id": 8883, + "name": "Guerra Davenport", + "gender": "male", + "age": 53, + "address": { + "state": "Kentucky", + "city": "Aberdeen" + } + }, + { + "id": 8884, + "name": "Moody Dunlap", + "gender": "male", + "age": 56, + "address": { + "state": "Hawaii", + "city": "Glenshaw" + } + }, + { + "id": 8885, + "name": "Bettye Leach", + "gender": "female", + "age": 81, + "address": { + "state": "Pennsylvania", + "city": "Fowlerville" + } + }, + { + "id": 8886, + "name": "Carly Chandler", + "gender": "female", + "age": 82, + "address": { + "state": "Georgia", + "city": "Blandburg" + } + }, + { + "id": 8887, + "name": "Mitchell Joyner", + "gender": "male", + "age": 60, + "address": { + "state": "California", + "city": "Barronett" + } + }, + { + "id": 8888, + "name": "Mcdonald Ramirez", + "gender": "male", + "age": 56, + "address": { + "state": "Texas", + "city": "Accoville" + } + }, + { + "id": 8889, + "name": "Bobbi Stanley", + "gender": "female", + "age": 41, + "address": { + "state": "Wisconsin", + "city": "Motley" + } + }, + { + "id": 8890, + "name": "Keri Vincent", + "gender": "female", + "age": 32, + "address": { + "state": "South Carolina", + "city": "Dundee" + } + }, + { + "id": 8891, + "name": "Fischer Hays", + "gender": "male", + "age": 53, + "address": { + "state": "Colorado", + "city": "Hamilton" + } + }, + { + "id": 8892, + "name": "Latonya Fitzpatrick", + "gender": "female", + "age": 66, + "address": { + "state": "Rhode Island", + "city": "Duryea" + } + }, + { + "id": 8893, + "name": "Hooper Conrad", + "gender": "male", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Glasgow" + } + }, + { + "id": 8894, + "name": "Rowena Dyer", + "gender": "female", + "age": 65, + "address": { + "state": "Missouri", + "city": "Garfield" + } + }, + { + "id": 8895, + "name": "Rowland Irwin", + "gender": "male", + "age": 43, + "address": { + "state": "Nebraska", + "city": "Chamizal" + } + }, + { + "id": 8896, + "name": "Gomez Ellis", + "gender": "male", + "age": 57, + "address": { + "state": "Nevada", + "city": "Geyserville" + } + }, + { + "id": 8897, + "name": "Dawn Rowland", + "gender": "female", + "age": 66, + "address": { + "state": "Alabama", + "city": "Kula" + } + }, + { + "id": 8898, + "name": "Mercedes Foster", + "gender": "female", + "age": 23, + "address": { + "state": "Idaho", + "city": "Darrtown" + } + }, + { + "id": 8899, + "name": "Brandy Harris", + "gender": "female", + "age": 43, + "address": { + "state": "Mississippi", + "city": "Wildwood" + } + }, + { + "id": 8900, + "name": "Shelton Velasquez", + "gender": "male", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Needmore" + } + }, + { + "id": 8901, + "name": "Velasquez Griffin", + "gender": "male", + "age": 21, + "address": { + "state": "Washington", + "city": "Riceville" + } + }, + { + "id": 8902, + "name": "Kitty Boyle", + "gender": "female", + "age": 33, + "address": { + "state": "Illinois", + "city": "Grenelefe" + } + }, + { + "id": 8903, + "name": "Pitts Tate", + "gender": "male", + "age": 77, + "address": { + "state": "South Dakota", + "city": "Edneyville" + } + }, + { + "id": 8904, + "name": "Vinson Nelson", + "gender": "male", + "age": 76, + "address": { + "state": "West Virginia", + "city": "Gratton" + } + }, + { + "id": 8905, + "name": "Campos Douglas", + "gender": "male", + "age": 30, + "address": { + "state": "Michigan", + "city": "Carlton" + } + }, + { + "id": 8906, + "name": "Selena Craig", + "gender": "female", + "age": 77, + "address": { + "state": "New Mexico", + "city": "Orason" + } + }, + { + "id": 8907, + "name": "Silvia Kaufman", + "gender": "female", + "age": 74, + "address": { + "state": "North Dakota", + "city": "Floris" + } + }, + { + "id": 8908, + "name": "Morgan Perez", + "gender": "female", + "age": 18, + "address": { + "state": "Arkansas", + "city": "Fairmount" + } + }, + { + "id": 8909, + "name": "Nash Wiggins", + "gender": "male", + "age": 32, + "address": { + "state": "Florida", + "city": "Calverton" + } + }, + { + "id": 8910, + "name": "Roy Sullivan", + "gender": "male", + "age": 37, + "address": { + "state": "North Carolina", + "city": "Stonybrook" + } + }, + { + "id": 8911, + "name": "Booth Contreras", + "gender": "male", + "age": 45, + "address": { + "state": "Delaware", + "city": "Groton" + } + }, + { + "id": 8912, + "name": "Alford Schmidt", + "gender": "male", + "age": 60, + "address": { + "state": "Arizona", + "city": "Thornport" + } + }, + { + "id": 8913, + "name": "Mcgowan Blevins", + "gender": "male", + "age": 80, + "address": { + "state": "Utah", + "city": "Makena" + } + }, + { + "id": 8914, + "name": "Rachel Ward", + "gender": "female", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Hemlock" + } + }, + { + "id": 8915, + "name": "Deena Taylor", + "gender": "female", + "age": 58, + "address": { + "state": "Minnesota", + "city": "Caln" + } + }, + { + "id": 8916, + "name": "Noemi Kirkland", + "gender": "female", + "age": 62, + "address": { + "state": "New Jersey", + "city": "Noxen" + } + }, + { + "id": 8917, + "name": "Franklin Blankenship", + "gender": "male", + "age": 53, + "address": { + "state": "Maine", + "city": "Williams" + } + }, + { + "id": 8918, + "name": "Jeanie Mccall", + "gender": "female", + "age": 52, + "address": { + "state": "Michigan", + "city": "Hobucken" + } + }, + { + "id": 8919, + "name": "Sykes Best", + "gender": "male", + "age": 56, + "address": { + "state": "Montana", + "city": "Stevens" + } + }, + { + "id": 8920, + "name": "Aurelia Zimmerman", + "gender": "female", + "age": 67, + "address": { + "state": "Florida", + "city": "Stockdale" + } + }, + { + "id": 8921, + "name": "Flossie Dominguez", + "gender": "female", + "age": 81, + "address": { + "state": "New Hampshire", + "city": "Brookfield" + } + }, + { + "id": 8922, + "name": "Shields Tyler", + "gender": "male", + "age": 42, + "address": { + "state": "North Dakota", + "city": "Washington" + } + }, + { + "id": 8923, + "name": "Amanda Mullen", + "gender": "female", + "age": 41, + "address": { + "state": "Mississippi", + "city": "Carbonville" + } + }, + { + "id": 8924, + "name": "Carpenter Nieves", + "gender": "male", + "age": 34, + "address": { + "state": "South Dakota", + "city": "Twilight" + } + }, + { + "id": 8925, + "name": "Lewis Carlson", + "gender": "male", + "age": 48, + "address": { + "state": "Maryland", + "city": "Chamberino" + } + }, + { + "id": 8926, + "name": "Adela Gregory", + "gender": "female", + "age": 28, + "address": { + "state": "Wisconsin", + "city": "Valle" + } + }, + { + "id": 8927, + "name": "Collins Rhodes", + "gender": "male", + "age": 64, + "address": { + "state": "New York", + "city": "Cascades" + } + }, + { + "id": 8928, + "name": "Maryellen Shannon", + "gender": "female", + "age": 82, + "address": { + "state": "New Mexico", + "city": "Naomi" + } + }, + { + "id": 8929, + "name": "Nora Pollard", + "gender": "female", + "age": 69, + "address": { + "state": "Arizona", + "city": "Westphalia" + } + }, + { + "id": 8930, + "name": "Joanne Berg", + "gender": "female", + "age": 59, + "address": { + "state": "Kansas", + "city": "Bannock" + } + }, + { + "id": 8931, + "name": "Jewel Tran", + "gender": "female", + "age": 38, + "address": { + "state": "Massachusetts", + "city": "Jacksonwald" + } + }, + { + "id": 8932, + "name": "Kelley Day", + "gender": "female", + "age": 26, + "address": { + "state": "Oregon", + "city": "Linganore" + } + }, + { + "id": 8933, + "name": "Johanna Velazquez", + "gender": "female", + "age": 36, + "address": { + "state": "Vermont", + "city": "Eastvale" + } + }, + { + "id": 8934, + "name": "Shawn Velasquez", + "gender": "female", + "age": 58, + "address": { + "state": "Maine", + "city": "Tolu" + } + }, + { + "id": 8935, + "name": "Lydia Hansen", + "gender": "female", + "age": 65, + "address": { + "state": "Kentucky", + "city": "Waverly" + } + }, + { + "id": 8936, + "name": "Sara Roy", + "gender": "female", + "age": 52, + "address": { + "state": "Virginia", + "city": "Riceville" + } + }, + { + "id": 8937, + "name": "Scott Bradley", + "gender": "male", + "age": 80, + "address": { + "state": "Tennessee", + "city": "Clarksburg" + } + }, + { + "id": 8938, + "name": "Cash Harrison", + "gender": "male", + "age": 19, + "address": { + "state": "Texas", + "city": "Nipinnawasee" + } + }, + { + "id": 8939, + "name": "Guadalupe Sexton", + "gender": "female", + "age": 49, + "address": { + "state": "Hawaii", + "city": "Rose" + } + }, + { + "id": 8940, + "name": "Bean Boone", + "gender": "male", + "age": 79, + "address": { + "state": "Nevada", + "city": "Rosewood" + } + }, + { + "id": 8941, + "name": "Cornelia Walls", + "gender": "female", + "age": 61, + "address": { + "state": "South Carolina", + "city": "Montura" + } + }, + { + "id": 8942, + "name": "Caitlin Patrick", + "gender": "female", + "age": 24, + "address": { + "state": "Utah", + "city": "Fingerville" + } + }, + { + "id": 8943, + "name": "Patel Davidson", + "gender": "male", + "age": 22, + "address": { + "state": "Colorado", + "city": "Brogan" + } + }, + { + "id": 8944, + "name": "Essie Nunez", + "gender": "female", + "age": 59, + "address": { + "state": "California", + "city": "Corinne" + } + }, + { + "id": 8945, + "name": "Carver Duke", + "gender": "male", + "age": 64, + "address": { + "state": "Oklahoma", + "city": "Woodburn" + } + }, + { + "id": 8946, + "name": "Edwards Roth", + "gender": "male", + "age": 53, + "address": { + "state": "Nebraska", + "city": "Sexton" + } + }, + { + "id": 8947, + "name": "Helen Bruce", + "gender": "female", + "age": 39, + "address": { + "state": "Missouri", + "city": "Troy" + } + }, + { + "id": 8948, + "name": "Delaney Luna", + "gender": "male", + "age": 76, + "address": { + "state": "Idaho", + "city": "Seymour" + } + }, + { + "id": 8949, + "name": "Arnold Moore", + "gender": "male", + "age": 35, + "address": { + "state": "New Jersey", + "city": "Bellfountain" + } + }, + { + "id": 8950, + "name": "Harrison Lewis", + "gender": "male", + "age": 78, + "address": { + "state": "Alaska", + "city": "Kenvil" + } + }, + { + "id": 8951, + "name": "Cleveland Mckenzie", + "gender": "male", + "age": 74, + "address": { + "state": "Arkansas", + "city": "Mathews" + } + }, + { + "id": 8952, + "name": "Brewer Nolan", + "gender": "male", + "age": 66, + "address": { + "state": "Rhode Island", + "city": "Efland" + } + }, + { + "id": 8953, + "name": "Bolton Summers", + "gender": "male", + "age": 80, + "address": { + "state": "Minnesota", + "city": "Finderne" + } + }, + { + "id": 8954, + "name": "Melissa Jackson", + "gender": "female", + "age": 22, + "address": { + "state": "Georgia", + "city": "Bawcomville" + } + }, + { + "id": 8955, + "name": "Kerr Guerrero", + "gender": "male", + "age": 32, + "address": { + "state": "Alabama", + "city": "Lupton" + } + }, + { + "id": 8956, + "name": "Jill Hodge", + "gender": "female", + "age": 51, + "address": { + "state": "Connecticut", + "city": "Monument" + } + }, + { + "id": 8957, + "name": "Howell Blake", + "gender": "male", + "age": 33, + "address": { + "state": "Illinois", + "city": "Dana" + } + }, + { + "id": 8958, + "name": "Robert Elliott", + "gender": "female", + "age": 35, + "address": { + "state": "Pennsylvania", + "city": "Villarreal" + } + }, + { + "id": 8959, + "name": "Reynolds Barrera", + "gender": "male", + "age": 32, + "address": { + "state": "North Carolina", + "city": "Tedrow" + } + }, + { + "id": 8960, + "name": "Mcleod Gillespie", + "gender": "male", + "age": 37, + "address": { + "state": "West Virginia", + "city": "Somerset" + } + }, + { + "id": 8961, + "name": "Mcpherson Stokes", + "gender": "male", + "age": 61, + "address": { + "state": "Washington", + "city": "Fairview" + } + }, + { + "id": 8962, + "name": "Helena Benjamin", + "gender": "female", + "age": 20, + "address": { + "state": "Indiana", + "city": "Fannett" + } + }, + { + "id": 8963, + "name": "Gardner Andrews", + "gender": "male", + "age": 25, + "address": { + "state": "Louisiana", + "city": "Dragoon" + } + }, + { + "id": 8964, + "name": "Landry Pacheco", + "gender": "male", + "age": 41, + "address": { + "state": "Iowa", + "city": "Silkworth" + } + }, + { + "id": 8965, + "name": "Farley Nicholson", + "gender": "male", + "age": 61, + "address": { + "state": "Delaware", + "city": "Jamestown" + } + }, + { + "id": 8966, + "name": "Yates Sutton", + "gender": "male", + "age": 59, + "address": { + "state": "Ohio", + "city": "Wadsworth" + } + }, + { + "id": 8967, + "name": "Marcella Crosby", + "gender": "female", + "age": 39, + "address": { + "state": "California", + "city": "Lorraine" + } + }, + { + "id": 8968, + "name": "Soto Oneal", + "gender": "male", + "age": 76, + "address": { + "state": "Utah", + "city": "Sehili" + } + }, + { + "id": 8969, + "name": "Bush Vega", + "gender": "male", + "age": 35, + "address": { + "state": "Iowa", + "city": "Hollins" + } + }, + { + "id": 8970, + "name": "Dyer Barnett", + "gender": "male", + "age": 55, + "address": { + "state": "Wyoming", + "city": "Rutherford" + } + }, + { + "id": 8971, + "name": "Heath Burch", + "gender": "male", + "age": 26, + "address": { + "state": "Pennsylvania", + "city": "Cade" + } + }, + { + "id": 8972, + "name": "June Austin", + "gender": "female", + "age": 44, + "address": { + "state": "Idaho", + "city": "Emison" + } + }, + { + "id": 8973, + "name": "Jacklyn Gutierrez", + "gender": "female", + "age": 29, + "address": { + "state": "Rhode Island", + "city": "Tryon" + } + }, + { + "id": 8974, + "name": "Amparo Castillo", + "gender": "female", + "age": 39, + "address": { + "state": "Connecticut", + "city": "Holcombe" + } + }, + { + "id": 8975, + "name": "Perez Higgins", + "gender": "male", + "age": 43, + "address": { + "state": "Michigan", + "city": "Belgreen" + } + }, + { + "id": 8976, + "name": "Tran Crosby", + "gender": "male", + "age": 60, + "address": { + "state": "Indiana", + "city": "Hamilton" + } + }, + { + "id": 8977, + "name": "Olive Briggs", + "gender": "female", + "age": 70, + "address": { + "state": "Minnesota", + "city": "Turah" + } + }, + { + "id": 8978, + "name": "Merritt Ryan", + "gender": "male", + "age": 48, + "address": { + "state": "Hawaii", + "city": "Brandermill" + } + }, + { + "id": 8979, + "name": "Louisa Dyer", + "gender": "female", + "age": 35, + "address": { + "state": "Massachusetts", + "city": "Keller" + } + }, + { + "id": 8980, + "name": "Melva Huff", + "gender": "female", + "age": 63, + "address": { + "state": "Maine", + "city": "Albrightsville" + } + }, + { + "id": 8981, + "name": "Jacqueline White", + "gender": "female", + "age": 50, + "address": { + "state": "Louisiana", + "city": "Lookingglass" + } + }, + { + "id": 8982, + "name": "Fulton Mckay", + "gender": "male", + "age": 33, + "address": { + "state": "Kansas", + "city": "Deltaville" + } + }, + { + "id": 8983, + "name": "Jaime Rutledge", + "gender": "female", + "age": 65, + "address": { + "state": "Alabama", + "city": "Jenkinsville" + } + }, + { + "id": 8984, + "name": "Debra Gallegos", + "gender": "female", + "age": 80, + "address": { + "state": "Colorado", + "city": "Rivera" + } + }, + { + "id": 8985, + "name": "Winnie Reid", + "gender": "female", + "age": 60, + "address": { + "state": "Nebraska", + "city": "Succasunna" + } + }, + { + "id": 8986, + "name": "Hunt Gould", + "gender": "male", + "age": 17, + "address": { + "state": "Arkansas", + "city": "Canoochee" + } + }, + { + "id": 8987, + "name": "Myers Stevens", + "gender": "male", + "age": 32, + "address": { + "state": "Vermont", + "city": "Harleigh" + } + }, + { + "id": 8988, + "name": "Concetta Diaz", + "gender": "female", + "age": 33, + "address": { + "state": "Missouri", + "city": "Islandia" + } + }, + { + "id": 8989, + "name": "Lina Brock", + "gender": "female", + "age": 69, + "address": { + "state": "Tennessee", + "city": "Caln" + } + }, + { + "id": 8990, + "name": "Meyer Ramos", + "gender": "male", + "age": 22, + "address": { + "state": "Maryland", + "city": "Shawmut" + } + }, + { + "id": 8991, + "name": "Lela Mcpherson", + "gender": "female", + "age": 31, + "address": { + "state": "Wisconsin", + "city": "Northchase" + } + }, + { + "id": 8992, + "name": "Jennie York", + "gender": "female", + "age": 59, + "address": { + "state": "North Carolina", + "city": "Boykin" + } + }, + { + "id": 8993, + "name": "Marcella Hendricks", + "gender": "female", + "age": 40, + "address": { + "state": "New York", + "city": "Bradenville" + } + }, + { + "id": 8994, + "name": "Bernice Mcguire", + "gender": "female", + "age": 49, + "address": { + "state": "Delaware", + "city": "Sardis" + } + }, + { + "id": 8995, + "name": "Pugh Anderson", + "gender": "male", + "age": 64, + "address": { + "state": "West Virginia", + "city": "Odessa" + } + }, + { + "id": 8996, + "name": "Violet Thornton", + "gender": "female", + "age": 31, + "address": { + "state": "Illinois", + "city": "Goochland" + } + }, + { + "id": 8997, + "name": "Candace Hinton", + "gender": "female", + "age": 58, + "address": { + "state": "New Mexico", + "city": "Gordon" + } + }, + { + "id": 8998, + "name": "Owens Kemp", + "gender": "male", + "age": 17, + "address": { + "state": "Georgia", + "city": "Winesburg" + } + }, + { + "id": 8999, + "name": "Chang Rivers", + "gender": "male", + "age": 46, + "address": { + "state": "Texas", + "city": "Grandview" + } + }, + { + "id": 9000, + "name": "Deanna Levy", + "gender": "female", + "age": 61, + "address": { + "state": "Ohio", + "city": "Savannah" + } + }, + { + "id": 9001, + "name": "Crystal Ramsey", + "gender": "female", + "age": 36, + "address": { + "state": "New Hampshire", + "city": "Rushford" + } + }, + { + "id": 9002, + "name": "Brittany Todd", + "gender": "female", + "age": 76, + "address": { + "state": "Montana", + "city": "Lacomb" + } + }, + { + "id": 9003, + "name": "Nikki Snyder", + "gender": "female", + "age": 79, + "address": { + "state": "Arizona", + "city": "Martell" + } + }, + { + "id": 9004, + "name": "Claire Randolph", + "gender": "female", + "age": 40, + "address": { + "state": "South Dakota", + "city": "Mooresburg" + } + }, + { + "id": 9005, + "name": "Dollie Vang", + "gender": "female", + "age": 50, + "address": { + "state": "Oklahoma", + "city": "Wadsworth" + } + }, + { + "id": 9006, + "name": "Traci Pruitt", + "gender": "female", + "age": 21, + "address": { + "state": "Oregon", + "city": "Joppa" + } + }, + { + "id": 9007, + "name": "Hilda Clark", + "gender": "female", + "age": 34, + "address": { + "state": "Florida", + "city": "Iberia" + } + }, + { + "id": 9008, + "name": "Hazel Parsons", + "gender": "female", + "age": 55, + "address": { + "state": "New Jersey", + "city": "Columbus" + } + }, + { + "id": 9009, + "name": "Sawyer Hines", + "gender": "male", + "age": 46, + "address": { + "state": "Alaska", + "city": "Kraemer" + } + }, + { + "id": 9010, + "name": "Robbins Rollins", + "gender": "male", + "age": 40, + "address": { + "state": "Washington", + "city": "Lewis" + } + }, + { + "id": 9011, + "name": "Pittman Head", + "gender": "male", + "age": 18, + "address": { + "state": "North Dakota", + "city": "Fairlee" + } + }, + { + "id": 9012, + "name": "Kay Noel", + "gender": "female", + "age": 40, + "address": { + "state": "Kentucky", + "city": "Websterville" + } + }, + { + "id": 9013, + "name": "Shawna Nguyen", + "gender": "female", + "age": 82, + "address": { + "state": "Nevada", + "city": "Charco" + } + }, + { + "id": 9014, + "name": "Renee Howe", + "gender": "female", + "age": 64, + "address": { + "state": "Mississippi", + "city": "Warren" + } + }, + { + "id": 9015, + "name": "Wilcox Aguirre", + "gender": "male", + "age": 75, + "address": { + "state": "South Carolina", + "city": "Chamberino" + } + }, + { + "id": 9016, + "name": "Myrtle Sharpe", + "gender": "female", + "age": 35, + "address": { + "state": "Mississippi", + "city": "Whitmer" + } + }, + { + "id": 9017, + "name": "Randolph Vasquez", + "gender": "male", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Neibert" + } + }, + { + "id": 9018, + "name": "Audra Espinoza", + "gender": "female", + "age": 35, + "address": { + "state": "Vermont", + "city": "Clay" + } + }, + { + "id": 9019, + "name": "Brewer Reese", + "gender": "male", + "age": 67, + "address": { + "state": "Virginia", + "city": "Watchtower" + } + }, + { + "id": 9020, + "name": "Lillian Donovan", + "gender": "female", + "age": 23, + "address": { + "state": "Utah", + "city": "Forestburg" + } + }, + { + "id": 9021, + "name": "Natalie Goodman", + "gender": "female", + "age": 77, + "address": { + "state": "Texas", + "city": "Kingstowne" + } + }, + { + "id": 9022, + "name": "Goff Mcfarland", + "gender": "male", + "age": 50, + "address": { + "state": "Missouri", + "city": "Wintersburg" + } + }, + { + "id": 9023, + "name": "Morin Clarke", + "gender": "male", + "age": 66, + "address": { + "state": "Idaho", + "city": "Gulf" + } + }, + { + "id": 9024, + "name": "Louella Best", + "gender": "female", + "age": 55, + "address": { + "state": "Arizona", + "city": "Bayview" + } + }, + { + "id": 9025, + "name": "Oneill Mayo", + "gender": "male", + "age": 52, + "address": { + "state": "Michigan", + "city": "Volta" + } + }, + { + "id": 9026, + "name": "Talley Holmes", + "gender": "male", + "age": 22, + "address": { + "state": "Rhode Island", + "city": "Ruffin" + } + }, + { + "id": 9027, + "name": "Hoffman Gallegos", + "gender": "male", + "age": 68, + "address": { + "state": "Alaska", + "city": "Tuttle" + } + }, + { + "id": 9028, + "name": "Ivy Crosby", + "gender": "female", + "age": 37, + "address": { + "state": "Alabama", + "city": "Cannondale" + } + }, + { + "id": 9029, + "name": "Trisha Cross", + "gender": "female", + "age": 19, + "address": { + "state": "Wisconsin", + "city": "Conway" + } + }, + { + "id": 9030, + "name": "Shawn Valdez", + "gender": "female", + "age": 63, + "address": { + "state": "Nebraska", + "city": "Cliffside" + } + }, + { + "id": 9031, + "name": "Holmes Petty", + "gender": "male", + "age": 33, + "address": { + "state": "Illinois", + "city": "Hartsville/Hartley" + } + }, + { + "id": 9032, + "name": "Hanson England", + "gender": "male", + "age": 46, + "address": { + "state": "Kansas", + "city": "Moraida" + } + }, + { + "id": 9033, + "name": "Small Carey", + "gender": "male", + "age": 18, + "address": { + "state": "Iowa", + "city": "Belleview" + } + }, + { + "id": 9034, + "name": "Huffman Gay", + "gender": "male", + "age": 80, + "address": { + "state": "Arkansas", + "city": "Eggertsville" + } + }, + { + "id": 9035, + "name": "Anderson Phelps", + "gender": "male", + "age": 18, + "address": { + "state": "New York", + "city": "Williston" + } + }, + { + "id": 9036, + "name": "Virgie Monroe", + "gender": "female", + "age": 22, + "address": { + "state": "Maine", + "city": "Wattsville" + } + }, + { + "id": 9037, + "name": "Delacruz Mccarthy", + "gender": "male", + "age": 36, + "address": { + "state": "Florida", + "city": "Allentown" + } + }, + { + "id": 9038, + "name": "Dale Mcgowan", + "gender": "male", + "age": 50, + "address": { + "state": "Massachusetts", + "city": "Trexlertown" + } + }, + { + "id": 9039, + "name": "Corina Oneill", + "gender": "female", + "age": 61, + "address": { + "state": "Indiana", + "city": "Warren" + } + }, + { + "id": 9040, + "name": "Ochoa Zimmerman", + "gender": "male", + "age": 18, + "address": { + "state": "West Virginia", + "city": "Blanford" + } + }, + { + "id": 9041, + "name": "Mckenzie Walker", + "gender": "male", + "age": 54, + "address": { + "state": "Kentucky", + "city": "Fowlerville" + } + }, + { + "id": 9042, + "name": "Charles Hartman", + "gender": "male", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Brownlee" + } + }, + { + "id": 9043, + "name": "Allie Terrell", + "gender": "female", + "age": 65, + "address": { + "state": "North Carolina", + "city": "Fillmore" + } + }, + { + "id": 9044, + "name": "Blake Burton", + "gender": "male", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Blodgett" + } + }, + { + "id": 9045, + "name": "Sanchez Brady", + "gender": "male", + "age": 45, + "address": { + "state": "California", + "city": "Finderne" + } + }, + { + "id": 9046, + "name": "Rowland Leon", + "gender": "male", + "age": 28, + "address": { + "state": "Nevada", + "city": "Allendale" + } + }, + { + "id": 9047, + "name": "Donaldson Sweeney", + "gender": "male", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Rowe" + } + }, + { + "id": 9048, + "name": "Bender Mcneil", + "gender": "male", + "age": 61, + "address": { + "state": "New Jersey", + "city": "Bagtown" + } + }, + { + "id": 9049, + "name": "Bertie Lucas", + "gender": "female", + "age": 20, + "address": { + "state": "Pennsylvania", + "city": "Beaulieu" + } + }, + { + "id": 9050, + "name": "Marta Peck", + "gender": "female", + "age": 42, + "address": { + "state": "Oregon", + "city": "Calverton" + } + }, + { + "id": 9051, + "name": "Katherine Morrow", + "gender": "female", + "age": 54, + "address": { + "state": "Delaware", + "city": "Harrodsburg" + } + }, + { + "id": 9052, + "name": "Butler Kemp", + "gender": "male", + "age": 70, + "address": { + "state": "Oklahoma", + "city": "Curtice" + } + }, + { + "id": 9053, + "name": "Pearl Miles", + "gender": "female", + "age": 63, + "address": { + "state": "North Dakota", + "city": "Omar" + } + }, + { + "id": 9054, + "name": "Leta Farmer", + "gender": "female", + "age": 77, + "address": { + "state": "Colorado", + "city": "Bend" + } + }, + { + "id": 9055, + "name": "Maritza Davenport", + "gender": "female", + "age": 71, + "address": { + "state": "Ohio", + "city": "Waverly" + } + }, + { + "id": 9056, + "name": "Clayton Avila", + "gender": "male", + "age": 47, + "address": { + "state": "Tennessee", + "city": "Calvary" + } + }, + { + "id": 9057, + "name": "Randi Hamilton", + "gender": "female", + "age": 27, + "address": { + "state": "Montana", + "city": "Konterra" + } + }, + { + "id": 9058, + "name": "Mcintosh Shelton", + "gender": "male", + "age": 40, + "address": { + "state": "Hawaii", + "city": "Brenton" + } + }, + { + "id": 9059, + "name": "Marsh Bishop", + "gender": "male", + "age": 38, + "address": { + "state": "Wyoming", + "city": "Dodge" + } + }, + { + "id": 9060, + "name": "Elliott Young", + "gender": "male", + "age": 60, + "address": { + "state": "Connecticut", + "city": "Boykin" + } + }, + { + "id": 9061, + "name": "Wilson Aguilar", + "gender": "male", + "age": 23, + "address": { + "state": "Georgia", + "city": "Hegins" + } + }, + { + "id": 9062, + "name": "Glenna Lawson", + "gender": "female", + "age": 29, + "address": { + "state": "New Hampshire", + "city": "Inkerman" + } + }, + { + "id": 9063, + "name": "Alicia Doyle", + "gender": "female", + "age": 52, + "address": { + "state": "Maryland", + "city": "Fannett" + } + }, + { + "id": 9064, + "name": "Nora Sampson", + "gender": "female", + "age": 58, + "address": { + "state": "South Dakota", + "city": "Tryon" + } + }, + { + "id": 9065, + "name": "Diane Roach", + "gender": "female", + "age": 24, + "address": { + "state": "Hawaii", + "city": "Watrous" + } + }, + { + "id": 9066, + "name": "Arnold Marks", + "gender": "male", + "age": 17, + "address": { + "state": "Iowa", + "city": "Yukon" + } + }, + { + "id": 9067, + "name": "Huber Wilson", + "gender": "male", + "age": 29, + "address": { + "state": "Minnesota", + "city": "Hessville" + } + }, + { + "id": 9068, + "name": "Geneva Tyler", + "gender": "female", + "age": 82, + "address": { + "state": "Nevada", + "city": "Retsof" + } + }, + { + "id": 9069, + "name": "Adela Whitley", + "gender": "female", + "age": 26, + "address": { + "state": "Utah", + "city": "Marysville" + } + }, + { + "id": 9070, + "name": "Ramos Sanders", + "gender": "male", + "age": 76, + "address": { + "state": "Massachusetts", + "city": "Woodlands" + } + }, + { + "id": 9071, + "name": "Pugh Sears", + "gender": "male", + "age": 44, + "address": { + "state": "Arkansas", + "city": "Chicopee" + } + }, + { + "id": 9072, + "name": "Duncan Blevins", + "gender": "male", + "age": 51, + "address": { + "state": "Maryland", + "city": "Coral" + } + }, + { + "id": 9073, + "name": "Blanca Davis", + "gender": "female", + "age": 57, + "address": { + "state": "North Dakota", + "city": "Chase" + } + }, + { + "id": 9074, + "name": "Knox Caldwell", + "gender": "male", + "age": 18, + "address": { + "state": "Wyoming", + "city": "Mapletown" + } + }, + { + "id": 9075, + "name": "York Washington", + "gender": "male", + "age": 35, + "address": { + "state": "Michigan", + "city": "Gibsonia" + } + }, + { + "id": 9076, + "name": "Kerri Blake", + "gender": "female", + "age": 72, + "address": { + "state": "Vermont", + "city": "Edmund" + } + }, + { + "id": 9077, + "name": "Marjorie Reid", + "gender": "female", + "age": 46, + "address": { + "state": "Washington", + "city": "Floriston" + } + }, + { + "id": 9078, + "name": "Gardner Wagner", + "gender": "male", + "age": 68, + "address": { + "state": "Pennsylvania", + "city": "Rockingham" + } + }, + { + "id": 9079, + "name": "Kane Glover", + "gender": "male", + "age": 23, + "address": { + "state": "Connecticut", + "city": "Swartzville" + } + }, + { + "id": 9080, + "name": "Frye Whitehead", + "gender": "male", + "age": 76, + "address": { + "state": "Oregon", + "city": "Independence" + } + }, + { + "id": 9081, + "name": "Laurie Mendoza", + "gender": "female", + "age": 45, + "address": { + "state": "Louisiana", + "city": "Dixonville" + } + }, + { + "id": 9082, + "name": "Hogan Sharpe", + "gender": "male", + "age": 71, + "address": { + "state": "Georgia", + "city": "Delco" + } + }, + { + "id": 9083, + "name": "Beatrice Romero", + "gender": "female", + "age": 59, + "address": { + "state": "Colorado", + "city": "Brownlee" + } + }, + { + "id": 9084, + "name": "Jarvis Briggs", + "gender": "male", + "age": 33, + "address": { + "state": "Wisconsin", + "city": "Witmer" + } + }, + { + "id": 9085, + "name": "Lilian Coleman", + "gender": "female", + "age": 23, + "address": { + "state": "South Dakota", + "city": "Southmont" + } + }, + { + "id": 9086, + "name": "Estelle Sawyer", + "gender": "female", + "age": 49, + "address": { + "state": "Illinois", + "city": "Deercroft" + } + }, + { + "id": 9087, + "name": "Blair Harper", + "gender": "male", + "age": 39, + "address": { + "state": "Alabama", + "city": "Northchase" + } + }, + { + "id": 9088, + "name": "Margret Clemons", + "gender": "female", + "age": 30, + "address": { + "state": "Indiana", + "city": "Wiscon" + } + }, + { + "id": 9089, + "name": "Lane Patel", + "gender": "male", + "age": 31, + "address": { + "state": "Kentucky", + "city": "Villarreal" + } + }, + { + "id": 9090, + "name": "Stuart Shepard", + "gender": "male", + "age": 45, + "address": { + "state": "Kansas", + "city": "Smock" + } + }, + { + "id": 9091, + "name": "June Duncan", + "gender": "female", + "age": 42, + "address": { + "state": "Missouri", + "city": "Idledale" + } + }, + { + "id": 9092, + "name": "Polly Kane", + "gender": "female", + "age": 28, + "address": { + "state": "Nebraska", + "city": "Kirk" + } + }, + { + "id": 9093, + "name": "Vicki Haley", + "gender": "female", + "age": 19, + "address": { + "state": "New York", + "city": "Berlin" + } + }, + { + "id": 9094, + "name": "Imogene Morse", + "gender": "female", + "age": 47, + "address": { + "state": "South Carolina", + "city": "Longoria" + } + }, + { + "id": 9095, + "name": "Miranda Hoover", + "gender": "male", + "age": 27, + "address": { + "state": "Delaware", + "city": "Olney" + } + }, + { + "id": 9096, + "name": "Courtney Wooten", + "gender": "female", + "age": 48, + "address": { + "state": "Maine", + "city": "Cetronia" + } + }, + { + "id": 9097, + "name": "Iris Gill", + "gender": "female", + "age": 54, + "address": { + "state": "Idaho", + "city": "Coinjock" + } + }, + { + "id": 9098, + "name": "Reyna Robinson", + "gender": "female", + "age": 23, + "address": { + "state": "Arizona", + "city": "Goochland" + } + }, + { + "id": 9099, + "name": "Dennis Bradshaw", + "gender": "male", + "age": 37, + "address": { + "state": "North Carolina", + "city": "Orovada" + } + }, + { + "id": 9100, + "name": "Weeks Pruitt", + "gender": "male", + "age": 28, + "address": { + "state": "Mississippi", + "city": "Croom" + } + }, + { + "id": 9101, + "name": "Erma Key", + "gender": "female", + "age": 73, + "address": { + "state": "Alaska", + "city": "Allentown" + } + }, + { + "id": 9102, + "name": "Merle Klein", + "gender": "female", + "age": 43, + "address": { + "state": "Florida", + "city": "Boomer" + } + }, + { + "id": 9103, + "name": "Goodwin Adkins", + "gender": "male", + "age": 69, + "address": { + "state": "Ohio", + "city": "Zeba" + } + }, + { + "id": 9104, + "name": "Mckee Sparks", + "gender": "male", + "age": 21, + "address": { + "state": "New Hampshire", + "city": "Hondah" + } + }, + { + "id": 9105, + "name": "Richards Lancaster", + "gender": "male", + "age": 77, + "address": { + "state": "Tennessee", + "city": "Shaft" + } + }, + { + "id": 9106, + "name": "Atkinson Velazquez", + "gender": "male", + "age": 34, + "address": { + "state": "Rhode Island", + "city": "Gloucester" + } + }, + { + "id": 9107, + "name": "Randall Whitaker", + "gender": "male", + "age": 24, + "address": { + "state": "West Virginia", + "city": "Zortman" + } + }, + { + "id": 9108, + "name": "Mildred Vargas", + "gender": "female", + "age": 43, + "address": { + "state": "Montana", + "city": "Bonanza" + } + }, + { + "id": 9109, + "name": "Barlow Noble", + "gender": "male", + "age": 46, + "address": { + "state": "Virginia", + "city": "Barrelville" + } + }, + { + "id": 9110, + "name": "Clay Knight", + "gender": "male", + "age": 69, + "address": { + "state": "New Mexico", + "city": "Carlos" + } + }, + { + "id": 9111, + "name": "Mcconnell Clayton", + "gender": "male", + "age": 19, + "address": { + "state": "California", + "city": "Winston" + } + }, + { + "id": 9112, + "name": "Simon Sharp", + "gender": "male", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Emerald" + } + }, + { + "id": 9113, + "name": "Irwin Hodge", + "gender": "male", + "age": 65, + "address": { + "state": "Oklahoma", + "city": "Allamuchy" + } + }, + { + "id": 9114, + "name": "Martin Randolph", + "gender": "male", + "age": 64, + "address": { + "state": "Mississippi", + "city": "Glendale" + } + }, + { + "id": 9115, + "name": "Gabriela Knapp", + "gender": "female", + "age": 42, + "address": { + "state": "Missouri", + "city": "Carlos" + } + }, + { + "id": 9116, + "name": "Gracie Trujillo", + "gender": "female", + "age": 21, + "address": { + "state": "New Jersey", + "city": "Seymour" + } + }, + { + "id": 9117, + "name": "Rosa Salinas", + "gender": "female", + "age": 39, + "address": { + "state": "Georgia", + "city": "Juarez" + } + }, + { + "id": 9118, + "name": "Lawanda Gamble", + "gender": "female", + "age": 27, + "address": { + "state": "Washington", + "city": "Chalfant" + } + }, + { + "id": 9119, + "name": "Alexis Kim", + "gender": "female", + "age": 51, + "address": { + "state": "Montana", + "city": "Westerville" + } + }, + { + "id": 9120, + "name": "Buck Griffin", + "gender": "male", + "age": 42, + "address": { + "state": "Iowa", + "city": "Breinigsville" + } + }, + { + "id": 9121, + "name": "Compton Merritt", + "gender": "male", + "age": 74, + "address": { + "state": "Virginia", + "city": "Nadine" + } + }, + { + "id": 9122, + "name": "Robbie Madden", + "gender": "female", + "age": 78, + "address": { + "state": "New Mexico", + "city": "Alleghenyville" + } + }, + { + "id": 9123, + "name": "Oconnor Molina", + "gender": "male", + "age": 33, + "address": { + "state": "Vermont", + "city": "Lynn" + } + }, + { + "id": 9124, + "name": "Mabel Torres", + "gender": "female", + "age": 58, + "address": { + "state": "Wisconsin", + "city": "Inkerman" + } + }, + { + "id": 9125, + "name": "Kerry Greene", + "gender": "female", + "age": 43, + "address": { + "state": "Massachusetts", + "city": "Tuttle" + } + }, + { + "id": 9126, + "name": "Kathie Vega", + "gender": "female", + "age": 25, + "address": { + "state": "South Dakota", + "city": "Stockdale" + } + }, + { + "id": 9127, + "name": "Cooley Bright", + "gender": "male", + "age": 36, + "address": { + "state": "Maine", + "city": "Waukeenah" + } + }, + { + "id": 9128, + "name": "Davenport Campbell", + "gender": "male", + "age": 38, + "address": { + "state": "Oregon", + "city": "Calpine" + } + }, + { + "id": 9129, + "name": "Madeleine Lopez", + "gender": "female", + "age": 69, + "address": { + "state": "Idaho", + "city": "Itmann" + } + }, + { + "id": 9130, + "name": "Pamela Mack", + "gender": "female", + "age": 50, + "address": { + "state": "Oklahoma", + "city": "Convent" + } + }, + { + "id": 9131, + "name": "Sosa Garrison", + "gender": "male", + "age": 71, + "address": { + "state": "New York", + "city": "Boonville" + } + }, + { + "id": 9132, + "name": "Michael Bradley", + "gender": "female", + "age": 61, + "address": { + "state": "Utah", + "city": "Kerby" + } + }, + { + "id": 9133, + "name": "Bailey Pruitt", + "gender": "male", + "age": 53, + "address": { + "state": "South Carolina", + "city": "Tedrow" + } + }, + { + "id": 9134, + "name": "Terry Johns", + "gender": "male", + "age": 59, + "address": { + "state": "Indiana", + "city": "Bloomington" + } + }, + { + "id": 9135, + "name": "Stacie Velasquez", + "gender": "female", + "age": 57, + "address": { + "state": "Texas", + "city": "Ola" + } + }, + { + "id": 9136, + "name": "Dotson Wheeler", + "gender": "male", + "age": 57, + "address": { + "state": "California", + "city": "Allensworth" + } + }, + { + "id": 9137, + "name": "Jessie Nixon", + "gender": "female", + "age": 63, + "address": { + "state": "Florida", + "city": "Lutsen" + } + }, + { + "id": 9138, + "name": "Bridgette Mosley", + "gender": "female", + "age": 77, + "address": { + "state": "Alabama", + "city": "Stouchsburg" + } + }, + { + "id": 9139, + "name": "Riggs Hampton", + "gender": "male", + "age": 55, + "address": { + "state": "Pennsylvania", + "city": "Imperial" + } + }, + { + "id": 9140, + "name": "Eliza Brock", + "gender": "female", + "age": 80, + "address": { + "state": "Michigan", + "city": "Carlton" + } + }, + { + "id": 9141, + "name": "Hilda Hyde", + "gender": "female", + "age": 66, + "address": { + "state": "New Hampshire", + "city": "Fulford" + } + }, + { + "id": 9142, + "name": "Bush Murray", + "gender": "male", + "age": 49, + "address": { + "state": "Kansas", + "city": "Eureka" + } + }, + { + "id": 9143, + "name": "Ramona Barry", + "gender": "female", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Keller" + } + }, + { + "id": 9144, + "name": "Meadows Byrd", + "gender": "male", + "age": 43, + "address": { + "state": "Arkansas", + "city": "Snelling" + } + }, + { + "id": 9145, + "name": "Joan Mcgee", + "gender": "female", + "age": 21, + "address": { + "state": "Alaska", + "city": "Sanborn" + } + }, + { + "id": 9146, + "name": "Dickerson Hopkins", + "gender": "male", + "age": 41, + "address": { + "state": "Illinois", + "city": "Harrison" + } + }, + { + "id": 9147, + "name": "Joanna Munoz", + "gender": "female", + "age": 29, + "address": { + "state": "Kentucky", + "city": "Adamstown" + } + }, + { + "id": 9148, + "name": "Macdonald Melton", + "gender": "male", + "age": 20, + "address": { + "state": "Nebraska", + "city": "Garnet" + } + }, + { + "id": 9149, + "name": "Flossie Harrington", + "gender": "female", + "age": 17, + "address": { + "state": "Louisiana", + "city": "Geyserville" + } + }, + { + "id": 9150, + "name": "Hallie Mcneil", + "gender": "female", + "age": 17, + "address": { + "state": "Connecticut", + "city": "Woodburn" + } + }, + { + "id": 9151, + "name": "Beverly Bauer", + "gender": "female", + "age": 79, + "address": { + "state": "Wyoming", + "city": "Orason" + } + }, + { + "id": 9152, + "name": "Daugherty Johnson", + "gender": "male", + "age": 62, + "address": { + "state": "North Carolina", + "city": "Lacomb" + } + }, + { + "id": 9153, + "name": "Virginia Pratt", + "gender": "female", + "age": 57, + "address": { + "state": "Rhode Island", + "city": "Wawona" + } + }, + { + "id": 9154, + "name": "Ruiz Watkins", + "gender": "male", + "age": 19, + "address": { + "state": "North Dakota", + "city": "Volta" + } + }, + { + "id": 9155, + "name": "Ashlee Fleming", + "gender": "female", + "age": 20, + "address": { + "state": "Tennessee", + "city": "Bergoo" + } + }, + { + "id": 9156, + "name": "Morrow Gonzalez", + "gender": "male", + "age": 58, + "address": { + "state": "Delaware", + "city": "Snyderville" + } + }, + { + "id": 9157, + "name": "Hardy Marshall", + "gender": "male", + "age": 25, + "address": { + "state": "Hawaii", + "city": "Caspar" + } + }, + { + "id": 9158, + "name": "Tamra Montgomery", + "gender": "female", + "age": 29, + "address": { + "state": "Arizona", + "city": "Flintville" + } + }, + { + "id": 9159, + "name": "Jaime Sims", + "gender": "female", + "age": 45, + "address": { + "state": "Colorado", + "city": "Smock" + } + }, + { + "id": 9160, + "name": "Kidd Donaldson", + "gender": "male", + "age": 17, + "address": { + "state": "Nevada", + "city": "Martinez" + } + }, + { + "id": 9161, + "name": "Mercado Rivas", + "gender": "male", + "age": 57, + "address": { + "state": "Maryland", + "city": "Darrtown" + } + }, + { + "id": 9162, + "name": "Peterson Vaughn", + "gender": "male", + "age": 68, + "address": { + "state": "Minnesota", + "city": "Detroit" + } + }, + { + "id": 9163, + "name": "Case Wells", + "gender": "male", + "age": 60, + "address": { + "state": "South Dakota", + "city": "Avoca" + } + }, + { + "id": 9164, + "name": "Dora Poole", + "gender": "female", + "age": 42, + "address": { + "state": "New Jersey", + "city": "Bridgetown" + } + }, + { + "id": 9165, + "name": "Emilia Long", + "gender": "female", + "age": 29, + "address": { + "state": "Nebraska", + "city": "Allison" + } + }, + { + "id": 9166, + "name": "Jodi Edwards", + "gender": "female", + "age": 20, + "address": { + "state": "Iowa", + "city": "Sattley" + } + }, + { + "id": 9167, + "name": "Allyson Love", + "gender": "female", + "age": 66, + "address": { + "state": "Wyoming", + "city": "Blackgum" + } + }, + { + "id": 9168, + "name": "Mathews Palmer", + "gender": "male", + "age": 73, + "address": { + "state": "Pennsylvania", + "city": "Dunnavant" + } + }, + { + "id": 9169, + "name": "Monroe Hendrix", + "gender": "male", + "age": 64, + "address": { + "state": "Utah", + "city": "Bagtown" + } + }, + { + "id": 9170, + "name": "Bailey Barnett", + "gender": "male", + "age": 75, + "address": { + "state": "North Carolina", + "city": "Harborton" + } + }, + { + "id": 9171, + "name": "Taylor Lancaster", + "gender": "female", + "age": 64, + "address": { + "state": "Rhode Island", + "city": "Holcombe" + } + }, + { + "id": 9172, + "name": "Denise Caldwell", + "gender": "female", + "age": 65, + "address": { + "state": "New Hampshire", + "city": "Belleview" + } + }, + { + "id": 9173, + "name": "Levine Montoya", + "gender": "male", + "age": 26, + "address": { + "state": "Georgia", + "city": "Harold" + } + }, + { + "id": 9174, + "name": "Maude Valentine", + "gender": "female", + "age": 63, + "address": { + "state": "Kentucky", + "city": "Saranap" + } + }, + { + "id": 9175, + "name": "Beryl Castillo", + "gender": "female", + "age": 30, + "address": { + "state": "Colorado", + "city": "Irwin" + } + }, + { + "id": 9176, + "name": "Estrada Mason", + "gender": "male", + "age": 31, + "address": { + "state": "West Virginia", + "city": "Whipholt" + } + }, + { + "id": 9177, + "name": "Craig Blankenship", + "gender": "male", + "age": 29, + "address": { + "state": "Hawaii", + "city": "Driftwood" + } + }, + { + "id": 9178, + "name": "Cherry Olson", + "gender": "male", + "age": 76, + "address": { + "state": "Nevada", + "city": "Haena" + } + }, + { + "id": 9179, + "name": "Shawn Strong", + "gender": "female", + "age": 53, + "address": { + "state": "California", + "city": "Woodlands" + } + }, + { + "id": 9180, + "name": "Wallace May", + "gender": "male", + "age": 45, + "address": { + "state": "Connecticut", + "city": "Heil" + } + }, + { + "id": 9181, + "name": "Young Casey", + "gender": "male", + "age": 79, + "address": { + "state": "Mississippi", + "city": "Whitestone" + } + }, + { + "id": 9182, + "name": "Oneal Kline", + "gender": "male", + "age": 64, + "address": { + "state": "Michigan", + "city": "Coaldale" + } + }, + { + "id": 9183, + "name": "Elsa Hampton", + "gender": "female", + "age": 77, + "address": { + "state": "New Mexico", + "city": "Bowmansville" + } + }, + { + "id": 9184, + "name": "Colleen Jacobson", + "gender": "female", + "age": 76, + "address": { + "state": "Vermont", + "city": "Deltaville" + } + }, + { + "id": 9185, + "name": "Gill Hendricks", + "gender": "male", + "age": 80, + "address": { + "state": "Florida", + "city": "Sugartown" + } + }, + { + "id": 9186, + "name": "Elisa Brooks", + "gender": "female", + "age": 18, + "address": { + "state": "Idaho", + "city": "Hackneyville" + } + }, + { + "id": 9187, + "name": "Roberts Soto", + "gender": "male", + "age": 50, + "address": { + "state": "Wisconsin", + "city": "Waterford" + } + }, + { + "id": 9188, + "name": "Dorothea Aguilar", + "gender": "female", + "age": 76, + "address": { + "state": "North Dakota", + "city": "Lafferty" + } + }, + { + "id": 9189, + "name": "Snyder Macias", + "gender": "male", + "age": 46, + "address": { + "state": "Delaware", + "city": "Cobbtown" + } + }, + { + "id": 9190, + "name": "Sasha Sexton", + "gender": "female", + "age": 75, + "address": { + "state": "Maryland", + "city": "Boling" + } + }, + { + "id": 9191, + "name": "Brown Armstrong", + "gender": "male", + "age": 36, + "address": { + "state": "South Carolina", + "city": "Salix" + } + }, + { + "id": 9192, + "name": "Erika Lowe", + "gender": "female", + "age": 43, + "address": { + "state": "Alabama", + "city": "Richville" + } + }, + { + "id": 9193, + "name": "Swanson Durham", + "gender": "male", + "age": 75, + "address": { + "state": "Kansas", + "city": "Shindler" + } + }, + { + "id": 9194, + "name": "Schmidt Vega", + "gender": "male", + "age": 28, + "address": { + "state": "Maine", + "city": "Alamo" + } + }, + { + "id": 9195, + "name": "Felecia Barker", + "gender": "female", + "age": 62, + "address": { + "state": "Louisiana", + "city": "Barstow" + } + }, + { + "id": 9196, + "name": "Mcintosh Delaney", + "gender": "male", + "age": 48, + "address": { + "state": "Arkansas", + "city": "Cassel" + } + }, + { + "id": 9197, + "name": "Dejesus Moon", + "gender": "male", + "age": 41, + "address": { + "state": "Minnesota", + "city": "Bascom" + } + }, + { + "id": 9198, + "name": "Gabriela Williamson", + "gender": "female", + "age": 36, + "address": { + "state": "Virginia", + "city": "Coleville" + } + }, + { + "id": 9199, + "name": "Socorro Dotson", + "gender": "female", + "age": 27, + "address": { + "state": "Missouri", + "city": "Saddlebrooke" + } + }, + { + "id": 9200, + "name": "Ford Bonner", + "gender": "male", + "age": 60, + "address": { + "state": "Oklahoma", + "city": "Rote" + } + }, + { + "id": 9201, + "name": "Robles Welch", + "gender": "male", + "age": 28, + "address": { + "state": "Arizona", + "city": "Dragoon" + } + }, + { + "id": 9202, + "name": "Dolly Daniel", + "gender": "female", + "age": 42, + "address": { + "state": "Indiana", + "city": "Marienthal" + } + }, + { + "id": 9203, + "name": "Carlson Booker", + "gender": "male", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Gasquet" + } + }, + { + "id": 9204, + "name": "Buckley Burt", + "gender": "male", + "age": 35, + "address": { + "state": "New York", + "city": "Kylertown" + } + }, + { + "id": 9205, + "name": "Lucinda Mays", + "gender": "female", + "age": 61, + "address": { + "state": "Illinois", + "city": "Cloverdale" + } + }, + { + "id": 9206, + "name": "Elliott Middleton", + "gender": "male", + "age": 65, + "address": { + "state": "Texas", + "city": "Cedarville" + } + }, + { + "id": 9207, + "name": "Ina Robbins", + "gender": "female", + "age": 51, + "address": { + "state": "Alaska", + "city": "Brownlee" + } + }, + { + "id": 9208, + "name": "Lorene Watkins", + "gender": "female", + "age": 55, + "address": { + "state": "Montana", + "city": "Klagetoh" + } + }, + { + "id": 9209, + "name": "Sondra Gallegos", + "gender": "female", + "age": 22, + "address": { + "state": "Massachusetts", + "city": "Odessa" + } + }, + { + "id": 9210, + "name": "Lottie Keller", + "gender": "female", + "age": 30, + "address": { + "state": "Washington", + "city": "Wright" + } + }, + { + "id": 9211, + "name": "Kelly Morgan", + "gender": "male", + "age": 55, + "address": { + "state": "Oregon", + "city": "Sisquoc" + } + }, + { + "id": 9212, + "name": "Hallie Stokes", + "gender": "female", + "age": 29, + "address": { + "state": "Florida", + "city": "Garberville" + } + }, + { + "id": 9213, + "name": "Marion Reilly", + "gender": "female", + "age": 52, + "address": { + "state": "Pennsylvania", + "city": "Alfarata" + } + }, + { + "id": 9214, + "name": "Cecilia Gray", + "gender": "female", + "age": 46, + "address": { + "state": "Rhode Island", + "city": "Robbins" + } + }, + { + "id": 9215, + "name": "Eva Barlow", + "gender": "female", + "age": 61, + "address": { + "state": "Connecticut", + "city": "Gorst" + } + }, + { + "id": 9216, + "name": "Holcomb Chase", + "gender": "male", + "age": 24, + "address": { + "state": "North Carolina", + "city": "Hobucken" + } + }, + { + "id": 9217, + "name": "Jannie Odom", + "gender": "female", + "age": 27, + "address": { + "state": "Kansas", + "city": "Riceville" + } + }, + { + "id": 9218, + "name": "Kay Hinton", + "gender": "female", + "age": 71, + "address": { + "state": "Colorado", + "city": "Shindler" + } + }, + { + "id": 9219, + "name": "Robert Schneider", + "gender": "female", + "age": 69, + "address": { + "state": "South Dakota", + "city": "Cresaptown" + } + }, + { + "id": 9220, + "name": "Pruitt Larson", + "gender": "male", + "age": 64, + "address": { + "state": "Massachusetts", + "city": "Cecilia" + } + }, + { + "id": 9221, + "name": "Sonya Key", + "gender": "female", + "age": 30, + "address": { + "state": "Texas", + "city": "Glenshaw" + } + }, + { + "id": 9222, + "name": "Stevenson Roberts", + "gender": "male", + "age": 67, + "address": { + "state": "Delaware", + "city": "Chamizal" + } + }, + { + "id": 9223, + "name": "Kayla Marsh", + "gender": "female", + "age": 56, + "address": { + "state": "New Mexico", + "city": "Floris" + } + }, + { + "id": 9224, + "name": "Fleming Castillo", + "gender": "male", + "age": 40, + "address": { + "state": "Nebraska", + "city": "Eagleville" + } + }, + { + "id": 9225, + "name": "Glenda Stuart", + "gender": "female", + "age": 25, + "address": { + "state": "New York", + "city": "Selma" + } + }, + { + "id": 9226, + "name": "Kristen Ward", + "gender": "female", + "age": 42, + "address": { + "state": "Wisconsin", + "city": "Dunbar" + } + }, + { + "id": 9227, + "name": "Leanna Howe", + "gender": "female", + "age": 69, + "address": { + "state": "New Jersey", + "city": "Steinhatchee" + } + }, + { + "id": 9228, + "name": "Martin Austin", + "gender": "male", + "age": 78, + "address": { + "state": "Montana", + "city": "Golconda" + } + }, + { + "id": 9229, + "name": "Bond Grimes", + "gender": "male", + "age": 42, + "address": { + "state": "Utah", + "city": "Interlochen" + } + }, + { + "id": 9230, + "name": "Ryan Fisher", + "gender": "male", + "age": 49, + "address": { + "state": "Alabama", + "city": "Walker" + } + }, + { + "id": 9231, + "name": "Jacobs Bates", + "gender": "male", + "age": 43, + "address": { + "state": "South Carolina", + "city": "Courtland" + } + }, + { + "id": 9232, + "name": "Gaines Harris", + "gender": "male", + "age": 20, + "address": { + "state": "Louisiana", + "city": "Brethren" + } + }, + { + "id": 9233, + "name": "Deena Crosby", + "gender": "female", + "age": 33, + "address": { + "state": "Arkansas", + "city": "Cleary" + } + }, + { + "id": 9234, + "name": "Bridgette Hutchinson", + "gender": "female", + "age": 35, + "address": { + "state": "New Hampshire", + "city": "Bluetown" + } + }, + { + "id": 9235, + "name": "Gates Conrad", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Belmont" + } + }, + { + "id": 9236, + "name": "Casey Mathis", + "gender": "female", + "age": 17, + "address": { + "state": "Alaska", + "city": "Hampstead" + } + }, + { + "id": 9237, + "name": "Luz Carr", + "gender": "female", + "age": 25, + "address": { + "state": "Mississippi", + "city": "Lynn" + } + }, + { + "id": 9238, + "name": "Ladonna Gilmore", + "gender": "female", + "age": 61, + "address": { + "state": "Georgia", + "city": "Limestone" + } + }, + { + "id": 9239, + "name": "Rodriguez Walker", + "gender": "male", + "age": 49, + "address": { + "state": "Arizona", + "city": "Waukeenah" + } + }, + { + "id": 9240, + "name": "Vivian Mays", + "gender": "female", + "age": 30, + "address": { + "state": "Nevada", + "city": "Jugtown" + } + }, + { + "id": 9241, + "name": "Spears Kim", + "gender": "male", + "age": 30, + "address": { + "state": "Wyoming", + "city": "Riegelwood" + } + }, + { + "id": 9242, + "name": "Barker Lara", + "gender": "male", + "age": 64, + "address": { + "state": "Illinois", + "city": "Valle" + } + }, + { + "id": 9243, + "name": "Tanisha Duke", + "gender": "female", + "age": 26, + "address": { + "state": "Maine", + "city": "Hiko" + } + }, + { + "id": 9244, + "name": "Stacey Mccarty", + "gender": "female", + "age": 62, + "address": { + "state": "Iowa", + "city": "Enoree" + } + }, + { + "id": 9245, + "name": "Beatriz Mcgee", + "gender": "female", + "age": 81, + "address": { + "state": "North Dakota", + "city": "Norfolk" + } + }, + { + "id": 9246, + "name": "Mack Vang", + "gender": "male", + "age": 36, + "address": { + "state": "California", + "city": "Urie" + } + }, + { + "id": 9247, + "name": "Quinn Delacruz", + "gender": "male", + "age": 31, + "address": { + "state": "Oklahoma", + "city": "Zarephath" + } + }, + { + "id": 9248, + "name": "Hillary Berger", + "gender": "female", + "age": 23, + "address": { + "state": "Vermont", + "city": "Naomi" + } + }, + { + "id": 9249, + "name": "Patel Gaines", + "gender": "male", + "age": 79, + "address": { + "state": "Maryland", + "city": "Southview" + } + }, + { + "id": 9250, + "name": "Bean Burgess", + "gender": "male", + "age": 43, + "address": { + "state": "Hawaii", + "city": "Williston" + } + }, + { + "id": 9251, + "name": "Sheryl Shaw", + "gender": "female", + "age": 69, + "address": { + "state": "Tennessee", + "city": "Ronco" + } + }, + { + "id": 9252, + "name": "Penelope Mendez", + "gender": "female", + "age": 48, + "address": { + "state": "Oregon", + "city": "Hannasville" + } + }, + { + "id": 9253, + "name": "Jodi Carson", + "gender": "female", + "age": 65, + "address": { + "state": "Michigan", + "city": "Lund" + } + }, + { + "id": 9254, + "name": "Justice Bean", + "gender": "male", + "age": 30, + "address": { + "state": "Minnesota", + "city": "Hayden" + } + }, + { + "id": 9255, + "name": "Lily Chavez", + "gender": "female", + "age": 52, + "address": { + "state": "Idaho", + "city": "Lutsen" + } + }, + { + "id": 9256, + "name": "Greene Witt", + "gender": "male", + "age": 27, + "address": { + "state": "Washington", + "city": "Fedora" + } + }, + { + "id": 9257, + "name": "Teresa Frank", + "gender": "female", + "age": 63, + "address": { + "state": "Missouri", + "city": "Clay" + } + }, + { + "id": 9258, + "name": "Lelia Weber", + "gender": "female", + "age": 77, + "address": { + "state": "Kentucky", + "city": "Colton" + } + }, + { + "id": 9259, + "name": "Mara Norton", + "gender": "female", + "age": 76, + "address": { + "state": "Ohio", + "city": "Waterview" + } + }, + { + "id": 9260, + "name": "Shields Bowen", + "gender": "male", + "age": 66, + "address": { + "state": "Virginia", + "city": "Martell" + } + }, + { + "id": 9261, + "name": "Gracie Rivers", + "gender": "female", + "age": 77, + "address": { + "state": "Oklahoma", + "city": "Faywood" + } + }, + { + "id": 9262, + "name": "Geneva Baker", + "gender": "female", + "age": 68, + "address": { + "state": "Colorado", + "city": "Wacissa" + } + }, + { + "id": 9263, + "name": "Gayle Berry", + "gender": "female", + "age": 41, + "address": { + "state": "California", + "city": "Blue" + } + }, + { + "id": 9264, + "name": "Josie Hull", + "gender": "female", + "age": 70, + "address": { + "state": "Illinois", + "city": "Gallina" + } + }, + { + "id": 9265, + "name": "Briana Stark", + "gender": "female", + "age": 60, + "address": { + "state": "Minnesota", + "city": "Cornucopia" + } + }, + { + "id": 9266, + "name": "Baxter Cunningham", + "gender": "male", + "age": 41, + "address": { + "state": "Kentucky", + "city": "Hasty" + } + }, + { + "id": 9267, + "name": "Eloise Malone", + "gender": "female", + "age": 47, + "address": { + "state": "Ohio", + "city": "Weeksville" + } + }, + { + "id": 9268, + "name": "Loraine Foley", + "gender": "female", + "age": 24, + "address": { + "state": "Louisiana", + "city": "Manitou" + } + }, + { + "id": 9269, + "name": "Cheryl Noble", + "gender": "female", + "age": 44, + "address": { + "state": "Montana", + "city": "Graniteville" + } + }, + { + "id": 9270, + "name": "Jones Pratt", + "gender": "male", + "age": 59, + "address": { + "state": "South Carolina", + "city": "Maury" + } + }, + { + "id": 9271, + "name": "Nanette Montgomery", + "gender": "female", + "age": 66, + "address": { + "state": "Missouri", + "city": "Shepardsville" + } + }, + { + "id": 9272, + "name": "Leann Holmes", + "gender": "female", + "age": 64, + "address": { + "state": "North Dakota", + "city": "Sedley" + } + }, + { + "id": 9273, + "name": "Craft Calhoun", + "gender": "male", + "age": 74, + "address": { + "state": "Vermont", + "city": "Roderfield" + } + }, + { + "id": 9274, + "name": "Randi Trevino", + "gender": "female", + "age": 58, + "address": { + "state": "New York", + "city": "Greenock" + } + }, + { + "id": 9275, + "name": "Teri Norris", + "gender": "female", + "age": 17, + "address": { + "state": "Indiana", + "city": "Jennings" + } + }, + { + "id": 9276, + "name": "Cherry Hodge", + "gender": "female", + "age": 68, + "address": { + "state": "Hawaii", + "city": "Urbana" + } + }, + { + "id": 9277, + "name": "Schwartz Warner", + "gender": "male", + "age": 36, + "address": { + "state": "Rhode Island", + "city": "Templeton" + } + }, + { + "id": 9278, + "name": "Terrell Stein", + "gender": "male", + "age": 40, + "address": { + "state": "Georgia", + "city": "Fillmore" + } + }, + { + "id": 9279, + "name": "Rena Whitehead", + "gender": "female", + "age": 65, + "address": { + "state": "West Virginia", + "city": "Moquino" + } + }, + { + "id": 9280, + "name": "Bell Mathews", + "gender": "male", + "age": 67, + "address": { + "state": "Massachusetts", + "city": "Cresaptown" + } + }, + { + "id": 9281, + "name": "Logan Burns", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Salix" + } + }, + { + "id": 9282, + "name": "Hensley Reilly", + "gender": "male", + "age": 50, + "address": { + "state": "Washington", + "city": "Oneida" + } + }, + { + "id": 9283, + "name": "Mindy Conley", + "gender": "female", + "age": 40, + "address": { + "state": "Virginia", + "city": "Stagecoach" + } + }, + { + "id": 9284, + "name": "Annette Burgess", + "gender": "female", + "age": 26, + "address": { + "state": "Maryland", + "city": "Hatteras" + } + }, + { + "id": 9285, + "name": "Wallace Cobb", + "gender": "male", + "age": 61, + "address": { + "state": "Arizona", + "city": "Emerald" + } + }, + { + "id": 9286, + "name": "Hallie Franks", + "gender": "female", + "age": 47, + "address": { + "state": "Florida", + "city": "Olney" + } + }, + { + "id": 9287, + "name": "Lisa Boyd", + "gender": "female", + "age": 59, + "address": { + "state": "Michigan", + "city": "Cliff" + } + }, + { + "id": 9288, + "name": "Stephens Cleveland", + "gender": "male", + "age": 46, + "address": { + "state": "Nevada", + "city": "Moscow" + } + }, + { + "id": 9289, + "name": "Elisa Mcintosh", + "gender": "female", + "age": 59, + "address": { + "state": "New Hampshire", + "city": "Wescosville" + } + }, + { + "id": 9290, + "name": "Vega Bowers", + "gender": "male", + "age": 46, + "address": { + "state": "Arkansas", + "city": "Sylvanite" + } + }, + { + "id": 9291, + "name": "Mcmahon Huber", + "gender": "male", + "age": 39, + "address": { + "state": "Oregon", + "city": "Wanamie" + } + }, + { + "id": 9292, + "name": "Pam Hubbard", + "gender": "female", + "age": 43, + "address": { + "state": "New Jersey", + "city": "Sabillasville" + } + }, + { + "id": 9293, + "name": "Earline Sutton", + "gender": "female", + "age": 59, + "address": { + "state": "Nebraska", + "city": "Nanafalia" + } + }, + { + "id": 9294, + "name": "Steele Torres", + "gender": "male", + "age": 76, + "address": { + "state": "Maine", + "city": "Hackneyville" + } + }, + { + "id": 9295, + "name": "Kemp Huffman", + "gender": "male", + "age": 29, + "address": { + "state": "Kansas", + "city": "Kula" + } + }, + { + "id": 9296, + "name": "Sampson Casey", + "gender": "male", + "age": 63, + "address": { + "state": "Texas", + "city": "Cazadero" + } + }, + { + "id": 9297, + "name": "Dawn Blake", + "gender": "female", + "age": 45, + "address": { + "state": "South Dakota", + "city": "Babb" + } + }, + { + "id": 9298, + "name": "Bush Flynn", + "gender": "male", + "age": 47, + "address": { + "state": "Wisconsin", + "city": "Germanton" + } + }, + { + "id": 9299, + "name": "Byrd Collins", + "gender": "male", + "age": 81, + "address": { + "state": "Connecticut", + "city": "Herlong" + } + }, + { + "id": 9300, + "name": "Shannon Drake", + "gender": "male", + "age": 28, + "address": { + "state": "Wyoming", + "city": "Frystown" + } + }, + { + "id": 9301, + "name": "Wilkinson Hester", + "gender": "male", + "age": 34, + "address": { + "state": "North Carolina", + "city": "Dunbar" + } + }, + { + "id": 9302, + "name": "Webb Reid", + "gender": "male", + "age": 23, + "address": { + "state": "Mississippi", + "city": "Bowmansville" + } + }, + { + "id": 9303, + "name": "Stafford Nixon", + "gender": "male", + "age": 71, + "address": { + "state": "Pennsylvania", + "city": "Villarreal" + } + }, + { + "id": 9304, + "name": "Janet Heath", + "gender": "female", + "age": 36, + "address": { + "state": "Tennessee", + "city": "Advance" + } + }, + { + "id": 9305, + "name": "Petersen Oneil", + "gender": "male", + "age": 62, + "address": { + "state": "Delaware", + "city": "Colton" + } + }, + { + "id": 9306, + "name": "Kennedy Leblanc", + "gender": "male", + "age": 24, + "address": { + "state": "New Mexico", + "city": "Mooresburg" + } + }, + { + "id": 9307, + "name": "Earlene Sloan", + "gender": "female", + "age": 74, + "address": { + "state": "Utah", + "city": "Ola" + } + }, + { + "id": 9308, + "name": "Sharron Flowers", + "gender": "female", + "age": 51, + "address": { + "state": "Iowa", + "city": "Whipholt" + } + }, + { + "id": 9309, + "name": "Bonita Hines", + "gender": "female", + "age": 59, + "address": { + "state": "Alaska", + "city": "Navarre" + } + }, + { + "id": 9310, + "name": "Noemi Young", + "gender": "female", + "age": 69, + "address": { + "state": "New Jersey", + "city": "Masthope" + } + }, + { + "id": 9311, + "name": "Karla Carson", + "gender": "female", + "age": 34, + "address": { + "state": "South Carolina", + "city": "Edgewater" + } + }, + { + "id": 9312, + "name": "Huff Bush", + "gender": "male", + "age": 75, + "address": { + "state": "Nebraska", + "city": "Elliott" + } + }, + { + "id": 9313, + "name": "Vivian Faulkner", + "gender": "female", + "age": 37, + "address": { + "state": "North Dakota", + "city": "Waterford" + } + }, + { + "id": 9314, + "name": "Cobb Booker", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Laurelton" + } + }, + { + "id": 9315, + "name": "Bond Evans", + "gender": "male", + "age": 21, + "address": { + "state": "Kansas", + "city": "Crawfordsville" + } + }, + { + "id": 9316, + "name": "Anderson Mcdowell", + "gender": "male", + "age": 54, + "address": { + "state": "Texas", + "city": "Kylertown" + } + }, + { + "id": 9317, + "name": "Deanna Bass", + "gender": "female", + "age": 32, + "address": { + "state": "Illinois", + "city": "Bladensburg" + } + }, + { + "id": 9318, + "name": "Lindsay Carpenter", + "gender": "female", + "age": 61, + "address": { + "state": "Kentucky", + "city": "Albrightsville" + } + }, + { + "id": 9319, + "name": "Pace Vargas", + "gender": "male", + "age": 61, + "address": { + "state": "Iowa", + "city": "Chumuckla" + } + }, + { + "id": 9320, + "name": "Browning Hill", + "gender": "male", + "age": 23, + "address": { + "state": "Florida", + "city": "Utting" + } + }, + { + "id": 9321, + "name": "Russo Armstrong", + "gender": "male", + "age": 30, + "address": { + "state": "Washington", + "city": "Alamo" + } + }, + { + "id": 9322, + "name": "Taylor Haney", + "gender": "male", + "age": 66, + "address": { + "state": "California", + "city": "Neahkahnie" + } + }, + { + "id": 9323, + "name": "Kristina Slater", + "gender": "female", + "age": 63, + "address": { + "state": "Mississippi", + "city": "Riegelwood" + } + }, + { + "id": 9324, + "name": "Ann Vaughan", + "gender": "female", + "age": 28, + "address": { + "state": "Arkansas", + "city": "Fairlee" + } + }, + { + "id": 9325, + "name": "Maryanne Dudley", + "gender": "female", + "age": 35, + "address": { + "state": "Virginia", + "city": "Statenville" + } + }, + { + "id": 9326, + "name": "Sykes Rose", + "gender": "male", + "age": 46, + "address": { + "state": "Indiana", + "city": "Cataract" + } + }, + { + "id": 9327, + "name": "Madelyn Sykes", + "gender": "female", + "age": 44, + "address": { + "state": "Utah", + "city": "Hampstead" + } + }, + { + "id": 9328, + "name": "Kane Bailey", + "gender": "male", + "age": 46, + "address": { + "state": "South Dakota", + "city": "Temperanceville" + } + }, + { + "id": 9329, + "name": "Sharlene Miles", + "gender": "female", + "age": 79, + "address": { + "state": "Nevada", + "city": "Concho" + } + }, + { + "id": 9330, + "name": "Serrano Beck", + "gender": "male", + "age": 76, + "address": { + "state": "Tennessee", + "city": "Walton" + } + }, + { + "id": 9331, + "name": "Leonor Branch", + "gender": "female", + "age": 62, + "address": { + "state": "Minnesota", + "city": "Sanders" + } + }, + { + "id": 9332, + "name": "Alejandra Mckinney", + "gender": "female", + "age": 37, + "address": { + "state": "Massachusetts", + "city": "Goldfield" + } + }, + { + "id": 9333, + "name": "Wheeler Barry", + "gender": "male", + "age": 66, + "address": { + "state": "Georgia", + "city": "Hobucken" + } + }, + { + "id": 9334, + "name": "Henry Martin", + "gender": "male", + "age": 44, + "address": { + "state": "Arizona", + "city": "Galesville" + } + }, + { + "id": 9335, + "name": "Lindsey Copeland", + "gender": "male", + "age": 76, + "address": { + "state": "Rhode Island", + "city": "Lowell" + } + }, + { + "id": 9336, + "name": "Kinney Dotson", + "gender": "male", + "age": 52, + "address": { + "state": "Vermont", + "city": "Brazos" + } + }, + { + "id": 9337, + "name": "Cassie Cole", + "gender": "female", + "age": 48, + "address": { + "state": "Montana", + "city": "Cavalero" + } + }, + { + "id": 9338, + "name": "Travis Bruce", + "gender": "male", + "age": 35, + "address": { + "state": "Louisiana", + "city": "Gilmore" + } + }, + { + "id": 9339, + "name": "Mcdowell Lane", + "gender": "male", + "age": 45, + "address": { + "state": "Hawaii", + "city": "Deltaville" + } + }, + { + "id": 9340, + "name": "Garza Guerrero", + "gender": "male", + "age": 30, + "address": { + "state": "Alabama", + "city": "Orason" + } + }, + { + "id": 9341, + "name": "Hubbard Beasley", + "gender": "male", + "age": 58, + "address": { + "state": "Wisconsin", + "city": "Enlow" + } + }, + { + "id": 9342, + "name": "Cecilia Lowe", + "gender": "female", + "age": 59, + "address": { + "state": "Maryland", + "city": "Stevens" + } + }, + { + "id": 9343, + "name": "Malinda Thomas", + "gender": "female", + "age": 60, + "address": { + "state": "Ohio", + "city": "Floris" + } + }, + { + "id": 9344, + "name": "Best Hoffman", + "gender": "male", + "age": 21, + "address": { + "state": "Pennsylvania", + "city": "Leeper" + } + }, + { + "id": 9345, + "name": "Pennington Whitaker", + "gender": "male", + "age": 62, + "address": { + "state": "New Hampshire", + "city": "Ypsilanti" + } + }, + { + "id": 9346, + "name": "Castro Glass", + "gender": "male", + "age": 55, + "address": { + "state": "Missouri", + "city": "Bartonsville" + } + }, + { + "id": 9347, + "name": "Maura Stanley", + "gender": "female", + "age": 57, + "address": { + "state": "Colorado", + "city": "Orviston" + } + }, + { + "id": 9348, + "name": "Hattie Williamson", + "gender": "female", + "age": 40, + "address": { + "state": "New York", + "city": "Leming" + } + }, + { + "id": 9349, + "name": "Jodi Cooley", + "gender": "female", + "age": 62, + "address": { + "state": "Idaho", + "city": "Rote" + } + }, + { + "id": 9350, + "name": "Ana Calderon", + "gender": "female", + "age": 74, + "address": { + "state": "Connecticut", + "city": "Coventry" + } + }, + { + "id": 9351, + "name": "Jerry Burnett", + "gender": "female", + "age": 31, + "address": { + "state": "Wyoming", + "city": "Clay" + } + }, + { + "id": 9352, + "name": "Charles Perkins", + "gender": "male", + "age": 57, + "address": { + "state": "Oklahoma", + "city": "Brownsville" + } + }, + { + "id": 9353, + "name": "Lillian Klein", + "gender": "female", + "age": 74, + "address": { + "state": "New Mexico", + "city": "Rose" + } + }, + { + "id": 9354, + "name": "Jennings Palmer", + "gender": "male", + "age": 57, + "address": { + "state": "Delaware", + "city": "Savage" + } + }, + { + "id": 9355, + "name": "Sullivan Sweeney", + "gender": "male", + "age": 17, + "address": { + "state": "Michigan", + "city": "Fairforest" + } + }, + { + "id": 9356, + "name": "Matilda Higgins", + "gender": "female", + "age": 78, + "address": { + "state": "Oregon", + "city": "Sabillasville" + } + }, + { + "id": 9357, + "name": "Adeline Bender", + "gender": "female", + "age": 60, + "address": { + "state": "Maine", + "city": "Dargan" + } + }, + { + "id": 9358, + "name": "Catherine Chandler", + "gender": "female", + "age": 60, + "address": { + "state": "Alaska", + "city": "Durham" + } + }, + { + "id": 9359, + "name": "Yvonne Shannon", + "gender": "female", + "age": 53, + "address": { + "state": "Minnesota", + "city": "Enoree" + } + }, + { + "id": 9360, + "name": "Frieda Schneider", + "gender": "female", + "age": 36, + "address": { + "state": "South Dakota", + "city": "Ahwahnee" + } + }, + { + "id": 9361, + "name": "Miriam Swanson", + "gender": "female", + "age": 66, + "address": { + "state": "Wyoming", + "city": "Callaghan" + } + }, + { + "id": 9362, + "name": "Carmela Maddox", + "gender": "female", + "age": 74, + "address": { + "state": "North Dakota", + "city": "Leroy" + } + }, + { + "id": 9363, + "name": "Sharon Adkins", + "gender": "female", + "age": 28, + "address": { + "state": "Pennsylvania", + "city": "Naomi" + } + }, + { + "id": 9364, + "name": "Kelly Bird", + "gender": "female", + "age": 49, + "address": { + "state": "Kentucky", + "city": "Southview" + } + }, + { + "id": 9365, + "name": "Vonda Aguilar", + "gender": "female", + "age": 65, + "address": { + "state": "Utah", + "city": "Wyoming" + } + }, + { + "id": 9366, + "name": "Minnie Booth", + "gender": "female", + "age": 38, + "address": { + "state": "Georgia", + "city": "Monument" + } + }, + { + "id": 9367, + "name": "Ola Haley", + "gender": "female", + "age": 57, + "address": { + "state": "South Carolina", + "city": "Mapletown" + } + }, + { + "id": 9368, + "name": "Dorothea Estes", + "gender": "female", + "age": 33, + "address": { + "state": "Connecticut", + "city": "Coinjock" + } + }, + { + "id": 9369, + "name": "Luna Horn", + "gender": "male", + "age": 51, + "address": { + "state": "Hawaii", + "city": "Cresaptown" + } + }, + { + "id": 9370, + "name": "Fannie Gaines", + "gender": "female", + "age": 30, + "address": { + "state": "Iowa", + "city": "Statenville" + } + }, + { + "id": 9371, + "name": "Luz Jimenez", + "gender": "female", + "age": 34, + "address": { + "state": "Nevada", + "city": "Idledale" + } + }, + { + "id": 9372, + "name": "Eunice Bolton", + "gender": "female", + "age": 78, + "address": { + "state": "Arkansas", + "city": "Crisman" + } + }, + { + "id": 9373, + "name": "Rhea Mcintosh", + "gender": "female", + "age": 59, + "address": { + "state": "Oregon", + "city": "Mappsville" + } + }, + { + "id": 9374, + "name": "Jeannine Clark", + "gender": "female", + "age": 77, + "address": { + "state": "Texas", + "city": "Yettem" + } + }, + { + "id": 9375, + "name": "Johanna Grant", + "gender": "female", + "age": 75, + "address": { + "state": "Kansas", + "city": "Edgewater" + } + }, + { + "id": 9376, + "name": "Esperanza Mcgee", + "gender": "female", + "age": 39, + "address": { + "state": "West Virginia", + "city": "Wescosville" + } + }, + { + "id": 9377, + "name": "Maryellen Mcdowell", + "gender": "female", + "age": 32, + "address": { + "state": "Alaska", + "city": "Inkerman" + } + }, + { + "id": 9378, + "name": "Hicks Harper", + "gender": "male", + "age": 71, + "address": { + "state": "Colorado", + "city": "Fulford" + } + }, + { + "id": 9379, + "name": "Stephens Wiggins", + "gender": "male", + "age": 45, + "address": { + "state": "Virginia", + "city": "Gila" + } + }, + { + "id": 9380, + "name": "Karina Calderon", + "gender": "female", + "age": 43, + "address": { + "state": "Alabama", + "city": "Welda" + } + }, + { + "id": 9381, + "name": "Helene Bryant", + "gender": "female", + "age": 31, + "address": { + "state": "Montana", + "city": "Blanco" + } + }, + { + "id": 9382, + "name": "Lori Mckenzie", + "gender": "female", + "age": 76, + "address": { + "state": "Arizona", + "city": "Terlingua" + } + }, + { + "id": 9383, + "name": "Alford Flores", + "gender": "male", + "age": 74, + "address": { + "state": "Ohio", + "city": "Hiwasse" + } + }, + { + "id": 9384, + "name": "Geraldine Beard", + "gender": "female", + "age": 32, + "address": { + "state": "Michigan", + "city": "Nogal" + } + }, + { + "id": 9385, + "name": "Jacobson Lowery", + "gender": "male", + "age": 67, + "address": { + "state": "Delaware", + "city": "Crucible" + } + }, + { + "id": 9386, + "name": "Mindy Moses", + "gender": "female", + "age": 26, + "address": { + "state": "Louisiana", + "city": "Hinsdale" + } + }, + { + "id": 9387, + "name": "Weaver Cooke", + "gender": "male", + "age": 49, + "address": { + "state": "Rhode Island", + "city": "Bordelonville" + } + }, + { + "id": 9388, + "name": "Johnnie Brooks", + "gender": "female", + "age": 46, + "address": { + "state": "Maine", + "city": "Brandermill" + } + }, + { + "id": 9389, + "name": "John Ball", + "gender": "female", + "age": 66, + "address": { + "state": "Florida", + "city": "Cotopaxi" + } + }, + { + "id": 9390, + "name": "Ruiz Kaufman", + "gender": "male", + "age": 78, + "address": { + "state": "Idaho", + "city": "Drytown" + } + }, + { + "id": 9391, + "name": "Daphne Zimmerman", + "gender": "female", + "age": 40, + "address": { + "state": "New Hampshire", + "city": "Osmond" + } + }, + { + "id": 9392, + "name": "Decker Keller", + "gender": "male", + "age": 39, + "address": { + "state": "Vermont", + "city": "Hachita" + } + }, + { + "id": 9393, + "name": "Strong Hyde", + "gender": "male", + "age": 73, + "address": { + "state": "New Mexico", + "city": "Sunbury" + } + }, + { + "id": 9394, + "name": "Munoz Bonner", + "gender": "male", + "age": 65, + "address": { + "state": "Indiana", + "city": "Dodge" + } + }, + { + "id": 9395, + "name": "Tanya Chavez", + "gender": "female", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Adamstown" + } + }, + { + "id": 9396, + "name": "Shelton Holcomb", + "gender": "male", + "age": 32, + "address": { + "state": "Missouri", + "city": "Caroline" + } + }, + { + "id": 9397, + "name": "Mccray Pugh", + "gender": "male", + "age": 65, + "address": { + "state": "Oklahoma", + "city": "Sabillasville" + } + }, + { + "id": 9398, + "name": "Chavez Noel", + "gender": "male", + "age": 22, + "address": { + "state": "Mississippi", + "city": "Chamizal" + } + }, + { + "id": 9399, + "name": "Stuart Beck", + "gender": "male", + "age": 70, + "address": { + "state": "Illinois", + "city": "Cazadero" + } + }, + { + "id": 9400, + "name": "Wanda Benjamin", + "gender": "female", + "age": 81, + "address": { + "state": "Washington", + "city": "Onton" + } + }, + { + "id": 9401, + "name": "Valerie Castillo", + "gender": "female", + "age": 29, + "address": { + "state": "New York", + "city": "Camino" + } + }, + { + "id": 9402, + "name": "Jo Davenport", + "gender": "female", + "age": 22, + "address": { + "state": "Wisconsin", + "city": "Bluetown" + } + }, + { + "id": 9403, + "name": "Audra Haney", + "gender": "female", + "age": 45, + "address": { + "state": "North Carolina", + "city": "Roderfield" + } + }, + { + "id": 9404, + "name": "Mack Yates", + "gender": "male", + "age": 66, + "address": { + "state": "New Jersey", + "city": "Condon" + } + }, + { + "id": 9405, + "name": "Bernice Sharpe", + "gender": "female", + "age": 61, + "address": { + "state": "California", + "city": "Needmore" + } + }, + { + "id": 9406, + "name": "Pansy Owen", + "gender": "female", + "age": 63, + "address": { + "state": "Tennessee", + "city": "Newkirk" + } + }, + { + "id": 9407, + "name": "Bush Carr", + "gender": "male", + "age": 36, + "address": { + "state": "Massachusetts", + "city": "Emison" + } + }, + { + "id": 9408, + "name": "Lesa Hinton", + "gender": "female", + "age": 78, + "address": { + "state": "Massachusetts", + "city": "Wildwood" + } + }, + { + "id": 9409, + "name": "Schultz Flowers", + "gender": "male", + "age": 37, + "address": { + "state": "Louisiana", + "city": "Coldiron" + } + }, + { + "id": 9410, + "name": "Ann Matthews", + "gender": "female", + "age": 78, + "address": { + "state": "Michigan", + "city": "Homestead" + } + }, + { + "id": 9411, + "name": "Maribel Bates", + "gender": "female", + "age": 80, + "address": { + "state": "Connecticut", + "city": "Imperial" + } + }, + { + "id": 9412, + "name": "Martina Kelley", + "gender": "female", + "age": 68, + "address": { + "state": "Delaware", + "city": "Omar" + } + }, + { + "id": 9413, + "name": "Collier Wilkerson", + "gender": "male", + "age": 73, + "address": { + "state": "Wyoming", + "city": "Fingerville" + } + }, + { + "id": 9414, + "name": "Debora Wheeler", + "gender": "female", + "age": 22, + "address": { + "state": "Indiana", + "city": "Toftrees" + } + }, + { + "id": 9415, + "name": "Leona Harper", + "gender": "female", + "age": 43, + "address": { + "state": "Virginia", + "city": "Kieler" + } + }, + { + "id": 9416, + "name": "Stacie Humphrey", + "gender": "female", + "age": 77, + "address": { + "state": "Oklahoma", + "city": "Campo" + } + }, + { + "id": 9417, + "name": "Odessa Leblanc", + "gender": "female", + "age": 33, + "address": { + "state": "Alabama", + "city": "Welda" + } + }, + { + "id": 9418, + "name": "Randi Green", + "gender": "female", + "age": 53, + "address": { + "state": "Colorado", + "city": "Freetown" + } + }, + { + "id": 9419, + "name": "Terry Hurst", + "gender": "male", + "age": 23, + "address": { + "state": "Oregon", + "city": "Beaulieu" + } + }, + { + "id": 9420, + "name": "Mercado Bowman", + "gender": "male", + "age": 76, + "address": { + "state": "Ohio", + "city": "Gulf" + } + }, + { + "id": 9421, + "name": "Gayle Lara", + "gender": "female", + "age": 32, + "address": { + "state": "Iowa", + "city": "Condon" + } + }, + { + "id": 9422, + "name": "Mckenzie Whitaker", + "gender": "male", + "age": 61, + "address": { + "state": "Mississippi", + "city": "Vallonia" + } + }, + { + "id": 9423, + "name": "Shirley Mcleod", + "gender": "female", + "age": 77, + "address": { + "state": "South Dakota", + "city": "Trona" + } + }, + { + "id": 9424, + "name": "Mueller Carney", + "gender": "male", + "age": 80, + "address": { + "state": "California", + "city": "Bascom" + } + }, + { + "id": 9425, + "name": "Baldwin Bernard", + "gender": "male", + "age": 24, + "address": { + "state": "Rhode Island", + "city": "Davenport" + } + }, + { + "id": 9426, + "name": "Townsend Mullins", + "gender": "male", + "age": 47, + "address": { + "state": "Vermont", + "city": "Savannah" + } + }, + { + "id": 9427, + "name": "Marquez Watson", + "gender": "male", + "age": 80, + "address": { + "state": "Tennessee", + "city": "Grahamtown" + } + }, + { + "id": 9428, + "name": "Fry Vaughn", + "gender": "male", + "age": 65, + "address": { + "state": "New York", + "city": "Albany" + } + }, + { + "id": 9429, + "name": "York Dale", + "gender": "male", + "age": 49, + "address": { + "state": "Arkansas", + "city": "Torboy" + } + }, + { + "id": 9430, + "name": "Kathrine Lindsay", + "gender": "female", + "age": 53, + "address": { + "state": "New Hampshire", + "city": "Sparkill" + } + }, + { + "id": 9431, + "name": "Susana Mccall", + "gender": "female", + "age": 72, + "address": { + "state": "New Jersey", + "city": "Johnsonburg" + } + }, + { + "id": 9432, + "name": "Carly Harmon", + "gender": "female", + "age": 35, + "address": { + "state": "Idaho", + "city": "Walton" + } + }, + { + "id": 9433, + "name": "Miriam Pena", + "gender": "female", + "age": 80, + "address": { + "state": "Missouri", + "city": "Clarktown" + } + }, + { + "id": 9434, + "name": "Burt Curry", + "gender": "male", + "age": 68, + "address": { + "state": "Maine", + "city": "Alafaya" + } + }, + { + "id": 9435, + "name": "Liza Hinton", + "gender": "female", + "age": 42, + "address": { + "state": "Maryland", + "city": "Dorneyville" + } + }, + { + "id": 9436, + "name": "Suarez Hicks", + "gender": "male", + "age": 37, + "address": { + "state": "Illinois", + "city": "Osage" + } + }, + { + "id": 9437, + "name": "Nadia Frye", + "gender": "female", + "age": 75, + "address": { + "state": "Kentucky", + "city": "Herlong" + } + }, + { + "id": 9438, + "name": "Marquita Medina", + "gender": "female", + "age": 20, + "address": { + "state": "Wisconsin", + "city": "Geyserville" + } + }, + { + "id": 9439, + "name": "Miranda Bennett", + "gender": "male", + "age": 72, + "address": { + "state": "South Carolina", + "city": "Enoree" + } + }, + { + "id": 9440, + "name": "Luna Valentine", + "gender": "male", + "age": 20, + "address": { + "state": "Nebraska", + "city": "Caron" + } + }, + { + "id": 9441, + "name": "Eunice Larsen", + "gender": "female", + "age": 48, + "address": { + "state": "New Mexico", + "city": "Bentonville" + } + }, + { + "id": 9442, + "name": "Cash Barr", + "gender": "male", + "age": 24, + "address": { + "state": "Pennsylvania", + "city": "Tilden" + } + }, + { + "id": 9443, + "name": "Delaney Padilla", + "gender": "male", + "age": 71, + "address": { + "state": "Arizona", + "city": "Ivanhoe" + } + }, + { + "id": 9444, + "name": "Minerva Melton", + "gender": "female", + "age": 68, + "address": { + "state": "North Carolina", + "city": "Helen" + } + }, + { + "id": 9445, + "name": "Barbara Tran", + "gender": "female", + "age": 58, + "address": { + "state": "Texas", + "city": "Takilma" + } + }, + { + "id": 9446, + "name": "Ollie Clark", + "gender": "female", + "age": 74, + "address": { + "state": "Alaska", + "city": "Dola" + } + }, + { + "id": 9447, + "name": "Burns Hyde", + "gender": "male", + "age": 61, + "address": { + "state": "Kansas", + "city": "Hessville" + } + }, + { + "id": 9448, + "name": "Wheeler Delacruz", + "gender": "male", + "age": 59, + "address": { + "state": "Georgia", + "city": "Stonybrook" + } + }, + { + "id": 9449, + "name": "Barrett Reyes", + "gender": "male", + "age": 66, + "address": { + "state": "North Dakota", + "city": "Forbestown" + } + }, + { + "id": 9450, + "name": "Ginger Hudson", + "gender": "female", + "age": 58, + "address": { + "state": "Hawaii", + "city": "Hackneyville" + } + }, + { + "id": 9451, + "name": "Benton Byrd", + "gender": "male", + "age": 80, + "address": { + "state": "Montana", + "city": "Garfield" + } + }, + { + "id": 9452, + "name": "Guerrero Cole", + "gender": "male", + "age": 77, + "address": { + "state": "Utah", + "city": "Canoochee" + } + }, + { + "id": 9453, + "name": "Pennington Benjamin", + "gender": "male", + "age": 39, + "address": { + "state": "Florida", + "city": "Summerfield" + } + }, + { + "id": 9454, + "name": "Sabrina Parker", + "gender": "female", + "age": 29, + "address": { + "state": "Nevada", + "city": "Datil" + } + }, + { + "id": 9455, + "name": "Raquel Zimmerman", + "gender": "female", + "age": 19, + "address": { + "state": "Washington", + "city": "Aguila" + } + }, + { + "id": 9456, + "name": "Pearl Larson", + "gender": "female", + "age": 61, + "address": { + "state": "Minnesota", + "city": "Linwood" + } + }, + { + "id": 9457, + "name": "Gonzales Shaw", + "gender": "male", + "age": 47, + "address": { + "state": "Maine", + "city": "Sehili" + } + }, + { + "id": 9458, + "name": "Garcia Luna", + "gender": "male", + "age": 57, + "address": { + "state": "Oklahoma", + "city": "Noxen" + } + }, + { + "id": 9459, + "name": "Fowler Sellers", + "gender": "male", + "age": 26, + "address": { + "state": "Arizona", + "city": "Riner" + } + }, + { + "id": 9460, + "name": "Heidi Moody", + "gender": "female", + "age": 18, + "address": { + "state": "Alabama", + "city": "Hannasville" + } + }, + { + "id": 9461, + "name": "Chandler Hill", + "gender": "male", + "age": 60, + "address": { + "state": "Missouri", + "city": "Vincent" + } + }, + { + "id": 9462, + "name": "Brock Brewer", + "gender": "male", + "age": 36, + "address": { + "state": "Arkansas", + "city": "Adelino" + } + }, + { + "id": 9463, + "name": "Abigail Barrera", + "gender": "female", + "age": 42, + "address": { + "state": "Vermont", + "city": "Sultana" + } + }, + { + "id": 9464, + "name": "Leta Macdonald", + "gender": "female", + "age": 27, + "address": { + "state": "Tennessee", + "city": "Lookingglass" + } + }, + { + "id": 9465, + "name": "Rich Sherman", + "gender": "male", + "age": 25, + "address": { + "state": "North Dakota", + "city": "Winchester" + } + }, + { + "id": 9466, + "name": "Barrett Snyder", + "gender": "male", + "age": 77, + "address": { + "state": "Georgia", + "city": "Eggertsville" + } + }, + { + "id": 9467, + "name": "Ivy Kemp", + "gender": "female", + "age": 82, + "address": { + "state": "Illinois", + "city": "Windsor" + } + }, + { + "id": 9468, + "name": "Christensen Padilla", + "gender": "male", + "age": 76, + "address": { + "state": "Wisconsin", + "city": "Murillo" + } + }, + { + "id": 9469, + "name": "Cline Landry", + "gender": "male", + "age": 50, + "address": { + "state": "South Carolina", + "city": "Shasta" + } + }, + { + "id": 9470, + "name": "Flynn Lambert", + "gender": "male", + "age": 41, + "address": { + "state": "Virginia", + "city": "Celeryville" + } + }, + { + "id": 9471, + "name": "Hawkins Roth", + "gender": "male", + "age": 17, + "address": { + "state": "Idaho", + "city": "Brownsville" + } + }, + { + "id": 9472, + "name": "Allison Watts", + "gender": "male", + "age": 28, + "address": { + "state": "Nebraska", + "city": "Harmon" + } + }, + { + "id": 9473, + "name": "Bobbie Phillips", + "gender": "female", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Sanford" + } + }, + { + "id": 9474, + "name": "Tracy Horton", + "gender": "female", + "age": 22, + "address": { + "state": "Wyoming", + "city": "Calverton" + } + }, + { + "id": 9475, + "name": "Jacobs Heath", + "gender": "male", + "age": 20, + "address": { + "state": "Ohio", + "city": "Norwood" + } + }, + { + "id": 9476, + "name": "Tami Kirkland", + "gender": "female", + "age": 43, + "address": { + "state": "California", + "city": "Cobbtown" + } + }, + { + "id": 9477, + "name": "Kirkland Clark", + "gender": "male", + "age": 40, + "address": { + "state": "New Hampshire", + "city": "Morningside" + } + }, + { + "id": 9478, + "name": "Suarez Hale", + "gender": "male", + "age": 70, + "address": { + "state": "Montana", + "city": "Nile" + } + }, + { + "id": 9479, + "name": "Britt Cantu", + "gender": "male", + "age": 57, + "address": { + "state": "Iowa", + "city": "Chesapeake" + } + }, + { + "id": 9480, + "name": "York Dyer", + "gender": "male", + "age": 71, + "address": { + "state": "Louisiana", + "city": "Thermal" + } + }, + { + "id": 9481, + "name": "Rosalinda Joseph", + "gender": "female", + "age": 33, + "address": { + "state": "Pennsylvania", + "city": "Tyhee" + } + }, + { + "id": 9482, + "name": "Kelsey Bradshaw", + "gender": "female", + "age": 81, + "address": { + "state": "Hawaii", + "city": "Loomis" + } + }, + { + "id": 9483, + "name": "Sanford Mccormick", + "gender": "male", + "age": 25, + "address": { + "state": "Mississippi", + "city": "Konterra" + } + }, + { + "id": 9484, + "name": "Letitia Ramsey", + "gender": "female", + "age": 28, + "address": { + "state": "Washington", + "city": "Templeton" + } + }, + { + "id": 9485, + "name": "Nikki Moses", + "gender": "female", + "age": 36, + "address": { + "state": "Texas", + "city": "Levant" + } + }, + { + "id": 9486, + "name": "Martin Mclaughlin", + "gender": "male", + "age": 59, + "address": { + "state": "Utah", + "city": "Caron" + } + }, + { + "id": 9487, + "name": "Walsh Garner", + "gender": "male", + "age": 41, + "address": { + "state": "South Dakota", + "city": "Hillsboro" + } + }, + { + "id": 9488, + "name": "Deanne Todd", + "gender": "female", + "age": 25, + "address": { + "state": "Oregon", + "city": "Dunbar" + } + }, + { + "id": 9489, + "name": "Stephenson Hays", + "gender": "male", + "age": 45, + "address": { + "state": "Delaware", + "city": "Taft" + } + }, + { + "id": 9490, + "name": "Bradshaw Guthrie", + "gender": "male", + "age": 51, + "address": { + "state": "North Carolina", + "city": "Galesville" + } + }, + { + "id": 9491, + "name": "Roman Cervantes", + "gender": "male", + "age": 24, + "address": { + "state": "Florida", + "city": "Warren" + } + }, + { + "id": 9492, + "name": "Wilkerson Burt", + "gender": "male", + "age": 73, + "address": { + "state": "New Jersey", + "city": "Elfrida" + } + }, + { + "id": 9493, + "name": "Horn King", + "gender": "male", + "age": 31, + "address": { + "state": "Kentucky", + "city": "Bowmansville" + } + }, + { + "id": 9494, + "name": "Koch Knight", + "gender": "male", + "age": 74, + "address": { + "state": "Michigan", + "city": "Aurora" + } + }, + { + "id": 9495, + "name": "Espinoza Hendricks", + "gender": "male", + "age": 52, + "address": { + "state": "Connecticut", + "city": "Trail" + } + }, + { + "id": 9496, + "name": "Trudy Walker", + "gender": "female", + "age": 31, + "address": { + "state": "Indiana", + "city": "Marbury" + } + }, + { + "id": 9497, + "name": "Terrie Coffey", + "gender": "female", + "age": 36, + "address": { + "state": "Maryland", + "city": "Succasunna" + } + }, + { + "id": 9498, + "name": "Erin Wright", + "gender": "female", + "age": 59, + "address": { + "state": "Colorado", + "city": "Cataract" + } + }, + { + "id": 9499, + "name": "Russell Solis", + "gender": "male", + "age": 76, + "address": { + "state": "Alaska", + "city": "Longbranch" + } + }, + { + "id": 9500, + "name": "Roach Gordon", + "gender": "male", + "age": 65, + "address": { + "state": "Minnesota", + "city": "Onton" + } + }, + { + "id": 9501, + "name": "Lola Daniel", + "gender": "female", + "age": 37, + "address": { + "state": "Massachusetts", + "city": "Lumberton" + } + }, + { + "id": 9502, + "name": "Laurel Camacho", + "gender": "female", + "age": 41, + "address": { + "state": "New York", + "city": "Helen" + } + }, + { + "id": 9503, + "name": "Lamb Rasmussen", + "gender": "male", + "age": 72, + "address": { + "state": "West Virginia", + "city": "Vaughn" + } + }, + { + "id": 9504, + "name": "Nanette Hodges", + "gender": "female", + "age": 72, + "address": { + "state": "Kansas", + "city": "Orovada" + } + }, + { + "id": 9505, + "name": "Porter Rutledge", + "gender": "male", + "age": 24, + "address": { + "state": "Nevada", + "city": "Bynum" + } + }, + { + "id": 9506, + "name": "Ollie Gates", + "gender": "female", + "age": 34, + "address": { + "state": "Wyoming", + "city": "Draper" + } + }, + { + "id": 9507, + "name": "Burton Wilkerson", + "gender": "male", + "age": 35, + "address": { + "state": "North Carolina", + "city": "Fidelis" + } + }, + { + "id": 9508, + "name": "Bailey Zamora", + "gender": "male", + "age": 72, + "address": { + "state": "Missouri", + "city": "Gallina" + } + }, + { + "id": 9509, + "name": "Banks Lane", + "gender": "male", + "age": 73, + "address": { + "state": "New York", + "city": "Moscow" + } + }, + { + "id": 9510, + "name": "Burch Morris", + "gender": "male", + "age": 37, + "address": { + "state": "Maine", + "city": "Lydia" + } + }, + { + "id": 9511, + "name": "Pamela Dudley", + "gender": "female", + "age": 72, + "address": { + "state": "Florida", + "city": "Eggertsville" + } + }, + { + "id": 9512, + "name": "Tricia Underwood", + "gender": "female", + "age": 69, + "address": { + "state": "Indiana", + "city": "Finderne" + } + }, + { + "id": 9513, + "name": "Lora Cervantes", + "gender": "female", + "age": 52, + "address": { + "state": "Utah", + "city": "Sunnyside" + } + }, + { + "id": 9514, + "name": "Smith Lloyd", + "gender": "male", + "age": 39, + "address": { + "state": "Nebraska", + "city": "Hamilton" + } + }, + { + "id": 9515, + "name": "Harrison Bruce", + "gender": "male", + "age": 42, + "address": { + "state": "Pennsylvania", + "city": "Kula" + } + }, + { + "id": 9516, + "name": "Lawanda Flowers", + "gender": "female", + "age": 34, + "address": { + "state": "Oregon", + "city": "Century" + } + }, + { + "id": 9517, + "name": "Tran Berger", + "gender": "male", + "age": 38, + "address": { + "state": "Tennessee", + "city": "Rosewood" + } + }, + { + "id": 9518, + "name": "Howard Lang", + "gender": "male", + "age": 72, + "address": { + "state": "South Carolina", + "city": "Rivera" + } + }, + { + "id": 9519, + "name": "Mejia Turner", + "gender": "male", + "age": 45, + "address": { + "state": "Alabama", + "city": "Holtville" + } + }, + { + "id": 9520, + "name": "Kirkland Strickland", + "gender": "male", + "age": 42, + "address": { + "state": "Michigan", + "city": "Curtice" + } + }, + { + "id": 9521, + "name": "Lindsey Gregory", + "gender": "female", + "age": 25, + "address": { + "state": "South Dakota", + "city": "Duryea" + } + }, + { + "id": 9522, + "name": "Gertrude Dominguez", + "gender": "female", + "age": 41, + "address": { + "state": "Idaho", + "city": "Elizaville" + } + }, + { + "id": 9523, + "name": "Stacie Vance", + "gender": "female", + "age": 38, + "address": { + "state": "Wisconsin", + "city": "Efland" + } + }, + { + "id": 9524, + "name": "Cecilia Clayton", + "gender": "female", + "age": 74, + "address": { + "state": "Maryland", + "city": "Dundee" + } + }, + { + "id": 9525, + "name": "Shelley Sexton", + "gender": "female", + "age": 29, + "address": { + "state": "New Jersey", + "city": "Nord" + } + }, + { + "id": 9526, + "name": "Wood Graves", + "gender": "male", + "age": 48, + "address": { + "state": "Delaware", + "city": "Rushford" + } + }, + { + "id": 9527, + "name": "Rochelle Livingston", + "gender": "female", + "age": 68, + "address": { + "state": "Mississippi", + "city": "Bethpage" + } + }, + { + "id": 9528, + "name": "Tonya Kline", + "gender": "female", + "age": 67, + "address": { + "state": "Texas", + "city": "Albany" + } + }, + { + "id": 9529, + "name": "Allie Randall", + "gender": "female", + "age": 50, + "address": { + "state": "Kansas", + "city": "Muir" + } + }, + { + "id": 9530, + "name": "Skinner Blackburn", + "gender": "male", + "age": 41, + "address": { + "state": "Vermont", + "city": "Mappsville" + } + }, + { + "id": 9531, + "name": "Henry Farrell", + "gender": "male", + "age": 36, + "address": { + "state": "Rhode Island", + "city": "Coyote" + } + }, + { + "id": 9532, + "name": "Adriana Morse", + "gender": "female", + "age": 56, + "address": { + "state": "Alaska", + "city": "Kenmar" + } + }, + { + "id": 9533, + "name": "Evelyn Hart", + "gender": "female", + "age": 60, + "address": { + "state": "Montana", + "city": "Longoria" + } + }, + { + "id": 9534, + "name": "Meghan Reeves", + "gender": "female", + "age": 74, + "address": { + "state": "Illinois", + "city": "Cleary" + } + }, + { + "id": 9535, + "name": "Rene Wilder", + "gender": "female", + "age": 75, + "address": { + "state": "New Hampshire", + "city": "Bowmansville" + } + }, + { + "id": 9536, + "name": "Meredith Santiago", + "gender": "female", + "age": 21, + "address": { + "state": "Georgia", + "city": "Zeba" + } + }, + { + "id": 9537, + "name": "Angelita Porter", + "gender": "female", + "age": 70, + "address": { + "state": "Massachusetts", + "city": "Homeworth" + } + }, + { + "id": 9538, + "name": "Patsy Rocha", + "gender": "female", + "age": 64, + "address": { + "state": "Ohio", + "city": "Riviera" + } + }, + { + "id": 9539, + "name": "Parrish Pruitt", + "gender": "male", + "age": 30, + "address": { + "state": "Washington", + "city": "Manitou" + } + }, + { + "id": 9540, + "name": "Lowe Tillman", + "gender": "male", + "age": 60, + "address": { + "state": "California", + "city": "Thynedale" + } + }, + { + "id": 9541, + "name": "Freda Bowen", + "gender": "female", + "age": 60, + "address": { + "state": "Iowa", + "city": "Robinette" + } + }, + { + "id": 9542, + "name": "Louise Hall", + "gender": "female", + "age": 42, + "address": { + "state": "Nevada", + "city": "Genoa" + } + }, + { + "id": 9543, + "name": "Lott Woods", + "gender": "male", + "age": 76, + "address": { + "state": "Connecticut", + "city": "Gambrills" + } + }, + { + "id": 9544, + "name": "Nanette Hughes", + "gender": "female", + "age": 79, + "address": { + "state": "Arizona", + "city": "Riceville" + } + }, + { + "id": 9545, + "name": "Huber Hunter", + "gender": "male", + "age": 27, + "address": { + "state": "Virginia", + "city": "Basye" + } + }, + { + "id": 9546, + "name": "Bette Mills", + "gender": "female", + "age": 32, + "address": { + "state": "Kentucky", + "city": "Cobbtown" + } + }, + { + "id": 9547, + "name": "Marie Melton", + "gender": "female", + "age": 31, + "address": { + "state": "North Dakota", + "city": "Nelson" + } + }, + { + "id": 9548, + "name": "Goodman Cannon", + "gender": "male", + "age": 77, + "address": { + "state": "Minnesota", + "city": "Westmoreland" + } + }, + { + "id": 9549, + "name": "Velazquez Neal", + "gender": "male", + "age": 70, + "address": { + "state": "Oklahoma", + "city": "Shaft" + } + }, + { + "id": 9550, + "name": "Reynolds Wilcox", + "gender": "male", + "age": 71, + "address": { + "state": "New Mexico", + "city": "Omar" + } + }, + { + "id": 9551, + "name": "Robbie Shelton", + "gender": "female", + "age": 50, + "address": { + "state": "Arkansas", + "city": "Hollins" + } + }, + { + "id": 9552, + "name": "Shelly Mcbride", + "gender": "female", + "age": 40, + "address": { + "state": "Colorado", + "city": "Boomer" + } + }, + { + "id": 9553, + "name": "Salas Ross", + "gender": "male", + "age": 47, + "address": { + "state": "West Virginia", + "city": "Chamberino" + } + }, + { + "id": 9554, + "name": "Acosta Gibson", + "gender": "male", + "age": 60, + "address": { + "state": "Hawaii", + "city": "Lindcove" + } + }, + { + "id": 9555, + "name": "April Conley", + "gender": "female", + "age": 76, + "address": { + "state": "Iowa", + "city": "Lowell" + } + }, + { + "id": 9556, + "name": "Santana Good", + "gender": "male", + "age": 19, + "address": { + "state": "Indiana", + "city": "Darlington" + } + }, + { + "id": 9557, + "name": "Rivera Tillman", + "gender": "male", + "age": 59, + "address": { + "state": "Alabama", + "city": "Knowlton" + } + }, + { + "id": 9558, + "name": "Amanda Holden", + "gender": "female", + "age": 21, + "address": { + "state": "South Carolina", + "city": "Brecon" + } + }, + { + "id": 9559, + "name": "Velez Snyder", + "gender": "male", + "age": 70, + "address": { + "state": "Missouri", + "city": "Elrama" + } + }, + { + "id": 9560, + "name": "Stuart Goodwin", + "gender": "male", + "age": 52, + "address": { + "state": "Idaho", + "city": "Kaka" + } + }, + { + "id": 9561, + "name": "Smith Gilmore", + "gender": "male", + "age": 46, + "address": { + "state": "Virginia", + "city": "Greenock" + } + }, + { + "id": 9562, + "name": "Jimmie Gentry", + "gender": "female", + "age": 19, + "address": { + "state": "Wisconsin", + "city": "Curtice" + } + }, + { + "id": 9563, + "name": "Phelps Holland", + "gender": "male", + "age": 17, + "address": { + "state": "Texas", + "city": "Florence" + } + }, + { + "id": 9564, + "name": "Bonnie Tate", + "gender": "female", + "age": 21, + "address": { + "state": "Pennsylvania", + "city": "Wyano" + } + }, + { + "id": 9565, + "name": "Tillman Mercer", + "gender": "male", + "age": 44, + "address": { + "state": "Louisiana", + "city": "Concho" + } + }, + { + "id": 9566, + "name": "Helga Charles", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Wakarusa" + } + }, + { + "id": 9567, + "name": "Mendoza Gay", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Foxworth" + } + }, + { + "id": 9568, + "name": "Lenora Cantrell", + "gender": "female", + "age": 78, + "address": { + "state": "Minnesota", + "city": "Coventry" + } + }, + { + "id": 9569, + "name": "Williams Richard", + "gender": "male", + "age": 75, + "address": { + "state": "Florida", + "city": "Cliffside" + } + }, + { + "id": 9570, + "name": "Houston Poole", + "gender": "male", + "age": 30, + "address": { + "state": "New York", + "city": "Norfolk" + } + }, + { + "id": 9571, + "name": "Lara Ford", + "gender": "female", + "age": 34, + "address": { + "state": "West Virginia", + "city": "Eagletown" + } + }, + { + "id": 9572, + "name": "Byers Travis", + "gender": "male", + "age": 65, + "address": { + "state": "Colorado", + "city": "Woodruff" + } + }, + { + "id": 9573, + "name": "Lynette Waller", + "gender": "female", + "age": 27, + "address": { + "state": "Maine", + "city": "Downsville" + } + }, + { + "id": 9574, + "name": "Lyons Hawkins", + "gender": "male", + "age": 73, + "address": { + "state": "Kansas", + "city": "Blanford" + } + }, + { + "id": 9575, + "name": "Alma Brennan", + "gender": "female", + "age": 76, + "address": { + "state": "Rhode Island", + "city": "Bluffview" + } + }, + { + "id": 9576, + "name": "Johnnie Bruce", + "gender": "female", + "age": 69, + "address": { + "state": "Georgia", + "city": "Thermal" + } + }, + { + "id": 9577, + "name": "Jenifer Santana", + "gender": "female", + "age": 36, + "address": { + "state": "New Jersey", + "city": "Greenbackville" + } + }, + { + "id": 9578, + "name": "Terry Wilkerson", + "gender": "male", + "age": 51, + "address": { + "state": "Vermont", + "city": "Fruitdale" + } + }, + { + "id": 9579, + "name": "Cummings Sawyer", + "gender": "male", + "age": 72, + "address": { + "state": "Montana", + "city": "Nescatunga" + } + }, + { + "id": 9580, + "name": "Dolores Huber", + "gender": "female", + "age": 55, + "address": { + "state": "Nebraska", + "city": "Kilbourne" + } + }, + { + "id": 9581, + "name": "Douglas Roberts", + "gender": "male", + "age": 30, + "address": { + "state": "Mississippi", + "city": "Somerset" + } + }, + { + "id": 9582, + "name": "Flowers Pickett", + "gender": "male", + "age": 63, + "address": { + "state": "Washington", + "city": "Conway" + } + }, + { + "id": 9583, + "name": "Miranda Bass", + "gender": "female", + "age": 48, + "address": { + "state": "Utah", + "city": "Neahkahnie" + } + }, + { + "id": 9584, + "name": "Hallie Hubbard", + "gender": "female", + "age": 57, + "address": { + "state": "Tennessee", + "city": "Garberville" + } + }, + { + "id": 9585, + "name": "Katrina Hogan", + "gender": "female", + "age": 82, + "address": { + "state": "Illinois", + "city": "Fontanelle" + } + }, + { + "id": 9586, + "name": "Durham Scott", + "gender": "male", + "age": 63, + "address": { + "state": "California", + "city": "Lemoyne" + } + }, + { + "id": 9587, + "name": "Adele Santiago", + "gender": "female", + "age": 63, + "address": { + "state": "Connecticut", + "city": "Avalon" + } + }, + { + "id": 9588, + "name": "Francisca French", + "gender": "female", + "age": 24, + "address": { + "state": "Oregon", + "city": "Magnolia" + } + }, + { + "id": 9589, + "name": "Ofelia Stark", + "gender": "female", + "age": 40, + "address": { + "state": "North Carolina", + "city": "Chestnut" + } + }, + { + "id": 9590, + "name": "Sonja Palmer", + "gender": "female", + "age": 19, + "address": { + "state": "New Mexico", + "city": "Glidden" + } + }, + { + "id": 9591, + "name": "Heath Barry", + "gender": "male", + "age": 79, + "address": { + "state": "Hawaii", + "city": "Coinjock" + } + }, + { + "id": 9592, + "name": "Hendricks Obrien", + "gender": "male", + "age": 75, + "address": { + "state": "South Dakota", + "city": "Driftwood" + } + }, + { + "id": 9593, + "name": "Sanchez Terry", + "gender": "male", + "age": 33, + "address": { + "state": "Delaware", + "city": "Harrison" + } + }, + { + "id": 9594, + "name": "Nora Norris", + "gender": "female", + "age": 70, + "address": { + "state": "Michigan", + "city": "Stockwell" + } + }, + { + "id": 9595, + "name": "Henson Richards", + "gender": "male", + "age": 41, + "address": { + "state": "Maryland", + "city": "Newry" + } + }, + { + "id": 9596, + "name": "Claudine Pena", + "gender": "female", + "age": 79, + "address": { + "state": "North Dakota", + "city": "Weogufka" + } + }, + { + "id": 9597, + "name": "Holman Acevedo", + "gender": "male", + "age": 18, + "address": { + "state": "Ohio", + "city": "Nicholson" + } + }, + { + "id": 9598, + "name": "Earline Espinoza", + "gender": "female", + "age": 19, + "address": { + "state": "Arkansas", + "city": "Efland" + } + }, + { + "id": 9599, + "name": "Whitney Mcneil", + "gender": "female", + "age": 37, + "address": { + "state": "Kentucky", + "city": "Lacomb" + } + }, + { + "id": 9600, + "name": "Meredith Chapman", + "gender": "female", + "age": 24, + "address": { + "state": "Nevada", + "city": "Sandston" + } + }, + { + "id": 9601, + "name": "Amparo Stone", + "gender": "female", + "age": 28, + "address": { + "state": "Arizona", + "city": "Loveland" + } + }, + { + "id": 9602, + "name": "Sally Gaines", + "gender": "female", + "age": 72, + "address": { + "state": "Alaska", + "city": "Ticonderoga" + } + }, + { + "id": 9603, + "name": "Ward Jefferson", + "gender": "male", + "age": 79, + "address": { + "state": "Wyoming", + "city": "Axis" + } + }, + { + "id": 9604, + "name": "Hodges Gross", + "gender": "male", + "age": 20, + "address": { + "state": "South Carolina", + "city": "Genoa" + } + }, + { + "id": 9605, + "name": "Francine Levine", + "gender": "female", + "age": 24, + "address": { + "state": "Hawaii", + "city": "Spelter" + } + }, + { + "id": 9606, + "name": "Finch Levy", + "gender": "male", + "age": 64, + "address": { + "state": "Missouri", + "city": "Homeworth" + } + }, + { + "id": 9607, + "name": "Kristi Good", + "gender": "female", + "age": 59, + "address": { + "state": "Illinois", + "city": "Inkerman" + } + }, + { + "id": 9608, + "name": "Brady Schroeder", + "gender": "male", + "age": 52, + "address": { + "state": "Indiana", + "city": "Gracey" + } + }, + { + "id": 9609, + "name": "Jodie Gilmore", + "gender": "female", + "age": 74, + "address": { + "state": "Rhode Island", + "city": "Kingstowne" + } + }, + { + "id": 9610, + "name": "Cortez Perez", + "gender": "male", + "age": 63, + "address": { + "state": "Vermont", + "city": "Tuttle" + } + }, + { + "id": 9611, + "name": "Nancy Cooper", + "gender": "female", + "age": 59, + "address": { + "state": "Georgia", + "city": "Sanders" + } + }, + { + "id": 9612, + "name": "Eve Hill", + "gender": "female", + "age": 78, + "address": { + "state": "Alaska", + "city": "Kieler" + } + }, + { + "id": 9613, + "name": "Bernice Dickson", + "gender": "female", + "age": 61, + "address": { + "state": "Tennessee", + "city": "Sattley" + } + }, + { + "id": 9614, + "name": "Collins Gallagher", + "gender": "male", + "age": 31, + "address": { + "state": "Washington", + "city": "Kipp" + } + }, + { + "id": 9615, + "name": "Velasquez Horne", + "gender": "male", + "age": 60, + "address": { + "state": "North Dakota", + "city": "Nelson" + } + }, + { + "id": 9616, + "name": "Downs Jarvis", + "gender": "male", + "age": 38, + "address": { + "state": "Minnesota", + "city": "Charco" + } + }, + { + "id": 9617, + "name": "Ernestine Vincent", + "gender": "female", + "age": 54, + "address": { + "state": "Colorado", + "city": "Hollins" + } + }, + { + "id": 9618, + "name": "Bertha Dillon", + "gender": "female", + "age": 30, + "address": { + "state": "Oklahoma", + "city": "Rote" + } + }, + { + "id": 9619, + "name": "Debbie Reynolds", + "gender": "female", + "age": 59, + "address": { + "state": "Texas", + "city": "Ripley" + } + }, + { + "id": 9620, + "name": "Deann Serrano", + "gender": "female", + "age": 60, + "address": { + "state": "Arkansas", + "city": "Irwin" + } + }, + { + "id": 9621, + "name": "Elizabeth Jimenez", + "gender": "female", + "age": 75, + "address": { + "state": "Idaho", + "city": "Davenport" + } + }, + { + "id": 9622, + "name": "Owen Hull", + "gender": "male", + "age": 48, + "address": { + "state": "Massachusetts", + "city": "Calvary" + } + }, + { + "id": 9623, + "name": "Heidi Powell", + "gender": "female", + "age": 68, + "address": { + "state": "West Virginia", + "city": "Moraida" + } + }, + { + "id": 9624, + "name": "Curtis Rosa", + "gender": "male", + "age": 22, + "address": { + "state": "Kentucky", + "city": "Wakulla" + } + }, + { + "id": 9625, + "name": "Booker Byers", + "gender": "male", + "age": 41, + "address": { + "state": "Mississippi", + "city": "Lorraine" + } + }, + { + "id": 9626, + "name": "Odom Ball", + "gender": "male", + "age": 67, + "address": { + "state": "Virginia", + "city": "Malo" + } + }, + { + "id": 9627, + "name": "Manning Hart", + "gender": "male", + "age": 46, + "address": { + "state": "Pennsylvania", + "city": "Brogan" + } + }, + { + "id": 9628, + "name": "Simmons Blankenship", + "gender": "male", + "age": 60, + "address": { + "state": "Montana", + "city": "Baker" + } + }, + { + "id": 9629, + "name": "Mattie Cherry", + "gender": "female", + "age": 61, + "address": { + "state": "Ohio", + "city": "Loveland" + } + }, + { + "id": 9630, + "name": "Gwen Walton", + "gender": "female", + "age": 75, + "address": { + "state": "Delaware", + "city": "Goochland" + } + }, + { + "id": 9631, + "name": "Bradshaw Phillips", + "gender": "male", + "age": 77, + "address": { + "state": "Kansas", + "city": "Conway" + } + }, + { + "id": 9632, + "name": "Mcmillan Kemp", + "gender": "male", + "age": 62, + "address": { + "state": "New Jersey", + "city": "Deltaville" + } + }, + { + "id": 9633, + "name": "House Knox", + "gender": "male", + "age": 28, + "address": { + "state": "Maine", + "city": "Cresaptown" + } + }, + { + "id": 9634, + "name": "Leola Taylor", + "gender": "female", + "age": 68, + "address": { + "state": "Iowa", + "city": "Sunwest" + } + }, + { + "id": 9635, + "name": "Miranda Brooks", + "gender": "male", + "age": 45, + "address": { + "state": "Nevada", + "city": "Alleghenyville" + } + }, + { + "id": 9636, + "name": "Kaitlin Gilliam", + "gender": "female", + "age": 68, + "address": { + "state": "California", + "city": "Curtice" + } + }, + { + "id": 9637, + "name": "Nannie Allen", + "gender": "female", + "age": 31, + "address": { + "state": "Utah", + "city": "Websterville" + } + }, + { + "id": 9638, + "name": "Calhoun Robertson", + "gender": "male", + "age": 53, + "address": { + "state": "Michigan", + "city": "Trexlertown" + } + }, + { + "id": 9639, + "name": "Benjamin Lawson", + "gender": "male", + "age": 81, + "address": { + "state": "Oregon", + "city": "Caron" + } + }, + { + "id": 9640, + "name": "Bartlett Hooper", + "gender": "male", + "age": 62, + "address": { + "state": "Alabama", + "city": "Woodlands" + } + }, + { + "id": 9641, + "name": "Muriel Buck", + "gender": "female", + "age": 70, + "address": { + "state": "Wisconsin", + "city": "Gloucester" + } + }, + { + "id": 9642, + "name": "Jan Frederick", + "gender": "female", + "age": 44, + "address": { + "state": "Connecticut", + "city": "Hardyville" + } + }, + { + "id": 9643, + "name": "Paula Mckenzie", + "gender": "female", + "age": 41, + "address": { + "state": "New York", + "city": "Eastmont" + } + }, + { + "id": 9644, + "name": "Thelma Alvarez", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Finderne" + } + }, + { + "id": 9645, + "name": "Lina Burke", + "gender": "female", + "age": 17, + "address": { + "state": "Arizona", + "city": "Tryon" + } + }, + { + "id": 9646, + "name": "Staci Price", + "gender": "female", + "age": 52, + "address": { + "state": "Wyoming", + "city": "Brenton" + } + }, + { + "id": 9647, + "name": "Fletcher Gallegos", + "gender": "male", + "age": 24, + "address": { + "state": "New Mexico", + "city": "Rutherford" + } + }, + { + "id": 9648, + "name": "Frederick Blair", + "gender": "male", + "age": 26, + "address": { + "state": "Nebraska", + "city": "Cobbtown" + } + }, + { + "id": 9649, + "name": "Jones Mcdaniel", + "gender": "male", + "age": 45, + "address": { + "state": "North Carolina", + "city": "Norfolk" + } + }, + { + "id": 9650, + "name": "Leona Fields", + "gender": "female", + "age": 64, + "address": { + "state": "Maryland", + "city": "Corinne" + } + }, + { + "id": 9651, + "name": "Dixie Wilson", + "gender": "female", + "age": 71, + "address": { + "state": "Louisiana", + "city": "Snelling" + } + }, + { + "id": 9652, + "name": "Angelica Olsen", + "gender": "female", + "age": 58, + "address": { + "state": "South Dakota", + "city": "Fillmore" + } + }, + { + "id": 9653, + "name": "Harmon Little", + "gender": "male", + "age": 76, + "address": { + "state": "Minnesota", + "city": "Neahkahnie" + } + }, + { + "id": 9654, + "name": "Waller Huber", + "gender": "male", + "age": 54, + "address": { + "state": "Texas", + "city": "Dellview" + } + }, + { + "id": 9655, + "name": "Chambers Jones", + "gender": "male", + "age": 18, + "address": { + "state": "Michigan", + "city": "Swartzville" + } + }, + { + "id": 9656, + "name": "Olga Wooten", + "gender": "female", + "age": 54, + "address": { + "state": "Mississippi", + "city": "Choctaw" + } + }, + { + "id": 9657, + "name": "Sherry Romero", + "gender": "female", + "age": 52, + "address": { + "state": "Rhode Island", + "city": "Coyote" + } + }, + { + "id": 9658, + "name": "Tonia Tate", + "gender": "female", + "age": 78, + "address": { + "state": "Ohio", + "city": "Dorneyville" + } + }, + { + "id": 9659, + "name": "Donna Talley", + "gender": "female", + "age": 51, + "address": { + "state": "West Virginia", + "city": "Springdale" + } + }, + { + "id": 9660, + "name": "Cecilia Hoover", + "gender": "female", + "age": 59, + "address": { + "state": "Washington", + "city": "Allendale" + } + }, + { + "id": 9661, + "name": "Kris Parrish", + "gender": "female", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Shindler" + } + }, + { + "id": 9662, + "name": "Leola Richmond", + "gender": "female", + "age": 34, + "address": { + "state": "Hawaii", + "city": "Williams" + } + }, + { + "id": 9663, + "name": "Guadalupe Meyers", + "gender": "female", + "age": 20, + "address": { + "state": "South Dakota", + "city": "Murillo" + } + }, + { + "id": 9664, + "name": "Freida Roy", + "gender": "female", + "age": 48, + "address": { + "state": "Georgia", + "city": "Rivera" + } + }, + { + "id": 9665, + "name": "Trina Miranda", + "gender": "female", + "age": 71, + "address": { + "state": "South Carolina", + "city": "Ferney" + } + }, + { + "id": 9666, + "name": "Francis Noble", + "gender": "male", + "age": 20, + "address": { + "state": "Indiana", + "city": "Rehrersburg" + } + }, + { + "id": 9667, + "name": "Cantu Moody", + "gender": "male", + "age": 79, + "address": { + "state": "California", + "city": "Longoria" + } + }, + { + "id": 9668, + "name": "Dickson Fitzgerald", + "gender": "male", + "age": 47, + "address": { + "state": "New Hampshire", + "city": "Trona" + } + }, + { + "id": 9669, + "name": "Fuentes Farmer", + "gender": "male", + "age": 80, + "address": { + "state": "Louisiana", + "city": "Caberfae" + } + }, + { + "id": 9670, + "name": "Ida Campos", + "gender": "female", + "age": 30, + "address": { + "state": "New York", + "city": "Rossmore" + } + }, + { + "id": 9671, + "name": "Carol Perez", + "gender": "female", + "age": 37, + "address": { + "state": "Maryland", + "city": "Cutter" + } + }, + { + "id": 9672, + "name": "Hampton Lowe", + "gender": "male", + "age": 47, + "address": { + "state": "Alabama", + "city": "Garnet" + } + }, + { + "id": 9673, + "name": "Simpson Collier", + "gender": "male", + "age": 33, + "address": { + "state": "Montana", + "city": "Graniteville" + } + }, + { + "id": 9674, + "name": "Shaffer Rosales", + "gender": "male", + "age": 44, + "address": { + "state": "Virginia", + "city": "Blodgett" + } + }, + { + "id": 9675, + "name": "Rocha Sawyer", + "gender": "male", + "age": 75, + "address": { + "state": "Connecticut", + "city": "Fidelis" + } + }, + { + "id": 9676, + "name": "Patti Jensen", + "gender": "female", + "age": 74, + "address": { + "state": "North Carolina", + "city": "Sena" + } + }, + { + "id": 9677, + "name": "Yvonne Gibbs", + "gender": "female", + "age": 76, + "address": { + "state": "Nevada", + "city": "Curtice" + } + }, + { + "id": 9678, + "name": "Weeks Moore", + "gender": "male", + "age": 43, + "address": { + "state": "Iowa", + "city": "Glenshaw" + } + }, + { + "id": 9679, + "name": "Consuelo Horn", + "gender": "female", + "age": 64, + "address": { + "state": "Wyoming", + "city": "Staples" + } + }, + { + "id": 9680, + "name": "Aguilar Spence", + "gender": "male", + "age": 53, + "address": { + "state": "Arkansas", + "city": "Kempton" + } + }, + { + "id": 9681, + "name": "Suzanne Montoya", + "gender": "female", + "age": 54, + "address": { + "state": "Alaska", + "city": "Thatcher" + } + }, + { + "id": 9682, + "name": "Yates Santana", + "gender": "male", + "age": 56, + "address": { + "state": "Utah", + "city": "Boykin" + } + }, + { + "id": 9683, + "name": "Stanley Sosa", + "gender": "male", + "age": 28, + "address": { + "state": "Idaho", + "city": "Nile" + } + }, + { + "id": 9684, + "name": "Georgina Maldonado", + "gender": "female", + "age": 38, + "address": { + "state": "Kansas", + "city": "Helen" + } + }, + { + "id": 9685, + "name": "Vera Aguilar", + "gender": "female", + "age": 32, + "address": { + "state": "Florida", + "city": "Harborton" + } + }, + { + "id": 9686, + "name": "Elvia Matthews", + "gender": "female", + "age": 22, + "address": { + "state": "Missouri", + "city": "Hemlock" + } + }, + { + "id": 9687, + "name": "Angie Schmidt", + "gender": "female", + "age": 80, + "address": { + "state": "Delaware", + "city": "Byrnedale" + } + }, + { + "id": 9688, + "name": "Clara Haney", + "gender": "female", + "age": 22, + "address": { + "state": "Arizona", + "city": "Cochranville" + } + }, + { + "id": 9689, + "name": "Kristie Gregory", + "gender": "female", + "age": 53, + "address": { + "state": "North Dakota", + "city": "Marenisco" + } + }, + { + "id": 9690, + "name": "Lupe Stout", + "gender": "female", + "age": 26, + "address": { + "state": "Vermont", + "city": "Centerville" + } + }, + { + "id": 9691, + "name": "Maria Sharpe", + "gender": "female", + "age": 61, + "address": { + "state": "New Mexico", + "city": "Dexter" + } + }, + { + "id": 9692, + "name": "Peck Rosa", + "gender": "male", + "age": 55, + "address": { + "state": "Pennsylvania", + "city": "Suitland" + } + }, + { + "id": 9693, + "name": "Ingram Miller", + "gender": "male", + "age": 67, + "address": { + "state": "Tennessee", + "city": "Herald" + } + }, + { + "id": 9694, + "name": "Wolf West", + "gender": "male", + "age": 28, + "address": { + "state": "Maine", + "city": "Mulino" + } + }, + { + "id": 9695, + "name": "Brennan Garner", + "gender": "male", + "age": 54, + "address": { + "state": "Massachusetts", + "city": "Singer" + } + }, + { + "id": 9696, + "name": "Kelsey Anthony", + "gender": "female", + "age": 78, + "address": { + "state": "Oregon", + "city": "Clinton" + } + }, + { + "id": 9697, + "name": "Rose Macdonald", + "gender": "female", + "age": 81, + "address": { + "state": "Kentucky", + "city": "Dubois" + } + }, + { + "id": 9698, + "name": "Ruiz Kramer", + "gender": "male", + "age": 40, + "address": { + "state": "Illinois", + "city": "Holtville" + } + }, + { + "id": 9699, + "name": "Bridges Battle", + "gender": "male", + "age": 62, + "address": { + "state": "Colorado", + "city": "Englevale" + } + }, + { + "id": 9700, + "name": "Ellen Schneider", + "gender": "female", + "age": 76, + "address": { + "state": "Nebraska", + "city": "Wescosville" + } + }, + { + "id": 9701, + "name": "Sue Sanders", + "gender": "female", + "age": 48, + "address": { + "state": "Oklahoma", + "city": "Bison" + } + }, + { + "id": 9702, + "name": "Decker Savage", + "gender": "male", + "age": 58, + "address": { + "state": "Missouri", + "city": "Longoria" + } + }, + { + "id": 9703, + "name": "Dixon Avery", + "gender": "male", + "age": 52, + "address": { + "state": "Arkansas", + "city": "Waverly" + } + }, + { + "id": 9704, + "name": "Lowe Lawson", + "gender": "male", + "age": 29, + "address": { + "state": "Texas", + "city": "Echo" + } + }, + { + "id": 9705, + "name": "Roberta Odom", + "gender": "female", + "age": 67, + "address": { + "state": "New Hampshire", + "city": "Dixonville" + } + }, + { + "id": 9706, + "name": "Marguerite Glass", + "gender": "female", + "age": 37, + "address": { + "state": "Pennsylvania", + "city": "Winston" + } + }, + { + "id": 9707, + "name": "Petersen Cooper", + "gender": "male", + "age": 17, + "address": { + "state": "Oregon", + "city": "Faxon" + } + }, + { + "id": 9708, + "name": "Scott Ryan", + "gender": "male", + "age": 19, + "address": { + "state": "Michigan", + "city": "Ronco" + } + }, + { + "id": 9709, + "name": "Odom Key", + "gender": "male", + "age": 23, + "address": { + "state": "Nevada", + "city": "Corriganville" + } + }, + { + "id": 9710, + "name": "Muriel Cruz", + "gender": "female", + "age": 33, + "address": { + "state": "Nebraska", + "city": "Kennedyville" + } + }, + { + "id": 9711, + "name": "Alberta Anthony", + "gender": "female", + "age": 74, + "address": { + "state": "Arizona", + "city": "Welch" + } + }, + { + "id": 9712, + "name": "Bridges Walter", + "gender": "male", + "age": 57, + "address": { + "state": "Indiana", + "city": "Chumuckla" + } + }, + { + "id": 9713, + "name": "Duncan Buck", + "gender": "male", + "age": 81, + "address": { + "state": "California", + "city": "Verdi" + } + }, + { + "id": 9714, + "name": "Liza Reeves", + "gender": "female", + "age": 60, + "address": { + "state": "West Virginia", + "city": "Rew" + } + }, + { + "id": 9715, + "name": "Best David", + "gender": "male", + "age": 54, + "address": { + "state": "South Carolina", + "city": "Harrison" + } + }, + { + "id": 9716, + "name": "Alma Burns", + "gender": "female", + "age": 34, + "address": { + "state": "Idaho", + "city": "Hayden" + } + }, + { + "id": 9717, + "name": "Orr Levine", + "gender": "male", + "age": 69, + "address": { + "state": "Utah", + "city": "Levant" + } + }, + { + "id": 9718, + "name": "Bowman Harrington", + "gender": "male", + "age": 18, + "address": { + "state": "Kentucky", + "city": "Hilltop" + } + }, + { + "id": 9719, + "name": "Schneider Stokes", + "gender": "male", + "age": 76, + "address": { + "state": "Montana", + "city": "Sanborn" + } + }, + { + "id": 9720, + "name": "Nona Rowe", + "gender": "female", + "age": 66, + "address": { + "state": "Colorado", + "city": "Bentonville" + } + }, + { + "id": 9721, + "name": "Obrien Jimenez", + "gender": "male", + "age": 20, + "address": { + "state": "Massachusetts", + "city": "Grenelefe" + } + }, + { + "id": 9722, + "name": "Francis Estes", + "gender": "male", + "age": 31, + "address": { + "state": "Louisiana", + "city": "Glenville" + } + }, + { + "id": 9723, + "name": "Shauna Hopper", + "gender": "female", + "age": 62, + "address": { + "state": "Vermont", + "city": "Walker" + } + }, + { + "id": 9724, + "name": "Wynn Valdez", + "gender": "male", + "age": 44, + "address": { + "state": "Mississippi", + "city": "Jamestown" + } + }, + { + "id": 9725, + "name": "Ollie Rice", + "gender": "female", + "age": 26, + "address": { + "state": "Washington", + "city": "Martinez" + } + }, + { + "id": 9726, + "name": "Sybil Valentine", + "gender": "female", + "age": 31, + "address": { + "state": "Maryland", + "city": "Florence" + } + }, + { + "id": 9727, + "name": "Kathryn Vinson", + "gender": "female", + "age": 41, + "address": { + "state": "Florida", + "city": "Lafferty" + } + }, + { + "id": 9728, + "name": "Schroeder Bates", + "gender": "male", + "age": 25, + "address": { + "state": "Wyoming", + "city": "Gilmore" + } + }, + { + "id": 9729, + "name": "Christian Brewer", + "gender": "male", + "age": 62, + "address": { + "state": "Tennessee", + "city": "Fresno" + } + }, + { + "id": 9730, + "name": "Kathleen Gallagher", + "gender": "female", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Westmoreland" + } + }, + { + "id": 9731, + "name": "Rosalind William", + "gender": "female", + "age": 42, + "address": { + "state": "Delaware", + "city": "Bakersville" + } + }, + { + "id": 9732, + "name": "Shelton Boone", + "gender": "male", + "age": 81, + "address": { + "state": "Maine", + "city": "Urbana" + } + }, + { + "id": 9733, + "name": "Latisha Guthrie", + "gender": "female", + "age": 24, + "address": { + "state": "Minnesota", + "city": "Lutsen" + } + }, + { + "id": 9734, + "name": "Garner Dudley", + "gender": "male", + "age": 41, + "address": { + "state": "South Dakota", + "city": "Henrietta" + } + }, + { + "id": 9735, + "name": "Winters Chaney", + "gender": "male", + "age": 38, + "address": { + "state": "Georgia", + "city": "Klondike" + } + }, + { + "id": 9736, + "name": "Leticia Schwartz", + "gender": "female", + "age": 69, + "address": { + "state": "Kansas", + "city": "Nanafalia" + } + }, + { + "id": 9737, + "name": "Ramona Ingram", + "gender": "female", + "age": 27, + "address": { + "state": "Ohio", + "city": "Holcombe" + } + }, + { + "id": 9738, + "name": "Jimenez Wiggins", + "gender": "male", + "age": 59, + "address": { + "state": "Rhode Island", + "city": "Brenton" + } + }, + { + "id": 9739, + "name": "Mcmillan Mcfarland", + "gender": "male", + "age": 82, + "address": { + "state": "New Jersey", + "city": "Devon" + } + }, + { + "id": 9740, + "name": "Flores Lucas", + "gender": "male", + "age": 62, + "address": { + "state": "Oklahoma", + "city": "Faywood" + } + }, + { + "id": 9741, + "name": "Smith Weaver", + "gender": "male", + "age": 67, + "address": { + "state": "Iowa", + "city": "Richville" + } + }, + { + "id": 9742, + "name": "Christian Carrillo", + "gender": "female", + "age": 24, + "address": { + "state": "North Carolina", + "city": "Diaperville" + } + }, + { + "id": 9743, + "name": "Sweeney Mooney", + "gender": "male", + "age": 54, + "address": { + "state": "Alaska", + "city": "Chesapeake" + } + }, + { + "id": 9744, + "name": "Dorsey Dixon", + "gender": "male", + "age": 18, + "address": { + "state": "Alabama", + "city": "Grantville" + } + }, + { + "id": 9745, + "name": "Gill Landry", + "gender": "male", + "age": 53, + "address": { + "state": "Connecticut", + "city": "Linganore" + } + }, + { + "id": 9746, + "name": "Annie Skinner", + "gender": "female", + "age": 61, + "address": { + "state": "New York", + "city": "Thermal" + } + }, + { + "id": 9747, + "name": "Desiree Duran", + "gender": "female", + "age": 69, + "address": { + "state": "Illinois", + "city": "Coventry" + } + }, + { + "id": 9748, + "name": "Lacey Wolfe", + "gender": "female", + "age": 71, + "address": { + "state": "North Dakota", + "city": "Conestoga" + } + }, + { + "id": 9749, + "name": "Bolton Christensen", + "gender": "male", + "age": 34, + "address": { + "state": "Wisconsin", + "city": "Libertytown" + } + }, + { + "id": 9750, + "name": "Romero Villarreal", + "gender": "male", + "age": 22, + "address": { + "state": "Virginia", + "city": "Strong" + } + }, + { + "id": 9751, + "name": "Haney Ford", + "gender": "male", + "age": 28, + "address": { + "state": "Colorado", + "city": "Nogal" + } + }, + { + "id": 9752, + "name": "Bruce Cunningham", + "gender": "male", + "age": 52, + "address": { + "state": "Montana", + "city": "Montura" + } + }, + { + "id": 9753, + "name": "Olivia Sexton", + "gender": "female", + "age": 71, + "address": { + "state": "Missouri", + "city": "Lodoga" + } + }, + { + "id": 9754, + "name": "Minerva Pittman", + "gender": "female", + "age": 60, + "address": { + "state": "Alaska", + "city": "Mathews" + } + }, + { + "id": 9755, + "name": "Lorrie Carr", + "gender": "female", + "age": 28, + "address": { + "state": "Ohio", + "city": "Witmer" + } + }, + { + "id": 9756, + "name": "Vaughan Craft", + "gender": "male", + "age": 57, + "address": { + "state": "South Carolina", + "city": "Loveland" + } + }, + { + "id": 9757, + "name": "Blevins Thompson", + "gender": "male", + "age": 28, + "address": { + "state": "Maryland", + "city": "Coldiron" + } + }, + { + "id": 9758, + "name": "Kelsey Newman", + "gender": "female", + "age": 75, + "address": { + "state": "Virginia", + "city": "Veyo" + } + }, + { + "id": 9759, + "name": "Jillian Daugherty", + "gender": "female", + "age": 44, + "address": { + "state": "Mississippi", + "city": "Crown" + } + }, + { + "id": 9760, + "name": "Young Bauer", + "gender": "female", + "age": 34, + "address": { + "state": "Louisiana", + "city": "Matthews" + } + }, + { + "id": 9761, + "name": "Martha Crane", + "gender": "female", + "age": 54, + "address": { + "state": "Connecticut", + "city": "Brethren" + } + }, + { + "id": 9762, + "name": "Huber Andrews", + "gender": "male", + "age": 32, + "address": { + "state": "Texas", + "city": "Blanford" + } + }, + { + "id": 9763, + "name": "Vazquez Walsh", + "gender": "male", + "age": 38, + "address": { + "state": "Michigan", + "city": "Jardine" + } + }, + { + "id": 9764, + "name": "Wiley Ray", + "gender": "male", + "age": 54, + "address": { + "state": "Idaho", + "city": "Farmers" + } + }, + { + "id": 9765, + "name": "Dionne Webb", + "gender": "female", + "age": 82, + "address": { + "state": "Delaware", + "city": "Brookfield" + } + }, + { + "id": 9766, + "name": "Sallie Martinez", + "gender": "female", + "age": 42, + "address": { + "state": "North Dakota", + "city": "Bedias" + } + }, + { + "id": 9767, + "name": "Underwood Mcpherson", + "gender": "male", + "age": 52, + "address": { + "state": "Florida", + "city": "Chelsea" + } + }, + { + "id": 9768, + "name": "Schneider Vance", + "gender": "male", + "age": 36, + "address": { + "state": "Iowa", + "city": "Unionville" + } + }, + { + "id": 9769, + "name": "Pickett Goff", + "gender": "male", + "age": 73, + "address": { + "state": "Maine", + "city": "Riner" + } + }, + { + "id": 9770, + "name": "Coffey Hebert", + "gender": "male", + "age": 29, + "address": { + "state": "Tennessee", + "city": "Groveville" + } + }, + { + "id": 9771, + "name": "Cherry Peters", + "gender": "male", + "age": 18, + "address": { + "state": "Minnesota", + "city": "Oasis" + } + }, + { + "id": 9772, + "name": "Marquita Kinney", + "gender": "female", + "age": 54, + "address": { + "state": "New Hampshire", + "city": "Albrightsville" + } + }, + { + "id": 9773, + "name": "Benton Strickland", + "gender": "male", + "age": 22, + "address": { + "state": "Wyoming", + "city": "Wilmington" + } + }, + { + "id": 9774, + "name": "Lourdes Mooney", + "gender": "female", + "age": 17, + "address": { + "state": "New Jersey", + "city": "Lupton" + } + }, + { + "id": 9775, + "name": "Marina Edwards", + "gender": "female", + "age": 81, + "address": { + "state": "Kansas", + "city": "Barrelville" + } + }, + { + "id": 9776, + "name": "Brennan Boone", + "gender": "male", + "age": 55, + "address": { + "state": "Illinois", + "city": "Joes" + } + }, + { + "id": 9777, + "name": "Leonard Aguirre", + "gender": "male", + "age": 21, + "address": { + "state": "South Dakota", + "city": "Wilsonia" + } + }, + { + "id": 9778, + "name": "Byrd Snow", + "gender": "male", + "age": 61, + "address": { + "state": "California", + "city": "Blende" + } + }, + { + "id": 9779, + "name": "Sawyer Norris", + "gender": "male", + "age": 67, + "address": { + "state": "Nevada", + "city": "Nanafalia" + } + }, + { + "id": 9780, + "name": "Bowman Long", + "gender": "male", + "age": 81, + "address": { + "state": "Arkansas", + "city": "Leeper" + } + }, + { + "id": 9781, + "name": "Shanna Whitehead", + "gender": "female", + "age": 25, + "address": { + "state": "Massachusetts", + "city": "Ticonderoga" + } + }, + { + "id": 9782, + "name": "Tanisha Soto", + "gender": "female", + "age": 51, + "address": { + "state": "Kentucky", + "city": "Salix" + } + }, + { + "id": 9783, + "name": "Kristen Brewer", + "gender": "female", + "age": 53, + "address": { + "state": "Vermont", + "city": "Vale" + } + }, + { + "id": 9784, + "name": "Johnnie Hatfield", + "gender": "female", + "age": 52, + "address": { + "state": "West Virginia", + "city": "Vincent" + } + }, + { + "id": 9785, + "name": "Hardin Lyons", + "gender": "male", + "age": 19, + "address": { + "state": "Alabama", + "city": "Cannondale" + } + }, + { + "id": 9786, + "name": "Catalina Ramsey", + "gender": "female", + "age": 20, + "address": { + "state": "New York", + "city": "Singer" + } + }, + { + "id": 9787, + "name": "Mendoza Santana", + "gender": "male", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Olney" + } + }, + { + "id": 9788, + "name": "Porter Noel", + "gender": "male", + "age": 45, + "address": { + "state": "Indiana", + "city": "Comptche" + } + }, + { + "id": 9789, + "name": "Boone Barrett", + "gender": "male", + "age": 24, + "address": { + "state": "Arizona", + "city": "Rose" + } + }, + { + "id": 9790, + "name": "Abby Bright", + "gender": "female", + "age": 34, + "address": { + "state": "Georgia", + "city": "Bennett" + } + }, + { + "id": 9791, + "name": "Lindsay Banks", + "gender": "male", + "age": 37, + "address": { + "state": "Utah", + "city": "Dotsero" + } + }, + { + "id": 9792, + "name": "Ayers Melendez", + "gender": "male", + "age": 68, + "address": { + "state": "Wisconsin", + "city": "Indio" + } + }, + { + "id": 9793, + "name": "Welch Butler", + "gender": "male", + "age": 25, + "address": { + "state": "Rhode Island", + "city": "Bordelonville" + } + }, + { + "id": 9794, + "name": "Michael Hamilton", + "gender": "male", + "age": 74, + "address": { + "state": "Oregon", + "city": "Dubois" + } + }, + { + "id": 9795, + "name": "Fulton Jones", + "gender": "male", + "age": 58, + "address": { + "state": "North Carolina", + "city": "Kiskimere" + } + }, + { + "id": 9796, + "name": "Chavez Mcbride", + "gender": "male", + "age": 29, + "address": { + "state": "Oklahoma", + "city": "Soudan" + } + }, + { + "id": 9797, + "name": "Darlene Barron", + "gender": "female", + "age": 53, + "address": { + "state": "New Mexico", + "city": "Gardiner" + } + }, + { + "id": 9798, + "name": "Twila Osborne", + "gender": "female", + "age": 45, + "address": { + "state": "Nebraska", + "city": "Cliff" + } + }, + { + "id": 9799, + "name": "Cheri Patrick", + "gender": "female", + "age": 78, + "address": { + "state": "Washington", + "city": "Gilmore" + } + }, + { + "id": 9800, + "name": "Kate Mccarthy", + "gender": "female", + "age": 24, + "address": { + "state": "Louisiana", + "city": "Wauhillau" + } + }, + { + "id": 9801, + "name": "Gertrude Reyes", + "gender": "female", + "age": 43, + "address": { + "state": "Delaware", + "city": "Coalmont" + } + }, + { + "id": 9802, + "name": "Elsa Bowen", + "gender": "female", + "age": 25, + "address": { + "state": "Connecticut", + "city": "Lacomb" + } + }, + { + "id": 9803, + "name": "Aurora Robbins", + "gender": "female", + "age": 45, + "address": { + "state": "North Dakota", + "city": "Weogufka" + } + }, + { + "id": 9804, + "name": "Strickland Key", + "gender": "male", + "age": 29, + "address": { + "state": "Texas", + "city": "Sanford" + } + }, + { + "id": 9805, + "name": "Lea Brady", + "gender": "female", + "age": 32, + "address": { + "state": "Alaska", + "city": "Wheatfields" + } + }, + { + "id": 9806, + "name": "Patricia Mcgowan", + "gender": "female", + "age": 71, + "address": { + "state": "Kentucky", + "city": "Lupton" + } + }, + { + "id": 9807, + "name": "Wheeler Hoffman", + "gender": "male", + "age": 62, + "address": { + "state": "Maine", + "city": "Hoehne" + } + }, + { + "id": 9808, + "name": "Snider Burton", + "gender": "male", + "age": 79, + "address": { + "state": "Arizona", + "city": "Blodgett" + } + }, + { + "id": 9809, + "name": "Yang Beach", + "gender": "male", + "age": 26, + "address": { + "state": "Oregon", + "city": "Bluffview" + } + }, + { + "id": 9810, + "name": "Penny Anthony", + "gender": "female", + "age": 18, + "address": { + "state": "South Carolina", + "city": "Collins" + } + }, + { + "id": 9811, + "name": "Rasmussen Myers", + "gender": "male", + "age": 53, + "address": { + "state": "Maryland", + "city": "Imperial" + } + }, + { + "id": 9812, + "name": "Pickett Gay", + "gender": "male", + "age": 82, + "address": { + "state": "Arkansas", + "city": "Graball" + } + }, + { + "id": 9813, + "name": "Knowles Rosales", + "gender": "male", + "age": 26, + "address": { + "state": "Minnesota", + "city": "Brambleton" + } + }, + { + "id": 9814, + "name": "Alice Sims", + "gender": "female", + "age": 30, + "address": { + "state": "Montana", + "city": "Denio" + } + }, + { + "id": 9815, + "name": "Chrystal Miller", + "gender": "female", + "age": 73, + "address": { + "state": "Florida", + "city": "Greenbush" + } + }, + { + "id": 9816, + "name": "Mueller Burnett", + "gender": "male", + "age": 22, + "address": { + "state": "Mississippi", + "city": "Healy" + } + }, + { + "id": 9817, + "name": "Fuller Estes", + "gender": "male", + "age": 61, + "address": { + "state": "Iowa", + "city": "Bedias" + } + }, + { + "id": 9818, + "name": "Ferguson Summers", + "gender": "male", + "age": 53, + "address": { + "state": "Massachusetts", + "city": "Eureka" + } + }, + { + "id": 9819, + "name": "Jacquelyn Salas", + "gender": "female", + "age": 75, + "address": { + "state": "Kansas", + "city": "Ticonderoga" + } + }, + { + "id": 9820, + "name": "Sonia Beasley", + "gender": "female", + "age": 57, + "address": { + "state": "West Virginia", + "city": "Riverton" + } + }, + { + "id": 9821, + "name": "Tracy Wooten", + "gender": "female", + "age": 73, + "address": { + "state": "New Hampshire", + "city": "Gambrills" + } + }, + { + "id": 9822, + "name": "Atkins Crosby", + "gender": "male", + "age": 80, + "address": { + "state": "Wyoming", + "city": "Escondida" + } + }, + { + "id": 9823, + "name": "Ruthie Petty", + "gender": "female", + "age": 57, + "address": { + "state": "Oklahoma", + "city": "Hiseville" + } + }, + { + "id": 9824, + "name": "Mildred Macias", + "gender": "female", + "age": 44, + "address": { + "state": "Pennsylvania", + "city": "Mayfair" + } + }, + { + "id": 9825, + "name": "Mclaughlin Rodriguez", + "gender": "male", + "age": 81, + "address": { + "state": "Rhode Island", + "city": "Robinson" + } + }, + { + "id": 9826, + "name": "Juarez Ramirez", + "gender": "male", + "age": 18, + "address": { + "state": "New Jersey", + "city": "Snyderville" + } + }, + { + "id": 9827, + "name": "Moore Gaines", + "gender": "male", + "age": 41, + "address": { + "state": "Georgia", + "city": "Sunbury" + } + }, + { + "id": 9828, + "name": "Bradford Palmer", + "gender": "male", + "age": 23, + "address": { + "state": "South Dakota", + "city": "Nadine" + } + }, + { + "id": 9829, + "name": "Allen Gallagher", + "gender": "male", + "age": 31, + "address": { + "state": "Ohio", + "city": "Topanga" + } + }, + { + "id": 9830, + "name": "Millie Cortez", + "gender": "female", + "age": 50, + "address": { + "state": "Washington", + "city": "Aurora" + } + }, + { + "id": 9831, + "name": "Pennington Roy", + "gender": "male", + "age": 26, + "address": { + "state": "New York", + "city": "Titanic" + } + }, + { + "id": 9832, + "name": "Lucille Bell", + "gender": "female", + "age": 64, + "address": { + "state": "Colorado", + "city": "Lydia" + } + }, + { + "id": 9833, + "name": "Ruby Mayo", + "gender": "female", + "age": 60, + "address": { + "state": "Tennessee", + "city": "Riner" + } + }, + { + "id": 9834, + "name": "Pugh James", + "gender": "male", + "age": 72, + "address": { + "state": "Utah", + "city": "Savannah" + } + }, + { + "id": 9835, + "name": "Walton Frost", + "gender": "male", + "age": 53, + "address": { + "state": "Vermont", + "city": "Orin" + } + }, + { + "id": 9836, + "name": "Sawyer Blair", + "gender": "male", + "age": 33, + "address": { + "state": "New Mexico", + "city": "Fivepointville" + } + }, + { + "id": 9837, + "name": "Teresa King", + "gender": "female", + "age": 79, + "address": { + "state": "Michigan", + "city": "Verdi" + } + }, + { + "id": 9838, + "name": "Janelle Rush", + "gender": "female", + "age": 46, + "address": { + "state": "Indiana", + "city": "Albany" + } + }, + { + "id": 9839, + "name": "Hutchinson Jordan", + "gender": "male", + "age": 36, + "address": { + "state": "Nevada", + "city": "Fruitdale" + } + }, + { + "id": 9840, + "name": "Nolan Fry", + "gender": "male", + "age": 60, + "address": { + "state": "North Carolina", + "city": "Wadsworth" + } + }, + { + "id": 9841, + "name": "Dixon Nelson", + "gender": "male", + "age": 48, + "address": { + "state": "Wisconsin", + "city": "Rosine" + } + }, + { + "id": 9842, + "name": "Barry Holloway", + "gender": "male", + "age": 56, + "address": { + "state": "California", + "city": "Toftrees" + } + }, + { + "id": 9843, + "name": "Christa Edwards", + "gender": "female", + "age": 62, + "address": { + "state": "Hawaii", + "city": "Summerset" + } + }, + { + "id": 9844, + "name": "Karyn Howell", + "gender": "female", + "age": 74, + "address": { + "state": "Nebraska", + "city": "Esmont" + } + }, + { + "id": 9845, + "name": "Heather Chandler", + "gender": "female", + "age": 35, + "address": { + "state": "Illinois", + "city": "Nelson" + } + }, + { + "id": 9846, + "name": "Mayra Olsen", + "gender": "female", + "age": 51, + "address": { + "state": "Alabama", + "city": "Sanborn" + } + }, + { + "id": 9847, + "name": "Kathie Oliver", + "gender": "female", + "age": 55, + "address": { + "state": "Missouri", + "city": "Gorham" + } + }, + { + "id": 9848, + "name": "Estela Williamson", + "gender": "female", + "age": 71, + "address": { + "state": "Idaho", + "city": "Laurelton" + } + }, + { + "id": 9849, + "name": "Fry Duncan", + "gender": "male", + "age": 20, + "address": { + "state": "Maine", + "city": "Conway" + } + }, + { + "id": 9850, + "name": "Carver Aguilar", + "gender": "male", + "age": 66, + "address": { + "state": "Rhode Island", + "city": "Stouchsburg" + } + }, + { + "id": 9851, + "name": "Tamara Bolton", + "gender": "female", + "age": 17, + "address": { + "state": "Oregon", + "city": "Gadsden" + } + }, + { + "id": 9852, + "name": "Moore Maynard", + "gender": "male", + "age": 79, + "address": { + "state": "Hawaii", + "city": "Silkworth" + } + }, + { + "id": 9853, + "name": "Fulton Osborne", + "gender": "male", + "age": 54, + "address": { + "state": "North Carolina", + "city": "Matheny" + } + }, + { + "id": 9854, + "name": "Twila Keller", + "gender": "female", + "age": 59, + "address": { + "state": "California", + "city": "Brandywine" + } + }, + { + "id": 9855, + "name": "Erickson Sykes", + "gender": "male", + "age": 66, + "address": { + "state": "South Carolina", + "city": "Wheaton" + } + }, + { + "id": 9856, + "name": "Nellie Hammond", + "gender": "female", + "age": 77, + "address": { + "state": "New York", + "city": "Adelino" + } + }, + { + "id": 9857, + "name": "Bell Hawkins", + "gender": "male", + "age": 51, + "address": { + "state": "Montana", + "city": "Wilmington" + } + }, + { + "id": 9858, + "name": "Marianne Hernandez", + "gender": "female", + "age": 48, + "address": { + "state": "Wyoming", + "city": "Oneida" + } + }, + { + "id": 9859, + "name": "Hilda Carey", + "gender": "female", + "age": 72, + "address": { + "state": "Illinois", + "city": "Loyalhanna" + } + }, + { + "id": 9860, + "name": "Lang Sloan", + "gender": "male", + "age": 57, + "address": { + "state": "North Dakota", + "city": "Hiseville" + } + }, + { + "id": 9861, + "name": "Aileen Bradshaw", + "gender": "female", + "age": 18, + "address": { + "state": "Alaska", + "city": "Deputy" + } + }, + { + "id": 9862, + "name": "Rosalyn Madden", + "gender": "female", + "age": 17, + "address": { + "state": "Alabama", + "city": "Escondida" + } + }, + { + "id": 9863, + "name": "Georgette Baird", + "gender": "female", + "age": 53, + "address": { + "state": "Nebraska", + "city": "Gouglersville" + } + }, + { + "id": 9864, + "name": "Krystal Jacobs", + "gender": "female", + "age": 45, + "address": { + "state": "Nevada", + "city": "Lisco" + } + }, + { + "id": 9865, + "name": "Rhonda Jennings", + "gender": "female", + "age": 80, + "address": { + "state": "Connecticut", + "city": "Kingstowne" + } + }, + { + "id": 9866, + "name": "Mcmahon Joseph", + "gender": "male", + "age": 47, + "address": { + "state": "Minnesota", + "city": "Columbus" + } + }, + { + "id": 9867, + "name": "Holden Sims", + "gender": "male", + "age": 30, + "address": { + "state": "Pennsylvania", + "city": "Nadine" + } + }, + { + "id": 9868, + "name": "Patton Russo", + "gender": "male", + "age": 19, + "address": { + "state": "Vermont", + "city": "Kapowsin" + } + }, + { + "id": 9869, + "name": "Bonner Norman", + "gender": "male", + "age": 62, + "address": { + "state": "Iowa", + "city": "Rossmore" + } + }, + { + "id": 9870, + "name": "Josefina Payne", + "gender": "female", + "age": 41, + "address": { + "state": "Delaware", + "city": "Lawrence" + } + }, + { + "id": 9871, + "name": "Lowery Farley", + "gender": "male", + "age": 78, + "address": { + "state": "Colorado", + "city": "Stewartville" + } + }, + { + "id": 9872, + "name": "Hughes Sargent", + "gender": "male", + "age": 38, + "address": { + "state": "Utah", + "city": "Kaka" + } + }, + { + "id": 9873, + "name": "Mindy Davenport", + "gender": "female", + "age": 61, + "address": { + "state": "Louisiana", + "city": "Esmont" + } + }, + { + "id": 9874, + "name": "Mullen Sosa", + "gender": "male", + "age": 57, + "address": { + "state": "Idaho", + "city": "Tyhee" + } + }, + { + "id": 9875, + "name": "Selma Noble", + "gender": "female", + "age": 18, + "address": { + "state": "Kentucky", + "city": "Neibert" + } + }, + { + "id": 9876, + "name": "Thornton Velez", + "gender": "male", + "age": 71, + "address": { + "state": "Texas", + "city": "Yogaville" + } + }, + { + "id": 9877, + "name": "Russell Shepherd", + "gender": "male", + "age": 39, + "address": { + "state": "New Jersey", + "city": "Gorham" + } + }, + { + "id": 9878, + "name": "Cindy Blackwell", + "gender": "female", + "age": 21, + "address": { + "state": "Maryland", + "city": "Elwood" + } + }, + { + "id": 9879, + "name": "Marla Church", + "gender": "female", + "age": 68, + "address": { + "state": "Indiana", + "city": "Bladensburg" + } + }, + { + "id": 9880, + "name": "Maryellen Norris", + "gender": "female", + "age": 32, + "address": { + "state": "New Mexico", + "city": "Haring" + } + }, + { + "id": 9881, + "name": "Morrison Garza", + "gender": "male", + "age": 38, + "address": { + "state": "Ohio", + "city": "Wollochet" + } + }, + { + "id": 9882, + "name": "Holly Short", + "gender": "female", + "age": 36, + "address": { + "state": "Arizona", + "city": "Vowinckel" + } + }, + { + "id": 9883, + "name": "Brooks Castillo", + "gender": "male", + "age": 53, + "address": { + "state": "Wisconsin", + "city": "Byrnedale" + } + }, + { + "id": 9884, + "name": "Rocha Rowland", + "gender": "male", + "age": 38, + "address": { + "state": "Missouri", + "city": "Tuttle" + } + }, + { + "id": 9885, + "name": "Harriett Atkinson", + "gender": "female", + "age": 50, + "address": { + "state": "Oklahoma", + "city": "Weeksville" + } + }, + { + "id": 9886, + "name": "Merritt Spencer", + "gender": "male", + "age": 54, + "address": { + "state": "Massachusetts", + "city": "Henrietta" + } + }, + { + "id": 9887, + "name": "Reba Finley", + "gender": "female", + "age": 77, + "address": { + "state": "Kansas", + "city": "Cressey" + } + }, + { + "id": 9888, + "name": "Baxter Ramsey", + "gender": "male", + "age": 51, + "address": { + "state": "Virginia", + "city": "Vandiver" + } + }, + { + "id": 9889, + "name": "Hubbard Stuart", + "gender": "male", + "age": 79, + "address": { + "state": "Michigan", + "city": "Cade" + } + }, + { + "id": 9890, + "name": "Zimmerman Montoya", + "gender": "male", + "age": 43, + "address": { + "state": "Washington", + "city": "Frank" + } + }, + { + "id": 9891, + "name": "Graham Goodwin", + "gender": "male", + "age": 55, + "address": { + "state": "Arkansas", + "city": "Heil" + } + }, + { + "id": 9892, + "name": "Johnson Golden", + "gender": "male", + "age": 29, + "address": { + "state": "Mississippi", + "city": "Nogal" + } + }, + { + "id": 9893, + "name": "Smith Duncan", + "gender": "male", + "age": 42, + "address": { + "state": "West Virginia", + "city": "Kula" + } + }, + { + "id": 9894, + "name": "Maureen Padilla", + "gender": "female", + "age": 25, + "address": { + "state": "New Hampshire", + "city": "Vienna" + } + }, + { + "id": 9895, + "name": "Lora Barnett", + "gender": "female", + "age": 26, + "address": { + "state": "South Dakota", + "city": "Freelandville" + } + }, + { + "id": 9896, + "name": "Benjamin Mcknight", + "gender": "male", + "age": 21, + "address": { + "state": "Florida", + "city": "Smock" + } + }, + { + "id": 9897, + "name": "Belinda Ferrell", + "gender": "female", + "age": 60, + "address": { + "state": "Georgia", + "city": "Harleigh" + } + }, + { + "id": 9898, + "name": "Valdez Manning", + "gender": "male", + "age": 70, + "address": { + "state": "Michigan", + "city": "Buxton" + } + }, + { + "id": 9899, + "name": "Ruthie Gilbert", + "gender": "female", + "age": 66, + "address": { + "state": "Oregon", + "city": "Ezel" + } + }, + { + "id": 9900, + "name": "Buck Lowery", + "gender": "male", + "age": 64, + "address": { + "state": "Nebraska", + "city": "Dale" + } + }, + { + "id": 9901, + "name": "Jill Kidd", + "gender": "female", + "age": 42, + "address": { + "state": "Kansas", + "city": "Bynum" + } + }, + { + "id": 9902, + "name": "Lori Harding", + "gender": "female", + "age": 46, + "address": { + "state": "Maine", + "city": "Fedora" + } + }, + { + "id": 9903, + "name": "Polly Watts", + "gender": "female", + "age": 21, + "address": { + "state": "Utah", + "city": "Finderne" + } + }, + { + "id": 9904, + "name": "Holly Witt", + "gender": "female", + "age": 21, + "address": { + "state": "Iowa", + "city": "Gila" + } + }, + { + "id": 9905, + "name": "Lacey Stone", + "gender": "female", + "age": 29, + "address": { + "state": "Vermont", + "city": "Wanship" + } + }, + { + "id": 9906, + "name": "Sweet Joyner", + "gender": "male", + "age": 65, + "address": { + "state": "New Mexico", + "city": "Coinjock" + } + }, + { + "id": 9907, + "name": "Wanda Townsend", + "gender": "female", + "age": 81, + "address": { + "state": "Idaho", + "city": "Century" + } + }, + { + "id": 9908, + "name": "Louella Dominguez", + "gender": "female", + "age": 40, + "address": { + "state": "Wyoming", + "city": "Summertown" + } + }, + { + "id": 9909, + "name": "Dickerson Maxwell", + "gender": "male", + "age": 37, + "address": { + "state": "Montana", + "city": "Imperial" + } + }, + { + "id": 9910, + "name": "Hoover Barlow", + "gender": "male", + "age": 71, + "address": { + "state": "Alabama", + "city": "Brogan" + } + }, + { + "id": 9911, + "name": "Schultz Weiss", + "gender": "male", + "age": 32, + "address": { + "state": "Connecticut", + "city": "Lowgap" + } + }, + { + "id": 9912, + "name": "Ruby Camacho", + "gender": "female", + "age": 41, + "address": { + "state": "Pennsylvania", + "city": "Choctaw" + } + }, + { + "id": 9913, + "name": "Lawson Blair", + "gender": "male", + "age": 64, + "address": { + "state": "New York", + "city": "Hoehne" + } + }, + { + "id": 9914, + "name": "Alford Rogers", + "gender": "male", + "age": 39, + "address": { + "state": "Indiana", + "city": "Mayfair" + } + }, + { + "id": 9915, + "name": "Evangeline Gill", + "gender": "female", + "age": 54, + "address": { + "state": "South Dakota", + "city": "Galesville" + } + }, + { + "id": 9916, + "name": "Gaines Graham", + "gender": "male", + "age": 37, + "address": { + "state": "Washington", + "city": "Tolu" + } + }, + { + "id": 9917, + "name": "Lucinda Goff", + "gender": "female", + "age": 57, + "address": { + "state": "Arizona", + "city": "Onton" + } + }, + { + "id": 9918, + "name": "Stuart Rich", + "gender": "male", + "age": 25, + "address": { + "state": "Georgia", + "city": "Springdale" + } + }, + { + "id": 9919, + "name": "Steele Michael", + "gender": "male", + "age": 52, + "address": { + "state": "Delaware", + "city": "Romeville" + } + }, + { + "id": 9920, + "name": "Betsy Cash", + "gender": "female", + "age": 73, + "address": { + "state": "Florida", + "city": "Lund" + } + }, + { + "id": 9921, + "name": "Singleton Macdonald", + "gender": "male", + "age": 58, + "address": { + "state": "Arkansas", + "city": "Warren" + } + }, + { + "id": 9922, + "name": "Thornton Griffith", + "gender": "male", + "age": 40, + "address": { + "state": "Massachusetts", + "city": "Nelson" + } + }, + { + "id": 9923, + "name": "Mamie Pittman", + "gender": "female", + "age": 35, + "address": { + "state": "Hawaii", + "city": "Mammoth" + } + }, + { + "id": 9924, + "name": "Katy Nunez", + "gender": "female", + "age": 48, + "address": { + "state": "Louisiana", + "city": "Ferney" + } + }, + { + "id": 9925, + "name": "Hughes Mckay", + "gender": "male", + "age": 24, + "address": { + "state": "Mississippi", + "city": "Toftrees" + } + }, + { + "id": 9926, + "name": "Chan Garcia", + "gender": "male", + "age": 53, + "address": { + "state": "Tennessee", + "city": "Farmington" + } + }, + { + "id": 9927, + "name": "Leanna Mclaughlin", + "gender": "female", + "age": 17, + "address": { + "state": "Wisconsin", + "city": "Waikele" + } + }, + { + "id": 9928, + "name": "Stacey Espinoza", + "gender": "female", + "age": 36, + "address": { + "state": "New Jersey", + "city": "Washington" + } + }, + { + "id": 9929, + "name": "Tracie Berry", + "gender": "female", + "age": 22, + "address": { + "state": "North Dakota", + "city": "Edgewater" + } + }, + { + "id": 9930, + "name": "Mills Cherry", + "gender": "male", + "age": 25, + "address": { + "state": "Kentucky", + "city": "Hemlock" + } + }, + { + "id": 9931, + "name": "Tania Bauer", + "gender": "female", + "age": 61, + "address": { + "state": "Oklahoma", + "city": "Chaparrito" + } + }, + { + "id": 9932, + "name": "Mable Montoya", + "gender": "female", + "age": 44, + "address": { + "state": "Missouri", + "city": "Henrietta" + } + }, + { + "id": 9933, + "name": "Arline Wilson", + "gender": "female", + "age": 36, + "address": { + "state": "Alaska", + "city": "Kenvil" + } + }, + { + "id": 9934, + "name": "Mathis Brock", + "gender": "male", + "age": 48, + "address": { + "state": "North Carolina", + "city": "Ernstville" + } + }, + { + "id": 9935, + "name": "Mcguire Higgins", + "gender": "male", + "age": 20, + "address": { + "state": "California", + "city": "Spokane" + } + }, + { + "id": 9936, + "name": "Baldwin Carroll", + "gender": "male", + "age": 32, + "address": { + "state": "South Carolina", + "city": "Ribera" + } + }, + { + "id": 9937, + "name": "Hernandez Ramos", + "gender": "male", + "age": 57, + "address": { + "state": "New Hampshire", + "city": "Woodburn" + } + }, + { + "id": 9938, + "name": "May Wallace", + "gender": "female", + "age": 32, + "address": { + "state": "Ohio", + "city": "Alamo" + } + }, + { + "id": 9939, + "name": "Joyce Sweet", + "gender": "female", + "age": 41, + "address": { + "state": "Colorado", + "city": "Longbranch" + } + }, + { + "id": 9940, + "name": "Natalia Benton", + "gender": "female", + "age": 45, + "address": { + "state": "Maryland", + "city": "Sidman" + } + }, + { + "id": 9941, + "name": "Kane Davidson", + "gender": "male", + "age": 62, + "address": { + "state": "West Virginia", + "city": "Dixie" + } + }, + { + "id": 9942, + "name": "Baird Roth", + "gender": "male", + "age": 67, + "address": { + "state": "Illinois", + "city": "Dante" + } + }, + { + "id": 9943, + "name": "Barron Alvarez", + "gender": "male", + "age": 19, + "address": { + "state": "Minnesota", + "city": "Enoree" + } + }, + { + "id": 9944, + "name": "Norris Garza", + "gender": "male", + "age": 68, + "address": { + "state": "Virginia", + "city": "Waverly" + } + }, + { + "id": 9945, + "name": "Eugenia Stanley", + "gender": "female", + "age": 61, + "address": { + "state": "Nevada", + "city": "Dexter" + } + }, + { + "id": 9946, + "name": "Hope Murphy", + "gender": "female", + "age": 72, + "address": { + "state": "Texas", + "city": "Wheatfields" + } + }, + { + "id": 9947, + "name": "Chang Garrison", + "gender": "male", + "age": 71, + "address": { + "state": "Delaware", + "city": "Caspar" + } + }, + { + "id": 9948, + "name": "Ryan Peck", + "gender": "male", + "age": 51, + "address": { + "state": "California", + "city": "Unionville" + } + }, + { + "id": 9949, + "name": "Marianne Bright", + "gender": "female", + "age": 39, + "address": { + "state": "New Hampshire", + "city": "Aurora" + } + }, + { + "id": 9950, + "name": "Ratliff Merritt", + "gender": "male", + "age": 30, + "address": { + "state": "Montana", + "city": "Rockbridge" + } + }, + { + "id": 9951, + "name": "Swanson Stevenson", + "gender": "male", + "age": 49, + "address": { + "state": "Louisiana", + "city": "Byrnedale" + } + }, + { + "id": 9952, + "name": "Beatrice Pitts", + "gender": "female", + "age": 78, + "address": { + "state": "Missouri", + "city": "Callaghan" + } + }, + { + "id": 9953, + "name": "Mable Hansen", + "gender": "female", + "age": 31, + "address": { + "state": "Colorado", + "city": "Bordelonville" + } + }, + { + "id": 9954, + "name": "Autumn Robles", + "gender": "female", + "age": 38, + "address": { + "state": "Pennsylvania", + "city": "Rosine" + } + }, + { + "id": 9955, + "name": "Jarvis Blackburn", + "gender": "male", + "age": 69, + "address": { + "state": "Michigan", + "city": "Interlochen" + } + }, + { + "id": 9956, + "name": "Kari Jennings", + "gender": "female", + "age": 20, + "address": { + "state": "New York", + "city": "Como" + } + }, + { + "id": 9957, + "name": "Bradley Crane", + "gender": "male", + "age": 75, + "address": { + "state": "Washington", + "city": "Watchtower" + } + }, + { + "id": 9958, + "name": "Hurst Shepard", + "gender": "male", + "age": 71, + "address": { + "state": "Kansas", + "city": "Gorst" + } + }, + { + "id": 9959, + "name": "House Bryant", + "gender": "male", + "age": 80, + "address": { + "state": "Arizona", + "city": "Waverly" + } + }, + { + "id": 9960, + "name": "Hope Norton", + "gender": "female", + "age": 41, + "address": { + "state": "Arkansas", + "city": "Grill" + } + }, + { + "id": 9961, + "name": "Wilma Montgomery", + "gender": "female", + "age": 43, + "address": { + "state": "Wisconsin", + "city": "Manila" + } + }, + { + "id": 9962, + "name": "Baldwin Donaldson", + "gender": "male", + "age": 22, + "address": { + "state": "Nebraska", + "city": "Kapowsin" + } + }, + { + "id": 9963, + "name": "Stark Chapman", + "gender": "male", + "age": 41, + "address": { + "state": "Illinois", + "city": "Greer" + } + }, + { + "id": 9964, + "name": "Sosa Burnett", + "gender": "male", + "age": 81, + "address": { + "state": "West Virginia", + "city": "Connerton" + } + }, + { + "id": 9965, + "name": "Mann Kline", + "gender": "male", + "age": 46, + "address": { + "state": "Nevada", + "city": "Ronco" + } + }, + { + "id": 9966, + "name": "Renee Gates", + "gender": "female", + "age": 23, + "address": { + "state": "Vermont", + "city": "Nettie" + } + }, + { + "id": 9967, + "name": "Kaufman Hogan", + "gender": "male", + "age": 81, + "address": { + "state": "New Jersey", + "city": "Tivoli" + } + }, + { + "id": 9968, + "name": "Emma Berger", + "gender": "female", + "age": 60, + "address": { + "state": "Texas", + "city": "Madrid" + } + }, + { + "id": 9969, + "name": "Jenkins Dennis", + "gender": "male", + "age": 73, + "address": { + "state": "Utah", + "city": "Gratton" + } + }, + { + "id": 9970, + "name": "Hopkins Fischer", + "gender": "male", + "age": 67, + "address": { + "state": "South Carolina", + "city": "Sexton" + } + }, + { + "id": 9971, + "name": "Opal Cox", + "gender": "female", + "age": 23, + "address": { + "state": "Tennessee", + "city": "Goochland" + } + }, + { + "id": 9972, + "name": "Janice Slater", + "gender": "female", + "age": 62, + "address": { + "state": "Alaska", + "city": "Hasty" + } + }, + { + "id": 9973, + "name": "Jerry Barron", + "gender": "female", + "age": 59, + "address": { + "state": "North Dakota", + "city": "Westwood" + } + }, + { + "id": 9974, + "name": "Randolph Day", + "gender": "male", + "age": 77, + "address": { + "state": "Ohio", + "city": "Genoa" + } + }, + { + "id": 9975, + "name": "Bessie Mcdaniel", + "gender": "female", + "age": 34, + "address": { + "state": "North Carolina", + "city": "Berlin" + } + }, + { + "id": 9976, + "name": "Pennington Hoover", + "gender": "male", + "age": 41, + "address": { + "state": "Oregon", + "city": "Holtville" + } + }, + { + "id": 9977, + "name": "Tamara Norman", + "gender": "female", + "age": 61, + "address": { + "state": "Iowa", + "city": "Garberville" + } + }, + { + "id": 9978, + "name": "Lupe Walls", + "gender": "female", + "age": 41, + "address": { + "state": "Connecticut", + "city": "Hickory" + } + }, + { + "id": 9979, + "name": "Navarro Barry", + "gender": "male", + "age": 78, + "address": { + "state": "South Dakota", + "city": "Wauhillau" + } + }, + { + "id": 9980, + "name": "Lessie Ashley", + "gender": "female", + "age": 66, + "address": { + "state": "Minnesota", + "city": "Cassel" + } + }, + { + "id": 9981, + "name": "Lucas Rivera", + "gender": "male", + "age": 52, + "address": { + "state": "Kentucky", + "city": "Hobucken" + } + }, + { + "id": 9982, + "name": "Ann Cochran", + "gender": "female", + "age": 38, + "address": { + "state": "Mississippi", + "city": "Orason" + } + }, + { + "id": 9983, + "name": "Duke Hawkins", + "gender": "male", + "age": 65, + "address": { + "state": "Massachusetts", + "city": "Verdi" + } + }, + { + "id": 9984, + "name": "Charlotte Lowe", + "gender": "female", + "age": 75, + "address": { + "state": "Hawaii", + "city": "Germanton" + } + }, + { + "id": 9985, + "name": "Sheryl Rice", + "gender": "female", + "age": 36, + "address": { + "state": "Idaho", + "city": "Warsaw" + } + }, + { + "id": 9986, + "name": "Griffin Pena", + "gender": "male", + "age": 66, + "address": { + "state": "Florida", + "city": "Vienna" + } + }, + { + "id": 9987, + "name": "Cleo Gill", + "gender": "female", + "age": 25, + "address": { + "state": "Georgia", + "city": "Alderpoint" + } + }, + { + "id": 9988, + "name": "Lynette York", + "gender": "female", + "age": 71, + "address": { + "state": "Wyoming", + "city": "Bagtown" + } + }, + { + "id": 9989, + "name": "Stevenson Marsh", + "gender": "male", + "age": 79, + "address": { + "state": "Indiana", + "city": "Bawcomville" + } + }, + { + "id": 9990, + "name": "Kathy Perkins", + "gender": "female", + "age": 18, + "address": { + "state": "Maryland", + "city": "Springdale" + } + }, + { + "id": 9991, + "name": "Knowles Oneil", + "gender": "male", + "age": 47, + "address": { + "state": "Oklahoma", + "city": "Sunnyside" + } + }, + { + "id": 9992, + "name": "Cherie Guthrie", + "gender": "female", + "age": 40, + "address": { + "state": "New Mexico", + "city": "Lumberton" + } + }, + { + "id": 9993, + "name": "Simpson Howard", + "gender": "male", + "age": 64, + "address": { + "state": "Alabama", + "city": "Summerfield" + } + }, + { + "id": 9994, + "name": "Patrica Rich", + "gender": "female", + "age": 23, + "address": { + "state": "Virginia", + "city": "Dana" + } + }, + { + "id": 9995, + "name": "Frazier Tillman", + "gender": "male", + "age": 18, + "address": { + "state": "Maine", + "city": "Taycheedah" + } + }, + { + "id": 9996, + "name": "Kristie Rutledge", + "gender": "female", + "age": 26, + "address": { + "state": "Alaska", + "city": "Bison" + } + }, + { + "id": 9997, + "name": "Reva Reese", + "gender": "female", + "age": 39, + "address": { + "state": "Ohio", + "city": "Templeton" + } + }, + { + "id": 9998, + "name": "Shirley Ellison", + "gender": "female", + "age": 25, + "address": { + "state": "New Mexico", + "city": "Walland" + } + }, + { + "id": 9999, + "name": "Bonita Black", + "gender": "female", + "age": 62, + "address": { + "state": "Virginia", + "city": "Coaldale" + } + } +] \ No newline at end of file diff --git a/data/1000_columns.json b/data/1000_columns.json new file mode 100644 index 000000000..dfdb4b4e3 --- /dev/null +++ b/data/1000_columns.json @@ -0,0 +1,100402 @@ +[ + { + "name": "Eula Juarez", + "gender": "female", + "col0": "vr2bt", + "col1": "y6n3q", + "col2": "ct1vl", + "col3": "tewag", + "col4": "7ehmp", + "col5": "ylfyd", + "col6": "58sgx", + "col7": "vhu1i", + "col8": "dl3yh", + "col9": "b2y7r", + "col10": "7xht7", + "col11": "woyv1", + "col12": "kz80m", + "col13": "9p5jc", + "col14": "zmyw4", + "col15": "fv9jq", + "col16": "28i58", + "col17": "2pqvt", + "col18": "m6p03", + "col19": "l7hfs", + "col20": "lho0e", + "col21": "lo2w3", + "col22": "sxhud", + "col23": "gt40u", + "col24": "cu7ta", + "col25": "ur1zb", + "col26": "48r2t", + "col27": "ratnw", + "col28": "x75zo", + "col29": "jxhwq", + "col30": "mj8j2", + "col31": "ir0s8", + "col32": "z7s9w", + "col33": "qvwfm", + "col34": "6fthm", + "col35": "5vjkg", + "col36": "2k0t7", + "col37": "usf50", + "col38": "2g1vt", + "col39": "q4nmf", + "col40": "peq6i", + "col41": "2lre4", + "col42": "c0r6x", + "col43": "7avig", + "col44": "5egiy", + "col45": "qc19l", + "col46": "2tr92", + "col47": "h25m6", + "col48": "i9dxb", + "col49": "vjvog", + "col50": "kicsq", + "col51": "f99s9", + "col52": "ekr0y", + "col53": "1gza9", + "col54": "gd93z", + "col55": "bg8n6", + "col56": "yk5k9", + "col57": "rvxso", + "col58": "lbnad", + "col59": "m1lz6", + "col60": "v6so1", + "col61": "29z1f", + "col62": "un3qa", + "col63": "zq6wo", + "col64": "ka4i0", + "col65": "987k1", + "col66": "tn3qg", + "col67": "v5w7u", + "col68": "foi98", + "col69": "o3zym", + "col70": "26zin", + "col71": "6joyy", + "col72": "twduk", + "col73": "r3kll", + "col74": "dh31h", + "col75": "y8zj7", + "col76": "u47va", + "col77": "r5fjg", + "col78": "q3dco", + "col79": "zdkl0", + "col80": "s06h7", + "col81": "w70x0", + "col82": "mw2sb", + "col83": "4or7r", + "col84": "jm092", + "col85": "oqq5x", + "col86": "gk5qm", + "col87": "t2yk7", + "col88": "qbp2b", + "col89": "ga48a", + "col90": "rc4cp", + "col91": "rl5bf", + "col92": "i9xaa", + "col93": "wk5gy", + "col94": "hnllp", + "col95": "wv1qz", + "col96": "qtex0", + "col97": "w0qil", + "col98": "jj03d", + "col99": "ykbkq", + "col100": "id45x", + "col101": "i0qvv", + "col102": "1ggvy", + "col103": "kw87t", + "col104": "jvz7c", + "col105": "i4lkk", + "col106": "k8thz", + "col107": "zvfbz", + "col108": "vsnbb", + "col109": "po40r", + "col110": "50iue", + "col111": "awnve", + "col112": "50p6b", + "col113": "pzwkh", + "col114": "t35j5", + "col115": "dszb0", + "col116": "ly21j", + "col117": "c9z0t", + "col118": "v6qdc", + "col119": "7y6v8", + "col120": "9jjfa", + "col121": "wu7ft", + "col122": "ce0xx", + "col123": "hcz5v", + "col124": "61b2p", + "col125": "0ispw", + "col126": "fw7ej", + "col127": "h5qk5", + "col128": "07m11", + "col129": "i5gap", + "col130": "lwl83", + "col131": "89mo1", + "col132": "9cdlq", + "col133": "zan08", + "col134": "8qqym", + "col135": "73r9v", + "col136": "qxhwp", + "col137": "tott7", + "col138": "pawat", + "col139": "v9tqd", + "col140": "1unin", + "col141": "gklyx", + "col142": "o5hhw", + "col143": "wraym", + "col144": "4dnb3", + "col145": "78hwd", + "col146": "mr33u", + "col147": "t97zv", + "col148": "yglus", + "col149": "03zbx", + "col150": "h2d82", + "col151": "mfc46", + "col152": "jny4q", + "col153": "0czd1", + "col154": "322hg", + "col155": "tk2ul", + "col156": "86wra", + "col157": "hqe4m", + "col158": "gfo44", + "col159": "o3wpl", + "col160": "39tj7", + "col161": "nho12", + "col162": "yourw", + "col163": "j40hk", + "col164": "uafji", + "col165": "qtuy1", + "col166": "codst", + "col167": "g1h1y", + "col168": "5mejz", + "col169": "bu2ro", + "col170": "abl1p", + "col171": "6ayze", + "col172": "5ye3l", + "col173": "fgwv6", + "col174": "4kzig", + "col175": "pwy4m", + "col176": "bv5tx", + "col177": "pjhk2", + "col178": "d8c8l", + "col179": "2l0x3", + "col180": "hb36l", + "col181": "j7qzk", + "col182": "7181m", + "col183": "kydze", + "col184": "mzzkw", + "col185": "90bda", + "col186": "agvp5", + "col187": "5n8wz", + "col188": "ex2hy", + "col189": "0su58", + "col190": "qfzvt", + "col191": "t2pvh", + "col192": "1klym", + "col193": "2vac3", + "col194": "9hnuf", + "col195": "yse5v", + "col196": "r07gu", + "col197": "czev9", + "col198": "6zlye", + "col199": "kr3k6", + "col200": "h1wzq", + "col201": "ic141", + "col202": "l53tg", + "col203": "qhd7t", + "col204": "cd5xa", + "col205": "fyuhx", + "col206": "u4nhv", + "col207": "8g35p", + "col208": "ffvm9", + "col209": "7e85q", + "col210": "0om85", + "col211": "2son1", + "col212": "7vfg6", + "col213": "4i6qr", + "col214": "4yjzt", + "col215": "z79ny", + "col216": "ll81o", + "col217": "tu7yn", + "col218": "24rit", + "col219": "atypk", + "col220": "w6p5a", + "col221": "6ip16", + "col222": "kazed", + "col223": "frair", + "col224": "8xtwy", + "col225": "05onu", + "col226": "qr5yg", + "col227": "zmk92", + "col228": "89lv7", + "col229": "34qw9", + "col230": "2x8hv", + "col231": "36i5v", + "col232": "us9d4", + "col233": "a8qva", + "col234": "doylr", + "col235": "fznpp", + "col236": "ky7wv", + "col237": "x4c0b", + "col238": "4c9fw", + "col239": "yqmhf", + "col240": "r75kg", + "col241": "urs7z", + "col242": "73bjs", + "col243": "n84zo", + "col244": "86rag", + "col245": "hpdh8", + "col246": "lxfl0", + "col247": "v7qmy", + "col248": "8iv2r", + "col249": "pewg0", + "col250": "8i7ra", + "col251": "y49qi", + "col252": "napdd", + "col253": "9k8b7", + "col254": "xgeyo", + "col255": "6na3l", + "col256": "gx8xw", + "col257": "ghvut", + "col258": "c0wm7", + "col259": "1ws9s", + "col260": "mswq8", + "col261": "2otog", + "col262": "ln2gj", + "col263": "sbb0f", + "col264": "u2svx", + "col265": "7q8mi", + "col266": "ykdoc", + "col267": "qr49l", + "col268": "hm7of", + "col269": "7l6vz", + "col270": "vn1ks", + "col271": "b365y", + "col272": "cv9yv", + "col273": "cr9nk", + "col274": "a1k6n", + "col275": "og4yf", + "col276": "wu7x0", + "col277": "1hk0e", + "col278": "yl8ah", + "col279": "tnffz", + "col280": "gbuan", + "col281": "t57it", + "col282": "3hytj", + "col283": "0bzpp", + "col284": "zsnwk", + "col285": "t4dnk", + "col286": "tdr7v", + "col287": "ktnez", + "col288": "yp9lv", + "col289": "295je", + "col290": "dkftt", + "col291": "0pdqq", + "col292": "507i2", + "col293": "aso9j", + "col294": "5yfua", + "col295": "gpypz", + "col296": "wybbk", + "col297": "qrpwg", + "col298": "6udbl", + "col299": "ikuvn", + "col300": "ijngi", + "col301": "1g0hu", + "col302": "m3nzp", + "col303": "0gwvh", + "col304": "l898v", + "col305": "ng8xm", + "col306": "nkj61", + "col307": "h9ljc", + "col308": "n800p", + "col309": "hs3ey", + "col310": "zsf1w", + "col311": "3yurr", + "col312": "2yvpw", + "col313": "v4hwk", + "col314": "y060p", + "col315": "r9fxu", + "col316": "5an3c", + "col317": "vyyh8", + "col318": "z8dhu", + "col319": "q4xc6", + "col320": "g0rpp", + "col321": "aj0ob", + "col322": "e6fqe", + "col323": "nbn25", + "col324": "2r4f1", + "col325": "5ol1j", + "col326": "3sujn", + "col327": "lk6xz", + "col328": "0m6k6", + "col329": "npuxd", + "col330": "2mspk", + "col331": "dl1pb", + "col332": "6esvf", + "col333": "6sjjc", + "col334": "pfrbx", + "col335": "1r8qd", + "col336": "rdji5", + "col337": "15k3r", + "col338": "lp662", + "col339": "k9wl8", + "col340": "afg6v", + "col341": "1229i", + "col342": "1srq2", + "col343": "6hvhj", + "col344": "ordgu", + "col345": "k58tk", + "col346": "kwk7k", + "col347": "0oi5y", + "col348": "hgxs7", + "col349": "mrwau", + "col350": "44ib9", + "col351": "nloix", + "col352": "ulwyc", + "col353": "pgb5b", + "col354": "zt3xg", + "col355": "4yc92", + "col356": "aj9a6", + "col357": "l1a1n", + "col358": "tee4t", + "col359": "386d4", + "col360": "hbviz", + "col361": "hdffm", + "col362": "27cgq", + "col363": "7uuob", + "col364": "zltjq", + "col365": "wmh7q", + "col366": "3vhkt", + "col367": "8mm96", + "col368": "61eh1", + "col369": "tua6g", + "col370": "rwok0", + "col371": "hzjil", + "col372": "sqwfc", + "col373": "15ywu", + "col374": "qwqcv", + "col375": "hib4v", + "col376": "f8dsx", + "col377": "blznh", + "col378": "t5wbk", + "col379": "61qzd", + "col380": "3mer9", + "col381": "eha3w", + "col382": "34m6b", + "col383": "8wewv", + "col384": "dzz0o", + "col385": "i70o5", + "col386": "o7tmm", + "col387": "yo7fh", + "col388": "15zgz", + "col389": "azvbj", + "col390": "a1mh7", + "col391": "9obcg", + "col392": "ugnxn", + "col393": "ny5d6", + "col394": "knq9h", + "col395": "4vb50", + "col396": "sl2nb", + "col397": "q1j8n", + "col398": "d6k4w", + "col399": "zc155", + "col400": "7i65j", + "col401": "5agfn", + "col402": "d56mi", + "col403": "fxkau", + "col404": "t9xec", + "col405": "5g0rc", + "col406": "qrx72", + "col407": "e4uuk", + "col408": "yen95", + "col409": "nky8v", + "col410": "clq17", + "col411": "5gt2t", + "col412": "z5ss3", + "col413": "gicxg", + "col414": "q39kt", + "col415": "o3z4i", + "col416": "nj3uz", + "col417": "m9m7f", + "col418": "gid0v", + "col419": "7fq7k", + "col420": "rx2i0", + "col421": "exe8r", + "col422": "w0d7k", + "col423": "2zl1z", + "col424": "xn0c2", + "col425": "zcqwd", + "col426": "ziaqt", + "col427": "a26ip", + "col428": "cxx9u", + "col429": "2xj0i", + "col430": "eznv0", + "col431": "we3tw", + "col432": "cqqrn", + "col433": "t3bai", + "col434": "5v3zu", + "col435": "1j6v0", + "col436": "3pzey", + "col437": "wjp6i", + "col438": "69dtv", + "col439": "r3otk", + "col440": "f6m4z", + "col441": "pyboq", + "col442": "ddpks", + "col443": "m1ap5", + "col444": "jwetx", + "col445": "cdaqm", + "col446": "hezs3", + "col447": "ecc35", + "col448": "hk3gh", + "col449": "1pbqq", + "col450": "53bfi", + "col451": "vghqa", + "col452": "p0rvb", + "col453": "1z3c1", + "col454": "xrxc3", + "col455": "jguxf", + "col456": "ifr6h", + "col457": "3ekpb", + "col458": "vhsf9", + "col459": "iylbh", + "col460": "2j7cl", + "col461": "qf7ac", + "col462": "giwac", + "col463": "rm22c", + "col464": "o1uq6", + "col465": "mea7l", + "col466": "jkvod", + "col467": "ay49p", + "col468": "ig7wc", + "col469": "8d7lu", + "col470": "rpdkp", + "col471": "snfkj", + "col472": "yqmfb", + "col473": "xz61u", + "col474": "6xlv0", + "col475": "t76nm", + "col476": "mlt7j", + "col477": "lu2er", + "col478": "0m5ki", + "col479": "emhx8", + "col480": "t8yy3", + "col481": "jqss4", + "col482": "nlxk7", + "col483": "vho1e", + "col484": "cwxp8", + "col485": "sl7pj", + "col486": "lj262", + "col487": "1cepq", + "col488": "13j42", + "col489": "tkv4b", + "col490": "344sk", + "col491": "bnqxr", + "col492": "qnzql", + "col493": "wqdll", + "col494": "gd83p", + "col495": "l1a0l", + "col496": "p4xi4", + "col497": "i3xgj", + "col498": "ue1ji", + "col499": "mf8rw", + "col500": "hl834", + "col501": "8hz69", + "col502": "lztwj", + "col503": "z4oo7", + "col504": "cfaa5", + "col505": "6ism1", + "col506": "81gul", + "col507": "cwynf", + "col508": "io8ba", + "col509": "dp3yn", + "col510": "bl1yr", + "col511": "whrx1", + "col512": "btgdd", + "col513": "un9xt", + "col514": "d76pe", + "col515": "st01i", + "col516": "rcmxk", + "col517": "6kfyg", + "col518": "9srib", + "col519": "41gjy", + "col520": "h5zsa", + "col521": "6ujsw", + "col522": "o7a80", + "col523": "rjr6w", + "col524": "yrmdy", + "col525": "likx0", + "col526": "1m4yh", + "col527": "p6t83", + "col528": "2o1zo", + "col529": "tcgvd", + "col530": "y3d6s", + "col531": "gxvb1", + "col532": "nv2um", + "col533": "o3xro", + "col534": "5cex8", + "col535": "vyzfq", + "col536": "eawmh", + "col537": "ma8mb", + "col538": "13pp1", + "col539": "rsmb2", + "col540": "1qrd6", + "col541": "s811g", + "col542": "6qykh", + "col543": "cz7nh", + "col544": "0kgsb", + "col545": "ek2q9", + "col546": "xnsjt", + "col547": "x6iei", + "col548": "w10s5", + "col549": "kc6pn", + "col550": "n61kq", + "col551": "zf16u", + "col552": "3xtd5", + "col553": "tax5o", + "col554": "zzdnr", + "col555": "4wqn8", + "col556": "n0u8b", + "col557": "bomm5", + "col558": "e9q9c", + "col559": "fglpn", + "col560": "adg0p", + "col561": "wf6hz", + "col562": "0xzri", + "col563": "altaj", + "col564": "st8v4", + "col565": "5l8wo", + "col566": "46wdv", + "col567": "jek2u", + "col568": "hwa5y", + "col569": "hrl64", + "col570": "pbpao", + "col571": "z3f8w", + "col572": "gfm19", + "col573": "8vh1y", + "col574": "tv44s", + "col575": "sbg9k", + "col576": "i34hw", + "col577": "apr9b", + "col578": "v0cpn", + "col579": "5ckc6", + "col580": "vahn6", + "col581": "567xd", + "col582": "0qhw4", + "col583": "orvxy", + "col584": "rinnh", + "col585": "pd4oo", + "col586": "aeu6t", + "col587": "pch71", + "col588": "ay374", + "col589": "7iebd", + "col590": "5x8f7", + "col591": "ukbd2", + "col592": "4hpt0", + "col593": "4tfjl", + "col594": "henh7", + "col595": "llist", + "col596": "bd9ze", + "col597": "erkrt", + "col598": "zumbm", + "col599": "8u3f4", + "col600": "y7j9o", + "col601": "il1s7", + "col602": "3htv1", + "col603": "e6kus", + "col604": "yoj8m", + "col605": "eywk3", + "col606": "3w06b", + "col607": "f6zl8", + "col608": "wpdre", + "col609": "kayzm", + "col610": "0h4p2", + "col611": "x6hsh", + "col612": "hr74y", + "col613": "vf2h6", + "col614": "dakhi", + "col615": "ozjpb", + "col616": "o7tmh", + "col617": "t1cmx", + "col618": "7erjs", + "col619": "pzz1x", + "col620": "7xydl", + "col621": "d7kgm", + "col622": "h9lsj", + "col623": "2rmyt", + "col624": "pip99", + "col625": "rrsj0", + "col626": "vio6u", + "col627": "hugtm", + "col628": "l4ong", + "col629": "t1ogh", + "col630": "83gxg", + "col631": "u0nov", + "col632": "znx03", + "col633": "cr8q9", + "col634": "vgcjt", + "col635": "qdvu4", + "col636": "ninz3", + "col637": "d1z69", + "col638": "ewuv2", + "col639": "0gace", + "col640": "r1em6", + "col641": "b8hd7", + "col642": "p4rra", + "col643": "hzaks", + "col644": "x32rp", + "col645": "vopwh", + "col646": "whp87", + "col647": "arghq", + "col648": "atb2x", + "col649": "ppivu", + "col650": "ogmm3", + "col651": "3ixar", + "col652": "6y4ok", + "col653": "is46i", + "col654": "6xxfk", + "col655": "0jmwa", + "col656": "frk3y", + "col657": "ie34y", + "col658": "5n77l", + "col659": "2xt6q", + "col660": "r1rsd", + "col661": "02524", + "col662": "hhx3x", + "col663": "7xrnc", + "col664": "8f9aa", + "col665": "tpkqa", + "col666": "y1li8", + "col667": "b580t", + "col668": "vw138", + "col669": "rag2f", + "col670": "a47za", + "col671": "31e9c", + "col672": "hiak8", + "col673": "11sjv", + "col674": "zptr5", + "col675": "r9zpp", + "col676": "wbeyd", + "col677": "90eqw", + "col678": "s4g5m", + "col679": "pg5nm", + "col680": "uystj", + "col681": "gvmtn", + "col682": "zpub3", + "col683": "0pkd8", + "col684": "jhcck", + "col685": "29t5o", + "col686": "fp5xz", + "col687": "napnw", + "col688": "gz1c4", + "col689": "r1b5a", + "col690": "e77d2", + "col691": "xfky1", + "col692": "5t88q", + "col693": "b4n7g", + "col694": "2hpcm", + "col695": "ev85x", + "col696": "icdv4", + "col697": "r3jbr", + "col698": "7qq6q", + "col699": "tasmd", + "col700": "g70xl", + "col701": "ruujn", + "col702": "t86hf", + "col703": "ismva", + "col704": "4kf2u", + "col705": "dpng8", + "col706": "uthcy", + "col707": "a3les", + "col708": "gus1y", + "col709": "hqd7u", + "col710": "w9kp9", + "col711": "le83m", + "col712": "9ktgl", + "col713": "kyjje", + "col714": "61r4v", + "col715": "bdf6w", + "col716": "0ao2d", + "col717": "dgx2x", + "col718": "ay30j", + "col719": "hm4qm", + "col720": "gljpy", + "col721": "x6nam", + "col722": "ujvks", + "col723": "n6twk", + "col724": "64q9i", + "col725": "85il5", + "col726": "l1ap6", + "col727": "wvvrd", + "col728": "pqk5v", + "col729": "51n5p", + "col730": "hz6uk", + "col731": "ktqe3", + "col732": "unklt", + "col733": "eqvrn", + "col734": "ny4gl", + "col735": "stoph", + "col736": "j5nyk", + "col737": "7thph", + "col738": "39h8a", + "col739": "ute9w", + "col740": "vi8l9", + "col741": "0g7nq", + "col742": "e3lop", + "col743": "1oa63", + "col744": "en2ir", + "col745": "hky40", + "col746": "4s6uh", + "col747": "fqoa2", + "col748": "uuyda", + "col749": "ie6n3", + "col750": "vkgso", + "col751": "hr446", + "col752": "z7qvx", + "col753": "e26aj", + "col754": "b5yo2", + "col755": "oap1q", + "col756": "h6xpy", + "col757": "la8ye", + "col758": "xx09d", + "col759": "wltpb", + "col760": "r55ud", + "col761": "rr34m", + "col762": "vhddu", + "col763": "kx69p", + "col764": "udx5v", + "col765": "yza8o", + "col766": "fi5ky", + "col767": "n0f26", + "col768": "ur29l", + "col769": "x1ft4", + "col770": "p3pxb", + "col771": "g52lw", + "col772": "pwi1p", + "col773": "2qbu2", + "col774": "jbxh0", + "col775": "rw8j0", + "col776": "cqib0", + "col777": "2u6r9", + "col778": "klswe", + "col779": "cdz39", + "col780": "iyvgq", + "col781": "3rtrw", + "col782": "2ae3z", + "col783": "zcrqi", + "col784": "qrnnv", + "col785": "ob1kv", + "col786": "eovos", + "col787": "ivux0", + "col788": "bmtnk", + "col789": "77tjn", + "col790": "sfqyq", + "col791": "ljos3", + "col792": "vzxe9", + "col793": "f26k6", + "col794": "5v2ec", + "col795": "v412a", + "col796": "z00ze", + "col797": "ymkv8", + "col798": "1k2xk", + "col799": "orzn9", + "col800": "ayc58", + "col801": "otnwc", + "col802": "xr9m3", + "col803": "dkspc", + "col804": "nkx86", + "col805": "oczpp", + "col806": "726zw", + "col807": "0738q", + "col808": "xym1k", + "col809": "hnwpv", + "col810": "ts5eu", + "col811": "9ikp4", + "col812": "k3lh4", + "col813": "gjp10", + "col814": "pgvln", + "col815": "y40u2", + "col816": "umrhw", + "col817": "vdmz7", + "col818": "j6v6f", + "col819": "wa43e", + "col820": "4tfvj", + "col821": "rnyaq", + "col822": "uu2gg", + "col823": "ekk9h", + "col824": "pziiu", + "col825": "yg8er", + "col826": "ti1o6", + "col827": "9i25g", + "col828": "oghpl", + "col829": "ktg1h", + "col830": "zxlkp", + "col831": "96vpp", + "col832": "1349a", + "col833": "ijjos", + "col834": "7h1oh", + "col835": "pejjb", + "col836": "wmolq", + "col837": "vx055", + "col838": "w12rq", + "col839": "36yc4", + "col840": "cqwh6", + "col841": "o8e9p", + "col842": "59j33", + "col843": "ql0vb", + "col844": "nvuog", + "col845": "yt8ek", + "col846": "76pn8", + "col847": "08unv", + "col848": "29451", + "col849": "3ym1y", + "col850": "pkbgd", + "col851": "j1koa", + "col852": "s0onr", + "col853": "5mzdi", + "col854": "pslqa", + "col855": "4w4ca", + "col856": "9k9mu", + "col857": "zunbp", + "col858": "rgnck", + "col859": "q0zym", + "col860": "tum1p", + "col861": "o4ceq", + "col862": "oe0cn", + "col863": "cmd5y", + "col864": "rzmsk", + "col865": "9cc1h", + "col866": "pqjp2", + "col867": "b10uc", + "col868": "4na5w", + "col869": "b31k3", + "col870": "2265u", + "col871": "e9ty2", + "col872": "8j613", + "col873": "ld84r", + "col874": "k4u4z", + "col875": "f4q5c", + "col876": "9t7an", + "col877": "oo6g3", + "col878": "1jyng", + "col879": "5ay99", + "col880": "cxncj", + "col881": "k4uvy", + "col882": "wuqfj", + "col883": "8e9x9", + "col884": "b65b8", + "col885": "f3dba", + "col886": "isenu", + "col887": "gn9yd", + "col888": "ebczd", + "col889": "10z6f", + "col890": "0ukod", + "col891": "3dk43", + "col892": "yle8t", + "col893": "sfvq4", + "col894": "7d9jc", + "col895": "lhbgh", + "col896": "emgle", + "col897": "ne10n", + "col898": "yga9t", + "col899": "mw31y", + "col900": "va22r", + "col901": "dmq9d", + "col902": "b4nle", + "col903": "s4hog", + "col904": "p663k", + "col905": "wxhf7", + "col906": "eg7n4", + "col907": "6r9db", + "col908": "0na9w", + "col909": "y65y4", + "col910": "hqoeg", + "col911": "slo60", + "col912": "4906h", + "col913": "x9kmw", + "col914": "y685o", + "col915": "sh58f", + "col916": "rmh2g", + "col917": "747fn", + "col918": "3j78o", + "col919": "3npsj", + "col920": "n8vr4", + "col921": "62sju", + "col922": "wh6ix", + "col923": "znsfk", + "col924": "z95v1", + "col925": "lrjos", + "col926": "ze89j", + "col927": "al7l8", + "col928": "so0in", + "col929": "4l3wr", + "col930": "ud7wv", + "col931": "5m97e", + "col932": "50o2f", + "col933": "yk53a", + "col934": "2n0pr", + "col935": "lj4o5", + "col936": "j7cvx", + "col937": "awt92", + "col938": "9qw60", + "col939": "sozcv", + "col940": "potdo", + "col941": "0hjf1", + "col942": "th1hy", + "col943": "fkasf", + "col944": "s1tfk", + "col945": "5tzrm", + "col946": "rojcs", + "col947": "ptc48", + "col948": "4v7bt", + "col949": "vrccd", + "col950": "rmsct", + "col951": "m4jf5", + "col952": "tz4dp", + "col953": "l1a2d", + "col954": "6cjeh", + "col955": "cfd2s", + "col956": "55n6g", + "col957": "7fupg", + "col958": "qe50t", + "col959": "2fzxt", + "col960": "prrie", + "col961": "9efwz", + "col962": "gn2b8", + "col963": "9a8p7", + "col964": "7ln0r", + "col965": "bk63c", + "col966": "w1kp4", + "col967": "heg84", + "col968": "fv9pi", + "col969": "s4ue4", + "col970": "x24n9", + "col971": "qlkfr", + "col972": "pk49x", + "col973": "ryj16", + "col974": "eakv5", + "col975": "r5bvb", + "col976": "a052p", + "col977": "urpyf", + "col978": "j38or", + "col979": "7rlms", + "col980": "lnzyx", + "col981": "shc4d", + "col982": "gihp1", + "col983": "4x9p0", + "col984": "5mohm", + "col985": "fas5l", + "col986": "behbf", + "col987": "4wt0c", + "col988": "08txv", + "col989": "z3wxx", + "col990": "kxirs", + "col991": "tkevb", + "col992": "m8z6d", + "col993": "kzk90", + "col994": "zxoyv", + "col995": "8ddi8", + "col996": "kt26d", + "col997": "d7dux", + "col998": "sh5p8", + "col999": "oacvy" + }, + { + "name": "Maxwell Horton", + "gender": "male", + "col0": "itxvq", + "col1": "f5xl7", + "col2": "wbuii", + "col3": "cz07g", + "col4": "b68ex", + "col5": "232pa", + "col6": "814t2", + "col7": "xl3ex", + "col8": "o79m2", + "col9": "exg84", + "col10": "p34c0", + "col11": "8v5oz", + "col12": "s80q2", + "col13": "onqjd", + "col14": "wu8cy", + "col15": "t5emd", + "col16": "5hwov", + "col17": "ndj40", + "col18": "1zhwo", + "col19": "kktyw", + "col20": "ob0vj", + "col21": "2xgus", + "col22": "1glxc", + "col23": "zw7yi", + "col24": "l5orn", + "col25": "tg98t", + "col26": "cfxnn", + "col27": "zmvvm", + "col28": "idcy4", + "col29": "kqg7m", + "col30": "5ggcj", + "col31": "vqepm", + "col32": "ow92s", + "col33": "cg372", + "col34": "rlyit", + "col35": "onekd", + "col36": "thbli", + "col37": "afhtp", + "col38": "spvcp", + "col39": "omnt5", + "col40": "uy0dd", + "col41": "v7wch", + "col42": "gtu0d", + "col43": "9t97g", + "col44": "ie1xa", + "col45": "jwqad", + "col46": "cwave", + "col47": "4pbfa", + "col48": "ewdct", + "col49": "p56zd", + "col50": "lblbl", + "col51": "emd1p", + "col52": "e6avj", + "col53": "cs7pq", + "col54": "fteut", + "col55": "5w3ul", + "col56": "loe5f", + "col57": "hqa3a", + "col58": "yh8rc", + "col59": "wlys2", + "col60": "jobw2", + "col61": "yuwmb", + "col62": "8mnsw", + "col63": "4n0op", + "col64": "vgbg4", + "col65": "rhzsb", + "col66": "zwphu", + "col67": "4rxr6", + "col68": "jaxi8", + "col69": "m6p8a", + "col70": "ptyfb", + "col71": "flgrq", + "col72": "oto5o", + "col73": "gm6ti", + "col74": "y1hsg", + "col75": "j9nb6", + "col76": "0syvz", + "col77": "2gtd3", + "col78": "2bz02", + "col79": "xgfvv", + "col80": "c5qzz", + "col81": "2t58p", + "col82": "sg6bi", + "col83": "52lil", + "col84": "mi5c5", + "col85": "mm0vc", + "col86": "ow4yj", + "col87": "o6r7a", + "col88": "thje2", + "col89": "2oeu9", + "col90": "08q3t", + "col91": "pbghy", + "col92": "nn70q", + "col93": "jxfbx", + "col94": "vn6ir", + "col95": "ht61l", + "col96": "lqj4a", + "col97": "hldp9", + "col98": "4285c", + "col99": "hbdv0", + "col100": "xpxok", + "col101": "hxwqy", + "col102": "9bdhf", + "col103": "94nob", + "col104": "wcqdj", + "col105": "50q9d", + "col106": "v3wy5", + "col107": "ajhwt", + "col108": "fomf1", + "col109": "o5gr7", + "col110": "1j1l8", + "col111": "lgon7", + "col112": "kt2ps", + "col113": "3fujd", + "col114": "ljnn6", + "col115": "ezmo0", + "col116": "1kzje", + "col117": "kk9hw", + "col118": "yik51", + "col119": "jewfj", + "col120": "bz208", + "col121": "q5yw9", + "col122": "j3ih4", + "col123": "sz0na", + "col124": "rz1b0", + "col125": "j7h2w", + "col126": "yf7wn", + "col127": "jovqx", + "col128": "pwq41", + "col129": "tl4eo", + "col130": "1jhq9", + "col131": "hrrbz", + "col132": "33rpx", + "col133": "56gg7", + "col134": "rwtuf", + "col135": "lx6s4", + "col136": "mh6yg", + "col137": "iis3k", + "col138": "afw4r", + "col139": "lbkzj", + "col140": "d12zi", + "col141": "75jdj", + "col142": "dy7ze", + "col143": "1rs66", + "col144": "trvu4", + "col145": "dkqr6", + "col146": "ozaiw", + "col147": "mqxuj", + "col148": "7gu5k", + "col149": "i9xqg", + "col150": "lxi43", + "col151": "ziw6y", + "col152": "yi57p", + "col153": "16xhf", + "col154": "jqhne", + "col155": "3c0bb", + "col156": "20mc7", + "col157": "64bnz", + "col158": "ezjf0", + "col159": "91z3y", + "col160": "aunpu", + "col161": "2um9l", + "col162": "cd1jg", + "col163": "xp7tc", + "col164": "p8onn", + "col165": "kslxu", + "col166": "d2w9x", + "col167": "mxxhb", + "col168": "gxn34", + "col169": "3a74b", + "col170": "3qf6a", + "col171": "fa05u", + "col172": "hwyo6", + "col173": "dthld", + "col174": "4cvbr", + "col175": "txtga", + "col176": "0q701", + "col177": "k3g16", + "col178": "dbnlr", + "col179": "fguvd", + "col180": "rkxv4", + "col181": "f292c", + "col182": "opi26", + "col183": "4yguc", + "col184": "e3lpu", + "col185": "vehct", + "col186": "45tt6", + "col187": "h1ffz", + "col188": "ero8f", + "col189": "alntp", + "col190": "qvgao", + "col191": "4sbr4", + "col192": "ri0r4", + "col193": "wmhag", + "col194": "u33mr", + "col195": "73jf5", + "col196": "2v46a", + "col197": "hs908", + "col198": "mhohc", + "col199": "m72k4", + "col200": "twoeh", + "col201": "uhyny", + "col202": "82ppy", + "col203": "bi46p", + "col204": "oqcfi", + "col205": "3l0rs", + "col206": "byjxo", + "col207": "kathl", + "col208": "lisb2", + "col209": "zzx5g", + "col210": "6p6ce", + "col211": "e9l0i", + "col212": "nc4h0", + "col213": "e9mf9", + "col214": "uhhsc", + "col215": "et6mx", + "col216": "l7p1c", + "col217": "ebjdx", + "col218": "32mx8", + "col219": "s597b", + "col220": "nexel", + "col221": "gwdtg", + "col222": "bigtg", + "col223": "jh0y4", + "col224": "749qg", + "col225": "8sfhz", + "col226": "qyik7", + "col227": "n0uu7", + "col228": "aautf", + "col229": "n4h5d", + "col230": "gl59a", + "col231": "vj8m6", + "col232": "pcjlm", + "col233": "0wu1d", + "col234": "hi8al", + "col235": "6ce8z", + "col236": "ao48h", + "col237": "bpeb2", + "col238": "dtnhq", + "col239": "bskkf", + "col240": "zuvxx", + "col241": "zimda", + "col242": "j9w5x", + "col243": "g6e0n", + "col244": "ruuoj", + "col245": "qpnq6", + "col246": "ix5q0", + "col247": "g20bf", + "col248": "ld0fm", + "col249": "mbqq1", + "col250": "cfyfa", + "col251": "f7olr", + "col252": "le0eh", + "col253": "92fty", + "col254": "bkuf3", + "col255": "16pt2", + "col256": "kyttw", + "col257": "2qu51", + "col258": "qxlgk", + "col259": "z4sxb", + "col260": "71otq", + "col261": "ltqw4", + "col262": "koy7p", + "col263": "734el", + "col264": "2y1os", + "col265": "cario", + "col266": "ve8fe", + "col267": "18vcj", + "col268": "73wrd", + "col269": "i322p", + "col270": "2ah24", + "col271": "mju9u", + "col272": "04shs", + "col273": "qs1o2", + "col274": "ydbdp", + "col275": "p61hn", + "col276": "0eo4o", + "col277": "dv705", + "col278": "tp280", + "col279": "gjmpc", + "col280": "dyecy", + "col281": "ec0vv", + "col282": "fwyzo", + "col283": "d3mef", + "col284": "70hko", + "col285": "kek1q", + "col286": "z7zpx", + "col287": "3sqo1", + "col288": "zollh", + "col289": "jcl67", + "col290": "ndsnz", + "col291": "4vvtj", + "col292": "4u1d5", + "col293": "h8bpo", + "col294": "g272g", + "col295": "d9jwn", + "col296": "1vp8q", + "col297": "lzek3", + "col298": "7ifx0", + "col299": "t2p9e", + "col300": "r9yno", + "col301": "hx24x", + "col302": "5e27a", + "col303": "yi6bk", + "col304": "acseq", + "col305": "myk9p", + "col306": "qsnpg", + "col307": "xsf31", + "col308": "ucj8k", + "col309": "7dv52", + "col310": "gphl5", + "col311": "5xuzr", + "col312": "fa1md", + "col313": "5zc7s", + "col314": "8brqy", + "col315": "ow9vy", + "col316": "nhgg9", + "col317": "1fp1x", + "col318": "eekjh", + "col319": "lbkkl", + "col320": "e4vz8", + "col321": "6x7x6", + "col322": "afxdx", + "col323": "76iec", + "col324": "nnopr", + "col325": "itvuu", + "col326": "chbki", + "col327": "7s4bm", + "col328": "7uxk3", + "col329": "uel7l", + "col330": "f4ni0", + "col331": "g1wc6", + "col332": "yl5r1", + "col333": "m16iv", + "col334": "u23fp", + "col335": "ba4n9", + "col336": "54y1u", + "col337": "3968d", + "col338": "kzt95", + "col339": "onomk", + "col340": "qoaz5", + "col341": "gykmm", + "col342": "lic0p", + "col343": "mpikh", + "col344": "ep0zy", + "col345": "bomtf", + "col346": "lzh7r", + "col347": "gwlg7", + "col348": "l23a2", + "col349": "saah0", + "col350": "ue29t", + "col351": "7p16f", + "col352": "0v4m7", + "col353": "pw694", + "col354": "nr859", + "col355": "88oxf", + "col356": "12ifj", + "col357": "04nwu", + "col358": "bmdf1", + "col359": "s538w", + "col360": "fus4c", + "col361": "onnw1", + "col362": "za1fy", + "col363": "nc28p", + "col364": "xjfra", + "col365": "ibp3c", + "col366": "a08cf", + "col367": "ty8gq", + "col368": "xyl9g", + "col369": "uz7ba", + "col370": "j27ii", + "col371": "pv618", + "col372": "cifut", + "col373": "ky35z", + "col374": "vdn74", + "col375": "mdmaz", + "col376": "a897g", + "col377": "hfbrp", + "col378": "ef9px", + "col379": "r4v8s", + "col380": "a8b1q", + "col381": "vatgx", + "col382": "0jumj", + "col383": "9wy21", + "col384": "tstbu", + "col385": "jm7df", + "col386": "gl9zg", + "col387": "2uua9", + "col388": "qeygt", + "col389": "k33w4", + "col390": "yv6i4", + "col391": "q7qba", + "col392": "r89d5", + "col393": "mwgix", + "col394": "wg931", + "col395": "qjlg0", + "col396": "q8u4f", + "col397": "nkbvn", + "col398": "4q4uv", + "col399": "7gcqk", + "col400": "eb61a", + "col401": "bz3is", + "col402": "nvgro", + "col403": "chulw", + "col404": "x818o", + "col405": "c1n91", + "col406": "0eim0", + "col407": "wvxan", + "col408": "y69j1", + "col409": "dbb8t", + "col410": "b6rlr", + "col411": "r32ns", + "col412": "qvpnd", + "col413": "quo9m", + "col414": "wag83", + "col415": "v30wo", + "col416": "qx5lu", + "col417": "pnsbq", + "col418": "pkaog", + "col419": "hkby4", + "col420": "x7hft", + "col421": "ufw2r", + "col422": "bl6as", + "col423": "7tmjv", + "col424": "gzc4k", + "col425": "3bpn5", + "col426": "alxxx", + "col427": "xmli8", + "col428": "1o4sj", + "col429": "wq71j", + "col430": "jj1q2", + "col431": "0ehdd", + "col432": "eweq4", + "col433": "vh1zz", + "col434": "vprm3", + "col435": "1gcr2", + "col436": "be8r6", + "col437": "wzs4o", + "col438": "4jlcv", + "col439": "pkxw2", + "col440": "lfh7t", + "col441": "4mrws", + "col442": "505sf", + "col443": "msppd", + "col444": "ipc19", + "col445": "kzt13", + "col446": "dwpbw", + "col447": "yrpy1", + "col448": "vwegr", + "col449": "3kn2c", + "col450": "38rhs", + "col451": "i8lvh", + "col452": "69nu4", + "col453": "tofm5", + "col454": "r9bjg", + "col455": "zxr81", + "col456": "1q2av", + "col457": "927xw", + "col458": "164sh", + "col459": "r7o5l", + "col460": "7t0m1", + "col461": "5p61l", + "col462": "dbkq2", + "col463": "i7k7i", + "col464": "uhwsa", + "col465": "fpv0t", + "col466": "z16k6", + "col467": "gfymz", + "col468": "20859", + "col469": "rj2ci", + "col470": "sv1s3", + "col471": "5ax4e", + "col472": "sy159", + "col473": "xrrek", + "col474": "v8e06", + "col475": "e1r9n", + "col476": "cr5jg", + "col477": "irme8", + "col478": "c4n1z", + "col479": "k4tpg", + "col480": "p3mqv", + "col481": "8e3lt", + "col482": "j53wr", + "col483": "6k34l", + "col484": "wsmgu", + "col485": "nzu86", + "col486": "74sto", + "col487": "y34nn", + "col488": "978tr", + "col489": "yqo72", + "col490": "k5oa4", + "col491": "52az3", + "col492": "nnxcy", + "col493": "zpn7w", + "col494": "7pro8", + "col495": "ns28w", + "col496": "ctwa3", + "col497": "xnqfg", + "col498": "nj33g", + "col499": "cdrus", + "col500": "jvnlb", + "col501": "6oi3r", + "col502": "8eyod", + "col503": "mskms", + "col504": "2yh11", + "col505": "izx86", + "col506": "y5nc5", + "col507": "8uxiu", + "col508": "0qff0", + "col509": "o5rdy", + "col510": "dynic", + "col511": "gcyvh", + "col512": "uycv3", + "col513": "oknhj", + "col514": "0o5ii", + "col515": "xqlwo", + "col516": "c5b58", + "col517": "t1ik2", + "col518": "us2m6", + "col519": "95iyu", + "col520": "ufg97", + "col521": "cllym", + "col522": "gn1q3", + "col523": "k7qom", + "col524": "fuvgh", + "col525": "foz0d", + "col526": "m5uvr", + "col527": "v3chx", + "col528": "eqjm7", + "col529": "kvska", + "col530": "67ov8", + "col531": "sreji", + "col532": "yguwi", + "col533": "pu71w", + "col534": "qgcw3", + "col535": "bn3v8", + "col536": "ybshr", + "col537": "cfyes", + "col538": "l2i8l", + "col539": "gtasy", + "col540": "8wqmt", + "col541": "5y1g4", + "col542": "x2zxe", + "col543": "lo86a", + "col544": "hvno5", + "col545": "l6xs8", + "col546": "19ung", + "col547": "x4ki2", + "col548": "lcdl1", + "col549": "1eqw0", + "col550": "uzbis", + "col551": "0q0hu", + "col552": "phzrx", + "col553": "dasxg", + "col554": "ursjt", + "col555": "o5ray", + "col556": "hbglv", + "col557": "4yprc", + "col558": "q4sz4", + "col559": "ec5jr", + "col560": "mlfb3", + "col561": "fdcuq", + "col562": "u1pau", + "col563": "73qkd", + "col564": "htap5", + "col565": "s7r0p", + "col566": "c6z9p", + "col567": "j7lcq", + "col568": "meeys", + "col569": "1frsq", + "col570": "87pcz", + "col571": "1zf07", + "col572": "epk3l", + "col573": "6hjs9", + "col574": "jaauz", + "col575": "2vijv", + "col576": "jcmwi", + "col577": "nekov", + "col578": "xufsm", + "col579": "wp50u", + "col580": "dx5tq", + "col581": "1ub6z", + "col582": "b23qw", + "col583": "uzzxh", + "col584": "ankn0", + "col585": "7yiiw", + "col586": "c0t26", + "col587": "5f16z", + "col588": "kpdsj", + "col589": "revx4", + "col590": "wlo9k", + "col591": "b5294", + "col592": "4r4t9", + "col593": "zd4cu", + "col594": "znse2", + "col595": "ihrz3", + "col596": "672e1", + "col597": "5spnc", + "col598": "s1okr", + "col599": "i9ff3", + "col600": "sq85a", + "col601": "9xbi3", + "col602": "evps7", + "col603": "gujdp", + "col604": "1ldmi", + "col605": "zy19y", + "col606": "g6sfv", + "col607": "h9c56", + "col608": "omzre", + "col609": "o9yc8", + "col610": "m3muz", + "col611": "lw55m", + "col612": "xvona", + "col613": "5qoe5", + "col614": "4001c", + "col615": "o87pz", + "col616": "4k8ay", + "col617": "1won2", + "col618": "1ijn0", + "col619": "3rv8k", + "col620": "mik3v", + "col621": "m26r8", + "col622": "c11qy", + "col623": "48in4", + "col624": "h5llp", + "col625": "g9fk8", + "col626": "wldyu", + "col627": "6hhvi", + "col628": "cldtp", + "col629": "ckhyo", + "col630": "uksin", + "col631": "3n7id", + "col632": "brq0p", + "col633": "5spuh", + "col634": "doby7", + "col635": "rkzmg", + "col636": "l81s0", + "col637": "8irpw", + "col638": "7kk5b", + "col639": "1saek", + "col640": "qxoub", + "col641": "fkceu", + "col642": "dxerh", + "col643": "do01g", + "col644": "fr9gc", + "col645": "fhgb9", + "col646": "7wcqf", + "col647": "p8664", + "col648": "9n3ba", + "col649": "qvc8u", + "col650": "jo4iz", + "col651": "xcooy", + "col652": "zek15", + "col653": "cut1q", + "col654": "n3s0h", + "col655": "fxzmj", + "col656": "3e5jb", + "col657": "awvbi", + "col658": "ojon9", + "col659": "27uhv", + "col660": "nur0h", + "col661": "vvflq", + "col662": "slwuv", + "col663": "83ewe", + "col664": "rdzmp", + "col665": "crorq", + "col666": "xz3qg", + "col667": "97br8", + "col668": "5dat2", + "col669": "84u91", + "col670": "119rw", + "col671": "t54u2", + "col672": "v308q", + "col673": "vxgpq", + "col674": "22hz7", + "col675": "vo4cw", + "col676": "t5awx", + "col677": "yie09", + "col678": "qx6x2", + "col679": "aovif", + "col680": "qbsmp", + "col681": "xqhi8", + "col682": "xl0fs", + "col683": "c5toq", + "col684": "h17wb", + "col685": "el1dl", + "col686": "yhsqq", + "col687": "h9dx1", + "col688": "3s32p", + "col689": "tbjqn", + "col690": "81qx4", + "col691": "9wv5z", + "col692": "4acm6", + "col693": "e2g6e", + "col694": "6lhf8", + "col695": "84m82", + "col696": "ljqm6", + "col697": "7wfcx", + "col698": "034c0", + "col699": "1n6r1", + "col700": "66vzc", + "col701": "qae42", + "col702": "bc3tn", + "col703": "ewpv7", + "col704": "cm69z", + "col705": "cw6u1", + "col706": "lyyiv", + "col707": "5r7v9", + "col708": "x3yus", + "col709": "bz2wg", + "col710": "whsk4", + "col711": "gy066", + "col712": "94ube", + "col713": "gtisq", + "col714": "s2l1c", + "col715": "k34x7", + "col716": "zbsn4", + "col717": "ae6p5", + "col718": "8c2qr", + "col719": "wotux", + "col720": "zdg25", + "col721": "84l4y", + "col722": "9hv8n", + "col723": "a74ck", + "col724": "co1wn", + "col725": "ustio", + "col726": "kzzny", + "col727": "zmc6p", + "col728": "1qmca", + "col729": "h31kh", + "col730": "45tsa", + "col731": "vhd6p", + "col732": "eccg3", + "col733": "iyy8y", + "col734": "q17zc", + "col735": "3xnui", + "col736": "9zmly", + "col737": "wvt1t", + "col738": "02n1i", + "col739": "kko5m", + "col740": "ag9s0", + "col741": "j70pn", + "col742": "jou7m", + "col743": "qoj7n", + "col744": "x1m71", + "col745": "1aec2", + "col746": "vzvcu", + "col747": "csfp8", + "col748": "kovas", + "col749": "pid6d", + "col750": "eixp2", + "col751": "qwi3b", + "col752": "qchng", + "col753": "q72zx", + "col754": "gqqa3", + "col755": "qjczf", + "col756": "jg751", + "col757": "0s5ac", + "col758": "7x3fe", + "col759": "ozqh3", + "col760": "7kesd", + "col761": "vkecw", + "col762": "s5cad", + "col763": "aewqx", + "col764": "p96k1", + "col765": "o5fl7", + "col766": "52dmz", + "col767": "lee5t", + "col768": "gybn4", + "col769": "1p6k4", + "col770": "6nrqd", + "col771": "mxpr6", + "col772": "q58h7", + "col773": "0q2d7", + "col774": "pska6", + "col775": "4e3an", + "col776": "a4f1c", + "col777": "j55d0", + "col778": "m3igl", + "col779": "zm0gt", + "col780": "syyyy", + "col781": "2grcn", + "col782": "lyjtj", + "col783": "0j20j", + "col784": "mqw64", + "col785": "91pbz", + "col786": "izv53", + "col787": "nb3sy", + "col788": "q3joj", + "col789": "lnwke", + "col790": "9d7s6", + "col791": "v4dx5", + "col792": "o3yhg", + "col793": "ew90o", + "col794": "3tj84", + "col795": "7x3tk", + "col796": "cfay6", + "col797": "1g003", + "col798": "wxva1", + "col799": "cnws1", + "col800": "18kvi", + "col801": "irt7c", + "col802": "w9w1x", + "col803": "zs0w4", + "col804": "qmuwv", + "col805": "hci8y", + "col806": "2o4jk", + "col807": "ns6iu", + "col808": "9oqtc", + "col809": "i6er8", + "col810": "ia4ea", + "col811": "28iq2", + "col812": "3dzqt", + "col813": "yshg2", + "col814": "qy23t", + "col815": "2uxii", + "col816": "4zbgq", + "col817": "cn85z", + "col818": "3rhmv", + "col819": "3zwfp", + "col820": "w2m7o", + "col821": "tvgcf", + "col822": "mx0xg", + "col823": "huhey", + "col824": "cuh01", + "col825": "rkhpx", + "col826": "c0fgm", + "col827": "g3dr3", + "col828": "r5xvd", + "col829": "7plmj", + "col830": "al4xs", + "col831": "qu0t6", + "col832": "ags9t", + "col833": "wfen6", + "col834": "ifuzk", + "col835": "r3cxt", + "col836": "6zv9i", + "col837": "3naf7", + "col838": "5yuqv", + "col839": "m2epa", + "col840": "mdjrd", + "col841": "03qmi", + "col842": "qc5pf", + "col843": "zm34o", + "col844": "lraz5", + "col845": "qf5ol", + "col846": "bug9b", + "col847": "fxhbj", + "col848": "8u8mz", + "col849": "je1il", + "col850": "v5n5i", + "col851": "ntmf4", + "col852": "aaxmi", + "col853": "jywu9", + "col854": "8tma1", + "col855": "9w9k9", + "col856": "2a1sq", + "col857": "5eiee", + "col858": "jwxfv", + "col859": "lq92w", + "col860": "433sl", + "col861": "s4jij", + "col862": "hblx1", + "col863": "f8myk", + "col864": "32dqh", + "col865": "dfwy1", + "col866": "8tgb5", + "col867": "vmhc0", + "col868": "dcvo7", + "col869": "1exro", + "col870": "62n3e", + "col871": "eplr2", + "col872": "p6zk2", + "col873": "17exl", + "col874": "g309k", + "col875": "jbn3u", + "col876": "6mckl", + "col877": "p4yu6", + "col878": "o4lr2", + "col879": "hyl5u", + "col880": "sxw53", + "col881": "szzd5", + "col882": "slni6", + "col883": "0qbcp", + "col884": "0f4ef", + "col885": "qxqd7", + "col886": "6sd0t", + "col887": "ipixy", + "col888": "lgcy3", + "col889": "ox593", + "col890": "idbmo", + "col891": "v5u2b", + "col892": "yck0y", + "col893": "xfh2u", + "col894": "ouewh", + "col895": "uh1e2", + "col896": "uhwj8", + "col897": "gmmzh", + "col898": "zfk7j", + "col899": "q5gsw", + "col900": "wl29e", + "col901": "3jnjf", + "col902": "akhth", + "col903": "2i7l7", + "col904": "ylfv4", + "col905": "3vk7z", + "col906": "pvjeq", + "col907": "8ygmw", + "col908": "v5wse", + "col909": "oyxdp", + "col910": "9eqtm", + "col911": "fgc94", + "col912": "sezcp", + "col913": "dbfk7", + "col914": "acsqn", + "col915": "ejk66", + "col916": "xaqnm", + "col917": "er6k7", + "col918": "5adwj", + "col919": "nk8jh", + "col920": "85biz", + "col921": "si1q6", + "col922": "lmku0", + "col923": "t1jtr", + "col924": "zxlob", + "col925": "reqth", + "col926": "iibv0", + "col927": "4h6gx", + "col928": "7j6eu", + "col929": "23imw", + "col930": "ua1a5", + "col931": "jrlgi", + "col932": "5y7hl", + "col933": "jbgli", + "col934": "iy2jp", + "col935": "v6gvj", + "col936": "lofum", + "col937": "9q2vu", + "col938": "g5elb", + "col939": "6d9pi", + "col940": "z079v", + "col941": "51pex", + "col942": "w8or7", + "col943": "qmu1d", + "col944": "8u1xn", + "col945": "mgvx8", + "col946": "3aeiu", + "col947": "05upw", + "col948": "xh96l", + "col949": "npxwy", + "col950": "axfiy", + "col951": "fqony", + "col952": "p1nb8", + "col953": "9rbre", + "col954": "jwawf", + "col955": "0n76v", + "col956": "g4asx", + "col957": "nm4bz", + "col958": "cth94", + "col959": "acmif", + "col960": "131ub", + "col961": "klpix", + "col962": "inkmz", + "col963": "oirmm", + "col964": "n6xx8", + "col965": "soaqu", + "col966": "m70s6", + "col967": "hfzd7", + "col968": "wj4cw", + "col969": "4hglk", + "col970": "ldugz", + "col971": "nqko6", + "col972": "zqqi3", + "col973": "1dec6", + "col974": "agzhf", + "col975": "p8e9z", + "col976": "2qfmu", + "col977": "oxokx", + "col978": "tnp3x", + "col979": "8iupu", + "col980": "z0ljx", + "col981": "durvh", + "col982": "yil9m", + "col983": "mk8r5", + "col984": "mcd8r", + "col985": "ned47", + "col986": "yrw0v", + "col987": "gvwv8", + "col988": "apyzl", + "col989": "4m9ve", + "col990": "o0r3o", + "col991": "iyxkc", + "col992": "g6ngg", + "col993": "br50h", + "col994": "w5y5r", + "col995": "yrdpn", + "col996": "cuxvq", + "col997": "xqfxo", + "col998": "c9hds", + "col999": "uikrm" + }, + { + "name": "Lamb Atkinson", + "gender": "male", + "col0": "layqk", + "col1": "geivc", + "col2": "gesax", + "col3": "wiif4", + "col4": "r2dkd", + "col5": "0ho73", + "col6": "znd92", + "col7": "8ymh9", + "col8": "w5hq9", + "col9": "d87v7", + "col10": "q8msy", + "col11": "1ifhm", + "col12": "gfzyu", + "col13": "57g4q", + "col14": "lzk4q", + "col15": "1oneg", + "col16": "wknh6", + "col17": "oim9l", + "col18": "xtukx", + "col19": "cckqv", + "col20": "rh0ql", + "col21": "1ptdy", + "col22": "btd3q", + "col23": "pfxkb", + "col24": "bgh2r", + "col25": "vz5ee", + "col26": "brdy2", + "col27": "s2qbz", + "col28": "ogw3p", + "col29": "t6nwm", + "col30": "g098n", + "col31": "4woqo", + "col32": "4wodf", + "col33": "0654l", + "col34": "9iidb", + "col35": "rrn6c", + "col36": "nrsy2", + "col37": "ed62z", + "col38": "iy92h", + "col39": "4lw34", + "col40": "x5y4k", + "col41": "4wsm9", + "col42": "ysa6r", + "col43": "1i3go", + "col44": "d4nl4", + "col45": "xi0xw", + "col46": "v79lf", + "col47": "7sdxv", + "col48": "4l4lm", + "col49": "642fa", + "col50": "fsr5m", + "col51": "f80ic", + "col52": "qdpb3", + "col53": "kq7si", + "col54": "csxh7", + "col55": "3y0sc", + "col56": "ke6h3", + "col57": "q5sab", + "col58": "o1tnq", + "col59": "lzpre", + "col60": "zbdfc", + "col61": "g4ugd", + "col62": "xv5ks", + "col63": "tim7n", + "col64": "uv327", + "col65": "fhc2a", + "col66": "ysfgr", + "col67": "rt362", + "col68": "kzeg9", + "col69": "5qcj8", + "col70": "porvf", + "col71": "wlf5d", + "col72": "6lr6q", + "col73": "kq78a", + "col74": "x91zn", + "col75": "orqqq", + "col76": "usjsy", + "col77": "rui6m", + "col78": "2i72n", + "col79": "axvcb", + "col80": "yq78h", + "col81": "ftbnm", + "col82": "qakzd", + "col83": "tum6c", + "col84": "u30gy", + "col85": "827a1", + "col86": "uvnyr", + "col87": "hlwpy", + "col88": "c7njq", + "col89": "a2zf7", + "col90": "r0cie", + "col91": "zc6w5", + "col92": "9mg1o", + "col93": "gk3cn", + "col94": "cbk8w", + "col95": "26s03", + "col96": "pxtkn", + "col97": "pvh53", + "col98": "vwgbo", + "col99": "b4oo7", + "col100": "tubrz", + "col101": "ycip0", + "col102": "ivh0c", + "col103": "dxbtf", + "col104": "2ws4s", + "col105": "6dqiw", + "col106": "7o74b", + "col107": "73jee", + "col108": "o7teh", + "col109": "poxad", + "col110": "ngrbv", + "col111": "q9hoz", + "col112": "gj8na", + "col113": "i7kh2", + "col114": "qdhe2", + "col115": "z2m22", + "col116": "jm7mq", + "col117": "aj8wd", + "col118": "0100j", + "col119": "3bx70", + "col120": "t8m7o", + "col121": "3dbg7", + "col122": "u23i3", + "col123": "gzda1", + "col124": "c17bj", + "col125": "ineh9", + "col126": "6aw8m", + "col127": "o7a0v", + "col128": "ovxxp", + "col129": "8su1f", + "col130": "j6cv6", + "col131": "6yudf", + "col132": "r0ehk", + "col133": "nkbli", + "col134": "9yg0j", + "col135": "on8h1", + "col136": "3pmih", + "col137": "n99pf", + "col138": "oc1hc", + "col139": "5phsm", + "col140": "625ot", + "col141": "by7am", + "col142": "csbgf", + "col143": "1s54h", + "col144": "z5a7u", + "col145": "4v2pm", + "col146": "v2uwy", + "col147": "8go73", + "col148": "690lp", + "col149": "nuz8e", + "col150": "ue425", + "col151": "i4z9q", + "col152": "7xea0", + "col153": "7xblh", + "col154": "q0tfr", + "col155": "im265", + "col156": "bn5e2", + "col157": "nqt0z", + "col158": "zfv2d", + "col159": "m5gqq", + "col160": "cgvly", + "col161": "beno3", + "col162": "exjyp", + "col163": "erhxb", + "col164": "wp14x", + "col165": "ueslb", + "col166": "9etyr", + "col167": "8kosc", + "col168": "btdk3", + "col169": "bfghr", + "col170": "rs7jz", + "col171": "red8z", + "col172": "nygga", + "col173": "qdafb", + "col174": "sdfh3", + "col175": "ad839", + "col176": "xlvm3", + "col177": "v87wu", + "col178": "j4747", + "col179": "gokv3", + "col180": "cyuce", + "col181": "2nsta", + "col182": "8gxig", + "col183": "ib3q1", + "col184": "se87b", + "col185": "dmjp8", + "col186": "x05np", + "col187": "0tntz", + "col188": "7njch", + "col189": "8cdnw", + "col190": "1mglc", + "col191": "d0vvl", + "col192": "1r6kf", + "col193": "vfwej", + "col194": "aylhj", + "col195": "t3hxp", + "col196": "g6ewg", + "col197": "s32z0", + "col198": "0eygv", + "col199": "g870h", + "col200": "kyvll", + "col201": "titk2", + "col202": "8qkjx", + "col203": "27mxc", + "col204": "ok5bo", + "col205": "it5i9", + "col206": "er5n7", + "col207": "74woj", + "col208": "9p3mv", + "col209": "gq193", + "col210": "d1xfg", + "col211": "8010b", + "col212": "1zlw1", + "col213": "wzmy0", + "col214": "tmbvt", + "col215": "76ver", + "col216": "x27sf", + "col217": "yy25c", + "col218": "3ejbn", + "col219": "q2545", + "col220": "5vgxc", + "col221": "gf7xm", + "col222": "5xq8g", + "col223": "gxndh", + "col224": "3k6t4", + "col225": "mpoj2", + "col226": "ujg18", + "col227": "vd5jb", + "col228": "560xt", + "col229": "5vbia", + "col230": "s9amx", + "col231": "cci6p", + "col232": "lrp9t", + "col233": "9peuu", + "col234": "8xmbv", + "col235": "ykcrc", + "col236": "r38te", + "col237": "vnw00", + "col238": "soviw", + "col239": "1opbp", + "col240": "g0cj1", + "col241": "8x5k9", + "col242": "dxe27", + "col243": "6snfa", + "col244": "y6ybx", + "col245": "40lvm", + "col246": "lu75u", + "col247": "ypprq", + "col248": "xbt48", + "col249": "4uhvk", + "col250": "6jash", + "col251": "jx9s9", + "col252": "k7p84", + "col253": "1ptc4", + "col254": "4rtya", + "col255": "84pbb", + "col256": "545b6", + "col257": "faxmt", + "col258": "c14c2", + "col259": "gjexm", + "col260": "t79ti", + "col261": "b01xh", + "col262": "f99ik", + "col263": "3j0r9", + "col264": "q3jsx", + "col265": "inoyq", + "col266": "qtsji", + "col267": "xr6no", + "col268": "p1hgk", + "col269": "ljbbw", + "col270": "udep0", + "col271": "l5jsd", + "col272": "tncid", + "col273": "5x9ys", + "col274": "5r81e", + "col275": "f7ytd", + "col276": "b193a", + "col277": "wlnga", + "col278": "cgl2j", + "col279": "08655", + "col280": "whbbr", + "col281": "jqwzi", + "col282": "cqinv", + "col283": "32sb0", + "col284": "0vhc1", + "col285": "hr6k6", + "col286": "7cssn", + "col287": "m2hnn", + "col288": "yfw3w", + "col289": "1roz9", + "col290": "larwa", + "col291": "2lipy", + "col292": "lvl24", + "col293": "9fbq1", + "col294": "k6xae", + "col295": "0t9bo", + "col296": "hoomg", + "col297": "p6c65", + "col298": "ccwfi", + "col299": "35iyn", + "col300": "uiiee", + "col301": "r5svv", + "col302": "qvqm2", + "col303": "3f5j0", + "col304": "oe5us", + "col305": "mofmf", + "col306": "kzsr7", + "col307": "9zyur", + "col308": "5p27u", + "col309": "fo1mc", + "col310": "zmrti", + "col311": "p5mlz", + "col312": "5yv2q", + "col313": "74c8n", + "col314": "lpzxq", + "col315": "j1pgi", + "col316": "lu0ld", + "col317": "x42ls", + "col318": "d2v44", + "col319": "3sj6r", + "col320": "m2rby", + "col321": "1i53j", + "col322": "67jn0", + "col323": "a1fni", + "col324": "qvalh", + "col325": "erfy7", + "col326": "0w25w", + "col327": "qm4a3", + "col328": "yqkrs", + "col329": "vrnfx", + "col330": "1ia11", + "col331": "klaj2", + "col332": "dxzow", + "col333": "0le46", + "col334": "dkt31", + "col335": "ni5jg", + "col336": "kku8u", + "col337": "zbokt", + "col338": "rbpo7", + "col339": "7zq06", + "col340": "r0726", + "col341": "pl6c7", + "col342": "mktdn", + "col343": "feyun", + "col344": "hlo1z", + "col345": "0gvln", + "col346": "9xq06", + "col347": "btwr8", + "col348": "y7c00", + "col349": "b47bn", + "col350": "d3ve5", + "col351": "uob6h", + "col352": "nzmu2", + "col353": "a0jgy", + "col354": "en37s", + "col355": "yyne6", + "col356": "dwo16", + "col357": "smidt", + "col358": "v9tmt", + "col359": "fbpnj", + "col360": "ca9aw", + "col361": "uvy1v", + "col362": "1wc1t", + "col363": "d72kc", + "col364": "43a8e", + "col365": "i4i83", + "col366": "k33yh", + "col367": "mijhu", + "col368": "qlx3j", + "col369": "4v1lj", + "col370": "g5g2f", + "col371": "u3uit", + "col372": "dwbwl", + "col373": "t3qxy", + "col374": "8i6n2", + "col375": "k39r7", + "col376": "s4uay", + "col377": "pu7xz", + "col378": "oortq", + "col379": "6lth5", + "col380": "hnkaz", + "col381": "i3jlu", + "col382": "mlx4n", + "col383": "acd8g", + "col384": "etby8", + "col385": "ivnu5", + "col386": "ycite", + "col387": "xdtjj", + "col388": "umgoi", + "col389": "8oowv", + "col390": "sgwyc", + "col391": "x5qyd", + "col392": "44pny", + "col393": "3tf68", + "col394": "5sb6d", + "col395": "go0ae", + "col396": "g73qx", + "col397": "uzvju", + "col398": "nv1br", + "col399": "qdwcd", + "col400": "2ytsk", + "col401": "d5cwy", + "col402": "cog2x", + "col403": "1bie1", + "col404": "jybtc", + "col405": "ksi4r", + "col406": "xf1cr", + "col407": "16i1d", + "col408": "eltix", + "col409": "uk83c", + "col410": "64zpk", + "col411": "lsh4r", + "col412": "7ldw1", + "col413": "mo5kj", + "col414": "78j1a", + "col415": "fb0gh", + "col416": "485zr", + "col417": "3z4el", + "col418": "y83nc", + "col419": "mtxj8", + "col420": "h3yf6", + "col421": "6a7ys", + "col422": "6hqxj", + "col423": "4alw4", + "col424": "zlrjj", + "col425": "whytt", + "col426": "ob1hx", + "col427": "qbsfo", + "col428": "e2x75", + "col429": "50wds", + "col430": "qsbjt", + "col431": "oqe8y", + "col432": "bzuzz", + "col433": "26bl3", + "col434": "9caqp", + "col435": "3herw", + "col436": "quofl", + "col437": "prm1j", + "col438": "ntwwz", + "col439": "7u6md", + "col440": "vvsy9", + "col441": "ny9ye", + "col442": "5wksa", + "col443": "7tx8f", + "col444": "lynik", + "col445": "l8d7q", + "col446": "v33ue", + "col447": "af6db", + "col448": "hkyon", + "col449": "g5jyz", + "col450": "wsa7l", + "col451": "v0i9i", + "col452": "ko840", + "col453": "5s6e6", + "col454": "fkoli", + "col455": "2tlaw", + "col456": "o6wxi", + "col457": "s98x5", + "col458": "puofp", + "col459": "g4vcz", + "col460": "7ruzr", + "col461": "zsxko", + "col462": "co1jm", + "col463": "0asae", + "col464": "agcbs", + "col465": "2mu6c", + "col466": "wgy81", + "col467": "x5lfv", + "col468": "4h1ka", + "col469": "qro1q", + "col470": "4sg2q", + "col471": "s8u9u", + "col472": "83452", + "col473": "vmjog", + "col474": "6ec10", + "col475": "0c1w8", + "col476": "x88kx", + "col477": "ti3r5", + "col478": "t8ggb", + "col479": "xcgs6", + "col480": "4ob0r", + "col481": "wr5zb", + "col482": "sacwa", + "col483": "lvkfz", + "col484": "llx61", + "col485": "uuxkl", + "col486": "uxpff", + "col487": "nvrmg", + "col488": "6s5da", + "col489": "rzoa1", + "col490": "57fot", + "col491": "q2ngc", + "col492": "rwhno", + "col493": "w34p0", + "col494": "ugoww", + "col495": "1q57o", + "col496": "bopd1", + "col497": "z2ed3", + "col498": "4pl11", + "col499": "rn770", + "col500": "vyj32", + "col501": "y4jhl", + "col502": "bb2oi", + "col503": "p3h6j", + "col504": "2n9ue", + "col505": "7w380", + "col506": "u514s", + "col507": "bw3yv", + "col508": "h2nnb", + "col509": "oqyv5", + "col510": "ztz6q", + "col511": "pbl84", + "col512": "lsk67", + "col513": "4jq4f", + "col514": "i7n34", + "col515": "b98ua", + "col516": "h9rwm", + "col517": "uln7k", + "col518": "4kpwk", + "col519": "nkj6v", + "col520": "m1gjd", + "col521": "sj7sb", + "col522": "t6cb1", + "col523": "82ex8", + "col524": "pihfd", + "col525": "p71b3", + "col526": "e96uq", + "col527": "q6b0m", + "col528": "qaqtd", + "col529": "wn5ot", + "col530": "nktch", + "col531": "7ylsk", + "col532": "27lnz", + "col533": "6s0ue", + "col534": "q70ck", + "col535": "kjsza", + "col536": "d3j57", + "col537": "2igyu", + "col538": "kx8ff", + "col539": "qgkjh", + "col540": "9b0ya", + "col541": "0sesk", + "col542": "u35t4", + "col543": "9wfa8", + "col544": "dzynv", + "col545": "ay0g7", + "col546": "57seo", + "col547": "121nb", + "col548": "is0n4", + "col549": "olm8k", + "col550": "2oq2h", + "col551": "cz2go", + "col552": "c2uoj", + "col553": "7lne4", + "col554": "jv7dk", + "col555": "81prv", + "col556": "t372q", + "col557": "0ei35", + "col558": "gp3sv", + "col559": "46lvf", + "col560": "vv1by", + "col561": "xcphj", + "col562": "v9y6r", + "col563": "kskta", + "col564": "s6fa8", + "col565": "byc9t", + "col566": "ys6ng", + "col567": "mrofd", + "col568": "91qsv", + "col569": "vjsdo", + "col570": "5e80d", + "col571": "dzey8", + "col572": "435pg", + "col573": "f27qe", + "col574": "849em", + "col575": "s8wz6", + "col576": "9sby7", + "col577": "7rmzp", + "col578": "qlm0l", + "col579": "br0wo", + "col580": "pweqe", + "col581": "5r2og", + "col582": "f00ea", + "col583": "lb463", + "col584": "9gzq4", + "col585": "j9sbi", + "col586": "9s9ho", + "col587": "jjqma", + "col588": "w89mq", + "col589": "ft84p", + "col590": "otm23", + "col591": "mkcgq", + "col592": "8qeif", + "col593": "myamj", + "col594": "8ve6f", + "col595": "1khpd", + "col596": "3zngz", + "col597": "twytb", + "col598": "gxge4", + "col599": "rwp8e", + "col600": "4cj68", + "col601": "ttaxp", + "col602": "9h9j2", + "col603": "gj1uy", + "col604": "7qi74", + "col605": "qg2rg", + "col606": "975xy", + "col607": "0uu9v", + "col608": "c7w3m", + "col609": "ac1hy", + "col610": "0bz2e", + "col611": "ro0bs", + "col612": "g63r2", + "col613": "xo2x2", + "col614": "1onwf", + "col615": "7cy37", + "col616": "4y2er", + "col617": "b3cw3", + "col618": "cuyin", + "col619": "jlwf0", + "col620": "0a8fw", + "col621": "5x3gq", + "col622": "rs0q6", + "col623": "0v3fj", + "col624": "eskio", + "col625": "ox1ds", + "col626": "ztbfp", + "col627": "n566f", + "col628": "rkcn8", + "col629": "vobgp", + "col630": "7oujf", + "col631": "2ylzs", + "col632": "5it8u", + "col633": "9t0za", + "col634": "b6ksq", + "col635": "2qydy", + "col636": "wi6rr", + "col637": "bo8bf", + "col638": "dq5h2", + "col639": "o7p8s", + "col640": "t9wwu", + "col641": "sp2wm", + "col642": "te9fn", + "col643": "8qpct", + "col644": "bcgrp", + "col645": "uro18", + "col646": "gyfuu", + "col647": "vwx9k", + "col648": "f445n", + "col649": "pxe14", + "col650": "h4d2p", + "col651": "7tqrk", + "col652": "k5z26", + "col653": "u340v", + "col654": "ylsdx", + "col655": "s668m", + "col656": "lscls", + "col657": "sw1gx", + "col658": "miyuo", + "col659": "gbpaj", + "col660": "xwvwg", + "col661": "mx7lm", + "col662": "jqwvt", + "col663": "2jibd", + "col664": "78rdz", + "col665": "dqy6a", + "col666": "00guu", + "col667": "l7l4v", + "col668": "qzlf7", + "col669": "kzqji", + "col670": "4je2j", + "col671": "nyzhi", + "col672": "ajg73", + "col673": "q8ov6", + "col674": "uvkuu", + "col675": "8hm8d", + "col676": "z254t", + "col677": "4s6cd", + "col678": "flexn", + "col679": "yvppq", + "col680": "7z8s2", + "col681": "2kg5v", + "col682": "xp102", + "col683": "p45gs", + "col684": "in3xm", + "col685": "5w8hh", + "col686": "n8js6", + "col687": "hp7fs", + "col688": "1wdzt", + "col689": "r315v", + "col690": "grj06", + "col691": "c7smq", + "col692": "d4o12", + "col693": "8vtr0", + "col694": "tmed1", + "col695": "zln8r", + "col696": "v9cmv", + "col697": "ku6ms", + "col698": "5p1c8", + "col699": "g6jln", + "col700": "et2bp", + "col701": "viaj5", + "col702": "sly4l", + "col703": "d0hs3", + "col704": "ehnf6", + "col705": "yw9p9", + "col706": "arff0", + "col707": "wfe5l", + "col708": "yg2g1", + "col709": "fguo0", + "col710": "ievuw", + "col711": "nm49u", + "col712": "3f71z", + "col713": "hlg25", + "col714": "5m66s", + "col715": "xb0lw", + "col716": "nulnm", + "col717": "69z1c", + "col718": "oe41h", + "col719": "ydqdr", + "col720": "99717", + "col721": "aihp1", + "col722": "t9uty", + "col723": "2ai90", + "col724": "x77po", + "col725": "h3wq1", + "col726": "cjxf1", + "col727": "v95md", + "col728": "ei9fr", + "col729": "w631l", + "col730": "nr59o", + "col731": "3bwss", + "col732": "mftk5", + "col733": "pomx5", + "col734": "lf7x3", + "col735": "79m91", + "col736": "oipqg", + "col737": "seuvy", + "col738": "p3yzr", + "col739": "tt6m2", + "col740": "dmjko", + "col741": "sdntj", + "col742": "0u0su", + "col743": "7wrw6", + "col744": "ky9o8", + "col745": "z0nb1", + "col746": "dxxs2", + "col747": "i15gv", + "col748": "51xqv", + "col749": "owjby", + "col750": "t4zhh", + "col751": "vy2q3", + "col752": "4mabj", + "col753": "6hizy", + "col754": "mcx2y", + "col755": "12b4j", + "col756": "1nft1", + "col757": "syad9", + "col758": "lr38z", + "col759": "iru8q", + "col760": "ryiiu", + "col761": "ksrbr", + "col762": "4knao", + "col763": "lpcio", + "col764": "2p63r", + "col765": "ehhh0", + "col766": "l7juj", + "col767": "ih3h7", + "col768": "xflko", + "col769": "m26a2", + "col770": "ckbeg", + "col771": "evll1", + "col772": "vv81m", + "col773": "xq9ho", + "col774": "cmz66", + "col775": "ms59t", + "col776": "cpxuj", + "col777": "ddldp", + "col778": "ck006", + "col779": "awsyq", + "col780": "aeija", + "col781": "pnp5d", + "col782": "6rps7", + "col783": "imxyy", + "col784": "a1lm4", + "col785": "f6m9h", + "col786": "w3o2s", + "col787": "jyxsw", + "col788": "mfh8r", + "col789": "169d2", + "col790": "1ljod", + "col791": "dwwbt", + "col792": "3az0h", + "col793": "ea9i3", + "col794": "tmqsa", + "col795": "qvlrb", + "col796": "vt2zb", + "col797": "9jz98", + "col798": "icwwn", + "col799": "64gj8", + "col800": "4e4lg", + "col801": "h6q5x", + "col802": "kujm3", + "col803": "miv00", + "col804": "4wy2h", + "col805": "z3kyg", + "col806": "5mnx3", + "col807": "ymac8", + "col808": "4d7zd", + "col809": "pifrr", + "col810": "e4ika", + "col811": "cfj6f", + "col812": "i4wo8", + "col813": "w9aui", + "col814": "1izkc", + "col815": "ejyb2", + "col816": "znxmx", + "col817": "sis7j", + "col818": "n4lts", + "col819": "9w4p8", + "col820": "zlw11", + "col821": "9qknw", + "col822": "nzt63", + "col823": "gmo1m", + "col824": "v3xut", + "col825": "stzqz", + "col826": "9aaso", + "col827": "g0nmy", + "col828": "bpuqe", + "col829": "p5svi", + "col830": "f4pau", + "col831": "ynwcn", + "col832": "23swm", + "col833": "0vowu", + "col834": "7co1j", + "col835": "qmmbq", + "col836": "c0yqi", + "col837": "1cw3a", + "col838": "9xpon", + "col839": "4jucy", + "col840": "0mghr", + "col841": "qequj", + "col842": "h1rkn", + "col843": "lnc9h", + "col844": "gaqpn", + "col845": "cbxyl", + "col846": "1xbxu", + "col847": "axa5r", + "col848": "wcdqr", + "col849": "na09q", + "col850": "57b9t", + "col851": "31jt0", + "col852": "b0vd7", + "col853": "sj0gr", + "col854": "spipp", + "col855": "0ixws", + "col856": "mzldk", + "col857": "ik4ke", + "col858": "t7v06", + "col859": "oozc3", + "col860": "hhn5y", + "col861": "4v4cs", + "col862": "57n6r", + "col863": "q6uyn", + "col864": "yectc", + "col865": "rwl5l", + "col866": "a3672", + "col867": "g8d2h", + "col868": "q2w97", + "col869": "2etts", + "col870": "6yc8r", + "col871": "qrrhl", + "col872": "yq3ve", + "col873": "8ju6x", + "col874": "e8iw1", + "col875": "tch4t", + "col876": "yt73x", + "col877": "21s9h", + "col878": "g266j", + "col879": "e1upy", + "col880": "u8pbu", + "col881": "m13zy", + "col882": "x3d86", + "col883": "brz3k", + "col884": "kknzt", + "col885": "w5cwq", + "col886": "foxcw", + "col887": "vpzxt", + "col888": "tkvq5", + "col889": "lov5q", + "col890": "0oyzh", + "col891": "2fw47", + "col892": "3jqnv", + "col893": "xx2qk", + "col894": "j9idr", + "col895": "zzyc0", + "col896": "nmxyl", + "col897": "iulrq", + "col898": "yrvxv", + "col899": "d3wg8", + "col900": "r8csv", + "col901": "p1c8e", + "col902": "y0369", + "col903": "ge7tr", + "col904": "0u8lp", + "col905": "c01we", + "col906": "0fpr1", + "col907": "pn7z9", + "col908": "p4hqz", + "col909": "kgbpl", + "col910": "b1fpx", + "col911": "gedbt", + "col912": "q6u2i", + "col913": "whxb7", + "col914": "94umy", + "col915": "07pbj", + "col916": "mkoqp", + "col917": "hlv3m", + "col918": "y7ux2", + "col919": "gosit", + "col920": "2118o", + "col921": "ulfor", + "col922": "khuyb", + "col923": "0zqxh", + "col924": "ao4y0", + "col925": "cq1g5", + "col926": "u2p05", + "col927": "qtz8e", + "col928": "0uf0j", + "col929": "zrdho", + "col930": "28c4x", + "col931": "ie5ko", + "col932": "ikgy1", + "col933": "qz3vr", + "col934": "qbzrx", + "col935": "zo7hw", + "col936": "fs8jx", + "col937": "m0fwr", + "col938": "fxlde", + "col939": "ic1sl", + "col940": "dawot", + "col941": "4gbd4", + "col942": "ccknb", + "col943": "6qgeq", + "col944": "n0xnw", + "col945": "sw23l", + "col946": "kd3ol", + "col947": "3h99i", + "col948": "92ra4", + "col949": "i6028", + "col950": "jxvz7", + "col951": "amhlm", + "col952": "qalwe", + "col953": "42xub", + "col954": "w070v", + "col955": "u65lu", + "col956": "c9395", + "col957": "isz5g", + "col958": "fkgzj", + "col959": "exyz1", + "col960": "sa29d", + "col961": "cuu1z", + "col962": "nml9s", + "col963": "yayg1", + "col964": "2r2ui", + "col965": "4lfef", + "col966": "jo4zu", + "col967": "3oroe", + "col968": "wabx4", + "col969": "kh34z", + "col970": "xlm0a", + "col971": "6jdya", + "col972": "wyli1", + "col973": "vd3d8", + "col974": "j9agf", + "col975": "pcbmr", + "col976": "mofyt", + "col977": "8pn41", + "col978": "hh6h9", + "col979": "qk571", + "col980": "cm5lo", + "col981": "inig8", + "col982": "4q8ky", + "col983": "k9th9", + "col984": "j443f", + "col985": "hvgnt", + "col986": "4ne5s", + "col987": "jngzs", + "col988": "90aka", + "col989": "uh8nl", + "col990": "igh1k", + "col991": "xsj8c", + "col992": "qacn5", + "col993": "3z5xb", + "col994": "rttnw", + "col995": "2uamy", + "col996": "5ieo7", + "col997": "93ekg", + "col998": "ig62r", + "col999": "dql67" + }, + { + "name": "Morse Good", + "gender": "male", + "col0": "auuj0", + "col1": "z1ju7", + "col2": "ks8ym", + "col3": "7ltou", + "col4": "jottw", + "col5": "dev32", + "col6": "bf15p", + "col7": "zy3yp", + "col8": "fjsnk", + "col9": "chd9g", + "col10": "lx8mp", + "col11": "turrp", + "col12": "dpo5t", + "col13": "kaz6g", + "col14": "a8ha2", + "col15": "3c59h", + "col16": "nleol", + "col17": "sue1l", + "col18": "fe8yz", + "col19": "xx3r7", + "col20": "7ic8j", + "col21": "pqqtv", + "col22": "nu5eq", + "col23": "ka5vj", + "col24": "f2wrq", + "col25": "bhajp", + "col26": "08f2i", + "col27": "nptax", + "col28": "0vvyn", + "col29": "89fcu", + "col30": "imu5y", + "col31": "jq3jx", + "col32": "3db3u", + "col33": "rekla", + "col34": "ym9sq", + "col35": "xw4dz", + "col36": "1klqd", + "col37": "k4wny", + "col38": "lafoy", + "col39": "jl5nd", + "col40": "25b95", + "col41": "v548v", + "col42": "pyl1f", + "col43": "lvxp9", + "col44": "6kx2j", + "col45": "n53y3", + "col46": "5862j", + "col47": "hoizb", + "col48": "0jfhl", + "col49": "xwu56", + "col50": "oeo4g", + "col51": "p3ppq", + "col52": "3p1sc", + "col53": "58j5t", + "col54": "7x3ay", + "col55": "q8gwx", + "col56": "mpn0b", + "col57": "e9ywj", + "col58": "uzlnt", + "col59": "3cgao", + "col60": "seywj", + "col61": "jzb6y", + "col62": "jkj5n", + "col63": "oniuq", + "col64": "hz3oh", + "col65": "jmtbu", + "col66": "bdb6i", + "col67": "qrk2x", + "col68": "fz7ud", + "col69": "276z3", + "col70": "gqb1k", + "col71": "wl3ez", + "col72": "dgrjr", + "col73": "lop85", + "col74": "6bz3k", + "col75": "okmhn", + "col76": "tt0r2", + "col77": "il8qm", + "col78": "76twv", + "col79": "e287o", + "col80": "fwdb0", + "col81": "5s6bf", + "col82": "oa66j", + "col83": "479zh", + "col84": "msa0d", + "col85": "64ego", + "col86": "j1gno", + "col87": "uzvsf", + "col88": "r5x94", + "col89": "mrs6v", + "col90": "b2nas", + "col91": "gh33k", + "col92": "2dm7h", + "col93": "t2lps", + "col94": "wllkw", + "col95": "pvx5p", + "col96": "f4t4z", + "col97": "umeal", + "col98": "ke28m", + "col99": "6v47d", + "col100": "84aui", + "col101": "dexxa", + "col102": "two5n", + "col103": "s1s06", + "col104": "fpxkv", + "col105": "xhchf", + "col106": "h5h19", + "col107": "v687r", + "col108": "b8i05", + "col109": "2twy6", + "col110": "nnt4l", + "col111": "lrpm8", + "col112": "hvnoy", + "col113": "sqyfo", + "col114": "nq0s5", + "col115": "too3q", + "col116": "3k5gd", + "col117": "w5jvz", + "col118": "5u255", + "col119": "ae3vt", + "col120": "5zwu7", + "col121": "51c8q", + "col122": "8f1b2", + "col123": "nz6xc", + "col124": "lkb7n", + "col125": "4i8fg", + "col126": "vd05b", + "col127": "jpxf4", + "col128": "m2j59", + "col129": "9f15n", + "col130": "sqin2", + "col131": "an9ps", + "col132": "ibvzf", + "col133": "ogyot", + "col134": "s3vj9", + "col135": "37pzo", + "col136": "jo2kd", + "col137": "yaaf7", + "col138": "huvnx", + "col139": "qqcyc", + "col140": "ez99y", + "col141": "xbyqs", + "col142": "54yld", + "col143": "6w588", + "col144": "kyd55", + "col145": "pgx09", + "col146": "6vc9i", + "col147": "lziaw", + "col148": "25cmu", + "col149": "8cx3m", + "col150": "ri1wa", + "col151": "2myb3", + "col152": "kfhwp", + "col153": "6shs0", + "col154": "moqro", + "col155": "hms3b", + "col156": "4j23f", + "col157": "etsja", + "col158": "sqw6k", + "col159": "7tcvg", + "col160": "056tx", + "col161": "41n8c", + "col162": "9czg2", + "col163": "3px8n", + "col164": "pk56h", + "col165": "pqc0d", + "col166": "lj5dr", + "col167": "eqgup", + "col168": "vms9a", + "col169": "34znw", + "col170": "buog7", + "col171": "1tbl4", + "col172": "p590q", + "col173": "49ai4", + "col174": "sttrf", + "col175": "thv7d", + "col176": "2530m", + "col177": "beyxt", + "col178": "g3w2t", + "col179": "8dhkh", + "col180": "0ztvp", + "col181": "lh8mb", + "col182": "dpokk", + "col183": "c2z3q", + "col184": "11v78", + "col185": "jx5nf", + "col186": "2uqt6", + "col187": "i68mz", + "col188": "akzn4", + "col189": "fk91u", + "col190": "hrjop", + "col191": "ypmk6", + "col192": "9ltt5", + "col193": "los9u", + "col194": "thckx", + "col195": "emhbb", + "col196": "76p04", + "col197": "zmugy", + "col198": "jex6e", + "col199": "cab6z", + "col200": "3k19d", + "col201": "n5jny", + "col202": "6pa38", + "col203": "md3o9", + "col204": "ohdk9", + "col205": "83k0m", + "col206": "oi0ev", + "col207": "bd5n7", + "col208": "wd84y", + "col209": "9lqca", + "col210": "9ct5c", + "col211": "9ik4z", + "col212": "6vl38", + "col213": "1iny2", + "col214": "5xjlo", + "col215": "6zk8r", + "col216": "4ljew", + "col217": "92s9f", + "col218": "ih8vw", + "col219": "xbyv8", + "col220": "nofgd", + "col221": "40vxt", + "col222": "pgzks", + "col223": "1a43m", + "col224": "uui1k", + "col225": "h2awb", + "col226": "49gap", + "col227": "rcj4n", + "col228": "e09qz", + "col229": "jv6fa", + "col230": "s9l1b", + "col231": "pbodt", + "col232": "7wrfs", + "col233": "mrgtq", + "col234": "p3qha", + "col235": "5qtj6", + "col236": "2bp2w", + "col237": "tg3qd", + "col238": "4s0r0", + "col239": "e4igl", + "col240": "wm2mb", + "col241": "knt3k", + "col242": "tvepf", + "col243": "0j029", + "col244": "hfapg", + "col245": "46vn0", + "col246": "slaj4", + "col247": "d7l4n", + "col248": "fhsnz", + "col249": "5cu1i", + "col250": "ih1in", + "col251": "bg30n", + "col252": "ear99", + "col253": "4vqx7", + "col254": "llqqm", + "col255": "rutp9", + "col256": "y40h5", + "col257": "dqc7r", + "col258": "xr393", + "col259": "c7ysx", + "col260": "63azc", + "col261": "mghqa", + "col262": "f9e5w", + "col263": "xgh64", + "col264": "tyazx", + "col265": "b5rcb", + "col266": "5daqk", + "col267": "3ns2y", + "col268": "fd00w", + "col269": "e1x5m", + "col270": "1knvi", + "col271": "l9hpb", + "col272": "84rjw", + "col273": "bcqjf", + "col274": "4jgot", + "col275": "pfmec", + "col276": "0csgq", + "col277": "ou1nz", + "col278": "x4c1o", + "col279": "cybvp", + "col280": "rlr7m", + "col281": "o0n84", + "col282": "3nw2c", + "col283": "8sazp", + "col284": "jc3nt", + "col285": "bx9p4", + "col286": "hqijj", + "col287": "t5k18", + "col288": "c3gyu", + "col289": "4as2t", + "col290": "ji67x", + "col291": "qchgi", + "col292": "1jsat", + "col293": "ciyg1", + "col294": "y1tnw", + "col295": "isyk9", + "col296": "z2753", + "col297": "bt4dd", + "col298": "rb1wo", + "col299": "6qo04", + "col300": "8o2na", + "col301": "4j3ar", + "col302": "bgl1s", + "col303": "edd4u", + "col304": "xutmc", + "col305": "z0alg", + "col306": "rrpva", + "col307": "xe1r7", + "col308": "q6pil", + "col309": "gdwoh", + "col310": "75g2m", + "col311": "d8t2z", + "col312": "3xdfu", + "col313": "ptkul", + "col314": "kqenf", + "col315": "pytec", + "col316": "qf0ir", + "col317": "zp77x", + "col318": "q8kh5", + "col319": "g6ccm", + "col320": "i4bo2", + "col321": "molax", + "col322": "chnyn", + "col323": "wzh15", + "col324": "ya8dq", + "col325": "rgha7", + "col326": "1d4cq", + "col327": "p1t4j", + "col328": "359bf", + "col329": "41952", + "col330": "7vl33", + "col331": "vl1if", + "col332": "wyu0q", + "col333": "wd6qx", + "col334": "yxi1h", + "col335": "q2xit", + "col336": "cn5gv", + "col337": "lf6e2", + "col338": "9ikvw", + "col339": "zc3gu", + "col340": "8zrc2", + "col341": "9s2j8", + "col342": "qtcii", + "col343": "dwkqi", + "col344": "x3xel", + "col345": "f43mh", + "col346": "va23t", + "col347": "o0dhm", + "col348": "5nfog", + "col349": "8k8us", + "col350": "fz8ko", + "col351": "c6kaf", + "col352": "fzmc6", + "col353": "kj137", + "col354": "28jc2", + "col355": "jxue0", + "col356": "phg4s", + "col357": "ajo8r", + "col358": "o246u", + "col359": "y8pyw", + "col360": "5k4b6", + "col361": "m3tlw", + "col362": "414q5", + "col363": "herbn", + "col364": "9lrz0", + "col365": "060am", + "col366": "2itwi", + "col367": "7yg1d", + "col368": "d4sot", + "col369": "sjkko", + "col370": "ggr1a", + "col371": "j49h4", + "col372": "e7hqh", + "col373": "1sfkp", + "col374": "h0hyn", + "col375": "srph3", + "col376": "30wch", + "col377": "iqzw3", + "col378": "n482g", + "col379": "evy4h", + "col380": "ryjrs", + "col381": "8t6mi", + "col382": "357cb", + "col383": "cx72w", + "col384": "umnns", + "col385": "ba6mv", + "col386": "4fev1", + "col387": "zmasn", + "col388": "fjxup", + "col389": "qku5t", + "col390": "jblh3", + "col391": "5e7vm", + "col392": "9pf32", + "col393": "pb7o3", + "col394": "ve9ln", + "col395": "cehz7", + "col396": "uyexh", + "col397": "p40b6", + "col398": "x12px", + "col399": "2s018", + "col400": "n2dsr", + "col401": "myx98", + "col402": "01aqy", + "col403": "qrzq8", + "col404": "wpb9x", + "col405": "zb2o6", + "col406": "cjzgk", + "col407": "h0yap", + "col408": "0lmx0", + "col409": "jczfr", + "col410": "ng4iy", + "col411": "8uz5d", + "col412": "wvmgl", + "col413": "rgfhr", + "col414": "edx2t", + "col415": "0e1oz", + "col416": "noxj6", + "col417": "duvap", + "col418": "x00yg", + "col419": "7n817", + "col420": "o5yyh", + "col421": "da92d", + "col422": "iwtak", + "col423": "rk3nd", + "col424": "vgk9i", + "col425": "0ayc5", + "col426": "nzr93", + "col427": "yxw76", + "col428": "l1osn", + "col429": "7jhf7", + "col430": "nbi17", + "col431": "k7dle", + "col432": "148cs", + "col433": "snzb7", + "col434": "bze3t", + "col435": "5yyrf", + "col436": "7lj99", + "col437": "3z5h8", + "col438": "k3uys", + "col439": "j2420", + "col440": "tlaj4", + "col441": "lcgrk", + "col442": "h4cno", + "col443": "llrn6", + "col444": "7tbry", + "col445": "i87qq", + "col446": "paspz", + "col447": "8vc48", + "col448": "liylp", + "col449": "7md7x", + "col450": "dtir1", + "col451": "oxty5", + "col452": "pzqm2", + "col453": "dsjv1", + "col454": "xtj60", + "col455": "abnrl", + "col456": "1j1fh", + "col457": "2juzs", + "col458": "irkqx", + "col459": "mp6i3", + "col460": "ks4at", + "col461": "3e4g0", + "col462": "9r38h", + "col463": "iz2cm", + "col464": "dujpy", + "col465": "2j7tp", + "col466": "1jjxy", + "col467": "0ymm7", + "col468": "0uec5", + "col469": "iibli", + "col470": "zkvnb", + "col471": "bqz73", + "col472": "vs3io", + "col473": "zxccz", + "col474": "86z36", + "col475": "8lpw5", + "col476": "8hpr8", + "col477": "wzzzw", + "col478": "m2m73", + "col479": "yu5u3", + "col480": "lcv1x", + "col481": "6pr2b", + "col482": "qowxp", + "col483": "95sbd", + "col484": "jxgtf", + "col485": "3a7os", + "col486": "jmhvl", + "col487": "88gj1", + "col488": "pz6is", + "col489": "61ktw", + "col490": "ojnoa", + "col491": "ycok8", + "col492": "4r6px", + "col493": "chtdk", + "col494": "zf4od", + "col495": "p6tkv", + "col496": "jme3z", + "col497": "smjn7", + "col498": "4e7ke", + "col499": "1ndnm", + "col500": "85y6o", + "col501": "m3sbv", + "col502": "pp89w", + "col503": "5zkfu", + "col504": "8ml6s", + "col505": "p2a4b", + "col506": "cibc9", + "col507": "hfted", + "col508": "8ze81", + "col509": "u2mw0", + "col510": "j4no5", + "col511": "7rv9m", + "col512": "pqd79", + "col513": "urdzr", + "col514": "tgim2", + "col515": "mjy59", + "col516": "p9uvu", + "col517": "bboci", + "col518": "9sosg", + "col519": "w74yv", + "col520": "lypc3", + "col521": "w6bxu", + "col522": "tw0v8", + "col523": "qwm04", + "col524": "6b6ud", + "col525": "czrof", + "col526": "ti2gn", + "col527": "10c38", + "col528": "dri6p", + "col529": "otih5", + "col530": "fc10u", + "col531": "9irra", + "col532": "ni51z", + "col533": "lyhp6", + "col534": "mbgn0", + "col535": "xnbtc", + "col536": "afwpc", + "col537": "zkr2g", + "col538": "xti54", + "col539": "iwl3n", + "col540": "cfoyd", + "col541": "f80yv", + "col542": "jjzme", + "col543": "gutqh", + "col544": "oiqil", + "col545": "v35hz", + "col546": "2xx6d", + "col547": "7b9sg", + "col548": "yj1oo", + "col549": "op4qz", + "col550": "r9snr", + "col551": "xhmys", + "col552": "3hhcg", + "col553": "wpudv", + "col554": "gujyd", + "col555": "j444f", + "col556": "ik880", + "col557": "9pd6h", + "col558": "6eayw", + "col559": "z8ono", + "col560": "190lm", + "col561": "twbyb", + "col562": "yvv1b", + "col563": "6up5p", + "col564": "euzbq", + "col565": "uk6r2", + "col566": "h459d", + "col567": "yb1d8", + "col568": "2kt0x", + "col569": "ln080", + "col570": "92qz7", + "col571": "86ah1", + "col572": "ouqx0", + "col573": "0nmup", + "col574": "wd9ch", + "col575": "rk94b", + "col576": "uyqhb", + "col577": "cg620", + "col578": "hj0nu", + "col579": "00ct8", + "col580": "o00xw", + "col581": "w96s3", + "col582": "zvn4j", + "col583": "blfq9", + "col584": "de7nf", + "col585": "9g44g", + "col586": "fsyua", + "col587": "l2qkz", + "col588": "hnkbl", + "col589": "m4sta", + "col590": "g6xt9", + "col591": "1mskj", + "col592": "pxczk", + "col593": "fvcge", + "col594": "66u91", + "col595": "7o4il", + "col596": "myx14", + "col597": "8ahln", + "col598": "k5x6k", + "col599": "p73qy", + "col600": "jf949", + "col601": "a1xqq", + "col602": "w061m", + "col603": "tbrcw", + "col604": "sdcvd", + "col605": "jl8op", + "col606": "5rhvh", + "col607": "30evu", + "col608": "7i8i5", + "col609": "8tmru", + "col610": "ggi4h", + "col611": "161dq", + "col612": "k3sek", + "col613": "wk55u", + "col614": "amwzv", + "col615": "g7h02", + "col616": "1iron", + "col617": "7nxyy", + "col618": "3buab", + "col619": "dsvqg", + "col620": "5lfan", + "col621": "0s2bo", + "col622": "ozwnd", + "col623": "nwybo", + "col624": "qd6t8", + "col625": "95kn0", + "col626": "ptm24", + "col627": "johu8", + "col628": "ruoh5", + "col629": "k97qt", + "col630": "ft286", + "col631": "7aoda", + "col632": "wijop", + "col633": "8llrj", + "col634": "r1qoe", + "col635": "rlkxa", + "col636": "ujw0n", + "col637": "qnfo7", + "col638": "6fpoh", + "col639": "p40rq", + "col640": "mte12", + "col641": "qj7aq", + "col642": "7tmyj", + "col643": "v6qoh", + "col644": "rnfan", + "col645": "vpwaz", + "col646": "h31md", + "col647": "mk2gt", + "col648": "45u8n", + "col649": "71n9b", + "col650": "qlsrz", + "col651": "mczj9", + "col652": "qr03r", + "col653": "xijx9", + "col654": "ukaaf", + "col655": "30ik8", + "col656": "04xnw", + "col657": "ynj9e", + "col658": "t3hjb", + "col659": "hrj00", + "col660": "avrro", + "col661": "1fb9o", + "col662": "2olni", + "col663": "uty7b", + "col664": "vxdux", + "col665": "stx1x", + "col666": "g9ogj", + "col667": "zr4yg", + "col668": "1lxky", + "col669": "bor46", + "col670": "lmaob", + "col671": "kapye", + "col672": "509vs", + "col673": "fe37l", + "col674": "iz01g", + "col675": "gadgd", + "col676": "qtzl7", + "col677": "wzz5j", + "col678": "w7efq", + "col679": "whmzr", + "col680": "z86qb", + "col681": "4kbyw", + "col682": "bmurh", + "col683": "2ctc3", + "col684": "h7417", + "col685": "7jmj8", + "col686": "swn9o", + "col687": "y71z5", + "col688": "mq8uy", + "col689": "yn706", + "col690": "stwcd", + "col691": "ojygm", + "col692": "gae4w", + "col693": "4xpou", + "col694": "aeavh", + "col695": "913s6", + "col696": "uw9ur", + "col697": "pzmsb", + "col698": "bazaa", + "col699": "3mekw", + "col700": "0vzgj", + "col701": "vwjas", + "col702": "2fdan", + "col703": "t8hr0", + "col704": "xbri2", + "col705": "j8sgb", + "col706": "dj64e", + "col707": "ik6e3", + "col708": "vlmw0", + "col709": "0j3i5", + "col710": "c0rkd", + "col711": "ro1z6", + "col712": "djhlq", + "col713": "tzfbp", + "col714": "mp4ur", + "col715": "raa1v", + "col716": "ochc2", + "col717": "k231l", + "col718": "oq6ys", + "col719": "sndmc", + "col720": "8tbdo", + "col721": "o6oa3", + "col722": "pvejt", + "col723": "nvrpx", + "col724": "wz2fx", + "col725": "hkrj9", + "col726": "hiot1", + "col727": "asr9j", + "col728": "sngu9", + "col729": "t5nu5", + "col730": "jagsr", + "col731": "hhwv1", + "col732": "8a2wv", + "col733": "hyl9z", + "col734": "8lkcb", + "col735": "qd7ol", + "col736": "mg5su", + "col737": "ws9wz", + "col738": "k7z3v", + "col739": "1twxq", + "col740": "d05gr", + "col741": "7zi4d", + "col742": "81v0c", + "col743": "poj1u", + "col744": "ia4mx", + "col745": "rs6zh", + "col746": "p5pbl", + "col747": "nusba", + "col748": "hbpgg", + "col749": "7alo2", + "col750": "xt2kj", + "col751": "m483t", + "col752": "v0nm4", + "col753": "cl2fw", + "col754": "q9dkv", + "col755": "v5sv6", + "col756": "gh1iw", + "col757": "7z938", + "col758": "k0ppy", + "col759": "5of8n", + "col760": "dq8zy", + "col761": "vpm3a", + "col762": "asgj8", + "col763": "vxiry", + "col764": "izu6r", + "col765": "zkp61", + "col766": "b4245", + "col767": "dl4q7", + "col768": "7wo6j", + "col769": "ctuz7", + "col770": "44zr2", + "col771": "osdka", + "col772": "gi5ed", + "col773": "37ufr", + "col774": "i2pik", + "col775": "lh01w", + "col776": "yhvv4", + "col777": "ib7ff", + "col778": "0fawq", + "col779": "z4fuz", + "col780": "ewhy5", + "col781": "od0z7", + "col782": "9npzg", + "col783": "xvbuf", + "col784": "wmuim", + "col785": "j4h58", + "col786": "l4ot0", + "col787": "odubo", + "col788": "0z4wt", + "col789": "g6ujv", + "col790": "gof7e", + "col791": "wbn8t", + "col792": "niytt", + "col793": "g96sv", + "col794": "lx1nw", + "col795": "k3h8d", + "col796": "j8erg", + "col797": "cjkc3", + "col798": "hr2fa", + "col799": "3y49t", + "col800": "mjnyn", + "col801": "i96br", + "col802": "77p20", + "col803": "625mb", + "col804": "usvbk", + "col805": "ptfkp", + "col806": "zumjw", + "col807": "mtoxa", + "col808": "2lpf1", + "col809": "c62v0", + "col810": "2ewmf", + "col811": "h9g9w", + "col812": "e1hos", + "col813": "hcom0", + "col814": "fuuz3", + "col815": "ks60h", + "col816": "birn0", + "col817": "jlaey", + "col818": "k9sbx", + "col819": "5ox7c", + "col820": "f904q", + "col821": "0i2q7", + "col822": "h3w2y", + "col823": "guoh5", + "col824": "nxio4", + "col825": "isi3f", + "col826": "usdpm", + "col827": "rwylz", + "col828": "790ca", + "col829": "86iz6", + "col830": "5tdew", + "col831": "tye67", + "col832": "p645l", + "col833": "qs28l", + "col834": "5co59", + "col835": "vr5ld", + "col836": "htprs", + "col837": "29xbi", + "col838": "gvke6", + "col839": "54qmz", + "col840": "ozhzj", + "col841": "fa4d8", + "col842": "kgofa", + "col843": "j0dzo", + "col844": "5cv2a", + "col845": "lyqrc", + "col846": "jo8ep", + "col847": "z9mfr", + "col848": "tnynw", + "col849": "2wtux", + "col850": "zv21i", + "col851": "7umfn", + "col852": "lmrod", + "col853": "s7iow", + "col854": "lr00p", + "col855": "wukox", + "col856": "6fkpi", + "col857": "ijfk9", + "col858": "ap68n", + "col859": "9ly6j", + "col860": "frkh6", + "col861": "zz52w", + "col862": "9mizk", + "col863": "ne9qt", + "col864": "oki5f", + "col865": "l8qgd", + "col866": "qlqdc", + "col867": "c4orj", + "col868": "lg8qr", + "col869": "wcn2y", + "col870": "rrafd", + "col871": "gwwzo", + "col872": "vqquo", + "col873": "iqaw8", + "col874": "6bc3q", + "col875": "t1w2h", + "col876": "qgbv1", + "col877": "rlcad", + "col878": "pgogy", + "col879": "trc87", + "col880": "66ncu", + "col881": "t7cix", + "col882": "x7h8s", + "col883": "q5ptk", + "col884": "igbb3", + "col885": "vtbzs", + "col886": "tp2sa", + "col887": "3456s", + "col888": "0sbja", + "col889": "t8bfi", + "col890": "tl3rw", + "col891": "5ue7f", + "col892": "2tqsb", + "col893": "orgwo", + "col894": "ps6k6", + "col895": "ntwnu", + "col896": "5byi4", + "col897": "dng0k", + "col898": "cs1ld", + "col899": "37y2c", + "col900": "v82fw", + "col901": "ty451", + "col902": "84fik", + "col903": "s5jli", + "col904": "tqu50", + "col905": "0gs2u", + "col906": "k2v1c", + "col907": "g1ncu", + "col908": "029l3", + "col909": "55xrv", + "col910": "szoqk", + "col911": "2uwro", + "col912": "t04s4", + "col913": "ekn69", + "col914": "ekgn6", + "col915": "9rsad", + "col916": "ng27o", + "col917": "cxxpk", + "col918": "e6wui", + "col919": "rye7s", + "col920": "ke0d8", + "col921": "h0yc5", + "col922": "ctlei", + "col923": "wqln7", + "col924": "rgvu3", + "col925": "44be4", + "col926": "wj724", + "col927": "cg3cb", + "col928": "lcbzx", + "col929": "41ej4", + "col930": "2tf30", + "col931": "z9ddr", + "col932": "zyrqx", + "col933": "jehic", + "col934": "mls7c", + "col935": "92enh", + "col936": "xq94q", + "col937": "tqfwj", + "col938": "h9kpi", + "col939": "ewiyf", + "col940": "aziik", + "col941": "i7ude", + "col942": "qdg4x", + "col943": "k0mjr", + "col944": "hk827", + "col945": "7fpga", + "col946": "0lvxu", + "col947": "y5p5k", + "col948": "5de07", + "col949": "e827x", + "col950": "tiosu", + "col951": "imrp8", + "col952": "3xn6a", + "col953": "2wmz9", + "col954": "5by7l", + "col955": "l8d4c", + "col956": "80iqx", + "col957": "i9lyw", + "col958": "0gney", + "col959": "2otko", + "col960": "pg6dt", + "col961": "0f5o0", + "col962": "cvxu2", + "col963": "eil8l", + "col964": "7ndbp", + "col965": "8vo13", + "col966": "jshmx", + "col967": "69fer", + "col968": "brrxs", + "col969": "fp2v3", + "col970": "ycb66", + "col971": "e5nn6", + "col972": "g261t", + "col973": "sc28f", + "col974": "ouw6f", + "col975": "5eqqs", + "col976": "cp6ea", + "col977": "n3pkx", + "col978": "ja0xn", + "col979": "8gxbk", + "col980": "zhjum", + "col981": "yp6o6", + "col982": "82v95", + "col983": "3ephk", + "col984": "tdnky", + "col985": "pff1a", + "col986": "4v5ro", + "col987": "bkt4e", + "col988": "pz7a2", + "col989": "bzsjo", + "col990": "uzrbo", + "col991": "8i1yu", + "col992": "rdevx", + "col993": "rcuub", + "col994": "jhls4", + "col995": "4l7cf", + "col996": "ygvgy", + "col997": "us070", + "col998": "e1kqq", + "col999": "f8de8" + }, + { + "name": "Briggs Irwin", + "gender": "male", + "col0": "5mjec", + "col1": "4us8h", + "col2": "druwh", + "col3": "y3ix3", + "col4": "px32r", + "col5": "icv2k", + "col6": "d742j", + "col7": "l86pm", + "col8": "4eysa", + "col9": "sjl4y", + "col10": "o2jls", + "col11": "d3tig", + "col12": "6ok8a", + "col13": "n85ks", + "col14": "82nun", + "col15": "hvcc2", + "col16": "dceff", + "col17": "7t15d", + "col18": "edn51", + "col19": "axjhn", + "col20": "wcbo0", + "col21": "fr2nq", + "col22": "aqz2i", + "col23": "orqrd", + "col24": "m0c9k", + "col25": "p6yvm", + "col26": "lo93z", + "col27": "mc8n3", + "col28": "3y0ys", + "col29": "i17pl", + "col30": "tv9jw", + "col31": "y5kpk", + "col32": "07lsh", + "col33": "mw2td", + "col34": "vrnq1", + "col35": "5qbxl", + "col36": "58q8m", + "col37": "fx2g1", + "col38": "or60l", + "col39": "4fmec", + "col40": "8ar8t", + "col41": "0m9t6", + "col42": "j5hl0", + "col43": "hm5el", + "col44": "gdiky", + "col45": "k0bpy", + "col46": "y67gs", + "col47": "pnci0", + "col48": "f871t", + "col49": "t147q", + "col50": "xgzc8", + "col51": "03yzw", + "col52": "0v5fb", + "col53": "irbyl", + "col54": "zqn1j", + "col55": "brblj", + "col56": "rhgqu", + "col57": "6dozx", + "col58": "jjh9p", + "col59": "vdgpi", + "col60": "5ac9t", + "col61": "i5oyb", + "col62": "aohob", + "col63": "0mam9", + "col64": "8wrly", + "col65": "8yk5c", + "col66": "enrlm", + "col67": "shvcn", + "col68": "2lfeb", + "col69": "wa3pc", + "col70": "img3d", + "col71": "fpe8k", + "col72": "ech1v", + "col73": "5b455", + "col74": "yu90f", + "col75": "2ed09", + "col76": "zjpy8", + "col77": "dmc9s", + "col78": "hiyq7", + "col79": "2ufu9", + "col80": "0wj88", + "col81": "25o98", + "col82": "vmo7g", + "col83": "1d9cc", + "col84": "lytw4", + "col85": "9aowj", + "col86": "1d6xi", + "col87": "i8zp9", + "col88": "dy6vy", + "col89": "ewhu8", + "col90": "00vzo", + "col91": "jp872", + "col92": "gzsqz", + "col93": "o0gm7", + "col94": "8bupw", + "col95": "5lonf", + "col96": "t9tpa", + "col97": "u9g4f", + "col98": "gq2kk", + "col99": "qbez6", + "col100": "opbod", + "col101": "xa79d", + "col102": "12y3u", + "col103": "htr57", + "col104": "5ehl8", + "col105": "j8cvx", + "col106": "odeas", + "col107": "qlmf0", + "col108": "tsnse", + "col109": "nhx6i", + "col110": "ijaa4", + "col111": "w915c", + "col112": "l1b6c", + "col113": "bzzpy", + "col114": "lzok2", + "col115": "ofd8y", + "col116": "4p8xg", + "col117": "y1de0", + "col118": "1raj2", + "col119": "duke9", + "col120": "kbhi7", + "col121": "o9t9i", + "col122": "7ku1u", + "col123": "v6cii", + "col124": "4bgw7", + "col125": "2q8v2", + "col126": "bo4rd", + "col127": "bb664", + "col128": "h3mhi", + "col129": "2e6uz", + "col130": "rbh2f", + "col131": "lhq51", + "col132": "pvqtu", + "col133": "isi94", + "col134": "cwcp2", + "col135": "gxs0g", + "col136": "r7u8k", + "col137": "9ll32", + "col138": "d195y", + "col139": "761pa", + "col140": "fegy2", + "col141": "1tdet", + "col142": "rrz2q", + "col143": "d4t99", + "col144": "0kwjy", + "col145": "uc5df", + "col146": "ybd7r", + "col147": "9g6oc", + "col148": "7csav", + "col149": "ra4io", + "col150": "obai8", + "col151": "bd2qg", + "col152": "n5alh", + "col153": "req9y", + "col154": "scyi3", + "col155": "lr57l", + "col156": "xnxmt", + "col157": "0tv48", + "col158": "12zbz", + "col159": "supu5", + "col160": "9spzf", + "col161": "132hg", + "col162": "716mz", + "col163": "avqil", + "col164": "jdjh1", + "col165": "buayf", + "col166": "t498m", + "col167": "eeh3b", + "col168": "4taqq", + "col169": "vy08q", + "col170": "ypcrs", + "col171": "jjixy", + "col172": "db55f", + "col173": "6c3fe", + "col174": "0faq7", + "col175": "pwa0o", + "col176": "edbnk", + "col177": "q79ze", + "col178": "8ad7a", + "col179": "vyzrp", + "col180": "mng64", + "col181": "f6p63", + "col182": "vdfiq", + "col183": "pvwtf", + "col184": "zqfj4", + "col185": "7yda6", + "col186": "o4orb", + "col187": "8x7vi", + "col188": "ww1fk", + "col189": "jr70x", + "col190": "qy0hh", + "col191": "9koip", + "col192": "qr46o", + "col193": "ppdj4", + "col194": "d2rs5", + "col195": "l12c6", + "col196": "6qywv", + "col197": "ii0d4", + "col198": "x64sd", + "col199": "r4fap", + "col200": "vkl4u", + "col201": "8euqk", + "col202": "6dlb7", + "col203": "fykaf", + "col204": "9cjpi", + "col205": "ererb", + "col206": "eft9r", + "col207": "ogrbb", + "col208": "b70z6", + "col209": "bnyqa", + "col210": "b9acf", + "col211": "7wzuu", + "col212": "acjbj", + "col213": "vkf2e", + "col214": "8ujs3", + "col215": "wto3x", + "col216": "gmq01", + "col217": "z7o2w", + "col218": "c3uyd", + "col219": "lpzuv", + "col220": "wzgro", + "col221": "tbwci", + "col222": "6u14h", + "col223": "w143v", + "col224": "touem", + "col225": "y91gc", + "col226": "hueg2", + "col227": "butb4", + "col228": "46f70", + "col229": "tqkc3", + "col230": "hbtqe", + "col231": "zo3uu", + "col232": "94gqz", + "col233": "iuqd3", + "col234": "szodm", + "col235": "461iv", + "col236": "h52ax", + "col237": "i6406", + "col238": "vczqu", + "col239": "jdni0", + "col240": "lp9yw", + "col241": "l3yye", + "col242": "g7uwe", + "col243": "momvo", + "col244": "8ky69", + "col245": "m2za9", + "col246": "sph1j", + "col247": "zljqa", + "col248": "gteve", + "col249": "yoeuq", + "col250": "hfxix", + "col251": "99zv0", + "col252": "w8n4z", + "col253": "cr87h", + "col254": "hyala", + "col255": "y9f9t", + "col256": "ub17v", + "col257": "86nh9", + "col258": "iwmhr", + "col259": "5abo5", + "col260": "eohyw", + "col261": "sts4c", + "col262": "hch3d", + "col263": "6nr9h", + "col264": "h9df8", + "col265": "ilopw", + "col266": "ik62r", + "col267": "afia0", + "col268": "d4ixd", + "col269": "mo42p", + "col270": "h6a6v", + "col271": "sn8t5", + "col272": "ihfbb", + "col273": "oi6f0", + "col274": "a0hun", + "col275": "c9y5d", + "col276": "aalau", + "col277": "xmzfj", + "col278": "tv3xz", + "col279": "039ji", + "col280": "ogrvn", + "col281": "eq0f2", + "col282": "shmli", + "col283": "2pfwi", + "col284": "ugy3c", + "col285": "v2uwn", + "col286": "al1sw", + "col287": "j5t07", + "col288": "vz6x9", + "col289": "0hq31", + "col290": "xn0q2", + "col291": "xshj2", + "col292": "bb96b", + "col293": "txev6", + "col294": "lai2r", + "col295": "3vso7", + "col296": "jk709", + "col297": "8kxoq", + "col298": "65mld", + "col299": "xt7rc", + "col300": "44zhl", + "col301": "qhls3", + "col302": "a1d93", + "col303": "7fhfr", + "col304": "m24cf", + "col305": "8ov43", + "col306": "ydtsy", + "col307": "40bf4", + "col308": "rvfp4", + "col309": "xxu63", + "col310": "wf4pj", + "col311": "xh3yp", + "col312": "qx8pv", + "col313": "uh6cc", + "col314": "qtx10", + "col315": "rsc0u", + "col316": "utnws", + "col317": "mbow7", + "col318": "kyvpp", + "col319": "l6p8b", + "col320": "knvky", + "col321": "tyv34", + "col322": "vmo0x", + "col323": "z308a", + "col324": "pwsqd", + "col325": "ui40w", + "col326": "5835w", + "col327": "5jlv7", + "col328": "a1zv8", + "col329": "gczpw", + "col330": "tv551", + "col331": "rw8sq", + "col332": "d5wf0", + "col333": "a6c9n", + "col334": "0no5h", + "col335": "4tk5n", + "col336": "m4p0s", + "col337": "lvnle", + "col338": "1gg9v", + "col339": "ud8u1", + "col340": "4qsmf", + "col341": "36hl8", + "col342": "673vb", + "col343": "kqet4", + "col344": "228c6", + "col345": "6242j", + "col346": "lu4uy", + "col347": "mqj14", + "col348": "co521", + "col349": "audqt", + "col350": "9uafv", + "col351": "72qy4", + "col352": "6roxw", + "col353": "nhsv9", + "col354": "i034l", + "col355": "86wol", + "col356": "13i3k", + "col357": "yv99y", + "col358": "p2hlg", + "col359": "trnw2", + "col360": "7mblc", + "col361": "snvjx", + "col362": "9n93b", + "col363": "rqcar", + "col364": "bu0c3", + "col365": "hcslb", + "col366": "0yg29", + "col367": "7uupp", + "col368": "6safp", + "col369": "ddzm1", + "col370": "apmdd", + "col371": "sxe2z", + "col372": "zkcgk", + "col373": "86mx3", + "col374": "pe2uk", + "col375": "sv8gw", + "col376": "d08gi", + "col377": "9myh4", + "col378": "bs645", + "col379": "6erbg", + "col380": "c6eci", + "col381": "rltfo", + "col382": "2uw2b", + "col383": "g2jzi", + "col384": "7fcw0", + "col385": "jl70x", + "col386": "7ga7h", + "col387": "6rutf", + "col388": "5xtni", + "col389": "sfm7j", + "col390": "vbmu7", + "col391": "xptlj", + "col392": "a619y", + "col393": "jwbaw", + "col394": "4wqix", + "col395": "8i1hr", + "col396": "hl88o", + "col397": "yqag2", + "col398": "eaj1m", + "col399": "cc5bi", + "col400": "m7q8q", + "col401": "ybjzy", + "col402": "agu1r", + "col403": "xnaba", + "col404": "fj6kw", + "col405": "oo7t3", + "col406": "aodx8", + "col407": "3b05s", + "col408": "zytby", + "col409": "ukgas", + "col410": "tkdkl", + "col411": "utnlq", + "col412": "kb7e1", + "col413": "mfvk7", + "col414": "h02uv", + "col415": "isk6q", + "col416": "m3o62", + "col417": "hupg5", + "col418": "hjk0t", + "col419": "i0wse", + "col420": "uh3dr", + "col421": "nkrmp", + "col422": "y6ojm", + "col423": "24rc5", + "col424": "9ja14", + "col425": "8q876", + "col426": "ee9xo", + "col427": "ea2jy", + "col428": "lwy73", + "col429": "irtet", + "col430": "hyrpl", + "col431": "zqylq", + "col432": "jqrt5", + "col433": "cvi2x", + "col434": "a20yp", + "col435": "fw8og", + "col436": "dxgl1", + "col437": "5d2at", + "col438": "mylqt", + "col439": "3laaq", + "col440": "kjg9y", + "col441": "w2v71", + "col442": "qv1xh", + "col443": "ihrb3", + "col444": "ooo2i", + "col445": "7xorq", + "col446": "6a29a", + "col447": "j33hs", + "col448": "smyp2", + "col449": "9xxop", + "col450": "hy4t2", + "col451": "53nzp", + "col452": "o48qo", + "col453": "atrsh", + "col454": "9xv0a", + "col455": "0fmy4", + "col456": "a0i1v", + "col457": "vixo4", + "col458": "b29rz", + "col459": "glfae", + "col460": "3r5vk", + "col461": "4f7o7", + "col462": "v3s4a", + "col463": "jmz7u", + "col464": "zvm5d", + "col465": "qih54", + "col466": "az7to", + "col467": "ty2rm", + "col468": "kwusc", + "col469": "sevky", + "col470": "qm43f", + "col471": "1e5sa", + "col472": "9a6x5", + "col473": "z75m5", + "col474": "w257e", + "col475": "ym3ce", + "col476": "4azlo", + "col477": "fnhes", + "col478": "jlt1g", + "col479": "www8u", + "col480": "pqap1", + "col481": "v3zmr", + "col482": "0e1v0", + "col483": "puiix", + "col484": "fzkf2", + "col485": "u861k", + "col486": "yj6uv", + "col487": "obxq6", + "col488": "unwt9", + "col489": "qfuik", + "col490": "qlasd", + "col491": "laqxb", + "col492": "pfx4s", + "col493": "92yq5", + "col494": "go27b", + "col495": "r5ixn", + "col496": "un7rh", + "col497": "xeekq", + "col498": "womq6", + "col499": "twtp8", + "col500": "93mep", + "col501": "z7079", + "col502": "xqvvf", + "col503": "o6qmu", + "col504": "0z4jh", + "col505": "ehsbe", + "col506": "iwayx", + "col507": "vgoad", + "col508": "3oidr", + "col509": "qi26u", + "col510": "ytabg", + "col511": "rznga", + "col512": "fj565", + "col513": "ixz3h", + "col514": "00clm", + "col515": "jdin8", + "col516": "yruo1", + "col517": "qo5dg", + "col518": "bh7bw", + "col519": "k9cqq", + "col520": "1z88q", + "col521": "powg2", + "col522": "1c8js", + "col523": "mffq8", + "col524": "og6k0", + "col525": "mvjy2", + "col526": "ykfo5", + "col527": "hk75w", + "col528": "e04f5", + "col529": "oreiy", + "col530": "8to9g", + "col531": "3pcbn", + "col532": "79ewr", + "col533": "dsbnt", + "col534": "b4l0f", + "col535": "0kbiy", + "col536": "d9nyx", + "col537": "grm33", + "col538": "k1kyw", + "col539": "v78kv", + "col540": "cflgc", + "col541": "bzpbv", + "col542": "xz0fe", + "col543": "d8ej7", + "col544": "42dyr", + "col545": "yfvri", + "col546": "xm83p", + "col547": "rpnsw", + "col548": "s2flt", + "col549": "29ygs", + "col550": "or2sy", + "col551": "tyy94", + "col552": "0x4j3", + "col553": "2rxmv", + "col554": "7g95z", + "col555": "4lgoh", + "col556": "a2okf", + "col557": "zvvr0", + "col558": "wx4s3", + "col559": "j9pc7", + "col560": "x44gs", + "col561": "8zj0p", + "col562": "wphja", + "col563": "mq0xp", + "col564": "5uqeo", + "col565": "k0u2k", + "col566": "vtjj5", + "col567": "7gd1c", + "col568": "4apo3", + "col569": "0n7yp", + "col570": "3dg9l", + "col571": "fbu36", + "col572": "ct1s7", + "col573": "t68wj", + "col574": "7241a", + "col575": "eydqv", + "col576": "anttn", + "col577": "ig37m", + "col578": "cj68n", + "col579": "ws3mk", + "col580": "e6b2l", + "col581": "sr5oe", + "col582": "mld28", + "col583": "1tpm8", + "col584": "7vgp5", + "col585": "brfgv", + "col586": "mzv4t", + "col587": "x9y2d", + "col588": "gmics", + "col589": "6ynp3", + "col590": "qe6lw", + "col591": "ccitz", + "col592": "xsnru", + "col593": "v8s99", + "col594": "orr54", + "col595": "gtgxv", + "col596": "sa39i", + "col597": "uy12y", + "col598": "h6jtq", + "col599": "9wxa5", + "col600": "9cajs", + "col601": "anrme", + "col602": "9cqqg", + "col603": "0n2tb", + "col604": "mfzwb", + "col605": "x8euj", + "col606": "22w10", + "col607": "tc1hk", + "col608": "1hxgh", + "col609": "5th21", + "col610": "tqdco", + "col611": "zg32t", + "col612": "xrl5i", + "col613": "fkqmn", + "col614": "5lqx4", + "col615": "jio5q", + "col616": "d3rm4", + "col617": "6a555", + "col618": "ypsj0", + "col619": "znebf", + "col620": "xk67e", + "col621": "82268", + "col622": "7mfao", + "col623": "o93vm", + "col624": "066og", + "col625": "403ds", + "col626": "awgcb", + "col627": "txccq", + "col628": "c0a0c", + "col629": "te61o", + "col630": "pwdfo", + "col631": "0mvba", + "col632": "h43gz", + "col633": "5vy9c", + "col634": "nrx89", + "col635": "bjq46", + "col636": "t7qvu", + "col637": "61ipw", + "col638": "3qbyd", + "col639": "yhd52", + "col640": "6wa4n", + "col641": "xaeol", + "col642": "9fpes", + "col643": "5m7sw", + "col644": "rnlba", + "col645": "muo7y", + "col646": "ks88l", + "col647": "z6s2p", + "col648": "649rq", + "col649": "p3r2r", + "col650": "g5tid", + "col651": "ldd7i", + "col652": "237j2", + "col653": "e5n27", + "col654": "21q56", + "col655": "09jnf", + "col656": "n4bh0", + "col657": "5hk0u", + "col658": "v1y17", + "col659": "4v913", + "col660": "zq9f8", + "col661": "yt72o", + "col662": "6c753", + "col663": "klyb6", + "col664": "wkjc0", + "col665": "flsaz", + "col666": "ovejr", + "col667": "fuxjk", + "col668": "w1pd8", + "col669": "oe49n", + "col670": "flqem", + "col671": "xhv35", + "col672": "coo59", + "col673": "pbyhg", + "col674": "f5dn3", + "col675": "q13fr", + "col676": "r6w5t", + "col677": "j9q31", + "col678": "0jbte", + "col679": "njjj3", + "col680": "emvxg", + "col681": "5c7yk", + "col682": "xkt0q", + "col683": "uawhk", + "col684": "fm5uq", + "col685": "rfdli", + "col686": "sheqg", + "col687": "os0si", + "col688": "hlfiy", + "col689": "wihl8", + "col690": "cc8oy", + "col691": "nx1de", + "col692": "il9ed", + "col693": "n46qy", + "col694": "urm6o", + "col695": "2o4uj", + "col696": "gma0z", + "col697": "3jkvr", + "col698": "1yv1p", + "col699": "2sc0b", + "col700": "mm0s3", + "col701": "rsfxc", + "col702": "zfuqr", + "col703": "884jp", + "col704": "74eia", + "col705": "5k2o5", + "col706": "hx9ss", + "col707": "u7ye1", + "col708": "qrts1", + "col709": "57pz7", + "col710": "3tt0q", + "col711": "bs8jd", + "col712": "3x5vy", + "col713": "c3fjj", + "col714": "5nrs3", + "col715": "bsz7b", + "col716": "0rox6", + "col717": "azuf2", + "col718": "cfz40", + "col719": "ymzhv", + "col720": "544uc", + "col721": "mp26g", + "col722": "v9bgw", + "col723": "s58rf", + "col724": "66fqy", + "col725": "dshyj", + "col726": "y6jkf", + "col727": "65odk", + "col728": "e4a5r", + "col729": "4megd", + "col730": "aoosn", + "col731": "p81xb", + "col732": "kjtyf", + "col733": "2scv6", + "col734": "wt6t0", + "col735": "02pl4", + "col736": "r7oks", + "col737": "9558q", + "col738": "xrxwc", + "col739": "3152n", + "col740": "lovcm", + "col741": "vst77", + "col742": "ozxg5", + "col743": "7gvha", + "col744": "vg5ux", + "col745": "6kla5", + "col746": "6p10r", + "col747": "7sppj", + "col748": "teve3", + "col749": "sl8ml", + "col750": "05zt2", + "col751": "huro9", + "col752": "313wp", + "col753": "kmmuo", + "col754": "zihmo", + "col755": "5uwzy", + "col756": "ay5zu", + "col757": "c44fy", + "col758": "vk4gn", + "col759": "pd14j", + "col760": "xcm0v", + "col761": "bwbob", + "col762": "0b48o", + "col763": "ydadp", + "col764": "xpnjd", + "col765": "g4rr8", + "col766": "e7jda", + "col767": "53tps", + "col768": "hyn4a", + "col769": "uaqot", + "col770": "fibmm", + "col771": "1j7q9", + "col772": "dxu0f", + "col773": "rzyeo", + "col774": "lakzz", + "col775": "p26xz", + "col776": "0zgqy", + "col777": "0cyj8", + "col778": "7vvnw", + "col779": "tljdc", + "col780": "x6yb6", + "col781": "zq0w6", + "col782": "7o6z5", + "col783": "rtrup", + "col784": "c9pwy", + "col785": "va4je", + "col786": "tvlar", + "col787": "tcu1t", + "col788": "osigj", + "col789": "e9pux", + "col790": "e3k0u", + "col791": "6e9j2", + "col792": "tt2js", + "col793": "a58oc", + "col794": "gog6x", + "col795": "epoh3", + "col796": "c86ph", + "col797": "5pgrd", + "col798": "3jube", + "col799": "aiaal", + "col800": "1tdmx", + "col801": "sx5w9", + "col802": "i4gyy", + "col803": "ohzix", + "col804": "u329z", + "col805": "apxwk", + "col806": "boawy", + "col807": "td98m", + "col808": "r1z9n", + "col809": "tx0h5", + "col810": "eyr4l", + "col811": "a6lw8", + "col812": "hremd", + "col813": "wfv8w", + "col814": "pawym", + "col815": "3kgri", + "col816": "90zdp", + "col817": "x8k3x", + "col818": "cj0s5", + "col819": "g20vi", + "col820": "tm7x0", + "col821": "gr1b8", + "col822": "32pxn", + "col823": "kfg4m", + "col824": "2rg1n", + "col825": "qhvvc", + "col826": "nqvci", + "col827": "rt4qz", + "col828": "pfk7s", + "col829": "hqw9j", + "col830": "wqbsn", + "col831": "os9fj", + "col832": "xqn11", + "col833": "nvzve", + "col834": "z2kwr", + "col835": "lfm78", + "col836": "fkw2v", + "col837": "n0jcg", + "col838": "32o6i", + "col839": "4lx7l", + "col840": "v8yc8", + "col841": "yz1fk", + "col842": "1necp", + "col843": "asvum", + "col844": "ribdi", + "col845": "7dhh0", + "col846": "578jc", + "col847": "m28zm", + "col848": "le27v", + "col849": "5yi1s", + "col850": "cx42w", + "col851": "dui3z", + "col852": "3cue4", + "col853": "5vq8n", + "col854": "mjkjd", + "col855": "9mgws", + "col856": "pjflv", + "col857": "0xebp", + "col858": "am54g", + "col859": "rud3x", + "col860": "xqvng", + "col861": "dqng6", + "col862": "3cjmi", + "col863": "1sn6i", + "col864": "2zg4w", + "col865": "6098v", + "col866": "jkp1y", + "col867": "gieq9", + "col868": "3b3c9", + "col869": "7dvqr", + "col870": "1n3bd", + "col871": "ez9xo", + "col872": "2vsun", + "col873": "m7ett", + "col874": "u50fj", + "col875": "e8r6r", + "col876": "hpfdo", + "col877": "a78v2", + "col878": "n9d30", + "col879": "1tmzv", + "col880": "6f1lb", + "col881": "ih5ma", + "col882": "ybtjf", + "col883": "tenca", + "col884": "tf6uq", + "col885": "cpi1s", + "col886": "0d1ys", + "col887": "runv5", + "col888": "wfovo", + "col889": "ca9ug", + "col890": "jqfxa", + "col891": "n7za4", + "col892": "gtqmc", + "col893": "3fjyp", + "col894": "vfqhu", + "col895": "j1vxb", + "col896": "crpe2", + "col897": "t55a5", + "col898": "qts2n", + "col899": "o4rjg", + "col900": "y9dxa", + "col901": "1x0ip", + "col902": "ldlxs", + "col903": "i3k3y", + "col904": "imlty", + "col905": "uyjhb", + "col906": "2iwe2", + "col907": "anmlf", + "col908": "wn39u", + "col909": "e75g6", + "col910": "2deni", + "col911": "l05au", + "col912": "7ityq", + "col913": "8jac3", + "col914": "f8lmw", + "col915": "e15z4", + "col916": "57c5p", + "col917": "n1sry", + "col918": "4moie", + "col919": "4omqu", + "col920": "qamk7", + "col921": "fu8k7", + "col922": "a57kw", + "col923": "rubjl", + "col924": "lxqrg", + "col925": "9mhw3", + "col926": "4fc65", + "col927": "2j7y4", + "col928": "3xp1j", + "col929": "3fs9b", + "col930": "hpk0m", + "col931": "czbn2", + "col932": "csn7d", + "col933": "l6j9v", + "col934": "hm2er", + "col935": "spr8x", + "col936": "jz17x", + "col937": "n4k90", + "col938": "sgbgs", + "col939": "6hmci", + "col940": "wabh4", + "col941": "16i3o", + "col942": "0vie4", + "col943": "or4w9", + "col944": "xqaih", + "col945": "koysa", + "col946": "pgl3v", + "col947": "q6zig", + "col948": "us2qn", + "col949": "tawq1", + "col950": "yaqtu", + "col951": "hue1a", + "col952": "mrvjx", + "col953": "wp8fk", + "col954": "o5i1s", + "col955": "2wa1h", + "col956": "ioqru", + "col957": "ccou5", + "col958": "liii7", + "col959": "3rgzy", + "col960": "jvvp7", + "col961": "t9x1d", + "col962": "mgzyh", + "col963": "0lci5", + "col964": "4a0xs", + "col965": "pujyq", + "col966": "3np2k", + "col967": "uc27q", + "col968": "p4xns", + "col969": "34v4q", + "col970": "awqzf", + "col971": "dnw36", + "col972": "qoudj", + "col973": "1xfr4", + "col974": "0n4nm", + "col975": "yk9j1", + "col976": "qiitp", + "col977": "78fhm", + "col978": "eqgs7", + "col979": "1oleq", + "col980": "7yuq8", + "col981": "nm63b", + "col982": "s43hl", + "col983": "dscgx", + "col984": "lyj7d", + "col985": "8pd4p", + "col986": "kr0ac", + "col987": "fw2ti", + "col988": "12ylc", + "col989": "4kwgi", + "col990": "wt57o", + "col991": "o118f", + "col992": "at7l6", + "col993": "6tohd", + "col994": "xptvc", + "col995": "5uil8", + "col996": "5m9z0", + "col997": "fqxrg", + "col998": "f2kws", + "col999": "tm3zl" + }, + { + "name": "Judy Bell", + "gender": "female", + "col0": "eu2ys", + "col1": "w9nsx", + "col2": "oqk3u", + "col3": "6rpel", + "col4": "8cd2o", + "col5": "mbiq6", + "col6": "8wp5u", + "col7": "nemup", + "col8": "wko57", + "col9": "23q93", + "col10": "tmya4", + "col11": "3b7lm", + "col12": "55nh6", + "col13": "jydeu", + "col14": "gud2u", + "col15": "uph4g", + "col16": "pbsy0", + "col17": "rsr5y", + "col18": "k6da2", + "col19": "kentz", + "col20": "tmkra", + "col21": "hrxh8", + "col22": "gq7zj", + "col23": "v4vck", + "col24": "p3qbx", + "col25": "t0uq8", + "col26": "yodkv", + "col27": "sdg36", + "col28": "p8dc8", + "col29": "8ldau", + "col30": "wn0mx", + "col31": "ehq6d", + "col32": "0znzp", + "col33": "evugd", + "col34": "v1zr9", + "col35": "hiwr1", + "col36": "gyysn", + "col37": "ssyro", + "col38": "sejbe", + "col39": "4oo4c", + "col40": "6ykhi", + "col41": "nxm5h", + "col42": "03xh8", + "col43": "hi9bx", + "col44": "xpznv", + "col45": "w6kzj", + "col46": "jnlvl", + "col47": "ey5le", + "col48": "9902s", + "col49": "a7k8l", + "col50": "ex4mp", + "col51": "4kxs5", + "col52": "apfg2", + "col53": "d5hlo", + "col54": "0jxtq", + "col55": "j1je2", + "col56": "xlece", + "col57": "b936z", + "col58": "qo8vm", + "col59": "87auk", + "col60": "6p91x", + "col61": "vm07q", + "col62": "xwg04", + "col63": "9t2or", + "col64": "i8746", + "col65": "j6z2g", + "col66": "od8sm", + "col67": "sbrwu", + "col68": "n49na", + "col69": "j76un", + "col70": "0jj1t", + "col71": "xgtyf", + "col72": "re93j", + "col73": "walzn", + "col74": "g304r", + "col75": "9k41c", + "col76": "n55sv", + "col77": "064ag", + "col78": "pi6sx", + "col79": "30he1", + "col80": "s2ei8", + "col81": "vdzyr", + "col82": "e4tsd", + "col83": "pnkkd", + "col84": "r42kh", + "col85": "dqpu7", + "col86": "gjzph", + "col87": "560hs", + "col88": "gsogw", + "col89": "wd64e", + "col90": "wxi2v", + "col91": "qhtir", + "col92": "xw6zc", + "col93": "g06nb", + "col94": "ujiva", + "col95": "1snm1", + "col96": "0j0iq", + "col97": "177ly", + "col98": "0wjj8", + "col99": "gr7he", + "col100": "8e0tk", + "col101": "49m7w", + "col102": "tuqd4", + "col103": "3rqls", + "col104": "nr9qj", + "col105": "w6pg3", + "col106": "cmrh6", + "col107": "7dztu", + "col108": "f1ull", + "col109": "ybpdj", + "col110": "br3zt", + "col111": "68phw", + "col112": "gklp1", + "col113": "ippwx", + "col114": "lks73", + "col115": "cvw9d", + "col116": "7v83j", + "col117": "xdhot", + "col118": "o7dh7", + "col119": "vkfrc", + "col120": "ua0e7", + "col121": "cxe2v", + "col122": "ukj5m", + "col123": "ytkg6", + "col124": "5kqr1", + "col125": "egdjl", + "col126": "7fk13", + "col127": "hegxq", + "col128": "gj7zl", + "col129": "prx8w", + "col130": "gm1s1", + "col131": "sijz5", + "col132": "cw3mh", + "col133": "zo42h", + "col134": "qbjst", + "col135": "7azt9", + "col136": "slg3x", + "col137": "yxcv1", + "col138": "0szhx", + "col139": "rrz40", + "col140": "1y2zg", + "col141": "bke9f", + "col142": "eg2fk", + "col143": "cko7i", + "col144": "ngwr8", + "col145": "7geb2", + "col146": "r2at0", + "col147": "wvqxq", + "col148": "36y8w", + "col149": "xxeid", + "col150": "7an8e", + "col151": "ezf17", + "col152": "l5o7h", + "col153": "tialn", + "col154": "xavrj", + "col155": "eomp8", + "col156": "4sf5x", + "col157": "tw7fp", + "col158": "bna85", + "col159": "1p7n1", + "col160": "f7tp7", + "col161": "6mcuv", + "col162": "y155g", + "col163": "89vz4", + "col164": "f50x2", + "col165": "d2far", + "col166": "j1owl", + "col167": "rtgh5", + "col168": "wbvf4", + "col169": "8yzl2", + "col170": "3fmgr", + "col171": "kulg9", + "col172": "59wly", + "col173": "0cssk", + "col174": "fu3ai", + "col175": "oq46o", + "col176": "xcwmq", + "col177": "386de", + "col178": "zzyp4", + "col179": "kt24f", + "col180": "3cclj", + "col181": "1cofa", + "col182": "l0x1r", + "col183": "f95k1", + "col184": "825px", + "col185": "t96kb", + "col186": "npe8c", + "col187": "e6obk", + "col188": "2kx5y", + "col189": "4962h", + "col190": "yb7ko", + "col191": "mcl3t", + "col192": "vljmx", + "col193": "kw0a2", + "col194": "j7u8k", + "col195": "75usb", + "col196": "lddp8", + "col197": "x2loe", + "col198": "g4i41", + "col199": "gmw8g", + "col200": "kf96y", + "col201": "5rr36", + "col202": "kpqem", + "col203": "s6wic", + "col204": "vtf8e", + "col205": "li7xq", + "col206": "q2tkl", + "col207": "s796h", + "col208": "n30z3", + "col209": "8tw2e", + "col210": "5nd80", + "col211": "cq3e2", + "col212": "lx42g", + "col213": "n9fsv", + "col214": "oarvo", + "col215": "eoe2m", + "col216": "hfhxx", + "col217": "0ihxx", + "col218": "uxu7f", + "col219": "doowt", + "col220": "f71qd", + "col221": "jig96", + "col222": "3bs2e", + "col223": "fgqbc", + "col224": "t1fnd", + "col225": "p1my4", + "col226": "ihhw5", + "col227": "z6h95", + "col228": "jusu1", + "col229": "5vzgm", + "col230": "no8gg", + "col231": "jx5l5", + "col232": "vqw7s", + "col233": "pczgk", + "col234": "kuvbg", + "col235": "dswyc", + "col236": "czmk3", + "col237": "2cg7d", + "col238": "1ua6o", + "col239": "sru2e", + "col240": "s1fgo", + "col241": "n4g9u", + "col242": "wfs3a", + "col243": "47n0y", + "col244": "pqkhe", + "col245": "n0ga2", + "col246": "49kib", + "col247": "h8emb", + "col248": "p2juj", + "col249": "t027m", + "col250": "e3t6q", + "col251": "h2h9i", + "col252": "pgkt3", + "col253": "p6muh", + "col254": "qz7jc", + "col255": "iwup3", + "col256": "phlov", + "col257": "v3yae", + "col258": "67jfc", + "col259": "kswfq", + "col260": "1siw8", + "col261": "uj58n", + "col262": "lh536", + "col263": "xq0ls", + "col264": "7brbf", + "col265": "v5ciq", + "col266": "1ck8r", + "col267": "s06ad", + "col268": "1rhl4", + "col269": "r4mv3", + "col270": "f6wmo", + "col271": "9xuzi", + "col272": "u4fev", + "col273": "wtpl8", + "col274": "u3a68", + "col275": "mzcqb", + "col276": "tephb", + "col277": "uesom", + "col278": "lwsid", + "col279": "9y5h6", + "col280": "k4l6q", + "col281": "ejtrw", + "col282": "gmho6", + "col283": "4930s", + "col284": "e025x", + "col285": "8i4mn", + "col286": "97w77", + "col287": "6dmcv", + "col288": "2rq79", + "col289": "j3up4", + "col290": "i3wxf", + "col291": "g5v6b", + "col292": "yh6ob", + "col293": "4kirb", + "col294": "8tj2i", + "col295": "1ga36", + "col296": "3dc5h", + "col297": "yuvmf", + "col298": "ezkai", + "col299": "tm5mj", + "col300": "mcah9", + "col301": "v93pl", + "col302": "unhbe", + "col303": "0yeeb", + "col304": "1iyh7", + "col305": "5tqsh", + "col306": "2tbps", + "col307": "lkh79", + "col308": "efnqr", + "col309": "fjxxe", + "col310": "x7tuu", + "col311": "x2ev6", + "col312": "g595e", + "col313": "zk0nk", + "col314": "t1d40", + "col315": "dy67z", + "col316": "vbqwr", + "col317": "hwl8p", + "col318": "p56rb", + "col319": "68het", + "col320": "ad2il", + "col321": "42pka", + "col322": "j9dfy", + "col323": "l0lbz", + "col324": "tlxbo", + "col325": "925nb", + "col326": "9t9q0", + "col327": "l8pv5", + "col328": "mhl26", + "col329": "5lev4", + "col330": "krp5y", + "col331": "ra93y", + "col332": "b9df8", + "col333": "5io1h", + "col334": "3tgha", + "col335": "q8y64", + "col336": "5gbpf", + "col337": "y50lv", + "col338": "stksq", + "col339": "q8tco", + "col340": "go64j", + "col341": "a4ktm", + "col342": "zvwih", + "col343": "ei11z", + "col344": "q0xne", + "col345": "squkz", + "col346": "5x2ig", + "col347": "fmyok", + "col348": "q4smd", + "col349": "1dzax", + "col350": "8dj9q", + "col351": "tigfz", + "col352": "9kg8c", + "col353": "u2p8r", + "col354": "5vn0p", + "col355": "89zib", + "col356": "5jvzc", + "col357": "xebaf", + "col358": "gioyw", + "col359": "r55vz", + "col360": "ccxwj", + "col361": "0bnhx", + "col362": "rjxig", + "col363": "0erx1", + "col364": "g68f1", + "col365": "bsav5", + "col366": "1h80q", + "col367": "czhxe", + "col368": "gki5x", + "col369": "vi0qj", + "col370": "gndi1", + "col371": "12h0b", + "col372": "taxuy", + "col373": "478gc", + "col374": "43y93", + "col375": "kckk4", + "col376": "7o012", + "col377": "im80o", + "col378": "ov15b", + "col379": "03f5n", + "col380": "2weo1", + "col381": "zc51j", + "col382": "8sep2", + "col383": "ytrcw", + "col384": "6xpuw", + "col385": "p6tsn", + "col386": "y9ixh", + "col387": "0h3yc", + "col388": "yk9nj", + "col389": "kkx27", + "col390": "cg1rt", + "col391": "bcmk8", + "col392": "4yzvm", + "col393": "qvrgc", + "col394": "zqrr4", + "col395": "cablv", + "col396": "zpp2g", + "col397": "ynn0c", + "col398": "h7b42", + "col399": "nzdk0", + "col400": "ge3j6", + "col401": "7b6pq", + "col402": "0n0be", + "col403": "p91d3", + "col404": "4q5mx", + "col405": "kgylb", + "col406": "97ty3", + "col407": "izak5", + "col408": "57gmz", + "col409": "a5bgn", + "col410": "iznq3", + "col411": "tlge4", + "col412": "iq13r", + "col413": "o8vzz", + "col414": "tbol6", + "col415": "r2q2w", + "col416": "5ardu", + "col417": "47xf2", + "col418": "3sgte", + "col419": "s04fq", + "col420": "0swcn", + "col421": "ft3ti", + "col422": "th4mc", + "col423": "akjpd", + "col424": "osgz2", + "col425": "oygdj", + "col426": "iq9m4", + "col427": "cticq", + "col428": "3ywu9", + "col429": "bmer2", + "col430": "38yar", + "col431": "kdz16", + "col432": "xla4s", + "col433": "ids42", + "col434": "ri1sh", + "col435": "2xarh", + "col436": "miugs", + "col437": "0s9ie", + "col438": "rzbr8", + "col439": "ugjja", + "col440": "9ueo1", + "col441": "kugw5", + "col442": "dthfs", + "col443": "yiigb", + "col444": "ieh6v", + "col445": "j2rlu", + "col446": "ae9aq", + "col447": "venr5", + "col448": "gg65g", + "col449": "3es8k", + "col450": "5qyws", + "col451": "7354p", + "col452": "vegtb", + "col453": "fmfar", + "col454": "6p078", + "col455": "8oiar", + "col456": "qwv71", + "col457": "5bk8x", + "col458": "25kbv", + "col459": "m1rcl", + "col460": "35vxj", + "col461": "s09e1", + "col462": "9spt8", + "col463": "sg9do", + "col464": "npvgd", + "col465": "nt6y1", + "col466": "ocf07", + "col467": "4151w", + "col468": "ukvyx", + "col469": "721g3", + "col470": "yne52", + "col471": "ebtar", + "col472": "qsu8b", + "col473": "iqon4", + "col474": "i5u04", + "col475": "p8ozv", + "col476": "1el8w", + "col477": "acl7a", + "col478": "2x3w9", + "col479": "r05ti", + "col480": "1l75u", + "col481": "isphv", + "col482": "l34k6", + "col483": "0qdi9", + "col484": "p24zn", + "col485": "65m3n", + "col486": "ozoub", + "col487": "7xxwy", + "col488": "af2tl", + "col489": "zg6s7", + "col490": "o4tki", + "col491": "4teab", + "col492": "2t51g", + "col493": "ysrrj", + "col494": "sbuuj", + "col495": "ls57i", + "col496": "li0zo", + "col497": "jzvcf", + "col498": "9tt6l", + "col499": "2ahrb", + "col500": "2omse", + "col501": "q1xxx", + "col502": "2e35r", + "col503": "alwla", + "col504": "7ekuc", + "col505": "kygik", + "col506": "9orqv", + "col507": "jwdax", + "col508": "4rvgd", + "col509": "7b813", + "col510": "425s4", + "col511": "7sf5g", + "col512": "omgrq", + "col513": "hodhz", + "col514": "l3n4w", + "col515": "bwr0s", + "col516": "48als", + "col517": "r97n9", + "col518": "74jy4", + "col519": "ci5gl", + "col520": "o7mck", + "col521": "ralc6", + "col522": "vbzkq", + "col523": "y2tkw", + "col524": "6viab", + "col525": "98hs0", + "col526": "tyk58", + "col527": "3fy6r", + "col528": "4snke", + "col529": "ln7mp", + "col530": "17b8y", + "col531": "8floy", + "col532": "3eyxa", + "col533": "dgfh8", + "col534": "zgj4f", + "col535": "aloo8", + "col536": "z5hc8", + "col537": "ytwlz", + "col538": "a1iye", + "col539": "i22y0", + "col540": "b439b", + "col541": "cupie", + "col542": "n35nh", + "col543": "iqkh6", + "col544": "xx4ds", + "col545": "nhz4g", + "col546": "lbs3e", + "col547": "j335l", + "col548": "hrx4j", + "col549": "5e24s", + "col550": "5zrdj", + "col551": "68vqs", + "col552": "jvyw3", + "col553": "34ywr", + "col554": "8ksdw", + "col555": "5tmmg", + "col556": "mfwa1", + "col557": "h43i4", + "col558": "pdshn", + "col559": "ytwou", + "col560": "s9e9t", + "col561": "tlc9t", + "col562": "0gj81", + "col563": "47fpb", + "col564": "eenas", + "col565": "nqhs6", + "col566": "h3kyk", + "col567": "e978r", + "col568": "qfbms", + "col569": "pl07r", + "col570": "5puox", + "col571": "em39b", + "col572": "4wgkf", + "col573": "ai0qr", + "col574": "35mb6", + "col575": "s9acw", + "col576": "glxc9", + "col577": "4zakm", + "col578": "t0xls", + "col579": "9rk7b", + "col580": "zyuqk", + "col581": "gg212", + "col582": "jtz5b", + "col583": "v5qwr", + "col584": "i25de", + "col585": "v6stt", + "col586": "66mr9", + "col587": "9iz6h", + "col588": "y9tvn", + "col589": "hqafa", + "col590": "mxooz", + "col591": "bnze6", + "col592": "w3i28", + "col593": "gkpot", + "col594": "qp46e", + "col595": "6so60", + "col596": "ltuzf", + "col597": "dv91c", + "col598": "773c7", + "col599": "7mpsf", + "col600": "i13ey", + "col601": "p3t4k", + "col602": "11sna", + "col603": "wtd6z", + "col604": "hxh52", + "col605": "u76jg", + "col606": "yoluc", + "col607": "60rks", + "col608": "oud4g", + "col609": "mtydt", + "col610": "w26jx", + "col611": "a7zag", + "col612": "sm7uy", + "col613": "l65w2", + "col614": "19r6q", + "col615": "gf8gl", + "col616": "jphbo", + "col617": "s4rjx", + "col618": "e1xlh", + "col619": "u893s", + "col620": "oqahr", + "col621": "jpm6e", + "col622": "tkwim", + "col623": "at9xx", + "col624": "zz3mn", + "col625": "387jz", + "col626": "gniq6", + "col627": "gjjyu", + "col628": "yn4lc", + "col629": "7wc7l", + "col630": "n1i28", + "col631": "77lxa", + "col632": "89e9c", + "col633": "sskr0", + "col634": "hrovn", + "col635": "llw5c", + "col636": "gaosu", + "col637": "kpus8", + "col638": "4amom", + "col639": "q5lft", + "col640": "180m0", + "col641": "60z0n", + "col642": "zhv27", + "col643": "hzxhg", + "col644": "kmu66", + "col645": "h0b2s", + "col646": "0mnj6", + "col647": "yszvn", + "col648": "gq0f9", + "col649": "sg9xk", + "col650": "32bbc", + "col651": "bc05g", + "col652": "1rtq5", + "col653": "5l99q", + "col654": "j8l1e", + "col655": "vuuq9", + "col656": "5sorn", + "col657": "cm7ml", + "col658": "9hhuk", + "col659": "arrx6", + "col660": "iho6j", + "col661": "xm3wc", + "col662": "u0rcx", + "col663": "gterv", + "col664": "c6en9", + "col665": "21bpj", + "col666": "uvtab", + "col667": "3abxu", + "col668": "ycwdb", + "col669": "ba3kr", + "col670": "tsf9e", + "col671": "1r4rn", + "col672": "yh488", + "col673": "weiab", + "col674": "ld3d8", + "col675": "2k9xp", + "col676": "e2hce", + "col677": "nom0e", + "col678": "wx23x", + "col679": "e85r9", + "col680": "0bzcn", + "col681": "159gl", + "col682": "ro3eq", + "col683": "n2219", + "col684": "db22l", + "col685": "o3ud9", + "col686": "pup9c", + "col687": "p0lmt", + "col688": "n3caq", + "col689": "1yjsa", + "col690": "rmw8a", + "col691": "c2x4u", + "col692": "0s5t9", + "col693": "2hiko", + "col694": "4jtd5", + "col695": "oi8yy", + "col696": "pc4wo", + "col697": "bowcm", + "col698": "6f7lr", + "col699": "tizxv", + "col700": "pj4ox", + "col701": "4xip6", + "col702": "d2g19", + "col703": "l7x6e", + "col704": "l9m1r", + "col705": "9d3zq", + "col706": "9am90", + "col707": "68ykl", + "col708": "oykpo", + "col709": "9b9qg", + "col710": "ctlba", + "col711": "i1j7q", + "col712": "qd1o8", + "col713": "6qrw7", + "col714": "f2c69", + "col715": "s2fpz", + "col716": "3rnrk", + "col717": "92jc3", + "col718": "icdih", + "col719": "ui22a", + "col720": "e0osu", + "col721": "kjyax", + "col722": "ah5sp", + "col723": "it3s6", + "col724": "j821y", + "col725": "giwzp", + "col726": "jpulv", + "col727": "xuuwe", + "col728": "fjz5v", + "col729": "hotv5", + "col730": "mj742", + "col731": "0k606", + "col732": "85auq", + "col733": "b6l6s", + "col734": "cbnor", + "col735": "1gnl1", + "col736": "6nze1", + "col737": "wt8cp", + "col738": "nqpkb", + "col739": "m4w87", + "col740": "r23r4", + "col741": "638vn", + "col742": "9wc1z", + "col743": "5o170", + "col744": "xok5b", + "col745": "ykdth", + "col746": "d1n98", + "col747": "bff1y", + "col748": "i37pc", + "col749": "1re08", + "col750": "slwtz", + "col751": "4puhw", + "col752": "hcp39", + "col753": "7dapx", + "col754": "7hczm", + "col755": "x05j7", + "col756": "bnp4w", + "col757": "7e9yn", + "col758": "jpa8p", + "col759": "4rl8h", + "col760": "87xqe", + "col761": "hvh4r", + "col762": "hjdgf", + "col763": "x6kee", + "col764": "42u28", + "col765": "yskou", + "col766": "2tf3b", + "col767": "g8c51", + "col768": "rfjn5", + "col769": "aztnz", + "col770": "prlge", + "col771": "4cpdu", + "col772": "z0b0i", + "col773": "yllp7", + "col774": "r4lu3", + "col775": "ocgio", + "col776": "436hh", + "col777": "rzl56", + "col778": "cundz", + "col779": "7ptmo", + "col780": "e100f", + "col781": "uszec", + "col782": "ont77", + "col783": "hmx0e", + "col784": "qsp08", + "col785": "8untl", + "col786": "tra6f", + "col787": "zwuul", + "col788": "3o2u8", + "col789": "pf7uh", + "col790": "fcxdl", + "col791": "yekmg", + "col792": "ma2yf", + "col793": "fz0ok", + "col794": "2oqrc", + "col795": "822ee", + "col796": "t4mhm", + "col797": "e0wrq", + "col798": "sh1xr", + "col799": "abr2w", + "col800": "0t5ri", + "col801": "pub6z", + "col802": "xrmnk", + "col803": "70eye", + "col804": "wx7j0", + "col805": "acl8q", + "col806": "u54oe", + "col807": "46jyj", + "col808": "vgkbc", + "col809": "yszws", + "col810": "xpo22", + "col811": "fduk6", + "col812": "c0ial", + "col813": "9bis9", + "col814": "y7l1b", + "col815": "uebar", + "col816": "8dtyp", + "col817": "qlnr0", + "col818": "6wirw", + "col819": "rm9zi", + "col820": "67r4r", + "col821": "trqw0", + "col822": "d69vl", + "col823": "nx7ob", + "col824": "ynjhe", + "col825": "es9s2", + "col826": "sn56b", + "col827": "ionsu", + "col828": "5cdt6", + "col829": "zh9w0", + "col830": "9p182", + "col831": "uifi6", + "col832": "dxf4c", + "col833": "v90vc", + "col834": "vomem", + "col835": "sp5ll", + "col836": "bmtch", + "col837": "mi0gn", + "col838": "v73jo", + "col839": "3y56h", + "col840": "0c1pf", + "col841": "se7e7", + "col842": "g56fo", + "col843": "a0ywj", + "col844": "8vvfh", + "col845": "uealh", + "col846": "6ca6r", + "col847": "02s9o", + "col848": "bfrl2", + "col849": "njp50", + "col850": "fxu8d", + "col851": "l6bry", + "col852": "05eyo", + "col853": "ikzje", + "col854": "7evkz", + "col855": "iu8bi", + "col856": "c08wg", + "col857": "nsld7", + "col858": "7y5xi", + "col859": "rk0fa", + "col860": "t9sh1", + "col861": "gb3kc", + "col862": "7lv02", + "col863": "00bgc", + "col864": "h30t0", + "col865": "el1xo", + "col866": "61cdg", + "col867": "eszt3", + "col868": "r1chm", + "col869": "06hey", + "col870": "ts0yo", + "col871": "xzbpl", + "col872": "6blxf", + "col873": "3vcmg", + "col874": "5jif4", + "col875": "1dlsp", + "col876": "ke0kw", + "col877": "oo5ym", + "col878": "zhgaj", + "col879": "9yz9u", + "col880": "gve8a", + "col881": "2cqpp", + "col882": "ojlk2", + "col883": "8883q", + "col884": "9vm96", + "col885": "scymu", + "col886": "5yjia", + "col887": "owfsb", + "col888": "mqa4l", + "col889": "v6o3z", + "col890": "u5z2n", + "col891": "jn9yy", + "col892": "srkii", + "col893": "lf4x8", + "col894": "cdcmn", + "col895": "ohzu3", + "col896": "ngnnw", + "col897": "u6dla", + "col898": "mbl5z", + "col899": "lnmg1", + "col900": "tcodg", + "col901": "qqw6y", + "col902": "67ydh", + "col903": "1twkl", + "col904": "e4c6m", + "col905": "8fkt3", + "col906": "70mle", + "col907": "euvy5", + "col908": "ixdca", + "col909": "54kvy", + "col910": "kmsox", + "col911": "awpkq", + "col912": "nk7ju", + "col913": "c811h", + "col914": "tzi21", + "col915": "vi07y", + "col916": "8pl6k", + "col917": "xcpdg", + "col918": "yuv5f", + "col919": "4www6", + "col920": "kz1eu", + "col921": "r530p", + "col922": "jhlar", + "col923": "ekg3d", + "col924": "9i2wz", + "col925": "bwa9q", + "col926": "b83n1", + "col927": "k8dly", + "col928": "j2xg4", + "col929": "962qc", + "col930": "jcqmb", + "col931": "qsvuo", + "col932": "worwe", + "col933": "aetbh", + "col934": "fpjqm", + "col935": "abhr1", + "col936": "argkk", + "col937": "s2zsv", + "col938": "i7gy7", + "col939": "zhbta", + "col940": "hfm8a", + "col941": "7ye36", + "col942": "5m0mz", + "col943": "8wg1c", + "col944": "3sbyh", + "col945": "q0ynv", + "col946": "n917z", + "col947": "d348i", + "col948": "nj6jv", + "col949": "ku27b", + "col950": "fbcu1", + "col951": "w5ehc", + "col952": "bpu8p", + "col953": "w63ba", + "col954": "rzt3b", + "col955": "i2rn8", + "col956": "xedkf", + "col957": "vosak", + "col958": "lo8uz", + "col959": "93f52", + "col960": "aeois", + "col961": "9zzcb", + "col962": "mthz0", + "col963": "n3coa", + "col964": "nxiko", + "col965": "0gem4", + "col966": "ubqgi", + "col967": "xlq40", + "col968": "mlqbw", + "col969": "nxkcu", + "col970": "5c6lz", + "col971": "621g0", + "col972": "b2m12", + "col973": "k7jci", + "col974": "0zfx3", + "col975": "o3okn", + "col976": "ch2q4", + "col977": "gvhbc", + "col978": "c7z6q", + "col979": "30xm1", + "col980": "utywo", + "col981": "w0uf0", + "col982": "bdrmo", + "col983": "y6hy6", + "col984": "ytrrn", + "col985": "3z8ha", + "col986": "5w0iy", + "col987": "bptsl", + "col988": "oufyk", + "col989": "diirj", + "col990": "ns9az", + "col991": "wscjd", + "col992": "m8fet", + "col993": "5dmag", + "col994": "8al1j", + "col995": "ijkxs", + "col996": "1ydg8", + "col997": "fk32m", + "col998": "phrrp", + "col999": "nf10o" + }, + { + "name": "Joyce Gould", + "gender": "female", + "col0": "ogmw1", + "col1": "0dm8p", + "col2": "6m8y1", + "col3": "aoplf", + "col4": "cd2xn", + "col5": "wi9wx", + "col6": "8gtei", + "col7": "7f8n9", + "col8": "6npv8", + "col9": "bzgck", + "col10": "9vd9y", + "col11": "8k52b", + "col12": "5h4db", + "col13": "w7ax8", + "col14": "knxwm", + "col15": "224fx", + "col16": "csklg", + "col17": "fmkv7", + "col18": "4scrm", + "col19": "01k4x", + "col20": "s9t4s", + "col21": "r8b5r", + "col22": "hl4vb", + "col23": "fq6yy", + "col24": "wz76r", + "col25": "7of18", + "col26": "th4vm", + "col27": "dbkit", + "col28": "dxl48", + "col29": "iu0ll", + "col30": "qgta4", + "col31": "3lxnr", + "col32": "xs1wj", + "col33": "fodwb", + "col34": "34g9y", + "col35": "lvkb1", + "col36": "ela15", + "col37": "hbdf9", + "col38": "91v6j", + "col39": "ztjzu", + "col40": "57ljs", + "col41": "5ks4k", + "col42": "nrj32", + "col43": "go6m1", + "col44": "4f1si", + "col45": "qekui", + "col46": "8xr6v", + "col47": "lk5je", + "col48": "x14ke", + "col49": "lv26s", + "col50": "lha38", + "col51": "jj6m6", + "col52": "izctj", + "col53": "zoooh", + "col54": "mppgm", + "col55": "q2wpz", + "col56": "grip4", + "col57": "114pu", + "col58": "zslns", + "col59": "k5bpw", + "col60": "i3fmp", + "col61": "mj2jl", + "col62": "oztra", + "col63": "y84j5", + "col64": "no8i9", + "col65": "msyq0", + "col66": "ntao9", + "col67": "9t0sk", + "col68": "xujlm", + "col69": "h4pxj", + "col70": "2bcra", + "col71": "oeyov", + "col72": "hu888", + "col73": "e86l5", + "col74": "nqcoq", + "col75": "nsysp", + "col76": "lxm6d", + "col77": "ms86m", + "col78": "jgpra", + "col79": "h3zyl", + "col80": "2u457", + "col81": "xllbb", + "col82": "e5yt0", + "col83": "wgd83", + "col84": "cc3pf", + "col85": "kmb64", + "col86": "1fjap", + "col87": "sr8f3", + "col88": "4r8bk", + "col89": "01358", + "col90": "qtar5", + "col91": "3noa4", + "col92": "9ntss", + "col93": "8so9p", + "col94": "44c56", + "col95": "jsr46", + "col96": "rfbrc", + "col97": "9kpv2", + "col98": "ayomt", + "col99": "yofnw", + "col100": "nc5bt", + "col101": "tzvmt", + "col102": "1s93x", + "col103": "pnrrv", + "col104": "04d03", + "col105": "ru4zt", + "col106": "au9bm", + "col107": "7eq2p", + "col108": "fwnfa", + "col109": "n1es6", + "col110": "pdcnr", + "col111": "bksjn", + "col112": "ar0of", + "col113": "v4uyy", + "col114": "0umc8", + "col115": "pyh5z", + "col116": "49rst", + "col117": "kgutf", + "col118": "pvruh", + "col119": "niy3z", + "col120": "4f92u", + "col121": "d5z7t", + "col122": "v8eu3", + "col123": "ic9oq", + "col124": "p02vc", + "col125": "9ibd2", + "col126": "r9acj", + "col127": "wtms8", + "col128": "bq6e6", + "col129": "khjed", + "col130": "roaz1", + "col131": "mguai", + "col132": "zdes9", + "col133": "l793n", + "col134": "zatoe", + "col135": "udzq0", + "col136": "ain8m", + "col137": "chi0c", + "col138": "felwe", + "col139": "6kz5g", + "col140": "rzsar", + "col141": "axwog", + "col142": "5u3hq", + "col143": "jj8w4", + "col144": "3ppyx", + "col145": "v01w3", + "col146": "f9n2g", + "col147": "i6gdm", + "col148": "nzjpj", + "col149": "hfqm2", + "col150": "nyfro", + "col151": "55ou1", + "col152": "kowfa", + "col153": "xf3ba", + "col154": "v9j5s", + "col155": "a3i89", + "col156": "huh7e", + "col157": "6rfxq", + "col158": "wh96n", + "col159": "4034g", + "col160": "jwqp0", + "col161": "xzc1m", + "col162": "w1js0", + "col163": "g4i5t", + "col164": "dua0v", + "col165": "a8dhm", + "col166": "0rfrs", + "col167": "e1214", + "col168": "kgvpo", + "col169": "slpq2", + "col170": "hk2jq", + "col171": "llrua", + "col172": "0ep17", + "col173": "6zgwd", + "col174": "izdow", + "col175": "b8skx", + "col176": "v3a58", + "col177": "ck85a", + "col178": "885wi", + "col179": "2dv91", + "col180": "d9f10", + "col181": "i8i52", + "col182": "xdrsu", + "col183": "yj2d4", + "col184": "4d3m3", + "col185": "r81yy", + "col186": "ofi93", + "col187": "4fajt", + "col188": "xhqqq", + "col189": "itxaq", + "col190": "mr1qd", + "col191": "4vw8r", + "col192": "m8178", + "col193": "mvtmt", + "col194": "2vasn", + "col195": "c1xz7", + "col196": "g2is6", + "col197": "9zp5e", + "col198": "mun4p", + "col199": "8byph", + "col200": "gyhhq", + "col201": "c8rp3", + "col202": "3jdkk", + "col203": "0ub0m", + "col204": "466hv", + "col205": "hldo0", + "col206": "bpltb", + "col207": "s7e3d", + "col208": "zrxcv", + "col209": "7xm4t", + "col210": "rszxg", + "col211": "6u3l8", + "col212": "9sj18", + "col213": "98ary", + "col214": "xdm8j", + "col215": "5a55i", + "col216": "lbhyb", + "col217": "wjb3e", + "col218": "8uim1", + "col219": "800hw", + "col220": "0tdnz", + "col221": "k2u3l", + "col222": "sov0g", + "col223": "tfppk", + "col224": "nzwf0", + "col225": "xstw7", + "col226": "6skqu", + "col227": "s2039", + "col228": "gpi9j", + "col229": "gq0tc", + "col230": "zy9x0", + "col231": "mtjox", + "col232": "jf8em", + "col233": "4debu", + "col234": "eiq87", + "col235": "61qy1", + "col236": "h3t8h", + "col237": "oa810", + "col238": "gj2xq", + "col239": "4c4qq", + "col240": "ycw3q", + "col241": "qmo2p", + "col242": "m2e5l", + "col243": "unb1h", + "col244": "nl30t", + "col245": "9tgm5", + "col246": "skqh3", + "col247": "1nduy", + "col248": "mfmle", + "col249": "jf79s", + "col250": "mp3sp", + "col251": "3ecz8", + "col252": "a6vs5", + "col253": "ilaz9", + "col254": "3d25m", + "col255": "m5z39", + "col256": "px4gi", + "col257": "cissg", + "col258": "z1wxh", + "col259": "l23u0", + "col260": "7dteh", + "col261": "xf4al", + "col262": "gnb5p", + "col263": "k1cds", + "col264": "q8qtm", + "col265": "p4m17", + "col266": "le59p", + "col267": "fzdnt", + "col268": "84vd7", + "col269": "0m86q", + "col270": "hgr9g", + "col271": "jh32x", + "col272": "suol4", + "col273": "ptyfq", + "col274": "daxu3", + "col275": "86mzg", + "col276": "bnm9y", + "col277": "9qln5", + "col278": "1e4nk", + "col279": "22fhr", + "col280": "aluts", + "col281": "n8l0f", + "col282": "gi7w8", + "col283": "bycjb", + "col284": "321fw", + "col285": "p9hmv", + "col286": "7pvw9", + "col287": "t61tu", + "col288": "0ps7e", + "col289": "95y8h", + "col290": "ay9nk", + "col291": "tqfy9", + "col292": "shb1r", + "col293": "g9432", + "col294": "94197", + "col295": "dmpyy", + "col296": "pw3x3", + "col297": "x79re", + "col298": "pbvoc", + "col299": "1nwit", + "col300": "kgyyg", + "col301": "ybnzl", + "col302": "ia8wn", + "col303": "if3jc", + "col304": "wp89k", + "col305": "xufb0", + "col306": "zadio", + "col307": "y3ral", + "col308": "6qanv", + "col309": "88r3m", + "col310": "xyqbi", + "col311": "koggk", + "col312": "o2r8p", + "col313": "gpf4r", + "col314": "wekqt", + "col315": "zm851", + "col316": "6nlxe", + "col317": "0myuq", + "col318": "hjgba", + "col319": "lmbqn", + "col320": "b0wue", + "col321": "58g7s", + "col322": "xey9q", + "col323": "l5va6", + "col324": "62w71", + "col325": "474uk", + "col326": "lydmj", + "col327": "csa5o", + "col328": "229ah", + "col329": "ge1ap", + "col330": "73309", + "col331": "u7rzn", + "col332": "cxtjc", + "col333": "6wtbu", + "col334": "5a3ri", + "col335": "caroo", + "col336": "63390", + "col337": "50d10", + "col338": "81teu", + "col339": "s88co", + "col340": "dfjzz", + "col341": "skkao", + "col342": "ht2g2", + "col343": "gq9mb", + "col344": "zalv6", + "col345": "8ajwr", + "col346": "rr4md", + "col347": "mul3p", + "col348": "p221y", + "col349": "0n5xx", + "col350": "mks5s", + "col351": "ecl2w", + "col352": "levk2", + "col353": "jcoyo", + "col354": "2lzpy", + "col355": "zbydb", + "col356": "nuzvu", + "col357": "7iogb", + "col358": "dkv95", + "col359": "kf0zp", + "col360": "5vqc4", + "col361": "tt811", + "col362": "89ixw", + "col363": "kt80b", + "col364": "0j7l4", + "col365": "zqxw9", + "col366": "saq7j", + "col367": "dcn06", + "col368": "i5a77", + "col369": "h9o4l", + "col370": "pv057", + "col371": "yoy8s", + "col372": "7zxxe", + "col373": "qgezr", + "col374": "pvfdc", + "col375": "12bsj", + "col376": "l2c8h", + "col377": "ke8n0", + "col378": "9zphw", + "col379": "gj13o", + "col380": "cwbl5", + "col381": "gb2yp", + "col382": "lh72x", + "col383": "6ay87", + "col384": "o4e6y", + "col385": "4epzh", + "col386": "1ud5b", + "col387": "7jbdd", + "col388": "75knu", + "col389": "wht8t", + "col390": "0jmaz", + "col391": "0ayk9", + "col392": "ei7oe", + "col393": "azo9p", + "col394": "i0dre", + "col395": "3qs2x", + "col396": "k2aqk", + "col397": "nwm24", + "col398": "5vlt4", + "col399": "e33q9", + "col400": "1qil0", + "col401": "4f59f", + "col402": "5g525", + "col403": "eqbx8", + "col404": "0ewxk", + "col405": "8cq4q", + "col406": "15g4w", + "col407": "fmcbk", + "col408": "6nm2o", + "col409": "v28ii", + "col410": "tbmux", + "col411": "yv4jt", + "col412": "3p0r5", + "col413": "2xtxv", + "col414": "3x4ez", + "col415": "d085q", + "col416": "l468f", + "col417": "8ohr7", + "col418": "auuva", + "col419": "mq4a3", + "col420": "dy7o2", + "col421": "r23d4", + "col422": "m8oxt", + "col423": "16c68", + "col424": "d85w4", + "col425": "dg9st", + "col426": "cbshw", + "col427": "drwqp", + "col428": "578o1", + "col429": "lc4d4", + "col430": "jojby", + "col431": "gk9x8", + "col432": "ieo5x", + "col433": "3xs4s", + "col434": "13xlc", + "col435": "001ee", + "col436": "u94cm", + "col437": "ryj3z", + "col438": "al2bp", + "col439": "sbsum", + "col440": "xgp9l", + "col441": "ax010", + "col442": "63mot", + "col443": "q5f4z", + "col444": "buwje", + "col445": "kolyh", + "col446": "dnyog", + "col447": "2l14z", + "col448": "4vqsk", + "col449": "pv53s", + "col450": "1159a", + "col451": "sallx", + "col452": "kgpgq", + "col453": "oa3rj", + "col454": "z4k4t", + "col455": "jtfqs", + "col456": "7b9gc", + "col457": "nb56r", + "col458": "3jec5", + "col459": "0jsto", + "col460": "x5m1d", + "col461": "0lax6", + "col462": "s777l", + "col463": "odgp2", + "col464": "4s2lp", + "col465": "lvntz", + "col466": "5seya", + "col467": "ncgm1", + "col468": "nhjlx", + "col469": "g25se", + "col470": "4z0bk", + "col471": "otf2f", + "col472": "8qc8a", + "col473": "jfhx1", + "col474": "fel3v", + "col475": "9dxi5", + "col476": "uqcjo", + "col477": "wwkga", + "col478": "wb03r", + "col479": "xcsrp", + "col480": "4khha", + "col481": "lx83i", + "col482": "z6dpa", + "col483": "rki93", + "col484": "aplbg", + "col485": "kc0wa", + "col486": "dxxx4", + "col487": "3wf2i", + "col488": "jqjio", + "col489": "z2k1d", + "col490": "7q9nn", + "col491": "hiv2w", + "col492": "7yho8", + "col493": "3wgty", + "col494": "plgxo", + "col495": "bsnyx", + "col496": "ao4fe", + "col497": "0of26", + "col498": "iv0xw", + "col499": "x7953", + "col500": "y9y4j", + "col501": "kyc50", + "col502": "gemmr", + "col503": "9k1it", + "col504": "fpe5h", + "col505": "rqrny", + "col506": "j7w2c", + "col507": "5p474", + "col508": "9uc97", + "col509": "29gzg", + "col510": "eub8i", + "col511": "yl1dp", + "col512": "hjmfs", + "col513": "3dxoq", + "col514": "qiedx", + "col515": "ue2ax", + "col516": "ts8pv", + "col517": "w9sni", + "col518": "m5etj", + "col519": "xe9yn", + "col520": "q5wh9", + "col521": "xgtru", + "col522": "im51w", + "col523": "acaz8", + "col524": "zif7k", + "col525": "3uvws", + "col526": "waxob", + "col527": "q4gmd", + "col528": "5cude", + "col529": "vh5ru", + "col530": "c9foc", + "col531": "cbhnu", + "col532": "4d8yj", + "col533": "0uyi9", + "col534": "wl7uz", + "col535": "9t9xs", + "col536": "palli", + "col537": "qozrr", + "col538": "dh36o", + "col539": "bjvnq", + "col540": "h2svo", + "col541": "1z2uo", + "col542": "bhg1e", + "col543": "4vr93", + "col544": "5rg0i", + "col545": "ovedh", + "col546": "7871q", + "col547": "wt1wg", + "col548": "fli66", + "col549": "qrnmn", + "col550": "kft9h", + "col551": "a1omz", + "col552": "tvff2", + "col553": "z7itw", + "col554": "p2be1", + "col555": "1hip8", + "col556": "zst2c", + "col557": "xlfh8", + "col558": "pyntf", + "col559": "wlw4e", + "col560": "0lqo6", + "col561": "kbtmp", + "col562": "l996v", + "col563": "od2vf", + "col564": "0ix1h", + "col565": "u68a8", + "col566": "03jdt", + "col567": "3iioe", + "col568": "stezk", + "col569": "3im5s", + "col570": "z36ph", + "col571": "cyiai", + "col572": "ukhe8", + "col573": "n5f2v", + "col574": "v100o", + "col575": "jfrum", + "col576": "33bir", + "col577": "qs2k7", + "col578": "f4d2n", + "col579": "3gg25", + "col580": "4m96x", + "col581": "jhhn4", + "col582": "p2wbu", + "col583": "2pb05", + "col584": "v98b6", + "col585": "if615", + "col586": "9hjyi", + "col587": "jx12v", + "col588": "yjohg", + "col589": "xtcu1", + "col590": "sr1jc", + "col591": "iwdzt", + "col592": "in7ml", + "col593": "9yaq2", + "col594": "jzmsf", + "col595": "rnam3", + "col596": "6vogk", + "col597": "n9rvy", + "col598": "aqsz0", + "col599": "3ibwb", + "col600": "fyhgb", + "col601": "mtzp2", + "col602": "8mz4d", + "col603": "m1hq7", + "col604": "btn3f", + "col605": "k3vir", + "col606": "l8ukf", + "col607": "g3dxf", + "col608": "r8abz", + "col609": "e6xek", + "col610": "vxtqc", + "col611": "qidcw", + "col612": "qoa5n", + "col613": "zwr48", + "col614": "16230", + "col615": "7ymuo", + "col616": "7n4ue", + "col617": "fjki2", + "col618": "26b0v", + "col619": "cuah4", + "col620": "zubh6", + "col621": "7mftm", + "col622": "gxx08", + "col623": "0k26r", + "col624": "kveua", + "col625": "rjn84", + "col626": "9m02c", + "col627": "71q2l", + "col628": "ys9qb", + "col629": "749yn", + "col630": "d25cv", + "col631": "l5gnw", + "col632": "0lfli", + "col633": "s4vik", + "col634": "ufx4o", + "col635": "a68di", + "col636": "8una8", + "col637": "p4ff6", + "col638": "qocp9", + "col639": "dpmwc", + "col640": "zcbmf", + "col641": "bpir2", + "col642": "dy2da", + "col643": "cb0ua", + "col644": "uzpll", + "col645": "byrb6", + "col646": "zdkrq", + "col647": "6hzrb", + "col648": "yw7u5", + "col649": "vzjm4", + "col650": "0jeg9", + "col651": "aapop", + "col652": "qzlsf", + "col653": "myup1", + "col654": "4i9tb", + "col655": "at5gv", + "col656": "zql3a", + "col657": "ek6v9", + "col658": "438jx", + "col659": "qwhhy", + "col660": "oazqg", + "col661": "eq9vn", + "col662": "hfzoo", + "col663": "1z6be", + "col664": "jw0x9", + "col665": "bzib4", + "col666": "q3xkp", + "col667": "44mlf", + "col668": "xp7ga", + "col669": "my2o6", + "col670": "awqw8", + "col671": "39gid", + "col672": "ln3p7", + "col673": "pyq14", + "col674": "hi0xb", + "col675": "ifxnj", + "col676": "8ncvu", + "col677": "dysdf", + "col678": "7sget", + "col679": "ovk8s", + "col680": "qzza7", + "col681": "jbb00", + "col682": "o1j4e", + "col683": "l1oqd", + "col684": "1zt3g", + "col685": "dy31s", + "col686": "w6ko8", + "col687": "1lh0z", + "col688": "ja14h", + "col689": "cifdy", + "col690": "wiui8", + "col691": "lmy1j", + "col692": "2daj1", + "col693": "dwp3a", + "col694": "3m4nn", + "col695": "q14yi", + "col696": "ak3w4", + "col697": "32sbb", + "col698": "rvc9o", + "col699": "r0ouj", + "col700": "hiuxu", + "col701": "5t4jw", + "col702": "2jkpb", + "col703": "5v88a", + "col704": "kv8nj", + "col705": "o3n1y", + "col706": "s1zrq", + "col707": "o1lhq", + "col708": "k3u7c", + "col709": "ujidf", + "col710": "ysd8x", + "col711": "1w5wm", + "col712": "ygbt7", + "col713": "vybux", + "col714": "xlz3v", + "col715": "hy0u8", + "col716": "fy0tn", + "col717": "63s0t", + "col718": "sbqkm", + "col719": "ahwau", + "col720": "qhb5t", + "col721": "7r6k0", + "col722": "2z3s2", + "col723": "6zp10", + "col724": "x0onr", + "col725": "5fzqc", + "col726": "zciwd", + "col727": "u92i1", + "col728": "56ypj", + "col729": "4b600", + "col730": "cdcfw", + "col731": "trlb4", + "col732": "wjvvm", + "col733": "qubam", + "col734": "alxg7", + "col735": "6oy9e", + "col736": "ppuf2", + "col737": "hbuzt", + "col738": "snslq", + "col739": "y5y37", + "col740": "n4ye8", + "col741": "x35r2", + "col742": "yrm9v", + "col743": "pkibu", + "col744": "u1p3f", + "col745": "uw2oo", + "col746": "l1e42", + "col747": "ce91h", + "col748": "li4kz", + "col749": "vkggn", + "col750": "dlllc", + "col751": "hkm3d", + "col752": "gd290", + "col753": "l1yre", + "col754": "3wozx", + "col755": "y66hq", + "col756": "q6e24", + "col757": "7j3qu", + "col758": "6i6oe", + "col759": "w202u", + "col760": "89vsk", + "col761": "m45hu", + "col762": "nweh4", + "col763": "41blr", + "col764": "htcqm", + "col765": "oulcx", + "col766": "q0voq", + "col767": "oz05r", + "col768": "m5ypy", + "col769": "edmh8", + "col770": "pu8zj", + "col771": "7fqcc", + "col772": "fgpge", + "col773": "2ky6v", + "col774": "yq2i6", + "col775": "q4j7q", + "col776": "cowb1", + "col777": "jszhr", + "col778": "joln0", + "col779": "hryv1", + "col780": "n4ghe", + "col781": "b561q", + "col782": "it2g1", + "col783": "gwdga", + "col784": "hrauv", + "col785": "v12gr", + "col786": "3ng6n", + "col787": "bsui0", + "col788": "zfpsx", + "col789": "s359m", + "col790": "dbbls", + "col791": "1ynsn", + "col792": "i5jly", + "col793": "vka0x", + "col794": "4d6md", + "col795": "5gc48", + "col796": "7ymn5", + "col797": "m91ty", + "col798": "qn4ez", + "col799": "7lf6c", + "col800": "o0shm", + "col801": "ny8fj", + "col802": "jmwyj", + "col803": "8sey0", + "col804": "mx6hm", + "col805": "7q0gs", + "col806": "bpzlh", + "col807": "7p358", + "col808": "zt7ac", + "col809": "rlugd", + "col810": "r0hiq", + "col811": "hjnng", + "col812": "3s9gd", + "col813": "ybns9", + "col814": "tk0iu", + "col815": "v6xhi", + "col816": "xm6ms", + "col817": "7lm2b", + "col818": "t8ypn", + "col819": "crkdi", + "col820": "2qmlz", + "col821": "ld3ks", + "col822": "1tiiu", + "col823": "p6yww", + "col824": "b0zd3", + "col825": "5d1lg", + "col826": "r66bh", + "col827": "c5gc2", + "col828": "4j2pq", + "col829": "2e62t", + "col830": "qboid", + "col831": "m9559", + "col832": "pviom", + "col833": "u05hv", + "col834": "y5h39", + "col835": "okj1r", + "col836": "dc498", + "col837": "j1al2", + "col838": "uldvh", + "col839": "613ka", + "col840": "9bozp", + "col841": "ox57t", + "col842": "pw4v3", + "col843": "zhbrs", + "col844": "r3qs3", + "col845": "mgp4b", + "col846": "iim2c", + "col847": "i26hs", + "col848": "wol74", + "col849": "d359x", + "col850": "2pjys", + "col851": "ubpdc", + "col852": "o71pd", + "col853": "wjq1x", + "col854": "w1irb", + "col855": "apgqx", + "col856": "7e5k9", + "col857": "crzol", + "col858": "6hsrt", + "col859": "q6i4x", + "col860": "gigb0", + "col861": "a6493", + "col862": "bq0i5", + "col863": "uyn9v", + "col864": "8wgkc", + "col865": "taf1y", + "col866": "ndb06", + "col867": "m4nqg", + "col868": "136t9", + "col869": "h4qmt", + "col870": "37ugm", + "col871": "4u1ei", + "col872": "oan0l", + "col873": "isz4c", + "col874": "ttyxw", + "col875": "sa2vx", + "col876": "bzj8k", + "col877": "44kcd", + "col878": "76fyo", + "col879": "cq66f", + "col880": "t08tq", + "col881": "akhw6", + "col882": "9lqdl", + "col883": "5se9y", + "col884": "7di78", + "col885": "1niz6", + "col886": "3vpmo", + "col887": "ozrae", + "col888": "ovg5p", + "col889": "wnvh2", + "col890": "inf0y", + "col891": "m3dcb", + "col892": "tok4o", + "col893": "8zozb", + "col894": "glkll", + "col895": "ow62u", + "col896": "gmfex", + "col897": "vgfx4", + "col898": "9110h", + "col899": "456z4", + "col900": "dlied", + "col901": "lp5wd", + "col902": "cu58h", + "col903": "r3hoh", + "col904": "r5gyf", + "col905": "jd6eg", + "col906": "e25mi", + "col907": "cmrwm", + "col908": "mergp", + "col909": "7t55e", + "col910": "g1geq", + "col911": "k6sw6", + "col912": "vzt39", + "col913": "80u7w", + "col914": "rtze9", + "col915": "9rh46", + "col916": "gfddc", + "col917": "rva8o", + "col918": "6ik49", + "col919": "xduda", + "col920": "1x628", + "col921": "jed8f", + "col922": "2avo0", + "col923": "55s8q", + "col924": "ffdb5", + "col925": "uzngz", + "col926": "sre03", + "col927": "8r2jq", + "col928": "az8hh", + "col929": "6k4qf", + "col930": "16e4k", + "col931": "pjtrt", + "col932": "axgfc", + "col933": "qaclk", + "col934": "f61ta", + "col935": "siqqt", + "col936": "jx7rx", + "col937": "zlwea", + "col938": "p2xms", + "col939": "duyib", + "col940": "u0d99", + "col941": "d5173", + "col942": "3m829", + "col943": "gjvpn", + "col944": "88cox", + "col945": "ocgme", + "col946": "1bu8y", + "col947": "3t4wn", + "col948": "iikd4", + "col949": "5bv7i", + "col950": "5ib2m", + "col951": "t38in", + "col952": "osghq", + "col953": "7j9d1", + "col954": "gxh5z", + "col955": "o6bys", + "col956": "ql8t3", + "col957": "gilso", + "col958": "smfgm", + "col959": "csk90", + "col960": "vfifd", + "col961": "46uye", + "col962": "rh6rz", + "col963": "wu7bx", + "col964": "uszqy", + "col965": "mdkdl", + "col966": "cku2q", + "col967": "303hv", + "col968": "3pi1e", + "col969": "81x3v", + "col970": "w0lbf", + "col971": "54j6f", + "col972": "j9ii2", + "col973": "ejyu6", + "col974": "ukm4o", + "col975": "8fyar", + "col976": "hav0y", + "col977": "awmxz", + "col978": "0wyh3", + "col979": "bqscv", + "col980": "yr9c7", + "col981": "5ixwp", + "col982": "zda1w", + "col983": "fpcxo", + "col984": "3yja9", + "col985": "ro8se", + "col986": "3o5de", + "col987": "jqxr8", + "col988": "ytdz0", + "col989": "z9y2s", + "col990": "w1zjr", + "col991": "it1zx", + "col992": "q3xyz", + "col993": "8jf3v", + "col994": "14aex", + "col995": "eib1r", + "col996": "5byjp", + "col997": "qz4kv", + "col998": "qsie8", + "col999": "i7n7d" + }, + { + "name": "Parrish Andrews", + "gender": "male", + "col0": "4wvvm", + "col1": "dtlw1", + "col2": "ex583", + "col3": "alwpj", + "col4": "vu8tx", + "col5": "iqbnc", + "col6": "vfq5t", + "col7": "da3af", + "col8": "v2jy9", + "col9": "p6sa4", + "col10": "8ddam", + "col11": "pc7dk", + "col12": "ivbs9", + "col13": "84syu", + "col14": "d72sm", + "col15": "3bkkt", + "col16": "yqoh3", + "col17": "7m39o", + "col18": "nhjn8", + "col19": "bo8a4", + "col20": "l9003", + "col21": "ufw12", + "col22": "0q3n1", + "col23": "q4ejc", + "col24": "ch5z9", + "col25": "j2uki", + "col26": "7vhyo", + "col27": "y50ol", + "col28": "3j8y9", + "col29": "3ny7g", + "col30": "pnqmk", + "col31": "ll66u", + "col32": "uk3c2", + "col33": "2akeu", + "col34": "z74zy", + "col35": "1n043", + "col36": "v4rko", + "col37": "u5r72", + "col38": "trjhr", + "col39": "9wqnj", + "col40": "s038p", + "col41": "iflj4", + "col42": "uz2fe", + "col43": "qi85s", + "col44": "jqrwl", + "col45": "udh0g", + "col46": "n5w5p", + "col47": "twx2n", + "col48": "n58fw", + "col49": "uxsyb", + "col50": "9yflz", + "col51": "gnu42", + "col52": "41g2a", + "col53": "e27e5", + "col54": "4zda3", + "col55": "mfez6", + "col56": "kg2ov", + "col57": "pfuc7", + "col58": "i3z2z", + "col59": "c1hyt", + "col60": "xxblu", + "col61": "ljaa5", + "col62": "hslbe", + "col63": "y9fgd", + "col64": "561wd", + "col65": "0sftr", + "col66": "i11bt", + "col67": "ang81", + "col68": "imirp", + "col69": "bbeml", + "col70": "dxb3d", + "col71": "lqxzh", + "col72": "m7fhx", + "col73": "kcc3n", + "col74": "3mxkj", + "col75": "oxnhh", + "col76": "reeji", + "col77": "78i97", + "col78": "vohk9", + "col79": "abnwd", + "col80": "aywnu", + "col81": "yshkf", + "col82": "ami26", + "col83": "h0q8a", + "col84": "k8e16", + "col85": "zr3ls", + "col86": "q6131", + "col87": "7alxo", + "col88": "09skx", + "col89": "smxyk", + "col90": "wasz0", + "col91": "h7av1", + "col92": "ktdbh", + "col93": "8texf", + "col94": "xoi1j", + "col95": "2tm73", + "col96": "dbe8m", + "col97": "6lghp", + "col98": "xvqma", + "col99": "e0wvl", + "col100": "wb34g", + "col101": "tqbii", + "col102": "2ol4o", + "col103": "w2dib", + "col104": "fews2", + "col105": "g3hgz", + "col106": "tr61p", + "col107": "srf4h", + "col108": "514gg", + "col109": "2baf0", + "col110": "0yryb", + "col111": "hr8go", + "col112": "rgekj", + "col113": "l2qya", + "col114": "zykzt", + "col115": "d1846", + "col116": "4h9uu", + "col117": "a5ob1", + "col118": "ohdq4", + "col119": "h8qj4", + "col120": "gbuiu", + "col121": "4qpkl", + "col122": "3ie5a", + "col123": "iflqp", + "col124": "j4klj", + "col125": "8rws7", + "col126": "gb3hg", + "col127": "bxhnj", + "col128": "vuq25", + "col129": "2zftz", + "col130": "qxmvj", + "col131": "oaluf", + "col132": "tzgbj", + "col133": "rc3b8", + "col134": "gcndp", + "col135": "81k3h", + "col136": "3vske", + "col137": "kvxwa", + "col138": "rewfx", + "col139": "mm5kf", + "col140": "9gt64", + "col141": "1aogi", + "col142": "3ijug", + "col143": "pruhm", + "col144": "qedeo", + "col145": "dcj6d", + "col146": "6t21j", + "col147": "stn4y", + "col148": "rslar", + "col149": "fcxfq", + "col150": "o5q8d", + "col151": "qfq4h", + "col152": "5kipu", + "col153": "4onab", + "col154": "33q92", + "col155": "wifsz", + "col156": "j7ece", + "col157": "833hu", + "col158": "lkv1e", + "col159": "wi8c2", + "col160": "yhmio", + "col161": "we0r9", + "col162": "gjen3", + "col163": "esw7n", + "col164": "4vfwj", + "col165": "v3rrb", + "col166": "s5rj1", + "col167": "hmh4l", + "col168": "rym7h", + "col169": "vadz8", + "col170": "kqquh", + "col171": "d43z3", + "col172": "fp3me", + "col173": "tp42r", + "col174": "sqfs8", + "col175": "x3e4u", + "col176": "v7ng5", + "col177": "4z5qc", + "col178": "c8zr8", + "col179": "a519e", + "col180": "tg28r", + "col181": "mvo7b", + "col182": "vpqg4", + "col183": "9yol5", + "col184": "ob8gm", + "col185": "cf51f", + "col186": "sp0ll", + "col187": "242xg", + "col188": "vqplg", + "col189": "w64a9", + "col190": "7m71a", + "col191": "azs8s", + "col192": "4bdri", + "col193": "6d628", + "col194": "rjzh6", + "col195": "drups", + "col196": "ctogj", + "col197": "xh1at", + "col198": "hb4yy", + "col199": "zctvx", + "col200": "rksvq", + "col201": "tve6s", + "col202": "chthr", + "col203": "7ai9d", + "col204": "sb5k9", + "col205": "585vn", + "col206": "vo2tn", + "col207": "mhzuc", + "col208": "y9unj", + "col209": "vduu5", + "col210": "7kb4y", + "col211": "y7ukq", + "col212": "1cbes", + "col213": "dwecg", + "col214": "u94iq", + "col215": "grzkd", + "col216": "m2vwh", + "col217": "4991x", + "col218": "aeput", + "col219": "b5r65", + "col220": "se31i", + "col221": "2gphi", + "col222": "991il", + "col223": "lsahh", + "col224": "lz0tc", + "col225": "4uv93", + "col226": "mhf2n", + "col227": "14cix", + "col228": "rkd8s", + "col229": "ah8t8", + "col230": "giknu", + "col231": "t5ek2", + "col232": "tf0sm", + "col233": "hr17z", + "col234": "jk2v3", + "col235": "qqd5g", + "col236": "fgdyp", + "col237": "mc9ju", + "col238": "h9mjn", + "col239": "cubfh", + "col240": "t55yf", + "col241": "fxuvz", + "col242": "lv8vo", + "col243": "939cv", + "col244": "m8ifc", + "col245": "xwh1x", + "col246": "8u1z6", + "col247": "3jvwk", + "col248": "nxeu1", + "col249": "9ahsm", + "col250": "4ip6n", + "col251": "z9yzf", + "col252": "05kec", + "col253": "zu1vg", + "col254": "mm59f", + "col255": "p8cnk", + "col256": "ufwu6", + "col257": "edr8w", + "col258": "nwiqk", + "col259": "iksdy", + "col260": "0pt9x", + "col261": "3pc9c", + "col262": "2hqa1", + "col263": "aabl4", + "col264": "td2yn", + "col265": "dcjih", + "col266": "p77eq", + "col267": "5qyer", + "col268": "o2hjo", + "col269": "xkxnw", + "col270": "7tpiu", + "col271": "epthz", + "col272": "ulsh0", + "col273": "tqabu", + "col274": "alqxg", + "col275": "mndea", + "col276": "rnwiv", + "col277": "y60yz", + "col278": "4faef", + "col279": "7qigl", + "col280": "80kco", + "col281": "63v6v", + "col282": "jcydn", + "col283": "db0v8", + "col284": "syno5", + "col285": "9r8qu", + "col286": "1s56g", + "col287": "yautp", + "col288": "axzf9", + "col289": "6q4xd", + "col290": "dk76n", + "col291": "afyal", + "col292": "0mvhu", + "col293": "6x225", + "col294": "tctrf", + "col295": "2gsio", + "col296": "g6hnf", + "col297": "rbkx5", + "col298": "qz5p4", + "col299": "rwk6z", + "col300": "xzbwu", + "col301": "lq31e", + "col302": "js5hm", + "col303": "6nnrc", + "col304": "lbg87", + "col305": "dpnri", + "col306": "5dm8s", + "col307": "vvoy1", + "col308": "jzesy", + "col309": "su57v", + "col310": "6yh0r", + "col311": "hchsr", + "col312": "i4k0e", + "col313": "pf91r", + "col314": "oepuh", + "col315": "btwzv", + "col316": "hamiq", + "col317": "9fq66", + "col318": "ync5j", + "col319": "xfcpo", + "col320": "z26xh", + "col321": "8cwwq", + "col322": "0ofnz", + "col323": "s955j", + "col324": "hnl86", + "col325": "qn5v3", + "col326": "agopg", + "col327": "n7fsh", + "col328": "q7gbk", + "col329": "tyj7r", + "col330": "y4ybk", + "col331": "ak42w", + "col332": "2ttvm", + "col333": "6rwvt", + "col334": "zmour", + "col335": "5z9sy", + "col336": "i8vc2", + "col337": "oi1gu", + "col338": "gpbrq", + "col339": "pv3ty", + "col340": "xo0wf", + "col341": "io6l3", + "col342": "mux76", + "col343": "7a0rc", + "col344": "bbb5z", + "col345": "bmpuf", + "col346": "eddr6", + "col347": "svv63", + "col348": "h6en6", + "col349": "11dqi", + "col350": "jw0v4", + "col351": "o9qrs", + "col352": "5te8j", + "col353": "0y8pl", + "col354": "78r49", + "col355": "daz4b", + "col356": "pl1wn", + "col357": "w699v", + "col358": "gpiwc", + "col359": "zfpdq", + "col360": "eed1x", + "col361": "9yb6y", + "col362": "8rnxc", + "col363": "dufpf", + "col364": "d3slg", + "col365": "zoj8f", + "col366": "xpw3o", + "col367": "nxh47", + "col368": "qvdub", + "col369": "f9abf", + "col370": "nvnjq", + "col371": "bo916", + "col372": "2xbil", + "col373": "zob7t", + "col374": "zzrop", + "col375": "oxgi8", + "col376": "30yn9", + "col377": "bsgtq", + "col378": "8mdza", + "col379": "0ta0o", + "col380": "b30dg", + "col381": "vz0n1", + "col382": "kx706", + "col383": "4k9dd", + "col384": "3huif", + "col385": "mtijq", + "col386": "vbg65", + "col387": "w8vux", + "col388": "5e3ag", + "col389": "f1o22", + "col390": "hxs9p", + "col391": "av4v2", + "col392": "9ac7m", + "col393": "ho3wo", + "col394": "uc2o0", + "col395": "bh6r5", + "col396": "8qdx0", + "col397": "jv0ze", + "col398": "8ghnw", + "col399": "frjsp", + "col400": "pm76t", + "col401": "dy5d0", + "col402": "uddz5", + "col403": "e0pik", + "col404": "s1qfs", + "col405": "4movm", + "col406": "2p6nc", + "col407": "h923t", + "col408": "dfxh6", + "col409": "uc6k6", + "col410": "w0loj", + "col411": "m8ui4", + "col412": "nem1u", + "col413": "xs6rq", + "col414": "thxas", + "col415": "xmv0r", + "col416": "nje0d", + "col417": "30lrb", + "col418": "krgpe", + "col419": "0p6g7", + "col420": "c4kd8", + "col421": "5xcyo", + "col422": "p3h2m", + "col423": "m389h", + "col424": "rbust", + "col425": "rns0x", + "col426": "2ulld", + "col427": "kfc5i", + "col428": "62r3h", + "col429": "37yn1", + "col430": "ydixb", + "col431": "yffal", + "col432": "8rogp", + "col433": "84fi8", + "col434": "wab61", + "col435": "hk7h1", + "col436": "0tijn", + "col437": "dhbum", + "col438": "obetx", + "col439": "vqmd7", + "col440": "j5h8f", + "col441": "qaias", + "col442": "pre3d", + "col443": "0behz", + "col444": "iu5fz", + "col445": "ifa7e", + "col446": "z9pl4", + "col447": "pxsp6", + "col448": "4zfc4", + "col449": "7b1fw", + "col450": "bqo8n", + "col451": "1eplp", + "col452": "37isl", + "col453": "cbjew", + "col454": "off0c", + "col455": "w49q1", + "col456": "82q62", + "col457": "1wzoy", + "col458": "6jt1q", + "col459": "qg1x6", + "col460": "9qg4x", + "col461": "ko2eh", + "col462": "hie3u", + "col463": "7lspl", + "col464": "3py8g", + "col465": "z3wjx", + "col466": "6ub74", + "col467": "qsg6i", + "col468": "q0h2v", + "col469": "291o5", + "col470": "1z5cb", + "col471": "bi180", + "col472": "fi34z", + "col473": "we1aa", + "col474": "toi0z", + "col475": "l4jpm", + "col476": "qjxyg", + "col477": "dq6uk", + "col478": "9xgks", + "col479": "8ylxz", + "col480": "j3f1k", + "col481": "k0x2v", + "col482": "ekhhn", + "col483": "8s6cr", + "col484": "qmcjr", + "col485": "sg191", + "col486": "nhgwa", + "col487": "fub5d", + "col488": "0yr4q", + "col489": "j0o59", + "col490": "8ztbp", + "col491": "6vbro", + "col492": "rfi5o", + "col493": "3d5sa", + "col494": "q9qn8", + "col495": "ndq5m", + "col496": "xn8h4", + "col497": "mif9u", + "col498": "c1t4d", + "col499": "sauxy", + "col500": "cjalj", + "col501": "iqhrm", + "col502": "lt3qj", + "col503": "gpht9", + "col504": "9ymdo", + "col505": "ayir5", + "col506": "nz28a", + "col507": "833i0", + "col508": "cvbte", + "col509": "8jh1i", + "col510": "434tz", + "col511": "g1y1l", + "col512": "s4p1g", + "col513": "lfjjk", + "col514": "6zi2a", + "col515": "29bq2", + "col516": "d9sgu", + "col517": "7z211", + "col518": "0sdxa", + "col519": "18ulo", + "col520": "ojctj", + "col521": "be52i", + "col522": "rr1gl", + "col523": "ymais", + "col524": "qgkgj", + "col525": "5lhv7", + "col526": "ihxbd", + "col527": "g5fmf", + "col528": "nve40", + "col529": "kexo0", + "col530": "m6112", + "col531": "c8mx2", + "col532": "47sha", + "col533": "xfa91", + "col534": "t33v5", + "col535": "1oqlx", + "col536": "cqnya", + "col537": "leebf", + "col538": "ozd31", + "col539": "bijzj", + "col540": "3aj8v", + "col541": "nucry", + "col542": "iy4sp", + "col543": "8zjs4", + "col544": "hun9c", + "col545": "er5ij", + "col546": "6v8xg", + "col547": "ovvrl", + "col548": "meg9x", + "col549": "n3gdf", + "col550": "my20q", + "col551": "7yal6", + "col552": "d1bnb", + "col553": "ddab3", + "col554": "tj4k2", + "col555": "i7ax4", + "col556": "hjmjk", + "col557": "dvk2o", + "col558": "f2q7r", + "col559": "ougyg", + "col560": "ohlec", + "col561": "r4q80", + "col562": "s6rqp", + "col563": "eee6a", + "col564": "svikt", + "col565": "j0mlm", + "col566": "cmk4c", + "col567": "6bmes", + "col568": "gcmi9", + "col569": "fllsh", + "col570": "2vlrg", + "col571": "e2sb6", + "col572": "1v2gr", + "col573": "glvul", + "col574": "3iakj", + "col575": "ckn3f", + "col576": "xu2rx", + "col577": "81zwg", + "col578": "g3hwy", + "col579": "cna7o", + "col580": "ee2oh", + "col581": "9kwdk", + "col582": "erfls", + "col583": "b4jke", + "col584": "5usc7", + "col585": "uz7rl", + "col586": "5c7o3", + "col587": "fjr5u", + "col588": "ow1kb", + "col589": "x4eo7", + "col590": "jmme9", + "col591": "uqs47", + "col592": "pj5o7", + "col593": "zdrg3", + "col594": "hprjb", + "col595": "oavmm", + "col596": "lfkgc", + "col597": "v0e2e", + "col598": "ux7ba", + "col599": "mh1lq", + "col600": "hqzig", + "col601": "fzava", + "col602": "ahwet", + "col603": "kj1f8", + "col604": "i9rp2", + "col605": "uopou", + "col606": "z9xzn", + "col607": "ya4ff", + "col608": "ixejc", + "col609": "0i5i2", + "col610": "osizq", + "col611": "3pqt0", + "col612": "lk7s4", + "col613": "84eku", + "col614": "vp92t", + "col615": "8jq48", + "col616": "grra7", + "col617": "8lfym", + "col618": "zase3", + "col619": "jcfyx", + "col620": "zx44d", + "col621": "i8gya", + "col622": "elsst", + "col623": "pa2i4", + "col624": "e1534", + "col625": "lf225", + "col626": "gnqwp", + "col627": "dznbm", + "col628": "yqkgb", + "col629": "urc7t", + "col630": "a94uv", + "col631": "gvg12", + "col632": "miaaj", + "col633": "y7duy", + "col634": "92q9y", + "col635": "6nrqj", + "col636": "mhdtf", + "col637": "z443l", + "col638": "ehjsc", + "col639": "ay0cv", + "col640": "xtmqg", + "col641": "7sjzs", + "col642": "r18m1", + "col643": "hiyss", + "col644": "p0r6r", + "col645": "0lltd", + "col646": "z06td", + "col647": "ayuq6", + "col648": "gkw3i", + "col649": "o37mx", + "col650": "1yfx7", + "col651": "vaizw", + "col652": "u6swh", + "col653": "6qztr", + "col654": "g1acq", + "col655": "0or78", + "col656": "5z9ay", + "col657": "l1sv1", + "col658": "xqad7", + "col659": "m63z3", + "col660": "972oy", + "col661": "n47sp", + "col662": "tsg3w", + "col663": "mmdee", + "col664": "uz9ts", + "col665": "2hgf6", + "col666": "vei7p", + "col667": "8g9xp", + "col668": "y4w65", + "col669": "cykcx", + "col670": "4c8hv", + "col671": "e27oi", + "col672": "hm24q", + "col673": "fto66", + "col674": "opgqk", + "col675": "cp4q4", + "col676": "99xdl", + "col677": "seo7f", + "col678": "7jfep", + "col679": "xrnuc", + "col680": "yj40n", + "col681": "m1bu6", + "col682": "2cfv3", + "col683": "kaci0", + "col684": "txq33", + "col685": "9ewmg", + "col686": "472kp", + "col687": "162ic", + "col688": "qq0zb", + "col689": "dsrj2", + "col690": "nw3yi", + "col691": "q4tcz", + "col692": "b7tqc", + "col693": "98nhe", + "col694": "ij0l5", + "col695": "y9a2b", + "col696": "emyag", + "col697": "ezigc", + "col698": "iyjdn", + "col699": "ysrdo", + "col700": "jf2ix", + "col701": "5aonm", + "col702": "aheh0", + "col703": "w0vvo", + "col704": "sakpr", + "col705": "yzrge", + "col706": "ysxrs", + "col707": "17hvf", + "col708": "4h8oi", + "col709": "wtkez", + "col710": "nt5h9", + "col711": "6t3ro", + "col712": "8aaj5", + "col713": "txy44", + "col714": "5z34o", + "col715": "lrup2", + "col716": "hvfal", + "col717": "tpmqh", + "col718": "hdlh0", + "col719": "bg4w6", + "col720": "d4h09", + "col721": "2vlxe", + "col722": "8d9fx", + "col723": "mhu5w", + "col724": "eghgy", + "col725": "qc3m6", + "col726": "4hf3d", + "col727": "c4o2w", + "col728": "085ym", + "col729": "hbz3j", + "col730": "s7q5z", + "col731": "x030n", + "col732": "as0zm", + "col733": "o324k", + "col734": "4l3xj", + "col735": "3zv4q", + "col736": "77ix8", + "col737": "h8f8t", + "col738": "ch6re", + "col739": "92mux", + "col740": "evtot", + "col741": "evh5a", + "col742": "y8zkg", + "col743": "r4oye", + "col744": "au1jb", + "col745": "n8dcn", + "col746": "94viv", + "col747": "hpe64", + "col748": "w8ceg", + "col749": "qz58p", + "col750": "o9634", + "col751": "jr8dj", + "col752": "dmp10", + "col753": "qcl2k", + "col754": "qnc7v", + "col755": "r2qz3", + "col756": "el9gt", + "col757": "to5te", + "col758": "9lkbw", + "col759": "q9l3a", + "col760": "rq39a", + "col761": "zv3te", + "col762": "rbde3", + "col763": "z2j6s", + "col764": "fq8fm", + "col765": "3hs1t", + "col766": "5ux8f", + "col767": "x00lr", + "col768": "phmky", + "col769": "z1b86", + "col770": "40lap", + "col771": "c1bda", + "col772": "loysl", + "col773": "p1o8l", + "col774": "nysrz", + "col775": "nvqfq", + "col776": "4u76q", + "col777": "88rpt", + "col778": "7h2fh", + "col779": "lnx5g", + "col780": "o905c", + "col781": "ne2de", + "col782": "g6zfu", + "col783": "ylsyb", + "col784": "fwdxo", + "col785": "344rd", + "col786": "hvryg", + "col787": "obiqm", + "col788": "8n9n3", + "col789": "ggzhq", + "col790": "mn9jc", + "col791": "ayk3k", + "col792": "j44c3", + "col793": "gx2ei", + "col794": "454bv", + "col795": "bna5i", + "col796": "hyzp7", + "col797": "1temk", + "col798": "7jsli", + "col799": "ehfoq", + "col800": "mk7yx", + "col801": "z6wgi", + "col802": "arhjx", + "col803": "qmfjn", + "col804": "vi9pe", + "col805": "odiw9", + "col806": "kraim", + "col807": "obcdt", + "col808": "65z6w", + "col809": "7w85x", + "col810": "8fx71", + "col811": "4bi83", + "col812": "juc8n", + "col813": "kxeet", + "col814": "dmpov", + "col815": "frp2z", + "col816": "zcyce", + "col817": "zg7ps", + "col818": "nk55e", + "col819": "oycfo", + "col820": "wo3cf", + "col821": "vzp1w", + "col822": "krlj0", + "col823": "ziihv", + "col824": "vuxeu", + "col825": "4g3c9", + "col826": "mmyo4", + "col827": "3juh3", + "col828": "a7jab", + "col829": "nd9x8", + "col830": "eauig", + "col831": "9uirv", + "col832": "n00sj", + "col833": "51jwu", + "col834": "s4duk", + "col835": "f6b8r", + "col836": "i13b9", + "col837": "8rvsv", + "col838": "dhsc7", + "col839": "kghxu", + "col840": "067cm", + "col841": "7ypvc", + "col842": "rfv1k", + "col843": "rsvge", + "col844": "3z2m4", + "col845": "91l6u", + "col846": "kimad", + "col847": "fjol8", + "col848": "7ekzf", + "col849": "nz3r3", + "col850": "22puu", + "col851": "3e5dz", + "col852": "8oric", + "col853": "9z0fa", + "col854": "yhtv6", + "col855": "fz1sk", + "col856": "dmaif", + "col857": "om6tc", + "col858": "9cydy", + "col859": "1xe40", + "col860": "u64ke", + "col861": "jshk0", + "col862": "n3s5v", + "col863": "mw9g4", + "col864": "uj1mw", + "col865": "ppx5h", + "col866": "s4krh", + "col867": "ic0m9", + "col868": "bolaw", + "col869": "fgz9x", + "col870": "kd8do", + "col871": "kl3u8", + "col872": "3dequ", + "col873": "sf2oo", + "col874": "6klb7", + "col875": "kwn2u", + "col876": "11qja", + "col877": "bkjdn", + "col878": "xeiqk", + "col879": "x5oih", + "col880": "yugek", + "col881": "014v6", + "col882": "47ywf", + "col883": "hdlp0", + "col884": "didz0", + "col885": "zzh7x", + "col886": "w9dq4", + "col887": "lk5c3", + "col888": "jgghs", + "col889": "lvsdf", + "col890": "gjgzs", + "col891": "b07qg", + "col892": "f0cmq", + "col893": "cjohn", + "col894": "d74sq", + "col895": "3olnu", + "col896": "x35me", + "col897": "ltbv0", + "col898": "i3sj4", + "col899": "a97ve", + "col900": "j4wl9", + "col901": "jpxu0", + "col902": "ins47", + "col903": "38jb7", + "col904": "ci4y5", + "col905": "5k7ku", + "col906": "p7qhk", + "col907": "z541q", + "col908": "84462", + "col909": "7z9sm", + "col910": "6s8v4", + "col911": "wq4t2", + "col912": "vv0t9", + "col913": "7tjhr", + "col914": "vwcj4", + "col915": "ehrdu", + "col916": "pvn6o", + "col917": "g2fuh", + "col918": "s4nme", + "col919": "rbn3j", + "col920": "1u45i", + "col921": "oxez7", + "col922": "kc00c", + "col923": "dr8s9", + "col924": "dlsq4", + "col925": "cichg", + "col926": "5ukle", + "col927": "6d6t2", + "col928": "kgcsn", + "col929": "cgwgi", + "col930": "5wx57", + "col931": "ueg5f", + "col932": "yr8s0", + "col933": "y6gsb", + "col934": "5ceyd", + "col935": "ys3ue", + "col936": "tbl9k", + "col937": "dbc87", + "col938": "3y3lw", + "col939": "ds4bk", + "col940": "mueu6", + "col941": "rx1tz", + "col942": "bp0vv", + "col943": "7wy1g", + "col944": "iv6dq", + "col945": "f1rhb", + "col946": "nc2yr", + "col947": "4g465", + "col948": "uaq8i", + "col949": "j9mvt", + "col950": "7affb", + "col951": "iiomc", + "col952": "21ygz", + "col953": "gfw3s", + "col954": "w6rsd", + "col955": "9q1v6", + "col956": "6j9sz", + "col957": "c451h", + "col958": "pb4b6", + "col959": "uff24", + "col960": "afzcf", + "col961": "mwkoc", + "col962": "02no3", + "col963": "mt6lg", + "col964": "g9rd8", + "col965": "n647z", + "col966": "se9z8", + "col967": "42r8t", + "col968": "oafms", + "col969": "sq39z", + "col970": "hhr8r", + "col971": "hnznt", + "col972": "fx9xx", + "col973": "n3srx", + "col974": "obufa", + "col975": "go0ak", + "col976": "du8cq", + "col977": "stfab", + "col978": "1dklp", + "col979": "vwdpm", + "col980": "561wl", + "col981": "04ro2", + "col982": "6vj9m", + "col983": "tvta0", + "col984": "tzg22", + "col985": "ld81w", + "col986": "b22tk", + "col987": "ahc1q", + "col988": "10bif", + "col989": "ayxq3", + "col990": "is0t8", + "col991": "tvhl4", + "col992": "o8915", + "col993": "eabn4", + "col994": "jjjca", + "col995": "f5948", + "col996": "imhk7", + "col997": "fy3w3", + "col998": "svmqf", + "col999": "xmvoa" + }, + { + "name": "Terra Webster", + "gender": "female", + "col0": "zwvis", + "col1": "otqrx", + "col2": "3uicq", + "col3": "q4wpy", + "col4": "rcghw", + "col5": "3es1e", + "col6": "8sd6a", + "col7": "8cwlv", + "col8": "8ep33", + "col9": "vr5b2", + "col10": "l6qst", + "col11": "a98i6", + "col12": "2fhww", + "col13": "yvl6z", + "col14": "2o0ua", + "col15": "ueny4", + "col16": "7sl07", + "col17": "k71u3", + "col18": "3mzkx", + "col19": "o0yzq", + "col20": "g3dbh", + "col21": "2wru1", + "col22": "6zhow", + "col23": "x3emh", + "col24": "j9gpu", + "col25": "359l7", + "col26": "9y6c5", + "col27": "zu84s", + "col28": "2nzeq", + "col29": "d3z5y", + "col30": "mfh23", + "col31": "jc2yq", + "col32": "i8imb", + "col33": "z2ret", + "col34": "n50c5", + "col35": "lkgrs", + "col36": "pzm2u", + "col37": "tnay8", + "col38": "5mp8u", + "col39": "c5km7", + "col40": "9c1ql", + "col41": "jrxve", + "col42": "icqaz", + "col43": "878ih", + "col44": "cs0ms", + "col45": "1p8e6", + "col46": "kju8f", + "col47": "gb0ee", + "col48": "jgjsl", + "col49": "ej4mv", + "col50": "v0bmg", + "col51": "29hze", + "col52": "5os3w", + "col53": "byqyq", + "col54": "ia6ep", + "col55": "c6ls0", + "col56": "najfd", + "col57": "56jvo", + "col58": "97wjr", + "col59": "czanh", + "col60": "7x1tt", + "col61": "ndjh1", + "col62": "a6t08", + "col63": "7gr2k", + "col64": "j0ol8", + "col65": "4x4kf", + "col66": "vinos", + "col67": "32tzu", + "col68": "nof8v", + "col69": "bijw2", + "col70": "qdqyx", + "col71": "w8oo4", + "col72": "1lmpt", + "col73": "gothz", + "col74": "x313y", + "col75": "r6dtc", + "col76": "h9xp0", + "col77": "ccyph", + "col78": "q1mg9", + "col79": "kc3wg", + "col80": "7b850", + "col81": "vumj8", + "col82": "2kcdx", + "col83": "so6gh", + "col84": "esvfm", + "col85": "j5s7c", + "col86": "4ojsv", + "col87": "xq17j", + "col88": "colk2", + "col89": "q9i9q", + "col90": "5zzhy", + "col91": "gznl8", + "col92": "gws3i", + "col93": "aeg63", + "col94": "ko4ec", + "col95": "oct62", + "col96": "qf2d3", + "col97": "lu3xp", + "col98": "j8shn", + "col99": "l8ijq", + "col100": "q2yzl", + "col101": "nvqry", + "col102": "lcpwz", + "col103": "aeyva", + "col104": "pv9g4", + "col105": "oagte", + "col106": "8u7hu", + "col107": "e6wsb", + "col108": "0um30", + "col109": "om1e3", + "col110": "sh7c1", + "col111": "35aez", + "col112": "hjb5v", + "col113": "vl276", + "col114": "kltft", + "col115": "vb4wn", + "col116": "wlc9f", + "col117": "qltme", + "col118": "gxp55", + "col119": "0xdjq", + "col120": "0oqo1", + "col121": "ebc1g", + "col122": "nepfs", + "col123": "ponbw", + "col124": "asebt", + "col125": "04xi6", + "col126": "fvkj9", + "col127": "rdhiw", + "col128": "02lnq", + "col129": "j1d3h", + "col130": "p5orb", + "col131": "xyq4u", + "col132": "fcvv9", + "col133": "t99ir", + "col134": "6fqt2", + "col135": "7em9p", + "col136": "8vxqo", + "col137": "ssrow", + "col138": "b6s0u", + "col139": "fh7u7", + "col140": "k4vg1", + "col141": "a3yva", + "col142": "dophe", + "col143": "qybif", + "col144": "l3tuf", + "col145": "4d41w", + "col146": "5wwjl", + "col147": "km2t1", + "col148": "upsjp", + "col149": "4gyx6", + "col150": "60gsj", + "col151": "jw6xa", + "col152": "nx5ou", + "col153": "tv8tn", + "col154": "qml3n", + "col155": "446l6", + "col156": "5kamm", + "col157": "ji06o", + "col158": "j9jwd", + "col159": "55b0w", + "col160": "w4cs8", + "col161": "3gzlr", + "col162": "ftu4f", + "col163": "bi0kc", + "col164": "k8cwu", + "col165": "t71dd", + "col166": "zkvrc", + "col167": "4ou63", + "col168": "lew70", + "col169": "0qgwg", + "col170": "lrvky", + "col171": "1csgi", + "col172": "9derm", + "col173": "fbscz", + "col174": "nqsri", + "col175": "7zu5o", + "col176": "z6dbu", + "col177": "a9q1t", + "col178": "aaiyd", + "col179": "wb0rk", + "col180": "m12yl", + "col181": "f8h87", + "col182": "6zf59", + "col183": "vifrk", + "col184": "69apl", + "col185": "wp8w1", + "col186": "7035f", + "col187": "digzr", + "col188": "18sen", + "col189": "sybfa", + "col190": "gmcdi", + "col191": "kwqzl", + "col192": "xyn0t", + "col193": "hjt70", + "col194": "t2wq6", + "col195": "mg7wr", + "col196": "wo8fe", + "col197": "w2f4t", + "col198": "ufopi", + "col199": "xy7h8", + "col200": "7un0v", + "col201": "g2vxz", + "col202": "tkneb", + "col203": "ari26", + "col204": "bn0g3", + "col205": "jwyo5", + "col206": "ax5dz", + "col207": "i5fmo", + "col208": "hd3zq", + "col209": "0vy5x", + "col210": "t2qxx", + "col211": "eiubl", + "col212": "om54e", + "col213": "czm5b", + "col214": "6892n", + "col215": "zjh83", + "col216": "ams2g", + "col217": "17je5", + "col218": "csocs", + "col219": "1z32a", + "col220": "ud6sa", + "col221": "daa02", + "col222": "27e4m", + "col223": "ybjzj", + "col224": "2dnze", + "col225": "kmsq4", + "col226": "ijh44", + "col227": "m6r1y", + "col228": "umzfe", + "col229": "h1xnf", + "col230": "b1xxo", + "col231": "3hgrq", + "col232": "0hyq0", + "col233": "s3zbf", + "col234": "36wbu", + "col235": "hjizg", + "col236": "yvovg", + "col237": "3i2sc", + "col238": "2pg3z", + "col239": "0x168", + "col240": "g46bc", + "col241": "ylg4b", + "col242": "hplov", + "col243": "vphd9", + "col244": "m152j", + "col245": "e761u", + "col246": "r0mxa", + "col247": "ekv2n", + "col248": "xzul8", + "col249": "b2cdq", + "col250": "ixbua", + "col251": "9yfuw", + "col252": "qq82d", + "col253": "w2uap", + "col254": "l27n9", + "col255": "36c32", + "col256": "hi466", + "col257": "8pl7x", + "col258": "0z735", + "col259": "0wyzx", + "col260": "wfeaa", + "col261": "ptagz", + "col262": "w5iqx", + "col263": "vcczy", + "col264": "skz9i", + "col265": "mm2hq", + "col266": "j23ls", + "col267": "p9pr1", + "col268": "r54ag", + "col269": "x8f1q", + "col270": "yde6q", + "col271": "nl7ud", + "col272": "38f6p", + "col273": "s5t33", + "col274": "bhtf0", + "col275": "dq8yi", + "col276": "zudf0", + "col277": "702fk", + "col278": "jenlu", + "col279": "zdmcc", + "col280": "2osn0", + "col281": "01wf8", + "col282": "puurz", + "col283": "40yhu", + "col284": "sl5bc", + "col285": "mfg39", + "col286": "bz09m", + "col287": "by6y5", + "col288": "yibfy", + "col289": "9kw2x", + "col290": "v9za1", + "col291": "nc1mk", + "col292": "mdy99", + "col293": "ipbe4", + "col294": "0sz7i", + "col295": "zsu6r", + "col296": "jzm79", + "col297": "4qq6i", + "col298": "4j56f", + "col299": "cvj14", + "col300": "fupkr", + "col301": "g913k", + "col302": "yxhy2", + "col303": "y4ubl", + "col304": "5aa4o", + "col305": "9ra4a", + "col306": "wtjg9", + "col307": "57e40", + "col308": "txhg2", + "col309": "xrzgv", + "col310": "6bgqs", + "col311": "vih65", + "col312": "tivmq", + "col313": "8au05", + "col314": "p6gyp", + "col315": "8063p", + "col316": "l75w9", + "col317": "fzox1", + "col318": "zl9su", + "col319": "qs3fz", + "col320": "ptn2o", + "col321": "b6ho2", + "col322": "d3osi", + "col323": "prn03", + "col324": "o5aox", + "col325": "122qv", + "col326": "kofms", + "col327": "mffu5", + "col328": "jsyy3", + "col329": "rezft", + "col330": "qgp78", + "col331": "zcdui", + "col332": "a8vk3", + "col333": "t5ieh", + "col334": "vtjfj", + "col335": "sfm3p", + "col336": "2jebb", + "col337": "ixhl7", + "col338": "uxrgb", + "col339": "pkpsb", + "col340": "lcr2w", + "col341": "k22j1", + "col342": "ivhcl", + "col343": "2evkj", + "col344": "qnrjr", + "col345": "9b1fo", + "col346": "3cqx2", + "col347": "qfblw", + "col348": "p1yjh", + "col349": "3dm3b", + "col350": "c03cb", + "col351": "l7wxx", + "col352": "igljv", + "col353": "ogf2i", + "col354": "loc6a", + "col355": "3p7x7", + "col356": "hllmp", + "col357": "vk5yy", + "col358": "8gf00", + "col359": "txktm", + "col360": "ked22", + "col361": "fqvaw", + "col362": "mklr0", + "col363": "v7b61", + "col364": "c9qgl", + "col365": "dsd7c", + "col366": "44ktj", + "col367": "7oi14", + "col368": "75aw8", + "col369": "rlzgl", + "col370": "78xj9", + "col371": "dzdxp", + "col372": "ukf88", + "col373": "3czak", + "col374": "gc30q", + "col375": "gp77v", + "col376": "zd0kn", + "col377": "78ks2", + "col378": "7xsjb", + "col379": "pn292", + "col380": "bdwe8", + "col381": "s5kwa", + "col382": "eqall", + "col383": "7m0l8", + "col384": "admw4", + "col385": "7jw1e", + "col386": "xkgxo", + "col387": "5x41f", + "col388": "8l4ib", + "col389": "n77xj", + "col390": "ztbnz", + "col391": "1pyu0", + "col392": "jxnkk", + "col393": "4hq0p", + "col394": "qy2hk", + "col395": "r1836", + "col396": "0a7ve", + "col397": "6cifc", + "col398": "o7hc5", + "col399": "27x59", + "col400": "7u3be", + "col401": "bo41f", + "col402": "v633s", + "col403": "iyyfz", + "col404": "fo17v", + "col405": "8cqjt", + "col406": "rzkwn", + "col407": "bj47k", + "col408": "4pndt", + "col409": "z9rej", + "col410": "nr83r", + "col411": "pwupn", + "col412": "81j7x", + "col413": "cfpxt", + "col414": "oqqef", + "col415": "ek410", + "col416": "9f5ik", + "col417": "xaxdr", + "col418": "vnzb0", + "col419": "8m2l1", + "col420": "y5czq", + "col421": "6xbaj", + "col422": "6ra17", + "col423": "b3hjc", + "col424": "hij85", + "col425": "krmbv", + "col426": "syv5y", + "col427": "7l9mg", + "col428": "6by0k", + "col429": "pnuk9", + "col430": "gfzdb", + "col431": "gyk9b", + "col432": "inocj", + "col433": "wobe9", + "col434": "1o4g7", + "col435": "3znee", + "col436": "ty01j", + "col437": "ounwe", + "col438": "vx02f", + "col439": "rco9m", + "col440": "hh04p", + "col441": "8ef3r", + "col442": "04jds", + "col443": "wysou", + "col444": "10cz9", + "col445": "wanom", + "col446": "sswy5", + "col447": "fz8nx", + "col448": "ze33r", + "col449": "o4l11", + "col450": "as5td", + "col451": "xag3f", + "col452": "pkq5l", + "col453": "8lftf", + "col454": "ltvze", + "col455": "tfc66", + "col456": "osail", + "col457": "cqryo", + "col458": "ef8ab", + "col459": "da5ln", + "col460": "c1ldm", + "col461": "d9ypg", + "col462": "dzfw3", + "col463": "lcbvv", + "col464": "zg808", + "col465": "c4gd0", + "col466": "twdgi", + "col467": "3k3wg", + "col468": "w7r5f", + "col469": "jxtzo", + "col470": "5deet", + "col471": "soxl9", + "col472": "thi8s", + "col473": "wenl1", + "col474": "s9wld", + "col475": "fb79h", + "col476": "kwiig", + "col477": "f99s0", + "col478": "19pyt", + "col479": "ot9sj", + "col480": "fbln5", + "col481": "wancf", + "col482": "a7ih4", + "col483": "19qoe", + "col484": "0thvw", + "col485": "nztsx", + "col486": "6m3he", + "col487": "lilmp", + "col488": "ldccf", + "col489": "zfl44", + "col490": "rh1mb", + "col491": "kp98w", + "col492": "cps9e", + "col493": "hwt2d", + "col494": "ovodd", + "col495": "fjcif", + "col496": "4kd3u", + "col497": "htmwi", + "col498": "d4mc4", + "col499": "cyeks", + "col500": "ubxj3", + "col501": "vz5q4", + "col502": "1yu2q", + "col503": "vnqdb", + "col504": "ddv84", + "col505": "gvfb4", + "col506": "id3os", + "col507": "t0ff1", + "col508": "70xlo", + "col509": "8q5wd", + "col510": "olpxk", + "col511": "rhj58", + "col512": "0p500", + "col513": "owoae", + "col514": "8md6r", + "col515": "mwiv3", + "col516": "ujmqq", + "col517": "feci4", + "col518": "a2kk9", + "col519": "m779s", + "col520": "joup8", + "col521": "ripnk", + "col522": "5ifwp", + "col523": "kzsun", + "col524": "7py7v", + "col525": "m3amn", + "col526": "wiue5", + "col527": "mo1a6", + "col528": "pyktr", + "col529": "4gtsm", + "col530": "yw8gm", + "col531": "swrls", + "col532": "j51xo", + "col533": "s7d5n", + "col534": "f9h1h", + "col535": "ln8vc", + "col536": "u3284", + "col537": "zvv9s", + "col538": "uyycw", + "col539": "759nr", + "col540": "90e8h", + "col541": "ilf6s", + "col542": "1aozv", + "col543": "yj6sd", + "col544": "m5k4g", + "col545": "ts41t", + "col546": "fsbpx", + "col547": "ji2wo", + "col548": "2tb46", + "col549": "0aewx", + "col550": "zhzyb", + "col551": "tptrt", + "col552": "x3nmq", + "col553": "x18ac", + "col554": "0repi", + "col555": "iquql", + "col556": "8apk7", + "col557": "sxisg", + "col558": "aklpn", + "col559": "3p1e9", + "col560": "dqbw3", + "col561": "zb4lm", + "col562": "lgc32", + "col563": "12t9x", + "col564": "nsjoi", + "col565": "cfj9x", + "col566": "0r89i", + "col567": "ra97v", + "col568": "86ugb", + "col569": "zj7bk", + "col570": "18jt9", + "col571": "cloxm", + "col572": "6rice", + "col573": "wnpz1", + "col574": "xrqoc", + "col575": "h7njp", + "col576": "1tv9y", + "col577": "75acw", + "col578": "5wif7", + "col579": "y4kqq", + "col580": "vn9fe", + "col581": "netms", + "col582": "yo14i", + "col583": "sn2bl", + "col584": "xhr66", + "col585": "i20in", + "col586": "njfhi", + "col587": "8pl7u", + "col588": "il2a9", + "col589": "0jau7", + "col590": "ftpnq", + "col591": "oyr5r", + "col592": "wtx6x", + "col593": "a4f9k", + "col594": "yln8x", + "col595": "ltyj6", + "col596": "apqsm", + "col597": "jiatv", + "col598": "r9ldt", + "col599": "15nus", + "col600": "xcin2", + "col601": "zcu1e", + "col602": "634ey", + "col603": "akiob", + "col604": "i9qks", + "col605": "kdps1", + "col606": "hsr9f", + "col607": "b9bon", + "col608": "b9nok", + "col609": "2lg6r", + "col610": "rh6q0", + "col611": "cbeu2", + "col612": "m0yz6", + "col613": "3vavg", + "col614": "scqlx", + "col615": "hslke", + "col616": "ws9bx", + "col617": "ix97y", + "col618": "eddd7", + "col619": "kvqra", + "col620": "1ymq4", + "col621": "57gxf", + "col622": "zihog", + "col623": "935jk", + "col624": "rs030", + "col625": "99uu1", + "col626": "sgmix", + "col627": "o904b", + "col628": "k9mqd", + "col629": "zk1ff", + "col630": "wp0hp", + "col631": "7ql25", + "col632": "2he0k", + "col633": "ut5nr", + "col634": "6aexx", + "col635": "a7u75", + "col636": "d4ogt", + "col637": "9ysnk", + "col638": "meun0", + "col639": "g8h4q", + "col640": "7pdv0", + "col641": "p7770", + "col642": "6ooyw", + "col643": "s8mgj", + "col644": "iqx61", + "col645": "v0ig3", + "col646": "fw1wf", + "col647": "1fnuh", + "col648": "4rbix", + "col649": "p17xq", + "col650": "60ogg", + "col651": "i05i9", + "col652": "dcvhb", + "col653": "f6kqc", + "col654": "hywse", + "col655": "m3ucf", + "col656": "pxal4", + "col657": "7e3xq", + "col658": "2tyvd", + "col659": "e6x8r", + "col660": "wnxvk", + "col661": "29844", + "col662": "w7hkj", + "col663": "fiqj5", + "col664": "ly94h", + "col665": "cnsab", + "col666": "eyt5h", + "col667": "pg4em", + "col668": "s5yra", + "col669": "0w7t7", + "col670": "q3sdx", + "col671": "uditl", + "col672": "34ika", + "col673": "e79py", + "col674": "id8zx", + "col675": "i4vru", + "col676": "3suxi", + "col677": "438k5", + "col678": "8ufj5", + "col679": "0xp34", + "col680": "u38ec", + "col681": "1jkym", + "col682": "np8mp", + "col683": "s9tet", + "col684": "8qceq", + "col685": "4gv47", + "col686": "o7biy", + "col687": "q0l0g", + "col688": "pr8qp", + "col689": "5cq9w", + "col690": "9nlkt", + "col691": "qxihr", + "col692": "5b0hh", + "col693": "88gkp", + "col694": "w0s2v", + "col695": "ihxz9", + "col696": "0xmgv", + "col697": "2o320", + "col698": "1n2ie", + "col699": "npa8m", + "col700": "9v5r8", + "col701": "kbfl5", + "col702": "d4fwj", + "col703": "qakrr", + "col704": "n7n0m", + "col705": "21x57", + "col706": "nmx4v", + "col707": "yh9rp", + "col708": "0rnbt", + "col709": "0mbrs", + "col710": "8nlza", + "col711": "5iutt", + "col712": "d19eu", + "col713": "g2ge4", + "col714": "g5h8x", + "col715": "n6zbx", + "col716": "pgzxk", + "col717": "o6v3v", + "col718": "bzl8c", + "col719": "d0vzh", + "col720": "9nyld", + "col721": "255lw", + "col722": "50mwh", + "col723": "8hxcg", + "col724": "lv5ux", + "col725": "5dg6s", + "col726": "cfr97", + "col727": "82nx0", + "col728": "9ue0v", + "col729": "zjryb", + "col730": "i7dbx", + "col731": "pvs9h", + "col732": "6yx9b", + "col733": "5ffbe", + "col734": "hgr2u", + "col735": "38z12", + "col736": "12pkh", + "col737": "uhon0", + "col738": "xmeep", + "col739": "cbt1r", + "col740": "gvzhb", + "col741": "v736j", + "col742": "9wtqh", + "col743": "t6a3h", + "col744": "lb2ve", + "col745": "qu8vl", + "col746": "xfo1m", + "col747": "f4n11", + "col748": "wtkr9", + "col749": "e8asx", + "col750": "v6ujw", + "col751": "u7kek", + "col752": "26tkw", + "col753": "7h5bn", + "col754": "ri7b0", + "col755": "t4kac", + "col756": "bx0uc", + "col757": "s38zp", + "col758": "ngbx0", + "col759": "tmthq", + "col760": "ygask", + "col761": "tnfe2", + "col762": "r758a", + "col763": "p7boy", + "col764": "g9q21", + "col765": "xvhhm", + "col766": "z92ui", + "col767": "n054w", + "col768": "ga16z", + "col769": "m9e06", + "col770": "4jmf1", + "col771": "e6vj1", + "col772": "ums67", + "col773": "mg2wd", + "col774": "1cmmd", + "col775": "gbbmo", + "col776": "mb7nk", + "col777": "elr6b", + "col778": "bcxnu", + "col779": "3qo9b", + "col780": "o3f37", + "col781": "fuilu", + "col782": "l45wr", + "col783": "1y138", + "col784": "flijp", + "col785": "s7a51", + "col786": "a4h8k", + "col787": "4u7n3", + "col788": "bxqi3", + "col789": "2lhmx", + "col790": "3cakt", + "col791": "m8jl2", + "col792": "3tstn", + "col793": "j1frs", + "col794": "ruh2x", + "col795": "6raa8", + "col796": "9eeab", + "col797": "1asvf", + "col798": "hontx", + "col799": "q6j3d", + "col800": "67td5", + "col801": "ye15d", + "col802": "ia46x", + "col803": "6r8pz", + "col804": "lshc1", + "col805": "g5x5a", + "col806": "tm8bf", + "col807": "3d5ua", + "col808": "ayfzr", + "col809": "agfth", + "col810": "6doq1", + "col811": "i66ek", + "col812": "jynoj", + "col813": "w1zo3", + "col814": "tlc2o", + "col815": "j303u", + "col816": "sh7h1", + "col817": "a026g", + "col818": "qzmbp", + "col819": "6yl7h", + "col820": "p4s45", + "col821": "8e57f", + "col822": "fruzt", + "col823": "h3ufv", + "col824": "8k73w", + "col825": "gntyw", + "col826": "r3q1a", + "col827": "h7t3y", + "col828": "as5n0", + "col829": "qceri", + "col830": "kxfqx", + "col831": "eks5c", + "col832": "viwis", + "col833": "aoyvo", + "col834": "5sp8r", + "col835": "kwjn4", + "col836": "hmivz", + "col837": "a0gym", + "col838": "acvbr", + "col839": "ka5nk", + "col840": "m89qf", + "col841": "wyv82", + "col842": "jpw9b", + "col843": "2fx77", + "col844": "3u2ef", + "col845": "7jeft", + "col846": "buz4d", + "col847": "c45md", + "col848": "avc13", + "col849": "q04i3", + "col850": "umifv", + "col851": "94yn4", + "col852": "qfb1w", + "col853": "e4bgs", + "col854": "cs5zc", + "col855": "6ms7o", + "col856": "c7vef", + "col857": "ww0bp", + "col858": "ljihu", + "col859": "oxq95", + "col860": "y1863", + "col861": "cigfk", + "col862": "ur2t7", + "col863": "ml4d7", + "col864": "3chun", + "col865": "xlo26", + "col866": "igjje", + "col867": "nrbn6", + "col868": "abjs8", + "col869": "kj899", + "col870": "t13ya", + "col871": "txi5q", + "col872": "gys5a", + "col873": "dxcxz", + "col874": "nblg0", + "col875": "a7nc4", + "col876": "fgs0v", + "col877": "f190k", + "col878": "deqsd", + "col879": "ed58b", + "col880": "60vjn", + "col881": "zvlhx", + "col882": "hp3fw", + "col883": "9o3g7", + "col884": "bqwms", + "col885": "ufxv0", + "col886": "78us1", + "col887": "5loxn", + "col888": "s3nz8", + "col889": "t15au", + "col890": "gzfoj", + "col891": "kx0ir", + "col892": "9nb3l", + "col893": "9nc5r", + "col894": "biwmf", + "col895": "uob16", + "col896": "cn33d", + "col897": "q2vee", + "col898": "ywdv1", + "col899": "ermpr", + "col900": "nz8fn", + "col901": "2e3f7", + "col902": "hk2vj", + "col903": "jbd1w", + "col904": "sxsz1", + "col905": "cohlf", + "col906": "frc31", + "col907": "vwnvb", + "col908": "i94dy", + "col909": "y57bb", + "col910": "6by65", + "col911": "i0bs7", + "col912": "8bxti", + "col913": "82tf8", + "col914": "12pwk", + "col915": "kxl9j", + "col916": "y9l4q", + "col917": "qw4pi", + "col918": "12804", + "col919": "zmrhu", + "col920": "iknn5", + "col921": "5q1ic", + "col922": "ngwfc", + "col923": "5jm8r", + "col924": "7m6gm", + "col925": "tj82s", + "col926": "prmzx", + "col927": "iovmo", + "col928": "m0gz7", + "col929": "gqrqj", + "col930": "ue2x7", + "col931": "jj7ii", + "col932": "gg3h8", + "col933": "yghhf", + "col934": "t97cq", + "col935": "u729u", + "col936": "cqvgo", + "col937": "e73k0", + "col938": "07b94", + "col939": "arf6t", + "col940": "a7g0z", + "col941": "r454t", + "col942": "sn2mz", + "col943": "uiodm", + "col944": "t5hdf", + "col945": "bie5u", + "col946": "h3jsp", + "col947": "qrqp5", + "col948": "eyxh5", + "col949": "u5lof", + "col950": "wvt8s", + "col951": "glnva", + "col952": "uooil", + "col953": "ra5ma", + "col954": "i9u9b", + "col955": "o67lr", + "col956": "xpw7w", + "col957": "zrzzm", + "col958": "8lq8g", + "col959": "iozat", + "col960": "6bkbq", + "col961": "2zfvo", + "col962": "tupzh", + "col963": "vvu7k", + "col964": "6mzdl", + "col965": "4who5", + "col966": "scnrv", + "col967": "qh9vg", + "col968": "nmzqy", + "col969": "1ww6p", + "col970": "cmjc6", + "col971": "p083j", + "col972": "nqufo", + "col973": "d7cr3", + "col974": "e8kcp", + "col975": "h89jh", + "col976": "r2ul8", + "col977": "nn58z", + "col978": "qazop", + "col979": "den0h", + "col980": "pwlxa", + "col981": "13m5c", + "col982": "4ksr5", + "col983": "l4wbj", + "col984": "f7q3r", + "col985": "stz2b", + "col986": "psq01", + "col987": "2you0", + "col988": "wac7c", + "col989": "073qo", + "col990": "xgr05", + "col991": "jrpxo", + "col992": "53ohq", + "col993": "b7ltn", + "col994": "5zbjq", + "col995": "826zs", + "col996": "voqwq", + "col997": "n0734", + "col998": "zcwvg", + "col999": "mes4s" + }, + { + "name": "Francine Banks", + "gender": "female", + "col0": "e59k9", + "col1": "kg7so", + "col2": "qevd4", + "col3": "db9pu", + "col4": "90tix", + "col5": "e8lka", + "col6": "b1mqo", + "col7": "m3kh6", + "col8": "whgjm", + "col9": "35ze2", + "col10": "9z087", + "col11": "6zpix", + "col12": "ljy98", + "col13": "hizbd", + "col14": "ih2c8", + "col15": "s985z", + "col16": "mm8kq", + "col17": "yso0o", + "col18": "ypz1d", + "col19": "pxuir", + "col20": "ccx44", + "col21": "nfuqq", + "col22": "5d1k8", + "col23": "5jdwf", + "col24": "nlss6", + "col25": "e7me1", + "col26": "c7jvt", + "col27": "ddogl", + "col28": "vmad6", + "col29": "ivh1m", + "col30": "ppo2a", + "col31": "mgnhw", + "col32": "0k8c1", + "col33": "x7zzl", + "col34": "67h32", + "col35": "m9bw4", + "col36": "wpty5", + "col37": "151tj", + "col38": "96tfb", + "col39": "urhcy", + "col40": "y0kdt", + "col41": "jfwp0", + "col42": "jr543", + "col43": "0lxcl", + "col44": "t74pb", + "col45": "lpmae", + "col46": "9gw31", + "col47": "sne4i", + "col48": "h3way", + "col49": "tpt52", + "col50": "4iqp8", + "col51": "e54lx", + "col52": "r8ig5", + "col53": "xmmzw", + "col54": "nvdzr", + "col55": "zbqw9", + "col56": "mcsxp", + "col57": "8bzdf", + "col58": "axiu7", + "col59": "x609i", + "col60": "e79jl", + "col61": "qqtg9", + "col62": "xughi", + "col63": "7nyue", + "col64": "ow0ua", + "col65": "fv8o4", + "col66": "z8mel", + "col67": "zqmc2", + "col68": "nvrzz", + "col69": "5m1fd", + "col70": "t9nhk", + "col71": "lyoaq", + "col72": "it96q", + "col73": "s7vl1", + "col74": "y6ria", + "col75": "52dli", + "col76": "as8tr", + "col77": "1576l", + "col78": "8v6tx", + "col79": "o20n4", + "col80": "9jpak", + "col81": "23qlc", + "col82": "zrgut", + "col83": "qt52p", + "col84": "va5x8", + "col85": "7yvbz", + "col86": "axaax", + "col87": "flerm", + "col88": "gin8t", + "col89": "zlewh", + "col90": "48xe8", + "col91": "q1mkx", + "col92": "h7f4g", + "col93": "s8r66", + "col94": "7ec9r", + "col95": "awuo1", + "col96": "0khov", + "col97": "1fody", + "col98": "0hgrt", + "col99": "7nhop", + "col100": "arb53", + "col101": "kog95", + "col102": "wnvlu", + "col103": "ick1j", + "col104": "ofpps", + "col105": "f9pfi", + "col106": "ujbm3", + "col107": "1op0w", + "col108": "bi6bq", + "col109": "14zzr", + "col110": "455q2", + "col111": "jsksr", + "col112": "hhmry", + "col113": "gwuq7", + "col114": "jpkbk", + "col115": "4te9k", + "col116": "z2c77", + "col117": "8ojuy", + "col118": "lepaj", + "col119": "1xypf", + "col120": "t3e1v", + "col121": "wyq5k", + "col122": "jzq8t", + "col123": "i4z8e", + "col124": "50zgy", + "col125": "8m6ck", + "col126": "41g7a", + "col127": "tdre4", + "col128": "0ezja", + "col129": "gl6bg", + "col130": "1qxwh", + "col131": "9y39f", + "col132": "varhv", + "col133": "lexpk", + "col134": "7a9il", + "col135": "nd4n2", + "col136": "2oaq5", + "col137": "ctihl", + "col138": "uh2zz", + "col139": "3ouu9", + "col140": "vx8d9", + "col141": "agare", + "col142": "cbiyf", + "col143": "xz5n3", + "col144": "vnv27", + "col145": "plcac", + "col146": "l9ufm", + "col147": "ivvxu", + "col148": "kzvs2", + "col149": "i3xe9", + "col150": "5s8cm", + "col151": "yxq1p", + "col152": "q3pt7", + "col153": "5lqif", + "col154": "xcypc", + "col155": "khahg", + "col156": "0b9x9", + "col157": "1jamj", + "col158": "ysnrl", + "col159": "0dcum", + "col160": "4kr46", + "col161": "wpg3k", + "col162": "bgf4v", + "col163": "6ebqn", + "col164": "28n52", + "col165": "e9gox", + "col166": "qc7ay", + "col167": "8kwpw", + "col168": "iy7lo", + "col169": "80i49", + "col170": "f4cbz", + "col171": "nbi53", + "col172": "ca3kc", + "col173": "1d398", + "col174": "5rgsu", + "col175": "8u2t8", + "col176": "arfc1", + "col177": "6q5nq", + "col178": "njpsy", + "col179": "c47oo", + "col180": "43a29", + "col181": "2rmnv", + "col182": "u8sf2", + "col183": "uk8ds", + "col184": "i10bk", + "col185": "hb6i8", + "col186": "z768r", + "col187": "idg34", + "col188": "bcj36", + "col189": "7hqux", + "col190": "h84r7", + "col191": "qxm01", + "col192": "i88ch", + "col193": "ajy8t", + "col194": "g1wvq", + "col195": "txlo7", + "col196": "rjb17", + "col197": "vjaft", + "col198": "wjv0f", + "col199": "4r122", + "col200": "jm9bf", + "col201": "emk9k", + "col202": "dlrme", + "col203": "v6qp3", + "col204": "qr50p", + "col205": "j6nj0", + "col206": "ijerx", + "col207": "98ic6", + "col208": "hae08", + "col209": "9obvr", + "col210": "qleba", + "col211": "psjmr", + "col212": "e44oa", + "col213": "566dq", + "col214": "0yq4i", + "col215": "yh6c5", + "col216": "xtn8t", + "col217": "ua0bm", + "col218": "ikpjs", + "col219": "brbrq", + "col220": "rpsts", + "col221": "guxfu", + "col222": "3caj7", + "col223": "0915b", + "col224": "r1qc7", + "col225": "4btbs", + "col226": "d5tt7", + "col227": "mwn3n", + "col228": "sfmym", + "col229": "hmcje", + "col230": "yskmt", + "col231": "gmnzb", + "col232": "kpe7x", + "col233": "zk5d0", + "col234": "8hwln", + "col235": "5af1w", + "col236": "tce9y", + "col237": "alllr", + "col238": "47c48", + "col239": "31n18", + "col240": "2cj7v", + "col241": "sb83f", + "col242": "n215h", + "col243": "0xu5a", + "col244": "er090", + "col245": "bf199", + "col246": "ir6xe", + "col247": "udq2a", + "col248": "6vanm", + "col249": "y9g0i", + "col250": "c5s6c", + "col251": "kllcj", + "col252": "hla8a", + "col253": "r75ww", + "col254": "5wy9c", + "col255": "b20pg", + "col256": "rzeiq", + "col257": "3zcyd", + "col258": "4r5t5", + "col259": "cfayx", + "col260": "vjiu2", + "col261": "mcsa5", + "col262": "7a1ro", + "col263": "yml8p", + "col264": "rbfs9", + "col265": "ntgfi", + "col266": "yf8ej", + "col267": "axtkm", + "col268": "qxirw", + "col269": "d6x4f", + "col270": "pcr4m", + "col271": "nb17l", + "col272": "2s0an", + "col273": "hug1x", + "col274": "32wfn", + "col275": "y1wop", + "col276": "mtxl9", + "col277": "r3moa", + "col278": "d56yf", + "col279": "imv79", + "col280": "xmtzo", + "col281": "iv9c3", + "col282": "iu9gu", + "col283": "odcn4", + "col284": "wdmcc", + "col285": "ixdr8", + "col286": "4zrqz", + "col287": "thegu", + "col288": "milkb", + "col289": "qpv8b", + "col290": "6fkbr", + "col291": "1rw21", + "col292": "vts4u", + "col293": "3wu5l", + "col294": "zfshk", + "col295": "1ke2l", + "col296": "n67jb", + "col297": "iepqq", + "col298": "9xkb8", + "col299": "th4gh", + "col300": "ju6he", + "col301": "c42cs", + "col302": "2a6i1", + "col303": "ocxp6", + "col304": "9ioe7", + "col305": "f7knd", + "col306": "wcipu", + "col307": "9bkml", + "col308": "dx2lo", + "col309": "689bn", + "col310": "jvixu", + "col311": "1oiwx", + "col312": "a9nwl", + "col313": "buv57", + "col314": "175tq", + "col315": "sduuk", + "col316": "0nf3r", + "col317": "fvq54", + "col318": "ustyv", + "col319": "lw8qs", + "col320": "h069a", + "col321": "7qj0g", + "col322": "90gkp", + "col323": "jj6oa", + "col324": "s1xcp", + "col325": "8kxru", + "col326": "q3635", + "col327": "edd4q", + "col328": "mvon7", + "col329": "4xca7", + "col330": "z0bqx", + "col331": "qd1zc", + "col332": "8ypxd", + "col333": "zct97", + "col334": "1sq4e", + "col335": "dju1d", + "col336": "ycqly", + "col337": "5u7wx", + "col338": "yd3r2", + "col339": "ubvjn", + "col340": "7txiv", + "col341": "iqi2y", + "col342": "piirm", + "col343": "1c7u4", + "col344": "4ta3n", + "col345": "xbim6", + "col346": "rl4zu", + "col347": "mgcbk", + "col348": "fgor8", + "col349": "9a258", + "col350": "sb6gf", + "col351": "zw78r", + "col352": "3jtmq", + "col353": "yumi5", + "col354": "02rpy", + "col355": "lwad6", + "col356": "xj44c", + "col357": "wav3o", + "col358": "k7izz", + "col359": "zdl3v", + "col360": "6aenl", + "col361": "wfmz3", + "col362": "r7ujv", + "col363": "yv12l", + "col364": "j15te", + "col365": "memv9", + "col366": "8tih6", + "col367": "rd8tm", + "col368": "93uzv", + "col369": "oco5l", + "col370": "yyue7", + "col371": "6hfa5", + "col372": "6leek", + "col373": "1v1m7", + "col374": "9i2o2", + "col375": "kwh7b", + "col376": "tk9kc", + "col377": "nz6rx", + "col378": "1hxhk", + "col379": "4bqht", + "col380": "wv9au", + "col381": "vegq4", + "col382": "mt6nv", + "col383": "jzhzs", + "col384": "pfv6v", + "col385": "9l1hx", + "col386": "g3vbg", + "col387": "nse74", + "col388": "lqgfb", + "col389": "hma3b", + "col390": "2taa6", + "col391": "ao2mt", + "col392": "qn8ur", + "col393": "l28n9", + "col394": "dc7he", + "col395": "6a62m", + "col396": "qdtvn", + "col397": "j0b5j", + "col398": "mxksx", + "col399": "cw46h", + "col400": "lkbq0", + "col401": "bgc14", + "col402": "k32e8", + "col403": "j0itt", + "col404": "ikkhg", + "col405": "mwfzy", + "col406": "gmfn4", + "col407": "ndfpe", + "col408": "ecnum", + "col409": "hdys1", + "col410": "bzrpj", + "col411": "dji6e", + "col412": "umqyy", + "col413": "x66uo", + "col414": "ekvja", + "col415": "27xx0", + "col416": "u8tbs", + "col417": "ji4xz", + "col418": "vxt2o", + "col419": "rzp0e", + "col420": "9pktf", + "col421": "8xiug", + "col422": "6yo9w", + "col423": "yaaqr", + "col424": "5x27h", + "col425": "tq8eh", + "col426": "yp89s", + "col427": "s6u4e", + "col428": "amfay", + "col429": "60ci3", + "col430": "7f5z3", + "col431": "zba8g", + "col432": "cxu1g", + "col433": "auaov", + "col434": "y8j7g", + "col435": "w308u", + "col436": "bdp25", + "col437": "p1072", + "col438": "bc7au", + "col439": "65qjj", + "col440": "9e2ms", + "col441": "2yr1f", + "col442": "oc0q6", + "col443": "01ujx", + "col444": "f6ze0", + "col445": "gkvd7", + "col446": "hqk2u", + "col447": "64qvu", + "col448": "y8h97", + "col449": "n8pib", + "col450": "w9ib5", + "col451": "68e42", + "col452": "y5r9t", + "col453": "byj8z", + "col454": "nt1y5", + "col455": "eely9", + "col456": "qovvo", + "col457": "w90f8", + "col458": "8942x", + "col459": "gnx68", + "col460": "l4oxg", + "col461": "sptrz", + "col462": "xi15x", + "col463": "4kdjg", + "col464": "csmul", + "col465": "lcdrj", + "col466": "aspr4", + "col467": "fj3v0", + "col468": "441wx", + "col469": "47gdn", + "col470": "hxnc4", + "col471": "c361t", + "col472": "75gyp", + "col473": "ymp75", + "col474": "ukavm", + "col475": "xftd2", + "col476": "wv3gt", + "col477": "xq7ba", + "col478": "697xk", + "col479": "fr3cz", + "col480": "xl8zf", + "col481": "71v9b", + "col482": "68sc5", + "col483": "qxtq2", + "col484": "xi7pe", + "col485": "cdcv2", + "col486": "4f0zj", + "col487": "7n235", + "col488": "70zan", + "col489": "7sax2", + "col490": "jnopu", + "col491": "jtp0i", + "col492": "4jpjj", + "col493": "a4w3r", + "col494": "t17nz", + "col495": "q5xbm", + "col496": "c6clz", + "col497": "ixcat", + "col498": "7r7cx", + "col499": "ifltw", + "col500": "kb6zi", + "col501": "3xhcf", + "col502": "yg8f3", + "col503": "sdbvv", + "col504": "5ymhn", + "col505": "giatx", + "col506": "dsnqw", + "col507": "gw582", + "col508": "etcpc", + "col509": "zrey1", + "col510": "xqch1", + "col511": "2tiyx", + "col512": "hkrju", + "col513": "j5bhs", + "col514": "e1j09", + "col515": "rwytt", + "col516": "sjjti", + "col517": "dxbmb", + "col518": "vki0s", + "col519": "qjlvg", + "col520": "8fl1b", + "col521": "2ychz", + "col522": "j8mvd", + "col523": "k7rs1", + "col524": "fpp85", + "col525": "lcrld", + "col526": "esqk1", + "col527": "gcj26", + "col528": "dt8cu", + "col529": "uuh1x", + "col530": "gemf4", + "col531": "pqbxj", + "col532": "lhnm1", + "col533": "nsr38", + "col534": "nwwhm", + "col535": "dhglz", + "col536": "0jrkj", + "col537": "qrbmp", + "col538": "kl0jm", + "col539": "yhv54", + "col540": "0hynx", + "col541": "lp6at", + "col542": "j81qw", + "col543": "rdbwh", + "col544": "b4zk7", + "col545": "bouxy", + "col546": "2gp13", + "col547": "jnfdh", + "col548": "1qmsw", + "col549": "cmplt", + "col550": "we1qr", + "col551": "s0e5t", + "col552": "nql7b", + "col553": "o69cm", + "col554": "oc4ll", + "col555": "cmiz1", + "col556": "dox8f", + "col557": "gnjua", + "col558": "oh92p", + "col559": "d9gza", + "col560": "5yooc", + "col561": "gg3d6", + "col562": "0k7y9", + "col563": "bgwrs", + "col564": "6ewx0", + "col565": "7uevx", + "col566": "l1nwa", + "col567": "if5bn", + "col568": "44qci", + "col569": "4q5ao", + "col570": "omdla", + "col571": "2msoo", + "col572": "iuq89", + "col573": "3q9ej", + "col574": "1a64n", + "col575": "wb93f", + "col576": "g1ojy", + "col577": "tfqfx", + "col578": "0e9uf", + "col579": "wtaif", + "col580": "3k4ib", + "col581": "21ool", + "col582": "5pfxe", + "col583": "o5z67", + "col584": "cqua0", + "col585": "5uq81", + "col586": "6c2ic", + "col587": "fwus6", + "col588": "hmjuw", + "col589": "7r4rn", + "col590": "ixuve", + "col591": "fi4jj", + "col592": "5znpl", + "col593": "eyd8z", + "col594": "g90cp", + "col595": "jmewx", + "col596": "mr8ss", + "col597": "uz2v3", + "col598": "p7buu", + "col599": "jtzru", + "col600": "xlm1j", + "col601": "xyoe4", + "col602": "dk8m4", + "col603": "ul0j5", + "col604": "vfg2v", + "col605": "wlscp", + "col606": "8vr1j", + "col607": "7g3y0", + "col608": "xzxvv", + "col609": "apunk", + "col610": "63v29", + "col611": "a2odh", + "col612": "0b3f4", + "col613": "it06c", + "col614": "uo5jo", + "col615": "6dc29", + "col616": "pmz9y", + "col617": "3f5vl", + "col618": "vkooh", + "col619": "nioqr", + "col620": "63s2e", + "col621": "9hscy", + "col622": "2z10e", + "col623": "pws8m", + "col624": "903gm", + "col625": "h9fn2", + "col626": "fvm8q", + "col627": "xshfy", + "col628": "nxdix", + "col629": "05nu4", + "col630": "tai6b", + "col631": "u3kwy", + "col632": "xkzew", + "col633": "c0lwo", + "col634": "g18m8", + "col635": "d2733", + "col636": "wt2eu", + "col637": "260n4", + "col638": "8kwfp", + "col639": "h8b3w", + "col640": "x11sb", + "col641": "0kvdy", + "col642": "9x5j5", + "col643": "3r17r", + "col644": "4apwu", + "col645": "kk15v", + "col646": "zd9gy", + "col647": "2bv1v", + "col648": "hj855", + "col649": "r7eh4", + "col650": "cgqjp", + "col651": "70wgq", + "col652": "2gzai", + "col653": "n9ta6", + "col654": "w3kx3", + "col655": "81dan", + "col656": "avn5z", + "col657": "5gv0n", + "col658": "acxvc", + "col659": "zpnbq", + "col660": "j28f9", + "col661": "m60qs", + "col662": "vxsrr", + "col663": "ymb61", + "col664": "e7oob", + "col665": "jfigj", + "col666": "vzngf", + "col667": "xv8wt", + "col668": "17w9q", + "col669": "jybc9", + "col670": "gm4ak", + "col671": "5y45s", + "col672": "bs0fb", + "col673": "23jpe", + "col674": "x3p4r", + "col675": "jg2k8", + "col676": "cqszf", + "col677": "c2dpu", + "col678": "2pi6u", + "col679": "ch4g2", + "col680": "ky4e9", + "col681": "ffwqy", + "col682": "pxqku", + "col683": "xtbqy", + "col684": "gb94e", + "col685": "jooj1", + "col686": "sheat", + "col687": "019nc", + "col688": "sbcoq", + "col689": "vkyf4", + "col690": "pchsc", + "col691": "jcwl3", + "col692": "io445", + "col693": "epvpf", + "col694": "rqr2v", + "col695": "gfoay", + "col696": "9c0qu", + "col697": "quwhu", + "col698": "9qj88", + "col699": "cdx2m", + "col700": "49ccj", + "col701": "9ch87", + "col702": "hdvjf", + "col703": "jv2yp", + "col704": "7hooy", + "col705": "ekxap", + "col706": "f4wp3", + "col707": "35cob", + "col708": "cy6r6", + "col709": "v0tdj", + "col710": "0ri2y", + "col711": "yvscq", + "col712": "s2heq", + "col713": "ydzmd", + "col714": "p8pe2", + "col715": "ih6n3", + "col716": "xosy8", + "col717": "oml8p", + "col718": "zphfs", + "col719": "rac30", + "col720": "rz3b6", + "col721": "q9hxd", + "col722": "hsgmm", + "col723": "ivpwi", + "col724": "3bsf1", + "col725": "ru4h7", + "col726": "rnta1", + "col727": "qfyap", + "col728": "1fjwu", + "col729": "w0r07", + "col730": "e3a9c", + "col731": "rd5kp", + "col732": "tvlsr", + "col733": "mdlg7", + "col734": "hc6ta", + "col735": "idcep", + "col736": "po5gh", + "col737": "svk9g", + "col738": "oo21p", + "col739": "b46rd", + "col740": "bbg4b", + "col741": "yezlr", + "col742": "shpic", + "col743": "xakxq", + "col744": "q9nbt", + "col745": "mk0nk", + "col746": "7la91", + "col747": "jlnru", + "col748": "9tg6x", + "col749": "7dz2f", + "col750": "487ef", + "col751": "tdezc", + "col752": "xa2am", + "col753": "e5n2g", + "col754": "frgjw", + "col755": "i1ax1", + "col756": "tsc6i", + "col757": "9iwj2", + "col758": "0pdgm", + "col759": "yuxr8", + "col760": "xga0v", + "col761": "af0s4", + "col762": "cg7vo", + "col763": "gtfos", + "col764": "hbgp0", + "col765": "bbb51", + "col766": "4e2tx", + "col767": "dm2ze", + "col768": "lheoj", + "col769": "ah5zo", + "col770": "fotjo", + "col771": "owmu4", + "col772": "htjp7", + "col773": "i0zx3", + "col774": "g9mbt", + "col775": "f6d4o", + "col776": "ivkmx", + "col777": "hr0oe", + "col778": "93bho", + "col779": "056oy", + "col780": "1w432", + "col781": "9qk86", + "col782": "x10ao", + "col783": "lxzrr", + "col784": "q172f", + "col785": "4rk7k", + "col786": "0tehz", + "col787": "3921h", + "col788": "d4prc", + "col789": "xzlm7", + "col790": "gn3uh", + "col791": "rthn1", + "col792": "apqc1", + "col793": "xq317", + "col794": "lw6pn", + "col795": "iordk", + "col796": "f53ky", + "col797": "f3qzo", + "col798": "kkn5p", + "col799": "d01cq", + "col800": "ozifp", + "col801": "mhsyc", + "col802": "hg6nk", + "col803": "eyccr", + "col804": "jfzyb", + "col805": "05n9p", + "col806": "pj79k", + "col807": "0w36t", + "col808": "8oasd", + "col809": "ac0a4", + "col810": "58e9d", + "col811": "8zv6k", + "col812": "s4d7c", + "col813": "b9aoi", + "col814": "ci69b", + "col815": "ww4tu", + "col816": "hdkvu", + "col817": "jv41v", + "col818": "cicrf", + "col819": "ihynm", + "col820": "x4vjc", + "col821": "roxs9", + "col822": "fo5ic", + "col823": "hg0rn", + "col824": "hapd7", + "col825": "03ftm", + "col826": "8bii9", + "col827": "ftjhq", + "col828": "vdqdm", + "col829": "e6yey", + "col830": "envn3", + "col831": "vlihz", + "col832": "r53yi", + "col833": "ex8lh", + "col834": "xj30w", + "col835": "l6s4o", + "col836": "pt3bo", + "col837": "gkf2u", + "col838": "8cbgg", + "col839": "fvqfd", + "col840": "w2rkp", + "col841": "ge8sc", + "col842": "ac8gr", + "col843": "mch7a", + "col844": "n9u7y", + "col845": "6nsjr", + "col846": "d0wsa", + "col847": "4sw4d", + "col848": "vr1p7", + "col849": "ygraj", + "col850": "k0i0y", + "col851": "6hy3w", + "col852": "lfxpj", + "col853": "j7466", + "col854": "3gal0", + "col855": "2h0uc", + "col856": "dvpyk", + "col857": "qpbol", + "col858": "vww3j", + "col859": "65gxw", + "col860": "dkx6v", + "col861": "89fpw", + "col862": "ukk54", + "col863": "012eg", + "col864": "bfbwc", + "col865": "2s4f1", + "col866": "aaapz", + "col867": "lx0bk", + "col868": "ea5q9", + "col869": "5kspu", + "col870": "irl8k", + "col871": "0yg5x", + "col872": "ptccw", + "col873": "jzzbt", + "col874": "u8lvy", + "col875": "eio2u", + "col876": "qobp6", + "col877": "88uxh", + "col878": "smb0k", + "col879": "warc7", + "col880": "25533", + "col881": "w9sxs", + "col882": "bxka1", + "col883": "bze67", + "col884": "r9oai", + "col885": "blvb1", + "col886": "govz4", + "col887": "2druq", + "col888": "6g9wa", + "col889": "dwrze", + "col890": "rc3kv", + "col891": "bvauw", + "col892": "5rneq", + "col893": "rlfoe", + "col894": "dt2ud", + "col895": "4qk2n", + "col896": "phl9e", + "col897": "229vy", + "col898": "9w5gy", + "col899": "w8qoi", + "col900": "olvh3", + "col901": "iw6c8", + "col902": "shqas", + "col903": "ixeeu", + "col904": "3wr99", + "col905": "p6jm7", + "col906": "ydsxb", + "col907": "g4x59", + "col908": "mp4vs", + "col909": "k1oyd", + "col910": "slvz9", + "col911": "urfgq", + "col912": "hppe1", + "col913": "bc37m", + "col914": "pxlbv", + "col915": "yeme0", + "col916": "gtzfj", + "col917": "bh4c1", + "col918": "qs2hp", + "col919": "e2x7o", + "col920": "55fnr", + "col921": "vg474", + "col922": "jc885", + "col923": "vk9vl", + "col924": "akz8j", + "col925": "wpkwz", + "col926": "be6is", + "col927": "0ouia", + "col928": "5gjaa", + "col929": "1tn9x", + "col930": "txeqd", + "col931": "8lusm", + "col932": "hu0b1", + "col933": "oyy08", + "col934": "zszzj", + "col935": "41otg", + "col936": "vulgl", + "col937": "7jkcj", + "col938": "xuyop", + "col939": "dst92", + "col940": "9yflr", + "col941": "ubhr9", + "col942": "tosqc", + "col943": "yn5xo", + "col944": "vmz4z", + "col945": "8le9x", + "col946": "ecml4", + "col947": "t6whu", + "col948": "c81hu", + "col949": "bh95r", + "col950": "fd2wf", + "col951": "xsrmx", + "col952": "fagjg", + "col953": "057y6", + "col954": "1405s", + "col955": "zppzb", + "col956": "77w1v", + "col957": "o8xdp", + "col958": "f7l3i", + "col959": "fidvf", + "col960": "qkm6z", + "col961": "ygmqg", + "col962": "rtz4v", + "col963": "onvms", + "col964": "5werb", + "col965": "wcmga", + "col966": "8d5pl", + "col967": "6hifu", + "col968": "chxqc", + "col969": "z18w0", + "col970": "3rrj5", + "col971": "49akr", + "col972": "4fni7", + "col973": "wp440", + "col974": "d8y2v", + "col975": "1sa00", + "col976": "kznj1", + "col977": "v049g", + "col978": "boraw", + "col979": "rayrp", + "col980": "k4e0f", + "col981": "titvw", + "col982": "ijft0", + "col983": "m5mhw", + "col984": "ikfh1", + "col985": "khsso", + "col986": "2nmzz", + "col987": "hbm11", + "col988": "9s3pf", + "col989": "kqnyu", + "col990": "fihqn", + "col991": "9oifp", + "col992": "tdqq0", + "col993": "cw754", + "col994": "wj6vq", + "col995": "zu55i", + "col996": "cc86g", + "col997": "tv43a", + "col998": "46vj3", + "col999": "ehr88" + }, + { + "name": "Hooper Hoover", + "gender": "male", + "col0": "286jq", + "col1": "96l6r", + "col2": "w14iq", + "col3": "ucep1", + "col4": "dndxl", + "col5": "26pne", + "col6": "233ea", + "col7": "qgurt", + "col8": "y2lyk", + "col9": "33s18", + "col10": "c8fsq", + "col11": "e1wuk", + "col12": "nacpt", + "col13": "8b559", + "col14": "wij2o", + "col15": "3v3xo", + "col16": "lc23w", + "col17": "momty", + "col18": "k1o93", + "col19": "8j1v1", + "col20": "r80ja", + "col21": "fjz4j", + "col22": "uwama", + "col23": "gwizb", + "col24": "edfdn", + "col25": "yi7cq", + "col26": "ojddw", + "col27": "mb2xd", + "col28": "w1rxm", + "col29": "faalm", + "col30": "ppot4", + "col31": "ak1l0", + "col32": "js6sx", + "col33": "61w59", + "col34": "luslf", + "col35": "cetap", + "col36": "wcmzh", + "col37": "rqvwt", + "col38": "w5uj0", + "col39": "ezs8k", + "col40": "srmvo", + "col41": "vsvlm", + "col42": "g2b0q", + "col43": "flbqh", + "col44": "qcfzt", + "col45": "2yvws", + "col46": "9rddy", + "col47": "cve0d", + "col48": "851lo", + "col49": "i37a7", + "col50": "98m6t", + "col51": "0db98", + "col52": "vt3a6", + "col53": "25vvw", + "col54": "1n45w", + "col55": "l1w55", + "col56": "5ou11", + "col57": "nv4hk", + "col58": "2jbu8", + "col59": "di8jx", + "col60": "njq34", + "col61": "3yw8m", + "col62": "x1oig", + "col63": "p2j3a", + "col64": "t9can", + "col65": "ktpm9", + "col66": "3oqps", + "col67": "zzkl2", + "col68": "dlgrr", + "col69": "pk3zh", + "col70": "fxr7c", + "col71": "z5iq1", + "col72": "ssf6w", + "col73": "4f25q", + "col74": "gdanr", + "col75": "beknr", + "col76": "edlkh", + "col77": "fb8p8", + "col78": "io604", + "col79": "snb2c", + "col80": "x35ud", + "col81": "va7p9", + "col82": "6c9v5", + "col83": "kecjg", + "col84": "6npyu", + "col85": "al0dp", + "col86": "9uarc", + "col87": "64uwt", + "col88": "pa1lw", + "col89": "j75ty", + "col90": "tm6nk", + "col91": "u69ir", + "col92": "2blmc", + "col93": "9irn5", + "col94": "jvj9j", + "col95": "6r078", + "col96": "2974d", + "col97": "7ez9h", + "col98": "fxfhn", + "col99": "vxa6z", + "col100": "n188j", + "col101": "7cg0y", + "col102": "gz4dp", + "col103": "0s0f6", + "col104": "dzdic", + "col105": "0ahi7", + "col106": "eakx2", + "col107": "1v8pr", + "col108": "4w6r2", + "col109": "ffsr6", + "col110": "852zo", + "col111": "dsa5f", + "col112": "27bev", + "col113": "cqqul", + "col114": "5m8xh", + "col115": "v33vk", + "col116": "8ku39", + "col117": "nnhgz", + "col118": "eaomh", + "col119": "44vzz", + "col120": "6ux2n", + "col121": "5bm0u", + "col122": "0pozx", + "col123": "eag38", + "col124": "stddc", + "col125": "sc2j0", + "col126": "pwjt3", + "col127": "np2dz", + "col128": "z5rpo", + "col129": "2dxua", + "col130": "ut2uu", + "col131": "op3al", + "col132": "ympeb", + "col133": "4h483", + "col134": "7vll0", + "col135": "y7ult", + "col136": "3xqxb", + "col137": "gf8d5", + "col138": "0djiw", + "col139": "wujsb", + "col140": "nxbq6", + "col141": "ibsuo", + "col142": "lih74", + "col143": "lcprl", + "col144": "maume", + "col145": "09xmx", + "col146": "3hcx8", + "col147": "48z6u", + "col148": "3od0q", + "col149": "uosyd", + "col150": "fa6g3", + "col151": "yll0m", + "col152": "y6b2f", + "col153": "mylr2", + "col154": "mj497", + "col155": "fg336", + "col156": "9l36d", + "col157": "kuigv", + "col158": "2u8ur", + "col159": "rvx7s", + "col160": "k08ul", + "col161": "jtdwm", + "col162": "txg9v", + "col163": "v6vih", + "col164": "9hpyi", + "col165": "pw4u5", + "col166": "imu8q", + "col167": "221eg", + "col168": "0jrie", + "col169": "7nc2h", + "col170": "fw1yf", + "col171": "9z6i4", + "col172": "8sycz", + "col173": "89fss", + "col174": "ncnxl", + "col175": "vlxtk", + "col176": "axu3g", + "col177": "57bp2", + "col178": "4me1a", + "col179": "prj7y", + "col180": "l0d02", + "col181": "iyvho", + "col182": "iq05q", + "col183": "g9hds", + "col184": "jm5hn", + "col185": "sqqti", + "col186": "0ujml", + "col187": "12dl1", + "col188": "fq88l", + "col189": "41tso", + "col190": "oil64", + "col191": "qqsib", + "col192": "j5l47", + "col193": "0ktln", + "col194": "1wgn6", + "col195": "0hyqn", + "col196": "mneez", + "col197": "oufij", + "col198": "1i6lv", + "col199": "r20ji", + "col200": "681n5", + "col201": "q55qv", + "col202": "fd7a7", + "col203": "v4rse", + "col204": "ny8nk", + "col205": "ri73m", + "col206": "7rbiw", + "col207": "oz4hn", + "col208": "pdevs", + "col209": "vbq2b", + "col210": "3iws2", + "col211": "h9ae6", + "col212": "nm70i", + "col213": "28b5t", + "col214": "chxrn", + "col215": "ae8tm", + "col216": "13mse", + "col217": "csw0z", + "col218": "1ujyf", + "col219": "79s5s", + "col220": "0j6on", + "col221": "vz0uu", + "col222": "khk6l", + "col223": "ox9ww", + "col224": "bcevt", + "col225": "nlovh", + "col226": "45e5s", + "col227": "cjmfq", + "col228": "cogm6", + "col229": "w4t7a", + "col230": "0d1hj", + "col231": "d6wrn", + "col232": "kggr6", + "col233": "azry7", + "col234": "xuxo3", + "col235": "po1wr", + "col236": "83kao", + "col237": "yvb4y", + "col238": "v68mw", + "col239": "l6zua", + "col240": "mjony", + "col241": "xyvqj", + "col242": "9ikeu", + "col243": "b8b7b", + "col244": "jh1xa", + "col245": "4j20s", + "col246": "ctxvm", + "col247": "jw7qs", + "col248": "hfcts", + "col249": "9l99s", + "col250": "isnya", + "col251": "94mlq", + "col252": "6ixph", + "col253": "lb49u", + "col254": "4ll9d", + "col255": "r9bfz", + "col256": "nxdss", + "col257": "qt0il", + "col258": "it846", + "col259": "yl6tw", + "col260": "rtlxu", + "col261": "reaxt", + "col262": "3w3ns", + "col263": "mt5fy", + "col264": "4sbu3", + "col265": "khbmp", + "col266": "scgfk", + "col267": "kvq8z", + "col268": "tb794", + "col269": "jo2eh", + "col270": "8xtpx", + "col271": "w882f", + "col272": "rws6v", + "col273": "a9625", + "col274": "u9mgu", + "col275": "oqo5b", + "col276": "6zfwq", + "col277": "bkuad", + "col278": "fnu4e", + "col279": "otkj6", + "col280": "7gs83", + "col281": "4nyye", + "col282": "ov1gl", + "col283": "4loso", + "col284": "hcbqn", + "col285": "963c3", + "col286": "6blk2", + "col287": "kekw6", + "col288": "bks5b", + "col289": "f93gp", + "col290": "dtll8", + "col291": "59727", + "col292": "72t6l", + "col293": "m6trj", + "col294": "qkpj4", + "col295": "zgexl", + "col296": "3g5s7", + "col297": "drers", + "col298": "w97jy", + "col299": "h3m0l", + "col300": "lnctm", + "col301": "xvlr1", + "col302": "z0itn", + "col303": "ja70e", + "col304": "1nqzq", + "col305": "kiti1", + "col306": "lsf9r", + "col307": "fun3a", + "col308": "163pd", + "col309": "j2eti", + "col310": "cfwj4", + "col311": "a5lat", + "col312": "mjvby", + "col313": "hdqsw", + "col314": "rsi70", + "col315": "301h1", + "col316": "du53m", + "col317": "2f7em", + "col318": "vtl5p", + "col319": "hlqk2", + "col320": "51k7f", + "col321": "wi3ol", + "col322": "j2g16", + "col323": "io2uh", + "col324": "n1alz", + "col325": "5aiok", + "col326": "92s39", + "col327": "dnk5v", + "col328": "uiowc", + "col329": "wi35b", + "col330": "dmg3w", + "col331": "rhmkt", + "col332": "u9bg8", + "col333": "uib7a", + "col334": "xy0qn", + "col335": "n0tss", + "col336": "zpav9", + "col337": "8hzkc", + "col338": "r1mgp", + "col339": "ddsit", + "col340": "dy1hs", + "col341": "g5gjc", + "col342": "a1zdn", + "col343": "p7dmz", + "col344": "poeqy", + "col345": "8vi4z", + "col346": "3yxvl", + "col347": "24i77", + "col348": "683yc", + "col349": "0r9tc", + "col350": "n1nyf", + "col351": "dissg", + "col352": "tuin7", + "col353": "1fem8", + "col354": "73pku", + "col355": "9u129", + "col356": "dnn5i", + "col357": "6es9k", + "col358": "05hx9", + "col359": "hqvyp", + "col360": "n68wk", + "col361": "h16to", + "col362": "f5794", + "col363": "my0j9", + "col364": "wkfh4", + "col365": "7yfc0", + "col366": "recz8", + "col367": "fx1f3", + "col368": "yb6kh", + "col369": "vhl6p", + "col370": "hmu2n", + "col371": "inurh", + "col372": "hpmk4", + "col373": "gcwya", + "col374": "aa860", + "col375": "ty3bd", + "col376": "ov9vg", + "col377": "5o3l3", + "col378": "3hvv6", + "col379": "m9d3x", + "col380": "vymod", + "col381": "dbkt5", + "col382": "73kdn", + "col383": "fr6j1", + "col384": "r2gbh", + "col385": "f0wah", + "col386": "525c8", + "col387": "30zx2", + "col388": "vcgob", + "col389": "15pkn", + "col390": "slgay", + "col391": "zq0hq", + "col392": "tud2l", + "col393": "uapzy", + "col394": "baitg", + "col395": "a16hl", + "col396": "fu318", + "col397": "ps4vu", + "col398": "8slvy", + "col399": "jip77", + "col400": "336vp", + "col401": "7ley2", + "col402": "ey3jm", + "col403": "p6txv", + "col404": "gf6jb", + "col405": "3skgy", + "col406": "piobw", + "col407": "xy2oq", + "col408": "0oqvr", + "col409": "l0eym", + "col410": "oivzd", + "col411": "71zgr", + "col412": "zgxxv", + "col413": "yl719", + "col414": "y3wes", + "col415": "cbq6c", + "col416": "ufv0y", + "col417": "loueg", + "col418": "odvzm", + "col419": "g6un0", + "col420": "t3cd1", + "col421": "ecp4m", + "col422": "o02h1", + "col423": "1wa6s", + "col424": "pk4o5", + "col425": "cobm6", + "col426": "yzju2", + "col427": "c40my", + "col428": "mfjl1", + "col429": "i6ugo", + "col430": "gmhtc", + "col431": "08ws3", + "col432": "oylmj", + "col433": "f61r8", + "col434": "zoexd", + "col435": "u54sc", + "col436": "st4cs", + "col437": "zcwkp", + "col438": "bhd39", + "col439": "fxb41", + "col440": "5gfuu", + "col441": "ue54g", + "col442": "ahz56", + "col443": "3lqox", + "col444": "vxiam", + "col445": "ji2pb", + "col446": "s9dgq", + "col447": "noc3j", + "col448": "vy6yr", + "col449": "gezlh", + "col450": "0r548", + "col451": "j8794", + "col452": "9r85a", + "col453": "6leen", + "col454": "5a9pc", + "col455": "73jbv", + "col456": "0yv5k", + "col457": "x9yr4", + "col458": "zkssp", + "col459": "e84oy", + "col460": "ykam7", + "col461": "yg9qy", + "col462": "0wuoc", + "col463": "k1mc1", + "col464": "fvg4i", + "col465": "g88gy", + "col466": "edhig", + "col467": "5ugp1", + "col468": "0848j", + "col469": "szszb", + "col470": "eswrr", + "col471": "lrd8l", + "col472": "le4zh", + "col473": "cjal9", + "col474": "z8prd", + "col475": "ahmy3", + "col476": "ebczs", + "col477": "zb7fh", + "col478": "y5wpt", + "col479": "9xo39", + "col480": "rza50", + "col481": "7wyl6", + "col482": "kwbda", + "col483": "kti0c", + "col484": "t1yr1", + "col485": "9jzbz", + "col486": "a28la", + "col487": "evhlv", + "col488": "9gbhe", + "col489": "dm2by", + "col490": "xssq8", + "col491": "1e0i1", + "col492": "aii9x", + "col493": "jjwf2", + "col494": "ot2u3", + "col495": "c4ah1", + "col496": "nncx9", + "col497": "8mi5x", + "col498": "y8d56", + "col499": "po8gd", + "col500": "yxtf5", + "col501": "mdt71", + "col502": "g598m", + "col503": "rk5ju", + "col504": "78h81", + "col505": "6mpsr", + "col506": "913yz", + "col507": "wcrl8", + "col508": "k1r44", + "col509": "ufl1s", + "col510": "rbeqr", + "col511": "7lbf3", + "col512": "f1is2", + "col513": "2pzzv", + "col514": "787ru", + "col515": "36fvm", + "col516": "wuqf7", + "col517": "71n2v", + "col518": "145z0", + "col519": "at3um", + "col520": "or6xv", + "col521": "kkof2", + "col522": "mcqdt", + "col523": "02h3h", + "col524": "vx6p5", + "col525": "pd7iz", + "col526": "ptu5r", + "col527": "d78yr", + "col528": "lkouv", + "col529": "26f53", + "col530": "pbz3l", + "col531": "m995m", + "col532": "nv2r9", + "col533": "80vzr", + "col534": "tpqcm", + "col535": "0cjly", + "col536": "w0e7d", + "col537": "32mmz", + "col538": "d05d1", + "col539": "yan0d", + "col540": "gofeo", + "col541": "hamtk", + "col542": "ibdvm", + "col543": "tw3y3", + "col544": "layhn", + "col545": "7tz84", + "col546": "pdz7u", + "col547": "m3ypn", + "col548": "g7wa8", + "col549": "zieb2", + "col550": "1chl1", + "col551": "44n2v", + "col552": "qsoc7", + "col553": "hmscd", + "col554": "kqcuo", + "col555": "yl8hg", + "col556": "91zl8", + "col557": "bappb", + "col558": "1i51b", + "col559": "881g1", + "col560": "8kfl8", + "col561": "41wdt", + "col562": "gmpml", + "col563": "8r8me", + "col564": "de00w", + "col565": "ga00r", + "col566": "3nlee", + "col567": "sjb6s", + "col568": "28ktg", + "col569": "lay04", + "col570": "8ip80", + "col571": "tekid", + "col572": "zn486", + "col573": "72wb2", + "col574": "77hj0", + "col575": "fl11s", + "col576": "yvmq1", + "col577": "dv1ky", + "col578": "kyuid", + "col579": "opnv9", + "col580": "3zyra", + "col581": "1wyqv", + "col582": "gbfeu", + "col583": "86ouq", + "col584": "lnww4", + "col585": "vz5ju", + "col586": "9l58t", + "col587": "ymjgq", + "col588": "kflzs", + "col589": "juznw", + "col590": "46x5l", + "col591": "0ssh0", + "col592": "0vapv", + "col593": "epdra", + "col594": "gb4t7", + "col595": "q4qgp", + "col596": "ndzhh", + "col597": "2j2no", + "col598": "qvsfc", + "col599": "lnal6", + "col600": "rfqmr", + "col601": "ex2sz", + "col602": "pb6tb", + "col603": "2qip7", + "col604": "0mw44", + "col605": "7a2en", + "col606": "03jkw", + "col607": "tr2e0", + "col608": "hn2xw", + "col609": "zndrx", + "col610": "g93fa", + "col611": "m0mgq", + "col612": "4adv5", + "col613": "j311v", + "col614": "vgicw", + "col615": "2yjyp", + "col616": "ukzhl", + "col617": "awnc4", + "col618": "tppk9", + "col619": "myndk", + "col620": "mxdm1", + "col621": "y5vov", + "col622": "wg0ix", + "col623": "unbol", + "col624": "klb8a", + "col625": "r3526", + "col626": "a784s", + "col627": "dbutg", + "col628": "ii10c", + "col629": "1ikit", + "col630": "awoxd", + "col631": "i8a77", + "col632": "hrkh7", + "col633": "fdqe5", + "col634": "gtydz", + "col635": "m3erh", + "col636": "4us2c", + "col637": "kvjql", + "col638": "9fw3g", + "col639": "cyues", + "col640": "6j1bv", + "col641": "fmfsy", + "col642": "ouovq", + "col643": "13b47", + "col644": "58xmn", + "col645": "okgia", + "col646": "g6mgp", + "col647": "lpixk", + "col648": "o9xug", + "col649": "m5ifm", + "col650": "yg7ed", + "col651": "0tvx3", + "col652": "ldkgi", + "col653": "g5jl8", + "col654": "stn60", + "col655": "gzh92", + "col656": "dbw4b", + "col657": "13abe", + "col658": "0e7nm", + "col659": "ztbmj", + "col660": "2w4sh", + "col661": "8m8n8", + "col662": "7lg8q", + "col663": "d40at", + "col664": "xue0f", + "col665": "4qero", + "col666": "uat8w", + "col667": "xja75", + "col668": "4fqs1", + "col669": "oxoh6", + "col670": "1nq14", + "col671": "3nxsb", + "col672": "7kk9p", + "col673": "s18cj", + "col674": "iy3s5", + "col675": "mpayd", + "col676": "t4sf7", + "col677": "2ydqs", + "col678": "y6iv9", + "col679": "405hs", + "col680": "h095f", + "col681": "efcom", + "col682": "57fgm", + "col683": "dw8fs", + "col684": "kioyh", + "col685": "g12ql", + "col686": "9n32r", + "col687": "jabiq", + "col688": "gasg1", + "col689": "5sbmj", + "col690": "u6nig", + "col691": "lg70r", + "col692": "mbvol", + "col693": "voa6v", + "col694": "onwte", + "col695": "8m3a1", + "col696": "nsrsa", + "col697": "jgevy", + "col698": "fuix4", + "col699": "79xtq", + "col700": "8l4xj", + "col701": "slhxj", + "col702": "1sj7g", + "col703": "qtdvf", + "col704": "sdjz6", + "col705": "r6v1b", + "col706": "7djwb", + "col707": "p6qsy", + "col708": "u8k53", + "col709": "ebnu9", + "col710": "ttetm", + "col711": "syim4", + "col712": "6xbtr", + "col713": "2st6r", + "col714": "vbx2w", + "col715": "x4wdt", + "col716": "srg1i", + "col717": "qx1ch", + "col718": "lqa77", + "col719": "v4sbf", + "col720": "cb45a", + "col721": "bgndg", + "col722": "5mt6f", + "col723": "fdxlw", + "col724": "5tq7b", + "col725": "k3fia", + "col726": "2770l", + "col727": "l98yt", + "col728": "vurcr", + "col729": "kn4hj", + "col730": "oxec9", + "col731": "d10a7", + "col732": "gk0hy", + "col733": "9zjg1", + "col734": "r8dmy", + "col735": "o61eu", + "col736": "acl26", + "col737": "wpw44", + "col738": "pf8y4", + "col739": "awsnn", + "col740": "qjefb", + "col741": "7sdnl", + "col742": "96ayh", + "col743": "11ww0", + "col744": "5oynd", + "col745": "o2wc0", + "col746": "ft62t", + "col747": "4zgzr", + "col748": "ok4ca", + "col749": "7whry", + "col750": "7l5od", + "col751": "m9rxd", + "col752": "cu3u4", + "col753": "76jk1", + "col754": "gsqy4", + "col755": "m0s3v", + "col756": "hrf46", + "col757": "konf7", + "col758": "ruwbd", + "col759": "m2xw9", + "col760": "3yv5o", + "col761": "45y4x", + "col762": "7nitb", + "col763": "quc6u", + "col764": "l8cyg", + "col765": "e0gqx", + "col766": "lfxpe", + "col767": "cw8nh", + "col768": "ygwwc", + "col769": "c5gs0", + "col770": "wizpt", + "col771": "es514", + "col772": "gdcxt", + "col773": "5wdpr", + "col774": "fun3p", + "col775": "mpab0", + "col776": "870ik", + "col777": "jz1e2", + "col778": "mf8ke", + "col779": "tqoox", + "col780": "o21gh", + "col781": "uf96g", + "col782": "btyfv", + "col783": "nzp0c", + "col784": "szhdk", + "col785": "sa1jc", + "col786": "u6obq", + "col787": "u8c6k", + "col788": "daxl5", + "col789": "ucqw1", + "col790": "u1th3", + "col791": "uhlhw", + "col792": "9y2cw", + "col793": "t9vu6", + "col794": "24tac", + "col795": "mcrml", + "col796": "mj5jt", + "col797": "kam7x", + "col798": "m1zz2", + "col799": "t2ja6", + "col800": "uk25j", + "col801": "9ecuv", + "col802": "8sy02", + "col803": "knd63", + "col804": "4zllm", + "col805": "0ptg4", + "col806": "wjagg", + "col807": "popql", + "col808": "jzpyt", + "col809": "57baw", + "col810": "yr1b1", + "col811": "c6ye7", + "col812": "g0ib5", + "col813": "98v13", + "col814": "4prl6", + "col815": "nq89g", + "col816": "ueysr", + "col817": "p8zmu", + "col818": "iwz8e", + "col819": "krg62", + "col820": "8icbh", + "col821": "03rj0", + "col822": "7ezzw", + "col823": "kcidt", + "col824": "mvd6c", + "col825": "ximj9", + "col826": "0537d", + "col827": "cy6ze", + "col828": "47zoo", + "col829": "8fn9n", + "col830": "99xip", + "col831": "r7wwb", + "col832": "rjda3", + "col833": "euquu", + "col834": "2xjgi", + "col835": "ukulj", + "col836": "k5wr5", + "col837": "8ts3q", + "col838": "y6aju", + "col839": "utwr0", + "col840": "alg3k", + "col841": "dvrfe", + "col842": "x4aa8", + "col843": "38mr9", + "col844": "fo1qs", + "col845": "jw57l", + "col846": "tznd8", + "col847": "ayh8m", + "col848": "1yeq8", + "col849": "a2b7n", + "col850": "qxzq3", + "col851": "9dqmo", + "col852": "vjagr", + "col853": "mgx5t", + "col854": "emyuu", + "col855": "1nutc", + "col856": "k004w", + "col857": "fz5mh", + "col858": "g8l6z", + "col859": "u4wtk", + "col860": "nhgba", + "col861": "8s7i2", + "col862": "ao7me", + "col863": "y3p5l", + "col864": "arrss", + "col865": "udgqg", + "col866": "x7km1", + "col867": "fkubl", + "col868": "r5z9a", + "col869": "46u25", + "col870": "to0ep", + "col871": "yed21", + "col872": "nuub1", + "col873": "yyhd1", + "col874": "vmn8y", + "col875": "5hr3h", + "col876": "7d9f8", + "col877": "u4zip", + "col878": "wov93", + "col879": "nvxsu", + "col880": "9ooyf", + "col881": "40n1b", + "col882": "1l74a", + "col883": "e12cn", + "col884": "n7is9", + "col885": "myemr", + "col886": "ejrun", + "col887": "ia6n0", + "col888": "nt68q", + "col889": "ucwz2", + "col890": "sqf78", + "col891": "s9d21", + "col892": "sreuu", + "col893": "0gnqw", + "col894": "n6ihi", + "col895": "g9psj", + "col896": "ps662", + "col897": "y0d44", + "col898": "s6q6y", + "col899": "m7b9r", + "col900": "cyt2v", + "col901": "clg78", + "col902": "7md5f", + "col903": "nvlbk", + "col904": "ffjhm", + "col905": "g1cjn", + "col906": "s7a4o", + "col907": "msm7l", + "col908": "0y1mq", + "col909": "h3a6f", + "col910": "nx3k1", + "col911": "lk3e4", + "col912": "7yomo", + "col913": "icgp4", + "col914": "3d0ek", + "col915": "myqip", + "col916": "jqcaq", + "col917": "9i1x6", + "col918": "j842v", + "col919": "30wiq", + "col920": "xnjg4", + "col921": "kw1gn", + "col922": "vgw32", + "col923": "rlfhf", + "col924": "5x2v7", + "col925": "fbcs6", + "col926": "m3qsa", + "col927": "azxew", + "col928": "4z755", + "col929": "38i3q", + "col930": "ynerd", + "col931": "4v6hq", + "col932": "gnntp", + "col933": "pau37", + "col934": "a2mym", + "col935": "40lvg", + "col936": "woeyx", + "col937": "3do53", + "col938": "5qdif", + "col939": "2cfkg", + "col940": "4u2w4", + "col941": "0liwv", + "col942": "6slq4", + "col943": "qbsp0", + "col944": "z5rlu", + "col945": "349z2", + "col946": "330mi", + "col947": "d5kf1", + "col948": "cm6x9", + "col949": "6ipuk", + "col950": "jv7yv", + "col951": "7qttf", + "col952": "qey3g", + "col953": "nyino", + "col954": "gtvbm", + "col955": "9fiy9", + "col956": "14fm4", + "col957": "x3fu2", + "col958": "a3knz", + "col959": "mia6q", + "col960": "ranlr", + "col961": "6jaz7", + "col962": "inlo3", + "col963": "h7z9o", + "col964": "t9vge", + "col965": "u4ibh", + "col966": "mahs5", + "col967": "7xhrw", + "col968": "krh73", + "col969": "pist3", + "col970": "jdikt", + "col971": "ea607", + "col972": "rgc7v", + "col973": "pzs5x", + "col974": "l5ko0", + "col975": "2gt51", + "col976": "8vg16", + "col977": "pyw3v", + "col978": "3t2gi", + "col979": "l8hgw", + "col980": "qsq7l", + "col981": "owvz2", + "col982": "89w5r", + "col983": "u5sw9", + "col984": "k0jcs", + "col985": "9g6dv", + "col986": "6quv9", + "col987": "4glkw", + "col988": "3o3dd", + "col989": "arlql", + "col990": "g3gz6", + "col991": "nftly", + "col992": "tutwh", + "col993": "nay8h", + "col994": "9x3fk", + "col995": "kzprn", + "col996": "cbsho", + "col997": "kw8rc", + "col998": "hwcsm", + "col999": "mbxiy" + }, + { + "name": "Cochran Dotson", + "gender": "male", + "col0": "bdrum", + "col1": "5ijmu", + "col2": "27kmi", + "col3": "ykesw", + "col4": "qush0", + "col5": "u6s3j", + "col6": "ixdyr", + "col7": "ly3xr", + "col8": "fchgu", + "col9": "xmi52", + "col10": "dw8pq", + "col11": "uyccn", + "col12": "wa5ag", + "col13": "uok8w", + "col14": "at106", + "col15": "18v8w", + "col16": "othek", + "col17": "6tp3k", + "col18": "bntlh", + "col19": "48xau", + "col20": "4bcj4", + "col21": "9i30o", + "col22": "y4s6e", + "col23": "e4au5", + "col24": "hfvyw", + "col25": "qzwcl", + "col26": "kmaz4", + "col27": "qgn0w", + "col28": "ybcz0", + "col29": "yc00h", + "col30": "io73m", + "col31": "5hanf", + "col32": "s9mqz", + "col33": "sub9e", + "col34": "2ie48", + "col35": "w2gii", + "col36": "jilzs", + "col37": "qdar3", + "col38": "66vk5", + "col39": "9q8jz", + "col40": "mn5wc", + "col41": "jzibt", + "col42": "hv588", + "col43": "ls4xg", + "col44": "nlnfw", + "col45": "21j06", + "col46": "vgq6v", + "col47": "ql211", + "col48": "v6wbd", + "col49": "q4k3n", + "col50": "e7sj3", + "col51": "ctg0p", + "col52": "yk6z5", + "col53": "7bov6", + "col54": "zml3g", + "col55": "mxbm1", + "col56": "kzxct", + "col57": "0sww6", + "col58": "orfm7", + "col59": "mphc7", + "col60": "kme4j", + "col61": "vxddw", + "col62": "8f0eg", + "col63": "tu1a7", + "col64": "w1m6l", + "col65": "ril2g", + "col66": "n8oup", + "col67": "fbzgm", + "col68": "6km7p", + "col69": "jrmsd", + "col70": "yh02v", + "col71": "35srz", + "col72": "4qgg3", + "col73": "ndwwq", + "col74": "wkc75", + "col75": "tw1lg", + "col76": "06msn", + "col77": "vci6a", + "col78": "20a3z", + "col79": "i9rck", + "col80": "ujidi", + "col81": "3ancg", + "col82": "ev3wm", + "col83": "gxcta", + "col84": "pg4q9", + "col85": "noxiy", + "col86": "8ap0w", + "col87": "pahz1", + "col88": "72a1n", + "col89": "w7ksb", + "col90": "p5uvo", + "col91": "9xscj", + "col92": "sr2q9", + "col93": "bdigb", + "col94": "vq0gz", + "col95": "dbjkc", + "col96": "hxpuo", + "col97": "stgz9", + "col98": "ck4mv", + "col99": "jd8eo", + "col100": "43o4g", + "col101": "235nq", + "col102": "mr848", + "col103": "554nk", + "col104": "786fr", + "col105": "6d210", + "col106": "1mrfx", + "col107": "t2nrh", + "col108": "82jan", + "col109": "srk7n", + "col110": "29mgo", + "col111": "8cdpc", + "col112": "552ft", + "col113": "j4u44", + "col114": "1lfsm", + "col115": "d4o6b", + "col116": "51xd2", + "col117": "xkp0z", + "col118": "q2k93", + "col119": "gltd9", + "col120": "63wo1", + "col121": "lr6gd", + "col122": "407q1", + "col123": "7nlx3", + "col124": "vtd4m", + "col125": "890xz", + "col126": "mfgzj", + "col127": "5fm8a", + "col128": "o6t6u", + "col129": "cacqh", + "col130": "gkdzv", + "col131": "9l9y1", + "col132": "b0zc9", + "col133": "q3twm", + "col134": "jsblk", + "col135": "14h00", + "col136": "uyo41", + "col137": "dh1u1", + "col138": "ms1yz", + "col139": "gbzb4", + "col140": "0ebnb", + "col141": "i95rk", + "col142": "4f030", + "col143": "wqg61", + "col144": "49yfd", + "col145": "s5ey8", + "col146": "9gs1q", + "col147": "r5v79", + "col148": "mnlsb", + "col149": "c3yh8", + "col150": "mddrz", + "col151": "ezmv1", + "col152": "p9kqy", + "col153": "7o3hs", + "col154": "aq1om", + "col155": "16h38", + "col156": "ktpnu", + "col157": "df8hi", + "col158": "whjf1", + "col159": "2dzsj", + "col160": "lnzlp", + "col161": "yiegw", + "col162": "hb2ih", + "col163": "kl76n", + "col164": "96giq", + "col165": "zib8z", + "col166": "aaeky", + "col167": "98am9", + "col168": "51noj", + "col169": "ddiaz", + "col170": "8rv9n", + "col171": "4o0rl", + "col172": "ocw88", + "col173": "l36qg", + "col174": "6fmoe", + "col175": "bvrcu", + "col176": "rcn9t", + "col177": "9dmll", + "col178": "9xlu6", + "col179": "yhfbj", + "col180": "kaxms", + "col181": "ygn6r", + "col182": "7nfx3", + "col183": "dkn6b", + "col184": "kjrby", + "col185": "5fdk2", + "col186": "b7p7w", + "col187": "xobww", + "col188": "l5gtg", + "col189": "gdr0o", + "col190": "8codv", + "col191": "0l1ve", + "col192": "wab85", + "col193": "aftop", + "col194": "hmp6t", + "col195": "c0p6g", + "col196": "jvzz0", + "col197": "797xc", + "col198": "zymlz", + "col199": "y9x5w", + "col200": "6nzr7", + "col201": "5ykah", + "col202": "5frqw", + "col203": "fco8u", + "col204": "nwojl", + "col205": "67ghp", + "col206": "pjswq", + "col207": "pqvcd", + "col208": "el0zt", + "col209": "te91u", + "col210": "aoz1a", + "col211": "v5zfw", + "col212": "h22pq", + "col213": "bz2wm", + "col214": "72p1i", + "col215": "nafdd", + "col216": "806lz", + "col217": "amv2e", + "col218": "2p7pu", + "col219": "kkgej", + "col220": "tppku", + "col221": "4pnzu", + "col222": "pa746", + "col223": "w4dlj", + "col224": "blfzg", + "col225": "xahnu", + "col226": "mfcke", + "col227": "z3flg", + "col228": "n5kd2", + "col229": "s1k3j", + "col230": "6ekbg", + "col231": "eaq8o", + "col232": "lwqx3", + "col233": "czgfx", + "col234": "eqkix", + "col235": "hh3so", + "col236": "o37t4", + "col237": "jrshb", + "col238": "e61dp", + "col239": "2mxzy", + "col240": "6o9ot", + "col241": "irepf", + "col242": "qgbz1", + "col243": "75ovv", + "col244": "nhfss", + "col245": "cez3k", + "col246": "v2hnu", + "col247": "zup82", + "col248": "7huhm", + "col249": "79jws", + "col250": "d3xfa", + "col251": "okyb5", + "col252": "9sbuw", + "col253": "e9ubu", + "col254": "qm1ic", + "col255": "tarc9", + "col256": "gfrrh", + "col257": "qgq2e", + "col258": "8tumr", + "col259": "z2azo", + "col260": "uqtvp", + "col261": "dwt73", + "col262": "s813z", + "col263": "a53wu", + "col264": "72fq2", + "col265": "7tenh", + "col266": "asqzq", + "col267": "8doji", + "col268": "eh49v", + "col269": "16733", + "col270": "htcyn", + "col271": "amwlf", + "col272": "72t36", + "col273": "8msdh", + "col274": "cq22m", + "col275": "sn141", + "col276": "ov5nl", + "col277": "c24mw", + "col278": "jljyz", + "col279": "wvh6n", + "col280": "emdfs", + "col281": "txztk", + "col282": "msnhn", + "col283": "0kb3o", + "col284": "9v3dr", + "col285": "h8trh", + "col286": "3utmp", + "col287": "9n8k8", + "col288": "o6xo6", + "col289": "4732v", + "col290": "1wsax", + "col291": "uno3q", + "col292": "xp7tx", + "col293": "089j7", + "col294": "j3mmf", + "col295": "4y4t0", + "col296": "5yxpy", + "col297": "d5w7t", + "col298": "bl8sz", + "col299": "9o0az", + "col300": "ltgcf", + "col301": "jvjo4", + "col302": "2nh0s", + "col303": "26u5b", + "col304": "ursly", + "col305": "54zqw", + "col306": "iq6on", + "col307": "kphku", + "col308": "ebyea", + "col309": "7rg3s", + "col310": "9j1n2", + "col311": "ae47m", + "col312": "c1piy", + "col313": "882ws", + "col314": "i5ywy", + "col315": "75nr2", + "col316": "l6aq8", + "col317": "m0ufb", + "col318": "82r81", + "col319": "j6dra", + "col320": "tcnlm", + "col321": "0ylts", + "col322": "9grnj", + "col323": "h2jnv", + "col324": "ewihd", + "col325": "gtflx", + "col326": "22qu3", + "col327": "lh29q", + "col328": "vodwa", + "col329": "diqw4", + "col330": "um35r", + "col331": "kwjjw", + "col332": "tk8zg", + "col333": "8x7eq", + "col334": "ebw9k", + "col335": "xtdob", + "col336": "x5gft", + "col337": "blp7i", + "col338": "rlh4s", + "col339": "zid80", + "col340": "h2d6y", + "col341": "m9d5u", + "col342": "pphxb", + "col343": "01sou", + "col344": "iydjt", + "col345": "yvqa6", + "col346": "iyawq", + "col347": "zf96t", + "col348": "smnqo", + "col349": "4jy5t", + "col350": "6lwjs", + "col351": "q897v", + "col352": "jxlza", + "col353": "jpz8l", + "col354": "kiwc1", + "col355": "sgshe", + "col356": "n50yt", + "col357": "m8hjt", + "col358": "06h99", + "col359": "avggz", + "col360": "fx4p6", + "col361": "su0hg", + "col362": "k3u2f", + "col363": "quw2d", + "col364": "mrz3i", + "col365": "py82w", + "col366": "1b595", + "col367": "rzvr8", + "col368": "ykcfj", + "col369": "wek8x", + "col370": "pjgw6", + "col371": "oufcm", + "col372": "us74l", + "col373": "tp6zo", + "col374": "bzwkm", + "col375": "xo741", + "col376": "25v06", + "col377": "pm4tr", + "col378": "608c5", + "col379": "8bf7l", + "col380": "ic4li", + "col381": "rvjyt", + "col382": "dm2oa", + "col383": "5g1s3", + "col384": "y36be", + "col385": "cvrr1", + "col386": "31z19", + "col387": "xx3iz", + "col388": "6ku1m", + "col389": "tvh9n", + "col390": "5rsj1", + "col391": "uvmw8", + "col392": "1wx6y", + "col393": "68wlu", + "col394": "ir215", + "col395": "x6m0y", + "col396": "l4594", + "col397": "rpzsr", + "col398": "rrmku", + "col399": "dsk2r", + "col400": "z6ll0", + "col401": "9a47d", + "col402": "m1bh9", + "col403": "tnwp6", + "col404": "hnnjh", + "col405": "xp35j", + "col406": "xh248", + "col407": "n4nrp", + "col408": "qbx2b", + "col409": "4hj4k", + "col410": "2v3au", + "col411": "ugz14", + "col412": "1s8fm", + "col413": "ln5t3", + "col414": "oonjt", + "col415": "ep89b", + "col416": "x2z6h", + "col417": "1j10p", + "col418": "8w9za", + "col419": "mtfyv", + "col420": "f9arc", + "col421": "rrm8k", + "col422": "0a31a", + "col423": "aspa8", + "col424": "8sf0e", + "col425": "cxfdc", + "col426": "do7vb", + "col427": "hw4wg", + "col428": "7v7jb", + "col429": "760j1", + "col430": "t0lou", + "col431": "jqf7d", + "col432": "4fkua", + "col433": "kbbwv", + "col434": "fut9w", + "col435": "1j78t", + "col436": "ce9ax", + "col437": "sm14b", + "col438": "jd0xc", + "col439": "5aptj", + "col440": "xx4ih", + "col441": "war0z", + "col442": "r2lpd", + "col443": "hwgzz", + "col444": "x82x9", + "col445": "ikiv1", + "col446": "bt1yf", + "col447": "8irwu", + "col448": "dcatu", + "col449": "4fdp8", + "col450": "nn92z", + "col451": "d8fdv", + "col452": "xt5g4", + "col453": "eiafn", + "col454": "9ffpb", + "col455": "rb2vo", + "col456": "62t6o", + "col457": "550dy", + "col458": "odytj", + "col459": "9u5b6", + "col460": "wnwq5", + "col461": "ohupx", + "col462": "ib4gb", + "col463": "jg3kx", + "col464": "crqrp", + "col465": "dbroh", + "col466": "6o535", + "col467": "fy634", + "col468": "3qf6h", + "col469": "ntvgp", + "col470": "clmxw", + "col471": "1dvt4", + "col472": "bcv9i", + "col473": "3fldw", + "col474": "3y62y", + "col475": "7nbak", + "col476": "tdx6c", + "col477": "pnb4i", + "col478": "6d5n1", + "col479": "kyg76", + "col480": "wum3d", + "col481": "fdodl", + "col482": "5zbkz", + "col483": "j9d7d", + "col484": "bieo5", + "col485": "qvvuf", + "col486": "4uisa", + "col487": "otean", + "col488": "el039", + "col489": "vn7ob", + "col490": "fgbqr", + "col491": "okup4", + "col492": "m7sm1", + "col493": "99f9b", + "col494": "ejzrc", + "col495": "wsxar", + "col496": "1t4uu", + "col497": "7mo7z", + "col498": "rfmih", + "col499": "rsx6k", + "col500": "0lf7w", + "col501": "zvkld", + "col502": "do8o4", + "col503": "3chdt", + "col504": "rql9k", + "col505": "wkf4f", + "col506": "u8hzg", + "col507": "bd269", + "col508": "mad0c", + "col509": "8l2kf", + "col510": "cpian", + "col511": "fhwma", + "col512": "1u6wc", + "col513": "ztfyn", + "col514": "ez10m", + "col515": "ddhv7", + "col516": "bjk3l", + "col517": "xxrzt", + "col518": "pcv8d", + "col519": "4rpky", + "col520": "qhuja", + "col521": "p6c9e", + "col522": "kp9ig", + "col523": "omcwz", + "col524": "r5wq5", + "col525": "ihf84", + "col526": "i7ei9", + "col527": "g3ufn", + "col528": "08age", + "col529": "z4yvs", + "col530": "pguqt", + "col531": "j7yxe", + "col532": "bq2cq", + "col533": "pyib4", + "col534": "9t8pl", + "col535": "oba7b", + "col536": "3zcsp", + "col537": "oo9c8", + "col538": "wjvk0", + "col539": "5cf7t", + "col540": "2h75h", + "col541": "rq8us", + "col542": "926zu", + "col543": "eb4ug", + "col544": "2dwsa", + "col545": "9xr25", + "col546": "txibi", + "col547": "wl5td", + "col548": "8r1h2", + "col549": "xuwbj", + "col550": "f0679", + "col551": "vk6fv", + "col552": "2pon5", + "col553": "59oy7", + "col554": "nv6b8", + "col555": "bl7w5", + "col556": "q2dhq", + "col557": "d2xdb", + "col558": "oeve0", + "col559": "bo5gq", + "col560": "ovw1n", + "col561": "b70b1", + "col562": "1qs22", + "col563": "052vl", + "col564": "439l0", + "col565": "kdce3", + "col566": "5n04x", + "col567": "g4twr", + "col568": "pl7su", + "col569": "xqfpd", + "col570": "8a9j1", + "col571": "fqelm", + "col572": "lw6bt", + "col573": "l75us", + "col574": "jv48m", + "col575": "b2bxm", + "col576": "rj6qb", + "col577": "mzr1g", + "col578": "ludi6", + "col579": "rd2uc", + "col580": "fcbg2", + "col581": "vuo8t", + "col582": "juz2c", + "col583": "9vv0e", + "col584": "n42hp", + "col585": "j64i9", + "col586": "v4nrg", + "col587": "pvmmh", + "col588": "x9381", + "col589": "ht73k", + "col590": "c5cts", + "col591": "l7zta", + "col592": "98kco", + "col593": "zln37", + "col594": "opfyc", + "col595": "aomao", + "col596": "0pjc1", + "col597": "z34yj", + "col598": "kkmaj", + "col599": "60yen", + "col600": "ib0xn", + "col601": "l1xa5", + "col602": "cuhgd", + "col603": "kxlzy", + "col604": "36tny", + "col605": "be2ge", + "col606": "mo09l", + "col607": "p35ml", + "col608": "sl9ds", + "col609": "he7m8", + "col610": "pwm94", + "col611": "osnqi", + "col612": "llwsu", + "col613": "fqvrc", + "col614": "h0szh", + "col615": "5qj8w", + "col616": "bxud3", + "col617": "dnr8y", + "col618": "b5af5", + "col619": "lyla5", + "col620": "s1jn4", + "col621": "3k87d", + "col622": "oxx46", + "col623": "bcw8s", + "col624": "p240j", + "col625": "2gijn", + "col626": "xidc9", + "col627": "xx7fn", + "col628": "kv36b", + "col629": "g3fzn", + "col630": "w53bn", + "col631": "hx0f5", + "col632": "rox0p", + "col633": "hbaz8", + "col634": "v4yvd", + "col635": "dhr6p", + "col636": "u2kbf", + "col637": "b7vy4", + "col638": "hv5kq", + "col639": "vvs4q", + "col640": "96l3j", + "col641": "jctfk", + "col642": "kx3a5", + "col643": "pd564", + "col644": "xnzzn", + "col645": "g0vu9", + "col646": "lspbg", + "col647": "58k0q", + "col648": "s0tun", + "col649": "dgu4r", + "col650": "m1zoy", + "col651": "h4ni1", + "col652": "7f9ef", + "col653": "glnwb", + "col654": "coj4z", + "col655": "ggy9h", + "col656": "tno1g", + "col657": "b6kuw", + "col658": "aslhs", + "col659": "yibud", + "col660": "mo8tj", + "col661": "bd265", + "col662": "p75gv", + "col663": "8knh7", + "col664": "15uu7", + "col665": "fhont", + "col666": "stsuw", + "col667": "f29mf", + "col668": "bn15k", + "col669": "ilqj8", + "col670": "yk1q6", + "col671": "pq92m", + "col672": "8zhee", + "col673": "y0x50", + "col674": "y4f6o", + "col675": "xozy9", + "col676": "xww7s", + "col677": "4b94e", + "col678": "zfq0b", + "col679": "nhno9", + "col680": "04oin", + "col681": "2te0h", + "col682": "hh0kz", + "col683": "jzq8q", + "col684": "nuv8l", + "col685": "9zxz3", + "col686": "yyr5q", + "col687": "ls63y", + "col688": "mhds2", + "col689": "yb8yh", + "col690": "bi9sf", + "col691": "ub6vp", + "col692": "sknh7", + "col693": "nacc2", + "col694": "ev7x0", + "col695": "gm4cj", + "col696": "x02rt", + "col697": "ngvvx", + "col698": "o20px", + "col699": "v6mbs", + "col700": "hzl7s", + "col701": "0biep", + "col702": "zvln8", + "col703": "g3v48", + "col704": "2nc4e", + "col705": "cwu8s", + "col706": "ge9c1", + "col707": "44mup", + "col708": "xi47t", + "col709": "zcnix", + "col710": "qatlx", + "col711": "0ud6p", + "col712": "ainqd", + "col713": "wpz6g", + "col714": "9jlxc", + "col715": "5dwu6", + "col716": "0eydu", + "col717": "4vn9t", + "col718": "ti7jg", + "col719": "w53ly", + "col720": "1kxer", + "col721": "7s0xn", + "col722": "lm28i", + "col723": "lt9xq", + "col724": "xc9a0", + "col725": "xojyv", + "col726": "lc8ba", + "col727": "lqgpw", + "col728": "6wcb5", + "col729": "sv6xk", + "col730": "ir899", + "col731": "gt611", + "col732": "94ubl", + "col733": "996io", + "col734": "lwo5w", + "col735": "4x270", + "col736": "c8x4s", + "col737": "g0dw8", + "col738": "vxwgg", + "col739": "dlm17", + "col740": "z8ocf", + "col741": "t7wck", + "col742": "ky601", + "col743": "gqgkl", + "col744": "5ypfu", + "col745": "ce7wl", + "col746": "tugh5", + "col747": "m21u3", + "col748": "scubt", + "col749": "8kyau", + "col750": "2pwqw", + "col751": "iuckh", + "col752": "wexuz", + "col753": "ydodm", + "col754": "txcrf", + "col755": "2mnpa", + "col756": "ugt2b", + "col757": "1tb23", + "col758": "q6lvu", + "col759": "sixae", + "col760": "cuzr9", + "col761": "8jmiy", + "col762": "ks73j", + "col763": "1354g", + "col764": "47jek", + "col765": "xsdfy", + "col766": "1gs8t", + "col767": "qu6ow", + "col768": "srslv", + "col769": "xd6vj", + "col770": "fxtit", + "col771": "7zlsl", + "col772": "4mj4f", + "col773": "27yxe", + "col774": "mg86l", + "col775": "cmwh8", + "col776": "ags9l", + "col777": "zzwld", + "col778": "g5wax", + "col779": "a4iam", + "col780": "y3sa2", + "col781": "ot2mz", + "col782": "tlbax", + "col783": "zhwd2", + "col784": "ioikh", + "col785": "3z0mv", + "col786": "wgoni", + "col787": "djqh5", + "col788": "cshl5", + "col789": "n2q9n", + "col790": "5hun6", + "col791": "1lvet", + "col792": "z3ms8", + "col793": "x6gsv", + "col794": "usct4", + "col795": "1tb8y", + "col796": "fd8sn", + "col797": "v0ca3", + "col798": "508rq", + "col799": "e86pn", + "col800": "hn70l", + "col801": "ug97b", + "col802": "hyobe", + "col803": "dwuyp", + "col804": "m5fjd", + "col805": "xanr7", + "col806": "p9u3p", + "col807": "ebjp0", + "col808": "rnqtl", + "col809": "037nc", + "col810": "19k9u", + "col811": "9rsrj", + "col812": "m8tkq", + "col813": "ep2kc", + "col814": "e2bq3", + "col815": "to3sh", + "col816": "rvx9c", + "col817": "mgxes", + "col818": "b3zx2", + "col819": "xduj9", + "col820": "87z9p", + "col821": "asoqj", + "col822": "6uoa7", + "col823": "i6hoo", + "col824": "885n9", + "col825": "owa1w", + "col826": "pyuv4", + "col827": "k1thb", + "col828": "xo3y0", + "col829": "7sa0s", + "col830": "r35zh", + "col831": "1m15f", + "col832": "xhvfj", + "col833": "8s7g7", + "col834": "odd5h", + "col835": "dncvy", + "col836": "dxp9w", + "col837": "pl19o", + "col838": "jsvxs", + "col839": "937ma", + "col840": "p1du3", + "col841": "vgadc", + "col842": "d401k", + "col843": "ej7h7", + "col844": "sdcmo", + "col845": "xwbxy", + "col846": "x83js", + "col847": "c4j03", + "col848": "ux5ff", + "col849": "d22ho", + "col850": "06nlw", + "col851": "3780s", + "col852": "2wkx4", + "col853": "tg2yx", + "col854": "u17bp", + "col855": "zjg0j", + "col856": "ercir", + "col857": "9723y", + "col858": "tg3wl", + "col859": "qrmu9", + "col860": "484pn", + "col861": "5j5rz", + "col862": "5tfa3", + "col863": "5rja9", + "col864": "46u8x", + "col865": "kbkhs", + "col866": "pq8x5", + "col867": "50k3o", + "col868": "3e9b3", + "col869": "tkyke", + "col870": "ffnlg", + "col871": "6q15u", + "col872": "y44b9", + "col873": "r1ogz", + "col874": "s1xwc", + "col875": "aoec5", + "col876": "p6w8y", + "col877": "lw5u2", + "col878": "69psi", + "col879": "be62y", + "col880": "oarwh", + "col881": "5hcz1", + "col882": "vh6zm", + "col883": "gg2w5", + "col884": "p8ovc", + "col885": "yf3fa", + "col886": "5jjol", + "col887": "gjzz5", + "col888": "7wg15", + "col889": "onp9f", + "col890": "zkiue", + "col891": "pc07i", + "col892": "gifzh", + "col893": "7f9vc", + "col894": "xzvkz", + "col895": "glj5v", + "col896": "z8pts", + "col897": "e4ots", + "col898": "2i46q", + "col899": "xy5xa", + "col900": "5y5nr", + "col901": "87rh9", + "col902": "nbdpa", + "col903": "b814x", + "col904": "ddmdh", + "col905": "yq0b9", + "col906": "j3kk1", + "col907": "ffmpy", + "col908": "6b59l", + "col909": "zr9h7", + "col910": "pkf7h", + "col911": "q67wl", + "col912": "ka94a", + "col913": "prrf7", + "col914": "f8ryi", + "col915": "16eha", + "col916": "xuzjg", + "col917": "c0ykv", + "col918": "ea3s0", + "col919": "0b64p", + "col920": "0obmd", + "col921": "4amow", + "col922": "aj1i8", + "col923": "pyrl6", + "col924": "6vitt", + "col925": "wxmy1", + "col926": "48gc1", + "col927": "2wqot", + "col928": "jlp07", + "col929": "7n7cf", + "col930": "ae6co", + "col931": "lk5g0", + "col932": "0tagg", + "col933": "m7wio", + "col934": "qv0b0", + "col935": "j4d6f", + "col936": "iqyc1", + "col937": "a1cqd", + "col938": "mu4a2", + "col939": "ru6ph", + "col940": "jooen", + "col941": "o60ml", + "col942": "0psrt", + "col943": "pc5gc", + "col944": "hls9c", + "col945": "xcijt", + "col946": "bgyom", + "col947": "kkpiv", + "col948": "b4c4y", + "col949": "v0w09", + "col950": "bxlrp", + "col951": "z37m4", + "col952": "2ra2w", + "col953": "c8u7j", + "col954": "68kkd", + "col955": "00di4", + "col956": "zwp5q", + "col957": "c60od", + "col958": "ckf47", + "col959": "mxguf", + "col960": "wwnk8", + "col961": "t9gcm", + "col962": "175d0", + "col963": "kottj", + "col964": "uoazw", + "col965": "dk0ql", + "col966": "trfhv", + "col967": "tllx3", + "col968": "7fyco", + "col969": "syou3", + "col970": "0lboi", + "col971": "imvqf", + "col972": "p45g2", + "col973": "ud7gh", + "col974": "m8x3w", + "col975": "h26k7", + "col976": "noavj", + "col977": "drt6s", + "col978": "k517r", + "col979": "hxqxl", + "col980": "i66va", + "col981": "zqc2v", + "col982": "z55tt", + "col983": "sm25i", + "col984": "292pb", + "col985": "rsmyi", + "col986": "s0yte", + "col987": "n1hvm", + "col988": "xrnix", + "col989": "qazkq", + "col990": "tn94q", + "col991": "j4tqw", + "col992": "tdegg", + "col993": "eunbk", + "col994": "p97hb", + "col995": "6ybjq", + "col996": "pm2fk", + "col997": "usmv6", + "col998": "m6zwq", + "col999": "i1am5" + }, + { + "name": "Castro Heath", + "gender": "male", + "col0": "o1wp1", + "col1": "gck8a", + "col2": "xyh2p", + "col3": "7z7z1", + "col4": "7busl", + "col5": "x4z7x", + "col6": "pcpdx", + "col7": "9nrs7", + "col8": "2aodk", + "col9": "p4jmk", + "col10": "un1gu", + "col11": "bzjbi", + "col12": "5nj2a", + "col13": "wt8xw", + "col14": "2iiz4", + "col15": "7zie8", + "col16": "q2iwu", + "col17": "9gyon", + "col18": "lguzb", + "col19": "vbnsh", + "col20": "fune5", + "col21": "yt63d", + "col22": "vryaw", + "col23": "vjmf8", + "col24": "odghw", + "col25": "j4kq1", + "col26": "x0l3d", + "col27": "znq3r", + "col28": "nq5b7", + "col29": "yw620", + "col30": "bp2n9", + "col31": "1gr4a", + "col32": "y3es5", + "col33": "boejv", + "col34": "9x8mk", + "col35": "azuv8", + "col36": "2g7lb", + "col37": "0fsvc", + "col38": "iqidu", + "col39": "sh0gu", + "col40": "441i8", + "col41": "srbfg", + "col42": "24ja5", + "col43": "289i6", + "col44": "hevev", + "col45": "nafhe", + "col46": "nfl5j", + "col47": "jes9k", + "col48": "knovl", + "col49": "c026d", + "col50": "az9sw", + "col51": "rjfv1", + "col52": "129dh", + "col53": "jvzif", + "col54": "gqytq", + "col55": "jnygi", + "col56": "yryam", + "col57": "p0j6j", + "col58": "xz5wh", + "col59": "k5at6", + "col60": "2j3y8", + "col61": "ckc4l", + "col62": "tia1l", + "col63": "ful1r", + "col64": "gqkk1", + "col65": "5bb88", + "col66": "1x50r", + "col67": "qmmyh", + "col68": "vgeuf", + "col69": "od6w6", + "col70": "hk17m", + "col71": "vburh", + "col72": "kjw0p", + "col73": "142bv", + "col74": "myyr9", + "col75": "t1ok7", + "col76": "inaw8", + "col77": "pbwju", + "col78": "044lu", + "col79": "a9vs1", + "col80": "3spvc", + "col81": "tlgfp", + "col82": "bz7o3", + "col83": "1b0f6", + "col84": "nbt4n", + "col85": "chgbd", + "col86": "cbfah", + "col87": "ctr05", + "col88": "68jtf", + "col89": "g3jr9", + "col90": "3qpyd", + "col91": "eie3d", + "col92": "mreuj", + "col93": "4cy3d", + "col94": "5lpu8", + "col95": "eqzrg", + "col96": "56tv9", + "col97": "jafem", + "col98": "ftz19", + "col99": "lpbqv", + "col100": "z6fk9", + "col101": "o4o0t", + "col102": "wfrny", + "col103": "9iexj", + "col104": "f1ron", + "col105": "zs9pd", + "col106": "dc7v2", + "col107": "mxo89", + "col108": "cy9q7", + "col109": "eq86s", + "col110": "mobkd", + "col111": "rkaia", + "col112": "mdiuo", + "col113": "u3z41", + "col114": "rba4b", + "col115": "6qann", + "col116": "bdayq", + "col117": "281a1", + "col118": "7jc7x", + "col119": "jt31m", + "col120": "wfkzy", + "col121": "iftdo", + "col122": "ol3j1", + "col123": "jkqhi", + "col124": "asasg", + "col125": "wskfq", + "col126": "02w3d", + "col127": "r44qu", + "col128": "fs578", + "col129": "gcf6c", + "col130": "db9se", + "col131": "m53q8", + "col132": "e0nbj", + "col133": "j3a5w", + "col134": "up5xi", + "col135": "9cok6", + "col136": "22rec", + "col137": "vxt49", + "col138": "kmdx5", + "col139": "g2diq", + "col140": "93i8a", + "col141": "73xht", + "col142": "k9xji", + "col143": "8ve04", + "col144": "6pkye", + "col145": "cefdw", + "col146": "4v6gb", + "col147": "cynlu", + "col148": "9hxw6", + "col149": "s8quq", + "col150": "mtbxl", + "col151": "7bxur", + "col152": "xwbln", + "col153": "yvx7j", + "col154": "22xl3", + "col155": "jr8up", + "col156": "9yhhc", + "col157": "60ksv", + "col158": "h6csd", + "col159": "4p6me", + "col160": "ze8a9", + "col161": "bps7u", + "col162": "n1b53", + "col163": "avrbg", + "col164": "gb7cv", + "col165": "44due", + "col166": "dhxvx", + "col167": "mfz71", + "col168": "j93ko", + "col169": "tlzbg", + "col170": "mra74", + "col171": "7spbr", + "col172": "tqong", + "col173": "41xcv", + "col174": "43n4r", + "col175": "dqs1w", + "col176": "bs330", + "col177": "lu6gb", + "col178": "yd9lz", + "col179": "toebx", + "col180": "mjqlc", + "col181": "mx4hf", + "col182": "tzqjw", + "col183": "kyyv4", + "col184": "mgfdn", + "col185": "580kz", + "col186": "96t22", + "col187": "ec2ep", + "col188": "0axjo", + "col189": "t99yr", + "col190": "9rnpj", + "col191": "lqxqk", + "col192": "a53n2", + "col193": "v84wi", + "col194": "8f9ka", + "col195": "8lk2q", + "col196": "htjqq", + "col197": "v1n88", + "col198": "ead6y", + "col199": "plce2", + "col200": "0i3qo", + "col201": "u102d", + "col202": "t7eeu", + "col203": "d0ynd", + "col204": "11tld", + "col205": "q2jtj", + "col206": "shbn7", + "col207": "7pb5u", + "col208": "lyc5n", + "col209": "oo3h5", + "col210": "gpoia", + "col211": "y47f5", + "col212": "ny1k4", + "col213": "uxyrm", + "col214": "odb5d", + "col215": "5n149", + "col216": "1bnq5", + "col217": "l9unn", + "col218": "drbko", + "col219": "741u4", + "col220": "1ekp2", + "col221": "8o8s2", + "col222": "5ghow", + "col223": "eyenp", + "col224": "06c3j", + "col225": "4oypt", + "col226": "kplov", + "col227": "w4xji", + "col228": "gserv", + "col229": "ox86q", + "col230": "sqy6o", + "col231": "knzmp", + "col232": "7r5jw", + "col233": "ttonc", + "col234": "f97wf", + "col235": "enyc0", + "col236": "nhvb8", + "col237": "ocso4", + "col238": "c5fpq", + "col239": "jo56r", + "col240": "5sm5m", + "col241": "97w1e", + "col242": "e0r2k", + "col243": "m5dsg", + "col244": "i9pod", + "col245": "v4yj3", + "col246": "68bdd", + "col247": "68ora", + "col248": "rkuop", + "col249": "3bk4r", + "col250": "v81tk", + "col251": "jxpjp", + "col252": "qwmxy", + "col253": "b28ze", + "col254": "wvezf", + "col255": "uocaw", + "col256": "8k26y", + "col257": "i1583", + "col258": "gys6d", + "col259": "fml10", + "col260": "yf9kz", + "col261": "l78ij", + "col262": "riaj7", + "col263": "8ms5h", + "col264": "sgiuw", + "col265": "ksdbp", + "col266": "rhkk8", + "col267": "x4j4v", + "col268": "egpiu", + "col269": "iarx6", + "col270": "iheun", + "col271": "gln0j", + "col272": "vovgi", + "col273": "8le7j", + "col274": "gvhdf", + "col275": "spfn1", + "col276": "e2ibn", + "col277": "2i0cb", + "col278": "jqrac", + "col279": "13fv7", + "col280": "5gqmd", + "col281": "gwagf", + "col282": "utv5q", + "col283": "t8bxw", + "col284": "rxar7", + "col285": "7hqsr", + "col286": "qv8l6", + "col287": "4vqw7", + "col288": "p3vu2", + "col289": "gl9no", + "col290": "598g6", + "col291": "hvzp9", + "col292": "28jdl", + "col293": "vr0fb", + "col294": "g6meq", + "col295": "v8pa1", + "col296": "0njaw", + "col297": "7eur2", + "col298": "trk16", + "col299": "r0nei", + "col300": "2zt3h", + "col301": "xski9", + "col302": "gyga6", + "col303": "jccym", + "col304": "aq9rr", + "col305": "4c8mh", + "col306": "fy55i", + "col307": "linc4", + "col308": "5jdyb", + "col309": "s3xi7", + "col310": "n14ww", + "col311": "24q7h", + "col312": "lhapk", + "col313": "n79dw", + "col314": "8fgvt", + "col315": "ba947", + "col316": "oz2yu", + "col317": "75do6", + "col318": "bhjzg", + "col319": "i03ab", + "col320": "4uggu", + "col321": "t3fyo", + "col322": "rvx9n", + "col323": "3visn", + "col324": "juroq", + "col325": "26g10", + "col326": "oupe2", + "col327": "7dq6t", + "col328": "bw6g9", + "col329": "cdbbc", + "col330": "u8nxb", + "col331": "3zs3o", + "col332": "56w46", + "col333": "zhzgl", + "col334": "8hztw", + "col335": "10y4x", + "col336": "2lr3o", + "col337": "cr2fa", + "col338": "jtkze", + "col339": "ofk6g", + "col340": "ewmpw", + "col341": "17jv5", + "col342": "liktz", + "col343": "2ao1w", + "col344": "ie656", + "col345": "nltfa", + "col346": "faa0z", + "col347": "2eyt9", + "col348": "3ukcx", + "col349": "owo26", + "col350": "r2dwb", + "col351": "vv1cq", + "col352": "w7ddu", + "col353": "4khkz", + "col354": "gl1uh", + "col355": "x43uk", + "col356": "frkcl", + "col357": "rh1sv", + "col358": "cpgu1", + "col359": "i938v", + "col360": "2tu2u", + "col361": "lgshz", + "col362": "1vaii", + "col363": "3im15", + "col364": "a0bkf", + "col365": "qlf03", + "col366": "se7q5", + "col367": "00gkt", + "col368": "so5go", + "col369": "u0j3l", + "col370": "s2xop", + "col371": "9dyok", + "col372": "atb7o", + "col373": "6w4jc", + "col374": "pwxu8", + "col375": "hizpe", + "col376": "yqw9l", + "col377": "9u4s9", + "col378": "piizd", + "col379": "tu7dj", + "col380": "o63am", + "col381": "sn3z6", + "col382": "ga783", + "col383": "15hff", + "col384": "r01m3", + "col385": "acyoe", + "col386": "qnqog", + "col387": "tye1p", + "col388": "zzyxh", + "col389": "s9aaz", + "col390": "kqy88", + "col391": "m7mm9", + "col392": "zw4nq", + "col393": "a8v3g", + "col394": "avcfa", + "col395": "c2ehj", + "col396": "4p0mm", + "col397": "x71sh", + "col398": "oj809", + "col399": "3lqdc", + "col400": "frpxx", + "col401": "k0n1i", + "col402": "9l30z", + "col403": "16hek", + "col404": "xx8ge", + "col405": "lvukp", + "col406": "oq2x5", + "col407": "1jy43", + "col408": "mvtav", + "col409": "jox0q", + "col410": "6rknj", + "col411": "2sa7t", + "col412": "rbqxy", + "col413": "5kwbw", + "col414": "amn58", + "col415": "750ak", + "col416": "ec6a4", + "col417": "gfhry", + "col418": "zsxpl", + "col419": "f2waq", + "col420": "8a2wz", + "col421": "ote5d", + "col422": "d13r8", + "col423": "upn4p", + "col424": "wkelk", + "col425": "l0zsf", + "col426": "d1u5i", + "col427": "7k5ju", + "col428": "armdj", + "col429": "eo6pm", + "col430": "b8sdo", + "col431": "jumva", + "col432": "iim9w", + "col433": "3wyyt", + "col434": "bk247", + "col435": "jc4hq", + "col436": "bttxm", + "col437": "wobqn", + "col438": "uqvr3", + "col439": "evwcd", + "col440": "mk2xv", + "col441": "8kgkw", + "col442": "i34ty", + "col443": "rsjw6", + "col444": "usutn", + "col445": "mpgyc", + "col446": "n67hz", + "col447": "8dlyy", + "col448": "laz5k", + "col449": "k9q75", + "col450": "cx957", + "col451": "b2y4u", + "col452": "hs8kn", + "col453": "x6edo", + "col454": "awji3", + "col455": "elutw", + "col456": "juthh", + "col457": "4aw72", + "col458": "tyx4n", + "col459": "faiff", + "col460": "o674g", + "col461": "5a7su", + "col462": "zg7lm", + "col463": "49n4e", + "col464": "3wpnk", + "col465": "g2rs4", + "col466": "544qy", + "col467": "43skg", + "col468": "s891x", + "col469": "urihz", + "col470": "neeee", + "col471": "3msdc", + "col472": "zx5wb", + "col473": "i08mw", + "col474": "ft2eb", + "col475": "6o3og", + "col476": "hib2e", + "col477": "tnz3r", + "col478": "7zykp", + "col479": "rk9bx", + "col480": "naxdh", + "col481": "7n29b", + "col482": "85340", + "col483": "d90uc", + "col484": "gnkwa", + "col485": "3ev5l", + "col486": "u180e", + "col487": "4ttur", + "col488": "9a5hm", + "col489": "g2wwc", + "col490": "rgnoz", + "col491": "22xd9", + "col492": "co15i", + "col493": "5ya3j", + "col494": "viyqm", + "col495": "cfuu8", + "col496": "h08q3", + "col497": "e9q1k", + "col498": "4edk3", + "col499": "8gen9", + "col500": "mcymq", + "col501": "qpiqb", + "col502": "qnimd", + "col503": "14ath", + "col504": "jk3h2", + "col505": "jl1mg", + "col506": "shuft", + "col507": "rf5wx", + "col508": "b84zb", + "col509": "q78zu", + "col510": "ktujm", + "col511": "13jz0", + "col512": "tzr3p", + "col513": "1gyta", + "col514": "d4ygp", + "col515": "1jogo", + "col516": "n4jlm", + "col517": "fsbwr", + "col518": "rom25", + "col519": "u8d8f", + "col520": "mn6jb", + "col521": "fnyrf", + "col522": "dmfpi", + "col523": "cr8ee", + "col524": "f9st8", + "col525": "xxvpp", + "col526": "n0qk8", + "col527": "j06lz", + "col528": "g7bqm", + "col529": "j05ch", + "col530": "oc8ju", + "col531": "fc1hp", + "col532": "jfar1", + "col533": "bgbd5", + "col534": "tiy64", + "col535": "f96hl", + "col536": "afi2p", + "col537": "h82g6", + "col538": "g2ohs", + "col539": "jqgkj", + "col540": "lrniz", + "col541": "wpkc5", + "col542": "pf2kx", + "col543": "cn8tr", + "col544": "pdxno", + "col545": "deuqt", + "col546": "pjxgc", + "col547": "sj1hm", + "col548": "jcf62", + "col549": "akti6", + "col550": "dh2fg", + "col551": "yns33", + "col552": "8ecbk", + "col553": "ncprj", + "col554": "us2qw", + "col555": "v0ntt", + "col556": "mj18a", + "col557": "qygui", + "col558": "1rdyh", + "col559": "skjyk", + "col560": "doqam", + "col561": "ylz2c", + "col562": "sisrz", + "col563": "pccg5", + "col564": "ua1yp", + "col565": "kczf9", + "col566": "zpsij", + "col567": "k44cn", + "col568": "msn3m", + "col569": "3pi99", + "col570": "b29b9", + "col571": "3tl5g", + "col572": "ygdbg", + "col573": "40ppg", + "col574": "l1jke", + "col575": "35xyk", + "col576": "eb7mk", + "col577": "xd50z", + "col578": "sp70q", + "col579": "ssu05", + "col580": "fufwy", + "col581": "t6kxq", + "col582": "jhmxp", + "col583": "k5m4n", + "col584": "cl3bm", + "col585": "9tbbd", + "col586": "8t7m8", + "col587": "ko3w0", + "col588": "nwu3c", + "col589": "nip3z", + "col590": "meggf", + "col591": "6sejl", + "col592": "j34yx", + "col593": "ss2rg", + "col594": "hp267", + "col595": "3jg4n", + "col596": "6igte", + "col597": "ex88r", + "col598": "f8aqw", + "col599": "wp9he", + "col600": "h13l3", + "col601": "64e36", + "col602": "cf1fm", + "col603": "ege47", + "col604": "1t71d", + "col605": "f26bc", + "col606": "ddd1s", + "col607": "dawte", + "col608": "kmsyy", + "col609": "kpv0b", + "col610": "syhyr", + "col611": "1vnsl", + "col612": "nukvw", + "col613": "5wsg3", + "col614": "uai71", + "col615": "er3ys", + "col616": "g83kw", + "col617": "89orn", + "col618": "wuorq", + "col619": "nirdo", + "col620": "fmosr", + "col621": "8jvfe", + "col622": "n3olo", + "col623": "t0z2h", + "col624": "mcfpk", + "col625": "fxqiz", + "col626": "j76j3", + "col627": "v5w6l", + "col628": "dmy4s", + "col629": "ij1yv", + "col630": "zhef6", + "col631": "qowvd", + "col632": "opl3h", + "col633": "3yaoo", + "col634": "9c2cs", + "col635": "wjp29", + "col636": "v9ynn", + "col637": "r897d", + "col638": "0uxa8", + "col639": "qf0az", + "col640": "8mh5p", + "col641": "40stp", + "col642": "em4dg", + "col643": "4ffs8", + "col644": "82r3v", + "col645": "vu4tb", + "col646": "os3du", + "col647": "cn58x", + "col648": "b0s5x", + "col649": "jiv66", + "col650": "jjeth", + "col651": "nczht", + "col652": "kdj8d", + "col653": "1qvvj", + "col654": "6umii", + "col655": "amyvb", + "col656": "aojur", + "col657": "smwf1", + "col658": "a3ugw", + "col659": "pbj0l", + "col660": "9losi", + "col661": "5qzxm", + "col662": "1a9gw", + "col663": "2o3wb", + "col664": "48zcs", + "col665": "0xubi", + "col666": "ylns6", + "col667": "e91r4", + "col668": "elxfu", + "col669": "ewkum", + "col670": "7qhh8", + "col671": "vvq3u", + "col672": "4pty4", + "col673": "y6vfk", + "col674": "xnagx", + "col675": "ujl5s", + "col676": "983ql", + "col677": "8a0h2", + "col678": "e0gla", + "col679": "egaxa", + "col680": "s7sw5", + "col681": "kfbto", + "col682": "vl2cj", + "col683": "iwgfc", + "col684": "yhown", + "col685": "eb921", + "col686": "a8ypy", + "col687": "ljvnq", + "col688": "gsk58", + "col689": "f7t6f", + "col690": "atv0p", + "col691": "u1jjf", + "col692": "clcwx", + "col693": "42wo8", + "col694": "s6mir", + "col695": "jqvtb", + "col696": "oybgj", + "col697": "34sfk", + "col698": "1oswd", + "col699": "fjjsn", + "col700": "nytlj", + "col701": "kd3xo", + "col702": "m6jjd", + "col703": "2rs9g", + "col704": "xjtuu", + "col705": "sbnu1", + "col706": "0l27m", + "col707": "bw4uc", + "col708": "duncp", + "col709": "bdcvb", + "col710": "yblsn", + "col711": "blf5w", + "col712": "0ew5w", + "col713": "k0xol", + "col714": "bv9s5", + "col715": "17vgn", + "col716": "8sshn", + "col717": "012tg", + "col718": "cvtd9", + "col719": "2q6qk", + "col720": "z04eb", + "col721": "ibcub", + "col722": "6cv0v", + "col723": "hd75o", + "col724": "wq9qy", + "col725": "7436z", + "col726": "6oxvd", + "col727": "6b2wk", + "col728": "fr6ke", + "col729": "49gos", + "col730": "q44q3", + "col731": "thdzg", + "col732": "7gml9", + "col733": "2ol10", + "col734": "cfw13", + "col735": "t1gco", + "col736": "loz1y", + "col737": "s58p7", + "col738": "qypvu", + "col739": "fs08d", + "col740": "x3f1p", + "col741": "e6njm", + "col742": "l4e6o", + "col743": "nyxdr", + "col744": "xllg8", + "col745": "2hrlo", + "col746": "2p4it", + "col747": "1lls0", + "col748": "odkxl", + "col749": "ll86g", + "col750": "6qvq1", + "col751": "zg6nh", + "col752": "n3yyg", + "col753": "c3zin", + "col754": "j4d8g", + "col755": "emujj", + "col756": "wktoo", + "col757": "0fgkx", + "col758": "syunn", + "col759": "6xte8", + "col760": "ho267", + "col761": "tohfo", + "col762": "w2w1a", + "col763": "oe6p7", + "col764": "kmqqo", + "col765": "m63ne", + "col766": "bfjx0", + "col767": "3u8nc", + "col768": "sdtob", + "col769": "gfzg9", + "col770": "il5aj", + "col771": "cq9ax", + "col772": "la4de", + "col773": "fz5hd", + "col774": "e365b", + "col775": "m48jy", + "col776": "to6x3", + "col777": "96rzs", + "col778": "g4ugc", + "col779": "o2j6k", + "col780": "pklsm", + "col781": "l6ekp", + "col782": "5cflz", + "col783": "hqnzz", + "col784": "n2p2l", + "col785": "f9ray", + "col786": "3brv8", + "col787": "ea6we", + "col788": "phlxq", + "col789": "js20y", + "col790": "62di4", + "col791": "3898p", + "col792": "42hnr", + "col793": "kqssq", + "col794": "w9cqu", + "col795": "x8hy3", + "col796": "ccfxv", + "col797": "y27q6", + "col798": "yhlcb", + "col799": "ubamu", + "col800": "pputb", + "col801": "xydax", + "col802": "9tea3", + "col803": "gesrx", + "col804": "n5fik", + "col805": "okip3", + "col806": "a9nbr", + "col807": "i8lzx", + "col808": "0p4ss", + "col809": "yvi8e", + "col810": "t0j9w", + "col811": "qoqq9", + "col812": "225fi", + "col813": "oiew2", + "col814": "hvy0s", + "col815": "azdw3", + "col816": "4uy0y", + "col817": "mp9am", + "col818": "skzcn", + "col819": "rqbvk", + "col820": "hzant", + "col821": "2twli", + "col822": "xxqmq", + "col823": "xu08c", + "col824": "he26t", + "col825": "bjenw", + "col826": "dcaiy", + "col827": "htesm", + "col828": "birnv", + "col829": "to547", + "col830": "8qrqr", + "col831": "klbov", + "col832": "mmf6g", + "col833": "ezypq", + "col834": "kzsq3", + "col835": "7uta4", + "col836": "he4cq", + "col837": "dgqrq", + "col838": "4wgnw", + "col839": "u97yl", + "col840": "xh6v2", + "col841": "vc7v7", + "col842": "n5s1x", + "col843": "ecpyy", + "col844": "yw8ms", + "col845": "vo101", + "col846": "qme8a", + "col847": "wbgke", + "col848": "nvsyy", + "col849": "bbge3", + "col850": "rxret", + "col851": "yxgfb", + "col852": "rctx1", + "col853": "bk3h9", + "col854": "zwtgf", + "col855": "eipdm", + "col856": "x9yxj", + "col857": "6qft5", + "col858": "dszyw", + "col859": "fppbq", + "col860": "uh13x", + "col861": "feiyb", + "col862": "uwen7", + "col863": "2ks5v", + "col864": "4rgzu", + "col865": "k8ms2", + "col866": "3ro9u", + "col867": "qyprv", + "col868": "bhoao", + "col869": "u6rfi", + "col870": "oojhy", + "col871": "xvigu", + "col872": "j5v2i", + "col873": "f0q0l", + "col874": "ldwa6", + "col875": "qoc58", + "col876": "xm1bj", + "col877": "4p6ic", + "col878": "cdfxw", + "col879": "t086g", + "col880": "5g9lh", + "col881": "ur8v2", + "col882": "fi2uq", + "col883": "6rylw", + "col884": "4szp5", + "col885": "prgl8", + "col886": "lxfy0", + "col887": "4znk1", + "col888": "nnqza", + "col889": "9tmms", + "col890": "nhdg7", + "col891": "3zmle", + "col892": "5wvwf", + "col893": "ldloi", + "col894": "k2wo7", + "col895": "nimeb", + "col896": "dt12v", + "col897": "wxtzx", + "col898": "gz8j6", + "col899": "4jbcb", + "col900": "3n6ss", + "col901": "jkd0p", + "col902": "wqp3q", + "col903": "df7pa", + "col904": "prts0", + "col905": "rippc", + "col906": "c87bo", + "col907": "jbcmy", + "col908": "1hlfd", + "col909": "jwvxc", + "col910": "izuqf", + "col911": "ba3i5", + "col912": "c39lw", + "col913": "4ffgk", + "col914": "oxtii", + "col915": "dc3fq", + "col916": "qnzn9", + "col917": "78j5e", + "col918": "fjw1t", + "col919": "w2wql", + "col920": "zidmx", + "col921": "5rpju", + "col922": "saqo9", + "col923": "z3v3p", + "col924": "20kuk", + "col925": "9yjdn", + "col926": "7qbot", + "col927": "c5wbw", + "col928": "8yhhj", + "col929": "1do0y", + "col930": "phqek", + "col931": "yiqom", + "col932": "d5z2t", + "col933": "ylvm3", + "col934": "u42tq", + "col935": "gfs9i", + "col936": "nba4k", + "col937": "zbud1", + "col938": "0dyhg", + "col939": "kd1ex", + "col940": "vj4xv", + "col941": "ts1c2", + "col942": "hmmsc", + "col943": "frqbt", + "col944": "aigwv", + "col945": "5zx5g", + "col946": "ihi0d", + "col947": "3wmbb", + "col948": "fw1ne", + "col949": "hbvgx", + "col950": "neufr", + "col951": "ma3w9", + "col952": "2vbl4", + "col953": "qxvvg", + "col954": "ar4ws", + "col955": "8l640", + "col956": "dn3k6", + "col957": "n1mhn", + "col958": "c3g7c", + "col959": "xkrl7", + "col960": "m5aqd", + "col961": "w4c3s", + "col962": "92vny", + "col963": "zbmdj", + "col964": "1j6og", + "col965": "rv0kz", + "col966": "fvfg5", + "col967": "ddzqx", + "col968": "37fuv", + "col969": "3zdcc", + "col970": "isda8", + "col971": "q3f0o", + "col972": "730za", + "col973": "2t5yo", + "col974": "tjk65", + "col975": "k349a", + "col976": "28uut", + "col977": "225mn", + "col978": "z9he0", + "col979": "ggaz9", + "col980": "64ids", + "col981": "vgnhv", + "col982": "54zkd", + "col983": "qg4vj", + "col984": "nj3ht", + "col985": "fe2dm", + "col986": "glucl", + "col987": "uqdgj", + "col988": "dz34b", + "col989": "pj4pz", + "col990": "fnevh", + "col991": "cz8p9", + "col992": "nzssf", + "col993": "a056e", + "col994": "1f1ra", + "col995": "axixj", + "col996": "g6ik6", + "col997": "st9ej", + "col998": "yqxtn", + "col999": "jn7pi" + }, + { + "name": "England Gaines", + "gender": "male", + "col0": "8bqqz", + "col1": "xq13u", + "col2": "dp6p6", + "col3": "jxl4k", + "col4": "g87pp", + "col5": "fi6dd", + "col6": "lxk8z", + "col7": "nuimi", + "col8": "he18u", + "col9": "r6rgl", + "col10": "a76lw", + "col11": "qrsj3", + "col12": "um2sp", + "col13": "c1vdd", + "col14": "toy3o", + "col15": "9do5u", + "col16": "26snt", + "col17": "k3nef", + "col18": "ykxam", + "col19": "36jip", + "col20": "spdri", + "col21": "07qgd", + "col22": "h4jq3", + "col23": "t17br", + "col24": "81ctm", + "col25": "7igxq", + "col26": "jat0v", + "col27": "74e3l", + "col28": "zh5be", + "col29": "w05js", + "col30": "3sjrp", + "col31": "1e2s7", + "col32": "qdfwi", + "col33": "ab0y5", + "col34": "yv9ec", + "col35": "j8p92", + "col36": "i7ic8", + "col37": "omazz", + "col38": "esgb0", + "col39": "aoyji", + "col40": "65gnc", + "col41": "l2x1p", + "col42": "9ule1", + "col43": "j05l0", + "col44": "hjrxs", + "col45": "ztcdk", + "col46": "coxtj", + "col47": "939b1", + "col48": "r7h87", + "col49": "cmc10", + "col50": "w5j5z", + "col51": "grbel", + "col52": "b7sgz", + "col53": "cihrp", + "col54": "oe0kp", + "col55": "ofw2r", + "col56": "1suam", + "col57": "8rq9t", + "col58": "36em4", + "col59": "5ohh6", + "col60": "5nli3", + "col61": "wp1or", + "col62": "jh5nm", + "col63": "jomdz", + "col64": "1rcyy", + "col65": "83y2h", + "col66": "ve21w", + "col67": "068if", + "col68": "nk4hy", + "col69": "7l8pv", + "col70": "n9b09", + "col71": "m1ffx", + "col72": "grmj0", + "col73": "92mwi", + "col74": "v4yjy", + "col75": "m3lwc", + "col76": "w78o4", + "col77": "in054", + "col78": "dr99a", + "col79": "9r8dj", + "col80": "f3utf", + "col81": "rde85", + "col82": "o6h90", + "col83": "a76j6", + "col84": "3cjqr", + "col85": "vsf8v", + "col86": "j7cwp", + "col87": "5di6t", + "col88": "j81vo", + "col89": "hssak", + "col90": "v0dwf", + "col91": "redpd", + "col92": "nzjci", + "col93": "rjbhk", + "col94": "cb78q", + "col95": "onb3j", + "col96": "ik1dh", + "col97": "2y39y", + "col98": "s1le8", + "col99": "ic38z", + "col100": "0r4eq", + "col101": "c8fpw", + "col102": "ycbvn", + "col103": "35k8e", + "col104": "kpw0b", + "col105": "5nepm", + "col106": "3hsog", + "col107": "qi0ot", + "col108": "75psn", + "col109": "xj9jn", + "col110": "qgdtf", + "col111": "pgrjt", + "col112": "v31l4", + "col113": "9ympn", + "col114": "mhsc3", + "col115": "2crd2", + "col116": "nlolc", + "col117": "bojhl", + "col118": "pc5sb", + "col119": "s6ukn", + "col120": "d13ap", + "col121": "bksen", + "col122": "x9u0v", + "col123": "2mqec", + "col124": "zjrut", + "col125": "ab1nh", + "col126": "yx1ks", + "col127": "mmpco", + "col128": "ukr1o", + "col129": "6g7am", + "col130": "clp3i", + "col131": "o54th", + "col132": "a1258", + "col133": "v6wra", + "col134": "32r7d", + "col135": "103ld", + "col136": "wgcy8", + "col137": "r3j2t", + "col138": "qqfa7", + "col139": "qq3vs", + "col140": "rl5y7", + "col141": "unhl8", + "col142": "u1qs7", + "col143": "iw4rc", + "col144": "wilok", + "col145": "5y21m", + "col146": "w4xri", + "col147": "gtom8", + "col148": "u8oee", + "col149": "58iwz", + "col150": "kc7yu", + "col151": "i7ikm", + "col152": "2cazq", + "col153": "kyer0", + "col154": "5rlh7", + "col155": "hkxau", + "col156": "7bu2o", + "col157": "0onbj", + "col158": "6xf6q", + "col159": "j567w", + "col160": "q82ts", + "col161": "f4j28", + "col162": "883qj", + "col163": "y2ypq", + "col164": "6839s", + "col165": "um012", + "col166": "76wjm", + "col167": "rg8x1", + "col168": "2aums", + "col169": "ktlie", + "col170": "x1eox", + "col171": "kp0xx", + "col172": "1tdon", + "col173": "1nbu9", + "col174": "zwzvx", + "col175": "o7i4a", + "col176": "hzrh2", + "col177": "z5b1t", + "col178": "8iia5", + "col179": "exawr", + "col180": "bjj0s", + "col181": "3e2ke", + "col182": "d29g8", + "col183": "7gw6u", + "col184": "znf3w", + "col185": "hkee3", + "col186": "rmiik", + "col187": "ln3wq", + "col188": "rqkm4", + "col189": "mlzyb", + "col190": "opl6l", + "col191": "iqmvg", + "col192": "515dt", + "col193": "om2f4", + "col194": "g892e", + "col195": "5wjws", + "col196": "pr4ps", + "col197": "y3tds", + "col198": "37b5y", + "col199": "yy53p", + "col200": "f5ksn", + "col201": "l356n", + "col202": "yulhl", + "col203": "neffr", + "col204": "wdfpp", + "col205": "cv5sv", + "col206": "cwerj", + "col207": "zd0ye", + "col208": "dpfva", + "col209": "bwahp", + "col210": "7dld8", + "col211": "ciyqh", + "col212": "tseu3", + "col213": "4m1xg", + "col214": "6ui0k", + "col215": "anwec", + "col216": "bxvgj", + "col217": "2hj2r", + "col218": "a62x4", + "col219": "7t9is", + "col220": "3d1z1", + "col221": "u2drz", + "col222": "iix7c", + "col223": "pvi0s", + "col224": "80ua2", + "col225": "l3wuy", + "col226": "y7tda", + "col227": "digym", + "col228": "swoc7", + "col229": "jxnws", + "col230": "ombi4", + "col231": "crg1e", + "col232": "t5cv2", + "col233": "y99fh", + "col234": "7k8g9", + "col235": "nc72z", + "col236": "t3eah", + "col237": "x1lvc", + "col238": "kea66", + "col239": "uwahy", + "col240": "fqrdo", + "col241": "svj8z", + "col242": "oer7y", + "col243": "9ey2k", + "col244": "mq9yt", + "col245": "9avnd", + "col246": "jx216", + "col247": "g26h5", + "col248": "e0ke4", + "col249": "fr8gw", + "col250": "iykyb", + "col251": "qm86f", + "col252": "mzc2v", + "col253": "kwu0k", + "col254": "8wmoj", + "col255": "wa147", + "col256": "vae58", + "col257": "vzdaw", + "col258": "yret4", + "col259": "wvv3x", + "col260": "ojmum", + "col261": "0tddt", + "col262": "18l6w", + "col263": "omzwv", + "col264": "ixxbd", + "col265": "qvcxm", + "col266": "3tsv3", + "col267": "ze0wm", + "col268": "qmieu", + "col269": "vma6g", + "col270": "zzfwz", + "col271": "fldku", + "col272": "yeqby", + "col273": "m90t1", + "col274": "bfjfz", + "col275": "yuffs", + "col276": "9wc5c", + "col277": "8ny8c", + "col278": "3rq04", + "col279": "0a8vj", + "col280": "jxqj3", + "col281": "ia39t", + "col282": "g55wm", + "col283": "77i31", + "col284": "y1b46", + "col285": "8cb8z", + "col286": "7c7g8", + "col287": "8towy", + "col288": "qg4f2", + "col289": "13s5w", + "col290": "airz2", + "col291": "53fb7", + "col292": "onhlc", + "col293": "gg5cg", + "col294": "mgxv1", + "col295": "cxvpa", + "col296": "otp7e", + "col297": "4yzoc", + "col298": "pmccy", + "col299": "qronb", + "col300": "n8f0f", + "col301": "05w0q", + "col302": "kltg3", + "col303": "qp7cs", + "col304": "218ps", + "col305": "zsv7a", + "col306": "ruy46", + "col307": "2uea7", + "col308": "s3ro4", + "col309": "li8qc", + "col310": "94a8a", + "col311": "mj1jj", + "col312": "sdmsu", + "col313": "gqac7", + "col314": "4r2z0", + "col315": "qvubc", + "col316": "bczps", + "col317": "w9bvy", + "col318": "9oasy", + "col319": "5o91w", + "col320": "rmyz1", + "col321": "zp9n5", + "col322": "0m746", + "col323": "k4t8m", + "col324": "1tf8n", + "col325": "lke8s", + "col326": "xgi95", + "col327": "38mx3", + "col328": "ks357", + "col329": "0h4p3", + "col330": "xbbak", + "col331": "yvaj8", + "col332": "uo9ue", + "col333": "p1dq1", + "col334": "jwkel", + "col335": "dz7m6", + "col336": "i9lp6", + "col337": "ulipl", + "col338": "6l7y9", + "col339": "w4v5p", + "col340": "vaaq1", + "col341": "a86zz", + "col342": "5pzks", + "col343": "tje1s", + "col344": "clhsz", + "col345": "tt1y2", + "col346": "edtt4", + "col347": "09tt3", + "col348": "x4g9s", + "col349": "wu6p5", + "col350": "ggd9b", + "col351": "4kynt", + "col352": "8mij8", + "col353": "2ycr8", + "col354": "tbvuo", + "col355": "b0887", + "col356": "053yu", + "col357": "qqwka", + "col358": "s6su6", + "col359": "3dw7r", + "col360": "9ej4a", + "col361": "jkfh8", + "col362": "508lj", + "col363": "q3ckt", + "col364": "gnla6", + "col365": "ok619", + "col366": "xqp1p", + "col367": "wzthu", + "col368": "xcymx", + "col369": "fkkxy", + "col370": "9qkkv", + "col371": "ybzvj", + "col372": "tdt20", + "col373": "leq5s", + "col374": "rshmx", + "col375": "rkrqq", + "col376": "xnfih", + "col377": "tgzdh", + "col378": "matsa", + "col379": "5x187", + "col380": "m8izy", + "col381": "zixu8", + "col382": "q6vs5", + "col383": "lwnsl", + "col384": "n22x3", + "col385": "bp7hi", + "col386": "bhfvr", + "col387": "ii06v", + "col388": "wulzy", + "col389": "s40h2", + "col390": "c7n5i", + "col391": "qfaj4", + "col392": "4xtob", + "col393": "me2x4", + "col394": "vwtka", + "col395": "sejue", + "col396": "vigt8", + "col397": "77meg", + "col398": "qjpvu", + "col399": "eyl17", + "col400": "l0n8o", + "col401": "p14a8", + "col402": "mbqi3", + "col403": "kzuiw", + "col404": "tz2nb", + "col405": "n8aac", + "col406": "v9lc2", + "col407": "otlx4", + "col408": "9b1dt", + "col409": "kempa", + "col410": "9145d", + "col411": "hrgpr", + "col412": "w48fi", + "col413": "l9rd7", + "col414": "d6dc8", + "col415": "5mmzx", + "col416": "fyknq", + "col417": "1m155", + "col418": "huhh1", + "col419": "4e9xx", + "col420": "xrv0d", + "col421": "7lfez", + "col422": "01t4g", + "col423": "ix7gc", + "col424": "2qghw", + "col425": "84b48", + "col426": "ttv5y", + "col427": "2pt7g", + "col428": "8xqx6", + "col429": "nco1e", + "col430": "3brhc", + "col431": "mf8hj", + "col432": "50u9b", + "col433": "ll37m", + "col434": "3354t", + "col435": "bjqnl", + "col436": "sgs4x", + "col437": "kmzdi", + "col438": "85iso", + "col439": "hjwap", + "col440": "2kxdw", + "col441": "1te4k", + "col442": "1m6vx", + "col443": "3rs32", + "col444": "ddggh", + "col445": "3eek2", + "col446": "98ete", + "col447": "3w9q3", + "col448": "mo3k0", + "col449": "on0gb", + "col450": "evmwv", + "col451": "yd4yr", + "col452": "8j3hk", + "col453": "a9rz0", + "col454": "wz3vx", + "col455": "xutac", + "col456": "f3k2d", + "col457": "p0m3q", + "col458": "o8two", + "col459": "ygglq", + "col460": "0g6wv", + "col461": "fsi95", + "col462": "elsuh", + "col463": "3nin4", + "col464": "7zs05", + "col465": "6zokp", + "col466": "3forn", + "col467": "tgszd", + "col468": "y1nrr", + "col469": "56szd", + "col470": "oo3tf", + "col471": "doh22", + "col472": "coagr", + "col473": "vobvz", + "col474": "8k155", + "col475": "2duve", + "col476": "idede", + "col477": "kmqsd", + "col478": "s0m9v", + "col479": "6y8hq", + "col480": "epejb", + "col481": "2y58o", + "col482": "a6e2g", + "col483": "1ykmy", + "col484": "5lmue", + "col485": "hgi9u", + "col486": "ydh5b", + "col487": "ncd1w", + "col488": "78b9d", + "col489": "x5jwx", + "col490": "5tyne", + "col491": "oycni", + "col492": "bst3r", + "col493": "ae95n", + "col494": "tdn05", + "col495": "ov8v7", + "col496": "6dms9", + "col497": "74tcp", + "col498": "0p8mr", + "col499": "u1hq3", + "col500": "kobbn", + "col501": "9nsnw", + "col502": "ik631", + "col503": "fgqt9", + "col504": "7bmxj", + "col505": "4c9df", + "col506": "u2142", + "col507": "n52lz", + "col508": "p6qpx", + "col509": "r3q7o", + "col510": "71npv", + "col511": "ekhe7", + "col512": "v4lbp", + "col513": "aep2p", + "col514": "134pu", + "col515": "orntr", + "col516": "eap65", + "col517": "rwcay", + "col518": "ujgwy", + "col519": "bv866", + "col520": "zzzzh", + "col521": "uqszr", + "col522": "rl5bt", + "col523": "3au5m", + "col524": "dy1c5", + "col525": "7gaic", + "col526": "k9aah", + "col527": "gs4wk", + "col528": "uyzwi", + "col529": "buuv6", + "col530": "1yax4", + "col531": "c1ura", + "col532": "j6wu6", + "col533": "ihuar", + "col534": "38s9o", + "col535": "gigzv", + "col536": "7xahb", + "col537": "fvbu3", + "col538": "9kelq", + "col539": "3onvx", + "col540": "a9gsk", + "col541": "z3fs0", + "col542": "1btyr", + "col543": "6t1z3", + "col544": "uhnz1", + "col545": "cmuin", + "col546": "l3sey", + "col547": "lbago", + "col548": "ohtg2", + "col549": "hnkjj", + "col550": "5is1p", + "col551": "ttreg", + "col552": "g9xhd", + "col553": "9z3tz", + "col554": "9s36m", + "col555": "14hws", + "col556": "rb00s", + "col557": "h6ebm", + "col558": "84j70", + "col559": "5ag8g", + "col560": "uvr96", + "col561": "xj9sp", + "col562": "ahh15", + "col563": "umsgd", + "col564": "iwldo", + "col565": "tzam3", + "col566": "mju2a", + "col567": "qacw7", + "col568": "vtmc2", + "col569": "idcip", + "col570": "9mtxz", + "col571": "xg6vt", + "col572": "wq3wz", + "col573": "45yut", + "col574": "gjfbd", + "col575": "timke", + "col576": "mnm4o", + "col577": "f9w3a", + "col578": "ty1fx", + "col579": "ombct", + "col580": "n2wa2", + "col581": "jlqd4", + "col582": "zupfz", + "col583": "wrr69", + "col584": "p0mq6", + "col585": "93fa0", + "col586": "7yoza", + "col587": "9updj", + "col588": "8lam4", + "col589": "low9w", + "col590": "jxmh0", + "col591": "f2ts5", + "col592": "9qs4v", + "col593": "ljxpu", + "col594": "d9uzl", + "col595": "chg8v", + "col596": "r2xir", + "col597": "dx9wk", + "col598": "oi1h8", + "col599": "kime4", + "col600": "4srh5", + "col601": "r6h4w", + "col602": "l2ge4", + "col603": "3csqi", + "col604": "su4vu", + "col605": "ev6vp", + "col606": "i5ref", + "col607": "6lext", + "col608": "54bjk", + "col609": "zq2lm", + "col610": "wgtqe", + "col611": "fn8wt", + "col612": "94crd", + "col613": "chwfe", + "col614": "ur1vp", + "col615": "7ivm1", + "col616": "xu6ok", + "col617": "put3w", + "col618": "quygx", + "col619": "52ucp", + "col620": "b26gi", + "col621": "52is8", + "col622": "f58ho", + "col623": "3olhj", + "col624": "7o1ji", + "col625": "272tx", + "col626": "644ow", + "col627": "p64p1", + "col628": "mn2yb", + "col629": "mne8f", + "col630": "nhpuz", + "col631": "o625p", + "col632": "1s1bv", + "col633": "e3cl4", + "col634": "s3pgg", + "col635": "xwoms", + "col636": "qau8n", + "col637": "ivhbv", + "col638": "968ft", + "col639": "k2isg", + "col640": "uccaa", + "col641": "l80e1", + "col642": "mpguu", + "col643": "piqov", + "col644": "zuagi", + "col645": "g6bxp", + "col646": "9w5du", + "col647": "b327y", + "col648": "dk59v", + "col649": "e60k9", + "col650": "kzbgz", + "col651": "dpbku", + "col652": "c4tis", + "col653": "3kjr1", + "col654": "jjjym", + "col655": "opdpk", + "col656": "cym6o", + "col657": "3cnsu", + "col658": "namhl", + "col659": "4d0oz", + "col660": "9wg76", + "col661": "ii87h", + "col662": "ytmur", + "col663": "bdr28", + "col664": "txw3w", + "col665": "p9s6d", + "col666": "1pd1o", + "col667": "6dgqr", + "col668": "kugpd", + "col669": "q9ktv", + "col670": "puaww", + "col671": "d9cia", + "col672": "4p9ik", + "col673": "2gav5", + "col674": "keeum", + "col675": "c8f7a", + "col676": "6bveh", + "col677": "58n4r", + "col678": "9fcih", + "col679": "n2wiy", + "col680": "pel43", + "col681": "l20c6", + "col682": "0jjyn", + "col683": "ny4fu", + "col684": "zrooo", + "col685": "rs9xr", + "col686": "aqcse", + "col687": "kvsmw", + "col688": "iig0a", + "col689": "te5mm", + "col690": "2m9va", + "col691": "w5ch0", + "col692": "5o282", + "col693": "lg928", + "col694": "jn60l", + "col695": "s2m68", + "col696": "ndv1h", + "col697": "cc2qk", + "col698": "s4lb5", + "col699": "yof74", + "col700": "ums2h", + "col701": "kmq5p", + "col702": "6ccn7", + "col703": "rgt68", + "col704": "7nz7i", + "col705": "n3z1j", + "col706": "lxgv2", + "col707": "99pso", + "col708": "l1g1b", + "col709": "geig8", + "col710": "lcu5v", + "col711": "rjdul", + "col712": "87790", + "col713": "0a3x2", + "col714": "jj2ur", + "col715": "iyj2w", + "col716": "5345l", + "col717": "su5b5", + "col718": "v9vel", + "col719": "wy7up", + "col720": "u1y3m", + "col721": "3ihvg", + "col722": "3ogml", + "col723": "b6jd1", + "col724": "egfpb", + "col725": "33twx", + "col726": "dfcg5", + "col727": "t6seb", + "col728": "ipw4a", + "col729": "uvx65", + "col730": "omxyj", + "col731": "5hp9l", + "col732": "8so5l", + "col733": "n16wn", + "col734": "vvmky", + "col735": "xaxwz", + "col736": "4fra3", + "col737": "6fqv8", + "col738": "syfqy", + "col739": "qdbd6", + "col740": "w9z3x", + "col741": "qzn6z", + "col742": "i6ujc", + "col743": "6zmk3", + "col744": "jp0b3", + "col745": "qk7ka", + "col746": "usqmr", + "col747": "x9q1h", + "col748": "os68c", + "col749": "m7l05", + "col750": "10mwe", + "col751": "2deqa", + "col752": "cb77s", + "col753": "l0bih", + "col754": "l3sd3", + "col755": "imp8i", + "col756": "9zhmm", + "col757": "sofqf", + "col758": "0ume3", + "col759": "hqupk", + "col760": "qqtyr", + "col761": "lf1mg", + "col762": "p80jb", + "col763": "xkvoi", + "col764": "vlmyj", + "col765": "d45a7", + "col766": "srfbb", + "col767": "xvpm4", + "col768": "hp1pr", + "col769": "4yn82", + "col770": "c1rm3", + "col771": "5udze", + "col772": "bcnhy", + "col773": "uqfl7", + "col774": "p20tr", + "col775": "8q91a", + "col776": "pds92", + "col777": "bjqtf", + "col778": "8pyl9", + "col779": "uz5ik", + "col780": "9ijve", + "col781": "0cx2d", + "col782": "b4s4b", + "col783": "mor26", + "col784": "2x0g4", + "col785": "l9w9l", + "col786": "3apc3", + "col787": "dx6g0", + "col788": "5bn4o", + "col789": "hqkhe", + "col790": "80emr", + "col791": "fngnz", + "col792": "s61u8", + "col793": "me06v", + "col794": "j6jau", + "col795": "d681b", + "col796": "49t2q", + "col797": "8iaxv", + "col798": "ouggq", + "col799": "k59fq", + "col800": "cj7hr", + "col801": "n7sit", + "col802": "bj9nz", + "col803": "t90t3", + "col804": "le4ul", + "col805": "73fz2", + "col806": "waetf", + "col807": "fjcy4", + "col808": "44gbf", + "col809": "hfkuz", + "col810": "489kh", + "col811": "nrysf", + "col812": "snfu5", + "col813": "zaaa3", + "col814": "ye40p", + "col815": "ki020", + "col816": "0bb60", + "col817": "8787e", + "col818": "07xa9", + "col819": "19wpi", + "col820": "vfhcy", + "col821": "5zxf2", + "col822": "5vttk", + "col823": "6hkfg", + "col824": "vvpeb", + "col825": "1uz19", + "col826": "ptemo", + "col827": "jds7j", + "col828": "uysl0", + "col829": "9aurw", + "col830": "c6fz9", + "col831": "kvua2", + "col832": "80dm6", + "col833": "cdklk", + "col834": "28ctt", + "col835": "6urq6", + "col836": "bjoaj", + "col837": "9fxf9", + "col838": "keknc", + "col839": "kub91", + "col840": "ihwm7", + "col841": "cvi47", + "col842": "4ouhz", + "col843": "00yg7", + "col844": "sj5iq", + "col845": "qeyvk", + "col846": "6aup6", + "col847": "gbw4w", + "col848": "4765k", + "col849": "gezkw", + "col850": "82n5a", + "col851": "ihcr4", + "col852": "67z6l", + "col853": "omahz", + "col854": "lhgmy", + "col855": "hp36u", + "col856": "t3wvp", + "col857": "9guqt", + "col858": "ko9ed", + "col859": "tw09f", + "col860": "g65w8", + "col861": "dchhf", + "col862": "hddeq", + "col863": "h0mnm", + "col864": "afnka", + "col865": "xjmpb", + "col866": "ahb92", + "col867": "mc05t", + "col868": "kzrop", + "col869": "4vt1t", + "col870": "51atm", + "col871": "y2ipl", + "col872": "5iy41", + "col873": "1opja", + "col874": "m3gu1", + "col875": "29tlb", + "col876": "8wenl", + "col877": "oo23b", + "col878": "vi9lr", + "col879": "ntvex", + "col880": "zeg2s", + "col881": "qzro4", + "col882": "ju1h5", + "col883": "s7nl5", + "col884": "8luor", + "col885": "urqud", + "col886": "zec23", + "col887": "os1jf", + "col888": "4gsmy", + "col889": "ehnxq", + "col890": "41hqx", + "col891": "nhrd3", + "col892": "akzcv", + "col893": "ry82j", + "col894": "g3nyx", + "col895": "t05g1", + "col896": "ztx5n", + "col897": "3x97x", + "col898": "su4fx", + "col899": "sfvtf", + "col900": "o7500", + "col901": "7pasi", + "col902": "t5nco", + "col903": "3euch", + "col904": "3enh7", + "col905": "bdmqx", + "col906": "6zscn", + "col907": "djrpu", + "col908": "xajc5", + "col909": "om0eh", + "col910": "mguo6", + "col911": "ildfl", + "col912": "3eohv", + "col913": "m9sjj", + "col914": "8am2k", + "col915": "n93v8", + "col916": "3w8uj", + "col917": "90gws", + "col918": "ydyt2", + "col919": "7drsn", + "col920": "ejvh8", + "col921": "n3y2q", + "col922": "yr7z4", + "col923": "71w68", + "col924": "j46rg", + "col925": "zwl0q", + "col926": "j8ccp", + "col927": "csu8z", + "col928": "1vuuy", + "col929": "lrbkz", + "col930": "3lp7b", + "col931": "2g5z5", + "col932": "9a7li", + "col933": "ol5aj", + "col934": "yl6z6", + "col935": "g0kh3", + "col936": "4l0us", + "col937": "a57an", + "col938": "zlvyw", + "col939": "8xv2h", + "col940": "n9axp", + "col941": "oxbrk", + "col942": "h4x1u", + "col943": "5m9sb", + "col944": "nwxsu", + "col945": "dfnw1", + "col946": "n4c7v", + "col947": "y95rb", + "col948": "hnkxy", + "col949": "pt37m", + "col950": "kllzt", + "col951": "gdmxq", + "col952": "ri0gf", + "col953": "ptfs2", + "col954": "t1ia3", + "col955": "64bvr", + "col956": "1ku1o", + "col957": "rcqdx", + "col958": "y3vxj", + "col959": "kcgx6", + "col960": "f99t5", + "col961": "h1ewf", + "col962": "mvpai", + "col963": "n8j8l", + "col964": "fs0f5", + "col965": "ehm8l", + "col966": "7711m", + "col967": "g77j4", + "col968": "91vn9", + "col969": "zidlx", + "col970": "bw7sv", + "col971": "6so4l", + "col972": "p8b2j", + "col973": "q1628", + "col974": "41g18", + "col975": "1m5p3", + "col976": "ucpbe", + "col977": "gr69n", + "col978": "cg7g9", + "col979": "v4qfu", + "col980": "d3jtv", + "col981": "emuek", + "col982": "y9zxm", + "col983": "9w14u", + "col984": "rwkg2", + "col985": "vq41w", + "col986": "14w9c", + "col987": "fo3c0", + "col988": "5w1s3", + "col989": "gm987", + "col990": "2stp8", + "col991": "lhj6y", + "col992": "37rxl", + "col993": "1wd6a", + "col994": "5ha6t", + "col995": "2na7b", + "col996": "7fube", + "col997": "x816x", + "col998": "t2hts", + "col999": "tis57" + }, + { + "name": "Johnson Duffy", + "gender": "male", + "col0": "wt372", + "col1": "vumhl", + "col2": "ajigt", + "col3": "p2631", + "col4": "ixi6b", + "col5": "h51pm", + "col6": "osm7x", + "col7": "z3970", + "col8": "qf4el", + "col9": "8wjae", + "col10": "16xdf", + "col11": "mmycx", + "col12": "2n8d9", + "col13": "nzwsp", + "col14": "vckgt", + "col15": "q7o9m", + "col16": "g7jre", + "col17": "hjj9b", + "col18": "f21u4", + "col19": "tj5a0", + "col20": "noxhg", + "col21": "wvyc1", + "col22": "c707n", + "col23": "73kjo", + "col24": "4jbwh", + "col25": "vvddg", + "col26": "8601v", + "col27": "jmk0y", + "col28": "g9abb", + "col29": "xdlym", + "col30": "78qc8", + "col31": "5nd8g", + "col32": "uptk4", + "col33": "7trd9", + "col34": "kkw58", + "col35": "pxmcm", + "col36": "sl54e", + "col37": "vwycs", + "col38": "5t5e7", + "col39": "bknv0", + "col40": "20i9a", + "col41": "p7ijl", + "col42": "t87ha", + "col43": "w8u2a", + "col44": "t4oio", + "col45": "3z3sw", + "col46": "b1z5w", + "col47": "tybbn", + "col48": "7f801", + "col49": "ho0re", + "col50": "c8ynj", + "col51": "tlq1r", + "col52": "o9zu4", + "col53": "nhhw2", + "col54": "batzy", + "col55": "jpsey", + "col56": "x9o0k", + "col57": "o7ad8", + "col58": "welp8", + "col59": "grh58", + "col60": "3nugm", + "col61": "rphwh", + "col62": "nykzj", + "col63": "yr8kc", + "col64": "wdu39", + "col65": "lq7ld", + "col66": "v0kql", + "col67": "3b2h2", + "col68": "s80hc", + "col69": "x5bqx", + "col70": "rpe2f", + "col71": "5g2xf", + "col72": "uhksw", + "col73": "fmrjo", + "col74": "c4wbr", + "col75": "fsd5q", + "col76": "jlog9", + "col77": "9lbpg", + "col78": "g0vty", + "col79": "z5r88", + "col80": "pcacp", + "col81": "wzznm", + "col82": "vsfoq", + "col83": "tzcvf", + "col84": "576os", + "col85": "8agf1", + "col86": "mqmja", + "col87": "24xs3", + "col88": "drz5a", + "col89": "400xr", + "col90": "i2nbb", + "col91": "citaf", + "col92": "wv6h4", + "col93": "12c7c", + "col94": "s18hn", + "col95": "emfux", + "col96": "6s5dp", + "col97": "1ydwb", + "col98": "beq7t", + "col99": "l63nw", + "col100": "jxazb", + "col101": "vtkwy", + "col102": "z13h0", + "col103": "jajmk", + "col104": "psl6u", + "col105": "omiks", + "col106": "9a3uk", + "col107": "91x5h", + "col108": "u7cft", + "col109": "ol387", + "col110": "sqril", + "col111": "4qqn3", + "col112": "ykq0k", + "col113": "lkuqc", + "col114": "nywh7", + "col115": "3m27t", + "col116": "ntgly", + "col117": "ka8sg", + "col118": "lqhlb", + "col119": "t6rnf", + "col120": "ij0o2", + "col121": "9pgtm", + "col122": "aje9r", + "col123": "s5huf", + "col124": "0b077", + "col125": "tqbak", + "col126": "3sopk", + "col127": "oze1u", + "col128": "frxzm", + "col129": "7g7bt", + "col130": "jzu37", + "col131": "49ql6", + "col132": "joalb", + "col133": "eepzg", + "col134": "yphrq", + "col135": "xv09n", + "col136": "nvvj3", + "col137": "e99y8", + "col138": "tyjat", + "col139": "usz0u", + "col140": "5ne1c", + "col141": "du04e", + "col142": "cfbiq", + "col143": "842lq", + "col144": "hkkzh", + "col145": "2ab6f", + "col146": "jzt9m", + "col147": "qa7ml", + "col148": "karcc", + "col149": "iussa", + "col150": "l79as", + "col151": "amavl", + "col152": "pvfno", + "col153": "wnbyr", + "col154": "kurw8", + "col155": "y9noh", + "col156": "524du", + "col157": "ea2gp", + "col158": "6ri80", + "col159": "x4j1l", + "col160": "7thjk", + "col161": "75p5g", + "col162": "sbpx9", + "col163": "scucn", + "col164": "kd8nv", + "col165": "t73aa", + "col166": "yqxoy", + "col167": "orpir", + "col168": "2qkpm", + "col169": "n2k2i", + "col170": "xrnu6", + "col171": "hwypv", + "col172": "d36w5", + "col173": "v7qur", + "col174": "r026s", + "col175": "dq293", + "col176": "rpr9f", + "col177": "ks64h", + "col178": "8xxjr", + "col179": "0owfj", + "col180": "4rv0b", + "col181": "ufgtc", + "col182": "raxxn", + "col183": "g6e1e", + "col184": "44sph", + "col185": "ptfnc", + "col186": "rjm32", + "col187": "l119f", + "col188": "qpjd4", + "col189": "xt7yk", + "col190": "i9jos", + "col191": "yhgzp", + "col192": "wnw8h", + "col193": "vd9ou", + "col194": "hfrut", + "col195": "rnlv0", + "col196": "hr357", + "col197": "y4h0f", + "col198": "n9q3j", + "col199": "t8x7j", + "col200": "0fsky", + "col201": "r2qip", + "col202": "pps0p", + "col203": "2xr7c", + "col204": "shs40", + "col205": "0719g", + "col206": "i7w99", + "col207": "bl8uz", + "col208": "b2pxc", + "col209": "4yktx", + "col210": "1176u", + "col211": "aov8h", + "col212": "0o9p3", + "col213": "pmg5a", + "col214": "tq0t1", + "col215": "2neku", + "col216": "fuaoq", + "col217": "l4aav", + "col218": "dmco3", + "col219": "2lkpl", + "col220": "iv977", + "col221": "xn3k5", + "col222": "hyxkg", + "col223": "oqs4a", + "col224": "f8fu8", + "col225": "sookr", + "col226": "n5ufd", + "col227": "1u87q", + "col228": "bzqj0", + "col229": "u5evj", + "col230": "dpo2b", + "col231": "4go2m", + "col232": "i5qiy", + "col233": "r59m1", + "col234": "628a8", + "col235": "r3gdv", + "col236": "7p2l3", + "col237": "6lvu9", + "col238": "20e3s", + "col239": "enlga", + "col240": "t5w9f", + "col241": "pbvrq", + "col242": "82ayz", + "col243": "6viaf", + "col244": "pfmpz", + "col245": "djvs3", + "col246": "93dkz", + "col247": "n76h6", + "col248": "2grfm", + "col249": "jhcwp", + "col250": "l75e6", + "col251": "hjrl3", + "col252": "7ydi4", + "col253": "n7koj", + "col254": "cv4yj", + "col255": "2tdgv", + "col256": "53i3w", + "col257": "37b8l", + "col258": "vvl7k", + "col259": "k8wdc", + "col260": "ns3l8", + "col261": "0ed29", + "col262": "jgnf8", + "col263": "qsk90", + "col264": "2pacr", + "col265": "u3bdk", + "col266": "16406", + "col267": "sxbrz", + "col268": "q8txu", + "col269": "j7j6o", + "col270": "jnorx", + "col271": "5g1nn", + "col272": "865lt", + "col273": "i1tw3", + "col274": "86f5m", + "col275": "81zue", + "col276": "3x8sj", + "col277": "sman1", + "col278": "xlpoo", + "col279": "21x7t", + "col280": "t1mcx", + "col281": "14unp", + "col282": "sc3gl", + "col283": "jttqx", + "col284": "b47q3", + "col285": "u1lb7", + "col286": "a5ww9", + "col287": "31kho", + "col288": "tz0iw", + "col289": "llnbm", + "col290": "s6vyw", + "col291": "g4zrp", + "col292": "gq58o", + "col293": "d42u3", + "col294": "m3t1b", + "col295": "h1iy7", + "col296": "xyj0c", + "col297": "x9jmh", + "col298": "yxh06", + "col299": "6995e", + "col300": "dktso", + "col301": "a0xob", + "col302": "qlsbk", + "col303": "5miwm", + "col304": "0hwom", + "col305": "m1nm0", + "col306": "m06ed", + "col307": "b447a", + "col308": "ggm2q", + "col309": "537wr", + "col310": "qejow", + "col311": "f0gkg", + "col312": "kzngi", + "col313": "9lh7l", + "col314": "jozwz", + "col315": "eqp0r", + "col316": "dgjxk", + "col317": "z8n0b", + "col318": "miq49", + "col319": "85iwv", + "col320": "768lh", + "col321": "8xe3z", + "col322": "sxotj", + "col323": "y3sw9", + "col324": "u1w9p", + "col325": "n4zga", + "col326": "iixm7", + "col327": "ny1je", + "col328": "t3rdo", + "col329": "0edvz", + "col330": "pysag", + "col331": "o4hx8", + "col332": "t3j4j", + "col333": "1exsb", + "col334": "cz0qb", + "col335": "k4b19", + "col336": "qe7rt", + "col337": "v2lul", + "col338": "zi81k", + "col339": "pnp05", + "col340": "0cow3", + "col341": "s9xbz", + "col342": "vgv6m", + "col343": "21rfq", + "col344": "wp17w", + "col345": "vvxaq", + "col346": "eyiog", + "col347": "5t3c7", + "col348": "4c5qm", + "col349": "vdaqe", + "col350": "l7wu5", + "col351": "dtmdr", + "col352": "yitwt", + "col353": "whup7", + "col354": "juqp6", + "col355": "v3onn", + "col356": "78rz9", + "col357": "6nn6d", + "col358": "v8jsi", + "col359": "x8374", + "col360": "madvp", + "col361": "jp84q", + "col362": "anl1h", + "col363": "3xu4f", + "col364": "j0ste", + "col365": "fm650", + "col366": "tau41", + "col367": "xg2r2", + "col368": "y22e4", + "col369": "ojjig", + "col370": "mycwc", + "col371": "oyjd3", + "col372": "ywx8u", + "col373": "pxxtb", + "col374": "5nnij", + "col375": "e0wng", + "col376": "vyulj", + "col377": "och3y", + "col378": "gce9s", + "col379": "y4ti2", + "col380": "2m0gd", + "col381": "fzzzi", + "col382": "xldnk", + "col383": "zhyk7", + "col384": "1d2fv", + "col385": "c8h76", + "col386": "smgup", + "col387": "37bl7", + "col388": "ch3l1", + "col389": "nlfax", + "col390": "5fh4d", + "col391": "dpbcz", + "col392": "1wrf4", + "col393": "aq1t7", + "col394": "73ptn", + "col395": "scosz", + "col396": "jkbju", + "col397": "w3mr7", + "col398": "tl7tp", + "col399": "ftaxs", + "col400": "cb8ej", + "col401": "xxci5", + "col402": "36g5h", + "col403": "mqbq2", + "col404": "u5avs", + "col405": "uzp9e", + "col406": "bx5n4", + "col407": "ebrm1", + "col408": "vdbgc", + "col409": "8y4fa", + "col410": "6200q", + "col411": "r4v7m", + "col412": "aelpo", + "col413": "ddyds", + "col414": "wnwqv", + "col415": "5esvh", + "col416": "jw8l4", + "col417": "mvv06", + "col418": "ttnlp", + "col419": "4f2ay", + "col420": "gnptj", + "col421": "p6bse", + "col422": "ziwi9", + "col423": "ctoah", + "col424": "4elsd", + "col425": "9lkbb", + "col426": "gpmo8", + "col427": "prh2d", + "col428": "bu1un", + "col429": "0vpg9", + "col430": "k3mtu", + "col431": "38ezu", + "col432": "68uox", + "col433": "p093a", + "col434": "w0522", + "col435": "5w5qx", + "col436": "rtyae", + "col437": "z4orv", + "col438": "lkyt8", + "col439": "d7us6", + "col440": "ckqoa", + "col441": "1be1b", + "col442": "gn4xo", + "col443": "7swq1", + "col444": "h1b6u", + "col445": "f0dxo", + "col446": "6p6aa", + "col447": "vv922", + "col448": "ai8al", + "col449": "t0ikd", + "col450": "1gjn5", + "col451": "sza6g", + "col452": "olmwj", + "col453": "30t4q", + "col454": "fy1o5", + "col455": "rwko2", + "col456": "7g9v5", + "col457": "u1bby", + "col458": "z77at", + "col459": "9di68", + "col460": "xxl3h", + "col461": "9sjx0", + "col462": "k5uly", + "col463": "yvq5s", + "col464": "e9rt0", + "col465": "ofsqw", + "col466": "sbj8c", + "col467": "ureg4", + "col468": "u6j4z", + "col469": "sicnw", + "col470": "98obv", + "col471": "7fa2f", + "col472": "g1jt1", + "col473": "zwty9", + "col474": "2cqym", + "col475": "ou0po", + "col476": "g40wk", + "col477": "pfon7", + "col478": "q5zdp", + "col479": "fbmsl", + "col480": "478dm", + "col481": "somqj", + "col482": "xi39o", + "col483": "omriu", + "col484": "0fg59", + "col485": "e7die", + "col486": "fvnpv", + "col487": "ojk2c", + "col488": "acy30", + "col489": "5wd41", + "col490": "e6ad0", + "col491": "nroa7", + "col492": "4s86c", + "col493": "wisbz", + "col494": "ctm5b", + "col495": "62ugp", + "col496": "2qngr", + "col497": "yk09b", + "col498": "tpcby", + "col499": "xwblk", + "col500": "nk5cj", + "col501": "ehdnm", + "col502": "hutc4", + "col503": "tluwj", + "col504": "gkq00", + "col505": "v0s9u", + "col506": "z9ipy", + "col507": "sogdx", + "col508": "dscdg", + "col509": "4jtio", + "col510": "lrrba", + "col511": "y9nl1", + "col512": "srnrh", + "col513": "m49a2", + "col514": "5aj2j", + "col515": "vemmd", + "col516": "uy9oj", + "col517": "h38fx", + "col518": "i3iwh", + "col519": "jxwh5", + "col520": "j029g", + "col521": "m3m6a", + "col522": "b92eg", + "col523": "8etix", + "col524": "kscjq", + "col525": "wswx2", + "col526": "l42vs", + "col527": "uzsj7", + "col528": "djwf8", + "col529": "pp9uu", + "col530": "g5fg3", + "col531": "8ba7h", + "col532": "acru6", + "col533": "fno35", + "col534": "do3ol", + "col535": "zg3ba", + "col536": "o9nkb", + "col537": "tggeu", + "col538": "glb7v", + "col539": "339ks", + "col540": "iggt0", + "col541": "imno7", + "col542": "mnvtw", + "col543": "6987e", + "col544": "hoqo5", + "col545": "gnn1o", + "col546": "bb66k", + "col547": "qvyw9", + "col548": "etw18", + "col549": "y42zs", + "col550": "rnx0e", + "col551": "5igas", + "col552": "xkxvs", + "col553": "a6h5z", + "col554": "9mrx7", + "col555": "l4mbh", + "col556": "2j2iv", + "col557": "v9sij", + "col558": "0isgw", + "col559": "5d54m", + "col560": "8beua", + "col561": "84cd5", + "col562": "fgodg", + "col563": "npqwr", + "col564": "sl1n7", + "col565": "w5xns", + "col566": "vx9ks", + "col567": "9zsps", + "col568": "7ywc6", + "col569": "1m0mu", + "col570": "fmbmx", + "col571": "f6i6x", + "col572": "qzvvn", + "col573": "cgjar", + "col574": "yny7l", + "col575": "3vbgq", + "col576": "ydxly", + "col577": "yf4kw", + "col578": "n5e64", + "col579": "r2y88", + "col580": "5zq4o", + "col581": "n788j", + "col582": "gnpc7", + "col583": "hv79m", + "col584": "pvf01", + "col585": "4k14f", + "col586": "zy9a3", + "col587": "eer8c", + "col588": "iay1o", + "col589": "bpo7c", + "col590": "2fv7y", + "col591": "4zb6k", + "col592": "f1cws", + "col593": "g9zil", + "col594": "a038l", + "col595": "2n57p", + "col596": "hyrad", + "col597": "7st76", + "col598": "e4e4y", + "col599": "e8xjy", + "col600": "ko70l", + "col601": "8mxi6", + "col602": "zpz6t", + "col603": "j9d90", + "col604": "n6icy", + "col605": "yxbz4", + "col606": "p983j", + "col607": "rltg2", + "col608": "gjice", + "col609": "1p0v4", + "col610": "39fe0", + "col611": "919kr", + "col612": "w6s5n", + "col613": "55db4", + "col614": "bejh6", + "col615": "h4ynw", + "col616": "lx9vz", + "col617": "f87ve", + "col618": "mz28x", + "col619": "q87mi", + "col620": "hu312", + "col621": "lhjgz", + "col622": "rhgr4", + "col623": "93dkb", + "col624": "70dqo", + "col625": "dhskd", + "col626": "926qh", + "col627": "srw7x", + "col628": "1kuf6", + "col629": "a7t4q", + "col630": "9b3za", + "col631": "ve2w5", + "col632": "fkc3n", + "col633": "f65dp", + "col634": "vblcn", + "col635": "p023r", + "col636": "5lmk8", + "col637": "1arp4", + "col638": "k0252", + "col639": "z2yju", + "col640": "l10ua", + "col641": "dr55n", + "col642": "9nchd", + "col643": "z96dz", + "col644": "1yr3r", + "col645": "chyn3", + "col646": "xrw5r", + "col647": "7cei8", + "col648": "uvlnz", + "col649": "d9d4q", + "col650": "bzqkz", + "col651": "pszto", + "col652": "jvzza", + "col653": "snz22", + "col654": "epk5k", + "col655": "79ldf", + "col656": "bqpqg", + "col657": "3wmn8", + "col658": "8zmjw", + "col659": "ruf6o", + "col660": "yxq25", + "col661": "m7smf", + "col662": "op3g4", + "col663": "ophg0", + "col664": "54ua6", + "col665": "684bc", + "col666": "gnhpj", + "col667": "kr84r", + "col668": "i0f0g", + "col669": "bhhgi", + "col670": "pa0gy", + "col671": "j1rsv", + "col672": "ucq53", + "col673": "5ov1v", + "col674": "ny5fg", + "col675": "qasun", + "col676": "yj53d", + "col677": "bk2xc", + "col678": "by5ie", + "col679": "bt5uf", + "col680": "kv343", + "col681": "ey46f", + "col682": "pierx", + "col683": "rzc13", + "col684": "ttnyt", + "col685": "fvkzu", + "col686": "jq8j3", + "col687": "obehr", + "col688": "2i26a", + "col689": "z597h", + "col690": "p502a", + "col691": "13luj", + "col692": "rtg15", + "col693": "otdte", + "col694": "tduy9", + "col695": "0bkd9", + "col696": "d3b2s", + "col697": "r2wk7", + "col698": "vnp4x", + "col699": "7ub39", + "col700": "erify", + "col701": "havky", + "col702": "f6eff", + "col703": "arotj", + "col704": "8ecmo", + "col705": "y99e8", + "col706": "btaxt", + "col707": "ud5zr", + "col708": "jemkc", + "col709": "qu3ag", + "col710": "ekgcw", + "col711": "bju6v", + "col712": "2bsj8", + "col713": "mo1pn", + "col714": "z3ua4", + "col715": "kisgu", + "col716": "q3f7k", + "col717": "rn5gw", + "col718": "l83q3", + "col719": "7o5ef", + "col720": "w6jub", + "col721": "ar0vm", + "col722": "ig1f7", + "col723": "8eo22", + "col724": "6ynuw", + "col725": "o3qfn", + "col726": "arhx9", + "col727": "02rs7", + "col728": "rq6y1", + "col729": "lt2mm", + "col730": "wmqdy", + "col731": "rj94l", + "col732": "c7o6x", + "col733": "7twl7", + "col734": "dom8u", + "col735": "r6qi7", + "col736": "cjlve", + "col737": "ozkgu", + "col738": "0jxp4", + "col739": "1edfy", + "col740": "3ka4p", + "col741": "u27q8", + "col742": "08syk", + "col743": "4ha3s", + "col744": "o5ni3", + "col745": "e8fby", + "col746": "ehp6o", + "col747": "yd7yf", + "col748": "hl9iy", + "col749": "dgzo0", + "col750": "zud1b", + "col751": "gystr", + "col752": "pm1s5", + "col753": "3h1cl", + "col754": "upkk5", + "col755": "zscxw", + "col756": "3f9xf", + "col757": "clczx", + "col758": "6p24m", + "col759": "bzj07", + "col760": "gjjft", + "col761": "2cy2f", + "col762": "wr4uo", + "col763": "01f62", + "col764": "cpow3", + "col765": "2zc53", + "col766": "ibdiw", + "col767": "ne3ns", + "col768": "3mrr2", + "col769": "rirnw", + "col770": "hqf2g", + "col771": "9a0mp", + "col772": "qfo5q", + "col773": "pqpdx", + "col774": "ll39c", + "col775": "lery0", + "col776": "r9ay0", + "col777": "61284", + "col778": "obhxf", + "col779": "hw0fq", + "col780": "51kjs", + "col781": "6mc0t", + "col782": "nny61", + "col783": "cox09", + "col784": "o4x1q", + "col785": "rpsmi", + "col786": "noryg", + "col787": "6ii30", + "col788": "9mtyt", + "col789": "6ovcn", + "col790": "isan2", + "col791": "xlrm7", + "col792": "5yz0a", + "col793": "dmlac", + "col794": "t9dt7", + "col795": "98iy3", + "col796": "zc0ys", + "col797": "mbxbn", + "col798": "jmd4j", + "col799": "rtv0x", + "col800": "jr1st", + "col801": "m91aq", + "col802": "usoz8", + "col803": "9hdcf", + "col804": "hkrm4", + "col805": "02a8p", + "col806": "d4aby", + "col807": "eur38", + "col808": "bgja4", + "col809": "pn9jk", + "col810": "otjxw", + "col811": "8lw3g", + "col812": "80ibs", + "col813": "9q8p0", + "col814": "83gdm", + "col815": "jm4sl", + "col816": "rc14c", + "col817": "mq4dp", + "col818": "qxt7n", + "col819": "23lge", + "col820": "lem7e", + "col821": "b0ihz", + "col822": "mxj8p", + "col823": "t3hph", + "col824": "ehuvz", + "col825": "ic9df", + "col826": "udg0l", + "col827": "7psj6", + "col828": "dw6lp", + "col829": "3nhvr", + "col830": "09mti", + "col831": "bsjmb", + "col832": "c05q1", + "col833": "7n30b", + "col834": "u32ga", + "col835": "v43ni", + "col836": "5r6yp", + "col837": "s4pn3", + "col838": "xm7ng", + "col839": "vu904", + "col840": "52kzl", + "col841": "pyi5h", + "col842": "7ygya", + "col843": "jo31s", + "col844": "aih6j", + "col845": "r5pnc", + "col846": "8rd42", + "col847": "fge39", + "col848": "nzlup", + "col849": "ft58v", + "col850": "kvtx1", + "col851": "gjt8e", + "col852": "6dxlc", + "col853": "wbll7", + "col854": "339bl", + "col855": "59zgq", + "col856": "4kmt2", + "col857": "8zbz9", + "col858": "yvs7p", + "col859": "mtykm", + "col860": "yuz1f", + "col861": "ylq1l", + "col862": "fb9t9", + "col863": "ycik2", + "col864": "rddqy", + "col865": "mvuy6", + "col866": "lvc3l", + "col867": "co25f", + "col868": "bgy33", + "col869": "jtrur", + "col870": "3wk8s", + "col871": "h4pwx", + "col872": "1hu9t", + "col873": "45hqb", + "col874": "aj67r", + "col875": "bn41p", + "col876": "bgcjc", + "col877": "rcrc0", + "col878": "pyfn7", + "col879": "pxzb8", + "col880": "2ahix", + "col881": "trfky", + "col882": "gf5a1", + "col883": "ni1x7", + "col884": "9oykh", + "col885": "kifxm", + "col886": "2enbr", + "col887": "enz16", + "col888": "3zlkd", + "col889": "iieu2", + "col890": "pjuc2", + "col891": "88dy1", + "col892": "pzjca", + "col893": "tb2dv", + "col894": "csfss", + "col895": "mg8e6", + "col896": "un2xp", + "col897": "67xni", + "col898": "afxyl", + "col899": "dn9si", + "col900": "oc4ic", + "col901": "fkram", + "col902": "fits9", + "col903": "gg3sx", + "col904": "88u8s", + "col905": "prmkv", + "col906": "f9j1m", + "col907": "p46zx", + "col908": "xkspc", + "col909": "jw2kb", + "col910": "jxetd", + "col911": "24j6e", + "col912": "aoa4c", + "col913": "3rtvu", + "col914": "u3621", + "col915": "5ppnm", + "col916": "kzf1x", + "col917": "4l9ym", + "col918": "8x9fa", + "col919": "6hzfd", + "col920": "7fzdb", + "col921": "1kt98", + "col922": "rq16g", + "col923": "bex10", + "col924": "aoxg6", + "col925": "06upx", + "col926": "hi3z7", + "col927": "cwcir", + "col928": "tzrwo", + "col929": "79qus", + "col930": "1px2a", + "col931": "kdcxo", + "col932": "7hj14", + "col933": "rd62o", + "col934": "ujnob", + "col935": "o63t3", + "col936": "kfykc", + "col937": "wohm8", + "col938": "ki9ed", + "col939": "1dt8h", + "col940": "ogtyt", + "col941": "gq1qi", + "col942": "r7jhu", + "col943": "2z3hi", + "col944": "zv8ao", + "col945": "sptn7", + "col946": "rkmos", + "col947": "umjdj", + "col948": "r53js", + "col949": "enhgs", + "col950": "gyoah", + "col951": "lfs6a", + "col952": "afoc9", + "col953": "iuoen", + "col954": "6ru4c", + "col955": "xfqse", + "col956": "g6y7i", + "col957": "7amig", + "col958": "f22bo", + "col959": "y7ale", + "col960": "mx987", + "col961": "gg5vo", + "col962": "w0xt6", + "col963": "90gqc", + "col964": "g9ob7", + "col965": "mp8al", + "col966": "j7t68", + "col967": "sm1ct", + "col968": "xt6xm", + "col969": "xuoos", + "col970": "jku0l", + "col971": "1lery", + "col972": "88hff", + "col973": "xhu72", + "col974": "y2yav", + "col975": "nb2xy", + "col976": "pacls", + "col977": "5gg1g", + "col978": "jl3ot", + "col979": "xqdut", + "col980": "chxgw", + "col981": "rkpol", + "col982": "qvjiv", + "col983": "ym1kr", + "col984": "lajds", + "col985": "4bkw0", + "col986": "wlfib", + "col987": "i7nq7", + "col988": "91ghg", + "col989": "2rrwt", + "col990": "6fly2", + "col991": "eayhv", + "col992": "ltmzx", + "col993": "8iyss", + "col994": "xlt0l", + "col995": "340kx", + "col996": "ok1m1", + "col997": "frye2", + "col998": "ow88r", + "col999": "pk9vj" + }, + { + "name": "Jennings Hinton", + "gender": "male", + "col0": "mdcdm", + "col1": "ynz1k", + "col2": "go5cj", + "col3": "7ggtk", + "col4": "ja5a7", + "col5": "ptok7", + "col6": "5pn20", + "col7": "pojf9", + "col8": "u6944", + "col9": "ypsj9", + "col10": "w9uar", + "col11": "hmyw5", + "col12": "x2ho5", + "col13": "8fbjq", + "col14": "qofk0", + "col15": "4t6lr", + "col16": "ylett", + "col17": "aeor3", + "col18": "uivp4", + "col19": "gfzze", + "col20": "nc22i", + "col21": "y6dbt", + "col22": "8wvq1", + "col23": "417jf", + "col24": "hvq17", + "col25": "wyzx7", + "col26": "tbep0", + "col27": "zhoyp", + "col28": "l7i8i", + "col29": "ealgt", + "col30": "6ty22", + "col31": "v7qt9", + "col32": "ecn2v", + "col33": "mybfr", + "col34": "kh6dh", + "col35": "hkw9c", + "col36": "6er53", + "col37": "dslxf", + "col38": "cfoyk", + "col39": "bag3s", + "col40": "gtrde", + "col41": "skt7u", + "col42": "a9hz7", + "col43": "ogy8w", + "col44": "zwaex", + "col45": "go2gn", + "col46": "ymogg", + "col47": "s759s", + "col48": "8rsw6", + "col49": "plcmk", + "col50": "yypvp", + "col51": "b2pkd", + "col52": "ow4wu", + "col53": "00ze4", + "col54": "vnjtj", + "col55": "71wjk", + "col56": "87pfz", + "col57": "ohqn0", + "col58": "4tzki", + "col59": "3hors", + "col60": "h3off", + "col61": "gwt2q", + "col62": "9kage", + "col63": "saozf", + "col64": "115uy", + "col65": "kkrss", + "col66": "2blrt", + "col67": "oetry", + "col68": "ymvc7", + "col69": "smesh", + "col70": "q8okh", + "col71": "pvo6i", + "col72": "fysm7", + "col73": "2586u", + "col74": "vv9ig", + "col75": "j9utw", + "col76": "v337t", + "col77": "zu8e1", + "col78": "w0fyt", + "col79": "agkx8", + "col80": "bdqs2", + "col81": "i4oq4", + "col82": "ehu3v", + "col83": "2qhpi", + "col84": "nkywt", + "col85": "7x8kq", + "col86": "65saw", + "col87": "01izz", + "col88": "62kua", + "col89": "7o2qo", + "col90": "cweh1", + "col91": "sw54v", + "col92": "ktm22", + "col93": "zfnhg", + "col94": "lfmqs", + "col95": "5n5tb", + "col96": "8t1x4", + "col97": "q9f6v", + "col98": "5sbge", + "col99": "mxb5y", + "col100": "p81re", + "col101": "fkgbe", + "col102": "u5eox", + "col103": "25u8r", + "col104": "h3ozn", + "col105": "o2gyb", + "col106": "asa4b", + "col107": "lhz8r", + "col108": "kb41l", + "col109": "i76wq", + "col110": "o8mpv", + "col111": "gq6xt", + "col112": "pertr", + "col113": "mkes5", + "col114": "um4jp", + "col115": "xgqun", + "col116": "y4xrs", + "col117": "qlbep", + "col118": "a11n6", + "col119": "0w5ag", + "col120": "5zpl2", + "col121": "7i2n4", + "col122": "qg4r0", + "col123": "lofz3", + "col124": "a1ojw", + "col125": "z8kpp", + "col126": "405fb", + "col127": "n6sio", + "col128": "18jyn", + "col129": "lpikx", + "col130": "fyfpr", + "col131": "ueye3", + "col132": "d1ncd", + "col133": "2qrj2", + "col134": "25177", + "col135": "me045", + "col136": "ogyve", + "col137": "at15v", + "col138": "ekkqd", + "col139": "xtfdu", + "col140": "esaec", + "col141": "zxsch", + "col142": "8a7lq", + "col143": "tri74", + "col144": "76od7", + "col145": "6d4oa", + "col146": "nc5ol", + "col147": "eknla", + "col148": "fhy8s", + "col149": "1hok1", + "col150": "cym0m", + "col151": "gyeee", + "col152": "1uuc3", + "col153": "ne5gf", + "col154": "e3num", + "col155": "i3vn1", + "col156": "malg4", + "col157": "cvpz5", + "col158": "ao6od", + "col159": "7n151", + "col160": "op2cf", + "col161": "5l5ns", + "col162": "cb6aw", + "col163": "bv83l", + "col164": "xfcpt", + "col165": "hsvxq", + "col166": "x8fpo", + "col167": "icpmr", + "col168": "rvnzd", + "col169": "f9c1h", + "col170": "frh5d", + "col171": "8b0od", + "col172": "8p7fc", + "col173": "08uh8", + "col174": "2oa6o", + "col175": "ix5m5", + "col176": "f8o4b", + "col177": "yhrf4", + "col178": "cf8y5", + "col179": "h91y0", + "col180": "jj4vg", + "col181": "cs9mz", + "col182": "cak9x", + "col183": "vq4i1", + "col184": "4b7q5", + "col185": "3uf1n", + "col186": "3pxz1", + "col187": "j03hu", + "col188": "qqw7z", + "col189": "vt1we", + "col190": "cw94t", + "col191": "8vys2", + "col192": "zckm7", + "col193": "xq0g0", + "col194": "9jyoc", + "col195": "tspmr", + "col196": "achuw", + "col197": "f2z53", + "col198": "nrn1n", + "col199": "00n52", + "col200": "ytbbl", + "col201": "pmjsj", + "col202": "2de4q", + "col203": "t7ju2", + "col204": "oird3", + "col205": "xnvob", + "col206": "hivne", + "col207": "mpunl", + "col208": "6qe8r", + "col209": "kwckq", + "col210": "uj1k9", + "col211": "7lfzb", + "col212": "e785m", + "col213": "72evc", + "col214": "ywtjq", + "col215": "z8kzg", + "col216": "tdcj3", + "col217": "mpv7e", + "col218": "1n2um", + "col219": "477ma", + "col220": "4sj57", + "col221": "a6ek8", + "col222": "cidsp", + "col223": "tziht", + "col224": "n6jym", + "col225": "b33hx", + "col226": "qfnpo", + "col227": "fcb8g", + "col228": "6i0uq", + "col229": "tb4mu", + "col230": "e0me8", + "col231": "618wr", + "col232": "d06td", + "col233": "e6df8", + "col234": "ghh5t", + "col235": "lhj1r", + "col236": "olik7", + "col237": "hq393", + "col238": "jgp9o", + "col239": "kpwjt", + "col240": "hq33j", + "col241": "aureg", + "col242": "lyras", + "col243": "fbgn5", + "col244": "29923", + "col245": "ywbvk", + "col246": "qk3ku", + "col247": "kulix", + "col248": "6pc8i", + "col249": "8b0t2", + "col250": "v9o4g", + "col251": "ixb9k", + "col252": "y0ukh", + "col253": "k73js", + "col254": "iha38", + "col255": "kiabb", + "col256": "k0d5f", + "col257": "9cz9z", + "col258": "x9j22", + "col259": "i15ku", + "col260": "7xirt", + "col261": "iphbm", + "col262": "hmdli", + "col263": "5922f", + "col264": "uthff", + "col265": "nnxec", + "col266": "pbqnh", + "col267": "as06x", + "col268": "rtwp6", + "col269": "ny1ti", + "col270": "frwup", + "col271": "d1oue", + "col272": "iqilk", + "col273": "djx3m", + "col274": "1c9lr", + "col275": "qklkr", + "col276": "zj1dt", + "col277": "liirz", + "col278": "57g81", + "col279": "0tddu", + "col280": "ea58r", + "col281": "77zk5", + "col282": "e0wpq", + "col283": "3xiic", + "col284": "0ulr7", + "col285": "ta3mo", + "col286": "kg3dd", + "col287": "zqtbc", + "col288": "oohif", + "col289": "kd9rw", + "col290": "x6xcs", + "col291": "31bev", + "col292": "1cvro", + "col293": "dbep4", + "col294": "xsiq5", + "col295": "uqplt", + "col296": "hswbj", + "col297": "rgv44", + "col298": "zye8y", + "col299": "90uo7", + "col300": "ul6ud", + "col301": "4z545", + "col302": "uicdz", + "col303": "8gl16", + "col304": "6ylq8", + "col305": "rhum3", + "col306": "zu2k9", + "col307": "p7udk", + "col308": "oa4d2", + "col309": "ahn8f", + "col310": "str90", + "col311": "70cld", + "col312": "3xv0i", + "col313": "n0vb7", + "col314": "qgwyc", + "col315": "dy3g0", + "col316": "0hwlj", + "col317": "0wwl4", + "col318": "m9866", + "col319": "zhlgz", + "col320": "xiv1o", + "col321": "tizza", + "col322": "0gq37", + "col323": "hi971", + "col324": "0bx15", + "col325": "uj8rz", + "col326": "bszlw", + "col327": "06e1o", + "col328": "gd14b", + "col329": "661xv", + "col330": "urt5l", + "col331": "68xr4", + "col332": "gre53", + "col333": "d5t37", + "col334": "5fes2", + "col335": "5rx1n", + "col336": "dxi5f", + "col337": "pzsgl", + "col338": "cd5sl", + "col339": "uw150", + "col340": "lzv0c", + "col341": "70jla", + "col342": "wx7x0", + "col343": "mwccu", + "col344": "tvzsi", + "col345": "qtsvh", + "col346": "v008k", + "col347": "wm77l", + "col348": "xo12b", + "col349": "fjcdd", + "col350": "ae63f", + "col351": "acdsi", + "col352": "xzsf6", + "col353": "5qeex", + "col354": "iermv", + "col355": "f3vqr", + "col356": "r9ybd", + "col357": "ljvpy", + "col358": "e0hrf", + "col359": "y2vn4", + "col360": "yo2la", + "col361": "t3rq8", + "col362": "3e0wj", + "col363": "fg9ys", + "col364": "1n6h8", + "col365": "vf1mf", + "col366": "w93ng", + "col367": "7u1f1", + "col368": "2h6zw", + "col369": "k0wkd", + "col370": "ri2zd", + "col371": "5w3u8", + "col372": "wgpcx", + "col373": "0o1fo", + "col374": "ta1hz", + "col375": "ke7qn", + "col376": "ca53f", + "col377": "y1d5b", + "col378": "wcciq", + "col379": "4mlri", + "col380": "kotes", + "col381": "llcw0", + "col382": "3zdw8", + "col383": "nwyuf", + "col384": "ujkdm", + "col385": "lkg8v", + "col386": "7z8cx", + "col387": "beir3", + "col388": "aebb8", + "col389": "sedzq", + "col390": "oqna9", + "col391": "6golk", + "col392": "zvlvl", + "col393": "zdv2t", + "col394": "3t29h", + "col395": "bbbvb", + "col396": "vltz3", + "col397": "6t5hr", + "col398": "c3mxd", + "col399": "0hcr6", + "col400": "meg17", + "col401": "qbtrt", + "col402": "xmhgn", + "col403": "wvtyp", + "col404": "p3h19", + "col405": "tluw0", + "col406": "l3qck", + "col407": "3gn4n", + "col408": "h3i4l", + "col409": "gzxor", + "col410": "e0rul", + "col411": "ifk74", + "col412": "fe9eg", + "col413": "k3xsb", + "col414": "6bffl", + "col415": "molr3", + "col416": "bpho8", + "col417": "cxc7p", + "col418": "ac5pc", + "col419": "zntp6", + "col420": "fo0kl", + "col421": "6cj94", + "col422": "igh1b", + "col423": "8mq5g", + "col424": "e996l", + "col425": "d5s6r", + "col426": "vk6ya", + "col427": "raj70", + "col428": "ibqd4", + "col429": "uujfs", + "col430": "tceq6", + "col431": "2o21l", + "col432": "c2liq", + "col433": "prkr1", + "col434": "m7whz", + "col435": "5chcr", + "col436": "ootik", + "col437": "f2x72", + "col438": "smupk", + "col439": "c7akw", + "col440": "zxi4o", + "col441": "xmb66", + "col442": "w9z6r", + "col443": "n4grw", + "col444": "hp12b", + "col445": "jj0tb", + "col446": "jnwur", + "col447": "xwqzv", + "col448": "4n6rl", + "col449": "8akqc", + "col450": "ftth8", + "col451": "ueryq", + "col452": "s5u5z", + "col453": "6ix7x", + "col454": "91rwm", + "col455": "sntt1", + "col456": "5w6pq", + "col457": "fzt0d", + "col458": "yltf4", + "col459": "t9d0f", + "col460": "si2hz", + "col461": "wj6i2", + "col462": "46ss7", + "col463": "2ouc3", + "col464": "fl1pb", + "col465": "60jyo", + "col466": "omslk", + "col467": "cu8kq", + "col468": "yko6m", + "col469": "gb5k4", + "col470": "qnh1w", + "col471": "94ife", + "col472": "7xx7y", + "col473": "5zucv", + "col474": "soa0x", + "col475": "ty4h4", + "col476": "7etq1", + "col477": "zf80g", + "col478": "rx87z", + "col479": "ni2w2", + "col480": "mxqss", + "col481": "whf8k", + "col482": "mp9rl", + "col483": "2sjkw", + "col484": "kroyi", + "col485": "qi5na", + "col486": "2pl23", + "col487": "83sdr", + "col488": "8aqtl", + "col489": "50pjh", + "col490": "ed4xn", + "col491": "729iv", + "col492": "42ksv", + "col493": "ngc8c", + "col494": "9irm4", + "col495": "qmz2g", + "col496": "o7rgy", + "col497": "jgjt8", + "col498": "vsjy2", + "col499": "bx8bm", + "col500": "g6w1n", + "col501": "eplmz", + "col502": "mzvgc", + "col503": "e0w3j", + "col504": "gq4vw", + "col505": "2hh46", + "col506": "giudm", + "col507": "ycs2d", + "col508": "gpezi", + "col509": "ebr03", + "col510": "lsor5", + "col511": "4rhn3", + "col512": "plkam", + "col513": "65bt2", + "col514": "ikpwg", + "col515": "45vk0", + "col516": "dgqeo", + "col517": "73kzk", + "col518": "mgeht", + "col519": "3v51t", + "col520": "xl5ep", + "col521": "23hdp", + "col522": "mhi15", + "col523": "r36b0", + "col524": "t5x5e", + "col525": "xtc5o", + "col526": "ys1jj", + "col527": "zmce3", + "col528": "t18of", + "col529": "7b2qc", + "col530": "ig2o1", + "col531": "lmv1m", + "col532": "zb92o", + "col533": "1ugmz", + "col534": "zd1d1", + "col535": "i5hlg", + "col536": "0q4ij", + "col537": "wqdyg", + "col538": "y87n0", + "col539": "bjn86", + "col540": "4izn1", + "col541": "1gb3i", + "col542": "r9kzz", + "col543": "r3r7d", + "col544": "f5lqz", + "col545": "les0l", + "col546": "pgpg0", + "col547": "9lohj", + "col548": "t8qsu", + "col549": "yd2ko", + "col550": "tbt0x", + "col551": "32evv", + "col552": "zsxny", + "col553": "bcrc0", + "col554": "wbyya", + "col555": "55jvl", + "col556": "h8fs6", + "col557": "og9ki", + "col558": "vgtjx", + "col559": "lxduy", + "col560": "pvt6c", + "col561": "xyx2w", + "col562": "5fdtz", + "col563": "eydv0", + "col564": "cppxo", + "col565": "dsrud", + "col566": "u0tq9", + "col567": "x0b8i", + "col568": "iprt9", + "col569": "a8j7q", + "col570": "vd7l9", + "col571": "ymza6", + "col572": "b9clk", + "col573": "0wn86", + "col574": "59y6j", + "col575": "wfr91", + "col576": "cnhs1", + "col577": "3so2v", + "col578": "hpoee", + "col579": "ore7l", + "col580": "usuuw", + "col581": "yepky", + "col582": "wdmxn", + "col583": "lq5ww", + "col584": "tdfgz", + "col585": "76f14", + "col586": "zowmt", + "col587": "gthj7", + "col588": "cw3zh", + "col589": "3xqsl", + "col590": "gd3l0", + "col591": "1bs3m", + "col592": "p1d5g", + "col593": "gqof3", + "col594": "tlats", + "col595": "hbo4n", + "col596": "c9t98", + "col597": "41627", + "col598": "193m0", + "col599": "6wstz", + "col600": "m3fj1", + "col601": "oo95b", + "col602": "rk9w3", + "col603": "ugn6h", + "col604": "iwcm5", + "col605": "hhcme", + "col606": "hmik0", + "col607": "y5kk4", + "col608": "rs0n6", + "col609": "nsiad", + "col610": "d7qmh", + "col611": "bjwge", + "col612": "tjycb", + "col613": "ppo0m", + "col614": "2uu7y", + "col615": "6dduw", + "col616": "63xwv", + "col617": "n1u5m", + "col618": "mg34k", + "col619": "1quuh", + "col620": "7ffyd", + "col621": "m97fw", + "col622": "m8wno", + "col623": "tur1d", + "col624": "lbwxt", + "col625": "j4chl", + "col626": "oqewa", + "col627": "txlq6", + "col628": "jx2gj", + "col629": "qtyxw", + "col630": "lgqpt", + "col631": "eg529", + "col632": "1x1hj", + "col633": "ezjni", + "col634": "2v4re", + "col635": "mht0i", + "col636": "lbhri", + "col637": "c8n0x", + "col638": "biatz", + "col639": "zu3lw", + "col640": "ztgfb", + "col641": "bwjti", + "col642": "01765", + "col643": "1z6bi", + "col644": "iesxg", + "col645": "fpaku", + "col646": "3h5g3", + "col647": "ylu85", + "col648": "yxujh", + "col649": "cbs65", + "col650": "jrlcq", + "col651": "vxd41", + "col652": "t4d2k", + "col653": "na8u6", + "col654": "gr8le", + "col655": "c4c6p", + "col656": "fio1x", + "col657": "pm7c3", + "col658": "6cobs", + "col659": "r0upw", + "col660": "yvqxb", + "col661": "5a0qj", + "col662": "iggtk", + "col663": "j8lpl", + "col664": "4gqf9", + "col665": "8sks2", + "col666": "ilfz7", + "col667": "jo66q", + "col668": "u6dj9", + "col669": "8pu59", + "col670": "yj1y7", + "col671": "mkwwh", + "col672": "3mlnd", + "col673": "cc0yz", + "col674": "a2mj4", + "col675": "lcfjl", + "col676": "z4prf", + "col677": "ytu9d", + "col678": "kxw1k", + "col679": "tasgw", + "col680": "euv6j", + "col681": "a2zwi", + "col682": "ebxrj", + "col683": "aopp3", + "col684": "eiinm", + "col685": "kg9yc", + "col686": "o08di", + "col687": "rtld3", + "col688": "og301", + "col689": "q48eh", + "col690": "j6oh7", + "col691": "rj5jy", + "col692": "7owic", + "col693": "bucn3", + "col694": "7fcir", + "col695": "grof8", + "col696": "1mckw", + "col697": "iqztd", + "col698": "jcinr", + "col699": "h0qmg", + "col700": "romb3", + "col701": "n1oqe", + "col702": "7m4er", + "col703": "lv6js", + "col704": "7my06", + "col705": "63len", + "col706": "1s7vp", + "col707": "hctjh", + "col708": "euolg", + "col709": "3gz9p", + "col710": "g16fj", + "col711": "rgzw6", + "col712": "v7rom", + "col713": "hlgpw", + "col714": "2gkrd", + "col715": "vfg7x", + "col716": "yst0c", + "col717": "rwx4q", + "col718": "e97ss", + "col719": "tfxh1", + "col720": "2b6xn", + "col721": "w3bz0", + "col722": "kq1ql", + "col723": "ehp5x", + "col724": "sndsf", + "col725": "iiaaq", + "col726": "apk6u", + "col727": "ht463", + "col728": "98mbu", + "col729": "kd6j0", + "col730": "m862u", + "col731": "lb8nb", + "col732": "s6ndg", + "col733": "b4uae", + "col734": "b580x", + "col735": "4k5e6", + "col736": "mky0y", + "col737": "srchr", + "col738": "6ep83", + "col739": "7qp95", + "col740": "iifv3", + "col741": "355zi", + "col742": "kn95j", + "col743": "55cji", + "col744": "bk9ip", + "col745": "71ek5", + "col746": "3o3wk", + "col747": "dzuef", + "col748": "vw0vz", + "col749": "vgnre", + "col750": "5nthi", + "col751": "bbglv", + "col752": "udwi9", + "col753": "77jf0", + "col754": "r3o3f", + "col755": "cxt20", + "col756": "dkind", + "col757": "acee2", + "col758": "tuxu0", + "col759": "5dawe", + "col760": "bdtm6", + "col761": "dbyy5", + "col762": "ynr67", + "col763": "vt8di", + "col764": "4yws5", + "col765": "cih9b", + "col766": "clyzy", + "col767": "1f0s5", + "col768": "hjksy", + "col769": "hl9mh", + "col770": "lbs4r", + "col771": "exfub", + "col772": "0ty7e", + "col773": "mlesh", + "col774": "93glz", + "col775": "ouosa", + "col776": "z9ufb", + "col777": "nhhfz", + "col778": "uagyi", + "col779": "c4git", + "col780": "hjz67", + "col781": "0b9kv", + "col782": "t6v5x", + "col783": "vrd7n", + "col784": "5xx1i", + "col785": "56v5m", + "col786": "q042c", + "col787": "altp5", + "col788": "9u4lb", + "col789": "drkw0", + "col790": "bcwfh", + "col791": "1v7k3", + "col792": "u1clb", + "col793": "a6sym", + "col794": "za85f", + "col795": "lpr5k", + "col796": "lz6wj", + "col797": "fndce", + "col798": "xssh7", + "col799": "fddoy", + "col800": "flrl7", + "col801": "a1eel", + "col802": "gxwok", + "col803": "r6ys8", + "col804": "sew5r", + "col805": "hgko8", + "col806": "mavuw", + "col807": "rnsge", + "col808": "3ygaz", + "col809": "ochop", + "col810": "v484l", + "col811": "u0rez", + "col812": "hrf44", + "col813": "4haxj", + "col814": "t1hzb", + "col815": "ils0w", + "col816": "kz324", + "col817": "u396t", + "col818": "jogue", + "col819": "wf4xv", + "col820": "9fa80", + "col821": "5kc26", + "col822": "f3cmz", + "col823": "un1tu", + "col824": "96t38", + "col825": "1cisl", + "col826": "oe3hy", + "col827": "4j9h9", + "col828": "lmxwp", + "col829": "ficgp", + "col830": "j6zq6", + "col831": "05oab", + "col832": "ek29y", + "col833": "8gb0j", + "col834": "0yu00", + "col835": "8k7pl", + "col836": "756g0", + "col837": "c0wx3", + "col838": "jdn3y", + "col839": "dswim", + "col840": "v0fek", + "col841": "ad018", + "col842": "buphc", + "col843": "nwkw1", + "col844": "bzhdf", + "col845": "3rv5b", + "col846": "jjprn", + "col847": "h4xwc", + "col848": "3926h", + "col849": "2mi9c", + "col850": "m96ps", + "col851": "pxe3f", + "col852": "92ox4", + "col853": "2pjr2", + "col854": "5r68s", + "col855": "55mn8", + "col856": "izt0a", + "col857": "5iwi6", + "col858": "zzq0a", + "col859": "yyh9s", + "col860": "mgqjj", + "col861": "cb688", + "col862": "91npz", + "col863": "jgpmw", + "col864": "sc3qn", + "col865": "oxsnk", + "col866": "ch2qz", + "col867": "zjipt", + "col868": "6hhyt", + "col869": "2ib4y", + "col870": "38yyc", + "col871": "wwjs6", + "col872": "h44it", + "col873": "ox7xc", + "col874": "693l6", + "col875": "p2la7", + "col876": "uyhld", + "col877": "wskcj", + "col878": "d8fit", + "col879": "qbnka", + "col880": "cqad9", + "col881": "fws06", + "col882": "f9apm", + "col883": "9x16c", + "col884": "s0i2o", + "col885": "vnscf", + "col886": "h9rmv", + "col887": "b71za", + "col888": "w8r16", + "col889": "40yhx", + "col890": "qzoyf", + "col891": "gz2z8", + "col892": "zlg8v", + "col893": "eeun0", + "col894": "3x3my", + "col895": "b6p7s", + "col896": "1vov5", + "col897": "d09ui", + "col898": "4mg9v", + "col899": "1z8s9", + "col900": "itmbn", + "col901": "excl7", + "col902": "3idko", + "col903": "ns707", + "col904": "uv4u8", + "col905": "n1tex", + "col906": "jb9ht", + "col907": "qbgmd", + "col908": "8ms4p", + "col909": "316ag", + "col910": "r86zc", + "col911": "rcckc", + "col912": "hzwx9", + "col913": "atz4g", + "col914": "qknur", + "col915": "x5n6t", + "col916": "ke7bb", + "col917": "taajt", + "col918": "9vhie", + "col919": "wlban", + "col920": "dyvxk", + "col921": "q56k2", + "col922": "o6p60", + "col923": "9rdw1", + "col924": "0crm9", + "col925": "fg2sl", + "col926": "kytsb", + "col927": "wokct", + "col928": "8vnho", + "col929": "e82pg", + "col930": "olyb4", + "col931": "x2qkr", + "col932": "ru6u2", + "col933": "o6i0p", + "col934": "uelo3", + "col935": "kjpql", + "col936": "sjzxv", + "col937": "j7l5y", + "col938": "mt82t", + "col939": "qmgn6", + "col940": "81c48", + "col941": "rs9va", + "col942": "kkc41", + "col943": "k0cpa", + "col944": "3hoan", + "col945": "3rpfe", + "col946": "rb863", + "col947": "4ekgd", + "col948": "zg8mf", + "col949": "tzhwu", + "col950": "rxq7d", + "col951": "hju9a", + "col952": "mdsbe", + "col953": "r80p0", + "col954": "bw0qj", + "col955": "73abt", + "col956": "qcwjy", + "col957": "qdcn0", + "col958": "0kiv6", + "col959": "4vkxp", + "col960": "1y1jc", + "col961": "k8m39", + "col962": "lf0ep", + "col963": "ddddc", + "col964": "a20bv", + "col965": "xlk3e", + "col966": "b5rd1", + "col967": "dwyc4", + "col968": "5yvr3", + "col969": "ljuvl", + "col970": "82lg4", + "col971": "sb72e", + "col972": "hzp05", + "col973": "q93yg", + "col974": "4ahnk", + "col975": "3h03e", + "col976": "c7v9c", + "col977": "ilc8z", + "col978": "8y407", + "col979": "zzgnd", + "col980": "0vh6h", + "col981": "of5vy", + "col982": "md1v1", + "col983": "hqt10", + "col984": "2mnzd", + "col985": "l6m4k", + "col986": "1d39x", + "col987": "5qg5z", + "col988": "ayaci", + "col989": "mw3ce", + "col990": "dtid4", + "col991": "arg40", + "col992": "fn63e", + "col993": "3xovq", + "col994": "m5ep6", + "col995": "s070b", + "col996": "7kba4", + "col997": "pqvnq", + "col998": "w5jpi", + "col999": "fedvh" + }, + { + "name": "Mayo Webb", + "gender": "male", + "col0": "pkqjz", + "col1": "b4xnb", + "col2": "ph274", + "col3": "2e93f", + "col4": "iqxai", + "col5": "ae7f7", + "col6": "17bd7", + "col7": "sqxrp", + "col8": "85y6n", + "col9": "dql9z", + "col10": "ai08h", + "col11": "e0mgb", + "col12": "0sfh4", + "col13": "agi17", + "col14": "v5cbh", + "col15": "27zlu", + "col16": "wcs1o", + "col17": "knsmg", + "col18": "wb3ud", + "col19": "84n5b", + "col20": "np50n", + "col21": "lt0lv", + "col22": "qhmmu", + "col23": "9y14n", + "col24": "d3o47", + "col25": "1yz65", + "col26": "17guf", + "col27": "g9lqg", + "col28": "fi5ps", + "col29": "jfnf0", + "col30": "i2epo", + "col31": "1v2hr", + "col32": "7okhh", + "col33": "t3p5w", + "col34": "a5e6z", + "col35": "ytjlh", + "col36": "mgtl4", + "col37": "dww7g", + "col38": "2go8x", + "col39": "b3kzf", + "col40": "jlmo6", + "col41": "lp7pd", + "col42": "8mh3f", + "col43": "hri2a", + "col44": "cp9o2", + "col45": "28627", + "col46": "m3hp9", + "col47": "jznoa", + "col48": "ayhin", + "col49": "j8rfq", + "col50": "ao9dg", + "col51": "b207b", + "col52": "vtijq", + "col53": "9yz94", + "col54": "2fmp9", + "col55": "c4b7d", + "col56": "heu90", + "col57": "0yadg", + "col58": "9lxrd", + "col59": "dx1b0", + "col60": "9or4u", + "col61": "ffblb", + "col62": "c6dg6", + "col63": "xhwz2", + "col64": "gqwxq", + "col65": "0vgy7", + "col66": "ql38x", + "col67": "98vdk", + "col68": "mpubw", + "col69": "jhciw", + "col70": "vv3kk", + "col71": "vqc6w", + "col72": "x4kdv", + "col73": "28e2o", + "col74": "z84jc", + "col75": "myj87", + "col76": "g5wzm", + "col77": "rflj0", + "col78": "p5w8d", + "col79": "q67r7", + "col80": "k64fq", + "col81": "k1ryr", + "col82": "12msm", + "col83": "528wh", + "col84": "icduh", + "col85": "vw478", + "col86": "xg2we", + "col87": "ys2fu", + "col88": "m3nvd", + "col89": "jstjq", + "col90": "y2vjf", + "col91": "abhit", + "col92": "ie4qt", + "col93": "5rl4x", + "col94": "gv73j", + "col95": "gc245", + "col96": "2wep1", + "col97": "ha3v8", + "col98": "8vfak", + "col99": "7ilub", + "col100": "iny8m", + "col101": "qkgiq", + "col102": "3l2xm", + "col103": "t636s", + "col104": "onovb", + "col105": "5i1bo", + "col106": "kdxpv", + "col107": "wksfh", + "col108": "5eu97", + "col109": "6gf5a", + "col110": "i1am7", + "col111": "68zd7", + "col112": "7bmc6", + "col113": "2mziq", + "col114": "3wcad", + "col115": "4wm2o", + "col116": "scyqf", + "col117": "9lckv", + "col118": "dg4a4", + "col119": "81572", + "col120": "dauzw", + "col121": "wk5ai", + "col122": "0cck1", + "col123": "yjh9h", + "col124": "2hnt6", + "col125": "jr616", + "col126": "lufy2", + "col127": "80x16", + "col128": "y683l", + "col129": "yupgg", + "col130": "wu8gw", + "col131": "8jfp7", + "col132": "aiw0n", + "col133": "6arot", + "col134": "a9bme", + "col135": "zx4zs", + "col136": "cbo6j", + "col137": "8d0bt", + "col138": "8iz57", + "col139": "rcbfl", + "col140": "08ijk", + "col141": "c7qtf", + "col142": "ubxrt", + "col143": "vrnyg", + "col144": "xrooq", + "col145": "munmq", + "col146": "xe889", + "col147": "tqkh5", + "col148": "cxexf", + "col149": "6ytpe", + "col150": "06aa8", + "col151": "taoof", + "col152": "4wxkn", + "col153": "ijyht", + "col154": "yb8xt", + "col155": "5e5d6", + "col156": "n5ehs", + "col157": "o08d4", + "col158": "rpfcr", + "col159": "ziq3l", + "col160": "585ok", + "col161": "v64g5", + "col162": "dsq7u", + "col163": "fyl1u", + "col164": "30rda", + "col165": "vywjx", + "col166": "eiuea", + "col167": "keixy", + "col168": "h8ol2", + "col169": "djt03", + "col170": "mqfv6", + "col171": "ssk4h", + "col172": "u77p8", + "col173": "de2xa", + "col174": "8ucng", + "col175": "wvbwb", + "col176": "yawxr", + "col177": "16d5d", + "col178": "d7lwa", + "col179": "zgdzw", + "col180": "zq1pv", + "col181": "at7xk", + "col182": "clep6", + "col183": "laxou", + "col184": "6dzsh", + "col185": "ws2ms", + "col186": "zwwyw", + "col187": "w4456", + "col188": "s2jfn", + "col189": "f6l3a", + "col190": "m2ljm", + "col191": "hbm5e", + "col192": "v496q", + "col193": "ukm92", + "col194": "5j7lw", + "col195": "hba6x", + "col196": "mg8l2", + "col197": "0x480", + "col198": "kr4n8", + "col199": "jifnu", + "col200": "zuxs6", + "col201": "u515t", + "col202": "jotla", + "col203": "c626n", + "col204": "81p4p", + "col205": "jexaa", + "col206": "c4ci7", + "col207": "qao1a", + "col208": "m2b5a", + "col209": "gd5n4", + "col210": "aj6cu", + "col211": "u3ovm", + "col212": "qm606", + "col213": "eerjw", + "col214": "x9liw", + "col215": "th9db", + "col216": "jl7vt", + "col217": "r0knl", + "col218": "lyw4w", + "col219": "i38f0", + "col220": "s5ggt", + "col221": "4x48l", + "col222": "330ij", + "col223": "q7dn6", + "col224": "mpis7", + "col225": "dhtgp", + "col226": "0w14h", + "col227": "66q6x", + "col228": "a8wjt", + "col229": "z7mam", + "col230": "3o1ay", + "col231": "xmgva", + "col232": "t2pde", + "col233": "9go25", + "col234": "36yk1", + "col235": "ghpo4", + "col236": "jyxxt", + "col237": "x4umr", + "col238": "xzoca", + "col239": "ve15n", + "col240": "kt0eu", + "col241": "cyov8", + "col242": "yvxx8", + "col243": "opqfq", + "col244": "wz2ii", + "col245": "mtrzq", + "col246": "dh9eq", + "col247": "0c9iw", + "col248": "4zt7t", + "col249": "kx6u4", + "col250": "w65c7", + "col251": "isda5", + "col252": "6cmkk", + "col253": "7jysh", + "col254": "5m7ox", + "col255": "71z8x", + "col256": "53qy2", + "col257": "btdzo", + "col258": "agmy4", + "col259": "rgu85", + "col260": "vee8z", + "col261": "m697d", + "col262": "za5zm", + "col263": "pxa99", + "col264": "g319t", + "col265": "59rvp", + "col266": "ncj6j", + "col267": "e2t7r", + "col268": "2jvju", + "col269": "3tyur", + "col270": "gu1ro", + "col271": "9lxtv", + "col272": "9y4fh", + "col273": "1n4uz", + "col274": "pqeu1", + "col275": "litga", + "col276": "vmgju", + "col277": "qxrkn", + "col278": "0fk20", + "col279": "bgxtb", + "col280": "8vyj4", + "col281": "jw6mn", + "col282": "w91ui", + "col283": "lewfj", + "col284": "fy3cy", + "col285": "yoa7f", + "col286": "812le", + "col287": "a1uai", + "col288": "tp0pr", + "col289": "x1owx", + "col290": "yr203", + "col291": "e2i8w", + "col292": "u5cp6", + "col293": "k6hg7", + "col294": "wqpgc", + "col295": "7phwh", + "col296": "sxlw0", + "col297": "dotu3", + "col298": "ugtbr", + "col299": "zvmun", + "col300": "w1guc", + "col301": "9zuim", + "col302": "d0t6h", + "col303": "pwgyz", + "col304": "f9xn2", + "col305": "9wms9", + "col306": "3vx6t", + "col307": "r753k", + "col308": "743bk", + "col309": "7nqzr", + "col310": "z3iou", + "col311": "d5eay", + "col312": "8814d", + "col313": "6snr5", + "col314": "u3c7x", + "col315": "twwyy", + "col316": "k23jq", + "col317": "2tr41", + "col318": "094wd", + "col319": "02nr8", + "col320": "32x43", + "col321": "t3jt1", + "col322": "kn0ml", + "col323": "p0x9m", + "col324": "yv2oa", + "col325": "sghyo", + "col326": "75p5r", + "col327": "vkkmp", + "col328": "7v3y1", + "col329": "4bli0", + "col330": "aezvc", + "col331": "k92ug", + "col332": "p89fu", + "col333": "jqtdx", + "col334": "e3cl4", + "col335": "d1c3m", + "col336": "a28t5", + "col337": "8bdq7", + "col338": "ze678", + "col339": "im0xy", + "col340": "grhq5", + "col341": "jw5ln", + "col342": "1tpow", + "col343": "kj9zk", + "col344": "xbm1z", + "col345": "04cnn", + "col346": "bjftt", + "col347": "djoz6", + "col348": "0apm4", + "col349": "41dtl", + "col350": "5chbh", + "col351": "c3cw8", + "col352": "bxzr2", + "col353": "tmban", + "col354": "3twkm", + "col355": "4azsf", + "col356": "b7w9p", + "col357": "s8xz0", + "col358": "5mszg", + "col359": "ng0i4", + "col360": "1r0tb", + "col361": "tfaaz", + "col362": "wlo7y", + "col363": "k3hp1", + "col364": "6ac48", + "col365": "liio5", + "col366": "4ky1w", + "col367": "pylcs", + "col368": "rwabp", + "col369": "9kehm", + "col370": "uhonf", + "col371": "xhaqk", + "col372": "em0kn", + "col373": "tflsg", + "col374": "5vse5", + "col375": "2zh97", + "col376": "r805j", + "col377": "8zmrx", + "col378": "0uuru", + "col379": "9ngjh", + "col380": "7c5hk", + "col381": "k3g4g", + "col382": "2mcmy", + "col383": "g528w", + "col384": "g99pj", + "col385": "twbdy", + "col386": "5ktr5", + "col387": "jqob4", + "col388": "pen5l", + "col389": "rni6f", + "col390": "dbavq", + "col391": "1u9l6", + "col392": "5vb78", + "col393": "rbyso", + "col394": "os1ci", + "col395": "osurd", + "col396": "r34fy", + "col397": "jrsrp", + "col398": "uxe7e", + "col399": "u5f5j", + "col400": "t13qs", + "col401": "7inbl", + "col402": "uy1j9", + "col403": "vgtsc", + "col404": "7t8xo", + "col405": "6shrv", + "col406": "bn3b4", + "col407": "suf9h", + "col408": "jlbny", + "col409": "7jb8d", + "col410": "22cis", + "col411": "qlrlb", + "col412": "3emdh", + "col413": "7t4kw", + "col414": "y6ztm", + "col415": "p8rig", + "col416": "zzm6x", + "col417": "8pa11", + "col418": "2y0wd", + "col419": "ka0ri", + "col420": "gvp8w", + "col421": "1r7yq", + "col422": "jyxnj", + "col423": "izkhc", + "col424": "knonp", + "col425": "1ugmk", + "col426": "nqwqz", + "col427": "awapb", + "col428": "h39f9", + "col429": "j61l3", + "col430": "soer9", + "col431": "6sdgo", + "col432": "asp3q", + "col433": "83eo2", + "col434": "utgca", + "col435": "jfszu", + "col436": "klkry", + "col437": "uj0yr", + "col438": "xh4yw", + "col439": "bc6qj", + "col440": "q2yr1", + "col441": "l4e3d", + "col442": "zondh", + "col443": "6m2g9", + "col444": "jraej", + "col445": "g8mvc", + "col446": "7qjbj", + "col447": "7xlpa", + "col448": "xehro", + "col449": "ekrae", + "col450": "j2stw", + "col451": "qw98k", + "col452": "iji6n", + "col453": "x3pf8", + "col454": "8z2bk", + "col455": "muuye", + "col456": "vemu4", + "col457": "sbkla", + "col458": "48ejn", + "col459": "sgcwb", + "col460": "isd9r", + "col461": "huzk7", + "col462": "i5wws", + "col463": "0oasl", + "col464": "49608", + "col465": "nqrff", + "col466": "asn5p", + "col467": "tm3zg", + "col468": "b4uu3", + "col469": "tz5pc", + "col470": "m4d74", + "col471": "caepo", + "col472": "cm1dr", + "col473": "2zurc", + "col474": "1ayb7", + "col475": "j6hkq", + "col476": "29uzt", + "col477": "s5uae", + "col478": "67hjo", + "col479": "dbj7z", + "col480": "ndckr", + "col481": "9a40f", + "col482": "dq0ju", + "col483": "pa7lq", + "col484": "olhoe", + "col485": "r6hbz", + "col486": "85jx7", + "col487": "iidok", + "col488": "6mycj", + "col489": "9khg4", + "col490": "fatyb", + "col491": "4z0z2", + "col492": "m3g19", + "col493": "vnsvg", + "col494": "d3zha", + "col495": "72ah8", + "col496": "drcdd", + "col497": "0n24m", + "col498": "07vdr", + "col499": "k40ez", + "col500": "3q63l", + "col501": "k2c4u", + "col502": "4lkzh", + "col503": "wsrk0", + "col504": "vr11i", + "col505": "dsr3i", + "col506": "k9u33", + "col507": "voh46", + "col508": "ywi3v", + "col509": "hyvob", + "col510": "7j0u9", + "col511": "7lf21", + "col512": "npmsa", + "col513": "4oblh", + "col514": "9zqyx", + "col515": "vcplg", + "col516": "75mp2", + "col517": "9smjx", + "col518": "odie3", + "col519": "jq0h8", + "col520": "3bvi7", + "col521": "74jdz", + "col522": "zy21a", + "col523": "rrodp", + "col524": "v5332", + "col525": "zm5qf", + "col526": "4nv0e", + "col527": "8hdz6", + "col528": "pc4da", + "col529": "zp1be", + "col530": "niv8i", + "col531": "xzm88", + "col532": "ylhss", + "col533": "k6n9k", + "col534": "8sjl6", + "col535": "vdip3", + "col536": "2ag8w", + "col537": "dpl0b", + "col538": "az8xv", + "col539": "iuhzo", + "col540": "r3cpg", + "col541": "23bp5", + "col542": "cdh5j", + "col543": "ev54t", + "col544": "eft97", + "col545": "4f4gt", + "col546": "owz70", + "col547": "nr3x1", + "col548": "9pgcd", + "col549": "ufg6z", + "col550": "ka6lh", + "col551": "rtqrr", + "col552": "gnhqa", + "col553": "5u2kf", + "col554": "dli7g", + "col555": "ga7wo", + "col556": "ok6wq", + "col557": "4arop", + "col558": "hyoea", + "col559": "p1wr3", + "col560": "w00jf", + "col561": "7n5hj", + "col562": "trvo6", + "col563": "mqq4j", + "col564": "jt1j1", + "col565": "e37sd", + "col566": "79g4m", + "col567": "bnv0k", + "col568": "l2ekw", + "col569": "zwaan", + "col570": "urx41", + "col571": "2rhap", + "col572": "tdqj1", + "col573": "v1gto", + "col574": "a2u4l", + "col575": "30hnd", + "col576": "5bw83", + "col577": "ir2b4", + "col578": "jignp", + "col579": "tew18", + "col580": "eai7b", + "col581": "dd5no", + "col582": "t3xqc", + "col583": "qp1q9", + "col584": "14d1r", + "col585": "2s0aa", + "col586": "44py2", + "col587": "ff4wr", + "col588": "usr9q", + "col589": "a35t5", + "col590": "r2r6i", + "col591": "hi0gc", + "col592": "g8r0f", + "col593": "2v2w6", + "col594": "sqbhl", + "col595": "dxlgg", + "col596": "kmd2q", + "col597": "thayb", + "col598": "a6bjd", + "col599": "a855e", + "col600": "frdvz", + "col601": "xqc08", + "col602": "tv5ds", + "col603": "k6yck", + "col604": "gjqvz", + "col605": "uij5a", + "col606": "9y9d4", + "col607": "gn2ce", + "col608": "6xeih", + "col609": "ikmx2", + "col610": "8mjbx", + "col611": "vy608", + "col612": "i3vkd", + "col613": "unczx", + "col614": "j3pog", + "col615": "f2jz5", + "col616": "xxd0r", + "col617": "qj5tc", + "col618": "49ei7", + "col619": "z08dj", + "col620": "ykmuq", + "col621": "xe84j", + "col622": "20yfg", + "col623": "nkplj", + "col624": "dph60", + "col625": "q6esw", + "col626": "4c2y6", + "col627": "muyj2", + "col628": "pv7r9", + "col629": "b28jt", + "col630": "f0n1r", + "col631": "z1vbs", + "col632": "a2ped", + "col633": "pxzqf", + "col634": "lbe4y", + "col635": "91ub5", + "col636": "qweeq", + "col637": "t2eem", + "col638": "q45pp", + "col639": "afp5f", + "col640": "z7n3b", + "col641": "adp4v", + "col642": "zbn4c", + "col643": "bxmbl", + "col644": "huooz", + "col645": "4o3cq", + "col646": "q0q3y", + "col647": "slzmp", + "col648": "t1sos", + "col649": "gu9fe", + "col650": "lkca9", + "col651": "2imsb", + "col652": "wgaw4", + "col653": "7g25w", + "col654": "0f3ta", + "col655": "17eyi", + "col656": "3ad1r", + "col657": "a5q82", + "col658": "krvli", + "col659": "demn9", + "col660": "wrbc0", + "col661": "qh7mz", + "col662": "aohkl", + "col663": "agw5v", + "col664": "ojmkt", + "col665": "74484", + "col666": "4euum", + "col667": "vd5ey", + "col668": "vde6c", + "col669": "zey4f", + "col670": "s1d5f", + "col671": "exrjj", + "col672": "48ze2", + "col673": "4d01c", + "col674": "9lzwj", + "col675": "giadm", + "col676": "ounae", + "col677": "ma585", + "col678": "ey9s0", + "col679": "bmeo3", + "col680": "0f9tg", + "col681": "n7xkz", + "col682": "1ejp3", + "col683": "i6lxo", + "col684": "nek16", + "col685": "pzppx", + "col686": "lrhrw", + "col687": "dlsta", + "col688": "h936d", + "col689": "3xrl1", + "col690": "1nk8y", + "col691": "7xxkr", + "col692": "mchcg", + "col693": "rmfr7", + "col694": "0e022", + "col695": "4sqr7", + "col696": "j23mm", + "col697": "hskf7", + "col698": "a479x", + "col699": "kgqgt", + "col700": "3abdd", + "col701": "sxzqt", + "col702": "33gx8", + "col703": "japhf", + "col704": "k67w3", + "col705": "er5jw", + "col706": "rl8cf", + "col707": "d16fl", + "col708": "30hjx", + "col709": "ip9nr", + "col710": "nvgvd", + "col711": "gvqis", + "col712": "mu0i4", + "col713": "30dp2", + "col714": "844no", + "col715": "bkgjf", + "col716": "2r2ew", + "col717": "8aje3", + "col718": "q7h59", + "col719": "9vknp", + "col720": "sct2j", + "col721": "3jnci", + "col722": "9e04z", + "col723": "fnfsp", + "col724": "sjvoq", + "col725": "l8143", + "col726": "3rts3", + "col727": "x12xi", + "col728": "1ujm5", + "col729": "b9t88", + "col730": "j6gac", + "col731": "gtte9", + "col732": "hd1tl", + "col733": "wd6un", + "col734": "tplp3", + "col735": "c8xtq", + "col736": "hwj68", + "col737": "29cjk", + "col738": "itrx6", + "col739": "0pyxa", + "col740": "66peg", + "col741": "mqym2", + "col742": "poj5p", + "col743": "hcx3q", + "col744": "fmmcn", + "col745": "7p93s", + "col746": "3bbgd", + "col747": "usocj", + "col748": "clkx2", + "col749": "gqp3l", + "col750": "f7un6", + "col751": "2f1rh", + "col752": "xxxsl", + "col753": "b1fsr", + "col754": "rosgq", + "col755": "m5iph", + "col756": "2s2wc", + "col757": "6m6th", + "col758": "bctak", + "col759": "89on9", + "col760": "30uh2", + "col761": "n2i50", + "col762": "7vw2t", + "col763": "miidu", + "col764": "y43sv", + "col765": "wbfp2", + "col766": "dfcki", + "col767": "1bzd1", + "col768": "bkpma", + "col769": "zwaa1", + "col770": "s4nlv", + "col771": "wummh", + "col772": "jw2o8", + "col773": "x537h", + "col774": "af4gw", + "col775": "bhtw5", + "col776": "qck6j", + "col777": "yg5mx", + "col778": "5djgf", + "col779": "mlsbo", + "col780": "55kuk", + "col781": "3m9qd", + "col782": "od2hi", + "col783": "s88vm", + "col784": "7xx6d", + "col785": "w9j0i", + "col786": "8mk22", + "col787": "9sy87", + "col788": "uhdie", + "col789": "ucvwq", + "col790": "c5shc", + "col791": "m0r4w", + "col792": "viwzi", + "col793": "58o6k", + "col794": "y0lyr", + "col795": "3xgyi", + "col796": "29t7c", + "col797": "dveb1", + "col798": "7jaga", + "col799": "bdjbi", + "col800": "mfeuz", + "col801": "c6ya3", + "col802": "v0hy6", + "col803": "rh7q8", + "col804": "6tqpw", + "col805": "gjxg6", + "col806": "43wp4", + "col807": "emgnr", + "col808": "7n10r", + "col809": "0pahd", + "col810": "lscbf", + "col811": "l8b1y", + "col812": "kzxkv", + "col813": "rxn4n", + "col814": "9936t", + "col815": "zjn7e", + "col816": "gecra", + "col817": "9kiic", + "col818": "9mior", + "col819": "vyjba", + "col820": "lkntv", + "col821": "39akn", + "col822": "qcmvz", + "col823": "5bkqn", + "col824": "m2kum", + "col825": "jlbmo", + "col826": "i72e7", + "col827": "uskqw", + "col828": "k4imc", + "col829": "q90cs", + "col830": "gns6o", + "col831": "6xw9c", + "col832": "9zr0u", + "col833": "1vfl4", + "col834": "139c8", + "col835": "po7qp", + "col836": "koh6e", + "col837": "taitc", + "col838": "salzc", + "col839": "dacxu", + "col840": "5rz99", + "col841": "f94ze", + "col842": "c7fcg", + "col843": "hx0df", + "col844": "h447x", + "col845": "y5pe2", + "col846": "4yfaa", + "col847": "z61nf", + "col848": "sthqt", + "col849": "dzfib", + "col850": "up0po", + "col851": "zmlcu", + "col852": "6uw0y", + "col853": "2f8yn", + "col854": "y0xeh", + "col855": "c7u1q", + "col856": "20lxe", + "col857": "b3rdr", + "col858": "6tzbb", + "col859": "3humo", + "col860": "0014l", + "col861": "seqms", + "col862": "z2fl3", + "col863": "6v4iu", + "col864": "try9i", + "col865": "t6mti", + "col866": "p0j29", + "col867": "bh1d1", + "col868": "6h7o7", + "col869": "a6e5r", + "col870": "xxbls", + "col871": "az9do", + "col872": "114kj", + "col873": "t5tyr", + "col874": "6h3p0", + "col875": "5xtl8", + "col876": "cfawb", + "col877": "vvg24", + "col878": "h0xhn", + "col879": "b0941", + "col880": "royqn", + "col881": "4hdrk", + "col882": "ddj5y", + "col883": "l5w1u", + "col884": "kkide", + "col885": "gff8h", + "col886": "sdcy0", + "col887": "v1r4h", + "col888": "qecws", + "col889": "yw79m", + "col890": "2ejco", + "col891": "pfgw0", + "col892": "wh4s5", + "col893": "ay04b", + "col894": "ns6w4", + "col895": "uff4m", + "col896": "z42ld", + "col897": "f2a0x", + "col898": "tbffw", + "col899": "kgl3w", + "col900": "8qfo6", + "col901": "dywa7", + "col902": "tj5cc", + "col903": "5tnyx", + "col904": "ccylw", + "col905": "4f06i", + "col906": "cnn5g", + "col907": "qva4i", + "col908": "kievi", + "col909": "t0b6o", + "col910": "rsnd8", + "col911": "m2l9b", + "col912": "5s709", + "col913": "v0te6", + "col914": "yrj3s", + "col915": "2eool", + "col916": "7qehf", + "col917": "t9jaa", + "col918": "fwa1y", + "col919": "jabnk", + "col920": "kjz5h", + "col921": "wvyb5", + "col922": "yrsdm", + "col923": "ufrm2", + "col924": "b911o", + "col925": "888os", + "col926": "w4sho", + "col927": "1mq3x", + "col928": "65a31", + "col929": "crfnp", + "col930": "0jlvy", + "col931": "ztmaf", + "col932": "kekbp", + "col933": "s74hd", + "col934": "urmy3", + "col935": "k0h6o", + "col936": "i0j5u", + "col937": "ffe3b", + "col938": "dmnt5", + "col939": "mmu4a", + "col940": "cv8ja", + "col941": "jcpsu", + "col942": "fa97t", + "col943": "tpbkd", + "col944": "fz73e", + "col945": "5j1mj", + "col946": "zx9fn", + "col947": "eafts", + "col948": "3i22x", + "col949": "kf0ig", + "col950": "pnnzm", + "col951": "phhoi", + "col952": "gahdr", + "col953": "lw5y8", + "col954": "5ficm", + "col955": "usm6c", + "col956": "35fjw", + "col957": "81t2x", + "col958": "rplaq", + "col959": "fx2od", + "col960": "kzcyq", + "col961": "3a8eg", + "col962": "tyeno", + "col963": "theog", + "col964": "oghfl", + "col965": "6bau5", + "col966": "km1wh", + "col967": "kshqi", + "col968": "0z7ug", + "col969": "bt846", + "col970": "gxp8i", + "col971": "f8hbl", + "col972": "uno0r", + "col973": "dyldy", + "col974": "y3i4s", + "col975": "3dyyd", + "col976": "v4kly", + "col977": "4s2y9", + "col978": "5bv1p", + "col979": "f3g2d", + "col980": "3qqy4", + "col981": "tad94", + "col982": "msrhc", + "col983": "c24o7", + "col984": "6h4hl", + "col985": "8p4y8", + "col986": "y3dj4", + "col987": "8ocg0", + "col988": "w4x8s", + "col989": "a2154", + "col990": "sslqi", + "col991": "aqohe", + "col992": "gtktd", + "col993": "4769x", + "col994": "tywp4", + "col995": "sohe3", + "col996": "rd6q8", + "col997": "kj37b", + "col998": "21491", + "col999": "7ch1p" + }, + { + "name": "Hannah Black", + "gender": "female", + "col0": "3lauy", + "col1": "npozi", + "col2": "06h0e", + "col3": "af1se", + "col4": "5olcz", + "col5": "qvpdc", + "col6": "dctk7", + "col7": "v2mkl", + "col8": "quo3h", + "col9": "5utzr", + "col10": "mtczo", + "col11": "2qbt7", + "col12": "igx49", + "col13": "uvuao", + "col14": "feb7i", + "col15": "q3awf", + "col16": "feiel", + "col17": "h4qkj", + "col18": "pn6zu", + "col19": "h8d4s", + "col20": "yeq0y", + "col21": "mpglq", + "col22": "arhwo", + "col23": "x6hbb", + "col24": "vj4h5", + "col25": "38jir", + "col26": "7p1i7", + "col27": "uxowt", + "col28": "cek2t", + "col29": "wgv58", + "col30": "ibbwn", + "col31": "yzod5", + "col32": "munxa", + "col33": "pc8la", + "col34": "1yp4t", + "col35": "n5e0m", + "col36": "xyhcm", + "col37": "zu576", + "col38": "snt5a", + "col39": "0tdl2", + "col40": "scm49", + "col41": "iohh7", + "col42": "ug88h", + "col43": "d8etr", + "col44": "n5sfh", + "col45": "3f2oa", + "col46": "t8p7h", + "col47": "u4o19", + "col48": "23zsi", + "col49": "212ez", + "col50": "s68l7", + "col51": "jd3f3", + "col52": "1snww", + "col53": "cgvc1", + "col54": "37z88", + "col55": "zaeoq", + "col56": "ul0pr", + "col57": "oxwdj", + "col58": "h937y", + "col59": "x264a", + "col60": "hocid", + "col61": "pymju", + "col62": "27hvx", + "col63": "yh4uz", + "col64": "o4pz0", + "col65": "2wjst", + "col66": "a6u2r", + "col67": "bsl1f", + "col68": "ttsjv", + "col69": "d06v3", + "col70": "nbk02", + "col71": "8baoz", + "col72": "ev3lc", + "col73": "vqndd", + "col74": "qjzjk", + "col75": "t8grm", + "col76": "jz6k2", + "col77": "i5nzr", + "col78": "c9k4e", + "col79": "bvy3d", + "col80": "bbfys", + "col81": "olf06", + "col82": "e47he", + "col83": "t2ce7", + "col84": "5usny", + "col85": "8dklk", + "col86": "cbni3", + "col87": "0oi43", + "col88": "2j3tc", + "col89": "ul7u8", + "col90": "pqybu", + "col91": "wor00", + "col92": "3gg43", + "col93": "9ilwi", + "col94": "f9quf", + "col95": "vea16", + "col96": "x20dc", + "col97": "fttgf", + "col98": "ornib", + "col99": "tb83f", + "col100": "ev3yw", + "col101": "gngac", + "col102": "knlod", + "col103": "h4aks", + "col104": "1c2wb", + "col105": "yblcq", + "col106": "8sr14", + "col107": "53x76", + "col108": "klrge", + "col109": "dw0x3", + "col110": "evbuw", + "col111": "78jl6", + "col112": "9r5du", + "col113": "rkm85", + "col114": "lylsv", + "col115": "rlqj2", + "col116": "bgzx7", + "col117": "s55ry", + "col118": "jypoy", + "col119": "bdrup", + "col120": "7d505", + "col121": "nhalg", + "col122": "1nulq", + "col123": "2e02y", + "col124": "h7zus", + "col125": "bbm08", + "col126": "v06fc", + "col127": "d5597", + "col128": "ajznm", + "col129": "jnkle", + "col130": "can9m", + "col131": "lv7f5", + "col132": "dyml9", + "col133": "y5mtz", + "col134": "ndm1l", + "col135": "voxbb", + "col136": "r6imr", + "col137": "f5hvm", + "col138": "4qgbm", + "col139": "lpmx0", + "col140": "f71bp", + "col141": "e7zjf", + "col142": "4nkgz", + "col143": "g11rf", + "col144": "ims3y", + "col145": "f8a47", + "col146": "08ur3", + "col147": "1zjck", + "col148": "vp0ps", + "col149": "1wwhj", + "col150": "1gfly", + "col151": "rb758", + "col152": "enyzq", + "col153": "0w7p6", + "col154": "3wp3t", + "col155": "v26zw", + "col156": "ed9vg", + "col157": "rn46m", + "col158": "ui1rg", + "col159": "0ot7n", + "col160": "u352r", + "col161": "zu21z", + "col162": "pxvch", + "col163": "lu6py", + "col164": "7c34d", + "col165": "ay1ep", + "col166": "iex39", + "col167": "we3w9", + "col168": "w4rao", + "col169": "tb6f7", + "col170": "pbatd", + "col171": "f1wdm", + "col172": "aul77", + "col173": "wztca", + "col174": "4e3x4", + "col175": "r6pki", + "col176": "mi03o", + "col177": "4jvvy", + "col178": "ibbxv", + "col179": "3r54w", + "col180": "7ervk", + "col181": "szkqa", + "col182": "ka0qm", + "col183": "y6fo2", + "col184": "76zmz", + "col185": "z3rdc", + "col186": "jl1yu", + "col187": "4cx1y", + "col188": "zp6bf", + "col189": "pz4id", + "col190": "r48bk", + "col191": "16sj9", + "col192": "5zyhl", + "col193": "a00jt", + "col194": "qlw61", + "col195": "1delm", + "col196": "0ebgu", + "col197": "1j8vi", + "col198": "rai3b", + "col199": "sdzef", + "col200": "yns40", + "col201": "2io7c", + "col202": "99ujg", + "col203": "dw26k", + "col204": "8bz54", + "col205": "g3kdn", + "col206": "8h6zv", + "col207": "v4o7j", + "col208": "fdccy", + "col209": "n9aq4", + "col210": "44s1u", + "col211": "7ps4u", + "col212": "935wp", + "col213": "94csx", + "col214": "zrfwb", + "col215": "iq8ux", + "col216": "5smht", + "col217": "twdbp", + "col218": "6ta1s", + "col219": "ptbcl", + "col220": "1k213", + "col221": "3vw81", + "col222": "pqkvs", + "col223": "eixqo", + "col224": "6w57t", + "col225": "ofvtg", + "col226": "1xy9u", + "col227": "cdg5b", + "col228": "n7xqn", + "col229": "up6gx", + "col230": "xydi1", + "col231": "0at1t", + "col232": "0goet", + "col233": "1txfo", + "col234": "rkj2c", + "col235": "fllmy", + "col236": "04b8y", + "col237": "9z4tg", + "col238": "mu8un", + "col239": "ik00y", + "col240": "au87w", + "col241": "qmtjx", + "col242": "latib", + "col243": "ymh1n", + "col244": "4hp2a", + "col245": "ihtr3", + "col246": "1nlna", + "col247": "r23ga", + "col248": "ntz9j", + "col249": "kqupx", + "col250": "rqcwh", + "col251": "zvcko", + "col252": "8sf67", + "col253": "oxq8a", + "col254": "207d5", + "col255": "cbydv", + "col256": "7z9m0", + "col257": "bc6dm", + "col258": "3wxy1", + "col259": "71njc", + "col260": "y2dty", + "col261": "q97qj", + "col262": "5e90p", + "col263": "gnq08", + "col264": "mxrzb", + "col265": "jo3zr", + "col266": "jpjno", + "col267": "alp25", + "col268": "cbs81", + "col269": "n0mfx", + "col270": "nvuc5", + "col271": "8q2ml", + "col272": "woi85", + "col273": "orn99", + "col274": "nz2ar", + "col275": "muam7", + "col276": "tzi11", + "col277": "dim0y", + "col278": "tdbj4", + "col279": "z3hy7", + "col280": "gp069", + "col281": "s52y5", + "col282": "78cxw", + "col283": "yho4j", + "col284": "61fry", + "col285": "g3y6o", + "col286": "0zkad", + "col287": "65xc3", + "col288": "rcr7k", + "col289": "4el04", + "col290": "w30kz", + "col291": "9q034", + "col292": "ce3kx", + "col293": "gpfq2", + "col294": "fqc1c", + "col295": "mlmrl", + "col296": "kon5b", + "col297": "5r6x9", + "col298": "wr1z5", + "col299": "9dqzq", + "col300": "orbwm", + "col301": "0vi0f", + "col302": "qb526", + "col303": "acba2", + "col304": "lqee2", + "col305": "c8782", + "col306": "z9lof", + "col307": "z47ic", + "col308": "jozzy", + "col309": "gu6tc", + "col310": "n796h", + "col311": "8ry4y", + "col312": "413km", + "col313": "3nmkp", + "col314": "wnebr", + "col315": "r7in1", + "col316": "y8ud7", + "col317": "unwwi", + "col318": "6manw", + "col319": "fr4bn", + "col320": "7q7y8", + "col321": "749z8", + "col322": "zmkhf", + "col323": "mv84y", + "col324": "l2vq4", + "col325": "eietm", + "col326": "hk3a0", + "col327": "7mwfe", + "col328": "zvq7b", + "col329": "yugdf", + "col330": "lqdhc", + "col331": "j273c", + "col332": "lnai2", + "col333": "zak4x", + "col334": "5igsc", + "col335": "zpi4l", + "col336": "vzt8g", + "col337": "fq70y", + "col338": "b15vw", + "col339": "k714e", + "col340": "kgs1d", + "col341": "q6699", + "col342": "gco06", + "col343": "cqk5o", + "col344": "h6o71", + "col345": "pop5k", + "col346": "j39wu", + "col347": "3u884", + "col348": "fgpw1", + "col349": "e4jgc", + "col350": "9mot9", + "col351": "fkg3l", + "col352": "9viyw", + "col353": "huzi4", + "col354": "o2qn3", + "col355": "pyh9e", + "col356": "j56ke", + "col357": "vj47g", + "col358": "6upmb", + "col359": "0ib6a", + "col360": "w8h6z", + "col361": "ek4c0", + "col362": "rfmqi", + "col363": "8shde", + "col364": "vr5fe", + "col365": "5d9sr", + "col366": "ru5fe", + "col367": "7aacv", + "col368": "rnvoc", + "col369": "bg6r7", + "col370": "dhdfg", + "col371": "7z7hv", + "col372": "6n0m2", + "col373": "pu80t", + "col374": "xr0pz", + "col375": "6fevd", + "col376": "vfm3x", + "col377": "qn2su", + "col378": "048m8", + "col379": "3vtb6", + "col380": "7rsfe", + "col381": "x98bs", + "col382": "8ikeu", + "col383": "ofp34", + "col384": "ciyk6", + "col385": "3ka4p", + "col386": "jqwn2", + "col387": "r9aak", + "col388": "pn2j6", + "col389": "qt7cq", + "col390": "u3ofr", + "col391": "lzfg9", + "col392": "ufrmi", + "col393": "k8dr2", + "col394": "qy57a", + "col395": "7yxq1", + "col396": "3ttl1", + "col397": "1nbxa", + "col398": "sy905", + "col399": "f3c8z", + "col400": "om1q9", + "col401": "e0kbp", + "col402": "fmoh1", + "col403": "8etlj", + "col404": "zf794", + "col405": "upkmm", + "col406": "r4nw5", + "col407": "jvvlm", + "col408": "ap26f", + "col409": "tae7x", + "col410": "w9kvk", + "col411": "c2i4p", + "col412": "9sjbo", + "col413": "vmq9g", + "col414": "mpaea", + "col415": "u5sf0", + "col416": "hdkto", + "col417": "y5pml", + "col418": "shddg", + "col419": "wjlb2", + "col420": "4v2fa", + "col421": "csbxy", + "col422": "8z2tc", + "col423": "8snft", + "col424": "dyshb", + "col425": "5bk8x", + "col426": "v5zel", + "col427": "815vo", + "col428": "87bj2", + "col429": "t3tgp", + "col430": "v56q9", + "col431": "mkl2b", + "col432": "c1hmx", + "col433": "o9gk5", + "col434": "r6e8i", + "col435": "9sqel", + "col436": "i6lkm", + "col437": "kq5gv", + "col438": "3uvkf", + "col439": "n5u4h", + "col440": "ux0xg", + "col441": "wxegu", + "col442": "bwfuz", + "col443": "ij2hm", + "col444": "1iarj", + "col445": "l1rwp", + "col446": "ex2p1", + "col447": "azcmx", + "col448": "mgtjw", + "col449": "s7kc9", + "col450": "8kdn5", + "col451": "zl4im", + "col452": "d174p", + "col453": "a9hev", + "col454": "hmjfe", + "col455": "g7sdg", + "col456": "k2mgt", + "col457": "5h6zz", + "col458": "egx2h", + "col459": "sxf8m", + "col460": "uq6yd", + "col461": "2g6dl", + "col462": "qvuu7", + "col463": "5p6t8", + "col464": "q62sj", + "col465": "ghas1", + "col466": "j1eee", + "col467": "tqf77", + "col468": "t3eqw", + "col469": "1c51o", + "col470": "wn69m", + "col471": "lmyjd", + "col472": "uvhpf", + "col473": "5kcb4", + "col474": "b1aen", + "col475": "ligl4", + "col476": "49h93", + "col477": "p7mwx", + "col478": "vhxv2", + "col479": "d9meq", + "col480": "66kyp", + "col481": "c22l5", + "col482": "k9xpu", + "col483": "4d2op", + "col484": "i89j9", + "col485": "dfi5w", + "col486": "d8h24", + "col487": "7ibuc", + "col488": "2ese7", + "col489": "rqjar", + "col490": "pn730", + "col491": "u851b", + "col492": "ga5lv", + "col493": "6m4i5", + "col494": "ecja4", + "col495": "ze81j", + "col496": "yhcth", + "col497": "i8gf3", + "col498": "ck9gz", + "col499": "dt5zj", + "col500": "eqfl7", + "col501": "wuw42", + "col502": "q3jm9", + "col503": "p70in", + "col504": "gxduq", + "col505": "9w4lo", + "col506": "0dxbn", + "col507": "893ko", + "col508": "59pdg", + "col509": "r1w0b", + "col510": "wgncw", + "col511": "hh1gm", + "col512": "yx2fz", + "col513": "w5ny3", + "col514": "66lrx", + "col515": "n7non", + "col516": "yydft", + "col517": "9qd0s", + "col518": "ivzr4", + "col519": "048m2", + "col520": "e9rab", + "col521": "h97te", + "col522": "zvj88", + "col523": "5ru5p", + "col524": "qnz09", + "col525": "q2llp", + "col526": "19ixx", + "col527": "5c5yo", + "col528": "4r5r8", + "col529": "ruxnr", + "col530": "mnqo4", + "col531": "5jpxy", + "col532": "qlgka", + "col533": "nrus0", + "col534": "i6u3t", + "col535": "3l0tl", + "col536": "rpabf", + "col537": "j0in6", + "col538": "n7dv0", + "col539": "dj8us", + "col540": "tpajj", + "col541": "0flmk", + "col542": "3uflg", + "col543": "v3z17", + "col544": "k8z5v", + "col545": "oc97l", + "col546": "n7kky", + "col547": "ptu1o", + "col548": "k4lqk", + "col549": "8xxm5", + "col550": "5ixbl", + "col551": "rav9f", + "col552": "47so9", + "col553": "mkh5i", + "col554": "dssp0", + "col555": "cp0bl", + "col556": "zkpdn", + "col557": "uapil", + "col558": "pfqz3", + "col559": "t93bg", + "col560": "5yt5c", + "col561": "mjni0", + "col562": "w8fez", + "col563": "tyuqj", + "col564": "mb2k3", + "col565": "v1vw4", + "col566": "x0dbj", + "col567": "0kho5", + "col568": "ro7o1", + "col569": "l5ppz", + "col570": "b8fr8", + "col571": "xj3sd", + "col572": "48gg0", + "col573": "5l31o", + "col574": "hictb", + "col575": "8f370", + "col576": "1hqib", + "col577": "cmmg4", + "col578": "n5hvk", + "col579": "wonuw", + "col580": "8mbzx", + "col581": "xgw6q", + "col582": "curis", + "col583": "sgbaa", + "col584": "jjsqx", + "col585": "n5fmg", + "col586": "mxp15", + "col587": "29src", + "col588": "mjqcv", + "col589": "bwh0y", + "col590": "0kts0", + "col591": "7epdp", + "col592": "ixjtc", + "col593": "2yce5", + "col594": "ypoel", + "col595": "zl7wo", + "col596": "oh0n3", + "col597": "b3wva", + "col598": "6c7ax", + "col599": "fn3oi", + "col600": "tj6jd", + "col601": "kh8og", + "col602": "b0q6e", + "col603": "mksfh", + "col604": "6c3lw", + "col605": "kkrkj", + "col606": "1akba", + "col607": "j96df", + "col608": "aar0c", + "col609": "ga475", + "col610": "gzbyd", + "col611": "t4w83", + "col612": "x44sf", + "col613": "bqkn7", + "col614": "2t9dn", + "col615": "rgo2r", + "col616": "shsap", + "col617": "hxupu", + "col618": "w6gp8", + "col619": "12gez", + "col620": "dk5is", + "col621": "tt5aj", + "col622": "b9w3z", + "col623": "nliu2", + "col624": "br6us", + "col625": "ktcfc", + "col626": "ur103", + "col627": "9udlz", + "col628": "ycdnm", + "col629": "rkzhk", + "col630": "zdr3r", + "col631": "vpa8t", + "col632": "l62ji", + "col633": "gewrt", + "col634": "w3tng", + "col635": "nlh6d", + "col636": "zzwcu", + "col637": "caoyy", + "col638": "7znkq", + "col639": "yl993", + "col640": "aiqkh", + "col641": "ht4jc", + "col642": "ya6od", + "col643": "o3eol", + "col644": "1s1er", + "col645": "gky9n", + "col646": "78qgq", + "col647": "03h4f", + "col648": "24yp2", + "col649": "43483", + "col650": "k5lqx", + "col651": "ibs0w", + "col652": "zim3w", + "col653": "3ha9w", + "col654": "9xa9n", + "col655": "vakv4", + "col656": "837gr", + "col657": "kpcdo", + "col658": "qind8", + "col659": "6nhfk", + "col660": "7d5d1", + "col661": "drjct", + "col662": "vm05j", + "col663": "exczr", + "col664": "uj1bx", + "col665": "52a61", + "col666": "j1062", + "col667": "kuog2", + "col668": "nt69w", + "col669": "a4pts", + "col670": "l312e", + "col671": "e8osf", + "col672": "xm5lv", + "col673": "cwsge", + "col674": "dcol5", + "col675": "vf7yk", + "col676": "mvkak", + "col677": "lgdbv", + "col678": "55171", + "col679": "580le", + "col680": "tgdr9", + "col681": "jog91", + "col682": "h6oyq", + "col683": "a1zwc", + "col684": "zj37n", + "col685": "sl54d", + "col686": "649z4", + "col687": "ccwjh", + "col688": "qb6l8", + "col689": "xmas3", + "col690": "1zrbk", + "col691": "pum5w", + "col692": "s456q", + "col693": "0zv69", + "col694": "oh0vs", + "col695": "e0dku", + "col696": "s8g6f", + "col697": "xfjvj", + "col698": "c8dwu", + "col699": "zxbe3", + "col700": "noqd7", + "col701": "yrli0", + "col702": "ff5nc", + "col703": "98713", + "col704": "krd9x", + "col705": "z5ce5", + "col706": "eb026", + "col707": "6dl8w", + "col708": "7kd26", + "col709": "lcwtl", + "col710": "t814y", + "col711": "5az7e", + "col712": "po1k4", + "col713": "slzl1", + "col714": "sy90y", + "col715": "k3kxr", + "col716": "lyskf", + "col717": "wybh3", + "col718": "kpd1n", + "col719": "9zw8z", + "col720": "33r8l", + "col721": "plk1m", + "col722": "y5o1n", + "col723": "s9ix7", + "col724": "hmpzk", + "col725": "4fxbp", + "col726": "rxm0z", + "col727": "m7c1f", + "col728": "stm3x", + "col729": "9i2r2", + "col730": "5u11p", + "col731": "1kdrf", + "col732": "mg1l0", + "col733": "wmghc", + "col734": "f9fuq", + "col735": "srka2", + "col736": "f6euc", + "col737": "dypgk", + "col738": "kikoh", + "col739": "wucn0", + "col740": "b7bas", + "col741": "i20l1", + "col742": "6f1sf", + "col743": "cyp91", + "col744": "mh9j5", + "col745": "xl80i", + "col746": "lh2o8", + "col747": "bzqq4", + "col748": "3030x", + "col749": "g3dgk", + "col750": "ki3uo", + "col751": "jfri7", + "col752": "k8dz2", + "col753": "ldeku", + "col754": "qog6i", + "col755": "bsqmt", + "col756": "f4fim", + "col757": "vwi6r", + "col758": "pp6lh", + "col759": "4khuf", + "col760": "ttrbq", + "col761": "3goa2", + "col762": "642ej", + "col763": "s15o7", + "col764": "ee30q", + "col765": "rac79", + "col766": "r1rjl", + "col767": "6ui0y", + "col768": "4dgz3", + "col769": "cnkm0", + "col770": "co46g", + "col771": "xzswi", + "col772": "0hr83", + "col773": "d9c23", + "col774": "dk66n", + "col775": "poh67", + "col776": "s7m9z", + "col777": "so5r2", + "col778": "7rkc0", + "col779": "p7fn6", + "col780": "6lt4s", + "col781": "ucfss", + "col782": "0ob11", + "col783": "04fkq", + "col784": "hhq4l", + "col785": "76k6r", + "col786": "s4u16", + "col787": "x5akq", + "col788": "2l39x", + "col789": "zepx1", + "col790": "7k42c", + "col791": "oj0x8", + "col792": "blthw", + "col793": "ngdkx", + "col794": "e4pjk", + "col795": "1q4if", + "col796": "enrh2", + "col797": "vhz1s", + "col798": "pdpke", + "col799": "67v2l", + "col800": "sa2lv", + "col801": "5eihq", + "col802": "g9cbw", + "col803": "2kxkq", + "col804": "8zcqs", + "col805": "2h778", + "col806": "ab37h", + "col807": "mbhs4", + "col808": "wwrzo", + "col809": "9sh3o", + "col810": "kqv2t", + "col811": "xus5d", + "col812": "p3stb", + "col813": "2y9kl", + "col814": "r9j5l", + "col815": "9yecq", + "col816": "y2nh4", + "col817": "g2fmp", + "col818": "cuigd", + "col819": "spo1p", + "col820": "bzg57", + "col821": "5zggw", + "col822": "wi2sn", + "col823": "49uok", + "col824": "vgnxi", + "col825": "s2pco", + "col826": "7djt8", + "col827": "1zake", + "col828": "7tefc", + "col829": "eebsj", + "col830": "s7qh0", + "col831": "17cyw", + "col832": "crwsc", + "col833": "90iu7", + "col834": "ifg5j", + "col835": "2blt3", + "col836": "188sy", + "col837": "wrz2y", + "col838": "4d24v", + "col839": "k2pzx", + "col840": "ivatx", + "col841": "ml7an", + "col842": "yanqg", + "col843": "5xocn", + "col844": "wtnxo", + "col845": "uviq9", + "col846": "ipykr", + "col847": "zibcy", + "col848": "5f6b1", + "col849": "pilt0", + "col850": "4aaq0", + "col851": "if30e", + "col852": "ad2d1", + "col853": "p1f6s", + "col854": "kwhe4", + "col855": "dtjy2", + "col856": "56sth", + "col857": "ljgep", + "col858": "kl9x5", + "col859": "643sz", + "col860": "4c344", + "col861": "lf0k2", + "col862": "3x3rv", + "col863": "j0y7z", + "col864": "8ut4k", + "col865": "5s1w0", + "col866": "t2mpf", + "col867": "u6522", + "col868": "jtyo9", + "col869": "9w4yk", + "col870": "22bqe", + "col871": "yseax", + "col872": "birhm", + "col873": "tdudz", + "col874": "z4h61", + "col875": "rzv6j", + "col876": "ai40f", + "col877": "irlky", + "col878": "4u8cg", + "col879": "l0706", + "col880": "cd0v1", + "col881": "59sm6", + "col882": "otjcb", + "col883": "fh3tv", + "col884": "78kr0", + "col885": "jyjvg", + "col886": "29rgn", + "col887": "t8v1c", + "col888": "zln1e", + "col889": "mrbih", + "col890": "yk7vv", + "col891": "clrxb", + "col892": "hp3kq", + "col893": "y5tp8", + "col894": "qu3by", + "col895": "ylrvh", + "col896": "3t73h", + "col897": "wt8xo", + "col898": "wzcxo", + "col899": "apfmd", + "col900": "b17hl", + "col901": "ismo6", + "col902": "uh4kr", + "col903": "cvuiv", + "col904": "l960d", + "col905": "alwd6", + "col906": "sl73a", + "col907": "j8u5s", + "col908": "h8b3x", + "col909": "f2494", + "col910": "cng3b", + "col911": "bhwgu", + "col912": "k7ser", + "col913": "10ab3", + "col914": "l7oli", + "col915": "7yol8", + "col916": "d8ccu", + "col917": "2pb5q", + "col918": "5d7rz", + "col919": "pmgoe", + "col920": "v14iq", + "col921": "8co7w", + "col922": "76f2l", + "col923": "ttxyl", + "col924": "hiebk", + "col925": "552pg", + "col926": "ib7ng", + "col927": "s8mgm", + "col928": "tinga", + "col929": "av0tb", + "col930": "1pdk2", + "col931": "7dgjw", + "col932": "nyvyf", + "col933": "76hd4", + "col934": "evsvn", + "col935": "k8ev9", + "col936": "46dz4", + "col937": "fdkbw", + "col938": "4qolg", + "col939": "5r4zg", + "col940": "aqpex", + "col941": "7vzbp", + "col942": "ur6hq", + "col943": "r379h", + "col944": "80ml7", + "col945": "o1tjl", + "col946": "jfygp", + "col947": "w14yq", + "col948": "ttsxq", + "col949": "58dc6", + "col950": "qz7mj", + "col951": "2g017", + "col952": "2hcux", + "col953": "99bzs", + "col954": "ktshl", + "col955": "4rq8k", + "col956": "rqpdq", + "col957": "w3dgb", + "col958": "gwo6f", + "col959": "0f8c8", + "col960": "oox6g", + "col961": "uekxv", + "col962": "zqxo1", + "col963": "gjuee", + "col964": "pl43z", + "col965": "c4w0j", + "col966": "vz73y", + "col967": "3jw0a", + "col968": "1wp1w", + "col969": "8rena", + "col970": "k3ex1", + "col971": "szb1b", + "col972": "c8cka", + "col973": "pijbh", + "col974": "hyj8v", + "col975": "992pt", + "col976": "p8j43", + "col977": "y5dqq", + "col978": "91waf", + "col979": "207rs", + "col980": "kg9kc", + "col981": "fhyre", + "col982": "85d6m", + "col983": "mvjfh", + "col984": "eyra9", + "col985": "fqzqb", + "col986": "49h9j", + "col987": "il46r", + "col988": "rrndz", + "col989": "684dt", + "col990": "rzdy3", + "col991": "vz4a0", + "col992": "duvm9", + "col993": "oejxy", + "col994": "2tbsg", + "col995": "45wsi", + "col996": "fq8hp", + "col997": "zw8to", + "col998": "1omnb", + "col999": "bcwl9" + }, + { + "name": "Jacobson Spence", + "gender": "male", + "col0": "djz7p", + "col1": "6t81i", + "col2": "omuz7", + "col3": "76ak8", + "col4": "p786s", + "col5": "t4fl6", + "col6": "nx2dh", + "col7": "i93r4", + "col8": "buboy", + "col9": "2ucbe", + "col10": "w1agc", + "col11": "ifzym", + "col12": "1sliq", + "col13": "s4xbf", + "col14": "hczgs", + "col15": "7wzv7", + "col16": "20fc7", + "col17": "z3esc", + "col18": "mhanq", + "col19": "7ws4g", + "col20": "b2awr", + "col21": "z3u6d", + "col22": "s6y77", + "col23": "rfm2q", + "col24": "ay9yg", + "col25": "6cunx", + "col26": "59w61", + "col27": "wbbni", + "col28": "istmc", + "col29": "ssan3", + "col30": "u2en9", + "col31": "jq8ji", + "col32": "prido", + "col33": "k7d0y", + "col34": "xndqy", + "col35": "9un2j", + "col36": "j4pnt", + "col37": "r8b3q", + "col38": "cj1o5", + "col39": "vy41k", + "col40": "cj97v", + "col41": "zobmh", + "col42": "a78hk", + "col43": "kqpvm", + "col44": "4q3he", + "col45": "k2ydk", + "col46": "pj85u", + "col47": "5kvyl", + "col48": "q1yo3", + "col49": "j4evd", + "col50": "royp7", + "col51": "z7syw", + "col52": "8fq2y", + "col53": "h1tg8", + "col54": "qobvw", + "col55": "tw7sy", + "col56": "wt08b", + "col57": "a8j3j", + "col58": "teomi", + "col59": "quuzl", + "col60": "2sbic", + "col61": "zfrlh", + "col62": "750as", + "col63": "l98zt", + "col64": "anb1s", + "col65": "qa4xy", + "col66": "v3xov", + "col67": "tvtqk", + "col68": "89p0r", + "col69": "0ntbg", + "col70": "mmm7s", + "col71": "yfuin", + "col72": "fcag7", + "col73": "w6ohv", + "col74": "b5j6k", + "col75": "oit1p", + "col76": "nlz7v", + "col77": "zc0un", + "col78": "8rscb", + "col79": "z3z63", + "col80": "jxgac", + "col81": "5i10v", + "col82": "lkswm", + "col83": "gq9p9", + "col84": "7vihk", + "col85": "ng1c7", + "col86": "yzwxq", + "col87": "y85jv", + "col88": "fjyx6", + "col89": "wulew", + "col90": "os4sh", + "col91": "7wm65", + "col92": "eb5df", + "col93": "elya1", + "col94": "916sk", + "col95": "58mpq", + "col96": "55sln", + "col97": "16snx", + "col98": "exkj0", + "col99": "10bfh", + "col100": "h8bz7", + "col101": "4yg4w", + "col102": "6zuas", + "col103": "fwqok", + "col104": "oke3t", + "col105": "7h65c", + "col106": "mu54i", + "col107": "66frq", + "col108": "6fa8w", + "col109": "tmraf", + "col110": "tpfe8", + "col111": "t5bwp", + "col112": "gea4r", + "col113": "3mx19", + "col114": "3re25", + "col115": "37zcb", + "col116": "4e0we", + "col117": "c8460", + "col118": "2ts2y", + "col119": "zpkli", + "col120": "wvy2w", + "col121": "gewju", + "col122": "ruh8l", + "col123": "yhvns", + "col124": "k39d3", + "col125": "2rcnm", + "col126": "c7qwj", + "col127": "7kza6", + "col128": "hoiye", + "col129": "w6fap", + "col130": "6vt52", + "col131": "07qpb", + "col132": "3iggb", + "col133": "dskvg", + "col134": "mj6e6", + "col135": "jjskb", + "col136": "3xlqk", + "col137": "bk5ud", + "col138": "q02nm", + "col139": "d92he", + "col140": "6ku8p", + "col141": "llnk6", + "col142": "o6g7g", + "col143": "gzgyr", + "col144": "8nod6", + "col145": "bq8cf", + "col146": "fe1ig", + "col147": "3a1l1", + "col148": "xid1t", + "col149": "86t1z", + "col150": "9nzha", + "col151": "icz7e", + "col152": "hu1z8", + "col153": "hni2p", + "col154": "m3hce", + "col155": "e94t1", + "col156": "v74i8", + "col157": "borq3", + "col158": "hbm1e", + "col159": "pppjf", + "col160": "m12c5", + "col161": "8dlow", + "col162": "yefr4", + "col163": "ym9xs", + "col164": "aqy4o", + "col165": "9yet9", + "col166": "4demt", + "col167": "b0fmy", + "col168": "e15hp", + "col169": "oyv4g", + "col170": "d12im", + "col171": "j2pqw", + "col172": "mb941", + "col173": "ke6r2", + "col174": "8p2ut", + "col175": "5cnui", + "col176": "5rort", + "col177": "hdoz6", + "col178": "klnxo", + "col179": "5mrw8", + "col180": "isvwe", + "col181": "4jwly", + "col182": "ha6x4", + "col183": "02ic9", + "col184": "kgypa", + "col185": "itp80", + "col186": "rm0sp", + "col187": "zlja1", + "col188": "gid8w", + "col189": "xqmuy", + "col190": "91ab4", + "col191": "eq3s3", + "col192": "xcugy", + "col193": "ivgjc", + "col194": "yldwp", + "col195": "6stij", + "col196": "9qw6e", + "col197": "6lpud", + "col198": "6tubv", + "col199": "txsuj", + "col200": "hc8tc", + "col201": "c2zu0", + "col202": "9lalq", + "col203": "tuo14", + "col204": "io675", + "col205": "z7l0o", + "col206": "ika1i", + "col207": "5sofw", + "col208": "lgfks", + "col209": "4iz17", + "col210": "oahun", + "col211": "ph17x", + "col212": "629bs", + "col213": "apc6q", + "col214": "tho7u", + "col215": "aljqd", + "col216": "p6rgj", + "col217": "smjow", + "col218": "lvdpv", + "col219": "brbqq", + "col220": "56mgz", + "col221": "dj6q4", + "col222": "9md2p", + "col223": "jqt4i", + "col224": "i4y5c", + "col225": "ta1x6", + "col226": "cpu8w", + "col227": "3icft", + "col228": "8405z", + "col229": "dfy95", + "col230": "9csct", + "col231": "qidwy", + "col232": "gzxtl", + "col233": "j5l8t", + "col234": "aeqlq", + "col235": "csza0", + "col236": "nng23", + "col237": "5fq0u", + "col238": "ka8u3", + "col239": "42a8w", + "col240": "c6hgg", + "col241": "q2zdr", + "col242": "khkl2", + "col243": "d8tge", + "col244": "54xhg", + "col245": "h7uxl", + "col246": "oqb7u", + "col247": "a7134", + "col248": "f9y7l", + "col249": "0ibmz", + "col250": "13d7r", + "col251": "xldci", + "col252": "ypxns", + "col253": "szcs4", + "col254": "5eiba", + "col255": "3wn4j", + "col256": "wbfpg", + "col257": "cj516", + "col258": "e2aer", + "col259": "8zq26", + "col260": "h9f0j", + "col261": "idvn4", + "col262": "yml2i", + "col263": "bz9n9", + "col264": "6uywq", + "col265": "k20jj", + "col266": "juo6v", + "col267": "3epg9", + "col268": "p4sxp", + "col269": "uuqyh", + "col270": "a7axt", + "col271": "0ypeu", + "col272": "ibabe", + "col273": "xqg6w", + "col274": "yq7m4", + "col275": "s21uz", + "col276": "8kn5l", + "col277": "zg7qh", + "col278": "l3xc9", + "col279": "2hh7r", + "col280": "f8iub", + "col281": "o4ajg", + "col282": "xq7cp", + "col283": "0fwl4", + "col284": "j25ok", + "col285": "pqz0i", + "col286": "jfnik", + "col287": "nfk07", + "col288": "gp0e4", + "col289": "3xydr", + "col290": "dy8fq", + "col291": "fxmgn", + "col292": "smumw", + "col293": "sd67i", + "col294": "bymqq", + "col295": "cxeu4", + "col296": "20fsz", + "col297": "beb7o", + "col298": "vewba", + "col299": "o5v5o", + "col300": "o5ple", + "col301": "bbqw5", + "col302": "3liqf", + "col303": "6am1i", + "col304": "nh7o3", + "col305": "c9p71", + "col306": "1lii6", + "col307": "cuuwa", + "col308": "pcuwt", + "col309": "wdrq7", + "col310": "ozrgf", + "col311": "of9zo", + "col312": "ouaf2", + "col313": "w7h8v", + "col314": "df77p", + "col315": "0j2fl", + "col316": "m0a2p", + "col317": "3dm8v", + "col318": "64uj0", + "col319": "axhsi", + "col320": "7gj8w", + "col321": "ltwov", + "col322": "0my7a", + "col323": "rnq6z", + "col324": "w9v6j", + "col325": "s7s9n", + "col326": "cujn6", + "col327": "jjxdj", + "col328": "jkmrz", + "col329": "l5mpu", + "col330": "usdrc", + "col331": "diodn", + "col332": "59qm1", + "col333": "7krqs", + "col334": "fu7si", + "col335": "jzej9", + "col336": "z9suz", + "col337": "s0k9q", + "col338": "hscj5", + "col339": "q4jcb", + "col340": "lduvi", + "col341": "r9g3m", + "col342": "qvcsr", + "col343": "tlna8", + "col344": "39b2u", + "col345": "048oe", + "col346": "4w4mo", + "col347": "7f6k0", + "col348": "o3h4v", + "col349": "vxjas", + "col350": "co21f", + "col351": "jaksg", + "col352": "iovrn", + "col353": "7nt7w", + "col354": "2bpyi", + "col355": "mg9as", + "col356": "6s1pi", + "col357": "5vhqv", + "col358": "ikobp", + "col359": "ezr0e", + "col360": "zvux8", + "col361": "o94sy", + "col362": "s4mnb", + "col363": "70ptu", + "col364": "r0av5", + "col365": "vz4om", + "col366": "623i6", + "col367": "z74sn", + "col368": "g3qhb", + "col369": "taef4", + "col370": "5avn6", + "col371": "o1nlr", + "col372": "xu6qq", + "col373": "5d6z3", + "col374": "yaztq", + "col375": "2ofv8", + "col376": "bmfpb", + "col377": "4j2t5", + "col378": "zqk4m", + "col379": "ip3x4", + "col380": "c5f4j", + "col381": "n41i9", + "col382": "upj3n", + "col383": "w3csh", + "col384": "0618n", + "col385": "0eacv", + "col386": "8q6ww", + "col387": "lvvoq", + "col388": "u8wvl", + "col389": "o49zf", + "col390": "ab6c9", + "col391": "wi626", + "col392": "74f16", + "col393": "aoo85", + "col394": "ci4zd", + "col395": "a5cbu", + "col396": "hnay4", + "col397": "hjfss", + "col398": "iu0nr", + "col399": "91cus", + "col400": "1aybg", + "col401": "8bidi", + "col402": "3m065", + "col403": "csl18", + "col404": "g26ej", + "col405": "ugo7k", + "col406": "hbwts", + "col407": "ll62w", + "col408": "29tdk", + "col409": "3qkf1", + "col410": "9vrpu", + "col411": "oi696", + "col412": "xkuhx", + "col413": "r8x3s", + "col414": "stiqa", + "col415": "u7k6s", + "col416": "bkejc", + "col417": "79ref", + "col418": "e5bbg", + "col419": "hvdlp", + "col420": "f1dwe", + "col421": "wf3r1", + "col422": "vl190", + "col423": "9p3px", + "col424": "sk2zv", + "col425": "gygpq", + "col426": "petob", + "col427": "o9sq5", + "col428": "j18oc", + "col429": "2ntt6", + "col430": "7nfzj", + "col431": "c8f89", + "col432": "2rwnf", + "col433": "qj4jv", + "col434": "33q6t", + "col435": "7mela", + "col436": "rw2og", + "col437": "9kgcu", + "col438": "h2pfs", + "col439": "86ax2", + "col440": "do3h9", + "col441": "xcz1w", + "col442": "wrn27", + "col443": "a4t2n", + "col444": "1rs5t", + "col445": "8mvcm", + "col446": "5cuv5", + "col447": "qll8q", + "col448": "by2k2", + "col449": "ed1tc", + "col450": "4ud7w", + "col451": "qfsqr", + "col452": "mror7", + "col453": "j9nu4", + "col454": "f884w", + "col455": "r936r", + "col456": "3j6an", + "col457": "a54n6", + "col458": "v5x6s", + "col459": "ka5ku", + "col460": "fhen7", + "col461": "a0zft", + "col462": "dpxgm", + "col463": "nunyw", + "col464": "auqoy", + "col465": "g577b", + "col466": "eb1wl", + "col467": "07jzn", + "col468": "4t4iz", + "col469": "opbyd", + "col470": "nwpog", + "col471": "2xdte", + "col472": "78kp0", + "col473": "3wuw5", + "col474": "z8qf0", + "col475": "d3q34", + "col476": "o2xh4", + "col477": "6yxf5", + "col478": "hgyop", + "col479": "sofuw", + "col480": "nvr69", + "col481": "3n6bk", + "col482": "iar6m", + "col483": "ag1yy", + "col484": "l5xs7", + "col485": "jr2v9", + "col486": "ufi0g", + "col487": "80xfo", + "col488": "n5eyt", + "col489": "r90di", + "col490": "1lal6", + "col491": "pixh2", + "col492": "yvmbq", + "col493": "1ksgl", + "col494": "fanf2", + "col495": "h10d2", + "col496": "fjwfi", + "col497": "vfjyo", + "col498": "43bq4", + "col499": "ppvym", + "col500": "87j5p", + "col501": "3tuj9", + "col502": "lsfek", + "col503": "xs5gz", + "col504": "twzp9", + "col505": "p8iqa", + "col506": "tvfym", + "col507": "qwcsr", + "col508": "2919a", + "col509": "n5ynu", + "col510": "l7dnl", + "col511": "2k3ci", + "col512": "gmolo", + "col513": "46t7a", + "col514": "y99cl", + "col515": "vkz9o", + "col516": "2oley", + "col517": "z3aiy", + "col518": "9cjtf", + "col519": "7jprv", + "col520": "hgahn", + "col521": "1irx8", + "col522": "x3stm", + "col523": "xh1am", + "col524": "5eb5z", + "col525": "fakak", + "col526": "mc7ew", + "col527": "x59y5", + "col528": "3ha5n", + "col529": "moemn", + "col530": "a55dk", + "col531": "75wja", + "col532": "lcom5", + "col533": "loe8a", + "col534": "m1iuu", + "col535": "s07ga", + "col536": "50uz6", + "col537": "n531p", + "col538": "cbkkq", + "col539": "6j7d5", + "col540": "2svx1", + "col541": "ht2dh", + "col542": "kg8qt", + "col543": "evwut", + "col544": "zm2g3", + "col545": "vz8w7", + "col546": "z6xtv", + "col547": "a0fdg", + "col548": "635oy", + "col549": "yhfn9", + "col550": "lqp0s", + "col551": "cz7my", + "col552": "d596b", + "col553": "r8tc6", + "col554": "mcivt", + "col555": "w4ydj", + "col556": "6c9jv", + "col557": "0k7f0", + "col558": "ioumo", + "col559": "pw2o6", + "col560": "okpst", + "col561": "3ert5", + "col562": "2zwb9", + "col563": "ntzpe", + "col564": "y3zkm", + "col565": "7l9jr", + "col566": "a9yci", + "col567": "7ithv", + "col568": "0iwyy", + "col569": "olygi", + "col570": "bovrt", + "col571": "dqyr3", + "col572": "w8ggy", + "col573": "qnakl", + "col574": "64re8", + "col575": "frynu", + "col576": "77nln", + "col577": "3q4tj", + "col578": "ywjef", + "col579": "4adx3", + "col580": "541se", + "col581": "2jyxl", + "col582": "vg052", + "col583": "kco1l", + "col584": "qyro0", + "col585": "mrv1g", + "col586": "49ia7", + "col587": "x3bzu", + "col588": "k8mqz", + "col589": "e6erk", + "col590": "dhesb", + "col591": "17mf7", + "col592": "56ys6", + "col593": "vcepd", + "col594": "u8fyp", + "col595": "jf1vk", + "col596": "e2816", + "col597": "yd3o4", + "col598": "lpu10", + "col599": "fu0nq", + "col600": "bh1b1", + "col601": "3x0be", + "col602": "w6f8k", + "col603": "t097u", + "col604": "dhep7", + "col605": "7us8h", + "col606": "q7dzj", + "col607": "t23dc", + "col608": "wrucc", + "col609": "r9sw8", + "col610": "4rdh2", + "col611": "0e100", + "col612": "5ybf7", + "col613": "253sk", + "col614": "cdo4j", + "col615": "i5s9p", + "col616": "8etfo", + "col617": "q38ug", + "col618": "8foyg", + "col619": "h0jlm", + "col620": "w9kjy", + "col621": "w3mwb", + "col622": "5iwl8", + "col623": "g6yv6", + "col624": "yn77u", + "col625": "ohzic", + "col626": "9lg4m", + "col627": "fnjhx", + "col628": "rqpuw", + "col629": "6nniy", + "col630": "q1mub", + "col631": "mw9az", + "col632": "0d9eu", + "col633": "80h0x", + "col634": "kuh8h", + "col635": "0rc36", + "col636": "5b5mz", + "col637": "woyzm", + "col638": "a7kv3", + "col639": "qh2tf", + "col640": "7rriy", + "col641": "ohyah", + "col642": "74eei", + "col643": "sj3kg", + "col644": "t9fx1", + "col645": "xguw7", + "col646": "jh7gv", + "col647": "o1tpj", + "col648": "52l3d", + "col649": "ade2o", + "col650": "kcs10", + "col651": "p8nn1", + "col652": "zi9e2", + "col653": "4q9py", + "col654": "llgf3", + "col655": "iqktl", + "col656": "rm8bv", + "col657": "feifw", + "col658": "rle8u", + "col659": "1ftl2", + "col660": "r89gb", + "col661": "ii1d3", + "col662": "aerqk", + "col663": "rog2v", + "col664": "0cqy1", + "col665": "pgl4w", + "col666": "kiurv", + "col667": "f0d2a", + "col668": "xmtao", + "col669": "rw8gn", + "col670": "46d2q", + "col671": "z2voo", + "col672": "7g105", + "col673": "yn4fd", + "col674": "7ve1j", + "col675": "z725u", + "col676": "hh7f9", + "col677": "0gakz", + "col678": "qvw3t", + "col679": "wqw9a", + "col680": "mwady", + "col681": "haizd", + "col682": "qsyml", + "col683": "zea8y", + "col684": "ojh7s", + "col685": "go3vi", + "col686": "0he9b", + "col687": "sp03i", + "col688": "9ou5w", + "col689": "spqpn", + "col690": "f96ux", + "col691": "05zvr", + "col692": "6lwji", + "col693": "mhupr", + "col694": "vj6wd", + "col695": "4esag", + "col696": "5jvb6", + "col697": "zp1pp", + "col698": "jnahz", + "col699": "wtefo", + "col700": "zntdk", + "col701": "9dz37", + "col702": "0do8e", + "col703": "o4puo", + "col704": "ec8s5", + "col705": "2qec4", + "col706": "4byqu", + "col707": "h6yb5", + "col708": "s9jq6", + "col709": "wz4zg", + "col710": "ff38t", + "col711": "8q7ku", + "col712": "dizvk", + "col713": "i8cqn", + "col714": "f46zg", + "col715": "kdich", + "col716": "m17d5", + "col717": "nl6ot", + "col718": "llqyz", + "col719": "73ypa", + "col720": "xsswx", + "col721": "zkqdr", + "col722": "2oxkv", + "col723": "3e1fn", + "col724": "pnict", + "col725": "u04e4", + "col726": "1gubx", + "col727": "cd9wi", + "col728": "28m9w", + "col729": "vuoiq", + "col730": "8of6u", + "col731": "1aybc", + "col732": "krkq6", + "col733": "gx3zb", + "col734": "9mdha", + "col735": "79t8d", + "col736": "xohrg", + "col737": "oz5vn", + "col738": "wlnp8", + "col739": "bbtwu", + "col740": "u6gx3", + "col741": "xzuk0", + "col742": "pg86v", + "col743": "t84no", + "col744": "8346k", + "col745": "5xtjf", + "col746": "qae3k", + "col747": "2va66", + "col748": "2ysrw", + "col749": "u1mfx", + "col750": "zht4y", + "col751": "4mabv", + "col752": "zy3xb", + "col753": "tku0n", + "col754": "nqile", + "col755": "hya29", + "col756": "c8aw9", + "col757": "xcfoz", + "col758": "5tlnk", + "col759": "eajk0", + "col760": "luday", + "col761": "4v0mg", + "col762": "x9au5", + "col763": "p9pjj", + "col764": "ijyb6", + "col765": "1h7y4", + "col766": "txfbk", + "col767": "7n6fq", + "col768": "0q3a4", + "col769": "jrl4z", + "col770": "v78o3", + "col771": "hdh16", + "col772": "hqz0y", + "col773": "156kc", + "col774": "ic41c", + "col775": "atjqd", + "col776": "9ai5r", + "col777": "ng435", + "col778": "117jg", + "col779": "ats8u", + "col780": "60hew", + "col781": "vpcwt", + "col782": "x1z0x", + "col783": "qtihw", + "col784": "kas2y", + "col785": "j07ur", + "col786": "phd83", + "col787": "64viy", + "col788": "ynosr", + "col789": "4pm18", + "col790": "wjso8", + "col791": "n8e7w", + "col792": "p88d1", + "col793": "ixngr", + "col794": "71ytx", + "col795": "du4ic", + "col796": "jh7hg", + "col797": "b1p8f", + "col798": "u7xsw", + "col799": "n7q8e", + "col800": "zrr98", + "col801": "z3yti", + "col802": "sbpbs", + "col803": "il36q", + "col804": "jf62s", + "col805": "hh2js", + "col806": "q9gv6", + "col807": "s9zmo", + "col808": "edb36", + "col809": "igzdj", + "col810": "i7fic", + "col811": "xo4ng", + "col812": "ppfky", + "col813": "43l5t", + "col814": "y2cro", + "col815": "adlkb", + "col816": "uunmh", + "col817": "zffuc", + "col818": "tccvq", + "col819": "8yrpv", + "col820": "2p2gz", + "col821": "gtjoz", + "col822": "qa0ck", + "col823": "tjo8t", + "col824": "9u74a", + "col825": "qkpsp", + "col826": "qzr3r", + "col827": "use3f", + "col828": "p6kxt", + "col829": "pydey", + "col830": "sprpo", + "col831": "wc428", + "col832": "y7wrp", + "col833": "jxf3n", + "col834": "r2c49", + "col835": "2v8r5", + "col836": "o4htf", + "col837": "k5bnx", + "col838": "rdyev", + "col839": "in1e0", + "col840": "4vxih", + "col841": "55i46", + "col842": "4kaat", + "col843": "89n0e", + "col844": "c1ajx", + "col845": "uepyx", + "col846": "cwylr", + "col847": "7ce37", + "col848": "f0vet", + "col849": "verex", + "col850": "0y4bn", + "col851": "imhnu", + "col852": "3lc5n", + "col853": "vvmhj", + "col854": "mv58r", + "col855": "lrtb4", + "col856": "5vs96", + "col857": "3cvhn", + "col858": "2shst", + "col859": "vas8g", + "col860": "yh7ue", + "col861": "w8r2o", + "col862": "5i1ei", + "col863": "9yco3", + "col864": "0edn1", + "col865": "pn6n6", + "col866": "u4su6", + "col867": "rud9m", + "col868": "j4543", + "col869": "6kill", + "col870": "bniko", + "col871": "2mofc", + "col872": "egsqh", + "col873": "ouqdu", + "col874": "3a21y", + "col875": "xn0bi", + "col876": "r1ei8", + "col877": "cyiua", + "col878": "hf2ip", + "col879": "8mddf", + "col880": "89nrp", + "col881": "s83e2", + "col882": "v5hts", + "col883": "piioc", + "col884": "86h2o", + "col885": "1qnmk", + "col886": "eg9tt", + "col887": "x6vyc", + "col888": "bf9dp", + "col889": "cw834", + "col890": "37elj", + "col891": "er0lq", + "col892": "713tu", + "col893": "xzsqr", + "col894": "jv4bu", + "col895": "dri2e", + "col896": "u2rzy", + "col897": "xs8i9", + "col898": "sukvs", + "col899": "d4gn9", + "col900": "b3vml", + "col901": "41kn2", + "col902": "qp7te", + "col903": "cgztw", + "col904": "ye43o", + "col905": "e5049", + "col906": "m8ukh", + "col907": "kxizw", + "col908": "hl2j3", + "col909": "pqsbv", + "col910": "i8z8x", + "col911": "d7w4g", + "col912": "89r96", + "col913": "dky1m", + "col914": "3tybd", + "col915": "3zh20", + "col916": "c7hop", + "col917": "syod8", + "col918": "1x6xz", + "col919": "s7ce2", + "col920": "2xl4o", + "col921": "kvwhg", + "col922": "m4ns4", + "col923": "0e7w0", + "col924": "5oj4u", + "col925": "j2ew5", + "col926": "g7h7t", + "col927": "ixcvc", + "col928": "aituj", + "col929": "2javh", + "col930": "uq9an", + "col931": "gt2tt", + "col932": "465ob", + "col933": "eil3g", + "col934": "hrlm1", + "col935": "3fsgt", + "col936": "fof45", + "col937": "m9lnp", + "col938": "ebkhz", + "col939": "0uwed", + "col940": "7rcav", + "col941": "bnpsd", + "col942": "hx8j7", + "col943": "oe7rr", + "col944": "db41d", + "col945": "yinl8", + "col946": "qk6pt", + "col947": "wf6su", + "col948": "4l7fw", + "col949": "hzzmq", + "col950": "08puv", + "col951": "jjvhb", + "col952": "6vyqj", + "col953": "u388d", + "col954": "93b6x", + "col955": "w22ra", + "col956": "84kgq", + "col957": "tijyq", + "col958": "tko07", + "col959": "3lrsk", + "col960": "3rbb3", + "col961": "qnynw", + "col962": "h44lm", + "col963": "fnli0", + "col964": "dwvu5", + "col965": "kmzac", + "col966": "gn3r3", + "col967": "e248a", + "col968": "gw3uf", + "col969": "oxcp8", + "col970": "rwp2b", + "col971": "e3sgm", + "col972": "bqsd0", + "col973": "hhorf", + "col974": "vd4zm", + "col975": "gl3tz", + "col976": "tohmp", + "col977": "au0qw", + "col978": "8vxa4", + "col979": "ep3k3", + "col980": "m0obb", + "col981": "0h69k", + "col982": "4bffo", + "col983": "clq7g", + "col984": "cn5ok", + "col985": "7mk81", + "col986": "b8wv5", + "col987": "3lqg2", + "col988": "tmp6e", + "col989": "ra0j1", + "col990": "h7etc", + "col991": "3hpxl", + "col992": "x3kw7", + "col993": "ql8kg", + "col994": "bh5qf", + "col995": "g329z", + "col996": "2vtln", + "col997": "qnzwd", + "col998": "1tc6m", + "col999": "gq7qh" + }, + { + "name": "Merritt Delacruz", + "gender": "male", + "col0": "891ec", + "col1": "s9ecj", + "col2": "h5vn6", + "col3": "huivf", + "col4": "b8p3t", + "col5": "922rk", + "col6": "82i5y", + "col7": "x7zvr", + "col8": "at7c9", + "col9": "pb9ct", + "col10": "vpcvk", + "col11": "rj254", + "col12": "c1sjk", + "col13": "h5kfn", + "col14": "eahbw", + "col15": "zwpdy", + "col16": "dn190", + "col17": "lhsjl", + "col18": "q7wcc", + "col19": "auv3u", + "col20": "p3u59", + "col21": "vo67b", + "col22": "r6a4k", + "col23": "hr1m8", + "col24": "3vkcz", + "col25": "io2xf", + "col26": "ff7n9", + "col27": "3vbwi", + "col28": "324dn", + "col29": "8q47d", + "col30": "kziau", + "col31": "h3y0v", + "col32": "bnm6g", + "col33": "3ty8h", + "col34": "jdfwt", + "col35": "j517y", + "col36": "fi9az", + "col37": "4b7fz", + "col38": "hr8xb", + "col39": "9ycjp", + "col40": "orfcg", + "col41": "f81rx", + "col42": "2x2o3", + "col43": "goooy", + "col44": "2kci6", + "col45": "jfapr", + "col46": "ntg6t", + "col47": "jobin", + "col48": "twb24", + "col49": "1igvo", + "col50": "wis59", + "col51": "mtfbz", + "col52": "p7yfb", + "col53": "8vl8m", + "col54": "7zt1c", + "col55": "5xr8i", + "col56": "iqg77", + "col57": "rhv5m", + "col58": "kol0r", + "col59": "i0yta", + "col60": "zi04s", + "col61": "ynwpv", + "col62": "b5t81", + "col63": "3b0o5", + "col64": "cnc92", + "col65": "mi5ns", + "col66": "tqsid", + "col67": "cb0nk", + "col68": "7sick", + "col69": "q1zld", + "col70": "r9nsi", + "col71": "ul3o9", + "col72": "td4hl", + "col73": "o10c0", + "col74": "sa9bl", + "col75": "v7u0r", + "col76": "eg0pc", + "col77": "syi45", + "col78": "wr4ha", + "col79": "xf1m6", + "col80": "9j8nl", + "col81": "ft48t", + "col82": "0xgi5", + "col83": "20hik", + "col84": "ysd70", + "col85": "ox5ik", + "col86": "olidl", + "col87": "r2tuk", + "col88": "x8436", + "col89": "a81xs", + "col90": "ukzuc", + "col91": "ffxia", + "col92": "nlqhk", + "col93": "9g08r", + "col94": "ufcf4", + "col95": "bwore", + "col96": "cptj4", + "col97": "elarp", + "col98": "js36i", + "col99": "5jccr", + "col100": "kyq2a", + "col101": "fqciq", + "col102": "g9bnt", + "col103": "7yyva", + "col104": "nfm25", + "col105": "hne10", + "col106": "kdkfw", + "col107": "rrbfr", + "col108": "61pha", + "col109": "5qlv3", + "col110": "24jph", + "col111": "oa6vs", + "col112": "2bb7z", + "col113": "gdd96", + "col114": "zwucu", + "col115": "hi4ee", + "col116": "5ah1y", + "col117": "hkjwo", + "col118": "bjasv", + "col119": "z7dzd", + "col120": "wlefu", + "col121": "mo8pl", + "col122": "8bi1y", + "col123": "726mg", + "col124": "vq4el", + "col125": "vbn61", + "col126": "ipm08", + "col127": "cddd0", + "col128": "iq3tk", + "col129": "sm2x3", + "col130": "xo9c6", + "col131": "ih37r", + "col132": "oczad", + "col133": "d5vsu", + "col134": "96tgf", + "col135": "ql5gt", + "col136": "pr593", + "col137": "tu1hy", + "col138": "dfbqd", + "col139": "gkd61", + "col140": "uumhk", + "col141": "9jss5", + "col142": "zr3sz", + "col143": "vl2kw", + "col144": "zpyz8", + "col145": "fmc9t", + "col146": "w7x6g", + "col147": "y42pg", + "col148": "9277j", + "col149": "dktxw", + "col150": "zwhoe", + "col151": "g1n0z", + "col152": "zgea8", + "col153": "i2vpc", + "col154": "xqqym", + "col155": "f9je3", + "col156": "9rw3j", + "col157": "rsetn", + "col158": "bsavn", + "col159": "83d4h", + "col160": "v3dkz", + "col161": "8ayjj", + "col162": "5g3i7", + "col163": "gomn7", + "col164": "j6ziv", + "col165": "5i4sh", + "col166": "22jl2", + "col167": "fwjns", + "col168": "cdrry", + "col169": "2p2cw", + "col170": "5857u", + "col171": "uez15", + "col172": "uzx8s", + "col173": "bwefz", + "col174": "0fbpb", + "col175": "4v2lj", + "col176": "0ge6d", + "col177": "hhdlx", + "col178": "misv8", + "col179": "fqycx", + "col180": "geoz5", + "col181": "kniao", + "col182": "ferq6", + "col183": "engt7", + "col184": "65x5e", + "col185": "dlh9t", + "col186": "6c6yf", + "col187": "jpner", + "col188": "55fde", + "col189": "kh0e9", + "col190": "bufmb", + "col191": "7m0sl", + "col192": "x0xgs", + "col193": "jpkn5", + "col194": "qvi1w", + "col195": "9u2bu", + "col196": "bn4c9", + "col197": "3q9ne", + "col198": "3f53s", + "col199": "uhi3s", + "col200": "gsznb", + "col201": "2gli1", + "col202": "rtxd7", + "col203": "glusu", + "col204": "88mu4", + "col205": "pwo7b", + "col206": "ldi02", + "col207": "5kx2s", + "col208": "6gl9c", + "col209": "ld795", + "col210": "9imoh", + "col211": "edk65", + "col212": "d58kj", + "col213": "cku36", + "col214": "nvqg6", + "col215": "a23qz", + "col216": "76vai", + "col217": "wmkfi", + "col218": "54d8r", + "col219": "tkf7c", + "col220": "kcmkg", + "col221": "wbuq1", + "col222": "th0rh", + "col223": "60a3b", + "col224": "qykr6", + "col225": "gd0kj", + "col226": "ojgoz", + "col227": "gdp6f", + "col228": "coat7", + "col229": "rergo", + "col230": "r2x85", + "col231": "n3pn8", + "col232": "4uqs2", + "col233": "63mou", + "col234": "3im84", + "col235": "8ogyp", + "col236": "5y9gm", + "col237": "0auc6", + "col238": "uanjx", + "col239": "y1d2m", + "col240": "es3xm", + "col241": "p6t0e", + "col242": "dv7oe", + "col243": "y3ept", + "col244": "wp7tm", + "col245": "78hg9", + "col246": "vio1o", + "col247": "jnbov", + "col248": "vnhvy", + "col249": "lsdqv", + "col250": "8wz6j", + "col251": "h9yel", + "col252": "esoep", + "col253": "l3jw5", + "col254": "1xp82", + "col255": "gjy0s", + "col256": "9ek8h", + "col257": "n8lbd", + "col258": "v85sz", + "col259": "w5euv", + "col260": "2ql3u", + "col261": "p4lzp", + "col262": "hckph", + "col263": "x8bc6", + "col264": "4wliu", + "col265": "t0fee", + "col266": "e6gu1", + "col267": "45l1l", + "col268": "d79h3", + "col269": "246wm", + "col270": "poqzo", + "col271": "yyq0e", + "col272": "yjyol", + "col273": "lzn78", + "col274": "341d4", + "col275": "cx5w1", + "col276": "25bsh", + "col277": "ta81m", + "col278": "e1x5d", + "col279": "5gexu", + "col280": "wdnc3", + "col281": "v7vo5", + "col282": "76vyt", + "col283": "k39n4", + "col284": "9c1r0", + "col285": "egll1", + "col286": "py7en", + "col287": "mfzp0", + "col288": "luv2y", + "col289": "dlrnb", + "col290": "fmyoz", + "col291": "fq9cd", + "col292": "d4rnv", + "col293": "5m7m5", + "col294": "v6z1l", + "col295": "g17mb", + "col296": "5v1a3", + "col297": "oq2w4", + "col298": "fisan", + "col299": "eui5s", + "col300": "31xqy", + "col301": "vyha5", + "col302": "fl7tl", + "col303": "llvb1", + "col304": "y4fze", + "col305": "jbsqr", + "col306": "2dx85", + "col307": "gct1g", + "col308": "jf9sp", + "col309": "wojxi", + "col310": "lv47n", + "col311": "xxfe8", + "col312": "mjfxa", + "col313": "f14xu", + "col314": "tnyhf", + "col315": "zs434", + "col316": "1l3z1", + "col317": "jlqvy", + "col318": "esx9b", + "col319": "vot5u", + "col320": "t192n", + "col321": "qabko", + "col322": "nldlo", + "col323": "hoe9s", + "col324": "nbmq1", + "col325": "8qxvh", + "col326": "tmt5l", + "col327": "9erlr", + "col328": "gr46v", + "col329": "u2a5f", + "col330": "n4lxx", + "col331": "mvciz", + "col332": "qrkz9", + "col333": "qpon1", + "col334": "v5wcr", + "col335": "ccqbj", + "col336": "92hef", + "col337": "41ewg", + "col338": "1wkqf", + "col339": "ko6fe", + "col340": "8klp4", + "col341": "ic1sz", + "col342": "17mp3", + "col343": "o40o6", + "col344": "2b6em", + "col345": "80tgd", + "col346": "ejckh", + "col347": "1rgaz", + "col348": "qr0t4", + "col349": "wsgc8", + "col350": "2w1tl", + "col351": "2r9f0", + "col352": "qpy0u", + "col353": "hmca7", + "col354": "tap33", + "col355": "mbqwr", + "col356": "r7ah4", + "col357": "s31uy", + "col358": "wtuem", + "col359": "lweqj", + "col360": "sdpeo", + "col361": "85p36", + "col362": "jm9a8", + "col363": "d2e19", + "col364": "07wax", + "col365": "7ngel", + "col366": "40y4n", + "col367": "nieil", + "col368": "efxcn", + "col369": "f4qqc", + "col370": "ut4mj", + "col371": "i7oll", + "col372": "sm97i", + "col373": "kw1qu", + "col374": "9zmxe", + "col375": "p2a0o", + "col376": "zh11n", + "col377": "cs3uy", + "col378": "ay0jh", + "col379": "2d6ky", + "col380": "p7kcz", + "col381": "nftal", + "col382": "weard", + "col383": "k0u9s", + "col384": "o5wyx", + "col385": "u5hxb", + "col386": "dq8x5", + "col387": "cknt8", + "col388": "i91g6", + "col389": "8oeoh", + "col390": "shs9z", + "col391": "k8b3e", + "col392": "c7v33", + "col393": "j42un", + "col394": "zpc6v", + "col395": "cff0i", + "col396": "seco7", + "col397": "kae6d", + "col398": "67y61", + "col399": "v0dny", + "col400": "6lu8c", + "col401": "jf2og", + "col402": "2gcub", + "col403": "l4jb6", + "col404": "lh1n6", + "col405": "4d67r", + "col406": "mpolw", + "col407": "eu85p", + "col408": "b1k3a", + "col409": "5khg3", + "col410": "yqz6r", + "col411": "hbayz", + "col412": "i1sk5", + "col413": "87uz2", + "col414": "ksy22", + "col415": "tydnw", + "col416": "bs67o", + "col417": "zizmr", + "col418": "9v0tp", + "col419": "ze0q9", + "col420": "zu2kx", + "col421": "o1hlj", + "col422": "i4jb4", + "col423": "4pfiy", + "col424": "22mdx", + "col425": "ouo0p", + "col426": "fqxh9", + "col427": "wzcpt", + "col428": "0xf6r", + "col429": "1s8ar", + "col430": "uyz9o", + "col431": "f7eg6", + "col432": "sdz0g", + "col433": "vai00", + "col434": "cgpa1", + "col435": "y4iro", + "col436": "dedia", + "col437": "t1qdd", + "col438": "hmasw", + "col439": "ew2e5", + "col440": "23r23", + "col441": "0dvll", + "col442": "zf4ic", + "col443": "lt7ct", + "col444": "jmg4f", + "col445": "3d4q6", + "col446": "z016m", + "col447": "9bpcx", + "col448": "7whjx", + "col449": "vt78w", + "col450": "pzc31", + "col451": "pxsbp", + "col452": "uv6gl", + "col453": "so66p", + "col454": "skubi", + "col455": "f7g1e", + "col456": "5wrf8", + "col457": "v9dpn", + "col458": "u4isa", + "col459": "ze2iw", + "col460": "pk8bh", + "col461": "nnmte", + "col462": "9rnpd", + "col463": "54po3", + "col464": "ld0cq", + "col465": "3crd5", + "col466": "le4p8", + "col467": "zvj6i", + "col468": "ct9hm", + "col469": "yt34v", + "col470": "lrcss", + "col471": "wuu29", + "col472": "kj1m5", + "col473": "ue4y7", + "col474": "9okvn", + "col475": "rn6tu", + "col476": "0q0m8", + "col477": "np7v5", + "col478": "cziym", + "col479": "1tmc2", + "col480": "timqs", + "col481": "yh5oh", + "col482": "e6ikt", + "col483": "5og8b", + "col484": "tnysc", + "col485": "1bm6y", + "col486": "xuyp0", + "col487": "r4f4m", + "col488": "y9vge", + "col489": "k4lgu", + "col490": "yr0dz", + "col491": "trogx", + "col492": "9g99v", + "col493": "so5tu", + "col494": "46bz9", + "col495": "nm7us", + "col496": "b4pf9", + "col497": "1khy1", + "col498": "4majk", + "col499": "fkzbd", + "col500": "ey5fn", + "col501": "amfqp", + "col502": "ccsqp", + "col503": "2gzat", + "col504": "ivf9k", + "col505": "axbyg", + "col506": "7q8o8", + "col507": "8a766", + "col508": "lwany", + "col509": "1glew", + "col510": "05zlo", + "col511": "iopyh", + "col512": "42b0k", + "col513": "6ps9v", + "col514": "dh36e", + "col515": "8hoxy", + "col516": "1qgdn", + "col517": "3q6r1", + "col518": "wi9ts", + "col519": "b2txy", + "col520": "9xaw5", + "col521": "icskb", + "col522": "9lss8", + "col523": "fhj1q", + "col524": "5bbxa", + "col525": "93mye", + "col526": "nbh9v", + "col527": "o0mt7", + "col528": "2guge", + "col529": "gbydn", + "col530": "4rtdx", + "col531": "x5bj3", + "col532": "crop7", + "col533": "zkxqk", + "col534": "jbh7c", + "col535": "m6sr2", + "col536": "40xtn", + "col537": "mjnqq", + "col538": "i9y3m", + "col539": "2olld", + "col540": "5f2qk", + "col541": "pmmus", + "col542": "zytmv", + "col543": "ndlwq", + "col544": "73qa3", + "col545": "nhduf", + "col546": "uu1n0", + "col547": "ob84h", + "col548": "d7z1g", + "col549": "1kat4", + "col550": "fc43a", + "col551": "9p61u", + "col552": "t1okp", + "col553": "cfqoo", + "col554": "pku22", + "col555": "ohw61", + "col556": "uis8a", + "col557": "b7ev7", + "col558": "lk7am", + "col559": "ils9j", + "col560": "5h2q4", + "col561": "7efvj", + "col562": "2trsz", + "col563": "ltgrf", + "col564": "kh8ss", + "col565": "xyn4q", + "col566": "jxuzh", + "col567": "iemm7", + "col568": "aro3t", + "col569": "wr47n", + "col570": "as3he", + "col571": "32juq", + "col572": "n0ce1", + "col573": "26vu6", + "col574": "uk70u", + "col575": "7p1ue", + "col576": "52byp", + "col577": "rpv9z", + "col578": "93qnx", + "col579": "fa4g0", + "col580": "l1wxu", + "col581": "c02ki", + "col582": "im9ue", + "col583": "rpnp4", + "col584": "kiaki", + "col585": "50n9w", + "col586": "8ll8i", + "col587": "6u00x", + "col588": "2sp91", + "col589": "9l7a4", + "col590": "d2orj", + "col591": "3zm5y", + "col592": "5ip9n", + "col593": "ihkdg", + "col594": "hyn2q", + "col595": "ggmty", + "col596": "okak9", + "col597": "l1oyx", + "col598": "um081", + "col599": "bboes", + "col600": "8ry22", + "col601": "t6v3h", + "col602": "1hyib", + "col603": "5s10v", + "col604": "gzgt8", + "col605": "9eyqi", + "col606": "5lq2e", + "col607": "dnfwa", + "col608": "xsncb", + "col609": "d67eq", + "col610": "nekhh", + "col611": "jkpmi", + "col612": "0f2qs", + "col613": "x27cq", + "col614": "pj39r", + "col615": "td9jw", + "col616": "ux3cb", + "col617": "l8qoq", + "col618": "kugp8", + "col619": "ueto7", + "col620": "w2hn0", + "col621": "vg2mp", + "col622": "wqdsw", + "col623": "k7kbe", + "col624": "uh6f7", + "col625": "rgtqn", + "col626": "0z9ll", + "col627": "2rlv7", + "col628": "3ewsj", + "col629": "a8hb5", + "col630": "14x55", + "col631": "w9dm5", + "col632": "0xqv8", + "col633": "d5yef", + "col634": "9bfzu", + "col635": "6xgkv", + "col636": "ljtir", + "col637": "lr6qz", + "col638": "fuagt", + "col639": "qfzwq", + "col640": "9tdj1", + "col641": "u8nvt", + "col642": "kulay", + "col643": "g4lya", + "col644": "2bla7", + "col645": "amgvb", + "col646": "vf601", + "col647": "5f2nc", + "col648": "g2qv9", + "col649": "81of0", + "col650": "fhi43", + "col651": "arl2a", + "col652": "je2a0", + "col653": "ksf5u", + "col654": "1i87d", + "col655": "4zbun", + "col656": "8w296", + "col657": "du75k", + "col658": "t5q5t", + "col659": "6rios", + "col660": "r8l3d", + "col661": "33ivl", + "col662": "cxmwa", + "col663": "6z0uw", + "col664": "q1kwj", + "col665": "w8zv2", + "col666": "y17hn", + "col667": "14yo2", + "col668": "itjfz", + "col669": "fk7cq", + "col670": "py6k2", + "col671": "p9cop", + "col672": "xem9k", + "col673": "nk69i", + "col674": "gusyk", + "col675": "iz3ku", + "col676": "wixs1", + "col677": "7ij6i", + "col678": "cpmw6", + "col679": "sip7l", + "col680": "7k502", + "col681": "2j4r1", + "col682": "vn26q", + "col683": "ep2p3", + "col684": "39n25", + "col685": "7jnyw", + "col686": "e479w", + "col687": "gs6la", + "col688": "ndf3u", + "col689": "9dmbu", + "col690": "ldbqp", + "col691": "3ksib", + "col692": "tju09", + "col693": "jc4u5", + "col694": "jcr0n", + "col695": "15wyf", + "col696": "p5pfe", + "col697": "y00mg", + "col698": "9rmw1", + "col699": "i1wur", + "col700": "xpu3t", + "col701": "1g5j8", + "col702": "3ngb9", + "col703": "v5nlk", + "col704": "4dm26", + "col705": "z9e2t", + "col706": "zj7sz", + "col707": "opice", + "col708": "7acs8", + "col709": "3c87y", + "col710": "6uikj", + "col711": "q8fcg", + "col712": "2c5y2", + "col713": "bijnr", + "col714": "c198l", + "col715": "67vcv", + "col716": "b5698", + "col717": "glr0j", + "col718": "0ax93", + "col719": "tw1x8", + "col720": "744d4", + "col721": "ax5n3", + "col722": "c2mkb", + "col723": "c55cd", + "col724": "jptq9", + "col725": "mlj5f", + "col726": "cmkd1", + "col727": "9tuiy", + "col728": "ucknx", + "col729": "0pf16", + "col730": "jq0zq", + "col731": "mowde", + "col732": "tjfuc", + "col733": "9svmu", + "col734": "9kslf", + "col735": "k8jpl", + "col736": "8hnao", + "col737": "eizlo", + "col738": "r6cta", + "col739": "22ci2", + "col740": "9hvn2", + "col741": "8i84k", + "col742": "dr6id", + "col743": "ctf5e", + "col744": "fzyno", + "col745": "m91ic", + "col746": "ve4kn", + "col747": "38zb0", + "col748": "iderl", + "col749": "uwrx2", + "col750": "lndud", + "col751": "48l4o", + "col752": "5jyyg", + "col753": "7y73z", + "col754": "mgwvt", + "col755": "una6p", + "col756": "64qgy", + "col757": "rspks", + "col758": "etpqc", + "col759": "3h9js", + "col760": "6nwa8", + "col761": "8a3m6", + "col762": "jyked", + "col763": "f3ybh", + "col764": "qu93l", + "col765": "lo5yq", + "col766": "h07xo", + "col767": "lv0ge", + "col768": "peny5", + "col769": "mcwiz", + "col770": "h8uyq", + "col771": "e02nf", + "col772": "x2ivj", + "col773": "9x3mo", + "col774": "ip1w4", + "col775": "sejov", + "col776": "lxvgo", + "col777": "vi00l", + "col778": "bhk27", + "col779": "n5gks", + "col780": "9s4ue", + "col781": "dywfy", + "col782": "maluh", + "col783": "bq622", + "col784": "f1iwj", + "col785": "6dtah", + "col786": "za37z", + "col787": "xapw0", + "col788": "vfy03", + "col789": "1blq9", + "col790": "48r29", + "col791": "5oh65", + "col792": "0xke1", + "col793": "a009y", + "col794": "99stb", + "col795": "btqq3", + "col796": "7a7ny", + "col797": "e1415", + "col798": "osp5t", + "col799": "fsehe", + "col800": "4p424", + "col801": "pu6eq", + "col802": "qjr8b", + "col803": "z7n9j", + "col804": "n9p30", + "col805": "wxdf0", + "col806": "ca09t", + "col807": "sd2nj", + "col808": "as2l9", + "col809": "4cugd", + "col810": "5n0rq", + "col811": "8agi6", + "col812": "4fdyg", + "col813": "w9y1g", + "col814": "dccq8", + "col815": "55wc8", + "col816": "hmxrp", + "col817": "s0q9r", + "col818": "58x09", + "col819": "ufokp", + "col820": "1dlkq", + "col821": "rbwdq", + "col822": "l0mz0", + "col823": "8ek50", + "col824": "thou8", + "col825": "bliy4", + "col826": "aquxc", + "col827": "mu7e0", + "col828": "h4niz", + "col829": "ijp5r", + "col830": "k8xl0", + "col831": "1mo4k", + "col832": "2tzfj", + "col833": "521o7", + "col834": "ny3yj", + "col835": "nm1ni", + "col836": "pwpfd", + "col837": "s66ho", + "col838": "fzg3c", + "col839": "u3nqa", + "col840": "nzep7", + "col841": "42933", + "col842": "o47re", + "col843": "qgonh", + "col844": "6tj6a", + "col845": "3texx", + "col846": "bjzlm", + "col847": "a50zr", + "col848": "dbq0k", + "col849": "lv20b", + "col850": "teend", + "col851": "02vfg", + "col852": "63bmk", + "col853": "5np3v", + "col854": "dibyd", + "col855": "2lszr", + "col856": "0b17j", + "col857": "e7n72", + "col858": "9v33i", + "col859": "xlhxk", + "col860": "1xr3e", + "col861": "1lt7f", + "col862": "lk8bn", + "col863": "xhud1", + "col864": "k8byc", + "col865": "k9tox", + "col866": "qt99z", + "col867": "4a6ob", + "col868": "kim8s", + "col869": "46j2k", + "col870": "srysk", + "col871": "ubzmo", + "col872": "xvlgp", + "col873": "4t8tf", + "col874": "jt2wt", + "col875": "d8ns7", + "col876": "k3jjs", + "col877": "igbvv", + "col878": "45x2z", + "col879": "uzsx7", + "col880": "ki7y6", + "col881": "luv2w", + "col882": "d2bbe", + "col883": "2kws7", + "col884": "li7z2", + "col885": "ol4xv", + "col886": "mxu0a", + "col887": "5ycwt", + "col888": "0174k", + "col889": "0be1z", + "col890": "e67fw", + "col891": "75kqf", + "col892": "aw1ep", + "col893": "ck5bs", + "col894": "q1nvh", + "col895": "ykvtc", + "col896": "4u8c6", + "col897": "acxci", + "col898": "cyad2", + "col899": "g8ln8", + "col900": "auxdg", + "col901": "bf1e4", + "col902": "6rj1m", + "col903": "1cjhl", + "col904": "l7fzk", + "col905": "d6589", + "col906": "usta1", + "col907": "62zjn", + "col908": "60mes", + "col909": "q4urr", + "col910": "lah94", + "col911": "ssdos", + "col912": "1f8e0", + "col913": "9evpz", + "col914": "24r3t", + "col915": "k6yt4", + "col916": "2xfvo", + "col917": "0bcp5", + "col918": "3au7l", + "col919": "bczg5", + "col920": "ponqg", + "col921": "uvqmm", + "col922": "qo93v", + "col923": "3myng", + "col924": "arx8h", + "col925": "1pk31", + "col926": "33tdx", + "col927": "kryiv", + "col928": "4omqd", + "col929": "2bplr", + "col930": "j41yx", + "col931": "5cask", + "col932": "xyfcl", + "col933": "puon0", + "col934": "f7rgd", + "col935": "46p5k", + "col936": "x37pp", + "col937": "b1qlk", + "col938": "81xc1", + "col939": "t1mdu", + "col940": "cufwj", + "col941": "i582u", + "col942": "ldfn6", + "col943": "wr6ei", + "col944": "1ymyp", + "col945": "04fa1", + "col946": "mvbzg", + "col947": "rvorm", + "col948": "qk0sx", + "col949": "h91p7", + "col950": "xiesl", + "col951": "4k1v0", + "col952": "jnag1", + "col953": "vnvp7", + "col954": "6jinx", + "col955": "pnz2i", + "col956": "78jwj", + "col957": "pb4wr", + "col958": "y33tb", + "col959": "lspy5", + "col960": "hswbo", + "col961": "4wdpr", + "col962": "78lqh", + "col963": "ojdum", + "col964": "h7odx", + "col965": "qux7y", + "col966": "61oo2", + "col967": "qfkgx", + "col968": "x8k2i", + "col969": "wfsga", + "col970": "uhi1i", + "col971": "twwj2", + "col972": "rp2uv", + "col973": "ix9sq", + "col974": "5f9gk", + "col975": "f08ix", + "col976": "06g08", + "col977": "bd85i", + "col978": "3rv2k", + "col979": "jdiyo", + "col980": "xb9tp", + "col981": "u3omp", + "col982": "stdqn", + "col983": "9agzt", + "col984": "lszsi", + "col985": "exzym", + "col986": "7fnh2", + "col987": "as89b", + "col988": "rrkf2", + "col989": "oztor", + "col990": "n4xct", + "col991": "elulk", + "col992": "d8cd2", + "col993": "zjalr", + "col994": "6skha", + "col995": "fzr23", + "col996": "x7re3", + "col997": "wezlr", + "col998": "91qlh", + "col999": "y8owl" + }, + { + "name": "Goldie Haney", + "gender": "female", + "col0": "mbhem", + "col1": "9gwzx", + "col2": "xu46d", + "col3": "trw40", + "col4": "6ld1g", + "col5": "wogak", + "col6": "z2u21", + "col7": "cvsih", + "col8": "nelro", + "col9": "l4vre", + "col10": "2wczt", + "col11": "gz71b", + "col12": "r52xi", + "col13": "5ttfz", + "col14": "p0j2i", + "col15": "pwk5l", + "col16": "uar0d", + "col17": "1sphn", + "col18": "74cch", + "col19": "zm5w1", + "col20": "fj477", + "col21": "ik60k", + "col22": "b7r9z", + "col23": "nx7z1", + "col24": "90i3f", + "col25": "3yx8w", + "col26": "25vxz", + "col27": "rdawc", + "col28": "dwr69", + "col29": "26suh", + "col30": "1aeeu", + "col31": "ux4k3", + "col32": "f1y5c", + "col33": "vmcrn", + "col34": "yecii", + "col35": "vxfan", + "col36": "ix3sn", + "col37": "qrw73", + "col38": "b8dk0", + "col39": "fvz7g", + "col40": "1t2ey", + "col41": "h73ks", + "col42": "ptpa0", + "col43": "cnpek", + "col44": "lxjvg", + "col45": "s2mfe", + "col46": "t1hug", + "col47": "k5vhd", + "col48": "ycyvs", + "col49": "hmjy5", + "col50": "femsf", + "col51": "s3a8l", + "col52": "diqq3", + "col53": "8o3mj", + "col54": "aklcq", + "col55": "d3p53", + "col56": "75x7m", + "col57": "6920c", + "col58": "simip", + "col59": "bn7sn", + "col60": "n4m8i", + "col61": "a7fu8", + "col62": "x2lyf", + "col63": "s2gby", + "col64": "7x6yh", + "col65": "5rry7", + "col66": "wa9bz", + "col67": "ee814", + "col68": "dbiie", + "col69": "i4iuw", + "col70": "wp3p1", + "col71": "ek27d", + "col72": "px6xw", + "col73": "ol6nz", + "col74": "kskqi", + "col75": "lan41", + "col76": "pk9th", + "col77": "1ahg6", + "col78": "vju7k", + "col79": "d9obo", + "col80": "ackyu", + "col81": "emgrt", + "col82": "9dna0", + "col83": "5ikoh", + "col84": "6o6bu", + "col85": "vc457", + "col86": "5napb", + "col87": "cc97j", + "col88": "kkrtj", + "col89": "23lfg", + "col90": "s10er", + "col91": "mjbq2", + "col92": "u6exk", + "col93": "14d2s", + "col94": "h5v7w", + "col95": "9etd8", + "col96": "mg2l6", + "col97": "1bjqp", + "col98": "99hhd", + "col99": "ns9l1", + "col100": "0ma5a", + "col101": "51bw0", + "col102": "udexk", + "col103": "1hxcy", + "col104": "m15gb", + "col105": "daxtv", + "col106": "jo7oc", + "col107": "xpxdv", + "col108": "05y00", + "col109": "xkho7", + "col110": "osxp1", + "col111": "q5rsf", + "col112": "a80j9", + "col113": "g2fej", + "col114": "b7t1t", + "col115": "ywlet", + "col116": "xzb7s", + "col117": "noeby", + "col118": "7kz7i", + "col119": "uwy2k", + "col120": "lx9ou", + "col121": "914y7", + "col122": "n7cse", + "col123": "t6n1h", + "col124": "amw98", + "col125": "nnw86", + "col126": "24rl1", + "col127": "88pl9", + "col128": "a3jrg", + "col129": "y0hza", + "col130": "201s7", + "col131": "bky5k", + "col132": "fwv2f", + "col133": "lli6w", + "col134": "01mka", + "col135": "okahy", + "col136": "6fjb4", + "col137": "w5jh0", + "col138": "mk6vm", + "col139": "f0toq", + "col140": "25t3u", + "col141": "0c6d5", + "col142": "k9uwp", + "col143": "ad0ef", + "col144": "bd88n", + "col145": "gnh3w", + "col146": "9n45o", + "col147": "v4yvr", + "col148": "1bc5p", + "col149": "eahgn", + "col150": "y01h6", + "col151": "kxdur", + "col152": "xi64d", + "col153": "0npq5", + "col154": "gcesk", + "col155": "j4sxk", + "col156": "zp6zk", + "col157": "vqiue", + "col158": "ljyv4", + "col159": "gwcm6", + "col160": "9cr1a", + "col161": "9woyj", + "col162": "c9uso", + "col163": "b4slp", + "col164": "k4exm", + "col165": "blmb1", + "col166": "x87bh", + "col167": "mlsfw", + "col168": "7wg5a", + "col169": "af4vp", + "col170": "h076w", + "col171": "h2zc0", + "col172": "quosx", + "col173": "m126z", + "col174": "8p0h8", + "col175": "4625d", + "col176": "t1q78", + "col177": "sglar", + "col178": "n3pka", + "col179": "g55vk", + "col180": "q4a2i", + "col181": "5yqpn", + "col182": "lo7hl", + "col183": "7t4pk", + "col184": "5smws", + "col185": "axips", + "col186": "7d5sh", + "col187": "ncp8r", + "col188": "wzzaw", + "col189": "7s7v7", + "col190": "xnlem", + "col191": "2wxb9", + "col192": "7mw6x", + "col193": "e8dl0", + "col194": "0prog", + "col195": "uypb4", + "col196": "yaypj", + "col197": "zs0m3", + "col198": "18k35", + "col199": "49vcr", + "col200": "4b6vg", + "col201": "3pvo8", + "col202": "93gai", + "col203": "4j7eg", + "col204": "sa0of", + "col205": "y9vob", + "col206": "rz4qj", + "col207": "bf3n5", + "col208": "y4cyw", + "col209": "hcs6h", + "col210": "4nuv3", + "col211": "ydh9c", + "col212": "7880b", + "col213": "zgfd6", + "col214": "zp25w", + "col215": "hy4ne", + "col216": "ottts", + "col217": "s31fi", + "col218": "on140", + "col219": "leo2v", + "col220": "gfg90", + "col221": "u8x5p", + "col222": "p3uyk", + "col223": "w23xq", + "col224": "bq2y4", + "col225": "imrih", + "col226": "j1soy", + "col227": "011hb", + "col228": "n9rbb", + "col229": "m90i0", + "col230": "qredl", + "col231": "0o7xr", + "col232": "sgmj6", + "col233": "ocyfo", + "col234": "vvg8o", + "col235": "abdzl", + "col236": "jijp7", + "col237": "8mk0q", + "col238": "b9npi", + "col239": "pbao9", + "col240": "zzddb", + "col241": "8tegz", + "col242": "fbnku", + "col243": "ef40m", + "col244": "i8yk9", + "col245": "fy595", + "col246": "mvxrq", + "col247": "rutgc", + "col248": "vykgb", + "col249": "5pm94", + "col250": "3xsu8", + "col251": "cmj05", + "col252": "kjvgo", + "col253": "3fdng", + "col254": "u27kb", + "col255": "f9f61", + "col256": "235nt", + "col257": "dblxg", + "col258": "1a0mq", + "col259": "5qr20", + "col260": "p0tlu", + "col261": "txr7v", + "col262": "37grq", + "col263": "632r0", + "col264": "rkgrh", + "col265": "037sa", + "col266": "18orx", + "col267": "g1fb8", + "col268": "zx8h5", + "col269": "76j9w", + "col270": "zs4hd", + "col271": "6zumy", + "col272": "oi4l5", + "col273": "4av46", + "col274": "6672t", + "col275": "js9yj", + "col276": "5lqs7", + "col277": "j1ty5", + "col278": "82r35", + "col279": "nd6v1", + "col280": "tmqi9", + "col281": "ua0no", + "col282": "rfyet", + "col283": "orauz", + "col284": "ydrv0", + "col285": "vxye3", + "col286": "absio", + "col287": "9b09w", + "col288": "orf4j", + "col289": "rl7fu", + "col290": "j7748", + "col291": "gufpj", + "col292": "tmoi3", + "col293": "8dudj", + "col294": "n0b34", + "col295": "15wz4", + "col296": "3lcjn", + "col297": "11oo3", + "col298": "z7puv", + "col299": "ru5bx", + "col300": "flwbq", + "col301": "cn7kn", + "col302": "1ph4i", + "col303": "okihr", + "col304": "9b3ar", + "col305": "eg7xf", + "col306": "nmgdm", + "col307": "vgt6p", + "col308": "j6qog", + "col309": "vj616", + "col310": "0z6oo", + "col311": "zr0pm", + "col312": "rjwmx", + "col313": "pce2d", + "col314": "41qcg", + "col315": "d09wq", + "col316": "zc7wg", + "col317": "utd60", + "col318": "va3r0", + "col319": "hhcqa", + "col320": "v46ie", + "col321": "vhijh", + "col322": "f3qxp", + "col323": "hlnkv", + "col324": "nu030", + "col325": "ra08t", + "col326": "klu4s", + "col327": "y9bxw", + "col328": "6tl8n", + "col329": "xlftb", + "col330": "1yg7u", + "col331": "5gyle", + "col332": "707c6", + "col333": "z5wrx", + "col334": "v4lpq", + "col335": "q6sz1", + "col336": "oxdgd", + "col337": "4jcuo", + "col338": "nfcvs", + "col339": "1q9ty", + "col340": "pjxqw", + "col341": "rs3m4", + "col342": "s1zcw", + "col343": "ieqan", + "col344": "nu9jb", + "col345": "8z1n5", + "col346": "k9v1x", + "col347": "1v0wo", + "col348": "0rqnb", + "col349": "5pofl", + "col350": "udjd0", + "col351": "nehsz", + "col352": "z9yhx", + "col353": "xw56w", + "col354": "p7h9c", + "col355": "i1joo", + "col356": "ttee7", + "col357": "z0g83", + "col358": "vke6t", + "col359": "872no", + "col360": "fotq9", + "col361": "j92yo", + "col362": "co5qz", + "col363": "ty50l", + "col364": "pjaqv", + "col365": "3b7dz", + "col366": "e1u4e", + "col367": "o6dfk", + "col368": "sapio", + "col369": "l1586", + "col370": "a4gyl", + "col371": "mwyfp", + "col372": "0nv4v", + "col373": "j6nhg", + "col374": "drvpp", + "col375": "n1cf1", + "col376": "kmg6g", + "col377": "k8t97", + "col378": "qj3oo", + "col379": "gdd5c", + "col380": "bokui", + "col381": "mgak4", + "col382": "qyc1v", + "col383": "b04ns", + "col384": "is5g8", + "col385": "fllu8", + "col386": "v5rig", + "col387": "vxqs6", + "col388": "1zv7z", + "col389": "g44t4", + "col390": "cb99r", + "col391": "vi0sd", + "col392": "0ekkh", + "col393": "bhcbs", + "col394": "8ou4s", + "col395": "bcxvy", + "col396": "x2mog", + "col397": "cgsgg", + "col398": "q84vs", + "col399": "2cxgd", + "col400": "ufmol", + "col401": "0kl6k", + "col402": "04fcc", + "col403": "6k27y", + "col404": "bkdwb", + "col405": "fqdoe", + "col406": "2qdt4", + "col407": "s69la", + "col408": "657d1", + "col409": "q1re1", + "col410": "fzxpo", + "col411": "xgvmx", + "col412": "hf6u2", + "col413": "sizys", + "col414": "x02kx", + "col415": "3c5ar", + "col416": "1gxyq", + "col417": "gm1de", + "col418": "96ur1", + "col419": "6lt7x", + "col420": "kv036", + "col421": "5yvuv", + "col422": "axw8l", + "col423": "zozcd", + "col424": "m0p2j", + "col425": "ivow5", + "col426": "vc50i", + "col427": "6jj4a", + "col428": "c5qdj", + "col429": "2u1ch", + "col430": "23t35", + "col431": "m49aw", + "col432": "ntlic", + "col433": "6558v", + "col434": "fnzjv", + "col435": "folep", + "col436": "lfive", + "col437": "qyuv9", + "col438": "4n2d2", + "col439": "alpq5", + "col440": "n6lsr", + "col441": "86wxe", + "col442": "igqzj", + "col443": "llgsz", + "col444": "95ins", + "col445": "gyoht", + "col446": "jwngr", + "col447": "3bwlz", + "col448": "6b4hs", + "col449": "8xg1s", + "col450": "9e5wm", + "col451": "stxb7", + "col452": "bmjza", + "col453": "q0d77", + "col454": "ju0mc", + "col455": "mx45v", + "col456": "vqv3l", + "col457": "dnf1p", + "col458": "ii1wf", + "col459": "wl1tl", + "col460": "iz7e4", + "col461": "a2x8s", + "col462": "8tk6n", + "col463": "dw7i6", + "col464": "ev7gb", + "col465": "j0hs1", + "col466": "n0569", + "col467": "e9cou", + "col468": "7wij7", + "col469": "pnrc1", + "col470": "7pn6t", + "col471": "ocqmc", + "col472": "58nbm", + "col473": "9fla8", + "col474": "9kky1", + "col475": "a6wcq", + "col476": "pbxiy", + "col477": "6xbm3", + "col478": "1segy", + "col479": "rj3w7", + "col480": "dqtyr", + "col481": "jycy8", + "col482": "46k60", + "col483": "5607p", + "col484": "j8eb3", + "col485": "py3jt", + "col486": "c3iff", + "col487": "8f9gc", + "col488": "0r72a", + "col489": "in0yk", + "col490": "2hc7n", + "col491": "jnr8j", + "col492": "jzklb", + "col493": "b5bvx", + "col494": "b6ecy", + "col495": "zuapr", + "col496": "x4e8r", + "col497": "g0sdn", + "col498": "ch3vc", + "col499": "w6q4u", + "col500": "h0ky5", + "col501": "sukfz", + "col502": "dgtyz", + "col503": "kn618", + "col504": "ixhwa", + "col505": "a0trx", + "col506": "erysy", + "col507": "za9x7", + "col508": "72i9y", + "col509": "dyjr1", + "col510": "uwcfs", + "col511": "82aey", + "col512": "wqwwa", + "col513": "z7s88", + "col514": "d80ky", + "col515": "3qiog", + "col516": "tq82l", + "col517": "qkare", + "col518": "vv0nk", + "col519": "ojbn4", + "col520": "9w3yc", + "col521": "obj94", + "col522": "vifx2", + "col523": "w18qv", + "col524": "8vds1", + "col525": "1lb7m", + "col526": "tkjup", + "col527": "wori0", + "col528": "c1t0k", + "col529": "7oqmb", + "col530": "z828i", + "col531": "9f7dm", + "col532": "272v5", + "col533": "o62sy", + "col534": "kxpxs", + "col535": "lehpj", + "col536": "pj3w1", + "col537": "nlw65", + "col538": "i1s51", + "col539": "3b9c9", + "col540": "yjrwm", + "col541": "9vrsh", + "col542": "pke10", + "col543": "6etfl", + "col544": "g0s7b", + "col545": "hkplc", + "col546": "csikh", + "col547": "5rknq", + "col548": "q7l0i", + "col549": "2f09z", + "col550": "gxiqx", + "col551": "jddo3", + "col552": "xp5oy", + "col553": "s2c4x", + "col554": "4tbjl", + "col555": "pps0x", + "col556": "1qz9t", + "col557": "mj2kb", + "col558": "ff28z", + "col559": "gpz5e", + "col560": "d09kw", + "col561": "vcgzf", + "col562": "3xxve", + "col563": "dvuaf", + "col564": "4fm2l", + "col565": "g6a11", + "col566": "2028v", + "col567": "0px6f", + "col568": "xce8i", + "col569": "2m2r8", + "col570": "fs4g3", + "col571": "4hs92", + "col572": "he5am", + "col573": "a0mn7", + "col574": "g31el", + "col575": "ieilx", + "col576": "0iufv", + "col577": "5xd4s", + "col578": "odcm9", + "col579": "acdbh", + "col580": "csnfj", + "col581": "c1tb7", + "col582": "i2b4y", + "col583": "fq87e", + "col584": "yr4j2", + "col585": "tbdul", + "col586": "8duv4", + "col587": "adhax", + "col588": "9i4a1", + "col589": "cdas2", + "col590": "13pnr", + "col591": "ux05r", + "col592": "3bmk9", + "col593": "mw1j1", + "col594": "u4kqe", + "col595": "yp65v", + "col596": "93dwo", + "col597": "wh2z5", + "col598": "zqa2p", + "col599": "jx820", + "col600": "vqa85", + "col601": "raegp", + "col602": "kz86z", + "col603": "vn6fl", + "col604": "pmryb", + "col605": "6eum9", + "col606": "cnt48", + "col607": "9rihu", + "col608": "sw98f", + "col609": "o3izu", + "col610": "62gi4", + "col611": "06rxa", + "col612": "71lqo", + "col613": "vduql", + "col614": "4zo76", + "col615": "la0m8", + "col616": "xzkzi", + "col617": "sy9mg", + "col618": "86otn", + "col619": "xl0pb", + "col620": "hl2pe", + "col621": "vs46z", + "col622": "o4z4v", + "col623": "zjpyn", + "col624": "244d4", + "col625": "9bxab", + "col626": "5ardq", + "col627": "1s7qs", + "col628": "m5hw4", + "col629": "5ld7d", + "col630": "y376l", + "col631": "71c1i", + "col632": "3ai44", + "col633": "2iqln", + "col634": "akc18", + "col635": "owbpr", + "col636": "4t392", + "col637": "ty2b4", + "col638": "ftbjx", + "col639": "9whfh", + "col640": "y8v6t", + "col641": "9wxsd", + "col642": "j49p7", + "col643": "jwrwh", + "col644": "x6eja", + "col645": "ows1x", + "col646": "fxwpq", + "col647": "n73yb", + "col648": "0833q", + "col649": "nsmyk", + "col650": "gcdgw", + "col651": "301e1", + "col652": "i69wg", + "col653": "x7jsb", + "col654": "75p7n", + "col655": "zelk2", + "col656": "76z19", + "col657": "rx327", + "col658": "1fxvt", + "col659": "75bjt", + "col660": "2f2xy", + "col661": "vown9", + "col662": "6a49e", + "col663": "79wjl", + "col664": "pzscr", + "col665": "5hpy7", + "col666": "z4x2o", + "col667": "1uc68", + "col668": "egphh", + "col669": "x11vv", + "col670": "7c5az", + "col671": "0nfde", + "col672": "6mtwo", + "col673": "2y693", + "col674": "7xedj", + "col675": "677vj", + "col676": "l6uef", + "col677": "cau6c", + "col678": "s33ie", + "col679": "6v39v", + "col680": "xpuyz", + "col681": "3ciuc", + "col682": "zu4fx", + "col683": "97yth", + "col684": "vkdbb", + "col685": "3ij0v", + "col686": "y7q0m", + "col687": "9h67k", + "col688": "q5ieb", + "col689": "qzlu3", + "col690": "1fdjn", + "col691": "m8brq", + "col692": "8eq27", + "col693": "aiz7f", + "col694": "20mdb", + "col695": "i5tky", + "col696": "x4jgf", + "col697": "oetru", + "col698": "782qj", + "col699": "vwl32", + "col700": "tac4o", + "col701": "ungvo", + "col702": "svp88", + "col703": "3dldn", + "col704": "szsci", + "col705": "ql4cw", + "col706": "3o6sq", + "col707": "3iqx1", + "col708": "ntym8", + "col709": "o7wor", + "col710": "ogypa", + "col711": "oqd1s", + "col712": "jqu9k", + "col713": "t0cdt", + "col714": "qppdf", + "col715": "zxwdz", + "col716": "sb2tb", + "col717": "wimx6", + "col718": "8klt2", + "col719": "6kxyo", + "col720": "qyh2h", + "col721": "xba0j", + "col722": "3qsk1", + "col723": "obwbz", + "col724": "cwrvi", + "col725": "arhzb", + "col726": "pfg81", + "col727": "zoars", + "col728": "3rc53", + "col729": "kjv4x", + "col730": "yg1jo", + "col731": "kjypa", + "col732": "m22c6", + "col733": "4tlxw", + "col734": "4n5a9", + "col735": "im91x", + "col736": "0kfep", + "col737": "gzy5l", + "col738": "ogxgv", + "col739": "a6679", + "col740": "5jol7", + "col741": "ggcjv", + "col742": "4i0po", + "col743": "p0hxx", + "col744": "ah709", + "col745": "qpkki", + "col746": "1j0kz", + "col747": "m6f62", + "col748": "rq5bf", + "col749": "my6ph", + "col750": "4zysa", + "col751": "uic7y", + "col752": "oe5c3", + "col753": "54zbx", + "col754": "gy41v", + "col755": "x9ebv", + "col756": "6ttgz", + "col757": "esbdg", + "col758": "1kzu1", + "col759": "piwu9", + "col760": "ppf73", + "col761": "wt3lt", + "col762": "zt0rw", + "col763": "w70ta", + "col764": "f100t", + "col765": "an0xc", + "col766": "4kbgd", + "col767": "cb1m3", + "col768": "eyjj9", + "col769": "mxnv0", + "col770": "fwwet", + "col771": "c7tsk", + "col772": "hwqsv", + "col773": "9omeu", + "col774": "pszn1", + "col775": "u5fws", + "col776": "e6r71", + "col777": "bwn59", + "col778": "gl4r6", + "col779": "3b8ou", + "col780": "e2dnv", + "col781": "x5lye", + "col782": "6va8a", + "col783": "bkycn", + "col784": "dw6q0", + "col785": "5lk7u", + "col786": "t6ls0", + "col787": "93t3g", + "col788": "n7tmk", + "col789": "pmwog", + "col790": "txiao", + "col791": "qxc22", + "col792": "a6ql0", + "col793": "u9kel", + "col794": "h6z39", + "col795": "h28c9", + "col796": "xy2cd", + "col797": "vtjbg", + "col798": "bc2ik", + "col799": "3wkfh", + "col800": "x751o", + "col801": "kxph0", + "col802": "leu3p", + "col803": "w3epw", + "col804": "mo54i", + "col805": "1iph4", + "col806": "4g58q", + "col807": "8agux", + "col808": "mj1n4", + "col809": "jr17n", + "col810": "na5l5", + "col811": "hiry3", + "col812": "lk4xl", + "col813": "cu84k", + "col814": "3lr38", + "col815": "e5epp", + "col816": "fzc63", + "col817": "ufrw3", + "col818": "8ist9", + "col819": "njztx", + "col820": "1m67s", + "col821": "fpv67", + "col822": "yia88", + "col823": "6hb4r", + "col824": "prnoe", + "col825": "ttvkh", + "col826": "skx5j", + "col827": "x3hak", + "col828": "rsk97", + "col829": "yzhqd", + "col830": "s3mub", + "col831": "zkywv", + "col832": "q3n08", + "col833": "0rjrz", + "col834": "wn6rg", + "col835": "t08md", + "col836": "yk1fd", + "col837": "3jb8f", + "col838": "mzlg5", + "col839": "jeefl", + "col840": "urdn9", + "col841": "moakz", + "col842": "zev1d", + "col843": "8wyvn", + "col844": "lxwym", + "col845": "z8ggi", + "col846": "9231e", + "col847": "d4b02", + "col848": "9u1ut", + "col849": "0a0dx", + "col850": "bon4f", + "col851": "el5mn", + "col852": "srad5", + "col853": "dg08t", + "col854": "a3dav", + "col855": "9lfxy", + "col856": "z38mx", + "col857": "r780e", + "col858": "9xdhs", + "col859": "r0477", + "col860": "kc1pk", + "col861": "dgqsc", + "col862": "d90zr", + "col863": "5lbly", + "col864": "40635", + "col865": "1i877", + "col866": "hv7nj", + "col867": "pspp7", + "col868": "p00wl", + "col869": "z1gh9", + "col870": "x4hk1", + "col871": "ll8x1", + "col872": "qr2fw", + "col873": "owk3z", + "col874": "6preu", + "col875": "oaw7a", + "col876": "zxji5", + "col877": "0ztp9", + "col878": "936je", + "col879": "up8cu", + "col880": "glmml", + "col881": "2h43n", + "col882": "goddx", + "col883": "pzn47", + "col884": "xavkk", + "col885": "ipz5b", + "col886": "b3b0m", + "col887": "sh1tx", + "col888": "r2plu", + "col889": "ih4y0", + "col890": "j55j7", + "col891": "vye8f", + "col892": "8e9pp", + "col893": "uzuip", + "col894": "e5pjf", + "col895": "u6lc0", + "col896": "zk2g2", + "col897": "h0wcc", + "col898": "9iugb", + "col899": "fkv5f", + "col900": "h6ofu", + "col901": "1dtza", + "col902": "0375z", + "col903": "he50t", + "col904": "qcsq5", + "col905": "wmcfn", + "col906": "81svc", + "col907": "xf201", + "col908": "a6975", + "col909": "jpwxe", + "col910": "g5vga", + "col911": "wf1tb", + "col912": "gu8y1", + "col913": "9ygr6", + "col914": "f8oay", + "col915": "g2jq9", + "col916": "avn6x", + "col917": "rs8l9", + "col918": "9ohn5", + "col919": "7phm7", + "col920": "e3w56", + "col921": "xpqim", + "col922": "drirk", + "col923": "xxvpd", + "col924": "518sy", + "col925": "kgf7r", + "col926": "r5kwo", + "col927": "lnx8j", + "col928": "75ht0", + "col929": "m8tbl", + "col930": "tvzon", + "col931": "3708e", + "col932": "h633c", + "col933": "2d6z9", + "col934": "ofp85", + "col935": "pvamv", + "col936": "28kf4", + "col937": "5i4nj", + "col938": "zuofk", + "col939": "gaipn", + "col940": "tsw37", + "col941": "c4r0j", + "col942": "oupp4", + "col943": "ijwdh", + "col944": "4qm1m", + "col945": "4zyog", + "col946": "rxue4", + "col947": "3tsre", + "col948": "s5q3v", + "col949": "zzbbp", + "col950": "2y6h4", + "col951": "l4no1", + "col952": "fq2r2", + "col953": "78c53", + "col954": "ni1da", + "col955": "x3dfu", + "col956": "c6sha", + "col957": "upe5t", + "col958": "zsw94", + "col959": "yzgxc", + "col960": "1v225", + "col961": "nb0sm", + "col962": "jogpg", + "col963": "h41nv", + "col964": "21147", + "col965": "x80gc", + "col966": "94j9j", + "col967": "jta0e", + "col968": "k8gwu", + "col969": "klvi8", + "col970": "1bcjv", + "col971": "jr0nl", + "col972": "7btp5", + "col973": "iutba", + "col974": "wn244", + "col975": "twf4y", + "col976": "gt2ts", + "col977": "o0k42", + "col978": "exrb7", + "col979": "y3uyr", + "col980": "gvtob", + "col981": "dwwb8", + "col982": "axy3v", + "col983": "r03m6", + "col984": "9plrd", + "col985": "v8nqf", + "col986": "dwmne", + "col987": "fwpju", + "col988": "nzd7g", + "col989": "diqe6", + "col990": "a17tx", + "col991": "d2stt", + "col992": "nbjyh", + "col993": "vsbcq", + "col994": "al2ew", + "col995": "8ga6i", + "col996": "uu9kw", + "col997": "wkmkl", + "col998": "7jw2n", + "col999": "bab4n" + }, + { + "name": "Ayers Ballard", + "gender": "male", + "col0": "yrkul", + "col1": "tj10g", + "col2": "xfln2", + "col3": "97tt1", + "col4": "rm45t", + "col5": "tjiqv", + "col6": "fboez", + "col7": "mpiay", + "col8": "5fxp4", + "col9": "2d01l", + "col10": "l9f25", + "col11": "e8kw1", + "col12": "gytwp", + "col13": "h2t20", + "col14": "vyf9x", + "col15": "uelpu", + "col16": "gtttz", + "col17": "72sgi", + "col18": "vawb9", + "col19": "ivm8v", + "col20": "swpax", + "col21": "lfjfy", + "col22": "zo7mr", + "col23": "yhrq9", + "col24": "alczw", + "col25": "384h4", + "col26": "hz2an", + "col27": "4hlsv", + "col28": "x5lkv", + "col29": "u5uc4", + "col30": "6vjoz", + "col31": "2976t", + "col32": "miajh", + "col33": "7jm4a", + "col34": "pd7if", + "col35": "84ipy", + "col36": "52d5r", + "col37": "9ej8i", + "col38": "p1z49", + "col39": "65r7w", + "col40": "fq2ra", + "col41": "26s72", + "col42": "lvdg5", + "col43": "1vntb", + "col44": "6tdkj", + "col45": "8qidy", + "col46": "bt08p", + "col47": "vqopv", + "col48": "x8afz", + "col49": "1e22g", + "col50": "jiuk4", + "col51": "zadew", + "col52": "a19zl", + "col53": "y7dja", + "col54": "5lk8c", + "col55": "4qdez", + "col56": "oxox4", + "col57": "ho0x4", + "col58": "s1e95", + "col59": "9zmlw", + "col60": "c01bk", + "col61": "geg7m", + "col62": "r8bxd", + "col63": "3df1q", + "col64": "05nfe", + "col65": "mowgi", + "col66": "ao2rx", + "col67": "jn1xo", + "col68": "ddxwl", + "col69": "2m5xw", + "col70": "8hadu", + "col71": "dyde9", + "col72": "7xlos", + "col73": "bok90", + "col74": "ckkz9", + "col75": "ijqih", + "col76": "82imz", + "col77": "zvbnb", + "col78": "gq0el", + "col79": "7szfe", + "col80": "tlspv", + "col81": "r6r7o", + "col82": "3kfst", + "col83": "w4xtj", + "col84": "ylgfa", + "col85": "n1nce", + "col86": "kg4wa", + "col87": "umob3", + "col88": "zyt9z", + "col89": "flpzt", + "col90": "wknu3", + "col91": "fume1", + "col92": "6opxe", + "col93": "m956b", + "col94": "9hrip", + "col95": "9zgrr", + "col96": "v5g4y", + "col97": "isb7e", + "col98": "yjdov", + "col99": "tfyxo", + "col100": "9lw5x", + "col101": "btmu9", + "col102": "lntn1", + "col103": "m6fud", + "col104": "yzbj4", + "col105": "us4bt", + "col106": "ncrxh", + "col107": "xn3zq", + "col108": "3ao21", + "col109": "zt08n", + "col110": "qh5zs", + "col111": "oxzzv", + "col112": "gvn9u", + "col113": "vj1rr", + "col114": "4kvpp", + "col115": "ipqi2", + "col116": "5opcd", + "col117": "6ii9m", + "col118": "4m5t6", + "col119": "ymdl9", + "col120": "88htu", + "col121": "wo0p9", + "col122": "4qwoj", + "col123": "qejkm", + "col124": "oyd71", + "col125": "rkqdx", + "col126": "cs8qd", + "col127": "4hwya", + "col128": "etklh", + "col129": "tp8m8", + "col130": "qr4gq", + "col131": "qaq4n", + "col132": "hqwy7", + "col133": "pg0x7", + "col134": "4pqi1", + "col135": "s8sl6", + "col136": "5k1qc", + "col137": "jnsfh", + "col138": "zwhoe", + "col139": "q5049", + "col140": "fc7sl", + "col141": "etbqc", + "col142": "cqtnc", + "col143": "38x5f", + "col144": "j27mw", + "col145": "t1fsu", + "col146": "2lf5g", + "col147": "me7yq", + "col148": "rvq4h", + "col149": "kjas4", + "col150": "ujv1h", + "col151": "pjrky", + "col152": "7fujx", + "col153": "w2v6u", + "col154": "s89fh", + "col155": "p5f77", + "col156": "rgbmw", + "col157": "8y7oh", + "col158": "944b9", + "col159": "ztibz", + "col160": "8ls5m", + "col161": "hu3ne", + "col162": "llcsq", + "col163": "apql6", + "col164": "th7a2", + "col165": "puiml", + "col166": "vmlrz", + "col167": "bclz4", + "col168": "hujkh", + "col169": "h5df8", + "col170": "xkhob", + "col171": "ji1tz", + "col172": "l6qqt", + "col173": "ed9kl", + "col174": "7bp3l", + "col175": "6jmie", + "col176": "9m3bq", + "col177": "cve72", + "col178": "j07ex", + "col179": "zygl7", + "col180": "dbpc5", + "col181": "rf4jc", + "col182": "cvt6n", + "col183": "sssd6", + "col184": "hblnw", + "col185": "fffs3", + "col186": "5wpf5", + "col187": "qavf9", + "col188": "u9vp6", + "col189": "n8f48", + "col190": "tm38m", + "col191": "pi9rs", + "col192": "hvqtt", + "col193": "0g6pe", + "col194": "5a6up", + "col195": "m6dzm", + "col196": "nr514", + "col197": "kmc77", + "col198": "18jzo", + "col199": "ihcat", + "col200": "ecpsy", + "col201": "v2z1a", + "col202": "7qcbp", + "col203": "x3yjr", + "col204": "kx67e", + "col205": "7dzjx", + "col206": "prbxc", + "col207": "odxbl", + "col208": "1ec1r", + "col209": "q4s36", + "col210": "8bodl", + "col211": "qd1c0", + "col212": "j3agt", + "col213": "1ioh8", + "col214": "lvsfk", + "col215": "y4hrm", + "col216": "lwvab", + "col217": "u6x4t", + "col218": "uvcy5", + "col219": "umq3s", + "col220": "7w3jg", + "col221": "pe7qs", + "col222": "8m5br", + "col223": "d3jyu", + "col224": "lrs69", + "col225": "gkqo6", + "col226": "0d4qz", + "col227": "zl8v6", + "col228": "rfzhd", + "col229": "ipn2t", + "col230": "gb452", + "col231": "plvee", + "col232": "ifwny", + "col233": "obnz9", + "col234": "elfcn", + "col235": "17ehm", + "col236": "0kuk0", + "col237": "yjd7t", + "col238": "tdwd0", + "col239": "znjde", + "col240": "9e651", + "col241": "kcvj7", + "col242": "n8d1e", + "col243": "bsiah", + "col244": "e97ux", + "col245": "j243s", + "col246": "ejlgq", + "col247": "jsttx", + "col248": "gwzm9", + "col249": "q593l", + "col250": "42b20", + "col251": "baz7i", + "col252": "hkzvj", + "col253": "i1grh", + "col254": "mo6z7", + "col255": "mp2wo", + "col256": "2nu6k", + "col257": "09xa2", + "col258": "i2xby", + "col259": "24e6d", + "col260": "0zmsa", + "col261": "tvb9g", + "col262": "odtr4", + "col263": "jc682", + "col264": "pfxk5", + "col265": "thak7", + "col266": "3zpww", + "col267": "lrun6", + "col268": "n7ew8", + "col269": "8eyfw", + "col270": "9u37j", + "col271": "347fu", + "col272": "hu16a", + "col273": "if4zq", + "col274": "fs51h", + "col275": "0i7n3", + "col276": "0gokt", + "col277": "7rwl2", + "col278": "x2pz2", + "col279": "alj3k", + "col280": "sp2vq", + "col281": "qp4ee", + "col282": "u93gg", + "col283": "7sr9g", + "col284": "hjq6k", + "col285": "a3v65", + "col286": "ep7ca", + "col287": "y1d85", + "col288": "fg81m", + "col289": "v4rix", + "col290": "0irxg", + "col291": "xsp5y", + "col292": "h1fo6", + "col293": "pjg3d", + "col294": "s36zi", + "col295": "epeub", + "col296": "8ubo9", + "col297": "zqu8t", + "col298": "nyd84", + "col299": "642u7", + "col300": "14etm", + "col301": "r5gl2", + "col302": "73sb0", + "col303": "h0acs", + "col304": "wuv5v", + "col305": "e6n56", + "col306": "0zcjw", + "col307": "j4ysa", + "col308": "irxhm", + "col309": "svc9v", + "col310": "mu8qq", + "col311": "qby1l", + "col312": "3jdch", + "col313": "ougib", + "col314": "g93cb", + "col315": "o0spd", + "col316": "qd73p", + "col317": "rm8kk", + "col318": "e5htz", + "col319": "obgjj", + "col320": "5yqot", + "col321": "b4si5", + "col322": "o92um", + "col323": "m3eri", + "col324": "udl3d", + "col325": "9j9su", + "col326": "o4qnk", + "col327": "jeh1f", + "col328": "brz6w", + "col329": "bqiuq", + "col330": "1vpuk", + "col331": "fo3p5", + "col332": "xp88o", + "col333": "7qc4m", + "col334": "dried", + "col335": "0qcyl", + "col336": "7ynuo", + "col337": "2i2vk", + "col338": "c5i6h", + "col339": "p98jp", + "col340": "b7vsj", + "col341": "y38j7", + "col342": "12q3a", + "col343": "zppoy", + "col344": "5kgl8", + "col345": "ljxzi", + "col346": "emb3b", + "col347": "6pnvp", + "col348": "amij0", + "col349": "e7lk5", + "col350": "1288a", + "col351": "g68ny", + "col352": "1xixf", + "col353": "mszx8", + "col354": "edhmc", + "col355": "56690", + "col356": "1wlui", + "col357": "fyut1", + "col358": "24bx3", + "col359": "9nxz2", + "col360": "wlbef", + "col361": "aj6l0", + "col362": "h29fo", + "col363": "m1tiw", + "col364": "hcxh8", + "col365": "em8dl", + "col366": "caphd", + "col367": "71pnd", + "col368": "hyvmq", + "col369": "kpf5u", + "col370": "2fwqr", + "col371": "1lmy4", + "col372": "5vf4f", + "col373": "0fndh", + "col374": "oswsl", + "col375": "vz5qq", + "col376": "zk3cg", + "col377": "zylri", + "col378": "m398v", + "col379": "rulj8", + "col380": "jaaay", + "col381": "dulmz", + "col382": "z8ssj", + "col383": "7h749", + "col384": "7dq8x", + "col385": "4jest", + "col386": "rpdnu", + "col387": "zz8p1", + "col388": "3otxs", + "col389": "uy5j8", + "col390": "l4xap", + "col391": "50107", + "col392": "vn73k", + "col393": "xq3mh", + "col394": "howjx", + "col395": "wm85p", + "col396": "oxq38", + "col397": "m2a1j", + "col398": "ihttw", + "col399": "e2yyq", + "col400": "ok2qx", + "col401": "vdtsa", + "col402": "psqcr", + "col403": "srnzw", + "col404": "leclo", + "col405": "gwjhx", + "col406": "97r1e", + "col407": "xwsk0", + "col408": "z8170", + "col409": "2joit", + "col410": "x9x6g", + "col411": "tcv0a", + "col412": "7b0ds", + "col413": "0yz9g", + "col414": "o2lrd", + "col415": "7xfmg", + "col416": "tnm2b", + "col417": "eosfa", + "col418": "ekzh8", + "col419": "stkl5", + "col420": "xc79q", + "col421": "fk8g7", + "col422": "1iyjq", + "col423": "4vp5w", + "col424": "lf4k6", + "col425": "i9bjm", + "col426": "q3t7l", + "col427": "e9twd", + "col428": "f8iww", + "col429": "j0c2n", + "col430": "bfdto", + "col431": "26pr3", + "col432": "girdu", + "col433": "e71tf", + "col434": "opghz", + "col435": "c8qxh", + "col436": "o4st7", + "col437": "brddn", + "col438": "sedaa", + "col439": "cko4s", + "col440": "oumqs", + "col441": "ylmzx", + "col442": "pxsf7", + "col443": "kpz5l", + "col444": "a9j4n", + "col445": "xykpx", + "col446": "0e6z0", + "col447": "1g8tl", + "col448": "g2r05", + "col449": "lzv77", + "col450": "2vvn9", + "col451": "ks9u7", + "col452": "dp4e5", + "col453": "jp9mz", + "col454": "rgtom", + "col455": "syfec", + "col456": "w8eyo", + "col457": "0rv51", + "col458": "7fd1a", + "col459": "ab0mt", + "col460": "4hqbm", + "col461": "lr2q6", + "col462": "byb7z", + "col463": "7w9ht", + "col464": "p41fb", + "col465": "0mzfv", + "col466": "7moia", + "col467": "b6k3u", + "col468": "9o46p", + "col469": "z0wbg", + "col470": "n8zq5", + "col471": "0jeup", + "col472": "xtnbg", + "col473": "nbp47", + "col474": "9vev2", + "col475": "97mx7", + "col476": "57qba", + "col477": "6gj76", + "col478": "b86ud", + "col479": "pdj49", + "col480": "fptgx", + "col481": "b0qbl", + "col482": "l8zxv", + "col483": "gud61", + "col484": "l16li", + "col485": "gywyk", + "col486": "n4em1", + "col487": "vv0mk", + "col488": "a5sfq", + "col489": "1wspj", + "col490": "4ptwf", + "col491": "nbm9q", + "col492": "rpvkv", + "col493": "j7qmc", + "col494": "xe0ep", + "col495": "lagd4", + "col496": "zttxj", + "col497": "7nqkr", + "col498": "ahb2o", + "col499": "clvlk", + "col500": "p658s", + "col501": "ikdrq", + "col502": "jozsx", + "col503": "m9dfl", + "col504": "vgklz", + "col505": "8v55v", + "col506": "scvek", + "col507": "oz8u8", + "col508": "btasj", + "col509": "wsqa0", + "col510": "ymr7u", + "col511": "6qg4t", + "col512": "j78ng", + "col513": "hovtl", + "col514": "skg5c", + "col515": "euebm", + "col516": "hlk50", + "col517": "s08zm", + "col518": "2wznw", + "col519": "56xv9", + "col520": "bqut3", + "col521": "wkm8u", + "col522": "287zu", + "col523": "ta3e5", + "col524": "ft7o5", + "col525": "y1caq", + "col526": "xbrme", + "col527": "s40zv", + "col528": "3y4vn", + "col529": "kf1hc", + "col530": "87pwb", + "col531": "calmm", + "col532": "okctw", + "col533": "jvsmu", + "col534": "uxb72", + "col535": "sjhmz", + "col536": "n5v7d", + "col537": "k8fcz", + "col538": "bi60q", + "col539": "c72lj", + "col540": "09oel", + "col541": "y9153", + "col542": "s2pka", + "col543": "s89qi", + "col544": "qjljo", + "col545": "xgpty", + "col546": "rzgt7", + "col547": "57n0a", + "col548": "51824", + "col549": "jz0tp", + "col550": "84klp", + "col551": "q58jh", + "col552": "z3qgg", + "col553": "x9lqf", + "col554": "wqmxj", + "col555": "flnca", + "col556": "o58mi", + "col557": "rk9p4", + "col558": "hrnxd", + "col559": "m4sqm", + "col560": "va3ho", + "col561": "uzhck", + "col562": "wenc2", + "col563": "f9zeo", + "col564": "qs10p", + "col565": "0yaaj", + "col566": "s57g9", + "col567": "l6j5c", + "col568": "4bphb", + "col569": "ce5l6", + "col570": "wrozl", + "col571": "btdtu", + "col572": "vl91l", + "col573": "syaw4", + "col574": "k2bjs", + "col575": "sfbfx", + "col576": "xprv4", + "col577": "7pv6q", + "col578": "lhkkw", + "col579": "jn813", + "col580": "750ka", + "col581": "u9okc", + "col582": "agfg8", + "col583": "wpfyp", + "col584": "i45tl", + "col585": "rdxe2", + "col586": "5ix0h", + "col587": "7cnmk", + "col588": "1yms4", + "col589": "8ypxi", + "col590": "dhwlm", + "col591": "r63y9", + "col592": "1veib", + "col593": "qtnw0", + "col594": "ztvzx", + "col595": "t9y4l", + "col596": "di2sn", + "col597": "hokc7", + "col598": "pflwt", + "col599": "7e9r4", + "col600": "xkxbs", + "col601": "5oos1", + "col602": "lkd2q", + "col603": "byap8", + "col604": "ke4tj", + "col605": "e7d3b", + "col606": "nydn5", + "col607": "cnhsl", + "col608": "y1xn8", + "col609": "x111a", + "col610": "l73hb", + "col611": "w8ei6", + "col612": "m27ze", + "col613": "nwqbz", + "col614": "d3fkn", + "col615": "oe75g", + "col616": "rvwzj", + "col617": "fz8ys", + "col618": "bol22", + "col619": "7abfy", + "col620": "c94oi", + "col621": "z0e02", + "col622": "2fy97", + "col623": "pnxxr", + "col624": "w22i6", + "col625": "1ubcu", + "col626": "q5gxh", + "col627": "ju9mp", + "col628": "1x695", + "col629": "kn2ei", + "col630": "tzvq8", + "col631": "3jjee", + "col632": "qn301", + "col633": "89ivf", + "col634": "yzg02", + "col635": "hmx5v", + "col636": "dqz6f", + "col637": "hyv5f", + "col638": "mkpx3", + "col639": "p2ekq", + "col640": "9n5pw", + "col641": "kxs6m", + "col642": "izrgh", + "col643": "xdmps", + "col644": "2zgt2", + "col645": "1ebgj", + "col646": "xkxfr", + "col647": "mg46q", + "col648": "x5juw", + "col649": "cl1y2", + "col650": "ocgcz", + "col651": "dg6e4", + "col652": "h5vs8", + "col653": "hv7zi", + "col654": "rnjeg", + "col655": "l8y6k", + "col656": "wdx3d", + "col657": "ynqog", + "col658": "ejgy8", + "col659": "ndm3j", + "col660": "w40tp", + "col661": "sthfo", + "col662": "amfed", + "col663": "dppie", + "col664": "e2pah", + "col665": "441v7", + "col666": "oqt1h", + "col667": "iwb3f", + "col668": "fvys9", + "col669": "9tx6d", + "col670": "ctltt", + "col671": "4rqqe", + "col672": "72qf6", + "col673": "5cunv", + "col674": "63802", + "col675": "dvt7c", + "col676": "ngq09", + "col677": "phde5", + "col678": "4vaam", + "col679": "hdsws", + "col680": "3k3bs", + "col681": "q7rn8", + "col682": "u6gq5", + "col683": "x4n1l", + "col684": "3fvun", + "col685": "bkdws", + "col686": "usema", + "col687": "kvrcr", + "col688": "gkqin", + "col689": "f69rs", + "col690": "et8g4", + "col691": "q42bh", + "col692": "s9wjp", + "col693": "b1o9p", + "col694": "7ksbi", + "col695": "1ix1y", + "col696": "057hj", + "col697": "zs7j1", + "col698": "rm8xj", + "col699": "lso6w", + "col700": "qwisp", + "col701": "4x6m5", + "col702": "uc8yj", + "col703": "iqel2", + "col704": "97fzk", + "col705": "59rbo", + "col706": "yuhxc", + "col707": "4swi6", + "col708": "4cev3", + "col709": "k36ro", + "col710": "fapbn", + "col711": "c5fdj", + "col712": "68l7l", + "col713": "xh3vx", + "col714": "4kdxk", + "col715": "fao2r", + "col716": "pe0cm", + "col717": "da9jv", + "col718": "bq0m1", + "col719": "yc9x2", + "col720": "sz2b9", + "col721": "nts33", + "col722": "7yjp2", + "col723": "i7esy", + "col724": "x8w0a", + "col725": "sb7xw", + "col726": "t5vr9", + "col727": "1j8xa", + "col728": "k98g1", + "col729": "niycl", + "col730": "wyss1", + "col731": "50vya", + "col732": "w1w9l", + "col733": "dqye8", + "col734": "uduai", + "col735": "b9ixo", + "col736": "zmk7i", + "col737": "3y6i8", + "col738": "wjto3", + "col739": "czd7t", + "col740": "3ilnz", + "col741": "pnmej", + "col742": "37ib6", + "col743": "whw0x", + "col744": "63qpg", + "col745": "1yhkb", + "col746": "rx37r", + "col747": "nfrpu", + "col748": "6f1x6", + "col749": "1x23q", + "col750": "nnigv", + "col751": "wij4d", + "col752": "t33xh", + "col753": "1fn9p", + "col754": "jcdta", + "col755": "8wt2b", + "col756": "6ngo2", + "col757": "zy3z5", + "col758": "wnkxb", + "col759": "54wg8", + "col760": "01lh9", + "col761": "eyd2c", + "col762": "yo01s", + "col763": "g8u28", + "col764": "p7rxn", + "col765": "zlytd", + "col766": "c9uyz", + "col767": "sc6au", + "col768": "oko9q", + "col769": "wk9ls", + "col770": "hock4", + "col771": "y7ybv", + "col772": "fu950", + "col773": "4tr4f", + "col774": "l8xvx", + "col775": "ihscy", + "col776": "c7qx9", + "col777": "6y7yf", + "col778": "udfr9", + "col779": "w56s0", + "col780": "q1qwc", + "col781": "368cz", + "col782": "uo0kb", + "col783": "18kpm", + "col784": "0ca7u", + "col785": "438np", + "col786": "wz3l9", + "col787": "r428a", + "col788": "7dxxs", + "col789": "puewv", + "col790": "18ov2", + "col791": "pqbag", + "col792": "er29x", + "col793": "zwa4w", + "col794": "rdgvg", + "col795": "bjhvy", + "col796": "pamqh", + "col797": "g9qau", + "col798": "iuf6h", + "col799": "wtcw6", + "col800": "2te9i", + "col801": "o2r36", + "col802": "gqsac", + "col803": "5051u", + "col804": "63kmp", + "col805": "4fcym", + "col806": "425o2", + "col807": "ojv5c", + "col808": "v6y7q", + "col809": "b9z82", + "col810": "un5hz", + "col811": "mba46", + "col812": "g37gu", + "col813": "bp4ty", + "col814": "xv21x", + "col815": "0obv0", + "col816": "l6e8f", + "col817": "kzm5b", + "col818": "9oax4", + "col819": "00t7h", + "col820": "t5bfa", + "col821": "upeee", + "col822": "9jtop", + "col823": "78ls9", + "col824": "7egh5", + "col825": "idj5n", + "col826": "crmzt", + "col827": "c98q1", + "col828": "4osbj", + "col829": "38cl3", + "col830": "nrdey", + "col831": "2p2ok", + "col832": "8ebjg", + "col833": "4eha3", + "col834": "k51m2", + "col835": "7snn2", + "col836": "nzr32", + "col837": "bxpp0", + "col838": "2x58d", + "col839": "herak", + "col840": "1rlpr", + "col841": "sboeh", + "col842": "k7034", + "col843": "57ofc", + "col844": "feqil", + "col845": "g8d3v", + "col846": "1lo77", + "col847": "m9jk3", + "col848": "185p4", + "col849": "qnrcn", + "col850": "reqoj", + "col851": "awkt7", + "col852": "en2h8", + "col853": "7lvqa", + "col854": "21vc9", + "col855": "1pytq", + "col856": "vgocu", + "col857": "1eg89", + "col858": "jpijb", + "col859": "xzbmu", + "col860": "8j7nk", + "col861": "fye8h", + "col862": "e72iu", + "col863": "tkhgq", + "col864": "ji66y", + "col865": "t8oew", + "col866": "ejg5z", + "col867": "4auwz", + "col868": "gt4ij", + "col869": "azlvf", + "col870": "jirpv", + "col871": "qa8py", + "col872": "0v563", + "col873": "l1d39", + "col874": "tzgsi", + "col875": "nx49w", + "col876": "2kg6z", + "col877": "um1mi", + "col878": "l88wk", + "col879": "6rfae", + "col880": "pw89b", + "col881": "oj6f5", + "col882": "2fpul", + "col883": "q7rer", + "col884": "rctzo", + "col885": "94m6e", + "col886": "ou5l5", + "col887": "r65ff", + "col888": "518ix", + "col889": "q3h0o", + "col890": "xczqz", + "col891": "kb310", + "col892": "1fiyp", + "col893": "57sf1", + "col894": "ih80j", + "col895": "eovto", + "col896": "pnkjz", + "col897": "gcypx", + "col898": "vpd7s", + "col899": "u1wth", + "col900": "1iw8a", + "col901": "tv2tq", + "col902": "b7n4r", + "col903": "kewhy", + "col904": "ehj3u", + "col905": "a825e", + "col906": "pcxd6", + "col907": "n92kk", + "col908": "9isoy", + "col909": "ppn1n", + "col910": "9thfb", + "col911": "o5cq1", + "col912": "y93vh", + "col913": "gauf7", + "col914": "7g8ly", + "col915": "47tls", + "col916": "ok827", + "col917": "yfb3w", + "col918": "59avr", + "col919": "yjgg0", + "col920": "mand7", + "col921": "jz014", + "col922": "8sej2", + "col923": "uji72", + "col924": "kq5u0", + "col925": "ywnlr", + "col926": "4s7v8", + "col927": "5ijga", + "col928": "sudiy", + "col929": "varmi", + "col930": "e4ysf", + "col931": "3te2j", + "col932": "62eqp", + "col933": "xwrub", + "col934": "if441", + "col935": "l4rp7", + "col936": "sc6ii", + "col937": "r1ljr", + "col938": "bdycb", + "col939": "v1zm7", + "col940": "0mhbv", + "col941": "pei4k", + "col942": "t2ve8", + "col943": "n00dg", + "col944": "18ila", + "col945": "93w94", + "col946": "8o3p9", + "col947": "bulco", + "col948": "ja4q6", + "col949": "8m5is", + "col950": "nxv1g", + "col951": "ul5hi", + "col952": "hj4np", + "col953": "j96ot", + "col954": "we310", + "col955": "8wxmp", + "col956": "b29bf", + "col957": "ud5rz", + "col958": "8aisd", + "col959": "dtybg", + "col960": "tyd0g", + "col961": "euurd", + "col962": "mtaco", + "col963": "ojkxj", + "col964": "jtiil", + "col965": "dj5qk", + "col966": "r478s", + "col967": "xpx5z", + "col968": "amwmo", + "col969": "bihj8", + "col970": "smru3", + "col971": "720lm", + "col972": "i6j0c", + "col973": "scuxe", + "col974": "u35i4", + "col975": "igflk", + "col976": "m072o", + "col977": "hn3gn", + "col978": "dew2c", + "col979": "ne621", + "col980": "dy1dv", + "col981": "qgx0k", + "col982": "0ieul", + "col983": "qsstn", + "col984": "ew0df", + "col985": "ajwgd", + "col986": "ayyab", + "col987": "d1j4z", + "col988": "vojml", + "col989": "egb2f", + "col990": "szqd6", + "col991": "4kxsn", + "col992": "kiloy", + "col993": "1r5hr", + "col994": "5xfoc", + "col995": "dt4gi", + "col996": "680e8", + "col997": "hfg5y", + "col998": "928cz", + "col999": "qht3q" + }, + { + "name": "Hoffman Mercado", + "gender": "male", + "col0": "oq9ka", + "col1": "v7rbl", + "col2": "jc9vv", + "col3": "n3nq2", + "col4": "r0lf4", + "col5": "4ik5x", + "col6": "az3qs", + "col7": "23h1l", + "col8": "656bd", + "col9": "3q0nc", + "col10": "st9jg", + "col11": "5b85n", + "col12": "w4apl", + "col13": "ru74e", + "col14": "3u7qp", + "col15": "xtsi1", + "col16": "1kaze", + "col17": "v49ke", + "col18": "2q5p8", + "col19": "hi28n", + "col20": "121er", + "col21": "8sden", + "col22": "mrbzk", + "col23": "8nfpp", + "col24": "jbiya", + "col25": "nun9d", + "col26": "xcvfe", + "col27": "0h1w3", + "col28": "gqsp8", + "col29": "nimjy", + "col30": "vb6c4", + "col31": "4xllb", + "col32": "sv8wf", + "col33": "ovbcx", + "col34": "0cjmi", + "col35": "tsgqh", + "col36": "fejui", + "col37": "797pe", + "col38": "17wvj", + "col39": "rl7jl", + "col40": "cmv85", + "col41": "wuc9w", + "col42": "bik0y", + "col43": "vg21i", + "col44": "jh1td", + "col45": "hp0z7", + "col46": "gvazx", + "col47": "2v7b9", + "col48": "m5gdz", + "col49": "gsuoh", + "col50": "ogig8", + "col51": "rvfkm", + "col52": "jke4s", + "col53": "b0uqg", + "col54": "zn5q0", + "col55": "w2hkh", + "col56": "0a8ky", + "col57": "mt4mv", + "col58": "zmpi0", + "col59": "hz8wt", + "col60": "oc335", + "col61": "1q5yt", + "col62": "e4lqr", + "col63": "jzljl", + "col64": "w6sqg", + "col65": "fqc08", + "col66": "lwcaa", + "col67": "8k1wr", + "col68": "s4pa0", + "col69": "ocyyd", + "col70": "o948g", + "col71": "hdvhk", + "col72": "als05", + "col73": "qqizk", + "col74": "0bcet", + "col75": "jz60m", + "col76": "7l0zn", + "col77": "bg5c9", + "col78": "mxuvj", + "col79": "ovl6m", + "col80": "v83kt", + "col81": "kxfbn", + "col82": "0voh6", + "col83": "f3x6o", + "col84": "8z19r", + "col85": "5aij7", + "col86": "1s0bq", + "col87": "3t9bs", + "col88": "a8tod", + "col89": "2sn3q", + "col90": "yuyza", + "col91": "km9im", + "col92": "06krw", + "col93": "iq486", + "col94": "550ka", + "col95": "wxndj", + "col96": "enobq", + "col97": "tdzla", + "col98": "5seqf", + "col99": "9iiyo", + "col100": "gsek1", + "col101": "oi4g1", + "col102": "cx2x7", + "col103": "wfllt", + "col104": "e0bfn", + "col105": "cvx9k", + "col106": "scapw", + "col107": "s11m7", + "col108": "hb00e", + "col109": "jneeg", + "col110": "lswc8", + "col111": "ejqxz", + "col112": "7x8v6", + "col113": "3n5fm", + "col114": "iv9sa", + "col115": "5gklq", + "col116": "8j4w4", + "col117": "geej0", + "col118": "tn3i5", + "col119": "pmyau", + "col120": "o6xzb", + "col121": "3mz84", + "col122": "v0z9o", + "col123": "339ud", + "col124": "cfyxq", + "col125": "wfo13", + "col126": "fio4q", + "col127": "7tta8", + "col128": "gc9xg", + "col129": "zey9d", + "col130": "fg9eq", + "col131": "qhw4k", + "col132": "yt9b2", + "col133": "ffx9i", + "col134": "os8we", + "col135": "wanz1", + "col136": "9gvig", + "col137": "lka7q", + "col138": "ythc0", + "col139": "qip36", + "col140": "d3k7v", + "col141": "j8ekw", + "col142": "272pq", + "col143": "ecv5j", + "col144": "rbbb9", + "col145": "ox6xw", + "col146": "42s1v", + "col147": "jxy0k", + "col148": "qrpss", + "col149": "d943h", + "col150": "sid44", + "col151": "jkujr", + "col152": "v35hr", + "col153": "u1cfl", + "col154": "y9e5z", + "col155": "11xd2", + "col156": "k7s5p", + "col157": "s7joe", + "col158": "khj0v", + "col159": "r92yl", + "col160": "xgy1k", + "col161": "kk3f7", + "col162": "bnjbw", + "col163": "40qfk", + "col164": "gbrlj", + "col165": "fc5ze", + "col166": "mzdln", + "col167": "4cnz9", + "col168": "1lwu7", + "col169": "fh8dn", + "col170": "wirfv", + "col171": "qpldg", + "col172": "2nnq9", + "col173": "rg9qj", + "col174": "cpq5o", + "col175": "ha82j", + "col176": "jwrld", + "col177": "gqmr5", + "col178": "fm7ef", + "col179": "snxm2", + "col180": "zbvr3", + "col181": "4e0yp", + "col182": "dnfpu", + "col183": "sft1w", + "col184": "4wo4t", + "col185": "z7cp0", + "col186": "i756o", + "col187": "vrq9w", + "col188": "lzll8", + "col189": "na3ll", + "col190": "gi622", + "col191": "abnkq", + "col192": "vtxbi", + "col193": "x13c4", + "col194": "tquoa", + "col195": "edfip", + "col196": "czpqk", + "col197": "bo9if", + "col198": "ncbts", + "col199": "8fgy1", + "col200": "du17h", + "col201": "i7x4q", + "col202": "vbg3g", + "col203": "a0rv7", + "col204": "0nz3i", + "col205": "3tbya", + "col206": "vnfut", + "col207": "zt2mr", + "col208": "2j4si", + "col209": "qyuvf", + "col210": "yi4rp", + "col211": "8uckv", + "col212": "htam4", + "col213": "w2tz5", + "col214": "yhyjz", + "col215": "6zgql", + "col216": "fxvxi", + "col217": "kpj4x", + "col218": "v4evs", + "col219": "jqs4l", + "col220": "glpr5", + "col221": "snwa9", + "col222": "9n3n7", + "col223": "9e538", + "col224": "alfpa", + "col225": "pgy90", + "col226": "t2qz0", + "col227": "3t83z", + "col228": "2srbg", + "col229": "7vmmc", + "col230": "7sd2x", + "col231": "j114o", + "col232": "bkpyb", + "col233": "kr6yr", + "col234": "e32rs", + "col235": "awjtz", + "col236": "vv8tz", + "col237": "qqfhj", + "col238": "23el6", + "col239": "8wa8r", + "col240": "fg4zn", + "col241": "hgojk", + "col242": "zdtrp", + "col243": "x147f", + "col244": "7a8wm", + "col245": "jxxkk", + "col246": "k4vp5", + "col247": "sx7so", + "col248": "x9qry", + "col249": "0t0ta", + "col250": "2zscy", + "col251": "bfd92", + "col252": "v7ntz", + "col253": "9u978", + "col254": "cr7dp", + "col255": "k3r3p", + "col256": "i82fz", + "col257": "7vlo5", + "col258": "mzs2k", + "col259": "pj8i1", + "col260": "9rpfr", + "col261": "zrlsc", + "col262": "enved", + "col263": "1m18r", + "col264": "ritg4", + "col265": "3r5bd", + "col266": "2g5e0", + "col267": "vwstu", + "col268": "aand5", + "col269": "an2nv", + "col270": "fsjcb", + "col271": "1iti8", + "col272": "o8vt1", + "col273": "8lrqf", + "col274": "4klhz", + "col275": "0ql7x", + "col276": "mvbap", + "col277": "cztw6", + "col278": "34yvh", + "col279": "wm8e8", + "col280": "sep07", + "col281": "tz2b6", + "col282": "nnkdr", + "col283": "tfkm7", + "col284": "u7u2b", + "col285": "gnrln", + "col286": "311j7", + "col287": "58m50", + "col288": "3hhtl", + "col289": "dxmmd", + "col290": "2odci", + "col291": "wrui4", + "col292": "gjfnk", + "col293": "jxgjp", + "col294": "qaat1", + "col295": "tg8vo", + "col296": "c8bp2", + "col297": "fluu2", + "col298": "ftmxw", + "col299": "jzwxd", + "col300": "pt7sf", + "col301": "bzmmo", + "col302": "q0v1t", + "col303": "waiyc", + "col304": "rh3vm", + "col305": "y0i8e", + "col306": "edhmx", + "col307": "ncphl", + "col308": "9uzfw", + "col309": "gxr4b", + "col310": "ve2jb", + "col311": "sljxu", + "col312": "fogs2", + "col313": "0t5mc", + "col314": "mbcjl", + "col315": "10mwf", + "col316": "ku32p", + "col317": "gkbrh", + "col318": "kdcd9", + "col319": "k0taq", + "col320": "5r5z7", + "col321": "mj2k8", + "col322": "vlag4", + "col323": "8hkel", + "col324": "b17e8", + "col325": "5mnki", + "col326": "mw0or", + "col327": "n8q5x", + "col328": "85lvf", + "col329": "j1x9i", + "col330": "sv3o2", + "col331": "5g34u", + "col332": "oxbea", + "col333": "h6t6w", + "col334": "x8gik", + "col335": "y3ugd", + "col336": "muq98", + "col337": "e6r80", + "col338": "hedyo", + "col339": "u6w9e", + "col340": "olc27", + "col341": "rrx2k", + "col342": "gz4cv", + "col343": "med4v", + "col344": "bpwhm", + "col345": "2m93a", + "col346": "tqcs5", + "col347": "pduix", + "col348": "3zklt", + "col349": "bgneg", + "col350": "5toc7", + "col351": "mdnsl", + "col352": "28j98", + "col353": "hy0am", + "col354": "1b72p", + "col355": "2b87i", + "col356": "gpz4g", + "col357": "lwfsg", + "col358": "7yq2u", + "col359": "2imch", + "col360": "06trz", + "col361": "b2lky", + "col362": "djzet", + "col363": "grnmf", + "col364": "yb9ag", + "col365": "sch3r", + "col366": "iulxk", + "col367": "2lhtt", + "col368": "l6zwi", + "col369": "om4yp", + "col370": "mdju9", + "col371": "auqzo", + "col372": "87fle", + "col373": "vja0u", + "col374": "9lgua", + "col375": "q0ekk", + "col376": "5updj", + "col377": "awhxc", + "col378": "jja1k", + "col379": "rpnqm", + "col380": "y6edu", + "col381": "wpwxk", + "col382": "m110h", + "col383": "l8kpj", + "col384": "nhage", + "col385": "i2qnp", + "col386": "l8g02", + "col387": "n8xqs", + "col388": "v1xkl", + "col389": "kq3oz", + "col390": "kuzxc", + "col391": "uujug", + "col392": "bm5o5", + "col393": "kvjbn", + "col394": "iusor", + "col395": "bbp8r", + "col396": "aimtr", + "col397": "81gjk", + "col398": "birot", + "col399": "0zeo1", + "col400": "ciayx", + "col401": "n9ssv", + "col402": "rdc60", + "col403": "otdxb", + "col404": "qqzz1", + "col405": "88j72", + "col406": "ymefj", + "col407": "yc9p1", + "col408": "a9jid", + "col409": "p7j5m", + "col410": "vj34d", + "col411": "ogvhg", + "col412": "46opa", + "col413": "x5rzo", + "col414": "9wno3", + "col415": "js238", + "col416": "wp9d6", + "col417": "kt3qb", + "col418": "j4dl0", + "col419": "9j6ar", + "col420": "rqws3", + "col421": "4utuw", + "col422": "40nz0", + "col423": "xqg2i", + "col424": "foo36", + "col425": "kkx44", + "col426": "jq7a6", + "col427": "x5mce", + "col428": "ni5s4", + "col429": "nj39o", + "col430": "20tnb", + "col431": "go8sz", + "col432": "f1y0r", + "col433": "01m8q", + "col434": "a6vbb", + "col435": "f5apf", + "col436": "1qetk", + "col437": "izypr", + "col438": "zghhj", + "col439": "5hlbu", + "col440": "3igeg", + "col441": "f9gwu", + "col442": "1cfr8", + "col443": "jfcnx", + "col444": "hlb1n", + "col445": "1rzig", + "col446": "d4mmr", + "col447": "oeman", + "col448": "ltg43", + "col449": "dy6qz", + "col450": "ls8h0", + "col451": "ut8w2", + "col452": "39yj2", + "col453": "6215i", + "col454": "kj8by", + "col455": "bx1x8", + "col456": "s7c2c", + "col457": "d8yv9", + "col458": "d2ux5", + "col459": "0rh2r", + "col460": "3x2s6", + "col461": "38adi", + "col462": "qx6zr", + "col463": "h0vo8", + "col464": "23i13", + "col465": "1xyy0", + "col466": "7s7fr", + "col467": "o4m33", + "col468": "c95qk", + "col469": "3pfmb", + "col470": "cdace", + "col471": "fesio", + "col472": "2awxe", + "col473": "y5v5r", + "col474": "43w3g", + "col475": "3lyw8", + "col476": "mix08", + "col477": "z8m22", + "col478": "p1rpc", + "col479": "fyv67", + "col480": "l4avm", + "col481": "xqc1q", + "col482": "lbkxl", + "col483": "bzvgl", + "col484": "drozd", + "col485": "rsdve", + "col486": "xucsl", + "col487": "r9c5u", + "col488": "b4wqp", + "col489": "xgy7i", + "col490": "7o3yj", + "col491": "0gp1a", + "col492": "yv7pm", + "col493": "ccgmz", + "col494": "w08g0", + "col495": "34wqm", + "col496": "ctpui", + "col497": "phkji", + "col498": "tesqd", + "col499": "jc2f4", + "col500": "7mwgu", + "col501": "qc50x", + "col502": "u6pfm", + "col503": "c4f5j", + "col504": "zyk4s", + "col505": "ajdla", + "col506": "2ukim", + "col507": "n6h6a", + "col508": "zdbmn", + "col509": "pn9oi", + "col510": "0i8dc", + "col511": "5q1cx", + "col512": "3ditc", + "col513": "zy9st", + "col514": "llw13", + "col515": "gcl2c", + "col516": "i7x29", + "col517": "b2qmr", + "col518": "za3mc", + "col519": "dnuxp", + "col520": "qtprx", + "col521": "ppaq7", + "col522": "8y2as", + "col523": "2u3gl", + "col524": "qaxd1", + "col525": "nj2r2", + "col526": "rwaq3", + "col527": "aj2sz", + "col528": "42n7o", + "col529": "f5od0", + "col530": "qo366", + "col531": "bwaj4", + "col532": "lwcd1", + "col533": "xg7x8", + "col534": "7o5zn", + "col535": "tpbga", + "col536": "bcflw", + "col537": "yyzns", + "col538": "14c4f", + "col539": "yfb7g", + "col540": "8rer1", + "col541": "blfxv", + "col542": "taaj1", + "col543": "4wu19", + "col544": "4d3rc", + "col545": "bfp42", + "col546": "h7r8i", + "col547": "7a317", + "col548": "bds07", + "col549": "h8sv8", + "col550": "u8pk8", + "col551": "jjikd", + "col552": "71o0r", + "col553": "eyuxe", + "col554": "em8gn", + "col555": "0q3d2", + "col556": "lplbl", + "col557": "z0sbn", + "col558": "2dnqk", + "col559": "scsja", + "col560": "qjtsg", + "col561": "4xjuq", + "col562": "9z2ld", + "col563": "bmva6", + "col564": "8vuks", + "col565": "o6oe1", + "col566": "eziwc", + "col567": "1jn17", + "col568": "tj21z", + "col569": "vp6q8", + "col570": "qahxe", + "col571": "wmwj2", + "col572": "sovo8", + "col573": "mwfri", + "col574": "9elgb", + "col575": "t5q1b", + "col576": "kl0yv", + "col577": "bpnrn", + "col578": "vjraf", + "col579": "1zgmt", + "col580": "kcl4g", + "col581": "khkly", + "col582": "t7mn8", + "col583": "5945g", + "col584": "d3u85", + "col585": "rebqg", + "col586": "hcqog", + "col587": "v9bba", + "col588": "d8nod", + "col589": "cdu3x", + "col590": "q6g6i", + "col591": "d4w5y", + "col592": "k7lp1", + "col593": "bli75", + "col594": "ao0bs", + "col595": "rgcw1", + "col596": "mh7yt", + "col597": "7inro", + "col598": "40uxz", + "col599": "td0ld", + "col600": "cgx5s", + "col601": "xhpbi", + "col602": "3ide5", + "col603": "rbhsq", + "col604": "1q6p4", + "col605": "4x8ug", + "col606": "2dj33", + "col607": "gohob", + "col608": "bofsl", + "col609": "6pjkp", + "col610": "85uxo", + "col611": "ayx9g", + "col612": "kruts", + "col613": "inewl", + "col614": "0cc1w", + "col615": "pn778", + "col616": "a1ino", + "col617": "ah4f1", + "col618": "uxl3x", + "col619": "tz0s6", + "col620": "ocy9u", + "col621": "9pkl2", + "col622": "0e3u7", + "col623": "1g0yg", + "col624": "dnsqm", + "col625": "meq2c", + "col626": "qj2ud", + "col627": "bygwh", + "col628": "a037m", + "col629": "yxg8d", + "col630": "juh0p", + "col631": "a5qj3", + "col632": "ehffz", + "col633": "d92oo", + "col634": "sgkr4", + "col635": "5a6ga", + "col636": "40vyh", + "col637": "ctcnw", + "col638": "k1gqb", + "col639": "0upbv", + "col640": "lzw1h", + "col641": "b6pu2", + "col642": "gyj33", + "col643": "eohws", + "col644": "8mmzl", + "col645": "qm9dr", + "col646": "wndaj", + "col647": "04a28", + "col648": "9pkqs", + "col649": "ynhsg", + "col650": "96hhx", + "col651": "8g53v", + "col652": "tocl7", + "col653": "q84fg", + "col654": "ulzgu", + "col655": "2qas6", + "col656": "kn6l5", + "col657": "ydeij", + "col658": "hkjgc", + "col659": "kih5s", + "col660": "23cod", + "col661": "eotjo", + "col662": "v4j1w", + "col663": "bb52z", + "col664": "zxtbw", + "col665": "6g2v4", + "col666": "atbd2", + "col667": "im9uc", + "col668": "jupk4", + "col669": "h71iu", + "col670": "nbthf", + "col671": "b0zja", + "col672": "yyfnj", + "col673": "2yhhr", + "col674": "1g25v", + "col675": "4c868", + "col676": "8c98u", + "col677": "hhqdy", + "col678": "wxbza", + "col679": "lknj4", + "col680": "l3e34", + "col681": "akxjc", + "col682": "9ptod", + "col683": "gj24e", + "col684": "hua1k", + "col685": "6530k", + "col686": "txazo", + "col687": "qlrkg", + "col688": "ymla1", + "col689": "k5px2", + "col690": "ck4bx", + "col691": "g2zyg", + "col692": "6kccm", + "col693": "ifjp2", + "col694": "ftss5", + "col695": "vlgwq", + "col696": "ex2dj", + "col697": "0ib6p", + "col698": "4dexh", + "col699": "vtw8e", + "col700": "69z95", + "col701": "t4j99", + "col702": "qxykc", + "col703": "umdcq", + "col704": "8mjta", + "col705": "lw5pu", + "col706": "gph2y", + "col707": "9zhha", + "col708": "aktx7", + "col709": "fvsow", + "col710": "oaxfl", + "col711": "cixvr", + "col712": "wv7ls", + "col713": "l538t", + "col714": "qdv41", + "col715": "83e85", + "col716": "gqash", + "col717": "1lsrq", + "col718": "s713h", + "col719": "wa43g", + "col720": "zsrxe", + "col721": "3o7bg", + "col722": "yk7y7", + "col723": "jtxh3", + "col724": "jihb1", + "col725": "74nam", + "col726": "12wiv", + "col727": "i2ab4", + "col728": "ik3as", + "col729": "l6onx", + "col730": "cgp4m", + "col731": "l9p51", + "col732": "iloso", + "col733": "ukzvx", + "col734": "58bgb", + "col735": "ukf0r", + "col736": "0x4a0", + "col737": "ujnll", + "col738": "1qoaj", + "col739": "295p5", + "col740": "qynax", + "col741": "gyflm", + "col742": "ktcxn", + "col743": "yplgz", + "col744": "3sq8t", + "col745": "0eqaq", + "col746": "h2t9m", + "col747": "jt6ns", + "col748": "kt643", + "col749": "ukzor", + "col750": "0ttb0", + "col751": "xpo8u", + "col752": "8f56w", + "col753": "slfs2", + "col754": "f5tce", + "col755": "fuesv", + "col756": "kcz4u", + "col757": "5q6vy", + "col758": "6b3dj", + "col759": "2xtgv", + "col760": "251ns", + "col761": "cemjt", + "col762": "l28eu", + "col763": "ub8t7", + "col764": "4eo3v", + "col765": "126dk", + "col766": "lu2z5", + "col767": "h6xbg", + "col768": "fkv94", + "col769": "gt9w6", + "col770": "hf0lu", + "col771": "znopa", + "col772": "wsjl4", + "col773": "hx6cp", + "col774": "56y0l", + "col775": "awrnt", + "col776": "0tkho", + "col777": "ptbc3", + "col778": "uv8kt", + "col779": "zao9h", + "col780": "rago3", + "col781": "f7sfk", + "col782": "yp62y", + "col783": "mi27y", + "col784": "j6z5m", + "col785": "ukuxh", + "col786": "244ep", + "col787": "nvdzz", + "col788": "t1qun", + "col789": "d0f2i", + "col790": "7y9an", + "col791": "v7k36", + "col792": "9qo3e", + "col793": "4c130", + "col794": "sbdxy", + "col795": "4b1w1", + "col796": "24bsm", + "col797": "319mp", + "col798": "l5y15", + "col799": "eb3b1", + "col800": "y8d4k", + "col801": "h7xlg", + "col802": "qygb2", + "col803": "0a1b2", + "col804": "klzuf", + "col805": "9xsfp", + "col806": "z0fyd", + "col807": "5y5ab", + "col808": "vys4y", + "col809": "rzcal", + "col810": "e24gp", + "col811": "a0lbv", + "col812": "ij6pf", + "col813": "wqkmp", + "col814": "wfrut", + "col815": "mteua", + "col816": "1qux4", + "col817": "pysmg", + "col818": "dlfss", + "col819": "v5txf", + "col820": "x0n0v", + "col821": "9oarh", + "col822": "tc6no", + "col823": "ogq67", + "col824": "l8gyi", + "col825": "u1os3", + "col826": "17lne", + "col827": "4sksd", + "col828": "lw2h5", + "col829": "t1zlg", + "col830": "jw2k8", + "col831": "nonls", + "col832": "cqal3", + "col833": "mpbae", + "col834": "1fqdi", + "col835": "qqeu4", + "col836": "c1k2i", + "col837": "wy9lc", + "col838": "lbbvk", + "col839": "6urgm", + "col840": "1t7t6", + "col841": "x0jwg", + "col842": "9vxtd", + "col843": "uxig0", + "col844": "uoei4", + "col845": "zm8hz", + "col846": "xs1j7", + "col847": "uhm2z", + "col848": "q1ivd", + "col849": "iqaug", + "col850": "js67p", + "col851": "0sxwu", + "col852": "b0b64", + "col853": "ha5mm", + "col854": "kaxfp", + "col855": "elx8u", + "col856": "qmlu3", + "col857": "916d7", + "col858": "tj9fi", + "col859": "v6l3w", + "col860": "achze", + "col861": "xwimu", + "col862": "0i04a", + "col863": "upcll", + "col864": "mi8pi", + "col865": "7y302", + "col866": "n1osu", + "col867": "74ols", + "col868": "w6hgf", + "col869": "t1aa1", + "col870": "gdw0w", + "col871": "dtze3", + "col872": "ismwu", + "col873": "rvm2s", + "col874": "5cdqv", + "col875": "h3il1", + "col876": "94lct", + "col877": "1wg4v", + "col878": "ntqgn", + "col879": "lcq24", + "col880": "2035e", + "col881": "9oykr", + "col882": "zgn57", + "col883": "q913e", + "col884": "deqf2", + "col885": "eze8m", + "col886": "ue0z5", + "col887": "1h65f", + "col888": "t2sr5", + "col889": "dthgj", + "col890": "dcuet", + "col891": "ox6cp", + "col892": "l4obl", + "col893": "ay00q", + "col894": "5k89j", + "col895": "3u4fq", + "col896": "2isnv", + "col897": "txag4", + "col898": "n321m", + "col899": "0wu05", + "col900": "yfwyy", + "col901": "quouu", + "col902": "gty6k", + "col903": "4clqt", + "col904": "fth08", + "col905": "q4gwi", + "col906": "0rdvf", + "col907": "td6zr", + "col908": "re2o0", + "col909": "htyl3", + "col910": "njrvs", + "col911": "p905w", + "col912": "m0phh", + "col913": "01igj", + "col914": "5h408", + "col915": "4qelj", + "col916": "lisqx", + "col917": "i8ogk", + "col918": "xy780", + "col919": "rwhol", + "col920": "0sk8a", + "col921": "v0zse", + "col922": "4t26w", + "col923": "glln9", + "col924": "09um4", + "col925": "fb3oq", + "col926": "8y12r", + "col927": "9z3a9", + "col928": "a8v1t", + "col929": "h26fz", + "col930": "mu83s", + "col931": "gdox9", + "col932": "epiji", + "col933": "lenyp", + "col934": "3mf16", + "col935": "sss6k", + "col936": "dveaz", + "col937": "7ejlp", + "col938": "ec5qm", + "col939": "1g46v", + "col940": "6n7qj", + "col941": "3ujwe", + "col942": "xm409", + "col943": "2hh3c", + "col944": "jl8l3", + "col945": "v6238", + "col946": "8msz0", + "col947": "6w6xi", + "col948": "qy69h", + "col949": "tcer0", + "col950": "y7e3c", + "col951": "azeki", + "col952": "ruek1", + "col953": "2v9sr", + "col954": "quo1b", + "col955": "plf31", + "col956": "o2ya0", + "col957": "cym25", + "col958": "s9ti7", + "col959": "5qkrj", + "col960": "6ok04", + "col961": "yl4x5", + "col962": "gwrrg", + "col963": "6wtah", + "col964": "8waom", + "col965": "6r5ai", + "col966": "iegqe", + "col967": "wa4pt", + "col968": "s1rt0", + "col969": "iw2jd", + "col970": "4cuda", + "col971": "2vrhh", + "col972": "qrt3c", + "col973": "k6c20", + "col974": "2k270", + "col975": "3smhc", + "col976": "4uz2t", + "col977": "85fi6", + "col978": "e0u4d", + "col979": "sifye", + "col980": "lfnms", + "col981": "nsdym", + "col982": "uqypv", + "col983": "gk72h", + "col984": "ur9ep", + "col985": "xnm3b", + "col986": "6t8g0", + "col987": "1ro7b", + "col988": "w12b1", + "col989": "87btj", + "col990": "y5n49", + "col991": "3c7gg", + "col992": "guirt", + "col993": "0vvn2", + "col994": "bd6b7", + "col995": "owym9", + "col996": "pou6p", + "col997": "h015d", + "col998": "5ig9r", + "col999": "5iici" + }, + { + "name": "Mona Bryan", + "gender": "female", + "col0": "8yxr7", + "col1": "vyfqv", + "col2": "tsd4e", + "col3": "3d8zd", + "col4": "k66t4", + "col5": "abae9", + "col6": "m4zo1", + "col7": "e1u98", + "col8": "uaku0", + "col9": "sp982", + "col10": "ugdtd", + "col11": "rpf3e", + "col12": "bcta4", + "col13": "z3emr", + "col14": "ng149", + "col15": "ezd0z", + "col16": "i4r3l", + "col17": "9m3tg", + "col18": "lzl2g", + "col19": "c2zws", + "col20": "fwnh9", + "col21": "49lru", + "col22": "qxjdw", + "col23": "nvph5", + "col24": "z06jh", + "col25": "ku5e3", + "col26": "cmlp3", + "col27": "ecvzb", + "col28": "1r041", + "col29": "ted16", + "col30": "my0z1", + "col31": "31srq", + "col32": "4yvrb", + "col33": "1zgay", + "col34": "dszhk", + "col35": "ygpuh", + "col36": "zyboo", + "col37": "u9z27", + "col38": "z3c8z", + "col39": "l6xbe", + "col40": "62mx0", + "col41": "5652w", + "col42": "s28cl", + "col43": "q76ar", + "col44": "3t0bl", + "col45": "9mb71", + "col46": "c0gl3", + "col47": "nmxqr", + "col48": "yqwgh", + "col49": "t3vc4", + "col50": "2jk64", + "col51": "wft0k", + "col52": "0zer6", + "col53": "zwoew", + "col54": "puqe1", + "col55": "7d16d", + "col56": "icgjm", + "col57": "t5njl", + "col58": "wc9c9", + "col59": "qpw35", + "col60": "gp6i0", + "col61": "kotux", + "col62": "1i6py", + "col63": "pwbdd", + "col64": "dsv0l", + "col65": "ubkm9", + "col66": "6fsb6", + "col67": "zb0r2", + "col68": "63m1r", + "col69": "h0x20", + "col70": "6buab", + "col71": "931g5", + "col72": "ujmuw", + "col73": "gka41", + "col74": "0hqvf", + "col75": "tcb8s", + "col76": "k614f", + "col77": "u74kb", + "col78": "1tdb5", + "col79": "guemo", + "col80": "jrglr", + "col81": "t1a6b", + "col82": "cx94h", + "col83": "5zx52", + "col84": "38f0c", + "col85": "s9yod", + "col86": "1ael9", + "col87": "x6aa6", + "col88": "25k1t", + "col89": "h9qiu", + "col90": "vft9c", + "col91": "13j5l", + "col92": "ufz2c", + "col93": "49wpf", + "col94": "1jr7e", + "col95": "ot0f4", + "col96": "0frvf", + "col97": "cf7h5", + "col98": "b4s6w", + "col99": "a4je4", + "col100": "jaaut", + "col101": "gfp2b", + "col102": "135t6", + "col103": "24lz4", + "col104": "3ondn", + "col105": "qmhj4", + "col106": "xoo0f", + "col107": "l3v8g", + "col108": "2v0yf", + "col109": "a0fpq", + "col110": "h59r2", + "col111": "w91rs", + "col112": "c92qc", + "col113": "1tif0", + "col114": "7lgb5", + "col115": "r50tx", + "col116": "blvjq", + "col117": "iaoo0", + "col118": "qy8v9", + "col119": "qmxms", + "col120": "qkdi2", + "col121": "mlolk", + "col122": "hthp6", + "col123": "kres7", + "col124": "n9d17", + "col125": "jtni2", + "col126": "nzhh4", + "col127": "b8ftn", + "col128": "ybg1i", + "col129": "y8k9z", + "col130": "7nb85", + "col131": "57ho1", + "col132": "g5m5j", + "col133": "uz5yr", + "col134": "u0t0c", + "col135": "p92v5", + "col136": "0ddah", + "col137": "gyyln", + "col138": "3y3n0", + "col139": "4rha9", + "col140": "5kbzg", + "col141": "yqhym", + "col142": "5tnbd", + "col143": "sva0r", + "col144": "p475w", + "col145": "1ddzf", + "col146": "fwmt6", + "col147": "tr4jz", + "col148": "r2gmg", + "col149": "1d0q2", + "col150": "4v71m", + "col151": "hex24", + "col152": "fmlo5", + "col153": "2p5p1", + "col154": "fas53", + "col155": "d3fd0", + "col156": "zequh", + "col157": "n1b38", + "col158": "6kxi5", + "col159": "2imz4", + "col160": "wfbsa", + "col161": "ekzzr", + "col162": "3njaf", + "col163": "7zj51", + "col164": "ujehu", + "col165": "ysc7a", + "col166": "aagrv", + "col167": "bjdc0", + "col168": "tso1v", + "col169": "ycqi7", + "col170": "0bz53", + "col171": "brzfc", + "col172": "lh69t", + "col173": "ckit4", + "col174": "m5bif", + "col175": "0ata6", + "col176": "zojc4", + "col177": "z5zds", + "col178": "zqvf4", + "col179": "ss8ym", + "col180": "r9j7b", + "col181": "kjclw", + "col182": "9fnyo", + "col183": "cyvep", + "col184": "j2nez", + "col185": "s6lj4", + "col186": "ttbpy", + "col187": "l54h7", + "col188": "tomvz", + "col189": "l9u0b", + "col190": "949je", + "col191": "412yx", + "col192": "jocfq", + "col193": "3fpyv", + "col194": "kghkw", + "col195": "pu7we", + "col196": "1lqg9", + "col197": "gjnda", + "col198": "08iyp", + "col199": "ta2yk", + "col200": "f98kz", + "col201": "1yqwz", + "col202": "ze6ll", + "col203": "0x0uu", + "col204": "xmkdy", + "col205": "j1k6b", + "col206": "p8z83", + "col207": "87tdm", + "col208": "58st6", + "col209": "ztipt", + "col210": "zzwn5", + "col211": "uremz", + "col212": "1c79z", + "col213": "lc0cz", + "col214": "fbjvu", + "col215": "3q0mb", + "col216": "itqcs", + "col217": "jkcaa", + "col218": "edytl", + "col219": "psl32", + "col220": "879yi", + "col221": "9u0la", + "col222": "etwst", + "col223": "5wlte", + "col224": "muqrd", + "col225": "8tzub", + "col226": "6cvyu", + "col227": "3tdzd", + "col228": "esxdq", + "col229": "gdqxr", + "col230": "blmog", + "col231": "st329", + "col232": "nj1hs", + "col233": "vz1u4", + "col234": "vx260", + "col235": "hkcvr", + "col236": "oxyaa", + "col237": "pat7b", + "col238": "2cgud", + "col239": "xqss2", + "col240": "zz02z", + "col241": "bcuhj", + "col242": "y0pqv", + "col243": "wdbjy", + "col244": "a17bu", + "col245": "ftni3", + "col246": "k31mb", + "col247": "zague", + "col248": "eccy9", + "col249": "7hiou", + "col250": "i5lw4", + "col251": "m75wj", + "col252": "kaxmc", + "col253": "siz6h", + "col254": "nrmhw", + "col255": "dszm8", + "col256": "hycfd", + "col257": "yjzxu", + "col258": "6c9pd", + "col259": "gaidg", + "col260": "t3pnb", + "col261": "45k8a", + "col262": "us0df", + "col263": "vjvpu", + "col264": "i42am", + "col265": "pf98l", + "col266": "yfy9a", + "col267": "2pdm8", + "col268": "ffk7u", + "col269": "7mh5w", + "col270": "wyw5j", + "col271": "zq1bh", + "col272": "xkliq", + "col273": "aeb1u", + "col274": "ei76n", + "col275": "r7xi4", + "col276": "klkvl", + "col277": "roevz", + "col278": "vo33c", + "col279": "w4ybv", + "col280": "iz69z", + "col281": "dbzxc", + "col282": "dbpvk", + "col283": "q4nut", + "col284": "7hwy5", + "col285": "q9slz", + "col286": "r1k7t", + "col287": "e6s1q", + "col288": "q3gnw", + "col289": "nd8fu", + "col290": "m3ur8", + "col291": "o1wmu", + "col292": "jzt44", + "col293": "rc0hu", + "col294": "favbp", + "col295": "lls7n", + "col296": "4sqma", + "col297": "exp2v", + "col298": "b6m84", + "col299": "au9ev", + "col300": "8njox", + "col301": "u6nqi", + "col302": "76yb6", + "col303": "dwyw5", + "col304": "yz598", + "col305": "2lxrx", + "col306": "72d2d", + "col307": "z228w", + "col308": "08hpp", + "col309": "1tgh5", + "col310": "a4r0i", + "col311": "1jdqn", + "col312": "vnbkh", + "col313": "kzevm", + "col314": "9b895", + "col315": "mmc6l", + "col316": "7paem", + "col317": "fatjb", + "col318": "w209f", + "col319": "usuyc", + "col320": "i0c31", + "col321": "v2v9g", + "col322": "s1xh4", + "col323": "z963f", + "col324": "9lu3f", + "col325": "gtk35", + "col326": "9ro3o", + "col327": "4v78o", + "col328": "c8a1p", + "col329": "183e6", + "col330": "3sbph", + "col331": "8ttzo", + "col332": "5aee9", + "col333": "lwq8n", + "col334": "gcxys", + "col335": "fls22", + "col336": "l7xb4", + "col337": "ti4mo", + "col338": "2fmwm", + "col339": "uz9xz", + "col340": "gxibw", + "col341": "jt2lx", + "col342": "1k8le", + "col343": "i1h0l", + "col344": "vma3j", + "col345": "a4wbm", + "col346": "i5cf4", + "col347": "nwfe9", + "col348": "n088r", + "col349": "c8u4m", + "col350": "ka2qx", + "col351": "064y3", + "col352": "w8hnl", + "col353": "wwan7", + "col354": "57tnm", + "col355": "m8f2n", + "col356": "8li1y", + "col357": "2golu", + "col358": "b9dez", + "col359": "9i27k", + "col360": "nisjk", + "col361": "lo1v3", + "col362": "wvihd", + "col363": "cot4l", + "col364": "uy9of", + "col365": "wtap0", + "col366": "m47gn", + "col367": "pq0ch", + "col368": "lja5e", + "col369": "0g7oh", + "col370": "yrtnz", + "col371": "nwi1w", + "col372": "j8sb3", + "col373": "8eaps", + "col374": "ce7zf", + "col375": "pi9qa", + "col376": "qhvm1", + "col377": "ciuga", + "col378": "qthk5", + "col379": "myyls", + "col380": "no1qm", + "col381": "1bs9y", + "col382": "wym7o", + "col383": "1fse6", + "col384": "093gh", + "col385": "zorxq", + "col386": "1khpb", + "col387": "hcpqr", + "col388": "qkeze", + "col389": "rjh6b", + "col390": "kgpaf", + "col391": "biso9", + "col392": "12jcp", + "col393": "by8l8", + "col394": "0hlc2", + "col395": "eqiqo", + "col396": "zsx00", + "col397": "s0w9h", + "col398": "b32aa", + "col399": "v5wh7", + "col400": "qfizy", + "col401": "53ykv", + "col402": "zk3wd", + "col403": "p39s9", + "col404": "wygx2", + "col405": "9stu7", + "col406": "fjrtl", + "col407": "sn6xz", + "col408": "0go4p", + "col409": "zp16a", + "col410": "fpxgq", + "col411": "i1q1t", + "col412": "okch6", + "col413": "akxky", + "col414": "pqoi1", + "col415": "x3a75", + "col416": "ymhak", + "col417": "mu2kk", + "col418": "zk6xi", + "col419": "t5ygf", + "col420": "p9rq1", + "col421": "t3bfq", + "col422": "oewwx", + "col423": "2pyt0", + "col424": "prjbv", + "col425": "4k0s0", + "col426": "uwjjk", + "col427": "vb38v", + "col428": "0byl2", + "col429": "nh47p", + "col430": "yxdzh", + "col431": "thn2d", + "col432": "4szic", + "col433": "jjpe4", + "col434": "ewyzq", + "col435": "6eu5x", + "col436": "m803b", + "col437": "43ofx", + "col438": "gat7m", + "col439": "rijwf", + "col440": "3smix", + "col441": "a6edc", + "col442": "9q10w", + "col443": "qcyc2", + "col444": "q8hlj", + "col445": "wvfw4", + "col446": "jul18", + "col447": "cv9fv", + "col448": "f779a", + "col449": "a0pf2", + "col450": "c3f7s", + "col451": "rfn3v", + "col452": "i54io", + "col453": "stio2", + "col454": "wowd5", + "col455": "02eqq", + "col456": "n4hyu", + "col457": "0bfy5", + "col458": "7728w", + "col459": "bdoca", + "col460": "x57yf", + "col461": "gckyt", + "col462": "lfr6a", + "col463": "w2rxz", + "col464": "aeyqp", + "col465": "5elhy", + "col466": "kg4zz", + "col467": "uqa49", + "col468": "0uuqm", + "col469": "pr1b6", + "col470": "nj01m", + "col471": "q3obp", + "col472": "4xlfu", + "col473": "7c9aa", + "col474": "jjvm2", + "col475": "levy3", + "col476": "mfzuk", + "col477": "klcya", + "col478": "iwxoi", + "col479": "aalkc", + "col480": "2v69v", + "col481": "faq9v", + "col482": "j0zqb", + "col483": "l7310", + "col484": "hf7fg", + "col485": "3ak5k", + "col486": "jlreo", + "col487": "kap8w", + "col488": "ueoqg", + "col489": "hq850", + "col490": "4ag35", + "col491": "m1gjf", + "col492": "vjz3c", + "col493": "9sdvq", + "col494": "5b85f", + "col495": "6qnbu", + "col496": "5wtc3", + "col497": "jmtei", + "col498": "248a6", + "col499": "j30lt", + "col500": "ib3ct", + "col501": "dsdjy", + "col502": "vruh0", + "col503": "wfsnk", + "col504": "bn4kh", + "col505": "1mye4", + "col506": "adjgx", + "col507": "u7g1b", + "col508": "i73la", + "col509": "1wm0d", + "col510": "h38u9", + "col511": "1lpn7", + "col512": "936xf", + "col513": "7ez80", + "col514": "1woj7", + "col515": "2b6p5", + "col516": "4c864", + "col517": "nn04t", + "col518": "t8aye", + "col519": "kwf42", + "col520": "7gls1", + "col521": "b72z1", + "col522": "3jpab", + "col523": "h5icz", + "col524": "pc1dc", + "col525": "n1zzi", + "col526": "div70", + "col527": "5j160", + "col528": "6rnlx", + "col529": "807v8", + "col530": "p8fel", + "col531": "yo479", + "col532": "n9ex9", + "col533": "7s0qi", + "col534": "clnwg", + "col535": "r0rb2", + "col536": "oy0j6", + "col537": "w36sh", + "col538": "3ocg9", + "col539": "5tsj0", + "col540": "kzb25", + "col541": "ge8fn", + "col542": "ha6sz", + "col543": "5vnx0", + "col544": "dvp89", + "col545": "wo7h3", + "col546": "h4r8l", + "col547": "pftgj", + "col548": "19ev3", + "col549": "efc4x", + "col550": "yb1uq", + "col551": "gvs5t", + "col552": "6fvpf", + "col553": "i5674", + "col554": "c26ja", + "col555": "f7pdt", + "col556": "2uk9i", + "col557": "jgqjs", + "col558": "fpaj7", + "col559": "lc2jb", + "col560": "shu69", + "col561": "kdrbm", + "col562": "83nde", + "col563": "1jnlf", + "col564": "1nazt", + "col565": "aqwi6", + "col566": "lpcqf", + "col567": "4f4ie", + "col568": "b0kn6", + "col569": "6f5nf", + "col570": "48v6b", + "col571": "qb4kt", + "col572": "m6rho", + "col573": "1tmm0", + "col574": "3lz58", + "col575": "3gd8o", + "col576": "7amj8", + "col577": "qk7v4", + "col578": "gfqnl", + "col579": "0lwsd", + "col580": "0o1mu", + "col581": "mwntz", + "col582": "1hxwp", + "col583": "tzk9z", + "col584": "j8qwz", + "col585": "xjoyk", + "col586": "9k6lq", + "col587": "w5u7y", + "col588": "wi8me", + "col589": "yxhd4", + "col590": "2o05x", + "col591": "m0xl0", + "col592": "3orkm", + "col593": "rxbzb", + "col594": "kg1yw", + "col595": "9ekvx", + "col596": "ky4c4", + "col597": "72302", + "col598": "cnt6g", + "col599": "uvzdj", + "col600": "c1ixd", + "col601": "biycy", + "col602": "kfr4o", + "col603": "qqlur", + "col604": "tsjb9", + "col605": "wst7e", + "col606": "mume0", + "col607": "25721", + "col608": "va26f", + "col609": "cv54t", + "col610": "mmqrn", + "col611": "nk7dc", + "col612": "qeb0w", + "col613": "a7xvg", + "col614": "1xzj2", + "col615": "k35gd", + "col616": "s1jlb", + "col617": "lh17k", + "col618": "vdy2r", + "col619": "zqzdg", + "col620": "igt0i", + "col621": "ne5re", + "col622": "7tr9v", + "col623": "0z0bo", + "col624": "lpg8k", + "col625": "3c4sm", + "col626": "rnsfy", + "col627": "m4dvx", + "col628": "e5itf", + "col629": "6uyah", + "col630": "knuh2", + "col631": "3dzi5", + "col632": "izekb", + "col633": "4cr75", + "col634": "tqmtg", + "col635": "tx968", + "col636": "zoye4", + "col637": "4q6ng", + "col638": "zxjdi", + "col639": "izlqd", + "col640": "j7xiu", + "col641": "pub49", + "col642": "itnkt", + "col643": "0mycf", + "col644": "0uvct", + "col645": "3y1n7", + "col646": "tly4x", + "col647": "kzwx8", + "col648": "cpbif", + "col649": "i6mxz", + "col650": "5lzfj", + "col651": "rog0n", + "col652": "91zlj", + "col653": "ee0p6", + "col654": "egres", + "col655": "9p3z0", + "col656": "vbbzc", + "col657": "4d357", + "col658": "692u4", + "col659": "hp4ny", + "col660": "dyfwx", + "col661": "4m61t", + "col662": "ut4w7", + "col663": "9e88o", + "col664": "qj9fi", + "col665": "88d77", + "col666": "8p18p", + "col667": "ke87m", + "col668": "gkvkq", + "col669": "t85hc", + "col670": "s745q", + "col671": "fnrxf", + "col672": "jf180", + "col673": "9zx5j", + "col674": "cs7xa", + "col675": "c57l0", + "col676": "biqez", + "col677": "n2ivz", + "col678": "a977q", + "col679": "qeob9", + "col680": "c7hkt", + "col681": "mo3e4", + "col682": "1v17b", + "col683": "ow1i3", + "col684": "qsovp", + "col685": "zyvjq", + "col686": "59nw7", + "col687": "76e6h", + "col688": "8w8zk", + "col689": "zas14", + "col690": "6vrcm", + "col691": "h0cpq", + "col692": "lw09p", + "col693": "i9u0m", + "col694": "u74xj", + "col695": "oqod4", + "col696": "1y2rz", + "col697": "36xyv", + "col698": "paxgn", + "col699": "5g8k0", + "col700": "ula9b", + "col701": "upp7k", + "col702": "o1pfc", + "col703": "riakk", + "col704": "9fenl", + "col705": "5u6e2", + "col706": "d83ms", + "col707": "s60c0", + "col708": "wmatx", + "col709": "efyio", + "col710": "54g3f", + "col711": "7pby0", + "col712": "4ja0s", + "col713": "w1fex", + "col714": "tq7qy", + "col715": "wtea7", + "col716": "ddlb9", + "col717": "x7r6n", + "col718": "37rtj", + "col719": "7oemb", + "col720": "spfuv", + "col721": "giwow", + "col722": "x9odu", + "col723": "d9xfc", + "col724": "fr3cy", + "col725": "pich6", + "col726": "qkagr", + "col727": "s6axd", + "col728": "mttdz", + "col729": "yq3wr", + "col730": "xeviu", + "col731": "hph4s", + "col732": "24pov", + "col733": "mi8ob", + "col734": "xh0kj", + "col735": "fuvo0", + "col736": "edc1h", + "col737": "f09ph", + "col738": "wsci6", + "col739": "many4", + "col740": "nmrzt", + "col741": "vtl78", + "col742": "hmpwa", + "col743": "xwm68", + "col744": "dccro", + "col745": "qk7co", + "col746": "fm0zw", + "col747": "25ok9", + "col748": "ko8fv", + "col749": "mtvsg", + "col750": "fuaz7", + "col751": "3aizf", + "col752": "p1t5u", + "col753": "tn7cz", + "col754": "drhyt", + "col755": "zbbkm", + "col756": "trj8r", + "col757": "3tfzb", + "col758": "7wwki", + "col759": "z3qv8", + "col760": "78lzu", + "col761": "zgxpp", + "col762": "tmeuk", + "col763": "ejgwu", + "col764": "8k2nd", + "col765": "2mk0g", + "col766": "wwj71", + "col767": "lyjja", + "col768": "t3a0k", + "col769": "tdkv0", + "col770": "a073k", + "col771": "fgqyo", + "col772": "jztdu", + "col773": "bitij", + "col774": "dhigo", + "col775": "enrmt", + "col776": "25lxr", + "col777": "8q9zk", + "col778": "6g9ab", + "col779": "y430q", + "col780": "6w70b", + "col781": "5kxzl", + "col782": "rim4i", + "col783": "pwdm7", + "col784": "a5d2x", + "col785": "gd3n0", + "col786": "t0smq", + "col787": "75az7", + "col788": "8gtot", + "col789": "0cmpi", + "col790": "ydz3g", + "col791": "chu2q", + "col792": "l3k0k", + "col793": "1an6p", + "col794": "skh01", + "col795": "6wakj", + "col796": "vn0pd", + "col797": "if8le", + "col798": "67rfg", + "col799": "r7ihk", + "col800": "0wte8", + "col801": "n1lbv", + "col802": "ogyzs", + "col803": "8h8cl", + "col804": "hjcsp", + "col805": "m5zjt", + "col806": "yw18z", + "col807": "s1ynv", + "col808": "hvs25", + "col809": "g7sgc", + "col810": "mnhdz", + "col811": "4wn7s", + "col812": "2ly6i", + "col813": "r5jzg", + "col814": "e6ffx", + "col815": "zhhwu", + "col816": "w511h", + "col817": "94vqz", + "col818": "cnqnr", + "col819": "be4to", + "col820": "vyux3", + "col821": "cpemr", + "col822": "kdiag", + "col823": "1ab9u", + "col824": "z7tzp", + "col825": "07cac", + "col826": "i9iz2", + "col827": "a231x", + "col828": "vl31w", + "col829": "a4g3w", + "col830": "t8g8s", + "col831": "wymyl", + "col832": "ybcd7", + "col833": "dk5fh", + "col834": "alvll", + "col835": "dw83k", + "col836": "h083p", + "col837": "joyg4", + "col838": "eap49", + "col839": "ak51n", + "col840": "zt1ya", + "col841": "a2e2m", + "col842": "x0689", + "col843": "9vavx", + "col844": "2qoup", + "col845": "24e0b", + "col846": "u7cfv", + "col847": "a3rw7", + "col848": "e2ulu", + "col849": "6e00q", + "col850": "zs735", + "col851": "ydmbv", + "col852": "o7du2", + "col853": "kxwfm", + "col854": "dsh3q", + "col855": "qmb3e", + "col856": "s78tq", + "col857": "5o4xi", + "col858": "9fzis", + "col859": "eins0", + "col860": "xfc5v", + "col861": "tg6fo", + "col862": "ckxh1", + "col863": "wkrz8", + "col864": "89465", + "col865": "vt8w6", + "col866": "sl6vt", + "col867": "u6dfq", + "col868": "jlnua", + "col869": "dltc6", + "col870": "u2cvl", + "col871": "3td65", + "col872": "qfjgw", + "col873": "p35f5", + "col874": "b7fkz", + "col875": "z3m8m", + "col876": "mfve5", + "col877": "8kvdl", + "col878": "ac2l0", + "col879": "gvvp9", + "col880": "mcavm", + "col881": "1qoop", + "col882": "xghbl", + "col883": "63u3s", + "col884": "ixavv", + "col885": "tin5c", + "col886": "89iqr", + "col887": "y59wb", + "col888": "l427z", + "col889": "dsu12", + "col890": "lghhj", + "col891": "yd30v", + "col892": "yoo5k", + "col893": "ldaxm", + "col894": "d532s", + "col895": "xtvic", + "col896": "kuvj6", + "col897": "ioar0", + "col898": "kxf64", + "col899": "9xed0", + "col900": "odupo", + "col901": "kfqv0", + "col902": "4d41r", + "col903": "88jch", + "col904": "sdoxf", + "col905": "jeltn", + "col906": "yohhy", + "col907": "9rm1u", + "col908": "t5bc5", + "col909": "id5oc", + "col910": "845aq", + "col911": "5t9b7", + "col912": "o56lu", + "col913": "mborw", + "col914": "glhos", + "col915": "th7gc", + "col916": "tzxdh", + "col917": "xlzvt", + "col918": "yyotg", + "col919": "8ahlz", + "col920": "2kesc", + "col921": "66ev8", + "col922": "o83su", + "col923": "ogz7f", + "col924": "gc5tt", + "col925": "qqim2", + "col926": "9fx0z", + "col927": "w61bc", + "col928": "cayvp", + "col929": "jdhg7", + "col930": "t14m9", + "col931": "ejuy2", + "col932": "bkwla", + "col933": "zc424", + "col934": "dpvgr", + "col935": "qr7vv", + "col936": "f33rb", + "col937": "y4uip", + "col938": "zr25m", + "col939": "2ft45", + "col940": "1n9c8", + "col941": "tfjvr", + "col942": "j2835", + "col943": "cvxul", + "col944": "1a16h", + "col945": "pp3wv", + "col946": "r0ft0", + "col947": "mwfah", + "col948": "rdfvg", + "col949": "lbzes", + "col950": "mkv7a", + "col951": "5u0vv", + "col952": "v69wi", + "col953": "tsmj6", + "col954": "m9gac", + "col955": "9yd5q", + "col956": "clpd9", + "col957": "1nzvo", + "col958": "k7feb", + "col959": "skixv", + "col960": "w8rea", + "col961": "bdq2o", + "col962": "bnnwp", + "col963": "28fn8", + "col964": "zwcqz", + "col965": "onona", + "col966": "ia5xd", + "col967": "5opiz", + "col968": "79gu1", + "col969": "qvxfw", + "col970": "8omgs", + "col971": "y6mj8", + "col972": "rbhs9", + "col973": "7rru5", + "col974": "m82km", + "col975": "v7qqj", + "col976": "8ls6s", + "col977": "j27wa", + "col978": "h49qf", + "col979": "lu3ps", + "col980": "gne43", + "col981": "pz5y2", + "col982": "fx2of", + "col983": "khy9e", + "col984": "nmw6z", + "col985": "4hols", + "col986": "xv5fj", + "col987": "kdrmc", + "col988": "17awk", + "col989": "82y9d", + "col990": "d9yjt", + "col991": "adaya", + "col992": "2kdob", + "col993": "eaa3r", + "col994": "v2fug", + "col995": "it3xu", + "col996": "6j2zq", + "col997": "iw7mh", + "col998": "a19tb", + "col999": "b7723" + }, + { + "name": "Vonda Lowery", + "gender": "female", + "col0": "nh07g", + "col1": "omxws", + "col2": "siohi", + "col3": "avt4m", + "col4": "lzmwo", + "col5": "ozfkb", + "col6": "pv87i", + "col7": "8a01c", + "col8": "tk5ty", + "col9": "3rdbs", + "col10": "7xv55", + "col11": "cw9lg", + "col12": "4qsdc", + "col13": "46zr2", + "col14": "kt4j6", + "col15": "npvig", + "col16": "fsj15", + "col17": "5638a", + "col18": "kqgqk", + "col19": "jcamp", + "col20": "a53y7", + "col21": "n0xxm", + "col22": "jsw6i", + "col23": "0ui9u", + "col24": "jimd9", + "col25": "54aqu", + "col26": "j92j4", + "col27": "x6cqb", + "col28": "oq61f", + "col29": "bd2ko", + "col30": "xas9y", + "col31": "0gcc4", + "col32": "0bdgk", + "col33": "z8ewn", + "col34": "y0ah1", + "col35": "lnh4n", + "col36": "6qqrk", + "col37": "irpge", + "col38": "c3f28", + "col39": "uqqfo", + "col40": "ievv7", + "col41": "7sq1c", + "col42": "k4ued", + "col43": "nw6zg", + "col44": "b3v28", + "col45": "9k0wl", + "col46": "mmfud", + "col47": "dk9gr", + "col48": "ljbuv", + "col49": "9lv46", + "col50": "fi7ej", + "col51": "hks4i", + "col52": "1qoao", + "col53": "q8q33", + "col54": "zy9ge", + "col55": "5efcs", + "col56": "hmgx7", + "col57": "fq9l9", + "col58": "151xj", + "col59": "1xybj", + "col60": "xh9d4", + "col61": "gosz9", + "col62": "ed9t0", + "col63": "q59qg", + "col64": "yc1o8", + "col65": "kjl4o", + "col66": "lck6r", + "col67": "g8myx", + "col68": "86jon", + "col69": "iczx6", + "col70": "mfu1g", + "col71": "our58", + "col72": "4mu4k", + "col73": "q18f8", + "col74": "wk5he", + "col75": "yvhr4", + "col76": "udbk8", + "col77": "vmmd2", + "col78": "47pel", + "col79": "tnso2", + "col80": "l31ys", + "col81": "h6dj9", + "col82": "bet96", + "col83": "1ylwi", + "col84": "023mw", + "col85": "vfzvq", + "col86": "tozv3", + "col87": "6e0c8", + "col88": "0rco4", + "col89": "dtspw", + "col90": "h1moz", + "col91": "n95ga", + "col92": "le51c", + "col93": "hyxt7", + "col94": "suusy", + "col95": "v7arq", + "col96": "5micq", + "col97": "9b2xz", + "col98": "f1z0u", + "col99": "s3po8", + "col100": "usrue", + "col101": "dmhof", + "col102": "oi5re", + "col103": "65dpv", + "col104": "7d4x4", + "col105": "8lt2s", + "col106": "jxtwn", + "col107": "bc3zx", + "col108": "vkl0n", + "col109": "bjdhq", + "col110": "s79u1", + "col111": "qk56t", + "col112": "o01sd", + "col113": "xrrc9", + "col114": "4rfdl", + "col115": "4pldm", + "col116": "gop90", + "col117": "kmpuo", + "col118": "xfn8c", + "col119": "lskj1", + "col120": "p8r3t", + "col121": "424j3", + "col122": "7rs00", + "col123": "xb185", + "col124": "1v6ul", + "col125": "2o05n", + "col126": "09bp1", + "col127": "hi0tt", + "col128": "3qvul", + "col129": "kozyd", + "col130": "r4ywc", + "col131": "2ppoz", + "col132": "tzyqh", + "col133": "a82g4", + "col134": "c4a23", + "col135": "20nkj", + "col136": "dl4fh", + "col137": "pg43k", + "col138": "mre60", + "col139": "mgqom", + "col140": "wd0bp", + "col141": "2r97y", + "col142": "tx325", + "col143": "mdm6p", + "col144": "twaq6", + "col145": "ju049", + "col146": "3xfht", + "col147": "oa3lq", + "col148": "m4ahx", + "col149": "lluva", + "col150": "kvzc0", + "col151": "gfj3c", + "col152": "goos7", + "col153": "7z371", + "col154": "491xo", + "col155": "z1k3w", + "col156": "nymm8", + "col157": "pw8jd", + "col158": "kxk51", + "col159": "g3aua", + "col160": "mzoun", + "col161": "8m6gl", + "col162": "bk6df", + "col163": "rb4l2", + "col164": "vrkk0", + "col165": "g89ec", + "col166": "nto65", + "col167": "iosr3", + "col168": "7a5p8", + "col169": "0vxwn", + "col170": "q9im6", + "col171": "ub9tz", + "col172": "fw95l", + "col173": "3nl5h", + "col174": "av1op", + "col175": "b6xtg", + "col176": "3pz89", + "col177": "p79kh", + "col178": "c8ggi", + "col179": "a6eng", + "col180": "4jr3l", + "col181": "blhez", + "col182": "4nqu4", + "col183": "g2ide", + "col184": "7xhds", + "col185": "e0d4n", + "col186": "6213k", + "col187": "3gbve", + "col188": "1beop", + "col189": "87ny9", + "col190": "0b3ut", + "col191": "ceb8v", + "col192": "dzk5c", + "col193": "u9l17", + "col194": "n9rpe", + "col195": "jrx0k", + "col196": "fkv41", + "col197": "f0wgc", + "col198": "crhxz", + "col199": "i2q8f", + "col200": "d88z3", + "col201": "jt0qv", + "col202": "1ecvn", + "col203": "zrd8r", + "col204": "cf8v7", + "col205": "k41wo", + "col206": "ba5eo", + "col207": "hf5hl", + "col208": "ounax", + "col209": "nelbx", + "col210": "6wldd", + "col211": "2elyh", + "col212": "oab5o", + "col213": "j39by", + "col214": "0xv4m", + "col215": "q6x7f", + "col216": "ha4hb", + "col217": "ehxdu", + "col218": "o7ufi", + "col219": "56550", + "col220": "um1mf", + "col221": "theba", + "col222": "h411l", + "col223": "293g0", + "col224": "ejsq4", + "col225": "p20mh", + "col226": "bqtxm", + "col227": "9n0ce", + "col228": "0iwlz", + "col229": "cngp0", + "col230": "ez2rc", + "col231": "ti28j", + "col232": "wjhs1", + "col233": "dji0q", + "col234": "5dnu7", + "col235": "502qn", + "col236": "ld3rd", + "col237": "4ylen", + "col238": "iyhvu", + "col239": "b26y2", + "col240": "ggxox", + "col241": "u2ofc", + "col242": "ipi33", + "col243": "2unu7", + "col244": "g6zk7", + "col245": "0eph8", + "col246": "sxheu", + "col247": "de2ut", + "col248": "5z7us", + "col249": "c1myd", + "col250": "fe2ll", + "col251": "if9qk", + "col252": "qs3le", + "col253": "0ymvl", + "col254": "g9yk0", + "col255": "r0pt1", + "col256": "vutyd", + "col257": "swr6o", + "col258": "lo5i4", + "col259": "96r59", + "col260": "jsgpx", + "col261": "h94cq", + "col262": "9t8gk", + "col263": "vx9ll", + "col264": "w8f8t", + "col265": "43y8p", + "col266": "uoc29", + "col267": "0jci0", + "col268": "qq1kw", + "col269": "l5g47", + "col270": "4eko0", + "col271": "rugpp", + "col272": "q4mmb", + "col273": "tzary", + "col274": "w3d4g", + "col275": "4zeo6", + "col276": "lkj17", + "col277": "mki78", + "col278": "dmat3", + "col279": "wcchc", + "col280": "ghzs8", + "col281": "m4820", + "col282": "v7nbs", + "col283": "hu9jg", + "col284": "impep", + "col285": "5p5de", + "col286": "jprhp", + "col287": "o6gjs", + "col288": "nzlm2", + "col289": "d7ysc", + "col290": "j1gdy", + "col291": "cwf4b", + "col292": "12yf3", + "col293": "18kk8", + "col294": "x3x9e", + "col295": "t5dcb", + "col296": "weis8", + "col297": "twyyi", + "col298": "tvbv7", + "col299": "vkvqr", + "col300": "i92yb", + "col301": "li9tk", + "col302": "gepow", + "col303": "3tnh4", + "col304": "vp6ou", + "col305": "qnj4y", + "col306": "df0pp", + "col307": "943ct", + "col308": "9gngf", + "col309": "slygc", + "col310": "bvvg9", + "col311": "p513o", + "col312": "zmqz6", + "col313": "a8cm9", + "col314": "mribr", + "col315": "7befd", + "col316": "ccvfj", + "col317": "vnvre", + "col318": "ol0zz", + "col319": "e3c1y", + "col320": "tfxx9", + "col321": "zr937", + "col322": "jgwnr", + "col323": "x6i01", + "col324": "2z6rt", + "col325": "i8amr", + "col326": "d1m96", + "col327": "2q0i5", + "col328": "vrjqh", + "col329": "zc4ae", + "col330": "u92kj", + "col331": "k8vco", + "col332": "dagma", + "col333": "a6zhw", + "col334": "mzom9", + "col335": "6yzxv", + "col336": "it3rz", + "col337": "evba6", + "col338": "h06h9", + "col339": "7f2a2", + "col340": "y897x", + "col341": "r2mln", + "col342": "fxh8j", + "col343": "flg0m", + "col344": "wyvce", + "col345": "ehpvi", + "col346": "12yvm", + "col347": "z67qh", + "col348": "q04vc", + "col349": "3wsp3", + "col350": "67lnb", + "col351": "euzcr", + "col352": "zefi1", + "col353": "by1cz", + "col354": "k6xsv", + "col355": "vmkwr", + "col356": "79jiu", + "col357": "s8ejf", + "col358": "bh661", + "col359": "6i851", + "col360": "znvkn", + "col361": "8pke1", + "col362": "61jm9", + "col363": "d2klr", + "col364": "78uus", + "col365": "asppt", + "col366": "y6m5r", + "col367": "uf1zg", + "col368": "77yhz", + "col369": "8hh4m", + "col370": "48ioq", + "col371": "fatzy", + "col372": "divj3", + "col373": "qtix8", + "col374": "hd10l", + "col375": "e7k1v", + "col376": "0fjq7", + "col377": "afi7z", + "col378": "pmwdv", + "col379": "xw4kl", + "col380": "bm3mv", + "col381": "rm27c", + "col382": "7mibc", + "col383": "vcex8", + "col384": "ch8ng", + "col385": "9mmm9", + "col386": "2k7c5", + "col387": "qpzzi", + "col388": "rloes", + "col389": "npf1o", + "col390": "2tk8l", + "col391": "1d4mp", + "col392": "ouazm", + "col393": "ps1s6", + "col394": "4na1z", + "col395": "l2zbb", + "col396": "l3xwr", + "col397": "9dxp4", + "col398": "jrvza", + "col399": "qrir5", + "col400": "dawi9", + "col401": "ebx51", + "col402": "e3e0u", + "col403": "qkynj", + "col404": "69ti5", + "col405": "1snzd", + "col406": "6b327", + "col407": "ofbyy", + "col408": "ns5d4", + "col409": "6l1ip", + "col410": "ofz51", + "col411": "qy7bc", + "col412": "puc90", + "col413": "xiz0g", + "col414": "k2xi8", + "col415": "8gz1z", + "col416": "manl7", + "col417": "lvdkr", + "col418": "6m90s", + "col419": "bnszq", + "col420": "z65ox", + "col421": "majuj", + "col422": "niw28", + "col423": "vw4ud", + "col424": "dy68k", + "col425": "711bb", + "col426": "65zmo", + "col427": "pnrdw", + "col428": "ttc90", + "col429": "wzjhs", + "col430": "an5et", + "col431": "b7p2a", + "col432": "rlo0r", + "col433": "hqpwk", + "col434": "aug9h", + "col435": "mxl1v", + "col436": "n5tzt", + "col437": "spikt", + "col438": "eyf0k", + "col439": "6npag", + "col440": "qmpj1", + "col441": "q0sei", + "col442": "ntt5u", + "col443": "m6xt3", + "col444": "ohlyp", + "col445": "ki3jp", + "col446": "avfux", + "col447": "ll4i8", + "col448": "1c97i", + "col449": "sta9e", + "col450": "kkmlx", + "col451": "ebbcc", + "col452": "5hzuh", + "col453": "7gpjm", + "col454": "k7ytd", + "col455": "7bgsx", + "col456": "o736a", + "col457": "mr6ra", + "col458": "eomew", + "col459": "6va06", + "col460": "ov6xd", + "col461": "l1ohw", + "col462": "i5br7", + "col463": "jex44", + "col464": "cfdx5", + "col465": "nutsb", + "col466": "fezsi", + "col467": "phkmp", + "col468": "xigog", + "col469": "vy3b8", + "col470": "pwwh1", + "col471": "kd3ic", + "col472": "xmowj", + "col473": "xmt2p", + "col474": "ukt1g", + "col475": "oko0p", + "col476": "kn1w7", + "col477": "2tkei", + "col478": "n3hbv", + "col479": "z1va8", + "col480": "1f76l", + "col481": "l74jv", + "col482": "f0w6v", + "col483": "4ahcy", + "col484": "stape", + "col485": "0gabl", + "col486": "zxmz7", + "col487": "105zc", + "col488": "798a2", + "col489": "pociq", + "col490": "28836", + "col491": "tv5t2", + "col492": "814fu", + "col493": "xsxke", + "col494": "3442s", + "col495": "fci3c", + "col496": "9xveh", + "col497": "mmzc9", + "col498": "z71lv", + "col499": "t4gzc", + "col500": "nbrtp", + "col501": "mqzyy", + "col502": "r2zid", + "col503": "pye68", + "col504": "ftwl5", + "col505": "vyifu", + "col506": "vp6yv", + "col507": "106ij", + "col508": "57ijo", + "col509": "u87uc", + "col510": "jr52c", + "col511": "tkvyf", + "col512": "qr08x", + "col513": "zj2g8", + "col514": "j1yev", + "col515": "i27bn", + "col516": "gwpxy", + "col517": "vn6a4", + "col518": "4f7zi", + "col519": "xv23v", + "col520": "15lrt", + "col521": "k4o90", + "col522": "b8bvh", + "col523": "bizm9", + "col524": "u8yp5", + "col525": "ued00", + "col526": "6ete5", + "col527": "ccmne", + "col528": "1e5r6", + "col529": "mvc66", + "col530": "4s4jc", + "col531": "0im1e", + "col532": "c9dwu", + "col533": "r50bh", + "col534": "kfrpq", + "col535": "sl24x", + "col536": "npzzj", + "col537": "ynp9s", + "col538": "fi3m9", + "col539": "qaq5b", + "col540": "jmosy", + "col541": "hxoop", + "col542": "nx00w", + "col543": "xkfba", + "col544": "m99rw", + "col545": "3km2m", + "col546": "d3n80", + "col547": "129mj", + "col548": "xfg9g", + "col549": "qgww4", + "col550": "jcv8t", + "col551": "1f0uh", + "col552": "og1xh", + "col553": "r5fox", + "col554": "62u36", + "col555": "u6smp", + "col556": "9r98o", + "col557": "tq6bo", + "col558": "qlno8", + "col559": "zfuyo", + "col560": "cwu8a", + "col561": "7z1q9", + "col562": "5pgm1", + "col563": "hf86q", + "col564": "oxr34", + "col565": "udh3l", + "col566": "iq2oq", + "col567": "nlg6s", + "col568": "9ok06", + "col569": "d77os", + "col570": "tmara", + "col571": "6owzd", + "col572": "qv7gr", + "col573": "760iz", + "col574": "ybcub", + "col575": "nxmuf", + "col576": "msiub", + "col577": "t3gsu", + "col578": "6xfg6", + "col579": "r2ay6", + "col580": "bsiq4", + "col581": "kcc8z", + "col582": "4vtgg", + "col583": "jwuhw", + "col584": "uujuv", + "col585": "3tm97", + "col586": "84eb6", + "col587": "0slrj", + "col588": "jmj3m", + "col589": "mlhjc", + "col590": "7kzi0", + "col591": "xzq7l", + "col592": "8c7t4", + "col593": "y5lsb", + "col594": "tc7kv", + "col595": "achwz", + "col596": "2eovw", + "col597": "jcxgi", + "col598": "9rifk", + "col599": "fpgu7", + "col600": "jekub", + "col601": "61tvh", + "col602": "u5a59", + "col603": "gaw1j", + "col604": "7y1y9", + "col605": "3r1ub", + "col606": "gaj9l", + "col607": "jzfkj", + "col608": "ticx3", + "col609": "r36v9", + "col610": "cosaa", + "col611": "obgso", + "col612": "s52h6", + "col613": "0ylzm", + "col614": "6m8sb", + "col615": "sew8g", + "col616": "j91or", + "col617": "m3tp9", + "col618": "ssi5c", + "col619": "zwul1", + "col620": "kyqj1", + "col621": "qpls7", + "col622": "1y019", + "col623": "4lxgv", + "col624": "7hber", + "col625": "d0yzi", + "col626": "z56f8", + "col627": "ytvt2", + "col628": "fxdjg", + "col629": "9ge1s", + "col630": "24qyc", + "col631": "rqfk0", + "col632": "6cxxj", + "col633": "t5sev", + "col634": "iv84j", + "col635": "igop8", + "col636": "fej2g", + "col637": "1l865", + "col638": "zmyrk", + "col639": "dlvc1", + "col640": "cq37e", + "col641": "1k04p", + "col642": "r2eh3", + "col643": "4enxw", + "col644": "10v5t", + "col645": "sal5j", + "col646": "xvlgj", + "col647": "obiqn", + "col648": "d3sqf", + "col649": "u7dkb", + "col650": "cas8l", + "col651": "80kmi", + "col652": "9vz6u", + "col653": "umby4", + "col654": "6ds1d", + "col655": "ry0ln", + "col656": "pxjh4", + "col657": "yvwse", + "col658": "arig7", + "col659": "am1gw", + "col660": "sy0h6", + "col661": "49sxp", + "col662": "lavqn", + "col663": "hhdwe", + "col664": "7e1oa", + "col665": "qfvpd", + "col666": "46er5", + "col667": "16kck", + "col668": "uogb6", + "col669": "sypet", + "col670": "tnlsa", + "col671": "s2wzf", + "col672": "bso8t", + "col673": "ahs2r", + "col674": "05lh6", + "col675": "kizh5", + "col676": "irj2v", + "col677": "nk6t4", + "col678": "wuiso", + "col679": "wweq8", + "col680": "20egt", + "col681": "ww4r0", + "col682": "1wi04", + "col683": "r2ou8", + "col684": "8k54z", + "col685": "v7rs9", + "col686": "9tbsw", + "col687": "owtge", + "col688": "eg2rf", + "col689": "oov3x", + "col690": "u5vsd", + "col691": "nq3k0", + "col692": "vpxss", + "col693": "mnfrw", + "col694": "52udh", + "col695": "hewto", + "col696": "i73sg", + "col697": "oauiw", + "col698": "hez25", + "col699": "f5r3n", + "col700": "dlgp5", + "col701": "26p1e", + "col702": "736me", + "col703": "ehesa", + "col704": "fruns", + "col705": "gali5", + "col706": "ext69", + "col707": "mox1c", + "col708": "n6pss", + "col709": "9tolz", + "col710": "jz0l8", + "col711": "rwafj", + "col712": "zi14o", + "col713": "3xath", + "col714": "rvjnu", + "col715": "9lfq1", + "col716": "eybfo", + "col717": "os6rz", + "col718": "jm35a", + "col719": "oggpr", + "col720": "g3yss", + "col721": "b54pe", + "col722": "za9tx", + "col723": "dl26n", + "col724": "x2xs5", + "col725": "r6idh", + "col726": "qg1ss", + "col727": "2xtt6", + "col728": "wuk87", + "col729": "yog6q", + "col730": "ygh5n", + "col731": "de9sl", + "col732": "uvlph", + "col733": "z0taa", + "col734": "2fc91", + "col735": "hk2kz", + "col736": "u8aey", + "col737": "79sua", + "col738": "yeqek", + "col739": "uu5dq", + "col740": "5joyf", + "col741": "r8gof", + "col742": "tl7dh", + "col743": "11j0q", + "col744": "j3t9y", + "col745": "ayssx", + "col746": "n1ux0", + "col747": "lai9g", + "col748": "ojtgu", + "col749": "ifk7u", + "col750": "4x1q4", + "col751": "jobzn", + "col752": "8paq1", + "col753": "sibhw", + "col754": "xd7dg", + "col755": "vshg4", + "col756": "qpg5c", + "col757": "u5gv6", + "col758": "9f50k", + "col759": "k32je", + "col760": "pz5jl", + "col761": "zb7io", + "col762": "ywnxf", + "col763": "ortzy", + "col764": "ohycs", + "col765": "edgll", + "col766": "o2taw", + "col767": "6jtdc", + "col768": "o888w", + "col769": "q7rvl", + "col770": "7gxl7", + "col771": "5trfw", + "col772": "h0oh7", + "col773": "8uumz", + "col774": "jeppz", + "col775": "4wwcy", + "col776": "y8bke", + "col777": "21w0y", + "col778": "t7vt7", + "col779": "z5d9g", + "col780": "j67tm", + "col781": "04jgx", + "col782": "xgmad", + "col783": "1etsf", + "col784": "2icsu", + "col785": "edrhe", + "col786": "3kebl", + "col787": "8hogb", + "col788": "bir45", + "col789": "jjjnv", + "col790": "je3i8", + "col791": "9tiwl", + "col792": "vk0rx", + "col793": "i27nj", + "col794": "ke8cj", + "col795": "44vlv", + "col796": "115hh", + "col797": "ys6ys", + "col798": "oqp4i", + "col799": "utsy9", + "col800": "9pa9n", + "col801": "o3n7l", + "col802": "jx9wt", + "col803": "a1z8u", + "col804": "q9855", + "col805": "qayq1", + "col806": "wkka7", + "col807": "24xnv", + "col808": "ljcag", + "col809": "qhw7d", + "col810": "3vycf", + "col811": "yc0n0", + "col812": "p8r3h", + "col813": "7k1im", + "col814": "zz8u9", + "col815": "lixj5", + "col816": "7nef0", + "col817": "pw1ay", + "col818": "lhvsk", + "col819": "pe04x", + "col820": "zygbo", + "col821": "xjf97", + "col822": "hoz7p", + "col823": "y7flc", + "col824": "jet5w", + "col825": "f9jbn", + "col826": "db1sl", + "col827": "qybun", + "col828": "dh09a", + "col829": "mj324", + "col830": "npfvv", + "col831": "rd7si", + "col832": "aqy25", + "col833": "lciqz", + "col834": "5z973", + "col835": "vtx4q", + "col836": "bqs0a", + "col837": "jx9qs", + "col838": "bmlre", + "col839": "cme9q", + "col840": "jewvr", + "col841": "0ulku", + "col842": "sksgm", + "col843": "8bfua", + "col844": "m4cyq", + "col845": "gaeam", + "col846": "z8l0j", + "col847": "ptgpp", + "col848": "crk09", + "col849": "1s9n5", + "col850": "3aihq", + "col851": "w1aqa", + "col852": "q3ho4", + "col853": "tzgpn", + "col854": "fahx6", + "col855": "e4yya", + "col856": "eetxm", + "col857": "1bd56", + "col858": "x2vwb", + "col859": "el69w", + "col860": "ds1de", + "col861": "6lrcj", + "col862": "22daz", + "col863": "5eg61", + "col864": "4ssny", + "col865": "kgdhx", + "col866": "tlimn", + "col867": "5ps4b", + "col868": "92n2w", + "col869": "n1b87", + "col870": "eam07", + "col871": "2bmnj", + "col872": "53ece", + "col873": "cbugo", + "col874": "82dgo", + "col875": "4w1se", + "col876": "qfizd", + "col877": "0ak55", + "col878": "edxll", + "col879": "b8zih", + "col880": "w81x5", + "col881": "7pg4e", + "col882": "w60or", + "col883": "gu6ex", + "col884": "ar6ls", + "col885": "oz7i2", + "col886": "7rv89", + "col887": "ousih", + "col888": "nzyuc", + "col889": "41t2l", + "col890": "jakdz", + "col891": "tpcmb", + "col892": "omge3", + "col893": "b8mvn", + "col894": "6spww", + "col895": "mjdw1", + "col896": "4yfq1", + "col897": "g06et", + "col898": "mh1sr", + "col899": "q4vva", + "col900": "hhdfv", + "col901": "b8xz6", + "col902": "ge1ow", + "col903": "jon4k", + "col904": "8fgtc", + "col905": "q8af2", + "col906": "uh7f5", + "col907": "vnnem", + "col908": "ulknj", + "col909": "m00lm", + "col910": "cq57a", + "col911": "iy9t7", + "col912": "j7ham", + "col913": "l030a", + "col914": "d33a7", + "col915": "cv7wr", + "col916": "qq8wu", + "col917": "4f2sc", + "col918": "nbmcc", + "col919": "k3x66", + "col920": "gxbyc", + "col921": "1tbvj", + "col922": "t2hz0", + "col923": "krg8t", + "col924": "7yp97", + "col925": "fm4m3", + "col926": "8nfn0", + "col927": "cb4te", + "col928": "cpzng", + "col929": "hzgvh", + "col930": "jhr4m", + "col931": "hsznd", + "col932": "a1r9a", + "col933": "kqq64", + "col934": "r9kjv", + "col935": "oyenx", + "col936": "kad4p", + "col937": "b5alx", + "col938": "b9e2l", + "col939": "dkbjd", + "col940": "k0cr3", + "col941": "9xoig", + "col942": "0kw3f", + "col943": "8i05x", + "col944": "bd41m", + "col945": "wxc3n", + "col946": "9tt73", + "col947": "qu79r", + "col948": "v3pjc", + "col949": "bp8bt", + "col950": "3otje", + "col951": "lo2wb", + "col952": "0iixc", + "col953": "l7s4l", + "col954": "tjhk5", + "col955": "l2ind", + "col956": "6iul7", + "col957": "uiv4u", + "col958": "rwpw7", + "col959": "79qdi", + "col960": "65ozn", + "col961": "1lje5", + "col962": "8n88i", + "col963": "8hub9", + "col964": "0aivp", + "col965": "bw6di", + "col966": "ryjbn", + "col967": "ahgdc", + "col968": "1h3g1", + "col969": "3gbxy", + "col970": "523j5", + "col971": "fq478", + "col972": "ucp7y", + "col973": "s7r3m", + "col974": "s8iug", + "col975": "ak7q4", + "col976": "ke2si", + "col977": "tqp5y", + "col978": "f3eb8", + "col979": "gfqid", + "col980": "u16g3", + "col981": "qw5mp", + "col982": "z0eil", + "col983": "d6nx9", + "col984": "03mc8", + "col985": "5fqcj", + "col986": "66smv", + "col987": "79q7p", + "col988": "njywt", + "col989": "w8wjr", + "col990": "5qiu3", + "col991": "ip2er", + "col992": "r8k6i", + "col993": "lhdt8", + "col994": "z7wu7", + "col995": "pwsgv", + "col996": "9lgm2", + "col997": "b101r", + "col998": "7o9rn", + "col999": "1n1xk" + }, + { + "name": "Sparks Montoya", + "gender": "male", + "col0": "nghmq", + "col1": "pjfml", + "col2": "wdxmx", + "col3": "cehad", + "col4": "v8elc", + "col5": "y1w19", + "col6": "n5go3", + "col7": "v4q3e", + "col8": "3jbhh", + "col9": "m18g3", + "col10": "nwsf7", + "col11": "tsb56", + "col12": "h1sax", + "col13": "ml9rd", + "col14": "fcts9", + "col15": "eenhy", + "col16": "ydcna", + "col17": "dblg5", + "col18": "aa1gk", + "col19": "xcgnf", + "col20": "4eqge", + "col21": "ohndm", + "col22": "4n1jn", + "col23": "dag70", + "col24": "kwdgw", + "col25": "3vvlh", + "col26": "61b4x", + "col27": "vwavq", + "col28": "sa1o5", + "col29": "xi9c0", + "col30": "edx8c", + "col31": "ujqz0", + "col32": "yqodt", + "col33": "b1yhq", + "col34": "5wpxn", + "col35": "f1n78", + "col36": "5j920", + "col37": "x25uo", + "col38": "gx334", + "col39": "8153i", + "col40": "wpat0", + "col41": "j6ath", + "col42": "tk2g2", + "col43": "050zq", + "col44": "060km", + "col45": "xdinm", + "col46": "701sm", + "col47": "15jqb", + "col48": "yg9aa", + "col49": "mkrua", + "col50": "2twtm", + "col51": "tbzzm", + "col52": "cm23w", + "col53": "rtljz", + "col54": "5cgjb", + "col55": "w519u", + "col56": "da1al", + "col57": "dp9ne", + "col58": "kw41s", + "col59": "hiaw1", + "col60": "l30m6", + "col61": "r7duw", + "col62": "9ayl3", + "col63": "mt2rx", + "col64": "s3w82", + "col65": "2r1fu", + "col66": "7vv2q", + "col67": "4avj1", + "col68": "41qwj", + "col69": "9neaf", + "col70": "qnrtv", + "col71": "ld1fs", + "col72": "zbkdq", + "col73": "0t0x0", + "col74": "8l2yr", + "col75": "1p73m", + "col76": "1tdpi", + "col77": "dx0wa", + "col78": "mkjwk", + "col79": "s6kuo", + "col80": "use6y", + "col81": "hzk9z", + "col82": "8lt03", + "col83": "ufgtd", + "col84": "hgqkj", + "col85": "mrniy", + "col86": "p5vkv", + "col87": "hcbi5", + "col88": "9vrrt", + "col89": "na02e", + "col90": "t1xah", + "col91": "g4m92", + "col92": "en9wq", + "col93": "32yju", + "col94": "r9woe", + "col95": "y4gfc", + "col96": "8cx64", + "col97": "uj3qv", + "col98": "5qo06", + "col99": "vjbi3", + "col100": "fkhez", + "col101": "fzhk7", + "col102": "vlum9", + "col103": "d4qdq", + "col104": "ngkhu", + "col105": "muv3r", + "col106": "6z1cx", + "col107": "st4jc", + "col108": "5g0c2", + "col109": "krcmb", + "col110": "5mdmq", + "col111": "84qqk", + "col112": "wybrt", + "col113": "yeus4", + "col114": "5a3ef", + "col115": "ozibx", + "col116": "pcy7i", + "col117": "6falm", + "col118": "heykf", + "col119": "nla91", + "col120": "l39w3", + "col121": "xtmmq", + "col122": "84106", + "col123": "qwx5j", + "col124": "odbcf", + "col125": "70wu1", + "col126": "sdg9n", + "col127": "94i78", + "col128": "3eknq", + "col129": "gclqc", + "col130": "9rmy0", + "col131": "o1bhz", + "col132": "q0by0", + "col133": "bm75g", + "col134": "9hmd3", + "col135": "oojca", + "col136": "d1qjv", + "col137": "5al4f", + "col138": "4jyzd", + "col139": "u7q0o", + "col140": "82z7a", + "col141": "n07vk", + "col142": "zfs9i", + "col143": "mtcmu", + "col144": "qwiw9", + "col145": "v61eu", + "col146": "ao7cl", + "col147": "xolgt", + "col148": "p20xh", + "col149": "9juzj", + "col150": "ura1t", + "col151": "d9nlj", + "col152": "2lldb", + "col153": "cvrfy", + "col154": "4b8o8", + "col155": "inzl6", + "col156": "ot3ru", + "col157": "1u1vy", + "col158": "hkd0f", + "col159": "fooqe", + "col160": "f7ce4", + "col161": "y5ve9", + "col162": "k955i", + "col163": "3dop4", + "col164": "29o5y", + "col165": "gbmb3", + "col166": "gl1sn", + "col167": "ui5th", + "col168": "tcxj4", + "col169": "35mir", + "col170": "kywrd", + "col171": "2fbrb", + "col172": "w2nd1", + "col173": "jedo7", + "col174": "fq7la", + "col175": "p34uj", + "col176": "voajk", + "col177": "vbi9o", + "col178": "hx8t9", + "col179": "yw9ul", + "col180": "46v69", + "col181": "xgo00", + "col182": "u5cyw", + "col183": "n2slu", + "col184": "rwgve", + "col185": "14zyt", + "col186": "nrs0x", + "col187": "zevkl", + "col188": "0to5z", + "col189": "0socg", + "col190": "0srs3", + "col191": "kv5sb", + "col192": "2m1kp", + "col193": "yvvma", + "col194": "49igq", + "col195": "iwgqt", + "col196": "nhxc5", + "col197": "kinyz", + "col198": "olfze", + "col199": "y8wo3", + "col200": "n6gnq", + "col201": "t2fdy", + "col202": "44vn2", + "col203": "sjlnn", + "col204": "1era5", + "col205": "my7x3", + "col206": "7p4ho", + "col207": "22oh9", + "col208": "x7q1u", + "col209": "xjy5o", + "col210": "rjqec", + "col211": "1dgfl", + "col212": "zsig0", + "col213": "ohmg8", + "col214": "47xj2", + "col215": "f1206", + "col216": "kemip", + "col217": "t278c", + "col218": "jdrrb", + "col219": "49mkl", + "col220": "wx34y", + "col221": "svxik", + "col222": "qhzqr", + "col223": "k4ift", + "col224": "k184y", + "col225": "2zjdb", + "col226": "pa4xw", + "col227": "zvwb3", + "col228": "66fsd", + "col229": "shy5f", + "col230": "mtdjc", + "col231": "mghtq", + "col232": "tynuo", + "col233": "69ftt", + "col234": "zju2a", + "col235": "ve6p6", + "col236": "8lhzl", + "col237": "p3dcq", + "col238": "b5lr0", + "col239": "38pss", + "col240": "2scts", + "col241": "rzhmj", + "col242": "e83wc", + "col243": "jwdt2", + "col244": "xn6ya", + "col245": "ox1gn", + "col246": "2k79q", + "col247": "awq4g", + "col248": "v2hwx", + "col249": "zfl6q", + "col250": "6q48n", + "col251": "q9xwn", + "col252": "45a4i", + "col253": "mk0jx", + "col254": "1f99i", + "col255": "rr12u", + "col256": "gs5ip", + "col257": "w6xxp", + "col258": "32c8a", + "col259": "txz8j", + "col260": "70xqs", + "col261": "6h5gn", + "col262": "jucqb", + "col263": "y2rps", + "col264": "4jg5j", + "col265": "rm9km", + "col266": "s5399", + "col267": "4e3ia", + "col268": "0qooq", + "col269": "9eihy", + "col270": "lc7s4", + "col271": "eyrwn", + "col272": "ct7oy", + "col273": "wcrrd", + "col274": "q4fpp", + "col275": "drmi8", + "col276": "rkryc", + "col277": "dtcdu", + "col278": "opnub", + "col279": "aeg3v", + "col280": "htrat", + "col281": "nxa1l", + "col282": "1lc6r", + "col283": "ipmju", + "col284": "37oxw", + "col285": "5de27", + "col286": "o12dg", + "col287": "pqu9x", + "col288": "6mrbz", + "col289": "lpws0", + "col290": "js28l", + "col291": "50iib", + "col292": "p6uiz", + "col293": "l6j9z", + "col294": "g1rze", + "col295": "h2gfb", + "col296": "ih2tb", + "col297": "epmjg", + "col298": "snfcu", + "col299": "u8wlj", + "col300": "a2xg0", + "col301": "zeynz", + "col302": "w4z6p", + "col303": "z2sm9", + "col304": "v60jm", + "col305": "lcj63", + "col306": "hk6v8", + "col307": "nqdb9", + "col308": "tr2ut", + "col309": "lq0fm", + "col310": "mukj2", + "col311": "xewhb", + "col312": "5zysv", + "col313": "lhqnz", + "col314": "vm846", + "col315": "wws5m", + "col316": "1h5y1", + "col317": "1b6ab", + "col318": "8mhq2", + "col319": "c2t79", + "col320": "dwyvh", + "col321": "2uj1d", + "col322": "41o9o", + "col323": "roh7t", + "col324": "b4lyp", + "col325": "r0vh1", + "col326": "dmmo0", + "col327": "y9g6x", + "col328": "0mnwi", + "col329": "64j6q", + "col330": "137r7", + "col331": "jbu3d", + "col332": "cdrsj", + "col333": "65t5r", + "col334": "jpybi", + "col335": "k28xm", + "col336": "39k60", + "col337": "exeus", + "col338": "lr99g", + "col339": "27yt3", + "col340": "h6uht", + "col341": "fzwjz", + "col342": "ig9it", + "col343": "3vzhg", + "col344": "8mz5z", + "col345": "p5kvl", + "col346": "6u6y3", + "col347": "fpq3o", + "col348": "p5haj", + "col349": "9og0j", + "col350": "h0h86", + "col351": "sgk3v", + "col352": "3tn4g", + "col353": "ndoo9", + "col354": "ovlip", + "col355": "2vgdt", + "col356": "pxg8d", + "col357": "fckyk", + "col358": "5e7nn", + "col359": "636ue", + "col360": "1ck3e", + "col361": "sjntx", + "col362": "ouvsx", + "col363": "ahiwe", + "col364": "ou2jb", + "col365": "chq5n", + "col366": "lt8jl", + "col367": "n9o2y", + "col368": "88ylf", + "col369": "5uxcf", + "col370": "avh38", + "col371": "p1613", + "col372": "m09wz", + "col373": "l45sz", + "col374": "w4se7", + "col375": "583gz", + "col376": "3hnms", + "col377": "epbhq", + "col378": "7vbu1", + "col379": "tmw40", + "col380": "ncr9b", + "col381": "voix5", + "col382": "1eib5", + "col383": "3uebx", + "col384": "afon4", + "col385": "nzfwa", + "col386": "3lkvv", + "col387": "2an14", + "col388": "ycapt", + "col389": "7wt7p", + "col390": "buz6e", + "col391": "tsasg", + "col392": "nq82a", + "col393": "ywbt5", + "col394": "7g979", + "col395": "gxibc", + "col396": "ln60i", + "col397": "0fptb", + "col398": "sbz19", + "col399": "2xpaf", + "col400": "cixxd", + "col401": "dhtep", + "col402": "ghg6r", + "col403": "qbcpv", + "col404": "ell14", + "col405": "hl7bu", + "col406": "gctq7", + "col407": "12uu9", + "col408": "izsjf", + "col409": "9envq", + "col410": "c59e9", + "col411": "26j94", + "col412": "3efpz", + "col413": "2qfy3", + "col414": "ve8wf", + "col415": "h0j9n", + "col416": "b29rq", + "col417": "ml6eh", + "col418": "uha4k", + "col419": "c7g4t", + "col420": "ypio7", + "col421": "jtw0x", + "col422": "tlbra", + "col423": "t38v3", + "col424": "qhjrw", + "col425": "0apvi", + "col426": "homv2", + "col427": "8c34q", + "col428": "lb317", + "col429": "iiqgh", + "col430": "v227u", + "col431": "1qui4", + "col432": "pr5hm", + "col433": "r22xc", + "col434": "c478s", + "col435": "p58oc", + "col436": "enp66", + "col437": "suwqi", + "col438": "yfjhe", + "col439": "8vd8w", + "col440": "koza8", + "col441": "7mhcg", + "col442": "gvbk8", + "col443": "52u2r", + "col444": "y8i4t", + "col445": "pgfuw", + "col446": "gnekg", + "col447": "qzj7f", + "col448": "x4woy", + "col449": "z2v24", + "col450": "2z29i", + "col451": "n0766", + "col452": "8x4fb", + "col453": "qs8xh", + "col454": "qorlb", + "col455": "8yrhk", + "col456": "h0fh0", + "col457": "pr4ny", + "col458": "m59s3", + "col459": "ztq07", + "col460": "4m66e", + "col461": "6sn0e", + "col462": "90gdg", + "col463": "woq5s", + "col464": "m8qjk", + "col465": "ef9yl", + "col466": "pyxf8", + "col467": "la4a9", + "col468": "pjz88", + "col469": "28zig", + "col470": "wtt0o", + "col471": "4nodm", + "col472": "6xn88", + "col473": "2l9q9", + "col474": "5f4t3", + "col475": "c6rzk", + "col476": "s099c", + "col477": "we20g", + "col478": "9po2r", + "col479": "lu50w", + "col480": "b7i41", + "col481": "7d5ex", + "col482": "kx76b", + "col483": "hrz1l", + "col484": "0vtmn", + "col485": "k0rvk", + "col486": "nrw1r", + "col487": "qe90r", + "col488": "m1ys6", + "col489": "i84cf", + "col490": "nh7k5", + "col491": "lhcp6", + "col492": "d85l4", + "col493": "apucn", + "col494": "fdeil", + "col495": "y9jg0", + "col496": "l6w2y", + "col497": "bq89b", + "col498": "nwios", + "col499": "1wvkh", + "col500": "u9ign", + "col501": "psk85", + "col502": "02wqo", + "col503": "hmsjy", + "col504": "zv8tg", + "col505": "cq945", + "col506": "60vuz", + "col507": "oikdv", + "col508": "eqw2r", + "col509": "h7tn8", + "col510": "owg5s", + "col511": "pvcpx", + "col512": "4vkex", + "col513": "oxblj", + "col514": "ok1ae", + "col515": "0wyt2", + "col516": "n2t9z", + "col517": "yt27q", + "col518": "c2q3z", + "col519": "7w93f", + "col520": "rnjq7", + "col521": "si8yu", + "col522": "efaad", + "col523": "wqgbd", + "col524": "9kreg", + "col525": "rhys3", + "col526": "bdgi9", + "col527": "lc1kz", + "col528": "c8c9y", + "col529": "2fsie", + "col530": "ijhzj", + "col531": "w66zb", + "col532": "833js", + "col533": "monah", + "col534": "6balw", + "col535": "k49ev", + "col536": "mwayx", + "col537": "latt6", + "col538": "di8gm", + "col539": "2te0a", + "col540": "xqzgk", + "col541": "0vkgg", + "col542": "2uqpn", + "col543": "2tpi3", + "col544": "lf1ng", + "col545": "q2xld", + "col546": "sy7mp", + "col547": "qx988", + "col548": "0qrso", + "col549": "8xjd4", + "col550": "1ybw4", + "col551": "7uwf8", + "col552": "8pdlw", + "col553": "igkgz", + "col554": "td345", + "col555": "alw7z", + "col556": "uujsm", + "col557": "8raff", + "col558": "re3jb", + "col559": "16iib", + "col560": "kgctj", + "col561": "vyrv1", + "col562": "dlau5", + "col563": "w2716", + "col564": "mp8sz", + "col565": "7p07r", + "col566": "ds0v7", + "col567": "un8qp", + "col568": "ongja", + "col569": "lxkpv", + "col570": "bcaua", + "col571": "oi665", + "col572": "xzfra", + "col573": "3479d", + "col574": "9icyj", + "col575": "rtfah", + "col576": "4kp1v", + "col577": "1ukxx", + "col578": "k1biy", + "col579": "s05go", + "col580": "acot8", + "col581": "pe6d8", + "col582": "04ro5", + "col583": "f0wef", + "col584": "l02n2", + "col585": "lyflg", + "col586": "1jn0t", + "col587": "fjqce", + "col588": "tpw97", + "col589": "37tjk", + "col590": "vspvg", + "col591": "s8pqk", + "col592": "ghh2l", + "col593": "mwfnu", + "col594": "lxeyl", + "col595": "7kib5", + "col596": "xzsng", + "col597": "1kyg8", + "col598": "ftmz9", + "col599": "xniz9", + "col600": "ly6i8", + "col601": "g2o9r", + "col602": "ijj29", + "col603": "u34ye", + "col604": "vn5cj", + "col605": "alroi", + "col606": "c9zqy", + "col607": "4knru", + "col608": "ocibl", + "col609": "kduxf", + "col610": "q5hh0", + "col611": "rip7y", + "col612": "ovojm", + "col613": "s97br", + "col614": "jdtdf", + "col615": "86yjz", + "col616": "o2cfl", + "col617": "k2piw", + "col618": "qvf5l", + "col619": "0rky0", + "col620": "vzn50", + "col621": "57mrf", + "col622": "14pnj", + "col623": "xgpc7", + "col624": "zyf5k", + "col625": "5ofem", + "col626": "d5h6v", + "col627": "lqi6u", + "col628": "18l24", + "col629": "sty2y", + "col630": "wszy1", + "col631": "eyl6g", + "col632": "q51e0", + "col633": "q756e", + "col634": "vqqha", + "col635": "dsgza", + "col636": "3o4db", + "col637": "tak8e", + "col638": "cn8fz", + "col639": "qgt0o", + "col640": "lylfa", + "col641": "h9c34", + "col642": "dp5gc", + "col643": "zf1fu", + "col644": "trp76", + "col645": "r7bqp", + "col646": "z6egd", + "col647": "uolix", + "col648": "o5qgz", + "col649": "c9wrt", + "col650": "47aao", + "col651": "9edzj", + "col652": "8zf7s", + "col653": "qynuc", + "col654": "7xb1c", + "col655": "nsw9m", + "col656": "fvvjq", + "col657": "ynexq", + "col658": "5vu25", + "col659": "4ft3o", + "col660": "2xwru", + "col661": "zvqjg", + "col662": "wo25o", + "col663": "hh1ak", + "col664": "mffp7", + "col665": "geh0o", + "col666": "k3nyr", + "col667": "a2k0i", + "col668": "ayqvj", + "col669": "qf4e4", + "col670": "9pfio", + "col671": "nn9ie", + "col672": "4o2p6", + "col673": "a2i0i", + "col674": "p3fbc", + "col675": "5ohop", + "col676": "jamuj", + "col677": "o9q2k", + "col678": "d6h1k", + "col679": "s6hjn", + "col680": "0kekr", + "col681": "x2vrn", + "col682": "0yrlp", + "col683": "ba0ej", + "col684": "nutpp", + "col685": "q02q4", + "col686": "95h6l", + "col687": "6ifzd", + "col688": "8yhvm", + "col689": "mdzpv", + "col690": "3sded", + "col691": "6c0ch", + "col692": "ipqxz", + "col693": "66c4l", + "col694": "c13br", + "col695": "tx52d", + "col696": "jy00t", + "col697": "ulj41", + "col698": "yns3h", + "col699": "t3i62", + "col700": "ee0k0", + "col701": "zza8m", + "col702": "hjm3r", + "col703": "c67g1", + "col704": "samvo", + "col705": "cnylm", + "col706": "43d6a", + "col707": "uiun7", + "col708": "zmkzd", + "col709": "0x730", + "col710": "nk5m6", + "col711": "pd49r", + "col712": "9b4kr", + "col713": "h6iv2", + "col714": "rc0t5", + "col715": "64edd", + "col716": "q71fc", + "col717": "w1ocw", + "col718": "9piw0", + "col719": "kyuwi", + "col720": "f5qlm", + "col721": "phqi3", + "col722": "88zq9", + "col723": "fnbqn", + "col724": "tyzi8", + "col725": "pzfhk", + "col726": "64f4a", + "col727": "ewvsm", + "col728": "g30uq", + "col729": "osauv", + "col730": "d6ap9", + "col731": "4ytpy", + "col732": "t4lsf", + "col733": "anj1t", + "col734": "kuoj2", + "col735": "bfszl", + "col736": "8eb4p", + "col737": "p9xlh", + "col738": "3zztz", + "col739": "m5axa", + "col740": "bbq18", + "col741": "5jpxn", + "col742": "8doku", + "col743": "vg1l7", + "col744": "8k942", + "col745": "d4s7a", + "col746": "yllq8", + "col747": "7m2p2", + "col748": "50fxi", + "col749": "wpavf", + "col750": "39ygb", + "col751": "qnpo6", + "col752": "mym3f", + "col753": "c1e8z", + "col754": "059dz", + "col755": "rt5cs", + "col756": "0f1kx", + "col757": "zctmy", + "col758": "zexgq", + "col759": "36plk", + "col760": "w7yt4", + "col761": "c7n78", + "col762": "6mlcy", + "col763": "op8it", + "col764": "2p8b9", + "col765": "ze98r", + "col766": "2rhb8", + "col767": "zosnf", + "col768": "6f302", + "col769": "hvq1m", + "col770": "616k1", + "col771": "41m15", + "col772": "gvyrl", + "col773": "nvbmv", + "col774": "t0lok", + "col775": "jdfls", + "col776": "dm6mp", + "col777": "er5b7", + "col778": "873ir", + "col779": "ygd49", + "col780": "07xwe", + "col781": "dm4eq", + "col782": "mtub0", + "col783": "radcz", + "col784": "v1igk", + "col785": "inwok", + "col786": "plmmn", + "col787": "j6y9z", + "col788": "iw974", + "col789": "7oi8u", + "col790": "jnv13", + "col791": "d1hrf", + "col792": "hem11", + "col793": "dupnb", + "col794": "hxdul", + "col795": "uspbp", + "col796": "asar1", + "col797": "ez99b", + "col798": "6au01", + "col799": "o1ph5", + "col800": "uqmcw", + "col801": "3emrv", + "col802": "vjn9c", + "col803": "viq7p", + "col804": "pk2cd", + "col805": "tbwmc", + "col806": "yvhix", + "col807": "qykfi", + "col808": "edeao", + "col809": "9pgtq", + "col810": "9dot5", + "col811": "o7xko", + "col812": "my6bn", + "col813": "6j30c", + "col814": "7i1gn", + "col815": "6iun1", + "col816": "bonmx", + "col817": "qd8l3", + "col818": "d9u6e", + "col819": "760fw", + "col820": "mzwcs", + "col821": "qz58o", + "col822": "y85s9", + "col823": "2evmn", + "col824": "ddh93", + "col825": "ajryt", + "col826": "3w0ya", + "col827": "y1chv", + "col828": "mh2t1", + "col829": "l4ji9", + "col830": "r1yrx", + "col831": "518p8", + "col832": "54crl", + "col833": "ecfxy", + "col834": "zuipy", + "col835": "agg7n", + "col836": "o845e", + "col837": "fmkoh", + "col838": "5grac", + "col839": "2ik5k", + "col840": "xun7c", + "col841": "yb0vq", + "col842": "s6pbg", + "col843": "wbp8x", + "col844": "vr51g", + "col845": "fb4ug", + "col846": "f7p4d", + "col847": "jogsr", + "col848": "xagxp", + "col849": "743ro", + "col850": "edlez", + "col851": "blstr", + "col852": "fltkv", + "col853": "lja61", + "col854": "2nchl", + "col855": "lydey", + "col856": "n9bmu", + "col857": "02yfu", + "col858": "yhsuy", + "col859": "36fsc", + "col860": "wxchy", + "col861": "u4njx", + "col862": "anznl", + "col863": "f1zhy", + "col864": "pz2ry", + "col865": "r8wrn", + "col866": "j665g", + "col867": "jqgnk", + "col868": "lrft8", + "col869": "bv1v4", + "col870": "7opnn", + "col871": "mmhcp", + "col872": "24w7p", + "col873": "jmr7y", + "col874": "uejna", + "col875": "qt2ca", + "col876": "77azq", + "col877": "xq683", + "col878": "go1py", + "col879": "qhxef", + "col880": "u4tbk", + "col881": "9na9j", + "col882": "x5s5m", + "col883": "sztmq", + "col884": "6f2qg", + "col885": "038pn", + "col886": "vcfil", + "col887": "la8ug", + "col888": "58p52", + "col889": "06hqj", + "col890": "xqm84", + "col891": "1yzh1", + "col892": "oj0wt", + "col893": "ngqms", + "col894": "0uezk", + "col895": "sxm7r", + "col896": "48wzc", + "col897": "qp458", + "col898": "if0xi", + "col899": "uwa91", + "col900": "04who", + "col901": "etmd1", + "col902": "1nll1", + "col903": "fzumj", + "col904": "ezko7", + "col905": "fyj02", + "col906": "woyez", + "col907": "ao5kb", + "col908": "3ztb1", + "col909": "eshcj", + "col910": "gme3l", + "col911": "b2mon", + "col912": "zpb2k", + "col913": "v4ofb", + "col914": "wzxqw", + "col915": "3agek", + "col916": "zpy8k", + "col917": "v6mdl", + "col918": "b7cc9", + "col919": "rmrk8", + "col920": "3ui66", + "col921": "9cqzv", + "col922": "yqn4m", + "col923": "mpluy", + "col924": "chvsb", + "col925": "tir41", + "col926": "4qh8l", + "col927": "zr73j", + "col928": "pzuo1", + "col929": "mlnkn", + "col930": "cn365", + "col931": "it694", + "col932": "szwde", + "col933": "wj53d", + "col934": "2oqm0", + "col935": "04n1g", + "col936": "hygz3", + "col937": "klwte", + "col938": "i8ujq", + "col939": "3hht3", + "col940": "zzs0s", + "col941": "2jfqh", + "col942": "l1dja", + "col943": "zgyc9", + "col944": "4zydq", + "col945": "dxaw3", + "col946": "9y4jh", + "col947": "nseco", + "col948": "f0036", + "col949": "ntuk8", + "col950": "0onpg", + "col951": "90rp1", + "col952": "u0p82", + "col953": "zx6a9", + "col954": "6xgi3", + "col955": "lfuge", + "col956": "hobxi", + "col957": "coon9", + "col958": "sg6z6", + "col959": "ac1cp", + "col960": "nal1i", + "col961": "76cmn", + "col962": "6e4gu", + "col963": "l7shn", + "col964": "f9862", + "col965": "zpt13", + "col966": "7s9iv", + "col967": "01xzd", + "col968": "dv2bp", + "col969": "b9b7b", + "col970": "ikeg0", + "col971": "mh430", + "col972": "0vz1q", + "col973": "r4gqs", + "col974": "bnyqe", + "col975": "d6t5l", + "col976": "wvfar", + "col977": "b6x7n", + "col978": "owxs3", + "col979": "i41lh", + "col980": "q2zuk", + "col981": "9lf3k", + "col982": "jh1ct", + "col983": "42nzq", + "col984": "xkozz", + "col985": "zu30r", + "col986": "azmwp", + "col987": "9rpqo", + "col988": "arobx", + "col989": "zd42v", + "col990": "ma3i1", + "col991": "nrpfu", + "col992": "tmou2", + "col993": "7szpz", + "col994": "rbeub", + "col995": "bbm64", + "col996": "w6ev9", + "col997": "v2lgy", + "col998": "9ihaj", + "col999": "ith9d" + }, + { + "name": "Casey Newton", + "gender": "female", + "col0": "175c0", + "col1": "4d0zu", + "col2": "vcesj", + "col3": "z0r85", + "col4": "clei4", + "col5": "9ma1e", + "col6": "ww9rc", + "col7": "wehms", + "col8": "de9n3", + "col9": "rsmeo", + "col10": "565p8", + "col11": "fonlf", + "col12": "mnky4", + "col13": "6ef5b", + "col14": "uge9x", + "col15": "x607a", + "col16": "3pwzj", + "col17": "68hi3", + "col18": "lyd10", + "col19": "yaqbf", + "col20": "fsobp", + "col21": "tu3w0", + "col22": "uq2xx", + "col23": "m0706", + "col24": "0zisq", + "col25": "15de6", + "col26": "jgdzy", + "col27": "kfqli", + "col28": "sy9js", + "col29": "mu9ay", + "col30": "gbg07", + "col31": "ty1w4", + "col32": "hdrl5", + "col33": "6edbx", + "col34": "qh722", + "col35": "8cldi", + "col36": "f67er", + "col37": "pxlfn", + "col38": "ej6r9", + "col39": "jeaxm", + "col40": "5tgc2", + "col41": "yq2or", + "col42": "8lfhh", + "col43": "4b0rd", + "col44": "2idoo", + "col45": "a64e1", + "col46": "7th41", + "col47": "ftas1", + "col48": "yppbt", + "col49": "apd53", + "col50": "cdttx", + "col51": "aextc", + "col52": "2fb8j", + "col53": "bkabi", + "col54": "5esjg", + "col55": "33uyy", + "col56": "fx6gi", + "col57": "4uv1q", + "col58": "uu05d", + "col59": "e3lbi", + "col60": "03x66", + "col61": "erm2c", + "col62": "99cu9", + "col63": "vs1pw", + "col64": "momxe", + "col65": "cx6a3", + "col66": "nj2q5", + "col67": "e4nmr", + "col68": "q2ff1", + "col69": "hxspj", + "col70": "vi69l", + "col71": "q76r4", + "col72": "tuwy6", + "col73": "zr3vh", + "col74": "ntxvp", + "col75": "4qijv", + "col76": "5p4jg", + "col77": "ndcuv", + "col78": "75n5s", + "col79": "sie0g", + "col80": "w2far", + "col81": "bpkx9", + "col82": "eo9tc", + "col83": "pp2ct", + "col84": "lksua", + "col85": "etzlq", + "col86": "3ajkt", + "col87": "m9bof", + "col88": "btvc0", + "col89": "z4qda", + "col90": "em00f", + "col91": "4ss9c", + "col92": "73kmj", + "col93": "iee0l", + "col94": "zr6n8", + "col95": "zoyga", + "col96": "bdee5", + "col97": "9fjgd", + "col98": "h61jl", + "col99": "7hf0f", + "col100": "x87dq", + "col101": "8wt08", + "col102": "i1tkn", + "col103": "nfvzl", + "col104": "zf6jt", + "col105": "s8nrg", + "col106": "8bp1p", + "col107": "djalr", + "col108": "tpcab", + "col109": "zkcis", + "col110": "yd23m", + "col111": "v38nv", + "col112": "twvea", + "col113": "7sfiu", + "col114": "z7kkn", + "col115": "lezb3", + "col116": "8dikz", + "col117": "446ca", + "col118": "vgfwj", + "col119": "fkuor", + "col120": "0pqjr", + "col121": "nt7er", + "col122": "pgkgz", + "col123": "wy7hg", + "col124": "uxx0z", + "col125": "yep35", + "col126": "ow2ok", + "col127": "pu0q4", + "col128": "5g0mg", + "col129": "uu2s9", + "col130": "fwll9", + "col131": "5ch2b", + "col132": "xu2uo", + "col133": "3j4ao", + "col134": "wx5r9", + "col135": "hrx6p", + "col136": "brb5y", + "col137": "mh487", + "col138": "90zu1", + "col139": "rlpvt", + "col140": "qau7d", + "col141": "3p8yw", + "col142": "5h4fj", + "col143": "fsike", + "col144": "2lcxa", + "col145": "9j3gu", + "col146": "t0zn9", + "col147": "3i65k", + "col148": "wttkv", + "col149": "sgm6w", + "col150": "d911k", + "col151": "4r6vr", + "col152": "wkpka", + "col153": "6xsva", + "col154": "08mut", + "col155": "rdhfx", + "col156": "6mb0i", + "col157": "cbrd6", + "col158": "uaz82", + "col159": "gcnhh", + "col160": "raxlw", + "col161": "3uu9x", + "col162": "4x5pa", + "col163": "iw89o", + "col164": "h44ff", + "col165": "q18e3", + "col166": "v0r6d", + "col167": "wvu3p", + "col168": "0x20e", + "col169": "oj5oq", + "col170": "nxxyx", + "col171": "871hu", + "col172": "zdipe", + "col173": "gcsd3", + "col174": "lyowr", + "col175": "7olf2", + "col176": "is4gy", + "col177": "4mxih", + "col178": "a23lh", + "col179": "hqzwr", + "col180": "cir02", + "col181": "2ntve", + "col182": "4yu57", + "col183": "io24l", + "col184": "qmq9k", + "col185": "ocnkb", + "col186": "rb40x", + "col187": "pan36", + "col188": "849eo", + "col189": "djbme", + "col190": "w5kyn", + "col191": "g583z", + "col192": "a7gof", + "col193": "u9a4s", + "col194": "vkt2g", + "col195": "e7kib", + "col196": "pc7kb", + "col197": "7y83k", + "col198": "9jv6f", + "col199": "2jath", + "col200": "wyvv9", + "col201": "0taxl", + "col202": "7u1ht", + "col203": "tpmqu", + "col204": "4jgi2", + "col205": "xxizv", + "col206": "ebx4x", + "col207": "etqat", + "col208": "oth84", + "col209": "5lbwo", + "col210": "uolf3", + "col211": "xh5ct", + "col212": "xytsg", + "col213": "vv54p", + "col214": "bg60b", + "col215": "enmaj", + "col216": "yax6o", + "col217": "2rcox", + "col218": "14edg", + "col219": "tldjw", + "col220": "229qi", + "col221": "djq89", + "col222": "rrmh4", + "col223": "zsx82", + "col224": "j3yaa", + "col225": "5ia3h", + "col226": "nri09", + "col227": "wkptq", + "col228": "osbfz", + "col229": "f9f8z", + "col230": "anl6l", + "col231": "l4z5i", + "col232": "vyqa8", + "col233": "oorpf", + "col234": "0s9q4", + "col235": "7n3y7", + "col236": "g1vox", + "col237": "1ip94", + "col238": "8hnch", + "col239": "qvh3a", + "col240": "f3o8c", + "col241": "69zov", + "col242": "60zvo", + "col243": "axxah", + "col244": "ermv5", + "col245": "wcrml", + "col246": "lnesh", + "col247": "s3du7", + "col248": "3hjwk", + "col249": "kb1tt", + "col250": "e1lr7", + "col251": "ggohd", + "col252": "xic92", + "col253": "zbfpz", + "col254": "sikbr", + "col255": "s58ms", + "col256": "qcv7v", + "col257": "c5xv2", + "col258": "38scd", + "col259": "jrn62", + "col260": "ihlb4", + "col261": "zckjz", + "col262": "mzf5c", + "col263": "puu3e", + "col264": "suomd", + "col265": "z4z7r", + "col266": "fvs1x", + "col267": "l45i3", + "col268": "cuzjv", + "col269": "txj8g", + "col270": "4xgt1", + "col271": "p79q3", + "col272": "nh5qw", + "col273": "kx1yx", + "col274": "y1i2l", + "col275": "71udg", + "col276": "wbyaa", + "col277": "6gpx1", + "col278": "70h3b", + "col279": "l29fg", + "col280": "adj8f", + "col281": "kke3n", + "col282": "obpxq", + "col283": "9atya", + "col284": "q90oq", + "col285": "g5gfo", + "col286": "q175s", + "col287": "qlpmj", + "col288": "0x2rb", + "col289": "zbsm5", + "col290": "51trt", + "col291": "nxn8e", + "col292": "jnfru", + "col293": "f943b", + "col294": "smd2b", + "col295": "0rep0", + "col296": "e5077", + "col297": "hvyrx", + "col298": "uoajz", + "col299": "6vwrm", + "col300": "d44gr", + "col301": "5y4j6", + "col302": "39v9l", + "col303": "wm436", + "col304": "47w9s", + "col305": "esa8g", + "col306": "ropmc", + "col307": "j1mwt", + "col308": "btikm", + "col309": "8gom7", + "col310": "ydevs", + "col311": "95ma1", + "col312": "9m9ks", + "col313": "vxs3p", + "col314": "2nex8", + "col315": "gghf2", + "col316": "9heyy", + "col317": "f7yg5", + "col318": "mz7zb", + "col319": "w0lk6", + "col320": "z9205", + "col321": "cg6d2", + "col322": "tmmlx", + "col323": "kknl9", + "col324": "65a60", + "col325": "xyuek", + "col326": "ndlxf", + "col327": "tzzu6", + "col328": "7l76d", + "col329": "4z7li", + "col330": "rdo89", + "col331": "5c3fw", + "col332": "vc6py", + "col333": "kbyl1", + "col334": "80inu", + "col335": "s1y7t", + "col336": "ae0ab", + "col337": "sziw8", + "col338": "ohjnp", + "col339": "0ohxy", + "col340": "axukq", + "col341": "bmvzo", + "col342": "44sb7", + "col343": "tkhjw", + "col344": "0rvyk", + "col345": "6oluc", + "col346": "be1nb", + "col347": "2p59q", + "col348": "93l4m", + "col349": "50t4s", + "col350": "q9lrt", + "col351": "i1ubp", + "col352": "kr1jy", + "col353": "2klwn", + "col354": "2131t", + "col355": "krtfz", + "col356": "tknit", + "col357": "r4nof", + "col358": "70rm3", + "col359": "8aokm", + "col360": "fmgkj", + "col361": "fb26c", + "col362": "fqhp4", + "col363": "5f0gp", + "col364": "bpbn1", + "col365": "d85uw", + "col366": "lemoz", + "col367": "e47az", + "col368": "83lfg", + "col369": "vnb3j", + "col370": "rtz7x", + "col371": "8tlr6", + "col372": "2x1kk", + "col373": "wgrfo", + "col374": "rfzps", + "col375": "fbvtr", + "col376": "r1nso", + "col377": "4dr6w", + "col378": "rd0ak", + "col379": "ivasu", + "col380": "66pdn", + "col381": "rt50f", + "col382": "uknqf", + "col383": "w7pnf", + "col384": "exa07", + "col385": "5lqt0", + "col386": "u8qvl", + "col387": "qbzrn", + "col388": "s6r7j", + "col389": "6nbxm", + "col390": "4jqs0", + "col391": "i50c3", + "col392": "nb0jz", + "col393": "t8l6s", + "col394": "hc3da", + "col395": "m0pv8", + "col396": "0cgep", + "col397": "s81mw", + "col398": "vgchz", + "col399": "0l1g8", + "col400": "7qttv", + "col401": "xl2nt", + "col402": "41p7j", + "col403": "l6y6y", + "col404": "9yond", + "col405": "nvz22", + "col406": "3cjfb", + "col407": "zluep", + "col408": "vd7t6", + "col409": "5pmsh", + "col410": "m7hph", + "col411": "rjrsw", + "col412": "d9lfi", + "col413": "clz7g", + "col414": "j6yqz", + "col415": "xpj0y", + "col416": "g599y", + "col417": "n6qvg", + "col418": "zlqxk", + "col419": "u8kdf", + "col420": "ivbwh", + "col421": "ufy7p", + "col422": "p5nkn", + "col423": "rz2ku", + "col424": "27uip", + "col425": "78shb", + "col426": "g605f", + "col427": "qc0ei", + "col428": "0t6jh", + "col429": "k9lw8", + "col430": "i47cw", + "col431": "7zt54", + "col432": "8ihjx", + "col433": "2c2g0", + "col434": "4xlpt", + "col435": "narfa", + "col436": "32cr7", + "col437": "t3qw6", + "col438": "kjhd8", + "col439": "fqnf9", + "col440": "mpg7k", + "col441": "8xp97", + "col442": "bcxgc", + "col443": "9oscj", + "col444": "dufeu", + "col445": "qrz2q", + "col446": "dyvi1", + "col447": "6ygvr", + "col448": "4sykr", + "col449": "frx31", + "col450": "k99ij", + "col451": "1j8k4", + "col452": "rt5o1", + "col453": "zxrjl", + "col454": "4dy94", + "col455": "252wt", + "col456": "6x9lv", + "col457": "m5kbf", + "col458": "tm214", + "col459": "a5ep9", + "col460": "j1f3t", + "col461": "zhuwn", + "col462": "5p70k", + "col463": "7mjqy", + "col464": "6sw3y", + "col465": "8w05x", + "col466": "7oqbw", + "col467": "5vcrr", + "col468": "n2omz", + "col469": "1xbcj", + "col470": "otnr6", + "col471": "htnrs", + "col472": "labdo", + "col473": "uprqi", + "col474": "zn1ed", + "col475": "atngc", + "col476": "2cc65", + "col477": "kjf0k", + "col478": "44lat", + "col479": "m3yj5", + "col480": "pcjt6", + "col481": "8bla0", + "col482": "r0f5o", + "col483": "zmcbe", + "col484": "kzd7r", + "col485": "69ouq", + "col486": "h0yjk", + "col487": "0hm31", + "col488": "sp4si", + "col489": "pirfi", + "col490": "6j55b", + "col491": "n9vgt", + "col492": "yvg6o", + "col493": "xo0ff", + "col494": "v7zd6", + "col495": "gpwsl", + "col496": "xc7yv", + "col497": "25d62", + "col498": "o2iey", + "col499": "lo61o", + "col500": "fd7ml", + "col501": "we7o6", + "col502": "r1cyj", + "col503": "ayzr0", + "col504": "7loyj", + "col505": "8ngxm", + "col506": "e85cg", + "col507": "3lrnr", + "col508": "ry9m9", + "col509": "lomz8", + "col510": "3plpe", + "col511": "7dggr", + "col512": "oj1da", + "col513": "1imne", + "col514": "qrzd1", + "col515": "x45vk", + "col516": "nmjdj", + "col517": "ow9qz", + "col518": "6t36s", + "col519": "g48zs", + "col520": "pc0q2", + "col521": "snk98", + "col522": "wcam6", + "col523": "t37gy", + "col524": "umoon", + "col525": "ex6sj", + "col526": "lyd11", + "col527": "y7jsj", + "col528": "3t31y", + "col529": "azi5h", + "col530": "f4gqu", + "col531": "krqrt", + "col532": "gix9j", + "col533": "wp33f", + "col534": "93c3w", + "col535": "1svms", + "col536": "m20j8", + "col537": "d0c6f", + "col538": "jf1tz", + "col539": "48orc", + "col540": "u0xys", + "col541": "xmhy3", + "col542": "piood", + "col543": "h62wv", + "col544": "b3lww", + "col545": "np942", + "col546": "3bz8k", + "col547": "90cc2", + "col548": "2h5j2", + "col549": "b6n6s", + "col550": "zu4ie", + "col551": "6dwtk", + "col552": "lrxe4", + "col553": "s0xc9", + "col554": "trbph", + "col555": "pc020", + "col556": "oxe65", + "col557": "dguxx", + "col558": "npa8x", + "col559": "e139c", + "col560": "3et1o", + "col561": "gr6nn", + "col562": "jzun8", + "col563": "6v4wh", + "col564": "i1ouw", + "col565": "rzfkq", + "col566": "tdvim", + "col567": "17c3o", + "col568": "s5nbs", + "col569": "sl7mo", + "col570": "5pcnd", + "col571": "rf0fs", + "col572": "u26ue", + "col573": "9ej5d", + "col574": "jh52x", + "col575": "4skur", + "col576": "9f21a", + "col577": "0gtfx", + "col578": "l2kv6", + "col579": "7l3k5", + "col580": "avxa3", + "col581": "pbm5n", + "col582": "izkcb", + "col583": "b8rdx", + "col584": "8icg4", + "col585": "av6kn", + "col586": "961zv", + "col587": "pgke3", + "col588": "vdm08", + "col589": "b37xk", + "col590": "mtzva", + "col591": "yvubx", + "col592": "zv4nx", + "col593": "j9vre", + "col594": "stlvu", + "col595": "15ot8", + "col596": "v9r3l", + "col597": "8j9il", + "col598": "p8kwm", + "col599": "fijtc", + "col600": "ckq5d", + "col601": "fdd40", + "col602": "oqry8", + "col603": "tkcak", + "col604": "y7x5h", + "col605": "rjv1k", + "col606": "d8kp1", + "col607": "pmtbd", + "col608": "s0jro", + "col609": "4708t", + "col610": "jrqyg", + "col611": "4gwz0", + "col612": "tsi7a", + "col613": "bj7su", + "col614": "qxk54", + "col615": "k0pbb", + "col616": "6t914", + "col617": "0h3h6", + "col618": "jdpk6", + "col619": "9pno9", + "col620": "d6xdd", + "col621": "xyvp7", + "col622": "1vycj", + "col623": "5ujez", + "col624": "5wvy2", + "col625": "3gmja", + "col626": "fdda1", + "col627": "c5y18", + "col628": "7pk5x", + "col629": "yvkdd", + "col630": "7ily4", + "col631": "idwgv", + "col632": "niims", + "col633": "a1u7p", + "col634": "0iuw1", + "col635": "tk5y1", + "col636": "z37bu", + "col637": "a6l90", + "col638": "lqd62", + "col639": "n36qy", + "col640": "rvgsz", + "col641": "y8n2x", + "col642": "p21t6", + "col643": "ts7zv", + "col644": "5owtt", + "col645": "5csp3", + "col646": "j49vt", + "col647": "8ln2t", + "col648": "7dyf2", + "col649": "ca938", + "col650": "cqzjj", + "col651": "zxppt", + "col652": "06pcf", + "col653": "l9b8e", + "col654": "peofz", + "col655": "zlqw5", + "col656": "9wxsd", + "col657": "eha4g", + "col658": "ptpq8", + "col659": "og48t", + "col660": "jo83x", + "col661": "uxw46", + "col662": "y300o", + "col663": "1nh3x", + "col664": "zne19", + "col665": "vvbgx", + "col666": "0559s", + "col667": "gn2kk", + "col668": "j8zy5", + "col669": "dszmy", + "col670": "6nl6g", + "col671": "x2dtr", + "col672": "h4wyo", + "col673": "kfnzm", + "col674": "0p96w", + "col675": "b5yuo", + "col676": "75l1m", + "col677": "u4mtq", + "col678": "9d7rw", + "col679": "cje1k", + "col680": "hltzw", + "col681": "0frlc", + "col682": "aewfd", + "col683": "f0o4p", + "col684": "lgdn9", + "col685": "fhuzc", + "col686": "k7ar5", + "col687": "n99vj", + "col688": "0gljy", + "col689": "rj889", + "col690": "j61a3", + "col691": "84ycm", + "col692": "j2kh2", + "col693": "sklsd", + "col694": "g02ui", + "col695": "3yprl", + "col696": "1p51e", + "col697": "lgyhj", + "col698": "mei2m", + "col699": "to524", + "col700": "eaaqe", + "col701": "2minc", + "col702": "9ep55", + "col703": "mmyvj", + "col704": "mi1sh", + "col705": "3a86w", + "col706": "munoo", + "col707": "twxih", + "col708": "ul41h", + "col709": "hk080", + "col710": "xxivn", + "col711": "kgwgw", + "col712": "vn550", + "col713": "afl4z", + "col714": "2hmzt", + "col715": "kk5dt", + "col716": "zmwxd", + "col717": "raljy", + "col718": "ohbmj", + "col719": "7ty1q", + "col720": "b7swq", + "col721": "wlx5c", + "col722": "o3g68", + "col723": "duzjn", + "col724": "6a5l2", + "col725": "3y28l", + "col726": "054m1", + "col727": "eqogw", + "col728": "pkn0q", + "col729": "p8iwu", + "col730": "dlt84", + "col731": "86lbe", + "col732": "z6y8l", + "col733": "qtuku", + "col734": "e1l2z", + "col735": "5qiea", + "col736": "oixh5", + "col737": "6y4q2", + "col738": "x16gt", + "col739": "yhjbm", + "col740": "nd7rs", + "col741": "vz681", + "col742": "7jxyf", + "col743": "dmnon", + "col744": "7w2r3", + "col745": "n5yao", + "col746": "v69rt", + "col747": "zhuh1", + "col748": "z1ndh", + "col749": "uxr8m", + "col750": "6m4wk", + "col751": "ml30o", + "col752": "k2i12", + "col753": "y2ym5", + "col754": "m2nvu", + "col755": "6o193", + "col756": "wo7y5", + "col757": "f4cbt", + "col758": "v29uo", + "col759": "gmm9e", + "col760": "xy4ni", + "col761": "oxy1n", + "col762": "3wlmw", + "col763": "co7h6", + "col764": "zpek6", + "col765": "rbudx", + "col766": "xyu93", + "col767": "u5hlt", + "col768": "dyb4q", + "col769": "twepz", + "col770": "y6l4s", + "col771": "0m1a2", + "col772": "8wcpj", + "col773": "95b0b", + "col774": "njzzq", + "col775": "ec4s9", + "col776": "lvhy9", + "col777": "q43xh", + "col778": "9ast1", + "col779": "vrmq3", + "col780": "uewh9", + "col781": "sczsa", + "col782": "wmoxh", + "col783": "49nd4", + "col784": "5mqj6", + "col785": "wokgk", + "col786": "4lpll", + "col787": "w2lff", + "col788": "fusgg", + "col789": "zsh3y", + "col790": "xjnye", + "col791": "rl7ja", + "col792": "o5pr4", + "col793": "9rtep", + "col794": "b2911", + "col795": "aj47h", + "col796": "6wpib", + "col797": "xy3hi", + "col798": "25qeq", + "col799": "7cmw8", + "col800": "61i2u", + "col801": "7o812", + "col802": "l6wi0", + "col803": "yfehf", + "col804": "sjmbv", + "col805": "3ytbr", + "col806": "lw5ca", + "col807": "pg3dd", + "col808": "k23xh", + "col809": "qo9s2", + "col810": "ppry4", + "col811": "ir0pg", + "col812": "q2c35", + "col813": "ckgoz", + "col814": "j9zgb", + "col815": "lgioi", + "col816": "ncbeu", + "col817": "g6d4b", + "col818": "bfcpn", + "col819": "uqjva", + "col820": "5rwll", + "col821": "tds7g", + "col822": "tdbt4", + "col823": "v4iyj", + "col824": "2usxt", + "col825": "7vpvt", + "col826": "62go6", + "col827": "92x2u", + "col828": "68ws4", + "col829": "fqbnb", + "col830": "4mkhn", + "col831": "b1djn", + "col832": "h05vg", + "col833": "jrjfe", + "col834": "s7l94", + "col835": "9gdmx", + "col836": "iz0v4", + "col837": "8qtwv", + "col838": "qs29d", + "col839": "t8sq0", + "col840": "i7hux", + "col841": "mdzuu", + "col842": "lfa15", + "col843": "bd7fh", + "col844": "pmgf8", + "col845": "u6yrw", + "col846": "kzx9r", + "col847": "hvuwz", + "col848": "ieeqp", + "col849": "mu5jg", + "col850": "rnpwh", + "col851": "7hflx", + "col852": "xn5fm", + "col853": "dxdby", + "col854": "tm4cf", + "col855": "6zmzc", + "col856": "xsa4v", + "col857": "t2mjc", + "col858": "5cty9", + "col859": "eqbem", + "col860": "vdapo", + "col861": "wigsj", + "col862": "653ud", + "col863": "d2m7v", + "col864": "79vdw", + "col865": "ipthf", + "col866": "26wme", + "col867": "8f71y", + "col868": "3vqq4", + "col869": "yeod4", + "col870": "eu1v9", + "col871": "dj2er", + "col872": "o349z", + "col873": "mx263", + "col874": "0b3rg", + "col875": "8ywlh", + "col876": "phksy", + "col877": "y82bc", + "col878": "8r4ad", + "col879": "f0gbu", + "col880": "3ir48", + "col881": "yisea", + "col882": "m3hsp", + "col883": "jtouv", + "col884": "q64nd", + "col885": "9igak", + "col886": "xdj0g", + "col887": "3pwpq", + "col888": "oq6l3", + "col889": "i7dz0", + "col890": "6xwxj", + "col891": "7wujq", + "col892": "8de7t", + "col893": "2362z", + "col894": "bedqw", + "col895": "x2ran", + "col896": "lna2q", + "col897": "lmx3n", + "col898": "v6on6", + "col899": "dxnv4", + "col900": "wzgkc", + "col901": "zjylt", + "col902": "3m8yq", + "col903": "9dyi4", + "col904": "6i408", + "col905": "3bras", + "col906": "jd6mz", + "col907": "jynmx", + "col908": "1eoog", + "col909": "0he8j", + "col910": "gwrh3", + "col911": "pvfsb", + "col912": "vw6rc", + "col913": "4kdgd", + "col914": "us2ft", + "col915": "evipb", + "col916": "hqls3", + "col917": "d6mcv", + "col918": "q9izy", + "col919": "l71il", + "col920": "hsspd", + "col921": "5llf2", + "col922": "k8eeu", + "col923": "gn8pm", + "col924": "pmijf", + "col925": "2bqhw", + "col926": "tyxdp", + "col927": "4pd8q", + "col928": "183xh", + "col929": "97rci", + "col930": "12ebt", + "col931": "zmksg", + "col932": "08k8o", + "col933": "yllr3", + "col934": "yzz2s", + "col935": "xyhtd", + "col936": "i72dp", + "col937": "nw61d", + "col938": "fl2vu", + "col939": "nlsyz", + "col940": "134xs", + "col941": "k1vxs", + "col942": "eyjld", + "col943": "a1e83", + "col944": "e93nd", + "col945": "kb1nd", + "col946": "m2d08", + "col947": "8t5f1", + "col948": "rgohl", + "col949": "mmwmr", + "col950": "9yx6d", + "col951": "go10d", + "col952": "7bqnw", + "col953": "6bfgb", + "col954": "z1je6", + "col955": "132rq", + "col956": "e2mq6", + "col957": "1gj8q", + "col958": "1d0d2", + "col959": "dnfgr", + "col960": "z4haj", + "col961": "smlmo", + "col962": "xt7em", + "col963": "issu2", + "col964": "loah4", + "col965": "i1ojl", + "col966": "l7gu4", + "col967": "htrhd", + "col968": "b0gno", + "col969": "lxmd9", + "col970": "e75da", + "col971": "4ekzd", + "col972": "kvxoy", + "col973": "gnjuw", + "col974": "dxr4k", + "col975": "9mp1i", + "col976": "7zjxr", + "col977": "tp2j9", + "col978": "yzbg0", + "col979": "pcjyg", + "col980": "gxg90", + "col981": "lm5uw", + "col982": "ih7zq", + "col983": "z6pfx", + "col984": "3u0q9", + "col985": "4znjq", + "col986": "l4gf1", + "col987": "vg0tp", + "col988": "ah1ud", + "col989": "mpnz7", + "col990": "ce22j", + "col991": "xqsqg", + "col992": "nps7i", + "col993": "xojj2", + "col994": "8m8kk", + "col995": "14j9y", + "col996": "lyojm", + "col997": "yf1y6", + "col998": "x3mhz", + "col999": "jaczx" + }, + { + "name": "Carla Kirkland", + "gender": "female", + "col0": "4eo0w", + "col1": "xzi7b", + "col2": "hl6hi", + "col3": "rnapk", + "col4": "g8y99", + "col5": "dzsjz", + "col6": "7sj5p", + "col7": "li8ff", + "col8": "8h148", + "col9": "gt1xu", + "col10": "aiez9", + "col11": "19ldl", + "col12": "p83cw", + "col13": "3n2hq", + "col14": "ok5si", + "col15": "lptca", + "col16": "ala1z", + "col17": "31gu8", + "col18": "oasnm", + "col19": "i7hqh", + "col20": "ii2d6", + "col21": "7w7t7", + "col22": "hrnkr", + "col23": "vpfck", + "col24": "c0eg1", + "col25": "s5k23", + "col26": "ewjrg", + "col27": "ljs39", + "col28": "dxwbj", + "col29": "hnkmy", + "col30": "p5wcn", + "col31": "8e0rq", + "col32": "p1om8", + "col33": "zb936", + "col34": "srcqp", + "col35": "xetfc", + "col36": "lxj1x", + "col37": "oot27", + "col38": "s3n69", + "col39": "6r03p", + "col40": "7xbtj", + "col41": "i5yde", + "col42": "khm7w", + "col43": "2n3mz", + "col44": "wnvv0", + "col45": "9xx9s", + "col46": "gk6qd", + "col47": "bjhaj", + "col48": "9qd2q", + "col49": "owpek", + "col50": "08g8o", + "col51": "rglf1", + "col52": "11el0", + "col53": "4bn17", + "col54": "nkjnp", + "col55": "w0bok", + "col56": "sulm5", + "col57": "ronot", + "col58": "0drlx", + "col59": "uvhri", + "col60": "s407l", + "col61": "95hjx", + "col62": "c49mx", + "col63": "vty0j", + "col64": "siflf", + "col65": "czfnj", + "col66": "z0iio", + "col67": "8fsu2", + "col68": "078tb", + "col69": "hjw6t", + "col70": "ds31s", + "col71": "u0jzb", + "col72": "aiif2", + "col73": "wjyat", + "col74": "fl45p", + "col75": "l018q", + "col76": "21evo", + "col77": "40720", + "col78": "0ilwl", + "col79": "hxke3", + "col80": "1w0h4", + "col81": "xzzja", + "col82": "8arec", + "col83": "6cnx9", + "col84": "193yz", + "col85": "f34ew", + "col86": "1267f", + "col87": "6dn9r", + "col88": "fjv15", + "col89": "0ux51", + "col90": "n5q7o", + "col91": "ieisu", + "col92": "sgi1i", + "col93": "sj3co", + "col94": "jabx9", + "col95": "o2sba", + "col96": "5euyg", + "col97": "e4hox", + "col98": "a7d5s", + "col99": "7z7jo", + "col100": "lnewu", + "col101": "cwgaq", + "col102": "lvvul", + "col103": "veslk", + "col104": "ae0fn", + "col105": "owk2q", + "col106": "kl5jz", + "col107": "baph4", + "col108": "x6w7x", + "col109": "kkz5p", + "col110": "nqpfi", + "col111": "0aj6t", + "col112": "ojhaf", + "col113": "3i3ym", + "col114": "jwboo", + "col115": "d37o8", + "col116": "lqapb", + "col117": "m9aq0", + "col118": "zekhh", + "col119": "otgta", + "col120": "oquuy", + "col121": "68iwv", + "col122": "ofs2t", + "col123": "049x2", + "col124": "purkt", + "col125": "mh610", + "col126": "c38vs", + "col127": "51ij5", + "col128": "kxftp", + "col129": "ok79p", + "col130": "y2beq", + "col131": "smpg4", + "col132": "1nyw1", + "col133": "c4jp0", + "col134": "q9rpr", + "col135": "zv23m", + "col136": "mrddn", + "col137": "v98wx", + "col138": "qiv32", + "col139": "kem32", + "col140": "h7jqt", + "col141": "cdx52", + "col142": "dvc7w", + "col143": "ssfhc", + "col144": "og3i1", + "col145": "0f9zj", + "col146": "vtcgk", + "col147": "73r5o", + "col148": "0qp7b", + "col149": "z96pi", + "col150": "ejdms", + "col151": "vxtls", + "col152": "qls98", + "col153": "tat5g", + "col154": "n3h40", + "col155": "6foy3", + "col156": "e2zme", + "col157": "xqptv", + "col158": "hizrm", + "col159": "5y2ek", + "col160": "1zuoc", + "col161": "qfnxb", + "col162": "2rp8y", + "col163": "x3hm2", + "col164": "pm4m2", + "col165": "m5q2x", + "col166": "oou4b", + "col167": "m9zbr", + "col168": "mj1st", + "col169": "q5t79", + "col170": "w68yr", + "col171": "tf1hq", + "col172": "l3q66", + "col173": "0wd0k", + "col174": "yy56s", + "col175": "jj5fs", + "col176": "v4snl", + "col177": "qr3sc", + "col178": "bn35k", + "col179": "0x4ql", + "col180": "7paqp", + "col181": "48dbl", + "col182": "k72er", + "col183": "xmlt4", + "col184": "bvdtw", + "col185": "p33t1", + "col186": "pku5h", + "col187": "pijp8", + "col188": "iawh5", + "col189": "ougx3", + "col190": "kdbjb", + "col191": "297vh", + "col192": "q9obl", + "col193": "qg6jw", + "col194": "dhvzd", + "col195": "3kpes", + "col196": "pprfb", + "col197": "hbtms", + "col198": "3kex0", + "col199": "1s9hk", + "col200": "896zd", + "col201": "7at2i", + "col202": "hrnii", + "col203": "o0fmv", + "col204": "g2m05", + "col205": "eyta8", + "col206": "7yqe0", + "col207": "d4o6v", + "col208": "6twit", + "col209": "dbpez", + "col210": "ycqva", + "col211": "ftcdq", + "col212": "v7hwo", + "col213": "2ri6p", + "col214": "yis9q", + "col215": "ecsnh", + "col216": "8q057", + "col217": "7fsot", + "col218": "cbwoa", + "col219": "keejq", + "col220": "fuubp", + "col221": "y6g4r", + "col222": "5ykus", + "col223": "8376x", + "col224": "noep1", + "col225": "cwv49", + "col226": "26my9", + "col227": "ru9h9", + "col228": "h7jkg", + "col229": "9fvdt", + "col230": "9fnbp", + "col231": "heiiz", + "col232": "c2p5z", + "col233": "vijea", + "col234": "jcub5", + "col235": "omur6", + "col236": "kpm28", + "col237": "k4orh", + "col238": "y8z93", + "col239": "g1r3s", + "col240": "3597k", + "col241": "4174x", + "col242": "xu85t", + "col243": "6g5cs", + "col244": "bvajm", + "col245": "chm4g", + "col246": "whbtb", + "col247": "fmxxx", + "col248": "v12yc", + "col249": "d3gwg", + "col250": "0f09z", + "col251": "8o2ex", + "col252": "ze0qp", + "col253": "4ises", + "col254": "4tgtl", + "col255": "400t2", + "col256": "y0auo", + "col257": "21dk1", + "col258": "njz4k", + "col259": "hdgzi", + "col260": "qiwyf", + "col261": "i6c7p", + "col262": "sv1z0", + "col263": "v5yc9", + "col264": "x11y6", + "col265": "wxqsd", + "col266": "kp43z", + "col267": "fz427", + "col268": "bey5n", + "col269": "2edb5", + "col270": "akzm7", + "col271": "oktz7", + "col272": "7fwtb", + "col273": "4z9fj", + "col274": "mbiys", + "col275": "ahbse", + "col276": "wmal1", + "col277": "64ssp", + "col278": "tzn4o", + "col279": "ukogy", + "col280": "pakz1", + "col281": "40ecf", + "col282": "6wkx0", + "col283": "kg91e", + "col284": "lvuz8", + "col285": "vvhzv", + "col286": "r6vio", + "col287": "px31o", + "col288": "jt4ei", + "col289": "87vru", + "col290": "2uzm1", + "col291": "hbpgx", + "col292": "wf6g2", + "col293": "ffeaj", + "col294": "f4ykl", + "col295": "00853", + "col296": "u367u", + "col297": "9olb8", + "col298": "p1rg4", + "col299": "le27l", + "col300": "z9h4l", + "col301": "3epwi", + "col302": "9cssn", + "col303": "ip0ch", + "col304": "ll65g", + "col305": "b1s6j", + "col306": "he56h", + "col307": "ectad", + "col308": "wf2vf", + "col309": "0eu8f", + "col310": "qp6wx", + "col311": "1f7xo", + "col312": "duldr", + "col313": "wrurp", + "col314": "pjjyx", + "col315": "ql794", + "col316": "1u9qx", + "col317": "uii4h", + "col318": "ddojq", + "col319": "6lz7u", + "col320": "4d8n1", + "col321": "z9ozo", + "col322": "bzbir", + "col323": "663qm", + "col324": "hryez", + "col325": "jcun3", + "col326": "zv0y7", + "col327": "day0y", + "col328": "8gx98", + "col329": "5cmkq", + "col330": "gm0eg", + "col331": "speir", + "col332": "t1wa8", + "col333": "mnqzn", + "col334": "uz5b3", + "col335": "brdyd", + "col336": "rsoo3", + "col337": "1c6py", + "col338": "ldhzn", + "col339": "h5wjp", + "col340": "f23n4", + "col341": "2lhot", + "col342": "52xph", + "col343": "8g0nv", + "col344": "1sntk", + "col345": "qzlzi", + "col346": "m8lc5", + "col347": "9jy4r", + "col348": "gk4je", + "col349": "s84jn", + "col350": "mk3lk", + "col351": "esn3f", + "col352": "rl84m", + "col353": "vh6o6", + "col354": "a2cct", + "col355": "wnzl2", + "col356": "dni4r", + "col357": "6zft7", + "col358": "azwch", + "col359": "vqrmi", + "col360": "15kkx", + "col361": "zgoej", + "col362": "5fp6o", + "col363": "tgpyj", + "col364": "mxaw4", + "col365": "e9cjd", + "col366": "mxr0b", + "col367": "hcxi4", + "col368": "ev3xo", + "col369": "t8t6h", + "col370": "evwv4", + "col371": "h4d3z", + "col372": "9rk1r", + "col373": "6opai", + "col374": "2zqf1", + "col375": "bfd9n", + "col376": "tkk22", + "col377": "xsc7q", + "col378": "yi16k", + "col379": "9yysz", + "col380": "y5vr0", + "col381": "b9jbm", + "col382": "kr89p", + "col383": "1gby6", + "col384": "3bi5j", + "col385": "ix68q", + "col386": "wzhvy", + "col387": "sjq53", + "col388": "pa5qm", + "col389": "ym98v", + "col390": "y632i", + "col391": "d0ugv", + "col392": "qr6sn", + "col393": "ks1ck", + "col394": "fffo9", + "col395": "qy4qh", + "col396": "j6erf", + "col397": "g6fz1", + "col398": "ogags", + "col399": "wta8q", + "col400": "7r7vg", + "col401": "wcdlr", + "col402": "rev4i", + "col403": "88rw3", + "col404": "1800z", + "col405": "w0j4y", + "col406": "u1x2g", + "col407": "u3177", + "col408": "n69am", + "col409": "hyp86", + "col410": "jesrf", + "col411": "j4qv9", + "col412": "8yb0t", + "col413": "fyqim", + "col414": "pw85t", + "col415": "dojrj", + "col416": "enq41", + "col417": "d45ij", + "col418": "i5fzx", + "col419": "ag41k", + "col420": "f8i2p", + "col421": "qc88l", + "col422": "qf03i", + "col423": "xalh6", + "col424": "otlxa", + "col425": "9vgey", + "col426": "r72kp", + "col427": "pkplm", + "col428": "mtlxj", + "col429": "t2s3n", + "col430": "x6p2m", + "col431": "5k6tm", + "col432": "tca5x", + "col433": "mg5zz", + "col434": "nkp41", + "col435": "of45q", + "col436": "dmtj1", + "col437": "2gkvh", + "col438": "jf3bd", + "col439": "veuu9", + "col440": "1az04", + "col441": "ymrvx", + "col442": "pk2w7", + "col443": "7m5a7", + "col444": "mkdo6", + "col445": "fm5ft", + "col446": "06chi", + "col447": "fs5wx", + "col448": "czg6k", + "col449": "lfcc5", + "col450": "wyy05", + "col451": "q5ll4", + "col452": "475tk", + "col453": "wklv2", + "col454": "nkt5n", + "col455": "nv4ip", + "col456": "mky81", + "col457": "vmto8", + "col458": "rwrhr", + "col459": "k4jvq", + "col460": "c158q", + "col461": "5c7ct", + "col462": "0888j", + "col463": "ekixe", + "col464": "xdla0", + "col465": "2mbb5", + "col466": "ov4ks", + "col467": "aow45", + "col468": "cc4rc", + "col469": "g6y3q", + "col470": "bg695", + "col471": "rulq8", + "col472": "fg7g5", + "col473": "yfd2d", + "col474": "zcb96", + "col475": "fud8x", + "col476": "0w5gx", + "col477": "53rbd", + "col478": "a3lts", + "col479": "epbnb", + "col480": "jr0jc", + "col481": "il987", + "col482": "6way0", + "col483": "7wxdf", + "col484": "ddlth", + "col485": "vahcr", + "col486": "asekv", + "col487": "gra8a", + "col488": "xqbcw", + "col489": "xirjd", + "col490": "2auvx", + "col491": "mihnj", + "col492": "z2c7g", + "col493": "638fy", + "col494": "7414x", + "col495": "2n6rh", + "col496": "4m2z4", + "col497": "ode6m", + "col498": "bmaki", + "col499": "foxbv", + "col500": "si9j5", + "col501": "snkhy", + "col502": "otx7m", + "col503": "f566h", + "col504": "ckieo", + "col505": "uf55p", + "col506": "hw5nl", + "col507": "mknk0", + "col508": "sf72n", + "col509": "u9k73", + "col510": "n5bcy", + "col511": "u63of", + "col512": "853gr", + "col513": "1yugo", + "col514": "42j34", + "col515": "ei98g", + "col516": "9j4bd", + "col517": "lfxke", + "col518": "u2y4i", + "col519": "93d0u", + "col520": "7qddz", + "col521": "v4p63", + "col522": "k6hrm", + "col523": "h3beq", + "col524": "gqi1h", + "col525": "gkey7", + "col526": "3awi4", + "col527": "xgg8q", + "col528": "gkvxf", + "col529": "bxbgx", + "col530": "dl8m7", + "col531": "iy0gk", + "col532": "c0l28", + "col533": "bycve", + "col534": "ws936", + "col535": "1dc0v", + "col536": "2zkx3", + "col537": "wmfsk", + "col538": "zsrj7", + "col539": "jow10", + "col540": "2u7gx", + "col541": "mjnt4", + "col542": "nu0ig", + "col543": "dll9g", + "col544": "aeazh", + "col545": "8xoc9", + "col546": "fgfi4", + "col547": "bhp9n", + "col548": "3iy8a", + "col549": "fvnc7", + "col550": "e1c6l", + "col551": "14wpd", + "col552": "5pss8", + "col553": "ipcch", + "col554": "g8c4s", + "col555": "dfboi", + "col556": "9e99p", + "col557": "as77f", + "col558": "namo6", + "col559": "ywm91", + "col560": "3uu91", + "col561": "ekg0w", + "col562": "6s8hw", + "col563": "b3xkq", + "col564": "iz0jb", + "col565": "o9gl4", + "col566": "vma56", + "col567": "zbp30", + "col568": "4fuaa", + "col569": "8n2w3", + "col570": "xlyj3", + "col571": "lhbmz", + "col572": "vz7x1", + "col573": "ympfw", + "col574": "wguch", + "col575": "uedg6", + "col576": "ffc9k", + "col577": "xvimo", + "col578": "o3ywg", + "col579": "n6wij", + "col580": "v2hpx", + "col581": "2uuqb", + "col582": "6zx4o", + "col583": "ohr6s", + "col584": "r2t0i", + "col585": "y2bwg", + "col586": "gs927", + "col587": "zlef4", + "col588": "rrwyo", + "col589": "7htkw", + "col590": "7is4g", + "col591": "x8pdp", + "col592": "pfgj8", + "col593": "fzbc1", + "col594": "skb04", + "col595": "3k47a", + "col596": "e9xni", + "col597": "unywc", + "col598": "pa14a", + "col599": "lvyk4", + "col600": "vhev0", + "col601": "if1pb", + "col602": "bacrh", + "col603": "9bnv0", + "col604": "3ss84", + "col605": "k2en0", + "col606": "m6ovf", + "col607": "vxlr1", + "col608": "8rbih", + "col609": "wpln5", + "col610": "uyknq", + "col611": "5l2pu", + "col612": "zv8le", + "col613": "tfyzc", + "col614": "7gwf6", + "col615": "1pjs5", + "col616": "s57r4", + "col617": "xxucl", + "col618": "mghft", + "col619": "pjbq4", + "col620": "isecg", + "col621": "654nh", + "col622": "4859n", + "col623": "md44h", + "col624": "5cxba", + "col625": "ei3tv", + "col626": "qom9p", + "col627": "hbces", + "col628": "9wxs3", + "col629": "qy16s", + "col630": "5ymni", + "col631": "imave", + "col632": "7lgie", + "col633": "j9xay", + "col634": "k2kbw", + "col635": "ts82g", + "col636": "1si1w", + "col637": "pi987", + "col638": "l13lt", + "col639": "wstje", + "col640": "keqgy", + "col641": "25zx1", + "col642": "7mr4o", + "col643": "i9oqp", + "col644": "wz7i2", + "col645": "tbwcd", + "col646": "ecywy", + "col647": "qhcsn", + "col648": "7yog3", + "col649": "w9jyg", + "col650": "l6hpw", + "col651": "iw30j", + "col652": "id779", + "col653": "cs7ce", + "col654": "hut37", + "col655": "z0oz5", + "col656": "znw2y", + "col657": "94ss0", + "col658": "1yos7", + "col659": "dlzr7", + "col660": "1llfd", + "col661": "2brdi", + "col662": "7ch1u", + "col663": "dpn7l", + "col664": "6i215", + "col665": "2w3hk", + "col666": "i0et7", + "col667": "1hgt8", + "col668": "8qmwd", + "col669": "4flt2", + "col670": "h8yye", + "col671": "fnuzk", + "col672": "kik6i", + "col673": "i9c5k", + "col674": "hgje4", + "col675": "rv612", + "col676": "a6hyv", + "col677": "x4rj4", + "col678": "l8087", + "col679": "mm77c", + "col680": "ubr4e", + "col681": "19v4r", + "col682": "zo8oe", + "col683": "afsbb", + "col684": "611ov", + "col685": "h4cj0", + "col686": "tvo80", + "col687": "no6cx", + "col688": "j2ybr", + "col689": "48odw", + "col690": "giobn", + "col691": "o17yo", + "col692": "tmlse", + "col693": "ypjtb", + "col694": "3qua8", + "col695": "8smf3", + "col696": "fvvqg", + "col697": "ae254", + "col698": "tqrwg", + "col699": "bfr7r", + "col700": "oagzb", + "col701": "yxg8k", + "col702": "18t5r", + "col703": "j0044", + "col704": "k9hy4", + "col705": "txwld", + "col706": "1s8r3", + "col707": "i49il", + "col708": "9i1tw", + "col709": "qax20", + "col710": "xs94o", + "col711": "qxh61", + "col712": "mxtx2", + "col713": "948xm", + "col714": "0cbt9", + "col715": "mzih4", + "col716": "zaudn", + "col717": "eykst", + "col718": "0vhpz", + "col719": "g1sa8", + "col720": "nya7f", + "col721": "yz9sn", + "col722": "om480", + "col723": "b5vya", + "col724": "4njnp", + "col725": "2mnm2", + "col726": "ciims", + "col727": "8kuy7", + "col728": "mmhjj", + "col729": "uuuqr", + "col730": "64jy2", + "col731": "wyz3q", + "col732": "0y0wg", + "col733": "jxh46", + "col734": "lxrio", + "col735": "uve5r", + "col736": "4095n", + "col737": "mqssw", + "col738": "ja6du", + "col739": "955ph", + "col740": "d4qnf", + "col741": "4ncyu", + "col742": "ftk1f", + "col743": "csiz4", + "col744": "aal6i", + "col745": "iq30h", + "col746": "piuz0", + "col747": "kg59y", + "col748": "5cvrv", + "col749": "gh6ae", + "col750": "6krnu", + "col751": "pvn56", + "col752": "sx0rv", + "col753": "bihr5", + "col754": "a9x8p", + "col755": "g5710", + "col756": "6m7e8", + "col757": "cknuy", + "col758": "3py64", + "col759": "fjtv8", + "col760": "3hvwo", + "col761": "xeuqe", + "col762": "wgb7l", + "col763": "104tm", + "col764": "19mu0", + "col765": "k2bk4", + "col766": "ouuzl", + "col767": "qk0hz", + "col768": "vgs6u", + "col769": "2ftey", + "col770": "dv6yp", + "col771": "7ocjk", + "col772": "1k9fe", + "col773": "h612c", + "col774": "09qvy", + "col775": "r8omi", + "col776": "cys2n", + "col777": "3yn9x", + "col778": "98xl9", + "col779": "kk8if", + "col780": "qm61f", + "col781": "tbd6j", + "col782": "646dt", + "col783": "oc1vg", + "col784": "yf4gi", + "col785": "rvjdq", + "col786": "31h4o", + "col787": "35ok8", + "col788": "7qtd8", + "col789": "o9j1z", + "col790": "k3a84", + "col791": "6kft4", + "col792": "v87oi", + "col793": "e363v", + "col794": "nuzab", + "col795": "lo5fc", + "col796": "2re6j", + "col797": "wqcx2", + "col798": "i3i81", + "col799": "485vo", + "col800": "upubr", + "col801": "eyk3n", + "col802": "7zqrl", + "col803": "ijfyb", + "col804": "g5ieh", + "col805": "ki5gh", + "col806": "05jk6", + "col807": "6mbwh", + "col808": "be97q", + "col809": "xkfgi", + "col810": "sswiw", + "col811": "svpb6", + "col812": "0cohy", + "col813": "j4vgb", + "col814": "4euhw", + "col815": "m635c", + "col816": "yiglw", + "col817": "0nkml", + "col818": "4y25z", + "col819": "j9ga6", + "col820": "7uej6", + "col821": "7291f", + "col822": "79t2o", + "col823": "fegyx", + "col824": "rt4l6", + "col825": "umtp8", + "col826": "abj2a", + "col827": "9wky4", + "col828": "japs0", + "col829": "ioxah", + "col830": "ebmeq", + "col831": "whg7e", + "col832": "9e5ys", + "col833": "by1kd", + "col834": "21bsq", + "col835": "4uug2", + "col836": "vzbyg", + "col837": "n8p14", + "col838": "gksad", + "col839": "zwn7k", + "col840": "k5w1b", + "col841": "7sx2t", + "col842": "5gxxb", + "col843": "b56in", + "col844": "qfm0m", + "col845": "r4r82", + "col846": "2rmly", + "col847": "ape3t", + "col848": "2lx0u", + "col849": "iqcjg", + "col850": "cdocq", + "col851": "4cotg", + "col852": "0akdz", + "col853": "sb00g", + "col854": "2i5sg", + "col855": "4epz3", + "col856": "nf3p9", + "col857": "56129", + "col858": "b6jjh", + "col859": "6h4g4", + "col860": "yf0rg", + "col861": "676fz", + "col862": "of93l", + "col863": "jln75", + "col864": "rxcy7", + "col865": "hcs7k", + "col866": "7ybfm", + "col867": "j0666", + "col868": "yl3e8", + "col869": "cti01", + "col870": "5vq4t", + "col871": "wpkt6", + "col872": "hm2rv", + "col873": "vxj5m", + "col874": "auygl", + "col875": "uuml3", + "col876": "swjdn", + "col877": "lhhj7", + "col878": "2yrk1", + "col879": "6rixk", + "col880": "oycly", + "col881": "x05ny", + "col882": "902u1", + "col883": "gqb9c", + "col884": "tgo9r", + "col885": "gwm0f", + "col886": "y1sfj", + "col887": "dd5c4", + "col888": "ioypy", + "col889": "2monv", + "col890": "lg4kk", + "col891": "7zhz4", + "col892": "0d8qc", + "col893": "lf6rd", + "col894": "ykds7", + "col895": "4lwne", + "col896": "wi0lx", + "col897": "ou0px", + "col898": "byzs5", + "col899": "ii9rt", + "col900": "b2ut2", + "col901": "l2sk5", + "col902": "ag7ou", + "col903": "k7alj", + "col904": "bt8yq", + "col905": "8vpeg", + "col906": "xi0nl", + "col907": "u0m4f", + "col908": "q1swt", + "col909": "hmvlr", + "col910": "w792g", + "col911": "1gyq4", + "col912": "w6tfg", + "col913": "y0r31", + "col914": "m962n", + "col915": "khrzy", + "col916": "21mgz", + "col917": "3ro0x", + "col918": "rrzku", + "col919": "5a6gk", + "col920": "eqmqd", + "col921": "zeikd", + "col922": "slzc7", + "col923": "j47zy", + "col924": "v0c69", + "col925": "q4l6z", + "col926": "goak2", + "col927": "fvyev", + "col928": "46yc2", + "col929": "jrlmi", + "col930": "yocab", + "col931": "y6r7r", + "col932": "bvwxb", + "col933": "iar55", + "col934": "q5sik", + "col935": "dfg8d", + "col936": "8say4", + "col937": "700nm", + "col938": "bv37d", + "col939": "xom4r", + "col940": "mvn9f", + "col941": "7sty0", + "col942": "emgfa", + "col943": "65prh", + "col944": "2s1o0", + "col945": "76es8", + "col946": "fq9w0", + "col947": "iav78", + "col948": "s06ft", + "col949": "he8z3", + "col950": "juuo3", + "col951": "q0x76", + "col952": "q38o6", + "col953": "j8gq3", + "col954": "yah21", + "col955": "2l33k", + "col956": "n6hid", + "col957": "rrlnd", + "col958": "4zykm", + "col959": "99ln8", + "col960": "c612i", + "col961": "k73uf", + "col962": "ew90r", + "col963": "f9wcx", + "col964": "wsv0x", + "col965": "2vmof", + "col966": "xxhk0", + "col967": "ivwt3", + "col968": "l5c5d", + "col969": "litta", + "col970": "mtg7o", + "col971": "yp9tv", + "col972": "7tuqy", + "col973": "0qxev", + "col974": "pbmj4", + "col975": "08jov", + "col976": "t7s8r", + "col977": "x01hc", + "col978": "efpyr", + "col979": "0b0w3", + "col980": "4yoif", + "col981": "8uamd", + "col982": "hz2b5", + "col983": "620hf", + "col984": "uip13", + "col985": "by5g4", + "col986": "jlszo", + "col987": "lub6a", + "col988": "3u000", + "col989": "8sqxh", + "col990": "95k0b", + "col991": "zz8jo", + "col992": "b2cem", + "col993": "11mgw", + "col994": "pm8xu", + "col995": "o1801", + "col996": "w5xic", + "col997": "x5zkb", + "col998": "v0yoh", + "col999": "w9li3" + }, + { + "name": "Gay Porter", + "gender": "female", + "col0": "45nbt", + "col1": "tx7hc", + "col2": "aztdq", + "col3": "0hxcq", + "col4": "a4n31", + "col5": "cxyjk", + "col6": "4lb7p", + "col7": "8bogt", + "col8": "abiap", + "col9": "b7mtd", + "col10": "4xbam", + "col11": "vr7vh", + "col12": "gu7cc", + "col13": "5mf57", + "col14": "71cn7", + "col15": "zi5fh", + "col16": "6eru4", + "col17": "8r6lw", + "col18": "8wc0k", + "col19": "1doxm", + "col20": "c2895", + "col21": "h795o", + "col22": "8igti", + "col23": "zvtmw", + "col24": "xcogy", + "col25": "bgc5h", + "col26": "uwcpk", + "col27": "rft5w", + "col28": "e4bha", + "col29": "plzb5", + "col30": "0668t", + "col31": "7rb75", + "col32": "3xtwz", + "col33": "86doz", + "col34": "1lyrj", + "col35": "anp75", + "col36": "82esj", + "col37": "rvkzk", + "col38": "uto95", + "col39": "wdxe1", + "col40": "3u6hl", + "col41": "1lrxx", + "col42": "c1yc1", + "col43": "ap6tx", + "col44": "sqvjo", + "col45": "k2umd", + "col46": "gejre", + "col47": "8jhwi", + "col48": "ihkmw", + "col49": "8rl6b", + "col50": "720hn", + "col51": "a4sam", + "col52": "pkytk", + "col53": "el9uj", + "col54": "kuuxk", + "col55": "7f7ba", + "col56": "2l2bu", + "col57": "s8hkc", + "col58": "ocwpf", + "col59": "gr5ep", + "col60": "as1da", + "col61": "m2any", + "col62": "9j38s", + "col63": "gw1u1", + "col64": "6yqbl", + "col65": "s3wmh", + "col66": "ieppn", + "col67": "gbt90", + "col68": "3fbfr", + "col69": "6arfa", + "col70": "o7c9g", + "col71": "6g8s0", + "col72": "cgr1z", + "col73": "ntmau", + "col74": "v1zx5", + "col75": "rjmad", + "col76": "9xw5u", + "col77": "hn614", + "col78": "o8ksx", + "col79": "tzktl", + "col80": "vgzor", + "col81": "5t4x5", + "col82": "bg8jc", + "col83": "bjh2t", + "col84": "3ag1k", + "col85": "75jli", + "col86": "67rxs", + "col87": "90csf", + "col88": "3a2p4", + "col89": "8a2ab", + "col90": "jvt5z", + "col91": "2xjc3", + "col92": "bwof2", + "col93": "2jiup", + "col94": "q0117", + "col95": "y6tsc", + "col96": "r17yg", + "col97": "fpv2a", + "col98": "bhb0w", + "col99": "5fj0m", + "col100": "6y63x", + "col101": "ltlqq", + "col102": "jw5fd", + "col103": "vph1n", + "col104": "f40xj", + "col105": "5slmn", + "col106": "iuqfj", + "col107": "s27sh", + "col108": "u0i2t", + "col109": "fd2x8", + "col110": "x2v2z", + "col111": "az8fe", + "col112": "j89up", + "col113": "j9lh5", + "col114": "clml5", + "col115": "nke1p", + "col116": "dgv7j", + "col117": "fsig7", + "col118": "hd8iz", + "col119": "yhrj2", + "col120": "vg9ns", + "col121": "y6kd6", + "col122": "w0xyb", + "col123": "gguxs", + "col124": "qqza2", + "col125": "lu2m1", + "col126": "4a2g0", + "col127": "ictav", + "col128": "5iqjd", + "col129": "1jtf1", + "col130": "qslft", + "col131": "a95yk", + "col132": "ce1hg", + "col133": "56d4n", + "col134": "yqw9f", + "col135": "vhjqw", + "col136": "k9l19", + "col137": "wjzz1", + "col138": "wht37", + "col139": "2lxsu", + "col140": "maqp5", + "col141": "9bxrb", + "col142": "0vzse", + "col143": "ifufu", + "col144": "zv7a1", + "col145": "qdb3g", + "col146": "e4kxj", + "col147": "6s8w6", + "col148": "vxi2v", + "col149": "5byz1", + "col150": "vu0wc", + "col151": "9ttc0", + "col152": "ghw2k", + "col153": "p3q5c", + "col154": "wgzdg", + "col155": "dgi5v", + "col156": "f36iu", + "col157": "135m8", + "col158": "54px4", + "col159": "szajg", + "col160": "8251d", + "col161": "5h6t0", + "col162": "q6bvf", + "col163": "uifrz", + "col164": "yg5tw", + "col165": "whzop", + "col166": "5jsv5", + "col167": "pyn8b", + "col168": "1c38q", + "col169": "gpog4", + "col170": "a1m07", + "col171": "r6zhn", + "col172": "lh0v2", + "col173": "3jr3z", + "col174": "gn2pv", + "col175": "p7uqw", + "col176": "ny32y", + "col177": "bo484", + "col178": "5jrhh", + "col179": "sju6f", + "col180": "j9unf", + "col181": "wo38x", + "col182": "6yf5k", + "col183": "5vb39", + "col184": "dp8nd", + "col185": "lc3jo", + "col186": "hwdlp", + "col187": "tzeah", + "col188": "gduqc", + "col189": "jzgb7", + "col190": "jhy0w", + "col191": "vok90", + "col192": "mws5m", + "col193": "kyfs4", + "col194": "3z3fj", + "col195": "m6uxq", + "col196": "1dydk", + "col197": "29a4p", + "col198": "f37g1", + "col199": "i1dpf", + "col200": "ct2no", + "col201": "megs5", + "col202": "oqtef", + "col203": "kmb18", + "col204": "hfqnb", + "col205": "m5dmm", + "col206": "ya2pa", + "col207": "soljf", + "col208": "jaz5z", + "col209": "baar4", + "col210": "9kkna", + "col211": "kqwam", + "col212": "rwlps", + "col213": "lc4ta", + "col214": "kzoug", + "col215": "d00z5", + "col216": "p3p1x", + "col217": "0ijkj", + "col218": "ypysg", + "col219": "8uogo", + "col220": "vytt6", + "col221": "hvthz", + "col222": "8wsmb", + "col223": "qbkni", + "col224": "zuf5g", + "col225": "4mj92", + "col226": "f0957", + "col227": "2gs90", + "col228": "4ndby", + "col229": "pe6eb", + "col230": "g3wmf", + "col231": "c9rxc", + "col232": "3oxjk", + "col233": "00mfr", + "col234": "44dii", + "col235": "0k38k", + "col236": "1dfkw", + "col237": "s9kuu", + "col238": "v2o6d", + "col239": "f2zt7", + "col240": "b40w9", + "col241": "ry47j", + "col242": "fh41e", + "col243": "fmy6f", + "col244": "2u39i", + "col245": "4psvq", + "col246": "2mz8h", + "col247": "qmipd", + "col248": "cg6xg", + "col249": "gbe44", + "col250": "ojdyg", + "col251": "eq5y7", + "col252": "5twap", + "col253": "79p6g", + "col254": "5vz7x", + "col255": "hnhmk", + "col256": "ssydq", + "col257": "ik1kh", + "col258": "wkr9p", + "col259": "7er8o", + "col260": "w06o6", + "col261": "7n9pc", + "col262": "zkf85", + "col263": "bf4xw", + "col264": "xq7td", + "col265": "1x2bb", + "col266": "mvf1a", + "col267": "9y0qz", + "col268": "on1zb", + "col269": "ki1mk", + "col270": "99wn0", + "col271": "0gziw", + "col272": "lsyvr", + "col273": "8c1em", + "col274": "ktcxg", + "col275": "jrbkh", + "col276": "gtktn", + "col277": "p5avm", + "col278": "f3p79", + "col279": "y9oxx", + "col280": "yfqif", + "col281": "xqj0k", + "col282": "hetgz", + "col283": "peyjd", + "col284": "a4728", + "col285": "uzijq", + "col286": "aky1p", + "col287": "k03u6", + "col288": "gq5vt", + "col289": "e6vtk", + "col290": "ggpqh", + "col291": "025lm", + "col292": "3n0j7", + "col293": "uyil8", + "col294": "5vhoq", + "col295": "crrbd", + "col296": "717fg", + "col297": "qorg0", + "col298": "qws87", + "col299": "xsl4r", + "col300": "xnwtu", + "col301": "rn0gg", + "col302": "k1wf9", + "col303": "4snf4", + "col304": "0bawv", + "col305": "3tm4z", + "col306": "n27e0", + "col307": "eyj78", + "col308": "fw849", + "col309": "mtp4u", + "col310": "3p4ah", + "col311": "stt1i", + "col312": "u7ijj", + "col313": "jyrai", + "col314": "yjks7", + "col315": "tof7z", + "col316": "p3ucm", + "col317": "6t0vk", + "col318": "4hwe7", + "col319": "i67k8", + "col320": "106ai", + "col321": "9tz33", + "col322": "09zz6", + "col323": "6o06t", + "col324": "whcty", + "col325": "t2jvs", + "col326": "ienwk", + "col327": "ozq9h", + "col328": "sxb84", + "col329": "kc8xa", + "col330": "ixbp5", + "col331": "f1u1b", + "col332": "92h6x", + "col333": "ov6ul", + "col334": "5qho1", + "col335": "ezwnn", + "col336": "en7h1", + "col337": "h1t1u", + "col338": "id8zp", + "col339": "ixh1u", + "col340": "a988z", + "col341": "1stcl", + "col342": "fpzh3", + "col343": "v6kad", + "col344": "yysjf", + "col345": "995s9", + "col346": "35bja", + "col347": "nutcu", + "col348": "0a68m", + "col349": "xxneu", + "col350": "wcm5y", + "col351": "l7afk", + "col352": "gw4zw", + "col353": "gvnca", + "col354": "vsiru", + "col355": "8ozkh", + "col356": "mtbw0", + "col357": "1vqqb", + "col358": "8pxmp", + "col359": "usgf4", + "col360": "qqz4v", + "col361": "ars4d", + "col362": "4vc1b", + "col363": "ptuve", + "col364": "rk69p", + "col365": "92f46", + "col366": "qpobf", + "col367": "hu0v9", + "col368": "7fnwt", + "col369": "e3l8y", + "col370": "jjo55", + "col371": "fv59r", + "col372": "ejjm0", + "col373": "3ur78", + "col374": "i5nkd", + "col375": "q7dlm", + "col376": "vxhc7", + "col377": "qo6q8", + "col378": "zs1h2", + "col379": "39d5f", + "col380": "ofa3p", + "col381": "nst5g", + "col382": "iueec", + "col383": "o0ax6", + "col384": "flkie", + "col385": "mkv0b", + "col386": "wpg83", + "col387": "gh47f", + "col388": "7jjym", + "col389": "r2998", + "col390": "ue990", + "col391": "mbbv6", + "col392": "rp8lb", + "col393": "z55q7", + "col394": "xwflt", + "col395": "ibjh8", + "col396": "eco29", + "col397": "yevgi", + "col398": "rp3ka", + "col399": "99ta8", + "col400": "ls1kq", + "col401": "ymdms", + "col402": "xyq68", + "col403": "zk8iv", + "col404": "qdppy", + "col405": "xxeyl", + "col406": "17owb", + "col407": "mknzw", + "col408": "vau0c", + "col409": "gjfq6", + "col410": "m0ys3", + "col411": "wnesp", + "col412": "nxlxx", + "col413": "hb3ua", + "col414": "z7d9t", + "col415": "d9cv5", + "col416": "i7v17", + "col417": "im0jk", + "col418": "fcqnq", + "col419": "e5zij", + "col420": "eti6d", + "col421": "tvxz1", + "col422": "9irab", + "col423": "fvskn", + "col424": "o0al4", + "col425": "mauvb", + "col426": "g2kdm", + "col427": "4ga2j", + "col428": "i50wt", + "col429": "fr155", + "col430": "6sf8h", + "col431": "trzx2", + "col432": "uszze", + "col433": "5lllg", + "col434": "qdc8z", + "col435": "us5pw", + "col436": "k34qk", + "col437": "g09ha", + "col438": "jxq2s", + "col439": "489hf", + "col440": "gy2ae", + "col441": "af7wo", + "col442": "inp2r", + "col443": "oyq9g", + "col444": "04o7x", + "col445": "sbiog", + "col446": "y0ta0", + "col447": "inykc", + "col448": "i1al4", + "col449": "80e9i", + "col450": "5p1i0", + "col451": "z6sje", + "col452": "9ftwg", + "col453": "aapm0", + "col454": "djn5w", + "col455": "austc", + "col456": "tyvhu", + "col457": "s0yyg", + "col458": "8l8aq", + "col459": "u4xbu", + "col460": "qddak", + "col461": "95gdq", + "col462": "y7wc4", + "col463": "qvn90", + "col464": "23t9x", + "col465": "laksp", + "col466": "ctnx0", + "col467": "ah4kx", + "col468": "y7uks", + "col469": "9okg9", + "col470": "io6zs", + "col471": "spx0p", + "col472": "3h31v", + "col473": "fnhwv", + "col474": "5yjmk", + "col475": "nv7y0", + "col476": "tcjjn", + "col477": "90wdz", + "col478": "q8ji3", + "col479": "h4rxv", + "col480": "zboch", + "col481": "2wt1i", + "col482": "xaguc", + "col483": "hhsk1", + "col484": "d1wa7", + "col485": "blbga", + "col486": "isy1v", + "col487": "qaezt", + "col488": "dzh8k", + "col489": "whzin", + "col490": "napa3", + "col491": "j5b2t", + "col492": "fmx8n", + "col493": "js9cs", + "col494": "j5clj", + "col495": "74p91", + "col496": "g1cb2", + "col497": "3aupc", + "col498": "ps4ld", + "col499": "huhgl", + "col500": "b4w9w", + "col501": "fshcg", + "col502": "7jqdb", + "col503": "tac5m", + "col504": "8swlc", + "col505": "tkjsj", + "col506": "w6t4f", + "col507": "3chv1", + "col508": "pdhif", + "col509": "6uyej", + "col510": "xtuk7", + "col511": "ri34t", + "col512": "78ayy", + "col513": "o9wil", + "col514": "4pa9a", + "col515": "vhj4u", + "col516": "ublfn", + "col517": "7zrp4", + "col518": "fao3a", + "col519": "w8cbi", + "col520": "5czw6", + "col521": "lel11", + "col522": "pc6gp", + "col523": "7g2w3", + "col524": "v23bf", + "col525": "yno84", + "col526": "u3dpz", + "col527": "1okst", + "col528": "n5lzn", + "col529": "cu8hx", + "col530": "qmtzb", + "col531": "dgmwb", + "col532": "lrgkk", + "col533": "f4q91", + "col534": "uc74w", + "col535": "o393l", + "col536": "xeb96", + "col537": "o72hg", + "col538": "u0yuz", + "col539": "5p5y8", + "col540": "jilsv", + "col541": "1g9rc", + "col542": "sxq12", + "col543": "g3h4e", + "col544": "dg6y4", + "col545": "3yi9k", + "col546": "m0x4s", + "col547": "mhdwd", + "col548": "qunl0", + "col549": "nj8sm", + "col550": "adzw3", + "col551": "u8gz2", + "col552": "05rqm", + "col553": "tbboe", + "col554": "c5j2t", + "col555": "ltq7k", + "col556": "el55m", + "col557": "0lpvf", + "col558": "rumwz", + "col559": "rhe49", + "col560": "vt83u", + "col561": "xy89j", + "col562": "d94s5", + "col563": "afo42", + "col564": "91gop", + "col565": "n6qe9", + "col566": "q3e8g", + "col567": "fu5jo", + "col568": "ni7c6", + "col569": "q89ue", + "col570": "9l5h5", + "col571": "phtmc", + "col572": "7gxf9", + "col573": "an81o", + "col574": "nayrk", + "col575": "h3zis", + "col576": "bfns6", + "col577": "lmwsa", + "col578": "oymix", + "col579": "06s6v", + "col580": "zrhva", + "col581": "7ub1c", + "col582": "if3pz", + "col583": "1bdsk", + "col584": "zu706", + "col585": "npl7v", + "col586": "ky15s", + "col587": "thbzd", + "col588": "1vbzu", + "col589": "nbf0v", + "col590": "9gedq", + "col591": "a2wvh", + "col592": "m37nd", + "col593": "32fzf", + "col594": "cuchk", + "col595": "rozwn", + "col596": "mk6q4", + "col597": "w7oox", + "col598": "55ub2", + "col599": "vamdy", + "col600": "vus11", + "col601": "7imiw", + "col602": "rkxyq", + "col603": "wx5nq", + "col604": "ohe7g", + "col605": "vziel", + "col606": "ikvcw", + "col607": "pk0d4", + "col608": "bj8mh", + "col609": "cc4y9", + "col610": "wcpgu", + "col611": "9aidw", + "col612": "ygzpy", + "col613": "noz7h", + "col614": "dbmcb", + "col615": "9t7fz", + "col616": "d9e5d", + "col617": "pbqm2", + "col618": "cwaai", + "col619": "zjvo7", + "col620": "wdicr", + "col621": "fdwnu", + "col622": "j62qb", + "col623": "wcqpa", + "col624": "iq4t5", + "col625": "y6nn6", + "col626": "wmn02", + "col627": "99oya", + "col628": "j0650", + "col629": "2bway", + "col630": "ujd0b", + "col631": "fn87u", + "col632": "4fhw4", + "col633": "u2x0a", + "col634": "wtljo", + "col635": "zys7l", + "col636": "nqpte", + "col637": "738ct", + "col638": "jmi64", + "col639": "9aq7h", + "col640": "5qfd8", + "col641": "gji6l", + "col642": "y3uby", + "col643": "d6iuq", + "col644": "u20md", + "col645": "ajsh4", + "col646": "ogqmk", + "col647": "7ll40", + "col648": "5r64u", + "col649": "lkpa7", + "col650": "ho3on", + "col651": "v912a", + "col652": "obvsv", + "col653": "n37h9", + "col654": "xm6l0", + "col655": "6zcdn", + "col656": "zv6p1", + "col657": "d4xq9", + "col658": "wy5un", + "col659": "sdiq0", + "col660": "iv2xh", + "col661": "9xx36", + "col662": "ua1ax", + "col663": "qz1sz", + "col664": "zhfv0", + "col665": "am36b", + "col666": "4uuv5", + "col667": "vv2vm", + "col668": "p57m0", + "col669": "l16fo", + "col670": "qt9sp", + "col671": "cw26n", + "col672": "u6bw7", + "col673": "a7eh6", + "col674": "mho15", + "col675": "rm2ig", + "col676": "5myhz", + "col677": "kntgh", + "col678": "y115r", + "col679": "fkgcy", + "col680": "wlq48", + "col681": "6yxju", + "col682": "zrukg", + "col683": "nto48", + "col684": "5pe2t", + "col685": "xm63j", + "col686": "s3hb0", + "col687": "teqg8", + "col688": "3d4vd", + "col689": "6qw29", + "col690": "6wzxn", + "col691": "tf4on", + "col692": "x9mzl", + "col693": "9ccik", + "col694": "9n5zv", + "col695": "d6c0k", + "col696": "zvkqk", + "col697": "9nl3y", + "col698": "iqpmd", + "col699": "f0ssa", + "col700": "c05dd", + "col701": "10gwd", + "col702": "m7fhf", + "col703": "4isy8", + "col704": "65tnn", + "col705": "mjq59", + "col706": "qeekg", + "col707": "j3uiw", + "col708": "r7g8p", + "col709": "ae5xz", + "col710": "11u29", + "col711": "4e42p", + "col712": "7dj9o", + "col713": "yr6g0", + "col714": "7ooui", + "col715": "6f98k", + "col716": "zxszi", + "col717": "02d1u", + "col718": "9ubgl", + "col719": "aqcbe", + "col720": "ybb3q", + "col721": "psokw", + "col722": "hwn3n", + "col723": "p8st9", + "col724": "i172q", + "col725": "87db4", + "col726": "3f8wi", + "col727": "9x678", + "col728": "x0jr5", + "col729": "i19k3", + "col730": "h14kh", + "col731": "4jiu4", + "col732": "g3zac", + "col733": "78cbj", + "col734": "smm7z", + "col735": "2kwaw", + "col736": "ft3ux", + "col737": "tyzfb", + "col738": "sjemb", + "col739": "iqtwv", + "col740": "tggm3", + "col741": "rlkvt", + "col742": "q7fg1", + "col743": "in00q", + "col744": "cycq9", + "col745": "f64hv", + "col746": "kk2hj", + "col747": "jyrug", + "col748": "df21u", + "col749": "gf30h", + "col750": "79kuj", + "col751": "s5605", + "col752": "qbj1o", + "col753": "62om4", + "col754": "d9csg", + "col755": "k4tph", + "col756": "ufpnr", + "col757": "i2q7f", + "col758": "vkiri", + "col759": "ltbzm", + "col760": "cnwwp", + "col761": "d6via", + "col762": "trvrn", + "col763": "98cei", + "col764": "m5mro", + "col765": "ayb32", + "col766": "40nfb", + "col767": "pe8ga", + "col768": "rm02i", + "col769": "cc4gy", + "col770": "qsneh", + "col771": "mfikc", + "col772": "pnufj", + "col773": "aw9wz", + "col774": "xjsdy", + "col775": "5hwa0", + "col776": "c1zfh", + "col777": "8em09", + "col778": "b2fnq", + "col779": "a1x1r", + "col780": "la006", + "col781": "lzi7e", + "col782": "c1xzm", + "col783": "bd177", + "col784": "m8kb1", + "col785": "b2z75", + "col786": "wxeep", + "col787": "6ddn5", + "col788": "peecq", + "col789": "o0qfj", + "col790": "ork9u", + "col791": "mff4q", + "col792": "tc9l0", + "col793": "on3bg", + "col794": "2gfqa", + "col795": "bodoq", + "col796": "nop4s", + "col797": "4juqo", + "col798": "8lvxx", + "col799": "iacqg", + "col800": "h1f2p", + "col801": "b6ee2", + "col802": "3zq7f", + "col803": "daiy2", + "col804": "cbma2", + "col805": "0esjc", + "col806": "qzdm5", + "col807": "1vdks", + "col808": "vseng", + "col809": "nta1w", + "col810": "s8hvx", + "col811": "buf7n", + "col812": "28wgs", + "col813": "mcgkw", + "col814": "fzx1x", + "col815": "rf2qw", + "col816": "tjx49", + "col817": "rmkmn", + "col818": "llt6h", + "col819": "uthwv", + "col820": "hbhlg", + "col821": "zakr1", + "col822": "9bpwx", + "col823": "kj4yg", + "col824": "m3dzl", + "col825": "qtwie", + "col826": "cwgmy", + "col827": "7ek8w", + "col828": "aotwo", + "col829": "fv58o", + "col830": "jlp4l", + "col831": "oo5zd", + "col832": "rqjey", + "col833": "jb04d", + "col834": "q2umd", + "col835": "lp8fy", + "col836": "afjre", + "col837": "amg00", + "col838": "xohxe", + "col839": "uxib4", + "col840": "h8jbo", + "col841": "3603y", + "col842": "nabpr", + "col843": "v8fta", + "col844": "crmkm", + "col845": "fuam9", + "col846": "2zvcc", + "col847": "4polp", + "col848": "9ft3l", + "col849": "ws56h", + "col850": "cfxai", + "col851": "32myg", + "col852": "7jozr", + "col853": "s90b8", + "col854": "3qpqz", + "col855": "g9bpu", + "col856": "i1j1m", + "col857": "ixb04", + "col858": "kapx9", + "col859": "1qxll", + "col860": "9c7ge", + "col861": "wpchi", + "col862": "ylfqk", + "col863": "7a1yw", + "col864": "9kfb4", + "col865": "vehpl", + "col866": "mz2hr", + "col867": "kp6tz", + "col868": "tw9r5", + "col869": "7or5x", + "col870": "1ouy7", + "col871": "pzdv8", + "col872": "1m589", + "col873": "dvwb7", + "col874": "qdb5y", + "col875": "aiauv", + "col876": "86fq3", + "col877": "02d3e", + "col878": "jo27z", + "col879": "dbz7m", + "col880": "9d7pq", + "col881": "ssrdj", + "col882": "gc9s0", + "col883": "q7g68", + "col884": "9m27j", + "col885": "45yef", + "col886": "u66wl", + "col887": "6zze2", + "col888": "ioztl", + "col889": "xh7ju", + "col890": "h7kb1", + "col891": "b0g57", + "col892": "z6dh7", + "col893": "ykcj5", + "col894": "1s74v", + "col895": "6uwvd", + "col896": "76dkl", + "col897": "4bisd", + "col898": "imeq3", + "col899": "w8d77", + "col900": "w9064", + "col901": "mceo8", + "col902": "rqop5", + "col903": "tgtzi", + "col904": "i8l4p", + "col905": "jgrkr", + "col906": "u13fv", + "col907": "2n6wx", + "col908": "q24y4", + "col909": "d6voy", + "col910": "shl6h", + "col911": "kpp96", + "col912": "jguw6", + "col913": "1dr6x", + "col914": "u2cm4", + "col915": "fgpkt", + "col916": "0htb6", + "col917": "kn297", + "col918": "c15es", + "col919": "kjctk", + "col920": "f85u2", + "col921": "ky20h", + "col922": "dp8hh", + "col923": "7z0y3", + "col924": "tdp0t", + "col925": "ktacu", + "col926": "0j6u4", + "col927": "79xqz", + "col928": "0xtjc", + "col929": "0b9b4", + "col930": "dnj4p", + "col931": "2zcpk", + "col932": "0554u", + "col933": "b3g3k", + "col934": "y3sqm", + "col935": "wlskn", + "col936": "yq0o7", + "col937": "gxih0", + "col938": "ncz9z", + "col939": "jnar8", + "col940": "3ez5j", + "col941": "wid4u", + "col942": "sk0fj", + "col943": "lodwq", + "col944": "rfdod", + "col945": "oacq2", + "col946": "ijfjl", + "col947": "34p1c", + "col948": "o7wwg", + "col949": "2rvqg", + "col950": "cb2jy", + "col951": "lzm0u", + "col952": "5b16w", + "col953": "wtkr8", + "col954": "wfqnv", + "col955": "xqx7x", + "col956": "4zezs", + "col957": "bzrc3", + "col958": "v0zp2", + "col959": "dtdk4", + "col960": "jsalx", + "col961": "cr4jr", + "col962": "nquuz", + "col963": "rcpme", + "col964": "z9p35", + "col965": "9ztw0", + "col966": "8wjk3", + "col967": "hk02d", + "col968": "bykou", + "col969": "as5f9", + "col970": "ywzvx", + "col971": "dld6o", + "col972": "117tr", + "col973": "kmlop", + "col974": "ut2px", + "col975": "x5sme", + "col976": "mcjzc", + "col977": "g7zg9", + "col978": "totai", + "col979": "mbegu", + "col980": "41sjb", + "col981": "baoix", + "col982": "qxtrw", + "col983": "6fwoz", + "col984": "a1hs3", + "col985": "54fcl", + "col986": "jw64j", + "col987": "3ljeh", + "col988": "ekiam", + "col989": "ybedd", + "col990": "v0kv4", + "col991": "gupqt", + "col992": "ygxsg", + "col993": "frihz", + "col994": "spv3n", + "col995": "v4wjh", + "col996": "uydzi", + "col997": "cro37", + "col998": "7d8tx", + "col999": "uiyvi" + }, + { + "name": "Colon Chen", + "gender": "male", + "col0": "c7xwa", + "col1": "xnvpe", + "col2": "y63dm", + "col3": "zccsk", + "col4": "xc4o6", + "col5": "fql8h", + "col6": "w5tqj", + "col7": "6mjc7", + "col8": "05f6w", + "col9": "ylnb7", + "col10": "lk4pi", + "col11": "k40xx", + "col12": "umet9", + "col13": "qsp9s", + "col14": "1kgng", + "col15": "2bsgi", + "col16": "6gxlb", + "col17": "8l82l", + "col18": "t58wn", + "col19": "dvwkr", + "col20": "5kmsm", + "col21": "7uf2n", + "col22": "fsho9", + "col23": "89rss", + "col24": "5wiah", + "col25": "lw6lu", + "col26": "nh5vw", + "col27": "mi704", + "col28": "jcibm", + "col29": "plfcz", + "col30": "62b76", + "col31": "psmil", + "col32": "a13zz", + "col33": "prkp4", + "col34": "431t3", + "col35": "mlcfs", + "col36": "ieet3", + "col37": "o5e4v", + "col38": "y4wwc", + "col39": "cbemp", + "col40": "6berc", + "col41": "vezv7", + "col42": "vwyii", + "col43": "j57zl", + "col44": "wbotu", + "col45": "qq2as", + "col46": "cg5lj", + "col47": "ys2hg", + "col48": "yohmv", + "col49": "aocqa", + "col50": "4gcch", + "col51": "frl76", + "col52": "b31k4", + "col53": "p8h25", + "col54": "jlrgg", + "col55": "dvavs", + "col56": "t5rwc", + "col57": "0vw49", + "col58": "s7r48", + "col59": "2gdkm", + "col60": "b155k", + "col61": "6gero", + "col62": "m44co", + "col63": "gqd1x", + "col64": "h6yd4", + "col65": "ib2nn", + "col66": "sbgxb", + "col67": "ccrc4", + "col68": "5riu1", + "col69": "q36s2", + "col70": "621h0", + "col71": "yf99p", + "col72": "xl9dj", + "col73": "maoh7", + "col74": "6ahrp", + "col75": "zg46l", + "col76": "3rzal", + "col77": "7nm80", + "col78": "ic4oo", + "col79": "hnioy", + "col80": "8tm3w", + "col81": "p6biy", + "col82": "88tu8", + "col83": "s7acr", + "col84": "flqls", + "col85": "zff4u", + "col86": "2i8yu", + "col87": "4nqv8", + "col88": "8ingj", + "col89": "pmqqo", + "col90": "a02dt", + "col91": "08e0n", + "col92": "y7jpa", + "col93": "09epv", + "col94": "vbbok", + "col95": "99e9e", + "col96": "hykeo", + "col97": "9qku5", + "col98": "t4031", + "col99": "lft2j", + "col100": "w98ya", + "col101": "8c0bt", + "col102": "v9but", + "col103": "0ossa", + "col104": "4c5c2", + "col105": "rfjp4", + "col106": "6t658", + "col107": "ye493", + "col108": "a1t9i", + "col109": "gyz9y", + "col110": "e686y", + "col111": "qutca", + "col112": "6xo4n", + "col113": "vd2kg", + "col114": "eicm9", + "col115": "hwz3f", + "col116": "q5iln", + "col117": "tcamu", + "col118": "zpw15", + "col119": "0t1fg", + "col120": "tmzuc", + "col121": "73n5f", + "col122": "gxea7", + "col123": "ox98d", + "col124": "ssa49", + "col125": "3ay38", + "col126": "3dhii", + "col127": "coyxd", + "col128": "2jzru", + "col129": "f4idf", + "col130": "7ihjt", + "col131": "67uuu", + "col132": "9vrx6", + "col133": "ho283", + "col134": "0dxja", + "col135": "fftvt", + "col136": "lxw5v", + "col137": "mv4xo", + "col138": "0kfsa", + "col139": "d5xra", + "col140": "clbku", + "col141": "6wgq4", + "col142": "6588c", + "col143": "97pg8", + "col144": "o91kn", + "col145": "90fs3", + "col146": "u0wgy", + "col147": "xbcx5", + "col148": "17zki", + "col149": "gf48f", + "col150": "xz93j", + "col151": "lwf60", + "col152": "kazot", + "col153": "4zomk", + "col154": "zr5aw", + "col155": "ofduu", + "col156": "thd2k", + "col157": "fdzdp", + "col158": "rj5ay", + "col159": "bngmw", + "col160": "wsn2w", + "col161": "9hp13", + "col162": "69kcr", + "col163": "d1t5i", + "col164": "guw7f", + "col165": "1rh8d", + "col166": "1fnu7", + "col167": "tahjv", + "col168": "7vemp", + "col169": "07p2z", + "col170": "oqbvo", + "col171": "fhq8m", + "col172": "rvez9", + "col173": "wzn0g", + "col174": "5utac", + "col175": "jicv8", + "col176": "hijkx", + "col177": "znqri", + "col178": "vy9mk", + "col179": "raavj", + "col180": "lwp1w", + "col181": "sdoec", + "col182": "d6gjv", + "col183": "vu5ap", + "col184": "g5yy4", + "col185": "vjsur", + "col186": "7dmg5", + "col187": "s1kld", + "col188": "ol8sl", + "col189": "ujzqy", + "col190": "yzabr", + "col191": "d1g3r", + "col192": "lodw5", + "col193": "25pf0", + "col194": "ywuqn", + "col195": "cxckd", + "col196": "wqaky", + "col197": "fwubl", + "col198": "ey5i1", + "col199": "vnqx4", + "col200": "9h66m", + "col201": "hwvhi", + "col202": "5jinh", + "col203": "pd80j", + "col204": "7kh36", + "col205": "usyhb", + "col206": "2s9gi", + "col207": "rdad2", + "col208": "hgmps", + "col209": "b3rmf", + "col210": "c090y", + "col211": "aqa56", + "col212": "3xocf", + "col213": "d92ak", + "col214": "fheal", + "col215": "t0f1k", + "col216": "jn0m7", + "col217": "ecllh", + "col218": "9oq80", + "col219": "fjplg", + "col220": "ogl8d", + "col221": "aq8tk", + "col222": "nc066", + "col223": "hixil", + "col224": "ggkpq", + "col225": "2q6i5", + "col226": "ifl5y", + "col227": "nxedk", + "col228": "qust4", + "col229": "c5y6m", + "col230": "ltfe0", + "col231": "fjx7b", + "col232": "ebzj7", + "col233": "nw1rs", + "col234": "g8uuk", + "col235": "6abvm", + "col236": "5drqx", + "col237": "18qot", + "col238": "94azr", + "col239": "azo1s", + "col240": "1gats", + "col241": "vkuad", + "col242": "dpg16", + "col243": "aubqi", + "col244": "v2nn1", + "col245": "xodwb", + "col246": "cel4z", + "col247": "cah49", + "col248": "jxvgw", + "col249": "txfjg", + "col250": "08sdb", + "col251": "byyc3", + "col252": "y8h51", + "col253": "julvp", + "col254": "xbpwb", + "col255": "rj7h1", + "col256": "nb78l", + "col257": "qqsfm", + "col258": "gb78r", + "col259": "61879", + "col260": "inwvk", + "col261": "62wtx", + "col262": "0zqm9", + "col263": "1mr06", + "col264": "44hhl", + "col265": "l31ha", + "col266": "2j2ka", + "col267": "15c3t", + "col268": "sa48h", + "col269": "j1ppb", + "col270": "oj4du", + "col271": "vi89n", + "col272": "b8u3i", + "col273": "b4qql", + "col274": "3507t", + "col275": "spwm7", + "col276": "lq9tu", + "col277": "6jgp6", + "col278": "wxken", + "col279": "zzotz", + "col280": "ezu58", + "col281": "xziah", + "col282": "pk63g", + "col283": "glrpp", + "col284": "6u0pz", + "col285": "shdu8", + "col286": "rflw3", + "col287": "nkvzg", + "col288": "lkb1v", + "col289": "rukv5", + "col290": "42yp9", + "col291": "0l5q8", + "col292": "5wmjy", + "col293": "5guv3", + "col294": "owbju", + "col295": "0vlnz", + "col296": "ph9s9", + "col297": "ehvow", + "col298": "hc012", + "col299": "drcbo", + "col300": "60irt", + "col301": "bksr3", + "col302": "qao3a", + "col303": "vy7cu", + "col304": "73x4u", + "col305": "5pcq1", + "col306": "dwdja", + "col307": "6dgm7", + "col308": "5t784", + "col309": "3l146", + "col310": "0sovp", + "col311": "z22bd", + "col312": "q3am2", + "col313": "fv5ej", + "col314": "ivkp6", + "col315": "uhnqg", + "col316": "0xy0m", + "col317": "mm5ca", + "col318": "zksk6", + "col319": "lagmi", + "col320": "ldt2s", + "col321": "taiyc", + "col322": "xiba9", + "col323": "dsup5", + "col324": "hdxk9", + "col325": "f7uco", + "col326": "q1uif", + "col327": "xl1lt", + "col328": "wlrtn", + "col329": "ufc99", + "col330": "2fvgu", + "col331": "7otfc", + "col332": "d8rpr", + "col333": "2fpud", + "col334": "s35wm", + "col335": "94pfx", + "col336": "0pwqt", + "col337": "pancb", + "col338": "88e84", + "col339": "neo5c", + "col340": "tvize", + "col341": "onfuv", + "col342": "o85vh", + "col343": "b6s6o", + "col344": "96o1v", + "col345": "56tnw", + "col346": "a7lej", + "col347": "sue6a", + "col348": "bnxrp", + "col349": "tleoh", + "col350": "xh28c", + "col351": "gyrh0", + "col352": "ptgjt", + "col353": "cotdk", + "col354": "ajsj6", + "col355": "16u25", + "col356": "6eca3", + "col357": "zdjwr", + "col358": "miggp", + "col359": "lp9uw", + "col360": "w0ttx", + "col361": "r9q7r", + "col362": "5f4l2", + "col363": "gk6ut", + "col364": "2r2mm", + "col365": "c6yix", + "col366": "r62u0", + "col367": "2dlwl", + "col368": "4g8fg", + "col369": "55h2m", + "col370": "huvdj", + "col371": "g3izx", + "col372": "r24mb", + "col373": "4em1z", + "col374": "w03zu", + "col375": "g2mzl", + "col376": "3s30p", + "col377": "szn08", + "col378": "ddme7", + "col379": "66ohf", + "col380": "b7z2z", + "col381": "rwkbh", + "col382": "h1ewt", + "col383": "ldz7m", + "col384": "2x08q", + "col385": "ieibc", + "col386": "bwr6o", + "col387": "vy6xe", + "col388": "33iri", + "col389": "u677d", + "col390": "qrzz6", + "col391": "sk3su", + "col392": "e6x5b", + "col393": "os4nx", + "col394": "paep6", + "col395": "xh0n4", + "col396": "gmruu", + "col397": "3jli7", + "col398": "m1ow9", + "col399": "fbq1n", + "col400": "orpi6", + "col401": "889uq", + "col402": "hgvom", + "col403": "s98xf", + "col404": "gg6k1", + "col405": "shql8", + "col406": "mea8k", + "col407": "39492", + "col408": "gmxr0", + "col409": "ay4dq", + "col410": "cm1q0", + "col411": "nkd2f", + "col412": "8gbgb", + "col413": "vy7b6", + "col414": "4n4w9", + "col415": "g57sm", + "col416": "nhbx2", + "col417": "gnmr3", + "col418": "0dn83", + "col419": "eh8mn", + "col420": "i5btl", + "col421": "mlpi2", + "col422": "fgyyp", + "col423": "5ui06", + "col424": "82428", + "col425": "bkpgg", + "col426": "a64cw", + "col427": "2tfw0", + "col428": "5zk0t", + "col429": "pp713", + "col430": "403qc", + "col431": "s21w9", + "col432": "50xzs", + "col433": "9qp6w", + "col434": "h3yxp", + "col435": "nksel", + "col436": "oknq8", + "col437": "r32u1", + "col438": "zmsyj", + "col439": "da85l", + "col440": "x0giy", + "col441": "ywblj", + "col442": "a1ga8", + "col443": "dxblh", + "col444": "8udjh", + "col445": "r4r5k", + "col446": "cx5ci", + "col447": "9pnwx", + "col448": "lfdbg", + "col449": "b439z", + "col450": "sujew", + "col451": "mq66u", + "col452": "vif1o", + "col453": "0lxpx", + "col454": "wh41k", + "col455": "oyuwx", + "col456": "84tag", + "col457": "1hbhz", + "col458": "xolal", + "col459": "wj5d9", + "col460": "6i4at", + "col461": "29223", + "col462": "t5pbk", + "col463": "thunl", + "col464": "84bv3", + "col465": "1aj6b", + "col466": "arfiu", + "col467": "74re2", + "col468": "rvwhb", + "col469": "l7coy", + "col470": "3vgk9", + "col471": "ldaf6", + "col472": "mzfcq", + "col473": "sm9c4", + "col474": "h79bd", + "col475": "d4og6", + "col476": "ucjwp", + "col477": "e68xh", + "col478": "0gz6g", + "col479": "78slm", + "col480": "s86wj", + "col481": "vn1dn", + "col482": "3fdqp", + "col483": "4oj9z", + "col484": "obgil", + "col485": "auq0y", + "col486": "w76oi", + "col487": "2ygb2", + "col488": "bl0cf", + "col489": "fb6xg", + "col490": "5cdeu", + "col491": "yjdh4", + "col492": "upri0", + "col493": "6ppeu", + "col494": "woerg", + "col495": "wlpf7", + "col496": "mnasf", + "col497": "uij56", + "col498": "bng50", + "col499": "hpajv", + "col500": "ss5hd", + "col501": "0ikux", + "col502": "rcmg4", + "col503": "zjr7f", + "col504": "n3384", + "col505": "7hzfv", + "col506": "h0yq4", + "col507": "bqm6q", + "col508": "fw3uo", + "col509": "nny56", + "col510": "l5wuk", + "col511": "sggvr", + "col512": "rnrep", + "col513": "e2hjl", + "col514": "fmfm3", + "col515": "lxow8", + "col516": "oni2y", + "col517": "l58n8", + "col518": "we73s", + "col519": "2oo9w", + "col520": "v2lhk", + "col521": "1ahsz", + "col522": "ukstz", + "col523": "ajd2f", + "col524": "yu8g0", + "col525": "ergpz", + "col526": "fnrjb", + "col527": "34ir1", + "col528": "nihio", + "col529": "y9nhs", + "col530": "e729g", + "col531": "679zy", + "col532": "14jm7", + "col533": "vbs8u", + "col534": "tdwde", + "col535": "opxu6", + "col536": "2vg7o", + "col537": "t9hcw", + "col538": "kfea5", + "col539": "kyx7i", + "col540": "78q02", + "col541": "77i1y", + "col542": "83nfd", + "col543": "vd217", + "col544": "7b284", + "col545": "llsib", + "col546": "wok5k", + "col547": "z0q25", + "col548": "1adel", + "col549": "u1b6g", + "col550": "zzn8q", + "col551": "u43vk", + "col552": "ocov5", + "col553": "ccpla", + "col554": "umfcx", + "col555": "yo7yj", + "col556": "xxk03", + "col557": "lv42t", + "col558": "0sbs1", + "col559": "5zhft", + "col560": "7kflt", + "col561": "zfrza", + "col562": "3gbkp", + "col563": "tl1qb", + "col564": "omc9p", + "col565": "kgxqe", + "col566": "s6fjn", + "col567": "tfije", + "col568": "wcgu8", + "col569": "e5j9m", + "col570": "h8lcu", + "col571": "p81qp", + "col572": "8yp64", + "col573": "uvyts", + "col574": "3hbyk", + "col575": "xq7n6", + "col576": "i525b", + "col577": "iw7wy", + "col578": "ptha9", + "col579": "prulj", + "col580": "rljet", + "col581": "cmrm1", + "col582": "w2muo", + "col583": "c7fm0", + "col584": "466uc", + "col585": "cd6cd", + "col586": "rbbnm", + "col587": "yejit", + "col588": "x557p", + "col589": "g3xqa", + "col590": "jg9sz", + "col591": "0dsdw", + "col592": "skt29", + "col593": "i84ah", + "col594": "zc1pa", + "col595": "jtfwb", + "col596": "4v278", + "col597": "6qbv6", + "col598": "roycm", + "col599": "sdst6", + "col600": "vhmx1", + "col601": "u66ak", + "col602": "22kk8", + "col603": "1u91o", + "col604": "3loyr", + "col605": "egl46", + "col606": "49x0c", + "col607": "23zi5", + "col608": "7d8r1", + "col609": "j5p3h", + "col610": "gw3oj", + "col611": "nu5aw", + "col612": "pcej8", + "col613": "30ei9", + "col614": "fh422", + "col615": "tmnwi", + "col616": "5hsrd", + "col617": "u9jtn", + "col618": "e8qq6", + "col619": "6u3d5", + "col620": "qyfjb", + "col621": "asso9", + "col622": "xsino", + "col623": "6l3u1", + "col624": "lcgn7", + "col625": "d7rrm", + "col626": "kwnmh", + "col627": "hyg6d", + "col628": "r9q2w", + "col629": "tywwz", + "col630": "u3da9", + "col631": "it4uc", + "col632": "dsb7k", + "col633": "guu5m", + "col634": "2u4b2", + "col635": "01ef6", + "col636": "wucz9", + "col637": "802n4", + "col638": "95alc", + "col639": "d9oa6", + "col640": "u2djs", + "col641": "b90gk", + "col642": "0lgv8", + "col643": "zevuy", + "col644": "mu0f0", + "col645": "d70p8", + "col646": "7f2wb", + "col647": "orqm5", + "col648": "v4ay0", + "col649": "46g0d", + "col650": "4zwlr", + "col651": "l4h97", + "col652": "d0flp", + "col653": "sbrqy", + "col654": "91ml1", + "col655": "xyw2p", + "col656": "gnne2", + "col657": "dc9fx", + "col658": "cl01x", + "col659": "69ur8", + "col660": "x0wd1", + "col661": "coean", + "col662": "57wrf", + "col663": "euxj9", + "col664": "f1qzx", + "col665": "oq6p0", + "col666": "nvi9e", + "col667": "8itc3", + "col668": "uw6sb", + "col669": "8a8c5", + "col670": "xdiag", + "col671": "vukzq", + "col672": "o46ql", + "col673": "43jnq", + "col674": "b1ae8", + "col675": "56djg", + "col676": "she8r", + "col677": "610pt", + "col678": "m5ib4", + "col679": "6s1if", + "col680": "t8rzm", + "col681": "p6g3l", + "col682": "jqbi3", + "col683": "cmkf8", + "col684": "o368n", + "col685": "brezj", + "col686": "xektq", + "col687": "erxa5", + "col688": "o8mf9", + "col689": "ia5fi", + "col690": "t0qyo", + "col691": "nlu3y", + "col692": "hdo8v", + "col693": "fjeda", + "col694": "2h4hv", + "col695": "7zg0s", + "col696": "skhzp", + "col697": "6922d", + "col698": "0zshc", + "col699": "5txmj", + "col700": "5y6ck", + "col701": "ffjpi", + "col702": "ikfsa", + "col703": "l4orf", + "col704": "45id9", + "col705": "q1l4u", + "col706": "x3sjr", + "col707": "05s67", + "col708": "rlt2f", + "col709": "kg9fg", + "col710": "mmwl7", + "col711": "xz4uj", + "col712": "lzqef", + "col713": "9m251", + "col714": "xyzsg", + "col715": "7jsef", + "col716": "2i8kr", + "col717": "wvx25", + "col718": "75mxn", + "col719": "snlpa", + "col720": "xxm0v", + "col721": "rpqfw", + "col722": "gdqho", + "col723": "v4ioy", + "col724": "obsfp", + "col725": "nx6i6", + "col726": "rq5uk", + "col727": "ycd9z", + "col728": "k0rgq", + "col729": "aiq75", + "col730": "jmtz1", + "col731": "vvhiq", + "col732": "j19lr", + "col733": "cb4kr", + "col734": "y1vnq", + "col735": "nrg02", + "col736": "rziqx", + "col737": "t8rgy", + "col738": "tgah3", + "col739": "zn1bl", + "col740": "5g91v", + "col741": "u3h4p", + "col742": "hrj5d", + "col743": "l75a0", + "col744": "doyej", + "col745": "vlcua", + "col746": "djvqg", + "col747": "o859e", + "col748": "5l1gr", + "col749": "sz0id", + "col750": "95box", + "col751": "0ohuv", + "col752": "z4uvs", + "col753": "wckek", + "col754": "yy8h2", + "col755": "o1z9p", + "col756": "u8g5o", + "col757": "rf7po", + "col758": "dcqy7", + "col759": "zgwtw", + "col760": "ladm5", + "col761": "yrona", + "col762": "lesv1", + "col763": "7h9tp", + "col764": "a6n75", + "col765": "ppndz", + "col766": "a04jq", + "col767": "csx9j", + "col768": "tfcst", + "col769": "m9lzr", + "col770": "pokmt", + "col771": "h852f", + "col772": "efv3u", + "col773": "u66qy", + "col774": "cdi7m", + "col775": "54l02", + "col776": "hxsp1", + "col777": "fmkva", + "col778": "st1z9", + "col779": "w6i6t", + "col780": "rju89", + "col781": "2mpt8", + "col782": "fiq66", + "col783": "8orec", + "col784": "qrnyu", + "col785": "azfzg", + "col786": "ev5o0", + "col787": "lkvt4", + "col788": "8fp8j", + "col789": "5pvav", + "col790": "ow0ee", + "col791": "ab2g6", + "col792": "0yr73", + "col793": "2f3vb", + "col794": "4066t", + "col795": "n7hd7", + "col796": "g0b46", + "col797": "4vs7d", + "col798": "65m3y", + "col799": "6tfu6", + "col800": "gl8ad", + "col801": "xna35", + "col802": "jr0jd", + "col803": "h7my1", + "col804": "xx4se", + "col805": "zmd7f", + "col806": "5ccdn", + "col807": "2k4es", + "col808": "swlfe", + "col809": "579et", + "col810": "ukplk", + "col811": "zy73c", + "col812": "xfsjs", + "col813": "obso3", + "col814": "9ieg4", + "col815": "xqcsa", + "col816": "3104n", + "col817": "ie7z5", + "col818": "cwiim", + "col819": "hlnqv", + "col820": "356st", + "col821": "wxr8v", + "col822": "ows4t", + "col823": "pwtjf", + "col824": "ls17z", + "col825": "lp04w", + "col826": "1ssmw", + "col827": "yu1tq", + "col828": "e28v4", + "col829": "566pj", + "col830": "yfuqr", + "col831": "7yq9h", + "col832": "vz3xo", + "col833": "39au2", + "col834": "e71bq", + "col835": "8gmwk", + "col836": "1jj1y", + "col837": "03s9l", + "col838": "9mfx9", + "col839": "6qfsg", + "col840": "6c9yi", + "col841": "l2xuh", + "col842": "1i86m", + "col843": "xj8v8", + "col844": "twdst", + "col845": "zhp51", + "col846": "ldc81", + "col847": "nelko", + "col848": "odcwz", + "col849": "05sls", + "col850": "rofwt", + "col851": "7j90c", + "col852": "56s69", + "col853": "280dl", + "col854": "e7l6i", + "col855": "ga9gu", + "col856": "3semb", + "col857": "r7s25", + "col858": "jchws", + "col859": "jdpfc", + "col860": "p0hc6", + "col861": "22vg9", + "col862": "ehtpq", + "col863": "960sq", + "col864": "lgbga", + "col865": "zoame", + "col866": "7o3du", + "col867": "dmhw6", + "col868": "eogai", + "col869": "ohq8a", + "col870": "95575", + "col871": "h3bsa", + "col872": "cshht", + "col873": "qkn8p", + "col874": "hrzrq", + "col875": "43p31", + "col876": "k2vsa", + "col877": "65jk1", + "col878": "bx952", + "col879": "ll7z9", + "col880": "aswfc", + "col881": "fi3p2", + "col882": "drc8a", + "col883": "i1tdq", + "col884": "h9iqx", + "col885": "a05i1", + "col886": "r56wn", + "col887": "4nmcu", + "col888": "b8jhd", + "col889": "kj5ti", + "col890": "wnwgi", + "col891": "whu78", + "col892": "9asde", + "col893": "8gcgo", + "col894": "ek2st", + "col895": "899uj", + "col896": "f0ig9", + "col897": "pyuk9", + "col898": "tu93j", + "col899": "pxqca", + "col900": "zbhdi", + "col901": "i08dt", + "col902": "9r41r", + "col903": "zlf0v", + "col904": "9w1z8", + "col905": "hd6fp", + "col906": "a9fkl", + "col907": "dtdqn", + "col908": "dzxmj", + "col909": "xul2z", + "col910": "7e7xw", + "col911": "qrcqf", + "col912": "cgcw1", + "col913": "67yqq", + "col914": "mxueq", + "col915": "lrymy", + "col916": "0sh0w", + "col917": "wp5rw", + "col918": "m9pf3", + "col919": "x95mw", + "col920": "vv090", + "col921": "gd2ie", + "col922": "942n5", + "col923": "fawrf", + "col924": "e0k2s", + "col925": "80kw8", + "col926": "7uxl9", + "col927": "7vyp1", + "col928": "pstcx", + "col929": "7xm8d", + "col930": "u1ke8", + "col931": "wq8pg", + "col932": "j1lp4", + "col933": "o4pfv", + "col934": "eixjd", + "col935": "1f9vt", + "col936": "on4xe", + "col937": "h98zy", + "col938": "ude3j", + "col939": "cfkn3", + "col940": "6qq03", + "col941": "m354w", + "col942": "sytss", + "col943": "xx6bf", + "col944": "afdaz", + "col945": "gmwof", + "col946": "bb28d", + "col947": "k7zbv", + "col948": "tbxm9", + "col949": "9xnlw", + "col950": "lm3gu", + "col951": "1gyep", + "col952": "y97gc", + "col953": "y7cqh", + "col954": "prm4w", + "col955": "pvp8i", + "col956": "kumru", + "col957": "34z1s", + "col958": "waqil", + "col959": "2kbgy", + "col960": "l9pon", + "col961": "qqy6f", + "col962": "lj7i0", + "col963": "mjqev", + "col964": "po2mw", + "col965": "kvdgo", + "col966": "rvw24", + "col967": "hi8b4", + "col968": "ivslk", + "col969": "uupr0", + "col970": "zagyx", + "col971": "tw25z", + "col972": "8h0xj", + "col973": "z2isq", + "col974": "n0sje", + "col975": "ngxy5", + "col976": "0by2o", + "col977": "h52ia", + "col978": "72a2i", + "col979": "jwgyy", + "col980": "fpzpo", + "col981": "hskmv", + "col982": "bp2pz", + "col983": "6qfj1", + "col984": "udfop", + "col985": "h0z37", + "col986": "4p82p", + "col987": "eeriz", + "col988": "226mi", + "col989": "p8jy0", + "col990": "l8lkd", + "col991": "3fks2", + "col992": "mmm66", + "col993": "6qo55", + "col994": "ew3xv", + "col995": "381ef", + "col996": "cif14", + "col997": "zkpyh", + "col998": "jc9x5", + "col999": "ea2x3" + }, + { + "name": "Sweet Moon", + "gender": "male", + "col0": "37uyj", + "col1": "1j3s3", + "col2": "78bhb", + "col3": "jjk8h", + "col4": "7agl5", + "col5": "2o6b6", + "col6": "hlnpu", + "col7": "mvk44", + "col8": "1oddp", + "col9": "g7vhg", + "col10": "1ca5o", + "col11": "6dezs", + "col12": "5or5o", + "col13": "83bj7", + "col14": "wrqqb", + "col15": "mao80", + "col16": "w0xcp", + "col17": "an62u", + "col18": "sicu5", + "col19": "cynzi", + "col20": "ilm8v", + "col21": "n8ydm", + "col22": "bvurb", + "col23": "g45i1", + "col24": "a1u1d", + "col25": "vy6nx", + "col26": "a3uy8", + "col27": "v9gpt", + "col28": "h0hmr", + "col29": "ofuvt", + "col30": "297et", + "col31": "zsujw", + "col32": "pev9p", + "col33": "tiyj9", + "col34": "37zjn", + "col35": "z0zcq", + "col36": "kkz4g", + "col37": "o93au", + "col38": "lcoyf", + "col39": "0haqc", + "col40": "puk45", + "col41": "k5wg8", + "col42": "7ibgq", + "col43": "f8yq1", + "col44": "uckmz", + "col45": "9qsno", + "col46": "9vxhn", + "col47": "jfa60", + "col48": "0rk7h", + "col49": "us3zl", + "col50": "lcd1h", + "col51": "lp47n", + "col52": "ux8s1", + "col53": "rel71", + "col54": "dtx7k", + "col55": "7ohe6", + "col56": "4u1om", + "col57": "kiqf3", + "col58": "l16io", + "col59": "ujj5o", + "col60": "6kqof", + "col61": "27380", + "col62": "kv6xm", + "col63": "vh4c2", + "col64": "z0prp", + "col65": "g0al8", + "col66": "35p0o", + "col67": "lebns", + "col68": "es3i5", + "col69": "389rn", + "col70": "bin1d", + "col71": "dxbvm", + "col72": "jaltp", + "col73": "bignv", + "col74": "530y1", + "col75": "46b92", + "col76": "8n6tg", + "col77": "mmplb", + "col78": "us12d", + "col79": "sb4r4", + "col80": "k68mg", + "col81": "c8yq8", + "col82": "pa5jb", + "col83": "wkzfe", + "col84": "u4uf0", + "col85": "bcczl", + "col86": "zyku1", + "col87": "rvxod", + "col88": "bodeb", + "col89": "5omdh", + "col90": "8sr62", + "col91": "75rgc", + "col92": "bt051", + "col93": "2tv1u", + "col94": "tpesi", + "col95": "da0wv", + "col96": "qfq3t", + "col97": "ckn1o", + "col98": "tblgn", + "col99": "ootam", + "col100": "97w72", + "col101": "brcqh", + "col102": "gplg5", + "col103": "vdu3n", + "col104": "f7pfn", + "col105": "t6iie", + "col106": "ho8q1", + "col107": "j37sc", + "col108": "7hrme", + "col109": "jdt3v", + "col110": "2elz7", + "col111": "7ovv4", + "col112": "2brh8", + "col113": "o3npu", + "col114": "fcvx5", + "col115": "31yqh", + "col116": "r2wz6", + "col117": "gb88f", + "col118": "csed0", + "col119": "jp33s", + "col120": "js45t", + "col121": "m0kd3", + "col122": "09673", + "col123": "hyz5x", + "col124": "ekd1e", + "col125": "u0rys", + "col126": "n6mop", + "col127": "a8882", + "col128": "2lfsn", + "col129": "jnpfi", + "col130": "5twvg", + "col131": "8n60k", + "col132": "4npps", + "col133": "q5ie5", + "col134": "unvoi", + "col135": "6veas", + "col136": "z42xj", + "col137": "v2uod", + "col138": "4cms2", + "col139": "rbhj4", + "col140": "r21tr", + "col141": "tci05", + "col142": "fst08", + "col143": "39lm1", + "col144": "8pxc3", + "col145": "7q2dc", + "col146": "6w7fb", + "col147": "5r2hr", + "col148": "76wit", + "col149": "fi1ax", + "col150": "ykbop", + "col151": "3tqhg", + "col152": "nch42", + "col153": "4i6wr", + "col154": "eahxu", + "col155": "y0v8a", + "col156": "bdkue", + "col157": "ytyy6", + "col158": "a2mow", + "col159": "1nopo", + "col160": "gb869", + "col161": "87ju1", + "col162": "dr5n8", + "col163": "v63mu", + "col164": "okkbz", + "col165": "wkwpq", + "col166": "sameu", + "col167": "lqfur", + "col168": "h8duu", + "col169": "rflg7", + "col170": "0d8m7", + "col171": "9a0ad", + "col172": "91m59", + "col173": "nmzax", + "col174": "5g4as", + "col175": "uzuq4", + "col176": "xetph", + "col177": "u2zdd", + "col178": "418xu", + "col179": "hwbx6", + "col180": "niljn", + "col181": "5o303", + "col182": "y3oh2", + "col183": "4cwt7", + "col184": "c545p", + "col185": "k2qpl", + "col186": "f5ggr", + "col187": "v84ui", + "col188": "4svxr", + "col189": "tapwa", + "col190": "dqfhx", + "col191": "fm9ma", + "col192": "lxre3", + "col193": "l9w2v", + "col194": "bz9e9", + "col195": "gju3t", + "col196": "qhjhw", + "col197": "oejof", + "col198": "ivrzl", + "col199": "mqkwt", + "col200": "ii7pq", + "col201": "cfu29", + "col202": "ddjxr", + "col203": "kvh4s", + "col204": "2ncih", + "col205": "bqdq1", + "col206": "9gunq", + "col207": "at6nt", + "col208": "8nfyu", + "col209": "ihwjm", + "col210": "9h3xp", + "col211": "mmz3r", + "col212": "6lfck", + "col213": "yu80q", + "col214": "spvrv", + "col215": "d012x", + "col216": "r99pp", + "col217": "dq0cp", + "col218": "a7xnr", + "col219": "5xtnr", + "col220": "qvv07", + "col221": "45viw", + "col222": "sbs8t", + "col223": "6ktkp", + "col224": "xc0fw", + "col225": "byp9g", + "col226": "8fcmd", + "col227": "cechx", + "col228": "l9o0y", + "col229": "thld9", + "col230": "0zv3y", + "col231": "dy9tf", + "col232": "mn19v", + "col233": "mwdq8", + "col234": "dlu8c", + "col235": "ml5ho", + "col236": "7qfin", + "col237": "qhu5t", + "col238": "nhpaj", + "col239": "gucm3", + "col240": "o6121", + "col241": "icxly", + "col242": "ws6ot", + "col243": "tzjbv", + "col244": "lb1kx", + "col245": "1z17m", + "col246": "xlw2m", + "col247": "n002l", + "col248": "hjzeg", + "col249": "fw36d", + "col250": "f8xtm", + "col251": "98e3z", + "col252": "x5uwv", + "col253": "uipyk", + "col254": "oixns", + "col255": "bcjfr", + "col256": "qruep", + "col257": "wkovb", + "col258": "y0s25", + "col259": "3xe14", + "col260": "vm4du", + "col261": "xwg5g", + "col262": "2a42w", + "col263": "3p75b", + "col264": "zn842", + "col265": "t5pa3", + "col266": "l8okx", + "col267": "b6oy6", + "col268": "k4jiv", + "col269": "i9vg0", + "col270": "gahpm", + "col271": "9ugnu", + "col272": "of9zc", + "col273": "fljcu", + "col274": "q2m9f", + "col275": "5pevu", + "col276": "4whnm", + "col277": "75cv7", + "col278": "0vg76", + "col279": "rabbk", + "col280": "xbgee", + "col281": "23jg6", + "col282": "y38y5", + "col283": "b2x51", + "col284": "ojwjw", + "col285": "wa5u6", + "col286": "5g18g", + "col287": "1nivg", + "col288": "bqlds", + "col289": "37k1t", + "col290": "a6l3c", + "col291": "fcpri", + "col292": "rqmdu", + "col293": "4xld9", + "col294": "09ovu", + "col295": "3r5b0", + "col296": "nblop", + "col297": "zui5x", + "col298": "2x6fd", + "col299": "d65eu", + "col300": "d5j4l", + "col301": "2vq49", + "col302": "e62a3", + "col303": "emhxn", + "col304": "x1153", + "col305": "xcfyr", + "col306": "6lmxh", + "col307": "lsydf", + "col308": "u4a5q", + "col309": "fa74s", + "col310": "7lzhy", + "col311": "dwrys", + "col312": "z6sp8", + "col313": "hm7bz", + "col314": "xe7cg", + "col315": "5ozlm", + "col316": "kjskl", + "col317": "uu1jm", + "col318": "kzev3", + "col319": "gm1ce", + "col320": "oo4b0", + "col321": "rrrlm", + "col322": "66qgf", + "col323": "f8g0j", + "col324": "q0pvk", + "col325": "8yyo7", + "col326": "1ob83", + "col327": "pralo", + "col328": "2ptl4", + "col329": "1ww3e", + "col330": "3ew7t", + "col331": "k1aup", + "col332": "zyuu7", + "col333": "vus83", + "col334": "bbu9k", + "col335": "mfyxl", + "col336": "l5q4h", + "col337": "kolhr", + "col338": "8qcn0", + "col339": "88nm5", + "col340": "q7y21", + "col341": "iub78", + "col342": "nwt53", + "col343": "qdvdc", + "col344": "aicnw", + "col345": "aoxi6", + "col346": "zxs4p", + "col347": "h6fza", + "col348": "eonh2", + "col349": "huywo", + "col350": "zgd3z", + "col351": "qzbrm", + "col352": "mjqz1", + "col353": "nt489", + "col354": "dzcrx", + "col355": "2k9zf", + "col356": "6zq6i", + "col357": "lzvog", + "col358": "hx0j8", + "col359": "rdfcw", + "col360": "hfn8t", + "col361": "xapxv", + "col362": "vhj14", + "col363": "2ap2p", + "col364": "13l5o", + "col365": "gfgpl", + "col366": "w42nx", + "col367": "ni5uk", + "col368": "x9wk6", + "col369": "z7aem", + "col370": "gxsph", + "col371": "uxe97", + "col372": "ydnx2", + "col373": "9fox2", + "col374": "5x78c", + "col375": "8il4z", + "col376": "pze0t", + "col377": "0530d", + "col378": "3bj59", + "col379": "v3pr2", + "col380": "nkqk3", + "col381": "8ec7h", + "col382": "pa57a", + "col383": "lgzd6", + "col384": "8wh5t", + "col385": "36v5d", + "col386": "n39o4", + "col387": "vvevj", + "col388": "2fn9e", + "col389": "0nqaq", + "col390": "4awrw", + "col391": "3oa13", + "col392": "lj7sa", + "col393": "7psy9", + "col394": "vi8eu", + "col395": "mhcfw", + "col396": "jgi25", + "col397": "h4dl4", + "col398": "q3g6k", + "col399": "arojd", + "col400": "nzo4p", + "col401": "g54ij", + "col402": "bb3wn", + "col403": "qqs41", + "col404": "n02dl", + "col405": "78tx7", + "col406": "b21d3", + "col407": "jyh43", + "col408": "oa4i9", + "col409": "bj5zq", + "col410": "2t7lf", + "col411": "hdajt", + "col412": "cfs9i", + "col413": "ajsia", + "col414": "w3mae", + "col415": "jjovp", + "col416": "idief", + "col417": "646j2", + "col418": "g9l9r", + "col419": "cq1x5", + "col420": "aowvq", + "col421": "izlw5", + "col422": "yrmei", + "col423": "881lp", + "col424": "muyze", + "col425": "ofuqn", + "col426": "yv6hf", + "col427": "e0hes", + "col428": "u9ii9", + "col429": "42mhc", + "col430": "gic55", + "col431": "sbqg1", + "col432": "zzdzs", + "col433": "eo9qi", + "col434": "1hbse", + "col435": "tmcnf", + "col436": "ih9uk", + "col437": "5kjbf", + "col438": "kwdmn", + "col439": "99d69", + "col440": "cjnd2", + "col441": "lmpzu", + "col442": "ww8vc", + "col443": "j1xmr", + "col444": "7afx7", + "col445": "8f7vx", + "col446": "7taa2", + "col447": "0d5lo", + "col448": "pm8o7", + "col449": "itprj", + "col450": "83qbb", + "col451": "q7eqe", + "col452": "n8myk", + "col453": "4xiks", + "col454": "zvsy8", + "col455": "4r1gm", + "col456": "s2pwf", + "col457": "uwsdz", + "col458": "bt3rf", + "col459": "oia3n", + "col460": "wdon4", + "col461": "t02xi", + "col462": "crmsh", + "col463": "a78sm", + "col464": "p9cbf", + "col465": "ggs9h", + "col466": "hc24i", + "col467": "3eiau", + "col468": "m0lf6", + "col469": "aqs6h", + "col470": "o3olw", + "col471": "wrg26", + "col472": "7naof", + "col473": "cbr3p", + "col474": "kjvca", + "col475": "avcha", + "col476": "extfd", + "col477": "q75a8", + "col478": "ikygg", + "col479": "i1xqs", + "col480": "wspus", + "col481": "vco2r", + "col482": "tfuv0", + "col483": "vefln", + "col484": "wre13", + "col485": "s47an", + "col486": "9kyoo", + "col487": "568kr", + "col488": "ma92r", + "col489": "so6dv", + "col490": "084hp", + "col491": "rtyza", + "col492": "l03bv", + "col493": "zkcs4", + "col494": "8hfr2", + "col495": "xy90r", + "col496": "awcwk", + "col497": "lkucd", + "col498": "prhr7", + "col499": "866yo", + "col500": "kc7ia", + "col501": "gin50", + "col502": "0x08v", + "col503": "cftyg", + "col504": "dhoz8", + "col505": "uqr6q", + "col506": "0d928", + "col507": "k8kan", + "col508": "nhjwu", + "col509": "rqnxv", + "col510": "m9ab6", + "col511": "9h5hb", + "col512": "ucifw", + "col513": "gj56u", + "col514": "hpe5i", + "col515": "pw9u1", + "col516": "t8303", + "col517": "t5kud", + "col518": "08qvw", + "col519": "wp6mu", + "col520": "g897e", + "col521": "i74qs", + "col522": "iy8xs", + "col523": "fpq7c", + "col524": "q0rlk", + "col525": "votxf", + "col526": "yo6t4", + "col527": "5rauf", + "col528": "ovlfd", + "col529": "x3d2k", + "col530": "ckmk1", + "col531": "r108q", + "col532": "tuyla", + "col533": "mkgrj", + "col534": "pytdj", + "col535": "yggxb", + "col536": "tegsy", + "col537": "g4zpk", + "col538": "70z3s", + "col539": "v3l5h", + "col540": "0dtjv", + "col541": "iet21", + "col542": "v6k1n", + "col543": "erswb", + "col544": "udhkz", + "col545": "kwqmw", + "col546": "lvdsi", + "col547": "8qlrr", + "col548": "rolgq", + "col549": "ap7a1", + "col550": "josrg", + "col551": "hnhu1", + "col552": "k3sfs", + "col553": "3nww1", + "col554": "rrr60", + "col555": "xtk1w", + "col556": "978x7", + "col557": "ommu7", + "col558": "7xp8b", + "col559": "aew5z", + "col560": "zjlr3", + "col561": "51jth", + "col562": "qllai", + "col563": "9ckpn", + "col564": "bu9cb", + "col565": "ypwbx", + "col566": "ad9nu", + "col567": "bx877", + "col568": "575uq", + "col569": "44fxa", + "col570": "h2661", + "col571": "imex4", + "col572": "cbxpw", + "col573": "0xm41", + "col574": "1tf3d", + "col575": "xs2hl", + "col576": "k74ce", + "col577": "kx7ti", + "col578": "qdeuy", + "col579": "d8sa1", + "col580": "cnwnf", + "col581": "8ajah", + "col582": "dwvoc", + "col583": "xn2y9", + "col584": "llv6r", + "col585": "vmmgc", + "col586": "1rrie", + "col587": "tonos", + "col588": "xfs1p", + "col589": "mkxxj", + "col590": "lr8y0", + "col591": "7qchw", + "col592": "x0nxa", + "col593": "kpi6l", + "col594": "qpnv8", + "col595": "ikgtl", + "col596": "kwbtn", + "col597": "b8q75", + "col598": "40tb0", + "col599": "0ae62", + "col600": "ks48o", + "col601": "klh6v", + "col602": "boyjt", + "col603": "3d6n6", + "col604": "lvrgo", + "col605": "jkye8", + "col606": "ozqo4", + "col607": "8b4qd", + "col608": "wzo88", + "col609": "kh63p", + "col610": "accgm", + "col611": "wnjne", + "col612": "6e5v0", + "col613": "5qhz1", + "col614": "yxsmk", + "col615": "lud7p", + "col616": "d4lum", + "col617": "mh0to", + "col618": "csd8t", + "col619": "ytu9q", + "col620": "m8on8", + "col621": "qsn86", + "col622": "547gn", + "col623": "17f91", + "col624": "s1sh9", + "col625": "uaxmn", + "col626": "y5g53", + "col627": "22g9b", + "col628": "c7pa1", + "col629": "nbdhp", + "col630": "86r5u", + "col631": "mqvwo", + "col632": "doxj2", + "col633": "by6q6", + "col634": "4vivo", + "col635": "l1jb1", + "col636": "fy8oc", + "col637": "4d348", + "col638": "eij93", + "col639": "sq61t", + "col640": "jsblh", + "col641": "eefsw", + "col642": "x6zpd", + "col643": "30ipd", + "col644": "gslwi", + "col645": "1ngqn", + "col646": "2ctzt", + "col647": "0zyfo", + "col648": "80yu5", + "col649": "1j1s9", + "col650": "lzicc", + "col651": "0nq40", + "col652": "c9klj", + "col653": "ry9rb", + "col654": "0n9me", + "col655": "2fu57", + "col656": "zdv03", + "col657": "pgrpa", + "col658": "xko08", + "col659": "z535p", + "col660": "dtkp0", + "col661": "8ag9w", + "col662": "1otou", + "col663": "g42do", + "col664": "y1f38", + "col665": "ez4ml", + "col666": "3m4zt", + "col667": "7w8xi", + "col668": "2plqk", + "col669": "khckq", + "col670": "9bzzs", + "col671": "cxhfn", + "col672": "ve2k0", + "col673": "6jaca", + "col674": "791vl", + "col675": "osyeh", + "col676": "kgmp5", + "col677": "lnxw8", + "col678": "1wqw7", + "col679": "8sjgh", + "col680": "g8nla", + "col681": "3ta3e", + "col682": "qtoaz", + "col683": "ffg3r", + "col684": "dks94", + "col685": "sibul", + "col686": "c51fg", + "col687": "mnqq7", + "col688": "nr1vy", + "col689": "9y250", + "col690": "9tvdr", + "col691": "r3apu", + "col692": "sx1jg", + "col693": "tf0dx", + "col694": "hopt1", + "col695": "n44n8", + "col696": "uikm6", + "col697": "0vjns", + "col698": "h0bfz", + "col699": "p8e6x", + "col700": "4k17o", + "col701": "tvxir", + "col702": "wmc7g", + "col703": "j2m7r", + "col704": "3jtmh", + "col705": "52dq8", + "col706": "pozfm", + "col707": "wbbhk", + "col708": "muqfz", + "col709": "m31wq", + "col710": "e91vz", + "col711": "b49sy", + "col712": "z5d0m", + "col713": "o5wzd", + "col714": "99wue", + "col715": "403e9", + "col716": "ocgl3", + "col717": "g2o6t", + "col718": "boj9l", + "col719": "x9wcz", + "col720": "0xae6", + "col721": "ei9tu", + "col722": "59ygd", + "col723": "58wsj", + "col724": "d6rrj", + "col725": "8hzh8", + "col726": "87xoo", + "col727": "wbtew", + "col728": "g1wpp", + "col729": "uzixa", + "col730": "zov94", + "col731": "qu2pw", + "col732": "1jig9", + "col733": "ykg9l", + "col734": "5q4fv", + "col735": "yl7ar", + "col736": "zuoy7", + "col737": "oefof", + "col738": "2aamn", + "col739": "8hg4j", + "col740": "m5wtk", + "col741": "zqrxk", + "col742": "ninbz", + "col743": "n6wzg", + "col744": "uwjlu", + "col745": "fk5sx", + "col746": "grtlr", + "col747": "d23m3", + "col748": "vddjd", + "col749": "a8ifx", + "col750": "ouun8", + "col751": "7w4ns", + "col752": "5cns3", + "col753": "vi7q7", + "col754": "quatz", + "col755": "5aqnz", + "col756": "wml1d", + "col757": "w7401", + "col758": "iai15", + "col759": "3g22n", + "col760": "xap2i", + "col761": "hjscw", + "col762": "w9tgk", + "col763": "srws0", + "col764": "znk8u", + "col765": "vt42m", + "col766": "9hsbw", + "col767": "03oq7", + "col768": "ilgbp", + "col769": "wax74", + "col770": "u8eox", + "col771": "n29id", + "col772": "lgdjf", + "col773": "cpvn9", + "col774": "lejqa", + "col775": "cc1ke", + "col776": "ielqu", + "col777": "q7nb6", + "col778": "7l0lt", + "col779": "ll0dh", + "col780": "r95g3", + "col781": "2sllp", + "col782": "3lpx6", + "col783": "jqtqk", + "col784": "klx3q", + "col785": "0b6c4", + "col786": "pw5eb", + "col787": "l3b0k", + "col788": "v354t", + "col789": "h1jj4", + "col790": "7zqdj", + "col791": "42biq", + "col792": "ishjw", + "col793": "p8y4k", + "col794": "859fl", + "col795": "gfb5e", + "col796": "d89r0", + "col797": "8fshz", + "col798": "6oakm", + "col799": "2t9am", + "col800": "7m8yt", + "col801": "1xx9s", + "col802": "05kzk", + "col803": "o11mc", + "col804": "8d6m6", + "col805": "96o0w", + "col806": "10x4b", + "col807": "ipwxb", + "col808": "238r8", + "col809": "uzdpo", + "col810": "f3l5y", + "col811": "o7t55", + "col812": "5c6qa", + "col813": "w3i0c", + "col814": "1e9ka", + "col815": "z1dm3", + "col816": "7c35r", + "col817": "eml6d", + "col818": "f775g", + "col819": "aic6t", + "col820": "1opdk", + "col821": "v0jq8", + "col822": "inuos", + "col823": "ixml1", + "col824": "3ky2f", + "col825": "0b0ld", + "col826": "ac0a1", + "col827": "rzr5b", + "col828": "fd5l6", + "col829": "j3mh5", + "col830": "45cdj", + "col831": "opfkm", + "col832": "ctj8b", + "col833": "ankix", + "col834": "hy33h", + "col835": "nqf81", + "col836": "y0dhb", + "col837": "1ngyk", + "col838": "c6cs7", + "col839": "r5b1a", + "col840": "efk33", + "col841": "lcsih", + "col842": "6wt9s", + "col843": "z89sa", + "col844": "mj0ad", + "col845": "akd5c", + "col846": "zhw3q", + "col847": "ybj5b", + "col848": "p2svb", + "col849": "xo517", + "col850": "6ogyr", + "col851": "knoqo", + "col852": "v1cac", + "col853": "jf59m", + "col854": "fxdpw", + "col855": "hph37", + "col856": "zrj6i", + "col857": "wstkr", + "col858": "12bvm", + "col859": "mzvsp", + "col860": "zb85w", + "col861": "up5mx", + "col862": "os3o5", + "col863": "2adhb", + "col864": "g4958", + "col865": "3zvbm", + "col866": "hyam7", + "col867": "grgk6", + "col868": "75u1p", + "col869": "e114s", + "col870": "flcp7", + "col871": "4u0uu", + "col872": "p8i2v", + "col873": "5ba8d", + "col874": "p8gqg", + "col875": "gcoob", + "col876": "u1j14", + "col877": "f021a", + "col878": "m6zvl", + "col879": "no3cf", + "col880": "fapn4", + "col881": "jt78h", + "col882": "cs9yo", + "col883": "3z11h", + "col884": "jww5f", + "col885": "opgph", + "col886": "du6dd", + "col887": "vxfh0", + "col888": "o3aoc", + "col889": "fem66", + "col890": "2agyr", + "col891": "wplke", + "col892": "42bei", + "col893": "5ltts", + "col894": "myx6f", + "col895": "nn1xt", + "col896": "8glvd", + "col897": "p4axv", + "col898": "ty0o0", + "col899": "cb3ii", + "col900": "tkazn", + "col901": "d6pyx", + "col902": "3ll1d", + "col903": "odnti", + "col904": "iroz7", + "col905": "rx075", + "col906": "vi2si", + "col907": "eskkw", + "col908": "fw7ni", + "col909": "a8enl", + "col910": "8v369", + "col911": "ewt85", + "col912": "smehz", + "col913": "ccfap", + "col914": "mqlex", + "col915": "j6y7x", + "col916": "vifhs", + "col917": "75ibv", + "col918": "win2t", + "col919": "p9alu", + "col920": "dirki", + "col921": "vbymr", + "col922": "u8knt", + "col923": "sl11w", + "col924": "qgc0t", + "col925": "whc5b", + "col926": "tkiga", + "col927": "olpwl", + "col928": "prpzo", + "col929": "y0if9", + "col930": "vgqiu", + "col931": "20bfv", + "col932": "2dmjn", + "col933": "z2pzl", + "col934": "nqk5z", + "col935": "oi4mh", + "col936": "hd6cz", + "col937": "4asax", + "col938": "si3it", + "col939": "joosd", + "col940": "kz5ky", + "col941": "ue46s", + "col942": "mcpjj", + "col943": "hv321", + "col944": "iag4q", + "col945": "0bft4", + "col946": "0two3", + "col947": "lwa6l", + "col948": "ud2sb", + "col949": "zmtst", + "col950": "y9ucj", + "col951": "9yc0b", + "col952": "1rgxt", + "col953": "c21up", + "col954": "yyw9r", + "col955": "akywz", + "col956": "xnrz3", + "col957": "ei8oi", + "col958": "kajp1", + "col959": "y3ni3", + "col960": "vvzey", + "col961": "gzowk", + "col962": "apoqu", + "col963": "vkm9n", + "col964": "0gjnx", + "col965": "an7lh", + "col966": "svnps", + "col967": "3oozs", + "col968": "n6cff", + "col969": "3ujji", + "col970": "2833v", + "col971": "khwzi", + "col972": "4rf02", + "col973": "10cn9", + "col974": "ygxl8", + "col975": "waecq", + "col976": "i5fyv", + "col977": "ktamk", + "col978": "atfkw", + "col979": "8cadr", + "col980": "brot1", + "col981": "jnkad", + "col982": "a4j1r", + "col983": "wkfdt", + "col984": "th5yf", + "col985": "a81ms", + "col986": "12ekb", + "col987": "sdrhx", + "col988": "jwxi8", + "col989": "s4vit", + "col990": "ztsxg", + "col991": "kh1ai", + "col992": "4h15y", + "col993": "4sr33", + "col994": "xm124", + "col995": "m1ujs", + "col996": "yirqv", + "col997": "un1i1", + "col998": "72t5e", + "col999": "p45pz" + }, + { + "name": "Cheryl White", + "gender": "female", + "col0": "iqwi1", + "col1": "976vx", + "col2": "cwb9u", + "col3": "6qh10", + "col4": "es7hb", + "col5": "y9tz5", + "col6": "qq24f", + "col7": "i0e2m", + "col8": "84ngj", + "col9": "19z2o", + "col10": "rqy4j", + "col11": "hlyha", + "col12": "xxat9", + "col13": "d1tyw", + "col14": "14805", + "col15": "lnilj", + "col16": "mo1df", + "col17": "hws7f", + "col18": "k4iyg", + "col19": "mno75", + "col20": "3e37y", + "col21": "a9yup", + "col22": "8v1e4", + "col23": "kt4m1", + "col24": "u1ft4", + "col25": "72o5d", + "col26": "d9ou2", + "col27": "q3yhe", + "col28": "r2kmm", + "col29": "m2b7d", + "col30": "z0ldx", + "col31": "a3p80", + "col32": "yq0c8", + "col33": "d6065", + "col34": "iqlwf", + "col35": "f88mx", + "col36": "3nhw3", + "col37": "j2may", + "col38": "fjqdt", + "col39": "1462e", + "col40": "4s5rf", + "col41": "8n34y", + "col42": "63nvk", + "col43": "r5n1k", + "col44": "0v9ee", + "col45": "jjlmt", + "col46": "s3nvh", + "col47": "mvoi4", + "col48": "vc78n", + "col49": "4a4xy", + "col50": "7laqo", + "col51": "ei7m9", + "col52": "0h5nl", + "col53": "5lnyq", + "col54": "jjx4j", + "col55": "hjw6x", + "col56": "94zfh", + "col57": "wtfs8", + "col58": "ydfp5", + "col59": "00t4a", + "col60": "fyid4", + "col61": "xjd27", + "col62": "h4we7", + "col63": "80rn7", + "col64": "r2fqj", + "col65": "nrx8k", + "col66": "scxcw", + "col67": "i8cz4", + "col68": "z6e2t", + "col69": "am4xz", + "col70": "6eu9l", + "col71": "g05le", + "col72": "7toik", + "col73": "urd7b", + "col74": "4e1ab", + "col75": "txy6w", + "col76": "uumbn", + "col77": "e5bs8", + "col78": "qyc4b", + "col79": "srhje", + "col80": "ltd7i", + "col81": "g167l", + "col82": "u2sxi", + "col83": "ec9bj", + "col84": "bx4xd", + "col85": "n3jb7", + "col86": "iacgk", + "col87": "g28z7", + "col88": "q3uv3", + "col89": "08v65", + "col90": "cjoqz", + "col91": "aq084", + "col92": "kz27s", + "col93": "cu431", + "col94": "zaiwd", + "col95": "1eze6", + "col96": "yrvc5", + "col97": "kskvq", + "col98": "qn6nu", + "col99": "1atza", + "col100": "6kgw1", + "col101": "7jzjn", + "col102": "0nnp5", + "col103": "e4ldz", + "col104": "eo5kw", + "col105": "9o61q", + "col106": "hkari", + "col107": "3oles", + "col108": "5u17f", + "col109": "fv8rm", + "col110": "1gdsf", + "col111": "138yt", + "col112": "ahyj5", + "col113": "ahnjt", + "col114": "widri", + "col115": "yohem", + "col116": "pyto3", + "col117": "1u2hw", + "col118": "kec2a", + "col119": "5eh96", + "col120": "cf5yb", + "col121": "nf9bw", + "col122": "0n7kc", + "col123": "8pecw", + "col124": "3whn4", + "col125": "utnm5", + "col126": "84vr0", + "col127": "havwl", + "col128": "5sukk", + "col129": "az1a1", + "col130": "lr80j", + "col131": "9igkc", + "col132": "8oz9j", + "col133": "z19sq", + "col134": "k9y5o", + "col135": "arqep", + "col136": "bgmtd", + "col137": "f8qu6", + "col138": "d41xa", + "col139": "wlibk", + "col140": "wcczk", + "col141": "6qh8e", + "col142": "hp1nw", + "col143": "2et0i", + "col144": "yq82x", + "col145": "3ecm4", + "col146": "xme73", + "col147": "hbidd", + "col148": "u6s02", + "col149": "ladmx", + "col150": "i8mww", + "col151": "w8pft", + "col152": "jely5", + "col153": "hblt9", + "col154": "fbgwm", + "col155": "oeyjh", + "col156": "iyg3i", + "col157": "pqyuf", + "col158": "0yxop", + "col159": "j6boe", + "col160": "hbz75", + "col161": "50wvi", + "col162": "qtp77", + "col163": "ce0yp", + "col164": "ppz2m", + "col165": "tqa50", + "col166": "robye", + "col167": "p1kj0", + "col168": "0jg0m", + "col169": "ddopy", + "col170": "ku6fq", + "col171": "0plg0", + "col172": "zerpp", + "col173": "yn15h", + "col174": "lk13g", + "col175": "6svad", + "col176": "v7gtd", + "col177": "q7lpp", + "col178": "tl3q0", + "col179": "a0r0n", + "col180": "2oxey", + "col181": "r8wno", + "col182": "04pzn", + "col183": "d15es", + "col184": "aex7p", + "col185": "ij3xq", + "col186": "noh6q", + "col187": "7fdia", + "col188": "1mux0", + "col189": "p4hwn", + "col190": "xu0hg", + "col191": "2dwtl", + "col192": "mwt27", + "col193": "2r0f0", + "col194": "cblz8", + "col195": "f1ayk", + "col196": "lp8pd", + "col197": "ox3ar", + "col198": "bs1u9", + "col199": "ptkzt", + "col200": "6zvm6", + "col201": "atlmp", + "col202": "7rr0n", + "col203": "6pwnx", + "col204": "0832k", + "col205": "6nj2i", + "col206": "1oay9", + "col207": "462eu", + "col208": "3myyx", + "col209": "rycyn", + "col210": "pubup", + "col211": "mwekq", + "col212": "63pxx", + "col213": "cp5kz", + "col214": "y79ve", + "col215": "26unz", + "col216": "b3hpf", + "col217": "5c3aa", + "col218": "vteeg", + "col219": "p63ux", + "col220": "3ugta", + "col221": "tlysg", + "col222": "pzmvx", + "col223": "vw0v3", + "col224": "dv2h5", + "col225": "mn565", + "col226": "g4agt", + "col227": "8sztq", + "col228": "rjgv2", + "col229": "fifra", + "col230": "u0dhs", + "col231": "q5dla", + "col232": "gvvby", + "col233": "j7yap", + "col234": "qw84f", + "col235": "q40r2", + "col236": "hgdfe", + "col237": "5tv5k", + "col238": "gfcxb", + "col239": "z61p1", + "col240": "gynzp", + "col241": "ujc1b", + "col242": "znd02", + "col243": "cbit5", + "col244": "fwplw", + "col245": "0yfwz", + "col246": "se8oz", + "col247": "cxsct", + "col248": "yvizm", + "col249": "jvoyj", + "col250": "phxfz", + "col251": "m0puq", + "col252": "g1ark", + "col253": "4y1ar", + "col254": "6uqe3", + "col255": "34t8j", + "col256": "6of5b", + "col257": "oovwh", + "col258": "uibcb", + "col259": "7aq7w", + "col260": "zqvc2", + "col261": "02j5u", + "col262": "r9c6n", + "col263": "brblm", + "col264": "cklw3", + "col265": "xmkil", + "col266": "zpgy8", + "col267": "eqm8j", + "col268": "b9h9m", + "col269": "sr6h0", + "col270": "3cjja", + "col271": "vy15u", + "col272": "5tnoo", + "col273": "24lpq", + "col274": "aw4kv", + "col275": "xqro7", + "col276": "ar04r", + "col277": "bco8o", + "col278": "do28p", + "col279": "z42u7", + "col280": "4i2yk", + "col281": "tcj6v", + "col282": "8n6eb", + "col283": "r50gv", + "col284": "bwf5u", + "col285": "ubw1r", + "col286": "z24oy", + "col287": "0u1f2", + "col288": "gfka7", + "col289": "2p5gf", + "col290": "kjjfh", + "col291": "cj0rf", + "col292": "f0xs0", + "col293": "1093y", + "col294": "835bz", + "col295": "83vxz", + "col296": "vigsh", + "col297": "92w8z", + "col298": "bp7dp", + "col299": "clurt", + "col300": "xwpe4", + "col301": "qzxzb", + "col302": "wqld6", + "col303": "8u2gj", + "col304": "frwic", + "col305": "bccfn", + "col306": "tg3n7", + "col307": "tvks9", + "col308": "it43r", + "col309": "elf2l", + "col310": "h8cf0", + "col311": "7vj0m", + "col312": "cogok", + "col313": "oy0n5", + "col314": "80i4o", + "col315": "99h1r", + "col316": "m9vwd", + "col317": "rhsg8", + "col318": "sfbmj", + "col319": "urnnp", + "col320": "965f4", + "col321": "6oqck", + "col322": "6z663", + "col323": "wlovv", + "col324": "aglzk", + "col325": "5nr6j", + "col326": "8u9av", + "col327": "e0lf3", + "col328": "ssrzd", + "col329": "hmwy5", + "col330": "r2xlg", + "col331": "wxdoa", + "col332": "gpxna", + "col333": "sslnd", + "col334": "rnmlz", + "col335": "de1tt", + "col336": "0lsfg", + "col337": "gm15r", + "col338": "3xgrm", + "col339": "k05zg", + "col340": "8zgck", + "col341": "3ygke", + "col342": "naf6v", + "col343": "h673t", + "col344": "w72x1", + "col345": "redsw", + "col346": "z80vx", + "col347": "ptpi7", + "col348": "a5ndj", + "col349": "rxcgy", + "col350": "epy8n", + "col351": "qy0j7", + "col352": "9t6gx", + "col353": "c1jcx", + "col354": "d6dx7", + "col355": "s5c3d", + "col356": "pd36d", + "col357": "o04ow", + "col358": "1l6nr", + "col359": "fga15", + "col360": "dos7a", + "col361": "6ms9y", + "col362": "pvwy9", + "col363": "aeiqi", + "col364": "ha8za", + "col365": "5ulqc", + "col366": "9c7t0", + "col367": "8r5tc", + "col368": "4p0ci", + "col369": "ys66n", + "col370": "n96tx", + "col371": "qc6vr", + "col372": "w13k7", + "col373": "z4mcd", + "col374": "g3amx", + "col375": "9dv00", + "col376": "lr67q", + "col377": "7fg3w", + "col378": "pbp39", + "col379": "h5lza", + "col380": "r5tnu", + "col381": "js5ap", + "col382": "e25lb", + "col383": "ubdaj", + "col384": "43ill", + "col385": "2q7c4", + "col386": "p0vk9", + "col387": "x8v34", + "col388": "03n91", + "col389": "q33lz", + "col390": "7usgf", + "col391": "r7j6f", + "col392": "ixoss", + "col393": "a47d8", + "col394": "5q7tt", + "col395": "oe6pf", + "col396": "7eba8", + "col397": "hd8di", + "col398": "m43a3", + "col399": "1cay3", + "col400": "2zxfv", + "col401": "zsw2w", + "col402": "m8os2", + "col403": "io6tx", + "col404": "zljdr", + "col405": "341rc", + "col406": "6oe49", + "col407": "9mneo", + "col408": "lvy00", + "col409": "w51vf", + "col410": "7uqsg", + "col411": "trkbl", + "col412": "tngj3", + "col413": "9yq50", + "col414": "humjh", + "col415": "iekhy", + "col416": "q3zml", + "col417": "v0fiq", + "col418": "18ucq", + "col419": "ry144", + "col420": "yjbce", + "col421": "ruiq1", + "col422": "ilt0c", + "col423": "zp59i", + "col424": "1h3yn", + "col425": "s1rlo", + "col426": "2rvym", + "col427": "sfkpw", + "col428": "cvhy3", + "col429": "hhvdk", + "col430": "ljp8g", + "col431": "i1hxc", + "col432": "l9mn6", + "col433": "yfu5d", + "col434": "2ex34", + "col435": "shnky", + "col436": "btm92", + "col437": "edmqg", + "col438": "kg2xx", + "col439": "uq27s", + "col440": "4bwkz", + "col441": "ftsl5", + "col442": "p5lcr", + "col443": "8ubqg", + "col444": "xn27e", + "col445": "54ycb", + "col446": "6z9cb", + "col447": "cv8ev", + "col448": "u1lf5", + "col449": "79u4f", + "col450": "sgwpn", + "col451": "hpjoi", + "col452": "9x7di", + "col453": "2mzo2", + "col454": "4mfcr", + "col455": "94i7o", + "col456": "zaia9", + "col457": "0dod3", + "col458": "ntpbw", + "col459": "aw644", + "col460": "3sklu", + "col461": "vi6nr", + "col462": "8u8mo", + "col463": "xrpul", + "col464": "t07ob", + "col465": "hb02d", + "col466": "xc3ip", + "col467": "0o5zu", + "col468": "f8m7u", + "col469": "jd9uo", + "col470": "1h01r", + "col471": "4af57", + "col472": "dctp3", + "col473": "ort74", + "col474": "kzzn0", + "col475": "7z8bm", + "col476": "r63cz", + "col477": "l9yqp", + "col478": "rmk3q", + "col479": "1qd0d", + "col480": "sd5wi", + "col481": "tk070", + "col482": "yjtn0", + "col483": "8sx88", + "col484": "7l4v9", + "col485": "chf0i", + "col486": "2wsdj", + "col487": "gvu5i", + "col488": "hrelk", + "col489": "lrewi", + "col490": "jpik1", + "col491": "ekbqg", + "col492": "vdgeg", + "col493": "1e1ey", + "col494": "dzj9l", + "col495": "3qti1", + "col496": "81a40", + "col497": "3u9eh", + "col498": "1h3df", + "col499": "e5bw3", + "col500": "b8jm4", + "col501": "n6g4a", + "col502": "2kqa4", + "col503": "5zjzk", + "col504": "775ih", + "col505": "h42t1", + "col506": "62q3p", + "col507": "n8lvo", + "col508": "zbh0s", + "col509": "d3rlr", + "col510": "0nec1", + "col511": "z2mpt", + "col512": "92eqf", + "col513": "dr1nc", + "col514": "h7xj5", + "col515": "srwg7", + "col516": "gegdp", + "col517": "lvefg", + "col518": "fvoct", + "col519": "e4qup", + "col520": "tq668", + "col521": "crkpm", + "col522": "2vgd2", + "col523": "2h76a", + "col524": "12s8g", + "col525": "0xpa6", + "col526": "wxxf8", + "col527": "44h5e", + "col528": "geep0", + "col529": "8c54f", + "col530": "u49xo", + "col531": "ql2v3", + "col532": "heg89", + "col533": "f7r2v", + "col534": "1tuk5", + "col535": "p0vyv", + "col536": "rz61d", + "col537": "duxxa", + "col538": "9vh82", + "col539": "y6ct0", + "col540": "7o5ct", + "col541": "uruti", + "col542": "vre3t", + "col543": "tu50w", + "col544": "lrd5w", + "col545": "xzc2x", + "col546": "u1tq7", + "col547": "iy9t4", + "col548": "5lsh8", + "col549": "2w6kh", + "col550": "of5c3", + "col551": "pflxb", + "col552": "0vn58", + "col553": "orebq", + "col554": "k7yxm", + "col555": "pjzlu", + "col556": "h0dy1", + "col557": "2ruwa", + "col558": "udeju", + "col559": "pymn5", + "col560": "e57u3", + "col561": "hahab", + "col562": "mq26w", + "col563": "1k038", + "col564": "mbqd4", + "col565": "9fhce", + "col566": "05b63", + "col567": "w3nc0", + "col568": "bml2i", + "col569": "0ykcu", + "col570": "kg561", + "col571": "vzz62", + "col572": "ge8hj", + "col573": "mv4ho", + "col574": "6jrw7", + "col575": "wacsx", + "col576": "w6h30", + "col577": "5xqh8", + "col578": "lbu1z", + "col579": "qqgmf", + "col580": "lqn9k", + "col581": "lpznx", + "col582": "26ifd", + "col583": "jhj1x", + "col584": "dhu0u", + "col585": "sgoit", + "col586": "c0etb", + "col587": "oqp9z", + "col588": "zdu6c", + "col589": "42w9h", + "col590": "gz19a", + "col591": "gnsql", + "col592": "msea3", + "col593": "kenr8", + "col594": "fatde", + "col595": "ai5s5", + "col596": "zasog", + "col597": "wf8eq", + "col598": "olaii", + "col599": "3axkp", + "col600": "rar80", + "col601": "acpiq", + "col602": "p714d", + "col603": "6ne08", + "col604": "xtu4v", + "col605": "9vlc8", + "col606": "pgmiq", + "col607": "fnf54", + "col608": "2x4vr", + "col609": "xi1xj", + "col610": "jyh9c", + "col611": "n0dmm", + "col612": "lyed7", + "col613": "pk3u9", + "col614": "d8zwr", + "col615": "mdobt", + "col616": "gur0o", + "col617": "w28a1", + "col618": "05p8c", + "col619": "4q942", + "col620": "6py98", + "col621": "ogyh6", + "col622": "juoee", + "col623": "w8rxp", + "col624": "md74c", + "col625": "kp5sp", + "col626": "751qa", + "col627": "68oiv", + "col628": "7r7y4", + "col629": "rfznu", + "col630": "simhm", + "col631": "7ilci", + "col632": "6kqir", + "col633": "5tad4", + "col634": "pcumj", + "col635": "wxdug", + "col636": "kdzfk", + "col637": "avt3v", + "col638": "w9rqd", + "col639": "mrlrs", + "col640": "6pewi", + "col641": "kiqjw", + "col642": "o2adt", + "col643": "guol2", + "col644": "xeejs", + "col645": "2vi3j", + "col646": "cdpad", + "col647": "u1mez", + "col648": "zm02e", + "col649": "ykcmz", + "col650": "bxy0c", + "col651": "8a4wt", + "col652": "5ia1c", + "col653": "us41e", + "col654": "1q0d8", + "col655": "njqqk", + "col656": "7cczf", + "col657": "qdvno", + "col658": "ea98j", + "col659": "f4i13", + "col660": "89v0o", + "col661": "mewh6", + "col662": "2cjnd", + "col663": "inlqb", + "col664": "q3an4", + "col665": "qcki5", + "col666": "f2dge", + "col667": "7kl2d", + "col668": "io0jx", + "col669": "pps6v", + "col670": "84cyr", + "col671": "wuyp4", + "col672": "9yy3m", + "col673": "3ldxn", + "col674": "8ireb", + "col675": "v4iu9", + "col676": "16yxz", + "col677": "aee1c", + "col678": "jnzso", + "col679": "uhvj0", + "col680": "b3tmo", + "col681": "jsjlu", + "col682": "og5bi", + "col683": "4kqoe", + "col684": "8ftd0", + "col685": "6rqsr", + "col686": "5fv2r", + "col687": "3sxd0", + "col688": "77kpz", + "col689": "69vv4", + "col690": "n4odl", + "col691": "acmj8", + "col692": "3yhku", + "col693": "q6hws", + "col694": "ibbn0", + "col695": "x8knt", + "col696": "k4y16", + "col697": "45mjm", + "col698": "gi3lf", + "col699": "2hdap", + "col700": "zrgw7", + "col701": "gvldk", + "col702": "zevnr", + "col703": "we54l", + "col704": "uzfzh", + "col705": "f5h73", + "col706": "atak7", + "col707": "8hzyu", + "col708": "k3syz", + "col709": "3mdqv", + "col710": "0u223", + "col711": "q3mrg", + "col712": "jjrnx", + "col713": "dbp97", + "col714": "wvr77", + "col715": "wuq0i", + "col716": "2s3ld", + "col717": "3pp2b", + "col718": "isvtg", + "col719": "hfl8r", + "col720": "0sl74", + "col721": "tr0yz", + "col722": "domt8", + "col723": "me41r", + "col724": "3dc1f", + "col725": "s5dp5", + "col726": "hlyt1", + "col727": "dylkh", + "col728": "kf6nb", + "col729": "ltf2q", + "col730": "7tgh9", + "col731": "bj5sv", + "col732": "89cb7", + "col733": "pujwa", + "col734": "hbaz3", + "col735": "s4679", + "col736": "v8llh", + "col737": "krvnd", + "col738": "6qjrb", + "col739": "r0kva", + "col740": "xfz1a", + "col741": "rmmu3", + "col742": "obz5j", + "col743": "b6a37", + "col744": "spg3e", + "col745": "k0buw", + "col746": "44awc", + "col747": "7vaag", + "col748": "rjx5b", + "col749": "f25hd", + "col750": "s2se3", + "col751": "ehd59", + "col752": "glucw", + "col753": "hxlal", + "col754": "nxy7h", + "col755": "tt2h3", + "col756": "p2npo", + "col757": "i81z2", + "col758": "6r4mv", + "col759": "dh0du", + "col760": "0yzua", + "col761": "4ui3j", + "col762": "xilqb", + "col763": "qyqwv", + "col764": "8voic", + "col765": "cmprg", + "col766": "gtcsd", + "col767": "kqvqh", + "col768": "4txo6", + "col769": "7gpnj", + "col770": "mjn0q", + "col771": "f32d9", + "col772": "cvu08", + "col773": "gyott", + "col774": "ifpvy", + "col775": "g4edm", + "col776": "jb6ho", + "col777": "zak70", + "col778": "xc0kh", + "col779": "cfxpe", + "col780": "t6rqb", + "col781": "kyef8", + "col782": "gmosd", + "col783": "ec61t", + "col784": "z01g5", + "col785": "rfw5d", + "col786": "9dl5q", + "col787": "2ff57", + "col788": "jkrbm", + "col789": "jnvzp", + "col790": "agx3n", + "col791": "07ybq", + "col792": "gyrag", + "col793": "bj0bb", + "col794": "xhms9", + "col795": "a03lm", + "col796": "2f8w1", + "col797": "ywhbo", + "col798": "etvoq", + "col799": "7vjrj", + "col800": "1z1yl", + "col801": "3wecn", + "col802": "gechj", + "col803": "as9ph", + "col804": "jcy0j", + "col805": "170re", + "col806": "oomtn", + "col807": "8zx6e", + "col808": "47czu", + "col809": "k5y3h", + "col810": "901u2", + "col811": "344mr", + "col812": "ye6jp", + "col813": "kp4f3", + "col814": "5h3vs", + "col815": "zl6vn", + "col816": "jp490", + "col817": "rs1k4", + "col818": "3u4vk", + "col819": "yofsd", + "col820": "cyd5l", + "col821": "m5hkz", + "col822": "b7vka", + "col823": "fnqao", + "col824": "80vr0", + "col825": "7cp74", + "col826": "rr39c", + "col827": "f24v7", + "col828": "qhpvi", + "col829": "r9pro", + "col830": "1d908", + "col831": "zt3ko", + "col832": "o79yl", + "col833": "d1dzm", + "col834": "h13eh", + "col835": "qlo8d", + "col836": "3fe4d", + "col837": "ftmdm", + "col838": "36ot0", + "col839": "3b05t", + "col840": "0dykq", + "col841": "6ez1j", + "col842": "otwvd", + "col843": "iza51", + "col844": "h35fv", + "col845": "zpd2l", + "col846": "oet7d", + "col847": "iujhh", + "col848": "zuwux", + "col849": "mfd6e", + "col850": "mea0m", + "col851": "u17v3", + "col852": "xknz4", + "col853": "fgwdh", + "col854": "otv8t", + "col855": "o0l3n", + "col856": "r7nbn", + "col857": "u3mjg", + "col858": "m3he9", + "col859": "ilbw1", + "col860": "1nuov", + "col861": "v50lr", + "col862": "t7bf5", + "col863": "6ob29", + "col864": "07eg6", + "col865": "1wr2l", + "col866": "cuikw", + "col867": "26jmd", + "col868": "r1sp9", + "col869": "wgw32", + "col870": "yy1bm", + "col871": "1lj1a", + "col872": "0quyy", + "col873": "8j4et", + "col874": "fycdr", + "col875": "a1ltu", + "col876": "gy0ae", + "col877": "su4hz", + "col878": "ojiab", + "col879": "izmj4", + "col880": "2mo0y", + "col881": "6h11e", + "col882": "egr1y", + "col883": "2gzvo", + "col884": "9f81a", + "col885": "84c0o", + "col886": "pt4mu", + "col887": "uhltm", + "col888": "lb63g", + "col889": "vcvxl", + "col890": "g3q65", + "col891": "i6h65", + "col892": "0rntc", + "col893": "64308", + "col894": "eqepq", + "col895": "s795q", + "col896": "jx7fx", + "col897": "phag3", + "col898": "tucwa", + "col899": "6hzff", + "col900": "38mfq", + "col901": "uttsm", + "col902": "ad682", + "col903": "z5q4h", + "col904": "8phfg", + "col905": "7mx8s", + "col906": "cgx1g", + "col907": "cdmu6", + "col908": "njsz2", + "col909": "mv1lf", + "col910": "59dwr", + "col911": "9i5fm", + "col912": "dgd71", + "col913": "5egkn", + "col914": "s1s1a", + "col915": "dwmu9", + "col916": "6mff1", + "col917": "buqz5", + "col918": "1x22d", + "col919": "98tgs", + "col920": "e766s", + "col921": "pymgb", + "col922": "h5u6f", + "col923": "oqfa6", + "col924": "tdwqg", + "col925": "bz6w0", + "col926": "op847", + "col927": "wnwll", + "col928": "3jnk7", + "col929": "5kmdv", + "col930": "zxwj7", + "col931": "ljlc7", + "col932": "9v56f", + "col933": "9ogat", + "col934": "2pn2f", + "col935": "cl0nm", + "col936": "0sthq", + "col937": "4ulkc", + "col938": "1m9tw", + "col939": "18ksj", + "col940": "cbc62", + "col941": "klha1", + "col942": "yff0l", + "col943": "2f0qy", + "col944": "lqc52", + "col945": "2hmww", + "col946": "iovov", + "col947": "n1td3", + "col948": "8e03v", + "col949": "3ij31", + "col950": "05cjp", + "col951": "w3blj", + "col952": "01jwc", + "col953": "uv848", + "col954": "fka0o", + "col955": "f0vok", + "col956": "paze5", + "col957": "pg3xn", + "col958": "ii2g7", + "col959": "xd4w0", + "col960": "ggbax", + "col961": "27w21", + "col962": "y592q", + "col963": "4dcgs", + "col964": "124oa", + "col965": "p7chz", + "col966": "lj3jb", + "col967": "0eegh", + "col968": "nupxw", + "col969": "itgsd", + "col970": "06g57", + "col971": "zvtjg", + "col972": "ihdc0", + "col973": "6g345", + "col974": "a3hnt", + "col975": "kyqjg", + "col976": "m0t98", + "col977": "80npm", + "col978": "z6oxv", + "col979": "1s7s3", + "col980": "ek7zi", + "col981": "zn4q5", + "col982": "0fkbm", + "col983": "nxmts", + "col984": "uwqov", + "col985": "anjik", + "col986": "svlgp", + "col987": "m4g1j", + "col988": "3l4tm", + "col989": "4h5cu", + "col990": "tc1gg", + "col991": "epo6i", + "col992": "na72g", + "col993": "57jfi", + "col994": "73n4x", + "col995": "mnw24", + "col996": "s4wd7", + "col997": "ko5is", + "col998": "oa5vq", + "col999": "dddi3" + }, + { + "name": "Bishop Mcmillan", + "gender": "male", + "col0": "sf7l0", + "col1": "03gom", + "col2": "3w67j", + "col3": "luvgj", + "col4": "si7xu", + "col5": "aaria", + "col6": "swe59", + "col7": "ch134", + "col8": "o3k0k", + "col9": "90ojr", + "col10": "tvxag", + "col11": "5e6by", + "col12": "tg1fx", + "col13": "e12vr", + "col14": "5vro1", + "col15": "zk363", + "col16": "f9nsr", + "col17": "ikzik", + "col18": "wkl0t", + "col19": "44u0r", + "col20": "egqhn", + "col21": "5753w", + "col22": "prw7c", + "col23": "8fn03", + "col24": "58zar", + "col25": "j33zh", + "col26": "4w94s", + "col27": "vx1k5", + "col28": "sg4u5", + "col29": "y4py7", + "col30": "07106", + "col31": "ttw2m", + "col32": "qgwmv", + "col33": "dc2xe", + "col34": "ejndx", + "col35": "etsxv", + "col36": "8ycgb", + "col37": "xyy0d", + "col38": "4uvia", + "col39": "ex8yw", + "col40": "rbe7d", + "col41": "vqmoz", + "col42": "eyytu", + "col43": "y1rh2", + "col44": "wwfrt", + "col45": "3zip8", + "col46": "1vogp", + "col47": "6ujnj", + "col48": "oyi8z", + "col49": "rww58", + "col50": "gj25o", + "col51": "hw9fh", + "col52": "1woef", + "col53": "nnyut", + "col54": "lezdr", + "col55": "f70ar", + "col56": "43pe4", + "col57": "lvbrx", + "col58": "dbfz8", + "col59": "b1f6r", + "col60": "jffch", + "col61": "9dxej", + "col62": "awrpf", + "col63": "9iox6", + "col64": "d3phe", + "col65": "msngg", + "col66": "vv97k", + "col67": "zxrl3", + "col68": "0hyl4", + "col69": "olzw1", + "col70": "dbo9u", + "col71": "j8hu7", + "col72": "bffes", + "col73": "hb0vh", + "col74": "p23a5", + "col75": "bn9n4", + "col76": "nsyj6", + "col77": "xme5y", + "col78": "fhb3w", + "col79": "jmtae", + "col80": "9sz8d", + "col81": "2khv0", + "col82": "zuex0", + "col83": "ajtmu", + "col84": "hol5q", + "col85": "15mau", + "col86": "pnl4e", + "col87": "f3iet", + "col88": "b1v97", + "col89": "dug6p", + "col90": "irc3f", + "col91": "fwku6", + "col92": "r2m4f", + "col93": "kuyem", + "col94": "xhjes", + "col95": "fzb59", + "col96": "2c6f0", + "col97": "ip1ba", + "col98": "yorqr", + "col99": "in4r8", + "col100": "v5cfe", + "col101": "4i4zq", + "col102": "7apvp", + "col103": "51ilj", + "col104": "15npf", + "col105": "67gnz", + "col106": "t8rpu", + "col107": "p0onx", + "col108": "ot5xk", + "col109": "crvlb", + "col110": "pmupm", + "col111": "7t6zq", + "col112": "g2jds", + "col113": "1a2l7", + "col114": "anr2t", + "col115": "73tjd", + "col116": "915qn", + "col117": "lky7r", + "col118": "dgvf8", + "col119": "uaoux", + "col120": "mnhp7", + "col121": "oraoa", + "col122": "agnp5", + "col123": "l1clv", + "col124": "k43l8", + "col125": "g6xfw", + "col126": "b3w02", + "col127": "mgrex", + "col128": "t423g", + "col129": "rhu37", + "col130": "dje4m", + "col131": "fquxo", + "col132": "4qdy9", + "col133": "bu9mh", + "col134": "xfj1u", + "col135": "xmhyu", + "col136": "ber6g", + "col137": "41dfd", + "col138": "0x0p5", + "col139": "1fjsu", + "col140": "9ujap", + "col141": "vykel", + "col142": "87wsj", + "col143": "qbnvx", + "col144": "gcm3j", + "col145": "8mnd9", + "col146": "ejc00", + "col147": "mvgsp", + "col148": "p56af", + "col149": "3gxm1", + "col150": "raq8r", + "col151": "islm2", + "col152": "rhdqx", + "col153": "z69cr", + "col154": "9ws72", + "col155": "7p6fr", + "col156": "dhrf0", + "col157": "roo6e", + "col158": "q7oz4", + "col159": "wr5l8", + "col160": "t9wd0", + "col161": "dif5l", + "col162": "xez7a", + "col163": "f2ork", + "col164": "xo7pc", + "col165": "d25j4", + "col166": "xkojn", + "col167": "fr75s", + "col168": "yg8ur", + "col169": "gm1mc", + "col170": "3bwkh", + "col171": "qc0lr", + "col172": "28yl3", + "col173": "5fyx3", + "col174": "6oxub", + "col175": "3byye", + "col176": "9aahz", + "col177": "lgenn", + "col178": "qfyg1", + "col179": "mad71", + "col180": "xqenu", + "col181": "naerw", + "col182": "qcbj0", + "col183": "edob6", + "col184": "r07cf", + "col185": "cb8tb", + "col186": "6xmp3", + "col187": "uoprf", + "col188": "h22p9", + "col189": "jd93s", + "col190": "4hm2z", + "col191": "7kxzt", + "col192": "0gz9i", + "col193": "dswyb", + "col194": "ovehc", + "col195": "uetln", + "col196": "osn0h", + "col197": "5aswk", + "col198": "in3j0", + "col199": "cx16t", + "col200": "j4ceu", + "col201": "4tl3e", + "col202": "8uc58", + "col203": "9jcc4", + "col204": "77zqg", + "col205": "xn84e", + "col206": "s1jzs", + "col207": "zaj0f", + "col208": "i7bgy", + "col209": "9457y", + "col210": "pupot", + "col211": "asp2z", + "col212": "0v2xa", + "col213": "7ju3v", + "col214": "5tmfz", + "col215": "r69sb", + "col216": "fk72x", + "col217": "7c2c5", + "col218": "wnbwu", + "col219": "x944u", + "col220": "9nrv8", + "col221": "hwzqe", + "col222": "yu5zx", + "col223": "1rh0j", + "col224": "ghiai", + "col225": "74azg", + "col226": "m56lp", + "col227": "81m0b", + "col228": "9nccc", + "col229": "xnvt9", + "col230": "8cyyk", + "col231": "hur8h", + "col232": "q99pv", + "col233": "00ab7", + "col234": "h9k8s", + "col235": "f0fjr", + "col236": "3duhh", + "col237": "t6jog", + "col238": "g0j3l", + "col239": "ghqtf", + "col240": "azzy8", + "col241": "51y11", + "col242": "zhlhn", + "col243": "ruyl8", + "col244": "l6wbs", + "col245": "2ewkk", + "col246": "8vf1g", + "col247": "tbzcu", + "col248": "0vr4z", + "col249": "j3dt7", + "col250": "l5e7d", + "col251": "d6lkw", + "col252": "9ndny", + "col253": "e5hm6", + "col254": "eadni", + "col255": "xfhpk", + "col256": "e8emr", + "col257": "hy2ld", + "col258": "4nkz2", + "col259": "w4gf6", + "col260": "f0fwx", + "col261": "rlqmf", + "col262": "zhye7", + "col263": "4pl74", + "col264": "ws7bh", + "col265": "f9whf", + "col266": "wrqxc", + "col267": "6qeeh", + "col268": "w3isv", + "col269": "4akxj", + "col270": "48g0c", + "col271": "pwm9e", + "col272": "3k7jl", + "col273": "bsqoh", + "col274": "abfz8", + "col275": "d1slf", + "col276": "qdtnn", + "col277": "auux5", + "col278": "hmgra", + "col279": "c8cku", + "col280": "yw8c1", + "col281": "xl2e6", + "col282": "6lk74", + "col283": "il6ue", + "col284": "qokkw", + "col285": "gtbjf", + "col286": "kihbr", + "col287": "zdg3t", + "col288": "up1du", + "col289": "32xw8", + "col290": "95x0w", + "col291": "z2bbn", + "col292": "893sg", + "col293": "z0iky", + "col294": "encpl", + "col295": "fvijz", + "col296": "nw5fj", + "col297": "nc2dp", + "col298": "rutxj", + "col299": "dnfhg", + "col300": "e1fho", + "col301": "c6ygw", + "col302": "ka0rm", + "col303": "thudl", + "col304": "d68ik", + "col305": "9nobl", + "col306": "fozrh", + "col307": "h20cb", + "col308": "8izhh", + "col309": "duaj3", + "col310": "x7icy", + "col311": "odv9u", + "col312": "4cftd", + "col313": "pjr4w", + "col314": "slqko", + "col315": "31rlh", + "col316": "jyodi", + "col317": "1vjvg", + "col318": "eoi5b", + "col319": "zemqf", + "col320": "1rf0i", + "col321": "6lt3a", + "col322": "stu6l", + "col323": "mmh6b", + "col324": "gff60", + "col325": "geb4y", + "col326": "hnmha", + "col327": "scvcn", + "col328": "evte0", + "col329": "2oo9n", + "col330": "b4s7n", + "col331": "scrvx", + "col332": "lgnl8", + "col333": "j4am4", + "col334": "i3z7r", + "col335": "pc1ca", + "col336": "nbkai", + "col337": "yc4c8", + "col338": "8umrg", + "col339": "wq680", + "col340": "t26ja", + "col341": "a9rrs", + "col342": "imfmh", + "col343": "uigvr", + "col344": "lfpc3", + "col345": "igjz0", + "col346": "zf6dg", + "col347": "nh1c2", + "col348": "72jy2", + "col349": "kpawl", + "col350": "xrgho", + "col351": "zs9it", + "col352": "5560a", + "col353": "xg27t", + "col354": "zpvn7", + "col355": "pek4b", + "col356": "fet9s", + "col357": "fz5tx", + "col358": "eyjtn", + "col359": "dx38i", + "col360": "ww8lj", + "col361": "5zvtn", + "col362": "oq6a8", + "col363": "yrl99", + "col364": "d78dt", + "col365": "qkqj0", + "col366": "m1joe", + "col367": "nhfes", + "col368": "e2195", + "col369": "s2doj", + "col370": "6v4a3", + "col371": "wuc9e", + "col372": "cewma", + "col373": "v633q", + "col374": "qpho6", + "col375": "1i9d2", + "col376": "44fhj", + "col377": "3hdsx", + "col378": "kdmob", + "col379": "kfhxi", + "col380": "6pv9z", + "col381": "tps8v", + "col382": "2hq59", + "col383": "rksh7", + "col384": "s8it2", + "col385": "kf7tt", + "col386": "xbrd0", + "col387": "obcyo", + "col388": "c6hdo", + "col389": "e5xyk", + "col390": "tuykh", + "col391": "8y19w", + "col392": "oxsdl", + "col393": "72foi", + "col394": "udksy", + "col395": "fdsz5", + "col396": "w0xv0", + "col397": "0bhxw", + "col398": "yru98", + "col399": "qdj2s", + "col400": "vajvs", + "col401": "slmep", + "col402": "6dzop", + "col403": "1bojv", + "col404": "bfzvu", + "col405": "mxkjp", + "col406": "y8fs3", + "col407": "xt8zz", + "col408": "gzitu", + "col409": "ysqkr", + "col410": "epuba", + "col411": "fjhl5", + "col412": "zzwzm", + "col413": "515vr", + "col414": "3goqh", + "col415": "6q8ll", + "col416": "27k1t", + "col417": "7avt1", + "col418": "56dr8", + "col419": "utjba", + "col420": "57kmy", + "col421": "rmwu9", + "col422": "ah5wi", + "col423": "cduv0", + "col424": "1yfh7", + "col425": "cyz8k", + "col426": "ms3q2", + "col427": "5aang", + "col428": "j4ysc", + "col429": "eygvo", + "col430": "t31pk", + "col431": "1k38t", + "col432": "zs1ag", + "col433": "eox66", + "col434": "ympm2", + "col435": "f3o3g", + "col436": "ebrrw", + "col437": "vdylt", + "col438": "l7k0m", + "col439": "pp4ib", + "col440": "u26i8", + "col441": "mc8w4", + "col442": "gbiv2", + "col443": "xyerf", + "col444": "gd6ep", + "col445": "nvym1", + "col446": "l2202", + "col447": "rq0hj", + "col448": "1sgv7", + "col449": "zu6x7", + "col450": "baoaf", + "col451": "2b7fx", + "col452": "637cj", + "col453": "n2n7g", + "col454": "kf3yj", + "col455": "z9h63", + "col456": "85nv5", + "col457": "jw72h", + "col458": "imrmi", + "col459": "193vc", + "col460": "yfnry", + "col461": "ehs5k", + "col462": "anrkr", + "col463": "ft3ju", + "col464": "m6op9", + "col465": "mclpi", + "col466": "zqtr1", + "col467": "u8926", + "col468": "4tdix", + "col469": "zhkqf", + "col470": "hr7ng", + "col471": "ehumj", + "col472": "hotw6", + "col473": "s4i0i", + "col474": "6xbqo", + "col475": "024i5", + "col476": "6v7yc", + "col477": "5qcst", + "col478": "vsgk9", + "col479": "ovzz8", + "col480": "00dh9", + "col481": "q1w3n", + "col482": "ngg73", + "col483": "othl2", + "col484": "qflf8", + "col485": "sfmdh", + "col486": "q4rfj", + "col487": "0szk7", + "col488": "jfslf", + "col489": "eqp98", + "col490": "avnrq", + "col491": "zt5g7", + "col492": "ydqpq", + "col493": "9xfsn", + "col494": "epysr", + "col495": "bw0v6", + "col496": "noj8v", + "col497": "uo2ev", + "col498": "yk6ic", + "col499": "s84sf", + "col500": "wlito", + "col501": "dyy3w", + "col502": "1tolw", + "col503": "0g7yw", + "col504": "ne010", + "col505": "9k44u", + "col506": "wphaw", + "col507": "wx69t", + "col508": "sf6i6", + "col509": "vian8", + "col510": "1fatz", + "col511": "ebkia", + "col512": "wor89", + "col513": "pd4xq", + "col514": "vxgvw", + "col515": "qfq5q", + "col516": "7qih6", + "col517": "vpwej", + "col518": "0ml9f", + "col519": "yrabd", + "col520": "sdylm", + "col521": "392l0", + "col522": "0qrde", + "col523": "d8jpz", + "col524": "84f8i", + "col525": "5xe63", + "col526": "klnqk", + "col527": "k07c0", + "col528": "b4fs4", + "col529": "o3zph", + "col530": "5xxd1", + "col531": "qifx0", + "col532": "slfk9", + "col533": "q3eol", + "col534": "n8fax", + "col535": "pxrbe", + "col536": "hjvn7", + "col537": "ngqnb", + "col538": "qi6dy", + "col539": "azp0y", + "col540": "w9f6x", + "col541": "l91pw", + "col542": "hqvvc", + "col543": "j0n0h", + "col544": "b5wmu", + "col545": "amdz3", + "col546": "w8tt0", + "col547": "ix9k5", + "col548": "j8kp1", + "col549": "emqz3", + "col550": "0uw48", + "col551": "l9gll", + "col552": "8stbk", + "col553": "i5ykv", + "col554": "5oc2d", + "col555": "y5l35", + "col556": "b154z", + "col557": "now47", + "col558": "hoy3z", + "col559": "lf9vy", + "col560": "7jp81", + "col561": "fsu2j", + "col562": "jrtwo", + "col563": "9chce", + "col564": "95wgj", + "col565": "gqhk7", + "col566": "k8pwr", + "col567": "0cnho", + "col568": "46hhb", + "col569": "i4tjx", + "col570": "pt4k7", + "col571": "pr3rz", + "col572": "r3uak", + "col573": "7z67r", + "col574": "svfb0", + "col575": "0j1ic", + "col576": "m60bs", + "col577": "z5z5n", + "col578": "tgukt", + "col579": "9ej3y", + "col580": "1quos", + "col581": "jptkb", + "col582": "24sy9", + "col583": "9ngn0", + "col584": "a79ub", + "col585": "q16oo", + "col586": "oxzrc", + "col587": "z6u3e", + "col588": "hbda8", + "col589": "zqklv", + "col590": "bcsqh", + "col591": "bdd74", + "col592": "v48iw", + "col593": "bcio0", + "col594": "60y2t", + "col595": "i8s4e", + "col596": "srdgk", + "col597": "06gz9", + "col598": "rqzh5", + "col599": "wd0li", + "col600": "k5jo4", + "col601": "b5l6y", + "col602": "fa42b", + "col603": "6kg42", + "col604": "o003b", + "col605": "j0ykj", + "col606": "11dzq", + "col607": "pfbc0", + "col608": "17kz8", + "col609": "lxs2w", + "col610": "ral31", + "col611": "x7h5x", + "col612": "x5kzv", + "col613": "akbqj", + "col614": "7h91o", + "col615": "811b1", + "col616": "nerrz", + "col617": "24e1g", + "col618": "0u0xf", + "col619": "zpylr", + "col620": "rzld0", + "col621": "vphoy", + "col622": "dzq9i", + "col623": "s1103", + "col624": "0rbcb", + "col625": "aov94", + "col626": "gitcs", + "col627": "j2rl9", + "col628": "nabky", + "col629": "x5ueh", + "col630": "9cgob", + "col631": "qb8tn", + "col632": "jd395", + "col633": "m7yy5", + "col634": "57bo2", + "col635": "kbcwq", + "col636": "ikux0", + "col637": "jsi6a", + "col638": "reh6l", + "col639": "7fz8j", + "col640": "xda89", + "col641": "bmvmm", + "col642": "stm45", + "col643": "6jznx", + "col644": "qbmv6", + "col645": "kwj97", + "col646": "uvjyn", + "col647": "wypbs", + "col648": "xwjz7", + "col649": "yetk4", + "col650": "8x6u2", + "col651": "i6w1y", + "col652": "m10nj", + "col653": "zmbzb", + "col654": "4jaxz", + "col655": "r9xfm", + "col656": "064yq", + "col657": "t608z", + "col658": "m2btq", + "col659": "m6n9j", + "col660": "tzax7", + "col661": "8eqei", + "col662": "1s6sn", + "col663": "czdyd", + "col664": "px4qq", + "col665": "ez8qg", + "col666": "s33qn", + "col667": "sjxmc", + "col668": "yq6c0", + "col669": "lldzp", + "col670": "pgm3e", + "col671": "0hdqq", + "col672": "q4lau", + "col673": "i79xc", + "col674": "u0gld", + "col675": "dhcxw", + "col676": "0ltnb", + "col677": "pt2mg", + "col678": "8biio", + "col679": "0ekp6", + "col680": "a1bbp", + "col681": "v4yzf", + "col682": "weoez", + "col683": "xr4qi", + "col684": "jxpwa", + "col685": "rm1i8", + "col686": "2f021", + "col687": "hbm86", + "col688": "unoey", + "col689": "mxu4j", + "col690": "v3ksj", + "col691": "ow9lg", + "col692": "3vers", + "col693": "mecyi", + "col694": "5k39o", + "col695": "c57h5", + "col696": "r2im0", + "col697": "i64i9", + "col698": "lkz3b", + "col699": "iiyk2", + "col700": "l025s", + "col701": "stix0", + "col702": "hk8vj", + "col703": "yzg3a", + "col704": "hpvs7", + "col705": "hfpy4", + "col706": "opwad", + "col707": "ve2ez", + "col708": "2alfo", + "col709": "ji9ip", + "col710": "4ueso", + "col711": "egh3w", + "col712": "lexza", + "col713": "02xnk", + "col714": "dwkqr", + "col715": "pnk54", + "col716": "63s5c", + "col717": "xjixt", + "col718": "54f5e", + "col719": "5i1t7", + "col720": "z0kdy", + "col721": "vg3yc", + "col722": "l0a2h", + "col723": "yu5m1", + "col724": "ijs4x", + "col725": "lt18q", + "col726": "u2kow", + "col727": "xm277", + "col728": "lkj95", + "col729": "pj64k", + "col730": "f9brs", + "col731": "k4kk6", + "col732": "b0ijg", + "col733": "f1ol8", + "col734": "w1w4p", + "col735": "1hjiu", + "col736": "49aga", + "col737": "h7oe3", + "col738": "l7cme", + "col739": "td9tr", + "col740": "3r12g", + "col741": "zojm9", + "col742": "a5zq4", + "col743": "ntp0q", + "col744": "jib36", + "col745": "zxx3h", + "col746": "vbdvz", + "col747": "ftwe9", + "col748": "sfmir", + "col749": "5lysi", + "col750": "xwxy8", + "col751": "6inx6", + "col752": "37yxv", + "col753": "b1md2", + "col754": "ljayd", + "col755": "dx8ub", + "col756": "kg1qf", + "col757": "5i2m8", + "col758": "3abye", + "col759": "6c53q", + "col760": "6ssra", + "col761": "jfnlw", + "col762": "zpq27", + "col763": "s91tc", + "col764": "87su7", + "col765": "b3ozr", + "col766": "7sfp4", + "col767": "6ie4q", + "col768": "oi5qz", + "col769": "hkzix", + "col770": "p3jzu", + "col771": "yic2q", + "col772": "d8ty8", + "col773": "t4e4p", + "col774": "30nsu", + "col775": "vhmw4", + "col776": "0ihry", + "col777": "dwyqc", + "col778": "ulqz1", + "col779": "4euh2", + "col780": "6xl7h", + "col781": "pz2q9", + "col782": "41gzu", + "col783": "bmynk", + "col784": "ged0a", + "col785": "sv8h4", + "col786": "5habk", + "col787": "f6p33", + "col788": "6ib3k", + "col789": "heagy", + "col790": "8uddc", + "col791": "kklmv", + "col792": "oo55n", + "col793": "x0wge", + "col794": "6whdp", + "col795": "k8m1i", + "col796": "gwvaf", + "col797": "phsxh", + "col798": "wyrjo", + "col799": "izkyv", + "col800": "av4u9", + "col801": "4k8pp", + "col802": "y6l60", + "col803": "ykdcc", + "col804": "t3z4n", + "col805": "qpwyv", + "col806": "fsr8e", + "col807": "axhbd", + "col808": "54tlm", + "col809": "tzjas", + "col810": "xo9y3", + "col811": "r979s", + "col812": "xrpen", + "col813": "e2bgv", + "col814": "6impz", + "col815": "62yr0", + "col816": "wqjgw", + "col817": "ixf55", + "col818": "wp2tj", + "col819": "x7pjq", + "col820": "tjn7b", + "col821": "1qfym", + "col822": "ujjvn", + "col823": "qae1b", + "col824": "pnkt2", + "col825": "ui225", + "col826": "ikf7h", + "col827": "ruaxg", + "col828": "6px3f", + "col829": "ndx0j", + "col830": "5iikl", + "col831": "iz0im", + "col832": "hoo5z", + "col833": "q38s9", + "col834": "vyro6", + "col835": "sktpy", + "col836": "gzrig", + "col837": "1e4zm", + "col838": "t6ofx", + "col839": "jlzsd", + "col840": "3ywd8", + "col841": "ygise", + "col842": "cd21o", + "col843": "tyu6j", + "col844": "e995b", + "col845": "0obg2", + "col846": "vmvbt", + "col847": "pyahz", + "col848": "7xjg0", + "col849": "8d9hc", + "col850": "6c6as", + "col851": "xb857", + "col852": "8wemj", + "col853": "9vb1v", + "col854": "lzdn6", + "col855": "9qmu6", + "col856": "9ag2e", + "col857": "y1w4n", + "col858": "m1ygy", + "col859": "xrvxe", + "col860": "mk1zl", + "col861": "ep9jl", + "col862": "5npfa", + "col863": "xh4tl", + "col864": "9f94h", + "col865": "oak46", + "col866": "7jbf4", + "col867": "3divq", + "col868": "ahvfe", + "col869": "ufi86", + "col870": "n0ezu", + "col871": "bgln6", + "col872": "m18jo", + "col873": "xnc7o", + "col874": "ad083", + "col875": "k46z7", + "col876": "ow8e9", + "col877": "1ogy9", + "col878": "sgklt", + "col879": "221j2", + "col880": "8b3wy", + "col881": "j2g2v", + "col882": "efjcn", + "col883": "glbxt", + "col884": "6fhmt", + "col885": "9uua4", + "col886": "1ephw", + "col887": "uaarn", + "col888": "v5oc3", + "col889": "axqgp", + "col890": "odm4i", + "col891": "as03g", + "col892": "hj363", + "col893": "3oyt6", + "col894": "qkqtp", + "col895": "5z5ci", + "col896": "e2xca", + "col897": "lxmic", + "col898": "rllvv", + "col899": "fpmn9", + "col900": "983vc", + "col901": "0rjkv", + "col902": "ug2we", + "col903": "2g22z", + "col904": "k5b4k", + "col905": "19n5s", + "col906": "bzjm2", + "col907": "rkpuh", + "col908": "3a3ju", + "col909": "xj2yz", + "col910": "h2o6u", + "col911": "n95bj", + "col912": "8urud", + "col913": "hv2up", + "col914": "jjlyt", + "col915": "ubxmg", + "col916": "3p6vk", + "col917": "ezska", + "col918": "cfpz4", + "col919": "e4rkn", + "col920": "0am0u", + "col921": "xji96", + "col922": "yhgxq", + "col923": "odmcb", + "col924": "i7lcp", + "col925": "k5xq6", + "col926": "5dn9y", + "col927": "f8ss6", + "col928": "fkenj", + "col929": "mcjmi", + "col930": "iucgo", + "col931": "qzdcs", + "col932": "cwdyf", + "col933": "lqa9z", + "col934": "bat5m", + "col935": "u4reb", + "col936": "vddyn", + "col937": "k0khu", + "col938": "calwh", + "col939": "4egef", + "col940": "r43hc", + "col941": "pdqnk", + "col942": "k1vta", + "col943": "1np8y", + "col944": "y5g3p", + "col945": "go02q", + "col946": "oz1v6", + "col947": "q7q86", + "col948": "g2ppc", + "col949": "h7yvq", + "col950": "02yme", + "col951": "gvv1f", + "col952": "3k2fn", + "col953": "dj3mk", + "col954": "uz9w2", + "col955": "9zjwb", + "col956": "09ubf", + "col957": "aydi1", + "col958": "s10ib", + "col959": "riim2", + "col960": "phy1x", + "col961": "lmzxq", + "col962": "7xsi9", + "col963": "8pkvr", + "col964": "auwmj", + "col965": "za60n", + "col966": "a814b", + "col967": "nmnn9", + "col968": "k5lgt", + "col969": "g8xni", + "col970": "tgwt1", + "col971": "ft2vc", + "col972": "na2k4", + "col973": "wcg5r", + "col974": "xdrd2", + "col975": "9znhx", + "col976": "k5er2", + "col977": "6njqr", + "col978": "4q13l", + "col979": "jj7g2", + "col980": "eb5k2", + "col981": "pdo4e", + "col982": "ovm85", + "col983": "01ykf", + "col984": "b3kz4", + "col985": "beefx", + "col986": "x2uwl", + "col987": "9vfql", + "col988": "jglej", + "col989": "mrw6q", + "col990": "76tf1", + "col991": "2ohqg", + "col992": "87pfz", + "col993": "saiwq", + "col994": "nc26l", + "col995": "y3p5o", + "col996": "jblob", + "col997": "4zf0y", + "col998": "fi0j4", + "col999": "gdtzs" + }, + { + "name": "Ginger Suarez", + "gender": "female", + "col0": "5wogp", + "col1": "bifh1", + "col2": "wbywc", + "col3": "f8ghu", + "col4": "hdwld", + "col5": "vjiay", + "col6": "b6x68", + "col7": "ufjbg", + "col8": "7a4l0", + "col9": "512it", + "col10": "9qm7n", + "col11": "x19q8", + "col12": "tdkuh", + "col13": "nnfki", + "col14": "2j40l", + "col15": "yhfxi", + "col16": "xaocr", + "col17": "iobwb", + "col18": "8h0f8", + "col19": "8hn2n", + "col20": "nsk9x", + "col21": "6yx43", + "col22": "ztq1b", + "col23": "ffvhd", + "col24": "fw9yb", + "col25": "71a3o", + "col26": "j5tzf", + "col27": "cjyvf", + "col28": "fwfbu", + "col29": "ej55h", + "col30": "e3bv6", + "col31": "u0mmn", + "col32": "s60at", + "col33": "m8t09", + "col34": "s7xs4", + "col35": "0sajm", + "col36": "nokwl", + "col37": "dag2q", + "col38": "w3gmk", + "col39": "9i0aa", + "col40": "a4il8", + "col41": "m7jlm", + "col42": "q9qal", + "col43": "ilirx", + "col44": "sp0ho", + "col45": "os1od", + "col46": "53sar", + "col47": "avefm", + "col48": "ko5zl", + "col49": "b2mi3", + "col50": "986ud", + "col51": "b5ec9", + "col52": "ywwcm", + "col53": "719qq", + "col54": "vzrkc", + "col55": "nno2z", + "col56": "86mbe", + "col57": "4i4eh", + "col58": "v0bsq", + "col59": "1z66e", + "col60": "w2eez", + "col61": "jd9b1", + "col62": "65xf2", + "col63": "oy81c", + "col64": "g51f9", + "col65": "ibyui", + "col66": "46ura", + "col67": "dsef3", + "col68": "ru3ht", + "col69": "zlh3g", + "col70": "jy96o", + "col71": "w32cv", + "col72": "y4r2w", + "col73": "stbb1", + "col74": "w84j7", + "col75": "u61pl", + "col76": "vm833", + "col77": "rsuns", + "col78": "k6zbm", + "col79": "a337q", + "col80": "rhwck", + "col81": "7d6e0", + "col82": "9jdk4", + "col83": "3fjrd", + "col84": "eciea", + "col85": "8jndn", + "col86": "cssvm", + "col87": "weawu", + "col88": "wzb5i", + "col89": "t0tof", + "col90": "tcg4m", + "col91": "nvke9", + "col92": "lhlz5", + "col93": "zttx6", + "col94": "q5d2a", + "col95": "sjkf8", + "col96": "ckckx", + "col97": "asqjy", + "col98": "eq2vk", + "col99": "nt6w1", + "col100": "dfvf3", + "col101": "khjee", + "col102": "eqkx6", + "col103": "c1fys", + "col104": "aedyw", + "col105": "bs6sw", + "col106": "gnrtj", + "col107": "xw07s", + "col108": "kvwdd", + "col109": "fpclr", + "col110": "xerxn", + "col111": "kstdf", + "col112": "soeln", + "col113": "9r4is", + "col114": "xjuxa", + "col115": "zagc0", + "col116": "pmicj", + "col117": "zztlo", + "col118": "ssc7o", + "col119": "0i3l1", + "col120": "zxqin", + "col121": "btto5", + "col122": "iva3h", + "col123": "pb5ro", + "col124": "h9632", + "col125": "8u9sl", + "col126": "dvf5q", + "col127": "bvjya", + "col128": "egr7j", + "col129": "9v59y", + "col130": "rs3jy", + "col131": "l64wo", + "col132": "ohmen", + "col133": "rquoj", + "col134": "jxkwv", + "col135": "538c7", + "col136": "eto1m", + "col137": "26214", + "col138": "q5fx6", + "col139": "nb601", + "col140": "h6sth", + "col141": "mqv31", + "col142": "m36g5", + "col143": "z2i9u", + "col144": "0usu6", + "col145": "6vvzi", + "col146": "i7ro3", + "col147": "2n7g4", + "col148": "4bxp6", + "col149": "ul06b", + "col150": "3reu2", + "col151": "xbkt5", + "col152": "os9vw", + "col153": "8t75f", + "col154": "et0b5", + "col155": "jez6t", + "col156": "y2x9v", + "col157": "uae3l", + "col158": "9abpb", + "col159": "80zo1", + "col160": "gdxar", + "col161": "4ljax", + "col162": "bp3v4", + "col163": "unoq0", + "col164": "ki3nu", + "col165": "52c6a", + "col166": "pehoa", + "col167": "ubfu5", + "col168": "3vrot", + "col169": "wzfdb", + "col170": "z9fek", + "col171": "xgzl9", + "col172": "6v76z", + "col173": "50d4q", + "col174": "pu1fh", + "col175": "4x5jb", + "col176": "uwq3o", + "col177": "ssxyp", + "col178": "jqr22", + "col179": "8ff7s", + "col180": "xrwdo", + "col181": "67mbq", + "col182": "0logl", + "col183": "7y8kh", + "col184": "q3xd2", + "col185": "d1hwm", + "col186": "j7d7i", + "col187": "g2jsw", + "col188": "ykixo", + "col189": "otzt6", + "col190": "a1eqc", + "col191": "jiko0", + "col192": "l3h9x", + "col193": "6mnxp", + "col194": "qb5vc", + "col195": "ohrw8", + "col196": "hendd", + "col197": "70beu", + "col198": "o7kbj", + "col199": "92aeb", + "col200": "wja1i", + "col201": "qdgq6", + "col202": "o0de4", + "col203": "rqjkm", + "col204": "gm0eq", + "col205": "jw5eb", + "col206": "u93eu", + "col207": "uzudy", + "col208": "rs4ss", + "col209": "r27wj", + "col210": "yebaa", + "col211": "unp9l", + "col212": "bry52", + "col213": "ps52f", + "col214": "f6ws6", + "col215": "4jml4", + "col216": "3tnro", + "col217": "pvquk", + "col218": "dv69a", + "col219": "971ac", + "col220": "6m2t7", + "col221": "9uzxp", + "col222": "1d4lj", + "col223": "grllk", + "col224": "lqr25", + "col225": "m84nn", + "col226": "95eec", + "col227": "8u68r", + "col228": "5thfb", + "col229": "ndswf", + "col230": "ylqgk", + "col231": "tof0b", + "col232": "e7t4g", + "col233": "6a2xq", + "col234": "sd6q8", + "col235": "psyy0", + "col236": "9eb84", + "col237": "sf7uc", + "col238": "t3nj1", + "col239": "tck9k", + "col240": "7z1dr", + "col241": "v8dfj", + "col242": "edu9h", + "col243": "fq4qs", + "col244": "ylezo", + "col245": "kz9ru", + "col246": "uaz0h", + "col247": "g95gn", + "col248": "ooctp", + "col249": "go67r", + "col250": "znjh7", + "col251": "lrss3", + "col252": "r0kjk", + "col253": "f1v2o", + "col254": "r908s", + "col255": "7q70p", + "col256": "abpmt", + "col257": "tdv3w", + "col258": "ysgh6", + "col259": "j4z8l", + "col260": "y3759", + "col261": "j7itd", + "col262": "9ar92", + "col263": "s78jy", + "col264": "ien3i", + "col265": "fkws2", + "col266": "tp61u", + "col267": "hsood", + "col268": "c7qj6", + "col269": "vumpu", + "col270": "ovkbt", + "col271": "xphih", + "col272": "hqbd1", + "col273": "1tzdl", + "col274": "82axp", + "col275": "vaz6n", + "col276": "38acu", + "col277": "w1qgy", + "col278": "ch2qa", + "col279": "gkw5l", + "col280": "g42mt", + "col281": "pn6te", + "col282": "efsjk", + "col283": "2elji", + "col284": "qdwrp", + "col285": "jkip7", + "col286": "yu3e7", + "col287": "vkb58", + "col288": "6i9my", + "col289": "aa88t", + "col290": "8rlbe", + "col291": "et0td", + "col292": "vy6vy", + "col293": "8xa5x", + "col294": "gmxmu", + "col295": "xh08w", + "col296": "5toqb", + "col297": "2jxl0", + "col298": "o469r", + "col299": "jdqkn", + "col300": "2w0d1", + "col301": "zvvez", + "col302": "xfd9m", + "col303": "byaad", + "col304": "iohzp", + "col305": "icns0", + "col306": "w7t91", + "col307": "anejp", + "col308": "kxvkk", + "col309": "4zplg", + "col310": "uwu7o", + "col311": "9it46", + "col312": "kbkiq", + "col313": "75306", + "col314": "b5l4o", + "col315": "wlf6y", + "col316": "hlwah", + "col317": "sm7d8", + "col318": "qlwbl", + "col319": "ri81n", + "col320": "l1op4", + "col321": "0g7a8", + "col322": "w4jwa", + "col323": "s11h4", + "col324": "pw1x7", + "col325": "4le2m", + "col326": "nm04f", + "col327": "0fphj", + "col328": "cyhpw", + "col329": "0tyd2", + "col330": "c08ki", + "col331": "g9fpr", + "col332": "57140", + "col333": "16kz3", + "col334": "xh0ib", + "col335": "oyv7s", + "col336": "pz5y6", + "col337": "s9x5g", + "col338": "a51fc", + "col339": "agm8d", + "col340": "wvwmd", + "col341": "qxuy1", + "col342": "4xm7m", + "col343": "u5oy8", + "col344": "xd6ku", + "col345": "6adiu", + "col346": "td3mf", + "col347": "m9rsz", + "col348": "lf177", + "col349": "qhhz0", + "col350": "glapd", + "col351": "9sgw8", + "col352": "xre16", + "col353": "hoooy", + "col354": "qu3po", + "col355": "e354t", + "col356": "u5y6m", + "col357": "zto46", + "col358": "cql91", + "col359": "z5tzt", + "col360": "nk1s2", + "col361": "5o0lk", + "col362": "hexjq", + "col363": "pw10o", + "col364": "z4k62", + "col365": "06umn", + "col366": "lszhf", + "col367": "7dxlw", + "col368": "ay60a", + "col369": "p37x1", + "col370": "ogbha", + "col371": "jddou", + "col372": "9u08r", + "col373": "uhqdn", + "col374": "f4b46", + "col375": "zh18b", + "col376": "k1nzx", + "col377": "pic5b", + "col378": "jd4ug", + "col379": "imc1y", + "col380": "8tlz9", + "col381": "ryctl", + "col382": "eqpvy", + "col383": "2cilm", + "col384": "rf8j0", + "col385": "alf0k", + "col386": "hy8h9", + "col387": "11bnd", + "col388": "51s4k", + "col389": "bv3jm", + "col390": "76b9j", + "col391": "0p3yi", + "col392": "bprnu", + "col393": "o9kes", + "col394": "csv5j", + "col395": "fu5ot", + "col396": "ponx8", + "col397": "l82q3", + "col398": "uktp4", + "col399": "ilr6b", + "col400": "gdvsh", + "col401": "3e9oq", + "col402": "ebi9v", + "col403": "90fmz", + "col404": "m8k2q", + "col405": "2wezf", + "col406": "beail", + "col407": "gls0g", + "col408": "hxwnh", + "col409": "phl16", + "col410": "arhfj", + "col411": "8uxjb", + "col412": "obm3g", + "col413": "4e6pu", + "col414": "0g558", + "col415": "7eqjr", + "col416": "vfyh1", + "col417": "450mu", + "col418": "40mfy", + "col419": "dgi1d", + "col420": "tqo7u", + "col421": "6i027", + "col422": "7d0y7", + "col423": "vdsom", + "col424": "dh5dz", + "col425": "4gobz", + "col426": "i3d9r", + "col427": "0l9l0", + "col428": "6fmhl", + "col429": "l82mc", + "col430": "wqlpn", + "col431": "783uc", + "col432": "7e9el", + "col433": "7k6cq", + "col434": "kva98", + "col435": "v8gey", + "col436": "uixk6", + "col437": "nw5qz", + "col438": "1ght5", + "col439": "p1kyy", + "col440": "gojam", + "col441": "x1zb3", + "col442": "473sr", + "col443": "bwt8m", + "col444": "15p2x", + "col445": "n6dyy", + "col446": "s8kz3", + "col447": "y93km", + "col448": "exiap", + "col449": "3ke0n", + "col450": "3miu6", + "col451": "myhwt", + "col452": "2c0oq", + "col453": "9tue4", + "col454": "9ww3b", + "col455": "pq6so", + "col456": "bdleu", + "col457": "bkrc5", + "col458": "06rmi", + "col459": "b38it", + "col460": "qooep", + "col461": "nw2qx", + "col462": "197c4", + "col463": "lm9ip", + "col464": "2c0ez", + "col465": "rw0kl", + "col466": "0kchx", + "col467": "vcvx0", + "col468": "pdigh", + "col469": "itjtf", + "col470": "hat9m", + "col471": "r7rwu", + "col472": "lh3d0", + "col473": "q4zvz", + "col474": "nv3fx", + "col475": "y77mi", + "col476": "q8x4u", + "col477": "jtahp", + "col478": "jzknv", + "col479": "5awss", + "col480": "vhofg", + "col481": "iprx9", + "col482": "7aw9b", + "col483": "esoqo", + "col484": "7esq6", + "col485": "g53zr", + "col486": "u50ux", + "col487": "45l3f", + "col488": "k5sm7", + "col489": "5pdb6", + "col490": "952c4", + "col491": "cpz8y", + "col492": "16dv7", + "col493": "c7o6g", + "col494": "d110n", + "col495": "i115l", + "col496": "6j9c6", + "col497": "ogve5", + "col498": "posjp", + "col499": "uahvl", + "col500": "q5ksy", + "col501": "bukep", + "col502": "ch8j1", + "col503": "wnx9t", + "col504": "z9o5f", + "col505": "twrlf", + "col506": "aovad", + "col507": "h4f6h", + "col508": "077j4", + "col509": "ncmb8", + "col510": "eazrs", + "col511": "5lfyr", + "col512": "a3909", + "col513": "t7vlg", + "col514": "3wd7o", + "col515": "etqa7", + "col516": "3h7mq", + "col517": "df4h4", + "col518": "3faj6", + "col519": "xykkd", + "col520": "60jo5", + "col521": "3slnq", + "col522": "j8mpf", + "col523": "pgvrd", + "col524": "yv1gc", + "col525": "skz8n", + "col526": "xmr1t", + "col527": "hhqmi", + "col528": "txuig", + "col529": "ucp55", + "col530": "ujexp", + "col531": "ky5ve", + "col532": "s0avc", + "col533": "ttav9", + "col534": "il1ny", + "col535": "9sqrl", + "col536": "arpog", + "col537": "bx2lj", + "col538": "phauu", + "col539": "f2c5v", + "col540": "ccj3z", + "col541": "s4l0a", + "col542": "tnufc", + "col543": "1sgf4", + "col544": "7wnq2", + "col545": "wzqte", + "col546": "jhv06", + "col547": "q53uj", + "col548": "rgn32", + "col549": "jxv1w", + "col550": "0o399", + "col551": "ut11w", + "col552": "rlf60", + "col553": "zuha2", + "col554": "u2on9", + "col555": "i81i7", + "col556": "anmst", + "col557": "l3exe", + "col558": "ck0fm", + "col559": "plybi", + "col560": "y3bz5", + "col561": "0uc3q", + "col562": "hpiqy", + "col563": "78mcc", + "col564": "x4ogs", + "col565": "oncqm", + "col566": "dgetv", + "col567": "w7kfe", + "col568": "1uo02", + "col569": "z9pwf", + "col570": "qc3q3", + "col571": "08xoy", + "col572": "qstx4", + "col573": "4ryo5", + "col574": "ielri", + "col575": "llg4f", + "col576": "449jg", + "col577": "vriz7", + "col578": "28gbi", + "col579": "qg64t", + "col580": "btb4a", + "col581": "285i7", + "col582": "6slzb", + "col583": "vssyd", + "col584": "ic21u", + "col585": "56gpl", + "col586": "72can", + "col587": "fp34e", + "col588": "72fm1", + "col589": "wthdu", + "col590": "5boat", + "col591": "ujaaz", + "col592": "9tglr", + "col593": "4juld", + "col594": "i5lkj", + "col595": "nw1ua", + "col596": "uq5o6", + "col597": "11l18", + "col598": "g1mrq", + "col599": "0n5mp", + "col600": "fwuj0", + "col601": "600r7", + "col602": "ps7j6", + "col603": "7p06t", + "col604": "x2jo7", + "col605": "9sw8e", + "col606": "znm2v", + "col607": "d3ofr", + "col608": "6mpoo", + "col609": "34yqj", + "col610": "cer3e", + "col611": "s01wk", + "col612": "hhn97", + "col613": "vqy3r", + "col614": "drz56", + "col615": "27wa5", + "col616": "7folb", + "col617": "wbw1d", + "col618": "xeg1b", + "col619": "jqmwx", + "col620": "3x2pt", + "col621": "l2f4h", + "col622": "fayeo", + "col623": "dyym8", + "col624": "hy2fj", + "col625": "yp1pi", + "col626": "wizoz", + "col627": "b1436", + "col628": "86kdw", + "col629": "9dox8", + "col630": "g9mk5", + "col631": "souck", + "col632": "at4wf", + "col633": "evmid", + "col634": "afmop", + "col635": "fdrcy", + "col636": "tuebs", + "col637": "16988", + "col638": "15nu2", + "col639": "xlm36", + "col640": "8oftw", + "col641": "4atxz", + "col642": "mpc8f", + "col643": "z34s9", + "col644": "44azu", + "col645": "ombbn", + "col646": "uxpq7", + "col647": "onh3s", + "col648": "3kvud", + "col649": "8nju3", + "col650": "jri1w", + "col651": "0sfra", + "col652": "x05qn", + "col653": "cav2p", + "col654": "hyrhm", + "col655": "i0rsq", + "col656": "yu6eg", + "col657": "p8t9t", + "col658": "4bi34", + "col659": "ykbls", + "col660": "i9w9x", + "col661": "wv2qq", + "col662": "10y4x", + "col663": "yhpvn", + "col664": "4b586", + "col665": "firzf", + "col666": "y8y4a", + "col667": "x7520", + "col668": "6t84q", + "col669": "45euq", + "col670": "nsdv3", + "col671": "xghhz", + "col672": "erifn", + "col673": "gwzo4", + "col674": "oqovy", + "col675": "daquw", + "col676": "kirwo", + "col677": "miwel", + "col678": "2bap4", + "col679": "ybdc8", + "col680": "cjkw2", + "col681": "wv44x", + "col682": "pe4lx", + "col683": "cansa", + "col684": "ax5ai", + "col685": "vya81", + "col686": "1ycqd", + "col687": "6qzq9", + "col688": "0mwaa", + "col689": "0vbbw", + "col690": "h626u", + "col691": "1ptj0", + "col692": "o001h", + "col693": "rpnmt", + "col694": "9gkez", + "col695": "66vqn", + "col696": "7ivx4", + "col697": "eg0co", + "col698": "s8n9z", + "col699": "pxgnb", + "col700": "ew56w", + "col701": "q50fo", + "col702": "m11e1", + "col703": "lwt7i", + "col704": "1q46d", + "col705": "gtx7q", + "col706": "0pze8", + "col707": "vlckz", + "col708": "eyauk", + "col709": "auaup", + "col710": "3tgbl", + "col711": "2mzys", + "col712": "qdgx7", + "col713": "x8nvj", + "col714": "lijyv", + "col715": "3p6t7", + "col716": "cjbgy", + "col717": "tfvyj", + "col718": "mryij", + "col719": "u1r3r", + "col720": "t8sz7", + "col721": "j4cnt", + "col722": "9dhz0", + "col723": "qxuoe", + "col724": "8eys0", + "col725": "5uvhy", + "col726": "8erzh", + "col727": "wp5v7", + "col728": "teuq7", + "col729": "mzh7j", + "col730": "jyec3", + "col731": "ltd94", + "col732": "thzpd", + "col733": "qx5ix", + "col734": "k77bv", + "col735": "27s9v", + "col736": "sj2qf", + "col737": "pdw3p", + "col738": "65ut5", + "col739": "z0wh2", + "col740": "m9qu4", + "col741": "mzwz8", + "col742": "sogds", + "col743": "kej21", + "col744": "iof0c", + "col745": "vm43w", + "col746": "7we08", + "col747": "nu6s1", + "col748": "pcg8o", + "col749": "75u6u", + "col750": "80uot", + "col751": "f0szo", + "col752": "3zvdi", + "col753": "v298y", + "col754": "b0m7c", + "col755": "wa8xa", + "col756": "o97ex", + "col757": "b77bc", + "col758": "wgc86", + "col759": "8zyde", + "col760": "6ddzp", + "col761": "b76z8", + "col762": "6iwb2", + "col763": "ecux6", + "col764": "7kt3s", + "col765": "fv34b", + "col766": "tn2ba", + "col767": "gbgfr", + "col768": "tbz2z", + "col769": "1bg9b", + "col770": "7wf4t", + "col771": "cvq9b", + "col772": "j7dhy", + "col773": "f5qyx", + "col774": "p01fu", + "col775": "ojp0q", + "col776": "8nl0w", + "col777": "25nm5", + "col778": "l8r8l", + "col779": "rvt18", + "col780": "jcgsg", + "col781": "c1fc1", + "col782": "z4zcz", + "col783": "dpf0s", + "col784": "p91jt", + "col785": "tb9w5", + "col786": "mj0ka", + "col787": "qhcpt", + "col788": "l5b8v", + "col789": "3kc8q", + "col790": "3puad", + "col791": "c9kqa", + "col792": "vbclo", + "col793": "hmi66", + "col794": "wzond", + "col795": "24ozw", + "col796": "u58um", + "col797": "cp6jk", + "col798": "mgyry", + "col799": "60afo", + "col800": "6kogj", + "col801": "3r2iv", + "col802": "cj7n9", + "col803": "somoy", + "col804": "sanl1", + "col805": "osp9c", + "col806": "rakcq", + "col807": "y082x", + "col808": "hsp9f", + "col809": "pyq8e", + "col810": "tud6c", + "col811": "bngev", + "col812": "mj9a9", + "col813": "81p0f", + "col814": "wcc93", + "col815": "9xe8r", + "col816": "k1eby", + "col817": "ni21m", + "col818": "y5k1x", + "col819": "dhp5e", + "col820": "kvg4t", + "col821": "hqhbb", + "col822": "y5sua", + "col823": "u82un", + "col824": "pevf1", + "col825": "wzn5i", + "col826": "7ofmi", + "col827": "8jacx", + "col828": "7r4yd", + "col829": "gelrl", + "col830": "48h2f", + "col831": "ne8se", + "col832": "xyzqb", + "col833": "1ct52", + "col834": "uc8x4", + "col835": "cpxyo", + "col836": "cz3kn", + "col837": "8zn4j", + "col838": "fbfem", + "col839": "jkz3r", + "col840": "kni5j", + "col841": "dsafk", + "col842": "xam4p", + "col843": "nt4g5", + "col844": "egtkl", + "col845": "3xejv", + "col846": "cqvfg", + "col847": "lxg2w", + "col848": "es0cs", + "col849": "skfrp", + "col850": "90ias", + "col851": "mtz6l", + "col852": "97nq5", + "col853": "iv674", + "col854": "stolz", + "col855": "1tduf", + "col856": "8xmh3", + "col857": "8wutp", + "col858": "ffgoi", + "col859": "l4nsd", + "col860": "at17m", + "col861": "g5bvs", + "col862": "shask", + "col863": "jzrm0", + "col864": "b020x", + "col865": "mq7ji", + "col866": "i51y5", + "col867": "nctnv", + "col868": "6nxot", + "col869": "iuams", + "col870": "fy4f3", + "col871": "i17jl", + "col872": "84de3", + "col873": "9rw58", + "col874": "sb2hl", + "col875": "9apmu", + "col876": "fojue", + "col877": "9m87c", + "col878": "m2to4", + "col879": "29dsc", + "col880": "rin8u", + "col881": "vmurj", + "col882": "gqo10", + "col883": "6c5js", + "col884": "fkib6", + "col885": "n59hi", + "col886": "03xvp", + "col887": "befn6", + "col888": "j3xcp", + "col889": "jnaz1", + "col890": "d4u9a", + "col891": "kwbp9", + "col892": "h97ms", + "col893": "9947h", + "col894": "wkhce", + "col895": "db2bz", + "col896": "5tffr", + "col897": "vduwk", + "col898": "9nzxy", + "col899": "3vtmz", + "col900": "7xanz", + "col901": "prh30", + "col902": "1uufk", + "col903": "ft592", + "col904": "dufx1", + "col905": "kydv7", + "col906": "hdbny", + "col907": "93mwa", + "col908": "88txi", + "col909": "ip8j1", + "col910": "hszcb", + "col911": "s9fq2", + "col912": "tv4hp", + "col913": "13mhh", + "col914": "i8a48", + "col915": "zz1rr", + "col916": "g787f", + "col917": "ekg81", + "col918": "8l1kw", + "col919": "5j9ed", + "col920": "fc29g", + "col921": "j79vh", + "col922": "k35yb", + "col923": "ogh82", + "col924": "b814j", + "col925": "15eul", + "col926": "yurn6", + "col927": "uak6f", + "col928": "6wcq5", + "col929": "09sag", + "col930": "0x9a6", + "col931": "hunx2", + "col932": "rk9xn", + "col933": "vxrdb", + "col934": "l2es7", + "col935": "pmk72", + "col936": "8ksqe", + "col937": "c3ccp", + "col938": "0ardo", + "col939": "npinm", + "col940": "rtter", + "col941": "fvd1y", + "col942": "oaaqm", + "col943": "09c8d", + "col944": "q1cmn", + "col945": "9j2vo", + "col946": "7yjhv", + "col947": "vsa73", + "col948": "c6svn", + "col949": "jfles", + "col950": "h5377", + "col951": "1he75", + "col952": "jehtg", + "col953": "7z162", + "col954": "3d7ur", + "col955": "7fh1s", + "col956": "wqsoy", + "col957": "ic9go", + "col958": "mwwj7", + "col959": "duy74", + "col960": "odxny", + "col961": "5lzac", + "col962": "rrnbz", + "col963": "xl7yp", + "col964": "2vhhm", + "col965": "dax2x", + "col966": "a6fca", + "col967": "yyikv", + "col968": "jf3oq", + "col969": "ufqdl", + "col970": "hvioe", + "col971": "wwg3h", + "col972": "mxhnm", + "col973": "v1qiq", + "col974": "7bebc", + "col975": "4mpwv", + "col976": "pe20e", + "col977": "rvj0m", + "col978": "d2kv0", + "col979": "lqbjr", + "col980": "ts3r4", + "col981": "fo49k", + "col982": "lelx3", + "col983": "79pke", + "col984": "06zp3", + "col985": "s84qs", + "col986": "73a1d", + "col987": "au5ac", + "col988": "8dpeo", + "col989": "1xt7u", + "col990": "695vr", + "col991": "q6wt5", + "col992": "g95g9", + "col993": "nj3vm", + "col994": "hkfn1", + "col995": "8bj5h", + "col996": "uqa7k", + "col997": "zzhwz", + "col998": "eh525", + "col999": "iwlzn" + }, + { + "name": "Martina Mcdaniel", + "gender": "female", + "col0": "r476k", + "col1": "6qur8", + "col2": "yhdw2", + "col3": "cr7px", + "col4": "qz3b9", + "col5": "w8m99", + "col6": "co7sy", + "col7": "rokdb", + "col8": "mpb7d", + "col9": "j0r70", + "col10": "qqghr", + "col11": "3j3gr", + "col12": "fvu3f", + "col13": "mc6cy", + "col14": "xb81p", + "col15": "qs03t", + "col16": "lwk82", + "col17": "lkto5", + "col18": "2vawn", + "col19": "96hwm", + "col20": "4ltmn", + "col21": "dqst6", + "col22": "efiut", + "col23": "q0h8f", + "col24": "3tn76", + "col25": "49igv", + "col26": "zc29o", + "col27": "ml1kv", + "col28": "s2sa2", + "col29": "bk9qz", + "col30": "vv52q", + "col31": "cq9sm", + "col32": "ozf9p", + "col33": "sazfw", + "col34": "wuao4", + "col35": "1p1c9", + "col36": "0a1e8", + "col37": "lyoa9", + "col38": "y6kol", + "col39": "0wowd", + "col40": "j72hq", + "col41": "v7v81", + "col42": "jfu94", + "col43": "hc0sx", + "col44": "a4af6", + "col45": "bxu94", + "col46": "7cokq", + "col47": "it2oa", + "col48": "3anwm", + "col49": "j4ek1", + "col50": "oq2h2", + "col51": "t98pl", + "col52": "hg36y", + "col53": "g2cw2", + "col54": "5p9lv", + "col55": "6cwak", + "col56": "2xyi6", + "col57": "cyqty", + "col58": "o0pi2", + "col59": "tp0hd", + "col60": "9c67q", + "col61": "adska", + "col62": "xwgif", + "col63": "8wq3i", + "col64": "1jgvn", + "col65": "13i7p", + "col66": "ynjmm", + "col67": "fy53q", + "col68": "oy92k", + "col69": "vewmc", + "col70": "eiy6a", + "col71": "nj3is", + "col72": "ynfio", + "col73": "d177i", + "col74": "94tsi", + "col75": "d7yqn", + "col76": "ks853", + "col77": "414bd", + "col78": "w3i47", + "col79": "3jhaz", + "col80": "ulr8w", + "col81": "wi29q", + "col82": "m1ki7", + "col83": "e8aa9", + "col84": "i5c61", + "col85": "wkimd", + "col86": "zv3i0", + "col87": "imocq", + "col88": "6kmec", + "col89": "koqgp", + "col90": "hzgjt", + "col91": "rlnba", + "col92": "r5nq5", + "col93": "bvrrm", + "col94": "i2nso", + "col95": "ysl0b", + "col96": "oaai9", + "col97": "qh8zs", + "col98": "riw73", + "col99": "pqrjf", + "col100": "g041v", + "col101": "y5o4v", + "col102": "n2vy2", + "col103": "26tha", + "col104": "ge4ov", + "col105": "0d3v4", + "col106": "uirte", + "col107": "cver8", + "col108": "1dqm8", + "col109": "x8tpc", + "col110": "bxze7", + "col111": "af7bg", + "col112": "tt77p", + "col113": "wzead", + "col114": "wgbwd", + "col115": "ig87r", + "col116": "6u31p", + "col117": "25yx2", + "col118": "3uhyl", + "col119": "jtiha", + "col120": "v7qtz", + "col121": "nuz3a", + "col122": "oszdl", + "col123": "z4r7v", + "col124": "xa90x", + "col125": "gj9vs", + "col126": "tc4na", + "col127": "9og2r", + "col128": "i6gm5", + "col129": "jx525", + "col130": "03o4j", + "col131": "8yewn", + "col132": "bficc", + "col133": "smkyi", + "col134": "w81pb", + "col135": "004tr", + "col136": "knvsu", + "col137": "vl9qn", + "col138": "bcej5", + "col139": "ff7sj", + "col140": "qx7c8", + "col141": "7vl6u", + "col142": "c07ag", + "col143": "llti2", + "col144": "nydf5", + "col145": "264q5", + "col146": "uc6sx", + "col147": "lce09", + "col148": "5nfr6", + "col149": "iq2ez", + "col150": "boiq2", + "col151": "vi7vu", + "col152": "djsqq", + "col153": "wljou", + "col154": "j1rhs", + "col155": "ywk6i", + "col156": "2o83n", + "col157": "jeyiq", + "col158": "fn312", + "col159": "uo410", + "col160": "8v5yw", + "col161": "jqovb", + "col162": "8r8df", + "col163": "6q6mz", + "col164": "jlyzt", + "col165": "07s9n", + "col166": "g8b35", + "col167": "qpdzh", + "col168": "ia8ok", + "col169": "0dbqi", + "col170": "0u9ly", + "col171": "p3jna", + "col172": "wco1f", + "col173": "l8xtl", + "col174": "w21ir", + "col175": "mf6h2", + "col176": "d19uj", + "col177": "d9418", + "col178": "ukf96", + "col179": "o3m14", + "col180": "35nul", + "col181": "12hqj", + "col182": "h5aih", + "col183": "9okx1", + "col184": "ajaaq", + "col185": "hc111", + "col186": "u7yqr", + "col187": "40tz7", + "col188": "n57z9", + "col189": "09nw5", + "col190": "h881r", + "col191": "vkw1j", + "col192": "c7t73", + "col193": "rap2c", + "col194": "l8g7d", + "col195": "t733i", + "col196": "zuvps", + "col197": "rtk0x", + "col198": "k80kc", + "col199": "zkuo7", + "col200": "kmguq", + "col201": "3nymm", + "col202": "4gnvk", + "col203": "pea3q", + "col204": "mpruj", + "col205": "4s097", + "col206": "raybg", + "col207": "ao06g", + "col208": "ycc75", + "col209": "a8vxw", + "col210": "vds3o", + "col211": "z813t", + "col212": "gwcis", + "col213": "d5yav", + "col214": "toxun", + "col215": "m8k50", + "col216": "14ztb", + "col217": "24629", + "col218": "wcy54", + "col219": "d0au8", + "col220": "uoqkv", + "col221": "2trcs", + "col222": "d95r2", + "col223": "0w0iw", + "col224": "13mzf", + "col225": "sl21p", + "col226": "zw88g", + "col227": "2rbei", + "col228": "1kdnu", + "col229": "40t82", + "col230": "03iuk", + "col231": "ntqwo", + "col232": "dbnrm", + "col233": "yxwd1", + "col234": "x4mxm", + "col235": "7a2sx", + "col236": "95or0", + "col237": "5cjlx", + "col238": "xlfpw", + "col239": "glpuh", + "col240": "riaw0", + "col241": "9uzf3", + "col242": "fl5vr", + "col243": "8scg4", + "col244": "roh1z", + "col245": "2etuj", + "col246": "whqxl", + "col247": "k608f", + "col248": "ygbyx", + "col249": "b34mi", + "col250": "c0hj5", + "col251": "qk0vm", + "col252": "5at6n", + "col253": "gmezd", + "col254": "v0dl8", + "col255": "ok9ng", + "col256": "pyxr5", + "col257": "i7x6z", + "col258": "g9naw", + "col259": "k8zrh", + "col260": "2mw5u", + "col261": "grna2", + "col262": "yn7qf", + "col263": "w6pb1", + "col264": "d5pl7", + "col265": "bgrp9", + "col266": "lp8ik", + "col267": "wbjpj", + "col268": "qnv7m", + "col269": "lsmb8", + "col270": "41w0o", + "col271": "pc89i", + "col272": "momui", + "col273": "injrl", + "col274": "2ili1", + "col275": "86rq3", + "col276": "jgicx", + "col277": "pok5b", + "col278": "5jbjn", + "col279": "f2zuk", + "col280": "tyc20", + "col281": "05f8y", + "col282": "iirf1", + "col283": "p5nqv", + "col284": "vb7as", + "col285": "cx3oy", + "col286": "0uau4", + "col287": "a5yfo", + "col288": "hhitl", + "col289": "a2s2a", + "col290": "2m164", + "col291": "eb7hj", + "col292": "jskki", + "col293": "bxdbz", + "col294": "nnn5b", + "col295": "dhsmk", + "col296": "tmjcf", + "col297": "bp2dq", + "col298": "7ivo6", + "col299": "kzy3f", + "col300": "41axl", + "col301": "6yvoz", + "col302": "a8qo2", + "col303": "ui70c", + "col304": "mkl8v", + "col305": "1tqgp", + "col306": "mx9ab", + "col307": "6jz9a", + "col308": "c4t4d", + "col309": "k0dt9", + "col310": "8nzvv", + "col311": "vombd", + "col312": "wfu2f", + "col313": "6llz1", + "col314": "9vg6t", + "col315": "tn5au", + "col316": "xurh0", + "col317": "mkggo", + "col318": "ugiem", + "col319": "aufhk", + "col320": "1dur5", + "col321": "px9dq", + "col322": "u31c1", + "col323": "l5jgd", + "col324": "m1fvr", + "col325": "htm0g", + "col326": "ivak8", + "col327": "thmhd", + "col328": "5cgin", + "col329": "95hqw", + "col330": "ft606", + "col331": "3by37", + "col332": "p8pmo", + "col333": "weix0", + "col334": "0crsy", + "col335": "3bp0v", + "col336": "di2im", + "col337": "2x356", + "col338": "v9fbq", + "col339": "auuva", + "col340": "dyt2n", + "col341": "0vkqp", + "col342": "3zxtb", + "col343": "srcim", + "col344": "m657r", + "col345": "abiru", + "col346": "wn0af", + "col347": "iclhk", + "col348": "ijk53", + "col349": "x89r1", + "col350": "q6knm", + "col351": "x4vi6", + "col352": "wcfpk", + "col353": "l2ou3", + "col354": "unwl1", + "col355": "vf1n1", + "col356": "gw45n", + "col357": "epk7r", + "col358": "gj3jh", + "col359": "dcg3f", + "col360": "jzbpr", + "col361": "zg0j4", + "col362": "guvhd", + "col363": "xytre", + "col364": "lcegd", + "col365": "e6woe", + "col366": "cqdck", + "col367": "5rshr", + "col368": "rqmdi", + "col369": "7a3mr", + "col370": "rqcpq", + "col371": "ymisy", + "col372": "cy1vz", + "col373": "y07tm", + "col374": "5ecwv", + "col375": "9jxn6", + "col376": "0yfkk", + "col377": "5ojap", + "col378": "bp31i", + "col379": "yc81d", + "col380": "c9ntb", + "col381": "s2sq1", + "col382": "v9r7e", + "col383": "0zh7l", + "col384": "c4nm3", + "col385": "k70fp", + "col386": "d8t5i", + "col387": "si8xz", + "col388": "hxn3k", + "col389": "nvrvo", + "col390": "n8cso", + "col391": "2qje8", + "col392": "ihn0w", + "col393": "dt40n", + "col394": "274at", + "col395": "6ygpe", + "col396": "wi67i", + "col397": "g83d3", + "col398": "d7wx9", + "col399": "06e7q", + "col400": "gr7vf", + "col401": "d7dwh", + "col402": "gfuy6", + "col403": "7ozwl", + "col404": "4i63v", + "col405": "pup5v", + "col406": "okhiq", + "col407": "ofqhv", + "col408": "63i3n", + "col409": "prokc", + "col410": "69r3p", + "col411": "4y2ck", + "col412": "ft4jm", + "col413": "n3p0p", + "col414": "p5xb5", + "col415": "oyqlb", + "col416": "mvxmh", + "col417": "jgnvh", + "col418": "h501z", + "col419": "utyjy", + "col420": "fvsj9", + "col421": "7d70q", + "col422": "nv7ki", + "col423": "75k2q", + "col424": "g3ptc", + "col425": "yvuva", + "col426": "syu1b", + "col427": "j1yrv", + "col428": "0b0zc", + "col429": "ds2li", + "col430": "u84la", + "col431": "5g2b6", + "col432": "2pyzx", + "col433": "afssw", + "col434": "1uwp9", + "col435": "4s7ok", + "col436": "1bgan", + "col437": "2p1va", + "col438": "252sc", + "col439": "6gapi", + "col440": "dublo", + "col441": "gpe9a", + "col442": "6yt6o", + "col443": "tp6ib", + "col444": "cvwcc", + "col445": "ij0cv", + "col446": "p8idy", + "col447": "j63br", + "col448": "448ly", + "col449": "xli7d", + "col450": "adgff", + "col451": "mf6n4", + "col452": "kek75", + "col453": "vznq0", + "col454": "fpe4s", + "col455": "fkbnm", + "col456": "0rcx0", + "col457": "bd7fw", + "col458": "9tnup", + "col459": "p2m3j", + "col460": "nk3ng", + "col461": "kf2jt", + "col462": "7sn22", + "col463": "gjj18", + "col464": "yoi8u", + "col465": "alx42", + "col466": "nxmt2", + "col467": "59xq1", + "col468": "qb83r", + "col469": "y5jec", + "col470": "mo630", + "col471": "tp3mh", + "col472": "uof81", + "col473": "0wy2m", + "col474": "77urg", + "col475": "okxgj", + "col476": "ankmf", + "col477": "nqhrx", + "col478": "slkly", + "col479": "p8218", + "col480": "h5crr", + "col481": "x45hj", + "col482": "sgz8s", + "col483": "yybmm", + "col484": "ziqwy", + "col485": "9rafe", + "col486": "v7pse", + "col487": "8ia1r", + "col488": "havku", + "col489": "8ew20", + "col490": "gl390", + "col491": "9v7e0", + "col492": "7fgp9", + "col493": "1xnnw", + "col494": "l50v3", + "col495": "a8c01", + "col496": "iq1a1", + "col497": "3sg4u", + "col498": "6yaty", + "col499": "ona5h", + "col500": "ejvnn", + "col501": "4gyfl", + "col502": "mg80w", + "col503": "0pruz", + "col504": "9sveb", + "col505": "6k5sp", + "col506": "5v93d", + "col507": "g3l18", + "col508": "aatfu", + "col509": "jjw98", + "col510": "jqb60", + "col511": "qzewp", + "col512": "79c16", + "col513": "638ar", + "col514": "jflo4", + "col515": "7wufw", + "col516": "rs194", + "col517": "al5wz", + "col518": "livm5", + "col519": "yxhpy", + "col520": "kjq7u", + "col521": "6d1s1", + "col522": "fdu6d", + "col523": "ru89y", + "col524": "8cbym", + "col525": "qjx4o", + "col526": "f6jp2", + "col527": "bm21l", + "col528": "apshb", + "col529": "kt309", + "col530": "7yy2g", + "col531": "r7mzo", + "col532": "una6f", + "col533": "hhp4g", + "col534": "e1v38", + "col535": "i3bgl", + "col536": "lp50h", + "col537": "mhju5", + "col538": "qnygi", + "col539": "29f25", + "col540": "fdqqb", + "col541": "4406z", + "col542": "u4lw2", + "col543": "vyzcy", + "col544": "dokyc", + "col545": "xx1f0", + "col546": "zi5jg", + "col547": "gex3g", + "col548": "xlfkh", + "col549": "zm2ep", + "col550": "l9rpn", + "col551": "z3cto", + "col552": "v89h5", + "col553": "13juj", + "col554": "musqf", + "col555": "bn7h1", + "col556": "e0r9s", + "col557": "6wgbd", + "col558": "4wjjp", + "col559": "chzth", + "col560": "7rgcj", + "col561": "y41kd", + "col562": "upnef", + "col563": "ezp5f", + "col564": "bo17n", + "col565": "ywf9a", + "col566": "nam89", + "col567": "5mmvj", + "col568": "2uuhn", + "col569": "at7rt", + "col570": "odge6", + "col571": "dch9q", + "col572": "oocbl", + "col573": "id9i6", + "col574": "xloq3", + "col575": "47p0f", + "col576": "hnyke", + "col577": "s5cbl", + "col578": "wi0js", + "col579": "qdn8j", + "col580": "6c7ui", + "col581": "2bzhs", + "col582": "v5pmc", + "col583": "t3tmh", + "col584": "2etyg", + "col585": "kcdfr", + "col586": "zrco1", + "col587": "ikp8q", + "col588": "arzv8", + "col589": "py713", + "col590": "dw0o2", + "col591": "8tyt4", + "col592": "oswb5", + "col593": "gr4mj", + "col594": "ycty5", + "col595": "5v46b", + "col596": "n2qok", + "col597": "imeay", + "col598": "txlhz", + "col599": "86dg6", + "col600": "3u7x6", + "col601": "jy7f3", + "col602": "t4auo", + "col603": "t7iuh", + "col604": "qym47", + "col605": "pc90k", + "col606": "t2mi7", + "col607": "aj3k3", + "col608": "zdr6s", + "col609": "dj5qe", + "col610": "d0sdy", + "col611": "3fpyt", + "col612": "dl02p", + "col613": "u37n5", + "col614": "8g66x", + "col615": "wzuo7", + "col616": "0ce2i", + "col617": "dpufr", + "col618": "m0psh", + "col619": "hrrdz", + "col620": "gcc5a", + "col621": "c85dj", + "col622": "65tp2", + "col623": "op2kz", + "col624": "05kzg", + "col625": "gyiir", + "col626": "e45um", + "col627": "rswbt", + "col628": "bxp49", + "col629": "6hp99", + "col630": "jaamr", + "col631": "vch5c", + "col632": "4toy5", + "col633": "3uuj8", + "col634": "tmtra", + "col635": "pm14v", + "col636": "1zjcg", + "col637": "2rofr", + "col638": "sset7", + "col639": "dtn3b", + "col640": "t3swr", + "col641": "03639", + "col642": "2jdf4", + "col643": "lxm79", + "col644": "u9q6q", + "col645": "w5bfl", + "col646": "e8vf5", + "col647": "900sx", + "col648": "3yzmd", + "col649": "1ahet", + "col650": "emjet", + "col651": "qxgz5", + "col652": "z5x72", + "col653": "gluzg", + "col654": "7rv8z", + "col655": "rjerq", + "col656": "dkzzh", + "col657": "yasre", + "col658": "u5qsx", + "col659": "0j99d", + "col660": "j1uvs", + "col661": "bojj3", + "col662": "qkrki", + "col663": "fqdn7", + "col664": "rv01q", + "col665": "1eduz", + "col666": "c1n0u", + "col667": "z2324", + "col668": "bnu98", + "col669": "emngu", + "col670": "d0zt3", + "col671": "ymlck", + "col672": "vfg63", + "col673": "2r1wf", + "col674": "m86ig", + "col675": "2zg8e", + "col676": "t9qrj", + "col677": "hur2w", + "col678": "ok57s", + "col679": "5lshz", + "col680": "ehujc", + "col681": "wqhtz", + "col682": "jmtp8", + "col683": "hzro4", + "col684": "af4m6", + "col685": "zqqry", + "col686": "a7ff5", + "col687": "t28x6", + "col688": "y3qhb", + "col689": "hjgmb", + "col690": "avisg", + "col691": "yy5nh", + "col692": "3vnhs", + "col693": "k355j", + "col694": "03zi3", + "col695": "d22fh", + "col696": "95pq4", + "col697": "ji8xz", + "col698": "z89a2", + "col699": "xkfnb", + "col700": "mwgi5", + "col701": "fs8yj", + "col702": "dfloo", + "col703": "t913n", + "col704": "3hidz", + "col705": "d3loz", + "col706": "3jpow", + "col707": "eazph", + "col708": "wp4pj", + "col709": "iiduo", + "col710": "ihz9b", + "col711": "ra56h", + "col712": "xb3il", + "col713": "dysxm", + "col714": "h6a6i", + "col715": "59wt8", + "col716": "1uadz", + "col717": "3ml9k", + "col718": "369l1", + "col719": "skdpf", + "col720": "o7n31", + "col721": "5t6wu", + "col722": "ohf9f", + "col723": "8i4q1", + "col724": "c53ca", + "col725": "l8c94", + "col726": "2dv7b", + "col727": "9cx3g", + "col728": "y8lup", + "col729": "fqulv", + "col730": "1c2ov", + "col731": "ivspi", + "col732": "gb1p3", + "col733": "vjini", + "col734": "ob07o", + "col735": "5zfva", + "col736": "hi2y3", + "col737": "m1gs7", + "col738": "tcoke", + "col739": "z901i", + "col740": "6oq3h", + "col741": "clv0r", + "col742": "j3er2", + "col743": "ygevr", + "col744": "exq18", + "col745": "g2rbb", + "col746": "86vw8", + "col747": "1fctr", + "col748": "w1n7x", + "col749": "0ajsy", + "col750": "kyy1f", + "col751": "95mzh", + "col752": "pygnz", + "col753": "wjrc2", + "col754": "6kmox", + "col755": "jjrmw", + "col756": "zhfia", + "col757": "ogsvb", + "col758": "dollu", + "col759": "5v1o3", + "col760": "kouk9", + "col761": "djfzs", + "col762": "ah0se", + "col763": "l3il7", + "col764": "y7zgj", + "col765": "ycwwu", + "col766": "6hmbj", + "col767": "qekeq", + "col768": "zh9vt", + "col769": "81h3j", + "col770": "nhyyl", + "col771": "37dt6", + "col772": "u94je", + "col773": "2w13t", + "col774": "pi3w8", + "col775": "fjn0m", + "col776": "w8zl0", + "col777": "nktf4", + "col778": "fdlq3", + "col779": "9a6sj", + "col780": "848l0", + "col781": "jz672", + "col782": "790iw", + "col783": "q1jgp", + "col784": "3utg4", + "col785": "7y4t8", + "col786": "fc4yj", + "col787": "y2aen", + "col788": "bvbbr", + "col789": "a5i4q", + "col790": "5p248", + "col791": "n8mwx", + "col792": "p69px", + "col793": "up6c3", + "col794": "6119z", + "col795": "k9dq5", + "col796": "4lxvx", + "col797": "7kgvl", + "col798": "93aa0", + "col799": "n9p6j", + "col800": "kmhvc", + "col801": "bwuwy", + "col802": "ptcv5", + "col803": "0gw0g", + "col804": "1bk7o", + "col805": "5n7av", + "col806": "i96j8", + "col807": "a11zd", + "col808": "ykhac", + "col809": "fmc0x", + "col810": "5xp3p", + "col811": "j7x7q", + "col812": "3rnq7", + "col813": "u23on", + "col814": "c2nli", + "col815": "6klfe", + "col816": "iuz12", + "col817": "s6lpi", + "col818": "nv8bb", + "col819": "ag6g8", + "col820": "pzzbf", + "col821": "m7eum", + "col822": "j0lot", + "col823": "2darp", + "col824": "n7syi", + "col825": "ynxjy", + "col826": "4cwzu", + "col827": "dxv36", + "col828": "cv2h5", + "col829": "tkl1k", + "col830": "xbk8g", + "col831": "jfn3c", + "col832": "czv6y", + "col833": "m9747", + "col834": "17rre", + "col835": "fxvdf", + "col836": "llzgp", + "col837": "xcpft", + "col838": "hifjg", + "col839": "novas", + "col840": "pdx87", + "col841": "jvcu8", + "col842": "18c4q", + "col843": "kvn30", + "col844": "7k8ks", + "col845": "66ywc", + "col846": "dnjuo", + "col847": "3r4xi", + "col848": "m1ay7", + "col849": "x51uq", + "col850": "ijnb2", + "col851": "x3vju", + "col852": "ttmf5", + "col853": "ppc0r", + "col854": "ou7g6", + "col855": "fv7tx", + "col856": "cn1sw", + "col857": "ly7sg", + "col858": "6u5sk", + "col859": "ju9yb", + "col860": "jzka4", + "col861": "xs5fn", + "col862": "tevo8", + "col863": "utfhy", + "col864": "v9owu", + "col865": "u7w0l", + "col866": "xvclm", + "col867": "7dxg1", + "col868": "p7v2h", + "col869": "nvkrs", + "col870": "ct6c6", + "col871": "ttjqi", + "col872": "fw6gl", + "col873": "kb68m", + "col874": "voxw8", + "col875": "isog6", + "col876": "1vk5n", + "col877": "1t4xo", + "col878": "hftum", + "col879": "g1c2y", + "col880": "66cdq", + "col881": "vcyfj", + "col882": "8i8kc", + "col883": "juogw", + "col884": "cqi3a", + "col885": "j13zx", + "col886": "elh3n", + "col887": "tuahe", + "col888": "wsydr", + "col889": "8kz9m", + "col890": "hdj8q", + "col891": "y0znc", + "col892": "23qpw", + "col893": "blx0w", + "col894": "iucsw", + "col895": "qhv3b", + "col896": "5nakh", + "col897": "jdzca", + "col898": "2nvbj", + "col899": "bwe78", + "col900": "siwau", + "col901": "erjbr", + "col902": "uliyb", + "col903": "fndp5", + "col904": "1ubzp", + "col905": "5nhgu", + "col906": "rh43e", + "col907": "vlrpj", + "col908": "oqd9v", + "col909": "j85u2", + "col910": "rchg2", + "col911": "qks58", + "col912": "00vxr", + "col913": "7142v", + "col914": "ywovc", + "col915": "0yofa", + "col916": "moxnc", + "col917": "if7vo", + "col918": "jn8d9", + "col919": "5ey1j", + "col920": "b5i9p", + "col921": "uh09a", + "col922": "6lpja", + "col923": "f477c", + "col924": "emieo", + "col925": "d7vvr", + "col926": "n6ngm", + "col927": "vi5zp", + "col928": "e8vhh", + "col929": "0faze", + "col930": "kko7v", + "col931": "0ihn2", + "col932": "qspff", + "col933": "y6vpk", + "col934": "ld8mx", + "col935": "6cea0", + "col936": "oalji", + "col937": "bp3sl", + "col938": "g2qba", + "col939": "ppxfc", + "col940": "pqlel", + "col941": "82dfk", + "col942": "3lyfs", + "col943": "06ec1", + "col944": "bkgfm", + "col945": "qhzyd", + "col946": "efe3r", + "col947": "ufrzv", + "col948": "zoxt1", + "col949": "araez", + "col950": "ocixp", + "col951": "9k7bh", + "col952": "l789l", + "col953": "d1q9q", + "col954": "wsnjc", + "col955": "rg4m0", + "col956": "ipcxy", + "col957": "gek5w", + "col958": "kpeg0", + "col959": "cwtzl", + "col960": "1csw4", + "col961": "10jr6", + "col962": "aua8e", + "col963": "ndsm4", + "col964": "50rac", + "col965": "k7n36", + "col966": "3g6mu", + "col967": "4hqcj", + "col968": "cb8er", + "col969": "zsdjg", + "col970": "3baff", + "col971": "0zieg", + "col972": "vxq4r", + "col973": "g61rw", + "col974": "fnirf", + "col975": "tknz1", + "col976": "28zt6", + "col977": "6cfhr", + "col978": "n44yu", + "col979": "9scru", + "col980": "dv32b", + "col981": "0k27m", + "col982": "ux60p", + "col983": "ccb5a", + "col984": "f2t7y", + "col985": "b03yl", + "col986": "cyl78", + "col987": "4jsfx", + "col988": "3z4fq", + "col989": "gqxy6", + "col990": "p9lae", + "col991": "pq3gl", + "col992": "y3b6c", + "col993": "ltiuy", + "col994": "0q4j2", + "col995": "ip741", + "col996": "o3qt5", + "col997": "5n361", + "col998": "gb2in", + "col999": "efmw4" + }, + { + "name": "Millicent Lyons", + "gender": "female", + "col0": "ozq78", + "col1": "hs343", + "col2": "nqikc", + "col3": "244a2", + "col4": "w00vm", + "col5": "2vy24", + "col6": "eb65e", + "col7": "zsmgf", + "col8": "7xakq", + "col9": "8p5wj", + "col10": "th945", + "col11": "zbn9m", + "col12": "9q9xu", + "col13": "cbz0s", + "col14": "v2pfn", + "col15": "hasy8", + "col16": "umqn8", + "col17": "y7y9f", + "col18": "efk9a", + "col19": "cf5jg", + "col20": "sg8v7", + "col21": "pbdo1", + "col22": "ggbha", + "col23": "ieqph", + "col24": "824zu", + "col25": "7jqsa", + "col26": "8p27z", + "col27": "z9eni", + "col28": "vpvs7", + "col29": "e6siu", + "col30": "8yqxm", + "col31": "ygz9j", + "col32": "v4q2p", + "col33": "z5wiw", + "col34": "kaffv", + "col35": "83tqs", + "col36": "cbvvd", + "col37": "0icbb", + "col38": "kcitz", + "col39": "hkexb", + "col40": "hgz9h", + "col41": "91qqw", + "col42": "e5b5k", + "col43": "pw9e3", + "col44": "y4cbo", + "col45": "eqakh", + "col46": "6rku9", + "col47": "tvge0", + "col48": "ne06x", + "col49": "071zj", + "col50": "5w30s", + "col51": "oumk3", + "col52": "u86z1", + "col53": "55lts", + "col54": "fs3fh", + "col55": "7pnos", + "col56": "6jkmb", + "col57": "4pd5e", + "col58": "27yvv", + "col59": "1j11z", + "col60": "fcljt", + "col61": "3m0au", + "col62": "9qg5v", + "col63": "vv6u0", + "col64": "oro4t", + "col65": "nqw8b", + "col66": "hae2x", + "col67": "g8cww", + "col68": "2ztki", + "col69": "aple9", + "col70": "dhdsd", + "col71": "np398", + "col72": "88pwn", + "col73": "g3z15", + "col74": "t7gad", + "col75": "958gr", + "col76": "a0d3v", + "col77": "h9bqu", + "col78": "2u7ae", + "col79": "vwl6w", + "col80": "xyazo", + "col81": "mg5f4", + "col82": "eto8h", + "col83": "pfw3w", + "col84": "x8nac", + "col85": "q9xck", + "col86": "oydt9", + "col87": "4320o", + "col88": "dyxgb", + "col89": "9ss8x", + "col90": "sott4", + "col91": "yyt5l", + "col92": "v579a", + "col93": "ibi9i", + "col94": "ohn7u", + "col95": "9dx5d", + "col96": "fp7gv", + "col97": "zbhf6", + "col98": "skg6k", + "col99": "jrdnh", + "col100": "0jspc", + "col101": "cl1yi", + "col102": "ub6eo", + "col103": "2wu2b", + "col104": "v0wht", + "col105": "74u3j", + "col106": "u5o6b", + "col107": "qgbfs", + "col108": "nr1kj", + "col109": "l1g7c", + "col110": "pgm1f", + "col111": "8q54l", + "col112": "9nz1q", + "col113": "xkdz2", + "col114": "ia60w", + "col115": "aogjx", + "col116": "lll7k", + "col117": "644vt", + "col118": "23w6p", + "col119": "c4kiq", + "col120": "iv7ef", + "col121": "8p089", + "col122": "lput3", + "col123": "ctrmn", + "col124": "3u8vb", + "col125": "l8tsf", + "col126": "wi4fh", + "col127": "g21zi", + "col128": "qsdr7", + "col129": "ofjoa", + "col130": "ec8vm", + "col131": "7u50e", + "col132": "95trz", + "col133": "3rlap", + "col134": "h7rcc", + "col135": "f6gyz", + "col136": "hejbq", + "col137": "htrk4", + "col138": "pvmr4", + "col139": "9guq2", + "col140": "c8sz1", + "col141": "j0jc2", + "col142": "vfwr8", + "col143": "ar73k", + "col144": "yxp00", + "col145": "wi8u0", + "col146": "x7070", + "col147": "x5o99", + "col148": "m8p8d", + "col149": "0d8i9", + "col150": "va7tp", + "col151": "amutm", + "col152": "rmioc", + "col153": "6ajiy", + "col154": "q0yh2", + "col155": "0husy", + "col156": "7ns9j", + "col157": "kpelg", + "col158": "czdgn", + "col159": "a9482", + "col160": "1vmyc", + "col161": "8lfef", + "col162": "f826m", + "col163": "8g41j", + "col164": "itbhz", + "col165": "g1yfo", + "col166": "opi8a", + "col167": "pb2x8", + "col168": "1bdgy", + "col169": "rpzgg", + "col170": "r9lnb", + "col171": "terp9", + "col172": "ppv0f", + "col173": "xp8m5", + "col174": "aj716", + "col175": "7bzg4", + "col176": "w461w", + "col177": "rmmp1", + "col178": "sz9an", + "col179": "luxye", + "col180": "yms4s", + "col181": "2td2l", + "col182": "14o35", + "col183": "06b16", + "col184": "47qkp", + "col185": "f058h", + "col186": "aqw64", + "col187": "rxtr3", + "col188": "3sg2u", + "col189": "ejhsc", + "col190": "be4yg", + "col191": "whrfu", + "col192": "mo38p", + "col193": "wm14b", + "col194": "7zhdz", + "col195": "8i1tg", + "col196": "8ert6", + "col197": "sf070", + "col198": "8ugwh", + "col199": "7pvwx", + "col200": "ol8iy", + "col201": "ovysr", + "col202": "nypun", + "col203": "dsub8", + "col204": "4os1h", + "col205": "15i5q", + "col206": "ir0vo", + "col207": "45rzw", + "col208": "6up7a", + "col209": "gbxqj", + "col210": "bvqdy", + "col211": "7iyo1", + "col212": "z8kwp", + "col213": "t9i5t", + "col214": "9dkfr", + "col215": "dubxu", + "col216": "u2dr2", + "col217": "816q7", + "col218": "9jdhw", + "col219": "13wlk", + "col220": "6kvgn", + "col221": "juwbx", + "col222": "9lc29", + "col223": "sn6bl", + "col224": "eq71n", + "col225": "yktde", + "col226": "f3jsd", + "col227": "houvh", + "col228": "1gnor", + "col229": "j2gse", + "col230": "k1ups", + "col231": "ibwgn", + "col232": "nppzt", + "col233": "9b3kt", + "col234": "j8bfd", + "col235": "vci4g", + "col236": "mdgt3", + "col237": "yjitb", + "col238": "sphjq", + "col239": "n5bvc", + "col240": "yr595", + "col241": "fgl07", + "col242": "gyctt", + "col243": "nhufd", + "col244": "9xr2n", + "col245": "5pc0i", + "col246": "jpeym", + "col247": "kzpqk", + "col248": "p3ezd", + "col249": "9lcwr", + "col250": "u3qhy", + "col251": "itpuv", + "col252": "6uel1", + "col253": "nw3zg", + "col254": "89r4n", + "col255": "e1ph7", + "col256": "tszyi", + "col257": "fnlr6", + "col258": "wiao9", + "col259": "jf6lx", + "col260": "khjia", + "col261": "bdxw9", + "col262": "ft71k", + "col263": "5lgin", + "col264": "80220", + "col265": "mhs8k", + "col266": "mr1m1", + "col267": "8f08g", + "col268": "orl6j", + "col269": "umgp7", + "col270": "tqir8", + "col271": "pkjyq", + "col272": "067zw", + "col273": "zcmxu", + "col274": "m0y1j", + "col275": "fb6wa", + "col276": "vphhp", + "col277": "n04zk", + "col278": "ucg68", + "col279": "7r8iy", + "col280": "j3x7x", + "col281": "8lctr", + "col282": "0ti87", + "col283": "q1aad", + "col284": "klabg", + "col285": "sb6qq", + "col286": "82f6d", + "col287": "ed5x8", + "col288": "x07z7", + "col289": "2o67r", + "col290": "tsgih", + "col291": "0zvdc", + "col292": "rg8ht", + "col293": "5ld69", + "col294": "5gchn", + "col295": "xealf", + "col296": "y20ze", + "col297": "h01of", + "col298": "pesmw", + "col299": "1p8h3", + "col300": "j1zg1", + "col301": "v7pj9", + "col302": "8l7t8", + "col303": "kzkpr", + "col304": "65yrt", + "col305": "pehbs", + "col306": "n3eac", + "col307": "qajwf", + "col308": "lubii", + "col309": "glqr5", + "col310": "y9o2e", + "col311": "otdt5", + "col312": "pap52", + "col313": "z0zht", + "col314": "8ax6p", + "col315": "exv86", + "col316": "x0dtj", + "col317": "3lt01", + "col318": "ma73l", + "col319": "o319d", + "col320": "ip6cf", + "col321": "d1wmn", + "col322": "4efn8", + "col323": "zpyhl", + "col324": "nyr7q", + "col325": "bsukx", + "col326": "p6bkl", + "col327": "0ohhl", + "col328": "jj2lr", + "col329": "jxstf", + "col330": "57m2c", + "col331": "sr3ac", + "col332": "2j1do", + "col333": "y9mhv", + "col334": "tadzm", + "col335": "cvhvd", + "col336": "hqho4", + "col337": "vxg4s", + "col338": "qtihu", + "col339": "9y5h3", + "col340": "md5lh", + "col341": "wwyip", + "col342": "h8iqk", + "col343": "w6x9s", + "col344": "qn67g", + "col345": "rxkzl", + "col346": "t9f8c", + "col347": "5p4pt", + "col348": "p6sxj", + "col349": "qe1m8", + "col350": "o6pey", + "col351": "2au62", + "col352": "wgiid", + "col353": "9stlm", + "col354": "stp8h", + "col355": "4b350", + "col356": "s83qp", + "col357": "lng41", + "col358": "cnsjq", + "col359": "4udky", + "col360": "ml3vo", + "col361": "b6f43", + "col362": "n3sxl", + "col363": "zjuf5", + "col364": "7mabz", + "col365": "05wez", + "col366": "ssszq", + "col367": "cwm77", + "col368": "l9x7v", + "col369": "r0z6p", + "col370": "x5kgl", + "col371": "xxp47", + "col372": "4nc94", + "col373": "1jnr8", + "col374": "87ma9", + "col375": "qc286", + "col376": "8mni1", + "col377": "jtuy2", + "col378": "9rshg", + "col379": "mehvm", + "col380": "5gr1d", + "col381": "ud65z", + "col382": "6qcpx", + "col383": "6c1ah", + "col384": "c085a", + "col385": "ru267", + "col386": "cijex", + "col387": "d3io0", + "col388": "udw07", + "col389": "a7rl1", + "col390": "aoily", + "col391": "8fx97", + "col392": "6qipn", + "col393": "nkv05", + "col394": "5r6xp", + "col395": "2ks3n", + "col396": "2rt4l", + "col397": "h6guz", + "col398": "7y1nb", + "col399": "jx4oq", + "col400": "4rz5d", + "col401": "3xw4x", + "col402": "rf6a7", + "col403": "1vdk3", + "col404": "1sqhi", + "col405": "j9pqt", + "col406": "0zfsk", + "col407": "69u29", + "col408": "ort4p", + "col409": "mei7p", + "col410": "7509q", + "col411": "v1c1f", + "col412": "n6gab", + "col413": "83jdx", + "col414": "hh6zc", + "col415": "gclvj", + "col416": "nq7ny", + "col417": "2oh9y", + "col418": "q8nqy", + "col419": "8lx5r", + "col420": "ig3v2", + "col421": "r0m5z", + "col422": "i9ug6", + "col423": "n8dcv", + "col424": "w5k6g", + "col425": "h7gu2", + "col426": "e0ra0", + "col427": "0x8kd", + "col428": "bnb2k", + "col429": "sr6ud", + "col430": "yfqaj", + "col431": "17wtu", + "col432": "a2mtk", + "col433": "2bm0j", + "col434": "6fbxx", + "col435": "k5s3b", + "col436": "8uiwd", + "col437": "h3hcv", + "col438": "3fzgt", + "col439": "iruvj", + "col440": "oht7s", + "col441": "mu0e0", + "col442": "nkd53", + "col443": "0eah3", + "col444": "v6dt4", + "col445": "ev5e7", + "col446": "74su4", + "col447": "n56b4", + "col448": "70s6u", + "col449": "wa0fq", + "col450": "x9ud5", + "col451": "2ijtv", + "col452": "kntiw", + "col453": "5k0r2", + "col454": "501iv", + "col455": "jrtkg", + "col456": "wao5r", + "col457": "82kdw", + "col458": "irccm", + "col459": "u7yla", + "col460": "1wtpd", + "col461": "kcilm", + "col462": "xvtsj", + "col463": "byyit", + "col464": "sk4m7", + "col465": "z5o9u", + "col466": "4lzve", + "col467": "qs1al", + "col468": "fjlk1", + "col469": "2hova", + "col470": "8kivw", + "col471": "e4tuy", + "col472": "48gai", + "col473": "a7r95", + "col474": "0voqr", + "col475": "pjbkx", + "col476": "1v7ka", + "col477": "xzoyw", + "col478": "1q754", + "col479": "lu7fd", + "col480": "d4sk6", + "col481": "urunu", + "col482": "4t7gt", + "col483": "rc6qa", + "col484": "v1spt", + "col485": "xn06y", + "col486": "trhx2", + "col487": "47w4k", + "col488": "wfamd", + "col489": "ngcl2", + "col490": "d9wus", + "col491": "pk8u4", + "col492": "z1zn7", + "col493": "8rqhq", + "col494": "7fgx7", + "col495": "vqqsg", + "col496": "l3re0", + "col497": "bl1p5", + "col498": "oisi7", + "col499": "2sb7x", + "col500": "ysavx", + "col501": "sij6p", + "col502": "5evep", + "col503": "kdp2e", + "col504": "hl9dj", + "col505": "zj65l", + "col506": "ttjkv", + "col507": "zn8la", + "col508": "8u3ke", + "col509": "362tw", + "col510": "gp6pi", + "col511": "bm4fl", + "col512": "mtg7a", + "col513": "0yjwj", + "col514": "6034a", + "col515": "0o4to", + "col516": "sk6cx", + "col517": "05n33", + "col518": "9n26i", + "col519": "mdze2", + "col520": "3z6b6", + "col521": "pvfpx", + "col522": "usohc", + "col523": "lee3e", + "col524": "mhkyl", + "col525": "e1aco", + "col526": "8v63f", + "col527": "k4eth", + "col528": "guqfz", + "col529": "2ykyk", + "col530": "flrbj", + "col531": "42i7n", + "col532": "loo7w", + "col533": "irmog", + "col534": "jmyjj", + "col535": "rf2vu", + "col536": "745cg", + "col537": "9d1q8", + "col538": "0bvfw", + "col539": "0nqrq", + "col540": "b8ub8", + "col541": "a22r2", + "col542": "jlavp", + "col543": "cc4wc", + "col544": "13w3h", + "col545": "xbltt", + "col546": "s71t0", + "col547": "7mss8", + "col548": "73cce", + "col549": "br6q5", + "col550": "abtc1", + "col551": "3oex9", + "col552": "yw3n9", + "col553": "ei2qt", + "col554": "hcqh5", + "col555": "clvio", + "col556": "ejfq6", + "col557": "m8w74", + "col558": "cn9n6", + "col559": "q5823", + "col560": "isqs9", + "col561": "pf9m2", + "col562": "olg1u", + "col563": "eo8t4", + "col564": "u5ng0", + "col565": "lw6ii", + "col566": "z9a8r", + "col567": "doivn", + "col568": "n5k5k", + "col569": "b601a", + "col570": "df1hl", + "col571": "hcc70", + "col572": "bmiuq", + "col573": "pbfg7", + "col574": "brfxk", + "col575": "htnjq", + "col576": "sjsnw", + "col577": "k6pti", + "col578": "b9c1b", + "col579": "pcmy4", + "col580": "6xsau", + "col581": "z3f9v", + "col582": "6ae4p", + "col583": "mbf4t", + "col584": "6p1u8", + "col585": "s4368", + "col586": "o4jtw", + "col587": "3qdvv", + "col588": "q3xr8", + "col589": "je6t8", + "col590": "t7tx7", + "col591": "utb5d", + "col592": "c0a9a", + "col593": "8p471", + "col594": "n36in", + "col595": "t99wl", + "col596": "v6ftp", + "col597": "9hvnr", + "col598": "j4u3u", + "col599": "0auz1", + "col600": "6da7o", + "col601": "c5gcg", + "col602": "lbbis", + "col603": "62osz", + "col604": "uar3o", + "col605": "oqow1", + "col606": "zgq4a", + "col607": "tktmu", + "col608": "61awb", + "col609": "izfwp", + "col610": "hn1af", + "col611": "00v2y", + "col612": "rzpet", + "col613": "pwmzf", + "col614": "hpqgy", + "col615": "k0nwb", + "col616": "brq8m", + "col617": "ad2d2", + "col618": "kob9k", + "col619": "qre82", + "col620": "v7rgv", + "col621": "sayg6", + "col622": "h0gfr", + "col623": "3jfru", + "col624": "vez9y", + "col625": "a74ub", + "col626": "lahol", + "col627": "ocdir", + "col628": "tahnj", + "col629": "ja0rl", + "col630": "a73ej", + "col631": "la6bo", + "col632": "6vev7", + "col633": "6j9l6", + "col634": "0evvz", + "col635": "sngwr", + "col636": "xsgxm", + "col637": "zvv7m", + "col638": "efqzd", + "col639": "08qy9", + "col640": "nktvt", + "col641": "jvaon", + "col642": "o6h6l", + "col643": "fmw16", + "col644": "h1bil", + "col645": "3s0zm", + "col646": "gpkvq", + "col647": "j4f90", + "col648": "50f0d", + "col649": "kusxz", + "col650": "o1xlh", + "col651": "draw0", + "col652": "isk8i", + "col653": "l72mo", + "col654": "9twbq", + "col655": "p7jfx", + "col656": "0fd0b", + "col657": "a7rc4", + "col658": "cd34n", + "col659": "6exeb", + "col660": "alrm9", + "col661": "noctb", + "col662": "632em", + "col663": "y577u", + "col664": "swhk8", + "col665": "n9sm1", + "col666": "yg7fu", + "col667": "dorrc", + "col668": "efr2p", + "col669": "1kyo9", + "col670": "hwe8y", + "col671": "efpcy", + "col672": "dnstm", + "col673": "q15hv", + "col674": "dczru", + "col675": "5na6m", + "col676": "n93y8", + "col677": "aop3d", + "col678": "h04if", + "col679": "fimlq", + "col680": "bx3pv", + "col681": "xgqmi", + "col682": "nwnb5", + "col683": "w78dn", + "col684": "wk3d1", + "col685": "6hbm3", + "col686": "9atwr", + "col687": "7uysc", + "col688": "4v82c", + "col689": "5t5td", + "col690": "vmxar", + "col691": "rdv96", + "col692": "v3vhp", + "col693": "cmi7v", + "col694": "s4m39", + "col695": "r8amh", + "col696": "mke1a", + "col697": "10bz5", + "col698": "jcx7l", + "col699": "4cu4j", + "col700": "8webn", + "col701": "zabvt", + "col702": "ag6vx", + "col703": "t6l7v", + "col704": "hzgwq", + "col705": "e1nh2", + "col706": "ibr73", + "col707": "w67q6", + "col708": "c6e0v", + "col709": "s4o5r", + "col710": "nq8r9", + "col711": "vxclz", + "col712": "z8ty2", + "col713": "u31kc", + "col714": "ynq7w", + "col715": "6d9zs", + "col716": "qr1l1", + "col717": "fn3rz", + "col718": "wpshq", + "col719": "l3t86", + "col720": "dhxch", + "col721": "h51il", + "col722": "psgj7", + "col723": "xaglw", + "col724": "1agat", + "col725": "3ld3n", + "col726": "w2b6d", + "col727": "ljyri", + "col728": "630m9", + "col729": "5y6tt", + "col730": "5gr59", + "col731": "i91l4", + "col732": "mmdtm", + "col733": "bu544", + "col734": "bome1", + "col735": "l6rf8", + "col736": "w9i39", + "col737": "5nrkf", + "col738": "ex1pn", + "col739": "qrk6e", + "col740": "8kjhc", + "col741": "uxt62", + "col742": "3dvj6", + "col743": "djqmp", + "col744": "76wcm", + "col745": "9a152", + "col746": "fyv1j", + "col747": "z5lry", + "col748": "h0u4u", + "col749": "ht2q9", + "col750": "g0q0s", + "col751": "o4pb2", + "col752": "l7j2r", + "col753": "xpm23", + "col754": "jznxn", + "col755": "0s40m", + "col756": "5k5d8", + "col757": "crzj1", + "col758": "vxzgw", + "col759": "fzbki", + "col760": "jh3gl", + "col761": "uy5v9", + "col762": "i0but", + "col763": "q3n2s", + "col764": "6rq8s", + "col765": "cvheu", + "col766": "3xhor", + "col767": "1ebkk", + "col768": "nt0tb", + "col769": "hcjz9", + "col770": "1vqvt", + "col771": "9pfuf", + "col772": "tclbp", + "col773": "oa5sq", + "col774": "fsj0b", + "col775": "curn4", + "col776": "a3v96", + "col777": "xgu5f", + "col778": "6ly6m", + "col779": "3b56o", + "col780": "h654b", + "col781": "1j3op", + "col782": "g50v5", + "col783": "gtl12", + "col784": "bl949", + "col785": "pqrb5", + "col786": "9x3up", + "col787": "wksq5", + "col788": "mkf1f", + "col789": "451ce", + "col790": "bkuxx", + "col791": "wfm6a", + "col792": "07xms", + "col793": "n36a7", + "col794": "jd82b", + "col795": "4j3ag", + "col796": "pcm9g", + "col797": "xj7or", + "col798": "rdk0u", + "col799": "6mzn5", + "col800": "jkk5x", + "col801": "fwwro", + "col802": "xv4he", + "col803": "eecd9", + "col804": "pfue9", + "col805": "lfw3k", + "col806": "qzjd5", + "col807": "l21gq", + "col808": "0zfob", + "col809": "k6qk9", + "col810": "g4b5y", + "col811": "vkncz", + "col812": "mwqar", + "col813": "grv5j", + "col814": "ybcga", + "col815": "o3puu", + "col816": "ie1rp", + "col817": "vf6tk", + "col818": "p5csl", + "col819": "arxjk", + "col820": "a7shc", + "col821": "wte4z", + "col822": "khhum", + "col823": "0xlmh", + "col824": "gmy2t", + "col825": "htvqp", + "col826": "dw0wi", + "col827": "qn6ms", + "col828": "zdl8s", + "col829": "d3nbo", + "col830": "rhv7h", + "col831": "bl21u", + "col832": "b8wi2", + "col833": "h95cj", + "col834": "hgtfx", + "col835": "s9h90", + "col836": "2xucf", + "col837": "da49x", + "col838": "zo65k", + "col839": "9mw7r", + "col840": "lhb6o", + "col841": "2pi06", + "col842": "7kk5b", + "col843": "wscfz", + "col844": "rr3jv", + "col845": "9lpz6", + "col846": "lhggd", + "col847": "3h09v", + "col848": "ufdoa", + "col849": "jev0t", + "col850": "6okyx", + "col851": "mh33k", + "col852": "sk285", + "col853": "ivn7w", + "col854": "n4ek2", + "col855": "ov57h", + "col856": "kk54z", + "col857": "gs72y", + "col858": "mnr13", + "col859": "chxnn", + "col860": "qzxm3", + "col861": "e7y8s", + "col862": "xwnxt", + "col863": "yz7ed", + "col864": "i7y9j", + "col865": "0cffm", + "col866": "jmwyz", + "col867": "c8tqg", + "col868": "btaky", + "col869": "966nq", + "col870": "6f6hd", + "col871": "ypmrq", + "col872": "8yck8", + "col873": "1vj5p", + "col874": "4y8hh", + "col875": "hv7jy", + "col876": "p47xz", + "col877": "0tatg", + "col878": "34v9s", + "col879": "wlizb", + "col880": "63vmb", + "col881": "l70qm", + "col882": "zmshh", + "col883": "6mfst", + "col884": "xu3f9", + "col885": "dx9q5", + "col886": "aglf9", + "col887": "sx8e7", + "col888": "w7p9d", + "col889": "pdcv5", + "col890": "vpa3m", + "col891": "8c8jl", + "col892": "8fa2b", + "col893": "78jyw", + "col894": "xx0c6", + "col895": "xphwg", + "col896": "2onpl", + "col897": "qf2o9", + "col898": "iay6q", + "col899": "cjv0c", + "col900": "ty0z0", + "col901": "dtl2p", + "col902": "bv1wd", + "col903": "0gava", + "col904": "fa5gy", + "col905": "a8tae", + "col906": "b0dyt", + "col907": "koqld", + "col908": "vrpmm", + "col909": "7mm0d", + "col910": "5oaaf", + "col911": "ok2oe", + "col912": "qj2hn", + "col913": "50yxn", + "col914": "8g3de", + "col915": "vw7eh", + "col916": "bdutd", + "col917": "9tnbv", + "col918": "cj62s", + "col919": "09h62", + "col920": "tf3me", + "col921": "0fla9", + "col922": "w8kau", + "col923": "14cwq", + "col924": "rrxg4", + "col925": "2whyg", + "col926": "w5bzl", + "col927": "0q764", + "col928": "9t1sv", + "col929": "jvsae", + "col930": "e9g0g", + "col931": "v99kp", + "col932": "ztybi", + "col933": "omj2j", + "col934": "66znx", + "col935": "0ufvj", + "col936": "870h8", + "col937": "gdyy3", + "col938": "h6ud8", + "col939": "6j6kc", + "col940": "hkneo", + "col941": "v37ej", + "col942": "conzc", + "col943": "17hb2", + "col944": "vsw5m", + "col945": "xh4f0", + "col946": "wmxk4", + "col947": "78pbf", + "col948": "qdux8", + "col949": "3cmbf", + "col950": "jicst", + "col951": "vvhj3", + "col952": "j01st", + "col953": "rxo7k", + "col954": "pe60j", + "col955": "hkz29", + "col956": "hth7x", + "col957": "0xdwl", + "col958": "sjd7y", + "col959": "o2809", + "col960": "tzqbh", + "col961": "nsre9", + "col962": "2tx5g", + "col963": "177xj", + "col964": "6kdqe", + "col965": "vuh2a", + "col966": "1l218", + "col967": "qwjcn", + "col968": "rrani", + "col969": "adjaf", + "col970": "e1chu", + "col971": "joenw", + "col972": "st8om", + "col973": "y2wzc", + "col974": "6y1b1", + "col975": "qizdw", + "col976": "b0ufx", + "col977": "2gcou", + "col978": "oo8lt", + "col979": "m35sa", + "col980": "2zgch", + "col981": "vqmjw", + "col982": "fprcm", + "col983": "r2rmb", + "col984": "t3vs1", + "col985": "7xlky", + "col986": "nforg", + "col987": "vtrmy", + "col988": "icjak", + "col989": "6mx78", + "col990": "jk863", + "col991": "9cks5", + "col992": "psv6z", + "col993": "uxbpi", + "col994": "oawsk", + "col995": "bp7za", + "col996": "ecaym", + "col997": "qve5z", + "col998": "k4261", + "col999": "ior0y" + }, + { + "name": "Sue Snider", + "gender": "female", + "col0": "c4vl3", + "col1": "mixes", + "col2": "p2i4f", + "col3": "su2qw", + "col4": "br1j0", + "col5": "alj5m", + "col6": "k8pg8", + "col7": "ekc0a", + "col8": "flj5t", + "col9": "zvcoa", + "col10": "afb83", + "col11": "s31qe", + "col12": "h8u0x", + "col13": "vitpp", + "col14": "4s18q", + "col15": "oqolh", + "col16": "hfxwy", + "col17": "vln2r", + "col18": "l5u0f", + "col19": "8yacz", + "col20": "qkg51", + "col21": "ltme7", + "col22": "fbnuk", + "col23": "uldm6", + "col24": "citpd", + "col25": "4iadk", + "col26": "kfz0v", + "col27": "b9tg0", + "col28": "5xgck", + "col29": "31q8k", + "col30": "4gzaw", + "col31": "3bf74", + "col32": "0jz17", + "col33": "cx73z", + "col34": "t1fii", + "col35": "9a3k2", + "col36": "np6sw", + "col37": "l9db3", + "col38": "ygysa", + "col39": "3kqlb", + "col40": "78r2p", + "col41": "hexqr", + "col42": "su668", + "col43": "isc87", + "col44": "0ehmx", + "col45": "yrnu0", + "col46": "5jsho", + "col47": "t3raj", + "col48": "g7sa1", + "col49": "t5qnr", + "col50": "cg1cy", + "col51": "8q1z5", + "col52": "zdlej", + "col53": "x76ya", + "col54": "ba05f", + "col55": "f9z43", + "col56": "uxa31", + "col57": "76iq8", + "col58": "jbww5", + "col59": "d7n86", + "col60": "m2xtz", + "col61": "mgy0q", + "col62": "c02eq", + "col63": "6gsyk", + "col64": "247zk", + "col65": "mxuxt", + "col66": "77un1", + "col67": "d5mwx", + "col68": "hx47w", + "col69": "844fo", + "col70": "apgad", + "col71": "t702h", + "col72": "va6rr", + "col73": "w333l", + "col74": "bbu1n", + "col75": "u19su", + "col76": "66185", + "col77": "yl0l0", + "col78": "cm8z3", + "col79": "mj4ze", + "col80": "wmwyu", + "col81": "rn4kh", + "col82": "n1r8s", + "col83": "z7eth", + "col84": "3ybta", + "col85": "ersu4", + "col86": "073mc", + "col87": "54nm1", + "col88": "3mzjr", + "col89": "uqcoo", + "col90": "ir7ne", + "col91": "s8kna", + "col92": "fgahy", + "col93": "sn9rf", + "col94": "h4v69", + "col95": "k2lf5", + "col96": "ar3em", + "col97": "k34ah", + "col98": "ziman", + "col99": "hdwl5", + "col100": "dqug3", + "col101": "uji0h", + "col102": "phj39", + "col103": "p6kmy", + "col104": "ud38v", + "col105": "bge7z", + "col106": "vpgx2", + "col107": "kae18", + "col108": "4mthw", + "col109": "9pdej", + "col110": "f26w1", + "col111": "9oneb", + "col112": "j4e77", + "col113": "i3yyb", + "col114": "7rq8x", + "col115": "jnnty", + "col116": "kotzu", + "col117": "krio4", + "col118": "n6yx1", + "col119": "6on9x", + "col120": "2l3wp", + "col121": "s132f", + "col122": "48jr4", + "col123": "d7xdo", + "col124": "0zgpw", + "col125": "toiw5", + "col126": "8zs2w", + "col127": "fqaq3", + "col128": "qc3rq", + "col129": "2bvw0", + "col130": "px8v2", + "col131": "xq4s1", + "col132": "k8wbq", + "col133": "oapq6", + "col134": "jq1ai", + "col135": "id4av", + "col136": "yts30", + "col137": "73imh", + "col138": "wnpdh", + "col139": "dsfop", + "col140": "7awrz", + "col141": "vuuwx", + "col142": "4z5ka", + "col143": "tzviv", + "col144": "46yog", + "col145": "fax8r", + "col146": "48w9t", + "col147": "aclpg", + "col148": "17byr", + "col149": "2rv94", + "col150": "sh3sp", + "col151": "3t7zb", + "col152": "p7rci", + "col153": "b79dt", + "col154": "tcg4r", + "col155": "wbm8h", + "col156": "c01zc", + "col157": "z6cgu", + "col158": "ttj9j", + "col159": "jmajz", + "col160": "xam3g", + "col161": "4hs3k", + "col162": "zovbj", + "col163": "10h4s", + "col164": "5cvq4", + "col165": "qzfi3", + "col166": "ktesb", + "col167": "o39mz", + "col168": "9srjh", + "col169": "yvz9g", + "col170": "rzep6", + "col171": "o1lq1", + "col172": "2ir2u", + "col173": "veoal", + "col174": "ls511", + "col175": "izcc3", + "col176": "nrlz0", + "col177": "m1szy", + "col178": "wn6ep", + "col179": "6gut5", + "col180": "7082q", + "col181": "bzmsd", + "col182": "ew5lh", + "col183": "h8fqx", + "col184": "n0l8x", + "col185": "dkli3", + "col186": "rcbqb", + "col187": "1n5bc", + "col188": "h61d8", + "col189": "2svpf", + "col190": "xbi0l", + "col191": "mvk6c", + "col192": "egd29", + "col193": "erj5w", + "col194": "6ljdb", + "col195": "2fq1l", + "col196": "v94c1", + "col197": "gpdxr", + "col198": "jcmbj", + "col199": "n40bw", + "col200": "k648f", + "col201": "cjc7n", + "col202": "ggt8i", + "col203": "sucox", + "col204": "awf1a", + "col205": "mnwq0", + "col206": "gnd97", + "col207": "141t7", + "col208": "oe3dz", + "col209": "4gw4o", + "col210": "f5lf7", + "col211": "u5n1j", + "col212": "jinvg", + "col213": "jy8gg", + "col214": "k2q97", + "col215": "pq4el", + "col216": "k3jfd", + "col217": "gx17w", + "col218": "v8xxo", + "col219": "ftgmx", + "col220": "slqfl", + "col221": "0c5j6", + "col222": "nht9w", + "col223": "sr8jl", + "col224": "awpyp", + "col225": "fsdqm", + "col226": "av0pv", + "col227": "x0cqj", + "col228": "sfhxa", + "col229": "r6wjd", + "col230": "6iukr", + "col231": "tq1vr", + "col232": "oxeux", + "col233": "zmwvr", + "col234": "0wnlz", + "col235": "h3d4c", + "col236": "5h5zf", + "col237": "ykzbn", + "col238": "89wa2", + "col239": "7rit8", + "col240": "h0bbj", + "col241": "3p79o", + "col242": "2vv1i", + "col243": "fom8u", + "col244": "bz8wd", + "col245": "rjhfz", + "col246": "tt9r5", + "col247": "ydodj", + "col248": "1liou", + "col249": "e046e", + "col250": "bwv05", + "col251": "81kto", + "col252": "7nx9k", + "col253": "v3z6d", + "col254": "vcp3x", + "col255": "0hxvo", + "col256": "5rmy3", + "col257": "vyb0q", + "col258": "5ja9c", + "col259": "gtwo8", + "col260": "4ajgd", + "col261": "uyjeb", + "col262": "r01ja", + "col263": "02dsv", + "col264": "e0cky", + "col265": "qg3zh", + "col266": "fyseh", + "col267": "cc7p8", + "col268": "vuolm", + "col269": "yy58f", + "col270": "77vmo", + "col271": "bhit2", + "col272": "iw3c6", + "col273": "kojog", + "col274": "y28cr", + "col275": "lr7ug", + "col276": "fy9oj", + "col277": "x17uc", + "col278": "djmss", + "col279": "4ndb0", + "col280": "5wc43", + "col281": "7k9ic", + "col282": "c1y49", + "col283": "1gbwq", + "col284": "kywmg", + "col285": "kduax", + "col286": "bslzr", + "col287": "gqt6n", + "col288": "qo7wo", + "col289": "27f2l", + "col290": "c3a6z", + "col291": "6x2ki", + "col292": "u1i6n", + "col293": "he1k5", + "col294": "qem9s", + "col295": "hkomf", + "col296": "o2z9u", + "col297": "jw94n", + "col298": "n2nen", + "col299": "6pca3", + "col300": "6f0lx", + "col301": "n7o68", + "col302": "0nsyg", + "col303": "98957", + "col304": "2cy98", + "col305": "otsyu", + "col306": "3nupk", + "col307": "ewdoc", + "col308": "1ego9", + "col309": "k3z1c", + "col310": "7fnm3", + "col311": "9pqr8", + "col312": "6he11", + "col313": "4kly5", + "col314": "f7by5", + "col315": "iio4o", + "col316": "7mzad", + "col317": "za3kn", + "col318": "56cp7", + "col319": "g196m", + "col320": "iolct", + "col321": "q5dlq", + "col322": "5bv0i", + "col323": "l1wru", + "col324": "47j5m", + "col325": "vtsw5", + "col326": "kik6w", + "col327": "7pjzg", + "col328": "6829e", + "col329": "5owzb", + "col330": "iuzv7", + "col331": "jjijk", + "col332": "dwsv6", + "col333": "a1j2p", + "col334": "wasiy", + "col335": "9icip", + "col336": "5u941", + "col337": "6hpy9", + "col338": "wn2zf", + "col339": "aj1ky", + "col340": "3r8iq", + "col341": "rtoaf", + "col342": "pglz5", + "col343": "d4hy9", + "col344": "td9vf", + "col345": "6impc", + "col346": "7ua5p", + "col347": "7r5ie", + "col348": "g7lw0", + "col349": "oxxk9", + "col350": "evu3z", + "col351": "tc3pl", + "col352": "e8kvw", + "col353": "bovce", + "col354": "yb75a", + "col355": "wtg19", + "col356": "vcqwe", + "col357": "g13c0", + "col358": "2mgj8", + "col359": "5qsmm", + "col360": "uey7k", + "col361": "hq3z5", + "col362": "sm4le", + "col363": "z1cr0", + "col364": "4vzry", + "col365": "m9sfs", + "col366": "16fzy", + "col367": "txk3u", + "col368": "t9yef", + "col369": "uaity", + "col370": "16x26", + "col371": "l2ks9", + "col372": "pcri2", + "col373": "kheqw", + "col374": "otdcu", + "col375": "1dlvm", + "col376": "us798", + "col377": "s6bfm", + "col378": "lhss5", + "col379": "9btaf", + "col380": "zw4r9", + "col381": "mkud8", + "col382": "uu4v0", + "col383": "zqmps", + "col384": "536d7", + "col385": "bpdhi", + "col386": "x7jhd", + "col387": "fe2qs", + "col388": "yd32j", + "col389": "pgqxp", + "col390": "2b1f7", + "col391": "hnxzn", + "col392": "a1rik", + "col393": "cb1qd", + "col394": "1fknq", + "col395": "s2x85", + "col396": "rdp60", + "col397": "qu13e", + "col398": "7mcb6", + "col399": "rufad", + "col400": "12a1z", + "col401": "bks4m", + "col402": "1gq8i", + "col403": "dzgs3", + "col404": "754ey", + "col405": "yhdph", + "col406": "acv3s", + "col407": "20bom", + "col408": "ll57m", + "col409": "dxayu", + "col410": "h2yxv", + "col411": "8ff80", + "col412": "5ff4j", + "col413": "bzf1y", + "col414": "9j2lh", + "col415": "9262j", + "col416": "6q490", + "col417": "xz9tv", + "col418": "t8hvy", + "col419": "3m4pn", + "col420": "uaylu", + "col421": "5ixoi", + "col422": "359l5", + "col423": "inzo4", + "col424": "bxolf", + "col425": "jv9fm", + "col426": "vu8k3", + "col427": "698df", + "col428": "hqhw8", + "col429": "k1nm8", + "col430": "eoe06", + "col431": "8ptgh", + "col432": "cn38y", + "col433": "bk8lv", + "col434": "mjj1b", + "col435": "omfnf", + "col436": "qt5q4", + "col437": "s6dku", + "col438": "ojby3", + "col439": "let3j", + "col440": "pkku0", + "col441": "cwoyn", + "col442": "rwj14", + "col443": "nea7f", + "col444": "67mam", + "col445": "a992z", + "col446": "0rier", + "col447": "85exr", + "col448": "0bymg", + "col449": "ojp0d", + "col450": "od2z1", + "col451": "6gmd8", + "col452": "y4ql1", + "col453": "e5293", + "col454": "layfp", + "col455": "3fwus", + "col456": "dadfr", + "col457": "1cwbp", + "col458": "v8bu8", + "col459": "ng0ti", + "col460": "ixcs2", + "col461": "8e1ee", + "col462": "ptcyb", + "col463": "ymblb", + "col464": "zyjwf", + "col465": "z8rpy", + "col466": "645li", + "col467": "3ehqe", + "col468": "sxd9v", + "col469": "0wn2l", + "col470": "61uvl", + "col471": "glbso", + "col472": "1l0ty", + "col473": "mne6b", + "col474": "p5by4", + "col475": "o96x1", + "col476": "qrxxa", + "col477": "uabcb", + "col478": "fn916", + "col479": "6046k", + "col480": "79xvb", + "col481": "8cme3", + "col482": "6fwv7", + "col483": "zu7j6", + "col484": "bq2g9", + "col485": "opfoc", + "col486": "2du24", + "col487": "0af1s", + "col488": "thqbi", + "col489": "vx5ks", + "col490": "yfu0s", + "col491": "b9shm", + "col492": "d7hfk", + "col493": "t3ld2", + "col494": "7jfw8", + "col495": "lev7z", + "col496": "e2q7y", + "col497": "7wdvt", + "col498": "gftsc", + "col499": "9ld54", + "col500": "cmrdp", + "col501": "noaee", + "col502": "uz04e", + "col503": "ds2h2", + "col504": "q89sz", + "col505": "jf82f", + "col506": "srwob", + "col507": "bzxyf", + "col508": "xewy7", + "col509": "ai2tv", + "col510": "q5wi2", + "col511": "1zobo", + "col512": "jmcdk", + "col513": "ujxgm", + "col514": "q2d1d", + "col515": "xfaik", + "col516": "p52j8", + "col517": "n7ckn", + "col518": "7pngz", + "col519": "q6hot", + "col520": "gunh4", + "col521": "vh9rb", + "col522": "ssbwo", + "col523": "mp3n8", + "col524": "qy9ps", + "col525": "ohjbb", + "col526": "7n4nm", + "col527": "p637z", + "col528": "x3s0v", + "col529": "p0ctq", + "col530": "u87e1", + "col531": "06jmd", + "col532": "jrfx9", + "col533": "zamae", + "col534": "mjy8c", + "col535": "ter2x", + "col536": "oej7q", + "col537": "x41ce", + "col538": "baaim", + "col539": "yd4xz", + "col540": "0008q", + "col541": "qz9xm", + "col542": "3hsv0", + "col543": "6hi75", + "col544": "c098o", + "col545": "4fa7v", + "col546": "933ef", + "col547": "41xa1", + "col548": "jabb7", + "col549": "4pemc", + "col550": "nc7rt", + "col551": "ztqqy", + "col552": "u1jj6", + "col553": "ryjre", + "col554": "d1a07", + "col555": "otzxx", + "col556": "417vd", + "col557": "3vxol", + "col558": "d0hpa", + "col559": "ro7zk", + "col560": "h3m34", + "col561": "gzt0m", + "col562": "y6y76", + "col563": "rsxt1", + "col564": "p29qw", + "col565": "rw6k5", + "col566": "xmxsw", + "col567": "h7bjx", + "col568": "xqiwz", + "col569": "023kw", + "col570": "jd0rc", + "col571": "ksdzc", + "col572": "tyxw1", + "col573": "ztcfs", + "col574": "c08so", + "col575": "aykie", + "col576": "q6o9j", + "col577": "p6tge", + "col578": "3mrad", + "col579": "0f31l", + "col580": "p8l81", + "col581": "5q2ah", + "col582": "wuuqx", + "col583": "3idbt", + "col584": "6757c", + "col585": "5rq22", + "col586": "z6ltg", + "col587": "uhy7w", + "col588": "zi9vp", + "col589": "16d1w", + "col590": "3ibl0", + "col591": "xd4li", + "col592": "zq65e", + "col593": "5zfjy", + "col594": "o2d0g", + "col595": "6wtl9", + "col596": "py4ok", + "col597": "l7hry", + "col598": "rk3kl", + "col599": "3mmqb", + "col600": "2tey8", + "col601": "a1t8m", + "col602": "ur23y", + "col603": "vxqwt", + "col604": "9esv3", + "col605": "ox9ug", + "col606": "qou4k", + "col607": "cljem", + "col608": "iz373", + "col609": "ga4c8", + "col610": "qxhk3", + "col611": "s3k02", + "col612": "qoc5l", + "col613": "9itc0", + "col614": "lnbwj", + "col615": "e77xk", + "col616": "yftbn", + "col617": "8u7kl", + "col618": "h0rtx", + "col619": "bc7mh", + "col620": "o03r4", + "col621": "q5cja", + "col622": "za9ge", + "col623": "q5zww", + "col624": "fk6a3", + "col625": "afjnz", + "col626": "8wsvj", + "col627": "0sf91", + "col628": "e1yto", + "col629": "u4svn", + "col630": "66dvl", + "col631": "1stb7", + "col632": "uic2w", + "col633": "8g06a", + "col634": "erwbh", + "col635": "d4n3k", + "col636": "c3tod", + "col637": "81cgk", + "col638": "q8wui", + "col639": "u30ua", + "col640": "h3eo4", + "col641": "so1i3", + "col642": "nyt0h", + "col643": "6ggky", + "col644": "caygj", + "col645": "wa50u", + "col646": "vdash", + "col647": "8xn1a", + "col648": "r6vvp", + "col649": "6z2yy", + "col650": "t5e3o", + "col651": "o8vfs", + "col652": "lbrvo", + "col653": "z7x2k", + "col654": "at6k7", + "col655": "2exvp", + "col656": "iiwb0", + "col657": "33yk9", + "col658": "2sbvc", + "col659": "ladjw", + "col660": "fm96h", + "col661": "j0xr1", + "col662": "73inc", + "col663": "eu4a7", + "col664": "a2dws", + "col665": "h4bb2", + "col666": "5wt6m", + "col667": "f01e3", + "col668": "ag4ye", + "col669": "gv7fs", + "col670": "k5d5t", + "col671": "4f5wt", + "col672": "flmw3", + "col673": "dqo63", + "col674": "j8drl", + "col675": "0qffq", + "col676": "8mad4", + "col677": "6zuc8", + "col678": "1vhvj", + "col679": "ud73x", + "col680": "naoj5", + "col681": "jf6n7", + "col682": "feqzm", + "col683": "z936i", + "col684": "zf5sk", + "col685": "328gq", + "col686": "t79rm", + "col687": "4qerv", + "col688": "flbus", + "col689": "5meq2", + "col690": "u54mr", + "col691": "1zrs2", + "col692": "y1sp4", + "col693": "yauxi", + "col694": "6iw9l", + "col695": "uu6ib", + "col696": "abhgu", + "col697": "2fk4g", + "col698": "akpgr", + "col699": "i0w1n", + "col700": "q0s5x", + "col701": "yuc1n", + "col702": "juoh8", + "col703": "wmhpk", + "col704": "ym2n1", + "col705": "9hakh", + "col706": "oj1ir", + "col707": "zlecx", + "col708": "e0dm8", + "col709": "ga0nl", + "col710": "1bgfm", + "col711": "vv3kr", + "col712": "d92ii", + "col713": "fqpin", + "col714": "4qxq4", + "col715": "xd3jz", + "col716": "xk9zq", + "col717": "t4y25", + "col718": "z890s", + "col719": "b5o08", + "col720": "q554w", + "col721": "taf5u", + "col722": "aly63", + "col723": "tykz8", + "col724": "yt1p4", + "col725": "j0flx", + "col726": "g0mrh", + "col727": "2r05o", + "col728": "kfsjt", + "col729": "fw97v", + "col730": "8ff7m", + "col731": "z7kwk", + "col732": "kq51e", + "col733": "63i5j", + "col734": "umexj", + "col735": "rwppu", + "col736": "ur0zv", + "col737": "ebyoj", + "col738": "iyj7b", + "col739": "w3uxn", + "col740": "ycc30", + "col741": "q9do0", + "col742": "vc91t", + "col743": "rt3t4", + "col744": "k0sqo", + "col745": "xsi10", + "col746": "k2a6r", + "col747": "ysk8b", + "col748": "79vve", + "col749": "oruqm", + "col750": "8ed1h", + "col751": "ak5lm", + "col752": "y5u1r", + "col753": "et1ft", + "col754": "31388", + "col755": "yu49f", + "col756": "tgoc3", + "col757": "bwyir", + "col758": "8z4yn", + "col759": "l3lr7", + "col760": "1ycob", + "col761": "stegf", + "col762": "t1nnc", + "col763": "q5vmu", + "col764": "75qqo", + "col765": "z2xrl", + "col766": "415eh", + "col767": "030c1", + "col768": "cc7vy", + "col769": "mejmp", + "col770": "2sx5y", + "col771": "qdrum", + "col772": "6cz8x", + "col773": "q9uvf", + "col774": "ozn0r", + "col775": "4dr9u", + "col776": "8cqck", + "col777": "9sbcm", + "col778": "83uwo", + "col779": "4dsu2", + "col780": "b68kx", + "col781": "uo7nz", + "col782": "jar7r", + "col783": "ohf8j", + "col784": "mauiw", + "col785": "r3yi4", + "col786": "g6nnh", + "col787": "bihz8", + "col788": "1phe1", + "col789": "bpg9k", + "col790": "hzf9p", + "col791": "f24xi", + "col792": "cv14x", + "col793": "tvtrt", + "col794": "apjlw", + "col795": "nhn1i", + "col796": "qq32l", + "col797": "gn7kd", + "col798": "6hog7", + "col799": "pm81d", + "col800": "qf4u1", + "col801": "it5nf", + "col802": "kah8o", + "col803": "mr3tv", + "col804": "gyz01", + "col805": "za68a", + "col806": "bxf8r", + "col807": "uhdk6", + "col808": "rkogd", + "col809": "hpbbe", + "col810": "zqa1v", + "col811": "2e2jk", + "col812": "j70mm", + "col813": "hfzj2", + "col814": "z2msf", + "col815": "w6kd3", + "col816": "hiu6p", + "col817": "x7m4x", + "col818": "63y8h", + "col819": "7y7iz", + "col820": "u5hyk", + "col821": "5twgk", + "col822": "bkjnc", + "col823": "8rwyi", + "col824": "lqahl", + "col825": "xlq7r", + "col826": "04s9a", + "col827": "oub3p", + "col828": "h1dgq", + "col829": "xy5ru", + "col830": "u2scc", + "col831": "lug09", + "col832": "kxwkj", + "col833": "i5e72", + "col834": "xknks", + "col835": "24byr", + "col836": "c2bix", + "col837": "vlfl6", + "col838": "1bm1a", + "col839": "0wnkl", + "col840": "7ixf6", + "col841": "730n4", + "col842": "2nhb7", + "col843": "8nsuk", + "col844": "9de1v", + "col845": "ow27i", + "col846": "hzgth", + "col847": "kdm6n", + "col848": "4ecif", + "col849": "a5qec", + "col850": "slzqg", + "col851": "l8xqr", + "col852": "f36h3", + "col853": "t7yhr", + "col854": "zekur", + "col855": "vs1ks", + "col856": "cepnv", + "col857": "uyuua", + "col858": "he7tt", + "col859": "6htq4", + "col860": "tz64v", + "col861": "8a4iw", + "col862": "gf73i", + "col863": "z2urf", + "col864": "yb9on", + "col865": "hj060", + "col866": "63u48", + "col867": "wx0oz", + "col868": "zab9h", + "col869": "180mj", + "col870": "11odj", + "col871": "6y7r5", + "col872": "znkyt", + "col873": "29ovv", + "col874": "ogck8", + "col875": "fipx4", + "col876": "s6qmg", + "col877": "r32j3", + "col878": "5nrbd", + "col879": "0xeu0", + "col880": "k4lub", + "col881": "h1ybs", + "col882": "4qusf", + "col883": "c0h86", + "col884": "ge3ml", + "col885": "6hcqv", + "col886": "tvyas", + "col887": "x5nkk", + "col888": "xv5jc", + "col889": "at4sw", + "col890": "7xbhn", + "col891": "48p6v", + "col892": "deony", + "col893": "jr5cl", + "col894": "ccac2", + "col895": "tj1dy", + "col896": "is9ak", + "col897": "wfzo2", + "col898": "afo02", + "col899": "ee69b", + "col900": "t1gib", + "col901": "ys8n2", + "col902": "j4x1d", + "col903": "gisot", + "col904": "1crro", + "col905": "myph8", + "col906": "6mh94", + "col907": "8hoqv", + "col908": "yygb2", + "col909": "esqxl", + "col910": "k53yb", + "col911": "7bdne", + "col912": "e4w2v", + "col913": "i2pmd", + "col914": "6y9bi", + "col915": "lywzk", + "col916": "hih17", + "col917": "r6cu3", + "col918": "vdao5", + "col919": "zzfuc", + "col920": "d0hvc", + "col921": "t3c5k", + "col922": "siwdf", + "col923": "4i26p", + "col924": "u0oq4", + "col925": "b7jv0", + "col926": "yqnt2", + "col927": "865cz", + "col928": "2rjoa", + "col929": "gbo0h", + "col930": "dchc9", + "col931": "yz9sp", + "col932": "vp1op", + "col933": "12opb", + "col934": "hh9po", + "col935": "q2luc", + "col936": "onyyf", + "col937": "r4k7n", + "col938": "rgppl", + "col939": "4ahsm", + "col940": "wa6oq", + "col941": "n8x9d", + "col942": "aoi5l", + "col943": "724ty", + "col944": "7afhh", + "col945": "clu12", + "col946": "k4p5j", + "col947": "yhz5l", + "col948": "158al", + "col949": "uj9y4", + "col950": "oksst", + "col951": "leh5r", + "col952": "bhmi9", + "col953": "118w4", + "col954": "7hsbn", + "col955": "vwzft", + "col956": "p0ub2", + "col957": "w7qf1", + "col958": "px8sw", + "col959": "sn7nu", + "col960": "vtuuo", + "col961": "dwvrs", + "col962": "a3a38", + "col963": "alfpm", + "col964": "0klip", + "col965": "n29qc", + "col966": "kpo52", + "col967": "nudts", + "col968": "8qw0g", + "col969": "trzwz", + "col970": "vcnz1", + "col971": "b15o0", + "col972": "1ysmy", + "col973": "nb587", + "col974": "uip97", + "col975": "bqp3y", + "col976": "5de2m", + "col977": "nwap5", + "col978": "2quil", + "col979": "1sdyx", + "col980": "19opn", + "col981": "3hne5", + "col982": "dlldx", + "col983": "mah69", + "col984": "5tx5m", + "col985": "ofo97", + "col986": "k6czw", + "col987": "ze88l", + "col988": "nk771", + "col989": "wgslr", + "col990": "27t1n", + "col991": "0yvq5", + "col992": "yfbrn", + "col993": "2twfn", + "col994": "p3uq7", + "col995": "azzgb", + "col996": "ezgiw", + "col997": "ba8ex", + "col998": "p5qdz", + "col999": "uxlvz" + }, + { + "name": "Laverne Ratliff", + "gender": "female", + "col0": "83sts", + "col1": "iobo2", + "col2": "qjl9a", + "col3": "ussca", + "col4": "ov9xk", + "col5": "jblib", + "col6": "ozt60", + "col7": "nai5c", + "col8": "185xt", + "col9": "0zeq3", + "col10": "r7cb1", + "col11": "dqjni", + "col12": "vqbme", + "col13": "h5zka", + "col14": "m3hkb", + "col15": "gmj5n", + "col16": "qfh9t", + "col17": "r0ozm", + "col18": "zk2eo", + "col19": "m14cv", + "col20": "dmq02", + "col21": "il3sr", + "col22": "lzfxe", + "col23": "eoi6h", + "col24": "uz3p2", + "col25": "my97k", + "col26": "kyl9z", + "col27": "9rztm", + "col28": "sicpo", + "col29": "snafs", + "col30": "fr8go", + "col31": "zl3ef", + "col32": "uylqb", + "col33": "dwvbs", + "col34": "reymv", + "col35": "9rkld", + "col36": "20z5p", + "col37": "v6agd", + "col38": "ip4i4", + "col39": "8dbfq", + "col40": "ecwvw", + "col41": "s5ye3", + "col42": "kdzap", + "col43": "kgngu", + "col44": "cwlxy", + "col45": "yvh3j", + "col46": "jvd6o", + "col47": "yuvgg", + "col48": "8oky8", + "col49": "qdafo", + "col50": "922m1", + "col51": "s7niv", + "col52": "5lmnc", + "col53": "m9p7k", + "col54": "i64jx", + "col55": "1t4g4", + "col56": "lzett", + "col57": "7hpxx", + "col58": "rpuv7", + "col59": "mbsqi", + "col60": "ndv7j", + "col61": "9v6ze", + "col62": "9bol6", + "col63": "3el7a", + "col64": "iwyf1", + "col65": "x3spd", + "col66": "36wcu", + "col67": "6dxyo", + "col68": "co72w", + "col69": "phql8", + "col70": "f31r1", + "col71": "iq3kv", + "col72": "td9y2", + "col73": "5kfnq", + "col74": "yua23", + "col75": "rkbpc", + "col76": "ev11y", + "col77": "9i5wh", + "col78": "q61wb", + "col79": "mk5my", + "col80": "8c36k", + "col81": "p6efk", + "col82": "erqxz", + "col83": "6zfl9", + "col84": "gbrzd", + "col85": "g5xmy", + "col86": "zmdhs", + "col87": "216k5", + "col88": "86daz", + "col89": "jigsb", + "col90": "qgqu1", + "col91": "s4df3", + "col92": "dm9xh", + "col93": "svd85", + "col94": "s29y1", + "col95": "9csrt", + "col96": "i1fw1", + "col97": "srvne", + "col98": "min0d", + "col99": "kmtrg", + "col100": "naaqw", + "col101": "xlg1o", + "col102": "t4tyk", + "col103": "b0fh3", + "col104": "uz0xq", + "col105": "bw1gy", + "col106": "ppbi3", + "col107": "9stry", + "col108": "qxxs7", + "col109": "7nztz", + "col110": "ph156", + "col111": "3xq5m", + "col112": "6ge0d", + "col113": "k4u06", + "col114": "cm58k", + "col115": "1szpm", + "col116": "yptl9", + "col117": "nhu76", + "col118": "2cbru", + "col119": "qkwvm", + "col120": "be45h", + "col121": "pta9d", + "col122": "w6a1l", + "col123": "vtw8c", + "col124": "yz0vu", + "col125": "bukx0", + "col126": "91u2k", + "col127": "u5b9r", + "col128": "w71iq", + "col129": "kz8gp", + "col130": "h36r7", + "col131": "npp4l", + "col132": "yx9ip", + "col133": "2tj6j", + "col134": "70396", + "col135": "4b90y", + "col136": "r2czk", + "col137": "b29bq", + "col138": "abyys", + "col139": "3e0lf", + "col140": "im3vw", + "col141": "wxogc", + "col142": "zzaj7", + "col143": "hp1cb", + "col144": "klq9j", + "col145": "7d030", + "col146": "6udaf", + "col147": "anoh4", + "col148": "70ly0", + "col149": "ld3xd", + "col150": "aji4d", + "col151": "piinq", + "col152": "z1z8h", + "col153": "oojms", + "col154": "4924x", + "col155": "g8wmv", + "col156": "ezy0x", + "col157": "6o2tc", + "col158": "yukz5", + "col159": "vxdvd", + "col160": "rfvp5", + "col161": "8iqsz", + "col162": "cojlr", + "col163": "976bh", + "col164": "jlr75", + "col165": "9ebkd", + "col166": "43yaq", + "col167": "6qodi", + "col168": "m9vox", + "col169": "fvsp7", + "col170": "p21ji", + "col171": "22usm", + "col172": "bzvn4", + "col173": "ngn23", + "col174": "t77w2", + "col175": "vd6sq", + "col176": "cbmvx", + "col177": "swid4", + "col178": "3rsuv", + "col179": "p4s8x", + "col180": "a0hkj", + "col181": "sdjd1", + "col182": "u18rz", + "col183": "9a1yp", + "col184": "6eu4h", + "col185": "qjcdd", + "col186": "jy31p", + "col187": "7ubrl", + "col188": "n6fga", + "col189": "u3p3z", + "col190": "010wa", + "col191": "m780v", + "col192": "3h2tn", + "col193": "du3f3", + "col194": "qvify", + "col195": "kqqxy", + "col196": "8i6p9", + "col197": "ms1mp", + "col198": "4wq9f", + "col199": "1rxe1", + "col200": "x1mx5", + "col201": "mtf5i", + "col202": "fbwgy", + "col203": "pr8k9", + "col204": "mg8l3", + "col205": "95rkg", + "col206": "b7ur6", + "col207": "tlnyd", + "col208": "8xkyi", + "col209": "wl2dv", + "col210": "8s5nh", + "col211": "gl7of", + "col212": "blxqb", + "col213": "ehhj6", + "col214": "2r04u", + "col215": "mirzu", + "col216": "j63jt", + "col217": "kxddj", + "col218": "dg0fc", + "col219": "cxepq", + "col220": "mhzql", + "col221": "dzqzq", + "col222": "my6ld", + "col223": "8p3r9", + "col224": "8kpx5", + "col225": "t6mta", + "col226": "z10og", + "col227": "jfav3", + "col228": "1vzki", + "col229": "wrwt1", + "col230": "lc73p", + "col231": "8xmqp", + "col232": "gv5h7", + "col233": "x531c", + "col234": "16hjd", + "col235": "m20mx", + "col236": "rw3mv", + "col237": "cq1tz", + "col238": "lgm4p", + "col239": "yu2hd", + "col240": "tkydt", + "col241": "e5vv8", + "col242": "x2jzz", + "col243": "6l6an", + "col244": "7q9uw", + "col245": "g8qg4", + "col246": "l2zca", + "col247": "49kt3", + "col248": "3a3ry", + "col249": "bz2o7", + "col250": "kssjd", + "col251": "f67lh", + "col252": "tel6b", + "col253": "6ile3", + "col254": "2ty08", + "col255": "rd249", + "col256": "z4v3q", + "col257": "yrqe3", + "col258": "tf7te", + "col259": "e7eif", + "col260": "8wps3", + "col261": "w1rqk", + "col262": "qlra2", + "col263": "gsads", + "col264": "2j8bi", + "col265": "arayw", + "col266": "e8g2s", + "col267": "0ptzk", + "col268": "6n4t4", + "col269": "zhtpf", + "col270": "84qcp", + "col271": "v8u0j", + "col272": "qs9n0", + "col273": "kd6bd", + "col274": "ekku8", + "col275": "5i02g", + "col276": "k2zd2", + "col277": "zsf12", + "col278": "pjytg", + "col279": "6aoip", + "col280": "8no7c", + "col281": "m5vxr", + "col282": "kqhjj", + "col283": "0mlb7", + "col284": "gmz3d", + "col285": "cq302", + "col286": "ey3wz", + "col287": "0nnuq", + "col288": "14rtm", + "col289": "g9qvo", + "col290": "r5vf0", + "col291": "g5mf5", + "col292": "r250a", + "col293": "11mi6", + "col294": "k1fx8", + "col295": "cml4r", + "col296": "0pwsc", + "col297": "acg7s", + "col298": "acnmg", + "col299": "ziw7q", + "col300": "xs9il", + "col301": "1wbn6", + "col302": "9upfu", + "col303": "6weuo", + "col304": "3qoso", + "col305": "ctd4b", + "col306": "oza6v", + "col307": "chyl4", + "col308": "lr8tg", + "col309": "ozuwf", + "col310": "i3223", + "col311": "i6nyf", + "col312": "c4oxa", + "col313": "j3p1p", + "col314": "hfoo1", + "col315": "ck3eg", + "col316": "8ny3n", + "col317": "hxbjt", + "col318": "jb9x9", + "col319": "dzgfy", + "col320": "kijya", + "col321": "mt6ua", + "col322": "efvxv", + "col323": "nbz64", + "col324": "8iurq", + "col325": "29ql9", + "col326": "ij32m", + "col327": "leq0s", + "col328": "r9ubm", + "col329": "e514r", + "col330": "4c3ks", + "col331": "l5834", + "col332": "39zin", + "col333": "5043b", + "col334": "nac4u", + "col335": "db9nx", + "col336": "vlro9", + "col337": "zu9hw", + "col338": "dq12n", + "col339": "k54gj", + "col340": "okzjw", + "col341": "tbda4", + "col342": "iyqfn", + "col343": "snu7q", + "col344": "14q9o", + "col345": "ced00", + "col346": "5tja4", + "col347": "gujme", + "col348": "6lgcs", + "col349": "tuill", + "col350": "uh7t0", + "col351": "u5mbu", + "col352": "3pt2t", + "col353": "pkcik", + "col354": "zo7pn", + "col355": "fklwt", + "col356": "5d2an", + "col357": "2h3qt", + "col358": "a61ui", + "col359": "3nq2s", + "col360": "wmgvs", + "col361": "zzgrx", + "col362": "mj5zl", + "col363": "fp7ik", + "col364": "803si", + "col365": "ofwu0", + "col366": "tus3o", + "col367": "yhmg3", + "col368": "kqsdd", + "col369": "s6z85", + "col370": "rkv17", + "col371": "ohy10", + "col372": "njw9d", + "col373": "fc0zh", + "col374": "vr4wm", + "col375": "8283c", + "col376": "hxfv0", + "col377": "2cqhj", + "col378": "s7szt", + "col379": "4i66i", + "col380": "33rje", + "col381": "tycki", + "col382": "f8sxm", + "col383": "sb00g", + "col384": "96i1u", + "col385": "e7h6y", + "col386": "ozbho", + "col387": "kexf2", + "col388": "ozfru", + "col389": "1z6fa", + "col390": "muxqx", + "col391": "54sl6", + "col392": "5pkvz", + "col393": "xbsx7", + "col394": "lurwg", + "col395": "9z92o", + "col396": "73725", + "col397": "vpo04", + "col398": "6ff23", + "col399": "oz7li", + "col400": "92szt", + "col401": "t6i5w", + "col402": "fykyo", + "col403": "zs68n", + "col404": "4fc0w", + "col405": "pr2v3", + "col406": "imvcx", + "col407": "ipp3x", + "col408": "73ick", + "col409": "pnm0h", + "col410": "lrtwn", + "col411": "6nvqg", + "col412": "6pyj8", + "col413": "rio95", + "col414": "kbv8y", + "col415": "abrm7", + "col416": "b337v", + "col417": "pd05l", + "col418": "rn6cl", + "col419": "xkea7", + "col420": "nam0l", + "col421": "famb4", + "col422": "0hxv6", + "col423": "nvgxu", + "col424": "gtoqk", + "col425": "wydzn", + "col426": "5us63", + "col427": "m0auk", + "col428": "7dejd", + "col429": "kglsx", + "col430": "cnkoy", + "col431": "c4x3d", + "col432": "7fg6f", + "col433": "023rx", + "col434": "1zm7n", + "col435": "s9jtb", + "col436": "5a84k", + "col437": "3ywmg", + "col438": "r34jc", + "col439": "6fnu2", + "col440": "051hq", + "col441": "gaz4a", + "col442": "tozqp", + "col443": "i3ckl", + "col444": "q2551", + "col445": "chahw", + "col446": "ppz1r", + "col447": "tr6cb", + "col448": "leqgh", + "col449": "kd5ws", + "col450": "81xwb", + "col451": "0ntk9", + "col452": "7igih", + "col453": "d3aix", + "col454": "qkt9q", + "col455": "3ktk6", + "col456": "z5jc9", + "col457": "9f2ig", + "col458": "dy9mg", + "col459": "ozl11", + "col460": "oefg1", + "col461": "xm7j8", + "col462": "xb2r2", + "col463": "prrpv", + "col464": "vf7hk", + "col465": "lbhed", + "col466": "m9a4j", + "col467": "zafuj", + "col468": "ozhmi", + "col469": "g5sit", + "col470": "itu11", + "col471": "lapd9", + "col472": "lmylk", + "col473": "moxn2", + "col474": "440ou", + "col475": "zjku6", + "col476": "t8xmx", + "col477": "0hcu1", + "col478": "73vhx", + "col479": "2tckg", + "col480": "yh1nr", + "col481": "2l3ix", + "col482": "s8zrl", + "col483": "xc6e2", + "col484": "vbrmt", + "col485": "sbvcc", + "col486": "ptwv4", + "col487": "s7qt5", + "col488": "9erlx", + "col489": "nvx5p", + "col490": "1jv5g", + "col491": "l0adu", + "col492": "pmt1e", + "col493": "a3tlm", + "col494": "gyf31", + "col495": "b3jwb", + "col496": "bym0r", + "col497": "y2op2", + "col498": "utaoo", + "col499": "fve7k", + "col500": "k3l8s", + "col501": "y8rzu", + "col502": "sojav", + "col503": "48ku6", + "col504": "deiu9", + "col505": "bg6sh", + "col506": "g61mb", + "col507": "hgybl", + "col508": "okyp6", + "col509": "03jl6", + "col510": "bzq5v", + "col511": "elwea", + "col512": "z7sxq", + "col513": "hc14r", + "col514": "3lzsq", + "col515": "ud38r", + "col516": "c3noz", + "col517": "phgzu", + "col518": "iecnx", + "col519": "4vq6l", + "col520": "v552e", + "col521": "purew", + "col522": "nlmt9", + "col523": "z0y7j", + "col524": "xsksy", + "col525": "ndnx1", + "col526": "vlcjy", + "col527": "g913v", + "col528": "fv7wf", + "col529": "soij2", + "col530": "rl185", + "col531": "ehzjl", + "col532": "ioz63", + "col533": "czg2l", + "col534": "w9yn1", + "col535": "i8lvi", + "col536": "mrcy1", + "col537": "69leq", + "col538": "fvqbn", + "col539": "gfxy2", + "col540": "xj873", + "col541": "dzknz", + "col542": "f7spa", + "col543": "xhzwh", + "col544": "lqudc", + "col545": "sj5g9", + "col546": "90or5", + "col547": "053m0", + "col548": "spcjs", + "col549": "xq4od", + "col550": "g03rx", + "col551": "xvggx", + "col552": "hlyva", + "col553": "2559h", + "col554": "pnzsu", + "col555": "2mt0e", + "col556": "o5yl5", + "col557": "mslcg", + "col558": "ustuk", + "col559": "vcmwr", + "col560": "w9e6y", + "col561": "ub0n8", + "col562": "5zfe7", + "col563": "6mmtx", + "col564": "9jtiu", + "col565": "iyjpq", + "col566": "3xzv7", + "col567": "9kc1g", + "col568": "oojak", + "col569": "znjzk", + "col570": "vjad1", + "col571": "h8ylz", + "col572": "85wrs", + "col573": "3vd79", + "col574": "dkxus", + "col575": "f5kbd", + "col576": "xkb8r", + "col577": "upuxz", + "col578": "77qfh", + "col579": "jklc5", + "col580": "7og6k", + "col581": "zrx7y", + "col582": "uokri", + "col583": "tcfjs", + "col584": "1r5ur", + "col585": "8e0c0", + "col586": "v2e58", + "col587": "kjjak", + "col588": "0d2hq", + "col589": "hhl8z", + "col590": "e05m1", + "col591": "du22c", + "col592": "jru4n", + "col593": "qd34q", + "col594": "wbj8c", + "col595": "4ie7p", + "col596": "rltv4", + "col597": "vpaad", + "col598": "yx936", + "col599": "shzdc", + "col600": "6icl1", + "col601": "dkwgb", + "col602": "gr95z", + "col603": "yib14", + "col604": "0vrv1", + "col605": "i10e0", + "col606": "bjnmu", + "col607": "awz67", + "col608": "kxknv", + "col609": "qz0nb", + "col610": "kbwku", + "col611": "1s1xr", + "col612": "d0w1v", + "col613": "ws3tf", + "col614": "ocjr3", + "col615": "x9nyl", + "col616": "2wqaw", + "col617": "a4s3f", + "col618": "9das9", + "col619": "b43vx", + "col620": "cxtad", + "col621": "z2pc9", + "col622": "1l4is", + "col623": "dique", + "col624": "oqdqk", + "col625": "5sbfe", + "col626": "wjbw2", + "col627": "150l8", + "col628": "f0wty", + "col629": "cvw5h", + "col630": "g2sxf", + "col631": "gsedk", + "col632": "suckk", + "col633": "vxk2i", + "col634": "5lett", + "col635": "negn9", + "col636": "8aiup", + "col637": "tgebt", + "col638": "s28zt", + "col639": "ugm8o", + "col640": "3zbk2", + "col641": "3sxz9", + "col642": "rqvfl", + "col643": "e5w21", + "col644": "lnk6g", + "col645": "xu0o6", + "col646": "wednn", + "col647": "4hjv6", + "col648": "72bph", + "col649": "fi5rp", + "col650": "buk1g", + "col651": "tkzz6", + "col652": "6vvpi", + "col653": "b62oi", + "col654": "n2g0d", + "col655": "b0xci", + "col656": "s83eb", + "col657": "qwk1n", + "col658": "mn08l", + "col659": "1eyq6", + "col660": "kc9wz", + "col661": "is6yq", + "col662": "hc358", + "col663": "lm5jm", + "col664": "8jy2q", + "col665": "yt2i6", + "col666": "d1jjo", + "col667": "2bqlo", + "col668": "i2dab", + "col669": "ul1nw", + "col670": "k4z7a", + "col671": "xj1y4", + "col672": "z6tel", + "col673": "9o639", + "col674": "887lf", + "col675": "qoaoh", + "col676": "7cwzv", + "col677": "4dw01", + "col678": "k4vkb", + "col679": "70mg1", + "col680": "s5mtx", + "col681": "1qlov", + "col682": "xfrc0", + "col683": "9rr3l", + "col684": "c0aa1", + "col685": "ke987", + "col686": "1kst8", + "col687": "qbbhq", + "col688": "7xkcm", + "col689": "cmas4", + "col690": "0tgig", + "col691": "hzlma", + "col692": "jgeho", + "col693": "vsk0p", + "col694": "jg8a6", + "col695": "upvc5", + "col696": "y9eaz", + "col697": "r7fl7", + "col698": "c3zd5", + "col699": "snqwy", + "col700": "sk5bs", + "col701": "ysi1i", + "col702": "fj36w", + "col703": "y983r", + "col704": "m768e", + "col705": "ma8a0", + "col706": "o8zdi", + "col707": "g180t", + "col708": "1ey3c", + "col709": "0xlbo", + "col710": "6aw01", + "col711": "e8sps", + "col712": "568ug", + "col713": "yhn5h", + "col714": "vff6u", + "col715": "dm87l", + "col716": "raasm", + "col717": "6rbuw", + "col718": "qt6lu", + "col719": "hb2gm", + "col720": "ifvbz", + "col721": "jhzmz", + "col722": "6xl7o", + "col723": "2kslj", + "col724": "vklr7", + "col725": "z250k", + "col726": "w5ucg", + "col727": "w377o", + "col728": "fq3xl", + "col729": "9f359", + "col730": "vzjwi", + "col731": "vy085", + "col732": "nuhyr", + "col733": "p78bo", + "col734": "15cuz", + "col735": "dnpct", + "col736": "0lz1m", + "col737": "6jxz0", + "col738": "0w5d6", + "col739": "8eh5o", + "col740": "pm6j7", + "col741": "lxm8u", + "col742": "88bxs", + "col743": "4wjq5", + "col744": "hw2ai", + "col745": "6af8x", + "col746": "rk2y7", + "col747": "1z8s4", + "col748": "f6h42", + "col749": "ppang", + "col750": "fqhw8", + "col751": "uwewh", + "col752": "cpj0i", + "col753": "y9lhh", + "col754": "ek8r3", + "col755": "g85ve", + "col756": "mek8k", + "col757": "3vyqm", + "col758": "uolxc", + "col759": "uhozq", + "col760": "0uwwh", + "col761": "zpzaw", + "col762": "m3xxg", + "col763": "bkm79", + "col764": "9xpm0", + "col765": "ptx6z", + "col766": "um3eq", + "col767": "8etr4", + "col768": "nob3w", + "col769": "lecam", + "col770": "fhdil", + "col771": "fcww3", + "col772": "y5536", + "col773": "mbg23", + "col774": "4f9v7", + "col775": "rvv07", + "col776": "vcsn0", + "col777": "3qyoa", + "col778": "io516", + "col779": "fdww8", + "col780": "zf8a0", + "col781": "p4l5h", + "col782": "wcidc", + "col783": "72fpd", + "col784": "jw9x9", + "col785": "puske", + "col786": "2130v", + "col787": "r9jnr", + "col788": "un3wd", + "col789": "j8pc0", + "col790": "13sys", + "col791": "0460z", + "col792": "k7uxu", + "col793": "1ziwq", + "col794": "jp4me", + "col795": "pxtka", + "col796": "0n4i3", + "col797": "l6jf8", + "col798": "z61hi", + "col799": "0q0ky", + "col800": "t6bsi", + "col801": "cuw05", + "col802": "22cc5", + "col803": "24iff", + "col804": "prnkc", + "col805": "sm5d4", + "col806": "lct9q", + "col807": "ie97x", + "col808": "2yf96", + "col809": "2pq0z", + "col810": "euw1y", + "col811": "eclss", + "col812": "0tqup", + "col813": "z2ogh", + "col814": "0pxpj", + "col815": "u0og8", + "col816": "xlwob", + "col817": "fri1e", + "col818": "ky6ve", + "col819": "s1f1k", + "col820": "kxx7j", + "col821": "mdxhy", + "col822": "2z7rz", + "col823": "bucgg", + "col824": "q6r4t", + "col825": "wyqcm", + "col826": "z3uur", + "col827": "0t2bo", + "col828": "slly8", + "col829": "svafe", + "col830": "d179w", + "col831": "uz225", + "col832": "u0pqb", + "col833": "g2xih", + "col834": "ppswu", + "col835": "4w269", + "col836": "aeoux", + "col837": "iv69c", + "col838": "j4d3w", + "col839": "ljdqp", + "col840": "0900p", + "col841": "oleca", + "col842": "8isy8", + "col843": "3hpju", + "col844": "n5fgl", + "col845": "xiiq5", + "col846": "ei3sx", + "col847": "r095p", + "col848": "wf4za", + "col849": "5kxkr", + "col850": "9jgoe", + "col851": "hzmv4", + "col852": "yfowa", + "col853": "qot6g", + "col854": "7pykn", + "col855": "sp44f", + "col856": "7gmsc", + "col857": "ci0s1", + "col858": "sjvcb", + "col859": "aazop", + "col860": "kf3bt", + "col861": "t71oa", + "col862": "n310m", + "col863": "6liwo", + "col864": "y3h2o", + "col865": "4pmjq", + "col866": "ywgxe", + "col867": "mzwfp", + "col868": "w78vc", + "col869": "6cdf2", + "col870": "27wox", + "col871": "hwrtj", + "col872": "9elli", + "col873": "mqy86", + "col874": "0m8p3", + "col875": "ljg3p", + "col876": "gt1s8", + "col877": "j6abs", + "col878": "k3vaz", + "col879": "37zb4", + "col880": "eu0lm", + "col881": "sacow", + "col882": "rsa3c", + "col883": "np9o3", + "col884": "s268t", + "col885": "w8far", + "col886": "ak7tj", + "col887": "1ffmv", + "col888": "5vlbn", + "col889": "iq3d2", + "col890": "gri82", + "col891": "ewjxz", + "col892": "pwgp3", + "col893": "ktiu1", + "col894": "1z7vt", + "col895": "ft6n0", + "col896": "sxmqz", + "col897": "shuny", + "col898": "wjde5", + "col899": "ezzgr", + "col900": "b7l6h", + "col901": "689op", + "col902": "370vz", + "col903": "c7nw3", + "col904": "sncct", + "col905": "xspsg", + "col906": "twhrf", + "col907": "dr4zb", + "col908": "x2e8a", + "col909": "y6667", + "col910": "vsr56", + "col911": "0vgy5", + "col912": "0o2el", + "col913": "zj0y8", + "col914": "495o3", + "col915": "kwwt1", + "col916": "7u2ad", + "col917": "1tpk4", + "col918": "backs", + "col919": "h8t9t", + "col920": "obtwg", + "col921": "95apt", + "col922": "xquji", + "col923": "6vw9u", + "col924": "3xkaz", + "col925": "vhct8", + "col926": "ea0ve", + "col927": "6lomg", + "col928": "83b47", + "col929": "4jxam", + "col930": "8es9d", + "col931": "9r01f", + "col932": "3o9ju", + "col933": "kjjiy", + "col934": "7s3nx", + "col935": "7ljok", + "col936": "4haq2", + "col937": "spr76", + "col938": "qck14", + "col939": "5rb56", + "col940": "z3qry", + "col941": "95boq", + "col942": "fszkg", + "col943": "2k42c", + "col944": "ro751", + "col945": "960ao", + "col946": "7k87g", + "col947": "8tdbu", + "col948": "4w1ia", + "col949": "e3bpq", + "col950": "ixjcw", + "col951": "i8d6n", + "col952": "y6vfg", + "col953": "3xaa1", + "col954": "7fp97", + "col955": "pa0b2", + "col956": "5dfb1", + "col957": "lsa26", + "col958": "idrbr", + "col959": "lp8qi", + "col960": "t89l5", + "col961": "0a96k", + "col962": "g4owv", + "col963": "arysc", + "col964": "k8xdn", + "col965": "tkqxf", + "col966": "f7j44", + "col967": "7ttm1", + "col968": "0bvmi", + "col969": "cs10t", + "col970": "h2kki", + "col971": "kufy8", + "col972": "o89vr", + "col973": "browd", + "col974": "mfzva", + "col975": "st5cw", + "col976": "ponbf", + "col977": "n77hr", + "col978": "pixfo", + "col979": "nc4tx", + "col980": "ewawv", + "col981": "nogas", + "col982": "bfl84", + "col983": "1r1nv", + "col984": "wqgbc", + "col985": "dkjsq", + "col986": "idgrs", + "col987": "srqv0", + "col988": "ydus2", + "col989": "r69ix", + "col990": "vx8k2", + "col991": "wxa9m", + "col992": "gfebn", + "col993": "tb1kn", + "col994": "p6koz", + "col995": "vffij", + "col996": "0zhlq", + "col997": "jp83o", + "col998": "tt7kl", + "col999": "x27nn" + }, + { + "name": "Faye Washington", + "gender": "female", + "col0": "7rhfq", + "col1": "ytssg", + "col2": "bo4fg", + "col3": "nmz7c", + "col4": "g7ur4", + "col5": "yal37", + "col6": "cjzf2", + "col7": "rnbom", + "col8": "twf0k", + "col9": "wzc7q", + "col10": "sbtsq", + "col11": "jmu2h", + "col12": "grhte", + "col13": "k6cku", + "col14": "hbyg4", + "col15": "ipy5l", + "col16": "95bof", + "col17": "8q6q1", + "col18": "tcd68", + "col19": "e2ghc", + "col20": "ohmj4", + "col21": "n995e", + "col22": "u4lva", + "col23": "ivkzc", + "col24": "9dei6", + "col25": "p89m3", + "col26": "lq9so", + "col27": "4p8k9", + "col28": "d7lj4", + "col29": "xxf3f", + "col30": "sisab", + "col31": "e8xal", + "col32": "pk1uu", + "col33": "zf6lq", + "col34": "0cwdo", + "col35": "ndh2b", + "col36": "8y7ez", + "col37": "ahjvn", + "col38": "hw38z", + "col39": "hvryv", + "col40": "pxhl6", + "col41": "r27sl", + "col42": "0e42s", + "col43": "gbjqi", + "col44": "th7g1", + "col45": "9ufin", + "col46": "i29mr", + "col47": "sj3ns", + "col48": "tswsp", + "col49": "n2k3z", + "col50": "kdfmb", + "col51": "kyu0z", + "col52": "83dhf", + "col53": "2o6to", + "col54": "4erqs", + "col55": "a1tv6", + "col56": "07pne", + "col57": "ogz8u", + "col58": "74t62", + "col59": "38i6z", + "col60": "ocfxr", + "col61": "seopy", + "col62": "bqr9x", + "col63": "hbuj5", + "col64": "776db", + "col65": "rswny", + "col66": "uyaye", + "col67": "ilf32", + "col68": "0r5vz", + "col69": "tvf6j", + "col70": "50kpw", + "col71": "c2sz5", + "col72": "xurq3", + "col73": "cnekp", + "col74": "rn6gg", + "col75": "j48pb", + "col76": "i6xrf", + "col77": "o01ig", + "col78": "2yt9a", + "col79": "7gq30", + "col80": "r1kok", + "col81": "lhp6v", + "col82": "naolw", + "col83": "qzg56", + "col84": "7dw9g", + "col85": "5qeal", + "col86": "g0bnk", + "col87": "f2gb4", + "col88": "bcjx3", + "col89": "glwaz", + "col90": "8nu6g", + "col91": "ewkv9", + "col92": "06w08", + "col93": "64o8g", + "col94": "1qlvi", + "col95": "qffnb", + "col96": "dp5xx", + "col97": "cvoqs", + "col98": "o7638", + "col99": "hjtat", + "col100": "0e9w5", + "col101": "oha8s", + "col102": "vba4d", + "col103": "di5cy", + "col104": "hdt0u", + "col105": "buphf", + "col106": "ibzo1", + "col107": "ulkss", + "col108": "0py41", + "col109": "7tstg", + "col110": "m95g0", + "col111": "d6szx", + "col112": "4uemm", + "col113": "05dtu", + "col114": "6hzxe", + "col115": "wlmhs", + "col116": "iq2i0", + "col117": "bo19l", + "col118": "wk9yf", + "col119": "o43m7", + "col120": "0599a", + "col121": "q5n5p", + "col122": "ro439", + "col123": "blfud", + "col124": "b3tvb", + "col125": "eitw0", + "col126": "165zc", + "col127": "q84wz", + "col128": "mnv31", + "col129": "3cv8x", + "col130": "5tutm", + "col131": "f05z5", + "col132": "dpgc2", + "col133": "vbceo", + "col134": "4m1re", + "col135": "wd7e8", + "col136": "06yhu", + "col137": "p6s56", + "col138": "n7rl3", + "col139": "kya1q", + "col140": "o8944", + "col141": "9aegp", + "col142": "xxwlg", + "col143": "cye68", + "col144": "3igvq", + "col145": "ovg6q", + "col146": "t6lxs", + "col147": "dlyzo", + "col148": "u4r70", + "col149": "bxvah", + "col150": "7wwlj", + "col151": "halg8", + "col152": "gqmop", + "col153": "hea49", + "col154": "6odnr", + "col155": "3km6o", + "col156": "gab7t", + "col157": "fvnuu", + "col158": "hldnc", + "col159": "riu80", + "col160": "36voi", + "col161": "hdl4b", + "col162": "vnoff", + "col163": "ijt3k", + "col164": "xgt3e", + "col165": "8ymus", + "col166": "x6q1y", + "col167": "rk0ow", + "col168": "g8djp", + "col169": "pxkf3", + "col170": "s8rin", + "col171": "eul26", + "col172": "ia2nb", + "col173": "wafy0", + "col174": "v7auw", + "col175": "blohl", + "col176": "h0jpp", + "col177": "s4od5", + "col178": "k22gk", + "col179": "7cino", + "col180": "v7a6q", + "col181": "x4bu6", + "col182": "n4hzt", + "col183": "my5xs", + "col184": "tof0p", + "col185": "qw3v3", + "col186": "pqtfs", + "col187": "5serv", + "col188": "of8r1", + "col189": "fc3g7", + "col190": "8jle5", + "col191": "wdng9", + "col192": "m1jjr", + "col193": "f2c01", + "col194": "wbyqk", + "col195": "b7fle", + "col196": "q7qu2", + "col197": "jript", + "col198": "y5mih", + "col199": "92mg8", + "col200": "8dsgk", + "col201": "am8au", + "col202": "d4nz2", + "col203": "q05z8", + "col204": "2s5z0", + "col205": "0xphz", + "col206": "kven4", + "col207": "52d0e", + "col208": "x17zj", + "col209": "xymwj", + "col210": "dej93", + "col211": "jqkka", + "col212": "0upvs", + "col213": "4ciob", + "col214": "zomys", + "col215": "m0fc3", + "col216": "wdyp5", + "col217": "wd2ph", + "col218": "kkufc", + "col219": "za7x3", + "col220": "om1tx", + "col221": "73j3b", + "col222": "sxwey", + "col223": "7jda9", + "col224": "h7vlj", + "col225": "jijl9", + "col226": "0ii33", + "col227": "d35db", + "col228": "tqo91", + "col229": "8wljj", + "col230": "8ryta", + "col231": "1onx8", + "col232": "vefww", + "col233": "1kj7i", + "col234": "7rflz", + "col235": "dhyer", + "col236": "7j6ug", + "col237": "74cyu", + "col238": "drdlj", + "col239": "9tsh3", + "col240": "dysdx", + "col241": "n6c4o", + "col242": "f40b3", + "col243": "ocyk6", + "col244": "82q5h", + "col245": "ouhsv", + "col246": "z30oo", + "col247": "ghp9o", + "col248": "3rop1", + "col249": "av08t", + "col250": "r5dmu", + "col251": "vmr90", + "col252": "9z76h", + "col253": "86973", + "col254": "f2gny", + "col255": "qq8qp", + "col256": "f2kih", + "col257": "siycz", + "col258": "upe6q", + "col259": "ee9hr", + "col260": "keplp", + "col261": "uixut", + "col262": "3b3lk", + "col263": "69uqy", + "col264": "zgfzz", + "col265": "bz7z9", + "col266": "qe5xm", + "col267": "yousq", + "col268": "oxw1j", + "col269": "av8v6", + "col270": "rxqf8", + "col271": "h8l61", + "col272": "j1262", + "col273": "3axk0", + "col274": "s99sv", + "col275": "wkqji", + "col276": "nj40x", + "col277": "r4wrq", + "col278": "4df7b", + "col279": "0qth6", + "col280": "z9l8d", + "col281": "bu8al", + "col282": "3fo5x", + "col283": "37rl7", + "col284": "ucs5r", + "col285": "xwamk", + "col286": "q92de", + "col287": "fhdof", + "col288": "rm8ew", + "col289": "tjvyt", + "col290": "q1hy4", + "col291": "ye6ce", + "col292": "okwek", + "col293": "86zbs", + "col294": "zjvx9", + "col295": "sjzvu", + "col296": "chkz7", + "col297": "uh2fm", + "col298": "ei6nj", + "col299": "f945v", + "col300": "9mc4i", + "col301": "05cxr", + "col302": "iqkbv", + "col303": "z1vow", + "col304": "dme7n", + "col305": "y345d", + "col306": "skr9g", + "col307": "51egg", + "col308": "wa1tn", + "col309": "ltc3s", + "col310": "wxqwi", + "col311": "50u5z", + "col312": "4fvqe", + "col313": "ub0gh", + "col314": "iaw2r", + "col315": "dmtox", + "col316": "0r644", + "col317": "shkej", + "col318": "9puw9", + "col319": "knjdf", + "col320": "xmcnj", + "col321": "72qt7", + "col322": "qtbqo", + "col323": "28s0s", + "col324": "x9xcr", + "col325": "vs7ro", + "col326": "a2tju", + "col327": "37wvm", + "col328": "9j1m9", + "col329": "rk5lr", + "col330": "zi3v1", + "col331": "pjozm", + "col332": "jq4kh", + "col333": "zer6m", + "col334": "8yl81", + "col335": "64ijm", + "col336": "bt4t3", + "col337": "bpjvb", + "col338": "6ikkn", + "col339": "7xpja", + "col340": "g9pag", + "col341": "8zfjk", + "col342": "2wytc", + "col343": "xdnuv", + "col344": "l36ve", + "col345": "tw58f", + "col346": "ymhxx", + "col347": "yhnr3", + "col348": "w42h5", + "col349": "ii5ci", + "col350": "3dgw0", + "col351": "bwtyw", + "col352": "v1ihv", + "col353": "6ulnp", + "col354": "x37y9", + "col355": "vv70d", + "col356": "l8odf", + "col357": "117dh", + "col358": "k90cw", + "col359": "kz2nt", + "col360": "nw28x", + "col361": "31eyg", + "col362": "pi09o", + "col363": "wdnq4", + "col364": "dcscs", + "col365": "zzfqr", + "col366": "fip8e", + "col367": "ld3ym", + "col368": "su3ol", + "col369": "sa8t1", + "col370": "hi38j", + "col371": "5oadb", + "col372": "maie0", + "col373": "spqy7", + "col374": "irmri", + "col375": "6jioh", + "col376": "r35rr", + "col377": "gbkks", + "col378": "vwhbh", + "col379": "2kwwx", + "col380": "469u5", + "col381": "sw0he", + "col382": "2k4vp", + "col383": "zgw0w", + "col384": "ksdqk", + "col385": "8hydq", + "col386": "fcwqo", + "col387": "w70lh", + "col388": "4b2p0", + "col389": "aqb13", + "col390": "1se8u", + "col391": "nklak", + "col392": "mwm1c", + "col393": "lasm0", + "col394": "5zc4x", + "col395": "8d2zw", + "col396": "sh2ek", + "col397": "2v0hx", + "col398": "ziqfu", + "col399": "vsg2d", + "col400": "78bzj", + "col401": "71cmp", + "col402": "sfb81", + "col403": "rkoux", + "col404": "17e13", + "col405": "rnh34", + "col406": "jzc7a", + "col407": "yewlo", + "col408": "o8y3g", + "col409": "payx3", + "col410": "qdk14", + "col411": "p9vzh", + "col412": "j1uqz", + "col413": "qz4yl", + "col414": "pljaq", + "col415": "mdnzf", + "col416": "kao9s", + "col417": "dm6lu", + "col418": "p1sc2", + "col419": "ozv4f", + "col420": "j040k", + "col421": "f40vl", + "col422": "4reu0", + "col423": "c1z5r", + "col424": "apkm3", + "col425": "sk0dy", + "col426": "82jpg", + "col427": "05ei4", + "col428": "oytdn", + "col429": "a0x1h", + "col430": "jqp9v", + "col431": "vnx0e", + "col432": "d87s2", + "col433": "dk0xd", + "col434": "gi2w0", + "col435": "azpkb", + "col436": "8j3ou", + "col437": "3r5g6", + "col438": "266di", + "col439": "af7fy", + "col440": "4i1pc", + "col441": "9x02w", + "col442": "ez44b", + "col443": "zed34", + "col444": "5bemf", + "col445": "qbw0s", + "col446": "c2hf0", + "col447": "t2xcz", + "col448": "2hkcv", + "col449": "llxio", + "col450": "ejodg", + "col451": "onttv", + "col452": "271z2", + "col453": "dczsq", + "col454": "6j2es", + "col455": "i8rdw", + "col456": "xx25z", + "col457": "kuni1", + "col458": "vc9yp", + "col459": "vbgi9", + "col460": "dogop", + "col461": "1zccl", + "col462": "9kpwh", + "col463": "6dmzj", + "col464": "0cxky", + "col465": "zcnaj", + "col466": "jkhco", + "col467": "6cpys", + "col468": "thl5s", + "col469": "1uvwi", + "col470": "0xag0", + "col471": "uuamv", + "col472": "ejrio", + "col473": "7xnq3", + "col474": "oeagh", + "col475": "zm63l", + "col476": "4f7x3", + "col477": "j1mom", + "col478": "ke17s", + "col479": "4i6sx", + "col480": "qvtzj", + "col481": "jorzg", + "col482": "emy3h", + "col483": "oc9v2", + "col484": "o5km5", + "col485": "0kai5", + "col486": "4cs9x", + "col487": "olooi", + "col488": "7u2o4", + "col489": "7vfl5", + "col490": "0w2hn", + "col491": "m6m65", + "col492": "e1evn", + "col493": "4jakk", + "col494": "ir0ni", + "col495": "53pfy", + "col496": "xifwt", + "col497": "va5zr", + "col498": "cchbv", + "col499": "f2zu4", + "col500": "awpuf", + "col501": "w1um4", + "col502": "irlkw", + "col503": "xfmxf", + "col504": "3phsn", + "col505": "9vkx3", + "col506": "14xfj", + "col507": "yo5il", + "col508": "0m89l", + "col509": "6fgas", + "col510": "cxgnk", + "col511": "h5ytm", + "col512": "jd5k3", + "col513": "8rl4n", + "col514": "n85m3", + "col515": "ym7x1", + "col516": "ijdgz", + "col517": "3i2nd", + "col518": "vn34h", + "col519": "wj7e8", + "col520": "xjcby", + "col521": "a2tsw", + "col522": "to6h3", + "col523": "pwotx", + "col524": "4rnbu", + "col525": "9y7se", + "col526": "9gk1v", + "col527": "b9zva", + "col528": "65dv8", + "col529": "ombzv", + "col530": "81smz", + "col531": "b40wa", + "col532": "shv4w", + "col533": "p24nx", + "col534": "js9yi", + "col535": "gr8kt", + "col536": "dnjyi", + "col537": "z63p6", + "col538": "htuqw", + "col539": "lkdbg", + "col540": "zewp0", + "col541": "pawjv", + "col542": "w00bd", + "col543": "mrnhh", + "col544": "5rfxa", + "col545": "oubli", + "col546": "b2v60", + "col547": "lz2a8", + "col548": "10662", + "col549": "0usi8", + "col550": "ftl30", + "col551": "qshz8", + "col552": "fyvoc", + "col553": "ap5ql", + "col554": "1d73d", + "col555": "tjpyl", + "col556": "af3uy", + "col557": "d02f8", + "col558": "w6x7o", + "col559": "h2eo0", + "col560": "xvq0i", + "col561": "lymwb", + "col562": "v05mk", + "col563": "62m2t", + "col564": "ba7if", + "col565": "k5ye6", + "col566": "nitux", + "col567": "elnrf", + "col568": "a208a", + "col569": "8uj38", + "col570": "ycs7j", + "col571": "c23vw", + "col572": "klquf", + "col573": "qqd7o", + "col574": "9uv5w", + "col575": "8pmv2", + "col576": "be76q", + "col577": "mgzss", + "col578": "vlusx", + "col579": "mgw1k", + "col580": "kjksi", + "col581": "zlv6g", + "col582": "xngt9", + "col583": "4vqqs", + "col584": "4ezim", + "col585": "nzjc7", + "col586": "dljqn", + "col587": "nurmx", + "col588": "42c6i", + "col589": "kpba0", + "col590": "wx9pm", + "col591": "ibhzx", + "col592": "cfsaa", + "col593": "lpxyc", + "col594": "qf28b", + "col595": "dklh3", + "col596": "i9317", + "col597": "vjhq5", + "col598": "1e81i", + "col599": "wdf7e", + "col600": "u6l2f", + "col601": "uljkt", + "col602": "e29ix", + "col603": "tybpk", + "col604": "sc3x4", + "col605": "4er5p", + "col606": "25ea9", + "col607": "02uvp", + "col608": "th5be", + "col609": "b7csv", + "col610": "yon1t", + "col611": "ksrwq", + "col612": "t15jn", + "col613": "e2ws6", + "col614": "ibqwq", + "col615": "to96c", + "col616": "mbi5s", + "col617": "7bt7f", + "col618": "70wg4", + "col619": "b2r9y", + "col620": "dq38w", + "col621": "meo48", + "col622": "9ul0v", + "col623": "0xuo3", + "col624": "smuam", + "col625": "y7zy7", + "col626": "d0bwk", + "col627": "xpszh", + "col628": "ay566", + "col629": "me3em", + "col630": "v2sb2", + "col631": "j8iuq", + "col632": "nwpbg", + "col633": "29qcu", + "col634": "5951f", + "col635": "4q5ds", + "col636": "hem0o", + "col637": "1hwpg", + "col638": "3cz65", + "col639": "d8w07", + "col640": "ol5cj", + "col641": "pnm5b", + "col642": "qnbri", + "col643": "fz79s", + "col644": "4ofbh", + "col645": "r1kef", + "col646": "ur19x", + "col647": "t5abt", + "col648": "1mqn4", + "col649": "zfea6", + "col650": "r31mw", + "col651": "yic4i", + "col652": "opdbj", + "col653": "17k6j", + "col654": "96uke", + "col655": "jvla5", + "col656": "boch3", + "col657": "fzvvk", + "col658": "6vmo0", + "col659": "idr5i", + "col660": "f195e", + "col661": "lr1jz", + "col662": "37osr", + "col663": "irk9h", + "col664": "srrpk", + "col665": "60u2p", + "col666": "79rrr", + "col667": "a3cgv", + "col668": "2ut0w", + "col669": "4ixqz", + "col670": "bkr0g", + "col671": "8bdul", + "col672": "ps122", + "col673": "8fnni", + "col674": "ucche", + "col675": "fgty8", + "col676": "js2o9", + "col677": "lpf30", + "col678": "9g3n7", + "col679": "zoqzc", + "col680": "e64qa", + "col681": "ir5d4", + "col682": "3jljz", + "col683": "clmdq", + "col684": "t7vpx", + "col685": "x2ij9", + "col686": "o79aw", + "col687": "zq8d3", + "col688": "q0gty", + "col689": "x7q0b", + "col690": "wpao5", + "col691": "ojys4", + "col692": "wf94r", + "col693": "y54pj", + "col694": "r2pri", + "col695": "6n5gg", + "col696": "uao2n", + "col697": "usb6s", + "col698": "6wbt0", + "col699": "nuyr5", + "col700": "jnz6z", + "col701": "ku34g", + "col702": "gquyc", + "col703": "ksqfv", + "col704": "hdeb3", + "col705": "t4tjk", + "col706": "bi9pb", + "col707": "2wjnt", + "col708": "gpgk3", + "col709": "i3reu", + "col710": "ysoa7", + "col711": "avmrn", + "col712": "2w2jo", + "col713": "96ynd", + "col714": "yj9sx", + "col715": "xiv9s", + "col716": "fug5f", + "col717": "71pbo", + "col718": "lgu8v", + "col719": "82c0u", + "col720": "j7lp0", + "col721": "sry8i", + "col722": "ilish", + "col723": "dgvq6", + "col724": "tgpez", + "col725": "hmxr5", + "col726": "9p8dm", + "col727": "hwvoi", + "col728": "78uwe", + "col729": "jocg8", + "col730": "9cn4k", + "col731": "40tv4", + "col732": "9spms", + "col733": "lris3", + "col734": "krq8t", + "col735": "idm5s", + "col736": "n5ixg", + "col737": "kvec3", + "col738": "sts80", + "col739": "rgway", + "col740": "znhkh", + "col741": "zovqq", + "col742": "i3jnr", + "col743": "ckvfr", + "col744": "lvsf3", + "col745": "w6tcw", + "col746": "irr9a", + "col747": "bnr54", + "col748": "v12fn", + "col749": "bzl85", + "col750": "2dv2q", + "col751": "p7tco", + "col752": "8alh1", + "col753": "6ic69", + "col754": "0f2w6", + "col755": "oecwo", + "col756": "6ouxw", + "col757": "fdf5a", + "col758": "jq5vk", + "col759": "hikvo", + "col760": "erwq2", + "col761": "hatzn", + "col762": "g1rh9", + "col763": "niit9", + "col764": "4dpq9", + "col765": "1a4jy", + "col766": "whtrf", + "col767": "qierr", + "col768": "fx6cf", + "col769": "8vepi", + "col770": "enywk", + "col771": "dbi96", + "col772": "kpjxo", + "col773": "ue3wm", + "col774": "pnov6", + "col775": "9u0vt", + "col776": "c6594", + "col777": "gz4ih", + "col778": "9nfsj", + "col779": "za9py", + "col780": "j216g", + "col781": "r5vus", + "col782": "wuw25", + "col783": "ojlyw", + "col784": "6p3gs", + "col785": "aau7j", + "col786": "ef6em", + "col787": "5xvhq", + "col788": "b9gfh", + "col789": "17i21", + "col790": "gck0g", + "col791": "p2ugz", + "col792": "mrsh4", + "col793": "zl526", + "col794": "9gr1d", + "col795": "j742e", + "col796": "hogtm", + "col797": "xrwsg", + "col798": "xvuwl", + "col799": "s9i03", + "col800": "if7ud", + "col801": "sq6g6", + "col802": "ezlie", + "col803": "gzyvd", + "col804": "2izdt", + "col805": "shb4c", + "col806": "r3o5e", + "col807": "3tazp", + "col808": "lgee9", + "col809": "jwdid", + "col810": "s4qu2", + "col811": "u16xk", + "col812": "hlw55", + "col813": "hv48q", + "col814": "jh55r", + "col815": "zmgw3", + "col816": "kity8", + "col817": "nqa9w", + "col818": "2z1y5", + "col819": "dydtd", + "col820": "8wp6h", + "col821": "0zy1m", + "col822": "jw3f4", + "col823": "kvpk5", + "col824": "60esj", + "col825": "7rria", + "col826": "5dmf2", + "col827": "1r1c8", + "col828": "sjc1w", + "col829": "qstvm", + "col830": "49pgr", + "col831": "6ikgd", + "col832": "tb9h4", + "col833": "tumq1", + "col834": "p1cgz", + "col835": "tpo72", + "col836": "jdis1", + "col837": "7x8oa", + "col838": "xgjvp", + "col839": "h016i", + "col840": "hps7d", + "col841": "loomj", + "col842": "rlaya", + "col843": "92rtp", + "col844": "wf36z", + "col845": "8z8dn", + "col846": "py643", + "col847": "8d9vq", + "col848": "dvepa", + "col849": "e9517", + "col850": "7ykfu", + "col851": "c5pnm", + "col852": "vpags", + "col853": "um8ab", + "col854": "o8kn8", + "col855": "l23f2", + "col856": "msu66", + "col857": "gfaz6", + "col858": "zqz2e", + "col859": "lto61", + "col860": "1yjfx", + "col861": "dv8pg", + "col862": "wmxwe", + "col863": "wr51j", + "col864": "iiokp", + "col865": "z47i4", + "col866": "rkjn9", + "col867": "jv28g", + "col868": "7tmw6", + "col869": "brdpc", + "col870": "0eane", + "col871": "jhl7d", + "col872": "zkxli", + "col873": "l6wzl", + "col874": "h444i", + "col875": "o5ym1", + "col876": "8eamo", + "col877": "xuaoo", + "col878": "luodf", + "col879": "5yyxd", + "col880": "fdad5", + "col881": "16px4", + "col882": "oj906", + "col883": "9qgps", + "col884": "cluzz", + "col885": "2dml2", + "col886": "pheaf", + "col887": "3520i", + "col888": "vuqtg", + "col889": "828tm", + "col890": "2184m", + "col891": "fjry7", + "col892": "bf6s1", + "col893": "m9dmu", + "col894": "vnufw", + "col895": "4rc9r", + "col896": "p2f2a", + "col897": "76n0o", + "col898": "axxet", + "col899": "rmxu4", + "col900": "r4s8f", + "col901": "pors4", + "col902": "v16bj", + "col903": "rkss9", + "col904": "v6ck8", + "col905": "celgb", + "col906": "42ahu", + "col907": "hidrb", + "col908": "ukwht", + "col909": "o89pm", + "col910": "m0e62", + "col911": "bmjtf", + "col912": "35yfv", + "col913": "45nwc", + "col914": "ea47c", + "col915": "vltas", + "col916": "u801l", + "col917": "4mjgy", + "col918": "5wsqf", + "col919": "cdtvq", + "col920": "lmkia", + "col921": "1yocf", + "col922": "722yd", + "col923": "frk65", + "col924": "55fau", + "col925": "qwdwn", + "col926": "pgy0r", + "col927": "3ibke", + "col928": "cj873", + "col929": "f7620", + "col930": "cfos1", + "col931": "o87j6", + "col932": "pcipm", + "col933": "dxjw9", + "col934": "pkd5v", + "col935": "5wct9", + "col936": "de8qb", + "col937": "7uwc7", + "col938": "9dxmo", + "col939": "q494k", + "col940": "gmnlb", + "col941": "o6atx", + "col942": "etrje", + "col943": "1lndn", + "col944": "odpke", + "col945": "ovdmm", + "col946": "ktcs7", + "col947": "btmd8", + "col948": "m9x09", + "col949": "wcvaa", + "col950": "rw5qq", + "col951": "zo73k", + "col952": "r4iew", + "col953": "n06u1", + "col954": "qk6c2", + "col955": "6ml7m", + "col956": "q6wwr", + "col957": "swmgs", + "col958": "tcvdu", + "col959": "w1teo", + "col960": "wb2xx", + "col961": "c6803", + "col962": "1fi9g", + "col963": "xxfst", + "col964": "yeolp", + "col965": "i70xe", + "col966": "7bl8j", + "col967": "0y8lg", + "col968": "a68p6", + "col969": "vm115", + "col970": "tuli4", + "col971": "5lpxm", + "col972": "jchyr", + "col973": "setw9", + "col974": "yknj1", + "col975": "am4b7", + "col976": "h5ewq", + "col977": "i4wvn", + "col978": "l0zd7", + "col979": "e1pwm", + "col980": "ib1o9", + "col981": "sb4zo", + "col982": "qqc3t", + "col983": "zgjjj", + "col984": "lty58", + "col985": "q0e2e", + "col986": "a4rnn", + "col987": "ktv2k", + "col988": "vqyn3", + "col989": "8tj4g", + "col990": "tz0t2", + "col991": "i6ze7", + "col992": "tjdnz", + "col993": "yibqa", + "col994": "9gpil", + "col995": "len11", + "col996": "pm5kk", + "col997": "dvrd3", + "col998": "4omj9", + "col999": "svfuf" + }, + { + "name": "Burt Mitchell", + "gender": "male", + "col0": "m6z2r", + "col1": "k0dsk", + "col2": "jv9sg", + "col3": "an09p", + "col4": "1rikf", + "col5": "osl1c", + "col6": "fqu6v", + "col7": "is0o8", + "col8": "g5dhc", + "col9": "mb3kh", + "col10": "3qy4z", + "col11": "tk7of", + "col12": "4515w", + "col13": "9dmjm", + "col14": "02z6a", + "col15": "h7idn", + "col16": "u68sq", + "col17": "zqaoa", + "col18": "0ui7m", + "col19": "vhh5p", + "col20": "gp8gg", + "col21": "nnral", + "col22": "n4jtt", + "col23": "qz0ob", + "col24": "ngckk", + "col25": "e9jux", + "col26": "vdvtr", + "col27": "jjuw2", + "col28": "qh6v9", + "col29": "jjkqp", + "col30": "f5ylg", + "col31": "j41hs", + "col32": "6ev0e", + "col33": "ne2my", + "col34": "2to83", + "col35": "zjiu5", + "col36": "yrzvd", + "col37": "3h856", + "col38": "82rm7", + "col39": "849od", + "col40": "qatb3", + "col41": "0rz6w", + "col42": "e2mx5", + "col43": "0i7ok", + "col44": "uyt1a", + "col45": "91zum", + "col46": "zdr4a", + "col47": "5ld0r", + "col48": "u8z90", + "col49": "ctk3z", + "col50": "ysaqm", + "col51": "b8huz", + "col52": "vfxkp", + "col53": "dlrng", + "col54": "ktimu", + "col55": "gzcxj", + "col56": "jhtzo", + "col57": "qp1ge", + "col58": "dhxjq", + "col59": "sqjxz", + "col60": "6rlzd", + "col61": "q93da", + "col62": "ziq3s", + "col63": "hd9xh", + "col64": "gjg6l", + "col65": "27vcl", + "col66": "lmffs", + "col67": "ycuo4", + "col68": "9qdn0", + "col69": "66cn5", + "col70": "1zwcg", + "col71": "n4e0k", + "col72": "02zou", + "col73": "2luds", + "col74": "43cq4", + "col75": "mp5yu", + "col76": "0ri85", + "col77": "o60o1", + "col78": "bd74x", + "col79": "vemxw", + "col80": "6on1t", + "col81": "uu62q", + "col82": "keewv", + "col83": "2kzmf", + "col84": "hnzis", + "col85": "6qygh", + "col86": "7ix70", + "col87": "g8oq0", + "col88": "qwtw5", + "col89": "9xs8h", + "col90": "goyew", + "col91": "q57a9", + "col92": "7dp7g", + "col93": "83q0z", + "col94": "fhgvj", + "col95": "uuwx1", + "col96": "0rbrc", + "col97": "8yyxc", + "col98": "n3ofq", + "col99": "s9xuy", + "col100": "1t7gs", + "col101": "iwuq9", + "col102": "7keue", + "col103": "wdqxy", + "col104": "2gvak", + "col105": "3lwsi", + "col106": "mxq31", + "col107": "ee09m", + "col108": "qqe62", + "col109": "ko6mm", + "col110": "73k8z", + "col111": "ht00c", + "col112": "42yzx", + "col113": "va2lm", + "col114": "denok", + "col115": "zot4r", + "col116": "hs61b", + "col117": "ey0z4", + "col118": "swbdz", + "col119": "r6mt5", + "col120": "03718", + "col121": "ol3jl", + "col122": "w0v85", + "col123": "3r6a7", + "col124": "3pehv", + "col125": "zylzd", + "col126": "2aw3y", + "col127": "ou4ak", + "col128": "hqmkk", + "col129": "ih0mw", + "col130": "0pl4j", + "col131": "dszn8", + "col132": "0m919", + "col133": "d5rsb", + "col134": "wrzk4", + "col135": "56h6c", + "col136": "g3ywu", + "col137": "scmzy", + "col138": "ol35l", + "col139": "hbi6x", + "col140": "woqh0", + "col141": "b56cs", + "col142": "31fgg", + "col143": "ly2gw", + "col144": "497pg", + "col145": "2ud5j", + "col146": "dzvjf", + "col147": "d80ro", + "col148": "fdwjc", + "col149": "nv7zv", + "col150": "9e2go", + "col151": "2vt0s", + "col152": "4q0sz", + "col153": "7kqjc", + "col154": "lkpxw", + "col155": "y3owz", + "col156": "3rttb", + "col157": "y40e3", + "col158": "1zvme", + "col159": "furyn", + "col160": "hdabk", + "col161": "b219y", + "col162": "pahu6", + "col163": "2tbh5", + "col164": "4etle", + "col165": "woc40", + "col166": "7qi80", + "col167": "0u3rr", + "col168": "0f1hs", + "col169": "hsq8a", + "col170": "8793h", + "col171": "u6r9e", + "col172": "0b7v5", + "col173": "p6of3", + "col174": "vn83e", + "col175": "ybyz6", + "col176": "pge8c", + "col177": "a0n05", + "col178": "vqw4k", + "col179": "e7a3r", + "col180": "7wxiv", + "col181": "ugzyh", + "col182": "qn7tw", + "col183": "bj02u", + "col184": "snsiz", + "col185": "zxbmx", + "col186": "xa9bd", + "col187": "vta4x", + "col188": "3pwf4", + "col189": "1phfb", + "col190": "9j8ov", + "col191": "ehwbl", + "col192": "cvx6x", + "col193": "ifuax", + "col194": "y6x44", + "col195": "d5f2t", + "col196": "i09g6", + "col197": "nncjl", + "col198": "64502", + "col199": "mr4yh", + "col200": "pkefd", + "col201": "4zb4s", + "col202": "lhifa", + "col203": "6c1ld", + "col204": "g4cd6", + "col205": "0vo7j", + "col206": "3qafb", + "col207": "5ftpe", + "col208": "bcpvs", + "col209": "m845s", + "col210": "w7oi7", + "col211": "7ktc0", + "col212": "7fejc", + "col213": "trotg", + "col214": "ub0kg", + "col215": "fbtlm", + "col216": "64lmq", + "col217": "1t6k6", + "col218": "7pxn3", + "col219": "rnb0t", + "col220": "8h7k0", + "col221": "gs6s9", + "col222": "3d57v", + "col223": "utv18", + "col224": "pgime", + "col225": "zry1p", + "col226": "25dyd", + "col227": "jqcdc", + "col228": "16qum", + "col229": "4t0wn", + "col230": "ktq70", + "col231": "61e90", + "col232": "kp0ey", + "col233": "oedlr", + "col234": "6gg6z", + "col235": "2dyfz", + "col236": "jfest", + "col237": "ei5qv", + "col238": "4n6e1", + "col239": "5e3rw", + "col240": "men7l", + "col241": "50mdy", + "col242": "bmxnx", + "col243": "go483", + "col244": "3jo1s", + "col245": "8n40h", + "col246": "uumes", + "col247": "9unft", + "col248": "8ba37", + "col249": "dm7y8", + "col250": "8akcs", + "col251": "vquq3", + "col252": "jlwhx", + "col253": "31hql", + "col254": "dedyi", + "col255": "mw2t3", + "col256": "9he4m", + "col257": "4gspu", + "col258": "mrspc", + "col259": "yuyab", + "col260": "jj3io", + "col261": "vz6n9", + "col262": "vksmz", + "col263": "um293", + "col264": "pxuak", + "col265": "dq2pq", + "col266": "1gfxq", + "col267": "x41sy", + "col268": "hfoil", + "col269": "1enh8", + "col270": "urasm", + "col271": "g0kcy", + "col272": "th6xs", + "col273": "jsqnt", + "col274": "zd4ep", + "col275": "wbqv8", + "col276": "jgzsh", + "col277": "dsebq", + "col278": "b5jnl", + "col279": "lwhvw", + "col280": "vi8fs", + "col281": "qfp3h", + "col282": "xkwpx", + "col283": "8hg2g", + "col284": "jzefe", + "col285": "esa39", + "col286": "inxm4", + "col287": "f6ji2", + "col288": "wv64w", + "col289": "p9atz", + "col290": "079hy", + "col291": "trq07", + "col292": "jw8dw", + "col293": "22mcs", + "col294": "t35rg", + "col295": "s2tjt", + "col296": "sfja3", + "col297": "zus1e", + "col298": "8efr5", + "col299": "wusut", + "col300": "u7x8l", + "col301": "e8lxg", + "col302": "9fdfm", + "col303": "4n91p", + "col304": "33xxc", + "col305": "euavh", + "col306": "9q5pq", + "col307": "8cwi8", + "col308": "olh4m", + "col309": "9wwsf", + "col310": "ixsle", + "col311": "jhdd9", + "col312": "ztu4p", + "col313": "aj7le", + "col314": "hyqa5", + "col315": "fvw0g", + "col316": "s07ag", + "col317": "gq1hb", + "col318": "n6epv", + "col319": "f0fzh", + "col320": "2ivxc", + "col321": "w66zs", + "col322": "ioc8t", + "col323": "uqtdk", + "col324": "wsn26", + "col325": "9sneu", + "col326": "x5xp5", + "col327": "wbgjo", + "col328": "hba3k", + "col329": "prpfg", + "col330": "1v94c", + "col331": "27g0c", + "col332": "hpzgz", + "col333": "cg50f", + "col334": "h7neo", + "col335": "0wjhb", + "col336": "tm64i", + "col337": "p2otp", + "col338": "0lqjt", + "col339": "hcxp1", + "col340": "v8047", + "col341": "c698q", + "col342": "ym9o0", + "col343": "tn8mr", + "col344": "bexn4", + "col345": "tnvqa", + "col346": "h7dwi", + "col347": "gpc2g", + "col348": "0dk7p", + "col349": "kdmmg", + "col350": "3n1o7", + "col351": "vltte", + "col352": "c75eu", + "col353": "7iij5", + "col354": "zil0m", + "col355": "bdddm", + "col356": "bw3jq", + "col357": "4b8ow", + "col358": "ie0ij", + "col359": "fv65p", + "col360": "bpkev", + "col361": "p7ns7", + "col362": "z7sc8", + "col363": "g52l4", + "col364": "aaeth", + "col365": "h8sr7", + "col366": "j16wo", + "col367": "ezhcg", + "col368": "ditbe", + "col369": "j7b7r", + "col370": "nqh7v", + "col371": "8ed81", + "col372": "pbp05", + "col373": "whda5", + "col374": "uwabn", + "col375": "z1f9h", + "col376": "2593v", + "col377": "2ttrr", + "col378": "rvq37", + "col379": "wn95f", + "col380": "ma6hi", + "col381": "to7ue", + "col382": "ls6q7", + "col383": "ayv10", + "col384": "1zhvb", + "col385": "r5n8p", + "col386": "jsppz", + "col387": "h5gil", + "col388": "s83kv", + "col389": "7o02x", + "col390": "exb6g", + "col391": "bb13t", + "col392": "7736k", + "col393": "lz0b4", + "col394": "ya1tw", + "col395": "l3r3m", + "col396": "hb7q0", + "col397": "a3fjy", + "col398": "hc164", + "col399": "u3iyx", + "col400": "xmivk", + "col401": "fi1gj", + "col402": "tdxmv", + "col403": "ly6un", + "col404": "7ctrt", + "col405": "wepq6", + "col406": "nqv5n", + "col407": "rtbc9", + "col408": "6wjwe", + "col409": "kffhn", + "col410": "1bjq9", + "col411": "r4sm7", + "col412": "hhcl3", + "col413": "yz9cv", + "col414": "fa5ni", + "col415": "mdokl", + "col416": "406fi", + "col417": "iqhmy", + "col418": "og4rs", + "col419": "k7fwi", + "col420": "3xxit", + "col421": "as1bu", + "col422": "l00ej", + "col423": "qnryw", + "col424": "bza1g", + "col425": "x3zi1", + "col426": "ynimv", + "col427": "urdrk", + "col428": "vy2yi", + "col429": "xjkax", + "col430": "yww8j", + "col431": "arpnu", + "col432": "5i6s6", + "col433": "6drb9", + "col434": "ng8f8", + "col435": "bwg3b", + "col436": "5ujuo", + "col437": "dq1eh", + "col438": "df5uv", + "col439": "itu6e", + "col440": "d04ns", + "col441": "snfvg", + "col442": "epr02", + "col443": "m843w", + "col444": "pmf3s", + "col445": "79blm", + "col446": "y6jgf", + "col447": "6uhhg", + "col448": "h9ngd", + "col449": "co80q", + "col450": "sixby", + "col451": "6l1la", + "col452": "i8kqb", + "col453": "0jfh3", + "col454": "6gnbz", + "col455": "0nqkx", + "col456": "qdczb", + "col457": "dh9yn", + "col458": "nwu7p", + "col459": "vjuma", + "col460": "tm354", + "col461": "bwi32", + "col462": "wnurg", + "col463": "8dftd", + "col464": "qjy7c", + "col465": "hp6rv", + "col466": "iqxeq", + "col467": "m6sk4", + "col468": "yui9x", + "col469": "tlf6l", + "col470": "o0frj", + "col471": "oe02g", + "col472": "k4atl", + "col473": "eitzp", + "col474": "jly3p", + "col475": "0qyf1", + "col476": "hpai7", + "col477": "urdwj", + "col478": "eo7a8", + "col479": "vvj5q", + "col480": "48igk", + "col481": "bs7p9", + "col482": "jylvg", + "col483": "xnhcy", + "col484": "81pga", + "col485": "4glqa", + "col486": "z0hq8", + "col487": "dl8s0", + "col488": "pdsg7", + "col489": "0ctbp", + "col490": "qgnkd", + "col491": "q5n4a", + "col492": "whwou", + "col493": "z375w", + "col494": "tfoac", + "col495": "o50ty", + "col496": "8291j", + "col497": "zvseb", + "col498": "0ls4t", + "col499": "mvr8m", + "col500": "1uyyc", + "col501": "4vhfd", + "col502": "qmkvr", + "col503": "or3qr", + "col504": "o7nlg", + "col505": "zq6rq", + "col506": "kzy25", + "col507": "4ddyn", + "col508": "jz75b", + "col509": "67f8g", + "col510": "ogbqk", + "col511": "gm78y", + "col512": "vfgu1", + "col513": "dniv3", + "col514": "lozp4", + "col515": "4jvow", + "col516": "i39tf", + "col517": "2coev", + "col518": "d7cy8", + "col519": "uuvif", + "col520": "04ece", + "col521": "dd13x", + "col522": "ayvlh", + "col523": "4nnkt", + "col524": "grj4t", + "col525": "8h0a3", + "col526": "agr50", + "col527": "maf83", + "col528": "serd5", + "col529": "muir0", + "col530": "55zgd", + "col531": "qy4h7", + "col532": "6a0nw", + "col533": "jd8ei", + "col534": "3zrmg", + "col535": "fkrrs", + "col536": "hdo1e", + "col537": "o7env", + "col538": "w4jit", + "col539": "eksxv", + "col540": "8ooan", + "col541": "mcrne", + "col542": "ye7rb", + "col543": "cnct8", + "col544": "62v2x", + "col545": "06jtu", + "col546": "eo3bp", + "col547": "j7750", + "col548": "0p3qx", + "col549": "00ev6", + "col550": "0vew1", + "col551": "hrosj", + "col552": "1a02e", + "col553": "kedop", + "col554": "v7jff", + "col555": "qmk3n", + "col556": "pfmo9", + "col557": "403xx", + "col558": "ffp4w", + "col559": "b9p12", + "col560": "itf4v", + "col561": "siq48", + "col562": "jarh3", + "col563": "dufpn", + "col564": "603q5", + "col565": "gt7h2", + "col566": "32gz9", + "col567": "sxobg", + "col568": "e1b7w", + "col569": "9so1j", + "col570": "ad9o8", + "col571": "f0eq3", + "col572": "txn3x", + "col573": "yrusm", + "col574": "l7v9d", + "col575": "poesi", + "col576": "595h0", + "col577": "17prw", + "col578": "dpjti", + "col579": "86354", + "col580": "sr28b", + "col581": "lsb08", + "col582": "t1vkk", + "col583": "vmxt5", + "col584": "xv5e8", + "col585": "2uu7a", + "col586": "08y8x", + "col587": "4btox", + "col588": "n94xh", + "col589": "rvvhr", + "col590": "ljryl", + "col591": "2i4ay", + "col592": "ckaov", + "col593": "6wzcq", + "col594": "niixb", + "col595": "4cc4w", + "col596": "2pyes", + "col597": "f5g38", + "col598": "du7ek", + "col599": "ndilh", + "col600": "4b8v3", + "col601": "6j980", + "col602": "uojr1", + "col603": "3mkp3", + "col604": "elcw6", + "col605": "le9bx", + "col606": "dti5z", + "col607": "nrfk6", + "col608": "x924x", + "col609": "25u70", + "col610": "fgim2", + "col611": "2uj9j", + "col612": "wy67s", + "col613": "4k9fc", + "col614": "lwljv", + "col615": "ufwr4", + "col616": "dgfe7", + "col617": "0c2fz", + "col618": "clzb6", + "col619": "i3gw4", + "col620": "eji8h", + "col621": "7upfy", + "col622": "mck6o", + "col623": "qqc6d", + "col624": "16ctf", + "col625": "9gjq4", + "col626": "c7hqx", + "col627": "mymic", + "col628": "qfy2z", + "col629": "co4qv", + "col630": "9d8jx", + "col631": "a6h0s", + "col632": "fffjk", + "col633": "dydko", + "col634": "oxf4u", + "col635": "q7yqk", + "col636": "8frs5", + "col637": "ioz41", + "col638": "3rk2o", + "col639": "xae6b", + "col640": "119ff", + "col641": "56an0", + "col642": "1gv0e", + "col643": "ujfpa", + "col644": "zh97g", + "col645": "e7mwn", + "col646": "x33up", + "col647": "kljyj", + "col648": "tbbah", + "col649": "xs0t4", + "col650": "v8pf1", + "col651": "82huj", + "col652": "z9981", + "col653": "xa141", + "col654": "t7p1u", + "col655": "5fwm6", + "col656": "51jho", + "col657": "0n22c", + "col658": "8ozm4", + "col659": "lnmm9", + "col660": "ahuek", + "col661": "21bm4", + "col662": "6ymoh", + "col663": "espq5", + "col664": "mdfur", + "col665": "4u08j", + "col666": "x0hpb", + "col667": "jzudh", + "col668": "wc9gm", + "col669": "bm81l", + "col670": "fekpz", + "col671": "orvfz", + "col672": "5n8ys", + "col673": "lf2e5", + "col674": "4a6qo", + "col675": "y2ita", + "col676": "l8nj8", + "col677": "50yvy", + "col678": "pem9o", + "col679": "l1h9o", + "col680": "7hkuh", + "col681": "43lij", + "col682": "30tkt", + "col683": "k9mn9", + "col684": "w5ad1", + "col685": "gh3db", + "col686": "2d90s", + "col687": "3ars7", + "col688": "htjlm", + "col689": "eig8o", + "col690": "fs3hw", + "col691": "0a6ao", + "col692": "fra3f", + "col693": "br4b1", + "col694": "3kmou", + "col695": "f6un1", + "col696": "0v2cq", + "col697": "sumjs", + "col698": "32rxc", + "col699": "stjtq", + "col700": "p42bp", + "col701": "j0pp4", + "col702": "priyp", + "col703": "1klcw", + "col704": "7tygy", + "col705": "xavkc", + "col706": "w3b6h", + "col707": "49ohw", + "col708": "d0bck", + "col709": "r06uu", + "col710": "6wr6b", + "col711": "6oxj2", + "col712": "9mm5i", + "col713": "vxfib", + "col714": "jjfsl", + "col715": "fwv44", + "col716": "qbst3", + "col717": "98abb", + "col718": "jjy0w", + "col719": "ika8g", + "col720": "o0l39", + "col721": "uhes7", + "col722": "ddlv1", + "col723": "hi9me", + "col724": "1f7eh", + "col725": "lbok6", + "col726": "tq19k", + "col727": "o1aod", + "col728": "6h6w8", + "col729": "sqi74", + "col730": "pr2i8", + "col731": "acv4p", + "col732": "ypg9t", + "col733": "mox4c", + "col734": "pbjnx", + "col735": "fmdcj", + "col736": "3cw8m", + "col737": "nxw88", + "col738": "86dei", + "col739": "h85g5", + "col740": "r4jzf", + "col741": "abyrj", + "col742": "adlzv", + "col743": "e767z", + "col744": "yo8d7", + "col745": "fxseu", + "col746": "bqcib", + "col747": "5n91k", + "col748": "crgq9", + "col749": "0eld0", + "col750": "69926", + "col751": "ghxru", + "col752": "xa08z", + "col753": "mca8z", + "col754": "iuvd8", + "col755": "2gweu", + "col756": "ew7db", + "col757": "w57wo", + "col758": "o8qk1", + "col759": "ysy31", + "col760": "j5l2e", + "col761": "l9dcm", + "col762": "4qedf", + "col763": "tavl6", + "col764": "r19jv", + "col765": "8gt61", + "col766": "ngm83", + "col767": "9s68y", + "col768": "35eu7", + "col769": "al7ch", + "col770": "m6ll8", + "col771": "e8ftm", + "col772": "tv8bh", + "col773": "gec02", + "col774": "3u54j", + "col775": "vi8a4", + "col776": "gdrco", + "col777": "177x4", + "col778": "cuphh", + "col779": "wvbr2", + "col780": "4fsms", + "col781": "qe4h2", + "col782": "uy3r2", + "col783": "sbzrj", + "col784": "bfw39", + "col785": "68iom", + "col786": "d79dz", + "col787": "cqg3k", + "col788": "4mnof", + "col789": "4behk", + "col790": "h4zza", + "col791": "91ias", + "col792": "1lqni", + "col793": "gvpzm", + "col794": "5ptr4", + "col795": "zn1b2", + "col796": "bdpze", + "col797": "clryb", + "col798": "r5pov", + "col799": "1tb6n", + "col800": "1t5fx", + "col801": "tyw6j", + "col802": "pi5q3", + "col803": "25g10", + "col804": "xka9c", + "col805": "ejogd", + "col806": "zivio", + "col807": "ztkxk", + "col808": "clay6", + "col809": "bkt14", + "col810": "h822v", + "col811": "aib2r", + "col812": "y3nwz", + "col813": "y6gsm", + "col814": "8jek6", + "col815": "jal2k", + "col816": "4zqpy", + "col817": "jjq80", + "col818": "sdsbg", + "col819": "j6is5", + "col820": "4t0pl", + "col821": "o7aa8", + "col822": "qz87c", + "col823": "2pq1h", + "col824": "90d2f", + "col825": "jvbdt", + "col826": "f3kre", + "col827": "ilxuc", + "col828": "huzco", + "col829": "d3fqq", + "col830": "f6hch", + "col831": "17710", + "col832": "avjj4", + "col833": "rvsns", + "col834": "qhsys", + "col835": "1i7gu", + "col836": "blbqf", + "col837": "y0otf", + "col838": "cczbm", + "col839": "28obc", + "col840": "uzcu0", + "col841": "g0c5p", + "col842": "jli91", + "col843": "nxrd5", + "col844": "qzno9", + "col845": "idgs2", + "col846": "vn5tw", + "col847": "ev8yx", + "col848": "5j1cm", + "col849": "d149s", + "col850": "aa0tm", + "col851": "5nu01", + "col852": "hygg3", + "col853": "h4ra1", + "col854": "hyjhm", + "col855": "gybiv", + "col856": "gnz6g", + "col857": "54fg4", + "col858": "t9mgg", + "col859": "gt358", + "col860": "5ekn8", + "col861": "kl73b", + "col862": "kx0vi", + "col863": "fo5fy", + "col864": "s3rf0", + "col865": "py8ay", + "col866": "fccr4", + "col867": "xyu0h", + "col868": "kx6ul", + "col869": "z8bqg", + "col870": "n1z6l", + "col871": "qbju6", + "col872": "gc3sl", + "col873": "4o2rr", + "col874": "xzth2", + "col875": "qqfor", + "col876": "a7qvo", + "col877": "24u8o", + "col878": "jjsm5", + "col879": "vqk83", + "col880": "r371v", + "col881": "assfw", + "col882": "0c7bw", + "col883": "f5jou", + "col884": "rd3jw", + "col885": "sj85n", + "col886": "unr24", + "col887": "eaj6a", + "col888": "g7zf5", + "col889": "1hcjf", + "col890": "4yg38", + "col891": "rp6np", + "col892": "2p7lc", + "col893": "08c0u", + "col894": "zjvlx", + "col895": "18pq9", + "col896": "pxdvh", + "col897": "i9rke", + "col898": "688og", + "col899": "nlhug", + "col900": "rwwth", + "col901": "dn1mt", + "col902": "3c95g", + "col903": "nobbw", + "col904": "xed5a", + "col905": "kpcb1", + "col906": "l0zvm", + "col907": "h9ury", + "col908": "jwpzo", + "col909": "rn6d5", + "col910": "w1nhk", + "col911": "53d1t", + "col912": "31va8", + "col913": "50f57", + "col914": "8uhdx", + "col915": "g8zvv", + "col916": "hx4nj", + "col917": "gi5cd", + "col918": "0flpd", + "col919": "rrn5w", + "col920": "iqc0u", + "col921": "hr4zm", + "col922": "urnyo", + "col923": "tnd95", + "col924": "r1dta", + "col925": "p9fyr", + "col926": "pb9j7", + "col927": "zqf5f", + "col928": "09j48", + "col929": "bkfyg", + "col930": "d40e2", + "col931": "txkpy", + "col932": "u3e34", + "col933": "qbtnf", + "col934": "aoa5w", + "col935": "n2ien", + "col936": "8dmns", + "col937": "b8inz", + "col938": "34xbw", + "col939": "9jji8", + "col940": "y07tm", + "col941": "wx8m1", + "col942": "rwwn2", + "col943": "xt0oh", + "col944": "httg4", + "col945": "jjllj", + "col946": "zc7gg", + "col947": "k39th", + "col948": "n2ju5", + "col949": "2luxi", + "col950": "zlfaa", + "col951": "ffbea", + "col952": "bvdbk", + "col953": "e4j5p", + "col954": "w2zd5", + "col955": "y8s14", + "col956": "lzhvj", + "col957": "anelr", + "col958": "umv5r", + "col959": "klbda", + "col960": "14d1t", + "col961": "12q91", + "col962": "bgqxz", + "col963": "gotm9", + "col964": "zu1b8", + "col965": "m7exk", + "col966": "gqnvc", + "col967": "ssxyv", + "col968": "t7g57", + "col969": "6sp74", + "col970": "p1ddc", + "col971": "evyfo", + "col972": "f2w1v", + "col973": "idf9x", + "col974": "5qldp", + "col975": "ywiq6", + "col976": "ut7yq", + "col977": "4f8kb", + "col978": "wri4e", + "col979": "oquwl", + "col980": "fzb12", + "col981": "xe3y2", + "col982": "tk4qd", + "col983": "e52fe", + "col984": "rk331", + "col985": "wmzzk", + "col986": "n5o7w", + "col987": "31dnz", + "col988": "8lj7x", + "col989": "75cpr", + "col990": "jgvqt", + "col991": "7mysy", + "col992": "xwhxl", + "col993": "rckfj", + "col994": "raj6m", + "col995": "n1dbh", + "col996": "vx617", + "col997": "o8p7v", + "col998": "69q8x", + "col999": "zi47s" + }, + { + "name": "Haley Mejia", + "gender": "female", + "col0": "4k07j", + "col1": "g1v2s", + "col2": "86oeh", + "col3": "j2ww5", + "col4": "icx0x", + "col5": "3rf0j", + "col6": "twsip", + "col7": "iloyr", + "col8": "jks3a", + "col9": "0pynv", + "col10": "hato0", + "col11": "8r2tc", + "col12": "aakb9", + "col13": "51wcc", + "col14": "v552s", + "col15": "5tsob", + "col16": "ilmqq", + "col17": "ssbd3", + "col18": "bkrx4", + "col19": "1nyw0", + "col20": "pt0wl", + "col21": "ykr5m", + "col22": "1homu", + "col23": "5qguq", + "col24": "0y923", + "col25": "279t3", + "col26": "6nlo5", + "col27": "c9k2x", + "col28": "r45ez", + "col29": "qpfr0", + "col30": "qc5z8", + "col31": "uhdwr", + "col32": "qkmrs", + "col33": "nkvia", + "col34": "itctf", + "col35": "4cj87", + "col36": "c7yn4", + "col37": "hyuk9", + "col38": "m5d98", + "col39": "budzh", + "col40": "o05dh", + "col41": "ssr0t", + "col42": "ugjpl", + "col43": "mmcaq", + "col44": "q59bq", + "col45": "n7wgy", + "col46": "8ksul", + "col47": "yvhfj", + "col48": "dn804", + "col49": "3jmcv", + "col50": "dong1", + "col51": "hlffs", + "col52": "8h7u6", + "col53": "dz9xg", + "col54": "e7nez", + "col55": "3mz0i", + "col56": "cbj4w", + "col57": "w2rrk", + "col58": "mxiwc", + "col59": "4utb3", + "col60": "cpmtl", + "col61": "uaa96", + "col62": "j94ny", + "col63": "taeyh", + "col64": "yngj9", + "col65": "c4ogw", + "col66": "b5b6a", + "col67": "j0v53", + "col68": "oa9bx", + "col69": "3ncws", + "col70": "nc1xz", + "col71": "m7lro", + "col72": "kouhn", + "col73": "iyt9c", + "col74": "ji27o", + "col75": "on8gs", + "col76": "6df1t", + "col77": "c6o5g", + "col78": "1jecx", + "col79": "699hz", + "col80": "td2c8", + "col81": "flodg", + "col82": "uqd42", + "col83": "tmamt", + "col84": "41tya", + "col85": "ndbdr", + "col86": "46r16", + "col87": "yhu30", + "col88": "qwpjj", + "col89": "47trt", + "col90": "tzitt", + "col91": "iczsx", + "col92": "nhzh3", + "col93": "62zz5", + "col94": "gj0vl", + "col95": "1rri4", + "col96": "rzf12", + "col97": "mc50i", + "col98": "bl8y7", + "col99": "9pp3c", + "col100": "54rko", + "col101": "hyxav", + "col102": "eaa7a", + "col103": "58zt7", + "col104": "cblct", + "col105": "o4o26", + "col106": "2m3hv", + "col107": "xaa3z", + "col108": "e4o9m", + "col109": "5c1x6", + "col110": "hlteu", + "col111": "vx6g9", + "col112": "cov7t", + "col113": "ospfs", + "col114": "1zz51", + "col115": "ewdn8", + "col116": "gv270", + "col117": "31syc", + "col118": "y96pq", + "col119": "15ivk", + "col120": "ti3h1", + "col121": "4d7k4", + "col122": "40bv9", + "col123": "w1uin", + "col124": "jcodi", + "col125": "5kro5", + "col126": "p75rf", + "col127": "9gw4s", + "col128": "tmc5p", + "col129": "zrina", + "col130": "qyccm", + "col131": "76pd0", + "col132": "d3yt1", + "col133": "xqa0k", + "col134": "4wfl4", + "col135": "lps6m", + "col136": "a4mm8", + "col137": "1am7t", + "col138": "agbyv", + "col139": "phvd7", + "col140": "uap8z", + "col141": "v0wg5", + "col142": "78okh", + "col143": "7i3o7", + "col144": "e8z57", + "col145": "xvu0w", + "col146": "hsqvw", + "col147": "z3jvh", + "col148": "k4n0h", + "col149": "o2m7t", + "col150": "9w4rt", + "col151": "aryzl", + "col152": "8gz14", + "col153": "m7nqp", + "col154": "e19ud", + "col155": "gbdsf", + "col156": "hgacb", + "col157": "wfrw9", + "col158": "2mrhr", + "col159": "6uhn2", + "col160": "az9ds", + "col161": "sm27p", + "col162": "0j7f2", + "col163": "lzy8x", + "col164": "v69le", + "col165": "p4tj1", + "col166": "7m5zy", + "col167": "whin3", + "col168": "6nkhy", + "col169": "pq667", + "col170": "zkbse", + "col171": "85spb", + "col172": "i8r3j", + "col173": "jbgcv", + "col174": "9tqcj", + "col175": "5h9db", + "col176": "aqt9a", + "col177": "62r75", + "col178": "gg17e", + "col179": "lja56", + "col180": "aet0r", + "col181": "clmnb", + "col182": "smig4", + "col183": "yaagz", + "col184": "pdgqr", + "col185": "aguvf", + "col186": "sn6kt", + "col187": "hhaqf", + "col188": "htz9w", + "col189": "ce0c4", + "col190": "pq1am", + "col191": "xvnwr", + "col192": "k85eq", + "col193": "afqkz", + "col194": "q1jwh", + "col195": "n6esn", + "col196": "hlz3f", + "col197": "z5s05", + "col198": "5pi6d", + "col199": "z1hgg", + "col200": "k7v1d", + "col201": "97pro", + "col202": "78a3k", + "col203": "o71ej", + "col204": "f7aob", + "col205": "6f8fj", + "col206": "rzy0h", + "col207": "454u8", + "col208": "zogqf", + "col209": "jjg6x", + "col210": "gyk8o", + "col211": "bzp98", + "col212": "1qqmt", + "col213": "b9ppe", + "col214": "ezx0f", + "col215": "5a6do", + "col216": "doq72", + "col217": "4nx9u", + "col218": "1i2sh", + "col219": "knlsz", + "col220": "wyy4n", + "col221": "7ia24", + "col222": "r7qh3", + "col223": "nre3p", + "col224": "3hvu7", + "col225": "erbav", + "col226": "14mcp", + "col227": "qyfna", + "col228": "yaw7g", + "col229": "c2rnw", + "col230": "zcxus", + "col231": "qw40z", + "col232": "wci39", + "col233": "igril", + "col234": "iamx5", + "col235": "w8md0", + "col236": "a93xp", + "col237": "9r9v7", + "col238": "383tu", + "col239": "cpzj0", + "col240": "fg9y6", + "col241": "tc9fi", + "col242": "2melb", + "col243": "kcxpt", + "col244": "kh6br", + "col245": "9buui", + "col246": "18xqi", + "col247": "a4gri", + "col248": "jwoyf", + "col249": "y1o2k", + "col250": "7jin8", + "col251": "8id8o", + "col252": "yxewu", + "col253": "fa1qx", + "col254": "lldbn", + "col255": "hj2dv", + "col256": "477uz", + "col257": "taqpb", + "col258": "7ogjv", + "col259": "hjlec", + "col260": "ebhb7", + "col261": "hz3tn", + "col262": "e8pst", + "col263": "bszdm", + "col264": "86isr", + "col265": "em4zb", + "col266": "i4uck", + "col267": "08uk4", + "col268": "5b1b1", + "col269": "o8xg4", + "col270": "6a3vz", + "col271": "1tm8l", + "col272": "u5mp3", + "col273": "scjsa", + "col274": "49ybl", + "col275": "5zdu9", + "col276": "rubp1", + "col277": "jwp9j", + "col278": "n293d", + "col279": "yi0m5", + "col280": "3lpuf", + "col281": "sl2i9", + "col282": "n6gof", + "col283": "cflo9", + "col284": "up4m9", + "col285": "uy4lf", + "col286": "dlxix", + "col287": "ajqqo", + "col288": "hdcrl", + "col289": "8pjii", + "col290": "ecu7m", + "col291": "gkygf", + "col292": "ar0d4", + "col293": "u0rf3", + "col294": "hywf5", + "col295": "nqgcs", + "col296": "y0lor", + "col297": "e3qho", + "col298": "gtphh", + "col299": "jbpgc", + "col300": "0xtx2", + "col301": "nqxza", + "col302": "x87tk", + "col303": "cktda", + "col304": "efa28", + "col305": "krjit", + "col306": "vhd9w", + "col307": "5k3br", + "col308": "75diw", + "col309": "imevt", + "col310": "zj34o", + "col311": "0v3km", + "col312": "gyfa9", + "col313": "v3srv", + "col314": "5kfua", + "col315": "a8cno", + "col316": "jecl0", + "col317": "m6oae", + "col318": "y98qu", + "col319": "giyd1", + "col320": "lef8v", + "col321": "p623r", + "col322": "9c5up", + "col323": "94ejg", + "col324": "ew0lz", + "col325": "upsaz", + "col326": "7w8ns", + "col327": "l681i", + "col328": "ep7t8", + "col329": "jk2pt", + "col330": "qqxdx", + "col331": "7n28m", + "col332": "gmope", + "col333": "zpx15", + "col334": "etujo", + "col335": "wfau3", + "col336": "0g676", + "col337": "cpq26", + "col338": "x7hfa", + "col339": "lk5eb", + "col340": "w9ntg", + "col341": "5o1bt", + "col342": "t0hxn", + "col343": "ijlyn", + "col344": "ka13r", + "col345": "xrx4p", + "col346": "tl7nd", + "col347": "5djzu", + "col348": "ynzbi", + "col349": "oh9bl", + "col350": "d9kv9", + "col351": "u6tl3", + "col352": "e9pzd", + "col353": "s5dqs", + "col354": "4q12l", + "col355": "c40ia", + "col356": "gi3zl", + "col357": "9pxeo", + "col358": "wdc15", + "col359": "vqa9i", + "col360": "kpyge", + "col361": "a8me2", + "col362": "p65hz", + "col363": "xtwro", + "col364": "95iq1", + "col365": "mvstu", + "col366": "bruhs", + "col367": "zdylk", + "col368": "6997l", + "col369": "15q0t", + "col370": "t4ojn", + "col371": "g913n", + "col372": "5541n", + "col373": "kgwzw", + "col374": "cpjqx", + "col375": "rzb74", + "col376": "tmsfm", + "col377": "9r5cd", + "col378": "ssqvo", + "col379": "qhhhi", + "col380": "2q35c", + "col381": "yn8xs", + "col382": "s9rf2", + "col383": "496ye", + "col384": "kj4r4", + "col385": "d5h54", + "col386": "atjqv", + "col387": "1yi86", + "col388": "39s7p", + "col389": "x8mh0", + "col390": "51blu", + "col391": "0yg9t", + "col392": "gyvp5", + "col393": "cia7v", + "col394": "l2hif", + "col395": "ocvvh", + "col396": "4pve3", + "col397": "g618w", + "col398": "pmpf1", + "col399": "kj4bi", + "col400": "e3dzb", + "col401": "xbxor", + "col402": "xd0bu", + "col403": "rcedw", + "col404": "6aisj", + "col405": "fwrfp", + "col406": "fz08k", + "col407": "0wr5t", + "col408": "psq60", + "col409": "ub5xf", + "col410": "rjhrd", + "col411": "twlih", + "col412": "spdw6", + "col413": "con81", + "col414": "lhkjd", + "col415": "l12gm", + "col416": "wjpir", + "col417": "g3qlt", + "col418": "azfa0", + "col419": "gwsq1", + "col420": "qahyr", + "col421": "cl5x3", + "col422": "7a45m", + "col423": "xjlmu", + "col424": "m5cem", + "col425": "l7da3", + "col426": "etjlh", + "col427": "0var5", + "col428": "snhvk", + "col429": "cz26l", + "col430": "bsfl1", + "col431": "ttw5d", + "col432": "ypxtt", + "col433": "jj9rz", + "col434": "ycoa2", + "col435": "sgb8p", + "col436": "x2mme", + "col437": "9pcl4", + "col438": "qd93x", + "col439": "gvcik", + "col440": "htzj8", + "col441": "s54r1", + "col442": "vrx8q", + "col443": "230nx", + "col444": "s23xc", + "col445": "r2pws", + "col446": "au0j2", + "col447": "qldcc", + "col448": "v4vqc", + "col449": "aadak", + "col450": "be03j", + "col451": "khwft", + "col452": "kqbjw", + "col453": "ruyds", + "col454": "8ofdd", + "col455": "xol6b", + "col456": "6xmnh", + "col457": "n89zn", + "col458": "wdco4", + "col459": "4ik7q", + "col460": "riuz1", + "col461": "jmc34", + "col462": "z5y2p", + "col463": "r48n6", + "col464": "yqe8t", + "col465": "g2vw9", + "col466": "wx0a9", + "col467": "zk4li", + "col468": "rtpbu", + "col469": "pxiv9", + "col470": "gf3dc", + "col471": "88tii", + "col472": "xacvl", + "col473": "hca4g", + "col474": "d0lhq", + "col475": "9m1l6", + "col476": "vgvr6", + "col477": "tgw80", + "col478": "avqsb", + "col479": "flfj0", + "col480": "t1w7g", + "col481": "1fruf", + "col482": "hlj2d", + "col483": "e8bgk", + "col484": "603u4", + "col485": "eep5o", + "col486": "zwxea", + "col487": "ilfv8", + "col488": "8sshi", + "col489": "pthgb", + "col490": "sug1a", + "col491": "u7dz9", + "col492": "z4e34", + "col493": "85dwr", + "col494": "4w8ey", + "col495": "tqi3e", + "col496": "kwmuk", + "col497": "de5a8", + "col498": "kfu8o", + "col499": "ldg3a", + "col500": "zwlhn", + "col501": "mdaqg", + "col502": "mhrui", + "col503": "wn8vt", + "col504": "qo2r4", + "col505": "br3za", + "col506": "43ttc", + "col507": "vpxqq", + "col508": "c5swn", + "col509": "j0tjh", + "col510": "4hqsk", + "col511": "arp24", + "col512": "2wsg3", + "col513": "2znr1", + "col514": "irqds", + "col515": "8jdc0", + "col516": "7gvpd", + "col517": "ocnn3", + "col518": "9f2sc", + "col519": "jc2kw", + "col520": "h4a3z", + "col521": "9d620", + "col522": "s7oiz", + "col523": "apej1", + "col524": "c7muz", + "col525": "85nh3", + "col526": "01w3f", + "col527": "9tc54", + "col528": "7tr8e", + "col529": "n5bji", + "col530": "fikwp", + "col531": "3lgly", + "col532": "yajf2", + "col533": "oyjc0", + "col534": "emeh2", + "col535": "lulyc", + "col536": "mfa7i", + "col537": "4awq1", + "col538": "330al", + "col539": "dhgbh", + "col540": "n7ng6", + "col541": "vz0g7", + "col542": "6qkb5", + "col543": "z5otc", + "col544": "b2lkv", + "col545": "ptae4", + "col546": "08j0s", + "col547": "9a2lf", + "col548": "y3pov", + "col549": "ugirm", + "col550": "tzjal", + "col551": "840we", + "col552": "uv2r5", + "col553": "r2uiv", + "col554": "9vmt1", + "col555": "f6k46", + "col556": "jicuz", + "col557": "p4uto", + "col558": "8iion", + "col559": "zl4oc", + "col560": "2z90j", + "col561": "23w7k", + "col562": "sthls", + "col563": "kowpt", + "col564": "tz8a8", + "col565": "iwd3j", + "col566": "tw7w4", + "col567": "d2l0q", + "col568": "3uvin", + "col569": "031ss", + "col570": "hb5wb", + "col571": "k5pbd", + "col572": "f9cqv", + "col573": "xop2u", + "col574": "4iv0c", + "col575": "vy2g4", + "col576": "aawuz", + "col577": "25pci", + "col578": "ibpby", + "col579": "itl9e", + "col580": "fc0xx", + "col581": "ufmd1", + "col582": "rn566", + "col583": "yzczp", + "col584": "ory8a", + "col585": "xov07", + "col586": "0f6nu", + "col587": "u8o0k", + "col588": "fpx1x", + "col589": "gizob", + "col590": "vafp3", + "col591": "k2aue", + "col592": "o23bn", + "col593": "eb52m", + "col594": "t5fow", + "col595": "mwy7h", + "col596": "azh8y", + "col597": "hxvrk", + "col598": "0gtuh", + "col599": "a15dn", + "col600": "ab25i", + "col601": "1u8h2", + "col602": "uzst3", + "col603": "kq67g", + "col604": "jz5l2", + "col605": "t77t5", + "col606": "fc60e", + "col607": "6hw2e", + "col608": "p5oe8", + "col609": "ae33m", + "col610": "6d6sd", + "col611": "8azc3", + "col612": "imnn5", + "col613": "etbqu", + "col614": "b5g4d", + "col615": "s2o51", + "col616": "roc2n", + "col617": "tlor6", + "col618": "0z4t4", + "col619": "dhsww", + "col620": "2cxt5", + "col621": "jcu3g", + "col622": "83wz8", + "col623": "nr0h2", + "col624": "vul0x", + "col625": "kk9wl", + "col626": "12hwl", + "col627": "wwmel", + "col628": "y2mi5", + "col629": "oz1vv", + "col630": "q1su7", + "col631": "iqmlp", + "col632": "suwd7", + "col633": "ujs3w", + "col634": "aawx9", + "col635": "4a18y", + "col636": "k5pf3", + "col637": "lnwbo", + "col638": "f8l6o", + "col639": "f6lkq", + "col640": "clv2i", + "col641": "qhej4", + "col642": "2ggzx", + "col643": "jpwzb", + "col644": "1gnrb", + "col645": "8q85o", + "col646": "enl5n", + "col647": "q0lo7", + "col648": "zn0rx", + "col649": "1zg77", + "col650": "1exk7", + "col651": "afi7k", + "col652": "xft60", + "col653": "1adn1", + "col654": "70ehy", + "col655": "hz8yl", + "col656": "0fgvv", + "col657": "1fzfa", + "col658": "ejfzc", + "col659": "voj6j", + "col660": "wfnxy", + "col661": "dcrjy", + "col662": "kxxlj", + "col663": "2d7kg", + "col664": "9kauu", + "col665": "vrrci", + "col666": "w4owl", + "col667": "7f7ap", + "col668": "o5tdl", + "col669": "cg868", + "col670": "n5r07", + "col671": "42hjb", + "col672": "irt9b", + "col673": "4ld5w", + "col674": "mhtp5", + "col675": "kxkw5", + "col676": "6qxgu", + "col677": "qvc95", + "col678": "5g3jp", + "col679": "od9xt", + "col680": "ilt1q", + "col681": "8rnka", + "col682": "jmxpq", + "col683": "72b7c", + "col684": "c76uf", + "col685": "4tmii", + "col686": "jgkwl", + "col687": "5fx1d", + "col688": "wfoho", + "col689": "v4qtn", + "col690": "v7x0b", + "col691": "4bzen", + "col692": "bpvfa", + "col693": "v2mo9", + "col694": "nvvrx", + "col695": "q0xoj", + "col696": "qcfme", + "col697": "1q5e8", + "col698": "75td2", + "col699": "zsod6", + "col700": "xj9bi", + "col701": "oejvq", + "col702": "y9hoc", + "col703": "6575k", + "col704": "v4ikf", + "col705": "ggeza", + "col706": "lo34w", + "col707": "blowf", + "col708": "4bih3", + "col709": "s927d", + "col710": "ug04q", + "col711": "tewb0", + "col712": "etvlr", + "col713": "m9qln", + "col714": "us4mw", + "col715": "tulkf", + "col716": "lap0l", + "col717": "r7vcf", + "col718": "nd0nc", + "col719": "miku7", + "col720": "z1tzj", + "col721": "i1yyc", + "col722": "wdc2s", + "col723": "5kxjz", + "col724": "14mdx", + "col725": "lw0tf", + "col726": "nvsp5", + "col727": "eanev", + "col728": "1ou0f", + "col729": "2qcvo", + "col730": "p4kgl", + "col731": "kq13y", + "col732": "z4rt0", + "col733": "xsbjl", + "col734": "siu8j", + "col735": "gpt1q", + "col736": "nf0a2", + "col737": "1xskt", + "col738": "nv1y7", + "col739": "pt9pm", + "col740": "zngcx", + "col741": "mohka", + "col742": "i8vmq", + "col743": "e3mic", + "col744": "0qygk", + "col745": "q7d95", + "col746": "64s9a", + "col747": "d56cq", + "col748": "08qjr", + "col749": "ao2jt", + "col750": "xge9b", + "col751": "oiti4", + "col752": "tttse", + "col753": "5nb70", + "col754": "jg5o6", + "col755": "yc0wk", + "col756": "dno3a", + "col757": "na1h2", + "col758": "rlggz", + "col759": "xqvfr", + "col760": "do86u", + "col761": "ylpd1", + "col762": "thahu", + "col763": "qmeji", + "col764": "lo47y", + "col765": "gy29y", + "col766": "noier", + "col767": "g5jqk", + "col768": "tgtyi", + "col769": "p1nb8", + "col770": "l43g1", + "col771": "7vw8i", + "col772": "gy8hi", + "col773": "und1h", + "col774": "qb4n2", + "col775": "w24ou", + "col776": "9jua9", + "col777": "v2iaj", + "col778": "blm95", + "col779": "zeunw", + "col780": "5trp4", + "col781": "jsixk", + "col782": "0e5ca", + "col783": "ydcir", + "col784": "aa6ks", + "col785": "mf80w", + "col786": "ehopa", + "col787": "5o4e1", + "col788": "kogy3", + "col789": "dof3k", + "col790": "ktrhj", + "col791": "b0rgb", + "col792": "ea0hd", + "col793": "vvo5j", + "col794": "9x3dr", + "col795": "5tewz", + "col796": "6zko7", + "col797": "4ke1j", + "col798": "2w4go", + "col799": "rid1t", + "col800": "xn4xt", + "col801": "mvz68", + "col802": "5ygqp", + "col803": "vru3m", + "col804": "wrj4u", + "col805": "y0gx9", + "col806": "t9jet", + "col807": "5noe6", + "col808": "sd6yq", + "col809": "x5qqp", + "col810": "43n9r", + "col811": "btksf", + "col812": "ni3v1", + "col813": "ngtem", + "col814": "osayj", + "col815": "06b1c", + "col816": "sdly7", + "col817": "sxkco", + "col818": "2r64p", + "col819": "yum5d", + "col820": "cegkj", + "col821": "ecovo", + "col822": "tdvnt", + "col823": "p09tr", + "col824": "chqp2", + "col825": "luxm3", + "col826": "wjo5u", + "col827": "h7ckg", + "col828": "ne7pt", + "col829": "u232w", + "col830": "44qm0", + "col831": "uk0sc", + "col832": "ne1s6", + "col833": "0dw5u", + "col834": "mx5el", + "col835": "aebdl", + "col836": "d6cud", + "col837": "f56pv", + "col838": "za751", + "col839": "30ryl", + "col840": "gexyh", + "col841": "w2due", + "col842": "0t5nn", + "col843": "btt41", + "col844": "z1d6c", + "col845": "v6ro6", + "col846": "oc0do", + "col847": "tqdch", + "col848": "ahvc7", + "col849": "u90lg", + "col850": "gp324", + "col851": "hivx1", + "col852": "7y5yy", + "col853": "nardq", + "col854": "1eawm", + "col855": "y83v5", + "col856": "ynozq", + "col857": "xhicm", + "col858": "4rrvr", + "col859": "ueisq", + "col860": "02wst", + "col861": "1cp5r", + "col862": "lr8o5", + "col863": "qwo0g", + "col864": "llxk7", + "col865": "8t1tv", + "col866": "4r1p1", + "col867": "23axa", + "col868": "ym6hh", + "col869": "monjw", + "col870": "ynk84", + "col871": "8jwmn", + "col872": "id95d", + "col873": "bjj1v", + "col874": "f96ko", + "col875": "x0qfu", + "col876": "ubzr3", + "col877": "ln8qm", + "col878": "lqm75", + "col879": "fa8a0", + "col880": "csumk", + "col881": "fu9xt", + "col882": "80x7p", + "col883": "mglhx", + "col884": "mgmlg", + "col885": "qhggg", + "col886": "tfid5", + "col887": "yduoz", + "col888": "jtvdn", + "col889": "bxois", + "col890": "54wym", + "col891": "qw08i", + "col892": "ytpsq", + "col893": "rwqkt", + "col894": "qwkng", + "col895": "6mk2b", + "col896": "tny61", + "col897": "rjs4p", + "col898": "cu59g", + "col899": "14ikh", + "col900": "alcbx", + "col901": "jvrih", + "col902": "ehckc", + "col903": "4a8lz", + "col904": "3nvyf", + "col905": "0rvlr", + "col906": "yld8s", + "col907": "f624d", + "col908": "yzire", + "col909": "npo39", + "col910": "zrjng", + "col911": "jf3i3", + "col912": "s5for", + "col913": "sqt97", + "col914": "utwof", + "col915": "bl9x4", + "col916": "ela8t", + "col917": "yit8k", + "col918": "u7ajx", + "col919": "k09v2", + "col920": "af92d", + "col921": "r1gg9", + "col922": "qk878", + "col923": "bwirl", + "col924": "ddj4f", + "col925": "x9qdd", + "col926": "o2pbj", + "col927": "mq4f1", + "col928": "f4j0m", + "col929": "pomd4", + "col930": "3givc", + "col931": "j8pjc", + "col932": "62ni8", + "col933": "jojsh", + "col934": "nzhz7", + "col935": "2ssnf", + "col936": "8hfyo", + "col937": "1d3hf", + "col938": "eqnym", + "col939": "kw910", + "col940": "3ikjh", + "col941": "09alv", + "col942": "b2qqf", + "col943": "qw7zi", + "col944": "195ba", + "col945": "mgfhz", + "col946": "zq4it", + "col947": "6bj8l", + "col948": "63dh9", + "col949": "9wmd2", + "col950": "wb34f", + "col951": "v3c8a", + "col952": "2ic7o", + "col953": "f4m4l", + "col954": "ktjix", + "col955": "biqrx", + "col956": "720bx", + "col957": "ycqki", + "col958": "e2g0s", + "col959": "kv9u9", + "col960": "7ybyn", + "col961": "z1iq6", + "col962": "cg4r3", + "col963": "h0v4q", + "col964": "twt4l", + "col965": "x7fq4", + "col966": "r82s3", + "col967": "1hpg3", + "col968": "0azzx", + "col969": "1csrs", + "col970": "awyh3", + "col971": "fkwnd", + "col972": "45mzu", + "col973": "rs4ad", + "col974": "jksye", + "col975": "uvs4i", + "col976": "o3pve", + "col977": "cewuv", + "col978": "xr1tp", + "col979": "a7ltx", + "col980": "ux4cu", + "col981": "hjkq5", + "col982": "qoq49", + "col983": "mbamb", + "col984": "1kl8w", + "col985": "9dn51", + "col986": "wuwpa", + "col987": "olqo2", + "col988": "uu5ar", + "col989": "ueycr", + "col990": "m7q4v", + "col991": "e9mhk", + "col992": "1p81h", + "col993": "fy367", + "col994": "0pfzt", + "col995": "4sued", + "col996": "frnqs", + "col997": "7syt1", + "col998": "lt7pc", + "col999": "ucxlt" + }, + { + "name": "Opal Bradford", + "gender": "female", + "col0": "78f47", + "col1": "y8quw", + "col2": "fxar2", + "col3": "hortf", + "col4": "v16bj", + "col5": "2rg01", + "col6": "vyokf", + "col7": "ugwr1", + "col8": "y7uty", + "col9": "a8ktl", + "col10": "os62j", + "col11": "fsegq", + "col12": "orn6v", + "col13": "5uk04", + "col14": "9s7gv", + "col15": "89z6h", + "col16": "f1dlu", + "col17": "9o2sn", + "col18": "jegnx", + "col19": "2q4lv", + "col20": "6ph9w", + "col21": "tzm5b", + "col22": "i6r90", + "col23": "ekyz2", + "col24": "kmk6x", + "col25": "642sc", + "col26": "57oz8", + "col27": "am3bv", + "col28": "vjqfd", + "col29": "e87pt", + "col30": "p1l09", + "col31": "4bgs1", + "col32": "6wmg5", + "col33": "pjzdw", + "col34": "ktr6k", + "col35": "lv0wo", + "col36": "gfnz9", + "col37": "mqz6a", + "col38": "k567f", + "col39": "3nbpy", + "col40": "n1qwe", + "col41": "xjaq2", + "col42": "kuljy", + "col43": "m2a6g", + "col44": "hctoq", + "col45": "2xxid", + "col46": "jeord", + "col47": "asjsu", + "col48": "lqvgz", + "col49": "m79fn", + "col50": "wzedf", + "col51": "kak0u", + "col52": "xd7cb", + "col53": "ohczz", + "col54": "r3a1e", + "col55": "20su0", + "col56": "q2b9p", + "col57": "8rrbd", + "col58": "u0ndm", + "col59": "vpac3", + "col60": "74jh9", + "col61": "173ep", + "col62": "jjbnl", + "col63": "92xhn", + "col64": "sfp64", + "col65": "pg0aa", + "col66": "56ozv", + "col67": "t0zvh", + "col68": "jv00k", + "col69": "p0s0k", + "col70": "nu1ji", + "col71": "awvcg", + "col72": "coido", + "col73": "d8s7r", + "col74": "ivs2m", + "col75": "16xtu", + "col76": "keeik", + "col77": "zc2f2", + "col78": "jjz7k", + "col79": "9x2g9", + "col80": "dad36", + "col81": "gkvpw", + "col82": "jpt1b", + "col83": "r7n0e", + "col84": "fhkxc", + "col85": "cqevq", + "col86": "q7j5v", + "col87": "mskyh", + "col88": "2wd5p", + "col89": "91k7e", + "col90": "mq67t", + "col91": "7k09q", + "col92": "1s9ki", + "col93": "0yy8e", + "col94": "xfr5b", + "col95": "c2b43", + "col96": "butla", + "col97": "52srp", + "col98": "hs4kr", + "col99": "6er0e", + "col100": "r9m09", + "col101": "nguwj", + "col102": "pu2er", + "col103": "mm1yf", + "col104": "7dwsv", + "col105": "tlvhn", + "col106": "csdfe", + "col107": "fvj4r", + "col108": "8bfxm", + "col109": "ikvae", + "col110": "qhf0k", + "col111": "t7raa", + "col112": "cppzg", + "col113": "f9l70", + "col114": "d2vs9", + "col115": "0ggma", + "col116": "xylg2", + "col117": "wsj5j", + "col118": "jyh6q", + "col119": "kavwr", + "col120": "hv3re", + "col121": "6tafa", + "col122": "mgi33", + "col123": "uinwo", + "col124": "wg5y8", + "col125": "rw9f0", + "col126": "dvtmm", + "col127": "tjmd2", + "col128": "otei1", + "col129": "gg8md", + "col130": "o5ly3", + "col131": "k2y8g", + "col132": "3clav", + "col133": "q5bbg", + "col134": "jhk82", + "col135": "z8e6z", + "col136": "qt27r", + "col137": "jgfzz", + "col138": "goovs", + "col139": "oqouw", + "col140": "sah16", + "col141": "vbkap", + "col142": "b3de4", + "col143": "2nbxh", + "col144": "gj6cp", + "col145": "bmhcc", + "col146": "kxvy3", + "col147": "xqf0i", + "col148": "wy6h1", + "col149": "pq0mm", + "col150": "4ha5r", + "col151": "xrok7", + "col152": "rsghs", + "col153": "fys72", + "col154": "f81iw", + "col155": "kjfi2", + "col156": "4c9va", + "col157": "7s1uq", + "col158": "twu01", + "col159": "76bl7", + "col160": "vowxo", + "col161": "sjs1d", + "col162": "e0lpt", + "col163": "e7w4v", + "col164": "nmnm1", + "col165": "g8zax", + "col166": "ojw9x", + "col167": "3m198", + "col168": "oul2y", + "col169": "ry8uh", + "col170": "hkhci", + "col171": "3o0g6", + "col172": "g5pw6", + "col173": "w6rxq", + "col174": "kjt8f", + "col175": "erom0", + "col176": "bkwcd", + "col177": "ohojr", + "col178": "o7di0", + "col179": "0ma59", + "col180": "iki6l", + "col181": "3l1xw", + "col182": "paoos", + "col183": "kpksf", + "col184": "kbdaw", + "col185": "mwiin", + "col186": "b7yrh", + "col187": "940r1", + "col188": "m9ie4", + "col189": "auil3", + "col190": "nbqd4", + "col191": "7m8dj", + "col192": "sls45", + "col193": "32iuz", + "col194": "ba596", + "col195": "hoqq8", + "col196": "x45lm", + "col197": "b207l", + "col198": "fhpeu", + "col199": "343gb", + "col200": "f9dw5", + "col201": "7znu8", + "col202": "1xcqi", + "col203": "4ozrz", + "col204": "2rkhv", + "col205": "5be74", + "col206": "jqov5", + "col207": "pbzc7", + "col208": "on8jy", + "col209": "i1cg7", + "col210": "3silr", + "col211": "8ehn8", + "col212": "pk2z3", + "col213": "cukms", + "col214": "vcy3l", + "col215": "hw9hg", + "col216": "oh4ce", + "col217": "ueheo", + "col218": "3xjnp", + "col219": "mzcgt", + "col220": "722k7", + "col221": "0oj1x", + "col222": "g48t9", + "col223": "nmhcf", + "col224": "nj8d3", + "col225": "1ylku", + "col226": "5y436", + "col227": "k8oxu", + "col228": "t6xs2", + "col229": "xxvc8", + "col230": "6tpt5", + "col231": "fugcv", + "col232": "x3cyp", + "col233": "k394x", + "col234": "yznf0", + "col235": "ncijv", + "col236": "7b3t8", + "col237": "vx0za", + "col238": "0ncfl", + "col239": "6tsg3", + "col240": "d81to", + "col241": "ybv71", + "col242": "b5d8i", + "col243": "49r8l", + "col244": "iukm8", + "col245": "gtsi9", + "col246": "h9pjq", + "col247": "c2u8b", + "col248": "yrg1e", + "col249": "yv3rm", + "col250": "snvtd", + "col251": "77cyt", + "col252": "ktx06", + "col253": "2gleq", + "col254": "sybap", + "col255": "61x5f", + "col256": "iiw9n", + "col257": "6mv2n", + "col258": "svkbm", + "col259": "odpbt", + "col260": "nb0uo", + "col261": "a19cv", + "col262": "ft1z9", + "col263": "mvnu5", + "col264": "mw5ur", + "col265": "w7bbj", + "col266": "agqdf", + "col267": "trugw", + "col268": "l0qaw", + "col269": "5pht9", + "col270": "54uh3", + "col271": "2khjd", + "col272": "oi80j", + "col273": "pngm0", + "col274": "sd18n", + "col275": "4gyvw", + "col276": "5csr5", + "col277": "cw3sy", + "col278": "qpao2", + "col279": "qm9hq", + "col280": "z6fd7", + "col281": "21q6k", + "col282": "r2i0y", + "col283": "nr1pm", + "col284": "g6xzj", + "col285": "torhx", + "col286": "zq2fl", + "col287": "bpouw", + "col288": "ywfof", + "col289": "xcgj8", + "col290": "jo6u1", + "col291": "o930s", + "col292": "61i7y", + "col293": "zu844", + "col294": "1kpo2", + "col295": "dx96d", + "col296": "he0j1", + "col297": "8hvul", + "col298": "fa00p", + "col299": "j8qow", + "col300": "bvo71", + "col301": "rn3ua", + "col302": "x6nz5", + "col303": "05234", + "col304": "2tigx", + "col305": "apy8w", + "col306": "e3zgv", + "col307": "wth8z", + "col308": "4s22g", + "col309": "z536v", + "col310": "ncyii", + "col311": "x4ct3", + "col312": "rlhae", + "col313": "ulrot", + "col314": "aqigq", + "col315": "yzl9k", + "col316": "bkij0", + "col317": "9dken", + "col318": "nyrze", + "col319": "12up2", + "col320": "8khur", + "col321": "8pws8", + "col322": "z5xmw", + "col323": "34vnb", + "col324": "jla2i", + "col325": "kfz2z", + "col326": "vehy4", + "col327": "kzlaa", + "col328": "a0k3b", + "col329": "fg3ds", + "col330": "dmi5f", + "col331": "mqfgv", + "col332": "68a5b", + "col333": "9s9mv", + "col334": "506hi", + "col335": "t946z", + "col336": "xrbgh", + "col337": "bfnut", + "col338": "3p0bn", + "col339": "rdz1w", + "col340": "yzt8x", + "col341": "v6ar4", + "col342": "cu0b8", + "col343": "tu1qw", + "col344": "zs9ae", + "col345": "eybyd", + "col346": "c0c60", + "col347": "fydsq", + "col348": "q2ifk", + "col349": "45yq1", + "col350": "jpc3a", + "col351": "dwkqs", + "col352": "nliq0", + "col353": "6lmab", + "col354": "wi3ac", + "col355": "ji2gc", + "col356": "2geqg", + "col357": "7qfzf", + "col358": "pwfu0", + "col359": "yquc7", + "col360": "75iwb", + "col361": "k05u2", + "col362": "4v661", + "col363": "shygd", + "col364": "gk8hk", + "col365": "qr4hq", + "col366": "clhkp", + "col367": "6g2xc", + "col368": "6tdie", + "col369": "uybn5", + "col370": "gw5mu", + "col371": "tmxb0", + "col372": "kully", + "col373": "7k845", + "col374": "tn1id", + "col375": "1ge9a", + "col376": "cgg13", + "col377": "3be7k", + "col378": "ctiuo", + "col379": "77948", + "col380": "fn13p", + "col381": "i3g80", + "col382": "ns4h7", + "col383": "euukw", + "col384": "8jmx5", + "col385": "vdjkq", + "col386": "6dez8", + "col387": "1iko5", + "col388": "f21cy", + "col389": "4zkjl", + "col390": "7jyf2", + "col391": "58icj", + "col392": "8zrid", + "col393": "y0anf", + "col394": "0x6em", + "col395": "qhh7g", + "col396": "xgl4n", + "col397": "ds44n", + "col398": "tfk2h", + "col399": "gk4jk", + "col400": "sqyot", + "col401": "mhfna", + "col402": "1wa5g", + "col403": "46xrp", + "col404": "kvuf3", + "col405": "ftjzz", + "col406": "wdjkc", + "col407": "utsb6", + "col408": "1siwk", + "col409": "7d47d", + "col410": "0qaps", + "col411": "9k0dh", + "col412": "9owrg", + "col413": "1kfno", + "col414": "a3shm", + "col415": "sog7d", + "col416": "oc6sz", + "col417": "bddr0", + "col418": "3r7qc", + "col419": "s23ib", + "col420": "1ksoe", + "col421": "pxxsz", + "col422": "wd2n9", + "col423": "qb806", + "col424": "372na", + "col425": "4eawp", + "col426": "lajr2", + "col427": "5xo0d", + "col428": "lo5bi", + "col429": "l7qm8", + "col430": "kdtwx", + "col431": "k9dqj", + "col432": "ykpzz", + "col433": "5twdo", + "col434": "fb8fl", + "col435": "ntdhv", + "col436": "edmtq", + "col437": "b8s9l", + "col438": "oseyy", + "col439": "fz26c", + "col440": "uzngi", + "col441": "ivi9m", + "col442": "230ek", + "col443": "l30wc", + "col444": "1yji3", + "col445": "g64w8", + "col446": "31snd", + "col447": "ghtzi", + "col448": "i711r", + "col449": "7cgqk", + "col450": "kn8ro", + "col451": "gcvkp", + "col452": "r0xv9", + "col453": "o97zh", + "col454": "ytt83", + "col455": "lacqp", + "col456": "1yrvj", + "col457": "v6qxk", + "col458": "f42g5", + "col459": "t3nro", + "col460": "ra0qc", + "col461": "ejrwv", + "col462": "mv4qb", + "col463": "vzu9r", + "col464": "ntp9b", + "col465": "c6g3s", + "col466": "e0zlf", + "col467": "eheib", + "col468": "mq62y", + "col469": "ri9y3", + "col470": "z0sin", + "col471": "wgwbq", + "col472": "71wux", + "col473": "2jx50", + "col474": "ogh8i", + "col475": "ivr1j", + "col476": "sn0d2", + "col477": "y4073", + "col478": "ourrj", + "col479": "aebrs", + "col480": "163n5", + "col481": "sgbi7", + "col482": "xuwxs", + "col483": "s104m", + "col484": "19zf1", + "col485": "ccqmv", + "col486": "gns3s", + "col487": "izqi1", + "col488": "zkbfg", + "col489": "3rum2", + "col490": "gy9os", + "col491": "a767g", + "col492": "iwdfz", + "col493": "qvzv4", + "col494": "3j398", + "col495": "xhph4", + "col496": "10mh2", + "col497": "ny9wk", + "col498": "apof4", + "col499": "shtwk", + "col500": "ewqu0", + "col501": "903um", + "col502": "vrfu1", + "col503": "cv04s", + "col504": "byezn", + "col505": "w5h3n", + "col506": "z0ab0", + "col507": "os8g7", + "col508": "9a2xn", + "col509": "u1i65", + "col510": "i1q6k", + "col511": "v2h5b", + "col512": "ovke7", + "col513": "0001p", + "col514": "jbbye", + "col515": "qjw9i", + "col516": "bkxww", + "col517": "p9mvb", + "col518": "nf03r", + "col519": "wskyc", + "col520": "v7gec", + "col521": "pxjjt", + "col522": "ccc46", + "col523": "7ssbk", + "col524": "cjxo5", + "col525": "mrph1", + "col526": "zh0ms", + "col527": "4m25z", + "col528": "si9nv", + "col529": "ul0nj", + "col530": "zlh25", + "col531": "7aw28", + "col532": "zfh54", + "col533": "uazo9", + "col534": "gwkap", + "col535": "8bkfk", + "col536": "embw6", + "col537": "plvzb", + "col538": "phycq", + "col539": "7ow5d", + "col540": "ds8ug", + "col541": "emhfl", + "col542": "7tttl", + "col543": "xnpb7", + "col544": "2265d", + "col545": "xzelm", + "col546": "08gjr", + "col547": "6je1p", + "col548": "soc6t", + "col549": "j6xbm", + "col550": "i41en", + "col551": "gyi1i", + "col552": "blcdz", + "col553": "wfuuv", + "col554": "2n05h", + "col555": "0v3ea", + "col556": "4ep8e", + "col557": "sukwz", + "col558": "2f8a7", + "col559": "cjx7r", + "col560": "67rm7", + "col561": "5huqz", + "col562": "6xx4s", + "col563": "lxo7i", + "col564": "25n66", + "col565": "mfp56", + "col566": "g6pkt", + "col567": "ecznz", + "col568": "ef5yx", + "col569": "elo4n", + "col570": "xh9cs", + "col571": "u9821", + "col572": "cz0zg", + "col573": "4pi7r", + "col574": "tvrax", + "col575": "wrah9", + "col576": "azukr", + "col577": "bbph7", + "col578": "7ggxw", + "col579": "hsg9j", + "col580": "inm90", + "col581": "rw09x", + "col582": "8hs98", + "col583": "hflum", + "col584": "verqh", + "col585": "e60d2", + "col586": "ycpoo", + "col587": "b154z", + "col588": "g7vr0", + "col589": "ow56q", + "col590": "6ha1p", + "col591": "d1t42", + "col592": "eepeb", + "col593": "pbyxx", + "col594": "i50r9", + "col595": "6illt", + "col596": "4pjm6", + "col597": "ula16", + "col598": "vdiel", + "col599": "iensu", + "col600": "nzs23", + "col601": "yyyuj", + "col602": "30712", + "col603": "0osg3", + "col604": "mf5qa", + "col605": "rqo77", + "col606": "thlj1", + "col607": "dph45", + "col608": "rtqja", + "col609": "ouurw", + "col610": "csn2h", + "col611": "dl6h2", + "col612": "xgzi9", + "col613": "ddbl8", + "col614": "3dn8d", + "col615": "5d9lh", + "col616": "xcagr", + "col617": "ql6w6", + "col618": "mg5wc", + "col619": "uc58q", + "col620": "1wkim", + "col621": "cy23f", + "col622": "qive9", + "col623": "jg79q", + "col624": "0s0b4", + "col625": "9nj9p", + "col626": "t13u4", + "col627": "lvm5j", + "col628": "ifrdy", + "col629": "k01nv", + "col630": "rb9pv", + "col631": "iyv1z", + "col632": "svjk2", + "col633": "4d77v", + "col634": "eqo4u", + "col635": "lqcog", + "col636": "0wp2j", + "col637": "5osb6", + "col638": "glu6w", + "col639": "5fzf7", + "col640": "86qhp", + "col641": "7q5e8", + "col642": "kxnyq", + "col643": "u8ej4", + "col644": "wftia", + "col645": "vaecw", + "col646": "oi0fi", + "col647": "v8vqa", + "col648": "qbw66", + "col649": "p6lxh", + "col650": "8sar7", + "col651": "59ekr", + "col652": "o0hmk", + "col653": "wns4j", + "col654": "roagq", + "col655": "39zmr", + "col656": "rrlm8", + "col657": "ke2hu", + "col658": "im357", + "col659": "e818k", + "col660": "kny4o", + "col661": "730tu", + "col662": "m8llh", + "col663": "gjtbj", + "col664": "rpfw0", + "col665": "k0wxh", + "col666": "lzkv5", + "col667": "9yt48", + "col668": "mdete", + "col669": "divho", + "col670": "xt7o2", + "col671": "r4vf7", + "col672": "fmxac", + "col673": "mvoso", + "col674": "muezz", + "col675": "mxbmc", + "col676": "1iaeb", + "col677": "c8jgw", + "col678": "1u16v", + "col679": "qlvcn", + "col680": "wl4x5", + "col681": "0amox", + "col682": "k92ki", + "col683": "yyf2a", + "col684": "lgcss", + "col685": "5zyrj", + "col686": "y31t4", + "col687": "78t9z", + "col688": "k18id", + "col689": "wvwp9", + "col690": "4ii8i", + "col691": "531cb", + "col692": "podms", + "col693": "lp4fj", + "col694": "olok0", + "col695": "7nhai", + "col696": "dbzvl", + "col697": "04nma", + "col698": "7ifcj", + "col699": "afm8d", + "col700": "pvhr9", + "col701": "o792a", + "col702": "q6zuo", + "col703": "fdcw9", + "col704": "fzsmr", + "col705": "op78t", + "col706": "l8ibh", + "col707": "6nqpn", + "col708": "xefp6", + "col709": "wnnuw", + "col710": "r0c1u", + "col711": "n76f3", + "col712": "kvl0o", + "col713": "w4elc", + "col714": "ad60s", + "col715": "71pi8", + "col716": "40je6", + "col717": "7ly6z", + "col718": "38oag", + "col719": "2o2dx", + "col720": "i7jvb", + "col721": "hhmti", + "col722": "bg909", + "col723": "wd20u", + "col724": "os31e", + "col725": "08pmi", + "col726": "bejn6", + "col727": "zucwm", + "col728": "ge279", + "col729": "83x01", + "col730": "vbhry", + "col731": "tsalg", + "col732": "36viy", + "col733": "7yzif", + "col734": "jset4", + "col735": "zckt7", + "col736": "ibqna", + "col737": "jofxh", + "col738": "t50gr", + "col739": "c20pa", + "col740": "chm7v", + "col741": "eytza", + "col742": "zfqv1", + "col743": "80y55", + "col744": "m1cin", + "col745": "sg15v", + "col746": "4n395", + "col747": "ygvk7", + "col748": "n9hxt", + "col749": "of4pt", + "col750": "vzbgx", + "col751": "crqnz", + "col752": "6saoz", + "col753": "fmk4r", + "col754": "fnshe", + "col755": "ycho6", + "col756": "tz5pm", + "col757": "g1my0", + "col758": "5bydc", + "col759": "rekkd", + "col760": "97bud", + "col761": "3jdtz", + "col762": "cjie5", + "col763": "bqi0w", + "col764": "sxa7s", + "col765": "lnu72", + "col766": "q2wko", + "col767": "mcvux", + "col768": "1icsz", + "col769": "m49io", + "col770": "g4il0", + "col771": "q4oai", + "col772": "o7ce0", + "col773": "tjnnk", + "col774": "99e9w", + "col775": "eygdc", + "col776": "ffcgv", + "col777": "tkiox", + "col778": "dyiba", + "col779": "w5i88", + "col780": "4l2cf", + "col781": "h5id9", + "col782": "fl3hg", + "col783": "vrhlc", + "col784": "iuic8", + "col785": "pd163", + "col786": "tt0mb", + "col787": "aevar", + "col788": "34qtw", + "col789": "b1rns", + "col790": "rawa4", + "col791": "fskc0", + "col792": "xrup2", + "col793": "6mgpr", + "col794": "9v3ct", + "col795": "d1o9d", + "col796": "m3va2", + "col797": "dnaxq", + "col798": "1mj7f", + "col799": "l5unv", + "col800": "potdd", + "col801": "dfzhe", + "col802": "98jqb", + "col803": "2gb3j", + "col804": "1lakx", + "col805": "v5qr4", + "col806": "n0eig", + "col807": "1mk6w", + "col808": "2tuwm", + "col809": "ye947", + "col810": "tsd08", + "col811": "0o724", + "col812": "bqo97", + "col813": "n0ei0", + "col814": "tpakt", + "col815": "d427f", + "col816": "0moka", + "col817": "2qldd", + "col818": "gc7gj", + "col819": "mbhn9", + "col820": "h0w28", + "col821": "3bl4k", + "col822": "6gwe1", + "col823": "iwkon", + "col824": "2at48", + "col825": "3dsbz", + "col826": "nzxcw", + "col827": "likl2", + "col828": "l74as", + "col829": "pn7i9", + "col830": "7gk89", + "col831": "4zov5", + "col832": "jmi72", + "col833": "g8nni", + "col834": "56wsq", + "col835": "svibx", + "col836": "8x4r2", + "col837": "mja9m", + "col838": "9smn0", + "col839": "v68pi", + "col840": "e791z", + "col841": "58t4a", + "col842": "oxudk", + "col843": "p8r2a", + "col844": "xervr", + "col845": "tchwi", + "col846": "k2ws0", + "col847": "s8ye5", + "col848": "s6f0y", + "col849": "0m7yx", + "col850": "zlopv", + "col851": "erx2g", + "col852": "etbxa", + "col853": "p4v2g", + "col854": "s5bgr", + "col855": "b4prn", + "col856": "0bnq6", + "col857": "r7jpv", + "col858": "0wrmx", + "col859": "qf6pg", + "col860": "dk9c6", + "col861": "a1phz", + "col862": "ejfnu", + "col863": "y2wf0", + "col864": "leg22", + "col865": "f09t4", + "col866": "jovks", + "col867": "cyswt", + "col868": "wu7fo", + "col869": "id04e", + "col870": "avocb", + "col871": "sf81k", + "col872": "lzgr0", + "col873": "j2abv", + "col874": "mhp2h", + "col875": "1lyv3", + "col876": "s2b3d", + "col877": "vv5fy", + "col878": "ju8tr", + "col879": "qyuj4", + "col880": "1os2i", + "col881": "jogsz", + "col882": "r0cf3", + "col883": "9jkix", + "col884": "768y5", + "col885": "4ao5x", + "col886": "yxbgk", + "col887": "eyz10", + "col888": "vk6xs", + "col889": "cqqnv", + "col890": "3rl51", + "col891": "vmo1k", + "col892": "wsnri", + "col893": "wmn64", + "col894": "8vt8m", + "col895": "hhqra", + "col896": "zl5hc", + "col897": "0gpms", + "col898": "95s72", + "col899": "q166g", + "col900": "m561s", + "col901": "qqgje", + "col902": "pcefq", + "col903": "gd82x", + "col904": "qi6iz", + "col905": "90fj0", + "col906": "82hgr", + "col907": "0l6s5", + "col908": "rykmj", + "col909": "1fzm0", + "col910": "w95nj", + "col911": "jjvn6", + "col912": "ibmgg", + "col913": "m13ol", + "col914": "yselb", + "col915": "4jegs", + "col916": "ubt4a", + "col917": "gb50y", + "col918": "aesg7", + "col919": "xq5dd", + "col920": "50k17", + "col921": "an5j1", + "col922": "v0n9y", + "col923": "pb5m9", + "col924": "x6tgt", + "col925": "q8691", + "col926": "34abg", + "col927": "6h9of", + "col928": "9hmdt", + "col929": "fpxk8", + "col930": "frch2", + "col931": "cohle", + "col932": "c31wq", + "col933": "ozm7l", + "col934": "cz0pk", + "col935": "iapiy", + "col936": "dx0t4", + "col937": "ujjxy", + "col938": "g9r62", + "col939": "mte0j", + "col940": "i6k59", + "col941": "mppo5", + "col942": "l778v", + "col943": "1npat", + "col944": "8icwt", + "col945": "prbh6", + "col946": "m6uja", + "col947": "yajel", + "col948": "51t0x", + "col949": "xom4f", + "col950": "v0ndf", + "col951": "o7eim", + "col952": "ezfmj", + "col953": "hh4z8", + "col954": "gmna7", + "col955": "fvjnb", + "col956": "8irs3", + "col957": "jhsc7", + "col958": "eaq9c", + "col959": "23w82", + "col960": "6vnpv", + "col961": "v7h4z", + "col962": "v93ru", + "col963": "75spt", + "col964": "i2gdi", + "col965": "sjzlt", + "col966": "dhyrz", + "col967": "dbwmz", + "col968": "l27nj", + "col969": "ukila", + "col970": "w2i4f", + "col971": "0id36", + "col972": "punzu", + "col973": "5w1lv", + "col974": "ud3wg", + "col975": "imes2", + "col976": "xlsvk", + "col977": "fynxa", + "col978": "7ocen", + "col979": "n3at1", + "col980": "i2eq7", + "col981": "rz5gd", + "col982": "bx5g0", + "col983": "qwfns", + "col984": "dxw1e", + "col985": "380j2", + "col986": "4pvrc", + "col987": "mtkoi", + "col988": "sa4or", + "col989": "mkuy1", + "col990": "fatdo", + "col991": "12l3j", + "col992": "tp8dl", + "col993": "hwfc6", + "col994": "sxq4q", + "col995": "zqmzw", + "col996": "9ksth", + "col997": "rgvh4", + "col998": "ua8fw", + "col999": "qqtm6" + }, + { + "name": "Diann Combs", + "gender": "female", + "col0": "rfa1f", + "col1": "rfpwy", + "col2": "1h1n8", + "col3": "411zj", + "col4": "hjks3", + "col5": "5rtdq", + "col6": "vla4e", + "col7": "tryqs", + "col8": "2l7cb", + "col9": "mp10e", + "col10": "czl17", + "col11": "o4jea", + "col12": "h2z99", + "col13": "yq35y", + "col14": "j9h8c", + "col15": "xpn13", + "col16": "yi76r", + "col17": "ps57z", + "col18": "wflkw", + "col19": "wnhbh", + "col20": "ifs0g", + "col21": "elyan", + "col22": "sm9vg", + "col23": "yxvpo", + "col24": "et3cd", + "col25": "pu09f", + "col26": "ik2ct", + "col27": "ncof3", + "col28": "0zn5p", + "col29": "s9cyt", + "col30": "xkltl", + "col31": "3anzi", + "col32": "zs8vy", + "col33": "p4a9w", + "col34": "jzw8f", + "col35": "dcj28", + "col36": "0056o", + "col37": "feej9", + "col38": "krgw2", + "col39": "1n62j", + "col40": "ctmcd", + "col41": "a0lh4", + "col42": "anqwn", + "col43": "4isl0", + "col44": "5g7g3", + "col45": "dw4c1", + "col46": "tuoyn", + "col47": "cc9pu", + "col48": "otgol", + "col49": "vq963", + "col50": "8kr22", + "col51": "18vjs", + "col52": "fswm6", + "col53": "4lmi0", + "col54": "pq1r1", + "col55": "j5rmj", + "col56": "v6h0i", + "col57": "3ay0d", + "col58": "bkigc", + "col59": "31v2a", + "col60": "ech6v", + "col61": "rqqjh", + "col62": "bb6mu", + "col63": "t3xjz", + "col64": "a73fz", + "col65": "n5m37", + "col66": "ws22r", + "col67": "jn9lx", + "col68": "ruppv", + "col69": "jdl3a", + "col70": "qlzai", + "col71": "fnxog", + "col72": "1bb65", + "col73": "serzf", + "col74": "jicua", + "col75": "drnna", + "col76": "860lx", + "col77": "ynlij", + "col78": "ugtap", + "col79": "aqqzp", + "col80": "yusrb", + "col81": "hwsax", + "col82": "xk8d5", + "col83": "79fdb", + "col84": "m411o", + "col85": "ude3l", + "col86": "dsczc", + "col87": "a1j5k", + "col88": "m86ex", + "col89": "zzyr8", + "col90": "l334x", + "col91": "gfoyd", + "col92": "k0w8a", + "col93": "yrsdk", + "col94": "u88y7", + "col95": "7x7qt", + "col96": "dwfyq", + "col97": "g5v2p", + "col98": "4tzp8", + "col99": "q9gix", + "col100": "eps4m", + "col101": "y3tea", + "col102": "555zo", + "col103": "ejitg", + "col104": "tc30o", + "col105": "43ra0", + "col106": "401c2", + "col107": "vateq", + "col108": "dvb5g", + "col109": "qjadb", + "col110": "kdxxc", + "col111": "uwvay", + "col112": "svdvl", + "col113": "ct6nt", + "col114": "inzqg", + "col115": "w73g8", + "col116": "wu2hj", + "col117": "vci7r", + "col118": "12m35", + "col119": "fqoij", + "col120": "be1gv", + "col121": "581n7", + "col122": "2q46z", + "col123": "aa4cl", + "col124": "8kxb8", + "col125": "123xt", + "col126": "ve7sx", + "col127": "o2ovv", + "col128": "zm8sf", + "col129": "3gqgb", + "col130": "ee02v", + "col131": "styzs", + "col132": "s2rju", + "col133": "qpx26", + "col134": "7zdv3", + "col135": "yjzik", + "col136": "v5yah", + "col137": "m2hib", + "col138": "a3mgx", + "col139": "tgy8x", + "col140": "36qq1", + "col141": "23b7f", + "col142": "376no", + "col143": "gunti", + "col144": "u3bq1", + "col145": "xl3pe", + "col146": "fao6g", + "col147": "fwwrr", + "col148": "gqy0x", + "col149": "yhchr", + "col150": "d19ew", + "col151": "e3rvg", + "col152": "v1u7q", + "col153": "bil3l", + "col154": "hj585", + "col155": "y0h6i", + "col156": "e40nw", + "col157": "0sxcz", + "col158": "ti1j2", + "col159": "cnzq9", + "col160": "egtxm", + "col161": "6phm5", + "col162": "ets27", + "col163": "quezs", + "col164": "3xguf", + "col165": "muvvb", + "col166": "j3d9b", + "col167": "m9bcn", + "col168": "16ggd", + "col169": "3yrt2", + "col170": "k5dhq", + "col171": "sfevd", + "col172": "zdowv", + "col173": "je2lr", + "col174": "rni1y", + "col175": "9zu27", + "col176": "qus7u", + "col177": "o7ck4", + "col178": "tqymf", + "col179": "v4a9h", + "col180": "vj0gf", + "col181": "3j5me", + "col182": "8tolk", + "col183": "fcm5i", + "col184": "n7kaj", + "col185": "exdgx", + "col186": "knpym", + "col187": "7dful", + "col188": "gpes8", + "col189": "6syl3", + "col190": "fkkvt", + "col191": "xbc1r", + "col192": "s66xs", + "col193": "n2gck", + "col194": "88laj", + "col195": "7mukq", + "col196": "j3dfw", + "col197": "kiv5m", + "col198": "5pfm4", + "col199": "tbf3j", + "col200": "1xeai", + "col201": "fnq0p", + "col202": "s0njn", + "col203": "31zqh", + "col204": "ulxpj", + "col205": "1aehr", + "col206": "nsds8", + "col207": "rn1ys", + "col208": "30ku7", + "col209": "1tyo6", + "col210": "7c79x", + "col211": "oknv6", + "col212": "vq5lq", + "col213": "1ulq3", + "col214": "7j43u", + "col215": "28ckq", + "col216": "kk7ke", + "col217": "9lqgy", + "col218": "ohwo8", + "col219": "sks0n", + "col220": "zutdt", + "col221": "ay89d", + "col222": "16daw", + "col223": "wnvw6", + "col224": "ryu78", + "col225": "mu98k", + "col226": "8ikzd", + "col227": "qjt4x", + "col228": "lzieg", + "col229": "g17uv", + "col230": "6o5c1", + "col231": "t905k", + "col232": "43ydt", + "col233": "3vpb2", + "col234": "knp2z", + "col235": "wrlgq", + "col236": "ch8c1", + "col237": "k2b3m", + "col238": "suluv", + "col239": "0wgic", + "col240": "v7ybz", + "col241": "siy2e", + "col242": "oax5w", + "col243": "og354", + "col244": "wnx38", + "col245": "g0tkg", + "col246": "mdxkx", + "col247": "wl61k", + "col248": "t8bqk", + "col249": "4yose", + "col250": "cr8a8", + "col251": "2thf7", + "col252": "gqwfj", + "col253": "ia7r1", + "col254": "ijae0", + "col255": "krbdc", + "col256": "494ys", + "col257": "eac56", + "col258": "li0jt", + "col259": "hwny3", + "col260": "t2bz6", + "col261": "w085x", + "col262": "b6cl8", + "col263": "rgw6m", + "col264": "858wr", + "col265": "zh604", + "col266": "qei5s", + "col267": "6sd1i", + "col268": "5588r", + "col269": "w0qzq", + "col270": "l0hp8", + "col271": "ywgem", + "col272": "chhfe", + "col273": "ulm6p", + "col274": "fsclr", + "col275": "troe1", + "col276": "rm7wj", + "col277": "2jyqe", + "col278": "u6vaj", + "col279": "kgal0", + "col280": "ri9t3", + "col281": "kz0ui", + "col282": "0thlz", + "col283": "gxu6o", + "col284": "4jq4a", + "col285": "yfc8r", + "col286": "eqh34", + "col287": "p6udn", + "col288": "2y5wi", + "col289": "5knm3", + "col290": "2aapb", + "col291": "lo1no", + "col292": "3i03h", + "col293": "7f307", + "col294": "1zohg", + "col295": "b0jn0", + "col296": "t7556", + "col297": "w534u", + "col298": "1hskd", + "col299": "fv729", + "col300": "h1ejj", + "col301": "leqfs", + "col302": "quwc7", + "col303": "i4d9u", + "col304": "jrv9g", + "col305": "1lgie", + "col306": "4wu5c", + "col307": "4661f", + "col308": "q97ol", + "col309": "c48f2", + "col310": "txude", + "col311": "2w1jv", + "col312": "wxyi4", + "col313": "25toc", + "col314": "b7zy4", + "col315": "iduo2", + "col316": "6zbvb", + "col317": "5nlt7", + "col318": "emgi0", + "col319": "i3w51", + "col320": "mfvg3", + "col321": "iwape", + "col322": "a868h", + "col323": "uql18", + "col324": "jmmea", + "col325": "94vpx", + "col326": "967d0", + "col327": "pr0x3", + "col328": "ft5eg", + "col329": "qe6oi", + "col330": "7abqo", + "col331": "ysf4n", + "col332": "cz3uo", + "col333": "p6hol", + "col334": "4ae9j", + "col335": "u05a5", + "col336": "d2qio", + "col337": "tr7u8", + "col338": "m16vi", + "col339": "spm28", + "col340": "mxwkz", + "col341": "r6h0y", + "col342": "2oav0", + "col343": "tt2rh", + "col344": "lnjuf", + "col345": "77qdc", + "col346": "4hvmt", + "col347": "389fl", + "col348": "tlc35", + "col349": "xmpp9", + "col350": "hrv3n", + "col351": "v9b61", + "col352": "aujm5", + "col353": "zvdhd", + "col354": "t6aje", + "col355": "xkcpa", + "col356": "w4bs2", + "col357": "zpt2g", + "col358": "ne4ew", + "col359": "q1ttk", + "col360": "2dgop", + "col361": "aw61u", + "col362": "keb0l", + "col363": "19n5b", + "col364": "x01le", + "col365": "95hnw", + "col366": "533y8", + "col367": "a6ek5", + "col368": "hm1pf", + "col369": "unz14", + "col370": "q7gkj", + "col371": "nn6ji", + "col372": "a4xsa", + "col373": "7j198", + "col374": "itr72", + "col375": "77lt1", + "col376": "7yd0n", + "col377": "2reyt", + "col378": "czdp9", + "col379": "l683b", + "col380": "immhe", + "col381": "0u3eg", + "col382": "jdn8x", + "col383": "kpwxv", + "col384": "rqlxu", + "col385": "rdefj", + "col386": "f5jrh", + "col387": "iz5v2", + "col388": "w1ueg", + "col389": "l0kyw", + "col390": "i48yz", + "col391": "9ue89", + "col392": "zu96f", + "col393": "coaln", + "col394": "a9379", + "col395": "p8u68", + "col396": "a0fxk", + "col397": "t9wrf", + "col398": "ep6dz", + "col399": "99n7v", + "col400": "wfu1j", + "col401": "7vlzr", + "col402": "60iwv", + "col403": "eyelp", + "col404": "ug01y", + "col405": "4rh4z", + "col406": "xw9my", + "col407": "wj1r1", + "col408": "eyhc7", + "col409": "tfwhz", + "col410": "uzatp", + "col411": "gxmq2", + "col412": "nyhs0", + "col413": "u40e2", + "col414": "3fkez", + "col415": "u4em7", + "col416": "axnjf", + "col417": "ex520", + "col418": "mcmz2", + "col419": "kazoo", + "col420": "cn90k", + "col421": "ixwxv", + "col422": "2kysb", + "col423": "h9cjk", + "col424": "uvpjj", + "col425": "qu25x", + "col426": "imw1d", + "col427": "owin3", + "col428": "fcxwq", + "col429": "aszoi", + "col430": "70cqz", + "col431": "32exu", + "col432": "64o8y", + "col433": "axs18", + "col434": "gj4lm", + "col435": "hbblm", + "col436": "cyxp6", + "col437": "1yv9e", + "col438": "s0162", + "col439": "r4kqn", + "col440": "icuzt", + "col441": "jf4q7", + "col442": "7ddpr", + "col443": "or90b", + "col444": "g8n3z", + "col445": "443hl", + "col446": "efviq", + "col447": "kmmnn", + "col448": "snoi5", + "col449": "8cmmi", + "col450": "sbs28", + "col451": "msv7e", + "col452": "cka99", + "col453": "rmq1j", + "col454": "6qgsw", + "col455": "nwq8s", + "col456": "cz0ae", + "col457": "cz7fw", + "col458": "d7l6g", + "col459": "norf3", + "col460": "rkbgu", + "col461": "1pq97", + "col462": "2o6jx", + "col463": "sldj5", + "col464": "qz38x", + "col465": "y5bhu", + "col466": "7w9cr", + "col467": "67duw", + "col468": "8jd89", + "col469": "e0367", + "col470": "6bjw7", + "col471": "k40q5", + "col472": "hz4yn", + "col473": "id7c4", + "col474": "mkbco", + "col475": "r0bf3", + "col476": "2tj80", + "col477": "pqnpu", + "col478": "vsl6f", + "col479": "09c93", + "col480": "y0n44", + "col481": "u55fu", + "col482": "9wtuq", + "col483": "lcqvi", + "col484": "gk2dv", + "col485": "qhwl1", + "col486": "cjbbl", + "col487": "zsoi7", + "col488": "1jlyf", + "col489": "57uop", + "col490": "53fav", + "col491": "fn9ad", + "col492": "tyko8", + "col493": "q68j7", + "col494": "i4q4t", + "col495": "v60ij", + "col496": "qnqyi", + "col497": "x8wsr", + "col498": "275fg", + "col499": "7cxdz", + "col500": "q17bm", + "col501": "vogqu", + "col502": "ixweq", + "col503": "lazae", + "col504": "7ag4j", + "col505": "o3sqm", + "col506": "u28g2", + "col507": "03149", + "col508": "ekuny", + "col509": "6erwt", + "col510": "fgsqi", + "col511": "5kt4k", + "col512": "t4t6c", + "col513": "krjrw", + "col514": "en2mc", + "col515": "wxwew", + "col516": "iuprx", + "col517": "5iow7", + "col518": "v12qj", + "col519": "q78pf", + "col520": "r7uw5", + "col521": "257az", + "col522": "hfv3a", + "col523": "dmcqh", + "col524": "u1ml5", + "col525": "xg432", + "col526": "lpuys", + "col527": "n3st3", + "col528": "ciz9b", + "col529": "5pbb1", + "col530": "2v2n4", + "col531": "krukk", + "col532": "dvpcq", + "col533": "3c16g", + "col534": "qcic7", + "col535": "zjuk4", + "col536": "lxso1", + "col537": "jawjk", + "col538": "4dzty", + "col539": "k368m", + "col540": "59r37", + "col541": "rud6h", + "col542": "75v9q", + "col543": "irahc", + "col544": "7drdo", + "col545": "mqof0", + "col546": "3ix32", + "col547": "wfijq", + "col548": "erm2g", + "col549": "9vh6r", + "col550": "l0i6n", + "col551": "mua7v", + "col552": "bledq", + "col553": "x7mcm", + "col554": "r1fji", + "col555": "4g0c4", + "col556": "c4gye", + "col557": "2tjas", + "col558": "y4vls", + "col559": "nxpzx", + "col560": "ecgy9", + "col561": "sjpjw", + "col562": "ifzlh", + "col563": "talt2", + "col564": "0u96w", + "col565": "x5xi0", + "col566": "9quj8", + "col567": "hbyqo", + "col568": "ibjvx", + "col569": "tt1d0", + "col570": "ayk6v", + "col571": "l40he", + "col572": "2bfk6", + "col573": "17c3y", + "col574": "akltp", + "col575": "nkg9x", + "col576": "w3y0m", + "col577": "8sps7", + "col578": "702no", + "col579": "6ukar", + "col580": "dua7e", + "col581": "a5kt0", + "col582": "pg983", + "col583": "6nijr", + "col584": "omui0", + "col585": "74rgk", + "col586": "e6s8n", + "col587": "74mnj", + "col588": "s2hmy", + "col589": "374ij", + "col590": "4vzm9", + "col591": "de76w", + "col592": "01qqb", + "col593": "0grfw", + "col594": "bsqzz", + "col595": "rw0r2", + "col596": "e3yft", + "col597": "sfoxy", + "col598": "oc4j1", + "col599": "yr98e", + "col600": "mg8sj", + "col601": "5s8z1", + "col602": "55xoi", + "col603": "h66q7", + "col604": "x10th", + "col605": "vjliz", + "col606": "oq1z0", + "col607": "v2uql", + "col608": "rez0r", + "col609": "h26bg", + "col610": "1nvo8", + "col611": "zqbug", + "col612": "ki2ix", + "col613": "owvmo", + "col614": "0mt8e", + "col615": "u95ht", + "col616": "m8x3y", + "col617": "ylg3h", + "col618": "f9psk", + "col619": "uv09s", + "col620": "ztw4o", + "col621": "5b2ve", + "col622": "4tuvg", + "col623": "91qtw", + "col624": "t23an", + "col625": "20yrw", + "col626": "dywkj", + "col627": "rnrhs", + "col628": "rlffj", + "col629": "rfv5d", + "col630": "cbwft", + "col631": "fxsmw", + "col632": "kk4hs", + "col633": "bs6rt", + "col634": "gzdq0", + "col635": "w15tj", + "col636": "5ou7h", + "col637": "jeax0", + "col638": "tbc45", + "col639": "u2d8c", + "col640": "d7qky", + "col641": "ft7op", + "col642": "ei3mg", + "col643": "m2ie5", + "col644": "i008v", + "col645": "3n8at", + "col646": "nbi52", + "col647": "j4bqr", + "col648": "imo0f", + "col649": "mui4b", + "col650": "uws0n", + "col651": "cuzh2", + "col652": "mmhf7", + "col653": "tjfvh", + "col654": "3w803", + "col655": "vpkkr", + "col656": "tuz8r", + "col657": "ys41o", + "col658": "l3olw", + "col659": "t83n0", + "col660": "wu38k", + "col661": "tngfb", + "col662": "vrl3f", + "col663": "9cpsd", + "col664": "yzw88", + "col665": "k9cbt", + "col666": "8j98r", + "col667": "68sbv", + "col668": "et1sx", + "col669": "g6ueq", + "col670": "5h6b7", + "col671": "uycfr", + "col672": "3z0u3", + "col673": "2e7de", + "col674": "q636s", + "col675": "pligb", + "col676": "czfqi", + "col677": "88lh8", + "col678": "7bza2", + "col679": "6dqjv", + "col680": "ixx30", + "col681": "bqq10", + "col682": "eot35", + "col683": "dqn9x", + "col684": "dyj0l", + "col685": "p8a5h", + "col686": "5fzw4", + "col687": "kmoey", + "col688": "57ero", + "col689": "y265d", + "col690": "pu557", + "col691": "18txf", + "col692": "qi2fb", + "col693": "y4w0n", + "col694": "5g1ls", + "col695": "4og8g", + "col696": "5o8pr", + "col697": "3npn3", + "col698": "xvpvk", + "col699": "o40m3", + "col700": "jtck9", + "col701": "039ww", + "col702": "vpam8", + "col703": "1agnk", + "col704": "i7fen", + "col705": "2wzkd", + "col706": "xfw4g", + "col707": "vtb51", + "col708": "itfz8", + "col709": "zw16m", + "col710": "b1c8p", + "col711": "j27gh", + "col712": "2qnxp", + "col713": "kly21", + "col714": "846es", + "col715": "qig9z", + "col716": "nb926", + "col717": "d1j2c", + "col718": "u3qiu", + "col719": "jsazf", + "col720": "es964", + "col721": "tilt9", + "col722": "x2lep", + "col723": "ddmeq", + "col724": "prbky", + "col725": "dictv", + "col726": "apvun", + "col727": "71zrx", + "col728": "6izz4", + "col729": "jv13u", + "col730": "rx0y1", + "col731": "av2au", + "col732": "2we9y", + "col733": "ut8hf", + "col734": "vi1ey", + "col735": "0jme6", + "col736": "v0d8j", + "col737": "nggv1", + "col738": "l6jzr", + "col739": "umdwa", + "col740": "b65e6", + "col741": "vbv6s", + "col742": "la5k7", + "col743": "3lg2w", + "col744": "pv2vq", + "col745": "wir09", + "col746": "65ioj", + "col747": "0c4t2", + "col748": "9pfc4", + "col749": "fi58h", + "col750": "7kejf", + "col751": "kivjb", + "col752": "95hbm", + "col753": "u2uae", + "col754": "qm0n2", + "col755": "63pfd", + "col756": "8pr2u", + "col757": "r1kfz", + "col758": "3elll", + "col759": "2wuiw", + "col760": "q16ni", + "col761": "cvehi", + "col762": "k7ene", + "col763": "381gd", + "col764": "vk3v0", + "col765": "pe47h", + "col766": "9f82v", + "col767": "zgcsh", + "col768": "8pdym", + "col769": "tj5u0", + "col770": "ofhlx", + "col771": "ni2ep", + "col772": "1vz12", + "col773": "cytbz", + "col774": "egl6l", + "col775": "bwl8u", + "col776": "lokg5", + "col777": "2m5fo", + "col778": "qptzu", + "col779": "wqbzq", + "col780": "ytaq9", + "col781": "69v5t", + "col782": "kseh3", + "col783": "5dmfv", + "col784": "2vfb8", + "col785": "dtyig", + "col786": "hje22", + "col787": "8ln2v", + "col788": "oifs2", + "col789": "bbd8q", + "col790": "dxacx", + "col791": "o98o6", + "col792": "2pb21", + "col793": "ih9a4", + "col794": "j0bqw", + "col795": "5o665", + "col796": "ik6ej", + "col797": "3g3x3", + "col798": "4we1j", + "col799": "d9u98", + "col800": "ssagp", + "col801": "sixi1", + "col802": "dl3sq", + "col803": "crgk5", + "col804": "rpnfr", + "col805": "ivhbx", + "col806": "el2y2", + "col807": "0ne2a", + "col808": "ryiq7", + "col809": "ps7i6", + "col810": "19pdb", + "col811": "nlgqf", + "col812": "6gfk0", + "col813": "5jgue", + "col814": "747up", + "col815": "uv84n", + "col816": "cinq6", + "col817": "x5fxc", + "col818": "o3l8i", + "col819": "4qw3v", + "col820": "izx4g", + "col821": "jlkvn", + "col822": "8uhbd", + "col823": "wv51i", + "col824": "8fqt3", + "col825": "lev5v", + "col826": "1s3h7", + "col827": "nd17c", + "col828": "olcwe", + "col829": "uw3u1", + "col830": "h0bh9", + "col831": "0403o", + "col832": "6b8c9", + "col833": "r8mhh", + "col834": "4m2r5", + "col835": "kbpc1", + "col836": "qmdad", + "col837": "glx8t", + "col838": "7wi5n", + "col839": "g9xuu", + "col840": "vgpoo", + "col841": "x298a", + "col842": "xbgme", + "col843": "ssyoi", + "col844": "2ujob", + "col845": "kquv3", + "col846": "vx3r5", + "col847": "bx92n", + "col848": "va5sy", + "col849": "6bt8l", + "col850": "gfss9", + "col851": "z483h", + "col852": "efyc4", + "col853": "uwy8g", + "col854": "dsqjj", + "col855": "hj59i", + "col856": "w52xb", + "col857": "t81dm", + "col858": "5supj", + "col859": "1qyux", + "col860": "gz5bk", + "col861": "6qvhg", + "col862": "glhtr", + "col863": "6p7zg", + "col864": "xyak7", + "col865": "2vgbs", + "col866": "aw5h1", + "col867": "ukp84", + "col868": "jywa5", + "col869": "m03s8", + "col870": "ny8m3", + "col871": "oym32", + "col872": "lrxet", + "col873": "ero7i", + "col874": "3iy02", + "col875": "gslod", + "col876": "cp8ix", + "col877": "xsyam", + "col878": "lzd3h", + "col879": "yujzj", + "col880": "631kg", + "col881": "tqasw", + "col882": "lc03s", + "col883": "35t2z", + "col884": "imy0f", + "col885": "rgzf4", + "col886": "8hlsq", + "col887": "lka56", + "col888": "w1c21", + "col889": "crbsb", + "col890": "6zp0t", + "col891": "uq5fe", + "col892": "dwaye", + "col893": "qrlb0", + "col894": "ku0rm", + "col895": "m3pwl", + "col896": "mknh1", + "col897": "m2gzf", + "col898": "sna79", + "col899": "vixke", + "col900": "3pkq2", + "col901": "a4b1e", + "col902": "i6h1x", + "col903": "1lv93", + "col904": "u8net", + "col905": "8isba", + "col906": "clcw0", + "col907": "s6yrp", + "col908": "2q1ad", + "col909": "8dtvv", + "col910": "n1a3d", + "col911": "4xmo6", + "col912": "o1u5t", + "col913": "2nq3y", + "col914": "xdehw", + "col915": "gym3m", + "col916": "2fm35", + "col917": "cfd8s", + "col918": "eyytl", + "col919": "k9p06", + "col920": "tld3e", + "col921": "fspyj", + "col922": "rnn9h", + "col923": "c9yfb", + "col924": "7oo1c", + "col925": "p8yyu", + "col926": "ckuox", + "col927": "trjyr", + "col928": "xh71f", + "col929": "pbd5s", + "col930": "b70w8", + "col931": "jfgp2", + "col932": "g3bhz", + "col933": "uyvmf", + "col934": "f1kqf", + "col935": "vtprb", + "col936": "jdulc", + "col937": "qr7f4", + "col938": "k1kvf", + "col939": "3047u", + "col940": "9xx6z", + "col941": "asuxx", + "col942": "fmtrb", + "col943": "bnxpf", + "col944": "hij3w", + "col945": "vtxx0", + "col946": "ria6k", + "col947": "1k6uf", + "col948": "5zxd4", + "col949": "clzwo", + "col950": "w81cw", + "col951": "ghe1e", + "col952": "7b8a3", + "col953": "us0a7", + "col954": "me9e3", + "col955": "rcchn", + "col956": "6m1w9", + "col957": "uugub", + "col958": "0zg0r", + "col959": "pfaoj", + "col960": "qaesc", + "col961": "o8735", + "col962": "o6xqs", + "col963": "e5exp", + "col964": "vrbkh", + "col965": "v37oo", + "col966": "6lo6a", + "col967": "q712o", + "col968": "22g7l", + "col969": "7hird", + "col970": "77dhz", + "col971": "rgysb", + "col972": "7t6kq", + "col973": "gkxql", + "col974": "8xatw", + "col975": "reo5n", + "col976": "vx830", + "col977": "4ilky", + "col978": "lihd3", + "col979": "chfos", + "col980": "z9inm", + "col981": "dh01p", + "col982": "casp0", + "col983": "ddzpt", + "col984": "s66sl", + "col985": "mj4mk", + "col986": "jep04", + "col987": "b8ivk", + "col988": "m4wq3", + "col989": "v3ke2", + "col990": "m5wkn", + "col991": "lz240", + "col992": "u20lh", + "col993": "s21yr", + "col994": "291km", + "col995": "f3bkj", + "col996": "yqh8d", + "col997": "qwxdw", + "col998": "lr5rg", + "col999": "7arf5" + }, + { + "name": "Janet Rivas", + "gender": "female", + "col0": "9uodm", + "col1": "awy6m", + "col2": "4jau4", + "col3": "mwbpy", + "col4": "oheau", + "col5": "88y44", + "col6": "8pezl", + "col7": "sls3s", + "col8": "pyh1y", + "col9": "mwyrc", + "col10": "p5gnx", + "col11": "mlchc", + "col12": "0tj97", + "col13": "giwsp", + "col14": "x0rgt", + "col15": "6d748", + "col16": "x1th5", + "col17": "bge7o", + "col18": "cdqoq", + "col19": "hdoxr", + "col20": "4vnrt", + "col21": "as9bh", + "col22": "3lm7x", + "col23": "htlyn", + "col24": "q9xag", + "col25": "up1c1", + "col26": "vixmn", + "col27": "cog2j", + "col28": "md8vt", + "col29": "vxvel", + "col30": "ke5vw", + "col31": "1ce8d", + "col32": "vrgem", + "col33": "ps6ui", + "col34": "n9u1v", + "col35": "53x3k", + "col36": "w63vo", + "col37": "06uyj", + "col38": "ye9rj", + "col39": "t1v5z", + "col40": "e7jjf", + "col41": "elgzs", + "col42": "2jaaw", + "col43": "9a566", + "col44": "xvjor", + "col45": "jvwy9", + "col46": "978iw", + "col47": "36f89", + "col48": "nd5nt", + "col49": "o440f", + "col50": "53xw2", + "col51": "1f788", + "col52": "ac7ny", + "col53": "5mh8x", + "col54": "bvx40", + "col55": "fcq09", + "col56": "uq2v5", + "col57": "21hq5", + "col58": "nevyf", + "col59": "23b6m", + "col60": "qejpl", + "col61": "o7qnp", + "col62": "6ukw9", + "col63": "sodwf", + "col64": "yc2u0", + "col65": "q9o3g", + "col66": "fbh1z", + "col67": "qwrnr", + "col68": "qh2ec", + "col69": "ibbct", + "col70": "psirw", + "col71": "558wq", + "col72": "yt4p2", + "col73": "8psbh", + "col74": "j4fu1", + "col75": "ww8jr", + "col76": "4xtuk", + "col77": "e5q42", + "col78": "wyd1a", + "col79": "a4qzs", + "col80": "l4irw", + "col81": "qznx9", + "col82": "wnaty", + "col83": "w2nub", + "col84": "fa0p8", + "col85": "38d90", + "col86": "t80i0", + "col87": "b5m63", + "col88": "ruh4o", + "col89": "uis6p", + "col90": "n1mj8", + "col91": "rpgmq", + "col92": "vvhp4", + "col93": "drb46", + "col94": "2jgwr", + "col95": "ywwjc", + "col96": "opmcq", + "col97": "r6v08", + "col98": "osd34", + "col99": "cw53y", + "col100": "b6d5r", + "col101": "l9rsy", + "col102": "sa39v", + "col103": "h4mc7", + "col104": "rlcxt", + "col105": "pdf33", + "col106": "tjny8", + "col107": "pidss", + "col108": "m0iat", + "col109": "2px40", + "col110": "002bt", + "col111": "ncd72", + "col112": "ws23a", + "col113": "x437h", + "col114": "dmczx", + "col115": "aynax", + "col116": "apmam", + "col117": "hcfa2", + "col118": "ciizz", + "col119": "xmk76", + "col120": "277yf", + "col121": "j55cb", + "col122": "reyvu", + "col123": "qa45t", + "col124": "aouct", + "col125": "62l9w", + "col126": "n6n2y", + "col127": "dl638", + "col128": "ffbil", + "col129": "lns63", + "col130": "n6msr", + "col131": "ntm2v", + "col132": "izhzm", + "col133": "gpmwy", + "col134": "xeg6t", + "col135": "7use8", + "col136": "0rybz", + "col137": "ju3x8", + "col138": "wkx75", + "col139": "sm56h", + "col140": "n96mp", + "col141": "r4lul", + "col142": "noywc", + "col143": "b9v5y", + "col144": "3ggt3", + "col145": "g3cf2", + "col146": "pnck2", + "col147": "f7gc1", + "col148": "niw4d", + "col149": "8z3i5", + "col150": "k6qm4", + "col151": "fu6h2", + "col152": "1s5d6", + "col153": "50l1d", + "col154": "99jv6", + "col155": "0ht6x", + "col156": "bdtcr", + "col157": "wx1uu", + "col158": "y8yan", + "col159": "21qnj", + "col160": "tbj8z", + "col161": "sidk5", + "col162": "0lrbx", + "col163": "pui97", + "col164": "60ete", + "col165": "j6ydv", + "col166": "8ey0d", + "col167": "r5go7", + "col168": "gnxaw", + "col169": "czfnd", + "col170": "d9x1o", + "col171": "6px0r", + "col172": "wqmv3", + "col173": "2b8zi", + "col174": "om5gn", + "col175": "on1vz", + "col176": "ejy9s", + "col177": "r1yg9", + "col178": "o57uu", + "col179": "zrx6z", + "col180": "mq50p", + "col181": "xfzzl", + "col182": "d0o3l", + "col183": "qnd0p", + "col184": "9xzvc", + "col185": "o1xa9", + "col186": "0odq0", + "col187": "mlc0c", + "col188": "1ixg4", + "col189": "zbabe", + "col190": "tq961", + "col191": "efajp", + "col192": "h5ebj", + "col193": "t8hkw", + "col194": "t1882", + "col195": "d215c", + "col196": "31cib", + "col197": "o7pqy", + "col198": "xtn5s", + "col199": "1gcxq", + "col200": "r1ey4", + "col201": "6htat", + "col202": "e8au2", + "col203": "vdnsx", + "col204": "73988", + "col205": "46srf", + "col206": "e14nd", + "col207": "2znpy", + "col208": "btxt2", + "col209": "agdjb", + "col210": "ciehj", + "col211": "hinyi", + "col212": "rtkyp", + "col213": "a385s", + "col214": "1xd3k", + "col215": "xr0w3", + "col216": "ete48", + "col217": "jinz1", + "col218": "n78xb", + "col219": "pg4kz", + "col220": "9iow9", + "col221": "i0um2", + "col222": "kph89", + "col223": "1l7fb", + "col224": "8nag7", + "col225": "03hk3", + "col226": "00qk8", + "col227": "wd5z0", + "col228": "kq3rr", + "col229": "ipvcs", + "col230": "te7px", + "col231": "gv4ha", + "col232": "dr3kr", + "col233": "yg8y3", + "col234": "b17xy", + "col235": "1yng6", + "col236": "k0zkk", + "col237": "0j0j2", + "col238": "4n4ep", + "col239": "ceg22", + "col240": "yeih6", + "col241": "yvcde", + "col242": "1myw3", + "col243": "5y36m", + "col244": "xkbzc", + "col245": "77gua", + "col246": "cxkgg", + "col247": "gija4", + "col248": "zpxwu", + "col249": "3w2qg", + "col250": "2jpgj", + "col251": "132z2", + "col252": "wm4ss", + "col253": "inzym", + "col254": "k5hhm", + "col255": "vnnpq", + "col256": "qupjo", + "col257": "sloy9", + "col258": "bt6wb", + "col259": "s0ivj", + "col260": "xtx4q", + "col261": "hh3u0", + "col262": "jdhz4", + "col263": "jkeb0", + "col264": "xqyxf", + "col265": "82115", + "col266": "ikyj6", + "col267": "kiwh0", + "col268": "kmacu", + "col269": "8qdil", + "col270": "4ueuu", + "col271": "dymuw", + "col272": "l0hnj", + "col273": "tv7fd", + "col274": "sbo2x", + "col275": "22g1q", + "col276": "o06e7", + "col277": "a5cpj", + "col278": "nd1i3", + "col279": "jecds", + "col280": "5rrjt", + "col281": "zhhb9", + "col282": "orz9i", + "col283": "7v7qq", + "col284": "378th", + "col285": "xio94", + "col286": "9ppdd", + "col287": "m5gjb", + "col288": "2sc2v", + "col289": "t3tn1", + "col290": "w54gj", + "col291": "ljn0q", + "col292": "0eqdz", + "col293": "rwv1d", + "col294": "znb7c", + "col295": "hh2yw", + "col296": "7c305", + "col297": "fm6rs", + "col298": "02v0t", + "col299": "i6a5u", + "col300": "ywihy", + "col301": "fudl9", + "col302": "uvw2s", + "col303": "c5na6", + "col304": "ivxml", + "col305": "7jrfw", + "col306": "6p3nn", + "col307": "s591s", + "col308": "9d794", + "col309": "1y56g", + "col310": "al1yp", + "col311": "q3el5", + "col312": "eu0r9", + "col313": "omk5l", + "col314": "cvv73", + "col315": "m4s89", + "col316": "ev0ps", + "col317": "0gmkk", + "col318": "z8bzv", + "col319": "cbx3g", + "col320": "s5d0v", + "col321": "hlj1c", + "col322": "38t09", + "col323": "st5qg", + "col324": "gyb8j", + "col325": "h6h78", + "col326": "0zsxv", + "col327": "yu89z", + "col328": "67pfs", + "col329": "u57j0", + "col330": "h7sej", + "col331": "1l9dz", + "col332": "9b9pf", + "col333": "nvffv", + "col334": "53eqh", + "col335": "y9fec", + "col336": "qpyca", + "col337": "ivj3h", + "col338": "8f6v2", + "col339": "slwyc", + "col340": "blg6l", + "col341": "os6h0", + "col342": "ioew3", + "col343": "a90ix", + "col344": "wt1uq", + "col345": "turl5", + "col346": "e8jfo", + "col347": "4b0c8", + "col348": "bm1gw", + "col349": "v4vuc", + "col350": "7r1n4", + "col351": "3hyhl", + "col352": "qznt3", + "col353": "ebf99", + "col354": "iytyf", + "col355": "4b5oc", + "col356": "15ms3", + "col357": "bvzg4", + "col358": "ztms9", + "col359": "xlrrh", + "col360": "0on8e", + "col361": "ro54f", + "col362": "1478f", + "col363": "356dp", + "col364": "iazae", + "col365": "069mv", + "col366": "1h52s", + "col367": "uous8", + "col368": "2w5rt", + "col369": "gcwm5", + "col370": "09ija", + "col371": "tmbne", + "col372": "331mc", + "col373": "x39y9", + "col374": "xbpq1", + "col375": "ht6v1", + "col376": "jp3yb", + "col377": "v7w2b", + "col378": "15876", + "col379": "ymzl5", + "col380": "wy297", + "col381": "a575a", + "col382": "k2buq", + "col383": "28jp4", + "col384": "bevbc", + "col385": "9h41b", + "col386": "d4wd9", + "col387": "i27vx", + "col388": "ubckg", + "col389": "57n98", + "col390": "fpzns", + "col391": "3nt3f", + "col392": "usm0l", + "col393": "l3c6m", + "col394": "6hr6q", + "col395": "ydvs5", + "col396": "2j1oo", + "col397": "xbtbx", + "col398": "8f4uz", + "col399": "shkfu", + "col400": "rs5td", + "col401": "2wr0n", + "col402": "g4qp6", + "col403": "y3c0z", + "col404": "37xew", + "col405": "h3cyq", + "col406": "64am6", + "col407": "0r7qm", + "col408": "agwy0", + "col409": "5ura0", + "col410": "36wpt", + "col411": "nvszp", + "col412": "lmpy5", + "col413": "ayl7w", + "col414": "2wmya", + "col415": "9st70", + "col416": "fkeyj", + "col417": "uv9kg", + "col418": "jw5bb", + "col419": "38xwo", + "col420": "skykb", + "col421": "es1pl", + "col422": "jinbi", + "col423": "j1fmm", + "col424": "m6lq3", + "col425": "wij27", + "col426": "nno7b", + "col427": "t9tst", + "col428": "ua0b8", + "col429": "9s07l", + "col430": "a5y45", + "col431": "cg6mw", + "col432": "vswrx", + "col433": "fnygz", + "col434": "v8fxa", + "col435": "ljpql", + "col436": "9bpcy", + "col437": "964s8", + "col438": "88igb", + "col439": "jonas", + "col440": "8nweg", + "col441": "mf7r9", + "col442": "lki9a", + "col443": "4ugn2", + "col444": "958jv", + "col445": "d96za", + "col446": "u97oz", + "col447": "n9bwb", + "col448": "pukq0", + "col449": "izi9i", + "col450": "mamy8", + "col451": "27xc5", + "col452": "9t7j9", + "col453": "coc0b", + "col454": "7575y", + "col455": "29lb2", + "col456": "ev3c1", + "col457": "k0mfc", + "col458": "bubkg", + "col459": "ie1c0", + "col460": "mzfn6", + "col461": "a7ytx", + "col462": "8irj9", + "col463": "kff3b", + "col464": "mppj9", + "col465": "quevi", + "col466": "dnq1n", + "col467": "spvq4", + "col468": "ujqx0", + "col469": "sp4lt", + "col470": "nv6ab", + "col471": "ghbr6", + "col472": "nexx4", + "col473": "cs11v", + "col474": "l0010", + "col475": "pkq8z", + "col476": "a6qou", + "col477": "gh3dl", + "col478": "m7gti", + "col479": "qee4p", + "col480": "3yejd", + "col481": "lhhu6", + "col482": "lz0vb", + "col483": "29ipm", + "col484": "i83or", + "col485": "hyk1r", + "col486": "x6lr5", + "col487": "lrfff", + "col488": "alcac", + "col489": "s5aaa", + "col490": "pidn4", + "col491": "j44nd", + "col492": "dg49f", + "col493": "35q81", + "col494": "s7m8m", + "col495": "wfehd", + "col496": "sen72", + "col497": "hdgn0", + "col498": "pd9cl", + "col499": "av7oi", + "col500": "0gbzn", + "col501": "mj68n", + "col502": "ftutg", + "col503": "dfrqy", + "col504": "wjmnr", + "col505": "mdu4q", + "col506": "khxra", + "col507": "7vdva", + "col508": "ctgxa", + "col509": "ecuxl", + "col510": "zalqu", + "col511": "dinrq", + "col512": "yzzsc", + "col513": "x3jl7", + "col514": "fasnr", + "col515": "tyve9", + "col516": "u4rbu", + "col517": "o12qd", + "col518": "46gj2", + "col519": "d220n", + "col520": "0984s", + "col521": "m4uoo", + "col522": "swomv", + "col523": "catca", + "col524": "wqyzc", + "col525": "5eyss", + "col526": "et0ik", + "col527": "3euqy", + "col528": "lzl4n", + "col529": "cv474", + "col530": "nf2sl", + "col531": "cjk81", + "col532": "1cr6c", + "col533": "p8csh", + "col534": "nn97q", + "col535": "1gwq3", + "col536": "jrk5y", + "col537": "8to03", + "col538": "zsujj", + "col539": "m839q", + "col540": "y0fj0", + "col541": "su32u", + "col542": "47i83", + "col543": "8whwz", + "col544": "dfjzs", + "col545": "mbbff", + "col546": "vd7j3", + "col547": "207x8", + "col548": "bm6qc", + "col549": "cu0ka", + "col550": "l0314", + "col551": "svhxc", + "col552": "y9tc9", + "col553": "5k42p", + "col554": "x0sbr", + "col555": "yagl5", + "col556": "ov2uw", + "col557": "9hfnx", + "col558": "f1y5p", + "col559": "flu5k", + "col560": "rikac", + "col561": "8mb9s", + "col562": "lzo5k", + "col563": "0wfha", + "col564": "grew4", + "col565": "o7ugh", + "col566": "uw8eh", + "col567": "k6scp", + "col568": "vzjdz", + "col569": "wfrnp", + "col570": "1nyd2", + "col571": "qlrm8", + "col572": "t99ij", + "col573": "x0xqd", + "col574": "d74b0", + "col575": "og86i", + "col576": "crxqc", + "col577": "n0u2x", + "col578": "gdv6m", + "col579": "9nbkb", + "col580": "0usks", + "col581": "zso5k", + "col582": "o8zlu", + "col583": "hajey", + "col584": "toxew", + "col585": "qrjq8", + "col586": "l34ts", + "col587": "0g0j2", + "col588": "itfva", + "col589": "jm3pc", + "col590": "pax2l", + "col591": "wm3xw", + "col592": "vayxu", + "col593": "wnpwa", + "col594": "4m2pr", + "col595": "gtfrz", + "col596": "k5hr3", + "col597": "l3t9w", + "col598": "fvrm6", + "col599": "i2iyd", + "col600": "wmkqz", + "col601": "kpajo", + "col602": "t7kfx", + "col603": "tmt09", + "col604": "q0qcp", + "col605": "n0ux9", + "col606": "a1g4k", + "col607": "x76z2", + "col608": "u6ar3", + "col609": "5txbc", + "col610": "wipg8", + "col611": "dzets", + "col612": "wlf20", + "col613": "av8nk", + "col614": "z3amf", + "col615": "94coe", + "col616": "1zudl", + "col617": "up3el", + "col618": "i014k", + "col619": "ng39n", + "col620": "buxf4", + "col621": "ceezw", + "col622": "ve98l", + "col623": "m7u0l", + "col624": "rv09j", + "col625": "6l1ww", + "col626": "pkv2r", + "col627": "zex9v", + "col628": "3u70h", + "col629": "pwieg", + "col630": "f855o", + "col631": "celv0", + "col632": "x3uin", + "col633": "i2nle", + "col634": "uob2h", + "col635": "mv3gt", + "col636": "8w0sz", + "col637": "m7bud", + "col638": "q0qc5", + "col639": "xhz7b", + "col640": "76x3c", + "col641": "9tjfa", + "col642": "h8y4c", + "col643": "r7bre", + "col644": "o5rw7", + "col645": "tqnvo", + "col646": "1yfk3", + "col647": "cshve", + "col648": "6ffm8", + "col649": "m7lvw", + "col650": "ayfw9", + "col651": "kqc1f", + "col652": "ho65g", + "col653": "e82h2", + "col654": "rxhuk", + "col655": "t6ay2", + "col656": "su9xx", + "col657": "7s5fk", + "col658": "whuoo", + "col659": "hf03b", + "col660": "6jghx", + "col661": "z3x2k", + "col662": "a4ypw", + "col663": "87rgu", + "col664": "bxqgv", + "col665": "q4fh2", + "col666": "4p4p0", + "col667": "08x9q", + "col668": "87xkv", + "col669": "hhc36", + "col670": "jo144", + "col671": "t3f0s", + "col672": "9fpug", + "col673": "pe2ab", + "col674": "89s9h", + "col675": "nmwhv", + "col676": "12wy8", + "col677": "p6c3a", + "col678": "dm4ss", + "col679": "8uc54", + "col680": "ehxzl", + "col681": "ec2r7", + "col682": "wrknr", + "col683": "0ofm9", + "col684": "1kj8i", + "col685": "98emd", + "col686": "5wa6l", + "col687": "c7vv3", + "col688": "e8yzw", + "col689": "z769s", + "col690": "2gp1f", + "col691": "3maik", + "col692": "zai76", + "col693": "nxt18", + "col694": "fful4", + "col695": "u5cd2", + "col696": "n2lkr", + "col697": "phjip", + "col698": "umk5y", + "col699": "powl6", + "col700": "ws57n", + "col701": "rvq9p", + "col702": "kx81g", + "col703": "528hd", + "col704": "1ajm9", + "col705": "1ihsm", + "col706": "tkahb", + "col707": "xmm56", + "col708": "634da", + "col709": "xji7i", + "col710": "sklxm", + "col711": "7hodz", + "col712": "pelso", + "col713": "j7uzh", + "col714": "a2cs8", + "col715": "qqkrt", + "col716": "zao6u", + "col717": "q5117", + "col718": "6rvbw", + "col719": "64pch", + "col720": "3kp0f", + "col721": "ka6ot", + "col722": "gykh7", + "col723": "ys7fb", + "col724": "ar0xj", + "col725": "mjrhu", + "col726": "z7hku", + "col727": "xxdn3", + "col728": "oma0c", + "col729": "wl6gb", + "col730": "ou1gu", + "col731": "tk8dh", + "col732": "fwmtc", + "col733": "k1p4r", + "col734": "godxn", + "col735": "y9l1o", + "col736": "2930c", + "col737": "vvpk3", + "col738": "qn47e", + "col739": "spnym", + "col740": "ftx2w", + "col741": "a548w", + "col742": "64dqm", + "col743": "0gikw", + "col744": "nmgkf", + "col745": "e5eu2", + "col746": "o2lwg", + "col747": "ln1pn", + "col748": "e7ae7", + "col749": "nj55d", + "col750": "r162m", + "col751": "57u2k", + "col752": "umupy", + "col753": "vmg9p", + "col754": "ogirr", + "col755": "61kov", + "col756": "z0znv", + "col757": "n0dl8", + "col758": "071ew", + "col759": "y9a38", + "col760": "70lvd", + "col761": "c0qzi", + "col762": "bwtjk", + "col763": "vt6nr", + "col764": "ol70k", + "col765": "6if5u", + "col766": "gn1cw", + "col767": "q1mc0", + "col768": "0l34h", + "col769": "0cl8s", + "col770": "c45b0", + "col771": "nl1pz", + "col772": "m7sh2", + "col773": "y2viy", + "col774": "qx1ye", + "col775": "7ac5j", + "col776": "t1qzg", + "col777": "demjv", + "col778": "p0zvx", + "col779": "60jz7", + "col780": "waafl", + "col781": "byc3p", + "col782": "7gfe1", + "col783": "xw3d4", + "col784": "2e7i0", + "col785": "3j1tv", + "col786": "u1gzq", + "col787": "yvlfp", + "col788": "hw4im", + "col789": "gadze", + "col790": "t1j5r", + "col791": "tfcd8", + "col792": "lryra", + "col793": "g0jrk", + "col794": "zdbrk", + "col795": "7q1pc", + "col796": "9azoe", + "col797": "0kz7a", + "col798": "k04hz", + "col799": "vi5dv", + "col800": "yaxym", + "col801": "2frrp", + "col802": "74ol7", + "col803": "1c95y", + "col804": "jrfh5", + "col805": "759hm", + "col806": "jarek", + "col807": "c1d52", + "col808": "2i2w9", + "col809": "uus7h", + "col810": "1dstx", + "col811": "tv0ve", + "col812": "ejsvr", + "col813": "wr5ly", + "col814": "q0unn", + "col815": "x2a08", + "col816": "8ckas", + "col817": "1ybmo", + "col818": "q4n6n", + "col819": "1tg5v", + "col820": "juz8h", + "col821": "91ewv", + "col822": "9495y", + "col823": "gjixz", + "col824": "u1432", + "col825": "zbhem", + "col826": "e4nfz", + "col827": "ig4v5", + "col828": "f545m", + "col829": "z41k4", + "col830": "8ahl9", + "col831": "skjyo", + "col832": "dv4sc", + "col833": "7fnms", + "col834": "2ycw5", + "col835": "akcuc", + "col836": "k00rm", + "col837": "a283e", + "col838": "croez", + "col839": "6k583", + "col840": "97e9r", + "col841": "uci47", + "col842": "0j39i", + "col843": "5s9q7", + "col844": "j4o6q", + "col845": "jfodc", + "col846": "i7i1w", + "col847": "73x2w", + "col848": "crzn4", + "col849": "wdjoh", + "col850": "lkxwr", + "col851": "mhiku", + "col852": "92emk", + "col853": "parwe", + "col854": "gcowy", + "col855": "p1frp", + "col856": "e6ag6", + "col857": "d6jej", + "col858": "gyvln", + "col859": "uz04w", + "col860": "ef4ub", + "col861": "k3ns7", + "col862": "9io7k", + "col863": "t2ve0", + "col864": "a6a9a", + "col865": "fzzrl", + "col866": "zpauk", + "col867": "6jhut", + "col868": "ybhn0", + "col869": "12vbk", + "col870": "izfs9", + "col871": "8q8mk", + "col872": "io76b", + "col873": "if0og", + "col874": "nn1kv", + "col875": "un7py", + "col876": "wf41c", + "col877": "ezobi", + "col878": "w7tzx", + "col879": "tsedp", + "col880": "ihwdj", + "col881": "ackjb", + "col882": "l3mp8", + "col883": "jwj4x", + "col884": "vbbsr", + "col885": "ra818", + "col886": "p3udx", + "col887": "59pr1", + "col888": "o81ct", + "col889": "f1swi", + "col890": "wcww6", + "col891": "7fzt6", + "col892": "3rp83", + "col893": "2gbrg", + "col894": "f4e03", + "col895": "8cq4t", + "col896": "cs2m2", + "col897": "5w4le", + "col898": "u01tf", + "col899": "ka1od", + "col900": "dimhn", + "col901": "fr9dr", + "col902": "0dxqi", + "col903": "utuyf", + "col904": "r4ya0", + "col905": "wdcso", + "col906": "fn6w3", + "col907": "fujz1", + "col908": "irbcq", + "col909": "tvo9g", + "col910": "wixdm", + "col911": "y0bg6", + "col912": "zyabd", + "col913": "z640z", + "col914": "1gnfx", + "col915": "2zw2t", + "col916": "2cgm8", + "col917": "e417l", + "col918": "pgql1", + "col919": "u5f1h", + "col920": "u0lbf", + "col921": "z5i8m", + "col922": "6r3mo", + "col923": "fon5p", + "col924": "ajrkl", + "col925": "myu31", + "col926": "2fkov", + "col927": "glyva", + "col928": "cu562", + "col929": "y2oe6", + "col930": "dhojp", + "col931": "kuok6", + "col932": "26xgy", + "col933": "bixn9", + "col934": "k78ph", + "col935": "kictu", + "col936": "4k9oe", + "col937": "2ifme", + "col938": "ofi71", + "col939": "8ftio", + "col940": "cb26z", + "col941": "qy1ui", + "col942": "gnzrx", + "col943": "ph41x", + "col944": "qisxb", + "col945": "b9jjy", + "col946": "dlug0", + "col947": "gu0q4", + "col948": "7bfwn", + "col949": "d7pak", + "col950": "kderi", + "col951": "9tmca", + "col952": "k21g0", + "col953": "an2ed", + "col954": "tf4bj", + "col955": "j90ed", + "col956": "4tjp7", + "col957": "c987l", + "col958": "u2pwm", + "col959": "vpzpm", + "col960": "g0wxa", + "col961": "hvkxj", + "col962": "s0iq2", + "col963": "hygmg", + "col964": "lq34f", + "col965": "nplqk", + "col966": "9hdcu", + "col967": "akyzs", + "col968": "j0z7e", + "col969": "fqbfl", + "col970": "fpvyu", + "col971": "uwya5", + "col972": "t7m7a", + "col973": "t3q7f", + "col974": "sp62g", + "col975": "2init", + "col976": "q1n4q", + "col977": "972rd", + "col978": "rkquz", + "col979": "fx2bh", + "col980": "ycx8x", + "col981": "yvm0q", + "col982": "u053a", + "col983": "rhp1x", + "col984": "fitrr", + "col985": "tt260", + "col986": "55sop", + "col987": "d24iv", + "col988": "i3gib", + "col989": "enz3n", + "col990": "iegzm", + "col991": "djl8l", + "col992": "j04j9", + "col993": "lygrw", + "col994": "yh9jx", + "col995": "xsfos", + "col996": "oymsk", + "col997": "q5s6k", + "col998": "zd24q", + "col999": "wgl3l" + }, + { + "name": "Ferrell Gross", + "gender": "male", + "col0": "33d80", + "col1": "tji2q", + "col2": "l1842", + "col3": "w6tuk", + "col4": "b07m2", + "col5": "6ts9o", + "col6": "gz6o6", + "col7": "7akh3", + "col8": "b4hmj", + "col9": "eoew1", + "col10": "5d1ez", + "col11": "33gbq", + "col12": "nml6f", + "col13": "qkb5c", + "col14": "hm1z4", + "col15": "wq4ce", + "col16": "1e2n7", + "col17": "6u3pd", + "col18": "ez4av", + "col19": "jheot", + "col20": "3qq9n", + "col21": "qczs4", + "col22": "3mib5", + "col23": "98jfn", + "col24": "9r1k4", + "col25": "0j0v6", + "col26": "btcp2", + "col27": "mln7q", + "col28": "66cnf", + "col29": "zp6uv", + "col30": "31338", + "col31": "ajpvw", + "col32": "9efh7", + "col33": "ewj9g", + "col34": "gbks7", + "col35": "nhjg6", + "col36": "glz6b", + "col37": "sqtao", + "col38": "1nhan", + "col39": "t53la", + "col40": "squf2", + "col41": "f6ksg", + "col42": "yt3vm", + "col43": "jwubd", + "col44": "lmjix", + "col45": "6kjsh", + "col46": "3yfqm", + "col47": "xise0", + "col48": "ap3f6", + "col49": "23ycg", + "col50": "7ilm3", + "col51": "8drz6", + "col52": "55xxp", + "col53": "2u71k", + "col54": "iht8x", + "col55": "r5otf", + "col56": "4bo10", + "col57": "hfr5z", + "col58": "2js5e", + "col59": "qkvif", + "col60": "mcrlb", + "col61": "df74a", + "col62": "huvqh", + "col63": "sfxud", + "col64": "rspae", + "col65": "qxm8a", + "col66": "m1la4", + "col67": "04oq7", + "col68": "1jjq3", + "col69": "5b74k", + "col70": "byu1p", + "col71": "6eizn", + "col72": "9tbt1", + "col73": "jmuux", + "col74": "0p1zf", + "col75": "7nsek", + "col76": "uspp8", + "col77": "hymux", + "col78": "cd85k", + "col79": "mrfoa", + "col80": "vd405", + "col81": "5ibpv", + "col82": "b97ic", + "col83": "elh4y", + "col84": "j9zeh", + "col85": "ykjws", + "col86": "9sw47", + "col87": "53bmf", + "col88": "rtvvw", + "col89": "ural6", + "col90": "lqp7j", + "col91": "116gv", + "col92": "g8lo3", + "col93": "uzlmt", + "col94": "6eilp", + "col95": "8gjmo", + "col96": "64j83", + "col97": "0rfoo", + "col98": "ug8ud", + "col99": "37xl4", + "col100": "nlrnf", + "col101": "l3b23", + "col102": "4hl4v", + "col103": "ggjec", + "col104": "mjkwy", + "col105": "00y8e", + "col106": "ckdbw", + "col107": "hwifx", + "col108": "xbu4e", + "col109": "6tjb2", + "col110": "narf2", + "col111": "r1num", + "col112": "hibr7", + "col113": "rtgwz", + "col114": "te34h", + "col115": "yjyfc", + "col116": "kfr3m", + "col117": "akpd2", + "col118": "h5nll", + "col119": "ukryv", + "col120": "eymwf", + "col121": "em4jp", + "col122": "zy793", + "col123": "d2amp", + "col124": "6id6p", + "col125": "3dz85", + "col126": "u3ejd", + "col127": "d1eu1", + "col128": "v7y0g", + "col129": "yf4o0", + "col130": "bd183", + "col131": "awpgw", + "col132": "0wgw5", + "col133": "q7ume", + "col134": "nju56", + "col135": "vqn39", + "col136": "wcr1n", + "col137": "du28s", + "col138": "9u029", + "col139": "nxg74", + "col140": "coljr", + "col141": "53lhk", + "col142": "q123o", + "col143": "p9a93", + "col144": "46l1l", + "col145": "e68lg", + "col146": "37p65", + "col147": "vphjp", + "col148": "jmpn2", + "col149": "sm3eo", + "col150": "5gel2", + "col151": "qeg2w", + "col152": "tectf", + "col153": "zpds7", + "col154": "rubqp", + "col155": "i5pol", + "col156": "yj9ak", + "col157": "v060l", + "col158": "omrsd", + "col159": "haruy", + "col160": "18b3y", + "col161": "rot7q", + "col162": "8ig9p", + "col163": "w5bf4", + "col164": "pquo8", + "col165": "wckki", + "col166": "9qzt3", + "col167": "l960r", + "col168": "ma516", + "col169": "cb2it", + "col170": "4ubm7", + "col171": "sdhsx", + "col172": "b0yqo", + "col173": "w7o0y", + "col174": "fd1u2", + "col175": "oismx", + "col176": "gdyoj", + "col177": "wnde0", + "col178": "cbmbg", + "col179": "fugm9", + "col180": "14upt", + "col181": "17c47", + "col182": "07f63", + "col183": "nu205", + "col184": "lk62y", + "col185": "21v5h", + "col186": "d509g", + "col187": "bqvgl", + "col188": "ldedy", + "col189": "if9j0", + "col190": "7i4ha", + "col191": "j0bk8", + "col192": "ho30c", + "col193": "hzmgz", + "col194": "6l7i8", + "col195": "2nnea", + "col196": "8fe2j", + "col197": "ywa0g", + "col198": "87awe", + "col199": "gitqp", + "col200": "pwr7v", + "col201": "wuslb", + "col202": "f0xnl", + "col203": "1nk7c", + "col204": "ik6yx", + "col205": "mehjh", + "col206": "0dyly", + "col207": "j9mzb", + "col208": "6h8ts", + "col209": "owais", + "col210": "h31p7", + "col211": "liuf6", + "col212": "fsqip", + "col213": "rwyef", + "col214": "83572", + "col215": "zonz8", + "col216": "enpp0", + "col217": "qs1th", + "col218": "iceir", + "col219": "w25or", + "col220": "3ybkb", + "col221": "ossup", + "col222": "3ppxm", + "col223": "jx880", + "col224": "a99xy", + "col225": "h4ss3", + "col226": "4wnyg", + "col227": "637w8", + "col228": "68a82", + "col229": "49zaj", + "col230": "2bryy", + "col231": "83c6f", + "col232": "aw27s", + "col233": "v972w", + "col234": "s8dsg", + "col235": "t2kzx", + "col236": "r9f0p", + "col237": "ywg37", + "col238": "hlrrb", + "col239": "hkvq6", + "col240": "gilqs", + "col241": "g2nnj", + "col242": "rxmid", + "col243": "5dcnv", + "col244": "dcsjq", + "col245": "f1bnm", + "col246": "yjcce", + "col247": "8bn11", + "col248": "g5psl", + "col249": "mkwoc", + "col250": "bx3h5", + "col251": "kdm4q", + "col252": "57tfs", + "col253": "iqr1w", + "col254": "8rlx0", + "col255": "4m8ur", + "col256": "igf10", + "col257": "e19tx", + "col258": "hs20d", + "col259": "s7kj6", + "col260": "esf0e", + "col261": "k39m3", + "col262": "we9wc", + "col263": "oz5xb", + "col264": "tqdb9", + "col265": "s8nz4", + "col266": "ob0gx", + "col267": "2jzlu", + "col268": "pw2nu", + "col269": "ml3y5", + "col270": "ejbxy", + "col271": "fuytu", + "col272": "na0vr", + "col273": "9ry2o", + "col274": "bl9u4", + "col275": "b8b4l", + "col276": "rkvlm", + "col277": "osbn3", + "col278": "bcz51", + "col279": "gm8sy", + "col280": "ed2zi", + "col281": "do9ic", + "col282": "sbx9q", + "col283": "nf1wi", + "col284": "4b2zf", + "col285": "iblcp", + "col286": "son9m", + "col287": "y27p3", + "col288": "qhvq8", + "col289": "tyr7d", + "col290": "e1ph5", + "col291": "uu2pf", + "col292": "arxg6", + "col293": "mpfvv", + "col294": "1ny8b", + "col295": "ivf7u", + "col296": "5ojti", + "col297": "o7xtx", + "col298": "ee24f", + "col299": "sqdp7", + "col300": "w7bhc", + "col301": "yoegh", + "col302": "gpow8", + "col303": "jc99g", + "col304": "90qwj", + "col305": "hnmg6", + "col306": "nsfc4", + "col307": "qbfgu", + "col308": "frnay", + "col309": "r7usd", + "col310": "eag7k", + "col311": "7qdmf", + "col312": "z35ex", + "col313": "u2452", + "col314": "4vshj", + "col315": "01a57", + "col316": "o8rxl", + "col317": "wid2n", + "col318": "uzitw", + "col319": "1rqj7", + "col320": "wvt8w", + "col321": "g7pnn", + "col322": "u7o2u", + "col323": "4obg1", + "col324": "9an0y", + "col325": "1kbsk", + "col326": "lrqgy", + "col327": "ta8d1", + "col328": "b4k0t", + "col329": "7ea9m", + "col330": "h1omh", + "col331": "d2di0", + "col332": "sudtn", + "col333": "zwvlo", + "col334": "nhmw7", + "col335": "q832j", + "col336": "3siub", + "col337": "vmmw8", + "col338": "buy20", + "col339": "gbmkx", + "col340": "ybdhb", + "col341": "fkwt0", + "col342": "0n951", + "col343": "tyytc", + "col344": "vu838", + "col345": "jzadr", + "col346": "i0ikc", + "col347": "9j4ml", + "col348": "hehsc", + "col349": "9law0", + "col350": "stqf1", + "col351": "ltb80", + "col352": "vz2b1", + "col353": "d0agv", + "col354": "kjjqo", + "col355": "qb4fm", + "col356": "o80ue", + "col357": "ls6kz", + "col358": "r0ixa", + "col359": "f1w9x", + "col360": "5frzh", + "col361": "pey8j", + "col362": "gtdew", + "col363": "brgqn", + "col364": "21cnq", + "col365": "hcpff", + "col366": "e5dqi", + "col367": "ou00l", + "col368": "rspeq", + "col369": "hj21p", + "col370": "3f70k", + "col371": "5v0eq", + "col372": "dogiw", + "col373": "dbeqb", + "col374": "ypt57", + "col375": "y8es4", + "col376": "9hukk", + "col377": "uw4fr", + "col378": "ud5y1", + "col379": "yri4y", + "col380": "fn3p0", + "col381": "hdt6s", + "col382": "z179o", + "col383": "604bs", + "col384": "a64t2", + "col385": "0eamf", + "col386": "wgk6q", + "col387": "3dsb5", + "col388": "9tme8", + "col389": "npqog", + "col390": "gz38a", + "col391": "67k2s", + "col392": "oe1vg", + "col393": "u7npt", + "col394": "zfc9f", + "col395": "7g4kl", + "col396": "ffnk6", + "col397": "9pxrn", + "col398": "g594d", + "col399": "5le6n", + "col400": "1fmat", + "col401": "ht97g", + "col402": "cg1f3", + "col403": "n4gm3", + "col404": "r81dz", + "col405": "on74p", + "col406": "qylmo", + "col407": "gjczv", + "col408": "qped9", + "col409": "qrn18", + "col410": "ed6cv", + "col411": "c9azr", + "col412": "z8wpg", + "col413": "l7zez", + "col414": "5n1dh", + "col415": "czrda", + "col416": "qsyqv", + "col417": "qo5eg", + "col418": "brlt7", + "col419": "nzpct", + "col420": "xzj5p", + "col421": "23tdy", + "col422": "377me", + "col423": "0xhb6", + "col424": "xmqca", + "col425": "zqrcx", + "col426": "vqft0", + "col427": "oxzlv", + "col428": "0s1gr", + "col429": "7t2vb", + "col430": "zyy4f", + "col431": "rktw2", + "col432": "42xat", + "col433": "1dpxk", + "col434": "n9j7l", + "col435": "6spx8", + "col436": "pw2ow", + "col437": "5c268", + "col438": "dcvnb", + "col439": "bned9", + "col440": "it1sy", + "col441": "kf3yy", + "col442": "bhmfl", + "col443": "5s13g", + "col444": "jrq65", + "col445": "zw43y", + "col446": "s01jd", + "col447": "6h0rp", + "col448": "evppd", + "col449": "5ui4w", + "col450": "hxj7h", + "col451": "dex6i", + "col452": "51i7b", + "col453": "b9bwh", + "col454": "cqao5", + "col455": "3bc9u", + "col456": "tosoz", + "col457": "8og43", + "col458": "0p7wl", + "col459": "ff190", + "col460": "j14ia", + "col461": "rw0wa", + "col462": "hrmdt", + "col463": "h7gh8", + "col464": "xgo8o", + "col465": "q8z6z", + "col466": "nradw", + "col467": "sezd1", + "col468": "n5sq0", + "col469": "k75hd", + "col470": "r4qcg", + "col471": "3jdgp", + "col472": "u35iw", + "col473": "o2z02", + "col474": "qrh2d", + "col475": "0bc38", + "col476": "eysua", + "col477": "m08ek", + "col478": "looz7", + "col479": "qa2u9", + "col480": "u18zr", + "col481": "cuf1b", + "col482": "8dqo1", + "col483": "e6fqd", + "col484": "1s3v6", + "col485": "afv1y", + "col486": "e55jn", + "col487": "khnxv", + "col488": "y5465", + "col489": "l8mwr", + "col490": "shyae", + "col491": "l4kkp", + "col492": "xr3b4", + "col493": "brv17", + "col494": "7frwj", + "col495": "qljcg", + "col496": "de78m", + "col497": "ind14", + "col498": "p469d", + "col499": "ohepw", + "col500": "nx7wr", + "col501": "4bdea", + "col502": "ezljq", + "col503": "p90k7", + "col504": "em4gf", + "col505": "hvhrw", + "col506": "dfjwn", + "col507": "mb0th", + "col508": "yu84l", + "col509": "s2x11", + "col510": "d8qpu", + "col511": "vkofa", + "col512": "dpl6y", + "col513": "qo6ri", + "col514": "up7sl", + "col515": "o0gjy", + "col516": "4me89", + "col517": "kyxyt", + "col518": "pf39s", + "col519": "gwdi3", + "col520": "m401z", + "col521": "2y2sc", + "col522": "d3ztx", + "col523": "wjo8n", + "col524": "3uwi4", + "col525": "xzjtf", + "col526": "tzdz4", + "col527": "5t9n5", + "col528": "4a3f0", + "col529": "xyp8s", + "col530": "9jaia", + "col531": "z646m", + "col532": "z45y2", + "col533": "749qo", + "col534": "ca5s9", + "col535": "qyhqz", + "col536": "vixzg", + "col537": "o6lud", + "col538": "c4onq", + "col539": "887u4", + "col540": "bfnpv", + "col541": "bmt63", + "col542": "q2zwi", + "col543": "kc1wu", + "col544": "urx9j", + "col545": "0xmjl", + "col546": "1xuxj", + "col547": "yafkw", + "col548": "v94ex", + "col549": "s3idw", + "col550": "0a0dz", + "col551": "qtcy3", + "col552": "nsx7y", + "col553": "sojr0", + "col554": "wb2jz", + "col555": "b8dtc", + "col556": "9186f", + "col557": "5xuum", + "col558": "amnn8", + "col559": "erlvw", + "col560": "3sm8i", + "col561": "89j5f", + "col562": "g2g7b", + "col563": "7akvp", + "col564": "kwrb6", + "col565": "af0xm", + "col566": "dyzvk", + "col567": "vn42x", + "col568": "ei9zr", + "col569": "ldaqd", + "col570": "7ikp2", + "col571": "m5efr", + "col572": "ggfod", + "col573": "nbfrr", + "col574": "q2ic9", + "col575": "73445", + "col576": "9gniq", + "col577": "h4zhh", + "col578": "7ytxp", + "col579": "wxxah", + "col580": "634ou", + "col581": "kswhj", + "col582": "bsm22", + "col583": "zanba", + "col584": "6wys8", + "col585": "bf0c6", + "col586": "qlvjv", + "col587": "49y74", + "col588": "i1odc", + "col589": "or429", + "col590": "8ekhf", + "col591": "khupp", + "col592": "9v1jr", + "col593": "v75x1", + "col594": "hznoc", + "col595": "6zf4z", + "col596": "h83pe", + "col597": "bqine", + "col598": "eb0db", + "col599": "rgbno", + "col600": "5xcis", + "col601": "jbyc6", + "col602": "rx2kj", + "col603": "xarz9", + "col604": "7kv54", + "col605": "ubcx7", + "col606": "cbt5v", + "col607": "nhvqv", + "col608": "ylyom", + "col609": "1554h", + "col610": "xxxi1", + "col611": "pqnw0", + "col612": "jj013", + "col613": "gvxpn", + "col614": "83zyd", + "col615": "tpxpd", + "col616": "q8mbv", + "col617": "eiank", + "col618": "9tqq8", + "col619": "wlx61", + "col620": "nphms", + "col621": "j9ss8", + "col622": "g9fpg", + "col623": "uobqn", + "col624": "ywmfz", + "col625": "dfxh4", + "col626": "wr2k1", + "col627": "jx8fj", + "col628": "dc1xq", + "col629": "ilvaz", + "col630": "s9xrm", + "col631": "o0eg5", + "col632": "2b07i", + "col633": "alji1", + "col634": "p4wyh", + "col635": "l32ne", + "col636": "pycpw", + "col637": "hjbzp", + "col638": "hv9jr", + "col639": "zabuy", + "col640": "hywa0", + "col641": "k6m1x", + "col642": "rlza0", + "col643": "avr8q", + "col644": "z5h6f", + "col645": "9td4q", + "col646": "01pba", + "col647": "xtqtt", + "col648": "wcvfr", + "col649": "l2r3e", + "col650": "tsre1", + "col651": "v4k2z", + "col652": "pk4ze", + "col653": "uv3ou", + "col654": "9cvox", + "col655": "jlcq4", + "col656": "ds6wg", + "col657": "3r67m", + "col658": "8nlgb", + "col659": "6ecxs", + "col660": "yy7ag", + "col661": "mpds4", + "col662": "49540", + "col663": "1ewaq", + "col664": "yim1c", + "col665": "y5fmn", + "col666": "y8240", + "col667": "ip2oh", + "col668": "6pjpp", + "col669": "a4bsb", + "col670": "ambtw", + "col671": "rsww7", + "col672": "yezej", + "col673": "d0ibf", + "col674": "l4l60", + "col675": "vy1fw", + "col676": "daj28", + "col677": "sih04", + "col678": "abonp", + "col679": "u5tqo", + "col680": "0if4o", + "col681": "wuibn", + "col682": "y020j", + "col683": "60xi1", + "col684": "wydhh", + "col685": "hwfpc", + "col686": "har4o", + "col687": "fa242", + "col688": "t84jp", + "col689": "v7nnb", + "col690": "tuyyl", + "col691": "15h32", + "col692": "t5a6q", + "col693": "qvaov", + "col694": "hku4y", + "col695": "gl7au", + "col696": "t4ass", + "col697": "cch5s", + "col698": "oinzk", + "col699": "up5ep", + "col700": "j9d9y", + "col701": "kws1u", + "col702": "admi4", + "col703": "ooc6m", + "col704": "zz5i1", + "col705": "c3zv3", + "col706": "k74w7", + "col707": "gis2x", + "col708": "e76st", + "col709": "cxmyu", + "col710": "a2h0z", + "col711": "fpy8s", + "col712": "50hzn", + "col713": "y3g5k", + "col714": "u8e58", + "col715": "divqv", + "col716": "cjs74", + "col717": "8jdwt", + "col718": "0psdk", + "col719": "vvvb0", + "col720": "thts4", + "col721": "6dd03", + "col722": "6vl0m", + "col723": "aoh4v", + "col724": "sgf41", + "col725": "m85k6", + "col726": "xltsf", + "col727": "egk3n", + "col728": "g0ody", + "col729": "d5qdr", + "col730": "w1wae", + "col731": "azwp9", + "col732": "pbf3l", + "col733": "vnuaq", + "col734": "y32v8", + "col735": "gwq3g", + "col736": "7mzjy", + "col737": "tt82w", + "col738": "2v8hs", + "col739": "4te89", + "col740": "4enqf", + "col741": "ew75q", + "col742": "grdsr", + "col743": "fko31", + "col744": "z80lu", + "col745": "2g9pb", + "col746": "8u30k", + "col747": "euwy2", + "col748": "8izjv", + "col749": "d88ll", + "col750": "17wrf", + "col751": "45q6j", + "col752": "wy001", + "col753": "45l3j", + "col754": "xhlpn", + "col755": "n02b0", + "col756": "t79ts", + "col757": "7s8x6", + "col758": "t7wuu", + "col759": "396yy", + "col760": "498wz", + "col761": "55qc6", + "col762": "jck8e", + "col763": "megab", + "col764": "bih6e", + "col765": "fzl5q", + "col766": "ip8vq", + "col767": "hgek5", + "col768": "w8fwg", + "col769": "u6ruo", + "col770": "4i4nb", + "col771": "9jge8", + "col772": "u8i83", + "col773": "mia0n", + "col774": "rw5mu", + "col775": "pe8y8", + "col776": "vr9jz", + "col777": "lofut", + "col778": "ce97h", + "col779": "5r9l1", + "col780": "m1kvb", + "col781": "jbk0q", + "col782": "z41bm", + "col783": "gzf7p", + "col784": "7k194", + "col785": "2ozlq", + "col786": "x7w7v", + "col787": "nlfmc", + "col788": "l91rb", + "col789": "pdax6", + "col790": "lzg8l", + "col791": "i7nm8", + "col792": "dlzvj", + "col793": "r2llu", + "col794": "hpkrj", + "col795": "m2wjy", + "col796": "tm0n4", + "col797": "skcd2", + "col798": "jwk5c", + "col799": "mhos1", + "col800": "mse3n", + "col801": "wxsuf", + "col802": "wwd4v", + "col803": "7x716", + "col804": "w7n42", + "col805": "wxjea", + "col806": "syl8r", + "col807": "ohp80", + "col808": "vk5cj", + "col809": "5cy4n", + "col810": "r3rqr", + "col811": "j32fx", + "col812": "uakn3", + "col813": "uz0ix", + "col814": "zp9eh", + "col815": "ricrc", + "col816": "wr0rb", + "col817": "vdf0v", + "col818": "zsvzv", + "col819": "2js8e", + "col820": "qokwm", + "col821": "7bmsq", + "col822": "auhd9", + "col823": "f0buz", + "col824": "xg1xk", + "col825": "uxwkf", + "col826": "wwjfq", + "col827": "mbscb", + "col828": "s7hy2", + "col829": "b1bxw", + "col830": "og455", + "col831": "fjshm", + "col832": "6ritg", + "col833": "k2coq", + "col834": "xx1wv", + "col835": "w9ir2", + "col836": "5ty7m", + "col837": "jorgh", + "col838": "3qy9f", + "col839": "2va4t", + "col840": "z6twj", + "col841": "npf2f", + "col842": "cgond", + "col843": "qzprp", + "col844": "vvfkh", + "col845": "61394", + "col846": "trb5w", + "col847": "bo73i", + "col848": "0ewux", + "col849": "a0bl5", + "col850": "i798q", + "col851": "fh9d1", + "col852": "sr0yi", + "col853": "yqd6c", + "col854": "yywv0", + "col855": "ee9m9", + "col856": "bk4ft", + "col857": "ivqst", + "col858": "1l9jb", + "col859": "upz5d", + "col860": "ezv4c", + "col861": "j3ni4", + "col862": "qmrvn", + "col863": "oh1b7", + "col864": "3lbuq", + "col865": "2izlc", + "col866": "epd37", + "col867": "u6q0d", + "col868": "d14e6", + "col869": "9mi9u", + "col870": "wx813", + "col871": "7p85f", + "col872": "qkk0j", + "col873": "un574", + "col874": "e12eb", + "col875": "l9u7b", + "col876": "fnr7y", + "col877": "cguxk", + "col878": "x1ssy", + "col879": "fnxb5", + "col880": "o1wz2", + "col881": "4s5c4", + "col882": "2hjyr", + "col883": "ovdx6", + "col884": "epl9q", + "col885": "5c91f", + "col886": "k6lmw", + "col887": "bjhe9", + "col888": "sb3uu", + "col889": "wdgnp", + "col890": "o9sdf", + "col891": "ocq3i", + "col892": "xb4kp", + "col893": "79ggy", + "col894": "g5m2j", + "col895": "8ypln", + "col896": "rhobe", + "col897": "x3zez", + "col898": "5hiq3", + "col899": "nsu4d", + "col900": "f7fnt", + "col901": "s12va", + "col902": "7r9ee", + "col903": "kyzo4", + "col904": "2u8ro", + "col905": "9hiq5", + "col906": "s4dno", + "col907": "be89h", + "col908": "ue5k4", + "col909": "9n6ut", + "col910": "t2yw8", + "col911": "jdlw1", + "col912": "b12wt", + "col913": "kft7f", + "col914": "x9eyp", + "col915": "udw88", + "col916": "fu4cb", + "col917": "x3imf", + "col918": "pvpjz", + "col919": "pemho", + "col920": "eb46t", + "col921": "9gasb", + "col922": "yednt", + "col923": "zs9cq", + "col924": "0aujj", + "col925": "ijggk", + "col926": "qk0jv", + "col927": "h5or2", + "col928": "z167p", + "col929": "0x4rw", + "col930": "qrrtx", + "col931": "x1k5b", + "col932": "h8lkq", + "col933": "kgb3x", + "col934": "swyt1", + "col935": "xgd7j", + "col936": "7w4rv", + "col937": "pbci1", + "col938": "4276f", + "col939": "rv77m", + "col940": "3xpvv", + "col941": "d0enm", + "col942": "0y7kn", + "col943": "roll3", + "col944": "ikerf", + "col945": "rx8sp", + "col946": "5dy3y", + "col947": "3138n", + "col948": "en5ny", + "col949": "160gw", + "col950": "fg3x9", + "col951": "kbr4t", + "col952": "3ofk8", + "col953": "8c7wd", + "col954": "s7pj6", + "col955": "myuho", + "col956": "psi92", + "col957": "vjbyz", + "col958": "63odr", + "col959": "01su3", + "col960": "xkb4x", + "col961": "we82f", + "col962": "tlo6u", + "col963": "x9r8m", + "col964": "xmb64", + "col965": "3xl3x", + "col966": "veofb", + "col967": "h5pda", + "col968": "7wwp9", + "col969": "iqzq3", + "col970": "jglao", + "col971": "zadta", + "col972": "2hmoz", + "col973": "2ea5y", + "col974": "mdkw1", + "col975": "c6opx", + "col976": "q2px3", + "col977": "lgaee", + "col978": "6wege", + "col979": "mwevu", + "col980": "qs7v8", + "col981": "vgbzv", + "col982": "cqaoc", + "col983": "rdnpx", + "col984": "zyw85", + "col985": "ve6g2", + "col986": "tnni9", + "col987": "mve8y", + "col988": "7n3q7", + "col989": "r888h", + "col990": "rre1f", + "col991": "9lllr", + "col992": "s8od2", + "col993": "sq9ss", + "col994": "bua5k", + "col995": "1m218", + "col996": "y9isc", + "col997": "re541", + "col998": "ncizj", + "col999": "cpthm" + }, + { + "name": "Barr Holloway", + "gender": "male", + "col0": "f9s2p", + "col1": "0fsn9", + "col2": "jsue5", + "col3": "pj3x9", + "col4": "zpj3q", + "col5": "93p34", + "col6": "4ynbf", + "col7": "24ilq", + "col8": "90ean", + "col9": "r8exh", + "col10": "0fy33", + "col11": "6ce4e", + "col12": "axj27", + "col13": "u3n84", + "col14": "1mpoo", + "col15": "uoa9m", + "col16": "ia0rg", + "col17": "blw2w", + "col18": "ncpgc", + "col19": "0oz8a", + "col20": "cy082", + "col21": "4gwvy", + "col22": "m026m", + "col23": "7y7cw", + "col24": "jj0gk", + "col25": "4edfv", + "col26": "cfkr7", + "col27": "cwxb8", + "col28": "sal56", + "col29": "l9no3", + "col30": "veu5m", + "col31": "zb8mw", + "col32": "agkmx", + "col33": "hbjr0", + "col34": "09y6d", + "col35": "182x1", + "col36": "i0ohl", + "col37": "7l2j1", + "col38": "kxve1", + "col39": "6na7k", + "col40": "ydmoj", + "col41": "dkm58", + "col42": "cy0ue", + "col43": "fl73e", + "col44": "bacyr", + "col45": "xmohk", + "col46": "slev6", + "col47": "s2sud", + "col48": "usw2z", + "col49": "0z4ps", + "col50": "bbk3e", + "col51": "esocp", + "col52": "bwrim", + "col53": "7hnnb", + "col54": "xb36q", + "col55": "te5zd", + "col56": "u72wu", + "col57": "7rm7c", + "col58": "eq4pb", + "col59": "w4uxf", + "col60": "7ld1h", + "col61": "leiuz", + "col62": "awkts", + "col63": "xwqgo", + "col64": "d3vee", + "col65": "w0eeb", + "col66": "rkozt", + "col67": "782bi", + "col68": "p9d9w", + "col69": "fmvyb", + "col70": "3x7zs", + "col71": "s82q0", + "col72": "6hlvz", + "col73": "23yjg", + "col74": "leefz", + "col75": "in1l4", + "col76": "aqvn9", + "col77": "osuh0", + "col78": "28apn", + "col79": "l8540", + "col80": "s6tbk", + "col81": "rt4ct", + "col82": "0pjg2", + "col83": "h9zw8", + "col84": "43zr5", + "col85": "d39fp", + "col86": "ggiaz", + "col87": "tyn84", + "col88": "n0v5x", + "col89": "8mqeo", + "col90": "5hpty", + "col91": "p9zyg", + "col92": "evabo", + "col93": "3r3i5", + "col94": "euevl", + "col95": "pqgqu", + "col96": "ydiog", + "col97": "n52ur", + "col98": "ves0h", + "col99": "5pyou", + "col100": "2to55", + "col101": "kkrup", + "col102": "cuxn8", + "col103": "ts3e7", + "col104": "0nblq", + "col105": "tong8", + "col106": "eox4q", + "col107": "cutst", + "col108": "mckja", + "col109": "i35em", + "col110": "35v5t", + "col111": "1t1pr", + "col112": "xq2bu", + "col113": "4cpob", + "col114": "ypspk", + "col115": "gofln", + "col116": "mflo2", + "col117": "eg03e", + "col118": "julyn", + "col119": "a8n9r", + "col120": "wge28", + "col121": "nsd99", + "col122": "b8kbw", + "col123": "4x7mn", + "col124": "ck0eu", + "col125": "dklfe", + "col126": "9d9kd", + "col127": "rzvk5", + "col128": "sf16q", + "col129": "gtd66", + "col130": "p5aej", + "col131": "7knat", + "col132": "5jwud", + "col133": "x76oa", + "col134": "n1cot", + "col135": "0y3si", + "col136": "18fa9", + "col137": "3tt69", + "col138": "5nnbc", + "col139": "ns632", + "col140": "syckw", + "col141": "jizki", + "col142": "sotzw", + "col143": "6p4o1", + "col144": "pn852", + "col145": "lun71", + "col146": "h3lar", + "col147": "acoxa", + "col148": "rdedh", + "col149": "2s1zt", + "col150": "t0kqr", + "col151": "tf1sb", + "col152": "a6nxn", + "col153": "de6mk", + "col154": "bk8q3", + "col155": "jdjid", + "col156": "ryfyv", + "col157": "vvgii", + "col158": "tr38h", + "col159": "t0efu", + "col160": "116eb", + "col161": "xbmnb", + "col162": "fmjp8", + "col163": "fj4f2", + "col164": "fhvfv", + "col165": "hokai", + "col166": "pzmbi", + "col167": "njn93", + "col168": "0sfq8", + "col169": "32u1p", + "col170": "mmxa2", + "col171": "i86rk", + "col172": "f8qjl", + "col173": "hi9ui", + "col174": "wx82g", + "col175": "ex3gq", + "col176": "jb8mt", + "col177": "e0hh2", + "col178": "hj3rd", + "col179": "c4iy2", + "col180": "t1wvv", + "col181": "ul19v", + "col182": "koxzs", + "col183": "9j0mc", + "col184": "9uji7", + "col185": "lo480", + "col186": "jsozs", + "col187": "n5d0r", + "col188": "5fszp", + "col189": "98lqq", + "col190": "msz9v", + "col191": "8vt3e", + "col192": "er4ca", + "col193": "pb8ie", + "col194": "hqxs3", + "col195": "rogfn", + "col196": "xds13", + "col197": "3o45h", + "col198": "sv8kl", + "col199": "yjxbz", + "col200": "zchkj", + "col201": "ksvhr", + "col202": "2dx0g", + "col203": "de0o1", + "col204": "ykuom", + "col205": "26fu9", + "col206": "qg7h2", + "col207": "6s4bw", + "col208": "13ofp", + "col209": "3ebj6", + "col210": "p434d", + "col211": "il9v1", + "col212": "3depg", + "col213": "pcobq", + "col214": "8w2gv", + "col215": "ufbl3", + "col216": "u6r48", + "col217": "9vw6a", + "col218": "xiqac", + "col219": "vnih8", + "col220": "4pmpd", + "col221": "fsaz9", + "col222": "k1hbc", + "col223": "bpvnx", + "col224": "1ym34", + "col225": "2njre", + "col226": "dw3om", + "col227": "ljla6", + "col228": "g9g89", + "col229": "7ut32", + "col230": "vzyco", + "col231": "g9hd4", + "col232": "y80gh", + "col233": "yniz8", + "col234": "xky38", + "col235": "5r88c", + "col236": "ugl0e", + "col237": "ctgl4", + "col238": "i59i0", + "col239": "x1mre", + "col240": "rdqf0", + "col241": "298b7", + "col242": "ano5b", + "col243": "88vsa", + "col244": "y6v9a", + "col245": "xrfeh", + "col246": "jgymh", + "col247": "e6tux", + "col248": "akijo", + "col249": "xxywj", + "col250": "9xmi3", + "col251": "wxsoc", + "col252": "grmy9", + "col253": "x21xe", + "col254": "gro33", + "col255": "r79mf", + "col256": "1fwdz", + "col257": "nqpix", + "col258": "uyeea", + "col259": "qmp0a", + "col260": "k8y8h", + "col261": "d1ws6", + "col262": "3yp53", + "col263": "qu5t1", + "col264": "qyihr", + "col265": "zl0go", + "col266": "ox01s", + "col267": "txkw0", + "col268": "xdvsc", + "col269": "ihldh", + "col270": "0mwy4", + "col271": "y968q", + "col272": "xyz85", + "col273": "ru5vd", + "col274": "cr0rl", + "col275": "ocjdv", + "col276": "1pzmu", + "col277": "46uzc", + "col278": "44x7h", + "col279": "n8xrd", + "col280": "fdmzg", + "col281": "o8x01", + "col282": "jzwfy", + "col283": "vjdg8", + "col284": "tkxch", + "col285": "blnxw", + "col286": "40j6x", + "col287": "lfbki", + "col288": "pg7ln", + "col289": "85m4g", + "col290": "uknn7", + "col291": "qqgpr", + "col292": "6r1pu", + "col293": "j81cf", + "col294": "ppm7j", + "col295": "pxt3j", + "col296": "sa5rp", + "col297": "uz7e0", + "col298": "hh7no", + "col299": "4anat", + "col300": "9brbd", + "col301": "q2t5b", + "col302": "ernv2", + "col303": "po2hu", + "col304": "7snny", + "col305": "s1lxd", + "col306": "h6eqy", + "col307": "zxpsh", + "col308": "2aggg", + "col309": "2fmvp", + "col310": "chjd8", + "col311": "0lt0j", + "col312": "nvz9t", + "col313": "38y1v", + "col314": "8r2ni", + "col315": "1ctg7", + "col316": "zurt1", + "col317": "vu0b9", + "col318": "vr4n8", + "col319": "2mftx", + "col320": "k5yh0", + "col321": "g36av", + "col322": "oiird", + "col323": "506tx", + "col324": "cexxl", + "col325": "f0e0w", + "col326": "mz5v3", + "col327": "paryo", + "col328": "569b4", + "col329": "37oyi", + "col330": "899dj", + "col331": "9c9fp", + "col332": "q4f12", + "col333": "jwd3i", + "col334": "4c891", + "col335": "qwhlz", + "col336": "yeu04", + "col337": "8m18x", + "col338": "juw5v", + "col339": "p7s4f", + "col340": "foa9k", + "col341": "p200k", + "col342": "9jth3", + "col343": "qlwcx", + "col344": "tpwep", + "col345": "h7ibs", + "col346": "ndnia", + "col347": "3ij28", + "col348": "lw75q", + "col349": "zcwh9", + "col350": "4jasd", + "col351": "h5zth", + "col352": "h0v4l", + "col353": "csiss", + "col354": "d4zjd", + "col355": "m9qbr", + "col356": "hrflp", + "col357": "ev6h6", + "col358": "00l9a", + "col359": "uou0n", + "col360": "uyij0", + "col361": "vum66", + "col362": "wm07l", + "col363": "0ickk", + "col364": "od0sw", + "col365": "s8b30", + "col366": "x19nx", + "col367": "8klzw", + "col368": "98g8e", + "col369": "ke7rm", + "col370": "gq9kg", + "col371": "00lgg", + "col372": "58xiu", + "col373": "bpxrm", + "col374": "ry5rn", + "col375": "mb10z", + "col376": "vcwtv", + "col377": "2ysh8", + "col378": "708fm", + "col379": "7mvjs", + "col380": "hvrbc", + "col381": "vgsyf", + "col382": "1nucx", + "col383": "pk6ab", + "col384": "z71je", + "col385": "xbdst", + "col386": "k88vx", + "col387": "qz5ml", + "col388": "7hr7r", + "col389": "0n1pg", + "col390": "ee9mf", + "col391": "okme4", + "col392": "gzwjt", + "col393": "w13ol", + "col394": "1jk2p", + "col395": "p3z40", + "col396": "3vw25", + "col397": "h8yry", + "col398": "pjpff", + "col399": "r6ldf", + "col400": "z5lpp", + "col401": "v23aq", + "col402": "3vi1t", + "col403": "5oj60", + "col404": "rkcx2", + "col405": "tbf2h", + "col406": "lfqmo", + "col407": "278yg", + "col408": "4u78i", + "col409": "h96y9", + "col410": "29jqa", + "col411": "l24z2", + "col412": "pudmk", + "col413": "51xih", + "col414": "w3m5p", + "col415": "kivjt", + "col416": "jdbw3", + "col417": "4l4yp", + "col418": "1t9yd", + "col419": "aklrs", + "col420": "l89th", + "col421": "l8zsq", + "col422": "24hh3", + "col423": "ly40r", + "col424": "kp5tk", + "col425": "ejwzw", + "col426": "0uyev", + "col427": "4g41h", + "col428": "t1tem", + "col429": "1pg36", + "col430": "92gs2", + "col431": "8llax", + "col432": "fhpkq", + "col433": "dc2b0", + "col434": "bhh4i", + "col435": "qhfwv", + "col436": "jpj3f", + "col437": "9zsw3", + "col438": "21zxe", + "col439": "j30su", + "col440": "kssvf", + "col441": "7471t", + "col442": "6ndi9", + "col443": "nrn7u", + "col444": "f8dzr", + "col445": "fv7g4", + "col446": "fum4v", + "col447": "ffz1z", + "col448": "62xli", + "col449": "7mets", + "col450": "l6wsm", + "col451": "lv62k", + "col452": "3w7nd", + "col453": "h0t3q", + "col454": "jzwfb", + "col455": "im6zo", + "col456": "xbiqz", + "col457": "iw10k", + "col458": "rmyf5", + "col459": "fxlwe", + "col460": "evss9", + "col461": "99bb1", + "col462": "lrwi1", + "col463": "nt2y6", + "col464": "x2gfp", + "col465": "iji3t", + "col466": "77xzx", + "col467": "il8n4", + "col468": "5wtde", + "col469": "hx54h", + "col470": "3l16p", + "col471": "96vfz", + "col472": "x33ea", + "col473": "0rl8r", + "col474": "13kaj", + "col475": "sju4b", + "col476": "fivjt", + "col477": "u3o1h", + "col478": "vdt8w", + "col479": "tuqfb", + "col480": "ysa1t", + "col481": "vwsr1", + "col482": "1qv3u", + "col483": "nhdwy", + "col484": "qtwhe", + "col485": "schik", + "col486": "p5rvl", + "col487": "77wi2", + "col488": "xun7d", + "col489": "4mwhh", + "col490": "u6msn", + "col491": "w19rl", + "col492": "5zpz7", + "col493": "dobvm", + "col494": "1ocov", + "col495": "w37ci", + "col496": "783wt", + "col497": "s5qfp", + "col498": "0xfjp", + "col499": "ivfmu", + "col500": "n1iph", + "col501": "1vhvc", + "col502": "ix1vc", + "col503": "ybi29", + "col504": "rzf14", + "col505": "iv61c", + "col506": "0khbg", + "col507": "154w6", + "col508": "yhn0p", + "col509": "xokdf", + "col510": "lnpvx", + "col511": "5ovdq", + "col512": "j0irt", + "col513": "h2fuk", + "col514": "ea55o", + "col515": "vtu3m", + "col516": "mgfgf", + "col517": "88z4t", + "col518": "x8fq5", + "col519": "i75xr", + "col520": "faozi", + "col521": "gn70o", + "col522": "96wdi", + "col523": "38jjq", + "col524": "met3a", + "col525": "hqjjb", + "col526": "3lufq", + "col527": "jnzr2", + "col528": "55dc5", + "col529": "kgja1", + "col530": "mxul7", + "col531": "7balz", + "col532": "lo5q9", + "col533": "aoylj", + "col534": "d36mw", + "col535": "t78u3", + "col536": "kxzyz", + "col537": "axqq7", + "col538": "j0t1y", + "col539": "2ieql", + "col540": "tbtst", + "col541": "tbegd", + "col542": "lxedp", + "col543": "lwmrw", + "col544": "btvf0", + "col545": "92j3b", + "col546": "y08j0", + "col547": "zat55", + "col548": "lerlm", + "col549": "03mmd", + "col550": "cqyzn", + "col551": "jzra4", + "col552": "z35zo", + "col553": "dehi2", + "col554": "pxtgc", + "col555": "dxzoo", + "col556": "kirmf", + "col557": "q2xpy", + "col558": "nojsj", + "col559": "dokk4", + "col560": "bj3zi", + "col561": "894so", + "col562": "iezad", + "col563": "ap43q", + "col564": "lcle5", + "col565": "xki4q", + "col566": "zq9xk", + "col567": "a6vh0", + "col568": "7j56z", + "col569": "elf5b", + "col570": "vniu4", + "col571": "12rkr", + "col572": "92ku4", + "col573": "z5rk8", + "col574": "vssfj", + "col575": "l83f4", + "col576": "3t72d", + "col577": "qkm2k", + "col578": "l5t6c", + "col579": "2j5rc", + "col580": "mvwl6", + "col581": "41g1t", + "col582": "vpxvp", + "col583": "c5684", + "col584": "1qri2", + "col585": "dtjbq", + "col586": "mfj3w", + "col587": "b4z56", + "col588": "ipkkb", + "col589": "wpctq", + "col590": "3pvns", + "col591": "ufdcx", + "col592": "by9ef", + "col593": "2sc1s", + "col594": "7ttxq", + "col595": "9evmv", + "col596": "qi36y", + "col597": "fgvj5", + "col598": "5akju", + "col599": "8lw7u", + "col600": "xjshe", + "col601": "hekwl", + "col602": "zhtl7", + "col603": "sp5lt", + "col604": "k85kc", + "col605": "3z1uz", + "col606": "6xi8c", + "col607": "o7jns", + "col608": "vml6b", + "col609": "5vhtt", + "col610": "khgkv", + "col611": "oehkc", + "col612": "n3gcr", + "col613": "7kug8", + "col614": "whli0", + "col615": "pupxy", + "col616": "eszsv", + "col617": "e4nei", + "col618": "7plch", + "col619": "6ya67", + "col620": "5nxug", + "col621": "v7vn8", + "col622": "zqpto", + "col623": "0y6na", + "col624": "bfpi2", + "col625": "la6i3", + "col626": "836cv", + "col627": "is3hr", + "col628": "d5a0y", + "col629": "2wfrq", + "col630": "iwevk", + "col631": "lh4uj", + "col632": "kfys3", + "col633": "jdqan", + "col634": "pbhdy", + "col635": "30nz6", + "col636": "mwgdj", + "col637": "upwnq", + "col638": "tc3bu", + "col639": "tk401", + "col640": "i11co", + "col641": "w36t4", + "col642": "z8jqu", + "col643": "q2nos", + "col644": "l7x79", + "col645": "1fves", + "col646": "14oet", + "col647": "7bits", + "col648": "pj5ve", + "col649": "7wq41", + "col650": "io41e", + "col651": "gjmsl", + "col652": "kx38l", + "col653": "q81r7", + "col654": "bgxwv", + "col655": "xn8b4", + "col656": "6n6hw", + "col657": "l816v", + "col658": "2oma2", + "col659": "nszxk", + "col660": "7o2p7", + "col661": "fc0nj", + "col662": "wccv2", + "col663": "yjkr1", + "col664": "4noc5", + "col665": "kts9c", + "col666": "skx09", + "col667": "9n5g2", + "col668": "ofddo", + "col669": "r7xl8", + "col670": "icify", + "col671": "irnsr", + "col672": "ipgwg", + "col673": "5l467", + "col674": "n6qvd", + "col675": "522bo", + "col676": "71eij", + "col677": "6vhey", + "col678": "47f8b", + "col679": "14zpg", + "col680": "c59rc", + "col681": "4w8zb", + "col682": "9wo5g", + "col683": "0zsau", + "col684": "k9jii", + "col685": "bi7j5", + "col686": "veuog", + "col687": "6mk72", + "col688": "chlck", + "col689": "fynuh", + "col690": "hpnqj", + "col691": "x65xc", + "col692": "vx6oc", + "col693": "r2g6g", + "col694": "zgi78", + "col695": "mskhz", + "col696": "vfuc7", + "col697": "f6oum", + "col698": "67wz0", + "col699": "9iezi", + "col700": "kaaw9", + "col701": "mrlin", + "col702": "ob47m", + "col703": "hq4kn", + "col704": "0y791", + "col705": "8x9xp", + "col706": "vg1jg", + "col707": "8poba", + "col708": "biy7f", + "col709": "oj1ma", + "col710": "7ozlp", + "col711": "rp9du", + "col712": "6qtar", + "col713": "ekj16", + "col714": "rnww5", + "col715": "7laun", + "col716": "cmolp", + "col717": "ouref", + "col718": "59yr3", + "col719": "t2psy", + "col720": "d8keu", + "col721": "5zhgh", + "col722": "6vynp", + "col723": "5d2ux", + "col724": "aymjx", + "col725": "tcnpn", + "col726": "nrju2", + "col727": "d9fy5", + "col728": "y8hyd", + "col729": "a68mv", + "col730": "uuqxo", + "col731": "jg321", + "col732": "yp9tn", + "col733": "1vadt", + "col734": "h8rnu", + "col735": "6nbq4", + "col736": "hf7t7", + "col737": "motwv", + "col738": "3sxtz", + "col739": "701zs", + "col740": "xxedr", + "col741": "lrsrh", + "col742": "8yv5u", + "col743": "rbjvh", + "col744": "jy3ze", + "col745": "qhuo2", + "col746": "0xnxi", + "col747": "7eomv", + "col748": "t2ilr", + "col749": "8wnn8", + "col750": "xopio", + "col751": "v8387", + "col752": "xf7j9", + "col753": "eweqw", + "col754": "x5gjl", + "col755": "ysszu", + "col756": "xeufo", + "col757": "k8kzy", + "col758": "53jbz", + "col759": "t03qh", + "col760": "7o40l", + "col761": "6qvx7", + "col762": "t23t4", + "col763": "vhxwo", + "col764": "qvxed", + "col765": "7wuki", + "col766": "rckpb", + "col767": "cil6d", + "col768": "h435a", + "col769": "rmswu", + "col770": "enwjp", + "col771": "qy3w8", + "col772": "dy2wp", + "col773": "1hyuk", + "col774": "gl2vd", + "col775": "8t13n", + "col776": "grk2y", + "col777": "3qqr9", + "col778": "c6rgv", + "col779": "ezrtk", + "col780": "fo4x7", + "col781": "be7zn", + "col782": "azuyq", + "col783": "mxpkq", + "col784": "ouesz", + "col785": "1l22h", + "col786": "6ilhi", + "col787": "f5fe5", + "col788": "7db6r", + "col789": "zcaja", + "col790": "8arho", + "col791": "z76q9", + "col792": "yamxh", + "col793": "hugen", + "col794": "3h0hs", + "col795": "lvxah", + "col796": "ss4u1", + "col797": "rn9pd", + "col798": "2o5ox", + "col799": "aqb8i", + "col800": "os9c2", + "col801": "rltg0", + "col802": "wc3f7", + "col803": "0f5m2", + "col804": "s80of", + "col805": "ttzov", + "col806": "k00zc", + "col807": "sujrj", + "col808": "9a2bq", + "col809": "l4xlj", + "col810": "33xkv", + "col811": "107g5", + "col812": "kosbh", + "col813": "fkavs", + "col814": "4nqti", + "col815": "9ncpz", + "col816": "k6646", + "col817": "hy8u0", + "col818": "g94ya", + "col819": "q92sw", + "col820": "umy68", + "col821": "5mzr7", + "col822": "32kkm", + "col823": "vm47b", + "col824": "8kepo", + "col825": "fld8v", + "col826": "3b9q2", + "col827": "0dhys", + "col828": "9zgui", + "col829": "l2v8e", + "col830": "tcnl4", + "col831": "j22li", + "col832": "9l1vd", + "col833": "rqprt", + "col834": "4yqj9", + "col835": "o0p84", + "col836": "1i1wv", + "col837": "v2lha", + "col838": "g0mag", + "col839": "g5ecy", + "col840": "0le7s", + "col841": "booh9", + "col842": "75b74", + "col843": "q7s6b", + "col844": "cqu88", + "col845": "lhcn3", + "col846": "cqskx", + "col847": "7m71v", + "col848": "5kuss", + "col849": "b0pwn", + "col850": "sglx4", + "col851": "9ofsf", + "col852": "ffc0x", + "col853": "9nz80", + "col854": "2t8zx", + "col855": "0x94v", + "col856": "60i4s", + "col857": "0gypy", + "col858": "5u4vi", + "col859": "saj7a", + "col860": "u78wz", + "col861": "nadlu", + "col862": "4eydd", + "col863": "e2aje", + "col864": "e98es", + "col865": "m7a58", + "col866": "mhzd5", + "col867": "1isis", + "col868": "yihok", + "col869": "2fc9r", + "col870": "4v7qr", + "col871": "gude4", + "col872": "bg0dr", + "col873": "or0u4", + "col874": "kuip8", + "col875": "zjgew", + "col876": "znhc0", + "col877": "4g6f9", + "col878": "1vrxp", + "col879": "2qd98", + "col880": "48iy6", + "col881": "tmc83", + "col882": "j8ygx", + "col883": "y7sg4", + "col884": "i0hk9", + "col885": "tfb0v", + "col886": "xrau3", + "col887": "yxpc3", + "col888": "gc3ju", + "col889": "h3w94", + "col890": "qa9sz", + "col891": "v6790", + "col892": "qbutr", + "col893": "xk76m", + "col894": "kihyd", + "col895": "y5mvi", + "col896": "u82pf", + "col897": "jiwg0", + "col898": "7bs0j", + "col899": "tp48l", + "col900": "7yset", + "col901": "bcnwa", + "col902": "xu2p3", + "col903": "06pzz", + "col904": "d579f", + "col905": "8mdqs", + "col906": "r5hkg", + "col907": "5tgcj", + "col908": "9a5lw", + "col909": "5ga05", + "col910": "cpkif", + "col911": "st868", + "col912": "om15h", + "col913": "8o6cg", + "col914": "08y3g", + "col915": "tegrx", + "col916": "0pqbg", + "col917": "v1jfd", + "col918": "8qtav", + "col919": "hlixl", + "col920": "is1x2", + "col921": "t7o1d", + "col922": "wdn13", + "col923": "pan6h", + "col924": "14w23", + "col925": "6ch47", + "col926": "bwb8t", + "col927": "cuptj", + "col928": "tyrgu", + "col929": "rt6pz", + "col930": "la3gk", + "col931": "diqug", + "col932": "49ekg", + "col933": "lcbin", + "col934": "u88ko", + "col935": "j8eci", + "col936": "rwz2b", + "col937": "qm1fl", + "col938": "zm2ae", + "col939": "6ry54", + "col940": "kg7nv", + "col941": "9av2d", + "col942": "br7qc", + "col943": "vvxi0", + "col944": "t712p", + "col945": "2tu8a", + "col946": "6y94t", + "col947": "1skhi", + "col948": "7d5sv", + "col949": "jxqsw", + "col950": "9cl0q", + "col951": "fv9x9", + "col952": "ezbp1", + "col953": "ygcs4", + "col954": "pkbdc", + "col955": "j5bxb", + "col956": "g9plz", + "col957": "h4q3g", + "col958": "8bjj0", + "col959": "i28lk", + "col960": "nycs5", + "col961": "elhby", + "col962": "cs4ls", + "col963": "cnhqq", + "col964": "px23d", + "col965": "4ulch", + "col966": "insfb", + "col967": "ci6k7", + "col968": "1gt2v", + "col969": "kwlfm", + "col970": "syp5f", + "col971": "bvggu", + "col972": "jjgzb", + "col973": "mva0x", + "col974": "vnhnx", + "col975": "wq198", + "col976": "tmiwf", + "col977": "h232c", + "col978": "o3a8v", + "col979": "laps0", + "col980": "c74qj", + "col981": "zmfje", + "col982": "vwpr8", + "col983": "qauo6", + "col984": "nc29j", + "col985": "q0opi", + "col986": "m4uvb", + "col987": "royjj", + "col988": "hmfi2", + "col989": "7r8rd", + "col990": "n3764", + "col991": "nz75p", + "col992": "d3xvc", + "col993": "y9cif", + "col994": "maoxm", + "col995": "bhw7s", + "col996": "0bhi5", + "col997": "t1qqm", + "col998": "8yacu", + "col999": "0anqy" + }, + { + "name": "Kidd Stanton", + "gender": "male", + "col0": "iol3b", + "col1": "qs3fp", + "col2": "116bm", + "col3": "z7kqa", + "col4": "h0umf", + "col5": "nplng", + "col6": "vmg8y", + "col7": "rjp5z", + "col8": "98d3u", + "col9": "e090g", + "col10": "9smkp", + "col11": "mwouc", + "col12": "o4aq3", + "col13": "38uie", + "col14": "znbpq", + "col15": "n55on", + "col16": "jzot3", + "col17": "7vdjw", + "col18": "f6pa6", + "col19": "h7pbh", + "col20": "o91om", + "col21": "irqs0", + "col22": "3k5b2", + "col23": "i7gvn", + "col24": "b2trv", + "col25": "3fe35", + "col26": "yy5os", + "col27": "p95o7", + "col28": "2inct", + "col29": "wm3j1", + "col30": "rglie", + "col31": "wnha4", + "col32": "ejlf2", + "col33": "60vca", + "col34": "hhr2f", + "col35": "8tsce", + "col36": "4yi16", + "col37": "nuywr", + "col38": "wjhsb", + "col39": "byxea", + "col40": "t1yay", + "col41": "s13cl", + "col42": "t6kmb", + "col43": "pe9hy", + "col44": "ymjze", + "col45": "yvo2h", + "col46": "loitj", + "col47": "1hql0", + "col48": "r8dd5", + "col49": "ob3ax", + "col50": "nzp6w", + "col51": "ewcj0", + "col52": "zjhnr", + "col53": "n34sd", + "col54": "wlbbp", + "col55": "z7wha", + "col56": "8xm20", + "col57": "86rlz", + "col58": "vaa0t", + "col59": "jh3ip", + "col60": "z7qji", + "col61": "9it1z", + "col62": "lip28", + "col63": "5dyq6", + "col64": "ba5j8", + "col65": "uvpm6", + "col66": "a3z9n", + "col67": "e66kq", + "col68": "sbhs3", + "col69": "hv0s6", + "col70": "dalma", + "col71": "2rwip", + "col72": "lt3i5", + "col73": "man5g", + "col74": "307r9", + "col75": "jqksv", + "col76": "0gnp5", + "col77": "fnbqn", + "col78": "f93dj", + "col79": "cg4l2", + "col80": "giujm", + "col81": "nptiz", + "col82": "5fedt", + "col83": "m4vfu", + "col84": "zd7xu", + "col85": "q8302", + "col86": "n0zu0", + "col87": "kwqb9", + "col88": "ppkw8", + "col89": "le03g", + "col90": "pessg", + "col91": "2x9ax", + "col92": "jfg4s", + "col93": "ds8bh", + "col94": "ad92i", + "col95": "dm3c0", + "col96": "pnqym", + "col97": "1rzdm", + "col98": "ufm4z", + "col99": "gc26x", + "col100": "lqmhs", + "col101": "itlv0", + "col102": "2vd9n", + "col103": "xi9et", + "col104": "x9i7y", + "col105": "h8hun", + "col106": "duqi6", + "col107": "r1s4l", + "col108": "n6ei6", + "col109": "mwq26", + "col110": "qzd00", + "col111": "90hbo", + "col112": "me063", + "col113": "qdy9o", + "col114": "6pf4f", + "col115": "vkgqf", + "col116": "uf1px", + "col117": "gj3ua", + "col118": "nm21v", + "col119": "nu99q", + "col120": "xvluh", + "col121": "i2563", + "col122": "of3hh", + "col123": "zjrvk", + "col124": "6cdod", + "col125": "x9lt0", + "col126": "lccln", + "col127": "2bf3o", + "col128": "c68ng", + "col129": "amwe2", + "col130": "dwftc", + "col131": "bwftl", + "col132": "o4pjd", + "col133": "xh5k3", + "col134": "15pur", + "col135": "o66ih", + "col136": "gedic", + "col137": "szfxr", + "col138": "oiryk", + "col139": "nk8wj", + "col140": "03dyf", + "col141": "fyd09", + "col142": "2o854", + "col143": "bmcya", + "col144": "summt", + "col145": "eh0sw", + "col146": "w2hx7", + "col147": "by2pn", + "col148": "5ukqr", + "col149": "ir773", + "col150": "0cu69", + "col151": "4jdn5", + "col152": "d75g0", + "col153": "j0lkt", + "col154": "d9vtc", + "col155": "wpxvm", + "col156": "pdb8y", + "col157": "ea148", + "col158": "ibcjv", + "col159": "3yfup", + "col160": "t9odk", + "col161": "0k57b", + "col162": "8dw00", + "col163": "mfkuy", + "col164": "zl0r1", + "col165": "q5wbs", + "col166": "txedh", + "col167": "7v771", + "col168": "0hg9z", + "col169": "1x29e", + "col170": "62nr4", + "col171": "redu9", + "col172": "9i8gi", + "col173": "irbjt", + "col174": "ajl32", + "col175": "pk8r0", + "col176": "gq8v8", + "col177": "4u3h3", + "col178": "n1j96", + "col179": "0gy5l", + "col180": "i43ee", + "col181": "ieccf", + "col182": "2tpao", + "col183": "s9hke", + "col184": "9rgum", + "col185": "gjptz", + "col186": "k2rqn", + "col187": "5h1xm", + "col188": "xrvys", + "col189": "ntj2c", + "col190": "4dhl8", + "col191": "jw8lh", + "col192": "1nik4", + "col193": "38123", + "col194": "ys7hm", + "col195": "rv0xx", + "col196": "e8jwr", + "col197": "dsdou", + "col198": "4oa7p", + "col199": "rau1i", + "col200": "rfipr", + "col201": "qmm03", + "col202": "0267f", + "col203": "3yq25", + "col204": "n7r6p", + "col205": "u39di", + "col206": "7ra8g", + "col207": "qkdgp", + "col208": "7asyu", + "col209": "xs0c6", + "col210": "bosoq", + "col211": "ul699", + "col212": "5pvrm", + "col213": "tfa2u", + "col214": "a95iq", + "col215": "am2zm", + "col216": "pfasy", + "col217": "qgpxx", + "col218": "wa03a", + "col219": "v5zhh", + "col220": "fjr0z", + "col221": "1z8bb", + "col222": "vwnki", + "col223": "9e2tl", + "col224": "a57md", + "col225": "azkcy", + "col226": "3h2l1", + "col227": "8777i", + "col228": "4h7p1", + "col229": "oqfmf", + "col230": "8aafr", + "col231": "sa2i3", + "col232": "iizad", + "col233": "4fniv", + "col234": "j3xer", + "col235": "u92u8", + "col236": "t4wbz", + "col237": "0tbuf", + "col238": "3dzs4", + "col239": "3etnf", + "col240": "ntpzi", + "col241": "z6uhm", + "col242": "12u1q", + "col243": "rmgrh", + "col244": "4hw0r", + "col245": "1e4dg", + "col246": "5mi0z", + "col247": "qyfjy", + "col248": "4kocv", + "col249": "u2xog", + "col250": "yi67j", + "col251": "eqc2w", + "col252": "bw4xi", + "col253": "facef", + "col254": "lqhtm", + "col255": "k9n0s", + "col256": "3vgxu", + "col257": "cpm8q", + "col258": "9xrfi", + "col259": "a83ih", + "col260": "5nlkk", + "col261": "i1f4t", + "col262": "04yt5", + "col263": "ug0gu", + "col264": "351ts", + "col265": "kou4s", + "col266": "xq3cn", + "col267": "1804e", + "col268": "gj878", + "col269": "xt7d6", + "col270": "uhgb6", + "col271": "7pnrw", + "col272": "84t02", + "col273": "e8g9w", + "col274": "rl8qq", + "col275": "2um3y", + "col276": "rxow5", + "col277": "3bpvv", + "col278": "w3gr9", + "col279": "e903l", + "col280": "4qprf", + "col281": "0f4yp", + "col282": "c4rs6", + "col283": "0qfnw", + "col284": "lp0uh", + "col285": "5yvyz", + "col286": "npysv", + "col287": "dalxl", + "col288": "yiqyf", + "col289": "zq64q", + "col290": "8tcqh", + "col291": "2pcwf", + "col292": "punr1", + "col293": "90f0j", + "col294": "xul1z", + "col295": "0zi7p", + "col296": "kdj52", + "col297": "i3dll", + "col298": "kybb3", + "col299": "zcj8g", + "col300": "r1prk", + "col301": "p0qsi", + "col302": "o75md", + "col303": "gsal2", + "col304": "eepnx", + "col305": "0eug0", + "col306": "loezm", + "col307": "65z2p", + "col308": "um1le", + "col309": "gce61", + "col310": "extjt", + "col311": "04by0", + "col312": "hbgm1", + "col313": "5sg94", + "col314": "l7d7g", + "col315": "f9zu6", + "col316": "a8m1v", + "col317": "g4ie2", + "col318": "spb6y", + "col319": "h8lg0", + "col320": "97fkk", + "col321": "utf4f", + "col322": "km5ra", + "col323": "kv8qm", + "col324": "uq10m", + "col325": "oitqt", + "col326": "84fhp", + "col327": "lmf9b", + "col328": "xhs72", + "col329": "627t3", + "col330": "yr3h2", + "col331": "gkzos", + "col332": "iy3uh", + "col333": "uf0ea", + "col334": "iwcws", + "col335": "cg6q1", + "col336": "lovdp", + "col337": "3fz2j", + "col338": "rkzu8", + "col339": "xfc6j", + "col340": "enmv9", + "col341": "11yu3", + "col342": "tt2wu", + "col343": "ioxkj", + "col344": "9q3n9", + "col345": "09g35", + "col346": "l3xf5", + "col347": "q5xm9", + "col348": "6l6xy", + "col349": "uwehg", + "col350": "q2yx5", + "col351": "5mr2a", + "col352": "7s87h", + "col353": "mnaz5", + "col354": "k7sak", + "col355": "lokst", + "col356": "6km0n", + "col357": "y32uc", + "col358": "40xtf", + "col359": "jz7f4", + "col360": "ykyy6", + "col361": "x9f7v", + "col362": "bqtfx", + "col363": "runwc", + "col364": "pkjwo", + "col365": "h7olb", + "col366": "21vwa", + "col367": "efqh6", + "col368": "wp2b9", + "col369": "vymhr", + "col370": "16cc9", + "col371": "0voqx", + "col372": "zkb0b", + "col373": "691qu", + "col374": "bca73", + "col375": "mn3p3", + "col376": "drw62", + "col377": "al2sd", + "col378": "sivzz", + "col379": "bw0b6", + "col380": "4xzv0", + "col381": "apsmr", + "col382": "dxjdf", + "col383": "dyfst", + "col384": "b3evj", + "col385": "per76", + "col386": "dgw34", + "col387": "qcdrn", + "col388": "5r3qi", + "col389": "47v90", + "col390": "85xgn", + "col391": "a9x1x", + "col392": "v4vb3", + "col393": "pt9g8", + "col394": "e84cn", + "col395": "awcxc", + "col396": "yih0b", + "col397": "kyq8k", + "col398": "qbjjj", + "col399": "t62kk", + "col400": "5wh6p", + "col401": "rpy1e", + "col402": "tevta", + "col403": "lljtw", + "col404": "ysic3", + "col405": "3jve3", + "col406": "3k61n", + "col407": "320hy", + "col408": "4hn2n", + "col409": "0ivxi", + "col410": "r51sv", + "col411": "3r152", + "col412": "wjuln", + "col413": "71fi1", + "col414": "14k66", + "col415": "y2ih8", + "col416": "1xbja", + "col417": "ued6g", + "col418": "61ih9", + "col419": "z1l2d", + "col420": "b1nnn", + "col421": "1xpu8", + "col422": "vbgso", + "col423": "ai02r", + "col424": "5i4ro", + "col425": "znag3", + "col426": "67gqn", + "col427": "feorv", + "col428": "wfova", + "col429": "gce0s", + "col430": "kgqrb", + "col431": "50vhv", + "col432": "5zdma", + "col433": "ahhgb", + "col434": "kfx9i", + "col435": "r81q8", + "col436": "qel4y", + "col437": "q7cdv", + "col438": "bn8di", + "col439": "1jesh", + "col440": "sow8f", + "col441": "auqoo", + "col442": "xf3a5", + "col443": "52gel", + "col444": "76xvx", + "col445": "4ek4e", + "col446": "tu8j7", + "col447": "9vw7l", + "col448": "ezkm0", + "col449": "grkys", + "col450": "0g5hj", + "col451": "vsvor", + "col452": "i7g0n", + "col453": "3w7w6", + "col454": "sjsjx", + "col455": "op6n2", + "col456": "4nt38", + "col457": "ld6fp", + "col458": "jx6yc", + "col459": "7nfw0", + "col460": "mxnbc", + "col461": "wb37i", + "col462": "6944f", + "col463": "omctq", + "col464": "i4744", + "col465": "j8tg2", + "col466": "vvk9s", + "col467": "24vft", + "col468": "4n8du", + "col469": "m0p4c", + "col470": "hr189", + "col471": "4y4w8", + "col472": "i52fy", + "col473": "hj35b", + "col474": "ialoo", + "col475": "8ixvx", + "col476": "hkb2x", + "col477": "sghaw", + "col478": "psdvr", + "col479": "h8ktt", + "col480": "0v55c", + "col481": "5yurh", + "col482": "7vh8i", + "col483": "rz3go", + "col484": "xeduc", + "col485": "qx5oo", + "col486": "iryhq", + "col487": "47jba", + "col488": "07myl", + "col489": "r35fc", + "col490": "9jeqq", + "col491": "ju5ud", + "col492": "rhwtq", + "col493": "kzmht", + "col494": "d2see", + "col495": "bbfiz", + "col496": "bid4m", + "col497": "oo7t8", + "col498": "4jcpi", + "col499": "ic4sc", + "col500": "lsx53", + "col501": "39zsi", + "col502": "56qan", + "col503": "rv544", + "col504": "u7nz3", + "col505": "vdidn", + "col506": "nbi2c", + "col507": "ltxzu", + "col508": "p4v2v", + "col509": "u3t4y", + "col510": "js27y", + "col511": "7cnl5", + "col512": "fz171", + "col513": "dkvqs", + "col514": "lwklp", + "col515": "zgr4i", + "col516": "cv318", + "col517": "c4b8o", + "col518": "efkv1", + "col519": "r78x9", + "col520": "5t3df", + "col521": "g5bz8", + "col522": "9is55", + "col523": "g7bih", + "col524": "swpmz", + "col525": "291on", + "col526": "xrhq3", + "col527": "r9hcc", + "col528": "4cyk9", + "col529": "6uwjw", + "col530": "lb6e1", + "col531": "eqaf5", + "col532": "krduk", + "col533": "i8zd5", + "col534": "u9gwq", + "col535": "5930o", + "col536": "zzfiu", + "col537": "sbfln", + "col538": "x7gv3", + "col539": "fvgcx", + "col540": "cdbdy", + "col541": "2vmc7", + "col542": "ao1d7", + "col543": "blt0n", + "col544": "m3lc2", + "col545": "j87k6", + "col546": "fph3h", + "col547": "3lxvf", + "col548": "36b69", + "col549": "cmxoa", + "col550": "a3zb7", + "col551": "lmr8u", + "col552": "695oe", + "col553": "ln7zu", + "col554": "hj9kb", + "col555": "f0x7u", + "col556": "4ws31", + "col557": "gb8p0", + "col558": "wkiz0", + "col559": "kalqy", + "col560": "etdia", + "col561": "sbc4t", + "col562": "n5jnl", + "col563": "2p6bg", + "col564": "wgcn8", + "col565": "gnzbz", + "col566": "yje29", + "col567": "cxgja", + "col568": "kup23", + "col569": "omaa5", + "col570": "pkcmb", + "col571": "6d95n", + "col572": "bo1hz", + "col573": "vmlt1", + "col574": "rh05n", + "col575": "4l0rs", + "col576": "0shtk", + "col577": "rwke5", + "col578": "6lr1h", + "col579": "gwsjo", + "col580": "k1ttx", + "col581": "zanlb", + "col582": "6pk2l", + "col583": "77yab", + "col584": "hst4b", + "col585": "oacj1", + "col586": "uws6h", + "col587": "sbeuk", + "col588": "dcxr3", + "col589": "4n5of", + "col590": "3fjji", + "col591": "kifx8", + "col592": "923u8", + "col593": "vlip4", + "col594": "opkhh", + "col595": "q9i1p", + "col596": "oeqwa", + "col597": "om25o", + "col598": "z1ov7", + "col599": "ehjok", + "col600": "0vzkn", + "col601": "rem60", + "col602": "n0rf4", + "col603": "itmcm", + "col604": "nazo8", + "col605": "uaq1f", + "col606": "wx7cp", + "col607": "lv1sy", + "col608": "otsdy", + "col609": "mik91", + "col610": "7ut3i", + "col611": "l6ywq", + "col612": "slbks", + "col613": "af7to", + "col614": "lwkia", + "col615": "ojp92", + "col616": "pcx5a", + "col617": "oqi3a", + "col618": "n9xzi", + "col619": "o0xab", + "col620": "jxffx", + "col621": "y9af2", + "col622": "1m25x", + "col623": "9j7lq", + "col624": "lzxss", + "col625": "xojo5", + "col626": "fo0t6", + "col627": "uw190", + "col628": "wydqq", + "col629": "79mur", + "col630": "jc5y6", + "col631": "x7sz8", + "col632": "yzpmx", + "col633": "tildk", + "col634": "a8f1v", + "col635": "u86nu", + "col636": "r1hui", + "col637": "2qs5t", + "col638": "8jval", + "col639": "9gw8u", + "col640": "91zob", + "col641": "gu9yx", + "col642": "l0d7h", + "col643": "wel4s", + "col644": "idred", + "col645": "m5gys", + "col646": "a81ar", + "col647": "xdsrx", + "col648": "ivokv", + "col649": "ogwpt", + "col650": "t4n95", + "col651": "k8o6i", + "col652": "25zch", + "col653": "a3eaa", + "col654": "alntu", + "col655": "pkm03", + "col656": "rgksc", + "col657": "qjcr6", + "col658": "9w36v", + "col659": "8ydg3", + "col660": "k1q8j", + "col661": "8unm4", + "col662": "ab5j7", + "col663": "d6uyf", + "col664": "j2ut1", + "col665": "d3ciu", + "col666": "3u7i3", + "col667": "ntu06", + "col668": "a4cm8", + "col669": "cvt58", + "col670": "vi5xl", + "col671": "h9gwo", + "col672": "emh58", + "col673": "bb1f4", + "col674": "jnqjh", + "col675": "4vssr", + "col676": "umle0", + "col677": "hfrxo", + "col678": "ce684", + "col679": "qdxbz", + "col680": "9t0pc", + "col681": "ykbvm", + "col682": "mbajz", + "col683": "8sclw", + "col684": "tjx5f", + "col685": "1hkan", + "col686": "06mhj", + "col687": "ier1r", + "col688": "3it30", + "col689": "m1xis", + "col690": "9c5vg", + "col691": "5qsc0", + "col692": "3te0l", + "col693": "r6hgu", + "col694": "nazg5", + "col695": "p3kvn", + "col696": "ijfq0", + "col697": "8di5n", + "col698": "0sxpv", + "col699": "1xu07", + "col700": "bo3n9", + "col701": "lzvxu", + "col702": "boz67", + "col703": "johil", + "col704": "gdtrq", + "col705": "c3clp", + "col706": "a0267", + "col707": "e0wu4", + "col708": "pnel4", + "col709": "ladvf", + "col710": "62fgg", + "col711": "kcivu", + "col712": "o4y57", + "col713": "9rv4j", + "col714": "u9ii4", + "col715": "xvck2", + "col716": "hfo82", + "col717": "j6nu7", + "col718": "uzwzl", + "col719": "sufzk", + "col720": "1j98c", + "col721": "z81bp", + "col722": "xo5kv", + "col723": "4hn57", + "col724": "41gno", + "col725": "uqoqu", + "col726": "m1zkm", + "col727": "qys1y", + "col728": "0nxqw", + "col729": "vzotp", + "col730": "ecp4k", + "col731": "jshrq", + "col732": "09e6e", + "col733": "ralo7", + "col734": "r5y84", + "col735": "vry21", + "col736": "3g8qh", + "col737": "9cwin", + "col738": "ww7od", + "col739": "83pup", + "col740": "ck8y9", + "col741": "vxhnq", + "col742": "mva3m", + "col743": "cispa", + "col744": "380hk", + "col745": "wsl2k", + "col746": "n2dhl", + "col747": "5diyf", + "col748": "jfil9", + "col749": "b39ho", + "col750": "077k1", + "col751": "d9t1w", + "col752": "9wq9t", + "col753": "4yxy3", + "col754": "8wxx0", + "col755": "ih39o", + "col756": "4wqrl", + "col757": "zpg0m", + "col758": "98pzp", + "col759": "ze98u", + "col760": "kidys", + "col761": "cy7vm", + "col762": "yzsii", + "col763": "r5cv0", + "col764": "9vyeh", + "col765": "fvoll", + "col766": "nc7rw", + "col767": "duj4z", + "col768": "it3rx", + "col769": "u78b1", + "col770": "i4vys", + "col771": "22xg4", + "col772": "bpig0", + "col773": "76j9r", + "col774": "0k3sw", + "col775": "zpthj", + "col776": "b7qwt", + "col777": "v7qvc", + "col778": "szmpf", + "col779": "yg04g", + "col780": "vaupu", + "col781": "8xxuu", + "col782": "7rum4", + "col783": "mw6tm", + "col784": "71okf", + "col785": "kx844", + "col786": "wqt7t", + "col787": "21114", + "col788": "rjjv8", + "col789": "msih1", + "col790": "p2zp4", + "col791": "uczzn", + "col792": "et1mx", + "col793": "cvlwo", + "col794": "hul64", + "col795": "wmq3h", + "col796": "xyjpr", + "col797": "bnfi2", + "col798": "m1hnn", + "col799": "mp7dc", + "col800": "dapp0", + "col801": "uuxmg", + "col802": "560ls", + "col803": "y76gj", + "col804": "5z7qi", + "col805": "g7fc4", + "col806": "g59vd", + "col807": "ktgk8", + "col808": "slhfu", + "col809": "cqcsh", + "col810": "s824q", + "col811": "rdoeh", + "col812": "u90fc", + "col813": "qf96f", + "col814": "3b3vj", + "col815": "54pp9", + "col816": "eji85", + "col817": "tbyml", + "col818": "5uanp", + "col819": "h1cro", + "col820": "im2qw", + "col821": "0qo93", + "col822": "ie0eo", + "col823": "sa89o", + "col824": "omls5", + "col825": "6ljes", + "col826": "l3zmc", + "col827": "c09gm", + "col828": "0z22l", + "col829": "w1j2s", + "col830": "udhxo", + "col831": "uqr54", + "col832": "v1fov", + "col833": "iusmz", + "col834": "e5p72", + "col835": "j9nvi", + "col836": "ue4vc", + "col837": "lvlek", + "col838": "190x8", + "col839": "ka8p6", + "col840": "qcmaq", + "col841": "nhg96", + "col842": "xovs2", + "col843": "mn8ui", + "col844": "2ceys", + "col845": "71k59", + "col846": "4dsth", + "col847": "3ckrw", + "col848": "bqfon", + "col849": "19n6c", + "col850": "x3dg0", + "col851": "xlbud", + "col852": "sl2wy", + "col853": "8yeof", + "col854": "ecqko", + "col855": "hioqv", + "col856": "tz6hj", + "col857": "bcs7h", + "col858": "ko512", + "col859": "omede", + "col860": "on721", + "col861": "kcilo", + "col862": "6qba2", + "col863": "b2hou", + "col864": "eltc5", + "col865": "2c4xj", + "col866": "vq61v", + "col867": "glbdt", + "col868": "b93nw", + "col869": "ofwz5", + "col870": "urejv", + "col871": "t3k5x", + "col872": "zvxp2", + "col873": "c9fpj", + "col874": "g2435", + "col875": "57z76", + "col876": "ktjkw", + "col877": "3qnpk", + "col878": "p3cly", + "col879": "d6gkg", + "col880": "xfexz", + "col881": "rc6vb", + "col882": "dxm15", + "col883": "6tg14", + "col884": "tnx5e", + "col885": "xhm8t", + "col886": "k2tla", + "col887": "05q93", + "col888": "qhbwi", + "col889": "wh4qa", + "col890": "dqxwb", + "col891": "afczk", + "col892": "v34c8", + "col893": "oz5ih", + "col894": "9ajme", + "col895": "yx9fh", + "col896": "eq35n", + "col897": "zk2ss", + "col898": "xnpb0", + "col899": "jttrg", + "col900": "rnmv0", + "col901": "505qu", + "col902": "44dys", + "col903": "6ytj3", + "col904": "7r77i", + "col905": "mmkh8", + "col906": "gcce4", + "col907": "2oat1", + "col908": "5ubb4", + "col909": "3pu0d", + "col910": "wz4oz", + "col911": "l4glp", + "col912": "loiaa", + "col913": "060e0", + "col914": "oborj", + "col915": "tkouh", + "col916": "x4z10", + "col917": "dzlsj", + "col918": "hm5bc", + "col919": "mgotz", + "col920": "nedym", + "col921": "ra3tr", + "col922": "jma4m", + "col923": "nf0z9", + "col924": "fakn9", + "col925": "lh3yk", + "col926": "1057r", + "col927": "vp4ls", + "col928": "o81xd", + "col929": "1h2tj", + "col930": "n7hz8", + "col931": "bxc76", + "col932": "ffrzj", + "col933": "k50hv", + "col934": "0u1ix", + "col935": "hahx0", + "col936": "y2h5u", + "col937": "ov7of", + "col938": "05ps8", + "col939": "v70fz", + "col940": "w2t0n", + "col941": "78yd1", + "col942": "buo2i", + "col943": "sx82t", + "col944": "wlobq", + "col945": "jyiby", + "col946": "cpzx4", + "col947": "hlylc", + "col948": "9npsj", + "col949": "8j9gg", + "col950": "qqmyv", + "col951": "30rh6", + "col952": "tygda", + "col953": "fzr90", + "col954": "g7xe3", + "col955": "fdck1", + "col956": "5onwy", + "col957": "8yk7g", + "col958": "b942k", + "col959": "mbd94", + "col960": "md18m", + "col961": "r71b3", + "col962": "giemk", + "col963": "qdmln", + "col964": "ucoyw", + "col965": "12mpt", + "col966": "cycl0", + "col967": "ru7ss", + "col968": "dju3d", + "col969": "upj42", + "col970": "yg4h3", + "col971": "k0909", + "col972": "ln6y5", + "col973": "bbx5c", + "col974": "2svnx", + "col975": "37wu9", + "col976": "pxl83", + "col977": "l8j5v", + "col978": "jju6q", + "col979": "nnc4u", + "col980": "920a4", + "col981": "frx7z", + "col982": "lfvou", + "col983": "j9vky", + "col984": "erg8i", + "col985": "iuile", + "col986": "9pr3a", + "col987": "c6aqf", + "col988": "za63p", + "col989": "kmkyf", + "col990": "lx62j", + "col991": "c1swg", + "col992": "znyvq", + "col993": "6vnct", + "col994": "fgw3z", + "col995": "evlzs", + "col996": "6prle", + "col997": "wev63", + "col998": "dfktt", + "col999": "vdl8k" + }, + { + "name": "Davis Wong", + "gender": "male", + "col0": "rt6ui", + "col1": "0qbbu", + "col2": "7q6dd", + "col3": "5ftu9", + "col4": "mi57y", + "col5": "1rrwn", + "col6": "r52hg", + "col7": "mj5nk", + "col8": "qnc25", + "col9": "f3u8q", + "col10": "wy7eg", + "col11": "23f3f", + "col12": "d51yz", + "col13": "oaymv", + "col14": "vu2kt", + "col15": "wol5n", + "col16": "bwqxj", + "col17": "7gk8l", + "col18": "15rap", + "col19": "ik6at", + "col20": "fls7y", + "col21": "quor3", + "col22": "j3wt8", + "col23": "3vmd3", + "col24": "koupf", + "col25": "nw5gx", + "col26": "w7f3t", + "col27": "yywvc", + "col28": "nq9ac", + "col29": "kf0ne", + "col30": "xt17g", + "col31": "0ohzk", + "col32": "djf78", + "col33": "89p1z", + "col34": "do4in", + "col35": "9xmim", + "col36": "h8xzc", + "col37": "s3om0", + "col38": "8tnru", + "col39": "tq9o7", + "col40": "rzfs4", + "col41": "u4rha", + "col42": "shtbh", + "col43": "kbod3", + "col44": "i80cl", + "col45": "ve24i", + "col46": "fjh1r", + "col47": "fjve4", + "col48": "3evkw", + "col49": "8s63m", + "col50": "5y0fe", + "col51": "cz27o", + "col52": "2y76o", + "col53": "or1b4", + "col54": "529tx", + "col55": "rgdbz", + "col56": "f11ym", + "col57": "9bht3", + "col58": "9ygs2", + "col59": "ko7pw", + "col60": "uw3t6", + "col61": "a123t", + "col62": "zl00w", + "col63": "550ew", + "col64": "wm5zq", + "col65": "wccsj", + "col66": "jac6k", + "col67": "6pg33", + "col68": "c0squ", + "col69": "ayf8k", + "col70": "5cacg", + "col71": "5py4w", + "col72": "0koio", + "col73": "pur5j", + "col74": "hl2at", + "col75": "ipyt0", + "col76": "e8i3e", + "col77": "onm9g", + "col78": "fmbej", + "col79": "0nszn", + "col80": "oogdv", + "col81": "bgdgw", + "col82": "mleec", + "col83": "4j3v2", + "col84": "7tc6u", + "col85": "ayj95", + "col86": "se9id", + "col87": "qmssf", + "col88": "08ehq", + "col89": "5cu39", + "col90": "e7vir", + "col91": "q8emg", + "col92": "farsp", + "col93": "4llvl", + "col94": "i1xey", + "col95": "7yctf", + "col96": "dbama", + "col97": "3vlht", + "col98": "hfk3y", + "col99": "rm46v", + "col100": "decjh", + "col101": "s3n59", + "col102": "nobd1", + "col103": "lvbu8", + "col104": "g9lfw", + "col105": "tnuxg", + "col106": "3i2wm", + "col107": "190nx", + "col108": "p735g", + "col109": "y858f", + "col110": "2s8oy", + "col111": "9vzsp", + "col112": "gm50w", + "col113": "pq4ap", + "col114": "5pv0p", + "col115": "x35s3", + "col116": "jvehj", + "col117": "sh1wc", + "col118": "6xt05", + "col119": "f0t5l", + "col120": "3oxtl", + "col121": "8b9w3", + "col122": "kaoue", + "col123": "h80u8", + "col124": "yr20v", + "col125": "kk8ku", + "col126": "kb877", + "col127": "olk8m", + "col128": "rfo0w", + "col129": "j4b5k", + "col130": "jrz6f", + "col131": "60xwt", + "col132": "0ilu4", + "col133": "a3koi", + "col134": "8el1d", + "col135": "80ic7", + "col136": "x4h30", + "col137": "bjmb7", + "col138": "535rg", + "col139": "kvrw8", + "col140": "ogtup", + "col141": "4le5s", + "col142": "i73tz", + "col143": "86ghi", + "col144": "x6tzy", + "col145": "d1xy4", + "col146": "xj8gy", + "col147": "fjxs8", + "col148": "kz7xe", + "col149": "2ero6", + "col150": "lgezo", + "col151": "6ymrj", + "col152": "slwpd", + "col153": "8og8b", + "col154": "bb0u8", + "col155": "0fo99", + "col156": "wz98u", + "col157": "8fkxm", + "col158": "9rles", + "col159": "gt6ir", + "col160": "447m2", + "col161": "fdfpw", + "col162": "t1ouh", + "col163": "1gzzx", + "col164": "kehps", + "col165": "w19j2", + "col166": "puly2", + "col167": "300v5", + "col168": "ibdum", + "col169": "kvyje", + "col170": "5h3nl", + "col171": "umcke", + "col172": "u8uze", + "col173": "rf8x4", + "col174": "3bhhr", + "col175": "oipog", + "col176": "8vlzm", + "col177": "udt2x", + "col178": "sca4h", + "col179": "0a8rw", + "col180": "qsd21", + "col181": "xg5m1", + "col182": "6iyh0", + "col183": "4mx63", + "col184": "95f1b", + "col185": "t10k1", + "col186": "kyrmw", + "col187": "rate6", + "col188": "1v0se", + "col189": "3lh24", + "col190": "717p5", + "col191": "j3zzm", + "col192": "zzsy4", + "col193": "1vlps", + "col194": "bmee7", + "col195": "mqoq7", + "col196": "uo4gm", + "col197": "audt1", + "col198": "yxmmo", + "col199": "2f54b", + "col200": "nii3z", + "col201": "s6lvz", + "col202": "f4lty", + "col203": "gasvl", + "col204": "4mkgq", + "col205": "66h9w", + "col206": "ttgrz", + "col207": "jxion", + "col208": "vmnwq", + "col209": "1azof", + "col210": "jmwk1", + "col211": "7hrl4", + "col212": "w30uy", + "col213": "0joky", + "col214": "k9l6p", + "col215": "sy52m", + "col216": "8lqom", + "col217": "ycrpe", + "col218": "ehyia", + "col219": "qgvfj", + "col220": "jyupn", + "col221": "45rw4", + "col222": "jqlwd", + "col223": "y9y8e", + "col224": "c6iv4", + "col225": "yiaes", + "col226": "0h2s8", + "col227": "h2cxl", + "col228": "7h0fr", + "col229": "7fdr4", + "col230": "24w22", + "col231": "fe6nl", + "col232": "3vxhg", + "col233": "do74j", + "col234": "sscla", + "col235": "hqbad", + "col236": "kjcbf", + "col237": "49m3b", + "col238": "s8003", + "col239": "pvxdn", + "col240": "vh8x9", + "col241": "yom0m", + "col242": "symgx", + "col243": "t4qqy", + "col244": "kmil0", + "col245": "g22ah", + "col246": "axi0s", + "col247": "f8twy", + "col248": "222zh", + "col249": "8rtob", + "col250": "tzgd2", + "col251": "2xl22", + "col252": "ldthj", + "col253": "o687f", + "col254": "8mgfq", + "col255": "ydlpk", + "col256": "vot24", + "col257": "yhrcp", + "col258": "9hcn2", + "col259": "b2ug4", + "col260": "v3uzb", + "col261": "d3hub", + "col262": "kiixd", + "col263": "ievox", + "col264": "4y2zr", + "col265": "u3lvn", + "col266": "av9ma", + "col267": "3ey4w", + "col268": "hih6k", + "col269": "3khm5", + "col270": "of5sl", + "col271": "klow0", + "col272": "wosqg", + "col273": "g7lnj", + "col274": "gu5xd", + "col275": "8tdr2", + "col276": "chv3t", + "col277": "o0826", + "col278": "x4r92", + "col279": "xh262", + "col280": "uhy5b", + "col281": "o4i7o", + "col282": "wvdl1", + "col283": "f40vp", + "col284": "6zk91", + "col285": "zmo4d", + "col286": "efmwu", + "col287": "9fq0i", + "col288": "qblec", + "col289": "4552m", + "col290": "wp8j3", + "col291": "qhjzw", + "col292": "bcc14", + "col293": "9ul0k", + "col294": "qbst3", + "col295": "512e7", + "col296": "u3u17", + "col297": "db2ka", + "col298": "ijly2", + "col299": "7i2qo", + "col300": "mf4ab", + "col301": "x0oa5", + "col302": "oswhx", + "col303": "ih8e5", + "col304": "a44h9", + "col305": "owgac", + "col306": "0focs", + "col307": "vr139", + "col308": "zr7xu", + "col309": "f3ff8", + "col310": "h8vlq", + "col311": "ehii8", + "col312": "ua8er", + "col313": "n4i2t", + "col314": "68fkl", + "col315": "zrexe", + "col316": "vc6c4", + "col317": "qb1v8", + "col318": "kkkkh", + "col319": "3ktsb", + "col320": "py8ow", + "col321": "g16x4", + "col322": "59npr", + "col323": "ciumc", + "col324": "2gr8d", + "col325": "tx5nu", + "col326": "ot1aw", + "col327": "auw8x", + "col328": "3roge", + "col329": "vvk3z", + "col330": "qagin", + "col331": "47p1c", + "col332": "uoky5", + "col333": "x3dlp", + "col334": "1n5l5", + "col335": "st4de", + "col336": "ev5rt", + "col337": "qjsvn", + "col338": "w5is2", + "col339": "t1dyf", + "col340": "23fo0", + "col341": "olf2j", + "col342": "d6pso", + "col343": "maey2", + "col344": "t63pk", + "col345": "ourwx", + "col346": "oy06e", + "col347": "lg1bn", + "col348": "mlrlr", + "col349": "i15m3", + "col350": "pwhza", + "col351": "t7wca", + "col352": "kur2p", + "col353": "i97z9", + "col354": "tbrs5", + "col355": "jiogo", + "col356": "m885e", + "col357": "wr6sl", + "col358": "n596n", + "col359": "39d0h", + "col360": "av4mm", + "col361": "snak2", + "col362": "zxhof", + "col363": "kn284", + "col364": "gw6kp", + "col365": "8bs8p", + "col366": "rxslg", + "col367": "ljsyu", + "col368": "00b5y", + "col369": "51nw5", + "col370": "nclz1", + "col371": "poz6y", + "col372": "rdims", + "col373": "l8ttp", + "col374": "bgkyo", + "col375": "lji1k", + "col376": "tv9sx", + "col377": "p3eh4", + "col378": "m3urv", + "col379": "pehe1", + "col380": "rjeri", + "col381": "l0ard", + "col382": "7s9xm", + "col383": "b0e16", + "col384": "sed0v", + "col385": "hdtie", + "col386": "xkl0r", + "col387": "7ski6", + "col388": "yhqcl", + "col389": "0b44p", + "col390": "r94qc", + "col391": "jg539", + "col392": "cr6b1", + "col393": "k9ttl", + "col394": "dtlsn", + "col395": "j7ac0", + "col396": "w7qpz", + "col397": "98tsq", + "col398": "z6zn0", + "col399": "l8kuc", + "col400": "l9jan", + "col401": "imtn9", + "col402": "db8pr", + "col403": "hrcr8", + "col404": "87tg2", + "col405": "urehd", + "col406": "h1o26", + "col407": "158o4", + "col408": "zpg0x", + "col409": "o465u", + "col410": "05ksg", + "col411": "rpc7i", + "col412": "jp6cw", + "col413": "9no3v", + "col414": "nefxh", + "col415": "6wzfw", + "col416": "t1mge", + "col417": "hjoh7", + "col418": "3heqb", + "col419": "qmq2p", + "col420": "a2xf0", + "col421": "0wykk", + "col422": "e0uft", + "col423": "vigt6", + "col424": "87w5k", + "col425": "xq7kc", + "col426": "4eker", + "col427": "699pz", + "col428": "wo5za", + "col429": "uxgjg", + "col430": "gycdy", + "col431": "1ugwh", + "col432": "6seda", + "col433": "pwfoj", + "col434": "djeo2", + "col435": "aa722", + "col436": "0oum0", + "col437": "nl0b3", + "col438": "4ucrb", + "col439": "qhzrx", + "col440": "uzkeq", + "col441": "hns6a", + "col442": "27uab", + "col443": "ubwos", + "col444": "yv8es", + "col445": "9rmsj", + "col446": "5qvhm", + "col447": "pnicx", + "col448": "zoh5h", + "col449": "zkrri", + "col450": "i9ul5", + "col451": "0iuqj", + "col452": "8ediz", + "col453": "0f2oa", + "col454": "ljprm", + "col455": "fsg7x", + "col456": "nv6ln", + "col457": "c0g60", + "col458": "z4zl7", + "col459": "663uy", + "col460": "45npl", + "col461": "1pbbe", + "col462": "yug5k", + "col463": "r9coo", + "col464": "qh0gu", + "col465": "0uepr", + "col466": "r9g7k", + "col467": "57txv", + "col468": "c9kwy", + "col469": "5rqqy", + "col470": "ngjm2", + "col471": "kszzo", + "col472": "frrpl", + "col473": "3vc6v", + "col474": "qlw8u", + "col475": "epwj6", + "col476": "oxqgf", + "col477": "w4o1y", + "col478": "plcg7", + "col479": "1bsmk", + "col480": "7j8qs", + "col481": "5d9wj", + "col482": "sm256", + "col483": "mf8in", + "col484": "9kde4", + "col485": "8w2ja", + "col486": "52uyu", + "col487": "q4h6v", + "col488": "huaxh", + "col489": "iuq58", + "col490": "7yvtu", + "col491": "ch713", + "col492": "0lpgh", + "col493": "4ogy3", + "col494": "9cbd4", + "col495": "z5ua1", + "col496": "wnbgm", + "col497": "5vnfs", + "col498": "0lj9c", + "col499": "em1cd", + "col500": "gvzt6", + "col501": "qtdwr", + "col502": "hj06s", + "col503": "919jy", + "col504": "56nxy", + "col505": "eewpr", + "col506": "pjycw", + "col507": "st3d9", + "col508": "6h401", + "col509": "idz2x", + "col510": "cbfek", + "col511": "oiexs", + "col512": "apjjf", + "col513": "9fz92", + "col514": "vujnc", + "col515": "tzp61", + "col516": "jb5ze", + "col517": "j32c9", + "col518": "25n0u", + "col519": "gmepy", + "col520": "rmjzq", + "col521": "7yon6", + "col522": "cicrc", + "col523": "z993m", + "col524": "bxm1c", + "col525": "7soxe", + "col526": "y927a", + "col527": "e9088", + "col528": "kebfl", + "col529": "ytpaq", + "col530": "v49h1", + "col531": "hvxja", + "col532": "pdd9g", + "col533": "jb6cv", + "col534": "4dq0z", + "col535": "k6n57", + "col536": "kfyk3", + "col537": "0l5rg", + "col538": "qe3l7", + "col539": "8xgec", + "col540": "uwzgi", + "col541": "lfhvo", + "col542": "08fqa", + "col543": "3wnh1", + "col544": "0rghs", + "col545": "mawxm", + "col546": "w6btc", + "col547": "9wot4", + "col548": "b3y7w", + "col549": "ur163", + "col550": "249n3", + "col551": "w7yjx", + "col552": "efb87", + "col553": "sr249", + "col554": "dht0h", + "col555": "fzmg9", + "col556": "idw8r", + "col557": "0s5av", + "col558": "p6qx4", + "col559": "icxs3", + "col560": "h55fl", + "col561": "nrnly", + "col562": "pos99", + "col563": "hjpst", + "col564": "k4482", + "col565": "7ovgj", + "col566": "hauw8", + "col567": "kqe8b", + "col568": "7o1g5", + "col569": "fchn7", + "col570": "w5i8l", + "col571": "2gl9u", + "col572": "14oln", + "col573": "v20zg", + "col574": "pd9m4", + "col575": "opwsg", + "col576": "a5cpc", + "col577": "v38de", + "col578": "po5ir", + "col579": "bh9n2", + "col580": "ribkw", + "col581": "nhjxk", + "col582": "duc5e", + "col583": "y03jo", + "col584": "iajo4", + "col585": "wf66c", + "col586": "d6skd", + "col587": "nlqpm", + "col588": "oqmxx", + "col589": "q2gqo", + "col590": "ci1yp", + "col591": "spzsy", + "col592": "5wmbw", + "col593": "vqtox", + "col594": "bewkp", + "col595": "6soen", + "col596": "50qzo", + "col597": "akg25", + "col598": "bb89e", + "col599": "fxajj", + "col600": "8sbnx", + "col601": "a7h9p", + "col602": "33zm6", + "col603": "s2hw5", + "col604": "ontla", + "col605": "qwt9e", + "col606": "fnw6e", + "col607": "n7jxv", + "col608": "xg4wz", + "col609": "8wn0u", + "col610": "7avs6", + "col611": "20uox", + "col612": "3r3d9", + "col613": "8r78v", + "col614": "i71ce", + "col615": "cps1n", + "col616": "yrzh6", + "col617": "opvyf", + "col618": "inrfn", + "col619": "i1n4t", + "col620": "l8go9", + "col621": "kq8gy", + "col622": "nwxt3", + "col623": "9917o", + "col624": "6tm3v", + "col625": "i83vo", + "col626": "5tbmq", + "col627": "04u9d", + "col628": "g83o0", + "col629": "aupse", + "col630": "900gl", + "col631": "1zncq", + "col632": "7b1us", + "col633": "5vx8p", + "col634": "03ihj", + "col635": "6s1ye", + "col636": "r8vt9", + "col637": "75ojg", + "col638": "2rf5q", + "col639": "f9piz", + "col640": "ohtgm", + "col641": "tdsfa", + "col642": "inxxe", + "col643": "97q25", + "col644": "wrbw0", + "col645": "9ds1x", + "col646": "3tf1d", + "col647": "28dcr", + "col648": "ei94s", + "col649": "gjpvu", + "col650": "nwr0b", + "col651": "aoupc", + "col652": "hyiwl", + "col653": "njwkv", + "col654": "cn4e3", + "col655": "pqgft", + "col656": "09osg", + "col657": "ekmgs", + "col658": "41q4t", + "col659": "7hter", + "col660": "3f0sj", + "col661": "kq34t", + "col662": "84wq7", + "col663": "m0i3n", + "col664": "suu4p", + "col665": "yu9i5", + "col666": "3y19y", + "col667": "83rnu", + "col668": "64q97", + "col669": "83i1c", + "col670": "k93cv", + "col671": "w41hy", + "col672": "9iiwb", + "col673": "qmxu7", + "col674": "gop84", + "col675": "qqrjv", + "col676": "3k2wd", + "col677": "1805e", + "col678": "zq74c", + "col679": "zj54j", + "col680": "ppgsf", + "col681": "oozd9", + "col682": "txc05", + "col683": "2frfa", + "col684": "jbor1", + "col685": "cuogy", + "col686": "6xxgd", + "col687": "3wt5a", + "col688": "v0dwr", + "col689": "qwlu7", + "col690": "u2orl", + "col691": "kr1cg", + "col692": "ebjzr", + "col693": "fho66", + "col694": "oyvc2", + "col695": "shr5a", + "col696": "26q0m", + "col697": "nsfvc", + "col698": "wwrpc", + "col699": "p98ng", + "col700": "r1n64", + "col701": "80mfg", + "col702": "84498", + "col703": "svz5q", + "col704": "g7des", + "col705": "sf738", + "col706": "vv6ux", + "col707": "tz894", + "col708": "wx4g5", + "col709": "rnqbm", + "col710": "fbacr", + "col711": "8yhq0", + "col712": "mc09c", + "col713": "xzgl2", + "col714": "ngcxv", + "col715": "2szdo", + "col716": "5qcpt", + "col717": "pmzcf", + "col718": "j62dx", + "col719": "53knq", + "col720": "hsqa4", + "col721": "okbz8", + "col722": "8vdol", + "col723": "pgz7q", + "col724": "04fhc", + "col725": "0ycc8", + "col726": "judt4", + "col727": "t5pj9", + "col728": "5xeuv", + "col729": "xzvjy", + "col730": "q7txq", + "col731": "1sphp", + "col732": "qxdk0", + "col733": "jwopr", + "col734": "7qz4y", + "col735": "b9uj5", + "col736": "1irpv", + "col737": "svgh2", + "col738": "subf2", + "col739": "0652p", + "col740": "14pys", + "col741": "ykhbu", + "col742": "84e1l", + "col743": "pagkz", + "col744": "ejixv", + "col745": "1gnb1", + "col746": "zr857", + "col747": "wm29f", + "col748": "gni1t", + "col749": "h7igt", + "col750": "m8u57", + "col751": "tbcd5", + "col752": "uux7y", + "col753": "jo4zo", + "col754": "disd0", + "col755": "ldlg2", + "col756": "gbddr", + "col757": "mvlwc", + "col758": "bctuc", + "col759": "2rjqs", + "col760": "epag4", + "col761": "a6gqk", + "col762": "pb8o6", + "col763": "321ib", + "col764": "81kha", + "col765": "mrdy7", + "col766": "52c10", + "col767": "q162t", + "col768": "dh1a1", + "col769": "bd6v2", + "col770": "sfbqf", + "col771": "xssk9", + "col772": "5iomu", + "col773": "mnep8", + "col774": "sr4po", + "col775": "yztu6", + "col776": "bh9t6", + "col777": "goydn", + "col778": "90bku", + "col779": "m4i1f", + "col780": "os6sn", + "col781": "z10j5", + "col782": "s8gnk", + "col783": "sdwnh", + "col784": "cc7j6", + "col785": "hqyl4", + "col786": "5mlj3", + "col787": "zo33i", + "col788": "j9yaj", + "col789": "mvouh", + "col790": "iu9vc", + "col791": "hyjgm", + "col792": "mg4cu", + "col793": "hw6bq", + "col794": "kcmtc", + "col795": "ljojt", + "col796": "oq2d5", + "col797": "jw65i", + "col798": "0nzrn", + "col799": "o4sy4", + "col800": "sluzx", + "col801": "qvqb5", + "col802": "jqz94", + "col803": "7sr5f", + "col804": "fhkx0", + "col805": "hcwl9", + "col806": "xq8z4", + "col807": "l526p", + "col808": "o45p2", + "col809": "m203h", + "col810": "wn9f4", + "col811": "840et", + "col812": "34sjc", + "col813": "4iqbf", + "col814": "47x89", + "col815": "w1n4y", + "col816": "oixrv", + "col817": "rp567", + "col818": "5na9b", + "col819": "oqq7f", + "col820": "p7o6h", + "col821": "st7wz", + "col822": "pl6g8", + "col823": "zmlr4", + "col824": "9kza6", + "col825": "tuqq3", + "col826": "nopvc", + "col827": "c4o61", + "col828": "0k9ag", + "col829": "ucas1", + "col830": "o6fqi", + "col831": "qy85q", + "col832": "4tpwh", + "col833": "hopp4", + "col834": "vbaci", + "col835": "j4ylm", + "col836": "zmonj", + "col837": "fb8yy", + "col838": "65tfy", + "col839": "zlcha", + "col840": "maywf", + "col841": "8e8qs", + "col842": "aqld9", + "col843": "zgelm", + "col844": "qmyfg", + "col845": "qfenp", + "col846": "n5exv", + "col847": "hbpa0", + "col848": "h4vuw", + "col849": "tgn8i", + "col850": "h0nls", + "col851": "3rne6", + "col852": "ijb7e", + "col853": "5szx4", + "col854": "r59oi", + "col855": "skw43", + "col856": "otipd", + "col857": "1wdjb", + "col858": "8zrrv", + "col859": "s25rj", + "col860": "821va", + "col861": "l57tt", + "col862": "4bbf9", + "col863": "u5293", + "col864": "5vknq", + "col865": "6nlt2", + "col866": "as2r2", + "col867": "0t9tn", + "col868": "lq0mp", + "col869": "yusx0", + "col870": "0121x", + "col871": "k5e4z", + "col872": "hajhn", + "col873": "g01xh", + "col874": "bq5nm", + "col875": "0qmzx", + "col876": "3x65m", + "col877": "rg787", + "col878": "caniz", + "col879": "3yrpt", + "col880": "36a01", + "col881": "l4sri", + "col882": "e1srd", + "col883": "mhg95", + "col884": "cure0", + "col885": "uepux", + "col886": "i5v4q", + "col887": "51hpf", + "col888": "hlofz", + "col889": "v2cvu", + "col890": "fkz0k", + "col891": "wd157", + "col892": "ls3r2", + "col893": "wnv2j", + "col894": "q6mdk", + "col895": "r3a1h", + "col896": "fwt62", + "col897": "qshb8", + "col898": "q162o", + "col899": "tkhpa", + "col900": "hsbbl", + "col901": "txpps", + "col902": "r5g2q", + "col903": "a4awy", + "col904": "h6rlv", + "col905": "gk3d3", + "col906": "bx5jc", + "col907": "q85kl", + "col908": "783gv", + "col909": "32ls0", + "col910": "w20jr", + "col911": "ovu18", + "col912": "a7u2b", + "col913": "daocw", + "col914": "7awnd", + "col915": "ary9o", + "col916": "crn04", + "col917": "eacv4", + "col918": "fh754", + "col919": "021iu", + "col920": "sjylv", + "col921": "dhwhh", + "col922": "p3qgk", + "col923": "n8jbm", + "col924": "2zc7v", + "col925": "2tc8c", + "col926": "ut9ry", + "col927": "h6yzs", + "col928": "h7sgb", + "col929": "gewu6", + "col930": "00tia", + "col931": "hm00t", + "col932": "uceou", + "col933": "c513r", + "col934": "8463t", + "col935": "ln43a", + "col936": "6diu2", + "col937": "5gjp4", + "col938": "7k51m", + "col939": "14fgy", + "col940": "2gk7m", + "col941": "8ehxh", + "col942": "a4nge", + "col943": "p6ocd", + "col944": "gtced", + "col945": "qr6j3", + "col946": "lu492", + "col947": "5x5pc", + "col948": "ehewt", + "col949": "71tnh", + "col950": "qvo7d", + "col951": "elvdj", + "col952": "brjc6", + "col953": "qijke", + "col954": "shc2m", + "col955": "cugeg", + "col956": "uj9g9", + "col957": "a9vhd", + "col958": "otplm", + "col959": "98ua3", + "col960": "oqkl8", + "col961": "adz24", + "col962": "qf4ys", + "col963": "jkzpk", + "col964": "nqz34", + "col965": "mi2nk", + "col966": "v74c0", + "col967": "8yu9d", + "col968": "rfsxi", + "col969": "s2xhx", + "col970": "b6fjw", + "col971": "m4kyt", + "col972": "yk28e", + "col973": "95bx2", + "col974": "5m7ak", + "col975": "uy8xj", + "col976": "2dbj2", + "col977": "j0kaz", + "col978": "no39o", + "col979": "jfj3j", + "col980": "r3iz4", + "col981": "5jbhj", + "col982": "zjup6", + "col983": "hrzeg", + "col984": "rjs14", + "col985": "1zs33", + "col986": "i9rgp", + "col987": "khzac", + "col988": "fw7vf", + "col989": "6t0au", + "col990": "kd4oy", + "col991": "9v8qc", + "col992": "53r5p", + "col993": "7ky23", + "col994": "aoge2", + "col995": "2out3", + "col996": "4ufn8", + "col997": "8wg3s", + "col998": "9glp5", + "col999": "5yr3c" + }, + { + "name": "Amie Ayala", + "gender": "female", + "col0": "9hyiw", + "col1": "qaiw2", + "col2": "fjg6p", + "col3": "qodcj", + "col4": "v45q9", + "col5": "dz2pq", + "col6": "d3ahy", + "col7": "3aa0z", + "col8": "u9j6q", + "col9": "son7y", + "col10": "jtq2t", + "col11": "4jwon", + "col12": "wmhkk", + "col13": "mtj4j", + "col14": "3ftyb", + "col15": "9k4wt", + "col16": "nrnbn", + "col17": "8imlk", + "col18": "de5pq", + "col19": "tj6bd", + "col20": "n89df", + "col21": "l3sbq", + "col22": "97mkb", + "col23": "tagq0", + "col24": "ngcqm", + "col25": "gjuxt", + "col26": "w72bk", + "col27": "dt6nx", + "col28": "a647h", + "col29": "l0ale", + "col30": "agxf5", + "col31": "0lgp7", + "col32": "mnayi", + "col33": "s90cu", + "col34": "vej8w", + "col35": "27zl5", + "col36": "yxprq", + "col37": "k39nu", + "col38": "kg63f", + "col39": "6cp7e", + "col40": "75f02", + "col41": "iue9x", + "col42": "mqrx9", + "col43": "ddqck", + "col44": "8lg8n", + "col45": "5vrnq", + "col46": "n4y67", + "col47": "z8n4c", + "col48": "6s87n", + "col49": "jdtlr", + "col50": "kn47c", + "col51": "gfh8g", + "col52": "42li7", + "col53": "xlfuj", + "col54": "3p6ek", + "col55": "nfl48", + "col56": "bftr1", + "col57": "lnw97", + "col58": "5a2ol", + "col59": "be7nq", + "col60": "o0ud3", + "col61": "wjdkh", + "col62": "5csdo", + "col63": "o3e07", + "col64": "8rqb1", + "col65": "zcshx", + "col66": "ho1s5", + "col67": "mjpz9", + "col68": "ejwj4", + "col69": "1djey", + "col70": "nrrba", + "col71": "ry7sf", + "col72": "9qo70", + "col73": "dgpik", + "col74": "b5z6r", + "col75": "j4109", + "col76": "ipnm2", + "col77": "83ikx", + "col78": "l922h", + "col79": "l1nzf", + "col80": "8qs1g", + "col81": "i6snc", + "col82": "5a4kh", + "col83": "mz0a5", + "col84": "99jx1", + "col85": "5i2mw", + "col86": "nme7u", + "col87": "lfyg9", + "col88": "311pl", + "col89": "p08lo", + "col90": "7nig8", + "col91": "a2g10", + "col92": "qsnkl", + "col93": "9916u", + "col94": "cn6v4", + "col95": "dcorm", + "col96": "b9u24", + "col97": "lim5b", + "col98": "wph4b", + "col99": "653ye", + "col100": "83vdp", + "col101": "aw8ki", + "col102": "nmxe0", + "col103": "gvbp5", + "col104": "20i67", + "col105": "vpegc", + "col106": "iiugq", + "col107": "m6lrw", + "col108": "et0js", + "col109": "y1tbw", + "col110": "ucfy7", + "col111": "yae91", + "col112": "928du", + "col113": "g4ys0", + "col114": "jse7z", + "col115": "hjti6", + "col116": "wnn5x", + "col117": "wmn9s", + "col118": "bcrbq", + "col119": "6cotl", + "col120": "23sn2", + "col121": "nytbh", + "col122": "bljik", + "col123": "gqeak", + "col124": "yc4di", + "col125": "r37mu", + "col126": "lka0e", + "col127": "r6pby", + "col128": "pna9d", + "col129": "5r3xb", + "col130": "4w1ny", + "col131": "7coce", + "col132": "1sa29", + "col133": "gu729", + "col134": "s8v2m", + "col135": "aksui", + "col136": "0wfs7", + "col137": "l3uz2", + "col138": "c5m0d", + "col139": "13ofu", + "col140": "exmzb", + "col141": "3hs21", + "col142": "y3wvz", + "col143": "b6mvp", + "col144": "65bp4", + "col145": "wzopz", + "col146": "regpx", + "col147": "dmu9s", + "col148": "lq5fz", + "col149": "t5yud", + "col150": "sxyvb", + "col151": "squpg", + "col152": "6qamx", + "col153": "5vqak", + "col154": "51tef", + "col155": "jvi3p", + "col156": "3v1ne", + "col157": "aa7wu", + "col158": "nycsa", + "col159": "tzsgr", + "col160": "5c2ad", + "col161": "ei1e7", + "col162": "wkawh", + "col163": "1g8qg", + "col164": "4yxof", + "col165": "t533l", + "col166": "c3s0z", + "col167": "kwca3", + "col168": "9fvcl", + "col169": "7yeb0", + "col170": "0vhqt", + "col171": "bl2u6", + "col172": "czug2", + "col173": "2i0yk", + "col174": "qyxet", + "col175": "04ws2", + "col176": "l98n2", + "col177": "iqdzp", + "col178": "7jhxh", + "col179": "mo8kp", + "col180": "xygxg", + "col181": "knci2", + "col182": "fdnt1", + "col183": "v1tl9", + "col184": "gw0l2", + "col185": "cyrh3", + "col186": "9h23s", + "col187": "3j4mx", + "col188": "ilk9w", + "col189": "qi5aq", + "col190": "enj6f", + "col191": "obcgz", + "col192": "fd9c5", + "col193": "gc5sy", + "col194": "dailb", + "col195": "nakun", + "col196": "5hqwg", + "col197": "8f7ms", + "col198": "hcj59", + "col199": "f5mx7", + "col200": "ze0g6", + "col201": "c7wav", + "col202": "9xcfb", + "col203": "7rmoc", + "col204": "kr21h", + "col205": "osr6c", + "col206": "lta7m", + "col207": "38xre", + "col208": "0n8fa", + "col209": "83kge", + "col210": "absb2", + "col211": "q3zc9", + "col212": "7tdzc", + "col213": "yji75", + "col214": "jmq2r", + "col215": "1st1m", + "col216": "qqaw7", + "col217": "7zps9", + "col218": "obwq7", + "col219": "87hqe", + "col220": "tem21", + "col221": "m520y", + "col222": "0xtwk", + "col223": "6ysfs", + "col224": "pavsv", + "col225": "e13u0", + "col226": "1clzx", + "col227": "eu5ba", + "col228": "3g0p2", + "col229": "n5uxx", + "col230": "cd9v2", + "col231": "0re82", + "col232": "7yqn0", + "col233": "j7gxm", + "col234": "7wfpl", + "col235": "1xza9", + "col236": "jfuy6", + "col237": "j7igh", + "col238": "0717u", + "col239": "fmp0r", + "col240": "elgfx", + "col241": "nvj6n", + "col242": "n9io0", + "col243": "gg2ea", + "col244": "cwv3j", + "col245": "rrtj9", + "col246": "s03hc", + "col247": "8cw4x", + "col248": "68jrt", + "col249": "yxcfj", + "col250": "23inx", + "col251": "oi1o3", + "col252": "epjvr", + "col253": "2q6s5", + "col254": "ekhn1", + "col255": "wfj9l", + "col256": "ue5rt", + "col257": "c4sgs", + "col258": "t624e", + "col259": "pee40", + "col260": "pcvja", + "col261": "expd8", + "col262": "og03e", + "col263": "xfgpy", + "col264": "9ja2x", + "col265": "ozd1g", + "col266": "prtrm", + "col267": "4s4c7", + "col268": "yth0n", + "col269": "k74qx", + "col270": "5absu", + "col271": "2hsvz", + "col272": "9v0il", + "col273": "b4e3j", + "col274": "tofva", + "col275": "2neg6", + "col276": "sdhv7", + "col277": "myncr", + "col278": "zywpr", + "col279": "qsabr", + "col280": "gnwn7", + "col281": "st3rj", + "col282": "1hjah", + "col283": "nff8m", + "col284": "ngq3h", + "col285": "82g7f", + "col286": "fiutc", + "col287": "oe1u2", + "col288": "9ctkt", + "col289": "8madf", + "col290": "ly368", + "col291": "fulcl", + "col292": "emmuy", + "col293": "y9r6u", + "col294": "4yqq5", + "col295": "as7gs", + "col296": "w3htg", + "col297": "iu7ki", + "col298": "bd0wd", + "col299": "ri915", + "col300": "tcd4l", + "col301": "k658b", + "col302": "sgn5s", + "col303": "os1g1", + "col304": "2j5kz", + "col305": "nw6yv", + "col306": "16h15", + "col307": "w0y1n", + "col308": "ca9yc", + "col309": "pi859", + "col310": "sz37p", + "col311": "7y69s", + "col312": "1ea67", + "col313": "ty0lh", + "col314": "i8pra", + "col315": "sroql", + "col316": "lst7g", + "col317": "mz7v3", + "col318": "vcbo7", + "col319": "l06f3", + "col320": "4p1l2", + "col321": "n52w8", + "col322": "c88fo", + "col323": "m8u5i", + "col324": "7unir", + "col325": "4f6z4", + "col326": "m7mbg", + "col327": "stwxe", + "col328": "sm6y7", + "col329": "opvzn", + "col330": "lyl23", + "col331": "tbf1v", + "col332": "yxgy8", + "col333": "wrdho", + "col334": "yzjna", + "col335": "2nkft", + "col336": "x50f3", + "col337": "6he43", + "col338": "yk0vb", + "col339": "29wp5", + "col340": "e0k0y", + "col341": "ucgc7", + "col342": "v7n5m", + "col343": "hmiqp", + "col344": "hwojy", + "col345": "myrkw", + "col346": "5cpff", + "col347": "jsa1q", + "col348": "b9gjh", + "col349": "fz15d", + "col350": "zm4ud", + "col351": "xxadw", + "col352": "xzwhy", + "col353": "nzirm", + "col354": "4a2e2", + "col355": "81s31", + "col356": "hzjtz", + "col357": "rcxjd", + "col358": "cmjkr", + "col359": "3mn1b", + "col360": "v9xa7", + "col361": "rkbfj", + "col362": "eqiqu", + "col363": "9uzni", + "col364": "tlcu7", + "col365": "felc5", + "col366": "ormuz", + "col367": "j5npt", + "col368": "rmoxe", + "col369": "r09ru", + "col370": "ron7o", + "col371": "7ec2s", + "col372": "d9lk3", + "col373": "ug0rg", + "col374": "bti68", + "col375": "o6snw", + "col376": "hg0tb", + "col377": "m6k6l", + "col378": "wxrgh", + "col379": "p780k", + "col380": "dpx1b", + "col381": "n28rr", + "col382": "4ax5y", + "col383": "7et92", + "col384": "i8i7l", + "col385": "z4nhd", + "col386": "h9hs5", + "col387": "c99tb", + "col388": "xjmtp", + "col389": "032bo", + "col390": "5ig6m", + "col391": "fupek", + "col392": "dbvmd", + "col393": "965lp", + "col394": "lwgk0", + "col395": "kx0co", + "col396": "jex5j", + "col397": "n8kjw", + "col398": "3wm13", + "col399": "klb8b", + "col400": "67r04", + "col401": "pax5g", + "col402": "iu89k", + "col403": "12j9o", + "col404": "o124u", + "col405": "bzzwp", + "col406": "2r1fl", + "col407": "tctev", + "col408": "m8wm9", + "col409": "tbq41", + "col410": "t109b", + "col411": "5nbek", + "col412": "z5f1p", + "col413": "lrp2v", + "col414": "7o1lr", + "col415": "uox4t", + "col416": "h60hs", + "col417": "8e42u", + "col418": "djv9f", + "col419": "4cbw1", + "col420": "xfmyq", + "col421": "4pdgs", + "col422": "c884j", + "col423": "4k2ki", + "col424": "nr23k", + "col425": "tzq90", + "col426": "65ahi", + "col427": "d5337", + "col428": "oke5y", + "col429": "qs3rw", + "col430": "a7aeo", + "col431": "saqs3", + "col432": "vbnzf", + "col433": "06um0", + "col434": "t538l", + "col435": "ptuyp", + "col436": "1pdxq", + "col437": "gkeng", + "col438": "6n279", + "col439": "x9399", + "col440": "mhd57", + "col441": "6j3wc", + "col442": "xbzdz", + "col443": "egku7", + "col444": "00pm8", + "col445": "18j3k", + "col446": "paak6", + "col447": "a7knu", + "col448": "eddcz", + "col449": "2iymt", + "col450": "55vou", + "col451": "x206s", + "col452": "b0uyb", + "col453": "ocl5d", + "col454": "w7xd2", + "col455": "d3db3", + "col456": "p2hpa", + "col457": "59hf3", + "col458": "p6b9g", + "col459": "3vj3u", + "col460": "j3k15", + "col461": "bumg3", + "col462": "w87kv", + "col463": "w3m1c", + "col464": "vh7fu", + "col465": "gc90q", + "col466": "lxomy", + "col467": "zrau7", + "col468": "giazo", + "col469": "3o5no", + "col470": "0pl1m", + "col471": "ep5oa", + "col472": "try7r", + "col473": "lbx03", + "col474": "o4all", + "col475": "0aoft", + "col476": "6ziuu", + "col477": "dxlrx", + "col478": "71198", + "col479": "ipjx2", + "col480": "o14jx", + "col481": "q35cn", + "col482": "jjoam", + "col483": "gp6qx", + "col484": "do4zq", + "col485": "mbkc6", + "col486": "1zy98", + "col487": "rmgmk", + "col488": "upsw6", + "col489": "juasq", + "col490": "5pb86", + "col491": "4wfk8", + "col492": "n2lg3", + "col493": "2isme", + "col494": "6tdin", + "col495": "wdcfc", + "col496": "2g6vz", + "col497": "hb03u", + "col498": "zywsi", + "col499": "hohga", + "col500": "xfn14", + "col501": "5wvuj", + "col502": "1449x", + "col503": "i0sdz", + "col504": "bper2", + "col505": "idqd4", + "col506": "6cbmn", + "col507": "3dx40", + "col508": "8by27", + "col509": "gjrmp", + "col510": "w83pc", + "col511": "3aoj7", + "col512": "hud4b", + "col513": "lnoom", + "col514": "m7s4o", + "col515": "01uxl", + "col516": "jmdsb", + "col517": "y5xbn", + "col518": "5k5z8", + "col519": "ole8b", + "col520": "z3h4a", + "col521": "5bqgu", + "col522": "f8vam", + "col523": "zmlmn", + "col524": "hlsdp", + "col525": "ubuoi", + "col526": "j2zgk", + "col527": "l5k9a", + "col528": "lhcdi", + "col529": "7k828", + "col530": "c8zeb", + "col531": "vsxdc", + "col532": "pnbpb", + "col533": "4j2dp", + "col534": "ymmot", + "col535": "s6w11", + "col536": "ratos", + "col537": "tu5f1", + "col538": "73mlr", + "col539": "tj3lm", + "col540": "1ecd9", + "col541": "k1ebm", + "col542": "3k300", + "col543": "6vquf", + "col544": "350u1", + "col545": "1kmyz", + "col546": "t4lr5", + "col547": "4orcv", + "col548": "xwct5", + "col549": "o434i", + "col550": "6em6p", + "col551": "n8mxf", + "col552": "zep7u", + "col553": "xe5h8", + "col554": "vlky1", + "col555": "lghgn", + "col556": "yb1ux", + "col557": "8t1nx", + "col558": "o7syu", + "col559": "r1azx", + "col560": "tmu13", + "col561": "tkdm6", + "col562": "n1axy", + "col563": "fuwk3", + "col564": "gh8xc", + "col565": "w36l7", + "col566": "ivqhy", + "col567": "n8nia", + "col568": "xvad5", + "col569": "3sqcy", + "col570": "p9oh5", + "col571": "aca0h", + "col572": "3vl8c", + "col573": "glqxw", + "col574": "0scop", + "col575": "712l4", + "col576": "f1m3f", + "col577": "j9g22", + "col578": "fofgg", + "col579": "gn2ep", + "col580": "2n09q", + "col581": "wghyj", + "col582": "cehzk", + "col583": "7stc1", + "col584": "f2vp7", + "col585": "0h11k", + "col586": "a08oc", + "col587": "t4eo1", + "col588": "69le7", + "col589": "a4kd2", + "col590": "wzgl9", + "col591": "v45d6", + "col592": "prsdn", + "col593": "xbkkx", + "col594": "zxt0b", + "col595": "cl0ym", + "col596": "7k1ob", + "col597": "yyhvu", + "col598": "jk0vv", + "col599": "cbl1i", + "col600": "kl8yw", + "col601": "jgvvz", + "col602": "1chus", + "col603": "9oxi0", + "col604": "6t2u1", + "col605": "ubbi8", + "col606": "agze4", + "col607": "apupj", + "col608": "jmgdz", + "col609": "3nd4b", + "col610": "9hkd7", + "col611": "7eg8c", + "col612": "t1g4c", + "col613": "9dr4z", + "col614": "dopo0", + "col615": "0sfbh", + "col616": "vb5l9", + "col617": "3m5z4", + "col618": "mhjv4", + "col619": "424cz", + "col620": "7vdsq", + "col621": "j515i", + "col622": "4rru3", + "col623": "8u4q8", + "col624": "4ljxx", + "col625": "171o6", + "col626": "opvm1", + "col627": "ye1a5", + "col628": "uyv2b", + "col629": "q1741", + "col630": "n7fh4", + "col631": "pj06u", + "col632": "oz8cg", + "col633": "b0w4f", + "col634": "g7l2u", + "col635": "0re55", + "col636": "gkd4c", + "col637": "78u2h", + "col638": "rp260", + "col639": "wofso", + "col640": "fvbfb", + "col641": "6fi4a", + "col642": "h6lk0", + "col643": "x6wme", + "col644": "9oeiu", + "col645": "2k10p", + "col646": "8eb6n", + "col647": "f9qhs", + "col648": "54cka", + "col649": "6al5s", + "col650": "6c3tu", + "col651": "7n0fe", + "col652": "0wg9g", + "col653": "jf4rh", + "col654": "uz8ik", + "col655": "hilmh", + "col656": "mxkuw", + "col657": "4y410", + "col658": "hy1ue", + "col659": "22dsa", + "col660": "q4mvb", + "col661": "rt9cc", + "col662": "0wpn7", + "col663": "ewu77", + "col664": "xxl7h", + "col665": "nvrih", + "col666": "hnm40", + "col667": "keo8v", + "col668": "1bkhz", + "col669": "66nly", + "col670": "l9ufk", + "col671": "f44do", + "col672": "20njv", + "col673": "ef85u", + "col674": "sq41d", + "col675": "os1i1", + "col676": "rp63u", + "col677": "na67w", + "col678": "bc88c", + "col679": "jv21z", + "col680": "qqzwk", + "col681": "1u522", + "col682": "ivqsn", + "col683": "hbac6", + "col684": "nnx3k", + "col685": "6i72r", + "col686": "6fvhm", + "col687": "a8blh", + "col688": "73fkg", + "col689": "y73w0", + "col690": "arebs", + "col691": "9nbtu", + "col692": "u9py7", + "col693": "q7nux", + "col694": "3d356", + "col695": "98efx", + "col696": "1dmf1", + "col697": "lf3ov", + "col698": "9r4en", + "col699": "0jok0", + "col700": "y45as", + "col701": "4dq1o", + "col702": "u75oy", + "col703": "micgf", + "col704": "zer37", + "col705": "ma8md", + "col706": "1yx6w", + "col707": "r7xkj", + "col708": "eleay", + "col709": "c1s6s", + "col710": "nl16w", + "col711": "h6ihq", + "col712": "irn7h", + "col713": "5u031", + "col714": "u42f4", + "col715": "axcbs", + "col716": "8cpv4", + "col717": "93nml", + "col718": "j5960", + "col719": "50nr5", + "col720": "ztn1n", + "col721": "vosld", + "col722": "ouwhd", + "col723": "xy48x", + "col724": "jplz8", + "col725": "w5g3h", + "col726": "ziyw6", + "col727": "5i3pc", + "col728": "wl4e1", + "col729": "9gur6", + "col730": "u1fwj", + "col731": "lh6wl", + "col732": "rp5es", + "col733": "md1hr", + "col734": "083ac", + "col735": "ijk5y", + "col736": "rb1vv", + "col737": "q6nc2", + "col738": "zmvl8", + "col739": "joxfq", + "col740": "pdlyj", + "col741": "m87b8", + "col742": "0wd2a", + "col743": "codga", + "col744": "m83xu", + "col745": "94pp8", + "col746": "rk1ds", + "col747": "65b2t", + "col748": "z1nzb", + "col749": "6tuza", + "col750": "9eb4k", + "col751": "s5gtj", + "col752": "sgk4g", + "col753": "fbnuh", + "col754": "memdb", + "col755": "2ro0a", + "col756": "gwy3r", + "col757": "le8xj", + "col758": "jhi75", + "col759": "m88w2", + "col760": "gtl7p", + "col761": "as3ed", + "col762": "w4d5x", + "col763": "fy5kc", + "col764": "1nqvl", + "col765": "66bkt", + "col766": "mbwzf", + "col767": "d4tk0", + "col768": "k06r1", + "col769": "gkiqr", + "col770": "sfulr", + "col771": "i9myd", + "col772": "dop9y", + "col773": "t89sr", + "col774": "qirza", + "col775": "etlov", + "col776": "ce0c0", + "col777": "1fj9x", + "col778": "syxth", + "col779": "5hb1c", + "col780": "rrfld", + "col781": "56cbs", + "col782": "81uxu", + "col783": "mdzwl", + "col784": "61ln4", + "col785": "njlmp", + "col786": "7rvjd", + "col787": "3ifm2", + "col788": "vtrxm", + "col789": "csk0g", + "col790": "jrywy", + "col791": "1r2w4", + "col792": "wjv69", + "col793": "j125u", + "col794": "hm1v4", + "col795": "n3j0g", + "col796": "us2r6", + "col797": "cii8r", + "col798": "1dfm9", + "col799": "90io2", + "col800": "pabs8", + "col801": "e0o0f", + "col802": "1j9so", + "col803": "skwsz", + "col804": "wqgwd", + "col805": "l1txl", + "col806": "7p5ke", + "col807": "qmy2r", + "col808": "096si", + "col809": "0tpwm", + "col810": "xnl2e", + "col811": "zc0in", + "col812": "vnc7x", + "col813": "mvo9z", + "col814": "78god", + "col815": "dq0f1", + "col816": "m7aym", + "col817": "6fbw4", + "col818": "vl91a", + "col819": "wgw5i", + "col820": "3l56v", + "col821": "wgddw", + "col822": "lxk52", + "col823": "xlbxf", + "col824": "kgdx0", + "col825": "f1hji", + "col826": "ys3ta", + "col827": "jh97e", + "col828": "dib9i", + "col829": "ghvnz", + "col830": "sn06h", + "col831": "idzrn", + "col832": "2km9o", + "col833": "ixosy", + "col834": "xcxwh", + "col835": "vq6e6", + "col836": "wrr8c", + "col837": "lcute", + "col838": "npbnw", + "col839": "wxfsw", + "col840": "jxeqo", + "col841": "dae1k", + "col842": "az20e", + "col843": "fg3v5", + "col844": "804lo", + "col845": "8g3uy", + "col846": "jb4wd", + "col847": "i3gok", + "col848": "nxruf", + "col849": "9074k", + "col850": "4xsnu", + "col851": "a08o8", + "col852": "htkrp", + "col853": "2yt3l", + "col854": "iaeo8", + "col855": "72jec", + "col856": "e8mkl", + "col857": "ukq5i", + "col858": "mjmoj", + "col859": "3ynhd", + "col860": "9eqho", + "col861": "9lfqb", + "col862": "tvpw6", + "col863": "j2b51", + "col864": "ooyg7", + "col865": "d0omt", + "col866": "y8vqr", + "col867": "dahz0", + "col868": "36vph", + "col869": "ng44l", + "col870": "hrm23", + "col871": "kzjai", + "col872": "c3o5c", + "col873": "pdm8r", + "col874": "z625p", + "col875": "thtn3", + "col876": "caz6z", + "col877": "7q2au", + "col878": "lb5os", + "col879": "9yd2p", + "col880": "i82us", + "col881": "011hn", + "col882": "lecpc", + "col883": "qgdse", + "col884": "h28aw", + "col885": "0iz0q", + "col886": "gd3en", + "col887": "2vxbi", + "col888": "2f814", + "col889": "v9yf6", + "col890": "gbi9l", + "col891": "czvb8", + "col892": "gd8fd", + "col893": "74wxn", + "col894": "wqd7v", + "col895": "ydh2i", + "col896": "k2lvm", + "col897": "kktez", + "col898": "moqy2", + "col899": "akiyq", + "col900": "ke0mu", + "col901": "c6efv", + "col902": "vi575", + "col903": "h2e4z", + "col904": "l53ue", + "col905": "l3zem", + "col906": "8j7jm", + "col907": "hdw0l", + "col908": "8qb3a", + "col909": "4t7ra", + "col910": "g69xs", + "col911": "74l5b", + "col912": "10pe6", + "col913": "sa0vv", + "col914": "mdzr4", + "col915": "z4x2e", + "col916": "u07fp", + "col917": "arslv", + "col918": "y91id", + "col919": "pzh4r", + "col920": "1ffa0", + "col921": "v4drd", + "col922": "buw5a", + "col923": "9it9m", + "col924": "hingo", + "col925": "jgklo", + "col926": "ccya3", + "col927": "lmub8", + "col928": "3i2x6", + "col929": "bk5t1", + "col930": "uwgqc", + "col931": "j2klx", + "col932": "t15df", + "col933": "11vpe", + "col934": "jmljq", + "col935": "gs577", + "col936": "txesk", + "col937": "fadl4", + "col938": "5tjtk", + "col939": "z7wn5", + "col940": "ljn45", + "col941": "r87j6", + "col942": "llil0", + "col943": "3784z", + "col944": "3uu0k", + "col945": "0pj8z", + "col946": "x6laa", + "col947": "dkoq8", + "col948": "ybrpg", + "col949": "x22x1", + "col950": "sbq2e", + "col951": "2ygxv", + "col952": "d0edr", + "col953": "prr23", + "col954": "2b898", + "col955": "g0hnp", + "col956": "4ukj3", + "col957": "oam83", + "col958": "8rqha", + "col959": "bygck", + "col960": "u56pn", + "col961": "dssd1", + "col962": "et25j", + "col963": "4vpkc", + "col964": "e7sz2", + "col965": "qyw2c", + "col966": "wqs19", + "col967": "jn09k", + "col968": "2ueih", + "col969": "xcb51", + "col970": "7g6fi", + "col971": "3y5lg", + "col972": "w7zgf", + "col973": "wi1dl", + "col974": "hh6cu", + "col975": "32vkn", + "col976": "qf64p", + "col977": "j6oll", + "col978": "hktm9", + "col979": "ze39w", + "col980": "h1kn1", + "col981": "qr8rb", + "col982": "q1vtf", + "col983": "au8z2", + "col984": "htgpe", + "col985": "4xoym", + "col986": "t98h2", + "col987": "yifq8", + "col988": "xm2hz", + "col989": "wug08", + "col990": "vjuh7", + "col991": "w3sse", + "col992": "l5ns9", + "col993": "t9ho2", + "col994": "ki7ef", + "col995": "qe4pe", + "col996": "r12nj", + "col997": "uc3t5", + "col998": "8775y", + "col999": "62yn0" + }, + { + "name": "Chan Rhodes", + "gender": "male", + "col0": "8427r", + "col1": "as8df", + "col2": "pg30u", + "col3": "4ex23", + "col4": "74xhz", + "col5": "qw11m", + "col6": "rutkl", + "col7": "kj29i", + "col8": "ak9k0", + "col9": "zt14d", + "col10": "wngu9", + "col11": "lw0jw", + "col12": "hm4k9", + "col13": "m5nmb", + "col14": "2dvtv", + "col15": "4ljp3", + "col16": "rvbeh", + "col17": "ks6jx", + "col18": "gigqp", + "col19": "q8ax9", + "col20": "jbf0d", + "col21": "uhmcz", + "col22": "4fztk", + "col23": "82epr", + "col24": "snj8k", + "col25": "42oph", + "col26": "hp8lm", + "col27": "1kpu1", + "col28": "ytsmt", + "col29": "1jrew", + "col30": "889gr", + "col31": "2li7x", + "col32": "s9qfy", + "col33": "dr6e5", + "col34": "lpdzl", + "col35": "pbzxu", + "col36": "6ra2i", + "col37": "5bmnk", + "col38": "apz87", + "col39": "via24", + "col40": "9wkhe", + "col41": "p7dsn", + "col42": "4ozrb", + "col43": "z7vam", + "col44": "66aav", + "col45": "chcwq", + "col46": "tchqv", + "col47": "j9k6k", + "col48": "gafpx", + "col49": "5yyjd", + "col50": "dteg4", + "col51": "kbt0h", + "col52": "jx7p6", + "col53": "cdovs", + "col54": "770g8", + "col55": "5kpnj", + "col56": "xky2r", + "col57": "k8g78", + "col58": "lxq9z", + "col59": "2hggf", + "col60": "ag5jy", + "col61": "av7yi", + "col62": "nw9c3", + "col63": "mpofk", + "col64": "dmiqr", + "col65": "waea7", + "col66": "i86gt", + "col67": "myaeq", + "col68": "gjddc", + "col69": "s3g4t", + "col70": "3pcr6", + "col71": "a4jwa", + "col72": "25ofl", + "col73": "0pk5e", + "col74": "rovmj", + "col75": "k1l2y", + "col76": "ibk74", + "col77": "pjmod", + "col78": "399l0", + "col79": "sbrop", + "col80": "orcyb", + "col81": "09p2r", + "col82": "lttrx", + "col83": "20dy4", + "col84": "ran8r", + "col85": "j963p", + "col86": "u3g9y", + "col87": "ri2h1", + "col88": "tn4ek", + "col89": "v8ord", + "col90": "6wzb7", + "col91": "q7ni4", + "col92": "rtyyo", + "col93": "x9m60", + "col94": "1ddym", + "col95": "kosyv", + "col96": "vl881", + "col97": "ldzn7", + "col98": "h0hja", + "col99": "go4fz", + "col100": "axj7f", + "col101": "rynpr", + "col102": "yfy6y", + "col103": "vvskn", + "col104": "nud1m", + "col105": "4c24d", + "col106": "m7ix2", + "col107": "b8o7n", + "col108": "v7wcw", + "col109": "oqzei", + "col110": "qcygb", + "col111": "ei0mm", + "col112": "pvou9", + "col113": "cow97", + "col114": "h852p", + "col115": "7fw4j", + "col116": "bbore", + "col117": "me0qz", + "col118": "12isd", + "col119": "p0mhv", + "col120": "ruzf0", + "col121": "cdtyt", + "col122": "55u0k", + "col123": "i8ltk", + "col124": "f74yj", + "col125": "1ha82", + "col126": "i34ia", + "col127": "xceu4", + "col128": "uwot2", + "col129": "z360s", + "col130": "ak3mf", + "col131": "bhn8u", + "col132": "i33s6", + "col133": "vzffh", + "col134": "u7l2u", + "col135": "hgtz1", + "col136": "quuks", + "col137": "jj5o6", + "col138": "khb68", + "col139": "6hrzi", + "col140": "4vhgo", + "col141": "wxtd0", + "col142": "pe5s4", + "col143": "iz4mo", + "col144": "6fomr", + "col145": "nuaf7", + "col146": "ankai", + "col147": "yfmvq", + "col148": "c3ipe", + "col149": "ft4rk", + "col150": "hki11", + "col151": "nqeil", + "col152": "qdlia", + "col153": "jth34", + "col154": "tyug9", + "col155": "xwh46", + "col156": "3gna4", + "col157": "28bv3", + "col158": "6vomh", + "col159": "b5zc5", + "col160": "1clo6", + "col161": "0mejt", + "col162": "khvul", + "col163": "6tmrf", + "col164": "2xf45", + "col165": "f0rw5", + "col166": "fzm4k", + "col167": "ntuss", + "col168": "l1c4f", + "col169": "w8j5i", + "col170": "zc5by", + "col171": "w0ylx", + "col172": "jat36", + "col173": "we0kt", + "col174": "4rwdh", + "col175": "ncb2n", + "col176": "3zxhy", + "col177": "ey4lb", + "col178": "iasi7", + "col179": "62hzn", + "col180": "l5mwq", + "col181": "gzgo4", + "col182": "0ad8u", + "col183": "ecuym", + "col184": "lrg49", + "col185": "ad2vv", + "col186": "yd89a", + "col187": "dxgve", + "col188": "80690", + "col189": "aj8xk", + "col190": "buipe", + "col191": "qk0q0", + "col192": "wuuhd", + "col193": "ec4t9", + "col194": "thk0v", + "col195": "chaix", + "col196": "j5deg", + "col197": "u6rla", + "col198": "48ccy", + "col199": "nyd75", + "col200": "cds5o", + "col201": "7g87a", + "col202": "854e8", + "col203": "kq5sg", + "col204": "nn5wo", + "col205": "r1kw6", + "col206": "v0qd4", + "col207": "fll9k", + "col208": "6yvri", + "col209": "ni5ce", + "col210": "165k0", + "col211": "sqaoh", + "col212": "btj5o", + "col213": "099u3", + "col214": "tbgay", + "col215": "nv00v", + "col216": "0to47", + "col217": "njc05", + "col218": "hbiv4", + "col219": "we82r", + "col220": "z3xic", + "col221": "3xikl", + "col222": "bqx8p", + "col223": "5e26c", + "col224": "mqu8e", + "col225": "b9rkb", + "col226": "cghht", + "col227": "nmakl", + "col228": "6op0g", + "col229": "paf6k", + "col230": "f0d04", + "col231": "gj0i7", + "col232": "wqckj", + "col233": "8iq7h", + "col234": "qpdnd", + "col235": "m0rf7", + "col236": "236ni", + "col237": "za407", + "col238": "59o43", + "col239": "1yqw8", + "col240": "gomjb", + "col241": "zsf8j", + "col242": "dp7ub", + "col243": "r62dy", + "col244": "7tean", + "col245": "wbs37", + "col246": "ltspq", + "col247": "lurs1", + "col248": "u84b2", + "col249": "g3exm", + "col250": "eocac", + "col251": "53s6y", + "col252": "81ymo", + "col253": "832i6", + "col254": "kz7ue", + "col255": "mwtz7", + "col256": "x111h", + "col257": "d2l4t", + "col258": "up0bd", + "col259": "wv26b", + "col260": "2ukv8", + "col261": "odwik", + "col262": "0129q", + "col263": "wacn2", + "col264": "wvdmj", + "col265": "9uuvr", + "col266": "xvjya", + "col267": "hjcvd", + "col268": "gp5jo", + "col269": "s60ap", + "col270": "cn7lv", + "col271": "62tht", + "col272": "06kb6", + "col273": "ule4d", + "col274": "4x9b6", + "col275": "ui1hf", + "col276": "59bgi", + "col277": "4z1z2", + "col278": "5vr03", + "col279": "21wj9", + "col280": "3qzve", + "col281": "d0ats", + "col282": "9akxf", + "col283": "x87p4", + "col284": "thnw1", + "col285": "yg0jc", + "col286": "0gl14", + "col287": "km4y0", + "col288": "2d6os", + "col289": "cun22", + "col290": "0kl82", + "col291": "2qyvt", + "col292": "r1edh", + "col293": "1u6o9", + "col294": "3wkmb", + "col295": "c4620", + "col296": "ym37w", + "col297": "bahwy", + "col298": "731ve", + "col299": "sslgx", + "col300": "rh9x5", + "col301": "l9imw", + "col302": "fct9g", + "col303": "90ole", + "col304": "tyi36", + "col305": "eadjy", + "col306": "ub4b2", + "col307": "bs8hw", + "col308": "opzt5", + "col309": "2zf33", + "col310": "4vd79", + "col311": "v6qyv", + "col312": "gseo3", + "col313": "h4q88", + "col314": "fzs3o", + "col315": "2lug8", + "col316": "g22e6", + "col317": "5wmf3", + "col318": "essim", + "col319": "14u52", + "col320": "lurim", + "col321": "104gv", + "col322": "97t3o", + "col323": "2n87u", + "col324": "jdyb4", + "col325": "1tr31", + "col326": "ojmyh", + "col327": "c8cv2", + "col328": "3c22l", + "col329": "zxbcv", + "col330": "b60j7", + "col331": "r0ium", + "col332": "21zsn", + "col333": "2vvdo", + "col334": "ecvy5", + "col335": "u0jpz", + "col336": "0mwux", + "col337": "wg7t0", + "col338": "xr2fk", + "col339": "zvh44", + "col340": "r5y3j", + "col341": "i8trn", + "col342": "iqah7", + "col343": "v0txf", + "col344": "jxvzv", + "col345": "rmgo1", + "col346": "zpv7a", + "col347": "xtg4s", + "col348": "79mru", + "col349": "wzrce", + "col350": "5wfqg", + "col351": "8pmd8", + "col352": "59tdj", + "col353": "g9uz6", + "col354": "qkxzm", + "col355": "58lsf", + "col356": "nguis", + "col357": "gbegt", + "col358": "008fn", + "col359": "bzedc", + "col360": "nxy16", + "col361": "s5d3w", + "col362": "ncenp", + "col363": "r7nf8", + "col364": "1fwr0", + "col365": "rw9dt", + "col366": "sowrr", + "col367": "kpl9a", + "col368": "g8r4f", + "col369": "w8aii", + "col370": "3ze9b", + "col371": "ni534", + "col372": "vbh2k", + "col373": "5lv23", + "col374": "x2ujf", + "col375": "lo91n", + "col376": "ufavc", + "col377": "xr27f", + "col378": "f8fdq", + "col379": "q6dth", + "col380": "9s0vh", + "col381": "y463r", + "col382": "wx01d", + "col383": "s1fei", + "col384": "kwffz", + "col385": "ukxlu", + "col386": "gs14q", + "col387": "m65vp", + "col388": "ojo71", + "col389": "5cvvc", + "col390": "xjmcr", + "col391": "qmpy8", + "col392": "xionm", + "col393": "g8wog", + "col394": "t1no8", + "col395": "z7fs6", + "col396": "ljslz", + "col397": "tn15f", + "col398": "2ui0w", + "col399": "ebgx4", + "col400": "tsvnv", + "col401": "wiuib", + "col402": "dwuz0", + "col403": "q7ie7", + "col404": "km357", + "col405": "2vvk9", + "col406": "wy3ij", + "col407": "2xlav", + "col408": "ultip", + "col409": "nxnih", + "col410": "tabvc", + "col411": "qsdc1", + "col412": "szm8t", + "col413": "zpw09", + "col414": "0pi9d", + "col415": "wwcpb", + "col416": "gi2h4", + "col417": "bd5lh", + "col418": "46ad3", + "col419": "vc6fd", + "col420": "ezlt1", + "col421": "rrk2z", + "col422": "ykbnk", + "col423": "knrrd", + "col424": "bzb5n", + "col425": "pjt2h", + "col426": "1e7hq", + "col427": "5lwjb", + "col428": "8t3od", + "col429": "zf6u7", + "col430": "5q4wx", + "col431": "ge5cz", + "col432": "dwbq0", + "col433": "1tsha", + "col434": "x1x9e", + "col435": "5xyw4", + "col436": "31ihy", + "col437": "w6a2r", + "col438": "phbr9", + "col439": "pqced", + "col440": "alq6n", + "col441": "vkmzj", + "col442": "nvphm", + "col443": "rwi85", + "col444": "ny374", + "col445": "jy23z", + "col446": "xy8qx", + "col447": "92q3e", + "col448": "6l7mg", + "col449": "xnu33", + "col450": "ciuw1", + "col451": "mxg8f", + "col452": "muvjd", + "col453": "zanim", + "col454": "u2qnl", + "col455": "4nlqz", + "col456": "myibm", + "col457": "u82fg", + "col458": "gegpq", + "col459": "tswi8", + "col460": "m7746", + "col461": "03krb", + "col462": "gci95", + "col463": "i3xz3", + "col464": "4hhw4", + "col465": "vjwnf", + "col466": "395pm", + "col467": "5rvwx", + "col468": "y9m9k", + "col469": "z7oj8", + "col470": "c070t", + "col471": "0r5x6", + "col472": "zk9e5", + "col473": "w6ffw", + "col474": "1txth", + "col475": "svuyn", + "col476": "npuf5", + "col477": "xyumu", + "col478": "prmi3", + "col479": "2d0m0", + "col480": "l1iec", + "col481": "q5n24", + "col482": "pytw8", + "col483": "pf4aa", + "col484": "uu83f", + "col485": "wa9i5", + "col486": "3tjl4", + "col487": "fa10y", + "col488": "vcqrw", + "col489": "io15a", + "col490": "ixjtv", + "col491": "r1b0a", + "col492": "eqtvm", + "col493": "5dfpq", + "col494": "7xwjg", + "col495": "zxi9o", + "col496": "me8mz", + "col497": "b7naj", + "col498": "xdwng", + "col499": "hf30x", + "col500": "tdf9z", + "col501": "vxujd", + "col502": "pq2mg", + "col503": "qs8r9", + "col504": "19e5l", + "col505": "4rhc8", + "col506": "eup3m", + "col507": "ci9gy", + "col508": "kh93z", + "col509": "7ww7j", + "col510": "74mpi", + "col511": "isib8", + "col512": "0538i", + "col513": "8ubqo", + "col514": "37pqt", + "col515": "hocyp", + "col516": "2l0tj", + "col517": "0zdfc", + "col518": "nfkz6", + "col519": "y4uzw", + "col520": "n0v5k", + "col521": "29lb3", + "col522": "hndgq", + "col523": "oifha", + "col524": "w9sz9", + "col525": "5meyo", + "col526": "swmkl", + "col527": "k8snv", + "col528": "ntkeo", + "col529": "84ph5", + "col530": "0dywc", + "col531": "a9pru", + "col532": "0lar8", + "col533": "gsty6", + "col534": "quc9t", + "col535": "cvjjp", + "col536": "dodpp", + "col537": "dmrle", + "col538": "vbbd2", + "col539": "i0agv", + "col540": "64mbm", + "col541": "nhzsd", + "col542": "k8lzj", + "col543": "rfeg9", + "col544": "ldkbd", + "col545": "8ihoe", + "col546": "yjdcx", + "col547": "34lds", + "col548": "rwosl", + "col549": "um3vp", + "col550": "evlw2", + "col551": "igqk3", + "col552": "sh9x4", + "col553": "vjlyc", + "col554": "ngdfc", + "col555": "24gnn", + "col556": "z3yrw", + "col557": "0icjy", + "col558": "qp87s", + "col559": "dzwmc", + "col560": "rek4a", + "col561": "k0ly4", + "col562": "2sjy0", + "col563": "xfn0u", + "col564": "td5c4", + "col565": "ixmpx", + "col566": "t5gwq", + "col567": "t81vk", + "col568": "zy6jm", + "col569": "ujuui", + "col570": "nyiix", + "col571": "cysds", + "col572": "dyc9a", + "col573": "boz3o", + "col574": "rh4ie", + "col575": "xadc0", + "col576": "mpc3n", + "col577": "n3dx4", + "col578": "0g2t8", + "col579": "qwmmx", + "col580": "vl8sb", + "col581": "x5rmx", + "col582": "501wi", + "col583": "rgwol", + "col584": "ggkva", + "col585": "s309f", + "col586": "hae4v", + "col587": "4w643", + "col588": "epu1d", + "col589": "6c28y", + "col590": "dd7dv", + "col591": "ihssi", + "col592": "4zxeo", + "col593": "bp9h6", + "col594": "bgv9r", + "col595": "5darq", + "col596": "yq5lc", + "col597": "p61ew", + "col598": "ixvuv", + "col599": "6xz27", + "col600": "fn9l5", + "col601": "70t6w", + "col602": "p654y", + "col603": "pekv1", + "col604": "wjln9", + "col605": "y484e", + "col606": "uv9wv", + "col607": "u2z3p", + "col608": "kw26w", + "col609": "70py8", + "col610": "z10td", + "col611": "na7pg", + "col612": "avh87", + "col613": "1f2ho", + "col614": "dolij", + "col615": "fcz9a", + "col616": "btt9t", + "col617": "0l0ss", + "col618": "cb5y3", + "col619": "4l3jg", + "col620": "381fd", + "col621": "m6nix", + "col622": "tqtcs", + "col623": "6btp2", + "col624": "53r33", + "col625": "434gp", + "col626": "q008u", + "col627": "m2lty", + "col628": "wvv9o", + "col629": "52zsj", + "col630": "q279t", + "col631": "nwqmv", + "col632": "o8xso", + "col633": "3xva6", + "col634": "mt9sh", + "col635": "3xlkq", + "col636": "uwivf", + "col637": "smgm0", + "col638": "5wcet", + "col639": "lryak", + "col640": "9gety", + "col641": "c5rnx", + "col642": "b69ep", + "col643": "6vlnx", + "col644": "tl0mu", + "col645": "ailzj", + "col646": "zpsid", + "col647": "hdc4c", + "col648": "t53dw", + "col649": "um93q", + "col650": "7lkcy", + "col651": "sewcs", + "col652": "9hk1s", + "col653": "rq0l4", + "col654": "g4p8n", + "col655": "awddw", + "col656": "glxau", + "col657": "l30an", + "col658": "0zn8e", + "col659": "j8cww", + "col660": "d3ryb", + "col661": "r56ll", + "col662": "30dyr", + "col663": "5xtvp", + "col664": "1f5gf", + "col665": "0j5o4", + "col666": "ucbnr", + "col667": "gn3jj", + "col668": "ls8h9", + "col669": "yxvkh", + "col670": "nt3rw", + "col671": "sccgy", + "col672": "skbz4", + "col673": "c0uyc", + "col674": "3mtt2", + "col675": "igr71", + "col676": "pce6k", + "col677": "t48zg", + "col678": "fno5j", + "col679": "iwhsq", + "col680": "4360u", + "col681": "xzx9g", + "col682": "wd4rx", + "col683": "wphgu", + "col684": "t8pkw", + "col685": "n8nrz", + "col686": "39nmc", + "col687": "zw1bd", + "col688": "qrxx5", + "col689": "a2sax", + "col690": "57bd2", + "col691": "4drti", + "col692": "l9pyr", + "col693": "8ti4s", + "col694": "bzrhv", + "col695": "g66b2", + "col696": "neuse", + "col697": "8jhbk", + "col698": "9jcpk", + "col699": "zlwe9", + "col700": "ba3v5", + "col701": "96z2r", + "col702": "0vgx4", + "col703": "zdvvd", + "col704": "mipe9", + "col705": "j3m37", + "col706": "ym7du", + "col707": "7cn6l", + "col708": "si958", + "col709": "ds65t", + "col710": "w78ps", + "col711": "0eal7", + "col712": "iizmk", + "col713": "e83uc", + "col714": "1c6un", + "col715": "wnb4m", + "col716": "yyj7w", + "col717": "y2va9", + "col718": "c1aoh", + "col719": "u2rcl", + "col720": "87ijc", + "col721": "nh84l", + "col722": "ruxbi", + "col723": "pdbmz", + "col724": "hxwv9", + "col725": "ufwp0", + "col726": "cckyo", + "col727": "y21hn", + "col728": "yl1ao", + "col729": "peuqy", + "col730": "t6qo5", + "col731": "1zjvc", + "col732": "w8ipz", + "col733": "z1n5w", + "col734": "9ydco", + "col735": "m1xh1", + "col736": "13cdp", + "col737": "m17wj", + "col738": "4smmh", + "col739": "qttm6", + "col740": "5kgrh", + "col741": "i7jup", + "col742": "fsdb9", + "col743": "adys0", + "col744": "aidxd", + "col745": "xu4go", + "col746": "hioki", + "col747": "7sxua", + "col748": "3v4b9", + "col749": "3jewp", + "col750": "a6nd8", + "col751": "yng34", + "col752": "btkx0", + "col753": "624mo", + "col754": "r2grd", + "col755": "hc9kw", + "col756": "69iol", + "col757": "snk6s", + "col758": "62yai", + "col759": "3s0vh", + "col760": "13yl1", + "col761": "hiq5g", + "col762": "mwn2f", + "col763": "jm15l", + "col764": "ttjbq", + "col765": "mt3d8", + "col766": "cvuz7", + "col767": "t5l0y", + "col768": "0pf59", + "col769": "yg0tb", + "col770": "u2s9l", + "col771": "1wpe4", + "col772": "g5oab", + "col773": "1l0tk", + "col774": "rjptl", + "col775": "aw87h", + "col776": "wfmri", + "col777": "012m1", + "col778": "lzdrq", + "col779": "jjlme", + "col780": "6dujt", + "col781": "klyav", + "col782": "94r8u", + "col783": "b6ifs", + "col784": "xjjpu", + "col785": "bk28o", + "col786": "z4jp1", + "col787": "68d1d", + "col788": "bi6wq", + "col789": "ncm4h", + "col790": "puqt2", + "col791": "rbaem", + "col792": "s4mg2", + "col793": "vbra5", + "col794": "ebwl0", + "col795": "1jx2f", + "col796": "nd493", + "col797": "tjqg6", + "col798": "0mmuc", + "col799": "pr6vo", + "col800": "vrjq9", + "col801": "pu0d5", + "col802": "kryhk", + "col803": "vyp96", + "col804": "jkgfs", + "col805": "itqhm", + "col806": "dy0gh", + "col807": "f5r0p", + "col808": "q1k6i", + "col809": "w0twe", + "col810": "shb2k", + "col811": "edrb0", + "col812": "8asyj", + "col813": "5wgmj", + "col814": "4c1s7", + "col815": "w9itg", + "col816": "diar5", + "col817": "nfrzh", + "col818": "bki5b", + "col819": "m2xtp", + "col820": "zfcdh", + "col821": "ws95h", + "col822": "0dxrb", + "col823": "x2iu5", + "col824": "13t0s", + "col825": "jwazg", + "col826": "0qnr3", + "col827": "iqwkq", + "col828": "astsd", + "col829": "i36p9", + "col830": "7gzpl", + "col831": "06lee", + "col832": "ml5du", + "col833": "mfck3", + "col834": "dodqj", + "col835": "dsbry", + "col836": "ntlne", + "col837": "bcj2a", + "col838": "6i32b", + "col839": "oth5s", + "col840": "1mnzr", + "col841": "p1s9p", + "col842": "37vdf", + "col843": "r499v", + "col844": "hfhm2", + "col845": "ztyat", + "col846": "y6pdx", + "col847": "31ed5", + "col848": "vqwg6", + "col849": "9qx4e", + "col850": "the6a", + "col851": "7wz9p", + "col852": "0dg6p", + "col853": "8rdxn", + "col854": "pjz50", + "col855": "r8bgu", + "col856": "vvwin", + "col857": "ige9z", + "col858": "7g8pr", + "col859": "4tf8r", + "col860": "i8cp9", + "col861": "55s82", + "col862": "urwgx", + "col863": "f4w2k", + "col864": "04uqs", + "col865": "xvpm3", + "col866": "eqbkz", + "col867": "3blxh", + "col868": "o9jeu", + "col869": "bbvt6", + "col870": "9f64m", + "col871": "tw6on", + "col872": "5eqgf", + "col873": "e3r47", + "col874": "dv7wz", + "col875": "a2758", + "col876": "3j3bu", + "col877": "67ral", + "col878": "n213u", + "col879": "i8c4c", + "col880": "07i19", + "col881": "49fga", + "col882": "47quj", + "col883": "w2iv9", + "col884": "gm4w5", + "col885": "qw3z5", + "col886": "tmoi2", + "col887": "dp2ot", + "col888": "x2pot", + "col889": "uolfe", + "col890": "2mouw", + "col891": "h9eq1", + "col892": "930pc", + "col893": "ofa4d", + "col894": "pf7q5", + "col895": "imx16", + "col896": "imfkj", + "col897": "mt3zd", + "col898": "upfmi", + "col899": "zdynq", + "col900": "hf6xw", + "col901": "ko056", + "col902": "kitcf", + "col903": "m2haw", + "col904": "x3eqq", + "col905": "3e5ff", + "col906": "i7c94", + "col907": "gx1qh", + "col908": "jtbkl", + "col909": "3z0fg", + "col910": "zaekk", + "col911": "fqjlu", + "col912": "02yri", + "col913": "dylvy", + "col914": "4mocp", + "col915": "zn2ji", + "col916": "yj2vh", + "col917": "z3ts1", + "col918": "dsjtk", + "col919": "w7jx9", + "col920": "ehqon", + "col921": "3dpah", + "col922": "d7iq3", + "col923": "jdcp7", + "col924": "hls3j", + "col925": "volk5", + "col926": "1fv2q", + "col927": "hgneu", + "col928": "80xqs", + "col929": "ufwmy", + "col930": "220rz", + "col931": "lemys", + "col932": "xl3z7", + "col933": "mwu3x", + "col934": "0jjn1", + "col935": "dk40d", + "col936": "9l582", + "col937": "qzdde", + "col938": "hui66", + "col939": "twkug", + "col940": "kzff2", + "col941": "6benc", + "col942": "dr9r8", + "col943": "3t652", + "col944": "qzyak", + "col945": "igk4h", + "col946": "tg2rs", + "col947": "u7xk9", + "col948": "nbodd", + "col949": "bdjeo", + "col950": "0vaph", + "col951": "f57eo", + "col952": "sh2rc", + "col953": "s7euw", + "col954": "bz8ae", + "col955": "ayfm3", + "col956": "hvkxx", + "col957": "gkaal", + "col958": "mx991", + "col959": "e1g5b", + "col960": "6dt4w", + "col961": "4vxt1", + "col962": "6r5iv", + "col963": "wc7k0", + "col964": "nulph", + "col965": "g1mvs", + "col966": "h1d6k", + "col967": "y07d2", + "col968": "jyflj", + "col969": "j015e", + "col970": "71q6p", + "col971": "mcgyb", + "col972": "ov4cu", + "col973": "xr9oz", + "col974": "q4vzz", + "col975": "y1kls", + "col976": "2mbfj", + "col977": "2gr31", + "col978": "ondbw", + "col979": "hg9fd", + "col980": "r8dsk", + "col981": "2snoa", + "col982": "xplsm", + "col983": "us4r9", + "col984": "uj1r4", + "col985": "1ye97", + "col986": "5hf61", + "col987": "0xekr", + "col988": "xhsmx", + "col989": "rw610", + "col990": "f1lpz", + "col991": "k28gc", + "col992": "wxyp8", + "col993": "gzjd4", + "col994": "3kphg", + "col995": "o6f8w", + "col996": "jhlpy", + "col997": "tnxez", + "col998": "g2tpx", + "col999": "qhgax" + }, + { + "name": "Lynnette Burton", + "gender": "female", + "col0": "mmq0j", + "col1": "jtw68", + "col2": "3n1d8", + "col3": "nx9xs", + "col4": "l367h", + "col5": "gcnuv", + "col6": "oqg8x", + "col7": "87syc", + "col8": "mo2gq", + "col9": "vqbq5", + "col10": "s1w08", + "col11": "zfp51", + "col12": "k2lu4", + "col13": "3b34h", + "col14": "98uw1", + "col15": "dpuwm", + "col16": "lzqdd", + "col17": "jvymu", + "col18": "sh069", + "col19": "abjk1", + "col20": "tdju0", + "col21": "s80yl", + "col22": "r015x", + "col23": "0cakc", + "col24": "2vl0f", + "col25": "4syfn", + "col26": "jnm14", + "col27": "cc1qz", + "col28": "zhhy9", + "col29": "bjs4s", + "col30": "vm0yd", + "col31": "lu5qc", + "col32": "esxhp", + "col33": "qfayl", + "col34": "35hr2", + "col35": "tf0pv", + "col36": "5hge5", + "col37": "11zly", + "col38": "6azmn", + "col39": "f1v3k", + "col40": "t05x4", + "col41": "hz1tn", + "col42": "u3zrw", + "col43": "co3kn", + "col44": "2v24s", + "col45": "a64lv", + "col46": "xvo9r", + "col47": "nf05z", + "col48": "47pfu", + "col49": "we30k", + "col50": "uokx4", + "col51": "xf4vw", + "col52": "i4j7t", + "col53": "eujt4", + "col54": "afu7v", + "col55": "uc1r1", + "col56": "9gora", + "col57": "8k9ua", + "col58": "dnv8q", + "col59": "8gvip", + "col60": "iv6ao", + "col61": "2nnf7", + "col62": "k8w22", + "col63": "uoum6", + "col64": "giw67", + "col65": "l9wmg", + "col66": "pixi1", + "col67": "crfkl", + "col68": "aytdn", + "col69": "vbk7v", + "col70": "op4b5", + "col71": "tr75s", + "col72": "573k4", + "col73": "z23p3", + "col74": "jsent", + "col75": "4e3hw", + "col76": "01vof", + "col77": "b9wwj", + "col78": "4e5rp", + "col79": "wt7hr", + "col80": "qhg8z", + "col81": "jro60", + "col82": "91kqg", + "col83": "9v61g", + "col84": "q9n9h", + "col85": "ij8p0", + "col86": "bb2qq", + "col87": "fqcuy", + "col88": "61dmg", + "col89": "e97ke", + "col90": "cfpab", + "col91": "y03fc", + "col92": "ug4rl", + "col93": "97evj", + "col94": "jfwq6", + "col95": "rw5vx", + "col96": "tk5u3", + "col97": "98ae5", + "col98": "5edjp", + "col99": "7nxgo", + "col100": "4er8p", + "col101": "dyabb", + "col102": "a6chp", + "col103": "pyzpg", + "col104": "j870g", + "col105": "vuck6", + "col106": "wta4k", + "col107": "juszm", + "col108": "a8wvh", + "col109": "0igug", + "col110": "qff31", + "col111": "auhs1", + "col112": "wvuhb", + "col113": "0b7es", + "col114": "uyfpr", + "col115": "j8ajh", + "col116": "yvipa", + "col117": "gm4je", + "col118": "u6l32", + "col119": "csgph", + "col120": "cnp7j", + "col121": "89fca", + "col122": "k9yeq", + "col123": "j8and", + "col124": "qvl43", + "col125": "nw0l3", + "col126": "s529m", + "col127": "wovnq", + "col128": "uuwk7", + "col129": "82cde", + "col130": "tcy44", + "col131": "zeqcv", + "col132": "k1kyh", + "col133": "svaau", + "col134": "i6dky", + "col135": "tikwu", + "col136": "qhmoc", + "col137": "c3fkz", + "col138": "gyxnc", + "col139": "c8fuw", + "col140": "feqn6", + "col141": "caz71", + "col142": "oqn1k", + "col143": "7v1jz", + "col144": "at901", + "col145": "wffsi", + "col146": "54dto", + "col147": "yj4zw", + "col148": "5nktd", + "col149": "d4vyj", + "col150": "8ll0e", + "col151": "qnw5z", + "col152": "u8lu8", + "col153": "bcw6g", + "col154": "8ywjw", + "col155": "ygemg", + "col156": "kids9", + "col157": "2ngq3", + "col158": "9w6sy", + "col159": "li2no", + "col160": "o7klr", + "col161": "9q5rx", + "col162": "nilw6", + "col163": "0vp4x", + "col164": "xe9lk", + "col165": "a7292", + "col166": "6saq8", + "col167": "yzg7c", + "col168": "or2x6", + "col169": "y2jd2", + "col170": "sl695", + "col171": "saosg", + "col172": "m9e31", + "col173": "my943", + "col174": "a4vcb", + "col175": "lm8fg", + "col176": "7bh7h", + "col177": "8nt4v", + "col178": "pqasb", + "col179": "eb8hn", + "col180": "b6lbt", + "col181": "0mmac", + "col182": "5kubz", + "col183": "wivw3", + "col184": "m7qgp", + "col185": "jvg7i", + "col186": "m29b3", + "col187": "4jdi6", + "col188": "mmmys", + "col189": "x0fwl", + "col190": "4vpb5", + "col191": "z7tdd", + "col192": "toeus", + "col193": "edzue", + "col194": "610mq", + "col195": "n8p7j", + "col196": "tf1vf", + "col197": "im3l0", + "col198": "rn9w4", + "col199": "2cf14", + "col200": "yebh8", + "col201": "vamc6", + "col202": "hf7rc", + "col203": "r1vkv", + "col204": "ewo99", + "col205": "9gunj", + "col206": "gprbz", + "col207": "6fbxs", + "col208": "wkj7k", + "col209": "rkqde", + "col210": "wh0od", + "col211": "iarns", + "col212": "yeq48", + "col213": "fh5gm", + "col214": "91kic", + "col215": "q8fwm", + "col216": "aha4p", + "col217": "8m92q", + "col218": "km7hs", + "col219": "bas3o", + "col220": "yuagt", + "col221": "t5v9z", + "col222": "kx6xk", + "col223": "8sptg", + "col224": "yv2iy", + "col225": "geks5", + "col226": "oc9xu", + "col227": "dqpa4", + "col228": "0q4dg", + "col229": "vi4vn", + "col230": "legmk", + "col231": "obrcr", + "col232": "jkjsy", + "col233": "dbf1p", + "col234": "5dnrd", + "col235": "xeslf", + "col236": "ugv76", + "col237": "ugyad", + "col238": "fd89r", + "col239": "be75e", + "col240": "8eg64", + "col241": "7lmtl", + "col242": "0eosu", + "col243": "j08lh", + "col244": "e1rgo", + "col245": "4bt61", + "col246": "uhb39", + "col247": "w7i3h", + "col248": "k0hbl", + "col249": "avz4z", + "col250": "ke4lk", + "col251": "bee1a", + "col252": "31oky", + "col253": "g1982", + "col254": "vi5nr", + "col255": "po2eo", + "col256": "7fyh6", + "col257": "rv92y", + "col258": "oye2f", + "col259": "hy03m", + "col260": "v3kes", + "col261": "vwf9h", + "col262": "v0t1r", + "col263": "ohbpp", + "col264": "gedvu", + "col265": "t2jui", + "col266": "gflqt", + "col267": "s4xf9", + "col268": "0hy5g", + "col269": "mfq6b", + "col270": "i8eft", + "col271": "46on2", + "col272": "cziwx", + "col273": "gggtr", + "col274": "krgth", + "col275": "4g2mh", + "col276": "jjjod", + "col277": "oy6eg", + "col278": "fpxfa", + "col279": "2i44g", + "col280": "fyfl6", + "col281": "k1i6t", + "col282": "awdq8", + "col283": "cohwy", + "col284": "xbbl6", + "col285": "yw8rm", + "col286": "tfce6", + "col287": "2gs9b", + "col288": "r3qe5", + "col289": "nap0n", + "col290": "q1gup", + "col291": "wneev", + "col292": "ci79x", + "col293": "0cjvj", + "col294": "3rbzm", + "col295": "uryzi", + "col296": "sxmvo", + "col297": "01noq", + "col298": "5nyfu", + "col299": "8ckk7", + "col300": "vycet", + "col301": "hxn90", + "col302": "rcqj5", + "col303": "2o3sc", + "col304": "6hz5b", + "col305": "vnuke", + "col306": "2vgjc", + "col307": "pb8oq", + "col308": "10rnx", + "col309": "jxmrz", + "col310": "6t21e", + "col311": "82psj", + "col312": "2dwz4", + "col313": "4tlrd", + "col314": "e7qto", + "col315": "rtila", + "col316": "z4q65", + "col317": "ao7jh", + "col318": "bc3cn", + "col319": "vhx36", + "col320": "ef0iq", + "col321": "tig6j", + "col322": "17qqz", + "col323": "2wo36", + "col324": "ond2w", + "col325": "xi219", + "col326": "3fjwn", + "col327": "iiqlg", + "col328": "g1954", + "col329": "owvct", + "col330": "2rius", + "col331": "3fd65", + "col332": "rm0qw", + "col333": "ssmqs", + "col334": "knjtk", + "col335": "5g4z5", + "col336": "e8mnp", + "col337": "6o4xj", + "col338": "l80e8", + "col339": "f8m7y", + "col340": "0065o", + "col341": "pysfp", + "col342": "y1vuo", + "col343": "gny7j", + "col344": "9w3az", + "col345": "m4kfo", + "col346": "wk0y7", + "col347": "ui30x", + "col348": "jmi85", + "col349": "vqzwy", + "col350": "8hfrf", + "col351": "6xb49", + "col352": "x3bhh", + "col353": "nhpir", + "col354": "tl7o2", + "col355": "dew52", + "col356": "t8hb9", + "col357": "suzty", + "col358": "44xqr", + "col359": "xi575", + "col360": "8ivs5", + "col361": "v2ia8", + "col362": "gc22s", + "col363": "4cmli", + "col364": "x8tze", + "col365": "uc3xm", + "col366": "4wyod", + "col367": "dtqku", + "col368": "y4kdv", + "col369": "aefiz", + "col370": "20lmk", + "col371": "n584b", + "col372": "js88c", + "col373": "15yo4", + "col374": "gvpci", + "col375": "335fx", + "col376": "cqtn8", + "col377": "wlm8k", + "col378": "qcqok", + "col379": "f56h7", + "col380": "vffyj", + "col381": "psgze", + "col382": "h7562", + "col383": "t4t4o", + "col384": "y1k1l", + "col385": "oee6z", + "col386": "l32lv", + "col387": "aov0w", + "col388": "18tqt", + "col389": "ytqii", + "col390": "przev", + "col391": "5scud", + "col392": "ofj5i", + "col393": "5z5iw", + "col394": "lvn1b", + "col395": "m1ojy", + "col396": "hxhiy", + "col397": "tpf5o", + "col398": "kv4xl", + "col399": "vm7aq", + "col400": "wqhw0", + "col401": "3gq48", + "col402": "jh0g6", + "col403": "sbpp1", + "col404": "gqgfz", + "col405": "fjqde", + "col406": "ai365", + "col407": "spkt8", + "col408": "i32pm", + "col409": "o8ky4", + "col410": "gp15h", + "col411": "j83vh", + "col412": "mlgyi", + "col413": "ux7aw", + "col414": "wobsc", + "col415": "02jes", + "col416": "nw6lc", + "col417": "5ih10", + "col418": "424pi", + "col419": "i70b4", + "col420": "8wbrq", + "col421": "rgs9u", + "col422": "vtxnu", + "col423": "ua4hw", + "col424": "isifd", + "col425": "t6jsy", + "col426": "2qtj6", + "col427": "39f2u", + "col428": "ws315", + "col429": "bl5tu", + "col430": "l0scc", + "col431": "mcseq", + "col432": "wtdrz", + "col433": "0f0yg", + "col434": "44oho", + "col435": "x73j5", + "col436": "5xw0n", + "col437": "qjbmi", + "col438": "29228", + "col439": "7530o", + "col440": "ojrw9", + "col441": "9gton", + "col442": "zbs09", + "col443": "eyli7", + "col444": "ig47n", + "col445": "qa3k8", + "col446": "0nr2i", + "col447": "xjchp", + "col448": "qabr7", + "col449": "7a6aq", + "col450": "xziif", + "col451": "neoaz", + "col452": "snriy", + "col453": "ialh4", + "col454": "z2yed", + "col455": "9n9iz", + "col456": "9g2yw", + "col457": "c90bs", + "col458": "8vkfu", + "col459": "1v8iy", + "col460": "ky6dz", + "col461": "j57ze", + "col462": "qr9av", + "col463": "92k6l", + "col464": "or3ui", + "col465": "ax78a", + "col466": "oiobq", + "col467": "qx76i", + "col468": "hxyxd", + "col469": "ozjen", + "col470": "5fqyp", + "col471": "fmy0s", + "col472": "xj1lj", + "col473": "ysxba", + "col474": "1o114", + "col475": "cz9hq", + "col476": "lqklh", + "col477": "g8ty0", + "col478": "fq2jw", + "col479": "3cyal", + "col480": "x50pi", + "col481": "qr5da", + "col482": "6b9qk", + "col483": "yo1za", + "col484": "sw3jm", + "col485": "mqp5u", + "col486": "1zu1t", + "col487": "th6dk", + "col488": "lrvq3", + "col489": "ofazy", + "col490": "vgy9l", + "col491": "99yuf", + "col492": "cp5h3", + "col493": "6m4zf", + "col494": "9yxyq", + "col495": "dub3j", + "col496": "q2xa6", + "col497": "vuvxh", + "col498": "snabc", + "col499": "t8hzn", + "col500": "w8mr7", + "col501": "ft9ck", + "col502": "nyge0", + "col503": "m9qru", + "col504": "hego8", + "col505": "33s09", + "col506": "1p5yv", + "col507": "7teyy", + "col508": "6shs9", + "col509": "y84te", + "col510": "hq975", + "col511": "0c3wx", + "col512": "hyc38", + "col513": "2bu4y", + "col514": "0zzqc", + "col515": "c63s9", + "col516": "eiixd", + "col517": "8bh6u", + "col518": "fots9", + "col519": "kxdjk", + "col520": "ezfrq", + "col521": "mg3t4", + "col522": "ejyfx", + "col523": "iwv4o", + "col524": "dmlfx", + "col525": "w01an", + "col526": "b493y", + "col527": "4yrtq", + "col528": "5yw3p", + "col529": "bizgq", + "col530": "rwv11", + "col531": "csa9t", + "col532": "oo0iv", + "col533": "rkmiz", + "col534": "3j81k", + "col535": "edpbt", + "col536": "ttc4x", + "col537": "ixp66", + "col538": "kvq8p", + "col539": "qos80", + "col540": "2aunk", + "col541": "d2wrk", + "col542": "zcox4", + "col543": "x5jvh", + "col544": "b5ugw", + "col545": "kg72n", + "col546": "fjifn", + "col547": "j5spa", + "col548": "zvaz6", + "col549": "jtd6b", + "col550": "lswr2", + "col551": "b7v89", + "col552": "816ad", + "col553": "wr54y", + "col554": "o7fl6", + "col555": "hz8im", + "col556": "583tk", + "col557": "h3z3c", + "col558": "3vuv9", + "col559": "7hm3h", + "col560": "di5ll", + "col561": "frc9z", + "col562": "20wqu", + "col563": "ykx76", + "col564": "2akgz", + "col565": "8puub", + "col566": "bp4vk", + "col567": "av3bm", + "col568": "igbek", + "col569": "u26uc", + "col570": "zdkph", + "col571": "e1zl8", + "col572": "bb0xo", + "col573": "uen1a", + "col574": "xnlaa", + "col575": "u5zsz", + "col576": "ze42g", + "col577": "m72s6", + "col578": "3e73d", + "col579": "u8012", + "col580": "4abri", + "col581": "eplzf", + "col582": "yqeho", + "col583": "u6p80", + "col584": "yje6y", + "col585": "j7he4", + "col586": "hti69", + "col587": "iy3au", + "col588": "jusbv", + "col589": "8w4eg", + "col590": "khu5w", + "col591": "9zvk6", + "col592": "qhyvs", + "col593": "yxnii", + "col594": "p7u9y", + "col595": "liq0u", + "col596": "4quni", + "col597": "ar0oa", + "col598": "lp7o0", + "col599": "1509l", + "col600": "h0v0o", + "col601": "8bogg", + "col602": "b9xia", + "col603": "0t9pt", + "col604": "9ba9h", + "col605": "soahq", + "col606": "8acon", + "col607": "xj2qw", + "col608": "0wjer", + "col609": "87dzw", + "col610": "r4bpg", + "col611": "2w623", + "col612": "kdr77", + "col613": "q2363", + "col614": "o0vgv", + "col615": "34ytb", + "col616": "zoy7r", + "col617": "pqbja", + "col618": "6sgof", + "col619": "t6lj9", + "col620": "r03iw", + "col621": "zqp6e", + "col622": "fp41r", + "col623": "hkkz6", + "col624": "w05ic", + "col625": "gd7i0", + "col626": "4wqjd", + "col627": "xh9vs", + "col628": "2gidr", + "col629": "uu715", + "col630": "8bfoy", + "col631": "56q1g", + "col632": "vs3qo", + "col633": "t2rwq", + "col634": "x69hi", + "col635": "arq9n", + "col636": "nge8g", + "col637": "bdz5n", + "col638": "t6pcx", + "col639": "8zekc", + "col640": "sbvop", + "col641": "jlorw", + "col642": "flmfd", + "col643": "bb9pc", + "col644": "hbta9", + "col645": "cyrt9", + "col646": "w6ic6", + "col647": "4p6fl", + "col648": "3krmb", + "col649": "gi8nc", + "col650": "vkeve", + "col651": "fl0gw", + "col652": "qm3p6", + "col653": "irc8t", + "col654": "rv04s", + "col655": "zqfdf", + "col656": "6v2ua", + "col657": "cea8i", + "col658": "e67fc", + "col659": "fjjck", + "col660": "2cr37", + "col661": "o69ve", + "col662": "0t5q9", + "col663": "747wq", + "col664": "g4sgh", + "col665": "qvcwk", + "col666": "0jaa4", + "col667": "kn5zw", + "col668": "mur3u", + "col669": "hyma5", + "col670": "f64z9", + "col671": "thcp3", + "col672": "aapdt", + "col673": "1kgie", + "col674": "08jlr", + "col675": "p3prl", + "col676": "pfcxe", + "col677": "om6x5", + "col678": "a54xo", + "col679": "dladw", + "col680": "uztf1", + "col681": "flumq", + "col682": "vyl88", + "col683": "cc21q", + "col684": "7xmaz", + "col685": "vb2w3", + "col686": "jw3en", + "col687": "gs98j", + "col688": "3661z", + "col689": "sy9bv", + "col690": "m6eam", + "col691": "ht23c", + "col692": "4wpoa", + "col693": "fg1rm", + "col694": "jq8rj", + "col695": "t7sp0", + "col696": "8bmd6", + "col697": "ulmh8", + "col698": "4l7ae", + "col699": "wjs88", + "col700": "0m3ku", + "col701": "a314a", + "col702": "wxyy2", + "col703": "qr19x", + "col704": "i15d2", + "col705": "645wg", + "col706": "np69h", + "col707": "srvwz", + "col708": "qlqia", + "col709": "3bnyv", + "col710": "y8ghe", + "col711": "uusta", + "col712": "7q09u", + "col713": "1dxzz", + "col714": "o6ox6", + "col715": "5d8lb", + "col716": "5ngld", + "col717": "qtgac", + "col718": "vym5a", + "col719": "fglck", + "col720": "spz2k", + "col721": "grn2j", + "col722": "dg36f", + "col723": "fx2wb", + "col724": "r1idb", + "col725": "yr4zr", + "col726": "j1zpp", + "col727": "9g5z8", + "col728": "8zje4", + "col729": "2nkwd", + "col730": "p0pua", + "col731": "wgb3r", + "col732": "l8y8l", + "col733": "l6ef7", + "col734": "qq29p", + "col735": "vxchz", + "col736": "q1k4j", + "col737": "884wq", + "col738": "okupg", + "col739": "rq8x9", + "col740": "f80cb", + "col741": "ds780", + "col742": "51m0q", + "col743": "h5jyl", + "col744": "cc568", + "col745": "pisob", + "col746": "tknic", + "col747": "iezhr", + "col748": "qoelz", + "col749": "nirk3", + "col750": "mb0ip", + "col751": "z54sz", + "col752": "ov9ta", + "col753": "23l4z", + "col754": "vqghw", + "col755": "n3af1", + "col756": "jr8yw", + "col757": "8ad50", + "col758": "q0wr7", + "col759": "rvsr1", + "col760": "d5gnf", + "col761": "2u15c", + "col762": "pu3er", + "col763": "yfd7d", + "col764": "upj9m", + "col765": "z8x0x", + "col766": "cy9wp", + "col767": "d53y6", + "col768": "vhdws", + "col769": "3fk6x", + "col770": "cxrls", + "col771": "pek6m", + "col772": "vn5cw", + "col773": "octtx", + "col774": "yhv3c", + "col775": "y66yq", + "col776": "drg3h", + "col777": "3ycfx", + "col778": "qcwve", + "col779": "21kck", + "col780": "baeov", + "col781": "qh50v", + "col782": "d3adv", + "col783": "p7cts", + "col784": "dz8oq", + "col785": "h8h98", + "col786": "ed5iw", + "col787": "cz6t7", + "col788": "dljiv", + "col789": "i9y7f", + "col790": "8l0ly", + "col791": "jzg31", + "col792": "3wp05", + "col793": "2w3t2", + "col794": "jsogv", + "col795": "uglrx", + "col796": "z6038", + "col797": "vs44q", + "col798": "6gez3", + "col799": "7tlnu", + "col800": "i26qi", + "col801": "68zul", + "col802": "hd5p1", + "col803": "489gw", + "col804": "tn9ky", + "col805": "7yi4b", + "col806": "hbhpo", + "col807": "vfh09", + "col808": "ldmh2", + "col809": "tpei2", + "col810": "eaqc7", + "col811": "xfbhs", + "col812": "5xnqp", + "col813": "k195z", + "col814": "6k4er", + "col815": "elwm7", + "col816": "msnwm", + "col817": "1b0nn", + "col818": "itbdx", + "col819": "86ato", + "col820": "1lv8r", + "col821": "rg7nd", + "col822": "89t0x", + "col823": "lp8ti", + "col824": "qer74", + "col825": "h1fqx", + "col826": "fy97l", + "col827": "fsmlx", + "col828": "75kbp", + "col829": "6bpmc", + "col830": "lhgxk", + "col831": "clg2l", + "col832": "ie387", + "col833": "hb0qc", + "col834": "w0neq", + "col835": "zb6f2", + "col836": "lj8zx", + "col837": "qkqxp", + "col838": "luuev", + "col839": "er6i3", + "col840": "4lvsh", + "col841": "6whey", + "col842": "tvs8i", + "col843": "exntd", + "col844": "ande1", + "col845": "073bz", + "col846": "txx28", + "col847": "3puip", + "col848": "r5arz", + "col849": "omcdr", + "col850": "yuhti", + "col851": "1sviq", + "col852": "p35fi", + "col853": "rsgc7", + "col854": "sln81", + "col855": "hyivd", + "col856": "q1cl0", + "col857": "jhcnr", + "col858": "6tpl9", + "col859": "ebm7r", + "col860": "ks2fg", + "col861": "4fnxw", + "col862": "c7ib4", + "col863": "koy54", + "col864": "zdvn6", + "col865": "ujys8", + "col866": "ugmrq", + "col867": "wa23g", + "col868": "6bggj", + "col869": "xlpvt", + "col870": "nft0b", + "col871": "74w1a", + "col872": "22xb8", + "col873": "w3eif", + "col874": "78r91", + "col875": "ww6oi", + "col876": "f1hwk", + "col877": "28y01", + "col878": "urlmk", + "col879": "xpzhz", + "col880": "89y57", + "col881": "j7a52", + "col882": "4pe4e", + "col883": "zv47i", + "col884": "pwzk3", + "col885": "zn5th", + "col886": "q6l0p", + "col887": "0bhbt", + "col888": "y0edq", + "col889": "cou5t", + "col890": "abnfz", + "col891": "pqypp", + "col892": "w1zl9", + "col893": "g5ddn", + "col894": "ihb9m", + "col895": "yfq3m", + "col896": "ycrga", + "col897": "o7ktk", + "col898": "39tn8", + "col899": "2kpve", + "col900": "durlm", + "col901": "7wk9s", + "col902": "w7dsq", + "col903": "21gpo", + "col904": "tpoms", + "col905": "mzzms", + "col906": "bg8r0", + "col907": "qdd82", + "col908": "o0nqv", + "col909": "3bieu", + "col910": "mpbyr", + "col911": "orxgj", + "col912": "k89aq", + "col913": "m359q", + "col914": "p769s", + "col915": "o3xl8", + "col916": "xbi2x", + "col917": "adsv6", + "col918": "fhsc1", + "col919": "cypfy", + "col920": "1k0vp", + "col921": "g86lr", + "col922": "0ce4w", + "col923": "6j6o7", + "col924": "wyb5o", + "col925": "yu3jt", + "col926": "p9bt4", + "col927": "lp08u", + "col928": "q8154", + "col929": "6o239", + "col930": "adhm5", + "col931": "t3np3", + "col932": "vucq4", + "col933": "9lse2", + "col934": "97jj7", + "col935": "3hzdk", + "col936": "7bl8k", + "col937": "ef46r", + "col938": "azxrx", + "col939": "ufu0c", + "col940": "yqiez", + "col941": "v6yil", + "col942": "93goz", + "col943": "oqnqx", + "col944": "dmlqb", + "col945": "nl86g", + "col946": "ddi6a", + "col947": "rcyyn", + "col948": "6bj78", + "col949": "vd2wy", + "col950": "qvwbx", + "col951": "xu65i", + "col952": "3nehk", + "col953": "a2oqa", + "col954": "kkdlp", + "col955": "wn03b", + "col956": "8nsuc", + "col957": "a7eub", + "col958": "dzdg8", + "col959": "bbd5o", + "col960": "a4cqj", + "col961": "lxvq1", + "col962": "fhtxv", + "col963": "kc7pw", + "col964": "ik3hp", + "col965": "8ekpv", + "col966": "irnbm", + "col967": "ngodh", + "col968": "a599h", + "col969": "6iimh", + "col970": "vtk51", + "col971": "b7qtf", + "col972": "1nmb8", + "col973": "93pyf", + "col974": "qg4ke", + "col975": "omwph", + "col976": "ho42h", + "col977": "3mtxb", + "col978": "neznw", + "col979": "8bsf4", + "col980": "veasv", + "col981": "wrgme", + "col982": "4nuch", + "col983": "f7u1l", + "col984": "xep4a", + "col985": "lj5hv", + "col986": "buvoq", + "col987": "1tuu3", + "col988": "5nibb", + "col989": "bjp1m", + "col990": "bm704", + "col991": "7ys51", + "col992": "1ahcc", + "col993": "j46t2", + "col994": "3bgbz", + "col995": "75av0", + "col996": "qe4ys", + "col997": "uu11v", + "col998": "hlgqf", + "col999": "88lwm" + }, + { + "name": "Nadine Mullins", + "gender": "female", + "col0": "xpls2", + "col1": "8ug3t", + "col2": "o93uo", + "col3": "30tqj", + "col4": "zx9vu", + "col5": "tiiln", + "col6": "1boxo", + "col7": "pf6ia", + "col8": "n3nsj", + "col9": "spnua", + "col10": "kqain", + "col11": "5216p", + "col12": "dvscj", + "col13": "gin30", + "col14": "bnw5t", + "col15": "070rs", + "col16": "600rr", + "col17": "rae40", + "col18": "lbwc7", + "col19": "fwanm", + "col20": "w4oo0", + "col21": "uljbg", + "col22": "elsmk", + "col23": "l7447", + "col24": "v8v3n", + "col25": "zg2wy", + "col26": "37fui", + "col27": "skcjp", + "col28": "gp0bp", + "col29": "nt435", + "col30": "euw91", + "col31": "2ny10", + "col32": "mbdef", + "col33": "gl8df", + "col34": "eikvz", + "col35": "3nulg", + "col36": "ylw1x", + "col37": "qlfky", + "col38": "6s7ka", + "col39": "hu8ci", + "col40": "yem4y", + "col41": "71rhq", + "col42": "5p3rw", + "col43": "t173y", + "col44": "rfnzh", + "col45": "ue4tn", + "col46": "y6wvx", + "col47": "izrzi", + "col48": "oiyfl", + "col49": "n6uhn", + "col50": "g4o2a", + "col51": "9mueq", + "col52": "3hfjm", + "col53": "3hcxf", + "col54": "g1sqz", + "col55": "ooh1p", + "col56": "usvfm", + "col57": "8f9fa", + "col58": "5yzf7", + "col59": "t6v25", + "col60": "385po", + "col61": "4q45o", + "col62": "hpi59", + "col63": "t9jb8", + "col64": "13zap", + "col65": "dq0go", + "col66": "2xi6k", + "col67": "xn32u", + "col68": "nk9zz", + "col69": "u8ozv", + "col70": "jnwp5", + "col71": "oclmq", + "col72": "q8dhk", + "col73": "fm6gh", + "col74": "67s01", + "col75": "sxnr7", + "col76": "d9ts4", + "col77": "ryifu", + "col78": "5ukpe", + "col79": "zrl9c", + "col80": "l3kx6", + "col81": "csv2f", + "col82": "mhb91", + "col83": "bqdxe", + "col84": "z2mpo", + "col85": "r7p4u", + "col86": "1c1r2", + "col87": "9j6bg", + "col88": "6v3fr", + "col89": "p6188", + "col90": "3n7po", + "col91": "58q49", + "col92": "7t5g5", + "col93": "68elq", + "col94": "ixypx", + "col95": "pw0ug", + "col96": "zjvh4", + "col97": "fx98y", + "col98": "xz9br", + "col99": "vsua5", + "col100": "zy8hk", + "col101": "9gju7", + "col102": "lwido", + "col103": "47cgp", + "col104": "yo1vz", + "col105": "2c8ml", + "col106": "pjp4d", + "col107": "swxnc", + "col108": "79op0", + "col109": "md0ud", + "col110": "uizvb", + "col111": "fj7xl", + "col112": "is7vc", + "col113": "fzso3", + "col114": "77ter", + "col115": "8plda", + "col116": "34ng1", + "col117": "yw97e", + "col118": "a3qfm", + "col119": "vb8fr", + "col120": "xtdkq", + "col121": "bx9bn", + "col122": "3c78e", + "col123": "n71uc", + "col124": "2ljn8", + "col125": "e0ati", + "col126": "4kict", + "col127": "ljqay", + "col128": "jgewu", + "col129": "cpli2", + "col130": "rp3v7", + "col131": "88nkb", + "col132": "nzag2", + "col133": "h9op7", + "col134": "wi7ty", + "col135": "s9ndv", + "col136": "kg9qz", + "col137": "bwybn", + "col138": "j0cuw", + "col139": "n1s55", + "col140": "ed58e", + "col141": "679ad", + "col142": "m47q9", + "col143": "xcx51", + "col144": "hk38c", + "col145": "0cgog", + "col146": "yiamx", + "col147": "h91aj", + "col148": "5m4y0", + "col149": "fn8nu", + "col150": "7ioek", + "col151": "gb14i", + "col152": "9xtli", + "col153": "7umei", + "col154": "ubwwb", + "col155": "qef1o", + "col156": "qan8m", + "col157": "njbvn", + "col158": "pahe4", + "col159": "dtkq7", + "col160": "81xsc", + "col161": "vgi3d", + "col162": "zvvn7", + "col163": "3r197", + "col164": "gjzj1", + "col165": "9wq83", + "col166": "fx7sc", + "col167": "gsj35", + "col168": "eijoj", + "col169": "b8we2", + "col170": "d1xt9", + "col171": "wfot2", + "col172": "i739p", + "col173": "uzxoj", + "col174": "v2ugj", + "col175": "37b28", + "col176": "angph", + "col177": "bzedj", + "col178": "jdqoq", + "col179": "uhiwb", + "col180": "pemuw", + "col181": "i3p1c", + "col182": "pjjq6", + "col183": "mhx7u", + "col184": "uxape", + "col185": "lqpoh", + "col186": "oj4zp", + "col187": "yrmbz", + "col188": "hanrc", + "col189": "xebr7", + "col190": "ttxn6", + "col191": "c9vag", + "col192": "95s1t", + "col193": "ycet1", + "col194": "6g5f5", + "col195": "eipew", + "col196": "gnxgu", + "col197": "1xmtf", + "col198": "q837m", + "col199": "7thg7", + "col200": "crg64", + "col201": "yi22u", + "col202": "89ema", + "col203": "8su21", + "col204": "c12ry", + "col205": "km301", + "col206": "8yv5b", + "col207": "3jmkp", + "col208": "1h2z1", + "col209": "e2d2l", + "col210": "hl47c", + "col211": "ekboy", + "col212": "euxjl", + "col213": "cmv3a", + "col214": "qs7ad", + "col215": "7ndnl", + "col216": "s83mp", + "col217": "7izh4", + "col218": "bbn2m", + "col219": "i9iqk", + "col220": "i6edy", + "col221": "ko80x", + "col222": "uo9j6", + "col223": "v46ya", + "col224": "z5w82", + "col225": "kaakq", + "col226": "9ud68", + "col227": "gd8oz", + "col228": "nto2r", + "col229": "g7wbl", + "col230": "if6dj", + "col231": "pda6c", + "col232": "2rfa0", + "col233": "rvhlv", + "col234": "p71we", + "col235": "rgk70", + "col236": "aia11", + "col237": "5z2e5", + "col238": "swics", + "col239": "h261j", + "col240": "fhs77", + "col241": "mcsxo", + "col242": "xs7zl", + "col243": "arsmb", + "col244": "p9l4y", + "col245": "t2s25", + "col246": "7wlo9", + "col247": "vfkj7", + "col248": "6z7r9", + "col249": "q33f8", + "col250": "4r5tt", + "col251": "nlv9m", + "col252": "d4g6l", + "col253": "op9tq", + "col254": "9j1xg", + "col255": "k4tge", + "col256": "0xan6", + "col257": "ne3k1", + "col258": "r997o", + "col259": "hhihu", + "col260": "9tnwt", + "col261": "j92tc", + "col262": "qym0j", + "col263": "mkaez", + "col264": "k8i60", + "col265": "agvpy", + "col266": "w886v", + "col267": "sc47o", + "col268": "pzl7m", + "col269": "6fu0m", + "col270": "d5jk0", + "col271": "vzk32", + "col272": "my6fl", + "col273": "m3yzk", + "col274": "9ngnr", + "col275": "nau58", + "col276": "3ii04", + "col277": "zabgy", + "col278": "y1k84", + "col279": "dkfk8", + "col280": "x0sc1", + "col281": "qhi4v", + "col282": "hbhd5", + "col283": "ljc7h", + "col284": "cam3t", + "col285": "xapih", + "col286": "bmblz", + "col287": "9s8ew", + "col288": "1hl9i", + "col289": "9q7c7", + "col290": "tq7dg", + "col291": "n7tjp", + "col292": "dtklj", + "col293": "sf4s5", + "col294": "3liwr", + "col295": "3j7rh", + "col296": "nmd0a", + "col297": "qs5kz", + "col298": "ozsjy", + "col299": "4ffwm", + "col300": "l0bs0", + "col301": "iwn6v", + "col302": "5hhb7", + "col303": "zrlqq", + "col304": "5xw2m", + "col305": "ump03", + "col306": "tetyy", + "col307": "krn5l", + "col308": "qea84", + "col309": "zejql", + "col310": "ig07q", + "col311": "a9hdz", + "col312": "j4vzw", + "col313": "76as6", + "col314": "63pag", + "col315": "y9xbc", + "col316": "sgb0e", + "col317": "h4jzu", + "col318": "sidy9", + "col319": "x7g4y", + "col320": "gsnfm", + "col321": "ckve3", + "col322": "gi2fz", + "col323": "apuzz", + "col324": "xulw8", + "col325": "0ldtb", + "col326": "mi80o", + "col327": "72x3z", + "col328": "dl1fn", + "col329": "5547b", + "col330": "r97fs", + "col331": "sbo33", + "col332": "9qgpr", + "col333": "l6wvm", + "col334": "9wqt6", + "col335": "n3pqo", + "col336": "ii0yv", + "col337": "53vo8", + "col338": "arhco", + "col339": "0o1bs", + "col340": "n881g", + "col341": "fkcah", + "col342": "9imzf", + "col343": "7qnip", + "col344": "7p6b6", + "col345": "mxc6s", + "col346": "4tbrv", + "col347": "3c778", + "col348": "q8cmv", + "col349": "78x21", + "col350": "62ih7", + "col351": "x4r3l", + "col352": "ky1as", + "col353": "m2ke0", + "col354": "haceq", + "col355": "friza", + "col356": "sy226", + "col357": "krj31", + "col358": "mzi31", + "col359": "2hj3b", + "col360": "krzst", + "col361": "c1gl7", + "col362": "h3p1d", + "col363": "gsbdm", + "col364": "exv95", + "col365": "mts5f", + "col366": "2k9i4", + "col367": "w1k0u", + "col368": "hejy2", + "col369": "zxyhw", + "col370": "6eqsc", + "col371": "c96ts", + "col372": "lck9b", + "col373": "lggz0", + "col374": "3ug4b", + "col375": "dioid", + "col376": "7sp2d", + "col377": "17bt2", + "col378": "c3lnb", + "col379": "2ao97", + "col380": "ia1v5", + "col381": "tnot6", + "col382": "3agf4", + "col383": "epohd", + "col384": "v2t3u", + "col385": "c2ub6", + "col386": "skofw", + "col387": "5nmgn", + "col388": "uolkh", + "col389": "sh4dq", + "col390": "o53oe", + "col391": "munc8", + "col392": "4qxmh", + "col393": "ubt5n", + "col394": "swxpv", + "col395": "12pzq", + "col396": "6o0ox", + "col397": "brcyy", + "col398": "nj1v6", + "col399": "opkbo", + "col400": "vjjf4", + "col401": "i94mc", + "col402": "t0vit", + "col403": "4anuw", + "col404": "a1cv4", + "col405": "18qii", + "col406": "sumg6", + "col407": "apjzf", + "col408": "ankr9", + "col409": "7bim6", + "col410": "c9jjb", + "col411": "9qgdk", + "col412": "bp0kg", + "col413": "7v3tl", + "col414": "ld4l8", + "col415": "89naz", + "col416": "e7mez", + "col417": "s0be4", + "col418": "9i1mx", + "col419": "t26a4", + "col420": "gcae3", + "col421": "0bgxc", + "col422": "sr9lf", + "col423": "tjhk6", + "col424": "33hd0", + "col425": "6x0dn", + "col426": "uwtd4", + "col427": "00sj9", + "col428": "9z4d9", + "col429": "kaymj", + "col430": "u4z21", + "col431": "8oybw", + "col432": "x9c2b", + "col433": "7wk6r", + "col434": "hjgcc", + "col435": "xonl1", + "col436": "b1pck", + "col437": "o54tc", + "col438": "m546u", + "col439": "b5dxf", + "col440": "50udq", + "col441": "fxjha", + "col442": "dlj67", + "col443": "6jv6k", + "col444": "aeg2t", + "col445": "7qrfv", + "col446": "dqkl8", + "col447": "5d2yr", + "col448": "hw0zu", + "col449": "jtxih", + "col450": "livjb", + "col451": "6iwyb", + "col452": "3tjuu", + "col453": "785kj", + "col454": "vyh4d", + "col455": "j9hqf", + "col456": "mwjty", + "col457": "igflk", + "col458": "blt4h", + "col459": "6pfjf", + "col460": "4uztn", + "col461": "vjo3q", + "col462": "3gd15", + "col463": "fyb0z", + "col464": "tkkd4", + "col465": "0ovdo", + "col466": "i20db", + "col467": "bvv1x", + "col468": "eo206", + "col469": "as5am", + "col470": "9pgfq", + "col471": "xh3gb", + "col472": "iy5uu", + "col473": "dbc85", + "col474": "9galg", + "col475": "y4eni", + "col476": "6rnm3", + "col477": "vwinx", + "col478": "jzo1n", + "col479": "fbzh5", + "col480": "d70uf", + "col481": "q9ths", + "col482": "7orme", + "col483": "prw6d", + "col484": "rk6ty", + "col485": "o3xvc", + "col486": "3v5di", + "col487": "kmrgm", + "col488": "vi0pt", + "col489": "a9552", + "col490": "tmjja", + "col491": "xdls1", + "col492": "oduhb", + "col493": "9es5f", + "col494": "wursy", + "col495": "mz0kj", + "col496": "9fac4", + "col497": "khx7q", + "col498": "1qzbj", + "col499": "q3c6a", + "col500": "aq9mp", + "col501": "b8oez", + "col502": "x1c1g", + "col503": "dvf2a", + "col504": "imem6", + "col505": "bfxg8", + "col506": "w020r", + "col507": "0gxog", + "col508": "y100y", + "col509": "ibz33", + "col510": "qqreu", + "col511": "mg8km", + "col512": "jh227", + "col513": "p82hz", + "col514": "zjq28", + "col515": "eys45", + "col516": "br3td", + "col517": "de1bt", + "col518": "16t3z", + "col519": "epuai", + "col520": "0a8ml", + "col521": "phyxl", + "col522": "qld1t", + "col523": "2lo59", + "col524": "36kj5", + "col525": "rbg37", + "col526": "f1ted", + "col527": "yv0ui", + "col528": "33bs8", + "col529": "k69l7", + "col530": "rsxzb", + "col531": "8luan", + "col532": "eqdcm", + "col533": "du9kp", + "col534": "me47q", + "col535": "bt697", + "col536": "g8u1k", + "col537": "ag0ky", + "col538": "ajz5q", + "col539": "8v3vz", + "col540": "6lrw2", + "col541": "lmz92", + "col542": "rrk5w", + "col543": "sw1tg", + "col544": "gnz57", + "col545": "ihk5s", + "col546": "ik5n0", + "col547": "uh1kl", + "col548": "l7s0t", + "col549": "1w93y", + "col550": "c8gn3", + "col551": "nr5yi", + "col552": "5avfa", + "col553": "u12gt", + "col554": "m5bkg", + "col555": "xn3ef", + "col556": "3tslr", + "col557": "r8mt2", + "col558": "we5wm", + "col559": "08f2e", + "col560": "jib68", + "col561": "nh511", + "col562": "gtl4w", + "col563": "xpmsf", + "col564": "irmdv", + "col565": "0elb6", + "col566": "mzkl2", + "col567": "azy4s", + "col568": "ubh4n", + "col569": "whjhd", + "col570": "73jf3", + "col571": "nlylm", + "col572": "ryqqw", + "col573": "q7bbv", + "col574": "4jv87", + "col575": "z9ryc", + "col576": "v8oa8", + "col577": "tffcy", + "col578": "5linx", + "col579": "bsqdv", + "col580": "grt6u", + "col581": "jjemn", + "col582": "a1nf6", + "col583": "jl0p2", + "col584": "uv334", + "col585": "05wm9", + "col586": "wrs9q", + "col587": "45rq4", + "col588": "arezt", + "col589": "nuvma", + "col590": "cfxap", + "col591": "33czw", + "col592": "sz9nw", + "col593": "2gzui", + "col594": "dgxka", + "col595": "6j7sd", + "col596": "34crt", + "col597": "1re5u", + "col598": "nkefm", + "col599": "c36db", + "col600": "m4y3z", + "col601": "1zxq7", + "col602": "cikor", + "col603": "008rf", + "col604": "8ewl0", + "col605": "briac", + "col606": "osf59", + "col607": "dlzfo", + "col608": "qeatf", + "col609": "pvpz2", + "col610": "iimus", + "col611": "kniat", + "col612": "g001r", + "col613": "3hscv", + "col614": "qvjuw", + "col615": "6yef4", + "col616": "ho36i", + "col617": "onylh", + "col618": "wb8i2", + "col619": "pxynr", + "col620": "hh8qn", + "col621": "hy57v", + "col622": "yt165", + "col623": "t2ttc", + "col624": "pmczd", + "col625": "xhpgr", + "col626": "ajyfe", + "col627": "5931j", + "col628": "rz84l", + "col629": "k0yhg", + "col630": "w3o44", + "col631": "gaup8", + "col632": "tfojj", + "col633": "sxuxp", + "col634": "73tpc", + "col635": "6lmbn", + "col636": "pe7ie", + "col637": "vphuj", + "col638": "are09", + "col639": "rdx8x", + "col640": "0ysk6", + "col641": "jq7w2", + "col642": "k5qkl", + "col643": "kya56", + "col644": "cgzqa", + "col645": "f8168", + "col646": "ejp3s", + "col647": "9gsme", + "col648": "7g12z", + "col649": "4wyob", + "col650": "hhalg", + "col651": "16ipu", + "col652": "k76pn", + "col653": "023rf", + "col654": "akfrl", + "col655": "hggiq", + "col656": "anz70", + "col657": "rg25x", + "col658": "sgiht", + "col659": "539ib", + "col660": "3scvs", + "col661": "rh0ce", + "col662": "lwxhz", + "col663": "mg9os", + "col664": "n59u6", + "col665": "rzmlg", + "col666": "ca0di", + "col667": "9f617", + "col668": "wo0gc", + "col669": "022b0", + "col670": "wh8mn", + "col671": "aj424", + "col672": "cvoin", + "col673": "nbeud", + "col674": "4zuxv", + "col675": "gf6ya", + "col676": "apkcy", + "col677": "c7gls", + "col678": "pth8v", + "col679": "iw2vf", + "col680": "w7hgf", + "col681": "f53dt", + "col682": "duquc", + "col683": "gfd2f", + "col684": "iyylf", + "col685": "llg2q", + "col686": "mpjcw", + "col687": "8tzyh", + "col688": "or4l1", + "col689": "3bq17", + "col690": "wulpm", + "col691": "2xpc9", + "col692": "5e1fp", + "col693": "2q0ex", + "col694": "olzw6", + "col695": "ggbho", + "col696": "2abqk", + "col697": "suoqi", + "col698": "njq0a", + "col699": "sbl89", + "col700": "ynxg7", + "col701": "lphu4", + "col702": "rsbaa", + "col703": "te8qv", + "col704": "oeuo4", + "col705": "3oaam", + "col706": "c31yy", + "col707": "uvh75", + "col708": "fg4o8", + "col709": "nl8fg", + "col710": "7ztwq", + "col711": "hkh2i", + "col712": "vlc1z", + "col713": "jne1n", + "col714": "cdcgq", + "col715": "6ftxe", + "col716": "lwinl", + "col717": "0uoj2", + "col718": "zxij2", + "col719": "703kr", + "col720": "yhkdt", + "col721": "pa1ns", + "col722": "4inuz", + "col723": "ga6lt", + "col724": "wxp0x", + "col725": "lwybp", + "col726": "gg20p", + "col727": "uyywi", + "col728": "48hh3", + "col729": "oy2cn", + "col730": "ov65l", + "col731": "v3raq", + "col732": "cshs1", + "col733": "20ayn", + "col734": "c89j3", + "col735": "bc06h", + "col736": "6u5g9", + "col737": "1tloq", + "col738": "zbw2g", + "col739": "w1bg9", + "col740": "bksyu", + "col741": "7la8f", + "col742": "90gf8", + "col743": "mvcr8", + "col744": "kbjg5", + "col745": "5uej4", + "col746": "xqdw2", + "col747": "tlw7q", + "col748": "wohtj", + "col749": "9nbyp", + "col750": "2w15o", + "col751": "jr83t", + "col752": "2nkue", + "col753": "sw2ps", + "col754": "iu09t", + "col755": "pm9uj", + "col756": "lgq3o", + "col757": "bln45", + "col758": "k6plt", + "col759": "e27fs", + "col760": "1yf22", + "col761": "igibr", + "col762": "uuxil", + "col763": "gn5yf", + "col764": "yh4al", + "col765": "qikyq", + "col766": "1bla5", + "col767": "zho7u", + "col768": "kxiot", + "col769": "la0zw", + "col770": "2fmg1", + "col771": "no1b9", + "col772": "34nkw", + "col773": "izneq", + "col774": "bprh9", + "col775": "ocjht", + "col776": "wewid", + "col777": "8bacd", + "col778": "say2s", + "col779": "up8bk", + "col780": "8jkzy", + "col781": "qmju1", + "col782": "lmhjf", + "col783": "1s7od", + "col784": "t7oeu", + "col785": "46qz3", + "col786": "v3tiz", + "col787": "c1n2u", + "col788": "uskel", + "col789": "yc2zy", + "col790": "0w9kr", + "col791": "bwh33", + "col792": "9lj8i", + "col793": "yq408", + "col794": "191p2", + "col795": "2x93b", + "col796": "xmz1p", + "col797": "msfi2", + "col798": "cle0d", + "col799": "r5fs5", + "col800": "pcxiq", + "col801": "rz0lz", + "col802": "t3s9c", + "col803": "wi5de", + "col804": "hdpna", + "col805": "czzg4", + "col806": "tzdb4", + "col807": "rkbw1", + "col808": "azwy1", + "col809": "y3rlq", + "col810": "f0gfz", + "col811": "n4yvx", + "col812": "z9zc4", + "col813": "l9rsw", + "col814": "mgbnk", + "col815": "r4827", + "col816": "585sy", + "col817": "3qfo1", + "col818": "ku7y6", + "col819": "n44vg", + "col820": "nv7xh", + "col821": "91ckd", + "col822": "8ledi", + "col823": "i33nj", + "col824": "pagfv", + "col825": "zr8me", + "col826": "t7v3s", + "col827": "qzb0t", + "col828": "e5fh7", + "col829": "wjaph", + "col830": "edjr7", + "col831": "h1vwv", + "col832": "912h0", + "col833": "a60zf", + "col834": "qfgif", + "col835": "f6ggq", + "col836": "9xqbb", + "col837": "obthv", + "col838": "n164c", + "col839": "cr7rr", + "col840": "7uvxy", + "col841": "z66ir", + "col842": "xs453", + "col843": "w072l", + "col844": "hic3u", + "col845": "gnj3h", + "col846": "pjlr8", + "col847": "g7ieh", + "col848": "y5c4x", + "col849": "whwx9", + "col850": "ornm3", + "col851": "d0ldc", + "col852": "bol0c", + "col853": "3yaqv", + "col854": "92x7r", + "col855": "e1yyc", + "col856": "meotz", + "col857": "u0mkj", + "col858": "zi4ji", + "col859": "2s3t2", + "col860": "fcwo0", + "col861": "75aoc", + "col862": "4nmuo", + "col863": "8649c", + "col864": "aavk5", + "col865": "qidtz", + "col866": "h9fg5", + "col867": "n9pf1", + "col868": "eiaed", + "col869": "8zxf0", + "col870": "yuvb0", + "col871": "vm421", + "col872": "cesxu", + "col873": "6ll3o", + "col874": "tdrlr", + "col875": "b60s4", + "col876": "cn6mj", + "col877": "6cvju", + "col878": "d9wln", + "col879": "d9mgm", + "col880": "io214", + "col881": "0h1wg", + "col882": "54c22", + "col883": "pmdx6", + "col884": "yc7rf", + "col885": "sp5au", + "col886": "rfhyf", + "col887": "egy7r", + "col888": "935ur", + "col889": "g0vla", + "col890": "cfnu7", + "col891": "6w2b1", + "col892": "lcjpr", + "col893": "hgb0i", + "col894": "lalik", + "col895": "tncqh", + "col896": "azcto", + "col897": "6hxpo", + "col898": "aj089", + "col899": "oxrzv", + "col900": "4zxyy", + "col901": "2lauz", + "col902": "yzs4e", + "col903": "mmbqd", + "col904": "ccre7", + "col905": "1o14x", + "col906": "k4vnr", + "col907": "ntqp6", + "col908": "nxfee", + "col909": "z0occ", + "col910": "rbjua", + "col911": "zlunw", + "col912": "72hhn", + "col913": "1i1m2", + "col914": "vd40q", + "col915": "237y3", + "col916": "4e9l2", + "col917": "vw2q5", + "col918": "ufcei", + "col919": "poziz", + "col920": "3du7w", + "col921": "m4h35", + "col922": "lkny8", + "col923": "30x68", + "col924": "idrru", + "col925": "31zoc", + "col926": "4gxwb", + "col927": "yatgn", + "col928": "wmxce", + "col929": "ux9e7", + "col930": "4hqzt", + "col931": "6k26m", + "col932": "a9wio", + "col933": "4q3hf", + "col934": "69bt3", + "col935": "ebpfd", + "col936": "yt3cv", + "col937": "b9x62", + "col938": "o4edk", + "col939": "ataox", + "col940": "tfn84", + "col941": "7c0f6", + "col942": "8wvgs", + "col943": "wjq04", + "col944": "uaiqz", + "col945": "c54l9", + "col946": "erdkc", + "col947": "cpije", + "col948": "bbwha", + "col949": "ss6dq", + "col950": "lbp9i", + "col951": "6dcnx", + "col952": "4lleb", + "col953": "xzzpq", + "col954": "41brp", + "col955": "32cyv", + "col956": "3noq9", + "col957": "824c2", + "col958": "vwpb6", + "col959": "l4gaq", + "col960": "fhv3t", + "col961": "z5zkz", + "col962": "z4w57", + "col963": "l0rqw", + "col964": "dv3wi", + "col965": "dq4gc", + "col966": "hankl", + "col967": "wjr9g", + "col968": "boob7", + "col969": "q3eou", + "col970": "mo3rb", + "col971": "ia6a1", + "col972": "dizte", + "col973": "idycf", + "col974": "u7ia9", + "col975": "9iyhx", + "col976": "fvl9g", + "col977": "t4i5f", + "col978": "ziad4", + "col979": "j87r6", + "col980": "3ir34", + "col981": "pnqcy", + "col982": "o21pa", + "col983": "8cbz9", + "col984": "zjaga", + "col985": "pi5oq", + "col986": "0bsxo", + "col987": "gxo5p", + "col988": "ugtf5", + "col989": "uw9a7", + "col990": "yh6di", + "col991": "tme9b", + "col992": "98tvf", + "col993": "8iaxx", + "col994": "ctfee", + "col995": "9ik54", + "col996": "ke01o", + "col997": "4cu7g", + "col998": "qr308", + "col999": "gpydn" + }, + { + "name": "Mcmillan Kirby", + "gender": "male", + "col0": "08qqo", + "col1": "5s1tk", + "col2": "d9919", + "col3": "8dfhn", + "col4": "imtp2", + "col5": "h8wdy", + "col6": "7y0ia", + "col7": "ptqui", + "col8": "rn933", + "col9": "ubhh1", + "col10": "14oo1", + "col11": "vanqc", + "col12": "zqz50", + "col13": "xhvyb", + "col14": "ptu5i", + "col15": "s0hp9", + "col16": "k6a51", + "col17": "r813h", + "col18": "2vmle", + "col19": "zr3gt", + "col20": "lbshg", + "col21": "wjfh0", + "col22": "jnqcs", + "col23": "5s845", + "col24": "ef9ks", + "col25": "2y3e4", + "col26": "tegcu", + "col27": "he2v3", + "col28": "fbmlw", + "col29": "hoerm", + "col30": "p5zwa", + "col31": "gp456", + "col32": "dlisg", + "col33": "1qvsb", + "col34": "zxxrw", + "col35": "uihwh", + "col36": "hv8qh", + "col37": "2wm0f", + "col38": "01odi", + "col39": "8g0j7", + "col40": "fg6k8", + "col41": "iz8ny", + "col42": "xry0h", + "col43": "gohcq", + "col44": "xul2j", + "col45": "vlgxj", + "col46": "2dlv4", + "col47": "n90p4", + "col48": "bidp7", + "col49": "9kbac", + "col50": "5uk4z", + "col51": "y0lmx", + "col52": "rjtkk", + "col53": "i77vv", + "col54": "7tp2m", + "col55": "5es4e", + "col56": "s0x9p", + "col57": "gsqn2", + "col58": "9ecmu", + "col59": "2gi2m", + "col60": "o4jje", + "col61": "k17c0", + "col62": "rk0fl", + "col63": "a212n", + "col64": "hha4v", + "col65": "b0bwu", + "col66": "q2z40", + "col67": "53rkc", + "col68": "to4hl", + "col69": "huzev", + "col70": "14gcv", + "col71": "mwdgq", + "col72": "xkh9x", + "col73": "05tl2", + "col74": "6sgmw", + "col75": "jjlwc", + "col76": "jppzt", + "col77": "2y1zz", + "col78": "ibvo1", + "col79": "rcbvv", + "col80": "0gjwk", + "col81": "w1sny", + "col82": "0snty", + "col83": "1z5pk", + "col84": "nn5h2", + "col85": "3dqkw", + "col86": "2cdkv", + "col87": "mm43p", + "col88": "pxjrx", + "col89": "4xfvc", + "col90": "yzom7", + "col91": "y6csv", + "col92": "eo9my", + "col93": "gwhuk", + "col94": "zt80h", + "col95": "j9noq", + "col96": "duhbo", + "col97": "5zt1u", + "col98": "a8ts2", + "col99": "v084r", + "col100": "9gq83", + "col101": "cwggr", + "col102": "01y5q", + "col103": "xq0bv", + "col104": "ttqbx", + "col105": "42a2q", + "col106": "x9w0f", + "col107": "h8f85", + "col108": "pmrln", + "col109": "7eusk", + "col110": "d9xyh", + "col111": "058ro", + "col112": "unwp7", + "col113": "ulqhd", + "col114": "4xizm", + "col115": "ji2hy", + "col116": "kqaza", + "col117": "p2o47", + "col118": "y4jpi", + "col119": "60dmh", + "col120": "ywzrf", + "col121": "be8g2", + "col122": "yspwg", + "col123": "y3n8l", + "col124": "7gjd3", + "col125": "7ci1a", + "col126": "brkuz", + "col127": "dl4a3", + "col128": "5kvcy", + "col129": "6sqyx", + "col130": "shm84", + "col131": "8w7f4", + "col132": "8mbsg", + "col133": "lte9u", + "col134": "4j1uo", + "col135": "0xssf", + "col136": "x1bxp", + "col137": "xl03o", + "col138": "m04qn", + "col139": "6sv8g", + "col140": "cwbrt", + "col141": "yjflq", + "col142": "1u8wr", + "col143": "ho9k7", + "col144": "kmunr", + "col145": "0zrlk", + "col146": "fq8sc", + "col147": "mgqkf", + "col148": "pdqgy", + "col149": "dqkry", + "col150": "08qpk", + "col151": "pw4el", + "col152": "0zwzl", + "col153": "zj6l1", + "col154": "k6a78", + "col155": "fwkoo", + "col156": "7e30w", + "col157": "mmhaj", + "col158": "cyiyl", + "col159": "dodbo", + "col160": "l6lwg", + "col161": "ji05e", + "col162": "iloib", + "col163": "bnk72", + "col164": "548ay", + "col165": "my4l9", + "col166": "hzv7s", + "col167": "4l6fi", + "col168": "dz7wt", + "col169": "bhhre", + "col170": "na8ku", + "col171": "0xkc2", + "col172": "2d0yv", + "col173": "j4xfz", + "col174": "hine2", + "col175": "g936t", + "col176": "61yn6", + "col177": "42swj", + "col178": "m7l6u", + "col179": "sqg3o", + "col180": "a2aep", + "col181": "6t0nb", + "col182": "mvyvs", + "col183": "qy3yv", + "col184": "dqat7", + "col185": "6nsja", + "col186": "ufvni", + "col187": "u5c2q", + "col188": "oqu1g", + "col189": "so0zg", + "col190": "slyjr", + "col191": "eq9p7", + "col192": "2pxqs", + "col193": "80br3", + "col194": "pqvki", + "col195": "1apl8", + "col196": "nz9ut", + "col197": "b6m4t", + "col198": "j8ywv", + "col199": "0lpxq", + "col200": "36sxi", + "col201": "y6yn4", + "col202": "lg1y0", + "col203": "f57m2", + "col204": "o69f3", + "col205": "9e844", + "col206": "m6cie", + "col207": "ccr0o", + "col208": "41x3b", + "col209": "k737f", + "col210": "p6i89", + "col211": "bbjs5", + "col212": "0lovo", + "col213": "rt40b", + "col214": "5kama", + "col215": "v4hqm", + "col216": "tpj4x", + "col217": "hsfra", + "col218": "pq7uq", + "col219": "p93n2", + "col220": "tacxx", + "col221": "xtbbt", + "col222": "m9k4t", + "col223": "4bktr", + "col224": "kbhyr", + "col225": "t55jo", + "col226": "pjwnh", + "col227": "rw8kh", + "col228": "bym8v", + "col229": "59n4v", + "col230": "qg1to", + "col231": "6v8ps", + "col232": "unjl6", + "col233": "pwuso", + "col234": "icz45", + "col235": "ywr7y", + "col236": "xd8un", + "col237": "p6gnz", + "col238": "zxq54", + "col239": "3njtu", + "col240": "rcvl3", + "col241": "rxk0b", + "col242": "bw7bv", + "col243": "i3m4u", + "col244": "xjrtn", + "col245": "fwfsq", + "col246": "fd8e2", + "col247": "7bzkv", + "col248": "fwbos", + "col249": "caw37", + "col250": "2ah1k", + "col251": "yctc8", + "col252": "pab1k", + "col253": "jfym2", + "col254": "3wkkh", + "col255": "m1ktr", + "col256": "w7wln", + "col257": "zwjt1", + "col258": "ac5nz", + "col259": "g3ulm", + "col260": "y1a1m", + "col261": "t9c9y", + "col262": "t7lgk", + "col263": "0630k", + "col264": "9mrgj", + "col265": "0rqwv", + "col266": "mxq62", + "col267": "8kunr", + "col268": "0fq0d", + "col269": "18iw5", + "col270": "hvfji", + "col271": "fl7o5", + "col272": "hoibr", + "col273": "0x52d", + "col274": "vyyhh", + "col275": "vi4uu", + "col276": "zzzrs", + "col277": "no6vd", + "col278": "88qdb", + "col279": "yjdnf", + "col280": "iz3pg", + "col281": "wfr9w", + "col282": "bgbfp", + "col283": "fl4ck", + "col284": "6pxyf", + "col285": "bkmnd", + "col286": "d69o6", + "col287": "6av0e", + "col288": "53xzw", + "col289": "3zfeo", + "col290": "ig990", + "col291": "dyd8y", + "col292": "0ocow", + "col293": "n5k93", + "col294": "515tg", + "col295": "asdod", + "col296": "4ez7y", + "col297": "c7wc5", + "col298": "8tg4l", + "col299": "cuijn", + "col300": "vpm6w", + "col301": "xzvgq", + "col302": "2fb5f", + "col303": "x739f", + "col304": "gdgrh", + "col305": "xm794", + "col306": "cmwvj", + "col307": "dkxgn", + "col308": "fygdm", + "col309": "flqar", + "col310": "yiti5", + "col311": "rz2om", + "col312": "usief", + "col313": "3n9hp", + "col314": "vwjz9", + "col315": "y6exk", + "col316": "nulvw", + "col317": "911o9", + "col318": "ekllk", + "col319": "he99d", + "col320": "b3ay7", + "col321": "c6hlm", + "col322": "pj7g5", + "col323": "gshoo", + "col324": "eopq1", + "col325": "qx5sn", + "col326": "2njgy", + "col327": "kumbi", + "col328": "wnu54", + "col329": "ybkdk", + "col330": "sfsd6", + "col331": "910o8", + "col332": "8bkty", + "col333": "oyzq6", + "col334": "epwov", + "col335": "jgn15", + "col336": "prlst", + "col337": "5uh5j", + "col338": "qurib", + "col339": "4m2uu", + "col340": "7o6ao", + "col341": "43hx8", + "col342": "twk9b", + "col343": "h5g06", + "col344": "fzhhm", + "col345": "q5pxt", + "col346": "cs77j", + "col347": "43q3z", + "col348": "59rv0", + "col349": "hhzlz", + "col350": "b16eo", + "col351": "t3168", + "col352": "vfz50", + "col353": "coycz", + "col354": "fedr2", + "col355": "98t6j", + "col356": "ui8t5", + "col357": "yu8gg", + "col358": "efxtw", + "col359": "arff4", + "col360": "y92rt", + "col361": "k3har", + "col362": "hnjpg", + "col363": "mq91v", + "col364": "jzsgp", + "col365": "yhqwz", + "col366": "9ljaf", + "col367": "k2x7x", + "col368": "u9sj3", + "col369": "7b7ic", + "col370": "1zz7b", + "col371": "f1i4k", + "col372": "ynidx", + "col373": "4s2a7", + "col374": "trill", + "col375": "2tzb8", + "col376": "0ctnt", + "col377": "skkfw", + "col378": "t7vm8", + "col379": "rhg4g", + "col380": "0ceap", + "col381": "zmvzk", + "col382": "k0lah", + "col383": "q13zk", + "col384": "xkeri", + "col385": "rv54w", + "col386": "i1tic", + "col387": "w3pvf", + "col388": "na1tj", + "col389": "49lhz", + "col390": "dxgxo", + "col391": "x3owz", + "col392": "q4dtp", + "col393": "6g4nw", + "col394": "h8ub2", + "col395": "c2owo", + "col396": "0hoot", + "col397": "qg5yc", + "col398": "bbs32", + "col399": "awae1", + "col400": "q6bfa", + "col401": "gysfd", + "col402": "5cliw", + "col403": "6fknd", + "col404": "pxfja", + "col405": "yrvdr", + "col406": "1o04p", + "col407": "gclrs", + "col408": "49ihu", + "col409": "ir5jb", + "col410": "t9599", + "col411": "e4zn4", + "col412": "9wozx", + "col413": "12875", + "col414": "4xo9o", + "col415": "ejnno", + "col416": "1kth0", + "col417": "w7n2a", + "col418": "a7w0s", + "col419": "wwmoi", + "col420": "5n5m7", + "col421": "uftn0", + "col422": "hbg1u", + "col423": "clo7c", + "col424": "b8wy1", + "col425": "hjfi2", + "col426": "mxr8t", + "col427": "sb6vc", + "col428": "tnxyq", + "col429": "b0exj", + "col430": "60zaj", + "col431": "zprot", + "col432": "127ou", + "col433": "4lo2e", + "col434": "n96ng", + "col435": "cwk7b", + "col436": "fksas", + "col437": "8yhuu", + "col438": "hdxwo", + "col439": "2ynvf", + "col440": "xbjot", + "col441": "c0hyh", + "col442": "lul6h", + "col443": "6n2fw", + "col444": "18i6i", + "col445": "phomk", + "col446": "crjth", + "col447": "k4jf4", + "col448": "v9ftf", + "col449": "i5yy5", + "col450": "9fh0l", + "col451": "rghhu", + "col452": "1ymkk", + "col453": "ekiw4", + "col454": "qby55", + "col455": "h5ouc", + "col456": "yywkl", + "col457": "8mla9", + "col458": "n3t79", + "col459": "3uy94", + "col460": "aetbn", + "col461": "k7w4z", + "col462": "hehgb", + "col463": "wnamc", + "col464": "lvdw1", + "col465": "mx2gk", + "col466": "x6l40", + "col467": "d3umt", + "col468": "gr103", + "col469": "ygzrb", + "col470": "ev85a", + "col471": "m8nvg", + "col472": "ctyxz", + "col473": "bf3kc", + "col474": "4t0qr", + "col475": "ojoc0", + "col476": "ummha", + "col477": "c0ixp", + "col478": "smjo5", + "col479": "9stx3", + "col480": "ecao1", + "col481": "xvcwy", + "col482": "qeugu", + "col483": "c1aim", + "col484": "wyi1m", + "col485": "g76nf", + "col486": "tnewl", + "col487": "ynk3v", + "col488": "xy3w6", + "col489": "2d812", + "col490": "vmikr", + "col491": "t4g7p", + "col492": "tuz2v", + "col493": "32szs", + "col494": "zrf8r", + "col495": "zh6r7", + "col496": "j1o3w", + "col497": "8z05o", + "col498": "rc0m8", + "col499": "1bo6p", + "col500": "c9ms4", + "col501": "jqoz5", + "col502": "c7p76", + "col503": "zrr6e", + "col504": "dlw3f", + "col505": "pb2v4", + "col506": "5qzhg", + "col507": "0n9yk", + "col508": "gbp24", + "col509": "cr6uz", + "col510": "ygi7i", + "col511": "jtxi8", + "col512": "oi3tl", + "col513": "68nk3", + "col514": "ihfh6", + "col515": "jwdv7", + "col516": "c8vnf", + "col517": "g1aij", + "col518": "4q7wv", + "col519": "w38sh", + "col520": "m9j4k", + "col521": "77uj1", + "col522": "0f6bb", + "col523": "fbxnn", + "col524": "8lstj", + "col525": "ypi31", + "col526": "3rpel", + "col527": "f2mw2", + "col528": "7u8sx", + "col529": "a5247", + "col530": "79tv6", + "col531": "qanwf", + "col532": "29z8b", + "col533": "ux2t4", + "col534": "nq7mn", + "col535": "hncc0", + "col536": "vd2r9", + "col537": "p0vqi", + "col538": "hrzeg", + "col539": "3o5ka", + "col540": "ehajk", + "col541": "351uz", + "col542": "xsyj4", + "col543": "eapph", + "col544": "tjsh2", + "col545": "x8epr", + "col546": "cgj8j", + "col547": "8ssny", + "col548": "aov9r", + "col549": "2u9fr", + "col550": "u2mcd", + "col551": "mfp0v", + "col552": "bf8ym", + "col553": "ksxpa", + "col554": "art9p", + "col555": "nadkn", + "col556": "mg90x", + "col557": "l0pj6", + "col558": "dpdet", + "col559": "dsbhk", + "col560": "qc69z", + "col561": "yep4s", + "col562": "cp88w", + "col563": "nnsmh", + "col564": "ji17q", + "col565": "pychj", + "col566": "c2qqp", + "col567": "uisuq", + "col568": "a90dl", + "col569": "a5afj", + "col570": "mwmys", + "col571": "f1o9u", + "col572": "pbxuq", + "col573": "e5zjg", + "col574": "z61xt", + "col575": "iub4p", + "col576": "ivk3f", + "col577": "qavgg", + "col578": "w8zd9", + "col579": "y3u6h", + "col580": "k2ibp", + "col581": "8tm8a", + "col582": "7evs7", + "col583": "snyrx", + "col584": "m4wqm", + "col585": "xg6el", + "col586": "hrz9p", + "col587": "9eaeq", + "col588": "w2krn", + "col589": "opxap", + "col590": "eiztg", + "col591": "88ytl", + "col592": "kzi5e", + "col593": "r0gn0", + "col594": "aohrv", + "col595": "po9oy", + "col596": "ri6ju", + "col597": "qoa4c", + "col598": "06sax", + "col599": "np1kd", + "col600": "2w8aq", + "col601": "tgs9i", + "col602": "r8idj", + "col603": "xqzn1", + "col604": "f7n7l", + "col605": "zq632", + "col606": "8g8ct", + "col607": "xp89d", + "col608": "blqh3", + "col609": "lv19m", + "col610": "le54u", + "col611": "ckb2s", + "col612": "75wc1", + "col613": "ehwb5", + "col614": "1biig", + "col615": "myzez", + "col616": "o336o", + "col617": "kj6mw", + "col618": "q7l2l", + "col619": "rh7ep", + "col620": "7zuf6", + "col621": "crld9", + "col622": "wtddz", + "col623": "ylz6v", + "col624": "xut6b", + "col625": "xzmeg", + "col626": "qkkpn", + "col627": "eiqgs", + "col628": "4pj5j", + "col629": "6uy9o", + "col630": "7zqof", + "col631": "68qlo", + "col632": "oowi2", + "col633": "6xmaa", + "col634": "0na0b", + "col635": "5qxhk", + "col636": "jqc6a", + "col637": "tsmnt", + "col638": "whkwa", + "col639": "wwxyt", + "col640": "sgeoo", + "col641": "ybbgo", + "col642": "s87ha", + "col643": "y64lp", + "col644": "la1ow", + "col645": "7rk1i", + "col646": "77wx8", + "col647": "n4361", + "col648": "cjgzu", + "col649": "x4ah5", + "col650": "xugry", + "col651": "byal9", + "col652": "8rcqn", + "col653": "g8hdh", + "col654": "1dzl8", + "col655": "ko76f", + "col656": "v0i1b", + "col657": "c9xot", + "col658": "nofs9", + "col659": "qmkiw", + "col660": "2e30d", + "col661": "arozy", + "col662": "2bpf4", + "col663": "kt3mz", + "col664": "852c7", + "col665": "wujg7", + "col666": "v3xcj", + "col667": "kt3ok", + "col668": "8n1mu", + "col669": "iytww", + "col670": "8m4l5", + "col671": "jp9rc", + "col672": "g0h5i", + "col673": "x5e4z", + "col674": "k1y8j", + "col675": "ahf0l", + "col676": "p8e03", + "col677": "xpv2x", + "col678": "53djr", + "col679": "gxlkn", + "col680": "z6be4", + "col681": "r1mrt", + "col682": "nbw40", + "col683": "2va02", + "col684": "kko9c", + "col685": "dqnk0", + "col686": "x5y2w", + "col687": "9yqti", + "col688": "vdl9g", + "col689": "49bd6", + "col690": "en4di", + "col691": "7e90r", + "col692": "kj90g", + "col693": "9s6at", + "col694": "n9xun", + "col695": "1f656", + "col696": "vbtku", + "col697": "xm9ys", + "col698": "ax2jz", + "col699": "wvnfx", + "col700": "fhgj1", + "col701": "nkt5m", + "col702": "y5nj8", + "col703": "f5kev", + "col704": "icxqe", + "col705": "f7q2v", + "col706": "i0r5q", + "col707": "vk7hi", + "col708": "g3nhi", + "col709": "92fey", + "col710": "q11rn", + "col711": "gbrgv", + "col712": "1ed6y", + "col713": "ldjd5", + "col714": "r7wwh", + "col715": "id3py", + "col716": "ayb8y", + "col717": "czw66", + "col718": "o1hwx", + "col719": "p68rj", + "col720": "8c4wr", + "col721": "rjn4q", + "col722": "xpwp2", + "col723": "sbl7f", + "col724": "rgna2", + "col725": "aiexj", + "col726": "1q7yz", + "col727": "zda0u", + "col728": "4lxwi", + "col729": "494mu", + "col730": "4ri84", + "col731": "pq29e", + "col732": "kuhk6", + "col733": "2bii7", + "col734": "hts5y", + "col735": "5qxdl", + "col736": "wx3hu", + "col737": "vt5ra", + "col738": "vbcfa", + "col739": "ulr57", + "col740": "p6rsl", + "col741": "88oed", + "col742": "mewqy", + "col743": "savuh", + "col744": "2vlyc", + "col745": "rnom9", + "col746": "7sypj", + "col747": "gq7vz", + "col748": "rhjqt", + "col749": "3iqnx", + "col750": "wzb5b", + "col751": "si1vu", + "col752": "dhvlo", + "col753": "f1u6p", + "col754": "f31lc", + "col755": "e686s", + "col756": "gaitb", + "col757": "dpzw7", + "col758": "um5g3", + "col759": "wmzgj", + "col760": "0k06f", + "col761": "05lni", + "col762": "f8xvb", + "col763": "krqb8", + "col764": "qlk3q", + "col765": "67gyz", + "col766": "2uh9u", + "col767": "rux3d", + "col768": "yo8bn", + "col769": "ormht", + "col770": "1y06x", + "col771": "o55sk", + "col772": "el23b", + "col773": "ul868", + "col774": "e1xm7", + "col775": "xf9ps", + "col776": "482zu", + "col777": "xcmaq", + "col778": "eeeuh", + "col779": "jepwh", + "col780": "o0wlk", + "col781": "0eyxu", + "col782": "a2ope", + "col783": "drzbg", + "col784": "67qiz", + "col785": "yb2zg", + "col786": "dq3d6", + "col787": "ag6el", + "col788": "pojd3", + "col789": "6ei3y", + "col790": "zg8jm", + "col791": "zk89h", + "col792": "z6w17", + "col793": "tfzmo", + "col794": "et66e", + "col795": "de871", + "col796": "7u0fc", + "col797": "povr8", + "col798": "sxoig", + "col799": "l7nzb", + "col800": "kronr", + "col801": "llp36", + "col802": "znv0f", + "col803": "nts0s", + "col804": "s9aw4", + "col805": "7bel4", + "col806": "8vcd1", + "col807": "d4vdr", + "col808": "2u4ti", + "col809": "j2rko", + "col810": "lzbrq", + "col811": "vlzfz", + "col812": "ak2hl", + "col813": "2zonq", + "col814": "4z5nh", + "col815": "th4x6", + "col816": "2j41s", + "col817": "f5xks", + "col818": "4bydk", + "col819": "y2n55", + "col820": "3la95", + "col821": "v5z5x", + "col822": "hl4rj", + "col823": "4a0f4", + "col824": "kjr71", + "col825": "cvfqi", + "col826": "g60y2", + "col827": "mvwd2", + "col828": "7ubpw", + "col829": "ov6a9", + "col830": "8rr7x", + "col831": "22v4i", + "col832": "zxfgv", + "col833": "1jvcn", + "col834": "tdvqk", + "col835": "6dpmm", + "col836": "u3xyt", + "col837": "mupyb", + "col838": "szvoa", + "col839": "cpps0", + "col840": "561n1", + "col841": "prhac", + "col842": "63sny", + "col843": "u71qb", + "col844": "2535f", + "col845": "gmn4m", + "col846": "mi9b6", + "col847": "gkjnv", + "col848": "0o0dc", + "col849": "kp2go", + "col850": "m1764", + "col851": "58qvh", + "col852": "phf5b", + "col853": "1fgfl", + "col854": "k2qk3", + "col855": "ulisw", + "col856": "684c6", + "col857": "66qqg", + "col858": "oa64u", + "col859": "gv2kl", + "col860": "86bfq", + "col861": "so0cd", + "col862": "qhzyo", + "col863": "mkn4f", + "col864": "2cme9", + "col865": "rvbq3", + "col866": "brccm", + "col867": "of7c8", + "col868": "4gb25", + "col869": "ziw2e", + "col870": "c2a0e", + "col871": "sd238", + "col872": "0oktj", + "col873": "144pv", + "col874": "gk8jy", + "col875": "apxs9", + "col876": "4j1km", + "col877": "xuf7p", + "col878": "rfmst", + "col879": "u3e4k", + "col880": "s52mh", + "col881": "8ghhy", + "col882": "n3dgo", + "col883": "mfo7d", + "col884": "9h6si", + "col885": "mvauf", + "col886": "vcsek", + "col887": "ce0dn", + "col888": "9f3fk", + "col889": "02pes", + "col890": "s7wuq", + "col891": "ulrku", + "col892": "fxgcp", + "col893": "jyfqr", + "col894": "0jlzy", + "col895": "zbgpo", + "col896": "5wobi", + "col897": "obky2", + "col898": "rw50h", + "col899": "kvs2s", + "col900": "xc1k7", + "col901": "7k1yj", + "col902": "zq486", + "col903": "25zbv", + "col904": "karzj", + "col905": "jnqnk", + "col906": "ksybu", + "col907": "c795q", + "col908": "ioxah", + "col909": "n8xy1", + "col910": "vzh75", + "col911": "o4f9t", + "col912": "bkgyq", + "col913": "77q9x", + "col914": "taen2", + "col915": "2to5f", + "col916": "jmbvu", + "col917": "n9a3s", + "col918": "pe4bq", + "col919": "3qacc", + "col920": "28jij", + "col921": "ms6pt", + "col922": "izmxj", + "col923": "4ncen", + "col924": "xdmmd", + "col925": "90vk3", + "col926": "hbodt", + "col927": "91onn", + "col928": "se1s9", + "col929": "cs4tx", + "col930": "ghyg7", + "col931": "wl58s", + "col932": "506bd", + "col933": "24a7b", + "col934": "e4y1g", + "col935": "o5i0m", + "col936": "v7klo", + "col937": "j9x1b", + "col938": "939fy", + "col939": "3y5m0", + "col940": "clr7x", + "col941": "k2ey3", + "col942": "r5cnt", + "col943": "88hyg", + "col944": "pkcr3", + "col945": "bu5yy", + "col946": "6m7nq", + "col947": "8v2sc", + "col948": "3v58m", + "col949": "dvfud", + "col950": "pjlk4", + "col951": "9jltb", + "col952": "3dx7n", + "col953": "gr4e8", + "col954": "kus90", + "col955": "8w4wi", + "col956": "mf0gk", + "col957": "z56wu", + "col958": "wfelp", + "col959": "mt5rg", + "col960": "f95wu", + "col961": "qzpfm", + "col962": "rmseg", + "col963": "iadmh", + "col964": "9sp5x", + "col965": "5nzyu", + "col966": "05vhj", + "col967": "86i6x", + "col968": "wb9jt", + "col969": "xw7rm", + "col970": "v1hvc", + "col971": "5g6c7", + "col972": "onwgw", + "col973": "6bhzf", + "col974": "i2d5r", + "col975": "t6qed", + "col976": "zxraf", + "col977": "et493", + "col978": "nlmzs", + "col979": "v2sy9", + "col980": "tm0gh", + "col981": "k5zxc", + "col982": "mquzm", + "col983": "ade1a", + "col984": "6uiad", + "col985": "jsqqf", + "col986": "n61cf", + "col987": "7nuta", + "col988": "cqr3y", + "col989": "4mqs1", + "col990": "0xvj0", + "col991": "68i4f", + "col992": "g5tq2", + "col993": "b3cm5", + "col994": "ecelp", + "col995": "mgenx", + "col996": "awji6", + "col997": "gmvht", + "col998": "lh7db", + "col999": "qgybk" + }, + { + "name": "Tanner Stephens", + "gender": "male", + "col0": "moo1m", + "col1": "5jys9", + "col2": "iz9xg", + "col3": "1obtu", + "col4": "53f2d", + "col5": "tpri4", + "col6": "fgcu1", + "col7": "4qkmc", + "col8": "cj56v", + "col9": "1crlv", + "col10": "u8xsz", + "col11": "7hkbn", + "col12": "e70mm", + "col13": "2445d", + "col14": "gslus", + "col15": "hbq1r", + "col16": "hvecp", + "col17": "000h4", + "col18": "1fpn1", + "col19": "ufw8u", + "col20": "xpkuq", + "col21": "pxw5m", + "col22": "srvmk", + "col23": "lcd6m", + "col24": "imouq", + "col25": "a1uw3", + "col26": "j8idk", + "col27": "0h7rc", + "col28": "nm8ok", + "col29": "1pcov", + "col30": "bst2d", + "col31": "ju5p4", + "col32": "4oala", + "col33": "3w6hp", + "col34": "77kjh", + "col35": "6at0f", + "col36": "gv08b", + "col37": "5o7hu", + "col38": "kgzpp", + "col39": "4glpp", + "col40": "4zjka", + "col41": "9mbfg", + "col42": "2axre", + "col43": "93grc", + "col44": "u3ol3", + "col45": "w3o7d", + "col46": "riati", + "col47": "6nj6i", + "col48": "u84dn", + "col49": "azjqo", + "col50": "glpil", + "col51": "dob00", + "col52": "x3tpp", + "col53": "gsbcs", + "col54": "vy66n", + "col55": "kds6c", + "col56": "t51lc", + "col57": "yu4ul", + "col58": "0qqw3", + "col59": "9hue7", + "col60": "koohl", + "col61": "h5ql1", + "col62": "jzcp5", + "col63": "0ia01", + "col64": "qq7u1", + "col65": "bvm5d", + "col66": "m785d", + "col67": "7nayj", + "col68": "9dpin", + "col69": "q5ma4", + "col70": "xmebk", + "col71": "nnx7r", + "col72": "55yr1", + "col73": "zklwp", + "col74": "j122h", + "col75": "ydm06", + "col76": "ojvyi", + "col77": "v91du", + "col78": "6690q", + "col79": "iwkdy", + "col80": "83smq", + "col81": "fblw2", + "col82": "f3760", + "col83": "j6790", + "col84": "khwky", + "col85": "mwgut", + "col86": "h5rbm", + "col87": "25yoi", + "col88": "cm3g3", + "col89": "k8y2v", + "col90": "hjjg5", + "col91": "3mvxc", + "col92": "rj6xh", + "col93": "nfggi", + "col94": "tuvpi", + "col95": "9vwkr", + "col96": "rjiik", + "col97": "5rxeg", + "col98": "a22jb", + "col99": "8103f", + "col100": "t5d3h", + "col101": "bzrr5", + "col102": "bsv2r", + "col103": "td688", + "col104": "ryiaq", + "col105": "cugmu", + "col106": "1x17q", + "col107": "cwdv5", + "col108": "c8eea", + "col109": "hnj9q", + "col110": "fikrk", + "col111": "h4cqp", + "col112": "eykb5", + "col113": "vszsg", + "col114": "kikhh", + "col115": "mrf6k", + "col116": "10jqj", + "col117": "ltspt", + "col118": "5lgjk", + "col119": "kl07t", + "col120": "2mq8a", + "col121": "g35xz", + "col122": "zjte3", + "col123": "ll40n", + "col124": "d8lu8", + "col125": "fkp3d", + "col126": "2e3ja", + "col127": "cpeuw", + "col128": "jnmek", + "col129": "c0yyo", + "col130": "egzm9", + "col131": "ovadc", + "col132": "3v47i", + "col133": "j7cvr", + "col134": "g0rqr", + "col135": "v6i23", + "col136": "cgszy", + "col137": "s7g6g", + "col138": "lpbqq", + "col139": "7nb65", + "col140": "br172", + "col141": "776a1", + "col142": "v9m2c", + "col143": "zeqxo", + "col144": "s3qog", + "col145": "nxdyr", + "col146": "m0vlq", + "col147": "nwdqa", + "col148": "yzr5j", + "col149": "5z65b", + "col150": "tuc0q", + "col151": "eh4j8", + "col152": "pl8pe", + "col153": "9ti6f", + "col154": "n8xs7", + "col155": "zeb4m", + "col156": "7mhzu", + "col157": "axkni", + "col158": "4hw7y", + "col159": "z8wk7", + "col160": "t3fyd", + "col161": "hxiz6", + "col162": "i96dp", + "col163": "5xd3e", + "col164": "tbcis", + "col165": "lagc2", + "col166": "onnak", + "col167": "wn6y2", + "col168": "77231", + "col169": "2ttq4", + "col170": "vspxm", + "col171": "9p8aa", + "col172": "wrpak", + "col173": "nm0xl", + "col174": "5s8mi", + "col175": "0gwlz", + "col176": "8a7ao", + "col177": "wf6r0", + "col178": "aebls", + "col179": "3a24v", + "col180": "jklhh", + "col181": "9397q", + "col182": "e2gea", + "col183": "ve24p", + "col184": "ms0m3", + "col185": "yqpaw", + "col186": "d1d6m", + "col187": "7f7jr", + "col188": "2wwpj", + "col189": "ssjhl", + "col190": "oobkq", + "col191": "iix8r", + "col192": "9bevd", + "col193": "49urq", + "col194": "9xxxz", + "col195": "iol2h", + "col196": "yhjlk", + "col197": "fzm3y", + "col198": "p3vih", + "col199": "zlzat", + "col200": "jruvb", + "col201": "evcre", + "col202": "yu8jq", + "col203": "7kp54", + "col204": "xclwt", + "col205": "fc17p", + "col206": "jfgh8", + "col207": "pn3mx", + "col208": "b7nu7", + "col209": "lqtei", + "col210": "jt5a0", + "col211": "kgyvg", + "col212": "eahec", + "col213": "qsnt2", + "col214": "0e4g0", + "col215": "67ilz", + "col216": "equzt", + "col217": "onthc", + "col218": "fo1m2", + "col219": "xe6b6", + "col220": "l2pjk", + "col221": "f131h", + "col222": "lq92b", + "col223": "v721k", + "col224": "jnps0", + "col225": "baorz", + "col226": "5buu5", + "col227": "lxi8h", + "col228": "guy33", + "col229": "qtlm0", + "col230": "whbpl", + "col231": "onjgs", + "col232": "lkpa9", + "col233": "hx2q4", + "col234": "0fa60", + "col235": "tzrsw", + "col236": "dtw0k", + "col237": "fxiig", + "col238": "gx6wc", + "col239": "9wwoz", + "col240": "yd5a4", + "col241": "d17l1", + "col242": "jyjgt", + "col243": "1dlvo", + "col244": "5z46b", + "col245": "x0mj6", + "col246": "v4gza", + "col247": "otd18", + "col248": "edqgq", + "col249": "9salj", + "col250": "yvp4c", + "col251": "0gypp", + "col252": "xynmg", + "col253": "gvdam", + "col254": "whuqr", + "col255": "mgmti", + "col256": "yavjy", + "col257": "fubv2", + "col258": "6hom2", + "col259": "cuet3", + "col260": "jdssb", + "col261": "wdaqo", + "col262": "vwyrp", + "col263": "jesbr", + "col264": "ujs8j", + "col265": "p8gy6", + "col266": "zxrel", + "col267": "om25s", + "col268": "n7e98", + "col269": "p4s4r", + "col270": "ntrma", + "col271": "ly1at", + "col272": "ngtx7", + "col273": "ydzxq", + "col274": "5iwyr", + "col275": "1rxw8", + "col276": "s74lf", + "col277": "fj8th", + "col278": "oslul", + "col279": "4j11k", + "col280": "ebdj7", + "col281": "nm0b8", + "col282": "qll4e", + "col283": "ylofs", + "col284": "i11s3", + "col285": "a1hju", + "col286": "ybefk", + "col287": "r8uit", + "col288": "pqqms", + "col289": "99iw6", + "col290": "tq6ng", + "col291": "8we90", + "col292": "ma8d8", + "col293": "9mw5u", + "col294": "v5wd7", + "col295": "ihxmf", + "col296": "psf43", + "col297": "dldoo", + "col298": "tgzxo", + "col299": "rm3sb", + "col300": "z6rtd", + "col301": "vh4cw", + "col302": "qgubt", + "col303": "4miap", + "col304": "7dfbf", + "col305": "kms2c", + "col306": "mfx1o", + "col307": "w5bmn", + "col308": "w50ju", + "col309": "t5czq", + "col310": "3nsce", + "col311": "byaxd", + "col312": "ry1zt", + "col313": "qm6if", + "col314": "vdijz", + "col315": "9rr2g", + "col316": "8xazs", + "col317": "5fm7v", + "col318": "kfap1", + "col319": "v4abn", + "col320": "5h3pq", + "col321": "sgdk5", + "col322": "d8xlb", + "col323": "j1bll", + "col324": "m67d8", + "col325": "z7nch", + "col326": "g5s52", + "col327": "gnun5", + "col328": "t829y", + "col329": "yz5zg", + "col330": "zclxq", + "col331": "k1v3q", + "col332": "1xek7", + "col333": "un393", + "col334": "25122", + "col335": "p5d4f", + "col336": "k6efn", + "col337": "3qtr6", + "col338": "es49d", + "col339": "gqq2t", + "col340": "ic3s8", + "col341": "7n2ue", + "col342": "tccpv", + "col343": "c4gwp", + "col344": "poq1g", + "col345": "9a54c", + "col346": "vxogo", + "col347": "9b8hu", + "col348": "d4hi8", + "col349": "juiyn", + "col350": "d91d5", + "col351": "sbc9n", + "col352": "4a8r9", + "col353": "2i251", + "col354": "b4m3o", + "col355": "4y2vz", + "col356": "enkan", + "col357": "9wm4p", + "col358": "r60n0", + "col359": "7mlal", + "col360": "kbd15", + "col361": "yb957", + "col362": "obglr", + "col363": "92qis", + "col364": "dxvbw", + "col365": "451d4", + "col366": "p3j5v", + "col367": "pqrr3", + "col368": "npzno", + "col369": "aevjv", + "col370": "hd00d", + "col371": "2z42c", + "col372": "m7tbs", + "col373": "fs8mq", + "col374": "na3g2", + "col375": "ha622", + "col376": "xreri", + "col377": "ytzwf", + "col378": "199qt", + "col379": "0civa", + "col380": "y43ot", + "col381": "hqluq", + "col382": "sl3c2", + "col383": "15qiu", + "col384": "fa3f0", + "col385": "gbtzq", + "col386": "a2ym6", + "col387": "al9tf", + "col388": "s9m8c", + "col389": "wryte", + "col390": "58n5p", + "col391": "tch0q", + "col392": "orv5i", + "col393": "wzhm1", + "col394": "98khy", + "col395": "0dezh", + "col396": "mjj68", + "col397": "ghfw5", + "col398": "0d8wi", + "col399": "toe0l", + "col400": "s4fas", + "col401": "nomsp", + "col402": "nf4uz", + "col403": "9o8hn", + "col404": "93h4w", + "col405": "ss0pr", + "col406": "ceeb4", + "col407": "nkeai", + "col408": "uz6si", + "col409": "xq8z1", + "col410": "hesk3", + "col411": "cv5r8", + "col412": "qalbd", + "col413": "32cjt", + "col414": "4ugd5", + "col415": "rfsb0", + "col416": "bvixd", + "col417": "t5jeh", + "col418": "iuwhg", + "col419": "9dw78", + "col420": "lnn1l", + "col421": "2akny", + "col422": "cn4xn", + "col423": "4r0dl", + "col424": "5o3cs", + "col425": "cxyod", + "col426": "kww5w", + "col427": "ubzgr", + "col428": "5q17g", + "col429": "96ktl", + "col430": "c28aw", + "col431": "ecvfc", + "col432": "z2zi5", + "col433": "b22fu", + "col434": "u88zb", + "col435": "vf7za", + "col436": "f19hn", + "col437": "pdvkw", + "col438": "ozirt", + "col439": "aw188", + "col440": "2h5ok", + "col441": "1o50s", + "col442": "knvtb", + "col443": "oizjt", + "col444": "8lm7e", + "col445": "yuufl", + "col446": "0isak", + "col447": "8vgxu", + "col448": "fe1ol", + "col449": "7i2j7", + "col450": "bi3j2", + "col451": "r2wdg", + "col452": "g5rdg", + "col453": "a8tis", + "col454": "17u16", + "col455": "yb45h", + "col456": "9tnva", + "col457": "gev6f", + "col458": "iwl4d", + "col459": "f3y2m", + "col460": "33edk", + "col461": "m70om", + "col462": "muwc7", + "col463": "vpppk", + "col464": "ez6tu", + "col465": "2yt60", + "col466": "7ghno", + "col467": "4jyio", + "col468": "0pd8a", + "col469": "a0q3g", + "col470": "kloez", + "col471": "tjiz7", + "col472": "4yzdj", + "col473": "l1sg5", + "col474": "5ugit", + "col475": "s1ras", + "col476": "tyds5", + "col477": "itm5n", + "col478": "ikrsy", + "col479": "k8ri6", + "col480": "3dhia", + "col481": "mfp6a", + "col482": "rfjke", + "col483": "uafl1", + "col484": "glo90", + "col485": "gjq1c", + "col486": "yj6hu", + "col487": "nwai1", + "col488": "j9sgz", + "col489": "ito21", + "col490": "3tp5k", + "col491": "wdep0", + "col492": "nbxo9", + "col493": "ofh12", + "col494": "woggh", + "col495": "wiw2g", + "col496": "h80m6", + "col497": "jq4bc", + "col498": "fiuy1", + "col499": "hlq6q", + "col500": "i2agk", + "col501": "zplbz", + "col502": "b66ra", + "col503": "6s8gn", + "col504": "hovfq", + "col505": "1nh5i", + "col506": "k69t5", + "col507": "jvgi7", + "col508": "gh3yb", + "col509": "1gd8o", + "col510": "oplr4", + "col511": "zfatq", + "col512": "dfz44", + "col513": "udwkl", + "col514": "fbuov", + "col515": "kc5za", + "col516": "q1gqc", + "col517": "0udle", + "col518": "21s19", + "col519": "gmlqz", + "col520": "7fai5", + "col521": "fle4l", + "col522": "kk6wt", + "col523": "y9ta2", + "col524": "t7ahc", + "col525": "igdq6", + "col526": "gqn5i", + "col527": "2nwr6", + "col528": "b5u9t", + "col529": "zehrn", + "col530": "7jcdz", + "col531": "1ge1h", + "col532": "w998g", + "col533": "l725j", + "col534": "yiz8k", + "col535": "1u0tk", + "col536": "ubbp8", + "col537": "e3p6l", + "col538": "0qgwt", + "col539": "6bktg", + "col540": "nxw4q", + "col541": "1h3nq", + "col542": "m9fqa", + "col543": "hzebh", + "col544": "fhrpg", + "col545": "cko2t", + "col546": "0b577", + "col547": "g4fty", + "col548": "iemf3", + "col549": "6brsw", + "col550": "l8ti0", + "col551": "fmnjj", + "col552": "nualp", + "col553": "xak7q", + "col554": "oyzvu", + "col555": "j67ea", + "col556": "kqpy7", + "col557": "jrsds", + "col558": "aq3n3", + "col559": "m4drm", + "col560": "6x5yt", + "col561": "sld1e", + "col562": "y1nzs", + "col563": "9yq89", + "col564": "40o85", + "col565": "e7r34", + "col566": "f1ss3", + "col567": "13gym", + "col568": "o8cbt", + "col569": "myipx", + "col570": "s5l52", + "col571": "rzsjr", + "col572": "jgr88", + "col573": "p81pl", + "col574": "x1abv", + "col575": "ka2q0", + "col576": "vxh0b", + "col577": "rj0ks", + "col578": "22oxh", + "col579": "kb549", + "col580": "wuw5w", + "col581": "97vkt", + "col582": "90pt9", + "col583": "2a9uy", + "col584": "k49id", + "col585": "3cacj", + "col586": "20z5e", + "col587": "yei4h", + "col588": "og7p2", + "col589": "092fr", + "col590": "w2ezg", + "col591": "wax3q", + "col592": "bejlt", + "col593": "w8h69", + "col594": "a2fug", + "col595": "ildw0", + "col596": "xfvw8", + "col597": "57dql", + "col598": "hk2c6", + "col599": "kytw9", + "col600": "n8fgh", + "col601": "62mud", + "col602": "nazrc", + "col603": "atdvz", + "col604": "whn5m", + "col605": "lqihj", + "col606": "44akq", + "col607": "kwd1n", + "col608": "h917p", + "col609": "0y9gm", + "col610": "kgwoz", + "col611": "6isl6", + "col612": "ht6tm", + "col613": "tsg0j", + "col614": "g4dfa", + "col615": "ozibu", + "col616": "dbql5", + "col617": "fypuo", + "col618": "4j4q6", + "col619": "azhz1", + "col620": "7sn54", + "col621": "xzl75", + "col622": "a4vt1", + "col623": "gasi6", + "col624": "bmrp0", + "col625": "jws72", + "col626": "rpm7b", + "col627": "o8sm5", + "col628": "grv3x", + "col629": "w6f0h", + "col630": "z3n5b", + "col631": "sacsb", + "col632": "7h3sk", + "col633": "r94yd", + "col634": "3voz3", + "col635": "rz83o", + "col636": "m5gst", + "col637": "adz6s", + "col638": "esk06", + "col639": "cinb5", + "col640": "075p9", + "col641": "ugomy", + "col642": "ff3fz", + "col643": "gf7fb", + "col644": "imv0s", + "col645": "m01bl", + "col646": "1v0kc", + "col647": "74y02", + "col648": "kafl1", + "col649": "9glma", + "col650": "vq4mq", + "col651": "614a4", + "col652": "69h8o", + "col653": "uiogs", + "col654": "4hahs", + "col655": "4zs42", + "col656": "ol4as", + "col657": "ftrqp", + "col658": "ps92n", + "col659": "hyn3i", + "col660": "fzj11", + "col661": "fhbm3", + "col662": "un5mu", + "col663": "igt46", + "col664": "zdwdm", + "col665": "mel4p", + "col666": "tb069", + "col667": "f63dk", + "col668": "51h7c", + "col669": "98npv", + "col670": "1qzhz", + "col671": "uhco9", + "col672": "zn32r", + "col673": "naz7o", + "col674": "bj84m", + "col675": "7k4y0", + "col676": "xsox2", + "col677": "8yrqx", + "col678": "yx484", + "col679": "duxu5", + "col680": "9as17", + "col681": "sco09", + "col682": "ho2se", + "col683": "d2cwc", + "col684": "82mkk", + "col685": "a0ov0", + "col686": "xk8km", + "col687": "01jmu", + "col688": "66m62", + "col689": "tbb9m", + "col690": "3snwf", + "col691": "9t7bw", + "col692": "5l3oq", + "col693": "ao1fo", + "col694": "hdq5j", + "col695": "gy5xp", + "col696": "fqavn", + "col697": "sjyff", + "col698": "rwiry", + "col699": "jd4pk", + "col700": "u6xnx", + "col701": "gqswg", + "col702": "6phqj", + "col703": "zjcuq", + "col704": "gnjq7", + "col705": "7zhml", + "col706": "z146f", + "col707": "ead38", + "col708": "loqma", + "col709": "lma0x", + "col710": "vhew9", + "col711": "vra06", + "col712": "8bgo1", + "col713": "s0y87", + "col714": "p4zc9", + "col715": "rl3w7", + "col716": "545nt", + "col717": "hcmtc", + "col718": "idvyh", + "col719": "nqwhz", + "col720": "i0n8g", + "col721": "tse2q", + "col722": "b5u74", + "col723": "kdok4", + "col724": "vqoa6", + "col725": "ulovy", + "col726": "2pzyl", + "col727": "bkdut", + "col728": "4miyj", + "col729": "i9vh6", + "col730": "oim51", + "col731": "28l3v", + "col732": "7mwyj", + "col733": "6ijhn", + "col734": "55nxa", + "col735": "pv6qz", + "col736": "b58iy", + "col737": "ipcyp", + "col738": "wsw2t", + "col739": "iw2mt", + "col740": "368a6", + "col741": "v6j6q", + "col742": "syi3k", + "col743": "md2sr", + "col744": "83rw8", + "col745": "w7m41", + "col746": "mxzq2", + "col747": "radja", + "col748": "l1cjb", + "col749": "zpln9", + "col750": "4h180", + "col751": "z0cfn", + "col752": "q8hyf", + "col753": "4ayfx", + "col754": "vqz60", + "col755": "98blb", + "col756": "553la", + "col757": "azgpn", + "col758": "xxhm3", + "col759": "oiwhd", + "col760": "5mzpl", + "col761": "tu850", + "col762": "nn8cq", + "col763": "csj0k", + "col764": "7ghtp", + "col765": "uquzn", + "col766": "5ci16", + "col767": "9i442", + "col768": "bu3c2", + "col769": "308d2", + "col770": "lu9r6", + "col771": "53bzs", + "col772": "63b92", + "col773": "x0ned", + "col774": "06bgh", + "col775": "d3w4w", + "col776": "51ekb", + "col777": "4ihev", + "col778": "krrlt", + "col779": "f7kzg", + "col780": "fetq7", + "col781": "knt2s", + "col782": "o7hck", + "col783": "16wza", + "col784": "jdim6", + "col785": "mjyfl", + "col786": "lld15", + "col787": "jk41d", + "col788": "ms8mt", + "col789": "qbw6g", + "col790": "faofr", + "col791": "nxgei", + "col792": "6odyj", + "col793": "cxa77", + "col794": "29ufb", + "col795": "sxdp4", + "col796": "ammtq", + "col797": "3lytu", + "col798": "fy4gj", + "col799": "18meb", + "col800": "lbvw6", + "col801": "r2gs2", + "col802": "oz6v8", + "col803": "n873a", + "col804": "cb1fg", + "col805": "l16r5", + "col806": "i7p8u", + "col807": "zxfcd", + "col808": "xnk8u", + "col809": "lo27b", + "col810": "tt99x", + "col811": "9ae6p", + "col812": "9jdba", + "col813": "2bruc", + "col814": "jljb0", + "col815": "a32n1", + "col816": "jsvu6", + "col817": "rcp77", + "col818": "92qi0", + "col819": "hanjz", + "col820": "b6faj", + "col821": "wjbzs", + "col822": "nl1jo", + "col823": "fd4rb", + "col824": "nr9x3", + "col825": "gziav", + "col826": "ogs8k", + "col827": "jfkq3", + "col828": "ix9ab", + "col829": "5mm7d", + "col830": "p3a6f", + "col831": "ekpkg", + "col832": "0297h", + "col833": "ca54w", + "col834": "hgmt4", + "col835": "611yk", + "col836": "t47yc", + "col837": "a9s11", + "col838": "soc3j", + "col839": "mqoz8", + "col840": "oiopw", + "col841": "k6j8r", + "col842": "k9myg", + "col843": "5y8es", + "col844": "3j5ep", + "col845": "qscc9", + "col846": "ea2us", + "col847": "kcn6g", + "col848": "n1qvn", + "col849": "26y40", + "col850": "c4z7g", + "col851": "g6vp7", + "col852": "4qexr", + "col853": "bypj8", + "col854": "nwkex", + "col855": "jjmw7", + "col856": "ohjqg", + "col857": "32grs", + "col858": "l1dm2", + "col859": "24mm3", + "col860": "cmh5x", + "col861": "f0zkw", + "col862": "cpmd1", + "col863": "n30yf", + "col864": "h22p9", + "col865": "c8bho", + "col866": "4mgkw", + "col867": "jbsqx", + "col868": "bq6qz", + "col869": "bpeg1", + "col870": "j4uz5", + "col871": "01q6m", + "col872": "22cu3", + "col873": "w1lm9", + "col874": "8v8lv", + "col875": "tam83", + "col876": "vntg5", + "col877": "7l7c4", + "col878": "ujayu", + "col879": "fgwvg", + "col880": "8xcnc", + "col881": "sqmjd", + "col882": "ensw2", + "col883": "szqj5", + "col884": "x3ze2", + "col885": "5wm8w", + "col886": "4hw73", + "col887": "hx50p", + "col888": "usk21", + "col889": "f13zg", + "col890": "ofr0o", + "col891": "dh6js", + "col892": "k39zt", + "col893": "8ktf3", + "col894": "fkgcm", + "col895": "9kz6c", + "col896": "j8o5l", + "col897": "b5pif", + "col898": "daemq", + "col899": "g22xh", + "col900": "ix66w", + "col901": "pmr27", + "col902": "2v6kf", + "col903": "wzomt", + "col904": "3whhm", + "col905": "z33ly", + "col906": "hb8h2", + "col907": "bhfhz", + "col908": "cj9vy", + "col909": "1hxvj", + "col910": "8nwch", + "col911": "n8npq", + "col912": "2jqcc", + "col913": "y333v", + "col914": "qcva4", + "col915": "qda33", + "col916": "6ggxe", + "col917": "agpd6", + "col918": "1nisv", + "col919": "5lzie", + "col920": "n2hdq", + "col921": "r1i22", + "col922": "t7y5x", + "col923": "8miho", + "col924": "juyxg", + "col925": "5x2a3", + "col926": "d5qol", + "col927": "5s8yb", + "col928": "530ts", + "col929": "7lhsy", + "col930": "towls", + "col931": "e0wi8", + "col932": "q4dj0", + "col933": "jk92h", + "col934": "tu514", + "col935": "2fmdi", + "col936": "2lmx7", + "col937": "txpe0", + "col938": "6zr95", + "col939": "yndza", + "col940": "wqsxb", + "col941": "5us7u", + "col942": "ef7n8", + "col943": "eqm53", + "col944": "wxlnh", + "col945": "uqxf8", + "col946": "glmn8", + "col947": "7i9ow", + "col948": "wosy7", + "col949": "pz1em", + "col950": "3oxul", + "col951": "3u6pn", + "col952": "ejqht", + "col953": "nuwv7", + "col954": "q1oeh", + "col955": "f57qg", + "col956": "uh3p6", + "col957": "je9xd", + "col958": "3lpke", + "col959": "te59m", + "col960": "b0c7p", + "col961": "bu5wt", + "col962": "f3tjn", + "col963": "nsvov", + "col964": "ufn7g", + "col965": "926yq", + "col966": "cjx3d", + "col967": "flcvs", + "col968": "jhcan", + "col969": "29uhy", + "col970": "8653u", + "col971": "ennnu", + "col972": "u0gq3", + "col973": "mj75g", + "col974": "1hkb7", + "col975": "e5dqh", + "col976": "kerhc", + "col977": "c0uwh", + "col978": "wcakc", + "col979": "60my5", + "col980": "2h4n2", + "col981": "xsxbd", + "col982": "hhnpc", + "col983": "zvhj7", + "col984": "97qt2", + "col985": "3773l", + "col986": "nuvzn", + "col987": "cudok", + "col988": "ml14e", + "col989": "jaop1", + "col990": "n3hg2", + "col991": "nq0a5", + "col992": "um9a2", + "col993": "3kt2q", + "col994": "xrrha", + "col995": "gmrek", + "col996": "m29dl", + "col997": "c12gd", + "col998": "jak65", + "col999": "oefp8" + }, + { + "name": "Eugenia Palmer", + "gender": "female", + "col0": "11qaj", + "col1": "2i7oc", + "col2": "l1a7u", + "col3": "3pgg8", + "col4": "8xhh5", + "col5": "b6bw8", + "col6": "7m971", + "col7": "td8qr", + "col8": "av9gw", + "col9": "qnut9", + "col10": "ku0qe", + "col11": "m2q6h", + "col12": "ukqux", + "col13": "3s944", + "col14": "zg4ra", + "col15": "d44xb", + "col16": "8w4ml", + "col17": "nmw6b", + "col18": "tq59c", + "col19": "aeaj3", + "col20": "fxxwp", + "col21": "88ueg", + "col22": "pmk9q", + "col23": "1mi9s", + "col24": "6xpek", + "col25": "ngkdt", + "col26": "7pr1a", + "col27": "mvfrs", + "col28": "aoyv1", + "col29": "awwvh", + "col30": "5mzy9", + "col31": "dhwg1", + "col32": "abg9j", + "col33": "skul3", + "col34": "01vo9", + "col35": "2ynwl", + "col36": "00jiu", + "col37": "ur0jh", + "col38": "jyw7q", + "col39": "ug5x9", + "col40": "4f8fy", + "col41": "z65p3", + "col42": "4cn1q", + "col43": "uyyit", + "col44": "lt0va", + "col45": "01nae", + "col46": "721i9", + "col47": "2olqe", + "col48": "4srbf", + "col49": "eofy6", + "col50": "tk4vg", + "col51": "0izrf", + "col52": "pqfuc", + "col53": "pd184", + "col54": "uuyf6", + "col55": "djtlz", + "col56": "refnf", + "col57": "lmlvz", + "col58": "5a6zx", + "col59": "kjx02", + "col60": "nyqjp", + "col61": "q09lu", + "col62": "u13k2", + "col63": "acsef", + "col64": "bo8wg", + "col65": "u4ugg", + "col66": "ulw2f", + "col67": "ung6x", + "col68": "t8xks", + "col69": "wlwhp", + "col70": "e2eba", + "col71": "5bnnv", + "col72": "9ds5d", + "col73": "on1lt", + "col74": "ipav3", + "col75": "ghlys", + "col76": "v1u34", + "col77": "jpj19", + "col78": "tp9ux", + "col79": "s47te", + "col80": "b8kck", + "col81": "v82f3", + "col82": "m58ux", + "col83": "erkmb", + "col84": "cw7q7", + "col85": "xh4xa", + "col86": "0j9js", + "col87": "7fh7o", + "col88": "ofdyd", + "col89": "vmf61", + "col90": "sm4n6", + "col91": "fgk4w", + "col92": "06po9", + "col93": "ny2me", + "col94": "d33u8", + "col95": "65ryz", + "col96": "ce02j", + "col97": "4wi3s", + "col98": "6i2ec", + "col99": "ujsh1", + "col100": "wjj96", + "col101": "du0k2", + "col102": "hex2k", + "col103": "d3yak", + "col104": "vk95u", + "col105": "3tqql", + "col106": "z1zfh", + "col107": "msb6e", + "col108": "h8i07", + "col109": "lu74g", + "col110": "zw10c", + "col111": "vye3o", + "col112": "d2e2y", + "col113": "olqhx", + "col114": "crv05", + "col115": "qfypl", + "col116": "mdiro", + "col117": "tspwg", + "col118": "bev2p", + "col119": "c505t", + "col120": "ad3o0", + "col121": "7d49n", + "col122": "aneaq", + "col123": "girpt", + "col124": "tyxwi", + "col125": "65h25", + "col126": "aj4sr", + "col127": "klfx8", + "col128": "ysqhq", + "col129": "4tg8s", + "col130": "xdvse", + "col131": "o1641", + "col132": "bquqe", + "col133": "zbcu3", + "col134": "ksz4i", + "col135": "o3gmt", + "col136": "d2tve", + "col137": "eozid", + "col138": "he6l8", + "col139": "jitxs", + "col140": "9myyz", + "col141": "w17u0", + "col142": "npsrg", + "col143": "78s4r", + "col144": "x2fo8", + "col145": "ixvlq", + "col146": "goa13", + "col147": "jrptv", + "col148": "5fu93", + "col149": "8anb5", + "col150": "p7y62", + "col151": "87fny", + "col152": "khfkl", + "col153": "ci8rk", + "col154": "1z2u7", + "col155": "rrx7v", + "col156": "n7tby", + "col157": "0q9vx", + "col158": "1fdv5", + "col159": "e1j9d", + "col160": "hyeq8", + "col161": "xr4c9", + "col162": "ycam9", + "col163": "1mjpo", + "col164": "tfwx6", + "col165": "3t4n0", + "col166": "19bqr", + "col167": "0v7wg", + "col168": "n8bgq", + "col169": "c8sc6", + "col170": "09oaw", + "col171": "e6t3b", + "col172": "2pesj", + "col173": "mbydf", + "col174": "75ajl", + "col175": "1ky0e", + "col176": "kvvp3", + "col177": "mme7b", + "col178": "f2wu4", + "col179": "ukgos", + "col180": "b6zlq", + "col181": "pwvhs", + "col182": "c2gqk", + "col183": "gf37g", + "col184": "rtz4a", + "col185": "c3py4", + "col186": "legap", + "col187": "sychk", + "col188": "iv3y3", + "col189": "p5r8y", + "col190": "zk294", + "col191": "o0syo", + "col192": "4576g", + "col193": "7qmdj", + "col194": "tnj04", + "col195": "s1t43", + "col196": "i5raa", + "col197": "g5pd9", + "col198": "sp783", + "col199": "ized9", + "col200": "3vt98", + "col201": "vgs51", + "col202": "65j78", + "col203": "hlwfz", + "col204": "q9f8i", + "col205": "frpgt", + "col206": "69d5w", + "col207": "rfx8c", + "col208": "aj7o7", + "col209": "n5jcp", + "col210": "q7ovk", + "col211": "nypab", + "col212": "hjplx", + "col213": "733fp", + "col214": "22h4c", + "col215": "9oq9y", + "col216": "pjbww", + "col217": "jdlno", + "col218": "a1hah", + "col219": "w6joz", + "col220": "0i7q8", + "col221": "mlo8n", + "col222": "y072q", + "col223": "8ykfq", + "col224": "j5bhz", + "col225": "e5dxj", + "col226": "59azf", + "col227": "gc7v8", + "col228": "x232w", + "col229": "sbsik", + "col230": "r6kwq", + "col231": "au3dz", + "col232": "hcx8s", + "col233": "vkb3o", + "col234": "lpj3k", + "col235": "di9bm", + "col236": "cyulq", + "col237": "mpvnm", + "col238": "uk23v", + "col239": "a4yeb", + "col240": "zf2ne", + "col241": "acbrl", + "col242": "auwe8", + "col243": "an57u", + "col244": "ckjve", + "col245": "37awy", + "col246": "2zca5", + "col247": "fnwek", + "col248": "y3rgr", + "col249": "3rkh6", + "col250": "gn2kc", + "col251": "zbf19", + "col252": "b9jdt", + "col253": "60q67", + "col254": "ibcig", + "col255": "e79mm", + "col256": "mlrdi", + "col257": "3grsq", + "col258": "891w0", + "col259": "c0jum", + "col260": "6gmr9", + "col261": "ttigr", + "col262": "93rxo", + "col263": "ne8j9", + "col264": "1u67b", + "col265": "kgd60", + "col266": "dpt3o", + "col267": "5wqg4", + "col268": "4vr42", + "col269": "gr6vj", + "col270": "zglw6", + "col271": "d5udv", + "col272": "s7igw", + "col273": "azohi", + "col274": "jbmhn", + "col275": "q55rp", + "col276": "ame5p", + "col277": "qdu9r", + "col278": "sm5ji", + "col279": "bhmnh", + "col280": "t0aj9", + "col281": "cqenh", + "col282": "mg7pb", + "col283": "umgpm", + "col284": "34m71", + "col285": "sgivx", + "col286": "vstvp", + "col287": "5xwjy", + "col288": "yjjjs", + "col289": "0o9pa", + "col290": "9osem", + "col291": "0ttio", + "col292": "mv9z0", + "col293": "xynso", + "col294": "pmjnn", + "col295": "75kn9", + "col296": "u0bca", + "col297": "tpdka", + "col298": "j7pgr", + "col299": "0gasd", + "col300": "4s919", + "col301": "hmh04", + "col302": "811yq", + "col303": "2sbvd", + "col304": "98tp1", + "col305": "jglk4", + "col306": "wmxta", + "col307": "yba7n", + "col308": "5xw7c", + "col309": "bsfte", + "col310": "zea98", + "col311": "zer60", + "col312": "ndabc", + "col313": "gb4px", + "col314": "dhm35", + "col315": "j9wv4", + "col316": "6np09", + "col317": "7repf", + "col318": "uucaf", + "col319": "0j3vc", + "col320": "vvtkf", + "col321": "tg073", + "col322": "ytwmc", + "col323": "ayj7z", + "col324": "7gfqv", + "col325": "55282", + "col326": "7z9w0", + "col327": "5ycfj", + "col328": "5wc3b", + "col329": "phq92", + "col330": "uri4d", + "col331": "ihhd2", + "col332": "8av81", + "col333": "q953x", + "col334": "p1kz7", + "col335": "l32o8", + "col336": "2h412", + "col337": "kft13", + "col338": "5s5ke", + "col339": "i0o65", + "col340": "dvhy8", + "col341": "q431n", + "col342": "21sf0", + "col343": "a9b9b", + "col344": "69hxt", + "col345": "vp4gr", + "col346": "9rlb7", + "col347": "naquj", + "col348": "fbhjb", + "col349": "7naih", + "col350": "xfbjv", + "col351": "k06cx", + "col352": "s44uc", + "col353": "6w7eu", + "col354": "mcd75", + "col355": "33sux", + "col356": "qj41g", + "col357": "e3nrx", + "col358": "flugz", + "col359": "m8cyv", + "col360": "cczkp", + "col361": "t2f5f", + "col362": "oklji", + "col363": "iksqc", + "col364": "5x606", + "col365": "dkr1m", + "col366": "0rh2c", + "col367": "bl09y", + "col368": "bbkrt", + "col369": "edje3", + "col370": "g5p2f", + "col371": "hlv60", + "col372": "o1587", + "col373": "mej09", + "col374": "6xky0", + "col375": "awyi0", + "col376": "jn7yx", + "col377": "yaxr7", + "col378": "p3da7", + "col379": "ftb51", + "col380": "dkg4n", + "col381": "m1uo5", + "col382": "0gksk", + "col383": "74e7p", + "col384": "qug6k", + "col385": "gu7dv", + "col386": "99sc8", + "col387": "ir32x", + "col388": "82c5q", + "col389": "ckfqo", + "col390": "oao9y", + "col391": "2ixu9", + "col392": "xw2th", + "col393": "q4482", + "col394": "cnf23", + "col395": "hygh8", + "col396": "j2wc8", + "col397": "b1la6", + "col398": "fx6om", + "col399": "cyi3c", + "col400": "7nnv7", + "col401": "f0d75", + "col402": "z2e5w", + "col403": "e18b9", + "col404": "sapsh", + "col405": "zrp2l", + "col406": "qhm6k", + "col407": "iuvrg", + "col408": "okfy0", + "col409": "eyi9b", + "col410": "3rnjy", + "col411": "hymw1", + "col412": "1gbj1", + "col413": "2jibw", + "col414": "d1s7n", + "col415": "qq3q5", + "col416": "g8t14", + "col417": "cyou2", + "col418": "a5vgp", + "col419": "bp52o", + "col420": "ookag", + "col421": "2rb7n", + "col422": "bupqw", + "col423": "3cm2o", + "col424": "xw43x", + "col425": "sup05", + "col426": "dxcob", + "col427": "0oa6s", + "col428": "0k9o3", + "col429": "3ozvf", + "col430": "ye7at", + "col431": "atnbv", + "col432": "pg5r7", + "col433": "w10w6", + "col434": "4rmws", + "col435": "bnoiz", + "col436": "mz54i", + "col437": "1s0on", + "col438": "g9rym", + "col439": "tupdd", + "col440": "n1hrb", + "col441": "xer0z", + "col442": "ip2a8", + "col443": "evmz4", + "col444": "hng87", + "col445": "3pgae", + "col446": "i0v0a", + "col447": "y56o4", + "col448": "w89qs", + "col449": "gi53k", + "col450": "5ai8j", + "col451": "otkh2", + "col452": "x1ppt", + "col453": "ncs0t", + "col454": "t962t", + "col455": "9jaim", + "col456": "gagyb", + "col457": "xdda5", + "col458": "krd9i", + "col459": "2i2nu", + "col460": "us0nu", + "col461": "041d3", + "col462": "2mgi2", + "col463": "3tana", + "col464": "m5r7i", + "col465": "g3qse", + "col466": "t14uq", + "col467": "8mbh8", + "col468": "6hjoy", + "col469": "u4tle", + "col470": "lms6a", + "col471": "yf57j", + "col472": "b748f", + "col473": "7opy2", + "col474": "oy7f8", + "col475": "tza5a", + "col476": "mlglf", + "col477": "3t3zz", + "col478": "pba8m", + "col479": "lcuiw", + "col480": "423jl", + "col481": "u530d", + "col482": "dbyzf", + "col483": "wd0w3", + "col484": "7qn08", + "col485": "mgs7x", + "col486": "4pyh6", + "col487": "c9h8w", + "col488": "cdxm6", + "col489": "p1cn5", + "col490": "3wfd8", + "col491": "2r85z", + "col492": "zeeya", + "col493": "w0ur6", + "col494": "7mylw", + "col495": "1ejmv", + "col496": "8tin7", + "col497": "bh2u8", + "col498": "eicng", + "col499": "n9vxu", + "col500": "8mjfa", + "col501": "x9bva", + "col502": "1zy9k", + "col503": "uo8n3", + "col504": "yb1tt", + "col505": "1c5o0", + "col506": "upur9", + "col507": "o6wzr", + "col508": "5x8tu", + "col509": "p6ds8", + "col510": "36w6q", + "col511": "970w4", + "col512": "sqbwb", + "col513": "5nsxg", + "col514": "311lz", + "col515": "fl77v", + "col516": "gx2t4", + "col517": "fpfh6", + "col518": "lecx0", + "col519": "utqvp", + "col520": "69djg", + "col521": "0ns24", + "col522": "pg1np", + "col523": "z2zyk", + "col524": "1lonm", + "col525": "p0ct2", + "col526": "xzp34", + "col527": "35t82", + "col528": "m5ybd", + "col529": "9xs5g", + "col530": "1ycp4", + "col531": "x8fao", + "col532": "esxic", + "col533": "ryn55", + "col534": "kgpzv", + "col535": "loect", + "col536": "488my", + "col537": "nbirx", + "col538": "e9g5o", + "col539": "tpewh", + "col540": "iz4gg", + "col541": "b0jrr", + "col542": "8u6d0", + "col543": "vfm15", + "col544": "bdzwn", + "col545": "fhjsx", + "col546": "ya8m3", + "col547": "wm824", + "col548": "bzycd", + "col549": "3i4os", + "col550": "807hz", + "col551": "mom76", + "col552": "w95u7", + "col553": "ffr08", + "col554": "o5xxf", + "col555": "0egb3", + "col556": "65kfd", + "col557": "8y1zm", + "col558": "jyxa7", + "col559": "8g25u", + "col560": "3fseo", + "col561": "8282l", + "col562": "7iwoo", + "col563": "e3gou", + "col564": "pghq5", + "col565": "f6oce", + "col566": "9ki8l", + "col567": "wqmi2", + "col568": "y38ht", + "col569": "zjqen", + "col570": "rh4kr", + "col571": "jv49d", + "col572": "4f347", + "col573": "8v0tr", + "col574": "y8e5m", + "col575": "zrzx1", + "col576": "emumx", + "col577": "73xwt", + "col578": "5w77o", + "col579": "4yred", + "col580": "h258n", + "col581": "iuw9r", + "col582": "og4ga", + "col583": "mr090", + "col584": "4t7yk", + "col585": "hkmrv", + "col586": "fjwsv", + "col587": "qkbgo", + "col588": "4gecu", + "col589": "u8fqv", + "col590": "jg59q", + "col591": "064ox", + "col592": "b26ib", + "col593": "67n5m", + "col594": "lvdi8", + "col595": "4n44j", + "col596": "lq9f4", + "col597": "1gwys", + "col598": "96y49", + "col599": "j2yfu", + "col600": "g4n0x", + "col601": "5zb7n", + "col602": "ze7u6", + "col603": "4jnac", + "col604": "wwrzi", + "col605": "hdpt9", + "col606": "uoerc", + "col607": "xhd1s", + "col608": "dslnn", + "col609": "mhqxp", + "col610": "1s6dy", + "col611": "6vdfz", + "col612": "6zhyq", + "col613": "88k51", + "col614": "o3d1q", + "col615": "fgl4n", + "col616": "t1e8t", + "col617": "sf6yj", + "col618": "4gnw9", + "col619": "6c485", + "col620": "pk914", + "col621": "c6d9i", + "col622": "2tz48", + "col623": "kjo5f", + "col624": "gpr2v", + "col625": "64ve0", + "col626": "3qrfu", + "col627": "j9er7", + "col628": "sgbl2", + "col629": "nugdt", + "col630": "6nsgu", + "col631": "0n0c3", + "col632": "u3611", + "col633": "cd7xw", + "col634": "xo7sk", + "col635": "4rxvk", + "col636": "v877z", + "col637": "l461u", + "col638": "68cgh", + "col639": "2kv6q", + "col640": "mzbq8", + "col641": "ckfxr", + "col642": "deai9", + "col643": "qezla", + "col644": "4la9i", + "col645": "el7ht", + "col646": "fvg0q", + "col647": "epfem", + "col648": "9l6s7", + "col649": "osi1w", + "col650": "b9m09", + "col651": "9qv5n", + "col652": "8ptli", + "col653": "188x8", + "col654": "q5xl0", + "col655": "jh99v", + "col656": "q5vkv", + "col657": "9iekm", + "col658": "ft3wi", + "col659": "lv66a", + "col660": "2e7lv", + "col661": "nmo53", + "col662": "x10s4", + "col663": "iaebo", + "col664": "kh02u", + "col665": "vflrw", + "col666": "fi24a", + "col667": "fd11p", + "col668": "euf76", + "col669": "3vl1p", + "col670": "zfaji", + "col671": "2m5g5", + "col672": "73fri", + "col673": "8mc7w", + "col674": "0de0z", + "col675": "hcoma", + "col676": "w4bfz", + "col677": "f9qt7", + "col678": "gr82s", + "col679": "xc8ft", + "col680": "76dyr", + "col681": "5tek9", + "col682": "yp1hr", + "col683": "92htw", + "col684": "4ds5h", + "col685": "mcjmv", + "col686": "n953w", + "col687": "0aaiq", + "col688": "11ppf", + "col689": "fuvt2", + "col690": "kdvgk", + "col691": "rxoy1", + "col692": "sae8s", + "col693": "zl8i8", + "col694": "rp79k", + "col695": "adg01", + "col696": "frbiv", + "col697": "tmfqz", + "col698": "y51eg", + "col699": "c3usa", + "col700": "gej5j", + "col701": "qe46b", + "col702": "pvxiu", + "col703": "if8af", + "col704": "pk16v", + "col705": "lj1fo", + "col706": "qglm1", + "col707": "4gfc8", + "col708": "obide", + "col709": "uv5fo", + "col710": "i6lex", + "col711": "whi9r", + "col712": "m5cpm", + "col713": "ddrty", + "col714": "pzutu", + "col715": "m9156", + "col716": "1k1vr", + "col717": "2w3kt", + "col718": "bm38u", + "col719": "8xj5h", + "col720": "ief90", + "col721": "fblmy", + "col722": "7x7fe", + "col723": "ttjwy", + "col724": "4hpve", + "col725": "18brv", + "col726": "o497h", + "col727": "27zcw", + "col728": "pdkh9", + "col729": "fpsmw", + "col730": "gwlp8", + "col731": "qu5i0", + "col732": "pjqk3", + "col733": "6ekzj", + "col734": "imdmo", + "col735": "rslhp", + "col736": "f0xdr", + "col737": "l6pyz", + "col738": "alxz0", + "col739": "wpwg7", + "col740": "uijda", + "col741": "by9iw", + "col742": "g85zi", + "col743": "locbg", + "col744": "nznvq", + "col745": "wlmdm", + "col746": "thk2m", + "col747": "hkj17", + "col748": "38572", + "col749": "90hzd", + "col750": "37w54", + "col751": "mna4p", + "col752": "1dlrh", + "col753": "wosvk", + "col754": "j8vmv", + "col755": "7guob", + "col756": "9rqse", + "col757": "wdc7m", + "col758": "sd8m4", + "col759": "en851", + "col760": "cdqfk", + "col761": "utdxo", + "col762": "0k2hd", + "col763": "ys15d", + "col764": "2w6lf", + "col765": "hi0g6", + "col766": "kelz2", + "col767": "yrnwi", + "col768": "noblb", + "col769": "15753", + "col770": "uw6cm", + "col771": "684xt", + "col772": "gb1au", + "col773": "72i5n", + "col774": "jkmeo", + "col775": "6rpbb", + "col776": "ogvvi", + "col777": "hcv7l", + "col778": "dnfgv", + "col779": "oiz35", + "col780": "golpm", + "col781": "zf51o", + "col782": "sv60h", + "col783": "j6k2m", + "col784": "zx50l", + "col785": "rd010", + "col786": "a3ib6", + "col787": "vtdg0", + "col788": "hbsx7", + "col789": "2r9mo", + "col790": "mcmb3", + "col791": "vyxiz", + "col792": "9vhi4", + "col793": "ar4tm", + "col794": "0g7d6", + "col795": "fuax5", + "col796": "9lm29", + "col797": "txrmr", + "col798": "izdsn", + "col799": "v24q4", + "col800": "yhv6q", + "col801": "siiwo", + "col802": "ss8n9", + "col803": "568d3", + "col804": "v0lzl", + "col805": "irjpn", + "col806": "315vk", + "col807": "miufd", + "col808": "xfrxr", + "col809": "xzyu4", + "col810": "el4m7", + "col811": "xc6r1", + "col812": "eyye2", + "col813": "th4ix", + "col814": "kdi2e", + "col815": "lvxr4", + "col816": "2iikp", + "col817": "5t1hw", + "col818": "z83d4", + "col819": "nyd0c", + "col820": "8h6t7", + "col821": "5pswn", + "col822": "t5ace", + "col823": "zo6fi", + "col824": "hfrw0", + "col825": "itglo", + "col826": "qv0fq", + "col827": "d5ipx", + "col828": "1oh2r", + "col829": "jaunt", + "col830": "kjt8v", + "col831": "b69t6", + "col832": "gqurf", + "col833": "d321b", + "col834": "45j6i", + "col835": "g9tpd", + "col836": "g8bql", + "col837": "2pl2q", + "col838": "pbdl9", + "col839": "rplg6", + "col840": "360ml", + "col841": "59iyt", + "col842": "5nity", + "col843": "f0h3k", + "col844": "1seia", + "col845": "orlqw", + "col846": "srxdb", + "col847": "v1vv6", + "col848": "ra8t2", + "col849": "93ykp", + "col850": "7jc4y", + "col851": "z54cs", + "col852": "kr1vc", + "col853": "usgad", + "col854": "hk1a5", + "col855": "i2acr", + "col856": "pntqo", + "col857": "x4plx", + "col858": "ldyw0", + "col859": "mgkt8", + "col860": "q6p8c", + "col861": "4xz1f", + "col862": "umkph", + "col863": "hgc3p", + "col864": "zk5ij", + "col865": "mn9q8", + "col866": "xuivv", + "col867": "kplug", + "col868": "z8w19", + "col869": "8isx5", + "col870": "qjb22", + "col871": "pjzma", + "col872": "la652", + "col873": "h1izu", + "col874": "v7wbk", + "col875": "mzmig", + "col876": "g7mg4", + "col877": "frwyy", + "col878": "kxf2g", + "col879": "rjxko", + "col880": "sqne7", + "col881": "eu3fj", + "col882": "jh6by", + "col883": "gcfc3", + "col884": "odrbk", + "col885": "gfpb0", + "col886": "ng9jn", + "col887": "6b3za", + "col888": "feqnw", + "col889": "gjexm", + "col890": "2jfg8", + "col891": "uo4nt", + "col892": "ms24c", + "col893": "yji65", + "col894": "lakek", + "col895": "u9h4y", + "col896": "63o9r", + "col897": "s5z6k", + "col898": "umt6f", + "col899": "dsnwh", + "col900": "ft865", + "col901": "yqmrt", + "col902": "9gbv5", + "col903": "5qk6h", + "col904": "ccauz", + "col905": "5jnpr", + "col906": "ol4n7", + "col907": "2kd81", + "col908": "o4wzw", + "col909": "twrdz", + "col910": "woix1", + "col911": "x6n23", + "col912": "jz9v9", + "col913": "neq7u", + "col914": "6bjpn", + "col915": "6t4h2", + "col916": "2jk71", + "col917": "65avb", + "col918": "7zwac", + "col919": "vwtah", + "col920": "qwcec", + "col921": "mw5er", + "col922": "mf11i", + "col923": "pmqmm", + "col924": "8uvoj", + "col925": "0v75l", + "col926": "v8j2c", + "col927": "o2vul", + "col928": "707th", + "col929": "5zur9", + "col930": "kvwjd", + "col931": "fgg4n", + "col932": "cbbiq", + "col933": "ket2c", + "col934": "84rk7", + "col935": "v6vtc", + "col936": "sidgi", + "col937": "14jls", + "col938": "lmdjb", + "col939": "0k5x3", + "col940": "aej6y", + "col941": "zbg09", + "col942": "w3z82", + "col943": "jlpq2", + "col944": "vpjyt", + "col945": "asazt", + "col946": "2onsr", + "col947": "u2ck7", + "col948": "8atdk", + "col949": "mtjkd", + "col950": "vsfhg", + "col951": "9kshr", + "col952": "0em1o", + "col953": "hwzij", + "col954": "bbax0", + "col955": "9krg9", + "col956": "d4pfw", + "col957": "et3iy", + "col958": "h8q71", + "col959": "b4fmd", + "col960": "0r8jf", + "col961": "1tqai", + "col962": "gu9zj", + "col963": "vjfu3", + "col964": "9ecz2", + "col965": "u0u7v", + "col966": "j8h3a", + "col967": "6wy2u", + "col968": "mv4ev", + "col969": "jtwp7", + "col970": "qaef0", + "col971": "p6emz", + "col972": "jrvtl", + "col973": "q5dup", + "col974": "qkrpk", + "col975": "eqwpw", + "col976": "rtxc8", + "col977": "2gvd5", + "col978": "4uj57", + "col979": "ahad1", + "col980": "k7xs0", + "col981": "gjz8x", + "col982": "zg2rz", + "col983": "ciwpo", + "col984": "kx0hu", + "col985": "8ek3w", + "col986": "9dzz8", + "col987": "pei9g", + "col988": "0jic9", + "col989": "52z2i", + "col990": "oki6w", + "col991": "7qom3", + "col992": "jf8zs", + "col993": "mr10g", + "col994": "a2i28", + "col995": "rmnil", + "col996": "csng3", + "col997": "9caqb", + "col998": "juy8p", + "col999": "tkhzi" + }, + { + "name": "Farley Melton", + "gender": "male", + "col0": "7o1q6", + "col1": "mttkw", + "col2": "pmpzy", + "col3": "jvnau", + "col4": "fe4hl", + "col5": "c7lhr", + "col6": "rwb9n", + "col7": "ewhx7", + "col8": "eti0f", + "col9": "uymww", + "col10": "84fph", + "col11": "sfod5", + "col12": "f508t", + "col13": "v8jxm", + "col14": "4lv5v", + "col15": "j0xys", + "col16": "1ingc", + "col17": "jcudy", + "col18": "0civn", + "col19": "o3pe3", + "col20": "qhgej", + "col21": "mcyja", + "col22": "j6rq0", + "col23": "pm6yn", + "col24": "2ctio", + "col25": "smhg1", + "col26": "ivtn5", + "col27": "lelyi", + "col28": "t3xx2", + "col29": "nx18j", + "col30": "i8yu2", + "col31": "dkt49", + "col32": "fvn30", + "col33": "jcjiz", + "col34": "5bc8i", + "col35": "2nddb", + "col36": "918e0", + "col37": "b2pdr", + "col38": "cn6os", + "col39": "1b8jt", + "col40": "sfpoo", + "col41": "i9cv6", + "col42": "74ci1", + "col43": "a3ax6", + "col44": "srxst", + "col45": "yhlkp", + "col46": "7wa9h", + "col47": "svwlm", + "col48": "mwehx", + "col49": "pdvaz", + "col50": "9m39g", + "col51": "izrm4", + "col52": "ho9nt", + "col53": "5cb4n", + "col54": "7le02", + "col55": "szlzj", + "col56": "jgmg6", + "col57": "75v1q", + "col58": "otfrt", + "col59": "wsmnp", + "col60": "vlibm", + "col61": "ypfpa", + "col62": "b1ruo", + "col63": "nk5zl", + "col64": "n63rt", + "col65": "0bea2", + "col66": "qid9y", + "col67": "gzjgd", + "col68": "yehi5", + "col69": "2nqvy", + "col70": "mublt", + "col71": "d501q", + "col72": "sg7b5", + "col73": "0f9ey", + "col74": "2tfb9", + "col75": "gop0d", + "col76": "f302m", + "col77": "r6b5k", + "col78": "s6lb4", + "col79": "h0kim", + "col80": "9aqgb", + "col81": "6n9zm", + "col82": "a6qwx", + "col83": "nqt60", + "col84": "z1ab3", + "col85": "ucyoj", + "col86": "a1vq8", + "col87": "jzy6y", + "col88": "goaqf", + "col89": "p31um", + "col90": "2owzp", + "col91": "ai3y3", + "col92": "lqy8k", + "col93": "xsrym", + "col94": "ollsn", + "col95": "pb59j", + "col96": "iuozk", + "col97": "3e3k2", + "col98": "mmohz", + "col99": "oaosq", + "col100": "7uass", + "col101": "p9a1e", + "col102": "vqegg", + "col103": "9h19c", + "col104": "m6fh5", + "col105": "ljmc2", + "col106": "a6d76", + "col107": "4mvhe", + "col108": "djo9c", + "col109": "yddzj", + "col110": "akl99", + "col111": "pad61", + "col112": "w0q3g", + "col113": "92a7l", + "col114": "w7b2t", + "col115": "bmlpq", + "col116": "608a2", + "col117": "jh2a1", + "col118": "zp0oj", + "col119": "yfptl", + "col120": "vmie0", + "col121": "m52bp", + "col122": "lmtsv", + "col123": "tokgc", + "col124": "bdfmk", + "col125": "zcw5y", + "col126": "e5cqs", + "col127": "x8caf", + "col128": "9162p", + "col129": "7x70k", + "col130": "pk1k0", + "col131": "mr1ph", + "col132": "jb454", + "col133": "pgnch", + "col134": "heuy6", + "col135": "76kzn", + "col136": "jpqzx", + "col137": "uh9vt", + "col138": "syzd7", + "col139": "3jkje", + "col140": "0e5d5", + "col141": "otjy1", + "col142": "gmhzl", + "col143": "ahois", + "col144": "uuasd", + "col145": "ephpb", + "col146": "is1ft", + "col147": "9z2gu", + "col148": "ivhd0", + "col149": "4mbxf", + "col150": "4hdyd", + "col151": "lzyoi", + "col152": "iuwv4", + "col153": "ceqy0", + "col154": "lh8vd", + "col155": "zbw5c", + "col156": "91nbu", + "col157": "pvtwt", + "col158": "ze9fp", + "col159": "lrvbe", + "col160": "8icpj", + "col161": "2w9af", + "col162": "9b1f0", + "col163": "497dc", + "col164": "mrr7w", + "col165": "h8g8m", + "col166": "1rdmy", + "col167": "nco56", + "col168": "tsobu", + "col169": "wmnw2", + "col170": "fkooa", + "col171": "sqoxm", + "col172": "848b7", + "col173": "zfvsl", + "col174": "pbp4y", + "col175": "2dpts", + "col176": "m9upn", + "col177": "4mohw", + "col178": "ykuyb", + "col179": "yv92u", + "col180": "kznqt", + "col181": "a43d3", + "col182": "7620q", + "col183": "66wzr", + "col184": "6vv6n", + "col185": "24x4b", + "col186": "gvtkx", + "col187": "hjmj9", + "col188": "azxpi", + "col189": "2u6il", + "col190": "f3pby", + "col191": "73qp9", + "col192": "v7pu1", + "col193": "fanl8", + "col194": "2pg1u", + "col195": "bqggd", + "col196": "inkfc", + "col197": "ok3pi", + "col198": "bpqwy", + "col199": "kvrks", + "col200": "drmly", + "col201": "q46z6", + "col202": "yn6ft", + "col203": "266i4", + "col204": "meubi", + "col205": "whuav", + "col206": "6fu31", + "col207": "eyw97", + "col208": "wvrtr", + "col209": "hdwwz", + "col210": "0go3z", + "col211": "miouy", + "col212": "edseu", + "col213": "bnm2f", + "col214": "li7ff", + "col215": "zig1n", + "col216": "m0yr5", + "col217": "zfkdp", + "col218": "52jyp", + "col219": "tgveb", + "col220": "055jm", + "col221": "dglrw", + "col222": "6ujgy", + "col223": "i5fi0", + "col224": "3okg0", + "col225": "6v4c7", + "col226": "a49ya", + "col227": "t3iio", + "col228": "51brm", + "col229": "ccl7r", + "col230": "thdds", + "col231": "c0qah", + "col232": "i6aen", + "col233": "zq2xy", + "col234": "q2j3n", + "col235": "d1yic", + "col236": "kn6to", + "col237": "bacuv", + "col238": "1jpyz", + "col239": "j8ee8", + "col240": "7dfir", + "col241": "r7qhc", + "col242": "g72sc", + "col243": "6bzux", + "col244": "zl8ku", + "col245": "e1tj1", + "col246": "5ko07", + "col247": "cwpe0", + "col248": "szih5", + "col249": "z863p", + "col250": "bzfyu", + "col251": "7st7o", + "col252": "p01pp", + "col253": "bl65y", + "col254": "du1o2", + "col255": "j3mo0", + "col256": "w70ha", + "col257": "2uaab", + "col258": "47xtn", + "col259": "e0g8e", + "col260": "gp6xe", + "col261": "toznf", + "col262": "zrqh3", + "col263": "odbkv", + "col264": "h0uue", + "col265": "uq417", + "col266": "f1xxg", + "col267": "j0qdh", + "col268": "wzx00", + "col269": "9yb2a", + "col270": "ouylw", + "col271": "r0qk2", + "col272": "gom3i", + "col273": "1raai", + "col274": "e10qd", + "col275": "0o4u6", + "col276": "7ch4e", + "col277": "frdda", + "col278": "pef7f", + "col279": "fqcgf", + "col280": "z28z2", + "col281": "siq2c", + "col282": "nttyq", + "col283": "mw0pt", + "col284": "0powe", + "col285": "95ewz", + "col286": "zgmdh", + "col287": "djwtv", + "col288": "9dqyq", + "col289": "wtidg", + "col290": "v29dz", + "col291": "vlkif", + "col292": "hfje9", + "col293": "xpb3l", + "col294": "ut11h", + "col295": "j8pfq", + "col296": "c21y6", + "col297": "iwca0", + "col298": "jvlr5", + "col299": "tfth4", + "col300": "79am7", + "col301": "54rtg", + "col302": "8vzxd", + "col303": "zoz45", + "col304": "1dbxa", + "col305": "iusz1", + "col306": "devts", + "col307": "0a2jo", + "col308": "ebpid", + "col309": "311rp", + "col310": "zkihg", + "col311": "6r6hj", + "col312": "7ejjc", + "col313": "hde1l", + "col314": "bzeg1", + "col315": "vakth", + "col316": "w474b", + "col317": "idu92", + "col318": "xr0f4", + "col319": "1u7kt", + "col320": "2ebkp", + "col321": "vd68p", + "col322": "cdjxn", + "col323": "oo1pd", + "col324": "6iiib", + "col325": "jxzr3", + "col326": "qkzl3", + "col327": "lbhht", + "col328": "3cb44", + "col329": "6ihsd", + "col330": "jvx8y", + "col331": "rj6lo", + "col332": "4ibun", + "col333": "w5nbq", + "col334": "hrzwm", + "col335": "fp1t0", + "col336": "ig846", + "col337": "m8kym", + "col338": "x4tu0", + "col339": "l7hcq", + "col340": "ojlcx", + "col341": "3g3in", + "col342": "j449n", + "col343": "cbd6j", + "col344": "5i8qr", + "col345": "gummm", + "col346": "y42m7", + "col347": "uqkex", + "col348": "onadh", + "col349": "spnjj", + "col350": "07sxo", + "col351": "xtoh2", + "col352": "weknz", + "col353": "ucp3m", + "col354": "2r4g3", + "col355": "cnt75", + "col356": "8qutc", + "col357": "9ynzq", + "col358": "hwn0s", + "col359": "uv7a3", + "col360": "i1blj", + "col361": "lg7zf", + "col362": "fkb43", + "col363": "4vc1t", + "col364": "67ysa", + "col365": "scpj5", + "col366": "ax8dy", + "col367": "m5a21", + "col368": "t6jz8", + "col369": "m4368", + "col370": "zm6ad", + "col371": "tr07s", + "col372": "yasdf", + "col373": "w5nz0", + "col374": "60d10", + "col375": "3dyf8", + "col376": "pszqi", + "col377": "zxaxt", + "col378": "ex7rp", + "col379": "4zw75", + "col380": "t5133", + "col381": "czbks", + "col382": "vwnur", + "col383": "sdsi3", + "col384": "wnypi", + "col385": "yootl", + "col386": "fvl8u", + "col387": "sm057", + "col388": "htph5", + "col389": "mccft", + "col390": "tltfn", + "col391": "aaqb3", + "col392": "loczz", + "col393": "yvu6y", + "col394": "cyfzc", + "col395": "qcyys", + "col396": "3omao", + "col397": "ncbw4", + "col398": "dqbg7", + "col399": "n7z94", + "col400": "99jlm", + "col401": "al99g", + "col402": "ah2ht", + "col403": "tg161", + "col404": "afe47", + "col405": "ufyp3", + "col406": "qyakq", + "col407": "qn9mf", + "col408": "m83ts", + "col409": "i1mdf", + "col410": "768zq", + "col411": "booku", + "col412": "e0235", + "col413": "y11co", + "col414": "w5732", + "col415": "h1400", + "col416": "lw3cy", + "col417": "1hica", + "col418": "mdadh", + "col419": "lajws", + "col420": "jcap4", + "col421": "aaoza", + "col422": "jolgg", + "col423": "wovy6", + "col424": "mm3yc", + "col425": "jc2tl", + "col426": "nb2hs", + "col427": "dn9uc", + "col428": "4gxlc", + "col429": "4mq4p", + "col430": "3nj8g", + "col431": "so02q", + "col432": "057hp", + "col433": "krk64", + "col434": "e338j", + "col435": "awme9", + "col436": "a214p", + "col437": "zf6kt", + "col438": "8l1bk", + "col439": "r9xpx", + "col440": "9p0mc", + "col441": "foef7", + "col442": "6g216", + "col443": "2nkjz", + "col444": "gs7ty", + "col445": "99phq", + "col446": "w5fqy", + "col447": "j79t5", + "col448": "h900v", + "col449": "wbuii", + "col450": "yhuxu", + "col451": "dt6gf", + "col452": "ftwwl", + "col453": "g0w0n", + "col454": "ye3ao", + "col455": "q197m", + "col456": "pstqy", + "col457": "2yf7n", + "col458": "9sq8w", + "col459": "qhi1f", + "col460": "7gqmw", + "col461": "skzx2", + "col462": "v0dyh", + "col463": "fcl1u", + "col464": "vwmqu", + "col465": "y28yv", + "col466": "t1clp", + "col467": "ijujn", + "col468": "qukta", + "col469": "iaf07", + "col470": "8pm3v", + "col471": "yosmp", + "col472": "uwxrl", + "col473": "3ipaa", + "col474": "orn6a", + "col475": "xeptv", + "col476": "gnzw4", + "col477": "6bz1l", + "col478": "9rb2s", + "col479": "h6tj6", + "col480": "vikou", + "col481": "88fui", + "col482": "bq5uy", + "col483": "131lt", + "col484": "nht7d", + "col485": "vh3ix", + "col486": "ppsp4", + "col487": "z59ru", + "col488": "6ilzx", + "col489": "oi8s9", + "col490": "ndjpe", + "col491": "4rzyv", + "col492": "cfjd6", + "col493": "s2slg", + "col494": "8qcpt", + "col495": "aaub6", + "col496": "z2cao", + "col497": "l488r", + "col498": "1eyvw", + "col499": "sb8jn", + "col500": "wtz9i", + "col501": "k86bd", + "col502": "rpl98", + "col503": "bs9nc", + "col504": "n4n3v", + "col505": "msl61", + "col506": "fgf6u", + "col507": "ac2g5", + "col508": "qbvgf", + "col509": "qvsex", + "col510": "5p48n", + "col511": "ykc6m", + "col512": "tkdi6", + "col513": "gvr9e", + "col514": "3h4wr", + "col515": "bheiu", + "col516": "663b6", + "col517": "l0kz3", + "col518": "5vro6", + "col519": "6iwk4", + "col520": "fdtkr", + "col521": "byloh", + "col522": "hpe27", + "col523": "x0ph3", + "col524": "kz9qm", + "col525": "hbfnm", + "col526": "7gfs5", + "col527": "ud7uc", + "col528": "ju178", + "col529": "z1g0q", + "col530": "t6c5u", + "col531": "i9xoc", + "col532": "20raa", + "col533": "g2qpx", + "col534": "r6a4a", + "col535": "vu4ru", + "col536": "f1s08", + "col537": "0zo41", + "col538": "501hd", + "col539": "2ko9c", + "col540": "9bdf6", + "col541": "9v3rt", + "col542": "h6ad8", + "col543": "95d6p", + "col544": "hguoa", + "col545": "5xeer", + "col546": "uqhel", + "col547": "1qcx9", + "col548": "39qf4", + "col549": "s5luj", + "col550": "lmy7z", + "col551": "olr2t", + "col552": "1qwui", + "col553": "kku09", + "col554": "45w70", + "col555": "y3ici", + "col556": "vmxyo", + "col557": "z9tnc", + "col558": "5avaw", + "col559": "i6p6a", + "col560": "ilqu7", + "col561": "2w3sm", + "col562": "ividx", + "col563": "9b13s", + "col564": "8pmjb", + "col565": "b8m7n", + "col566": "jxe2l", + "col567": "d4n4y", + "col568": "0zvp4", + "col569": "zcno6", + "col570": "orjc7", + "col571": "pl4g1", + "col572": "efbus", + "col573": "dhgtd", + "col574": "mzw2u", + "col575": "q89yv", + "col576": "gz334", + "col577": "zdtfp", + "col578": "hu6fm", + "col579": "4qkis", + "col580": "i7q0e", + "col581": "mznax", + "col582": "a2r8b", + "col583": "459aq", + "col584": "803hg", + "col585": "158hi", + "col586": "c8opt", + "col587": "fx6o1", + "col588": "xd79z", + "col589": "usi8d", + "col590": "xmb8j", + "col591": "2dgpi", + "col592": "5h4oh", + "col593": "wzl6a", + "col594": "sy994", + "col595": "ntwtl", + "col596": "w6fpx", + "col597": "3kti0", + "col598": "t6qjh", + "col599": "te1r9", + "col600": "cclmy", + "col601": "7ssum", + "col602": "rm2y7", + "col603": "o4kqf", + "col604": "no3jn", + "col605": "ati93", + "col606": "loner", + "col607": "t1pbs", + "col608": "iad80", + "col609": "mqmc8", + "col610": "sdlef", + "col611": "u7doa", + "col612": "tyzdl", + "col613": "e49bg", + "col614": "en1jz", + "col615": "tg3g8", + "col616": "n9ld0", + "col617": "17hsn", + "col618": "eod8n", + "col619": "5z2o0", + "col620": "u2bqp", + "col621": "gquik", + "col622": "ya04u", + "col623": "7yu2s", + "col624": "6qpgq", + "col625": "0rkwf", + "col626": "iujoa", + "col627": "0skb0", + "col628": "a2irp", + "col629": "8yh9m", + "col630": "seeb2", + "col631": "oca1t", + "col632": "kgolm", + "col633": "j0yrf", + "col634": "ihk7e", + "col635": "k34i8", + "col636": "mm8dt", + "col637": "1jd76", + "col638": "45cn7", + "col639": "s7fod", + "col640": "f8ee5", + "col641": "elde6", + "col642": "omslp", + "col643": "06bnv", + "col644": "uuf2x", + "col645": "sj0gd", + "col646": "ib72a", + "col647": "9o0es", + "col648": "spltf", + "col649": "wwpxv", + "col650": "mh77u", + "col651": "j2q45", + "col652": "mfrk4", + "col653": "4z8ob", + "col654": "y11tx", + "col655": "iq0fv", + "col656": "afc6p", + "col657": "zunsa", + "col658": "7mk35", + "col659": "p8uu2", + "col660": "qugtk", + "col661": "9cdvy", + "col662": "m1io4", + "col663": "tl28z", + "col664": "3u9dp", + "col665": "kwe98", + "col666": "8ryij", + "col667": "shduk", + "col668": "rz4qn", + "col669": "uqyrv", + "col670": "a76au", + "col671": "7osr9", + "col672": "adz14", + "col673": "o6bju", + "col674": "h8jr3", + "col675": "iujym", + "col676": "ff8u8", + "col677": "0jikc", + "col678": "1fm3p", + "col679": "osud4", + "col680": "30ffy", + "col681": "xr7s5", + "col682": "7hsbl", + "col683": "wn5vu", + "col684": "zwhw8", + "col685": "w9n0z", + "col686": "5ilg0", + "col687": "n3awh", + "col688": "jz430", + "col689": "x8jv0", + "col690": "fkwqw", + "col691": "xu0cl", + "col692": "jssvo", + "col693": "c9at2", + "col694": "vqq6c", + "col695": "6ixdy", + "col696": "wmrzu", + "col697": "txmsr", + "col698": "674im", + "col699": "0l91t", + "col700": "347f4", + "col701": "wtls0", + "col702": "kx59x", + "col703": "s92cs", + "col704": "u1yjq", + "col705": "uoatj", + "col706": "59f9q", + "col707": "rlw9y", + "col708": "v1j0k", + "col709": "ir4qu", + "col710": "vp8sv", + "col711": "wgfgi", + "col712": "ysg0g", + "col713": "wjin4", + "col714": "2gxz1", + "col715": "ctl9i", + "col716": "8ltwt", + "col717": "lgm14", + "col718": "g4cpt", + "col719": "cmjtj", + "col720": "0huhq", + "col721": "bg9xl", + "col722": "wn6tq", + "col723": "8j7hz", + "col724": "szyvo", + "col725": "xte2b", + "col726": "dsen8", + "col727": "hnuwl", + "col728": "j4zlz", + "col729": "avmx1", + "col730": "8k9bj", + "col731": "bjps3", + "col732": "z0fe6", + "col733": "6eatf", + "col734": "oqe8f", + "col735": "r95os", + "col736": "g7wal", + "col737": "3gbyj", + "col738": "lpv05", + "col739": "eqqvs", + "col740": "upxzo", + "col741": "b4vd4", + "col742": "tf1e3", + "col743": "mrkpf", + "col744": "td4ci", + "col745": "ebhwl", + "col746": "3pf3y", + "col747": "afnkx", + "col748": "wc9s4", + "col749": "y1oqd", + "col750": "dip8g", + "col751": "g7uqr", + "col752": "302yz", + "col753": "78dbo", + "col754": "y53mx", + "col755": "z3x4j", + "col756": "cte5x", + "col757": "a9uim", + "col758": "n9hzf", + "col759": "2m6sm", + "col760": "l9pmu", + "col761": "ndv40", + "col762": "fghqx", + "col763": "oot99", + "col764": "vbcv2", + "col765": "nllfi", + "col766": "qifhw", + "col767": "xilw4", + "col768": "olwpm", + "col769": "fvd5r", + "col770": "0swyn", + "col771": "7ensb", + "col772": "ghi0d", + "col773": "dpnty", + "col774": "o3t4n", + "col775": "jb0pq", + "col776": "loua9", + "col777": "8qg5r", + "col778": "k750m", + "col779": "pm9mx", + "col780": "4a2k2", + "col781": "vyhf2", + "col782": "xhw71", + "col783": "ortlh", + "col784": "1is4m", + "col785": "wmy3k", + "col786": "3ckks", + "col787": "16dv9", + "col788": "9lkd6", + "col789": "xdjo5", + "col790": "ds490", + "col791": "nis1j", + "col792": "kcm9e", + "col793": "s4van", + "col794": "kw6hz", + "col795": "0l826", + "col796": "272fk", + "col797": "bo2uh", + "col798": "ugqca", + "col799": "7pml0", + "col800": "gixln", + "col801": "8zbx5", + "col802": "x70v7", + "col803": "kpjta", + "col804": "2fx26", + "col805": "441yl", + "col806": "ghbhz", + "col807": "1zdq6", + "col808": "4gur8", + "col809": "rcazj", + "col810": "p2ev5", + "col811": "ii03q", + "col812": "35b9l", + "col813": "jrul8", + "col814": "sehch", + "col815": "fkwgd", + "col816": "40hrs", + "col817": "9zmce", + "col818": "hulyz", + "col819": "8dfo5", + "col820": "mf8cc", + "col821": "5ka95", + "col822": "9jocz", + "col823": "c05yh", + "col824": "zhgz6", + "col825": "0juy3", + "col826": "nmo9e", + "col827": "rhvxm", + "col828": "c0ddi", + "col829": "efm2t", + "col830": "dr9a1", + "col831": "oiaii", + "col832": "wx7pm", + "col833": "k8xgx", + "col834": "fob6i", + "col835": "58jf1", + "col836": "qbbh5", + "col837": "8yana", + "col838": "4jx00", + "col839": "70a7j", + "col840": "26v3n", + "col841": "slwoy", + "col842": "hdvhw", + "col843": "z9sx9", + "col844": "3u56b", + "col845": "dbcd5", + "col846": "wuc95", + "col847": "u4z3l", + "col848": "ep596", + "col849": "wymj2", + "col850": "u9eqv", + "col851": "2p1dp", + "col852": "sn92r", + "col853": "eg1qr", + "col854": "s8omk", + "col855": "rkjpn", + "col856": "hy1ny", + "col857": "de6ai", + "col858": "w5tk3", + "col859": "5yzry", + "col860": "7c57v", + "col861": "j2i35", + "col862": "fsuhr", + "col863": "21ixy", + "col864": "vsqlz", + "col865": "jipdv", + "col866": "cvp5g", + "col867": "4vocr", + "col868": "4iey2", + "col869": "1iqwo", + "col870": "4eiox", + "col871": "n8mro", + "col872": "bebgh", + "col873": "tsz9x", + "col874": "xcn9n", + "col875": "847ye", + "col876": "lo25l", + "col877": "z8mch", + "col878": "mau3s", + "col879": "f1w36", + "col880": "p2et3", + "col881": "hkylo", + "col882": "ws7nb", + "col883": "nvtr6", + "col884": "rddwq", + "col885": "gl8ae", + "col886": "jawjp", + "col887": "suwrh", + "col888": "s733b", + "col889": "ajfvn", + "col890": "xb2tg", + "col891": "wr0xk", + "col892": "zhzpm", + "col893": "b5zmr", + "col894": "p95eu", + "col895": "0wmjb", + "col896": "k32i6", + "col897": "v4p9y", + "col898": "2oixe", + "col899": "hedya", + "col900": "gy0y8", + "col901": "u0p25", + "col902": "ulr40", + "col903": "otsid", + "col904": "rgmn6", + "col905": "wzoyc", + "col906": "5qn1t", + "col907": "joco3", + "col908": "8xj34", + "col909": "c92xx", + "col910": "st4fy", + "col911": "csz5s", + "col912": "iqsy0", + "col913": "a0gr8", + "col914": "0mquk", + "col915": "b1lii", + "col916": "vpwrn", + "col917": "e3gqy", + "col918": "c4odt", + "col919": "xvy41", + "col920": "picz5", + "col921": "aodo0", + "col922": "61pzk", + "col923": "8i8oq", + "col924": "08xez", + "col925": "wqep1", + "col926": "0lqjw", + "col927": "1xgas", + "col928": "3enot", + "col929": "52u7r", + "col930": "m35kx", + "col931": "si43p", + "col932": "m4wag", + "col933": "7fz0f", + "col934": "btp4o", + "col935": "u861n", + "col936": "4whnb", + "col937": "hd1hq", + "col938": "d46y3", + "col939": "fiyzg", + "col940": "y3kft", + "col941": "ahg10", + "col942": "t5efc", + "col943": "hp5ef", + "col944": "aavfw", + "col945": "vodtt", + "col946": "ffb2l", + "col947": "bnc84", + "col948": "hqo3n", + "col949": "8wmvn", + "col950": "uixo0", + "col951": "ho3jb", + "col952": "g6iz3", + "col953": "s6lrs", + "col954": "t0ac8", + "col955": "7clnk", + "col956": "jewwq", + "col957": "lypgz", + "col958": "05248", + "col959": "pni0f", + "col960": "vlvcn", + "col961": "pv5tm", + "col962": "lwb8x", + "col963": "ttda1", + "col964": "xku98", + "col965": "sqacr", + "col966": "kuuff", + "col967": "c8djg", + "col968": "hd1vn", + "col969": "xles5", + "col970": "cf9gz", + "col971": "w22qv", + "col972": "bke1k", + "col973": "2rlna", + "col974": "6d6kt", + "col975": "h321v", + "col976": "s1aym", + "col977": "fporx", + "col978": "8h7tj", + "col979": "7kgmr", + "col980": "7nrxk", + "col981": "rp0td", + "col982": "k8w5l", + "col983": "u56v8", + "col984": "11x3i", + "col985": "bjgbi", + "col986": "2wdqd", + "col987": "ig9s9", + "col988": "cs79p", + "col989": "zg153", + "col990": "wf08i", + "col991": "zmreh", + "col992": "4qesd", + "col993": "ps4cs", + "col994": "vnrz4", + "col995": "lnzby", + "col996": "k361r", + "col997": "2k4re", + "col998": "ziwp2", + "col999": "qld70" + }, + { + "name": "Guy Chavez", + "gender": "male", + "col0": "0dmjy", + "col1": "m9od1", + "col2": "wn0os", + "col3": "qp9hq", + "col4": "uheom", + "col5": "gmwxt", + "col6": "9de59", + "col7": "x03ug", + "col8": "5iwsu", + "col9": "3wd4o", + "col10": "87yvc", + "col11": "02dg1", + "col12": "m6tth", + "col13": "ynnre", + "col14": "2j0x1", + "col15": "dbs53", + "col16": "bcb6v", + "col17": "q97n1", + "col18": "1kjy0", + "col19": "duu52", + "col20": "99lq6", + "col21": "i0izq", + "col22": "e2m0o", + "col23": "dpg93", + "col24": "2l068", + "col25": "7ejq7", + "col26": "b6uhe", + "col27": "l6uoi", + "col28": "ctmlh", + "col29": "fgrq1", + "col30": "xbuui", + "col31": "r31ua", + "col32": "ki9om", + "col33": "menmu", + "col34": "ybqko", + "col35": "7x1ip", + "col36": "gs2fh", + "col37": "rj3ov", + "col38": "wze74", + "col39": "47pik", + "col40": "k00nf", + "col41": "fth8b", + "col42": "uhka5", + "col43": "vxvyd", + "col44": "a3y4k", + "col45": "pdfqz", + "col46": "68kb4", + "col47": "71rk7", + "col48": "ae2r6", + "col49": "orsgw", + "col50": "8hrqn", + "col51": "35cct", + "col52": "l4ve4", + "col53": "kp9qy", + "col54": "a2v7e", + "col55": "rqexz", + "col56": "g3rxz", + "col57": "m6s90", + "col58": "qkxso", + "col59": "lxz0y", + "col60": "o8ipm", + "col61": "r1am2", + "col62": "tn352", + "col63": "lxwqw", + "col64": "depsj", + "col65": "su87s", + "col66": "z8i0l", + "col67": "2kz6s", + "col68": "ob7o2", + "col69": "ad18a", + "col70": "946jp", + "col71": "msqlh", + "col72": "3xcl1", + "col73": "ydf4o", + "col74": "kfqad", + "col75": "kka9a", + "col76": "itwqj", + "col77": "p15wl", + "col78": "at5wi", + "col79": "fhzk3", + "col80": "s1nj2", + "col81": "5wt4l", + "col82": "5hz79", + "col83": "2m20n", + "col84": "kkb7n", + "col85": "qeoni", + "col86": "pzj8h", + "col87": "vv47i", + "col88": "mn0pv", + "col89": "7thh7", + "col90": "6qr40", + "col91": "9w5wc", + "col92": "clqs1", + "col93": "3ag7j", + "col94": "z1y4m", + "col95": "3fei7", + "col96": "x8jo2", + "col97": "yf53w", + "col98": "1vvtd", + "col99": "uao8p", + "col100": "9dtri", + "col101": "ppp84", + "col102": "dxhah", + "col103": "y2912", + "col104": "o0wzi", + "col105": "mxnmi", + "col106": "ky5qf", + "col107": "rj0b4", + "col108": "tzs55", + "col109": "duy9j", + "col110": "7xdgp", + "col111": "z7d7z", + "col112": "344rf", + "col113": "prx6s", + "col114": "7uqhm", + "col115": "ffyao", + "col116": "ytz9c", + "col117": "66rd6", + "col118": "bbdrj", + "col119": "vegaa", + "col120": "bs7bn", + "col121": "4y7qp", + "col122": "5kkxt", + "col123": "sszwq", + "col124": "6sgr1", + "col125": "p0sff", + "col126": "u880r", + "col127": "f8nut", + "col128": "e6zv2", + "col129": "1rjvg", + "col130": "yyexk", + "col131": "qc6i2", + "col132": "rriub", + "col133": "rovli", + "col134": "py3pp", + "col135": "gypw1", + "col136": "r3ic4", + "col137": "cdlex", + "col138": "shv4x", + "col139": "h0kmr", + "col140": "wu7iq", + "col141": "m01ej", + "col142": "0svuv", + "col143": "43ka5", + "col144": "h30xn", + "col145": "d7rj3", + "col146": "9okdm", + "col147": "ctcvb", + "col148": "n99yg", + "col149": "nhvva", + "col150": "96p86", + "col151": "q6q8n", + "col152": "tpop1", + "col153": "3rree", + "col154": "65hgo", + "col155": "frub4", + "col156": "8ydak", + "col157": "951hg", + "col158": "3l9eg", + "col159": "45188", + "col160": "oq1tq", + "col161": "py38r", + "col162": "3l74i", + "col163": "c7a5h", + "col164": "aiitk", + "col165": "z45tk", + "col166": "np5xd", + "col167": "tbxo5", + "col168": "qttw8", + "col169": "kt10h", + "col170": "atndh", + "col171": "qog7j", + "col172": "iw5ts", + "col173": "84hjr", + "col174": "qpoea", + "col175": "uzi43", + "col176": "q46jh", + "col177": "temvt", + "col178": "w5hag", + "col179": "mb0xw", + "col180": "glua4", + "col181": "7kf3s", + "col182": "iblxf", + "col183": "do4d6", + "col184": "img9v", + "col185": "2zkke", + "col186": "j00ve", + "col187": "7c2a8", + "col188": "q2w3o", + "col189": "kvgti", + "col190": "1654a", + "col191": "rzuox", + "col192": "3jn28", + "col193": "bsrqi", + "col194": "fbyu0", + "col195": "ltefj", + "col196": "ou1k7", + "col197": "e0dma", + "col198": "uudyu", + "col199": "ouv74", + "col200": "inn46", + "col201": "rcjrv", + "col202": "pjs8f", + "col203": "qme6x", + "col204": "75pt2", + "col205": "a45tc", + "col206": "7gpaj", + "col207": "hcv5x", + "col208": "0ie0a", + "col209": "3beem", + "col210": "pev0v", + "col211": "h3c9e", + "col212": "pq0of", + "col213": "z6vt8", + "col214": "447cg", + "col215": "agme4", + "col216": "58vbo", + "col217": "0g1q4", + "col218": "eegbj", + "col219": "wth8m", + "col220": "7dacf", + "col221": "p7k9s", + "col222": "ou0wk", + "col223": "u0imj", + "col224": "6xq49", + "col225": "6a6cl", + "col226": "4iwez", + "col227": "vu04y", + "col228": "4l0nc", + "col229": "wzkoc", + "col230": "v7kwx", + "col231": "3b07b", + "col232": "877u4", + "col233": "dlna8", + "col234": "q41un", + "col235": "kepp6", + "col236": "va8cf", + "col237": "l8na7", + "col238": "bs0b7", + "col239": "ercsr", + "col240": "xjvpe", + "col241": "t5p4m", + "col242": "zposj", + "col243": "3cxrd", + "col244": "xp0nm", + "col245": "csgz2", + "col246": "63vx1", + "col247": "4rita", + "col248": "fc32i", + "col249": "unzu8", + "col250": "ailnd", + "col251": "fxxxc", + "col252": "5rqep", + "col253": "ze0om", + "col254": "8qdpw", + "col255": "6gcd3", + "col256": "29j3n", + "col257": "aiquv", + "col258": "w904o", + "col259": "w7qqu", + "col260": "ug4e0", + "col261": "2ti7v", + "col262": "qp46u", + "col263": "pjmvg", + "col264": "x72ly", + "col265": "pbuku", + "col266": "k3erv", + "col267": "2m7vx", + "col268": "bzo5l", + "col269": "nphk2", + "col270": "8i5x6", + "col271": "g2q62", + "col272": "ixzua", + "col273": "smt15", + "col274": "t7dry", + "col275": "g0kf1", + "col276": "1fwks", + "col277": "77fx8", + "col278": "ox40m", + "col279": "cr8iu", + "col280": "qtg62", + "col281": "5gvy7", + "col282": "wdbrh", + "col283": "emcxh", + "col284": "h97t2", + "col285": "2hgda", + "col286": "a0dxg", + "col287": "feeoz", + "col288": "b09e4", + "col289": "tqzat", + "col290": "ty5ji", + "col291": "pa0e9", + "col292": "loqkm", + "col293": "3qktt", + "col294": "59aby", + "col295": "nh21g", + "col296": "8p65g", + "col297": "irb5h", + "col298": "fc86n", + "col299": "soi53", + "col300": "hee8w", + "col301": "89qcx", + "col302": "jrll0", + "col303": "ztb5m", + "col304": "4542l", + "col305": "zck47", + "col306": "webvc", + "col307": "ku1t4", + "col308": "7qyv5", + "col309": "yziu4", + "col310": "wjqw0", + "col311": "936ub", + "col312": "xlzq2", + "col313": "5oiy8", + "col314": "nb5ec", + "col315": "vk07k", + "col316": "6rkpu", + "col317": "tjpn8", + "col318": "gy038", + "col319": "3aj17", + "col320": "4evk4", + "col321": "vxtyt", + "col322": "ad9r0", + "col323": "r2m33", + "col324": "ltpjk", + "col325": "w5wxr", + "col326": "9yq9k", + "col327": "60537", + "col328": "kqw7m", + "col329": "0y6s4", + "col330": "9rkhb", + "col331": "4opzu", + "col332": "5wx0q", + "col333": "n7o89", + "col334": "bfeqb", + "col335": "ja86o", + "col336": "skl5t", + "col337": "v4az9", + "col338": "58kho", + "col339": "c6qyw", + "col340": "7vrh6", + "col341": "3nep0", + "col342": "cvgvp", + "col343": "323yo", + "col344": "dqtmx", + "col345": "d4pjn", + "col346": "5xjel", + "col347": "rsfu6", + "col348": "zt3qp", + "col349": "bhqm5", + "col350": "8byit", + "col351": "5e7ag", + "col352": "7idz3", + "col353": "hsfgh", + "col354": "w33b1", + "col355": "f3fi8", + "col356": "iqcln", + "col357": "fv1i2", + "col358": "djl01", + "col359": "ksxwi", + "col360": "vfu8k", + "col361": "22zse", + "col362": "4ih2v", + "col363": "scew6", + "col364": "tuep6", + "col365": "x9c6u", + "col366": "lbujn", + "col367": "kxsmx", + "col368": "6btf5", + "col369": "djy1u", + "col370": "2wdmd", + "col371": "1g4rf", + "col372": "nj4kc", + "col373": "kyv0y", + "col374": "reqyx", + "col375": "4aryx", + "col376": "nrx8z", + "col377": "w1rcy", + "col378": "5nnk5", + "col379": "qmrgq", + "col380": "eu5i6", + "col381": "d04um", + "col382": "ezo18", + "col383": "98ln7", + "col384": "7whmv", + "col385": "e805u", + "col386": "sl1p5", + "col387": "gyyjn", + "col388": "z9lwv", + "col389": "dur2r", + "col390": "jj2if", + "col391": "v51l2", + "col392": "o5b2i", + "col393": "01ow9", + "col394": "zb9dp", + "col395": "oar3y", + "col396": "s2qfv", + "col397": "aecej", + "col398": "em2r5", + "col399": "w629k", + "col400": "vb982", + "col401": "3yuh6", + "col402": "rol2q", + "col403": "edz7k", + "col404": "pjrak", + "col405": "ld7qg", + "col406": "wemq4", + "col407": "fz232", + "col408": "vh0s9", + "col409": "gygtq", + "col410": "2rrwb", + "col411": "8n3vs", + "col412": "zni9d", + "col413": "649c3", + "col414": "lusy6", + "col415": "tzvkp", + "col416": "1df9s", + "col417": "1cayf", + "col418": "es43z", + "col419": "b1x4m", + "col420": "vbmov", + "col421": "afsq3", + "col422": "apanj", + "col423": "qk3y6", + "col424": "t5so1", + "col425": "zekw7", + "col426": "j7rb2", + "col427": "9kjn5", + "col428": "qc35c", + "col429": "90b0o", + "col430": "ha9uw", + "col431": "czo5q", + "col432": "ta0gl", + "col433": "ba7dv", + "col434": "qmvp8", + "col435": "4mqan", + "col436": "ow2ij", + "col437": "wl7z4", + "col438": "8zibx", + "col439": "p17bk", + "col440": "82eej", + "col441": "jc7dx", + "col442": "sf5j7", + "col443": "f68wr", + "col444": "kmgeq", + "col445": "d17p0", + "col446": "nnmj9", + "col447": "nuaav", + "col448": "xw1gc", + "col449": "mvz5c", + "col450": "jfy0o", + "col451": "vpios", + "col452": "blxc3", + "col453": "65lgp", + "col454": "h39wd", + "col455": "2sde5", + "col456": "obfxm", + "col457": "cu00o", + "col458": "ojm9r", + "col459": "g6319", + "col460": "mrgws", + "col461": "mdzfk", + "col462": "l1v9c", + "col463": "mdp65", + "col464": "y3370", + "col465": "0wnbk", + "col466": "hj1vu", + "col467": "ecvvl", + "col468": "vl7v4", + "col469": "kho7j", + "col470": "80unk", + "col471": "nr8pb", + "col472": "pudsg", + "col473": "dc1n6", + "col474": "k9b0f", + "col475": "xh5ny", + "col476": "53i3o", + "col477": "98p4y", + "col478": "5wzce", + "col479": "q4hl5", + "col480": "30pm9", + "col481": "uni3j", + "col482": "uq3jj", + "col483": "ld2to", + "col484": "23fax", + "col485": "40r9u", + "col486": "xqjnf", + "col487": "6f4t4", + "col488": "t0jou", + "col489": "cv6po", + "col490": "62ry6", + "col491": "okc80", + "col492": "up4ec", + "col493": "98jwp", + "col494": "kofm9", + "col495": "pkrjw", + "col496": "p5l6i", + "col497": "6jjma", + "col498": "fgcfk", + "col499": "j7wwi", + "col500": "yw5vb", + "col501": "xw5yk", + "col502": "6o09l", + "col503": "sfu5w", + "col504": "xxw2t", + "col505": "j5vt3", + "col506": "u3d1f", + "col507": "pu26q", + "col508": "wuvby", + "col509": "lnwhc", + "col510": "g9r1q", + "col511": "rvay8", + "col512": "qjqs2", + "col513": "0n8sn", + "col514": "m4gi9", + "col515": "iaset", + "col516": "s59k1", + "col517": "a3c1u", + "col518": "g7c4l", + "col519": "fnh2d", + "col520": "1zbjs", + "col521": "034z0", + "col522": "kxrnq", + "col523": "dti4k", + "col524": "2ov9n", + "col525": "vondn", + "col526": "zsh4y", + "col527": "pesf1", + "col528": "jhiey", + "col529": "zwao7", + "col530": "58ohu", + "col531": "u7uhu", + "col532": "cfcfn", + "col533": "7ntre", + "col534": "knhay", + "col535": "agohl", + "col536": "wfved", + "col537": "7casj", + "col538": "gbfrh", + "col539": "d2r3v", + "col540": "xgtn5", + "col541": "p02hl", + "col542": "xswhm", + "col543": "16qia", + "col544": "toala", + "col545": "u3557", + "col546": "0e05c", + "col547": "iwhbk", + "col548": "7cx4n", + "col549": "78jjj", + "col550": "2n1lh", + "col551": "lftjj", + "col552": "t109w", + "col553": "jdf9l", + "col554": "nnmob", + "col555": "i2w3y", + "col556": "1zcp7", + "col557": "ftk80", + "col558": "c1q4r", + "col559": "ray9u", + "col560": "2nopx", + "col561": "6ob0t", + "col562": "irloe", + "col563": "itw5y", + "col564": "oj4i6", + "col565": "0gswd", + "col566": "v6709", + "col567": "1kaxw", + "col568": "5a83m", + "col569": "lmb12", + "col570": "iig4p", + "col571": "w3x2g", + "col572": "38kbg", + "col573": "xthlv", + "col574": "utzjy", + "col575": "ukm0m", + "col576": "bcaw1", + "col577": "yfw25", + "col578": "m8byh", + "col579": "52ehg", + "col580": "2fkc2", + "col581": "k0iqs", + "col582": "grsol", + "col583": "ydkb4", + "col584": "raudf", + "col585": "poakh", + "col586": "iq16g", + "col587": "x6ub9", + "col588": "l0fun", + "col589": "k65r5", + "col590": "snbtj", + "col591": "hky4r", + "col592": "q97b2", + "col593": "o93nu", + "col594": "hwxnk", + "col595": "itxs7", + "col596": "pxoks", + "col597": "jp9ze", + "col598": "xe1o4", + "col599": "nxr0h", + "col600": "vpc2j", + "col601": "s0hiu", + "col602": "ea5x9", + "col603": "1e3mp", + "col604": "e8oi9", + "col605": "n3rac", + "col606": "vdybv", + "col607": "12lk0", + "col608": "t60yt", + "col609": "rc1p9", + "col610": "ji1qe", + "col611": "ogtvg", + "col612": "oa9y6", + "col613": "g2lc2", + "col614": "f1kfb", + "col615": "p5uxv", + "col616": "q3fkr", + "col617": "bdaqm", + "col618": "k63np", + "col619": "3dk3u", + "col620": "yyljl", + "col621": "vpkbt", + "col622": "hktcr", + "col623": "lbe0s", + "col624": "47ilo", + "col625": "ayhqa", + "col626": "urngg", + "col627": "wrs3b", + "col628": "a6nkr", + "col629": "hpggx", + "col630": "kr0c5", + "col631": "0u3b7", + "col632": "ey9yr", + "col633": "n7k59", + "col634": "i6z09", + "col635": "f3tan", + "col636": "i1mdw", + "col637": "wshim", + "col638": "xyeb1", + "col639": "qugaw", + "col640": "obk4h", + "col641": "io8cp", + "col642": "lw7sv", + "col643": "g4spr", + "col644": "pz0jj", + "col645": "uxdqm", + "col646": "gto1m", + "col647": "cc34l", + "col648": "0c3ws", + "col649": "3whp0", + "col650": "hl2bv", + "col651": "ni7ls", + "col652": "8a40g", + "col653": "yozj5", + "col654": "n683k", + "col655": "1om9c", + "col656": "2si95", + "col657": "frzab", + "col658": "19fyc", + "col659": "qsd4x", + "col660": "fac3l", + "col661": "4y01o", + "col662": "qpx1r", + "col663": "j3iwq", + "col664": "0njyf", + "col665": "35qlz", + "col666": "on8ri", + "col667": "oefbo", + "col668": "hlh2p", + "col669": "t1590", + "col670": "e1zon", + "col671": "r3ntp", + "col672": "eulsp", + "col673": "cy0cj", + "col674": "8f286", + "col675": "136m5", + "col676": "purgi", + "col677": "rrm4s", + "col678": "qopfo", + "col679": "z7aaq", + "col680": "p4yug", + "col681": "3mi2s", + "col682": "bent4", + "col683": "4xqzc", + "col684": "qlllf", + "col685": "8ga1n", + "col686": "uac17", + "col687": "253iu", + "col688": "bmw78", + "col689": "97j5c", + "col690": "hh9pq", + "col691": "sc8j7", + "col692": "hmncf", + "col693": "wxnsf", + "col694": "erftk", + "col695": "7lo9l", + "col696": "s55h3", + "col697": "xxw5n", + "col698": "j2xrq", + "col699": "0g1oz", + "col700": "87wxy", + "col701": "9529m", + "col702": "jb6yc", + "col703": "zuuje", + "col704": "ielx3", + "col705": "cp1no", + "col706": "kxo9f", + "col707": "y4mkf", + "col708": "wgifj", + "col709": "iob52", + "col710": "voxcr", + "col711": "at90a", + "col712": "o0koh", + "col713": "jxbb4", + "col714": "rlitj", + "col715": "ednhn", + "col716": "hbed2", + "col717": "amtwc", + "col718": "xrp5r", + "col719": "ohi85", + "col720": "20k35", + "col721": "adhp2", + "col722": "pamfo", + "col723": "tcxyi", + "col724": "bqndt", + "col725": "pznpe", + "col726": "iidfp", + "col727": "o5nh2", + "col728": "s6mbm", + "col729": "hte2e", + "col730": "34209", + "col731": "wp94j", + "col732": "8mtgx", + "col733": "twmf9", + "col734": "k21p4", + "col735": "dq8yg", + "col736": "9rc7e", + "col737": "qs0t2", + "col738": "lzygj", + "col739": "xgyh1", + "col740": "kqgld", + "col741": "oq0o1", + "col742": "23nk6", + "col743": "heqky", + "col744": "gley9", + "col745": "8wfbl", + "col746": "wt85i", + "col747": "9b341", + "col748": "wo807", + "col749": "ndvfq", + "col750": "imz0h", + "col751": "24np7", + "col752": "g3skv", + "col753": "bo5is", + "col754": "rl5v9", + "col755": "xzfmt", + "col756": "he44c", + "col757": "t5anj", + "col758": "7xze3", + "col759": "36ida", + "col760": "g9bax", + "col761": "eicut", + "col762": "66b1a", + "col763": "5u90j", + "col764": "iz863", + "col765": "xlstv", + "col766": "107p1", + "col767": "88yr3", + "col768": "76hvb", + "col769": "nwxm7", + "col770": "sxbmh", + "col771": "e5h9w", + "col772": "3qke9", + "col773": "86bz1", + "col774": "u0xx4", + "col775": "w7oat", + "col776": "285d9", + "col777": "7gob2", + "col778": "ho0v4", + "col779": "zpoki", + "col780": "7olfq", + "col781": "wnill", + "col782": "t3rqv", + "col783": "ir5fb", + "col784": "snhrl", + "col785": "sv56v", + "col786": "hako6", + "col787": "7iw76", + "col788": "j6jm8", + "col789": "tyy9z", + "col790": "ly89k", + "col791": "p336e", + "col792": "3anec", + "col793": "dceew", + "col794": "c529h", + "col795": "8e6bs", + "col796": "yqg5p", + "col797": "p1p35", + "col798": "j7ex3", + "col799": "dj4n1", + "col800": "0ze8f", + "col801": "n3udf", + "col802": "0uyi3", + "col803": "rryok", + "col804": "cv77o", + "col805": "i9zjg", + "col806": "hjr7i", + "col807": "4mqnz", + "col808": "ov619", + "col809": "mxjza", + "col810": "rxuwv", + "col811": "epqmh", + "col812": "oj8tv", + "col813": "skb8p", + "col814": "0xad1", + "col815": "n8ce5", + "col816": "wc3le", + "col817": "hmud7", + "col818": "bdb2s", + "col819": "fav71", + "col820": "9miy7", + "col821": "02dlj", + "col822": "6nmb9", + "col823": "8ahg8", + "col824": "c8mr7", + "col825": "qb7ta", + "col826": "v2rx6", + "col827": "l76j2", + "col828": "xbwm7", + "col829": "crb87", + "col830": "4ublo", + "col831": "0wa68", + "col832": "srsph", + "col833": "xnuip", + "col834": "8o705", + "col835": "fbivh", + "col836": "8l4wt", + "col837": "jxmrb", + "col838": "6enjt", + "col839": "g6phc", + "col840": "oy440", + "col841": "x7ssd", + "col842": "i4civ", + "col843": "1h0v8", + "col844": "re6ui", + "col845": "fuhjc", + "col846": "peump", + "col847": "ajp3d", + "col848": "5lro6", + "col849": "kmiht", + "col850": "jj841", + "col851": "cuw1j", + "col852": "csk2w", + "col853": "ji86u", + "col854": "v81ao", + "col855": "lxttr", + "col856": "or9s0", + "col857": "crtqw", + "col858": "nz731", + "col859": "ms2ec", + "col860": "e8o3w", + "col861": "0lif4", + "col862": "mtxyk", + "col863": "rt4p4", + "col864": "e9rg2", + "col865": "gkwkq", + "col866": "6krkc", + "col867": "auoki", + "col868": "4o1ny", + "col869": "90fsi", + "col870": "okbgd", + "col871": "t09yy", + "col872": "1bnqw", + "col873": "2p1e4", + "col874": "kkqhg", + "col875": "2sajl", + "col876": "0710m", + "col877": "sm8lc", + "col878": "xfjvw", + "col879": "7bmxa", + "col880": "577dq", + "col881": "rxnvs", + "col882": "yyk75", + "col883": "ayc2b", + "col884": "mn5iy", + "col885": "ruse3", + "col886": "vw4km", + "col887": "v2wyg", + "col888": "q1c8x", + "col889": "0k0k7", + "col890": "5ubpi", + "col891": "85aou", + "col892": "nk7pz", + "col893": "8xz1r", + "col894": "d55p7", + "col895": "10yrt", + "col896": "6eqhg", + "col897": "ck0wk", + "col898": "qj75t", + "col899": "xfny7", + "col900": "zzhiu", + "col901": "hqnjz", + "col902": "359dj", + "col903": "m2jfj", + "col904": "3xf1g", + "col905": "revsa", + "col906": "ufmvb", + "col907": "pzrq6", + "col908": "ctekk", + "col909": "wtpc6", + "col910": "bulbf", + "col911": "fza0e", + "col912": "4pa09", + "col913": "88918", + "col914": "tfrrj", + "col915": "hf99d", + "col916": "pnzk2", + "col917": "bwy3q", + "col918": "sv1lh", + "col919": "bupz7", + "col920": "33mgu", + "col921": "2r8ev", + "col922": "3brtg", + "col923": "8a6gc", + "col924": "28jw5", + "col925": "t2kn3", + "col926": "437q4", + "col927": "ls04v", + "col928": "32afa", + "col929": "6yplg", + "col930": "46fg6", + "col931": "ic3zr", + "col932": "e6cdk", + "col933": "dtjeu", + "col934": "dcmqg", + "col935": "blmqz", + "col936": "1zysk", + "col937": "iqvmg", + "col938": "spugh", + "col939": "bw5i4", + "col940": "o7dod", + "col941": "c5uv5", + "col942": "jfrl9", + "col943": "cvz29", + "col944": "1dsfk", + "col945": "yw3ko", + "col946": "m9cex", + "col947": "kn2bc", + "col948": "pmoaa", + "col949": "u6c3l", + "col950": "17k92", + "col951": "usi0e", + "col952": "17a8x", + "col953": "lvzzh", + "col954": "le4tq", + "col955": "z5mch", + "col956": "8hyoo", + "col957": "qw3n2", + "col958": "3wxwl", + "col959": "9qo8e", + "col960": "0vi9b", + "col961": "jm226", + "col962": "a9irl", + "col963": "thypj", + "col964": "8n5ev", + "col965": "toui6", + "col966": "jc1pu", + "col967": "06pu7", + "col968": "42xvz", + "col969": "svirk", + "col970": "indxw", + "col971": "3gwhe", + "col972": "ziwsg", + "col973": "gt5ly", + "col974": "4n1or", + "col975": "dnoyf", + "col976": "43css", + "col977": "zthff", + "col978": "zocp5", + "col979": "qqc4w", + "col980": "jy4un", + "col981": "hxnql", + "col982": "y1k87", + "col983": "ssy8o", + "col984": "km94u", + "col985": "ucen7", + "col986": "vev4n", + "col987": "uba5o", + "col988": "etm24", + "col989": "pzr8a", + "col990": "02g2u", + "col991": "q9yg1", + "col992": "ovjde", + "col993": "m46jq", + "col994": "xjq9c", + "col995": "ufp9w", + "col996": "tcd9f", + "col997": "529yn", + "col998": "sqhrk", + "col999": "fbhnl" + }, + { + "name": "Sofia Matthews", + "gender": "female", + "col0": "e6jp5", + "col1": "rxvgr", + "col2": "1dbtl", + "col3": "z4jq1", + "col4": "shh9x", + "col5": "2lrms", + "col6": "wycm8", + "col7": "6ws2s", + "col8": "qs8hw", + "col9": "nm9s3", + "col10": "40pn7", + "col11": "ukhz4", + "col12": "x7ex4", + "col13": "7bz6x", + "col14": "0sndz", + "col15": "b0but", + "col16": "6dirs", + "col17": "2htl4", + "col18": "bsywn", + "col19": "9xbqq", + "col20": "7nj3a", + "col21": "0udsy", + "col22": "1xupe", + "col23": "j7hlb", + "col24": "5cqqn", + "col25": "q9klg", + "col26": "t1s84", + "col27": "sqf7g", + "col28": "wwx5r", + "col29": "4tou7", + "col30": "wrk39", + "col31": "iywf2", + "col32": "w1d1h", + "col33": "okylt", + "col34": "p3qoe", + "col35": "695yg", + "col36": "p4cru", + "col37": "if7dx", + "col38": "efqyv", + "col39": "19e3q", + "col40": "ivw0s", + "col41": "m2qhr", + "col42": "vobk7", + "col43": "old3d", + "col44": "jsk9m", + "col45": "s7jso", + "col46": "rw96c", + "col47": "rrcsg", + "col48": "zqwad", + "col49": "uvcbm", + "col50": "67sbr", + "col51": "7853c", + "col52": "50ry4", + "col53": "86dxw", + "col54": "lzlqj", + "col55": "rlwmr", + "col56": "zpfkv", + "col57": "vht37", + "col58": "uh55x", + "col59": "30em0", + "col60": "ubihx", + "col61": "3fhdt", + "col62": "sjfwd", + "col63": "sws8n", + "col64": "hdax7", + "col65": "jps92", + "col66": "txxi2", + "col67": "z4fuq", + "col68": "i43im", + "col69": "i0vaa", + "col70": "ak3a8", + "col71": "6qcqv", + "col72": "idivf", + "col73": "k3vwz", + "col74": "i20lm", + "col75": "eseaw", + "col76": "ma19u", + "col77": "8v3ov", + "col78": "5q1fm", + "col79": "5pe3g", + "col80": "rp6qk", + "col81": "4js6t", + "col82": "0k1zw", + "col83": "9vzoz", + "col84": "xk5wc", + "col85": "0vhvh", + "col86": "g7sjm", + "col87": "feg41", + "col88": "hr7mx", + "col89": "lfxg6", + "col90": "wdhou", + "col91": "2a503", + "col92": "ibvld", + "col93": "to0se", + "col94": "saxc0", + "col95": "z0jft", + "col96": "a792h", + "col97": "0hbkb", + "col98": "1sp7l", + "col99": "9pn93", + "col100": "ftfqz", + "col101": "ig6cd", + "col102": "s5qwp", + "col103": "u0p79", + "col104": "faokq", + "col105": "9wghl", + "col106": "bimat", + "col107": "t77sk", + "col108": "ki8xg", + "col109": "svtvm", + "col110": "bcyak", + "col111": "57nww", + "col112": "zj3z8", + "col113": "9o6d3", + "col114": "dcb88", + "col115": "79aeq", + "col116": "aolzq", + "col117": "jaokv", + "col118": "3upn2", + "col119": "lzo9h", + "col120": "c49um", + "col121": "fc3ht", + "col122": "k62ff", + "col123": "hwasd", + "col124": "cyjno", + "col125": "ev9yw", + "col126": "cv5j2", + "col127": "kkdeh", + "col128": "xf07p", + "col129": "c0tp3", + "col130": "pxj7r", + "col131": "c0fq9", + "col132": "n608f", + "col133": "xypgc", + "col134": "esvyj", + "col135": "x6nlm", + "col136": "hi5q1", + "col137": "g7ku5", + "col138": "2kdua", + "col139": "ifb07", + "col140": "s81pj", + "col141": "bef66", + "col142": "rtdv0", + "col143": "q1njl", + "col144": "irb94", + "col145": "k6crf", + "col146": "qa95d", + "col147": "egmn1", + "col148": "9qbig", + "col149": "34xy2", + "col150": "d9u3q", + "col151": "ps9bf", + "col152": "1bpbn", + "col153": "8ggmx", + "col154": "5ksy0", + "col155": "68hgg", + "col156": "mh1l9", + "col157": "vt5ib", + "col158": "ndu6t", + "col159": "8cwba", + "col160": "hhy0g", + "col161": "rtf2a", + "col162": "btkex", + "col163": "ml4g2", + "col164": "uouyd", + "col165": "opd83", + "col166": "sm6h3", + "col167": "xlt41", + "col168": "dqbiv", + "col169": "04c3f", + "col170": "62qv0", + "col171": "v1rp1", + "col172": "rpmv3", + "col173": "jtklg", + "col174": "ike70", + "col175": "pqd19", + "col176": "tmc1b", + "col177": "a6m9y", + "col178": "vvx1t", + "col179": "dpahk", + "col180": "xlx9g", + "col181": "ss2lb", + "col182": "vs6o0", + "col183": "tronb", + "col184": "w2rga", + "col185": "pac33", + "col186": "suh6t", + "col187": "hib0d", + "col188": "ia69y", + "col189": "yoa3d", + "col190": "c2454", + "col191": "x8kxf", + "col192": "ci5w4", + "col193": "vhsje", + "col194": "8y7hz", + "col195": "ube8u", + "col196": "9bxpa", + "col197": "aniyq", + "col198": "ctoom", + "col199": "cj0zl", + "col200": "fdrm4", + "col201": "9hf3k", + "col202": "cesvs", + "col203": "nvte3", + "col204": "qpkgj", + "col205": "q7j66", + "col206": "vpktd", + "col207": "cmmqf", + "col208": "8zrxo", + "col209": "az3dx", + "col210": "ddqlx", + "col211": "mvp2l", + "col212": "c6fnq", + "col213": "ypgvo", + "col214": "n778d", + "col215": "c476w", + "col216": "vlj8l", + "col217": "d0m5x", + "col218": "b2rw2", + "col219": "uga6i", + "col220": "in56c", + "col221": "jxfrb", + "col222": "yedma", + "col223": "cqt0e", + "col224": "b7so0", + "col225": "xz79y", + "col226": "uhjkd", + "col227": "vzg5y", + "col228": "v5s44", + "col229": "0i61g", + "col230": "n6nqd", + "col231": "wzaee", + "col232": "jsm7m", + "col233": "onu7z", + "col234": "m3cj6", + "col235": "kg9xp", + "col236": "k8bai", + "col237": "bm7aq", + "col238": "mxnc2", + "col239": "cgz8t", + "col240": "frxww", + "col241": "wfjvp", + "col242": "ppmmk", + "col243": "15eet", + "col244": "suvlc", + "col245": "flwq7", + "col246": "cxip1", + "col247": "h7qhx", + "col248": "mr5pp", + "col249": "l4riu", + "col250": "w20t4", + "col251": "wfeph", + "col252": "vzjc1", + "col253": "7dowo", + "col254": "er0g9", + "col255": "premk", + "col256": "fj6ji", + "col257": "ozdmp", + "col258": "tycrk", + "col259": "cy45o", + "col260": "degew", + "col261": "1bxfn", + "col262": "rhtpk", + "col263": "966u1", + "col264": "8a8ce", + "col265": "ix8a8", + "col266": "shcy4", + "col267": "9v118", + "col268": "kvl82", + "col269": "hhwjk", + "col270": "g91t0", + "col271": "6x0lx", + "col272": "q6kzb", + "col273": "4uu8a", + "col274": "638q0", + "col275": "7uukj", + "col276": "xb84e", + "col277": "lvc0l", + "col278": "fkpqg", + "col279": "7b2vw", + "col280": "oqc8z", + "col281": "ri8yt", + "col282": "9m8f3", + "col283": "6xy9u", + "col284": "d1q5d", + "col285": "qb8ki", + "col286": "acwju", + "col287": "tueew", + "col288": "cbgww", + "col289": "gst6m", + "col290": "cjp5h", + "col291": "ctsdy", + "col292": "lcuvr", + "col293": "zpk37", + "col294": "fgupb", + "col295": "ssyo3", + "col296": "2w317", + "col297": "rltx3", + "col298": "pd1fc", + "col299": "vdq1k", + "col300": "bu0hm", + "col301": "chf7p", + "col302": "9442q", + "col303": "wnk6u", + "col304": "q4j5j", + "col305": "kidwt", + "col306": "fduir", + "col307": "idb7n", + "col308": "hlj1b", + "col309": "8wx53", + "col310": "titf6", + "col311": "5dmfw", + "col312": "2srop", + "col313": "qqyon", + "col314": "7zj9k", + "col315": "4culk", + "col316": "nam1q", + "col317": "4n3kt", + "col318": "h3v8u", + "col319": "4l8fe", + "col320": "cv194", + "col321": "vzebi", + "col322": "15f4m", + "col323": "w8wuv", + "col324": "200cr", + "col325": "lztd4", + "col326": "ztt8t", + "col327": "8q26b", + "col328": "ifz92", + "col329": "2tmkr", + "col330": "qmt1e", + "col331": "vm3xp", + "col332": "2l9p1", + "col333": "cauhw", + "col334": "ufhio", + "col335": "5y74h", + "col336": "27rtf", + "col337": "6zlur", + "col338": "f8p1f", + "col339": "57cw9", + "col340": "mipn1", + "col341": "d70zh", + "col342": "prm3j", + "col343": "f04jn", + "col344": "47knk", + "col345": "971tm", + "col346": "fll2b", + "col347": "fxurl", + "col348": "5jobe", + "col349": "aj8b9", + "col350": "b5u8o", + "col351": "rk4mc", + "col352": "8ct17", + "col353": "hw155", + "col354": "ammbt", + "col355": "fl9vy", + "col356": "i66gb", + "col357": "9zex6", + "col358": "0y5y2", + "col359": "p76cl", + "col360": "fpeuh", + "col361": "sq53z", + "col362": "rnaip", + "col363": "1se0o", + "col364": "t5nyu", + "col365": "6s4ti", + "col366": "jf800", + "col367": "xe2gh", + "col368": "vdxdi", + "col369": "8yipm", + "col370": "tbn1a", + "col371": "7r84v", + "col372": "xvpm8", + "col373": "p95ak", + "col374": "i57fm", + "col375": "dxeon", + "col376": "ms6a9", + "col377": "epy2s", + "col378": "s0s56", + "col379": "yjqg6", + "col380": "a40o6", + "col381": "4aeoz", + "col382": "aqw1f", + "col383": "xchr0", + "col384": "ekrvr", + "col385": "gjyep", + "col386": "gb1xy", + "col387": "2f4wp", + "col388": "zvwpi", + "col389": "9uc9u", + "col390": "5nthr", + "col391": "kcfe9", + "col392": "ccfkl", + "col393": "2v5tg", + "col394": "gqmg1", + "col395": "gqzfq", + "col396": "feped", + "col397": "vzx2z", + "col398": "3b7tl", + "col399": "uwq6m", + "col400": "7ev07", + "col401": "77vc7", + "col402": "2xv9l", + "col403": "1ivzv", + "col404": "rbojr", + "col405": "oj5ki", + "col406": "vaz0p", + "col407": "zfbo6", + "col408": "sp2fq", + "col409": "04ny4", + "col410": "ocdei", + "col411": "vsbqd", + "col412": "pxeu1", + "col413": "47cet", + "col414": "4t5my", + "col415": "nb38f", + "col416": "3pi9r", + "col417": "b7eti", + "col418": "vnfe2", + "col419": "pbkq2", + "col420": "kmm4l", + "col421": "6lj0k", + "col422": "cgu0d", + "col423": "cyh1z", + "col424": "46nh5", + "col425": "wgkeo", + "col426": "rw2eg", + "col427": "0kem6", + "col428": "olp4x", + "col429": "eb1g5", + "col430": "a3hjd", + "col431": "5l9dm", + "col432": "90gv5", + "col433": "jsy0d", + "col434": "tk7b5", + "col435": "135m4", + "col436": "bod7t", + "col437": "o68k8", + "col438": "0wbas", + "col439": "n9819", + "col440": "ij46i", + "col441": "iv2oi", + "col442": "r9u4j", + "col443": "5wha1", + "col444": "x2syj", + "col445": "qrvd5", + "col446": "v3t23", + "col447": "0rxxi", + "col448": "isg19", + "col449": "0vof6", + "col450": "1yslh", + "col451": "afvlj", + "col452": "atf92", + "col453": "cz6fk", + "col454": "hmndt", + "col455": "3k2r3", + "col456": "nrwna", + "col457": "obbun", + "col458": "cw5ho", + "col459": "050qo", + "col460": "0jf2k", + "col461": "ywmnr", + "col462": "466dd", + "col463": "docgh", + "col464": "162uk", + "col465": "9aifs", + "col466": "i8vv8", + "col467": "9i1dg", + "col468": "dsjdh", + "col469": "wlksg", + "col470": "lmjeq", + "col471": "02ki7", + "col472": "uuo7s", + "col473": "4y921", + "col474": "uyo5u", + "col475": "jk6nm", + "col476": "m0oir", + "col477": "gw17q", + "col478": "hz41q", + "col479": "9xulq", + "col480": "pvpo3", + "col481": "nysqe", + "col482": "fpvhu", + "col483": "pokyb", + "col484": "ej4g4", + "col485": "u8er1", + "col486": "4owsk", + "col487": "biyzn", + "col488": "xg1lh", + "col489": "tyvvk", + "col490": "ybng9", + "col491": "3d71y", + "col492": "4qofg", + "col493": "ftim1", + "col494": "muqp4", + "col495": "t5x21", + "col496": "z57ym", + "col497": "pwu42", + "col498": "16hdv", + "col499": "2h3es", + "col500": "1h0qh", + "col501": "x2gti", + "col502": "3x1yj", + "col503": "x6h76", + "col504": "nqg04", + "col505": "79zqd", + "col506": "9x0e3", + "col507": "2c3dc", + "col508": "q9mx1", + "col509": "beypl", + "col510": "csouy", + "col511": "wfahr", + "col512": "ktrm2", + "col513": "yokzq", + "col514": "vvmxw", + "col515": "al7v1", + "col516": "brd3v", + "col517": "tn2ig", + "col518": "49m8f", + "col519": "n8dh1", + "col520": "9tbta", + "col521": "u7pap", + "col522": "hy2g4", + "col523": "j5cqy", + "col524": "0q8y2", + "col525": "2sxo6", + "col526": "muidp", + "col527": "flclj", + "col528": "kpjre", + "col529": "xj8a5", + "col530": "xm1ms", + "col531": "rjyg0", + "col532": "trkr4", + "col533": "t991r", + "col534": "agem3", + "col535": "4tlgl", + "col536": "3x1dl", + "col537": "6vd37", + "col538": "v16ok", + "col539": "1dz2u", + "col540": "uon4w", + "col541": "5h3mc", + "col542": "y7yrf", + "col543": "6jsqt", + "col544": "eicty", + "col545": "0ykas", + "col546": "b7oav", + "col547": "3yg45", + "col548": "6cghd", + "col549": "8j6ix", + "col550": "38bls", + "col551": "wczix", + "col552": "at504", + "col553": "xgu9a", + "col554": "ec02s", + "col555": "bbgut", + "col556": "qwzv4", + "col557": "gv728", + "col558": "jq0kj", + "col559": "enfpe", + "col560": "nahyn", + "col561": "48a4o", + "col562": "acrub", + "col563": "mwy4h", + "col564": "0q60r", + "col565": "vjw2c", + "col566": "4pquo", + "col567": "mf3ap", + "col568": "m7bze", + "col569": "gdmnk", + "col570": "mxfqi", + "col571": "gejta", + "col572": "ecpn1", + "col573": "71r1h", + "col574": "f5wgx", + "col575": "8yvq4", + "col576": "ph76r", + "col577": "k4pcn", + "col578": "s1tgs", + "col579": "zkuw0", + "col580": "6vqze", + "col581": "c2eup", + "col582": "q61zf", + "col583": "d8jsp", + "col584": "a6xe6", + "col585": "sv3zj", + "col586": "kjl09", + "col587": "esy3r", + "col588": "xlbmf", + "col589": "v0j3s", + "col590": "zye52", + "col591": "nfe80", + "col592": "ukd1e", + "col593": "6v2ky", + "col594": "vwe4r", + "col595": "46t2i", + "col596": "ifu7i", + "col597": "96jv0", + "col598": "5kj0l", + "col599": "dacyc", + "col600": "6yxpq", + "col601": "gz0eg", + "col602": "2ervz", + "col603": "htuym", + "col604": "scunb", + "col605": "cf702", + "col606": "vgq3t", + "col607": "ly9dy", + "col608": "uiqe3", + "col609": "nwq50", + "col610": "723wn", + "col611": "3g7dp", + "col612": "ie0r5", + "col613": "fmi0z", + "col614": "77tas", + "col615": "m0thz", + "col616": "j8mnx", + "col617": "4l77v", + "col618": "8fsxi", + "col619": "f66ni", + "col620": "qtqpr", + "col621": "mqtb1", + "col622": "eqk5r", + "col623": "co1s2", + "col624": "tk2ou", + "col625": "j9p4e", + "col626": "c3p9c", + "col627": "wfggc", + "col628": "sxkx5", + "col629": "vhldx", + "col630": "l5laz", + "col631": "tyjyz", + "col632": "z8kgj", + "col633": "4jbiu", + "col634": "dr5gp", + "col635": "1o8hp", + "col636": "wz9gd", + "col637": "18zno", + "col638": "5tb1s", + "col639": "1ae22", + "col640": "4bsfe", + "col641": "3gvqz", + "col642": "bgg2m", + "col643": "5rwcq", + "col644": "bgibi", + "col645": "x5hxj", + "col646": "7vm4m", + "col647": "ssp1a", + "col648": "8eb9u", + "col649": "6nszw", + "col650": "5i1tu", + "col651": "pemeg", + "col652": "xpxvq", + "col653": "u8fuv", + "col654": "mla08", + "col655": "e0hih", + "col656": "ydbl7", + "col657": "wijm9", + "col658": "jiybl", + "col659": "73j10", + "col660": "4xrkn", + "col661": "ehr6t", + "col662": "zxe8z", + "col663": "pyinn", + "col664": "tz5wi", + "col665": "15qpc", + "col666": "esss3", + "col667": "ccydo", + "col668": "ct0e7", + "col669": "nbrvz", + "col670": "i77o4", + "col671": "e6awj", + "col672": "8rira", + "col673": "womrp", + "col674": "ukk4a", + "col675": "uagyy", + "col676": "e3ki5", + "col677": "7hhsz", + "col678": "y0hty", + "col679": "6aihs", + "col680": "07chx", + "col681": "cphsn", + "col682": "d5rg8", + "col683": "xmzsm", + "col684": "c86p6", + "col685": "2l5sk", + "col686": "q75yz", + "col687": "mnyns", + "col688": "f0zst", + "col689": "0gdmw", + "col690": "fapos", + "col691": "o8sdt", + "col692": "gouvk", + "col693": "axc92", + "col694": "ukngc", + "col695": "2ev8f", + "col696": "ev4ow", + "col697": "t85ot", + "col698": "z8xgz", + "col699": "2i1c1", + "col700": "zoovl", + "col701": "y1ks1", + "col702": "2rtjn", + "col703": "uz01q", + "col704": "hzntm", + "col705": "htqqq", + "col706": "sjt9j", + "col707": "k6se2", + "col708": "vc0p4", + "col709": "3mhkd", + "col710": "d4uex", + "col711": "tugbr", + "col712": "26r80", + "col713": "y7csn", + "col714": "5x389", + "col715": "8ri5n", + "col716": "fbqc8", + "col717": "l2bta", + "col718": "9bc3m", + "col719": "kwlyj", + "col720": "a7ieg", + "col721": "5mdn8", + "col722": "a7jsr", + "col723": "yumt8", + "col724": "tjagn", + "col725": "6j6hg", + "col726": "yfkkd", + "col727": "z9p2e", + "col728": "kd3gz", + "col729": "pbz1u", + "col730": "haflv", + "col731": "nc10x", + "col732": "te6yv", + "col733": "e01h7", + "col734": "vfq94", + "col735": "w19i9", + "col736": "qezx2", + "col737": "3wfwd", + "col738": "29r13", + "col739": "h8pkr", + "col740": "q27kf", + "col741": "dvu74", + "col742": "8yjbh", + "col743": "vyydk", + "col744": "7s4ad", + "col745": "as8id", + "col746": "eg50u", + "col747": "wfkdg", + "col748": "csnbc", + "col749": "o3eem", + "col750": "fv23v", + "col751": "44rm8", + "col752": "5nk4b", + "col753": "r8txx", + "col754": "6ufuv", + "col755": "v9a8q", + "col756": "7sugs", + "col757": "jgwoo", + "col758": "kd5qt", + "col759": "f1gu2", + "col760": "m7i86", + "col761": "k40yo", + "col762": "yyaa9", + "col763": "9qhyj", + "col764": "m6722", + "col765": "u40dw", + "col766": "lda2b", + "col767": "a8548", + "col768": "gde8a", + "col769": "9na47", + "col770": "qtbzu", + "col771": "lea81", + "col772": "76tr2", + "col773": "kq9j9", + "col774": "e41rr", + "col775": "h6bo3", + "col776": "kdfiu", + "col777": "lu214", + "col778": "ng07u", + "col779": "18x7j", + "col780": "91hdf", + "col781": "n4x33", + "col782": "8imnw", + "col783": "us76a", + "col784": "z6lvi", + "col785": "j1cyv", + "col786": "jw4ue", + "col787": "negok", + "col788": "harcr", + "col789": "bslqq", + "col790": "vt556", + "col791": "cvmoh", + "col792": "z4x8e", + "col793": "hbflu", + "col794": "wcgcb", + "col795": "dabni", + "col796": "v8868", + "col797": "7ka68", + "col798": "vnyeh", + "col799": "9tx3q", + "col800": "troid", + "col801": "a14zc", + "col802": "kzipp", + "col803": "eyqb9", + "col804": "ilk2e", + "col805": "w79pa", + "col806": "z88oi", + "col807": "tkt6s", + "col808": "8hbfj", + "col809": "31eet", + "col810": "jk8wb", + "col811": "0tfpv", + "col812": "ceb1k", + "col813": "p19k1", + "col814": "5n0iy", + "col815": "tzbt3", + "col816": "veeq0", + "col817": "pdshp", + "col818": "hvbb8", + "col819": "ljs4h", + "col820": "9qyd6", + "col821": "n9hj8", + "col822": "sfkwz", + "col823": "q45zr", + "col824": "2qdi5", + "col825": "8hg4n", + "col826": "rb2c9", + "col827": "8bn3m", + "col828": "94j01", + "col829": "vay09", + "col830": "61882", + "col831": "pcp5l", + "col832": "w7t70", + "col833": "f3zbh", + "col834": "9bbxw", + "col835": "wntaw", + "col836": "q34m1", + "col837": "pbvn7", + "col838": "77hea", + "col839": "ljipj", + "col840": "a8zdy", + "col841": "b0qt7", + "col842": "3sv2d", + "col843": "ukrub", + "col844": "dqwf2", + "col845": "xcn3y", + "col846": "w41f4", + "col847": "34mpr", + "col848": "qd4ra", + "col849": "wp68a", + "col850": "yf3ja", + "col851": "f5hf1", + "col852": "u7eag", + "col853": "keaxn", + "col854": "lpj41", + "col855": "0csim", + "col856": "7vddo", + "col857": "26m47", + "col858": "maavd", + "col859": "mtie6", + "col860": "izmry", + "col861": "9odmi", + "col862": "64h5q", + "col863": "m1nf1", + "col864": "b0z7z", + "col865": "h17de", + "col866": "wpaww", + "col867": "p28s0", + "col868": "96kmx", + "col869": "ozcch", + "col870": "fmzba", + "col871": "iwgx0", + "col872": "e4cb0", + "col873": "urb0a", + "col874": "r36it", + "col875": "ulqhl", + "col876": "3xmnt", + "col877": "r6rpv", + "col878": "6g51c", + "col879": "u3aq9", + "col880": "fmnsc", + "col881": "8qrd3", + "col882": "95cn5", + "col883": "clumi", + "col884": "zpecp", + "col885": "eridx", + "col886": "k1va4", + "col887": "b8svq", + "col888": "qdcx6", + "col889": "ixwkp", + "col890": "caprv", + "col891": "0q4gf", + "col892": "dj9hs", + "col893": "k213p", + "col894": "boa4g", + "col895": "4dal2", + "col896": "t5hrm", + "col897": "ro6b5", + "col898": "91yht", + "col899": "rsvpf", + "col900": "5i7ny", + "col901": "noeg9", + "col902": "ep9is", + "col903": "9cm07", + "col904": "qyem9", + "col905": "o1q8l", + "col906": "80wko", + "col907": "dudg9", + "col908": "m5usi", + "col909": "74iem", + "col910": "11q4b", + "col911": "57v20", + "col912": "xfdcb", + "col913": "7jxu6", + "col914": "6i7v3", + "col915": "r1hd8", + "col916": "tmauy", + "col917": "i2tov", + "col918": "c1gmo", + "col919": "5fzi8", + "col920": "3jbvc", + "col921": "rf12s", + "col922": "v3jxx", + "col923": "lzul8", + "col924": "5fi6q", + "col925": "ewd4y", + "col926": "pcgr0", + "col927": "r95u8", + "col928": "0gs8z", + "col929": "8h6v2", + "col930": "vsdho", + "col931": "d3uta", + "col932": "8u0wc", + "col933": "v8u39", + "col934": "1vws9", + "col935": "8gsjc", + "col936": "yvvxq", + "col937": "qu7rn", + "col938": "zkv6g", + "col939": "t4n1w", + "col940": "o7glv", + "col941": "dl7sl", + "col942": "euc8u", + "col943": "moqti", + "col944": "ccju5", + "col945": "9b398", + "col946": "b1hdj", + "col947": "1illd", + "col948": "kib8x", + "col949": "karil", + "col950": "x65es", + "col951": "7jpre", + "col952": "0n4se", + "col953": "djk2i", + "col954": "t3uj8", + "col955": "bosgc", + "col956": "8cdco", + "col957": "8mv7t", + "col958": "m8vtn", + "col959": "tfoq1", + "col960": "d14vj", + "col961": "thp2h", + "col962": "st8g1", + "col963": "nehr0", + "col964": "yubcv", + "col965": "u102u", + "col966": "q8fy3", + "col967": "r8hl7", + "col968": "9e8i6", + "col969": "9m6eq", + "col970": "l6z0t", + "col971": "0m04r", + "col972": "b5x5d", + "col973": "2z9s9", + "col974": "7uh08", + "col975": "1njta", + "col976": "6it7y", + "col977": "2iyop", + "col978": "7zrtn", + "col979": "hkzlv", + "col980": "zjuqk", + "col981": "g47k8", + "col982": "38f4h", + "col983": "f66de", + "col984": "jhljg", + "col985": "3p9t7", + "col986": "b3rgm", + "col987": "8663f", + "col988": "67n5c", + "col989": "7ngm3", + "col990": "fqe4d", + "col991": "j7fh5", + "col992": "ckqlb", + "col993": "0h4xv", + "col994": "f3lv8", + "col995": "9tnzg", + "col996": "q44mq", + "col997": "ayicn", + "col998": "pywbl", + "col999": "mtmbu" + }, + { + "name": "Walls Berg", + "gender": "male", + "col0": "zuh3n", + "col1": "7su3d", + "col2": "apmlo", + "col3": "8xokw", + "col4": "2zvzl", + "col5": "hugd0", + "col6": "352l7", + "col7": "w8e98", + "col8": "w30vb", + "col9": "jzogw", + "col10": "5cgsz", + "col11": "bit8l", + "col12": "mtd7h", + "col13": "bu7a9", + "col14": "fw03k", + "col15": "zgsbe", + "col16": "v9cf0", + "col17": "4viuy", + "col18": "lepmi", + "col19": "516wt", + "col20": "wvwbe", + "col21": "7uzf0", + "col22": "8xmel", + "col23": "d3w3q", + "col24": "ci141", + "col25": "00ha7", + "col26": "3anrh", + "col27": "bddx5", + "col28": "cy15e", + "col29": "z1tew", + "col30": "9hyz2", + "col31": "ebr5q", + "col32": "9qyxf", + "col33": "7u1g3", + "col34": "ooc4o", + "col35": "z9kw7", + "col36": "azgpo", + "col37": "m951g", + "col38": "gkua2", + "col39": "m7tpb", + "col40": "r3v2j", + "col41": "pfchd", + "col42": "nj843", + "col43": "uxoa7", + "col44": "1rjt6", + "col45": "c0p09", + "col46": "fgpm4", + "col47": "0hd3l", + "col48": "5rt81", + "col49": "0vdyq", + "col50": "ua34r", + "col51": "q31lj", + "col52": "9m02i", + "col53": "7ibrp", + "col54": "yvzxq", + "col55": "8wt5x", + "col56": "iiio8", + "col57": "z83a9", + "col58": "2ej1k", + "col59": "x1tq5", + "col60": "pen17", + "col61": "surw6", + "col62": "5o7t9", + "col63": "5dqdd", + "col64": "4g5ox", + "col65": "ygm68", + "col66": "qomt6", + "col67": "cud3f", + "col68": "ya05o", + "col69": "0zsi2", + "col70": "ojuei", + "col71": "rtuh6", + "col72": "g3uwq", + "col73": "0eimc", + "col74": "d2smn", + "col75": "t14a7", + "col76": "kbnw2", + "col77": "3bf9r", + "col78": "sfdvk", + "col79": "h9tgm", + "col80": "9fca9", + "col81": "nxdgo", + "col82": "td2zh", + "col83": "pjr7q", + "col84": "pjjsn", + "col85": "3moak", + "col86": "gfyeg", + "col87": "gpb1p", + "col88": "q4ksk", + "col89": "7o2ij", + "col90": "jcy45", + "col91": "iraw7", + "col92": "uuvx9", + "col93": "u53lb", + "col94": "hfeok", + "col95": "92kmy", + "col96": "c44bo", + "col97": "aylgg", + "col98": "l73xg", + "col99": "k6y23", + "col100": "gn3j1", + "col101": "yvnj6", + "col102": "j6ab1", + "col103": "97xyd", + "col104": "qx5ye", + "col105": "9izlq", + "col106": "riaop", + "col107": "kfnc0", + "col108": "bznei", + "col109": "tjjyp", + "col110": "7l9l3", + "col111": "902c1", + "col112": "m6xt8", + "col113": "huhqn", + "col114": "v2s0r", + "col115": "hywfr", + "col116": "lipbx", + "col117": "xpfed", + "col118": "7mgwn", + "col119": "x1lyt", + "col120": "qyfrl", + "col121": "zo7z0", + "col122": "019o9", + "col123": "584fz", + "col124": "yowqy", + "col125": "n6s9o", + "col126": "9sjwu", + "col127": "it1ps", + "col128": "j16ev", + "col129": "zhuqq", + "col130": "y65m4", + "col131": "ewqcn", + "col132": "5kfcf", + "col133": "y6qrh", + "col134": "r81wy", + "col135": "hovj2", + "col136": "ps9cq", + "col137": "cldyi", + "col138": "20wqy", + "col139": "hrwoa", + "col140": "o349u", + "col141": "i7pmw", + "col142": "pvigk", + "col143": "0entj", + "col144": "bjxwv", + "col145": "6oh2p", + "col146": "8lr5f", + "col147": "9pn75", + "col148": "l3dnn", + "col149": "ang2t", + "col150": "tioti", + "col151": "l0hr9", + "col152": "0por2", + "col153": "q6yx5", + "col154": "gcm8h", + "col155": "nncw6", + "col156": "x980c", + "col157": "fg9gr", + "col158": "chad5", + "col159": "9cj03", + "col160": "gas9k", + "col161": "qguio", + "col162": "71zeg", + "col163": "3e2ji", + "col164": "bt9qo", + "col165": "z68ju", + "col166": "d2kkm", + "col167": "ss7ol", + "col168": "tc7ir", + "col169": "c844e", + "col170": "4rjfb", + "col171": "h1iv5", + "col172": "o3rpi", + "col173": "mqtul", + "col174": "jv7uw", + "col175": "78zxg", + "col176": "iheeo", + "col177": "a54b8", + "col178": "off1d", + "col179": "bfpsf", + "col180": "q6rq4", + "col181": "1var4", + "col182": "hdpay", + "col183": "rwthw", + "col184": "086e1", + "col185": "atr1p", + "col186": "o81a2", + "col187": "6k653", + "col188": "jxdi5", + "col189": "yeoch", + "col190": "vuufj", + "col191": "fwvnm", + "col192": "9oq8h", + "col193": "lvb5g", + "col194": "oww5q", + "col195": "9esjw", + "col196": "zifr7", + "col197": "3llc7", + "col198": "aj298", + "col199": "n9dia", + "col200": "11oye", + "col201": "s5fce", + "col202": "q4pux", + "col203": "o6haw", + "col204": "7ce4i", + "col205": "vktzj", + "col206": "uekqq", + "col207": "wnbhb", + "col208": "jlylp", + "col209": "kuxvm", + "col210": "qdxp0", + "col211": "yr1vt", + "col212": "9pbbo", + "col213": "ltg3u", + "col214": "jvyoj", + "col215": "dd6fv", + "col216": "tsszx", + "col217": "zmvp2", + "col218": "4rwqh", + "col219": "t9l2o", + "col220": "u4l5e", + "col221": "xyu5d", + "col222": "uxj2o", + "col223": "bfgaa", + "col224": "d1fp6", + "col225": "ni9za", + "col226": "r38uy", + "col227": "v37z6", + "col228": "fc7b8", + "col229": "m2y94", + "col230": "0h7av", + "col231": "1trtk", + "col232": "j9v0q", + "col233": "1rjno", + "col234": "gane8", + "col235": "7nmte", + "col236": "ydh0d", + "col237": "x5ni3", + "col238": "f1hqi", + "col239": "2bm4y", + "col240": "xrwsl", + "col241": "1zwsq", + "col242": "xbpqu", + "col243": "go2kx", + "col244": "fhahw", + "col245": "ksm33", + "col246": "acxku", + "col247": "zu1xq", + "col248": "uh8ul", + "col249": "0ud8a", + "col250": "o8adi", + "col251": "iqksi", + "col252": "as8vw", + "col253": "k0f66", + "col254": "2el36", + "col255": "0c5oh", + "col256": "sqjvr", + "col257": "8442q", + "col258": "l90qd", + "col259": "nk8ad", + "col260": "hm897", + "col261": "6p5ow", + "col262": "6mq4r", + "col263": "vgq3x", + "col264": "6x4ph", + "col265": "g53c3", + "col266": "jys4h", + "col267": "zn1xg", + "col268": "cufwh", + "col269": "xedmc", + "col270": "7n9zc", + "col271": "dde2o", + "col272": "b8hio", + "col273": "aez1w", + "col274": "s2esj", + "col275": "2gywn", + "col276": "872so", + "col277": "v12rp", + "col278": "qy2wf", + "col279": "oe9vn", + "col280": "zwdy8", + "col281": "fs2l2", + "col282": "oojh9", + "col283": "jtilp", + "col284": "nlw6o", + "col285": "yw1p5", + "col286": "nfpyu", + "col287": "ddpxn", + "col288": "19dbk", + "col289": "3javx", + "col290": "8oo49", + "col291": "8db94", + "col292": "86v0k", + "col293": "rr094", + "col294": "dnfku", + "col295": "6hd9j", + "col296": "bk3a6", + "col297": "f18wi", + "col298": "4sfwn", + "col299": "91q82", + "col300": "vk1o5", + "col301": "7t2tv", + "col302": "thu5v", + "col303": "260d5", + "col304": "hozor", + "col305": "h29u2", + "col306": "84gb3", + "col307": "eitar", + "col308": "0c7di", + "col309": "ip86x", + "col310": "82mlz", + "col311": "wj7sc", + "col312": "ikhqx", + "col313": "4yd4z", + "col314": "d98ok", + "col315": "qks8w", + "col316": "143f4", + "col317": "dqv9w", + "col318": "2jtv9", + "col319": "9mjtd", + "col320": "923ns", + "col321": "03cbe", + "col322": "2qndj", + "col323": "aawrs", + "col324": "cg7vk", + "col325": "lsx82", + "col326": "95w6w", + "col327": "wr6ab", + "col328": "tjgs0", + "col329": "u67sc", + "col330": "86rgb", + "col331": "jn364", + "col332": "k81ds", + "col333": "xaqgd", + "col334": "tr6ck", + "col335": "xk44d", + "col336": "et6gc", + "col337": "m2jws", + "col338": "d2fj0", + "col339": "dg86j", + "col340": "s7j1p", + "col341": "ohje5", + "col342": "d0epn", + "col343": "lqio5", + "col344": "8q4il", + "col345": "xq1z2", + "col346": "tqgh6", + "col347": "rawf3", + "col348": "0xfie", + "col349": "so5fq", + "col350": "1spr1", + "col351": "e70qk", + "col352": "n426a", + "col353": "cufdf", + "col354": "yx8hb", + "col355": "kqdsx", + "col356": "xix64", + "col357": "6z8x1", + "col358": "qo45d", + "col359": "8qw39", + "col360": "pjpq3", + "col361": "rbli6", + "col362": "iom5h", + "col363": "0tofw", + "col364": "dp532", + "col365": "38czx", + "col366": "q9rlx", + "col367": "7f2ar", + "col368": "dcz6k", + "col369": "bd1m6", + "col370": "u4n09", + "col371": "4nina", + "col372": "sv0xe", + "col373": "9tvp0", + "col374": "jtfuc", + "col375": "htqxq", + "col376": "bhu7u", + "col377": "pwjyo", + "col378": "bh1gq", + "col379": "ro36u", + "col380": "uye2v", + "col381": "z94xa", + "col382": "aezh5", + "col383": "6aj1n", + "col384": "b6wt4", + "col385": "ne3ah", + "col386": "u4b6u", + "col387": "i8hpl", + "col388": "5gkpy", + "col389": "vt5pi", + "col390": "in1p9", + "col391": "g5pk7", + "col392": "isnng", + "col393": "v19g8", + "col394": "wbe4c", + "col395": "2j3zo", + "col396": "tdgx1", + "col397": "1tpmv", + "col398": "9rhtm", + "col399": "kurtv", + "col400": "ueaji", + "col401": "7640g", + "col402": "9c5ay", + "col403": "u2cv0", + "col404": "hol7u", + "col405": "z2j6p", + "col406": "n2y73", + "col407": "hhzkh", + "col408": "q1aop", + "col409": "xmyaq", + "col410": "0rejc", + "col411": "2zopc", + "col412": "84t3e", + "col413": "lbbx2", + "col414": "2g0ui", + "col415": "8fi1x", + "col416": "ulars", + "col417": "0kam3", + "col418": "r3dxz", + "col419": "rz2ul", + "col420": "hta5k", + "col421": "iz6jo", + "col422": "yfo2l", + "col423": "1vdrs", + "col424": "3r5df", + "col425": "5c1li", + "col426": "c7bdz", + "col427": "sked2", + "col428": "o7xxa", + "col429": "cdh7k", + "col430": "njm60", + "col431": "rz45z", + "col432": "49zm7", + "col433": "uz2wg", + "col434": "f13ya", + "col435": "3jl4x", + "col436": "o3xem", + "col437": "h8tsy", + "col438": "5bjop", + "col439": "rxh2w", + "col440": "e5aai", + "col441": "jhbkb", + "col442": "1vajx", + "col443": "ahnzd", + "col444": "6ni5p", + "col445": "2wbsy", + "col446": "2wh5h", + "col447": "a5lj1", + "col448": "6h7b9", + "col449": "hc6fz", + "col450": "mbzxj", + "col451": "cv9yl", + "col452": "qspqv", + "col453": "95wei", + "col454": "vn0wf", + "col455": "wgwow", + "col456": "a9g1q", + "col457": "vfyfh", + "col458": "uwcp1", + "col459": "7x231", + "col460": "uvqfy", + "col461": "j7l6x", + "col462": "2ikn3", + "col463": "yazdd", + "col464": "qz8k1", + "col465": "qh48c", + "col466": "7fdx7", + "col467": "cga9v", + "col468": "1p606", + "col469": "cxkvm", + "col470": "hhkmt", + "col471": "4yl8l", + "col472": "wxnjk", + "col473": "yolqp", + "col474": "49x8d", + "col475": "8m9fj", + "col476": "vfnfw", + "col477": "nvhct", + "col478": "mxto7", + "col479": "89lol", + "col480": "2yzd8", + "col481": "2zc0e", + "col482": "c80om", + "col483": "wn72v", + "col484": "b99p8", + "col485": "b99i5", + "col486": "ctn38", + "col487": "smdrk", + "col488": "mo36i", + "col489": "gh5bf", + "col490": "es52o", + "col491": "rtjc6", + "col492": "1sr01", + "col493": "t0io9", + "col494": "41sj8", + "col495": "34iwv", + "col496": "4cngi", + "col497": "63yan", + "col498": "z19m2", + "col499": "zhaq0", + "col500": "m4izz", + "col501": "h3tko", + "col502": "hv1bw", + "col503": "f6psu", + "col504": "miadn", + "col505": "v8378", + "col506": "uazvf", + "col507": "kr2bw", + "col508": "g0xs2", + "col509": "3wug1", + "col510": "u5wu3", + "col511": "208hq", + "col512": "ntsu4", + "col513": "pj95o", + "col514": "mjpth", + "col515": "dd9uo", + "col516": "r5yn7", + "col517": "9gjfs", + "col518": "w01bt", + "col519": "zx03q", + "col520": "p53xq", + "col521": "236e3", + "col522": "61f3d", + "col523": "piafy", + "col524": "lcgdo", + "col525": "dh27v", + "col526": "2j6cs", + "col527": "s9qa6", + "col528": "16uag", + "col529": "ysh91", + "col530": "ffbpm", + "col531": "j6bnf", + "col532": "ld3g3", + "col533": "ou4bx", + "col534": "4mbo6", + "col535": "ejivm", + "col536": "944mg", + "col537": "jta61", + "col538": "p8ypz", + "col539": "dg829", + "col540": "e1fbg", + "col541": "23mn6", + "col542": "fatcx", + "col543": "0dol7", + "col544": "sae04", + "col545": "mvzrk", + "col546": "perqi", + "col547": "e8x87", + "col548": "3qtgl", + "col549": "am8jx", + "col550": "ecfnh", + "col551": "3vzl6", + "col552": "rkf5u", + "col553": "pfu1n", + "col554": "p43yd", + "col555": "jpv6z", + "col556": "8ndat", + "col557": "jc9s1", + "col558": "u81p2", + "col559": "0c4xh", + "col560": "gf1tb", + "col561": "13yie", + "col562": "l1mny", + "col563": "e17dx", + "col564": "bua18", + "col565": "mlvxz", + "col566": "xoypg", + "col567": "o1lc0", + "col568": "bn2m5", + "col569": "v59ox", + "col570": "luqau", + "col571": "7q8w3", + "col572": "gcjd7", + "col573": "9bxs3", + "col574": "moju0", + "col575": "7j379", + "col576": "iy2sh", + "col577": "4frvg", + "col578": "p0oob", + "col579": "2u6eo", + "col580": "tx07v", + "col581": "i91l2", + "col582": "gw4ww", + "col583": "l2otj", + "col584": "fg5ie", + "col585": "sdwyp", + "col586": "8rvum", + "col587": "1bq4k", + "col588": "yp05u", + "col589": "fcghf", + "col590": "m4e5m", + "col591": "9uo4t", + "col592": "pydha", + "col593": "ijznp", + "col594": "46fhe", + "col595": "lkhy9", + "col596": "uqn6r", + "col597": "zc63k", + "col598": "y4875", + "col599": "d7p88", + "col600": "v81sa", + "col601": "hobzo", + "col602": "kfikd", + "col603": "q1i25", + "col604": "vuof7", + "col605": "xqzk6", + "col606": "qjcc9", + "col607": "z3iz7", + "col608": "ciyqy", + "col609": "mgnqu", + "col610": "7shxk", + "col611": "bbkfk", + "col612": "961kt", + "col613": "ulruf", + "col614": "i58ua", + "col615": "5drfl", + "col616": "afq0r", + "col617": "je7w5", + "col618": "3wjp4", + "col619": "wxpn7", + "col620": "axmuo", + "col621": "kq2md", + "col622": "072r5", + "col623": "q39kn", + "col624": "ioxie", + "col625": "ynf2j", + "col626": "mlaua", + "col627": "uasi7", + "col628": "pytwy", + "col629": "34dy5", + "col630": "h7td8", + "col631": "t6tnq", + "col632": "jryeu", + "col633": "ldpdg", + "col634": "c68qm", + "col635": "td626", + "col636": "ahwef", + "col637": "46q27", + "col638": "atx62", + "col639": "g29je", + "col640": "0kpsd", + "col641": "rvcrd", + "col642": "68uin", + "col643": "8f819", + "col644": "p3656", + "col645": "66mfp", + "col646": "cuead", + "col647": "u7b6z", + "col648": "s5fsb", + "col649": "qqcig", + "col650": "zf0do", + "col651": "athid", + "col652": "40lpv", + "col653": "5a7pu", + "col654": "erwt4", + "col655": "osmv9", + "col656": "jdezm", + "col657": "ozhn7", + "col658": "97p97", + "col659": "3jgl5", + "col660": "y9eri", + "col661": "67nrn", + "col662": "exbjd", + "col663": "kxrt9", + "col664": "4jk72", + "col665": "4nk10", + "col666": "qqucl", + "col667": "papft", + "col668": "22put", + "col669": "opeu8", + "col670": "er0ya", + "col671": "fj8xg", + "col672": "diljd", + "col673": "1vxu2", + "col674": "3ith7", + "col675": "z0if3", + "col676": "t9474", + "col677": "l6kbc", + "col678": "yqy8c", + "col679": "f0atx", + "col680": "sfh5c", + "col681": "oolsz", + "col682": "eya23", + "col683": "hb7ek", + "col684": "3d050", + "col685": "f5d4d", + "col686": "4uipb", + "col687": "8zuea", + "col688": "x15zy", + "col689": "ezd9h", + "col690": "89b3w", + "col691": "wp5b5", + "col692": "luatm", + "col693": "xg1p1", + "col694": "eev4r", + "col695": "lr7gb", + "col696": "gczcz", + "col697": "816hu", + "col698": "vogcg", + "col699": "nylwz", + "col700": "2dh28", + "col701": "hu5tp", + "col702": "y1lrh", + "col703": "vabmf", + "col704": "nazg1", + "col705": "rvu4x", + "col706": "o2m3y", + "col707": "20lcl", + "col708": "eet7y", + "col709": "xxnk1", + "col710": "rw6m3", + "col711": "7mziw", + "col712": "1w6r7", + "col713": "vwi6h", + "col714": "yk2db", + "col715": "gw42l", + "col716": "y0nt8", + "col717": "ys3w6", + "col718": "6c52j", + "col719": "szw7j", + "col720": "d4nkq", + "col721": "3ix0o", + "col722": "r8oey", + "col723": "7zjnq", + "col724": "tl4k0", + "col725": "1kah7", + "col726": "n9zhm", + "col727": "rllw0", + "col728": "l3smv", + "col729": "cxufw", + "col730": "bwc36", + "col731": "h790v", + "col732": "l0l1o", + "col733": "1fgme", + "col734": "gbius", + "col735": "znkoo", + "col736": "da0b2", + "col737": "h6vgc", + "col738": "qlxqb", + "col739": "kxzee", + "col740": "dlalx", + "col741": "81kh3", + "col742": "pp472", + "col743": "2xpfi", + "col744": "tcwi6", + "col745": "6dhnx", + "col746": "f526f", + "col747": "4551r", + "col748": "3meno", + "col749": "rd4r1", + "col750": "bwi8g", + "col751": "yjjnu", + "col752": "jwf82", + "col753": "pw51y", + "col754": "84cqb", + "col755": "abr0r", + "col756": "8jt7x", + "col757": "mhnfg", + "col758": "m4pn6", + "col759": "nfdzf", + "col760": "959h0", + "col761": "8ecdq", + "col762": "vamc0", + "col763": "u8zfv", + "col764": "kust4", + "col765": "v39eb", + "col766": "snnsw", + "col767": "9mhqg", + "col768": "3sgsi", + "col769": "6xdi3", + "col770": "0svil", + "col771": "ftgr4", + "col772": "wnufz", + "col773": "tjgbr", + "col774": "6p11r", + "col775": "k39bt", + "col776": "7jzt2", + "col777": "byfrp", + "col778": "277y8", + "col779": "zophz", + "col780": "7zzd6", + "col781": "e6nth", + "col782": "t6jly", + "col783": "yyaax", + "col784": "n67iy", + "col785": "hoi41", + "col786": "gg641", + "col787": "zky3n", + "col788": "pd1f7", + "col789": "xlrdl", + "col790": "09yum", + "col791": "5rkse", + "col792": "4aclz", + "col793": "kftho", + "col794": "5f3j6", + "col795": "c59f0", + "col796": "l58vf", + "col797": "2y1hv", + "col798": "q97wo", + "col799": "ea9q1", + "col800": "51tv1", + "col801": "eougo", + "col802": "edsss", + "col803": "63fpe", + "col804": "bacw3", + "col805": "ifpu3", + "col806": "mxp4g", + "col807": "vxriu", + "col808": "6d14d", + "col809": "3i2qo", + "col810": "juksv", + "col811": "znszz", + "col812": "t82vh", + "col813": "jbwm1", + "col814": "hptd0", + "col815": "8x4np", + "col816": "jf8sf", + "col817": "5iihl", + "col818": "mvxxm", + "col819": "90rd4", + "col820": "ka8he", + "col821": "cl9sw", + "col822": "jsk62", + "col823": "1etin", + "col824": "jn4xx", + "col825": "7ff1e", + "col826": "n3dx3", + "col827": "irski", + "col828": "0q8jo", + "col829": "3kfcn", + "col830": "s4xhe", + "col831": "kd3q2", + "col832": "db1t2", + "col833": "ftsvl", + "col834": "lrrqi", + "col835": "hc6um", + "col836": "gk5dd", + "col837": "120w6", + "col838": "jfl78", + "col839": "hexq0", + "col840": "r7u1s", + "col841": "9qaxa", + "col842": "u5crn", + "col843": "6f8ak", + "col844": "r58pn", + "col845": "nqeb8", + "col846": "qjcn6", + "col847": "bd2wo", + "col848": "nrkee", + "col849": "jxc4m", + "col850": "mi9bq", + "col851": "rj08u", + "col852": "0bd4a", + "col853": "u8hs4", + "col854": "sbxq9", + "col855": "w6rix", + "col856": "lfqf3", + "col857": "ny2mh", + "col858": "gi113", + "col859": "ytwsc", + "col860": "meowl", + "col861": "n9hid", + "col862": "6003g", + "col863": "xpw57", + "col864": "hao5v", + "col865": "d147g", + "col866": "3ir4n", + "col867": "xyxdv", + "col868": "47mee", + "col869": "3kto6", + "col870": "5gpbp", + "col871": "ckkoq", + "col872": "z8zlt", + "col873": "rywrb", + "col874": "rpo6v", + "col875": "vifjd", + "col876": "5dleb", + "col877": "tbbdj", + "col878": "dlynr", + "col879": "xjo73", + "col880": "5h922", + "col881": "wex4p", + "col882": "zo8bc", + "col883": "6kouf", + "col884": "1489h", + "col885": "6fjrj", + "col886": "76kha", + "col887": "e576d", + "col888": "eka4w", + "col889": "rbbf0", + "col890": "tzxs4", + "col891": "m3lua", + "col892": "5x5am", + "col893": "20f91", + "col894": "4fba2", + "col895": "2x5ik", + "col896": "4epph", + "col897": "q1mjc", + "col898": "zomqs", + "col899": "zl7lp", + "col900": "oqs25", + "col901": "roavr", + "col902": "637pn", + "col903": "v0hv3", + "col904": "i8w6o", + "col905": "d1ozk", + "col906": "tgp4s", + "col907": "2gnfm", + "col908": "ffpyt", + "col909": "fuyaa", + "col910": "yfnze", + "col911": "slqc9", + "col912": "0ibkr", + "col913": "xa6j1", + "col914": "cro9l", + "col915": "zm9wg", + "col916": "hvnbw", + "col917": "cj83t", + "col918": "gp4b8", + "col919": "f3d78", + "col920": "mu6zf", + "col921": "at9r4", + "col922": "o21ha", + "col923": "6po5d", + "col924": "frjcz", + "col925": "rn1gu", + "col926": "u4ah3", + "col927": "bw3jz", + "col928": "ek3jj", + "col929": "vstea", + "col930": "x1oz8", + "col931": "hrutd", + "col932": "ijrku", + "col933": "1zqzs", + "col934": "voorf", + "col935": "oov4x", + "col936": "mf91c", + "col937": "2l2io", + "col938": "eunwr", + "col939": "4de7u", + "col940": "88561", + "col941": "03o84", + "col942": "87e0z", + "col943": "3fymd", + "col944": "18mbs", + "col945": "ctpui", + "col946": "rgvk7", + "col947": "soien", + "col948": "i9toc", + "col949": "3mazj", + "col950": "tnu1g", + "col951": "4ztht", + "col952": "o2v40", + "col953": "d3tio", + "col954": "f2y78", + "col955": "ehzcl", + "col956": "nlp9t", + "col957": "p3rxx", + "col958": "5408h", + "col959": "fvwnb", + "col960": "0ytpc", + "col961": "28j8y", + "col962": "dm85i", + "col963": "z2kyo", + "col964": "104cv", + "col965": "wz6ol", + "col966": "w1mmg", + "col967": "4xvnl", + "col968": "30j23", + "col969": "31379", + "col970": "lid3b", + "col971": "affrm", + "col972": "etfcz", + "col973": "zlm95", + "col974": "66sih", + "col975": "j244v", + "col976": "kowsc", + "col977": "c79j0", + "col978": "8mevq", + "col979": "0xehp", + "col980": "awzpw", + "col981": "4k2da", + "col982": "8bvt6", + "col983": "7pcy1", + "col984": "hz6dw", + "col985": "yzeqf", + "col986": "don3b", + "col987": "8sl9o", + "col988": "q6n9b", + "col989": "zhq6c", + "col990": "ze2rj", + "col991": "6454j", + "col992": "3fzv4", + "col993": "pqzhw", + "col994": "e7mkb", + "col995": "4erty", + "col996": "d9mzg", + "col997": "5agxv", + "col998": "dvqfd", + "col999": "e2o74" + }, + { + "name": "Harris Pollard", + "gender": "male", + "col0": "rm0vo", + "col1": "y9spp", + "col2": "57g6x", + "col3": "6vsp6", + "col4": "v7amz", + "col5": "ryzbt", + "col6": "d62cd", + "col7": "ayxal", + "col8": "zl2jb", + "col9": "x05nt", + "col10": "9ggbn", + "col11": "bwub6", + "col12": "z8y00", + "col13": "q5949", + "col14": "u48dc", + "col15": "ghsxl", + "col16": "gkn5m", + "col17": "5ncjv", + "col18": "2c59a", + "col19": "0rael", + "col20": "thmcw", + "col21": "7tq3f", + "col22": "3jfod", + "col23": "190jm", + "col24": "p7h6d", + "col25": "8xwj8", + "col26": "ueajx", + "col27": "er26s", + "col28": "g92m6", + "col29": "09iil", + "col30": "64ysv", + "col31": "gq0pe", + "col32": "71jhi", + "col33": "3demg", + "col34": "9l1mn", + "col35": "hhdhy", + "col36": "mk3f7", + "col37": "u8gtz", + "col38": "jh5p4", + "col39": "i4mrz", + "col40": "47dy4", + "col41": "ebayf", + "col42": "tep80", + "col43": "x0es7", + "col44": "6rqpk", + "col45": "hb7tq", + "col46": "12vf4", + "col47": "oa1eg", + "col48": "yqonm", + "col49": "jcdxr", + "col50": "kpe4z", + "col51": "5c18p", + "col52": "gxi43", + "col53": "xlneh", + "col54": "znvc5", + "col55": "c469k", + "col56": "pwims", + "col57": "z3j0o", + "col58": "euw7o", + "col59": "kvc7k", + "col60": "9tcxr", + "col61": "v735b", + "col62": "8t5pi", + "col63": "ri0nq", + "col64": "14e13", + "col65": "d1fck", + "col66": "n56ig", + "col67": "w4e1z", + "col68": "5z9da", + "col69": "maaqt", + "col70": "khyu5", + "col71": "ei6ig", + "col72": "z21vi", + "col73": "xaii0", + "col74": "qgiko", + "col75": "m0qqk", + "col76": "vczsg", + "col77": "uhn7q", + "col78": "4fbh4", + "col79": "bq94p", + "col80": "5tb0v", + "col81": "988nx", + "col82": "h7ok0", + "col83": "xhuom", + "col84": "qjqke", + "col85": "c94rd", + "col86": "mta8p", + "col87": "2vfik", + "col88": "v8q35", + "col89": "eianz", + "col90": "b7x9w", + "col91": "wqerb", + "col92": "15kro", + "col93": "fnwqk", + "col94": "03qz1", + "col95": "4e2ub", + "col96": "kiy37", + "col97": "ptxzr", + "col98": "a45ca", + "col99": "60dlr", + "col100": "s81dy", + "col101": "ve29h", + "col102": "ku59t", + "col103": "0ppar", + "col104": "nmuv0", + "col105": "wgr67", + "col106": "d55mi", + "col107": "021dk", + "col108": "rwk0a", + "col109": "yvbf3", + "col110": "i9db8", + "col111": "nyxuf", + "col112": "uahuj", + "col113": "78n06", + "col114": "ur1n2", + "col115": "8kh7c", + "col116": "pe1ta", + "col117": "nyd9p", + "col118": "ia5zp", + "col119": "dvxmm", + "col120": "kz7fp", + "col121": "1y0fg", + "col122": "plg2i", + "col123": "yp9zl", + "col124": "8lqm5", + "col125": "5ugv7", + "col126": "r36ch", + "col127": "3kw6a", + "col128": "0xpqh", + "col129": "cp3gg", + "col130": "f72yq", + "col131": "bpj8d", + "col132": "futue", + "col133": "5sifr", + "col134": "wh5m3", + "col135": "ahkmz", + "col136": "yhkcs", + "col137": "l8b8l", + "col138": "yksuw", + "col139": "4d7ht", + "col140": "iu8ex", + "col141": "090id", + "col142": "xvn6j", + "col143": "83s4o", + "col144": "9gkb7", + "col145": "vpenr", + "col146": "x5bmy", + "col147": "sod5g", + "col148": "40zdn", + "col149": "dg66d", + "col150": "33pnf", + "col151": "7cqok", + "col152": "qdo9z", + "col153": "5zkly", + "col154": "h7ngu", + "col155": "j6dyg", + "col156": "vwenx", + "col157": "a4ros", + "col158": "scwkf", + "col159": "9epje", + "col160": "tt9du", + "col161": "aw0ps", + "col162": "jqtrp", + "col163": "u642f", + "col164": "4onv7", + "col165": "2flgx", + "col166": "0lsxt", + "col167": "cork6", + "col168": "thd4i", + "col169": "c440l", + "col170": "gnhfs", + "col171": "ccz9r", + "col172": "9y2ls", + "col173": "bo89v", + "col174": "9y2ha", + "col175": "ghzp7", + "col176": "fvdk1", + "col177": "b38vy", + "col178": "xkdql", + "col179": "np5hm", + "col180": "2xpja", + "col181": "ad722", + "col182": "tw4y5", + "col183": "gkuc0", + "col184": "lu4r6", + "col185": "331nx", + "col186": "7guc7", + "col187": "xqhc1", + "col188": "uu2cp", + "col189": "17i4s", + "col190": "vucwe", + "col191": "4c451", + "col192": "q2xjz", + "col193": "qp36u", + "col194": "6xrnl", + "col195": "9ib3d", + "col196": "c6p30", + "col197": "2evfs", + "col198": "uoj3b", + "col199": "hj6ez", + "col200": "zz9wb", + "col201": "if513", + "col202": "39xax", + "col203": "7mb1l", + "col204": "g9cix", + "col205": "0oupb", + "col206": "6tb6r", + "col207": "gswss", + "col208": "u7wvf", + "col209": "yuubr", + "col210": "4wokk", + "col211": "xm41d", + "col212": "7srn1", + "col213": "0x4t7", + "col214": "bnen9", + "col215": "kcvl1", + "col216": "r8lcd", + "col217": "qyqj7", + "col218": "i18i2", + "col219": "5b2wl", + "col220": "38wmz", + "col221": "9gjk5", + "col222": "7rlur", + "col223": "ggyn9", + "col224": "2bnb0", + "col225": "9unlh", + "col226": "zhnyw", + "col227": "nb58z", + "col228": "ot7mh", + "col229": "tv3xl", + "col230": "copa0", + "col231": "ng81w", + "col232": "l6sat", + "col233": "fgwmu", + "col234": "8tu9w", + "col235": "g2n5i", + "col236": "2c5wp", + "col237": "tmjmf", + "col238": "g43ta", + "col239": "dctkq", + "col240": "s2k6z", + "col241": "wjcb5", + "col242": "xbbfg", + "col243": "fc49k", + "col244": "2mhx3", + "col245": "epwdr", + "col246": "ps21y", + "col247": "uamf0", + "col248": "8imom", + "col249": "6tgf5", + "col250": "zok7w", + "col251": "l2432", + "col252": "hlgbr", + "col253": "kkisp", + "col254": "jl06l", + "col255": "b7mt4", + "col256": "f1dl9", + "col257": "xxu0m", + "col258": "vclni", + "col259": "zn9pf", + "col260": "qtvko", + "col261": "e65dx", + "col262": "aeame", + "col263": "j4rpr", + "col264": "qihl5", + "col265": "5fvtb", + "col266": "lurxl", + "col267": "ma0qb", + "col268": "5tbnv", + "col269": "w8sco", + "col270": "rmbs7", + "col271": "tzbdb", + "col272": "zvz6i", + "col273": "p1ynu", + "col274": "ikaoc", + "col275": "i0pt1", + "col276": "40t3n", + "col277": "h8eyj", + "col278": "z1h6v", + "col279": "7ia99", + "col280": "uavau", + "col281": "fvj8y", + "col282": "d77s1", + "col283": "vch4x", + "col284": "t38wm", + "col285": "bx2c8", + "col286": "9n7sq", + "col287": "0h93i", + "col288": "kxyzn", + "col289": "nvdwq", + "col290": "yaqej", + "col291": "7xmnn", + "col292": "hct9k", + "col293": "mgdtf", + "col294": "hmocu", + "col295": "nrldf", + "col296": "j5u7c", + "col297": "trllm", + "col298": "je1a9", + "col299": "qyctn", + "col300": "k6pee", + "col301": "nczpm", + "col302": "80bz5", + "col303": "lgqa2", + "col304": "6ouwi", + "col305": "jknkm", + "col306": "lpy8e", + "col307": "2g0tj", + "col308": "smb63", + "col309": "fmh8g", + "col310": "a2g5x", + "col311": "320k8", + "col312": "w9lfi", + "col313": "ca6f0", + "col314": "0h9lv", + "col315": "y860s", + "col316": "fyw4i", + "col317": "nofi7", + "col318": "rnm4w", + "col319": "byptq", + "col320": "uamm1", + "col321": "c6z8z", + "col322": "yuj7h", + "col323": "8dftt", + "col324": "178z6", + "col325": "fmyyr", + "col326": "6dvoy", + "col327": "6z38i", + "col328": "db832", + "col329": "mwmg5", + "col330": "ngfrp", + "col331": "gewps", + "col332": "hosxz", + "col333": "q5csk", + "col334": "017i3", + "col335": "ihu58", + "col336": "nv6fp", + "col337": "l5vk4", + "col338": "ih4v6", + "col339": "id2pc", + "col340": "0zk1h", + "col341": "wr925", + "col342": "3t2cy", + "col343": "31w4j", + "col344": "oq6kp", + "col345": "kj2ka", + "col346": "epk8t", + "col347": "wln9q", + "col348": "2ktzs", + "col349": "wuci2", + "col350": "tniy8", + "col351": "riqel", + "col352": "zw6t6", + "col353": "0tlfj", + "col354": "f7p64", + "col355": "up2ne", + "col356": "u2ztf", + "col357": "0roik", + "col358": "jgxla", + "col359": "avlhz", + "col360": "1zvyh", + "col361": "mshsl", + "col362": "afija", + "col363": "5wrjf", + "col364": "wfqr2", + "col365": "pdi6s", + "col366": "1k0of", + "col367": "m74pr", + "col368": "vllde", + "col369": "eyjk7", + "col370": "5q8r7", + "col371": "ovin5", + "col372": "vfzag", + "col373": "3zq4w", + "col374": "tul1e", + "col375": "lcryx", + "col376": "l8x8a", + "col377": "d2dbc", + "col378": "u0i0h", + "col379": "sqxji", + "col380": "1556j", + "col381": "os2r7", + "col382": "93qks", + "col383": "rvkro", + "col384": "nl3kh", + "col385": "o3p4k", + "col386": "xtyjd", + "col387": "x2xwy", + "col388": "paopz", + "col389": "dvnn7", + "col390": "5gpcf", + "col391": "lbvdc", + "col392": "n85qo", + "col393": "9nc6y", + "col394": "fb6ie", + "col395": "kq9ou", + "col396": "ra6ar", + "col397": "zkj11", + "col398": "2lzkq", + "col399": "3uqoo", + "col400": "rdkvs", + "col401": "jb1bw", + "col402": "7jle8", + "col403": "8jtvo", + "col404": "j7e0w", + "col405": "dyals", + "col406": "rprvx", + "col407": "eyl66", + "col408": "oq0a0", + "col409": "ixcz1", + "col410": "is5tm", + "col411": "ucttd", + "col412": "9rlsy", + "col413": "kex47", + "col414": "t5102", + "col415": "jsdix", + "col416": "b4zw7", + "col417": "21q7n", + "col418": "4fwkb", + "col419": "yhsk8", + "col420": "yia56", + "col421": "1odrc", + "col422": "3jbvj", + "col423": "5faqt", + "col424": "xaueq", + "col425": "nw4x6", + "col426": "fn9aw", + "col427": "e9ah1", + "col428": "1p8kb", + "col429": "pzert", + "col430": "bnmc0", + "col431": "h7nnn", + "col432": "t5i7m", + "col433": "rviiq", + "col434": "k099o", + "col435": "4r7uu", + "col436": "8hvqk", + "col437": "1pu3w", + "col438": "o39ch", + "col439": "1ypvy", + "col440": "f9sun", + "col441": "7h8ag", + "col442": "lvyei", + "col443": "y1qs8", + "col444": "osihr", + "col445": "fkt0y", + "col446": "jsvhv", + "col447": "oqebl", + "col448": "2ip1n", + "col449": "e18cn", + "col450": "j80vy", + "col451": "55nf0", + "col452": "6tpye", + "col453": "q93no", + "col454": "yo33n", + "col455": "5z9sw", + "col456": "pi7o6", + "col457": "tq4qi", + "col458": "ngsyr", + "col459": "re1q8", + "col460": "b61r8", + "col461": "16jv1", + "col462": "ml9po", + "col463": "fy704", + "col464": "5nub7", + "col465": "ylgvk", + "col466": "4rb0o", + "col467": "o8r4l", + "col468": "b8pos", + "col469": "2g1cp", + "col470": "pp5a7", + "col471": "tui46", + "col472": "fq74o", + "col473": "s00wn", + "col474": "avwrv", + "col475": "hlmjp", + "col476": "ii9qt", + "col477": "a4zof", + "col478": "g4te0", + "col479": "bsd3k", + "col480": "o1uw9", + "col481": "x1inj", + "col482": "2ajdy", + "col483": "0rbku", + "col484": "2nauz", + "col485": "tkqu7", + "col486": "fbjts", + "col487": "jfom0", + "col488": "23771", + "col489": "8lki5", + "col490": "qyk3s", + "col491": "tmpoe", + "col492": "iqduy", + "col493": "wglsr", + "col494": "l1i53", + "col495": "m02jt", + "col496": "u4x80", + "col497": "a19ml", + "col498": "p8m2x", + "col499": "2ioch", + "col500": "hjxcl", + "col501": "lydwb", + "col502": "own0j", + "col503": "my0d6", + "col504": "ecefk", + "col505": "i8dvf", + "col506": "kd48l", + "col507": "i2m2w", + "col508": "om18p", + "col509": "n8szm", + "col510": "08n72", + "col511": "buee4", + "col512": "6zkle", + "col513": "0cx5y", + "col514": "x0fsq", + "col515": "8pjmo", + "col516": "8ogt4", + "col517": "hfph1", + "col518": "opgki", + "col519": "amxga", + "col520": "ljocc", + "col521": "tjlns", + "col522": "ubwny", + "col523": "1gwqj", + "col524": "1jxzn", + "col525": "yu1qt", + "col526": "rephg", + "col527": "5nmjz", + "col528": "csj1z", + "col529": "ch84r", + "col530": "h03fb", + "col531": "xkyoj", + "col532": "pxhxk", + "col533": "vfsq6", + "col534": "th4l5", + "col535": "xd1qt", + "col536": "2texj", + "col537": "y9kep", + "col538": "ocnde", + "col539": "ub05n", + "col540": "w90mj", + "col541": "obfha", + "col542": "tg2bg", + "col543": "tce2p", + "col544": "ur0d2", + "col545": "unme2", + "col546": "43kce", + "col547": "1ybuy", + "col548": "90pc1", + "col549": "rv45l", + "col550": "tn09m", + "col551": "h5jed", + "col552": "95nk2", + "col553": "j09uy", + "col554": "li81s", + "col555": "o5a4n", + "col556": "uuo98", + "col557": "95l5g", + "col558": "8mxw0", + "col559": "vn3l9", + "col560": "s2svc", + "col561": "o4jaw", + "col562": "emo52", + "col563": "33567", + "col564": "r6bff", + "col565": "4rekh", + "col566": "hxdyp", + "col567": "4t794", + "col568": "66w3f", + "col569": "dr6nx", + "col570": "9nvak", + "col571": "37qwp", + "col572": "9i9fu", + "col573": "8myp0", + "col574": "lpc90", + "col575": "zoin5", + "col576": "2mi4d", + "col577": "0bejw", + "col578": "cdy2r", + "col579": "e6hhe", + "col580": "kgnkl", + "col581": "l7m92", + "col582": "0u7qw", + "col583": "xf4wb", + "col584": "7ao6g", + "col585": "mdbph", + "col586": "m1km9", + "col587": "3vluw", + "col588": "re93m", + "col589": "0ld56", + "col590": "ao3eg", + "col591": "sja5k", + "col592": "u5loj", + "col593": "kqnfh", + "col594": "g6c3d", + "col595": "j3gdq", + "col596": "63zj6", + "col597": "n80g0", + "col598": "zm1m2", + "col599": "auno5", + "col600": "xpj1k", + "col601": "lcitt", + "col602": "zu377", + "col603": "01uwa", + "col604": "uy54x", + "col605": "7koit", + "col606": "yrtmb", + "col607": "7gcvd", + "col608": "f5qbz", + "col609": "o8e05", + "col610": "dgr8c", + "col611": "za3uw", + "col612": "0wvuo", + "col613": "ubbr3", + "col614": "iv69i", + "col615": "r6gzl", + "col616": "6k16n", + "col617": "eyk9t", + "col618": "xvl7h", + "col619": "x5dox", + "col620": "ux9f2", + "col621": "pku8i", + "col622": "r5700", + "col623": "7cxh0", + "col624": "ff856", + "col625": "d9giu", + "col626": "nih34", + "col627": "13e3y", + "col628": "1hxtp", + "col629": "nwo49", + "col630": "sb0sq", + "col631": "9365g", + "col632": "prnoa", + "col633": "ahbgp", + "col634": "cn01n", + "col635": "18puo", + "col636": "64hpw", + "col637": "s38gx", + "col638": "8f8kk", + "col639": "v6e4f", + "col640": "g8g4q", + "col641": "g1cc7", + "col642": "5uagw", + "col643": "8b7f4", + "col644": "nemj3", + "col645": "4sz8e", + "col646": "7tbfj", + "col647": "vz9pz", + "col648": "mf9x3", + "col649": "x35cb", + "col650": "w24w3", + "col651": "1eirs", + "col652": "o0ygv", + "col653": "xwl5m", + "col654": "yfec6", + "col655": "w398l", + "col656": "5g87v", + "col657": "j2h7m", + "col658": "crlqc", + "col659": "hguab", + "col660": "r0fww", + "col661": "x5ijh", + "col662": "h8fpk", + "col663": "75utc", + "col664": "kth04", + "col665": "codki", + "col666": "9ceq5", + "col667": "znmie", + "col668": "n0iap", + "col669": "71576", + "col670": "fcq05", + "col671": "xit97", + "col672": "rafwd", + "col673": "znxz5", + "col674": "tk9z5", + "col675": "d1dtt", + "col676": "5z8mq", + "col677": "1wr0o", + "col678": "tifp5", + "col679": "xq620", + "col680": "acbek", + "col681": "drghl", + "col682": "hdu4z", + "col683": "l3dr6", + "col684": "bx9k2", + "col685": "5og08", + "col686": "d413p", + "col687": "wfvqj", + "col688": "5kl5a", + "col689": "qfko5", + "col690": "4muvx", + "col691": "nyr3w", + "col692": "i6uai", + "col693": "dob6v", + "col694": "ihpit", + "col695": "3fwz6", + "col696": "1lhs2", + "col697": "hxaq1", + "col698": "pqlka", + "col699": "50xbc", + "col700": "1kcsv", + "col701": "jpjsq", + "col702": "km0n9", + "col703": "ji9al", + "col704": "eyys6", + "col705": "znp12", + "col706": "3mzzr", + "col707": "5r2q8", + "col708": "lc8j3", + "col709": "ggf5l", + "col710": "d1zjw", + "col711": "fgchc", + "col712": "dia4v", + "col713": "l9fyn", + "col714": "zs3pr", + "col715": "gt3nf", + "col716": "77y1x", + "col717": "d37jn", + "col718": "s8d1g", + "col719": "y1lae", + "col720": "j4mb0", + "col721": "ermv5", + "col722": "g7arw", + "col723": "udd2g", + "col724": "kj988", + "col725": "npu6n", + "col726": "6jneg", + "col727": "dbemv", + "col728": "mov6q", + "col729": "u9f9v", + "col730": "hebqg", + "col731": "4k6b7", + "col732": "nggvo", + "col733": "3rp0a", + "col734": "9fd3s", + "col735": "1q8z2", + "col736": "min20", + "col737": "26pu7", + "col738": "w5rml", + "col739": "5cvxz", + "col740": "x5p4k", + "col741": "q5nnc", + "col742": "awuz4", + "col743": "y9rye", + "col744": "6fqoz", + "col745": "w98n8", + "col746": "f237b", + "col747": "55w5l", + "col748": "0jt09", + "col749": "g1juz", + "col750": "3vr82", + "col751": "vii6v", + "col752": "hxuyw", + "col753": "726rr", + "col754": "5xoyh", + "col755": "ebo2p", + "col756": "23ilu", + "col757": "r5jrw", + "col758": "90mxt", + "col759": "0miy0", + "col760": "auzr1", + "col761": "3opz0", + "col762": "9r7pa", + "col763": "hbgy8", + "col764": "3ghx2", + "col765": "wu2og", + "col766": "2e28s", + "col767": "2glav", + "col768": "0cxvr", + "col769": "y9c44", + "col770": "8pcvp", + "col771": "j5rdy", + "col772": "qfm53", + "col773": "pzkdz", + "col774": "igha8", + "col775": "ez5ks", + "col776": "k7nq2", + "col777": "0c467", + "col778": "nnyk8", + "col779": "ye4mc", + "col780": "bdeg3", + "col781": "j3u9x", + "col782": "5g68j", + "col783": "xvs07", + "col784": "fcftd", + "col785": "oemgk", + "col786": "4vazr", + "col787": "om2ch", + "col788": "tlkjk", + "col789": "60aia", + "col790": "w0hnw", + "col791": "iu9ev", + "col792": "nvtyj", + "col793": "hlgqx", + "col794": "7y02w", + "col795": "ie86r", + "col796": "6qt4f", + "col797": "6yfr5", + "col798": "b6qlo", + "col799": "uby6d", + "col800": "dwyua", + "col801": "0er4z", + "col802": "2bzin", + "col803": "qzuan", + "col804": "27ttd", + "col805": "ehylu", + "col806": "rjlzr", + "col807": "5bpbg", + "col808": "n6fcm", + "col809": "yf1dl", + "col810": "4yvil", + "col811": "j4j1i", + "col812": "50r9l", + "col813": "txj8d", + "col814": "xq3kn", + "col815": "ys2df", + "col816": "zld9s", + "col817": "zaumr", + "col818": "kzgrt", + "col819": "1xmmc", + "col820": "7csij", + "col821": "cn0wo", + "col822": "pgp84", + "col823": "h6yx6", + "col824": "d7qtu", + "col825": "n4lv7", + "col826": "345om", + "col827": "6he2n", + "col828": "crptg", + "col829": "9pocd", + "col830": "duwgs", + "col831": "5nczt", + "col832": "1kvso", + "col833": "sv23u", + "col834": "d4gvl", + "col835": "dmcf9", + "col836": "suafh", + "col837": "0xqs4", + "col838": "pml1c", + "col839": "c4trl", + "col840": "6w6vr", + "col841": "c01nk", + "col842": "i1qgl", + "col843": "f4qkw", + "col844": "8cyfj", + "col845": "9b6gf", + "col846": "u07vb", + "col847": "128qk", + "col848": "811ak", + "col849": "36so1", + "col850": "l7fa4", + "col851": "b6ca6", + "col852": "jftgr", + "col853": "p5qvr", + "col854": "s6rya", + "col855": "veymu", + "col856": "kg5ip", + "col857": "1zd7u", + "col858": "qinae", + "col859": "6g9tn", + "col860": "5kz81", + "col861": "bgu5n", + "col862": "dp9vx", + "col863": "ufb48", + "col864": "y1dks", + "col865": "yw48a", + "col866": "7wtuf", + "col867": "6zupp", + "col868": "e81ng", + "col869": "6ipzi", + "col870": "pc0w4", + "col871": "7jkls", + "col872": "b3kts", + "col873": "5ylpu", + "col874": "rm7su", + "col875": "odz3u", + "col876": "lzr25", + "col877": "4fgkh", + "col878": "cn44f", + "col879": "mwuz7", + "col880": "28cti", + "col881": "jty0p", + "col882": "pjyh8", + "col883": "6v5ry", + "col884": "66ic4", + "col885": "r2d3q", + "col886": "vnp80", + "col887": "0b3xs", + "col888": "yv062", + "col889": "7dnw0", + "col890": "xzijt", + "col891": "kxdjq", + "col892": "pyzyd", + "col893": "tr4mv", + "col894": "6f5cm", + "col895": "1xxjn", + "col896": "9uvqk", + "col897": "4b2r5", + "col898": "h1sds", + "col899": "ki6y3", + "col900": "7xii6", + "col901": "9cxq3", + "col902": "pqukp", + "col903": "mm7pg", + "col904": "t2tly", + "col905": "h7cl5", + "col906": "jx1c7", + "col907": "d8so3", + "col908": "9zuql", + "col909": "4ejb5", + "col910": "fkc9u", + "col911": "6s0k3", + "col912": "wfbvv", + "col913": "zueiq", + "col914": "bcimk", + "col915": "saf30", + "col916": "if2dy", + "col917": "hx8y9", + "col918": "7ufet", + "col919": "gq6c5", + "col920": "ibvjs", + "col921": "nnn1n", + "col922": "hsekp", + "col923": "j0tvp", + "col924": "lzjmo", + "col925": "81p78", + "col926": "w6sq4", + "col927": "rgiyp", + "col928": "fu3w2", + "col929": "h850i", + "col930": "gpq4w", + "col931": "yjsmv", + "col932": "xp0ru", + "col933": "qi60n", + "col934": "nvpu5", + "col935": "bfkox", + "col936": "jdgt0", + "col937": "0beky", + "col938": "4ich1", + "col939": "dnw63", + "col940": "hdjx0", + "col941": "ei0z7", + "col942": "4xvcv", + "col943": "i77cr", + "col944": "oz1or", + "col945": "z1ei4", + "col946": "305tj", + "col947": "lnf8p", + "col948": "gj7ey", + "col949": "bwixm", + "col950": "i3vo9", + "col951": "loje1", + "col952": "gw456", + "col953": "zg3ls", + "col954": "98onx", + "col955": "uawzv", + "col956": "agyoh", + "col957": "n9gb4", + "col958": "l3t8j", + "col959": "3bz71", + "col960": "ncaqb", + "col961": "132ip", + "col962": "kuj5r", + "col963": "qfis4", + "col964": "es1ti", + "col965": "fjglj", + "col966": "3e30c", + "col967": "8ahmo", + "col968": "1ahwa", + "col969": "0rt5a", + "col970": "r9qst", + "col971": "6qrx8", + "col972": "rv3u9", + "col973": "klvub", + "col974": "q0zbg", + "col975": "mx7fh", + "col976": "mkcuk", + "col977": "ccqyz", + "col978": "45tkd", + "col979": "rnivm", + "col980": "7e0tk", + "col981": "lqyc8", + "col982": "bzklb", + "col983": "zspfs", + "col984": "caopm", + "col985": "qd8bq", + "col986": "v0c5y", + "col987": "akxe9", + "col988": "miq3g", + "col989": "9occv", + "col990": "7z5mi", + "col991": "o0ela", + "col992": "3b0dz", + "col993": "66zns", + "col994": "hhje6", + "col995": "1fvyx", + "col996": "7m8lt", + "col997": "z1smi", + "col998": "ger3e", + "col999": "a401n" + }, + { + "name": "Mable Wilcox", + "gender": "female", + "col0": "2lwec", + "col1": "q3g0h", + "col2": "clxys", + "col3": "xobd9", + "col4": "t2hn2", + "col5": "3onud", + "col6": "qlwui", + "col7": "kjyz1", + "col8": "dzfum", + "col9": "zx2hp", + "col10": "gqpg2", + "col11": "6nwmh", + "col12": "6yi1m", + "col13": "wvr88", + "col14": "v2qzp", + "col15": "4lfvg", + "col16": "j6530", + "col17": "2ii40", + "col18": "mm6mc", + "col19": "f2lg0", + "col20": "qidh0", + "col21": "8jzdz", + "col22": "zaze1", + "col23": "k3ucs", + "col24": "snua3", + "col25": "1g5lh", + "col26": "28oib", + "col27": "eiv5p", + "col28": "dr6w5", + "col29": "ehtc0", + "col30": "1ilor", + "col31": "lgysd", + "col32": "cbak5", + "col33": "h2hbe", + "col34": "bjncp", + "col35": "uq1nz", + "col36": "ee7qf", + "col37": "2ugsf", + "col38": "p4hme", + "col39": "lmh88", + "col40": "3vhei", + "col41": "31vsh", + "col42": "oqx0h", + "col43": "1t52k", + "col44": "5dslh", + "col45": "kxt3h", + "col46": "ucr31", + "col47": "h4fjg", + "col48": "fpw0q", + "col49": "5c93u", + "col50": "cxopb", + "col51": "47ygl", + "col52": "lueat", + "col53": "67cyl", + "col54": "asbev", + "col55": "amodw", + "col56": "57nm4", + "col57": "pafjx", + "col58": "elm87", + "col59": "6e9zc", + "col60": "t2v36", + "col61": "p88w3", + "col62": "kkd54", + "col63": "jaos6", + "col64": "43me8", + "col65": "iv2s8", + "col66": "5omvd", + "col67": "8ahgp", + "col68": "eh5pq", + "col69": "q8nsh", + "col70": "tgqeg", + "col71": "l74df", + "col72": "pcoau", + "col73": "bckq4", + "col74": "ilwnf", + "col75": "u8d8f", + "col76": "mmf7r", + "col77": "k72d1", + "col78": "59jih", + "col79": "hxhti", + "col80": "e4aki", + "col81": "aewwn", + "col82": "tqmmx", + "col83": "y4glb", + "col84": "6jc64", + "col85": "x3u43", + "col86": "1dpvh", + "col87": "it8gf", + "col88": "cfxla", + "col89": "hlzos", + "col90": "l9d8i", + "col91": "ec7pm", + "col92": "4fz06", + "col93": "lzx4p", + "col94": "r8tgj", + "col95": "es1kh", + "col96": "0pjzl", + "col97": "v7ke2", + "col98": "rsosw", + "col99": "k6blq", + "col100": "5cnfy", + "col101": "mdu09", + "col102": "wzn8a", + "col103": "1td11", + "col104": "7l2jl", + "col105": "xzm05", + "col106": "wnvkn", + "col107": "r2ufy", + "col108": "fee5g", + "col109": "gmsyu", + "col110": "3ivlb", + "col111": "anj4w", + "col112": "l8os7", + "col113": "0506a", + "col114": "stu3l", + "col115": "pu8yf", + "col116": "jv2zi", + "col117": "usjkk", + "col118": "qh66l", + "col119": "rp4up", + "col120": "omhb3", + "col121": "cbli9", + "col122": "eh544", + "col123": "zremn", + "col124": "q3xg8", + "col125": "5qmuc", + "col126": "g45oz", + "col127": "fv6qf", + "col128": "dl2yr", + "col129": "ls4e8", + "col130": "cde3u", + "col131": "r3x9u", + "col132": "5vytz", + "col133": "0lmf7", + "col134": "dqvm7", + "col135": "wiq1l", + "col136": "l7j7f", + "col137": "ihg44", + "col138": "y40qo", + "col139": "oj927", + "col140": "wbwoj", + "col141": "un29i", + "col142": "3yfz9", + "col143": "wpeoh", + "col144": "ensaa", + "col145": "1mjvz", + "col146": "5iqae", + "col147": "pcvuw", + "col148": "eevpb", + "col149": "oipog", + "col150": "abwdi", + "col151": "nxmsv", + "col152": "8kra5", + "col153": "k0mj7", + "col154": "52k9w", + "col155": "hn4dd", + "col156": "pe0mo", + "col157": "8x3b2", + "col158": "6i96o", + "col159": "1gm1z", + "col160": "0w48k", + "col161": "ojoe5", + "col162": "m0cgz", + "col163": "mme2b", + "col164": "cvtqr", + "col165": "bjap6", + "col166": "vdzwz", + "col167": "ugx0d", + "col168": "bgzon", + "col169": "qfj7p", + "col170": "h6msu", + "col171": "6x4i5", + "col172": "kk265", + "col173": "54a4s", + "col174": "eiszu", + "col175": "wzonm", + "col176": "tqiuq", + "col177": "q8c1n", + "col178": "5fsmt", + "col179": "sj6dv", + "col180": "1ymmf", + "col181": "jvyfq", + "col182": "wxar6", + "col183": "klnkt", + "col184": "ndpnn", + "col185": "63nhe", + "col186": "v9lhw", + "col187": "bnewj", + "col188": "nsrwe", + "col189": "7r7hn", + "col190": "zpuo2", + "col191": "87cf5", + "col192": "6ponv", + "col193": "0ftqd", + "col194": "jx99m", + "col195": "5ysb4", + "col196": "whpkn", + "col197": "12wr4", + "col198": "k45gb", + "col199": "jsoze", + "col200": "z9gtm", + "col201": "lecso", + "col202": "b6oj1", + "col203": "1qhf9", + "col204": "h0zkw", + "col205": "u7f7w", + "col206": "zz5jr", + "col207": "7rjj0", + "col208": "dts20", + "col209": "83aeq", + "col210": "rigsi", + "col211": "kt2hl", + "col212": "nk5g1", + "col213": "zxe3n", + "col214": "shh3z", + "col215": "ssgui", + "col216": "f3thg", + "col217": "clr58", + "col218": "4qtv3", + "col219": "qp3v4", + "col220": "g1mu6", + "col221": "munca", + "col222": "2hoam", + "col223": "32uwq", + "col224": "epqxl", + "col225": "rn3mi", + "col226": "2zsu5", + "col227": "qfs7r", + "col228": "m96df", + "col229": "zy0vw", + "col230": "pbsw2", + "col231": "j7wrb", + "col232": "z4wmb", + "col233": "gkr1h", + "col234": "rjlb1", + "col235": "5wksj", + "col236": "ivb2b", + "col237": "f9dnq", + "col238": "cdrhq", + "col239": "p3m9m", + "col240": "3pxdm", + "col241": "ty6ij", + "col242": "c4t6f", + "col243": "y27pg", + "col244": "5ygip", + "col245": "ouml6", + "col246": "hp7cf", + "col247": "frhuh", + "col248": "y2upe", + "col249": "bpcjh", + "col250": "v97yn", + "col251": "kxjgk", + "col252": "00r8w", + "col253": "76x0l", + "col254": "80j7m", + "col255": "yfe8b", + "col256": "md0l7", + "col257": "pjwoy", + "col258": "ih57j", + "col259": "l88rf", + "col260": "awmcf", + "col261": "c1pop", + "col262": "sg0gv", + "col263": "f9qds", + "col264": "d7x4v", + "col265": "wj757", + "col266": "ch4o1", + "col267": "t9got", + "col268": "81ppk", + "col269": "ptmms", + "col270": "vx53r", + "col271": "pvwl7", + "col272": "u01ed", + "col273": "ku30v", + "col274": "jmlbr", + "col275": "ttsr0", + "col276": "cohvf", + "col277": "l0xym", + "col278": "uyjgh", + "col279": "ps1tt", + "col280": "1c16j", + "col281": "7hqq2", + "col282": "bxatx", + "col283": "ogzw3", + "col284": "cwokm", + "col285": "p357e", + "col286": "kukrc", + "col287": "w971s", + "col288": "91dzv", + "col289": "xingg", + "col290": "or787", + "col291": "yfmsx", + "col292": "g123j", + "col293": "bvm8c", + "col294": "vrjc8", + "col295": "kblks", + "col296": "p0rgw", + "col297": "lgega", + "col298": "388l4", + "col299": "1p5xt", + "col300": "2tyk4", + "col301": "023g6", + "col302": "y75ei", + "col303": "svh29", + "col304": "pelm6", + "col305": "2lig5", + "col306": "fhq0u", + "col307": "dawty", + "col308": "sr5ji", + "col309": "tvn02", + "col310": "rs6dg", + "col311": "9yib5", + "col312": "ksumt", + "col313": "ns3ih", + "col314": "bgmhl", + "col315": "jqlp7", + "col316": "xsu7y", + "col317": "poji7", + "col318": "cwvdn", + "col319": "hsubh", + "col320": "icft9", + "col321": "8m21a", + "col322": "m1d8w", + "col323": "conpa", + "col324": "m4xt2", + "col325": "pm7rn", + "col326": "n95cf", + "col327": "l9udy", + "col328": "zsq71", + "col329": "j1b3r", + "col330": "fwujv", + "col331": "3lnq6", + "col332": "qs5bp", + "col333": "gwiz2", + "col334": "d85gf", + "col335": "fbtdt", + "col336": "ixkwz", + "col337": "g2hqo", + "col338": "a9myr", + "col339": "0t7sh", + "col340": "whg6f", + "col341": "upxvd", + "col342": "8jzsa", + "col343": "sy7sv", + "col344": "9hn00", + "col345": "11jne", + "col346": "aznl2", + "col347": "47wag", + "col348": "3qj8x", + "col349": "bakt9", + "col350": "u8952", + "col351": "0ia1r", + "col352": "3mfee", + "col353": "afb8f", + "col354": "ap51f", + "col355": "3730n", + "col356": "mmnyz", + "col357": "z5bne", + "col358": "9t1h7", + "col359": "b1osh", + "col360": "2fgrb", + "col361": "hj5fn", + "col362": "80zp1", + "col363": "tlc04", + "col364": "4us9b", + "col365": "c27aw", + "col366": "vl3uu", + "col367": "y4va5", + "col368": "wtohn", + "col369": "v7j5m", + "col370": "bnnpz", + "col371": "q73tv", + "col372": "k6bxs", + "col373": "ft8c3", + "col374": "szo4z", + "col375": "o9fj3", + "col376": "za1fr", + "col377": "9t6hg", + "col378": "rs3cz", + "col379": "q692g", + "col380": "ci5z3", + "col381": "9g452", + "col382": "x4duu", + "col383": "7sm2b", + "col384": "ngmc8", + "col385": "22gd4", + "col386": "ro1il", + "col387": "arklu", + "col388": "57yox", + "col389": "0wti4", + "col390": "ubugl", + "col391": "6wf4w", + "col392": "1x89v", + "col393": "3m9al", + "col394": "ify1c", + "col395": "rd2ak", + "col396": "bvuby", + "col397": "wbh2v", + "col398": "gecji", + "col399": "h2ezo", + "col400": "g29q5", + "col401": "9udab", + "col402": "hp72f", + "col403": "t58ez", + "col404": "qgppc", + "col405": "7cp0s", + "col406": "1wwb1", + "col407": "kmrxk", + "col408": "8degx", + "col409": "34gea", + "col410": "iyzap", + "col411": "rx9v0", + "col412": "n2eae", + "col413": "6j16l", + "col414": "0vhgp", + "col415": "3nru7", + "col416": "j4jtd", + "col417": "c6nci", + "col418": "nj1ua", + "col419": "hauyw", + "col420": "v1c9q", + "col421": "fz3y2", + "col422": "rpo3a", + "col423": "9qdhh", + "col424": "6tyu7", + "col425": "ljqgc", + "col426": "00e3v", + "col427": "bpfkk", + "col428": "nebr7", + "col429": "98195", + "col430": "w8yzv", + "col431": "bs0vd", + "col432": "ze64c", + "col433": "g78hy", + "col434": "9dvze", + "col435": "sg1ob", + "col436": "tl1gt", + "col437": "ljtiy", + "col438": "fixfk", + "col439": "eqfzo", + "col440": "9vskd", + "col441": "hj5fg", + "col442": "f4hzs", + "col443": "wmsej", + "col444": "osxkb", + "col445": "2g2ms", + "col446": "108wt", + "col447": "r5xur", + "col448": "qygdc", + "col449": "t0i0p", + "col450": "8jy7t", + "col451": "sh3ou", + "col452": "svju0", + "col453": "c19gc", + "col454": "10tmp", + "col455": "hvg6z", + "col456": "fj37b", + "col457": "3kq9i", + "col458": "wxw1k", + "col459": "i9zkn", + "col460": "y1xc6", + "col461": "c0e20", + "col462": "adgm2", + "col463": "5hwqc", + "col464": "i523w", + "col465": "q2wdg", + "col466": "nvxh0", + "col467": "8pj7x", + "col468": "iomb8", + "col469": "35x3m", + "col470": "c0fmb", + "col471": "u8dur", + "col472": "ty9wb", + "col473": "08207", + "col474": "0l32w", + "col475": "glr0f", + "col476": "zv9ld", + "col477": "j3npk", + "col478": "mewz8", + "col479": "qb6vh", + "col480": "veifw", + "col481": "rn6pp", + "col482": "u8dvf", + "col483": "e8gru", + "col484": "xr19a", + "col485": "krb28", + "col486": "6ur6x", + "col487": "rm8bd", + "col488": "b7y6b", + "col489": "2wbyn", + "col490": "yadsr", + "col491": "1eq5i", + "col492": "6zji5", + "col493": "lrq1d", + "col494": "evf8u", + "col495": "11e6i", + "col496": "qrw3f", + "col497": "nt7v9", + "col498": "vuwsh", + "col499": "4k76k", + "col500": "1ixgk", + "col501": "zaxgb", + "col502": "d4knf", + "col503": "q86o1", + "col504": "ckw07", + "col505": "884st", + "col506": "pueuc", + "col507": "yytl0", + "col508": "08mmw", + "col509": "q0own", + "col510": "n81r4", + "col511": "6t06t", + "col512": "hdyw6", + "col513": "cedh0", + "col514": "vaokm", + "col515": "7wt4o", + "col516": "3hg1r", + "col517": "syojk", + "col518": "pga7c", + "col519": "mswi2", + "col520": "lstes", + "col521": "ba0a9", + "col522": "tnwrr", + "col523": "69eq5", + "col524": "ug59r", + "col525": "an1va", + "col526": "raqlz", + "col527": "xcacs", + "col528": "wpbb6", + "col529": "65mdj", + "col530": "ekp0r", + "col531": "euwz5", + "col532": "cmzc6", + "col533": "4yzq6", + "col534": "gc2we", + "col535": "yppz8", + "col536": "pwl8t", + "col537": "ekidb", + "col538": "phahq", + "col539": "y8l2m", + "col540": "zaokh", + "col541": "d6ah4", + "col542": "kfzz5", + "col543": "b6gfy", + "col544": "1kdht", + "col545": "ttnlz", + "col546": "bw1f9", + "col547": "abpsp", + "col548": "9low2", + "col549": "u1g2d", + "col550": "vjwkt", + "col551": "feac1", + "col552": "xsz74", + "col553": "wrtgb", + "col554": "djhx8", + "col555": "6b86x", + "col556": "fxemq", + "col557": "qlkvy", + "col558": "9vil4", + "col559": "vuc0a", + "col560": "03bm5", + "col561": "t62xf", + "col562": "w2wgx", + "col563": "fuq6l", + "col564": "fpwy2", + "col565": "xghxj", + "col566": "u2uym", + "col567": "zw9sy", + "col568": "n92nv", + "col569": "2f8xd", + "col570": "iis40", + "col571": "xbj7b", + "col572": "lddh0", + "col573": "ubtkf", + "col574": "dh2we", + "col575": "7jn6m", + "col576": "gym21", + "col577": "ud3k9", + "col578": "vqxh0", + "col579": "ow74t", + "col580": "zwhs3", + "col581": "t8knn", + "col582": "sdk66", + "col583": "6x864", + "col584": "4dgzf", + "col585": "z9ciq", + "col586": "2wrx3", + "col587": "aopz2", + "col588": "5fxjh", + "col589": "91onc", + "col590": "44trr", + "col591": "5e8m8", + "col592": "2yn0q", + "col593": "whgfo", + "col594": "st6cy", + "col595": "p3suu", + "col596": "glnjm", + "col597": "52ccg", + "col598": "lt0x4", + "col599": "ypip3", + "col600": "ez7fq", + "col601": "cyyaa", + "col602": "1bg49", + "col603": "ddjca", + "col604": "ka6jn", + "col605": "s38jo", + "col606": "aq8dr", + "col607": "bsq6w", + "col608": "foyor", + "col609": "7m3jr", + "col610": "cacxi", + "col611": "lzd71", + "col612": "2vwll", + "col613": "oxkc7", + "col614": "7zf2z", + "col615": "i4tsa", + "col616": "4a73w", + "col617": "pmh99", + "col618": "tuzu5", + "col619": "74ek6", + "col620": "7fsfh", + "col621": "ofjx0", + "col622": "bgcb2", + "col623": "hi6x7", + "col624": "1r752", + "col625": "536i0", + "col626": "9r7o5", + "col627": "hpjqe", + "col628": "c8ef4", + "col629": "vjhul", + "col630": "i5f8w", + "col631": "d2rg6", + "col632": "dwjgr", + "col633": "yaq41", + "col634": "l2trr", + "col635": "g20la", + "col636": "yidia", + "col637": "d8gmr", + "col638": "oak2r", + "col639": "gzun0", + "col640": "zbxkh", + "col641": "v8ygl", + "col642": "511fq", + "col643": "yuvdk", + "col644": "cxuv7", + "col645": "usesc", + "col646": "nrxac", + "col647": "teaey", + "col648": "7d9ze", + "col649": "qrkw7", + "col650": "3yfiz", + "col651": "ll5y0", + "col652": "gz5mm", + "col653": "otmxd", + "col654": "9h1m0", + "col655": "6u5v7", + "col656": "tryc5", + "col657": "t6ep0", + "col658": "shjmr", + "col659": "sjtm9", + "col660": "83pm3", + "col661": "sx1ab", + "col662": "qmrna", + "col663": "8rwzz", + "col664": "xghyu", + "col665": "km7dl", + "col666": "e2q54", + "col667": "smcp1", + "col668": "czcaa", + "col669": "3af6x", + "col670": "f2yaj", + "col671": "ycgwg", + "col672": "macue", + "col673": "sepex", + "col674": "v8r6k", + "col675": "i91j7", + "col676": "osgjh", + "col677": "70tai", + "col678": "1r8r5", + "col679": "8tqve", + "col680": "3y69m", + "col681": "1mgy4", + "col682": "qur7g", + "col683": "5y0gc", + "col684": "fi445", + "col685": "4vk7p", + "col686": "63xt2", + "col687": "u5uwv", + "col688": "ygup7", + "col689": "09mnz", + "col690": "fd5o6", + "col691": "vg2r6", + "col692": "xynzd", + "col693": "pia1l", + "col694": "921xw", + "col695": "pgoqp", + "col696": "tlzxf", + "col697": "bxv4o", + "col698": "mtp1l", + "col699": "iiri5", + "col700": "syzbc", + "col701": "07j7s", + "col702": "hakzl", + "col703": "r507a", + "col704": "6s7s3", + "col705": "9lh7r", + "col706": "36poq", + "col707": "rj4mf", + "col708": "y7kf5", + "col709": "mxf5r", + "col710": "3t5qw", + "col711": "9hbws", + "col712": "uzv6p", + "col713": "jhaoz", + "col714": "hh05y", + "col715": "b821o", + "col716": "z798t", + "col717": "pug51", + "col718": "0lm2g", + "col719": "gsw1e", + "col720": "shk01", + "col721": "k2wsv", + "col722": "khctn", + "col723": "95mm5", + "col724": "4vlt9", + "col725": "of089", + "col726": "54zbq", + "col727": "112ie", + "col728": "ezjoh", + "col729": "ho8zr", + "col730": "1prkg", + "col731": "jzlns", + "col732": "csxf0", + "col733": "68wgy", + "col734": "qt163", + "col735": "iwg9y", + "col736": "eq3qs", + "col737": "u80dj", + "col738": "se21u", + "col739": "3mmc3", + "col740": "82gti", + "col741": "f0ejt", + "col742": "takov", + "col743": "8a19v", + "col744": "16aoj", + "col745": "1szhm", + "col746": "izbnj", + "col747": "ao1y4", + "col748": "8khqk", + "col749": "matff", + "col750": "7m74v", + "col751": "ar3hj", + "col752": "5pifq", + "col753": "zrhw9", + "col754": "kaahw", + "col755": "wlfn6", + "col756": "cmi3e", + "col757": "02i9f", + "col758": "89jza", + "col759": "955xs", + "col760": "shslz", + "col761": "fc9zw", + "col762": "pi92y", + "col763": "be5kw", + "col764": "c3ic6", + "col765": "tgkd9", + "col766": "wemo5", + "col767": "fpxvy", + "col768": "c41hl", + "col769": "tltpi", + "col770": "wjgg4", + "col771": "gy7x1", + "col772": "mgtiz", + "col773": "ousfl", + "col774": "kkdgg", + "col775": "8acmn", + "col776": "0aec3", + "col777": "thy9f", + "col778": "6qb11", + "col779": "r18ic", + "col780": "76xno", + "col781": "pl2i6", + "col782": "kfk1l", + "col783": "s8tt7", + "col784": "wisvk", + "col785": "qw5de", + "col786": "knfsm", + "col787": "mkwjg", + "col788": "85hrx", + "col789": "un44p", + "col790": "6du9b", + "col791": "iop9z", + "col792": "gpbfp", + "col793": "t9dh7", + "col794": "2kfl4", + "col795": "jjwre", + "col796": "45pmt", + "col797": "fh1i5", + "col798": "utew2", + "col799": "3xi2p", + "col800": "6ef0p", + "col801": "1s6uf", + "col802": "9wtvr", + "col803": "kz369", + "col804": "sj9wf", + "col805": "zjdpk", + "col806": "mqlrd", + "col807": "zp3sv", + "col808": "0zkjv", + "col809": "p1ic0", + "col810": "tyss6", + "col811": "58vl1", + "col812": "5vthk", + "col813": "w8oes", + "col814": "ocus7", + "col815": "q9mhx", + "col816": "sglzh", + "col817": "bf7c3", + "col818": "kuc50", + "col819": "yfd58", + "col820": "pxrwf", + "col821": "zqawz", + "col822": "x5pos", + "col823": "4ihh9", + "col824": "iknv7", + "col825": "22ee1", + "col826": "w6xhy", + "col827": "ox822", + "col828": "hzhmg", + "col829": "cuuun", + "col830": "med4z", + "col831": "0j7u9", + "col832": "mrwxf", + "col833": "4f6pc", + "col834": "ag40z", + "col835": "wcnez", + "col836": "tpjud", + "col837": "n5e18", + "col838": "n9ci1", + "col839": "0exx1", + "col840": "7cnz4", + "col841": "flbxo", + "col842": "5heif", + "col843": "po8oy", + "col844": "3gyoj", + "col845": "90f3z", + "col846": "6nz5q", + "col847": "mdb3a", + "col848": "guk09", + "col849": "nrbzh", + "col850": "9vcto", + "col851": "p9a44", + "col852": "c844u", + "col853": "4htnb", + "col854": "n27w8", + "col855": "a4ngb", + "col856": "bpf4i", + "col857": "59vji", + "col858": "0bdin", + "col859": "336re", + "col860": "poz3j", + "col861": "e72oa", + "col862": "1aw1w", + "col863": "s6wne", + "col864": "5gknd", + "col865": "dn4lp", + "col866": "en85a", + "col867": "vq91n", + "col868": "lnxj8", + "col869": "0149z", + "col870": "5kbza", + "col871": "k02tx", + "col872": "b6d0x", + "col873": "n94g5", + "col874": "untvs", + "col875": "jh8qo", + "col876": "evdy2", + "col877": "gbo6t", + "col878": "bpaho", + "col879": "nsnm1", + "col880": "6zwq1", + "col881": "58l2d", + "col882": "2yalv", + "col883": "vric1", + "col884": "fbnic", + "col885": "schtu", + "col886": "vzmz1", + "col887": "hx5kq", + "col888": "fvhm2", + "col889": "78ljg", + "col890": "459cy", + "col891": "26x2l", + "col892": "zc7wy", + "col893": "k9q2l", + "col894": "3f8hu", + "col895": "lojie", + "col896": "7rz81", + "col897": "9ni2s", + "col898": "eaa21", + "col899": "agisj", + "col900": "3xgqa", + "col901": "areh4", + "col902": "irvl2", + "col903": "8yukf", + "col904": "lgsec", + "col905": "yk7vw", + "col906": "osi3t", + "col907": "0nxou", + "col908": "vdvih", + "col909": "utcmr", + "col910": "47rva", + "col911": "l1cjr", + "col912": "serf9", + "col913": "7fys5", + "col914": "61o34", + "col915": "q1cys", + "col916": "g5trv", + "col917": "lmr3m", + "col918": "7xtr3", + "col919": "val4g", + "col920": "cjzmf", + "col921": "yca2y", + "col922": "e5d8b", + "col923": "eihp8", + "col924": "raxw4", + "col925": "qsomg", + "col926": "t443u", + "col927": "kb1yb", + "col928": "v878l", + "col929": "rygdu", + "col930": "rne74", + "col931": "37p2h", + "col932": "ug3e1", + "col933": "d60ha", + "col934": "u3c98", + "col935": "t6iou", + "col936": "ltla8", + "col937": "3i99n", + "col938": "7d5pe", + "col939": "hwlj8", + "col940": "2jg1x", + "col941": "l0i8o", + "col942": "fryld", + "col943": "yt9lp", + "col944": "ribgp", + "col945": "6jh7g", + "col946": "3ka06", + "col947": "d25bi", + "col948": "e9ufa", + "col949": "42krj", + "col950": "4itjw", + "col951": "r2ds4", + "col952": "hs39r", + "col953": "dep6b", + "col954": "cmd9r", + "col955": "3zhvf", + "col956": "h62hz", + "col957": "g04b0", + "col958": "vrl44", + "col959": "un4w5", + "col960": "agl9q", + "col961": "g0nsj", + "col962": "70wmw", + "col963": "njc0w", + "col964": "1hflo", + "col965": "q7d3y", + "col966": "tshmu", + "col967": "xip0u", + "col968": "h4koq", + "col969": "tx86t", + "col970": "s0ywn", + "col971": "g3rwe", + "col972": "3u2cn", + "col973": "nwa52", + "col974": "87chg", + "col975": "01ejn", + "col976": "kxaub", + "col977": "wfixa", + "col978": "c398r", + "col979": "huqmm", + "col980": "ytq0h", + "col981": "4g2sr", + "col982": "5wbdd", + "col983": "ciwrw", + "col984": "u8slt", + "col985": "euj82", + "col986": "8sstx", + "col987": "qexl7", + "col988": "gq5mh", + "col989": "yeuxc", + "col990": "39k7h", + "col991": "mb2gw", + "col992": "smkg4", + "col993": "a5t42", + "col994": "b1meu", + "col995": "00oid", + "col996": "xrxws", + "col997": "0hm2u", + "col998": "as6tn", + "col999": "zv782" + }, + { + "name": "Ethel Bass", + "gender": "female", + "col0": "ich9q", + "col1": "norll", + "col2": "0ivd7", + "col3": "z05p5", + "col4": "4ac1g", + "col5": "l2c5r", + "col6": "w76k5", + "col7": "t995u", + "col8": "3ls48", + "col9": "iq6n8", + "col10": "rt4fi", + "col11": "fmx4e", + "col12": "eo7m3", + "col13": "clmrx", + "col14": "sy127", + "col15": "d821a", + "col16": "ugia6", + "col17": "d99ws", + "col18": "zbvx9", + "col19": "f5eem", + "col20": "adtr4", + "col21": "ziqen", + "col22": "s02dv", + "col23": "nxngs", + "col24": "njggh", + "col25": "wxlc0", + "col26": "ernsa", + "col27": "p2lk5", + "col28": "utm8d", + "col29": "bj2fc", + "col30": "lfeuo", + "col31": "t6qo7", + "col32": "jb7bc", + "col33": "gcn33", + "col34": "t9azd", + "col35": "oa3s3", + "col36": "e4ic3", + "col37": "72h6l", + "col38": "0j4ya", + "col39": "6tm13", + "col40": "89mdk", + "col41": "b0xo4", + "col42": "bjrks", + "col43": "ma7o1", + "col44": "dr1bd", + "col45": "ddjmg", + "col46": "0amid", + "col47": "oxmzv", + "col48": "8whhu", + "col49": "wmmaa", + "col50": "uox3b", + "col51": "qmwjl", + "col52": "2ij84", + "col53": "ba6aq", + "col54": "rkija", + "col55": "0o5ch", + "col56": "ojccp", + "col57": "ssq6v", + "col58": "0hvev", + "col59": "3eva3", + "col60": "73deg", + "col61": "26kux", + "col62": "ejh0g", + "col63": "jc8m2", + "col64": "0vuy8", + "col65": "zihnf", + "col66": "ae39z", + "col67": "rot4z", + "col68": "61ouq", + "col69": "qnwx8", + "col70": "dloz8", + "col71": "ctrt9", + "col72": "z2ejy", + "col73": "a1prf", + "col74": "fimun", + "col75": "z2qeo", + "col76": "jven7", + "col77": "0jyrr", + "col78": "hje6a", + "col79": "wi5l4", + "col80": "z3lsy", + "col81": "lpuj5", + "col82": "xls7m", + "col83": "z9em7", + "col84": "l3hbl", + "col85": "l22lf", + "col86": "lxcos", + "col87": "0e9o0", + "col88": "pp6u8", + "col89": "xfc3d", + "col90": "941a3", + "col91": "xh3d7", + "col92": "0cjwx", + "col93": "toj6e", + "col94": "nvds2", + "col95": "arufh", + "col96": "blgsk", + "col97": "lg9pk", + "col98": "8qzxs", + "col99": "n84eh", + "col100": "h1ns7", + "col101": "mhvi2", + "col102": "8hayt", + "col103": "3klgf", + "col104": "48oas", + "col105": "4nyom", + "col106": "nylco", + "col107": "oyejw", + "col108": "odux0", + "col109": "4jxik", + "col110": "dtkq0", + "col111": "foqi8", + "col112": "y8ieq", + "col113": "aukzs", + "col114": "37mxe", + "col115": "lm26w", + "col116": "5hflo", + "col117": "oubl3", + "col118": "8hruo", + "col119": "j3cd5", + "col120": "87r7j", + "col121": "jgbv3", + "col122": "9uztl", + "col123": "iczsm", + "col124": "kea9m", + "col125": "kwxum", + "col126": "dz4xu", + "col127": "ofp4t", + "col128": "1i5fj", + "col129": "mshbm", + "col130": "mubhi", + "col131": "w5ytg", + "col132": "tge4p", + "col133": "r6vax", + "col134": "cp3na", + "col135": "pw5r8", + "col136": "13cu4", + "col137": "3110o", + "col138": "5x0gh", + "col139": "8gtqx", + "col140": "a1n2w", + "col141": "o0wza", + "col142": "7ucdp", + "col143": "6qzv9", + "col144": "cbbuf", + "col145": "4kgd9", + "col146": "60ona", + "col147": "tv2ng", + "col148": "pvoit", + "col149": "oi5pc", + "col150": "kh2b4", + "col151": "yt255", + "col152": "wajwi", + "col153": "owmqw", + "col154": "sc32p", + "col155": "xzgho", + "col156": "f398q", + "col157": "0x9b7", + "col158": "ww21m", + "col159": "9zws4", + "col160": "heq0f", + "col161": "ool88", + "col162": "gwc7t", + "col163": "2p5vl", + "col164": "33vl7", + "col165": "hobco", + "col166": "xj9m6", + "col167": "qvnhp", + "col168": "ego3g", + "col169": "9wbdm", + "col170": "aidb2", + "col171": "hrx3u", + "col172": "gf0cy", + "col173": "rs5uo", + "col174": "16p07", + "col175": "0e5yz", + "col176": "o5w9g", + "col177": "pjnd4", + "col178": "yzxo1", + "col179": "leb4p", + "col180": "jicdd", + "col181": "bt80m", + "col182": "jlbtx", + "col183": "wwgnh", + "col184": "kwce3", + "col185": "1tmz5", + "col186": "89oyq", + "col187": "7w6oe", + "col188": "tyxr8", + "col189": "qbxpe", + "col190": "nymlz", + "col191": "5whsq", + "col192": "66yet", + "col193": "o3ijk", + "col194": "fnw51", + "col195": "rfzql", + "col196": "zqlov", + "col197": "o7u4s", + "col198": "l4otx", + "col199": "frlzr", + "col200": "36pk3", + "col201": "dbrxs", + "col202": "mfltb", + "col203": "ij0s1", + "col204": "huyci", + "col205": "318na", + "col206": "ahwqb", + "col207": "tgt59", + "col208": "pz69p", + "col209": "tj2uf", + "col210": "wmho7", + "col211": "eq7zv", + "col212": "s5rm5", + "col213": "plrp9", + "col214": "hlhjg", + "col215": "ocj7s", + "col216": "izuh3", + "col217": "cilk5", + "col218": "yuy40", + "col219": "5rjqp", + "col220": "esqge", + "col221": "eieoa", + "col222": "nc0yu", + "col223": "xmxr5", + "col224": "fxl6a", + "col225": "o32wo", + "col226": "8j6j6", + "col227": "91ojr", + "col228": "zz7oj", + "col229": "4dijx", + "col230": "ew0yc", + "col231": "te572", + "col232": "gnxps", + "col233": "8lae8", + "col234": "g2bkb", + "col235": "rk0zk", + "col236": "bgj7h", + "col237": "bmcjb", + "col238": "7ufuf", + "col239": "6kmhl", + "col240": "wqk6n", + "col241": "j2dkr", + "col242": "c2nw8", + "col243": "jfl6a", + "col244": "hz5yd", + "col245": "9s424", + "col246": "sg9ti", + "col247": "ymagl", + "col248": "j4moy", + "col249": "xd1mj", + "col250": "7gk2d", + "col251": "pkpua", + "col252": "3wigz", + "col253": "r4pbp", + "col254": "1i6kh", + "col255": "a4kvy", + "col256": "0odvb", + "col257": "65wlx", + "col258": "267lf", + "col259": "g42iz", + "col260": "lmldp", + "col261": "aj3j5", + "col262": "owsm8", + "col263": "zl8yn", + "col264": "96yyu", + "col265": "djeju", + "col266": "5mgmx", + "col267": "hspn5", + "col268": "pktjt", + "col269": "dg21s", + "col270": "3bits", + "col271": "jr797", + "col272": "g6ur8", + "col273": "paj3q", + "col274": "obiob", + "col275": "uscyv", + "col276": "1ur0f", + "col277": "i2vg2", + "col278": "vwjis", + "col279": "32j0z", + "col280": "w9y9g", + "col281": "n03c7", + "col282": "qcqzs", + "col283": "z1usx", + "col284": "salhp", + "col285": "2cjlu", + "col286": "07wjr", + "col287": "ep6o2", + "col288": "nr2bu", + "col289": "9d816", + "col290": "t714s", + "col291": "hhqi1", + "col292": "fad0g", + "col293": "2cp8o", + "col294": "6jbof", + "col295": "e7ki9", + "col296": "cgw16", + "col297": "96wu8", + "col298": "embqt", + "col299": "8a8yg", + "col300": "cwwgi", + "col301": "21lpj", + "col302": "z57b2", + "col303": "kv07e", + "col304": "jt9pc", + "col305": "xjlny", + "col306": "0jr19", + "col307": "gffai", + "col308": "ka45d", + "col309": "3ugk3", + "col310": "kpw2r", + "col311": "px26i", + "col312": "czids", + "col313": "zxj8i", + "col314": "0ciqg", + "col315": "csu43", + "col316": "p3avj", + "col317": "i7q6r", + "col318": "snwyu", + "col319": "p5bi2", + "col320": "kwvnf", + "col321": "l6sqz", + "col322": "ttfun", + "col323": "1j4c7", + "col324": "yq071", + "col325": "aryg1", + "col326": "kext5", + "col327": "qwux3", + "col328": "3klao", + "col329": "4d0k5", + "col330": "6wtzg", + "col331": "c21mv", + "col332": "afvx1", + "col333": "l5rge", + "col334": "iz7kg", + "col335": "wuvgc", + "col336": "tsgdk", + "col337": "ucthk", + "col338": "nqolx", + "col339": "sz8wn", + "col340": "0p7f3", + "col341": "djrbs", + "col342": "8ybei", + "col343": "8ircw", + "col344": "k2nnh", + "col345": "9zpmq", + "col346": "iy602", + "col347": "eal98", + "col348": "16jn4", + "col349": "kyc42", + "col350": "76hf4", + "col351": "wh3it", + "col352": "0u4du", + "col353": "jv323", + "col354": "2vm3y", + "col355": "hrwwf", + "col356": "8ee9w", + "col357": "msn0t", + "col358": "zkp5b", + "col359": "4n4jq", + "col360": "9mkmq", + "col361": "h64e7", + "col362": "borbn", + "col363": "2i5me", + "col364": "ywosv", + "col365": "h9o1c", + "col366": "2xjbw", + "col367": "dopqg", + "col368": "gk1b1", + "col369": "u8uxv", + "col370": "a32pt", + "col371": "k9gby", + "col372": "4vf7y", + "col373": "p3j5s", + "col374": "if2mj", + "col375": "64m79", + "col376": "cpjwf", + "col377": "gg9xc", + "col378": "ew7jn", + "col379": "7kjo4", + "col380": "snni3", + "col381": "5krn3", + "col382": "k9j9b", + "col383": "q76xu", + "col384": "t8g0z", + "col385": "yxq28", + "col386": "hl1ry", + "col387": "16cr5", + "col388": "61g5m", + "col389": "jd8yg", + "col390": "mcyss", + "col391": "1a10x", + "col392": "ptvyu", + "col393": "o1s1k", + "col394": "gvres", + "col395": "wx4yl", + "col396": "lhyj2", + "col397": "gfxe7", + "col398": "j6cg1", + "col399": "j4ylc", + "col400": "tqhij", + "col401": "s961w", + "col402": "ap7rh", + "col403": "mcv4o", + "col404": "33xql", + "col405": "78e3d", + "col406": "bl6mo", + "col407": "wc07a", + "col408": "hrk67", + "col409": "tcnwn", + "col410": "t1eht", + "col411": "ldz5u", + "col412": "lbjib", + "col413": "lyxet", + "col414": "liord", + "col415": "3u9o6", + "col416": "ing6k", + "col417": "o3cas", + "col418": "dcg9y", + "col419": "20inu", + "col420": "s7m74", + "col421": "ym9uf", + "col422": "j26m5", + "col423": "6t1xw", + "col424": "7tw6d", + "col425": "jpe3f", + "col426": "jy0rg", + "col427": "rr1gt", + "col428": "6w33v", + "col429": "318ak", + "col430": "sdsen", + "col431": "c2h3n", + "col432": "omukf", + "col433": "64pj3", + "col434": "xnd7e", + "col435": "v0s55", + "col436": "whwjy", + "col437": "0fzf0", + "col438": "1x9oh", + "col439": "5yuah", + "col440": "ll286", + "col441": "nfbe1", + "col442": "9uzhe", + "col443": "ohio0", + "col444": "5dxxg", + "col445": "ki8o1", + "col446": "ept6v", + "col447": "91oda", + "col448": "lrylt", + "col449": "kdap7", + "col450": "nzhc8", + "col451": "gel6t", + "col452": "ntewk", + "col453": "nuovz", + "col454": "2rifc", + "col455": "3zzto", + "col456": "fvb6a", + "col457": "l0n9i", + "col458": "uax6w", + "col459": "dr8u3", + "col460": "iw8yn", + "col461": "158mx", + "col462": "g593r", + "col463": "vo9u2", + "col464": "ae72k", + "col465": "s9d6v", + "col466": "snynd", + "col467": "ry4dn", + "col468": "uep3n", + "col469": "2an4e", + "col470": "yadc3", + "col471": "69c7w", + "col472": "cj40e", + "col473": "z9o0a", + "col474": "lsb82", + "col475": "davsx", + "col476": "kgyx7", + "col477": "rj60v", + "col478": "x551y", + "col479": "qqnk6", + "col480": "frntj", + "col481": "gfigy", + "col482": "xoxqw", + "col483": "3vy4y", + "col484": "irwjd", + "col485": "ekvaa", + "col486": "o62al", + "col487": "oe0f9", + "col488": "2lh5q", + "col489": "rr8g3", + "col490": "ojjg5", + "col491": "q7uy4", + "col492": "hlfir", + "col493": "gznfg", + "col494": "a3t5c", + "col495": "kfj3q", + "col496": "xysus", + "col497": "29lz8", + "col498": "uqki9", + "col499": "2cqil", + "col500": "ta0c1", + "col501": "5t2x8", + "col502": "t9t5h", + "col503": "bvvri", + "col504": "ef1ye", + "col505": "ko114", + "col506": "bacel", + "col507": "rimba", + "col508": "6jq28", + "col509": "qx9sf", + "col510": "zilbx", + "col511": "996zu", + "col512": "ya6yk", + "col513": "8alr3", + "col514": "j2mpj", + "col515": "odcxw", + "col516": "wfyia", + "col517": "fdbuw", + "col518": "a7iad", + "col519": "z267k", + "col520": "rujdf", + "col521": "ir2x8", + "col522": "5ptie", + "col523": "1148n", + "col524": "f5cf6", + "col525": "6pfq2", + "col526": "4zak6", + "col527": "iqksk", + "col528": "vdnpb", + "col529": "uxj77", + "col530": "qmssu", + "col531": "4bhw0", + "col532": "evk5n", + "col533": "eidu7", + "col534": "2etaj", + "col535": "0cmc5", + "col536": "02t0o", + "col537": "otmen", + "col538": "x8g1l", + "col539": "noskk", + "col540": "pm9d0", + "col541": "wuukx", + "col542": "1j2ag", + "col543": "nw264", + "col544": "hozee", + "col545": "i3o8g", + "col546": "yaqbx", + "col547": "m8y2h", + "col548": "es1y1", + "col549": "hr1jl", + "col550": "khtwb", + "col551": "ez7my", + "col552": "ew6xn", + "col553": "oq60i", + "col554": "m6vkg", + "col555": "fkj8j", + "col556": "p22un", + "col557": "tlhaz", + "col558": "cvwci", + "col559": "hmphh", + "col560": "rrbei", + "col561": "rv90l", + "col562": "kkw2z", + "col563": "pmujr", + "col564": "rjxm6", + "col565": "miv4i", + "col566": "k76h5", + "col567": "qyclv", + "col568": "0c4vn", + "col569": "uk8te", + "col570": "1aids", + "col571": "m1ep6", + "col572": "pp73h", + "col573": "oek6h", + "col574": "3ltpu", + "col575": "6gvtm", + "col576": "tw1qw", + "col577": "ldnha", + "col578": "xfd4r", + "col579": "ffpuc", + "col580": "ohqoi", + "col581": "wt4i9", + "col582": "mx4e3", + "col583": "pbrbc", + "col584": "t03wg", + "col585": "putiz", + "col586": "72ssw", + "col587": "kejio", + "col588": "1qz3f", + "col589": "skqnc", + "col590": "ohrkp", + "col591": "n206z", + "col592": "4w5bk", + "col593": "gbrf1", + "col594": "n3xq6", + "col595": "49og1", + "col596": "n1ve0", + "col597": "yhc08", + "col598": "28us2", + "col599": "9g9b1", + "col600": "ayl39", + "col601": "af20t", + "col602": "w52en", + "col603": "tqys7", + "col604": "2cmk9", + "col605": "9smf5", + "col606": "h5dct", + "col607": "b8y4h", + "col608": "lbblq", + "col609": "dclsc", + "col610": "tm7rl", + "col611": "dhl3m", + "col612": "iu410", + "col613": "ph4br", + "col614": "ekxct", + "col615": "xkdex", + "col616": "x2hbe", + "col617": "ssf2b", + "col618": "8uuoy", + "col619": "xlejm", + "col620": "ck888", + "col621": "viayy", + "col622": "c23lt", + "col623": "6e6he", + "col624": "95ugn", + "col625": "aw42j", + "col626": "c941u", + "col627": "8et20", + "col628": "0zn2a", + "col629": "5nq18", + "col630": "dq5ir", + "col631": "z32ke", + "col632": "7i54a", + "col633": "g4je9", + "col634": "c0m0m", + "col635": "sqec9", + "col636": "i4kla", + "col637": "v3wyo", + "col638": "mlbg8", + "col639": "ybwhq", + "col640": "vbqfn", + "col641": "nl6ht", + "col642": "0qrlh", + "col643": "nxdwc", + "col644": "lx9a0", + "col645": "n0ad7", + "col646": "fuf28", + "col647": "f0qn7", + "col648": "jlc0t", + "col649": "g8apl", + "col650": "4i59f", + "col651": "zrfn2", + "col652": "kti39", + "col653": "83rpw", + "col654": "5tf0c", + "col655": "qk0wg", + "col656": "nnbd9", + "col657": "5znwr", + "col658": "pme3u", + "col659": "tk9u7", + "col660": "a8ji3", + "col661": "nhgk5", + "col662": "ksuk1", + "col663": "p1hm1", + "col664": "1zzfc", + "col665": "wj60y", + "col666": "p9tcb", + "col667": "p0foz", + "col668": "ypaxl", + "col669": "v0vg1", + "col670": "iib4e", + "col671": "dvpwk", + "col672": "hra9w", + "col673": "98u8d", + "col674": "v5x29", + "col675": "px3gz", + "col676": "pxpkw", + "col677": "t7hex", + "col678": "tg9d7", + "col679": "i2cjg", + "col680": "8181d", + "col681": "8pasv", + "col682": "cpsc7", + "col683": "15dra", + "col684": "ebucj", + "col685": "41le8", + "col686": "lpl9a", + "col687": "2gf1e", + "col688": "dd9vo", + "col689": "i6pc4", + "col690": "icdxs", + "col691": "72uny", + "col692": "zvirx", + "col693": "swaas", + "col694": "uidv9", + "col695": "mnqd5", + "col696": "lcegk", + "col697": "yho9m", + "col698": "ne15w", + "col699": "o2h5t", + "col700": "kxmyw", + "col701": "1aqsw", + "col702": "3c2y7", + "col703": "4ej3w", + "col704": "0ajj2", + "col705": "ar5i6", + "col706": "nqqts", + "col707": "026zu", + "col708": "aoqlf", + "col709": "4nbr1", + "col710": "2lcq9", + "col711": "6f7up", + "col712": "yip6l", + "col713": "8ptkv", + "col714": "0lyh4", + "col715": "l3n2j", + "col716": "9ns0z", + "col717": "c0m8g", + "col718": "dik0o", + "col719": "jc8hv", + "col720": "qk9v2", + "col721": "jsmu4", + "col722": "cu0mc", + "col723": "psicz", + "col724": "08lwt", + "col725": "2ilcv", + "col726": "akx5t", + "col727": "h314j", + "col728": "z3kva", + "col729": "ceg1d", + "col730": "hssrh", + "col731": "d6m5t", + "col732": "ir4jv", + "col733": "0rc5s", + "col734": "78i3a", + "col735": "j8geh", + "col736": "vjjee", + "col737": "lqszo", + "col738": "5ehoq", + "col739": "htajk", + "col740": "k7o1j", + "col741": "h1w2k", + "col742": "anlnx", + "col743": "87zm1", + "col744": "h07as", + "col745": "82oep", + "col746": "v6xk8", + "col747": "z5kky", + "col748": "72wmd", + "col749": "w6099", + "col750": "wl73a", + "col751": "ijjzc", + "col752": "67ule", + "col753": "2x4hs", + "col754": "sd2zo", + "col755": "0n4u6", + "col756": "od6zx", + "col757": "qj33q", + "col758": "rk5bc", + "col759": "2lpcv", + "col760": "q1bp5", + "col761": "l37p0", + "col762": "4e6en", + "col763": "5fltm", + "col764": "j5sh6", + "col765": "ki63j", + "col766": "eemk5", + "col767": "usfep", + "col768": "j5wm5", + "col769": "sch26", + "col770": "x270l", + "col771": "ztqte", + "col772": "u8soy", + "col773": "tqq9u", + "col774": "fbx8p", + "col775": "6qr3x", + "col776": "ojap3", + "col777": "0dmq1", + "col778": "j6okx", + "col779": "2sf7p", + "col780": "3yjhm", + "col781": "qkvt0", + "col782": "1sxra", + "col783": "nk05y", + "col784": "4rfln", + "col785": "eer4x", + "col786": "4l6yf", + "col787": "2xv2e", + "col788": "vrt9b", + "col789": "0xyzs", + "col790": "0dz3k", + "col791": "da8x5", + "col792": "ca3k1", + "col793": "r1bh8", + "col794": "2uriq", + "col795": "2lanc", + "col796": "tdie2", + "col797": "ijfk3", + "col798": "w5jll", + "col799": "avpb2", + "col800": "1acwj", + "col801": "o69ds", + "col802": "n3h4h", + "col803": "7ikd4", + "col804": "k4bj8", + "col805": "ywt7l", + "col806": "ff9kg", + "col807": "cjswr", + "col808": "bkqdo", + "col809": "ajwpk", + "col810": "wmrj6", + "col811": "sjrkf", + "col812": "f59sb", + "col813": "cqlqs", + "col814": "dh0ia", + "col815": "nl2mx", + "col816": "ck1h5", + "col817": "cvzap", + "col818": "9i4i9", + "col819": "y0hpm", + "col820": "vy4as", + "col821": "7mbiv", + "col822": "bpgmq", + "col823": "9ldgq", + "col824": "7xo1t", + "col825": "r5wvx", + "col826": "agd9e", + "col827": "u7a2y", + "col828": "ascw5", + "col829": "jtw78", + "col830": "wyk2z", + "col831": "4yfzv", + "col832": "sy29q", + "col833": "uarx5", + "col834": "nl8hv", + "col835": "ukic5", + "col836": "7ohge", + "col837": "4he83", + "col838": "4f3ep", + "col839": "72z1b", + "col840": "rqvpt", + "col841": "u4vjv", + "col842": "rk7hn", + "col843": "faad3", + "col844": "ikpe9", + "col845": "z6led", + "col846": "o14so", + "col847": "s64jh", + "col848": "vdv4v", + "col849": "pxqz2", + "col850": "jtp8p", + "col851": "8t11g", + "col852": "morls", + "col853": "29p4k", + "col854": "ibu1f", + "col855": "elu54", + "col856": "6vdbn", + "col857": "5jiab", + "col858": "osrcb", + "col859": "cjww8", + "col860": "7fnxq", + "col861": "f4wtu", + "col862": "15lsf", + "col863": "zuo18", + "col864": "a27wg", + "col865": "zmf7c", + "col866": "qal33", + "col867": "zdcx9", + "col868": "zonf9", + "col869": "kmhxt", + "col870": "ssfvb", + "col871": "su9ft", + "col872": "dk9qq", + "col873": "5pbbc", + "col874": "d6sfv", + "col875": "nok8z", + "col876": "k4jd6", + "col877": "bpxge", + "col878": "ej4hg", + "col879": "hxzs4", + "col880": "n68fx", + "col881": "m3w5v", + "col882": "iz9xr", + "col883": "r8h6d", + "col884": "sbdo7", + "col885": "pqzdi", + "col886": "yk7p8", + "col887": "2j6v2", + "col888": "d7f2j", + "col889": "mifne", + "col890": "0grbp", + "col891": "80u0o", + "col892": "d5ik0", + "col893": "3yed4", + "col894": "rtwwr", + "col895": "pf7f5", + "col896": "hy0q0", + "col897": "l6w9a", + "col898": "9ot4y", + "col899": "rhqmc", + "col900": "9uwkp", + "col901": "qhkp3", + "col902": "e5594", + "col903": "pu15v", + "col904": "zxt23", + "col905": "bd2zx", + "col906": "agoix", + "col907": "1dn5c", + "col908": "fvk1n", + "col909": "cnwbg", + "col910": "qlarg", + "col911": "jyt5r", + "col912": "u5p52", + "col913": "ez25a", + "col914": "lu28r", + "col915": "yhixk", + "col916": "f86es", + "col917": "rchbe", + "col918": "0d8ls", + "col919": "1q43g", + "col920": "0s8xt", + "col921": "8rob1", + "col922": "tq20b", + "col923": "9mlrs", + "col924": "psyz7", + "col925": "rmjkb", + "col926": "ulkns", + "col927": "vs7cg", + "col928": "jdcm7", + "col929": "v6iqc", + "col930": "5vd0x", + "col931": "m3g3m", + "col932": "qw64y", + "col933": "a7q1d", + "col934": "26d6p", + "col935": "uk81j", + "col936": "hqbek", + "col937": "vxs7x", + "col938": "pusvt", + "col939": "gaks4", + "col940": "dll05", + "col941": "nclea", + "col942": "aihbm", + "col943": "kno3l", + "col944": "ejfef", + "col945": "jh2aq", + "col946": "7yn1z", + "col947": "imri3", + "col948": "s1e1e", + "col949": "2qaio", + "col950": "2cz7h", + "col951": "5g5aq", + "col952": "j6cxl", + "col953": "l3a7p", + "col954": "e5q6f", + "col955": "1gipd", + "col956": "yvjzz", + "col957": "5rtha", + "col958": "sw735", + "col959": "kh6aj", + "col960": "gq8l7", + "col961": "fyqsh", + "col962": "fim68", + "col963": "j5plc", + "col964": "y7zph", + "col965": "vb525", + "col966": "2wf27", + "col967": "8wo59", + "col968": "agnlz", + "col969": "fr2fk", + "col970": "4nddm", + "col971": "gjug2", + "col972": "6vmwz", + "col973": "q2c37", + "col974": "z7y04", + "col975": "r6t4e", + "col976": "k6uvh", + "col977": "go3uk", + "col978": "vw4mo", + "col979": "zhnn8", + "col980": "wtzpa", + "col981": "766p6", + "col982": "lp2il", + "col983": "7ri1a", + "col984": "kr2y4", + "col985": "c9237", + "col986": "m2f4x", + "col987": "gll0u", + "col988": "a3s66", + "col989": "aaa37", + "col990": "1dfou", + "col991": "pyjtu", + "col992": "9fogy", + "col993": "oimdg", + "col994": "jukpk", + "col995": "qgq8w", + "col996": "ppdwf", + "col997": "ahj7c", + "col998": "uyi1x", + "col999": "59v0f" + }, + { + "name": "Rose Hampton", + "gender": "male", + "col0": "llxsq", + "col1": "htyws", + "col2": "og1u0", + "col3": "as80j", + "col4": "bkfcu", + "col5": "4d38m", + "col6": "sck10", + "col7": "23pcp", + "col8": "cj7ev", + "col9": "et22r", + "col10": "jl24j", + "col11": "b8vhp", + "col12": "ue2zo", + "col13": "zkcsj", + "col14": "g4d0y", + "col15": "tz1ze", + "col16": "1sno4", + "col17": "lba8l", + "col18": "j3z3x", + "col19": "ljjl1", + "col20": "il5ul", + "col21": "bn5b1", + "col22": "ipuw3", + "col23": "vvqmd", + "col24": "htea7", + "col25": "y98ae", + "col26": "csrgs", + "col27": "mv9j2", + "col28": "9p4c2", + "col29": "b2l4l", + "col30": "yn2w8", + "col31": "ha1xj", + "col32": "q4aie", + "col33": "nujgm", + "col34": "v3qlk", + "col35": "fvug2", + "col36": "blcxl", + "col37": "om1zj", + "col38": "5igfy", + "col39": "a583n", + "col40": "6j0cy", + "col41": "urga9", + "col42": "0ngs8", + "col43": "y3ywt", + "col44": "1zspy", + "col45": "6on7a", + "col46": "6pmxe", + "col47": "pz80g", + "col48": "4r14e", + "col49": "gwz42", + "col50": "qyw6x", + "col51": "sh6bb", + "col52": "25v39", + "col53": "wk763", + "col54": "jtmnd", + "col55": "jx264", + "col56": "6g4ha", + "col57": "xy8p5", + "col58": "nqveb", + "col59": "etvj1", + "col60": "n77e7", + "col61": "mi03l", + "col62": "jd7ai", + "col63": "pb495", + "col64": "evsrm", + "col65": "rso0y", + "col66": "7887k", + "col67": "04sc8", + "col68": "riyco", + "col69": "ciftz", + "col70": "oscg0", + "col71": "4nea1", + "col72": "e1twz", + "col73": "h0t0j", + "col74": "59ite", + "col75": "9imcm", + "col76": "xc6mb", + "col77": "7o3im", + "col78": "hzrkp", + "col79": "73187", + "col80": "325hc", + "col81": "ypslj", + "col82": "yr35s", + "col83": "1zl9u", + "col84": "kdfk0", + "col85": "97b3f", + "col86": "hi1mu", + "col87": "0cpgv", + "col88": "2jqos", + "col89": "wpzn1", + "col90": "8yqjz", + "col91": "jkbet", + "col92": "94p1r", + "col93": "brb9q", + "col94": "k2c37", + "col95": "hqtk1", + "col96": "ugn9z", + "col97": "io2rk", + "col98": "fb0y4", + "col99": "9x8wb", + "col100": "r2ahx", + "col101": "l0tu7", + "col102": "37swc", + "col103": "4a1ma", + "col104": "d5yc4", + "col105": "dmkrg", + "col106": "humew", + "col107": "g1qs8", + "col108": "w2ahb", + "col109": "u1pjg", + "col110": "6qne2", + "col111": "ct5vl", + "col112": "4yu23", + "col113": "y1mc1", + "col114": "6r7eg", + "col115": "6z98j", + "col116": "o831r", + "col117": "4m9m7", + "col118": "9cn2t", + "col119": "2c043", + "col120": "3iyrl", + "col121": "5srba", + "col122": "dvwdk", + "col123": "u1ljg", + "col124": "pzp9i", + "col125": "a74b6", + "col126": "yu0px", + "col127": "6d63j", + "col128": "5301u", + "col129": "spahv", + "col130": "6mqwo", + "col131": "p1yf3", + "col132": "vclqx", + "col133": "d3bbd", + "col134": "s7dfq", + "col135": "2o53o", + "col136": "5v7du", + "col137": "neup3", + "col138": "j3215", + "col139": "t9gy4", + "col140": "9w2o4", + "col141": "pmyze", + "col142": "ud3m7", + "col143": "i8prc", + "col144": "uiz4g", + "col145": "1u4df", + "col146": "2da11", + "col147": "e9w5t", + "col148": "xpn4k", + "col149": "pl2sn", + "col150": "pbe1i", + "col151": "84ibp", + "col152": "2ji42", + "col153": "9w22c", + "col154": "n7fgp", + "col155": "f531p", + "col156": "bce92", + "col157": "pw4tn", + "col158": "vp2em", + "col159": "l4kh2", + "col160": "m3ir0", + "col161": "f7z54", + "col162": "i3kf8", + "col163": "3hu0h", + "col164": "lkr47", + "col165": "c0q6b", + "col166": "kzkzp", + "col167": "h5rj1", + "col168": "wm0k8", + "col169": "dz78y", + "col170": "99gdx", + "col171": "wc0b8", + "col172": "h487y", + "col173": "swxe3", + "col174": "uvqrm", + "col175": "1m1xp", + "col176": "m097r", + "col177": "tn3aq", + "col178": "jo5oh", + "col179": "29xai", + "col180": "wg5hd", + "col181": "e4tjs", + "col182": "kxjsm", + "col183": "aaxcg", + "col184": "94jqv", + "col185": "8ehow", + "col186": "w2a8w", + "col187": "fd9la", + "col188": "3fxcb", + "col189": "vpiqe", + "col190": "9nncx", + "col191": "fuejm", + "col192": "baqm8", + "col193": "5wo4b", + "col194": "sj2kq", + "col195": "le8n3", + "col196": "xmp7w", + "col197": "iv5b4", + "col198": "s3tr6", + "col199": "fxpt2", + "col200": "38mql", + "col201": "a0b43", + "col202": "3xjqw", + "col203": "mbc2o", + "col204": "faxc7", + "col205": "mpp41", + "col206": "mwp3y", + "col207": "cnwqi", + "col208": "8h5zk", + "col209": "cltkb", + "col210": "hybbp", + "col211": "lo8qx", + "col212": "xqhvm", + "col213": "h8b82", + "col214": "u07rj", + "col215": "asq7d", + "col216": "20pxm", + "col217": "1g0wg", + "col218": "u1fbp", + "col219": "t9zmo", + "col220": "0zco0", + "col221": "nci8g", + "col222": "qanj0", + "col223": "wq0fg", + "col224": "823me", + "col225": "ex17h", + "col226": "4ull2", + "col227": "flbqp", + "col228": "kpjut", + "col229": "7kk1y", + "col230": "mqz07", + "col231": "cnhoe", + "col232": "dn3ek", + "col233": "vpfts", + "col234": "kwde8", + "col235": "mfmbg", + "col236": "c8rv4", + "col237": "fywn9", + "col238": "lp7hh", + "col239": "aznfx", + "col240": "zxv7d", + "col241": "0gy9y", + "col242": "z4jnb", + "col243": "5neom", + "col244": "rl3dg", + "col245": "zol6j", + "col246": "qumdk", + "col247": "s30jl", + "col248": "wqak2", + "col249": "mnd8y", + "col250": "b8woq", + "col251": "fbjqt", + "col252": "yeekm", + "col253": "o08og", + "col254": "ianm9", + "col255": "pe0k4", + "col256": "z2c8a", + "col257": "uce54", + "col258": "kdu5t", + "col259": "crnuz", + "col260": "4f2u7", + "col261": "lxusu", + "col262": "ha897", + "col263": "zwbuh", + "col264": "3raqi", + "col265": "d331s", + "col266": "i3j2p", + "col267": "19bis", + "col268": "aqld8", + "col269": "pxs8n", + "col270": "llix0", + "col271": "8q7tn", + "col272": "k9o9z", + "col273": "wvbp7", + "col274": "90ltf", + "col275": "s6ku8", + "col276": "r0cv7", + "col277": "4dv2w", + "col278": "pm2p2", + "col279": "448ee", + "col280": "09g8h", + "col281": "r2nx6", + "col282": "32zrm", + "col283": "4rzjl", + "col284": "bsl0k", + "col285": "88p7h", + "col286": "7rsle", + "col287": "v3d3o", + "col288": "krfrv", + "col289": "vzbc5", + "col290": "mnmvx", + "col291": "2josl", + "col292": "8tu7r", + "col293": "kv8zl", + "col294": "ty228", + "col295": "2q5zq", + "col296": "74zca", + "col297": "fih5b", + "col298": "fxabw", + "col299": "mi6yw", + "col300": "x61a0", + "col301": "rgslo", + "col302": "2lkl5", + "col303": "covh9", + "col304": "o5ei3", + "col305": "bll8h", + "col306": "5vlwo", + "col307": "i6llu", + "col308": "em3ii", + "col309": "8dl2s", + "col310": "9qyw4", + "col311": "9jw2p", + "col312": "qhmva", + "col313": "35f2h", + "col314": "uaxre", + "col315": "18twx", + "col316": "rquzn", + "col317": "kz95q", + "col318": "ndj2x", + "col319": "1a6wi", + "col320": "8g9yv", + "col321": "aojo3", + "col322": "uja4c", + "col323": "gbykw", + "col324": "siu9e", + "col325": "lvx8o", + "col326": "tvmqr", + "col327": "2eydd", + "col328": "xvo9c", + "col329": "dq7a3", + "col330": "wwxln", + "col331": "2a35z", + "col332": "0wwk8", + "col333": "ua5xj", + "col334": "a67l7", + "col335": "jppud", + "col336": "8q6zj", + "col337": "yst2x", + "col338": "j2pvo", + "col339": "3aeod", + "col340": "u73jq", + "col341": "aixz5", + "col342": "re8tj", + "col343": "zxr8g", + "col344": "mpdko", + "col345": "kgd85", + "col346": "c08rp", + "col347": "4644v", + "col348": "gk0ry", + "col349": "f1m0h", + "col350": "0z384", + "col351": "jh30v", + "col352": "o952j", + "col353": "54a9y", + "col354": "fjxfa", + "col355": "9oclk", + "col356": "7ocmf", + "col357": "0e7ym", + "col358": "p3sry", + "col359": "r43db", + "col360": "sn8c4", + "col361": "l94u1", + "col362": "7h35h", + "col363": "a8hyx", + "col364": "ppzpv", + "col365": "d7d69", + "col366": "eserh", + "col367": "f1f2r", + "col368": "t1u9v", + "col369": "25gyr", + "col370": "jhvd3", + "col371": "6mw75", + "col372": "prppd", + "col373": "yw2qi", + "col374": "amip1", + "col375": "4i2lv", + "col376": "chdqy", + "col377": "ve0ht", + "col378": "jtsas", + "col379": "rw4a1", + "col380": "m50ht", + "col381": "nyw3a", + "col382": "vdftf", + "col383": "7e2db", + "col384": "zbz6r", + "col385": "6rbiq", + "col386": "amb3e", + "col387": "vvssj", + "col388": "oq8yp", + "col389": "xl57z", + "col390": "5ejfx", + "col391": "rrxh5", + "col392": "o66pw", + "col393": "gall3", + "col394": "poeig", + "col395": "yuzzx", + "col396": "yj0sp", + "col397": "n7k20", + "col398": "hri55", + "col399": "1poj7", + "col400": "5tryj", + "col401": "xujai", + "col402": "v2smf", + "col403": "oxv3p", + "col404": "txp5j", + "col405": "36lp1", + "col406": "qjj6b", + "col407": "dxnps", + "col408": "z2e7o", + "col409": "5c644", + "col410": "wm2c1", + "col411": "uraku", + "col412": "n2ruw", + "col413": "0gu15", + "col414": "twblo", + "col415": "b7qaq", + "col416": "okmwb", + "col417": "xod4s", + "col418": "8ybfo", + "col419": "mj1yt", + "col420": "jxoqn", + "col421": "bxocu", + "col422": "cp0tg", + "col423": "rixyx", + "col424": "v2jtr", + "col425": "gm2oy", + "col426": "412c8", + "col427": "bq776", + "col428": "1jvkd", + "col429": "f3z58", + "col430": "j73ic", + "col431": "o9tep", + "col432": "zqk5j", + "col433": "957tg", + "col434": "4awsk", + "col435": "thsa6", + "col436": "4kfdq", + "col437": "vr3if", + "col438": "v0tuk", + "col439": "yh7sd", + "col440": "8ppc9", + "col441": "9v0hg", + "col442": "1y7yo", + "col443": "owroz", + "col444": "78g09", + "col445": "ltgbe", + "col446": "1mr2p", + "col447": "9xixh", + "col448": "n5ld3", + "col449": "f4zxc", + "col450": "ys6f9", + "col451": "a8op5", + "col452": "zr19g", + "col453": "j8bj1", + "col454": "f9m8s", + "col455": "1hddx", + "col456": "1baha", + "col457": "ef21z", + "col458": "rr8ef", + "col459": "ru79u", + "col460": "hogtd", + "col461": "snoj2", + "col462": "pyl14", + "col463": "npc77", + "col464": "bmlbc", + "col465": "14llk", + "col466": "vyy3o", + "col467": "t1t8j", + "col468": "jf4rg", + "col469": "2tru4", + "col470": "02qpt", + "col471": "nveyb", + "col472": "ck007", + "col473": "6b57r", + "col474": "ox1gq", + "col475": "nernm", + "col476": "zatly", + "col477": "a26h4", + "col478": "rxtya", + "col479": "q6kgi", + "col480": "87h2r", + "col481": "owhiy", + "col482": "hgz3y", + "col483": "3ke58", + "col484": "k99v8", + "col485": "n83a1", + "col486": "p9vnf", + "col487": "ljseb", + "col488": "1rxq6", + "col489": "u5lwi", + "col490": "iapf7", + "col491": "q8g0l", + "col492": "kl5hl", + "col493": "wm39q", + "col494": "hfzse", + "col495": "7ty1z", + "col496": "99632", + "col497": "vkyml", + "col498": "qox57", + "col499": "l446b", + "col500": "ausaz", + "col501": "1yts4", + "col502": "zt1my", + "col503": "6sv8h", + "col504": "gquul", + "col505": "gvtpf", + "col506": "t5ae9", + "col507": "kcmc6", + "col508": "m6a4d", + "col509": "qbdh1", + "col510": "3mzct", + "col511": "d6o0o", + "col512": "1e0up", + "col513": "wdaur", + "col514": "oe065", + "col515": "ex5ic", + "col516": "050q2", + "col517": "64gnn", + "col518": "cq6nm", + "col519": "64l32", + "col520": "ykqpf", + "col521": "oh341", + "col522": "ez6e1", + "col523": "dht84", + "col524": "69h44", + "col525": "7i7y3", + "col526": "rap8u", + "col527": "xc25p", + "col528": "6u1va", + "col529": "wa1x7", + "col530": "zqcmc", + "col531": "bgzyu", + "col532": "mvpja", + "col533": "qpbdy", + "col534": "yf72g", + "col535": "wopvh", + "col536": "0uv8n", + "col537": "8q9ec", + "col538": "v6m15", + "col539": "tn0w8", + "col540": "i2uqr", + "col541": "tm206", + "col542": "lk6nm", + "col543": "cty9i", + "col544": "yokn4", + "col545": "r5271", + "col546": "aribk", + "col547": "3fn65", + "col548": "iu9ti", + "col549": "7iosp", + "col550": "9o48t", + "col551": "dxf2i", + "col552": "ugh48", + "col553": "jcax5", + "col554": "pedgs", + "col555": "51wr7", + "col556": "6vrsk", + "col557": "xo4vm", + "col558": "rkf2h", + "col559": "sq3dr", + "col560": "ls8rv", + "col561": "ow4os", + "col562": "fk6ku", + "col563": "2jrue", + "col564": "5zbtz", + "col565": "i6wue", + "col566": "09ink", + "col567": "mlp7b", + "col568": "i0hv8", + "col569": "3lqrg", + "col570": "bfxtn", + "col571": "wtxt4", + "col572": "vg41x", + "col573": "wy331", + "col574": "gs7da", + "col575": "2nr4q", + "col576": "kfrjc", + "col577": "fveda", + "col578": "ep3tw", + "col579": "3w0h8", + "col580": "47mml", + "col581": "rtctd", + "col582": "yy5mj", + "col583": "oix93", + "col584": "ckz23", + "col585": "9e623", + "col586": "wcybq", + "col587": "2hnny", + "col588": "6ljvf", + "col589": "rhfh3", + "col590": "riy5f", + "col591": "47o1c", + "col592": "yelka", + "col593": "89m1o", + "col594": "xrslh", + "col595": "zi8ql", + "col596": "vfgmw", + "col597": "80iyi", + "col598": "g3b1c", + "col599": "1tneq", + "col600": "gyubr", + "col601": "imwzg", + "col602": "685nn", + "col603": "ej2nz", + "col604": "c9etz", + "col605": "f4ej4", + "col606": "11suc", + "col607": "qnl9b", + "col608": "gjtix", + "col609": "nx4rq", + "col610": "6cl3v", + "col611": "meezw", + "col612": "cwncp", + "col613": "3kdl7", + "col614": "gh6vj", + "col615": "eh1je", + "col616": "mqbrr", + "col617": "9udp2", + "col618": "m2jgw", + "col619": "6nxtm", + "col620": "8g0jp", + "col621": "x7vtm", + "col622": "p76km", + "col623": "h6dg3", + "col624": "xi0bc", + "col625": "bdvwq", + "col626": "ucg41", + "col627": "zhxfg", + "col628": "0gfz9", + "col629": "k4y26", + "col630": "v0ls8", + "col631": "fepwq", + "col632": "xgs82", + "col633": "ghevq", + "col634": "1rrmx", + "col635": "my971", + "col636": "zei46", + "col637": "pvpkm", + "col638": "iiqsh", + "col639": "erm6f", + "col640": "jesx7", + "col641": "usdyo", + "col642": "5i3m5", + "col643": "5awcs", + "col644": "3zxfv", + "col645": "wi2i5", + "col646": "labp4", + "col647": "h8rh9", + "col648": "ph58w", + "col649": "ar9w3", + "col650": "5kp3v", + "col651": "w2el1", + "col652": "ac1bm", + "col653": "lshp5", + "col654": "ds8r3", + "col655": "jf89k", + "col656": "bw0t7", + "col657": "2enyg", + "col658": "c9cse", + "col659": "mnb83", + "col660": "qhev1", + "col661": "mtmmy", + "col662": "5vlbm", + "col663": "w7utl", + "col664": "1a9n0", + "col665": "ax1pq", + "col666": "h7amt", + "col667": "4tfr9", + "col668": "ky8zg", + "col669": "e2wbj", + "col670": "8jlo1", + "col671": "b31sl", + "col672": "x9c6n", + "col673": "0696i", + "col674": "5na8i", + "col675": "h2elr", + "col676": "klazu", + "col677": "mfl3s", + "col678": "s2zqs", + "col679": "tuwbj", + "col680": "g7a4b", + "col681": "m1543", + "col682": "sb6ko", + "col683": "vx5pi", + "col684": "s7zg0", + "col685": "v36f1", + "col686": "o1tzt", + "col687": "kuuy5", + "col688": "nh2vt", + "col689": "n30t2", + "col690": "k22ts", + "col691": "dgx8r", + "col692": "yw2t7", + "col693": "kly39", + "col694": "h2vgk", + "col695": "jk01b", + "col696": "ccugz", + "col697": "uxc35", + "col698": "2zmo0", + "col699": "mfh52", + "col700": "8zg4z", + "col701": "eo6gw", + "col702": "ks92f", + "col703": "4fqa0", + "col704": "duo74", + "col705": "gtj2n", + "col706": "0wxet", + "col707": "avrc6", + "col708": "99uqt", + "col709": "xsdqb", + "col710": "kg00x", + "col711": "bwpep", + "col712": "1je3p", + "col713": "66if4", + "col714": "s38nn", + "col715": "od2l8", + "col716": "jzvfo", + "col717": "j0uth", + "col718": "u4ocq", + "col719": "jc5bv", + "col720": "4gkzd", + "col721": "314ni", + "col722": "lwvgf", + "col723": "o14qe", + "col724": "8jolf", + "col725": "kir21", + "col726": "m2g5u", + "col727": "5hoff", + "col728": "gh6hm", + "col729": "p1qfa", + "col730": "qntja", + "col731": "2795p", + "col732": "8sz37", + "col733": "nntl1", + "col734": "zzdbj", + "col735": "bqcd9", + "col736": "ns447", + "col737": "5jxdr", + "col738": "vtzi3", + "col739": "iaa0s", + "col740": "lvgwn", + "col741": "zm1iw", + "col742": "qedfy", + "col743": "2oc52", + "col744": "b5mth", + "col745": "ryz3p", + "col746": "z6leo", + "col747": "qnfpm", + "col748": "k9wd6", + "col749": "4a4p3", + "col750": "14myu", + "col751": "1g8n6", + "col752": "8r4d6", + "col753": "degll", + "col754": "56ic6", + "col755": "jvlue", + "col756": "pm5l8", + "col757": "523lx", + "col758": "4c5sb", + "col759": "k96nz", + "col760": "z7plu", + "col761": "27m5h", + "col762": "1tvm4", + "col763": "7zdq0", + "col764": "lq7vu", + "col765": "ftdvy", + "col766": "992p0", + "col767": "yoexm", + "col768": "ab9w1", + "col769": "dmvej", + "col770": "q4pf1", + "col771": "p5h2n", + "col772": "fyl7e", + "col773": "3odhy", + "col774": "2yznu", + "col775": "bqo6e", + "col776": "nnguu", + "col777": "hoqm1", + "col778": "fmc8o", + "col779": "188q0", + "col780": "fji6d", + "col781": "69us3", + "col782": "xum4c", + "col783": "58nb4", + "col784": "omlwr", + "col785": "f88tf", + "col786": "fbxk9", + "col787": "mrtil", + "col788": "4ecvt", + "col789": "t9dcj", + "col790": "6nxcg", + "col791": "5fhlu", + "col792": "845ib", + "col793": "jrsfi", + "col794": "pmy9v", + "col795": "308yy", + "col796": "s74ci", + "col797": "uxmns", + "col798": "vjb8n", + "col799": "f2btu", + "col800": "rg9o6", + "col801": "tl8j7", + "col802": "g5pk3", + "col803": "dgbcy", + "col804": "zqbdi", + "col805": "onp6y", + "col806": "xajgu", + "col807": "cnh6i", + "col808": "j39dv", + "col809": "f9gbs", + "col810": "41prg", + "col811": "a74xm", + "col812": "64qse", + "col813": "m3frc", + "col814": "ly34x", + "col815": "m47wy", + "col816": "6rotn", + "col817": "xkqxj", + "col818": "33hvq", + "col819": "81flf", + "col820": "w1b39", + "col821": "1gkj6", + "col822": "ix1u9", + "col823": "0pncl", + "col824": "fklwe", + "col825": "358nw", + "col826": "mc1fh", + "col827": "szice", + "col828": "f9rmy", + "col829": "5udia", + "col830": "macqg", + "col831": "ffxfa", + "col832": "xu7l7", + "col833": "i0w93", + "col834": "gl03g", + "col835": "lt70b", + "col836": "rscsz", + "col837": "8hcqn", + "col838": "ckply", + "col839": "sgty6", + "col840": "500eu", + "col841": "6321w", + "col842": "5hfmn", + "col843": "ujtrr", + "col844": "dtmpg", + "col845": "w3tx7", + "col846": "0afvd", + "col847": "7o07d", + "col848": "24808", + "col849": "fqv8a", + "col850": "1jqx4", + "col851": "x0tjb", + "col852": "m9k9r", + "col853": "wkjxk", + "col854": "ikrme", + "col855": "o2ta8", + "col856": "2pehk", + "col857": "a15b1", + "col858": "igj5p", + "col859": "h6qwr", + "col860": "tsgsz", + "col861": "shte7", + "col862": "hpw6o", + "col863": "i4vmz", + "col864": "q7edc", + "col865": "fzzg1", + "col866": "ckj4i", + "col867": "fln6i", + "col868": "l13vr", + "col869": "1kfvj", + "col870": "t6wd8", + "col871": "3n0qi", + "col872": "qja8k", + "col873": "mjx6f", + "col874": "bwts2", + "col875": "19adk", + "col876": "tygo6", + "col877": "7z370", + "col878": "xwvdu", + "col879": "ak0kd", + "col880": "ugp7a", + "col881": "2dpjz", + "col882": "g6hdp", + "col883": "osecr", + "col884": "9tlgt", + "col885": "3py85", + "col886": "hai08", + "col887": "lgijt", + "col888": "1ufwa", + "col889": "iy8y3", + "col890": "b5luz", + "col891": "mh0rr", + "col892": "s5txp", + "col893": "guwxt", + "col894": "8hi0a", + "col895": "htvwt", + "col896": "lnlkh", + "col897": "lfvj3", + "col898": "oahcp", + "col899": "wp6l8", + "col900": "7vnh3", + "col901": "so5ag", + "col902": "3qisx", + "col903": "3214a", + "col904": "cxnrh", + "col905": "gzy7m", + "col906": "aco8r", + "col907": "mbpiz", + "col908": "cr0sw", + "col909": "pbjoo", + "col910": "kdk8d", + "col911": "1fa9y", + "col912": "xsvy4", + "col913": "m7thq", + "col914": "lvcdj", + "col915": "miouh", + "col916": "huarg", + "col917": "fc80j", + "col918": "hiot9", + "col919": "mq27z", + "col920": "rkwup", + "col921": "9k2fb", + "col922": "69ufn", + "col923": "oniqt", + "col924": "489nn", + "col925": "xbgy0", + "col926": "fqvi1", + "col927": "l5jhk", + "col928": "pkkb5", + "col929": "abq71", + "col930": "sh1jr", + "col931": "z9c36", + "col932": "7zjtr", + "col933": "qsxfa", + "col934": "cq5bn", + "col935": "bw7fa", + "col936": "nwbfq", + "col937": "21zyx", + "col938": "kg76b", + "col939": "kj5rd", + "col940": "f5pxa", + "col941": "muy5j", + "col942": "lcsfz", + "col943": "0v70s", + "col944": "ypxgp", + "col945": "dyvnq", + "col946": "qqm75", + "col947": "2w8lf", + "col948": "ub9q4", + "col949": "jf2v4", + "col950": "92dll", + "col951": "msugl", + "col952": "znzmw", + "col953": "utkjz", + "col954": "v9ycx", + "col955": "6o76j", + "col956": "mlh3r", + "col957": "4u5nc", + "col958": "hx8a6", + "col959": "u0qge", + "col960": "z0zan", + "col961": "s215b", + "col962": "70jkw", + "col963": "b5qar", + "col964": "9vq2f", + "col965": "7d62t", + "col966": "c5m66", + "col967": "x9sy4", + "col968": "0a6mq", + "col969": "y1tlp", + "col970": "qanjj", + "col971": "x73kq", + "col972": "4lduz", + "col973": "pndhr", + "col974": "8mg8d", + "col975": "76pjt", + "col976": "d0odx", + "col977": "3eita", + "col978": "kt9pn", + "col979": "e8e5s", + "col980": "10gg9", + "col981": "csf0c", + "col982": "20jsz", + "col983": "9mg3m", + "col984": "zql4g", + "col985": "e89l7", + "col986": "9f3w2", + "col987": "n6an1", + "col988": "m8mdp", + "col989": "skb1b", + "col990": "rvxsq", + "col991": "68jxq", + "col992": "a9bzo", + "col993": "mhjth", + "col994": "axggx", + "col995": "pfnbq", + "col996": "ulvq5", + "col997": "qtx3u", + "col998": "zcn2q", + "col999": "gwtqi" + }, + { + "name": "Ophelia Singleton", + "gender": "female", + "col0": "w7u4g", + "col1": "1umc4", + "col2": "bthjt", + "col3": "15q2f", + "col4": "s66ws", + "col5": "wjd6g", + "col6": "xcag2", + "col7": "n98pk", + "col8": "6mv4h", + "col9": "1q2p7", + "col10": "dftnf", + "col11": "k7rm1", + "col12": "j452t", + "col13": "w1qcd", + "col14": "a8s4f", + "col15": "85p9p", + "col16": "9jj7p", + "col17": "fby5h", + "col18": "8n01a", + "col19": "z06j1", + "col20": "y5jqg", + "col21": "f24mf", + "col22": "n9b3d", + "col23": "6k0ls", + "col24": "waste", + "col25": "2nfve", + "col26": "o34yu", + "col27": "j0lgb", + "col28": "lbtco", + "col29": "9fuli", + "col30": "izbwd", + "col31": "7s1qo", + "col32": "ixorv", + "col33": "tsjqu", + "col34": "25hxs", + "col35": "6adkp", + "col36": "fn4kn", + "col37": "11ov6", + "col38": "a3oze", + "col39": "u9rnu", + "col40": "ffl9a", + "col41": "4emhj", + "col42": "iq1kq", + "col43": "jqb3q", + "col44": "atrrx", + "col45": "yoh1k", + "col46": "mfjx8", + "col47": "wvlgg", + "col48": "65bb9", + "col49": "ggfas", + "col50": "w9qcg", + "col51": "3dlfx", + "col52": "mesxr", + "col53": "mslkf", + "col54": "4cm3x", + "col55": "eyykd", + "col56": "s1wrk", + "col57": "juvv8", + "col58": "d2l1b", + "col59": "62uqk", + "col60": "2t6l2", + "col61": "3at4g", + "col62": "20pp4", + "col63": "a9eiu", + "col64": "7w8pq", + "col65": "h3zqy", + "col66": "jonuj", + "col67": "7re7m", + "col68": "3hrcu", + "col69": "ym9vh", + "col70": "24qsg", + "col71": "eo8vn", + "col72": "s1jzi", + "col73": "41gbp", + "col74": "9peef", + "col75": "jwyps", + "col76": "kf4j1", + "col77": "eb3nz", + "col78": "viioy", + "col79": "2etvo", + "col80": "7lmi7", + "col81": "4mhdz", + "col82": "241ta", + "col83": "ezrnf", + "col84": "ufdqx", + "col85": "01fqu", + "col86": "om05c", + "col87": "86duk", + "col88": "ce66j", + "col89": "2v16h", + "col90": "ni9m6", + "col91": "0spkt", + "col92": "tpft9", + "col93": "p99sx", + "col94": "pa6dt", + "col95": "f9k4c", + "col96": "wiclg", + "col97": "awzq0", + "col98": "pwpfo", + "col99": "675zi", + "col100": "jjkbs", + "col101": "ry3tj", + "col102": "sqe4s", + "col103": "py2lf", + "col104": "pnfts", + "col105": "w52vk", + "col106": "d1wh4", + "col107": "x8roh", + "col108": "3imtv", + "col109": "cva5k", + "col110": "s7lyh", + "col111": "ml7uk", + "col112": "qv2yc", + "col113": "pvu4h", + "col114": "gwtz6", + "col115": "jjguh", + "col116": "j97kf", + "col117": "cvkhb", + "col118": "bk6j9", + "col119": "ckk4g", + "col120": "5ytzc", + "col121": "r2a74", + "col122": "yz691", + "col123": "bal1z", + "col124": "5g8ex", + "col125": "qopsf", + "col126": "lg9lp", + "col127": "ag3y8", + "col128": "8mmgf", + "col129": "stbkn", + "col130": "vru27", + "col131": "s8etp", + "col132": "5rfq9", + "col133": "iu5mw", + "col134": "cey4e", + "col135": "or5j4", + "col136": "0y53a", + "col137": "grqyp", + "col138": "evenv", + "col139": "x4txk", + "col140": "j5khz", + "col141": "388um", + "col142": "b3f40", + "col143": "3zfjx", + "col144": "rnd18", + "col145": "hh2ml", + "col146": "iiqob", + "col147": "9wwp7", + "col148": "zofw5", + "col149": "8lofg", + "col150": "13le9", + "col151": "anqzn", + "col152": "71zsv", + "col153": "lkf3n", + "col154": "3xs2e", + "col155": "pfw45", + "col156": "1qe5b", + "col157": "4ax1d", + "col158": "8zra6", + "col159": "14lbf", + "col160": "b5skg", + "col161": "jx0xz", + "col162": "jygc5", + "col163": "rma77", + "col164": "owtx5", + "col165": "3hih5", + "col166": "pb1pk", + "col167": "6ayut", + "col168": "rp5tr", + "col169": "n5g5d", + "col170": "49ikb", + "col171": "9qss2", + "col172": "03q6l", + "col173": "hsogi", + "col174": "vkgvp", + "col175": "2j1wj", + "col176": "9365c", + "col177": "p8o8t", + "col178": "rcizf", + "col179": "9tjx0", + "col180": "nqk1s", + "col181": "rhysm", + "col182": "sqkjv", + "col183": "pq4iq", + "col184": "42up8", + "col185": "6r1fv", + "col186": "my1dk", + "col187": "bsi9a", + "col188": "0rf7x", + "col189": "pdda5", + "col190": "ry9ol", + "col191": "cp1g7", + "col192": "ikt0p", + "col193": "g0xi8", + "col194": "o914c", + "col195": "3durp", + "col196": "1n8mv", + "col197": "tp0pd", + "col198": "33mc6", + "col199": "2po0q", + "col200": "i9yce", + "col201": "x5hqt", + "col202": "cae8b", + "col203": "3534d", + "col204": "uondr", + "col205": "lvzj8", + "col206": "pgo86", + "col207": "pnpg8", + "col208": "52y5y", + "col209": "rf8a6", + "col210": "1biaz", + "col211": "t30iy", + "col212": "dohb9", + "col213": "1cvql", + "col214": "2vb63", + "col215": "3jjf8", + "col216": "o3hlx", + "col217": "nbj8b", + "col218": "dwz1k", + "col219": "gvzbf", + "col220": "j3ed6", + "col221": "klelf", + "col222": "4kave", + "col223": "51lyp", + "col224": "el1t3", + "col225": "nmf7w", + "col226": "szrqj", + "col227": "r7ooh", + "col228": "plpyq", + "col229": "d6hr0", + "col230": "romzi", + "col231": "ti70q", + "col232": "qtknw", + "col233": "vuua9", + "col234": "itep5", + "col235": "o7zuf", + "col236": "eoban", + "col237": "5qa2y", + "col238": "dw2rm", + "col239": "cd4xa", + "col240": "9y62u", + "col241": "2eq2h", + "col242": "idno6", + "col243": "9mzyd", + "col244": "fsh6q", + "col245": "c5d21", + "col246": "4qfr8", + "col247": "uwv6z", + "col248": "6xvzl", + "col249": "tw2dz", + "col250": "j01r3", + "col251": "3xiwq", + "col252": "d554h", + "col253": "kkj2k", + "col254": "nd188", + "col255": "n68t0", + "col256": "w0jgl", + "col257": "q4vhu", + "col258": "nirao", + "col259": "m5jk8", + "col260": "0qxqn", + "col261": "pxuuq", + "col262": "20nvz", + "col263": "91kip", + "col264": "41rbu", + "col265": "8gnjx", + "col266": "ga4ff", + "col267": "we7pz", + "col268": "raid3", + "col269": "og04t", + "col270": "yd5ur", + "col271": "66g7g", + "col272": "kjnmb", + "col273": "f50fc", + "col274": "vjnbf", + "col275": "3t4o7", + "col276": "ee4x2", + "col277": "8raki", + "col278": "4daxi", + "col279": "2djex", + "col280": "qkamv", + "col281": "o8e39", + "col282": "t6xuh", + "col283": "cgwvx", + "col284": "8cnqq", + "col285": "hxd7x", + "col286": "qr637", + "col287": "9lkd2", + "col288": "zhln8", + "col289": "qm6m4", + "col290": "f1ljg", + "col291": "jpcz1", + "col292": "61631", + "col293": "0eh28", + "col294": "xpxn5", + "col295": "n9hqm", + "col296": "6n872", + "col297": "9xjm1", + "col298": "8mm5o", + "col299": "57vv1", + "col300": "9ktli", + "col301": "klntx", + "col302": "oeevo", + "col303": "ggv85", + "col304": "dpv8f", + "col305": "3xhl2", + "col306": "bo4n1", + "col307": "p26hd", + "col308": "o9i2z", + "col309": "fqzin", + "col310": "vy7j1", + "col311": "z5e8f", + "col312": "bjekd", + "col313": "t76zo", + "col314": "2y3zv", + "col315": "7k3ht", + "col316": "7y7c8", + "col317": "i0es0", + "col318": "xvkc7", + "col319": "rc9co", + "col320": "0n78h", + "col321": "d6bp7", + "col322": "nbua2", + "col323": "tze6s", + "col324": "adb24", + "col325": "uod87", + "col326": "8xvri", + "col327": "5yjf3", + "col328": "6xvfw", + "col329": "5d8hb", + "col330": "lsanq", + "col331": "4yrfw", + "col332": "weagn", + "col333": "sacwx", + "col334": "47mxv", + "col335": "70h0g", + "col336": "hxcrb", + "col337": "3spy6", + "col338": "t7y54", + "col339": "jplir", + "col340": "fryu0", + "col341": "vxwli", + "col342": "g1n6i", + "col343": "jakvr", + "col344": "m55a3", + "col345": "uqqzd", + "col346": "150lb", + "col347": "w3bq2", + "col348": "0bing", + "col349": "3t4cc", + "col350": "5oqib", + "col351": "7dm74", + "col352": "5rzi7", + "col353": "oien6", + "col354": "6dijp", + "col355": "0deks", + "col356": "0sw71", + "col357": "gi3b4", + "col358": "9xz72", + "col359": "sr3b5", + "col360": "ytw2p", + "col361": "j5uoy", + "col362": "zcyci", + "col363": "xvw63", + "col364": "4dtjo", + "col365": "funvj", + "col366": "qfioq", + "col367": "ls7ru", + "col368": "6oqz7", + "col369": "5h313", + "col370": "j4uvc", + "col371": "97tbl", + "col372": "q4w98", + "col373": "18mfx", + "col374": "lnuej", + "col375": "vrwmv", + "col376": "hubhy", + "col377": "ae5bx", + "col378": "9chii", + "col379": "41ed1", + "col380": "fecby", + "col381": "06660", + "col382": "mh8ch", + "col383": "9y4jj", + "col384": "q66ps", + "col385": "uzgg5", + "col386": "awqu2", + "col387": "8vrdg", + "col388": "oumdj", + "col389": "7lytr", + "col390": "tzs4g", + "col391": "vra0w", + "col392": "wzxdo", + "col393": "lwf8k", + "col394": "9zpsy", + "col395": "l3kwk", + "col396": "x7xcg", + "col397": "iosrd", + "col398": "jxttd", + "col399": "94m06", + "col400": "k9blb", + "col401": "gdn1x", + "col402": "8yzgr", + "col403": "e1kz9", + "col404": "j6v97", + "col405": "mfeu6", + "col406": "edci3", + "col407": "qvk63", + "col408": "k0wk1", + "col409": "e89jk", + "col410": "v00vg", + "col411": "85t95", + "col412": "yjakh", + "col413": "ou86x", + "col414": "mhcff", + "col415": "xiudk", + "col416": "zxqyr", + "col417": "3gy75", + "col418": "wtfc9", + "col419": "064kq", + "col420": "x7y64", + "col421": "ehtbw", + "col422": "rvz1t", + "col423": "ccnmw", + "col424": "rgg1y", + "col425": "g6xea", + "col426": "0lwlt", + "col427": "fnniy", + "col428": "8fxdb", + "col429": "33qn7", + "col430": "hmve9", + "col431": "xbyr0", + "col432": "xhdgv", + "col433": "eja13", + "col434": "77x8p", + "col435": "uvziq", + "col436": "d17f7", + "col437": "vjdff", + "col438": "mmawg", + "col439": "nxsk0", + "col440": "faaf3", + "col441": "sgzj9", + "col442": "j2p3f", + "col443": "41881", + "col444": "zrrop", + "col445": "vegr4", + "col446": "cprvq", + "col447": "5u5xp", + "col448": "5qu71", + "col449": "hwc3l", + "col450": "nzstc", + "col451": "6cu7b", + "col452": "1dtb1", + "col453": "kiuek", + "col454": "t8muj", + "col455": "d6jor", + "col456": "7r61m", + "col457": "rqkwk", + "col458": "3oj0u", + "col459": "h2ezn", + "col460": "2h8bw", + "col461": "z59fx", + "col462": "u5hhp", + "col463": "6r6l8", + "col464": "vurk6", + "col465": "0o9rg", + "col466": "iz53e", + "col467": "elkn2", + "col468": "aiwpi", + "col469": "d0b4h", + "col470": "ymydj", + "col471": "okmnd", + "col472": "e8roi", + "col473": "hsmd6", + "col474": "vczhu", + "col475": "grkp0", + "col476": "2i41g", + "col477": "16wwd", + "col478": "ftz0p", + "col479": "y7zhh", + "col480": "gyuqe", + "col481": "hmpcl", + "col482": "nvl2k", + "col483": "zsf8j", + "col484": "vmqxq", + "col485": "ew83v", + "col486": "vvm7d", + "col487": "52ner", + "col488": "7jb7m", + "col489": "gg8yy", + "col490": "jc6ef", + "col491": "urb5q", + "col492": "5yjth", + "col493": "d0udd", + "col494": "iw1jb", + "col495": "61zq6", + "col496": "i89ks", + "col497": "mapg0", + "col498": "8o3fj", + "col499": "gebaq", + "col500": "0fn53", + "col501": "jcbzz", + "col502": "jjcho", + "col503": "y7s4x", + "col504": "0j190", + "col505": "57xov", + "col506": "t1cj9", + "col507": "s2q9n", + "col508": "qrz22", + "col509": "7wbi7", + "col510": "kujm0", + "col511": "2da6u", + "col512": "153io", + "col513": "uu8d4", + "col514": "zjxlk", + "col515": "yvbss", + "col516": "cv56h", + "col517": "dlfq4", + "col518": "92p4t", + "col519": "bthsl", + "col520": "d7k3n", + "col521": "pvg8l", + "col522": "jyfqd", + "col523": "46pa5", + "col524": "8g55z", + "col525": "xawhp", + "col526": "bbjw4", + "col527": "b9g5t", + "col528": "so35x", + "col529": "0j15m", + "col530": "3obe1", + "col531": "x1078", + "col532": "f8fsw", + "col533": "hkuo2", + "col534": "au37y", + "col535": "jp98v", + "col536": "z2ek3", + "col537": "ued15", + "col538": "noeq0", + "col539": "o5e91", + "col540": "m6vel", + "col541": "70irt", + "col542": "mxsvj", + "col543": "jhmxg", + "col544": "de8r4", + "col545": "go1bp", + "col546": "y8qs5", + "col547": "co2gt", + "col548": "ex5ze", + "col549": "mtz45", + "col550": "xg19r", + "col551": "kkoxs", + "col552": "ra99w", + "col553": "66rg6", + "col554": "lraw9", + "col555": "4sv3f", + "col556": "0ozum", + "col557": "9et1p", + "col558": "mvfop", + "col559": "r3bqc", + "col560": "1km33", + "col561": "xamsl", + "col562": "9hxf9", + "col563": "iusp6", + "col564": "29jwl", + "col565": "3xuxg", + "col566": "j6w93", + "col567": "l94mv", + "col568": "krg6r", + "col569": "0rich", + "col570": "sn8a7", + "col571": "gf1zu", + "col572": "9vchp", + "col573": "d69ri", + "col574": "o9dd9", + "col575": "kty05", + "col576": "1bw7b", + "col577": "ke8mi", + "col578": "r2lhj", + "col579": "h3dba", + "col580": "7r3m3", + "col581": "h5d7w", + "col582": "2a6m9", + "col583": "qmqz7", + "col584": "wbvfs", + "col585": "2r30w", + "col586": "0nyz3", + "col587": "qvrwe", + "col588": "3k7nw", + "col589": "c2lw8", + "col590": "kzus3", + "col591": "g7kcf", + "col592": "61rhn", + "col593": "e75ba", + "col594": "hji5q", + "col595": "h08b6", + "col596": "vm8at", + "col597": "vnr7w", + "col598": "t6hwq", + "col599": "eq9tt", + "col600": "su9vl", + "col601": "dsidb", + "col602": "4i1cp", + "col603": "fvia7", + "col604": "yhaag", + "col605": "r2pl5", + "col606": "f4qx9", + "col607": "5uwet", + "col608": "59jbi", + "col609": "0il7q", + "col610": "4v9ok", + "col611": "dsv53", + "col612": "ef56o", + "col613": "fbcdt", + "col614": "fax80", + "col615": "hdux6", + "col616": "qjl0t", + "col617": "ufwk3", + "col618": "zoxz3", + "col619": "frzja", + "col620": "fgcjr", + "col621": "98wae", + "col622": "g8j4h", + "col623": "y5chr", + "col624": "mguxi", + "col625": "673j9", + "col626": "qz9x3", + "col627": "ka189", + "col628": "2my5q", + "col629": "8dmp6", + "col630": "i34jh", + "col631": "z9mbe", + "col632": "aseum", + "col633": "ac6no", + "col634": "o5tlj", + "col635": "j5fke", + "col636": "9zosp", + "col637": "iovlq", + "col638": "mmr94", + "col639": "1qdn1", + "col640": "gxolk", + "col641": "rhblx", + "col642": "8oxl5", + "col643": "z0zem", + "col644": "3o9uh", + "col645": "mkk8y", + "col646": "6w62x", + "col647": "38di2", + "col648": "0x50t", + "col649": "9ibb5", + "col650": "kjnmg", + "col651": "8jesz", + "col652": "73g89", + "col653": "7rfe3", + "col654": "p2tod", + "col655": "0avue", + "col656": "eood8", + "col657": "tupgg", + "col658": "hkxb3", + "col659": "j28az", + "col660": "tnq5f", + "col661": "g1zbl", + "col662": "tdg9s", + "col663": "i55vi", + "col664": "ngznv", + "col665": "d5p4x", + "col666": "ll0is", + "col667": "qaqtu", + "col668": "qccf6", + "col669": "rrl1z", + "col670": "z7xn7", + "col671": "rnwi2", + "col672": "976v0", + "col673": "ssqty", + "col674": "su9mx", + "col675": "7odwi", + "col676": "naya4", + "col677": "m63lw", + "col678": "8stp9", + "col679": "0uosp", + "col680": "1aqbf", + "col681": "tl139", + "col682": "dzbap", + "col683": "k3jgo", + "col684": "3ls3z", + "col685": "148ig", + "col686": "j0p27", + "col687": "ll1qg", + "col688": "ufxxu", + "col689": "idtnm", + "col690": "s9j1b", + "col691": "kreud", + "col692": "r1iaz", + "col693": "g12y6", + "col694": "9tg73", + "col695": "gfid4", + "col696": "8kw97", + "col697": "7shp7", + "col698": "jzwhq", + "col699": "8ijnq", + "col700": "urzu5", + "col701": "hpmad", + "col702": "wa7wo", + "col703": "110sz", + "col704": "5uw9h", + "col705": "tszgo", + "col706": "vt1kz", + "col707": "3pnep", + "col708": "cpfy6", + "col709": "u28fz", + "col710": "ueand", + "col711": "kn4gs", + "col712": "ehc7x", + "col713": "c0u1r", + "col714": "erih0", + "col715": "si895", + "col716": "vrub0", + "col717": "s5904", + "col718": "dulum", + "col719": "e9gju", + "col720": "c0e4i", + "col721": "i9t3j", + "col722": "cdy7g", + "col723": "o7c6p", + "col724": "uqegy", + "col725": "v5djl", + "col726": "ugikd", + "col727": "aq8x5", + "col728": "xehuy", + "col729": "xsgl5", + "col730": "la91v", + "col731": "siay7", + "col732": "6re8e", + "col733": "hvwl7", + "col734": "b1vc8", + "col735": "jn6r8", + "col736": "k5k6v", + "col737": "q1jtc", + "col738": "4xzqw", + "col739": "n23b6", + "col740": "63q7r", + "col741": "2pem4", + "col742": "k2rty", + "col743": "u334o", + "col744": "w2lak", + "col745": "hxvos", + "col746": "1bubr", + "col747": "x07sx", + "col748": "ricip", + "col749": "tho73", + "col750": "pbl21", + "col751": "mja7r", + "col752": "buwf5", + "col753": "74ndi", + "col754": "jw2r7", + "col755": "a1lgo", + "col756": "5hsyn", + "col757": "iwyj5", + "col758": "k9tt7", + "col759": "syfi1", + "col760": "cnu5z", + "col761": "0zrwd", + "col762": "53vj1", + "col763": "ifesy", + "col764": "yq1fq", + "col765": "ujn1m", + "col766": "tlk97", + "col767": "55iq7", + "col768": "rdoec", + "col769": "2vhvy", + "col770": "o48a4", + "col771": "v5gd4", + "col772": "a6hzx", + "col773": "li2re", + "col774": "ybts6", + "col775": "ebqq9", + "col776": "hjicr", + "col777": "1zfp4", + "col778": "jtjmb", + "col779": "ot3b7", + "col780": "zn8x1", + "col781": "e3k9y", + "col782": "yxw0i", + "col783": "38c55", + "col784": "ypdhd", + "col785": "40aep", + "col786": "5dlwv", + "col787": "i9n1o", + "col788": "wcmc2", + "col789": "u8zgp", + "col790": "l5coa", + "col791": "18l0j", + "col792": "v6dw9", + "col793": "k48vz", + "col794": "ha6xi", + "col795": "udcu0", + "col796": "putwg", + "col797": "xf7nb", + "col798": "deils", + "col799": "20spg", + "col800": "ysjgd", + "col801": "9rsm5", + "col802": "bio11", + "col803": "psamt", + "col804": "zyuwg", + "col805": "ddt28", + "col806": "sz8rw", + "col807": "fdm9x", + "col808": "ft2dz", + "col809": "0x093", + "col810": "9qd23", + "col811": "9edz5", + "col812": "2zy1d", + "col813": "9ktnq", + "col814": "sdlwp", + "col815": "32wte", + "col816": "nkqju", + "col817": "8zeue", + "col818": "yali8", + "col819": "lfyng", + "col820": "8ig0q", + "col821": "m0cvl", + "col822": "4qiyv", + "col823": "a7hvc", + "col824": "ylr8q", + "col825": "clajp", + "col826": "yox8b", + "col827": "za3xu", + "col828": "a7ji2", + "col829": "74bez", + "col830": "wxwo8", + "col831": "bqhe0", + "col832": "l747t", + "col833": "keq1a", + "col834": "bh7zi", + "col835": "l0t36", + "col836": "otzo8", + "col837": "18rbq", + "col838": "1zvmi", + "col839": "k3t13", + "col840": "rrqya", + "col841": "xdum8", + "col842": "fdi3k", + "col843": "nsh0l", + "col844": "28834", + "col845": "0v98b", + "col846": "cle4s", + "col847": "545c6", + "col848": "0mg2r", + "col849": "d5g23", + "col850": "dnzuz", + "col851": "kk46y", + "col852": "iof0t", + "col853": "y6116", + "col854": "zepua", + "col855": "7yuxg", + "col856": "9kejz", + "col857": "tyefz", + "col858": "650u1", + "col859": "0og7j", + "col860": "97b37", + "col861": "6zoyu", + "col862": "ituea", + "col863": "q9lw5", + "col864": "3gs3a", + "col865": "df78f", + "col866": "hlyw1", + "col867": "1giu9", + "col868": "uthxn", + "col869": "6ol32", + "col870": "d3v6v", + "col871": "tfre6", + "col872": "ypky9", + "col873": "r585l", + "col874": "1iabf", + "col875": "obk4b", + "col876": "gmmd6", + "col877": "8m68i", + "col878": "x8jwl", + "col879": "whnj7", + "col880": "rzjg4", + "col881": "0ozvz", + "col882": "0tia3", + "col883": "vd1fk", + "col884": "q7xez", + "col885": "57owf", + "col886": "r4l8b", + "col887": "tkgx3", + "col888": "d2lk7", + "col889": "69zqd", + "col890": "qek9k", + "col891": "wwqn3", + "col892": "dfs3j", + "col893": "lds41", + "col894": "15296", + "col895": "g2ea5", + "col896": "nqp45", + "col897": "ozuqj", + "col898": "3kwdw", + "col899": "cweny", + "col900": "lv75b", + "col901": "43cpr", + "col902": "ukvhq", + "col903": "fgvh8", + "col904": "8xtxh", + "col905": "xkh5f", + "col906": "9onpn", + "col907": "p5g3s", + "col908": "bdiv5", + "col909": "eskej", + "col910": "08tgg", + "col911": "9e69w", + "col912": "xxser", + "col913": "h89ri", + "col914": "z2ymv", + "col915": "hqswh", + "col916": "iq1fx", + "col917": "xhkzz", + "col918": "zglze", + "col919": "7sgbz", + "col920": "9xaw2", + "col921": "j2x0i", + "col922": "6amse", + "col923": "6uosj", + "col924": "eezda", + "col925": "u63j9", + "col926": "87sk7", + "col927": "94ire", + "col928": "rwa55", + "col929": "oy3d9", + "col930": "5i2mr", + "col931": "x0hjs", + "col932": "bs9da", + "col933": "rzhgn", + "col934": "e81sn", + "col935": "zto8y", + "col936": "sd97p", + "col937": "9pzha", + "col938": "yt4x4", + "col939": "f0din", + "col940": "j6lbn", + "col941": "07ho5", + "col942": "h2oay", + "col943": "82q4d", + "col944": "mtd4c", + "col945": "3ckbq", + "col946": "qwrk5", + "col947": "jrb3m", + "col948": "5z3vy", + "col949": "xzqhs", + "col950": "cwrox", + "col951": "nhsmy", + "col952": "tr5se", + "col953": "37z3s", + "col954": "u2k1g", + "col955": "5ufy4", + "col956": "fib61", + "col957": "pp2zk", + "col958": "pylws", + "col959": "5b9cv", + "col960": "st9yj", + "col961": "89jyh", + "col962": "n1k0s", + "col963": "o0fvq", + "col964": "2hila", + "col965": "04dbu", + "col966": "iv7qj", + "col967": "5cgtj", + "col968": "dpuoh", + "col969": "5uhpj", + "col970": "rn9fr", + "col971": "bbzyo", + "col972": "r25v5", + "col973": "c8vcc", + "col974": "fivvb", + "col975": "zldu8", + "col976": "evk27", + "col977": "kpzqh", + "col978": "c7784", + "col979": "13pns", + "col980": "9xeke", + "col981": "1aghp", + "col982": "ypwg5", + "col983": "ri3k6", + "col984": "u2bms", + "col985": "l3tg9", + "col986": "kacde", + "col987": "51zec", + "col988": "jn8ou", + "col989": "mmsig", + "col990": "pg7wb", + "col991": "8hnwm", + "col992": "hmck8", + "col993": "ku4e9", + "col994": "cspxu", + "col995": "o57b8", + "col996": "lrguv", + "col997": "i3xkp", + "col998": "g19og", + "col999": "4pzvx" + }, + { + "name": "Cobb Conway", + "gender": "male", + "col0": "onpa0", + "col1": "onact", + "col2": "9g8cc", + "col3": "tr4vo", + "col4": "uabad", + "col5": "3280o", + "col6": "f81la", + "col7": "bx7qv", + "col8": "j3iza", + "col9": "bl543", + "col10": "81ez0", + "col11": "mq28w", + "col12": "t36e2", + "col13": "adt7b", + "col14": "quyyn", + "col15": "vquts", + "col16": "eqxqn", + "col17": "5tgom", + "col18": "xff4h", + "col19": "57kwd", + "col20": "hgh3n", + "col21": "boh6q", + "col22": "b2rej", + "col23": "mjv66", + "col24": "ii8j4", + "col25": "oxoly", + "col26": "bgx62", + "col27": "86wtm", + "col28": "7o4l9", + "col29": "7lqh3", + "col30": "wtqb9", + "col31": "wzbjg", + "col32": "qmuz3", + "col33": "40tnh", + "col34": "zk6no", + "col35": "leqnc", + "col36": "l460j", + "col37": "8ii92", + "col38": "3hhah", + "col39": "i829x", + "col40": "nbhsf", + "col41": "0llkw", + "col42": "tihfw", + "col43": "xd161", + "col44": "vas06", + "col45": "adn56", + "col46": "94znm", + "col47": "frf9k", + "col48": "u1twe", + "col49": "i0u7b", + "col50": "iwjwe", + "col51": "vhebg", + "col52": "k3fck", + "col53": "wt1gh", + "col54": "hjihy", + "col55": "tpywo", + "col56": "xvz76", + "col57": "fcxpd", + "col58": "vqsrn", + "col59": "1i588", + "col60": "mbi7i", + "col61": "ej2w9", + "col62": "j9cs5", + "col63": "h9tj4", + "col64": "1um08", + "col65": "q31ip", + "col66": "bpxfh", + "col67": "ipagz", + "col68": "fe9vu", + "col69": "a5chw", + "col70": "ydldn", + "col71": "ejqwf", + "col72": "wde9h", + "col73": "qblko", + "col74": "dwyha", + "col75": "a72w2", + "col76": "yueqx", + "col77": "c28w4", + "col78": "5l6kl", + "col79": "xvqrt", + "col80": "b8g08", + "col81": "ehpxs", + "col82": "f3jkw", + "col83": "hz84c", + "col84": "g3m1r", + "col85": "iozzt", + "col86": "hkwk0", + "col87": "3eljl", + "col88": "l7tee", + "col89": "gxkul", + "col90": "r4f9x", + "col91": "3l9uu", + "col92": "gojwz", + "col93": "m1ybo", + "col94": "x2yil", + "col95": "w1u00", + "col96": "7dsxt", + "col97": "aiun8", + "col98": "je5lm", + "col99": "hccy8", + "col100": "as7v7", + "col101": "pie5f", + "col102": "qtk8t", + "col103": "n7p95", + "col104": "bda3z", + "col105": "4b5m4", + "col106": "j438d", + "col107": "8elt0", + "col108": "qg8h8", + "col109": "7nbo1", + "col110": "fl34o", + "col111": "whnuv", + "col112": "tq3li", + "col113": "5c6bg", + "col114": "v4ijh", + "col115": "ynwhp", + "col116": "wiz0u", + "col117": "yh3kk", + "col118": "kwmip", + "col119": "3t41p", + "col120": "rco91", + "col121": "4m72z", + "col122": "3ka93", + "col123": "civu4", + "col124": "zhac5", + "col125": "5t6ic", + "col126": "1nu0d", + "col127": "ciouf", + "col128": "0orj5", + "col129": "7i9mr", + "col130": "md2vu", + "col131": "ophm7", + "col132": "9i1g6", + "col133": "9pe72", + "col134": "0hu9q", + "col135": "giwth", + "col136": "uf6hk", + "col137": "5kvk0", + "col138": "3yodh", + "col139": "9p5my", + "col140": "xekcc", + "col141": "45x5e", + "col142": "1o7q2", + "col143": "uaxv3", + "col144": "nf3cn", + "col145": "sb8od", + "col146": "gdv15", + "col147": "h0ch2", + "col148": "m1323", + "col149": "lvk2u", + "col150": "n8ohb", + "col151": "drdko", + "col152": "u8urg", + "col153": "6sq1e", + "col154": "faibz", + "col155": "nlina", + "col156": "keiw6", + "col157": "27ck2", + "col158": "sryti", + "col159": "1b5hl", + "col160": "8piil", + "col161": "psxp5", + "col162": "9sxyh", + "col163": "wrdxt", + "col164": "15fzi", + "col165": "3zs41", + "col166": "5h93u", + "col167": "43krg", + "col168": "9zmbx", + "col169": "4ggy6", + "col170": "3styf", + "col171": "7syjb", + "col172": "q01s7", + "col173": "epn1q", + "col174": "etpk8", + "col175": "mez93", + "col176": "id2fd", + "col177": "x2gn7", + "col178": "m1jkh", + "col179": "a8kra", + "col180": "0g0ke", + "col181": "5r85u", + "col182": "tmai6", + "col183": "i134n", + "col184": "v8h3s", + "col185": "nujzw", + "col186": "z1eqn", + "col187": "cq961", + "col188": "3a9z5", + "col189": "u5w9z", + "col190": "hr809", + "col191": "kjfcx", + "col192": "shztw", + "col193": "2hys0", + "col194": "m4j44", + "col195": "7wqpv", + "col196": "qvzu4", + "col197": "d0hrg", + "col198": "84gk6", + "col199": "kx7yg", + "col200": "zjx2v", + "col201": "14fes", + "col202": "wumby", + "col203": "4ty19", + "col204": "5tkc9", + "col205": "bd0kl", + "col206": "qdw36", + "col207": "h1q7v", + "col208": "2fo3v", + "col209": "o4ntb", + "col210": "fs5f4", + "col211": "kj58d", + "col212": "3tgks", + "col213": "1ym5k", + "col214": "n1a3w", + "col215": "d6hpf", + "col216": "ef64u", + "col217": "brgge", + "col218": "6dz78", + "col219": "6nyt7", + "col220": "aqc3q", + "col221": "wk5zz", + "col222": "i26f1", + "col223": "poysm", + "col224": "iddb9", + "col225": "zj13r", + "col226": "1nsav", + "col227": "qowog", + "col228": "mt3o3", + "col229": "jjgo8", + "col230": "xg1l1", + "col231": "drrq4", + "col232": "xrou7", + "col233": "muof5", + "col234": "7fluj", + "col235": "ivik4", + "col236": "y0yh1", + "col237": "qucwv", + "col238": "2mg99", + "col239": "3qmj9", + "col240": "mizel", + "col241": "qvmru", + "col242": "geul3", + "col243": "w23ju", + "col244": "wr5fc", + "col245": "t9hwg", + "col246": "dpa6c", + "col247": "9f8j7", + "col248": "vbrwl", + "col249": "88wwd", + "col250": "liqr0", + "col251": "mlivc", + "col252": "i5aop", + "col253": "mcus2", + "col254": "smzi0", + "col255": "sf3y0", + "col256": "07a89", + "col257": "s53ou", + "col258": "49v4w", + "col259": "wr7fg", + "col260": "h9r4u", + "col261": "ljenc", + "col262": "mbhjj", + "col263": "xj62r", + "col264": "wf4g1", + "col265": "ib13e", + "col266": "ux7y6", + "col267": "6du28", + "col268": "3pgn7", + "col269": "4ugow", + "col270": "u4lkv", + "col271": "yop3p", + "col272": "u87ey", + "col273": "lbaw8", + "col274": "9gzts", + "col275": "ls5mi", + "col276": "ke6a6", + "col277": "l3igm", + "col278": "bw5pi", + "col279": "b6b1v", + "col280": "ebxq1", + "col281": "53plk", + "col282": "ysgvx", + "col283": "evkg5", + "col284": "hzla7", + "col285": "3aucv", + "col286": "8rd8p", + "col287": "5fc9m", + "col288": "0eb02", + "col289": "mqo97", + "col290": "z2i9p", + "col291": "zea18", + "col292": "oc2ei", + "col293": "6kzzi", + "col294": "m36ur", + "col295": "czxob", + "col296": "16m81", + "col297": "umncg", + "col298": "fjeaf", + "col299": "15h1z", + "col300": "p5ips", + "col301": "33wpc", + "col302": "ulh2w", + "col303": "uu1xc", + "col304": "ssy0r", + "col305": "h7ofz", + "col306": "5gq9t", + "col307": "ra14z", + "col308": "n0ie2", + "col309": "9pq9v", + "col310": "t9f8m", + "col311": "0m8i5", + "col312": "9xvws", + "col313": "xl68k", + "col314": "lcsyl", + "col315": "8vibl", + "col316": "pcmyu", + "col317": "gb66t", + "col318": "i6xsc", + "col319": "kpm43", + "col320": "8annj", + "col321": "qyudw", + "col322": "skyuo", + "col323": "vfh9y", + "col324": "6324i", + "col325": "nrcfs", + "col326": "lxd4f", + "col327": "b6qt1", + "col328": "ogsse", + "col329": "bxep4", + "col330": "1i780", + "col331": "xhq5i", + "col332": "2yms1", + "col333": "rrsrd", + "col334": "mpupt", + "col335": "c3nke", + "col336": "dbc29", + "col337": "mllnz", + "col338": "uwzx8", + "col339": "f7cfd", + "col340": "xe4an", + "col341": "jaxqd", + "col342": "u5zk6", + "col343": "bbdqt", + "col344": "73tmq", + "col345": "1oogi", + "col346": "hinwr", + "col347": "gen49", + "col348": "yk7wh", + "col349": "xf3g0", + "col350": "ml12z", + "col351": "u1wtn", + "col352": "rgbns", + "col353": "4fi8r", + "col354": "vqd87", + "col355": "9jw4b", + "col356": "wmabp", + "col357": "3d656", + "col358": "rptck", + "col359": "tkp4g", + "col360": "5m2xj", + "col361": "jy638", + "col362": "tm3m6", + "col363": "r3n8a", + "col364": "6n2ax", + "col365": "nn5e2", + "col366": "76wig", + "col367": "s0mzw", + "col368": "t5ycl", + "col369": "fn16l", + "col370": "8aktm", + "col371": "leirw", + "col372": "imlcd", + "col373": "5x2lw", + "col374": "mus1e", + "col375": "bchug", + "col376": "m5n3h", + "col377": "e1x54", + "col378": "0yk6a", + "col379": "l4gp6", + "col380": "4cuqc", + "col381": "ik8fd", + "col382": "kn9wt", + "col383": "tispf", + "col384": "ej987", + "col385": "8mgb3", + "col386": "5q91l", + "col387": "i3acj", + "col388": "wsilf", + "col389": "x3jmz", + "col390": "h6ye4", + "col391": "abp5l", + "col392": "ohvs8", + "col393": "jlvkz", + "col394": "10oy5", + "col395": "8b0kl", + "col396": "jnaxw", + "col397": "f543c", + "col398": "4gqe9", + "col399": "z96ie", + "col400": "4o5ib", + "col401": "hgimf", + "col402": "o2s96", + "col403": "cfgmx", + "col404": "j9p6z", + "col405": "8yv96", + "col406": "922h6", + "col407": "sdowu", + "col408": "x1swt", + "col409": "51nuc", + "col410": "ezx8z", + "col411": "w0mph", + "col412": "jlycn", + "col413": "n6yqi", + "col414": "8vc31", + "col415": "f1vp5", + "col416": "8rx78", + "col417": "p7m03", + "col418": "cohh7", + "col419": "h8a8t", + "col420": "0ojls", + "col421": "szr67", + "col422": "qpdh1", + "col423": "co7sm", + "col424": "2ooh9", + "col425": "i1maq", + "col426": "wpens", + "col427": "l3kxz", + "col428": "9fujh", + "col429": "lfatg", + "col430": "bwm10", + "col431": "q4soq", + "col432": "is54v", + "col433": "hb5pv", + "col434": "abd9q", + "col435": "fgc7l", + "col436": "a8h5h", + "col437": "adqmo", + "col438": "rhod5", + "col439": "kyjas", + "col440": "9ef7p", + "col441": "7ro9l", + "col442": "4ojbd", + "col443": "x20mw", + "col444": "sge5r", + "col445": "awezk", + "col446": "1m0nt", + "col447": "gfqeg", + "col448": "3oshu", + "col449": "svliz", + "col450": "7msnt", + "col451": "7a6ef", + "col452": "ssadf", + "col453": "vvh73", + "col454": "vmj95", + "col455": "8vpjp", + "col456": "y0712", + "col457": "cnu7h", + "col458": "mh7r4", + "col459": "5whgj", + "col460": "ku2hf", + "col461": "my1jt", + "col462": "9ty2a", + "col463": "1dj4o", + "col464": "40q7m", + "col465": "dgkpl", + "col466": "0egnj", + "col467": "0nrwm", + "col468": "laxb6", + "col469": "0ju23", + "col470": "9mw3j", + "col471": "qqu1l", + "col472": "z2yel", + "col473": "wy0z6", + "col474": "7rb4t", + "col475": "t04mc", + "col476": "0vtkz", + "col477": "o0pfv", + "col478": "7w39b", + "col479": "cn9ul", + "col480": "c3q9n", + "col481": "69e0e", + "col482": "d07xe", + "col483": "tap4r", + "col484": "g0qw2", + "col485": "ixqkk", + "col486": "np1rf", + "col487": "33ref", + "col488": "1tb2w", + "col489": "slc4g", + "col490": "z4qvq", + "col491": "0umj9", + "col492": "wyl5y", + "col493": "r9mwy", + "col494": "u04kf", + "col495": "fc0l8", + "col496": "5y50j", + "col497": "szlkk", + "col498": "hd0ba", + "col499": "kp86i", + "col500": "oybgu", + "col501": "lu061", + "col502": "m7mbl", + "col503": "k9q2k", + "col504": "29s37", + "col505": "gsbfi", + "col506": "uvpvl", + "col507": "z3koh", + "col508": "8puol", + "col509": "zwguj", + "col510": "4nhrb", + "col511": "cwjrs", + "col512": "kfgo7", + "col513": "fjhog", + "col514": "k0u69", + "col515": "lz3me", + "col516": "tgjae", + "col517": "z5qrx", + "col518": "90fpb", + "col519": "pjcoi", + "col520": "vqk91", + "col521": "cu1ea", + "col522": "bk3an", + "col523": "eancu", + "col524": "e6ek9", + "col525": "jcqfc", + "col526": "porjp", + "col527": "xvsg1", + "col528": "dgk7q", + "col529": "ongqc", + "col530": "ypf80", + "col531": "6lr4j", + "col532": "8ro8x", + "col533": "my7bi", + "col534": "zpo18", + "col535": "1mnqg", + "col536": "aiu4y", + "col537": "58orf", + "col538": "uo53l", + "col539": "g03sk", + "col540": "9kgun", + "col541": "7vga6", + "col542": "1dhlc", + "col543": "1u1fb", + "col544": "3i5oi", + "col545": "05gpv", + "col546": "mtopz", + "col547": "a7plu", + "col548": "11jo9", + "col549": "2snlf", + "col550": "2yf4j", + "col551": "obspz", + "col552": "dk3ru", + "col553": "g7x93", + "col554": "um7b1", + "col555": "4v5jx", + "col556": "iwswb", + "col557": "u88rh", + "col558": "l2dsv", + "col559": "fzalu", + "col560": "hb4bn", + "col561": "20786", + "col562": "wsh8x", + "col563": "ogqn2", + "col564": "h6gh3", + "col565": "3yfj7", + "col566": "lf9j3", + "col567": "dr68s", + "col568": "3vduh", + "col569": "48hbb", + "col570": "evrtl", + "col571": "1ufj0", + "col572": "m4xv6", + "col573": "00crk", + "col574": "mrwpu", + "col575": "ebc3g", + "col576": "tkeud", + "col577": "hw9s5", + "col578": "qhgik", + "col579": "unzqp", + "col580": "l5i1i", + "col581": "c5xh6", + "col582": "1skw2", + "col583": "6b67f", + "col584": "nk2y2", + "col585": "p84a7", + "col586": "safkr", + "col587": "iwrbl", + "col588": "6ncmt", + "col589": "wxxzo", + "col590": "885jv", + "col591": "i3ub1", + "col592": "dzwq8", + "col593": "u0z6r", + "col594": "stfz4", + "col595": "awsiu", + "col596": "2e1vf", + "col597": "tu7fq", + "col598": "mqojk", + "col599": "kox4p", + "col600": "9umud", + "col601": "xyarl", + "col602": "qc4bd", + "col603": "2e2wh", + "col604": "86fx2", + "col605": "l95z7", + "col606": "jc0aa", + "col607": "b8ykb", + "col608": "8icvx", + "col609": "sfluq", + "col610": "r0rts", + "col611": "bsk4f", + "col612": "gycm9", + "col613": "u0254", + "col614": "cggvo", + "col615": "dsaoj", + "col616": "xinnu", + "col617": "f6b3e", + "col618": "jj9u0", + "col619": "7ykla", + "col620": "m0zl1", + "col621": "4ao71", + "col622": "0k3bu", + "col623": "weipk", + "col624": "3icr9", + "col625": "im9xn", + "col626": "7s3ya", + "col627": "cy413", + "col628": "m9wxy", + "col629": "u5ttm", + "col630": "8v02y", + "col631": "sv4ig", + "col632": "mok8h", + "col633": "verwb", + "col634": "0koag", + "col635": "mz9sb", + "col636": "c0bi2", + "col637": "j26jw", + "col638": "5irx7", + "col639": "rpjh3", + "col640": "v4ycd", + "col641": "6cqci", + "col642": "cn1mh", + "col643": "z81gk", + "col644": "j77r1", + "col645": "qi2h5", + "col646": "85ryh", + "col647": "fpsl9", + "col648": "em5bj", + "col649": "zahuo", + "col650": "gytfh", + "col651": "wzhew", + "col652": "zj5x6", + "col653": "j202s", + "col654": "oq11i", + "col655": "k2h69", + "col656": "9l389", + "col657": "9l89z", + "col658": "u0vvm", + "col659": "nfta0", + "col660": "148f2", + "col661": "yl4tv", + "col662": "cunbf", + "col663": "210ja", + "col664": "yjl77", + "col665": "w7d2i", + "col666": "cudul", + "col667": "6h885", + "col668": "n3ts8", + "col669": "ft2kg", + "col670": "izxcc", + "col671": "hnwqb", + "col672": "epbr6", + "col673": "ebzji", + "col674": "8li3a", + "col675": "2rql7", + "col676": "w9sl5", + "col677": "w6mvx", + "col678": "o9s9v", + "col679": "oav4j", + "col680": "vno4g", + "col681": "7xln8", + "col682": "lmxso", + "col683": "y0smf", + "col684": "5w92c", + "col685": "j4qw9", + "col686": "g38vf", + "col687": "8avds", + "col688": "5id5g", + "col689": "6grft", + "col690": "l9390", + "col691": "x4zkq", + "col692": "t8ebc", + "col693": "bryl0", + "col694": "pduej", + "col695": "tyqsi", + "col696": "16vx3", + "col697": "vvw8b", + "col698": "srdcb", + "col699": "oxdz8", + "col700": "ru6xc", + "col701": "gw2rs", + "col702": "c2jzc", + "col703": "s39p6", + "col704": "xj7ct", + "col705": "zo4me", + "col706": "b4sue", + "col707": "92yb8", + "col708": "l2p1y", + "col709": "892gt", + "col710": "100ty", + "col711": "lckhz", + "col712": "scuob", + "col713": "3d8w6", + "col714": "i4rki", + "col715": "syjnk", + "col716": "q956j", + "col717": "ps6sh", + "col718": "icxu0", + "col719": "294cx", + "col720": "yz0mk", + "col721": "noh3c", + "col722": "zgpq1", + "col723": "qruqh", + "col724": "e7cnx", + "col725": "0n3ed", + "col726": "laba1", + "col727": "nez7u", + "col728": "j4xvi", + "col729": "xfc6e", + "col730": "jtw37", + "col731": "lpdw8", + "col732": "bz03u", + "col733": "z78bg", + "col734": "g0mxl", + "col735": "9rufk", + "col736": "7xb6w", + "col737": "ow8gk", + "col738": "se691", + "col739": "dtmg7", + "col740": "8x3qk", + "col741": "t8so9", + "col742": "apx1g", + "col743": "gglk5", + "col744": "8cuz6", + "col745": "dxctz", + "col746": "uyjy0", + "col747": "g9qx8", + "col748": "4hy8p", + "col749": "zv7lf", + "col750": "qmss3", + "col751": "36o1e", + "col752": "eprr9", + "col753": "cm4wx", + "col754": "7tkte", + "col755": "27miy", + "col756": "6qn33", + "col757": "7k2ol", + "col758": "oxk03", + "col759": "u87fh", + "col760": "f7ru5", + "col761": "kgo02", + "col762": "6g1oo", + "col763": "rfy81", + "col764": "322a5", + "col765": "w3ayf", + "col766": "ob3uf", + "col767": "7s2xw", + "col768": "c0vpb", + "col769": "4i0u9", + "col770": "irbem", + "col771": "0r32t", + "col772": "i8lft", + "col773": "t0y1o", + "col774": "yem19", + "col775": "f6pj1", + "col776": "ekpjo", + "col777": "ushq7", + "col778": "4xf65", + "col779": "xu44o", + "col780": "51zez", + "col781": "uyaaz", + "col782": "erfhs", + "col783": "rzqai", + "col784": "u0ixs", + "col785": "wwqvf", + "col786": "jgp7i", + "col787": "oy9ck", + "col788": "izalq", + "col789": "s10it", + "col790": "ep0bw", + "col791": "i6nol", + "col792": "q8qgt", + "col793": "20y4g", + "col794": "d6m55", + "col795": "9c43p", + "col796": "gooq7", + "col797": "vyhq6", + "col798": "di6b6", + "col799": "p39ue", + "col800": "grptk", + "col801": "j3ekc", + "col802": "s38du", + "col803": "cwozl", + "col804": "xmg91", + "col805": "j3pve", + "col806": "kx4no", + "col807": "6uydj", + "col808": "wl4yf", + "col809": "cctvi", + "col810": "oir16", + "col811": "lfnpk", + "col812": "brqey", + "col813": "sbp94", + "col814": "phr9q", + "col815": "thkp3", + "col816": "31k6i", + "col817": "v7jv9", + "col818": "nfe5e", + "col819": "gp217", + "col820": "licc8", + "col821": "hm73i", + "col822": "tkvkn", + "col823": "7pw00", + "col824": "1wd7z", + "col825": "yc91j", + "col826": "tm1zj", + "col827": "slt1t", + "col828": "1o9i1", + "col829": "3mn5e", + "col830": "5mwg2", + "col831": "twdxo", + "col832": "gt27g", + "col833": "3xsve", + "col834": "0nsu9", + "col835": "iwsj5", + "col836": "d4spz", + "col837": "90hy8", + "col838": "q2241", + "col839": "0s05j", + "col840": "t28un", + "col841": "d1hr0", + "col842": "wknwh", + "col843": "wpck0", + "col844": "dgxz8", + "col845": "wj330", + "col846": "z84om", + "col847": "nvm6c", + "col848": "x61mi", + "col849": "pc79q", + "col850": "xb9ir", + "col851": "e74zx", + "col852": "52g1w", + "col853": "4cc47", + "col854": "iiqiy", + "col855": "0d49t", + "col856": "nl26u", + "col857": "lg66o", + "col858": "pi95r", + "col859": "82svr", + "col860": "tbetu", + "col861": "2l7en", + "col862": "4zzlg", + "col863": "qh1j6", + "col864": "76p1t", + "col865": "2xtmd", + "col866": "7ei5s", + "col867": "69q5w", + "col868": "jwh3q", + "col869": "i0dn8", + "col870": "w6v8z", + "col871": "rq8gm", + "col872": "urf85", + "col873": "eyida", + "col874": "xyu6n", + "col875": "y8bo1", + "col876": "q2uke", + "col877": "5scub", + "col878": "byvo3", + "col879": "e2cha", + "col880": "pj6ci", + "col881": "ppo3w", + "col882": "vuhj7", + "col883": "4evln", + "col884": "1e5ye", + "col885": "i5dkn", + "col886": "81r3v", + "col887": "a6cso", + "col888": "jb1f6", + "col889": "csaqm", + "col890": "nwqjl", + "col891": "kjp2i", + "col892": "lq1p9", + "col893": "ygzxl", + "col894": "onenb", + "col895": "2x7lb", + "col896": "e76sw", + "col897": "j6if8", + "col898": "grxel", + "col899": "4swdf", + "col900": "tf1tf", + "col901": "52pdv", + "col902": "03dau", + "col903": "db2ys", + "col904": "gu5b3", + "col905": "gejfi", + "col906": "a58t5", + "col907": "9kawm", + "col908": "0g525", + "col909": "8ule8", + "col910": "krqk4", + "col911": "c9mnf", + "col912": "bqy3a", + "col913": "cqdpl", + "col914": "mnnxk", + "col915": "os7nu", + "col916": "vsrwx", + "col917": "ncncy", + "col918": "8262o", + "col919": "8xczu", + "col920": "j58oc", + "col921": "pwx63", + "col922": "gsj0f", + "col923": "beysw", + "col924": "54wc6", + "col925": "qqssz", + "col926": "cvu5t", + "col927": "xmovb", + "col928": "j03fw", + "col929": "xfzwc", + "col930": "m0l78", + "col931": "6kmh7", + "col932": "y6e97", + "col933": "8e4m0", + "col934": "t79cy", + "col935": "r5w5c", + "col936": "h93uz", + "col937": "2p4zv", + "col938": "aqgfw", + "col939": "n21tw", + "col940": "b3efk", + "col941": "ry4d9", + "col942": "2x820", + "col943": "hmn0a", + "col944": "t853k", + "col945": "shlv7", + "col946": "rp0ha", + "col947": "iiyhr", + "col948": "k73c4", + "col949": "bneiw", + "col950": "s8oao", + "col951": "e8syx", + "col952": "nu2vz", + "col953": "20qjw", + "col954": "7l8kr", + "col955": "wb4vl", + "col956": "jjhnj", + "col957": "q23qr", + "col958": "8qey1", + "col959": "3um19", + "col960": "7d6ev", + "col961": "n0rq5", + "col962": "374el", + "col963": "2m0xp", + "col964": "9vv7h", + "col965": "da7hz", + "col966": "2drq5", + "col967": "be07g", + "col968": "7dxl9", + "col969": "gfwpd", + "col970": "dllmt", + "col971": "dcqik", + "col972": "i7850", + "col973": "3v54x", + "col974": "t0sl7", + "col975": "dp8z1", + "col976": "a85b0", + "col977": "j94fm", + "col978": "8myti", + "col979": "5zh50", + "col980": "s6ukv", + "col981": "6rmv9", + "col982": "55l1i", + "col983": "oan7m", + "col984": "xy6n9", + "col985": "g6bxj", + "col986": "zbt46", + "col987": "6sm0j", + "col988": "7jdgt", + "col989": "q3m9z", + "col990": "8vcbp", + "col991": "0t017", + "col992": "m5hzi", + "col993": "pe9yu", + "col994": "1opnl", + "col995": "a2lzz", + "col996": "idkyl", + "col997": "v2rbu", + "col998": "vj6hx", + "col999": "jcm3v" + }, + { + "name": "Hensley Harrell", + "gender": "male", + "col0": "oqhb2", + "col1": "e2la0", + "col2": "aka8d", + "col3": "nyxe4", + "col4": "fli43", + "col5": "kxce1", + "col6": "9xtk6", + "col7": "1lwue", + "col8": "jjn51", + "col9": "7d4dh", + "col10": "n8uha", + "col11": "jnmqy", + "col12": "jzh5w", + "col13": "eivcw", + "col14": "65lvw", + "col15": "6zuw5", + "col16": "2tu6z", + "col17": "db4z0", + "col18": "rmwu6", + "col19": "wt5r8", + "col20": "1zfze", + "col21": "0mies", + "col22": "wcrd7", + "col23": "q3oe9", + "col24": "7e54p", + "col25": "4itjt", + "col26": "jlgqw", + "col27": "y5f87", + "col28": "94cpp", + "col29": "u7cns", + "col30": "w4qvu", + "col31": "8mklo", + "col32": "28l28", + "col33": "xbh5g", + "col34": "f6vpm", + "col35": "p2ya7", + "col36": "0myce", + "col37": "a4qqj", + "col38": "m5hmv", + "col39": "xvurb", + "col40": "p0sb8", + "col41": "mq643", + "col42": "kepox", + "col43": "rttwu", + "col44": "jyz96", + "col45": "v9xy5", + "col46": "ymmrj", + "col47": "umr38", + "col48": "iz4l9", + "col49": "5dulc", + "col50": "3wu75", + "col51": "m6hhl", + "col52": "u174l", + "col53": "2j766", + "col54": "zebau", + "col55": "f9h2h", + "col56": "q5ssy", + "col57": "k3zqg", + "col58": "qvuxe", + "col59": "knswd", + "col60": "owau0", + "col61": "8hobh", + "col62": "jz567", + "col63": "psfpi", + "col64": "1giqn", + "col65": "i1jed", + "col66": "hb28y", + "col67": "yfi41", + "col68": "d6gfi", + "col69": "nhj0z", + "col70": "0oeju", + "col71": "wh0sl", + "col72": "ftfao", + "col73": "yu0u0", + "col74": "lcj9u", + "col75": "7obyd", + "col76": "65opi", + "col77": "98m22", + "col78": "n081z", + "col79": "0mn9e", + "col80": "iwv8n", + "col81": "d4f0n", + "col82": "idfit", + "col83": "cpyaz", + "col84": "23z70", + "col85": "x6c68", + "col86": "7egen", + "col87": "81hj4", + "col88": "cali8", + "col89": "6y8pf", + "col90": "ctud3", + "col91": "dwr3d", + "col92": "vmi2z", + "col93": "otb5t", + "col94": "keo2x", + "col95": "zxtk1", + "col96": "bhp8r", + "col97": "grm0q", + "col98": "h1did", + "col99": "vp36x", + "col100": "v7cqs", + "col101": "y0rlu", + "col102": "ohmz6", + "col103": "68i0s", + "col104": "rqv4l", + "col105": "x9wxt", + "col106": "af6xn", + "col107": "0mkya", + "col108": "lagig", + "col109": "locsp", + "col110": "7u41g", + "col111": "w5fxz", + "col112": "b9vlg", + "col113": "gpz97", + "col114": "vxddf", + "col115": "mdwge", + "col116": "w03rj", + "col117": "f76e4", + "col118": "mvtuq", + "col119": "dgjjk", + "col120": "oyo5n", + "col121": "n03bj", + "col122": "e9zu1", + "col123": "7m843", + "col124": "ijwwg", + "col125": "ezoqw", + "col126": "0qy30", + "col127": "1cwyx", + "col128": "1rv1m", + "col129": "kdhy1", + "col130": "fswyp", + "col131": "mhbx5", + "col132": "51gxa", + "col133": "ntpdo", + "col134": "9olrc", + "col135": "2cwq1", + "col136": "2dbfd", + "col137": "3ik0d", + "col138": "g1abl", + "col139": "pqwip", + "col140": "w08lz", + "col141": "pb1sj", + "col142": "bqxl7", + "col143": "8u9nc", + "col144": "zsdyo", + "col145": "ty3rt", + "col146": "0zzvd", + "col147": "xacap", + "col148": "b63ry", + "col149": "1yhzk", + "col150": "gs8tj", + "col151": "e3eg9", + "col152": "nw1by", + "col153": "w3qnt", + "col154": "1gdo8", + "col155": "qk3kq", + "col156": "0m9rk", + "col157": "t9ga4", + "col158": "zq2bh", + "col159": "gm4mq", + "col160": "7u23a", + "col161": "n7n9a", + "col162": "zexvj", + "col163": "7buqt", + "col164": "d6pxa", + "col165": "7fqg9", + "col166": "lz0zz", + "col167": "tbrxc", + "col168": "4mp05", + "col169": "vj1fj", + "col170": "r4m0p", + "col171": "axxpt", + "col172": "zpf5l", + "col173": "ydj4z", + "col174": "mjizv", + "col175": "ngf4s", + "col176": "gb7ob", + "col177": "6rd2j", + "col178": "hv2ee", + "col179": "nzad4", + "col180": "xd85t", + "col181": "w657p", + "col182": "pmviw", + "col183": "zsx87", + "col184": "7lya9", + "col185": "9leyk", + "col186": "4aa39", + "col187": "9tuez", + "col188": "7y3xz", + "col189": "9h2l6", + "col190": "75eif", + "col191": "r8om2", + "col192": "bi9t0", + "col193": "cewc1", + "col194": "hoxai", + "col195": "ia100", + "col196": "5h9rz", + "col197": "uo0aa", + "col198": "1vr7e", + "col199": "ifs0f", + "col200": "10e32", + "col201": "ov8ko", + "col202": "ijmaz", + "col203": "vo2yf", + "col204": "npc2p", + "col205": "xalj2", + "col206": "90bna", + "col207": "5t8bw", + "col208": "4biyt", + "col209": "vnm7w", + "col210": "sbpl9", + "col211": "xjoal", + "col212": "m4pi8", + "col213": "rdl02", + "col214": "iijm3", + "col215": "kaqmg", + "col216": "1mt63", + "col217": "9i7t1", + "col218": "o4c7n", + "col219": "b6r0k", + "col220": "44v5u", + "col221": "v356t", + "col222": "s8olv", + "col223": "4lw42", + "col224": "85hub", + "col225": "i3pg1", + "col226": "n8n8q", + "col227": "k8jii", + "col228": "uqces", + "col229": "7giau", + "col230": "eszwl", + "col231": "6hq2g", + "col232": "hkpgv", + "col233": "cn5la", + "col234": "5mvv7", + "col235": "n8sac", + "col236": "f0wes", + "col237": "7deg0", + "col238": "8h2re", + "col239": "ei9fy", + "col240": "xceyo", + "col241": "6gfg9", + "col242": "ptqc7", + "col243": "jpabl", + "col244": "da7a1", + "col245": "njxvs", + "col246": "3t6ml", + "col247": "3rp4e", + "col248": "ccfhr", + "col249": "nc587", + "col250": "67b4a", + "col251": "15ytj", + "col252": "o02gq", + "col253": "e55ec", + "col254": "1oqn5", + "col255": "11pwy", + "col256": "w68te", + "col257": "evw6m", + "col258": "kg418", + "col259": "das4v", + "col260": "eb0hh", + "col261": "kcxze", + "col262": "b6qai", + "col263": "bheuw", + "col264": "8bge5", + "col265": "ovt3m", + "col266": "g57ww", + "col267": "kq880", + "col268": "2f4y0", + "col269": "l71ae", + "col270": "64sl4", + "col271": "grjyp", + "col272": "fjmyp", + "col273": "er7vm", + "col274": "cvwf9", + "col275": "gvcfv", + "col276": "y5c1s", + "col277": "u68wt", + "col278": "wxb0q", + "col279": "a1xng", + "col280": "2a1n6", + "col281": "5g0w2", + "col282": "uxf9x", + "col283": "7q07s", + "col284": "8xouc", + "col285": "76jfw", + "col286": "x9xgx", + "col287": "4or41", + "col288": "z1xnj", + "col289": "vf77n", + "col290": "ytb9e", + "col291": "vvfht", + "col292": "glx8y", + "col293": "gw83k", + "col294": "jqzo7", + "col295": "f1tep", + "col296": "p81ze", + "col297": "3bzjq", + "col298": "lzcd7", + "col299": "19aog", + "col300": "1s6gs", + "col301": "l0yq4", + "col302": "actav", + "col303": "t8mcm", + "col304": "xsuiq", + "col305": "895ig", + "col306": "iqkzn", + "col307": "ts98t", + "col308": "izgx1", + "col309": "lr2l9", + "col310": "vx2d5", + "col311": "zno73", + "col312": "5ur5j", + "col313": "06ctc", + "col314": "m8b2h", + "col315": "0j67m", + "col316": "b1t0e", + "col317": "o2gz7", + "col318": "wjsry", + "col319": "l3nos", + "col320": "2n29x", + "col321": "zccja", + "col322": "q6qn2", + "col323": "ikmy6", + "col324": "liver", + "col325": "8omz4", + "col326": "oaj5y", + "col327": "5ou9m", + "col328": "eqauc", + "col329": "rb74x", + "col330": "8btw2", + "col331": "tz32y", + "col332": "75er9", + "col333": "zgtk6", + "col334": "cwekx", + "col335": "vmhob", + "col336": "8lv3v", + "col337": "xd4ko", + "col338": "ymzym", + "col339": "0ws9t", + "col340": "dfqye", + "col341": "nd98u", + "col342": "sm7oj", + "col343": "uq2it", + "col344": "bmkqo", + "col345": "qjdpf", + "col346": "7ziuc", + "col347": "gudcz", + "col348": "8xr1f", + "col349": "wb4ny", + "col350": "tyd39", + "col351": "4yaip", + "col352": "otrne", + "col353": "ru5c9", + "col354": "wsc9i", + "col355": "pvilu", + "col356": "hvvqu", + "col357": "os1rt", + "col358": "73zn8", + "col359": "0brvy", + "col360": "z9bk0", + "col361": "f70v9", + "col362": "fho6t", + "col363": "nkkax", + "col364": "j73t3", + "col365": "e32k7", + "col366": "6bhup", + "col367": "sj4vd", + "col368": "kn3ra", + "col369": "izbdx", + "col370": "ifhm4", + "col371": "p6cv3", + "col372": "2izg2", + "col373": "kpzgx", + "col374": "8r8ie", + "col375": "jjqtp", + "col376": "l1a4e", + "col377": "q0v7y", + "col378": "vfrfh", + "col379": "rv0c2", + "col380": "95k0b", + "col381": "5alw4", + "col382": "vxxc8", + "col383": "x75fz", + "col384": "ipr1v", + "col385": "spzzb", + "col386": "z8obo", + "col387": "pwqgu", + "col388": "qe7t1", + "col389": "wopui", + "col390": "659bm", + "col391": "geisi", + "col392": "umaid", + "col393": "41p81", + "col394": "rw7f4", + "col395": "buo84", + "col396": "ir6iu", + "col397": "rzr5p", + "col398": "2nnc8", + "col399": "4cv77", + "col400": "3di6e", + "col401": "kik77", + "col402": "7azsh", + "col403": "ogw8p", + "col404": "sev24", + "col405": "cjsol", + "col406": "55r4s", + "col407": "qoisc", + "col408": "qhfll", + "col409": "303ms", + "col410": "u65jc", + "col411": "460p1", + "col412": "9xwlx", + "col413": "b4gc5", + "col414": "xuni7", + "col415": "aqrax", + "col416": "reg5w", + "col417": "mhjem", + "col418": "5o4uh", + "col419": "6zexs", + "col420": "ba2nu", + "col421": "17ne8", + "col422": "179yv", + "col423": "q6t0p", + "col424": "35z9i", + "col425": "ztkf7", + "col426": "m05mk", + "col427": "kua01", + "col428": "oty7n", + "col429": "x1h7f", + "col430": "uzd7p", + "col431": "h2iha", + "col432": "e8qep", + "col433": "40tuc", + "col434": "0975v", + "col435": "9ktx7", + "col436": "mlgby", + "col437": "qla2i", + "col438": "mqfu0", + "col439": "6gu4p", + "col440": "53z0s", + "col441": "qm5gk", + "col442": "2f7vw", + "col443": "lyv9k", + "col444": "m4zmv", + "col445": "x82cs", + "col446": "ra4j0", + "col447": "tvvcw", + "col448": "6c0qt", + "col449": "kz0pn", + "col450": "7goll", + "col451": "fd80l", + "col452": "xg9zv", + "col453": "7hou0", + "col454": "idbur", + "col455": "adldt", + "col456": "qh739", + "col457": "1xid6", + "col458": "842ol", + "col459": "23h7b", + "col460": "9hw8r", + "col461": "g1ld6", + "col462": "2zx5p", + "col463": "nz5tn", + "col464": "p2mly", + "col465": "jz5qq", + "col466": "hv6lk", + "col467": "bqn5t", + "col468": "k9y95", + "col469": "z97w8", + "col470": "e3kk8", + "col471": "er9yf", + "col472": "hi25b", + "col473": "aaqwc", + "col474": "ptw7o", + "col475": "y3d8n", + "col476": "ye7r2", + "col477": "8e4au", + "col478": "icrq9", + "col479": "1ndka", + "col480": "r42zk", + "col481": "66jim", + "col482": "p6mok", + "col483": "llnoi", + "col484": "td6gs", + "col485": "am7f0", + "col486": "we8td", + "col487": "9sd4q", + "col488": "gg97h", + "col489": "mh5nz", + "col490": "cufdd", + "col491": "nu94r", + "col492": "4wuno", + "col493": "cvs3v", + "col494": "9z5ft", + "col495": "2y36j", + "col496": "zosmq", + "col497": "3ykz1", + "col498": "ouivd", + "col499": "pjeny", + "col500": "cp7ff", + "col501": "spr2e", + "col502": "6200c", + "col503": "ckmcj", + "col504": "jhno6", + "col505": "kjjjh", + "col506": "x4t3h", + "col507": "ap3qi", + "col508": "wzc1x", + "col509": "212t7", + "col510": "vrfms", + "col511": "5wc0v", + "col512": "a3pjo", + "col513": "pqhyt", + "col514": "zk7bh", + "col515": "914nu", + "col516": "1wuxr", + "col517": "10vt7", + "col518": "6njyz", + "col519": "4eoce", + "col520": "1zq3k", + "col521": "hpd2i", + "col522": "z9923", + "col523": "4zh68", + "col524": "tzbgz", + "col525": "dnhhd", + "col526": "h52zb", + "col527": "nbnyw", + "col528": "xowfi", + "col529": "lqge6", + "col530": "srxx5", + "col531": "6r6y4", + "col532": "301k9", + "col533": "czp9t", + "col534": "bvoub", + "col535": "miqgi", + "col536": "z4r6w", + "col537": "u4yij", + "col538": "abh7t", + "col539": "fnhzj", + "col540": "fe80s", + "col541": "1rohi", + "col542": "aywol", + "col543": "bgmcw", + "col544": "ht2jb", + "col545": "9g7j7", + "col546": "2r3ie", + "col547": "cpx88", + "col548": "7sia3", + "col549": "xp5ud", + "col550": "jtgos", + "col551": "4ela4", + "col552": "rh3fz", + "col553": "ymvhh", + "col554": "ly43c", + "col555": "4o2lz", + "col556": "m555m", + "col557": "sb05g", + "col558": "8lgkc", + "col559": "f28sn", + "col560": "3hlmr", + "col561": "ktnax", + "col562": "wi14a", + "col563": "0vsdn", + "col564": "wiu7y", + "col565": "ddkxo", + "col566": "5j3qn", + "col567": "grkxo", + "col568": "0bhaq", + "col569": "x0yyw", + "col570": "k6qsm", + "col571": "k19eh", + "col572": "5ii8v", + "col573": "2zbv9", + "col574": "af648", + "col575": "uosvg", + "col576": "697lg", + "col577": "2cvp6", + "col578": "jui25", + "col579": "hrwt9", + "col580": "5ls0u", + "col581": "2kf7c", + "col582": "5fh6v", + "col583": "cuwhp", + "col584": "i11fc", + "col585": "bi7xq", + "col586": "xar7v", + "col587": "gf3pm", + "col588": "7sgyl", + "col589": "s2iau", + "col590": "df2l6", + "col591": "iofd1", + "col592": "to05b", + "col593": "pw2e4", + "col594": "u582i", + "col595": "z9066", + "col596": "zdope", + "col597": "r6jd1", + "col598": "8nf5k", + "col599": "ula8u", + "col600": "40515", + "col601": "ed5bh", + "col602": "bsqlr", + "col603": "gph4k", + "col604": "n3fv9", + "col605": "dtv7j", + "col606": "e09qf", + "col607": "yj3i8", + "col608": "84quk", + "col609": "xhile", + "col610": "4wjo6", + "col611": "rfxj3", + "col612": "l282w", + "col613": "6whcb", + "col614": "lx96i", + "col615": "krr9a", + "col616": "py8w0", + "col617": "5rq5s", + "col618": "4ovon", + "col619": "82ylt", + "col620": "8d1as", + "col621": "wfsig", + "col622": "03gl8", + "col623": "mkv1v", + "col624": "sdtna", + "col625": "bmnmb", + "col626": "ln2l3", + "col627": "5po70", + "col628": "l4yqm", + "col629": "74t5u", + "col630": "regas", + "col631": "iyz2p", + "col632": "jmx8y", + "col633": "cf3bt", + "col634": "zsdt5", + "col635": "avc3q", + "col636": "1mdsf", + "col637": "16kge", + "col638": "4vfvk", + "col639": "js0se", + "col640": "yoanl", + "col641": "j4w5y", + "col642": "twnsf", + "col643": "kh38j", + "col644": "wxnde", + "col645": "309xg", + "col646": "gtexk", + "col647": "tqocj", + "col648": "1js30", + "col649": "fzc5a", + "col650": "5zaip", + "col651": "9e2q6", + "col652": "nuxwq", + "col653": "dp9ns", + "col654": "2wcwv", + "col655": "rg8of", + "col656": "v7tpi", + "col657": "46co5", + "col658": "5w2xy", + "col659": "7iwxw", + "col660": "q1gbb", + "col661": "5o0y7", + "col662": "m9afk", + "col663": "kw0p2", + "col664": "vo21m", + "col665": "ebjan", + "col666": "0yytp", + "col667": "3fxvs", + "col668": "rozy8", + "col669": "jxrqc", + "col670": "k18cw", + "col671": "hzo8d", + "col672": "dwre3", + "col673": "ah7cp", + "col674": "2o644", + "col675": "fzd7u", + "col676": "3s7su", + "col677": "6a84l", + "col678": "2ryyb", + "col679": "325vp", + "col680": "7jxg0", + "col681": "5kg00", + "col682": "8olz9", + "col683": "zrma1", + "col684": "oeb8z", + "col685": "1hoct", + "col686": "vd8q8", + "col687": "lakdt", + "col688": "5xaxo", + "col689": "f3u2l", + "col690": "m5jv3", + "col691": "0wu81", + "col692": "j4hpo", + "col693": "ou11a", + "col694": "t6np9", + "col695": "l4kxs", + "col696": "xxz8z", + "col697": "cvlms", + "col698": "79dov", + "col699": "oqorz", + "col700": "i4u6p", + "col701": "y1ty2", + "col702": "5b8wp", + "col703": "xkvmg", + "col704": "vxnsq", + "col705": "l3r6l", + "col706": "6mcat", + "col707": "s57x3", + "col708": "7pcwk", + "col709": "dgpd0", + "col710": "d3ue7", + "col711": "68hf0", + "col712": "4hwia", + "col713": "xxs6j", + "col714": "0t38c", + "col715": "us7gk", + "col716": "72m7h", + "col717": "6tehf", + "col718": "u9cbi", + "col719": "gcjy9", + "col720": "x6gze", + "col721": "4m5cn", + "col722": "ilqfx", + "col723": "z3xim", + "col724": "di3fh", + "col725": "ltfaf", + "col726": "ifoqf", + "col727": "7frbz", + "col728": "xh19t", + "col729": "nc3ru", + "col730": "khof6", + "col731": "o5nfc", + "col732": "xr574", + "col733": "6qb10", + "col734": "4rpia", + "col735": "68v6v", + "col736": "mxbkl", + "col737": "csyai", + "col738": "yo4gz", + "col739": "jsnbw", + "col740": "1oh70", + "col741": "12rj4", + "col742": "5qdet", + "col743": "grd5q", + "col744": "d0plg", + "col745": "dllh5", + "col746": "ewq9c", + "col747": "xbkfo", + "col748": "4fvfs", + "col749": "32ara", + "col750": "w8p5a", + "col751": "f6azm", + "col752": "397si", + "col753": "xtx06", + "col754": "26buc", + "col755": "pgvu9", + "col756": "50dcb", + "col757": "523es", + "col758": "3m03g", + "col759": "ygwf6", + "col760": "4jlm3", + "col761": "si3x6", + "col762": "x62zi", + "col763": "9u2f0", + "col764": "uylwd", + "col765": "oasj1", + "col766": "axqo9", + "col767": "1iull", + "col768": "kdsrq", + "col769": "ha2ho", + "col770": "yov7j", + "col771": "gie6s", + "col772": "hk9c7", + "col773": "dzjoq", + "col774": "vpfl9", + "col775": "fz5i4", + "col776": "6ydld", + "col777": "8qpde", + "col778": "z7ay7", + "col779": "6pyjt", + "col780": "kf33k", + "col781": "n6cy6", + "col782": "vyt94", + "col783": "ten7s", + "col784": "5b7t7", + "col785": "r9irn", + "col786": "83svi", + "col787": "hnj2q", + "col788": "tf7tk", + "col789": "6x7eu", + "col790": "76cq4", + "col791": "rsi66", + "col792": "05loj", + "col793": "0981n", + "col794": "l1mcm", + "col795": "gazkr", + "col796": "c2ivb", + "col797": "fdplf", + "col798": "xoekt", + "col799": "vhel6", + "col800": "6nc4z", + "col801": "xxv38", + "col802": "0jf91", + "col803": "ne07q", + "col804": "hzao0", + "col805": "ciuxm", + "col806": "q31g3", + "col807": "9oequ", + "col808": "s6gty", + "col809": "sxi5k", + "col810": "62sjw", + "col811": "83n8a", + "col812": "5ydfx", + "col813": "jciw6", + "col814": "kzctx", + "col815": "moa30", + "col816": "e901i", + "col817": "r7hz8", + "col818": "865qe", + "col819": "86yzq", + "col820": "pyi92", + "col821": "3t4ta", + "col822": "0aev2", + "col823": "zs05a", + "col824": "mqhl9", + "col825": "1hzm3", + "col826": "vkxjl", + "col827": "bzfa9", + "col828": "mph82", + "col829": "h22bt", + "col830": "m5vsp", + "col831": "kki0s", + "col832": "96eha", + "col833": "xv1hq", + "col834": "fwb96", + "col835": "tqilr", + "col836": "313h9", + "col837": "lfjy4", + "col838": "z49pf", + "col839": "7fujp", + "col840": "3rkxh", + "col841": "bptj7", + "col842": "6orff", + "col843": "f7p9m", + "col844": "3uzah", + "col845": "4tz5x", + "col846": "mu092", + "col847": "d2chp", + "col848": "9ig1j", + "col849": "w8dcv", + "col850": "b9yyo", + "col851": "7haak", + "col852": "ztv79", + "col853": "nvso3", + "col854": "zr096", + "col855": "qetu2", + "col856": "hkv6c", + "col857": "dyat8", + "col858": "dujst", + "col859": "g6x6n", + "col860": "pabhf", + "col861": "qxd9p", + "col862": "6dsau", + "col863": "3gkue", + "col864": "ahere", + "col865": "824qr", + "col866": "cv8s0", + "col867": "fag4s", + "col868": "2pciz", + "col869": "k4p22", + "col870": "bnv3u", + "col871": "h4kbv", + "col872": "69fiq", + "col873": "8ipct", + "col874": "mp8lp", + "col875": "tlpfm", + "col876": "jnurh", + "col877": "o66ht", + "col878": "e14dk", + "col879": "g3a4m", + "col880": "jfear", + "col881": "o7mnr", + "col882": "bnqf8", + "col883": "sebcu", + "col884": "ng82c", + "col885": "kjqji", + "col886": "fpiz0", + "col887": "d59b1", + "col888": "728zh", + "col889": "iscb0", + "col890": "9dxns", + "col891": "d8p8y", + "col892": "dtbus", + "col893": "kpriu", + "col894": "fdm95", + "col895": "gvp3k", + "col896": "phd6x", + "col897": "x5afg", + "col898": "ofibd", + "col899": "120ml", + "col900": "vnwjy", + "col901": "5iauc", + "col902": "duj8b", + "col903": "iut9m", + "col904": "tftch", + "col905": "1yck4", + "col906": "yiphd", + "col907": "k0nf7", + "col908": "jtz4a", + "col909": "ynwhz", + "col910": "tdn4e", + "col911": "y56jy", + "col912": "ct91i", + "col913": "98cax", + "col914": "nbbj4", + "col915": "xbg0w", + "col916": "slg4a", + "col917": "4jdij", + "col918": "8iwfo", + "col919": "omvha", + "col920": "a5vyc", + "col921": "rhxmq", + "col922": "oya6p", + "col923": "sqx5j", + "col924": "uppe3", + "col925": "3gg5h", + "col926": "dzgza", + "col927": "ilre2", + "col928": "98ytv", + "col929": "yoigu", + "col930": "im3fl", + "col931": "5nrpm", + "col932": "in2sg", + "col933": "xykh2", + "col934": "mt12r", + "col935": "sblqy", + "col936": "5zgkl", + "col937": "g43rd", + "col938": "gswnw", + "col939": "wt8ea", + "col940": "3435l", + "col941": "f2j59", + "col942": "0zx37", + "col943": "wijwp", + "col944": "6ucr5", + "col945": "cnjhh", + "col946": "o9hds", + "col947": "yvjru", + "col948": "x2p71", + "col949": "5lubw", + "col950": "sjpnj", + "col951": "k5pdu", + "col952": "ybhfa", + "col953": "38h0a", + "col954": "k8v8v", + "col955": "7ebav", + "col956": "v9o24", + "col957": "m1sc1", + "col958": "tpss0", + "col959": "9a01m", + "col960": "x5k7s", + "col961": "turb5", + "col962": "qvr86", + "col963": "mlsv9", + "col964": "g64bp", + "col965": "tqymr", + "col966": "7xn36", + "col967": "xnjbj", + "col968": "h8n8e", + "col969": "h8u2h", + "col970": "shznj", + "col971": "chifo", + "col972": "qb20z", + "col973": "rv0zx", + "col974": "bvi52", + "col975": "t9rfb", + "col976": "gyf8l", + "col977": "dxkpo", + "col978": "ur2cb", + "col979": "9kc1y", + "col980": "q9qhu", + "col981": "00l8l", + "col982": "lbmlj", + "col983": "bribo", + "col984": "xembl", + "col985": "lfr99", + "col986": "iebty", + "col987": "w83tf", + "col988": "76v23", + "col989": "sro4z", + "col990": "3nujz", + "col991": "niyuf", + "col992": "ptwyf", + "col993": "9b6ow", + "col994": "rcjqq", + "col995": "aebcf", + "col996": "hsdd4", + "col997": "fbqiy", + "col998": "b17qt", + "col999": "6o119" + }, + { + "name": "Merle Henderson", + "gender": "female", + "col0": "tldyb", + "col1": "3lxna", + "col2": "9k2rn", + "col3": "4lwie", + "col4": "hzy3c", + "col5": "g66bm", + "col6": "6niln", + "col7": "r2d96", + "col8": "3bhjc", + "col9": "vy5l3", + "col10": "qnz4n", + "col11": "nbyza", + "col12": "qzm78", + "col13": "vmek4", + "col14": "e9ti0", + "col15": "z7i2o", + "col16": "d6num", + "col17": "7ok3s", + "col18": "8t1iz", + "col19": "6r5uk", + "col20": "chlyk", + "col21": "5ym7q", + "col22": "x0ud8", + "col23": "q0643", + "col24": "xf98c", + "col25": "2jdcv", + "col26": "v864e", + "col27": "hzcwe", + "col28": "xx2z5", + "col29": "y6zh8", + "col30": "41ua4", + "col31": "w694t", + "col32": "i8fqs", + "col33": "9esg3", + "col34": "v52uo", + "col35": "5ehrz", + "col36": "aeaw3", + "col37": "e6ei7", + "col38": "4unx0", + "col39": "1yz0z", + "col40": "wecid", + "col41": "6icdf", + "col42": "h6d28", + "col43": "ps3ci", + "col44": "rlpnb", + "col45": "ifaj1", + "col46": "br1k6", + "col47": "q4orb", + "col48": "s05p5", + "col49": "rz5ci", + "col50": "plfpz", + "col51": "az9nk", + "col52": "8qukq", + "col53": "3lvou", + "col54": "h5rr1", + "col55": "1sxo1", + "col56": "5vci2", + "col57": "symy7", + "col58": "g2wb9", + "col59": "vb36y", + "col60": "b97ac", + "col61": "tbhr1", + "col62": "njtfl", + "col63": "cizq2", + "col64": "fv2wb", + "col65": "ih0e6", + "col66": "rsieu", + "col67": "atzv9", + "col68": "vt9me", + "col69": "kwu3d", + "col70": "8uw83", + "col71": "x1eml", + "col72": "bgyex", + "col73": "zjlm5", + "col74": "zg9w5", + "col75": "k8f14", + "col76": "hfu77", + "col77": "g5lmu", + "col78": "eb853", + "col79": "g1hxj", + "col80": "2p6up", + "col81": "20109", + "col82": "st82y", + "col83": "fql6u", + "col84": "kv1dd", + "col85": "0zkh5", + "col86": "ie9kp", + "col87": "hcpam", + "col88": "3nkcv", + "col89": "qbpzh", + "col90": "j85xk", + "col91": "qx8ra", + "col92": "vivpr", + "col93": "p1j7w", + "col94": "zyyub", + "col95": "3wszx", + "col96": "33p68", + "col97": "waqbr", + "col98": "8fy9x", + "col99": "07sdm", + "col100": "d47sn", + "col101": "88it2", + "col102": "sb8wd", + "col103": "op4bw", + "col104": "fi2if", + "col105": "ii1u1", + "col106": "joqzx", + "col107": "i6ppq", + "col108": "gq610", + "col109": "09pe7", + "col110": "9judt", + "col111": "itt7k", + "col112": "4ebp6", + "col113": "833ky", + "col114": "tzwzf", + "col115": "k479e", + "col116": "bxn62", + "col117": "cqu1f", + "col118": "eznr8", + "col119": "lpmxr", + "col120": "4n2nh", + "col121": "wlbei", + "col122": "u2r12", + "col123": "hbdpy", + "col124": "xg0ti", + "col125": "t2otf", + "col126": "ogvaa", + "col127": "vz0vp", + "col128": "jmt0b", + "col129": "1usi8", + "col130": "j4bmo", + "col131": "6ra6c", + "col132": "bzj5o", + "col133": "j2gq8", + "col134": "72714", + "col135": "gadz8", + "col136": "xjsdc", + "col137": "zgyng", + "col138": "iiusb", + "col139": "fpd5z", + "col140": "k7ehf", + "col141": "tz3t8", + "col142": "ujbyd", + "col143": "0rnmz", + "col144": "4jesx", + "col145": "sdcfn", + "col146": "q3cvt", + "col147": "fn59e", + "col148": "z1hdp", + "col149": "728ox", + "col150": "jvhgj", + "col151": "hu7ka", + "col152": "2x71q", + "col153": "9sglq", + "col154": "ty8og", + "col155": "xwgld", + "col156": "gvgli", + "col157": "o301o", + "col158": "c66mr", + "col159": "f28zy", + "col160": "wyiqs", + "col161": "r2xyi", + "col162": "jmr0f", + "col163": "ttzju", + "col164": "xj28i", + "col165": "wvghz", + "col166": "oe63d", + "col167": "dbofk", + "col168": "0qpgo", + "col169": "0zmbx", + "col170": "qz44x", + "col171": "qg60l", + "col172": "nqaio", + "col173": "m6ykc", + "col174": "10dw8", + "col175": "3bvpw", + "col176": "tigba", + "col177": "y4f8w", + "col178": "bhq4a", + "col179": "2ue6a", + "col180": "a4jip", + "col181": "egqh6", + "col182": "vyna3", + "col183": "b5bdg", + "col184": "3m136", + "col185": "dkzx6", + "col186": "wna9l", + "col187": "sc331", + "col188": "yi1qj", + "col189": "xjn7d", + "col190": "19lpp", + "col191": "qmmwh", + "col192": "huwi0", + "col193": "8o5pr", + "col194": "8ejz7", + "col195": "5z1yt", + "col196": "xc3gf", + "col197": "3ecnm", + "col198": "zqpga", + "col199": "38ag4", + "col200": "2azfg", + "col201": "re01g", + "col202": "xqn3g", + "col203": "m3tyk", + "col204": "mslkj", + "col205": "u8527", + "col206": "hzwbg", + "col207": "gnmzl", + "col208": "ervx9", + "col209": "7w1rq", + "col210": "kz3q5", + "col211": "4ipp8", + "col212": "a28rx", + "col213": "7l0nq", + "col214": "m3lqh", + "col215": "n4ht0", + "col216": "hd761", + "col217": "t0b2c", + "col218": "8hg9d", + "col219": "q8jmi", + "col220": "gzecs", + "col221": "sj99w", + "col222": "guzr2", + "col223": "a898l", + "col224": "zynzl", + "col225": "0qva2", + "col226": "t0mzc", + "col227": "rzbwd", + "col228": "usw33", + "col229": "tf2uk", + "col230": "ovfcy", + "col231": "r8lxj", + "col232": "kozny", + "col233": "cqueb", + "col234": "mg972", + "col235": "jpz3u", + "col236": "dp54t", + "col237": "g0zlx", + "col238": "12t2k", + "col239": "wbfui", + "col240": "3cgsu", + "col241": "cv16u", + "col242": "5o983", + "col243": "sixo6", + "col244": "4mskg", + "col245": "1yq6z", + "col246": "jvtlg", + "col247": "3ohn1", + "col248": "fqu5o", + "col249": "adqs1", + "col250": "o0a19", + "col251": "87xmn", + "col252": "i7vfl", + "col253": "w9h58", + "col254": "kraam", + "col255": "tw4k0", + "col256": "jh4a3", + "col257": "xyh4e", + "col258": "gdlsw", + "col259": "q7fd0", + "col260": "zl2r2", + "col261": "yqsse", + "col262": "0omcc", + "col263": "rzltg", + "col264": "6vszu", + "col265": "6kmzp", + "col266": "90j65", + "col267": "dbkq5", + "col268": "d8vzc", + "col269": "9spgb", + "col270": "ltthq", + "col271": "d29ai", + "col272": "v1kyz", + "col273": "gc7g6", + "col274": "rp9tr", + "col275": "k277t", + "col276": "2zc0q", + "col277": "9gj9b", + "col278": "cpln6", + "col279": "bhrrn", + "col280": "jgi77", + "col281": "0n4tu", + "col282": "jdhi7", + "col283": "xb26v", + "col284": "6qqxo", + "col285": "9h0md", + "col286": "hpxbg", + "col287": "rvypp", + "col288": "psq1h", + "col289": "mrz5r", + "col290": "qiuog", + "col291": "pkh97", + "col292": "k7xx6", + "col293": "87p6r", + "col294": "4plpk", + "col295": "u72vj", + "col296": "jbheg", + "col297": "ppgql", + "col298": "a4tyj", + "col299": "mdw0t", + "col300": "zyqqj", + "col301": "5rywn", + "col302": "9walr", + "col303": "qith5", + "col304": "ohizb", + "col305": "k2jq3", + "col306": "3mr78", + "col307": "6iqft", + "col308": "8yrxh", + "col309": "be0rf", + "col310": "j9bk6", + "col311": "qfngc", + "col312": "ayjr3", + "col313": "a4twk", + "col314": "y76p9", + "col315": "sb14j", + "col316": "9g2mp", + "col317": "mgzfp", + "col318": "cmne0", + "col319": "t0427", + "col320": "pp04z", + "col321": "sy7w0", + "col322": "brc6v", + "col323": "x4az2", + "col324": "k7mro", + "col325": "it78b", + "col326": "coa4c", + "col327": "5i5jg", + "col328": "092we", + "col329": "gqu2q", + "col330": "uzf54", + "col331": "bnoks", + "col332": "f897a", + "col333": "46qwi", + "col334": "3r3qe", + "col335": "je8s6", + "col336": "3okgu", + "col337": "4patx", + "col338": "rdvcp", + "col339": "7o920", + "col340": "9krzz", + "col341": "r671j", + "col342": "zwu1s", + "col343": "qeeog", + "col344": "pcdx0", + "col345": "touh5", + "col346": "hbx3g", + "col347": "6bcxa", + "col348": "k9kda", + "col349": "231t8", + "col350": "vidbx", + "col351": "lomss", + "col352": "radst", + "col353": "n724p", + "col354": "k6i4b", + "col355": "txphn", + "col356": "hs68e", + "col357": "ya8h3", + "col358": "pq90c", + "col359": "79n30", + "col360": "4rxyf", + "col361": "xwjbe", + "col362": "j0vf4", + "col363": "y0awn", + "col364": "togec", + "col365": "e1uma", + "col366": "ywn4a", + "col367": "nv5su", + "col368": "8687t", + "col369": "ixuzw", + "col370": "zp0u7", + "col371": "yabcj", + "col372": "bf6bg", + "col373": "4wdjl", + "col374": "s1l1j", + "col375": "gddbb", + "col376": "4kseq", + "col377": "va5k2", + "col378": "k7cqh", + "col379": "983k1", + "col380": "hxwdx", + "col381": "hjl5v", + "col382": "x3t4v", + "col383": "kdhrd", + "col384": "penmx", + "col385": "eexgr", + "col386": "07ki7", + "col387": "rfawy", + "col388": "wl3cf", + "col389": "dxrha", + "col390": "6jl0o", + "col391": "yws5d", + "col392": "94nt7", + "col393": "3hof1", + "col394": "89h1s", + "col395": "yezee", + "col396": "bpqkk", + "col397": "2oren", + "col398": "lxd67", + "col399": "6ybfj", + "col400": "tpdwy", + "col401": "59b3r", + "col402": "an1ip", + "col403": "f967a", + "col404": "p8nkl", + "col405": "6hck4", + "col406": "3vs0l", + "col407": "5e6tj", + "col408": "0drht", + "col409": "h4qc5", + "col410": "iy3hu", + "col411": "x2t9s", + "col412": "rwf8b", + "col413": "3xe7a", + "col414": "1fogu", + "col415": "lhwqp", + "col416": "04y70", + "col417": "r9btr", + "col418": "wpw92", + "col419": "mly5j", + "col420": "3ii2a", + "col421": "94rx1", + "col422": "iymx5", + "col423": "vfhnk", + "col424": "igilw", + "col425": "0khgt", + "col426": "w0fi6", + "col427": "0mi6y", + "col428": "uoq8l", + "col429": "9esuw", + "col430": "l740f", + "col431": "jrfhv", + "col432": "b1ibd", + "col433": "mv5n5", + "col434": "520ve", + "col435": "1xigd", + "col436": "9o0wb", + "col437": "i98s1", + "col438": "q7hmr", + "col439": "k6lhd", + "col440": "wf01g", + "col441": "vdk0y", + "col442": "aio6q", + "col443": "hs4vw", + "col444": "vdotk", + "col445": "i47l6", + "col446": "06qjz", + "col447": "8rel4", + "col448": "yo4rq", + "col449": "a9ts4", + "col450": "6rtxs", + "col451": "2kpez", + "col452": "2a5hu", + "col453": "z45de", + "col454": "iw78j", + "col455": "2y658", + "col456": "ivgb6", + "col457": "v4u9f", + "col458": "3469d", + "col459": "dqfny", + "col460": "se5z9", + "col461": "s9xxj", + "col462": "ata4b", + "col463": "752fm", + "col464": "gwddm", + "col465": "ei66f", + "col466": "izvka", + "col467": "9rvc0", + "col468": "w7hrn", + "col469": "wo9ip", + "col470": "bc1rf", + "col471": "u3qbm", + "col472": "yd6dl", + "col473": "uc8gg", + "col474": "b0q70", + "col475": "mth4f", + "col476": "atwgh", + "col477": "nrkt9", + "col478": "h9mpe", + "col479": "uszle", + "col480": "c5db4", + "col481": "rcu8e", + "col482": "06rpz", + "col483": "ldjsb", + "col484": "vwetn", + "col485": "i9uin", + "col486": "wzmu7", + "col487": "gldhq", + "col488": "5ptms", + "col489": "hzrik", + "col490": "y5551", + "col491": "4maql", + "col492": "ujt8s", + "col493": "2ocj8", + "col494": "3x0zr", + "col495": "oped8", + "col496": "ka751", + "col497": "ctcli", + "col498": "jjzr6", + "col499": "jkahb", + "col500": "uikac", + "col501": "hgaut", + "col502": "nuns7", + "col503": "9du9k", + "col504": "sxqnn", + "col505": "ib3xq", + "col506": "qkmv1", + "col507": "1r1a5", + "col508": "zbc8r", + "col509": "5h0s4", + "col510": "xvekp", + "col511": "d17k1", + "col512": "mbwzx", + "col513": "2hz0g", + "col514": "hw7dw", + "col515": "nyh5y", + "col516": "ctbte", + "col517": "i2h0l", + "col518": "t9gph", + "col519": "pj78v", + "col520": "yywk9", + "col521": "teapt", + "col522": "2ynl5", + "col523": "vned8", + "col524": "fhtkk", + "col525": "xy9ue", + "col526": "q9pdc", + "col527": "u9oni", + "col528": "artbe", + "col529": "ybmey", + "col530": "szua6", + "col531": "wpf46", + "col532": "t65f4", + "col533": "9bojl", + "col534": "ban2k", + "col535": "2g3ss", + "col536": "3wh7y", + "col537": "ljuwg", + "col538": "pxh0u", + "col539": "d10jz", + "col540": "1s1fj", + "col541": "0y5mb", + "col542": "jj7yu", + "col543": "namrp", + "col544": "gegr0", + "col545": "ctchp", + "col546": "01et3", + "col547": "ulur4", + "col548": "26mto", + "col549": "56648", + "col550": "dk8ir", + "col551": "go335", + "col552": "k08jf", + "col553": "95pu9", + "col554": "dwycf", + "col555": "hyivq", + "col556": "qylgr", + "col557": "itp4d", + "col558": "5yw8s", + "col559": "5cs6v", + "col560": "gooix", + "col561": "2dl6x", + "col562": "rhmx5", + "col563": "yng2z", + "col564": "6lxb1", + "col565": "ip2b9", + "col566": "z0dmc", + "col567": "brna0", + "col568": "hx6da", + "col569": "ms8kd", + "col570": "nd30g", + "col571": "wyhxq", + "col572": "0x9gf", + "col573": "9efck", + "col574": "s5838", + "col575": "xkmyy", + "col576": "hgc2h", + "col577": "bad34", + "col578": "vn0y9", + "col579": "too8v", + "col580": "fsyur", + "col581": "95i4b", + "col582": "sriks", + "col583": "lvdet", + "col584": "eb1hn", + "col585": "ecqh3", + "col586": "wfeet", + "col587": "1yfub", + "col588": "7njle", + "col589": "l7fu0", + "col590": "jy4i8", + "col591": "lex5o", + "col592": "cinnj", + "col593": "x0v5o", + "col594": "jfs2c", + "col595": "14ziy", + "col596": "qfhjh", + "col597": "k6ua3", + "col598": "lh79g", + "col599": "oycwy", + "col600": "ylh5s", + "col601": "wpy5q", + "col602": "nsdrl", + "col603": "19tlp", + "col604": "2vcdd", + "col605": "10dc9", + "col606": "xxwb8", + "col607": "84ygu", + "col608": "x87ty", + "col609": "gme08", + "col610": "15o91", + "col611": "wvxxc", + "col612": "3egug", + "col613": "dt0zt", + "col614": "1d9xx", + "col615": "8lo3u", + "col616": "hhti8", + "col617": "g7frm", + "col618": "4atuv", + "col619": "h9ugm", + "col620": "6ukhd", + "col621": "0s2t4", + "col622": "aahi2", + "col623": "3p31q", + "col624": "599re", + "col625": "qua1k", + "col626": "sylsl", + "col627": "payok", + "col628": "p6ips", + "col629": "zbvwe", + "col630": "v0ry6", + "col631": "zh3p2", + "col632": "l3mtw", + "col633": "tf2iw", + "col634": "c4n1o", + "col635": "25s7v", + "col636": "0efcp", + "col637": "ngzks", + "col638": "qnadx", + "col639": "yo4gf", + "col640": "xoyto", + "col641": "jvmcr", + "col642": "53eay", + "col643": "x5ch9", + "col644": "kdybs", + "col645": "ebnrl", + "col646": "jjhxo", + "col647": "xl72s", + "col648": "5ll29", + "col649": "omwtq", + "col650": "3glhh", + "col651": "szkn4", + "col652": "j6cc6", + "col653": "wo7ty", + "col654": "xnxcy", + "col655": "6dqwn", + "col656": "2tvdp", + "col657": "791an", + "col658": "vas6t", + "col659": "28aoa", + "col660": "czyt8", + "col661": "prbgh", + "col662": "sgjq5", + "col663": "oozr8", + "col664": "rbdw6", + "col665": "8i1yq", + "col666": "5ej51", + "col667": "naiif", + "col668": "gpidb", + "col669": "vbh73", + "col670": "c3y2m", + "col671": "tszaa", + "col672": "p5hwp", + "col673": "8l8vn", + "col674": "jar3x", + "col675": "ftg77", + "col676": "v5rvy", + "col677": "10jok", + "col678": "y7fsd", + "col679": "js4u5", + "col680": "l1k4i", + "col681": "51vgo", + "col682": "e2a5w", + "col683": "3j0lo", + "col684": "apj02", + "col685": "dmqc1", + "col686": "7wgcy", + "col687": "phgoe", + "col688": "9p7bg", + "col689": "xinnw", + "col690": "oxwx0", + "col691": "n35vb", + "col692": "b7bxb", + "col693": "hugbo", + "col694": "mzspj", + "col695": "xbxhh", + "col696": "eweh3", + "col697": "h78ol", + "col698": "jcbn7", + "col699": "8ae2u", + "col700": "7h3c2", + "col701": "vpqc3", + "col702": "i7qo6", + "col703": "uifuv", + "col704": "w88mo", + "col705": "6biyg", + "col706": "z8b10", + "col707": "gh4tm", + "col708": "qohuc", + "col709": "9kabe", + "col710": "sie8h", + "col711": "rpx1h", + "col712": "n64ry", + "col713": "vl6q8", + "col714": "hxisv", + "col715": "8wv6g", + "col716": "ffdgi", + "col717": "120cv", + "col718": "wj633", + "col719": "9yb65", + "col720": "oqb7b", + "col721": "o3dab", + "col722": "z46ac", + "col723": "wi60j", + "col724": "1hogw", + "col725": "55lc2", + "col726": "pbz87", + "col727": "zmtvo", + "col728": "efpnj", + "col729": "11fwo", + "col730": "xb9oz", + "col731": "bkoab", + "col732": "25k1n", + "col733": "2ukuf", + "col734": "2ep8v", + "col735": "6d18k", + "col736": "5b3az", + "col737": "a13gd", + "col738": "2hkaj", + "col739": "tpnyw", + "col740": "5k2ts", + "col741": "y9aty", + "col742": "7n6yu", + "col743": "m09yp", + "col744": "stbk4", + "col745": "kg4qw", + "col746": "8sa69", + "col747": "wes7f", + "col748": "evn1f", + "col749": "lh520", + "col750": "3ebq8", + "col751": "sa9f0", + "col752": "zi3tu", + "col753": "n8ovc", + "col754": "f1um3", + "col755": "spgws", + "col756": "nljgd", + "col757": "krkio", + "col758": "al6dz", + "col759": "w44t8", + "col760": "q100t", + "col761": "060no", + "col762": "h52wl", + "col763": "9izpn", + "col764": "wb47u", + "col765": "ml9y3", + "col766": "m4c6c", + "col767": "imjxk", + "col768": "m1k8p", + "col769": "g8y48", + "col770": "419lj", + "col771": "90ry1", + "col772": "f11oi", + "col773": "e7s6c", + "col774": "eqqa0", + "col775": "qzjxz", + "col776": "y8ttz", + "col777": "ulnws", + "col778": "5xhe1", + "col779": "fypaa", + "col780": "rk9x3", + "col781": "5g5qi", + "col782": "64nk0", + "col783": "42o41", + "col784": "lgill", + "col785": "qmsus", + "col786": "46ov6", + "col787": "hu6bf", + "col788": "tj2wc", + "col789": "wv5cj", + "col790": "96o3s", + "col791": "67ppj", + "col792": "khd5r", + "col793": "09qsv", + "col794": "eqyp5", + "col795": "jmlf8", + "col796": "n40jj", + "col797": "rrvkt", + "col798": "mg6rg", + "col799": "uo1ie", + "col800": "z30tx", + "col801": "77jl0", + "col802": "fv4xk", + "col803": "63203", + "col804": "qy2x5", + "col805": "z07ol", + "col806": "ibao4", + "col807": "27hgd", + "col808": "8w415", + "col809": "pm2g0", + "col810": "nt2rn", + "col811": "0nc1m", + "col812": "5fnml", + "col813": "26wmq", + "col814": "x6slp", + "col815": "6d4z2", + "col816": "d0rcu", + "col817": "mdoap", + "col818": "0v459", + "col819": "oywn9", + "col820": "oexqr", + "col821": "93k8o", + "col822": "11fv1", + "col823": "47zx5", + "col824": "mofk4", + "col825": "cuz0o", + "col826": "1w8e8", + "col827": "hfm74", + "col828": "b4yhu", + "col829": "9se03", + "col830": "i1u8m", + "col831": "xq22o", + "col832": "ttqis", + "col833": "u0wtq", + "col834": "84xdm", + "col835": "w4wi8", + "col836": "5r6gd", + "col837": "4yqjf", + "col838": "2u03f", + "col839": "ij7m5", + "col840": "mc7te", + "col841": "li247", + "col842": "e9k76", + "col843": "9wd92", + "col844": "fh456", + "col845": "32rxi", + "col846": "o80tp", + "col847": "6wqn0", + "col848": "lu9q7", + "col849": "3o6as", + "col850": "s5r44", + "col851": "9z2gr", + "col852": "82ojx", + "col853": "t8dcn", + "col854": "uqzts", + "col855": "umgz9", + "col856": "hzmqu", + "col857": "p9bt9", + "col858": "oiy9r", + "col859": "utqmi", + "col860": "0h03p", + "col861": "zc9pe", + "col862": "3v64y", + "col863": "2tlih", + "col864": "fwq7z", + "col865": "fvglt", + "col866": "f2opv", + "col867": "2tg6h", + "col868": "9v5er", + "col869": "h0601", + "col870": "ogg7g", + "col871": "2u352", + "col872": "n3mgx", + "col873": "rfmxi", + "col874": "h25jz", + "col875": "u511t", + "col876": "jgvd6", + "col877": "ewz66", + "col878": "6e2ph", + "col879": "6of09", + "col880": "qgt3e", + "col881": "f9zwk", + "col882": "mm1la", + "col883": "kd91z", + "col884": "50fiw", + "col885": "ym8zr", + "col886": "01noz", + "col887": "d4yye", + "col888": "jkyjc", + "col889": "44d8t", + "col890": "4dekr", + "col891": "4d71n", + "col892": "hy3x3", + "col893": "lz9ag", + "col894": "valgu", + "col895": "ggw5o", + "col896": "zpq5c", + "col897": "6hci1", + "col898": "p8iuz", + "col899": "2e9p9", + "col900": "dnuw9", + "col901": "lszqs", + "col902": "g5tvk", + "col903": "71bqm", + "col904": "fuxiw", + "col905": "tl1gt", + "col906": "d0s60", + "col907": "xvg9k", + "col908": "e9orv", + "col909": "gmoiz", + "col910": "ch2eh", + "col911": "upr6g", + "col912": "kmwjq", + "col913": "m7193", + "col914": "rr177", + "col915": "f1pa2", + "col916": "gn7ca", + "col917": "e52z9", + "col918": "5iuka", + "col919": "zi93q", + "col920": "u7ped", + "col921": "rmap2", + "col922": "1t6uy", + "col923": "66m1h", + "col924": "6cr41", + "col925": "n8wnv", + "col926": "3g8sp", + "col927": "wxvfj", + "col928": "d80ab", + "col929": "vkndb", + "col930": "3o1g0", + "col931": "95p0l", + "col932": "a887g", + "col933": "r5mkl", + "col934": "aey7x", + "col935": "419h9", + "col936": "2dj3b", + "col937": "lgaey", + "col938": "srg21", + "col939": "ka66d", + "col940": "oun4c", + "col941": "39cd4", + "col942": "1axc6", + "col943": "k4fs7", + "col944": "3u8c4", + "col945": "aqeme", + "col946": "0sezx", + "col947": "m39ms", + "col948": "i1irn", + "col949": "aif6b", + "col950": "950b6", + "col951": "jy8u7", + "col952": "c5ud9", + "col953": "kret9", + "col954": "u2uv7", + "col955": "ottl3", + "col956": "lfgnt", + "col957": "udwcj", + "col958": "xhaqv", + "col959": "b7dth", + "col960": "cciph", + "col961": "m15i2", + "col962": "3s7wz", + "col963": "nw9x2", + "col964": "0nshu", + "col965": "9f2zd", + "col966": "je1l8", + "col967": "adj6g", + "col968": "mlym6", + "col969": "ovz5b", + "col970": "kwjyd", + "col971": "ff3at", + "col972": "qay8c", + "col973": "12rvj", + "col974": "52jcs", + "col975": "evejd", + "col976": "yw3ux", + "col977": "a3fpy", + "col978": "m8j22", + "col979": "o58r9", + "col980": "qwjfp", + "col981": "vjg3z", + "col982": "i38yi", + "col983": "rfwwq", + "col984": "1aad9", + "col985": "on4ls", + "col986": "s4gxu", + "col987": "6ctmf", + "col988": "axjgt", + "col989": "p35ir", + "col990": "hse2i", + "col991": "qy6ju", + "col992": "8xgos", + "col993": "cmxu0", + "col994": "5tul6", + "col995": "51ml2", + "col996": "jycsp", + "col997": "vvbgh", + "col998": "vroda", + "col999": "j52sf" + }, + { + "name": "Rene Gibbs", + "gender": "female", + "col0": "y0pgd", + "col1": "6xqwa", + "col2": "mgdpy", + "col3": "waf8y", + "col4": "tuxci", + "col5": "ev8kd", + "col6": "fxq1d", + "col7": "4kfvb", + "col8": "712z8", + "col9": "b2u9a", + "col10": "4glw9", + "col11": "uuatd", + "col12": "2zjf7", + "col13": "9uwx3", + "col14": "toznl", + "col15": "5e3bm", + "col16": "k7zri", + "col17": "1pw1u", + "col18": "lh143", + "col19": "bi3s6", + "col20": "ifg72", + "col21": "ajl2m", + "col22": "5e7ua", + "col23": "i5x5c", + "col24": "uothq", + "col25": "5wmme", + "col26": "6bzio", + "col27": "k68bl", + "col28": "l6ftn", + "col29": "nwxt9", + "col30": "wtvij", + "col31": "kqjrl", + "col32": "q6o1j", + "col33": "7u9r2", + "col34": "aq80l", + "col35": "3n5o1", + "col36": "9m2p2", + "col37": "kgiab", + "col38": "gnmlf", + "col39": "uim6x", + "col40": "gn3e4", + "col41": "bsly8", + "col42": "35khb", + "col43": "gxwgg", + "col44": "576ks", + "col45": "d1tsc", + "col46": "lkvko", + "col47": "fgiks", + "col48": "bn159", + "col49": "15buc", + "col50": "2cj30", + "col51": "uakgt", + "col52": "vbpki", + "col53": "zvl5i", + "col54": "jqfwn", + "col55": "eqpw9", + "col56": "2kb8f", + "col57": "6c3e0", + "col58": "k0jrh", + "col59": "2syy1", + "col60": "et75w", + "col61": "l0vif", + "col62": "7btri", + "col63": "6nwqb", + "col64": "uaorq", + "col65": "xavfl", + "col66": "zugar", + "col67": "qna7r", + "col68": "r7r30", + "col69": "o2uhl", + "col70": "jaubu", + "col71": "ybq54", + "col72": "cxtf5", + "col73": "nzalm", + "col74": "3iul5", + "col75": "sml3r", + "col76": "zwlwq", + "col77": "vx5dr", + "col78": "0877m", + "col79": "mund0", + "col80": "gijb1", + "col81": "xgv6x", + "col82": "awl03", + "col83": "bb6xa", + "col84": "4c81e", + "col85": "62nr5", + "col86": "5hmo9", + "col87": "1z9pw", + "col88": "d6f4m", + "col89": "6wpzs", + "col90": "l9qv9", + "col91": "okx3t", + "col92": "zim78", + "col93": "g4ore", + "col94": "n3xeo", + "col95": "6q2qu", + "col96": "htkt5", + "col97": "s0hs2", + "col98": "7wi3t", + "col99": "thst6", + "col100": "kmkvi", + "col101": "7rdhs", + "col102": "yqk25", + "col103": "0jrbv", + "col104": "j9pdo", + "col105": "0mvtq", + "col106": "eeb3l", + "col107": "8n8nc", + "col108": "b72il", + "col109": "ny92x", + "col110": "q3kjv", + "col111": "z9add", + "col112": "jvfk5", + "col113": "vl52k", + "col114": "6z0of", + "col115": "sqg6k", + "col116": "yac7k", + "col117": "wxjgh", + "col118": "v6i0w", + "col119": "c5v0i", + "col120": "ldt2a", + "col121": "gpjmu", + "col122": "me0sh", + "col123": "ihwaa", + "col124": "bnx6y", + "col125": "y8jio", + "col126": "os8sv", + "col127": "wion1", + "col128": "mn7jp", + "col129": "hxygu", + "col130": "5czpl", + "col131": "hf5sp", + "col132": "s7w1b", + "col133": "xstz0", + "col134": "7yywr", + "col135": "38988", + "col136": "4ll1j", + "col137": "75twi", + "col138": "d59uo", + "col139": "n43vz", + "col140": "z4x4y", + "col141": "hnrp4", + "col142": "pyhil", + "col143": "6g5s2", + "col144": "tqws0", + "col145": "dmdko", + "col146": "sghse", + "col147": "eneek", + "col148": "kpgh9", + "col149": "0ncov", + "col150": "tnx0l", + "col151": "3ap4k", + "col152": "irqke", + "col153": "xpv0f", + "col154": "boqzv", + "col155": "kj9mg", + "col156": "teuap", + "col157": "c2d3r", + "col158": "2c3tg", + "col159": "v0n1k", + "col160": "21tkf", + "col161": "94696", + "col162": "hyydk", + "col163": "6zz7r", + "col164": "cs7fl", + "col165": "tqpdl", + "col166": "7yd8e", + "col167": "mgj98", + "col168": "2d5g9", + "col169": "aut43", + "col170": "9abtq", + "col171": "03nad", + "col172": "jelh6", + "col173": "avbsy", + "col174": "7yk6k", + "col175": "6711t", + "col176": "mxn1p", + "col177": "fz7ir", + "col178": "sqigf", + "col179": "seh2h", + "col180": "lggpx", + "col181": "pvxci", + "col182": "r30ge", + "col183": "ycxad", + "col184": "ady34", + "col185": "gk00i", + "col186": "ob16i", + "col187": "0xsdq", + "col188": "xj7t1", + "col189": "pl8fr", + "col190": "53f4b", + "col191": "5efb4", + "col192": "5n5l0", + "col193": "edg13", + "col194": "hy92e", + "col195": "9macz", + "col196": "vvptj", + "col197": "a9f43", + "col198": "srokt", + "col199": "r3riu", + "col200": "ajyxp", + "col201": "v2r9o", + "col202": "6ro6a", + "col203": "niyw4", + "col204": "j61sn", + "col205": "h20ng", + "col206": "13mqv", + "col207": "4mbtx", + "col208": "21b9s", + "col209": "xsmds", + "col210": "xdxmx", + "col211": "q848n", + "col212": "bkhbj", + "col213": "zejzz", + "col214": "ochz0", + "col215": "qgy9r", + "col216": "igtkt", + "col217": "xcrkh", + "col218": "lnj5q", + "col219": "5oz2q", + "col220": "9qxcs", + "col221": "bb9zg", + "col222": "pqeg5", + "col223": "y99fw", + "col224": "e4xs8", + "col225": "c65kg", + "col226": "x8eoa", + "col227": "f53n5", + "col228": "t73cl", + "col229": "n93ra", + "col230": "77rkc", + "col231": "rizyx", + "col232": "dm9wx", + "col233": "dnfn0", + "col234": "xirk2", + "col235": "ycce3", + "col236": "0oztn", + "col237": "iilbo", + "col238": "ykocl", + "col239": "5cfgl", + "col240": "nzfdg", + "col241": "773hv", + "col242": "zjnl7", + "col243": "y9dg0", + "col244": "q1ktf", + "col245": "yu60o", + "col246": "e2doz", + "col247": "dh4id", + "col248": "um4g7", + "col249": "k0vbl", + "col250": "q6d6b", + "col251": "8ltjf", + "col252": "cmyu8", + "col253": "88xr4", + "col254": "vd5q2", + "col255": "qjzqk", + "col256": "y5c2k", + "col257": "1w3t7", + "col258": "mlh15", + "col259": "ik7ph", + "col260": "pqc4b", + "col261": "159o1", + "col262": "opnc0", + "col263": "oflp4", + "col264": "hwtrh", + "col265": "4p0cb", + "col266": "4ponc", + "col267": "uusrc", + "col268": "c1bzq", + "col269": "d948a", + "col270": "6u435", + "col271": "0ptrk", + "col272": "hzu5k", + "col273": "1rmpd", + "col274": "p3yaq", + "col275": "7bpik", + "col276": "olh4f", + "col277": "en8ly", + "col278": "w9uk3", + "col279": "70soo", + "col280": "6cosq", + "col281": "0waqn", + "col282": "qonuu", + "col283": "b0g93", + "col284": "wsrma", + "col285": "f3s5g", + "col286": "oml9g", + "col287": "x1baq", + "col288": "hlrov", + "col289": "70tgv", + "col290": "zr5bn", + "col291": "jz483", + "col292": "t8ld6", + "col293": "aipuh", + "col294": "yr2kg", + "col295": "09dxk", + "col296": "nxrap", + "col297": "z0gbu", + "col298": "txchg", + "col299": "5bcl6", + "col300": "3391o", + "col301": "l7720", + "col302": "m5dly", + "col303": "a8gm2", + "col304": "9qm4a", + "col305": "jfgys", + "col306": "d6amp", + "col307": "2lryc", + "col308": "07ql4", + "col309": "9ujc9", + "col310": "0n09n", + "col311": "50lat", + "col312": "8y1pn", + "col313": "jnhd1", + "col314": "2oful", + "col315": "00cuk", + "col316": "hcmiq", + "col317": "udlna", + "col318": "2bro7", + "col319": "acntn", + "col320": "n91wg", + "col321": "cv621", + "col322": "1ykky", + "col323": "bdbcs", + "col324": "axibp", + "col325": "vi3xr", + "col326": "e7jfs", + "col327": "crqqo", + "col328": "6uk6k", + "col329": "hygni", + "col330": "hgnwy", + "col331": "cmom3", + "col332": "bohyt", + "col333": "9qbaf", + "col334": "iad1e", + "col335": "9tppj", + "col336": "3jrpp", + "col337": "f18ep", + "col338": "a3381", + "col339": "03g8a", + "col340": "ld5i3", + "col341": "v73xf", + "col342": "m2dzs", + "col343": "qwgnz", + "col344": "tbhwf", + "col345": "acgep", + "col346": "ncfui", + "col347": "jqkyl", + "col348": "yltqg", + "col349": "wtabu", + "col350": "d3j1e", + "col351": "8fxw1", + "col352": "scq0j", + "col353": "lkui1", + "col354": "jq3pc", + "col355": "u5isx", + "col356": "wke9b", + "col357": "9ytae", + "col358": "sp7ab", + "col359": "m9xcc", + "col360": "8lbh7", + "col361": "a3l9a", + "col362": "ppose", + "col363": "rjmsm", + "col364": "0x8e7", + "col365": "kfrtf", + "col366": "0bxoi", + "col367": "lb9hb", + "col368": "b6bre", + "col369": "gyiqg", + "col370": "9nqik", + "col371": "3c1v9", + "col372": "98svh", + "col373": "m4f7j", + "col374": "5n3mm", + "col375": "pshkz", + "col376": "loq82", + "col377": "tufiq", + "col378": "7y70t", + "col379": "t8q2b", + "col380": "5fh8e", + "col381": "1v3cn", + "col382": "e73yu", + "col383": "9pq3o", + "col384": "fw921", + "col385": "2xhfn", + "col386": "j6wj1", + "col387": "axn4i", + "col388": "ub2ug", + "col389": "z64d9", + "col390": "cfodq", + "col391": "eqlxs", + "col392": "tvc9i", + "col393": "2957r", + "col394": "ysz52", + "col395": "74y8k", + "col396": "4dqnf", + "col397": "tc57k", + "col398": "0ejcq", + "col399": "grlq0", + "col400": "8xe5s", + "col401": "d6dh2", + "col402": "9prsv", + "col403": "fm0up", + "col404": "nf6nj", + "col405": "u08jq", + "col406": "z3wr2", + "col407": "lp897", + "col408": "qd3hw", + "col409": "bwvt4", + "col410": "qjolo", + "col411": "jnfb5", + "col412": "dh1ea", + "col413": "s0qwt", + "col414": "0pim9", + "col415": "zrsfr", + "col416": "kfqs7", + "col417": "00d70", + "col418": "erutv", + "col419": "38xyx", + "col420": "qacfb", + "col421": "iwuzx", + "col422": "rt1ka", + "col423": "hfbxe", + "col424": "z90vw", + "col425": "vtz2o", + "col426": "j1db9", + "col427": "1e4cj", + "col428": "plrz8", + "col429": "7mdpx", + "col430": "lm75s", + "col431": "4z65q", + "col432": "m4d4n", + "col433": "hv7mz", + "col434": "twkcw", + "col435": "v10ex", + "col436": "ntw45", + "col437": "p88oj", + "col438": "0o0ps", + "col439": "c7fcc", + "col440": "qebmd", + "col441": "phmxj", + "col442": "po1bw", + "col443": "go6w2", + "col444": "u1jw1", + "col445": "p4n5q", + "col446": "hfm6v", + "col447": "v14h3", + "col448": "62hxs", + "col449": "24btw", + "col450": "61bdg", + "col451": "ld91y", + "col452": "jfsfx", + "col453": "5f1t7", + "col454": "2p4fc", + "col455": "ncvqh", + "col456": "j22vs", + "col457": "xvi14", + "col458": "2jbdf", + "col459": "gaou7", + "col460": "fefb9", + "col461": "7qo6o", + "col462": "buk80", + "col463": "owqz6", + "col464": "sfft3", + "col465": "ks7nl", + "col466": "bndeq", + "col467": "fuww6", + "col468": "asmtj", + "col469": "reys1", + "col470": "dwx56", + "col471": "5hd4z", + "col472": "k6p6p", + "col473": "2be75", + "col474": "jdnv8", + "col475": "l4s2w", + "col476": "g22rm", + "col477": "cpnuv", + "col478": "4xqjs", + "col479": "yhqz4", + "col480": "20ty8", + "col481": "h7yns", + "col482": "elivq", + "col483": "f1x1l", + "col484": "c0h3n", + "col485": "47hm1", + "col486": "vtecz", + "col487": "zrfsr", + "col488": "zyn9z", + "col489": "g9em9", + "col490": "v6dkn", + "col491": "5vdtp", + "col492": "8oh06", + "col493": "lnxy9", + "col494": "ejre2", + "col495": "larry", + "col496": "g7575", + "col497": "tryyc", + "col498": "ideb9", + "col499": "fpzvj", + "col500": "1fxv4", + "col501": "3qwbo", + "col502": "0aiwl", + "col503": "nzj60", + "col504": "xe4gq", + "col505": "5tu3k", + "col506": "0smwc", + "col507": "vj7p2", + "col508": "ifme2", + "col509": "5zw6w", + "col510": "34o32", + "col511": "o3n9x", + "col512": "d2nsj", + "col513": "tuhi1", + "col514": "jqi5t", + "col515": "ys04l", + "col516": "1ky3a", + "col517": "6068f", + "col518": "xgrs3", + "col519": "qeni4", + "col520": "b5h7s", + "col521": "dqpe5", + "col522": "22fnl", + "col523": "jxsno", + "col524": "adpx8", + "col525": "53pa7", + "col526": "8lero", + "col527": "gznnb", + "col528": "2kqnp", + "col529": "bsh61", + "col530": "b09cq", + "col531": "xrdsk", + "col532": "i0x23", + "col533": "j2j1v", + "col534": "7viue", + "col535": "fpars", + "col536": "n4h2h", + "col537": "31c1w", + "col538": "yjtuo", + "col539": "rddi5", + "col540": "c1ac0", + "col541": "y3dev", + "col542": "zkg6b", + "col543": "b9kow", + "col544": "l59hn", + "col545": "uaxzw", + "col546": "gatjr", + "col547": "dvloy", + "col548": "bcoiv", + "col549": "1zqx8", + "col550": "17fva", + "col551": "17txp", + "col552": "bppbb", + "col553": "uar7s", + "col554": "vbziy", + "col555": "9tka0", + "col556": "iymbt", + "col557": "e23ef", + "col558": "fwcil", + "col559": "vqt67", + "col560": "f2h6i", + "col561": "4twg6", + "col562": "wpovm", + "col563": "8x7jr", + "col564": "cp6os", + "col565": "1hxko", + "col566": "jm4lm", + "col567": "x0rza", + "col568": "27i64", + "col569": "pjgc0", + "col570": "dwzgk", + "col571": "wkb36", + "col572": "epbx3", + "col573": "fz5kz", + "col574": "3uu0c", + "col575": "wqsx7", + "col576": "7b2oe", + "col577": "egnq7", + "col578": "eh92y", + "col579": "9izbw", + "col580": "knuur", + "col581": "k2141", + "col582": "q7k2x", + "col583": "4rdgv", + "col584": "540uj", + "col585": "06boy", + "col586": "1y4zn", + "col587": "i23z3", + "col588": "n1mjq", + "col589": "dbrr4", + "col590": "4ilrl", + "col591": "3s4mw", + "col592": "hdcj0", + "col593": "bubkb", + "col594": "sk4mb", + "col595": "hk12h", + "col596": "2dums", + "col597": "vsbxo", + "col598": "esaw2", + "col599": "9es8m", + "col600": "hmsak", + "col601": "ybfxf", + "col602": "v03y0", + "col603": "2uulc", + "col604": "cv5sc", + "col605": "3svsa", + "col606": "03zcc", + "col607": "v3ojq", + "col608": "hnuqw", + "col609": "szft6", + "col610": "ovh89", + "col611": "dpats", + "col612": "36k67", + "col613": "cug6k", + "col614": "pzld2", + "col615": "opdkm", + "col616": "8vej8", + "col617": "hzczw", + "col618": "48bq1", + "col619": "d0ufh", + "col620": "7i2nz", + "col621": "idbwg", + "col622": "ugdaw", + "col623": "ixurl", + "col624": "gtavt", + "col625": "icqts", + "col626": "7dij8", + "col627": "xmp3p", + "col628": "mhh07", + "col629": "qplbl", + "col630": "kstlk", + "col631": "fwj8v", + "col632": "sidfa", + "col633": "4e3yn", + "col634": "a0fzl", + "col635": "f2c03", + "col636": "sz7ql", + "col637": "qr4zd", + "col638": "nl5qp", + "col639": "fe3hc", + "col640": "aqhbh", + "col641": "s8k2s", + "col642": "n96td", + "col643": "m061s", + "col644": "we5j2", + "col645": "gc8nc", + "col646": "jok08", + "col647": "wqifc", + "col648": "04wh6", + "col649": "ctrr6", + "col650": "qakiw", + "col651": "82mg6", + "col652": "15shk", + "col653": "l8mfm", + "col654": "vulci", + "col655": "jv58z", + "col656": "t3bny", + "col657": "2tvyf", + "col658": "b2mpp", + "col659": "tcih7", + "col660": "ah4fh", + "col661": "g8nol", + "col662": "rqg4m", + "col663": "htkjd", + "col664": "hy3m2", + "col665": "7aqdq", + "col666": "yr4y2", + "col667": "3ig83", + "col668": "ielm7", + "col669": "66qtm", + "col670": "6qi4f", + "col671": "7w4d3", + "col672": "zfjcf", + "col673": "okyvk", + "col674": "7m67b", + "col675": "yubvy", + "col676": "4om1i", + "col677": "jntgb", + "col678": "zno0x", + "col679": "7gdmw", + "col680": "uglv5", + "col681": "scjsu", + "col682": "rtb61", + "col683": "y5db5", + "col684": "9rs8n", + "col685": "trsut", + "col686": "vqe5i", + "col687": "e3x1z", + "col688": "w0nsa", + "col689": "ecbvi", + "col690": "o50ij", + "col691": "1cfab", + "col692": "bv2e4", + "col693": "ym53m", + "col694": "vanz5", + "col695": "wjfz1", + "col696": "cefl0", + "col697": "3o72l", + "col698": "22pt6", + "col699": "spoy9", + "col700": "lizba", + "col701": "x89pi", + "col702": "1x4a8", + "col703": "gugih", + "col704": "jsjuw", + "col705": "l13o7", + "col706": "v7g8f", + "col707": "z754v", + "col708": "un93h", + "col709": "n3fro", + "col710": "wrsng", + "col711": "umncq", + "col712": "td5kj", + "col713": "vkeou", + "col714": "vpuc7", + "col715": "o2bs2", + "col716": "u0edm", + "col717": "028q6", + "col718": "mh0z3", + "col719": "44iib", + "col720": "ihyj1", + "col721": "ps0ol", + "col722": "2vjxq", + "col723": "1v048", + "col724": "mqyyh", + "col725": "8jtys", + "col726": "kxo7v", + "col727": "h1qbq", + "col728": "kznqo", + "col729": "k79la", + "col730": "9qewr", + "col731": "jsnl0", + "col732": "kou9t", + "col733": "d9uoh", + "col734": "7842b", + "col735": "4haig", + "col736": "b1oan", + "col737": "dhp22", + "col738": "wv4aw", + "col739": "ma038", + "col740": "1cug4", + "col741": "tl5op", + "col742": "78p0b", + "col743": "c4bba", + "col744": "cv46f", + "col745": "793gz", + "col746": "s7lyf", + "col747": "0y2vx", + "col748": "cprv9", + "col749": "2d4y2", + "col750": "d5np1", + "col751": "ll39c", + "col752": "pfgwh", + "col753": "rsbuf", + "col754": "4gyb8", + "col755": "2oppz", + "col756": "7d029", + "col757": "pauio", + "col758": "ci077", + "col759": "qv7bm", + "col760": "m7bpa", + "col761": "v17g7", + "col762": "t44s3", + "col763": "d3b2u", + "col764": "rkyjz", + "col765": "vyrgn", + "col766": "315ps", + "col767": "b5avh", + "col768": "y1wg9", + "col769": "wlwl7", + "col770": "kfaq7", + "col771": "f8rrn", + "col772": "d3o4l", + "col773": "lvrs6", + "col774": "4qaw0", + "col775": "1veqa", + "col776": "i23i4", + "col777": "ivfq8", + "col778": "pb3xo", + "col779": "jrj7e", + "col780": "agael", + "col781": "6f5e6", + "col782": "rjgdk", + "col783": "9tsqy", + "col784": "zdhsk", + "col785": "jbgtm", + "col786": "b86l4", + "col787": "gexz4", + "col788": "0v311", + "col789": "lnx3f", + "col790": "9uy7v", + "col791": "hc4mz", + "col792": "lmuu6", + "col793": "tzeqz", + "col794": "910we", + "col795": "drtvk", + "col796": "slpch", + "col797": "355vf", + "col798": "df6ea", + "col799": "nepd4", + "col800": "7vcft", + "col801": "bzjxc", + "col802": "5yq3d", + "col803": "v5bo5", + "col804": "jehei", + "col805": "67d3f", + "col806": "bqv0g", + "col807": "ly5g0", + "col808": "zxeom", + "col809": "onorm", + "col810": "jxkma", + "col811": "e9jnl", + "col812": "4fvhx", + "col813": "ze37y", + "col814": "a04tn", + "col815": "235q2", + "col816": "mrf2q", + "col817": "8f8i2", + "col818": "17wsj", + "col819": "4gm1m", + "col820": "ulnj6", + "col821": "ikg4r", + "col822": "bxz9u", + "col823": "swzld", + "col824": "xl9vs", + "col825": "n9oqb", + "col826": "bj4yc", + "col827": "shp7q", + "col828": "qwue2", + "col829": "aufh2", + "col830": "lc861", + "col831": "uf7tv", + "col832": "3jo4w", + "col833": "7gfcn", + "col834": "pnpgg", + "col835": "2khy3", + "col836": "6ry5v", + "col837": "jmtzo", + "col838": "sbl63", + "col839": "yfuey", + "col840": "9ed4b", + "col841": "9vyah", + "col842": "vvh50", + "col843": "nuh3j", + "col844": "53sga", + "col845": "lim9e", + "col846": "2iklw", + "col847": "2bs19", + "col848": "f4pun", + "col849": "ztqqn", + "col850": "k82fm", + "col851": "vx6sc", + "col852": "a1kkw", + "col853": "waw35", + "col854": "xqhib", + "col855": "cnx29", + "col856": "y2wim", + "col857": "pwath", + "col858": "g83sw", + "col859": "lexxt", + "col860": "ghwrz", + "col861": "ceovz", + "col862": "vq4bg", + "col863": "9d29j", + "col864": "s4w22", + "col865": "udl6y", + "col866": "dq9wh", + "col867": "cmxs7", + "col868": "ajn9q", + "col869": "lcfg3", + "col870": "coghz", + "col871": "r2416", + "col872": "3gaa2", + "col873": "umivh", + "col874": "9idrl", + "col875": "pg7py", + "col876": "usnlr", + "col877": "r62dd", + "col878": "kz9hw", + "col879": "i7164", + "col880": "l57ch", + "col881": "5i0a1", + "col882": "gwawx", + "col883": "zuyd1", + "col884": "az67p", + "col885": "4y5jl", + "col886": "171ww", + "col887": "yuri8", + "col888": "06y3u", + "col889": "se1pt", + "col890": "09xjw", + "col891": "xngc7", + "col892": "sir5f", + "col893": "a0oph", + "col894": "vqgg6", + "col895": "msefr", + "col896": "r4axr", + "col897": "bz908", + "col898": "299y1", + "col899": "806gy", + "col900": "tv4do", + "col901": "d0qcw", + "col902": "m9usl", + "col903": "8grb3", + "col904": "2xepr", + "col905": "khvot", + "col906": "xff1p", + "col907": "lunmi", + "col908": "1pedh", + "col909": "2wt4s", + "col910": "sxnxm", + "col911": "wfd9w", + "col912": "b1jhn", + "col913": "5gbdc", + "col914": "ovpbs", + "col915": "jlbwd", + "col916": "0jlhb", + "col917": "u75dg", + "col918": "3vgpm", + "col919": "gciy0", + "col920": "ksy94", + "col921": "enmb9", + "col922": "fywzs", + "col923": "xa17i", + "col924": "8s1g7", + "col925": "njdbd", + "col926": "1z0nq", + "col927": "vpxuo", + "col928": "j3ekn", + "col929": "iubtu", + "col930": "3hnwi", + "col931": "vwz55", + "col932": "gdmhz", + "col933": "d3963", + "col934": "euz01", + "col935": "dv5ln", + "col936": "yld43", + "col937": "nu75e", + "col938": "rroz5", + "col939": "6tlwd", + "col940": "fv042", + "col941": "06mkc", + "col942": "9024g", + "col943": "2k8ew", + "col944": "qjq9d", + "col945": "tl7na", + "col946": "5vb8i", + "col947": "mir69", + "col948": "f0qdr", + "col949": "qh1gm", + "col950": "xflh3", + "col951": "tb4mi", + "col952": "bhkqm", + "col953": "y7w5z", + "col954": "z23yi", + "col955": "pdfzr", + "col956": "o3lfx", + "col957": "7lfny", + "col958": "4voz6", + "col959": "d2pu2", + "col960": "v5cnk", + "col961": "qej2s", + "col962": "zoymd", + "col963": "ds6v6", + "col964": "d9exp", + "col965": "2zbav", + "col966": "nhk22", + "col967": "wyskz", + "col968": "7iu43", + "col969": "1u00d", + "col970": "k9wag", + "col971": "4w1s2", + "col972": "1d3c0", + "col973": "g8x4b", + "col974": "qqod5", + "col975": "v4t34", + "col976": "srfsg", + "col977": "afm0b", + "col978": "gqrxm", + "col979": "3pjr7", + "col980": "9digw", + "col981": "rntnc", + "col982": "cwdss", + "col983": "ofha4", + "col984": "bc1uh", + "col985": "4cpz3", + "col986": "pyqv2", + "col987": "k7i8q", + "col988": "nkldd", + "col989": "pj5vx", + "col990": "pus1v", + "col991": "jiykg", + "col992": "2qarn", + "col993": "wlvl3", + "col994": "e78nm", + "col995": "gjufv", + "col996": "c1sjy", + "col997": "0oeo5", + "col998": "j8w3x", + "col999": "dlk3n" + }, + { + "name": "Rocha Frank", + "gender": "male", + "col0": "6lxiz", + "col1": "nqd9e", + "col2": "89ieq", + "col3": "glw4m", + "col4": "ab87i", + "col5": "gztuk", + "col6": "dv6zj", + "col7": "lrtes", + "col8": "ifiz7", + "col9": "k2gow", + "col10": "0ax0q", + "col11": "0qq9l", + "col12": "cexcp", + "col13": "tqwuy", + "col14": "v7hij", + "col15": "qpzsx", + "col16": "23kgg", + "col17": "gbql9", + "col18": "esutk", + "col19": "s9k6b", + "col20": "bd6i8", + "col21": "4y3kl", + "col22": "4oku6", + "col23": "bbp9p", + "col24": "5p1q7", + "col25": "2mg3o", + "col26": "stoq4", + "col27": "n8yor", + "col28": "1bhas", + "col29": "7ugrx", + "col30": "m4tm0", + "col31": "7kj0w", + "col32": "t16i1", + "col33": "ugucj", + "col34": "gpcs3", + "col35": "p0n1t", + "col36": "jo6sd", + "col37": "g1lmi", + "col38": "lrehi", + "col39": "gpwbx", + "col40": "s6uwn", + "col41": "c9nty", + "col42": "qd3se", + "col43": "6rvvp", + "col44": "g8b45", + "col45": "l08s7", + "col46": "i1qea", + "col47": "l0r0z", + "col48": "z28mh", + "col49": "cffmd", + "col50": "fo8dp", + "col51": "hc9n4", + "col52": "t1rv5", + "col53": "8oi4l", + "col54": "d2i7r", + "col55": "8ukt2", + "col56": "bqpg6", + "col57": "4cjkn", + "col58": "58bap", + "col59": "870qz", + "col60": "bq1z7", + "col61": "pe5ja", + "col62": "kl95t", + "col63": "vid3z", + "col64": "queu4", + "col65": "lzwob", + "col66": "fx8tr", + "col67": "48kkt", + "col68": "7c51y", + "col69": "b21wz", + "col70": "u0t7u", + "col71": "75eax", + "col72": "ry93o", + "col73": "u78rg", + "col74": "y3mex", + "col75": "9jzyq", + "col76": "vjljd", + "col77": "vlbuo", + "col78": "xl1jr", + "col79": "vn2de", + "col80": "ic2e8", + "col81": "49jsz", + "col82": "xht6l", + "col83": "fer3i", + "col84": "5on7q", + "col85": "6gkie", + "col86": "5gxdm", + "col87": "fsfim", + "col88": "buslg", + "col89": "13gru", + "col90": "zvyie", + "col91": "3l50s", + "col92": "vrmpq", + "col93": "laiyv", + "col94": "61bbt", + "col95": "0r0v3", + "col96": "d1uot", + "col97": "htw8r", + "col98": "cw0vb", + "col99": "02flb", + "col100": "p4suc", + "col101": "wfl1q", + "col102": "4v7m7", + "col103": "f65ja", + "col104": "2dmma", + "col105": "l6hat", + "col106": "n3pvp", + "col107": "887rt", + "col108": "hvf0f", + "col109": "uybnh", + "col110": "mhgae", + "col111": "50qla", + "col112": "uv79o", + "col113": "bxmnb", + "col114": "92z6u", + "col115": "7vrus", + "col116": "kcllu", + "col117": "l9hzq", + "col118": "nekx8", + "col119": "3ec6r", + "col120": "vbyrw", + "col121": "owkib", + "col122": "n1t2z", + "col123": "xkpn2", + "col124": "2m6wc", + "col125": "37bfk", + "col126": "07ekj", + "col127": "qwhvi", + "col128": "cbfyu", + "col129": "6t50m", + "col130": "z70a2", + "col131": "h6j0y", + "col132": "q5m1h", + "col133": "4tdau", + "col134": "0v0q5", + "col135": "awgm6", + "col136": "t1slw", + "col137": "vz7xm", + "col138": "scf6e", + "col139": "1i2of", + "col140": "ysdfj", + "col141": "9pzgl", + "col142": "0ll5a", + "col143": "kpb5m", + "col144": "gwgav", + "col145": "4vchd", + "col146": "z2dff", + "col147": "5bijd", + "col148": "zeqlf", + "col149": "icyu1", + "col150": "4xokj", + "col151": "3g15e", + "col152": "eijz5", + "col153": "a19tw", + "col154": "9z91u", + "col155": "1a8fj", + "col156": "er3pm", + "col157": "x8b6j", + "col158": "rmvc0", + "col159": "5qpvf", + "col160": "jtovh", + "col161": "gl9gq", + "col162": "nuwn1", + "col163": "35u1m", + "col164": "qvbrd", + "col165": "fcqtw", + "col166": "lhk9r", + "col167": "gr6bz", + "col168": "hi859", + "col169": "arf2l", + "col170": "4zqha", + "col171": "18qmg", + "col172": "j1slb", + "col173": "so6s2", + "col174": "4cbyc", + "col175": "50yqy", + "col176": "4rqg9", + "col177": "das0h", + "col178": "eybiq", + "col179": "arcd6", + "col180": "k7eub", + "col181": "a5tn6", + "col182": "nr50x", + "col183": "erel3", + "col184": "7jski", + "col185": "4ofj9", + "col186": "gapz8", + "col187": "v1xpg", + "col188": "7vr80", + "col189": "yvfmr", + "col190": "tdj8y", + "col191": "9z5am", + "col192": "pz7qg", + "col193": "i7imb", + "col194": "ggl59", + "col195": "ag1n5", + "col196": "0kq5j", + "col197": "xtyhq", + "col198": "ghf80", + "col199": "ogh2i", + "col200": "mrkm1", + "col201": "ffnrs", + "col202": "cclde", + "col203": "3wr29", + "col204": "puvfk", + "col205": "wpduy", + "col206": "t5xkv", + "col207": "zdr9z", + "col208": "w573i", + "col209": "heoha", + "col210": "5rilv", + "col211": "zw73b", + "col212": "zrtbt", + "col213": "vw1w7", + "col214": "j3n0h", + "col215": "tp75c", + "col216": "5d15d", + "col217": "9sko6", + "col218": "1aez2", + "col219": "elunh", + "col220": "eo016", + "col221": "6islj", + "col222": "dom8l", + "col223": "vu8wg", + "col224": "olump", + "col225": "lagt6", + "col226": "ncbxt", + "col227": "q62kl", + "col228": "bd0dv", + "col229": "l5jtk", + "col230": "eb79l", + "col231": "7ebyr", + "col232": "tm2vj", + "col233": "g2nwf", + "col234": "84s0p", + "col235": "2dm88", + "col236": "o8iyd", + "col237": "t3wui", + "col238": "w8ioa", + "col239": "4ytpu", + "col240": "gvjjl", + "col241": "ea1pk", + "col242": "7jtcp", + "col243": "mz93l", + "col244": "hby7a", + "col245": "9gor7", + "col246": "1k59e", + "col247": "l1k1l", + "col248": "4zm8i", + "col249": "5uh4k", + "col250": "54xn4", + "col251": "wpyem", + "col252": "ajxh4", + "col253": "ckdgz", + "col254": "puvcn", + "col255": "z48dc", + "col256": "157sq", + "col257": "4qsrn", + "col258": "xji5i", + "col259": "fnf40", + "col260": "568uw", + "col261": "gg71h", + "col262": "m21cd", + "col263": "ynrdn", + "col264": "1mep3", + "col265": "0abiv", + "col266": "kz94n", + "col267": "n8vh0", + "col268": "sgyf8", + "col269": "lalb3", + "col270": "wq152", + "col271": "wmjck", + "col272": "s5wpg", + "col273": "nu9qn", + "col274": "mlm66", + "col275": "7vygc", + "col276": "o0wa6", + "col277": "d4mlk", + "col278": "pl9zz", + "col279": "r0d90", + "col280": "l8953", + "col281": "nbmdb", + "col282": "oslez", + "col283": "j8xh6", + "col284": "ud07t", + "col285": "uqrje", + "col286": "52m53", + "col287": "9q77t", + "col288": "cakiy", + "col289": "hgivb", + "col290": "spmer", + "col291": "o6cp1", + "col292": "zre40", + "col293": "vbma2", + "col294": "d6cfr", + "col295": "dg6h9", + "col296": "0mtfy", + "col297": "noiz7", + "col298": "wjrvm", + "col299": "fz4rl", + "col300": "x5i6w", + "col301": "vq0kv", + "col302": "qx6d3", + "col303": "pu72v", + "col304": "1rkax", + "col305": "837vn", + "col306": "jzw6c", + "col307": "q5ydx", + "col308": "m7bjv", + "col309": "7dvv4", + "col310": "zdqt5", + "col311": "ijjt9", + "col312": "6zwbp", + "col313": "6a516", + "col314": "h357u", + "col315": "yo8q2", + "col316": "97rxv", + "col317": "5dg8q", + "col318": "bf334", + "col319": "kaip0", + "col320": "n7bu1", + "col321": "9qlw9", + "col322": "pjz82", + "col323": "e3645", + "col324": "nx4yr", + "col325": "ur8zw", + "col326": "zpjyq", + "col327": "y0hf5", + "col328": "qph4a", + "col329": "jv6km", + "col330": "e8pcr", + "col331": "eubaf", + "col332": "fc8ge", + "col333": "o7m24", + "col334": "xyy41", + "col335": "93zo7", + "col336": "8j5bl", + "col337": "mfqgj", + "col338": "s0290", + "col339": "4czk9", + "col340": "b7q8p", + "col341": "ozcnb", + "col342": "3nmvw", + "col343": "k21n0", + "col344": "bfh4v", + "col345": "rknkd", + "col346": "4v13z", + "col347": "dwu8z", + "col348": "ihx2s", + "col349": "octwx", + "col350": "9vywg", + "col351": "7km32", + "col352": "iv3x5", + "col353": "0rjlk", + "col354": "n3ho4", + "col355": "g1mx8", + "col356": "luhf5", + "col357": "dnh1m", + "col358": "evgo4", + "col359": "lcx6n", + "col360": "rvtil", + "col361": "yfq0o", + "col362": "ygt6o", + "col363": "jw5i2", + "col364": "jb1vb", + "col365": "4laie", + "col366": "ihr66", + "col367": "cl83d", + "col368": "2lhk4", + "col369": "lyhuk", + "col370": "8ymio", + "col371": "7e4nf", + "col372": "x8gmq", + "col373": "5ev7q", + "col374": "y8s41", + "col375": "zhpnu", + "col376": "9616j", + "col377": "c90sx", + "col378": "nusii", + "col379": "dq5or", + "col380": "k2ygg", + "col381": "n0y7x", + "col382": "p2yhy", + "col383": "rwztm", + "col384": "ur29o", + "col385": "aydsp", + "col386": "820y4", + "col387": "c85y1", + "col388": "ytxlr", + "col389": "nq322", + "col390": "c2tv7", + "col391": "32jll", + "col392": "y9zfl", + "col393": "6nxqb", + "col394": "jdk4i", + "col395": "anyoy", + "col396": "20pcf", + "col397": "4s9os", + "col398": "kkj2n", + "col399": "di3cs", + "col400": "ub83x", + "col401": "fprd8", + "col402": "88ty1", + "col403": "kjo4t", + "col404": "i85ce", + "col405": "ul1y1", + "col406": "z8mpi", + "col407": "osc3b", + "col408": "5ytpa", + "col409": "kfjc9", + "col410": "1tzhq", + "col411": "oqp1a", + "col412": "t62mh", + "col413": "7z1c9", + "col414": "6381o", + "col415": "em4fe", + "col416": "xh4ef", + "col417": "qz5pc", + "col418": "660sq", + "col419": "faqkv", + "col420": "7eh8z", + "col421": "pn455", + "col422": "adb1o", + "col423": "9e33h", + "col424": "j71e1", + "col425": "8hm27", + "col426": "lrjmr", + "col427": "7uxhg", + "col428": "46xpe", + "col429": "9zydy", + "col430": "q3riq", + "col431": "cu7uy", + "col432": "7dpwn", + "col433": "dk8fi", + "col434": "habq9", + "col435": "e9d2k", + "col436": "gcf17", + "col437": "702kr", + "col438": "ghcb6", + "col439": "l81vq", + "col440": "hz2nv", + "col441": "c0lum", + "col442": "lpxoz", + "col443": "2uj0h", + "col444": "w6pii", + "col445": "k7tye", + "col446": "0w2bj", + "col447": "824zx", + "col448": "p8zi0", + "col449": "xmi92", + "col450": "vpotb", + "col451": "7xulk", + "col452": "854q8", + "col453": "uwg2z", + "col454": "s5mya", + "col455": "yczb3", + "col456": "cbs3s", + "col457": "h3e50", + "col458": "fbi8o", + "col459": "dg31i", + "col460": "2yuxo", + "col461": "dow4k", + "col462": "rdk5w", + "col463": "yleqw", + "col464": "vr6pb", + "col465": "mlo8k", + "col466": "6ptzs", + "col467": "msiuu", + "col468": "de1yv", + "col469": "k6xoo", + "col470": "byc70", + "col471": "6ldn3", + "col472": "6rl0z", + "col473": "1n65o", + "col474": "qhi1k", + "col475": "a7jy9", + "col476": "w9un1", + "col477": "t8ljb", + "col478": "3wtnj", + "col479": "r6sjs", + "col480": "ghbdc", + "col481": "6rz4u", + "col482": "52s3a", + "col483": "0fw7c", + "col484": "g38sp", + "col485": "knnmr", + "col486": "r01th", + "col487": "0qosf", + "col488": "s98ca", + "col489": "rpl06", + "col490": "3zk1g", + "col491": "7yl4s", + "col492": "p7ysh", + "col493": "poefg", + "col494": "js7sb", + "col495": "gxgsd", + "col496": "xh882", + "col497": "8bka6", + "col498": "rn0au", + "col499": "pj68g", + "col500": "3jbm2", + "col501": "afoey", + "col502": "r9ws2", + "col503": "hqlia", + "col504": "j5h0i", + "col505": "9uaot", + "col506": "tguup", + "col507": "7czzk", + "col508": "mqaz3", + "col509": "nsam9", + "col510": "uc63o", + "col511": "jue7z", + "col512": "27x7s", + "col513": "6ma4x", + "col514": "q98b2", + "col515": "7s3ej", + "col516": "wn720", + "col517": "a0p7n", + "col518": "rv4wh", + "col519": "qjfqw", + "col520": "o6z5n", + "col521": "6ee3s", + "col522": "kujsd", + "col523": "zfxj3", + "col524": "cy6m5", + "col525": "tzmgh", + "col526": "hf174", + "col527": "auw9j", + "col528": "98jt9", + "col529": "6qz26", + "col530": "p9102", + "col531": "1eupa", + "col532": "07y6p", + "col533": "gy4sk", + "col534": "yec9z", + "col535": "zd6qm", + "col536": "724y2", + "col537": "95i66", + "col538": "ff3vm", + "col539": "pjcm3", + "col540": "si6op", + "col541": "m8cb4", + "col542": "0wi27", + "col543": "8fjxa", + "col544": "1ov06", + "col545": "noimy", + "col546": "pbc84", + "col547": "xk21q", + "col548": "qzik4", + "col549": "gwnao", + "col550": "mgb3l", + "col551": "pwet1", + "col552": "qavnd", + "col553": "pt6mv", + "col554": "b8l3y", + "col555": "7zvvo", + "col556": "frk2l", + "col557": "mz8re", + "col558": "elqk6", + "col559": "jxwlh", + "col560": "zlbm5", + "col561": "tiusy", + "col562": "muq8q", + "col563": "0d21g", + "col564": "i4ta3", + "col565": "76e3j", + "col566": "p11h8", + "col567": "qv3da", + "col568": "ljmn5", + "col569": "gi2q2", + "col570": "n97mp", + "col571": "mvt27", + "col572": "vmnar", + "col573": "h6nab", + "col574": "e96m8", + "col575": "2zwpn", + "col576": "vvjzd", + "col577": "600m1", + "col578": "f6dgo", + "col579": "7m9qf", + "col580": "2vpig", + "col581": "8h4bh", + "col582": "aqsqw", + "col583": "gy6ba", + "col584": "8v09b", + "col585": "hngk7", + "col586": "ziqwo", + "col587": "eyx8w", + "col588": "bnfxe", + "col589": "5uabk", + "col590": "22j01", + "col591": "iic6h", + "col592": "ict8u", + "col593": "4gxep", + "col594": "dh0bu", + "col595": "irqef", + "col596": "bgl7f", + "col597": "dblkk", + "col598": "nytrt", + "col599": "zo5fv", + "col600": "8grfg", + "col601": "gp6y1", + "col602": "c7zno", + "col603": "fixkl", + "col604": "r6vmu", + "col605": "6awho", + "col606": "t3dzc", + "col607": "y6ip8", + "col608": "lbxls", + "col609": "092qp", + "col610": "l5nvw", + "col611": "jiika", + "col612": "6mopf", + "col613": "9xzan", + "col614": "xj10k", + "col615": "793go", + "col616": "xyyvo", + "col617": "gxiti", + "col618": "y22ne", + "col619": "oyg9k", + "col620": "lb8vm", + "col621": "qfq9q", + "col622": "9sndt", + "col623": "gc2dz", + "col624": "52u78", + "col625": "ko7g8", + "col626": "125yl", + "col627": "svox7", + "col628": "sm9fs", + "col629": "gc1ow", + "col630": "xs1zd", + "col631": "vrthr", + "col632": "9jj35", + "col633": "edzfh", + "col634": "7xxaw", + "col635": "uwzef", + "col636": "3l91t", + "col637": "nmjug", + "col638": "94vge", + "col639": "kbnwk", + "col640": "5aoml", + "col641": "aqhq4", + "col642": "5cijq", + "col643": "qi9y4", + "col644": "k4kqi", + "col645": "6mdqt", + "col646": "by2al", + "col647": "bauc5", + "col648": "ghxyl", + "col649": "16y2a", + "col650": "yshjy", + "col651": "pgqnm", + "col652": "se03e", + "col653": "kqj8i", + "col654": "ewprl", + "col655": "1tj6w", + "col656": "kvtn3", + "col657": "2m29k", + "col658": "rd1d7", + "col659": "f0018", + "col660": "mbdh4", + "col661": "4z0li", + "col662": "qk9rt", + "col663": "kt1es", + "col664": "i9zoc", + "col665": "273hv", + "col666": "y5zlt", + "col667": "nabme", + "col668": "rbyu3", + "col669": "w57wz", + "col670": "4993h", + "col671": "i8dt7", + "col672": "44vqz", + "col673": "zk5bj", + "col674": "ny8ck", + "col675": "hu37f", + "col676": "vraor", + "col677": "3n80p", + "col678": "jmk74", + "col679": "ezu6i", + "col680": "0yaca", + "col681": "ouxsf", + "col682": "eh0x7", + "col683": "a0ft1", + "col684": "kdvaj", + "col685": "ton5s", + "col686": "xly0c", + "col687": "cahyz", + "col688": "rhrjy", + "col689": "h8u4r", + "col690": "vcw9l", + "col691": "hha7n", + "col692": "yik0s", + "col693": "609mb", + "col694": "zw60u", + "col695": "xc06q", + "col696": "q0vo5", + "col697": "yv6u1", + "col698": "zeczb", + "col699": "3c1ee", + "col700": "dwu2q", + "col701": "kkvf8", + "col702": "bpggs", + "col703": "0nt7i", + "col704": "103rx", + "col705": "5tfav", + "col706": "m2e1r", + "col707": "rcqf0", + "col708": "1b989", + "col709": "7fymn", + "col710": "q3f8f", + "col711": "6fgrz", + "col712": "7hinu", + "col713": "nh77h", + "col714": "01ygb", + "col715": "apiko", + "col716": "2mh0z", + "col717": "ydg8w", + "col718": "u40vi", + "col719": "8uhj1", + "col720": "i89mm", + "col721": "75hm7", + "col722": "qazdb", + "col723": "bbgjr", + "col724": "k7ucq", + "col725": "03a0q", + "col726": "j9l5p", + "col727": "hav8v", + "col728": "yv8mc", + "col729": "tl66p", + "col730": "z0qyr", + "col731": "5fzto", + "col732": "9y0k0", + "col733": "kngo9", + "col734": "wwt4x", + "col735": "lvfeb", + "col736": "uiq79", + "col737": "8tw8g", + "col738": "4cfx1", + "col739": "ab14l", + "col740": "8ni1h", + "col741": "zx99j", + "col742": "sko2a", + "col743": "wdone", + "col744": "qrdnb", + "col745": "qy6is", + "col746": "dxvhy", + "col747": "e53bp", + "col748": "hbfez", + "col749": "vie77", + "col750": "k1mz1", + "col751": "9cldq", + "col752": "nfd7s", + "col753": "fm9tx", + "col754": "3p4f7", + "col755": "e9r6k", + "col756": "n9tag", + "col757": "udcsa", + "col758": "p0lcc", + "col759": "vvnze", + "col760": "ff8w0", + "col761": "k3lh5", + "col762": "uqog1", + "col763": "t1iev", + "col764": "2h1hg", + "col765": "f4n7g", + "col766": "5r587", + "col767": "dmyvd", + "col768": "8xnyz", + "col769": "trwtu", + "col770": "umpg1", + "col771": "f43p2", + "col772": "n24m1", + "col773": "y15mf", + "col774": "1yb1p", + "col775": "fq2ld", + "col776": "3ivwo", + "col777": "ryqic", + "col778": "pmeox", + "col779": "4pjm9", + "col780": "pvn1w", + "col781": "2fmbu", + "col782": "oy7yq", + "col783": "f3jh3", + "col784": "f07ls", + "col785": "cwws0", + "col786": "dyegh", + "col787": "3a6lu", + "col788": "vdgr0", + "col789": "vqh8v", + "col790": "ab6w7", + "col791": "h276t", + "col792": "jh9t4", + "col793": "8kgkl", + "col794": "3t9ga", + "col795": "3qpi8", + "col796": "jhcne", + "col797": "qkm42", + "col798": "czfq3", + "col799": "jf0nv", + "col800": "cmo40", + "col801": "unqe4", + "col802": "ztjph", + "col803": "7303b", + "col804": "d1sli", + "col805": "4jghz", + "col806": "lr96a", + "col807": "a88zi", + "col808": "jrfi8", + "col809": "23hr9", + "col810": "g4e7t", + "col811": "osi95", + "col812": "82hw2", + "col813": "wlaqq", + "col814": "kzs1v", + "col815": "7qs8j", + "col816": "rlgpz", + "col817": "l0q6t", + "col818": "2lay4", + "col819": "azldt", + "col820": "lfz1o", + "col821": "tm8it", + "col822": "mekk4", + "col823": "a4q0x", + "col824": "n7bjq", + "col825": "1vxm9", + "col826": "irqop", + "col827": "xbnp0", + "col828": "oq186", + "col829": "d535f", + "col830": "75uig", + "col831": "s2oqf", + "col832": "ljntj", + "col833": "wrioi", + "col834": "im323", + "col835": "xlinc", + "col836": "9e82a", + "col837": "lfbwu", + "col838": "lxjmu", + "col839": "afwnq", + "col840": "8utc6", + "col841": "50ypw", + "col842": "yhz3w", + "col843": "h0bdx", + "col844": "w3lhp", + "col845": "r8fug", + "col846": "og2t9", + "col847": "ifbz7", + "col848": "8czaq", + "col849": "hr73x", + "col850": "11o0p", + "col851": "91ug0", + "col852": "ynuw1", + "col853": "yrph6", + "col854": "rnfk8", + "col855": "f5fge", + "col856": "pt3kk", + "col857": "1gvza", + "col858": "q95v2", + "col859": "jrdoo", + "col860": "xe81n", + "col861": "gbucr", + "col862": "p634j", + "col863": "mza8n", + "col864": "nvu06", + "col865": "qa1s8", + "col866": "9pdcd", + "col867": "g2ui2", + "col868": "de35z", + "col869": "rhnf6", + "col870": "1q1zj", + "col871": "wo3z8", + "col872": "zjvpd", + "col873": "ruobe", + "col874": "w7icw", + "col875": "oask5", + "col876": "tpwqh", + "col877": "vmb3p", + "col878": "sg5y1", + "col879": "d3sfm", + "col880": "tprcb", + "col881": "rq43z", + "col882": "2gv3s", + "col883": "us3zy", + "col884": "tchgc", + "col885": "gu797", + "col886": "ch8g3", + "col887": "5l1ha", + "col888": "79ebr", + "col889": "gtjcx", + "col890": "bmiua", + "col891": "02t48", + "col892": "kfu63", + "col893": "hnrf0", + "col894": "luyx3", + "col895": "3066d", + "col896": "21unn", + "col897": "qee7w", + "col898": "3cr9k", + "col899": "kaad8", + "col900": "7mtdr", + "col901": "ex9uh", + "col902": "r7ymr", + "col903": "2a65f", + "col904": "tfvmw", + "col905": "4uzkx", + "col906": "kbj8y", + "col907": "qs95j", + "col908": "mc5gr", + "col909": "g9vrg", + "col910": "5dl9f", + "col911": "wle52", + "col912": "az8zd", + "col913": "qmduv", + "col914": "5lsfe", + "col915": "rm96j", + "col916": "0u20e", + "col917": "lvvh0", + "col918": "x2e4z", + "col919": "6bqoj", + "col920": "ucmdl", + "col921": "6e062", + "col922": "9c9bw", + "col923": "vhlov", + "col924": "4sb1c", + "col925": "nrnlo", + "col926": "r9fao", + "col927": "uwtoi", + "col928": "d80yy", + "col929": "kyyhu", + "col930": "7qpdl", + "col931": "7ik2q", + "col932": "3aiz3", + "col933": "rqwby", + "col934": "o25m0", + "col935": "31cap", + "col936": "6c6o9", + "col937": "5v2so", + "col938": "g4th2", + "col939": "d3sjc", + "col940": "acuok", + "col941": "3krzc", + "col942": "fkp9r", + "col943": "pnq6m", + "col944": "hdq7a", + "col945": "g3yua", + "col946": "lpsl7", + "col947": "t6gmk", + "col948": "7t2l2", + "col949": "ypxjk", + "col950": "oauxv", + "col951": "oj77q", + "col952": "70bmh", + "col953": "mthpq", + "col954": "eqcso", + "col955": "novq2", + "col956": "tmo6m", + "col957": "cswec", + "col958": "tvo34", + "col959": "xdfyw", + "col960": "q6vii", + "col961": "b9p4h", + "col962": "6rcb9", + "col963": "1egqe", + "col964": "pd86a", + "col965": "8x90t", + "col966": "i6ewz", + "col967": "h75tt", + "col968": "dliox", + "col969": "zdjk4", + "col970": "m0g02", + "col971": "ra53k", + "col972": "xf4e8", + "col973": "ulcic", + "col974": "a1fwl", + "col975": "rs41k", + "col976": "xrm91", + "col977": "xihlk", + "col978": "nckkt", + "col979": "10a7r", + "col980": "m34hf", + "col981": "tvl00", + "col982": "av9mb", + "col983": "qszc1", + "col984": "sl47d", + "col985": "yo0xv", + "col986": "4zkk4", + "col987": "ul6ke", + "col988": "3ukut", + "col989": "qvioe", + "col990": "phl87", + "col991": "aqtb1", + "col992": "1m9bj", + "col993": "dsdc7", + "col994": "15mem", + "col995": "jjt79", + "col996": "pkspf", + "col997": "jtk2n", + "col998": "7xk4k", + "col999": "8arwv" + }, + { + "name": "Lilia Stokes", + "gender": "female", + "col0": "j5qbq", + "col1": "druwz", + "col2": "4lgft", + "col3": "vwvg9", + "col4": "7imw5", + "col5": "1mvb6", + "col6": "p5e93", + "col7": "rkczr", + "col8": "ophvj", + "col9": "3f8z4", + "col10": "h15pg", + "col11": "7zvt7", + "col12": "rf1fp", + "col13": "3vc2z", + "col14": "tuv3n", + "col15": "pdkik", + "col16": "sfu2q", + "col17": "pqqml", + "col18": "9litz", + "col19": "2l3ib", + "col20": "lbaiu", + "col21": "lubat", + "col22": "56eg8", + "col23": "nytvk", + "col24": "cgezk", + "col25": "fhbzk", + "col26": "8ppsa", + "col27": "r5eja", + "col28": "mmx78", + "col29": "naphg", + "col30": "8vb66", + "col31": "v07j7", + "col32": "mhwco", + "col33": "sap70", + "col34": "24o3x", + "col35": "3qrap", + "col36": "am6hb", + "col37": "p938i", + "col38": "7iakl", + "col39": "lonii", + "col40": "zngmy", + "col41": "844dm", + "col42": "i5r7t", + "col43": "uoaxj", + "col44": "ueya2", + "col45": "h5dkv", + "col46": "12m0o", + "col47": "1qtuj", + "col48": "9v5kq", + "col49": "5srar", + "col50": "c9xob", + "col51": "qopd6", + "col52": "dbdt8", + "col53": "sb20h", + "col54": "v894y", + "col55": "u6po1", + "col56": "v1xrc", + "col57": "roech", + "col58": "w2ofi", + "col59": "nxgog", + "col60": "le5l0", + "col61": "4qr3e", + "col62": "bl0kb", + "col63": "ft5vz", + "col64": "1hzl0", + "col65": "16gvn", + "col66": "5pep9", + "col67": "xympz", + "col68": "db7ds", + "col69": "9hkil", + "col70": "v1gw6", + "col71": "c267a", + "col72": "lbjli", + "col73": "ten9b", + "col74": "ztztf", + "col75": "fpql3", + "col76": "fo7tu", + "col77": "0owa5", + "col78": "z4gfw", + "col79": "ez5u8", + "col80": "bg02f", + "col81": "j7m06", + "col82": "247qa", + "col83": "ouo4x", + "col84": "psqds", + "col85": "qy5o4", + "col86": "h1tv2", + "col87": "qtfng", + "col88": "boqob", + "col89": "yj9d0", + "col90": "5qwtu", + "col91": "4357r", + "col92": "xpk0p", + "col93": "qznl6", + "col94": "xn8kz", + "col95": "2kmta", + "col96": "28xtg", + "col97": "4pcbv", + "col98": "l3jsw", + "col99": "bo46f", + "col100": "ottwy", + "col101": "0dcdi", + "col102": "rra7h", + "col103": "kjkyp", + "col104": "8lwth", + "col105": "lvmde", + "col106": "57rig", + "col107": "mjecj", + "col108": "4ij9i", + "col109": "jrijz", + "col110": "x4jbi", + "col111": "mck76", + "col112": "5b0j0", + "col113": "fcs4i", + "col114": "9l5d2", + "col115": "oz065", + "col116": "1nms6", + "col117": "hyh9c", + "col118": "azw16", + "col119": "6bwgv", + "col120": "40z3r", + "col121": "h9a9w", + "col122": "omicb", + "col123": "ucpy4", + "col124": "up4nr", + "col125": "aun2z", + "col126": "ttum3", + "col127": "6urud", + "col128": "6p0pk", + "col129": "is8iu", + "col130": "3hr39", + "col131": "mmtpk", + "col132": "rltum", + "col133": "ktw69", + "col134": "5n2zk", + "col135": "hwjka", + "col136": "qdoqg", + "col137": "tve2f", + "col138": "h6h3e", + "col139": "2ye3r", + "col140": "artdr", + "col141": "y8i45", + "col142": "h08xq", + "col143": "mutvh", + "col144": "dkjb5", + "col145": "839w6", + "col146": "zu4q5", + "col147": "xzvqy", + "col148": "tjdoo", + "col149": "2wxxb", + "col150": "j18as", + "col151": "u727j", + "col152": "4vlgw", + "col153": "k8st3", + "col154": "w6fog", + "col155": "nisih", + "col156": "ffwal", + "col157": "lmwfc", + "col158": "vyqqx", + "col159": "1dhhx", + "col160": "qzfpy", + "col161": "3s5g0", + "col162": "a7wtx", + "col163": "t4o3c", + "col164": "b9089", + "col165": "b8oth", + "col166": "x6j9e", + "col167": "ztaur", + "col168": "cwf1v", + "col169": "scdwq", + "col170": "w6ksx", + "col171": "849hi", + "col172": "s0601", + "col173": "wzozj", + "col174": "sh6cz", + "col175": "3ubuw", + "col176": "c6xwv", + "col177": "mgc47", + "col178": "14trh", + "col179": "yw6hu", + "col180": "pgz4s", + "col181": "9w0h7", + "col182": "fev8m", + "col183": "as5my", + "col184": "xdaos", + "col185": "51bp1", + "col186": "8is2l", + "col187": "321hr", + "col188": "deeii", + "col189": "1yapw", + "col190": "ezppj", + "col191": "l7nz1", + "col192": "edd0x", + "col193": "qjd1j", + "col194": "isg2y", + "col195": "bfw8d", + "col196": "9gpid", + "col197": "kv1lk", + "col198": "z8jjk", + "col199": "pgagq", + "col200": "inysq", + "col201": "i5k7i", + "col202": "a9c5j", + "col203": "kshlz", + "col204": "koddq", + "col205": "67q4v", + "col206": "xq195", + "col207": "5kx3j", + "col208": "oyijr", + "col209": "z37yt", + "col210": "dx1l0", + "col211": "ycuov", + "col212": "984p4", + "col213": "yfprg", + "col214": "t9jmt", + "col215": "y8upr", + "col216": "ruxd3", + "col217": "uvqje", + "col218": "tsfqi", + "col219": "h9abo", + "col220": "taqeb", + "col221": "yrspd", + "col222": "vy0ug", + "col223": "165uc", + "col224": "54cmk", + "col225": "uu0uy", + "col226": "vqn4n", + "col227": "0w781", + "col228": "r3oya", + "col229": "dotjc", + "col230": "heqgz", + "col231": "i6mo4", + "col232": "rv8d7", + "col233": "fefxx", + "col234": "2khc9", + "col235": "tvklu", + "col236": "7xnkz", + "col237": "k9t3y", + "col238": "hhw2w", + "col239": "xnc8d", + "col240": "93hsz", + "col241": "mx1du", + "col242": "20lwa", + "col243": "1jirt", + "col244": "u5on2", + "col245": "euszz", + "col246": "dp6fz", + "col247": "dswis", + "col248": "l15o9", + "col249": "074b4", + "col250": "kagko", + "col251": "50mx4", + "col252": "3ipl2", + "col253": "1mdf2", + "col254": "z4qpa", + "col255": "0uw2g", + "col256": "3iwg6", + "col257": "qbw18", + "col258": "mh28e", + "col259": "gguib", + "col260": "fothe", + "col261": "5mv9j", + "col262": "bjpge", + "col263": "1kmmh", + "col264": "qgb6h", + "col265": "ptf4c", + "col266": "v9bd5", + "col267": "i3zdj", + "col268": "q7l1t", + "col269": "3cl1l", + "col270": "zdxbk", + "col271": "x8xbk", + "col272": "pkp43", + "col273": "9g9sp", + "col274": "6k5nm", + "col275": "lp190", + "col276": "p5q22", + "col277": "is4d4", + "col278": "pfodc", + "col279": "6u2zp", + "col280": "mjotn", + "col281": "vlv4t", + "col282": "420fn", + "col283": "3r4rk", + "col284": "qvxbk", + "col285": "mrfyr", + "col286": "abjka", + "col287": "a7tyq", + "col288": "0u7hh", + "col289": "faqwr", + "col290": "dfyua", + "col291": "gdlcu", + "col292": "fgtjc", + "col293": "ie6od", + "col294": "wap4h", + "col295": "nm1me", + "col296": "85tj5", + "col297": "tyrel", + "col298": "akq62", + "col299": "rcb98", + "col300": "aufd4", + "col301": "30xbl", + "col302": "cvrxj", + "col303": "byjuy", + "col304": "peki0", + "col305": "gbamm", + "col306": "6fnlr", + "col307": "ajvq0", + "col308": "3lhc7", + "col309": "mvf52", + "col310": "cx6ss", + "col311": "p82c2", + "col312": "xpzxo", + "col313": "98ncc", + "col314": "mak58", + "col315": "2vp4r", + "col316": "a2488", + "col317": "eqzlx", + "col318": "we78u", + "col319": "bt477", + "col320": "3z97j", + "col321": "rxw11", + "col322": "q4m4g", + "col323": "hglte", + "col324": "d9llu", + "col325": "mcf39", + "col326": "916o2", + "col327": "cexv3", + "col328": "3l5yh", + "col329": "6sfg8", + "col330": "gcjdi", + "col331": "vnkxn", + "col332": "rj1mo", + "col333": "pg71w", + "col334": "cd4pp", + "col335": "x8xmh", + "col336": "e4xfj", + "col337": "4czpz", + "col338": "xb7oq", + "col339": "0tipo", + "col340": "4gep4", + "col341": "m6t5q", + "col342": "ktp2c", + "col343": "e9ez9", + "col344": "nzpqw", + "col345": "b8b69", + "col346": "ihp7h", + "col347": "ionng", + "col348": "ml7qo", + "col349": "j6stl", + "col350": "285jg", + "col351": "leagy", + "col352": "rxqi2", + "col353": "2lx1z", + "col354": "q1okz", + "col355": "tanvm", + "col356": "zkzet", + "col357": "qfo65", + "col358": "9mgkr", + "col359": "92337", + "col360": "ska4s", + "col361": "u3kft", + "col362": "nc9s4", + "col363": "gy0uf", + "col364": "939ac", + "col365": "pvsnc", + "col366": "kco45", + "col367": "ufo59", + "col368": "o0uea", + "col369": "zc80w", + "col370": "3rtv6", + "col371": "qxehf", + "col372": "71kvr", + "col373": "0bwk0", + "col374": "hkv8t", + "col375": "z5gz6", + "col376": "gp8im", + "col377": "746ab", + "col378": "vgxbd", + "col379": "xsgkg", + "col380": "pri20", + "col381": "qmtaw", + "col382": "zhz0n", + "col383": "3kmss", + "col384": "z86oz", + "col385": "oz1le", + "col386": "3saph", + "col387": "rzy6c", + "col388": "5x11p", + "col389": "ntq0s", + "col390": "ey0qc", + "col391": "c5c4v", + "col392": "mxkmb", + "col393": "l0l9s", + "col394": "d2cut", + "col395": "bilcb", + "col396": "k1nqg", + "col397": "nuj2r", + "col398": "dhhzd", + "col399": "822qs", + "col400": "r4cab", + "col401": "7vfnd", + "col402": "enxnd", + "col403": "lfsbg", + "col404": "kp808", + "col405": "ik656", + "col406": "cnnu6", + "col407": "d8w4b", + "col408": "h51tk", + "col409": "kpakj", + "col410": "1fr5i", + "col411": "kaett", + "col412": "w6yr3", + "col413": "qmigr", + "col414": "2979r", + "col415": "pi66s", + "col416": "jipj4", + "col417": "no8m2", + "col418": "npypg", + "col419": "xachn", + "col420": "93xly", + "col421": "z68xl", + "col422": "ur0iy", + "col423": "ldhgo", + "col424": "rvhp6", + "col425": "fbutb", + "col426": "s18mq", + "col427": "v5byo", + "col428": "4m25d", + "col429": "osk3f", + "col430": "ce03m", + "col431": "wojx0", + "col432": "1gvug", + "col433": "uoi1j", + "col434": "x71qk", + "col435": "1o0g4", + "col436": "deczp", + "col437": "riz7o", + "col438": "v9kmi", + "col439": "a3f4k", + "col440": "l848u", + "col441": "mup5y", + "col442": "y1q7k", + "col443": "a06o7", + "col444": "vtovi", + "col445": "khoj3", + "col446": "izw9t", + "col447": "8xlv3", + "col448": "jl8ll", + "col449": "kf22h", + "col450": "e7uys", + "col451": "vatom", + "col452": "lqlih", + "col453": "0eta1", + "col454": "14w2l", + "col455": "bydnp", + "col456": "svsly", + "col457": "me1db", + "col458": "3gh1w", + "col459": "z47bz", + "col460": "icosr", + "col461": "kvhpp", + "col462": "qmbxr", + "col463": "u6dv5", + "col464": "vlkrw", + "col465": "759gr", + "col466": "rm9rk", + "col467": "sv9h3", + "col468": "07n00", + "col469": "kjqad", + "col470": "47l0j", + "col471": "9vhdk", + "col472": "fk8gf", + "col473": "50qdk", + "col474": "5hfew", + "col475": "wrfcv", + "col476": "k0tow", + "col477": "z68rv", + "col478": "srwbn", + "col479": "lepb0", + "col480": "51bac", + "col481": "q4ojg", + "col482": "cpseb", + "col483": "lxmmv", + "col484": "m78oh", + "col485": "zjlwd", + "col486": "2fxu2", + "col487": "uty1z", + "col488": "ydasb", + "col489": "irpuy", + "col490": "erzgr", + "col491": "992ox", + "col492": "ydz7i", + "col493": "cgteq", + "col494": "n7ps1", + "col495": "mfars", + "col496": "znxl5", + "col497": "341r9", + "col498": "z61yw", + "col499": "i9oje", + "col500": "plkok", + "col501": "oyxsh", + "col502": "mwy6s", + "col503": "urinq", + "col504": "ubbrb", + "col505": "oofj6", + "col506": "oqqd1", + "col507": "cyb2k", + "col508": "gvfrn", + "col509": "d81us", + "col510": "ip28l", + "col511": "8dsh4", + "col512": "dasuh", + "col513": "hln7b", + "col514": "puaft", + "col515": "dcr4n", + "col516": "t52lz", + "col517": "gy9r6", + "col518": "s6h5s", + "col519": "zz619", + "col520": "26kd9", + "col521": "00bn0", + "col522": "x4xan", + "col523": "6m2wg", + "col524": "6hyhw", + "col525": "qvj7r", + "col526": "doi59", + "col527": "vq1k6", + "col528": "82rkt", + "col529": "tesn2", + "col530": "rw78h", + "col531": "xzbdx", + "col532": "y9qn2", + "col533": "l9k8i", + "col534": "6cbpw", + "col535": "z6629", + "col536": "7e99k", + "col537": "66mq7", + "col538": "cxgen", + "col539": "c2vhs", + "col540": "7l6c7", + "col541": "f1esx", + "col542": "m0t09", + "col543": "nxhdn", + "col544": "v4znk", + "col545": "7t3dq", + "col546": "8fnuc", + "col547": "4e1tw", + "col548": "l7h92", + "col549": "t2qps", + "col550": "a5f5s", + "col551": "nwoii", + "col552": "mbmcc", + "col553": "9vdnd", + "col554": "tvkh4", + "col555": "au86m", + "col556": "dv4xe", + "col557": "xh0v5", + "col558": "kz4fq", + "col559": "daife", + "col560": "jkffn", + "col561": "3ky3l", + "col562": "dwbok", + "col563": "6ngzs", + "col564": "jrt07", + "col565": "rqlc3", + "col566": "ek5vi", + "col567": "4d9we", + "col568": "6i63v", + "col569": "oiidm", + "col570": "fqydw", + "col571": "wvyuc", + "col572": "2g8q5", + "col573": "y5b0o", + "col574": "b3h1c", + "col575": "7l4gt", + "col576": "332bz", + "col577": "q2v5t", + "col578": "75300", + "col579": "f9q3u", + "col580": "n7e8e", + "col581": "wkb9i", + "col582": "3vmxo", + "col583": "1ut9c", + "col584": "yswez", + "col585": "xut2j", + "col586": "s5o0x", + "col587": "mmy4j", + "col588": "557is", + "col589": "duqzd", + "col590": "g5cqj", + "col591": "fwz5m", + "col592": "125h3", + "col593": "u2b90", + "col594": "dqgk7", + "col595": "ic92d", + "col596": "k4dwd", + "col597": "m07pd", + "col598": "km3wz", + "col599": "qt2tf", + "col600": "rxcnr", + "col601": "yf43e", + "col602": "2wx52", + "col603": "5c9gl", + "col604": "ub3qq", + "col605": "1repi", + "col606": "8katl", + "col607": "wgjc9", + "col608": "bjmit", + "col609": "wi5tc", + "col610": "p15s1", + "col611": "s1don", + "col612": "ol6mi", + "col613": "2y5s1", + "col614": "rzls5", + "col615": "wlwut", + "col616": "g82j8", + "col617": "psm3w", + "col618": "7ufk4", + "col619": "gev0v", + "col620": "qr0ci", + "col621": "awv66", + "col622": "xkguc", + "col623": "f94h2", + "col624": "mgoos", + "col625": "05l4p", + "col626": "bbes2", + "col627": "0dngd", + "col628": "uk0ox", + "col629": "ju1h9", + "col630": "440rc", + "col631": "suymk", + "col632": "30o0a", + "col633": "ldlxc", + "col634": "8d7ls", + "col635": "xji1u", + "col636": "lof5s", + "col637": "4hwvp", + "col638": "upsyt", + "col639": "nfij6", + "col640": "29wf5", + "col641": "tcguk", + "col642": "lfqr2", + "col643": "9qjmo", + "col644": "a089p", + "col645": "e541e", + "col646": "w56yc", + "col647": "o15uw", + "col648": "gf2ya", + "col649": "snqyk", + "col650": "ys2ly", + "col651": "87wub", + "col652": "tmb81", + "col653": "xrv5j", + "col654": "ujxy9", + "col655": "2eqk4", + "col656": "glijv", + "col657": "dvzd6", + "col658": "w6rtc", + "col659": "ce1f4", + "col660": "8s5vb", + "col661": "8g4em", + "col662": "r20vf", + "col663": "lkq3j", + "col664": "61iar", + "col665": "j626k", + "col666": "9o7ju", + "col667": "vd3po", + "col668": "msvep", + "col669": "tc3pf", + "col670": "1dzvp", + "col671": "jb0f0", + "col672": "fctkj", + "col673": "iicnu", + "col674": "dnv0x", + "col675": "nses3", + "col676": "cnp1w", + "col677": "3sta2", + "col678": "3fio5", + "col679": "q5wql", + "col680": "2izr1", + "col681": "ihlvm", + "col682": "73a34", + "col683": "84et4", + "col684": "6q1x3", + "col685": "b4qy8", + "col686": "vzotr", + "col687": "x7334", + "col688": "m3v08", + "col689": "6puyp", + "col690": "a3wh5", + "col691": "y9jst", + "col692": "bbqfq", + "col693": "nzf0f", + "col694": "9qf80", + "col695": "zwlxf", + "col696": "t5u2p", + "col697": "ymsqx", + "col698": "xbo1i", + "col699": "gljwh", + "col700": "t61sk", + "col701": "5pb1u", + "col702": "pxp5e", + "col703": "0470c", + "col704": "3oqp9", + "col705": "eadjw", + "col706": "725ro", + "col707": "xe0sq", + "col708": "rxufo", + "col709": "hmr5w", + "col710": "qxpph", + "col711": "wj2a8", + "col712": "7zzi5", + "col713": "puoox", + "col714": "kiuve", + "col715": "u6cy8", + "col716": "cc1mh", + "col717": "uw1co", + "col718": "timdz", + "col719": "p0ko2", + "col720": "6jq5x", + "col721": "sqiab", + "col722": "apru3", + "col723": "vgyk0", + "col724": "ivbc5", + "col725": "2bb9t", + "col726": "xan14", + "col727": "4op2l", + "col728": "4y2sf", + "col729": "kdvj0", + "col730": "ow6cw", + "col731": "u84uo", + "col732": "10lgx", + "col733": "s25ak", + "col734": "8cdlx", + "col735": "d77gr", + "col736": "964xn", + "col737": "ec3ic", + "col738": "7tr00", + "col739": "iis8o", + "col740": "6cs8x", + "col741": "d9uia", + "col742": "43hu7", + "col743": "80fm9", + "col744": "oe7gy", + "col745": "kkyaj", + "col746": "3q1qv", + "col747": "bw8vi", + "col748": "fi0xz", + "col749": "uuvz5", + "col750": "j712n", + "col751": "jhrdq", + "col752": "i54pm", + "col753": "aoh1r", + "col754": "anj14", + "col755": "zs8kn", + "col756": "73gpf", + "col757": "culg0", + "col758": "htdj9", + "col759": "dw4t5", + "col760": "usft8", + "col761": "kntz8", + "col762": "2j7mu", + "col763": "4b7py", + "col764": "893xa", + "col765": "8vh4v", + "col766": "wloam", + "col767": "8ha4m", + "col768": "6e2l0", + "col769": "9wgsn", + "col770": "916ke", + "col771": "gh1xa", + "col772": "6tt2g", + "col773": "f4jfd", + "col774": "ss4d9", + "col775": "36bl7", + "col776": "h57ns", + "col777": "08cdf", + "col778": "nnkcc", + "col779": "l4zx6", + "col780": "18ak1", + "col781": "8oned", + "col782": "l5658", + "col783": "vbip6", + "col784": "hhvsr", + "col785": "bmvtz", + "col786": "texsi", + "col787": "b861c", + "col788": "lqmsl", + "col789": "9vcbt", + "col790": "4m9ni", + "col791": "5clqo", + "col792": "qfyw0", + "col793": "2qm6h", + "col794": "hne2a", + "col795": "r5iky", + "col796": "kvr5n", + "col797": "30k38", + "col798": "k0sbh", + "col799": "vw9xr", + "col800": "dqtbm", + "col801": "tkeu7", + "col802": "wskd0", + "col803": "2t3w0", + "col804": "6ljj5", + "col805": "1m0ge", + "col806": "mrl6f", + "col807": "bknjv", + "col808": "p6azc", + "col809": "qksgx", + "col810": "r0tvc", + "col811": "7wcyn", + "col812": "uycba", + "col813": "oq12m", + "col814": "4y8w9", + "col815": "t9685", + "col816": "bxloj", + "col817": "13qs8", + "col818": "6h2gr", + "col819": "y47ot", + "col820": "nll03", + "col821": "h9604", + "col822": "pxhic", + "col823": "0x95s", + "col824": "rik95", + "col825": "jky21", + "col826": "o1zal", + "col827": "py8cw", + "col828": "u4ytw", + "col829": "hso0r", + "col830": "zsgnx", + "col831": "vks4z", + "col832": "o5clo", + "col833": "k8rce", + "col834": "9y3e1", + "col835": "d04ki", + "col836": "8lxsx", + "col837": "zp8li", + "col838": "l9tro", + "col839": "0raya", + "col840": "xwfxu", + "col841": "g9gev", + "col842": "m7h3v", + "col843": "vcys0", + "col844": "7ygd8", + "col845": "q6wy1", + "col846": "3baja", + "col847": "pwwc1", + "col848": "jwoga", + "col849": "sethc", + "col850": "tplml", + "col851": "08n2j", + "col852": "8mohh", + "col853": "f2anj", + "col854": "3hwym", + "col855": "bgq5q", + "col856": "9u5ie", + "col857": "qjtgv", + "col858": "1es7y", + "col859": "j0lxt", + "col860": "u28yh", + "col861": "16bsc", + "col862": "xu8vk", + "col863": "pq40u", + "col864": "5i1n3", + "col865": "cackd", + "col866": "dv5u2", + "col867": "7wwxy", + "col868": "7sjqi", + "col869": "6ea0f", + "col870": "uk2qx", + "col871": "pnurw", + "col872": "fo7cm", + "col873": "vxnrr", + "col874": "v606r", + "col875": "ziznq", + "col876": "xp9sx", + "col877": "t6vm9", + "col878": "52imz", + "col879": "co987", + "col880": "1o7mv", + "col881": "cloby", + "col882": "katqc", + "col883": "e66xv", + "col884": "xo448", + "col885": "dod39", + "col886": "wug8m", + "col887": "kz1av", + "col888": "3y4wd", + "col889": "uz2qh", + "col890": "exvjc", + "col891": "j97rl", + "col892": "t5qbv", + "col893": "uuyhw", + "col894": "72wd4", + "col895": "5vgpg", + "col896": "g5cr5", + "col897": "l7vwl", + "col898": "omy3c", + "col899": "2sobk", + "col900": "zhtt3", + "col901": "1688b", + "col902": "g5ch0", + "col903": "ztymk", + "col904": "zgy3t", + "col905": "wkpy9", + "col906": "pji2c", + "col907": "j0703", + "col908": "yh06j", + "col909": "2y58q", + "col910": "85s9x", + "col911": "o7dw8", + "col912": "3lczp", + "col913": "ezyyj", + "col914": "x96cy", + "col915": "3vb75", + "col916": "815ea", + "col917": "0lcdh", + "col918": "ruqx4", + "col919": "fpev8", + "col920": "og47d", + "col921": "gumu3", + "col922": "00mfn", + "col923": "xr57k", + "col924": "ng9tc", + "col925": "dna6t", + "col926": "wzc2x", + "col927": "stbc0", + "col928": "kzxsr", + "col929": "miobq", + "col930": "k3w97", + "col931": "e6x5k", + "col932": "jwzrw", + "col933": "0q4oo", + "col934": "79iob", + "col935": "72hnt", + "col936": "3myjs", + "col937": "g7shh", + "col938": "8n4kl", + "col939": "fy7tb", + "col940": "4a6yl", + "col941": "rixup", + "col942": "b5q7t", + "col943": "fljsf", + "col944": "yx4q3", + "col945": "7b8jt", + "col946": "hhgh7", + "col947": "xlofi", + "col948": "1gibf", + "col949": "hpmfk", + "col950": "vmxf0", + "col951": "upan7", + "col952": "b43ap", + "col953": "1blsd", + "col954": "b4e9h", + "col955": "9qbbl", + "col956": "x6qfv", + "col957": "9c2rj", + "col958": "x62pu", + "col959": "1zc45", + "col960": "u2d17", + "col961": "d4gj2", + "col962": "bg1l6", + "col963": "5a2ab", + "col964": "thk21", + "col965": "p0bua", + "col966": "lowee", + "col967": "4fp3t", + "col968": "lmu5p", + "col969": "oquk9", + "col970": "wybnz", + "col971": "6f8r6", + "col972": "rxfsn", + "col973": "pcyrr", + "col974": "284of", + "col975": "d2vx7", + "col976": "cquh9", + "col977": "6ww1e", + "col978": "ygx14", + "col979": "fi3e9", + "col980": "sr6ew", + "col981": "jl3gj", + "col982": "k5jrh", + "col983": "02d6z", + "col984": "hzl5s", + "col985": "z653u", + "col986": "84t0e", + "col987": "mrctp", + "col988": "dhhy5", + "col989": "wujow", + "col990": "6mz9r", + "col991": "smhmf", + "col992": "p3fir", + "col993": "yb1qj", + "col994": "x9u8d", + "col995": "y28f8", + "col996": "9cctt", + "col997": "meu4s", + "col998": "60u0v", + "col999": "4mo4x" + }, + { + "name": "Solis Elliott", + "gender": "male", + "col0": "rjfn6", + "col1": "cpf48", + "col2": "y72fd", + "col3": "eu2h1", + "col4": "5xxhr", + "col5": "vgcke", + "col6": "ze16j", + "col7": "iei1t", + "col8": "dfov8", + "col9": "gkeiq", + "col10": "uuqc7", + "col11": "nqlds", + "col12": "hfuea", + "col13": "22pmz", + "col14": "93kfo", + "col15": "9v9qb", + "col16": "ufp23", + "col17": "56c2t", + "col18": "eonfn", + "col19": "w2tpx", + "col20": "p8arf", + "col21": "s26wz", + "col22": "gqj1w", + "col23": "223oi", + "col24": "t9kk6", + "col25": "1rk9n", + "col26": "35nfd", + "col27": "cept2", + "col28": "hyw9p", + "col29": "tq8zi", + "col30": "s0ur7", + "col31": "6vra6", + "col32": "rj0ga", + "col33": "3hjaj", + "col34": "k5ceg", + "col35": "3767l", + "col36": "lvwm3", + "col37": "592rj", + "col38": "q4ah7", + "col39": "72wdu", + "col40": "zj8sl", + "col41": "l03wh", + "col42": "hmzw1", + "col43": "1gd9q", + "col44": "z2mpv", + "col45": "6s4wa", + "col46": "xmbj1", + "col47": "o5fb0", + "col48": "hfp7g", + "col49": "8y0ng", + "col50": "d2soi", + "col51": "5g94o", + "col52": "8qyym", + "col53": "l9sfa", + "col54": "qqh0i", + "col55": "gpdv1", + "col56": "klkjb", + "col57": "ys806", + "col58": "lsuol", + "col59": "dqzni", + "col60": "qnpmw", + "col61": "3apyj", + "col62": "hxmb8", + "col63": "mqpr6", + "col64": "1g3qg", + "col65": "lj8ai", + "col66": "jn7yk", + "col67": "zmh7l", + "col68": "kkg97", + "col69": "cxjg6", + "col70": "xnkdj", + "col71": "pampn", + "col72": "xcbjs", + "col73": "b78dd", + "col74": "gjy1k", + "col75": "wxi5z", + "col76": "tm31v", + "col77": "79o6d", + "col78": "uybv5", + "col79": "h0ps3", + "col80": "yaomh", + "col81": "ogf4p", + "col82": "04lgb", + "col83": "t1q5z", + "col84": "otoa4", + "col85": "kd82c", + "col86": "d5lb0", + "col87": "1ifuo", + "col88": "l6xnw", + "col89": "1q7k9", + "col90": "utfx0", + "col91": "hnw8f", + "col92": "xxa3e", + "col93": "0ipub", + "col94": "4gnhv", + "col95": "gznoe", + "col96": "dz0rn", + "col97": "2hrb9", + "col98": "s7fm3", + "col99": "1cvo0", + "col100": "2rom2", + "col101": "7o3ey", + "col102": "bz9c7", + "col103": "hs0z3", + "col104": "si4ex", + "col105": "zzovi", + "col106": "is1c6", + "col107": "ded27", + "col108": "26ouw", + "col109": "rz7c0", + "col110": "cid1y", + "col111": "hdtg3", + "col112": "0o4xf", + "col113": "lp32n", + "col114": "52zob", + "col115": "ryiqo", + "col116": "dlrka", + "col117": "juk1j", + "col118": "ieiai", + "col119": "rja0g", + "col120": "384dn", + "col121": "9a3x5", + "col122": "i572l", + "col123": "kdpms", + "col124": "impmy", + "col125": "wd8fl", + "col126": "bmpln", + "col127": "mr06w", + "col128": "xuwhw", + "col129": "805f8", + "col130": "yiwu9", + "col131": "41k3l", + "col132": "upwgc", + "col133": "lkh2p", + "col134": "kknr5", + "col135": "bfdtd", + "col136": "60131", + "col137": "9h43z", + "col138": "5qlu9", + "col139": "likge", + "col140": "8kvob", + "col141": "01g3h", + "col142": "0323s", + "col143": "ssk2p", + "col144": "dui7h", + "col145": "fb4x8", + "col146": "gvqo5", + "col147": "zi3ls", + "col148": "505p5", + "col149": "iuv6y", + "col150": "nlh5y", + "col151": "6ca95", + "col152": "vo40v", + "col153": "9e86g", + "col154": "dd0wr", + "col155": "yhx8r", + "col156": "p7xga", + "col157": "ahpcl", + "col158": "4rmdl", + "col159": "y4ira", + "col160": "ypez5", + "col161": "6qgwl", + "col162": "5t36z", + "col163": "7xie3", + "col164": "59e0u", + "col165": "ssknm", + "col166": "4dvj3", + "col167": "ikz3d", + "col168": "imsfu", + "col169": "fxx43", + "col170": "fk731", + "col171": "hm8p7", + "col172": "b4lyc", + "col173": "39xn1", + "col174": "qj30a", + "col175": "j62lo", + "col176": "mwx9z", + "col177": "gliqw", + "col178": "iqiij", + "col179": "tlm85", + "col180": "og1ww", + "col181": "tzmez", + "col182": "h8tfk", + "col183": "w1y2l", + "col184": "r6xxx", + "col185": "wmkpw", + "col186": "7bkfk", + "col187": "ie23u", + "col188": "vrfbp", + "col189": "0f76i", + "col190": "tpcew", + "col191": "guow7", + "col192": "3zpu6", + "col193": "d8ec7", + "col194": "ari9i", + "col195": "22ctc", + "col196": "wiu33", + "col197": "3o1n6", + "col198": "qzj8k", + "col199": "l4b5t", + "col200": "3bb1b", + "col201": "lzo3e", + "col202": "uegm4", + "col203": "d9zxd", + "col204": "glcvp", + "col205": "2qaqo", + "col206": "gqf0s", + "col207": "ig5n7", + "col208": "kvxhd", + "col209": "syt82", + "col210": "dicum", + "col211": "37sgp", + "col212": "jr105", + "col213": "ssx48", + "col214": "p10y7", + "col215": "sqqgf", + "col216": "4v7gl", + "col217": "p1q00", + "col218": "7hzgh", + "col219": "a1mek", + "col220": "tn6du", + "col221": "7xuqg", + "col222": "kzajq", + "col223": "oig82", + "col224": "c97s4", + "col225": "n0pw9", + "col226": "fgtro", + "col227": "k8upy", + "col228": "vr38p", + "col229": "ze5ec", + "col230": "z6m97", + "col231": "zdnnl", + "col232": "67wds", + "col233": "7m4mj", + "col234": "opcgu", + "col235": "ukub5", + "col236": "153h0", + "col237": "imqn2", + "col238": "r05xz", + "col239": "gvg1d", + "col240": "dric0", + "col241": "j7etj", + "col242": "wyxtq", + "col243": "9m1qj", + "col244": "1153k", + "col245": "mw5vh", + "col246": "rr3d0", + "col247": "bv4db", + "col248": "0yins", + "col249": "fhukb", + "col250": "4g8sx", + "col251": "gc60c", + "col252": "xp8wu", + "col253": "5emsl", + "col254": "5zwnw", + "col255": "c1k9t", + "col256": "dr62w", + "col257": "yqvsk", + "col258": "2wcp5", + "col259": "ut7hh", + "col260": "nz14n", + "col261": "rwklb", + "col262": "81rgy", + "col263": "rya3c", + "col264": "zgwx3", + "col265": "kcb1b", + "col266": "prq5l", + "col267": "57zqs", + "col268": "f4rj0", + "col269": "uqw5e", + "col270": "9ztlz", + "col271": "u84qe", + "col272": "6wfz8", + "col273": "6wt0v", + "col274": "2q6rv", + "col275": "zuh55", + "col276": "273cn", + "col277": "5koq6", + "col278": "r669z", + "col279": "znw45", + "col280": "rvz1b", + "col281": "aq3hp", + "col282": "dh89w", + "col283": "cw1dl", + "col284": "dwt6r", + "col285": "y5fsp", + "col286": "2imf3", + "col287": "uxxur", + "col288": "xg8sr", + "col289": "p90wq", + "col290": "wb4xj", + "col291": "efetw", + "col292": "jidn5", + "col293": "ljprj", + "col294": "11c5z", + "col295": "yitxa", + "col296": "ahwnh", + "col297": "koh55", + "col298": "6ml8u", + "col299": "4h7eo", + "col300": "e9acf", + "col301": "13hi8", + "col302": "qipky", + "col303": "acrqt", + "col304": "86ori", + "col305": "p0ssz", + "col306": "d1w09", + "col307": "65uye", + "col308": "qkeo2", + "col309": "vy8gh", + "col310": "znmbf", + "col311": "e9aup", + "col312": "3wibw", + "col313": "6eqjr", + "col314": "zxy1c", + "col315": "ybnlh", + "col316": "7jhjt", + "col317": "9gfjz", + "col318": "pr79n", + "col319": "kt9fq", + "col320": "sv33a", + "col321": "3ffx4", + "col322": "y0pnz", + "col323": "mmqar", + "col324": "9dtjk", + "col325": "yheu2", + "col326": "2l21s", + "col327": "i7prx", + "col328": "mdzzg", + "col329": "iwybh", + "col330": "exzyo", + "col331": "5rcsm", + "col332": "l0nzi", + "col333": "z0grv", + "col334": "vmfiz", + "col335": "y2qz1", + "col336": "cucbw", + "col337": "5cx25", + "col338": "gv7x2", + "col339": "l8l06", + "col340": "l690r", + "col341": "8ds7v", + "col342": "gi0rx", + "col343": "ph2aw", + "col344": "tuqoj", + "col345": "25kha", + "col346": "kht8k", + "col347": "bhunr", + "col348": "uspo9", + "col349": "gircn", + "col350": "jnx4a", + "col351": "zkx8y", + "col352": "b7b3k", + "col353": "lbvuj", + "col354": "haq71", + "col355": "l94yn", + "col356": "9btjo", + "col357": "mepv0", + "col358": "hska6", + "col359": "8jhqr", + "col360": "czmo3", + "col361": "6rjuq", + "col362": "odbli", + "col363": "y14nd", + "col364": "y60xe", + "col365": "b7wlk", + "col366": "lim7f", + "col367": "1pk5w", + "col368": "l5ndn", + "col369": "pt2hf", + "col370": "o34wx", + "col371": "qcbvc", + "col372": "piao3", + "col373": "1wwtm", + "col374": "x7yu1", + "col375": "ezby9", + "col376": "j7rj1", + "col377": "syvtf", + "col378": "6agiw", + "col379": "26ceo", + "col380": "zcsg8", + "col381": "5siat", + "col382": "pd6me", + "col383": "8i7jt", + "col384": "y3qzh", + "col385": "ye6wr", + "col386": "99h9o", + "col387": "m3m73", + "col388": "xmp2p", + "col389": "34yzb", + "col390": "zv1wa", + "col391": "lbtdf", + "col392": "946sl", + "col393": "2eiyv", + "col394": "apryp", + "col395": "y5yd1", + "col396": "s6580", + "col397": "o698t", + "col398": "d0ylg", + "col399": "25o59", + "col400": "9wxld", + "col401": "u8xm3", + "col402": "sb3ve", + "col403": "1l9jt", + "col404": "ptlu9", + "col405": "p3l3u", + "col406": "idebe", + "col407": "vzfmm", + "col408": "p9sdf", + "col409": "ywbis", + "col410": "5ddm5", + "col411": "bx5ej", + "col412": "n3v6e", + "col413": "yw1hx", + "col414": "d9d75", + "col415": "uof89", + "col416": "c99kn", + "col417": "oqmq1", + "col418": "xt8qr", + "col419": "wrt61", + "col420": "b15ba", + "col421": "9w2tb", + "col422": "n2baq", + "col423": "hf8uh", + "col424": "nw0cd", + "col425": "9ktjp", + "col426": "frork", + "col427": "j68l0", + "col428": "9s3na", + "col429": "g8kxk", + "col430": "3bbjd", + "col431": "4pb9q", + "col432": "8ulwi", + "col433": "9epl7", + "col434": "5xtgg", + "col435": "37f7a", + "col436": "fbjts", + "col437": "c2ym4", + "col438": "1i18c", + "col439": "sm0zt", + "col440": "nupxi", + "col441": "e4zpc", + "col442": "99q7v", + "col443": "dujzf", + "col444": "evv6l", + "col445": "xrq9p", + "col446": "h9xz2", + "col447": "45r68", + "col448": "8y7qo", + "col449": "k6ow0", + "col450": "ftvwh", + "col451": "pbvw1", + "col452": "9d65z", + "col453": "h351c", + "col454": "mzhmp", + "col455": "8zli6", + "col456": "fll4n", + "col457": "kwg4d", + "col458": "15g5d", + "col459": "j4bk2", + "col460": "wiu7l", + "col461": "td7re", + "col462": "7rvxr", + "col463": "l23yq", + "col464": "hccxf", + "col465": "17k6y", + "col466": "w8em2", + "col467": "dzbyv", + "col468": "ncgjj", + "col469": "kr30n", + "col470": "e33hh", + "col471": "yct0u", + "col472": "54e2x", + "col473": "435bp", + "col474": "2jvkl", + "col475": "b30ch", + "col476": "6hu06", + "col477": "hb5p1", + "col478": "10587", + "col479": "n0ank", + "col480": "7i2hs", + "col481": "8lw8v", + "col482": "j3yqg", + "col483": "veyms", + "col484": "cwce2", + "col485": "xvgds", + "col486": "4757d", + "col487": "74co8", + "col488": "iputy", + "col489": "4npdz", + "col490": "80mr4", + "col491": "jfq2p", + "col492": "982d5", + "col493": "v55ok", + "col494": "w32hf", + "col495": "h6dtr", + "col496": "gzjo2", + "col497": "j952n", + "col498": "s39d6", + "col499": "hyxgq", + "col500": "zqrma", + "col501": "4s85y", + "col502": "ksztq", + "col503": "y0k7c", + "col504": "t7oc0", + "col505": "gjvoe", + "col506": "ss785", + "col507": "paf2x", + "col508": "sp70l", + "col509": "o1gtl", + "col510": "9h4c4", + "col511": "y7z9d", + "col512": "7o0b9", + "col513": "ri5mj", + "col514": "6lfn6", + "col515": "hrfb0", + "col516": "xy71u", + "col517": "mr0kf", + "col518": "z2av0", + "col519": "ejuec", + "col520": "ar2z5", + "col521": "044vd", + "col522": "b88ml", + "col523": "hpxsm", + "col524": "ftyfm", + "col525": "yogz0", + "col526": "sugc4", + "col527": "clmxd", + "col528": "sqtyq", + "col529": "klwvg", + "col530": "iqsin", + "col531": "25fq6", + "col532": "t648m", + "col533": "0t0jv", + "col534": "cr8uk", + "col535": "gprsu", + "col536": "bhrbz", + "col537": "sz0u1", + "col538": "ibpmg", + "col539": "8qbuj", + "col540": "hmafh", + "col541": "oa3z4", + "col542": "sg22f", + "col543": "pc9vy", + "col544": "xmwyh", + "col545": "dzf9i", + "col546": "1xaz8", + "col547": "mafg2", + "col548": "xk309", + "col549": "2oubm", + "col550": "dqfxt", + "col551": "kqu7r", + "col552": "ljfce", + "col553": "sb27i", + "col554": "2jgsh", + "col555": "nwxuv", + "col556": "hlg7m", + "col557": "bbvkn", + "col558": "v0gqm", + "col559": "r8j4c", + "col560": "2byth", + "col561": "4d1bn", + "col562": "o4rzz", + "col563": "c2lt7", + "col564": "5sf4x", + "col565": "pmo21", + "col566": "2kwqw", + "col567": "jzr17", + "col568": "m7ohe", + "col569": "led6y", + "col570": "f2qv1", + "col571": "jeyls", + "col572": "36bg9", + "col573": "9ilay", + "col574": "7nwi3", + "col575": "1entx", + "col576": "4kyql", + "col577": "ue2mp", + "col578": "xpfwf", + "col579": "47lqt", + "col580": "djlch", + "col581": "rleqq", + "col582": "te50r", + "col583": "l2pq9", + "col584": "ny9k8", + "col585": "0do7q", + "col586": "s6yff", + "col587": "k9e2u", + "col588": "t8181", + "col589": "zz8ft", + "col590": "6meua", + "col591": "kimgl", + "col592": "cd2e4", + "col593": "0495n", + "col594": "2euqi", + "col595": "yugto", + "col596": "tytf1", + "col597": "ukc5a", + "col598": "jlcfu", + "col599": "i1z2r", + "col600": "x2ta1", + "col601": "wo6ce", + "col602": "9xqi7", + "col603": "0qf49", + "col604": "vzn0l", + "col605": "xo8s9", + "col606": "bvzy9", + "col607": "mb06f", + "col608": "qvohg", + "col609": "7ycyz", + "col610": "qogxd", + "col611": "m8sj7", + "col612": "zc2oh", + "col613": "xhgo9", + "col614": "dcvzk", + "col615": "4fwvu", + "col616": "e703i", + "col617": "num5h", + "col618": "jds4h", + "col619": "acd5d", + "col620": "bemmm", + "col621": "cp47g", + "col622": "i43ne", + "col623": "jarxf", + "col624": "sidrr", + "col625": "acw4u", + "col626": "zh6xn", + "col627": "1xa3y", + "col628": "i8up8", + "col629": "t9b4f", + "col630": "jsgx2", + "col631": "xr8ze", + "col632": "x46n6", + "col633": "c5ox8", + "col634": "8loqx", + "col635": "zk46w", + "col636": "a51qx", + "col637": "f0012", + "col638": "gn9mc", + "col639": "d9eif", + "col640": "24zpx", + "col641": "q6vib", + "col642": "sirxj", + "col643": "21vs1", + "col644": "00vqx", + "col645": "l4vre", + "col646": "3wod2", + "col647": "gmlqz", + "col648": "hzbt0", + "col649": "28r4q", + "col650": "d8w1t", + "col651": "wo5v0", + "col652": "9fc5y", + "col653": "ppm3h", + "col654": "i6pqb", + "col655": "nfcrh", + "col656": "vhxk8", + "col657": "uc1uf", + "col658": "7t0b7", + "col659": "hh59z", + "col660": "oo05k", + "col661": "19y4j", + "col662": "mbm1q", + "col663": "3k8gh", + "col664": "39syv", + "col665": "57neb", + "col666": "s980n", + "col667": "5i6jk", + "col668": "h57pa", + "col669": "9a23a", + "col670": "vafo6", + "col671": "kjua4", + "col672": "m1ogc", + "col673": "50epk", + "col674": "gngcl", + "col675": "7vdw6", + "col676": "k54ap", + "col677": "pgk6k", + "col678": "dhr64", + "col679": "ck8jd", + "col680": "2g866", + "col681": "sha5v", + "col682": "tl7od", + "col683": "yvo6d", + "col684": "9dcz4", + "col685": "pji1i", + "col686": "rlbxh", + "col687": "0461f", + "col688": "uzbhq", + "col689": "ntb2l", + "col690": "c3305", + "col691": "4n2p0", + "col692": "8ypue", + "col693": "lrrc4", + "col694": "wzlnk", + "col695": "ml7p5", + "col696": "ko2a7", + "col697": "nlqxv", + "col698": "tc0sm", + "col699": "p2d2l", + "col700": "tyl83", + "col701": "mwwdh", + "col702": "h3jl9", + "col703": "909pi", + "col704": "znkb6", + "col705": "8qa5r", + "col706": "zv7p8", + "col707": "586ey", + "col708": "v9n3c", + "col709": "gfc2c", + "col710": "c5cs2", + "col711": "8aefx", + "col712": "239kq", + "col713": "4mdc9", + "col714": "mdzj9", + "col715": "l0fox", + "col716": "tpesk", + "col717": "dbstf", + "col718": "nxu25", + "col719": "jcqfe", + "col720": "2g3hn", + "col721": "14mn9", + "col722": "l0jy4", + "col723": "1yv0q", + "col724": "7nrtb", + "col725": "dl5rz", + "col726": "oidyg", + "col727": "g2y9q", + "col728": "arizp", + "col729": "cwch6", + "col730": "s45b3", + "col731": "mh7uv", + "col732": "hqmtm", + "col733": "htcq6", + "col734": "ims6x", + "col735": "2b9ti", + "col736": "i67qh", + "col737": "hyl6l", + "col738": "yt46h", + "col739": "esrdt", + "col740": "u4zgj", + "col741": "zmnc2", + "col742": "uxd0a", + "col743": "3l9vu", + "col744": "cq0mr", + "col745": "jpdan", + "col746": "7w5qj", + "col747": "akpxe", + "col748": "1414u", + "col749": "a5fuq", + "col750": "2p2ta", + "col751": "74195", + "col752": "ybhi1", + "col753": "tpjt3", + "col754": "fauy8", + "col755": "jradz", + "col756": "xpul2", + "col757": "tj29v", + "col758": "x54j6", + "col759": "x6k5y", + "col760": "si701", + "col761": "jcdem", + "col762": "ggijt", + "col763": "6m08p", + "col764": "2pv8v", + "col765": "1lfwf", + "col766": "thw2o", + "col767": "x20jb", + "col768": "wv6ok", + "col769": "k7dv5", + "col770": "yrdfo", + "col771": "jk9n1", + "col772": "3rxcp", + "col773": "qohu9", + "col774": "djtc0", + "col775": "muw20", + "col776": "z6w30", + "col777": "auh2f", + "col778": "k9qz8", + "col779": "44e4r", + "col780": "c3by0", + "col781": "e41zy", + "col782": "4qa5i", + "col783": "fmnkf", + "col784": "lquw4", + "col785": "f5k0y", + "col786": "sbbaf", + "col787": "5omot", + "col788": "3ec19", + "col789": "s1620", + "col790": "l5vfd", + "col791": "hztkq", + "col792": "hi7q9", + "col793": "w1tej", + "col794": "vigb8", + "col795": "t657t", + "col796": "o1rl0", + "col797": "ioi2e", + "col798": "atgzr", + "col799": "a96zn", + "col800": "4k3zs", + "col801": "x8l6i", + "col802": "ffmi9", + "col803": "soo58", + "col804": "9sx38", + "col805": "3gbrd", + "col806": "xcdjd", + "col807": "ea3ui", + "col808": "jo3ms", + "col809": "wcn1p", + "col810": "ysgnt", + "col811": "mh2ds", + "col812": "lc4mb", + "col813": "9fvlp", + "col814": "vj1e3", + "col815": "rlm0m", + "col816": "auwcj", + "col817": "zj2pn", + "col818": "3pty5", + "col819": "b50ma", + "col820": "rogue", + "col821": "pniil", + "col822": "0rwsd", + "col823": "c93b4", + "col824": "83kip", + "col825": "xmyr0", + "col826": "qqokk", + "col827": "u3ffd", + "col828": "okjdv", + "col829": "4od2g", + "col830": "gw44o", + "col831": "otiis", + "col832": "olo9r", + "col833": "og2rr", + "col834": "mpjtl", + "col835": "4lwgp", + "col836": "o6cfe", + "col837": "fmit5", + "col838": "nvxga", + "col839": "ftyvx", + "col840": "pht69", + "col841": "7kjf8", + "col842": "40ak1", + "col843": "xt98y", + "col844": "l3r2k", + "col845": "h6jez", + "col846": "763kx", + "col847": "zrj50", + "col848": "oue03", + "col849": "l35u3", + "col850": "jzfw0", + "col851": "2djgg", + "col852": "5tpr9", + "col853": "we3eb", + "col854": "hpsdl", + "col855": "uzwbz", + "col856": "avcd1", + "col857": "l8amr", + "col858": "0dzzt", + "col859": "30m8o", + "col860": "ocfsd", + "col861": "nbrrz", + "col862": "vgebe", + "col863": "8e1ah", + "col864": "j9tfy", + "col865": "ei0qh", + "col866": "le64c", + "col867": "ens60", + "col868": "8idxp", + "col869": "ay8cm", + "col870": "bzho8", + "col871": "hq83a", + "col872": "46a4x", + "col873": "xzaqq", + "col874": "p58js", + "col875": "usi0h", + "col876": "hwxe7", + "col877": "vk5os", + "col878": "l39cl", + "col879": "cld17", + "col880": "bme4b", + "col881": "fouvv", + "col882": "qv98w", + "col883": "jpq48", + "col884": "4zjqc", + "col885": "wb0ir", + "col886": "74y3q", + "col887": "w5ohq", + "col888": "azfmk", + "col889": "6bvcp", + "col890": "jy5dm", + "col891": "4pwxx", + "col892": "mgrqf", + "col893": "dwyvj", + "col894": "lo2t3", + "col895": "qti33", + "col896": "ki2f7", + "col897": "jx45b", + "col898": "t7zxz", + "col899": "0r2q0", + "col900": "dmn2n", + "col901": "gwg3k", + "col902": "itmh0", + "col903": "91ufi", + "col904": "13ya3", + "col905": "y1q6r", + "col906": "re9vq", + "col907": "gj654", + "col908": "3gujt", + "col909": "xakfw", + "col910": "vu6nd", + "col911": "ieazh", + "col912": "uz14a", + "col913": "dy6v3", + "col914": "tcw1h", + "col915": "ue0i1", + "col916": "xyex4", + "col917": "07p3l", + "col918": "8jvhs", + "col919": "69714", + "col920": "r61pb", + "col921": "947yo", + "col922": "bk49y", + "col923": "heryy", + "col924": "bp9yw", + "col925": "gki6r", + "col926": "v56ef", + "col927": "y4rc5", + "col928": "7lv6o", + "col929": "sfhb6", + "col930": "p4o1u", + "col931": "tj4f0", + "col932": "ywc1d", + "col933": "z14u9", + "col934": "z7ema", + "col935": "4saor", + "col936": "jsauj", + "col937": "f95pw", + "col938": "xocpu", + "col939": "qff55", + "col940": "462b4", + "col941": "plg33", + "col942": "zbn6w", + "col943": "14b8d", + "col944": "qzslf", + "col945": "wv0kp", + "col946": "f8cx0", + "col947": "3cdjz", + "col948": "3y4br", + "col949": "ij3xp", + "col950": "eck95", + "col951": "2puwh", + "col952": "69dmt", + "col953": "kfbid", + "col954": "4ipeo", + "col955": "9wrqo", + "col956": "p446p", + "col957": "hwatb", + "col958": "guiyo", + "col959": "zxbj2", + "col960": "e2ftg", + "col961": "lb0e1", + "col962": "q06ij", + "col963": "6pbzo", + "col964": "9qrsu", + "col965": "atkrr", + "col966": "dk17l", + "col967": "5siyi", + "col968": "5vet7", + "col969": "bn24h", + "col970": "q2uni", + "col971": "4ibl5", + "col972": "o817d", + "col973": "ovg11", + "col974": "ox5w1", + "col975": "tcy8m", + "col976": "lo9o7", + "col977": "q0ey3", + "col978": "mmwq8", + "col979": "phkxs", + "col980": "r4myf", + "col981": "obd4t", + "col982": "hz8f2", + "col983": "fajwx", + "col984": "scu8v", + "col985": "1oe80", + "col986": "buxt7", + "col987": "czo9v", + "col988": "jdaqc", + "col989": "sg5zz", + "col990": "c7551", + "col991": "rktp2", + "col992": "4zbi7", + "col993": "tkovg", + "col994": "vw8o3", + "col995": "jsa8h", + "col996": "2qkmb", + "col997": "4436l", + "col998": "ur2zt", + "col999": "4bhjf" + }, + { + "name": "Britney Hodges", + "gender": "female", + "col0": "skkrc", + "col1": "ofqb1", + "col2": "uo0es", + "col3": "x4obf", + "col4": "so7rd", + "col5": "38x2k", + "col6": "hm51i", + "col7": "1wjv6", + "col8": "1vd9p", + "col9": "9qor2", + "col10": "g89tg", + "col11": "9aaku", + "col12": "rk8we", + "col13": "h02wv", + "col14": "2nm81", + "col15": "oqtzu", + "col16": "hmhka", + "col17": "yjdpe", + "col18": "t4cez", + "col19": "ovpmx", + "col20": "v7jgw", + "col21": "ohydz", + "col22": "m1ymd", + "col23": "k7edv", + "col24": "vqw4q", + "col25": "kf6h4", + "col26": "97jr9", + "col27": "e1ivo", + "col28": "z6j98", + "col29": "a7w7z", + "col30": "pc4p1", + "col31": "p9tkg", + "col32": "zjyl4", + "col33": "2c4ja", + "col34": "k01q8", + "col35": "59bac", + "col36": "fgn3w", + "col37": "cvpd6", + "col38": "yq7u0", + "col39": "qe4bu", + "col40": "shhjh", + "col41": "065um", + "col42": "ti5ru", + "col43": "t6pju", + "col44": "lk9n9", + "col45": "f827n", + "col46": "h2x2a", + "col47": "tqecw", + "col48": "q1f4h", + "col49": "lwbfd", + "col50": "wdgtj", + "col51": "hgqzf", + "col52": "38gjg", + "col53": "i22hf", + "col54": "qs5um", + "col55": "uyzmg", + "col56": "oolxs", + "col57": "4r5fv", + "col58": "s8h09", + "col59": "2dmzw", + "col60": "beo7p", + "col61": "9lwvt", + "col62": "qvavq", + "col63": "h5f6k", + "col64": "z7rqy", + "col65": "nxixi", + "col66": "ytfdz", + "col67": "ahav9", + "col68": "a55e9", + "col69": "9ncqp", + "col70": "8a8lx", + "col71": "o2ons", + "col72": "0paac", + "col73": "8sxpa", + "col74": "0nnw8", + "col75": "oii7c", + "col76": "voomg", + "col77": "aw6kr", + "col78": "cn6pf", + "col79": "gbip4", + "col80": "l7pwi", + "col81": "legi0", + "col82": "y06fy", + "col83": "w2skm", + "col84": "ajjsg", + "col85": "f35gw", + "col86": "65seb", + "col87": "mzfvk", + "col88": "4atzz", + "col89": "y7xsf", + "col90": "c40se", + "col91": "eovso", + "col92": "swbzz", + "col93": "g7fu8", + "col94": "wkoma", + "col95": "2lrsn", + "col96": "o22l9", + "col97": "1wxsy", + "col98": "1u27e", + "col99": "fc0y3", + "col100": "5mflp", + "col101": "qoy09", + "col102": "d08xr", + "col103": "vm7ec", + "col104": "ujo93", + "col105": "2rqdl", + "col106": "4wh9v", + "col107": "orhld", + "col108": "x0q9b", + "col109": "tlubx", + "col110": "uuak6", + "col111": "k1c9l", + "col112": "k5wpj", + "col113": "jawqo", + "col114": "rchay", + "col115": "whga5", + "col116": "s2xvp", + "col117": "f3f4t", + "col118": "f3uyh", + "col119": "3rmxu", + "col120": "nw2om", + "col121": "uv5mm", + "col122": "fjxio", + "col123": "ws3o2", + "col124": "p1wst", + "col125": "xmf8f", + "col126": "ncx0z", + "col127": "a43ne", + "col128": "nr3im", + "col129": "x6jss", + "col130": "kvbdq", + "col131": "nbldz", + "col132": "pk878", + "col133": "6vj3i", + "col134": "9db2p", + "col135": "f81wu", + "col136": "v8yhd", + "col137": "1xkcd", + "col138": "62b3a", + "col139": "0rh1p", + "col140": "ufl9u", + "col141": "g1v2w", + "col142": "0cfx7", + "col143": "o1shv", + "col144": "rcb08", + "col145": "uixtf", + "col146": "mt3bo", + "col147": "31ksa", + "col148": "xhyx5", + "col149": "5sz65", + "col150": "yp2kr", + "col151": "o4gae", + "col152": "md1aj", + "col153": "k64n8", + "col154": "gh6ih", + "col155": "apely", + "col156": "t0jkt", + "col157": "t47yn", + "col158": "lp6bk", + "col159": "9mxo2", + "col160": "96r0y", + "col161": "y01gh", + "col162": "9gsfr", + "col163": "2tww0", + "col164": "fmzpb", + "col165": "9cjx7", + "col166": "9nghc", + "col167": "h8cnl", + "col168": "bimc6", + "col169": "09hs6", + "col170": "apbv8", + "col171": "2s01p", + "col172": "tdxop", + "col173": "avi3a", + "col174": "t2zcr", + "col175": "jpy2p", + "col176": "aj0hd", + "col177": "a6vdh", + "col178": "vhh34", + "col179": "ltcuu", + "col180": "ea63i", + "col181": "fl4yi", + "col182": "zze1e", + "col183": "r1pc9", + "col184": "mor8i", + "col185": "psgfe", + "col186": "erevh", + "col187": "lj6xn", + "col188": "0rrkb", + "col189": "xs7v4", + "col190": "n6ry8", + "col191": "myg9d", + "col192": "3my3u", + "col193": "27ly6", + "col194": "y1mfz", + "col195": "0yswt", + "col196": "n84p1", + "col197": "rf9ei", + "col198": "gf0h1", + "col199": "c1fg5", + "col200": "8cw0f", + "col201": "ec0z4", + "col202": "8gw04", + "col203": "90lip", + "col204": "gcyhp", + "col205": "c0btf", + "col206": "w9rc4", + "col207": "eomum", + "col208": "r35d6", + "col209": "w09ya", + "col210": "78vw9", + "col211": "nlrme", + "col212": "tqrkp", + "col213": "02bfz", + "col214": "n65ye", + "col215": "ki1md", + "col216": "jrqe1", + "col217": "e19mk", + "col218": "qjhqh", + "col219": "eg6hc", + "col220": "sff7d", + "col221": "kdl4x", + "col222": "pqruf", + "col223": "j118h", + "col224": "j398o", + "col225": "ej2dz", + "col226": "pvxds", + "col227": "p5g7t", + "col228": "sfu7z", + "col229": "poi19", + "col230": "hazyu", + "col231": "yx310", + "col232": "14m80", + "col233": "f0hht", + "col234": "dxy9n", + "col235": "cgcxl", + "col236": "2nd9e", + "col237": "tgkuc", + "col238": "6bh7q", + "col239": "k9rnv", + "col240": "7vlmx", + "col241": "0422p", + "col242": "lbzxz", + "col243": "zx78j", + "col244": "h1yol", + "col245": "mkav6", + "col246": "lmg4h", + "col247": "35tlm", + "col248": "w4sxk", + "col249": "58hd5", + "col250": "icuak", + "col251": "pv2sz", + "col252": "y4kqi", + "col253": "irzgb", + "col254": "yov3l", + "col255": "1veja", + "col256": "ahh4r", + "col257": "obc3u", + "col258": "lqgm8", + "col259": "pakzp", + "col260": "hgyhl", + "col261": "66ngo", + "col262": "i8xly", + "col263": "spish", + "col264": "064hl", + "col265": "ojpw1", + "col266": "3dfp3", + "col267": "yji3p", + "col268": "ddga6", + "col269": "2t5gt", + "col270": "vapap", + "col271": "msx82", + "col272": "nfgu9", + "col273": "nirj9", + "col274": "sxf9a", + "col275": "5n904", + "col276": "p32eo", + "col277": "opm0w", + "col278": "ik6th", + "col279": "nt8a6", + "col280": "r240k", + "col281": "z0zy8", + "col282": "lccc8", + "col283": "xse7z", + "col284": "drs5m", + "col285": "hxtkl", + "col286": "jog0p", + "col287": "vjg1e", + "col288": "cp52r", + "col289": "5amhn", + "col290": "wxi38", + "col291": "iy1f1", + "col292": "oxptk", + "col293": "d8g7t", + "col294": "glqr4", + "col295": "dfl9r", + "col296": "3imr4", + "col297": "sag9j", + "col298": "fd74r", + "col299": "y8nmo", + "col300": "e1hpt", + "col301": "r3pzy", + "col302": "6g5mf", + "col303": "rk35v", + "col304": "ph3po", + "col305": "tk5js", + "col306": "jgmdq", + "col307": "cc76p", + "col308": "hroee", + "col309": "r256p", + "col310": "9w18g", + "col311": "k06fx", + "col312": "d5n2x", + "col313": "3x42i", + "col314": "0spus", + "col315": "gpufk", + "col316": "s8fz0", + "col317": "o5ea3", + "col318": "qu9c8", + "col319": "bn5h8", + "col320": "cmf6f", + "col321": "8ih80", + "col322": "4hsrm", + "col323": "uf6i4", + "col324": "jsipr", + "col325": "791l4", + "col326": "pzpqw", + "col327": "wbcp1", + "col328": "c13be", + "col329": "c43x4", + "col330": "1qyn4", + "col331": "omgr5", + "col332": "ii0gm", + "col333": "x4vig", + "col334": "wpmdk", + "col335": "6rz0z", + "col336": "h4rmr", + "col337": "cbzqn", + "col338": "c72ko", + "col339": "xzoty", + "col340": "ukkm2", + "col341": "unms5", + "col342": "92gwd", + "col343": "wlfgt", + "col344": "r2ae4", + "col345": "yvggy", + "col346": "m6bza", + "col347": "oh61n", + "col348": "855fj", + "col349": "hy2wl", + "col350": "fi7gk", + "col351": "evrss", + "col352": "u2ycv", + "col353": "6e9iu", + "col354": "ic88w", + "col355": "nynil", + "col356": "cubms", + "col357": "011v8", + "col358": "girv3", + "col359": "11p3w", + "col360": "xsrv4", + "col361": "0e60m", + "col362": "mclqp", + "col363": "xtkbp", + "col364": "f7vzy", + "col365": "s4f40", + "col366": "r6ien", + "col367": "6mn8i", + "col368": "xw6x8", + "col369": "nvo0i", + "col370": "g048s", + "col371": "xmxsu", + "col372": "vgcnq", + "col373": "r6t2d", + "col374": "1kp1k", + "col375": "yyqlo", + "col376": "zcvzp", + "col377": "fpg79", + "col378": "83ttz", + "col379": "617m9", + "col380": "gdihn", + "col381": "brdir", + "col382": "q8h41", + "col383": "sswfi", + "col384": "eae53", + "col385": "91k5k", + "col386": "kvuwu", + "col387": "op9or", + "col388": "e7ctm", + "col389": "niktj", + "col390": "d1918", + "col391": "sm2qg", + "col392": "io8sv", + "col393": "30k97", + "col394": "ofbuq", + "col395": "sqzpk", + "col396": "68ub8", + "col397": "4imqq", + "col398": "jdev0", + "col399": "p7wf8", + "col400": "m75y7", + "col401": "3u8kq", + "col402": "19u3v", + "col403": "7cejw", + "col404": "qu09a", + "col405": "ekx80", + "col406": "n1d9k", + "col407": "xe8rp", + "col408": "bcuao", + "col409": "i8vnr", + "col410": "ay0pi", + "col411": "9s0e8", + "col412": "4runb", + "col413": "cvx2y", + "col414": "d7ya4", + "col415": "eaxe1", + "col416": "b628e", + "col417": "52987", + "col418": "r1nxk", + "col419": "jyb12", + "col420": "stzia", + "col421": "66awy", + "col422": "n8xeo", + "col423": "kysfj", + "col424": "796az", + "col425": "3n0lo", + "col426": "mxfsy", + "col427": "q9mv4", + "col428": "kj7no", + "col429": "xh8dt", + "col430": "p90hg", + "col431": "oscxz", + "col432": "ccpha", + "col433": "vm0hk", + "col434": "9igzz", + "col435": "ggipw", + "col436": "xzdfv", + "col437": "1qnuv", + "col438": "frdcr", + "col439": "qcj79", + "col440": "x4m0c", + "col441": "2dgst", + "col442": "7ui99", + "col443": "y3uk4", + "col444": "4vcn3", + "col445": "erqz8", + "col446": "dv9ui", + "col447": "wtx7p", + "col448": "h2f2x", + "col449": "i4vtc", + "col450": "3fs61", + "col451": "0q2zo", + "col452": "nm0nu", + "col453": "bwkrn", + "col454": "6o10x", + "col455": "mb340", + "col456": "dnfz2", + "col457": "7h1sa", + "col458": "vkg8v", + "col459": "h7sfl", + "col460": "1zmax", + "col461": "ujhj3", + "col462": "r88oj", + "col463": "4150d", + "col464": "vdtyg", + "col465": "6nqg8", + "col466": "08cou", + "col467": "y589c", + "col468": "qeg0p", + "col469": "tvayv", + "col470": "80kwc", + "col471": "4r1u3", + "col472": "ucb4w", + "col473": "wvi1u", + "col474": "hm78x", + "col475": "bszsi", + "col476": "qosj5", + "col477": "ov3rf", + "col478": "wgiy8", + "col479": "iln7u", + "col480": "in8mh", + "col481": "hedfb", + "col482": "dvaav", + "col483": "2l108", + "col484": "ndfmt", + "col485": "s055q", + "col486": "69i30", + "col487": "t49k7", + "col488": "kdhyb", + "col489": "oan3b", + "col490": "270eb", + "col491": "z2ihk", + "col492": "2u621", + "col493": "p6ydz", + "col494": "6ag4e", + "col495": "sq6q4", + "col496": "rj48j", + "col497": "7u9nf", + "col498": "q5rme", + "col499": "s2sot", + "col500": "1nj7l", + "col501": "kk4hh", + "col502": "ww7ri", + "col503": "ir6uf", + "col504": "isvur", + "col505": "vnx13", + "col506": "5fq49", + "col507": "ezou0", + "col508": "74l36", + "col509": "ps6cr", + "col510": "2zlw4", + "col511": "xjkxm", + "col512": "vuxvz", + "col513": "ou9u3", + "col514": "vrtls", + "col515": "phda6", + "col516": "wa27c", + "col517": "p07y0", + "col518": "o7f85", + "col519": "ku6j5", + "col520": "oo7tx", + "col521": "9nc4o", + "col522": "0nnz0", + "col523": "25we5", + "col524": "5i2vk", + "col525": "krvew", + "col526": "yoye1", + "col527": "42kfi", + "col528": "2oq94", + "col529": "es0y0", + "col530": "29b56", + "col531": "afbxw", + "col532": "kcrlk", + "col533": "u9wiz", + "col534": "0mq66", + "col535": "z4kwe", + "col536": "sa3m1", + "col537": "ihda5", + "col538": "tf6xt", + "col539": "x45ol", + "col540": "yeg9q", + "col541": "n2z34", + "col542": "tuyil", + "col543": "dxubp", + "col544": "7falj", + "col545": "eufto", + "col546": "96xqk", + "col547": "rtup9", + "col548": "oddgi", + "col549": "y0lhz", + "col550": "wptfp", + "col551": "5ab4b", + "col552": "qxebe", + "col553": "2g26j", + "col554": "o6nhr", + "col555": "gki5v", + "col556": "jkh17", + "col557": "704ic", + "col558": "t23ve", + "col559": "1gfks", + "col560": "6epq2", + "col561": "xmbk0", + "col562": "vkphf", + "col563": "gvry4", + "col564": "0npzd", + "col565": "auah9", + "col566": "jwmy7", + "col567": "j6syh", + "col568": "j1kwm", + "col569": "rvsmi", + "col570": "7tung", + "col571": "1csx0", + "col572": "fiqpd", + "col573": "pwal7", + "col574": "q3so2", + "col575": "3utdd", + "col576": "zkghn", + "col577": "pf50z", + "col578": "nh9il", + "col579": "z60t6", + "col580": "dwqe7", + "col581": "msmhl", + "col582": "ylpae", + "col583": "1wtp7", + "col584": "y47qz", + "col585": "hb3w0", + "col586": "hyvcs", + "col587": "044t8", + "col588": "fr0pl", + "col589": "k73mx", + "col590": "2h8zu", + "col591": "7jq9o", + "col592": "x3rkr", + "col593": "nh3p4", + "col594": "bfz2y", + "col595": "mg5bi", + "col596": "dkdmj", + "col597": "h8p0b", + "col598": "lojvn", + "col599": "qop7g", + "col600": "xi6yv", + "col601": "mc7oc", + "col602": "4qf99", + "col603": "65esy", + "col604": "zccxe", + "col605": "m5af3", + "col606": "mkox2", + "col607": "nq1dj", + "col608": "zhnz4", + "col609": "oo2g3", + "col610": "xwitv", + "col611": "okirb", + "col612": "3886x", + "col613": "p5h49", + "col614": "16fwv", + "col615": "9si4x", + "col616": "djead", + "col617": "kuian", + "col618": "6g8u2", + "col619": "403wt", + "col620": "v35ax", + "col621": "s7b26", + "col622": "61o2j", + "col623": "qt3h7", + "col624": "5fjgz", + "col625": "3oz59", + "col626": "foboo", + "col627": "vlo02", + "col628": "othy3", + "col629": "xpz8e", + "col630": "qozws", + "col631": "dbafp", + "col632": "gmprr", + "col633": "h869t", + "col634": "3ip5g", + "col635": "7ja51", + "col636": "njnb3", + "col637": "s9mci", + "col638": "baltr", + "col639": "w1uig", + "col640": "3tgil", + "col641": "dkleu", + "col642": "muw06", + "col643": "z73pj", + "col644": "38063", + "col645": "an928", + "col646": "h3o7n", + "col647": "3ul7f", + "col648": "klum1", + "col649": "a5tut", + "col650": "tr49b", + "col651": "wzsq2", + "col652": "75j0w", + "col653": "6yxk9", + "col654": "2ppkw", + "col655": "ayhoa", + "col656": "vzoh9", + "col657": "c7bzp", + "col658": "zzz6f", + "col659": "d9tas", + "col660": "sabvs", + "col661": "yvoi8", + "col662": "rfwbd", + "col663": "qwq70", + "col664": "ou0lq", + "col665": "rz8ie", + "col666": "sv3v2", + "col667": "fgp22", + "col668": "smr6m", + "col669": "j2bo6", + "col670": "ydplm", + "col671": "aa2af", + "col672": "37vih", + "col673": "cymdw", + "col674": "mgei6", + "col675": "sya2m", + "col676": "2gka4", + "col677": "w330x", + "col678": "8b6yd", + "col679": "fo01t", + "col680": "ds1mg", + "col681": "ucvl9", + "col682": "4zqie", + "col683": "475ec", + "col684": "e4i6k", + "col685": "he7gc", + "col686": "ods9n", + "col687": "5tn16", + "col688": "vv9mr", + "col689": "kar4m", + "col690": "fe7pv", + "col691": "wejdt", + "col692": "k6znc", + "col693": "bdb91", + "col694": "3gvxz", + "col695": "3dqyk", + "col696": "1qkoy", + "col697": "t1egc", + "col698": "l7v0u", + "col699": "vlvjh", + "col700": "g8d4z", + "col701": "c07fo", + "col702": "5i1hw", + "col703": "lvl1c", + "col704": "pai2q", + "col705": "pwny6", + "col706": "w0nti", + "col707": "f4flf", + "col708": "lm6ic", + "col709": "khfqq", + "col710": "16t8r", + "col711": "p3ca3", + "col712": "hhhqj", + "col713": "bq8jw", + "col714": "1xeew", + "col715": "pt9ei", + "col716": "r0w6o", + "col717": "lvf1c", + "col718": "mzow2", + "col719": "hr9pn", + "col720": "f5v0v", + "col721": "muz0g", + "col722": "bbieg", + "col723": "vsx94", + "col724": "rwa2x", + "col725": "0affa", + "col726": "j1gwi", + "col727": "ocnq0", + "col728": "xl5co", + "col729": "abflr", + "col730": "gm41v", + "col731": "nc4yp", + "col732": "7e5qr", + "col733": "8rq89", + "col734": "jsiif", + "col735": "drdzo", + "col736": "yay34", + "col737": "pymha", + "col738": "9cpxg", + "col739": "ktzis", + "col740": "x68y2", + "col741": "vxa23", + "col742": "io5p4", + "col743": "mdg3t", + "col744": "fy7ht", + "col745": "up3i1", + "col746": "wsppy", + "col747": "1dync", + "col748": "l51z6", + "col749": "01fzj", + "col750": "b47dk", + "col751": "ehm0l", + "col752": "gstez", + "col753": "4r7ue", + "col754": "p62ow", + "col755": "zogxq", + "col756": "mw6f6", + "col757": "hc4vt", + "col758": "9cg4n", + "col759": "qx3uu", + "col760": "cxsbe", + "col761": "qxnul", + "col762": "eivha", + "col763": "32p1u", + "col764": "4r1kx", + "col765": "sypxb", + "col766": "mfdya", + "col767": "hyqss", + "col768": "qqbs4", + "col769": "2gmeu", + "col770": "joyk6", + "col771": "v6nqf", + "col772": "0uhj5", + "col773": "k6iaz", + "col774": "ioocb", + "col775": "fj5cl", + "col776": "swah2", + "col777": "hb77k", + "col778": "n6aan", + "col779": "ofuxn", + "col780": "hdyan", + "col781": "29c5r", + "col782": "l6xju", + "col783": "pe1wc", + "col784": "mgh1w", + "col785": "lid94", + "col786": "kv2m0", + "col787": "z7x9l", + "col788": "d6xct", + "col789": "a3mny", + "col790": "ti6lr", + "col791": "distc", + "col792": "lm1c0", + "col793": "oa7il", + "col794": "g56jj", + "col795": "syetd", + "col796": "o23m4", + "col797": "99fmz", + "col798": "a1s6n", + "col799": "4y1wz", + "col800": "mqyfl", + "col801": "effkr", + "col802": "fz7ie", + "col803": "8srbr", + "col804": "mkuyh", + "col805": "fr5ds", + "col806": "yrf44", + "col807": "ozc74", + "col808": "pa0d2", + "col809": "4dne1", + "col810": "slq2t", + "col811": "pmb8h", + "col812": "qp6sn", + "col813": "te6db", + "col814": "mgtnf", + "col815": "2czon", + "col816": "7kpy9", + "col817": "ienu2", + "col818": "wey1o", + "col819": "qqa4j", + "col820": "901zv", + "col821": "2fmo7", + "col822": "jdi4o", + "col823": "zg6z7", + "col824": "z0zq3", + "col825": "dn5qd", + "col826": "r1emz", + "col827": "oy91f", + "col828": "gxwr8", + "col829": "ds9uo", + "col830": "m808o", + "col831": "l7omm", + "col832": "sxmh7", + "col833": "9xcc7", + "col834": "415nz", + "col835": "d598o", + "col836": "trovh", + "col837": "5xqri", + "col838": "c9cn7", + "col839": "3k11o", + "col840": "zoy6l", + "col841": "zvuho", + "col842": "9y6ln", + "col843": "vjx49", + "col844": "4ryke", + "col845": "epmr2", + "col846": "yvagl", + "col847": "9kacq", + "col848": "krb4o", + "col849": "7n0li", + "col850": "pv86n", + "col851": "gus85", + "col852": "16nh1", + "col853": "2d31h", + "col854": "ncuxy", + "col855": "yvzms", + "col856": "o8ic0", + "col857": "n48sv", + "col858": "syr0j", + "col859": "hidyf", + "col860": "4wf8u", + "col861": "tqqel", + "col862": "arwcy", + "col863": "7chuv", + "col864": "dk4ay", + "col865": "3ydvl", + "col866": "kexm8", + "col867": "wjdph", + "col868": "pajz9", + "col869": "xwbto", + "col870": "wd6pi", + "col871": "qsksc", + "col872": "oqei6", + "col873": "jiw1p", + "col874": "uw26e", + "col875": "aksrm", + "col876": "e6mgw", + "col877": "7bec0", + "col878": "4y43r", + "col879": "l49r6", + "col880": "x626w", + "col881": "iolow", + "col882": "f02wb", + "col883": "33obh", + "col884": "kbz1v", + "col885": "mq5wf", + "col886": "vna45", + "col887": "lvgjz", + "col888": "oa415", + "col889": "m3q21", + "col890": "sjvdm", + "col891": "s1fh4", + "col892": "jom72", + "col893": "9610p", + "col894": "ke21q", + "col895": "qudr9", + "col896": "iw9wk", + "col897": "ov99t", + "col898": "53isu", + "col899": "ualil", + "col900": "q7cx2", + "col901": "1tosn", + "col902": "4q9io", + "col903": "m8ocx", + "col904": "7hxzf", + "col905": "7md8k", + "col906": "oyp2g", + "col907": "hzus7", + "col908": "04r1b", + "col909": "fgykf", + "col910": "jno8t", + "col911": "hth7j", + "col912": "cevlr", + "col913": "ucw41", + "col914": "pk16g", + "col915": "yw82q", + "col916": "m8szg", + "col917": "rl3gy", + "col918": "gutmi", + "col919": "bp9os", + "col920": "8vy58", + "col921": "jyih8", + "col922": "sp00b", + "col923": "hmp15", + "col924": "uiw4r", + "col925": "v09j9", + "col926": "028hk", + "col927": "9c1k5", + "col928": "sy9gu", + "col929": "gd8gy", + "col930": "1jqg4", + "col931": "alyx0", + "col932": "bbh0g", + "col933": "se0mb", + "col934": "99hbv", + "col935": "fepmd", + "col936": "us0fr", + "col937": "8q8bh", + "col938": "wv6cy", + "col939": "0088g", + "col940": "z157u", + "col941": "9jy0k", + "col942": "mmsnf", + "col943": "qsbzw", + "col944": "tn6uq", + "col945": "clwt4", + "col946": "uii8s", + "col947": "8uq52", + "col948": "2bl3a", + "col949": "6336g", + "col950": "wc8gw", + "col951": "a8yjs", + "col952": "t363l", + "col953": "bx9qv", + "col954": "mypsm", + "col955": "jlz0x", + "col956": "d51c8", + "col957": "0pszx", + "col958": "h8qye", + "col959": "m90mq", + "col960": "z48n9", + "col961": "q3ooy", + "col962": "5nl1x", + "col963": "ktn58", + "col964": "24fr9", + "col965": "oc7lf", + "col966": "33lfr", + "col967": "h574r", + "col968": "g4wre", + "col969": "mwt71", + "col970": "6l1id", + "col971": "bnj6w", + "col972": "2mu6o", + "col973": "cq840", + "col974": "btc4d", + "col975": "fyr88", + "col976": "arqeo", + "col977": "q6omb", + "col978": "526nb", + "col979": "npd2t", + "col980": "uw7ha", + "col981": "zywkm", + "col982": "yvrr7", + "col983": "zdiip", + "col984": "qayyi", + "col985": "95e9h", + "col986": "z2hpd", + "col987": "85lhh", + "col988": "pq69r", + "col989": "2hpcn", + "col990": "wcops", + "col991": "j3fmw", + "col992": "1gce2", + "col993": "xu68s", + "col994": "93s4m", + "col995": "8l8pl", + "col996": "ywc3y", + "col997": "zunzw", + "col998": "yiwnx", + "col999": "jc3iu" + }, + { + "name": "Elinor Burns", + "gender": "female", + "col0": "y5o9z", + "col1": "6fye4", + "col2": "8ocoo", + "col3": "disds", + "col4": "xdatp", + "col5": "nd8jv", + "col6": "qn9xg", + "col7": "w4qfq", + "col8": "f5tg6", + "col9": "ebiwf", + "col10": "bf97k", + "col11": "54hzn", + "col12": "vyg8t", + "col13": "l6p0h", + "col14": "v98qp", + "col15": "v3p2b", + "col16": "0dutt", + "col17": "uyihb", + "col18": "uxgmw", + "col19": "1f5ig", + "col20": "kwz24", + "col21": "iq1um", + "col22": "ltpx8", + "col23": "8w4n6", + "col24": "q2aqf", + "col25": "kq3nl", + "col26": "jgwp8", + "col27": "szkbn", + "col28": "l4r2w", + "col29": "166ir", + "col30": "c55g3", + "col31": "0r4n1", + "col32": "7zwu2", + "col33": "1xpaq", + "col34": "kfgur", + "col35": "6lf4k", + "col36": "da22o", + "col37": "5plqn", + "col38": "zllmo", + "col39": "m2z0y", + "col40": "2r12l", + "col41": "72ovh", + "col42": "35fst", + "col43": "1fqc2", + "col44": "irtj0", + "col45": "erjzx", + "col46": "hu899", + "col47": "qlcua", + "col48": "2z3j1", + "col49": "yttfp", + "col50": "rwfgl", + "col51": "rv9fj", + "col52": "77fws", + "col53": "x5ksk", + "col54": "ux1mm", + "col55": "ot3bs", + "col56": "7rc0a", + "col57": "at623", + "col58": "t49yr", + "col59": "j4rok", + "col60": "95djp", + "col61": "ahfz5", + "col62": "w8bs6", + "col63": "9wo3t", + "col64": "m12cw", + "col65": "1gmns", + "col66": "57xyk", + "col67": "oa0v9", + "col68": "ftk54", + "col69": "886j7", + "col70": "nd9e5", + "col71": "xtm7q", + "col72": "3q6fe", + "col73": "vf0en", + "col74": "rtdsq", + "col75": "qlxag", + "col76": "1blb8", + "col77": "2w6va", + "col78": "ur6io", + "col79": "i5zzg", + "col80": "fy6jd", + "col81": "mv2dv", + "col82": "cb7xy", + "col83": "ibq8n", + "col84": "vovau", + "col85": "z1cje", + "col86": "t75xx", + "col87": "fdvdu", + "col88": "sbj39", + "col89": "uqvsn", + "col90": "b5v87", + "col91": "osqv6", + "col92": "6ld68", + "col93": "ss3tf", + "col94": "uwqx8", + "col95": "wy44d", + "col96": "utlgz", + "col97": "72dxv", + "col98": "4ev2r", + "col99": "pgq17", + "col100": "9vqrq", + "col101": "qerpz", + "col102": "vb7hv", + "col103": "d9og5", + "col104": "csj24", + "col105": "4kb19", + "col106": "7w06i", + "col107": "o0hhu", + "col108": "cg8g2", + "col109": "n47b7", + "col110": "78rx3", + "col111": "egu0m", + "col112": "f8fif", + "col113": "pthcb", + "col114": "h84kq", + "col115": "oilmj", + "col116": "1y1j5", + "col117": "t3apn", + "col118": "7vdp9", + "col119": "7opm4", + "col120": "qj39x", + "col121": "ufnsq", + "col122": "mdax0", + "col123": "ydrfb", + "col124": "0anjh", + "col125": "aprlc", + "col126": "k5vbl", + "col127": "booua", + "col128": "clsap", + "col129": "w9fyv", + "col130": "goj5i", + "col131": "miqzv", + "col132": "d0mmt", + "col133": "il110", + "col134": "xl41l", + "col135": "h3uzi", + "col136": "8ic4g", + "col137": "z335x", + "col138": "61t1y", + "col139": "1w9ae", + "col140": "ul8yt", + "col141": "9ncdy", + "col142": "9u3r5", + "col143": "oejn4", + "col144": "woajr", + "col145": "j72yn", + "col146": "1kc0b", + "col147": "8lt70", + "col148": "dayy2", + "col149": "8eept", + "col150": "wgenj", + "col151": "fqwlm", + "col152": "uyajl", + "col153": "a7p7s", + "col154": "j8ew5", + "col155": "wdfo5", + "col156": "z5lps", + "col157": "gku9n", + "col158": "xcbls", + "col159": "sugpv", + "col160": "jr6on", + "col161": "fs1uz", + "col162": "54e7w", + "col163": "vj3ob", + "col164": "qeboa", + "col165": "ku76y", + "col166": "lwl81", + "col167": "wgwez", + "col168": "51dxs", + "col169": "xd4wx", + "col170": "k89h3", + "col171": "ohb2p", + "col172": "fwfi1", + "col173": "2sthp", + "col174": "adqgv", + "col175": "7uo3l", + "col176": "3mdik", + "col177": "7geyi", + "col178": "j0p91", + "col179": "eyd5h", + "col180": "6gv9d", + "col181": "fhliq", + "col182": "1293o", + "col183": "vl29c", + "col184": "xkrdd", + "col185": "6my7e", + "col186": "2v3l3", + "col187": "k60zs", + "col188": "58zjv", + "col189": "bgagv", + "col190": "aildw", + "col191": "82oh9", + "col192": "fywqv", + "col193": "nwxfa", + "col194": "xvx5d", + "col195": "16wdb", + "col196": "ol0yg", + "col197": "am77l", + "col198": "sjxqi", + "col199": "rcifx", + "col200": "e4dxp", + "col201": "uls1n", + "col202": "4gw4j", + "col203": "6ukx2", + "col204": "c9kx0", + "col205": "b8si5", + "col206": "qpjo4", + "col207": "a4z3e", + "col208": "py56t", + "col209": "15wql", + "col210": "gyiqv", + "col211": "gwlt7", + "col212": "9m999", + "col213": "qkjfh", + "col214": "071v5", + "col215": "z9029", + "col216": "12d3h", + "col217": "uc7ib", + "col218": "u7ga6", + "col219": "16g9m", + "col220": "dplco", + "col221": "d6dmw", + "col222": "055tm", + "col223": "tv1q7", + "col224": "j80bb", + "col225": "h3lou", + "col226": "czwo5", + "col227": "86qsf", + "col228": "ow1h5", + "col229": "l188d", + "col230": "3af1l", + "col231": "kpe5f", + "col232": "qtktb", + "col233": "qw4uh", + "col234": "ql5c6", + "col235": "uot4z", + "col236": "5qstk", + "col237": "otqno", + "col238": "figro", + "col239": "t93zz", + "col240": "fqtm9", + "col241": "9zdp9", + "col242": "sqszp", + "col243": "fq86u", + "col244": "p6mrj", + "col245": "o9izy", + "col246": "2db6e", + "col247": "23db5", + "col248": "c520j", + "col249": "rubpn", + "col250": "p03t0", + "col251": "gb2ot", + "col252": "3wpnw", + "col253": "9e7nl", + "col254": "5mb7e", + "col255": "3bkrr", + "col256": "j7pzp", + "col257": "y45tt", + "col258": "x1du4", + "col259": "ed3f8", + "col260": "n9qgl", + "col261": "v9l3a", + "col262": "hazbo", + "col263": "5hurn", + "col264": "sgvk7", + "col265": "9onvu", + "col266": "abbsl", + "col267": "lq39c", + "col268": "vm8wa", + "col269": "ejiqu", + "col270": "bmf1r", + "col271": "0b6fq", + "col272": "ndxph", + "col273": "stj19", + "col274": "urx3g", + "col275": "t9fmh", + "col276": "bida0", + "col277": "9lm6k", + "col278": "v8l3m", + "col279": "4pcoh", + "col280": "j589u", + "col281": "h7gwb", + "col282": "zhlap", + "col283": "r3ief", + "col284": "xgs9c", + "col285": "1b2y3", + "col286": "kx7uv", + "col287": "q4iuf", + "col288": "m9cfz", + "col289": "fordh", + "col290": "o1hba", + "col291": "4z7qw", + "col292": "qy4ou", + "col293": "iru66", + "col294": "8gmm0", + "col295": "0b74q", + "col296": "bllgp", + "col297": "491wa", + "col298": "2k9ch", + "col299": "9ap63", + "col300": "nk622", + "col301": "u7hgm", + "col302": "3fvmy", + "col303": "o61bg", + "col304": "r62lp", + "col305": "fr4zf", + "col306": "ay4hu", + "col307": "jw6vi", + "col308": "f9b5g", + "col309": "nko1y", + "col310": "savk8", + "col311": "san9l", + "col312": "m6kek", + "col313": "7hqof", + "col314": "a7jpe", + "col315": "4e49s", + "col316": "ncdmk", + "col317": "vhsbk", + "col318": "ehc1k", + "col319": "7it6k", + "col320": "a3enl", + "col321": "m4rlr", + "col322": "92cvn", + "col323": "q2hee", + "col324": "y3dd2", + "col325": "ygnm9", + "col326": "yy6fk", + "col327": "hze3r", + "col328": "girjz", + "col329": "b2k4l", + "col330": "5k950", + "col331": "jsosh", + "col332": "sp133", + "col333": "1nrhp", + "col334": "4pmoi", + "col335": "9xl5y", + "col336": "jrn93", + "col337": "4ff7n", + "col338": "1zh6p", + "col339": "59b89", + "col340": "mzina", + "col341": "36jyz", + "col342": "kgce2", + "col343": "u0iry", + "col344": "xbg35", + "col345": "feomn", + "col346": "jx21m", + "col347": "ms4nc", + "col348": "osejp", + "col349": "e66z1", + "col350": "8yka7", + "col351": "8lkh5", + "col352": "mzls0", + "col353": "xcv30", + "col354": "v7r2n", + "col355": "e7w1w", + "col356": "pwx4u", + "col357": "zhtg7", + "col358": "l18dr", + "col359": "68tof", + "col360": "jxksz", + "col361": "z3e16", + "col362": "nbrvg", + "col363": "gvwrs", + "col364": "ml21f", + "col365": "9imft", + "col366": "epsyc", + "col367": "ygf8w", + "col368": "tn2xu", + "col369": "fm5e5", + "col370": "s3ztn", + "col371": "2dwye", + "col372": "7wf0y", + "col373": "85s0g", + "col374": "pl398", + "col375": "s8aiz", + "col376": "nc6kw", + "col377": "oti95", + "col378": "ah46u", + "col379": "7g6pl", + "col380": "0309w", + "col381": "go3r7", + "col382": "ssnx1", + "col383": "wnt0l", + "col384": "vimda", + "col385": "lpvgb", + "col386": "u3h54", + "col387": "c9fq4", + "col388": "qzo9y", + "col389": "47p4s", + "col390": "db867", + "col391": "8px83", + "col392": "5i8cj", + "col393": "icw17", + "col394": "sg6di", + "col395": "mtjgu", + "col396": "tvmnf", + "col397": "ilmiu", + "col398": "pgewx", + "col399": "fo18h", + "col400": "co53a", + "col401": "vgidu", + "col402": "7252z", + "col403": "d2y4m", + "col404": "prtjb", + "col405": "wfzqb", + "col406": "ks4de", + "col407": "138k2", + "col408": "xgb08", + "col409": "2n5uq", + "col410": "egttg", + "col411": "8xk9m", + "col412": "ftffq", + "col413": "zspv5", + "col414": "7h7jt", + "col415": "uzm99", + "col416": "1g5vr", + "col417": "hy3k3", + "col418": "v7cig", + "col419": "wp3aa", + "col420": "d6o49", + "col421": "fdoc0", + "col422": "dwu08", + "col423": "aiu7q", + "col424": "q8ds5", + "col425": "1q052", + "col426": "ma3c5", + "col427": "bvndu", + "col428": "7jku3", + "col429": "1gmcs", + "col430": "3ovqm", + "col431": "cxd5i", + "col432": "zpd8n", + "col433": "zsokz", + "col434": "2zf5j", + "col435": "hzvig", + "col436": "6jtbm", + "col437": "f067v", + "col438": "8w13u", + "col439": "p11ve", + "col440": "wcygo", + "col441": "4c948", + "col442": "jgwuo", + "col443": "yghal", + "col444": "p2vbd", + "col445": "eenpi", + "col446": "ojcnt", + "col447": "a1j1k", + "col448": "wr2v9", + "col449": "akrwj", + "col450": "h7oqd", + "col451": "ffrcv", + "col452": "e329h", + "col453": "fb3cx", + "col454": "fb1l1", + "col455": "e08od", + "col456": "hdkls", + "col457": "elj72", + "col458": "nhs96", + "col459": "03yka", + "col460": "o1mo7", + "col461": "1eqa1", + "col462": "o7fex", + "col463": "bqxs1", + "col464": "l2xpn", + "col465": "beq5t", + "col466": "qi3od", + "col467": "8hwcz", + "col468": "mu6k4", + "col469": "dzoxe", + "col470": "kjaa4", + "col471": "gn1zv", + "col472": "oxp4x", + "col473": "cl8wh", + "col474": "617pp", + "col475": "f48m9", + "col476": "9g31z", + "col477": "b9kj7", + "col478": "sx3k5", + "col479": "87np8", + "col480": "sy51a", + "col481": "pbich", + "col482": "d7q9f", + "col483": "mvrws", + "col484": "ae95n", + "col485": "wgv70", + "col486": "57fxf", + "col487": "dwokm", + "col488": "fb6f5", + "col489": "lwznz", + "col490": "kp76a", + "col491": "dobwm", + "col492": "vqlp1", + "col493": "r3av4", + "col494": "41n24", + "col495": "p9q97", + "col496": "ffeg1", + "col497": "fniy7", + "col498": "jbxh5", + "col499": "szntu", + "col500": "hppl7", + "col501": "2g0t7", + "col502": "eyen1", + "col503": "bvsh3", + "col504": "8s9zt", + "col505": "eyt6v", + "col506": "dgmjv", + "col507": "vx9qq", + "col508": "9srhv", + "col509": "oiws9", + "col510": "0jv10", + "col511": "pla98", + "col512": "2k57q", + "col513": "yjsp2", + "col514": "19xp2", + "col515": "k2518", + "col516": "jxoqk", + "col517": "yp713", + "col518": "isr2j", + "col519": "wtue9", + "col520": "mosny", + "col521": "1ftxl", + "col522": "xdzqx", + "col523": "dtozo", + "col524": "tiql2", + "col525": "di17p", + "col526": "k9e1p", + "col527": "hllod", + "col528": "8kol1", + "col529": "j4azc", + "col530": "c0ajy", + "col531": "aggnz", + "col532": "p3uqb", + "col533": "qjg4f", + "col534": "nf8u7", + "col535": "r5zsy", + "col536": "ix9ev", + "col537": "csxvv", + "col538": "nily2", + "col539": "k6a13", + "col540": "sh8ie", + "col541": "6xdjg", + "col542": "rre2i", + "col543": "qives", + "col544": "yhjau", + "col545": "0lw9v", + "col546": "i8x8k", + "col547": "jmkem", + "col548": "yzq7n", + "col549": "etk9l", + "col550": "raq5y", + "col551": "yia0z", + "col552": "uni8s", + "col553": "bwfr4", + "col554": "cvhoq", + "col555": "ry0al", + "col556": "1s0fm", + "col557": "hnm32", + "col558": "3c4zy", + "col559": "n5h3q", + "col560": "44pz9", + "col561": "xncv9", + "col562": "ryczg", + "col563": "5qm3q", + "col564": "voqmj", + "col565": "ov7ii", + "col566": "9j4xu", + "col567": "gsy50", + "col568": "a18a9", + "col569": "gi424", + "col570": "wlcr6", + "col571": "u07ff", + "col572": "xik3c", + "col573": "syla0", + "col574": "17961", + "col575": "vezzi", + "col576": "9jp0f", + "col577": "ml83r", + "col578": "383vo", + "col579": "ntrci", + "col580": "fu4jd", + "col581": "iq0tc", + "col582": "0c0d6", + "col583": "z0vad", + "col584": "y27b3", + "col585": "pr655", + "col586": "2ktnl", + "col587": "auudg", + "col588": "g07qp", + "col589": "n91wb", + "col590": "6wxsc", + "col591": "bfqrw", + "col592": "my0ef", + "col593": "i47ls", + "col594": "cw2vk", + "col595": "p8ocr", + "col596": "chetd", + "col597": "srybu", + "col598": "z5nyg", + "col599": "pm4oa", + "col600": "hpqvz", + "col601": "40frv", + "col602": "ggxsm", + "col603": "m7ysq", + "col604": "6wl66", + "col605": "x21gx", + "col606": "vl2a9", + "col607": "tya47", + "col608": "j18zm", + "col609": "mofup", + "col610": "6y9ur", + "col611": "ow7pi", + "col612": "5jcfq", + "col613": "1g56y", + "col614": "6p81u", + "col615": "9ng8l", + "col616": "ghrpg", + "col617": "ie80l", + "col618": "k18xd", + "col619": "hk82s", + "col620": "sdtlc", + "col621": "cqp3e", + "col622": "3qywa", + "col623": "3fvl2", + "col624": "ifhg0", + "col625": "zwdud", + "col626": "0p8gh", + "col627": "agkws", + "col628": "a6il7", + "col629": "fqd4d", + "col630": "utf1o", + "col631": "j25dn", + "col632": "wktd9", + "col633": "ckgkz", + "col634": "7oex1", + "col635": "b8m85", + "col636": "piwug", + "col637": "4y2gq", + "col638": "ojznq", + "col639": "w7ohs", + "col640": "vohxi", + "col641": "mb29s", + "col642": "dyqk5", + "col643": "u16lj", + "col644": "q7cyx", + "col645": "1r0rp", + "col646": "1pyes", + "col647": "hyos7", + "col648": "ig57r", + "col649": "15j7l", + "col650": "e6uw2", + "col651": "x2bgx", + "col652": "6otnd", + "col653": "fa3q6", + "col654": "fd0tk", + "col655": "hahrj", + "col656": "m6zy4", + "col657": "ob50x", + "col658": "p3hcf", + "col659": "4mr4y", + "col660": "6w6mr", + "col661": "7ecr1", + "col662": "6ln74", + "col663": "20vd0", + "col664": "lzpdm", + "col665": "blvec", + "col666": "ecnzc", + "col667": "mi7mi", + "col668": "1qwct", + "col669": "7g262", + "col670": "pchz2", + "col671": "48f95", + "col672": "bp7u1", + "col673": "3q6po", + "col674": "05lss", + "col675": "3l09w", + "col676": "rovca", + "col677": "ic4ut", + "col678": "kqc65", + "col679": "trna8", + "col680": "dxuvy", + "col681": "scdm0", + "col682": "4va5y", + "col683": "t368s", + "col684": "5ekb7", + "col685": "vjgz8", + "col686": "b86zn", + "col687": "nz1cu", + "col688": "6iptg", + "col689": "i0icq", + "col690": "y8zi8", + "col691": "phw4y", + "col692": "bu47j", + "col693": "rjis9", + "col694": "bc5kh", + "col695": "jeq94", + "col696": "amif7", + "col697": "a7ybh", + "col698": "p5dn7", + "col699": "tyj7m", + "col700": "vc0hr", + "col701": "3u9rm", + "col702": "nw8t9", + "col703": "apq55", + "col704": "1ne6q", + "col705": "mh2z9", + "col706": "c3he9", + "col707": "7gemh", + "col708": "gd47e", + "col709": "hd5lf", + "col710": "ui2qb", + "col711": "xtlpf", + "col712": "ln34l", + "col713": "vz5h4", + "col714": "jma4t", + "col715": "bb7gv", + "col716": "0vrel", + "col717": "bk6be", + "col718": "k4rpm", + "col719": "zujgt", + "col720": "15xsg", + "col721": "9ok4d", + "col722": "oig6z", + "col723": "6lifo", + "col724": "1031v", + "col725": "rjs5g", + "col726": "ut27b", + "col727": "1llwq", + "col728": "oopjp", + "col729": "ksgr2", + "col730": "245y6", + "col731": "xosnq", + "col732": "z4flq", + "col733": "e52ay", + "col734": "lkx5n", + "col735": "cdutu", + "col736": "3erjn", + "col737": "tpjs3", + "col738": "bpcpp", + "col739": "mibar", + "col740": "6ssf1", + "col741": "beaht", + "col742": "a5x9u", + "col743": "cwi7o", + "col744": "2rbz2", + "col745": "nmjzl", + "col746": "3vw2b", + "col747": "od1tq", + "col748": "fr9gc", + "col749": "ye31s", + "col750": "mkype", + "col751": "dmjw1", + "col752": "iu3yn", + "col753": "zjtxf", + "col754": "mcr3v", + "col755": "ea6jd", + "col756": "zt9mx", + "col757": "ije4s", + "col758": "jrcpa", + "col759": "q82l3", + "col760": "2r290", + "col761": "2catj", + "col762": "0pzy4", + "col763": "1l904", + "col764": "kmzdf", + "col765": "4t469", + "col766": "mvg0z", + "col767": "pt38w", + "col768": "w3d3h", + "col769": "jqvtn", + "col770": "l0w0r", + "col771": "ss1ds", + "col772": "us81l", + "col773": "n9nak", + "col774": "93wl6", + "col775": "etak5", + "col776": "0yvau", + "col777": "gzsjx", + "col778": "larqd", + "col779": "1tnzi", + "col780": "ycdh0", + "col781": "4eijj", + "col782": "zrobu", + "col783": "wdfy4", + "col784": "69ygw", + "col785": "6ozpy", + "col786": "tj0kl", + "col787": "i2t61", + "col788": "4hiei", + "col789": "32kg6", + "col790": "l969i", + "col791": "fedsr", + "col792": "43ro4", + "col793": "g1epg", + "col794": "gn9e0", + "col795": "xmj1r", + "col796": "e9bvn", + "col797": "vt43e", + "col798": "qzavv", + "col799": "wfsy5", + "col800": "xrckx", + "col801": "ovbvd", + "col802": "e9cb5", + "col803": "kywiw", + "col804": "xzqzp", + "col805": "g83hb", + "col806": "8m5sj", + "col807": "kkv4v", + "col808": "b3jit", + "col809": "5fyce", + "col810": "t8gwv", + "col811": "i8rho", + "col812": "k6a6b", + "col813": "l4ci0", + "col814": "vj0fv", + "col815": "j6enb", + "col816": "rhsrg", + "col817": "6m8i4", + "col818": "zt8tu", + "col819": "nxh4s", + "col820": "2d0jv", + "col821": "xxzjl", + "col822": "p7m0l", + "col823": "6a55w", + "col824": "jnmzy", + "col825": "ub9hv", + "col826": "rgw2h", + "col827": "sjctg", + "col828": "0hd15", + "col829": "1w1r8", + "col830": "y5i8s", + "col831": "3bd2s", + "col832": "h86xz", + "col833": "owg6x", + "col834": "pvgbz", + "col835": "j2cwb", + "col836": "xm0t9", + "col837": "v1p72", + "col838": "aamxa", + "col839": "qbqn0", + "col840": "60ujd", + "col841": "j4xc7", + "col842": "dipb0", + "col843": "15lfl", + "col844": "hu2rk", + "col845": "zfv7d", + "col846": "n0k7x", + "col847": "tjzfr", + "col848": "n0s68", + "col849": "6vkno", + "col850": "npuhz", + "col851": "wulsy", + "col852": "8mdj2", + "col853": "46blg", + "col854": "23o1j", + "col855": "6nvpk", + "col856": "8rh44", + "col857": "24a86", + "col858": "l2knb", + "col859": "klf5n", + "col860": "544ic", + "col861": "2uqdi", + "col862": "gjyie", + "col863": "24rdr", + "col864": "m6opr", + "col865": "tfwvs", + "col866": "pgtht", + "col867": "az06w", + "col868": "oqabp", + "col869": "lvbm8", + "col870": "o376i", + "col871": "yevqz", + "col872": "cuf49", + "col873": "m5fec", + "col874": "4j095", + "col875": "ti4vk", + "col876": "2srw0", + "col877": "zzhn1", + "col878": "46g79", + "col879": "xyf47", + "col880": "n0nj5", + "col881": "6gmqg", + "col882": "htzle", + "col883": "mqdob", + "col884": "as2ku", + "col885": "0a01v", + "col886": "gyt9i", + "col887": "pqcbm", + "col888": "i9ors", + "col889": "ph7be", + "col890": "2nbi8", + "col891": "kjkfl", + "col892": "u2wzo", + "col893": "tsc5n", + "col894": "5croq", + "col895": "kthgo", + "col896": "zmixj", + "col897": "43pyp", + "col898": "94qn5", + "col899": "blim4", + "col900": "a352k", + "col901": "lq1mc", + "col902": "ghyv0", + "col903": "f07ad", + "col904": "e67vi", + "col905": "17mut", + "col906": "20afw", + "col907": "1h0g6", + "col908": "mwg29", + "col909": "bus4a", + "col910": "lihmg", + "col911": "ylt38", + "col912": "saggz", + "col913": "3yi9m", + "col914": "2pjbn", + "col915": "1the4", + "col916": "ickt3", + "col917": "7ftzc", + "col918": "u2miv", + "col919": "ymguh", + "col920": "r0i06", + "col921": "1xqyp", + "col922": "d6npp", + "col923": "vw8ni", + "col924": "rrhyc", + "col925": "u3vha", + "col926": "17ktz", + "col927": "7bhqr", + "col928": "zldha", + "col929": "cl8b9", + "col930": "heiaa", + "col931": "ag0p9", + "col932": "j9sbf", + "col933": "k3bss", + "col934": "p8zrr", + "col935": "q2quj", + "col936": "f24d4", + "col937": "fzj4p", + "col938": "pkr2l", + "col939": "8sgkw", + "col940": "b5t8a", + "col941": "r2n50", + "col942": "eiodc", + "col943": "aqiib", + "col944": "ziryi", + "col945": "24xsq", + "col946": "9tahn", + "col947": "z8kw8", + "col948": "mdfil", + "col949": "sys70", + "col950": "nymrm", + "col951": "0qyzr", + "col952": "vgp6y", + "col953": "8nom9", + "col954": "aquud", + "col955": "w2174", + "col956": "3kjjt", + "col957": "k2to1", + "col958": "tgj9d", + "col959": "m32fx", + "col960": "l42ua", + "col961": "hysut", + "col962": "s08de", + "col963": "wcx1z", + "col964": "05fkw", + "col965": "5ryec", + "col966": "9y50q", + "col967": "0kmui", + "col968": "1xsvs", + "col969": "1kfun", + "col970": "0exwb", + "col971": "ldo9p", + "col972": "u86vd", + "col973": "hlojb", + "col974": "9m7r3", + "col975": "k3spr", + "col976": "6fyca", + "col977": "x8ban", + "col978": "rtt8v", + "col979": "qx8cv", + "col980": "xx6rx", + "col981": "txk6i", + "col982": "ncjr5", + "col983": "ngppp", + "col984": "iyaa6", + "col985": "eoa9y", + "col986": "a5ckq", + "col987": "fqorx", + "col988": "qgvo2", + "col989": "wv0cn", + "col990": "hlf6d", + "col991": "dtp4t", + "col992": "2j48n", + "col993": "asvxp", + "col994": "05fdu", + "col995": "hbvv8", + "col996": "5lx6k", + "col997": "frfip", + "col998": "y347p", + "col999": "j4vb4" + }, + { + "name": "Maryellen Bender", + "gender": "female", + "col0": "8spbw", + "col1": "df5i9", + "col2": "rhqvc", + "col3": "xhfjx", + "col4": "8nt0e", + "col5": "x0yu2", + "col6": "ezgws", + "col7": "4vm0a", + "col8": "nj5ww", + "col9": "5zzmz", + "col10": "l8wba", + "col11": "yquk3", + "col12": "3ci2l", + "col13": "8ir3d", + "col14": "g02rl", + "col15": "9a3a2", + "col16": "mkmws", + "col17": "7l3zl", + "col18": "qd0g9", + "col19": "m9g2i", + "col20": "6hl0g", + "col21": "sx3mu", + "col22": "uby22", + "col23": "5g1t6", + "col24": "g5ymh", + "col25": "gnx08", + "col26": "ft4gw", + "col27": "nuyxg", + "col28": "73g77", + "col29": "ugvbg", + "col30": "26u0l", + "col31": "51cy3", + "col32": "jwksi", + "col33": "vurlv", + "col34": "uax5k", + "col35": "u6yue", + "col36": "zpv9e", + "col37": "w0vrf", + "col38": "1u6qz", + "col39": "1x02s", + "col40": "mdjp5", + "col41": "wztvm", + "col42": "1pvay", + "col43": "sev3r", + "col44": "g8sik", + "col45": "dfkzb", + "col46": "0wp3t", + "col47": "0v5s8", + "col48": "8xyue", + "col49": "6tbvt", + "col50": "36gx8", + "col51": "z8wx2", + "col52": "npl0l", + "col53": "qo36j", + "col54": "brqul", + "col55": "bclim", + "col56": "x95sd", + "col57": "fefny", + "col58": "zx78l", + "col59": "vbnj2", + "col60": "me13f", + "col61": "z482k", + "col62": "7pfxm", + "col63": "m2hs9", + "col64": "oi53r", + "col65": "9deb0", + "col66": "qsrzk", + "col67": "xa8h3", + "col68": "46bih", + "col69": "wfir2", + "col70": "zw5hw", + "col71": "d3fv9", + "col72": "mpsln", + "col73": "gelq9", + "col74": "5wdow", + "col75": "fuzgp", + "col76": "dcayk", + "col77": "lj2hx", + "col78": "9n0mh", + "col79": "ib6s7", + "col80": "zdqkc", + "col81": "ll7ko", + "col82": "eu1mi", + "col83": "icpj5", + "col84": "7ouyr", + "col85": "eav83", + "col86": "kj5fn", + "col87": "2jcxk", + "col88": "z5udl", + "col89": "aocl0", + "col90": "x26bs", + "col91": "icpg9", + "col92": "hsjjo", + "col93": "5ros5", + "col94": "7fo47", + "col95": "0p4bz", + "col96": "jbdp4", + "col97": "5sy3v", + "col98": "0mlnu", + "col99": "93i16", + "col100": "l8l2k", + "col101": "yxkpw", + "col102": "ekxpt", + "col103": "ubcw2", + "col104": "6r1pm", + "col105": "p8n2s", + "col106": "vprcx", + "col107": "zpsne", + "col108": "krrho", + "col109": "tspyb", + "col110": "0xfhy", + "col111": "eb7jh", + "col112": "49n1i", + "col113": "0iufr", + "col114": "9ihp2", + "col115": "7sh6h", + "col116": "f8m5q", + "col117": "yrnr4", + "col118": "trghi", + "col119": "kggnf", + "col120": "9q6wu", + "col121": "tzyz2", + "col122": "tqt5z", + "col123": "oflm3", + "col124": "moy5p", + "col125": "hfpdk", + "col126": "2nhwz", + "col127": "vmeju", + "col128": "p1xv3", + "col129": "prrjo", + "col130": "qlzso", + "col131": "rhif8", + "col132": "9nkuj", + "col133": "qftwk", + "col134": "urscw", + "col135": "rto67", + "col136": "20fny", + "col137": "s3kuk", + "col138": "dubsb", + "col139": "xn90y", + "col140": "ywoym", + "col141": "dejsn", + "col142": "p0rlm", + "col143": "bzxli", + "col144": "tuxm6", + "col145": "bptz9", + "col146": "5ke2q", + "col147": "7c27r", + "col148": "rcqne", + "col149": "n5zkf", + "col150": "upobh", + "col151": "9ffpc", + "col152": "de1o4", + "col153": "akw5y", + "col154": "3f1ib", + "col155": "n84e9", + "col156": "pliow", + "col157": "tq936", + "col158": "bpu96", + "col159": "iy1y8", + "col160": "y2s5r", + "col161": "ay87h", + "col162": "6khml", + "col163": "ka63o", + "col164": "xpx9m", + "col165": "3pm3h", + "col166": "sao4v", + "col167": "hu27x", + "col168": "zh9jy", + "col169": "pq5k5", + "col170": "3g7us", + "col171": "l336t", + "col172": "oxb1y", + "col173": "t2s3n", + "col174": "sr59k", + "col175": "gpmtr", + "col176": "ik35u", + "col177": "iareb", + "col178": "9l4ji", + "col179": "y6vty", + "col180": "bjstt", + "col181": "2s2tf", + "col182": "dp5vm", + "col183": "lcc9e", + "col184": "zdbzu", + "col185": "wnu5b", + "col186": "tz126", + "col187": "mby74", + "col188": "c8o21", + "col189": "6rtj8", + "col190": "34ga9", + "col191": "lwjlf", + "col192": "see6c", + "col193": "hwuwp", + "col194": "vrghf", + "col195": "huqvo", + "col196": "ws7kc", + "col197": "tufib", + "col198": "55m86", + "col199": "29bse", + "col200": "07rg4", + "col201": "1cskw", + "col202": "aw0hv", + "col203": "luk3g", + "col204": "8u3n8", + "col205": "k9kvr", + "col206": "5apoq", + "col207": "87k0z", + "col208": "kpxuf", + "col209": "l8xbs", + "col210": "stagv", + "col211": "nm3qb", + "col212": "1avc7", + "col213": "psq5b", + "col214": "rwrsb", + "col215": "ii0m4", + "col216": "dz72k", + "col217": "nrenm", + "col218": "7c1ky", + "col219": "2b8k0", + "col220": "mjuhe", + "col221": "ikl21", + "col222": "5gb0a", + "col223": "lykej", + "col224": "syqdg", + "col225": "yr68l", + "col226": "4j9vt", + "col227": "gzwnp", + "col228": "vgnyx", + "col229": "qlqz7", + "col230": "p0o1h", + "col231": "mflq8", + "col232": "lsc0c", + "col233": "3u3op", + "col234": "20zcy", + "col235": "lzt13", + "col236": "i9qkg", + "col237": "8ietw", + "col238": "9g2pk", + "col239": "6wwzt", + "col240": "clud2", + "col241": "bmocz", + "col242": "c7yqy", + "col243": "z1yc4", + "col244": "51uey", + "col245": "7xmyq", + "col246": "gq7u8", + "col247": "hhgbw", + "col248": "rtyeb", + "col249": "ptclh", + "col250": "u03ms", + "col251": "oysb4", + "col252": "atjut", + "col253": "a9tsi", + "col254": "7nfl2", + "col255": "zas34", + "col256": "bjwhq", + "col257": "h9xyz", + "col258": "ul5p8", + "col259": "n7924", + "col260": "fzk6z", + "col261": "bx7m3", + "col262": "u7vz9", + "col263": "vurbz", + "col264": "fm31a", + "col265": "w3s19", + "col266": "lqaro", + "col267": "gnl7s", + "col268": "y8ywy", + "col269": "00t6g", + "col270": "zzz6o", + "col271": "rfuxg", + "col272": "eoaz7", + "col273": "wlayw", + "col274": "cspgq", + "col275": "7chvx", + "col276": "qo3gf", + "col277": "waxmr", + "col278": "ex3np", + "col279": "lnbu3", + "col280": "aooi4", + "col281": "6ilfi", + "col282": "horz6", + "col283": "5tnax", + "col284": "qmfgg", + "col285": "vrs6h", + "col286": "ngz8h", + "col287": "htqzx", + "col288": "z3i6f", + "col289": "sj4yj", + "col290": "7q1o0", + "col291": "fsnry", + "col292": "3zpia", + "col293": "rzsyx", + "col294": "rsa9x", + "col295": "6203p", + "col296": "uqwkq", + "col297": "9z21b", + "col298": "yrb8t", + "col299": "7jgm1", + "col300": "c321o", + "col301": "skq2w", + "col302": "cbi1f", + "col303": "8x19l", + "col304": "toymk", + "col305": "8i7df", + "col306": "mrjg7", + "col307": "vxgt3", + "col308": "n7a9x", + "col309": "fhszo", + "col310": "j1qco", + "col311": "wn86b", + "col312": "x8jft", + "col313": "wj2nd", + "col314": "zpu5l", + "col315": "hmbnh", + "col316": "tap0e", + "col317": "291qw", + "col318": "cxebk", + "col319": "lw074", + "col320": "22tt3", + "col321": "h0231", + "col322": "ght9t", + "col323": "hxmcn", + "col324": "2ytmf", + "col325": "uv774", + "col326": "iw062", + "col327": "og159", + "col328": "tihob", + "col329": "6iqae", + "col330": "3mupe", + "col331": "gxitd", + "col332": "4njmy", + "col333": "brk1m", + "col334": "fcd82", + "col335": "qmx2h", + "col336": "t7usy", + "col337": "wu0on", + "col338": "afv8z", + "col339": "1uxpq", + "col340": "zrii9", + "col341": "3adby", + "col342": "ha7n3", + "col343": "matmd", + "col344": "p3o2f", + "col345": "t2jvv", + "col346": "dubop", + "col347": "xwzc4", + "col348": "fh0ur", + "col349": "d5g40", + "col350": "4e5xm", + "col351": "0pmnz", + "col352": "mfd9y", + "col353": "u5uu0", + "col354": "lgaiy", + "col355": "gfood", + "col356": "mmusv", + "col357": "kb5ki", + "col358": "v29el", + "col359": "zn0k5", + "col360": "3e4xg", + "col361": "6d77e", + "col362": "iwgm4", + "col363": "yzmpb", + "col364": "qe7ce", + "col365": "7m5uv", + "col366": "zcj8i", + "col367": "dahww", + "col368": "qyb1l", + "col369": "btrj6", + "col370": "c7ns9", + "col371": "dhktq", + "col372": "vjr0q", + "col373": "mk0a7", + "col374": "glb19", + "col375": "tn0ky", + "col376": "1gnx9", + "col377": "j0sfs", + "col378": "2dna7", + "col379": "wah5d", + "col380": "8c4ls", + "col381": "pdosv", + "col382": "uqpxc", + "col383": "hyt1f", + "col384": "4q6ww", + "col385": "a1lwd", + "col386": "qd0on", + "col387": "ff4cz", + "col388": "zcslm", + "col389": "bzs2h", + "col390": "ijta7", + "col391": "c25fi", + "col392": "udvl8", + "col393": "pun20", + "col394": "7k3we", + "col395": "btrki", + "col396": "z9yg1", + "col397": "26wl0", + "col398": "80r4s", + "col399": "7ue2b", + "col400": "1f31k", + "col401": "cu6hr", + "col402": "ixk2a", + "col403": "wxsvt", + "col404": "ienu7", + "col405": "g18me", + "col406": "pr0bn", + "col407": "v4xbo", + "col408": "qr1dm", + "col409": "xgat5", + "col410": "cb2i8", + "col411": "fhiii", + "col412": "11r4n", + "col413": "bp6k2", + "col414": "vb6jc", + "col415": "gp0m1", + "col416": "iord4", + "col417": "nq7pq", + "col418": "idzzq", + "col419": "em9rr", + "col420": "qrudd", + "col421": "awf4t", + "col422": "nq57l", + "col423": "ekr1s", + "col424": "m9nga", + "col425": "j13qy", + "col426": "3u72d", + "col427": "qcqoz", + "col428": "enich", + "col429": "lrg1h", + "col430": "7xnp6", + "col431": "ahef2", + "col432": "z9on5", + "col433": "v932r", + "col434": "39x1d", + "col435": "ynftg", + "col436": "2d7vw", + "col437": "avk1s", + "col438": "9rver", + "col439": "qkedq", + "col440": "mx28x", + "col441": "g22tz", + "col442": "gl7nn", + "col443": "g5c2m", + "col444": "mkc4z", + "col445": "xx3wk", + "col446": "9ide7", + "col447": "6ajqa", + "col448": "dg41l", + "col449": "4lnjs", + "col450": "j6fzn", + "col451": "6kkfz", + "col452": "y96yd", + "col453": "eoigx", + "col454": "igx8l", + "col455": "nb6ik", + "col456": "got1w", + "col457": "tyuse", + "col458": "zjeh2", + "col459": "pnau3", + "col460": "flwja", + "col461": "b5zbe", + "col462": "iub3u", + "col463": "h7cxy", + "col464": "olblx", + "col465": "qnxep", + "col466": "b8tup", + "col467": "uq26v", + "col468": "quwlz", + "col469": "ur9ox", + "col470": "lgzra", + "col471": "hyfwx", + "col472": "yye87", + "col473": "scdp8", + "col474": "87w67", + "col475": "fa0yr", + "col476": "u2jdb", + "col477": "e8326", + "col478": "uio03", + "col479": "wntr1", + "col480": "8jnu0", + "col481": "0c9ql", + "col482": "spmr7", + "col483": "ygjd4", + "col484": "oa1rj", + "col485": "0iqef", + "col486": "4a60v", + "col487": "aodmu", + "col488": "b18lh", + "col489": "fepk3", + "col490": "huvak", + "col491": "1e4qz", + "col492": "gvnsn", + "col493": "hfm77", + "col494": "7sc91", + "col495": "u3636", + "col496": "buom3", + "col497": "rril4", + "col498": "12d3m", + "col499": "kq1x4", + "col500": "chzar", + "col501": "75ly4", + "col502": "kgndy", + "col503": "bq4am", + "col504": "zh36e", + "col505": "y5k9u", + "col506": "gtw3l", + "col507": "28hcq", + "col508": "bdo99", + "col509": "bopr7", + "col510": "z8yhv", + "col511": "p7pfi", + "col512": "39ozc", + "col513": "pj7y9", + "col514": "qus14", + "col515": "nintq", + "col516": "i7df7", + "col517": "zy21a", + "col518": "qpgep", + "col519": "0bsrc", + "col520": "8vew2", + "col521": "abfnx", + "col522": "eqrn2", + "col523": "chhg1", + "col524": "1izkk", + "col525": "t46bc", + "col526": "yz8af", + "col527": "8hm66", + "col528": "imw7e", + "col529": "qg4jn", + "col530": "os7lb", + "col531": "1vjk3", + "col532": "bvidn", + "col533": "h07vq", + "col534": "ln18p", + "col535": "26zfw", + "col536": "0u87q", + "col537": "plwps", + "col538": "37zp5", + "col539": "fhy53", + "col540": "kws6c", + "col541": "4b5a9", + "col542": "47h96", + "col543": "zjy0j", + "col544": "vlgd4", + "col545": "stf1a", + "col546": "eq4zn", + "col547": "ff5be", + "col548": "8nn4w", + "col549": "yqslt", + "col550": "ks1fj", + "col551": "hnm2r", + "col552": "g5vmm", + "col553": "pye18", + "col554": "kbbkk", + "col555": "gu56s", + "col556": "kv63w", + "col557": "c3qx1", + "col558": "61l0a", + "col559": "y3bai", + "col560": "svn5a", + "col561": "v621t", + "col562": "w600z", + "col563": "gpxkh", + "col564": "7n1u7", + "col565": "bboye", + "col566": "yzq3u", + "col567": "mjmmy", + "col568": "p9q6b", + "col569": "s45se", + "col570": "fw1j6", + "col571": "vlvp4", + "col572": "h984b", + "col573": "2785f", + "col574": "yniv7", + "col575": "irldh", + "col576": "bknqu", + "col577": "an6z7", + "col578": "lxuz1", + "col579": "lj1bk", + "col580": "mxzi7", + "col581": "qti12", + "col582": "pvj1b", + "col583": "fcred", + "col584": "dojhs", + "col585": "z66b6", + "col586": "4f73g", + "col587": "dwhfh", + "col588": "bt50h", + "col589": "iwawr", + "col590": "9rso9", + "col591": "zk2hz", + "col592": "dueu9", + "col593": "8w85r", + "col594": "m3n5y", + "col595": "mme0q", + "col596": "hxhfv", + "col597": "wdhaq", + "col598": "qe874", + "col599": "60p4s", + "col600": "aurmq", + "col601": "2rxj9", + "col602": "zbft0", + "col603": "xd1gl", + "col604": "kd9pp", + "col605": "9nee3", + "col606": "3lx9c", + "col607": "wguh6", + "col608": "qrmeb", + "col609": "kzpbe", + "col610": "6zjkl", + "col611": "6ae4r", + "col612": "zfahz", + "col613": "lpzt1", + "col614": "jeuhc", + "col615": "6rig1", + "col616": "632ea", + "col617": "l14ie", + "col618": "lhxyx", + "col619": "5lm9w", + "col620": "2tx4s", + "col621": "jkwv5", + "col622": "d0sdu", + "col623": "l1ozs", + "col624": "re4q0", + "col625": "m67sp", + "col626": "e3a6f", + "col627": "71wrm", + "col628": "idfdi", + "col629": "qy9y2", + "col630": "sarrg", + "col631": "f1sq9", + "col632": "k2uws", + "col633": "1of47", + "col634": "m3kt9", + "col635": "dy867", + "col636": "vwgky", + "col637": "fc0ba", + "col638": "j0w4h", + "col639": "rymvu", + "col640": "37h1y", + "col641": "umpkz", + "col642": "06f3e", + "col643": "t4zwv", + "col644": "6mabt", + "col645": "nq42n", + "col646": "1pb84", + "col647": "mqi29", + "col648": "zizde", + "col649": "vclow", + "col650": "di35m", + "col651": "cdhff", + "col652": "vgmaa", + "col653": "a9b4p", + "col654": "4fdjr", + "col655": "f99sk", + "col656": "1p0br", + "col657": "7x7uj", + "col658": "xjrjz", + "col659": "x50it", + "col660": "k46bl", + "col661": "doh3b", + "col662": "rbuzk", + "col663": "uc2qh", + "col664": "6n6s2", + "col665": "hsfw7", + "col666": "5vrjg", + "col667": "fnwkw", + "col668": "md6z7", + "col669": "dkeh6", + "col670": "9ounm", + "col671": "ohyez", + "col672": "q3aht", + "col673": "rz6k7", + "col674": "vq1ji", + "col675": "20x1p", + "col676": "fkw26", + "col677": "p4rbt", + "col678": "gokhq", + "col679": "9mk1h", + "col680": "ukcnv", + "col681": "qgthk", + "col682": "gx1l0", + "col683": "tn8ps", + "col684": "gim8k", + "col685": "oggry", + "col686": "nn478", + "col687": "kjytq", + "col688": "ppfki", + "col689": "swwde", + "col690": "2ao9z", + "col691": "qcexg", + "col692": "v3yvj", + "col693": "vjikq", + "col694": "7hlvn", + "col695": "b6e0c", + "col696": "tsx4c", + "col697": "vnbnd", + "col698": "xvuxg", + "col699": "p5rnu", + "col700": "w7rpe", + "col701": "a1dli", + "col702": "gjy5v", + "col703": "6n5qy", + "col704": "0j5sl", + "col705": "tad2w", + "col706": "vxuqc", + "col707": "jt9k4", + "col708": "lks8h", + "col709": "0n9hv", + "col710": "365gs", + "col711": "djn3g", + "col712": "aie00", + "col713": "b9h0w", + "col714": "mk254", + "col715": "igp2z", + "col716": "vhl8x", + "col717": "7bwsl", + "col718": "yocw5", + "col719": "n6xja", + "col720": "ak9dw", + "col721": "o02w4", + "col722": "fw8yt", + "col723": "fb5mv", + "col724": "9x9yj", + "col725": "h0ygr", + "col726": "oyn3u", + "col727": "we5ij", + "col728": "zlkly", + "col729": "egsf7", + "col730": "830bf", + "col731": "l4j58", + "col732": "xy5f5", + "col733": "3m4ab", + "col734": "lkx3u", + "col735": "egtxo", + "col736": "qrdov", + "col737": "thf5h", + "col738": "54rqf", + "col739": "igp4t", + "col740": "j3qjn", + "col741": "6njbf", + "col742": "4fgtc", + "col743": "7hxrv", + "col744": "f79ow", + "col745": "f6los", + "col746": "q0h9r", + "col747": "jyi6b", + "col748": "8difg", + "col749": "jmtto", + "col750": "5ba33", + "col751": "sowvd", + "col752": "zcw0c", + "col753": "ywhh2", + "col754": "izt28", + "col755": "iu59n", + "col756": "v5rkv", + "col757": "bw7oe", + "col758": "5l1mt", + "col759": "22xla", + "col760": "glrx6", + "col761": "ued1k", + "col762": "03h2o", + "col763": "m0cq8", + "col764": "7ensy", + "col765": "mee5z", + "col766": "j39ir", + "col767": "qdjdo", + "col768": "5z74l", + "col769": "gj88v", + "col770": "wmlce", + "col771": "6uv4m", + "col772": "o679k", + "col773": "pim39", + "col774": "ej8l2", + "col775": "fwlie", + "col776": "5tguf", + "col777": "aaqpg", + "col778": "zzlyw", + "col779": "uhwge", + "col780": "5maxq", + "col781": "z603n", + "col782": "6f3lw", + "col783": "gv6bg", + "col784": "lja7m", + "col785": "vgxoc", + "col786": "3gaba", + "col787": "3duv5", + "col788": "sgv86", + "col789": "93ht1", + "col790": "nzd80", + "col791": "rjp0s", + "col792": "pj9rv", + "col793": "cofmt", + "col794": "7a6hv", + "col795": "br9sp", + "col796": "okg3w", + "col797": "n0mf7", + "col798": "4pm8g", + "col799": "iecih", + "col800": "mjiwe", + "col801": "wezmx", + "col802": "8ky5i", + "col803": "h9n23", + "col804": "anasc", + "col805": "p62ke", + "col806": "gdl4q", + "col807": "b7jwc", + "col808": "nenpc", + "col809": "jsszv", + "col810": "edaq6", + "col811": "r0g0h", + "col812": "1b1c1", + "col813": "42emt", + "col814": "djrud", + "col815": "hf4af", + "col816": "ffzhe", + "col817": "vm1oo", + "col818": "1zb2d", + "col819": "kgm3w", + "col820": "2r6hi", + "col821": "jxx5s", + "col822": "6br93", + "col823": "lo6ut", + "col824": "mysuh", + "col825": "3w6f4", + "col826": "pq4pn", + "col827": "s4sr3", + "col828": "sa1d4", + "col829": "jwsjq", + "col830": "esb62", + "col831": "xp9wi", + "col832": "9zt8i", + "col833": "yfdr1", + "col834": "ufvwx", + "col835": "oh5dr", + "col836": "8t07b", + "col837": "6f3on", + "col838": "fejyj", + "col839": "vpyla", + "col840": "wvlde", + "col841": "17haa", + "col842": "yx8jd", + "col843": "zx98d", + "col844": "pv1be", + "col845": "8wvh5", + "col846": "hmztd", + "col847": "n6fv3", + "col848": "ubnv4", + "col849": "n8oe7", + "col850": "7pwlg", + "col851": "v44b7", + "col852": "om3tn", + "col853": "8g13x", + "col854": "9r4z2", + "col855": "mw3pw", + "col856": "az6zl", + "col857": "ran49", + "col858": "1ohv6", + "col859": "fprvs", + "col860": "v8q6n", + "col861": "9ox4k", + "col862": "v2gdl", + "col863": "a00zj", + "col864": "03x3v", + "col865": "8ls8h", + "col866": "stlfd", + "col867": "i99yu", + "col868": "0kf0m", + "col869": "edzbj", + "col870": "x1jid", + "col871": "3qzre", + "col872": "e4cf6", + "col873": "5las9", + "col874": "cn5a9", + "col875": "x9uay", + "col876": "9l6xl", + "col877": "40auw", + "col878": "jbguy", + "col879": "zyy2m", + "col880": "usdef", + "col881": "53p59", + "col882": "99igu", + "col883": "y0bxz", + "col884": "3i7bq", + "col885": "qou00", + "col886": "z3h6h", + "col887": "kyrab", + "col888": "qhf9z", + "col889": "mcotx", + "col890": "1puv1", + "col891": "2uycx", + "col892": "ahpvp", + "col893": "b2urm", + "col894": "ve1ap", + "col895": "eez48", + "col896": "10ey8", + "col897": "nqwpz", + "col898": "d68m9", + "col899": "znory", + "col900": "d6be2", + "col901": "kjmc8", + "col902": "m3we9", + "col903": "9umgv", + "col904": "5vjxo", + "col905": "60lde", + "col906": "b0qty", + "col907": "54p8v", + "col908": "lpmow", + "col909": "fb000", + "col910": "fshxd", + "col911": "q9zhw", + "col912": "qqzo1", + "col913": "8n82j", + "col914": "ukey4", + "col915": "kb2am", + "col916": "e2ghx", + "col917": "lyxvq", + "col918": "m0af0", + "col919": "f8say", + "col920": "djka7", + "col921": "i4dku", + "col922": "l2y0d", + "col923": "5nq2l", + "col924": "u8her", + "col925": "erknp", + "col926": "5410l", + "col927": "5h5c8", + "col928": "q7zye", + "col929": "eoxwc", + "col930": "b0rxd", + "col931": "z5hxc", + "col932": "yy5h2", + "col933": "o2996", + "col934": "8bs0l", + "col935": "e0en9", + "col936": "pdgy9", + "col937": "4tbvi", + "col938": "t47n1", + "col939": "nck1r", + "col940": "5o3xq", + "col941": "fmckx", + "col942": "suz3q", + "col943": "b8tq4", + "col944": "hx5xu", + "col945": "k4m4r", + "col946": "0umk5", + "col947": "q9o3l", + "col948": "ygc46", + "col949": "xqbt8", + "col950": "xfpbn", + "col951": "4i3dl", + "col952": "lcokx", + "col953": "pycsj", + "col954": "e8eij", + "col955": "pwekg", + "col956": "weo6z", + "col957": "1b9b7", + "col958": "bd2gg", + "col959": "e82jf", + "col960": "v6v7s", + "col961": "7mhcl", + "col962": "28adv", + "col963": "lgetb", + "col964": "1w4l1", + "col965": "y41uq", + "col966": "5mg5m", + "col967": "yftpc", + "col968": "qiu4o", + "col969": "2uvy2", + "col970": "pszw8", + "col971": "rdoc4", + "col972": "sphwg", + "col973": "v6smk", + "col974": "5033e", + "col975": "l14pv", + "col976": "g6cy3", + "col977": "kthgp", + "col978": "hp84x", + "col979": "oof27", + "col980": "660vb", + "col981": "9n005", + "col982": "cduu3", + "col983": "1q0oz", + "col984": "kxfji", + "col985": "f8lgr", + "col986": "hhls7", + "col987": "33f90", + "col988": "ohxe4", + "col989": "8bsby", + "col990": "vp6i6", + "col991": "zfql3", + "col992": "q3ujj", + "col993": "o2ztt", + "col994": "s5ug1", + "col995": "79pjl", + "col996": "c457j", + "col997": "n07a5", + "col998": "3xthx", + "col999": "cfdoc" + }, + { + "name": "Marla Summers", + "gender": "female", + "col0": "h17q0", + "col1": "x3d2z", + "col2": "xu4tf", + "col3": "7w1pv", + "col4": "dqqo3", + "col5": "q926x", + "col6": "wg4q2", + "col7": "e5qko", + "col8": "74teh", + "col9": "wzgxv", + "col10": "2ofee", + "col11": "r6igh", + "col12": "x0w3f", + "col13": "8gx3y", + "col14": "97hyi", + "col15": "1jgrq", + "col16": "h3uj3", + "col17": "9m1ff", + "col18": "e6ajf", + "col19": "be00d", + "col20": "o37no", + "col21": "fkczd", + "col22": "c9m1h", + "col23": "sqb54", + "col24": "90zo9", + "col25": "99td6", + "col26": "o3nok", + "col27": "wcmun", + "col28": "xiknj", + "col29": "8o6wh", + "col30": "a9efn", + "col31": "4qegj", + "col32": "l7qjr", + "col33": "s7i4f", + "col34": "t5ss4", + "col35": "rgueh", + "col36": "34e0w", + "col37": "k57te", + "col38": "jw2bq", + "col39": "b5vt9", + "col40": "qshgv", + "col41": "9nif7", + "col42": "olu0e", + "col43": "ay9uk", + "col44": "unuad", + "col45": "l2gx5", + "col46": "4bscu", + "col47": "rf2wk", + "col48": "xtte5", + "col49": "5mox2", + "col50": "at8ns", + "col51": "6pmz7", + "col52": "m40e8", + "col53": "v35mv", + "col54": "9srt6", + "col55": "5uxl3", + "col56": "6adj6", + "col57": "z3z1h", + "col58": "u55i0", + "col59": "xo4u2", + "col60": "vjkb9", + "col61": "2bfgs", + "col62": "cib1d", + "col63": "dlu2s", + "col64": "tq82j", + "col65": "br2s8", + "col66": "yatg1", + "col67": "omo1z", + "col68": "hg0aq", + "col69": "up8zw", + "col70": "0htvp", + "col71": "8ynyr", + "col72": "0jgd3", + "col73": "vhc0e", + "col74": "t99ds", + "col75": "nh92b", + "col76": "5996r", + "col77": "tuirk", + "col78": "mkrqt", + "col79": "9xzqk", + "col80": "ug0sh", + "col81": "nftwf", + "col82": "0d7jq", + "col83": "y4kn6", + "col84": "u3p20", + "col85": "5l7e7", + "col86": "uijl2", + "col87": "gxn2s", + "col88": "it5hw", + "col89": "k5n36", + "col90": "rgab2", + "col91": "012nn", + "col92": "81ob7", + "col93": "7mtw8", + "col94": "1h3ba", + "col95": "v4ovc", + "col96": "ngd31", + "col97": "4imue", + "col98": "vp6k9", + "col99": "bseu2", + "col100": "cgt9r", + "col101": "wu7e3", + "col102": "86ond", + "col103": "16e1k", + "col104": "3f2qb", + "col105": "76s6u", + "col106": "86u6w", + "col107": "jw4yh", + "col108": "4galq", + "col109": "j7czc", + "col110": "5a559", + "col111": "us98x", + "col112": "3asf4", + "col113": "n8fgd", + "col114": "3nnnr", + "col115": "14u2w", + "col116": "nrmfr", + "col117": "olnqp", + "col118": "e44ix", + "col119": "1gocl", + "col120": "x4l5w", + "col121": "nwnxe", + "col122": "jk3ob", + "col123": "sg46g", + "col124": "alx6g", + "col125": "h6evm", + "col126": "q1zay", + "col127": "dymt1", + "col128": "mry1x", + "col129": "zroap", + "col130": "wh7t5", + "col131": "5fid1", + "col132": "csy93", + "col133": "x63gd", + "col134": "5gjdv", + "col135": "avmij", + "col136": "79bqp", + "col137": "1lm7k", + "col138": "d3o2p", + "col139": "n3haj", + "col140": "oi4nd", + "col141": "w8tt4", + "col142": "f9lei", + "col143": "8hlv3", + "col144": "5m2pd", + "col145": "91tvh", + "col146": "ezro1", + "col147": "79nq6", + "col148": "gu90v", + "col149": "qecho", + "col150": "3brzd", + "col151": "owugs", + "col152": "99bys", + "col153": "b5ms2", + "col154": "tt2mh", + "col155": "vjovp", + "col156": "kg22d", + "col157": "kgcqo", + "col158": "rav8c", + "col159": "6qi5j", + "col160": "2vgiz", + "col161": "fup55", + "col162": "xjdv4", + "col163": "zjfg5", + "col164": "i8v4g", + "col165": "rq3aj", + "col166": "f6ziy", + "col167": "lsb7b", + "col168": "2or2f", + "col169": "9ogt3", + "col170": "5q9en", + "col171": "zya3y", + "col172": "26tr7", + "col173": "92rjo", + "col174": "08qw6", + "col175": "jklwo", + "col176": "utswp", + "col177": "uuf4t", + "col178": "63flz", + "col179": "vsvj9", + "col180": "ttgfc", + "col181": "wyn6a", + "col182": "3hvp8", + "col183": "4rxkh", + "col184": "rtzah", + "col185": "dvju2", + "col186": "ffn71", + "col187": "ty26m", + "col188": "drafw", + "col189": "uh3xh", + "col190": "bha5h", + "col191": "uhmn9", + "col192": "jtqbm", + "col193": "xj23s", + "col194": "cilb1", + "col195": "svfyz", + "col196": "vwmro", + "col197": "6uqji", + "col198": "0m2fl", + "col199": "5ffxa", + "col200": "9sz1x", + "col201": "g6ask", + "col202": "g1oxr", + "col203": "vlg01", + "col204": "jzzwd", + "col205": "gsljl", + "col206": "mb8yb", + "col207": "jr9l2", + "col208": "akvf2", + "col209": "2omcy", + "col210": "uvj3e", + "col211": "mv57l", + "col212": "0jrn2", + "col213": "5x7i9", + "col214": "b230h", + "col215": "3nwhw", + "col216": "p8zhk", + "col217": "rdrcr", + "col218": "cmno5", + "col219": "ct0vy", + "col220": "yb2y3", + "col221": "30ls7", + "col222": "l99k4", + "col223": "eim5y", + "col224": "mj30w", + "col225": "y18pr", + "col226": "8gram", + "col227": "yofym", + "col228": "983yl", + "col229": "3jlvu", + "col230": "hgxzx", + "col231": "k72gt", + "col232": "tsgb8", + "col233": "vue5y", + "col234": "29oqf", + "col235": "vsdeb", + "col236": "jrtjs", + "col237": "1995k", + "col238": "c2lpe", + "col239": "egse4", + "col240": "bk7d5", + "col241": "pk98j", + "col242": "m14kd", + "col243": "8c2sl", + "col244": "hhzy2", + "col245": "g1a81", + "col246": "66z95", + "col247": "iiyz6", + "col248": "vrm13", + "col249": "7w596", + "col250": "yvrt9", + "col251": "4yn1h", + "col252": "ebwfr", + "col253": "qtnxb", + "col254": "kvch2", + "col255": "kohg0", + "col256": "70dix", + "col257": "gq4z7", + "col258": "31eg8", + "col259": "ihd1s", + "col260": "jvhpf", + "col261": "7lv1o", + "col262": "60sgw", + "col263": "otoau", + "col264": "1eg9p", + "col265": "cu8h3", + "col266": "0hrv3", + "col267": "2caai", + "col268": "03b72", + "col269": "iflkc", + "col270": "d5kmb", + "col271": "9d9wj", + "col272": "fc25i", + "col273": "hrdho", + "col274": "gb6ho", + "col275": "w01v2", + "col276": "bv5fw", + "col277": "m7xcf", + "col278": "8zy6k", + "col279": "g2bkl", + "col280": "6q318", + "col281": "7giyj", + "col282": "zprk0", + "col283": "3yvyc", + "col284": "kijnl", + "col285": "xfnd8", + "col286": "6pc2m", + "col287": "btclp", + "col288": "jayka", + "col289": "t62mp", + "col290": "8yq9w", + "col291": "coq5c", + "col292": "clrpt", + "col293": "o57qc", + "col294": "gow0b", + "col295": "ycma2", + "col296": "q0mal", + "col297": "f642a", + "col298": "1m59x", + "col299": "ddr5w", + "col300": "7pzg8", + "col301": "e2y07", + "col302": "jwulm", + "col303": "2fk8y", + "col304": "y6xxq", + "col305": "8os7n", + "col306": "60hbv", + "col307": "b1467", + "col308": "ndee6", + "col309": "rumnc", + "col310": "3pw8e", + "col311": "an25n", + "col312": "ywhbw", + "col313": "c3oex", + "col314": "icogv", + "col315": "r05lt", + "col316": "3drla", + "col317": "y9hm7", + "col318": "5atn8", + "col319": "5cutt", + "col320": "knh2s", + "col321": "35qge", + "col322": "eanns", + "col323": "qw3lt", + "col324": "ajrt7", + "col325": "v41zy", + "col326": "l92o1", + "col327": "whdss", + "col328": "m8bm2", + "col329": "ek3sc", + "col330": "m4vyl", + "col331": "timxe", + "col332": "z4d9p", + "col333": "qe447", + "col334": "60dil", + "col335": "lut4n", + "col336": "7dpik", + "col337": "thpiw", + "col338": "bba12", + "col339": "b5vht", + "col340": "jdnom", + "col341": "q3xgm", + "col342": "66thl", + "col343": "fjl97", + "col344": "p819v", + "col345": "oexvl", + "col346": "e6u6x", + "col347": "gyrj7", + "col348": "zhxrm", + "col349": "99ukb", + "col350": "d1rte", + "col351": "q3cga", + "col352": "iwdta", + "col353": "nshkl", + "col354": "8899i", + "col355": "3s3al", + "col356": "ddzbt", + "col357": "frcpz", + "col358": "h1pw1", + "col359": "okdgx", + "col360": "htxrz", + "col361": "hqpi3", + "col362": "upfqa", + "col363": "80ghh", + "col364": "988pq", + "col365": "6x4z8", + "col366": "pv5uw", + "col367": "gnlk6", + "col368": "9fu56", + "col369": "p7f9g", + "col370": "zjls9", + "col371": "y9fdr", + "col372": "u6zrx", + "col373": "idz61", + "col374": "qgiwt", + "col375": "bz6uu", + "col376": "vevzn", + "col377": "gsmoq", + "col378": "omkb8", + "col379": "5wj76", + "col380": "d1d3r", + "col381": "6wsed", + "col382": "xs09b", + "col383": "bkunu", + "col384": "n4szz", + "col385": "nib4h", + "col386": "izwoh", + "col387": "yv96r", + "col388": "bmivf", + "col389": "royg1", + "col390": "m7yvt", + "col391": "uz83o", + "col392": "2dgwm", + "col393": "9rawn", + "col394": "8k0af", + "col395": "h7ub3", + "col396": "s6z8a", + "col397": "t3t9s", + "col398": "944fa", + "col399": "6b31l", + "col400": "8wgop", + "col401": "mewig", + "col402": "hkw8a", + "col403": "cu4t2", + "col404": "nfs67", + "col405": "6d3so", + "col406": "l7h3q", + "col407": "15lo1", + "col408": "mhko2", + "col409": "iffc3", + "col410": "w1gfn", + "col411": "a5btx", + "col412": "81cas", + "col413": "9rzme", + "col414": "txbra", + "col415": "boynm", + "col416": "lw1x0", + "col417": "ifisu", + "col418": "mlzub", + "col419": "h3g7d", + "col420": "29g26", + "col421": "rrqaw", + "col422": "pwf96", + "col423": "rs8fs", + "col424": "2yktg", + "col425": "no7he", + "col426": "e3337", + "col427": "bpssq", + "col428": "jlrh2", + "col429": "f48hf", + "col430": "xb1fv", + "col431": "3wz2b", + "col432": "vltrf", + "col433": "28lo3", + "col434": "jnej5", + "col435": "wnnym", + "col436": "28bzj", + "col437": "k1dlc", + "col438": "3sgdm", + "col439": "4t555", + "col440": "79p0q", + "col441": "y2rmu", + "col442": "3jkz1", + "col443": "wsnxu", + "col444": "wbpz5", + "col445": "m4sd5", + "col446": "hru4m", + "col447": "kivo2", + "col448": "1ylxc", + "col449": "iitvc", + "col450": "dw04i", + "col451": "1qqfh", + "col452": "bsrrm", + "col453": "x9irj", + "col454": "tmafn", + "col455": "i65ox", + "col456": "sy8wf", + "col457": "baw23", + "col458": "fcq1f", + "col459": "jnnrp", + "col460": "58ko9", + "col461": "6hd3e", + "col462": "gqmc8", + "col463": "zbpsh", + "col464": "0aix2", + "col465": "f81y5", + "col466": "xqj4d", + "col467": "myk92", + "col468": "4ub3m", + "col469": "lb2mf", + "col470": "a0mu0", + "col471": "jopum", + "col472": "39v4j", + "col473": "ldxyw", + "col474": "bmkzx", + "col475": "qg1ke", + "col476": "tl0iu", + "col477": "ihcoj", + "col478": "m99qk", + "col479": "jfxsh", + "col480": "0jvgf", + "col481": "bmljg", + "col482": "9q942", + "col483": "gmr5y", + "col484": "xsiqf", + "col485": "apyj2", + "col486": "eco9q", + "col487": "m98z3", + "col488": "ksuqn", + "col489": "zlukt", + "col490": "q6zzz", + "col491": "f6agm", + "col492": "7gf80", + "col493": "bc15c", + "col494": "uln9l", + "col495": "ag5kh", + "col496": "ipfuo", + "col497": "ftcm3", + "col498": "jbd1y", + "col499": "mkdw2", + "col500": "orjht", + "col501": "zfqfj", + "col502": "vp9o9", + "col503": "3m8lr", + "col504": "lq7l5", + "col505": "x15v2", + "col506": "q26x1", + "col507": "389pf", + "col508": "zltwv", + "col509": "stp17", + "col510": "ox2g8", + "col511": "torg3", + "col512": "c6xxm", + "col513": "h43xq", + "col514": "p19n7", + "col515": "6ybff", + "col516": "c4x79", + "col517": "idvlc", + "col518": "h9va2", + "col519": "89lvu", + "col520": "qhitz", + "col521": "zie1z", + "col522": "47jjg", + "col523": "4vj4k", + "col524": "vfk8j", + "col525": "l6wh5", + "col526": "3ery2", + "col527": "16nsp", + "col528": "ym77w", + "col529": "4v46m", + "col530": "1lajy", + "col531": "iezj4", + "col532": "2y95e", + "col533": "zfrb2", + "col534": "m8qkf", + "col535": "xmhjl", + "col536": "ku6zm", + "col537": "1c2sf", + "col538": "uc9xr", + "col539": "zaskd", + "col540": "pep4s", + "col541": "l34ch", + "col542": "xk31d", + "col543": "xc442", + "col544": "snn52", + "col545": "58dly", + "col546": "qnfv8", + "col547": "61brg", + "col548": "upte0", + "col549": "svn7o", + "col550": "bshka", + "col551": "ncxtv", + "col552": "o3njt", + "col553": "sr2vt", + "col554": "doko6", + "col555": "cxzqg", + "col556": "pnqca", + "col557": "mj9gh", + "col558": "4f9l9", + "col559": "wyq7j", + "col560": "0kfbk", + "col561": "yexmc", + "col562": "0ee4s", + "col563": "oxr88", + "col564": "d2y92", + "col565": "8697w", + "col566": "yd7yg", + "col567": "ic6tp", + "col568": "lq3pe", + "col569": "2vglj", + "col570": "ci5ez", + "col571": "vfa3m", + "col572": "p5e2i", + "col573": "5rawt", + "col574": "c6oq2", + "col575": "bek9q", + "col576": "vn84s", + "col577": "jl218", + "col578": "vv5u1", + "col579": "eyu0z", + "col580": "4uaek", + "col581": "cf407", + "col582": "qn60m", + "col583": "yyrct", + "col584": "2yy60", + "col585": "nuc6u", + "col586": "1aia5", + "col587": "53xo4", + "col588": "nj3ax", + "col589": "jh7ar", + "col590": "2udlu", + "col591": "ccp7g", + "col592": "jlsku", + "col593": "ogpco", + "col594": "036i9", + "col595": "18sr4", + "col596": "wql3s", + "col597": "p3vbf", + "col598": "bt4no", + "col599": "oj4sn", + "col600": "qz9ij", + "col601": "mvp1y", + "col602": "7knxb", + "col603": "u0i3y", + "col604": "w8iyn", + "col605": "cqw1m", + "col606": "osx7k", + "col607": "abd40", + "col608": "u39ln", + "col609": "wmsco", + "col610": "8wfz7", + "col611": "r8su0", + "col612": "2qclf", + "col613": "w92kq", + "col614": "5q131", + "col615": "c872h", + "col616": "n9vv6", + "col617": "5hb1v", + "col618": "b46k6", + "col619": "2l8cl", + "col620": "6l30u", + "col621": "cnb8a", + "col622": "oad5u", + "col623": "qyqkx", + "col624": "w9oaf", + "col625": "kl986", + "col626": "hi3j2", + "col627": "10ohe", + "col628": "06w2l", + "col629": "79y5p", + "col630": "avohu", + "col631": "6wb7i", + "col632": "pu6y6", + "col633": "nsa6r", + "col634": "080yf", + "col635": "rc43g", + "col636": "pmb8v", + "col637": "0dtnz", + "col638": "zbfcz", + "col639": "z7apz", + "col640": "j5ba2", + "col641": "iyghy", + "col642": "av6p4", + "col643": "m4ayy", + "col644": "5bhon", + "col645": "tafjc", + "col646": "9tno9", + "col647": "9zt07", + "col648": "lvtrf", + "col649": "geu6l", + "col650": "s5mt6", + "col651": "2psk7", + "col652": "dhlii", + "col653": "veszp", + "col654": "d2fve", + "col655": "qyldp", + "col656": "4wxdc", + "col657": "nsfmw", + "col658": "mrl3h", + "col659": "7pvti", + "col660": "uzb7y", + "col661": "7hzoq", + "col662": "96t47", + "col663": "p0csi", + "col664": "0z38y", + "col665": "c7r7o", + "col666": "22cu9", + "col667": "ehs0q", + "col668": "z4kmz", + "col669": "71vaf", + "col670": "rm6dq", + "col671": "23vdc", + "col672": "y1nq8", + "col673": "53855", + "col674": "ns2l0", + "col675": "uj5f5", + "col676": "lpvn3", + "col677": "lfagw", + "col678": "ab7x6", + "col679": "8asay", + "col680": "hbbit", + "col681": "i7brk", + "col682": "0q47p", + "col683": "557zh", + "col684": "ubtlo", + "col685": "d3lwj", + "col686": "gx38j", + "col687": "7hf24", + "col688": "h8ffm", + "col689": "ifuwj", + "col690": "6xlla", + "col691": "etvf3", + "col692": "aze6o", + "col693": "1hzah", + "col694": "5py6f", + "col695": "712gx", + "col696": "xzit9", + "col697": "dat6y", + "col698": "epauu", + "col699": "alveu", + "col700": "wnbga", + "col701": "j3v7p", + "col702": "0h6wu", + "col703": "gx7ur", + "col704": "n67iy", + "col705": "p76ab", + "col706": "8hjk1", + "col707": "ycffv", + "col708": "garcl", + "col709": "yb0bk", + "col710": "7d8a6", + "col711": "d2tmx", + "col712": "rlerk", + "col713": "se64v", + "col714": "3o2dc", + "col715": "xd65i", + "col716": "4sh3r", + "col717": "z3pxr", + "col718": "9qu15", + "col719": "xso3d", + "col720": "h3qzc", + "col721": "hu0kp", + "col722": "4r873", + "col723": "7w2nd", + "col724": "fo6fr", + "col725": "qzaeo", + "col726": "zgt71", + "col727": "fx49o", + "col728": "n56v9", + "col729": "tjq2v", + "col730": "dzexk", + "col731": "vrl9c", + "col732": "k1iex", + "col733": "spyy5", + "col734": "n2cb1", + "col735": "xkxmt", + "col736": "xi8p4", + "col737": "idggu", + "col738": "nf77j", + "col739": "4tdj5", + "col740": "njy2h", + "col741": "dzvrx", + "col742": "32owi", + "col743": "pjplt", + "col744": "fpbbn", + "col745": "236mv", + "col746": "fybq7", + "col747": "88xac", + "col748": "ysscx", + "col749": "qgx7t", + "col750": "9pcbz", + "col751": "ehmc4", + "col752": "2zol9", + "col753": "3k9up", + "col754": "m3x12", + "col755": "njtuz", + "col756": "fjc3p", + "col757": "clav5", + "col758": "xiz25", + "col759": "6cmfu", + "col760": "mkj6g", + "col761": "8i9um", + "col762": "ew2rz", + "col763": "yp0x5", + "col764": "y6ore", + "col765": "l5nxt", + "col766": "mbdc9", + "col767": "1o5ir", + "col768": "nopdx", + "col769": "u8el3", + "col770": "2864c", + "col771": "lyu68", + "col772": "70zag", + "col773": "491d3", + "col774": "sw363", + "col775": "e9egp", + "col776": "m3b0h", + "col777": "3d4lk", + "col778": "c8had", + "col779": "j57n9", + "col780": "obqtx", + "col781": "xzxpx", + "col782": "aeket", + "col783": "iohcd", + "col784": "7vq43", + "col785": "aha7p", + "col786": "djcbi", + "col787": "vy2u2", + "col788": "v9231", + "col789": "37s9v", + "col790": "9n2rx", + "col791": "ap1uk", + "col792": "osgu7", + "col793": "4x07r", + "col794": "otq3k", + "col795": "fa509", + "col796": "fed4d", + "col797": "pw19z", + "col798": "soeh6", + "col799": "m2uyh", + "col800": "sinal", + "col801": "2n4ag", + "col802": "gguo8", + "col803": "7ne1i", + "col804": "w0bsy", + "col805": "qx648", + "col806": "px04b", + "col807": "h84md", + "col808": "h0jqz", + "col809": "183dj", + "col810": "a4zqa", + "col811": "qdcd3", + "col812": "imtyy", + "col813": "x663m", + "col814": "jmqhw", + "col815": "lhq6o", + "col816": "2sntu", + "col817": "ejls3", + "col818": "mslsw", + "col819": "umlyq", + "col820": "1hkr4", + "col821": "xz21m", + "col822": "zedol", + "col823": "i53qo", + "col824": "024yh", + "col825": "4z6ac", + "col826": "62m8o", + "col827": "0ndtm", + "col828": "n2q7c", + "col829": "d0l1d", + "col830": "ynv0q", + "col831": "4w6oy", + "col832": "9ix4n", + "col833": "bbtjk", + "col834": "q95ky", + "col835": "7gbjt", + "col836": "l6i2h", + "col837": "m0bbn", + "col838": "qp8ce", + "col839": "blf9k", + "col840": "j8dcn", + "col841": "2n8sb", + "col842": "c55ib", + "col843": "om8hx", + "col844": "lhsxv", + "col845": "dcsb6", + "col846": "4h638", + "col847": "tjrha", + "col848": "5ee7j", + "col849": "pvkmz", + "col850": "yh3c5", + "col851": "0ma81", + "col852": "nxxi9", + "col853": "exxp8", + "col854": "vhd6y", + "col855": "3xmj9", + "col856": "7cwts", + "col857": "o08v1", + "col858": "sbkoe", + "col859": "jqico", + "col860": "e9yo2", + "col861": "u5qv5", + "col862": "sfxhi", + "col863": "7rudr", + "col864": "0q5oe", + "col865": "belc0", + "col866": "mkaa9", + "col867": "xgpl6", + "col868": "tdudd", + "col869": "nobrh", + "col870": "jpsj7", + "col871": "88x7h", + "col872": "zuklx", + "col873": "cwmih", + "col874": "fpnus", + "col875": "f5y0x", + "col876": "d0v9w", + "col877": "kl7ut", + "col878": "i0u3t", + "col879": "irz3z", + "col880": "cmvby", + "col881": "7st2d", + "col882": "6qy1r", + "col883": "zr7h4", + "col884": "33rj2", + "col885": "rrdng", + "col886": "pgis9", + "col887": "1fhwp", + "col888": "50ggs", + "col889": "awh8g", + "col890": "gshsu", + "col891": "83ig9", + "col892": "n82dz", + "col893": "ecth7", + "col894": "lhwhd", + "col895": "ypvz2", + "col896": "ummbj", + "col897": "urwlb", + "col898": "1aiws", + "col899": "yn851", + "col900": "9fr5j", + "col901": "2m8hw", + "col902": "gjpmc", + "col903": "n3rit", + "col904": "jhcfa", + "col905": "3hygl", + "col906": "hprg9", + "col907": "7vur3", + "col908": "gvcrp", + "col909": "hp4g7", + "col910": "6vnpz", + "col911": "cyvm5", + "col912": "4y33y", + "col913": "7mz33", + "col914": "0ihs1", + "col915": "otxk7", + "col916": "dyi89", + "col917": "88wb1", + "col918": "lp2wu", + "col919": "undll", + "col920": "p4gj2", + "col921": "wr3iy", + "col922": "yuve3", + "col923": "28jeg", + "col924": "2zob7", + "col925": "l3a9g", + "col926": "m6yce", + "col927": "squ0l", + "col928": "i9jty", + "col929": "pjn40", + "col930": "38p8c", + "col931": "p8el6", + "col932": "frwug", + "col933": "ifa8e", + "col934": "3fnmm", + "col935": "kz6et", + "col936": "cg3df", + "col937": "lhxfl", + "col938": "vodc4", + "col939": "xln3w", + "col940": "lca0g", + "col941": "vr0z7", + "col942": "ghp2n", + "col943": "0btt0", + "col944": "slxxe", + "col945": "ecuvf", + "col946": "r5f0b", + "col947": "lp7hf", + "col948": "j4k7c", + "col949": "epdha", + "col950": "yte67", + "col951": "lbnhe", + "col952": "lgvd6", + "col953": "r3o8e", + "col954": "pb9zu", + "col955": "08vv8", + "col956": "ywsnz", + "col957": "sbe0c", + "col958": "1xe3t", + "col959": "pf30h", + "col960": "u0vhc", + "col961": "pcb4k", + "col962": "fn4jg", + "col963": "dw0fb", + "col964": "vx5h0", + "col965": "e5wk5", + "col966": "a9rbb", + "col967": "byl62", + "col968": "17yzx", + "col969": "x1tzk", + "col970": "rl2nb", + "col971": "zslg9", + "col972": "chsui", + "col973": "izc1e", + "col974": "dne24", + "col975": "7ewra", + "col976": "mhbgc", + "col977": "k9oy3", + "col978": "0pd5a", + "col979": "lxgu5", + "col980": "kl74p", + "col981": "ki8n0", + "col982": "vi2cg", + "col983": "zb8b2", + "col984": "uk4ya", + "col985": "pbu5y", + "col986": "1skkb", + "col987": "chmmq", + "col988": "176py", + "col989": "f59j1", + "col990": "njpot", + "col991": "egpx4", + "col992": "lim5s", + "col993": "8i3sj", + "col994": "yroiy", + "col995": "hufst", + "col996": "r21eu", + "col997": "3937e", + "col998": "5e2vs", + "col999": "cukzi" + }, + { + "name": "Marissa Clarke", + "gender": "female", + "col0": "zrv09", + "col1": "9jfcr", + "col2": "dv1lb", + "col3": "getfe", + "col4": "kweks", + "col5": "otww4", + "col6": "7ynvb", + "col7": "lrnyi", + "col8": "yg49z", + "col9": "chu40", + "col10": "06685", + "col11": "bmows", + "col12": "vc8hc", + "col13": "3nh63", + "col14": "sl1gd", + "col15": "qki4v", + "col16": "qff7m", + "col17": "5kbmw", + "col18": "caxs9", + "col19": "yjifp", + "col20": "auda2", + "col21": "kyi66", + "col22": "s7o2p", + "col23": "3wfpx", + "col24": "b623m", + "col25": "76hr7", + "col26": "yrkg3", + "col27": "sdu5k", + "col28": "sg0b6", + "col29": "caqhr", + "col30": "0v3st", + "col31": "h4zo9", + "col32": "d3j76", + "col33": "0p0dx", + "col34": "wo1u0", + "col35": "wr948", + "col36": "hnrxl", + "col37": "077yq", + "col38": "hm4e6", + "col39": "lzxe7", + "col40": "semwy", + "col41": "oi3bc", + "col42": "8mqra", + "col43": "ax88s", + "col44": "bmmnv", + "col45": "cmdom", + "col46": "9dii2", + "col47": "bpo6f", + "col48": "7h8ey", + "col49": "xfylt", + "col50": "jo634", + "col51": "5ue8q", + "col52": "hmk09", + "col53": "hhrbl", + "col54": "3nysx", + "col55": "b4a11", + "col56": "tosjs", + "col57": "qs3wh", + "col58": "43oji", + "col59": "k2wh7", + "col60": "g6wtn", + "col61": "1268v", + "col62": "6oq78", + "col63": "uoen4", + "col64": "hybne", + "col65": "o79pp", + "col66": "znult", + "col67": "yl7gg", + "col68": "j3rtq", + "col69": "ht6ru", + "col70": "n9cnn", + "col71": "ghok4", + "col72": "fizkn", + "col73": "6kgsp", + "col74": "vlgap", + "col75": "mdjqq", + "col76": "g6du4", + "col77": "l70g0", + "col78": "ndt82", + "col79": "5edq9", + "col80": "4312k", + "col81": "1utzl", + "col82": "8waxr", + "col83": "mwsi8", + "col84": "zjnq0", + "col85": "mptse", + "col86": "mnyo0", + "col87": "91esu", + "col88": "uue8e", + "col89": "axb2l", + "col90": "bxnu7", + "col91": "v4hxx", + "col92": "fk6cq", + "col93": "ebn20", + "col94": "uqr7f", + "col95": "6hjhc", + "col96": "nr7vx", + "col97": "0bkca", + "col98": "0m7pw", + "col99": "pbq2w", + "col100": "f9akv", + "col101": "kxrj8", + "col102": "pksl2", + "col103": "1rw2g", + "col104": "66nr9", + "col105": "2yszv", + "col106": "7imb9", + "col107": "ojm80", + "col108": "19soq", + "col109": "wf6us", + "col110": "3f9gb", + "col111": "j6kdk", + "col112": "mxu62", + "col113": "6yfp5", + "col114": "x9ncp", + "col115": "kn8sv", + "col116": "3ib7o", + "col117": "sr5th", + "col118": "8ppqp", + "col119": "ktau2", + "col120": "i81kd", + "col121": "82q41", + "col122": "0juiv", + "col123": "l06gy", + "col124": "r39v1", + "col125": "r0j5c", + "col126": "wgig3", + "col127": "z4iic", + "col128": "mytn5", + "col129": "cnw4m", + "col130": "tfrv0", + "col131": "jj0vm", + "col132": "kfdr7", + "col133": "usxpp", + "col134": "wc02t", + "col135": "31ro7", + "col136": "odnvk", + "col137": "06hmt", + "col138": "d4263", + "col139": "4y09z", + "col140": "nlqyj", + "col141": "yzkrs", + "col142": "hnzyi", + "col143": "2dbcu", + "col144": "59u1d", + "col145": "8mbhc", + "col146": "arolk", + "col147": "y6acz", + "col148": "19bza", + "col149": "6tpcq", + "col150": "cmca7", + "col151": "0ic30", + "col152": "isd1u", + "col153": "f35zm", + "col154": "xjxsk", + "col155": "7fr0l", + "col156": "1ot2g", + "col157": "vss86", + "col158": "tggtr", + "col159": "5a0ea", + "col160": "zdmtd", + "col161": "itn4n", + "col162": "j80i8", + "col163": "hec8p", + "col164": "gje74", + "col165": "8430t", + "col166": "xrwgq", + "col167": "64dxi", + "col168": "ekshk", + "col169": "8ymwg", + "col170": "pes73", + "col171": "rxho8", + "col172": "wan0i", + "col173": "16d3o", + "col174": "xlffp", + "col175": "xvggf", + "col176": "u1lka", + "col177": "j0nwd", + "col178": "elcob", + "col179": "ko39k", + "col180": "7yibr", + "col181": "etdet", + "col182": "hci4g", + "col183": "2r1lf", + "col184": "cevdf", + "col185": "06zgb", + "col186": "67h4f", + "col187": "plkbo", + "col188": "6jtzx", + "col189": "w6gud", + "col190": "xw5pv", + "col191": "ydsz8", + "col192": "vz8tk", + "col193": "8vyac", + "col194": "znepq", + "col195": "afnct", + "col196": "b4vcc", + "col197": "nretu", + "col198": "oz3re", + "col199": "c9pni", + "col200": "pgukv", + "col201": "2t15n", + "col202": "5fbsu", + "col203": "zluuy", + "col204": "ygdv8", + "col205": "rxseh", + "col206": "qbqzq", + "col207": "8fkn5", + "col208": "sursh", + "col209": "vx7sz", + "col210": "pv4m3", + "col211": "by3af", + "col212": "qpda0", + "col213": "kgv64", + "col214": "9jw1u", + "col215": "3ilqn", + "col216": "op5t0", + "col217": "nn7c5", + "col218": "h8ten", + "col219": "ua97f", + "col220": "ldvgs", + "col221": "2gjlc", + "col222": "40hg4", + "col223": "6bx7o", + "col224": "pj647", + "col225": "2m2xu", + "col226": "2p3dv", + "col227": "50emk", + "col228": "3q8b9", + "col229": "segs2", + "col230": "imw6y", + "col231": "6wme6", + "col232": "3l3u7", + "col233": "dncwo", + "col234": "fo2hq", + "col235": "6vc07", + "col236": "lrg2w", + "col237": "ktktz", + "col238": "sfes8", + "col239": "zkgj3", + "col240": "m8eaz", + "col241": "4ieq0", + "col242": "vgca3", + "col243": "rgq5i", + "col244": "vgl1u", + "col245": "huclm", + "col246": "6xdl0", + "col247": "h9l9v", + "col248": "smapb", + "col249": "tsncv", + "col250": "e0t23", + "col251": "oiaz3", + "col252": "9jlfb", + "col253": "e03x8", + "col254": "6lmf8", + "col255": "ttrat", + "col256": "llgpk", + "col257": "aogic", + "col258": "gmwc4", + "col259": "ytxc8", + "col260": "ceoa9", + "col261": "wor6a", + "col262": "28uk4", + "col263": "qim3c", + "col264": "7e49v", + "col265": "75da7", + "col266": "u1e8d", + "col267": "8a6uu", + "col268": "c6zk2", + "col269": "spl0r", + "col270": "04ggt", + "col271": "ubtgg", + "col272": "1nuqk", + "col273": "1sg3v", + "col274": "03l4q", + "col275": "29cmq", + "col276": "dv15x", + "col277": "gw24w", + "col278": "zrz6h", + "col279": "9sras", + "col280": "umb9f", + "col281": "c8suj", + "col282": "ustcz", + "col283": "3bdgl", + "col284": "3qvpk", + "col285": "p4tl1", + "col286": "1lwhj", + "col287": "8q6ic", + "col288": "x4mmk", + "col289": "p298a", + "col290": "vvzfc", + "col291": "byokk", + "col292": "ixgou", + "col293": "tewm5", + "col294": "lnoct", + "col295": "is731", + "col296": "v49qn", + "col297": "pymxn", + "col298": "lvnov", + "col299": "u4n0g", + "col300": "ihr2x", + "col301": "d1ruo", + "col302": "v686a", + "col303": "p5b5q", + "col304": "gld2l", + "col305": "b245l", + "col306": "o7gg6", + "col307": "thtov", + "col308": "98yju", + "col309": "rogx8", + "col310": "z5viz", + "col311": "1rd4v", + "col312": "cfbs7", + "col313": "es81u", + "col314": "hfbmh", + "col315": "pqdqm", + "col316": "3c7wh", + "col317": "r1own", + "col318": "w0p57", + "col319": "jlavb", + "col320": "dfwza", + "col321": "qu7kr", + "col322": "docca", + "col323": "ci9ds", + "col324": "hn4it", + "col325": "9wahc", + "col326": "ota5n", + "col327": "mqurp", + "col328": "vqrxd", + "col329": "1x7nq", + "col330": "818ql", + "col331": "o9xmh", + "col332": "7fnk6", + "col333": "ddw1g", + "col334": "mnxwu", + "col335": "lhrke", + "col336": "g6r6u", + "col337": "87lsx", + "col338": "xsm12", + "col339": "p2j9o", + "col340": "v3yl3", + "col341": "l5du0", + "col342": "e0w7a", + "col343": "5b0fb", + "col344": "fjlos", + "col345": "wi6cb", + "col346": "g3vtc", + "col347": "tb6dt", + "col348": "dbi14", + "col349": "n5ftx", + "col350": "fb6pp", + "col351": "625cc", + "col352": "jn701", + "col353": "mwumx", + "col354": "wnmcm", + "col355": "lkqfe", + "col356": "mnsnb", + "col357": "5fq8m", + "col358": "k0bs7", + "col359": "v4eaq", + "col360": "m22xw", + "col361": "xqafl", + "col362": "40mal", + "col363": "e6ihj", + "col364": "h9f0b", + "col365": "n7ihz", + "col366": "vdurz", + "col367": "mwwou", + "col368": "ch6f5", + "col369": "34kkg", + "col370": "3bnpz", + "col371": "cmrqp", + "col372": "bw05i", + "col373": "vhs0t", + "col374": "xvgln", + "col375": "6vfk8", + "col376": "f2dky", + "col377": "zmre9", + "col378": "puvrn", + "col379": "iyqo1", + "col380": "z848d", + "col381": "u4rar", + "col382": "uiikp", + "col383": "ira04", + "col384": "bdubd", + "col385": "h2e4k", + "col386": "pki7z", + "col387": "1nqdw", + "col388": "77vea", + "col389": "er0ls", + "col390": "pppv5", + "col391": "kg1ql", + "col392": "opppl", + "col393": "iwqvy", + "col394": "3522h", + "col395": "1jqgj", + "col396": "qzxab", + "col397": "5a417", + "col398": "jjj89", + "col399": "035n9", + "col400": "scbxj", + "col401": "60vf2", + "col402": "sv9or", + "col403": "z7klw", + "col404": "6cmb0", + "col405": "i0pyy", + "col406": "5mvtq", + "col407": "du60r", + "col408": "0nbog", + "col409": "7o921", + "col410": "m73dv", + "col411": "9up61", + "col412": "ck5zx", + "col413": "zsn0w", + "col414": "pvcan", + "col415": "zima8", + "col416": "qj0f2", + "col417": "ywvg3", + "col418": "du0kq", + "col419": "nyogw", + "col420": "z1ehs", + "col421": "2q1rs", + "col422": "kbxhz", + "col423": "01aoz", + "col424": "xkk7k", + "col425": "ivqlx", + "col426": "g4gzx", + "col427": "nl1ir", + "col428": "ibdlr", + "col429": "vn99a", + "col430": "o0qt7", + "col431": "t0mhb", + "col432": "1ulga", + "col433": "6rw9m", + "col434": "eevcy", + "col435": "igx00", + "col436": "llh1c", + "col437": "hjt3u", + "col438": "x5tnv", + "col439": "l5s1n", + "col440": "4daoe", + "col441": "3bpgj", + "col442": "c3zhz", + "col443": "b3dpo", + "col444": "twwfz", + "col445": "c92bu", + "col446": "r4pzd", + "col447": "jr8l4", + "col448": "bx7z6", + "col449": "v9o5j", + "col450": "cely1", + "col451": "p18fp", + "col452": "o2qmi", + "col453": "ae3r2", + "col454": "w0zm0", + "col455": "ghtig", + "col456": "c32hc", + "col457": "v2lzi", + "col458": "dy6la", + "col459": "vw7p8", + "col460": "it2e9", + "col461": "03o7g", + "col462": "tl66d", + "col463": "ly5mw", + "col464": "nc4sp", + "col465": "xz44e", + "col466": "pkde5", + "col467": "y2kap", + "col468": "vbprd", + "col469": "odt4c", + "col470": "wagje", + "col471": "6xyp2", + "col472": "teob0", + "col473": "0ucva", + "col474": "xyv42", + "col475": "je0jt", + "col476": "s4k42", + "col477": "1ihre", + "col478": "jh9y1", + "col479": "jah0w", + "col480": "hb2um", + "col481": "bbpjc", + "col482": "1osx0", + "col483": "mufef", + "col484": "b4qhv", + "col485": "yugtu", + "col486": "md11h", + "col487": "0kqj0", + "col488": "r48li", + "col489": "wm7e8", + "col490": "f0mtn", + "col491": "7kk8s", + "col492": "8m54f", + "col493": "kobk9", + "col494": "dq3lf", + "col495": "1mocu", + "col496": "yi70a", + "col497": "od38y", + "col498": "j9weu", + "col499": "n3rnf", + "col500": "zaqwx", + "col501": "8c012", + "col502": "r370d", + "col503": "1rimw", + "col504": "fyrxu", + "col505": "czj2y", + "col506": "uncgb", + "col507": "v3a6y", + "col508": "svlcw", + "col509": "crj86", + "col510": "b169n", + "col511": "jdasq", + "col512": "7tujt", + "col513": "1hnl2", + "col514": "0s9pl", + "col515": "8patf", + "col516": "n8ryi", + "col517": "o9yd2", + "col518": "z4mcp", + "col519": "bf4fg", + "col520": "046l7", + "col521": "d2070", + "col522": "2i0eo", + "col523": "3jaqh", + "col524": "tz3tc", + "col525": "pvzsg", + "col526": "04ayp", + "col527": "nqyuk", + "col528": "3nr84", + "col529": "cyhya", + "col530": "gsa6n", + "col531": "ntllb", + "col532": "oqch8", + "col533": "9iyv2", + "col534": "dhdns", + "col535": "xekhu", + "col536": "ms97v", + "col537": "br97m", + "col538": "h7mg3", + "col539": "t6k8k", + "col540": "zsnty", + "col541": "x0j85", + "col542": "rrdbg", + "col543": "w5nyl", + "col544": "rmzil", + "col545": "yosvg", + "col546": "06ykm", + "col547": "pu0f0", + "col548": "3krbj", + "col549": "4tzxw", + "col550": "1t6uu", + "col551": "4ulmx", + "col552": "udehc", + "col553": "twzpa", + "col554": "5unea", + "col555": "ufblh", + "col556": "kxzla", + "col557": "oozx8", + "col558": "2mwe5", + "col559": "kik7q", + "col560": "h4xg0", + "col561": "thg8s", + "col562": "9z861", + "col563": "mmqh1", + "col564": "f84eq", + "col565": "0l55u", + "col566": "oxrr2", + "col567": "up7u4", + "col568": "dhni1", + "col569": "2ce72", + "col570": "rxwvz", + "col571": "x794v", + "col572": "aufyr", + "col573": "763h8", + "col574": "beveu", + "col575": "uxax6", + "col576": "no3d4", + "col577": "f817a", + "col578": "cnfsv", + "col579": "oyi07", + "col580": "tj6ig", + "col581": "nxykt", + "col582": "m4vg3", + "col583": "w4uyd", + "col584": "d1aiy", + "col585": "hlnoi", + "col586": "apkk7", + "col587": "u3nii", + "col588": "42utn", + "col589": "czoc1", + "col590": "75vn4", + "col591": "736gl", + "col592": "kw1cw", + "col593": "yytd6", + "col594": "sywsl", + "col595": "kpwxd", + "col596": "rwiy2", + "col597": "eo5m6", + "col598": "edpuc", + "col599": "uerx5", + "col600": "rrbdu", + "col601": "8ug4i", + "col602": "a1nt7", + "col603": "1jpny", + "col604": "m9j2h", + "col605": "onvtv", + "col606": "qxkup", + "col607": "q6tnv", + "col608": "2t8g5", + "col609": "d237n", + "col610": "oyxwh", + "col611": "9dpfn", + "col612": "df2pq", + "col613": "kzuyz", + "col614": "z0pui", + "col615": "82ft0", + "col616": "q9tag", + "col617": "0dd2s", + "col618": "zot6o", + "col619": "5r3is", + "col620": "05w0h", + "col621": "87dut", + "col622": "vxif3", + "col623": "psvsl", + "col624": "b9ech", + "col625": "53qrk", + "col626": "czndk", + "col627": "ndg30", + "col628": "se8xm", + "col629": "95hop", + "col630": "m8jgq", + "col631": "0fgm3", + "col632": "djbrk", + "col633": "e34nt", + "col634": "lft1m", + "col635": "n1svl", + "col636": "k273y", + "col637": "wnzia", + "col638": "nyu4q", + "col639": "z6dcs", + "col640": "pmo4w", + "col641": "89kmu", + "col642": "ypbti", + "col643": "gbg42", + "col644": "x9408", + "col645": "cmtel", + "col646": "echph", + "col647": "ji9zm", + "col648": "7c5k9", + "col649": "ct18k", + "col650": "eedl2", + "col651": "r3g1x", + "col652": "cj3z4", + "col653": "fzh3p", + "col654": "s8zth", + "col655": "oizxg", + "col656": "sa4s5", + "col657": "x3duc", + "col658": "l1sin", + "col659": "b6evi", + "col660": "njnqq", + "col661": "6p2qn", + "col662": "rl687", + "col663": "p2hr6", + "col664": "f6w4q", + "col665": "rss21", + "col666": "qipzl", + "col667": "7rg6p", + "col668": "x03rq", + "col669": "k4trh", + "col670": "fv56d", + "col671": "c74jy", + "col672": "gjhbj", + "col673": "fu08l", + "col674": "uz3ao", + "col675": "n9ubd", + "col676": "oznkb", + "col677": "0613u", + "col678": "vwoov", + "col679": "ix9x3", + "col680": "qoa5e", + "col681": "xslpu", + "col682": "k6kfl", + "col683": "ww2y9", + "col684": "mw7o2", + "col685": "3570n", + "col686": "lv7ix", + "col687": "ixrq2", + "col688": "pbpes", + "col689": "fchpw", + "col690": "12pxq", + "col691": "rz814", + "col692": "trnki", + "col693": "5x8ua", + "col694": "o81qw", + "col695": "hqoer", + "col696": "xcu4l", + "col697": "h7f76", + "col698": "cpqmn", + "col699": "bx0p2", + "col700": "ihto0", + "col701": "oo3r1", + "col702": "saom1", + "col703": "inrsk", + "col704": "90886", + "col705": "aztu2", + "col706": "9pys8", + "col707": "1hsb5", + "col708": "kirrw", + "col709": "z5npm", + "col710": "4vm04", + "col711": "t5llw", + "col712": "xlt7e", + "col713": "bdfum", + "col714": "nwlid", + "col715": "3gf2o", + "col716": "fgqht", + "col717": "j1czh", + "col718": "4ctxd", + "col719": "bbjl7", + "col720": "0ok8p", + "col721": "mbp0u", + "col722": "1nqpe", + "col723": "iv09z", + "col724": "deec6", + "col725": "er6z3", + "col726": "n6xcl", + "col727": "7ilo8", + "col728": "br30f", + "col729": "zmunn", + "col730": "i6fhe", + "col731": "pik2f", + "col732": "b7zlx", + "col733": "xaljc", + "col734": "5j2d5", + "col735": "pp2iv", + "col736": "y2ztl", + "col737": "7pvmh", + "col738": "whv25", + "col739": "2cdk6", + "col740": "t39u1", + "col741": "sxd9u", + "col742": "d34zs", + "col743": "wn6ue", + "col744": "wfvy9", + "col745": "sl151", + "col746": "9i4j6", + "col747": "zvr8b", + "col748": "ef6lt", + "col749": "n400n", + "col750": "5doft", + "col751": "2nh6b", + "col752": "fppu1", + "col753": "1ef3p", + "col754": "mugjp", + "col755": "3it4a", + "col756": "aqtmy", + "col757": "qh3cs", + "col758": "nucpd", + "col759": "ufh2f", + "col760": "9622h", + "col761": "id8o9", + "col762": "1o9ut", + "col763": "sdk2q", + "col764": "obx6w", + "col765": "1ceoy", + "col766": "1vot2", + "col767": "b4p79", + "col768": "0j0ft", + "col769": "76ilg", + "col770": "kw6ca", + "col771": "etlng", + "col772": "7fwvh", + "col773": "9sa3b", + "col774": "rxf92", + "col775": "g9czy", + "col776": "dvprj", + "col777": "73f1h", + "col778": "cmnvi", + "col779": "tqd48", + "col780": "ttgji", + "col781": "ouwsk", + "col782": "dcou6", + "col783": "9nqti", + "col784": "mekbv", + "col785": "4ke7y", + "col786": "9p73l", + "col787": "6qpf7", + "col788": "gb07z", + "col789": "unxjp", + "col790": "5ro5a", + "col791": "eegn4", + "col792": "5tyei", + "col793": "jq4y0", + "col794": "cch7y", + "col795": "9cohl", + "col796": "wykn3", + "col797": "r4nfo", + "col798": "ah2e9", + "col799": "0kdfz", + "col800": "n4i6n", + "col801": "vfrt0", + "col802": "inkng", + "col803": "6lm57", + "col804": "614d6", + "col805": "co9s6", + "col806": "wx59b", + "col807": "wvdyh", + "col808": "bod4o", + "col809": "s0mdb", + "col810": "rwl8s", + "col811": "dbrg9", + "col812": "tbpdj", + "col813": "litkp", + "col814": "cjtzj", + "col815": "ptmug", + "col816": "raea2", + "col817": "quwuz", + "col818": "3u3r1", + "col819": "0xktg", + "col820": "ke4fl", + "col821": "xpukn", + "col822": "zlbjq", + "col823": "uusld", + "col824": "i4ywu", + "col825": "lgyff", + "col826": "lyt56", + "col827": "zufv2", + "col828": "dg5v7", + "col829": "wx0ha", + "col830": "8v22d", + "col831": "8osq6", + "col832": "vkmk9", + "col833": "db4fj", + "col834": "znfe3", + "col835": "vqp8e", + "col836": "gfdwd", + "col837": "yv59i", + "col838": "k69zr", + "col839": "5oie0", + "col840": "zhkr5", + "col841": "2xtjt", + "col842": "mtmk1", + "col843": "edb0x", + "col844": "zdu9x", + "col845": "yof6p", + "col846": "6ozl1", + "col847": "6gt25", + "col848": "gkas8", + "col849": "9pb95", + "col850": "o9x1r", + "col851": "iszic", + "col852": "qg6b4", + "col853": "tulqd", + "col854": "96jlf", + "col855": "68oc1", + "col856": "ndqxn", + "col857": "m69br", + "col858": "22elz", + "col859": "c9141", + "col860": "0xk34", + "col861": "cp9bs", + "col862": "5xhlw", + "col863": "5ydcq", + "col864": "0b4sr", + "col865": "z80ds", + "col866": "o5q2h", + "col867": "eepis", + "col868": "7him1", + "col869": "i69gv", + "col870": "3h9ku", + "col871": "az4vi", + "col872": "gv1ej", + "col873": "ojiyf", + "col874": "y31rl", + "col875": "40o1g", + "col876": "3dinb", + "col877": "adrb0", + "col878": "jowbl", + "col879": "qqg9v", + "col880": "onqxv", + "col881": "bhdaj", + "col882": "5eydz", + "col883": "3ut3p", + "col884": "3u5ti", + "col885": "21pdj", + "col886": "db83q", + "col887": "y2ur9", + "col888": "qy10u", + "col889": "l3hce", + "col890": "tn761", + "col891": "046dn", + "col892": "y28ha", + "col893": "xl6mx", + "col894": "kjyps", + "col895": "tchqk", + "col896": "t1lor", + "col897": "totta", + "col898": "dce20", + "col899": "ehard", + "col900": "3btgz", + "col901": "aolb6", + "col902": "7amxo", + "col903": "03ujw", + "col904": "8puv0", + "col905": "v5w8i", + "col906": "7c5ht", + "col907": "v42r0", + "col908": "wwiyu", + "col909": "s9exy", + "col910": "y2n9h", + "col911": "sp66b", + "col912": "rctyd", + "col913": "rdy35", + "col914": "qjct2", + "col915": "kryku", + "col916": "b7u1l", + "col917": "07vru", + "col918": "fj5s0", + "col919": "xs9t4", + "col920": "vgci0", + "col921": "75kik", + "col922": "t4gzc", + "col923": "x2ok3", + "col924": "tyrox", + "col925": "7hii9", + "col926": "zxd9a", + "col927": "y1ght", + "col928": "onhzf", + "col929": "wwzsu", + "col930": "pefqf", + "col931": "kikas", + "col932": "v0gw9", + "col933": "h93un", + "col934": "3rt72", + "col935": "4bi7v", + "col936": "sktzd", + "col937": "gt9ji", + "col938": "l1hob", + "col939": "a3zzn", + "col940": "bfeu2", + "col941": "9qq82", + "col942": "n1njk", + "col943": "g116n", + "col944": "m4ak3", + "col945": "1qmzc", + "col946": "uvwk7", + "col947": "xbh4k", + "col948": "84cj2", + "col949": "tyly1", + "col950": "kp4s0", + "col951": "6qzfg", + "col952": "de2wg", + "col953": "urwsg", + "col954": "whi9t", + "col955": "n5elk", + "col956": "y2l55", + "col957": "ung9g", + "col958": "u7oje", + "col959": "2taef", + "col960": "6nhh1", + "col961": "ft9cx", + "col962": "lucvb", + "col963": "sqklz", + "col964": "qnpmv", + "col965": "9ziyl", + "col966": "4ydnb", + "col967": "xg37e", + "col968": "8u38c", + "col969": "8g12q", + "col970": "qaonj", + "col971": "03fwr", + "col972": "0si1t", + "col973": "87wb9", + "col974": "xk1hq", + "col975": "3sa66", + "col976": "ctqzt", + "col977": "eritr", + "col978": "g6kh9", + "col979": "6ffct", + "col980": "zpb98", + "col981": "lftde", + "col982": "0lsy1", + "col983": "nvggt", + "col984": "ecd45", + "col985": "8gd32", + "col986": "q02ja", + "col987": "zu6h4", + "col988": "i1qdk", + "col989": "f4a5o", + "col990": "bxe22", + "col991": "rdcf6", + "col992": "votal", + "col993": "wjf63", + "col994": "hj42c", + "col995": "c9rw2", + "col996": "93xn2", + "col997": "j9w6r", + "col998": "sw1f2", + "col999": "oc527" + }, + { + "name": "Joanna Wood", + "gender": "female", + "col0": "ouevu", + "col1": "1z4mi", + "col2": "faitm", + "col3": "dutkp", + "col4": "n4oxa", + "col5": "9yd6o", + "col6": "cud09", + "col7": "q8jdk", + "col8": "ao5h2", + "col9": "eqqdv", + "col10": "2jp49", + "col11": "94p49", + "col12": "ym7fa", + "col13": "tnxhg", + "col14": "hsem6", + "col15": "5n4ij", + "col16": "65cnb", + "col17": "s2hty", + "col18": "xwjtk", + "col19": "c3o9z", + "col20": "ajply", + "col21": "pciin", + "col22": "l0v0x", + "col23": "v7jrl", + "col24": "8d68w", + "col25": "r41n7", + "col26": "qhk7x", + "col27": "jtixu", + "col28": "y5dns", + "col29": "ck5zw", + "col30": "1jusz", + "col31": "l88bw", + "col32": "dpsgi", + "col33": "13uen", + "col34": "8m3i8", + "col35": "c7orc", + "col36": "a2yla", + "col37": "b30h0", + "col38": "dm449", + "col39": "ftk8h", + "col40": "kb6vu", + "col41": "87vfh", + "col42": "n2pe5", + "col43": "p5w64", + "col44": "6iugb", + "col45": "e3mzj", + "col46": "sgl98", + "col47": "d1q3s", + "col48": "8uxq7", + "col49": "zv6df", + "col50": "xqh1u", + "col51": "1401w", + "col52": "wj8ho", + "col53": "e490l", + "col54": "kdev1", + "col55": "ih0l8", + "col56": "6gq5y", + "col57": "fp1ck", + "col58": "fao47", + "col59": "igcnn", + "col60": "ke1sw", + "col61": "ygblx", + "col62": "6zymr", + "col63": "kr6tl", + "col64": "http4", + "col65": "zzcv7", + "col66": "mniog", + "col67": "ph1yf", + "col68": "amjzn", + "col69": "thafs", + "col70": "uuacl", + "col71": "k01lm", + "col72": "fpscb", + "col73": "5dci5", + "col74": "eyvzn", + "col75": "rkcor", + "col76": "lvb0q", + "col77": "2aksq", + "col78": "4ayd5", + "col79": "bnqd7", + "col80": "ze7dj", + "col81": "ylnaa", + "col82": "lclnk", + "col83": "f50lf", + "col84": "8bgkq", + "col85": "auid7", + "col86": "ru1p2", + "col87": "x4u5v", + "col88": "7pn0f", + "col89": "osq13", + "col90": "0m069", + "col91": "r8427", + "col92": "z2cla", + "col93": "pu41w", + "col94": "9x78y", + "col95": "ktvgu", + "col96": "y76ms", + "col97": "5bq69", + "col98": "rjjq9", + "col99": "b5xij", + "col100": "0ga0v", + "col101": "014zo", + "col102": "ephkz", + "col103": "hpspc", + "col104": "a54a8", + "col105": "u3n7n", + "col106": "ov4ob", + "col107": "uwevm", + "col108": "rsuwz", + "col109": "zx4hi", + "col110": "x53ou", + "col111": "mf1ib", + "col112": "uzyr9", + "col113": "yrjuo", + "col114": "2eico", + "col115": "va4or", + "col116": "om74z", + "col117": "wpvr1", + "col118": "wrzfz", + "col119": "i5rhe", + "col120": "6kjao", + "col121": "lfavx", + "col122": "tjfkd", + "col123": "11v22", + "col124": "c8ofd", + "col125": "fw7jn", + "col126": "jk4hf", + "col127": "l71p4", + "col128": "awtzc", + "col129": "kc9en", + "col130": "dwjhw", + "col131": "8pvkc", + "col132": "bk2fv", + "col133": "28p42", + "col134": "rdpyy", + "col135": "jmog5", + "col136": "i8hdm", + "col137": "k3nbw", + "col138": "0jo2n", + "col139": "9e9zc", + "col140": "ysn03", + "col141": "8g7zo", + "col142": "uxi1h", + "col143": "p9af2", + "col144": "fl4cj", + "col145": "vijqb", + "col146": "xr0ee", + "col147": "xz0dm", + "col148": "99fxu", + "col149": "muok9", + "col150": "y3a3o", + "col151": "lvw7y", + "col152": "watxk", + "col153": "pcwbi", + "col154": "odztd", + "col155": "5fsvj", + "col156": "x1d0i", + "col157": "ttk1i", + "col158": "yy45b", + "col159": "z4erl", + "col160": "w230u", + "col161": "fdulj", + "col162": "t496p", + "col163": "fe0zc", + "col164": "qk9eg", + "col165": "b5w2j", + "col166": "a7tbv", + "col167": "rwmni", + "col168": "0u3lq", + "col169": "jgfmv", + "col170": "w11x8", + "col171": "8450a", + "col172": "w7f10", + "col173": "9mki2", + "col174": "mcgvl", + "col175": "aiyb7", + "col176": "tcuyv", + "col177": "lwnga", + "col178": "nxupb", + "col179": "6ov6k", + "col180": "7pukb", + "col181": "mcjcr", + "col182": "loadw", + "col183": "biamm", + "col184": "sfef0", + "col185": "4i05j", + "col186": "ibbem", + "col187": "w7n8e", + "col188": "psh7x", + "col189": "rgc2v", + "col190": "y7z3v", + "col191": "hp3wf", + "col192": "e85ww", + "col193": "l6l4w", + "col194": "uk2tc", + "col195": "orkkn", + "col196": "o90mn", + "col197": "0svli", + "col198": "i51r3", + "col199": "ra4nw", + "col200": "pofv8", + "col201": "oiby0", + "col202": "pcb5r", + "col203": "p0esg", + "col204": "9mme2", + "col205": "qzzcj", + "col206": "hkmpv", + "col207": "rmjba", + "col208": "na9qc", + "col209": "nv7lm", + "col210": "o53ai", + "col211": "e1f85", + "col212": "xjvow", + "col213": "fjigy", + "col214": "2qmqa", + "col215": "uj8ab", + "col216": "k066j", + "col217": "osrhe", + "col218": "o43cs", + "col219": "vh0h9", + "col220": "bp7oe", + "col221": "1a8q1", + "col222": "06dos", + "col223": "fxs2v", + "col224": "x3f42", + "col225": "1olul", + "col226": "qi1ap", + "col227": "qq762", + "col228": "379zb", + "col229": "pd1q3", + "col230": "h1p1x", + "col231": "m830t", + "col232": "2tlqa", + "col233": "iiodw", + "col234": "o9gm2", + "col235": "wcxi5", + "col236": "956t1", + "col237": "0up3n", + "col238": "6eu0z", + "col239": "5r2rw", + "col240": "m4164", + "col241": "1h93v", + "col242": "rjjgv", + "col243": "clod1", + "col244": "hh6vt", + "col245": "5258l", + "col246": "onj5h", + "col247": "szicu", + "col248": "sgpqh", + "col249": "iu6yc", + "col250": "pek0e", + "col251": "s9pkl", + "col252": "cl2nw", + "col253": "723yn", + "col254": "kd8l9", + "col255": "5oxmo", + "col256": "9e13x", + "col257": "8q0cm", + "col258": "qzvzc", + "col259": "i6r98", + "col260": "vb9q1", + "col261": "wox2h", + "col262": "zw8il", + "col263": "7a5tk", + "col264": "t4xof", + "col265": "bz4vx", + "col266": "9koto", + "col267": "bo9al", + "col268": "1g1gk", + "col269": "eapcp", + "col270": "s21wy", + "col271": "isvv5", + "col272": "bo7ei", + "col273": "ex8sy", + "col274": "ktjc0", + "col275": "rdzq9", + "col276": "sv3ik", + "col277": "wv7q0", + "col278": "33ztw", + "col279": "0wac3", + "col280": "2btgp", + "col281": "tqgkt", + "col282": "0460c", + "col283": "o1soa", + "col284": "26k0n", + "col285": "ls0h8", + "col286": "pzey0", + "col287": "dvjxm", + "col288": "ex39j", + "col289": "844sr", + "col290": "xbllz", + "col291": "z5zqe", + "col292": "6m7oj", + "col293": "0b8j4", + "col294": "dldsn", + "col295": "lhyqd", + "col296": "g2mt1", + "col297": "vtzhf", + "col298": "3ni18", + "col299": "npand", + "col300": "7x0ma", + "col301": "r8e2x", + "col302": "55npw", + "col303": "u031k", + "col304": "boe0v", + "col305": "gb6mu", + "col306": "edpdm", + "col307": "pum19", + "col308": "t25po", + "col309": "lroal", + "col310": "6u6wb", + "col311": "erpzd", + "col312": "ef0cs", + "col313": "gg9nl", + "col314": "acoow", + "col315": "h5jz0", + "col316": "w91sr", + "col317": "zpf4p", + "col318": "p9e01", + "col319": "2mtsd", + "col320": "y370d", + "col321": "w6akt", + "col322": "ll8i1", + "col323": "y0iso", + "col324": "zbfit", + "col325": "v5y4g", + "col326": "wbjy3", + "col327": "vt8i1", + "col328": "mr2yr", + "col329": "g16ym", + "col330": "jflfd", + "col331": "gkkhg", + "col332": "yxtjc", + "col333": "we4b4", + "col334": "xd136", + "col335": "8nc70", + "col336": "d3uey", + "col337": "cf3w4", + "col338": "kjvi7", + "col339": "3dbb7", + "col340": "u58sj", + "col341": "syxt5", + "col342": "lvuob", + "col343": "y90ju", + "col344": "gjbnd", + "col345": "8nt0r", + "col346": "2c5vl", + "col347": "j5v8a", + "col348": "st7h0", + "col349": "dv48b", + "col350": "0uaor", + "col351": "kgpwj", + "col352": "qnvr7", + "col353": "kzziq", + "col354": "3hhna", + "col355": "o7rnp", + "col356": "fiixe", + "col357": "9s43i", + "col358": "zaius", + "col359": "n5bef", + "col360": "n6bne", + "col361": "54ghd", + "col362": "moq97", + "col363": "4mcg2", + "col364": "szxl7", + "col365": "p73qp", + "col366": "oe856", + "col367": "1x5wf", + "col368": "bvgnz", + "col369": "rx9zd", + "col370": "55vjv", + "col371": "wlyu9", + "col372": "meo37", + "col373": "hmgy4", + "col374": "fg8ji", + "col375": "i5rkc", + "col376": "mom18", + "col377": "k11m8", + "col378": "gcbkz", + "col379": "cuuor", + "col380": "rtsas", + "col381": "dprf1", + "col382": "ivd0w", + "col383": "oyt5z", + "col384": "mrx6p", + "col385": "172rc", + "col386": "6c227", + "col387": "fhder", + "col388": "14cjf", + "col389": "81p53", + "col390": "5fex6", + "col391": "rsvy7", + "col392": "1zirg", + "col393": "tcc4p", + "col394": "81bb5", + "col395": "02kol", + "col396": "3lwwg", + "col397": "dvdqc", + "col398": "ph34h", + "col399": "0ne81", + "col400": "2is6n", + "col401": "izw1b", + "col402": "t0l2l", + "col403": "5gtpu", + "col404": "nta95", + "col405": "mjfrq", + "col406": "c7lkb", + "col407": "9tdoz", + "col408": "dq4gp", + "col409": "tl137", + "col410": "scp2e", + "col411": "ktchr", + "col412": "08x29", + "col413": "nm9fr", + "col414": "j7dew", + "col415": "33i4o", + "col416": "6jk92", + "col417": "tdmpv", + "col418": "2uk9z", + "col419": "xga9h", + "col420": "ql5su", + "col421": "7f8il", + "col422": "t9yay", + "col423": "838k7", + "col424": "6q5vk", + "col425": "crjrq", + "col426": "heiy9", + "col427": "745ws", + "col428": "6kiyv", + "col429": "uw4rm", + "col430": "12u7c", + "col431": "2yysp", + "col432": "5zvq9", + "col433": "nwtxg", + "col434": "6voly", + "col435": "w9nad", + "col436": "9yybv", + "col437": "sirnp", + "col438": "xj2x7", + "col439": "wia7u", + "col440": "9ck3v", + "col441": "0xvsz", + "col442": "sht74", + "col443": "4nnle", + "col444": "93pzt", + "col445": "tskkh", + "col446": "tiuqb", + "col447": "l8jfq", + "col448": "fj7oq", + "col449": "ipbwa", + "col450": "6f63h", + "col451": "3vov5", + "col452": "r6v8j", + "col453": "vj0v4", + "col454": "ndphs", + "col455": "ciyci", + "col456": "gomra", + "col457": "7r5zg", + "col458": "64o2v", + "col459": "ytwjl", + "col460": "wxizv", + "col461": "ypidf", + "col462": "plx8m", + "col463": "wqqfr", + "col464": "1oyc9", + "col465": "14aji", + "col466": "cllh9", + "col467": "8gu4h", + "col468": "jfpq8", + "col469": "6u7yj", + "col470": "y71f9", + "col471": "y53kh", + "col472": "u2uzs", + "col473": "l15o8", + "col474": "8422k", + "col475": "hglko", + "col476": "ar48k", + "col477": "nidf0", + "col478": "9nrsr", + "col479": "55tmn", + "col480": "eyv2t", + "col481": "bkz1o", + "col482": "g5f3n", + "col483": "gx8sy", + "col484": "lnkdu", + "col485": "xqfcm", + "col486": "un1sp", + "col487": "6uwi8", + "col488": "g3aeb", + "col489": "ex13y", + "col490": "x1vgh", + "col491": "khyif", + "col492": "sev0q", + "col493": "nznz3", + "col494": "qy6d8", + "col495": "85f7m", + "col496": "54iiu", + "col497": "xjw9h", + "col498": "umfo6", + "col499": "9lq0o", + "col500": "787l7", + "col501": "f4trh", + "col502": "c052b", + "col503": "3jwt6", + "col504": "8vvej", + "col505": "2mnxh", + "col506": "l7zxk", + "col507": "42ntx", + "col508": "fmmo7", + "col509": "90m7m", + "col510": "4xwoa", + "col511": "j6hjc", + "col512": "6ny1r", + "col513": "wqd77", + "col514": "ibhiq", + "col515": "2ch5a", + "col516": "uxhmx", + "col517": "5zmpf", + "col518": "z6g7m", + "col519": "dv0fq", + "col520": "8i4dr", + "col521": "5sxsi", + "col522": "7ng3f", + "col523": "5kz90", + "col524": "u8huy", + "col525": "iw7rd", + "col526": "t6xga", + "col527": "iiad7", + "col528": "kwcgk", + "col529": "5c7iw", + "col530": "k9l8g", + "col531": "4blsc", + "col532": "bd63t", + "col533": "5sq7a", + "col534": "l3a1y", + "col535": "kgrun", + "col536": "dvijn", + "col537": "vtblt", + "col538": "kw4gw", + "col539": "2heoq", + "col540": "l279j", + "col541": "miz63", + "col542": "o6i39", + "col543": "sxa6f", + "col544": "sicqb", + "col545": "aj57e", + "col546": "dey2i", + "col547": "5hidr", + "col548": "scj3q", + "col549": "kunnx", + "col550": "m9bkg", + "col551": "e7sic", + "col552": "988lf", + "col553": "w3prt", + "col554": "dagvs", + "col555": "sk18f", + "col556": "lc4bj", + "col557": "g5kst", + "col558": "5d035", + "col559": "bwig3", + "col560": "4ydm6", + "col561": "vgztz", + "col562": "sxzej", + "col563": "qvo51", + "col564": "7alw3", + "col565": "fj1g0", + "col566": "wh5ux", + "col567": "aoyfc", + "col568": "yj9rl", + "col569": "ahndz", + "col570": "t6cpm", + "col571": "szwje", + "col572": "eh8ax", + "col573": "yiwqs", + "col574": "oa5w5", + "col575": "h8gq4", + "col576": "jquqr", + "col577": "5z451", + "col578": "x4cb0", + "col579": "05y0i", + "col580": "rihhz", + "col581": "hqalt", + "col582": "ijhsn", + "col583": "xxao7", + "col584": "iburb", + "col585": "xgwyr", + "col586": "pljgz", + "col587": "o6v44", + "col588": "mxghr", + "col589": "l3alt", + "col590": "hpq86", + "col591": "xqdxn", + "col592": "1xr7j", + "col593": "45jbo", + "col594": "koym8", + "col595": "r92cy", + "col596": "igz5r", + "col597": "ob2k6", + "col598": "rfn5e", + "col599": "bidma", + "col600": "bllxl", + "col601": "4v3wn", + "col602": "8l7um", + "col603": "inrtz", + "col604": "g23aj", + "col605": "zh61y", + "col606": "104zz", + "col607": "ennii", + "col608": "zjkp1", + "col609": "r65ui", + "col610": "5icpo", + "col611": "6pj8q", + "col612": "md9k0", + "col613": "u9yi6", + "col614": "nrzoe", + "col615": "2f9qx", + "col616": "q72su", + "col617": "kz8o2", + "col618": "7vw2v", + "col619": "lxjsp", + "col620": "u4arg", + "col621": "udhyb", + "col622": "z869b", + "col623": "7cpa1", + "col624": "ka5a9", + "col625": "6c2os", + "col626": "ptlhe", + "col627": "2ywtd", + "col628": "3q5g6", + "col629": "a9n1z", + "col630": "zvquq", + "col631": "9m7wf", + "col632": "cnkn0", + "col633": "j5eqi", + "col634": "6s7iz", + "col635": "d9641", + "col636": "jk3up", + "col637": "kghx4", + "col638": "og45b", + "col639": "n72t5", + "col640": "tfe53", + "col641": "oaqhn", + "col642": "wbk5k", + "col643": "li0wv", + "col644": "xuc1b", + "col645": "fgw9z", + "col646": "sa7ap", + "col647": "r6uwk", + "col648": "2bya1", + "col649": "4ckj1", + "col650": "z88ik", + "col651": "brvn4", + "col652": "ufltr", + "col653": "gm2gm", + "col654": "osl93", + "col655": "ccuv1", + "col656": "vimb1", + "col657": "slqg6", + "col658": "uoc2p", + "col659": "rfvka", + "col660": "fp7yj", + "col661": "9de2p", + "col662": "1rdp0", + "col663": "xpeij", + "col664": "h66kf", + "col665": "mjvli", + "col666": "jc6g0", + "col667": "oxiam", + "col668": "shu6j", + "col669": "6brkl", + "col670": "5mh2m", + "col671": "qovuj", + "col672": "iw8p9", + "col673": "s7cb9", + "col674": "u905i", + "col675": "o5647", + "col676": "6jwig", + "col677": "2fn0f", + "col678": "g6mlr", + "col679": "4msrz", + "col680": "3jj4n", + "col681": "c1fbf", + "col682": "rcqyv", + "col683": "3jaf6", + "col684": "ocw82", + "col685": "kruin", + "col686": "us2me", + "col687": "bv6wf", + "col688": "0xp1j", + "col689": "auuql", + "col690": "5idk7", + "col691": "ephja", + "col692": "97g0z", + "col693": "qqdl6", + "col694": "466fq", + "col695": "yul5x", + "col696": "xqo8p", + "col697": "y81a1", + "col698": "8jnge", + "col699": "qql80", + "col700": "gfsn8", + "col701": "cc2lb", + "col702": "v7jez", + "col703": "iho4g", + "col704": "j8ktt", + "col705": "ufpbq", + "col706": "aaq3n", + "col707": "1tz1v", + "col708": "ygq60", + "col709": "wm4pn", + "col710": "cwy8k", + "col711": "5g8tq", + "col712": "ynzs6", + "col713": "11qry", + "col714": "5dbea", + "col715": "ls92w", + "col716": "8cefu", + "col717": "lhiuw", + "col718": "tuut5", + "col719": "a7ozf", + "col720": "ixefc", + "col721": "vfp0g", + "col722": "qr15w", + "col723": "v0z63", + "col724": "pgiqt", + "col725": "yyoq4", + "col726": "9e8af", + "col727": "obd80", + "col728": "kkbbq", + "col729": "ty727", + "col730": "ebkl4", + "col731": "0hpfc", + "col732": "okdeg", + "col733": "fq2d2", + "col734": "xa7vp", + "col735": "tk46m", + "col736": "ln0ri", + "col737": "e37q2", + "col738": "6wkmx", + "col739": "y614r", + "col740": "ipm9t", + "col741": "ppl0a", + "col742": "aqmqw", + "col743": "4a7ap", + "col744": "xllj9", + "col745": "15ji3", + "col746": "pxxkl", + "col747": "dt5ow", + "col748": "fycwe", + "col749": "qkmck", + "col750": "yl3gf", + "col751": "ib1bm", + "col752": "akz7g", + "col753": "iz62w", + "col754": "mdplb", + "col755": "shm8w", + "col756": "y6l0f", + "col757": "f9v4s", + "col758": "i3pk0", + "col759": "z9j63", + "col760": "a0pkp", + "col761": "555i5", + "col762": "0as2l", + "col763": "3c2v7", + "col764": "y8kk4", + "col765": "gkpj7", + "col766": "c8l6l", + "col767": "3iwtf", + "col768": "8k3w1", + "col769": "3pdwa", + "col770": "qe82s", + "col771": "qhwaw", + "col772": "7r2fm", + "col773": "9qf3j", + "col774": "0edfg", + "col775": "xz9qj", + "col776": "91cy4", + "col777": "gfljy", + "col778": "zyths", + "col779": "5r93q", + "col780": "nljz5", + "col781": "1tjst", + "col782": "5qlxs", + "col783": "3gfyk", + "col784": "204gs", + "col785": "zokfp", + "col786": "1a7f7", + "col787": "par6z", + "col788": "1mw2m", + "col789": "k2jpl", + "col790": "cbds3", + "col791": "4wji3", + "col792": "0le4q", + "col793": "nlsg7", + "col794": "rw062", + "col795": "oxfwy", + "col796": "t8jld", + "col797": "a9cvk", + "col798": "5g3qr", + "col799": "or7vy", + "col800": "5nwph", + "col801": "06lj6", + "col802": "m2z9f", + "col803": "xw4yj", + "col804": "knst3", + "col805": "gtawg", + "col806": "dtdab", + "col807": "o7ykl", + "col808": "o6q7a", + "col809": "tarqi", + "col810": "zu54b", + "col811": "wdrh0", + "col812": "cuy25", + "col813": "n18qg", + "col814": "3o5u0", + "col815": "7jt2i", + "col816": "f03f1", + "col817": "zzyt8", + "col818": "1i55r", + "col819": "a3bdt", + "col820": "9n7e1", + "col821": "nf7sk", + "col822": "nbpk6", + "col823": "6z089", + "col824": "iwhkw", + "col825": "j8d49", + "col826": "h8afr", + "col827": "zzz09", + "col828": "r7vxw", + "col829": "90zoj", + "col830": "yt8ou", + "col831": "d2w6v", + "col832": "qumqc", + "col833": "ddwis", + "col834": "pkhrt", + "col835": "t3rjn", + "col836": "e9ojj", + "col837": "v83qi", + "col838": "x10wq", + "col839": "xtlir", + "col840": "mch9c", + "col841": "c95gq", + "col842": "pskyg", + "col843": "53h1u", + "col844": "kiieu", + "col845": "sq9gt", + "col846": "76btt", + "col847": "xvc01", + "col848": "8hnin", + "col849": "ku5tm", + "col850": "rtgmz", + "col851": "wtsri", + "col852": "p79rr", + "col853": "kcl85", + "col854": "b1bwh", + "col855": "r9vv6", + "col856": "cvzr4", + "col857": "dlvk3", + "col858": "wcchc", + "col859": "vjxwt", + "col860": "v3gl8", + "col861": "t19xw", + "col862": "b2c34", + "col863": "k1wc9", + "col864": "xny32", + "col865": "wz45o", + "col866": "yhobi", + "col867": "5oup5", + "col868": "u4cdr", + "col869": "hg7r1", + "col870": "3nz47", + "col871": "tjga5", + "col872": "14axe", + "col873": "cu2fs", + "col874": "4nrzj", + "col875": "aj19s", + "col876": "g12d5", + "col877": "cqp5s", + "col878": "pecd6", + "col879": "blxn4", + "col880": "pc5kt", + "col881": "er63k", + "col882": "6g1bb", + "col883": "jypr2", + "col884": "cv2fu", + "col885": "sqon7", + "col886": "mf0zr", + "col887": "yshh8", + "col888": "tqotn", + "col889": "e38z0", + "col890": "z4k9q", + "col891": "4ffbp", + "col892": "vd0nc", + "col893": "9ns49", + "col894": "1gpqy", + "col895": "fykee", + "col896": "n199a", + "col897": "71nk4", + "col898": "tcvke", + "col899": "mktn4", + "col900": "ywhfz", + "col901": "kg71m", + "col902": "73rle", + "col903": "1q2iy", + "col904": "g2uix", + "col905": "xr1v8", + "col906": "b8f92", + "col907": "gyqly", + "col908": "r59d5", + "col909": "t6m10", + "col910": "a3erp", + "col911": "ligv6", + "col912": "bj340", + "col913": "dtadw", + "col914": "smuna", + "col915": "rrveq", + "col916": "bfxoj", + "col917": "128j4", + "col918": "pfrux", + "col919": "05nkn", + "col920": "ntqyi", + "col921": "seauo", + "col922": "9a0g2", + "col923": "qwb5k", + "col924": "419q5", + "col925": "63p34", + "col926": "mhv4x", + "col927": "8t2uc", + "col928": "uyllu", + "col929": "twdvl", + "col930": "lcuyc", + "col931": "1ylou", + "col932": "l9ld1", + "col933": "2cq02", + "col934": "t5btd", + "col935": "8rqbs", + "col936": "8ajsg", + "col937": "fc5f2", + "col938": "n94zz", + "col939": "qsy8q", + "col940": "6y12l", + "col941": "3jzle", + "col942": "6lwe0", + "col943": "kxkqj", + "col944": "prqif", + "col945": "zhzwt", + "col946": "5uazb", + "col947": "l9n7h", + "col948": "023e1", + "col949": "oa3k7", + "col950": "q23l3", + "col951": "6oe4v", + "col952": "jejw9", + "col953": "dkkdu", + "col954": "m6ncd", + "col955": "f2d2a", + "col956": "yvqni", + "col957": "4g9ng", + "col958": "ndtrq", + "col959": "iaoyw", + "col960": "gtifc", + "col961": "81hcb", + "col962": "jxt0i", + "col963": "9jaww", + "col964": "2sar2", + "col965": "x47ya", + "col966": "q3w32", + "col967": "kxc50", + "col968": "vawew", + "col969": "p91dz", + "col970": "j5x4e", + "col971": "1piz3", + "col972": "gck0h", + "col973": "z96iq", + "col974": "5h47v", + "col975": "ol9xz", + "col976": "o9fsl", + "col977": "32kwt", + "col978": "ta1cr", + "col979": "lxma0", + "col980": "6qqrs", + "col981": "iuj43", + "col982": "7h97x", + "col983": "pe8ne", + "col984": "tg07k", + "col985": "x0r7w", + "col986": "segh0", + "col987": "e98lv", + "col988": "io8jj", + "col989": "tzrvp", + "col990": "ix1wv", + "col991": "sqsbr", + "col992": "zsapn", + "col993": "w7q0g", + "col994": "sxaoc", + "col995": "tvsr0", + "col996": "q3e0j", + "col997": "f71vl", + "col998": "fg0nx", + "col999": "ig28e" + }, + { + "name": "Doyle Hobbs", + "gender": "male", + "col0": "tshbc", + "col1": "hxvac", + "col2": "lmw2r", + "col3": "e87u0", + "col4": "8v5jk", + "col5": "f5mon", + "col6": "kh3cx", + "col7": "7vma1", + "col8": "ua6ig", + "col9": "ont1s", + "col10": "mib6t", + "col11": "2vv3y", + "col12": "zzgt2", + "col13": "1ozzm", + "col14": "h2vig", + "col15": "gshsg", + "col16": "7b585", + "col17": "0r1nd", + "col18": "aw8ma", + "col19": "vmgab", + "col20": "1e1r5", + "col21": "tzd3j", + "col22": "u7qwx", + "col23": "a5j1j", + "col24": "cg9iy", + "col25": "pwwh4", + "col26": "4w0pq", + "col27": "du9av", + "col28": "ton03", + "col29": "yamuf", + "col30": "192i0", + "col31": "huwew", + "col32": "1lhz2", + "col33": "uc9bc", + "col34": "bx3pr", + "col35": "p1t65", + "col36": "8lisp", + "col37": "uuqdy", + "col38": "dzlk9", + "col39": "w19hr", + "col40": "3zj7s", + "col41": "1mwna", + "col42": "ia1bf", + "col43": "yht6j", + "col44": "5qqx1", + "col45": "j8585", + "col46": "b59gy", + "col47": "5y4un", + "col48": "58gg3", + "col49": "3iz70", + "col50": "y7jky", + "col51": "g8ivh", + "col52": "8hhtn", + "col53": "mocq2", + "col54": "ptmlk", + "col55": "hkb1d", + "col56": "i83ag", + "col57": "h7f3d", + "col58": "v2vl8", + "col59": "qymkt", + "col60": "zwdoq", + "col61": "dzh14", + "col62": "z6e6o", + "col63": "jgwgn", + "col64": "xvvv9", + "col65": "sfb76", + "col66": "ezfxd", + "col67": "dmr6s", + "col68": "0p48f", + "col69": "v2xro", + "col70": "3x8wt", + "col71": "bl67l", + "col72": "xx5gd", + "col73": "32l3u", + "col74": "bw7a7", + "col75": "2rqnc", + "col76": "4pz1w", + "col77": "oc59i", + "col78": "zo70e", + "col79": "f87us", + "col80": "5v3zw", + "col81": "cq486", + "col82": "bxwy2", + "col83": "c8ac8", + "col84": "y6ggh", + "col85": "hhukw", + "col86": "cfis4", + "col87": "e2355", + "col88": "qmgt1", + "col89": "83s1v", + "col90": "mhr1i", + "col91": "cqq1y", + "col92": "b9y41", + "col93": "cy8r6", + "col94": "3y4rh", + "col95": "ip6z4", + "col96": "9y3k0", + "col97": "51kag", + "col98": "ohbdy", + "col99": "44zd0", + "col100": "2xz36", + "col101": "mdr1c", + "col102": "4pqaa", + "col103": "yx407", + "col104": "2mxxp", + "col105": "4xjq7", + "col106": "au2gt", + "col107": "b5mzn", + "col108": "wr88a", + "col109": "o7h16", + "col110": "tno32", + "col111": "xey16", + "col112": "pgpsf", + "col113": "xw4py", + "col114": "tzzok", + "col115": "kk3yz", + "col116": "qlxsn", + "col117": "yfha3", + "col118": "e4ri1", + "col119": "9sy25", + "col120": "qzx3z", + "col121": "q0mld", + "col122": "83n2i", + "col123": "6hs84", + "col124": "6fw8t", + "col125": "4c9uo", + "col126": "wbhpy", + "col127": "gsypu", + "col128": "iwaug", + "col129": "ym64w", + "col130": "mco8m", + "col131": "zu1y3", + "col132": "l9xnw", + "col133": "uwrtz", + "col134": "zvg4k", + "col135": "xwfp3", + "col136": "di8es", + "col137": "m9519", + "col138": "yujqh", + "col139": "65qr8", + "col140": "axfbw", + "col141": "yao76", + "col142": "7p9az", + "col143": "yhcg6", + "col144": "5hqim", + "col145": "0mw12", + "col146": "d2cbb", + "col147": "aup9s", + "col148": "qjxr1", + "col149": "5ue8d", + "col150": "wykai", + "col151": "a84wx", + "col152": "b7gfd", + "col153": "1m9v2", + "col154": "nyens", + "col155": "955yl", + "col156": "gxxyo", + "col157": "8idfo", + "col158": "421zm", + "col159": "8zqfq", + "col160": "w1f96", + "col161": "8duys", + "col162": "q6uaf", + "col163": "rr4x5", + "col164": "gxmmv", + "col165": "aifzc", + "col166": "ysk05", + "col167": "23mok", + "col168": "55t09", + "col169": "fdea1", + "col170": "f5cyd", + "col171": "kqrrg", + "col172": "7qu5d", + "col173": "qnr4j", + "col174": "qpt8c", + "col175": "fze28", + "col176": "23axs", + "col177": "gsydg", + "col178": "73bjh", + "col179": "49wr5", + "col180": "l015u", + "col181": "et51k", + "col182": "60rzk", + "col183": "vum4o", + "col184": "fmck8", + "col185": "a71tm", + "col186": "zbkm1", + "col187": "socil", + "col188": "ulegj", + "col189": "7ukfw", + "col190": "xkvcs", + "col191": "bp6fh", + "col192": "mtcoq", + "col193": "f9ln6", + "col194": "ybxs4", + "col195": "o9ion", + "col196": "ozuax", + "col197": "3q7ua", + "col198": "ix3i4", + "col199": "lf6gd", + "col200": "r6vbi", + "col201": "piht3", + "col202": "s0lxb", + "col203": "5svz8", + "col204": "bg97d", + "col205": "j2fxg", + "col206": "xqp2c", + "col207": "lfcn0", + "col208": "v89bg", + "col209": "ccdqr", + "col210": "jbcc4", + "col211": "mgs55", + "col212": "2xgjp", + "col213": "3gh13", + "col214": "b9802", + "col215": "t2xeb", + "col216": "7a3rk", + "col217": "75t35", + "col218": "0h729", + "col219": "06byb", + "col220": "vmzs9", + "col221": "hf1y3", + "col222": "1a4vr", + "col223": "xmby5", + "col224": "1o9he", + "col225": "xhyad", + "col226": "2ww3a", + "col227": "5y94g", + "col228": "17cyh", + "col229": "glrw5", + "col230": "a2wb7", + "col231": "j2bd1", + "col232": "gnu9v", + "col233": "jzstl", + "col234": "1tgi0", + "col235": "x7h5g", + "col236": "5z4i3", + "col237": "qu298", + "col238": "atk9e", + "col239": "fta0c", + "col240": "aggaj", + "col241": "f9drp", + "col242": "rlq9r", + "col243": "pj2dc", + "col244": "kbgmg", + "col245": "k02ho", + "col246": "7rhki", + "col247": "nnodi", + "col248": "yx2ma", + "col249": "gbbso", + "col250": "j4hz0", + "col251": "91v3c", + "col252": "2u2sw", + "col253": "ntq9z", + "col254": "1jeen", + "col255": "tktmb", + "col256": "bmusu", + "col257": "f7szr", + "col258": "jfefu", + "col259": "ajwji", + "col260": "os893", + "col261": "9znbs", + "col262": "57fvc", + "col263": "54p08", + "col264": "p3yrh", + "col265": "0qg4o", + "col266": "f9wkn", + "col267": "5ecp8", + "col268": "9cnmb", + "col269": "kzi31", + "col270": "up3k4", + "col271": "nalq6", + "col272": "4giw6", + "col273": "cj4c3", + "col274": "eouxo", + "col275": "d39f0", + "col276": "8i3jr", + "col277": "t1i6v", + "col278": "r96n0", + "col279": "wh622", + "col280": "vj2j8", + "col281": "bfty6", + "col282": "leugg", + "col283": "5zsj6", + "col284": "2bf5r", + "col285": "wzjyc", + "col286": "zliij", + "col287": "x2d1p", + "col288": "rpqo7", + "col289": "xpdww", + "col290": "uap3k", + "col291": "ps7pb", + "col292": "w189i", + "col293": "ppjw1", + "col294": "rvatn", + "col295": "gmrr2", + "col296": "hwnk2", + "col297": "ho3b0", + "col298": "eazi0", + "col299": "tz4wo", + "col300": "nvglh", + "col301": "nehr6", + "col302": "avoad", + "col303": "masja", + "col304": "vpnm2", + "col305": "zrhpy", + "col306": "z2bta", + "col307": "9s75l", + "col308": "3vjxl", + "col309": "mc3zu", + "col310": "0pt4m", + "col311": "tudlg", + "col312": "enfz3", + "col313": "l3f2j", + "col314": "b5r33", + "col315": "5ert0", + "col316": "6de5j", + "col317": "p97b6", + "col318": "c48aa", + "col319": "jmhe2", + "col320": "qmg20", + "col321": "d1a7c", + "col322": "jfwrr", + "col323": "ix9eg", + "col324": "5mq61", + "col325": "3a26s", + "col326": "n9dt0", + "col327": "6jxy7", + "col328": "unt8d", + "col329": "kpl04", + "col330": "48s4y", + "col331": "06gan", + "col332": "fw76y", + "col333": "b6cgd", + "col334": "c2ksf", + "col335": "0j9rc", + "col336": "1gl3q", + "col337": "48ugz", + "col338": "1gyn9", + "col339": "q18lb", + "col340": "t635r", + "col341": "pwckk", + "col342": "qj7ni", + "col343": "8om3f", + "col344": "84e8n", + "col345": "jpqcl", + "col346": "29qwd", + "col347": "rjbtd", + "col348": "cx0yn", + "col349": "llnj8", + "col350": "3czqk", + "col351": "du2i9", + "col352": "gszex", + "col353": "pf6aa", + "col354": "wfou9", + "col355": "37mqx", + "col356": "1o3vi", + "col357": "t9lfn", + "col358": "lqdfg", + "col359": "9z4k4", + "col360": "0e959", + "col361": "2aiks", + "col362": "e8o25", + "col363": "4x75b", + "col364": "8dgji", + "col365": "cxk8l", + "col366": "tdxam", + "col367": "8oqij", + "col368": "pm65d", + "col369": "bz5jc", + "col370": "yk177", + "col371": "jqbi9", + "col372": "f8qoz", + "col373": "ntcyf", + "col374": "ua6ko", + "col375": "vm24w", + "col376": "dn7ba", + "col377": "howmx", + "col378": "3kdw9", + "col379": "ht5pn", + "col380": "dwq5v", + "col381": "0e0zi", + "col382": "q2ht4", + "col383": "d8ng8", + "col384": "vvr4l", + "col385": "b9rc3", + "col386": "9zhj4", + "col387": "5oncc", + "col388": "pw519", + "col389": "ml8g4", + "col390": "htkls", + "col391": "txg25", + "col392": "znj0y", + "col393": "hxv9o", + "col394": "4u5in", + "col395": "k03os", + "col396": "cm4yh", + "col397": "jc13o", + "col398": "xxo86", + "col399": "e7lah", + "col400": "51usl", + "col401": "m74ac", + "col402": "rjzn1", + "col403": "kp2d5", + "col404": "byt1a", + "col405": "tzx1e", + "col406": "ioviz", + "col407": "o25g8", + "col408": "kl4x1", + "col409": "qzk3j", + "col410": "fsrzs", + "col411": "skiux", + "col412": "pzwai", + "col413": "klic0", + "col414": "hatbn", + "col415": "7mufl", + "col416": "y61lo", + "col417": "dw8xs", + "col418": "xm1rc", + "col419": "b6877", + "col420": "iqvr4", + "col421": "q99ie", + "col422": "do86i", + "col423": "z0vtl", + "col424": "ebt1i", + "col425": "lvx7o", + "col426": "0trcc", + "col427": "dq247", + "col428": "ry1gw", + "col429": "ek8gn", + "col430": "tirry", + "col431": "2su60", + "col432": "goq38", + "col433": "lqngi", + "col434": "syjqs", + "col435": "oqyuu", + "col436": "i7btd", + "col437": "dparf", + "col438": "vfm0b", + "col439": "cqtt9", + "col440": "wz2qm", + "col441": "g3ztb", + "col442": "a51p1", + "col443": "zjfjf", + "col444": "lrej8", + "col445": "9lwod", + "col446": "h7ihd", + "col447": "bvva5", + "col448": "3iwpa", + "col449": "8glp1", + "col450": "6yqhy", + "col451": "zspbu", + "col452": "kxmyp", + "col453": "n04op", + "col454": "cab1p", + "col455": "c3247", + "col456": "mdbsa", + "col457": "uwo2y", + "col458": "yjdnk", + "col459": "wtp2a", + "col460": "nslyr", + "col461": "irt0q", + "col462": "xjnzk", + "col463": "wvro7", + "col464": "2hm87", + "col465": "jaif8", + "col466": "u4w2g", + "col467": "jbdqm", + "col468": "qk2tb", + "col469": "livl1", + "col470": "df5dl", + "col471": "8ghoj", + "col472": "3xiw1", + "col473": "gv3ax", + "col474": "p36co", + "col475": "thbq6", + "col476": "qh86x", + "col477": "jsxgn", + "col478": "0xvzc", + "col479": "cz2t3", + "col480": "aq2px", + "col481": "hptl2", + "col482": "oyeit", + "col483": "wogwc", + "col484": "vswh0", + "col485": "8rce1", + "col486": "j9d83", + "col487": "caaoz", + "col488": "vzhmj", + "col489": "xm0xe", + "col490": "15qsk", + "col491": "daz8x", + "col492": "bcctp", + "col493": "g7nie", + "col494": "zzbg3", + "col495": "x3w5q", + "col496": "67ope", + "col497": "223oi", + "col498": "18i3h", + "col499": "5s17q", + "col500": "gwtky", + "col501": "6eni5", + "col502": "abqsw", + "col503": "flnh8", + "col504": "0bwqa", + "col505": "2ebje", + "col506": "2h0rd", + "col507": "q4uhk", + "col508": "085wz", + "col509": "srjp6", + "col510": "g06di", + "col511": "35dso", + "col512": "ovaqx", + "col513": "ks6ot", + "col514": "qkz48", + "col515": "o299v", + "col516": "bvq66", + "col517": "c6x3z", + "col518": "n1x4a", + "col519": "xb9gr", + "col520": "v4k26", + "col521": "d4ie7", + "col522": "5usx3", + "col523": "izlyv", + "col524": "fupjh", + "col525": "zis8x", + "col526": "w1b6c", + "col527": "f0byz", + "col528": "oap4x", + "col529": "krux2", + "col530": "2aion", + "col531": "nauyg", + "col532": "bhxk2", + "col533": "x80xf", + "col534": "u78ut", + "col535": "9luvp", + "col536": "kfi5j", + "col537": "b8sbi", + "col538": "dxgsf", + "col539": "mi1kd", + "col540": "ob4k8", + "col541": "z7uzf", + "col542": "1ltrd", + "col543": "ialfi", + "col544": "chexk", + "col545": "bs5gl", + "col546": "n4m4l", + "col547": "ka6ex", + "col548": "4ug1i", + "col549": "8scv0", + "col550": "jnyw2", + "col551": "mio52", + "col552": "76t3b", + "col553": "g0um8", + "col554": "3icqa", + "col555": "oyfc3", + "col556": "uczqx", + "col557": "9r24q", + "col558": "1ebhn", + "col559": "9i5ei", + "col560": "mey8o", + "col561": "2oxf4", + "col562": "knyhr", + "col563": "6dkji", + "col564": "buk9z", + "col565": "6yq5t", + "col566": "6mlk3", + "col567": "urjr1", + "col568": "6gzaq", + "col569": "0leh6", + "col570": "gijoh", + "col571": "h84cu", + "col572": "4cu9i", + "col573": "fu00h", + "col574": "wlggf", + "col575": "iwuay", + "col576": "r1yxq", + "col577": "lzega", + "col578": "ej761", + "col579": "kszf9", + "col580": "uujmy", + "col581": "cgux7", + "col582": "gcabs", + "col583": "o5vqp", + "col584": "z0epu", + "col585": "cfag4", + "col586": "jwkoc", + "col587": "cyz6l", + "col588": "5771o", + "col589": "8keda", + "col590": "ln7h5", + "col591": "34fa4", + "col592": "l14pw", + "col593": "0lh5b", + "col594": "eor8r", + "col595": "yycqe", + "col596": "i9fbi", + "col597": "d364c", + "col598": "67shh", + "col599": "zr9nw", + "col600": "uk743", + "col601": "ugxw9", + "col602": "adhk6", + "col603": "y3g04", + "col604": "ib7pg", + "col605": "q9vrp", + "col606": "xc91y", + "col607": "two26", + "col608": "nkgc9", + "col609": "mg0i6", + "col610": "l6xd4", + "col611": "a2nlm", + "col612": "zhtmo", + "col613": "e3w3i", + "col614": "vfb6s", + "col615": "w982s", + "col616": "ehuzy", + "col617": "gpoyh", + "col618": "l8qis", + "col619": "bv6cs", + "col620": "5sx7a", + "col621": "nn7gq", + "col622": "tjl4z", + "col623": "fuy53", + "col624": "2dbn1", + "col625": "29d3g", + "col626": "jiiog", + "col627": "wcbfx", + "col628": "fmux2", + "col629": "6rk1a", + "col630": "wmxk4", + "col631": "d7hh0", + "col632": "wjpbz", + "col633": "6e8t4", + "col634": "meju5", + "col635": "w4knv", + "col636": "86sq6", + "col637": "hoe28", + "col638": "o1mok", + "col639": "gcft1", + "col640": "fm78v", + "col641": "cmmt3", + "col642": "c19xm", + "col643": "oypze", + "col644": "6ohw7", + "col645": "7bnx7", + "col646": "jggzd", + "col647": "5d713", + "col648": "mrmrk", + "col649": "wp23n", + "col650": "j88cv", + "col651": "sp5zt", + "col652": "4s7wc", + "col653": "nuyti", + "col654": "mgf2w", + "col655": "thb4j", + "col656": "kq2ry", + "col657": "kf944", + "col658": "csp92", + "col659": "3ybwv", + "col660": "nkwtv", + "col661": "p211f", + "col662": "roffb", + "col663": "1xhff", + "col664": "te2hs", + "col665": "1dfta", + "col666": "b7kjt", + "col667": "ictd4", + "col668": "9yons", + "col669": "i2t2r", + "col670": "41v51", + "col671": "p63v4", + "col672": "653ce", + "col673": "3hth1", + "col674": "zt2w9", + "col675": "x6umw", + "col676": "4tzqq", + "col677": "8faij", + "col678": "aesn7", + "col679": "6fmte", + "col680": "vhne0", + "col681": "ljh5x", + "col682": "9hpbh", + "col683": "t36p8", + "col684": "yaqkn", + "col685": "f9x0q", + "col686": "s68hv", + "col687": "ul3ra", + "col688": "m36zi", + "col689": "opkor", + "col690": "3jdi4", + "col691": "buhfz", + "col692": "9jsoe", + "col693": "kezbi", + "col694": "i67kk", + "col695": "hznxj", + "col696": "grmaw", + "col697": "7xzj1", + "col698": "28mfw", + "col699": "75y2z", + "col700": "napd4", + "col701": "omr3g", + "col702": "skcqs", + "col703": "2lbir", + "col704": "d3b0e", + "col705": "k6p9m", + "col706": "eh482", + "col707": "4gqbo", + "col708": "chhqp", + "col709": "r4t4n", + "col710": "5jehi", + "col711": "yozoz", + "col712": "txoj1", + "col713": "vv6pj", + "col714": "aboei", + "col715": "xlrx2", + "col716": "b53ct", + "col717": "00j3g", + "col718": "fgoh9", + "col719": "d234f", + "col720": "shvkn", + "col721": "ep2j1", + "col722": "nc1io", + "col723": "k9vbt", + "col724": "ja5ct", + "col725": "dh0h5", + "col726": "6z5ad", + "col727": "1vex4", + "col728": "spysf", + "col729": "swjlz", + "col730": "uxgcq", + "col731": "de7nm", + "col732": "7b68m", + "col733": "prj45", + "col734": "5u10z", + "col735": "8ly3v", + "col736": "4czhs", + "col737": "fuexp", + "col738": "8yb41", + "col739": "6ngf7", + "col740": "xg7u3", + "col741": "ay6mb", + "col742": "3vu1j", + "col743": "vqfdi", + "col744": "slun6", + "col745": "dxz4t", + "col746": "5c86f", + "col747": "putls", + "col748": "0hauj", + "col749": "ek43x", + "col750": "ikvt5", + "col751": "7a4i9", + "col752": "u71o9", + "col753": "43xor", + "col754": "p362s", + "col755": "hj1zh", + "col756": "g2w04", + "col757": "trg17", + "col758": "7pxig", + "col759": "rwwhk", + "col760": "wo03p", + "col761": "q5ob2", + "col762": "5r7gl", + "col763": "0sdk1", + "col764": "bj756", + "col765": "3se0g", + "col766": "uwtg0", + "col767": "hl1py", + "col768": "dgynq", + "col769": "nan36", + "col770": "x58wo", + "col771": "oostn", + "col772": "xqiel", + "col773": "259bc", + "col774": "uxqzz", + "col775": "idxeq", + "col776": "ezj86", + "col777": "p0rxv", + "col778": "u04w4", + "col779": "nvjxe", + "col780": "94jup", + "col781": "oqh8i", + "col782": "yob46", + "col783": "7yyme", + "col784": "5zdo5", + "col785": "nuqqw", + "col786": "4g8y2", + "col787": "l6euj", + "col788": "jj4qo", + "col789": "ralkl", + "col790": "z1psb", + "col791": "xo3ak", + "col792": "wwrwg", + "col793": "21roo", + "col794": "kjrw6", + "col795": "ttess", + "col796": "rbdi8", + "col797": "xdsdr", + "col798": "q5jfp", + "col799": "mqz0l", + "col800": "sqnqw", + "col801": "iii0n", + "col802": "n6r6e", + "col803": "g6s8e", + "col804": "nqlth", + "col805": "ndyn1", + "col806": "bwfn2", + "col807": "yay7y", + "col808": "hwy5z", + "col809": "376ab", + "col810": "qa618", + "col811": "n57g2", + "col812": "wfqka", + "col813": "2kslg", + "col814": "q4wh2", + "col815": "4emty", + "col816": "db6uf", + "col817": "joh9j", + "col818": "luptq", + "col819": "h2tiz", + "col820": "cdioi", + "col821": "biipz", + "col822": "9td4k", + "col823": "3hshp", + "col824": "p5i6g", + "col825": "yqqwz", + "col826": "5axur", + "col827": "jogg8", + "col828": "uiz4s", + "col829": "n6jkc", + "col830": "em3qb", + "col831": "jt3i9", + "col832": "3fb2v", + "col833": "cacpr", + "col834": "daaok", + "col835": "c7yvg", + "col836": "hy8l4", + "col837": "yzc09", + "col838": "okydm", + "col839": "zynbd", + "col840": "fnibj", + "col841": "hizne", + "col842": "vvuq3", + "col843": "t5vp7", + "col844": "z5isi", + "col845": "wh6up", + "col846": "08mu3", + "col847": "ly51b", + "col848": "2lvi0", + "col849": "6t5uj", + "col850": "gk9ew", + "col851": "rd5qw", + "col852": "4lugi", + "col853": "8ry7q", + "col854": "dwg9b", + "col855": "bdrpq", + "col856": "o3wny", + "col857": "zcroq", + "col858": "zcyfh", + "col859": "9xhl2", + "col860": "9z53u", + "col861": "fjct2", + "col862": "5fg2y", + "col863": "lhue5", + "col864": "kjwj4", + "col865": "yde5i", + "col866": "7i8cp", + "col867": "1n4sr", + "col868": "loab2", + "col869": "navih", + "col870": "ee75t", + "col871": "e6yhr", + "col872": "ey2gr", + "col873": "6ybde", + "col874": "wry1r", + "col875": "ecs1x", + "col876": "gmsg9", + "col877": "t70f9", + "col878": "tk0uc", + "col879": "6b5n9", + "col880": "l9ebq", + "col881": "v9jf3", + "col882": "473pj", + "col883": "betc0", + "col884": "kxcpx", + "col885": "69fgo", + "col886": "21uuc", + "col887": "c910p", + "col888": "tedp2", + "col889": "5snew", + "col890": "w09qm", + "col891": "orgw9", + "col892": "agr54", + "col893": "gsl5s", + "col894": "jnkis", + "col895": "90l4k", + "col896": "62b8j", + "col897": "8midn", + "col898": "py9zw", + "col899": "mgizp", + "col900": "ptf1t", + "col901": "u58ab", + "col902": "brz0u", + "col903": "unpsf", + "col904": "5gvxj", + "col905": "dd6sm", + "col906": "i926p", + "col907": "gfeia", + "col908": "u8g01", + "col909": "paojd", + "col910": "82d5i", + "col911": "0z7ov", + "col912": "t7gzz", + "col913": "ridrc", + "col914": "p1yq9", + "col915": "ynv3q", + "col916": "j5lww", + "col917": "2sbds", + "col918": "pre56", + "col919": "bbuak", + "col920": "n939w", + "col921": "updcp", + "col922": "0dnbk", + "col923": "xgavj", + "col924": "kvok8", + "col925": "34qk7", + "col926": "weftw", + "col927": "a449s", + "col928": "ke0a2", + "col929": "mygjh", + "col930": "ugk7e", + "col931": "7kroe", + "col932": "2scfu", + "col933": "vpb62", + "col934": "jlx13", + "col935": "vi0vf", + "col936": "9ytd9", + "col937": "u1mgy", + "col938": "tx1ha", + "col939": "xd4q4", + "col940": "x1wbh", + "col941": "s5fq8", + "col942": "1kchh", + "col943": "m0boc", + "col944": "tmlxh", + "col945": "urmhx", + "col946": "1z8w3", + "col947": "l3dqm", + "col948": "547dn", + "col949": "757ct", + "col950": "2o4uq", + "col951": "ifgc9", + "col952": "flxuw", + "col953": "bnwl9", + "col954": "ne5n5", + "col955": "fytzb", + "col956": "vk9qy", + "col957": "3r7in", + "col958": "l54ih", + "col959": "ew1hx", + "col960": "y2i0v", + "col961": "e5q67", + "col962": "f44zw", + "col963": "ckvhw", + "col964": "xljw5", + "col965": "4c3bd", + "col966": "ljw52", + "col967": "p6l2d", + "col968": "atwhv", + "col969": "5zp0g", + "col970": "q75rk", + "col971": "smst8", + "col972": "g64cp", + "col973": "5gv0k", + "col974": "ws16j", + "col975": "znnyl", + "col976": "oj217", + "col977": "6w7mo", + "col978": "qd091", + "col979": "14ju0", + "col980": "yfr2q", + "col981": "571ga", + "col982": "4lwkx", + "col983": "5vkfc", + "col984": "ompje", + "col985": "ym2ij", + "col986": "792ck", + "col987": "e777s", + "col988": "pem7f", + "col989": "ikvjy", + "col990": "09nta", + "col991": "5x2hm", + "col992": "56rg9", + "col993": "mpovy", + "col994": "k34fr", + "col995": "staue", + "col996": "mf8d4", + "col997": "4lqg1", + "col998": "qp8gs", + "col999": "roor3" + }, + { + "name": "Turner Wilkerson", + "gender": "male", + "col0": "2akbc", + "col1": "btacf", + "col2": "dx984", + "col3": "zauu1", + "col4": "zvyep", + "col5": "gi1es", + "col6": "x54jz", + "col7": "63ip5", + "col8": "i5qrq", + "col9": "50o9x", + "col10": "picir", + "col11": "hooxm", + "col12": "rwtze", + "col13": "rx0am", + "col14": "vjhj2", + "col15": "rjja2", + "col16": "5xed7", + "col17": "te8au", + "col18": "asdmi", + "col19": "dpw43", + "col20": "yywrv", + "col21": "b1pen", + "col22": "9fzgt", + "col23": "8hord", + "col24": "y3nr2", + "col25": "f6k4t", + "col26": "b7fst", + "col27": "syne8", + "col28": "7j0sr", + "col29": "anshz", + "col30": "3ttm6", + "col31": "7ezbm", + "col32": "xxla4", + "col33": "br63y", + "col34": "2r568", + "col35": "k0w3m", + "col36": "pxplo", + "col37": "e5d2q", + "col38": "pl1nc", + "col39": "mdban", + "col40": "3ouj7", + "col41": "r5kv4", + "col42": "oio2w", + "col43": "raqxn", + "col44": "tol82", + "col45": "svk3d", + "col46": "9v0ng", + "col47": "7kl9w", + "col48": "du63o", + "col49": "67em4", + "col50": "rreky", + "col51": "stxbn", + "col52": "e8m9h", + "col53": "ll5cj", + "col54": "9t0dz", + "col55": "zqhnx", + "col56": "541fp", + "col57": "6awjo", + "col58": "70et6", + "col59": "vxama", + "col60": "2zasr", + "col61": "sovob", + "col62": "tot3i", + "col63": "d8toe", + "col64": "hqlpk", + "col65": "cqb7o", + "col66": "54cs2", + "col67": "vjr6k", + "col68": "2no8i", + "col69": "kek8a", + "col70": "ajyde", + "col71": "t7i0p", + "col72": "47u5n", + "col73": "trbuv", + "col74": "aaqfl", + "col75": "t8xbx", + "col76": "ofahr", + "col77": "ihxcc", + "col78": "qf3gu", + "col79": "gto4w", + "col80": "f89lw", + "col81": "290hu", + "col82": "1h8ea", + "col83": "zf5t0", + "col84": "r4wnd", + "col85": "ildgo", + "col86": "x6jjl", + "col87": "9e4vu", + "col88": "pk1zg", + "col89": "vk2x0", + "col90": "917e6", + "col91": "hhrih", + "col92": "oq1bb", + "col93": "w6fc0", + "col94": "ivtj0", + "col95": "1gcke", + "col96": "0aes2", + "col97": "wm0nr", + "col98": "f5s60", + "col99": "rvati", + "col100": "xrl89", + "col101": "01pxg", + "col102": "okt4v", + "col103": "ugti9", + "col104": "hyxgm", + "col105": "xw8cs", + "col106": "xpcvy", + "col107": "zebl3", + "col108": "sz1cs", + "col109": "6jz8v", + "col110": "0ek82", + "col111": "hxx7x", + "col112": "7jz2e", + "col113": "le98r", + "col114": "rs51q", + "col115": "8gksk", + "col116": "tnhc8", + "col117": "5o095", + "col118": "o4thl", + "col119": "ozf35", + "col120": "6e0yk", + "col121": "6z4vh", + "col122": "uvlfo", + "col123": "4rc6m", + "col124": "9sg7z", + "col125": "1zntl", + "col126": "rlpzm", + "col127": "6ruq0", + "col128": "exn1u", + "col129": "p5ejw", + "col130": "srhnz", + "col131": "2vmwq", + "col132": "p9xu6", + "col133": "94cnq", + "col134": "wqyqq", + "col135": "h2qy2", + "col136": "tp2qp", + "col137": "tzieb", + "col138": "rz1kk", + "col139": "3kbx6", + "col140": "y3b9v", + "col141": "knpig", + "col142": "56uuk", + "col143": "sgr8w", + "col144": "nvs6v", + "col145": "v6plo", + "col146": "r3y9t", + "col147": "8mhxh", + "col148": "6q5aw", + "col149": "cwv9q", + "col150": "1lx2l", + "col151": "fcudq", + "col152": "05sgi", + "col153": "z7auy", + "col154": "gvfyz", + "col155": "g1t0t", + "col156": "zxwif", + "col157": "bx1kj", + "col158": "oyz9o", + "col159": "vnb1n", + "col160": "2f85b", + "col161": "uweco", + "col162": "rfi2z", + "col163": "7k1i0", + "col164": "qjs5f", + "col165": "gp4lf", + "col166": "fmhyh", + "col167": "u74fg", + "col168": "vj2vv", + "col169": "7fbk4", + "col170": "tsdez", + "col171": "6kf87", + "col172": "nw5o5", + "col173": "urziz", + "col174": "yjokt", + "col175": "fwefk", + "col176": "o1j87", + "col177": "7joq5", + "col178": "ljt34", + "col179": "bw0i4", + "col180": "aj0fp", + "col181": "5hx83", + "col182": "zqxqs", + "col183": "dra3v", + "col184": "eiyw4", + "col185": "sn7yq", + "col186": "p9v7c", + "col187": "5hs2e", + "col188": "i54xu", + "col189": "gtbrc", + "col190": "27fgz", + "col191": "yfpj1", + "col192": "rb3j0", + "col193": "plhf5", + "col194": "ktvjj", + "col195": "f49uh", + "col196": "q4bvd", + "col197": "urujd", + "col198": "ye9i9", + "col199": "4yfz8", + "col200": "yd8d8", + "col201": "ktjr6", + "col202": "zbhrf", + "col203": "417ow", + "col204": "za5gn", + "col205": "dc7o0", + "col206": "7qk97", + "col207": "c551b", + "col208": "q1da1", + "col209": "cubcw", + "col210": "vl684", + "col211": "u3ulp", + "col212": "i7amt", + "col213": "a6dyn", + "col214": "l9qan", + "col215": "vdnty", + "col216": "j39ju", + "col217": "lcoc3", + "col218": "wj4g2", + "col219": "fm0et", + "col220": "9phki", + "col221": "dvj83", + "col222": "ugg82", + "col223": "6s4ap", + "col224": "9qx36", + "col225": "93tlh", + "col226": "vzibz", + "col227": "qu7mw", + "col228": "dtva0", + "col229": "kxs5o", + "col230": "wpie1", + "col231": "v2p2i", + "col232": "vdlmz", + "col233": "z8m1x", + "col234": "hh8ox", + "col235": "kjgx7", + "col236": "9zm7t", + "col237": "oystn", + "col238": "mt2d9", + "col239": "rgh4w", + "col240": "bkvyq", + "col241": "lda8q", + "col242": "wnuis", + "col243": "b0fsw", + "col244": "b0j11", + "col245": "mjlpl", + "col246": "ogzt4", + "col247": "8c7r8", + "col248": "nz2uv", + "col249": "i9f51", + "col250": "uyvix", + "col251": "amnc7", + "col252": "gq85j", + "col253": "0o5bp", + "col254": "d4990", + "col255": "nf6le", + "col256": "47tin", + "col257": "d37wx", + "col258": "dz9ze", + "col259": "5gk5a", + "col260": "763pg", + "col261": "mgjdj", + "col262": "75xwu", + "col263": "sxpdr", + "col264": "553jr", + "col265": "izkb8", + "col266": "33u43", + "col267": "m7tsn", + "col268": "4wzqu", + "col269": "y59lq", + "col270": "z8g7v", + "col271": "u0y0y", + "col272": "4mj8w", + "col273": "2h7yr", + "col274": "1kdsy", + "col275": "6gada", + "col276": "v8yp6", + "col277": "pg5xk", + "col278": "brezm", + "col279": "aby11", + "col280": "9gyui", + "col281": "ekhlq", + "col282": "sfa5t", + "col283": "w6muk", + "col284": "s7txa", + "col285": "ctlo0", + "col286": "ptlv6", + "col287": "x92fs", + "col288": "dn556", + "col289": "gi96n", + "col290": "qufum", + "col291": "1w1kz", + "col292": "gep6y", + "col293": "awflc", + "col294": "xdtpn", + "col295": "5njie", + "col296": "09prq", + "col297": "j0fm7", + "col298": "mb7on", + "col299": "xsghc", + "col300": "5n8rq", + "col301": "1ci3z", + "col302": "yb7mr", + "col303": "3yz6b", + "col304": "o9ve7", + "col305": "x4skk", + "col306": "f45fq", + "col307": "fd1lp", + "col308": "eqizi", + "col309": "ghvhh", + "col310": "vhnst", + "col311": "ydtv2", + "col312": "zgm99", + "col313": "5j5cx", + "col314": "eiz1f", + "col315": "lbzoy", + "col316": "bgvr0", + "col317": "4odzq", + "col318": "sanlu", + "col319": "n4ewa", + "col320": "u02zb", + "col321": "wm0v8", + "col322": "sgpci", + "col323": "wec2z", + "col324": "6d8nx", + "col325": "thxh2", + "col326": "igpua", + "col327": "ndxi5", + "col328": "vden2", + "col329": "c8x9c", + "col330": "o95dq", + "col331": "amqd1", + "col332": "lij7n", + "col333": "zwk6p", + "col334": "ox1ys", + "col335": "fqkp3", + "col336": "tt9l0", + "col337": "p7a1j", + "col338": "uez4v", + "col339": "32ph3", + "col340": "y9wsy", + "col341": "k2wzi", + "col342": "8oiq9", + "col343": "klugj", + "col344": "y3b4u", + "col345": "mwevj", + "col346": "df6r8", + "col347": "2yayj", + "col348": "uo307", + "col349": "b7rue", + "col350": "rapec", + "col351": "fxoud", + "col352": "nyhvp", + "col353": "1d1h3", + "col354": "oxyvg", + "col355": "i9sun", + "col356": "7li9u", + "col357": "as7vs", + "col358": "ubkz7", + "col359": "am6nq", + "col360": "1ojlu", + "col361": "q4e7m", + "col362": "nnf0m", + "col363": "4zyvh", + "col364": "es15n", + "col365": "21af3", + "col366": "y4a3d", + "col367": "vj2uw", + "col368": "b12bk", + "col369": "69ezj", + "col370": "4b418", + "col371": "xm1qy", + "col372": "b0cv2", + "col373": "fiv6j", + "col374": "eazm3", + "col375": "8flpq", + "col376": "72gvb", + "col377": "me9b1", + "col378": "eufb9", + "col379": "8ckdt", + "col380": "gy4ic", + "col381": "y5m8e", + "col382": "o7lr2", + "col383": "ks8cy", + "col384": "kie6k", + "col385": "dw8ze", + "col386": "ma0n2", + "col387": "r1r3j", + "col388": "xx8ss", + "col389": "bj5a6", + "col390": "xyyq8", + "col391": "5kq81", + "col392": "6oup4", + "col393": "2libe", + "col394": "ucks2", + "col395": "2u94r", + "col396": "pin6o", + "col397": "62pl8", + "col398": "pkyt1", + "col399": "iha44", + "col400": "mvlyz", + "col401": "jhjvv", + "col402": "987lt", + "col403": "0y5l7", + "col404": "glaa8", + "col405": "q4hmt", + "col406": "0z5f2", + "col407": "44ltr", + "col408": "89aud", + "col409": "qajo3", + "col410": "bteyh", + "col411": "vfds1", + "col412": "kpmpq", + "col413": "12xs6", + "col414": "1rx9n", + "col415": "gx6ts", + "col416": "yfv6d", + "col417": "to8y7", + "col418": "oawdf", + "col419": "1baky", + "col420": "d943e", + "col421": "bdf2b", + "col422": "9u0z4", + "col423": "2asve", + "col424": "0urk8", + "col425": "w3vev", + "col426": "talqe", + "col427": "h72rl", + "col428": "2ibie", + "col429": "oo49c", + "col430": "0dxfv", + "col431": "fqym8", + "col432": "k9uhg", + "col433": "jodt6", + "col434": "kifzi", + "col435": "sn5cy", + "col436": "ubj04", + "col437": "ggpe4", + "col438": "elf9s", + "col439": "e2jv4", + "col440": "w1zwv", + "col441": "zh6yr", + "col442": "pjhgr", + "col443": "zqmdx", + "col444": "io3a9", + "col445": "p6arc", + "col446": "vxnqy", + "col447": "170br", + "col448": "zpw0o", + "col449": "qg64c", + "col450": "3l1dq", + "col451": "z0u1x", + "col452": "ty525", + "col453": "atm9w", + "col454": "5rwoc", + "col455": "it886", + "col456": "do05z", + "col457": "9lah8", + "col458": "7pk9v", + "col459": "t50oz", + "col460": "b86kw", + "col461": "388kr", + "col462": "wc58x", + "col463": "5awgr", + "col464": "ow905", + "col465": "k4tgj", + "col466": "b3fo7", + "col467": "66sx1", + "col468": "h8ty9", + "col469": "5ccc5", + "col470": "xfo2k", + "col471": "bn69k", + "col472": "zem4l", + "col473": "vw8yf", + "col474": "0gthh", + "col475": "1din8", + "col476": "we21t", + "col477": "tw43z", + "col478": "55jr5", + "col479": "t3nu7", + "col480": "egop3", + "col481": "pkop8", + "col482": "1pdgu", + "col483": "8ytyn", + "col484": "96f72", + "col485": "ep9a7", + "col486": "zf55a", + "col487": "5q7le", + "col488": "fixet", + "col489": "fcaj7", + "col490": "nj68g", + "col491": "0iq1v", + "col492": "ln2m4", + "col493": "a57n8", + "col494": "6vgg6", + "col495": "ni5in", + "col496": "v989n", + "col497": "ic0em", + "col498": "2in93", + "col499": "s69sv", + "col500": "imrni", + "col501": "im6n8", + "col502": "ke3hq", + "col503": "v4aud", + "col504": "n17lq", + "col505": "zldoi", + "col506": "gyyk0", + "col507": "8qyqn", + "col508": "eg3k4", + "col509": "eaq40", + "col510": "ln5r0", + "col511": "uokhg", + "col512": "1y97v", + "col513": "esj3i", + "col514": "3i7kg", + "col515": "qcjyf", + "col516": "ntn5q", + "col517": "t1doq", + "col518": "juizk", + "col519": "f6du3", + "col520": "8yw8g", + "col521": "213ee", + "col522": "p2dso", + "col523": "wdvlg", + "col524": "5lyd9", + "col525": "e2nnj", + "col526": "f9oc3", + "col527": "xjalo", + "col528": "iofnu", + "col529": "gu8mo", + "col530": "b58t0", + "col531": "l7fts", + "col532": "0uhx3", + "col533": "cdok1", + "col534": "zd5b8", + "col535": "yer0a", + "col536": "hq6s5", + "col537": "1990g", + "col538": "3z394", + "col539": "y9jvh", + "col540": "uk69x", + "col541": "p193t", + "col542": "prczs", + "col543": "ddr2s", + "col544": "r01z8", + "col545": "ga2w4", + "col546": "7g8sy", + "col547": "bqmmc", + "col548": "kr05y", + "col549": "gqhhq", + "col550": "hl3u1", + "col551": "xqu0l", + "col552": "u6ljz", + "col553": "f214f", + "col554": "ujo42", + "col555": "zsmb8", + "col556": "sdlrd", + "col557": "isdqo", + "col558": "hu8q0", + "col559": "mp1w8", + "col560": "1bdlk", + "col561": "9fe8l", + "col562": "dl9rq", + "col563": "n9lwe", + "col564": "9c0yi", + "col565": "q935h", + "col566": "kb8ly", + "col567": "07zat", + "col568": "gbxv1", + "col569": "p38fi", + "col570": "50ffa", + "col571": "7gmlh", + "col572": "awzn3", + "col573": "1cy8j", + "col574": "m696u", + "col575": "azdd4", + "col576": "ohn8c", + "col577": "reyjc", + "col578": "f835f", + "col579": "l81aq", + "col580": "rntsd", + "col581": "w4ldu", + "col582": "75825", + "col583": "q4ifi", + "col584": "py217", + "col585": "ox8cd", + "col586": "xt4hr", + "col587": "2pkdj", + "col588": "f5rx1", + "col589": "eih2a", + "col590": "bntah", + "col591": "6e2p1", + "col592": "ft1me", + "col593": "te4pu", + "col594": "zctrg", + "col595": "iefb7", + "col596": "k6iil", + "col597": "0zuej", + "col598": "h8qc5", + "col599": "9s3yi", + "col600": "ur86y", + "col601": "p3uf3", + "col602": "h55ie", + "col603": "c8gb3", + "col604": "afsxu", + "col605": "ejs7k", + "col606": "ca8gc", + "col607": "0k5iq", + "col608": "3nesa", + "col609": "qra8r", + "col610": "jt1d3", + "col611": "rr6op", + "col612": "mok91", + "col613": "v3n9f", + "col614": "1delg", + "col615": "rm1ak", + "col616": "4rnin", + "col617": "71rmq", + "col618": "chona", + "col619": "p8yvg", + "col620": "6e18s", + "col621": "ziqmp", + "col622": "jcyo9", + "col623": "ghlbp", + "col624": "3mphd", + "col625": "1dd54", + "col626": "hfynx", + "col627": "1mqbr", + "col628": "h3vcj", + "col629": "h5y1r", + "col630": "fidub", + "col631": "4j677", + "col632": "f0ddp", + "col633": "voop4", + "col634": "frsu6", + "col635": "g2n17", + "col636": "hosli", + "col637": "l19eq", + "col638": "ag663", + "col639": "f6792", + "col640": "8yaen", + "col641": "1g0eh", + "col642": "3i2z0", + "col643": "yehs1", + "col644": "we1m7", + "col645": "j0vxi", + "col646": "moit8", + "col647": "b3mnl", + "col648": "u99bc", + "col649": "98qx3", + "col650": "kgkst", + "col651": "y4bq0", + "col652": "36dua", + "col653": "7q8av", + "col654": "8mpkd", + "col655": "nt6l6", + "col656": "6q0yq", + "col657": "5gwzg", + "col658": "lqxl1", + "col659": "bg8xj", + "col660": "52tqo", + "col661": "jb72k", + "col662": "tpcwl", + "col663": "b7otf", + "col664": "pdxzl", + "col665": "ai6uk", + "col666": "9n43p", + "col667": "9ck0v", + "col668": "pjohr", + "col669": "nca5d", + "col670": "34ld3", + "col671": "dvqa8", + "col672": "te7te", + "col673": "7zkhp", + "col674": "u6td9", + "col675": "sq144", + "col676": "ch6ck", + "col677": "tucma", + "col678": "18bhc", + "col679": "q604p", + "col680": "574lq", + "col681": "gho8i", + "col682": "2ypgm", + "col683": "toxrh", + "col684": "1trcn", + "col685": "jw3nc", + "col686": "g3c57", + "col687": "1rb25", + "col688": "xxs5c", + "col689": "rncdq", + "col690": "nbfht", + "col691": "z2ps2", + "col692": "yldzq", + "col693": "3seyq", + "col694": "6cz2i", + "col695": "hgtks", + "col696": "slrb2", + "col697": "j89hh", + "col698": "38kuh", + "col699": "rpvwd", + "col700": "nnfg2", + "col701": "4ktj5", + "col702": "xb5xs", + "col703": "vv1xg", + "col704": "kj2ku", + "col705": "vr7d3", + "col706": "ioi2i", + "col707": "ld278", + "col708": "r7ivr", + "col709": "cnw30", + "col710": "c6ppu", + "col711": "kuvg8", + "col712": "6r1ub", + "col713": "mlqq8", + "col714": "gg0i2", + "col715": "3k50a", + "col716": "cjfpc", + "col717": "q0uw5", + "col718": "o1smd", + "col719": "wuxwv", + "col720": "4df6k", + "col721": "jwp5n", + "col722": "memfv", + "col723": "jyz1b", + "col724": "oqsgy", + "col725": "2dkpe", + "col726": "r87k8", + "col727": "onebv", + "col728": "5x7cb", + "col729": "msnfu", + "col730": "bfirm", + "col731": "jxvb1", + "col732": "c4ew0", + "col733": "s30i2", + "col734": "v4uzg", + "col735": "36ayn", + "col736": "7rjb0", + "col737": "i3h9p", + "col738": "zrx5j", + "col739": "diewu", + "col740": "z88wq", + "col741": "9b7dp", + "col742": "90wi5", + "col743": "9qsja", + "col744": "bgvux", + "col745": "wfedd", + "col746": "g7k64", + "col747": "6q8kg", + "col748": "go53w", + "col749": "n4apz", + "col750": "f2vyv", + "col751": "x7s0v", + "col752": "l99g2", + "col753": "ryez4", + "col754": "mcy2k", + "col755": "ekvcz", + "col756": "k5dl0", + "col757": "nuwb4", + "col758": "45kqw", + "col759": "de2jz", + "col760": "z2koo", + "col761": "5yjma", + "col762": "bprbf", + "col763": "4sg3g", + "col764": "0ldx6", + "col765": "djai0", + "col766": "wkeah", + "col767": "cuyno", + "col768": "9o7cj", + "col769": "70rd5", + "col770": "5xq0z", + "col771": "dg0in", + "col772": "stplo", + "col773": "l8xdq", + "col774": "7mbi9", + "col775": "yoo5v", + "col776": "gf880", + "col777": "dywhj", + "col778": "o59pr", + "col779": "8o9sj", + "col780": "9ad2h", + "col781": "14u1b", + "col782": "v83tl", + "col783": "jbtla", + "col784": "93tk8", + "col785": "ziz2y", + "col786": "4yqi3", + "col787": "inund", + "col788": "gosz5", + "col789": "077fa", + "col790": "x9mrh", + "col791": "r5n7c", + "col792": "dgmoa", + "col793": "edq32", + "col794": "f0lfz", + "col795": "xgtyd", + "col796": "2yilz", + "col797": "g33b1", + "col798": "i2pui", + "col799": "z3kag", + "col800": "04okx", + "col801": "dkvar", + "col802": "cgwjy", + "col803": "e1ang", + "col804": "nmzqw", + "col805": "bux1r", + "col806": "cgd2u", + "col807": "x1q0r", + "col808": "ljq62", + "col809": "mdlud", + "col810": "hixok", + "col811": "b69j5", + "col812": "de6yh", + "col813": "k8hfv", + "col814": "5egll", + "col815": "ox6jz", + "col816": "xyuuz", + "col817": "sm24s", + "col818": "wwmf0", + "col819": "da57p", + "col820": "kkpwc", + "col821": "bmh8r", + "col822": "3mr7l", + "col823": "j7zuj", + "col824": "299p5", + "col825": "7ij1d", + "col826": "49sg5", + "col827": "9fuq1", + "col828": "lr55h", + "col829": "icn04", + "col830": "n19i0", + "col831": "k9c3s", + "col832": "a7vka", + "col833": "l6bwl", + "col834": "tjbkr", + "col835": "v6wlj", + "col836": "lxh6r", + "col837": "o2i46", + "col838": "jnruo", + "col839": "qvi88", + "col840": "hcl3f", + "col841": "a9ixq", + "col842": "mzb7w", + "col843": "w9xq3", + "col844": "sjz12", + "col845": "eyaz1", + "col846": "kwfbe", + "col847": "jej9t", + "col848": "4zn8o", + "col849": "5e1k0", + "col850": "5syfo", + "col851": "ydxdc", + "col852": "ox5nm", + "col853": "qzrr5", + "col854": "lxjeu", + "col855": "4gqur", + "col856": "8odd6", + "col857": "zk13a", + "col858": "4dbgs", + "col859": "ev888", + "col860": "gcwal", + "col861": "zgb2u", + "col862": "rfix8", + "col863": "bc35t", + "col864": "l43cq", + "col865": "1jx09", + "col866": "bu8cs", + "col867": "riy5l", + "col868": "frybi", + "col869": "j2alc", + "col870": "fqodh", + "col871": "wbwmx", + "col872": "ttuwd", + "col873": "pe3bw", + "col874": "iz6oq", + "col875": "vj0ze", + "col876": "05br6", + "col877": "29eux", + "col878": "i0yrs", + "col879": "pce4g", + "col880": "lgt43", + "col881": "anlvg", + "col882": "4fm32", + "col883": "msv79", + "col884": "0vr7r", + "col885": "rb50u", + "col886": "wxtx8", + "col887": "8739g", + "col888": "vzw24", + "col889": "h857r", + "col890": "v98d5", + "col891": "gkyqz", + "col892": "mznhf", + "col893": "oogbt", + "col894": "cnv2s", + "col895": "7bwp6", + "col896": "yg1mv", + "col897": "jdkp4", + "col898": "0ug1n", + "col899": "rsjzy", + "col900": "k3sjz", + "col901": "ljqds", + "col902": "xtpqw", + "col903": "zucrx", + "col904": "2kfmc", + "col905": "qene2", + "col906": "51mj8", + "col907": "d5a2e", + "col908": "wk7bl", + "col909": "7tu77", + "col910": "561qe", + "col911": "3gigr", + "col912": "jeqvr", + "col913": "si2qp", + "col914": "bcpkh", + "col915": "l4kbd", + "col916": "syyxv", + "col917": "l0dbf", + "col918": "re4q0", + "col919": "h55sq", + "col920": "5cdu7", + "col921": "u14h5", + "col922": "oo3sc", + "col923": "iyqfw", + "col924": "nzlts", + "col925": "brmwp", + "col926": "re95v", + "col927": "0a7xp", + "col928": "bgss5", + "col929": "x5zlb", + "col930": "vx1k4", + "col931": "8q8sg", + "col932": "n5825", + "col933": "gmwg8", + "col934": "hd283", + "col935": "ge0ut", + "col936": "6by13", + "col937": "s46ie", + "col938": "i4zb9", + "col939": "n7tf8", + "col940": "i49sz", + "col941": "cyub7", + "col942": "6ft4o", + "col943": "pg5s0", + "col944": "xbcz4", + "col945": "f0313", + "col946": "umwz8", + "col947": "0v0nv", + "col948": "vikdw", + "col949": "vaaco", + "col950": "00mtx", + "col951": "wrbq1", + "col952": "zafru", + "col953": "rwxrs", + "col954": "ee45i", + "col955": "8tgan", + "col956": "xj2d1", + "col957": "tiv4y", + "col958": "jrnev", + "col959": "cee68", + "col960": "0z7sx", + "col961": "bzbr8", + "col962": "mkkf3", + "col963": "6p6tu", + "col964": "xz3uk", + "col965": "hjrz0", + "col966": "yz01b", + "col967": "qaw8l", + "col968": "scaa4", + "col969": "u4lb5", + "col970": "07us0", + "col971": "arkn3", + "col972": "a474p", + "col973": "oe6wc", + "col974": "ojn1b", + "col975": "3gtde", + "col976": "pho31", + "col977": "8dav5", + "col978": "8q301", + "col979": "7eqoe", + "col980": "ze64h", + "col981": "icxv3", + "col982": "7fx8n", + "col983": "loft4", + "col984": "pov91", + "col985": "cpwc2", + "col986": "ml3mp", + "col987": "tat06", + "col988": "rv2gq", + "col989": "05v00", + "col990": "zb9ps", + "col991": "vux8z", + "col992": "6wdk7", + "col993": "xbv8n", + "col994": "it3nw", + "col995": "9o62q", + "col996": "3nsl8", + "col997": "j2k0u", + "col998": "mb0lp", + "col999": "qdgei" + }, + { + "name": "Burgess Hartman", + "gender": "male", + "col0": "v71xv", + "col1": "quar6", + "col2": "xomm2", + "col3": "w2oug", + "col4": "4nta4", + "col5": "ddub6", + "col6": "k90fo", + "col7": "ygd8c", + "col8": "3kxpq", + "col9": "d12hu", + "col10": "kn3ww", + "col11": "240jq", + "col12": "efvad", + "col13": "2i6wj", + "col14": "unnoy", + "col15": "it4fe", + "col16": "rcz2n", + "col17": "2tgec", + "col18": "go2fq", + "col19": "hvmz0", + "col20": "erze2", + "col21": "j1jbj", + "col22": "jzslw", + "col23": "kx1tk", + "col24": "5gv60", + "col25": "vlclt", + "col26": "0cmve", + "col27": "4u4l5", + "col28": "526x2", + "col29": "hr0mn", + "col30": "mt07k", + "col31": "nsxjl", + "col32": "e5de7", + "col33": "mhc9u", + "col34": "x1vmt", + "col35": "hl5yx", + "col36": "1fbmz", + "col37": "zj9v2", + "col38": "qydtw", + "col39": "h5qsh", + "col40": "pvnog", + "col41": "0vxkv", + "col42": "ge83o", + "col43": "ml38k", + "col44": "ofq2k", + "col45": "vi8mz", + "col46": "iqy0x", + "col47": "vxd68", + "col48": "0d60y", + "col49": "gf1qt", + "col50": "ej5xg", + "col51": "vstxj", + "col52": "jmh6c", + "col53": "r3atm", + "col54": "i8d2k", + "col55": "sxpl7", + "col56": "ut9g8", + "col57": "pcfjt", + "col58": "rjhpi", + "col59": "f3qte", + "col60": "83rzk", + "col61": "tbhh7", + "col62": "p6hzw", + "col63": "6c3k5", + "col64": "2v8j4", + "col65": "0s4cp", + "col66": "gpk9e", + "col67": "t6vh4", + "col68": "5cnfl", + "col69": "3ycwq", + "col70": "t151x", + "col71": "wu4s9", + "col72": "8njp0", + "col73": "qa3ad", + "col74": "pj84k", + "col75": "d70j4", + "col76": "t46cb", + "col77": "i5lrx", + "col78": "uqmi3", + "col79": "6s7m8", + "col80": "o0inh", + "col81": "m6fk3", + "col82": "x4o7z", + "col83": "b8zsv", + "col84": "xat1c", + "col85": "0f68x", + "col86": "u4r4k", + "col87": "89h2s", + "col88": "ybg4k", + "col89": "kv1aw", + "col90": "8ocq5", + "col91": "p2jpo", + "col92": "gkubm", + "col93": "xwnxk", + "col94": "um6ng", + "col95": "i6yks", + "col96": "c5hea", + "col97": "71nn4", + "col98": "vcbxe", + "col99": "t3xno", + "col100": "ksucn", + "col101": "t4d4g", + "col102": "nk6xl", + "col103": "kogno", + "col104": "b4yo5", + "col105": "86kth", + "col106": "b1uv7", + "col107": "kbdiq", + "col108": "p88gf", + "col109": "n52gy", + "col110": "qco0b", + "col111": "av3vg", + "col112": "43r2x", + "col113": "6dlb4", + "col114": "yu186", + "col115": "5au8g", + "col116": "fjwt8", + "col117": "4pkkt", + "col118": "x3xh0", + "col119": "wmj58", + "col120": "xai3d", + "col121": "2bt6i", + "col122": "q7ym8", + "col123": "75mae", + "col124": "grbik", + "col125": "5vwcu", + "col126": "q6ol2", + "col127": "vaxs9", + "col128": "0r5af", + "col129": "fuk7p", + "col130": "8py9i", + "col131": "1708h", + "col132": "5skiv", + "col133": "uwc95", + "col134": "y992t", + "col135": "5jgkr", + "col136": "i8v4e", + "col137": "gum5g", + "col138": "bp9qh", + "col139": "be8xp", + "col140": "7dnnk", + "col141": "lk1pe", + "col142": "qszvl", + "col143": "gieyk", + "col144": "q9ntp", + "col145": "kdvgj", + "col146": "sbu0o", + "col147": "f944c", + "col148": "fze2w", + "col149": "dy92x", + "col150": "3d6u5", + "col151": "wjt2o", + "col152": "rvk5q", + "col153": "hkpla", + "col154": "nmiuz", + "col155": "xz7vl", + "col156": "2yt6h", + "col157": "7qjhu", + "col158": "1pzj0", + "col159": "onhhq", + "col160": "2ymq6", + "col161": "ubrem", + "col162": "yavyd", + "col163": "ai80b", + "col164": "3qalp", + "col165": "d53n6", + "col166": "xxhmr", + "col167": "lqyo6", + "col168": "1tk35", + "col169": "bvulj", + "col170": "k6f55", + "col171": "mmq2x", + "col172": "5iwel", + "col173": "ef60l", + "col174": "jnynl", + "col175": "aoa83", + "col176": "l7mh7", + "col177": "j1zt5", + "col178": "qm6sk", + "col179": "vel6v", + "col180": "luasx", + "col181": "5hcu2", + "col182": "4tunn", + "col183": "6l41k", + "col184": "uu5rq", + "col185": "cugd0", + "col186": "g4uuj", + "col187": "u3y1h", + "col188": "fj98p", + "col189": "cs30q", + "col190": "5dx7k", + "col191": "h8phy", + "col192": "tfu0p", + "col193": "oygco", + "col194": "chw3e", + "col195": "7k8ic", + "col196": "3uvcr", + "col197": "6y0sh", + "col198": "pmnkz", + "col199": "vdhk4", + "col200": "9hsa8", + "col201": "k2182", + "col202": "kl218", + "col203": "y9nu9", + "col204": "ieda8", + "col205": "2b5ve", + "col206": "ggspx", + "col207": "igp0h", + "col208": "6c5ql", + "col209": "q36hr", + "col210": "dqtdl", + "col211": "1zjat", + "col212": "kehkx", + "col213": "g95f1", + "col214": "vycrk", + "col215": "029h7", + "col216": "toarv", + "col217": "bcacm", + "col218": "qnwni", + "col219": "shs1e", + "col220": "hpr0l", + "col221": "mdqn2", + "col222": "jqnex", + "col223": "sg7j2", + "col224": "et7lm", + "col225": "x6wq6", + "col226": "t39m3", + "col227": "rhnfj", + "col228": "g4xc7", + "col229": "evztu", + "col230": "1ow3v", + "col231": "c2d1t", + "col232": "n2uwr", + "col233": "w113f", + "col234": "43ugx", + "col235": "6e4o5", + "col236": "2snzb", + "col237": "cuc5c", + "col238": "boywi", + "col239": "jmz7f", + "col240": "pg274", + "col241": "4dfr5", + "col242": "kclva", + "col243": "2pxss", + "col244": "elee4", + "col245": "7q8lk", + "col246": "9b11f", + "col247": "j0p23", + "col248": "gc8ke", + "col249": "quwgm", + "col250": "j7uw9", + "col251": "swiw0", + "col252": "kr2ib", + "col253": "knirj", + "col254": "t62l0", + "col255": "gvd3n", + "col256": "b32yp", + "col257": "uk85i", + "col258": "wreo2", + "col259": "pdhlh", + "col260": "a1kqe", + "col261": "zhv1v", + "col262": "j4881", + "col263": "mw2z0", + "col264": "iluvz", + "col265": "av3uo", + "col266": "wxdzs", + "col267": "w9u0u", + "col268": "22y2u", + "col269": "ko438", + "col270": "bzzse", + "col271": "rry66", + "col272": "q0e9l", + "col273": "quil2", + "col274": "15sjc", + "col275": "5j55z", + "col276": "uxby2", + "col277": "w2ew4", + "col278": "hegl1", + "col279": "fvja9", + "col280": "4l2kp", + "col281": "1pg01", + "col282": "9rwz4", + "col283": "32f9y", + "col284": "uco8s", + "col285": "4m0ka", + "col286": "4hty3", + "col287": "awf9l", + "col288": "4yv4a", + "col289": "f2shn", + "col290": "o05aw", + "col291": "3qlya", + "col292": "dflr0", + "col293": "id3hj", + "col294": "c4oqb", + "col295": "rjs3v", + "col296": "hzgf8", + "col297": "11jvs", + "col298": "xfoh5", + "col299": "svlkq", + "col300": "xhrl6", + "col301": "i4dkj", + "col302": "e3fwh", + "col303": "8c5px", + "col304": "oggmo", + "col305": "khshk", + "col306": "f7fsc", + "col307": "jkvpr", + "col308": "3xbba", + "col309": "if2fr", + "col310": "sp242", + "col311": "qdajp", + "col312": "tozc7", + "col313": "7hgss", + "col314": "frxec", + "col315": "2kipp", + "col316": "whq9v", + "col317": "xmjtb", + "col318": "dnnzn", + "col319": "ulyja", + "col320": "cn4jw", + "col321": "03lf5", + "col322": "xr9h4", + "col323": "96wrw", + "col324": "aioa3", + "col325": "42fy4", + "col326": "7pyft", + "col327": "euzps", + "col328": "wfy09", + "col329": "hqmef", + "col330": "30ydj", + "col331": "yvo3m", + "col332": "c02nh", + "col333": "cfqoq", + "col334": "xdfwk", + "col335": "vd7bj", + "col336": "fztb6", + "col337": "3730x", + "col338": "o3uo5", + "col339": "qeuih", + "col340": "ebyyz", + "col341": "gvpga", + "col342": "f5jm5", + "col343": "g1tc1", + "col344": "9i0v7", + "col345": "d6ge5", + "col346": "y3mr3", + "col347": "jv7xo", + "col348": "5eai9", + "col349": "8zmyp", + "col350": "i82bj", + "col351": "cb04f", + "col352": "m59f5", + "col353": "13eds", + "col354": "b5iw4", + "col355": "uwq5c", + "col356": "s16hj", + "col357": "2vcuc", + "col358": "dhn9f", + "col359": "d0om7", + "col360": "rqtzb", + "col361": "hloqp", + "col362": "oulyh", + "col363": "3dpfk", + "col364": "g3hh3", + "col365": "dupwc", + "col366": "hk9hb", + "col367": "fr783", + "col368": "7eh2a", + "col369": "fqbjk", + "col370": "9ytet", + "col371": "x6cbk", + "col372": "72yt5", + "col373": "i77og", + "col374": "ul8nz", + "col375": "a1knb", + "col376": "vxhrf", + "col377": "68ohi", + "col378": "4mple", + "col379": "6nlzz", + "col380": "71ysp", + "col381": "myja8", + "col382": "7fvhy", + "col383": "hxw9s", + "col384": "jk0kq", + "col385": "01sub", + "col386": "jqycv", + "col387": "xt1iw", + "col388": "i26p7", + "col389": "8h46e", + "col390": "cgune", + "col391": "7lcay", + "col392": "xhheb", + "col393": "uptjt", + "col394": "y0ujs", + "col395": "dg2e0", + "col396": "n8mq9", + "col397": "besau", + "col398": "ymsy4", + "col399": "sdgco", + "col400": "49wt0", + "col401": "qxmi9", + "col402": "h4jvq", + "col403": "i1s49", + "col404": "6iv0e", + "col405": "17l2r", + "col406": "as651", + "col407": "yfek9", + "col408": "s5gjo", + "col409": "h073x", + "col410": "ehykd", + "col411": "3714j", + "col412": "r2env", + "col413": "9vr0l", + "col414": "igl5x", + "col415": "qbblo", + "col416": "njne1", + "col417": "uzpcv", + "col418": "6pc9t", + "col419": "3luux", + "col420": "41kmp", + "col421": "h2uz7", + "col422": "tzrrf", + "col423": "qvckl", + "col424": "bxer7", + "col425": "76ziy", + "col426": "ki7k4", + "col427": "05xuw", + "col428": "1etb7", + "col429": "8a637", + "col430": "hmkqp", + "col431": "n6xfs", + "col432": "8bhq7", + "col433": "unn9x", + "col434": "1zu13", + "col435": "88c7d", + "col436": "f9o05", + "col437": "iho0j", + "col438": "mbl7z", + "col439": "ybnjv", + "col440": "m6d72", + "col441": "qtyu6", + "col442": "6655z", + "col443": "bvppa", + "col444": "flkp3", + "col445": "e6g6c", + "col446": "6aw3m", + "col447": "ffdcr", + "col448": "0bqi1", + "col449": "gmsqt", + "col450": "bvb3t", + "col451": "nq59e", + "col452": "4t3an", + "col453": "tmbhd", + "col454": "jeohy", + "col455": "t4x1k", + "col456": "hv7xz", + "col457": "0vnfg", + "col458": "1pgt7", + "col459": "g9qtm", + "col460": "ttzqe", + "col461": "lop28", + "col462": "sgld1", + "col463": "f5uwy", + "col464": "scr47", + "col465": "sh16r", + "col466": "wr7h3", + "col467": "dz9rl", + "col468": "dgbil", + "col469": "1mqvv", + "col470": "sji6k", + "col471": "1kus2", + "col472": "xlroh", + "col473": "66wwn", + "col474": "qswx2", + "col475": "pn4qx", + "col476": "fs0p6", + "col477": "z8ijw", + "col478": "1g8yn", + "col479": "y6rgg", + "col480": "xlpyl", + "col481": "8mhde", + "col482": "8jand", + "col483": "d1cdz", + "col484": "iju19", + "col485": "kqw3v", + "col486": "zfetv", + "col487": "qiyci", + "col488": "caz10", + "col489": "pbvxr", + "col490": "ob2qh", + "col491": "8ek80", + "col492": "2t18j", + "col493": "lm00g", + "col494": "17wcq", + "col495": "gj8t4", + "col496": "sshnh", + "col497": "3dmjq", + "col498": "80yge", + "col499": "d3jjo", + "col500": "t4un2", + "col501": "1x3f7", + "col502": "o3kw3", + "col503": "snt0s", + "col504": "8g5sr", + "col505": "e5vx7", + "col506": "is78k", + "col507": "o0eec", + "col508": "261wp", + "col509": "l6ll9", + "col510": "ds2ws", + "col511": "2k093", + "col512": "714wn", + "col513": "h6fs6", + "col514": "z3epd", + "col515": "o77p4", + "col516": "xs6n7", + "col517": "m6wz8", + "col518": "c7jr8", + "col519": "d3fsi", + "col520": "q5g4x", + "col521": "ittkq", + "col522": "yziwd", + "col523": "oqegk", + "col524": "u7fos", + "col525": "7588u", + "col526": "zmkeh", + "col527": "kd59p", + "col528": "h19vw", + "col529": "l0ucv", + "col530": "ld396", + "col531": "4eqo9", + "col532": "b41nq", + "col533": "jy9l5", + "col534": "gv21p", + "col535": "h07p7", + "col536": "n130h", + "col537": "1jmvq", + "col538": "0sg0m", + "col539": "m1dmt", + "col540": "0gr36", + "col541": "pghap", + "col542": "tthps", + "col543": "crcn0", + "col544": "vgsq0", + "col545": "inzc5", + "col546": "3wocr", + "col547": "pz8ee", + "col548": "txjke", + "col549": "q5h6e", + "col550": "u6jrf", + "col551": "xvstr", + "col552": "jqcn9", + "col553": "z4or5", + "col554": "z8w2f", + "col555": "wm8fh", + "col556": "dwnjk", + "col557": "hxo61", + "col558": "mbksi", + "col559": "5p1ai", + "col560": "vner1", + "col561": "adbhq", + "col562": "smrzq", + "col563": "oaxqn", + "col564": "g2w73", + "col565": "bkr07", + "col566": "rgn6n", + "col567": "5ud5g", + "col568": "5lzu8", + "col569": "j7uyp", + "col570": "c2n6n", + "col571": "gyswk", + "col572": "rdq62", + "col573": "l84te", + "col574": "hmvkw", + "col575": "ib48o", + "col576": "rklg1", + "col577": "49rx6", + "col578": "de2mo", + "col579": "6mred", + "col580": "ks7ka", + "col581": "pnb0n", + "col582": "8zi79", + "col583": "n3gvz", + "col584": "uvvmc", + "col585": "bo1n3", + "col586": "7hcyh", + "col587": "lnnlv", + "col588": "co0sp", + "col589": "bete4", + "col590": "5pzqr", + "col591": "8xd76", + "col592": "3fqgo", + "col593": "41mk6", + "col594": "g5w5i", + "col595": "68i5c", + "col596": "hw985", + "col597": "41zj6", + "col598": "7gi8a", + "col599": "hel5p", + "col600": "n7ag8", + "col601": "wdwpm", + "col602": "z7dnf", + "col603": "puypj", + "col604": "4k6ro", + "col605": "xcd54", + "col606": "oml5g", + "col607": "80co6", + "col608": "ltg3a", + "col609": "gwleq", + "col610": "0xqei", + "col611": "ot5do", + "col612": "tii2p", + "col613": "1lqji", + "col614": "7j6if", + "col615": "3sye6", + "col616": "rvay8", + "col617": "fjlqz", + "col618": "v9n35", + "col619": "javcu", + "col620": "2u527", + "col621": "2czja", + "col622": "23nrb", + "col623": "g6ypv", + "col624": "57usx", + "col625": "1nf5t", + "col626": "mkzi9", + "col627": "ej9tz", + "col628": "rmtbc", + "col629": "wdnjt", + "col630": "3wvka", + "col631": "c50dg", + "col632": "as5gv", + "col633": "e0txo", + "col634": "o86qf", + "col635": "y6qqs", + "col636": "hdak0", + "col637": "g62l2", + "col638": "aq26p", + "col639": "dl6qp", + "col640": "6xjm0", + "col641": "qw38m", + "col642": "lwsr0", + "col643": "o0wki", + "col644": "okcgz", + "col645": "78ax1", + "col646": "fxgtl", + "col647": "nh5ho", + "col648": "sdcx8", + "col649": "fg58i", + "col650": "rwtw2", + "col651": "275jy", + "col652": "sgdhp", + "col653": "9toce", + "col654": "3vj0i", + "col655": "rd7cv", + "col656": "3ksz3", + "col657": "aa125", + "col658": "znd87", + "col659": "gpi4v", + "col660": "dtj08", + "col661": "40q8s", + "col662": "6w6tp", + "col663": "fmioj", + "col664": "e1rbp", + "col665": "8ehjz", + "col666": "sf0pc", + "col667": "qeqo7", + "col668": "rb5f2", + "col669": "eymc2", + "col670": "xs0qz", + "col671": "tqxwc", + "col672": "v9zvm", + "col673": "0hibd", + "col674": "sirr4", + "col675": "sdjs6", + "col676": "u6bz5", + "col677": "6ztdp", + "col678": "2v6ne", + "col679": "6umyr", + "col680": "qvhp7", + "col681": "isnf4", + "col682": "qhtf0", + "col683": "t34lk", + "col684": "et8j5", + "col685": "tzppu", + "col686": "g7936", + "col687": "pg35v", + "col688": "5xan5", + "col689": "yp4py", + "col690": "psqp1", + "col691": "oo9wl", + "col692": "co5ux", + "col693": "5hx8n", + "col694": "qb3dt", + "col695": "1ldl9", + "col696": "0xzdt", + "col697": "4ir20", + "col698": "tkkyt", + "col699": "515gp", + "col700": "mm5m9", + "col701": "0ptgk", + "col702": "wfk0b", + "col703": "qj5rf", + "col704": "dvrks", + "col705": "1k93l", + "col706": "bdayx", + "col707": "5svmx", + "col708": "btset", + "col709": "swep6", + "col710": "70gt9", + "col711": "4qeu7", + "col712": "ly817", + "col713": "9nh8h", + "col714": "s9w1q", + "col715": "qj4v8", + "col716": "7pdxb", + "col717": "i17jq", + "col718": "fv0nw", + "col719": "au6rt", + "col720": "uwf82", + "col721": "ldo2c", + "col722": "hs83y", + "col723": "v14m5", + "col724": "b6pid", + "col725": "ww5tl", + "col726": "r1pri", + "col727": "6rp5y", + "col728": "lj7tl", + "col729": "nmy98", + "col730": "tvfhh", + "col731": "80nxn", + "col732": "beue5", + "col733": "oi2mw", + "col734": "jteu8", + "col735": "ms9xc", + "col736": "7yumi", + "col737": "lyywa", + "col738": "wup4t", + "col739": "jtchj", + "col740": "axcaq", + "col741": "qfbkw", + "col742": "ujie2", + "col743": "unupw", + "col744": "32spn", + "col745": "sgh23", + "col746": "j8kza", + "col747": "hafon", + "col748": "blgn6", + "col749": "prytw", + "col750": "buxrl", + "col751": "n35vv", + "col752": "f2ysf", + "col753": "8vuwx", + "col754": "vt21m", + "col755": "mz1iv", + "col756": "qp7pa", + "col757": "57cjl", + "col758": "lk9fy", + "col759": "a6e4i", + "col760": "75efh", + "col761": "mf4qu", + "col762": "mvtcz", + "col763": "2xb5u", + "col764": "xs5p8", + "col765": "toc5t", + "col766": "apert", + "col767": "sjldh", + "col768": "ptpvu", + "col769": "ftni2", + "col770": "rv5ph", + "col771": "zoqwe", + "col772": "1qmhs", + "col773": "72c8w", + "col774": "waz9d", + "col775": "121jl", + "col776": "isx1h", + "col777": "8ao7q", + "col778": "8vbga", + "col779": "8e0e3", + "col780": "fhft0", + "col781": "0tosi", + "col782": "ct0ky", + "col783": "hlp2h", + "col784": "ppamk", + "col785": "dwg5w", + "col786": "sndfp", + "col787": "dbnwr", + "col788": "pdrkg", + "col789": "6647c", + "col790": "8yry5", + "col791": "gb823", + "col792": "dmh37", + "col793": "zitgo", + "col794": "0fjx8", + "col795": "ahihu", + "col796": "qf65p", + "col797": "iqov5", + "col798": "x42cv", + "col799": "c7sbd", + "col800": "co1do", + "col801": "lbp59", + "col802": "ognme", + "col803": "mdm9h", + "col804": "7flto", + "col805": "b7s03", + "col806": "2dtoc", + "col807": "z1f6t", + "col808": "mo1fv", + "col809": "aqjfu", + "col810": "btz0l", + "col811": "2ksoo", + "col812": "1yfxq", + "col813": "pakqt", + "col814": "r0fio", + "col815": "ubd9l", + "col816": "k97g6", + "col817": "dziek", + "col818": "9ve8t", + "col819": "j5l07", + "col820": "vvh97", + "col821": "nx6xo", + "col822": "285el", + "col823": "k7foc", + "col824": "ruy3d", + "col825": "ef415", + "col826": "o92zd", + "col827": "735h8", + "col828": "li4sw", + "col829": "u36fb", + "col830": "5n03s", + "col831": "dtoav", + "col832": "grgm0", + "col833": "yhbfe", + "col834": "aj2kx", + "col835": "vvf6e", + "col836": "jvi0y", + "col837": "8txhy", + "col838": "dx9iy", + "col839": "5zwzy", + "col840": "102qk", + "col841": "ovdz2", + "col842": "ltorv", + "col843": "vjqyn", + "col844": "re37b", + "col845": "pyvkm", + "col846": "jvjst", + "col847": "bc30u", + "col848": "i50av", + "col849": "a55s1", + "col850": "99y8o", + "col851": "cn16o", + "col852": "nhpoc", + "col853": "nvw12", + "col854": "0gixu", + "col855": "xlht6", + "col856": "mro81", + "col857": "yohb8", + "col858": "kqq4t", + "col859": "gkg8y", + "col860": "11in9", + "col861": "fh402", + "col862": "o269e", + "col863": "3rkw6", + "col864": "1al6t", + "col865": "b6ukz", + "col866": "1x6x9", + "col867": "2axzn", + "col868": "uehtt", + "col869": "7sd60", + "col870": "kafga", + "col871": "kjrz1", + "col872": "9t5dp", + "col873": "dmug4", + "col874": "fy9qr", + "col875": "mdg7d", + "col876": "combq", + "col877": "9om0n", + "col878": "ocgh3", + "col879": "48scm", + "col880": "elvx8", + "col881": "9lpl7", + "col882": "zdvga", + "col883": "tz0d3", + "col884": "ajkdo", + "col885": "8m1sr", + "col886": "7beer", + "col887": "ydgy1", + "col888": "s1j0u", + "col889": "pghpb", + "col890": "yzywi", + "col891": "iv19q", + "col892": "9a1o3", + "col893": "icq61", + "col894": "nphxd", + "col895": "1vqpf", + "col896": "y2bmy", + "col897": "28ckk", + "col898": "7vrpx", + "col899": "0072j", + "col900": "pk24b", + "col901": "2z8bg", + "col902": "k97lm", + "col903": "bds3f", + "col904": "uwdjp", + "col905": "hdq3a", + "col906": "wmkth", + "col907": "zkeax", + "col908": "lrhyj", + "col909": "is8yd", + "col910": "4bdpo", + "col911": "sm2qp", + "col912": "g8p9c", + "col913": "gv8sg", + "col914": "vsvmy", + "col915": "ub9qi", + "col916": "uutsl", + "col917": "j6at0", + "col918": "32wn0", + "col919": "5y9pp", + "col920": "vd37o", + "col921": "97ufe", + "col922": "w1zl5", + "col923": "91561", + "col924": "3fzsv", + "col925": "giy1m", + "col926": "fbgpo", + "col927": "y8a19", + "col928": "kvma9", + "col929": "ybu6r", + "col930": "t7h5x", + "col931": "auilt", + "col932": "a7gel", + "col933": "ommuh", + "col934": "krhj1", + "col935": "oagby", + "col936": "u00ve", + "col937": "uffft", + "col938": "e9eyv", + "col939": "bm3v7", + "col940": "72xxs", + "col941": "763o9", + "col942": "ad3o9", + "col943": "8hjew", + "col944": "hnrbv", + "col945": "njnim", + "col946": "2m7uo", + "col947": "7xngo", + "col948": "xm64t", + "col949": "spv1b", + "col950": "g1dg2", + "col951": "0xavo", + "col952": "3tcvd", + "col953": "o6zdq", + "col954": "u6awt", + "col955": "auicd", + "col956": "kigqp", + "col957": "a98ol", + "col958": "rc3el", + "col959": "8cbm4", + "col960": "qewu1", + "col961": "1jg5r", + "col962": "tfk7s", + "col963": "0lifb", + "col964": "8mrp7", + "col965": "ax2bu", + "col966": "qs3ij", + "col967": "3vwuk", + "col968": "jctlw", + "col969": "ogll4", + "col970": "mp58y", + "col971": "2aj8q", + "col972": "hy7fd", + "col973": "tpcug", + "col974": "vrz0a", + "col975": "bopzj", + "col976": "mi2w6", + "col977": "wurg8", + "col978": "ozbgs", + "col979": "25ui2", + "col980": "t2spj", + "col981": "3yzht", + "col982": "pbpex", + "col983": "3n8h9", + "col984": "zecxq", + "col985": "m8g9p", + "col986": "jiqly", + "col987": "tf6g8", + "col988": "3ai9c", + "col989": "su2bd", + "col990": "d7hri", + "col991": "ixtwy", + "col992": "w2v99", + "col993": "xy2e8", + "col994": "2ilk0", + "col995": "4x9rh", + "col996": "mo4zd", + "col997": "o22yq", + "col998": "zzbct", + "col999": "1t059" + }, + { + "name": "Kasey Beach", + "gender": "female", + "col0": "07nyp", + "col1": "x2t7w", + "col2": "moe6y", + "col3": "5ukoz", + "col4": "qrm3u", + "col5": "b26kr", + "col6": "l5l6x", + "col7": "aul3p", + "col8": "4kz70", + "col9": "w5le0", + "col10": "g5p5n", + "col11": "z40rm", + "col12": "3k0ku", + "col13": "6xkgo", + "col14": "n84ds", + "col15": "34gez", + "col16": "fl11s", + "col17": "08xrt", + "col18": "vbxli", + "col19": "hd90c", + "col20": "ssbx3", + "col21": "vb610", + "col22": "tut47", + "col23": "afyej", + "col24": "smqqf", + "col25": "1qm8d", + "col26": "mnxe0", + "col27": "36ul2", + "col28": "bven8", + "col29": "fqclm", + "col30": "iqrgh", + "col31": "lqgse", + "col32": "q8yq4", + "col33": "pi865", + "col34": "mtwr5", + "col35": "w8tra", + "col36": "yvisg", + "col37": "wsgzn", + "col38": "04z2s", + "col39": "ji356", + "col40": "tfjsz", + "col41": "0l47y", + "col42": "nvnv5", + "col43": "u643w", + "col44": "0tgtb", + "col45": "kdfjm", + "col46": "6d95t", + "col47": "dlicr", + "col48": "lg8be", + "col49": "6srfb", + "col50": "6y81v", + "col51": "0e4je", + "col52": "appnw", + "col53": "nke5o", + "col54": "ekzps", + "col55": "nroru", + "col56": "oz3hh", + "col57": "amoer", + "col58": "rlqo5", + "col59": "o8mlz", + "col60": "1s8jm", + "col61": "ox88g", + "col62": "w3a82", + "col63": "wwxam", + "col64": "ib0bo", + "col65": "7lv9c", + "col66": "liaeh", + "col67": "ckkry", + "col68": "stef3", + "col69": "qzicr", + "col70": "5joh8", + "col71": "2phxa", + "col72": "d61a5", + "col73": "mcwp9", + "col74": "agfkj", + "col75": "kgqdu", + "col76": "jb0gz", + "col77": "d58q1", + "col78": "0jdg7", + "col79": "8f675", + "col80": "vw3eo", + "col81": "s64ri", + "col82": "xks89", + "col83": "apcqc", + "col84": "3o4dr", + "col85": "rkbiz", + "col86": "15ha5", + "col87": "k3x2p", + "col88": "9vilq", + "col89": "mi5t3", + "col90": "lfxg4", + "col91": "sog81", + "col92": "mh9z2", + "col93": "9hz4d", + "col94": "cgn8m", + "col95": "2yg3f", + "col96": "tj4m0", + "col97": "ucsbx", + "col98": "07rg5", + "col99": "gpurr", + "col100": "s2kpe", + "col101": "f1g8y", + "col102": "9asv6", + "col103": "xp64v", + "col104": "zakrw", + "col105": "nxg9g", + "col106": "js7ar", + "col107": "9s4ye", + "col108": "2zqm9", + "col109": "4rcua", + "col110": "yn0dt", + "col111": "gdye4", + "col112": "9ia8y", + "col113": "cb6i2", + "col114": "mzwty", + "col115": "k0j75", + "col116": "uwkbo", + "col117": "4mykl", + "col118": "0w37q", + "col119": "qav2t", + "col120": "r8fqu", + "col121": "fatu7", + "col122": "whefp", + "col123": "kkma6", + "col124": "abhsz", + "col125": "4l90p", + "col126": "0xkeh", + "col127": "d2ojz", + "col128": "hi016", + "col129": "s9gxa", + "col130": "xxh3i", + "col131": "ltc28", + "col132": "dbkoa", + "col133": "49oaa", + "col134": "59mj8", + "col135": "roehs", + "col136": "hctfc", + "col137": "hx83l", + "col138": "3ed4t", + "col139": "bdc12", + "col140": "bbzrm", + "col141": "ezsfc", + "col142": "4ixiv", + "col143": "xe7nn", + "col144": "h3my7", + "col145": "61iup", + "col146": "hx3ha", + "col147": "8n1s8", + "col148": "4qtnd", + "col149": "jpfuq", + "col150": "86ev2", + "col151": "04b7w", + "col152": "ffnbc", + "col153": "g2mg7", + "col154": "46gss", + "col155": "id8xc", + "col156": "0a7d1", + "col157": "qimcy", + "col158": "6ufq0", + "col159": "hn1t7", + "col160": "4603r", + "col161": "0k5fz", + "col162": "y0c5y", + "col163": "12t46", + "col164": "tsx92", + "col165": "kfnrv", + "col166": "z7phc", + "col167": "s83og", + "col168": "05nb6", + "col169": "4j02f", + "col170": "pvqcr", + "col171": "exh8j", + "col172": "h5o7x", + "col173": "5ttl2", + "col174": "bbpnp", + "col175": "eewey", + "col176": "znuzf", + "col177": "bs8oo", + "col178": "l70kk", + "col179": "68g5k", + "col180": "rp19k", + "col181": "etuse", + "col182": "qt4zx", + "col183": "70g63", + "col184": "hkd8g", + "col185": "toeu0", + "col186": "cuc7n", + "col187": "gohdp", + "col188": "ag2ru", + "col189": "ur0cb", + "col190": "zfabd", + "col191": "q17c8", + "col192": "vz5wk", + "col193": "dbcjd", + "col194": "unf3u", + "col195": "9dcqu", + "col196": "lup6k", + "col197": "e7c0y", + "col198": "6spqh", + "col199": "kusvq", + "col200": "13j6c", + "col201": "6jq0r", + "col202": "do3l3", + "col203": "4folg", + "col204": "k9ijy", + "col205": "7g4yb", + "col206": "r4sli", + "col207": "95h1f", + "col208": "5yjj5", + "col209": "okbgf", + "col210": "pn9u5", + "col211": "ky39v", + "col212": "u0sg6", + "col213": "uuo25", + "col214": "39izl", + "col215": "isyx2", + "col216": "y06d7", + "col217": "ffhq0", + "col218": "76lud", + "col219": "j5uau", + "col220": "clf8p", + "col221": "cq4nh", + "col222": "iu7ee", + "col223": "3g8d2", + "col224": "qoysl", + "col225": "4vfff", + "col226": "dh463", + "col227": "h59n4", + "col228": "d54uu", + "col229": "46hb5", + "col230": "o7k0z", + "col231": "nbzet", + "col232": "yp6xk", + "col233": "3tkr7", + "col234": "00ywu", + "col235": "uspyd", + "col236": "icdes", + "col237": "dz2kd", + "col238": "9j3vn", + "col239": "emsqv", + "col240": "9tt7u", + "col241": "8bo53", + "col242": "99pfj", + "col243": "ra7t0", + "col244": "gg8xu", + "col245": "rcqvk", + "col246": "79w0q", + "col247": "p7jsy", + "col248": "4qdjt", + "col249": "1xkbt", + "col250": "r55xd", + "col251": "ftl7b", + "col252": "qla7h", + "col253": "sdhfc", + "col254": "h394t", + "col255": "yy1g8", + "col256": "rf9i2", + "col257": "h6ddb", + "col258": "e1nps", + "col259": "s4xuq", + "col260": "zu09y", + "col261": "xsmr5", + "col262": "7og3v", + "col263": "b9o1c", + "col264": "gnia0", + "col265": "8qx8s", + "col266": "hqh5g", + "col267": "xac94", + "col268": "9y5xe", + "col269": "kshsr", + "col270": "y08d7", + "col271": "ihrvz", + "col272": "qodlj", + "col273": "0yhqc", + "col274": "cyqi7", + "col275": "514i7", + "col276": "fh52f", + "col277": "6qmja", + "col278": "drktm", + "col279": "ahqh6", + "col280": "o5o75", + "col281": "xh4sf", + "col282": "3ocog", + "col283": "b8ei2", + "col284": "dlj4p", + "col285": "rtr57", + "col286": "6e5sh", + "col287": "ogqwz", + "col288": "8y8e5", + "col289": "scuej", + "col290": "mhs0l", + "col291": "uxr5w", + "col292": "qkh9s", + "col293": "zh9g7", + "col294": "png0w", + "col295": "gd5a2", + "col296": "bj7de", + "col297": "kog0b", + "col298": "rux8j", + "col299": "m2w49", + "col300": "jw5ys", + "col301": "pw3wo", + "col302": "1gibr", + "col303": "n38hz", + "col304": "gc0zu", + "col305": "24jcp", + "col306": "m7uuv", + "col307": "w8ty5", + "col308": "g9qqb", + "col309": "utjqp", + "col310": "dblyd", + "col311": "49q7y", + "col312": "zdof2", + "col313": "v37l4", + "col314": "hndz8", + "col315": "wjq8c", + "col316": "1qu7r", + "col317": "xp73c", + "col318": "s62e4", + "col319": "3yu3g", + "col320": "vtq9p", + "col321": "5e42k", + "col322": "9ws4q", + "col323": "ct6k5", + "col324": "kwoxz", + "col325": "kcpyc", + "col326": "t1o5v", + "col327": "mxpfi", + "col328": "mcmex", + "col329": "k11qp", + "col330": "xtby3", + "col331": "w8cc4", + "col332": "aixhr", + "col333": "fey8u", + "col334": "u60a3", + "col335": "pacxd", + "col336": "wgpbg", + "col337": "tj3pw", + "col338": "jdjjb", + "col339": "7049a", + "col340": "bfrov", + "col341": "c2bkr", + "col342": "o5lg4", + "col343": "8tig1", + "col344": "pchq0", + "col345": "d0h30", + "col346": "l3vkl", + "col347": "4mk3w", + "col348": "xhb7g", + "col349": "j2tiw", + "col350": "yoaun", + "col351": "gfini", + "col352": "d04ww", + "col353": "aeyka", + "col354": "cmv3g", + "col355": "kiziy", + "col356": "znpie", + "col357": "wsgvq", + "col358": "vc6qz", + "col359": "af73n", + "col360": "xkrm8", + "col361": "qp88t", + "col362": "d6gdr", + "col363": "itixv", + "col364": "3v1jb", + "col365": "sf8j7", + "col366": "u2ekt", + "col367": "zjw8o", + "col368": "9k6ve", + "col369": "wq0fj", + "col370": "qud4c", + "col371": "jtq6m", + "col372": "6jrla", + "col373": "5h4cy", + "col374": "d7je3", + "col375": "tzsl1", + "col376": "ut6dw", + "col377": "nzywo", + "col378": "5pn5x", + "col379": "hn87y", + "col380": "enstp", + "col381": "hi45o", + "col382": "bwwup", + "col383": "e1dg7", + "col384": "mm68s", + "col385": "0pwzn", + "col386": "qjnag", + "col387": "ty1k8", + "col388": "56ehj", + "col389": "g6ruf", + "col390": "ipthl", + "col391": "s4qb6", + "col392": "jnxtc", + "col393": "hvgg4", + "col394": "7b9yw", + "col395": "cqcos", + "col396": "ere9y", + "col397": "pf472", + "col398": "49g4e", + "col399": "b8sf9", + "col400": "w088p", + "col401": "l9hvc", + "col402": "u157v", + "col403": "uqy50", + "col404": "da6ou", + "col405": "1jetv", + "col406": "o4njt", + "col407": "s2tsc", + "col408": "w2g44", + "col409": "vnwyc", + "col410": "gnx2w", + "col411": "rnq4e", + "col412": "0qrs0", + "col413": "u2uqn", + "col414": "yax3f", + "col415": "s03eu", + "col416": "wrjht", + "col417": "cvxih", + "col418": "0y5my", + "col419": "7kmjf", + "col420": "sx2sn", + "col421": "d2hhg", + "col422": "4geqo", + "col423": "nymf3", + "col424": "1fy85", + "col425": "10yl1", + "col426": "n7ysa", + "col427": "qnz1z", + "col428": "p1sw9", + "col429": "a786k", + "col430": "xpby4", + "col431": "7uip7", + "col432": "f8lbb", + "col433": "ld982", + "col434": "imioh", + "col435": "6ry0n", + "col436": "ap11o", + "col437": "y11wl", + "col438": "mtr8a", + "col439": "ypuf0", + "col440": "jbgq2", + "col441": "107ik", + "col442": "mp4z2", + "col443": "pv5se", + "col444": "b0lij", + "col445": "jxhrs", + "col446": "ys5ib", + "col447": "z135n", + "col448": "p4xt8", + "col449": "9gpwi", + "col450": "ypuf6", + "col451": "4oqvs", + "col452": "ufq5p", + "col453": "hx4ca", + "col454": "suv48", + "col455": "cr7li", + "col456": "kdz8b", + "col457": "dnlmp", + "col458": "rsbff", + "col459": "jmdlz", + "col460": "3dzq2", + "col461": "dobri", + "col462": "oehjt", + "col463": "3mq7z", + "col464": "v6kcf", + "col465": "y3tyv", + "col466": "27fmh", + "col467": "go6a9", + "col468": "q0cny", + "col469": "b7d07", + "col470": "0872c", + "col471": "jkz0i", + "col472": "81t0j", + "col473": "4otqs", + "col474": "m4up5", + "col475": "p4g2y", + "col476": "gyqod", + "col477": "ye9l8", + "col478": "08m6v", + "col479": "uvm3f", + "col480": "aepo0", + "col481": "xn0m8", + "col482": "dyy8w", + "col483": "kju2s", + "col484": "umqpr", + "col485": "95x4r", + "col486": "p6hf7", + "col487": "lns7l", + "col488": "ne6v4", + "col489": "g8t1m", + "col490": "yma6s", + "col491": "xah59", + "col492": "dsfac", + "col493": "9zkli", + "col494": "vhbq6", + "col495": "od4a9", + "col496": "pyiqv", + "col497": "uwihp", + "col498": "c6k3h", + "col499": "f4qo9", + "col500": "bqs1h", + "col501": "2pzhc", + "col502": "ys1zz", + "col503": "dja08", + "col504": "bzi2h", + "col505": "3e6pc", + "col506": "rdi7w", + "col507": "6moc9", + "col508": "s27fr", + "col509": "40slt", + "col510": "kwgcn", + "col511": "cz96t", + "col512": "zhuz9", + "col513": "40dax", + "col514": "h9z6z", + "col515": "ck6hv", + "col516": "mt3og", + "col517": "flmrr", + "col518": "3t6v3", + "col519": "rihkl", + "col520": "8pj0w", + "col521": "n2mg9", + "col522": "w21ts", + "col523": "wywjw", + "col524": "91kxw", + "col525": "slpox", + "col526": "uaq6z", + "col527": "8frh4", + "col528": "4rutq", + "col529": "4zgkv", + "col530": "qi006", + "col531": "nhzcr", + "col532": "lroq9", + "col533": "5abqq", + "col534": "hzkhe", + "col535": "o2x5o", + "col536": "yalri", + "col537": "zow9t", + "col538": "p8yrc", + "col539": "g8hr0", + "col540": "g0uw5", + "col541": "vzs5r", + "col542": "f98w8", + "col543": "wu25j", + "col544": "ap71y", + "col545": "8ksq8", + "col546": "fgi3v", + "col547": "s37h7", + "col548": "bw7dp", + "col549": "fmu8u", + "col550": "r0xzz", + "col551": "5mc18", + "col552": "aqxl2", + "col553": "crxfk", + "col554": "t8nnu", + "col555": "v3gsz", + "col556": "7g3ja", + "col557": "524dk", + "col558": "od5qs", + "col559": "zagqj", + "col560": "ulc4o", + "col561": "0ixnw", + "col562": "yf322", + "col563": "g7w5n", + "col564": "duj4e", + "col565": "bsx5b", + "col566": "vixcg", + "col567": "7etb7", + "col568": "da0rj", + "col569": "z9zl1", + "col570": "53suf", + "col571": "gb2w3", + "col572": "8eb6e", + "col573": "874vo", + "col574": "0txe6", + "col575": "zrv2f", + "col576": "w5go1", + "col577": "bj8yx", + "col578": "6nc5c", + "col579": "ic8bp", + "col580": "3375l", + "col581": "otyyz", + "col582": "24nf2", + "col583": "7so66", + "col584": "8xn90", + "col585": "0jhba", + "col586": "pl3pp", + "col587": "q3rvt", + "col588": "opokh", + "col589": "0euwu", + "col590": "r26pk", + "col591": "z5wip", + "col592": "e4uou", + "col593": "y8i6c", + "col594": "xvbt0", + "col595": "6v3h4", + "col596": "vyako", + "col597": "0to7b", + "col598": "aqkdq", + "col599": "iacpt", + "col600": "ro5ys", + "col601": "8j80m", + "col602": "96f2a", + "col603": "ui8x9", + "col604": "8uxvd", + "col605": "mas6b", + "col606": "56si8", + "col607": "tshvi", + "col608": "lrsx0", + "col609": "7tcy5", + "col610": "i9w4d", + "col611": "ehzkg", + "col612": "3js3s", + "col613": "nv7e7", + "col614": "w1xj0", + "col615": "o0qq4", + "col616": "llosu", + "col617": "t1iz7", + "col618": "seary", + "col619": "xbe7b", + "col620": "zwew1", + "col621": "pslij", + "col622": "8b71q", + "col623": "gf6xb", + "col624": "rk3ci", + "col625": "7b7sc", + "col626": "7wiiz", + "col627": "09py2", + "col628": "73amf", + "col629": "un9hg", + "col630": "4cp11", + "col631": "vckix", + "col632": "7biyc", + "col633": "ai7ow", + "col634": "ypsk0", + "col635": "neuau", + "col636": "omb7b", + "col637": "3p011", + "col638": "8h700", + "col639": "1phlh", + "col640": "av003", + "col641": "1h9ij", + "col642": "lwa6c", + "col643": "fhmwb", + "col644": "2usm9", + "col645": "qz35h", + "col646": "3inik", + "col647": "w2do4", + "col648": "upbeb", + "col649": "l9r1d", + "col650": "io1bl", + "col651": "v6d8u", + "col652": "tzww2", + "col653": "ljdh7", + "col654": "vr4v1", + "col655": "wdj4z", + "col656": "6sr33", + "col657": "zyjxv", + "col658": "gkx06", + "col659": "k5hd4", + "col660": "g0phl", + "col661": "rajtz", + "col662": "o135s", + "col663": "awynn", + "col664": "je6ji", + "col665": "91zko", + "col666": "w5kf4", + "col667": "9vkej", + "col668": "ri51u", + "col669": "77nfd", + "col670": "eiv19", + "col671": "mo4pc", + "col672": "u40cb", + "col673": "y1xca", + "col674": "9fazj", + "col675": "3igf1", + "col676": "3tbq8", + "col677": "rfcre", + "col678": "f5mu7", + "col679": "0k1hu", + "col680": "2t502", + "col681": "7nbhz", + "col682": "o1r5t", + "col683": "1ru2y", + "col684": "38yos", + "col685": "z7il9", + "col686": "7lpbq", + "col687": "mxsny", + "col688": "c4jij", + "col689": "s1vzz", + "col690": "jxj6m", + "col691": "56ab9", + "col692": "mntiz", + "col693": "sguqb", + "col694": "kcx6e", + "col695": "q1hln", + "col696": "0ukv3", + "col697": "ufber", + "col698": "702j3", + "col699": "kemwo", + "col700": "ycn9j", + "col701": "r1ywq", + "col702": "3paox", + "col703": "7bp7d", + "col704": "2p99h", + "col705": "8qm6v", + "col706": "hbggo", + "col707": "86xo6", + "col708": "fynqp", + "col709": "bhv7p", + "col710": "jhuya", + "col711": "e9ci4", + "col712": "gym96", + "col713": "3rjfq", + "col714": "578kq", + "col715": "sl0tz", + "col716": "gypxm", + "col717": "6w1mi", + "col718": "nhab6", + "col719": "6jqzy", + "col720": "cdrsl", + "col721": "hnida", + "col722": "um65x", + "col723": "l6tee", + "col724": "41w5p", + "col725": "02qan", + "col726": "vqpsy", + "col727": "qkxvm", + "col728": "olxah", + "col729": "rcpb2", + "col730": "cxbjv", + "col731": "9oheu", + "col732": "imfm7", + "col733": "kb76q", + "col734": "901z4", + "col735": "74wyq", + "col736": "d42de", + "col737": "pbg2b", + "col738": "8sqyd", + "col739": "k5wi3", + "col740": "xqi5e", + "col741": "49gmq", + "col742": "thj5z", + "col743": "75re7", + "col744": "2inq9", + "col745": "1lsor", + "col746": "lq024", + "col747": "6lt62", + "col748": "1rrkd", + "col749": "p7rbg", + "col750": "d52ok", + "col751": "ov3x7", + "col752": "5883z", + "col753": "otmpn", + "col754": "9kpwt", + "col755": "wtkcz", + "col756": "p8b2l", + "col757": "kqn1f", + "col758": "mbw4a", + "col759": "d1jqv", + "col760": "yuj0f", + "col761": "w2b41", + "col762": "rrcs1", + "col763": "nhs8z", + "col764": "gbrxl", + "col765": "2bzbc", + "col766": "2ymln", + "col767": "qm1c9", + "col768": "a7xn4", + "col769": "2062s", + "col770": "y6wgk", + "col771": "w0qch", + "col772": "863qd", + "col773": "su6xr", + "col774": "nqj3q", + "col775": "mriot", + "col776": "q50lk", + "col777": "o82vv", + "col778": "kv7s2", + "col779": "39bee", + "col780": "62ttg", + "col781": "xkaz8", + "col782": "pogkp", + "col783": "dpral", + "col784": "pssrn", + "col785": "x0g8j", + "col786": "89vjl", + "col787": "mdt2b", + "col788": "67aks", + "col789": "gtnod", + "col790": "khyks", + "col791": "0fnh6", + "col792": "ag4fv", + "col793": "fbcb3", + "col794": "vrh4h", + "col795": "17g2q", + "col796": "kf990", + "col797": "ox4tb", + "col798": "klb3g", + "col799": "s017d", + "col800": "er26p", + "col801": "fl37c", + "col802": "yh1ix", + "col803": "c1555", + "col804": "teumm", + "col805": "c7dyg", + "col806": "lv5nu", + "col807": "9s9j2", + "col808": "bvf6n", + "col809": "6nzlc", + "col810": "poe20", + "col811": "c3msg", + "col812": "vpdvn", + "col813": "2wh5d", + "col814": "x8urm", + "col815": "9uwdl", + "col816": "sykwm", + "col817": "zmgv9", + "col818": "c9eyq", + "col819": "lvftg", + "col820": "yst7i", + "col821": "p8zsg", + "col822": "028vt", + "col823": "ka0ax", + "col824": "g2r2t", + "col825": "4nt76", + "col826": "8x84y", + "col827": "mfz3p", + "col828": "uixgd", + "col829": "rbuxs", + "col830": "ri4bd", + "col831": "21g6o", + "col832": "ezhgp", + "col833": "7x0gi", + "col834": "dwc0l", + "col835": "fe0t2", + "col836": "79f8s", + "col837": "c0xod", + "col838": "lx6ie", + "col839": "ulgl6", + "col840": "nj6z2", + "col841": "ppuct", + "col842": "h08ee", + "col843": "khb0n", + "col844": "o83nt", + "col845": "yciin", + "col846": "hb2dy", + "col847": "n1v5d", + "col848": "ul5vg", + "col849": "6dkn3", + "col850": "em4p1", + "col851": "p5so9", + "col852": "tcq2j", + "col853": "z925i", + "col854": "vs2z9", + "col855": "8zlix", + "col856": "xz7cx", + "col857": "x8rlv", + "col858": "vxplx", + "col859": "hmtq8", + "col860": "m5yty", + "col861": "hcmpo", + "col862": "i4cyt", + "col863": "zk2jb", + "col864": "8n5tv", + "col865": "0eeax", + "col866": "57bw4", + "col867": "yb0gt", + "col868": "rq6if", + "col869": "suai3", + "col870": "4v9t0", + "col871": "8a70k", + "col872": "v4znp", + "col873": "5yejc", + "col874": "ev556", + "col875": "p71b5", + "col876": "2w0gz", + "col877": "918r3", + "col878": "g5r5o", + "col879": "ub0qa", + "col880": "0mlwl", + "col881": "tcf5u", + "col882": "ebgzz", + "col883": "w67iz", + "col884": "jgdw3", + "col885": "856z1", + "col886": "anp3l", + "col887": "jxc0d", + "col888": "sw3do", + "col889": "dm1x0", + "col890": "bm5dg", + "col891": "g2ij9", + "col892": "7cz5w", + "col893": "8yggv", + "col894": "2jsqd", + "col895": "lpfj1", + "col896": "r8a3m", + "col897": "o5iyo", + "col898": "otlhw", + "col899": "redme", + "col900": "c82e9", + "col901": "7lo03", + "col902": "j1dxs", + "col903": "6bcv6", + "col904": "j3n3g", + "col905": "t88k1", + "col906": "22kd9", + "col907": "ezr3i", + "col908": "xsimw", + "col909": "kax31", + "col910": "45m1p", + "col911": "90qna", + "col912": "a1k0e", + "col913": "7hdpc", + "col914": "npn5g", + "col915": "24tjd", + "col916": "nbaml", + "col917": "68umj", + "col918": "s3ec0", + "col919": "j9moq", + "col920": "z5abj", + "col921": "ttbyw", + "col922": "plfg4", + "col923": "7c9iz", + "col924": "uc021", + "col925": "zfgwg", + "col926": "t76md", + "col927": "n0v5n", + "col928": "8f12a", + "col929": "8x040", + "col930": "q3g6i", + "col931": "lwc8g", + "col932": "ov0om", + "col933": "bwyob", + "col934": "p9be0", + "col935": "4eckb", + "col936": "wgp1w", + "col937": "sq1p0", + "col938": "i4q7p", + "col939": "3enia", + "col940": "ki1wm", + "col941": "nfgy6", + "col942": "cub8p", + "col943": "fsyma", + "col944": "r1gkn", + "col945": "4lx9u", + "col946": "9gk81", + "col947": "i6lzl", + "col948": "uo418", + "col949": "uiog7", + "col950": "4mfws", + "col951": "lx054", + "col952": "rrabv", + "col953": "o1jr8", + "col954": "uxgu0", + "col955": "4ieu2", + "col956": "baj0z", + "col957": "fe01u", + "col958": "o3o9f", + "col959": "dzbop", + "col960": "a67h0", + "col961": "f63ex", + "col962": "n5q07", + "col963": "9ugpp", + "col964": "it6yn", + "col965": "9s5uw", + "col966": "wu01y", + "col967": "rlugk", + "col968": "q6ngc", + "col969": "fn5ge", + "col970": "j530a", + "col971": "62iex", + "col972": "le2y3", + "col973": "t3qtt", + "col974": "d3rnx", + "col975": "hcm7s", + "col976": "5k0t9", + "col977": "5pwhg", + "col978": "40epo", + "col979": "j0g0v", + "col980": "ozty5", + "col981": "hbitk", + "col982": "cq5iu", + "col983": "wpav7", + "col984": "5fek3", + "col985": "elohm", + "col986": "2i0gg", + "col987": "wft52", + "col988": "qxm3v", + "col989": "exuuj", + "col990": "9qeoj", + "col991": "ibsn7", + "col992": "1mp4j", + "col993": "9tp88", + "col994": "izc4u", + "col995": "hx9zg", + "col996": "vgcr0", + "col997": "rtqp9", + "col998": "h9cnm", + "col999": "pddpj" + }, + { + "name": "Webster Floyd", + "gender": "male", + "col0": "t6afv", + "col1": "vi7xe", + "col2": "ng2yy", + "col3": "o0r5u", + "col4": "goy5g", + "col5": "2grui", + "col6": "p71s7", + "col7": "rwj4t", + "col8": "kxqzp", + "col9": "40d3n", + "col10": "36ja7", + "col11": "2m6yu", + "col12": "5mujt", + "col13": "0dg23", + "col14": "qk2ns", + "col15": "w5zqf", + "col16": "71ein", + "col17": "1vxa2", + "col18": "98u9y", + "col19": "3aa94", + "col20": "vpbkp", + "col21": "9pkc1", + "col22": "fupq2", + "col23": "ei0qh", + "col24": "7w837", + "col25": "e53sc", + "col26": "s6ebr", + "col27": "a3ky0", + "col28": "l4xps", + "col29": "tatsq", + "col30": "bj8dd", + "col31": "gr9rr", + "col32": "fi67g", + "col33": "zhu62", + "col34": "s63ds", + "col35": "hvv7x", + "col36": "aczxj", + "col37": "n8zpp", + "col38": "w65s1", + "col39": "gxda9", + "col40": "zaidg", + "col41": "7kpqd", + "col42": "a0ry3", + "col43": "gmmx1", + "col44": "69qt1", + "col45": "hgewx", + "col46": "2t2vb", + "col47": "apuxa", + "col48": "wjird", + "col49": "kupeg", + "col50": "f15g0", + "col51": "d9qlt", + "col52": "pti42", + "col53": "95dss", + "col54": "hd9a4", + "col55": "p410n", + "col56": "pv1qw", + "col57": "pz260", + "col58": "wrs51", + "col59": "yt53h", + "col60": "lfs6p", + "col61": "drrml", + "col62": "6yudv", + "col63": "khf31", + "col64": "jou65", + "col65": "wxf6t", + "col66": "gas33", + "col67": "n083p", + "col68": "cmtqh", + "col69": "j0nks", + "col70": "9qlsf", + "col71": "qwcq9", + "col72": "wmxz2", + "col73": "gb9zy", + "col74": "btu20", + "col75": "3cytc", + "col76": "r1871", + "col77": "18g82", + "col78": "62z26", + "col79": "sr5en", + "col80": "9fih7", + "col81": "gzteb", + "col82": "xp2xx", + "col83": "d7pke", + "col84": "k79ap", + "col85": "fylsf", + "col86": "uroqr", + "col87": "fqfl2", + "col88": "5ksw0", + "col89": "lohro", + "col90": "98wa3", + "col91": "qdchj", + "col92": "qs4sz", + "col93": "i8d4w", + "col94": "vcz2z", + "col95": "gvx8w", + "col96": "1de4t", + "col97": "a8fzb", + "col98": "ow1dn", + "col99": "j3e6y", + "col100": "ucqce", + "col101": "glxpr", + "col102": "ggzii", + "col103": "kpqbm", + "col104": "b3kwv", + "col105": "ukqia", + "col106": "o6fch", + "col107": "egvi1", + "col108": "vmtae", + "col109": "uo09k", + "col110": "1n849", + "col111": "wa5rv", + "col112": "z21rl", + "col113": "9rwf0", + "col114": "evftd", + "col115": "6v2sc", + "col116": "gma8r", + "col117": "all8v", + "col118": "aoymm", + "col119": "pxbs7", + "col120": "lrvw9", + "col121": "fwnwb", + "col122": "ehxxb", + "col123": "babgq", + "col124": "37oe3", + "col125": "8biae", + "col126": "6nidu", + "col127": "9thsd", + "col128": "phuxa", + "col129": "007lx", + "col130": "zhhxq", + "col131": "up3bs", + "col132": "ca4p7", + "col133": "5xgp0", + "col134": "5u5hs", + "col135": "macas", + "col136": "hy7gt", + "col137": "u9bh5", + "col138": "1vxx0", + "col139": "pr9jy", + "col140": "7smoq", + "col141": "n1ryn", + "col142": "st0aa", + "col143": "mkjkv", + "col144": "ermp9", + "col145": "4m6rn", + "col146": "ihmgl", + "col147": "p8lhq", + "col148": "fs44u", + "col149": "db9c4", + "col150": "4f1dt", + "col151": "zi80t", + "col152": "jva9d", + "col153": "ncscn", + "col154": "zm8eu", + "col155": "39ih1", + "col156": "mn5wv", + "col157": "foaj4", + "col158": "49hv5", + "col159": "q3e0x", + "col160": "dxtdz", + "col161": "ttrhr", + "col162": "snt1l", + "col163": "7jcsi", + "col164": "9m39c", + "col165": "giyvd", + "col166": "h1dra", + "col167": "0ndre", + "col168": "2og5f", + "col169": "jt0bo", + "col170": "ygeuv", + "col171": "cmle7", + "col172": "d4yb2", + "col173": "5iwai", + "col174": "3dll4", + "col175": "6k24c", + "col176": "zxeu4", + "col177": "v9tvs", + "col178": "mdnqp", + "col179": "vwzwk", + "col180": "5pwwz", + "col181": "0gdey", + "col182": "hpy88", + "col183": "wwhk6", + "col184": "oj033", + "col185": "w36bt", + "col186": "8kuaj", + "col187": "iwv6v", + "col188": "ue9gi", + "col189": "hj72k", + "col190": "pv0e6", + "col191": "dtmwj", + "col192": "i92f0", + "col193": "6iokk", + "col194": "tu1vg", + "col195": "d2vvc", + "col196": "mybpv", + "col197": "1oqn5", + "col198": "b14gt", + "col199": "tp2f5", + "col200": "pskk7", + "col201": "uwid5", + "col202": "ool0f", + "col203": "5lre3", + "col204": "pfpmq", + "col205": "kq6m9", + "col206": "deoy1", + "col207": "ydxye", + "col208": "3l6or", + "col209": "zi0p3", + "col210": "x5bno", + "col211": "opqbh", + "col212": "whkxn", + "col213": "fkned", + "col214": "b4vod", + "col215": "rpaxn", + "col216": "mrenv", + "col217": "i2ods", + "col218": "qx60m", + "col219": "137a6", + "col220": "hlme7", + "col221": "ia9js", + "col222": "cvya3", + "col223": "eh6f0", + "col224": "z1vd0", + "col225": "2eamq", + "col226": "d0th5", + "col227": "2u9q8", + "col228": "4reo2", + "col229": "64gwz", + "col230": "y3at7", + "col231": "or18g", + "col232": "r5uz7", + "col233": "oeoup", + "col234": "s8o1a", + "col235": "2qt9s", + "col236": "xzaiv", + "col237": "epjyx", + "col238": "0cpvy", + "col239": "f6okq", + "col240": "xjvi3", + "col241": "qrlif", + "col242": "qb9mq", + "col243": "0royb", + "col244": "if39r", + "col245": "ubqqj", + "col246": "skq2a", + "col247": "uti3x", + "col248": "lrqk7", + "col249": "qjci1", + "col250": "e6xg8", + "col251": "db8lk", + "col252": "6hf39", + "col253": "zot4u", + "col254": "ndozm", + "col255": "sqqms", + "col256": "9fdqh", + "col257": "tmvj0", + "col258": "r5yih", + "col259": "3yi9v", + "col260": "asipq", + "col261": "hfque", + "col262": "6v23g", + "col263": "x98r7", + "col264": "nbi2n", + "col265": "2a3v3", + "col266": "ktn8h", + "col267": "r5a6g", + "col268": "mq954", + "col269": "bqh08", + "col270": "3akp0", + "col271": "fi9wm", + "col272": "41jrv", + "col273": "kecz4", + "col274": "0zz20", + "col275": "fke0l", + "col276": "ux82m", + "col277": "pp1cm", + "col278": "v4laj", + "col279": "8hpi4", + "col280": "o81rc", + "col281": "5wqq6", + "col282": "2siwy", + "col283": "11367", + "col284": "9bc5j", + "col285": "xr4pd", + "col286": "dhwur", + "col287": "s71ws", + "col288": "9mtmz", + "col289": "hr77e", + "col290": "4s0eh", + "col291": "uxvbe", + "col292": "meih4", + "col293": "1buu3", + "col294": "puoys", + "col295": "g5kdx", + "col296": "j5z4l", + "col297": "kw037", + "col298": "saram", + "col299": "6p7q3", + "col300": "22yhp", + "col301": "b127h", + "col302": "i4jms", + "col303": "q67r7", + "col304": "8675g", + "col305": "5e7m3", + "col306": "93tan", + "col307": "fpt6b", + "col308": "txohc", + "col309": "t311l", + "col310": "940vj", + "col311": "765nm", + "col312": "v07ve", + "col313": "w24qa", + "col314": "uxoe4", + "col315": "1mrwd", + "col316": "4y0io", + "col317": "5chv1", + "col318": "9u49c", + "col319": "uqcl8", + "col320": "4k5lh", + "col321": "fhum6", + "col322": "kidaf", + "col323": "scfoc", + "col324": "sf144", + "col325": "yh7qz", + "col326": "pjvzd", + "col327": "btf7r", + "col328": "q79p9", + "col329": "ihdi7", + "col330": "xuzjr", + "col331": "5y0l5", + "col332": "cfs3b", + "col333": "88ehe", + "col334": "4rkz4", + "col335": "8efj6", + "col336": "gnpdh", + "col337": "2tz2s", + "col338": "oazge", + "col339": "ixahf", + "col340": "m1mcw", + "col341": "5fczb", + "col342": "u2caf", + "col343": "winc9", + "col344": "1j7i2", + "col345": "okipg", + "col346": "wppmi", + "col347": "efbjp", + "col348": "s0pj3", + "col349": "edzm3", + "col350": "26sgo", + "col351": "gh93f", + "col352": "s9zbd", + "col353": "z3eo9", + "col354": "m9zkn", + "col355": "7v6cm", + "col356": "lt1cw", + "col357": "4iask", + "col358": "uk6qi", + "col359": "vsmql", + "col360": "lof7d", + "col361": "oyama", + "col362": "w58a6", + "col363": "m10rq", + "col364": "8j3d6", + "col365": "1taka", + "col366": "mkrrw", + "col367": "w8o8q", + "col368": "lheue", + "col369": "4rje3", + "col370": "72qxy", + "col371": "hwfyt", + "col372": "rnbpp", + "col373": "iudy7", + "col374": "7ijv4", + "col375": "dwz5q", + "col376": "1kp3g", + "col377": "abju9", + "col378": "lvmbk", + "col379": "lm6aw", + "col380": "bgmff", + "col381": "j4vz7", + "col382": "sgarv", + "col383": "isj8w", + "col384": "v6ka2", + "col385": "sal0y", + "col386": "sveh2", + "col387": "h3l17", + "col388": "fopvd", + "col389": "p40u5", + "col390": "kdib1", + "col391": "es6fz", + "col392": "i019i", + "col393": "j6fo2", + "col394": "v912h", + "col395": "76nww", + "col396": "mpcv8", + "col397": "rhrps", + "col398": "f4ohc", + "col399": "1tno4", + "col400": "qqk4u", + "col401": "5e8xt", + "col402": "99hnl", + "col403": "gixig", + "col404": "zdj0m", + "col405": "08rlj", + "col406": "yfnql", + "col407": "z5nby", + "col408": "m69bo", + "col409": "ssvvo", + "col410": "84zki", + "col411": "3ble3", + "col412": "yz16v", + "col413": "gg4q0", + "col414": "fb5my", + "col415": "7kh99", + "col416": "c2nlw", + "col417": "0awy0", + "col418": "thuq5", + "col419": "v1zca", + "col420": "y58ep", + "col421": "jxsk4", + "col422": "td2yp", + "col423": "lxbui", + "col424": "msbad", + "col425": "f7rta", + "col426": "idyvq", + "col427": "zp6fk", + "col428": "ova2k", + "col429": "n74f6", + "col430": "l5ak7", + "col431": "f72s6", + "col432": "qm0qk", + "col433": "tk2n7", + "col434": "83lam", + "col435": "pwycd", + "col436": "cueja", + "col437": "ereh1", + "col438": "9izdw", + "col439": "fq0hp", + "col440": "hetjh", + "col441": "zg53y", + "col442": "qy8dh", + "col443": "czhj0", + "col444": "no967", + "col445": "yg51l", + "col446": "pkp2i", + "col447": "29au1", + "col448": "0w1yd", + "col449": "5k8sx", + "col450": "ti80f", + "col451": "78kvw", + "col452": "6azzm", + "col453": "1ptre", + "col454": "kyy9j", + "col455": "9jw6c", + "col456": "b6nrk", + "col457": "qwkfx", + "col458": "eiclv", + "col459": "go77j", + "col460": "of7b7", + "col461": "5tmge", + "col462": "3eo86", + "col463": "3nlz5", + "col464": "tysyj", + "col465": "wrtzq", + "col466": "wjl9h", + "col467": "56t42", + "col468": "yafnj", + "col469": "m4eb9", + "col470": "v2368", + "col471": "cscvp", + "col472": "3qe3g", + "col473": "0d1g5", + "col474": "pck9x", + "col475": "rcqi6", + "col476": "knsab", + "col477": "2fx3p", + "col478": "946k9", + "col479": "plvv7", + "col480": "n3ifz", + "col481": "hyc8z", + "col482": "8o8y6", + "col483": "51xfk", + "col484": "4q85j", + "col485": "lhzm3", + "col486": "57ekv", + "col487": "gqicq", + "col488": "aqrg8", + "col489": "52c5b", + "col490": "xl4qs", + "col491": "uwhbz", + "col492": "gtewi", + "col493": "jyc72", + "col494": "xicf1", + "col495": "v9s6s", + "col496": "6ndrl", + "col497": "ui56k", + "col498": "rgg8u", + "col499": "l93pz", + "col500": "pkr4u", + "col501": "hsda0", + "col502": "mxo9u", + "col503": "vr9r7", + "col504": "dgokp", + "col505": "4r938", + "col506": "3akcg", + "col507": "l3ajd", + "col508": "eqz2h", + "col509": "rxxx1", + "col510": "llpxa", + "col511": "o8xdn", + "col512": "t9ejw", + "col513": "pm3j1", + "col514": "b1wb2", + "col515": "48bu0", + "col516": "imc65", + "col517": "9md43", + "col518": "7quof", + "col519": "mouez", + "col520": "13t5q", + "col521": "tjr3q", + "col522": "jil6j", + "col523": "kneww", + "col524": "cztmb", + "col525": "cjzmp", + "col526": "db9vw", + "col527": "xmqra", + "col528": "n9re3", + "col529": "i7dbg", + "col530": "xd7h8", + "col531": "5groo", + "col532": "kvjsu", + "col533": "h51th", + "col534": "08smz", + "col535": "kya02", + "col536": "eg2is", + "col537": "55jxk", + "col538": "c8xxb", + "col539": "dkdul", + "col540": "bvypx", + "col541": "bohs8", + "col542": "pg4g9", + "col543": "8tbdg", + "col544": "utjmi", + "col545": "st5gz", + "col546": "n01o7", + "col547": "srjkb", + "col548": "etsju", + "col549": "xv25x", + "col550": "6kg8j", + "col551": "u1sg3", + "col552": "yrffj", + "col553": "gf57l", + "col554": "9u93l", + "col555": "r2bsv", + "col556": "mn377", + "col557": "5m246", + "col558": "ahjsk", + "col559": "lz89w", + "col560": "e5odo", + "col561": "woqyb", + "col562": "hsigp", + "col563": "s79nq", + "col564": "37h4z", + "col565": "s6pb8", + "col566": "0770h", + "col567": "5hqrz", + "col568": "c0qth", + "col569": "y2ikl", + "col570": "7gzx5", + "col571": "jp2ig", + "col572": "fsgpc", + "col573": "sd9bm", + "col574": "gom6u", + "col575": "5idc9", + "col576": "svl7w", + "col577": "x8gw0", + "col578": "qgjud", + "col579": "nn9ag", + "col580": "4bjvc", + "col581": "zrf0o", + "col582": "5plig", + "col583": "de9jf", + "col584": "ue1dz", + "col585": "nm7ys", + "col586": "7j8vr", + "col587": "wj1bp", + "col588": "dhsom", + "col589": "3mmap", + "col590": "wdx0w", + "col591": "eouz1", + "col592": "jhvew", + "col593": "skdwn", + "col594": "b75ea", + "col595": "61vy2", + "col596": "10yni", + "col597": "3k9zz", + "col598": "3zs1i", + "col599": "09h87", + "col600": "8lu6o", + "col601": "phjjj", + "col602": "d6ff9", + "col603": "kzoz6", + "col604": "d8jbh", + "col605": "r6li7", + "col606": "o70pe", + "col607": "gm6wl", + "col608": "8rso7", + "col609": "ovh32", + "col610": "d31rg", + "col611": "wdpro", + "col612": "yzk6h", + "col613": "xj1uu", + "col614": "5u7e3", + "col615": "bjquv", + "col616": "5s2a8", + "col617": "ix1vt", + "col618": "oi43p", + "col619": "0ytks", + "col620": "xzbji", + "col621": "gq2vw", + "col622": "yvqba", + "col623": "sd9x0", + "col624": "zf72n", + "col625": "ymsb4", + "col626": "435wh", + "col627": "ib5fz", + "col628": "qays5", + "col629": "ucsep", + "col630": "a8157", + "col631": "26g44", + "col632": "tp2sq", + "col633": "xd1mc", + "col634": "qbwoa", + "col635": "zt9c5", + "col636": "edb64", + "col637": "ny5gd", + "col638": "59ls6", + "col639": "fljnw", + "col640": "4t2gy", + "col641": "4roed", + "col642": "fqu7m", + "col643": "x9p77", + "col644": "zn4v7", + "col645": "fonvm", + "col646": "7p5rw", + "col647": "v11vd", + "col648": "lsf4p", + "col649": "nss8p", + "col650": "akyz7", + "col651": "n0nzw", + "col652": "pwmia", + "col653": "xw60q", + "col654": "e75tc", + "col655": "pb02x", + "col656": "rq4tm", + "col657": "697yo", + "col658": "926ny", + "col659": "5t8x0", + "col660": "qx0pr", + "col661": "9g0sz", + "col662": "0daic", + "col663": "jbg8b", + "col664": "mep4r", + "col665": "fk6e7", + "col666": "gwtiu", + "col667": "qp6tm", + "col668": "djvb3", + "col669": "kcrd6", + "col670": "1175i", + "col671": "4y0kj", + "col672": "ws5rq", + "col673": "v9kdm", + "col674": "oz6t6", + "col675": "lw0jo", + "col676": "s0tdv", + "col677": "flp8t", + "col678": "mtx2e", + "col679": "9epn8", + "col680": "us3qb", + "col681": "l8rml", + "col682": "4vr6q", + "col683": "q1tlc", + "col684": "fnaks", + "col685": "7bwic", + "col686": "ebzk6", + "col687": "vmtx8", + "col688": "9oqfy", + "col689": "q95kj", + "col690": "ug4et", + "col691": "m3lhk", + "col692": "10z23", + "col693": "5j0sk", + "col694": "j7k1c", + "col695": "6cpep", + "col696": "gu9r8", + "col697": "uakq0", + "col698": "9ekby", + "col699": "jjhid", + "col700": "18jwj", + "col701": "5mszh", + "col702": "f1ksb", + "col703": "qeh44", + "col704": "8m9qa", + "col705": "j65f8", + "col706": "oku3j", + "col707": "2b3ib", + "col708": "e1f3b", + "col709": "e1rkj", + "col710": "s1ai7", + "col711": "hdkqd", + "col712": "azayc", + "col713": "32rc4", + "col714": "cxk0r", + "col715": "hvf0r", + "col716": "1a8j8", + "col717": "qzr2e", + "col718": "v9k1r", + "col719": "sdp93", + "col720": "arpiu", + "col721": "w5n4s", + "col722": "mwifp", + "col723": "rxsn2", + "col724": "x5364", + "col725": "u89ma", + "col726": "1kvx5", + "col727": "n63yi", + "col728": "qt5i3", + "col729": "4bgjc", + "col730": "cf0gh", + "col731": "rd75k", + "col732": "ii81u", + "col733": "8plzl", + "col734": "69zim", + "col735": "hnu56", + "col736": "ughcd", + "col737": "6yuf6", + "col738": "7kk20", + "col739": "nxr05", + "col740": "w15y5", + "col741": "2lwxi", + "col742": "3qgfm", + "col743": "o9duh", + "col744": "5nk3c", + "col745": "7rgls", + "col746": "68omy", + "col747": "kh6ex", + "col748": "20lkl", + "col749": "obcnz", + "col750": "gv4t7", + "col751": "hcspl", + "col752": "9vzrm", + "col753": "an0ry", + "col754": "ql0at", + "col755": "pdv43", + "col756": "o1zcl", + "col757": "1lsl4", + "col758": "f6jgy", + "col759": "pljpo", + "col760": "qmam9", + "col761": "dxen8", + "col762": "u5xrt", + "col763": "ureay", + "col764": "am9vf", + "col765": "dhebq", + "col766": "no688", + "col767": "eickm", + "col768": "ksf4h", + "col769": "coyto", + "col770": "uv3e9", + "col771": "nc3hs", + "col772": "dvixa", + "col773": "bo79s", + "col774": "qyt94", + "col775": "kcqn9", + "col776": "jtxh1", + "col777": "n2vue", + "col778": "qnzyh", + "col779": "2fc6m", + "col780": "2og69", + "col781": "uc80s", + "col782": "5k91k", + "col783": "roeru", + "col784": "1ihkk", + "col785": "gug9d", + "col786": "r7hd7", + "col787": "tu7zi", + "col788": "9l174", + "col789": "7an6w", + "col790": "d7r4m", + "col791": "rwa7h", + "col792": "60gj5", + "col793": "bdak0", + "col794": "myv0d", + "col795": "smffl", + "col796": "r4z47", + "col797": "zwksp", + "col798": "y0itm", + "col799": "8bt0m", + "col800": "3ddc4", + "col801": "zwmph", + "col802": "3xox3", + "col803": "070wa", + "col804": "qffbq", + "col805": "zuogk", + "col806": "w5xt4", + "col807": "sxlpm", + "col808": "duk16", + "col809": "kd8ge", + "col810": "hmhq1", + "col811": "ut3wh", + "col812": "iwqew", + "col813": "i98ok", + "col814": "dq5yx", + "col815": "53sv9", + "col816": "ct5m6", + "col817": "203mc", + "col818": "2ag5b", + "col819": "fk46n", + "col820": "c65qn", + "col821": "7nze9", + "col822": "5fi1j", + "col823": "3dimp", + "col824": "zvde5", + "col825": "c1b0o", + "col826": "d0e3m", + "col827": "0p6e7", + "col828": "ch1hb", + "col829": "nrjq0", + "col830": "g2ztq", + "col831": "c7576", + "col832": "qn201", + "col833": "35gbp", + "col834": "pbrh8", + "col835": "01f3w", + "col836": "an485", + "col837": "uhxg0", + "col838": "2pa17", + "col839": "k7ux4", + "col840": "wtj46", + "col841": "qk2h4", + "col842": "so0yx", + "col843": "o3fs3", + "col844": "pb2i3", + "col845": "olj67", + "col846": "vc66t", + "col847": "d5lu7", + "col848": "zjvb7", + "col849": "xbdy8", + "col850": "wvia9", + "col851": "ngra2", + "col852": "kqnk4", + "col853": "wqrol", + "col854": "wyhdc", + "col855": "lz1vl", + "col856": "5gngi", + "col857": "60rpg", + "col858": "gp3ue", + "col859": "fsb33", + "col860": "id242", + "col861": "08kqj", + "col862": "ivpzr", + "col863": "6txjf", + "col864": "jy2af", + "col865": "utigi", + "col866": "qw67e", + "col867": "wq0sz", + "col868": "5pp2m", + "col869": "5sk0z", + "col870": "b7oqu", + "col871": "hup8x", + "col872": "ufj93", + "col873": "94ycs", + "col874": "lcq83", + "col875": "lczqy", + "col876": "drkrt", + "col877": "h2v53", + "col878": "p6d54", + "col879": "umeus", + "col880": "jtaam", + "col881": "09j90", + "col882": "eno05", + "col883": "bvsfp", + "col884": "dpwvq", + "col885": "jckef", + "col886": "h9bm2", + "col887": "x1otw", + "col888": "xslvx", + "col889": "1vsqo", + "col890": "ky7ph", + "col891": "ksh4d", + "col892": "12nyj", + "col893": "aae2a", + "col894": "kkklj", + "col895": "z40lx", + "col896": "29z6d", + "col897": "39h8v", + "col898": "3b5q6", + "col899": "8pju5", + "col900": "mzd2x", + "col901": "uz3et", + "col902": "1t8uw", + "col903": "su1wa", + "col904": "7rxyd", + "col905": "wl7t4", + "col906": "ybrfu", + "col907": "sbm72", + "col908": "wne6d", + "col909": "n6g0q", + "col910": "nlq9a", + "col911": "riypq", + "col912": "gjobu", + "col913": "pwc5t", + "col914": "ujjpd", + "col915": "mzk6t", + "col916": "of51b", + "col917": "5xxq2", + "col918": "0mwis", + "col919": "0n7yp", + "col920": "frlm5", + "col921": "7ihsy", + "col922": "yvala", + "col923": "7k2bd", + "col924": "xn4sr", + "col925": "iytk0", + "col926": "d2rmu", + "col927": "bmdft", + "col928": "ncry6", + "col929": "0p48x", + "col930": "b7g9y", + "col931": "rfkou", + "col932": "yoray", + "col933": "l2uq2", + "col934": "io9pu", + "col935": "ni1lx", + "col936": "ipulv", + "col937": "z6s2j", + "col938": "sztx3", + "col939": "rxge8", + "col940": "qmupg", + "col941": "03qqa", + "col942": "2fjci", + "col943": "nng7g", + "col944": "kz909", + "col945": "treav", + "col946": "9336s", + "col947": "r1j29", + "col948": "rtums", + "col949": "tckh8", + "col950": "p6obc", + "col951": "oonso", + "col952": "ao2s0", + "col953": "rq2wo", + "col954": "82a7m", + "col955": "ydf1r", + "col956": "j2wnt", + "col957": "d40g4", + "col958": "q509p", + "col959": "5lvgu", + "col960": "y56as", + "col961": "8oxwm", + "col962": "0vv8t", + "col963": "jzyx0", + "col964": "y6y3e", + "col965": "nmepo", + "col966": "qxl7c", + "col967": "2g2gx", + "col968": "1ln9g", + "col969": "5vgpx", + "col970": "kid33", + "col971": "32ujh", + "col972": "269jy", + "col973": "ub2u1", + "col974": "vuwr1", + "col975": "xz5vo", + "col976": "r2oas", + "col977": "zxpjq", + "col978": "51tau", + "col979": "gkphk", + "col980": "qoluo", + "col981": "hw4hr", + "col982": "lj41q", + "col983": "2ihmn", + "col984": "y6gan", + "col985": "tueai", + "col986": "1ea3a", + "col987": "yeqbz", + "col988": "896bv", + "col989": "lf0qi", + "col990": "pydu4", + "col991": "6pzir", + "col992": "yjdn6", + "col993": "049uq", + "col994": "l54cg", + "col995": "qf765", + "col996": "o81kp", + "col997": "vuoy0", + "col998": "mc54d", + "col999": "04d6e" + }, + { + "name": "Oconnor Little", + "gender": "male", + "col0": "g057q", + "col1": "snl55", + "col2": "gbqb2", + "col3": "n2pmm", + "col4": "evlcd", + "col5": "waewo", + "col6": "sm3qf", + "col7": "o1h8y", + "col8": "w1bvb", + "col9": "tdfj5", + "col10": "k3a19", + "col11": "lemz5", + "col12": "skqmz", + "col13": "whetd", + "col14": "3bvuw", + "col15": "2acmi", + "col16": "48zrc", + "col17": "iegb6", + "col18": "t2my8", + "col19": "nnhsb", + "col20": "4ye8o", + "col21": "h6kva", + "col22": "u9qve", + "col23": "oxqj0", + "col24": "6cpyb", + "col25": "ifrpa", + "col26": "4rlag", + "col27": "cvzct", + "col28": "prjr6", + "col29": "zv0zo", + "col30": "p4mj9", + "col31": "y41z3", + "col32": "fhadi", + "col33": "pno6f", + "col34": "urou3", + "col35": "xhr1c", + "col36": "ine72", + "col37": "28x2l", + "col38": "t9fr8", + "col39": "sne5v", + "col40": "u5kp8", + "col41": "qnrqd", + "col42": "ry2nj", + "col43": "9rtq1", + "col44": "r6bc5", + "col45": "gnwch", + "col46": "bcm5g", + "col47": "npo3f", + "col48": "d90ig", + "col49": "qvtd6", + "col50": "omwfw", + "col51": "wuid7", + "col52": "n5ti6", + "col53": "lfm7g", + "col54": "ttoo8", + "col55": "qlk17", + "col56": "dr1b8", + "col57": "ui6zv", + "col58": "ij4fe", + "col59": "5tszj", + "col60": "p4fz9", + "col61": "xd0rr", + "col62": "cibhg", + "col63": "c83wt", + "col64": "ii8tb", + "col65": "ylq54", + "col66": "d9gv9", + "col67": "dszvj", + "col68": "cij1m", + "col69": "gpr75", + "col70": "esvlb", + "col71": "xe778", + "col72": "pupca", + "col73": "hkdw8", + "col74": "3y562", + "col75": "427ds", + "col76": "ygeic", + "col77": "37v2e", + "col78": "x48zf", + "col79": "2rvuy", + "col80": "tueot", + "col81": "rrqcd", + "col82": "v2xph", + "col83": "j017q", + "col84": "k6q81", + "col85": "nnfx4", + "col86": "cikln", + "col87": "lyx5c", + "col88": "j2amh", + "col89": "z16bt", + "col90": "8zbo8", + "col91": "xc6fr", + "col92": "ifcgz", + "col93": "pwarz", + "col94": "tfc3p", + "col95": "nerpt", + "col96": "3xqjt", + "col97": "gsabx", + "col98": "qbojk", + "col99": "cuoeh", + "col100": "hagx7", + "col101": "ovdyz", + "col102": "vdubi", + "col103": "7gae9", + "col104": "2jac2", + "col105": "cb1xu", + "col106": "bvtlw", + "col107": "pm2o5", + "col108": "c3duh", + "col109": "6os7b", + "col110": "kc811", + "col111": "v5r9h", + "col112": "zrmd6", + "col113": "flxih", + "col114": "wf80r", + "col115": "z0w6q", + "col116": "ym011", + "col117": "8ibtx", + "col118": "hdpsc", + "col119": "iutqf", + "col120": "9hc46", + "col121": "woiah", + "col122": "bk8yw", + "col123": "or4o5", + "col124": "bm5og", + "col125": "e5oa8", + "col126": "jrcix", + "col127": "4254i", + "col128": "3qdy7", + "col129": "7ysfg", + "col130": "e5csc", + "col131": "251xq", + "col132": "zlwl7", + "col133": "k4hez", + "col134": "uyxby", + "col135": "spqof", + "col136": "w3chm", + "col137": "ulcqi", + "col138": "m7u6b", + "col139": "k3x81", + "col140": "qnk3o", + "col141": "btqqc", + "col142": "x2oet", + "col143": "clhm5", + "col144": "t5gin", + "col145": "jxeju", + "col146": "zotrk", + "col147": "m3yxa", + "col148": "vmyab", + "col149": "xkkmp", + "col150": "roxo9", + "col151": "qp4y4", + "col152": "hfb3g", + "col153": "tx6dc", + "col154": "n390o", + "col155": "bq2j3", + "col156": "r1ch5", + "col157": "mruvi", + "col158": "k7izc", + "col159": "mokyu", + "col160": "0iwcu", + "col161": "18e54", + "col162": "4ktf3", + "col163": "64886", + "col164": "6j5kb", + "col165": "pe4ig", + "col166": "wk321", + "col167": "7yk6o", + "col168": "9qec9", + "col169": "2ytjp", + "col170": "8i73a", + "col171": "wvluw", + "col172": "catxe", + "col173": "aei9s", + "col174": "g08w0", + "col175": "c7wna", + "col176": "ek5ca", + "col177": "8fr8r", + "col178": "myv46", + "col179": "vyftn", + "col180": "v6h56", + "col181": "jf3id", + "col182": "jcf1e", + "col183": "0ics3", + "col184": "288rp", + "col185": "rv8p4", + "col186": "v10tv", + "col187": "ev53q", + "col188": "r618f", + "col189": "vleun", + "col190": "8wtj6", + "col191": "1o547", + "col192": "whutr", + "col193": "aozsb", + "col194": "snif3", + "col195": "xa2ug", + "col196": "judgy", + "col197": "klsoa", + "col198": "4kz9a", + "col199": "rcjoh", + "col200": "1juao", + "col201": "kbyrj", + "col202": "mak2x", + "col203": "5z110", + "col204": "4l3rs", + "col205": "3ysmc", + "col206": "b29pr", + "col207": "6eh5g", + "col208": "xvu1b", + "col209": "s5oh4", + "col210": "j9nev", + "col211": "mm997", + "col212": "bcih2", + "col213": "tmank", + "col214": "w4wlc", + "col215": "oaiei", + "col216": "jr8bd", + "col217": "640zz", + "col218": "2gnku", + "col219": "bfmz2", + "col220": "cj840", + "col221": "ce3cy", + "col222": "ndmo7", + "col223": "825em", + "col224": "1elug", + "col225": "82i70", + "col226": "b0j5l", + "col227": "vrehi", + "col228": "qu61y", + "col229": "4lge6", + "col230": "hzmkx", + "col231": "7yo1c", + "col232": "hcmob", + "col233": "bnflj", + "col234": "lk5s6", + "col235": "sro2n", + "col236": "55srs", + "col237": "sp0e5", + "col238": "5z4sa", + "col239": "i1s9s", + "col240": "axyz5", + "col241": "s5nv8", + "col242": "l9mae", + "col243": "r81dv", + "col244": "o4ik5", + "col245": "tg57f", + "col246": "zy6yc", + "col247": "c6h3h", + "col248": "3zqa3", + "col249": "8jy0m", + "col250": "1f5wy", + "col251": "dt3hg", + "col252": "9zhd8", + "col253": "1dea4", + "col254": "dburp", + "col255": "g1ewl", + "col256": "t97jr", + "col257": "wl86c", + "col258": "zaqlb", + "col259": "9c5r7", + "col260": "rvcjk", + "col261": "iq80s", + "col262": "ojc0s", + "col263": "xu0ah", + "col264": "kno27", + "col265": "vy4n5", + "col266": "yvkbj", + "col267": "lsvrl", + "col268": "isltr", + "col269": "2hwrb", + "col270": "pb1hr", + "col271": "thcw1", + "col272": "d4f6j", + "col273": "dskvw", + "col274": "cnzng", + "col275": "a342g", + "col276": "zfon3", + "col277": "p3lsh", + "col278": "b0la9", + "col279": "x4q1k", + "col280": "mbnig", + "col281": "j3pj3", + "col282": "cr0wm", + "col283": "ub4n6", + "col284": "le54h", + "col285": "mg46j", + "col286": "tr7og", + "col287": "h48u7", + "col288": "zq2ks", + "col289": "d87of", + "col290": "eotip", + "col291": "u2u3m", + "col292": "82v63", + "col293": "9nc34", + "col294": "xo76m", + "col295": "z00h4", + "col296": "v6ulx", + "col297": "fxczy", + "col298": "vw6o6", + "col299": "vwkh0", + "col300": "3jm99", + "col301": "nsm60", + "col302": "zpaux", + "col303": "8prai", + "col304": "1t2a3", + "col305": "u94jy", + "col306": "demcq", + "col307": "4f5g8", + "col308": "g8b05", + "col309": "wwbm2", + "col310": "qps72", + "col311": "56cn6", + "col312": "g5mp4", + "col313": "f1jc5", + "col314": "hno55", + "col315": "r3zbl", + "col316": "wge6b", + "col317": "pzdgc", + "col318": "a6zth", + "col319": "6gcw3", + "col320": "1sxwu", + "col321": "aex2g", + "col322": "ugfzr", + "col323": "qrcic", + "col324": "gdjxf", + "col325": "a0db3", + "col326": "ls7ym", + "col327": "ukx17", + "col328": "eijzl", + "col329": "siavu", + "col330": "uu4ca", + "col331": "oufe7", + "col332": "r8ptq", + "col333": "wd5d8", + "col334": "7dcld", + "col335": "vqs8t", + "col336": "u9ayr", + "col337": "z2mgg", + "col338": "mc9mc", + "col339": "za8mg", + "col340": "7jdas", + "col341": "t0xej", + "col342": "ivi6y", + "col343": "jyyju", + "col344": "xsqcc", + "col345": "411fw", + "col346": "t2dmp", + "col347": "9paiv", + "col348": "v519n", + "col349": "8uzhd", + "col350": "z0t3x", + "col351": "2y5dy", + "col352": "y9yj8", + "col353": "1m1oy", + "col354": "rz0vx", + "col355": "glgbl", + "col356": "fzw1t", + "col357": "d9mje", + "col358": "yhg52", + "col359": "iq23l", + "col360": "9om9y", + "col361": "q14tb", + "col362": "27q55", + "col363": "ih42g", + "col364": "9pakd", + "col365": "zpor2", + "col366": "pjeds", + "col367": "0o8gg", + "col368": "epfwc", + "col369": "xtjle", + "col370": "s5674", + "col371": "spdc7", + "col372": "n3ltz", + "col373": "ph5lc", + "col374": "mfew5", + "col375": "l53sh", + "col376": "p457i", + "col377": "0328p", + "col378": "s98od", + "col379": "wjmw9", + "col380": "qikq9", + "col381": "qqxgh", + "col382": "khh4j", + "col383": "eapji", + "col384": "schv2", + "col385": "qonlw", + "col386": "08c06", + "col387": "3qaft", + "col388": "l6mfi", + "col389": "6osux", + "col390": "7tfmu", + "col391": "86lmk", + "col392": "xkumr", + "col393": "hofa0", + "col394": "wrmdq", + "col395": "o71zw", + "col396": "cab1j", + "col397": "9wox8", + "col398": "km9ub", + "col399": "5rtat", + "col400": "rffws", + "col401": "o02k1", + "col402": "i382e", + "col403": "l6v87", + "col404": "x6it1", + "col405": "02tum", + "col406": "i1xlv", + "col407": "ckwd9", + "col408": "dh37i", + "col409": "u77ix", + "col410": "bmnit", + "col411": "zk99v", + "col412": "cmhum", + "col413": "tdadv", + "col414": "6dl2v", + "col415": "e9vfs", + "col416": "3ukr2", + "col417": "caf12", + "col418": "7im9r", + "col419": "dq97t", + "col420": "dshwk", + "col421": "dpbgs", + "col422": "u7brr", + "col423": "zx3fn", + "col424": "ir70s", + "col425": "m5ljo", + "col426": "m0741", + "col427": "dnjle", + "col428": "j2g41", + "col429": "fx7qw", + "col430": "z9o9r", + "col431": "1sdji", + "col432": "5bhcz", + "col433": "nmbfw", + "col434": "77dbh", + "col435": "6vjsn", + "col436": "0vgez", + "col437": "18yip", + "col438": "59a3t", + "col439": "a8e77", + "col440": "dfaum", + "col441": "xop03", + "col442": "tz367", + "col443": "lqzi2", + "col444": "d9kqc", + "col445": "vxr9b", + "col446": "olz9n", + "col447": "myipf", + "col448": "d7d4m", + "col449": "e0pyp", + "col450": "87bi2", + "col451": "n8xd2", + "col452": "bhs8t", + "col453": "ownsd", + "col454": "z319m", + "col455": "83zv3", + "col456": "trytk", + "col457": "m0792", + "col458": "88yzu", + "col459": "4mxdi", + "col460": "m6ftx", + "col461": "7ng80", + "col462": "skxr3", + "col463": "dhx7k", + "col464": "z5d4g", + "col465": "8whgf", + "col466": "7044y", + "col467": "l2dc7", + "col468": "eiv69", + "col469": "yxelx", + "col470": "1148h", + "col471": "sb8wv", + "col472": "ho4gn", + "col473": "9oemb", + "col474": "89mzq", + "col475": "gu7ti", + "col476": "vp0hl", + "col477": "ohl6a", + "col478": "i4t7d", + "col479": "nxwzi", + "col480": "rcrxd", + "col481": "gw3rt", + "col482": "ti0ve", + "col483": "ukfhg", + "col484": "xndhi", + "col485": "wtdzx", + "col486": "m00c2", + "col487": "0spo7", + "col488": "rna6q", + "col489": "cfn5t", + "col490": "l1drr", + "col491": "n67v1", + "col492": "af7wb", + "col493": "wxwo9", + "col494": "a5bfq", + "col495": "8af6i", + "col496": "ozhwm", + "col497": "xq6ft", + "col498": "wj63j", + "col499": "o2x4b", + "col500": "utkj1", + "col501": "73owo", + "col502": "sxqba", + "col503": "ho5jg", + "col504": "1gdls", + "col505": "z2zm7", + "col506": "xf6xc", + "col507": "ayg9f", + "col508": "dthxe", + "col509": "dbmx0", + "col510": "el2vn", + "col511": "1lyxp", + "col512": "pv0cp", + "col513": "f9qcq", + "col514": "4z18r", + "col515": "c1ttr", + "col516": "zyjex", + "col517": "sy82b", + "col518": "3pse5", + "col519": "a6axe", + "col520": "gggqk", + "col521": "eyktn", + "col522": "qlnmj", + "col523": "dr9e8", + "col524": "rwfuc", + "col525": "r0ggt", + "col526": "ihvnh", + "col527": "2wzhq", + "col528": "fyfll", + "col529": "7m00a", + "col530": "e3js8", + "col531": "2114x", + "col532": "lh5jk", + "col533": "9unmn", + "col534": "xay5k", + "col535": "0t0i6", + "col536": "ixfga", + "col537": "nsjoi", + "col538": "2cnsz", + "col539": "4rb74", + "col540": "cqq1d", + "col541": "duvi3", + "col542": "gj4xo", + "col543": "kmwvh", + "col544": "2bbla", + "col545": "rwh2v", + "col546": "2vmyd", + "col547": "hibvu", + "col548": "60v82", + "col549": "vqfu6", + "col550": "qp0b9", + "col551": "pb3ee", + "col552": "kaz21", + "col553": "5xw4m", + "col554": "2v5bj", + "col555": "z110z", + "col556": "m4ixh", + "col557": "9gaoe", + "col558": "5liok", + "col559": "dr7uc", + "col560": "jj9xj", + "col561": "kz8bu", + "col562": "q3rbf", + "col563": "avs2h", + "col564": "op077", + "col565": "hea3s", + "col566": "gf9m4", + "col567": "qppal", + "col568": "reu7b", + "col569": "1nlah", + "col570": "w1w2n", + "col571": "fbhf5", + "col572": "sisje", + "col573": "6js0t", + "col574": "lbd5k", + "col575": "14u8l", + "col576": "dmtw2", + "col577": "qy710", + "col578": "08rvn", + "col579": "3m2uz", + "col580": "c6ndb", + "col581": "lpmt6", + "col582": "mahnj", + "col583": "x6rb1", + "col584": "absgs", + "col585": "r7x33", + "col586": "kax43", + "col587": "cd1dj", + "col588": "ihq8w", + "col589": "0kfrn", + "col590": "bxzux", + "col591": "czmrx", + "col592": "1trmv", + "col593": "4bumv", + "col594": "l6pc8", + "col595": "diija", + "col596": "9cknf", + "col597": "qmig9", + "col598": "tdlwx", + "col599": "4arxv", + "col600": "bry4r", + "col601": "zzy9a", + "col602": "qkgxb", + "col603": "eb1ow", + "col604": "vl62w", + "col605": "7xi0j", + "col606": "sdfhw", + "col607": "rt7yp", + "col608": "ey5c7", + "col609": "6i4r6", + "col610": "6iq50", + "col611": "powai", + "col612": "g0rhx", + "col613": "ff8qr", + "col614": "uqgj4", + "col615": "mtaue", + "col616": "5imv8", + "col617": "x03uz", + "col618": "4g7y4", + "col619": "nq7c4", + "col620": "6w1qh", + "col621": "rvj6e", + "col622": "xvih6", + "col623": "uyjn1", + "col624": "u89db", + "col625": "qxmx7", + "col626": "9b2gj", + "col627": "8g6ya", + "col628": "yq8x8", + "col629": "1pe83", + "col630": "tybxw", + "col631": "3y4o7", + "col632": "fwu39", + "col633": "pcvhx", + "col634": "x8gom", + "col635": "vd4ds", + "col636": "8fd99", + "col637": "bx6zt", + "col638": "5iwt2", + "col639": "31f12", + "col640": "5bm5n", + "col641": "x4yyu", + "col642": "9qgug", + "col643": "z2y3m", + "col644": "5m8jn", + "col645": "6byjf", + "col646": "wn2s4", + "col647": "bcn99", + "col648": "782ff", + "col649": "eukiz", + "col650": "jy4gt", + "col651": "emfjm", + "col652": "aewed", + "col653": "lhcty", + "col654": "elq2t", + "col655": "3llda", + "col656": "ra9th", + "col657": "rf23z", + "col658": "f4vqh", + "col659": "cm48i", + "col660": "xwgf5", + "col661": "r3fmv", + "col662": "2wv94", + "col663": "hkvgm", + "col664": "z04uw", + "col665": "1ijg0", + "col666": "7zcs8", + "col667": "1ke46", + "col668": "filxk", + "col669": "v2h59", + "col670": "385dg", + "col671": "kaytr", + "col672": "euat7", + "col673": "c0fz1", + "col674": "7j0a9", + "col675": "6sura", + "col676": "6cnkf", + "col677": "j9p23", + "col678": "uq5vg", + "col679": "kp7so", + "col680": "oj02u", + "col681": "7qr1a", + "col682": "b0kkx", + "col683": "4u7cg", + "col684": "h7dd6", + "col685": "uq5hh", + "col686": "p53iw", + "col687": "vmd8k", + "col688": "8qldz", + "col689": "huq9d", + "col690": "sveu6", + "col691": "at4vy", + "col692": "e285i", + "col693": "jf0eh", + "col694": "x07v3", + "col695": "rj8rz", + "col696": "d6n21", + "col697": "vi7dc", + "col698": "8y6pc", + "col699": "f9ja2", + "col700": "0col2", + "col701": "ctwcb", + "col702": "jljh0", + "col703": "23va7", + "col704": "nexcp", + "col705": "w842h", + "col706": "b3jot", + "col707": "66kw8", + "col708": "9t6sb", + "col709": "ist8e", + "col710": "4y22q", + "col711": "k63r5", + "col712": "940km", + "col713": "m8zxq", + "col714": "1vb17", + "col715": "8r5uv", + "col716": "q2dmj", + "col717": "ou53j", + "col718": "tdt1f", + "col719": "irfeg", + "col720": "rrku2", + "col721": "eo4z7", + "col722": "8ge1e", + "col723": "f6qxu", + "col724": "wfjyu", + "col725": "4lshx", + "col726": "l3eb0", + "col727": "neyxm", + "col728": "j31m2", + "col729": "vru5o", + "col730": "ki1rg", + "col731": "r6sz6", + "col732": "1129j", + "col733": "dluw3", + "col734": "t1b9i", + "col735": "kdl9w", + "col736": "sf8tp", + "col737": "677i9", + "col738": "6turk", + "col739": "rbfic", + "col740": "l34su", + "col741": "amwmk", + "col742": "d0b7d", + "col743": "dq416", + "col744": "hxbrr", + "col745": "kq3x9", + "col746": "h79g0", + "col747": "fy45k", + "col748": "a1pip", + "col749": "7odrp", + "col750": "n2z2a", + "col751": "8zqxj", + "col752": "lf1vz", + "col753": "ub8vs", + "col754": "ae6iu", + "col755": "egp4u", + "col756": "zewz9", + "col757": "nbmo9", + "col758": "nqcbj", + "col759": "ntwvd", + "col760": "9s3dv", + "col761": "cinqx", + "col762": "r9r2u", + "col763": "a0poi", + "col764": "nuvcw", + "col765": "wb800", + "col766": "d6570", + "col767": "qd81m", + "col768": "q8ggr", + "col769": "v8gch", + "col770": "lzgga", + "col771": "7au50", + "col772": "bk2u1", + "col773": "zc52l", + "col774": "iqbyd", + "col775": "weu0q", + "col776": "a4fwj", + "col777": "0zsnq", + "col778": "pcemp", + "col779": "gpt8p", + "col780": "z2sxi", + "col781": "ocv84", + "col782": "m1dqg", + "col783": "tmdr5", + "col784": "0rc8o", + "col785": "q6w08", + "col786": "76yrj", + "col787": "1w90u", + "col788": "ch5gr", + "col789": "x9nmt", + "col790": "zllmh", + "col791": "9ox8v", + "col792": "jqha1", + "col793": "bla2e", + "col794": "vkm7h", + "col795": "y6z17", + "col796": "5wn66", + "col797": "tw6qm", + "col798": "gz73l", + "col799": "m4e1o", + "col800": "dom5f", + "col801": "06uyu", + "col802": "0rqhw", + "col803": "pbnnm", + "col804": "ioevl", + "col805": "hxg5g", + "col806": "iq8xd", + "col807": "3bynq", + "col808": "ij0yk", + "col809": "p2zfw", + "col810": "6l5xu", + "col811": "5i2ov", + "col812": "r0yix", + "col813": "5b0qj", + "col814": "94p3h", + "col815": "1w80b", + "col816": "nx8ja", + "col817": "ggaig", + "col818": "5h1o6", + "col819": "mq2oh", + "col820": "uvq6d", + "col821": "zvvsg", + "col822": "07lxj", + "col823": "cgu4t", + "col824": "l7ql9", + "col825": "59rc9", + "col826": "x6cwi", + "col827": "5rsyn", + "col828": "pwum3", + "col829": "gfxbk", + "col830": "7uyy0", + "col831": "wtler", + "col832": "76p36", + "col833": "zoufd", + "col834": "f6ig5", + "col835": "f0zwc", + "col836": "yd9dv", + "col837": "cq11m", + "col838": "qn9y5", + "col839": "vo93w", + "col840": "lpts1", + "col841": "ckn50", + "col842": "phy6x", + "col843": "4xbwm", + "col844": "kokz2", + "col845": "47dim", + "col846": "uy82z", + "col847": "rxu9z", + "col848": "6wvu5", + "col849": "v6g9a", + "col850": "dayl5", + "col851": "4nl01", + "col852": "naugp", + "col853": "joq9v", + "col854": "h0jyz", + "col855": "6xhgs", + "col856": "2r470", + "col857": "w3caw", + "col858": "xe3so", + "col859": "aljnp", + "col860": "xsx1s", + "col861": "3txmj", + "col862": "sxarf", + "col863": "3j7ge", + "col864": "era4n", + "col865": "doqll", + "col866": "hcfaj", + "col867": "yab77", + "col868": "1a9jg", + "col869": "t24be", + "col870": "whhda", + "col871": "l13c4", + "col872": "197p6", + "col873": "pu8c6", + "col874": "opzxz", + "col875": "6whci", + "col876": "c1dlu", + "col877": "931gh", + "col878": "20vc3", + "col879": "6rbld", + "col880": "3ud00", + "col881": "v8cg9", + "col882": "t5mgw", + "col883": "chcgd", + "col884": "s84ld", + "col885": "0h729", + "col886": "g35ox", + "col887": "owtmg", + "col888": "5adm2", + "col889": "2xvlf", + "col890": "tghaa", + "col891": "jtd1x", + "col892": "p18o2", + "col893": "hqspf", + "col894": "devhx", + "col895": "nf9j2", + "col896": "5xvtv", + "col897": "8r4oj", + "col898": "tpmfm", + "col899": "i7las", + "col900": "0phez", + "col901": "x19kl", + "col902": "8fd6x", + "col903": "d97s2", + "col904": "9z96l", + "col905": "eq7id", + "col906": "fyjd2", + "col907": "45c19", + "col908": "gaw58", + "col909": "vofi7", + "col910": "l8wrc", + "col911": "vv8lp", + "col912": "jkw21", + "col913": "06aa0", + "col914": "rsla3", + "col915": "tyeo8", + "col916": "7uems", + "col917": "f28zu", + "col918": "y9fka", + "col919": "4enj0", + "col920": "klg53", + "col921": "pkapa", + "col922": "intba", + "col923": "jx703", + "col924": "9emys", + "col925": "kstob", + "col926": "11h8s", + "col927": "43upl", + "col928": "7sgkq", + "col929": "h3xz4", + "col930": "7z7z0", + "col931": "nkodu", + "col932": "cuvfi", + "col933": "bes2w", + "col934": "o7j1n", + "col935": "cstyi", + "col936": "lphso", + "col937": "j6i22", + "col938": "2xys3", + "col939": "y3r8s", + "col940": "1v0q8", + "col941": "d0ujp", + "col942": "7pkip", + "col943": "rl57i", + "col944": "aakff", + "col945": "kcb2s", + "col946": "ssd0p", + "col947": "w4zcc", + "col948": "n6yw5", + "col949": "7ch00", + "col950": "1yov0", + "col951": "fmd2d", + "col952": "tgu4z", + "col953": "wfadh", + "col954": "9jrbe", + "col955": "dltvs", + "col956": "iv58x", + "col957": "u1t12", + "col958": "tsm0c", + "col959": "4drpd", + "col960": "epmq7", + "col961": "m7nrr", + "col962": "2cxfw", + "col963": "fwfqa", + "col964": "6o64x", + "col965": "go1l0", + "col966": "8wyhd", + "col967": "3au50", + "col968": "8qnbo", + "col969": "u15z6", + "col970": "6bbv9", + "col971": "73zou", + "col972": "so1q4", + "col973": "7rn8e", + "col974": "fxwt7", + "col975": "kxejd", + "col976": "k2mwc", + "col977": "9arkl", + "col978": "mjzwi", + "col979": "qb9vz", + "col980": "s2bxw", + "col981": "faunr", + "col982": "rp3ei", + "col983": "re8ld", + "col984": "ergqn", + "col985": "620v4", + "col986": "q8v48", + "col987": "oifek", + "col988": "16fvq", + "col989": "i0bsh", + "col990": "ef7is", + "col991": "s5z5u", + "col992": "kelhi", + "col993": "ho0l3", + "col994": "yay6r", + "col995": "h0h9y", + "col996": "gw4k4", + "col997": "n8lv5", + "col998": "9v1iw", + "col999": "vyp5c" + }, + { + "name": "Margarita Wise", + "gender": "female", + "col0": "wg6oc", + "col1": "meuwo", + "col2": "uwe8q", + "col3": "ekjgp", + "col4": "od36g", + "col5": "3oer3", + "col6": "wx24y", + "col7": "npdov", + "col8": "5641k", + "col9": "zhlb3", + "col10": "sre1e", + "col11": "pxkt8", + "col12": "gogsw", + "col13": "e3gwb", + "col14": "5fdsb", + "col15": "rukkm", + "col16": "23d9r", + "col17": "rn3kf", + "col18": "4ht1u", + "col19": "ppu93", + "col20": "5t86q", + "col21": "8z74d", + "col22": "njq4w", + "col23": "zbuwx", + "col24": "xy0gp", + "col25": "9b589", + "col26": "tm0eh", + "col27": "jzfcv", + "col28": "x80p5", + "col29": "gn52z", + "col30": "ml63a", + "col31": "w18ci", + "col32": "yuug8", + "col33": "xvx8e", + "col34": "rp0m9", + "col35": "mjfqs", + "col36": "zvkv4", + "col37": "rbkww", + "col38": "rg6km", + "col39": "vd8uz", + "col40": "3frec", + "col41": "aavah", + "col42": "7miic", + "col43": "32e3i", + "col44": "w9g4a", + "col45": "ljtbo", + "col46": "qb3l1", + "col47": "11siu", + "col48": "jqiis", + "col49": "qqx61", + "col50": "smtw2", + "col51": "nun7q", + "col52": "wktcl", + "col53": "nxykm", + "col54": "afr1c", + "col55": "iojpy", + "col56": "w49ig", + "col57": "yy0bd", + "col58": "rgp2t", + "col59": "ev8ws", + "col60": "wu1pw", + "col61": "qikay", + "col62": "vugxc", + "col63": "i1xzc", + "col64": "dwrvv", + "col65": "4lx78", + "col66": "vrejq", + "col67": "u2hw9", + "col68": "tq7kh", + "col69": "r8vb3", + "col70": "2nf7p", + "col71": "48u8n", + "col72": "05udi", + "col73": "2rl9i", + "col74": "41xn6", + "col75": "94kym", + "col76": "y9hs6", + "col77": "qz7ef", + "col78": "nychq", + "col79": "m3p2i", + "col80": "jahu6", + "col81": "h640a", + "col82": "qxgm2", + "col83": "hfv6r", + "col84": "d04oi", + "col85": "n8tsf", + "col86": "jl61b", + "col87": "k9bvu", + "col88": "48myo", + "col89": "f7ei7", + "col90": "2i0wx", + "col91": "hjsvy", + "col92": "592at", + "col93": "7cfml", + "col94": "rxydu", + "col95": "3m3wt", + "col96": "6hqw0", + "col97": "ohrcd", + "col98": "9dcbt", + "col99": "mnapn", + "col100": "qjoao", + "col101": "a3gz0", + "col102": "rfs1d", + "col103": "gps9b", + "col104": "d2qxl", + "col105": "q1thg", + "col106": "c1mtx", + "col107": "qvja7", + "col108": "7p35e", + "col109": "llo6s", + "col110": "ohm6p", + "col111": "udj0m", + "col112": "cpnx1", + "col113": "gggt4", + "col114": "9s2y7", + "col115": "zk0yf", + "col116": "76qtu", + "col117": "d00gt", + "col118": "m4fii", + "col119": "u53qd", + "col120": "pwc8s", + "col121": "98m2t", + "col122": "sic48", + "col123": "fy80b", + "col124": "4swxy", + "col125": "vp3c8", + "col126": "1twqj", + "col127": "2sfvd", + "col128": "bo0ql", + "col129": "5jbtj", + "col130": "ipc10", + "col131": "656w8", + "col132": "0tncj", + "col133": "xnlum", + "col134": "bvonq", + "col135": "sa4x5", + "col136": "643v0", + "col137": "6ha3o", + "col138": "wwq71", + "col139": "nt3xi", + "col140": "k8w8y", + "col141": "d4u4z", + "col142": "8ins0", + "col143": "c2kgb", + "col144": "zsjm7", + "col145": "35dab", + "col146": "fbx9i", + "col147": "1u61z", + "col148": "x9hna", + "col149": "99xgx", + "col150": "bk3i4", + "col151": "ktzai", + "col152": "srner", + "col153": "eztrz", + "col154": "bwc8x", + "col155": "587eg", + "col156": "ymcm5", + "col157": "3dyyh", + "col158": "5b5hh", + "col159": "zxpcc", + "col160": "yzb40", + "col161": "m2gl5", + "col162": "14l5l", + "col163": "7a1hi", + "col164": "a9tvq", + "col165": "y9n1w", + "col166": "xyhhp", + "col167": "7ye0r", + "col168": "hqx9k", + "col169": "ud9cc", + "col170": "u8aid", + "col171": "kvqhe", + "col172": "gf5bs", + "col173": "iikne", + "col174": "sx5z8", + "col175": "4cgi4", + "col176": "sgc2a", + "col177": "suv9p", + "col178": "d6kx5", + "col179": "u8cqa", + "col180": "k8p13", + "col181": "7hq5v", + "col182": "w94c2", + "col183": "m3w7g", + "col184": "6gd69", + "col185": "q2jhy", + "col186": "hfv1m", + "col187": "ubvat", + "col188": "gj0xk", + "col189": "ogemi", + "col190": "sny3y", + "col191": "gumfd", + "col192": "72u0t", + "col193": "ufv6i", + "col194": "wruu0", + "col195": "j9hdm", + "col196": "82ol9", + "col197": "avofc", + "col198": "7zknw", + "col199": "blznh", + "col200": "eljlp", + "col201": "oe8vh", + "col202": "mf19x", + "col203": "0358s", + "col204": "5oyfh", + "col205": "oofwk", + "col206": "hvl1k", + "col207": "xt0a0", + "col208": "kwzco", + "col209": "p8qct", + "col210": "3tds2", + "col211": "50h8p", + "col212": "y5hxm", + "col213": "97dvm", + "col214": "mzh6m", + "col215": "z9gnc", + "col216": "wboqb", + "col217": "596d5", + "col218": "x6ji4", + "col219": "0nlnb", + "col220": "piq2n", + "col221": "4lk0i", + "col222": "tasdx", + "col223": "6x7z3", + "col224": "4mrjz", + "col225": "qx5z5", + "col226": "2czvj", + "col227": "epdxk", + "col228": "u533h", + "col229": "ntufh", + "col230": "exzgu", + "col231": "ul1rp", + "col232": "j9o92", + "col233": "7dacl", + "col234": "xz9ag", + "col235": "azazu", + "col236": "xo1p3", + "col237": "g5w9e", + "col238": "mw3je", + "col239": "hs5vd", + "col240": "iwjj7", + "col241": "qedcg", + "col242": "8x8ib", + "col243": "fyez1", + "col244": "tczla", + "col245": "o70xb", + "col246": "h80sm", + "col247": "cdssj", + "col248": "9q1ms", + "col249": "yi430", + "col250": "z0krq", + "col251": "nlxfr", + "col252": "85aan", + "col253": "ih5cc", + "col254": "le6s8", + "col255": "88r33", + "col256": "0et7j", + "col257": "oz6ec", + "col258": "uuqa1", + "col259": "3hyrm", + "col260": "pwjds", + "col261": "lshs1", + "col262": "o0gw7", + "col263": "2502t", + "col264": "o63ym", + "col265": "xgswv", + "col266": "nxzno", + "col267": "zs203", + "col268": "50bn7", + "col269": "iu82q", + "col270": "nvso4", + "col271": "xir4l", + "col272": "to1io", + "col273": "376o5", + "col274": "bzsyg", + "col275": "223nm", + "col276": "qaub4", + "col277": "43v14", + "col278": "x9mo3", + "col279": "i7ix7", + "col280": "l03rf", + "col281": "7sf75", + "col282": "rpfni", + "col283": "xia2b", + "col284": "gqhec", + "col285": "g4gjr", + "col286": "x0wyu", + "col287": "ryxlj", + "col288": "ip0dh", + "col289": "fvdwk", + "col290": "o8wqp", + "col291": "1p6jv", + "col292": "8oy25", + "col293": "wuunz", + "col294": "oev2f", + "col295": "r83is", + "col296": "4254i", + "col297": "0smrt", + "col298": "024xy", + "col299": "conxs", + "col300": "f53sg", + "col301": "kyiva", + "col302": "5yh4n", + "col303": "npe3y", + "col304": "p98ka", + "col305": "yik28", + "col306": "fpbxt", + "col307": "jn7bm", + "col308": "n3ckh", + "col309": "2yx7g", + "col310": "fih8v", + "col311": "9qsmy", + "col312": "fseay", + "col313": "sz0hz", + "col314": "h0f9r", + "col315": "lak9a", + "col316": "1x8yy", + "col317": "rpe36", + "col318": "lu2nd", + "col319": "phm0p", + "col320": "vx8jl", + "col321": "o22hj", + "col322": "clj3e", + "col323": "xapal", + "col324": "46bhy", + "col325": "8zcju", + "col326": "dttmd", + "col327": "8fiv3", + "col328": "sqx44", + "col329": "nli0h", + "col330": "93j6o", + "col331": "e84zi", + "col332": "is8cg", + "col333": "s6fmk", + "col334": "ix7k9", + "col335": "iz1iy", + "col336": "lf96e", + "col337": "0dkkg", + "col338": "j6p92", + "col339": "7t1pt", + "col340": "azmm9", + "col341": "bzrd5", + "col342": "hn7dh", + "col343": "dwk6y", + "col344": "pj7w2", + "col345": "h9t91", + "col346": "dmy39", + "col347": "h5zo9", + "col348": "4i7db", + "col349": "f2v3r", + "col350": "xwvno", + "col351": "a0yed", + "col352": "m8kj4", + "col353": "36kso", + "col354": "wshh2", + "col355": "bdkur", + "col356": "tgwnv", + "col357": "jgv7t", + "col358": "c7xcw", + "col359": "n1uxy", + "col360": "vohzy", + "col361": "pmzw0", + "col362": "xxi5d", + "col363": "f71w5", + "col364": "02aya", + "col365": "jzedv", + "col366": "9xgf4", + "col367": "t52bk", + "col368": "yfjpc", + "col369": "8y6do", + "col370": "g2ust", + "col371": "29vrd", + "col372": "iwgdp", + "col373": "latbl", + "col374": "6i6hp", + "col375": "fthlk", + "col376": "o7psk", + "col377": "bfbmz", + "col378": "kfijj", + "col379": "e9drl", + "col380": "h81io", + "col381": "9m5al", + "col382": "dc963", + "col383": "338ke", + "col384": "f1he2", + "col385": "ox3rv", + "col386": "wi6gn", + "col387": "2spp9", + "col388": "yb9vl", + "col389": "b1b2s", + "col390": "g4122", + "col391": "j2vh0", + "col392": "beayz", + "col393": "v5hzh", + "col394": "scl3u", + "col395": "w5pqs", + "col396": "lx117", + "col397": "pebu5", + "col398": "qposq", + "col399": "ow8rb", + "col400": "xmrin", + "col401": "nzqut", + "col402": "1ko3y", + "col403": "liy1f", + "col404": "83gcm", + "col405": "mwi4g", + "col406": "fcbre", + "col407": "24zak", + "col408": "gqesd", + "col409": "t6ucc", + "col410": "17iqq", + "col411": "nuvr0", + "col412": "caelr", + "col413": "qifiq", + "col414": "ud1zo", + "col415": "vwg4j", + "col416": "heent", + "col417": "t8r3k", + "col418": "km2wi", + "col419": "tp09x", + "col420": "oba2x", + "col421": "1zxc6", + "col422": "83qvw", + "col423": "lihou", + "col424": "2kty2", + "col425": "25a1v", + "col426": "6bn8h", + "col427": "ck6sv", + "col428": "m9iuh", + "col429": "u8rcz", + "col430": "xhk91", + "col431": "56l5g", + "col432": "20xnd", + "col433": "n8ias", + "col434": "mibnj", + "col435": "cixmc", + "col436": "3w9e0", + "col437": "jfpml", + "col438": "t0lf9", + "col439": "d48s3", + "col440": "stc9i", + "col441": "s0aml", + "col442": "thvux", + "col443": "6xjml", + "col444": "is3dg", + "col445": "kcnfq", + "col446": "deazb", + "col447": "l24dr", + "col448": "maee4", + "col449": "190qj", + "col450": "ked92", + "col451": "q6kp7", + "col452": "w2emd", + "col453": "l3k13", + "col454": "gsf1j", + "col455": "gttcj", + "col456": "j7f58", + "col457": "dqzvu", + "col458": "fw963", + "col459": "wiwv9", + "col460": "lpnfy", + "col461": "ejr1x", + "col462": "sucda", + "col463": "dqoud", + "col464": "h1d6o", + "col465": "y8d6z", + "col466": "agajj", + "col467": "pidq7", + "col468": "5s88q", + "col469": "q3evq", + "col470": "vxgon", + "col471": "qn17k", + "col472": "do5yr", + "col473": "hkcgd", + "col474": "3xher", + "col475": "hrf11", + "col476": "poch6", + "col477": "f71n9", + "col478": "ab3nk", + "col479": "xe6tz", + "col480": "r3xkz", + "col481": "z7ayw", + "col482": "rrjcy", + "col483": "bq7b3", + "col484": "vmgcp", + "col485": "goeti", + "col486": "o2ulj", + "col487": "dur11", + "col488": "6df2z", + "col489": "6nzn4", + "col490": "d8khk", + "col491": "eskr1", + "col492": "t8jr8", + "col493": "sdm89", + "col494": "lz6gc", + "col495": "rjiyh", + "col496": "5rokc", + "col497": "2mhp9", + "col498": "uhhhx", + "col499": "0nnxc", + "col500": "kirhz", + "col501": "lich2", + "col502": "spyqn", + "col503": "tczij", + "col504": "k82nx", + "col505": "mlaw8", + "col506": "7ue1e", + "col507": "0go3q", + "col508": "7b9aa", + "col509": "stjru", + "col510": "67v31", + "col511": "lpjga", + "col512": "t0vp9", + "col513": "7rp91", + "col514": "cnvcx", + "col515": "mow3x", + "col516": "ciiyi", + "col517": "95k09", + "col518": "10jre", + "col519": "zlm1d", + "col520": "fr71u", + "col521": "extxo", + "col522": "p1sq4", + "col523": "zeh4e", + "col524": "lg1o3", + "col525": "zk2sg", + "col526": "9kkvy", + "col527": "eysez", + "col528": "b64tw", + "col529": "gxcf1", + "col530": "gvzip", + "col531": "whb4h", + "col532": "1t24w", + "col533": "ax0ma", + "col534": "7b6gu", + "col535": "lp4fe", + "col536": "zemta", + "col537": "qaw8k", + "col538": "a10ax", + "col539": "46v6e", + "col540": "licp1", + "col541": "5qcw1", + "col542": "exh6b", + "col543": "yzr02", + "col544": "l1glf", + "col545": "xm3fc", + "col546": "i6mm9", + "col547": "tvihc", + "col548": "5moyi", + "col549": "unhl1", + "col550": "xyo28", + "col551": "rsn5j", + "col552": "ngb1s", + "col553": "ehssv", + "col554": "hmw3f", + "col555": "5izbo", + "col556": "3ri9p", + "col557": "c1ubs", + "col558": "4n33v", + "col559": "3xpfp", + "col560": "40vh6", + "col561": "jys66", + "col562": "svt85", + "col563": "3oibm", + "col564": "sahvu", + "col565": "h1xkk", + "col566": "5dpan", + "col567": "skek7", + "col568": "ca522", + "col569": "0bcve", + "col570": "00u34", + "col571": "t1ron", + "col572": "3uo2l", + "col573": "fjgle", + "col574": "adqx5", + "col575": "80zhp", + "col576": "mku2x", + "col577": "24fwa", + "col578": "jt64g", + "col579": "1l1hf", + "col580": "l1d4y", + "col581": "cmb5g", + "col582": "rxb30", + "col583": "nszz7", + "col584": "x54jw", + "col585": "qkgqr", + "col586": "ij25l", + "col587": "t1tl6", + "col588": "s7wjx", + "col589": "11je8", + "col590": "0acme", + "col591": "whwz6", + "col592": "fbu0y", + "col593": "jaa8g", + "col594": "acvm4", + "col595": "wwjoj", + "col596": "j3j2g", + "col597": "iazrc", + "col598": "zlpz0", + "col599": "lcle6", + "col600": "cwst6", + "col601": "ey93k", + "col602": "bipqa", + "col603": "bb0xv", + "col604": "68wqp", + "col605": "iuzg5", + "col606": "eoe9t", + "col607": "sgnrv", + "col608": "n8v1z", + "col609": "n12fi", + "col610": "o89q1", + "col611": "7cxlt", + "col612": "m4xpr", + "col613": "vnqox", + "col614": "vk09l", + "col615": "e43uj", + "col616": "rq2dw", + "col617": "hf2v6", + "col618": "zbkkw", + "col619": "h9uh9", + "col620": "5glcg", + "col621": "d3uw8", + "col622": "1hsgg", + "col623": "qhdeq", + "col624": "gxa4l", + "col625": "jimat", + "col626": "onn7r", + "col627": "q9fdm", + "col628": "cprep", + "col629": "efz37", + "col630": "c4cnl", + "col631": "txgzg", + "col632": "am0cj", + "col633": "1o041", + "col634": "jndb0", + "col635": "whx3k", + "col636": "7b7qs", + "col637": "k6om2", + "col638": "5c3pz", + "col639": "0uymk", + "col640": "gxma0", + "col641": "kktzx", + "col642": "pyqfu", + "col643": "umcjj", + "col644": "3c291", + "col645": "k3w3i", + "col646": "dv0yz", + "col647": "za5ok", + "col648": "v4wb6", + "col649": "zamxn", + "col650": "4s4sf", + "col651": "gj1v9", + "col652": "3x0fm", + "col653": "7mi2f", + "col654": "yrz8s", + "col655": "y7djz", + "col656": "chw2a", + "col657": "ho3ny", + "col658": "xqlrf", + "col659": "9cwyd", + "col660": "cv8w2", + "col661": "i5sz5", + "col662": "dkdmx", + "col663": "3hyhl", + "col664": "g2chd", + "col665": "ua9q9", + "col666": "cnrf9", + "col667": "es464", + "col668": "gpurw", + "col669": "ipsng", + "col670": "fqc12", + "col671": "d4ek8", + "col672": "cguek", + "col673": "1d0vu", + "col674": "j8a95", + "col675": "llrt6", + "col676": "tcifx", + "col677": "qtrcy", + "col678": "y85no", + "col679": "nbd14", + "col680": "9b2ik", + "col681": "cghsh", + "col682": "zmc5e", + "col683": "mt7z6", + "col684": "inhee", + "col685": "xj92d", + "col686": "uj2mh", + "col687": "xpe2y", + "col688": "g0vst", + "col689": "ycrtu", + "col690": "vmhi3", + "col691": "s08zx", + "col692": "2oeu4", + "col693": "fr749", + "col694": "vq219", + "col695": "w3wq3", + "col696": "ze6em", + "col697": "k87qz", + "col698": "zy9ke", + "col699": "qb2jr", + "col700": "dgmkx", + "col701": "gnibc", + "col702": "wt87v", + "col703": "dz74h", + "col704": "lv5z0", + "col705": "ht4aa", + "col706": "hdahq", + "col707": "t62pw", + "col708": "ye0ne", + "col709": "s23z2", + "col710": "l0xac", + "col711": "7n6l2", + "col712": "pufig", + "col713": "2yd78", + "col714": "aoh6d", + "col715": "tvdc3", + "col716": "7s7qm", + "col717": "u9udo", + "col718": "kktl7", + "col719": "h4w00", + "col720": "gye5w", + "col721": "0icqx", + "col722": "qnncb", + "col723": "d0s8o", + "col724": "ujr16", + "col725": "99j06", + "col726": "7m340", + "col727": "sxhk7", + "col728": "5d1z5", + "col729": "4k5tp", + "col730": "shx7t", + "col731": "cbpb1", + "col732": "qd5nu", + "col733": "0wku9", + "col734": "dqgu7", + "col735": "uaa3n", + "col736": "eip3x", + "col737": "arhf0", + "col738": "2f9y1", + "col739": "z44aw", + "col740": "bel3b", + "col741": "7245d", + "col742": "uy0nr", + "col743": "ishin", + "col744": "jbu6y", + "col745": "29f6h", + "col746": "dc5b4", + "col747": "rvc36", + "col748": "rdbv1", + "col749": "nl6ig", + "col750": "umefr", + "col751": "k8mro", + "col752": "yfjul", + "col753": "t1vga", + "col754": "j8jxu", + "col755": "ncdg1", + "col756": "fk2lo", + "col757": "2zfkw", + "col758": "ev1a0", + "col759": "f75h3", + "col760": "lhc4f", + "col761": "vv2dc", + "col762": "orcch", + "col763": "yquqq", + "col764": "lw5hs", + "col765": "1enn4", + "col766": "gy0lb", + "col767": "ai4by", + "col768": "n7m5c", + "col769": "a72xd", + "col770": "8yr5p", + "col771": "4vwh8", + "col772": "xfrb5", + "col773": "qkn5d", + "col774": "qwv29", + "col775": "7sr2b", + "col776": "gm7eo", + "col777": "lrjlp", + "col778": "48i7i", + "col779": "6geel", + "col780": "couuq", + "col781": "rqidz", + "col782": "qva9c", + "col783": "r82wp", + "col784": "9rgs1", + "col785": "xtowl", + "col786": "9yzw9", + "col787": "xz2ag", + "col788": "ocl5t", + "col789": "2mapt", + "col790": "9srpu", + "col791": "7yhts", + "col792": "6rlbu", + "col793": "x07up", + "col794": "qik9n", + "col795": "vw8a1", + "col796": "rbvfm", + "col797": "mv82k", + "col798": "m58sf", + "col799": "ey0hv", + "col800": "964og", + "col801": "29xko", + "col802": "tiqxc", + "col803": "6wj72", + "col804": "uxwt4", + "col805": "72k7k", + "col806": "a8mwa", + "col807": "bbq3k", + "col808": "erw99", + "col809": "dxjxq", + "col810": "bpjg4", + "col811": "9m846", + "col812": "a2dip", + "col813": "komyg", + "col814": "s81m0", + "col815": "9isdz", + "col816": "uh54f", + "col817": "ze59w", + "col818": "ytudz", + "col819": "az5an", + "col820": "763jw", + "col821": "y18y5", + "col822": "o98c8", + "col823": "icj9r", + "col824": "20nmj", + "col825": "htzk2", + "col826": "5kgcc", + "col827": "o3gyf", + "col828": "5g87r", + "col829": "odara", + "col830": "b2v4h", + "col831": "u8lge", + "col832": "r35kj", + "col833": "2uruf", + "col834": "545yg", + "col835": "sw0yg", + "col836": "ke06k", + "col837": "n67n0", + "col838": "f9fby", + "col839": "dkygq", + "col840": "ncic7", + "col841": "3ujbs", + "col842": "s8eta", + "col843": "4mwdb", + "col844": "sm9qd", + "col845": "yo5pd", + "col846": "o7epw", + "col847": "0y2pq", + "col848": "93748", + "col849": "ereoq", + "col850": "5yylt", + "col851": "8ddt1", + "col852": "92peq", + "col853": "cve9b", + "col854": "vegyj", + "col855": "1b7z6", + "col856": "11ltg", + "col857": "hvo20", + "col858": "x094s", + "col859": "ipiyr", + "col860": "66hri", + "col861": "csuw2", + "col862": "dawq7", + "col863": "phtle", + "col864": "gwgtw", + "col865": "ssjf1", + "col866": "ygoct", + "col867": "50007", + "col868": "58vqq", + "col869": "vjlm4", + "col870": "9g69j", + "col871": "zx7dn", + "col872": "67mib", + "col873": "qalgk", + "col874": "0ca2r", + "col875": "sn6ys", + "col876": "jod9c", + "col877": "htseo", + "col878": "3253m", + "col879": "02jl4", + "col880": "5lkaf", + "col881": "7rfpz", + "col882": "jn3yl", + "col883": "mm3b9", + "col884": "fp4rs", + "col885": "wcgk3", + "col886": "cu1wc", + "col887": "o9v7z", + "col888": "zlq6a", + "col889": "n0gmi", + "col890": "70lih", + "col891": "wc6hv", + "col892": "tt6cy", + "col893": "fn2z7", + "col894": "l0squ", + "col895": "8fepm", + "col896": "j2pn5", + "col897": "yg0ys", + "col898": "k530f", + "col899": "ht9p5", + "col900": "6r7w0", + "col901": "u201v", + "col902": "xuoni", + "col903": "8htg3", + "col904": "5oiko", + "col905": "r7nsc", + "col906": "llzzw", + "col907": "kkkmn", + "col908": "x916q", + "col909": "25566", + "col910": "p0cqc", + "col911": "1ip07", + "col912": "nj9gh", + "col913": "j90zr", + "col914": "fq4k4", + "col915": "uxld6", + "col916": "vfs30", + "col917": "qpv73", + "col918": "dxrgq", + "col919": "uvcwe", + "col920": "55lwj", + "col921": "ye6ka", + "col922": "g8x3v", + "col923": "sf55g", + "col924": "3ep86", + "col925": "xepp0", + "col926": "prndi", + "col927": "783he", + "col928": "vey6a", + "col929": "yofgd", + "col930": "t1f84", + "col931": "6y5s5", + "col932": "xf8rl", + "col933": "4r4j0", + "col934": "5ksmn", + "col935": "dllku", + "col936": "2sn7i", + "col937": "1frue", + "col938": "7rnxb", + "col939": "3buyu", + "col940": "iulzx", + "col941": "vmea1", + "col942": "4h3xe", + "col943": "71dfu", + "col944": "wo9ux", + "col945": "5yi6l", + "col946": "yi14z", + "col947": "wbppc", + "col948": "p48he", + "col949": "evr3l", + "col950": "7o20b", + "col951": "0as4q", + "col952": "llutb", + "col953": "298eg", + "col954": "5o4ve", + "col955": "rb0sg", + "col956": "ig04h", + "col957": "806jj", + "col958": "jbjm5", + "col959": "58iyb", + "col960": "4qv7x", + "col961": "0bl5n", + "col962": "2ugqp", + "col963": "okrn5", + "col964": "b65tu", + "col965": "167af", + "col966": "1u6v9", + "col967": "j9zm8", + "col968": "kz47q", + "col969": "ua1t7", + "col970": "miqlc", + "col971": "9a29f", + "col972": "lvsbm", + "col973": "66c17", + "col974": "vck0r", + "col975": "iqfv6", + "col976": "bzv2p", + "col977": "n34g9", + "col978": "dhbtw", + "col979": "pi9tb", + "col980": "tb5l7", + "col981": "gt2r2", + "col982": "dt99r", + "col983": "2i3ty", + "col984": "ds6uq", + "col985": "lkofi", + "col986": "frarv", + "col987": "co6l2", + "col988": "qgp6u", + "col989": "ioof0", + "col990": "zpu92", + "col991": "b8ztd", + "col992": "pmhaj", + "col993": "qs7qo", + "col994": "yq2ev", + "col995": "pcfxg", + "col996": "cpi3s", + "col997": "a4r47", + "col998": "72yrj", + "col999": "qtwwb" + }, + { + "name": "Pearl Page", + "gender": "female", + "col0": "0bj0c", + "col1": "2cc2v", + "col2": "mmme2", + "col3": "3xg60", + "col4": "hj5cz", + "col5": "aydty", + "col6": "hs958", + "col7": "epi69", + "col8": "u70z4", + "col9": "jlfs3", + "col10": "sretz", + "col11": "uo4lu", + "col12": "f16fq", + "col13": "v2b5s", + "col14": "36qeh", + "col15": "k3oen", + "col16": "1d98k", + "col17": "xt5o5", + "col18": "yng3b", + "col19": "nffo1", + "col20": "wpnpy", + "col21": "mi6lj", + "col22": "zc6pj", + "col23": "qsx5r", + "col24": "l7z4b", + "col25": "lpwkn", + "col26": "lc5y8", + "col27": "8d19g", + "col28": "nl4qb", + "col29": "mt7qs", + "col30": "rufls", + "col31": "ipop0", + "col32": "24ww4", + "col33": "sku4u", + "col34": "2sg92", + "col35": "j4hf5", + "col36": "fbhlc", + "col37": "txqbq", + "col38": "xzoy5", + "col39": "ekoaa", + "col40": "fyjrz", + "col41": "94guz", + "col42": "ne96o", + "col43": "9dcuy", + "col44": "bfo54", + "col45": "1wvtv", + "col46": "tap0n", + "col47": "ph4hw", + "col48": "42y0v", + "col49": "fuoee", + "col50": "8s2y4", + "col51": "aa3zz", + "col52": "2qpcv", + "col53": "n6ixg", + "col54": "6v829", + "col55": "c6h7w", + "col56": "1rrpy", + "col57": "gqe89", + "col58": "j1tie", + "col59": "h2d8t", + "col60": "p75c3", + "col61": "a5us6", + "col62": "z6lsm", + "col63": "nbpze", + "col64": "6vgoe", + "col65": "r6hxf", + "col66": "aqnjy", + "col67": "bcqj6", + "col68": "aae8v", + "col69": "5vg9p", + "col70": "adst0", + "col71": "1ycd9", + "col72": "y84vl", + "col73": "3tyxa", + "col74": "s6bp9", + "col75": "32ofz", + "col76": "w0cb6", + "col77": "h8xs4", + "col78": "dbbnm", + "col79": "j0lj6", + "col80": "y8zk5", + "col81": "fqicr", + "col82": "9tw7w", + "col83": "5946b", + "col84": "zazea", + "col85": "ft4hw", + "col86": "bhprc", + "col87": "np5xn", + "col88": "qw79r", + "col89": "jtwoc", + "col90": "1g6nz", + "col91": "md5en", + "col92": "s1dv2", + "col93": "3rpts", + "col94": "5onbu", + "col95": "5q54f", + "col96": "j0a4t", + "col97": "9n7ch", + "col98": "idpae", + "col99": "go8u4", + "col100": "tng1l", + "col101": "duccs", + "col102": "288dx", + "col103": "84rgv", + "col104": "g30k1", + "col105": "7u83e", + "col106": "nu5sn", + "col107": "cs6rp", + "col108": "4bn1j", + "col109": "3e4em", + "col110": "xmv5p", + "col111": "nscry", + "col112": "e2plw", + "col113": "w0kto", + "col114": "057gm", + "col115": "ft82z", + "col116": "hioi7", + "col117": "cte5m", + "col118": "zhch0", + "col119": "ifugq", + "col120": "ry2cw", + "col121": "dd8lc", + "col122": "nnfs6", + "col123": "t1qu7", + "col124": "vdrvo", + "col125": "bzsub", + "col126": "4wb75", + "col127": "1gvf4", + "col128": "wyypn", + "col129": "epd20", + "col130": "l3xj5", + "col131": "1pxbn", + "col132": "qqm2j", + "col133": "jk08e", + "col134": "pyef7", + "col135": "dqcbw", + "col136": "fjy66", + "col137": "c2v2g", + "col138": "atv07", + "col139": "aqeyj", + "col140": "uccxl", + "col141": "b39cy", + "col142": "j6005", + "col143": "6277b", + "col144": "2abiu", + "col145": "0uxrf", + "col146": "61mr4", + "col147": "95886", + "col148": "q4y07", + "col149": "2uyol", + "col150": "mbkez", + "col151": "oy1ek", + "col152": "ccc7s", + "col153": "f1vic", + "col154": "wbt98", + "col155": "xvse6", + "col156": "htk1x", + "col157": "4lskg", + "col158": "8mj50", + "col159": "czxcf", + "col160": "ux3kp", + "col161": "0r5yp", + "col162": "371cv", + "col163": "fpe0u", + "col164": "50wmt", + "col165": "bbc0q", + "col166": "v2rwf", + "col167": "tkc8x", + "col168": "5ve28", + "col169": "vomik", + "col170": "t5d1w", + "col171": "smkud", + "col172": "jlipk", + "col173": "oy3os", + "col174": "qn2fs", + "col175": "97r91", + "col176": "j2470", + "col177": "33li8", + "col178": "cakgs", + "col179": "s5mun", + "col180": "y6ucr", + "col181": "gq99d", + "col182": "ero2v", + "col183": "x3kxc", + "col184": "tqequ", + "col185": "4jk7u", + "col186": "17urg", + "col187": "brxii", + "col188": "hkmfg", + "col189": "9ytv0", + "col190": "8lg9t", + "col191": "9y7xz", + "col192": "nxxka", + "col193": "6n0u2", + "col194": "2os8s", + "col195": "s1fzs", + "col196": "k01qn", + "col197": "uuwj7", + "col198": "9jldn", + "col199": "2cw68", + "col200": "saizn", + "col201": "vqnnb", + "col202": "zbhj1", + "col203": "n05ds", + "col204": "69cbq", + "col205": "eeiaq", + "col206": "a49ho", + "col207": "ingf5", + "col208": "jygn1", + "col209": "waa04", + "col210": "5sxsk", + "col211": "lt53e", + "col212": "h94h1", + "col213": "0c4z5", + "col214": "zdxpr", + "col215": "izpzf", + "col216": "9sywt", + "col217": "ft082", + "col218": "7rcve", + "col219": "3a4m7", + "col220": "kh756", + "col221": "w65su", + "col222": "dn64r", + "col223": "xrsno", + "col224": "ly65f", + "col225": "oi5te", + "col226": "vxaq0", + "col227": "vb87q", + "col228": "wddza", + "col229": "8eshx", + "col230": "mivry", + "col231": "8z44p", + "col232": "ty0x7", + "col233": "hudej", + "col234": "o2jpz", + "col235": "q1qw9", + "col236": "lv3hx", + "col237": "8mkvu", + "col238": "6wja0", + "col239": "4685n", + "col240": "8dkgb", + "col241": "vxhk0", + "col242": "asmcv", + "col243": "od949", + "col244": "7jubj", + "col245": "ut5nf", + "col246": "mrch5", + "col247": "ca4j2", + "col248": "683ia", + "col249": "g4vhp", + "col250": "hcuzb", + "col251": "du2gu", + "col252": "x96nn", + "col253": "q4oot", + "col254": "kkzpi", + "col255": "5uk4m", + "col256": "136hd", + "col257": "1op0c", + "col258": "dbxqc", + "col259": "6v11y", + "col260": "tlq8a", + "col261": "uax1v", + "col262": "8mbuq", + "col263": "gvqns", + "col264": "nllzc", + "col265": "ri6y0", + "col266": "coi4e", + "col267": "acabf", + "col268": "pgly8", + "col269": "ksscc", + "col270": "3vjnq", + "col271": "9hdn0", + "col272": "51unj", + "col273": "pwboj", + "col274": "28s0t", + "col275": "afmgk", + "col276": "tfadh", + "col277": "bkibd", + "col278": "va115", + "col279": "2y1pi", + "col280": "5mmda", + "col281": "n58o7", + "col282": "0pqea", + "col283": "px4t2", + "col284": "gkuw0", + "col285": "86kv7", + "col286": "pzd6u", + "col287": "sioue", + "col288": "qbe1t", + "col289": "7x09y", + "col290": "zhoqe", + "col291": "2p05q", + "col292": "f1n3x", + "col293": "h6ofh", + "col294": "lb6c4", + "col295": "u5or1", + "col296": "fci3z", + "col297": "rimks", + "col298": "f7g0c", + "col299": "d51zp", + "col300": "jkbfm", + "col301": "wvoac", + "col302": "mwwvc", + "col303": "feiff", + "col304": "g8ujp", + "col305": "ywgaa", + "col306": "okjj5", + "col307": "55drl", + "col308": "u8079", + "col309": "ju0cv", + "col310": "rgzyp", + "col311": "8tnr6", + "col312": "uf6kc", + "col313": "8g9f9", + "col314": "lbd86", + "col315": "2j87u", + "col316": "ej4ji", + "col317": "7ur1k", + "col318": "gghhe", + "col319": "fydkj", + "col320": "js61r", + "col321": "hlfoa", + "col322": "a6d56", + "col323": "61l46", + "col324": "02ddi", + "col325": "lkyq3", + "col326": "v1mfv", + "col327": "8oc3o", + "col328": "rwql9", + "col329": "8pi8r", + "col330": "amwld", + "col331": "hyc54", + "col332": "a7t5c", + "col333": "qf49l", + "col334": "ojyoo", + "col335": "5kv57", + "col336": "d8dvh", + "col337": "8p5fo", + "col338": "avsx9", + "col339": "t0cn1", + "col340": "ya687", + "col341": "h6iem", + "col342": "lr0nu", + "col343": "ysil8", + "col344": "xpevm", + "col345": "nvghq", + "col346": "lxjfh", + "col347": "no4bx", + "col348": "zau69", + "col349": "v2qo5", + "col350": "npcvp", + "col351": "9ob4o", + "col352": "icgf3", + "col353": "ytj0y", + "col354": "s4oeu", + "col355": "j4vur", + "col356": "x3meh", + "col357": "sfvu2", + "col358": "byxa6", + "col359": "h06b4", + "col360": "f0a2v", + "col361": "fyczl", + "col362": "qwlov", + "col363": "7fzqr", + "col364": "upy8o", + "col365": "j4zcz", + "col366": "eiql7", + "col367": "f6m4i", + "col368": "mg0kx", + "col369": "nvh0e", + "col370": "ae9q5", + "col371": "6s6yb", + "col372": "3abr6", + "col373": "p4l3m", + "col374": "rjcmv", + "col375": "vu6jj", + "col376": "u7hqs", + "col377": "j5uyw", + "col378": "y2jv4", + "col379": "tjg5u", + "col380": "hzr8c", + "col381": "ao807", + "col382": "92d7k", + "col383": "zf4h4", + "col384": "e702k", + "col385": "ex54k", + "col386": "sa09q", + "col387": "8p6sg", + "col388": "rmiln", + "col389": "89gvv", + "col390": "l2j6o", + "col391": "had6e", + "col392": "ki67o", + "col393": "nx8nh", + "col394": "ln301", + "col395": "j6e1i", + "col396": "oqik0", + "col397": "84zzi", + "col398": "4p4g0", + "col399": "fb2gz", + "col400": "coswo", + "col401": "0396p", + "col402": "h61jr", + "col403": "9wc36", + "col404": "68vwc", + "col405": "3etvl", + "col406": "4jn7v", + "col407": "5k4z8", + "col408": "1a4g3", + "col409": "a8mon", + "col410": "c7znf", + "col411": "omnka", + "col412": "lbr0z", + "col413": "wtccp", + "col414": "nkzzl", + "col415": "dst4p", + "col416": "73a2m", + "col417": "odppr", + "col418": "gd3cf", + "col419": "oldww", + "col420": "ukvv5", + "col421": "2r1wr", + "col422": "8koej", + "col423": "1k92v", + "col424": "6ifil", + "col425": "rsbs5", + "col426": "mne8n", + "col427": "heapm", + "col428": "segc1", + "col429": "iany8", + "col430": "y53l6", + "col431": "s5m4b", + "col432": "55eiy", + "col433": "wv496", + "col434": "uuwfl", + "col435": "33dws", + "col436": "vlsau", + "col437": "my9jf", + "col438": "cqnq4", + "col439": "upen9", + "col440": "ci71j", + "col441": "879l9", + "col442": "spm8a", + "col443": "t4g3d", + "col444": "yxo6m", + "col445": "509e7", + "col446": "pcy7j", + "col447": "vu2fd", + "col448": "kfia9", + "col449": "2dvg3", + "col450": "1lwsn", + "col451": "ib25o", + "col452": "szotm", + "col453": "yzuew", + "col454": "0n1l0", + "col455": "jk00o", + "col456": "08sla", + "col457": "bl610", + "col458": "lzk6z", + "col459": "v2h2g", + "col460": "fxqy1", + "col461": "y6fj4", + "col462": "q23yo", + "col463": "1wq1f", + "col464": "7ib3j", + "col465": "hooll", + "col466": "bziow", + "col467": "w5jv1", + "col468": "llm9h", + "col469": "17233", + "col470": "qy76o", + "col471": "btx2x", + "col472": "zkjld", + "col473": "lr71n", + "col474": "8ud6e", + "col475": "j9zgl", + "col476": "1zi73", + "col477": "9edj0", + "col478": "0u64n", + "col479": "uzs05", + "col480": "zi53e", + "col481": "t0jha", + "col482": "0wequ", + "col483": "g7kt0", + "col484": "0g1tf", + "col485": "928or", + "col486": "qs04p", + "col487": "mo6bb", + "col488": "wnqlm", + "col489": "c8slf", + "col490": "afbrh", + "col491": "vjakv", + "col492": "mrdbu", + "col493": "6lhyy", + "col494": "vhvly", + "col495": "o00lk", + "col496": "k394p", + "col497": "rfpgf", + "col498": "bz2tr", + "col499": "p0wtp", + "col500": "jwddy", + "col501": "0nm35", + "col502": "0vfg0", + "col503": "ffqty", + "col504": "h20eg", + "col505": "0276v", + "col506": "8tom4", + "col507": "9d26z", + "col508": "vscxl", + "col509": "j8o3u", + "col510": "eu8ho", + "col511": "46qwz", + "col512": "ol7jq", + "col513": "ors4s", + "col514": "eymgo", + "col515": "uk7ne", + "col516": "w790l", + "col517": "dgx3a", + "col518": "rdcf6", + "col519": "ejywi", + "col520": "kaa97", + "col521": "y7kxf", + "col522": "vtab0", + "col523": "6hgto", + "col524": "jwknh", + "col525": "w9a5x", + "col526": "rzcjm", + "col527": "t72gd", + "col528": "qu0c0", + "col529": "fnmku", + "col530": "t65sp", + "col531": "9l7m0", + "col532": "pg4ch", + "col533": "von7h", + "col534": "l6z32", + "col535": "7mqo4", + "col536": "ijypz", + "col537": "6ljl0", + "col538": "lxddm", + "col539": "qh8ho", + "col540": "mptmh", + "col541": "f47vs", + "col542": "j478e", + "col543": "h7ks9", + "col544": "r2zgu", + "col545": "yg5ym", + "col546": "0k9h8", + "col547": "83cio", + "col548": "aeb0a", + "col549": "bju3y", + "col550": "l8mli", + "col551": "19arg", + "col552": "mirj9", + "col553": "tnrid", + "col554": "m1d1l", + "col555": "dj6le", + "col556": "qv775", + "col557": "glqaz", + "col558": "c7rn2", + "col559": "5jzy5", + "col560": "p8b26", + "col561": "ko0u2", + "col562": "z8u04", + "col563": "3hotv", + "col564": "ulo3d", + "col565": "uughw", + "col566": "l34ep", + "col567": "qodlw", + "col568": "wnu6e", + "col569": "chqbe", + "col570": "ggstk", + "col571": "8r89l", + "col572": "0sml4", + "col573": "lfz2t", + "col574": "gqku5", + "col575": "qy5wd", + "col576": "3m8pz", + "col577": "9hwfk", + "col578": "y18uk", + "col579": "zt9gx", + "col580": "8zlcu", + "col581": "z3ni6", + "col582": "eam50", + "col583": "j3mug", + "col584": "bdm0a", + "col585": "ytnca", + "col586": "6vwgz", + "col587": "ropw9", + "col588": "yer6c", + "col589": "d2quo", + "col590": "fxewi", + "col591": "515bv", + "col592": "qc6ei", + "col593": "8iloa", + "col594": "wjkyy", + "col595": "0xp72", + "col596": "ln3f2", + "col597": "1v358", + "col598": "dp433", + "col599": "3irnc", + "col600": "o47p5", + "col601": "xu9io", + "col602": "h2d8l", + "col603": "0uktw", + "col604": "6zb05", + "col605": "95v2o", + "col606": "dkcpp", + "col607": "vz00b", + "col608": "rhyx3", + "col609": "clkid", + "col610": "ncp3e", + "col611": "wtgph", + "col612": "2c33o", + "col613": "977ln", + "col614": "ful5b", + "col615": "nmghl", + "col616": "ltj0b", + "col617": "2tpen", + "col618": "951eg", + "col619": "wv1wg", + "col620": "gwyl9", + "col621": "unlvk", + "col622": "7rpox", + "col623": "83ixi", + "col624": "9sxlz", + "col625": "7qzbd", + "col626": "8gfcy", + "col627": "4uz3g", + "col628": "oi8zb", + "col629": "0bu4v", + "col630": "ianw8", + "col631": "ae0xv", + "col632": "acbgv", + "col633": "9rl8d", + "col634": "eu145", + "col635": "cjoeb", + "col636": "fnn5o", + "col637": "qtt9j", + "col638": "gzru5", + "col639": "dgatl", + "col640": "kwmxk", + "col641": "qf2ac", + "col642": "uwu98", + "col643": "0fuh0", + "col644": "0pk4w", + "col645": "c5lkb", + "col646": "i00ep", + "col647": "zucuh", + "col648": "369uf", + "col649": "jzf2g", + "col650": "0rbs8", + "col651": "dgsel", + "col652": "fbigx", + "col653": "tzydb", + "col654": "5c9vm", + "col655": "yhdrm", + "col656": "txhiz", + "col657": "lv4zj", + "col658": "26gsw", + "col659": "bzyq8", + "col660": "hlpwy", + "col661": "4j8zh", + "col662": "zo0rm", + "col663": "dybk6", + "col664": "nwqzg", + "col665": "p0u6x", + "col666": "gkf20", + "col667": "x7u31", + "col668": "38j7h", + "col669": "y4law", + "col670": "u19qd", + "col671": "pxun5", + "col672": "ikvu7", + "col673": "agdea", + "col674": "f9cu7", + "col675": "7j03x", + "col676": "06h6c", + "col677": "quhm6", + "col678": "j1wky", + "col679": "840qj", + "col680": "6ve43", + "col681": "nt1i5", + "col682": "0fuso", + "col683": "b9v80", + "col684": "9ir14", + "col685": "2aq2w", + "col686": "u3uvm", + "col687": "a19lv", + "col688": "1s1gr", + "col689": "2mgvr", + "col690": "qv2jd", + "col691": "mtt5b", + "col692": "qtzcs", + "col693": "h99c4", + "col694": "pyo86", + "col695": "w7cdk", + "col696": "nv8u9", + "col697": "y5kp7", + "col698": "nms4s", + "col699": "50mfg", + "col700": "pe6we", + "col701": "0a8rm", + "col702": "cjv5m", + "col703": "wg5cc", + "col704": "m0mpw", + "col705": "xwetw", + "col706": "i1fmx", + "col707": "80ixi", + "col708": "zt5fw", + "col709": "moc9w", + "col710": "f0aa0", + "col711": "44d4h", + "col712": "fn8f7", + "col713": "23338", + "col714": "mowjo", + "col715": "g83ob", + "col716": "pjftf", + "col717": "kbzk6", + "col718": "0ie8i", + "col719": "z4k6r", + "col720": "kpvot", + "col721": "jl105", + "col722": "17rmm", + "col723": "mq2v0", + "col724": "h5bln", + "col725": "9u0ai", + "col726": "tver5", + "col727": "k3ev3", + "col728": "eshfl", + "col729": "qzwf7", + "col730": "me0sy", + "col731": "gcg86", + "col732": "6rab8", + "col733": "7u3og", + "col734": "phcwl", + "col735": "plt77", + "col736": "aymvk", + "col737": "j2lpy", + "col738": "v01j9", + "col739": "ej31m", + "col740": "logox", + "col741": "1pdcz", + "col742": "2v216", + "col743": "jnpuh", + "col744": "ngz4k", + "col745": "ti8zk", + "col746": "m9njt", + "col747": "9s2d5", + "col748": "21jvz", + "col749": "y9pnj", + "col750": "yy16w", + "col751": "m6dhd", + "col752": "9fw33", + "col753": "dbvu0", + "col754": "7dtlp", + "col755": "abkxl", + "col756": "hlxiv", + "col757": "o1pmp", + "col758": "svf33", + "col759": "50bge", + "col760": "ubtso", + "col761": "81ip6", + "col762": "093w7", + "col763": "hgay9", + "col764": "9iy63", + "col765": "4sj8d", + "col766": "lp84d", + "col767": "ry7c1", + "col768": "k2h98", + "col769": "pjg97", + "col770": "7zm3i", + "col771": "7awgy", + "col772": "u8oot", + "col773": "hmz0h", + "col774": "414yl", + "col775": "g5ve3", + "col776": "tonf2", + "col777": "3yktc", + "col778": "zq07o", + "col779": "afe9u", + "col780": "17omu", + "col781": "b03tq", + "col782": "p0qy2", + "col783": "trggu", + "col784": "a7muj", + "col785": "ma3ib", + "col786": "wohok", + "col787": "2l3gd", + "col788": "k80cx", + "col789": "8gsix", + "col790": "rg75m", + "col791": "xmzg6", + "col792": "r4a6u", + "col793": "negvt", + "col794": "z8ip0", + "col795": "q5tbf", + "col796": "x7iaz", + "col797": "kai36", + "col798": "gqbbu", + "col799": "hjws7", + "col800": "9zqxn", + "col801": "ccygc", + "col802": "t16rt", + "col803": "z6hcf", + "col804": "rtakh", + "col805": "01x4e", + "col806": "zdesg", + "col807": "ncjtf", + "col808": "tzz8a", + "col809": "kzuo9", + "col810": "3n4i6", + "col811": "ezfdr", + "col812": "bqor1", + "col813": "8kg5e", + "col814": "7jkbr", + "col815": "8xlbz", + "col816": "8004a", + "col817": "8daej", + "col818": "1c7l7", + "col819": "7k82q", + "col820": "e5s8a", + "col821": "9d484", + "col822": "weowb", + "col823": "98y7g", + "col824": "shqz9", + "col825": "2tmwa", + "col826": "bvb1c", + "col827": "1fx0j", + "col828": "61vhv", + "col829": "1onxw", + "col830": "pmcfz", + "col831": "xdqh6", + "col832": "j0tja", + "col833": "8roy4", + "col834": "bcthe", + "col835": "dvzst", + "col836": "s7rek", + "col837": "xolwl", + "col838": "yysd6", + "col839": "jzn4w", + "col840": "w431w", + "col841": "jh921", + "col842": "crl9t", + "col843": "xi9hf", + "col844": "ckkxu", + "col845": "zjg5s", + "col846": "9w2t1", + "col847": "weocw", + "col848": "eewg7", + "col849": "pm5yi", + "col850": "b29gi", + "col851": "u05bh", + "col852": "hh42x", + "col853": "89qba", + "col854": "manur", + "col855": "bs239", + "col856": "1mzc0", + "col857": "9jnjh", + "col858": "eaafr", + "col859": "zitzu", + "col860": "x8lqc", + "col861": "t346g", + "col862": "95xt7", + "col863": "3sy27", + "col864": "nay6w", + "col865": "55zoc", + "col866": "h1czv", + "col867": "5vktg", + "col868": "75hqj", + "col869": "rvo1i", + "col870": "gaaoi", + "col871": "z7ct0", + "col872": "qe15c", + "col873": "wv5wl", + "col874": "atglr", + "col875": "e7khz", + "col876": "g66yv", + "col877": "y2i8l", + "col878": "m1lxo", + "col879": "w8ge5", + "col880": "3v5qk", + "col881": "hvngj", + "col882": "l8wpj", + "col883": "cypak", + "col884": "lleq1", + "col885": "0yji0", + "col886": "n858d", + "col887": "j0vfl", + "col888": "p568n", + "col889": "widcf", + "col890": "14i07", + "col891": "dkgb3", + "col892": "0e1jq", + "col893": "dfe4t", + "col894": "p1xty", + "col895": "uqfa6", + "col896": "cy9lp", + "col897": "ofgv4", + "col898": "ivmdx", + "col899": "lz18c", + "col900": "rhy5n", + "col901": "x9icf", + "col902": "d1xeo", + "col903": "ihy5u", + "col904": "us0pf", + "col905": "zjxgn", + "col906": "rbnqs", + "col907": "821gt", + "col908": "3dhu1", + "col909": "gj0pd", + "col910": "lyim3", + "col911": "gzw54", + "col912": "dqjwh", + "col913": "nv8l6", + "col914": "iyvil", + "col915": "ei26n", + "col916": "isu6h", + "col917": "qbu6q", + "col918": "k2no7", + "col919": "sdc5b", + "col920": "jina5", + "col921": "6wkrt", + "col922": "ra8yr", + "col923": "uuj4z", + "col924": "0uy67", + "col925": "6hcg6", + "col926": "d0cs4", + "col927": "p4379", + "col928": "to0pm", + "col929": "6qpab", + "col930": "ecg1n", + "col931": "dppwv", + "col932": "mn22s", + "col933": "runoo", + "col934": "55mct", + "col935": "mn8u3", + "col936": "wwczx", + "col937": "rmxsy", + "col938": "4s52s", + "col939": "0z75l", + "col940": "7cjsv", + "col941": "4xv43", + "col942": "tmckv", + "col943": "bwz1i", + "col944": "j22v6", + "col945": "c8zod", + "col946": "91nu7", + "col947": "8jj2q", + "col948": "ajrqg", + "col949": "7k74i", + "col950": "e7wdu", + "col951": "3e8yo", + "col952": "m409q", + "col953": "gqx9e", + "col954": "v6w5h", + "col955": "uwsz3", + "col956": "4a42s", + "col957": "4ymcz", + "col958": "5ssvs", + "col959": "3dqnb", + "col960": "pubfx", + "col961": "gx13y", + "col962": "eevxc", + "col963": "vc33t", + "col964": "r3ye8", + "col965": "ymnii", + "col966": "eeu3t", + "col967": "w4dc1", + "col968": "g3bez", + "col969": "il0ns", + "col970": "tf9ol", + "col971": "8tntb", + "col972": "xh554", + "col973": "aazd4", + "col974": "gruht", + "col975": "d8gon", + "col976": "ay8fg", + "col977": "pumwf", + "col978": "m7rsr", + "col979": "9m6gk", + "col980": "ivqep", + "col981": "8ks63", + "col982": "56xpz", + "col983": "dbnxy", + "col984": "yrlgm", + "col985": "f1h2e", + "col986": "b5zrs", + "col987": "dnv84", + "col988": "o91w4", + "col989": "ubtxm", + "col990": "3dbfw", + "col991": "gy1nw", + "col992": "sm6sa", + "col993": "ahxmu", + "col994": "84lg5", + "col995": "52i5n", + "col996": "p8gbk", + "col997": "isk8x", + "col998": "qwo06", + "col999": "88gs3" + }, + { + "name": "Collins Aguirre", + "gender": "male", + "col0": "phx4l", + "col1": "yp31c", + "col2": "b6gji", + "col3": "0ipb9", + "col4": "foowl", + "col5": "hzadf", + "col6": "pfno8", + "col7": "wknoc", + "col8": "nm0p8", + "col9": "t6iwx", + "col10": "z2jnn", + "col11": "vb0s9", + "col12": "2d1ws", + "col13": "1n5xn", + "col14": "hqb4z", + "col15": "5fu49", + "col16": "ub8do", + "col17": "xjke3", + "col18": "lwrvk", + "col19": "pvn3p", + "col20": "27k7m", + "col21": "rp4e7", + "col22": "4g0ad", + "col23": "29qnc", + "col24": "i9fcf", + "col25": "txq7v", + "col26": "3twtb", + "col27": "zdhy1", + "col28": "z7pmp", + "col29": "etn9u", + "col30": "qhoso", + "col31": "r7e9s", + "col32": "uvy86", + "col33": "egflb", + "col34": "oiwel", + "col35": "wty7o", + "col36": "mjqwu", + "col37": "7vh1k", + "col38": "mk5rg", + "col39": "o6fx9", + "col40": "rah56", + "col41": "73kco", + "col42": "9m3og", + "col43": "sy8rt", + "col44": "hbb0j", + "col45": "1dl58", + "col46": "g55zu", + "col47": "rl6up", + "col48": "eacwr", + "col49": "c3028", + "col50": "8qmba", + "col51": "whdrf", + "col52": "yo2qr", + "col53": "l4q8e", + "col54": "08vay", + "col55": "g6fd5", + "col56": "gny2q", + "col57": "2ec64", + "col58": "hxksq", + "col59": "wiz2d", + "col60": "bdig6", + "col61": "btxqf", + "col62": "iohdn", + "col63": "zvrsj", + "col64": "imebz", + "col65": "a1tx9", + "col66": "u52h7", + "col67": "9zfay", + "col68": "ebnmb", + "col69": "bmcyu", + "col70": "g6a18", + "col71": "jxkui", + "col72": "4deb1", + "col73": "74rs9", + "col74": "55t6o", + "col75": "6qhs5", + "col76": "u6vsq", + "col77": "lmbai", + "col78": "pgi39", + "col79": "zptlc", + "col80": "84bj1", + "col81": "30xbo", + "col82": "torwu", + "col83": "b3w7k", + "col84": "sqkww", + "col85": "dmlv9", + "col86": "h6aoi", + "col87": "xniav", + "col88": "4rd0d", + "col89": "26374", + "col90": "zw4vn", + "col91": "s40ua", + "col92": "i2u7h", + "col93": "gmzh8", + "col94": "1o0q8", + "col95": "itj48", + "col96": "d76g9", + "col97": "zjo2t", + "col98": "4y9ih", + "col99": "bbuk1", + "col100": "wiau6", + "col101": "y5319", + "col102": "4ijti", + "col103": "0ew44", + "col104": "ulhch", + "col105": "lopwr", + "col106": "q5yee", + "col107": "48nwm", + "col108": "tecpr", + "col109": "62mn9", + "col110": "uwszx", + "col111": "pqzhp", + "col112": "hpx3u", + "col113": "me175", + "col114": "g9mz2", + "col115": "vg4om", + "col116": "rghxi", + "col117": "knc9p", + "col118": "v4tw0", + "col119": "ylbq4", + "col120": "dli6v", + "col121": "mns1z", + "col122": "aqnx0", + "col123": "7l0nm", + "col124": "3usjz", + "col125": "7thel", + "col126": "gk9m5", + "col127": "01kr0", + "col128": "j0c0c", + "col129": "n46ge", + "col130": "jz6wm", + "col131": "szyfl", + "col132": "yhwof", + "col133": "h1643", + "col134": "0qjhf", + "col135": "h6b1j", + "col136": "z2qp9", + "col137": "6x3xc", + "col138": "n1b1b", + "col139": "jkwk6", + "col140": "58mce", + "col141": "y2boy", + "col142": "86p8q", + "col143": "t4eyl", + "col144": "vpydl", + "col145": "vom15", + "col146": "5dj15", + "col147": "eb09b", + "col148": "zptec", + "col149": "zzqiy", + "col150": "nas0d", + "col151": "vsv7e", + "col152": "jk50m", + "col153": "unbw5", + "col154": "m0njq", + "col155": "ncya2", + "col156": "yhc0l", + "col157": "xb8yq", + "col158": "j99og", + "col159": "fujhj", + "col160": "osaif", + "col161": "qisvy", + "col162": "sn18u", + "col163": "g5zus", + "col164": "unpc8", + "col165": "o9c8v", + "col166": "90dis", + "col167": "icijc", + "col168": "abaea", + "col169": "1jzda", + "col170": "swirk", + "col171": "kuhci", + "col172": "93eqh", + "col173": "7o1lf", + "col174": "onakg", + "col175": "ytt9c", + "col176": "qexxa", + "col177": "0j3ls", + "col178": "d31ta", + "col179": "kkqhr", + "col180": "gl6n1", + "col181": "oxnz9", + "col182": "013lm", + "col183": "hdtmq", + "col184": "s65eo", + "col185": "yjtd0", + "col186": "dfpwr", + "col187": "f6ib0", + "col188": "0fc9k", + "col189": "uvf5r", + "col190": "vi1vz", + "col191": "t16pr", + "col192": "jknjo", + "col193": "cw6sr", + "col194": "ytftn", + "col195": "exim1", + "col196": "g9sb2", + "col197": "k3tk9", + "col198": "0rqvc", + "col199": "ku5pm", + "col200": "27o4s", + "col201": "wybc1", + "col202": "55qts", + "col203": "79wgf", + "col204": "i5j5w", + "col205": "agkdb", + "col206": "z4d2j", + "col207": "sltdv", + "col208": "7d039", + "col209": "hgzns", + "col210": "l9bik", + "col211": "wqfxp", + "col212": "o1065", + "col213": "ibiyi", + "col214": "jzt0w", + "col215": "cbgtm", + "col216": "6ivyx", + "col217": "h6he4", + "col218": "bi16e", + "col219": "770qg", + "col220": "7u6gx", + "col221": "bbihq", + "col222": "j7vog", + "col223": "8n9ef", + "col224": "cjhve", + "col225": "0m1p0", + "col226": "cwh50", + "col227": "7mgbd", + "col228": "25dzx", + "col229": "vygac", + "col230": "ctuit", + "col231": "vse7g", + "col232": "1rtnz", + "col233": "itlkk", + "col234": "4tyz3", + "col235": "eggbu", + "col236": "ge49z", + "col237": "3s9qv", + "col238": "5j4kp", + "col239": "o4mn2", + "col240": "bmjev", + "col241": "4mfsy", + "col242": "j5r6d", + "col243": "q5xre", + "col244": "yil0j", + "col245": "v0hdb", + "col246": "07o2b", + "col247": "63885", + "col248": "u0ldb", + "col249": "avo0p", + "col250": "bli1j", + "col251": "iyyzp", + "col252": "k8xkm", + "col253": "ydds0", + "col254": "uvjbs", + "col255": "o67as", + "col256": "c4yuh", + "col257": "tugtf", + "col258": "jh645", + "col259": "sxcq5", + "col260": "kg007", + "col261": "vhw3x", + "col262": "ze126", + "col263": "8dlg3", + "col264": "24jrf", + "col265": "hhn7s", + "col266": "g4y4o", + "col267": "zjyee", + "col268": "ovru8", + "col269": "g7mo4", + "col270": "18x92", + "col271": "cwtv4", + "col272": "5yvh6", + "col273": "67so7", + "col274": "dp4gn", + "col275": "zpqj1", + "col276": "d8kt7", + "col277": "cuqil", + "col278": "1v70l", + "col279": "c0s2t", + "col280": "ujs0s", + "col281": "fn98r", + "col282": "3kexp", + "col283": "tsc6g", + "col284": "5hoxa", + "col285": "g4bcd", + "col286": "gkj0j", + "col287": "mc6up", + "col288": "dfcwp", + "col289": "dlv67", + "col290": "6j4nh", + "col291": "oz0qd", + "col292": "bpm4p", + "col293": "cp3pp", + "col294": "lksqw", + "col295": "66s8x", + "col296": "48q2m", + "col297": "pgxej", + "col298": "c8xam", + "col299": "wn8r7", + "col300": "kfmey", + "col301": "yd4e5", + "col302": "2jt7y", + "col303": "5c4nv", + "col304": "v2q5u", + "col305": "5b8er", + "col306": "9aory", + "col307": "1qp1s", + "col308": "xyz16", + "col309": "st5xc", + "col310": "xx0q2", + "col311": "c48vo", + "col312": "ins4q", + "col313": "3mix2", + "col314": "b8qs0", + "col315": "f4p1w", + "col316": "jvkir", + "col317": "pvp7v", + "col318": "j7kgi", + "col319": "okp6u", + "col320": "1joih", + "col321": "lan08", + "col322": "lu5eg", + "col323": "4eebr", + "col324": "s4poh", + "col325": "298c5", + "col326": "9zzet", + "col327": "s2px9", + "col328": "1e407", + "col329": "epi6i", + "col330": "4oits", + "col331": "tz16a", + "col332": "ej39d", + "col333": "ivt69", + "col334": "riiel", + "col335": "xurwu", + "col336": "lz0fz", + "col337": "fr14j", + "col338": "qaiph", + "col339": "rbjyp", + "col340": "wb1fv", + "col341": "j92nl", + "col342": "i68vt", + "col343": "03kae", + "col344": "rrr9b", + "col345": "rt13a", + "col346": "3yxlr", + "col347": "scitw", + "col348": "fepuk", + "col349": "p6y3p", + "col350": "ouodm", + "col351": "yqpme", + "col352": "8libf", + "col353": "l0a5a", + "col354": "k2hhm", + "col355": "566cj", + "col356": "ijr2n", + "col357": "ijxnd", + "col358": "ul3kp", + "col359": "jenlw", + "col360": "ecnf8", + "col361": "7422c", + "col362": "1kiqa", + "col363": "vz07a", + "col364": "von4v", + "col365": "qe034", + "col366": "vvtr2", + "col367": "1irl7", + "col368": "3n0gr", + "col369": "nu6x4", + "col370": "37p59", + "col371": "0wwof", + "col372": "0fez8", + "col373": "clza9", + "col374": "0k0mi", + "col375": "4lwe2", + "col376": "piz9y", + "col377": "erx5y", + "col378": "4h5zc", + "col379": "1h0id", + "col380": "55kes", + "col381": "cs51e", + "col382": "1mgeq", + "col383": "vtqwt", + "col384": "otbdi", + "col385": "vdd2b", + "col386": "3h2ya", + "col387": "iwgus", + "col388": "y6lr9", + "col389": "f40m6", + "col390": "evpuh", + "col391": "nb834", + "col392": "4s3wd", + "col393": "d6skc", + "col394": "8d9cn", + "col395": "5alp2", + "col396": "5re41", + "col397": "astwd", + "col398": "9g5sv", + "col399": "46bo5", + "col400": "ztku8", + "col401": "lezo5", + "col402": "nlp8f", + "col403": "r186m", + "col404": "wua3h", + "col405": "iwnx6", + "col406": "tq76j", + "col407": "i8xul", + "col408": "a6fur", + "col409": "adi54", + "col410": "wl7be", + "col411": "jzt49", + "col412": "gaqj2", + "col413": "rsp0k", + "col414": "q21c9", + "col415": "jfivc", + "col416": "u9ryz", + "col417": "jobhz", + "col418": "88s71", + "col419": "z2dcx", + "col420": "4mbq0", + "col421": "9v68v", + "col422": "hi962", + "col423": "ivkse", + "col424": "sfskh", + "col425": "js16b", + "col426": "mt7rw", + "col427": "5u9qp", + "col428": "q4jf7", + "col429": "75dbf", + "col430": "rqeui", + "col431": "7rbun", + "col432": "p1g7y", + "col433": "1qowx", + "col434": "d9kji", + "col435": "2wkzt", + "col436": "iu6fj", + "col437": "ar1ah", + "col438": "pmpjs", + "col439": "lj2n3", + "col440": "d2f7z", + "col441": "lp41a", + "col442": "10eje", + "col443": "ztbsk", + "col444": "dywu4", + "col445": "w280j", + "col446": "1v2sr", + "col447": "o4rx3", + "col448": "tt4wr", + "col449": "yao4h", + "col450": "aggf3", + "col451": "cvxba", + "col452": "mc0vj", + "col453": "u25y8", + "col454": "7zj0r", + "col455": "ct2pe", + "col456": "dpm95", + "col457": "3057g", + "col458": "kq0mc", + "col459": "ixdew", + "col460": "gss4c", + "col461": "ee1l1", + "col462": "ln7qg", + "col463": "jswi2", + "col464": "s2e4o", + "col465": "fzu3q", + "col466": "9t1tf", + "col467": "lmo3w", + "col468": "c1zfa", + "col469": "ae7nx", + "col470": "qxuy9", + "col471": "66uz4", + "col472": "utye5", + "col473": "abjjt", + "col474": "z1xlc", + "col475": "aeo8y", + "col476": "26h0t", + "col477": "dtlz0", + "col478": "j6cc8", + "col479": "sfzqu", + "col480": "osc02", + "col481": "6l05f", + "col482": "n2ydt", + "col483": "w52di", + "col484": "4t3v3", + "col485": "dj5fs", + "col486": "4hxpr", + "col487": "ciozd", + "col488": "1h885", + "col489": "fp5gf", + "col490": "x42nm", + "col491": "iwb1j", + "col492": "qm8p7", + "col493": "ffqyb", + "col494": "p3pou", + "col495": "yonwc", + "col496": "3qeah", + "col497": "wfjho", + "col498": "zroy6", + "col499": "mmg4t", + "col500": "0son5", + "col501": "ubt7d", + "col502": "6v97s", + "col503": "vqjqm", + "col504": "cnbi8", + "col505": "ir49v", + "col506": "qkkym", + "col507": "mthit", + "col508": "2madn", + "col509": "bvq09", + "col510": "b8e8l", + "col511": "j9iih", + "col512": "b8kc5", + "col513": "ipuho", + "col514": "3aq12", + "col515": "ap8tq", + "col516": "hwpdq", + "col517": "03a68", + "col518": "06tjl", + "col519": "aeaud", + "col520": "5726s", + "col521": "elrj5", + "col522": "rj3gx", + "col523": "wdhot", + "col524": "0loh3", + "col525": "q5h96", + "col526": "uegtw", + "col527": "ruo2b", + "col528": "7bhzh", + "col529": "zhr7l", + "col530": "lqh5t", + "col531": "ne429", + "col532": "4l3r6", + "col533": "swc1w", + "col534": "oaofr", + "col535": "elug7", + "col536": "xmned", + "col537": "byb3p", + "col538": "xsk73", + "col539": "efpcd", + "col540": "y0mbi", + "col541": "qkfui", + "col542": "st709", + "col543": "ky2av", + "col544": "cgv5n", + "col545": "dkx1a", + "col546": "if2m0", + "col547": "7xoca", + "col548": "r45tx", + "col549": "h3qc0", + "col550": "fyyf5", + "col551": "n1yfs", + "col552": "5w84h", + "col553": "lyknf", + "col554": "bis0l", + "col555": "rg6nn", + "col556": "9e7pm", + "col557": "eoz7w", + "col558": "6bvyc", + "col559": "q013u", + "col560": "mp6sq", + "col561": "hs269", + "col562": "plswt", + "col563": "8tamv", + "col564": "ibfw5", + "col565": "o5dfx", + "col566": "0mf4e", + "col567": "49ol9", + "col568": "qtj19", + "col569": "9rgng", + "col570": "7qzfa", + "col571": "qvnuw", + "col572": "wd6f5", + "col573": "ou35d", + "col574": "g302i", + "col575": "chwn2", + "col576": "f4l8j", + "col577": "6wo9g", + "col578": "rp7ez", + "col579": "cevww", + "col580": "24rqh", + "col581": "njg46", + "col582": "gtgec", + "col583": "cvp6f", + "col584": "o78nr", + "col585": "6n95w", + "col586": "ws12n", + "col587": "3d1x9", + "col588": "l3nz7", + "col589": "ui4hv", + "col590": "ixt7m", + "col591": "gtqys", + "col592": "799ak", + "col593": "go89b", + "col594": "8zf4j", + "col595": "vi25f", + "col596": "4hvis", + "col597": "sfosv", + "col598": "6ll4y", + "col599": "laxbv", + "col600": "osh96", + "col601": "1zi5t", + "col602": "2jeoy", + "col603": "t4gca", + "col604": "wnm2u", + "col605": "iadv3", + "col606": "2stnx", + "col607": "iknpx", + "col608": "6lu6h", + "col609": "2j9fp", + "col610": "71vpy", + "col611": "hnr9l", + "col612": "d3xq9", + "col613": "e2blp", + "col614": "asjzx", + "col615": "zb8za", + "col616": "jrnxl", + "col617": "meqno", + "col618": "uqpbl", + "col619": "ypeol", + "col620": "boh0b", + "col621": "bqi73", + "col622": "solzn", + "col623": "h61nr", + "col624": "mvzl9", + "col625": "6dtfg", + "col626": "yyhrq", + "col627": "t9m2r", + "col628": "51vxw", + "col629": "xx8w5", + "col630": "mysi3", + "col631": "ureyb", + "col632": "2q3cf", + "col633": "ks3ex", + "col634": "qal40", + "col635": "pchjs", + "col636": "mwl8j", + "col637": "u6u6m", + "col638": "116kg", + "col639": "05rs8", + "col640": "xpx27", + "col641": "34b7g", + "col642": "hqj9i", + "col643": "ptxbj", + "col644": "1t4w1", + "col645": "llyff", + "col646": "tevfi", + "col647": "evkmo", + "col648": "1fkn0", + "col649": "0bosh", + "col650": "b39jw", + "col651": "puq4e", + "col652": "7yzbl", + "col653": "ikx7o", + "col654": "7ya1d", + "col655": "ebunn", + "col656": "8g846", + "col657": "4a4wo", + "col658": "b8uxd", + "col659": "smt7r", + "col660": "ojqxf", + "col661": "iu6bj", + "col662": "1q7hi", + "col663": "k4hg0", + "col664": "liur1", + "col665": "6lvkp", + "col666": "de912", + "col667": "akbte", + "col668": "4h91z", + "col669": "hv549", + "col670": "7f326", + "col671": "g197q", + "col672": "z8egx", + "col673": "5rmvb", + "col674": "anksr", + "col675": "021mx", + "col676": "tpw20", + "col677": "jucp0", + "col678": "hz0p7", + "col679": "hioro", + "col680": "aws84", + "col681": "u7xu0", + "col682": "es2st", + "col683": "u0e4z", + "col684": "7iccf", + "col685": "em732", + "col686": "20v00", + "col687": "boekf", + "col688": "7n2i2", + "col689": "6ji2b", + "col690": "akj9y", + "col691": "xgcbf", + "col692": "5abb1", + "col693": "66urz", + "col694": "9qizh", + "col695": "y85sn", + "col696": "q2tv4", + "col697": "vqz0v", + "col698": "2r95u", + "col699": "eoyg0", + "col700": "zgkkm", + "col701": "sihme", + "col702": "gi6ie", + "col703": "awzaw", + "col704": "tuceu", + "col705": "seee6", + "col706": "z6j8n", + "col707": "j8q28", + "col708": "uucu4", + "col709": "ga12j", + "col710": "60gco", + "col711": "an0h5", + "col712": "ag3ch", + "col713": "0ley1", + "col714": "2kchv", + "col715": "1ith9", + "col716": "kk3if", + "col717": "faijn", + "col718": "gj26m", + "col719": "wt8ez", + "col720": "3wn3i", + "col721": "ccrtj", + "col722": "o1w63", + "col723": "rbais", + "col724": "7ju3j", + "col725": "vmp6f", + "col726": "9j4yk", + "col727": "14fok", + "col728": "n32cb", + "col729": "svr50", + "col730": "5f17z", + "col731": "ufaz0", + "col732": "0qxm9", + "col733": "y4tnh", + "col734": "j7fd1", + "col735": "a6haz", + "col736": "vl4t8", + "col737": "rq1h7", + "col738": "h9sg8", + "col739": "j9mp5", + "col740": "jkyww", + "col741": "o9jg6", + "col742": "yapyw", + "col743": "vhv8w", + "col744": "j6dzg", + "col745": "cffh7", + "col746": "st52n", + "col747": "6ys1u", + "col748": "pjlys", + "col749": "mobua", + "col750": "x37wn", + "col751": "g7br2", + "col752": "4hyo4", + "col753": "pt6yk", + "col754": "k7ojr", + "col755": "iewx4", + "col756": "6i4tc", + "col757": "ie41w", + "col758": "d3ipj", + "col759": "yj9e3", + "col760": "tle52", + "col761": "leyoa", + "col762": "lv77s", + "col763": "dzso6", + "col764": "ygc2v", + "col765": "hrf7y", + "col766": "voewp", + "col767": "6lk7x", + "col768": "kkdr7", + "col769": "krhqv", + "col770": "y2cq6", + "col771": "a081u", + "col772": "tbjc7", + "col773": "29a7d", + "col774": "7tk59", + "col775": "f8xqx", + "col776": "6zf98", + "col777": "1ekf4", + "col778": "13xqs", + "col779": "jd91w", + "col780": "528kv", + "col781": "jakei", + "col782": "e25b3", + "col783": "47rs1", + "col784": "xxls5", + "col785": "fvsa1", + "col786": "qnxrw", + "col787": "vegfd", + "col788": "8j7yd", + "col789": "k97qe", + "col790": "cxkul", + "col791": "53hu7", + "col792": "bwq05", + "col793": "cbcvq", + "col794": "608t3", + "col795": "h5ngp", + "col796": "taxfn", + "col797": "r4dbz", + "col798": "5ed0o", + "col799": "a57gr", + "col800": "9vfi9", + "col801": "4o20k", + "col802": "b8xp2", + "col803": "4f4rb", + "col804": "d4cra", + "col805": "v4j3z", + "col806": "zyt5s", + "col807": "n9ntm", + "col808": "4nyhr", + "col809": "3azzq", + "col810": "5tgbe", + "col811": "1rjvd", + "col812": "mkz02", + "col813": "olq4k", + "col814": "mycbv", + "col815": "hg5pc", + "col816": "nh9cc", + "col817": "fdotp", + "col818": "jakw4", + "col819": "pbzg2", + "col820": "12eh6", + "col821": "44ee3", + "col822": "vtz18", + "col823": "fdm0z", + "col824": "eym2l", + "col825": "pfixf", + "col826": "wll0j", + "col827": "6fq45", + "col828": "0t5uy", + "col829": "76vvi", + "col830": "t6es0", + "col831": "ba881", + "col832": "aolvv", + "col833": "1zhps", + "col834": "r2tzc", + "col835": "4c3yj", + "col836": "h82tu", + "col837": "azyds", + "col838": "noz1e", + "col839": "1rb5n", + "col840": "024k5", + "col841": "0epng", + "col842": "bvv2w", + "col843": "js7z0", + "col844": "flbo1", + "col845": "jurlx", + "col846": "cz1v4", + "col847": "vx7ch", + "col848": "xzdx2", + "col849": "b2jh9", + "col850": "0e4h8", + "col851": "yg49t", + "col852": "vmnwp", + "col853": "rxqdi", + "col854": "vfanx", + "col855": "b0oee", + "col856": "qhz7m", + "col857": "2lgdv", + "col858": "as27h", + "col859": "n4v5n", + "col860": "1h1sv", + "col861": "ke9dz", + "col862": "ekdm1", + "col863": "n65gj", + "col864": "pest4", + "col865": "fyt9e", + "col866": "1577e", + "col867": "udwo8", + "col868": "ees57", + "col869": "taqsw", + "col870": "2zwzm", + "col871": "7ljcq", + "col872": "35aqa", + "col873": "ta3ev", + "col874": "coubo", + "col875": "gj81h", + "col876": "gxn2e", + "col877": "jxgk3", + "col878": "cz91k", + "col879": "gsgfu", + "col880": "b6npf", + "col881": "0ga44", + "col882": "igxro", + "col883": "tdp9e", + "col884": "5b1xf", + "col885": "dxqvg", + "col886": "1g3wr", + "col887": "6j674", + "col888": "i7dih", + "col889": "xpv2r", + "col890": "lkfdv", + "col891": "ytpde", + "col892": "sxms3", + "col893": "3onov", + "col894": "vl5uj", + "col895": "k0x7n", + "col896": "i1v5f", + "col897": "334au", + "col898": "5jksv", + "col899": "mvirx", + "col900": "1ovs2", + "col901": "eaht8", + "col902": "s7x8s", + "col903": "oj68h", + "col904": "t1ok7", + "col905": "40wk5", + "col906": "ly56b", + "col907": "5azf1", + "col908": "v6194", + "col909": "9o0ta", + "col910": "ivoma", + "col911": "gzkub", + "col912": "1ak6c", + "col913": "evkh1", + "col914": "b5on4", + "col915": "c2k5h", + "col916": "s4tly", + "col917": "w00in", + "col918": "g13hk", + "col919": "nqw7k", + "col920": "ow0m6", + "col921": "hubsd", + "col922": "53fkj", + "col923": "j600v", + "col924": "cs9r9", + "col925": "6axv7", + "col926": "44svu", + "col927": "i1n4v", + "col928": "r80ee", + "col929": "d6vmf", + "col930": "8ql88", + "col931": "061mz", + "col932": "tvwpo", + "col933": "3slgb", + "col934": "yaj53", + "col935": "icshf", + "col936": "ray78", + "col937": "6xb80", + "col938": "i9heh", + "col939": "jgkbq", + "col940": "wn3za", + "col941": "qov43", + "col942": "wbc3q", + "col943": "orrxo", + "col944": "r5lna", + "col945": "wwk1s", + "col946": "sssl6", + "col947": "ufjah", + "col948": "oqk0w", + "col949": "b9y1h", + "col950": "lbakk", + "col951": "vshzb", + "col952": "2ei58", + "col953": "4hna5", + "col954": "mxbzz", + "col955": "bg3ij", + "col956": "ulhii", + "col957": "772dt", + "col958": "jtnq7", + "col959": "uetpc", + "col960": "au9dz", + "col961": "33wwe", + "col962": "e23am", + "col963": "83lps", + "col964": "5o4du", + "col965": "dvngc", + "col966": "kxngi", + "col967": "vy6ke", + "col968": "giowi", + "col969": "kup7b", + "col970": "i3dvu", + "col971": "sm45f", + "col972": "f2az3", + "col973": "o4jpy", + "col974": "k64y5", + "col975": "byaoi", + "col976": "ndno9", + "col977": "elg1h", + "col978": "53bwd", + "col979": "93ba1", + "col980": "u3ued", + "col981": "1w32d", + "col982": "szx59", + "col983": "bw0mv", + "col984": "2kdy2", + "col985": "h7wyg", + "col986": "kmyfz", + "col987": "a1aft", + "col988": "1nb1o", + "col989": "pntas", + "col990": "k5nkw", + "col991": "nh3nk", + "col992": "uf1ku", + "col993": "jajf9", + "col994": "oiarc", + "col995": "ygrwm", + "col996": "4ks33", + "col997": "ad3av", + "col998": "v7vp1", + "col999": "egu24" + }, + { + "name": "Eva Mayer", + "gender": "female", + "col0": "ygrr8", + "col1": "u908h", + "col2": "dcdgm", + "col3": "uk6fv", + "col4": "5sckl", + "col5": "vngzy", + "col6": "4ibls", + "col7": "przk8", + "col8": "jx5d7", + "col9": "27wrs", + "col10": "o7fiw", + "col11": "9gria", + "col12": "q27u7", + "col13": "lr4dv", + "col14": "fghzs", + "col15": "6o359", + "col16": "ce5wt", + "col17": "pw5ol", + "col18": "vzl5q", + "col19": "x5ta2", + "col20": "u7g27", + "col21": "pf4rp", + "col22": "gyrwq", + "col23": "sla7m", + "col24": "oatqo", + "col25": "cscgs", + "col26": "cr668", + "col27": "yc8xh", + "col28": "gpqy2", + "col29": "aulr3", + "col30": "xghhg", + "col31": "g6bvt", + "col32": "u64io", + "col33": "0b62m", + "col34": "cmuc4", + "col35": "xmtlo", + "col36": "oq2t3", + "col37": "d84xd", + "col38": "z2okq", + "col39": "wncv5", + "col40": "uy6cd", + "col41": "38wdo", + "col42": "y69nd", + "col43": "z5vee", + "col44": "tj8uy", + "col45": "neukc", + "col46": "amiox", + "col47": "2xwv3", + "col48": "mjssk", + "col49": "b7wng", + "col50": "4v2en", + "col51": "5z2wf", + "col52": "yuu66", + "col53": "s9dym", + "col54": "m2jkj", + "col55": "ydv2h", + "col56": "pb17d", + "col57": "2dece", + "col58": "35ne4", + "col59": "7k4sg", + "col60": "5hy6p", + "col61": "li7kw", + "col62": "0b1p1", + "col63": "pdc2g", + "col64": "2qboh", + "col65": "bnhpj", + "col66": "935i0", + "col67": "xo7ds", + "col68": "yudme", + "col69": "eggrz", + "col70": "orf27", + "col71": "3xk6a", + "col72": "1bzu1", + "col73": "ggfpd", + "col74": "hijb3", + "col75": "26oba", + "col76": "35uqp", + "col77": "ibgg0", + "col78": "hjz8m", + "col79": "uid0g", + "col80": "9gi3n", + "col81": "kdx1r", + "col82": "06ub0", + "col83": "v3zvb", + "col84": "dceen", + "col85": "jw7jo", + "col86": "ml5ba", + "col87": "zg7qc", + "col88": "42nr5", + "col89": "ekre5", + "col90": "iffd3", + "col91": "6ds8g", + "col92": "640g0", + "col93": "74nzw", + "col94": "ewt6d", + "col95": "pmnfb", + "col96": "ho62k", + "col97": "0j6m6", + "col98": "1dr24", + "col99": "ral30", + "col100": "91kj3", + "col101": "6y1on", + "col102": "okboc", + "col103": "2gt7h", + "col104": "6g3t0", + "col105": "y3pyw", + "col106": "g95aj", + "col107": "863jt", + "col108": "nkn0l", + "col109": "ntfdc", + "col110": "0r7zo", + "col111": "mxkjw", + "col112": "nq4nt", + "col113": "aehkk", + "col114": "z47f9", + "col115": "wu3o5", + "col116": "xswn6", + "col117": "kxp46", + "col118": "5njy4", + "col119": "vxif1", + "col120": "f1za7", + "col121": "te5p7", + "col122": "96kru", + "col123": "g5i41", + "col124": "ns7uv", + "col125": "ye0sa", + "col126": "n6fsh", + "col127": "bjhqn", + "col128": "j3ver", + "col129": "aik44", + "col130": "56ute", + "col131": "9po56", + "col132": "ls4f4", + "col133": "5eiya", + "col134": "ohfre", + "col135": "50e3v", + "col136": "hby8o", + "col137": "ehou2", + "col138": "99oxb", + "col139": "8xeru", + "col140": "dlgo4", + "col141": "2yiol", + "col142": "xzzvm", + "col143": "yk47m", + "col144": "lmjp9", + "col145": "5myfe", + "col146": "re245", + "col147": "g8f6e", + "col148": "rj07e", + "col149": "63gd8", + "col150": "7fads", + "col151": "q2mgh", + "col152": "0x0v9", + "col153": "hm3m0", + "col154": "h6f2m", + "col155": "21n5w", + "col156": "1z38m", + "col157": "1eo3i", + "col158": "qg42s", + "col159": "ozz5j", + "col160": "2ljxw", + "col161": "3lsuv", + "col162": "vdd5j", + "col163": "q16od", + "col164": "ex6qh", + "col165": "y36ut", + "col166": "i16gm", + "col167": "i75da", + "col168": "il4f2", + "col169": "y5v5j", + "col170": "6506d", + "col171": "paz8c", + "col172": "myx2q", + "col173": "y5ele", + "col174": "a27x0", + "col175": "6obl8", + "col176": "2eb2y", + "col177": "2lnqa", + "col178": "rf0yv", + "col179": "5qq4s", + "col180": "jrhiq", + "col181": "iest7", + "col182": "5lsxh", + "col183": "a9r4e", + "col184": "yo2s7", + "col185": "mgrwa", + "col186": "wayhf", + "col187": "ns9qe", + "col188": "kgkm0", + "col189": "znxg8", + "col190": "f3zli", + "col191": "famlc", + "col192": "bmro7", + "col193": "h4eq0", + "col194": "2yz3r", + "col195": "nvv2e", + "col196": "29kg5", + "col197": "1yrsa", + "col198": "ya5qj", + "col199": "enpbt", + "col200": "gclbu", + "col201": "0cukf", + "col202": "xzcv0", + "col203": "y4c5i", + "col204": "gzhh0", + "col205": "jtq3f", + "col206": "qdwdg", + "col207": "zbzb4", + "col208": "uhmvo", + "col209": "nyr8m", + "col210": "rwps2", + "col211": "2xlkl", + "col212": "5qy3k", + "col213": "5b95r", + "col214": "c9t1q", + "col215": "i8xx4", + "col216": "wx06d", + "col217": "dkuxt", + "col218": "ozktk", + "col219": "oaono", + "col220": "8hz84", + "col221": "gc518", + "col222": "7860g", + "col223": "rx2i0", + "col224": "hdknb", + "col225": "sij97", + "col226": "0k2jj", + "col227": "qlwc5", + "col228": "69m49", + "col229": "114a5", + "col230": "fauz9", + "col231": "991dd", + "col232": "egj0i", + "col233": "47jll", + "col234": "gklfd", + "col235": "erry9", + "col236": "yp471", + "col237": "urvgy", + "col238": "5szam", + "col239": "fi1md", + "col240": "ps6c1", + "col241": "g8awh", + "col242": "drae8", + "col243": "0or13", + "col244": "pf53d", + "col245": "nsipm", + "col246": "f2fp6", + "col247": "8hzhx", + "col248": "nsuko", + "col249": "tgm64", + "col250": "ysttl", + "col251": "1ei8h", + "col252": "jrrjy", + "col253": "l996t", + "col254": "e63a3", + "col255": "eqap9", + "col256": "w6o7z", + "col257": "3gcqg", + "col258": "a8tl9", + "col259": "06psm", + "col260": "ric9i", + "col261": "jh08w", + "col262": "eycz2", + "col263": "bm21i", + "col264": "i6jhz", + "col265": "h2yhv", + "col266": "czoby", + "col267": "nc1zq", + "col268": "es35m", + "col269": "4n08f", + "col270": "31yjx", + "col271": "860xn", + "col272": "y6ewn", + "col273": "jqot6", + "col274": "ibo50", + "col275": "olccl", + "col276": "gxtzi", + "col277": "209bo", + "col278": "47q2g", + "col279": "7zif9", + "col280": "n61vt", + "col281": "gwzwf", + "col282": "3mqlp", + "col283": "t3f4p", + "col284": "mj38o", + "col285": "4lxzb", + "col286": "vnkzp", + "col287": "0svbk", + "col288": "k7cxy", + "col289": "nb77i", + "col290": "9n5k3", + "col291": "zi4uk", + "col292": "9n9ug", + "col293": "el1fl", + "col294": "hdl04", + "col295": "yu1u3", + "col296": "qsxc8", + "col297": "iklcp", + "col298": "hjm35", + "col299": "ovuif", + "col300": "xrxgw", + "col301": "asrjq", + "col302": "n59tm", + "col303": "trdbn", + "col304": "s4fp0", + "col305": "sq4fb", + "col306": "l2l0k", + "col307": "mzshp", + "col308": "e5lq4", + "col309": "is6by", + "col310": "lhwu6", + "col311": "7hd85", + "col312": "ecxol", + "col313": "rx4at", + "col314": "3fvp4", + "col315": "cmfwq", + "col316": "dr4vh", + "col317": "9tbse", + "col318": "6ml5b", + "col319": "6gsu8", + "col320": "34m9u", + "col321": "o8e72", + "col322": "02nji", + "col323": "potry", + "col324": "46o4w", + "col325": "f2f0w", + "col326": "sztgt", + "col327": "8widt", + "col328": "ctecq", + "col329": "i0ryp", + "col330": "z1ile", + "col331": "wtl1h", + "col332": "27v56", + "col333": "g4ffw", + "col334": "beucr", + "col335": "e7pn2", + "col336": "9ky7j", + "col337": "1aqas", + "col338": "3jnzl", + "col339": "vyicx", + "col340": "hdadh", + "col341": "d1dvr", + "col342": "7lhuh", + "col343": "qw2eh", + "col344": "uhs64", + "col345": "jvhqr", + "col346": "kzrfn", + "col347": "e8h0m", + "col348": "v6b66", + "col349": "3o08k", + "col350": "jy9bk", + "col351": "c9z1y", + "col352": "zngzv", + "col353": "iwmhz", + "col354": "x0qr3", + "col355": "uhfja", + "col356": "nezlt", + "col357": "0rawe", + "col358": "gxlz1", + "col359": "5htxf", + "col360": "ast1g", + "col361": "wtqt7", + "col362": "af36l", + "col363": "8wbq0", + "col364": "wtqj3", + "col365": "sboeo", + "col366": "gb17y", + "col367": "krcht", + "col368": "r30v5", + "col369": "jigjl", + "col370": "e643d", + "col371": "ybhkq", + "col372": "j4r9v", + "col373": "t18sj", + "col374": "q5udl", + "col375": "s3mgw", + "col376": "4ndzj", + "col377": "1k5ma", + "col378": "eol2j", + "col379": "oerti", + "col380": "s1jtg", + "col381": "z84vc", + "col382": "bpyvl", + "col383": "nrefa", + "col384": "z6bn5", + "col385": "ula2a", + "col386": "6dnas", + "col387": "xtltp", + "col388": "oyc13", + "col389": "zj4cg", + "col390": "cnzps", + "col391": "b4lmm", + "col392": "wvj97", + "col393": "jseec", + "col394": "254wy", + "col395": "0b6yk", + "col396": "ow89s", + "col397": "tncr0", + "col398": "fd2fr", + "col399": "0crwe", + "col400": "m0xot", + "col401": "i3mbq", + "col402": "cx6y7", + "col403": "ord22", + "col404": "b13pw", + "col405": "ik9ak", + "col406": "939xk", + "col407": "5e1tc", + "col408": "gzi7a", + "col409": "8fsq5", + "col410": "snwzu", + "col411": "mf5j8", + "col412": "x16fd", + "col413": "l8het", + "col414": "rezpm", + "col415": "8fhe0", + "col416": "2f9n1", + "col417": "qxmsr", + "col418": "vo118", + "col419": "bus1a", + "col420": "xzt3a", + "col421": "7smgd", + "col422": "fb3w5", + "col423": "xmmd7", + "col424": "pkbii", + "col425": "be17l", + "col426": "nvzi8", + "col427": "yq4zq", + "col428": "mswmv", + "col429": "4b7c8", + "col430": "ot6zk", + "col431": "1zdv1", + "col432": "mproy", + "col433": "0rd7t", + "col434": "ta923", + "col435": "2rbx5", + "col436": "78z4y", + "col437": "l8p3b", + "col438": "bqig4", + "col439": "myef5", + "col440": "bclz0", + "col441": "uhhq8", + "col442": "y2lga", + "col443": "br4fv", + "col444": "w4t71", + "col445": "2m2ib", + "col446": "210pv", + "col447": "j54tf", + "col448": "mcjao", + "col449": "ywa2b", + "col450": "21qvw", + "col451": "thzwu", + "col452": "iwf32", + "col453": "8tdyn", + "col454": "s4jrn", + "col455": "b40jq", + "col456": "o20s1", + "col457": "f6vox", + "col458": "gm0ph", + "col459": "ai88t", + "col460": "ivgbk", + "col461": "29dzz", + "col462": "y5j5b", + "col463": "fyru5", + "col464": "bz8f8", + "col465": "p3xkv", + "col466": "7nua5", + "col467": "5r6du", + "col468": "35p44", + "col469": "2m5cy", + "col470": "qkl48", + "col471": "0r238", + "col472": "feci1", + "col473": "49vpo", + "col474": "0qbt9", + "col475": "va1vy", + "col476": "7gazt", + "col477": "hk874", + "col478": "gh95y", + "col479": "93zjv", + "col480": "w4mqr", + "col481": "4hani", + "col482": "7304a", + "col483": "9bxur", + "col484": "f2vwj", + "col485": "vvodi", + "col486": "rpicr", + "col487": "avu6m", + "col488": "5u8uj", + "col489": "hs4re", + "col490": "wl0mb", + "col491": "ypadi", + "col492": "ajvyr", + "col493": "yxi52", + "col494": "z1z2r", + "col495": "8ve5w", + "col496": "ch0va", + "col497": "yfvb5", + "col498": "xg9gb", + "col499": "kc7qf", + "col500": "nkd3t", + "col501": "kn86o", + "col502": "yamzp", + "col503": "18ofx", + "col504": "x3smt", + "col505": "kuio0", + "col506": "4dm9s", + "col507": "1eler", + "col508": "c272n", + "col509": "oqjat", + "col510": "tltkz", + "col511": "ihtm3", + "col512": "c1942", + "col513": "aobaw", + "col514": "gkou0", + "col515": "35p3a", + "col516": "qknyy", + "col517": "wnnvl", + "col518": "j7x41", + "col519": "jm5ya", + "col520": "4h0aq", + "col521": "pi2hj", + "col522": "fzi1q", + "col523": "shlik", + "col524": "3xflc", + "col525": "j5zlg", + "col526": "cglv5", + "col527": "40blz", + "col528": "qs2oa", + "col529": "1ymqo", + "col530": "wtcvz", + "col531": "34jim", + "col532": "rff69", + "col533": "vntd3", + "col534": "omvdg", + "col535": "gm3t2", + "col536": "793nv", + "col537": "3aji8", + "col538": "br0d5", + "col539": "zbon0", + "col540": "dyg7z", + "col541": "c1h78", + "col542": "4ao4s", + "col543": "q8t1b", + "col544": "redvo", + "col545": "xkcqw", + "col546": "ll33q", + "col547": "slymv", + "col548": "zca30", + "col549": "1o9hx", + "col550": "i1xiz", + "col551": "n2c6z", + "col552": "x47a7", + "col553": "rly7a", + "col554": "bz7z9", + "col555": "ibhor", + "col556": "93uj0", + "col557": "0vvy2", + "col558": "6p6vv", + "col559": "pf55m", + "col560": "uhju9", + "col561": "c160h", + "col562": "xbk7v", + "col563": "r39eu", + "col564": "ker9g", + "col565": "78fl0", + "col566": "pkwft", + "col567": "oosl0", + "col568": "qlx7e", + "col569": "czu3n", + "col570": "yakul", + "col571": "7i8jj", + "col572": "ciysn", + "col573": "ttnwo", + "col574": "924z3", + "col575": "ks3qp", + "col576": "n1iap", + "col577": "puzuh", + "col578": "8p6r3", + "col579": "vyyr5", + "col580": "im3tw", + "col581": "mgyex", + "col582": "ikavd", + "col583": "esict", + "col584": "t2wlh", + "col585": "gnwe8", + "col586": "1uejj", + "col587": "kzqbp", + "col588": "01ecl", + "col589": "wvwec", + "col590": "8z6ad", + "col591": "605o4", + "col592": "x0ndy", + "col593": "p8sns", + "col594": "or77k", + "col595": "olmxa", + "col596": "msbwt", + "col597": "nhmaa", + "col598": "u3drr", + "col599": "h04gs", + "col600": "if2sx", + "col601": "wcdvz", + "col602": "muvnt", + "col603": "4fjoi", + "col604": "m1xuy", + "col605": "229oi", + "col606": "qi2df", + "col607": "tcd2a", + "col608": "e070z", + "col609": "m5pju", + "col610": "lgd0n", + "col611": "fufwq", + "col612": "167z6", + "col613": "forkm", + "col614": "c9wd8", + "col615": "ub7ov", + "col616": "acsmx", + "col617": "1pq9q", + "col618": "0dtdh", + "col619": "v5u3g", + "col620": "lszm0", + "col621": "g0urz", + "col622": "3fo2o", + "col623": "mtdei", + "col624": "4kdj5", + "col625": "kpxy1", + "col626": "u9nf6", + "col627": "oa4qr", + "col628": "yhdqn", + "col629": "mnv5i", + "col630": "n82u6", + "col631": "fwocf", + "col632": "ce6ds", + "col633": "sgus0", + "col634": "42wdd", + "col635": "k2a8n", + "col636": "0jpek", + "col637": "0zm21", + "col638": "0yfus", + "col639": "kuyo2", + "col640": "v81z1", + "col641": "wctkv", + "col642": "xrk1d", + "col643": "wa1nd", + "col644": "c9atm", + "col645": "qtqyw", + "col646": "ofxjl", + "col647": "1m3wo", + "col648": "gu1ek", + "col649": "e0ddl", + "col650": "sm461", + "col651": "lgdqf", + "col652": "u6x79", + "col653": "pq0oj", + "col654": "nsbgs", + "col655": "zbln9", + "col656": "vlhy3", + "col657": "kcrqu", + "col658": "v5rku", + "col659": "n81xy", + "col660": "88lhs", + "col661": "05efp", + "col662": "cgrss", + "col663": "jjzdd", + "col664": "61tme", + "col665": "mnsdb", + "col666": "ylkuq", + "col667": "spd6t", + "col668": "owe41", + "col669": "evvdu", + "col670": "bra8t", + "col671": "lo27l", + "col672": "xqusn", + "col673": "7v9ax", + "col674": "n9mab", + "col675": "v6v1q", + "col676": "rplsi", + "col677": "cbzvj", + "col678": "mo9nq", + "col679": "1sv5e", + "col680": "89yem", + "col681": "zead9", + "col682": "tev31", + "col683": "yn8yo", + "col684": "x7aq2", + "col685": "9c390", + "col686": "c8agd", + "col687": "7hms9", + "col688": "at70b", + "col689": "4q0c0", + "col690": "34kfq", + "col691": "4jd6b", + "col692": "8y97x", + "col693": "bw8xm", + "col694": "bxtd1", + "col695": "dqfr7", + "col696": "xd3o0", + "col697": "5ydrm", + "col698": "hzuu1", + "col699": "88vb7", + "col700": "kb8s3", + "col701": "fa0w2", + "col702": "sf9hc", + "col703": "hbog4", + "col704": "yj2cj", + "col705": "wicai", + "col706": "18czi", + "col707": "0y4iv", + "col708": "4bpgc", + "col709": "hnpda", + "col710": "5ospy", + "col711": "xtnig", + "col712": "ysril", + "col713": "tg5g8", + "col714": "uj255", + "col715": "wkeah", + "col716": "fygfr", + "col717": "7hbl4", + "col718": "q8ag8", + "col719": "rpe4w", + "col720": "109g2", + "col721": "384yl", + "col722": "pc6qb", + "col723": "9wneg", + "col724": "z5xka", + "col725": "tfcxs", + "col726": "rmvk3", + "col727": "klu5w", + "col728": "0v9db", + "col729": "5661c", + "col730": "pqrxt", + "col731": "n6onz", + "col732": "lky1j", + "col733": "tymya", + "col734": "60ls0", + "col735": "wsinz", + "col736": "w8qf1", + "col737": "fxocz", + "col738": "9evaj", + "col739": "15rln", + "col740": "92dly", + "col741": "4ao7m", + "col742": "4h0ey", + "col743": "nqmmo", + "col744": "6pdel", + "col745": "88sg6", + "col746": "7zu2s", + "col747": "xd4pn", + "col748": "div0c", + "col749": "8ekkq", + "col750": "ccgy8", + "col751": "ynywh", + "col752": "xy9j3", + "col753": "vm5hx", + "col754": "yqr38", + "col755": "234ny", + "col756": "on1n2", + "col757": "394up", + "col758": "1c6j5", + "col759": "146dx", + "col760": "3bxtj", + "col761": "12k1h", + "col762": "yrdn4", + "col763": "gqjzm", + "col764": "0jqon", + "col765": "e91s8", + "col766": "skfzq", + "col767": "3uj8b", + "col768": "ypje7", + "col769": "9yz43", + "col770": "0q9us", + "col771": "cshk9", + "col772": "8lgz4", + "col773": "xbkdo", + "col774": "mr7uy", + "col775": "266yt", + "col776": "llt96", + "col777": "5ad8n", + "col778": "rzb6j", + "col779": "94ok8", + "col780": "j4gu5", + "col781": "zipt3", + "col782": "hw1um", + "col783": "etp5y", + "col784": "naxfr", + "col785": "93t6i", + "col786": "pq8nh", + "col787": "fayk4", + "col788": "2q1cb", + "col789": "rdjqs", + "col790": "bgo1f", + "col791": "7br0b", + "col792": "zuh6o", + "col793": "3ha6d", + "col794": "xgvxn", + "col795": "8wt25", + "col796": "uo0bq", + "col797": "dqrc7", + "col798": "lp3vj", + "col799": "onjet", + "col800": "q3iu3", + "col801": "cvafa", + "col802": "ogw5m", + "col803": "e1fia", + "col804": "7oisw", + "col805": "oywdq", + "col806": "isbtc", + "col807": "rso8o", + "col808": "boxv0", + "col809": "lap8x", + "col810": "3pzgm", + "col811": "223kx", + "col812": "y17kp", + "col813": "8n5p2", + "col814": "pxoxs", + "col815": "vx3h7", + "col816": "5ud68", + "col817": "lwssw", + "col818": "5lwtx", + "col819": "okg2a", + "col820": "ypuqg", + "col821": "yv17w", + "col822": "oi1qw", + "col823": "itquj", + "col824": "4exk5", + "col825": "7stnn", + "col826": "mw1bj", + "col827": "0e85z", + "col828": "obt59", + "col829": "hv2rn", + "col830": "gbwwj", + "col831": "wio5c", + "col832": "a92vf", + "col833": "kqnxb", + "col834": "s6uei", + "col835": "3cnuo", + "col836": "6lj51", + "col837": "hosjv", + "col838": "fvtxn", + "col839": "vayys", + "col840": "ui5yw", + "col841": "8db5e", + "col842": "p6gp7", + "col843": "syuok", + "col844": "6b7pt", + "col845": "05j5u", + "col846": "f7mo1", + "col847": "yr799", + "col848": "evywg", + "col849": "crrfz", + "col850": "9jo6d", + "col851": "6hgdy", + "col852": "15cpg", + "col853": "ay6b1", + "col854": "2el9g", + "col855": "ke8t2", + "col856": "9t1rf", + "col857": "1wv41", + "col858": "xv2kk", + "col859": "vfscs", + "col860": "e4doq", + "col861": "vqvfc", + "col862": "8orcu", + "col863": "q9vmi", + "col864": "31vqa", + "col865": "a1qan", + "col866": "t6cs3", + "col867": "afvhg", + "col868": "ls6nr", + "col869": "knwql", + "col870": "hl4vb", + "col871": "6d8bq", + "col872": "kclvu", + "col873": "8alkm", + "col874": "1ruxh", + "col875": "wck00", + "col876": "vjbix", + "col877": "afugb", + "col878": "7dvls", + "col879": "okldh", + "col880": "mkk4n", + "col881": "g3gvg", + "col882": "vr1d8", + "col883": "k1rrd", + "col884": "7of4d", + "col885": "9y2jx", + "col886": "rxkzf", + "col887": "dp6dt", + "col888": "xdhd1", + "col889": "5r6qe", + "col890": "v9tlj", + "col891": "rdtg3", + "col892": "vvfww", + "col893": "g6evp", + "col894": "sv03o", + "col895": "5iji5", + "col896": "hzn7l", + "col897": "xbbc5", + "col898": "18q8g", + "col899": "ofoz8", + "col900": "2yyo8", + "col901": "zynut", + "col902": "tp9qt", + "col903": "bpdew", + "col904": "lmzh8", + "col905": "e4oyn", + "col906": "tow2z", + "col907": "dc2tq", + "col908": "myzyp", + "col909": "bidyo", + "col910": "bzwd3", + "col911": "l2mc5", + "col912": "4wwk2", + "col913": "w6o6m", + "col914": "xcb16", + "col915": "y2dt1", + "col916": "xl645", + "col917": "ainvz", + "col918": "oa9y7", + "col919": "m7xkm", + "col920": "p0cu7", + "col921": "enabi", + "col922": "8xq1i", + "col923": "6lq9r", + "col924": "1l1ci", + "col925": "eugwi", + "col926": "rn1ov", + "col927": "gg3n7", + "col928": "944dc", + "col929": "mupr9", + "col930": "278pd", + "col931": "8m0x3", + "col932": "ddur8", + "col933": "pi3gg", + "col934": "siblt", + "col935": "pi3nq", + "col936": "49534", + "col937": "26zmy", + "col938": "vzpf0", + "col939": "hafbe", + "col940": "njryn", + "col941": "96888", + "col942": "swg7a", + "col943": "gb78o", + "col944": "959k6", + "col945": "dxxva", + "col946": "nd7dh", + "col947": "666v7", + "col948": "mlase", + "col949": "gh0dk", + "col950": "qj8kr", + "col951": "yiz05", + "col952": "aumgd", + "col953": "4xnj3", + "col954": "x7a2o", + "col955": "6xsiv", + "col956": "ve9ci", + "col957": "7a3ew", + "col958": "xrp15", + "col959": "xl76h", + "col960": "4jpkz", + "col961": "y1pi0", + "col962": "4whpl", + "col963": "fx3tt", + "col964": "jn1lg", + "col965": "eumxz", + "col966": "4z573", + "col967": "cpfm8", + "col968": "zfl7v", + "col969": "bn38p", + "col970": "ney91", + "col971": "6es9f", + "col972": "kfw3m", + "col973": "8isan", + "col974": "n9zx8", + "col975": "yk6ea", + "col976": "v6lro", + "col977": "5v05q", + "col978": "bdrob", + "col979": "jcv1w", + "col980": "amikt", + "col981": "hqgeg", + "col982": "nrwa5", + "col983": "d7lrq", + "col984": "o6rxo", + "col985": "1wr9f", + "col986": "m1llf", + "col987": "t5i94", + "col988": "t7zqg", + "col989": "auu2c", + "col990": "98vjn", + "col991": "nco0k", + "col992": "tdigc", + "col993": "rpha7", + "col994": "618oe", + "col995": "ydza4", + "col996": "gl6y3", + "col997": "qa0sj", + "col998": "6129t", + "col999": "33qge" + }, + { + "name": "Leila Stuart", + "gender": "female", + "col0": "rv9sa", + "col1": "huwev", + "col2": "ce8on", + "col3": "unj70", + "col4": "7dkjs", + "col5": "a890m", + "col6": "5prmc", + "col7": "m3twc", + "col8": "z1z7n", + "col9": "abfbi", + "col10": "mwt6c", + "col11": "9z8v1", + "col12": "wh7l8", + "col13": "y8omq", + "col14": "ntxul", + "col15": "p97za", + "col16": "3kj59", + "col17": "i6l40", + "col18": "izlog", + "col19": "ob4rs", + "col20": "y8llg", + "col21": "6hvta", + "col22": "peq69", + "col23": "zn0lj", + "col24": "zazr9", + "col25": "e8riz", + "col26": "voxco", + "col27": "tnh3d", + "col28": "x36kj", + "col29": "lj01y", + "col30": "oeta0", + "col31": "cdurg", + "col32": "0tmwn", + "col33": "sqfmw", + "col34": "6lxqu", + "col35": "4i11n", + "col36": "h8yh2", + "col37": "ppvwd", + "col38": "qxmjs", + "col39": "314v3", + "col40": "po31w", + "col41": "m37ze", + "col42": "4wkgl", + "col43": "0t5w4", + "col44": "yd83k", + "col45": "8ra16", + "col46": "xe3gl", + "col47": "hi900", + "col48": "pfq5w", + "col49": "d513x", + "col50": "psm44", + "col51": "1ysvk", + "col52": "cdasb", + "col53": "yzz1l", + "col54": "9bqvz", + "col55": "20lja", + "col56": "q820u", + "col57": "q9xk9", + "col58": "4kdo9", + "col59": "t7oj2", + "col60": "f00nb", + "col61": "9ezm7", + "col62": "46j7s", + "col63": "x7iao", + "col64": "399f3", + "col65": "mxp6b", + "col66": "f5re7", + "col67": "sjqrd", + "col68": "zd8lv", + "col69": "72gqr", + "col70": "hcypi", + "col71": "zj8el", + "col72": "w9k52", + "col73": "3rtpu", + "col74": "g18p1", + "col75": "j5prr", + "col76": "vusmc", + "col77": "6n53z", + "col78": "vmopd", + "col79": "a5a2u", + "col80": "6a3qv", + "col81": "xw199", + "col82": "732ms", + "col83": "e5ipu", + "col84": "7oqb5", + "col85": "7c6ni", + "col86": "q7fzw", + "col87": "jncmk", + "col88": "j9l2r", + "col89": "q4py3", + "col90": "5rzk7", + "col91": "19o6m", + "col92": "5gyu8", + "col93": "odly5", + "col94": "1q4jj", + "col95": "zybdg", + "col96": "g4ovc", + "col97": "kpz23", + "col98": "2ig8f", + "col99": "nwz11", + "col100": "j89k0", + "col101": "7teji", + "col102": "j7fvh", + "col103": "hwch6", + "col104": "u9a3d", + "col105": "08dow", + "col106": "4q402", + "col107": "5yu2g", + "col108": "md6dq", + "col109": "4z5vf", + "col110": "79u52", + "col111": "t0b01", + "col112": "qm65n", + "col113": "blfez", + "col114": "5sjz4", + "col115": "xsovd", + "col116": "xkdoq", + "col117": "ris7k", + "col118": "yh5ks", + "col119": "12rty", + "col120": "9uwav", + "col121": "934ne", + "col122": "al4bt", + "col123": "tq5di", + "col124": "gsnmn", + "col125": "o5mcv", + "col126": "ho1l2", + "col127": "eelrf", + "col128": "9x761", + "col129": "u6tiu", + "col130": "kv647", + "col131": "kuh70", + "col132": "4ccaq", + "col133": "c0hlq", + "col134": "lar13", + "col135": "iva2l", + "col136": "fegnh", + "col137": "52vht", + "col138": "ug791", + "col139": "kcjeg", + "col140": "5u980", + "col141": "1zgve", + "col142": "kpikj", + "col143": "h6y3p", + "col144": "4czii", + "col145": "lm7pj", + "col146": "1k1u3", + "col147": "581ti", + "col148": "a0tdi", + "col149": "ayd8l", + "col150": "29wi0", + "col151": "eynxq", + "col152": "vtdi6", + "col153": "csp7d", + "col154": "c5fas", + "col155": "dxs4a", + "col156": "0ufr1", + "col157": "vaobw", + "col158": "eq7wz", + "col159": "pa34v", + "col160": "aor2q", + "col161": "gp7uh", + "col162": "nqwud", + "col163": "e64m0", + "col164": "wzn1n", + "col165": "9k9oe", + "col166": "f7re4", + "col167": "zn54b", + "col168": "s7v6j", + "col169": "lbd3z", + "col170": "ajywx", + "col171": "9dxq2", + "col172": "jcca9", + "col173": "r1wf1", + "col174": "xvjsa", + "col175": "8x00l", + "col176": "s6bwp", + "col177": "1ze8p", + "col178": "so72n", + "col179": "jnpva", + "col180": "830oh", + "col181": "hjxnp", + "col182": "hm956", + "col183": "gpaku", + "col184": "qgb5z", + "col185": "o5evo", + "col186": "5eecj", + "col187": "ec1ic", + "col188": "7n7xk", + "col189": "ggaoe", + "col190": "5yaid", + "col191": "bmznh", + "col192": "vzl7g", + "col193": "gmzxu", + "col194": "aka1i", + "col195": "b9om1", + "col196": "mh4xm", + "col197": "qggvb", + "col198": "j04re", + "col199": "c561k", + "col200": "lng9w", + "col201": "lla0k", + "col202": "2lx8d", + "col203": "o9zpb", + "col204": "nhl1j", + "col205": "5evuw", + "col206": "n4njn", + "col207": "xka4k", + "col208": "2tuk3", + "col209": "ur4dj", + "col210": "33bwl", + "col211": "bi1gf", + "col212": "goj98", + "col213": "o9dsj", + "col214": "6r6h3", + "col215": "p6z5c", + "col216": "1hvub", + "col217": "y04cd", + "col218": "o0q4u", + "col219": "pivke", + "col220": "9djhy", + "col221": "wvjab", + "col222": "ycv0n", + "col223": "cvc3l", + "col224": "vsgxc", + "col225": "ihddw", + "col226": "cu343", + "col227": "4heo6", + "col228": "8d4sz", + "col229": "en3dn", + "col230": "b1rxg", + "col231": "4jt3v", + "col232": "3fwy5", + "col233": "07x9v", + "col234": "4yu2v", + "col235": "zjvz9", + "col236": "wo9xm", + "col237": "3ves3", + "col238": "mxb5q", + "col239": "yq7ww", + "col240": "43n2g", + "col241": "po8mv", + "col242": "po2y9", + "col243": "ndufw", + "col244": "bo0f2", + "col245": "tpopn", + "col246": "aml63", + "col247": "jr59h", + "col248": "ap6ag", + "col249": "pvg3o", + "col250": "bq5yc", + "col251": "nkgpx", + "col252": "revy6", + "col253": "5soen", + "col254": "2zbuh", + "col255": "lelmp", + "col256": "drntj", + "col257": "0aspm", + "col258": "ksor8", + "col259": "mtnry", + "col260": "tdw0g", + "col261": "tvlpy", + "col262": "kfj5q", + "col263": "tfx40", + "col264": "j39o0", + "col265": "zv8at", + "col266": "zpx72", + "col267": "f67aj", + "col268": "02nsm", + "col269": "9r0j0", + "col270": "wbwji", + "col271": "n526e", + "col272": "ksxpr", + "col273": "bj4r7", + "col274": "57wnm", + "col275": "rydcw", + "col276": "0bk5v", + "col277": "za01k", + "col278": "gjunk", + "col279": "0d0ep", + "col280": "3tvjt", + "col281": "zixyo", + "col282": "8ifcp", + "col283": "8dcim", + "col284": "kotoq", + "col285": "f3wy1", + "col286": "wxitf", + "col287": "o6w6d", + "col288": "bk4l5", + "col289": "1jddy", + "col290": "12b7i", + "col291": "obhg6", + "col292": "ccq5b", + "col293": "pld3o", + "col294": "pxccb", + "col295": "kwr4l", + "col296": "s5tgk", + "col297": "jssar", + "col298": "aoa8g", + "col299": "vabjp", + "col300": "6r3vm", + "col301": "2236c", + "col302": "iya69", + "col303": "7u46d", + "col304": "khjd8", + "col305": "lkmkb", + "col306": "xjtei", + "col307": "l0rho", + "col308": "jb3qw", + "col309": "tzxt3", + "col310": "mdnx0", + "col311": "yxsiv", + "col312": "6eqoo", + "col313": "bz3o9", + "col314": "e57cx", + "col315": "8ddzs", + "col316": "yszlw", + "col317": "sx0qo", + "col318": "0l4nm", + "col319": "l863p", + "col320": "bt0wr", + "col321": "modcr", + "col322": "3amub", + "col323": "k78sn", + "col324": "aopd5", + "col325": "g5enk", + "col326": "95a0q", + "col327": "ix270", + "col328": "adt37", + "col329": "5l937", + "col330": "6kze1", + "col331": "rrmdx", + "col332": "vcnaw", + "col333": "2xx71", + "col334": "ewxjt", + "col335": "a6g23", + "col336": "6xrs5", + "col337": "ktrq9", + "col338": "go4tc", + "col339": "ojisc", + "col340": "31ub9", + "col341": "0ea5r", + "col342": "pgg12", + "col343": "4pdh2", + "col344": "z3jjx", + "col345": "ywt21", + "col346": "4jk9r", + "col347": "v4tt9", + "col348": "450aa", + "col349": "tw4qi", + "col350": "weqpj", + "col351": "42eqq", + "col352": "m7yal", + "col353": "yffvj", + "col354": "5dn6m", + "col355": "3aoyu", + "col356": "bzyvd", + "col357": "70b8t", + "col358": "u8bdb", + "col359": "4bwcq", + "col360": "29vcf", + "col361": "vjrir", + "col362": "qyiqj", + "col363": "jbx2n", + "col364": "iq5s0", + "col365": "c4ak0", + "col366": "qz0q7", + "col367": "zftpm", + "col368": "pka6g", + "col369": "2q3nr", + "col370": "5wwvb", + "col371": "z7o5k", + "col372": "bmmmf", + "col373": "qx6dg", + "col374": "zairm", + "col375": "cvckh", + "col376": "b3whu", + "col377": "vkq0a", + "col378": "er8w4", + "col379": "twhhv", + "col380": "kznkw", + "col381": "nsbli", + "col382": "gfrge", + "col383": "hecvw", + "col384": "2cjhu", + "col385": "279ie", + "col386": "4j81i", + "col387": "afi4w", + "col388": "o9sro", + "col389": "zsuiu", + "col390": "5l71i", + "col391": "9ioe0", + "col392": "z2kg4", + "col393": "9wd69", + "col394": "ns90j", + "col395": "3b0f3", + "col396": "xqggl", + "col397": "s16iw", + "col398": "3nq00", + "col399": "7hox3", + "col400": "f2y7w", + "col401": "ffxr4", + "col402": "yc5w1", + "col403": "ibxs3", + "col404": "bru11", + "col405": "i6yt1", + "col406": "8je31", + "col407": "ywsuv", + "col408": "m8f1n", + "col409": "zb7i9", + "col410": "suexn", + "col411": "g5hux", + "col412": "fukj7", + "col413": "d0k2n", + "col414": "51non", + "col415": "9estu", + "col416": "e1ot9", + "col417": "p3ra7", + "col418": "pwgf2", + "col419": "w25pi", + "col420": "8kffj", + "col421": "pr7uh", + "col422": "2zz8e", + "col423": "lo0rw", + "col424": "m4s4s", + "col425": "hb782", + "col426": "steji", + "col427": "d924b", + "col428": "jwsow", + "col429": "0k5k8", + "col430": "ibmos", + "col431": "bpqln", + "col432": "qo6zs", + "col433": "46k5b", + "col434": "x021f", + "col435": "mierw", + "col436": "ygdrb", + "col437": "qsoao", + "col438": "l2i4z", + "col439": "zvdxi", + "col440": "gyvpg", + "col441": "m8odh", + "col442": "ky329", + "col443": "s7ci3", + "col444": "d9b4l", + "col445": "jn7e7", + "col446": "ztpwv", + "col447": "we1wt", + "col448": "4d4xq", + "col449": "0nx20", + "col450": "ko6qq", + "col451": "na7fm", + "col452": "rtd87", + "col453": "9a7qt", + "col454": "j4111", + "col455": "caszy", + "col456": "1jne2", + "col457": "0b2wa", + "col458": "sz26n", + "col459": "6t4d2", + "col460": "wb8yz", + "col461": "kyp2g", + "col462": "d5rc5", + "col463": "xfjgj", + "col464": "81451", + "col465": "ts345", + "col466": "a7gz2", + "col467": "qj3yp", + "col468": "ilakn", + "col469": "5epdt", + "col470": "8fy07", + "col471": "htajs", + "col472": "604ey", + "col473": "1zpqd", + "col474": "s6q5b", + "col475": "9wcb1", + "col476": "te6q1", + "col477": "ubv71", + "col478": "wepkw", + "col479": "mmdm4", + "col480": "uuals", + "col481": "y0job", + "col482": "wvlyy", + "col483": "jex6g", + "col484": "6hwx9", + "col485": "sswxh", + "col486": "qcniv", + "col487": "ri0o2", + "col488": "g1v1a", + "col489": "uiaj3", + "col490": "9woz4", + "col491": "i66hr", + "col492": "xht47", + "col493": "roln4", + "col494": "mme3a", + "col495": "4fhao", + "col496": "pd4fq", + "col497": "0lh75", + "col498": "sfxn1", + "col499": "kh1ui", + "col500": "eymqq", + "col501": "9aduo", + "col502": "dsjlj", + "col503": "1k4va", + "col504": "pmmj5", + "col505": "4s15n", + "col506": "c6xn2", + "col507": "slpef", + "col508": "nnb38", + "col509": "u0ha5", + "col510": "rjqo9", + "col511": "vd8z2", + "col512": "g0eka", + "col513": "nuutj", + "col514": "3vazi", + "col515": "gbe84", + "col516": "c3wpd", + "col517": "d2qkw", + "col518": "eq8yy", + "col519": "gtnle", + "col520": "fcimf", + "col521": "vbslg", + "col522": "ex2tl", + "col523": "8tul4", + "col524": "3dghq", + "col525": "k4dpl", + "col526": "2ry6e", + "col527": "aap1e", + "col528": "p3nkj", + "col529": "d6bvd", + "col530": "97g6c", + "col531": "yp9gd", + "col532": "415yw", + "col533": "k1wcq", + "col534": "xcgq7", + "col535": "s2sqd", + "col536": "tmawl", + "col537": "t9tx7", + "col538": "di8f1", + "col539": "pzdag", + "col540": "hgetw", + "col541": "zwne0", + "col542": "fe3sp", + "col543": "cj38i", + "col544": "a7ktk", + "col545": "eyqmj", + "col546": "orjso", + "col547": "7ctti", + "col548": "32v7i", + "col549": "05cgp", + "col550": "bw8u1", + "col551": "9hgxg", + "col552": "bfsgd", + "col553": "5870p", + "col554": "th2u6", + "col555": "njmsg", + "col556": "wqppc", + "col557": "64w8m", + "col558": "apxeg", + "col559": "44okb", + "col560": "2kwgt", + "col561": "yxumr", + "col562": "a21gw", + "col563": "b54q8", + "col564": "q2j81", + "col565": "vanba", + "col566": "f3njb", + "col567": "3d0bf", + "col568": "4hs7l", + "col569": "lgg9a", + "col570": "gpl3o", + "col571": "t2k6s", + "col572": "e0dp9", + "col573": "3jxvl", + "col574": "6xrcj", + "col575": "ggy0z", + "col576": "7zbg9", + "col577": "1l28f", + "col578": "9cbcm", + "col579": "idihi", + "col580": "asrrf", + "col581": "bbpap", + "col582": "ib2a4", + "col583": "qoj8o", + "col584": "z641o", + "col585": "1dz5o", + "col586": "lsusi", + "col587": "pdrzd", + "col588": "ikjwx", + "col589": "9mdjl", + "col590": "g4n5b", + "col591": "avcxt", + "col592": "ynee6", + "col593": "rxs69", + "col594": "sw16d", + "col595": "bp0ft", + "col596": "kqf53", + "col597": "63r2m", + "col598": "w63wv", + "col599": "n1vus", + "col600": "w82n7", + "col601": "qx4nw", + "col602": "pz771", + "col603": "vbvy2", + "col604": "bzsmt", + "col605": "ex3cw", + "col606": "7l7vr", + "col607": "ncyf0", + "col608": "mxgn6", + "col609": "zwzza", + "col610": "010n2", + "col611": "5e0qf", + "col612": "kcgl4", + "col613": "had9m", + "col614": "sp66p", + "col615": "p6pn7", + "col616": "11s46", + "col617": "gww1i", + "col618": "bqwb7", + "col619": "e11vw", + "col620": "3gfpd", + "col621": "6tlko", + "col622": "t5mgf", + "col623": "i7zu2", + "col624": "nte7q", + "col625": "rqizc", + "col626": "e1ph1", + "col627": "ho0p7", + "col628": "rift3", + "col629": "5wt3l", + "col630": "5cmxi", + "col631": "ieovg", + "col632": "3bn9h", + "col633": "wtgpi", + "col634": "cocb1", + "col635": "g2hpq", + "col636": "ik6oy", + "col637": "dvftj", + "col638": "iqj3p", + "col639": "isxg9", + "col640": "d83h1", + "col641": "au8cj", + "col642": "wobvm", + "col643": "9j0d4", + "col644": "d6r0l", + "col645": "h7x6q", + "col646": "v4l05", + "col647": "g5zuw", + "col648": "sucyg", + "col649": "3acyb", + "col650": "0aqsw", + "col651": "xstpk", + "col652": "2p1rx", + "col653": "ekpp7", + "col654": "8vhkk", + "col655": "8eivq", + "col656": "qz1qj", + "col657": "q08rh", + "col658": "4wo5k", + "col659": "11add", + "col660": "ur19i", + "col661": "vxkyb", + "col662": "13wzb", + "col663": "ctnp2", + "col664": "jwm2u", + "col665": "fla8s", + "col666": "hdodz", + "col667": "vqipk", + "col668": "314mz", + "col669": "ohz74", + "col670": "pvjjg", + "col671": "c74g2", + "col672": "gtnu0", + "col673": "h5hms", + "col674": "bgy44", + "col675": "slttg", + "col676": "o7vok", + "col677": "5q3m3", + "col678": "y7o0n", + "col679": "01za2", + "col680": "v9oa8", + "col681": "42t9y", + "col682": "1mwmw", + "col683": "iayd4", + "col684": "s84h5", + "col685": "s2ajz", + "col686": "qqmp3", + "col687": "yfdxj", + "col688": "1mdzb", + "col689": "8m8is", + "col690": "uozp4", + "col691": "35c4k", + "col692": "tu1ot", + "col693": "23q5b", + "col694": "5f4ij", + "col695": "olm2q", + "col696": "cdjzs", + "col697": "wti32", + "col698": "btlu5", + "col699": "klqew", + "col700": "d94oz", + "col701": "z6p65", + "col702": "pttan", + "col703": "fxrj9", + "col704": "brxfy", + "col705": "6mcb0", + "col706": "9m8xg", + "col707": "b5mzf", + "col708": "1fpfe", + "col709": "l05el", + "col710": "ca3dm", + "col711": "0pscc", + "col712": "jii9l", + "col713": "jd5ku", + "col714": "oh4o7", + "col715": "psjx3", + "col716": "ygt3c", + "col717": "hhejz", + "col718": "il7a4", + "col719": "m6ucj", + "col720": "ts9bm", + "col721": "rh4bw", + "col722": "2bz7s", + "col723": "oi4k9", + "col724": "syr0b", + "col725": "hw9j6", + "col726": "fetx8", + "col727": "5hjun", + "col728": "dujin", + "col729": "dtxf0", + "col730": "iyh8r", + "col731": "bw5j8", + "col732": "qi3s6", + "col733": "g5rbk", + "col734": "wo090", + "col735": "ehfm8", + "col736": "6zagp", + "col737": "s0rcy", + "col738": "tvngp", + "col739": "z3ues", + "col740": "rjvcx", + "col741": "ii5mj", + "col742": "ooqp9", + "col743": "zjj7y", + "col744": "7dr43", + "col745": "txic2", + "col746": "ydtjt", + "col747": "9xjv7", + "col748": "gd2vr", + "col749": "nxycc", + "col750": "axnl1", + "col751": "4svvc", + "col752": "ime6e", + "col753": "ou4lw", + "col754": "yu58a", + "col755": "21uv4", + "col756": "z9x3h", + "col757": "qapqs", + "col758": "52egi", + "col759": "imdjg", + "col760": "yy6va", + "col761": "b23f8", + "col762": "wpase", + "col763": "ne9fl", + "col764": "kyq5p", + "col765": "d6kiq", + "col766": "x1uxq", + "col767": "zxulu", + "col768": "9zxnr", + "col769": "9v3gr", + "col770": "eusrf", + "col771": "zn97t", + "col772": "oqojg", + "col773": "oeogv", + "col774": "4426h", + "col775": "rmi0u", + "col776": "rxehs", + "col777": "b733w", + "col778": "1q2ip", + "col779": "w9xv8", + "col780": "rn9w4", + "col781": "ip9sw", + "col782": "uqprq", + "col783": "a7ufp", + "col784": "rh6gp", + "col785": "oha4k", + "col786": "5dgql", + "col787": "i6mwq", + "col788": "g45xy", + "col789": "wr0db", + "col790": "poodj", + "col791": "xguov", + "col792": "ni0hi", + "col793": "09ahv", + "col794": "lo1me", + "col795": "7yba9", + "col796": "rqhv5", + "col797": "c4ubp", + "col798": "9zqbh", + "col799": "8c7io", + "col800": "9wc5y", + "col801": "nuyl7", + "col802": "0ffz4", + "col803": "wf94q", + "col804": "hdl82", + "col805": "or1ud", + "col806": "gm595", + "col807": "mcaqh", + "col808": "gpylx", + "col809": "wi6rz", + "col810": "dxdp3", + "col811": "taneu", + "col812": "1812r", + "col813": "ucuiw", + "col814": "2czv5", + "col815": "s7idt", + "col816": "2ym7i", + "col817": "g9emw", + "col818": "dkwqh", + "col819": "9ftd3", + "col820": "9aig4", + "col821": "kjyti", + "col822": "u3mcc", + "col823": "f7yuz", + "col824": "2rl4t", + "col825": "38fme", + "col826": "we48q", + "col827": "yk604", + "col828": "v7rgx", + "col829": "m2z3g", + "col830": "rhml2", + "col831": "45a3d", + "col832": "vahfq", + "col833": "i9257", + "col834": "ix0xr", + "col835": "qc8fq", + "col836": "2cll5", + "col837": "yt1ah", + "col838": "bbc4s", + "col839": "1qncu", + "col840": "fbpup", + "col841": "lm6he", + "col842": "zlgou", + "col843": "x9t18", + "col844": "qw58d", + "col845": "xenzm", + "col846": "alkk3", + "col847": "hvsrr", + "col848": "gd8rc", + "col849": "v30s5", + "col850": "jz0ki", + "col851": "nsc9t", + "col852": "xpvdd", + "col853": "zo5gu", + "col854": "l7yzb", + "col855": "5r9jb", + "col856": "b3aa4", + "col857": "mcn20", + "col858": "qrj62", + "col859": "j1g4q", + "col860": "1mb5m", + "col861": "k91vs", + "col862": "hrc0s", + "col863": "b0s1p", + "col864": "df9bs", + "col865": "oqh8j", + "col866": "cf5x6", + "col867": "irxg2", + "col868": "b2k35", + "col869": "66vbd", + "col870": "ldzqw", + "col871": "cfv77", + "col872": "e6h7z", + "col873": "hyuam", + "col874": "mp1a8", + "col875": "h9y36", + "col876": "8lkma", + "col877": "ubswx", + "col878": "4w6q0", + "col879": "icsea", + "col880": "bkvjf", + "col881": "xw0j0", + "col882": "udisr", + "col883": "q8luz", + "col884": "w97gd", + "col885": "i2iwe", + "col886": "r5kev", + "col887": "2kbhg", + "col888": "7abdg", + "col889": "jqyha", + "col890": "7cqeb", + "col891": "v0sla", + "col892": "u6myq", + "col893": "tcqrd", + "col894": "fpiqd", + "col895": "viwnz", + "col896": "xldob", + "col897": "m9ei9", + "col898": "ee2x8", + "col899": "c9em2", + "col900": "51muh", + "col901": "t9zig", + "col902": "9xqrn", + "col903": "4t1jo", + "col904": "y67km", + "col905": "vg2t9", + "col906": "krsss", + "col907": "mpv5l", + "col908": "wqdsj", + "col909": "rt9rs", + "col910": "aa0fk", + "col911": "297qu", + "col912": "fxcol", + "col913": "kg6of", + "col914": "p9o12", + "col915": "dcbl4", + "col916": "j4ui1", + "col917": "8wfc3", + "col918": "nhci2", + "col919": "17yno", + "col920": "v8teo", + "col921": "x964i", + "col922": "df2cv", + "col923": "hm3tf", + "col924": "78xx4", + "col925": "5b4m8", + "col926": "bx288", + "col927": "lg514", + "col928": "zo34p", + "col929": "2qrrr", + "col930": "ni4tp", + "col931": "f1r1p", + "col932": "670p7", + "col933": "4u51r", + "col934": "bpjl4", + "col935": "pilj6", + "col936": "gy0yb", + "col937": "or4pd", + "col938": "pnx5a", + "col939": "kpnv3", + "col940": "okhao", + "col941": "aggwq", + "col942": "a6ann", + "col943": "pv4fi", + "col944": "kxutb", + "col945": "47qsy", + "col946": "t6vgo", + "col947": "mt70o", + "col948": "teneg", + "col949": "kbow2", + "col950": "nhwmw", + "col951": "fwacf", + "col952": "rprow", + "col953": "sx1q5", + "col954": "r2zeh", + "col955": "539jt", + "col956": "3ehn7", + "col957": "v5dex", + "col958": "ruudq", + "col959": "pv99b", + "col960": "z1hv4", + "col961": "pu884", + "col962": "bk1wm", + "col963": "ae6uc", + "col964": "ro3r2", + "col965": "26kk9", + "col966": "57z5m", + "col967": "bxlee", + "col968": "1xke3", + "col969": "t5gbr", + "col970": "bxpex", + "col971": "f9h46", + "col972": "w605b", + "col973": "mbmyd", + "col974": "3s0l1", + "col975": "t3b7b", + "col976": "tbqe4", + "col977": "ci4bh", + "col978": "8opg2", + "col979": "avbdy", + "col980": "z31xc", + "col981": "1osu8", + "col982": "ogavu", + "col983": "b7grz", + "col984": "qizd6", + "col985": "x5ko3", + "col986": "b7lum", + "col987": "dsuxl", + "col988": "2rsyp", + "col989": "6w5lv", + "col990": "mt1e0", + "col991": "utagq", + "col992": "f8nc4", + "col993": "cpsm5", + "col994": "sxnkr", + "col995": "wnih9", + "col996": "cg0kk", + "col997": "znpk6", + "col998": "n0c7l", + "col999": "3qyoq" + }, + { + "name": "Serrano Lott", + "gender": "male", + "col0": "lczj8", + "col1": "qf8a4", + "col2": "ybjhb", + "col3": "j64e9", + "col4": "gos7l", + "col5": "cvyrs", + "col6": "anm50", + "col7": "mzghy", + "col8": "n4bbk", + "col9": "od9ml", + "col10": "l0wfj", + "col11": "p1th4", + "col12": "13kx7", + "col13": "f8u4c", + "col14": "yg5e3", + "col15": "etseh", + "col16": "tk606", + "col17": "fmgqr", + "col18": "2syby", + "col19": "egciq", + "col20": "z4nv6", + "col21": "xrwhs", + "col22": "v7za8", + "col23": "980si", + "col24": "1t13p", + "col25": "rvutu", + "col26": "d247q", + "col27": "5zw5a", + "col28": "y9435", + "col29": "ssz0o", + "col30": "x7zk1", + "col31": "u09cf", + "col32": "4cob2", + "col33": "124nq", + "col34": "rphft", + "col35": "aoq4n", + "col36": "xau6r", + "col37": "kcakx", + "col38": "roa4m", + "col39": "nanel", + "col40": "13sqj", + "col41": "m6u19", + "col42": "6h4ad", + "col43": "90h3o", + "col44": "qpkhy", + "col45": "jk07c", + "col46": "sgf4x", + "col47": "op9ii", + "col48": "3rlhm", + "col49": "t2rxk", + "col50": "ab0ey", + "col51": "ulprb", + "col52": "ocl03", + "col53": "gqi0m", + "col54": "dkjir", + "col55": "vh7tv", + "col56": "ipbkv", + "col57": "ddlhy", + "col58": "97c9b", + "col59": "eok89", + "col60": "5llft", + "col61": "lvh8d", + "col62": "3lp96", + "col63": "7hyv7", + "col64": "6kons", + "col65": "o8ten", + "col66": "tbdaa", + "col67": "swp33", + "col68": "jbltl", + "col69": "ilbx0", + "col70": "3ed13", + "col71": "0neog", + "col72": "szlmv", + "col73": "9zxj2", + "col74": "nukdx", + "col75": "kpygh", + "col76": "umlx7", + "col77": "gu372", + "col78": "h2yjj", + "col79": "hmvuh", + "col80": "m68q2", + "col81": "sxoaq", + "col82": "zaf1g", + "col83": "rpr2b", + "col84": "vtdby", + "col85": "m8pbf", + "col86": "7iqup", + "col87": "78ncq", + "col88": "gvf5m", + "col89": "y7sp0", + "col90": "zsaov", + "col91": "csq3w", + "col92": "0piwu", + "col93": "s5dbt", + "col94": "jdks0", + "col95": "gnng0", + "col96": "k6e67", + "col97": "otujm", + "col98": "593j4", + "col99": "jev68", + "col100": "jql8b", + "col101": "00ozm", + "col102": "v6io7", + "col103": "s2ue4", + "col104": "82k8i", + "col105": "k3bpp", + "col106": "m4m28", + "col107": "gyryi", + "col108": "bqz2z", + "col109": "5nbze", + "col110": "zcox0", + "col111": "njxvz", + "col112": "9yr27", + "col113": "3lo01", + "col114": "1o4po", + "col115": "vvuur", + "col116": "jq2ir", + "col117": "fglhb", + "col118": "kaikg", + "col119": "eai9v", + "col120": "fu8v2", + "col121": "9b1wc", + "col122": "ug7ru", + "col123": "gib38", + "col124": "d3i67", + "col125": "yvjyh", + "col126": "vlnt2", + "col127": "rnvpa", + "col128": "i89i5", + "col129": "ksly4", + "col130": "dmv4e", + "col131": "reu0k", + "col132": "szn3j", + "col133": "hgj1o", + "col134": "4w8ut", + "col135": "iwzo4", + "col136": "z5tli", + "col137": "7pocv", + "col138": "yj6cg", + "col139": "xzarv", + "col140": "nko4c", + "col141": "igsxb", + "col142": "4xx1l", + "col143": "3dpjm", + "col144": "5izs3", + "col145": "s9fo0", + "col146": "qftb8", + "col147": "kwhfe", + "col148": "yaa73", + "col149": "s8n6a", + "col150": "qfysq", + "col151": "43rw8", + "col152": "lmkeq", + "col153": "trnch", + "col154": "bohbk", + "col155": "wxxu5", + "col156": "74ccw", + "col157": "y9e49", + "col158": "c89lk", + "col159": "9f5kc", + "col160": "46kk0", + "col161": "9r8pc", + "col162": "u04vs", + "col163": "9kyxe", + "col164": "5p8na", + "col165": "qd38d", + "col166": "8bjvf", + "col167": "77w95", + "col168": "fqnpn", + "col169": "0k2ax", + "col170": "n1p6g", + "col171": "f3vbn", + "col172": "q24jk", + "col173": "gnzz4", + "col174": "p861a", + "col175": "9kqht", + "col176": "ufasy", + "col177": "egdgv", + "col178": "rrvt6", + "col179": "u2ndr", + "col180": "btlio", + "col181": "etivk", + "col182": "gorfp", + "col183": "k2kmm", + "col184": "849d1", + "col185": "s060n", + "col186": "c1os8", + "col187": "fn8kg", + "col188": "jcmrj", + "col189": "bwret", + "col190": "6921a", + "col191": "wckn5", + "col192": "jdbde", + "col193": "xugxt", + "col194": "x7oh4", + "col195": "et7a0", + "col196": "yipzc", + "col197": "05ein", + "col198": "erx5l", + "col199": "sdsxk", + "col200": "5ax3d", + "col201": "kexdd", + "col202": "9glai", + "col203": "lq12v", + "col204": "19lyy", + "col205": "ktlsq", + "col206": "gtqgx", + "col207": "l744t", + "col208": "vv6i3", + "col209": "7vzlc", + "col210": "j2wk1", + "col211": "j550k", + "col212": "olecg", + "col213": "lbelb", + "col214": "l7zml", + "col215": "6rwfn", + "col216": "hazji", + "col217": "l9200", + "col218": "xnh2n", + "col219": "8emg8", + "col220": "r4ksu", + "col221": "c0vi1", + "col222": "zuvqo", + "col223": "2yiis", + "col224": "bqe24", + "col225": "8or0t", + "col226": "x8nfs", + "col227": "d7g9g", + "col228": "skd2e", + "col229": "zeoog", + "col230": "n76pp", + "col231": "uqugz", + "col232": "785q4", + "col233": "gvn81", + "col234": "0miti", + "col235": "817xb", + "col236": "nwx1a", + "col237": "qnkz8", + "col238": "wymod", + "col239": "03tev", + "col240": "tahfr", + "col241": "xgoxh", + "col242": "3nmzz", + "col243": "9vfvi", + "col244": "adysv", + "col245": "1c0kl", + "col246": "y6l58", + "col247": "v5m7n", + "col248": "2up0q", + "col249": "w7lbp", + "col250": "vil8d", + "col251": "e2cee", + "col252": "awo0u", + "col253": "p3vjo", + "col254": "37p15", + "col255": "opwjs", + "col256": "e0cg8", + "col257": "aqhq8", + "col258": "4edbb", + "col259": "chnpc", + "col260": "wwnqz", + "col261": "sv13m", + "col262": "7o3u8", + "col263": "e8hyd", + "col264": "oy7f9", + "col265": "sfec0", + "col266": "389p6", + "col267": "ip71a", + "col268": "ttlsa", + "col269": "rkmh0", + "col270": "hinvm", + "col271": "b2svt", + "col272": "y7r4e", + "col273": "d86c5", + "col274": "z7lat", + "col275": "m2ab0", + "col276": "6azcl", + "col277": "lrxjw", + "col278": "h3hur", + "col279": "ziqlj", + "col280": "cb1hi", + "col281": "yhwlv", + "col282": "ut9le", + "col283": "0xkkb", + "col284": "1yb0o", + "col285": "906dp", + "col286": "dv4ss", + "col287": "wym6i", + "col288": "zwzn0", + "col289": "acr5h", + "col290": "o7ydj", + "col291": "cbchb", + "col292": "jh83l", + "col293": "d4rmy", + "col294": "bokct", + "col295": "hecu0", + "col296": "thqun", + "col297": "0ovqw", + "col298": "2z5fx", + "col299": "966hp", + "col300": "litd3", + "col301": "11mum", + "col302": "l08mu", + "col303": "itytm", + "col304": "tb2h1", + "col305": "ku0rw", + "col306": "mt8je", + "col307": "3mgbp", + "col308": "5ql8a", + "col309": "me6uq", + "col310": "sraph", + "col311": "kn1ok", + "col312": "9vim1", + "col313": "k55tm", + "col314": "v1clh", + "col315": "8daxd", + "col316": "9eko8", + "col317": "ig5t3", + "col318": "tqydf", + "col319": "ohrod", + "col320": "xf5ey", + "col321": "qfskp", + "col322": "i6wmj", + "col323": "ed4ij", + "col324": "fr4ib", + "col325": "ewm6c", + "col326": "jqdo4", + "col327": "dwxf8", + "col328": "lrvkh", + "col329": "p3sh5", + "col330": "s1yus", + "col331": "99nyr", + "col332": "b2h4o", + "col333": "muaty", + "col334": "xwzxo", + "col335": "7y1pl", + "col336": "ejsgl", + "col337": "6khvy", + "col338": "qaysv", + "col339": "tl8sd", + "col340": "dbv78", + "col341": "ahpuj", + "col342": "yxxf5", + "col343": "ot695", + "col344": "kk5g5", + "col345": "5uyu0", + "col346": "fy68s", + "col347": "9e8we", + "col348": "yxsal", + "col349": "ctr61", + "col350": "ifkqm", + "col351": "p3mvl", + "col352": "0dyze", + "col353": "f02x2", + "col354": "y01ka", + "col355": "im6aq", + "col356": "ukd9p", + "col357": "xzr8y", + "col358": "raol0", + "col359": "kn8iv", + "col360": "zc1g3", + "col361": "x1e2o", + "col362": "ys18f", + "col363": "muv4n", + "col364": "iiw51", + "col365": "3shsb", + "col366": "jg1iz", + "col367": "zjy0p", + "col368": "t6m2g", + "col369": "u0567", + "col370": "zxw7l", + "col371": "ktr64", + "col372": "or9ze", + "col373": "hhcmx", + "col374": "lrnrh", + "col375": "noo1d", + "col376": "aqsd0", + "col377": "m23we", + "col378": "c4hr4", + "col379": "hrnsp", + "col380": "gymsg", + "col381": "fndca", + "col382": "3xfo3", + "col383": "fl3k7", + "col384": "d0oxs", + "col385": "2d67e", + "col386": "ut2jo", + "col387": "h5wxb", + "col388": "7nfnb", + "col389": "ga04q", + "col390": "khn8u", + "col391": "4mgnr", + "col392": "glzjl", + "col393": "0171y", + "col394": "vrd05", + "col395": "nrwfv", + "col396": "w6ebm", + "col397": "egug9", + "col398": "dsgj5", + "col399": "jsovh", + "col400": "awwox", + "col401": "35ndz", + "col402": "4x70f", + "col403": "g6t9e", + "col404": "07mb5", + "col405": "6z5yz", + "col406": "apzl2", + "col407": "eeg75", + "col408": "jrca4", + "col409": "rkwjm", + "col410": "8qbns", + "col411": "2mvj7", + "col412": "qyz70", + "col413": "xnwdk", + "col414": "2a700", + "col415": "csv72", + "col416": "jqu4u", + "col417": "5ly0v", + "col418": "8wozz", + "col419": "m4i8f", + "col420": "76rxk", + "col421": "0uv0r", + "col422": "5rrj6", + "col423": "wtr1e", + "col424": "jx8r1", + "col425": "zxtul", + "col426": "8uj7x", + "col427": "dysum", + "col428": "1yi7o", + "col429": "p3ara", + "col430": "a67ix", + "col431": "4unip", + "col432": "vu3yp", + "col433": "trnah", + "col434": "tky5l", + "col435": "hrp96", + "col436": "9a44e", + "col437": "jos9u", + "col438": "wbavh", + "col439": "q73mj", + "col440": "8d8nl", + "col441": "dxwqj", + "col442": "izxqj", + "col443": "g9wwm", + "col444": "oirze", + "col445": "p1ebx", + "col446": "x8t2q", + "col447": "q2g10", + "col448": "87nzb", + "col449": "9pwyv", + "col450": "k0osy", + "col451": "tm7bu", + "col452": "7tid3", + "col453": "g7t68", + "col454": "mcst7", + "col455": "kkldc", + "col456": "iegf4", + "col457": "a65v0", + "col458": "rb0si", + "col459": "8slyi", + "col460": "zvc6v", + "col461": "tgx53", + "col462": "qaoww", + "col463": "tert9", + "col464": "ejhoq", + "col465": "b098n", + "col466": "q4rpj", + "col467": "3h2yo", + "col468": "exhlo", + "col469": "0065d", + "col470": "uwe3h", + "col471": "o8vmp", + "col472": "brxii", + "col473": "vitp7", + "col474": "0qszd", + "col475": "xo05r", + "col476": "gopr4", + "col477": "7rfmt", + "col478": "xn04t", + "col479": "aq116", + "col480": "0w4ky", + "col481": "r4ndd", + "col482": "6jwud", + "col483": "e69fg", + "col484": "behw3", + "col485": "9m4xx", + "col486": "qruj3", + "col487": "m1wy2", + "col488": "vqtwj", + "col489": "awdqq", + "col490": "3ebdm", + "col491": "ruf5s", + "col492": "nc5o9", + "col493": "c5yhq", + "col494": "hgk8a", + "col495": "ka2vc", + "col496": "wlsvj", + "col497": "pule5", + "col498": "o3pu6", + "col499": "5zq0c", + "col500": "8yd2d", + "col501": "y0me8", + "col502": "k0szr", + "col503": "kgr34", + "col504": "8k47d", + "col505": "9aqiz", + "col506": "mq16h", + "col507": "k9o7d", + "col508": "ic6vi", + "col509": "a9kr3", + "col510": "s9wdy", + "col511": "5rboa", + "col512": "umga3", + "col513": "jf2h1", + "col514": "j6u23", + "col515": "3upbv", + "col516": "pc67s", + "col517": "f3m40", + "col518": "47hn3", + "col519": "wobsy", + "col520": "wruu6", + "col521": "xatt3", + "col522": "t0cby", + "col523": "0dpy1", + "col524": "14ouy", + "col525": "2077u", + "col526": "87d8a", + "col527": "rfb9y", + "col528": "xy10p", + "col529": "w78ik", + "col530": "bwjy1", + "col531": "1j6jm", + "col532": "vda62", + "col533": "5dqwq", + "col534": "p125s", + "col535": "gbpih", + "col536": "m2bno", + "col537": "b2rny", + "col538": "cweb6", + "col539": "jt02a", + "col540": "1b246", + "col541": "fgymy", + "col542": "hh3ag", + "col543": "6q87e", + "col544": "m1gg0", + "col545": "vd776", + "col546": "hurhr", + "col547": "p56jw", + "col548": "toa96", + "col549": "lpmx2", + "col550": "h4pbo", + "col551": "hd63a", + "col552": "n6ps7", + "col553": "fvamq", + "col554": "19wa6", + "col555": "kqk87", + "col556": "rfbpl", + "col557": "2b4mw", + "col558": "2ab28", + "col559": "n9n7z", + "col560": "tmtpt", + "col561": "kzih6", + "col562": "7vqdb", + "col563": "8m23c", + "col564": "e3ngh", + "col565": "5la0c", + "col566": "mobj3", + "col567": "u1a1n", + "col568": "4b83h", + "col569": "awgzo", + "col570": "u0fhm", + "col571": "3x33z", + "col572": "xyxk6", + "col573": "zawan", + "col574": "7487k", + "col575": "5o9b6", + "col576": "ygaf8", + "col577": "7ww6r", + "col578": "dj6ne", + "col579": "hwsv7", + "col580": "7jhd5", + "col581": "hfcd5", + "col582": "doaqz", + "col583": "d9b90", + "col584": "m93wn", + "col585": "c6z9x", + "col586": "6n7c2", + "col587": "pa2uj", + "col588": "bt7wu", + "col589": "sq8r3", + "col590": "jt1wo", + "col591": "88a2i", + "col592": "nm36x", + "col593": "dzw5c", + "col594": "83xfe", + "col595": "jqusx", + "col596": "odgyo", + "col597": "eywqw", + "col598": "jg5yg", + "col599": "5yblz", + "col600": "secl4", + "col601": "ni3qx", + "col602": "2zu6n", + "col603": "zbks9", + "col604": "frefe", + "col605": "jsby2", + "col606": "asazf", + "col607": "4dohw", + "col608": "spoam", + "col609": "en34c", + "col610": "6opw4", + "col611": "bvoau", + "col612": "d8fje", + "col613": "pievv", + "col614": "z14du", + "col615": "gnz04", + "col616": "55961", + "col617": "yrvt8", + "col618": "eb0e4", + "col619": "lbuwi", + "col620": "5m6rh", + "col621": "aw92w", + "col622": "ae8r9", + "col623": "llhpj", + "col624": "gxw8h", + "col625": "ac92w", + "col626": "blb7e", + "col627": "i1s4l", + "col628": "2gzbb", + "col629": "2w5zo", + "col630": "8hokx", + "col631": "gcnt1", + "col632": "nqe1q", + "col633": "0xyd1", + "col634": "d7bbr", + "col635": "laofs", + "col636": "mkt8e", + "col637": "z5vvy", + "col638": "adjjl", + "col639": "tiokc", + "col640": "ifcv0", + "col641": "8wp0o", + "col642": "kogn6", + "col643": "w59vr", + "col644": "cfux3", + "col645": "tq5ph", + "col646": "4rkoj", + "col647": "lx6rm", + "col648": "2lxep", + "col649": "te07q", + "col650": "pvu1o", + "col651": "01sxm", + "col652": "vjt9d", + "col653": "7wjyc", + "col654": "ejzsm", + "col655": "gi0s5", + "col656": "9mlgs", + "col657": "jlums", + "col658": "fb4zj", + "col659": "qvtqq", + "col660": "p7kwp", + "col661": "a799q", + "col662": "2rmh2", + "col663": "0ysvv", + "col664": "rx5hk", + "col665": "c95bt", + "col666": "9s5m3", + "col667": "3egyd", + "col668": "ew4za", + "col669": "2aguh", + "col670": "qoiwk", + "col671": "fnak4", + "col672": "f186m", + "col673": "kzjdk", + "col674": "0fmi6", + "col675": "lhn5x", + "col676": "yb71k", + "col677": "c3hmv", + "col678": "zulox", + "col679": "bgz7a", + "col680": "l9u5v", + "col681": "ey45o", + "col682": "5jtih", + "col683": "djes0", + "col684": "w7n4a", + "col685": "8j7yd", + "col686": "hyyzh", + "col687": "qww3f", + "col688": "fft8u", + "col689": "0v5pi", + "col690": "ahgwr", + "col691": "vk8yj", + "col692": "t239h", + "col693": "vr8dq", + "col694": "7n33e", + "col695": "jo1ue", + "col696": "mz0p4", + "col697": "kszlk", + "col698": "i56g9", + "col699": "q3pgd", + "col700": "5xvif", + "col701": "wyd2g", + "col702": "l97if", + "col703": "nqe01", + "col704": "zsvhj", + "col705": "xws2u", + "col706": "wlhtk", + "col707": "plel9", + "col708": "5lwb9", + "col709": "30d4x", + "col710": "8bwdx", + "col711": "wd8un", + "col712": "8rabn", + "col713": "1unj6", + "col714": "pcpx4", + "col715": "ii59g", + "col716": "1hn66", + "col717": "m7277", + "col718": "e0irp", + "col719": "9xqm0", + "col720": "n4voc", + "col721": "69anc", + "col722": "zdsqm", + "col723": "1fqan", + "col724": "f7lx4", + "col725": "qpsru", + "col726": "aa54c", + "col727": "a91k6", + "col728": "oktzp", + "col729": "sak9r", + "col730": "4g1a7", + "col731": "6l3uw", + "col732": "i6mft", + "col733": "jtwzx", + "col734": "jypwc", + "col735": "qmqt7", + "col736": "opogw", + "col737": "835dd", + "col738": "epusa", + "col739": "uoh3k", + "col740": "wqmrd", + "col741": "evpcj", + "col742": "kp6m8", + "col743": "p4mz6", + "col744": "8xvox", + "col745": "pcs41", + "col746": "16elw", + "col747": "87fga", + "col748": "aei1a", + "col749": "jvvvx", + "col750": "3itus", + "col751": "z0hch", + "col752": "j7t02", + "col753": "w1mrc", + "col754": "dndjf", + "col755": "v4qov", + "col756": "pzcza", + "col757": "n8niy", + "col758": "xc78q", + "col759": "8zhpu", + "col760": "u9eix", + "col761": "ohcu9", + "col762": "v8tnq", + "col763": "3qn2t", + "col764": "21bsp", + "col765": "52tfw", + "col766": "95oxg", + "col767": "amc5b", + "col768": "e4akd", + "col769": "qt5c7", + "col770": "zaaq7", + "col771": "vda6u", + "col772": "28sgw", + "col773": "r0ku5", + "col774": "3puvm", + "col775": "0dba6", + "col776": "bu3az", + "col777": "dvkby", + "col778": "az20h", + "col779": "n5122", + "col780": "9ttmu", + "col781": "i82id", + "col782": "pydsw", + "col783": "kw064", + "col784": "wp8af", + "col785": "r070j", + "col786": "ewrxd", + "col787": "dlsoo", + "col788": "kcxzy", + "col789": "iiqgf", + "col790": "aptmd", + "col791": "jcuyr", + "col792": "fghzj", + "col793": "042f8", + "col794": "50ey9", + "col795": "n309v", + "col796": "nb3d4", + "col797": "9o8lk", + "col798": "z0zrh", + "col799": "6ggdl", + "col800": "0bzm3", + "col801": "400vw", + "col802": "rqknn", + "col803": "p7vy3", + "col804": "63iji", + "col805": "00x95", + "col806": "bcv9p", + "col807": "flm8u", + "col808": "5mxfr", + "col809": "n777y", + "col810": "91333", + "col811": "3hg26", + "col812": "3b8tu", + "col813": "uhlc8", + "col814": "2ho5j", + "col815": "xoh27", + "col816": "8l6cf", + "col817": "9zwzl", + "col818": "i5tbd", + "col819": "58iu2", + "col820": "w0z1e", + "col821": "50o5g", + "col822": "5xap2", + "col823": "dy0cq", + "col824": "t4mkz", + "col825": "i69wp", + "col826": "h1i4e", + "col827": "2r0xm", + "col828": "kq3pi", + "col829": "fh9q6", + "col830": "bw027", + "col831": "h8bou", + "col832": "x300c", + "col833": "jsu7g", + "col834": "712ev", + "col835": "fbqf5", + "col836": "umb0w", + "col837": "lb8tz", + "col838": "72lze", + "col839": "lqqpw", + "col840": "4gro7", + "col841": "g5huq", + "col842": "6jkjz", + "col843": "s00bt", + "col844": "fut0n", + "col845": "r4mkb", + "col846": "o521f", + "col847": "purjp", + "col848": "u1js5", + "col849": "brgf2", + "col850": "0pgcq", + "col851": "657a4", + "col852": "ybd8g", + "col853": "070cq", + "col854": "tvqhm", + "col855": "y0bg3", + "col856": "99658", + "col857": "8rpbt", + "col858": "b54nk", + "col859": "n78ur", + "col860": "pmeya", + "col861": "df1wv", + "col862": "5g72q", + "col863": "9pokn", + "col864": "9b0d1", + "col865": "8nzgm", + "col866": "6456p", + "col867": "3is2e", + "col868": "gzgka", + "col869": "gbbnb", + "col870": "u1svx", + "col871": "3zlv7", + "col872": "crg0p", + "col873": "7gxxh", + "col874": "w6sag", + "col875": "er1oi", + "col876": "u62vu", + "col877": "lq3ic", + "col878": "ipwlt", + "col879": "nsdaa", + "col880": "7enhl", + "col881": "cuvdt", + "col882": "bx4dd", + "col883": "z8ebm", + "col884": "zlnij", + "col885": "vyf8h", + "col886": "zkjld", + "col887": "3wy7p", + "col888": "h6hf8", + "col889": "sc7i6", + "col890": "f1aq0", + "col891": "socix", + "col892": "vlkxu", + "col893": "47v81", + "col894": "ufd6m", + "col895": "s0lzv", + "col896": "i2s6h", + "col897": "wjbos", + "col898": "9kzzp", + "col899": "3128x", + "col900": "vqm4p", + "col901": "lm2w9", + "col902": "shsmt", + "col903": "nu3tc", + "col904": "ygrxw", + "col905": "ucpod", + "col906": "idu7j", + "col907": "x9cse", + "col908": "i4vvb", + "col909": "venhz", + "col910": "3juir", + "col911": "7mwjs", + "col912": "jfdyq", + "col913": "ay4op", + "col914": "fwcd5", + "col915": "9xl2d", + "col916": "culhi", + "col917": "nmi2a", + "col918": "6p5c4", + "col919": "vrdpp", + "col920": "x5v0j", + "col921": "e7taj", + "col922": "rbq0c", + "col923": "w8004", + "col924": "nyna6", + "col925": "rm9w5", + "col926": "sjf13", + "col927": "fkx24", + "col928": "eyh1x", + "col929": "w8t46", + "col930": "7l32a", + "col931": "1gcxb", + "col932": "jq0g6", + "col933": "4gsh7", + "col934": "fl79w", + "col935": "dxy42", + "col936": "k56xj", + "col937": "qa9q8", + "col938": "3jqgv", + "col939": "fh1hv", + "col940": "4on22", + "col941": "de5qe", + "col942": "aw9y2", + "col943": "o8qmk", + "col944": "xwcg8", + "col945": "13bes", + "col946": "csfk6", + "col947": "21bdv", + "col948": "p60a2", + "col949": "mdh4v", + "col950": "f94x3", + "col951": "ebn7g", + "col952": "flm8j", + "col953": "reoqn", + "col954": "3o5lk", + "col955": "r7ai9", + "col956": "ac3ot", + "col957": "ejsi4", + "col958": "27tuw", + "col959": "jfcm9", + "col960": "09lsr", + "col961": "dohvo", + "col962": "py104", + "col963": "vhp7q", + "col964": "il2hd", + "col965": "pbkuo", + "col966": "124rq", + "col967": "mnc37", + "col968": "uvylh", + "col969": "etrkt", + "col970": "qxdgo", + "col971": "sk5ke", + "col972": "dd4i9", + "col973": "74gk1", + "col974": "tkpr9", + "col975": "whqpv", + "col976": "wrcdx", + "col977": "j92vw", + "col978": "zv4ra", + "col979": "1i1c6", + "col980": "eas1m", + "col981": "enlpm", + "col982": "gnx76", + "col983": "6zpo8", + "col984": "fw33z", + "col985": "oum0h", + "col986": "kgxro", + "col987": "35cgw", + "col988": "thpta", + "col989": "mofrk", + "col990": "txyrw", + "col991": "wkla4", + "col992": "fp6in", + "col993": "39voo", + "col994": "57ylh", + "col995": "9q8ci", + "col996": "s9cxy", + "col997": "00bng", + "col998": "htly5", + "col999": "rs75h" + }, + { + "name": "Amalia Guerrero", + "gender": "female", + "col0": "rjgve", + "col1": "e54xw", + "col2": "56l2z", + "col3": "lq39x", + "col4": "lsgt9", + "col5": "muhyt", + "col6": "o9iac", + "col7": "wp6h6", + "col8": "5d0c2", + "col9": "5lxte", + "col10": "6jc4t", + "col11": "47obx", + "col12": "v2814", + "col13": "g3g0h", + "col14": "1hv03", + "col15": "ix4f6", + "col16": "jxhuq", + "col17": "6074q", + "col18": "mnnce", + "col19": "pezgu", + "col20": "d7xae", + "col21": "hsog5", + "col22": "p6rla", + "col23": "klen1", + "col24": "qc6ry", + "col25": "xsrj6", + "col26": "atn0a", + "col27": "6uk63", + "col28": "ce9oy", + "col29": "j6sjp", + "col30": "fb43c", + "col31": "0szr9", + "col32": "rbq4x", + "col33": "510q5", + "col34": "sqrgr", + "col35": "qw7tu", + "col36": "tmuu2", + "col37": "jhlkv", + "col38": "soel2", + "col39": "ubxn6", + "col40": "b9ing", + "col41": "24bxx", + "col42": "2gt52", + "col43": "g43ow", + "col44": "asvf3", + "col45": "ghgox", + "col46": "74pm2", + "col47": "6wa6q", + "col48": "osllt", + "col49": "zm057", + "col50": "h6bf4", + "col51": "lcjlg", + "col52": "sprue", + "col53": "ii5wp", + "col54": "mi4ko", + "col55": "19ie0", + "col56": "zbnj6", + "col57": "og4ib", + "col58": "hav85", + "col59": "wxnjq", + "col60": "pkqjj", + "col61": "b07fr", + "col62": "wl5c0", + "col63": "0yqpe", + "col64": "yld5c", + "col65": "hqcic", + "col66": "h4vwj", + "col67": "l6hsy", + "col68": "9nhnr", + "col69": "23jb4", + "col70": "4wmx9", + "col71": "bxmm8", + "col72": "tg5iv", + "col73": "u1i6m", + "col74": "63r0l", + "col75": "dtlbf", + "col76": "so1gp", + "col77": "ukz2a", + "col78": "0ibfp", + "col79": "7vf26", + "col80": "zptqj", + "col81": "voqtc", + "col82": "79hiw", + "col83": "8699n", + "col84": "tdalp", + "col85": "nkj7c", + "col86": "syd7x", + "col87": "gyir3", + "col88": "7378r", + "col89": "dl0qh", + "col90": "nkv6u", + "col91": "7nylc", + "col92": "1y7nn", + "col93": "0ufb9", + "col94": "feopi", + "col95": "sfh1p", + "col96": "raygp", + "col97": "i4q90", + "col98": "vhcn1", + "col99": "kqxbg", + "col100": "0iwb5", + "col101": "0oztw", + "col102": "blj7q", + "col103": "q64ar", + "col104": "x6juj", + "col105": "1gruw", + "col106": "37rzx", + "col107": "3uezu", + "col108": "3evzn", + "col109": "i2bt7", + "col110": "ic92h", + "col111": "196jf", + "col112": "50gr4", + "col113": "f061v", + "col114": "fzlwl", + "col115": "69b7d", + "col116": "oztzh", + "col117": "17t9y", + "col118": "y9qoc", + "col119": "3qdtw", + "col120": "qfg7g", + "col121": "j9v4h", + "col122": "r231o", + "col123": "ctih3", + "col124": "3s70n", + "col125": "itfgq", + "col126": "fixpv", + "col127": "t1320", + "col128": "gutsz", + "col129": "4kq6y", + "col130": "dul5p", + "col131": "hq81v", + "col132": "i3xvb", + "col133": "ksnwq", + "col134": "xobxl", + "col135": "5e05p", + "col136": "dsxc8", + "col137": "l83ag", + "col138": "ldle1", + "col139": "ye06r", + "col140": "icujc", + "col141": "30cxw", + "col142": "lx8ny", + "col143": "r7ose", + "col144": "06fu2", + "col145": "s6p2c", + "col146": "pbfss", + "col147": "vfoys", + "col148": "2kh6a", + "col149": "jaisg", + "col150": "97rl1", + "col151": "m127g", + "col152": "jpa7x", + "col153": "m9gcw", + "col154": "24elm", + "col155": "n3lin", + "col156": "kknwt", + "col157": "9cdcu", + "col158": "2q5g6", + "col159": "nz68r", + "col160": "ri85l", + "col161": "kbb0i", + "col162": "s6c04", + "col163": "7o3xm", + "col164": "e1jyb", + "col165": "nug0r", + "col166": "slt0e", + "col167": "532kv", + "col168": "dyjrv", + "col169": "ef35q", + "col170": "kdm53", + "col171": "8f8bg", + "col172": "32c15", + "col173": "hfg95", + "col174": "llff7", + "col175": "wbg6d", + "col176": "jz2bo", + "col177": "aps14", + "col178": "d3ny3", + "col179": "x615g", + "col180": "tv3yv", + "col181": "xg6oj", + "col182": "jxjfs", + "col183": "mlrbi", + "col184": "7kmbb", + "col185": "usz0l", + "col186": "9g0cd", + "col187": "lizpk", + "col188": "4eilk", + "col189": "g9rhh", + "col190": "h627a", + "col191": "60fy0", + "col192": "kxbno", + "col193": "0ltfi", + "col194": "7t2wa", + "col195": "0sf2i", + "col196": "ns6pr", + "col197": "457v5", + "col198": "a6k4q", + "col199": "kmr6e", + "col200": "fp1wq", + "col201": "lr8el", + "col202": "5t9qz", + "col203": "mxhu8", + "col204": "v0u02", + "col205": "nme0f", + "col206": "yg39q", + "col207": "2z4sf", + "col208": "ogwfg", + "col209": "suhtv", + "col210": "jsgrk", + "col211": "k83z5", + "col212": "j20rb", + "col213": "7wnxm", + "col214": "4bd4p", + "col215": "i1wf9", + "col216": "ypfrk", + "col217": "79sbn", + "col218": "x59by", + "col219": "lv346", + "col220": "ghrnt", + "col221": "rooos", + "col222": "ojhrx", + "col223": "jjbjg", + "col224": "x5mv7", + "col225": "3djzw", + "col226": "7ln2b", + "col227": "whwx8", + "col228": "rel6d", + "col229": "z7o7f", + "col230": "2katz", + "col231": "wzipi", + "col232": "i3nfj", + "col233": "v16md", + "col234": "rz0he", + "col235": "uor5q", + "col236": "zgzdr", + "col237": "7oqq2", + "col238": "uuk80", + "col239": "5flwq", + "col240": "qjdi0", + "col241": "tpofd", + "col242": "mawjl", + "col243": "5465c", + "col244": "yb819", + "col245": "z4wng", + "col246": "5q7ao", + "col247": "gbbhd", + "col248": "yfr6r", + "col249": "1weq1", + "col250": "fts3n", + "col251": "lyupf", + "col252": "pvi6b", + "col253": "txc27", + "col254": "iouvl", + "col255": "fn7ii", + "col256": "w3xyw", + "col257": "z24oh", + "col258": "qfaru", + "col259": "3s5kq", + "col260": "2j9oa", + "col261": "ntyew", + "col262": "bebsa", + "col263": "tyx1n", + "col264": "kndnp", + "col265": "ycekm", + "col266": "x3rfy", + "col267": "uy0gf", + "col268": "a4o0n", + "col269": "xz9p6", + "col270": "grnt2", + "col271": "407k7", + "col272": "8ru3l", + "col273": "4kcpk", + "col274": "jbeae", + "col275": "9e19m", + "col276": "u33pm", + "col277": "34oiv", + "col278": "sb456", + "col279": "rip7o", + "col280": "af9tr", + "col281": "pr7zb", + "col282": "slye8", + "col283": "xzsp8", + "col284": "kv4di", + "col285": "2p7f1", + "col286": "tb2vo", + "col287": "gc3ps", + "col288": "qfy3o", + "col289": "icltx", + "col290": "gtdr2", + "col291": "hbk96", + "col292": "elhlg", + "col293": "ydv1y", + "col294": "kpnrt", + "col295": "egb2k", + "col296": "zyz7s", + "col297": "sk835", + "col298": "p20ey", + "col299": "d55rg", + "col300": "nyboy", + "col301": "vnqf7", + "col302": "oj7ra", + "col303": "86z33", + "col304": "fgq6h", + "col305": "pdkac", + "col306": "5zs1j", + "col307": "od7fd", + "col308": "9l6v7", + "col309": "gkut9", + "col310": "2rdue", + "col311": "ssucf", + "col312": "7qrel", + "col313": "6bkxn", + "col314": "2fw4k", + "col315": "03loq", + "col316": "2fuyz", + "col317": "obsbz", + "col318": "3dms3", + "col319": "z933o", + "col320": "ingif", + "col321": "4dpge", + "col322": "uwoms", + "col323": "jhg5k", + "col324": "4t1t0", + "col325": "0u1bf", + "col326": "vg7ba", + "col327": "c8zkf", + "col328": "2gqv9", + "col329": "esc3a", + "col330": "0d62h", + "col331": "4404a", + "col332": "tbgny", + "col333": "1hbkp", + "col334": "l5l3x", + "col335": "fpf1e", + "col336": "mkxd0", + "col337": "eaxco", + "col338": "68yzx", + "col339": "xvvu3", + "col340": "zn67n", + "col341": "9yy9w", + "col342": "1uy7v", + "col343": "h76d6", + "col344": "410vr", + "col345": "4d3fk", + "col346": "w4uls", + "col347": "d3kwu", + "col348": "jxjt8", + "col349": "3ij63", + "col350": "8dwyb", + "col351": "us7o5", + "col352": "6och9", + "col353": "t481w", + "col354": "pi966", + "col355": "f8ger", + "col356": "agoyo", + "col357": "hij0g", + "col358": "i2vt5", + "col359": "kcfto", + "col360": "o7d7s", + "col361": "ad9l0", + "col362": "yyan7", + "col363": "jkebi", + "col364": "x2o6d", + "col365": "h9hed", + "col366": "45nka", + "col367": "5nwyi", + "col368": "rxgv2", + "col369": "lrr7v", + "col370": "ao9v9", + "col371": "6qpj6", + "col372": "e2h3b", + "col373": "uqgp0", + "col374": "7dojv", + "col375": "eegpj", + "col376": "dt53p", + "col377": "l4rxp", + "col378": "ykwk0", + "col379": "g0l85", + "col380": "c3xtv", + "col381": "4lhed", + "col382": "dvsix", + "col383": "xydfx", + "col384": "qlc60", + "col385": "4yj5y", + "col386": "vbkzh", + "col387": "onuy7", + "col388": "ofv0k", + "col389": "cs8pt", + "col390": "dnrvu", + "col391": "fj8ea", + "col392": "qmlz1", + "col393": "z93n6", + "col394": "523sf", + "col395": "9j8tw", + "col396": "uhjpf", + "col397": "k5g7i", + "col398": "4uakf", + "col399": "nwgll", + "col400": "3dddl", + "col401": "f5ju9", + "col402": "79i8q", + "col403": "2p38o", + "col404": "3sqgr", + "col405": "o3s07", + "col406": "qkvqw", + "col407": "fti2r", + "col408": "oslf0", + "col409": "x2wjt", + "col410": "l4vup", + "col411": "0ksa2", + "col412": "3blk1", + "col413": "wv5lj", + "col414": "bwxt3", + "col415": "zvye5", + "col416": "ezzxm", + "col417": "m6l4j", + "col418": "vdydr", + "col419": "pwrfg", + "col420": "6vy4y", + "col421": "6rnba", + "col422": "e9sqs", + "col423": "prou5", + "col424": "b25ep", + "col425": "j8iu5", + "col426": "5s1zl", + "col427": "lxh24", + "col428": "eh4y1", + "col429": "kvgg2", + "col430": "pjfdk", + "col431": "1jzfi", + "col432": "pmb1u", + "col433": "fs0gm", + "col434": "gsp2u", + "col435": "mrya3", + "col436": "alk95", + "col437": "kt1j1", + "col438": "1a1rw", + "col439": "hv8bh", + "col440": "pqfif", + "col441": "cmqpv", + "col442": "83mos", + "col443": "xqt24", + "col444": "k0cen", + "col445": "um9fo", + "col446": "si7ew", + "col447": "xoovb", + "col448": "lmr38", + "col449": "fc434", + "col450": "cs98n", + "col451": "b4egw", + "col452": "x044i", + "col453": "l2ipd", + "col454": "wkyo3", + "col455": "d18yv", + "col456": "l3qgv", + "col457": "1cmcb", + "col458": "vv5cc", + "col459": "2crmm", + "col460": "ior6h", + "col461": "9oz98", + "col462": "6mgq1", + "col463": "fp4q7", + "col464": "4fml8", + "col465": "pujw6", + "col466": "l9ncx", + "col467": "t36yh", + "col468": "u1uma", + "col469": "t9o6z", + "col470": "l90g2", + "col471": "bw7j6", + "col472": "8pj4k", + "col473": "nqhl6", + "col474": "pjpyo", + "col475": "nz14f", + "col476": "pkh8s", + "col477": "zfmva", + "col478": "a7kao", + "col479": "eoxfu", + "col480": "mhcmr", + "col481": "ha1pb", + "col482": "u9al9", + "col483": "xjtvd", + "col484": "3d70b", + "col485": "9jise", + "col486": "337d5", + "col487": "reaqr", + "col488": "9jia0", + "col489": "s83kx", + "col490": "vi9yg", + "col491": "wcnli", + "col492": "ahigz", + "col493": "jeblu", + "col494": "km5tj", + "col495": "54vwe", + "col496": "j9uvs", + "col497": "l4dah", + "col498": "7tm5k", + "col499": "9lomb", + "col500": "fxefz", + "col501": "u0wjj", + "col502": "gt5ai", + "col503": "d57xa", + "col504": "voucg", + "col505": "cnc7h", + "col506": "cuoex", + "col507": "52w2c", + "col508": "dtb3x", + "col509": "5w51v", + "col510": "a7oks", + "col511": "jrveh", + "col512": "jgtsw", + "col513": "9ijtz", + "col514": "h836z", + "col515": "zw7t9", + "col516": "kj9xg", + "col517": "a78lt", + "col518": "txoxz", + "col519": "ezy08", + "col520": "czsyt", + "col521": "l0lwi", + "col522": "bxq54", + "col523": "x2kiu", + "col524": "8h6i1", + "col525": "vpk6t", + "col526": "k8beg", + "col527": "uoiqs", + "col528": "ico15", + "col529": "s17nl", + "col530": "gxopo", + "col531": "zomm3", + "col532": "fhf1y", + "col533": "ocyk8", + "col534": "zs758", + "col535": "qucu6", + "col536": "t2qr8", + "col537": "46yua", + "col538": "50d95", + "col539": "7iuk0", + "col540": "42sku", + "col541": "si8dc", + "col542": "fdlw0", + "col543": "85bdz", + "col544": "59yxj", + "col545": "qxfpl", + "col546": "2fzym", + "col547": "9zuyh", + "col548": "yvroq", + "col549": "d2rs5", + "col550": "xmk91", + "col551": "pt7d9", + "col552": "38pdl", + "col553": "zchj7", + "col554": "rzveo", + "col555": "d2o2i", + "col556": "rk16z", + "col557": "fn6zi", + "col558": "tk9q6", + "col559": "zxdcu", + "col560": "wo24j", + "col561": "wjipp", + "col562": "yi2fz", + "col563": "w7jes", + "col564": "v67g2", + "col565": "2vvhx", + "col566": "jyrvu", + "col567": "ij37n", + "col568": "8ry9c", + "col569": "crig5", + "col570": "fgsgj", + "col571": "ps8yv", + "col572": "fcow4", + "col573": "ok7ap", + "col574": "922lt", + "col575": "u7vud", + "col576": "7lo1b", + "col577": "gj1gi", + "col578": "unzxl", + "col579": "seyph", + "col580": "sgrr7", + "col581": "mtwgz", + "col582": "n15rt", + "col583": "4t85b", + "col584": "cmu1v", + "col585": "3wod3", + "col586": "qt0ji", + "col587": "qn9tc", + "col588": "23yg8", + "col589": "6y1j4", + "col590": "wo5jb", + "col591": "ikpmx", + "col592": "cfcxr", + "col593": "9fnht", + "col594": "5oq8d", + "col595": "bgdle", + "col596": "rc2pr", + "col597": "3nnkk", + "col598": "s8p4s", + "col599": "jjmlt", + "col600": "d5dmg", + "col601": "esjig", + "col602": "gny7j", + "col603": "20d94", + "col604": "7f7r8", + "col605": "ks6e6", + "col606": "8ava3", + "col607": "echet", + "col608": "da3zr", + "col609": "ry2t8", + "col610": "3j6y4", + "col611": "zffza", + "col612": "vrj9u", + "col613": "tecjz", + "col614": "3pj5r", + "col615": "ae70q", + "col616": "211gj", + "col617": "vcmkl", + "col618": "gpjyy", + "col619": "z7fon", + "col620": "unof3", + "col621": "eidkn", + "col622": "rr8jk", + "col623": "ct4zy", + "col624": "o8r8v", + "col625": "8gvri", + "col626": "6rc0y", + "col627": "i6oay", + "col628": "332qc", + "col629": "t18fi", + "col630": "5ri6j", + "col631": "anwij", + "col632": "6mahg", + "col633": "hpcmj", + "col634": "y1e3v", + "col635": "cwtk3", + "col636": "nicfp", + "col637": "innkj", + "col638": "3ipxn", + "col639": "5fcyh", + "col640": "euzr3", + "col641": "talwh", + "col642": "xbyj8", + "col643": "gnols", + "col644": "y3un1", + "col645": "d7o3w", + "col646": "08niw", + "col647": "1ipqw", + "col648": "o5l95", + "col649": "8e0fl", + "col650": "3tkjn", + "col651": "f9vjw", + "col652": "m6pat", + "col653": "s35tq", + "col654": "c4myj", + "col655": "cozeb", + "col656": "wljqf", + "col657": "nttwe", + "col658": "fmosu", + "col659": "tkz2x", + "col660": "yrpwe", + "col661": "ctewo", + "col662": "gu5wu", + "col663": "7vbod", + "col664": "7n9vw", + "col665": "0d638", + "col666": "h6cjc", + "col667": "gjfo9", + "col668": "fkvmi", + "col669": "e4es4", + "col670": "gf0w2", + "col671": "pw9zf", + "col672": "nug3w", + "col673": "8gg45", + "col674": "1tjij", + "col675": "lldqy", + "col676": "lb0vi", + "col677": "d1qbt", + "col678": "6v354", + "col679": "8kxty", + "col680": "v32zo", + "col681": "th8o4", + "col682": "5ke9u", + "col683": "i6bik", + "col684": "5gbj5", + "col685": "6sjz1", + "col686": "k5fv5", + "col687": "scirm", + "col688": "ewiat", + "col689": "cfmnk", + "col690": "p0gsv", + "col691": "a6i83", + "col692": "wc6xq", + "col693": "s6lc0", + "col694": "k3i7i", + "col695": "kzafv", + "col696": "2t4os", + "col697": "yac1j", + "col698": "x8e9b", + "col699": "tpdl1", + "col700": "5231n", + "col701": "8urxe", + "col702": "lykgf", + "col703": "7buzo", + "col704": "lzbzk", + "col705": "7e2oo", + "col706": "z81qc", + "col707": "p9iix", + "col708": "39v3v", + "col709": "0cybr", + "col710": "tgs7a", + "col711": "n5fvp", + "col712": "x89vh", + "col713": "ex4sz", + "col714": "njoy7", + "col715": "eefit", + "col716": "t80w0", + "col717": "vu2dy", + "col718": "5kzsy", + "col719": "b0lzn", + "col720": "qtko1", + "col721": "0qnu1", + "col722": "vl001", + "col723": "qts5m", + "col724": "6dm8e", + "col725": "2ntjg", + "col726": "z3que", + "col727": "t85eo", + "col728": "xd29v", + "col729": "2qwc7", + "col730": "tirb2", + "col731": "719t9", + "col732": "hxw91", + "col733": "bwviu", + "col734": "lotvr", + "col735": "rm6tb", + "col736": "66s6l", + "col737": "gtz3t", + "col738": "r26wt", + "col739": "18eig", + "col740": "6yh75", + "col741": "3ri2y", + "col742": "sdhd0", + "col743": "5pfb3", + "col744": "vi84m", + "col745": "8i6pp", + "col746": "ztej3", + "col747": "4a9oc", + "col748": "h5298", + "col749": "i7a7h", + "col750": "lmac6", + "col751": "omi8p", + "col752": "0l7v3", + "col753": "gnfz0", + "col754": "j6nb1", + "col755": "s9qdo", + "col756": "3bmd0", + "col757": "zkf7a", + "col758": "7pcae", + "col759": "fj7ld", + "col760": "z076l", + "col761": "q1e1o", + "col762": "e73fy", + "col763": "0j2j5", + "col764": "w9hb9", + "col765": "ncqu6", + "col766": "mdjt8", + "col767": "0gpjk", + "col768": "sxidh", + "col769": "ycm6p", + "col770": "1tsra", + "col771": "08u3n", + "col772": "ibobj", + "col773": "d9otg", + "col774": "gp5p0", + "col775": "jg70i", + "col776": "6fms8", + "col777": "lgpha", + "col778": "h5n5a", + "col779": "554id", + "col780": "86cu0", + "col781": "fcz40", + "col782": "htizl", + "col783": "uf663", + "col784": "ni9re", + "col785": "8he99", + "col786": "i1k6u", + "col787": "e8vza", + "col788": "rninn", + "col789": "2oake", + "col790": "rfg83", + "col791": "s5nss", + "col792": "4x44l", + "col793": "0kp28", + "col794": "ts5i6", + "col795": "tufwd", + "col796": "4bivu", + "col797": "ewjp7", + "col798": "jx92b", + "col799": "px9jl", + "col800": "p7rtv", + "col801": "hd7i1", + "col802": "709rt", + "col803": "go3ll", + "col804": "ppidz", + "col805": "qyolb", + "col806": "q065f", + "col807": "bnqwg", + "col808": "xx0dr", + "col809": "usf03", + "col810": "15gj5", + "col811": "0xkh9", + "col812": "b8xcg", + "col813": "99m7y", + "col814": "mb2w4", + "col815": "pa507", + "col816": "fb6il", + "col817": "wm7wf", + "col818": "97td9", + "col819": "md61y", + "col820": "vufeo", + "col821": "cqu8a", + "col822": "n1uhe", + "col823": "qt2iv", + "col824": "xmgy7", + "col825": "c2ljg", + "col826": "dgdoy", + "col827": "dnay7", + "col828": "brccl", + "col829": "cxens", + "col830": "6z1ub", + "col831": "2l6kf", + "col832": "8t300", + "col833": "bztcw", + "col834": "l6qgm", + "col835": "798nt", + "col836": "l9kcx", + "col837": "ivvf8", + "col838": "7ku38", + "col839": "st0kd", + "col840": "4u9zf", + "col841": "2uzxo", + "col842": "7zimz", + "col843": "cr251", + "col844": "7wnpr", + "col845": "k4ioj", + "col846": "4tacz", + "col847": "ihdx3", + "col848": "ueosy", + "col849": "umz3y", + "col850": "6sq6t", + "col851": "705wx", + "col852": "hyvnb", + "col853": "4rog4", + "col854": "bvy1r", + "col855": "lrvso", + "col856": "4gqdm", + "col857": "r2f83", + "col858": "rsx4k", + "col859": "qgdxk", + "col860": "oqghp", + "col861": "60kvi", + "col862": "17zjc", + "col863": "0eusu", + "col864": "pj0w8", + "col865": "57jm1", + "col866": "l553c", + "col867": "cs93j", + "col868": "zbrv8", + "col869": "tauob", + "col870": "x2050", + "col871": "a83st", + "col872": "to1ow", + "col873": "roopr", + "col874": "5mo47", + "col875": "1kivz", + "col876": "uothp", + "col877": "8t1ln", + "col878": "zr66u", + "col879": "9kfj2", + "col880": "1pb0i", + "col881": "drn5t", + "col882": "2bzhp", + "col883": "4r8x9", + "col884": "a8901", + "col885": "4zhaj", + "col886": "s0psm", + "col887": "ja8pt", + "col888": "ttmgc", + "col889": "u8tvl", + "col890": "18l3r", + "col891": "l60ci", + "col892": "itpjm", + "col893": "lx1f4", + "col894": "iawhu", + "col895": "gbbo2", + "col896": "h0350", + "col897": "ui2yi", + "col898": "sp8t8", + "col899": "jlu0b", + "col900": "o07f2", + "col901": "cj200", + "col902": "5326x", + "col903": "jijv0", + "col904": "1a59f", + "col905": "t6pzd", + "col906": "l7x57", + "col907": "9u5iv", + "col908": "lqqeo", + "col909": "msw4h", + "col910": "d8lie", + "col911": "lsujw", + "col912": "07q5r", + "col913": "f76z2", + "col914": "qkds6", + "col915": "0z8w5", + "col916": "ifu39", + "col917": "7f4kg", + "col918": "ipcwb", + "col919": "y9stc", + "col920": "xpdg5", + "col921": "c1s8e", + "col922": "8u7iv", + "col923": "j6af6", + "col924": "9hkvh", + "col925": "j9due", + "col926": "2g8l5", + "col927": "fafu3", + "col928": "ow7y0", + "col929": "7v0kq", + "col930": "3bub3", + "col931": "ystnh", + "col932": "45igm", + "col933": "yvhdd", + "col934": "yzvhe", + "col935": "9t3u7", + "col936": "cn6u6", + "col937": "njm3a", + "col938": "x2fmb", + "col939": "si7ai", + "col940": "tckop", + "col941": "zeuez", + "col942": "0qmiv", + "col943": "dwh1u", + "col944": "396bn", + "col945": "5vgyn", + "col946": "kyy34", + "col947": "0o9ab", + "col948": "ngxe9", + "col949": "1mm9q", + "col950": "uk83v", + "col951": "a1sb9", + "col952": "vtsg8", + "col953": "yovvm", + "col954": "5iewl", + "col955": "ag378", + "col956": "p4l25", + "col957": "1xhxl", + "col958": "ubjug", + "col959": "y3zrj", + "col960": "rtz1p", + "col961": "m1yjs", + "col962": "snvbu", + "col963": "ym4k8", + "col964": "nfk2a", + "col965": "502fj", + "col966": "nw0ey", + "col967": "eif3x", + "col968": "9y00p", + "col969": "n6ezk", + "col970": "4q4ut", + "col971": "ztij4", + "col972": "sbosw", + "col973": "17sls", + "col974": "98knt", + "col975": "u0ugp", + "col976": "davqa", + "col977": "f8lib", + "col978": "mw08s", + "col979": "neswr", + "col980": "ntxfp", + "col981": "znj8a", + "col982": "qa1z9", + "col983": "swsvg", + "col984": "j8xwx", + "col985": "5jo49", + "col986": "326c3", + "col987": "vs0jv", + "col988": "quc8h", + "col989": "9iv8q", + "col990": "xdgzp", + "col991": "ujwjm", + "col992": "cc3qx", + "col993": "k385j", + "col994": "z388z", + "col995": "z57ry", + "col996": "u2nnu", + "col997": "7zn9k", + "col998": "l42up", + "col999": "o2on0" + }, + { + "name": "Galloway Nielsen", + "gender": "male", + "col0": "wr0uh", + "col1": "uex7c", + "col2": "xnhm0", + "col3": "ihojm", + "col4": "ce2uk", + "col5": "mj13k", + "col6": "fvkna", + "col7": "q38sa", + "col8": "0hapo", + "col9": "22pn0", + "col10": "9e26f", + "col11": "k9f56", + "col12": "0izsj", + "col13": "h972a", + "col14": "oim3s", + "col15": "bzpdj", + "col16": "osm8z", + "col17": "11440", + "col18": "217x6", + "col19": "l46h2", + "col20": "5mdf5", + "col21": "gml9e", + "col22": "0w4n9", + "col23": "q9k49", + "col24": "bvq7g", + "col25": "xr1if", + "col26": "pzjqm", + "col27": "5ftkn", + "col28": "u3rky", + "col29": "tcgos", + "col30": "43ow0", + "col31": "9w05l", + "col32": "62qmn", + "col33": "v9gki", + "col34": "iebvu", + "col35": "mf14c", + "col36": "btymi", + "col37": "j90dy", + "col38": "uwb58", + "col39": "wzmsq", + "col40": "6p6yo", + "col41": "tcpl2", + "col42": "rle7e", + "col43": "fd58n", + "col44": "o0bwx", + "col45": "9lzls", + "col46": "ohvow", + "col47": "qxqny", + "col48": "azo5i", + "col49": "wdrqu", + "col50": "xj9w1", + "col51": "uz9x4", + "col52": "plq2b", + "col53": "0te8e", + "col54": "rhupu", + "col55": "pq2ug", + "col56": "en1ma", + "col57": "wom97", + "col58": "9mgvb", + "col59": "8agy3", + "col60": "iycex", + "col61": "m4cy2", + "col62": "o9ut6", + "col63": "flvq4", + "col64": "y8hi3", + "col65": "pvsoe", + "col66": "3wswy", + "col67": "srfen", + "col68": "adf98", + "col69": "yhm41", + "col70": "g6j97", + "col71": "aadw4", + "col72": "4phhw", + "col73": "o43sx", + "col74": "nczm2", + "col75": "j51qs", + "col76": "qnn4m", + "col77": "5o2k7", + "col78": "3ztwv", + "col79": "if1ay", + "col80": "ylpr1", + "col81": "xb8ib", + "col82": "yciwq", + "col83": "we1s4", + "col84": "3ybaa", + "col85": "wf5uw", + "col86": "mlrva", + "col87": "cp044", + "col88": "71qtv", + "col89": "h7jxd", + "col90": "7slhb", + "col91": "o1kt9", + "col92": "lzgy4", + "col93": "fc1vd", + "col94": "iroqr", + "col95": "4g9m2", + "col96": "wb1yi", + "col97": "c07ax", + "col98": "9zctv", + "col99": "f5kh3", + "col100": "1kwjn", + "col101": "nzi9s", + "col102": "ip0xt", + "col103": "c92cf", + "col104": "t0r5n", + "col105": "bvzwr", + "col106": "8gjns", + "col107": "z9d22", + "col108": "ozpcy", + "col109": "nl45z", + "col110": "pt1bn", + "col111": "eq47i", + "col112": "tmxu3", + "col113": "bukml", + "col114": "v0l6b", + "col115": "lhvcz", + "col116": "roqe6", + "col117": "pxnt1", + "col118": "jnuiq", + "col119": "alok9", + "col120": "zrmfn", + "col121": "rfygx", + "col122": "67q6f", + "col123": "d0we1", + "col124": "klnyp", + "col125": "6xctf", + "col126": "s2ofv", + "col127": "nzlq1", + "col128": "gtgx2", + "col129": "kj8y9", + "col130": "7e2s6", + "col131": "tsvpn", + "col132": "kjzh0", + "col133": "9utot", + "col134": "kek6f", + "col135": "shhx5", + "col136": "b1omy", + "col137": "mp01e", + "col138": "2srdr", + "col139": "amtxx", + "col140": "m6z4r", + "col141": "zv7ng", + "col142": "dzz9z", + "col143": "focpc", + "col144": "g1hic", + "col145": "y29my", + "col146": "210t0", + "col147": "ehwg2", + "col148": "askvb", + "col149": "ehloa", + "col150": "j7yxi", + "col151": "65hta", + "col152": "a1l1h", + "col153": "z5kb0", + "col154": "nro1k", + "col155": "pou69", + "col156": "5rurx", + "col157": "hxrr4", + "col158": "8a23y", + "col159": "ak26n", + "col160": "hfjgf", + "col161": "pbq4f", + "col162": "40qms", + "col163": "a3o94", + "col164": "l26pq", + "col165": "h4eit", + "col166": "pocj4", + "col167": "kwl7g", + "col168": "up05w", + "col169": "6kpby", + "col170": "poyof", + "col171": "54og0", + "col172": "utjid", + "col173": "4bt5p", + "col174": "o8zn1", + "col175": "a5s6t", + "col176": "aoyll", + "col177": "ce02j", + "col178": "b6opk", + "col179": "1qdqi", + "col180": "2u7sx", + "col181": "cipnb", + "col182": "thk5i", + "col183": "pdys6", + "col184": "akxu2", + "col185": "0vkz3", + "col186": "bg73e", + "col187": "f6l5w", + "col188": "e26b6", + "col189": "aljuh", + "col190": "7gy02", + "col191": "bicp5", + "col192": "v4lv8", + "col193": "h31he", + "col194": "i8p3b", + "col195": "obc7d", + "col196": "vfcar", + "col197": "go2pm", + "col198": "pusk4", + "col199": "65c8o", + "col200": "g4z26", + "col201": "5k7sv", + "col202": "g6wbk", + "col203": "phfsc", + "col204": "ok32x", + "col205": "g4ng2", + "col206": "zzad5", + "col207": "5he11", + "col208": "3r4oe", + "col209": "m9lnn", + "col210": "0yhaw", + "col211": "j9gry", + "col212": "tbg1o", + "col213": "gm2z7", + "col214": "jgplq", + "col215": "rxqgi", + "col216": "x1uub", + "col217": "z197e", + "col218": "rxpu8", + "col219": "1e4in", + "col220": "c5tu0", + "col221": "vifjj", + "col222": "b2sph", + "col223": "m6x14", + "col224": "uz0my", + "col225": "xfxvi", + "col226": "g6nzv", + "col227": "d9zyr", + "col228": "6qr65", + "col229": "1do3u", + "col230": "cbu4u", + "col231": "4ir7t", + "col232": "jbx3y", + "col233": "ezada", + "col234": "xrya3", + "col235": "m85ph", + "col236": "f0jjh", + "col237": "3wduo", + "col238": "9zwbr", + "col239": "yf4pm", + "col240": "qdyzj", + "col241": "00uh0", + "col242": "hvt6m", + "col243": "ky6d2", + "col244": "10x2d", + "col245": "8l281", + "col246": "u8cu6", + "col247": "1e4cv", + "col248": "pcj79", + "col249": "51zga", + "col250": "ijqb6", + "col251": "6udsz", + "col252": "w7mvu", + "col253": "k2xx0", + "col254": "knhuv", + "col255": "jt9nm", + "col256": "ng565", + "col257": "rf5cc", + "col258": "urfcv", + "col259": "e05lz", + "col260": "rkm9o", + "col261": "kmweq", + "col262": "qc54s", + "col263": "ir4l7", + "col264": "zeq0l", + "col265": "h3327", + "col266": "2n5f0", + "col267": "9wimy", + "col268": "x2yqh", + "col269": "06uc7", + "col270": "b73w7", + "col271": "d74qw", + "col272": "dcef7", + "col273": "wgtip", + "col274": "bwytd", + "col275": "ovbk4", + "col276": "pqhkk", + "col277": "164lj", + "col278": "499h9", + "col279": "m56ri", + "col280": "x7kn4", + "col281": "fskr8", + "col282": "rw3qx", + "col283": "vx5n2", + "col284": "812ft", + "col285": "bsj1y", + "col286": "rl13j", + "col287": "n7fi4", + "col288": "f1zu4", + "col289": "tgy8j", + "col290": "ageoe", + "col291": "7e3vf", + "col292": "yio3x", + "col293": "8zjd2", + "col294": "x3kek", + "col295": "fkp11", + "col296": "iu1d6", + "col297": "5zbjg", + "col298": "a6osq", + "col299": "gwbcl", + "col300": "g7z4i", + "col301": "c8tqx", + "col302": "px21q", + "col303": "5lsmg", + "col304": "hds23", + "col305": "r7r6l", + "col306": "alb4g", + "col307": "22aoy", + "col308": "7dpgg", + "col309": "y0g47", + "col310": "c5cyg", + "col311": "4spdd", + "col312": "34pg9", + "col313": "5byj7", + "col314": "7vn3k", + "col315": "v2vkc", + "col316": "z9lz9", + "col317": "crq2w", + "col318": "v5j85", + "col319": "sqe1q", + "col320": "ydapl", + "col321": "lk9rk", + "col322": "lor44", + "col323": "06x3g", + "col324": "jp7uc", + "col325": "c0tlx", + "col326": "66k45", + "col327": "hliaa", + "col328": "s3obc", + "col329": "rcukm", + "col330": "joy42", + "col331": "aiucb", + "col332": "kbdc1", + "col333": "p2y8p", + "col334": "x1pg3", + "col335": "cit4a", + "col336": "8kh5v", + "col337": "ef5zz", + "col338": "xxiig", + "col339": "h343h", + "col340": "s6xzn", + "col341": "gisxj", + "col342": "dx33u", + "col343": "5q7wd", + "col344": "wzf6q", + "col345": "aokls", + "col346": "bexo3", + "col347": "qvwrq", + "col348": "n96ta", + "col349": "d8b5e", + "col350": "wxec9", + "col351": "tk0jh", + "col352": "i99hv", + "col353": "3a2xa", + "col354": "uxlx6", + "col355": "kfrno", + "col356": "dps84", + "col357": "shmse", + "col358": "se2ar", + "col359": "y4kz5", + "col360": "wwaly", + "col361": "lo27j", + "col362": "w3yve", + "col363": "nbq0r", + "col364": "bwk3l", + "col365": "p0sj6", + "col366": "92icf", + "col367": "wnypv", + "col368": "av5em", + "col369": "nfkij", + "col370": "jbnam", + "col371": "nq55j", + "col372": "pbid0", + "col373": "aw00i", + "col374": "q0rhu", + "col375": "9efzi", + "col376": "1nhhv", + "col377": "huzgo", + "col378": "iemin", + "col379": "f7gbp", + "col380": "5kz39", + "col381": "otbst", + "col382": "x81e4", + "col383": "xwv9d", + "col384": "wnh8p", + "col385": "3smho", + "col386": "vooei", + "col387": "k6aok", + "col388": "9tb0w", + "col389": "6rxal", + "col390": "vow2j", + "col391": "iegme", + "col392": "38foi", + "col393": "t83f3", + "col394": "mu2j3", + "col395": "t1c9l", + "col396": "2vhkg", + "col397": "h1vzf", + "col398": "e7uou", + "col399": "bxfhl", + "col400": "om08g", + "col401": "yy27x", + "col402": "egq3d", + "col403": "w80qs", + "col404": "9gww0", + "col405": "33w55", + "col406": "14n3p", + "col407": "q7v0n", + "col408": "xngam", + "col409": "x8ult", + "col410": "8e4u2", + "col411": "x3b1p", + "col412": "dv1t2", + "col413": "ui886", + "col414": "hoylr", + "col415": "mgeph", + "col416": "1srp6", + "col417": "ripd6", + "col418": "sztm7", + "col419": "he737", + "col420": "vwn59", + "col421": "155bu", + "col422": "fmgh6", + "col423": "ibxq8", + "col424": "92dr1", + "col425": "jzm8f", + "col426": "mdr4l", + "col427": "7ttei", + "col428": "fquvz", + "col429": "gk097", + "col430": "2cjc9", + "col431": "m1hn2", + "col432": "6ovac", + "col433": "3t6v8", + "col434": "p11fj", + "col435": "kwlw3", + "col436": "m4an3", + "col437": "33lnz", + "col438": "amzhe", + "col439": "23u1t", + "col440": "ybywq", + "col441": "umsib", + "col442": "23myz", + "col443": "rgeh3", + "col444": "e7b4k", + "col445": "wohn2", + "col446": "l9x9n", + "col447": "e3ron", + "col448": "zuwdk", + "col449": "g33oa", + "col450": "769di", + "col451": "l6dgw", + "col452": "v71kl", + "col453": "gzuar", + "col454": "r7twa", + "col455": "zkqwf", + "col456": "zzl21", + "col457": "41wvn", + "col458": "ddcyj", + "col459": "hrfa9", + "col460": "7d6c4", + "col461": "jdf0o", + "col462": "q0gyv", + "col463": "snkzi", + "col464": "1jtu9", + "col465": "85euc", + "col466": "al88g", + "col467": "mpks9", + "col468": "daism", + "col469": "2hgwu", + "col470": "szblb", + "col471": "twllm", + "col472": "kpm20", + "col473": "j39rx", + "col474": "4ymoc", + "col475": "4wsfq", + "col476": "oeuhk", + "col477": "zcssu", + "col478": "w2eyn", + "col479": "socl8", + "col480": "ypfie", + "col481": "cqrep", + "col482": "w8wn9", + "col483": "inaif", + "col484": "5a0el", + "col485": "qh74z", + "col486": "n3c12", + "col487": "oy9e0", + "col488": "sdxw4", + "col489": "0io7j", + "col490": "8sz2e", + "col491": "4r9s8", + "col492": "9iv7u", + "col493": "c5pof", + "col494": "669sd", + "col495": "q4l45", + "col496": "yuely", + "col497": "j0iut", + "col498": "a535u", + "col499": "7vnl3", + "col500": "ccf3d", + "col501": "zdy8f", + "col502": "6exwv", + "col503": "w2uhc", + "col504": "1zcbo", + "col505": "epduo", + "col506": "93bgl", + "col507": "1syji", + "col508": "q7fgn", + "col509": "5k5db", + "col510": "4t7eb", + "col511": "2qqw0", + "col512": "utooc", + "col513": "uec5d", + "col514": "eyuat", + "col515": "egwqh", + "col516": "bi0s1", + "col517": "md3vr", + "col518": "5qtw0", + "col519": "u16pf", + "col520": "0gkrs", + "col521": "wstaq", + "col522": "w8lf4", + "col523": "moz9o", + "col524": "yo5o0", + "col525": "rkmb0", + "col526": "r9mmy", + "col527": "vvlgj", + "col528": "9e2a9", + "col529": "ij670", + "col530": "rjlmv", + "col531": "re537", + "col532": "akhz6", + "col533": "wltw5", + "col534": "m9vjb", + "col535": "lgc5z", + "col536": "zy9t5", + "col537": "lmqse", + "col538": "lushn", + "col539": "6pu9i", + "col540": "001lm", + "col541": "tb238", + "col542": "un10m", + "col543": "ljru9", + "col544": "j73an", + "col545": "qxpmm", + "col546": "xu074", + "col547": "cxg27", + "col548": "knnyl", + "col549": "v4zft", + "col550": "zd8cg", + "col551": "v8qs9", + "col552": "f66xd", + "col553": "9qbsf", + "col554": "5ugl0", + "col555": "hd6ja", + "col556": "hj3jd", + "col557": "s45xb", + "col558": "0bf4g", + "col559": "gzeqk", + "col560": "aehn4", + "col561": "zqwrq", + "col562": "fzqs3", + "col563": "5abx8", + "col564": "gdm4j", + "col565": "d6znk", + "col566": "3z7v6", + "col567": "uu573", + "col568": "h4wkd", + "col569": "rcbmp", + "col570": "mpo6t", + "col571": "9keoy", + "col572": "5le0z", + "col573": "pk7tg", + "col574": "rw7xw", + "col575": "kd0ik", + "col576": "wjhf2", + "col577": "5z3eg", + "col578": "e3oha", + "col579": "mf5mi", + "col580": "xzpwh", + "col581": "4y5ow", + "col582": "z7ums", + "col583": "en59j", + "col584": "8hz7r", + "col585": "q6uup", + "col586": "bv0m8", + "col587": "1e5vc", + "col588": "7ogjn", + "col589": "28hz5", + "col590": "ysfpr", + "col591": "o45by", + "col592": "8amp2", + "col593": "0ba5t", + "col594": "zs0pr", + "col595": "lvggi", + "col596": "zgyzh", + "col597": "07nse", + "col598": "4tnph", + "col599": "snyo4", + "col600": "vg9wf", + "col601": "z2f26", + "col602": "v5z67", + "col603": "w8ysj", + "col604": "6znhd", + "col605": "05sm8", + "col606": "oh3lu", + "col607": "vcdfv", + "col608": "i1mmm", + "col609": "c83k2", + "col610": "a0heh", + "col611": "tsnx1", + "col612": "duqrh", + "col613": "swrbl", + "col614": "y7u2k", + "col615": "4s7d2", + "col616": "mvyub", + "col617": "veh8i", + "col618": "94flr", + "col619": "v2uls", + "col620": "zm1rt", + "col621": "d1gm2", + "col622": "yegiq", + "col623": "zx1q1", + "col624": "ce99q", + "col625": "jrigy", + "col626": "gvysk", + "col627": "n8e4s", + "col628": "7g31u", + "col629": "5dk8s", + "col630": "k3etl", + "col631": "4kytz", + "col632": "r7fs3", + "col633": "tsqed", + "col634": "7qoci", + "col635": "kvpz1", + "col636": "f64gv", + "col637": "06ks6", + "col638": "h7dcz", + "col639": "3gpzy", + "col640": "jajb5", + "col641": "gzsl1", + "col642": "ormvr", + "col643": "71x1q", + "col644": "bb9ji", + "col645": "2eaf0", + "col646": "bf5v9", + "col647": "v52sh", + "col648": "3gart", + "col649": "8b7m0", + "col650": "f7lwn", + "col651": "8k3sq", + "col652": "zfq41", + "col653": "jnk9l", + "col654": "o93rv", + "col655": "8josb", + "col656": "i2kls", + "col657": "3r1u1", + "col658": "glw69", + "col659": "tzxhk", + "col660": "riesi", + "col661": "jdwnf", + "col662": "m6bct", + "col663": "sk0xo", + "col664": "8r9gp", + "col665": "t9dp4", + "col666": "7vorh", + "col667": "6ro9j", + "col668": "q87qo", + "col669": "zwi5u", + "col670": "9jafm", + "col671": "5li91", + "col672": "8rcnz", + "col673": "11p8w", + "col674": "d79h5", + "col675": "badm8", + "col676": "pfpv4", + "col677": "wcj79", + "col678": "jp7qu", + "col679": "ih8vt", + "col680": "2sz0r", + "col681": "ms1qe", + "col682": "0t6k2", + "col683": "e992t", + "col684": "02mks", + "col685": "keeec", + "col686": "mh64b", + "col687": "qhr7m", + "col688": "xhlot", + "col689": "o7m91", + "col690": "s4jih", + "col691": "adwy8", + "col692": "29r2h", + "col693": "biqfm", + "col694": "6wh8v", + "col695": "5ugy9", + "col696": "kq77g", + "col697": "khqcz", + "col698": "6mxtk", + "col699": "hnfcj", + "col700": "etnwe", + "col701": "86hry", + "col702": "bb24x", + "col703": "5bd1r", + "col704": "uipl1", + "col705": "47qzk", + "col706": "0vpzu", + "col707": "khjjz", + "col708": "jmsoq", + "col709": "ektns", + "col710": "rsae9", + "col711": "ev0gc", + "col712": "cy0iy", + "col713": "dft9f", + "col714": "xdsui", + "col715": "787he", + "col716": "tal7f", + "col717": "l5yqf", + "col718": "j4cn1", + "col719": "23p98", + "col720": "9yle0", + "col721": "bwmdo", + "col722": "5davm", + "col723": "beae4", + "col724": "s75eg", + "col725": "9tjse", + "col726": "d2hqr", + "col727": "u41f1", + "col728": "nulg4", + "col729": "isuwa", + "col730": "ai0e9", + "col731": "20j0e", + "col732": "jw1wi", + "col733": "dmxr6", + "col734": "ssvp4", + "col735": "vpwti", + "col736": "6i1ed", + "col737": "2w81r", + "col738": "m5s48", + "col739": "u19yc", + "col740": "u4ox6", + "col741": "txn5m", + "col742": "i1ngd", + "col743": "3fool", + "col744": "9yrls", + "col745": "fk4hh", + "col746": "quwjh", + "col747": "qj14n", + "col748": "llcbb", + "col749": "i5n3f", + "col750": "a7fze", + "col751": "88dm1", + "col752": "qq7px", + "col753": "qkw4a", + "col754": "lkgpd", + "col755": "0zig9", + "col756": "3jcui", + "col757": "nnzm9", + "col758": "ecc21", + "col759": "1qinb", + "col760": "mxd12", + "col761": "qls7h", + "col762": "woagd", + "col763": "3vupx", + "col764": "vwmdr", + "col765": "dat46", + "col766": "lngf5", + "col767": "tfxvy", + "col768": "zcrd1", + "col769": "fwjl2", + "col770": "1l67j", + "col771": "35kwc", + "col772": "d85gt", + "col773": "t285o", + "col774": "hdo57", + "col775": "9j3nw", + "col776": "pme0c", + "col777": "22t04", + "col778": "d0tah", + "col779": "csdxe", + "col780": "nsqx9", + "col781": "dyk4o", + "col782": "22koz", + "col783": "2c6vp", + "col784": "9sptk", + "col785": "68lj4", + "col786": "9d6re", + "col787": "48hje", + "col788": "qg7jy", + "col789": "6hgwd", + "col790": "fwdzw", + "col791": "dphv1", + "col792": "840hd", + "col793": "5ds0m", + "col794": "54ofu", + "col795": "52yu2", + "col796": "ft7bv", + "col797": "wb66d", + "col798": "ydq5x", + "col799": "re04d", + "col800": "k3jis", + "col801": "owowa", + "col802": "855cx", + "col803": "75swt", + "col804": "43ftq", + "col805": "jq34o", + "col806": "k9bqw", + "col807": "9aoak", + "col808": "vvfn7", + "col809": "jj4co", + "col810": "p9afs", + "col811": "9wdl9", + "col812": "skrm1", + "col813": "5tl9w", + "col814": "uj0ft", + "col815": "ig7j9", + "col816": "m82h3", + "col817": "93jcx", + "col818": "qe24c", + "col819": "m7glx", + "col820": "krmby", + "col821": "lvn6o", + "col822": "soh17", + "col823": "j82yd", + "col824": "qt1gu", + "col825": "rje1f", + "col826": "3tzny", + "col827": "cw8ri", + "col828": "w2ihk", + "col829": "t2m6e", + "col830": "rgmsd", + "col831": "fqo47", + "col832": "r58lq", + "col833": "b9wkf", + "col834": "6xfl6", + "col835": "r44rv", + "col836": "p7v6g", + "col837": "luk69", + "col838": "7t9ir", + "col839": "1lkfg", + "col840": "aqwcb", + "col841": "9586b", + "col842": "zufrd", + "col843": "2cf9t", + "col844": "aq0hk", + "col845": "s61ve", + "col846": "8gu1m", + "col847": "qaby6", + "col848": "byzr9", + "col849": "qfw84", + "col850": "ah2g5", + "col851": "lbe2p", + "col852": "c9ln5", + "col853": "kaqcw", + "col854": "ibotz", + "col855": "du9zv", + "col856": "pwfwt", + "col857": "fi5d8", + "col858": "9klvs", + "col859": "l1ypj", + "col860": "20i3f", + "col861": "4edtl", + "col862": "rmghb", + "col863": "5f94t", + "col864": "4vuwo", + "col865": "xbeh7", + "col866": "3dq2t", + "col867": "pzic7", + "col868": "stm6l", + "col869": "ak0o7", + "col870": "i50t6", + "col871": "7ex8d", + "col872": "ctubi", + "col873": "oy2nd", + "col874": "262b1", + "col875": "0i1p7", + "col876": "qvi6h", + "col877": "4h7ic", + "col878": "wg7iy", + "col879": "tszzb", + "col880": "88n86", + "col881": "tl5de", + "col882": "1msdd", + "col883": "c3ijg", + "col884": "e6und", + "col885": "cnvng", + "col886": "10zh7", + "col887": "afbnk", + "col888": "ux2l3", + "col889": "ye96v", + "col890": "4zygk", + "col891": "b44u6", + "col892": "auosa", + "col893": "ihdfb", + "col894": "wyjy5", + "col895": "738qk", + "col896": "jomuj", + "col897": "xfurc", + "col898": "yulxr", + "col899": "oc316", + "col900": "6fj4u", + "col901": "3m9id", + "col902": "8snxr", + "col903": "uwnp5", + "col904": "d6sdw", + "col905": "0lgdi", + "col906": "4yzj4", + "col907": "xx64h", + "col908": "stvj8", + "col909": "bt0j9", + "col910": "osmwg", + "col911": "54qis", + "col912": "n1jn6", + "col913": "alab1", + "col914": "0wemg", + "col915": "l3y4v", + "col916": "af1w4", + "col917": "o2daq", + "col918": "0maop", + "col919": "7mgc5", + "col920": "694ta", + "col921": "uaaec", + "col922": "cfmwk", + "col923": "j9hze", + "col924": "j3nlc", + "col925": "kajrd", + "col926": "gy5ex", + "col927": "tyhnw", + "col928": "twyuf", + "col929": "z2rok", + "col930": "0fkt8", + "col931": "pf1rb", + "col932": "w49n3", + "col933": "3bwn6", + "col934": "jr3pr", + "col935": "wzi7y", + "col936": "nrfsz", + "col937": "53u0a", + "col938": "326tm", + "col939": "qmxi0", + "col940": "2c84u", + "col941": "t6zyo", + "col942": "vggta", + "col943": "e6b9u", + "col944": "7fwmj", + "col945": "pj2di", + "col946": "w9hlq", + "col947": "1umt7", + "col948": "gumo7", + "col949": "x3ede", + "col950": "mvq0j", + "col951": "wqcge", + "col952": "npi9y", + "col953": "ltej9", + "col954": "h4pzt", + "col955": "1gwbi", + "col956": "kgiuj", + "col957": "4cirg", + "col958": "p855x", + "col959": "h1prz", + "col960": "74pcs", + "col961": "x0kj6", + "col962": "ge0dc", + "col963": "5oel5", + "col964": "p9it2", + "col965": "dgxpj", + "col966": "5czix", + "col967": "g69pz", + "col968": "kp09f", + "col969": "opro0", + "col970": "s5cwe", + "col971": "ijiq9", + "col972": "uxymv", + "col973": "wwfyv", + "col974": "bil41", + "col975": "zm28b", + "col976": "f45s7", + "col977": "l2lkd", + "col978": "o7vj9", + "col979": "m23p7", + "col980": "zyf6y", + "col981": "u3m8f", + "col982": "jiljs", + "col983": "qov5l", + "col984": "l4m3i", + "col985": "uqlkn", + "col986": "k5oyq", + "col987": "bh3u9", + "col988": "bs70c", + "col989": "9fkuh", + "col990": "yuip1", + "col991": "53fej", + "col992": "dvbsu", + "col993": "bp6um", + "col994": "rcuyg", + "col995": "mn90i", + "col996": "5lk32", + "col997": "91d4u", + "col998": "04e8m", + "col999": "oud2a" + }, + { + "name": "Benson Nixon", + "gender": "male", + "col0": "3mbwx", + "col1": "fkhst", + "col2": "euzpp", + "col3": "jkqpi", + "col4": "82muh", + "col5": "teep0", + "col6": "w8i9k", + "col7": "2jcxj", + "col8": "zwxzn", + "col9": "uccu0", + "col10": "flppu", + "col11": "kyt2b", + "col12": "z8i7s", + "col13": "0dyo0", + "col14": "pcutv", + "col15": "8twgr", + "col16": "sv7o0", + "col17": "pydvo", + "col18": "iu7dx", + "col19": "zlz40", + "col20": "5h6un", + "col21": "0d94p", + "col22": "d6xvq", + "col23": "20wg0", + "col24": "sujkp", + "col25": "k6xei", + "col26": "b8u8v", + "col27": "i0h5s", + "col28": "fhra5", + "col29": "a2mhh", + "col30": "iukay", + "col31": "ig0fk", + "col32": "foo4f", + "col33": "gbhop", + "col34": "1zkqj", + "col35": "f8g6f", + "col36": "oulf0", + "col37": "2pwzf", + "col38": "atxds", + "col39": "ko7kb", + "col40": "smkmk", + "col41": "26evj", + "col42": "x6p67", + "col43": "i4ues", + "col44": "7xk32", + "col45": "7tvez", + "col46": "uxarl", + "col47": "f558j", + "col48": "7lxj1", + "col49": "1boev", + "col50": "gsy57", + "col51": "zcl4a", + "col52": "ezi5p", + "col53": "kkzqk", + "col54": "b4yul", + "col55": "anzpj", + "col56": "4qol3", + "col57": "husvx", + "col58": "qw29q", + "col59": "uud7c", + "col60": "pxuk9", + "col61": "it174", + "col62": "vxjf3", + "col63": "nqnxd", + "col64": "bunqu", + "col65": "f34u9", + "col66": "gkc1c", + "col67": "r5xbv", + "col68": "ssa3o", + "col69": "hcd4m", + "col70": "aw5k7", + "col71": "707iy", + "col72": "y60pz", + "col73": "iqm9c", + "col74": "xmpd2", + "col75": "eqx17", + "col76": "racq5", + "col77": "l9dsf", + "col78": "r2rnz", + "col79": "0jhsm", + "col80": "31fuq", + "col81": "qimjg", + "col82": "mo4eb", + "col83": "hj3sr", + "col84": "m2edd", + "col85": "zmzf6", + "col86": "6rqdo", + "col87": "5hw5v", + "col88": "9lu11", + "col89": "q391s", + "col90": "m6o7t", + "col91": "nknet", + "col92": "wqrcp", + "col93": "npknd", + "col94": "50xqd", + "col95": "v41vk", + "col96": "gc1j1", + "col97": "4d10h", + "col98": "22pci", + "col99": "gcy7k", + "col100": "a2nsw", + "col101": "j39cs", + "col102": "70jpj", + "col103": "65drd", + "col104": "2hnbi", + "col105": "zahdk", + "col106": "lzd4h", + "col107": "bt608", + "col108": "l5f80", + "col109": "spuzr", + "col110": "1nnk3", + "col111": "ghplm", + "col112": "ok8na", + "col113": "wtuml", + "col114": "3cm2u", + "col115": "isptg", + "col116": "yzs77", + "col117": "omlwy", + "col118": "2ky79", + "col119": "tr0wq", + "col120": "o7xik", + "col121": "7opc1", + "col122": "03w9k", + "col123": "n0kbf", + "col124": "bb35d", + "col125": "w1bmc", + "col126": "ex1pd", + "col127": "bjb6g", + "col128": "ygpv7", + "col129": "bv8wl", + "col130": "tkdpq", + "col131": "25ng1", + "col132": "9i9x3", + "col133": "8ccmk", + "col134": "vh9na", + "col135": "ivvz0", + "col136": "cxpq2", + "col137": "s2mlp", + "col138": "t1hqj", + "col139": "48lpf", + "col140": "cmu50", + "col141": "ntn5w", + "col142": "a5pi8", + "col143": "nzn3u", + "col144": "yenlo", + "col145": "7w6u8", + "col146": "r7z38", + "col147": "vax4l", + "col148": "ohvbe", + "col149": "pggtq", + "col150": "311x8", + "col151": "smvce", + "col152": "xxoth", + "col153": "8emn7", + "col154": "w849a", + "col155": "yimyy", + "col156": "u6zm8", + "col157": "00x2v", + "col158": "d22oi", + "col159": "6miv7", + "col160": "2cndd", + "col161": "k1ndy", + "col162": "7vntk", + "col163": "mmu4b", + "col164": "xuksq", + "col165": "pq5mc", + "col166": "s37uo", + "col167": "c8wl9", + "col168": "zvwbz", + "col169": "xixrc", + "col170": "2t20e", + "col171": "cow6l", + "col172": "o7ijp", + "col173": "vlaph", + "col174": "6g1dk", + "col175": "4l0dy", + "col176": "xfrqb", + "col177": "y0kn2", + "col178": "rpsj3", + "col179": "vgl8n", + "col180": "hwws0", + "col181": "vqwkh", + "col182": "3uvxz", + "col183": "b6fh0", + "col184": "hvrqe", + "col185": "ljsak", + "col186": "281oo", + "col187": "mx7lq", + "col188": "hkjut", + "col189": "1e9z2", + "col190": "50vf1", + "col191": "zsq0a", + "col192": "zg74a", + "col193": "6467a", + "col194": "xkmia", + "col195": "w96dy", + "col196": "nho99", + "col197": "0vsv2", + "col198": "u0eu3", + "col199": "8niya", + "col200": "9kguy", + "col201": "0t023", + "col202": "hbtze", + "col203": "962r9", + "col204": "6bg8w", + "col205": "m524s", + "col206": "om64o", + "col207": "2kcf9", + "col208": "0oxmx", + "col209": "x3xps", + "col210": "nz7v8", + "col211": "fwh5i", + "col212": "4ave6", + "col213": "yr5zn", + "col214": "wsfif", + "col215": "ijcrm", + "col216": "vgpyw", + "col217": "g4lnz", + "col218": "fbjh2", + "col219": "d6d0d", + "col220": "6h7p3", + "col221": "s7unf", + "col222": "i7b9w", + "col223": "4mtia", + "col224": "z32hq", + "col225": "p1jiq", + "col226": "q235g", + "col227": "ucbbx", + "col228": "0b004", + "col229": "4dpe1", + "col230": "ut6r3", + "col231": "qw6es", + "col232": "6r9kq", + "col233": "gnwd3", + "col234": "i7eeh", + "col235": "flk2a", + "col236": "ax9xc", + "col237": "smjzy", + "col238": "jj85o", + "col239": "mm5sk", + "col240": "ou5xi", + "col241": "uxinz", + "col242": "1csvc", + "col243": "9eywu", + "col244": "qc7x0", + "col245": "9qjaw", + "col246": "3uebc", + "col247": "58dq7", + "col248": "h84eg", + "col249": "8qlyv", + "col250": "1ak3b", + "col251": "v0cnl", + "col252": "58bm9", + "col253": "78e31", + "col254": "yrhz1", + "col255": "lqkv1", + "col256": "1djkt", + "col257": "7c8f8", + "col258": "djhsx", + "col259": "3dcuk", + "col260": "yumox", + "col261": "7k0mi", + "col262": "g2lo2", + "col263": "2ulcl", + "col264": "3s3zw", + "col265": "4cwms", + "col266": "0b7qp", + "col267": "2xdzk", + "col268": "d7d08", + "col269": "nhp3o", + "col270": "gikgw", + "col271": "2nx1u", + "col272": "57no7", + "col273": "aisbg", + "col274": "m5z1h", + "col275": "mw9do", + "col276": "wrxwf", + "col277": "gafr5", + "col278": "3uonb", + "col279": "h01lv", + "col280": "8lahu", + "col281": "spdrw", + "col282": "mnzzv", + "col283": "7bwdf", + "col284": "3qr6l", + "col285": "ynenv", + "col286": "xh8w5", + "col287": "frqsx", + "col288": "exj2o", + "col289": "fzaz0", + "col290": "i3wrw", + "col291": "hstn7", + "col292": "4qjrv", + "col293": "n81s1", + "col294": "jb00u", + "col295": "3vk46", + "col296": "o4f3k", + "col297": "ypmbf", + "col298": "bdog3", + "col299": "5only", + "col300": "5c616", + "col301": "of4zs", + "col302": "smhbl", + "col303": "93yja", + "col304": "ffrgi", + "col305": "jcqni", + "col306": "l0r7f", + "col307": "wwzy7", + "col308": "gv1kj", + "col309": "qic3g", + "col310": "9x7hi", + "col311": "l0n2k", + "col312": "11jjf", + "col313": "96pfd", + "col314": "401eu", + "col315": "brw5f", + "col316": "gpirx", + "col317": "x4k2h", + "col318": "qik04", + "col319": "3gdnx", + "col320": "q8ajp", + "col321": "o2mwl", + "col322": "wjaz1", + "col323": "w76ut", + "col324": "mf186", + "col325": "29i22", + "col326": "nd7d5", + "col327": "zjdcf", + "col328": "ise77", + "col329": "tvign", + "col330": "lpzag", + "col331": "1xsuc", + "col332": "4yeh8", + "col333": "l5zus", + "col334": "re1mm", + "col335": "pkzdx", + "col336": "tfuhw", + "col337": "dv6zb", + "col338": "u9f1k", + "col339": "7er26", + "col340": "8rwde", + "col341": "pl7fz", + "col342": "gmjje", + "col343": "twv9s", + "col344": "ba9l5", + "col345": "ycbue", + "col346": "vd1e2", + "col347": "7yout", + "col348": "nl88n", + "col349": "bsmne", + "col350": "2kwqv", + "col351": "xp6mg", + "col352": "k08ir", + "col353": "otaps", + "col354": "2428g", + "col355": "s5ft9", + "col356": "sxsjj", + "col357": "035y6", + "col358": "uyndt", + "col359": "y4nxz", + "col360": "1rhu4", + "col361": "aeg8x", + "col362": "nz3gj", + "col363": "hyui6", + "col364": "5cl8p", + "col365": "gqzil", + "col366": "273sp", + "col367": "iomv4", + "col368": "bdupo", + "col369": "8nc3h", + "col370": "h0lwg", + "col371": "vgg1e", + "col372": "bnd0r", + "col373": "m7kvn", + "col374": "xcrmk", + "col375": "bsj8l", + "col376": "jl6nq", + "col377": "olcor", + "col378": "gf797", + "col379": "dnwkk", + "col380": "7a82q", + "col381": "ejjif", + "col382": "txj3u", + "col383": "x01xo", + "col384": "68nc5", + "col385": "kusdg", + "col386": "gv8m8", + "col387": "4m5wx", + "col388": "ll20v", + "col389": "nx1fn", + "col390": "ojpg1", + "col391": "dddz3", + "col392": "xih9g", + "col393": "u7kb2", + "col394": "7utz5", + "col395": "exxmt", + "col396": "b2n0g", + "col397": "1qswg", + "col398": "skul4", + "col399": "56vfq", + "col400": "s5x52", + "col401": "v8v0n", + "col402": "yvnw3", + "col403": "cccdq", + "col404": "xqw2v", + "col405": "efr9a", + "col406": "n3k36", + "col407": "y1n7w", + "col408": "ye9o3", + "col409": "8dnt9", + "col410": "tg98o", + "col411": "1cnng", + "col412": "frcp2", + "col413": "65vd6", + "col414": "beapg", + "col415": "4yviu", + "col416": "2o38t", + "col417": "htltn", + "col418": "kzvxm", + "col419": "ht926", + "col420": "1z3kw", + "col421": "dbwr2", + "col422": "6xxyb", + "col423": "t50lg", + "col424": "8i4i1", + "col425": "51m3i", + "col426": "vluoa", + "col427": "wnzac", + "col428": "en1e3", + "col429": "ip0pz", + "col430": "s2vxm", + "col431": "m5mzl", + "col432": "yn4nv", + "col433": "tje30", + "col434": "843wl", + "col435": "ggduv", + "col436": "wtj31", + "col437": "mzxiq", + "col438": "fp18p", + "col439": "uta9p", + "col440": "o5txu", + "col441": "dyc0s", + "col442": "kpbvb", + "col443": "al5yd", + "col444": "4hseg", + "col445": "fxzk3", + "col446": "ar1bs", + "col447": "tuapy", + "col448": "5rorl", + "col449": "o7j6i", + "col450": "b85za", + "col451": "9dpjx", + "col452": "67jh0", + "col453": "jri4p", + "col454": "ijhif", + "col455": "8j371", + "col456": "0u93f", + "col457": "3x6uu", + "col458": "z07zi", + "col459": "rtii5", + "col460": "5so24", + "col461": "0l2jr", + "col462": "amp0d", + "col463": "ksy28", + "col464": "81jg8", + "col465": "skr8b", + "col466": "2sm87", + "col467": "e0d54", + "col468": "m6tpx", + "col469": "5203p", + "col470": "549l5", + "col471": "1szg9", + "col472": "cjv0a", + "col473": "jgh9o", + "col474": "gv11m", + "col475": "4blv8", + "col476": "7wlou", + "col477": "sohb3", + "col478": "ctg4n", + "col479": "p6fbd", + "col480": "2lqgq", + "col481": "gz5lk", + "col482": "1yq67", + "col483": "zvepz", + "col484": "fsjhl", + "col485": "ilfdf", + "col486": "5p4xc", + "col487": "oq3s6", + "col488": "4kgtu", + "col489": "w2au4", + "col490": "3e6uu", + "col491": "4i4bn", + "col492": "s144k", + "col493": "6ew29", + "col494": "pvkvl", + "col495": "dtayg", + "col496": "96k7k", + "col497": "p821w", + "col498": "z6s10", + "col499": "i9fpf", + "col500": "0lsi5", + "col501": "x0yuq", + "col502": "cqlsz", + "col503": "0w2xh", + "col504": "7m7so", + "col505": "9sw0q", + "col506": "sk31y", + "col507": "r0vbo", + "col508": "xjo8c", + "col509": "rnkh8", + "col510": "n40lp", + "col511": "witwr", + "col512": "cwwvw", + "col513": "gbvw5", + "col514": "8jy85", + "col515": "zudnh", + "col516": "82hlp", + "col517": "qi54g", + "col518": "k425u", + "col519": "v4psf", + "col520": "mrjt0", + "col521": "s77yo", + "col522": "x2d6o", + "col523": "n55qk", + "col524": "grex0", + "col525": "h081p", + "col526": "sw106", + "col527": "q7mh8", + "col528": "5hkiv", + "col529": "tem8c", + "col530": "5gf39", + "col531": "d7gvl", + "col532": "2duo8", + "col533": "pk13f", + "col534": "tlr86", + "col535": "eklbd", + "col536": "s5g39", + "col537": "6g5ke", + "col538": "1vz1q", + "col539": "qnaee", + "col540": "mrks8", + "col541": "djalh", + "col542": "dnknr", + "col543": "8b4u6", + "col544": "be7od", + "col545": "izbgf", + "col546": "kvcod", + "col547": "l04r7", + "col548": "xmh10", + "col549": "2xdac", + "col550": "zwq90", + "col551": "czb36", + "col552": "0awby", + "col553": "bba01", + "col554": "s490s", + "col555": "fa5yu", + "col556": "qcqw2", + "col557": "egs77", + "col558": "nxubs", + "col559": "m6ice", + "col560": "opncz", + "col561": "2p1qd", + "col562": "r3j3o", + "col563": "vundq", + "col564": "alawl", + "col565": "fwixb", + "col566": "pnxdf", + "col567": "fqj79", + "col568": "nd0ep", + "col569": "tcnkk", + "col570": "joyce", + "col571": "56wi2", + "col572": "3vjfl", + "col573": "sl1gm", + "col574": "92fdg", + "col575": "bxxyh", + "col576": "168if", + "col577": "h3zc4", + "col578": "q7fya", + "col579": "hcq8v", + "col580": "2ge1r", + "col581": "ul6by", + "col582": "ao5ho", + "col583": "51rio", + "col584": "ol5eo", + "col585": "ez17j", + "col586": "ubht1", + "col587": "cnh9j", + "col588": "sasb4", + "col589": "dknc0", + "col590": "irz69", + "col591": "80ka7", + "col592": "45zwe", + "col593": "qcifr", + "col594": "3xmev", + "col595": "3f1ll", + "col596": "8to95", + "col597": "ze6bx", + "col598": "vaunq", + "col599": "u5hd4", + "col600": "fpvps", + "col601": "bhero", + "col602": "uixmf", + "col603": "3bv5j", + "col604": "rpdyv", + "col605": "9ohfi", + "col606": "cpfaz", + "col607": "go3mc", + "col608": "jroq9", + "col609": "yrzip", + "col610": "e4wvu", + "col611": "29zit", + "col612": "u1d7s", + "col613": "fblwu", + "col614": "q82v5", + "col615": "tzhwi", + "col616": "4f6lv", + "col617": "uw33w", + "col618": "sy9ng", + "col619": "xa8i0", + "col620": "x8v4i", + "col621": "hgk6i", + "col622": "so1aj", + "col623": "y3t4e", + "col624": "qllgp", + "col625": "jyn47", + "col626": "yelm8", + "col627": "mp39r", + "col628": "fyz9h", + "col629": "g7tjj", + "col630": "670ap", + "col631": "2nhag", + "col632": "xi8ba", + "col633": "4qcwf", + "col634": "hnq2v", + "col635": "2fbbx", + "col636": "8ke3d", + "col637": "5tazw", + "col638": "ausou", + "col639": "cr8cz", + "col640": "ojbp1", + "col641": "w61yp", + "col642": "o1i1e", + "col643": "x0zvm", + "col644": "tb50p", + "col645": "7zywr", + "col646": "ceq1r", + "col647": "jbgt7", + "col648": "n97e3", + "col649": "no0ue", + "col650": "dyd0g", + "col651": "s3c79", + "col652": "9qjc0", + "col653": "1todz", + "col654": "mq160", + "col655": "9se49", + "col656": "7v8x3", + "col657": "wien2", + "col658": "d05xr", + "col659": "gjhml", + "col660": "b1emm", + "col661": "pcfhe", + "col662": "w2cnp", + "col663": "ya53f", + "col664": "2z3l5", + "col665": "vyaru", + "col666": "cabso", + "col667": "c2j3u", + "col668": "de424", + "col669": "gc2jb", + "col670": "gzj4h", + "col671": "t21xg", + "col672": "53xd1", + "col673": "q92cd", + "col674": "gmi3r", + "col675": "nftcy", + "col676": "zw2q6", + "col677": "izh3t", + "col678": "ngema", + "col679": "8nrvg", + "col680": "cnww3", + "col681": "70icm", + "col682": "rt7u7", + "col683": "1grt8", + "col684": "a44ic", + "col685": "ob4i4", + "col686": "0s82x", + "col687": "ifxs9", + "col688": "1h8pm", + "col689": "rdznj", + "col690": "kyn1m", + "col691": "2m7pg", + "col692": "4pcg0", + "col693": "do95q", + "col694": "s5ar0", + "col695": "iu8u0", + "col696": "eessu", + "col697": "ijuy9", + "col698": "57f8m", + "col699": "py850", + "col700": "li7hm", + "col701": "ofwnm", + "col702": "nl0ha", + "col703": "6g4cr", + "col704": "wgpgu", + "col705": "j9ay1", + "col706": "s5plj", + "col707": "p85g4", + "col708": "io0fe", + "col709": "9p11o", + "col710": "kt109", + "col711": "w0b60", + "col712": "kjthj", + "col713": "m8uag", + "col714": "wraqh", + "col715": "tt5cd", + "col716": "vokia", + "col717": "krnic", + "col718": "ji4vg", + "col719": "9806d", + "col720": "62fre", + "col721": "gze0z", + "col722": "1ysm0", + "col723": "6jb74", + "col724": "u1095", + "col725": "at9q8", + "col726": "q2946", + "col727": "omxm4", + "col728": "vqz1a", + "col729": "oxt1t", + "col730": "pz0q8", + "col731": "mh3mz", + "col732": "i0e2s", + "col733": "rvyvv", + "col734": "pvnq4", + "col735": "otl8l", + "col736": "v9bab", + "col737": "09lc7", + "col738": "zexv1", + "col739": "qw658", + "col740": "lgg6g", + "col741": "xv3rh", + "col742": "0vxob", + "col743": "xocef", + "col744": "ew7rc", + "col745": "wg6hd", + "col746": "k5tcz", + "col747": "06g44", + "col748": "aansw", + "col749": "4aww2", + "col750": "h9l5q", + "col751": "rvyxx", + "col752": "fmunw", + "col753": "sz7ii", + "col754": "1tf9y", + "col755": "d4k0j", + "col756": "9d074", + "col757": "aei2r", + "col758": "f6ru8", + "col759": "c15q6", + "col760": "lizzm", + "col761": "l1rwt", + "col762": "5fxcv", + "col763": "4emoq", + "col764": "k355x", + "col765": "cszcz", + "col766": "itn14", + "col767": "vd0vf", + "col768": "657ym", + "col769": "0z5k6", + "col770": "12gmw", + "col771": "jwy8k", + "col772": "s1s1t", + "col773": "nu8xw", + "col774": "1mfzg", + "col775": "ovfl8", + "col776": "3ka5d", + "col777": "d5gpr", + "col778": "8lmt9", + "col779": "o5q1o", + "col780": "c08f9", + "col781": "06ke6", + "col782": "6a8dd", + "col783": "lukeg", + "col784": "shvxy", + "col785": "pjkn2", + "col786": "6ymhj", + "col787": "dtot2", + "col788": "73ejk", + "col789": "mng5y", + "col790": "fs17h", + "col791": "5xius", + "col792": "qvzo5", + "col793": "xelfu", + "col794": "32izt", + "col795": "p5zfs", + "col796": "f4sqo", + "col797": "kdtgl", + "col798": "3ibc3", + "col799": "8luto", + "col800": "0fh8d", + "col801": "1c8ul", + "col802": "pf941", + "col803": "epiyd", + "col804": "dw2u8", + "col805": "9ujjp", + "col806": "gzzw8", + "col807": "8mh1n", + "col808": "jtwa2", + "col809": "6e5sn", + "col810": "m8gxq", + "col811": "pmdix", + "col812": "i620x", + "col813": "r2bvn", + "col814": "exb8r", + "col815": "460x3", + "col816": "zsy72", + "col817": "z44a3", + "col818": "kpn4u", + "col819": "zllii", + "col820": "iql30", + "col821": "ywcum", + "col822": "sn71d", + "col823": "3ckcd", + "col824": "q0yof", + "col825": "n4l9i", + "col826": "gq3pa", + "col827": "50woy", + "col828": "z1xfq", + "col829": "3wtpw", + "col830": "adjdw", + "col831": "xcn0z", + "col832": "a88zf", + "col833": "xwgm2", + "col834": "dvsdj", + "col835": "8mu9i", + "col836": "nshhi", + "col837": "xu85v", + "col838": "lztd0", + "col839": "yo16b", + "col840": "kpu4l", + "col841": "htbyx", + "col842": "9fayd", + "col843": "ql6be", + "col844": "8945v", + "col845": "mm2mq", + "col846": "4zrup", + "col847": "723u9", + "col848": "qnboi", + "col849": "o7gyj", + "col850": "0cmn2", + "col851": "v8yf3", + "col852": "srk14", + "col853": "178bs", + "col854": "babqg", + "col855": "9jkxp", + "col856": "2sejz", + "col857": "yrdvb", + "col858": "m8g5w", + "col859": "dggjt", + "col860": "kmpfl", + "col861": "42aas", + "col862": "ko981", + "col863": "fu09i", + "col864": "3niyw", + "col865": "dct26", + "col866": "4isug", + "col867": "ell9f", + "col868": "gj5i4", + "col869": "ftpn2", + "col870": "oelie", + "col871": "a0sfy", + "col872": "ntyt0", + "col873": "sji48", + "col874": "csdvw", + "col875": "313md", + "col876": "y9uwb", + "col877": "0v29o", + "col878": "424wm", + "col879": "jemeg", + "col880": "oiosv", + "col881": "tadqk", + "col882": "7narh", + "col883": "le8i0", + "col884": "papjl", + "col885": "up2ch", + "col886": "hu5vz", + "col887": "6t3y4", + "col888": "log9d", + "col889": "khvkv", + "col890": "dk84q", + "col891": "fx9lf", + "col892": "wv5px", + "col893": "9jho5", + "col894": "9o93a", + "col895": "hrvfp", + "col896": "3mvmo", + "col897": "u3tlg", + "col898": "aeqrm", + "col899": "dcixt", + "col900": "oxmmk", + "col901": "xhhfb", + "col902": "0f4bd", + "col903": "fzsyr", + "col904": "747z3", + "col905": "nqt92", + "col906": "5pg28", + "col907": "1qtvf", + "col908": "w3pbo", + "col909": "15yw4", + "col910": "rudmd", + "col911": "2n2px", + "col912": "b9enc", + "col913": "dpbm0", + "col914": "jglno", + "col915": "afdz8", + "col916": "47hxt", + "col917": "bapvv", + "col918": "567vo", + "col919": "q53om", + "col920": "2ixcl", + "col921": "jclf5", + "col922": "t7171", + "col923": "hrmv7", + "col924": "k2wca", + "col925": "zxeh9", + "col926": "mhusg", + "col927": "w6gxb", + "col928": "aqg0f", + "col929": "0amjk", + "col930": "j6ews", + "col931": "vbze3", + "col932": "qso3x", + "col933": "f6ho5", + "col934": "u42hl", + "col935": "xlves", + "col936": "fsf4u", + "col937": "yranz", + "col938": "1mu67", + "col939": "7nex3", + "col940": "4f539", + "col941": "ujug6", + "col942": "041t4", + "col943": "7ku8y", + "col944": "ijug7", + "col945": "uwl1v", + "col946": "br9ss", + "col947": "3juqe", + "col948": "25oo5", + "col949": "ou79b", + "col950": "tdlwv", + "col951": "du5en", + "col952": "4rawf", + "col953": "iges4", + "col954": "hg9ll", + "col955": "pi7qt", + "col956": "pe9un", + "col957": "cnpvf", + "col958": "jayb3", + "col959": "jd5nh", + "col960": "vy1i3", + "col961": "4eipx", + "col962": "vq13i", + "col963": "5hn8k", + "col964": "1lqme", + "col965": "dds5k", + "col966": "mrx72", + "col967": "n28nq", + "col968": "hqfrx", + "col969": "4nmfb", + "col970": "8m29d", + "col971": "0nkr2", + "col972": "a9swy", + "col973": "ccect", + "col974": "52pbn", + "col975": "8qyv4", + "col976": "b4npk", + "col977": "sel7u", + "col978": "rcy6i", + "col979": "2zdnu", + "col980": "y2ur1", + "col981": "bio81", + "col982": "hi92x", + "col983": "tdk7v", + "col984": "f65tl", + "col985": "z6a5v", + "col986": "e0ac7", + "col987": "6zp2b", + "col988": "cn2ls", + "col989": "tijuw", + "col990": "ptbgk", + "col991": "qbjc0", + "col992": "9kr1k", + "col993": "9scb5", + "col994": "2k798", + "col995": "6ow71", + "col996": "oc8tn", + "col997": "3i6fl", + "col998": "3x2rq", + "col999": "birqo" + }, + { + "name": "Adrian Rich", + "gender": "female", + "col0": "jwp5g", + "col1": "g03g5", + "col2": "jzf94", + "col3": "bv3cx", + "col4": "trv6m", + "col5": "qffdz", + "col6": "lik4a", + "col7": "p93ec", + "col8": "764ub", + "col9": "pgx7y", + "col10": "nyvw0", + "col11": "m9ir7", + "col12": "pw964", + "col13": "ph60m", + "col14": "kp798", + "col15": "s30wc", + "col16": "kz7vz", + "col17": "fxuug", + "col18": "r4dcq", + "col19": "p4keo", + "col20": "z1vb6", + "col21": "pfx5h", + "col22": "vcmqt", + "col23": "cc006", + "col24": "13qzq", + "col25": "6l49l", + "col26": "jre1o", + "col27": "eht3y", + "col28": "y69br", + "col29": "ap1qq", + "col30": "35qw0", + "col31": "wgpgp", + "col32": "uvxy6", + "col33": "uz8jb", + "col34": "s8q58", + "col35": "g99dm", + "col36": "n8flz", + "col37": "4reqr", + "col38": "wr5wr", + "col39": "0phxt", + "col40": "8ma2g", + "col41": "9hvh9", + "col42": "wx2z4", + "col43": "wut3y", + "col44": "jhmdx", + "col45": "dngff", + "col46": "46f7s", + "col47": "5572f", + "col48": "vaipl", + "col49": "545zw", + "col50": "0thdy", + "col51": "2hcjj", + "col52": "bbain", + "col53": "aak0m", + "col54": "go7j6", + "col55": "s9j0g", + "col56": "f9iwm", + "col57": "5qizj", + "col58": "vize0", + "col59": "2cb7j", + "col60": "driz0", + "col61": "p6xgz", + "col62": "6tu96", + "col63": "hk1vp", + "col64": "nxget", + "col65": "4ssq5", + "col66": "fl1c4", + "col67": "bmclg", + "col68": "8zv8h", + "col69": "1fi8o", + "col70": "khxba", + "col71": "zirmq", + "col72": "frj6q", + "col73": "0jesa", + "col74": "ft6dp", + "col75": "q0xff", + "col76": "rgyda", + "col77": "iy2bu", + "col78": "kwkvs", + "col79": "0cioz", + "col80": "ojaxi", + "col81": "w32o2", + "col82": "pdewc", + "col83": "xb403", + "col84": "5wn7a", + "col85": "jlw55", + "col86": "aw5bm", + "col87": "k6lpp", + "col88": "unlmb", + "col89": "8oi6q", + "col90": "v2zet", + "col91": "fbigf", + "col92": "4sqk2", + "col93": "fowx3", + "col94": "j2ucb", + "col95": "r7ft5", + "col96": "2uvi5", + "col97": "vvrn7", + "col98": "7i91x", + "col99": "dhv5m", + "col100": "vs6h3", + "col101": "h40bu", + "col102": "ith7t", + "col103": "o9cuv", + "col104": "cd8st", + "col105": "8lfhh", + "col106": "qjmeb", + "col107": "ekpp2", + "col108": "xyhhq", + "col109": "mjeid", + "col110": "wlsfp", + "col111": "nyxmd", + "col112": "qrgjr", + "col113": "fc8eg", + "col114": "p0y5l", + "col115": "ftja6", + "col116": "0wnps", + "col117": "41f8z", + "col118": "n30kw", + "col119": "fi9nl", + "col120": "kgrpx", + "col121": "cbfto", + "col122": "mkwel", + "col123": "pwjya", + "col124": "15cal", + "col125": "nw3pz", + "col126": "j89tw", + "col127": "huiud", + "col128": "vw6x5", + "col129": "7ch88", + "col130": "lyeuc", + "col131": "g6721", + "col132": "crx1i", + "col133": "x9h1n", + "col134": "hcc9u", + "col135": "m6gdb", + "col136": "nqnqr", + "col137": "6mhsm", + "col138": "omtwg", + "col139": "fiohz", + "col140": "uqvlm", + "col141": "v1oam", + "col142": "uft4o", + "col143": "4br3t", + "col144": "2feql", + "col145": "qkc8k", + "col146": "gpy61", + "col147": "3kh87", + "col148": "t7vu4", + "col149": "fhta8", + "col150": "juwq6", + "col151": "jlvx3", + "col152": "i5t3i", + "col153": "7wzwg", + "col154": "28g4n", + "col155": "8w79c", + "col156": "3t3dp", + "col157": "t0sxc", + "col158": "h2860", + "col159": "m6q1b", + "col160": "mp48n", + "col161": "bp3n0", + "col162": "fmo5l", + "col163": "v7ugv", + "col164": "dfcgx", + "col165": "ilb1v", + "col166": "eaw34", + "col167": "54yaq", + "col168": "lnvi4", + "col169": "yi676", + "col170": "cds0e", + "col171": "ugsz1", + "col172": "9jvq9", + "col173": "h7mb8", + "col174": "5zdv2", + "col175": "3ugk5", + "col176": "qrr51", + "col177": "3qvad", + "col178": "fqz3l", + "col179": "q89k5", + "col180": "ozpqw", + "col181": "3i27z", + "col182": "4yu2o", + "col183": "0gvbs", + "col184": "6evze", + "col185": "etbmx", + "col186": "9dz7h", + "col187": "9misi", + "col188": "gumez", + "col189": "qv3fu", + "col190": "0txfp", + "col191": "neuv0", + "col192": "p7i99", + "col193": "clzbp", + "col194": "7gsbf", + "col195": "19egx", + "col196": "gxy1g", + "col197": "bbxfo", + "col198": "oy1ie", + "col199": "k6nzj", + "col200": "g52oo", + "col201": "jih2n", + "col202": "dmlda", + "col203": "on39u", + "col204": "3ymn6", + "col205": "px2bg", + "col206": "se1ty", + "col207": "uwf90", + "col208": "8phxt", + "col209": "qix3h", + "col210": "xbr1x", + "col211": "dgwpm", + "col212": "p6azt", + "col213": "4iu2m", + "col214": "4h7zk", + "col215": "2rk6h", + "col216": "v7x7y", + "col217": "gi0zd", + "col218": "997h1", + "col219": "i2ou3", + "col220": "i4y6o", + "col221": "5cz7s", + "col222": "mhqi7", + "col223": "ehjiz", + "col224": "ncni5", + "col225": "ksrnt", + "col226": "qqoqf", + "col227": "gh74h", + "col228": "2i0kq", + "col229": "zgxs3", + "col230": "xbjpk", + "col231": "b1h7l", + "col232": "glw46", + "col233": "dlepp", + "col234": "53kio", + "col235": "vau7z", + "col236": "0rf7l", + "col237": "7cvg2", + "col238": "0jeoo", + "col239": "qvr0v", + "col240": "10moz", + "col241": "h3896", + "col242": "jse2c", + "col243": "ud36j", + "col244": "rimox", + "col245": "edjxo", + "col246": "y354z", + "col247": "fde81", + "col248": "s8ddn", + "col249": "g8uk4", + "col250": "cijo7", + "col251": "yyly6", + "col252": "j7aln", + "col253": "ukx29", + "col254": "op9qf", + "col255": "wtwh1", + "col256": "f2gg2", + "col257": "2mgfi", + "col258": "2yt98", + "col259": "1i4v2", + "col260": "3e30o", + "col261": "a9j66", + "col262": "j37l2", + "col263": "cycui", + "col264": "4e15l", + "col265": "1iwiw", + "col266": "f6gwi", + "col267": "pkr5s", + "col268": "b2pk9", + "col269": "raleu", + "col270": "k543l", + "col271": "puvkg", + "col272": "r6x5a", + "col273": "8bd7m", + "col274": "ckco1", + "col275": "f738r", + "col276": "govyk", + "col277": "8ehwh", + "col278": "o4uk7", + "col279": "euanp", + "col280": "31i5h", + "col281": "jljnw", + "col282": "runru", + "col283": "f7p4b", + "col284": "i5oyd", + "col285": "kz3qt", + "col286": "rgh6j", + "col287": "ilifp", + "col288": "8y7m8", + "col289": "gon13", + "col290": "k660j", + "col291": "wglv2", + "col292": "bekq4", + "col293": "gcrxu", + "col294": "zcry5", + "col295": "js7sv", + "col296": "x1ihm", + "col297": "g5qm9", + "col298": "9ea5m", + "col299": "0n193", + "col300": "zvbk3", + "col301": "693lu", + "col302": "umspf", + "col303": "u9szg", + "col304": "a93b3", + "col305": "97hk6", + "col306": "jlqrs", + "col307": "jfpx7", + "col308": "7fmhy", + "col309": "9iz2y", + "col310": "3n46s", + "col311": "rpmz1", + "col312": "tqvcl", + "col313": "hwnwh", + "col314": "0dsrt", + "col315": "26n7g", + "col316": "td6pj", + "col317": "uap2f", + "col318": "tldic", + "col319": "56fgh", + "col320": "xnoru", + "col321": "jr5xj", + "col322": "9la20", + "col323": "thenb", + "col324": "laecp", + "col325": "ul74t", + "col326": "ifjdx", + "col327": "1kz5r", + "col328": "qjho0", + "col329": "lvsxj", + "col330": "xkmaq", + "col331": "lldqi", + "col332": "1opck", + "col333": "t35mz", + "col334": "ryz54", + "col335": "51rwh", + "col336": "vx6af", + "col337": "464hj", + "col338": "g7yst", + "col339": "r4pr6", + "col340": "se44b", + "col341": "4eo06", + "col342": "szw78", + "col343": "sijrp", + "col344": "qdr35", + "col345": "8idks", + "col346": "46iaj", + "col347": "fe28z", + "col348": "3olqv", + "col349": "f9l45", + "col350": "lguuo", + "col351": "6z5lv", + "col352": "5qqs6", + "col353": "e2b4b", + "col354": "17l1v", + "col355": "fe7c4", + "col356": "tlbh9", + "col357": "wvf2e", + "col358": "88k5v", + "col359": "2u8jp", + "col360": "te0np", + "col361": "f1hbv", + "col362": "8ss0i", + "col363": "1dh9f", + "col364": "x2m9n", + "col365": "x4tjq", + "col366": "e6w3m", + "col367": "b02tx", + "col368": "8kafm", + "col369": "41zfj", + "col370": "aqrcw", + "col371": "j3dwb", + "col372": "qep2p", + "col373": "opk23", + "col374": "791md", + "col375": "iyt8b", + "col376": "y6t1g", + "col377": "k1vmz", + "col378": "j657f", + "col379": "a78h2", + "col380": "b4c57", + "col381": "un3fd", + "col382": "zom48", + "col383": "jb1p7", + "col384": "cdcng", + "col385": "iw33k", + "col386": "zzgia", + "col387": "b6boz", + "col388": "03ttx", + "col389": "etgwe", + "col390": "5w3j0", + "col391": "d046c", + "col392": "hil6x", + "col393": "stsjy", + "col394": "o0vjq", + "col395": "bfqco", + "col396": "rprod", + "col397": "p5wjb", + "col398": "abr9s", + "col399": "kty30", + "col400": "kwalp", + "col401": "6usjm", + "col402": "z6n23", + "col403": "bhwsr", + "col404": "lh9ae", + "col405": "lnut0", + "col406": "1f296", + "col407": "qq6mv", + "col408": "r6tg7", + "col409": "muazt", + "col410": "4x41l", + "col411": "6mdei", + "col412": "p9uoi", + "col413": "4df7t", + "col414": "2qg1l", + "col415": "vnz68", + "col416": "xkv78", + "col417": "at8zf", + "col418": "1ygta", + "col419": "j6yqn", + "col420": "4rx8s", + "col421": "h5jq4", + "col422": "zpqij", + "col423": "box5w", + "col424": "odhkm", + "col425": "nmp4m", + "col426": "0nb8a", + "col427": "7w7b4", + "col428": "pc32v", + "col429": "h3ggw", + "col430": "y05gv", + "col431": "ftjwu", + "col432": "2jibu", + "col433": "3n16d", + "col434": "5ossp", + "col435": "6gm4e", + "col436": "i0nxq", + "col437": "6jbgj", + "col438": "yi37f", + "col439": "0mwzc", + "col440": "xp9a3", + "col441": "3jfvh", + "col442": "vx43y", + "col443": "jo8a8", + "col444": "726z3", + "col445": "0j4z9", + "col446": "odv9v", + "col447": "ruum9", + "col448": "1ebrf", + "col449": "kftt9", + "col450": "s2eha", + "col451": "v89on", + "col452": "96c4g", + "col453": "rnwp4", + "col454": "yk6jb", + "col455": "yx1e2", + "col456": "wrpb7", + "col457": "h88s3", + "col458": "ulspr", + "col459": "cv570", + "col460": "uu8ly", + "col461": "xswni", + "col462": "kdoek", + "col463": "pi92a", + "col464": "sq02k", + "col465": "8nwmu", + "col466": "sblat", + "col467": "2wsqk", + "col468": "lau7y", + "col469": "khamz", + "col470": "pf76c", + "col471": "kww5m", + "col472": "qa858", + "col473": "24dyt", + "col474": "e6jf8", + "col475": "yaq0v", + "col476": "2pzfl", + "col477": "f3ukx", + "col478": "xt23w", + "col479": "3clqp", + "col480": "e1ukh", + "col481": "bn38p", + "col482": "xdlna", + "col483": "tenii", + "col484": "fqs9b", + "col485": "3d6sz", + "col486": "9lio6", + "col487": "es387", + "col488": "fv661", + "col489": "y5omb", + "col490": "n1hek", + "col491": "jjwfz", + "col492": "krv1z", + "col493": "8hv3x", + "col494": "g7yu1", + "col495": "cet58", + "col496": "hd4mg", + "col497": "odouw", + "col498": "e7mam", + "col499": "cfbel", + "col500": "87vrf", + "col501": "qrh02", + "col502": "xj69t", + "col503": "hqg66", + "col504": "xjd9a", + "col505": "k51lj", + "col506": "xhi9z", + "col507": "j5pgg", + "col508": "gn9pz", + "col509": "qysmu", + "col510": "vs0zx", + "col511": "a224i", + "col512": "l5zhn", + "col513": "la7i1", + "col514": "ozjrw", + "col515": "nxofq", + "col516": "1ra7y", + "col517": "g1sll", + "col518": "5riyw", + "col519": "jl9rm", + "col520": "13mpv", + "col521": "pei6j", + "col522": "38yoa", + "col523": "t8zb4", + "col524": "ll90w", + "col525": "4q8c0", + "col526": "61c6g", + "col527": "c21n1", + "col528": "q4f0c", + "col529": "d4lik", + "col530": "dmn3k", + "col531": "9g041", + "col532": "97lfo", + "col533": "8gzej", + "col534": "3cb4o", + "col535": "du6e3", + "col536": "uzkdo", + "col537": "5qdiu", + "col538": "cjxia", + "col539": "zlywf", + "col540": "m5rbc", + "col541": "tzixz", + "col542": "nd4r5", + "col543": "1h4oy", + "col544": "ynal0", + "col545": "8me2b", + "col546": "klnr5", + "col547": "y65wg", + "col548": "ksm2k", + "col549": "vhsps", + "col550": "xuhhv", + "col551": "t2ew6", + "col552": "5gua6", + "col553": "cx5t0", + "col554": "7tnj2", + "col555": "re4nh", + "col556": "aygey", + "col557": "3qn0i", + "col558": "8xd5e", + "col559": "myjx3", + "col560": "0fn4o", + "col561": "6440h", + "col562": "ga6dv", + "col563": "puo3d", + "col564": "htbun", + "col565": "uxkib", + "col566": "11ezm", + "col567": "ipepf", + "col568": "35k9d", + "col569": "3t6ms", + "col570": "5lw8u", + "col571": "h0fp5", + "col572": "28dlx", + "col573": "d5yun", + "col574": "c6sjc", + "col575": "47en4", + "col576": "03ye0", + "col577": "nop2t", + "col578": "os38m", + "col579": "0bx9n", + "col580": "1kv99", + "col581": "rdqes", + "col582": "thdob", + "col583": "ipy1u", + "col584": "a0wgj", + "col585": "5gbre", + "col586": "tm4q9", + "col587": "w8b2y", + "col588": "06m19", + "col589": "yibmk", + "col590": "r8qhe", + "col591": "qnwmp", + "col592": "9h25g", + "col593": "7ckcz", + "col594": "8y6rw", + "col595": "8j203", + "col596": "o4l4q", + "col597": "7fz2x", + "col598": "9vd6k", + "col599": "zrk8q", + "col600": "fk5i8", + "col601": "837nn", + "col602": "itpiy", + "col603": "naho1", + "col604": "aeuyj", + "col605": "eq9mq", + "col606": "a6zjf", + "col607": "auhil", + "col608": "ktu91", + "col609": "gw51o", + "col610": "98vuz", + "col611": "z2l34", + "col612": "twd9s", + "col613": "kv3nu", + "col614": "wjfh6", + "col615": "wy23s", + "col616": "h34e6", + "col617": "jiu0e", + "col618": "ekkjz", + "col619": "v86to", + "col620": "itsxl", + "col621": "svhmr", + "col622": "2ooqv", + "col623": "k1usj", + "col624": "2uwyc", + "col625": "ywoy7", + "col626": "7bsn7", + "col627": "aj8uq", + "col628": "j6psi", + "col629": "28rr3", + "col630": "3jlvy", + "col631": "x39v2", + "col632": "zypnw", + "col633": "h5nlx", + "col634": "u4knp", + "col635": "9nbhc", + "col636": "zo3cx", + "col637": "peygg", + "col638": "za5ze", + "col639": "99h32", + "col640": "hbvay", + "col641": "gjo7j", + "col642": "pkdho", + "col643": "j68wk", + "col644": "k1fxq", + "col645": "sl6w5", + "col646": "0xic0", + "col647": "77w1t", + "col648": "m2rlo", + "col649": "sf7xl", + "col650": "ck6rz", + "col651": "pwz29", + "col652": "lm70w", + "col653": "p4uwc", + "col654": "k094s", + "col655": "gjcdh", + "col656": "r9xmf", + "col657": "9eigf", + "col658": "dojkg", + "col659": "nh28s", + "col660": "dk1g4", + "col661": "1sjhn", + "col662": "mmeff", + "col663": "3vcg1", + "col664": "01qv6", + "col665": "xt4ob", + "col666": "o8wrb", + "col667": "526q0", + "col668": "qjgqe", + "col669": "ww2j9", + "col670": "r6f2v", + "col671": "m8pqp", + "col672": "8qkye", + "col673": "l4hsu", + "col674": "5nq02", + "col675": "mpve0", + "col676": "v115v", + "col677": "ig6c9", + "col678": "cbpw4", + "col679": "dixlx", + "col680": "9742h", + "col681": "x96s0", + "col682": "zqqcc", + "col683": "ll9vr", + "col684": "qm4ef", + "col685": "kfljr", + "col686": "z6z2m", + "col687": "z9ka1", + "col688": "halkq", + "col689": "gu71t", + "col690": "43ju7", + "col691": "850gc", + "col692": "o1cl3", + "col693": "h5pxr", + "col694": "avktv", + "col695": "vgred", + "col696": "lipnm", + "col697": "8zwbn", + "col698": "z65jw", + "col699": "84vho", + "col700": "qwssu", + "col701": "61alh", + "col702": "i8p8o", + "col703": "w530w", + "col704": "tf7ir", + "col705": "lv987", + "col706": "nr5o9", + "col707": "ukmcw", + "col708": "ygmqt", + "col709": "806w4", + "col710": "xtpvb", + "col711": "r1pnu", + "col712": "tm32h", + "col713": "d5ll3", + "col714": "93xia", + "col715": "ei4tc", + "col716": "rq9um", + "col717": "whnle", + "col718": "synd8", + "col719": "5xnif", + "col720": "2v5z6", + "col721": "rhxke", + "col722": "keqg2", + "col723": "87rws", + "col724": "3waa5", + "col725": "xaicx", + "col726": "4crbo", + "col727": "novg4", + "col728": "0rumb", + "col729": "f2yfn", + "col730": "xn8ah", + "col731": "k7510", + "col732": "ux8ym", + "col733": "gy74d", + "col734": "gzuol", + "col735": "jv9ds", + "col736": "i6z1l", + "col737": "asn4w", + "col738": "74f6o", + "col739": "baj3u", + "col740": "nn9jz", + "col741": "cn02i", + "col742": "z0xmk", + "col743": "fogx0", + "col744": "k61da", + "col745": "2xq33", + "col746": "zccps", + "col747": "q9pbs", + "col748": "c812k", + "col749": "34wod", + "col750": "wefxs", + "col751": "hn8oa", + "col752": "m3rrj", + "col753": "o6y23", + "col754": "55top", + "col755": "o1f8j", + "col756": "hyw2v", + "col757": "1zniy", + "col758": "8xry2", + "col759": "rasgj", + "col760": "10mkh", + "col761": "r8t1k", + "col762": "6f4xp", + "col763": "74n6j", + "col764": "7gvyn", + "col765": "ixssu", + "col766": "ff9nq", + "col767": "qj4up", + "col768": "f0z10", + "col769": "z0unj", + "col770": "zncou", + "col771": "il7ku", + "col772": "jq5ei", + "col773": "iew61", + "col774": "9qt09", + "col775": "j3tfm", + "col776": "sg5pe", + "col777": "73sfd", + "col778": "6gnc3", + "col779": "a0mrt", + "col780": "0hn9j", + "col781": "dbtxv", + "col782": "scag5", + "col783": "32169", + "col784": "becim", + "col785": "qoqm9", + "col786": "i390t", + "col787": "nkwck", + "col788": "qhit9", + "col789": "qd3ru", + "col790": "5pzk1", + "col791": "bgbyz", + "col792": "4rctr", + "col793": "yhl3y", + "col794": "c3u5f", + "col795": "dzocb", + "col796": "cix1y", + "col797": "exo3o", + "col798": "8bhif", + "col799": "exv9e", + "col800": "kguhv", + "col801": "w8gv9", + "col802": "q0e4y", + "col803": "aiw70", + "col804": "3n486", + "col805": "jlcr7", + "col806": "9ofjj", + "col807": "fgmmp", + "col808": "y6slj", + "col809": "40qdo", + "col810": "shx23", + "col811": "eonfn", + "col812": "2kyxu", + "col813": "3ivby", + "col814": "tbibz", + "col815": "2ykr9", + "col816": "tzhjq", + "col817": "i0e1f", + "col818": "rh0y3", + "col819": "xeov3", + "col820": "jxhst", + "col821": "k2z85", + "col822": "m8uf8", + "col823": "1n9ez", + "col824": "owyxm", + "col825": "ziwkl", + "col826": "4cq82", + "col827": "ob9is", + "col828": "7h95f", + "col829": "qx2tn", + "col830": "9wq9e", + "col831": "w86as", + "col832": "0kpy5", + "col833": "6eyeh", + "col834": "re56s", + "col835": "s4qb5", + "col836": "ejz1m", + "col837": "9lbzv", + "col838": "7383q", + "col839": "vlrx2", + "col840": "j1qar", + "col841": "c1lex", + "col842": "4ug4w", + "col843": "ljnts", + "col844": "cvg75", + "col845": "dxo7m", + "col846": "zel7q", + "col847": "e3oza", + "col848": "81kzt", + "col849": "397q7", + "col850": "5vnwi", + "col851": "ch8o9", + "col852": "cke1z", + "col853": "0fjra", + "col854": "u1pgt", + "col855": "ki5ss", + "col856": "rh9oz", + "col857": "5jc0i", + "col858": "76qon", + "col859": "jooz3", + "col860": "f16pn", + "col861": "afn5k", + "col862": "wzokv", + "col863": "8ita2", + "col864": "0tbyg", + "col865": "l3bmr", + "col866": "d6ulv", + "col867": "20dl1", + "col868": "1fmel", + "col869": "9a7ql", + "col870": "ycats", + "col871": "2byrh", + "col872": "6cco7", + "col873": "3xiiq", + "col874": "9m4bz", + "col875": "zlfb9", + "col876": "cczhz", + "col877": "f86gu", + "col878": "cs3i8", + "col879": "abj3g", + "col880": "7fpuz", + "col881": "ojv45", + "col882": "jl671", + "col883": "i44pi", + "col884": "8o7u8", + "col885": "q1fv1", + "col886": "v2ysq", + "col887": "iiolb", + "col888": "om302", + "col889": "cgmp8", + "col890": "n3epe", + "col891": "cnany", + "col892": "iuoe4", + "col893": "7dyf7", + "col894": "rouiv", + "col895": "edomc", + "col896": "rdp8p", + "col897": "4ktux", + "col898": "sgpd7", + "col899": "m2kyu", + "col900": "dhvmf", + "col901": "ce4g9", + "col902": "v69bm", + "col903": "j2r6a", + "col904": "6fflo", + "col905": "lge31", + "col906": "328e3", + "col907": "4d3ua", + "col908": "nguyw", + "col909": "3ixoy", + "col910": "rm6lc", + "col911": "tlg6n", + "col912": "w193w", + "col913": "ta4dg", + "col914": "kqrik", + "col915": "j7ovc", + "col916": "len45", + "col917": "sbxyd", + "col918": "tq49d", + "col919": "46fwm", + "col920": "9mks0", + "col921": "okfkp", + "col922": "heia0", + "col923": "7w9pt", + "col924": "y5qz9", + "col925": "hfyoy", + "col926": "qp4um", + "col927": "h2s3t", + "col928": "zjamh", + "col929": "pfijg", + "col930": "d8sc2", + "col931": "7drxv", + "col932": "q7zjb", + "col933": "2oefw", + "col934": "rsz9j", + "col935": "nszx2", + "col936": "pkub0", + "col937": "ro14t", + "col938": "hbm4j", + "col939": "rnqv8", + "col940": "ayqgi", + "col941": "nsnr1", + "col942": "9aujw", + "col943": "2ndod", + "col944": "mp04v", + "col945": "vft1r", + "col946": "njx2y", + "col947": "lf4s6", + "col948": "shgso", + "col949": "s4g03", + "col950": "sdaqr", + "col951": "wo3bu", + "col952": "wy1o9", + "col953": "4kr6y", + "col954": "ic3fe", + "col955": "99ltv", + "col956": "8cwja", + "col957": "dk71f", + "col958": "xhdal", + "col959": "anwi3", + "col960": "4b5z8", + "col961": "iwyp6", + "col962": "ex8j3", + "col963": "094mm", + "col964": "nirmu", + "col965": "j37qx", + "col966": "1let4", + "col967": "83k5f", + "col968": "i49ht", + "col969": "2v485", + "col970": "pvkws", + "col971": "q8oph", + "col972": "7jrgc", + "col973": "b97wd", + "col974": "49f0n", + "col975": "0mv6n", + "col976": "2onih", + "col977": "251do", + "col978": "1fgjx", + "col979": "8jopr", + "col980": "8bx6x", + "col981": "5ftsi", + "col982": "z7yes", + "col983": "sytuf", + "col984": "wka6p", + "col985": "iwf4r", + "col986": "9o4h1", + "col987": "3opk5", + "col988": "csupp", + "col989": "hmkiy", + "col990": "6vxcz", + "col991": "9h4zk", + "col992": "dii4k", + "col993": "12bqo", + "col994": "e8pgj", + "col995": "9lkhs", + "col996": "qzcc3", + "col997": "mv8li", + "col998": "q76n8", + "col999": "2cvsa" + }, + { + "name": "Celeste Barber", + "gender": "female", + "col0": "7uc8w", + "col1": "88h8p", + "col2": "wq9ll", + "col3": "cyol0", + "col4": "osnd1", + "col5": "2xyj9", + "col6": "unfrp", + "col7": "84bfp", + "col8": "44h3v", + "col9": "pej0i", + "col10": "z2lq1", + "col11": "ay6ui", + "col12": "6uga5", + "col13": "datht", + "col14": "247r4", + "col15": "29fcn", + "col16": "3ion3", + "col17": "lspra", + "col18": "z8ojt", + "col19": "iyi4e", + "col20": "4g3kq", + "col21": "qkf1d", + "col22": "i1zuu", + "col23": "0nx51", + "col24": "119w5", + "col25": "invly", + "col26": "77401", + "col27": "dzhrp", + "col28": "g9og9", + "col29": "ao5si", + "col30": "62rk4", + "col31": "ixnea", + "col32": "rodx6", + "col33": "3lkrd", + "col34": "xftte", + "col35": "mu2a8", + "col36": "99n7b", + "col37": "emqil", + "col38": "fn4k7", + "col39": "awhid", + "col40": "4p5g5", + "col41": "nlvfg", + "col42": "kmvri", + "col43": "u91su", + "col44": "ei7wi", + "col45": "6sltm", + "col46": "48onn", + "col47": "pn1fd", + "col48": "xt59a", + "col49": "iu1r7", + "col50": "8jztb", + "col51": "77abn", + "col52": "yixg3", + "col53": "gd8s5", + "col54": "t2cvj", + "col55": "e0dxv", + "col56": "lzgzm", + "col57": "p30mk", + "col58": "u4vxl", + "col59": "dejim", + "col60": "io6w6", + "col61": "jpx1n", + "col62": "3h2iw", + "col63": "d5507", + "col64": "ffat4", + "col65": "0lbnx", + "col66": "jvmay", + "col67": "8euap", + "col68": "5mk9z", + "col69": "ahbtq", + "col70": "zhspj", + "col71": "rmv4t", + "col72": "6dhum", + "col73": "x3dcb", + "col74": "rhkku", + "col75": "aldfg", + "col76": "gbt33", + "col77": "69kbn", + "col78": "hgtek", + "col79": "q2gjd", + "col80": "nw0lo", + "col81": "fd6tu", + "col82": "4jgsf", + "col83": "e08a8", + "col84": "je727", + "col85": "2e17l", + "col86": "emyt5", + "col87": "no0c0", + "col88": "91gxt", + "col89": "ebw7b", + "col90": "xuj5q", + "col91": "px4l7", + "col92": "7dr9g", + "col93": "traiw", + "col94": "4is42", + "col95": "bn5pq", + "col96": "lgejv", + "col97": "r3oid", + "col98": "4d4ek", + "col99": "985sw", + "col100": "wqean", + "col101": "ljj8e", + "col102": "cci0c", + "col103": "hdx1y", + "col104": "7a7b3", + "col105": "znmgm", + "col106": "xce5n", + "col107": "usd6q", + "col108": "ubzu9", + "col109": "vxf79", + "col110": "2q6u8", + "col111": "bu91t", + "col112": "gy2qk", + "col113": "hk9pv", + "col114": "5pme3", + "col115": "uwnbe", + "col116": "md65e", + "col117": "csqic", + "col118": "706nv", + "col119": "b8uft", + "col120": "bts98", + "col121": "mw0lj", + "col122": "oyytc", + "col123": "h50ne", + "col124": "8wwc2", + "col125": "6t5g2", + "col126": "kty48", + "col127": "rg13u", + "col128": "nrktk", + "col129": "zbe0p", + "col130": "6l9r4", + "col131": "6ma3m", + "col132": "o3hw3", + "col133": "iaj7r", + "col134": "r5fma", + "col135": "wu2qz", + "col136": "3z74o", + "col137": "nrnb1", + "col138": "rwjtl", + "col139": "7znms", + "col140": "s1b8a", + "col141": "d6e2u", + "col142": "44xhb", + "col143": "ap5c8", + "col144": "bhcph", + "col145": "91ubr", + "col146": "z28x7", + "col147": "8809r", + "col148": "stwkk", + "col149": "eodw1", + "col150": "g6nhm", + "col151": "n3odo", + "col152": "p9nds", + "col153": "y5pcj", + "col154": "i4wux", + "col155": "87cte", + "col156": "oe953", + "col157": "uo7sr", + "col158": "uiitc", + "col159": "wbott", + "col160": "tw4et", + "col161": "z8x4j", + "col162": "f8dko", + "col163": "o32x2", + "col164": "fv4ee", + "col165": "8a3h6", + "col166": "k0jkk", + "col167": "uy7fl", + "col168": "yutyj", + "col169": "mofbn", + "col170": "1bsb1", + "col171": "1pd8r", + "col172": "alqgp", + "col173": "9tfcj", + "col174": "2dbh3", + "col175": "x73pi", + "col176": "7ym3v", + "col177": "hfuyg", + "col178": "wt2po", + "col179": "uzome", + "col180": "f69n2", + "col181": "tqkm0", + "col182": "vasq9", + "col183": "0yz84", + "col184": "kq0p0", + "col185": "zxe71", + "col186": "mod36", + "col187": "2hqjz", + "col188": "4o5oh", + "col189": "ndo2u", + "col190": "2j0sn", + "col191": "4anbd", + "col192": "copk6", + "col193": "5f0rn", + "col194": "yb0w2", + "col195": "uaolb", + "col196": "nfyhh", + "col197": "6zgaq", + "col198": "acjrc", + "col199": "0bp42", + "col200": "l3se3", + "col201": "fdfs7", + "col202": "15r0o", + "col203": "d8l0r", + "col204": "aqwzf", + "col205": "rg3j5", + "col206": "00em4", + "col207": "t9xhk", + "col208": "4dr39", + "col209": "x00f7", + "col210": "cj37k", + "col211": "p5p1g", + "col212": "dprg7", + "col213": "279l5", + "col214": "hqoih", + "col215": "vd91n", + "col216": "ptqdh", + "col217": "92yaj", + "col218": "48858", + "col219": "esdpa", + "col220": "kxlh7", + "col221": "238e4", + "col222": "6i70d", + "col223": "x1px5", + "col224": "usn03", + "col225": "5u0x1", + "col226": "8deys", + "col227": "yzxc0", + "col228": "e3j7a", + "col229": "eon1a", + "col230": "ykdy2", + "col231": "kapi5", + "col232": "6z63n", + "col233": "vdn91", + "col234": "siq3c", + "col235": "zcjd9", + "col236": "o4z8c", + "col237": "i3u8s", + "col238": "50ohx", + "col239": "mzj9w", + "col240": "i675h", + "col241": "h2cot", + "col242": "9wadk", + "col243": "r5sdl", + "col244": "f8xtx", + "col245": "fr3l3", + "col246": "cn5d5", + "col247": "q2isn", + "col248": "t7cxp", + "col249": "59fm1", + "col250": "isucf", + "col251": "xsfru", + "col252": "s4a8g", + "col253": "qkel1", + "col254": "x1xby", + "col255": "xs9oi", + "col256": "8qh4l", + "col257": "k6z84", + "col258": "29d85", + "col259": "w0g9q", + "col260": "inwge", + "col261": "0rzfk", + "col262": "udml3", + "col263": "crehu", + "col264": "x9iqb", + "col265": "rdk2f", + "col266": "41wl3", + "col267": "lvk3r", + "col268": "4t9em", + "col269": "dyb3l", + "col270": "hte5f", + "col271": "t982b", + "col272": "x322s", + "col273": "h9k3m", + "col274": "3ai7z", + "col275": "5dd9i", + "col276": "0lk37", + "col277": "1x8n2", + "col278": "3i1mx", + "col279": "lzl5z", + "col280": "7vc1o", + "col281": "z1me6", + "col282": "86gd8", + "col283": "mtwzw", + "col284": "rev4b", + "col285": "knb9v", + "col286": "q3q0k", + "col287": "bnp19", + "col288": "ivxbf", + "col289": "mgs3n", + "col290": "kdjxx", + "col291": "90yb7", + "col292": "kcwv3", + "col293": "82nu8", + "col294": "9jii2", + "col295": "6ws8d", + "col296": "lwdmi", + "col297": "b45it", + "col298": "n3c1n", + "col299": "d51vj", + "col300": "rndvk", + "col301": "qoocz", + "col302": "k42a5", + "col303": "2pmjo", + "col304": "ivatt", + "col305": "wszrd", + "col306": "plhzv", + "col307": "1f56l", + "col308": "9e3jw", + "col309": "965nw", + "col310": "sbwoe", + "col311": "68my0", + "col312": "ej7so", + "col313": "5idx5", + "col314": "i8o2g", + "col315": "10fsa", + "col316": "lfnbr", + "col317": "7q3fq", + "col318": "phvix", + "col319": "gzm24", + "col320": "fooz6", + "col321": "5093z", + "col322": "jzpm7", + "col323": "mw2d5", + "col324": "tr8w7", + "col325": "h8nzy", + "col326": "q72z3", + "col327": "z5ayq", + "col328": "0rhmu", + "col329": "k3x2b", + "col330": "s7993", + "col331": "1cfsg", + "col332": "0g5ef", + "col333": "92g9z", + "col334": "qojhe", + "col335": "lorj8", + "col336": "wlpmg", + "col337": "zi8y8", + "col338": "2mse9", + "col339": "k8xez", + "col340": "mabf7", + "col341": "gy79q", + "col342": "tn98w", + "col343": "bi8l4", + "col344": "nzo4c", + "col345": "1ahvc", + "col346": "f6qdv", + "col347": "9hq0h", + "col348": "8vrr2", + "col349": "l2te8", + "col350": "bh9ay", + "col351": "xr7go", + "col352": "xb4tw", + "col353": "xc5mc", + "col354": "mp8hp", + "col355": "3wdvu", + "col356": "9mqdb", + "col357": "zaus5", + "col358": "8q66s", + "col359": "lkvlh", + "col360": "qsr92", + "col361": "y6g51", + "col362": "1he7j", + "col363": "o5igm", + "col364": "cmi8v", + "col365": "xpth4", + "col366": "ndz9l", + "col367": "yr9ed", + "col368": "dsg2s", + "col369": "ejqe2", + "col370": "e32u2", + "col371": "z4ufe", + "col372": "sk64e", + "col373": "y35ek", + "col374": "6s38o", + "col375": "qon5b", + "col376": "z8jwo", + "col377": "m2436", + "col378": "8wy81", + "col379": "9tlxs", + "col380": "ecp30", + "col381": "b3mwt", + "col382": "1yyj1", + "col383": "aorco", + "col384": "v57ap", + "col385": "tzg19", + "col386": "wmhrt", + "col387": "4td9y", + "col388": "7op1e", + "col389": "843n4", + "col390": "qaals", + "col391": "ub0i2", + "col392": "vx6d3", + "col393": "2tf0w", + "col394": "0dglh", + "col395": "ccuyc", + "col396": "24g3p", + "col397": "qzvge", + "col398": "3st4e", + "col399": "witzf", + "col400": "p3hik", + "col401": "gyhzo", + "col402": "djh7r", + "col403": "bxwdj", + "col404": "5sp44", + "col405": "3oni0", + "col406": "bq1f5", + "col407": "92xbr", + "col408": "66kpo", + "col409": "ob08l", + "col410": "6fxg2", + "col411": "qveis", + "col412": "9ihvm", + "col413": "02y4t", + "col414": "4p6me", + "col415": "d27x5", + "col416": "8pbhm", + "col417": "t6aqo", + "col418": "kyycy", + "col419": "h7jc3", + "col420": "7ivw6", + "col421": "6lzc8", + "col422": "nohxb", + "col423": "lo380", + "col424": "oirfd", + "col425": "0kuo9", + "col426": "kyr3j", + "col427": "6tjcq", + "col428": "ywobv", + "col429": "ye9dq", + "col430": "l60up", + "col431": "ukv6c", + "col432": "wrybm", + "col433": "uzb5s", + "col434": "rwg3x", + "col435": "5umto", + "col436": "tv3ca", + "col437": "cf3rm", + "col438": "v41ld", + "col439": "j9g3w", + "col440": "ropw8", + "col441": "4dce7", + "col442": "k786a", + "col443": "sjtn9", + "col444": "2ezqj", + "col445": "kynig", + "col446": "0o826", + "col447": "ax5ri", + "col448": "ht00y", + "col449": "2mzgt", + "col450": "4b7v1", + "col451": "39h2g", + "col452": "tu6pt", + "col453": "kh284", + "col454": "cuatw", + "col455": "7gckk", + "col456": "jy6tu", + "col457": "1nk8a", + "col458": "4vn4g", + "col459": "jtcqk", + "col460": "kov2s", + "col461": "ex73y", + "col462": "1m8wo", + "col463": "jz0w5", + "col464": "d28lb", + "col465": "5fk47", + "col466": "6isi4", + "col467": "ji7pc", + "col468": "ly42s", + "col469": "2ylfl", + "col470": "6zioo", + "col471": "8scym", + "col472": "9csd6", + "col473": "bspvr", + "col474": "fb6ni", + "col475": "vd5oc", + "col476": "ni8vp", + "col477": "4lgw8", + "col478": "9j5bu", + "col479": "iog5x", + "col480": "a5anv", + "col481": "9bvx6", + "col482": "fxmhn", + "col483": "iy5wn", + "col484": "axkv7", + "col485": "rq8om", + "col486": "y0415", + "col487": "b9ago", + "col488": "t79a3", + "col489": "ejozg", + "col490": "dd2tb", + "col491": "lnf8s", + "col492": "0zjoe", + "col493": "v5vz4", + "col494": "q4iyc", + "col495": "u4suq", + "col496": "20i45", + "col497": "9fwde", + "col498": "576h8", + "col499": "dgugb", + "col500": "uqww2", + "col501": "jkj7t", + "col502": "7kx0g", + "col503": "y0itq", + "col504": "cz78w", + "col505": "o3hjm", + "col506": "uyx1s", + "col507": "yubf7", + "col508": "h2z6o", + "col509": "u6n2a", + "col510": "myh6k", + "col511": "4py9b", + "col512": "jxd1k", + "col513": "0el3p", + "col514": "y7szo", + "col515": "wu2ss", + "col516": "nij9n", + "col517": "gl716", + "col518": "pr7da", + "col519": "07re9", + "col520": "aeyv9", + "col521": "6k50p", + "col522": "g2t9e", + "col523": "4zjor", + "col524": "q9u7u", + "col525": "71hmy", + "col526": "4e6rv", + "col527": "0nbel", + "col528": "p46r1", + "col529": "jgs46", + "col530": "6uqh9", + "col531": "trn49", + "col532": "51w96", + "col533": "o0x2k", + "col534": "re4oj", + "col535": "4ki8j", + "col536": "mrqgj", + "col537": "zr88s", + "col538": "q08t7", + "col539": "na2uo", + "col540": "f43ju", + "col541": "2krqz", + "col542": "8rcua", + "col543": "dmc9k", + "col544": "1nu38", + "col545": "25fsn", + "col546": "wsxnb", + "col547": "deo2j", + "col548": "u84si", + "col549": "5cbs8", + "col550": "dlpqt", + "col551": "tgse2", + "col552": "jbcaw", + "col553": "19ze0", + "col554": "xdjbq", + "col555": "8y9so", + "col556": "cepq0", + "col557": "h2og0", + "col558": "3y69x", + "col559": "ywmfd", + "col560": "0z0sh", + "col561": "8baby", + "col562": "dnewc", + "col563": "iml53", + "col564": "69ldr", + "col565": "4owuj", + "col566": "2c1fu", + "col567": "c9jwy", + "col568": "dd2g3", + "col569": "3g6z1", + "col570": "7lmeb", + "col571": "jyyfy", + "col572": "n4ixi", + "col573": "kx9bo", + "col574": "xulni", + "col575": "9bpw6", + "col576": "wocam", + "col577": "o5vrr", + "col578": "egztz", + "col579": "cbsn0", + "col580": "ll6ni", + "col581": "jb6vk", + "col582": "8cf0i", + "col583": "ewroh", + "col584": "008ec", + "col585": "z1koi", + "col586": "of3d6", + "col587": "6slbq", + "col588": "h1kfi", + "col589": "is77f", + "col590": "ny216", + "col591": "0pe0n", + "col592": "hxowe", + "col593": "mshem", + "col594": "hdw2g", + "col595": "xnckk", + "col596": "o4d24", + "col597": "wz4m6", + "col598": "vtvv7", + "col599": "grezo", + "col600": "gx0og", + "col601": "gwiha", + "col602": "gd1og", + "col603": "pvwcc", + "col604": "s666p", + "col605": "kzw5m", + "col606": "zr8ke", + "col607": "s0qx0", + "col608": "6x7b4", + "col609": "mpirs", + "col610": "4qobu", + "col611": "v91cq", + "col612": "pqs22", + "col613": "ej6g2", + "col614": "qvfje", + "col615": "lt0am", + "col616": "mctt2", + "col617": "9kylv", + "col618": "62rsl", + "col619": "071ms", + "col620": "8lczw", + "col621": "qj1kn", + "col622": "6gn65", + "col623": "xv8cv", + "col624": "50ak9", + "col625": "j68t1", + "col626": "lu3ur", + "col627": "m8qdn", + "col628": "ttygb", + "col629": "ibzk7", + "col630": "i1ork", + "col631": "so6lb", + "col632": "92x03", + "col633": "fxeik", + "col634": "rdcxu", + "col635": "ualur", + "col636": "6gai6", + "col637": "t7zoo", + "col638": "rz943", + "col639": "954g3", + "col640": "30bpa", + "col641": "hpoqx", + "col642": "tk4bs", + "col643": "jt2c7", + "col644": "fzmqz", + "col645": "02jtk", + "col646": "1oczm", + "col647": "ztls4", + "col648": "s8w7b", + "col649": "sf16s", + "col650": "3gxmw", + "col651": "zqmav", + "col652": "7hvcx", + "col653": "78f70", + "col654": "6x9eg", + "col655": "xlzo8", + "col656": "a3i3e", + "col657": "dhc9g", + "col658": "sjlom", + "col659": "qlk8x", + "col660": "kx5st", + "col661": "kmnpp", + "col662": "c1347", + "col663": "0gicn", + "col664": "mrft2", + "col665": "x29z2", + "col666": "cgghq", + "col667": "tp3ec", + "col668": "58wn9", + "col669": "ndgre", + "col670": "ctkh5", + "col671": "jgas7", + "col672": "13vdy", + "col673": "rs1fx", + "col674": "r4gjo", + "col675": "vpkhq", + "col676": "5ct6c", + "col677": "qdetc", + "col678": "lg8is", + "col679": "nrxb8", + "col680": "0tw8t", + "col681": "7ht7h", + "col682": "kych0", + "col683": "lhk3z", + "col684": "ft11y", + "col685": "8i91y", + "col686": "ukl4e", + "col687": "cn7xs", + "col688": "lsyxg", + "col689": "3bwle", + "col690": "lw9u6", + "col691": "yfta5", + "col692": "iiitu", + "col693": "c8a7x", + "col694": "ngpm4", + "col695": "zxc09", + "col696": "aw4te", + "col697": "h7etf", + "col698": "6g8xn", + "col699": "aik03", + "col700": "7jsit", + "col701": "eeg6a", + "col702": "orh64", + "col703": "y123l", + "col704": "1nitu", + "col705": "yrju1", + "col706": "eanv3", + "col707": "i4zbj", + "col708": "8gi6f", + "col709": "kaxgb", + "col710": "8rr5m", + "col711": "ne5yw", + "col712": "nk1tf", + "col713": "4w6si", + "col714": "ggst4", + "col715": "go9sk", + "col716": "86aw7", + "col717": "qz1bu", + "col718": "fwn74", + "col719": "3efrc", + "col720": "ozueb", + "col721": "khsqk", + "col722": "rwh1v", + "col723": "uj6rd", + "col724": "7t9xz", + "col725": "bjqq4", + "col726": "3tjmm", + "col727": "648yk", + "col728": "xx95f", + "col729": "zt503", + "col730": "4t2zn", + "col731": "kfxqy", + "col732": "77emt", + "col733": "03q7v", + "col734": "4jj5b", + "col735": "8vs2c", + "col736": "zmfvu", + "col737": "p3g1x", + "col738": "htmz4", + "col739": "8tcqd", + "col740": "58ob6", + "col741": "48c52", + "col742": "m0nmx", + "col743": "f4jix", + "col744": "ui7dc", + "col745": "80c36", + "col746": "ngi3i", + "col747": "jsd28", + "col748": "4jaep", + "col749": "mv0ks", + "col750": "k19qc", + "col751": "lbefh", + "col752": "nbuns", + "col753": "eopp8", + "col754": "sqsdt", + "col755": "1462m", + "col756": "ecjxn", + "col757": "uhfqj", + "col758": "cbo4o", + "col759": "k9duc", + "col760": "ttevl", + "col761": "oq69c", + "col762": "gb92k", + "col763": "ooez7", + "col764": "puutz", + "col765": "defpt", + "col766": "fu4om", + "col767": "2edil", + "col768": "jcewq", + "col769": "lq6ox", + "col770": "zryzm", + "col771": "dnmzn", + "col772": "w2sa8", + "col773": "ia8q6", + "col774": "pbipx", + "col775": "zc2qx", + "col776": "5vcdb", + "col777": "kqtek", + "col778": "1s2pl", + "col779": "9re9u", + "col780": "1mxbe", + "col781": "prx7l", + "col782": "eyty0", + "col783": "zrj80", + "col784": "9g9tw", + "col785": "bwpes", + "col786": "8iejn", + "col787": "hpka4", + "col788": "0zbb2", + "col789": "7kpzm", + "col790": "fige6", + "col791": "yhcrn", + "col792": "v4hmn", + "col793": "wr3lw", + "col794": "iyqd8", + "col795": "ipq8r", + "col796": "76r9o", + "col797": "9y219", + "col798": "7pyvk", + "col799": "t1qxo", + "col800": "vyk1z", + "col801": "dkn3p", + "col802": "rbpvy", + "col803": "8l6e6", + "col804": "xbh0o", + "col805": "61zcv", + "col806": "yssc0", + "col807": "8aih3", + "col808": "a1rak", + "col809": "pm84o", + "col810": "gi7v0", + "col811": "hmwh2", + "col812": "dm7zo", + "col813": "qtf6d", + "col814": "y6joz", + "col815": "s83ao", + "col816": "uuky7", + "col817": "sq5oa", + "col818": "jblb0", + "col819": "skufu", + "col820": "52l66", + "col821": "43tj8", + "col822": "ou6gg", + "col823": "jvrpm", + "col824": "fxzoi", + "col825": "mkhl2", + "col826": "tm774", + "col827": "g230g", + "col828": "7jtq5", + "col829": "v04fe", + "col830": "7xupz", + "col831": "qdmso", + "col832": "jkdyy", + "col833": "fmiyq", + "col834": "1no17", + "col835": "wx2el", + "col836": "5kqbc", + "col837": "esjdo", + "col838": "jkmlm", + "col839": "et5vb", + "col840": "n6t1e", + "col841": "eado8", + "col842": "pwtck", + "col843": "qcgkm", + "col844": "bqcvb", + "col845": "q445j", + "col846": "txaft", + "col847": "8py8w", + "col848": "q2ab1", + "col849": "an12r", + "col850": "l20xy", + "col851": "yxmog", + "col852": "spwoa", + "col853": "fjdx2", + "col854": "vlmjc", + "col855": "alcr3", + "col856": "xeerj", + "col857": "okzlj", + "col858": "c2gpm", + "col859": "q32u2", + "col860": "9jtsm", + "col861": "3fxqv", + "col862": "k1qgk", + "col863": "7bc8m", + "col864": "4xua7", + "col865": "dopva", + "col866": "zjtww", + "col867": "kx1o9", + "col868": "hbz1k", + "col869": "i242k", + "col870": "esdl7", + "col871": "c8opj", + "col872": "3suqr", + "col873": "pwckd", + "col874": "10x8m", + "col875": "k044o", + "col876": "z06ma", + "col877": "3tw9p", + "col878": "0sdzd", + "col879": "53xjz", + "col880": "ser84", + "col881": "nxyuq", + "col882": "tcm2l", + "col883": "x9sb8", + "col884": "sj3kk", + "col885": "82xrr", + "col886": "nelw0", + "col887": "9rb35", + "col888": "th70a", + "col889": "qg6fu", + "col890": "bvqel", + "col891": "cuuml", + "col892": "kp2p6", + "col893": "7v7fc", + "col894": "x1jpq", + "col895": "9gj3i", + "col896": "dkd16", + "col897": "m0j9n", + "col898": "w0f4l", + "col899": "9448l", + "col900": "r6zfv", + "col901": "nq0tw", + "col902": "8b36t", + "col903": "a1vr7", + "col904": "ldky1", + "col905": "l8fzi", + "col906": "j5btk", + "col907": "f28o8", + "col908": "mcsix", + "col909": "p9oi4", + "col910": "lefwm", + "col911": "e6ucg", + "col912": "cqx9l", + "col913": "8v68a", + "col914": "9q4k8", + "col915": "p4i4c", + "col916": "a4kfq", + "col917": "fnre9", + "col918": "rsmf3", + "col919": "vrkje", + "col920": "3te61", + "col921": "3gb2a", + "col922": "i9cnu", + "col923": "568mm", + "col924": "24aqk", + "col925": "o7xow", + "col926": "2hqmx", + "col927": "azl94", + "col928": "5hqi6", + "col929": "zyzqe", + "col930": "xlchr", + "col931": "qvmu6", + "col932": "4fwfz", + "col933": "nuozu", + "col934": "7ebog", + "col935": "oqu7g", + "col936": "wd02u", + "col937": "ydgi8", + "col938": "7f73h", + "col939": "ytq38", + "col940": "mhbrf", + "col941": "ss2bi", + "col942": "xp5nz", + "col943": "fmria", + "col944": "nxq04", + "col945": "0sghd", + "col946": "aprgs", + "col947": "2qg7o", + "col948": "ne94e", + "col949": "u6arf", + "col950": "5lu6t", + "col951": "f6yfc", + "col952": "y1vyo", + "col953": "dnsk2", + "col954": "lgowr", + "col955": "j66j5", + "col956": "os6vn", + "col957": "frqaj", + "col958": "hixbc", + "col959": "4ba4v", + "col960": "6jo0i", + "col961": "0dlos", + "col962": "o7g7e", + "col963": "y1m4y", + "col964": "w6zid", + "col965": "70b08", + "col966": "cenq0", + "col967": "e0w69", + "col968": "ga7ky", + "col969": "c4tan", + "col970": "wrfbo", + "col971": "u9v05", + "col972": "pwii0", + "col973": "k35ak", + "col974": "jnzfn", + "col975": "27rvw", + "col976": "kuos3", + "col977": "6krsv", + "col978": "r3jv2", + "col979": "m10si", + "col980": "74g1k", + "col981": "zd8x2", + "col982": "dn3mx", + "col983": "hyscr", + "col984": "5ugm7", + "col985": "drvb8", + "col986": "jbh8m", + "col987": "2ozdi", + "col988": "syycc", + "col989": "5u158", + "col990": "hwfs5", + "col991": "h9iuh", + "col992": "4y10g", + "col993": "9pef2", + "col994": "a4ndu", + "col995": "ukek5", + "col996": "2abbo", + "col997": "2oab9", + "col998": "wwiys", + "col999": "eg0ik" + }, + { + "name": "Madelyn Hurst", + "gender": "female", + "col0": "je3fm", + "col1": "vunac", + "col2": "ayb3n", + "col3": "mna0x", + "col4": "gy6tz", + "col5": "h76c8", + "col6": "votfv", + "col7": "9mngn", + "col8": "dt0e3", + "col9": "bi2ql", + "col10": "18fn1", + "col11": "49dq5", + "col12": "5dbu0", + "col13": "u7h0r", + "col14": "yd85l", + "col15": "eg0hs", + "col16": "haf63", + "col17": "kaqq5", + "col18": "ys6tc", + "col19": "k2qk8", + "col20": "nz0h7", + "col21": "giies", + "col22": "q92qk", + "col23": "9rleo", + "col24": "vtfem", + "col25": "duw8u", + "col26": "tdl2e", + "col27": "ptz1u", + "col28": "ckzfo", + "col29": "zpw17", + "col30": "b6tt9", + "col31": "6i1ck", + "col32": "ortpu", + "col33": "qm7hs", + "col34": "c2068", + "col35": "yddix", + "col36": "l298x", + "col37": "ah2xt", + "col38": "1dsl0", + "col39": "t76al", + "col40": "l23cr", + "col41": "5r0ii", + "col42": "9hzwe", + "col43": "q8eg3", + "col44": "1fp64", + "col45": "mp45c", + "col46": "8f6n2", + "col47": "piwmh", + "col48": "p3r64", + "col49": "yzl7a", + "col50": "0iowl", + "col51": "cacy3", + "col52": "zxfv2", + "col53": "w0415", + "col54": "tvsf2", + "col55": "gwz09", + "col56": "8vreg", + "col57": "izxqv", + "col58": "4tt62", + "col59": "w61c7", + "col60": "8i9gj", + "col61": "z4tps", + "col62": "udpjt", + "col63": "y0r9c", + "col64": "rmxd7", + "col65": "sjozo", + "col66": "8qgth", + "col67": "160hl", + "col68": "af9pf", + "col69": "vtqbu", + "col70": "fl6cp", + "col71": "ewt7p", + "col72": "zimmf", + "col73": "ig9t3", + "col74": "bu952", + "col75": "69y11", + "col76": "qxigi", + "col77": "bw3dx", + "col78": "npfiw", + "col79": "dhw6u", + "col80": "q9hgm", + "col81": "emerq", + "col82": "9nzq5", + "col83": "hn8pv", + "col84": "friup", + "col85": "5lcal", + "col86": "h943n", + "col87": "98bab", + "col88": "yla2a", + "col89": "3c7xk", + "col90": "9fw25", + "col91": "5kfup", + "col92": "qrx83", + "col93": "u3edx", + "col94": "4i3u7", + "col95": "h1jt5", + "col96": "o16w9", + "col97": "jqhxu", + "col98": "fl8yt", + "col99": "i796w", + "col100": "c0m9k", + "col101": "8d9mo", + "col102": "chx2p", + "col103": "hzr7l", + "col104": "pzvf8", + "col105": "xknkl", + "col106": "gurqy", + "col107": "1oxbr", + "col108": "u6hxn", + "col109": "ad5tc", + "col110": "tykkb", + "col111": "r7mt4", + "col112": "qqmz2", + "col113": "o5j7b", + "col114": "m6cjc", + "col115": "t0me2", + "col116": "1c3nm", + "col117": "7iz3r", + "col118": "tsczp", + "col119": "gmqef", + "col120": "ky7rr", + "col121": "jvtmy", + "col122": "wfesw", + "col123": "60b9l", + "col124": "oel2s", + "col125": "zrarc", + "col126": "s3qsy", + "col127": "vjw07", + "col128": "xaidy", + "col129": "71pum", + "col130": "8rkd6", + "col131": "ot5sz", + "col132": "382de", + "col133": "1v0fx", + "col134": "jgtwj", + "col135": "w4h0r", + "col136": "vour5", + "col137": "aevo8", + "col138": "h2kua", + "col139": "z8onf", + "col140": "z7g4n", + "col141": "cddky", + "col142": "cf359", + "col143": "2s4qa", + "col144": "fkzgv", + "col145": "lyrqh", + "col146": "438wi", + "col147": "sysyh", + "col148": "bc5xz", + "col149": "pow5q", + "col150": "1ftdh", + "col151": "da5s1", + "col152": "igkxw", + "col153": "jqgio", + "col154": "oxwr3", + "col155": "dcxhx", + "col156": "on8k2", + "col157": "h7gg9", + "col158": "bxeaw", + "col159": "cwazi", + "col160": "iehen", + "col161": "fk4uz", + "col162": "vpwk5", + "col163": "7tsve", + "col164": "fu9iq", + "col165": "f17sa", + "col166": "5zhub", + "col167": "ex115", + "col168": "eb5zx", + "col169": "t423c", + "col170": "u8p6a", + "col171": "q87h0", + "col172": "dz2ty", + "col173": "tamqu", + "col174": "74fai", + "col175": "ouhgm", + "col176": "bd488", + "col177": "oxpud", + "col178": "dmojr", + "col179": "7pwqy", + "col180": "ddl2p", + "col181": "b5t2g", + "col182": "asb7t", + "col183": "wyead", + "col184": "t9m2f", + "col185": "mxg6q", + "col186": "zx657", + "col187": "xfahc", + "col188": "2sjyk", + "col189": "iqlws", + "col190": "ovtqj", + "col191": "gji70", + "col192": "oe0i6", + "col193": "i1ak8", + "col194": "17m52", + "col195": "8z0k2", + "col196": "1f0g7", + "col197": "5mioe", + "col198": "bwnpg", + "col199": "kux8t", + "col200": "j7zsz", + "col201": "hyqoa", + "col202": "hfw7p", + "col203": "s2hye", + "col204": "l4nh3", + "col205": "hpi0e", + "col206": "xu7pb", + "col207": "nob5y", + "col208": "kykk5", + "col209": "ne778", + "col210": "ik4mv", + "col211": "6qvus", + "col212": "8n5ah", + "col213": "ibuga", + "col214": "8usq0", + "col215": "83d5f", + "col216": "u9ykc", + "col217": "jsp26", + "col218": "ukf8o", + "col219": "cie7x", + "col220": "akscb", + "col221": "gl61r", + "col222": "4kyj9", + "col223": "ip5mn", + "col224": "hniln", + "col225": "4rt0j", + "col226": "7jx0q", + "col227": "v4yt3", + "col228": "5r3g4", + "col229": "8xiiv", + "col230": "3clqs", + "col231": "zl4ll", + "col232": "z12pd", + "col233": "rvcyk", + "col234": "id3a6", + "col235": "r27xj", + "col236": "96rs5", + "col237": "vbxrd", + "col238": "twb7q", + "col239": "cahuj", + "col240": "gf7zj", + "col241": "q5ql1", + "col242": "0cxe1", + "col243": "ar5h9", + "col244": "q9ot3", + "col245": "xu5h4", + "col246": "8hx8z", + "col247": "hctek", + "col248": "k3p10", + "col249": "hv4f8", + "col250": "gsl2x", + "col251": "vr6zd", + "col252": "7lnso", + "col253": "fbde3", + "col254": "a0y2t", + "col255": "zhgms", + "col256": "pymvv", + "col257": "9olfh", + "col258": "vfchr", + "col259": "mmhxl", + "col260": "isjqp", + "col261": "131rk", + "col262": "715ru", + "col263": "qt1b1", + "col264": "e3p0j", + "col265": "5n9ob", + "col266": "yd74s", + "col267": "ii34k", + "col268": "jxfn5", + "col269": "wpwmz", + "col270": "i208z", + "col271": "scbyl", + "col272": "vz99f", + "col273": "n4n1r", + "col274": "pwxo8", + "col275": "hwik3", + "col276": "3k5q8", + "col277": "s03r0", + "col278": "94vrw", + "col279": "gixpr", + "col280": "9dm4h", + "col281": "bxm5f", + "col282": "5lm9a", + "col283": "xnkla", + "col284": "apbww", + "col285": "x16b3", + "col286": "cy64q", + "col287": "0uetp", + "col288": "fyona", + "col289": "im6xm", + "col290": "jnbxj", + "col291": "9mcfx", + "col292": "gfgu9", + "col293": "tgxom", + "col294": "5thf3", + "col295": "llx3t", + "col296": "sw23o", + "col297": "1j86l", + "col298": "03sff", + "col299": "s20n6", + "col300": "4t0mr", + "col301": "5qf54", + "col302": "kb5hf", + "col303": "nubbk", + "col304": "c0fn1", + "col305": "u41m3", + "col306": "2m1oi", + "col307": "ztmbo", + "col308": "nhllg", + "col309": "08kbr", + "col310": "q73bt", + "col311": "uem8y", + "col312": "f8089", + "col313": "4hnzx", + "col314": "d33px", + "col315": "kt8c3", + "col316": "hsupr", + "col317": "74reu", + "col318": "8wm9o", + "col319": "zyrbb", + "col320": "4izsh", + "col321": "5r2uy", + "col322": "whq6j", + "col323": "l3gnt", + "col324": "kaaz4", + "col325": "v0jiq", + "col326": "gbj8t", + "col327": "suhck", + "col328": "z30m9", + "col329": "wnvw8", + "col330": "3xjbz", + "col331": "w0cwx", + "col332": "xetxn", + "col333": "9f65o", + "col334": "cljfl", + "col335": "j6h8s", + "col336": "yrh8w", + "col337": "sg3uc", + "col338": "uruxx", + "col339": "u0vfn", + "col340": "0vg9j", + "col341": "sn9jq", + "col342": "3153f", + "col343": "hr1fk", + "col344": "c78jx", + "col345": "rvkrx", + "col346": "3i7jc", + "col347": "6jn0l", + "col348": "xn5vk", + "col349": "v8e7y", + "col350": "rfged", + "col351": "3hxly", + "col352": "2d5pa", + "col353": "vj3l3", + "col354": "9pao7", + "col355": "de4m8", + "col356": "ppn1q", + "col357": "0uy6k", + "col358": "kz3gy", + "col359": "01s4k", + "col360": "f4iaq", + "col361": "gupvu", + "col362": "7ge5p", + "col363": "f6j8f", + "col364": "tqn1c", + "col365": "1yn5u", + "col366": "f7dv3", + "col367": "lxvov", + "col368": "kah00", + "col369": "dl854", + "col370": "to9lh", + "col371": "xjnpo", + "col372": "9yj9k", + "col373": "bi52a", + "col374": "u9wnv", + "col375": "y5wsf", + "col376": "ef1za", + "col377": "9b96q", + "col378": "7dey3", + "col379": "yhhse", + "col380": "g7npk", + "col381": "iz9sp", + "col382": "c6bv7", + "col383": "lxvik", + "col384": "3isva", + "col385": "xy0u6", + "col386": "kilh7", + "col387": "xe99u", + "col388": "j1rwb", + "col389": "95wor", + "col390": "60wgz", + "col391": "q14s6", + "col392": "r5m3u", + "col393": "ywbgk", + "col394": "0vm7o", + "col395": "hd1o4", + "col396": "4gsjh", + "col397": "40wbs", + "col398": "wnt6a", + "col399": "iq2hv", + "col400": "45ocy", + "col401": "l4ljs", + "col402": "djshp", + "col403": "ds597", + "col404": "agsn1", + "col405": "nroz3", + "col406": "0dgcl", + "col407": "qlec4", + "col408": "4riwm", + "col409": "dirug", + "col410": "znnlj", + "col411": "lo1yx", + "col412": "aanwq", + "col413": "59w5n", + "col414": "9yk75", + "col415": "59djp", + "col416": "3ecfv", + "col417": "2tj8h", + "col418": "ard9f", + "col419": "lubb8", + "col420": "othzj", + "col421": "2j2o6", + "col422": "c8564", + "col423": "4tikm", + "col424": "ioztf", + "col425": "efng5", + "col426": "h9dzk", + "col427": "ut5it", + "col428": "sufj4", + "col429": "wgpj6", + "col430": "zjg50", + "col431": "cxeyn", + "col432": "l4sgr", + "col433": "br24q", + "col434": "odinc", + "col435": "57noi", + "col436": "1im1g", + "col437": "xxsn5", + "col438": "mk87f", + "col439": "enhlq", + "col440": "zreu1", + "col441": "xoouj", + "col442": "7qabi", + "col443": "qb3bf", + "col444": "83nun", + "col445": "d8h2o", + "col446": "g28hm", + "col447": "r7iew", + "col448": "ipos2", + "col449": "wxtsf", + "col450": "icio4", + "col451": "hupoo", + "col452": "ghtqw", + "col453": "28vkm", + "col454": "yjs63", + "col455": "4kds9", + "col456": "n4i97", + "col457": "milbs", + "col458": "404j4", + "col459": "9lqxu", + "col460": "wff8v", + "col461": "uqvsu", + "col462": "29s88", + "col463": "c6fa9", + "col464": "80mv8", + "col465": "6h7es", + "col466": "o9q0b", + "col467": "zkhgn", + "col468": "g1yg5", + "col469": "ih3i3", + "col470": "9etj6", + "col471": "085fo", + "col472": "e2b4h", + "col473": "9plhs", + "col474": "f34gd", + "col475": "0wslq", + "col476": "i0ugr", + "col477": "5rf8k", + "col478": "lvm9o", + "col479": "kcf8o", + "col480": "1t5ax", + "col481": "rlwrl", + "col482": "94xs7", + "col483": "xzc66", + "col484": "5l3nm", + "col485": "7daqr", + "col486": "j9cvm", + "col487": "msxti", + "col488": "p3b1q", + "col489": "fzh44", + "col490": "8arvd", + "col491": "ytibb", + "col492": "4dx46", + "col493": "uavjx", + "col494": "4ytdz", + "col495": "0evcl", + "col496": "qkn7j", + "col497": "6ss0f", + "col498": "8dp6r", + "col499": "yaxh7", + "col500": "10b6w", + "col501": "wo2hq", + "col502": "4df4m", + "col503": "2adc6", + "col504": "x0e6f", + "col505": "1puri", + "col506": "zy04r", + "col507": "w5cnh", + "col508": "ncth0", + "col509": "i3lav", + "col510": "qpg4n", + "col511": "0dd8p", + "col512": "2biwy", + "col513": "zkkn3", + "col514": "0o3ko", + "col515": "o9brj", + "col516": "d702p", + "col517": "0af3i", + "col518": "2e6cv", + "col519": "rnfhs", + "col520": "spifl", + "col521": "0a4q5", + "col522": "k89jf", + "col523": "jep3f", + "col524": "0k17t", + "col525": "90hn7", + "col526": "7hqw2", + "col527": "aosrw", + "col528": "6pxyj", + "col529": "2ofsh", + "col530": "ywxc2", + "col531": "eplzn", + "col532": "kosj7", + "col533": "zb5ql", + "col534": "kvtzk", + "col535": "w0x76", + "col536": "kac1l", + "col537": "uomod", + "col538": "qo2o7", + "col539": "g84pv", + "col540": "5pes4", + "col541": "5j9es", + "col542": "zh2a7", + "col543": "yxr6m", + "col544": "2j671", + "col545": "j74kb", + "col546": "sajic", + "col547": "vf0y5", + "col548": "r4wua", + "col549": "429uw", + "col550": "hgudv", + "col551": "ymgjr", + "col552": "yej05", + "col553": "wo4p7", + "col554": "5ad22", + "col555": "g0bap", + "col556": "9x90r", + "col557": "trnh9", + "col558": "v03bs", + "col559": "rjuch", + "col560": "urwjv", + "col561": "qecho", + "col562": "zonru", + "col563": "zosiv", + "col564": "lhfbh", + "col565": "i9vsk", + "col566": "bnhgr", + "col567": "6rdw8", + "col568": "fp1o2", + "col569": "ad0by", + "col570": "52m2v", + "col571": "glbeh", + "col572": "6bwsq", + "col573": "j0254", + "col574": "7ebuo", + "col575": "xfhzb", + "col576": "4s6fa", + "col577": "f527p", + "col578": "dqgp8", + "col579": "ibvxh", + "col580": "efd1l", + "col581": "li1ib", + "col582": "ffr5i", + "col583": "v7d5q", + "col584": "thkr6", + "col585": "eo72c", + "col586": "y1414", + "col587": "qg10f", + "col588": "na90h", + "col589": "q1pm0", + "col590": "1kjpp", + "col591": "lbqf9", + "col592": "nvkfa", + "col593": "o9t2h", + "col594": "b2un8", + "col595": "wq08l", + "col596": "trzid", + "col597": "0e7iv", + "col598": "xryi6", + "col599": "0lcs2", + "col600": "jz78t", + "col601": "v45pl", + "col602": "735ee", + "col603": "uxzly", + "col604": "0d5al", + "col605": "dmun4", + "col606": "t8uaa", + "col607": "r396p", + "col608": "oakge", + "col609": "sdyt7", + "col610": "ssz8t", + "col611": "5mh8m", + "col612": "h1aji", + "col613": "zcg08", + "col614": "vucqr", + "col615": "h8dlk", + "col616": "a6axo", + "col617": "btugg", + "col618": "lq2pj", + "col619": "m04hj", + "col620": "4d2lc", + "col621": "g79m2", + "col622": "4vv8z", + "col623": "5cb6c", + "col624": "tzmia", + "col625": "6wdoq", + "col626": "1ttm0", + "col627": "552s8", + "col628": "et11m", + "col629": "7hitm", + "col630": "d9m67", + "col631": "70m23", + "col632": "b6omv", + "col633": "2qtqs", + "col634": "o7e2w", + "col635": "jne6v", + "col636": "l7sri", + "col637": "6elc4", + "col638": "mfka4", + "col639": "41suq", + "col640": "qdvci", + "col641": "dd9ob", + "col642": "i72lv", + "col643": "fn5x8", + "col644": "tgm49", + "col645": "92nu8", + "col646": "tno1t", + "col647": "qopz4", + "col648": "84kc7", + "col649": "0ew2t", + "col650": "bj0r3", + "col651": "aftuv", + "col652": "gv2di", + "col653": "9c2li", + "col654": "xmw9y", + "col655": "1zrez", + "col656": "uvg3b", + "col657": "iit22", + "col658": "cs3c3", + "col659": "qaljs", + "col660": "n4833", + "col661": "ji232", + "col662": "5q57p", + "col663": "zenul", + "col664": "yec35", + "col665": "ff3l8", + "col666": "rk256", + "col667": "rz4h4", + "col668": "4j28v", + "col669": "7o9a5", + "col670": "2c48x", + "col671": "h8wpd", + "col672": "axftw", + "col673": "3wceh", + "col674": "pnfin", + "col675": "7k5mt", + "col676": "tc2tj", + "col677": "h7rby", + "col678": "28fq7", + "col679": "me5oa", + "col680": "2opzv", + "col681": "xau6u", + "col682": "unozj", + "col683": "twl5k", + "col684": "r2c60", + "col685": "pq6db", + "col686": "3m3z6", + "col687": "gs19h", + "col688": "b9wci", + "col689": "rhojx", + "col690": "aau5w", + "col691": "6sxa6", + "col692": "8rmdw", + "col693": "8tgv0", + "col694": "6v88e", + "col695": "35m0j", + "col696": "25fqe", + "col697": "mbbi8", + "col698": "caojw", + "col699": "u4wnh", + "col700": "rejhn", + "col701": "jhwut", + "col702": "v8rpi", + "col703": "0pidb", + "col704": "kqse2", + "col705": "la824", + "col706": "tvzr5", + "col707": "7y0bh", + "col708": "5wcjr", + "col709": "azo06", + "col710": "alabg", + "col711": "mmt3a", + "col712": "tl3xo", + "col713": "90udr", + "col714": "qawbs", + "col715": "7ov12", + "col716": "yya9a", + "col717": "8s5si", + "col718": "h8ytd", + "col719": "gviwp", + "col720": "7nyxo", + "col721": "rop7d", + "col722": "r3kct", + "col723": "kdwcj", + "col724": "iiuyn", + "col725": "6h850", + "col726": "b9wbs", + "col727": "ynpfj", + "col728": "h1ri0", + "col729": "ixh97", + "col730": "hf1a4", + "col731": "np6wr", + "col732": "02qa6", + "col733": "ooaye", + "col734": "5hz86", + "col735": "xt0cr", + "col736": "92gqq", + "col737": "f1fgj", + "col738": "90qhb", + "col739": "0j42y", + "col740": "2chrz", + "col741": "uzkqb", + "col742": "a21wf", + "col743": "50rrl", + "col744": "6ghqd", + "col745": "m2t8i", + "col746": "rcc6i", + "col747": "1i5uw", + "col748": "hppra", + "col749": "2b6fs", + "col750": "tox8g", + "col751": "k2tv4", + "col752": "bnc5l", + "col753": "ljqra", + "col754": "dwgdb", + "col755": "9xb1x", + "col756": "o5uhs", + "col757": "amykl", + "col758": "2yli5", + "col759": "8upy5", + "col760": "76p3n", + "col761": "akmxl", + "col762": "z9vw9", + "col763": "dm6v4", + "col764": "y8sve", + "col765": "lusvq", + "col766": "hrhbb", + "col767": "27bz3", + "col768": "0fqh0", + "col769": "zgklh", + "col770": "h0den", + "col771": "3w7iw", + "col772": "i6euz", + "col773": "o6zso", + "col774": "gm4jg", + "col775": "enppm", + "col776": "lgktj", + "col777": "csf63", + "col778": "hr4qb", + "col779": "0n1id", + "col780": "279n8", + "col781": "p02u1", + "col782": "mkovt", + "col783": "ehbs1", + "col784": "ax5wy", + "col785": "vox5t", + "col786": "l760l", + "col787": "uzq5w", + "col788": "w0f5c", + "col789": "1kw8l", + "col790": "g4ysi", + "col791": "u8z3i", + "col792": "5q10k", + "col793": "lpewq", + "col794": "25g71", + "col795": "jyih3", + "col796": "ob0rp", + "col797": "pca1o", + "col798": "cenez", + "col799": "42ud1", + "col800": "lh1r9", + "col801": "24f9h", + "col802": "kdake", + "col803": "0xscc", + "col804": "3ynfq", + "col805": "awvtr", + "col806": "r7qui", + "col807": "eo8r2", + "col808": "jzc6s", + "col809": "usmcf", + "col810": "x648f", + "col811": "s1hvb", + "col812": "2jd8i", + "col813": "h6hhn", + "col814": "kfe6t", + "col815": "k3yii", + "col816": "rsopx", + "col817": "olxq5", + "col818": "e9xge", + "col819": "bfx5x", + "col820": "7c34x", + "col821": "ak1sv", + "col822": "tppq5", + "col823": "bykpn", + "col824": "mkgft", + "col825": "dg3yl", + "col826": "go2jb", + "col827": "zwehq", + "col828": "xp8ri", + "col829": "gqzsu", + "col830": "nil8z", + "col831": "l9v0i", + "col832": "zvct4", + "col833": "m1kwb", + "col834": "k6tjn", + "col835": "snfck", + "col836": "o8xjw", + "col837": "iofjl", + "col838": "p5oew", + "col839": "8rpjw", + "col840": "s4f5v", + "col841": "kd4dl", + "col842": "aslhf", + "col843": "r12lv", + "col844": "2j8sg", + "col845": "v6ikv", + "col846": "2tgrb", + "col847": "zass4", + "col848": "2of1k", + "col849": "kaqrw", + "col850": "ko3g5", + "col851": "r45oc", + "col852": "334ky", + "col853": "pmwph", + "col854": "ycsgo", + "col855": "taahd", + "col856": "r6mk9", + "col857": "l53h3", + "col858": "osrml", + "col859": "tg7uf", + "col860": "z9olu", + "col861": "0jic6", + "col862": "7u2by", + "col863": "3o81j", + "col864": "chagk", + "col865": "62d5t", + "col866": "to1dx", + "col867": "1fiuk", + "col868": "l8qdc", + "col869": "v22oo", + "col870": "2i70y", + "col871": "rrg9x", + "col872": "1u51x", + "col873": "6m6q4", + "col874": "egxb2", + "col875": "dblkg", + "col876": "ermwa", + "col877": "c2oif", + "col878": "cchy7", + "col879": "equda", + "col880": "dto2r", + "col881": "lt8nv", + "col882": "imf87", + "col883": "8mwgg", + "col884": "e7far", + "col885": "79ht1", + "col886": "vrsfj", + "col887": "plmzm", + "col888": "kc83y", + "col889": "vex0y", + "col890": "37a0w", + "col891": "88gmx", + "col892": "8ul02", + "col893": "ugv5b", + "col894": "7p4x5", + "col895": "1nqj1", + "col896": "8w8p9", + "col897": "l7q1q", + "col898": "1riub", + "col899": "luvez", + "col900": "2thqd", + "col901": "ja8nf", + "col902": "7qk62", + "col903": "itgci", + "col904": "88dsn", + "col905": "1ixyz", + "col906": "xtey3", + "col907": "2r2ja", + "col908": "6yw1c", + "col909": "ewhcj", + "col910": "j0pf6", + "col911": "eisvt", + "col912": "gsio0", + "col913": "y79e4", + "col914": "gqx31", + "col915": "tjjgk", + "col916": "bfdv4", + "col917": "3hdg3", + "col918": "2c8x2", + "col919": "u9kpo", + "col920": "7h5if", + "col921": "vyeaj", + "col922": "u8m1k", + "col923": "fccja", + "col924": "z5xmy", + "col925": "ddlyf", + "col926": "dslbu", + "col927": "1ty29", + "col928": "vacod", + "col929": "0wrhb", + "col930": "xg1pv", + "col931": "g3p92", + "col932": "67quq", + "col933": "e0j7t", + "col934": "leoiu", + "col935": "te4cw", + "col936": "odbdd", + "col937": "k9hov", + "col938": "iw587", + "col939": "orr8w", + "col940": "8cscn", + "col941": "jmcyq", + "col942": "6d7l6", + "col943": "avmko", + "col944": "cj555", + "col945": "t10yc", + "col946": "b01uz", + "col947": "u9kpi", + "col948": "hf51m", + "col949": "wnhge", + "col950": "0u5t0", + "col951": "rfvn0", + "col952": "4vcm5", + "col953": "rytvf", + "col954": "rmzbk", + "col955": "dg0v4", + "col956": "tuv43", + "col957": "ah9nb", + "col958": "18boj", + "col959": "87zzd", + "col960": "tfoes", + "col961": "6m0io", + "col962": "ivtnf", + "col963": "pb055", + "col964": "izs6v", + "col965": "b55ai", + "col966": "f5aip", + "col967": "kfmjo", + "col968": "jg4ha", + "col969": "pwrcm", + "col970": "dlgf3", + "col971": "56kh8", + "col972": "j2b6q", + "col973": "csciz", + "col974": "vd9is", + "col975": "8in2q", + "col976": "en7j3", + "col977": "wt4wj", + "col978": "bs1bi", + "col979": "fh3u8", + "col980": "inoo0", + "col981": "lct1c", + "col982": "pnlg4", + "col983": "s99q0", + "col984": "nr170", + "col985": "vkxsh", + "col986": "vlq7w", + "col987": "o8g0t", + "col988": "jow5b", + "col989": "zm6p8", + "col990": "e0kx8", + "col991": "2ru23", + "col992": "ehb90", + "col993": "zihtp", + "col994": "wm6k8", + "col995": "cc7x7", + "col996": "3055b", + "col997": "xr7pb", + "col998": "kwp18", + "col999": "noktv" + }, + { + "name": "Chandler David", + "gender": "male", + "col0": "dvpgo", + "col1": "6nk3m", + "col2": "ai4iv", + "col3": "7smzm", + "col4": "qbnu5", + "col5": "0b3g2", + "col6": "ft274", + "col7": "p6pns", + "col8": "hj3e5", + "col9": "mrp0r", + "col10": "1q8h9", + "col11": "v98qc", + "col12": "jshlz", + "col13": "auzhu", + "col14": "40h8y", + "col15": "20gfb", + "col16": "5j8ox", + "col17": "yfzld", + "col18": "gd6du", + "col19": "j05fz", + "col20": "9btrr", + "col21": "e95x1", + "col22": "46ob7", + "col23": "ms6ab", + "col24": "jj80y", + "col25": "vw5ku", + "col26": "0acfy", + "col27": "v2665", + "col28": "idnlu", + "col29": "sj6lm", + "col30": "flxjv", + "col31": "pdwe1", + "col32": "wo82k", + "col33": "eg9l8", + "col34": "yadaa", + "col35": "4mn27", + "col36": "abrlh", + "col37": "p56h6", + "col38": "7i01m", + "col39": "2jiwm", + "col40": "8ujlp", + "col41": "jpng4", + "col42": "oa7il", + "col43": "4phdg", + "col44": "mzvtq", + "col45": "0btgv", + "col46": "fd6ro", + "col47": "80c91", + "col48": "0swd1", + "col49": "l5308", + "col50": "hg0f3", + "col51": "eo683", + "col52": "algnu", + "col53": "qxww7", + "col54": "ryp49", + "col55": "hyorf", + "col56": "vni0i", + "col57": "suhem", + "col58": "qta3f", + "col59": "f2iol", + "col60": "q1fn3", + "col61": "2r3q7", + "col62": "tw4lq", + "col63": "6258a", + "col64": "iowb4", + "col65": "vkowz", + "col66": "f8ab3", + "col67": "1ceg3", + "col68": "zc9l4", + "col69": "locwa", + "col70": "98ter", + "col71": "jphwe", + "col72": "nmdeq", + "col73": "vah1p", + "col74": "q6wma", + "col75": "kq4ui", + "col76": "639w1", + "col77": "28tly", + "col78": "1jai9", + "col79": "hrp6s", + "col80": "vkn98", + "col81": "cgq0g", + "col82": "qodv9", + "col83": "k7wog", + "col84": "60hjg", + "col85": "3c925", + "col86": "d5i80", + "col87": "vznw1", + "col88": "q8b92", + "col89": "g3rv4", + "col90": "gr05t", + "col91": "p9phc", + "col92": "t0brl", + "col93": "35rjl", + "col94": "y6y7v", + "col95": "8w2sp", + "col96": "by3bx", + "col97": "wvkq9", + "col98": "qod4e", + "col99": "ausob", + "col100": "10c8s", + "col101": "dl0y9", + "col102": "8gukm", + "col103": "w9chp", + "col104": "1c9qo", + "col105": "ta25d", + "col106": "ajnkj", + "col107": "pzh7k", + "col108": "pstem", + "col109": "xx8mq", + "col110": "2scra", + "col111": "qi37f", + "col112": "12ovi", + "col113": "ygqfv", + "col114": "0jwqb", + "col115": "jyu08", + "col116": "wxoej", + "col117": "ae94v", + "col118": "hpd0v", + "col119": "44006", + "col120": "vn4pp", + "col121": "aw2su", + "col122": "buxd3", + "col123": "8162d", + "col124": "fd9il", + "col125": "wqqks", + "col126": "3ut1y", + "col127": "3xfjj", + "col128": "carg3", + "col129": "j4hdq", + "col130": "qd5vr", + "col131": "5b33z", + "col132": "4p8kw", + "col133": "q75uf", + "col134": "priz4", + "col135": "byw7j", + "col136": "w6k6f", + "col137": "11mve", + "col138": "lgw5u", + "col139": "ajhf5", + "col140": "i0llu", + "col141": "jg3sz", + "col142": "052uw", + "col143": "e1mfd", + "col144": "5tkpe", + "col145": "szivl", + "col146": "i71dw", + "col147": "5t7ei", + "col148": "pbaly", + "col149": "5zn46", + "col150": "sleur", + "col151": "6ygch", + "col152": "errip", + "col153": "gyljm", + "col154": "x8v8e", + "col155": "2vd16", + "col156": "wibta", + "col157": "sejxv", + "col158": "na7yv", + "col159": "1i0gy", + "col160": "o7ff3", + "col161": "vuk7w", + "col162": "t36ka", + "col163": "cxf0d", + "col164": "1rlf8", + "col165": "iofz1", + "col166": "leclf", + "col167": "gljju", + "col168": "scox3", + "col169": "3s1hg", + "col170": "jv5tz", + "col171": "pez1z", + "col172": "8ahk3", + "col173": "uvvt7", + "col174": "f2hfy", + "col175": "x27mw", + "col176": "dousb", + "col177": "d6m73", + "col178": "sig9c", + "col179": "ruy3g", + "col180": "5tx32", + "col181": "vvgt5", + "col182": "rqer0", + "col183": "74iun", + "col184": "xkynh", + "col185": "i5mxw", + "col186": "b1hs2", + "col187": "7d0wu", + "col188": "970qe", + "col189": "1f5x2", + "col190": "dzk8z", + "col191": "8rsab", + "col192": "5peiv", + "col193": "2l7eu", + "col194": "fzfdr", + "col195": "0dtkd", + "col196": "1ndz5", + "col197": "eko4m", + "col198": "w1buh", + "col199": "qqf49", + "col200": "zmowo", + "col201": "gka2j", + "col202": "murqn", + "col203": "jc0h6", + "col204": "e7cxm", + "col205": "dmfvj", + "col206": "xaivn", + "col207": "w5ruj", + "col208": "wgpxi", + "col209": "ai2ed", + "col210": "2g2ac", + "col211": "uiemc", + "col212": "7r7ie", + "col213": "6ltve", + "col214": "71pp6", + "col215": "8upbn", + "col216": "au1lx", + "col217": "27nkb", + "col218": "2k6u9", + "col219": "4ktce", + "col220": "j18n5", + "col221": "al2cx", + "col222": "2dybo", + "col223": "815fb", + "col224": "f8j5u", + "col225": "zpc0t", + "col226": "iviac", + "col227": "ydpie", + "col228": "l4t8l", + "col229": "p9cob", + "col230": "m0w49", + "col231": "8ciam", + "col232": "4rgkj", + "col233": "k7fwz", + "col234": "g0oam", + "col235": "27q9r", + "col236": "uqpm2", + "col237": "e0mn3", + "col238": "bg9e0", + "col239": "agabx", + "col240": "bmrnu", + "col241": "ar2p0", + "col242": "9c5te", + "col243": "sjz0q", + "col244": "05rbl", + "col245": "garup", + "col246": "bcyis", + "col247": "98f7q", + "col248": "ojuok", + "col249": "hkuh2", + "col250": "dfmnn", + "col251": "w9fjv", + "col252": "ubugu", + "col253": "vkd1v", + "col254": "9eeqz", + "col255": "vo5nq", + "col256": "7qmj7", + "col257": "yti2p", + "col258": "p6886", + "col259": "qedmw", + "col260": "7aja2", + "col261": "8qe8c", + "col262": "l7ckb", + "col263": "ohtpf", + "col264": "hmh3t", + "col265": "jetr1", + "col266": "84rqd", + "col267": "vs4g8", + "col268": "3xp1d", + "col269": "glznx", + "col270": "sb7lq", + "col271": "m0h3q", + "col272": "0zodq", + "col273": "tj0k3", + "col274": "o0m8f", + "col275": "f3ug0", + "col276": "r73s9", + "col277": "2pn8x", + "col278": "ozv9p", + "col279": "fa8pd", + "col280": "8ovzg", + "col281": "40tpa", + "col282": "emrgq", + "col283": "lpiii", + "col284": "yqyr2", + "col285": "k684b", + "col286": "gjzql", + "col287": "wx8ni", + "col288": "x33w9", + "col289": "xcefy", + "col290": "wkww4", + "col291": "zrbkg", + "col292": "r067b", + "col293": "d96h8", + "col294": "nk188", + "col295": "ki136", + "col296": "wfa66", + "col297": "71rpr", + "col298": "mpnff", + "col299": "8xdgm", + "col300": "s8yuz", + "col301": "p2iej", + "col302": "peue6", + "col303": "5lb3y", + "col304": "fsh2k", + "col305": "xlst3", + "col306": "hongr", + "col307": "7l3fu", + "col308": "nctxc", + "col309": "g9pl8", + "col310": "5r8c0", + "col311": "d33lv", + "col312": "07xcw", + "col313": "f6o3c", + "col314": "v070v", + "col315": "bpji3", + "col316": "1ty1s", + "col317": "zq3mz", + "col318": "i4uxw", + "col319": "ylp4g", + "col320": "x8fh7", + "col321": "2ymm2", + "col322": "1qkdk", + "col323": "sx7o2", + "col324": "773pj", + "col325": "ec6dj", + "col326": "mbyjv", + "col327": "zheyx", + "col328": "wrth2", + "col329": "bi042", + "col330": "zv1xi", + "col331": "7qihs", + "col332": "1q2gh", + "col333": "5ckoc", + "col334": "s57vi", + "col335": "yycd3", + "col336": "w1uw2", + "col337": "uhlxg", + "col338": "23v21", + "col339": "gewwd", + "col340": "lru3s", + "col341": "y73wr", + "col342": "8ysa8", + "col343": "qmu8p", + "col344": "mf5rz", + "col345": "2crfv", + "col346": "8ix70", + "col347": "t1moc", + "col348": "agtcs", + "col349": "onaoo", + "col350": "s2vyz", + "col351": "su0ki", + "col352": "sim9k", + "col353": "0di0o", + "col354": "tk48q", + "col355": "p0d7f", + "col356": "o7x4m", + "col357": "wbr86", + "col358": "dures", + "col359": "sqxii", + "col360": "k37ut", + "col361": "g7nyp", + "col362": "wj7eo", + "col363": "t8gp8", + "col364": "y6w7f", + "col365": "ylfx5", + "col366": "l3xlv", + "col367": "n6vqs", + "col368": "hoou0", + "col369": "8txyn", + "col370": "ibzbo", + "col371": "jpu0h", + "col372": "tccdf", + "col373": "pj26a", + "col374": "qowun", + "col375": "wua25", + "col376": "it7oj", + "col377": "8o0c7", + "col378": "iswcq", + "col379": "ntyuo", + "col380": "7jdab", + "col381": "arwss", + "col382": "0ac5v", + "col383": "53j0y", + "col384": "sgkbp", + "col385": "6dxrg", + "col386": "ep5xj", + "col387": "cx96l", + "col388": "jkec7", + "col389": "vy8e0", + "col390": "a92vt", + "col391": "x4nhw", + "col392": "x0mtv", + "col393": "q5ag4", + "col394": "7on71", + "col395": "bjuhm", + "col396": "pi1ux", + "col397": "hyjyl", + "col398": "ob1cm", + "col399": "77tnb", + "col400": "vyyks", + "col401": "29xv5", + "col402": "cfb6x", + "col403": "cf1s1", + "col404": "sraib", + "col405": "9gnty", + "col406": "vkrax", + "col407": "vv47m", + "col408": "e5q8i", + "col409": "m0ztp", + "col410": "b1kft", + "col411": "rncr9", + "col412": "lya3o", + "col413": "3htqz", + "col414": "a3pym", + "col415": "zyzo2", + "col416": "79vas", + "col417": "wmrp0", + "col418": "xir3l", + "col419": "jk7q1", + "col420": "p8phm", + "col421": "4b0gc", + "col422": "zmeci", + "col423": "8ribf", + "col424": "v4vp3", + "col425": "1xsba", + "col426": "ni5uh", + "col427": "hc0xg", + "col428": "vbs61", + "col429": "xwmak", + "col430": "n1s4u", + "col431": "5yyad", + "col432": "pqlra", + "col433": "z6j9t", + "col434": "v1qlq", + "col435": "t61b5", + "col436": "alkrr", + "col437": "wmj8t", + "col438": "11veo", + "col439": "s5pe9", + "col440": "02pjk", + "col441": "neoaj", + "col442": "6no5i", + "col443": "8wvn5", + "col444": "jt8ru", + "col445": "rpc0o", + "col446": "cmsj7", + "col447": "2rg2w", + "col448": "eac4o", + "col449": "v4ek7", + "col450": "4jdro", + "col451": "k4ujo", + "col452": "jlu4x", + "col453": "fq7rl", + "col454": "1oyfd", + "col455": "mc6fa", + "col456": "49bjh", + "col457": "oo3l2", + "col458": "bs2tw", + "col459": "ovumu", + "col460": "3p2sf", + "col461": "f7p31", + "col462": "yvhmp", + "col463": "22vq7", + "col464": "4p32p", + "col465": "oiw9v", + "col466": "cjn58", + "col467": "vrxut", + "col468": "7rshy", + "col469": "516cm", + "col470": "851c7", + "col471": "8dh4w", + "col472": "1a62c", + "col473": "p7oeq", + "col474": "9pzlt", + "col475": "fhutf", + "col476": "bwvrp", + "col477": "yf5wi", + "col478": "l1879", + "col479": "v1gm9", + "col480": "7r0on", + "col481": "vxyhp", + "col482": "4jkq8", + "col483": "hrcj3", + "col484": "0r585", + "col485": "9kb0c", + "col486": "qauq2", + "col487": "b7tzp", + "col488": "jbohi", + "col489": "wv90m", + "col490": "n1b5q", + "col491": "0uro7", + "col492": "wvdag", + "col493": "3lq3g", + "col494": "d2pjl", + "col495": "usgkc", + "col496": "1zznk", + "col497": "0n70i", + "col498": "v7buj", + "col499": "ctfny", + "col500": "qqzbc", + "col501": "xd45f", + "col502": "w6308", + "col503": "d33zk", + "col504": "02335", + "col505": "byo4u", + "col506": "a1whg", + "col507": "6h00i", + "col508": "9vibk", + "col509": "7smr3", + "col510": "b3cke", + "col511": "64k22", + "col512": "rgixp", + "col513": "067zx", + "col514": "2dy63", + "col515": "k6ovk", + "col516": "owm3r", + "col517": "bjms2", + "col518": "mvc54", + "col519": "xkm7e", + "col520": "5y1v0", + "col521": "4tuo0", + "col522": "k4ot5", + "col523": "8vlzr", + "col524": "vo2dx", + "col525": "ayyr3", + "col526": "6dvbz", + "col527": "0ni2l", + "col528": "d11j5", + "col529": "et0cw", + "col530": "i2xdq", + "col531": "8olh5", + "col532": "5rmiy", + "col533": "e5pbw", + "col534": "9qcmt", + "col535": "kmc5m", + "col536": "37rn3", + "col537": "7jm1d", + "col538": "mhw15", + "col539": "kvx27", + "col540": "6n3ew", + "col541": "skjin", + "col542": "zzolz", + "col543": "yq1rc", + "col544": "pej8b", + "col545": "mntyx", + "col546": "lk7q5", + "col547": "8dvxc", + "col548": "ps1br", + "col549": "nidgo", + "col550": "iv9fn", + "col551": "qxc3m", + "col552": "n0z5x", + "col553": "11102", + "col554": "kud6h", + "col555": "i44o1", + "col556": "ql5un", + "col557": "zrokr", + "col558": "xjgs7", + "col559": "oav1n", + "col560": "qpnpw", + "col561": "70x0u", + "col562": "ywy5i", + "col563": "7izi4", + "col564": "0n419", + "col565": "yhaz7", + "col566": "thihb", + "col567": "0j2oa", + "col568": "gg6r0", + "col569": "2buy2", + "col570": "fmzwc", + "col571": "rn49t", + "col572": "ib52z", + "col573": "59ohw", + "col574": "s7qd6", + "col575": "3oczm", + "col576": "otng4", + "col577": "t7vxw", + "col578": "lf5gq", + "col579": "e508n", + "col580": "v6e54", + "col581": "g6pn4", + "col582": "bs2df", + "col583": "uwyqd", + "col584": "c6qq9", + "col585": "k25u9", + "col586": "71vru", + "col587": "k1dq4", + "col588": "nkh32", + "col589": "r7ze9", + "col590": "km718", + "col591": "ovuko", + "col592": "h2bl1", + "col593": "e9zm6", + "col594": "fzxei", + "col595": "1prqc", + "col596": "ei5gz", + "col597": "4q4ol", + "col598": "uw1yz", + "col599": "bgxil", + "col600": "7ccot", + "col601": "fhl8v", + "col602": "wae87", + "col603": "g8kcp", + "col604": "x1jvj", + "col605": "49ixn", + "col606": "xg0o0", + "col607": "4hq8x", + "col608": "kod8j", + "col609": "1o4yt", + "col610": "35j92", + "col611": "gmm7y", + "col612": "xp0ge", + "col613": "5kz8d", + "col614": "gjzfs", + "col615": "fftiv", + "col616": "80ijx", + "col617": "e54ga", + "col618": "ppa9a", + "col619": "sv13y", + "col620": "s8ubs", + "col621": "jtdvd", + "col622": "qc6ow", + "col623": "sk9m4", + "col624": "ovnou", + "col625": "l0moz", + "col626": "2pbjb", + "col627": "f2f83", + "col628": "nk8ww", + "col629": "2h6gv", + "col630": "rsey6", + "col631": "x7bgg", + "col632": "7f9ij", + "col633": "a6fbb", + "col634": "i9it5", + "col635": "kd8fi", + "col636": "bbq9i", + "col637": "k3x3i", + "col638": "dkvxu", + "col639": "80301", + "col640": "3rxh1", + "col641": "f270c", + "col642": "gffho", + "col643": "df6ar", + "col644": "c1z8n", + "col645": "83tup", + "col646": "2i9qs", + "col647": "s0rh3", + "col648": "cphu3", + "col649": "5ux01", + "col650": "onxmo", + "col651": "6fm7n", + "col652": "hwdts", + "col653": "arsll", + "col654": "nchxr", + "col655": "8y871", + "col656": "22zz4", + "col657": "y8por", + "col658": "bz89n", + "col659": "wpqth", + "col660": "7jed3", + "col661": "uth65", + "col662": "oaw7w", + "col663": "f1qof", + "col664": "hbn2n", + "col665": "fqtxx", + "col666": "wmafk", + "col667": "xk9cx", + "col668": "5h3ju", + "col669": "0nxxb", + "col670": "cl1f2", + "col671": "9eeab", + "col672": "gc8ar", + "col673": "fs1q2", + "col674": "lqifv", + "col675": "9hyzl", + "col676": "fmu1u", + "col677": "dt95t", + "col678": "x5kio", + "col679": "z9qa9", + "col680": "e4d3l", + "col681": "4cbe6", + "col682": "ijbpe", + "col683": "jdqgn", + "col684": "ram5j", + "col685": "o3lh4", + "col686": "d5h9m", + "col687": "k7odx", + "col688": "na4p5", + "col689": "a4e9d", + "col690": "mrnxn", + "col691": "2665k", + "col692": "y5on7", + "col693": "j82dc", + "col694": "nbd4q", + "col695": "f5twm", + "col696": "zbc04", + "col697": "bpxj7", + "col698": "g9aay", + "col699": "k9mg4", + "col700": "ty9z6", + "col701": "ie06o", + "col702": "qe3a3", + "col703": "1cfgj", + "col704": "hico7", + "col705": "4q89b", + "col706": "9x0uo", + "col707": "1mfyx", + "col708": "xjduq", + "col709": "0la89", + "col710": "zu39h", + "col711": "za6f9", + "col712": "19i31", + "col713": "lbllg", + "col714": "kiaie", + "col715": "2d8qk", + "col716": "zemfy", + "col717": "3cj6m", + "col718": "xsqm3", + "col719": "gyk7h", + "col720": "5282e", + "col721": "l4pyf", + "col722": "c2elw", + "col723": "011qg", + "col724": "w8agh", + "col725": "rxo3r", + "col726": "wgke4", + "col727": "qzgp2", + "col728": "7fj8b", + "col729": "auwdt", + "col730": "weylf", + "col731": "b7l4e", + "col732": "w13lz", + "col733": "uwtm5", + "col734": "kfu3g", + "col735": "iqaer", + "col736": "y56q6", + "col737": "wfce7", + "col738": "9zi2q", + "col739": "mhn4k", + "col740": "zy4bw", + "col741": "tjl0e", + "col742": "9923y", + "col743": "5vsj8", + "col744": "5r4zf", + "col745": "8jtnh", + "col746": "65r57", + "col747": "r1ou5", + "col748": "tfgm9", + "col749": "4fdgn", + "col750": "znr1e", + "col751": "2c753", + "col752": "5qxbk", + "col753": "nkxoy", + "col754": "r730f", + "col755": "ayohn", + "col756": "63ne9", + "col757": "2pjwh", + "col758": "7fn2c", + "col759": "2cr9f", + "col760": "9d7h8", + "col761": "5nusf", + "col762": "mq1d5", + "col763": "lrktz", + "col764": "qvrus", + "col765": "egn9y", + "col766": "mg1p1", + "col767": "a9aep", + "col768": "4f70m", + "col769": "6yh65", + "col770": "plgtg", + "col771": "a4zy9", + "col772": "0jkjs", + "col773": "mjkfn", + "col774": "qkk1k", + "col775": "ys2pv", + "col776": "wqdnt", + "col777": "tja5a", + "col778": "9bhlj", + "col779": "3ypcy", + "col780": "zu2xe", + "col781": "sp0oi", + "col782": "64pjq", + "col783": "trin2", + "col784": "42s49", + "col785": "ypgwu", + "col786": "zzwmw", + "col787": "wyl9p", + "col788": "imtfq", + "col789": "o3ns2", + "col790": "wgb4d", + "col791": "8g271", + "col792": "gygy2", + "col793": "mb9pm", + "col794": "yuyrj", + "col795": "lwsdc", + "col796": "nqkav", + "col797": "ktyez", + "col798": "b7y2p", + "col799": "3imkf", + "col800": "cm7ry", + "col801": "dvbkf", + "col802": "69o4a", + "col803": "f1kef", + "col804": "e15pd", + "col805": "l2olc", + "col806": "n1p44", + "col807": "ktrzx", + "col808": "07v7w", + "col809": "fp9gr", + "col810": "dgkv7", + "col811": "c1xmf", + "col812": "vkia8", + "col813": "7l5h2", + "col814": "0ebp2", + "col815": "ibpr7", + "col816": "db7qx", + "col817": "xlk29", + "col818": "21326", + "col819": "azm9w", + "col820": "cw3c9", + "col821": "prhc1", + "col822": "89bai", + "col823": "wbr9j", + "col824": "zd6vf", + "col825": "gimnv", + "col826": "mo9yy", + "col827": "xy63z", + "col828": "872yu", + "col829": "jqba1", + "col830": "2vfrh", + "col831": "udpxk", + "col832": "1kkii", + "col833": "j5o4d", + "col834": "q6l3l", + "col835": "qpbak", + "col836": "pazi0", + "col837": "inxk6", + "col838": "82s4u", + "col839": "xaoqm", + "col840": "vdywi", + "col841": "bfxie", + "col842": "737lr", + "col843": "jklou", + "col844": "wqj8e", + "col845": "rpjks", + "col846": "dmsvn", + "col847": "6r7fa", + "col848": "du1bg", + "col849": "cqg70", + "col850": "n8lw2", + "col851": "yny1i", + "col852": "ubtsr", + "col853": "195k2", + "col854": "neuvl", + "col855": "1vfwp", + "col856": "hdo34", + "col857": "kdtlm", + "col858": "lp7rk", + "col859": "ra1i2", + "col860": "k0fnh", + "col861": "zh2vp", + "col862": "7zrwx", + "col863": "8c1mt", + "col864": "dl5l9", + "col865": "yqiwk", + "col866": "s4vlm", + "col867": "dzyb6", + "col868": "ofe5x", + "col869": "pxbdn", + "col870": "i2r3z", + "col871": "zbzob", + "col872": "s68oq", + "col873": "l4ebo", + "col874": "09mhp", + "col875": "u2u2y", + "col876": "e3gzq", + "col877": "wm44i", + "col878": "rb8ov", + "col879": "xe2zq", + "col880": "a4txq", + "col881": "wxafk", + "col882": "4grv0", + "col883": "98df9", + "col884": "wo0rd", + "col885": "ifu9t", + "col886": "r5r3u", + "col887": "xjz1o", + "col888": "39y2t", + "col889": "bu9dj", + "col890": "x0wyu", + "col891": "lr8z9", + "col892": "upvmt", + "col893": "6fkd6", + "col894": "7wpts", + "col895": "fur4t", + "col896": "3ykso", + "col897": "ltsah", + "col898": "3wo0h", + "col899": "ockzc", + "col900": "bsuuv", + "col901": "uawi4", + "col902": "m3c75", + "col903": "hvhmd", + "col904": "d09mo", + "col905": "370mz", + "col906": "gm18m", + "col907": "r8lb2", + "col908": "3c1ug", + "col909": "j5y7v", + "col910": "n79og", + "col911": "kbvzq", + "col912": "lo4zy", + "col913": "rqmq0", + "col914": "k3yci", + "col915": "4qpe3", + "col916": "uixga", + "col917": "o17vc", + "col918": "p4wt2", + "col919": "wcyti", + "col920": "bwd68", + "col921": "k3uzg", + "col922": "3p8us", + "col923": "dsb0n", + "col924": "ij3lv", + "col925": "tmz6r", + "col926": "hxg24", + "col927": "tb85c", + "col928": "7xths", + "col929": "dcyec", + "col930": "vl0bv", + "col931": "uchta", + "col932": "54nk1", + "col933": "4il7d", + "col934": "ewqj9", + "col935": "ccrjd", + "col936": "20y3i", + "col937": "6sv0d", + "col938": "9u4rz", + "col939": "a6zvo", + "col940": "3lehn", + "col941": "2p4f2", + "col942": "htxrw", + "col943": "e5jjc", + "col944": "i7mz0", + "col945": "oubfn", + "col946": "h27k5", + "col947": "3gdey", + "col948": "ikp20", + "col949": "1rqty", + "col950": "5yw9i", + "col951": "84koc", + "col952": "1ao3s", + "col953": "vm3zb", + "col954": "31ymv", + "col955": "qle24", + "col956": "ny3be", + "col957": "717pw", + "col958": "jrj5k", + "col959": "mx72d", + "col960": "ktj0u", + "col961": "8oat0", + "col962": "sfosa", + "col963": "rual5", + "col964": "4gckm", + "col965": "vghrl", + "col966": "oubpl", + "col967": "prtt5", + "col968": "790ar", + "col969": "wof56", + "col970": "mpsm8", + "col971": "1sen3", + "col972": "vxj2i", + "col973": "0k83s", + "col974": "nbcfy", + "col975": "u17fm", + "col976": "7v8jr", + "col977": "c6z99", + "col978": "v3skv", + "col979": "wpkrw", + "col980": "elwgi", + "col981": "nfg9r", + "col982": "tmrg7", + "col983": "gvowo", + "col984": "jf3jm", + "col985": "ehmzk", + "col986": "qn6i3", + "col987": "elmlz", + "col988": "1r7ua", + "col989": "5x2wk", + "col990": "283h7", + "col991": "04ovq", + "col992": "3jms3", + "col993": "j330e", + "col994": "zeiu8", + "col995": "rb8bn", + "col996": "y6150", + "col997": "tf4ik", + "col998": "7dkcm", + "col999": "nat02" + }, + { + "name": "Stanley Sanders", + "gender": "male", + "col0": "qbxhf", + "col1": "olzzn", + "col2": "qevs3", + "col3": "imgrh", + "col4": "e2k8l", + "col5": "9q5ua", + "col6": "fo6jm", + "col7": "mh271", + "col8": "g07y5", + "col9": "nza9m", + "col10": "gxbu1", + "col11": "cxkqf", + "col12": "o8qvv", + "col13": "g15fr", + "col14": "pqfu7", + "col15": "oo0ga", + "col16": "soan2", + "col17": "51g5u", + "col18": "nwqup", + "col19": "mjel4", + "col20": "zowi7", + "col21": "qzlxr", + "col22": "43476", + "col23": "h1p6p", + "col24": "r76km", + "col25": "as5d9", + "col26": "aoz23", + "col27": "ngu5v", + "col28": "sqpej", + "col29": "zeuvx", + "col30": "n5ihr", + "col31": "n41qy", + "col32": "uedkt", + "col33": "rvfq9", + "col34": "xron3", + "col35": "gqvev", + "col36": "gvk3e", + "col37": "2iavb", + "col38": "70hda", + "col39": "wiak6", + "col40": "ufelo", + "col41": "ozxvk", + "col42": "onj0e", + "col43": "gzahg", + "col44": "yujh0", + "col45": "4ot9s", + "col46": "tlt2z", + "col47": "7vwel", + "col48": "6rq5b", + "col49": "7sng2", + "col50": "hr6jv", + "col51": "vvbbh", + "col52": "06a1t", + "col53": "io901", + "col54": "ho7dj", + "col55": "13o4p", + "col56": "8xzc6", + "col57": "uc1e4", + "col58": "e29az", + "col59": "qi46n", + "col60": "98j90", + "col61": "ykcrj", + "col62": "73l8v", + "col63": "qp4gi", + "col64": "e6yae", + "col65": "3bh6t", + "col66": "cfos3", + "col67": "5uxjh", + "col68": "eju52", + "col69": "03ktx", + "col70": "au4pi", + "col71": "mcs46", + "col72": "e1voy", + "col73": "thjv3", + "col74": "sbpb7", + "col75": "pexei", + "col76": "o2cxo", + "col77": "s946g", + "col78": "z2yf8", + "col79": "nbsy3", + "col80": "5z7eg", + "col81": "kpbq7", + "col82": "sftvm", + "col83": "rtdwn", + "col84": "2bo23", + "col85": "n1xt9", + "col86": "ahjx5", + "col87": "1qwqg", + "col88": "t6tll", + "col89": "fgodf", + "col90": "g6awt", + "col91": "clu2d", + "col92": "6om5z", + "col93": "x4huv", + "col94": "3n9zo", + "col95": "z2bbi", + "col96": "tarnv", + "col97": "stzfc", + "col98": "eo2d8", + "col99": "czz65", + "col100": "44qy1", + "col101": "7d5ma", + "col102": "30v7z", + "col103": "kb46i", + "col104": "i2g2j", + "col105": "h5vr5", + "col106": "6lwp4", + "col107": "yrilq", + "col108": "bixpy", + "col109": "yavx4", + "col110": "ioghs", + "col111": "jkc83", + "col112": "9bw4w", + "col113": "lxrkw", + "col114": "9heli", + "col115": "mmtgx", + "col116": "0szl8", + "col117": "8fa7x", + "col118": "1rbfa", + "col119": "auwu4", + "col120": "fryxc", + "col121": "nl4b9", + "col122": "pqxbw", + "col123": "0mcxy", + "col124": "pnpuf", + "col125": "y5j9t", + "col126": "6kb7z", + "col127": "xi8iw", + "col128": "ndzmi", + "col129": "w6u84", + "col130": "39i96", + "col131": "qpgo9", + "col132": "r7rg5", + "col133": "fp840", + "col134": "9b3vc", + "col135": "9gte9", + "col136": "l1gcn", + "col137": "nzjkj", + "col138": "fq1zf", + "col139": "s3qka", + "col140": "df3gk", + "col141": "ioq6g", + "col142": "kb0jj", + "col143": "387b1", + "col144": "jtat1", + "col145": "v4y2m", + "col146": "50qg1", + "col147": "fppas", + "col148": "226t4", + "col149": "s41sa", + "col150": "npbf4", + "col151": "zogbz", + "col152": "41tty", + "col153": "p24hx", + "col154": "s0w0p", + "col155": "27b4k", + "col156": "gppmh", + "col157": "mu09v", + "col158": "vfnw4", + "col159": "kb7eh", + "col160": "a29vn", + "col161": "h07c2", + "col162": "r0s6x", + "col163": "q691y", + "col164": "29701", + "col165": "7t9ql", + "col166": "r4779", + "col167": "156b1", + "col168": "0vgjw", + "col169": "kldaf", + "col170": "ugrgz", + "col171": "7otq5", + "col172": "v3dsf", + "col173": "pral4", + "col174": "ngvax", + "col175": "ufm43", + "col176": "hd32n", + "col177": "u9vk2", + "col178": "d7not", + "col179": "rn6ck", + "col180": "ro5x5", + "col181": "m1px2", + "col182": "b5ap6", + "col183": "grqg0", + "col184": "4aueh", + "col185": "cevry", + "col186": "ql5ij", + "col187": "vo45w", + "col188": "7ih6e", + "col189": "0sl5n", + "col190": "10r3o", + "col191": "4p92z", + "col192": "z1g4f", + "col193": "oydsv", + "col194": "91edh", + "col195": "fk3yl", + "col196": "yzuy3", + "col197": "by8r4", + "col198": "jzii8", + "col199": "evtsn", + "col200": "cwaer", + "col201": "ya6p1", + "col202": "4ag79", + "col203": "lmxuw", + "col204": "7wulk", + "col205": "zx6sk", + "col206": "8alf8", + "col207": "6zg9t", + "col208": "h127h", + "col209": "mejlq", + "col210": "gnpky", + "col211": "1pviv", + "col212": "7xk7x", + "col213": "y8egt", + "col214": "c2cvo", + "col215": "zj400", + "col216": "lmbik", + "col217": "lxde8", + "col218": "4pcjk", + "col219": "yzcsn", + "col220": "9zfqw", + "col221": "qktvl", + "col222": "1uc3j", + "col223": "b7jky", + "col224": "yevcx", + "col225": "rosx2", + "col226": "7q3q8", + "col227": "tr081", + "col228": "0k7wp", + "col229": "co5hn", + "col230": "765u1", + "col231": "yib2n", + "col232": "6luiq", + "col233": "ke63p", + "col234": "zasxc", + "col235": "01s7t", + "col236": "lmmf1", + "col237": "cpnoy", + "col238": "wgcdg", + "col239": "kbsjv", + "col240": "fy6j6", + "col241": "uztgg", + "col242": "w6t5r", + "col243": "8rg76", + "col244": "hmqnp", + "col245": "vmkxy", + "col246": "llsuv", + "col247": "5z0sa", + "col248": "gxwmo", + "col249": "8htf7", + "col250": "3h4la", + "col251": "7i482", + "col252": "cbvuj", + "col253": "5d02f", + "col254": "pw4rn", + "col255": "42e7s", + "col256": "fdub1", + "col257": "lbalf", + "col258": "7ucvk", + "col259": "2m4s6", + "col260": "zemtn", + "col261": "0wojb", + "col262": "c0cjc", + "col263": "2021e", + "col264": "7ycsr", + "col265": "dut71", + "col266": "l322e", + "col267": "v7dl4", + "col268": "sjw1l", + "col269": "ukt45", + "col270": "i501j", + "col271": "0g8z3", + "col272": "7v30j", + "col273": "o46no", + "col274": "2ffgr", + "col275": "64cik", + "col276": "u5q6r", + "col277": "g4ray", + "col278": "d7xcf", + "col279": "565v5", + "col280": "u1ymm", + "col281": "3anw3", + "col282": "ormz9", + "col283": "argoa", + "col284": "tlooe", + "col285": "gc06m", + "col286": "6g753", + "col287": "xq3hs", + "col288": "s8co5", + "col289": "1adv6", + "col290": "31sxa", + "col291": "twuaq", + "col292": "uy84a", + "col293": "bnjcr", + "col294": "ohh17", + "col295": "z85tk", + "col296": "0owss", + "col297": "c3ppv", + "col298": "lczin", + "col299": "q8rrz", + "col300": "hyw4y", + "col301": "03h7l", + "col302": "8iaf6", + "col303": "inwdt", + "col304": "z8p05", + "col305": "znfqt", + "col306": "f9rv6", + "col307": "bup45", + "col308": "f8gxw", + "col309": "qqcdd", + "col310": "j9nou", + "col311": "19x11", + "col312": "as1cj", + "col313": "f8n05", + "col314": "9n040", + "col315": "1hza2", + "col316": "pf4px", + "col317": "fme3w", + "col318": "ngl2b", + "col319": "a4vzs", + "col320": "idsn0", + "col321": "pzc0y", + "col322": "jooag", + "col323": "l510f", + "col324": "k75rn", + "col325": "t2tat", + "col326": "rfoae", + "col327": "kd968", + "col328": "dvuoa", + "col329": "jx29h", + "col330": "9t5mu", + "col331": "q099n", + "col332": "nko77", + "col333": "nrrt3", + "col334": "vmord", + "col335": "6ivsh", + "col336": "rkzyo", + "col337": "gpx88", + "col338": "ttc9m", + "col339": "c24ar", + "col340": "kz8b8", + "col341": "dzd9w", + "col342": "ocvbx", + "col343": "nopov", + "col344": "izr4z", + "col345": "y57tn", + "col346": "1iohq", + "col347": "v3lxg", + "col348": "qgam4", + "col349": "t15vv", + "col350": "33yf7", + "col351": "0p3d4", + "col352": "5kaj6", + "col353": "ygxxs", + "col354": "cm4t2", + "col355": "sdy2x", + "col356": "n1g0z", + "col357": "0dlp5", + "col358": "8qc28", + "col359": "02g85", + "col360": "ak3dm", + "col361": "48g02", + "col362": "6pi8j", + "col363": "gztpj", + "col364": "7ud1r", + "col365": "cbg0s", + "col366": "406oq", + "col367": "8efwp", + "col368": "nz38c", + "col369": "ewet2", + "col370": "c30wb", + "col371": "lgijw", + "col372": "sv5ij", + "col373": "crzxa", + "col374": "eznen", + "col375": "1nbbo", + "col376": "h07f3", + "col377": "3qcp1", + "col378": "ozosb", + "col379": "hazgi", + "col380": "r771e", + "col381": "idsjd", + "col382": "s8aba", + "col383": "baloo", + "col384": "m0349", + "col385": "3ypy3", + "col386": "0v1l1", + "col387": "y46z5", + "col388": "63y26", + "col389": "i8mtu", + "col390": "jm2kb", + "col391": "p56ro", + "col392": "7kvpk", + "col393": "s1iaj", + "col394": "xwsjh", + "col395": "m1blv", + "col396": "s4u4k", + "col397": "bbqyf", + "col398": "zosd2", + "col399": "oqamp", + "col400": "xs1r4", + "col401": "vlrfk", + "col402": "nzasx", + "col403": "176yr", + "col404": "atilr", + "col405": "m2vil", + "col406": "7m4e7", + "col407": "llia8", + "col408": "b5aln", + "col409": "bmkhm", + "col410": "slwrr", + "col411": "ne7dy", + "col412": "i6k9p", + "col413": "wwufo", + "col414": "zdeee", + "col415": "z0qc1", + "col416": "r4sug", + "col417": "1s86e", + "col418": "cbeg3", + "col419": "fqc77", + "col420": "ysiq6", + "col421": "6xmw3", + "col422": "5yzr6", + "col423": "7twbh", + "col424": "gyn72", + "col425": "4harn", + "col426": "0ch4k", + "col427": "9x1te", + "col428": "s08ww", + "col429": "6nuiy", + "col430": "fzhxa", + "col431": "zs6ic", + "col432": "jhlsf", + "col433": "9g5l6", + "col434": "z2in7", + "col435": "psxc9", + "col436": "h5kql", + "col437": "s5w6d", + "col438": "zg8h4", + "col439": "0lxs6", + "col440": "2lc9j", + "col441": "abddl", + "col442": "ldyba", + "col443": "3juz3", + "col444": "meoim", + "col445": "b5wgb", + "col446": "6js6t", + "col447": "izj6g", + "col448": "6vl84", + "col449": "45qds", + "col450": "jgqzx", + "col451": "q3u37", + "col452": "pil2n", + "col453": "pz7rc", + "col454": "ci5j4", + "col455": "6vtsd", + "col456": "tuyxe", + "col457": "6wwgf", + "col458": "da28h", + "col459": "vre74", + "col460": "gkb58", + "col461": "e8vxc", + "col462": "yrozn", + "col463": "thi75", + "col464": "bikcy", + "col465": "jlt81", + "col466": "1n9jc", + "col467": "d9tu8", + "col468": "pda8d", + "col469": "yth09", + "col470": "nffmt", + "col471": "9az54", + "col472": "8c8bg", + "col473": "m945a", + "col474": "sdzvg", + "col475": "juas1", + "col476": "xixsp", + "col477": "vto04", + "col478": "1ydbn", + "col479": "e8pur", + "col480": "ushir", + "col481": "krdbf", + "col482": "f766j", + "col483": "pmw4r", + "col484": "7m9bc", + "col485": "pvdb6", + "col486": "p5g2q", + "col487": "kwpty", + "col488": "irvfu", + "col489": "ydqdi", + "col490": "hq5dl", + "col491": "babmp", + "col492": "wl10c", + "col493": "9frmu", + "col494": "728lo", + "col495": "a843v", + "col496": "jwtc5", + "col497": "jsiq5", + "col498": "mr48l", + "col499": "gtybu", + "col500": "5pty2", + "col501": "80uhf", + "col502": "zk79b", + "col503": "j5dj5", + "col504": "gjoo4", + "col505": "k6nnd", + "col506": "sut3f", + "col507": "1pgk6", + "col508": "j1u56", + "col509": "c0a3r", + "col510": "mzhex", + "col511": "nhwvp", + "col512": "88o2v", + "col513": "jfksf", + "col514": "tggd7", + "col515": "2p2nn", + "col516": "f053m", + "col517": "huq7v", + "col518": "0i8of", + "col519": "xnu7v", + "col520": "3au71", + "col521": "y2om1", + "col522": "5taxj", + "col523": "s06uu", + "col524": "xznra", + "col525": "mfjgh", + "col526": "u6e04", + "col527": "ufjlq", + "col528": "f2ziv", + "col529": "igm1z", + "col530": "u9w4m", + "col531": "8hz2c", + "col532": "x24ku", + "col533": "574kz", + "col534": "f19ae", + "col535": "25cxx", + "col536": "qhstq", + "col537": "eeosr", + "col538": "1h6n2", + "col539": "nr4a5", + "col540": "zslcj", + "col541": "wdatj", + "col542": "80nyj", + "col543": "w6ltk", + "col544": "chmu5", + "col545": "x4k4d", + "col546": "rulub", + "col547": "md1d3", + "col548": "5a9nc", + "col549": "6h3hb", + "col550": "4aues", + "col551": "jku7p", + "col552": "8evj4", + "col553": "d2iyp", + "col554": "vcz81", + "col555": "afgsf", + "col556": "z4m5r", + "col557": "k3v9u", + "col558": "sm283", + "col559": "83ju0", + "col560": "o0ehy", + "col561": "qsgzn", + "col562": "ztic2", + "col563": "3hu5z", + "col564": "82xi3", + "col565": "sz1mx", + "col566": "rervi", + "col567": "867cb", + "col568": "nb2os", + "col569": "d1lna", + "col570": "wlyhr", + "col571": "g7h1o", + "col572": "7nb4n", + "col573": "2ovc3", + "col574": "j22he", + "col575": "zn1pj", + "col576": "a2yjq", + "col577": "ni4y8", + "col578": "x0rde", + "col579": "6o5ic", + "col580": "ixjl7", + "col581": "3m6ei", + "col582": "d5bt0", + "col583": "acmt4", + "col584": "b7nek", + "col585": "u10j0", + "col586": "yp91u", + "col587": "us6rm", + "col588": "evpij", + "col589": "p66uu", + "col590": "asxku", + "col591": "o13kq", + "col592": "iv4qh", + "col593": "2uecd", + "col594": "257ca", + "col595": "upvi6", + "col596": "8hpax", + "col597": "lll1y", + "col598": "pkvdx", + "col599": "w2mg6", + "col600": "y92ho", + "col601": "yfnua", + "col602": "13yq1", + "col603": "54h4d", + "col604": "0lysy", + "col605": "u4wc6", + "col606": "o57yr", + "col607": "qlgya", + "col608": "aiygp", + "col609": "vessh", + "col610": "zozgv", + "col611": "7neap", + "col612": "yuzcn", + "col613": "wvnxe", + "col614": "oo209", + "col615": "9q0so", + "col616": "5b1jx", + "col617": "odp6s", + "col618": "ne7o4", + "col619": "12uny", + "col620": "5wexp", + "col621": "n9kag", + "col622": "31f9k", + "col623": "v7lre", + "col624": "f12v2", + "col625": "9hwtw", + "col626": "b946w", + "col627": "gktn8", + "col628": "wkckh", + "col629": "4jg3h", + "col630": "r73e7", + "col631": "x9b96", + "col632": "szm73", + "col633": "rhfyg", + "col634": "sr2b1", + "col635": "emjtj", + "col636": "642vh", + "col637": "v570h", + "col638": "a9wjr", + "col639": "cg70y", + "col640": "98y9p", + "col641": "wyr7y", + "col642": "egi64", + "col643": "atlv1", + "col644": "9up0y", + "col645": "wua9r", + "col646": "t680m", + "col647": "8htcr", + "col648": "4djwo", + "col649": "jrvul", + "col650": "q8hj3", + "col651": "xjmq1", + "col652": "6hns4", + "col653": "7qsfq", + "col654": "hnylz", + "col655": "d7f3l", + "col656": "y9egn", + "col657": "otzg9", + "col658": "zwxt0", + "col659": "bgq90", + "col660": "vf8fz", + "col661": "mcmx5", + "col662": "hdlpe", + "col663": "yhlz3", + "col664": "788h8", + "col665": "ejmcl", + "col666": "d4h8w", + "col667": "tpcm4", + "col668": "ufkfv", + "col669": "7f8aw", + "col670": "mtj60", + "col671": "bgwm5", + "col672": "sjnc7", + "col673": "v227h", + "col674": "ui31e", + "col675": "qqfkp", + "col676": "wozfc", + "col677": "sqc67", + "col678": "znysr", + "col679": "bj3pr", + "col680": "ub1ml", + "col681": "4ctbq", + "col682": "1wwl5", + "col683": "ixcj4", + "col684": "6jb94", + "col685": "dt8su", + "col686": "h7czp", + "col687": "pp7p7", + "col688": "ul1cw", + "col689": "rabh9", + "col690": "liwnm", + "col691": "a8ulj", + "col692": "rt62f", + "col693": "5qsk4", + "col694": "1fscn", + "col695": "nn9gc", + "col696": "4vejn", + "col697": "02v5m", + "col698": "p7sl6", + "col699": "f6gj5", + "col700": "x1txu", + "col701": "qgjux", + "col702": "10coq", + "col703": "rz18l", + "col704": "1dd5m", + "col705": "y9o4t", + "col706": "kkih7", + "col707": "1n9wc", + "col708": "q38cl", + "col709": "rhs12", + "col710": "3j01q", + "col711": "mum3v", + "col712": "mgbg4", + "col713": "6m463", + "col714": "xmuh4", + "col715": "zlbc0", + "col716": "xcc3x", + "col717": "j39p5", + "col718": "5z43n", + "col719": "0bcz8", + "col720": "boezz", + "col721": "c6m1d", + "col722": "nyk6o", + "col723": "6z4o2", + "col724": "cbnao", + "col725": "0aff3", + "col726": "tr6wi", + "col727": "vvtxm", + "col728": "9zmmr", + "col729": "d2ncr", + "col730": "pwtq9", + "col731": "ih6ul", + "col732": "2w7fb", + "col733": "pi0cv", + "col734": "xzb90", + "col735": "sl0bq", + "col736": "9xjfy", + "col737": "rahwm", + "col738": "zqye3", + "col739": "uqnrz", + "col740": "3aid6", + "col741": "gnm14", + "col742": "zrmeu", + "col743": "vn2dx", + "col744": "qh1zb", + "col745": "9leo3", + "col746": "jkwrr", + "col747": "bj2jl", + "col748": "fsaee", + "col749": "a9fea", + "col750": "ddiqo", + "col751": "hr9rz", + "col752": "hhzw1", + "col753": "3luyc", + "col754": "eky63", + "col755": "gk9tn", + "col756": "zf46n", + "col757": "187q3", + "col758": "608w4", + "col759": "1ipbb", + "col760": "d7snb", + "col761": "wy0xu", + "col762": "6ohpk", + "col763": "r45ww", + "col764": "j9f11", + "col765": "bimes", + "col766": "qsjih", + "col767": "3v2vv", + "col768": "orbj1", + "col769": "1ugc1", + "col770": "eunt3", + "col771": "45xgg", + "col772": "o3q9k", + "col773": "wkiaj", + "col774": "7etup", + "col775": "b26de", + "col776": "0pbd1", + "col777": "2nxti", + "col778": "auabg", + "col779": "2wemn", + "col780": "psbdm", + "col781": "l0n67", + "col782": "ahet2", + "col783": "mzpvc", + "col784": "jlkvz", + "col785": "p0lh0", + "col786": "afx7k", + "col787": "orvut", + "col788": "p7emx", + "col789": "bclpl", + "col790": "th1kk", + "col791": "l3o1f", + "col792": "hpgeo", + "col793": "b8tpe", + "col794": "mc7ej", + "col795": "8kbk7", + "col796": "tst9n", + "col797": "vsdhg", + "col798": "tyhds", + "col799": "0k7yq", + "col800": "p9wzc", + "col801": "6u0pb", + "col802": "7g4dj", + "col803": "dcm1o", + "col804": "xa0j8", + "col805": "szrvg", + "col806": "xa6hw", + "col807": "foxm8", + "col808": "oieqm", + "col809": "6mpm0", + "col810": "nvtip", + "col811": "gp9wm", + "col812": "84jjx", + "col813": "0509g", + "col814": "6qiwe", + "col815": "cv7z6", + "col816": "9wh7b", + "col817": "id89g", + "col818": "zdbbz", + "col819": "aw1yd", + "col820": "qbbx3", + "col821": "vh07m", + "col822": "ywdlv", + "col823": "m5o3z", + "col824": "s5b6a", + "col825": "xr40i", + "col826": "iqzyt", + "col827": "y6z8n", + "col828": "xb8z9", + "col829": "o71n8", + "col830": "7f1t4", + "col831": "a9ski", + "col832": "p4vm3", + "col833": "q0g7n", + "col834": "wrqpn", + "col835": "m9ucz", + "col836": "qinvg", + "col837": "m5aei", + "col838": "cl2uj", + "col839": "rxqhb", + "col840": "smgb4", + "col841": "sivdb", + "col842": "9e13h", + "col843": "p4kh9", + "col844": "f1wtk", + "col845": "ibs2f", + "col846": "3zdz3", + "col847": "s0u8n", + "col848": "s6b5w", + "col849": "x9rc6", + "col850": "28n1m", + "col851": "gqkil", + "col852": "mgpef", + "col853": "y243y", + "col854": "s53hl", + "col855": "ekya1", + "col856": "4yvmb", + "col857": "im3h2", + "col858": "9x6y8", + "col859": "supso", + "col860": "ha47s", + "col861": "nmx6z", + "col862": "2q3ao", + "col863": "vc8s6", + "col864": "va8au", + "col865": "j9pvs", + "col866": "46qy9", + "col867": "iampu", + "col868": "cc1pt", + "col869": "wlfxa", + "col870": "wzt1n", + "col871": "qdp1d", + "col872": "vkiix", + "col873": "e3bfy", + "col874": "w9b9a", + "col875": "gbnzk", + "col876": "rghfm", + "col877": "jt4w9", + "col878": "m28h2", + "col879": "ryzo3", + "col880": "zpq40", + "col881": "n3qx5", + "col882": "haqdz", + "col883": "o9bbp", + "col884": "7skl8", + "col885": "nhzua", + "col886": "anyrl", + "col887": "y5clw", + "col888": "hjbra", + "col889": "hn6gv", + "col890": "7x773", + "col891": "cwh6v", + "col892": "75g9y", + "col893": "rbw2w", + "col894": "sijb6", + "col895": "ddcva", + "col896": "wz99j", + "col897": "ejqwk", + "col898": "b1eto", + "col899": "osflv", + "col900": "zzr5q", + "col901": "9cht6", + "col902": "2s2wf", + "col903": "pmqy7", + "col904": "awtt4", + "col905": "t3tq0", + "col906": "9bbjc", + "col907": "o0j7j", + "col908": "wx6sm", + "col909": "p4mde", + "col910": "7bwx3", + "col911": "4fhn8", + "col912": "hq3yb", + "col913": "r98po", + "col914": "if0cf", + "col915": "sjjsq", + "col916": "8rori", + "col917": "3z1hy", + "col918": "18692", + "col919": "fo6p8", + "col920": "46g7p", + "col921": "xb863", + "col922": "at235", + "col923": "64nov", + "col924": "pn7uo", + "col925": "goa84", + "col926": "o5dba", + "col927": "g36b8", + "col928": "d2t3t", + "col929": "hh905", + "col930": "qwrah", + "col931": "m227m", + "col932": "wk22e", + "col933": "wzscs", + "col934": "iuaiu", + "col935": "37qdy", + "col936": "ziqsw", + "col937": "vvzk8", + "col938": "3z1dd", + "col939": "xmwp9", + "col940": "xzldi", + "col941": "cbmjo", + "col942": "ynifk", + "col943": "oyrm1", + "col944": "4l7hk", + "col945": "cjl64", + "col946": "653g7", + "col947": "sg4i8", + "col948": "zc9ls", + "col949": "u3mzl", + "col950": "ebq6r", + "col951": "8u25m", + "col952": "qkbyn", + "col953": "539ad", + "col954": "puerz", + "col955": "vkzlk", + "col956": "nsffr", + "col957": "53u71", + "col958": "pnimr", + "col959": "rz04w", + "col960": "5qexp", + "col961": "vsdiz", + "col962": "i88qw", + "col963": "qypyr", + "col964": "fiukk", + "col965": "9kzmc", + "col966": "yaabu", + "col967": "2hyhy", + "col968": "xry58", + "col969": "jm35u", + "col970": "oge4x", + "col971": "byjw0", + "col972": "ildni", + "col973": "dw76g", + "col974": "f3079", + "col975": "wa8ys", + "col976": "ueot3", + "col977": "0zu56", + "col978": "wn1rh", + "col979": "wg5f0", + "col980": "00lam", + "col981": "n1og8", + "col982": "sdem5", + "col983": "ww61h", + "col984": "dejc4", + "col985": "60wf9", + "col986": "190da", + "col987": "8c25m", + "col988": "gq4f2", + "col989": "0wdra", + "col990": "faj1a", + "col991": "l31kb", + "col992": "d64nu", + "col993": "pqwah", + "col994": "nofgq", + "col995": "by4o5", + "col996": "v4420", + "col997": "krtcp", + "col998": "6p88v", + "col999": "6n70r" + }, + { + "name": "Suarez Richmond", + "gender": "male", + "col0": "xs9x8", + "col1": "lg55v", + "col2": "e5wn1", + "col3": "9uwp3", + "col4": "rshx3", + "col5": "8fiqw", + "col6": "1nqp1", + "col7": "1kjjx", + "col8": "3mav1", + "col9": "428fe", + "col10": "ky7fe", + "col11": "eqkdm", + "col12": "4n0wp", + "col13": "klx7f", + "col14": "146hq", + "col15": "b7os3", + "col16": "typbb", + "col17": "s7z9k", + "col18": "0ffvu", + "col19": "f7fna", + "col20": "8ysn7", + "col21": "gbk3l", + "col22": "eaxg1", + "col23": "1zuq7", + "col24": "b752h", + "col25": "q8y0n", + "col26": "7ifi3", + "col27": "hpset", + "col28": "84u2t", + "col29": "r29nf", + "col30": "5gtqn", + "col31": "xb1fl", + "col32": "qbhzj", + "col33": "zzkgb", + "col34": "7czd7", + "col35": "9hoji", + "col36": "46wlt", + "col37": "0f1c1", + "col38": "8p2cp", + "col39": "d74ig", + "col40": "5499m", + "col41": "rj0hj", + "col42": "d170d", + "col43": "pkwek", + "col44": "qazwd", + "col45": "dy5w1", + "col46": "2ylxp", + "col47": "mbn6v", + "col48": "t4ifn", + "col49": "3ta9e", + "col50": "4gcow", + "col51": "8u1wm", + "col52": "vcabi", + "col53": "4iiry", + "col54": "4nixo", + "col55": "45hz4", + "col56": "nyjan", + "col57": "poid4", + "col58": "v42p9", + "col59": "rz9vj", + "col60": "tqvnv", + "col61": "5foyg", + "col62": "htzte", + "col63": "1i1qq", + "col64": "yd6zc", + "col65": "cbt4p", + "col66": "ynw2p", + "col67": "x67y9", + "col68": "zs28y", + "col69": "xjnew", + "col70": "wlrqn", + "col71": "h00eu", + "col72": "mhuwq", + "col73": "test8", + "col74": "ihzu2", + "col75": "ofk3l", + "col76": "tleaa", + "col77": "v5aby", + "col78": "fybye", + "col79": "w9wu4", + "col80": "whbol", + "col81": "xp8ux", + "col82": "4w0lh", + "col83": "iisgp", + "col84": "kldp3", + "col85": "kbw0q", + "col86": "vulgd", + "col87": "zj9k8", + "col88": "uf240", + "col89": "k58ce", + "col90": "ozqno", + "col91": "lvqff", + "col92": "iy9ht", + "col93": "yb3kb", + "col94": "s6l6v", + "col95": "5l7vs", + "col96": "hfk08", + "col97": "pkz16", + "col98": "6l5xy", + "col99": "x8v79", + "col100": "xgx62", + "col101": "m8a75", + "col102": "i7k7p", + "col103": "h216n", + "col104": "qsmgf", + "col105": "66jxk", + "col106": "45h89", + "col107": "k8ius", + "col108": "acqr1", + "col109": "mcy4v", + "col110": "um504", + "col111": "hhdeq", + "col112": "sf4v3", + "col113": "w81u4", + "col114": "idoqf", + "col115": "myvpv", + "col116": "18knm", + "col117": "frbh2", + "col118": "l6trd", + "col119": "cgg5d", + "col120": "ys6nx", + "col121": "hw0w1", + "col122": "4kzwr", + "col123": "e1k68", + "col124": "kh5ac", + "col125": "523v7", + "col126": "kgz6n", + "col127": "rqqlv", + "col128": "zlqwp", + "col129": "vibtv", + "col130": "8g0wc", + "col131": "gp0a9", + "col132": "29v6p", + "col133": "918ti", + "col134": "vwurl", + "col135": "ga5i0", + "col136": "zjz8w", + "col137": "3z9z6", + "col138": "07e0r", + "col139": "c28yn", + "col140": "azif0", + "col141": "mfyji", + "col142": "54zb0", + "col143": "gelyu", + "col144": "60m2b", + "col145": "3x40d", + "col146": "jr0s8", + "col147": "0j0b2", + "col148": "x1dfz", + "col149": "2hkcy", + "col150": "k7ai1", + "col151": "jmpst", + "col152": "5bv1i", + "col153": "lqthz", + "col154": "84pb0", + "col155": "hdhi3", + "col156": "bbeud", + "col157": "2o6pv", + "col158": "3o17t", + "col159": "g5jzr", + "col160": "5gbgc", + "col161": "68a5h", + "col162": "p1jqk", + "col163": "2yghk", + "col164": "224uu", + "col165": "fdwhg", + "col166": "fqg36", + "col167": "vegl7", + "col168": "i18wj", + "col169": "rhkjc", + "col170": "wcvtd", + "col171": "ltfav", + "col172": "l6odu", + "col173": "ybeb9", + "col174": "4e02r", + "col175": "idwa4", + "col176": "p5fd2", + "col177": "itkyi", + "col178": "9pk09", + "col179": "rbgmv", + "col180": "azf2y", + "col181": "mjq06", + "col182": "f755b", + "col183": "q4su4", + "col184": "3rxeu", + "col185": "sifnz", + "col186": "055x9", + "col187": "35o9m", + "col188": "zeoo5", + "col189": "k9m11", + "col190": "q4es6", + "col191": "stybs", + "col192": "6933x", + "col193": "l55z8", + "col194": "n42z0", + "col195": "gf7in", + "col196": "88doh", + "col197": "kxk8z", + "col198": "7sg4i", + "col199": "ob64o", + "col200": "04vj7", + "col201": "fhtc0", + "col202": "lsapr", + "col203": "kc4gv", + "col204": "l6k9e", + "col205": "9odqe", + "col206": "98u1p", + "col207": "5gfhe", + "col208": "f43ds", + "col209": "xlv1y", + "col210": "42txg", + "col211": "6fta2", + "col212": "9jzxu", + "col213": "yqizk", + "col214": "w13vx", + "col215": "3z9e0", + "col216": "mo9rp", + "col217": "c0om9", + "col218": "drkzn", + "col219": "3kivd", + "col220": "cgxli", + "col221": "vbiqx", + "col222": "a26kq", + "col223": "ea762", + "col224": "1ehx8", + "col225": "t3w3p", + "col226": "y9let", + "col227": "ln5l6", + "col228": "q7nn2", + "col229": "di6l0", + "col230": "xiz9c", + "col231": "1l423", + "col232": "8xse8", + "col233": "zl11i", + "col234": "hdqb3", + "col235": "swytw", + "col236": "k1u9w", + "col237": "10220", + "col238": "w610m", + "col239": "hh8gg", + "col240": "74zo3", + "col241": "elv39", + "col242": "vcqxm", + "col243": "ni13s", + "col244": "774o8", + "col245": "mv31z", + "col246": "xbp1y", + "col247": "pv3ca", + "col248": "hcww6", + "col249": "ql3di", + "col250": "iuz8a", + "col251": "kcjx8", + "col252": "z8c7a", + "col253": "rwx31", + "col254": "tfiu6", + "col255": "sw93x", + "col256": "m1xew", + "col257": "be711", + "col258": "l683z", + "col259": "qkxne", + "col260": "6lrra", + "col261": "vljz7", + "col262": "bh9yk", + "col263": "375ev", + "col264": "4eutj", + "col265": "bu6jj", + "col266": "ia9h5", + "col267": "ba2yq", + "col268": "4d4km", + "col269": "i8ara", + "col270": "xi8fy", + "col271": "ric27", + "col272": "dpdd1", + "col273": "x5ugp", + "col274": "wmw8h", + "col275": "aj53s", + "col276": "kg8i1", + "col277": "wxjig", + "col278": "otbbl", + "col279": "vof4a", + "col280": "ilone", + "col281": "zztlf", + "col282": "z85fu", + "col283": "wdfq4", + "col284": "c0g5g", + "col285": "4vxu2", + "col286": "3azwo", + "col287": "3dciw", + "col288": "jg4l7", + "col289": "xp6v6", + "col290": "24gq9", + "col291": "pf56x", + "col292": "j68yk", + "col293": "7g9un", + "col294": "z4p9q", + "col295": "de0ap", + "col296": "im340", + "col297": "x7q59", + "col298": "n3y9z", + "col299": "gi6s5", + "col300": "jg43e", + "col301": "x7krk", + "col302": "95j79", + "col303": "wqx86", + "col304": "h31xj", + "col305": "kc32b", + "col306": "7bo51", + "col307": "qn3py", + "col308": "8ga8b", + "col309": "cqem6", + "col310": "96wc5", + "col311": "plmqd", + "col312": "yzj7u", + "col313": "gkyng", + "col314": "gi2un", + "col315": "jd2jv", + "col316": "gz57y", + "col317": "bnny4", + "col318": "1abfb", + "col319": "4bd2e", + "col320": "3np4k", + "col321": "ngp8x", + "col322": "v0ysk", + "col323": "m19jg", + "col324": "5m2ht", + "col325": "wwj0m", + "col326": "v6tsb", + "col327": "5ay74", + "col328": "ioqr3", + "col329": "ul80d", + "col330": "z9vod", + "col331": "wm1wl", + "col332": "t2eh3", + "col333": "cniy7", + "col334": "ry8o6", + "col335": "1mde0", + "col336": "odkid", + "col337": "qm2k2", + "col338": "q88wm", + "col339": "pie2o", + "col340": "v4k7d", + "col341": "fyuz7", + "col342": "fabqp", + "col343": "7tdjb", + "col344": "iz678", + "col345": "6jvnx", + "col346": "bwd9s", + "col347": "h29ej", + "col348": "mfjna", + "col349": "zht2c", + "col350": "zzjnf", + "col351": "2e19u", + "col352": "lrwlr", + "col353": "gveom", + "col354": "n7mtq", + "col355": "ueoe3", + "col356": "0z4wx", + "col357": "l8xnt", + "col358": "2d3ak", + "col359": "bdwct", + "col360": "gn9e4", + "col361": "9qsds", + "col362": "ohyy7", + "col363": "rqxaf", + "col364": "40c40", + "col365": "xjw0m", + "col366": "2pglk", + "col367": "3es30", + "col368": "4fdn9", + "col369": "2fxoy", + "col370": "emlb9", + "col371": "aghoh", + "col372": "9wv92", + "col373": "pwh2j", + "col374": "9e1fq", + "col375": "tewwd", + "col376": "ghjv3", + "col377": "6flsn", + "col378": "y1x1d", + "col379": "g8jx4", + "col380": "clcuk", + "col381": "v7net", + "col382": "p80th", + "col383": "b7vap", + "col384": "3ytzf", + "col385": "70v0k", + "col386": "v2xpp", + "col387": "s9thr", + "col388": "ibgdi", + "col389": "dnfc4", + "col390": "1cb3p", + "col391": "s8pxi", + "col392": "ge1lb", + "col393": "9d6su", + "col394": "21pvv", + "col395": "twqhr", + "col396": "bgqft", + "col397": "oq8w9", + "col398": "jhwvo", + "col399": "mywyo", + "col400": "mhsf6", + "col401": "lwm0t", + "col402": "4gkpn", + "col403": "b9uy0", + "col404": "5meu8", + "col405": "n1wep", + "col406": "8wakk", + "col407": "b95pw", + "col408": "syhea", + "col409": "z8omg", + "col410": "ngop9", + "col411": "6cc8u", + "col412": "urk45", + "col413": "wcr8q", + "col414": "vzuwp", + "col415": "vhn78", + "col416": "g4f12", + "col417": "hxjr5", + "col418": "180zu", + "col419": "3qhfe", + "col420": "3spzy", + "col421": "gv79x", + "col422": "ptlce", + "col423": "8f0n3", + "col424": "i3ehq", + "col425": "bqb3s", + "col426": "h5hls", + "col427": "u4j53", + "col428": "fj5jv", + "col429": "l6jle", + "col430": "auhpt", + "col431": "5gibw", + "col432": "75xf8", + "col433": "z3nkv", + "col434": "ntmu7", + "col435": "1d7st", + "col436": "284v1", + "col437": "tucpy", + "col438": "ig4w0", + "col439": "1ygrp", + "col440": "tpuxr", + "col441": "kde7i", + "col442": "kb9pv", + "col443": "b4nry", + "col444": "llbur", + "col445": "m9c17", + "col446": "th8d0", + "col447": "0lfn0", + "col448": "kf5f7", + "col449": "szupq", + "col450": "zhmu6", + "col451": "lzjbx", + "col452": "moal8", + "col453": "tl7d4", + "col454": "5npwn", + "col455": "f1i31", + "col456": "s58bw", + "col457": "p3xzm", + "col458": "24syh", + "col459": "3mldb", + "col460": "go4gg", + "col461": "6bxa4", + "col462": "y2vf4", + "col463": "j40py", + "col464": "hko5r", + "col465": "eit29", + "col466": "3uafe", + "col467": "sdmkn", + "col468": "yz099", + "col469": "fwnx5", + "col470": "85362", + "col471": "ixlvk", + "col472": "n8e3u", + "col473": "2zwde", + "col474": "5wmvh", + "col475": "sq1xz", + "col476": "kri3d", + "col477": "kevcv", + "col478": "tp348", + "col479": "9z3kj", + "col480": "3hg30", + "col481": "tjbtj", + "col482": "pdzg5", + "col483": "77uyw", + "col484": "3svdd", + "col485": "dld00", + "col486": "kty17", + "col487": "gsfvs", + "col488": "98443", + "col489": "ehal1", + "col490": "h8irp", + "col491": "g59jq", + "col492": "ilev8", + "col493": "vral1", + "col494": "wbv1o", + "col495": "a2isw", + "col496": "hr1nd", + "col497": "loxb6", + "col498": "ri8mw", + "col499": "yqevr", + "col500": "ip3am", + "col501": "lwnjh", + "col502": "51if9", + "col503": "2pych", + "col504": "1xi6m", + "col505": "90l9y", + "col506": "3mpnp", + "col507": "jd3qy", + "col508": "kwy00", + "col509": "nq4mq", + "col510": "zsv9j", + "col511": "agdbe", + "col512": "95o1s", + "col513": "ujxm5", + "col514": "pnoz7", + "col515": "rg0si", + "col516": "519uh", + "col517": "pay17", + "col518": "02s1k", + "col519": "o94uy", + "col520": "fmv1z", + "col521": "4id2p", + "col522": "zi0nb", + "col523": "2f9n4", + "col524": "eeowz", + "col525": "hclm4", + "col526": "8firh", + "col527": "h6l23", + "col528": "09a88", + "col529": "rfn9d", + "col530": "7b9sb", + "col531": "ugchn", + "col532": "bpept", + "col533": "0wji5", + "col534": "jomwj", + "col535": "qp17n", + "col536": "8j6pt", + "col537": "ca82y", + "col538": "6epwt", + "col539": "pqfbw", + "col540": "pd11v", + "col541": "dairp", + "col542": "frr6d", + "col543": "jc8mv", + "col544": "68yd9", + "col545": "q4btd", + "col546": "ztuyq", + "col547": "ty6hv", + "col548": "ikqul", + "col549": "5s2zk", + "col550": "au9jp", + "col551": "m7bmm", + "col552": "vl1v3", + "col553": "9cxdz", + "col554": "rbmfa", + "col555": "e628x", + "col556": "3vfqz", + "col557": "0z200", + "col558": "jqily", + "col559": "39v13", + "col560": "3u3h0", + "col561": "wv4ux", + "col562": "m3gkv", + "col563": "guq58", + "col564": "qyquf", + "col565": "mo0zz", + "col566": "je2tr", + "col567": "0nic5", + "col568": "e591u", + "col569": "lwvoz", + "col570": "r4qm3", + "col571": "6iyz3", + "col572": "5dtum", + "col573": "swv0c", + "col574": "mlc2n", + "col575": "crywx", + "col576": "6kw60", + "col577": "x5cez", + "col578": "89604", + "col579": "q31iy", + "col580": "qx7sr", + "col581": "3blpc", + "col582": "wojyq", + "col583": "owgsy", + "col584": "6q7oa", + "col585": "y5fo5", + "col586": "sziz2", + "col587": "ikcsc", + "col588": "36x4v", + "col589": "txp12", + "col590": "x4bzt", + "col591": "wt5q8", + "col592": "1vfpf", + "col593": "xexxo", + "col594": "7of06", + "col595": "14iwu", + "col596": "y8xxr", + "col597": "e4kwz", + "col598": "txahj", + "col599": "stybg", + "col600": "urkjb", + "col601": "cnspz", + "col602": "1i07f", + "col603": "dpsiz", + "col604": "ppv0b", + "col605": "aw4hd", + "col606": "zawp3", + "col607": "lmkdo", + "col608": "8cqce", + "col609": "m4ese", + "col610": "lbg8q", + "col611": "7zjdd", + "col612": "2ub6r", + "col613": "xgwyp", + "col614": "irsrj", + "col615": "ylofy", + "col616": "8bg6s", + "col617": "is6gy", + "col618": "mdniu", + "col619": "pxb8e", + "col620": "ux3kr", + "col621": "ee97p", + "col622": "7x647", + "col623": "1yi8b", + "col624": "pwxqy", + "col625": "8mh5a", + "col626": "tufs2", + "col627": "vwrzs", + "col628": "ffb6z", + "col629": "ta2f7", + "col630": "byovr", + "col631": "d6l6r", + "col632": "fhga7", + "col633": "25ten", + "col634": "sxsop", + "col635": "uhdiz", + "col636": "zp0lz", + "col637": "ex3jp", + "col638": "lq406", + "col639": "gz7n2", + "col640": "ov1v9", + "col641": "s3xkx", + "col642": "2ge9y", + "col643": "cn7fi", + "col644": "gh5mv", + "col645": "1y4su", + "col646": "ckfa1", + "col647": "pyu9o", + "col648": "qnd7o", + "col649": "xmpev", + "col650": "ud8tb", + "col651": "3ofqf", + "col652": "jja3d", + "col653": "esgym", + "col654": "ax1xr", + "col655": "v07hc", + "col656": "9nhrq", + "col657": "fqr4z", + "col658": "cwx4p", + "col659": "j6hm8", + "col660": "lfpfu", + "col661": "kbi81", + "col662": "ldb1q", + "col663": "k1hez", + "col664": "2dcmi", + "col665": "ni0t6", + "col666": "y8xrr", + "col667": "7thvw", + "col668": "4ymrr", + "col669": "p7wb7", + "col670": "79xmf", + "col671": "iq855", + "col672": "xunjl", + "col673": "cv405", + "col674": "t8h8l", + "col675": "pbusy", + "col676": "5krpv", + "col677": "rqd8e", + "col678": "n8u2w", + "col679": "spp6o", + "col680": "evrtr", + "col681": "l7u5r", + "col682": "47iqa", + "col683": "eb1kt", + "col684": "bxrcc", + "col685": "ubxx3", + "col686": "t6l3i", + "col687": "5ymzq", + "col688": "8c73g", + "col689": "m6w1q", + "col690": "ij1p2", + "col691": "9e98z", + "col692": "wa54a", + "col693": "9m3vq", + "col694": "mk1fx", + "col695": "i06jc", + "col696": "hywm4", + "col697": "0b3pd", + "col698": "xjx9e", + "col699": "j8po9", + "col700": "ue19j", + "col701": "v4udf", + "col702": "gd6cr", + "col703": "vhvxg", + "col704": "y93sp", + "col705": "zwx9n", + "col706": "o4p1k", + "col707": "p47bv", + "col708": "kzs22", + "col709": "vmd6k", + "col710": "52lz4", + "col711": "k0d4g", + "col712": "46ulc", + "col713": "1pize", + "col714": "w9041", + "col715": "6b1qc", + "col716": "b79xz", + "col717": "y3yxa", + "col718": "jzqn8", + "col719": "a28gh", + "col720": "hsa0e", + "col721": "jh7c6", + "col722": "r7dn7", + "col723": "iw7im", + "col724": "394sv", + "col725": "s7hvp", + "col726": "qntp2", + "col727": "kncmo", + "col728": "7gk9c", + "col729": "ojhkc", + "col730": "iwzhv", + "col731": "s3c13", + "col732": "tk1wv", + "col733": "tge3u", + "col734": "0i0jx", + "col735": "lxqi6", + "col736": "cwpw5", + "col737": "ayoxt", + "col738": "m6wrl", + "col739": "av58o", + "col740": "cze3u", + "col741": "a0mem", + "col742": "9u3xl", + "col743": "11xsy", + "col744": "ifcyn", + "col745": "jekrd", + "col746": "jcsfq", + "col747": "vanmt", + "col748": "9un6z", + "col749": "fyrr7", + "col750": "cqccw", + "col751": "h6a2o", + "col752": "dbsbe", + "col753": "vcnwg", + "col754": "6g0gy", + "col755": "zhxbz", + "col756": "orugo", + "col757": "yp97r", + "col758": "qt2wr", + "col759": "8eg90", + "col760": "1uzzt", + "col761": "ddtec", + "col762": "ohlbo", + "col763": "80cu1", + "col764": "5ut13", + "col765": "cjl9k", + "col766": "bifpy", + "col767": "0oxjr", + "col768": "2422r", + "col769": "d114r", + "col770": "mqnaq", + "col771": "2l7xw", + "col772": "cc2kg", + "col773": "yvkwd", + "col774": "svqoc", + "col775": "eldjy", + "col776": "kwqi9", + "col777": "cgcfi", + "col778": "i07vs", + "col779": "obl8p", + "col780": "5avw6", + "col781": "e9i91", + "col782": "b9osj", + "col783": "yexy7", + "col784": "qu4qw", + "col785": "5c3b5", + "col786": "2prig", + "col787": "s2jfc", + "col788": "eihc2", + "col789": "07cwa", + "col790": "zxzhe", + "col791": "1m3ew", + "col792": "4zgk8", + "col793": "s4lh0", + "col794": "wmmtv", + "col795": "hm916", + "col796": "ddlzj", + "col797": "xzuco", + "col798": "uszeh", + "col799": "u87a7", + "col800": "9bov6", + "col801": "lmnym", + "col802": "ht379", + "col803": "esmiz", + "col804": "m44fe", + "col805": "0mhci", + "col806": "xte16", + "col807": "tbvtg", + "col808": "h3pqj", + "col809": "z0sdh", + "col810": "dn3s4", + "col811": "zfo2b", + "col812": "qyjoe", + "col813": "9ic2g", + "col814": "zbzbu", + "col815": "9uxi0", + "col816": "l5aeg", + "col817": "wf4w1", + "col818": "3y4lt", + "col819": "z17a6", + "col820": "4rkqj", + "col821": "dd2xb", + "col822": "ixary", + "col823": "li2tg", + "col824": "ic02z", + "col825": "apds1", + "col826": "mvedd", + "col827": "yzaa7", + "col828": "5vpn1", + "col829": "69nf0", + "col830": "09oey", + "col831": "956nl", + "col832": "wx9f2", + "col833": "7kg7h", + "col834": "pdq0l", + "col835": "h41yk", + "col836": "w3994", + "col837": "vlrc6", + "col838": "kzync", + "col839": "2cpjy", + "col840": "amzm0", + "col841": "9fe6r", + "col842": "8ntdx", + "col843": "5dj2y", + "col844": "qbl9w", + "col845": "bem8s", + "col846": "tp63f", + "col847": "0pgm6", + "col848": "noxs2", + "col849": "ouofz", + "col850": "6pwf0", + "col851": "f0uc5", + "col852": "59vc6", + "col853": "c5bch", + "col854": "05tw6", + "col855": "dd6qp", + "col856": "6qfr5", + "col857": "uu6ew", + "col858": "mxato", + "col859": "23gct", + "col860": "jii53", + "col861": "orok3", + "col862": "bwloa", + "col863": "jjcn2", + "col864": "h3314", + "col865": "qou0w", + "col866": "aeufj", + "col867": "anrba", + "col868": "s33jy", + "col869": "rcked", + "col870": "i53il", + "col871": "b89sc", + "col872": "zajxn", + "col873": "03lit", + "col874": "rixjk", + "col875": "ci1vw", + "col876": "y58t1", + "col877": "rb9cz", + "col878": "fdsyk", + "col879": "l4uay", + "col880": "qmgzr", + "col881": "kzgbu", + "col882": "cxhiy", + "col883": "15d63", + "col884": "pak3y", + "col885": "lrnh7", + "col886": "at2ob", + "col887": "qd4bv", + "col888": "ttkf7", + "col889": "4m6a3", + "col890": "ho24o", + "col891": "tweb0", + "col892": "u75cu", + "col893": "4j44z", + "col894": "xe0ml", + "col895": "75pe5", + "col896": "c04l6", + "col897": "raht4", + "col898": "ssqdd", + "col899": "optey", + "col900": "rwcue", + "col901": "ddavj", + "col902": "pa1kn", + "col903": "65rph", + "col904": "t7cfg", + "col905": "po9e1", + "col906": "52by8", + "col907": "qucrt", + "col908": "h4tzb", + "col909": "uh4hc", + "col910": "hfw5e", + "col911": "y2dw6", + "col912": "pryjv", + "col913": "vjg9m", + "col914": "msm2q", + "col915": "qywni", + "col916": "o88ip", + "col917": "8gfg6", + "col918": "9gf4w", + "col919": "ni4jd", + "col920": "hse4z", + "col921": "lhl0o", + "col922": "ll0fz", + "col923": "nlnmf", + "col924": "706c7", + "col925": "grliq", + "col926": "7e3kt", + "col927": "abftl", + "col928": "1s5iy", + "col929": "8hu3v", + "col930": "gtbms", + "col931": "rzklp", + "col932": "geee0", + "col933": "7gohe", + "col934": "y60f9", + "col935": "3t82n", + "col936": "z75l6", + "col937": "h4bmg", + "col938": "qc1uq", + "col939": "dmdun", + "col940": "o4nkx", + "col941": "8v0yy", + "col942": "3q7s9", + "col943": "8j7md", + "col944": "sgq1f", + "col945": "x7oef", + "col946": "o7rnp", + "col947": "lalfa", + "col948": "dywfc", + "col949": "x16uz", + "col950": "ivmlp", + "col951": "jcocr", + "col952": "pcvch", + "col953": "88a4e", + "col954": "griur", + "col955": "gzy9b", + "col956": "1dqch", + "col957": "ye9nr", + "col958": "6srt2", + "col959": "76mfb", + "col960": "j9ja1", + "col961": "roagd", + "col962": "4k827", + "col963": "ga8qj", + "col964": "w2vuy", + "col965": "s6q1m", + "col966": "o69l8", + "col967": "uli0k", + "col968": "y75xr", + "col969": "dxppa", + "col970": "vbav1", + "col971": "klm13", + "col972": "ugkmn", + "col973": "bxsxl", + "col974": "ttfqm", + "col975": "jw838", + "col976": "w76uh", + "col977": "leh2q", + "col978": "so5ib", + "col979": "iewnu", + "col980": "77wlr", + "col981": "8ild8", + "col982": "lbsyl", + "col983": "9w16b", + "col984": "ybye7", + "col985": "1tl7z", + "col986": "pfi5i", + "col987": "6cn97", + "col988": "qz0dd", + "col989": "0cbox", + "col990": "0cyqv", + "col991": "f8fse", + "col992": "vx8eh", + "col993": "q7t1p", + "col994": "h573i", + "col995": "a18bh", + "col996": "t57uo", + "col997": "bs41w", + "col998": "v5g3u", + "col999": "vu1zj" + }, + { + "name": "Roberts Strong", + "gender": "male", + "col0": "eilm5", + "col1": "x090t", + "col2": "zc4rz", + "col3": "4mw7w", + "col4": "757og", + "col5": "k3nvf", + "col6": "4zcqq", + "col7": "u0186", + "col8": "f08sz", + "col9": "20geb", + "col10": "3kx89", + "col11": "e0roe", + "col12": "75t1y", + "col13": "utuxy", + "col14": "ywvid", + "col15": "xgt20", + "col16": "qxv3v", + "col17": "hn50b", + "col18": "8wiqk", + "col19": "752xy", + "col20": "ahapi", + "col21": "pvnqz", + "col22": "hgikb", + "col23": "jycdr", + "col24": "so4to", + "col25": "0fzfg", + "col26": "brfa7", + "col27": "sgc43", + "col28": "5twws", + "col29": "b3ibg", + "col30": "m9xd9", + "col31": "r4xc4", + "col32": "exeze", + "col33": "sev3s", + "col34": "yzg2u", + "col35": "vnefd", + "col36": "8hybt", + "col37": "0tjps", + "col38": "7kp1m", + "col39": "uivsy", + "col40": "amyck", + "col41": "fn1jz", + "col42": "0ma9f", + "col43": "nphnz", + "col44": "6z362", + "col45": "27rwr", + "col46": "mc0cl", + "col47": "m2g3h", + "col48": "tg4pq", + "col49": "jg93w", + "col50": "43nlq", + "col51": "ukzzl", + "col52": "nrv0q", + "col53": "z86ya", + "col54": "d1g1s", + "col55": "46i7y", + "col56": "94i9a", + "col57": "z60d3", + "col58": "9wnqs", + "col59": "1wl5c", + "col60": "otd8p", + "col61": "drgj3", + "col62": "bdtbe", + "col63": "859b9", + "col64": "uzrbl", + "col65": "9xqbr", + "col66": "ctaiy", + "col67": "rkqdy", + "col68": "qyq3s", + "col69": "kmxn1", + "col70": "ka3uy", + "col71": "50qau", + "col72": "hpemj", + "col73": "54e8h", + "col74": "wxpf2", + "col75": "3qu0d", + "col76": "xe5ef", + "col77": "uarpn", + "col78": "mbjsw", + "col79": "f137f", + "col80": "jke6q", + "col81": "cgod2", + "col82": "y8eij", + "col83": "fu5lz", + "col84": "t5hi0", + "col85": "scwsd", + "col86": "m8mw8", + "col87": "ozouk", + "col88": "hg3fx", + "col89": "owxop", + "col90": "eu6hs", + "col91": "hjk6p", + "col92": "r7xbv", + "col93": "nyeij", + "col94": "ga6aj", + "col95": "zugxc", + "col96": "lwh70", + "col97": "4wfg6", + "col98": "uyskb", + "col99": "v830m", + "col100": "46yte", + "col101": "lj67d", + "col102": "0c0hn", + "col103": "zt1vo", + "col104": "tssnm", + "col105": "vut09", + "col106": "4l9tc", + "col107": "egq2a", + "col108": "acdae", + "col109": "cjkdu", + "col110": "2q5f2", + "col111": "jun6n", + "col112": "3lfsk", + "col113": "hxotr", + "col114": "iktab", + "col115": "1k9g1", + "col116": "hp3wl", + "col117": "54dal", + "col118": "kdv0i", + "col119": "jx93c", + "col120": "wgyjx", + "col121": "ok636", + "col122": "tr6wa", + "col123": "a6fdi", + "col124": "yj0m4", + "col125": "nuv78", + "col126": "gk6ea", + "col127": "xusxf", + "col128": "0hhme", + "col129": "z4k7n", + "col130": "n7zdr", + "col131": "nmkri", + "col132": "3pcqs", + "col133": "ix23y", + "col134": "bdjim", + "col135": "plppo", + "col136": "8rk2e", + "col137": "oyq1a", + "col138": "pudng", + "col139": "ym4i2", + "col140": "k4ypd", + "col141": "c2iun", + "col142": "bfi07", + "col143": "ud3l4", + "col144": "6r47q", + "col145": "6tk0t", + "col146": "ieatm", + "col147": "82nh6", + "col148": "bi6ji", + "col149": "hz442", + "col150": "8fs84", + "col151": "xyk33", + "col152": "2e7wo", + "col153": "8kg6m", + "col154": "2ffb7", + "col155": "p8iud", + "col156": "19kaz", + "col157": "k5uik", + "col158": "tzrih", + "col159": "u8nv1", + "col160": "yvdp7", + "col161": "nxj6a", + "col162": "tp992", + "col163": "0tmjz", + "col164": "sjlj4", + "col165": "fjha6", + "col166": "ttc6d", + "col167": "47aqr", + "col168": "vuu8a", + "col169": "4zap3", + "col170": "x9zbn", + "col171": "y6qw1", + "col172": "meg4r", + "col173": "x7si4", + "col174": "zug1z", + "col175": "e2q06", + "col176": "bx8fx", + "col177": "nsq7y", + "col178": "iqlb6", + "col179": "vlvqp", + "col180": "kk3h0", + "col181": "inu85", + "col182": "l1cdx", + "col183": "sact7", + "col184": "w0xkj", + "col185": "7ankt", + "col186": "jgzov", + "col187": "gugxv", + "col188": "lb5qv", + "col189": "2gjey", + "col190": "3zqig", + "col191": "av09k", + "col192": "h67jj", + "col193": "7sbky", + "col194": "1jl6u", + "col195": "hhf4g", + "col196": "jg37p", + "col197": "7iqis", + "col198": "8yzbe", + "col199": "u0abl", + "col200": "7mj7g", + "col201": "q4ku4", + "col202": "homzp", + "col203": "d11mq", + "col204": "4hx2b", + "col205": "jwnod", + "col206": "mftju", + "col207": "4ccqx", + "col208": "xeguz", + "col209": "8k3er", + "col210": "ae8xc", + "col211": "pyq4b", + "col212": "6u66f", + "col213": "ydh4l", + "col214": "mw115", + "col215": "q8kue", + "col216": "01zly", + "col217": "32yvg", + "col218": "29fot", + "col219": "2x3j3", + "col220": "jqcz9", + "col221": "6f53v", + "col222": "mlmi7", + "col223": "n3ura", + "col224": "uc8vq", + "col225": "qbcec", + "col226": "oclb1", + "col227": "80ek7", + "col228": "ch66s", + "col229": "tycre", + "col230": "zf9o3", + "col231": "vp5ye", + "col232": "5cl1y", + "col233": "0i2mr", + "col234": "odspr", + "col235": "08sdn", + "col236": "hydi7", + "col237": "hcvwn", + "col238": "3fpi6", + "col239": "wcv1u", + "col240": "6prii", + "col241": "du2ai", + "col242": "f8d5o", + "col243": "t0qpi", + "col244": "56w8j", + "col245": "4u213", + "col246": "rcpqn", + "col247": "419h1", + "col248": "onyem", + "col249": "fypv1", + "col250": "05x60", + "col251": "sm7bx", + "col252": "id7bi", + "col253": "kih19", + "col254": "ccpk7", + "col255": "tjv7s", + "col256": "j9wki", + "col257": "13l8l", + "col258": "dmw8m", + "col259": "q2j7v", + "col260": "b1oc5", + "col261": "bzcr9", + "col262": "gzedy", + "col263": "eissi", + "col264": "nr4br", + "col265": "jcs8s", + "col266": "exxpe", + "col267": "z81y2", + "col268": "hc0xo", + "col269": "6zomm", + "col270": "3j34r", + "col271": "ry0sk", + "col272": "1ol7w", + "col273": "p2cfe", + "col274": "wadgn", + "col275": "2ze6b", + "col276": "hvxqp", + "col277": "9zzir", + "col278": "revic", + "col279": "jkv7v", + "col280": "eut8z", + "col281": "7dgm1", + "col282": "51vda", + "col283": "a941o", + "col284": "h8eko", + "col285": "j7ngh", + "col286": "0cooq", + "col287": "gfus1", + "col288": "43yhb", + "col289": "0b4yd", + "col290": "is68x", + "col291": "u6n1b", + "col292": "zz913", + "col293": "9eess", + "col294": "4fft4", + "col295": "qp4uq", + "col296": "iguek", + "col297": "icym9", + "col298": "hs0td", + "col299": "bulgn", + "col300": "u7vvz", + "col301": "ycco6", + "col302": "ur3a4", + "col303": "palr2", + "col304": "6kjok", + "col305": "av7ch", + "col306": "08a13", + "col307": "pa5nt", + "col308": "e692o", + "col309": "0p83s", + "col310": "1w4ff", + "col311": "2d4g9", + "col312": "l1mke", + "col313": "bvfge", + "col314": "7amp4", + "col315": "ivd3n", + "col316": "zq1mc", + "col317": "l8svd", + "col318": "lbfia", + "col319": "7qqk4", + "col320": "02zay", + "col321": "ybf6n", + "col322": "q3xh6", + "col323": "rx6ps", + "col324": "ybjjd", + "col325": "olu33", + "col326": "wvzam", + "col327": "2evaa", + "col328": "vfnvx", + "col329": "179w1", + "col330": "9irdv", + "col331": "c1af3", + "col332": "kpxki", + "col333": "28mg3", + "col334": "y6ihr", + "col335": "8togk", + "col336": "gd7zc", + "col337": "0ye78", + "col338": "3fghr", + "col339": "pdcnm", + "col340": "g5das", + "col341": "z1to2", + "col342": "fese2", + "col343": "8mnvs", + "col344": "6qvfx", + "col345": "ob2xe", + "col346": "frnsc", + "col347": "i9ej5", + "col348": "cr8z1", + "col349": "ll05u", + "col350": "l60sz", + "col351": "dlcu8", + "col352": "s6kvf", + "col353": "n9lp9", + "col354": "lsr42", + "col355": "hak1v", + "col356": "i3pky", + "col357": "i9dm5", + "col358": "5von6", + "col359": "u2tm6", + "col360": "vl2my", + "col361": "vmpv1", + "col362": "ommpf", + "col363": "967dz", + "col364": "u2hxk", + "col365": "xgsuy", + "col366": "ulvww", + "col367": "d58b0", + "col368": "yo5m3", + "col369": "owrvv", + "col370": "r9fyy", + "col371": "4edjm", + "col372": "tn93p", + "col373": "0h7ua", + "col374": "izp0j", + "col375": "xk8dg", + "col376": "si9n5", + "col377": "b1vss", + "col378": "ckd6o", + "col379": "v0jz7", + "col380": "qpqtt", + "col381": "qgolu", + "col382": "xi8fr", + "col383": "wbaq8", + "col384": "1ksf0", + "col385": "ekybg", + "col386": "q198h", + "col387": "hrnhr", + "col388": "5s7n4", + "col389": "ttlcd", + "col390": "y0c7x", + "col391": "bqvu0", + "col392": "m69os", + "col393": "ralcg", + "col394": "kq55c", + "col395": "nyqg7", + "col396": "njo5y", + "col397": "mt5sy", + "col398": "l67sr", + "col399": "du77g", + "col400": "wl03i", + "col401": "ijq7j", + "col402": "6zoli", + "col403": "mayo7", + "col404": "xwtmz", + "col405": "my1wa", + "col406": "ihwi4", + "col407": "vw78b", + "col408": "96381", + "col409": "7vchc", + "col410": "d1cxt", + "col411": "id3j0", + "col412": "c0pjf", + "col413": "pz9wh", + "col414": "5d18f", + "col415": "qbkd4", + "col416": "gf6yo", + "col417": "mjidi", + "col418": "dfkyh", + "col419": "61ifv", + "col420": "wtlev", + "col421": "o8t03", + "col422": "ao7pd", + "col423": "y9fp6", + "col424": "kqzrh", + "col425": "qe7d3", + "col426": "b68r7", + "col427": "j8s2x", + "col428": "sas29", + "col429": "cwemd", + "col430": "ipy7s", + "col431": "hy7md", + "col432": "4665k", + "col433": "rdr1f", + "col434": "ea3fk", + "col435": "kil25", + "col436": "wxh5h", + "col437": "x86ul", + "col438": "q1jzh", + "col439": "g47re", + "col440": "y2pe7", + "col441": "9dyyv", + "col442": "chfq2", + "col443": "dg7x7", + "col444": "2y7q4", + "col445": "izw8x", + "col446": "gl8hv", + "col447": "r084i", + "col448": "5edyp", + "col449": "2kzco", + "col450": "v1r3i", + "col451": "qqkzj", + "col452": "g1ynq", + "col453": "qx2f1", + "col454": "4rr4u", + "col455": "g0wr1", + "col456": "5ceza", + "col457": "ba7ug", + "col458": "z0pm5", + "col459": "xtx7l", + "col460": "djg7a", + "col461": "lnvzj", + "col462": "de6bo", + "col463": "s6eqd", + "col464": "wh55b", + "col465": "rmuzg", + "col466": "ajv9z", + "col467": "zgx50", + "col468": "kib8f", + "col469": "h7u6o", + "col470": "nzzp4", + "col471": "byiw6", + "col472": "fye7s", + "col473": "7mdu2", + "col474": "ixdhj", + "col475": "o1vot", + "col476": "qmw0w", + "col477": "o473i", + "col478": "f6vku", + "col479": "wjxpy", + "col480": "jedlv", + "col481": "zxspk", + "col482": "4jtkp", + "col483": "fegbi", + "col484": "h0fwd", + "col485": "choct", + "col486": "5fxh0", + "col487": "4j4kl", + "col488": "0itri", + "col489": "9l4xi", + "col490": "asrzs", + "col491": "aikym", + "col492": "nth0p", + "col493": "r880x", + "col494": "m8ep2", + "col495": "unoj9", + "col496": "nfw7c", + "col497": "2xpwq", + "col498": "sq7q5", + "col499": "n7v4g", + "col500": "7nkdj", + "col501": "8p9fe", + "col502": "52zz9", + "col503": "jbfbp", + "col504": "w4ajc", + "col505": "asty8", + "col506": "1qoqj", + "col507": "jbzow", + "col508": "dc52r", + "col509": "u4ebx", + "col510": "662om", + "col511": "64xbs", + "col512": "kvl5o", + "col513": "1eh31", + "col514": "8d0n5", + "col515": "d0cm2", + "col516": "unkr3", + "col517": "1ntc9", + "col518": "4e1zj", + "col519": "0vw3f", + "col520": "vchrh", + "col521": "fmajv", + "col522": "vv9rs", + "col523": "czq9d", + "col524": "405sg", + "col525": "b3k67", + "col526": "sfcol", + "col527": "kb6mm", + "col528": "47gnu", + "col529": "hfj7h", + "col530": "7mq9p", + "col531": "sesvh", + "col532": "7ure4", + "col533": "fb7a1", + "col534": "f7jrl", + "col535": "qfogk", + "col536": "1fmj8", + "col537": "l43ko", + "col538": "wa9cb", + "col539": "ok5gu", + "col540": "m6bie", + "col541": "tzxzh", + "col542": "fndb5", + "col543": "p4mue", + "col544": "7j6f4", + "col545": "0bsd3", + "col546": "efl4h", + "col547": "0gltw", + "col548": "hjlg2", + "col549": "wdrne", + "col550": "a9p0y", + "col551": "mxcj6", + "col552": "d25pl", + "col553": "pk64a", + "col554": "fsdaz", + "col555": "uvehn", + "col556": "x9vbi", + "col557": "4mtlg", + "col558": "8b2wp", + "col559": "zplgc", + "col560": "yex7o", + "col561": "v54s6", + "col562": "e0hkh", + "col563": "scw7y", + "col564": "gdnbp", + "col565": "jmk5p", + "col566": "tg8xl", + "col567": "9i7ek", + "col568": "bswix", + "col569": "v6lk9", + "col570": "cxjcu", + "col571": "lk44t", + "col572": "mgqzc", + "col573": "tim8y", + "col574": "z7p3w", + "col575": "aohey", + "col576": "rym6a", + "col577": "z8nyc", + "col578": "5mctq", + "col579": "fjo4c", + "col580": "ib5id", + "col581": "9fa57", + "col582": "wm22g", + "col583": "6svq1", + "col584": "dcgsu", + "col585": "h9nzf", + "col586": "bz3nm", + "col587": "yqidf", + "col588": "u73r9", + "col589": "1q7xj", + "col590": "naha9", + "col591": "34un0", + "col592": "5dj8g", + "col593": "wb5nu", + "col594": "6dksw", + "col595": "5219e", + "col596": "ewdea", + "col597": "k82x5", + "col598": "b144q", + "col599": "jt0zw", + "col600": "uwdai", + "col601": "76n25", + "col602": "shqz1", + "col603": "rcaza", + "col604": "o8igq", + "col605": "hmvsv", + "col606": "gn2vi", + "col607": "lmaha", + "col608": "443o7", + "col609": "fxvcy", + "col610": "ty2a9", + "col611": "1cq49", + "col612": "2hatw", + "col613": "1fcr1", + "col614": "5cycz", + "col615": "ctc9c", + "col616": "1z73j", + "col617": "q4iow", + "col618": "b3a0x", + "col619": "hzqr2", + "col620": "nyn28", + "col621": "so4y0", + "col622": "gm88p", + "col623": "wlppr", + "col624": "4r4ra", + "col625": "vb74q", + "col626": "osn7l", + "col627": "0j4e0", + "col628": "6qv1g", + "col629": "h14je", + "col630": "8x7bh", + "col631": "uws2t", + "col632": "vk8e3", + "col633": "6a4o0", + "col634": "jscmd", + "col635": "i6i82", + "col636": "1sl05", + "col637": "d07z5", + "col638": "73xaf", + "col639": "ius3q", + "col640": "p1tmc", + "col641": "n2vwq", + "col642": "klbgw", + "col643": "qm9j3", + "col644": "a0ukg", + "col645": "lxulr", + "col646": "6apvr", + "col647": "lu6di", + "col648": "7qumz", + "col649": "g23ue", + "col650": "3ylgw", + "col651": "fzxg2", + "col652": "78is2", + "col653": "axpqf", + "col654": "xmsfr", + "col655": "gq0dz", + "col656": "25ttm", + "col657": "vskwk", + "col658": "onypu", + "col659": "59o8c", + "col660": "z09gb", + "col661": "c9qkb", + "col662": "9txfx", + "col663": "1rypc", + "col664": "ihqc3", + "col665": "co8qc", + "col666": "lc7ai", + "col667": "fviuv", + "col668": "xab3m", + "col669": "kc66i", + "col670": "qwadt", + "col671": "kj8dr", + "col672": "56l2m", + "col673": "vwk3a", + "col674": "tl5lz", + "col675": "o5na9", + "col676": "3o30s", + "col677": "r5xmb", + "col678": "u7i0f", + "col679": "zfb3n", + "col680": "hhfyj", + "col681": "khxyp", + "col682": "gjkad", + "col683": "ttrtg", + "col684": "4ahpa", + "col685": "6z7hr", + "col686": "njc41", + "col687": "ljmnn", + "col688": "fko6u", + "col689": "zotrf", + "col690": "pwxom", + "col691": "d0bl6", + "col692": "s0rtu", + "col693": "am7d2", + "col694": "624r5", + "col695": "t8poi", + "col696": "ktrzy", + "col697": "zfomu", + "col698": "n2r6z", + "col699": "1rt2i", + "col700": "1c3z9", + "col701": "6l89o", + "col702": "klj5h", + "col703": "ofno2", + "col704": "3clr1", + "col705": "tvd8g", + "col706": "88x3k", + "col707": "a7k1t", + "col708": "741x6", + "col709": "gc7dx", + "col710": "njcq7", + "col711": "gmmuu", + "col712": "8eaqz", + "col713": "8ae0m", + "col714": "6xkz2", + "col715": "m1bo8", + "col716": "31ncn", + "col717": "real6", + "col718": "pgf2l", + "col719": "i4dbt", + "col720": "uadw6", + "col721": "wfucn", + "col722": "0bood", + "col723": "pmel7", + "col724": "yn5ot", + "col725": "x0idw", + "col726": "oxfo5", + "col727": "albhc", + "col728": "dz0q9", + "col729": "utjth", + "col730": "9awqn", + "col731": "lb2fr", + "col732": "yppzk", + "col733": "os5au", + "col734": "7k2xu", + "col735": "rga9v", + "col736": "glaxm", + "col737": "xigxk", + "col738": "q392p", + "col739": "lbkmp", + "col740": "txuig", + "col741": "5gi39", + "col742": "ne5n9", + "col743": "bq733", + "col744": "rw9p2", + "col745": "y2gya", + "col746": "ubyn9", + "col747": "9e2sd", + "col748": "s51x5", + "col749": "v5o7w", + "col750": "nr5aa", + "col751": "virti", + "col752": "mimmp", + "col753": "bd2fy", + "col754": "wolx0", + "col755": "678c0", + "col756": "24na5", + "col757": "f5aiv", + "col758": "zhixb", + "col759": "re1g2", + "col760": "ylfk3", + "col761": "lpzi0", + "col762": "vq67r", + "col763": "8kymz", + "col764": "ols2l", + "col765": "o2jbq", + "col766": "hw72r", + "col767": "mg0kj", + "col768": "4jyq6", + "col769": "jxuj4", + "col770": "2oewg", + "col771": "njjl7", + "col772": "06c7a", + "col773": "22god", + "col774": "kb09q", + "col775": "b52qk", + "col776": "ytb6f", + "col777": "aajpw", + "col778": "i7fvs", + "col779": "0eplt", + "col780": "gy0w7", + "col781": "xoejk", + "col782": "3g37o", + "col783": "j5ht0", + "col784": "avj0m", + "col785": "mum49", + "col786": "tir4k", + "col787": "hnsb6", + "col788": "zaqkg", + "col789": "wrz1e", + "col790": "bcnpg", + "col791": "hau8n", + "col792": "mme8l", + "col793": "0nyvg", + "col794": "hd5id", + "col795": "05syt", + "col796": "wdxon", + "col797": "g8cw8", + "col798": "tsek0", + "col799": "y47vk", + "col800": "p2wkl", + "col801": "jbuhc", + "col802": "o38dc", + "col803": "rtf4a", + "col804": "spr05", + "col805": "kb4zc", + "col806": "col2a", + "col807": "437lm", + "col808": "8t8sq", + "col809": "aodx7", + "col810": "oue4d", + "col811": "vnojl", + "col812": "s5s6g", + "col813": "pb14b", + "col814": "359sh", + "col815": "0q8t7", + "col816": "1pw5d", + "col817": "b0o9s", + "col818": "9tgq0", + "col819": "e5z2e", + "col820": "ian4y", + "col821": "u689b", + "col822": "51wnc", + "col823": "87obr", + "col824": "lfb3s", + "col825": "e2nm1", + "col826": "yqg29", + "col827": "41oj4", + "col828": "bh3qu", + "col829": "4s400", + "col830": "ewnbu", + "col831": "go9ku", + "col832": "sokwa", + "col833": "qxxcc", + "col834": "af7se", + "col835": "3vp1p", + "col836": "krxoi", + "col837": "zvpl9", + "col838": "f20oc", + "col839": "ekhkb", + "col840": "oyo1h", + "col841": "4vmm4", + "col842": "b98u7", + "col843": "b1lok", + "col844": "w68l5", + "col845": "f5y0j", + "col846": "ni254", + "col847": "6u0hc", + "col848": "6y988", + "col849": "fgieg", + "col850": "hlkr6", + "col851": "uosq7", + "col852": "j5ubr", + "col853": "y7eik", + "col854": "uq8sn", + "col855": "viuz1", + "col856": "sm1rt", + "col857": "yqdxl", + "col858": "32xxl", + "col859": "fb5ew", + "col860": "1byxx", + "col861": "pillt", + "col862": "o383p", + "col863": "r175o", + "col864": "kfhct", + "col865": "yjckm", + "col866": "2asy5", + "col867": "g4ym3", + "col868": "kevbe", + "col869": "8bx7b", + "col870": "drlmd", + "col871": "f37l2", + "col872": "r4v87", + "col873": "7wn1e", + "col874": "cgf25", + "col875": "xl6jr", + "col876": "9idq4", + "col877": "vakns", + "col878": "5gqw5", + "col879": "a9dlf", + "col880": "gduzz", + "col881": "3kubx", + "col882": "8uxhh", + "col883": "9rusv", + "col884": "0wrun", + "col885": "6i4lf", + "col886": "q229l", + "col887": "k5kbx", + "col888": "wunin", + "col889": "7mlqg", + "col890": "q1u20", + "col891": "5i90t", + "col892": "i64y3", + "col893": "zn6r9", + "col894": "83k5q", + "col895": "2inhq", + "col896": "1v8ok", + "col897": "bncsq", + "col898": "t0lal", + "col899": "ih2tf", + "col900": "i1ljz", + "col901": "r2jbs", + "col902": "9rz43", + "col903": "rpcen", + "col904": "rehuc", + "col905": "c5qb4", + "col906": "8ndv0", + "col907": "6bszm", + "col908": "2lm36", + "col909": "yee1h", + "col910": "kgin8", + "col911": "2mgm4", + "col912": "jixih", + "col913": "w95or", + "col914": "ek23b", + "col915": "psqv8", + "col916": "y45wq", + "col917": "yvhho", + "col918": "87um8", + "col919": "zj6j3", + "col920": "h64o8", + "col921": "3ur7a", + "col922": "ahozf", + "col923": "ra4m5", + "col924": "a4s5l", + "col925": "3m91h", + "col926": "4t2r0", + "col927": "32j0j", + "col928": "w90mu", + "col929": "971un", + "col930": "grbji", + "col931": "ccbp8", + "col932": "a9c98", + "col933": "arvsf", + "col934": "by8u4", + "col935": "xb3ev", + "col936": "25w79", + "col937": "4kg54", + "col938": "i8v6u", + "col939": "6jk1c", + "col940": "5zxy7", + "col941": "qjrx3", + "col942": "h4tq6", + "col943": "ue579", + "col944": "nsial", + "col945": "ggc8a", + "col946": "2257x", + "col947": "t6o9x", + "col948": "6dr51", + "col949": "hi7fl", + "col950": "adkag", + "col951": "sqv3h", + "col952": "cglad", + "col953": "1nsvg", + "col954": "zbgmh", + "col955": "735r5", + "col956": "g6wo5", + "col957": "4yt3z", + "col958": "oy7tx", + "col959": "89z0r", + "col960": "0ty0s", + "col961": "4tc2p", + "col962": "9q6ol", + "col963": "akx7m", + "col964": "wicko", + "col965": "4lbig", + "col966": "gadch", + "col967": "wuz7v", + "col968": "ma8dz", + "col969": "lc1bz", + "col970": "crio3", + "col971": "iyv1z", + "col972": "tu6vs", + "col973": "mcdsh", + "col974": "9i4ap", + "col975": "vmqph", + "col976": "k43hg", + "col977": "439jc", + "col978": "fwig4", + "col979": "19kb6", + "col980": "456g8", + "col981": "tv6te", + "col982": "b2pf6", + "col983": "fxwal", + "col984": "fymze", + "col985": "l6mfo", + "col986": "6pxvu", + "col987": "33f7j", + "col988": "vj7hh", + "col989": "35fmc", + "col990": "8997c", + "col991": "bu11c", + "col992": "jg9yn", + "col993": "lrwzq", + "col994": "vo0m3", + "col995": "uhqy2", + "col996": "3n569", + "col997": "533gn", + "col998": "w3ebz", + "col999": "d3jz3" + }, + { + "name": "Wyatt Ryan", + "gender": "male", + "col0": "ce4ss", + "col1": "k5oui", + "col2": "tta5c", + "col3": "lewyg", + "col4": "ubnur", + "col5": "zaosj", + "col6": "3orkz", + "col7": "whsg4", + "col8": "h576z", + "col9": "6rmkz", + "col10": "zke2f", + "col11": "ol7si", + "col12": "f340g", + "col13": "v0r5c", + "col14": "jskxr", + "col15": "u037u", + "col16": "d8zkg", + "col17": "8k94b", + "col18": "d2syh", + "col19": "2u1tp", + "col20": "4ve7m", + "col21": "a7883", + "col22": "74toi", + "col23": "jc0re", + "col24": "hcl6j", + "col25": "pq723", + "col26": "7kb0c", + "col27": "z5dc3", + "col28": "78xmw", + "col29": "l3qit", + "col30": "4r7og", + "col31": "dtkh9", + "col32": "krho0", + "col33": "w6ksm", + "col34": "ijwkz", + "col35": "z96ps", + "col36": "r189v", + "col37": "azwaz", + "col38": "osaad", + "col39": "486g7", + "col40": "z3azv", + "col41": "rcfvh", + "col42": "gta71", + "col43": "y437x", + "col44": "uq6ej", + "col45": "dxk0t", + "col46": "13mxb", + "col47": "vcpfv", + "col48": "76pdd", + "col49": "lv51c", + "col50": "kxky0", + "col51": "j49tf", + "col52": "phqpk", + "col53": "6uh1q", + "col54": "7bezx", + "col55": "fg4la", + "col56": "c03ty", + "col57": "w43hn", + "col58": "m9snc", + "col59": "enmu4", + "col60": "qezfj", + "col61": "cgy71", + "col62": "j98ol", + "col63": "2ibqs", + "col64": "6t5zn", + "col65": "3zn5d", + "col66": "dt63n", + "col67": "hczz8", + "col68": "vix9j", + "col69": "y1y2w", + "col70": "jutdm", + "col71": "zoszb", + "col72": "jkwpm", + "col73": "3qyzt", + "col74": "5clt6", + "col75": "noutq", + "col76": "3k5kk", + "col77": "ymuzz", + "col78": "pbfjk", + "col79": "s7qho", + "col80": "6ramo", + "col81": "eitgp", + "col82": "neu5e", + "col83": "3xi2u", + "col84": "3gtpa", + "col85": "77188", + "col86": "knjpj", + "col87": "4g2bs", + "col88": "wxegz", + "col89": "h2ezt", + "col90": "povo6", + "col91": "yvxr1", + "col92": "xa66v", + "col93": "etqii", + "col94": "6net6", + "col95": "hirsy", + "col96": "vz9ux", + "col97": "u5e3j", + "col98": "z7kon", + "col99": "97rgf", + "col100": "816me", + "col101": "68g1u", + "col102": "32xeg", + "col103": "wgh48", + "col104": "ievrz", + "col105": "uuzxr", + "col106": "0pfag", + "col107": "yx6d8", + "col108": "aotjv", + "col109": "qwy80", + "col110": "z4jdf", + "col111": "nxi32", + "col112": "or5va", + "col113": "rlzu4", + "col114": "tq15a", + "col115": "i9cua", + "col116": "rjwb2", + "col117": "hyiis", + "col118": "fphs0", + "col119": "ib8h0", + "col120": "dmb2c", + "col121": "k8z9i", + "col122": "jgptd", + "col123": "dw5tk", + "col124": "rvfrf", + "col125": "blno0", + "col126": "yiqdb", + "col127": "mph5t", + "col128": "0r90q", + "col129": "u5efu", + "col130": "n4myg", + "col131": "cuulm", + "col132": "ba9uv", + "col133": "dnrot", + "col134": "clurb", + "col135": "tfp7j", + "col136": "peegm", + "col137": "mx88n", + "col138": "litsh", + "col139": "zuxwc", + "col140": "mb095", + "col141": "l0mon", + "col142": "4httc", + "col143": "qdq4c", + "col144": "f8835", + "col145": "lpizz", + "col146": "ovkw9", + "col147": "2eq6b", + "col148": "zygf1", + "col149": "3ofde", + "col150": "l3dt1", + "col151": "fmnav", + "col152": "is4oo", + "col153": "9d04q", + "col154": "bz97u", + "col155": "ps0if", + "col156": "byqd3", + "col157": "qe8k4", + "col158": "dqro4", + "col159": "xx6b3", + "col160": "8ow6r", + "col161": "u5v1n", + "col162": "rnrp3", + "col163": "1zxkt", + "col164": "gkavb", + "col165": "2kkwt", + "col166": "ea0ef", + "col167": "4fftc", + "col168": "pjq9c", + "col169": "v4xxc", + "col170": "t7cc0", + "col171": "z5ass", + "col172": "rkbdb", + "col173": "ey3o6", + "col174": "hcaqb", + "col175": "pgtz7", + "col176": "grnun", + "col177": "k2e8m", + "col178": "zu73f", + "col179": "vg6lm", + "col180": "rwadp", + "col181": "snvds", + "col182": "dnpd4", + "col183": "asg34", + "col184": "niq1l", + "col185": "cuumv", + "col186": "8vuao", + "col187": "dmcba", + "col188": "wog1s", + "col189": "oho2z", + "col190": "k1tjf", + "col191": "ur09f", + "col192": "n1mjg", + "col193": "lvv0b", + "col194": "bnjpn", + "col195": "vzrz2", + "col196": "gjsjx", + "col197": "7ud8n", + "col198": "76a47", + "col199": "vfa92", + "col200": "msmkn", + "col201": "6v3s9", + "col202": "3rp09", + "col203": "2afap", + "col204": "60h9x", + "col205": "qtc1x", + "col206": "7u1yi", + "col207": "skds1", + "col208": "0f1pj", + "col209": "zkgi0", + "col210": "1vjdv", + "col211": "yyfzk", + "col212": "xwb9b", + "col213": "ch5uj", + "col214": "b7jll", + "col215": "tujqu", + "col216": "fu737", + "col217": "13kbz", + "col218": "55fbb", + "col219": "fa4yf", + "col220": "40wzx", + "col221": "26qo5", + "col222": "jh61c", + "col223": "09swt", + "col224": "4fhqq", + "col225": "na8dn", + "col226": "oxg6e", + "col227": "2uyag", + "col228": "zedhc", + "col229": "m0i76", + "col230": "ahtho", + "col231": "pl8yv", + "col232": "r57bx", + "col233": "rfp54", + "col234": "yvuxv", + "col235": "1597g", + "col236": "or6gr", + "col237": "fddpo", + "col238": "pmppp", + "col239": "ucgxr", + "col240": "g0lyt", + "col241": "5wsdk", + "col242": "plkwt", + "col243": "j0kl6", + "col244": "z5zti", + "col245": "8iiks", + "col246": "9wv44", + "col247": "cta8i", + "col248": "u2u9x", + "col249": "v0cgg", + "col250": "e4jdn", + "col251": "gh3si", + "col252": "88wqm", + "col253": "6h0pk", + "col254": "b0ill", + "col255": "sszw4", + "col256": "5srag", + "col257": "50dgf", + "col258": "s1p75", + "col259": "i1kq5", + "col260": "jp9sq", + "col261": "63e6p", + "col262": "2qdjc", + "col263": "fg4gz", + "col264": "n9sqz", + "col265": "i5h78", + "col266": "zv3xy", + "col267": "yompy", + "col268": "br1tx", + "col269": "4p7g0", + "col270": "fg2ig", + "col271": "3quju", + "col272": "nhzcl", + "col273": "myb25", + "col274": "2yaqy", + "col275": "qny14", + "col276": "rslqb", + "col277": "8vdit", + "col278": "dtqvp", + "col279": "wpyaz", + "col280": "fhhna", + "col281": "ronui", + "col282": "6p0gn", + "col283": "ejwwq", + "col284": "c0gk8", + "col285": "9yfy9", + "col286": "yu5gr", + "col287": "4k9mk", + "col288": "heumj", + "col289": "0hkdt", + "col290": "yoyuf", + "col291": "ihlsv", + "col292": "a65n4", + "col293": "3vndt", + "col294": "85qod", + "col295": "efbma", + "col296": "08c9b", + "col297": "nrjj3", + "col298": "hou9a", + "col299": "4qu0g", + "col300": "jpvax", + "col301": "74bbo", + "col302": "pjyz4", + "col303": "kvwpc", + "col304": "zyrfq", + "col305": "kexo6", + "col306": "0g01w", + "col307": "8lclt", + "col308": "0mtpk", + "col309": "rcem5", + "col310": "ra44g", + "col311": "s8u75", + "col312": "5ylsz", + "col313": "ywnh8", + "col314": "5on63", + "col315": "pb8of", + "col316": "ecnbo", + "col317": "lb102", + "col318": "552s0", + "col319": "9byi3", + "col320": "g6gvv", + "col321": "0ri3c", + "col322": "hbtw7", + "col323": "e6c0y", + "col324": "slgdm", + "col325": "qsxpt", + "col326": "nhphw", + "col327": "9egfk", + "col328": "8h610", + "col329": "p412i", + "col330": "vs3q3", + "col331": "ymsa3", + "col332": "t18mx", + "col333": "jktpw", + "col334": "093r3", + "col335": "i5rcp", + "col336": "xi0vu", + "col337": "j6rjq", + "col338": "08zou", + "col339": "lfgs0", + "col340": "53kzm", + "col341": "derl8", + "col342": "aq685", + "col343": "b300u", + "col344": "h64y5", + "col345": "16rx1", + "col346": "qof3o", + "col347": "g7hw5", + "col348": "ygr2a", + "col349": "i6swx", + "col350": "4x7vi", + "col351": "oj4ef", + "col352": "u2u9s", + "col353": "atnew", + "col354": "3av1b", + "col355": "6rfjl", + "col356": "2gni3", + "col357": "6lgot", + "col358": "4w66j", + "col359": "z6uy9", + "col360": "0tg39", + "col361": "vt62t", + "col362": "lhwef", + "col363": "bze1y", + "col364": "rfbly", + "col365": "2dlqn", + "col366": "wzqxz", + "col367": "ffymj", + "col368": "kwco9", + "col369": "ug2pu", + "col370": "825yx", + "col371": "zzzo9", + "col372": "jn6mn", + "col373": "b6n89", + "col374": "h662c", + "col375": "68hp2", + "col376": "ppdst", + "col377": "jwidw", + "col378": "7i55i", + "col379": "qy4t5", + "col380": "til1s", + "col381": "dvnha", + "col382": "rkzwu", + "col383": "g9djs", + "col384": "qbzk1", + "col385": "u6bbf", + "col386": "dybsz", + "col387": "twosv", + "col388": "amsif", + "col389": "w9dwg", + "col390": "12pg2", + "col391": "mnlip", + "col392": "yy5ve", + "col393": "4njsv", + "col394": "z80za", + "col395": "r0ddt", + "col396": "ai0rj", + "col397": "rr7bl", + "col398": "1nhy4", + "col399": "afk42", + "col400": "hkw50", + "col401": "64bt2", + "col402": "lu42f", + "col403": "ilof5", + "col404": "7acjn", + "col405": "lpla6", + "col406": "8dmye", + "col407": "sf9aw", + "col408": "mxgm1", + "col409": "os506", + "col410": "hopt6", + "col411": "vuxok", + "col412": "ej7mk", + "col413": "v35r1", + "col414": "mqpkn", + "col415": "wpwqw", + "col416": "svlrq", + "col417": "xaktp", + "col418": "agabt", + "col419": "f7npv", + "col420": "qpyq2", + "col421": "ikzv1", + "col422": "mclm9", + "col423": "vd2qt", + "col424": "gasjg", + "col425": "f1isx", + "col426": "04p6g", + "col427": "x2yyn", + "col428": "nffz1", + "col429": "trhh1", + "col430": "nye2g", + "col431": "tjegu", + "col432": "54v9n", + "col433": "1ope9", + "col434": "1wvn1", + "col435": "gjhkz", + "col436": "khqyt", + "col437": "ahmog", + "col438": "f80p8", + "col439": "3ygm1", + "col440": "2fynj", + "col441": "63nat", + "col442": "0c0tw", + "col443": "i3878", + "col444": "jlzkq", + "col445": "qu4c1", + "col446": "3pvmx", + "col447": "nrug1", + "col448": "p856b", + "col449": "mgp1w", + "col450": "0fcqq", + "col451": "1x6ru", + "col452": "p9jny", + "col453": "40xxs", + "col454": "sf7cw", + "col455": "z4ot4", + "col456": "lqv0d", + "col457": "0ikkm", + "col458": "2svs4", + "col459": "cr2j5", + "col460": "ccmnd", + "col461": "vmsxb", + "col462": "zyn9q", + "col463": "6pn0w", + "col464": "t4g0r", + "col465": "7uvyk", + "col466": "r6r2o", + "col467": "kygfg", + "col468": "u9egt", + "col469": "crhwo", + "col470": "yvdt1", + "col471": "34t6j", + "col472": "wxaah", + "col473": "50ui9", + "col474": "9geu3", + "col475": "e5bsw", + "col476": "v0zrs", + "col477": "vzemw", + "col478": "8q5vb", + "col479": "j0io4", + "col480": "5d6je", + "col481": "mn42c", + "col482": "6817s", + "col483": "xb2py", + "col484": "fmekd", + "col485": "er68u", + "col486": "3qk4c", + "col487": "lrdel", + "col488": "qpclt", + "col489": "annlu", + "col490": "fxiue", + "col491": "g1axn", + "col492": "38xa7", + "col493": "jz8ip", + "col494": "pyu90", + "col495": "v83jf", + "col496": "fcgdx", + "col497": "l5myz", + "col498": "9j7ni", + "col499": "tyg2r", + "col500": "7rs50", + "col501": "m3ayk", + "col502": "j4cnr", + "col503": "rgg2k", + "col504": "y05y2", + "col505": "q8kwf", + "col506": "868jc", + "col507": "h3cdv", + "col508": "hjdox", + "col509": "ylsq5", + "col510": "r6ifj", + "col511": "nhqna", + "col512": "6zxiw", + "col513": "2n57n", + "col514": "emaa5", + "col515": "7bq9p", + "col516": "5quw1", + "col517": "zvmxe", + "col518": "u604s", + "col519": "5142x", + "col520": "cqsq1", + "col521": "iyacg", + "col522": "fu20y", + "col523": "xacye", + "col524": "1w3b3", + "col525": "juhrc", + "col526": "xkk2h", + "col527": "oejd5", + "col528": "5sudk", + "col529": "5f98q", + "col530": "vf819", + "col531": "amkn8", + "col532": "u9ouk", + "col533": "0iw9f", + "col534": "e951g", + "col535": "brnzi", + "col536": "745ne", + "col537": "uylg0", + "col538": "g0i9l", + "col539": "7tgof", + "col540": "2dxct", + "col541": "s7bir", + "col542": "pnb89", + "col543": "ikzgf", + "col544": "h168z", + "col545": "orqn2", + "col546": "cursh", + "col547": "hmnya", + "col548": "2nmcn", + "col549": "ox5gi", + "col550": "fmx2a", + "col551": "gdiqx", + "col552": "9f4pv", + "col553": "b82fd", + "col554": "tktyd", + "col555": "gue1s", + "col556": "xe3p0", + "col557": "tsrah", + "col558": "imw5b", + "col559": "uqxw5", + "col560": "cm3u2", + "col561": "pphr4", + "col562": "4vyhe", + "col563": "jo53h", + "col564": "qct3q", + "col565": "kpi0a", + "col566": "6f7t7", + "col567": "4fsuf", + "col568": "lixms", + "col569": "gf6yq", + "col570": "09gm2", + "col571": "mz5ng", + "col572": "q7co2", + "col573": "9tjp0", + "col574": "7hsif", + "col575": "df75b", + "col576": "8p28h", + "col577": "9anir", + "col578": "im09h", + "col579": "actax", + "col580": "skchu", + "col581": "3motc", + "col582": "eryed", + "col583": "ig22y", + "col584": "g6u10", + "col585": "3ze5c", + "col586": "gissi", + "col587": "c6p5u", + "col588": "8iokg", + "col589": "9aocp", + "col590": "558lp", + "col591": "brxok", + "col592": "io2il", + "col593": "q0qd7", + "col594": "mh5sf", + "col595": "ahv84", + "col596": "i6utt", + "col597": "scoz6", + "col598": "grpbl", + "col599": "2fqp1", + "col600": "x7yue", + "col601": "53778", + "col602": "03fku", + "col603": "7falb", + "col604": "iifct", + "col605": "unqun", + "col606": "1gko4", + "col607": "l1j9g", + "col608": "ux8tg", + "col609": "8sd6i", + "col610": "g12xl", + "col611": "yuagk", + "col612": "kg06v", + "col613": "c7b4o", + "col614": "xnc5t", + "col615": "skaul", + "col616": "8hdxz", + "col617": "qzb9b", + "col618": "4zp1s", + "col619": "6mum9", + "col620": "u4bwa", + "col621": "rr3c1", + "col622": "3ub3d", + "col623": "4goz4", + "col624": "1zquc", + "col625": "mqn4c", + "col626": "0dqcc", + "col627": "zds4z", + "col628": "0nxb7", + "col629": "de8lg", + "col630": "iy2vy", + "col631": "w1aqq", + "col632": "4i0de", + "col633": "ydj33", + "col634": "veph2", + "col635": "26z78", + "col636": "r0l6m", + "col637": "r5n30", + "col638": "bpx4k", + "col639": "ow10x", + "col640": "bza4d", + "col641": "456wy", + "col642": "9edu9", + "col643": "t1kca", + "col644": "t59gd", + "col645": "w4ysa", + "col646": "0phum", + "col647": "te0pi", + "col648": "ti6b2", + "col649": "h9cdn", + "col650": "nbywb", + "col651": "mq44v", + "col652": "nbaix", + "col653": "ykkci", + "col654": "shuc5", + "col655": "3zv24", + "col656": "1bsmn", + "col657": "j2twc", + "col658": "hbc04", + "col659": "g6uxl", + "col660": "dpec2", + "col661": "rhvwn", + "col662": "6qged", + "col663": "epb6v", + "col664": "3r9us", + "col665": "ajxk4", + "col666": "6zyhy", + "col667": "i8qj6", + "col668": "0k6qc", + "col669": "pdxd5", + "col670": "ngis7", + "col671": "g8iyx", + "col672": "ukymg", + "col673": "n088a", + "col674": "j4kjl", + "col675": "ck525", + "col676": "38xis", + "col677": "n5qze", + "col678": "e1re0", + "col679": "s2ikp", + "col680": "ho83j", + "col681": "5d3vk", + "col682": "328n5", + "col683": "scjz6", + "col684": "eabvx", + "col685": "hbbha", + "col686": "ccfrl", + "col687": "h2orp", + "col688": "gh946", + "col689": "hddtm", + "col690": "wy3x4", + "col691": "jipdg", + "col692": "aov3j", + "col693": "yat1h", + "col694": "tcpfb", + "col695": "p93p2", + "col696": "zbe6l", + "col697": "8nbom", + "col698": "r2fn9", + "col699": "syu5v", + "col700": "oejbm", + "col701": "uha6b", + "col702": "4be2h", + "col703": "eb2iq", + "col704": "yjxaw", + "col705": "b7min", + "col706": "j7kdy", + "col707": "9kvwl", + "col708": "r0gha", + "col709": "ienut", + "col710": "mrzy9", + "col711": "dk0ku", + "col712": "6m85q", + "col713": "ed0fj", + "col714": "grt14", + "col715": "k92lr", + "col716": "11fjf", + "col717": "hda6e", + "col718": "tifg1", + "col719": "afn4b", + "col720": "ohbvi", + "col721": "0mecr", + "col722": "jf2jw", + "col723": "icqa2", + "col724": "ghxsd", + "col725": "91oqp", + "col726": "uo4zb", + "col727": "9jbvu", + "col728": "j6ye6", + "col729": "ly10f", + "col730": "tpcrs", + "col731": "4f1wd", + "col732": "j4tyu", + "col733": "6ewha", + "col734": "sezbd", + "col735": "db31t", + "col736": "plo54", + "col737": "6skm2", + "col738": "7c4i5", + "col739": "48r6m", + "col740": "satdu", + "col741": "3p5nk", + "col742": "6wf26", + "col743": "x0739", + "col744": "amlsl", + "col745": "zqam3", + "col746": "nvak3", + "col747": "3ag4j", + "col748": "al8kr", + "col749": "ve6eo", + "col750": "7iwcm", + "col751": "akcm2", + "col752": "ssy7p", + "col753": "417nj", + "col754": "ieqcq", + "col755": "4lht7", + "col756": "fn0s2", + "col757": "euwkh", + "col758": "kgo4a", + "col759": "nwu5v", + "col760": "yd7rt", + "col761": "q3sto", + "col762": "em4h9", + "col763": "d3eg2", + "col764": "wphhe", + "col765": "veac7", + "col766": "jhfxh", + "col767": "uwl5u", + "col768": "r2m96", + "col769": "wkhn0", + "col770": "pszr4", + "col771": "82838", + "col772": "b92h3", + "col773": "r2z07", + "col774": "p9blg", + "col775": "w2wu2", + "col776": "zpgtb", + "col777": "9aexu", + "col778": "ymufw", + "col779": "4bwfs", + "col780": "9e16b", + "col781": "yazom", + "col782": "3ss1z", + "col783": "gzslp", + "col784": "9jhsz", + "col785": "a9nc4", + "col786": "mg1dh", + "col787": "z1svg", + "col788": "s2kix", + "col789": "k5fji", + "col790": "lqddg", + "col791": "hgznc", + "col792": "1tbr4", + "col793": "9592c", + "col794": "oygv6", + "col795": "5yxjc", + "col796": "r51qm", + "col797": "l6x9f", + "col798": "6d612", + "col799": "9obai", + "col800": "skepl", + "col801": "2kmbc", + "col802": "j9kkl", + "col803": "nvpsr", + "col804": "6wlup", + "col805": "dfyl7", + "col806": "90pxw", + "col807": "3gqiq", + "col808": "mwbx2", + "col809": "43x3m", + "col810": "5hjca", + "col811": "pr2zi", + "col812": "vh9ff", + "col813": "8ommt", + "col814": "jjdsb", + "col815": "wvubm", + "col816": "rtu8p", + "col817": "pyjvr", + "col818": "gt86c", + "col819": "xq484", + "col820": "rqsnd", + "col821": "0sg41", + "col822": "vuofu", + "col823": "89y0i", + "col824": "3mjfu", + "col825": "lrem5", + "col826": "psxs8", + "col827": "pzppt", + "col828": "oxukl", + "col829": "q0c8w", + "col830": "lwkyv", + "col831": "xwuqb", + "col832": "ruseh", + "col833": "eyk7a", + "col834": "4onu7", + "col835": "nadbo", + "col836": "87fva", + "col837": "rh2ju", + "col838": "s5zpq", + "col839": "8zkvk", + "col840": "mxjy8", + "col841": "l032h", + "col842": "qo5zl", + "col843": "rpome", + "col844": "6tu46", + "col845": "37ana", + "col846": "gfoxk", + "col847": "rl3px", + "col848": "nmtxe", + "col849": "xapgs", + "col850": "x7rk3", + "col851": "ba3j1", + "col852": "qym2c", + "col853": "udmei", + "col854": "2hx0y", + "col855": "q0yok", + "col856": "cuq1b", + "col857": "1a6a1", + "col858": "gf7xd", + "col859": "eoxbz", + "col860": "8afpb", + "col861": "abtpj", + "col862": "bvp9h", + "col863": "grayg", + "col864": "26njo", + "col865": "xxl7c", + "col866": "htpgw", + "col867": "0dhb5", + "col868": "3zruy", + "col869": "rugrm", + "col870": "v177e", + "col871": "s6fph", + "col872": "8x6pj", + "col873": "6f081", + "col874": "8ryyk", + "col875": "1uwaa", + "col876": "4bfw4", + "col877": "n0yud", + "col878": "i6gf6", + "col879": "121wp", + "col880": "owi7s", + "col881": "xwrbh", + "col882": "b4h4u", + "col883": "uhwn4", + "col884": "ns5mt", + "col885": "y8ljd", + "col886": "3ua94", + "col887": "8s52x", + "col888": "yjb3e", + "col889": "wjhle", + "col890": "ey20x", + "col891": "tmu96", + "col892": "5912v", + "col893": "t5czz", + "col894": "b7y0r", + "col895": "6pao6", + "col896": "0loqp", + "col897": "fm4j7", + "col898": "e4iz1", + "col899": "m7w2u", + "col900": "c51sh", + "col901": "0twhu", + "col902": "6rbhp", + "col903": "ikcjq", + "col904": "tm7n5", + "col905": "1iza4", + "col906": "iu663", + "col907": "b8dv1", + "col908": "7sf4b", + "col909": "rhqa1", + "col910": "6thvy", + "col911": "e53uj", + "col912": "muwpg", + "col913": "3ia7w", + "col914": "hoxpg", + "col915": "4w0mg", + "col916": "e2492", + "col917": "8livp", + "col918": "7pobs", + "col919": "m3uvr", + "col920": "4mqkk", + "col921": "8kjst", + "col922": "ysywe", + "col923": "benzs", + "col924": "indx4", + "col925": "l6ly7", + "col926": "xfmci", + "col927": "ru0q6", + "col928": "yeud5", + "col929": "bdqbf", + "col930": "zpr91", + "col931": "v0xgz", + "col932": "stsev", + "col933": "4c5vs", + "col934": "jcqnj", + "col935": "pge0b", + "col936": "5u965", + "col937": "5x4cf", + "col938": "0usyb", + "col939": "9nvyk", + "col940": "759yn", + "col941": "o0f5t", + "col942": "83cae", + "col943": "zdcw0", + "col944": "d1lhl", + "col945": "zz3nm", + "col946": "rawdd", + "col947": "nm0qq", + "col948": "wqbol", + "col949": "bd4fn", + "col950": "m46x4", + "col951": "jqp2z", + "col952": "wixd1", + "col953": "k9ze0", + "col954": "0182q", + "col955": "ecj37", + "col956": "02jc0", + "col957": "68ilh", + "col958": "7isa0", + "col959": "fbpd6", + "col960": "vmgil", + "col961": "z8vs1", + "col962": "gl2ru", + "col963": "fpfgt", + "col964": "ntbso", + "col965": "6yj7g", + "col966": "468ez", + "col967": "ng5mp", + "col968": "m6vip", + "col969": "zagkt", + "col970": "exfrn", + "col971": "9qsb2", + "col972": "y24f2", + "col973": "m30kg", + "col974": "rey0c", + "col975": "ryukt", + "col976": "0flb0", + "col977": "deblv", + "col978": "73wps", + "col979": "6f2g7", + "col980": "zvgc6", + "col981": "m1xjh", + "col982": "vrvy3", + "col983": "ithmj", + "col984": "7eksj", + "col985": "eukds", + "col986": "jzxlz", + "col987": "233od", + "col988": "s23z5", + "col989": "9idr8", + "col990": "7626a", + "col991": "ly3fs", + "col992": "71sbo", + "col993": "9r52b", + "col994": "p0ecb", + "col995": "ct6x8", + "col996": "u4xpy", + "col997": "1l2gc", + "col998": "0gqp7", + "col999": "77hwo" + } +] \ No newline at end of file diff --git a/data/100_ASC.json b/data/100_ASC.json new file mode 100644 index 000000000..2d61b6259 --- /dev/null +++ b/data/100_ASC.json @@ -0,0 +1,502 @@ +[ + { + "name": "Beryl Rice", + "gender": "female", + "company": "Velity" + }, + { + "name": "Bruce Strong", + "gender": "male", + "company": "Xyqag" + }, + { + "name": "Carroll Buchanan", + "gender": "male", + "company": "Ecosys" + }, + { + "name": "Claudine Neal", + "gender": "female", + "company": "Sealoud" + }, + { + "name": "Dawson Barber", + "gender": "male", + "company": "Dymi" + }, + { + "name": "Ethel Price", + "gender": "female", + "company": "Enersol" + }, + { + "name": "Evans Hickman", + "gender": "male", + "company": "Parleynet" + }, + { + "name": "Georgina Schultz", + "gender": "female", + "company": "Suretech" + }, + { + "name": "Jackson Macias", + "gender": "male", + "company": "Aquamate" + }, + { + "name": "Lynda Mendoza", + "gender": "female", + "company": "Dogspa" + }, + { + "name": "Nellie Whitfield", + "gender": "female", + "company": "Exospace" + }, + { + "name": "Robles Boyle", + "gender": "male", + "company": "Comtract" + }, + { + "name": "Sarah Massey", + "gender": "female", + "company": "Bisba" + }, + { + "name": "Schroeder Mathews", + "gender": "male", + "company": "Polarium" + }, + { + "name": "Valarie Atkinson", + "gender": "female", + "company": "Hopeli" + }, + { + "name": "Wilder Gonzales", + "gender": "male", + "company": "Geekko" + }, + { + "name": "Pena Pena", + "gender": "male", + "company": "Quarx" + }, + { + "name": "Lelia Gates", + "gender": "female", + "company": "Proxsoft" + }, + { + "name": "Letitia Vasquez", + "gender": "female", + "company": "Slumberia" + }, + { + "name": "Trevino Moreno", + "gender": "male", + "company": "Conjurica" + }, + { + "name": "Barr Page", + "gender": "male", + "company": "Apex" + }, + { + "name": "Kirkland Merrill", + "gender": "male", + "company": "Utara" + }, + { + "name": "Blanche Conley", + "gender": "female", + "company": "Imkan" + }, + { + "name": "Atkins Dunlap", + "gender": "male", + "company": "Comveyor" + }, + { + "name": "Everett Foreman", + "gender": "male", + "company": "Maineland" + }, + { + "name": "Gould Randolph", + "gender": "male", + "company": "Intergeek" + }, + { + "name": "Kelli Leon", + "gender": "female", + "company": "Verbus" + }, + { + "name": "Freda Mason", + "gender": "female", + "company": "Accidency" + }, + { + "name": "Tucker Maxwell", + "gender": "male", + "company": "Lumbrex" + }, + { + "name": "Yvonne Parsons", + "gender": "female", + "company": "Zolar" + }, + { + "name": "Woods Key", + "gender": "male", + "company": "Bedder" + }, + { + "name": "Stephens Reilly", + "gender": "male", + "company": "Acusage" + }, + { + "name": "Mcfarland Sparks", + "gender": "male", + "company": "Comvey" + }, + { + "name": "Jocelyn Sawyer", + "gender": "female", + "company": "Fortean" + }, + { + "name": "Renee Barr", + "gender": "female", + "company": "Kiggle" + }, + { + "name": "Gaines Beck", + "gender": "male", + "company": "Sequitur" + }, + { + "name": "Luisa Farrell", + "gender": "female", + "company": "Cinesanct" + }, + { + "name": "Robyn Strickland", + "gender": "female", + "company": "Obones" + }, + { + "name": "Roseann Jarvis", + "gender": "female", + "company": "Aquazure" + }, + { + "name": "Johnston Park", + "gender": "male", + "company": "Netur" + }, + { + "name": "Wong Craft", + "gender": "male", + "company": "Opticall" + }, + { + "name": "Merritt Cole", + "gender": "male", + "company": "Techtrix" + }, + { + "name": "Dale Byrd", + "gender": "female", + "company": "Kneedles" + }, + { + "name": "Sara Delgado", + "gender": "female", + "company": "Netagy" + }, + { + "name": "Alisha Myers", + "gender": "female", + "company": "Intradisk" + }, + { + "name": "Felecia Smith", + "gender": "female", + "company": "Futurity" + }, + { + "name": "Neal Harvey", + "gender": "male", + "company": "Pyramax" + }, + { + "name": "Nola Miles", + "gender": "female", + "company": "Sonique" + }, + { + "name": "Herring Pierce", + "gender": "male", + "company": "Geeketron" + }, + { + "name": "Shelley Rodriquez", + "gender": "female", + "company": "Bostonic" + }, + { + "name": "Cora Chase", + "gender": "female", + "company": "Isonus" + }, + { + "name": "Mckay Santos", + "gender": "male", + "company": "Amtas" + }, + { + "name": "Hilda Crane", + "gender": "female", + "company": "Jumpstack" + }, + { + "name": "Jeanne Lindsay", + "gender": "female", + "company": "Genesynk" + }, + { + "name": "Frye Sharpe", + "gender": "male", + "company": "Eplode" + }, + { + "name": "Velma Fry", + "gender": "female", + "company": "Ronelon" + }, + { + "name": "Reyna Espinoza", + "gender": "female", + "company": "Prismatic" + }, + { + "name": "Spencer Sloan", + "gender": "male", + "company": "Comverges" + }, + { + "name": "Graham Marsh", + "gender": "male", + "company": "Medifax" + }, + { + "name": "Hale Boone", + "gender": "male", + "company": "Digial" + }, + { + "name": "Wiley Hubbard", + "gender": "male", + "company": "Zensus" + }, + { + "name": "Blackburn Drake", + "gender": "male", + "company": "Frenex" + }, + { + "name": "Franco Hunter", + "gender": "male", + "company": "Rockabye" + }, + { + "name": "Barnett Case", + "gender": "male", + "company": "Norali" + }, + { + "name": "Alexander Foley", + "gender": "male", + "company": "Geekosis" + }, + { + "name": "Lynette Stein", + "gender": "female", + "company": "Macronaut" + }, + { + "name": "Anthony Joyner", + "gender": "male", + "company": "Senmei" + }, + { + "name": "Garrett Brennan", + "gender": "male", + "company": "Bluegrain" + }, + { + "name": "Betsy Horton", + "gender": "female", + "company": "Zilla" + }, + { + "name": "Patton Small", + "gender": "male", + "company": "Genmex" + }, + { + "name": "Lakisha Huber", + "gender": "female", + "company": "Insource" + }, + { + "name": "Lindsay Avery", + "gender": "female", + "company": "Unq" + }, + { + "name": "Ayers Hood", + "gender": "male", + "company": "Accuprint" + }, + { + "name": "Torres Durham", + "gender": "male", + "company": "Uplinx" + }, + { + "name": "Vincent Hernandez", + "gender": "male", + "company": "Talendula" + }, + { + "name": "Baird Ryan", + "gender": "male", + "company": "Aquasseur" + }, + { + "name": "Georgia Mercer", + "gender": "female", + "company": "Skyplex" + }, + { + "name": "Francesca Elliott", + "gender": "female", + "company": "Nspire" + }, + { + "name": "Lyons Peters", + "gender": "male", + "company": "Quinex" + }, + { + "name": "Kristi Brewer", + "gender": "female", + "company": "Oronoko" + }, + { + "name": "Tonya Bray", + "gender": "female", + "company": "Insuron" + }, + { + "name": "Valenzuela Huff", + "gender": "male", + "company": "Applideck" + }, + { + "name": "Tiffany Anderson", + "gender": "female", + "company": "Zanymax" + }, + { + "name": "Jerri King", + "gender": "female", + "company": "Eventex" + }, + { + "name": "Rocha Meadows", + "gender": "male", + "company": "Goko" + }, + { + "name": "Marcy Green", + "gender": "female", + "company": "Pharmex" + }, + { + "name": "Kirk Cross", + "gender": "male", + "company": "Portico" + }, + { + "name": "Hattie Mullen", + "gender": "female", + "company": "Zilencio" + }, + { + "name": "Deann Bridges", + "gender": "female", + "company": "Equitox" + }, + { + "name": "Chaney Roach", + "gender": "male", + "company": "Qualitern" + }, + { + "name": "Consuelo Dickson", + "gender": "female", + "company": "Poshome" + }, + { + "name": "Billie Rowe", + "gender": "female", + "company": "Cemention" + }, + { + "name": "Bean Donovan", + "gender": "male", + "company": "Mantro" + }, + { + "name": "Lancaster Patel", + "gender": "male", + "company": "Krog" + }, + { + "name": "Rosa Dyer", + "gender": "female", + "company": "Netility" + }, + { + "name": "Christine Compton", + "gender": "female", + "company": "Bleeko" + }, + { + "name": "Milagros Finch", + "gender": "female", + "company": "Handshake" + }, + { + "name": "Ericka Alvarado", + "gender": "female", + "company": "Lyrichord" + }, + { + "name": "Sylvia Sosa", + "gender": "female", + "company": "Circum" + }, + { + "name": "Humphrey Curtis", + "gender": "male", + "company": "Corepan" + } +] \ No newline at end of file diff --git a/data/100_DESC.json b/data/100_DESC.json new file mode 100644 index 000000000..159ea9482 --- /dev/null +++ b/data/100_DESC.json @@ -0,0 +1,502 @@ +[ + { + "name": "Wilder Gonzales", + "gender": "male", + "company": "Geekko" + }, + { + "name": "Valarie Atkinson", + "gender": "female", + "company": "Hopeli" + }, + { + "name": "Schroeder Mathews", + "gender": "male", + "company": "Polarium" + }, + { + "name": "Sarah Massey", + "gender": "female", + "company": "Bisba" + }, + { + "name": "Robles Boyle", + "gender": "male", + "company": "Comtract" + }, + { + "name": "Nellie Whitfield", + "gender": "female", + "company": "Exospace" + }, + { + "name": "Lynda Mendoza", + "gender": "female", + "company": "Dogspa" + }, + { + "name": "Jackson Macias", + "gender": "male", + "company": "Aquamate" + }, + { + "name": "Georgina Schultz", + "gender": "female", + "company": "Suretech" + }, + { + "name": "Evans Hickman", + "gender": "male", + "company": "Parleynet" + }, + { + "name": "Ethel Price", + "gender": "female", + "company": "Enersol" + }, + { + "name": "Dawson Barber", + "gender": "male", + "company": "Dymi" + }, + { + "name": "Claudine Neal", + "gender": "female", + "company": "Sealoud" + }, + { + "name": "Carroll Buchanan", + "gender": "male", + "company": "Ecosys" + }, + { + "name": "Bruce Strong", + "gender": "male", + "company": "Xyqag" + }, + { + "name": "Beryl Rice", + "gender": "female", + "company": "Velity" + }, + { + "name": "Pena Pena", + "gender": "male", + "company": "Quarx" + }, + { + "name": "Lelia Gates", + "gender": "female", + "company": "Proxsoft" + }, + { + "name": "Letitia Vasquez", + "gender": "female", + "company": "Slumberia" + }, + { + "name": "Trevino Moreno", + "gender": "male", + "company": "Conjurica" + }, + { + "name": "Barr Page", + "gender": "male", + "company": "Apex" + }, + { + "name": "Kirkland Merrill", + "gender": "male", + "company": "Utara" + }, + { + "name": "Blanche Conley", + "gender": "female", + "company": "Imkan" + }, + { + "name": "Atkins Dunlap", + "gender": "male", + "company": "Comveyor" + }, + { + "name": "Everett Foreman", + "gender": "male", + "company": "Maineland" + }, + { + "name": "Gould Randolph", + "gender": "male", + "company": "Intergeek" + }, + { + "name": "Kelli Leon", + "gender": "female", + "company": "Verbus" + }, + { + "name": "Freda Mason", + "gender": "female", + "company": "Accidency" + }, + { + "name": "Tucker Maxwell", + "gender": "male", + "company": "Lumbrex" + }, + { + "name": "Yvonne Parsons", + "gender": "female", + "company": "Zolar" + }, + { + "name": "Woods Key", + "gender": "male", + "company": "Bedder" + }, + { + "name": "Stephens Reilly", + "gender": "male", + "company": "Acusage" + }, + { + "name": "Mcfarland Sparks", + "gender": "male", + "company": "Comvey" + }, + { + "name": "Jocelyn Sawyer", + "gender": "female", + "company": "Fortean" + }, + { + "name": "Renee Barr", + "gender": "female", + "company": "Kiggle" + }, + { + "name": "Gaines Beck", + "gender": "male", + "company": "Sequitur" + }, + { + "name": "Luisa Farrell", + "gender": "female", + "company": "Cinesanct" + }, + { + "name": "Robyn Strickland", + "gender": "female", + "company": "Obones" + }, + { + "name": "Roseann Jarvis", + "gender": "female", + "company": "Aquazure" + }, + { + "name": "Johnston Park", + "gender": "male", + "company": "Netur" + }, + { + "name": "Wong Craft", + "gender": "male", + "company": "Opticall" + }, + { + "name": "Merritt Cole", + "gender": "male", + "company": "Techtrix" + }, + { + "name": "Dale Byrd", + "gender": "female", + "company": "Kneedles" + }, + { + "name": "Sara Delgado", + "gender": "female", + "company": "Netagy" + }, + { + "name": "Alisha Myers", + "gender": "female", + "company": "Intradisk" + }, + { + "name": "Felecia Smith", + "gender": "female", + "company": "Futurity" + }, + { + "name": "Neal Harvey", + "gender": "male", + "company": "Pyramax" + }, + { + "name": "Nola Miles", + "gender": "female", + "company": "Sonique" + }, + { + "name": "Herring Pierce", + "gender": "male", + "company": "Geeketron" + }, + { + "name": "Shelley Rodriquez", + "gender": "female", + "company": "Bostonic" + }, + { + "name": "Cora Chase", + "gender": "female", + "company": "Isonus" + }, + { + "name": "Mckay Santos", + "gender": "male", + "company": "Amtas" + }, + { + "name": "Hilda Crane", + "gender": "female", + "company": "Jumpstack" + }, + { + "name": "Jeanne Lindsay", + "gender": "female", + "company": "Genesynk" + }, + { + "name": "Frye Sharpe", + "gender": "male", + "company": "Eplode" + }, + { + "name": "Velma Fry", + "gender": "female", + "company": "Ronelon" + }, + { + "name": "Reyna Espinoza", + "gender": "female", + "company": "Prismatic" + }, + { + "name": "Spencer Sloan", + "gender": "male", + "company": "Comverges" + }, + { + "name": "Graham Marsh", + "gender": "male", + "company": "Medifax" + }, + { + "name": "Hale Boone", + "gender": "male", + "company": "Digial" + }, + { + "name": "Wiley Hubbard", + "gender": "male", + "company": "Zensus" + }, + { + "name": "Blackburn Drake", + "gender": "male", + "company": "Frenex" + }, + { + "name": "Franco Hunter", + "gender": "male", + "company": "Rockabye" + }, + { + "name": "Barnett Case", + "gender": "male", + "company": "Norali" + }, + { + "name": "Alexander Foley", + "gender": "male", + "company": "Geekosis" + }, + { + "name": "Lynette Stein", + "gender": "female", + "company": "Macronaut" + }, + { + "name": "Anthony Joyner", + "gender": "male", + "company": "Senmei" + }, + { + "name": "Garrett Brennan", + "gender": "male", + "company": "Bluegrain" + }, + { + "name": "Betsy Horton", + "gender": "female", + "company": "Zilla" + }, + { + "name": "Patton Small", + "gender": "male", + "company": "Genmex" + }, + { + "name": "Lakisha Huber", + "gender": "female", + "company": "Insource" + }, + { + "name": "Lindsay Avery", + "gender": "female", + "company": "Unq" + }, + { + "name": "Ayers Hood", + "gender": "male", + "company": "Accuprint" + }, + { + "name": "Torres Durham", + "gender": "male", + "company": "Uplinx" + }, + { + "name": "Vincent Hernandez", + "gender": "male", + "company": "Talendula" + }, + { + "name": "Baird Ryan", + "gender": "male", + "company": "Aquasseur" + }, + { + "name": "Georgia Mercer", + "gender": "female", + "company": "Skyplex" + }, + { + "name": "Francesca Elliott", + "gender": "female", + "company": "Nspire" + }, + { + "name": "Lyons Peters", + "gender": "male", + "company": "Quinex" + }, + { + "name": "Kristi Brewer", + "gender": "female", + "company": "Oronoko" + }, + { + "name": "Tonya Bray", + "gender": "female", + "company": "Insuron" + }, + { + "name": "Valenzuela Huff", + "gender": "male", + "company": "Applideck" + }, + { + "name": "Tiffany Anderson", + "gender": "female", + "company": "Zanymax" + }, + { + "name": "Jerri King", + "gender": "female", + "company": "Eventex" + }, + { + "name": "Rocha Meadows", + "gender": "male", + "company": "Goko" + }, + { + "name": "Marcy Green", + "gender": "female", + "company": "Pharmex" + }, + { + "name": "Kirk Cross", + "gender": "male", + "company": "Portico" + }, + { + "name": "Hattie Mullen", + "gender": "female", + "company": "Zilencio" + }, + { + "name": "Deann Bridges", + "gender": "female", + "company": "Equitox" + }, + { + "name": "Chaney Roach", + "gender": "male", + "company": "Qualitern" + }, + { + "name": "Consuelo Dickson", + "gender": "female", + "company": "Poshome" + }, + { + "name": "Billie Rowe", + "gender": "female", + "company": "Cemention" + }, + { + "name": "Bean Donovan", + "gender": "male", + "company": "Mantro" + }, + { + "name": "Lancaster Patel", + "gender": "male", + "company": "Krog" + }, + { + "name": "Rosa Dyer", + "gender": "female", + "company": "Netility" + }, + { + "name": "Christine Compton", + "gender": "female", + "company": "Bleeko" + }, + { + "name": "Milagros Finch", + "gender": "female", + "company": "Handshake" + }, + { + "name": "Ericka Alvarado", + "gender": "female", + "company": "Lyrichord" + }, + { + "name": "Sylvia Sosa", + "gender": "female", + "company": "Circum" + }, + { + "name": "Humphrey Curtis", + "gender": "male", + "company": "Corepan" + } +] \ No newline at end of file diff --git a/data/100_columns.json b/data/100_columns.json new file mode 100644 index 000000000..76087dfda --- /dev/null +++ b/data/100_columns.json @@ -0,0 +1,10302 @@ +[ + { + "name": "Ethel Price", + "gender": "female", + "company": "Enersol", + "col0": "93gt8", + "col1": "npvdh", + "col2": "hjllr", + "col3": "xuhxw", + "col4": "gs3nt", + "col5": "jpcyw", + "col6": "jxhlq", + "col7": "irskr", + "col8": "sbeii", + "col9": "chfja", + "col10": "om5zt", + "col11": "2ds9p", + "col12": "w4342", + "col13": "g7lam", + "col14": "o7e5t", + "col15": "sf7bf", + "col16": "n6xok", + "col17": "trh7u", + "col18": "r9o1a", + "col19": "j2n3f", + "col20": "72r9t", + "col21": "1tccr", + "col22": "2vbtb", + "col23": "3o3g0", + "col24": "ctzqx", + "col25": "w7b6a", + "col26": "coeab", + "col27": "k1q2s", + "col28": "2d1bz", + "col29": "4e2d0", + "col30": "dmm64", + "col31": "adwd6", + "col32": "arydk", + "col33": "r1kyo", + "col34": "oxacg", + "col35": "vlv8c", + "col36": "pnsmt", + "col37": "fyp41", + "col38": "7yxm0", + "col39": "39xki", + "col40": "9q3vm", + "col41": "nkg0d", + "col42": "9aexb", + "col43": "7snsp", + "col44": "dfscc", + "col45": "tfskp", + "col46": "ts630", + "col47": "4ehte", + "col48": "b1njl", + "col49": "lv5ix", + "col50": "oinyc", + "col51": "9wdat", + "col52": "sddwd", + "col53": "lp77l", + "col54": "qzuot", + "col55": "hnluv", + "col56": "2ua0w", + "col57": "8k9be", + "col58": "p8azp", + "col59": "5kurh", + "col60": "uzjqr", + "col61": "te3qe", + "col62": "12svh", + "col63": "01ncu", + "col64": "8t005", + "col65": "n25y3", + "col66": "oquun", + "col67": "89936", + "col68": "fce1g", + "col69": "uocrc", + "col70": "dpf4b", + "col71": "d3myv", + "col72": "wcyv0", + "col73": "10iby", + "col74": "6xq8o", + "col75": "zu4gy", + "col76": "7pnlu", + "col77": "en9ne", + "col78": "6mfqr", + "col79": "zig1v", + "col80": "fdb4w", + "col81": "4ej7u", + "col82": "3nd5j", + "col83": "fa6jm", + "col84": "dn7p2", + "col85": "amnde", + "col86": "1uy2w", + "col87": "hdt06", + "col88": "8lsbm", + "col89": "u9f6o", + "col90": "vwlnj", + "col91": "0kuiq", + "col92": "s1i0i", + "col93": "8i7p2", + "col94": "dwomp", + "col95": "l8y94", + "col96": "v29xr", + "col97": "7fh2u" + }, + { + "name": "Claudine Neal", + "gender": "female", + "company": "Sealoud", + "col0": "1yib9", + "col1": "fqp3g", + "col2": "43yi7", + "col3": "dj39x", + "col4": "nlqsi", + "col5": "dxhbr", + "col6": "kxdm9", + "col7": "m0pog", + "col8": "bduwe", + "col9": "uiu7m", + "col10": "mltd5", + "col11": "ulnae", + "col12": "11la2", + "col13": "0ybkx", + "col14": "00yel", + "col15": "mgwnq", + "col16": "kwo6r", + "col17": "s2dv6", + "col18": "69jqi", + "col19": "zsnjd", + "col20": "qmjln", + "col21": "t80k1", + "col22": "p7guj", + "col23": "mmjwj", + "col24": "65htf", + "col25": "l1462", + "col26": "reifc", + "col27": "jgwfz", + "col28": "t7jjt", + "col29": "taemr", + "col30": "6g1so", + "col31": "izxyf", + "col32": "wmb1b", + "col33": "b0mv2", + "col34": "qtyk1", + "col35": "bgeuw", + "col36": "n6zgd", + "col37": "voxau", + "col38": "x0lkg", + "col39": "d78cy", + "col40": "8iuam", + "col41": "cv0ds", + "col42": "kj5ab", + "col43": "4nb3y", + "col44": "w60jw", + "col45": "ihsp4", + "col46": "rt1vt", + "col47": "ou5iq", + "col48": "tv9sr", + "col49": "siuzw", + "col50": "kn6sv", + "col51": "akzhz", + "col52": "r5p4j", + "col53": "9nand", + "col54": "maj8v", + "col55": "syehu", + "col56": "0ofuz", + "col57": "nyjx7", + "col58": "tqait", + "col59": "8qzz0", + "col60": "c484i", + "col61": "1ltgy", + "col62": "0y24y", + "col63": "v9cuk", + "col64": "g7178", + "col65": "futx6", + "col66": "20x5y", + "col67": "b5oe4", + "col68": "6uji0", + "col69": "4ymit", + "col70": "oy5e2", + "col71": "qpjgu", + "col72": "iz9h8", + "col73": "ih9my", + "col74": "f5dc8", + "col75": "0o1g1", + "col76": "6vwak", + "col77": "powgq", + "col78": "imt4d", + "col79": "ryoe0", + "col80": "vkj8f", + "col81": "ej7y9", + "col82": "v08mk", + "col83": "n7fi0", + "col84": "iinis", + "col85": "wgd75", + "col86": "ikfrl", + "col87": "sdv1r", + "col88": "s2s6t", + "col89": "kpgd2", + "col90": "rugfo", + "col91": "pnl2y", + "col92": "hiqwp", + "col93": "zmxnt", + "col94": "geout", + "col95": "xq4ro", + "col96": "z5rdi", + "col97": "2o9jq" + }, + { + "name": "Beryl Rice", + "gender": "female", + "company": "Velity", + "col0": "oi5vz", + "col1": "vkhyb", + "col2": "gy1gl", + "col3": "vglkb", + "col4": "jxfsa", + "col5": "wycnb", + "col6": "z6y80", + "col7": "59klf", + "col8": "ynqt6", + "col9": "1yjwi", + "col10": "xdc1u", + "col11": "47v6r", + "col12": "ne5a1", + "col13": "h9not", + "col14": "jsmfh", + "col15": "zc4t4", + "col16": "azoyk", + "col17": "18h2u", + "col18": "449q9", + "col19": "xm674", + "col20": "hm6hf", + "col21": "wyfki", + "col22": "nn52i", + "col23": "cvypg", + "col24": "xjbvk", + "col25": "r6pg0", + "col26": "nyu59", + "col27": "g2ygj", + "col28": "d4g7u", + "col29": "51cp0", + "col30": "pgltl", + "col31": "vv6ku", + "col32": "vnuy9", + "col33": "sdqxk", + "col34": "4zsva", + "col35": "14xe5", + "col36": "ztfli", + "col37": "hab9p", + "col38": "ui4jo", + "col39": "mw76o", + "col40": "2h9rw", + "col41": "o84cq", + "col42": "8ds90", + "col43": "weq0y", + "col44": "j0hvw", + "col45": "kd7qx", + "col46": "oy7mw", + "col47": "mlye8", + "col48": "wbw3c", + "col49": "k2cps", + "col50": "00zb2", + "col51": "4chvv", + "col52": "rxdbd", + "col53": "kmo37", + "col54": "dzdz3", + "col55": "auffa", + "col56": "6tvpi", + "col57": "0545q", + "col58": "2zxj2", + "col59": "h17ug", + "col60": "h1pw1", + "col61": "jwirg", + "col62": "f4mi2", + "col63": "83r8g", + "col64": "99137", + "col65": "ncue5", + "col66": "vsg7t", + "col67": "rakfx", + "col68": "ie15n", + "col69": "77s4t", + "col70": "ka7rj", + "col71": "21tkl", + "col72": "dnfrx", + "col73": "lwfms", + "col74": "9m9qf", + "col75": "5dnnt", + "col76": "rd0jn", + "col77": "qocra", + "col78": "gueom", + "col79": "j60du", + "col80": "xmmzx", + "col81": "t5dt5", + "col82": "t647z", + "col83": "qrnn3", + "col84": "mky3y", + "col85": "6hc0g", + "col86": "6io67", + "col87": "fnbc4", + "col88": "efkal", + "col89": "pod16", + "col90": "rojrl", + "col91": "xuv0s", + "col92": "soj3v", + "col93": "p2ld3", + "col94": "is15j", + "col95": "dqc1o", + "col96": "60w2s", + "col97": "ma8ho" + }, + { + "name": "Wilder Gonzales", + "gender": "male", + "company": "Geekko", + "col0": "ldpz7", + "col1": "hw2rg", + "col2": "8dfzq", + "col3": "yzddc", + "col4": "g0xza", + "col5": "nszuz", + "col6": "geqm7", + "col7": "wxr4m", + "col8": "b1ln7", + "col9": "x77pk", + "col10": "9ifs4", + "col11": "07e0i", + "col12": "g45a8", + "col13": "rqjjk", + "col14": "0zsu0", + "col15": "4ajps", + "col16": "qjktl", + "col17": "qsgyr", + "col18": "dxu4c", + "col19": "92uon", + "col20": "f7591", + "col21": "9tydi", + "col22": "k5qdk", + "col23": "i70d0", + "col24": "qswnv", + "col25": "bf73k", + "col26": "zfoqd", + "col27": "af0da", + "col28": "6cd2h", + "col29": "ynkjy", + "col30": "e16ax", + "col31": "i578s", + "col32": "asr7a", + "col33": "nt3vc", + "col34": "bkoo4", + "col35": "rz4in", + "col36": "q182g", + "col37": "izr9a", + "col38": "r9qgw", + "col39": "6szxk", + "col40": "030pl", + "col41": "izzal", + "col42": "40ji9", + "col43": "pzx9u", + "col44": "hwii8", + "col45": "bz9lf", + "col46": "eqrxp", + "col47": "x0xjr", + "col48": "rl4rf", + "col49": "2ao2p", + "col50": "7jec6", + "col51": "lgwaj", + "col52": "9uccd", + "col53": "1n52k", + "col54": "290oq", + "col55": "q5uk2", + "col56": "5kqcg", + "col57": "wze1d", + "col58": "s7fbo", + "col59": "i95qn", + "col60": "r85jq", + "col61": "3zfrt", + "col62": "h38am", + "col63": "fljws", + "col64": "j0cau", + "col65": "jxbxd", + "col66": "q77qh", + "col67": "vne79", + "col68": "qzpmv", + "col69": "17zym", + "col70": "8rrql", + "col71": "8180q", + "col72": "nobke", + "col73": "nsvqk", + "col74": "msd4h", + "col75": "i8w9b", + "col76": "frtj2", + "col77": "4sqd0", + "col78": "vqs81", + "col79": "9gpji", + "col80": "fm75d", + "col81": "0o7ps", + "col82": "ze4wx", + "col83": "izoji", + "col84": "d6lmd", + "col85": "oz090", + "col86": "nlphf", + "col87": "fh980", + "col88": "055wx", + "col89": "eku8r", + "col90": "lheer", + "col91": "pswqd", + "col92": "8chv3", + "col93": "pw309", + "col94": "qpldq", + "col95": "vsdo5", + "col96": "85ht8", + "col97": "x7j2d" + }, + { + "name": "Georgina Schultz", + "gender": "female", + "company": "Suretech", + "col0": "gwue2", + "col1": "6iyyp", + "col2": "cknmb", + "col3": "3p2yl", + "col4": "ltf3j", + "col5": "86azc", + "col6": "pwb70", + "col7": "i64bi", + "col8": "5buuv", + "col9": "xvvbd", + "col10": "1waau", + "col11": "jx1tn", + "col12": "3yipz", + "col13": "suhwh", + "col14": "aozf5", + "col15": "f38md", + "col16": "cv2do", + "col17": "dytob", + "col18": "vju3z", + "col19": "1quji", + "col20": "4y5y8", + "col21": "doh73", + "col22": "s49u8", + "col23": "shlb2", + "col24": "s96t1", + "col25": "hvp3w", + "col26": "c4dc8", + "col27": "9y0wq", + "col28": "rj3zi", + "col29": "5437b", + "col30": "aocpi", + "col31": "68w87", + "col32": "v8bhl", + "col33": "massc", + "col34": "tuzhk", + "col35": "66yi6", + "col36": "jvecw", + "col37": "igrhv", + "col38": "ju2mt", + "col39": "sce2v", + "col40": "y4707", + "col41": "h5drg", + "col42": "74gff", + "col43": "5jb3w", + "col44": "whr9c", + "col45": "b004k", + "col46": "h1ldv", + "col47": "exsl4", + "col48": "iqzob", + "col49": "sy35w", + "col50": "0nj5z", + "col51": "1r4w4", + "col52": "sv0wk", + "col53": "6idsu", + "col54": "mulw8", + "col55": "i9nkt", + "col56": "4lkac", + "col57": "ra1k4", + "col58": "uasi0", + "col59": "tsa32", + "col60": "yr81g", + "col61": "iy9he", + "col62": "pcmuf", + "col63": "j4bqt", + "col64": "asrqb", + "col65": "gjv9p", + "col66": "dlzzx", + "col67": "86cn4", + "col68": "a6zrz", + "col69": "0md6a", + "col70": "7wmvx", + "col71": "z6cks", + "col72": "xp5c6", + "col73": "jx9e4", + "col74": "hr06i", + "col75": "f9pw8", + "col76": "hrn4o", + "col77": "ipfph", + "col78": "5b2hj", + "col79": "xjoli", + "col80": "fpmwv", + "col81": "kx67b", + "col82": "7k228", + "col83": "1a5vi", + "col84": "cfqeu", + "col85": "4f8ey", + "col86": "f3ce5", + "col87": "1umyj", + "col88": "hy5bo", + "col89": "zgtv3", + "col90": "aw4kp", + "col91": "ph2vq", + "col92": "usrze", + "col93": "zh4l7", + "col94": "ij1y4", + "col95": "kmn1b", + "col96": "1bs8u", + "col97": "tlrxj" + }, + { + "name": "Carroll Buchanan", + "gender": "male", + "company": "Ecosys", + "col0": "cu1n1", + "col1": "52p0f", + "col2": "ix9b4", + "col3": "6n8wq", + "col4": "8pzcg", + "col5": "8nzpy", + "col6": "dh95d", + "col7": "6fi1q", + "col8": "1glg5", + "col9": "jayyc", + "col10": "5c5vh", + "col11": "uq8qx", + "col12": "xif1j", + "col13": "7g1pg", + "col14": "5qecp", + "col15": "ija93", + "col16": "jrqi0", + "col17": "lvsos", + "col18": "e49py", + "col19": "mf5nj", + "col20": "lg67v", + "col21": "xkve1", + "col22": "2xz6z", + "col23": "s2z4y", + "col24": "tfz78", + "col25": "nqeu9", + "col26": "h5229", + "col27": "q4tp7", + "col28": "qwg58", + "col29": "ug9xy", + "col30": "23z08", + "col31": "24brj", + "col32": "ick7d", + "col33": "awgil", + "col34": "nvx8z", + "col35": "w2xu1", + "col36": "qxfi9", + "col37": "jyf72", + "col38": "c0anj", + "col39": "d7763", + "col40": "xnao5", + "col41": "w7uxu", + "col42": "qlan6", + "col43": "wy452", + "col44": "9jike", + "col45": "trrv1", + "col46": "blcwr", + "col47": "ngsoh", + "col48": "yvp8r", + "col49": "k7k9e", + "col50": "hnroi", + "col51": "tbpmp", + "col52": "p8mn9", + "col53": "hxljg", + "col54": "afbx0", + "col55": "um1of", + "col56": "4zfot", + "col57": "v6z35", + "col58": "ndvtd", + "col59": "mdjmb", + "col60": "qfo6z", + "col61": "3flfj", + "col62": "ql6qu", + "col63": "gmbok", + "col64": "2olbx", + "col65": "mis3w", + "col66": "t6snf", + "col67": "ss840", + "col68": "7vbtt", + "col69": "8gtyz", + "col70": "x6bm1", + "col71": "45l9b", + "col72": "ihwln", + "col73": "37apg", + "col74": "4mrtg", + "col75": "7g74o", + "col76": "b02cl", + "col77": "46997", + "col78": "g6h6w", + "col79": "wtf5w", + "col80": "yp0a4", + "col81": "gljsa", + "col82": "bzg2z", + "col83": "k66as", + "col84": "xnsz3", + "col85": "24gem", + "col86": "hvpnx", + "col87": "ztemr", + "col88": "1vol3", + "col89": "pre55", + "col90": "11ds7", + "col91": "osi4f", + "col92": "be5pb", + "col93": "4db6m", + "col94": "n6on0", + "col95": "zp5al", + "col96": "np2i0", + "col97": "4eec3" + }, + { + "name": "Valarie Atkinson", + "gender": "female", + "company": "Hopeli", + "col0": "nmq5t", + "col1": "1qjmo", + "col2": "w6c9u", + "col3": "qragu", + "col4": "6teyd", + "col5": "zqyxd", + "col6": "lnk3w", + "col7": "6czsz", + "col8": "bjigl", + "col9": "eezx9", + "col10": "d1iiq", + "col11": "k3fmn", + "col12": "mn8xr", + "col13": "byxit", + "col14": "2u9yt", + "col15": "m17fd", + "col16": "xr5i7", + "col17": "3mnsu", + "col18": "tmyth", + "col19": "stxdy", + "col20": "uoqpl", + "col21": "x78y2", + "col22": "1kn85", + "col23": "whnff", + "col24": "5qr43", + "col25": "xq2wq", + "col26": "x1z3i", + "col27": "eu4fd", + "col28": "79kw0", + "col29": "7ml86", + "col30": "osx79", + "col31": "aj406", + "col32": "5px0t", + "col33": "c21zi", + "col34": "mnnai", + "col35": "c1pom", + "col36": "t7lpk", + "col37": "nuapy", + "col38": "w26nm", + "col39": "ai68g", + "col40": "txqkd", + "col41": "1o2vz", + "col42": "6lq81", + "col43": "onh06", + "col44": "p9kff", + "col45": "ufsx6", + "col46": "v6o4w", + "col47": "ytq3e", + "col48": "40fo9", + "col49": "15y9z", + "col50": "ezqed", + "col51": "p57v8", + "col52": "xw6sx", + "col53": "83kaa", + "col54": "w571p", + "col55": "ju7zw", + "col56": "rwue9", + "col57": "simde", + "col58": "p7mf9", + "col59": "7a07b", + "col60": "4fwre", + "col61": "9zo2k", + "col62": "omlo6", + "col63": "0mo1n", + "col64": "vwtx0", + "col65": "jtqmi", + "col66": "czbjl", + "col67": "kwub2", + "col68": "2qlad", + "col69": "3k50z", + "col70": "nrtvn", + "col71": "brnut", + "col72": "79brt", + "col73": "gwkcw", + "col74": "aahkz", + "col75": "fpy7k", + "col76": "2kets", + "col77": "zupqx", + "col78": "jmhx0", + "col79": "x8pe1", + "col80": "irk2c", + "col81": "65skf", + "col82": "5ko65", + "col83": "ev0f7", + "col84": "48p58", + "col85": "hulp0", + "col86": "tcsoa", + "col87": "3vgtn", + "col88": "nn4s5", + "col89": "7acsh", + "col90": "znvgq", + "col91": "wdqe8", + "col92": "fbjdg", + "col93": "u969l", + "col94": "suqt1", + "col95": "5dth9", + "col96": "cjxbq", + "col97": "c23zs" + }, + { + "name": "Schroeder Mathews", + "gender": "male", + "company": "Polarium", + "col0": "g5yrb", + "col1": "q1c0o", + "col2": "hcayd", + "col3": "njgtb", + "col4": "a5hms", + "col5": "bgiyh", + "col6": "ydfmj", + "col7": "u2cs7", + "col8": "tokm5", + "col9": "3oq4f", + "col10": "pwsk9", + "col11": "lqx85", + "col12": "ukdhr", + "col13": "xzy4s", + "col14": "enj88", + "col15": "czk66", + "col16": "qwitd", + "col17": "zygsz", + "col18": "nx9pq", + "col19": "7ij2j", + "col20": "2sbbq", + "col21": "ezjp4", + "col22": "x7vxk", + "col23": "eh3ub", + "col24": "32vr6", + "col25": "d1fe9", + "col26": "g5rgw", + "col27": "sww0o", + "col28": "um6vv", + "col29": "jb67n", + "col30": "97zdk", + "col31": "qyho5", + "col32": "83472", + "col33": "huo5a", + "col34": "63sr4", + "col35": "4j9pt", + "col36": "y3pz9", + "col37": "fpy38", + "col38": "rn3hf", + "col39": "39vki", + "col40": "xn6dk", + "col41": "zc6wq", + "col42": "dze4g", + "col43": "9xdkl", + "col44": "hficd", + "col45": "f42ge", + "col46": "gvb4t", + "col47": "75z8j", + "col48": "tvx26", + "col49": "sbw2e", + "col50": "7v325", + "col51": "ay1zh", + "col52": "b18rk", + "col53": "nvpx9", + "col54": "c4z4q", + "col55": "c78bd", + "col56": "m5uca", + "col57": "6o190", + "col58": "hn2xj", + "col59": "1lvds", + "col60": "wlkhl", + "col61": "i89sy", + "col62": "oohxc", + "col63": "ki4d4", + "col64": "axesb", + "col65": "n8n54", + "col66": "0o4zi", + "col67": "nbwzi", + "col68": "vijve", + "col69": "zwq06", + "col70": "sh9vo", + "col71": "nv0rp", + "col72": "zpza3", + "col73": "q0j1w", + "col74": "9rda2", + "col75": "99e68", + "col76": "tikom", + "col77": "gh29l", + "col78": "mkrd5", + "col79": "ns4ye", + "col80": "8krwf", + "col81": "lm4qj", + "col82": "q6oy6", + "col83": "x6ftv", + "col84": "9v9pa", + "col85": "8oe7z", + "col86": "128e6", + "col87": "h51ie", + "col88": "s7kt6", + "col89": "tnyc1", + "col90": "v22bm", + "col91": "cdrai", + "col92": "1wh7p", + "col93": "8t30o", + "col94": "lu9ap", + "col95": "97w27", + "col96": "sj4hd", + "col97": "xzxt7" + }, + { + "name": "Lynda Mendoza", + "gender": "female", + "company": "Dogspa", + "col0": "glgf2", + "col1": "2me4n", + "col2": "u80cz", + "col3": "42lkm", + "col4": "3y70s", + "col5": "hv4gc", + "col6": "uq2fs", + "col7": "a9p70", + "col8": "413dt", + "col9": "j4le1", + "col10": "8wqs1", + "col11": "wjzy7", + "col12": "wpd5f", + "col13": "7ktkg", + "col14": "7kc8i", + "col15": "9582k", + "col16": "giv7f", + "col17": "crbsi", + "col18": "56ayp", + "col19": "zpue9", + "col20": "p1rce", + "col21": "l4bpp", + "col22": "kc8bb", + "col23": "woab3", + "col24": "s3m55", + "col25": "j0hnr", + "col26": "t7aem", + "col27": "vrm62", + "col28": "taxub", + "col29": "2q08n", + "col30": "q9fb8", + "col31": "k0jo2", + "col32": "8d11m", + "col33": "ao74z", + "col34": "tu151", + "col35": "k4im3", + "col36": "dfoyt", + "col37": "ym0tx", + "col38": "7iasq", + "col39": "grmxt", + "col40": "sh4h6", + "col41": "7po2g", + "col42": "z6dwz", + "col43": "cp8zp", + "col44": "5fvcx", + "col45": "xxfnf", + "col46": "kguvd", + "col47": "qmf3c", + "col48": "sbr9y", + "col49": "2synk", + "col50": "piucy", + "col51": "njb34", + "col52": "1mfw9", + "col53": "9qdv9", + "col54": "zk2pr", + "col55": "gcd7n", + "col56": "eocv0", + "col57": "smmfl", + "col58": "x4ljd", + "col59": "80zpk", + "col60": "czxie", + "col61": "d6q4d", + "col62": "vlpy8", + "col63": "qmtqh", + "col64": "iozj6", + "col65": "qeluf", + "col66": "xv1cp", + "col67": "x8yu8", + "col68": "47fl7", + "col69": "njrw7", + "col70": "sz8ja", + "col71": "5nzoi", + "col72": "ixcfj", + "col73": "v197n", + "col74": "tud03", + "col75": "qhb1o", + "col76": "i63l6", + "col77": "ytynj", + "col78": "6y4vz", + "col79": "zwnlz", + "col80": "jzm2e", + "col81": "zr2sb", + "col82": "yhtxg", + "col83": "9qvy6", + "col84": "k7m0a", + "col85": "hbb6k", + "col86": "8z6oi", + "col87": "qr7sr", + "col88": "tot52", + "col89": "mqsrs", + "col90": "bdx8l", + "col91": "rchn6", + "col92": "jdej4", + "col93": "0lpyo", + "col94": "j5cfp", + "col95": "4ag50", + "col96": "ewnld", + "col97": "qknxg" + }, + { + "name": "Sarah Massey", + "gender": "female", + "company": "Bisba", + "col0": "2fy73", + "col1": "ptmz0", + "col2": "wv6kn", + "col3": "7a5ub", + "col4": "xb72s", + "col5": "95v74", + "col6": "kwpg2", + "col7": "bt3dr", + "col8": "qqkw0", + "col9": "pqt56", + "col10": "sbxnb", + "col11": "taltb", + "col12": "135xr", + "col13": "e3y3w", + "col14": "hl2pu", + "col15": "phfa1", + "col16": "7drmb", + "col17": "71uzc", + "col18": "cco70", + "col19": "qny45", + "col20": "4gcy1", + "col21": "a6smg", + "col22": "d3ekq", + "col23": "xzemm", + "col24": "3b9x6", + "col25": "xz2ao", + "col26": "zwodl", + "col27": "p0irg", + "col28": "3b76f", + "col29": "ttyh4", + "col30": "nykm5", + "col31": "rtlc7", + "col32": "9dl8c", + "col33": "51lrb", + "col34": "3dlm8", + "col35": "ggn1n", + "col36": "nvjkm", + "col37": "2u9eh", + "col38": "fbdht", + "col39": "8p59j", + "col40": "li2sq", + "col41": "7yafi", + "col42": "cmtuc", + "col43": "zrjmp", + "col44": "8sux5", + "col45": "6a8cu", + "col46": "1o0ej", + "col47": "ify6i", + "col48": "jah3l", + "col49": "bzyl3", + "col50": "6g4bj", + "col51": "pusc9", + "col52": "3aqw2", + "col53": "4akq5", + "col54": "1800r", + "col55": "ezkux", + "col56": "6tkkw", + "col57": "zr13g", + "col58": "y79xg", + "col59": "63wxb", + "col60": "y6t43", + "col61": "dyhap", + "col62": "ausv2", + "col63": "k1pzc", + "col64": "mso08", + "col65": "aclkp", + "col66": "3v757", + "col67": "ltcou", + "col68": "937d2", + "col69": "4nl0k", + "col70": "r59v4", + "col71": "d7cji", + "col72": "xmcke", + "col73": "4zwwk", + "col74": "5vpki", + "col75": "hzeba", + "col76": "axb9d", + "col77": "2gmjm", + "col78": "xpy5z", + "col79": "nu4ur", + "col80": "jzy70", + "col81": "pjbfu", + "col82": "x5qgk", + "col83": "3b9h9", + "col84": "v8fms", + "col85": "pmp8k", + "col86": "6ariq", + "col87": "ctvm5", + "col88": "16ilv", + "col89": "5hjq1", + "col90": "tydou", + "col91": "rl3zw", + "col92": "o0y9v", + "col93": "xoctc", + "col94": "iu50m", + "col95": "k74rc", + "col96": "0twm0", + "col97": "gj8lb" + }, + { + "name": "Robles Boyle", + "gender": "male", + "company": "Comtract", + "col0": "xpb6y", + "col1": "n11qj", + "col2": "pi2xl", + "col3": "xpglm", + "col4": "2ujw8", + "col5": "jlpwy", + "col6": "547vz", + "col7": "wovv6", + "col8": "b0w1d", + "col9": "3ayhl", + "col10": "8gjn6", + "col11": "kbhhk", + "col12": "cqc2s", + "col13": "uxobs", + "col14": "jp1f5", + "col15": "jtl7d", + "col16": "8sxfl", + "col17": "of9ju", + "col18": "v8d57", + "col19": "rd792", + "col20": "va4qm", + "col21": "3z2zf", + "col22": "hji8k", + "col23": "6mkca", + "col24": "r219g", + "col25": "q31zj", + "col26": "q9yin", + "col27": "olov9", + "col28": "ouor1", + "col29": "ykrn3", + "col30": "lartd", + "col31": "ls55u", + "col32": "8mts3", + "col33": "igqxw", + "col34": "lpwli", + "col35": "zmjqj", + "col36": "bvt9w", + "col37": "wzdva", + "col38": "2d03o", + "col39": "qfkbe", + "col40": "9mi90", + "col41": "364eh", + "col42": "bwfbo", + "col43": "g4aa1", + "col44": "vrtim", + "col45": "kjhmb", + "col46": "qirrf", + "col47": "utzr9", + "col48": "a3psv", + "col49": "5319x", + "col50": "dtjgc", + "col51": "atfwl", + "col52": "rc39u", + "col53": "jei4x", + "col54": "1rkhk", + "col55": "dtmjw", + "col56": "vlvho", + "col57": "e63l7", + "col58": "u5uqm", + "col59": "383o2", + "col60": "8dh4h", + "col61": "nd6fo", + "col62": "ukx1l", + "col63": "mheqb", + "col64": "ncnd0", + "col65": "i0cyt", + "col66": "31dsq", + "col67": "w96k7", + "col68": "939x5", + "col69": "p4rsd", + "col70": "yy68x", + "col71": "7urz1", + "col72": "73fkm", + "col73": "v0vkz", + "col74": "8aujt", + "col75": "s3we8", + "col76": "w74sx", + "col77": "m1tnz", + "col78": "y4jbt", + "col79": "nlm7a", + "col80": "lepyc", + "col81": "no35b", + "col82": "v0553", + "col83": "wibgb", + "col84": "2rb39", + "col85": "o2p5a", + "col86": "mm4ve", + "col87": "yhznx", + "col88": "wthgj", + "col89": "7yc0i", + "col90": "nbgs0", + "col91": "l6s32", + "col92": "zi9dy", + "col93": "ojlyo", + "col94": "4xahn", + "col95": "kf0va", + "col96": "5z7vm", + "col97": "wfss6" + }, + { + "name": "Evans Hickman", + "gender": "male", + "company": "Parleynet", + "col0": "4g8iw", + "col1": "q2vgw", + "col2": "6niyv", + "col3": "yui4k", + "col4": "ua51a", + "col5": "h4gfz", + "col6": "7avnf", + "col7": "gv3a3", + "col8": "l0bt4", + "col9": "eui1n", + "col10": "x1zv4", + "col11": "iqq45", + "col12": "e0ppu", + "col13": "4q8p6", + "col14": "0jphq", + "col15": "brq6p", + "col16": "z1o84", + "col17": "5vz1p", + "col18": "cuogt", + "col19": "gm1b3", + "col20": "sae35", + "col21": "me8su", + "col22": "92z3t", + "col23": "db3on", + "col24": "od2hc", + "col25": "qs2jp", + "col26": "a57yb", + "col27": "sdszr", + "col28": "915pq", + "col29": "jzh4a", + "col30": "e2iew", + "col31": "534n8", + "col32": "vmi6f", + "col33": "tvs7p", + "col34": "vv6dn", + "col35": "muvjh", + "col36": "u9do9", + "col37": "fsww8", + "col38": "hpi18", + "col39": "3vr2y", + "col40": "vz7vh", + "col41": "dsrj2", + "col42": "fbfyc", + "col43": "pxy3h", + "col44": "q5myo", + "col45": "mbd41", + "col46": "o0b6f", + "col47": "e245r", + "col48": "wd1il", + "col49": "5fjyb", + "col50": "hsf6s", + "col51": "y0kh0", + "col52": "zwe0a", + "col53": "011je", + "col54": "nth95", + "col55": "oaz7e", + "col56": "m9ka2", + "col57": "rmq6y", + "col58": "ww6kr", + "col59": "86gaq", + "col60": "3spsi", + "col61": "y14bc", + "col62": "ci8wd", + "col63": "38qkc", + "col64": "aoy6y", + "col65": "qdtcj", + "col66": "56kw5", + "col67": "sil04", + "col68": "6bqwm", + "col69": "0lzvw", + "col70": "c1c04", + "col71": "euur4", + "col72": "pcgwt", + "col73": "4np5n", + "col74": "9v5nj", + "col75": "94eoc", + "col76": "7ibph", + "col77": "m7fg6", + "col78": "nwdih", + "col79": "427z6", + "col80": "bjpc8", + "col81": "b6853", + "col82": "xjcmk", + "col83": "396hu", + "col84": "8u7bk", + "col85": "qrdd0", + "col86": "h0a8y", + "col87": "cdips", + "col88": "t26pn", + "col89": "w75gz", + "col90": "qguy2", + "col91": "owhh9", + "col92": "7i61v", + "col93": "7ed9c", + "col94": "earyg", + "col95": "gaujz", + "col96": "9ezjy", + "col97": "afixq" + }, + { + "name": "Dawson Barber", + "gender": "male", + "company": "Dymi", + "col0": "unf5p", + "col1": "xnte1", + "col2": "a2bht", + "col3": "urk2q", + "col4": "kuegn", + "col5": "7yz7a", + "col6": "w8o8f", + "col7": "ce615", + "col8": "uigvw", + "col9": "yr85m", + "col10": "z2u4l", + "col11": "q0b9e", + "col12": "yrrd2", + "col13": "jcn58", + "col14": "unn6p", + "col15": "q0jw0", + "col16": "kw6vm", + "col17": "u4088", + "col18": "2ktas", + "col19": "9ka4e", + "col20": "98tlt", + "col21": "lcl7a", + "col22": "unm1i", + "col23": "rfvlm", + "col24": "0mykl", + "col25": "0r18a", + "col26": "qlmel", + "col27": "et91w", + "col28": "av6ew", + "col29": "fxz3j", + "col30": "hjna3", + "col31": "37h0n", + "col32": "49sea", + "col33": "5q8kg", + "col34": "lw8zj", + "col35": "go7uk", + "col36": "i31c8", + "col37": "ne3ym", + "col38": "q5jaf", + "col39": "9xb5f", + "col40": "44hp9", + "col41": "k0oif", + "col42": "ahoc9", + "col43": "wnnlb", + "col44": "kme6s", + "col45": "b8wck", + "col46": "9qka1", + "col47": "kkvkw", + "col48": "d1tw1", + "col49": "xeaib", + "col50": "b2xhc", + "col51": "tdo8n", + "col52": "z3gz6", + "col53": "wmca4", + "col54": "s1wwx", + "col55": "9pzku", + "col56": "18b9s", + "col57": "aiquz", + "col58": "ygy1e", + "col59": "8z9cj", + "col60": "5kt4i", + "col61": "es0dv", + "col62": "5knrs", + "col63": "27eb6", + "col64": "b859a", + "col65": "logum", + "col66": "pvm62", + "col67": "d1x8q", + "col68": "iy69q", + "col69": "7md6w", + "col70": "d3ny9", + "col71": "zoiou", + "col72": "58v1y", + "col73": "2ggxz", + "col74": "af40d", + "col75": "agvlj", + "col76": "lyomr", + "col77": "nlxia", + "col78": "1zwi4", + "col79": "hy0k3", + "col80": "h62hq", + "col81": "6h8z0", + "col82": "awbgt", + "col83": "c9znr", + "col84": "s3w6h", + "col85": "i8zj4", + "col86": "6cn49", + "col87": "nbvom", + "col88": "n25xa", + "col89": "5cafr", + "col90": "1ke0o", + "col91": "yusr2", + "col92": "mvrul", + "col93": "ca169", + "col94": "ukw6c", + "col95": "zbfvs", + "col96": "hnrv7", + "col97": "q0cox" + }, + { + "name": "Bruce Strong", + "gender": "male", + "company": "Xyqag", + "col0": "twwio", + "col1": "be1bs", + "col2": "1navp", + "col3": "l0q1k", + "col4": "wzw6y", + "col5": "0gzfn", + "col6": "9zgpm", + "col7": "3jilb", + "col8": "3hues", + "col9": "f08ss", + "col10": "h7fhx", + "col11": "98nzq", + "col12": "a5sdw", + "col13": "vlpsk", + "col14": "satbc", + "col15": "qdtjk", + "col16": "clmqj", + "col17": "9mijx", + "col18": "wsx2w", + "col19": "fhozv", + "col20": "rm25w", + "col21": "l95ie", + "col22": "s4pqc", + "col23": "0apkn", + "col24": "y2fnm", + "col25": "fz81i", + "col26": "9968y", + "col27": "2vg4z", + "col28": "oy9bp", + "col29": "zaoei", + "col30": "zogc8", + "col31": "zr71h", + "col32": "ol64q", + "col33": "3gkgp", + "col34": "vhg1m", + "col35": "arq7p", + "col36": "uieyf", + "col37": "1oj1e", + "col38": "e3nmc", + "col39": "g7f88", + "col40": "vts3z", + "col41": "dtnbr", + "col42": "cdvu0", + "col43": "af04b", + "col44": "rioay", + "col45": "7y11e", + "col46": "kal10", + "col47": "sw5t2", + "col48": "wx5gy", + "col49": "6ewyv", + "col50": "8t1le", + "col51": "30vp8", + "col52": "d6m4m", + "col53": "n126y", + "col54": "nxiwg", + "col55": "n0u3a", + "col56": "1xi3a", + "col57": "eocq0", + "col58": "8onkc", + "col59": "wf44c", + "col60": "vgawu", + "col61": "1r6fv", + "col62": "3yij9", + "col63": "qaj77", + "col64": "o19c5", + "col65": "ber8q", + "col66": "790an", + "col67": "so97e", + "col68": "nmwrt", + "col69": "jbgcq", + "col70": "1al4c", + "col71": "vg80v", + "col72": "jwm7p", + "col73": "zub5k", + "col74": "jmpag", + "col75": "umuj3", + "col76": "szcyd", + "col77": "vv8u1", + "col78": "6ojrw", + "col79": "tbq2s", + "col80": "r73u1", + "col81": "rmex7", + "col82": "xlbnc", + "col83": "4h426", + "col84": "sj3br", + "col85": "k4lyl", + "col86": "jqev3", + "col87": "xsy46", + "col88": "wc82y", + "col89": "svt4y", + "col90": "n1zaa", + "col91": "h0tae", + "col92": "4e9jc", + "col93": "52nsf", + "col94": "mghmn", + "col95": "2fiwh", + "col96": "cbg23", + "col97": "cj6xb" + }, + { + "name": "Nellie Whitfield", + "gender": "female", + "company": "Exospace", + "col0": "039d3", + "col1": "4kso3", + "col2": "t91f7", + "col3": "10nde", + "col4": "zbehp", + "col5": "faztr", + "col6": "wzz5h", + "col7": "y0dvv", + "col8": "wphk0", + "col9": "r6vsz", + "col10": "q5gbt", + "col11": "hqmo5", + "col12": "lcifs", + "col13": "qd3vn", + "col14": "rqmwl", + "col15": "fj3ls", + "col16": "dutjo", + "col17": "d5ozi", + "col18": "bdg0x", + "col19": "rdfl2", + "col20": "c8da3", + "col21": "j6gct", + "col22": "3ohzh", + "col23": "fjraj", + "col24": "gwd33", + "col25": "6t8tk", + "col26": "x3f48", + "col27": "lq0hz", + "col28": "ad6sy", + "col29": "z4oat", + "col30": "6o9o3", + "col31": "07tc6", + "col32": "p64fa", + "col33": "a3bai", + "col34": "qa3b3", + "col35": "pxmpk", + "col36": "z7048", + "col37": "9ytpv", + "col38": "q1zec", + "col39": "egjhd", + "col40": "vhbfx", + "col41": "i2yu1", + "col42": "fubmz", + "col43": "h0wjd", + "col44": "whxc9", + "col45": "e3vzr", + "col46": "249j6", + "col47": "rkwch", + "col48": "1awu1", + "col49": "lvw4c", + "col50": "n5nvi", + "col51": "k45pa", + "col52": "qtknx", + "col53": "0rlfy", + "col54": "jfegv", + "col55": "gk8kg", + "col56": "e6qdw", + "col57": "vki3h", + "col58": "t4i12", + "col59": "ixrgq", + "col60": "wd7ez", + "col61": "wns4g", + "col62": "7f3ra", + "col63": "hnf0f", + "col64": "2hvf6", + "col65": "hgi9z", + "col66": "shnqn", + "col67": "qxa6t", + "col68": "y3uy5", + "col69": "il3rj", + "col70": "iisd6", + "col71": "tfgj7", + "col72": "16kac", + "col73": "rokmw", + "col74": "r0znm", + "col75": "bhm0v", + "col76": "xl1cy", + "col77": "3g72a", + "col78": "d8ll7", + "col79": "0haoh", + "col80": "djs6x", + "col81": "lfsc3", + "col82": "6z2nu", + "col83": "u1yqj", + "col84": "gcgyx", + "col85": "ixm61", + "col86": "n0g0h", + "col87": "ptlw8", + "col88": "iiwxn", + "col89": "m6mpm", + "col90": "tuzxw", + "col91": "5akd4", + "col92": "f4pwh", + "col93": "d77se", + "col94": "nm0re", + "col95": "g92iw", + "col96": "g5dt9", + "col97": "y5fj2" + }, + { + "name": "Jackson Macias", + "gender": "male", + "company": "Aquamate", + "col0": "0mrce", + "col1": "584g2", + "col2": "gf8hs", + "col3": "sc9ue", + "col4": "mcs7j", + "col5": "otixq", + "col6": "xnhze", + "col7": "ly6zb", + "col8": "w008m", + "col9": "49n28", + "col10": "nvzws", + "col11": "0w327", + "col12": "5pewa", + "col13": "0e3so", + "col14": "5cka0", + "col15": "7p5gx", + "col16": "26m9n", + "col17": "8tk8b", + "col18": "8ba4o", + "col19": "nd8pj", + "col20": "b9ggb", + "col21": "8krt5", + "col22": "izsjz", + "col23": "owuyd", + "col24": "dmm3o", + "col25": "dll0q", + "col26": "xifq1", + "col27": "f7st6", + "col28": "czbdn", + "col29": "c3l8m", + "col30": "vjky3", + "col31": "orv6p", + "col32": "xljaj", + "col33": "5875w", + "col34": "kli3n", + "col35": "txy36", + "col36": "1vlp3", + "col37": "mhdlu", + "col38": "iq4jf", + "col39": "ivul7", + "col40": "hrxx8", + "col41": "hvreq", + "col42": "5tmmv", + "col43": "6lp8h", + "col44": "383d8", + "col45": "lvn9n", + "col46": "nsdvp", + "col47": "zw3lk", + "col48": "y51xp", + "col49": "gd4ol", + "col50": "ern63", + "col51": "hxvny", + "col52": "bk6ar", + "col53": "bh304", + "col54": "a94wp", + "col55": "33kid", + "col56": "prhj0", + "col57": "i2pyb", + "col58": "9bpsd", + "col59": "d7zet", + "col60": "ey9ib", + "col61": "93hbi", + "col62": "mpyum", + "col63": "con9c", + "col64": "3w6zk", + "col65": "4fahx", + "col66": "gv136", + "col67": "slpbs", + "col68": "oy67j", + "col69": "n9j16", + "col70": "e8i1j", + "col71": "kwgre", + "col72": "xe5tg", + "col73": "f086x", + "col74": "czvk2", + "col75": "xkdp8", + "col76": "vrcig", + "col77": "xzsdr", + "col78": "e7owi", + "col79": "o9x77", + "col80": "p2zd5", + "col81": "fpu9u", + "col82": "fyf28", + "col83": "iphor", + "col84": "ywzb4", + "col85": "scne9", + "col86": "zprk2", + "col87": "wdnrj", + "col88": "159vf", + "col89": "vl18r", + "col90": "q2msk", + "col91": "7nl8k", + "col92": "wy7ly", + "col93": "pz7r1", + "col94": "c2fmm", + "col95": "iy13g", + "col96": "glxlt", + "col97": "9wuu7" + }, + { + "name": "Pena Pena", + "gender": "male", + "company": "Quarx", + "col0": "p3uhb", + "col1": "agr9f", + "col2": "uaz1a", + "col3": "7foce", + "col4": "mle05", + "col5": "v0gsj", + "col6": "pcyv6", + "col7": "83t2j", + "col8": "h4dix", + "col9": "4hxiy", + "col10": "8i1zi", + "col11": "u0t4s", + "col12": "vj5vt", + "col13": "oxxe1", + "col14": "o6d77", + "col15": "b99fj", + "col16": "lfyyz", + "col17": "c4mh7", + "col18": "5tmjy", + "col19": "f1bqh", + "col20": "cd0n7", + "col21": "tkjat", + "col22": "32ghw", + "col23": "mgf4g", + "col24": "hsox5", + "col25": "cpfjj", + "col26": "lfxgg", + "col27": "sggtu", + "col28": "p870t", + "col29": "7udxp", + "col30": "8q3y1", + "col31": "hawd2", + "col32": "iifi6", + "col33": "uwjhu", + "col34": "47vxp", + "col35": "k71s9", + "col36": "nl3t8", + "col37": "ogvjf", + "col38": "h0z3l", + "col39": "t0mbc", + "col40": "9xpwi", + "col41": "zpp3i", + "col42": "x4ssl", + "col43": "5rawv", + "col44": "6vr5u", + "col45": "7wkd1", + "col46": "a6s17", + "col47": "40ola", + "col48": "gs9re", + "col49": "nu69d", + "col50": "bwdou", + "col51": "wsczf", + "col52": "aiuwf", + "col53": "ajup0", + "col54": "zpv5t", + "col55": "bhplh", + "col56": "e708x", + "col57": "88zdr", + "col58": "kw7gb", + "col59": "mncfe", + "col60": "agg1r", + "col61": "x3bls", + "col62": "yiij5", + "col63": "8pwni", + "col64": "hb06m", + "col65": "z7ipn", + "col66": "90hjp", + "col67": "ukl5p", + "col68": "2qxdb", + "col69": "cthjo", + "col70": "hy516", + "col71": "8eu7v", + "col72": "hmv5j", + "col73": "eqim8", + "col74": "onrla", + "col75": "lju9q", + "col76": "fsk6q", + "col77": "c3cyl", + "col78": "twvay", + "col79": "5012p", + "col80": "5mcel", + "col81": "4lt3u", + "col82": "f9cdo", + "col83": "8elok", + "col84": "4fm0m", + "col85": "yq0fy", + "col86": "z1e85", + "col87": "37n9l", + "col88": "jyloo", + "col89": "sr3lm", + "col90": "j6ses", + "col91": "jvari", + "col92": "pgqob", + "col93": "y9kfx", + "col94": "n4xtj", + "col95": "4n8ub", + "col96": "5ahi9", + "col97": "rehwf" + }, + { + "name": "Lelia Gates", + "gender": "female", + "company": "Proxsoft", + "col0": "igh3u", + "col1": "ke0fx", + "col2": "rsj4b", + "col3": "xy9c7", + "col4": "184l5", + "col5": "3yfhb", + "col6": "9g53u", + "col7": "ppyml", + "col8": "3tbcp", + "col9": "v3w93", + "col10": "q4njv", + "col11": "nd1eg", + "col12": "nuq2y", + "col13": "rqb2h", + "col14": "bn6w4", + "col15": "cvcsa", + "col16": "c1k6v", + "col17": "8556i", + "col18": "w1nix", + "col19": "d2kge", + "col20": "h085m", + "col21": "wvo5j", + "col22": "yqx6f", + "col23": "lnam4", + "col24": "ekn2q", + "col25": "cilwr", + "col26": "2n8yh", + "col27": "cs1k9", + "col28": "4avi2", + "col29": "2whoo", + "col30": "763xk", + "col31": "t9vs0", + "col32": "8vy2f", + "col33": "wdydo", + "col34": "q6zao", + "col35": "p6jnq", + "col36": "zkso6", + "col37": "w1jc1", + "col38": "ll7ec", + "col39": "qg895", + "col40": "m8aik", + "col41": "l9u35", + "col42": "ffre4", + "col43": "56gjg", + "col44": "6992u", + "col45": "htut9", + "col46": "iiulc", + "col47": "ibasb", + "col48": "slc9k", + "col49": "b9ek0", + "col50": "0v26s", + "col51": "rr866", + "col52": "ty4le", + "col53": "9ny67", + "col54": "9dbbt", + "col55": "l0qbi", + "col56": "z5g1h", + "col57": "2lryw", + "col58": "77ka2", + "col59": "3fjw9", + "col60": "3nt3f", + "col61": "wdw6p", + "col62": "oqk2s", + "col63": "z9tbl", + "col64": "001k3", + "col65": "tqovx", + "col66": "4e1b8", + "col67": "h3zx4", + "col68": "ipgm9", + "col69": "wq97n", + "col70": "fvsup", + "col71": "ryz77", + "col72": "benaf", + "col73": "1orbo", + "col74": "fcai5", + "col75": "s2m4e", + "col76": "enl1i", + "col77": "cz55q", + "col78": "3n406", + "col79": "2plli", + "col80": "qtodc", + "col81": "hmodp", + "col82": "927ja", + "col83": "3yp7v", + "col84": "zrff1", + "col85": "9rgax", + "col86": "g4obp", + "col87": "awqrw", + "col88": "1d17m", + "col89": "stymu", + "col90": "qybf5", + "col91": "2qswk", + "col92": "q3d94", + "col93": "b09if", + "col94": "49awq", + "col95": "1fn8p", + "col96": "cf6kg", + "col97": "tuffx" + }, + { + "name": "Letitia Vasquez", + "gender": "female", + "company": "Slumberia", + "col0": "fel1v", + "col1": "4rf6a", + "col2": "tpazu", + "col3": "80x22", + "col4": "ntcdp", + "col5": "jvhf3", + "col6": "u1eq3", + "col7": "rr81u", + "col8": "r6aw1", + "col9": "o6s4v", + "col10": "1nh2v", + "col11": "9fpuf", + "col12": "gver9", + "col13": "4pqdh", + "col14": "uveao", + "col15": "e9ez0", + "col16": "gr8az", + "col17": "onu9q", + "col18": "srxke", + "col19": "ih5dd", + "col20": "jm9ak", + "col21": "igb7i", + "col22": "tzp5n", + "col23": "4o3vz", + "col24": "lvl3v", + "col25": "k1i7b", + "col26": "ky1y3", + "col27": "xh6vi", + "col28": "2s49r", + "col29": "tumeq", + "col30": "7lopy", + "col31": "8wc17", + "col32": "r0qq5", + "col33": "iw5f2", + "col34": "5pm3b", + "col35": "l8mkz", + "col36": "75npt", + "col37": "bzrjz", + "col38": "vmrqv", + "col39": "xcrch", + "col40": "zd1gp", + "col41": "0z40q", + "col42": "mmnk8", + "col43": "b2r01", + "col44": "y005a", + "col45": "nengv", + "col46": "b3jml", + "col47": "steoo", + "col48": "34efa", + "col49": "s1so3", + "col50": "iagtx", + "col51": "t4bvk", + "col52": "zenup", + "col53": "ic46i", + "col54": "0ar8j", + "col55": "kfi5e", + "col56": "ylze2", + "col57": "fcfdp", + "col58": "9jwts", + "col59": "uk7ad", + "col60": "po9n5", + "col61": "hzpjj", + "col62": "agngg", + "col63": "t6ual", + "col64": "pf63f", + "col65": "pup2e", + "col66": "xs0bm", + "col67": "9bzc8", + "col68": "6llr5", + "col69": "0x5rz", + "col70": "5fe7a", + "col71": "uu2rc", + "col72": "0ucb3", + "col73": "qu71z", + "col74": "q37ta", + "col75": "bxjw5", + "col76": "58ni2", + "col77": "iilxc", + "col78": "namcz", + "col79": "8l7su", + "col80": "is45n", + "col81": "iazf6", + "col82": "eklk8", + "col83": "mhpkq", + "col84": "kfkki", + "col85": "dyvv6", + "col86": "a7gs0", + "col87": "jm1rm", + "col88": "2ts4w", + "col89": "z9d80", + "col90": "k1l3d", + "col91": "2v5ld", + "col92": "ahkm1", + "col93": "ab3g6", + "col94": "c07qj", + "col95": "8v83u", + "col96": "npf44", + "col97": "2m41v" + }, + { + "name": "Trevino Moreno", + "gender": "male", + "company": "Conjurica", + "col0": "yt6ma", + "col1": "i1pxp", + "col2": "ywooa", + "col3": "6jl1o", + "col4": "ou0ix", + "col5": "283nv", + "col6": "lbugh", + "col7": "jt9qe", + "col8": "57c92", + "col9": "c467c", + "col10": "tygkh", + "col11": "l1f0m", + "col12": "23gzz", + "col13": "qikrw", + "col14": "2c086", + "col15": "j7v2a", + "col16": "h1paw", + "col17": "nvza9", + "col18": "uezzo", + "col19": "zby8b", + "col20": "3537e", + "col21": "64mvj", + "col22": "3fizh", + "col23": "3cx58", + "col24": "tplpx", + "col25": "3aijt", + "col26": "qep8p", + "col27": "58v96", + "col28": "z0641", + "col29": "d4qqn", + "col30": "vxp3l", + "col31": "kf7jq", + "col32": "vujxg", + "col33": "agt16", + "col34": "2udp9", + "col35": "euz2r", + "col36": "lwwb0", + "col37": "dwxo9", + "col38": "8yuou", + "col39": "hlpcm", + "col40": "tnfot", + "col41": "e3onk", + "col42": "dytrj", + "col43": "luw1f", + "col44": "qao9t", + "col45": "racnp", + "col46": "yipw6", + "col47": "zh6vq", + "col48": "sqi4d", + "col49": "0chj8", + "col50": "qpwqs", + "col51": "aaelv", + "col52": "a5nvj", + "col53": "nlcml", + "col54": "s8itn", + "col55": "rpglf", + "col56": "psjgn", + "col57": "6w8gn", + "col58": "sct8c", + "col59": "ubfpn", + "col60": "os3jh", + "col61": "c7wyz", + "col62": "bzhly", + "col63": "fkml7", + "col64": "xw4cl", + "col65": "h7f1a", + "col66": "cv2xe", + "col67": "w4f1o", + "col68": "zqjar", + "col69": "r9aie", + "col70": "wlxcn", + "col71": "ygf2c", + "col72": "m2zb1", + "col73": "4xszo", + "col74": "xq8lk", + "col75": "sl20o", + "col76": "jwf87", + "col77": "rlyy2", + "col78": "y98uj", + "col79": "n22ru", + "col80": "hnjls", + "col81": "skndq", + "col82": "unw2d", + "col83": "hl2qe", + "col84": "507gc", + "col85": "5grw0", + "col86": "hziov", + "col87": "bkywi", + "col88": "m0g3r", + "col89": "uonnq", + "col90": "dqff2", + "col91": "azi63", + "col92": "pf4ih", + "col93": "blub2", + "col94": "q7ovd", + "col95": "5orzy", + "col96": "b44ng", + "col97": "th7g0" + }, + { + "name": "Barr Page", + "gender": "male", + "company": "Apex", + "col0": "fx7cl", + "col1": "s4vxr", + "col2": "h5e7h", + "col3": "nw0t1", + "col4": "zgreu", + "col5": "ycxlw", + "col6": "6u50z", + "col7": "o62ku", + "col8": "c6wbb", + "col9": "iy965", + "col10": "j23mt", + "col11": "0spc1", + "col12": "vue17", + "col13": "ja1pj", + "col14": "df28u", + "col15": "omh0i", + "col16": "j8u7t", + "col17": "q5vu2", + "col18": "1x1iz", + "col19": "aq3pd", + "col20": "toumy", + "col21": "sb6rp", + "col22": "5l1qe", + "col23": "lppyj", + "col24": "olp9b", + "col25": "v3yko", + "col26": "5ymqj", + "col27": "3usex", + "col28": "ty8h5", + "col29": "vdmdr", + "col30": "wezpi", + "col31": "th8t0", + "col32": "5xpbi", + "col33": "plcv1", + "col34": "87nt5", + "col35": "s0qpe", + "col36": "z8phy", + "col37": "ppmp2", + "col38": "gzlrm", + "col39": "krkjq", + "col40": "17ub5", + "col41": "enpad", + "col42": "4mcxr", + "col43": "3b2qn", + "col44": "uwe6c", + "col45": "98s2r", + "col46": "s5zry", + "col47": "31boc", + "col48": "uxqfb", + "col49": "57v25", + "col50": "ktg4w", + "col51": "4lvbt", + "col52": "3knq7", + "col53": "d76ra", + "col54": "nrlf1", + "col55": "7w14v", + "col56": "axo5q", + "col57": "b8ave", + "col58": "weyyq", + "col59": "bbci9", + "col60": "l5ba7", + "col61": "bvs7r", + "col62": "2zf4m", + "col63": "m8gyc", + "col64": "23468", + "col65": "q66oh", + "col66": "8pun7", + "col67": "kv570", + "col68": "9u935", + "col69": "2caj3", + "col70": "f8vbn", + "col71": "r9mcr", + "col72": "4zlh0", + "col73": "8g7u6", + "col74": "p4o8m", + "col75": "5ivp7", + "col76": "47n1q", + "col77": "prdyc", + "col78": "wo39z", + "col79": "lb99l", + "col80": "ijuhu", + "col81": "zlp0g", + "col82": "jrzi7", + "col83": "5lpzj", + "col84": "90fsk", + "col85": "4r11h", + "col86": "kkz8j", + "col87": "39j1f", + "col88": "ig8pz", + "col89": "dr3tc", + "col90": "8xj9e", + "col91": "izw4g", + "col92": "87wrl", + "col93": "a5sid", + "col94": "adgeq", + "col95": "7houx", + "col96": "fb8pf", + "col97": "ybd78" + }, + { + "name": "Kirkland Merrill", + "gender": "male", + "company": "Utara", + "col0": "v81uo", + "col1": "l1v34", + "col2": "7a0my", + "col3": "vr4nv", + "col4": "fuogq", + "col5": "0kjdf", + "col6": "h00cz", + "col7": "smdny", + "col8": "dsngg", + "col9": "57pcp", + "col10": "l5hb5", + "col11": "01rqz", + "col12": "hooi6", + "col13": "ktbpp", + "col14": "n8gl5", + "col15": "iku7t", + "col16": "31g2a", + "col17": "bgx4t", + "col18": "r6gn1", + "col19": "4hu88", + "col20": "x4a08", + "col21": "vlni2", + "col22": "jn97n", + "col23": "jzu4t", + "col24": "u958t", + "col25": "hly1j", + "col26": "ol4bv", + "col27": "btegf", + "col28": "vtggy", + "col29": "iky1a", + "col30": "c3ceq", + "col31": "i55il", + "col32": "b4iow", + "col33": "p8cd2", + "col34": "qdbjo", + "col35": "2rkz5", + "col36": "nwq7w", + "col37": "hr5mv", + "col38": "oojmn", + "col39": "m0h52", + "col40": "3ctm7", + "col41": "kpceb", + "col42": "bs73r", + "col43": "c06rh", + "col44": "1r0vj", + "col45": "ab6pe", + "col46": "dpyg8", + "col47": "dw3su", + "col48": "h3n86", + "col49": "pp4nd", + "col50": "5gkz5", + "col51": "mzfu7", + "col52": "bmvy4", + "col53": "xgdz1", + "col54": "n5f9t", + "col55": "e9kcy", + "col56": "cv7hg", + "col57": "9hohr", + "col58": "88jic", + "col59": "4pt2c", + "col60": "rlhb3", + "col61": "k6bhf", + "col62": "sqyfg", + "col63": "0wq2y", + "col64": "wqm1o", + "col65": "1k94g", + "col66": "42wey", + "col67": "7jk18", + "col68": "xn7n9", + "col69": "d2ryh", + "col70": "i83o7", + "col71": "fyf2p", + "col72": "pak9w", + "col73": "uwy6d", + "col74": "ye0hx", + "col75": "p61ot", + "col76": "qdhqx", + "col77": "q3srr", + "col78": "yyzam", + "col79": "ingp2", + "col80": "u9ifg", + "col81": "adttf", + "col82": "3qfyz", + "col83": "iwfmr", + "col84": "95s3a", + "col85": "cqkts", + "col86": "49xsw", + "col87": "mkot5", + "col88": "l8yc3", + "col89": "dejyd", + "col90": "fbr5z", + "col91": "9t9es", + "col92": "svljx", + "col93": "6txbh", + "col94": "4asz5", + "col95": "c5ex1", + "col96": "qmhxs", + "col97": "k4ckb" + }, + { + "name": "Blanche Conley", + "gender": "female", + "company": "Imkan", + "col0": "wpn9p", + "col1": "o3a5p", + "col2": "kn5xn", + "col3": "9cirk", + "col4": "lyc5w", + "col5": "51voc", + "col6": "octl7", + "col7": "m2aps", + "col8": "8anr6", + "col9": "ou4l3", + "col10": "lx4q0", + "col11": "6ka9z", + "col12": "a0sho", + "col13": "oqsay", + "col14": "s2o22", + "col15": "nxrs7", + "col16": "jbdbv", + "col17": "4r77w", + "col18": "y9kmq", + "col19": "hd2px", + "col20": "8rbbx", + "col21": "sncp5", + "col22": "tgff1", + "col23": "aaa69", + "col24": "1r112", + "col25": "zskp9", + "col26": "ipex6", + "col27": "7tpyg", + "col28": "akjrs", + "col29": "nrvdx", + "col30": "ynyrp", + "col31": "ejvya", + "col32": "zqino", + "col33": "juncw", + "col34": "q7qjx", + "col35": "zl7yq", + "col36": "c2em2", + "col37": "p03hm", + "col38": "1vexi", + "col39": "q7v64", + "col40": "7w9z7", + "col41": "qku5l", + "col42": "bari4", + "col43": "nygha", + "col44": "3g34a", + "col45": "1dvrp", + "col46": "lco5z", + "col47": "1mrjt", + "col48": "hbun4", + "col49": "1vc40", + "col50": "bj5cw", + "col51": "p187c", + "col52": "aez79", + "col53": "ninir", + "col54": "dmbxe", + "col55": "y8z4x", + "col56": "wo1d0", + "col57": "4gzxl", + "col58": "1jd5d", + "col59": "43v62", + "col60": "5f3zt", + "col61": "02cao", + "col62": "1byen", + "col63": "2txay", + "col64": "px2hr", + "col65": "n1zet", + "col66": "l7pzx", + "col67": "na28n", + "col68": "b9ofd", + "col69": "8gfqf", + "col70": "o9z19", + "col71": "2j91j", + "col72": "kdj1a", + "col73": "iivb5", + "col74": "qjwsx", + "col75": "bcyt8", + "col76": "w5zxb", + "col77": "5b5mu", + "col78": "5g8c2", + "col79": "z21ab", + "col80": "fpky1", + "col81": "9nwlo", + "col82": "190eg", + "col83": "4bvir", + "col84": "romme", + "col85": "ykca1", + "col86": "er1x7", + "col87": "zuly0", + "col88": "c7lk1", + "col89": "5zx0g", + "col90": "81w8m", + "col91": "bpmlx", + "col92": "23a1y", + "col93": "alfxy", + "col94": "8dn13", + "col95": "hso2x", + "col96": "qchqb", + "col97": "63cm3" + }, + { + "name": "Atkins Dunlap", + "gender": "male", + "company": "Comveyor", + "col0": "0fo88", + "col1": "3x7dh", + "col2": "1egkk", + "col3": "tlgww", + "col4": "yrhnv", + "col5": "su9sg", + "col6": "bul4n", + "col7": "4tw9x", + "col8": "nf34x", + "col9": "09kiv", + "col10": "i6870", + "col11": "2c0pu", + "col12": "3h4zp", + "col13": "sdco0", + "col14": "cdqiy", + "col15": "r46it", + "col16": "8b04m", + "col17": "uas70", + "col18": "tihx9", + "col19": "5n5x7", + "col20": "3j54a", + "col21": "1lto7", + "col22": "128d4", + "col23": "f61lr", + "col24": "31xmt", + "col25": "9glxo", + "col26": "qx3bl", + "col27": "ujdbp", + "col28": "uwaj2", + "col29": "djwx1", + "col30": "i58hq", + "col31": "kpat3", + "col32": "br6wd", + "col33": "j5250", + "col34": "kwsx7", + "col35": "2tcwq", + "col36": "pryca", + "col37": "7rozt", + "col38": "1pvan", + "col39": "2xze8", + "col40": "39ud7", + "col41": "e7lbg", + "col42": "j346i", + "col43": "hfm7k", + "col44": "0vh0c", + "col45": "97lqm", + "col46": "dm1ia", + "col47": "3m9zp", + "col48": "nces4", + "col49": "5bd43", + "col50": "suunz", + "col51": "br0dj", + "col52": "lie50", + "col53": "0b861", + "col54": "4byow", + "col55": "8zl9q", + "col56": "5dotj", + "col57": "b9ctj", + "col58": "4fgmc", + "col59": "eo396", + "col60": "acf8m", + "col61": "6pq7t", + "col62": "620lg", + "col63": "6frfk", + "col64": "yfc3w", + "col65": "4cu65", + "col66": "pncfe", + "col67": "ohc1k", + "col68": "2csph", + "col69": "y6zg6", + "col70": "2s1d4", + "col71": "4yf9w", + "col72": "2ysu6", + "col73": "769z5", + "col74": "p1oa0", + "col75": "bir87", + "col76": "y73n8", + "col77": "bzrvt", + "col78": "kqlbg", + "col79": "4g9dx", + "col80": "wutim", + "col81": "vmk6t", + "col82": "39l3r", + "col83": "n66xj", + "col84": "le456", + "col85": "mysju", + "col86": "bcecm", + "col87": "2zcri", + "col88": "kfz8j", + "col89": "lr31c", + "col90": "gefwq", + "col91": "psu29", + "col92": "sqqtq", + "col93": "sj9lz", + "col94": "k50k6", + "col95": "6zvud", + "col96": "p5tug", + "col97": "numyd" + }, + { + "name": "Everett Foreman", + "gender": "male", + "company": "Maineland", + "col0": "j296x", + "col1": "venvz", + "col2": "qe8bp", + "col3": "o6jqt", + "col4": "qmfrk", + "col5": "ydqpm", + "col6": "4uxi1", + "col7": "z42wa", + "col8": "5f9o2", + "col9": "jiowm", + "col10": "x4p44", + "col11": "x3a6y", + "col12": "n9ooc", + "col13": "6dgvo", + "col14": "0w7as", + "col15": "1lg5t", + "col16": "i2yw5", + "col17": "mkf5i", + "col18": "8hvkn", + "col19": "u4wty", + "col20": "xvess", + "col21": "ty4cc", + "col22": "vg1kw", + "col23": "ekr0b", + "col24": "lwqf4", + "col25": "ajw31", + "col26": "ziiqp", + "col27": "aksi5", + "col28": "agdyp", + "col29": "4msm3", + "col30": "wxb20", + "col31": "agjjb", + "col32": "o6lrt", + "col33": "b9y0r", + "col34": "dmrtd", + "col35": "klvli", + "col36": "wypsc", + "col37": "nigci", + "col38": "p0r4q", + "col39": "hboxa", + "col40": "a4m61", + "col41": "hmw4t", + "col42": "mqsue", + "col43": "kklob", + "col44": "7lqqi", + "col45": "2xjyz", + "col46": "a4ht0", + "col47": "2t8d1", + "col48": "oi4sz", + "col49": "y48e4", + "col50": "q48dv", + "col51": "ecrk3", + "col52": "c9lo1", + "col53": "kv5vm", + "col54": "t9i6x", + "col55": "mxoem", + "col56": "7cr8b", + "col57": "ayt37", + "col58": "ma7qf", + "col59": "a7n5s", + "col60": "f6dbp", + "col61": "h6spa", + "col62": "mzjj2", + "col63": "anpbd", + "col64": "gja7b", + "col65": "n0ydy", + "col66": "d6r8e", + "col67": "fyr61", + "col68": "yls3k", + "col69": "vre1m", + "col70": "cgy7y", + "col71": "kqvuv", + "col72": "l6prj", + "col73": "2613c", + "col74": "zg9mq", + "col75": "00tcy", + "col76": "la1ps", + "col77": "y8rnt", + "col78": "nzosv", + "col79": "wq4k4", + "col80": "3623y", + "col81": "3a81f", + "col82": "mhatl", + "col83": "cgg04", + "col84": "botp8", + "col85": "b8938", + "col86": "pyt7p", + "col87": "tniss", + "col88": "s4437", + "col89": "khnpa", + "col90": "hyku6", + "col91": "6zg1j", + "col92": "9ort2", + "col93": "xkh2n", + "col94": "hf70d", + "col95": "xkor3", + "col96": "bybmx", + "col97": "sraa7" + }, + { + "name": "Gould Randolph", + "gender": "male", + "company": "Intergeek", + "col0": "4b8qg", + "col1": "umdd9", + "col2": "jvryk", + "col3": "k2fp6", + "col4": "j54oj", + "col5": "ur7bq", + "col6": "6rtvw", + "col7": "5rwzq", + "col8": "eazgu", + "col9": "voeip", + "col10": "t35q5", + "col11": "ssxd5", + "col12": "e7ss8", + "col13": "3ixaq", + "col14": "93yie", + "col15": "sijdr", + "col16": "sd7gt", + "col17": "w07ws", + "col18": "0xyla", + "col19": "2ymx9", + "col20": "09h9c", + "col21": "vrqea", + "col22": "630kn", + "col23": "8spev", + "col24": "x8fjx", + "col25": "8b9pg", + "col26": "hmlrk", + "col27": "zqyxy", + "col28": "4lc5q", + "col29": "r8a5n", + "col30": "qwqdr", + "col31": "waz4m", + "col32": "migvq", + "col33": "kuhem", + "col34": "x9wlz", + "col35": "gw5vi", + "col36": "ecvg1", + "col37": "fhifa", + "col38": "6n19s", + "col39": "1z02k", + "col40": "1wxke", + "col41": "krtfv", + "col42": "ji4iu", + "col43": "vt1xc", + "col44": "uybkg", + "col45": "oq9e3", + "col46": "cdu6b", + "col47": "6srsz", + "col48": "4f9ob", + "col49": "skrln", + "col50": "wrm9r", + "col51": "yrg5p", + "col52": "m75ik", + "col53": "9vm3t", + "col54": "w96as", + "col55": "5z81l", + "col56": "cab4m", + "col57": "tx7xe", + "col58": "ar21t", + "col59": "ruq70", + "col60": "ee0r1", + "col61": "kkpfv", + "col62": "3jc0v", + "col63": "5oc7j", + "col64": "2h2dt", + "col65": "tk2he", + "col66": "6dz3i", + "col67": "wkk8k", + "col68": "bn3wj", + "col69": "016m4", + "col70": "wvrw3", + "col71": "xaojn", + "col72": "kqlum", + "col73": "ae19l", + "col74": "g1gv1", + "col75": "7hs3l", + "col76": "cn9y2", + "col77": "r1sdh", + "col78": "ruzcj", + "col79": "xw5jk", + "col80": "rafzv", + "col81": "9t1p5", + "col82": "ytf2h", + "col83": "o3vy9", + "col84": "8eci4", + "col85": "7v4my", + "col86": "7wce0", + "col87": "i30tu", + "col88": "8ecn2", + "col89": "l8nfv", + "col90": "hy0pt", + "col91": "chxgw", + "col92": "n69b1", + "col93": "d25jw", + "col94": "m8z5z", + "col95": "vfwgp", + "col96": "1m8mj", + "col97": "3muzg" + }, + { + "name": "Kelli Leon", + "gender": "female", + "company": "Verbus", + "col0": "d1xyv", + "col1": "ofath", + "col2": "5l4p0", + "col3": "jrfvx", + "col4": "3b8hn", + "col5": "7f7xv", + "col6": "hrnsp", + "col7": "33q9s", + "col8": "nm2pz", + "col9": "u4taf", + "col10": "duzvc", + "col11": "73iun", + "col12": "3cyiw", + "col13": "pprhv", + "col14": "rb1pi", + "col15": "5lkqe", + "col16": "rwi32", + "col17": "5fo1y", + "col18": "casi9", + "col19": "v8026", + "col20": "sbs6d", + "col21": "lni5j", + "col22": "7o4hr", + "col23": "eqgpd", + "col24": "56kue", + "col25": "9cd5b", + "col26": "tf0l2", + "col27": "4p8i1", + "col28": "fcqwv", + "col29": "pcc2e", + "col30": "y4x7o", + "col31": "99sbb", + "col32": "q31lj", + "col33": "69fh0", + "col34": "ygvk4", + "col35": "2rv8l", + "col36": "2m9sm", + "col37": "oq7ao", + "col38": "0c0it", + "col39": "o5g1r", + "col40": "d69ga", + "col41": "s8qtl", + "col42": "bahw2", + "col43": "rw63f", + "col44": "yteou", + "col45": "wj2f7", + "col46": "56f0i", + "col47": "bw29h", + "col48": "v22e8", + "col49": "uvmeg", + "col50": "6gdi0", + "col51": "2jvqx", + "col52": "bqtbd", + "col53": "brep6", + "col54": "1hpix", + "col55": "gxsxw", + "col56": "0l0wa", + "col57": "8ptwr", + "col58": "67cyf", + "col59": "c5953", + "col60": "trdfp", + "col61": "p1znq", + "col62": "0xiws", + "col63": "r6eh9", + "col64": "fu858", + "col65": "xuemf", + "col66": "kjuap", + "col67": "xnx38", + "col68": "5ied4", + "col69": "553wz", + "col70": "7fqnh", + "col71": "ys9a2", + "col72": "h9je0", + "col73": "9nif1", + "col74": "ogk1q", + "col75": "uwcnz", + "col76": "5yys4", + "col77": "cvd85", + "col78": "pimj2", + "col79": "lf4qy", + "col80": "qit8w", + "col81": "a4u6e", + "col82": "k3skq", + "col83": "p0r32", + "col84": "le5q9", + "col85": "51pey", + "col86": "sg1w3", + "col87": "9xuu8", + "col88": "7uu20", + "col89": "eb7mg", + "col90": "3ovug", + "col91": "wfohs", + "col92": "5jrec", + "col93": "de9z0", + "col94": "ef6ce", + "col95": "6syh4", + "col96": "mgn4e", + "col97": "g8dw3" + }, + { + "name": "Freda Mason", + "gender": "female", + "company": "Accidency", + "col0": "8l4bn", + "col1": "cnslw", + "col2": "la0su", + "col3": "04lwa", + "col4": "32d6l", + "col5": "1p87s", + "col6": "ctopl", + "col7": "u3ukx", + "col8": "s10aw", + "col9": "spdi2", + "col10": "i1pqb", + "col11": "s6oj5", + "col12": "mrsf1", + "col13": "qf0jo", + "col14": "c841a", + "col15": "ccimw", + "col16": "jt159", + "col17": "sr8u9", + "col18": "pszs2", + "col19": "c0n10", + "col20": "qevsm", + "col21": "7l2tf", + "col22": "d8rd6", + "col23": "jyznr", + "col24": "ntwv5", + "col25": "irnym", + "col26": "1suq8", + "col27": "2631w", + "col28": "vot69", + "col29": "khrox", + "col30": "m8poz", + "col31": "4d5e7", + "col32": "0ccqe", + "col33": "0ptl5", + "col34": "b6040", + "col35": "um31j", + "col36": "mraf3", + "col37": "d3fu7", + "col38": "yz8zx", + "col39": "bjti3", + "col40": "xzboe", + "col41": "op081", + "col42": "3rfic", + "col43": "vogl2", + "col44": "7poza", + "col45": "nivpz", + "col46": "a9gyj", + "col47": "aik06", + "col48": "b4c03", + "col49": "79ymk", + "col50": "rcd3d", + "col51": "1j1xk", + "col52": "cbd3t", + "col53": "n6q2s", + "col54": "ohy28", + "col55": "3w66z", + "col56": "imhcf", + "col57": "htu1t", + "col58": "ud8xn", + "col59": "gu6bm", + "col60": "58htj", + "col61": "wizek", + "col62": "nrbfo", + "col63": "3c3lr", + "col64": "29pvf", + "col65": "uhzt7", + "col66": "kfzwd", + "col67": "5yzsw", + "col68": "6kw2n", + "col69": "14xzc", + "col70": "aaqz8", + "col71": "dqmg8", + "col72": "a83te", + "col73": "gr5f1", + "col74": "buvyi", + "col75": "qgka6", + "col76": "hoo74", + "col77": "po22n", + "col78": "oj75j", + "col79": "1i5wt", + "col80": "zd5ls", + "col81": "0eaas", + "col82": "jerui", + "col83": "6pfot", + "col84": "71cff", + "col85": "d7ygx", + "col86": "eb9j8", + "col87": "gv6yv", + "col88": "yn33o", + "col89": "ahxvn", + "col90": "ur10y", + "col91": "m0v2f", + "col92": "utkd6", + "col93": "40pf7", + "col94": "z33qz", + "col95": "3xheb", + "col96": "xjvkp", + "col97": "k91j0" + }, + { + "name": "Tucker Maxwell", + "gender": "male", + "company": "Lumbrex", + "col0": "blswi", + "col1": "9ppyp", + "col2": "mpbke", + "col3": "e0fv9", + "col4": "9azzc", + "col5": "xbg41", + "col6": "4m4ov", + "col7": "h0266", + "col8": "oqa28", + "col9": "b04t8", + "col10": "fngr1", + "col11": "5jrvz", + "col12": "dqj29", + "col13": "pozac", + "col14": "yqbh1", + "col15": "t3jxk", + "col16": "eeqx5", + "col17": "1c2hg", + "col18": "dhq35", + "col19": "6pd5s", + "col20": "ntk05", + "col21": "1uems", + "col22": "21lvm", + "col23": "ykg35", + "col24": "tbih2", + "col25": "misiw", + "col26": "bit54", + "col27": "k2r4o", + "col28": "riwi7", + "col29": "819hp", + "col30": "nvy2d", + "col31": "iqfoh", + "col32": "jycy3", + "col33": "d3mh2", + "col34": "5mplm", + "col35": "7jhtk", + "col36": "t24xq", + "col37": "bn8yu", + "col38": "ztrvd", + "col39": "e8h0m", + "col40": "f8ijt", + "col41": "re95z", + "col42": "dsnxq", + "col43": "hf1u7", + "col44": "lef29", + "col45": "wy12n", + "col46": "j00w9", + "col47": "i74ch", + "col48": "oqpmo", + "col49": "08mxt", + "col50": "rbij3", + "col51": "auot3", + "col52": "9l1op", + "col53": "zhpx5", + "col54": "zs6ne", + "col55": "7d0l8", + "col56": "3jpy3", + "col57": "7oq6g", + "col58": "ef590", + "col59": "g499i", + "col60": "wh3us", + "col61": "6phvb", + "col62": "2a7cp", + "col63": "fbp04", + "col64": "f3u8w", + "col65": "nwlzd", + "col66": "ej9qc", + "col67": "s0328", + "col68": "9opla", + "col69": "u9b03", + "col70": "x2of3", + "col71": "k8uqd", + "col72": "41fd4", + "col73": "uzfjm", + "col74": "pojkm", + "col75": "4llho", + "col76": "tcfgh", + "col77": "20ed1", + "col78": "vwf4s", + "col79": "1yv07", + "col80": "35ykn", + "col81": "qk38j", + "col82": "4h1qp", + "col83": "j1h2a", + "col84": "4kmhb", + "col85": "2s3i7", + "col86": "0uik0", + "col87": "ttshl", + "col88": "eyyvf", + "col89": "wnc5x", + "col90": "htcbf", + "col91": "ee7wg", + "col92": "f6800", + "col93": "u4mfi", + "col94": "e43iz", + "col95": "otbbr", + "col96": "ukyl7", + "col97": "uezk2" + }, + { + "name": "Yvonne Parsons", + "gender": "female", + "company": "Zolar", + "col0": "to559", + "col1": "3z2eo", + "col2": "ynqwp", + "col3": "1lk1s", + "col4": "apd21", + "col5": "i7i8s", + "col6": "s4i8v", + "col7": "3oz5q", + "col8": "zf3qm", + "col9": "q40ug", + "col10": "3wmli", + "col11": "kiwsf", + "col12": "an1sr", + "col13": "in798", + "col14": "ik0xu", + "col15": "19rrd", + "col16": "7aqh8", + "col17": "wm3gz", + "col18": "ssl47", + "col19": "c0f3n", + "col20": "dxeaz", + "col21": "g1ysy", + "col22": "4wu9l", + "col23": "t58im", + "col24": "mwddu", + "col25": "aehk8", + "col26": "wdmg1", + "col27": "2hi5f", + "col28": "0t920", + "col29": "f9av8", + "col30": "i956c", + "col31": "8k4yd", + "col32": "5aydb", + "col33": "cdn4c", + "col34": "bijzd", + "col35": "s8zdf", + "col36": "ztud7", + "col37": "ki8e0", + "col38": "anpsf", + "col39": "vroqd", + "col40": "xav25", + "col41": "mua8t", + "col42": "wl5zu", + "col43": "oc7my", + "col44": "blck5", + "col45": "ly7u6", + "col46": "6jnk4", + "col47": "7t0gj", + "col48": "kvqdb", + "col49": "nl0r1", + "col50": "ujr5c", + "col51": "epxzo", + "col52": "sjnmf", + "col53": "tgba2", + "col54": "63tc5", + "col55": "q7c6h", + "col56": "5489x", + "col57": "r04pi", + "col58": "fm5ux", + "col59": "iz70s", + "col60": "2u7qg", + "col61": "3wv9j", + "col62": "dxwxc", + "col63": "mrv3r", + "col64": "85tje", + "col65": "r81we", + "col66": "21cvg", + "col67": "lnvxh", + "col68": "7oeha", + "col69": "68w2p", + "col70": "v9h10", + "col71": "uzq8d", + "col72": "1bslr", + "col73": "40sgv", + "col74": "0154t", + "col75": "x9ncc", + "col76": "dp0jk", + "col77": "t2hyb", + "col78": "d64eq", + "col79": "7wboz", + "col80": "ejl8o", + "col81": "y96sd", + "col82": "pavlr", + "col83": "mi9rw", + "col84": "dywe2", + "col85": "zvomh", + "col86": "0lylh", + "col87": "ka15l", + "col88": "q9khu", + "col89": "c9mhk", + "col90": "y82bm", + "col91": "clfya", + "col92": "eey67", + "col93": "gpp51", + "col94": "5amyv", + "col95": "alghg", + "col96": "yd685", + "col97": "hdewk" + }, + { + "name": "Woods Key", + "gender": "male", + "company": "Bedder", + "col0": "tje9o", + "col1": "8bhvz", + "col2": "wfdmx", + "col3": "7sw7r", + "col4": "bedh4", + "col5": "9kr5q", + "col6": "ljvf6", + "col7": "1jsaf", + "col8": "w4pwt", + "col9": "d6lht", + "col10": "2o8v7", + "col11": "xfm8t", + "col12": "wpl86", + "col13": "7q6s0", + "col14": "9c5x9", + "col15": "z8myd", + "col16": "5g41s", + "col17": "bnakg", + "col18": "uvsvt", + "col19": "tf3tk", + "col20": "ow8l5", + "col21": "6s4zq", + "col22": "7bvjf", + "col23": "mro88", + "col24": "rcs5q", + "col25": "35b6p", + "col26": "iv4qa", + "col27": "r4t7j", + "col28": "re5ny", + "col29": "0f23e", + "col30": "7mx6b", + "col31": "slahi", + "col32": "e66tu", + "col33": "3cysi", + "col34": "wpf1h", + "col35": "12w4w", + "col36": "g0x5e", + "col37": "ecnuw", + "col38": "huk0j", + "col39": "9l7oo", + "col40": "yu7ec", + "col41": "1y8tj", + "col42": "vvi5f", + "col43": "qnhf7", + "col44": "fz4cr", + "col45": "szz5p", + "col46": "jyu0h", + "col47": "pt6ez", + "col48": "zfkuu", + "col49": "2qx40", + "col50": "qpzk7", + "col51": "2k7fb", + "col52": "ixtxo", + "col53": "y4ogd", + "col54": "kzwfs", + "col55": "ywolz", + "col56": "7d8dk", + "col57": "37jfv", + "col58": "3xzyq", + "col59": "f7im8", + "col60": "apvrf", + "col61": "000b5", + "col62": "uf80b", + "col63": "7mscm", + "col64": "06n6u", + "col65": "gqsc2", + "col66": "kxd4k", + "col67": "58mvq", + "col68": "3gie8", + "col69": "vz46x", + "col70": "9j2ry", + "col71": "oo6x1", + "col72": "9047k", + "col73": "ik44y", + "col74": "58sse", + "col75": "dlxqh", + "col76": "tccj9", + "col77": "aepyt", + "col78": "x7kdi", + "col79": "6mvbl", + "col80": "4hxyh", + "col81": "27884", + "col82": "604z1", + "col83": "g2nxh", + "col84": "mhpgz", + "col85": "sdpi0", + "col86": "t9mv9", + "col87": "aquf9", + "col88": "ws9e7", + "col89": "bxseb", + "col90": "jk5w8", + "col91": "wn1c4", + "col92": "uyofu", + "col93": "orrm6", + "col94": "e89re", + "col95": "gecdp", + "col96": "b5l7v", + "col97": "qs3sl" + }, + { + "name": "Stephens Reilly", + "gender": "male", + "company": "Acusage", + "col0": "3yaum", + "col1": "9wvox", + "col2": "o36iy", + "col3": "skjt8", + "col4": "d930y", + "col5": "hbzq6", + "col6": "obfxi", + "col7": "bvb5b", + "col8": "jzc0e", + "col9": "gliwm", + "col10": "ae3s0", + "col11": "yylha", + "col12": "q5061", + "col13": "hl4s9", + "col14": "5dto3", + "col15": "ogw82", + "col16": "1ww0d", + "col17": "6yxmb", + "col18": "69s46", + "col19": "dw4gd", + "col20": "94zir", + "col21": "j92my", + "col22": "qrnuq", + "col23": "lgi28", + "col24": "kew2e", + "col25": "cboe7", + "col26": "rho59", + "col27": "3xn4v", + "col28": "ishp0", + "col29": "ocgh3", + "col30": "553cc", + "col31": "f7624", + "col32": "vbgy0", + "col33": "j7t15", + "col34": "7k970", + "col35": "0plw4", + "col36": "uu7op", + "col37": "fcwb9", + "col38": "sdv0o", + "col39": "ypl3b", + "col40": "igceo", + "col41": "i9ymg", + "col42": "eyfjh", + "col43": "5e2m0", + "col44": "cqg53", + "col45": "4yld9", + "col46": "j28dg", + "col47": "q535o", + "col48": "haxgl", + "col49": "rio84", + "col50": "2c698", + "col51": "4cgb4", + "col52": "8htff", + "col53": "hj1da", + "col54": "izd60", + "col55": "e6nqm", + "col56": "x42qh", + "col57": "8fr3k", + "col58": "virj0", + "col59": "vntxz", + "col60": "prz0j", + "col61": "ktvwi", + "col62": "hoc6m", + "col63": "u2wkn", + "col64": "ajwtj", + "col65": "1siuq", + "col66": "e98vf", + "col67": "7vh5w", + "col68": "wsmre", + "col69": "qvf0j", + "col70": "guz6d", + "col71": "hampv", + "col72": "3b7rh", + "col73": "u6tdl", + "col74": "wfrqv", + "col75": "w56ta", + "col76": "y5jqw", + "col77": "98ohf", + "col78": "bibsl", + "col79": "rgxjd", + "col80": "ewd0l", + "col81": "dxb89", + "col82": "zaj6i", + "col83": "ycaq0", + "col84": "zjoly", + "col85": "dcv5p", + "col86": "zzwdv", + "col87": "tim71", + "col88": "i1kyt", + "col89": "a2npr", + "col90": "r37vg", + "col91": "cac15", + "col92": "ev64e", + "col93": "qyn7d", + "col94": "aflc4", + "col95": "g8nys", + "col96": "6s3tk", + "col97": "t8k6a" + }, + { + "name": "Mcfarland Sparks", + "gender": "male", + "company": "Comvey", + "col0": "7pj4d", + "col1": "h1t73", + "col2": "81d0v", + "col3": "lqlv2", + "col4": "j0pgr", + "col5": "mbd1m", + "col6": "ykdw5", + "col7": "nahmc", + "col8": "tuuio", + "col9": "xavlq", + "col10": "28dch", + "col11": "1s8zd", + "col12": "xufkw", + "col13": "qo42a", + "col14": "omw5g", + "col15": "cpoll", + "col16": "us6ol", + "col17": "b9beq", + "col18": "cdni2", + "col19": "x91nn", + "col20": "4vjep", + "col21": "qzekm", + "col22": "84xrf", + "col23": "g8b9i", + "col24": "nw7d3", + "col25": "wlql4", + "col26": "z9465", + "col27": "ybu32", + "col28": "d513i", + "col29": "9u9n4", + "col30": "v652z", + "col31": "v0a8l", + "col32": "uct9p", + "col33": "j28me", + "col34": "n6m93", + "col35": "i2tt5", + "col36": "a8uzt", + "col37": "5wj9m", + "col38": "e1o1z", + "col39": "gljyt", + "col40": "dr6wg", + "col41": "k3bqo", + "col42": "v8mn9", + "col43": "wq285", + "col44": "8kguh", + "col45": "de5xx", + "col46": "m0m4t", + "col47": "xlqzp", + "col48": "1ur3x", + "col49": "gcso1", + "col50": "47yly", + "col51": "pb4j9", + "col52": "y42c3", + "col53": "4mgiq", + "col54": "pfgqz", + "col55": "d0pc4", + "col56": "53znk", + "col57": "xglzc", + "col58": "q96wx", + "col59": "b43in", + "col60": "roo80", + "col61": "0gfdy", + "col62": "7x5le", + "col63": "livj9", + "col64": "sasvk", + "col65": "tgm6x", + "col66": "020bf", + "col67": "evymw", + "col68": "o1e7j", + "col69": "gj2o2", + "col70": "lu0jo", + "col71": "re2zi", + "col72": "hdfe0", + "col73": "p3183", + "col74": "ph1c6", + "col75": "eohyk", + "col76": "b03mk", + "col77": "cumde", + "col78": "2zb5c", + "col79": "icqk0", + "col80": "60yfv", + "col81": "z9409", + "col82": "je2ge", + "col83": "513ie", + "col84": "9qjpe", + "col85": "ag7bi", + "col86": "ylueo", + "col87": "jbfu0", + "col88": "jeqia", + "col89": "cukl8", + "col90": "l8zfm", + "col91": "n8nt7", + "col92": "ilqs0", + "col93": "ec87i", + "col94": "on9bw", + "col95": "u0zdz", + "col96": "dcpvh", + "col97": "2peg1" + }, + { + "name": "Jocelyn Sawyer", + "gender": "female", + "company": "Fortean", + "col0": "olwcw", + "col1": "ppnup", + "col2": "vla1l", + "col3": "cr31z", + "col4": "1xydp", + "col5": "e4r6e", + "col6": "scku4", + "col7": "me77l", + "col8": "hhu40", + "col9": "wlj2x", + "col10": "7lnsx", + "col11": "9nvkk", + "col12": "gjzl6", + "col13": "lli3q", + "col14": "yl13q", + "col15": "rtq5d", + "col16": "d42x6", + "col17": "03uop", + "col18": "culng", + "col19": "idj29", + "col20": "ltb0r", + "col21": "bhu5b", + "col22": "r0ka6", + "col23": "h7bb7", + "col24": "jcdvr", + "col25": "fte6e", + "col26": "g46vq", + "col27": "ioabs", + "col28": "dpw9g", + "col29": "g83rn", + "col30": "fidqw", + "col31": "rq0pb", + "col32": "pc4al", + "col33": "mmhhw", + "col34": "zj0y0", + "col35": "pfl0i", + "col36": "ut2fm", + "col37": "qz0yg", + "col38": "plffe", + "col39": "bkgse", + "col40": "xl4mu", + "col41": "ea68l", + "col42": "ldn48", + "col43": "j1ca8", + "col44": "qy488", + "col45": "ho9xq", + "col46": "k3wnr", + "col47": "abw80", + "col48": "49pvt", + "col49": "lzxvp", + "col50": "6939h", + "col51": "1o7ce", + "col52": "y9i1v", + "col53": "me1me", + "col54": "sere9", + "col55": "0ag8k", + "col56": "89yos", + "col57": "1hhsd", + "col58": "g29gc", + "col59": "aimrj", + "col60": "of0lc", + "col61": "tao24", + "col62": "z4kwg", + "col63": "5aikw", + "col64": "jz4ys", + "col65": "twzz4", + "col66": "gd9ag", + "col67": "tf3kf", + "col68": "zwkqg", + "col69": "4jemo", + "col70": "0iwbh", + "col71": "67n1x", + "col72": "8wbum", + "col73": "qmssh", + "col74": "xb0bk", + "col75": "oowh6", + "col76": "byy9f", + "col77": "5x5zv", + "col78": "1p0v0", + "col79": "2t5zz", + "col80": "s1hba", + "col81": "z3aj8", + "col82": "bedsn", + "col83": "opn30", + "col84": "h97ir", + "col85": "v9cn7", + "col86": "s9qju", + "col87": "bpia1", + "col88": "6yg7n", + "col89": "51ki4", + "col90": "b3lb2", + "col91": "csh9d", + "col92": "wfjra", + "col93": "9tobz", + "col94": "fw347", + "col95": "t0lgw", + "col96": "h5ax0", + "col97": "bl5v4" + }, + { + "name": "Renee Barr", + "gender": "female", + "company": "Kiggle", + "col0": "gnx7p", + "col1": "jjusk", + "col2": "6g3u8", + "col3": "fexpg", + "col4": "ghdh2", + "col5": "k6wng", + "col6": "q8bz8", + "col7": "1wptw", + "col8": "51p7x", + "col9": "agqpz", + "col10": "dszum", + "col11": "ybh57", + "col12": "o1qax", + "col13": "p4w9w", + "col14": "cadzx", + "col15": "vvxvy", + "col16": "0vfxp", + "col17": "lmyb1", + "col18": "m0kw2", + "col19": "5sgbs", + "col20": "mijhx", + "col21": "7kd3k", + "col22": "xdvd5", + "col23": "rb2yj", + "col24": "rtbga", + "col25": "gakwx", + "col26": "e5aig", + "col27": "vajf3", + "col28": "cn74u", + "col29": "9gk87", + "col30": "pfzd4", + "col31": "fthcv", + "col32": "w05vg", + "col33": "zybzp", + "col34": "dnztg", + "col35": "edaxp", + "col36": "bvxj3", + "col37": "4dj92", + "col38": "i7kt1", + "col39": "7263w", + "col40": "og1dr", + "col41": "0947x", + "col42": "ojc9k", + "col43": "3l55c", + "col44": "a61ft", + "col45": "ljata", + "col46": "tlpfi", + "col47": "3eunp", + "col48": "05ixx", + "col49": "6vi8k", + "col50": "ur9vt", + "col51": "kx0yb", + "col52": "q1ajd", + "col53": "tkl7s", + "col54": "djfzy", + "col55": "0efj1", + "col56": "5p9dy", + "col57": "7vn1h", + "col58": "8lghp", + "col59": "8hyde", + "col60": "lzwav", + "col61": "3a4fu", + "col62": "vz3vc", + "col63": "rwy2u", + "col64": "xjjbj", + "col65": "dpr7u", + "col66": "fg233", + "col67": "c59jx", + "col68": "8vv2f", + "col69": "5w5rv", + "col70": "ah9r2", + "col71": "x23gq", + "col72": "y811u", + "col73": "qsf4g", + "col74": "lywtb", + "col75": "2yw7u", + "col76": "q3t6v", + "col77": "pxoe9", + "col78": "gpo0k", + "col79": "4ctp0", + "col80": "uqv79", + "col81": "c0c31", + "col82": "ctwct", + "col83": "pcwcw", + "col84": "nz82c", + "col85": "5cg5v", + "col86": "iiqf7", + "col87": "vmioi", + "col88": "comrj", + "col89": "yujvi", + "col90": "8if0i", + "col91": "gkva7", + "col92": "auuzm", + "col93": "ute4b", + "col94": "60rp4", + "col95": "b7xag", + "col96": "v8h6u", + "col97": "gxgoj" + }, + { + "name": "Gaines Beck", + "gender": "male", + "company": "Sequitur", + "col0": "s9www", + "col1": "xkv78", + "col2": "evty1", + "col3": "o7s6o", + "col4": "v8m8n", + "col5": "sutm9", + "col6": "cbhrn", + "col7": "1gt52", + "col8": "7fp9p", + "col9": "g70g8", + "col10": "taf8h", + "col11": "zfv1y", + "col12": "l6tw2", + "col13": "kgbjz", + "col14": "ri9ak", + "col15": "axlp8", + "col16": "bojv9", + "col17": "vucst", + "col18": "ko6k0", + "col19": "vz4dj", + "col20": "4ak49", + "col21": "7ktna", + "col22": "umfaa", + "col23": "wgzn0", + "col24": "bmbag", + "col25": "c2aif", + "col26": "y8rvo", + "col27": "lf6vn", + "col28": "s34qy", + "col29": "bx01s", + "col30": "g4bbu", + "col31": "xf031", + "col32": "uuxnh", + "col33": "0qkez", + "col34": "hnh54", + "col35": "7alir", + "col36": "iuaoz", + "col37": "q5uje", + "col38": "56kgy", + "col39": "k22kd", + "col40": "0y7hy", + "col41": "h3mhv", + "col42": "r3y5u", + "col43": "pn2vb", + "col44": "ta1v8", + "col45": "4rut3", + "col46": "ftavo", + "col47": "kg6wx", + "col48": "4aioe", + "col49": "eefer", + "col50": "cy5gw", + "col51": "o4fva", + "col52": "18p27", + "col53": "u9oj8", + "col54": "xwmme", + "col55": "9c6qo", + "col56": "bk3ci", + "col57": "2exb6", + "col58": "dppcx", + "col59": "jbam5", + "col60": "fbi7r", + "col61": "6jb7a", + "col62": "5a1ll", + "col63": "x50ia", + "col64": "9q12q", + "col65": "u91td", + "col66": "algc3", + "col67": "16a35", + "col68": "idgzt", + "col69": "tgqst", + "col70": "bh52e", + "col71": "edn5p", + "col72": "7sxri", + "col73": "lf9jk", + "col74": "zrt89", + "col75": "q7pwn", + "col76": "oyzd5", + "col77": "eosx7", + "col78": "7e46x", + "col79": "27ki7", + "col80": "xg6l5", + "col81": "4ox81", + "col82": "4w6ha", + "col83": "0atln", + "col84": "7f2bd", + "col85": "m1juv", + "col86": "knfzq", + "col87": "pdmx3", + "col88": "jzjp0", + "col89": "2pc1k", + "col90": "rbr0x", + "col91": "0je56", + "col92": "3z7lj", + "col93": "ttg5b", + "col94": "9a1z2", + "col95": "qfc9s", + "col96": "qpgo5", + "col97": "v5zea" + }, + { + "name": "Luisa Farrell", + "gender": "female", + "company": "Cinesanct", + "col0": "owdcb", + "col1": "umlwn", + "col2": "hzz9o", + "col3": "uyd6q", + "col4": "93s4p", + "col5": "59z3h", + "col6": "b9pk4", + "col7": "sj4lo", + "col8": "jifzl", + "col9": "jlask", + "col10": "u11x1", + "col11": "3jpnz", + "col12": "8zly9", + "col13": "053py", + "col14": "v7c8k", + "col15": "f6pvr", + "col16": "dokc7", + "col17": "rlh26", + "col18": "7m8zh", + "col19": "lee6g", + "col20": "q2a49", + "col21": "1mkm7", + "col22": "iqitm", + "col23": "rxpm3", + "col24": "katel", + "col25": "ngub5", + "col26": "dusvy", + "col27": "7udhz", + "col28": "iywoy", + "col29": "wm971", + "col30": "uba7e", + "col31": "v3068", + "col32": "yrkyy", + "col33": "ez01l", + "col34": "akn8y", + "col35": "owbqm", + "col36": "xa5c3", + "col37": "zhs8x", + "col38": "ajfj1", + "col39": "bw0lw", + "col40": "uwsxo", + "col41": "tvo6e", + "col42": "4xkgl", + "col43": "0v53s", + "col44": "wnfro", + "col45": "pk89f", + "col46": "pegh4", + "col47": "5x310", + "col48": "r93ro", + "col49": "ecoky", + "col50": "vvvnx", + "col51": "9uf13", + "col52": "66r9v", + "col53": "bvj9q", + "col54": "mcy0b", + "col55": "hmgyj", + "col56": "5ef1k", + "col57": "44a5c", + "col58": "1acay", + "col59": "osq6r", + "col60": "dvkn1", + "col61": "omji3", + "col62": "2kx25", + "col63": "eoyte", + "col64": "gz65t", + "col65": "mwftj", + "col66": "l73qn", + "col67": "8gqhz", + "col68": "k708f", + "col69": "zob1n", + "col70": "7bhv8", + "col71": "7k8df", + "col72": "pv6dl", + "col73": "6sor9", + "col74": "gkuwc", + "col75": "hwo8d", + "col76": "hnlmg", + "col77": "vadq2", + "col78": "q9jjo", + "col79": "l82wp", + "col80": "zr9h4", + "col81": "yqstc", + "col82": "sc37f", + "col83": "o6hpn", + "col84": "hzu88", + "col85": "nd6vx", + "col86": "9t8cp", + "col87": "nl8ck", + "col88": "6f7bq", + "col89": "rttb2", + "col90": "efh94", + "col91": "txucz", + "col92": "10z4r", + "col93": "imaby", + "col94": "67vju", + "col95": "2xv6i", + "col96": "ntw5e", + "col97": "902u8" + }, + { + "name": "Robyn Strickland", + "gender": "female", + "company": "Obones", + "col0": "j6yxm", + "col1": "romme", + "col2": "633g0", + "col3": "vvs5u", + "col4": "ax2ne", + "col5": "ur62v", + "col6": "qagnw", + "col7": "1e2xg", + "col8": "6om36", + "col9": "rhjon", + "col10": "88xr7", + "col11": "c1xue", + "col12": "k2vut", + "col13": "yc1xj", + "col14": "1aa5w", + "col15": "fnpex", + "col16": "q74mv", + "col17": "nstmw", + "col18": "gtvkw", + "col19": "4d7tz", + "col20": "8066o", + "col21": "kexen", + "col22": "a7p8c", + "col23": "vcq3s", + "col24": "uo6d9", + "col25": "2ca1v", + "col26": "ee681", + "col27": "dd77d", + "col28": "ccdax", + "col29": "yeqf0", + "col30": "bb2tb", + "col31": "u70vf", + "col32": "g4zjy", + "col33": "288c7", + "col34": "r7ey6", + "col35": "d7t1x", + "col36": "f0ih4", + "col37": "tuzyv", + "col38": "6o68b", + "col39": "4mvh3", + "col40": "00qvd", + "col41": "f732m", + "col42": "d6z21", + "col43": "w4byv", + "col44": "lmzgw", + "col45": "tuz3o", + "col46": "l2frs", + "col47": "2gn77", + "col48": "82pd8", + "col49": "ss1pu", + "col50": "onvnb", + "col51": "l7yce", + "col52": "nmszl", + "col53": "iz3g7", + "col54": "teabo", + "col55": "yi4e9", + "col56": "kfdns", + "col57": "7dgm7", + "col58": "o64wd", + "col59": "8yq4i", + "col60": "h6hdj", + "col61": "2568y", + "col62": "oog1p", + "col63": "bva81", + "col64": "awu3h", + "col65": "gvd5y", + "col66": "xligf", + "col67": "qh6my", + "col68": "yd8kx", + "col69": "vu6ko", + "col70": "nppo7", + "col71": "ake3v", + "col72": "he54y", + "col73": "qroqq", + "col74": "0v43b", + "col75": "6483l", + "col76": "805qj", + "col77": "uxtdb", + "col78": "kskbh", + "col79": "0hav9", + "col80": "koba7", + "col81": "wef6i", + "col82": "uxjnq", + "col83": "yfzsm", + "col84": "ifeyp", + "col85": "1vtgo", + "col86": "0qp0b", + "col87": "cut6m", + "col88": "pzjlt", + "col89": "kk2j8", + "col90": "uiecx", + "col91": "5a0bw", + "col92": "c7wk2", + "col93": "llrqb", + "col94": "dz66v", + "col95": "r4x8z", + "col96": "47tq9", + "col97": "o5wg8" + }, + { + "name": "Roseann Jarvis", + "gender": "female", + "company": "Aquazure", + "col0": "0nfkq", + "col1": "w9oem", + "col2": "7d86g", + "col3": "pxbea", + "col4": "kuidi", + "col5": "ptvuf", + "col6": "qzvkw", + "col7": "5e2sr", + "col8": "dkzt0", + "col9": "d2gw6", + "col10": "g3qpm", + "col11": "0j6sb", + "col12": "dhpwb", + "col13": "8zonx", + "col14": "x0z8s", + "col15": "96sra", + "col16": "jkvmt", + "col17": "9rvpe", + "col18": "y0fry", + "col19": "hu4fc", + "col20": "g4o05", + "col21": "i6gc7", + "col22": "vr8o5", + "col23": "kj7hz", + "col24": "oyz92", + "col25": "vjfbq", + "col26": "p2wkl", + "col27": "g3oww", + "col28": "hapqr", + "col29": "jsnwc", + "col30": "gwspu", + "col31": "5ana9", + "col32": "s7v9u", + "col33": "hve21", + "col34": "31b91", + "col35": "9mt3s", + "col36": "t69v2", + "col37": "yna55", + "col38": "9omq7", + "col39": "pgao9", + "col40": "tz2mq", + "col41": "lyn3x", + "col42": "twxwf", + "col43": "9e877", + "col44": "ns0pl", + "col45": "wlm14", + "col46": "l17hk", + "col47": "qdq4f", + "col48": "1ek8k", + "col49": "lkpkr", + "col50": "wdp0j", + "col51": "ttqlk", + "col52": "8phxn", + "col53": "ip43n", + "col54": "r74yy", + "col55": "dr49t", + "col56": "ralw2", + "col57": "xfo73", + "col58": "2pi1c", + "col59": "obklg", + "col60": "r006j", + "col61": "qoskt", + "col62": "90w34", + "col63": "m48rf", + "col64": "kqclk", + "col65": "zu9pu", + "col66": "x9vuo", + "col67": "slqfn", + "col68": "b3btv", + "col69": "2rb7r", + "col70": "d30ia", + "col71": "652dy", + "col72": "vz3j3", + "col73": "spmn7", + "col74": "i6myy", + "col75": "k410s", + "col76": "st9ux", + "col77": "frpno", + "col78": "h0b62", + "col79": "btj3c", + "col80": "wzlvb", + "col81": "79m6j", + "col82": "z9ryi", + "col83": "ikyqp", + "col84": "x4psh", + "col85": "ofm2p", + "col86": "a7zps", + "col87": "nzb68", + "col88": "pclyl", + "col89": "fi44u", + "col90": "wvevg", + "col91": "bu7kj", + "col92": "b5ved", + "col93": "yl0hm", + "col94": "cdbxe", + "col95": "qj1b4", + "col96": "hjx37", + "col97": "7pf62" + }, + { + "name": "Johnston Park", + "gender": "male", + "company": "Netur", + "col0": "s2s7w", + "col1": "7ew6z", + "col2": "bg5j4", + "col3": "cuun8", + "col4": "qgmdg", + "col5": "1648d", + "col6": "jikme", + "col7": "f8w0s", + "col8": "ykc9q", + "col9": "it6zy", + "col10": "loyww", + "col11": "ofcgr", + "col12": "vg7cz", + "col13": "tqfzj", + "col14": "z2cyc", + "col15": "5lavc", + "col16": "52gbl", + "col17": "uex0c", + "col18": "kwyn8", + "col19": "br11f", + "col20": "tc12i", + "col21": "p4zea", + "col22": "ry8f7", + "col23": "032de", + "col24": "6gn6d", + "col25": "bfs61", + "col26": "pbu8y", + "col27": "3zp93", + "col28": "5k3gf", + "col29": "657sh", + "col30": "4orr0", + "col31": "z0od7", + "col32": "6wdbw", + "col33": "6lvn7", + "col34": "4aqu1", + "col35": "7xsbx", + "col36": "es67n", + "col37": "m29vj", + "col38": "e0w1g", + "col39": "ggq7q", + "col40": "wmv8x", + "col41": "8dwch", + "col42": "nuj5a", + "col43": "imp44", + "col44": "nap1x", + "col45": "crtlt", + "col46": "8ijkx", + "col47": "3o1ko", + "col48": "crkla", + "col49": "o2vx5", + "col50": "f9s2e", + "col51": "647tm", + "col52": "c0sub", + "col53": "pujaa", + "col54": "yaeht", + "col55": "0a1rz", + "col56": "v1sue", + "col57": "hp5q9", + "col58": "kvbdu", + "col59": "n5kgh", + "col60": "34ty8", + "col61": "67dgv", + "col62": "c89kf", + "col63": "p1trc", + "col64": "iq02p", + "col65": "2wjwi", + "col66": "3nu16", + "col67": "gbbey", + "col68": "cx48a", + "col69": "rn276", + "col70": "sgeix", + "col71": "qygag", + "col72": "gtsmv", + "col73": "yl5yi", + "col74": "m8znq", + "col75": "ow9tq", + "col76": "6f9sc", + "col77": "jsmsx", + "col78": "m9xay", + "col79": "w2jez", + "col80": "88irk", + "col81": "qxrt3", + "col82": "twqa6", + "col83": "fw7lm", + "col84": "gyfza", + "col85": "9c2ar", + "col86": "3jsn1", + "col87": "cdy4c", + "col88": "46b4m", + "col89": "qlrpa", + "col90": "wgsso", + "col91": "vjdug", + "col92": "ujotg", + "col93": "bx3iv", + "col94": "00itq", + "col95": "n7jni", + "col96": "gjbr3", + "col97": "alofb" + }, + { + "name": "Wong Craft", + "gender": "male", + "company": "Opticall", + "col0": "ouvti", + "col1": "s2ipu", + "col2": "5mqg1", + "col3": "o9h8o", + "col4": "cucvb", + "col5": "q2pfk", + "col6": "e3ur7", + "col7": "2u56q", + "col8": "gu774", + "col9": "v1rzu", + "col10": "x7xtu", + "col11": "ak2gq", + "col12": "ayxiy", + "col13": "6dwfb", + "col14": "fpkay", + "col15": "973rb", + "col16": "lbde8", + "col17": "hsp7g", + "col18": "1hcsu", + "col19": "rzd7y", + "col20": "pmuzt", + "col21": "r3wzb", + "col22": "7y1kt", + "col23": "2m1o7", + "col24": "va635", + "col25": "ga1ea", + "col26": "3mj98", + "col27": "qi2t3", + "col28": "3ted0", + "col29": "706iz", + "col30": "68d9q", + "col31": "w4vix", + "col32": "2pqr9", + "col33": "s0h2h", + "col34": "yo8kc", + "col35": "s6riz", + "col36": "yxpwt", + "col37": "hak03", + "col38": "p54xy", + "col39": "6xlig", + "col40": "964xj", + "col41": "nhs4n", + "col42": "l6kq9", + "col43": "n3ql7", + "col44": "na8vo", + "col45": "p44yk", + "col46": "fqkp8", + "col47": "1eady", + "col48": "jkiin", + "col49": "lzbwl", + "col50": "8an0v", + "col51": "pok5j", + "col52": "kuupc", + "col53": "sy6jd", + "col54": "qc2py", + "col55": "9e53w", + "col56": "nnbji", + "col57": "w6nea", + "col58": "aylib", + "col59": "j9j7b", + "col60": "v8l4g", + "col61": "fsoqa", + "col62": "5j1fs", + "col63": "9wtot", + "col64": "6ym27", + "col65": "6ygph", + "col66": "g9kpl", + "col67": "zjiwy", + "col68": "hkydh", + "col69": "i4zq4", + "col70": "bvubb", + "col71": "4nib2", + "col72": "l9iwn", + "col73": "giok0", + "col74": "2teyj", + "col75": "g5krb", + "col76": "07242", + "col77": "8w54p", + "col78": "94m5l", + "col79": "4ms58", + "col80": "rjcp2", + "col81": "w0b7y", + "col82": "90hhj", + "col83": "17gzs", + "col84": "86y4l", + "col85": "bgwu6", + "col86": "10igs", + "col87": "64rqp", + "col88": "yla44", + "col89": "446mk", + "col90": "npk9v", + "col91": "hzj82", + "col92": "o73ns", + "col93": "mcos7", + "col94": "63jfs", + "col95": "48ty7", + "col96": "3mubn", + "col97": "r7aj9" + }, + { + "name": "Merritt Cole", + "gender": "male", + "company": "Techtrix", + "col0": "7tdwu", + "col1": "maqcz", + "col2": "nbxh5", + "col3": "e3blb", + "col4": "90lna", + "col5": "9j5wo", + "col6": "9vgk1", + "col7": "c0xje", + "col8": "k51jr", + "col9": "wi90z", + "col10": "e0fhh", + "col11": "ymgtu", + "col12": "k0wcn", + "col13": "qfcoh", + "col14": "yq0em", + "col15": "v4s6j", + "col16": "sh7jg", + "col17": "4yp5o", + "col18": "gp2c9", + "col19": "cze27", + "col20": "bn70w", + "col21": "lb1ii", + "col22": "mtkld", + "col23": "hul36", + "col24": "9fxia", + "col25": "oo5gd", + "col26": "9uij0", + "col27": "nds5s", + "col28": "x7sh9", + "col29": "2mnao", + "col30": "qd4g1", + "col31": "gmubw", + "col32": "j4mu6", + "col33": "hfyim", + "col34": "u18we", + "col35": "7ve3g", + "col36": "5ften", + "col37": "k19uj", + "col38": "nzhnq", + "col39": "2wbq9", + "col40": "5853o", + "col41": "rym13", + "col42": "kazch", + "col43": "wn783", + "col44": "0yntm", + "col45": "oklb2", + "col46": "voqco", + "col47": "50vb4", + "col48": "j5crd", + "col49": "pll8r", + "col50": "hosnd", + "col51": "b57da", + "col52": "1d83z", + "col53": "irj5p", + "col54": "x9vwv", + "col55": "dsxhw", + "col56": "82075", + "col57": "x3emt", + "col58": "jk6rp", + "col59": "rmqdg", + "col60": "dpfss", + "col61": "27onn", + "col62": "f1fq6", + "col63": "4lm8d", + "col64": "fh0hk", + "col65": "xg6wo", + "col66": "awe09", + "col67": "qgfzy", + "col68": "388u5", + "col69": "pof12", + "col70": "5983s", + "col71": "pfwi1", + "col72": "kj8qh", + "col73": "zr9ft", + "col74": "m070s", + "col75": "rhei6", + "col76": "1pj8h", + "col77": "kb7bm", + "col78": "btaq6", + "col79": "lgfon", + "col80": "g8qis", + "col81": "yy2x2", + "col82": "isg2z", + "col83": "xuyt6", + "col84": "qz3bo", + "col85": "x3u1g", + "col86": "s0u7b", + "col87": "q9974", + "col88": "0bzx8", + "col89": "w3rvi", + "col90": "z1cyi", + "col91": "0uayh", + "col92": "7xoxo", + "col93": "252i4", + "col94": "sutcw", + "col95": "lrqop", + "col96": "igl09", + "col97": "71l74" + }, + { + "name": "Dale Byrd", + "gender": "female", + "company": "Kneedles", + "col0": "0habo", + "col1": "u9853", + "col2": "8sfzc", + "col3": "cgt8h", + "col4": "10rku", + "col5": "0fdt0", + "col6": "l1by3", + "col7": "zr1ag", + "col8": "x5ae5", + "col9": "jrl26", + "col10": "u79ja", + "col11": "2h5ws", + "col12": "ynp3u", + "col13": "3ov5o", + "col14": "4m7wr", + "col15": "h1h9v", + "col16": "e0y79", + "col17": "0s6ym", + "col18": "lgo9u", + "col19": "y0jcn", + "col20": "jcuzn", + "col21": "vzr5x", + "col22": "ol28m", + "col23": "e6o3h", + "col24": "dqb24", + "col25": "upgdg", + "col26": "wusc3", + "col27": "vf3gq", + "col28": "p14ec", + "col29": "p85tr", + "col30": "kayjl", + "col31": "fyf7a", + "col32": "cghli", + "col33": "6hpyp", + "col34": "vz8hq", + "col35": "6zxgh", + "col36": "wm2eb", + "col37": "q79ae", + "col38": "gr4nj", + "col39": "3rife", + "col40": "co7mc", + "col41": "770wf", + "col42": "n7yhg", + "col43": "uw9q5", + "col44": "6htti", + "col45": "xqoiz", + "col46": "5dg0v", + "col47": "d8kab", + "col48": "10nh5", + "col49": "scbq6", + "col50": "jp897", + "col51": "9u0a4", + "col52": "zlqmm", + "col53": "6fv2w", + "col54": "fu1jn", + "col55": "m9p7d", + "col56": "53lw5", + "col57": "q6y6n", + "col58": "sh88f", + "col59": "g4ths", + "col60": "jerpc", + "col61": "v63bh", + "col62": "nn0so", + "col63": "qo7yj", + "col64": "u39e5", + "col65": "b8bpd", + "col66": "k6vpq", + "col67": "jqy11", + "col68": "8fwbx", + "col69": "a4sut", + "col70": "ky8c1", + "col71": "xzuvt", + "col72": "wx0pq", + "col73": "fgk21", + "col74": "nyw0w", + "col75": "gyoex", + "col76": "qjn5u", + "col77": "nkfge", + "col78": "qiyba", + "col79": "bi7s0", + "col80": "unbng", + "col81": "jrsz7", + "col82": "0xrzc", + "col83": "6b0nx", + "col84": "k1bud", + "col85": "kum81", + "col86": "cevz8", + "col87": "a9bho", + "col88": "t89dv", + "col89": "pkg1f", + "col90": "jbyds", + "col91": "2exah", + "col92": "vt133", + "col93": "g5ecy", + "col94": "kx5zl", + "col95": "k82yy", + "col96": "4bc1m", + "col97": "cbff4" + }, + { + "name": "Sara Delgado", + "gender": "female", + "company": "Netagy", + "col0": "ajsao", + "col1": "tk1yl", + "col2": "ioeov", + "col3": "bkyft", + "col4": "kk8e6", + "col5": "gcyfq", + "col6": "k8xit", + "col7": "dkfi3", + "col8": "y7085", + "col9": "tcww5", + "col10": "k3yv8", + "col11": "56y63", + "col12": "1hc32", + "col13": "vzt7j", + "col14": "xsds6", + "col15": "z6bj7", + "col16": "ibus7", + "col17": "0bua7", + "col18": "91o7k", + "col19": "7q73g", + "col20": "sp9jv", + "col21": "frkgi", + "col22": "ipnzw", + "col23": "tqz7i", + "col24": "ylscy", + "col25": "9n45f", + "col26": "l36v6", + "col27": "xb8x8", + "col28": "i168u", + "col29": "nvc3u", + "col30": "tc40e", + "col31": "bq3ep", + "col32": "curjt", + "col33": "yxq4u", + "col34": "pkct9", + "col35": "6qh1t", + "col36": "ktnw6", + "col37": "2fd19", + "col38": "r0ina", + "col39": "fjkhz", + "col40": "q0ddq", + "col41": "avym4", + "col42": "8nc08", + "col43": "6uaqy", + "col44": "wtuti", + "col45": "0x4yf", + "col46": "dlxya", + "col47": "h8eoz", + "col48": "53acz", + "col49": "7bg3t", + "col50": "eyiy1", + "col51": "6hi4z", + "col52": "6t2py", + "col53": "0y59z", + "col54": "jam8f", + "col55": "ff6x9", + "col56": "o4a0h", + "col57": "v9r62", + "col58": "rheou", + "col59": "gub3r", + "col60": "dlnui", + "col61": "q0fc7", + "col62": "jilj0", + "col63": "c4txv", + "col64": "uaa6d", + "col65": "1iy76", + "col66": "gigux", + "col67": "cgrcz", + "col68": "j3kq5", + "col69": "oa8ea", + "col70": "c2f7a", + "col71": "vvya7", + "col72": "sexbk", + "col73": "g9boe", + "col74": "bi9rp", + "col75": "bv1uz", + "col76": "xaquc", + "col77": "bhxig", + "col78": "xhzin", + "col79": "x99ac", + "col80": "355k0", + "col81": "d2tjx", + "col82": "6cbna", + "col83": "kca06", + "col84": "wpdpr", + "col85": "z5ko3", + "col86": "hjh2e", + "col87": "g6rsl", + "col88": "237r0", + "col89": "2oa5s", + "col90": "pbl9r", + "col91": "k2q1w", + "col92": "itpg9", + "col93": "qmt54", + "col94": "sjp5d", + "col95": "lvbew", + "col96": "woixk", + "col97": "2gz6e" + }, + { + "name": "Alisha Myers", + "gender": "female", + "company": "Intradisk", + "col0": "kdzmm", + "col1": "zvs5b", + "col2": "41i0b", + "col3": "3hsw2", + "col4": "cmyk6", + "col5": "k8l2e", + "col6": "gvcjy", + "col7": "dm4or", + "col8": "cexf9", + "col9": "zuea2", + "col10": "89zgc", + "col11": "maylz", + "col12": "fu4jh", + "col13": "d9zup", + "col14": "95k9h", + "col15": "68w91", + "col16": "na2u6", + "col17": "emhtc", + "col18": "2y3yi", + "col19": "g1jmg", + "col20": "s04j7", + "col21": "ro6sa", + "col22": "st4l5", + "col23": "m4gje", + "col24": "8l37v", + "col25": "u87f4", + "col26": "o2nj7", + "col27": "f7u3f", + "col28": "cuxbh", + "col29": "5p8ro", + "col30": "nwdb5", + "col31": "hw5j9", + "col32": "2bjp1", + "col33": "h04tv", + "col34": "4se5b", + "col35": "qe2zk", + "col36": "8giqu", + "col37": "96v2v", + "col38": "uamzr", + "col39": "1dsby", + "col40": "oor0o", + "col41": "zsash", + "col42": "k6fgb", + "col43": "97xkh", + "col44": "c55m1", + "col45": "0hmco", + "col46": "jt52e", + "col47": "jk9ey", + "col48": "i1f3s", + "col49": "0mz6p", + "col50": "i7eze", + "col51": "sp2kr", + "col52": "xu5yk", + "col53": "o89t1", + "col54": "zgt2a", + "col55": "xl5ic", + "col56": "qtyl4", + "col57": "rs94m", + "col58": "5qaaj", + "col59": "a0mxs", + "col60": "kd188", + "col61": "1lfnn", + "col62": "yezpt", + "col63": "xb4zz", + "col64": "2jh6o", + "col65": "9dss8", + "col66": "khgpg", + "col67": "4frv1", + "col68": "7vqx8", + "col69": "6ibxc", + "col70": "5blr7", + "col71": "vlh8r", + "col72": "jinuv", + "col73": "7sy7m", + "col74": "6xi5i", + "col75": "wt2qn", + "col76": "5h4lk", + "col77": "7zdtt", + "col78": "hq6k8", + "col79": "bgd5a", + "col80": "y2j2e", + "col81": "hcnd6", + "col82": "xzkin", + "col83": "fb70b", + "col84": "jzin9", + "col85": "9xmdu", + "col86": "limvj", + "col87": "8vnlf", + "col88": "07fx8", + "col89": "516sh", + "col90": "3irvh", + "col91": "t89p2", + "col92": "kb7ry", + "col93": "gz62j", + "col94": "ogvrk", + "col95": "l2k4a", + "col96": "gseke", + "col97": "k74f4" + }, + { + "name": "Felecia Smith", + "gender": "female", + "company": "Futurity", + "col0": "sqd7v", + "col1": "g97zf", + "col2": "2fcii", + "col3": "7b14v", + "col4": "yhan1", + "col5": "xusub", + "col6": "0gngm", + "col7": "tmcpl", + "col8": "pq2h8", + "col9": "7pa49", + "col10": "iob52", + "col11": "sxw96", + "col12": "gngoe", + "col13": "w3voe", + "col14": "hrw45", + "col15": "tysuu", + "col16": "37vlu", + "col17": "shkn9", + "col18": "7w99k", + "col19": "w8cs1", + "col20": "t9cik", + "col21": "ucjoh", + "col22": "nouav", + "col23": "3vdz0", + "col24": "mxgm8", + "col25": "wzq7t", + "col26": "r28g8", + "col27": "2d0l0", + "col28": "tssmw", + "col29": "mj3zz", + "col30": "urn8b", + "col31": "zzyr0", + "col32": "5weca", + "col33": "kge3u", + "col34": "hcx55", + "col35": "u3h3x", + "col36": "3ip93", + "col37": "ojehk", + "col38": "xqr5s", + "col39": "zi0aw", + "col40": "vinio", + "col41": "cgzzg", + "col42": "x84s3", + "col43": "g6sz5", + "col44": "ghzwa", + "col45": "mmoeh", + "col46": "4hy0r", + "col47": "rlp61", + "col48": "wkdhr", + "col49": "z7v2k", + "col50": "jtzv3", + "col51": "qcs14", + "col52": "kr5lq", + "col53": "1ibkt", + "col54": "vph2t", + "col55": "wklel", + "col56": "q878j", + "col57": "c45w6", + "col58": "xb54d", + "col59": "lezk5", + "col60": "zg6yr", + "col61": "oow4i", + "col62": "v02po", + "col63": "v5jxi", + "col64": "qadoh", + "col65": "da186", + "col66": "ui3ip", + "col67": "qsn76", + "col68": "4wt23", + "col69": "r4ecx", + "col70": "dnjvm", + "col71": "elvaa", + "col72": "pn6ip", + "col73": "3zar3", + "col74": "chwdr", + "col75": "oar5b", + "col76": "qqepa", + "col77": "3d06n", + "col78": "cr8sd", + "col79": "2dfvh", + "col80": "s4pdx", + "col81": "2k4xm", + "col82": "1rmh4", + "col83": "ptphz", + "col84": "av5vi", + "col85": "t1xis", + "col86": "co18j", + "col87": "qvzed", + "col88": "1sk95", + "col89": "xvabo", + "col90": "xthow", + "col91": "tc37v", + "col92": "zfx3y", + "col93": "kc1m9", + "col94": "asueq", + "col95": "digpr", + "col96": "pr7ap", + "col97": "9e8tl" + }, + { + "name": "Neal Harvey", + "gender": "male", + "company": "Pyramax", + "col0": "gqav0", + "col1": "c0866", + "col2": "kp2d3", + "col3": "2m02b", + "col4": "zpffd", + "col5": "tjlwf", + "col6": "o8o8n", + "col7": "bhruc", + "col8": "cmuzj", + "col9": "2e6nv", + "col10": "600ig", + "col11": "mvrkz", + "col12": "jaga7", + "col13": "5pkoi", + "col14": "eou54", + "col15": "yn5bb", + "col16": "oy4ks", + "col17": "7drkj", + "col18": "lyhhb", + "col19": "fbc41", + "col20": "oxmsy", + "col21": "akuex", + "col22": "goa8c", + "col23": "1ihlx", + "col24": "5dqmg", + "col25": "qqrk6", + "col26": "6ah43", + "col27": "87qlk", + "col28": "ddiey", + "col29": "4n0dw", + "col30": "a6xex", + "col31": "dx2bj", + "col32": "j0o04", + "col33": "z6x4c", + "col34": "esnc6", + "col35": "vzael", + "col36": "fz2oq", + "col37": "7wfyj", + "col38": "ohu92", + "col39": "qglxy", + "col40": "7sjyl", + "col41": "bke2d", + "col42": "l3i5h", + "col43": "4evtu", + "col44": "vvvtc", + "col45": "elp58", + "col46": "xbxdr", + "col47": "00ibm", + "col48": "6lddx", + "col49": "q0qwr", + "col50": "5oyh4", + "col51": "nigym", + "col52": "wh2a9", + "col53": "8rocx", + "col54": "k4ilb", + "col55": "hlmft", + "col56": "sm0q4", + "col57": "pu05x", + "col58": "9uz4u", + "col59": "sj9w7", + "col60": "1gi5i", + "col61": "xv5a4", + "col62": "einsi", + "col63": "p6dkh", + "col64": "t1gs0", + "col65": "ec7i3", + "col66": "2gmge", + "col67": "yo69k", + "col68": "l28l2", + "col69": "y0f5h", + "col70": "ih0nm", + "col71": "wuoaz", + "col72": "oq4du", + "col73": "jo38j", + "col74": "k7iak", + "col75": "6rdna", + "col76": "nyx13", + "col77": "70bc2", + "col78": "f4rtc", + "col79": "pcwaq", + "col80": "9ka0e", + "col81": "x5t9s", + "col82": "5iovq", + "col83": "wid5s", + "col84": "5ow2s", + "col85": "tkfxz", + "col86": "zkcz8", + "col87": "nf2gy", + "col88": "8u2c0", + "col89": "d6bmz", + "col90": "epgpa", + "col91": "swrcr", + "col92": "digfi", + "col93": "2c0zk", + "col94": "26dwh", + "col95": "asrq0", + "col96": "gugco", + "col97": "tsodd" + }, + { + "name": "Nola Miles", + "gender": "female", + "company": "Sonique", + "col0": "zu0by", + "col1": "5saww", + "col2": "xzmw6", + "col3": "xsvl4", + "col4": "yo8dj", + "col5": "nwuzh", + "col6": "8zldf", + "col7": "8bvy0", + "col8": "y1ara", + "col9": "h1vxc", + "col10": "rxbd9", + "col11": "e4txg", + "col12": "w7twt", + "col13": "jid2d", + "col14": "iz92x", + "col15": "gh0sk", + "col16": "ujn2m", + "col17": "tj1o6", + "col18": "qd9vf", + "col19": "txchz", + "col20": "5exgx", + "col21": "jwmh6", + "col22": "q2l98", + "col23": "6wnjz", + "col24": "pqeh3", + "col25": "c3270", + "col26": "smp7a", + "col27": "o0dhc", + "col28": "xdvbm", + "col29": "9b26r", + "col30": "ubmyl", + "col31": "1t31y", + "col32": "kco19", + "col33": "l7mga", + "col34": "3bfvj", + "col35": "1uex7", + "col36": "8vgo3", + "col37": "2cdno", + "col38": "gm9ev", + "col39": "4bjt0", + "col40": "g8gpi", + "col41": "v4sz3", + "col42": "5r9sm", + "col43": "dupr6", + "col44": "6a6wi", + "col45": "qizlq", + "col46": "au6uo", + "col47": "dsrb4", + "col48": "ti0t2", + "col49": "74bn7", + "col50": "kr5hg", + "col51": "iqc31", + "col52": "pu3gg", + "col53": "vbxs9", + "col54": "lzpjs", + "col55": "1cew5", + "col56": "iskxb", + "col57": "065d1", + "col58": "ybvd1", + "col59": "500hb", + "col60": "cqk7c", + "col61": "5mh9q", + "col62": "f2cvg", + "col63": "rr6ih", + "col64": "qdlrf", + "col65": "50jgh", + "col66": "dm3oe", + "col67": "93ysw", + "col68": "8qrkt", + "col69": "jvoa0", + "col70": "5nydg", + "col71": "6coku", + "col72": "gfxmr", + "col73": "hgmil", + "col74": "s4s1j", + "col75": "ig2ub", + "col76": "4uwlc", + "col77": "8327j", + "col78": "2isra", + "col79": "g1vi8", + "col80": "v2mej", + "col81": "cjmr7", + "col82": "f5zbh", + "col83": "h5rn1", + "col84": "z51e3", + "col85": "6qj00", + "col86": "01h7n", + "col87": "emn97", + "col88": "9scij", + "col89": "e09u7", + "col90": "sduy7", + "col91": "lsd30", + "col92": "sy7hv", + "col93": "0msdc", + "col94": "bazt5", + "col95": "blwp2", + "col96": "bdej3", + "col97": "7qh8h" + }, + { + "name": "Herring Pierce", + "gender": "male", + "company": "Geeketron", + "col0": "fu9d3", + "col1": "9zn6z", + "col2": "l59tt", + "col3": "jwt07", + "col4": "2reyu", + "col5": "tqa7g", + "col6": "hwav7", + "col7": "83hek", + "col8": "nj6lb", + "col9": "thc62", + "col10": "2lbfx", + "col11": "qrfu1", + "col12": "bvymp", + "col13": "rwmpn", + "col14": "iv8vg", + "col15": "x62gv", + "col16": "zmcnx", + "col17": "mp6ig", + "col18": "hy96n", + "col19": "jgugg", + "col20": "y3nwp", + "col21": "d82so", + "col22": "kzqbv", + "col23": "y6wwj", + "col24": "8uciq", + "col25": "cph1c", + "col26": "d23ga", + "col27": "u8jbk", + "col28": "2jos3", + "col29": "ocw5n", + "col30": "fh7vx", + "col31": "nt2oe", + "col32": "0byfi", + "col33": "jqr3n", + "col34": "d1bsb", + "col35": "lobr5", + "col36": "nywhi", + "col37": "65ew8", + "col38": "s5qli", + "col39": "85m29", + "col40": "hwy1u", + "col41": "bu098", + "col42": "3pm7g", + "col43": "4mmxd", + "col44": "rrhhj", + "col45": "p0k0w", + "col46": "w0ruo", + "col47": "y2ywt", + "col48": "0b99s", + "col49": "q9qwb", + "col50": "u23ep", + "col51": "pvk1i", + "col52": "0byyv", + "col53": "zdkvj", + "col54": "ktml9", + "col55": "3r23d", + "col56": "owii4", + "col57": "167oj", + "col58": "86bip", + "col59": "grhbe", + "col60": "eh247", + "col61": "hsiq8", + "col62": "r9stj", + "col63": "0kzxl", + "col64": "z1w1w", + "col65": "b2jbk", + "col66": "gm499", + "col67": "xl1in", + "col68": "ex0iy", + "col69": "kd4eb", + "col70": "h5cxb", + "col71": "lq1cg", + "col72": "8fh39", + "col73": "0u2ew", + "col74": "vlbap", + "col75": "ezh19", + "col76": "h0xq6", + "col77": "3se36", + "col78": "2btyh", + "col79": "r5wl2", + "col80": "mb18n", + "col81": "f7rhf", + "col82": "87pyw", + "col83": "iddp7", + "col84": "h8mmo", + "col85": "ldr40", + "col86": "t157v", + "col87": "a3ana", + "col88": "yvw1z", + "col89": "ytjm7", + "col90": "1rewb", + "col91": "juxcm", + "col92": "uu2tc", + "col93": "xc74i", + "col94": "12eeo", + "col95": "tt3h7", + "col96": "dody4", + "col97": "pvps0" + }, + { + "name": "Shelley Rodriquez", + "gender": "female", + "company": "Bostonic", + "col0": "wjd3k", + "col1": "brdtt", + "col2": "i6zw5", + "col3": "g2a57", + "col4": "z915n", + "col5": "x3e8v", + "col6": "x12cj", + "col7": "hjuhv", + "col8": "xu75u", + "col9": "7ph5d", + "col10": "o7zk1", + "col11": "gliqd", + "col12": "hglq7", + "col13": "5l9v7", + "col14": "dknuq", + "col15": "j3ub7", + "col16": "tim5i", + "col17": "8bb4z", + "col18": "lly0w", + "col19": "2r7zl", + "col20": "1ts5e", + "col21": "e0sb0", + "col22": "gpll8", + "col23": "eg6eg", + "col24": "upedb", + "col25": "n0o9o", + "col26": "y106j", + "col27": "h3bfe", + "col28": "25udv", + "col29": "ihbbp", + "col30": "zk02u", + "col31": "zkov0", + "col32": "0o6s2", + "col33": "seran", + "col34": "gtj3j", + "col35": "zygcp", + "col36": "g3c90", + "col37": "w76sp", + "col38": "udoxd", + "col39": "am74i", + "col40": "gr5zk", + "col41": "9ghjr", + "col42": "hf4dc", + "col43": "1r8sc", + "col44": "bq381", + "col45": "a6myp", + "col46": "9buir", + "col47": "0w0jk", + "col48": "df4ch", + "col49": "hrbhv", + "col50": "qoj7v", + "col51": "j39hy", + "col52": "lomli", + "col53": "69bsc", + "col54": "qkzq2", + "col55": "wk61a", + "col56": "eya81", + "col57": "ykc39", + "col58": "tmvxo", + "col59": "fqmeq", + "col60": "f7bkp", + "col61": "o513t", + "col62": "e4s1e", + "col63": "lzqwb", + "col64": "u1ikg", + "col65": "1ilbm", + "col66": "i9yme", + "col67": "6uvn3", + "col68": "skhb9", + "col69": "btpc3", + "col70": "604kx", + "col71": "sslnj", + "col72": "73pib", + "col73": "dbbif", + "col74": "npqzj", + "col75": "5egmh", + "col76": "3b1m7", + "col77": "7nyh0", + "col78": "3tr43", + "col79": "9yjur", + "col80": "88i4d", + "col81": "krrgr", + "col82": "g8xtx", + "col83": "4jpa7", + "col84": "39170", + "col85": "hjrmq", + "col86": "gd8fa", + "col87": "tckpu", + "col88": "3jzx6", + "col89": "0b2zs", + "col90": "m07on", + "col91": "mm8j2", + "col92": "onnmn", + "col93": "tmwf9", + "col94": "piw88", + "col95": "v0ohv", + "col96": "b0vy4", + "col97": "cvgvv" + }, + { + "name": "Cora Chase", + "gender": "female", + "company": "Isonus", + "col0": "7mikj", + "col1": "tquyc", + "col2": "cb3im", + "col3": "6xatv", + "col4": "bkn1s", + "col5": "i904v", + "col6": "48y74", + "col7": "cta4d", + "col8": "00yuk", + "col9": "evdk3", + "col10": "sgs80", + "col11": "0md5s", + "col12": "iw00e", + "col13": "l143o", + "col14": "kx27s", + "col15": "ary5j", + "col16": "rgynw", + "col17": "c6m57", + "col18": "xdrtw", + "col19": "bwat9", + "col20": "fdevp", + "col21": "l6fk5", + "col22": "hk2sc", + "col23": "eik1d", + "col24": "tw8vd", + "col25": "5yno0", + "col26": "qyyeq", + "col27": "w2xxk", + "col28": "9csio", + "col29": "bmseh", + "col30": "mztrx", + "col31": "e168m", + "col32": "cdv4z", + "col33": "duqg1", + "col34": "0lnh7", + "col35": "a2wbk", + "col36": "3p1xy", + "col37": "nmrtf", + "col38": "92i6m", + "col39": "bc2rw", + "col40": "nisgz", + "col41": "r731l", + "col42": "fyqnt", + "col43": "a1e3k", + "col44": "64wrq", + "col45": "effe1", + "col46": "1b2pf", + "col47": "d3qlj", + "col48": "tob57", + "col49": "p0i81", + "col50": "1kmk3", + "col51": "wps9q", + "col52": "bapp3", + "col53": "bha2l", + "col54": "7kqzu", + "col55": "xhugz", + "col56": "svndz", + "col57": "rmezq", + "col58": "zp9js", + "col59": "anf25", + "col60": "b08ka", + "col61": "zyacp", + "col62": "sr6sw", + "col63": "ms0nk", + "col64": "5jbfv", + "col65": "jaire", + "col66": "2igxu", + "col67": "k50aa", + "col68": "ou1c7", + "col69": "xmb28", + "col70": "z2lpz", + "col71": "e3vmq", + "col72": "mws1w", + "col73": "b1d8w", + "col74": "myzni", + "col75": "lrx3w", + "col76": "bpecl", + "col77": "qyeya", + "col78": "tq2jb", + "col79": "x4voh", + "col80": "aqwla", + "col81": "kg39j", + "col82": "jo8q0", + "col83": "jsc2q", + "col84": "yglea", + "col85": "sg9je", + "col86": "5i1c0", + "col87": "8w9pf", + "col88": "iwmqe", + "col89": "23xb5", + "col90": "x9dtj", + "col91": "q56yq", + "col92": "1ykn0", + "col93": "rm9dp", + "col94": "jw747", + "col95": "6holx", + "col96": "t15a4", + "col97": "2ka0n" + }, + { + "name": "Mckay Santos", + "gender": "male", + "company": "Amtas", + "col0": "l845c", + "col1": "4tsp5", + "col2": "bue5t", + "col3": "ib24m", + "col4": "u7c3u", + "col5": "r5wvg", + "col6": "z3ijd", + "col7": "nlwg3", + "col8": "qlqo5", + "col9": "aa4vx", + "col10": "g3tcj", + "col11": "nzd2w", + "col12": "112jy", + "col13": "q4lwx", + "col14": "7g3d6", + "col15": "xsbxc", + "col16": "iamg6", + "col17": "qh3vf", + "col18": "2hvpd", + "col19": "jx3b9", + "col20": "go8g8", + "col21": "zyuq8", + "col22": "aubeb", + "col23": "w9dxz", + "col24": "14ugl", + "col25": "6ndb9", + "col26": "ziik7", + "col27": "r201z", + "col28": "91o7f", + "col29": "7nh5t", + "col30": "1gtjy", + "col31": "dnxcu", + "col32": "t2qq4", + "col33": "310y1", + "col34": "r4vh0", + "col35": "71xo0", + "col36": "byzqm", + "col37": "a67sk", + "col38": "m4wr4", + "col39": "7cmw0", + "col40": "hhykz", + "col41": "j50yw", + "col42": "xf132", + "col43": "88v4d", + "col44": "om361", + "col45": "737hr", + "col46": "i852a", + "col47": "fxcv9", + "col48": "ccrwe", + "col49": "jvix7", + "col50": "pz31l", + "col51": "co08k", + "col52": "a3syw", + "col53": "lqhad", + "col54": "xvmpi", + "col55": "z1ef9", + "col56": "sxw93", + "col57": "ipeo1", + "col58": "lu6kx", + "col59": "5biht", + "col60": "6mjfq", + "col61": "so0e5", + "col62": "b0d96", + "col63": "0q95c", + "col64": "5jvp7", + "col65": "7u8ge", + "col66": "px344", + "col67": "g212w", + "col68": "ptkup", + "col69": "qmg59", + "col70": "yu60m", + "col71": "46ui3", + "col72": "xg2kv", + "col73": "r215k", + "col74": "53cco", + "col75": "a2149", + "col76": "iqtr1", + "col77": "6qjpc", + "col78": "kkabx", + "col79": "u2fcw", + "col80": "2dn0j", + "col81": "6wc8c", + "col82": "ckahc", + "col83": "34dzi", + "col84": "8gmm3", + "col85": "edqvc", + "col86": "soi37", + "col87": "4l2ox", + "col88": "aaowk", + "col89": "pluvh", + "col90": "ls87k", + "col91": "ghtzk", + "col92": "avdqp", + "col93": "8sgi5", + "col94": "c2xc6", + "col95": "0jqin", + "col96": "dtjpn", + "col97": "c26t1" + }, + { + "name": "Hilda Crane", + "gender": "female", + "company": "Jumpstack", + "col0": "d53g1", + "col1": "l74eb", + "col2": "d9sxi", + "col3": "5q4xo", + "col4": "06im5", + "col5": "0drxm", + "col6": "4rqwh", + "col7": "3lviz", + "col8": "l2h9b", + "col9": "lvjwq", + "col10": "m3r8g", + "col11": "wwhip", + "col12": "35xcr", + "col13": "7ktqo", + "col14": "jeiss", + "col15": "19wnx", + "col16": "vrc0z", + "col17": "qmqmr", + "col18": "kh2nx", + "col19": "egecd", + "col20": "y64o5", + "col21": "oyup4", + "col22": "b46d9", + "col23": "beh23", + "col24": "c52tw", + "col25": "fdovw", + "col26": "07h42", + "col27": "edg97", + "col28": "yvcb1", + "col29": "1xvjo", + "col30": "nocmb", + "col31": "66exv", + "col32": "mkzuk", + "col33": "7ee7j", + "col34": "v1tsc", + "col35": "m6xjq", + "col36": "0jiu6", + "col37": "97g4l", + "col38": "paini", + "col39": "1fiup", + "col40": "mj4qo", + "col41": "jhbig", + "col42": "u63gr", + "col43": "c4xwn", + "col44": "dyb0x", + "col45": "ovniv", + "col46": "rujwv", + "col47": "u3ooa", + "col48": "m9w5y", + "col49": "uslvc", + "col50": "16qjw", + "col51": "hxhd5", + "col52": "xxdlj", + "col53": "haijt", + "col54": "zro81", + "col55": "tb19z", + "col56": "s2cjz", + "col57": "ykk7x", + "col58": "zpfwv", + "col59": "kvyyt", + "col60": "rw14e", + "col61": "ia9ti", + "col62": "5puh7", + "col63": "51udq", + "col64": "4rujl", + "col65": "1j4h2", + "col66": "p8ar9", + "col67": "6zxkh", + "col68": "5mz4h", + "col69": "2d9oq", + "col70": "7t2ej", + "col71": "tr5fm", + "col72": "yuj92", + "col73": "o6cfi", + "col74": "6hp5n", + "col75": "cnraw", + "col76": "anknq", + "col77": "mx4vq", + "col78": "ar2zo", + "col79": "xffn2", + "col80": "ln4p1", + "col81": "ngyuq", + "col82": "4yq64", + "col83": "ruhz0", + "col84": "pf0oz", + "col85": "c5oe7", + "col86": "8yr26", + "col87": "0ew6o", + "col88": "vu6o2", + "col89": "gradf", + "col90": "3llgk", + "col91": "rvu7h", + "col92": "ikubl", + "col93": "4c3ow", + "col94": "eus7n", + "col95": "e12xl", + "col96": "4bm52", + "col97": "w7ltf" + }, + { + "name": "Jeanne Lindsay", + "gender": "female", + "company": "Genesynk", + "col0": "gvd0d", + "col1": "gyaq1", + "col2": "trx8a", + "col3": "thke7", + "col4": "lswji", + "col5": "rbwgt", + "col6": "6mxd7", + "col7": "jk28g", + "col8": "r0eiw", + "col9": "okeii", + "col10": "31jtv", + "col11": "gf6rn", + "col12": "7nl98", + "col13": "jcqau", + "col14": "ld0c7", + "col15": "86tsy", + "col16": "8sdxg", + "col17": "x56cn", + "col18": "83i5o", + "col19": "mrk9z", + "col20": "avdi5", + "col21": "um3zl", + "col22": "roz26", + "col23": "1jvjo", + "col24": "h1w95", + "col25": "iv8jq", + "col26": "gq73e", + "col27": "xy7b2", + "col28": "91prh", + "col29": "h3p21", + "col30": "vvimb", + "col31": "hglez", + "col32": "jw178", + "col33": "8rw1x", + "col34": "3z3t2", + "col35": "su0bo", + "col36": "mntyy", + "col37": "blzw7", + "col38": "2rj22", + "col39": "n66pw", + "col40": "6716u", + "col41": "m5mpk", + "col42": "mnib7", + "col43": "t5b0v", + "col44": "ogwjp", + "col45": "thfec", + "col46": "4hrh2", + "col47": "8nyrc", + "col48": "7a42q", + "col49": "ljlwu", + "col50": "1061w", + "col51": "kt6v2", + "col52": "1vwhc", + "col53": "y12bb", + "col54": "abxla", + "col55": "kp3tz", + "col56": "19xx2", + "col57": "b6e8b", + "col58": "ukumm", + "col59": "7eoxx", + "col60": "9qbe8", + "col61": "165b6", + "col62": "twoau", + "col63": "r59bk", + "col64": "7p3gx", + "col65": "e5blw", + "col66": "zk1dh", + "col67": "awvi7", + "col68": "00v80", + "col69": "b26ek", + "col70": "w4tvz", + "col71": "zws19", + "col72": "f8id2", + "col73": "chvtt", + "col74": "2cdjq", + "col75": "v1kny", + "col76": "j8iy4", + "col77": "ivofx", + "col78": "kiwa6", + "col79": "s8co6", + "col80": "b0rw1", + "col81": "0f1mc", + "col82": "x6mvk", + "col83": "02t6x", + "col84": "kk9b0", + "col85": "n6v97", + "col86": "f0w6v", + "col87": "9v7hr", + "col88": "6zqqz", + "col89": "y2k7j", + "col90": "v5yy7", + "col91": "jfa3p", + "col92": "yatm0", + "col93": "ne418", + "col94": "5kwkc", + "col95": "h2479", + "col96": "j12an", + "col97": "o74nr" + }, + { + "name": "Frye Sharpe", + "gender": "male", + "company": "Eplode", + "col0": "hmgrz", + "col1": "8f89l", + "col2": "zsem3", + "col3": "ery9x", + "col4": "zt57r", + "col5": "9i7ng", + "col6": "8k0q7", + "col7": "emxya", + "col8": "cu8r3", + "col9": "j8oni", + "col10": "h32fz", + "col11": "qlveu", + "col12": "grili", + "col13": "21nv0", + "col14": "4db7z", + "col15": "xzuw4", + "col16": "aq5iq", + "col17": "1rj9b", + "col18": "lfxnk", + "col19": "kdwci", + "col20": "3j52i", + "col21": "qntis", + "col22": "ooacr", + "col23": "cwu8r", + "col24": "9zo3h", + "col25": "ti0lz", + "col26": "8kgg5", + "col27": "chtj4", + "col28": "6dbqq", + "col29": "4na90", + "col30": "x8ked", + "col31": "nus8y", + "col32": "zi4d7", + "col33": "bysib", + "col34": "kpkig", + "col35": "u0ge3", + "col36": "5sb0i", + "col37": "bf993", + "col38": "7rh7r", + "col39": "fdnnw", + "col40": "9w3pe", + "col41": "fvp7y", + "col42": "xdjxw", + "col43": "n276z", + "col44": "i6ijb", + "col45": "k9t7x", + "col46": "fc2nx", + "col47": "hf95b", + "col48": "e7g01", + "col49": "eqdbm", + "col50": "qb2i2", + "col51": "hkzfj", + "col52": "25etp", + "col53": "joetn", + "col54": "phvor", + "col55": "pc9mv", + "col56": "57kk7", + "col57": "k7y6e", + "col58": "wnfmp", + "col59": "zz7d2", + "col60": "8g4yk", + "col61": "ek7tg", + "col62": "0mpd0", + "col63": "29v97", + "col64": "zjb21", + "col65": "lawp5", + "col66": "hsy57", + "col67": "6eiox", + "col68": "9sw2q", + "col69": "d5wwh", + "col70": "2mbid", + "col71": "o8w30", + "col72": "6ef7w", + "col73": "p0ggx", + "col74": "b09y5", + "col75": "t1uc6", + "col76": "v52sa", + "col77": "5uy4c", + "col78": "jrl4q", + "col79": "1neff", + "col80": "bky7b", + "col81": "7f2n8", + "col82": "brts2", + "col83": "2lqor", + "col84": "i9959", + "col85": "3al0u", + "col86": "tvi2r", + "col87": "9vhlz", + "col88": "a643n", + "col89": "cdqdq", + "col90": "8mjvb", + "col91": "p7c35", + "col92": "57cuj", + "col93": "mseac", + "col94": "plx75", + "col95": "5yrip", + "col96": "8zdav", + "col97": "3f76r" + }, + { + "name": "Velma Fry", + "gender": "female", + "company": "Ronelon", + "col0": "0yu2p", + "col1": "19sb0", + "col2": "xdjkf", + "col3": "hci4p", + "col4": "5f1ie", + "col5": "9n4t9", + "col6": "phwqb", + "col7": "mjhtu", + "col8": "0wkzp", + "col9": "bsswl", + "col10": "yo589", + "col11": "dmn7p", + "col12": "xvvy4", + "col13": "oac1d", + "col14": "fbizc", + "col15": "ui8n8", + "col16": "s4ztv", + "col17": "egk7u", + "col18": "3l7ma", + "col19": "901xe", + "col20": "xgcda", + "col21": "mewlj", + "col22": "jenky", + "col23": "jlkrs", + "col24": "t1bcg", + "col25": "1z0ok", + "col26": "n7rnd", + "col27": "3kl53", + "col28": "0tk4k", + "col29": "dq9y7", + "col30": "qz9wa", + "col31": "twmv7", + "col32": "bra76", + "col33": "t8ico", + "col34": "9ys14", + "col35": "a7f30", + "col36": "gus2m", + "col37": "pag5e", + "col38": "wwhjg", + "col39": "qn0bk", + "col40": "7a55j", + "col41": "y32bl", + "col42": "k5dot", + "col43": "j9b8u", + "col44": "nuu6z", + "col45": "jtxuz", + "col46": "y3e20", + "col47": "6rbz7", + "col48": "wuz4l", + "col49": "n073d", + "col50": "jreqs", + "col51": "o3ath", + "col52": "13uvu", + "col53": "vkxnk", + "col54": "4ch5b", + "col55": "6m0b7", + "col56": "bvych", + "col57": "78cac", + "col58": "wgwzc", + "col59": "qwp16", + "col60": "nq7fj", + "col61": "ljqwv", + "col62": "mae2f", + "col63": "1dzcu", + "col64": "zrxhy", + "col65": "ledwg", + "col66": "khx4k", + "col67": "k590j", + "col68": "ep39v", + "col69": "p5mux", + "col70": "cog9q", + "col71": "pm041", + "col72": "4sboe", + "col73": "l9etu", + "col74": "9w96q", + "col75": "iakk3", + "col76": "otxcu", + "col77": "dwa84", + "col78": "012eh", + "col79": "eaz8i", + "col80": "gnr9c", + "col81": "m1mcp", + "col82": "1f1js", + "col83": "z8dfw", + "col84": "rnlv8", + "col85": "xm9fl", + "col86": "9w78p", + "col87": "wn945", + "col88": "x6zd5", + "col89": "5lbjr", + "col90": "rzz2o", + "col91": "iytir", + "col92": "8zpwj", + "col93": "0714j", + "col94": "zd8sb", + "col95": "p4iu2", + "col96": "9qwql", + "col97": "97cd6" + }, + { + "name": "Reyna Espinoza", + "gender": "female", + "company": "Prismatic", + "col0": "oks6m", + "col1": "xvzoz", + "col2": "xzyqo", + "col3": "76lqg", + "col4": "tcxmt", + "col5": "mm7dc", + "col6": "hje26", + "col7": "g2jol", + "col8": "yz0o9", + "col9": "p0rxv", + "col10": "pjfxq", + "col11": "hrmyc", + "col12": "t3hsm", + "col13": "ep41c", + "col14": "p56sh", + "col15": "nrxg4", + "col16": "pbbew", + "col17": "tfjpf", + "col18": "c8vk9", + "col19": "w3z3m", + "col20": "anqeu", + "col21": "y4x3x", + "col22": "l3nz0", + "col23": "fmnfj", + "col24": "vbx8w", + "col25": "t6nk4", + "col26": "cwhn7", + "col27": "vihvc", + "col28": "4j2we", + "col29": "v8uxx", + "col30": "ps4at", + "col31": "vix7i", + "col32": "qd5z0", + "col33": "c57v0", + "col34": "kbqa9", + "col35": "v89mf", + "col36": "okzp7", + "col37": "3xmym", + "col38": "s0o9r", + "col39": "1fduo", + "col40": "k0c93", + "col41": "e2t7w", + "col42": "bnrgn", + "col43": "74xa2", + "col44": "i04b2", + "col45": "g6fpu", + "col46": "j3syk", + "col47": "9atm4", + "col48": "ray2p", + "col49": "bxfmc", + "col50": "xa0e7", + "col51": "a5tzx", + "col52": "9tz2a", + "col53": "ke9pn", + "col54": "vybrj", + "col55": "oo5lv", + "col56": "so6nh", + "col57": "td2ql", + "col58": "gtytn", + "col59": "hlhlv", + "col60": "5z845", + "col61": "j3tcn", + "col62": "mdnnj", + "col63": "sivby", + "col64": "2mpgt", + "col65": "t7get", + "col66": "uhbxl", + "col67": "d6lx7", + "col68": "78dum", + "col69": "qxys4", + "col70": "b3n5p", + "col71": "vg1er", + "col72": "mqilk", + "col73": "cu66f", + "col74": "6fydj", + "col75": "l5z5l", + "col76": "paobc", + "col77": "qhcor", + "col78": "lx3kp", + "col79": "uh4nm", + "col80": "nskf1", + "col81": "i4ai0", + "col82": "knntm", + "col83": "u2qcf", + "col84": "qjbw2", + "col85": "6gwsl", + "col86": "zeyp8", + "col87": "05fj2", + "col88": "bnb13", + "col89": "yfbpz", + "col90": "t9f8o", + "col91": "k1zvp", + "col92": "vzf28", + "col93": "fpb87", + "col94": "dx4y8", + "col95": "4mpl3", + "col96": "iu1om", + "col97": "khvkl" + }, + { + "name": "Spencer Sloan", + "gender": "male", + "company": "Comverges", + "col0": "a9f4n", + "col1": "d1r2l", + "col2": "6akeg", + "col3": "thn9j", + "col4": "tg04n", + "col5": "qmwd6", + "col6": "klnfv", + "col7": "vnxqm", + "col8": "sivuy", + "col9": "v6l9e", + "col10": "a2d9a", + "col11": "wl0dp", + "col12": "k04pg", + "col13": "pdbfv", + "col14": "na0il", + "col15": "2e163", + "col16": "kqne0", + "col17": "pzzlt", + "col18": "rl1lv", + "col19": "dr43e", + "col20": "yxgsp", + "col21": "sf375", + "col22": "4gs8w", + "col23": "2yicy", + "col24": "0h0fp", + "col25": "1lxab", + "col26": "wtwp5", + "col27": "8mnzh", + "col28": "37fay", + "col29": "a6kz9", + "col30": "1xp85", + "col31": "diet8", + "col32": "i9kw9", + "col33": "ae4ac", + "col34": "pdzpk", + "col35": "zdb8f", + "col36": "va4nb", + "col37": "ssg89", + "col38": "ybirf", + "col39": "catsx", + "col40": "ftndz", + "col41": "0n3mv", + "col42": "icyij", + "col43": "fbf1z", + "col44": "eo1ab", + "col45": "u689q", + "col46": "lltk4", + "col47": "82s6p", + "col48": "fomuy", + "col49": "tcp6y", + "col50": "cj8uw", + "col51": "9uxmn", + "col52": "79e64", + "col53": "i0fca", + "col54": "wtcz3", + "col55": "rofjs", + "col56": "miyvr", + "col57": "ihxrn", + "col58": "yacam", + "col59": "lokiz", + "col60": "dvh9q", + "col61": "jlups", + "col62": "6gdn1", + "col63": "wwe9x", + "col64": "m961n", + "col65": "6rjqc", + "col66": "jfbh3", + "col67": "41odf", + "col68": "x63rw", + "col69": "5ixwv", + "col70": "lidmx", + "col71": "l5u6t", + "col72": "do2sz", + "col73": "rt973", + "col74": "idkd3", + "col75": "v06wj", + "col76": "2k9f0", + "col77": "47jkv", + "col78": "ks82d", + "col79": "rhbru", + "col80": "28lgd", + "col81": "dhanz", + "col82": "3rno8", + "col83": "k275r", + "col84": "eqrzt", + "col85": "rr00h", + "col86": "2xi5n", + "col87": "6kkn0", + "col88": "8s4kp", + "col89": "zaopn", + "col90": "cqiyd", + "col91": "7eu7k", + "col92": "umib8", + "col93": "3yefv", + "col94": "v25dv", + "col95": "4cf07", + "col96": "req67", + "col97": "9paz0" + }, + { + "name": "Graham Marsh", + "gender": "male", + "company": "Medifax", + "col0": "s6165", + "col1": "0nmm2", + "col2": "36e91", + "col3": "fyq1z", + "col4": "47jq1", + "col5": "r1267", + "col6": "voibc", + "col7": "0sb87", + "col8": "em045", + "col9": "aa4qf", + "col10": "pb4k6", + "col11": "tx09c", + "col12": "pduri", + "col13": "jyqrw", + "col14": "4q5fi", + "col15": "vjm67", + "col16": "lulzs", + "col17": "tnhm1", + "col18": "kb0e6", + "col19": "tqkhy", + "col20": "u7y8r", + "col21": "p1oom", + "col22": "myscq", + "col23": "2bqhj", + "col24": "lp959", + "col25": "r9egn", + "col26": "6vrom", + "col27": "1cnub", + "col28": "w1ucg", + "col29": "62amt", + "col30": "u3sc7", + "col31": "9g00u", + "col32": "3rmj1", + "col33": "797tc", + "col34": "lffte", + "col35": "hyg3p", + "col36": "8zasz", + "col37": "cngvl", + "col38": "7ajyr", + "col39": "tzrrk", + "col40": "i96fn", + "col41": "6s2zt", + "col42": "gdt1d", + "col43": "diidr", + "col44": "5i253", + "col45": "ot3ef", + "col46": "0o8j7", + "col47": "zg11e", + "col48": "kn770", + "col49": "cihyb", + "col50": "jhlkc", + "col51": "pjnbt", + "col52": "12n1i", + "col53": "e4f0u", + "col54": "3z5ml", + "col55": "0zeok", + "col56": "zhzlz", + "col57": "twuii", + "col58": "ce9uf", + "col59": "5jkx3", + "col60": "5e76h", + "col61": "5v4rb", + "col62": "zy1vo", + "col63": "7cbur", + "col64": "zq8cn", + "col65": "qbwdi", + "col66": "d0o1h", + "col67": "g9nij", + "col68": "0d5ju", + "col69": "kg66c", + "col70": "3d2ov", + "col71": "7miwm", + "col72": "g6syw", + "col73": "zbovw", + "col74": "7ny1i", + "col75": "ka5tc", + "col76": "d2ys5", + "col77": "bw5nw", + "col78": "lhjtg", + "col79": "iasng", + "col80": "cwumd", + "col81": "aq1js", + "col82": "a64hp", + "col83": "k5a37", + "col84": "dgk1i", + "col85": "3970h", + "col86": "9wehc", + "col87": "e1pfo", + "col88": "0594s", + "col89": "zwbhk", + "col90": "ce86q", + "col91": "77nto", + "col92": "7svtk", + "col93": "zclb7", + "col94": "p0sdp", + "col95": "zokpj", + "col96": "g3hx3", + "col97": "9fy1b" + }, + { + "name": "Hale Boone", + "gender": "male", + "company": "Digial", + "col0": "nbbzy", + "col1": "puk1b", + "col2": "y25yc", + "col3": "lk1ss", + "col4": "qpr3r", + "col5": "0dfkx", + "col6": "ev9x9", + "col7": "je6ec", + "col8": "slcl4", + "col9": "tzuu3", + "col10": "5rcnh", + "col11": "552p9", + "col12": "nfl6x", + "col13": "p984v", + "col14": "jdrp3", + "col15": "i9izl", + "col16": "cw8x2", + "col17": "cn39n", + "col18": "8krvp", + "col19": "jdmcl", + "col20": "l8jfe", + "col21": "7onss", + "col22": "a6jlm", + "col23": "lmbjk", + "col24": "hdad5", + "col25": "mpaim", + "col26": "b4jpc", + "col27": "0jimb", + "col28": "dnf8w", + "col29": "outrp", + "col30": "3topz", + "col31": "vjmoc", + "col32": "o3vx1", + "col33": "uxtg3", + "col34": "nn2nf", + "col35": "x9oob", + "col36": "hrnia", + "col37": "cthwg", + "col38": "yokyd", + "col39": "8pc8c", + "col40": "98pya", + "col41": "ze6ru", + "col42": "0fohj", + "col43": "yod0z", + "col44": "ssqlp", + "col45": "necu3", + "col46": "dzllq", + "col47": "3zsoq", + "col48": "o44nu", + "col49": "x7609", + "col50": "0lvet", + "col51": "cvb4a", + "col52": "yxfad", + "col53": "0kk79", + "col54": "uptft", + "col55": "wdh7b", + "col56": "2cupb", + "col57": "9ka8r", + "col58": "vrm6q", + "col59": "hxvr0", + "col60": "yqfw7", + "col61": "ho607", + "col62": "32lyr", + "col63": "jwt1d", + "col64": "wuoyd", + "col65": "bpn4a", + "col66": "yywbm", + "col67": "cztvt", + "col68": "vlt2b", + "col69": "uqctm", + "col70": "0l97n", + "col71": "cgvv6", + "col72": "sujzh", + "col73": "n3rwi", + "col74": "fdsr4", + "col75": "z0m3c", + "col76": "9vovi", + "col77": "qkbtu", + "col78": "7w52m", + "col79": "kvu7w", + "col80": "jd0ez", + "col81": "0msxm", + "col82": "l6g4m", + "col83": "xiuat", + "col84": "kintd", + "col85": "mddma", + "col86": "hc0sd", + "col87": "si3eo", + "col88": "vpspv", + "col89": "zr7t3", + "col90": "f34jk", + "col91": "qlss1", + "col92": "15cvc", + "col93": "vm6q5", + "col94": "r8mev", + "col95": "rle87", + "col96": "289xi", + "col97": "1xg1l" + }, + { + "name": "Wiley Hubbard", + "gender": "male", + "company": "Zensus", + "col0": "jsa8s", + "col1": "rvgdi", + "col2": "i9i1l", + "col3": "xp5cz", + "col4": "7ohv1", + "col5": "0c4yg", + "col6": "f5ghw", + "col7": "zraiv", + "col8": "em7wx", + "col9": "1i582", + "col10": "f1at5", + "col11": "ylzsc", + "col12": "6b8tf", + "col13": "tbwjs", + "col14": "bxzra", + "col15": "eclsi", + "col16": "a1v7e", + "col17": "0h6mm", + "col18": "ofn4v", + "col19": "iojqd", + "col20": "51esv", + "col21": "11s8o", + "col22": "8scsj", + "col23": "g3hxi", + "col24": "uezqe", + "col25": "i3qm1", + "col26": "3hgmx", + "col27": "xg306", + "col28": "9al71", + "col29": "nvb27", + "col30": "0xrkf", + "col31": "dc4ia", + "col32": "eyest", + "col33": "7e55v", + "col34": "ov902", + "col35": "pcbqh", + "col36": "gpp60", + "col37": "dcyfp", + "col38": "y11hg", + "col39": "sl6ir", + "col40": "fqj3i", + "col41": "ksqh3", + "col42": "8oyq7", + "col43": "eq978", + "col44": "x61pw", + "col45": "wtrpg", + "col46": "z3alo", + "col47": "7pqnr", + "col48": "q47jx", + "col49": "9i22a", + "col50": "mn9t8", + "col51": "t3a9l", + "col52": "g5i4s", + "col53": "fx48m", + "col54": "hrbp8", + "col55": "mcxmz", + "col56": "lrwmu", + "col57": "7dtgi", + "col58": "rqeyt", + "col59": "iqb5q", + "col60": "a7saa", + "col61": "mhicp", + "col62": "tcn0s", + "col63": "wv5cm", + "col64": "gnw8w", + "col65": "0e2n4", + "col66": "gst6l", + "col67": "gr0tk", + "col68": "7wcrg", + "col69": "kk8e5", + "col70": "sqyr6", + "col71": "8jnk3", + "col72": "rpzd8", + "col73": "3biq5", + "col74": "iptc6", + "col75": "h0i1u", + "col76": "hkc35", + "col77": "9vr9z", + "col78": "vqitd", + "col79": "yfhre", + "col80": "zmx1v", + "col81": "8krku", + "col82": "saq0s", + "col83": "ncapf", + "col84": "y0c4b", + "col85": "2eto8", + "col86": "j79k2", + "col87": "8yged", + "col88": "3cb2u", + "col89": "qios8", + "col90": "vxbpf", + "col91": "5wt5e", + "col92": "u1723", + "col93": "n38np", + "col94": "grvmj", + "col95": "494eh", + "col96": "85mx4", + "col97": "8qm35" + }, + { + "name": "Blackburn Drake", + "gender": "male", + "company": "Frenex", + "col0": "dtj4d", + "col1": "jd39a", + "col2": "xsl0w", + "col3": "i566y", + "col4": "h6dtv", + "col5": "329i0", + "col6": "t4s9x", + "col7": "k2b5p", + "col8": "cjvqb", + "col9": "zgef3", + "col10": "4k3kp", + "col11": "49kjv", + "col12": "h3tly", + "col13": "addlg", + "col14": "0995p", + "col15": "0fviz", + "col16": "os8hl", + "col17": "zn4qy", + "col18": "ftvsq", + "col19": "ziy74", + "col20": "lwaa7", + "col21": "2eaqk", + "col22": "9cqd2", + "col23": "avtz7", + "col24": "lnyxn", + "col25": "wq8p4", + "col26": "1nh25", + "col27": "4aft9", + "col28": "a0zwi", + "col29": "n598y", + "col30": "12o4h", + "col31": "q02dg", + "col32": "7tgqr", + "col33": "q43y3", + "col34": "kfqp1", + "col35": "i9dr4", + "col36": "whrxb", + "col37": "jkeye", + "col38": "hbxjm", + "col39": "b0rok", + "col40": "uvash", + "col41": "uazha", + "col42": "lirf9", + "col43": "xrlyn", + "col44": "dc1up", + "col45": "extiq", + "col46": "6t4j6", + "col47": "ndp2t", + "col48": "5mt5c", + "col49": "doutr", + "col50": "d2aro", + "col51": "aca8s", + "col52": "i1eok", + "col53": "qjfvs", + "col54": "tump4", + "col55": "97g9q", + "col56": "zz1nd", + "col57": "ipbk0", + "col58": "topz0", + "col59": "gcidh", + "col60": "7xcbg", + "col61": "dbb5w", + "col62": "3vaqy", + "col63": "av85g", + "col64": "jjxgu", + "col65": "txbbk", + "col66": "qyto5", + "col67": "mxo4d", + "col68": "981m1", + "col69": "m2xwr", + "col70": "3sifr", + "col71": "202z8", + "col72": "x9lfu", + "col73": "p5gar", + "col74": "0dw7h", + "col75": "5uhw8", + "col76": "wboni", + "col77": "c3xn3", + "col78": "rks8p", + "col79": "fv0u9", + "col80": "njb84", + "col81": "8yrk9", + "col82": "soil3", + "col83": "27h3i", + "col84": "bs4pe", + "col85": "pa5lo", + "col86": "wg8l9", + "col87": "r7k7d", + "col88": "krwd4", + "col89": "upgz4", + "col90": "6cjq5", + "col91": "p5tpi", + "col92": "no5ed", + "col93": "so8b4", + "col94": "n71sn", + "col95": "x448u", + "col96": "a2ye4", + "col97": "creao" + }, + { + "name": "Franco Hunter", + "gender": "male", + "company": "Rockabye", + "col0": "rlql4", + "col1": "6edlh", + "col2": "e9q19", + "col3": "qj9eu", + "col4": "uj9x5", + "col5": "5p03h", + "col6": "dv6gi", + "col7": "dlp59", + "col8": "5vqo3", + "col9": "hvgfg", + "col10": "je813", + "col11": "5z77d", + "col12": "h3gzi", + "col13": "hp8cd", + "col14": "g40vi", + "col15": "fx0ya", + "col16": "2oxcs", + "col17": "ld3tq", + "col18": "k8oef", + "col19": "2icxj", + "col20": "to4q8", + "col21": "emmvk", + "col22": "2zqem", + "col23": "dn1d1", + "col24": "tvrkp", + "col25": "49nma", + "col26": "ia3xw", + "col27": "tc99d", + "col28": "8fhht", + "col29": "7z7mc", + "col30": "crciu", + "col31": "fc804", + "col32": "3jxqo", + "col33": "tw2eq", + "col34": "9nsp8", + "col35": "62n5i", + "col36": "wxpce", + "col37": "j2gwc", + "col38": "iselo", + "col39": "zbk02", + "col40": "iiv2y", + "col41": "fntgm", + "col42": "3aynz", + "col43": "be77x", + "col44": "pzc9g", + "col45": "9c7o2", + "col46": "vxlq3", + "col47": "p92e1", + "col48": "axyky", + "col49": "mmxgz", + "col50": "0cehk", + "col51": "5t6au", + "col52": "9fhz7", + "col53": "i4kre", + "col54": "s8hp4", + "col55": "l5x1w", + "col56": "r7ysj", + "col57": "z047s", + "col58": "p59we", + "col59": "q243n", + "col60": "ze1fc", + "col61": "zc07e", + "col62": "h2plv", + "col63": "cula0", + "col64": "znkn8", + "col65": "mcjgb", + "col66": "60dqx", + "col67": "fphw0", + "col68": "u1b1z", + "col69": "oybnc", + "col70": "g1h5t", + "col71": "40xhk", + "col72": "9xdzf", + "col73": "ukutj", + "col74": "s01xw", + "col75": "1m34s", + "col76": "09e8n", + "col77": "3shkm", + "col78": "terfx", + "col79": "bn5e6", + "col80": "kv74x", + "col81": "uqc0w", + "col82": "l1tbe", + "col83": "i1nzu", + "col84": "azvoh", + "col85": "er2q3", + "col86": "dcosm", + "col87": "0yd5y", + "col88": "k5nak", + "col89": "rhqfz", + "col90": "mtea0", + "col91": "w7tti", + "col92": "bw5mo", + "col93": "e9xs5", + "col94": "5dxkm", + "col95": "48rbr", + "col96": "btysa", + "col97": "qqaju" + }, + { + "name": "Barnett Case", + "gender": "male", + "company": "Norali", + "col0": "j6r1k", + "col1": "wpzsy", + "col2": "egz7m", + "col3": "s4nea", + "col4": "qvm0e", + "col5": "gby3p", + "col6": "lm5sm", + "col7": "uuv5z", + "col8": "xg5ht", + "col9": "ikeub", + "col10": "dlswq", + "col11": "duonx", + "col12": "4bizk", + "col13": "khcml", + "col14": "mbu7a", + "col15": "ld9ao", + "col16": "31b0k", + "col17": "t1jch", + "col18": "uqz1q", + "col19": "n1l8a", + "col20": "hqev0", + "col21": "s3s7g", + "col22": "alna3", + "col23": "i1p4v", + "col24": "y1kux", + "col25": "aefqu", + "col26": "wz48q", + "col27": "phu3e", + "col28": "6gnws", + "col29": "53v6n", + "col30": "zvlxk", + "col31": "tzmvq", + "col32": "stwxi", + "col33": "d7vws", + "col34": "w5vik", + "col35": "k42ha", + "col36": "mo7eb", + "col37": "2bune", + "col38": "1g45y", + "col39": "icoea", + "col40": "j0khb", + "col41": "x58gu", + "col42": "q08pp", + "col43": "2h6vn", + "col44": "kxxkz", + "col45": "papus", + "col46": "d03hb", + "col47": "pfmvc", + "col48": "ka4kh", + "col49": "ytvb0", + "col50": "gsv2q", + "col51": "7x2f4", + "col52": "ofwsz", + "col53": "x7k2c", + "col54": "dxbkb", + "col55": "59lz0", + "col56": "wvo0d", + "col57": "syr5y", + "col58": "k8bxv", + "col59": "j0bwg", + "col60": "g75jr", + "col61": "d7opi", + "col62": "mul9u", + "col63": "a3kpb", + "col64": "233s6", + "col65": "57ye0", + "col66": "yhnva", + "col67": "iw82n", + "col68": "wvy1p", + "col69": "8cjvl", + "col70": "rv78v", + "col71": "7n2q0", + "col72": "thnj3", + "col73": "c932w", + "col74": "snjj1", + "col75": "noahw", + "col76": "ehu47", + "col77": "k7ij0", + "col78": "5bec1", + "col79": "ekeyr", + "col80": "klu5q", + "col81": "s7efl", + "col82": "mbxtd", + "col83": "bqvtw", + "col84": "2zqgl", + "col85": "hutxe", + "col86": "nw5ru", + "col87": "swn0j", + "col88": "7rsms", + "col89": "ob32e", + "col90": "nl0sz", + "col91": "qhh8a", + "col92": "c6e3j", + "col93": "83wn3", + "col94": "j8lh1", + "col95": "1kuzt", + "col96": "pzpkm", + "col97": "9sgrj" + }, + { + "name": "Alexander Foley", + "gender": "male", + "company": "Geekosis", + "col0": "itd2u", + "col1": "x4iyf", + "col2": "m32us", + "col3": "16w4q", + "col4": "b976h", + "col5": "de52b", + "col6": "mrnjp", + "col7": "bhb20", + "col8": "ptxnk", + "col9": "8gm7k", + "col10": "y4n3a", + "col11": "iy075", + "col12": "g3m5v", + "col13": "vidzi", + "col14": "m7rg2", + "col15": "yncuf", + "col16": "gwwam", + "col17": "3jt7s", + "col18": "h0d4r", + "col19": "hl04m", + "col20": "uje3v", + "col21": "hdwxo", + "col22": "tx8xg", + "col23": "x47p9", + "col24": "q58mf", + "col25": "tivqc", + "col26": "1s9e9", + "col27": "n0ota", + "col28": "ml228", + "col29": "8pvcg", + "col30": "yx6z5", + "col31": "zia90", + "col32": "uvrji", + "col33": "dhkz5", + "col34": "j6s2a", + "col35": "zot4b", + "col36": "vxvxy", + "col37": "0njyj", + "col38": "f4wcp", + "col39": "1ru14", + "col40": "0rjax", + "col41": "ibz4q", + "col42": "sdi2k", + "col43": "esba0", + "col44": "v1kix", + "col45": "p7s9v", + "col46": "drxjp", + "col47": "6a9cw", + "col48": "zobf0", + "col49": "5y70r", + "col50": "l8sma", + "col51": "d0kvm", + "col52": "o45ou", + "col53": "erse0", + "col54": "qrgmf", + "col55": "kaxn7", + "col56": "rai08", + "col57": "yhlyb", + "col58": "uxngj", + "col59": "4tixo", + "col60": "nwsgp", + "col61": "9265e", + "col62": "na4tw", + "col63": "m2i51", + "col64": "lbevy", + "col65": "ahb3f", + "col66": "1cyel", + "col67": "h17hu", + "col68": "glant", + "col69": "kkisu", + "col70": "gsllu", + "col71": "mh07j", + "col72": "eoded", + "col73": "jfi6u", + "col74": "14yr4", + "col75": "ytqcp", + "col76": "d77eh", + "col77": "e1odk", + "col78": "ji1oh", + "col79": "d8gvy", + "col80": "wnk8x", + "col81": "r9u1r", + "col82": "majsq", + "col83": "xvcv2", + "col84": "smmff", + "col85": "hjcox", + "col86": "l4has", + "col87": "6gysw", + "col88": "veaqb", + "col89": "c62sy", + "col90": "svj19", + "col91": "sfjtw", + "col92": "f4uup", + "col93": "2uylv", + "col94": "u5qg2", + "col95": "rroiq", + "col96": "3kdsu", + "col97": "i40ar" + }, + { + "name": "Lynette Stein", + "gender": "female", + "company": "Macronaut", + "col0": "q0m8n", + "col1": "y3emt", + "col2": "g0hdy", + "col3": "dpkj6", + "col4": "mbymg", + "col5": "k93cg", + "col6": "2lak6", + "col7": "e5h98", + "col8": "juiw4", + "col9": "sldm0", + "col10": "z52kt", + "col11": "1izhu", + "col12": "zfl0c", + "col13": "b1956", + "col14": "9riqs", + "col15": "nf992", + "col16": "4x8l9", + "col17": "v0d8m", + "col18": "w7hey", + "col19": "dhzs0", + "col20": "0xl1t", + "col21": "eouvn", + "col22": "ztkda", + "col23": "k75a6", + "col24": "0jr83", + "col25": "ilcrr", + "col26": "n9bzm", + "col27": "u4hpl", + "col28": "26fpi", + "col29": "k6rkf", + "col30": "klpwx", + "col31": "nzbt3", + "col32": "kptet", + "col33": "eu2mo", + "col34": "unkyi", + "col35": "4ohan", + "col36": "1sob4", + "col37": "iespm", + "col38": "ko451", + "col39": "y4a3o", + "col40": "gng16", + "col41": "5y5ke", + "col42": "vv55m", + "col43": "r395t", + "col44": "uwsur", + "col45": "j27ns", + "col46": "8a5w5", + "col47": "7hpb8", + "col48": "bcpg2", + "col49": "crd7o", + "col50": "qbfvf", + "col51": "7o89d", + "col52": "bsfm7", + "col53": "asbrl", + "col54": "7628x", + "col55": "geziw", + "col56": "yv3th", + "col57": "03gdq", + "col58": "d7tw7", + "col59": "blsz6", + "col60": "sp46j", + "col61": "8jn7o", + "col62": "z8ilo", + "col63": "1xzr6", + "col64": "1ytir", + "col65": "9vc83", + "col66": "6mu12", + "col67": "810ui", + "col68": "n6cl7", + "col69": "q04rs", + "col70": "o0m38", + "col71": "5q5h4", + "col72": "871d8", + "col73": "9cnq4", + "col74": "8cl32", + "col75": "mxzo0", + "col76": "jrl9g", + "col77": "3wkxw", + "col78": "on5nx", + "col79": "cxh3k", + "col80": "epr3s", + "col81": "wwbqs", + "col82": "0bxbo", + "col83": "6cpcb", + "col84": "bktxf", + "col85": "agsxw", + "col86": "zp9xt", + "col87": "pxybc", + "col88": "tbx20", + "col89": "hezv1", + "col90": "gk8a2", + "col91": "a8wi2", + "col92": "pk2kz", + "col93": "aupwz", + "col94": "6kyy5", + "col95": "5s4q8", + "col96": "4498f", + "col97": "3wi2m" + }, + { + "name": "Anthony Joyner", + "gender": "male", + "company": "Senmei", + "col0": "8lnni", + "col1": "ao8gy", + "col2": "t15vx", + "col3": "w78ln", + "col4": "d1k9e", + "col5": "e5aut", + "col6": "1wwkr", + "col7": "j5by0", + "col8": "9oa36", + "col9": "c22ah", + "col10": "tnbkp", + "col11": "wq4gr", + "col12": "797oa", + "col13": "4eqoz", + "col14": "9oqwh", + "col15": "hslv8", + "col16": "4zsll", + "col17": "xbet6", + "col18": "0whr3", + "col19": "lk5p6", + "col20": "i8rgd", + "col21": "ukxf3", + "col22": "nkec3", + "col23": "fz05m", + "col24": "nzlch", + "col25": "3en8a", + "col26": "72vqz", + "col27": "o6jqn", + "col28": "nqwex", + "col29": "yovr9", + "col30": "asd5p", + "col31": "q3ok7", + "col32": "tuokr", + "col33": "0oslp", + "col34": "ghor8", + "col35": "47tbg", + "col36": "m29y0", + "col37": "2ojoe", + "col38": "evbz3", + "col39": "94q0f", + "col40": "72lb9", + "col41": "5sq2m", + "col42": "wfvns", + "col43": "dkjxq", + "col44": "d9rpy", + "col45": "13a1w", + "col46": "vcxlp", + "col47": "em8ng", + "col48": "l7voo", + "col49": "vqkkc", + "col50": "43mmj", + "col51": "6ellt", + "col52": "48rud", + "col53": "yp8ra", + "col54": "109s3", + "col55": "cpbw6", + "col56": "ro12f", + "col57": "8pp3w", + "col58": "czclu", + "col59": "mu11h", + "col60": "ue7zq", + "col61": "gzgs4", + "col62": "iscvh", + "col63": "h68je", + "col64": "2gukc", + "col65": "lya7f", + "col66": "e1exo", + "col67": "m1ahj", + "col68": "a1na4", + "col69": "rt445", + "col70": "d7u94", + "col71": "u8jxt", + "col72": "2l82i", + "col73": "zdade", + "col74": "1gyte", + "col75": "jnnl1", + "col76": "6dvnj", + "col77": "zp37d", + "col78": "bhf8g", + "col79": "hnu09", + "col80": "5y5kf", + "col81": "w5b3a", + "col82": "senu7", + "col83": "beods", + "col84": "oe9bg", + "col85": "gic8s", + "col86": "d1rgv", + "col87": "4npm6", + "col88": "tw1eq", + "col89": "uwudi", + "col90": "dydef", + "col91": "t8rtd", + "col92": "w76pj", + "col93": "li0lp", + "col94": "5c35l", + "col95": "3qjiu", + "col96": "6l5gx", + "col97": "piiof" + }, + { + "name": "Garrett Brennan", + "gender": "male", + "company": "Bluegrain", + "col0": "dvl2e", + "col1": "mbela", + "col2": "jptaz", + "col3": "qawpy", + "col4": "y4hj9", + "col5": "s5wh2", + "col6": "gq85q", + "col7": "unlsh", + "col8": "nn4q9", + "col9": "ma80e", + "col10": "youa2", + "col11": "iry49", + "col12": "78sxr", + "col13": "5q8ax", + "col14": "xmqg1", + "col15": "b4af8", + "col16": "9kkck", + "col17": "anvoy", + "col18": "dkghh", + "col19": "5k50m", + "col20": "yrxm4", + "col21": "v4azl", + "col22": "4gip0", + "col23": "m8nf4", + "col24": "ncgcu", + "col25": "c5dzf", + "col26": "wsxd7", + "col27": "ipfa1", + "col28": "fdyxm", + "col29": "ykbjj", + "col30": "1aasy", + "col31": "0nxon", + "col32": "6ecfy", + "col33": "z8abu", + "col34": "ghw5i", + "col35": "m5c4r", + "col36": "8x8tv", + "col37": "wc4yn", + "col38": "1vcqt", + "col39": "ap3zp", + "col40": "fv9b1", + "col41": "2t85p", + "col42": "ikrrq", + "col43": "sbqvf", + "col44": "o0h1o", + "col45": "t1zdd", + "col46": "7xqbi", + "col47": "rkkp3", + "col48": "wczdv", + "col49": "0127e", + "col50": "thprv", + "col51": "wpsy3", + "col52": "tzi8c", + "col53": "laei8", + "col54": "kowbw", + "col55": "6xpvn", + "col56": "ynxg8", + "col57": "ps7pu", + "col58": "vly8b", + "col59": "t6kp0", + "col60": "vewzz", + "col61": "t4f5q", + "col62": "i4e0o", + "col63": "hwa0i", + "col64": "zu9qy", + "col65": "j2hnc", + "col66": "dpnxg", + "col67": "ca1oc", + "col68": "piiyz", + "col69": "s0emv", + "col70": "eam87", + "col71": "jmtbf", + "col72": "kdmyp", + "col73": "bimh4", + "col74": "q8fy9", + "col75": "ip2up", + "col76": "eioga", + "col77": "a1kbq", + "col78": "oxuuq", + "col79": "gjkim", + "col80": "8h9wo", + "col81": "zeiqk", + "col82": "ye3g2", + "col83": "uki9j", + "col84": "fpnhg", + "col85": "7jlq9", + "col86": "pzdh6", + "col87": "89jsa", + "col88": "8u8nw", + "col89": "272jr", + "col90": "8y55q", + "col91": "22m3m", + "col92": "sjmci", + "col93": "ieffb", + "col94": "d9erm", + "col95": "wqn0h", + "col96": "1mme5", + "col97": "znklj" + }, + { + "name": "Betsy Horton", + "gender": "female", + "company": "Zilla", + "col0": "ya03b", + "col1": "37b2u", + "col2": "j2k3z", + "col3": "tpg7i", + "col4": "08nqx", + "col5": "b4xpu", + "col6": "2hfpp", + "col7": "nczak", + "col8": "kmypx", + "col9": "vtnsq", + "col10": "ltbk2", + "col11": "cqh6c", + "col12": "20f2l", + "col13": "gd2zj", + "col14": "0sgmh", + "col15": "a8t24", + "col16": "9hbru", + "col17": "hqeur", + "col18": "brydu", + "col19": "m6fx4", + "col20": "74p0a", + "col21": "azrib", + "col22": "rms75", + "col23": "5fhd8", + "col24": "rdm0z", + "col25": "wahi2", + "col26": "pcd12", + "col27": "2uyo5", + "col28": "71jux", + "col29": "ek9z6", + "col30": "kbdjx", + "col31": "np4ic", + "col32": "1r0xc", + "col33": "l3k19", + "col34": "8c5xn", + "col35": "8ug2p", + "col36": "x3pgc", + "col37": "r7pgz", + "col38": "y9xik", + "col39": "oavf0", + "col40": "l158l", + "col41": "1hfoe", + "col42": "fgtpz", + "col43": "gr200", + "col44": "wmbu8", + "col45": "pg3u6", + "col46": "zlhql", + "col47": "fwn6y", + "col48": "pvoic", + "col49": "km1nk", + "col50": "iptn1", + "col51": "ydtzc", + "col52": "1sbxr", + "col53": "dgwqb", + "col54": "tsmsi", + "col55": "mceib", + "col56": "tkep3", + "col57": "52tkg", + "col58": "4aa01", + "col59": "2ojje", + "col60": "6jb1g", + "col61": "49hqs", + "col62": "7maz6", + "col63": "j1kz0", + "col64": "h4n54", + "col65": "42onl", + "col66": "oiw0e", + "col67": "rfe49", + "col68": "p2wzi", + "col69": "ozrwe", + "col70": "9ubwv", + "col71": "v3iey", + "col72": "x0o9l", + "col73": "h6nc9", + "col74": "tp64l", + "col75": "kr3l1", + "col76": "sejcb", + "col77": "ezh23", + "col78": "07m94", + "col79": "44o7t", + "col80": "76elm", + "col81": "v5w7g", + "col82": "pcayv", + "col83": "5x85e", + "col84": "uim0d", + "col85": "5942r", + "col86": "kzxfv", + "col87": "kyvp1", + "col88": "dad20", + "col89": "ypubd", + "col90": "gnqgy", + "col91": "f6vde", + "col92": "cwp4p", + "col93": "gm1r2", + "col94": "2cbgo", + "col95": "emiht", + "col96": "c600k", + "col97": "f13qt" + }, + { + "name": "Patton Small", + "gender": "male", + "company": "Genmex", + "col0": "97fkv", + "col1": "9993j", + "col2": "xlvnm", + "col3": "7gq34", + "col4": "pjsfp", + "col5": "djuk2", + "col6": "4z3zh", + "col7": "9u22b", + "col8": "81m7s", + "col9": "to5bl", + "col10": "l6v5i", + "col11": "iuf7p", + "col12": "37dsi", + "col13": "lfdjy", + "col14": "9atu7", + "col15": "ryb7n", + "col16": "safxm", + "col17": "h5qzo", + "col18": "nqpyt", + "col19": "ee5ek", + "col20": "gtpon", + "col21": "lwy3c", + "col22": "r0cl5", + "col23": "p7zyu", + "col24": "u4cio", + "col25": "rwz1j", + "col26": "h3n4j", + "col27": "ejw90", + "col28": "sbv0e", + "col29": "yki78", + "col30": "urerg", + "col31": "gv7rf", + "col32": "ar8na", + "col33": "rhtac", + "col34": "lu49b", + "col35": "m1xlk", + "col36": "mu9mx", + "col37": "lx7fk", + "col38": "k72ff", + "col39": "2k6mh", + "col40": "s0zeb", + "col41": "v2703", + "col42": "q43rb", + "col43": "k9am2", + "col44": "gyp3a", + "col45": "9l3gt", + "col46": "hw5sf", + "col47": "vtl3u", + "col48": "jenb4", + "col49": "tr1zj", + "col50": "xxk6d", + "col51": "qdo3l", + "col52": "oayg6", + "col53": "5ewok", + "col54": "kuhfk", + "col55": "mmak0", + "col56": "ig38e", + "col57": "pwk3i", + "col58": "50jh9", + "col59": "5yd2j", + "col60": "dguzc", + "col61": "pxtif", + "col62": "3x9w0", + "col63": "cnwq6", + "col64": "vnls8", + "col65": "s52te", + "col66": "307h7", + "col67": "ldarq", + "col68": "cpe86", + "col69": "ewsyi", + "col70": "emzza", + "col71": "72ze6", + "col72": "ulg3b", + "col73": "5zbks", + "col74": "vweb8", + "col75": "ghnap", + "col76": "18n4k", + "col77": "nzmgx", + "col78": "5yibh", + "col79": "m1gxp", + "col80": "2ofby", + "col81": "fqcuo", + "col82": "v8jak", + "col83": "ppsa8", + "col84": "j5j0v", + "col85": "l8hqu", + "col86": "v2pay", + "col87": "c97m4", + "col88": "ppvla", + "col89": "xxpzg", + "col90": "wopx9", + "col91": "iabze", + "col92": "b7eq3", + "col93": "maqts", + "col94": "qsa2h", + "col95": "1y2qn", + "col96": "lbu3a", + "col97": "s4rhz" + }, + { + "name": "Lakisha Huber", + "gender": "female", + "company": "Insource", + "col0": "h0ic1", + "col1": "rpvet", + "col2": "jyp55", + "col3": "stykv", + "col4": "x0c4j", + "col5": "autm7", + "col6": "mula3", + "col7": "zeixe", + "col8": "uvd6v", + "col9": "8mpm8", + "col10": "562mf", + "col11": "l8wzb", + "col12": "oh65k", + "col13": "0cs8f", + "col14": "okfaw", + "col15": "etgk0", + "col16": "060f0", + "col17": "ox445", + "col18": "cfn8i", + "col19": "a8nfp", + "col20": "9fzke", + "col21": "0qj1c", + "col22": "p3g33", + "col23": "n5i62", + "col24": "2o5x2", + "col25": "6yu2m", + "col26": "evpcc", + "col27": "3h67h", + "col28": "0vyd4", + "col29": "6rqtt", + "col30": "tap2j", + "col31": "objuw", + "col32": "odkru", + "col33": "0bjd6", + "col34": "4627f", + "col35": "y8ntb", + "col36": "pz5nb", + "col37": "0qx3r", + "col38": "egj0p", + "col39": "jelo5", + "col40": "n9o1m", + "col41": "01s6q", + "col42": "88i6f", + "col43": "c4e56", + "col44": "zq6vv", + "col45": "52uvc", + "col46": "q2uaz", + "col47": "cprlj", + "col48": "tg6ic", + "col49": "btqrj", + "col50": "isp6e", + "col51": "matju", + "col52": "swi63", + "col53": "wim3u", + "col54": "17j6a", + "col55": "6clbr", + "col56": "xmug6", + "col57": "4jcui", + "col58": "sd55q", + "col59": "08521", + "col60": "wrk42", + "col61": "k736y", + "col62": "uod9z", + "col63": "u47ph", + "col64": "3khkq", + "col65": "c0c53", + "col66": "7revi", + "col67": "dwg2p", + "col68": "1291z", + "col69": "dkq91", + "col70": "jhfzn", + "col71": "uydjc", + "col72": "4i0pk", + "col73": "y2o7x", + "col74": "sqdgh", + "col75": "gqy15", + "col76": "r5g5g", + "col77": "weloz", + "col78": "pzcil", + "col79": "xmq5y", + "col80": "qszg7", + "col81": "euxi1", + "col82": "8io66", + "col83": "wmig9", + "col84": "d0pi9", + "col85": "zl92t", + "col86": "kxl6i", + "col87": "ryrr0", + "col88": "aefi7", + "col89": "b7f1y", + "col90": "v0773", + "col91": "x6mtk", + "col92": "ykhhr", + "col93": "tlu65", + "col94": "15r8e", + "col95": "m829y", + "col96": "vvriw", + "col97": "ismmi" + }, + { + "name": "Lindsay Avery", + "gender": "female", + "company": "Unq", + "col0": "0acl0", + "col1": "reqk7", + "col2": "tijn2", + "col3": "rf85g", + "col4": "o222i", + "col5": "bcd0n", + "col6": "t8w0b", + "col7": "c61bs", + "col8": "usaa3", + "col9": "bvomx", + "col10": "rhdr5", + "col11": "7a7hv", + "col12": "ie844", + "col13": "41u81", + "col14": "1t0x0", + "col15": "8vjxp", + "col16": "8zso0", + "col17": "ey420", + "col18": "w8m8g", + "col19": "p8swr", + "col20": "m1128", + "col21": "j5je5", + "col22": "q3e0w", + "col23": "25z07", + "col24": "6picr", + "col25": "gf0aw", + "col26": "gavfo", + "col27": "f0v8e", + "col28": "hzdld", + "col29": "0xfz4", + "col30": "q2lpb", + "col31": "bnk0e", + "col32": "n4hy6", + "col33": "jh24e", + "col34": "mwfiu", + "col35": "lw62c", + "col36": "kotfk", + "col37": "8ub4l", + "col38": "x9inj", + "col39": "qa72n", + "col40": "flnsg", + "col41": "tvfc6", + "col42": "8ac38", + "col43": "xv36p", + "col44": "tu70g", + "col45": "yw6y9", + "col46": "5vdc2", + "col47": "26th9", + "col48": "933ue", + "col49": "vwfiy", + "col50": "3xvgj", + "col51": "ewpsl", + "col52": "fkja9", + "col53": "231p0", + "col54": "53v1f", + "col55": "h396p", + "col56": "cj8a8", + "col57": "1f64h", + "col58": "ptoo5", + "col59": "y7z3l", + "col60": "jr2x9", + "col61": "83v9f", + "col62": "19wne", + "col63": "slzz6", + "col64": "3ppwe", + "col65": "7khmm", + "col66": "qenbk", + "col67": "ywtme", + "col68": "c5o0r", + "col69": "lnexx", + "col70": "6jei2", + "col71": "dpawd", + "col72": "4q86d", + "col73": "0gij9", + "col74": "pqsz4", + "col75": "025yf", + "col76": "w6v3k", + "col77": "rqox3", + "col78": "tp9d4", + "col79": "4e7fh", + "col80": "uf3yj", + "col81": "i4eqk", + "col82": "xbc40", + "col83": "nv51o", + "col84": "ka0mv", + "col85": "f6mkr", + "col86": "j15d9", + "col87": "zcpjk", + "col88": "sxdss", + "col89": "9tck1", + "col90": "taj4d", + "col91": "mr6d8", + "col92": "3k0t5", + "col93": "v3ave", + "col94": "5ecc8", + "col95": "ypbkn", + "col96": "x30w4", + "col97": "w786b" + }, + { + "name": "Ayers Hood", + "gender": "male", + "company": "Accuprint", + "col0": "wlxuo", + "col1": "9vbth", + "col2": "co1z8", + "col3": "poudl", + "col4": "2ofk0", + "col5": "j9d3i", + "col6": "qijqx", + "col7": "ahv7g", + "col8": "oc37l", + "col9": "umear", + "col10": "7148w", + "col11": "rihpx", + "col12": "9lu4r", + "col13": "9n5xm", + "col14": "aqnte", + "col15": "me0br", + "col16": "6sl1j", + "col17": "1f4yp", + "col18": "vr3bl", + "col19": "mm75l", + "col20": "pqfxf", + "col21": "6ffx4", + "col22": "arhrt", + "col23": "smzww", + "col24": "tc5kx", + "col25": "4nopr", + "col26": "tev0a", + "col27": "k6pdg", + "col28": "ljauy", + "col29": "izc61", + "col30": "v86un", + "col31": "py1ql", + "col32": "bafo0", + "col33": "pm0f5", + "col34": "zdrpg", + "col35": "sn6c0", + "col36": "ygrpk", + "col37": "t6nah", + "col38": "68we9", + "col39": "itsb3", + "col40": "4cdhk", + "col41": "8xy86", + "col42": "b5uum", + "col43": "nqky0", + "col44": "pd5fz", + "col45": "gvxd7", + "col46": "s67ak", + "col47": "siwtw", + "col48": "ycvx0", + "col49": "pugma", + "col50": "qbrv2", + "col51": "ojnnq", + "col52": "lknqb", + "col53": "67lew", + "col54": "78lc3", + "col55": "ccvzb", + "col56": "qmelp", + "col57": "b0arx", + "col58": "61qxw", + "col59": "3ku4n", + "col60": "di6i3", + "col61": "69t9g", + "col62": "y5ezu", + "col63": "itke9", + "col64": "4ov9k", + "col65": "97nlj", + "col66": "bap2d", + "col67": "rierb", + "col68": "u3kl8", + "col69": "0gnv5", + "col70": "g0y3n", + "col71": "t8isq", + "col72": "59nl5", + "col73": "l83de", + "col74": "3xw90", + "col75": "3j9q5", + "col76": "rv9e0", + "col77": "svu9r", + "col78": "jarhk", + "col79": "t05xc", + "col80": "o6ckn", + "col81": "9vp73", + "col82": "l172u", + "col83": "1m2yh", + "col84": "5ugru", + "col85": "1oob7", + "col86": "9n17b", + "col87": "2qldg", + "col88": "2xbgk", + "col89": "wbd14", + "col90": "s6kpd", + "col91": "517yv", + "col92": "lcxc5", + "col93": "rndc7", + "col94": "6e6r2", + "col95": "qxaua", + "col96": "w3gei", + "col97": "39joe" + }, + { + "name": "Torres Durham", + "gender": "male", + "company": "Uplinx", + "col0": "e4ses", + "col1": "xqkq4", + "col2": "6qcnv", + "col3": "29610", + "col4": "xddnt", + "col5": "yev9m", + "col6": "kgbsu", + "col7": "q6dbe", + "col8": "m52ts", + "col9": "01d5g", + "col10": "4qggk", + "col11": "rja0e", + "col12": "6y0j1", + "col13": "4mk73", + "col14": "dlucz", + "col15": "bluph", + "col16": "cvq5b", + "col17": "u9xyp", + "col18": "nn2m3", + "col19": "74dou", + "col20": "i94bg", + "col21": "tqrc9", + "col22": "3l9v6", + "col23": "jx6yo", + "col24": "xocf8", + "col25": "04ksl", + "col26": "40jac", + "col27": "0nrre", + "col28": "3vij0", + "col29": "1cuh8", + "col30": "nl7ep", + "col31": "eyznm", + "col32": "ndqcf", + "col33": "ph439", + "col34": "9ykte", + "col35": "0uump", + "col36": "2e5uh", + "col37": "hrroc", + "col38": "nf29b", + "col39": "9repl", + "col40": "sm0yc", + "col41": "q5lp1", + "col42": "kjtn2", + "col43": "t0e8c", + "col44": "diukw", + "col45": "n44gx", + "col46": "quel5", + "col47": "drq91", + "col48": "ed2gp", + "col49": "ug096", + "col50": "9m7ab", + "col51": "8mn5e", + "col52": "rpqmy", + "col53": "jd30c", + "col54": "f32mz", + "col55": "rx7ie", + "col56": "rvbln", + "col57": "wb04w", + "col58": "lwwqd", + "col59": "r6bvk", + "col60": "rksk0", + "col61": "7ilka", + "col62": "iuy2f", + "col63": "cisbc", + "col64": "m6hmc", + "col65": "6gzk2", + "col66": "aqyj4", + "col67": "pk6v6", + "col68": "p6hpd", + "col69": "hu4ce", + "col70": "g6cc5", + "col71": "hf1wv", + "col72": "oknw0", + "col73": "gz12j", + "col74": "xa1w1", + "col75": "86u1c", + "col76": "w6qr9", + "col77": "0rhnr", + "col78": "485ub", + "col79": "se5iv", + "col80": "x5ijy", + "col81": "u60u1", + "col82": "u8eqr", + "col83": "1ivxi", + "col84": "zsuzk", + "col85": "49ihd", + "col86": "are00", + "col87": "nvvsl", + "col88": "4fs0v", + "col89": "ldkuw", + "col90": "m6f7l", + "col91": "tvu8k", + "col92": "8aef0", + "col93": "20mrw", + "col94": "rkq3m", + "col95": "sz0tm", + "col96": "1v49b", + "col97": "cd48h" + }, + { + "name": "Vincent Hernandez", + "gender": "male", + "company": "Talendula", + "col0": "93ti6", + "col1": "sked5", + "col2": "8auyg", + "col3": "txij7", + "col4": "nqeyg", + "col5": "ttp2o", + "col6": "25a0w", + "col7": "wcqii", + "col8": "i4psd", + "col9": "kccu4", + "col10": "1mrkc", + "col11": "4i0bi", + "col12": "ux37q", + "col13": "bst8k", + "col14": "kge7t", + "col15": "j02f5", + "col16": "gcshd", + "col17": "6hqg5", + "col18": "zkofk", + "col19": "g0sng", + "col20": "ppfvp", + "col21": "gqs4d", + "col22": "ah7cj", + "col23": "9cj4x", + "col24": "krcqg", + "col25": "e8lu6", + "col26": "lug4g", + "col27": "ljkk6", + "col28": "dgnku", + "col29": "fbnvd", + "col30": "pr4yu", + "col31": "qp0mo", + "col32": "imblj", + "col33": "ie6cs", + "col34": "pn92e", + "col35": "vrumr", + "col36": "zqv5s", + "col37": "mtiw7", + "col38": "4b6f6", + "col39": "x7lcp", + "col40": "7fymy", + "col41": "jxjn2", + "col42": "eheov", + "col43": "3fhrf", + "col44": "e33u8", + "col45": "11wux", + "col46": "jm0cz", + "col47": "ymuqr", + "col48": "oruxd", + "col49": "qxk62", + "col50": "npjll", + "col51": "ydyq9", + "col52": "bh95d", + "col53": "8zswc", + "col54": "et0ms", + "col55": "lz6x2", + "col56": "w5mkj", + "col57": "dh9y6", + "col58": "cz9l0", + "col59": "4yd1b", + "col60": "o8snu", + "col61": "2wg7h", + "col62": "b37px", + "col63": "wgk46", + "col64": "ttf02", + "col65": "3173p", + "col66": "4ntxa", + "col67": "udnt9", + "col68": "cz6a5", + "col69": "30b15", + "col70": "17sl4", + "col71": "i3ppf", + "col72": "lb17t", + "col73": "tn26u", + "col74": "rveod", + "col75": "fzobm", + "col76": "gi908", + "col77": "41ow9", + "col78": "lg64g", + "col79": "rl5jc", + "col80": "y78rv", + "col81": "m9lnt", + "col82": "4fecm", + "col83": "7p6ot", + "col84": "62sj4", + "col85": "ts91t", + "col86": "zj3em", + "col87": "o1srp", + "col88": "r449j", + "col89": "mgps8", + "col90": "iipuv", + "col91": "w8xbk", + "col92": "edb1x", + "col93": "jktq3", + "col94": "c35nz", + "col95": "xkm1i", + "col96": "vern3", + "col97": "3lyuo" + }, + { + "name": "Baird Ryan", + "gender": "male", + "company": "Aquasseur", + "col0": "1nzjz", + "col1": "k7h63", + "col2": "wpxx0", + "col3": "oslbz", + "col4": "wrtq9", + "col5": "a5r8i", + "col6": "317bu", + "col7": "wo5fi", + "col8": "e3u97", + "col9": "fkx8y", + "col10": "f334b", + "col11": "5x9rj", + "col12": "taqui", + "col13": "kpfbd", + "col14": "n61yb", + "col15": "cxp0l", + "col16": "465zv", + "col17": "2j4lc", + "col18": "83zfa", + "col19": "85iq7", + "col20": "gkifo", + "col21": "wnvd5", + "col22": "6aq3p", + "col23": "uppyc", + "col24": "tthzb", + "col25": "ta4wk", + "col26": "rnkil", + "col27": "3hlzh", + "col28": "6rovd", + "col29": "cgghm", + "col30": "2aezl", + "col31": "lum01", + "col32": "0jt47", + "col33": "9sg8z", + "col34": "97po2", + "col35": "uaa9g", + "col36": "380d0", + "col37": "p7723", + "col38": "7y0sb", + "col39": "x281l", + "col40": "o92zo", + "col41": "i65he", + "col42": "mfptg", + "col43": "i55dl", + "col44": "txo9a", + "col45": "76cx9", + "col46": "o63v9", + "col47": "6edqb", + "col48": "kuacd", + "col49": "mzm33", + "col50": "8ata7", + "col51": "at7vi", + "col52": "uwpsy", + "col53": "zgr7f", + "col54": "rx5ya", + "col55": "tegxo", + "col56": "ocpx7", + "col57": "r7nu6", + "col58": "48eai", + "col59": "9pkml", + "col60": "7bstj", + "col61": "eey7b", + "col62": "57ifx", + "col63": "sy5hz", + "col64": "ti01g", + "col65": "duprg", + "col66": "2v68v", + "col67": "tpeb5", + "col68": "89owz", + "col69": "j1pc3", + "col70": "vhz7r", + "col71": "35h9v", + "col72": "3879y", + "col73": "u35nr", + "col74": "6fgi7", + "col75": "12jfp", + "col76": "eoh5e", + "col77": "z6hpj", + "col78": "0cxqb", + "col79": "cef0a", + "col80": "up77w", + "col81": "2gst1", + "col82": "vlz2b", + "col83": "k69vg", + "col84": "n7flc", + "col85": "pjavl", + "col86": "izyb0", + "col87": "4gb7a", + "col88": "gg24b", + "col89": "2nd6x", + "col90": "74bvf", + "col91": "iaapg", + "col92": "z24zt", + "col93": "507zy", + "col94": "5bg1u", + "col95": "1xj4l", + "col96": "dw2vb", + "col97": "dtcow" + }, + { + "name": "Georgia Mercer", + "gender": "female", + "company": "Skyplex", + "col0": "fvkw8", + "col1": "7qhga", + "col2": "3oi3q", + "col3": "tx8o9", + "col4": "kweyy", + "col5": "8ir84", + "col6": "4yz81", + "col7": "l2qdz", + "col8": "c4i4e", + "col9": "k06r0", + "col10": "tpcab", + "col11": "wclre", + "col12": "xfqns", + "col13": "y8b2h", + "col14": "8d6cm", + "col15": "hx01c", + "col16": "q2vty", + "col17": "5e1q4", + "col18": "bonro", + "col19": "njhn4", + "col20": "b32fq", + "col21": "jviym", + "col22": "n3zrq", + "col23": "rue1z", + "col24": "r6zzg", + "col25": "2ze9m", + "col26": "bg44a", + "col27": "rjmsq", + "col28": "9hr10", + "col29": "ywvda", + "col30": "e3pho", + "col31": "cx9p4", + "col32": "lwq3c", + "col33": "52nt1", + "col34": "3vxz0", + "col35": "uvakp", + "col36": "nao0o", + "col37": "okyac", + "col38": "02y5w", + "col39": "tud9z", + "col40": "pdoag", + "col41": "wl4jt", + "col42": "k0zto", + "col43": "z11di", + "col44": "oeg6e", + "col45": "hzcrd", + "col46": "jguzb", + "col47": "biwln", + "col48": "ez8sg", + "col49": "qkzca", + "col50": "mfzqu", + "col51": "4gsuz", + "col52": "7y8q1", + "col53": "strkc", + "col54": "7xw8c", + "col55": "yxxzo", + "col56": "qlz1i", + "col57": "futec", + "col58": "0s1ez", + "col59": "g6j3m", + "col60": "3eal3", + "col61": "8dgjb", + "col62": "ci9yu", + "col63": "08nn4", + "col64": "1bmk9", + "col65": "uoa2i", + "col66": "i6yck", + "col67": "jp2yk", + "col68": "is1ex", + "col69": "rafes", + "col70": "6gjiv", + "col71": "owrs0", + "col72": "tfn33", + "col73": "nt84n", + "col74": "hjjui", + "col75": "opbwa", + "col76": "jxjil", + "col77": "z7z49", + "col78": "m3p24", + "col79": "ewlhp", + "col80": "6g4am", + "col81": "wjxao", + "col82": "9fm64", + "col83": "jp376", + "col84": "bbflx", + "col85": "ta35d", + "col86": "xehda", + "col87": "5h0km", + "col88": "mfl5p", + "col89": "8t5w9", + "col90": "bn152", + "col91": "vwzkd", + "col92": "2q3kg", + "col93": "2o27l", + "col94": "s3qui", + "col95": "esp7e", + "col96": "5ojpc", + "col97": "zmqec" + }, + { + "name": "Francesca Elliott", + "gender": "female", + "company": "Nspire", + "col0": "5o9gf", + "col1": "1du3m", + "col2": "udah5", + "col3": "1cj3g", + "col4": "cqcr2", + "col5": "zojwu", + "col6": "k76wh", + "col7": "umel4", + "col8": "3dbse", + "col9": "rxnfz", + "col10": "gvtlp", + "col11": "m89xy", + "col12": "623ev", + "col13": "hf9ss", + "col14": "43bg7", + "col15": "ea7z0", + "col16": "otz2k", + "col17": "1vehp", + "col18": "5886r", + "col19": "5v3u9", + "col20": "2eowx", + "col21": "zoa5w", + "col22": "sbl1u", + "col23": "fgjxh", + "col24": "p74uq", + "col25": "zodq2", + "col26": "acsfv", + "col27": "88a0d", + "col28": "01982", + "col29": "q1mi1", + "col30": "b0ehv", + "col31": "wmds8", + "col32": "2wlep", + "col33": "p3rdl", + "col34": "a8wbw", + "col35": "cvr3d", + "col36": "wem6o", + "col37": "06wo9", + "col38": "skpo5", + "col39": "e0r1h", + "col40": "e4phj", + "col41": "z3emm", + "col42": "ku9lj", + "col43": "uznlt", + "col44": "9br40", + "col45": "fye4a", + "col46": "hsm7o", + "col47": "e9qul", + "col48": "tpo1o", + "col49": "dv1zy", + "col50": "w2ofz", + "col51": "1n5ro", + "col52": "01vlj", + "col53": "7zya2", + "col54": "obr99", + "col55": "fu0pk", + "col56": "x57bz", + "col57": "cklr9", + "col58": "9h5jx", + "col59": "f3l1z", + "col60": "i7xzs", + "col61": "d8i77", + "col62": "xxsm1", + "col63": "kt64l", + "col64": "g36f9", + "col65": "74m69", + "col66": "xm6yh", + "col67": "ckh7p", + "col68": "swtaa", + "col69": "cwycd", + "col70": "9fqp0", + "col71": "zxpfh", + "col72": "u8rt3", + "col73": "duj4b", + "col74": "fpr18", + "col75": "ymxi9", + "col76": "cs67c", + "col77": "2bbxm", + "col78": "x8lfd", + "col79": "jtrzt", + "col80": "pwelc", + "col81": "xyruq", + "col82": "oqg78", + "col83": "o18gi", + "col84": "v1ss1", + "col85": "1qk2f", + "col86": "e63oe", + "col87": "6s1ad", + "col88": "yjozm", + "col89": "1og0f", + "col90": "56v2r", + "col91": "s6ylw", + "col92": "3605z", + "col93": "2w0ed", + "col94": "qcg65", + "col95": "uenra", + "col96": "4cvx9", + "col97": "xp3uj" + }, + { + "name": "Lyons Peters", + "gender": "male", + "company": "Quinex", + "col0": "w9wg4", + "col1": "8yh9d", + "col2": "4h675", + "col3": "cealx", + "col4": "5409g", + "col5": "4tb4l", + "col6": "kyhne", + "col7": "lihe1", + "col8": "m343v", + "col9": "ukqft", + "col10": "oqebl", + "col11": "qgtfr", + "col12": "fahu4", + "col13": "fo0ax", + "col14": "d7rz2", + "col15": "1rau7", + "col16": "x4ygb", + "col17": "emmim", + "col18": "qjjzf", + "col19": "8q8iz", + "col20": "37o9k", + "col21": "p67j2", + "col22": "v049x", + "col23": "7u0db", + "col24": "75cne", + "col25": "z6i08", + "col26": "5sco2", + "col27": "jiwvc", + "col28": "uml7o", + "col29": "gi0z7", + "col30": "881fj", + "col31": "57z4u", + "col32": "dm869", + "col33": "xe6cd", + "col34": "fhfvw", + "col35": "xrc1j", + "col36": "f4gvc", + "col37": "r49tz", + "col38": "9ud3b", + "col39": "37tcs", + "col40": "srimb", + "col41": "bti9c", + "col42": "v8xys", + "col43": "lxb9g", + "col44": "fs8gd", + "col45": "angju", + "col46": "22po5", + "col47": "26s5z", + "col48": "i2ar6", + "col49": "agylx", + "col50": "n86b3", + "col51": "vppj1", + "col52": "ckjok", + "col53": "hh2zi", + "col54": "vvptg", + "col55": "7fjod", + "col56": "8uf8z", + "col57": "ogbkc", + "col58": "4t25n", + "col59": "27xba", + "col60": "2fb57", + "col61": "ltrrl", + "col62": "lwujm", + "col63": "t9tfv", + "col64": "3tv09", + "col65": "7l68q", + "col66": "nn7ob", + "col67": "hhq1e", + "col68": "l9o7r", + "col69": "id2vr", + "col70": "mplhk", + "col71": "cy7lw", + "col72": "d0tq7", + "col73": "sd6pa", + "col74": "gs224", + "col75": "d5nj4", + "col76": "n3ex5", + "col77": "wwxyx", + "col78": "cf5ah", + "col79": "v3di2", + "col80": "r2rq2", + "col81": "xe91k", + "col82": "ux0m6", + "col83": "i7rmt", + "col84": "p9ozg", + "col85": "qwoxg", + "col86": "u46bs", + "col87": "ck04e", + "col88": "klicq", + "col89": "jfrp4", + "col90": "wszh4", + "col91": "eunjl", + "col92": "8nblu", + "col93": "iun6j", + "col94": "r7syn", + "col95": "ij0bg", + "col96": "t8d0s", + "col97": "l48yr" + }, + { + "name": "Kristi Brewer", + "gender": "female", + "company": "Oronoko", + "col0": "zsf8c", + "col1": "pudj9", + "col2": "k2eym", + "col3": "ksxv4", + "col4": "ao8xf", + "col5": "6h0gr", + "col6": "hksy7", + "col7": "99dso", + "col8": "y7ezl", + "col9": "kftug", + "col10": "h4zh6", + "col11": "nkotj", + "col12": "hx5uy", + "col13": "nke0m", + "col14": "z0z83", + "col15": "xs6uf", + "col16": "wqlws", + "col17": "i96w7", + "col18": "hkzi3", + "col19": "jz947", + "col20": "e1gph", + "col21": "31viz", + "col22": "u39sx", + "col23": "c6903", + "col24": "taams", + "col25": "aykgk", + "col26": "pzgrg", + "col27": "neol8", + "col28": "1c4ez", + "col29": "iickt", + "col30": "4qi1z", + "col31": "98d3u", + "col32": "hooyb", + "col33": "se5kt", + "col34": "jc836", + "col35": "n6j6l", + "col36": "vkk5o", + "col37": "pqwdb", + "col38": "st4j9", + "col39": "5ntc1", + "col40": "5k47k", + "col41": "bmngn", + "col42": "souvh", + "col43": "w3n1f", + "col44": "71ff3", + "col45": "eeyku", + "col46": "7mxhg", + "col47": "tzh3c", + "col48": "rpmrd", + "col49": "bzwa1", + "col50": "zmkwd", + "col51": "gp6k0", + "col52": "28bby", + "col53": "lh50e", + "col54": "xcz1o", + "col55": "6gziz", + "col56": "0g8gb", + "col57": "zl9cx", + "col58": "e1ua6", + "col59": "n51eh", + "col60": "aos46", + "col61": "11m9b", + "col62": "elu1y", + "col63": "r5b0g", + "col64": "siw86", + "col65": "j0m5m", + "col66": "a0pej", + "col67": "t32eq", + "col68": "im42f", + "col69": "lnz2y", + "col70": "1e4ze", + "col71": "pgwxb", + "col72": "hc8hr", + "col73": "vs1yu", + "col74": "mffoe", + "col75": "cv0kx", + "col76": "0yff9", + "col77": "e4si1", + "col78": "fj0wf", + "col79": "0w45g", + "col80": "deus9", + "col81": "b71y3", + "col82": "2p24n", + "col83": "4w6nv", + "col84": "zqsr9", + "col85": "09pmb", + "col86": "9u3be", + "col87": "e9dnp", + "col88": "ob121", + "col89": "dpoog", + "col90": "7umq7", + "col91": "x0uxw", + "col92": "0kj0a", + "col93": "1polc", + "col94": "8k6ey", + "col95": "samr1", + "col96": "u3cqq", + "col97": "atcsz" + }, + { + "name": "Tonya Bray", + "gender": "female", + "company": "Insuron", + "col0": "f69l1", + "col1": "i82fy", + "col2": "e13ms", + "col3": "wv608", + "col4": "3zugf", + "col5": "3ex5j", + "col6": "x5vid", + "col7": "veq8w", + "col8": "zcet0", + "col9": "ia9ju", + "col10": "q8cnk", + "col11": "jt6m9", + "col12": "kuqg5", + "col13": "lirga", + "col14": "8jojx", + "col15": "wd66j", + "col16": "jq2tm", + "col17": "unfgg", + "col18": "sq206", + "col19": "clv5e", + "col20": "coxjc", + "col21": "dixp3", + "col22": "p81xn", + "col23": "mzdm7", + "col24": "73v0w", + "col25": "9382c", + "col26": "alb93", + "col27": "w551m", + "col28": "gdrbk", + "col29": "0icis", + "col30": "qhxar", + "col31": "i3lb6", + "col32": "lp0r5", + "col33": "at6xl", + "col34": "3nv0l", + "col35": "2leto", + "col36": "rv5zi", + "col37": "qz9xr", + "col38": "qbid6", + "col39": "sc34b", + "col40": "oca7p", + "col41": "wzq4n", + "col42": "1hqjd", + "col43": "egmke", + "col44": "vaihi", + "col45": "snm4y", + "col46": "h7k4c", + "col47": "r8ehg", + "col48": "crmax", + "col49": "c7r13", + "col50": "1z6bx", + "col51": "tc3zv", + "col52": "pp0lf", + "col53": "kna86", + "col54": "31e7q", + "col55": "zhzy7", + "col56": "c1sal", + "col57": "tewnx", + "col58": "ysna0", + "col59": "90fmh", + "col60": "4hqxo", + "col61": "7z6ce", + "col62": "k23re", + "col63": "z7uu3", + "col64": "cyunf", + "col65": "8p4bx", + "col66": "8asdr", + "col67": "oe3ag", + "col68": "1gd50", + "col69": "3gqv9", + "col70": "jx4bb", + "col71": "yiay5", + "col72": "u8ixa", + "col73": "4dki4", + "col74": "ktg42", + "col75": "a9bx3", + "col76": "o1ki1", + "col77": "035qq", + "col78": "6588u", + "col79": "pqwls", + "col80": "t8xeu", + "col81": "xr23q", + "col82": "2cxta", + "col83": "u0vpc", + "col84": "6d5z4", + "col85": "r700p", + "col86": "h2ipl", + "col87": "aodhl", + "col88": "h3x4f", + "col89": "suv9h", + "col90": "cj2pt", + "col91": "ywsbj", + "col92": "e6c4v", + "col93": "nglno", + "col94": "4prmc", + "col95": "mo83e", + "col96": "5kdfq", + "col97": "3qa1y" + }, + { + "name": "Valenzuela Huff", + "gender": "male", + "company": "Applideck", + "col0": "k5rzn", + "col1": "83fpa", + "col2": "rjhq0", + "col3": "fbaei", + "col4": "ggbkc", + "col5": "uod13", + "col6": "qka9d", + "col7": "rz3hq", + "col8": "03nr3", + "col9": "jlijh", + "col10": "m0g6q", + "col11": "wx3ym", + "col12": "pftdc", + "col13": "bjstt", + "col14": "xtwnh", + "col15": "adhqm", + "col16": "j3w34", + "col17": "1skmp", + "col18": "frv1t", + "col19": "9dokf", + "col20": "aurb6", + "col21": "8qdrh", + "col22": "7517l", + "col23": "xvvsu", + "col24": "jyus4", + "col25": "g9lrp", + "col26": "364ps", + "col27": "qarnz", + "col28": "sqk7m", + "col29": "pe3dt", + "col30": "8mwxh", + "col31": "yizgx", + "col32": "kx21f", + "col33": "c11hr", + "col34": "bg0sn", + "col35": "pwzrq", + "col36": "5dpwg", + "col37": "a3f1e", + "col38": "rfa3e", + "col39": "cr8il", + "col40": "wj80t", + "col41": "twt34", + "col42": "o45yi", + "col43": "yjeyd", + "col44": "zy5rl", + "col45": "yjldx", + "col46": "o3hlj", + "col47": "603we", + "col48": "c51x2", + "col49": "nww3p", + "col50": "nnen1", + "col51": "9eiea", + "col52": "2mryw", + "col53": "ujb7s", + "col54": "92i0h", + "col55": "93yqo", + "col56": "xfrqb", + "col57": "lv1k9", + "col58": "6ja0u", + "col59": "c4f20", + "col60": "6s3co", + "col61": "h6kuy", + "col62": "2b2n5", + "col63": "4g76r", + "col64": "nkdsu", + "col65": "2sr9o", + "col66": "8d75b", + "col67": "ncbci", + "col68": "xgxf1", + "col69": "qzvzg", + "col70": "zzs6c", + "col71": "rj2wd", + "col72": "0p463", + "col73": "1gr40", + "col74": "a3169", + "col75": "s5up9", + "col76": "py9x5", + "col77": "cuk1c", + "col78": "kka40", + "col79": "vrqao", + "col80": "1pepp", + "col81": "fppes", + "col82": "g6ytd", + "col83": "yz3dy", + "col84": "t7f7h", + "col85": "tgnsv", + "col86": "2tg8r", + "col87": "os6x6", + "col88": "ynwap", + "col89": "n8bqp", + "col90": "e5157", + "col91": "y6tin", + "col92": "5aheh", + "col93": "h7dzq", + "col94": "mgetl", + "col95": "6okf9", + "col96": "38y2t", + "col97": "6goot" + }, + { + "name": "Tiffany Anderson", + "gender": "female", + "company": "Zanymax", + "col0": "nzx6r", + "col1": "8ylan", + "col2": "swlnz", + "col3": "m1iwo", + "col4": "o4t4w", + "col5": "12svw", + "col6": "m15qx", + "col7": "t40k7", + "col8": "rdhpi", + "col9": "196uv", + "col10": "2ihkx", + "col11": "p5chz", + "col12": "v6rzf", + "col13": "gk09a", + "col14": "45771", + "col15": "fp2en", + "col16": "zlbyj", + "col17": "exbca", + "col18": "tzyzv", + "col19": "l5mle", + "col20": "in0v7", + "col21": "t41ca", + "col22": "ge2lm", + "col23": "g9mhi", + "col24": "trzva", + "col25": "ybfnt", + "col26": "bsx6b", + "col27": "r703q", + "col28": "3j208", + "col29": "qx0nf", + "col30": "1a1yf", + "col31": "w4bd2", + "col32": "t81x3", + "col33": "3a9cw", + "col34": "8suwr", + "col35": "n6vjk", + "col36": "z74zh", + "col37": "dcpfk", + "col38": "45ayc", + "col39": "bfboa", + "col40": "7b2pb", + "col41": "g1o5h", + "col42": "bk4ap", + "col43": "u8vyq", + "col44": "2syn7", + "col45": "a4tvv", + "col46": "nj38o", + "col47": "0sztd", + "col48": "159tb", + "col49": "f93bf", + "col50": "df7nv", + "col51": "pwzar", + "col52": "9b7ce", + "col53": "dyeko", + "col54": "etog0", + "col55": "c617g", + "col56": "qrkht", + "col57": "g769f", + "col58": "9hmwk", + "col59": "7ixbu", + "col60": "uf4bm", + "col61": "izvs1", + "col62": "z5ji3", + "col63": "g86g5", + "col64": "26lp9", + "col65": "ynj35", + "col66": "w6cbh", + "col67": "xfbjt", + "col68": "fxqfj", + "col69": "yu60h", + "col70": "h4xu5", + "col71": "degv9", + "col72": "pyaqm", + "col73": "cvudy", + "col74": "9yedm", + "col75": "mj944", + "col76": "7kn5w", + "col77": "tx26x", + "col78": "tlvbx", + "col79": "gk8xh", + "col80": "jj90g", + "col81": "470md", + "col82": "3zonq", + "col83": "unaym", + "col84": "54ndp", + "col85": "23872", + "col86": "c4wwb", + "col87": "13s1d", + "col88": "gkhkk", + "col89": "n63go", + "col90": "uzkg3", + "col91": "8c2ab", + "col92": "7g8hd", + "col93": "w3xtf", + "col94": "f7laf", + "col95": "nlagg", + "col96": "7xfhw", + "col97": "r0fke" + }, + { + "name": "Jerri King", + "gender": "female", + "company": "Eventex", + "col0": "myqmk", + "col1": "ds19q", + "col2": "1etkn", + "col3": "724rl", + "col4": "raf6v", + "col5": "krag3", + "col6": "rmx0l", + "col7": "3wo1d", + "col8": "ky6u8", + "col9": "6aqth", + "col10": "gjiz4", + "col11": "0rtws", + "col12": "viv1q", + "col13": "mrpjn", + "col14": "i6eev", + "col15": "eee9v", + "col16": "k72tz", + "col17": "ukofo", + "col18": "95d2v", + "col19": "65aix", + "col20": "euxpx", + "col21": "2rdp3", + "col22": "ar739", + "col23": "v390w", + "col24": "dakmx", + "col25": "renh8", + "col26": "lgmwj", + "col27": "ld417", + "col28": "uhsq4", + "col29": "sdfr5", + "col30": "6hz3t", + "col31": "cv83z", + "col32": "9u4ph", + "col33": "rt7z8", + "col34": "zqq88", + "col35": "50lmx", + "col36": "fcsy1", + "col37": "w3beq", + "col38": "4a8pu", + "col39": "629tu", + "col40": "jupra", + "col41": "3nnec", + "col42": "57m0x", + "col43": "o7oyp", + "col44": "9c4nk", + "col45": "zoo3a", + "col46": "f0788", + "col47": "b4iks", + "col48": "qv9hw", + "col49": "ifwze", + "col50": "3qcgp", + "col51": "rwfmq", + "col52": "asuqn", + "col53": "x6t3m", + "col54": "engyo", + "col55": "sopr0", + "col56": "r5f0z", + "col57": "ca3vg", + "col58": "fui21", + "col59": "nphkd", + "col60": "16lrf", + "col61": "7ngvs", + "col62": "vwb3q", + "col63": "csypb", + "col64": "ynt5i", + "col65": "n9nfw", + "col66": "rr8sp", + "col67": "2pcrn", + "col68": "oh2op", + "col69": "9guqy", + "col70": "1tdgx", + "col71": "10yv4", + "col72": "xd34p", + "col73": "4x6aw", + "col74": "r4ebg", + "col75": "3mbdx", + "col76": "3npvb", + "col77": "d8d22", + "col78": "qlglz", + "col79": "sfbk4", + "col80": "h3qt9", + "col81": "gc2pz", + "col82": "23imq", + "col83": "9a48l", + "col84": "l7hdu", + "col85": "7uquy", + "col86": "ibie3", + "col87": "x1u9x", + "col88": "8wfal", + "col89": "7ac46", + "col90": "bh7ew", + "col91": "7bqs4", + "col92": "4vcnu", + "col93": "jump6", + "col94": "k47n2", + "col95": "gmtt6", + "col96": "jw9ur", + "col97": "2k8kt" + }, + { + "name": "Rocha Meadows", + "gender": "male", + "company": "Goko", + "col0": "jjprc", + "col1": "u7qvd", + "col2": "78tm5", + "col3": "vi2fo", + "col4": "qlgsz", + "col5": "pzpxx", + "col6": "6q7ii", + "col7": "gvz31", + "col8": "c2kj2", + "col9": "4mwzo", + "col10": "361r9", + "col11": "iwl50", + "col12": "1dna6", + "col13": "s9ksq", + "col14": "mogpt", + "col15": "m2npw", + "col16": "ijm9q", + "col17": "xefm5", + "col18": "0u66o", + "col19": "6pdir", + "col20": "zcjyd", + "col21": "jp33t", + "col22": "7mx3j", + "col23": "8077s", + "col24": "surxv", + "col25": "3bxsh", + "col26": "6anz6", + "col27": "zy7p5", + "col28": "utjat", + "col29": "ba34s", + "col30": "7uwpo", + "col31": "gbqas", + "col32": "rbc6b", + "col33": "wzyhs", + "col34": "maw9w", + "col35": "b1tt5", + "col36": "972ey", + "col37": "pwid4", + "col38": "8bnel", + "col39": "w6qji", + "col40": "3b61m", + "col41": "ja7f9", + "col42": "7vhha", + "col43": "y716d", + "col44": "3g8kw", + "col45": "pyez5", + "col46": "5v39f", + "col47": "0nq85", + "col48": "fards", + "col49": "8dhvs", + "col50": "uvryj", + "col51": "3ex67", + "col52": "5j23r", + "col53": "mdsi8", + "col54": "khrcd", + "col55": "pj8me", + "col56": "bkxff", + "col57": "mh4a3", + "col58": "reug3", + "col59": "0h0qs", + "col60": "v0f2n", + "col61": "rl69g", + "col62": "3djdx", + "col63": "b2f06", + "col64": "653xg", + "col65": "9lna9", + "col66": "svhat", + "col67": "v3cvb", + "col68": "j483r", + "col69": "38agw", + "col70": "a7t5b", + "col71": "esdg8", + "col72": "00o9h", + "col73": "m9spg", + "col74": "2buqu", + "col75": "bdg5r", + "col76": "luf9c", + "col77": "d7tv7", + "col78": "03pnh", + "col79": "yovcx", + "col80": "1ongm", + "col81": "xluh9", + "col82": "vbevx", + "col83": "f6i0u", + "col84": "dt1y7", + "col85": "yrl6z", + "col86": "7n9qk", + "col87": "xtsiu", + "col88": "7n8dc", + "col89": "azbho", + "col90": "cwte0", + "col91": "m3ks2", + "col92": "rzkst", + "col93": "nrdaj", + "col94": "zk7gl", + "col95": "5yw3p", + "col96": "wlt3z", + "col97": "0wz4i" + }, + { + "name": "Marcy Green", + "gender": "female", + "company": "Pharmex", + "col0": "crvoe", + "col1": "lhaie", + "col2": "8lnvl", + "col3": "umogr", + "col4": "j8w5w", + "col5": "vzkkn", + "col6": "sssqm", + "col7": "mnctm", + "col8": "2mf4e", + "col9": "xjv2z", + "col10": "sa8pt", + "col11": "3rckr", + "col12": "7l3ie", + "col13": "ohr2r", + "col14": "ep0cv", + "col15": "um596", + "col16": "kd4lr", + "col17": "bhk2z", + "col18": "go3qm", + "col19": "4dewl", + "col20": "qarx6", + "col21": "qkaf9", + "col22": "attek", + "col23": "s6sxm", + "col24": "owql0", + "col25": "uh4je", + "col26": "9kkzz", + "col27": "l2u2e", + "col28": "wm5ni", + "col29": "e7bn5", + "col30": "85nqs", + "col31": "j1h8a", + "col32": "83ydh", + "col33": "xp6dc", + "col34": "yyncu", + "col35": "6ob8p", + "col36": "k8tjz", + "col37": "e8sl6", + "col38": "llu2d", + "col39": "ioy32", + "col40": "xedwk", + "col41": "0vnor", + "col42": "3j3l6", + "col43": "3nl0j", + "col44": "91zs1", + "col45": "4bb2m", + "col46": "bpo6j", + "col47": "b34f8", + "col48": "s9777", + "col49": "9ngow", + "col50": "7g6gt", + "col51": "5qme8", + "col52": "2imns", + "col53": "x25xy", + "col54": "10re1", + "col55": "w4s81", + "col56": "aiy8p", + "col57": "m1p3m", + "col58": "wbw47", + "col59": "ty3la", + "col60": "8fki9", + "col61": "7a2sa", + "col62": "ju63q", + "col63": "sia12", + "col64": "1c8m8", + "col65": "d6cp2", + "col66": "hmwlk", + "col67": "coqtu", + "col68": "j69ix", + "col69": "dxt13", + "col70": "ueoij", + "col71": "axr8o", + "col72": "t6tiz", + "col73": "ahxl6", + "col74": "qq08i", + "col75": "c8yxb", + "col76": "65xc8", + "col77": "myrvd", + "col78": "zkies", + "col79": "7al5v", + "col80": "af6rg", + "col81": "dgiic", + "col82": "6fiey", + "col83": "33dzd", + "col84": "iwnli", + "col85": "nxz3e", + "col86": "lom5l", + "col87": "v2cuy", + "col88": "1nxq0", + "col89": "8nmgn", + "col90": "t9muh", + "col91": "pbm62", + "col92": "1j1i4", + "col93": "qt3x1", + "col94": "o8v6o", + "col95": "5m77o", + "col96": "qrj8i", + "col97": "edfs7" + }, + { + "name": "Kirk Cross", + "gender": "male", + "company": "Portico", + "col0": "3rk7g", + "col1": "r2aic", + "col2": "awqrb", + "col3": "rv3iy", + "col4": "z6pl3", + "col5": "cc4r3", + "col6": "fhr8n", + "col7": "l1dm0", + "col8": "lin70", + "col9": "kdesr", + "col10": "x2zwd", + "col11": "o1y21", + "col12": "4mc78", + "col13": "jcbdg", + "col14": "i71at", + "col15": "fo2uq", + "col16": "84xeh", + "col17": "x5gvc", + "col18": "pdyal", + "col19": "z20kx", + "col20": "g8zi2", + "col21": "cokdx", + "col22": "6c2nj", + "col23": "7s1qr", + "col24": "zhgxh", + "col25": "ucrb6", + "col26": "kb6y7", + "col27": "es58m", + "col28": "5fqjx", + "col29": "59iw7", + "col30": "lcckw", + "col31": "jlpow", + "col32": "2quwx", + "col33": "5lxg2", + "col34": "o8q1d", + "col35": "6glq4", + "col36": "an8sw", + "col37": "kik93", + "col38": "zam34", + "col39": "wsu2b", + "col40": "0xksm", + "col41": "zzvi8", + "col42": "3gwzv", + "col43": "a8yhl", + "col44": "8hokk", + "col45": "avgvr", + "col46": "d7v7r", + "col47": "onbol", + "col48": "qc57d", + "col49": "jve8v", + "col50": "o2xgy", + "col51": "dvion", + "col52": "jeoer", + "col53": "3szfj", + "col54": "g4et0", + "col55": "4bow5", + "col56": "vxd6a", + "col57": "6dt8h", + "col58": "9vg74", + "col59": "8mz8b", + "col60": "fx0tu", + "col61": "y3i9m", + "col62": "gh8o5", + "col63": "66xk2", + "col64": "8m1de", + "col65": "63pfk", + "col66": "8prho", + "col67": "12xh9", + "col68": "sjko4", + "col69": "o0dv0", + "col70": "9wofm", + "col71": "6ble9", + "col72": "uncwl", + "col73": "ku3wk", + "col74": "3vteo", + "col75": "yhp6i", + "col76": "035rd", + "col77": "924t3", + "col78": "4ylaw", + "col79": "fizdh", + "col80": "yc17v", + "col81": "mlodk", + "col82": "eyrey", + "col83": "kovbi", + "col84": "l3hk5", + "col85": "r16vp", + "col86": "c2fqk", + "col87": "gq9b7", + "col88": "7qdmq", + "col89": "foxtc", + "col90": "melvn", + "col91": "ntbk0", + "col92": "or3z2", + "col93": "sg3mg", + "col94": "20omc", + "col95": "rb5vb", + "col96": "i75xz", + "col97": "xpwfm" + }, + { + "name": "Hattie Mullen", + "gender": "female", + "company": "Zilencio", + "col0": "5n1mf", + "col1": "t0w8k", + "col2": "kutuc", + "col3": "s8n67", + "col4": "wqhiq", + "col5": "00hby", + "col6": "we3by", + "col7": "tietd", + "col8": "73dwb", + "col9": "m09kf", + "col10": "3kf1y", + "col11": "5ljkk", + "col12": "yp6hs", + "col13": "rcih3", + "col14": "7frn6", + "col15": "4z80q", + "col16": "28rgl", + "col17": "c4pro", + "col18": "c5d7c", + "col19": "w6qey", + "col20": "uc8ss", + "col21": "dsdtq", + "col22": "e6myk", + "col23": "o4xbm", + "col24": "82137", + "col25": "kx31h", + "col26": "lch5i", + "col27": "25lsf", + "col28": "zosmx", + "col29": "7490t", + "col30": "ast35", + "col31": "jv4r3", + "col32": "x9ch4", + "col33": "xlq3l", + "col34": "fw5pm", + "col35": "vei3m", + "col36": "x4vt2", + "col37": "iqr2b", + "col38": "34wew", + "col39": "wkv33", + "col40": "ese8d", + "col41": "5dv5p", + "col42": "q73vm", + "col43": "uz2bh", + "col44": "b3t5x", + "col45": "hf020", + "col46": "o1072", + "col47": "gk38o", + "col48": "jpouz", + "col49": "s2nnj", + "col50": "1lb3g", + "col51": "mdof9", + "col52": "3kbx7", + "col53": "bl7s0", + "col54": "kelr9", + "col55": "80x57", + "col56": "kcrcx", + "col57": "14uge", + "col58": "autr9", + "col59": "y1cob", + "col60": "lwp41", + "col61": "u9gry", + "col62": "w8iu7", + "col63": "2s0s7", + "col64": "4erum", + "col65": "xj6zb", + "col66": "vkrgx", + "col67": "nio2f", + "col68": "1333a", + "col69": "2gniq", + "col70": "hk8g1", + "col71": "a2isb", + "col72": "inidq", + "col73": "whn91", + "col74": "d0jla", + "col75": "oqpjy", + "col76": "9p8ey", + "col77": "rf83w", + "col78": "f5nnc", + "col79": "5kobk", + "col80": "9u7gx", + "col81": "t279y", + "col82": "3vz9o", + "col83": "j4gbt", + "col84": "o0tmt", + "col85": "22lnr", + "col86": "7nifv", + "col87": "15vau", + "col88": "buvn1", + "col89": "66r2k", + "col90": "hgfcn", + "col91": "1wxla", + "col92": "wm7y2", + "col93": "4m2hn", + "col94": "eapgz", + "col95": "ytpvr", + "col96": "0xzv8", + "col97": "vcpqt" + }, + { + "name": "Deann Bridges", + "gender": "female", + "company": "Equitox", + "col0": "n2h6u", + "col1": "wks6y", + "col2": "sqrm9", + "col3": "jiox6", + "col4": "ejel0", + "col5": "f07hh", + "col6": "in8ov", + "col7": "tt82y", + "col8": "btojj", + "col9": "os7ag", + "col10": "2tfdo", + "col11": "0w5to", + "col12": "ty0ig", + "col13": "nzj1l", + "col14": "kprn8", + "col15": "cbs43", + "col16": "y8gv4", + "col17": "ktgsl", + "col18": "smf2h", + "col19": "wfbqy", + "col20": "yeo5o", + "col21": "msklc", + "col22": "xnojs", + "col23": "jnaad", + "col24": "w8xet", + "col25": "eoof7", + "col26": "b5mu4", + "col27": "xtvjm", + "col28": "hsk4b", + "col29": "z6ggx", + "col30": "c4tn4", + "col31": "9k2sc", + "col32": "w2u7t", + "col33": "nsucm", + "col34": "a2o3m", + "col35": "l5zia", + "col36": "dreo4", + "col37": "8q33s", + "col38": "rci1t", + "col39": "a8f4i", + "col40": "m3e0c", + "col41": "sz6q4", + "col42": "3m9re", + "col43": "p4biy", + "col44": "3i17r", + "col45": "dee0b", + "col46": "s1evo", + "col47": "gbszf", + "col48": "m18sa", + "col49": "gkjcy", + "col50": "n49m9", + "col51": "sgvp2", + "col52": "uitvu", + "col53": "3wyrn", + "col54": "utvth", + "col55": "d2aru", + "col56": "clz6c", + "col57": "e46uz", + "col58": "zret2", + "col59": "8fwxv", + "col60": "r57sz", + "col61": "u6kyi", + "col62": "fq3qm", + "col63": "ixby7", + "col64": "ypiln", + "col65": "95oe1", + "col66": "8ufqw", + "col67": "4uwsp", + "col68": "rzpx7", + "col69": "3svbi", + "col70": "wsshp", + "col71": "kmfnb", + "col72": "2w48e", + "col73": "zd48d", + "col74": "wmsdy", + "col75": "add80", + "col76": "x23cy", + "col77": "blvvj", + "col78": "9wqnd", + "col79": "mxvnr", + "col80": "zcnvt", + "col81": "7fjlt", + "col82": "kpvqw", + "col83": "3gqk9", + "col84": "072xx", + "col85": "ketq0", + "col86": "79iqn", + "col87": "rm5h9", + "col88": "n3y5i", + "col89": "4wn1s", + "col90": "fa80s", + "col91": "vk8dc", + "col92": "4fjjo", + "col93": "ileiy", + "col94": "tcywz", + "col95": "wgg52", + "col96": "kq1oy", + "col97": "jm113" + }, + { + "name": "Chaney Roach", + "gender": "male", + "company": "Qualitern", + "col0": "looai", + "col1": "qhade", + "col2": "qsrfv", + "col3": "x18te", + "col4": "qlt8d", + "col5": "3n6yt", + "col6": "d65yl", + "col7": "zxvgo", + "col8": "jif6r", + "col9": "z2mm4", + "col10": "lurbz", + "col11": "xx2r5", + "col12": "1s640", + "col13": "k3edj", + "col14": "m0kj7", + "col15": "irxcq", + "col16": "67ws6", + "col17": "5htpy", + "col18": "fc9b0", + "col19": "t4sw2", + "col20": "3ev7g", + "col21": "nh4p8", + "col22": "d79cn", + "col23": "hjghd", + "col24": "p4gjy", + "col25": "fol83", + "col26": "y3rjj", + "col27": "vdk7e", + "col28": "lw82t", + "col29": "tplur", + "col30": "teknw", + "col31": "vii2o", + "col32": "hizba", + "col33": "2tenz", + "col34": "yvcgi", + "col35": "3qizy", + "col36": "hbvq8", + "col37": "z2x75", + "col38": "xp3b7", + "col39": "cdadk", + "col40": "vau4a", + "col41": "ipnng", + "col42": "qjxaw", + "col43": "nykhl", + "col44": "3gclh", + "col45": "nvka2", + "col46": "z7orf", + "col47": "t6kt0", + "col48": "twris", + "col49": "1gqs8", + "col50": "86uii", + "col51": "4vp02", + "col52": "9v1db", + "col53": "ngu34", + "col54": "ih11i", + "col55": "wf5fj", + "col56": "379ib", + "col57": "lxi0n", + "col58": "la96q", + "col59": "u7x4q", + "col60": "2m6d4", + "col61": "0mhsr", + "col62": "4230q", + "col63": "wr7kf", + "col64": "c6wr0", + "col65": "gbt0m", + "col66": "rnie4", + "col67": "fsvf5", + "col68": "mvano", + "col69": "4naav", + "col70": "bvjbe", + "col71": "4d2zk", + "col72": "sfnfp", + "col73": "u0m69", + "col74": "h3yqy", + "col75": "o7m4l", + "col76": "q2he5", + "col77": "zt16y", + "col78": "vyf60", + "col79": "jpdei", + "col80": "93sd0", + "col81": "9o1sd", + "col82": "ual8a", + "col83": "z09l8", + "col84": "yayya", + "col85": "0wmbh", + "col86": "7jweb", + "col87": "neema", + "col88": "jqs3f", + "col89": "ti8we", + "col90": "xrx7z", + "col91": "6790b", + "col92": "xexzs", + "col93": "xza3v", + "col94": "87f4d", + "col95": "hwnb9", + "col96": "udjoa", + "col97": "pxnc9" + }, + { + "name": "Consuelo Dickson", + "gender": "female", + "company": "Poshome", + "col0": "0c4m5", + "col1": "rrocs", + "col2": "5aegv", + "col3": "ypusr", + "col4": "yi7dw", + "col5": "q27c9", + "col6": "3n2eu", + "col7": "9qk9p", + "col8": "nh74o", + "col9": "87kql", + "col10": "ztscv", + "col11": "ex27g", + "col12": "f3pqb", + "col13": "5gbch", + "col14": "xjfzi", + "col15": "5t68m", + "col16": "tlckn", + "col17": "qtlag", + "col18": "si48t", + "col19": "nggyj", + "col20": "hz424", + "col21": "p6p8o", + "col22": "83j59", + "col23": "n21dh", + "col24": "sskmn", + "col25": "zb5jr", + "col26": "alit2", + "col27": "lsgq8", + "col28": "ysuls", + "col29": "z9hrz", + "col30": "9no2m", + "col31": "rqoh9", + "col32": "pxff2", + "col33": "27hhy", + "col34": "qxuik", + "col35": "yvysb", + "col36": "rqt2q", + "col37": "1469d", + "col38": "e2kgl", + "col39": "7csbe", + "col40": "dihew", + "col41": "lf04x", + "col42": "3yw3n", + "col43": "mextx", + "col44": "l816i", + "col45": "elz6g", + "col46": "qvw9b", + "col47": "gm8ux", + "col48": "npl83", + "col49": "t02ih", + "col50": "vaiqo", + "col51": "gsc26", + "col52": "qfapt", + "col53": "to2bv", + "col54": "m5xqj", + "col55": "0mplq", + "col56": "1vunj", + "col57": "0sryz", + "col58": "2qhus", + "col59": "n546v", + "col60": "6nxj2", + "col61": "ypf34", + "col62": "wki9o", + "col63": "7uv6w", + "col64": "zobtx", + "col65": "gfaxc", + "col66": "sfmwz", + "col67": "5rwee", + "col68": "5ab7w", + "col69": "b0qqt", + "col70": "kuo1y", + "col71": "1i3cs", + "col72": "e9j9u", + "col73": "hqiev", + "col74": "bdgho", + "col75": "8kq3k", + "col76": "6h7e5", + "col77": "4cmlf", + "col78": "hy8og", + "col79": "mqyyb", + "col80": "0hneu", + "col81": "4bxpt", + "col82": "6j1ly", + "col83": "i8fim", + "col84": "rcsd0", + "col85": "csg19", + "col86": "bvbj1", + "col87": "u6l2x", + "col88": "3xsu2", + "col89": "pc287", + "col90": "oe1wq", + "col91": "pi8s1", + "col92": "yuxz1", + "col93": "4d7fm", + "col94": "aitl9", + "col95": "8iivs", + "col96": "5judp", + "col97": "oak4t" + }, + { + "name": "Billie Rowe", + "gender": "female", + "company": "Cemention", + "col0": "wf3dy", + "col1": "5owlk", + "col2": "xoz4j", + "col3": "yduhr", + "col4": "dhmjn", + "col5": "qto8a", + "col6": "zowz3", + "col7": "ot0lv", + "col8": "ez8l0", + "col9": "sn6j0", + "col10": "xsmi6", + "col11": "n8mnw", + "col12": "jld8p", + "col13": "a4j5k", + "col14": "k05z3", + "col15": "qmw8u", + "col16": "elblo", + "col17": "soh3q", + "col18": "c6997", + "col19": "2xhvf", + "col20": "d4v29", + "col21": "3ouk7", + "col22": "c144t", + "col23": "asje0", + "col24": "c5syw", + "col25": "o3e34", + "col26": "y4atz", + "col27": "o9k4d", + "col28": "1hd8m", + "col29": "gdc4z", + "col30": "al57c", + "col31": "y9n6t", + "col32": "0jxhx", + "col33": "1h5su", + "col34": "eve6z", + "col35": "afr2t", + "col36": "w2tcr", + "col37": "yy9cm", + "col38": "0ixey", + "col39": "jpke1", + "col40": "mty6k", + "col41": "25o6f", + "col42": "moqhb", + "col43": "bbjp9", + "col44": "uvy1o", + "col45": "k2aj2", + "col46": "d1foh", + "col47": "4yxso", + "col48": "tv2ue", + "col49": "pl760", + "col50": "cgwsr", + "col51": "cd6qk", + "col52": "olwac", + "col53": "xfcgd", + "col54": "8t4ot", + "col55": "pm214", + "col56": "67uob", + "col57": "nbors", + "col58": "jqpwl", + "col59": "csehi", + "col60": "d4hua", + "col61": "t7os9", + "col62": "4u8rw", + "col63": "3uf6z", + "col64": "mauks", + "col65": "lcs4c", + "col66": "lniae", + "col67": "utjh3", + "col68": "7alel", + "col69": "z25a0", + "col70": "oixa7", + "col71": "l0d59", + "col72": "snssp", + "col73": "u67ob", + "col74": "2x9k5", + "col75": "pry1n", + "col76": "udu3p", + "col77": "9ll3c", + "col78": "sz2tb", + "col79": "6w256", + "col80": "5vus8", + "col81": "oavkb", + "col82": "uohql", + "col83": "w16zf", + "col84": "jjofu", + "col85": "icusi", + "col86": "ou33z", + "col87": "plbka", + "col88": "odxr0", + "col89": "ix2fl", + "col90": "ypihx", + "col91": "lpa1x", + "col92": "uekc7", + "col93": "9thgv", + "col94": "c1jwv", + "col95": "s8h4q", + "col96": "ti6s5", + "col97": "dk45h" + }, + { + "name": "Bean Donovan", + "gender": "male", + "company": "Mantro", + "col0": "u7kax", + "col1": "urjfo", + "col2": "dww6i", + "col3": "wdm9w", + "col4": "v2hx2", + "col5": "iu2ec", + "col6": "aatsv", + "col7": "ucol4", + "col8": "bnbrb", + "col9": "9csr2", + "col10": "cle4g", + "col11": "2gpb5", + "col12": "sarab", + "col13": "o59ub", + "col14": "hor1i", + "col15": "i9noo", + "col16": "i7qpy", + "col17": "3b42p", + "col18": "adavr", + "col19": "s9drl", + "col20": "snp4m", + "col21": "fhutn", + "col22": "yrap2", + "col23": "j49g1", + "col24": "bs4cq", + "col25": "uv6xn", + "col26": "m7ovs", + "col27": "lx6m4", + "col28": "kvzzi", + "col29": "33q9o", + "col30": "ohe2b", + "col31": "kalny", + "col32": "f2kt2", + "col33": "5scc6", + "col34": "dx2r8", + "col35": "0854f", + "col36": "2rwg7", + "col37": "s7bkp", + "col38": "t4scj", + "col39": "m1ze1", + "col40": "vj9x2", + "col41": "q04hv", + "col42": "5emk6", + "col43": "787wq", + "col44": "bgdnz", + "col45": "mqvom", + "col46": "x1c0s", + "col47": "15mho", + "col48": "2c01j", + "col49": "tpmsk", + "col50": "80xsw", + "col51": "xuuq6", + "col52": "n76hm", + "col53": "wtoql", + "col54": "i4g21", + "col55": "303t9", + "col56": "1vljs", + "col57": "hhabq", + "col58": "xtmpc", + "col59": "4lfuq", + "col60": "4vqll", + "col61": "tsynt", + "col62": "vj8jl", + "col63": "t171w", + "col64": "9jn7a", + "col65": "ee9g5", + "col66": "r1zre", + "col67": "kq3zq", + "col68": "9pk3y", + "col69": "fawle", + "col70": "govlv", + "col71": "5x9jb", + "col72": "zmsed", + "col73": "yzhze", + "col74": "gvbu0", + "col75": "u9t3u", + "col76": "vid2f", + "col77": "ehj2p", + "col78": "xe5tu", + "col79": "i8jj5", + "col80": "nxs1i", + "col81": "y4zx4", + "col82": "syfpo", + "col83": "bib4k", + "col84": "zh6cz", + "col85": "79j37", + "col86": "tb1pc", + "col87": "528co", + "col88": "c0z23", + "col89": "5dsya", + "col90": "st0xq", + "col91": "48a4e", + "col92": "6vf1f", + "col93": "wrewf", + "col94": "5cpno", + "col95": "mijr4", + "col96": "p0edw", + "col97": "ork5w" + }, + { + "name": "Lancaster Patel", + "gender": "male", + "company": "Krog", + "col0": "rq0hz", + "col1": "0bbm4", + "col2": "06cio", + "col3": "anbe5", + "col4": "9hxj8", + "col5": "7itrm", + "col6": "vaht7", + "col7": "bnyqt", + "col8": "guzqt", + "col9": "d1zt1", + "col10": "s43lt", + "col11": "pwd1j", + "col12": "7szhk", + "col13": "g8m71", + "col14": "zdwx0", + "col15": "ients", + "col16": "96saa", + "col17": "sx1cd", + "col18": "5zovy", + "col19": "l7d0k", + "col20": "l7xsh", + "col21": "mo32a", + "col22": "wujcd", + "col23": "f32e3", + "col24": "37m4r", + "col25": "2puts", + "col26": "8690i", + "col27": "s3m3w", + "col28": "eovt4", + "col29": "ex93c", + "col30": "6lreg", + "col31": "zvive", + "col32": "nqwa3", + "col33": "fd6cc", + "col34": "1zoni", + "col35": "krc8l", + "col36": "m84vg", + "col37": "3uugg", + "col38": "vz57m", + "col39": "op5rx", + "col40": "6hfx0", + "col41": "fesnk", + "col42": "86wl6", + "col43": "it2cs", + "col44": "b22vi", + "col45": "9rldq", + "col46": "u395s", + "col47": "rgl8a", + "col48": "zbq5z", + "col49": "ncs5h", + "col50": "1f2kq", + "col51": "tpkf8", + "col52": "13y3v", + "col53": "1aps0", + "col54": "nrq3k", + "col55": "0brnw", + "col56": "1e71h", + "col57": "131l0", + "col58": "26jb6", + "col59": "b81qp", + "col60": "2gto9", + "col61": "dmr6v", + "col62": "2866p", + "col63": "mcu2z", + "col64": "5rho8", + "col65": "dtjpu", + "col66": "njxjy", + "col67": "dzzea", + "col68": "x6qc2", + "col69": "syjp3", + "col70": "6zych", + "col71": "gprye", + "col72": "naw2j", + "col73": "ukt7a", + "col74": "6myhg", + "col75": "ffyao", + "col76": "103g1", + "col77": "mhif9", + "col78": "vstdz", + "col79": "jbzs4", + "col80": "p3his", + "col81": "89g0n", + "col82": "cu717", + "col83": "ftml5", + "col84": "bp2tj", + "col85": "q9cco", + "col86": "4y9xx", + "col87": "onxck", + "col88": "l8kcn", + "col89": "vqsgs", + "col90": "j2edd", + "col91": "axg5o", + "col92": "bxm9i", + "col93": "dk6zz", + "col94": "bw8b6", + "col95": "0oeqh", + "col96": "6nn4w", + "col97": "5ybv0" + }, + { + "name": "Rosa Dyer", + "gender": "female", + "company": "Netility", + "col0": "1dofa", + "col1": "jmx8o", + "col2": "a0ugs", + "col3": "z1qnh", + "col4": "71jdv", + "col5": "3gol8", + "col6": "ju4so", + "col7": "najo8", + "col8": "eug8b", + "col9": "8lk6x", + "col10": "c2zkk", + "col11": "eokft", + "col12": "tuqn7", + "col13": "j7zw7", + "col14": "s0334", + "col15": "di4xq", + "col16": "yw54x", + "col17": "yt4cu", + "col18": "penso", + "col19": "3drcq", + "col20": "keipt", + "col21": "u2657", + "col22": "fudh1", + "col23": "r0wwq", + "col24": "z0oyg", + "col25": "uoyid", + "col26": "tt83b", + "col27": "1rm7b", + "col28": "ndwr6", + "col29": "95hdj", + "col30": "sda0a", + "col31": "ura1m", + "col32": "ed52x", + "col33": "6pljd", + "col34": "dxikz", + "col35": "kd90e", + "col36": "cmmem", + "col37": "3blb2", + "col38": "b4pvq", + "col39": "3fss5", + "col40": "1a4q1", + "col41": "3rdx0", + "col42": "f4283", + "col43": "d22yz", + "col44": "ndqej", + "col45": "jx8ot", + "col46": "2bqli", + "col47": "pvdvj", + "col48": "q6n8b", + "col49": "492yz", + "col50": "fsrve", + "col51": "h7nu2", + "col52": "9d4he", + "col53": "29z4w", + "col54": "dnf7z", + "col55": "6wnak", + "col56": "eqr42", + "col57": "bjaq2", + "col58": "btxb2", + "col59": "dpg38", + "col60": "cv5ix", + "col61": "a7bao", + "col62": "q27bg", + "col63": "rufd9", + "col64": "w5zns", + "col65": "9wo45", + "col66": "yk4gj", + "col67": "jxdpq", + "col68": "173fq", + "col69": "qhet9", + "col70": "luzck", + "col71": "nwf8c", + "col72": "1gf4h", + "col73": "idtfs", + "col74": "rpl71", + "col75": "isu4h", + "col76": "wir9b", + "col77": "p4n6h", + "col78": "i4h9e", + "col79": "dekk5", + "col80": "bxzop", + "col81": "bjtzm", + "col82": "gngqu", + "col83": "or0zz", + "col84": "yugxw", + "col85": "cqra0", + "col86": "h88hr", + "col87": "e43wo", + "col88": "udz1e", + "col89": "9mq0k", + "col90": "hlcwx", + "col91": "371so", + "col92": "rxgvu", + "col93": "108d5", + "col94": "j7mph", + "col95": "3cts9", + "col96": "7dlxp", + "col97": "xljna" + }, + { + "name": "Christine Compton", + "gender": "female", + "company": "Bleeko", + "col0": "vcw9n", + "col1": "6zepv", + "col2": "5w8o7", + "col3": "u0w23", + "col4": "8zrkr", + "col5": "at1zr", + "col6": "1uv3f", + "col7": "ptul0", + "col8": "95lz1", + "col9": "9qwgg", + "col10": "koawr", + "col11": "bj5ev", + "col12": "f7xr2", + "col13": "cn69q", + "col14": "7hj87", + "col15": "6ryw9", + "col16": "52vz1", + "col17": "4lbeu", + "col18": "8n1gz", + "col19": "61s8h", + "col20": "pi3mj", + "col21": "ajdvj", + "col22": "p108u", + "col23": "q5pq9", + "col24": "aaaf0", + "col25": "8cxe5", + "col26": "nvtt6", + "col27": "s37ub", + "col28": "vt4x1", + "col29": "ewtck", + "col30": "j3hr8", + "col31": "vpyq8", + "col32": "7y1fb", + "col33": "bffrc", + "col34": "u2yj4", + "col35": "7xybs", + "col36": "6tjp4", + "col37": "b785g", + "col38": "o7t0l", + "col39": "mooib", + "col40": "ftxa3", + "col41": "ninf1", + "col42": "2kyp8", + "col43": "q2b66", + "col44": "8xfh5", + "col45": "aqybw", + "col46": "mv6rl", + "col47": "z36q6", + "col48": "vrpyy", + "col49": "6mhji", + "col50": "od26p", + "col51": "yydff", + "col52": "uzvki", + "col53": "fodek", + "col54": "5q4e8", + "col55": "br8ym", + "col56": "jzdz1", + "col57": "aoh71", + "col58": "ymbhv", + "col59": "8abea", + "col60": "52pnv", + "col61": "f59am", + "col62": "tnbyg", + "col63": "2lvmw", + "col64": "mdfbm", + "col65": "1flv5", + "col66": "hh0d9", + "col67": "h3hnz", + "col68": "px9jb", + "col69": "ee3t4", + "col70": "vps3s", + "col71": "tbb3j", + "col72": "ltlen", + "col73": "61url", + "col74": "mf9hi", + "col75": "xdy5s", + "col76": "uky8f", + "col77": "uapi6", + "col78": "bhxcu", + "col79": "u5jlh", + "col80": "jd7rb", + "col81": "qkqg8", + "col82": "16fcs", + "col83": "b2183", + "col84": "d8wos", + "col85": "o7zx7", + "col86": "4q4ur", + "col87": "hod48", + "col88": "80x1q", + "col89": "mz077", + "col90": "7irx5", + "col91": "2fbzi", + "col92": "fry0j", + "col93": "yneuz", + "col94": "e8zxa", + "col95": "5gbee", + "col96": "d87j6", + "col97": "188ls" + }, + { + "name": "Milagros Finch", + "gender": "female", + "company": "Handshake", + "col0": "jw4x8", + "col1": "ml3rt", + "col2": "ufjxx", + "col3": "cyucs", + "col4": "ew1k8", + "col5": "ne5vc", + "col6": "ua5jt", + "col7": "gft29", + "col8": "sdojr", + "col9": "6mxja", + "col10": "ur71d", + "col11": "qqm46", + "col12": "52cas", + "col13": "tnfnp", + "col14": "t1i2v", + "col15": "i3fvj", + "col16": "jznps", + "col17": "wfdic", + "col18": "3j3a2", + "col19": "zwkvj", + "col20": "jwijg", + "col21": "wxm4f", + "col22": "6858z", + "col23": "0y7cb", + "col24": "xbjjv", + "col25": "nzzpi", + "col26": "d2kbo", + "col27": "zpfbq", + "col28": "hei3i", + "col29": "3h3nf", + "col30": "zy7np", + "col31": "jzt4w", + "col32": "c7smo", + "col33": "yz0p2", + "col34": "ny580", + "col35": "bvm4j", + "col36": "xyzhn", + "col37": "86kze", + "col38": "zuncl", + "col39": "m23c5", + "col40": "93560", + "col41": "0klb9", + "col42": "988rj", + "col43": "5ppmn", + "col44": "k6quk", + "col45": "9wphp", + "col46": "4e03z", + "col47": "z189x", + "col48": "jy1qt", + "col49": "r08e4", + "col50": "bcpg2", + "col51": "7am41", + "col52": "15sbu", + "col53": "q1h8j", + "col54": "81jpf", + "col55": "j4qdp", + "col56": "39ukg", + "col57": "15qiu", + "col58": "krohp", + "col59": "cmric", + "col60": "j9h4b", + "col61": "hijc6", + "col62": "x2xl0", + "col63": "apigz", + "col64": "bu0w7", + "col65": "u68vs", + "col66": "ib25h", + "col67": "je0k4", + "col68": "xsoaf", + "col69": "jshl7", + "col70": "5ojtj", + "col71": "lyu1a", + "col72": "vfx30", + "col73": "qmss8", + "col74": "tjz8k", + "col75": "j0g7g", + "col76": "wzjjp", + "col77": "2m0zq", + "col78": "85iah", + "col79": "f1ayi", + "col80": "pk1x6", + "col81": "tr4ll", + "col82": "nvf5g", + "col83": "5rutr", + "col84": "ex77w", + "col85": "4zhmg", + "col86": "nfw5k", + "col87": "seex1", + "col88": "cgcqc", + "col89": "hl216", + "col90": "ch37p", + "col91": "a1f0y", + "col92": "q3vf0", + "col93": "ehpf4", + "col94": "u5epz", + "col95": "jfhka", + "col96": "wa5sm", + "col97": "oyi6x" + }, + { + "name": "Ericka Alvarado", + "gender": "female", + "company": "Lyrichord", + "col0": "whvzg", + "col1": "9nr7l", + "col2": "f70f7", + "col3": "5uctf", + "col4": "9pvmz", + "col5": "ec8ji", + "col6": "68rtj", + "col7": "nybns", + "col8": "w8tqv", + "col9": "wof1h", + "col10": "tomt7", + "col11": "620f3", + "col12": "hv166", + "col13": "7341q", + "col14": "ep9f0", + "col15": "1ch3f", + "col16": "grd1y", + "col17": "jbmcc", + "col18": "ec4no", + "col19": "kp0tj", + "col20": "t816h", + "col21": "54bhg", + "col22": "10iah", + "col23": "ofqta", + "col24": "mzfh1", + "col25": "1vb73", + "col26": "8yi2a", + "col27": "g2nup", + "col28": "oyhrv", + "col29": "2vtqq", + "col30": "wimq8", + "col31": "tybz7", + "col32": "2i31r", + "col33": "88vje", + "col34": "fzpe5", + "col35": "xma2s", + "col36": "o7kag", + "col37": "bgqny", + "col38": "pnfyu", + "col39": "kkqjz", + "col40": "z5evr", + "col41": "0u684", + "col42": "4omv1", + "col43": "u9756", + "col44": "7gbpk", + "col45": "manqc", + "col46": "z04tz", + "col47": "5c7b4", + "col48": "955uy", + "col49": "482kj", + "col50": "j1uu1", + "col51": "2o8m5", + "col52": "zxr27", + "col53": "zvynt", + "col54": "bnqem", + "col55": "i8jmk", + "col56": "wxouk", + "col57": "9wuzw", + "col58": "on3hb", + "col59": "agc3a", + "col60": "thv85", + "col61": "21c39", + "col62": "c9dg3", + "col63": "9zxsz", + "col64": "vqcd8", + "col65": "dm4qb", + "col66": "o34ly", + "col67": "9iztr", + "col68": "vqiwk", + "col69": "3cko6", + "col70": "0xd5i", + "col71": "ue1rl", + "col72": "2kqbd", + "col73": "sxys4", + "col74": "lc0c7", + "col75": "7ylqm", + "col76": "gn5gi", + "col77": "i1wiw", + "col78": "c6hcu", + "col79": "1if78", + "col80": "2hk1j", + "col81": "otsv8", + "col82": "8praa", + "col83": "qdn3k", + "col84": "9qs41", + "col85": "lbqhq", + "col86": "2pd1s", + "col87": "rp83o", + "col88": "m5bz9", + "col89": "ff9u8", + "col90": "ljcqi", + "col91": "6qwsr", + "col92": "r1fx4", + "col93": "i0ap0", + "col94": "1k4aj", + "col95": "6q7v4", + "col96": "hlpzt", + "col97": "fm0jq" + }, + { + "name": "Sylvia Sosa", + "gender": "female", + "company": "Circum", + "col0": "i3cgc", + "col1": "16t27", + "col2": "dip6n", + "col3": "w5f0p", + "col4": "ss6yy", + "col5": "jlnm4", + "col6": "fq4dt", + "col7": "fz38k", + "col8": "kxmep", + "col9": "wj7qk", + "col10": "4l5yq", + "col11": "s2h38", + "col12": "2hlf0", + "col13": "qch3m", + "col14": "k9acv", + "col15": "tkrdc", + "col16": "cpb0j", + "col17": "vhefk", + "col18": "lqqna", + "col19": "istdw", + "col20": "pu4pn", + "col21": "uhb2z", + "col22": "oshfv", + "col23": "rzyib", + "col24": "gsiqh", + "col25": "ke5l0", + "col26": "ulz89", + "col27": "dnf4b", + "col28": "et32s", + "col29": "4u8g1", + "col30": "he45f", + "col31": "mnsym", + "col32": "ydv9s", + "col33": "mymki", + "col34": "z4vys", + "col35": "f3wdf", + "col36": "iivd6", + "col37": "rlbvw", + "col38": "fq2a4", + "col39": "lkx6l", + "col40": "q8n2j", + "col41": "dvoef", + "col42": "5q63a", + "col43": "5da3m", + "col44": "d1v1x", + "col45": "qn8wg", + "col46": "vrili", + "col47": "609ev", + "col48": "7itc7", + "col49": "bvryx", + "col50": "u5xpk", + "col51": "6qjjj", + "col52": "b7919", + "col53": "t7l4l", + "col54": "567la", + "col55": "nlv2d", + "col56": "2c1e3", + "col57": "f11uc", + "col58": "rep44", + "col59": "xmhf6", + "col60": "zoz1c", + "col61": "arznc", + "col62": "uq0ce", + "col63": "wm418", + "col64": "of50d", + "col65": "3lx8q", + "col66": "y2r0s", + "col67": "f2j75", + "col68": "ahyl1", + "col69": "9dbrl", + "col70": "16fdo", + "col71": "it0mu", + "col72": "rjcl0", + "col73": "zynqy", + "col74": "8y4e3", + "col75": "jvt35", + "col76": "vl8fi", + "col77": "63wxn", + "col78": "sfxj2", + "col79": "6ydc3", + "col80": "d33rl", + "col81": "o09m0", + "col82": "reqwt", + "col83": "f6o5a", + "col84": "l0opn", + "col85": "e6r3o", + "col86": "qxarq", + "col87": "y9p3s", + "col88": "6r0od", + "col89": "gb0y1", + "col90": "s5r45", + "col91": "tf87f", + "col92": "ztcej", + "col93": "buqjc", + "col94": "sho92", + "col95": "lzepk", + "col96": "9wxq3", + "col97": "d6vpx" + }, + { + "name": "Humphrey Curtis", + "gender": "male", + "company": "Corepan", + "col0": "lh8ab", + "col1": "222dk", + "col2": "5hr51", + "col3": "mkrww", + "col4": "kpvlp", + "col5": "05rfa", + "col6": "93fql", + "col7": "w0hjc", + "col8": "zmhct", + "col9": "i4ppb", + "col10": "q9v5s", + "col11": "d7p6u", + "col12": "s63xa", + "col13": "qq964", + "col14": "3nz5y", + "col15": "nqbdi", + "col16": "fu9r8", + "col17": "ti792", + "col18": "f4ex4", + "col19": "3cjqg", + "col20": "eq8ft", + "col21": "z1ywx", + "col22": "vpmm9", + "col23": "6p4im", + "col24": "bfios", + "col25": "5ewmb", + "col26": "h99ko", + "col27": "z1qrh", + "col28": "u035e", + "col29": "rjg8i", + "col30": "oss9q", + "col31": "2rgwy", + "col32": "mp33g", + "col33": "w8s10", + "col34": "x73pv", + "col35": "w7qiy", + "col36": "kobtk", + "col37": "hsn4p", + "col38": "9p6nq", + "col39": "sv3ad", + "col40": "wycal", + "col41": "52941", + "col42": "ulzsk", + "col43": "wtu7q", + "col44": "k3eqv", + "col45": "i4h0h", + "col46": "r23fe", + "col47": "uxlku", + "col48": "w353s", + "col49": "ns0sg", + "col50": "x1ij6", + "col51": "27t0t", + "col52": "jk82q", + "col53": "pojx6", + "col54": "y1bo9", + "col55": "8h2oj", + "col56": "eevxc", + "col57": "ixxlp", + "col58": "83giy", + "col59": "c59sk", + "col60": "6u1n0", + "col61": "svp0m", + "col62": "u87f4", + "col63": "opn7u", + "col64": "1k7mw", + "col65": "4cnsi", + "col66": "86ml9", + "col67": "bo3pb", + "col68": "yn5mg", + "col69": "aoszb", + "col70": "df8fl", + "col71": "jmgda", + "col72": "10vht", + "col73": "o51hl", + "col74": "2nev6", + "col75": "vum17", + "col76": "9nvax", + "col77": "qoytp", + "col78": "gn738", + "col79": "9uz2c", + "col80": "f2fbp", + "col81": "engps", + "col82": "q563p", + "col83": "9biwm", + "col84": "umfea", + "col85": "fe3v9", + "col86": "7ogco", + "col87": "b5oac", + "col88": "kyyv1", + "col89": "jpp26", + "col90": "6pyz6", + "col91": "sncys", + "col92": "w9lm1", + "col93": "eedy5", + "col94": "e36fd", + "col95": "38rwr", + "col96": "fa9l9", + "col97": "f68qz" + } +] \ No newline at end of file diff --git a/data/100_female.json b/data/100_female.json new file mode 100644 index 000000000..9b53ac394 --- /dev/null +++ b/data/100_female.json @@ -0,0 +1,77 @@ +[ + { + "name": "Ethel Price", + "gender": "female", + "company": "Enersol" + }, + { + "name": "Claudine Neal", + "gender": "female", + "company": "Sealoud" + }, + { + "name": "Beryl Rice", + "gender": "female", + "company": "Velity" + }, + { + "name": "Georgina Schultz", + "gender": "female", + "company": "Suretech" + }, + { + "name": "Valarie Atkinson", + "gender": "female", + "company": "Hopeli" + }, + { + "name": "Lynda Mendoza", + "gender": "female", + "company": "Dogspa" + }, + { + "name": "Sarah Massey", + "gender": "female", + "company": "Bisba" + }, + { + "name": "Nellie Whitfield", + "gender": "female", + "company": "Exospace" + }, + { + "name": "Lelia Gates", + "gender": "female", + "company": "Proxsoft" + }, + { + "name": "Letitia Vasquez", + "gender": "female", + "company": "Slumberia" + }, + { + "name": "Blanche Conley", + "gender": "female", + "company": "Imkan" + }, + { + "name": "Kelli Leon", + "gender": "female", + "company": "Verbus" + }, + { + "name": "Freda Mason", + "gender": "female", + "company": "Accidency" + }, + { + "name": "Yvonne Parsons", + "gender": "female", + "company": "Zolar" + }, + { + "name": "Jocelyn Sawyer", + "gender": "female", + "company": "Fortean" + } +] \ No newline at end of file diff --git a/data/100_male.json b/data/100_male.json new file mode 100644 index 000000000..3d46eb020 --- /dev/null +++ b/data/100_male.json @@ -0,0 +1,97 @@ +[ + { + "name": "Wilder Gonzales", + "gender": "male", + "company": "Geekko" + }, + { + "name": "Carroll Buchanan", + "gender": "male", + "company": "Ecosys" + }, + { + "name": "Schroeder Mathews", + "gender": "male", + "company": "Polarium" + }, + { + "name": "Robles Boyle", + "gender": "male", + "company": "Comtract" + }, + { + "name": "Evans Hickman", + "gender": "male", + "company": "Parleynet" + }, + { + "name": "Dawson Barber", + "gender": "male", + "company": "Dymi" + }, + { + "name": "Bruce Strong", + "gender": "male", + "company": "Xyqag" + }, + { + "name": "Jackson Macias", + "gender": "male", + "company": "Aquamate" + }, + { + "name": "Pena Pena", + "gender": "male", + "company": "Quarx" + }, + { + "name": "Trevino Moreno", + "gender": "male", + "company": "Conjurica" + }, + { + "name": "Barr Page", + "gender": "male", + "company": "Apex" + }, + { + "name": "Kirkland Merrill", + "gender": "male", + "company": "Utara" + }, + { + "name": "Atkins Dunlap", + "gender": "male", + "company": "Comveyor" + }, + { + "name": "Everett Foreman", + "gender": "male", + "company": "Maineland" + }, + { + "name": "Gould Randolph", + "gender": "male", + "company": "Intergeek" + }, + { + "name": "Tucker Maxwell", + "gender": "male", + "company": "Lumbrex" + }, + { + "name": "Woods Key", + "gender": "male", + "company": "Bedder" + }, + { + "name": "Stephens Reilly", + "gender": "male", + "company": "Acusage" + }, + { + "name": "Mcfarland Sparks", + "gender": "male", + "company": "Comvey" + } +] \ No newline at end of file diff --git a/data/500.json b/data/500.json new file mode 100644 index 000000000..e97e128e7 --- /dev/null +++ b/data/500.json @@ -0,0 +1,3002 @@ +[ + { + "firstName": "Roseann", + "lastName": "Parker", + "company": "Zaggles", + "employed": false + }, + { + "firstName": "Ford", + "lastName": "Knox", + "company": "Coriander", + "employed": true + }, + { + "firstName": "Graves", + "lastName": "Randolph", + "company": "Supremia", + "employed": false + }, + { + "firstName": "Sears", + "lastName": "Jackson", + "company": "Netagy", + "employed": false + }, + { + "firstName": "Bernard", + "lastName": "Barrett", + "company": "Cubix", + "employed": false + }, + { + "firstName": "Tami", + "lastName": "Snider", + "company": "Lunchpod", + "employed": true + }, + { + "firstName": "Holt", + "lastName": "Murphy", + "company": "Eventage", + "employed": false + }, + { + "firstName": "Elizabeth", + "lastName": "Rice", + "company": "Deminimum", + "employed": true + }, + { + "firstName": "Herring", + "lastName": "Mccray", + "company": "Waretel", + "employed": false + }, + { + "firstName": "Wynn", + "lastName": "Randall", + "company": "Animalia", + "employed": false + }, + { + "firstName": "Briana", + "lastName": "Rivas", + "company": "Dancerity", + "employed": false + }, + { + "firstName": "Jerry", + "lastName": "Carey", + "company": "Silodyne", + "employed": true + }, + { + "firstName": "Christa", + "lastName": "Buckner", + "company": "Bugsall", + "employed": true + }, + { + "firstName": "Helene", + "lastName": "Kinney", + "company": "Xylar", + "employed": false + }, + { + "firstName": "Malone", + "lastName": "Jennings", + "company": "Bunga", + "employed": false + }, + { + "firstName": "Erica", + "lastName": "Mcguire", + "company": "Comverges", + "employed": true + }, + { + "firstName": "Santana", + "lastName": "Lynn", + "company": "Zboo", + "employed": true + }, + { + "firstName": "Mcclain", + "lastName": "Gay", + "company": "Chillium", + "employed": true + }, + { + "firstName": "Castaneda", + "lastName": "Bartlett", + "company": "Pathways", + "employed": false + }, + { + "firstName": "Singleton", + "lastName": "Stephenson", + "company": "Polaria", + "employed": false + }, + { + "firstName": "Alana", + "lastName": "Greene", + "company": "Tubesys", + "employed": false + }, + { + "firstName": "Angeline", + "lastName": "Riley", + "company": "Ecosys", + "employed": false + }, + { + "firstName": "Kerri", + "lastName": "Spence", + "company": "Podunk", + "employed": true + }, + { + "firstName": "Cherie", + "lastName": "Burgess", + "company": "Zidant", + "employed": true + }, + { + "firstName": "Atkins", + "lastName": "Meadows", + "company": "Accupharm", + "employed": false + }, + { + "firstName": "Deanne", + "lastName": "Le", + "company": "Emergent", + "employed": false + }, + { + "firstName": "Martinez", + "lastName": "Byrd", + "company": "Tetratrex", + "employed": true + }, + { + "firstName": "Evans", + "lastName": "Hoffman", + "company": "Plasto", + "employed": true + }, + { + "firstName": "Rebekah", + "lastName": "Guy", + "company": "Malathion", + "employed": true + }, + { + "firstName": "Elvia", + "lastName": "Elliott", + "company": "Boilcat", + "employed": false + }, + { + "firstName": "Padilla", + "lastName": "Cooley", + "company": "Comvex", + "employed": false + }, + { + "firstName": "Solomon", + "lastName": "Mclean", + "company": "Cosmosis", + "employed": true + }, + { + "firstName": "Bond", + "lastName": "Andrews", + "company": "Quotezart", + "employed": false + }, + { + "firstName": "Shelley", + "lastName": "Slater", + "company": "Digigene", + "employed": false + }, + { + "firstName": "Mcintosh", + "lastName": "Garrison", + "company": "Pheast", + "employed": true + }, + { + "firstName": "Arlene", + "lastName": "Jefferson", + "company": "Sultraxin", + "employed": false + }, + { + "firstName": "Cassandra", + "lastName": "Taylor", + "company": "Eclipsent", + "employed": false + }, + { + "firstName": "Soto", + "lastName": "Vance", + "company": "Imaginart", + "employed": false + }, + { + "firstName": "Ruiz", + "lastName": "Stark", + "company": "Helixo", + "employed": true + }, + { + "firstName": "Sofia", + "lastName": "Glass", + "company": "Otherside", + "employed": true + }, + { + "firstName": "Robles", + "lastName": "Henderson", + "company": "Recritube", + "employed": false + }, + { + "firstName": "Leta", + "lastName": "Aguirre", + "company": "Wazzu", + "employed": false + }, + { + "firstName": "Blackburn", + "lastName": "Kennedy", + "company": "Overplex", + "employed": false + }, + { + "firstName": "Tamra", + "lastName": "Solis", + "company": "Waab", + "employed": true + }, + { + "firstName": "Trevino", + "lastName": "Morrison", + "company": "Isotronic", + "employed": true + }, + { + "firstName": "Delia", + "lastName": "Mason", + "company": "Cujo", + "employed": false + }, + { + "firstName": "Blake", + "lastName": "Woods", + "company": "Krag", + "employed": true + }, + { + "firstName": "Mayo", + "lastName": "Levine", + "company": "Koffee", + "employed": false + }, + { + "firstName": "Cecelia", + "lastName": "Rivers", + "company": "Combogen", + "employed": false + }, + { + "firstName": "Alissa", + "lastName": "Short", + "company": "Corecom", + "employed": false + }, + { + "firstName": "Adele", + "lastName": "Chandler", + "company": "Entality", + "employed": false + }, + { + "firstName": "Rhonda", + "lastName": "Sanchez", + "company": "Zentility", + "employed": false + }, + { + "firstName": "Geneva", + "lastName": "Barnett", + "company": "Recognia", + "employed": true + }, + { + "firstName": "Brandi", + "lastName": "Padilla", + "company": "Pearlessa", + "employed": false + }, + { + "firstName": "Kidd", + "lastName": "Potts", + "company": "Equitax", + "employed": false + }, + { + "firstName": "Ball", + "lastName": "Petty", + "company": "Extragene", + "employed": false + }, + { + "firstName": "Mayer", + "lastName": "Stokes", + "company": "Kongene", + "employed": true + }, + { + "firstName": "Cherry", + "lastName": "Church", + "company": "Nixelt", + "employed": false + }, + { + "firstName": "Cantrell", + "lastName": "Wilkins", + "company": "Accufarm", + "employed": true + }, + { + "firstName": "Glover", + "lastName": "Barber", + "company": "Euron", + "employed": false + }, + { + "firstName": "Dorothea", + "lastName": "Gould", + "company": "Tropolis", + "employed": false + }, + { + "firstName": "Glenn", + "lastName": "Kemp", + "company": "Proflex", + "employed": true + }, + { + "firstName": "Noble", + "lastName": "Glenn", + "company": "Comtrail", + "employed": true + }, + { + "firstName": "Moon", + "lastName": "Santana", + "company": "Zillacom", + "employed": true + }, + { + "firstName": "Blanche", + "lastName": "Benton", + "company": "Insuron", + "employed": true + }, + { + "firstName": "Kathy", + "lastName": "Fitzgerald", + "company": "Opticall", + "employed": false + }, + { + "firstName": "Duran", + "lastName": "Hale", + "company": "Zenco", + "employed": false + }, + { + "firstName": "Hubbard", + "lastName": "Sexton", + "company": "Enerforce", + "employed": false + }, + { + "firstName": "Manning", + "lastName": "Baird", + "company": "Translink", + "employed": true + }, + { + "firstName": "Reilly", + "lastName": "Bridges", + "company": "Filodyne", + "employed": true + }, + { + "firstName": "Keith", + "lastName": "Pena", + "company": "Xelegyl", + "employed": false + }, + { + "firstName": "Jodie", + "lastName": "Holloway", + "company": "Enormo", + "employed": true + }, + { + "firstName": "Jami", + "lastName": "Wooten", + "company": "Netility", + "employed": false + }, + { + "firstName": "Liz", + "lastName": "Sykes", + "company": "Hinway", + "employed": false + }, + { + "firstName": "Raquel", + "lastName": "Gibbs", + "company": "Zentury", + "employed": true + }, + { + "firstName": "Crane", + "lastName": "Phillips", + "company": "Mazuda", + "employed": true + }, + { + "firstName": "Strickland", + "lastName": "Kidd", + "company": "Ovolo", + "employed": true + }, + { + "firstName": "Lula", + "lastName": "Sanford", + "company": "Ecstasia", + "employed": true + }, + { + "firstName": "Rodriquez", + "lastName": "Curry", + "company": "Neurocell", + "employed": false + }, + { + "firstName": "Andrea", + "lastName": "Sweet", + "company": "Namegen", + "employed": true + }, + { + "firstName": "Lana", + "lastName": "Robbins", + "company": "Dyno", + "employed": true + }, + { + "firstName": "Tran", + "lastName": "Lowery", + "company": "Farmex", + "employed": true + }, + { + "firstName": "Annmarie", + "lastName": "Pitts", + "company": "Goko", + "employed": false + }, + { + "firstName": "Bass", + "lastName": "Mendez", + "company": "Rockabye", + "employed": false + }, + { + "firstName": "Irma", + "lastName": "Avery", + "company": "Primordia", + "employed": true + }, + { + "firstName": "Evangelina", + "lastName": "Valentine", + "company": "Dognosis", + "employed": true + }, + { + "firstName": "Cruz", + "lastName": "Cochran", + "company": "Opticon", + "employed": true + }, + { + "firstName": "Bowers", + "lastName": "Talley", + "company": "Canopoly", + "employed": true + }, + { + "firstName": "Rosemarie", + "lastName": "Grant", + "company": "Lexicondo", + "employed": true + }, + { + "firstName": "Waller", + "lastName": "Lee", + "company": "Scentric", + "employed": true + }, + { + "firstName": "Billie", + "lastName": "Hodge", + "company": "Talkola", + "employed": true + }, + { + "firstName": "Stanley", + "lastName": "Gaines", + "company": "Slumberia", + "employed": true + }, + { + "firstName": "Petra", + "lastName": "Mejia", + "company": "Infotrips", + "employed": true + }, + { + "firstName": "Wilkerson", + "lastName": "Bradley", + "company": "Apextri", + "employed": true + }, + { + "firstName": "Brenda", + "lastName": "Medina", + "company": "Nurplex", + "employed": true + }, + { + "firstName": "Burt", + "lastName": "Hensley", + "company": "Utara", + "employed": true + }, + { + "firstName": "Annabelle", + "lastName": "Wright", + "company": "Zinca", + "employed": true + }, + { + "firstName": "Obrien", + "lastName": "Chapman", + "company": "Xoggle", + "employed": true + }, + { + "firstName": "Cline", + "lastName": "Dickerson", + "company": "Printspan", + "employed": true + }, + { + "firstName": "Hilary", + "lastName": "Justice", + "company": "Zaggle", + "employed": true + }, + { + "firstName": "Emilia", + "lastName": "Bowen", + "company": "Kage", + "employed": true + }, + { + "firstName": "Bethany", + "lastName": "Frost", + "company": "Ovium", + "employed": true + }, + { + "firstName": "Sarah", + "lastName": "Marshall", + "company": "Steelfab", + "employed": true + }, + { + "firstName": "Battle", + "lastName": "Vega", + "company": "Geekol", + "employed": true + }, + { + "firstName": "Shelly", + "lastName": "Mcgowan", + "company": "Illumity", + "employed": true + }, + { + "firstName": "Ortega", + "lastName": "Pierce", + "company": "Ontagene", + "employed": false + }, + { + "firstName": "Palmer", + "lastName": "Stafford", + "company": "Bitendrex", + "employed": false + }, + { + "firstName": "Parker", + "lastName": "Marsh", + "company": "Insuresys", + "employed": false + }, + { + "firstName": "Rowena", + "lastName": "English", + "company": "Parleynet", + "employed": true + }, + { + "firstName": "Liza", + "lastName": "Lyons", + "company": "Navir", + "employed": true + }, + { + "firstName": "Rebecca", + "lastName": "Tyler", + "company": "Zilphur", + "employed": true + }, + { + "firstName": "Stefanie", + "lastName": "Cruz", + "company": "Xanide", + "employed": true + }, + { + "firstName": "Chaney", + "lastName": "Arnold", + "company": "Boink", + "employed": false + }, + { + "firstName": "Whitney", + "lastName": "Herman", + "company": "Cofine", + "employed": false + }, + { + "firstName": "Leonard", + "lastName": "Christensen", + "company": "Capscreen", + "employed": true + }, + { + "firstName": "Crawford", + "lastName": "Erickson", + "company": "Securia", + "employed": true + }, + { + "firstName": "Belinda", + "lastName": "Mccormick", + "company": "Zerology", + "employed": false + }, + { + "firstName": "Toni", + "lastName": "Pratt", + "company": "Voratak", + "employed": true + }, + { + "firstName": "Jody", + "lastName": "Serrano", + "company": "Geekology", + "employed": true + }, + { + "firstName": "West", + "lastName": "Mcintosh", + "company": "Snorus", + "employed": false + }, + { + "firstName": "Angelita", + "lastName": "Hooper", + "company": "Architax", + "employed": false + }, + { + "firstName": "Sheena", + "lastName": "Newton", + "company": "Senmei", + "employed": true + }, + { + "firstName": "Harrell", + "lastName": "Lara", + "company": "Zomboid", + "employed": true + }, + { + "firstName": "Oneal", + "lastName": "Melton", + "company": "Visalia", + "employed": false + }, + { + "firstName": "Rowland", + "lastName": "Dunlap", + "company": "Globoil", + "employed": true + }, + { + "firstName": "Simon", + "lastName": "Park", + "company": "Fortean", + "employed": false + }, + { + "firstName": "Claudette", + "lastName": "Coleman", + "company": "Zilch", + "employed": false + }, + { + "firstName": "Carey", + "lastName": "Holmes", + "company": "Aquasseur", + "employed": false + }, + { + "firstName": "Quinn", + "lastName": "Brennan", + "company": "Equitox", + "employed": true + }, + { + "firstName": "Wallace", + "lastName": "Johnson", + "company": "Elpro", + "employed": true + }, + { + "firstName": "Kathryn", + "lastName": "Mays", + "company": "Orbean", + "employed": false + }, + { + "firstName": "York", + "lastName": "Adkins", + "company": "Stockpost", + "employed": true + }, + { + "firstName": "Patrick", + "lastName": "Wilkinson", + "company": "Sunclipse", + "employed": true + }, + { + "firstName": "Kelly", + "lastName": "Dunn", + "company": "Daycore", + "employed": true + }, + { + "firstName": "Latisha", + "lastName": "Deleon", + "company": "Enthaze", + "employed": true + }, + { + "firstName": "Garrison", + "lastName": "Fletcher", + "company": "Qimonk", + "employed": true + }, + { + "firstName": "Tamera", + "lastName": "Ortiz", + "company": "Anarco", + "employed": false + }, + { + "firstName": "Jeanine", + "lastName": "Hyde", + "company": "Freakin", + "employed": false + }, + { + "firstName": "Mccarty", + "lastName": "Cabrera", + "company": "Motovate", + "employed": false + }, + { + "firstName": "Moss", + "lastName": "Decker", + "company": "Maroptic", + "employed": false + }, + { + "firstName": "Greta", + "lastName": "Lindsey", + "company": "Roboid", + "employed": true + }, + { + "firstName": "Nona", + "lastName": "Kelly", + "company": "Vitricomp", + "employed": true + }, + { + "firstName": "Vincent", + "lastName": "Casey", + "company": "Zensure", + "employed": true + }, + { + "firstName": "Amber", + "lastName": "Carver", + "company": "Blanet", + "employed": true + }, + { + "firstName": "Hart", + "lastName": "Mathews", + "company": "Columella", + "employed": true + }, + { + "firstName": "Jeanne", + "lastName": "Cannon", + "company": "Ecratic", + "employed": true + }, + { + "firstName": "Maddox", + "lastName": "Davidson", + "company": "Corepan", + "employed": true + }, + { + "firstName": "Livingston", + "lastName": "Tate", + "company": "Zoxy", + "employed": false + }, + { + "firstName": "Joanna", + "lastName": "Calderon", + "company": "Squish", + "employed": true + }, + { + "firstName": "Hartman", + "lastName": "Powell", + "company": "Suretech", + "employed": true + }, + { + "firstName": "Church", + "lastName": "Williamson", + "company": "Extragen", + "employed": true + }, + { + "firstName": "Kerry", + "lastName": "Gilliam", + "company": "Earthwax", + "employed": false + }, + { + "firstName": "Lara", + "lastName": "Mueller", + "company": "Cytrek", + "employed": true + }, + { + "firstName": "Best", + "lastName": "Singleton", + "company": "Bytrex", + "employed": false + }, + { + "firstName": "Bernice", + "lastName": "Walsh", + "company": "Manglo", + "employed": false + }, + { + "firstName": "Noel", + "lastName": "Watts", + "company": "Digigen", + "employed": true + }, + { + "firstName": "Mathews", + "lastName": "Holden", + "company": "Kaggle", + "employed": false + }, + { + "firstName": "Anastasia", + "lastName": "Combs", + "company": "Quintity", + "employed": false + }, + { + "firstName": "Gray", + "lastName": "Oneil", + "company": "Flumbo", + "employed": false + }, + { + "firstName": "Huffman", + "lastName": "Cain", + "company": "Realmo", + "employed": true + }, + { + "firstName": "Paula", + "lastName": "Bender", + "company": "Rodeomad", + "employed": false + }, + { + "firstName": "Rowe", + "lastName": "Kramer", + "company": "Nimon", + "employed": false + }, + { + "firstName": "Lauren", + "lastName": "Cobb", + "company": "Ronelon", + "employed": true + }, + { + "firstName": "Guy", + "lastName": "Baldwin", + "company": "Electonic", + "employed": true + }, + { + "firstName": "Alisa", + "lastName": "Gonzales", + "company": "Protodyne", + "employed": true + }, + { + "firstName": "Ramos", + "lastName": "Strong", + "company": "Telequiet", + "employed": true + }, + { + "firstName": "Monroe", + "lastName": "Rosario", + "company": "Confrenzy", + "employed": false + }, + { + "firstName": "Kent", + "lastName": "Reilly", + "company": "Xeronk", + "employed": false + }, + { + "firstName": "Mcmillan", + "lastName": "Holland", + "company": "Nexgene", + "employed": false + }, + { + "firstName": "Olga", + "lastName": "Wells", + "company": "Optyk", + "employed": false + }, + { + "firstName": "Chase", + "lastName": "Finley", + "company": "Exodoc", + "employed": true + }, + { + "firstName": "Stafford", + "lastName": "Rodgers", + "company": "Exostream", + "employed": false + }, + { + "firstName": "Joanne", + "lastName": "Clay", + "company": "Elita", + "employed": false + }, + { + "firstName": "Lara", + "lastName": "Morrow", + "company": "Virva", + "employed": false + }, + { + "firstName": "Parks", + "lastName": "Alford", + "company": "Qualitern", + "employed": true + }, + { + "firstName": "Schultz", + "lastName": "Pope", + "company": "Accruex", + "employed": false + }, + { + "firstName": "Vonda", + "lastName": "Huber", + "company": "Dognost", + "employed": true + }, + { + "firstName": "Sims", + "lastName": "Frazier", + "company": "Xurban", + "employed": true + }, + { + "firstName": "Puckett", + "lastName": "Wood", + "company": "Valreda", + "employed": false + }, + { + "firstName": "Katina", + "lastName": "Houston", + "company": "Orboid", + "employed": true + }, + { + "firstName": "Trujillo", + "lastName": "Irwin", + "company": "Bluplanet", + "employed": false + }, + { + "firstName": "Willis", + "lastName": "Cook", + "company": "Zillacon", + "employed": false + }, + { + "firstName": "Combs", + "lastName": "Alexander", + "company": "Yurture", + "employed": false + }, + { + "firstName": "Carver", + "lastName": "Stein", + "company": "Inquala", + "employed": true + }, + { + "firstName": "Hebert", + "lastName": "West", + "company": "Fangold", + "employed": false + }, + { + "firstName": "Park", + "lastName": "House", + "company": "Premiant", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Caldwell", + "company": "Speedbolt", + "employed": true + }, + { + "firstName": "Rice", + "lastName": "Mccoy", + "company": "Bisba", + "employed": true + }, + { + "firstName": "Oliver", + "lastName": "Simmons", + "company": "Eventix", + "employed": true + }, + { + "firstName": "Torres", + "lastName": "Rowe", + "company": "Gushkool", + "employed": true + }, + { + "firstName": "Joyce", + "lastName": "Barker", + "company": "Unq", + "employed": true + }, + { + "firstName": "Guerra", + "lastName": "Walker", + "company": "Quailcom", + "employed": false + }, + { + "firstName": "Leslie", + "lastName": "Lester", + "company": "Artworlds", + "employed": false + }, + { + "firstName": "Althea", + "lastName": "Page", + "company": "Centice", + "employed": false + }, + { + "firstName": "Maggie", + "lastName": "Wade", + "company": "Deepends", + "employed": false + }, + { + "firstName": "Nielsen", + "lastName": "Norman", + "company": "Magmina", + "employed": true + }, + { + "firstName": "Gallagher", + "lastName": "Herring", + "company": "Insurity", + "employed": true + }, + { + "firstName": "Penny", + "lastName": "York", + "company": "Hometown", + "employed": false + }, + { + "firstName": "Jacqueline", + "lastName": "Conrad", + "company": "Digirang", + "employed": true + }, + { + "firstName": "Downs", + "lastName": "Cunningham", + "company": "Steeltab", + "employed": false + }, + { + "firstName": "Coleen", + "lastName": "Boyle", + "company": "Sealoud", + "employed": false + }, + { + "firstName": "Webster", + "lastName": "Thornton", + "company": "Tri@Tribalog", + "employed": false + }, + { + "firstName": "Reynolds", + "lastName": "Bennett", + "company": "Calcu", + "employed": false + }, + { + "firstName": "Moody", + "lastName": "Shepard", + "company": "Candecor", + "employed": false + }, + { + "firstName": "Beulah", + "lastName": "Webb", + "company": "Centregy", + "employed": true + }, + { + "firstName": "Zelma", + "lastName": "Colon", + "company": "Pearlesex", + "employed": true + }, + { + "firstName": "Rachael", + "lastName": "Rios", + "company": "Perkle", + "employed": true + }, + { + "firstName": "Leola", + "lastName": "Peck", + "company": "Conferia", + "employed": false + }, + { + "firstName": "Cooper", + "lastName": "Underwood", + "company": "Miracula", + "employed": true + }, + { + "firstName": "Barbara", + "lastName": "Mcfadden", + "company": "Strezzo", + "employed": true + }, + { + "firstName": "Sullivan", + "lastName": "Guerrero", + "company": "Marketoid", + "employed": true + }, + { + "firstName": "Barr", + "lastName": "Wilder", + "company": "Endipin", + "employed": false + }, + { + "firstName": "Hampton", + "lastName": "Salinas", + "company": "Pushcart", + "employed": false + }, + { + "firstName": "Madelyn", + "lastName": "Sargent", + "company": "Centrexin", + "employed": true + }, + { + "firstName": "Tracey", + "lastName": "Mccarthy", + "company": "Remotion", + "employed": false + }, + { + "firstName": "Kline", + "lastName": "Perkins", + "company": "Norali", + "employed": true + }, + { + "firstName": "Eve", + "lastName": "Hickman", + "company": "Kineticut", + "employed": false + }, + { + "firstName": "Sophie", + "lastName": "Lancaster", + "company": "Konnect", + "employed": false + }, + { + "firstName": "Dominguez", + "lastName": "Gross", + "company": "Anocha", + "employed": false + }, + { + "firstName": "Mullins", + "lastName": "Moss", + "company": "Tropoli", + "employed": true + }, + { + "firstName": "Roslyn", + "lastName": "Schwartz", + "company": "Zyple", + "employed": true + }, + { + "firstName": "Gibson", + "lastName": "Marks", + "company": "Nikuda", + "employed": false + }, + { + "firstName": "Becker", + "lastName": "Rosales", + "company": "Calcula", + "employed": true + }, + { + "firstName": "Fletcher", + "lastName": "Horn", + "company": "Fishland", + "employed": true + }, + { + "firstName": "Cassie", + "lastName": "Rojas", + "company": "Zillactic", + "employed": false + }, + { + "firstName": "Trisha", + "lastName": "Coffey", + "company": "Aeora", + "employed": true + }, + { + "firstName": "Ofelia", + "lastName": "Sims", + "company": "Isologix", + "employed": false + }, + { + "firstName": "Claire", + "lastName": "Rogers", + "company": "Plutorque", + "employed": false + }, + { + "firstName": "Mueller", + "lastName": "Thomas", + "company": "Futuris", + "employed": true + }, + { + "firstName": "Tameka", + "lastName": "Bentley", + "company": "Surelogic", + "employed": true + }, + { + "firstName": "Bridgett", + "lastName": "Valenzuela", + "company": "Techade", + "employed": true + }, + { + "firstName": "Leanna", + "lastName": "Goff", + "company": "Poshome", + "employed": false + }, + { + "firstName": "Harriet", + "lastName": "Bryant", + "company": "Enaut", + "employed": false + }, + { + "firstName": "Marisol", + "lastName": "Mcintyre", + "company": "Insectus", + "employed": true + }, + { + "firstName": "Justine", + "lastName": "Mcdonald", + "company": "Intrawear", + "employed": true + }, + { + "firstName": "Garcia", + "lastName": "Roberts", + "company": "Kiosk", + "employed": false + }, + { + "firstName": "Hatfield", + "lastName": "Winters", + "company": "Medcom", + "employed": false + }, + { + "firstName": "Tia", + "lastName": "Velasquez", + "company": "Oronoko", + "employed": true + }, + { + "firstName": "Guadalupe", + "lastName": "Mercer", + "company": "Vantage", + "employed": false + }, + { + "firstName": "Porter", + "lastName": "Goodman", + "company": "Progenex", + "employed": true + }, + { + "firstName": "Marianne", + "lastName": "Waters", + "company": "Frolix", + "employed": true + }, + { + "firstName": "Boyer", + "lastName": "Morales", + "company": "Toyletry", + "employed": true + }, + { + "firstName": "Elsie", + "lastName": "Maxwell", + "company": "Exospace", + "employed": true + }, + { + "firstName": "Berger", + "lastName": "Blake", + "company": "Applideck", + "employed": false + }, + { + "firstName": "Delaney", + "lastName": "Fischer", + "company": "Buzzmaker", + "employed": true + }, + { + "firstName": "Odessa", + "lastName": "Shaw", + "company": "Combogene", + "employed": false + }, + { + "firstName": "Chandler", + "lastName": "Riddle", + "company": "Geofarm", + "employed": false + }, + { + "firstName": "Glenna", + "lastName": "Castillo", + "company": "Zedalis", + "employed": false + }, + { + "firstName": "Jennings", + "lastName": "Gonzalez", + "company": "Indexia", + "employed": false + }, + { + "firstName": "Leann", + "lastName": "Bond", + "company": "Tingles", + "employed": true + }, + { + "firstName": "Flowers", + "lastName": "Lowe", + "company": "Poochies", + "employed": false + }, + { + "firstName": "Doreen", + "lastName": "Michael", + "company": "Microluxe", + "employed": true + }, + { + "firstName": "Jasmine", + "lastName": "Calhoun", + "company": "Lingoage", + "employed": true + }, + { + "firstName": "Norma", + "lastName": "Aguilar", + "company": "Melbacor", + "employed": true + }, + { + "firstName": "Socorro", + "lastName": "Gates", + "company": "Ramjob", + "employed": true + }, + { + "firstName": "Flora", + "lastName": "Wagner", + "company": "Corpulse", + "employed": false + }, + { + "firstName": "Castillo", + "lastName": "Ward", + "company": "Reversus", + "employed": false + }, + { + "firstName": "Weeks", + "lastName": "Luna", + "company": "Centuria", + "employed": false + }, + { + "firstName": "Bridgette", + "lastName": "Chase", + "company": "Ultrasure", + "employed": false + }, + { + "firstName": "Ochoa", + "lastName": "Gregory", + "company": "Zounds", + "employed": true + }, + { + "firstName": "Rosalind", + "lastName": "Duncan", + "company": "Orbaxter", + "employed": false + }, + { + "firstName": "Queen", + "lastName": "Patton", + "company": "Sensate", + "employed": true + }, + { + "firstName": "Florine", + "lastName": "Mccullough", + "company": "Xumonk", + "employed": false + }, + { + "firstName": "Ramsey", + "lastName": "Saunders", + "company": "Norsup", + "employed": true + }, + { + "firstName": "Kemp", + "lastName": "Case", + "company": "Netur", + "employed": false + }, + { + "firstName": "Copeland", + "lastName": "Joyce", + "company": "Uplinx", + "employed": true + }, + { + "firstName": "Freda", + "lastName": "Cleveland", + "company": "Isologics", + "employed": true + }, + { + "firstName": "Staci", + "lastName": "Beck", + "company": "Snowpoke", + "employed": false + }, + { + "firstName": "Patrice", + "lastName": "Gutierrez", + "company": "Comcubine", + "employed": true + }, + { + "firstName": "Cash", + "lastName": "Francis", + "company": "Isoternia", + "employed": true + }, + { + "firstName": "Lee", + "lastName": "Carr", + "company": "Emoltra", + "employed": false + }, + { + "firstName": "Stein", + "lastName": "Rush", + "company": "Idego", + "employed": false + }, + { + "firstName": "Valerie", + "lastName": "Stanton", + "company": "Applidec", + "employed": false + }, + { + "firstName": "Salazar", + "lastName": "Barton", + "company": "Unisure", + "employed": true + }, + { + "firstName": "Bonner", + "lastName": "Stevens", + "company": "Imperium", + "employed": true + }, + { + "firstName": "Mann", + "lastName": "Nguyen", + "company": "Songbird", + "employed": true + }, + { + "firstName": "Taylor", + "lastName": "Wyatt", + "company": "Uxmox", + "employed": true + }, + { + "firstName": "Payne", + "lastName": "Malone", + "company": "Zillar", + "employed": true + }, + { + "firstName": "Rivers", + "lastName": "Chen", + "company": "Bulljuice", + "employed": true + }, + { + "firstName": "Freida", + "lastName": "Lambert", + "company": "Tourmania", + "employed": false + }, + { + "firstName": "Duncan", + "lastName": "Leach", + "company": "Nebulean", + "employed": false + }, + { + "firstName": "Sheppard", + "lastName": "Thompson", + "company": "Quonata", + "employed": true + }, + { + "firstName": "Howe", + "lastName": "Montgomery", + "company": "Stelaecor", + "employed": false + }, + { + "firstName": "Rosalyn", + "lastName": "Donovan", + "company": "Arctiq", + "employed": false + }, + { + "firstName": "Dalton", + "lastName": "Tillman", + "company": "Providco", + "employed": false + }, + { + "firstName": "Duke", + "lastName": "Bolton", + "company": "Ersum", + "employed": false + }, + { + "firstName": "Edwina", + "lastName": "Buchanan", + "company": "Puria", + "employed": false + }, + { + "firstName": "Kelly", + "lastName": "Estrada", + "company": "Accusage", + "employed": true + }, + { + "firstName": "Boyle", + "lastName": "Gardner", + "company": "Bullzone", + "employed": false + }, + { + "firstName": "Isabelle", + "lastName": "Dotson", + "company": "Ecraze", + "employed": true + }, + { + "firstName": "Cameron", + "lastName": "Warren", + "company": "Multiflex", + "employed": false + }, + { + "firstName": "Denise", + "lastName": "Raymond", + "company": "Sureplex", + "employed": true + }, + { + "firstName": "Madeline", + "lastName": "Woodard", + "company": "Trollery", + "employed": false + }, + { + "firstName": "Kaitlin", + "lastName": "Bullock", + "company": "Roughies", + "employed": true + }, + { + "firstName": "Hewitt", + "lastName": "Parrish", + "company": "Ebidco", + "employed": true + }, + { + "firstName": "Tamika", + "lastName": "Suarez", + "company": "Gogol", + "employed": false + }, + { + "firstName": "Lowery", + "lastName": "Martin", + "company": "Immunics", + "employed": false + }, + { + "firstName": "Virginia", + "lastName": "Ramirez", + "company": "Portico", + "employed": false + }, + { + "firstName": "Green", + "lastName": "Oneill", + "company": "Automon", + "employed": false + }, + { + "firstName": "Mae", + "lastName": "Horton", + "company": "Billmed", + "employed": false + }, + { + "firstName": "Shepherd", + "lastName": "Foley", + "company": "Aquamate", + "employed": true + }, + { + "firstName": "Sweeney", + "lastName": "Peters", + "company": "Orbin", + "employed": true + }, + { + "firstName": "Odom", + "lastName": "Bowers", + "company": "Tersanki", + "employed": false + }, + { + "firstName": "Karyn", + "lastName": "Ferrell", + "company": "Artiq", + "employed": false + }, + { + "firstName": "Hogan", + "lastName": "Chavez", + "company": "Bristo", + "employed": true + }, + { + "firstName": "Jaclyn", + "lastName": "May", + "company": "Gadtron", + "employed": true + }, + { + "firstName": "Chandra", + "lastName": "Nunez", + "company": "Izzby", + "employed": false + }, + { + "firstName": "Kaye", + "lastName": "Dorsey", + "company": "Polarax", + "employed": false + }, + { + "firstName": "Fanny", + "lastName": "Hurst", + "company": "Zaya", + "employed": true + }, + { + "firstName": "Haley", + "lastName": "Wiley", + "company": "Jimbies", + "employed": true + }, + { + "firstName": "Hernandez", + "lastName": "Marquez", + "company": "Martgo", + "employed": false + }, + { + "firstName": "Marilyn", + "lastName": "Mcpherson", + "company": "Isotrack", + "employed": true + }, + { + "firstName": "Deena", + "lastName": "Estes", + "company": "Omnigog", + "employed": false + }, + { + "firstName": "Christensen", + "lastName": "Sampson", + "company": "Zosis", + "employed": false + }, + { + "firstName": "Preston", + "lastName": "Christian", + "company": "Vurbo", + "employed": false + }, + { + "firstName": "Essie", + "lastName": "Charles", + "company": "Vixo", + "employed": false + }, + { + "firstName": "Daisy", + "lastName": "William", + "company": "Zolavo", + "employed": false + }, + { + "firstName": "Rosie", + "lastName": "Guthrie", + "company": "Polarium", + "employed": true + }, + { + "firstName": "Strong", + "lastName": "Henson", + "company": "Empirica", + "employed": false + }, + { + "firstName": "Davenport", + "lastName": "Harrell", + "company": "Entropix", + "employed": false + }, + { + "firstName": "Jenifer", + "lastName": "Lindsay", + "company": "Minga", + "employed": false + }, + { + "firstName": "Peterson", + "lastName": "Odonnell", + "company": "Oceanica", + "employed": false + }, + { + "firstName": "Maryanne", + "lastName": "Robertson", + "company": "Isologica", + "employed": false + }, + { + "firstName": "Weaver", + "lastName": "Ball", + "company": "Lovepad", + "employed": false + }, + { + "firstName": "Lynne", + "lastName": "Bauer", + "company": "Octocore", + "employed": true + }, + { + "firstName": "Mcneil", + "lastName": "Albert", + "company": "Idetica", + "employed": false + }, + { + "firstName": "Joy", + "lastName": "Kent", + "company": "Liquicom", + "employed": true + }, + { + "firstName": "Elma", + "lastName": "Norris", + "company": "Limozen", + "employed": true + }, + { + "firstName": "Chrystal", + "lastName": "Flores", + "company": "Concility", + "employed": true + }, + { + "firstName": "Katy", + "lastName": "Carson", + "company": "Zentime", + "employed": false + }, + { + "firstName": "Marva", + "lastName": "Hays", + "company": "Eyewax", + "employed": true + }, + { + "firstName": "Vinson", + "lastName": "Castro", + "company": "Anixang", + "employed": true + }, + { + "firstName": "Louise", + "lastName": "Moreno", + "company": "Velity", + "employed": true + }, + { + "firstName": "Frederick", + "lastName": "Obrien", + "company": "Zentix", + "employed": false + }, + { + "firstName": "Etta", + "lastName": "Ramsey", + "company": "Retrotex", + "employed": false + }, + { + "firstName": "Calderon", + "lastName": "Prince", + "company": "Multron", + "employed": true + }, + { + "firstName": "Collins", + "lastName": "Mckee", + "company": "Zidox", + "employed": false + }, + { + "firstName": "Magdalena", + "lastName": "Daugherty", + "company": "Isosure", + "employed": false + }, + { + "firstName": "Hall", + "lastName": "Hicks", + "company": "Buzzworks", + "employed": true + }, + { + "firstName": "Marisa", + "lastName": "Moran", + "company": "Bezal", + "employed": false + }, + { + "firstName": "Christine", + "lastName": "Whitfield", + "company": "Papricut", + "employed": true + }, + { + "firstName": "Alejandra", + "lastName": "Frye", + "company": "Adornica", + "employed": true + }, + { + "firstName": "Joan", + "lastName": "Cross", + "company": "Shopabout", + "employed": true + }, + { + "firstName": "Montgomery", + "lastName": "Griffin", + "company": "Zanilla", + "employed": true + }, + { + "firstName": "Randi", + "lastName": "Reed", + "company": "Aquacine", + "employed": false + }, + { + "firstName": "Janie", + "lastName": "Olsen", + "company": "Realysis", + "employed": false + }, + { + "firstName": "Campos", + "lastName": "Holman", + "company": "Voipa", + "employed": false + }, + { + "firstName": "Florence", + "lastName": "Cortez", + "company": "Paprikut", + "employed": false + }, + { + "firstName": "Camacho", + "lastName": "Welch", + "company": "Assurity", + "employed": true + }, + { + "firstName": "Kathie", + "lastName": "Stewart", + "company": "Suremax", + "employed": true + }, + { + "firstName": "Lorna", + "lastName": "Fields", + "company": "Isostream", + "employed": false + }, + { + "firstName": "Lyons", + "lastName": "Clark", + "company": "Qaboos", + "employed": true + }, + { + "firstName": "Leon", + "lastName": "Sandoval", + "company": "Zaj", + "employed": false + }, + { + "firstName": "Kara", + "lastName": "Moore", + "company": "Netplode", + "employed": true + }, + { + "firstName": "Myrtle", + "lastName": "Velez", + "company": "Maxemia", + "employed": false + }, + { + "firstName": "Jessica", + "lastName": "Kline", + "company": "Envire", + "employed": false + }, + { + "firstName": "Dale", + "lastName": "Hewitt", + "company": "Accuprint", + "employed": false + }, + { + "firstName": "Davidson", + "lastName": "Sheppard", + "company": "Darwinium", + "employed": false + }, + { + "firstName": "Henrietta", + "lastName": "Ewing", + "company": "Moreganic", + "employed": false + }, + { + "firstName": "Saunders", + "lastName": "Ayers", + "company": "Skyplex", + "employed": true + }, + { + "firstName": "Lillian", + "lastName": "Carrillo", + "company": "Aquasure", + "employed": true + }, + { + "firstName": "Decker", + "lastName": "Schroeder", + "company": "Applica", + "employed": true + }, + { + "firstName": "Susana", + "lastName": "Nolan", + "company": "Virxo", + "employed": false + }, + { + "firstName": "Bernadette", + "lastName": "Best", + "company": "Avenetro", + "employed": false + }, + { + "firstName": "Rosalinda", + "lastName": "Crawford", + "company": "Comtrek", + "employed": false + }, + { + "firstName": "French", + "lastName": "Abbott", + "company": "Gonkle", + "employed": true + }, + { + "firstName": "Ingram", + "lastName": "Hatfield", + "company": "Tetak", + "employed": true + }, + { + "firstName": "Garrett", + "lastName": "Pacheco", + "company": "Kog", + "employed": true + }, + { + "firstName": "Patterson", + "lastName": "Barlow", + "company": "Comveyer", + "employed": true + }, + { + "firstName": "Bray", + "lastName": "Gallegos", + "company": "Acrodance", + "employed": true + }, + { + "firstName": "Britt", + "lastName": "Phelps", + "company": "Terrago", + "employed": false + }, + { + "firstName": "Davis", + "lastName": "Salas", + "company": "Xixan", + "employed": true + }, + { + "firstName": "Amanda", + "lastName": "Hubbard", + "company": "Keengen", + "employed": false + }, + { + "firstName": "Dyer", + "lastName": "Skinner", + "company": "Valpreal", + "employed": false + }, + { + "firstName": "Tracy", + "lastName": "Washington", + "company": "Futurity", + "employed": false + }, + { + "firstName": "Mills", + "lastName": "Larson", + "company": "Zentia", + "employed": true + }, + { + "firstName": "Velez", + "lastName": "Fox", + "company": "Quantalia", + "employed": true + }, + { + "firstName": "Bennett", + "lastName": "Hardin", + "company": "Cinaster", + "employed": true + }, + { + "firstName": "Brooks", + "lastName": "Horne", + "company": "Signidyne", + "employed": false + }, + { + "firstName": "Cain", + "lastName": "Young", + "company": "Aquazure", + "employed": true + }, + { + "firstName": "Horn", + "lastName": "Navarro", + "company": "Housedown", + "employed": false + }, + { + "firstName": "Geraldine", + "lastName": "Owens", + "company": "Plasmox", + "employed": true + }, + { + "firstName": "Ida", + "lastName": "Dejesus", + "company": "Organica", + "employed": false + }, + { + "firstName": "Pate", + "lastName": "Oneal", + "company": "Amril", + "employed": true + }, + { + "firstName": "Howell", + "lastName": "Snyder", + "company": "Pivitol", + "employed": true + }, + { + "firstName": "Alexandra", + "lastName": "Wise", + "company": "Ewaves", + "employed": true + }, + { + "firstName": "Wolf", + "lastName": "Hurley", + "company": "Handshake", + "employed": false + }, + { + "firstName": "Aurora", + "lastName": "Richard", + "company": "Eschoir", + "employed": false + }, + { + "firstName": "Dixie", + "lastName": "Small", + "company": "Quility", + "employed": false + }, + { + "firstName": "Deleon", + "lastName": "Dyer", + "company": "Blurrybus", + "employed": false + }, + { + "firstName": "Mejia", + "lastName": "Huff", + "company": "Sportan", + "employed": true + }, + { + "firstName": "Kennedy", + "lastName": "Good", + "company": "Geekko", + "employed": true + }, + { + "firstName": "Velma", + "lastName": "Trevino", + "company": "Terrasys", + "employed": true + }, + { + "firstName": "Meyer", + "lastName": "Bonner", + "company": "Combot", + "employed": false + }, + { + "firstName": "Contreras", + "lastName": "Kane", + "company": "Comvey", + "employed": false + }, + { + "firstName": "Woodward", + "lastName": "Neal", + "company": "Vinch", + "employed": false + }, + { + "firstName": "Carrillo", + "lastName": "Simpson", + "company": "Emtrak", + "employed": false + }, + { + "firstName": "Kenya", + "lastName": "Guerra", + "company": "Cablam", + "employed": true + }, + { + "firstName": "Jayne", + "lastName": "Hood", + "company": "Biolive", + "employed": true + }, + { + "firstName": "Ayala", + "lastName": "Walls", + "company": "Solaren", + "employed": true + }, + { + "firstName": "Griffin", + "lastName": "Galloway", + "company": "Typhonica", + "employed": false + }, + { + "firstName": "Opal", + "lastName": "Holt", + "company": "Anivet", + "employed": false + }, + { + "firstName": "Pamela", + "lastName": "Potter", + "company": "Gink", + "employed": false + }, + { + "firstName": "Pearson", + "lastName": "Britt", + "company": "Kyagoro", + "employed": true + }, + { + "firstName": "Desiree", + "lastName": "Knowles", + "company": "Extremo", + "employed": true + }, + { + "firstName": "Grace", + "lastName": "Dennis", + "company": "Gleamink", + "employed": true + }, + { + "firstName": "Wilma", + "lastName": "Murray", + "company": "Comtext", + "employed": false + }, + { + "firstName": "Shana", + "lastName": "Miranda", + "company": "Rooforia", + "employed": true + }, + { + "firstName": "Nettie", + "lastName": "Garrett", + "company": "Cogentry", + "employed": true + }, + { + "firstName": "Whitaker", + "lastName": "Blackburn", + "company": "Medmex", + "employed": true + }, + { + "firstName": "Tyson", + "lastName": "Burke", + "company": "Exospeed", + "employed": true + }, + { + "firstName": "Janine", + "lastName": "Mcmahon", + "company": "Genmom", + "employed": false + }, + { + "firstName": "Lauri", + "lastName": "Nieves", + "company": "Lumbrex", + "employed": false + }, + { + "firstName": "Margery", + "lastName": "Howe", + "company": "Xsports", + "employed": false + }, + { + "firstName": "Dillard", + "lastName": "Weber", + "company": "Hyplex", + "employed": true + }, + { + "firstName": "Sloan", + "lastName": "Wheeler", + "company": "Katakana", + "employed": true + }, + { + "firstName": "Kristin", + "lastName": "Sears", + "company": "Techmania", + "employed": true + }, + { + "firstName": "Jewel", + "lastName": "Villarreal", + "company": "Zolarity", + "employed": false + }, + { + "firstName": "Rhoda", + "lastName": "Flowers", + "company": "Kenegy", + "employed": false + }, + { + "firstName": "Kris", + "lastName": "Whitney", + "company": "Autograte", + "employed": true + }, + { + "firstName": "Mcgowan", + "lastName": "Lane", + "company": "Medifax", + "employed": true + }, + { + "firstName": "Moore", + "lastName": "Holcomb", + "company": "Zillatide", + "employed": false + }, + { + "firstName": "Foster", + "lastName": "Campbell", + "company": "Xerex", + "employed": false + }, + { + "firstName": "Savage", + "lastName": "Farmer", + "company": "Ozean", + "employed": true + }, + { + "firstName": "Emily", + "lastName": "Jimenez", + "company": "Quiltigen", + "employed": false + }, + { + "firstName": "May", + "lastName": "Knight", + "company": "Earbang", + "employed": true + }, + { + "firstName": "Gay", + "lastName": "Ruiz", + "company": "Ontality", + "employed": false + }, + { + "firstName": "Murray", + "lastName": "Burris", + "company": "Enquility", + "employed": false + }, + { + "firstName": "Aline", + "lastName": "Glover", + "company": "Zepitope", + "employed": false + }, + { + "firstName": "Harrington", + "lastName": "Wolf", + "company": "Hopeli", + "employed": true + }, + { + "firstName": "Phyllis", + "lastName": "Battle", + "company": "Syntac", + "employed": false + }, + { + "firstName": "Sherrie", + "lastName": "Green", + "company": "Noralex", + "employed": false + }, + { + "firstName": "Olson", + "lastName": "Hogan", + "company": "Exosis", + "employed": true + }, + { + "firstName": "Jones", + "lastName": "Morris", + "company": "Atomica", + "employed": false + }, + { + "firstName": "Deidre", + "lastName": "Rose", + "company": "Exerta", + "employed": true + }, + { + "firstName": "Misty", + "lastName": "Duran", + "company": "Maineland", + "employed": true + }, + { + "firstName": "Krystal", + "lastName": "Shannon", + "company": "Geekmosis", + "employed": true + }, + { + "firstName": "Rhea", + "lastName": "Merrill", + "company": "Accidency", + "employed": true + }, + { + "firstName": "Lelia", + "lastName": "Hines", + "company": "Solgan", + "employed": true + }, + { + "firstName": "Luz", + "lastName": "Swanson", + "company": "Otherway", + "employed": true + }, + { + "firstName": "Rios", + "lastName": "Cervantes", + "company": "Lyria", + "employed": true + }, + { + "firstName": "Hinton", + "lastName": "Osborne", + "company": "Coash", + "employed": true + }, + { + "firstName": "Stokes", + "lastName": "Delacruz", + "company": "Liquidoc", + "employed": true + }, + { + "firstName": "Maura", + "lastName": "Jarvis", + "company": "Twiggery", + "employed": false + }, + { + "firstName": "Sophia", + "lastName": "Alvarez", + "company": "Zisis", + "employed": false + }, + { + "firstName": "Guerrero", + "lastName": "Lynch", + "company": "Fanfare", + "employed": true + }, + { + "firstName": "Ashley", + "lastName": "Cooke", + "company": "Exotechno", + "employed": true + }, + { + "firstName": "Sawyer", + "lastName": "Haley", + "company": "Renovize", + "employed": false + }, + { + "firstName": "Corina", + "lastName": "Delaney", + "company": "Daido", + "employed": true + }, + { + "firstName": "Maude", + "lastName": "Zamora", + "company": "Kidstock", + "employed": false + }, + { + "firstName": "Brittney", + "lastName": "Daniels", + "company": "Krog", + "employed": true + }, + { + "firstName": "Alvarez", + "lastName": "Clements", + "company": "Edecine", + "employed": false + }, + { + "firstName": "Weiss", + "lastName": "Witt", + "company": "Comveyor", + "employed": true + }, + { + "firstName": "Jacobs", + "lastName": "Crane", + "company": "Terascape", + "employed": true + }, + { + "firstName": "Buckner", + "lastName": "Roach", + "company": "Tripsch", + "employed": true + }, + { + "firstName": "Carson", + "lastName": "Mcneil", + "company": "Xleen", + "employed": true + }, + { + "firstName": "Pickett", + "lastName": "Hughes", + "company": "Glukgluk", + "employed": true + }, + { + "firstName": "Kirsten", + "lastName": "Conner", + "company": "Brainquil", + "employed": true + }, + { + "firstName": "Mendez", + "lastName": "Berger", + "company": "Exoteric", + "employed": false + }, + { + "firstName": "Sue", + "lastName": "Blankenship", + "company": "Mobildata", + "employed": false + }, + { + "firstName": "Grimes", + "lastName": "Torres", + "company": "Zillanet", + "employed": true + }, + { + "firstName": "Ginger", + "lastName": "Daniel", + "company": "Neptide", + "employed": true + }, + { + "firstName": "Lena", + "lastName": "Anthony", + "company": "Flotonic", + "employed": false + }, + { + "firstName": "Alyssa", + "lastName": "Garza", + "company": "Imageflow", + "employed": false + }, + { + "firstName": "Neva", + "lastName": "Lopez", + "company": "Neteria", + "employed": false + }, + { + "firstName": "Deirdre", + "lastName": "Berry", + "company": "Isosphere", + "employed": true + }, + { + "firstName": "Joni", + "lastName": "Tucker", + "company": "Springbee", + "employed": false + }, + { + "firstName": "Deloris", + "lastName": "Sellers", + "company": "Prowaste", + "employed": true + }, + { + "firstName": "Sonya", + "lastName": "Brown", + "company": "Bedder", + "employed": false + }, + { + "firstName": "Suzette", + "lastName": "Harrison", + "company": "Imant", + "employed": false + }, + { + "firstName": "Janelle", + "lastName": "Maddox", + "company": "Xymonk", + "employed": false + }, + { + "firstName": "Gertrude", + "lastName": "Poole", + "company": "Dogspa", + "employed": false + }, + { + "firstName": "Rachelle", + "lastName": "Hahn", + "company": "Dancity", + "employed": true + }, + { + "firstName": "Rollins", + "lastName": "Foreman", + "company": "Kengen", + "employed": false + }, + { + "firstName": "Watson", + "lastName": "Rasmussen", + "company": "Pyramis", + "employed": true + }, + { + "firstName": "Shelia", + "lastName": "Haney", + "company": "Macronaut", + "employed": true + }, + { + "firstName": "Karin", + "lastName": "Carpenter", + "company": "Zoarere", + "employed": false + }, + { + "firstName": "Buck", + "lastName": "Livingston", + "company": "Thredz", + "employed": true + }, + { + "firstName": "Clarissa", + "lastName": "Peterson", + "company": "Uni", + "employed": false + }, + { + "firstName": "Holly", + "lastName": "Maynard", + "company": "Opticom", + "employed": true + }, + { + "firstName": "Bryan", + "lastName": "Kelley", + "company": "Pulze", + "employed": false + }, + { + "firstName": "Fowler", + "lastName": "Cummings", + "company": "Nutralab", + "employed": false + }, + { + "firstName": "Mitzi", + "lastName": "Burt", + "company": "Geeknet", + "employed": false + }, + { + "firstName": "Robin", + "lastName": "Ratliff", + "company": "Kiggle", + "employed": false + }, + { + "firstName": "Baker", + "lastName": "Ross", + "company": "Xth", + "employed": true + }, + { + "firstName": "Charles", + "lastName": "Stanley", + "company": "Medalert", + "employed": true + }, + { + "firstName": "Solis", + "lastName": "Williams", + "company": "Qot", + "employed": true + }, + { + "firstName": "Estrada", + "lastName": "Everett", + "company": "Xiix", + "employed": false + }, + { + "firstName": "Aileen", + "lastName": "Munoz", + "company": "Utarian", + "employed": true + }, + { + "firstName": "Pat", + "lastName": "Macdonald", + "company": "Megall", + "employed": true + }, + { + "firstName": "Merritt", + "lastName": "Jensen", + "company": "Cincyr", + "employed": false + }, + { + "firstName": "Cobb", + "lastName": "Allen", + "company": "Delphide", + "employed": true + }, + { + "firstName": "Diaz", + "lastName": "Garcia", + "company": "Pharmacon", + "employed": false + }, + { + "firstName": "Dora", + "lastName": "Fry", + "company": "Entroflex", + "employed": false + }, + { + "firstName": "Rena", + "lastName": "Olson", + "company": "Geeky", + "employed": true + }, + { + "firstName": "Powers", + "lastName": "Morse", + "company": "Techtrix", + "employed": false + }, + { + "firstName": "Cindy", + "lastName": "Robinson", + "company": "Keeg", + "employed": false + }, + { + "firstName": "Aimee", + "lastName": "Cohen", + "company": "Magnafone", + "employed": true + }, + { + "firstName": "Skinner", + "lastName": "Payne", + "company": "Sequitur", + "employed": true + }, + { + "firstName": "Fernandez", + "lastName": "Compton", + "company": "Terragen", + "employed": true + } +] \ No newline at end of file diff --git a/data/500_complex.json b/data/500_complex.json new file mode 100644 index 000000000..2e1533863 --- /dev/null +++ b/data/500_complex.json @@ -0,0 +1,17502 @@ +[ + { + "id": 0, + "guid": "de3db502-0a33-4e47-a0bb-35b6235503ca", + "isActive": false, + "balance": "$3,489.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Sandoval Mclean", + "gender": "male", + "company": "Zolavo", + "email": "sandovalmclean@zolavo.com", + "phone": "+1 (902) 569-2412", + "address": { + "street": 317, + "city": "Blairstown", + "state": "Maine", + "zip": 390 + }, + "about": "Fugiat velit laboris sit est. Amet eu consectetur reprehenderit proident irure non. Adipisicing mollit veniam enim veniam officia anim proident excepteur deserunt consectetur aliquip et irure. Elit aliquip laborum qui elit consectetur sit proident adipisicing.\r\n", + "registered": "1991-02-21T23:02:31+06:00", + "friends": [ + { + "id": 0, + "name": "Rosanne Barrett" + }, + { + "id": 1, + "name": "Nita Chase" + }, + { + "id": 2, + "name": "Briggs Stark" + } + ] + }, + { + "id": 1, + "guid": "9f507483-5ecc-4af4-800f-349306820585", + "isActive": false, + "balance": "$2,407.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Nieves Mack", + "gender": "male", + "company": "Oulu", + "email": "nievesmack@oulu.com", + "phone": "+1 (812) 535-2614", + "address": { + "street": 155, + "city": "Cherokee", + "state": "Kentucky", + "zip": 4723 + }, + "about": "Culpa anim anim nulla deserunt dolor exercitation eu in anim velit. Consectetur esse cillum ea esse ullamco magna do voluptate sit ut cupidatat ullamco. Et consequat eu excepteur do Lorem aute est quis proident irure.\r\n", + "registered": "1989-07-26T15:52:15+05:00", + "friends": [ + { + "id": 0, + "name": "Brewer Maxwell" + }, + { + "id": 1, + "name": "Ayala Franks" + }, + { + "id": 2, + "name": "Hale Nichols" + } + ] + }, + { + "id": 2, + "guid": "58c66190-15be-4e75-9b09-183599403241", + "isActive": false, + "balance": "$3,409.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Terry Clay", + "gender": "female", + "company": "Freakin", + "email": "terryclay@freakin.com", + "phone": "+1 (965) 462-3681", + "address": { + "street": 124, + "city": "Wright", + "state": "Pennsylvania", + "zip": 8002 + }, + "about": "Exercitation exercitation adipisicing eu cupidatat reprehenderit laborum incididunt reprehenderit Lorem anim. Velit aliquip dolore qui excepteur dolor non occaecat aute et. Consectetur anim veniam irure ea id aliqua amet. Nostrud tempor ullamco velit labore consequat aute nostrud nostrud veniam cupidatat amet nostrud quis. Qui exercitation eiusmod esse eu officia officia Lorem Lorem ullamco voluptate excepteur fugiat nulla et. Ea ipsum ut do culpa labore non duis commodo sit. Id sint dolor ipsum consectetur nostrud nulla consectetur esse deserunt.\r\n", + "registered": "2000-12-02T22:19:28+06:00", + "friends": [ + { + "id": 0, + "name": "Etta Hawkins" + }, + { + "id": 1, + "name": "Zamora Barlow" + }, + { + "id": 2, + "name": "Lynette Vinson" + } + ] + }, + { + "id": 3, + "guid": "0a1b0539-73ec-473a-846a-71a58e04551c", + "isActive": false, + "balance": "$3,567.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Bishop Carr", + "gender": "male", + "company": "Digirang", + "email": "bishopcarr@digirang.com", + "phone": "+1 (860) 463-2942", + "address": { + "street": 824, + "city": "Homeworth", + "state": "Oklahoma", + "zip": 5215 + }, + "about": "Nulla ullamco sint exercitation minim ea sunt. Excepteur minim tempor velit in. Proident id reprehenderit nisi officia in anim elit laboris aute sint amet voluptate. Deserunt et nostrud magna eu esse ea adipisicing non quis sint fugiat consectetur enim sint. Magna elit mollit eiusmod non voluptate sunt.\r\n", + "registered": "2012-10-15T19:03:24+05:00", + "friends": [ + { + "id": 0, + "name": "Young Gentry" + }, + { + "id": 1, + "name": "Dean Lopez" + }, + { + "id": 2, + "name": "Mccray Bradford" + } + ] + }, + { + "id": 4, + "guid": "f82261a1-71d0-4d96-aeb6-03e300112f18", + "isActive": true, + "balance": "$1,931.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Hatfield Hudson", + "gender": "male", + "company": "Quonata", + "email": "hatfieldhudson@quonata.com", + "phone": "+1 (981) 476-2966", + "address": { + "street": 853, + "city": "Bynum", + "state": "Rhode Island", + "zip": 3382 + }, + "about": "In fugiat elit ipsum qui occaecat elit enim eu labore. Esse incididunt adipisicing nostrud veniam proident duis ex aute sit id. Exercitation occaecat nisi incididunt ut esse nostrud pariatur. Consectetur culpa minim deserunt minim proident consectetur incididunt enim duis adipisicing pariatur proident.\r\n", + "registered": "2000-09-05T10:41:58+05:00", + "friends": [ + { + "id": 0, + "name": "Munoz Sharp" + }, + { + "id": 1, + "name": "Louella Vaughn" + }, + { + "id": 2, + "name": "Cleveland Parker" + } + ] + }, + { + "id": 5, + "guid": "3eeb5290-1357-4c8b-8ca3-ea9f01521928", + "isActive": false, + "balance": "$2,215.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Madge Wilkerson", + "gender": "female", + "company": "Mixers", + "email": "madgewilkerson@mixers.com", + "phone": "+1 (947) 551-2199", + "address": { + "street": 374, + "city": "Springdale", + "state": "Minnesota", + "zip": 7453 + }, + "about": "Officia laboris laborum dolore ad minim ad mollit et excepteur adipisicing do non nostrud officia. Anim in exercitation dolor cupidatat deserunt. Commodo excepteur aliqua consequat do. Aliquip incididunt quis sunt cillum reprehenderit consequat.\r\n", + "registered": "2005-12-16T01:13:09+06:00", + "friends": [ + { + "id": 0, + "name": "Tabatha Mclaughlin" + }, + { + "id": 1, + "name": "Letitia Evans" + }, + { + "id": 2, + "name": "Greta Sykes" + } + ] + }, + { + "id": 6, + "guid": "29bc47e3-5275-49be-b9cf-95853f1c5801", + "isActive": true, + "balance": "$3,623.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Harrell Gaines", + "gender": "male", + "company": "Namebox", + "email": "harrellgaines@namebox.com", + "phone": "+1 (902) 410-2375", + "address": { + "street": 639, + "city": "Jackpot", + "state": "Virginia", + "zip": 4822 + }, + "about": "Magna non sit laboris amet Lorem occaecat tempor aute cillum ut dolore dolor pariatur. Amet consequat id consequat id esse aliquip. Irure anim ex veniam aliquip magna aute velit qui duis minim.\r\n", + "registered": "1998-08-08T13:08:45+05:00", + "friends": [ + { + "id": 0, + "name": "Beatriz Lancaster" + }, + { + "id": 1, + "name": "Cora Lawrence" + }, + { + "id": 2, + "name": "Elva Pate" + } + ] + }, + { + "id": 7, + "guid": "7e7aba67-7562-4bea-9a16-86108f41b4b4", + "isActive": true, + "balance": "$2,731.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Christensen Wall", + "gender": "male", + "company": "Elentrix", + "email": "christensenwall@elentrix.com", + "phone": "+1 (985) 594-3954", + "address": { + "street": 510, + "city": "Vandiver", + "state": "Colorado", + "zip": 5384 + }, + "about": "Est quis nostrud elit sint commodo consectetur ea ullamco tempor voluptate veniam reprehenderit. Elit Lorem aliqua dolore commodo officia labore. Cupidatat proident qui ullamco in cillum.\r\n", + "registered": "1992-06-19T22:03:28+05:00", + "friends": [ + { + "id": 0, + "name": "Olsen Rosario" + }, + { + "id": 1, + "name": "Janelle Mcintosh" + }, + { + "id": 2, + "name": "Dorothy Gallegos" + } + ] + }, + { + "id": 8, + "guid": "8345f097-17d7-4a8d-8f16-dffbb92dab55", + "isActive": false, + "balance": "$1,971.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Solomon Flowers", + "gender": "male", + "company": "Bizmatic", + "email": "solomonflowers@bizmatic.com", + "phone": "+1 (815) 587-2364", + "address": { + "street": 834, + "city": "Edmund", + "state": "Wisconsin", + "zip": 6804 + }, + "about": "Deserunt cillum consectetur do irure aliqua non. Velit sunt incididunt consectetur pariatur Lorem. Exercitation eiusmod esse fugiat occaecat cillum in. Reprehenderit Lorem proident anim amet incididunt laborum. Enim ex eiusmod cillum occaecat cillum dolor non sunt nostrud enim occaecat duis sit. Commodo commodo culpa amet dolore Lorem ipsum nulla adipisicing quis. In Lorem ad ipsum non voluptate exercitation consectetur excepteur ipsum.\r\n", + "registered": "2006-03-04T18:49:18+06:00", + "friends": [ + { + "id": 0, + "name": "Mercedes Reed" + }, + { + "id": 1, + "name": "Anastasia Todd" + }, + { + "id": 2, + "name": "Alfreda Snyder" + } + ] + }, + { + "id": 9, + "guid": "aed7f3f9-e5e0-4d1e-88a7-94976095b01f", + "isActive": true, + "balance": "$1,291.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Flossie Davidson", + "gender": "female", + "company": "Marketoid", + "email": "flossiedavidson@marketoid.com", + "phone": "+1 (831) 464-3405", + "address": { + "street": 969, + "city": "Linwood", + "state": "Connecticut", + "zip": 9693 + }, + "about": "Aute laboris amet officia anim. Tempor cillum laborum dolor fugiat sint minim ullamco nisi aliquip Lorem mollit eiusmod do. Excepteur culpa aute aute incididunt et tempor nulla officia nostrud.\r\n", + "registered": "1991-12-27T21:30:00+06:00", + "friends": [ + { + "id": 0, + "name": "Doreen Pittman" + }, + { + "id": 1, + "name": "Baker Salinas" + }, + { + "id": 2, + "name": "Mcdowell Bryan" + } + ] + }, + { + "id": 10, + "guid": "aca740c5-e492-4254-a38e-da9a6e293a1e", + "isActive": true, + "balance": "$3,393.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Rodriquez Kent", + "gender": "male", + "company": "Telpod", + "email": "rodriquezkent@telpod.com", + "phone": "+1 (918) 489-2703", + "address": { + "street": 186, + "city": "Succasunna", + "state": "North Carolina", + "zip": 1844 + }, + "about": "Magna do aliquip laboris laborum duis aute magna laborum dolore occaecat. Sit culpa tempor qui eiusmod tempor occaecat. Amet pariatur laboris do exercitation quis ipsum do.\r\n", + "registered": "1996-12-30T13:14:49+06:00", + "friends": [ + { + "id": 0, + "name": "Perkins Kaufman" + }, + { + "id": 1, + "name": "Serena Solis" + }, + { + "id": 2, + "name": "Alyssa Mercer" + } + ] + }, + { + "id": 11, + "guid": "09008245-6877-4181-badd-43a6a5099ae4", + "isActive": true, + "balance": "$3,880.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Lawson Meyer", + "gender": "male", + "company": "Fuelworks", + "email": "lawsonmeyer@fuelworks.com", + "phone": "+1 (812) 451-2916", + "address": { + "street": 206, + "city": "Bladensburg", + "state": "Georgia", + "zip": 2294 + }, + "about": "Incididunt minim nulla excepteur voluptate labore ipsum reprehenderit occaecat qui duis minim aute amet. Do commodo magna incididunt anim in ipsum exercitation. Ipsum nostrud ipsum veniam aliquip irure nulla tempor quis. Voluptate magna in eu tempor sunt in sunt enim nisi duis pariatur anim consequat est.\r\n", + "registered": "2007-03-15T12:15:01+05:00", + "friends": [ + { + "id": 0, + "name": "Howe Delgado" + }, + { + "id": 1, + "name": "Goldie Santana" + }, + { + "id": 2, + "name": "Fuentes Schneider" + } + ] + }, + { + "id": 12, + "guid": "5014486c-fdf9-45f0-9f29-f3762180ce4d", + "isActive": false, + "balance": "$3,703.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Cheryl Mueller", + "gender": "female", + "company": "Hotcakes", + "email": "cherylmueller@hotcakes.com", + "phone": "+1 (943) 425-3326", + "address": { + "street": 823, + "city": "Nipinnawasee", + "state": "Arkansas", + "zip": 2742 + }, + "about": "Irure ea dolor labore adipisicing. Duis pariatur aute enim aute veniam voluptate sint labore ipsum laborum. Cillum amet in occaecat labore ea. Aliqua ad eu elit duis qui cupidatat Lorem enim voluptate ipsum nostrud consectetur Lorem cillum.\r\n", + "registered": "1995-10-20T09:33:29+05:00", + "friends": [ + { + "id": 0, + "name": "Durham Hewitt" + }, + { + "id": 1, + "name": "Kristie Hanson" + }, + { + "id": 2, + "name": "Susan Weiss" + } + ] + }, + { + "id": 13, + "guid": "65903217-3e10-4aa3-ad58-8293c33bb573", + "isActive": true, + "balance": "$3,467.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Marci Gill", + "gender": "female", + "company": "Pawnagra", + "email": "marcigill@pawnagra.com", + "phone": "+1 (971) 515-3892", + "address": { + "street": 337, + "city": "Osmond", + "state": "Delaware", + "zip": 2131 + }, + "about": "Consectetur dolore do cupidatat proident consectetur cillum elit commodo sit. Officia Lorem id laboris enim exercitation veniam est. Sunt laborum eu cupidatat nisi quis deserunt esse consectetur elit mollit esse. Elit eiusmod magna aliquip enim nostrud.\r\n", + "registered": "2005-08-10T17:06:51+05:00", + "friends": [ + { + "id": 0, + "name": "Becky Gilliam" + }, + { + "id": 1, + "name": "Maynard Lyons" + }, + { + "id": 2, + "name": "Delaney Goodwin" + } + ] + }, + { + "id": 14, + "guid": "20b311d2-6eb8-4863-b006-f0472b69b69c", + "isActive": false, + "balance": "$1,451.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Kelly Roy", + "gender": "female", + "company": "Aquazure", + "email": "kellyroy@aquazure.com", + "phone": "+1 (893) 541-3485", + "address": { + "street": 676, + "city": "Marbury", + "state": "Alabama", + "zip": 9686 + }, + "about": "Amet anim dolor ipsum sunt. Deserunt occaecat esse Lorem ad non consequat id dolore fugiat proident nulla mollit deserunt nulla. Eu exercitation amet laboris qui Lorem velit Lorem magna exercitation elit in nulla magna. Eu officia eu sint do consectetur mollit et fugiat sint tempor Lorem deserunt. Duis incididunt cillum incididunt adipisicing velit enim ad laborum ut ullamco quis irure nulla. Ex dolor exercitation nisi reprehenderit dolor. Laboris eiusmod ullamco aliqua adipisicing occaecat.\r\n", + "registered": "1992-05-29T18:15:10+05:00", + "friends": [ + { + "id": 0, + "name": "Garner Combs" + }, + { + "id": 1, + "name": "Cervantes Rasmussen" + }, + { + "id": 2, + "name": "Solis Fuller" + } + ] + }, + { + "id": 15, + "guid": "78d84243-9477-4ee1-8383-6926c9738e04", + "isActive": true, + "balance": "$2,835.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Sparks Berger", + "gender": "male", + "company": "Squish", + "email": "sparksberger@squish.com", + "phone": "+1 (813) 469-3191", + "address": { + "street": 163, + "city": "Wedgewood", + "state": "South Dakota", + "zip": 3203 + }, + "about": "Et dolore duis fugiat sunt excepteur. Ipsum eiusmod occaecat irure consequat aute. Incididunt exercitation nostrud occaecat dolor eu aliqua aliquip fugiat occaecat sit minim do commodo enim. Mollit et sit exercitation occaecat esse reprehenderit culpa.\r\n", + "registered": "2011-07-26T15:48:47+05:00", + "friends": [ + { + "id": 0, + "name": "Peterson Workman" + }, + { + "id": 1, + "name": "Lynch Ross" + }, + { + "id": 2, + "name": "Dyer Whitfield" + } + ] + }, + { + "id": 16, + "guid": "36d0a6d5-9c20-4565-a562-cb5f78f0f4b4", + "isActive": true, + "balance": "$3,108.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Annie Orr", + "gender": "female", + "company": "Lunchpod", + "email": "annieorr@lunchpod.com", + "phone": "+1 (805) 533-2734", + "address": { + "street": 997, + "city": "Trinway", + "state": "Louisiana", + "zip": 6555 + }, + "about": "Nostrud pariatur laboris sint eiusmod consectetur enim minim elit commodo laboris sunt tempor. Magna laborum consequat voluptate consectetur eiusmod. Irure duis ea ipsum voluptate laboris Lorem ad consectetur aliquip reprehenderit enim.\r\n", + "registered": "2012-03-09T22:44:11+06:00", + "friends": [ + { + "id": 0, + "name": "Gray Bush" + }, + { + "id": 1, + "name": "Agnes Washington" + }, + { + "id": 2, + "name": "Zimmerman Alexander" + } + ] + }, + { + "id": 17, + "guid": "881ad6a4-3057-43d9-a0f4-d06f9110c843", + "isActive": true, + "balance": "$1,481.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Carissa Bender", + "gender": "female", + "company": "Pearlessa", + "email": "carissabender@pearlessa.com", + "phone": "+1 (828) 447-2266", + "address": { + "street": 212, + "city": "Datil", + "state": "New Hampshire", + "zip": 3936 + }, + "about": "Anim sint ad pariatur proident occaecat sunt. Ipsum sit sit magna enim Lorem commodo consectetur nisi mollit aliquip ipsum qui laborum incididunt. Adipisicing duis cupidatat commodo fugiat ex deserunt ad non. Cillum voluptate laborum cupidatat dolor do aliquip veniam dolor est labore id quis enim anim.\r\n", + "registered": "2006-09-13T10:39:16+05:00", + "friends": [ + { + "id": 0, + "name": "Willie Graves" + }, + { + "id": 1, + "name": "Hansen Irwin" + }, + { + "id": 2, + "name": "Thornton Oconnor" + } + ] + }, + { + "id": 18, + "guid": "8996dab7-a8b7-41fc-be45-324404d58d0c", + "isActive": false, + "balance": "$1,324.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Michelle Huffman", + "gender": "female", + "company": "Aquasseur", + "email": "michellehuffman@aquasseur.com", + "phone": "+1 (809) 470-2888", + "address": { + "street": 491, + "city": "Winfred", + "state": "Florida", + "zip": 1292 + }, + "about": "Amet et minim occaecat consequat cillum laboris laboris cillum consectetur commodo aliquip. Mollit laboris nulla est reprehenderit. Velit laboris occaecat nisi irure mollit et enim id duis sint incididunt.\r\n", + "registered": "2004-09-21T16:54:39+05:00", + "friends": [ + { + "id": 0, + "name": "Wise Calderon" + }, + { + "id": 1, + "name": "Jennie Whitehead" + }, + { + "id": 2, + "name": "Weeks Guthrie" + } + ] + }, + { + "id": 19, + "guid": "55f535af-d174-4063-ba76-7023d945f7a3", + "isActive": false, + "balance": "$1,019.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Caroline Kirkland", + "gender": "female", + "company": "Boilicon", + "email": "carolinekirkland@boilicon.com", + "phone": "+1 (941) 521-3591", + "address": { + "street": 285, + "city": "Mansfield", + "state": "Nevada", + "zip": 9715 + }, + "about": "Ea commodo Lorem pariatur qui velit est ipsum qui non eiusmod esse. Irure velit ipsum tempor qui irure nostrud amet ad consequat eu consectetur in exercitation. Cupidatat exercitation duis sint occaecat et. Incididunt elit Lorem consequat eiusmod pariatur dolor. Officia non occaecat excepteur irure officia labore exercitation ea dolore ea id aute sit fugiat.\r\n", + "registered": "1991-06-20T23:43:39+05:00", + "friends": [ + { + "id": 0, + "name": "Wheeler Bond" + }, + { + "id": 1, + "name": "Tiffany Baker" + }, + { + "id": 2, + "name": "Jenna Odom" + } + ] + }, + { + "id": 20, + "guid": "8cfc70b1-30f1-4ddc-a70b-01bb399f62c5", + "isActive": false, + "balance": "$3,591.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Mcclain Pope", + "gender": "male", + "company": "Zork", + "email": "mcclainpope@zork.com", + "phone": "+1 (832) 490-3175", + "address": { + "street": 727, + "city": "Motley", + "state": "Montana", + "zip": 7714 + }, + "about": "Non quis do enim occaecat nostrud veniam aute sunt cupidatat dolor proident consequat nulla. Exercitation et quis nostrud consequat magna sit commodo. Ut cupidatat ea tempor aliqua sint Lorem. Ea consequat pariatur veniam fugiat quis et ullamco commodo anim eiusmod ex occaecat cupidatat. Mollit officia cupidatat ad ut aliquip irure esse incididunt et commodo.\r\n", + "registered": "1991-08-13T16:09:19+05:00", + "friends": [ + { + "id": 0, + "name": "Chandra Merrill" + }, + { + "id": 1, + "name": "Ella Burton" + }, + { + "id": 2, + "name": "Lewis Burt" + } + ] + }, + { + "id": 21, + "guid": "7626cead-abce-4a91-a4a8-ef429d4e5fe2", + "isActive": true, + "balance": "$1,389.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Gladys Rivas", + "gender": "female", + "company": "Repetwire", + "email": "gladysrivas@repetwire.com", + "phone": "+1 (959) 453-2419", + "address": { + "street": 933, + "city": "Vallonia", + "state": "West Virginia", + "zip": 5349 + }, + "about": "Non sit est excepteur magna dolore consectetur ut tempor. Voluptate occaecat id est duis tempor et irure enim. Id nisi dolore sunt incididunt eiusmod proident irure. Labore consectetur veniam adipisicing anim labore qui ullamco ad exercitation incididunt dolore. Aute anim ea reprehenderit anim reprehenderit labore culpa. Adipisicing magna velit reprehenderit magna reprehenderit. Aute excepteur excepteur ipsum cupidatat consectetur nisi exercitation reprehenderit mollit sit amet nulla mollit sit.\r\n", + "registered": "1996-02-02T19:45:02+06:00", + "friends": [ + { + "id": 0, + "name": "Deidre Francis" + }, + { + "id": 1, + "name": "Dixon Morrow" + }, + { + "id": 2, + "name": "Talley Vasquez" + } + ] + }, + { + "id": 22, + "guid": "f389226a-e1d7-4f4e-9cc9-469e72500dbe", + "isActive": true, + "balance": "$3,230.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Pickett Britt", + "gender": "male", + "company": "Filodyne", + "email": "pickettbritt@filodyne.com", + "phone": "+1 (935) 509-2267", + "address": { + "street": 806, + "city": "Longbranch", + "state": "Oregon", + "zip": 4795 + }, + "about": "Minim fugiat sit sit adipisicing mollit deserunt anim consectetur consequat ullamco anim veniam nostrud. Anim anim exercitation qui commodo. Amet sunt non ad in ipsum fugiat ipsum dolor aute aute culpa minim. Pariatur laborum nulla sunt consectetur commodo enim consequat excepteur ad est veniam. Quis duis adipisicing eu aute ad laboris laborum occaecat tempor voluptate.\r\n", + "registered": "2010-04-04T02:24:05+05:00", + "friends": [ + { + "id": 0, + "name": "Garrett House" + }, + { + "id": 1, + "name": "Vaughn Haynes" + }, + { + "id": 2, + "name": "Esmeralda England" + } + ] + }, + { + "id": 23, + "guid": "ffde4469-85e9-4f87-a956-b91ccd4a33af", + "isActive": true, + "balance": "$3,646.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Ann Carrillo", + "gender": "female", + "company": "Nimon", + "email": "anncarrillo@nimon.com", + "phone": "+1 (852) 577-3425", + "address": { + "street": 382, + "city": "Mappsville", + "state": "Arizona", + "zip": 3617 + }, + "about": "Reprehenderit nostrud commodo laborum commodo voluptate cupidatat veniam minim sit Lorem. Cupidatat laborum labore nulla adipisicing aliqua consectetur ut irure veniam. Mollit deserunt ad proident sunt officia aliqua nisi. Consequat aliqua et reprehenderit qui labore ullamco magna enim sit exercitation cillum culpa duis.\r\n", + "registered": "1997-10-19T02:13:37+05:00", + "friends": [ + { + "id": 0, + "name": "Owen Black" + }, + { + "id": 1, + "name": "Amber Fischer" + }, + { + "id": 2, + "name": "Amie Eaton" + } + ] + }, + { + "id": 24, + "guid": "6692f76c-8a2e-47df-b24d-a545dffbd626", + "isActive": true, + "balance": "$3,461.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Glover Shaffer", + "gender": "male", + "company": "Aeora", + "email": "glovershaffer@aeora.com", + "phone": "+1 (861) 600-2289", + "address": { + "street": 702, + "city": "Harrodsburg", + "state": "Vermont", + "zip": 3324 + }, + "about": "Qui aute quis exercitation aute dolore ea sit veniam excepteur sint aute commodo. Est minim ea reprehenderit sit cupidatat. Nisi esse adipisicing esse elit consequat laborum. Sint Lorem ullamco nisi ipsum magna laborum magna ad adipisicing excepteur excepteur elit. Laboris veniam veniam ullamco laboris.\r\n", + "registered": "2006-11-04T07:28:54+05:00", + "friends": [ + { + "id": 0, + "name": "Kelli Head" + }, + { + "id": 1, + "name": "Jeannine Romero" + }, + { + "id": 2, + "name": "Pate Rollins" + } + ] + }, + { + "id": 25, + "guid": "1eafb0d1-e190-4aa8-a1f9-061eccedae62", + "isActive": true, + "balance": "$1,019.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Avery Adams", + "gender": "male", + "company": "Bolax", + "email": "averyadams@bolax.com", + "phone": "+1 (833) 568-3176", + "address": { + "street": 186, + "city": "Siglerville", + "state": "Iowa", + "zip": 3639 + }, + "about": "Cillum irure non excepteur tempor nisi magna ea cupidatat. Anim laboris labore anim aliqua aute incididunt ea deserunt dolor fugiat. Laborum duis esse elit adipisicing pariatur Lorem consequat. Do excepteur mollit cupidatat mollit proident reprehenderit ipsum est ad.\r\n", + "registered": "2012-07-14T23:27:18+05:00", + "friends": [ + { + "id": 0, + "name": "Eaton Potter" + }, + { + "id": 1, + "name": "Blair Dominguez" + }, + { + "id": 2, + "name": "Heidi Savage" + } + ] + }, + { + "id": 26, + "guid": "bfbdf4ca-034e-4022-9745-f8fd5cc57386", + "isActive": false, + "balance": "$1,911.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Whitley Maddox", + "gender": "male", + "company": "Quailcom", + "email": "whitleymaddox@quailcom.com", + "phone": "+1 (802) 570-2659", + "address": { + "street": 225, + "city": "Fidelis", + "state": "New York", + "zip": 4962 + }, + "about": "Cillum consequat reprehenderit exercitation aliquip sunt. Tempor excepteur cupidatat incididunt ut nisi reprehenderit. Est deserunt nulla ullamco sit aliqua nulla eiusmod eiusmod elit. Ea esse et nisi magna voluptate amet id esse enim mollit. Velit adipisicing duis dolor exercitation consectetur commodo mollit sunt do sunt commodo. Irure id amet minim mollit laboris.\r\n", + "registered": "2010-03-03T16:09:59+06:00", + "friends": [ + { + "id": 0, + "name": "Jeannie Pollard" + }, + { + "id": 1, + "name": "Gretchen Griffin" + }, + { + "id": 2, + "name": "Leticia Bradley" + } + ] + }, + { + "id": 27, + "guid": "c14fe44e-020a-42cf-8589-8a3ce0245316", + "isActive": false, + "balance": "$3,291.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Harris Cain", + "gender": "male", + "company": "Dancity", + "email": "harriscain@dancity.com", + "phone": "+1 (894) 491-2850", + "address": { + "street": 272, + "city": "Colton", + "state": "Michigan", + "zip": 2740 + }, + "about": "Magna veniam id minim qui ea est commodo dolor nulla laboris. Irure mollit ad incididunt consequat enim ex veniam consequat dolor cupidatat. Cillum amet consectetur consectetur non irure. Ea ullamco do est qui do. Anim ut aliquip ad ea elit deserunt ea sunt velit.\r\n", + "registered": "1998-03-04T16:55:11+06:00", + "friends": [ + { + "id": 0, + "name": "Pitts Daugherty" + }, + { + "id": 1, + "name": "Angie Bright" + }, + { + "id": 2, + "name": "Twila Holt" + } + ] + }, + { + "id": 28, + "guid": "6b954b89-7932-433b-8b7f-88cf2a18316e", + "isActive": true, + "balance": "$2,313.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Ramos Garner", + "gender": "male", + "company": "Kyaguru", + "email": "ramosgarner@kyaguru.com", + "phone": "+1 (955) 474-2021", + "address": { + "street": 725, + "city": "Cressey", + "state": "Mississippi", + "zip": 1260 + }, + "about": "Nostrud elit id sit laborum cillum. Amet aliquip mollit ea veniam. Ex tempor mollit ex aliquip in. Ea ullamco commodo eu sint amet nisi reprehenderit id aliquip. Eiusmod ipsum duis mollit magna aliquip qui aliquip. Cillum et laboris fugiat mollit ipsum ad esse proident proident. Nisi fugiat ipsum incididunt do eiusmod tempor velit fugiat ullamco sint quis occaecat tempor.\r\n", + "registered": "1994-05-09T21:35:57+05:00", + "friends": [ + { + "id": 0, + "name": "Eva Hines" + }, + { + "id": 1, + "name": "Nancy Quinn" + }, + { + "id": 2, + "name": "Craig Stewart" + } + ] + }, + { + "id": 29, + "guid": "d214a8fd-6bc6-4f40-a260-b7843c885d9a", + "isActive": true, + "balance": "$3,455.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Hanson Cooke", + "gender": "male", + "company": "Baluba", + "email": "hansoncooke@baluba.com", + "phone": "+1 (911) 401-2909", + "address": { + "street": 334, + "city": "Machias", + "state": "Utah", + "zip": 4910 + }, + "about": "Aute anim duis officia do sit irure ea do ex ea veniam ut aute. Ut ex officia culpa cupidatat ea aliqua nulla reprehenderit reprehenderit nisi. Est eu duis cillum cillum. Nisi qui Lorem anim sunt ea. Cillum nostrud est sint minim consequat id ea deserunt. Exercitation consequat pariatur in tempor sint aliquip qui sit nostrud.\r\n", + "registered": "1998-12-12T03:11:02+06:00", + "friends": [ + { + "id": 0, + "name": "Rosales Villarreal" + }, + { + "id": 1, + "name": "Clayton Dawson" + }, + { + "id": 2, + "name": "Lottie Solomon" + } + ] + }, + { + "id": 30, + "guid": "5c0c5c68-ea8e-4e28-907c-bdf4bc984730", + "isActive": true, + "balance": "$1,735.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Flora Perry", + "gender": "female", + "company": "Jimbies", + "email": "floraperry@jimbies.com", + "phone": "+1 (865) 537-2581", + "address": { + "street": 665, + "city": "Kieler", + "state": "Texas", + "zip": 8491 + }, + "about": "Cillum esse culpa laboris ut elit veniam irure elit culpa ipsum fugiat aute. Officia dolore adipisicing deserunt laboris mollit do sunt id. Amet commodo ad quis dolore.\r\n", + "registered": "1991-01-25T16:15:43+06:00", + "friends": [ + { + "id": 0, + "name": "Schmidt Osborne" + }, + { + "id": 1, + "name": "Camille Mckinney" + }, + { + "id": 2, + "name": "Stacie Murray" + } + ] + }, + { + "id": 31, + "guid": "c63d9a6e-d77e-44aa-8344-094f890d37e6", + "isActive": false, + "balance": "$1,443.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Laura Luna", + "gender": "female", + "company": "Eclipsent", + "email": "lauraluna@eclipsent.com", + "phone": "+1 (940) 595-2216", + "address": { + "street": 803, + "city": "Whitehaven", + "state": "North Dakota", + "zip": 630 + }, + "about": "Sit ut et elit fugiat non aute. Est magna eiusmod id minim voluptate qui sunt. Commodo quis adipisicing dolore in ullamco officia aute sit voluptate esse nostrud nostrud dolore reprehenderit.\r\n", + "registered": "1996-10-16T13:48:59+05:00", + "friends": [ + { + "id": 0, + "name": "Griffin Craig" + }, + { + "id": 1, + "name": "Odom Cross" + }, + { + "id": 2, + "name": "Linda Hendricks" + } + ] + }, + { + "id": 32, + "guid": "140792fb-87f9-416a-ba2d-14b783a31c3c", + "isActive": false, + "balance": "$3,734.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Singleton Lowery", + "gender": "male", + "company": "Isologica", + "email": "singletonlowery@isologica.com", + "phone": "+1 (994) 418-2085", + "address": { + "street": 805, + "city": "Haena", + "state": "South Carolina", + "zip": 5655 + }, + "about": "Reprehenderit sit do tempor fugiat sunt proident tempor anim magna velit fugiat quis. Et veniam labore aliqua eu nisi nulla aute in consequat exercitation consequat nisi. Ad elit tempor laboris et laboris do voluptate enim pariatur veniam.\r\n", + "registered": "2009-04-28T14:27:38+05:00", + "friends": [ + { + "id": 0, + "name": "Terrie Welch" + }, + { + "id": 1, + "name": "Bradley Sims" + }, + { + "id": 2, + "name": "Phillips Mcfadden" + } + ] + }, + { + "id": 33, + "guid": "33fa1014-43d4-4b11-8031-399fc48893a7", + "isActive": true, + "balance": "$1,146.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Tillman Carson", + "gender": "male", + "company": "Comcubine", + "email": "tillmancarson@comcubine.com", + "phone": "+1 (827) 522-2239", + "address": { + "street": 193, + "city": "Spelter", + "state": "Nebraska", + "zip": 1858 + }, + "about": "Aliquip labore pariatur pariatur sint eiusmod dolor et enim eu officia minim sit adipisicing. Anim pariatur sunt magna aute voluptate fugiat labore est amet magna pariatur sit. Ipsum consectetur sit officia fugiat labore cupidatat.\r\n", + "registered": "2005-08-16T04:37:46+05:00", + "friends": [ + { + "id": 0, + "name": "Paige Sellers" + }, + { + "id": 1, + "name": "Leigh Charles" + }, + { + "id": 2, + "name": "Cabrera Ayala" + } + ] + }, + { + "id": 34, + "guid": "b9d1897a-cb27-4f25-b6e2-eea13d7de088", + "isActive": false, + "balance": "$2,423.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Francis Deleon", + "gender": "female", + "company": "Ebidco", + "email": "francisdeleon@ebidco.com", + "phone": "+1 (846) 453-2087", + "address": { + "street": 388, + "city": "Cartwright", + "state": "New Jersey", + "zip": 4016 + }, + "about": "Nulla dolor et ut fugiat labore. Ea aliquip in ex ex laborum. Dolore minim nulla sit cupidatat incididunt esse nulla culpa aliqua et reprehenderit. Eiusmod ex quis aliqua eiusmod. Aute nisi excepteur culpa reprehenderit.\r\n", + "registered": "2013-05-28T20:34:57+05:00", + "friends": [ + { + "id": 0, + "name": "Carlson Figueroa" + }, + { + "id": 1, + "name": "Webb Larsen" + }, + { + "id": 2, + "name": "Dorothea Wooten" + } + ] + }, + { + "id": 35, + "guid": "4e7a5262-b1d5-479d-a6df-32a457024800", + "isActive": false, + "balance": "$2,854.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Alston Lloyd", + "gender": "male", + "company": "Menbrain", + "email": "alstonlloyd@menbrain.com", + "phone": "+1 (886) 518-3247", + "address": { + "street": 345, + "city": "Stonybrook", + "state": "Indiana", + "zip": 9728 + }, + "about": "Ut in nostrud qui consequat minim ea tempor do id. Elit aliqua excepteur ut elit aliqua commodo et in mollit dolor mollit deserunt sit dolore. Mollit deserunt veniam voluptate pariatur laborum nostrud aute ullamco mollit occaecat aute sunt.\r\n", + "registered": "1999-10-28T05:02:16+05:00", + "friends": [ + { + "id": 0, + "name": "Mollie Lee" + }, + { + "id": 1, + "name": "Wilcox Kinney" + }, + { + "id": 2, + "name": "Louisa Smith" + } + ] + }, + { + "id": 36, + "guid": "50fd8949-8a9a-4840-aaa5-f57c421d683a", + "isActive": true, + "balance": "$2,079.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Susana Dejesus", + "gender": "female", + "company": "Nixelt", + "email": "susanadejesus@nixelt.com", + "phone": "+1 (938) 550-3084", + "address": { + "street": 687, + "city": "Byrnedale", + "state": "Wyoming", + "zip": 6054 + }, + "about": "Et nulla do do adipisicing eiusmod ut mollit sunt est excepteur. Magna duis nulla minim tempor velit officia. Anim tempor amet labore veniam. Cillum reprehenderit ut dolore ut cupidatat amet Lorem irure eiusmod eiusmod et sunt minim. Veniam veniam nulla ea in et mollit ullamco deserunt anim voluptate. Consequat sit occaecat irure Lorem laborum qui magna consequat pariatur proident.\r\n", + "registered": "2001-07-28T08:40:28+05:00", + "friends": [ + { + "id": 0, + "name": "Lily Sheppard" + }, + { + "id": 1, + "name": "Antonia Clemons" + }, + { + "id": 2, + "name": "Kristine Albert" + } + ] + }, + { + "id": 37, + "guid": "0eecbe31-ae4d-41d2-95c8-9a7239748018", + "isActive": true, + "balance": "$3,576.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Melanie Butler", + "gender": "female", + "company": "Satiance", + "email": "melaniebutler@satiance.com", + "phone": "+1 (896) 486-3851", + "address": { + "street": 866, + "city": "Irwin", + "state": "Kansas", + "zip": 9758 + }, + "about": "Laborum et non adipisicing enim. Non labore dolor adipisicing irure qui pariatur. Sunt ad consequat consequat magna enim in elit in. Duis reprehenderit irure nulla est velit est adipisicing voluptate quis qui velit labore ad. Minim esse aliquip quis Lorem amet commodo aute amet sunt sunt commodo Lorem ullamco. Ad Lorem ullamco elit est exercitation magna et.\r\n", + "registered": "1990-09-16T09:14:54+05:00", + "friends": [ + { + "id": 0, + "name": "Tracie Harvey" + }, + { + "id": 1, + "name": "Kemp Odonnell" + }, + { + "id": 2, + "name": "Deleon Spears" + } + ] + }, + { + "id": 38, + "guid": "0beb9d8a-7801-4557-a917-73639484cf22", + "isActive": false, + "balance": "$1,718.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Kathy Knowles", + "gender": "female", + "company": "Bunga", + "email": "kathyknowles@bunga.com", + "phone": "+1 (833) 547-2147", + "address": { + "street": 866, + "city": "Avalon", + "state": "Massachusetts", + "zip": 640 + }, + "about": "Esse fugiat voluptate exercitation sunt. Deserunt do incididunt nostrud est est Lorem deserunt adipisicing officia. Elit labore commodo est nostrud culpa amet amet exercitation irure veniam Lorem.\r\n", + "registered": "1996-12-03T23:03:14+06:00", + "friends": [ + { + "id": 0, + "name": "Elsie Mcdaniel" + }, + { + "id": 1, + "name": "Luella Dale" + }, + { + "id": 2, + "name": "Riley Landry" + } + ] + }, + { + "id": 39, + "guid": "04e916cb-ff19-40ea-acc2-6832e19879b9", + "isActive": false, + "balance": "$2,298.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Haley Case", + "gender": "female", + "company": "Eventix", + "email": "haleycase@eventix.com", + "phone": "+1 (814) 466-3133", + "address": { + "street": 932, + "city": "Brandywine", + "state": "Ohio", + "zip": 757 + }, + "about": "Laboris sunt nostrud velit mollit ea labore excepteur anim duis. Elit consequat eu ea ipsum. Cillum duis cupidatat amet reprehenderit. Commodo commodo ullamco incididunt aliquip reprehenderit id labore ut mollit aliqua dolore cupidatat minim qui.\r\n", + "registered": "2010-03-15T19:45:04+05:00", + "friends": [ + { + "id": 0, + "name": "French Forbes" + }, + { + "id": 1, + "name": "Conner Conner" + }, + { + "id": 2, + "name": "Sheila Bentley" + } + ] + }, + { + "id": 40, + "guid": "da2d737e-fa3f-47b3-b08b-a387e14af16e", + "isActive": true, + "balance": "$1,219.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Knapp Singleton", + "gender": "male", + "company": "Kaggle", + "email": "knappsingleton@kaggle.com", + "phone": "+1 (977) 417-3304", + "address": { + "street": 496, + "city": "Dunnavant", + "state": "New Mexico", + "zip": 2885 + }, + "about": "Do occaecat minim esse culpa adipisicing proident et est nulla ipsum anim dolor voluptate et. Sunt culpa ea pariatur laborum sunt sint nulla consectetur qui. Anim dolor mollit adipisicing pariatur voluptate est reprehenderit minim. Laborum laborum excepteur ullamco tempor incididunt quis id consequat aute est. Id culpa officia eu proident Lorem.\r\n", + "registered": "1997-11-09T09:45:31+06:00", + "friends": [ + { + "id": 0, + "name": "Romero Cook" + }, + { + "id": 1, + "name": "Brock Dillon" + }, + { + "id": 2, + "name": "Warner Cantrell" + } + ] + }, + { + "id": 41, + "guid": "5eafd295-20f5-4d35-b755-ce800b00f0c0", + "isActive": false, + "balance": "$2,247.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Lindsay Reilly", + "gender": "male", + "company": "Nurplex", + "email": "lindsayreilly@nurplex.com", + "phone": "+1 (831) 568-3942", + "address": { + "street": 963, + "city": "Wattsville", + "state": "Hawaii", + "zip": 8190 + }, + "about": "Aliqua tempor enim est elit. Aliquip voluptate enim incididunt culpa est do. Magna cillum quis dolore cupidatat laborum.\r\n", + "registered": "2003-08-26T21:42:50+05:00", + "friends": [ + { + "id": 0, + "name": "Franks Levy" + }, + { + "id": 1, + "name": "Elvira Holland" + }, + { + "id": 2, + "name": "Elisabeth Rowland" + } + ] + }, + { + "id": 42, + "guid": "b0ccd025-f823-4f5d-abc5-3b68f2e0e2c8", + "isActive": true, + "balance": "$1,788.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Snyder Snider", + "gender": "male", + "company": "Maximind", + "email": "snydersnider@maximind.com", + "phone": "+1 (944) 470-2621", + "address": { + "street": 547, + "city": "Hondah", + "state": "Tennessee", + "zip": 6902 + }, + "about": "Culpa sit veniam Lorem mollit laboris ad aliqua labore esse officia incididunt aliqua. Et esse tempor magna in ad incididunt tempor minim id et occaecat est occaecat nostrud. Nostrud cillum non veniam dolore reprehenderit aute est nisi occaecat officia.\r\n", + "registered": "2005-01-26T19:48:35+06:00", + "friends": [ + { + "id": 0, + "name": "Susanne Sherman" + }, + { + "id": 1, + "name": "Wall Leonard" + }, + { + "id": 2, + "name": "Fitzpatrick Shannon" + } + ] + }, + { + "id": 43, + "guid": "b191ff8e-bcf5-483c-bf53-be40bfdb05f0", + "isActive": false, + "balance": "$3,842.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Flores Rowe", + "gender": "male", + "company": "Digigen", + "email": "floresrowe@digigen.com", + "phone": "+1 (817) 456-3028", + "address": { + "street": 655, + "city": "Lisco", + "state": "Washington", + "zip": 8154 + }, + "about": "Duis sit cillum irure elit veniam. Do ut esse ipsum occaecat Lorem qui eu ea ut deserunt aute elit. Sint labore qui dolor sunt ex occaecat ea proident laborum minim enim veniam.\r\n", + "registered": "2002-02-07T13:40:17+06:00", + "friends": [ + { + "id": 0, + "name": "Skinner Finch" + }, + { + "id": 1, + "name": "Janell Dalton" + }, + { + "id": 2, + "name": "Mandy Estrada" + } + ] + }, + { + "id": 44, + "guid": "07a65893-6f53-46a9-8e62-4250003de0d9", + "isActive": true, + "balance": "$2,138.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Haynes Woodward", + "gender": "male", + "company": "Flumbo", + "email": "hayneswoodward@flumbo.com", + "phone": "+1 (805) 573-3161", + "address": { + "street": 926, + "city": "Manitou", + "state": "Idaho", + "zip": 6356 + }, + "about": "Enim fugiat cupidatat duis incididunt. Culpa esse nisi culpa consectetur eu laborum amet officia sit id voluptate voluptate. Ullamco enim commodo labore elit velit in. Incididunt veniam velit nostrud ut nulla mollit elit tempor sit. Laborum qui officia officia et deserunt laboris in esse ad nisi nisi. Nostrud dolore mollit excepteur nulla ut velit voluptate amet consectetur quis.\r\n", + "registered": "1988-01-06T17:05:05+06:00", + "friends": [ + { + "id": 0, + "name": "Margery Caldwell" + }, + { + "id": 1, + "name": "Cathryn Marsh" + }, + { + "id": 2, + "name": "Francine Wolfe" + } + ] + }, + { + "id": 45, + "guid": "2bd10e2d-669b-48d6-8c8e-c7ae73b3a5f6", + "isActive": false, + "balance": "$3,979.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Morgan Sanford", + "gender": "female", + "company": "Darwinium", + "email": "morgansanford@darwinium.com", + "phone": "+1 (894) 444-2551", + "address": { + "street": 517, + "city": "Eden", + "state": "Illinois", + "zip": 9068 + }, + "about": "Id commodo sit ullamco ad. Duis fugiat occaecat cupidatat tempor mollit et. Est voluptate mollit nisi sit consequat sit amet. Voluptate aliquip fugiat esse mollit aute esse est ea consequat minim voluptate veniam.\r\n", + "registered": "1998-12-13T11:20:50+06:00", + "friends": [ + { + "id": 0, + "name": "Reba Pace" + }, + { + "id": 1, + "name": "Tate Hendrix" + }, + { + "id": 2, + "name": "Terry Lott" + } + ] + }, + { + "id": 46, + "guid": "a7372f53-7b30-470b-a84f-3c1476b3e3a6", + "isActive": false, + "balance": "$1,721.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Gregory Reese", + "gender": "male", + "company": "Anacho", + "email": "gregoryreese@anacho.com", + "phone": "+1 (939) 559-2659", + "address": { + "street": 609, + "city": "Elbert", + "state": "Missouri", + "zip": 3362 + }, + "about": "Pariatur sunt pariatur ea dolor id ut pariatur consequat. Cupidatat velit reprehenderit ut proident exercitation. Elit labore proident occaecat exercitation. Ad nisi in aute labore quis do.\r\n", + "registered": "2008-08-25T12:10:41+05:00", + "friends": [ + { + "id": 0, + "name": "Wilma Bowman" + }, + { + "id": 1, + "name": "Bowers Chen" + }, + { + "id": 2, + "name": "Ortega Hodge" + } + ] + }, + { + "id": 47, + "guid": "364e7dd7-fee4-4b85-b6ff-3bc7e3c9b99f", + "isActive": false, + "balance": "$2,463.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Gail Hammond", + "gender": "female", + "company": "Elemantra", + "email": "gailhammond@elemantra.com", + "phone": "+1 (844) 439-2713", + "address": { + "street": 928, + "city": "Allendale", + "state": "Alaska", + "zip": 3114 + }, + "about": "Qui incididunt deserunt consequat veniam ex incididunt qui tempor non deserunt sint exercitation do minim. Cupidatat est exercitation aute non anim ut ullamco nisi dolore cillum eiusmod. Nulla id ad magna mollit qui sit non velit irure exercitation ipsum. Laborum fugiat reprehenderit sunt ex.\r\n", + "registered": "1990-10-29T13:42:29+05:00", + "friends": [ + { + "id": 0, + "name": "Callie Palmer" + }, + { + "id": 1, + "name": "Amanda Lowe" + }, + { + "id": 2, + "name": "Alisha Hardy" + } + ] + }, + { + "id": 48, + "guid": "4446cfa2-da6e-42dc-a91a-67a63e186378", + "isActive": false, + "balance": "$2,667.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Marquita Witt", + "gender": "female", + "company": "Xumonk", + "email": "marquitawitt@xumonk.com", + "phone": "+1 (914) 591-2928", + "address": { + "street": 482, + "city": "Islandia", + "state": "California", + "zip": 1402 + }, + "about": "Esse ea culpa aliquip consectetur deserunt velit dolore sunt ullamco commodo fugiat cupidatat deserunt. Ad elit cillum ipsum enim eiusmod ex consequat do elit excepteur. Nisi aliqua et aliqua magna. Culpa est labore sunt consectetur incididunt ut incididunt fugiat magna. Esse anim non qui cupidatat dolor adipisicing proident et proident. Sint eu officia ad excepteur elit in eu ipsum irure. Irure non aliqua consectetur ea officia non ipsum quis elit non ea Lorem.\r\n", + "registered": "2004-12-14T11:57:29+06:00", + "friends": [ + { + "id": 0, + "name": "Sanford Rocha" + }, + { + "id": 1, + "name": "Tara Berg" + }, + { + "id": 2, + "name": "Gamble Mayo" + } + ] + }, + { + "id": 49, + "guid": "d289ae6d-f97f-427b-9b38-6e75912aeeea", + "isActive": false, + "balance": "$2,000.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Rosemarie Norton", + "gender": "female", + "company": "Translink", + "email": "rosemarienorton@translink.com", + "phone": "+1 (989) 575-3632", + "address": { + "street": 518, + "city": "Eagletown", + "state": "Wisconsin", + "zip": 522 + }, + "about": "Nisi aliquip cillum culpa dolor laborum et. Mollit sint in et veniam consequat aliqua tempor proident anim est cupidatat. Excepteur cupidatat dolore esse duis. Quis officia irure nulla proident. Est commodo labore id anim exercitation officia culpa.\r\n", + "registered": "1998-10-13T16:52:13+05:00", + "friends": [ + { + "id": 0, + "name": "Lucia Colon" + }, + { + "id": 1, + "name": "Tia Richmond" + }, + { + "id": 2, + "name": "Freida Maddox" + } + ] + }, + { + "id": 50, + "guid": "904049e1-c5ed-45c2-bd6c-cc461f3d8b16", + "isActive": false, + "balance": "$2,645.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Guerrero Lopez", + "gender": "male", + "company": "Techmania", + "email": "guerrerolopez@techmania.com", + "phone": "+1 (894) 408-2426", + "address": { + "street": 974, + "city": "Vincent", + "state": "West Virginia", + "zip": 9020 + }, + "about": "Ut consectetur tempor laborum incididunt sunt commodo laboris dolor culpa id eiusmod culpa eu qui. Aliquip qui culpa Lorem irure enim dolore aliquip. Excepteur qui velit exercitation nisi exercitation excepteur dolor magna. Do ea irure nostrud est id ex velit Lorem irure nisi nostrud Lorem proident.\r\n", + "registered": "2009-12-02T13:56:28+06:00", + "friends": [ + { + "id": 0, + "name": "Miranda Guerra" + }, + { + "id": 1, + "name": "Yesenia Sellers" + }, + { + "id": 2, + "name": "Deloris Barr" + } + ] + }, + { + "id": 51, + "guid": "8c25311e-995d-4615-84fb-5c4d159dd523", + "isActive": false, + "balance": "$2,150.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Morse Mendoza", + "gender": "male", + "company": "Eyewax", + "email": "morsemendoza@eyewax.com", + "phone": "+1 (881) 412-2829", + "address": { + "street": 158, + "city": "Mansfield", + "state": "Montana", + "zip": 1153 + }, + "about": "Velit Lorem aliquip est cillum commodo exercitation laboris non sit laboris nulla deserunt minim consectetur. Cillum culpa id quis sunt voluptate est laborum. Excepteur do fugiat amet officia officia magna excepteur ullamco ipsum veniam duis cillum. Sit culpa reprehenderit commodo qui et velit eiusmod mollit pariatur aliqua nostrud veniam Lorem occaecat.\r\n", + "registered": "2008-08-29T09:54:48+05:00", + "friends": [ + { + "id": 0, + "name": "Hawkins Hood" + }, + { + "id": 1, + "name": "Jacobson Hinton" + }, + { + "id": 2, + "name": "Rae Byers" + } + ] + }, + { + "id": 52, + "guid": "ff4d3523-d595-4efc-8032-de493dd14d83", + "isActive": false, + "balance": "$1,553.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Bernadette Dorsey", + "gender": "female", + "company": "Zentia", + "email": "bernadettedorsey@zentia.com", + "phone": "+1 (926) 599-2987", + "address": { + "street": 330, + "city": "Waikele", + "state": "Alabama", + "zip": 8485 + }, + "about": "Nulla velit occaecat non ad ullamco nostrud pariatur laborum Lorem commodo id ea. Commodo nostrud irure consequat Lorem ullamco laborum exercitation laborum. Cupidatat nisi eu elit esse commodo veniam sunt sunt magna consectetur sunt aute. Sint aute sit sint magna culpa officia. Est ad officia ad nisi nostrud consectetur sint. Et reprehenderit nostrud Lorem fugiat tempor consequat cupidatat mollit laboris.\r\n", + "registered": "1999-04-09T01:39:51+05:00", + "friends": [ + { + "id": 0, + "name": "Debra Jackson" + }, + { + "id": 1, + "name": "Abigail Norris" + }, + { + "id": 2, + "name": "Riddle Murray" + } + ] + }, + { + "id": 53, + "guid": "3643fe10-3aa9-41d5-8d12-4914421804d0", + "isActive": true, + "balance": "$2,459.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Valencia Poole", + "gender": "male", + "company": "Geekola", + "email": "valenciapoole@geekola.com", + "phone": "+1 (824) 562-2593", + "address": { + "street": 964, + "city": "Skyland", + "state": "Florida", + "zip": 8561 + }, + "about": "Et dolore aliqua laboris non commodo nostrud velit sunt anim laborum ut laboris. In ex est in consectetur et et esse qui magna labore ad. Magna Lorem sunt nostrud reprehenderit eu ad qui occaecat mollit do. Ex nostrud et qui nulla consequat. Deserunt do adipisicing eiusmod commodo nisi laboris eiusmod. Dolor dolore dolor exercitation anim commodo quis excepteur.\r\n", + "registered": "2011-06-14T11:37:53+05:00", + "friends": [ + { + "id": 0, + "name": "Herring Martin" + }, + { + "id": 1, + "name": "Horton Paul" + }, + { + "id": 2, + "name": "Foreman Cook" + } + ] + }, + { + "id": 54, + "guid": "30edc68c-6eb7-47e2-837f-9335156cd08f", + "isActive": false, + "balance": "$2,628.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Santiago Thornton", + "gender": "male", + "company": "Aeora", + "email": "santiagothornton@aeora.com", + "phone": "+1 (928) 405-3248", + "address": { + "street": 148, + "city": "Canterwood", + "state": "Texas", + "zip": 7679 + }, + "about": "Veniam est voluptate irure ut tempor duis duis labore. Cupidatat velit reprehenderit ex sint nulla proident esse dolor. Irure ad enim dolor do cillum do Lorem duis irure voluptate magna aliqua consequat voluptate. Nisi aute mollit ut officia id Lorem cupidatat quis dolore veniam ipsum.\r\n", + "registered": "1999-07-01T01:39:53+05:00", + "friends": [ + { + "id": 0, + "name": "Tucker Oneil" + }, + { + "id": 1, + "name": "Kate Long" + }, + { + "id": 2, + "name": "Roxie Norton" + } + ] + }, + { + "id": 55, + "guid": "ed37360b-5356-4639-ab47-fbc0abc1860e", + "isActive": true, + "balance": "$1,957.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Ursula Velez", + "gender": "female", + "company": "Veraq", + "email": "ursulavelez@veraq.com", + "phone": "+1 (887) 450-3179", + "address": { + "street": 726, + "city": "Galesville", + "state": "Pennsylvania", + "zip": 3629 + }, + "about": "Nisi exercitation in nisi nostrud officia ex ut laboris veniam minim dolor. Minim cillum nostrud aliquip ullamco et do dolor. Reprehenderit aute adipisicing officia sunt irure ex veniam sunt sunt. Excepteur amet aute ut quis culpa consectetur incididunt. Enim occaecat nulla duis consequat sint excepteur tempor adipisicing ipsum sint eu minim ut veniam. Elit enim ipsum proident exercitation aliquip.\r\n", + "registered": "2011-11-13T09:25:32+06:00", + "friends": [ + { + "id": 0, + "name": "Holcomb Small" + }, + { + "id": 1, + "name": "Veronica Leblanc" + }, + { + "id": 2, + "name": "Elvia Snider" + } + ] + }, + { + "id": 56, + "guid": "212510c8-d8ea-4ff1-9a99-e61c4aa5f8f3", + "isActive": false, + "balance": "$1,544.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Kelley Carlson", + "gender": "female", + "company": "Norsup", + "email": "kelleycarlson@norsup.com", + "phone": "+1 (908) 437-3943", + "address": { + "street": 496, + "city": "Tonopah", + "state": "New Hampshire", + "zip": 1935 + }, + "about": "Eiusmod et sunt labore laboris cupidatat sint incididunt elit. Tempor reprehenderit aliquip exercitation commodo nostrud sint non Lorem exercitation sit tempor eu nulla reprehenderit. Ipsum commodo excepteur excepteur proident proident non consequat tempor cillum sit ea voluptate.\r\n", + "registered": "2002-02-18T00:58:12+06:00", + "friends": [ + { + "id": 0, + "name": "Karen Hicks" + }, + { + "id": 1, + "name": "Sosa Robinson" + }, + { + "id": 2, + "name": "Fuentes Martinez" + } + ] + }, + { + "id": 57, + "guid": "d2ab2e12-548c-482d-a0e7-3e970377f12c", + "isActive": false, + "balance": "$1,783.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Twila Davenport", + "gender": "female", + "company": "Teraprene", + "email": "twiladavenport@teraprene.com", + "phone": "+1 (997) 523-2336", + "address": { + "street": 477, + "city": "Trinway", + "state": "Nebraska", + "zip": 4183 + }, + "about": "Duis nostrud aliqua excepteur Lorem nisi eiusmod occaecat eu elit quis consequat consequat excepteur. Sint labore pariatur non voluptate. Anim culpa deserunt ex excepteur magna. Aute veniam velit laboris tempor dolor exercitation. Nisi aute dolor id minim occaecat laborum nostrud minim. Cillum mollit eiusmod consequat duis fugiat Lorem nisi Lorem ea Lorem cillum.\r\n", + "registered": "2003-05-14T13:20:27+05:00", + "friends": [ + { + "id": 0, + "name": "Gabriela Myers" + }, + { + "id": 1, + "name": "Lyons Weiss" + }, + { + "id": 2, + "name": "Marietta Dodson" + } + ] + }, + { + "id": 58, + "guid": "307bb1cf-351f-4442-b7f5-33225ec9b61c", + "isActive": false, + "balance": "$3,636.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Eunice Mcgowan", + "gender": "female", + "company": "Podunk", + "email": "eunicemcgowan@podunk.com", + "phone": "+1 (961) 557-3704", + "address": { + "street": 387, + "city": "Clarksburg", + "state": "Hawaii", + "zip": 7041 + }, + "about": "Sint ullamco sunt mollit reprehenderit proident dolor id non occaecat commodo. Anim eiusmod eu laborum adipisicing qui esse tempor tempor duis do. Aliquip occaecat fugiat dolore deserunt fugiat. Consectetur mollit duis quis proident consectetur adipisicing incididunt veniam.\r\n", + "registered": "2003-02-24T14:09:55+06:00", + "friends": [ + { + "id": 0, + "name": "Gay Burke" + }, + { + "id": 1, + "name": "Vargas Sykes" + }, + { + "id": 2, + "name": "Teresa Haney" + } + ] + }, + { + "id": 59, + "guid": "fee4256d-29d3-4e66-8236-51ef7ad9107f", + "isActive": true, + "balance": "$2,112.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Martinez Ferrell", + "gender": "male", + "company": "Cipromox", + "email": "martinezferrell@cipromox.com", + "phone": "+1 (957) 434-2527", + "address": { + "street": 529, + "city": "Escondida", + "state": "Idaho", + "zip": 1793 + }, + "about": "Amet ad quis nisi proident veniam magna non. Pariatur occaecat mollit dolore do ea ad labore magna et eu nulla dolor mollit deserunt. Voluptate irure fugiat exercitation et non laborum exercitation. Esse ea qui elit qui aute minim sint anim qui. Quis aute velit ad ex amet amet voluptate sit veniam tempor esse tempor culpa laboris. Ullamco sunt ipsum voluptate ex esse velit exercitation aliquip. Velit deserunt id officia nisi duis anim est eiusmod do veniam elit ipsum Lorem.\r\n", + "registered": "1994-07-13T20:52:59+05:00", + "friends": [ + { + "id": 0, + "name": "Inez Horn" + }, + { + "id": 1, + "name": "Williamson Gutierrez" + }, + { + "id": 2, + "name": "Porter Santiago" + } + ] + }, + { + "id": 60, + "guid": "e8faa7b5-1bb0-4d85-bfab-d409e279de15", + "isActive": false, + "balance": "$2,873.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Georgina Stanton", + "gender": "female", + "company": "Tropolis", + "email": "georginastanton@tropolis.com", + "phone": "+1 (847) 434-2483", + "address": { + "street": 993, + "city": "Riceville", + "state": "Colorado", + "zip": 9064 + }, + "about": "Nulla tempor exercitation ipsum aute elit et magna nisi. Duis enim reprehenderit non est. Reprehenderit cupidatat fugiat adipisicing Lorem deserunt nostrud. Incididunt enim labore adipisicing anim et. Sit exercitation dolore do mollit irure ullamco laboris ea nisi enim mollit pariatur. Adipisicing sint velit sit fugiat commodo cillum non sint adipisicing amet. Laborum culpa tempor culpa et elit nostrud.\r\n", + "registered": "2012-06-14T01:47:56+05:00", + "friends": [ + { + "id": 0, + "name": "Maude Schultz" + }, + { + "id": 1, + "name": "Laurel Nelson" + }, + { + "id": 2, + "name": "Mariana Bridges" + } + ] + }, + { + "id": 61, + "guid": "e0f8047b-9d4f-40f4-82dd-fa12e4961dfb", + "isActive": false, + "balance": "$3,723.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Lenore Sargent", + "gender": "female", + "company": "Aquacine", + "email": "lenoresargent@aquacine.com", + "phone": "+1 (903) 593-3818", + "address": { + "street": 463, + "city": "Berwind", + "state": "Illinois", + "zip": 4098 + }, + "about": "Esse mollit ad elit mollit mollit. Dolore do Lorem occaecat ex. Deserunt id aliquip et anim incididunt laborum magna. Ipsum elit ad elit excepteur. Exercitation amet commodo consectetur esse mollit id commodo pariatur id. Ullamco tempor velit adipisicing amet ad magna sit.\r\n", + "registered": "1988-11-12T16:15:17+06:00", + "friends": [ + { + "id": 0, + "name": "Pat Gilmore" + }, + { + "id": 1, + "name": "Maggie Atkinson" + }, + { + "id": 2, + "name": "Miles Lawrence" + } + ] + }, + { + "id": 62, + "guid": "cc501132-8ad1-4dba-91bf-19f3d9f7ff17", + "isActive": true, + "balance": "$1,543.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Jan Guzman", + "gender": "female", + "company": "Zytrac", + "email": "janguzman@zytrac.com", + "phone": "+1 (809) 585-2088", + "address": { + "street": 381, + "city": "Martell", + "state": "North Carolina", + "zip": 4000 + }, + "about": "Lorem aliqua veniam nostrud consequat sint ad Lorem occaecat do non. Irure anim cupidatat eu veniam consequat consectetur qui enim duis aute esse adipisicing qui. Adipisicing quis exercitation ad Lorem occaecat est laborum ea ea quis cillum elit eu. Cillum aliquip duis mollit occaecat anim duis magna nisi.\r\n", + "registered": "1993-12-07T04:26:20+06:00", + "friends": [ + { + "id": 0, + "name": "Edith Good" + }, + { + "id": 1, + "name": "Ellison Ortega" + }, + { + "id": 2, + "name": "Hines Green" + } + ] + }, + { + "id": 63, + "guid": "38e1c58b-64b2-4ba9-8151-ac541a50010f", + "isActive": false, + "balance": "$3,430.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Larsen Ortiz", + "gender": "male", + "company": "Furnitech", + "email": "larsenortiz@furnitech.com", + "phone": "+1 (868) 421-2159", + "address": { + "street": 648, + "city": "Beechmont", + "state": "Virginia", + "zip": 7812 + }, + "about": "Sunt duis incididunt fugiat sint. Sit cillum culpa cupidatat commodo sint adipisicing aliqua esse. Lorem nulla veniam enim adipisicing amet quis sit fugiat consequat amet aliquip.\r\n", + "registered": "2008-12-01T03:19:23+06:00", + "friends": [ + { + "id": 0, + "name": "Jacqueline Lowe" + }, + { + "id": 1, + "name": "Lelia Vaughn" + }, + { + "id": 2, + "name": "Bernard Becker" + } + ] + }, + { + "id": 64, + "guid": "0d194893-f02b-4746-b42c-2221c60c0b87", + "isActive": false, + "balance": "$2,589.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Traci Hobbs", + "gender": "female", + "company": "Prosely", + "email": "tracihobbs@prosely.com", + "phone": "+1 (857) 551-3765", + "address": { + "street": 212, + "city": "Avoca", + "state": "Alaska", + "zip": 8153 + }, + "about": "Ad veniam nostrud occaecat enim reprehenderit commodo deserunt ipsum aliqua exercitation nostrud. Commodo esse proident cillum officia irure sunt. Labore labore exercitation amet cillum sunt est. Consequat velit amet nostrud sit sunt non quis incididunt ad nostrud. Amet pariatur voluptate minim non minim in nostrud labore fugiat nulla fugiat. Velit est quis reprehenderit sunt laboris consectetur.\r\n", + "registered": "1997-02-05T11:20:29+06:00", + "friends": [ + { + "id": 0, + "name": "Colon Greer" + }, + { + "id": 1, + "name": "Andrea Brady" + }, + { + "id": 2, + "name": "Kelli Miller" + } + ] + }, + { + "id": 65, + "guid": "cecacc96-a4f7-406f-96cf-c92e95d58310", + "isActive": true, + "balance": "$1,983.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Phyllis Kidd", + "gender": "female", + "company": "Turnabout", + "email": "phylliskidd@turnabout.com", + "phone": "+1 (962) 497-2199", + "address": { + "street": 280, + "city": "Yogaville", + "state": "Oregon", + "zip": 2261 + }, + "about": "Ex exercitation sit cupidatat commodo ea sit. Non minim occaecat laboris qui enim eiusmod officia. Labore sint reprehenderit ea mollit dolor cupidatat ut sunt tempor anim enim.\r\n", + "registered": "2003-12-13T07:21:22+06:00", + "friends": [ + { + "id": 0, + "name": "Vickie Cannon" + }, + { + "id": 1, + "name": "Norris Lamb" + }, + { + "id": 2, + "name": "Kerr Kinney" + } + ] + }, + { + "id": 66, + "guid": "59777b45-c242-40c7-a5b6-6002fd50a207", + "isActive": true, + "balance": "$2,137.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Kellie Collins", + "gender": "female", + "company": "Kangle", + "email": "kelliecollins@kangle.com", + "phone": "+1 (886) 594-2104", + "address": { + "street": 466, + "city": "Saranap", + "state": "Missouri", + "zip": 9385 + }, + "about": "Dolore amet ea et qui laborum ut quis aliquip nostrud exercitation eu veniam. Nisi ut velit incididunt adipisicing quis eu ex commodo. Irure minim dolor in velit proident ullamco. Est sint do anim magna elit nostrud ut eu. Eu aliqua nulla Lorem elit. Dolor ipsum velit magna dolor laboris dolore sit excepteur in do occaecat consequat.\r\n", + "registered": "1993-10-24T20:41:38+05:00", + "friends": [ + { + "id": 0, + "name": "Mcpherson Bowers" + }, + { + "id": 1, + "name": "Sears Meadows" + }, + { + "id": 2, + "name": "Short Barrett" + } + ] + }, + { + "id": 67, + "guid": "e2804e7e-5497-4a4a-8b52-cece17662c70", + "isActive": true, + "balance": "$3,457.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Lynne Lane", + "gender": "female", + "company": "Zogak", + "email": "lynnelane@zogak.com", + "phone": "+1 (927) 486-2424", + "address": { + "street": 622, + "city": "Sussex", + "state": "Iowa", + "zip": 7849 + }, + "about": "Elit qui adipisicing commodo non in irure magna excepteur esse Lorem magna mollit consequat. Ut qui voluptate consequat do commodo aute cupidatat occaecat excepteur officia. Exercitation anim aliquip veniam deserunt nostrud do laborum. Sint excepteur non ut eiusmod.\r\n", + "registered": "2000-07-27T03:34:05+05:00", + "friends": [ + { + "id": 0, + "name": "Jacquelyn Buck" + }, + { + "id": 1, + "name": "Sullivan Douglas" + }, + { + "id": 2, + "name": "Helen Beck" + } + ] + }, + { + "id": 68, + "guid": "00d33efb-6dca-4d4a-baed-d8d83da7c518", + "isActive": false, + "balance": "$1,944.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Daisy Hamilton", + "gender": "female", + "company": "Pulze", + "email": "daisyhamilton@pulze.com", + "phone": "+1 (943) 496-2065", + "address": { + "street": 188, + "city": "Lupton", + "state": "New Jersey", + "zip": 333 + }, + "about": "Ipsum ullamco ad ea eiusmod. Elit excepteur ut voluptate do cupidatat eu. Nisi excepteur ut nostrud sunt anim labore reprehenderit eu. Proident culpa ad incididunt reprehenderit consequat velit ea consectetur nisi labore excepteur. Consequat proident est ut sunt incididunt consectetur aliquip ullamco.\r\n", + "registered": "1992-06-16T14:46:47+05:00", + "friends": [ + { + "id": 0, + "name": "Regina Dickson" + }, + { + "id": 1, + "name": "Villarreal Franks" + }, + { + "id": 2, + "name": "Beth Harvey" + } + ] + }, + { + "id": 69, + "guid": "6f06db74-67bc-4370-8850-fd292fc126ef", + "isActive": false, + "balance": "$2,239.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Lambert Berger", + "gender": "male", + "company": "Zillatide", + "email": "lambertberger@zillatide.com", + "phone": "+1 (880) 445-3824", + "address": { + "street": 783, + "city": "Brooktrails", + "state": "Massachusetts", + "zip": 7045 + }, + "about": "Proident ea mollit ea fugiat ea excepteur fugiat nisi velit dolor amet duis aliquip. Adipisicing anim fugiat velit velit do fugiat laboris ad veniam tempor officia eiusmod laborum ullamco. Reprehenderit elit sunt eiusmod duis cillum id labore. Cupidatat cupidatat laborum eu quis cupidatat ad pariatur tempor enim commodo aliqua mollit velit nulla. Fugiat voluptate duis labore aute reprehenderit culpa enim excepteur.\r\n", + "registered": "2003-11-10T18:31:46+06:00", + "friends": [ + { + "id": 0, + "name": "Lakisha Stein" + }, + { + "id": 1, + "name": "Erica Daugherty" + }, + { + "id": 2, + "name": "Elisabeth Bowen" + } + ] + }, + { + "id": 70, + "guid": "5c466742-5911-4527-b189-170091cb1974", + "isActive": false, + "balance": "$3,284.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Mabel Clayton", + "gender": "female", + "company": "Concility", + "email": "mabelclayton@concility.com", + "phone": "+1 (984) 546-3693", + "address": { + "street": 312, + "city": "Smeltertown", + "state": "New Mexico", + "zip": 6871 + }, + "about": "Ut enim duis amet commodo cillum ipsum ut quis nostrud culpa cupidatat. Proident mollit irure aute adipisicing id sit ullamco culpa exercitation duis duis fugiat. Ipsum ea qui sunt mollit ad reprehenderit duis mollit nisi pariatur. Dolore velit non do sunt laboris eu commodo officia incididunt nostrud adipisicing cillum dolor duis. Velit reprehenderit tempor adipisicing magna aute dolor cupidatat sit eu sit ullamco labore. Quis laborum voluptate aute ad do.\r\n", + "registered": "2009-02-02T02:55:29+06:00", + "friends": [ + { + "id": 0, + "name": "Blackburn Horton" + }, + { + "id": 1, + "name": "Jimenez Shannon" + }, + { + "id": 2, + "name": "Jacklyn Scott" + } + ] + }, + { + "id": 71, + "guid": "7a944ae5-a567-47d4-98db-cd7dbdd3e284", + "isActive": true, + "balance": "$2,297.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Gardner Morin", + "gender": "male", + "company": "Letpro", + "email": "gardnermorin@letpro.com", + "phone": "+1 (892) 527-2742", + "address": { + "street": 865, + "city": "Nile", + "state": "Louisiana", + "zip": 5199 + }, + "about": "Ea consectetur irure cillum dolore excepteur non ipsum proident ut est cillum magna. Voluptate laborum reprehenderit enim eiusmod nostrud laborum et culpa duis tempor sit enim ad. Irure amet laborum sit ullamco amet ad ex est sit. Dolore non velit aliqua ex ea enim ad proident mollit in id est. Elit aliqua sint ad ullamco veniam et esse esse. Cupidatat aute labore Lorem dolor laborum sunt est. Culpa minim elit laborum labore amet sunt excepteur adipisicing eiusmod amet in voluptate excepteur.\r\n", + "registered": "2013-08-03T14:37:59+05:00", + "friends": [ + { + "id": 0, + "name": "Crosby Hurst" + }, + { + "id": 1, + "name": "Vanessa Strickland" + }, + { + "id": 2, + "name": "Vivian Estes" + } + ] + }, + { + "id": 72, + "guid": "363541c9-7e6f-42b1-9f85-86febec215a7", + "isActive": false, + "balance": "$2,521.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Ortega Farley", + "gender": "male", + "company": "Myopium", + "email": "ortegafarley@myopium.com", + "phone": "+1 (801) 475-2264", + "address": { + "street": 182, + "city": "Blue", + "state": "Connecticut", + "zip": 4654 + }, + "about": "Sit elit est ea labore nulla eu consequat eu exercitation in. Non nisi aliquip do cupidatat veniam labore aliqua fugiat sunt est deserunt elit culpa. Enim sunt irure anim sunt occaecat. Reprehenderit sit nostrud tempor fugiat cillum anim aliquip irure officia culpa ut nulla amet sit. Magna dolor nulla nisi in nisi. Excepteur ullamco amet minim veniam quis.\r\n", + "registered": "1993-04-19T07:35:44+05:00", + "friends": [ + { + "id": 0, + "name": "Jenkins Sharp" + }, + { + "id": 1, + "name": "Stein Lott" + }, + { + "id": 2, + "name": "Katelyn Chavez" + } + ] + }, + { + "id": 73, + "guid": "6dc52132-1fd8-47e2-8886-f876de3ae78b", + "isActive": true, + "balance": "$3,114.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Byers Rosa", + "gender": "male", + "company": "Rameon", + "email": "byersrosa@rameon.com", + "phone": "+1 (868) 445-3783", + "address": { + "street": 699, + "city": "Montura", + "state": "Oklahoma", + "zip": 5324 + }, + "about": "Ullamco exercitation et minim incididunt exercitation incididunt cupidatat laboris labore consequat incididunt. Cupidatat do labore non ut enim elit dolor. Laborum amet nostrud nulla enim qui mollit in voluptate deserunt duis. Ad commodo enim minim elit officia aute veniam labore ea irure. Mollit nulla sit tempor et commodo non. Incididunt voluptate enim laboris amet aliqua aliquip officia irure quis esse dolore nisi excepteur.\r\n", + "registered": "2007-02-08T21:57:14+06:00", + "friends": [ + { + "id": 0, + "name": "Kirkland Thomas" + }, + { + "id": 1, + "name": "Rhoda Freeman" + }, + { + "id": 2, + "name": "Felicia Huff" + } + ] + }, + { + "id": 74, + "guid": "14089110-abb1-4e08-8bf2-a7297e2ada3f", + "isActive": false, + "balance": "$1,684.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Jodi Shepherd", + "gender": "female", + "company": "Turnling", + "email": "jodishepherd@turnling.com", + "phone": "+1 (853) 488-2483", + "address": { + "street": 764, + "city": "Layhill", + "state": "Ohio", + "zip": 2075 + }, + "about": "Nulla consectetur adipisicing enim qui proident ullamco minim cupidatat ex adipisicing magna. Fugiat nisi quis sint incididunt laborum veniam ea tempor excepteur ipsum qui adipisicing Lorem. Sunt tempor sunt Lorem Lorem reprehenderit ea excepteur quis. Deserunt do consequat culpa quis eu Lorem occaecat. Commodo occaecat consectetur ex non deserunt reprehenderit proident. Enim nisi veniam fugiat dolor incididunt ex. Aliqua reprehenderit aliqua adipisicing elit nisi cupidatat veniam anim eu laborum irure.\r\n", + "registered": "2001-09-30T10:41:28+05:00", + "friends": [ + { + "id": 0, + "name": "Goff Mercado" + }, + { + "id": 1, + "name": "Wooten Hoover" + }, + { + "id": 2, + "name": "Carey Pugh" + } + ] + }, + { + "id": 75, + "guid": "00ed18dd-3919-42ff-89ff-f2a1439061da", + "isActive": false, + "balance": "$3,305.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Carissa Tyson", + "gender": "female", + "company": "Telpod", + "email": "carissatyson@telpod.com", + "phone": "+1 (838) 503-2367", + "address": { + "street": 793, + "city": "Fredericktown", + "state": "Maryland", + "zip": 9120 + }, + "about": "Reprehenderit quis ipsum anim laborum velit mollit fugiat cillum magna sit amet tempor. Ut consequat nostrud aliqua id qui. Ad laboris sint magna sint cillum voluptate tempor quis tempor et esse ullamco. Enim ad anim mollit esse proident ullamco eu consectetur duis occaecat et velit voluptate magna.\r\n", + "registered": "1990-03-20T04:23:22+05:00", + "friends": [ + { + "id": 0, + "name": "Hammond Ferguson" + }, + { + "id": 1, + "name": "Jeannette William" + }, + { + "id": 2, + "name": "Marla Kelly" + } + ] + }, + { + "id": 76, + "guid": "ed4d6213-5de5-4a29-817b-818f5fde7eec", + "isActive": false, + "balance": "$1,157.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Chris Mueller", + "gender": "female", + "company": "Polarium", + "email": "chrismueller@polarium.com", + "phone": "+1 (809) 508-3542", + "address": { + "street": 854, + "city": "Tilden", + "state": "Vermont", + "zip": 3251 + }, + "about": "Consectetur tempor veniam nostrud officia aliqua. Ad qui esse est nulla nostrud. Consectetur cupidatat ipsum fugiat cupidatat dolor et velit est do quis laborum. Duis minim tempor est aute. Pariatur ut amet consectetur elit ad consequat irure ex deserunt sit irure cillum magna quis.\r\n", + "registered": "1995-01-17T10:36:19+06:00", + "friends": [ + { + "id": 0, + "name": "Steele Rasmussen" + }, + { + "id": 1, + "name": "Bridges Carson" + }, + { + "id": 2, + "name": "Georgia Cobb" + } + ] + }, + { + "id": 77, + "guid": "5fc117e0-f8ef-4f64-abfd-47cd1c68c579", + "isActive": false, + "balance": "$2,502.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Nadia Mcmillan", + "gender": "female", + "company": "Corporana", + "email": "nadiamcmillan@corporana.com", + "phone": "+1 (937) 436-2847", + "address": { + "street": 827, + "city": "Bluetown", + "state": "Delaware", + "zip": 5012 + }, + "about": "Esse aute sint amet anim incididunt exercitation cupidatat cillum nisi qui. Nostrud sunt ipsum aliquip ullamco sint tempor irure pariatur quis. Enim duis incididunt ut aute mollit duis occaecat tempor aliqua est aute eiusmod.\r\n", + "registered": "2010-04-11T01:50:36+05:00", + "friends": [ + { + "id": 0, + "name": "Cooley Michael" + }, + { + "id": 1, + "name": "Trisha Mcintosh" + }, + { + "id": 2, + "name": "Cora Ford" + } + ] + }, + { + "id": 78, + "guid": "fc2b4549-7103-46f8-aceb-e90d30713e50", + "isActive": true, + "balance": "$1,207.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Laurie Stevenson", + "gender": "female", + "company": "Prowaste", + "email": "lauriestevenson@prowaste.com", + "phone": "+1 (984) 462-2558", + "address": { + "street": 758, + "city": "Chautauqua", + "state": "Rhode Island", + "zip": 730 + }, + "about": "Sit ea do id deserunt et dolore dolore mollit esse. Nulla occaecat proident ea ad labore incididunt officia occaecat eiusmod anim. Consectetur aliqua sint anim labore do.\r\n", + "registered": "2008-03-08T01:45:41+06:00", + "friends": [ + { + "id": 0, + "name": "Herminia Parker" + }, + { + "id": 1, + "name": "Eddie Mason" + }, + { + "id": 2, + "name": "Velma Maynard" + } + ] + }, + { + "id": 79, + "guid": "324ba997-d30b-44a6-a938-f161fddef781", + "isActive": true, + "balance": "$3,408.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Sandoval Camacho", + "gender": "male", + "company": "Minga", + "email": "sandovalcamacho@minga.com", + "phone": "+1 (887) 572-2967", + "address": { + "street": 881, + "city": "Snyderville", + "state": "Kentucky", + "zip": 746 + }, + "about": "Labore ipsum quis aute et cupidatat dolore occaecat irure. Non eu proident fugiat tempor sunt minim mollit est fugiat. Labore duis ipsum est dolor labore adipisicing velit ex officia ut cupidatat dolor duis ipsum. Commodo veniam ipsum ea occaecat cupidatat ad sunt proident labore velit reprehenderit et.\r\n", + "registered": "2000-01-13T17:35:10+06:00", + "friends": [ + { + "id": 0, + "name": "Cynthia Cox" + }, + { + "id": 1, + "name": "Doyle Page" + }, + { + "id": 2, + "name": "Sondra Mosley" + } + ] + }, + { + "id": 80, + "guid": "aa687b50-2ff7-4943-96ef-0138bf3fda1e", + "isActive": false, + "balance": "$2,668.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Frederick Gallagher", + "gender": "male", + "company": "Lexicondo", + "email": "frederickgallagher@lexicondo.com", + "phone": "+1 (887) 593-3128", + "address": { + "street": 607, + "city": "Stevens", + "state": "Georgia", + "zip": 1987 + }, + "about": "Amet enim quis reprehenderit occaecat id exercitation non nulla. Commodo qui laborum laborum ea est magna veniam culpa culpa non ullamco id sint est. Ea eiusmod dolore sint consequat eiusmod aute deserunt. Minim pariatur laboris laborum anim nulla cupidatat tempor incididunt nulla enim. Fugiat sint exercitation aliqua aute quis irure id irure ut consectetur. Officia minim elit dolore et consectetur velit ea enim fugiat tempor ullamco aliquip enim.\r\n", + "registered": "2002-01-03T18:50:39+06:00", + "friends": [ + { + "id": 0, + "name": "Black Callahan" + }, + { + "id": 1, + "name": "Robin Rowland" + }, + { + "id": 2, + "name": "Moss Irwin" + } + ] + }, + { + "id": 81, + "guid": "e35867cb-720d-495e-8298-e8cdf256df71", + "isActive": true, + "balance": "$2,979.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Walls Randall", + "gender": "male", + "company": "Zentry", + "email": "wallsrandall@zentry.com", + "phone": "+1 (936) 468-3531", + "address": { + "street": 588, + "city": "Frystown", + "state": "Michigan", + "zip": 5894 + }, + "about": "Fugiat commodo adipisicing est anim quis duis culpa aute id mollit duis irure reprehenderit do. Proident nostrud duis ea consequat duis proident incididunt culpa reprehenderit ut do. Reprehenderit non proident amet consequat laborum magna reprehenderit dolore cupidatat. Ea nostrud nisi dolore deserunt officia.\r\n", + "registered": "2000-11-04T13:24:06+05:00", + "friends": [ + { + "id": 0, + "name": "Bonnie Holden" + }, + { + "id": 1, + "name": "Valentine Farmer" + }, + { + "id": 2, + "name": "Grant Hutchinson" + } + ] + }, + { + "id": 82, + "guid": "7edf3100-cc69-44ba-ab3b-878a9bb4bfd5", + "isActive": false, + "balance": "$1,652.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Floyd Calderon", + "gender": "male", + "company": "Zosis", + "email": "floydcalderon@zosis.com", + "phone": "+1 (995) 447-2915", + "address": { + "street": 621, + "city": "Germanton", + "state": "Wyoming", + "zip": 3826 + }, + "about": "Qui qui minim enim tempor eu amet excepteur cillum ullamco cillum ipsum. Ut occaecat est proident fugiat nostrud do ad in pariatur ut adipisicing. Est ad proident reprehenderit duis do do incididunt occaecat cupidatat. Pariatur nulla deserunt exercitation aliqua voluptate tempor est. Sunt id officia adipisicing Lorem esse. Ipsum nostrud consequat excepteur amet velit laboris nostrud irure officia. Dolore id in officia elit eiusmod dolore commodo veniam nostrud sint culpa est.\r\n", + "registered": "2001-09-25T17:33:26+05:00", + "friends": [ + { + "id": 0, + "name": "Savannah Witt" + }, + { + "id": 1, + "name": "Ana Mccray" + }, + { + "id": 2, + "name": "Eva Pena" + } + ] + }, + { + "id": 83, + "guid": "a517ae3a-a7eb-4355-9271-bd31fe395554", + "isActive": true, + "balance": "$2,499.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Stephens Yates", + "gender": "male", + "company": "Zidant", + "email": "stephensyates@zidant.com", + "phone": "+1 (958) 572-2803", + "address": { + "street": 107, + "city": "Smock", + "state": "South Carolina", + "zip": 776 + }, + "about": "Anim id proident culpa incididunt magna officia. Pariatur cupidatat reprehenderit esse eiusmod Lorem minim fugiat. Labore veniam velit nisi anim ipsum consectetur do cillum. Ea anim duis proident et pariatur tempor laborum aliquip do laboris. Proident est est deserunt veniam exercitation. Nulla dolor dolore duis reprehenderit nostrud deserunt ipsum duis adipisicing.\r\n", + "registered": "1997-04-29T14:28:22+05:00", + "friends": [ + { + "id": 0, + "name": "Noble Torres" + }, + { + "id": 1, + "name": "Susana Gordon" + }, + { + "id": 2, + "name": "Nichols Chase" + } + ] + }, + { + "id": 84, + "guid": "4c7dc20c-7936-41f1-83fe-0eb00226edde", + "isActive": true, + "balance": "$1,821.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Leigh Durham", + "gender": "female", + "company": "Nspire", + "email": "leighdurham@nspire.com", + "phone": "+1 (828) 476-2193", + "address": { + "street": 782, + "city": "Rosedale", + "state": "Arkansas", + "zip": 4419 + }, + "about": "Ut dolor proident pariatur veniam do reprehenderit anim incididunt culpa officia exercitation incididunt duis ullamco. Ut adipisicing eiusmod nulla qui do occaecat qui sit. Pariatur dolor ullamco ad est laboris proident sunt est. Mollit eu consequat est aute cillum nulla amet exercitation in aliquip commodo. In est proident eiusmod aliquip nisi sint eiusmod nulla esse nisi adipisicing. Cupidatat aute qui occaecat proident officia sunt id ad esse aliqua proident dolore mollit dolore. Tempor velit irure enim officia ad velit excepteur ea consectetur esse culpa ut.\r\n", + "registered": "1989-08-01T22:33:24+05:00", + "friends": [ + { + "id": 0, + "name": "Stephenson Henderson" + }, + { + "id": 1, + "name": "Dora Glenn" + }, + { + "id": 2, + "name": "Molly Gonzales" + } + ] + }, + { + "id": 85, + "guid": "a2dd93ad-bab6-43ec-8dc3-80a16f1c61a4", + "isActive": true, + "balance": "$2,753.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Odonnell Frank", + "gender": "male", + "company": "Stucco", + "email": "odonnellfrank@stucco.com", + "phone": "+1 (870) 436-3125", + "address": { + "street": 495, + "city": "Leeper", + "state": "New York", + "zip": 2904 + }, + "about": "Ipsum occaecat nulla minim adipisicing pariatur minim occaecat minim sunt deserunt et proident. Nisi ullamco eiusmod sint proident et quis excepteur voluptate ad. Occaecat veniam amet aliquip ea et voluptate magna. Dolor duis occaecat id elit nisi mollit commodo in ea adipisicing minim qui commodo. Laborum ex consectetur Lorem deserunt.\r\n", + "registered": "1994-09-22T21:00:56+05:00", + "friends": [ + { + "id": 0, + "name": "Young Kennedy" + }, + { + "id": 1, + "name": "Burt Chen" + }, + { + "id": 2, + "name": "Garrison Merrill" + } + ] + }, + { + "id": 86, + "guid": "5d92fc3d-3a2d-4804-b79f-feb595d6bc6f", + "isActive": true, + "balance": "$2,626.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Ingram Blackburn", + "gender": "male", + "company": "Lovepad", + "email": "ingramblackburn@lovepad.com", + "phone": "+1 (842) 463-2719", + "address": { + "street": 602, + "city": "Dola", + "state": "Washington", + "zip": 2790 + }, + "about": "Eu pariatur voluptate cillum ipsum ex id irure ea esse. Irure voluptate reprehenderit irure ut. Velit velit eu id nisi occaecat mollit reprehenderit nisi incididunt elit non nulla. Laboris deserunt voluptate occaecat voluptate veniam irure occaecat voluptate ut aliquip veniam aliqua.\r\n", + "registered": "2007-01-19T20:13:26+06:00", + "friends": [ + { + "id": 0, + "name": "Willie Alexander" + }, + { + "id": 1, + "name": "Patty Keller" + }, + { + "id": 2, + "name": "Hardy Mcclure" + } + ] + }, + { + "id": 87, + "guid": "2c506777-8a1e-4b6f-ad94-d297dc62ef30", + "isActive": false, + "balance": "$2,173.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Ford Daniel", + "gender": "male", + "company": "Isoplex", + "email": "forddaniel@isoplex.com", + "phone": "+1 (963) 427-2643", + "address": { + "street": 899, + "city": "Stagecoach", + "state": "South Dakota", + "zip": 5865 + }, + "about": "Cupidatat deserunt labore occaecat eiusmod quis magna anim magna laborum nisi Lorem fugiat commodo. Dolore nisi aliqua ut excepteur commodo esse aliquip incididunt id nisi incididunt. Commodo in dolore labore officia irure sit duis cillum. Esse sunt occaecat culpa adipisicing reprehenderit qui. Exercitation nisi sit exercitation nisi esse. Aliquip anim sunt eu pariatur nulla.\r\n", + "registered": "1992-07-10T05:46:44+05:00", + "friends": [ + { + "id": 0, + "name": "Castro Hendrix" + }, + { + "id": 1, + "name": "Addie Kane" + }, + { + "id": 2, + "name": "Renee Mcdaniel" + } + ] + }, + { + "id": 88, + "guid": "d1980b63-7ca0-4175-b126-7625a5821666", + "isActive": true, + "balance": "$2,818.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Hampton Johnston", + "gender": "male", + "company": "Inear", + "email": "hamptonjohnston@inear.com", + "phone": "+1 (904) 596-3756", + "address": { + "street": 352, + "city": "Winchester", + "state": "Tennessee", + "zip": 7609 + }, + "about": "Cupidatat exercitation aute proident et quis ullamco sint elit. Ex aliqua amet qui commodo exercitation deserunt fugiat aliqua dolore labore sint minim excepteur. Commodo laboris adipisicing nisi aute reprehenderit occaecat velit dolor eiusmod occaecat deserunt officia aute.\r\n", + "registered": "2002-11-01T15:48:32+05:00", + "friends": [ + { + "id": 0, + "name": "Roseann Wilder" + }, + { + "id": 1, + "name": "Cook Salazar" + }, + { + "id": 2, + "name": "Joanne Swanson" + } + ] + }, + { + "id": 89, + "guid": "023c6162-38b1-44a9-91c9-e8d42e7e5949", + "isActive": true, + "balance": "$1,805.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Margie Henry", + "gender": "female", + "company": "Orbixtar", + "email": "margiehenry@orbixtar.com", + "phone": "+1 (865) 516-3581", + "address": { + "street": 772, + "city": "Goochland", + "state": "California", + "zip": 7988 + }, + "about": "Duis ullamco aliquip aute ad adipisicing ad ipsum proident adipisicing excepteur veniam ad ut commodo. Sunt proident sit excepteur ullamco enim occaecat. Nisi anim pariatur dolore sunt sunt excepteur anim proident mollit velit aute sunt qui. Fugiat id amet veniam aute minim esse. Reprehenderit ea consequat culpa consequat fugiat velit incididunt quis deserunt. Incididunt Lorem ea ex nostrud.\r\n", + "registered": "2000-11-10T04:26:13+06:00", + "friends": [ + { + "id": 0, + "name": "Simmons Shields" + }, + { + "id": 1, + "name": "Esmeralda Stokes" + }, + { + "id": 2, + "name": "Justine Hill" + } + ] + }, + { + "id": 90, + "guid": "0130ba50-aa6f-4e88-be5e-50cdedef7942", + "isActive": false, + "balance": "$2,346.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Knight Peck", + "gender": "male", + "company": "Immunics", + "email": "knightpeck@immunics.com", + "phone": "+1 (950) 428-2460", + "address": { + "street": 645, + "city": "Allentown", + "state": "Minnesota", + "zip": 3577 + }, + "about": "Sit id anim qui consectetur minim sint. Consequat pariatur sint occaecat adipisicing aute cillum irure enim culpa reprehenderit. Laborum minim magna et reprehenderit anim adipisicing sint do esse qui. Exercitation veniam non incididunt excepteur deserunt voluptate Lorem nostrud esse eu officia amet ad amet. Labore ullamco id veniam exercitation. Laboris labore ex excepteur nostrud do incididunt.\r\n", + "registered": "1994-06-14T19:00:32+05:00", + "friends": [ + { + "id": 0, + "name": "Cabrera Hampton" + }, + { + "id": 1, + "name": "Caldwell Langley" + }, + { + "id": 2, + "name": "Tami Kaufman" + } + ] + }, + { + "id": 91, + "guid": "b013ecd9-3905-4420-b360-0f80a671e8c4", + "isActive": false, + "balance": "$1,609.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Chelsea Brewer", + "gender": "female", + "company": "Kozgene", + "email": "chelseabrewer@kozgene.com", + "phone": "+1 (891) 573-3046", + "address": { + "street": 483, + "city": "Chical", + "state": "North Dakota", + "zip": 3427 + }, + "about": "Qui ut cillum exercitation incididunt. Veniam enim fugiat ullamco esse duis esse esse laborum ipsum est. Reprehenderit sunt reprehenderit ad enim culpa. Dolor magna quis cillum irure adipisicing magna duis adipisicing enim dolore qui. Consequat qui eu dolore quis mollit irure ex dolore tempor anim aliquip fugiat dolor officia. Sint sint deserunt id laboris ullamco mollit in.\r\n", + "registered": "1997-07-30T20:41:34+05:00", + "friends": [ + { + "id": 0, + "name": "Hyde Whitehead" + }, + { + "id": 1, + "name": "Mcknight Oconnor" + }, + { + "id": 2, + "name": "Loretta Preston" + } + ] + }, + { + "id": 92, + "guid": "e324759a-a5e6-421e-93a8-2dfe99baef2b", + "isActive": true, + "balance": "$1,455.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Roth Clay", + "gender": "male", + "company": "Kog", + "email": "rothclay@kog.com", + "phone": "+1 (854) 488-2889", + "address": { + "street": 299, + "city": "Nicholson", + "state": "Indiana", + "zip": 5171 + }, + "about": "Occaecat magna proident adipisicing pariatur consectetur excepteur exercitation laborum eu nostrud officia. Sunt veniam duis excepteur Lorem velit et Lorem. Duis do enim eu voluptate.\r\n", + "registered": "1999-10-18T06:58:05+05:00", + "friends": [ + { + "id": 0, + "name": "Ruthie Avila" + }, + { + "id": 1, + "name": "Tran Patton" + }, + { + "id": 2, + "name": "Marie Boyd" + } + ] + }, + { + "id": 93, + "guid": "45ddf246-a762-45c8-9e93-e599f4e1afee", + "isActive": true, + "balance": "$2,396.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Valenzuela Ruiz", + "gender": "male", + "company": "Isotronic", + "email": "valenzuelaruiz@isotronic.com", + "phone": "+1 (834) 422-2961", + "address": { + "street": 782, + "city": "Marshall", + "state": "Maine", + "zip": 7843 + }, + "about": "Exercitation reprehenderit voluptate veniam reprehenderit sit dolor aute. Laboris cupidatat cupidatat magna sit velit ipsum cupidatat ipsum laboris est labore nulla incididunt proident. Proident quis laboris officia voluptate qui non officia ullamco minim nostrud commodo. Duis labore aliquip minim voluptate cillum ullamco ipsum eiusmod.\r\n", + "registered": "1995-02-14T05:26:22+06:00", + "friends": [ + { + "id": 0, + "name": "Ferrell Cochran" + }, + { + "id": 1, + "name": "Campbell Lowery" + }, + { + "id": 2, + "name": "Barrett Payne" + } + ] + }, + { + "id": 94, + "guid": "6bc1f3e6-b0ec-4eaf-b72b-9cfb170353fe", + "isActive": true, + "balance": "$3,925.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Caroline Snow", + "gender": "female", + "company": "Zomboid", + "email": "carolinesnow@zomboid.com", + "phone": "+1 (839) 579-2471", + "address": { + "street": 338, + "city": "Savannah", + "state": "Kansas", + "zip": 1315 + }, + "about": "Ullamco veniam aliqua sit esse aliquip ad adipisicing Lorem veniam laborum Lorem ad reprehenderit. Anim adipisicing cupidatat occaecat adipisicing eu ex ea occaecat nulla esse in officia. Anim esse quis mollit est quis et ex. Commodo commodo id ea voluptate magna non laborum proident laboris laboris velit magna enim. Anim do aliqua exercitation adipisicing. Ut ex cillum aute eiusmod sit ipsum occaecat occaecat. Cillum aute in laboris culpa ex qui ex Lorem.\r\n", + "registered": "2003-03-12T19:05:58+05:00", + "friends": [ + { + "id": 0, + "name": "Hoffman Morrison" + }, + { + "id": 1, + "name": "Erin Olsen" + }, + { + "id": 2, + "name": "Schroeder Barron" + } + ] + }, + { + "id": 95, + "guid": "d865be27-e6df-426f-a2d6-45a4b06f584f", + "isActive": false, + "balance": "$1,377.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Roberson Bush", + "gender": "male", + "company": "Exosis", + "email": "robersonbush@exosis.com", + "phone": "+1 (933) 443-2362", + "address": { + "street": 104, + "city": "Rose", + "state": "Utah", + "zip": 6981 + }, + "about": "Excepteur sunt anim nulla labore. Ipsum ullamco excepteur ullamco velit exercitation excepteur tempor. Proident irure consectetur incididunt aliquip do voluptate non minim. Nisi qui duis fugiat cupidatat. Ut exercitation eiusmod incididunt officia amet consequat culpa nostrud duis quis elit tempor.\r\n", + "registered": "2004-11-19T19:05:46+06:00", + "friends": [ + { + "id": 0, + "name": "Brandie Gillespie" + }, + { + "id": 1, + "name": "Melissa Cleveland" + }, + { + "id": 2, + "name": "Clemons Molina" + } + ] + }, + { + "id": 96, + "guid": "cb63f887-e7c2-4f68-ab8a-b079b1eed783", + "isActive": true, + "balance": "$3,104.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Good Mcmahon", + "gender": "male", + "company": "Sybixtex", + "email": "goodmcmahon@sybixtex.com", + "phone": "+1 (846) 499-3909", + "address": { + "street": 963, + "city": "Felt", + "state": "Mississippi", + "zip": 9683 + }, + "about": "Id ipsum enim labore culpa anim. Consectetur anim sunt eiusmod est aliquip nostrud veniam. Irure tempor eiusmod consectetur anim deserunt ut exercitation nulla fugiat consequat deserunt. Esse consequat sint est ex nisi ullamco elit excepteur est est consequat voluptate commodo Lorem. Culpa duis nostrud fugiat cillum nisi labore mollit nisi ipsum culpa. Dolore consequat elit non elit nulla culpa incididunt exercitation voluptate cupidatat sunt voluptate culpa excepteur.\r\n", + "registered": "2008-11-23T17:57:31+06:00", + "friends": [ + { + "id": 0, + "name": "Tanisha Turner" + }, + { + "id": 1, + "name": "Arnold Mcgee" + }, + { + "id": 2, + "name": "Billie Morse" + } + ] + }, + { + "id": 97, + "guid": "7d23d526-b6d8-49ff-ae80-0eb13de3ffb6", + "isActive": false, + "balance": "$1,557.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Betsy Jarvis", + "gender": "female", + "company": "Slumberia", + "email": "betsyjarvis@slumberia.com", + "phone": "+1 (976) 470-2848", + "address": { + "street": 846, + "city": "Coral", + "state": "Nevada", + "zip": 4102 + }, + "about": "Velit anim et minim proident do exercitation et non do dolore in duis excepteur adipisicing. Veniam adipisicing minim tempor aliquip nisi esse nostrud reprehenderit magna non excepteur dolor quis velit. Officia dolor nisi amet Lorem officia adipisicing exercitation. Dolor culpa dolore est non ut incididunt Lorem esse ipsum proident nulla. Culpa aliquip esse ipsum qui qui labore.\r\n", + "registered": "2007-12-10T08:25:04+06:00", + "friends": [ + { + "id": 0, + "name": "Carlson Cameron" + }, + { + "id": 1, + "name": "Jaime Dennis" + }, + { + "id": 2, + "name": "Coleen Oneal" + } + ] + }, + { + "id": 98, + "guid": "d0a75598-4a3d-4616-8601-f067b8b7bb49", + "isActive": false, + "balance": "$1,215.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Alba Welch", + "gender": "female", + "company": "Intrawear", + "email": "albawelch@intrawear.com", + "phone": "+1 (879) 434-2225", + "address": { + "street": 919, + "city": "Wiscon", + "state": "Delaware", + "zip": 2659 + }, + "about": "Lorem nisi proident qui consequat amet dolore ullamco consectetur voluptate consectetur. Officia dolor nisi excepteur mollit adipisicing do consequat duis aliquip enim aliquip occaecat culpa cillum. Pariatur consectetur est nisi id do culpa id culpa ea quis culpa. Ad ullamco et elit nostrud irure labore.\r\n", + "registered": "2006-07-19T06:26:33+05:00", + "friends": [ + { + "id": 0, + "name": "Claudette Gilbert" + }, + { + "id": 1, + "name": "Peggy Swanson" + }, + { + "id": 2, + "name": "Claudia Moreno" + } + ] + }, + { + "id": 99, + "guid": "2cfcb937-773c-4fbd-b988-7b00d92522d8", + "isActive": false, + "balance": "$1,714.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Moon Woods", + "gender": "male", + "company": "Tersanki", + "email": "moonwoods@tersanki.com", + "phone": "+1 (811) 444-2648", + "address": { + "street": 295, + "city": "Chamizal", + "state": "New Hampshire", + "zip": 7697 + }, + "about": "Reprehenderit laborum excepteur laborum aliqua non velit exercitation deserunt aliquip nisi ea fugiat incididunt ipsum. Excepteur exercitation irure nulla Lorem. Ut ad ex officia fugiat eu cillum Lorem consequat.\r\n", + "registered": "2008-01-03T09:00:55+06:00", + "friends": [ + { + "id": 0, + "name": "Isabelle Blackburn" + }, + { + "id": 1, + "name": "Delores Lester" + }, + { + "id": 2, + "name": "Hess Dominguez" + } + ] + }, + { + "id": 100, + "guid": "5af07698-a6dd-449d-9143-d4fd42d35c09", + "isActive": true, + "balance": "$3,774.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Bender Jefferson", + "gender": "male", + "company": "Applideck", + "email": "benderjefferson@applideck.com", + "phone": "+1 (991) 523-2602", + "address": { + "street": 664, + "city": "Orin", + "state": "Wyoming", + "zip": 9632 + }, + "about": "Magna mollit enim ex sint ex nulla aute nisi deserunt ipsum anim exercitation reprehenderit. Aliquip amet labore do commodo Lorem aliqua ea ad nisi officia cupidatat. Fugiat minim occaecat esse cillum mollit eu sit irure in consectetur deserunt in esse tempor. Elit velit tempor officia ex qui irure commodo. Est pariatur pariatur veniam minim veniam exercitation tempor enim excepteur mollit id amet eiusmod deserunt. Enim quis veniam aute reprehenderit aliqua.\r\n", + "registered": "1996-03-24T15:48:11+05:00", + "friends": [ + { + "id": 0, + "name": "Koch Burris" + }, + { + "id": 1, + "name": "Lelia Maddox" + }, + { + "id": 2, + "name": "Beard Higgins" + } + ] + }, + { + "id": 101, + "guid": "3b1b8e98-64e2-4bd8-b690-26a54b44bb2f", + "isActive": false, + "balance": "$3,163.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Catherine Ryan", + "gender": "female", + "company": "Quilch", + "email": "catherineryan@quilch.com", + "phone": "+1 (811) 462-3486", + "address": { + "street": 524, + "city": "Joppa", + "state": "Texas", + "zip": 4484 + }, + "about": "Ad occaecat excepteur velit tempor proident veniam id velit. Mollit consectetur adipisicing veniam ut dolore fugiat tempor nisi elit. Dolore est occaecat anim eiusmod id fugiat. Mollit Lorem sit excepteur aute aliqua tempor eiusmod elit ad id voluptate adipisicing. Fugiat laboris est enim ullamco pariatur tempor exercitation ullamco.\r\n", + "registered": "2009-09-19T00:48:13+05:00", + "friends": [ + { + "id": 0, + "name": "Hudson Sparks" + }, + { + "id": 1, + "name": "Clare Sampson" + }, + { + "id": 2, + "name": "Kellie Barber" + } + ] + }, + { + "id": 102, + "guid": "634ed11f-7181-44ed-96b5-c7fab1afdcad", + "isActive": false, + "balance": "$1,490.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Richardson Blake", + "gender": "male", + "company": "Otherside", + "email": "richardsonblake@otherside.com", + "phone": "+1 (838) 409-2825", + "address": { + "street": 687, + "city": "Stewart", + "state": "Washington", + "zip": 9997 + }, + "about": "Irure proident quis nostrud nulla quis duis exercitation ullamco. Fugiat elit nulla nisi mollit et laboris minim veniam aute ipsum. Nisi eiusmod nulla deserunt esse aliqua.\r\n", + "registered": "1988-06-19T11:10:04+05:00", + "friends": [ + { + "id": 0, + "name": "Pate Larson" + }, + { + "id": 1, + "name": "Martha Russell" + }, + { + "id": 2, + "name": "Serrano Evans" + } + ] + }, + { + "id": 103, + "guid": "a9621347-4ebc-4ec2-813a-bfa1125223a6", + "isActive": false, + "balance": "$2,081.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Decker Nieves", + "gender": "male", + "company": "Solgan", + "email": "deckernieves@solgan.com", + "phone": "+1 (998) 571-2537", + "address": { + "street": 547, + "city": "Nadine", + "state": "Mississippi", + "zip": 3310 + }, + "about": "Officia dolore eiusmod ea nostrud. Proident mollit eiusmod adipisicing nisi. Mollit esse amet cupidatat incididunt dolor laboris cillum est ex. Cupidatat nostrud sint tempor do sit adipisicing consequat consequat culpa exercitation aliquip id non. Esse anim in id labore dolor nostrud magna magna aute tempor excepteur.\r\n", + "registered": "2009-06-22T22:37:53+05:00", + "friends": [ + { + "id": 0, + "name": "Zamora Silva" + }, + { + "id": 1, + "name": "Bradley Britt" + }, + { + "id": 2, + "name": "Stark Best" + } + ] + }, + { + "id": 104, + "guid": "bef95243-9993-4afb-8350-a050f5bac952", + "isActive": true, + "balance": "$3,522.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Harris Glenn", + "gender": "male", + "company": "Cuizine", + "email": "harrisglenn@cuizine.com", + "phone": "+1 (976) 461-2189", + "address": { + "street": 956, + "city": "Riverton", + "state": "New Mexico", + "zip": 7611 + }, + "about": "Dolor duis ipsum consequat consequat ea cupidatat magna velit irure duis. Aliqua officia exercitation et exercitation do anim reprehenderit laboris ex minim elit. Proident nostrud exercitation velit sunt do culpa ipsum. Minim ad consequat exercitation amet aute proident culpa eu ipsum.\r\n", + "registered": "1989-03-29T18:25:05+05:00", + "friends": [ + { + "id": 0, + "name": "Duffy Willis" + }, + { + "id": 1, + "name": "Kristie Mckay" + }, + { + "id": 2, + "name": "Mcmahon James" + } + ] + }, + { + "id": 105, + "guid": "defcf523-468d-4c62-91d6-737ff05402b6", + "isActive": true, + "balance": "$1,633.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Mcmillan Pace", + "gender": "male", + "company": "Enersave", + "email": "mcmillanpace@enersave.com", + "phone": "+1 (847) 505-2306", + "address": { + "street": 420, + "city": "Marne", + "state": "Oregon", + "zip": 9414 + }, + "about": "Id irure voluptate in ex deserunt esse ullamco culpa culpa excepteur nulla incididunt in. Ut quis exercitation sit proident eu magna nulla officia consectetur ad sint dolore. Nisi elit enim consectetur labore.\r\n", + "registered": "2009-12-28T19:47:37+06:00", + "friends": [ + { + "id": 0, + "name": "Moss Newman" + }, + { + "id": 1, + "name": "Williams Nolan" + }, + { + "id": 2, + "name": "Minerva Lyons" + } + ] + }, + { + "id": 106, + "guid": "383611ef-d06f-4e54-89a0-433a27cc9f32", + "isActive": false, + "balance": "$2,748.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Neva Berg", + "gender": "female", + "company": "Talkalot", + "email": "nevaberg@talkalot.com", + "phone": "+1 (871) 485-2567", + "address": { + "street": 307, + "city": "Austinburg", + "state": "Tennessee", + "zip": 4215 + }, + "about": "Laborum ea est nulla excepteur occaecat eiusmod sunt commodo in qui. Cupidatat aliqua velit aliquip ipsum aute. Duis minim deserunt culpa proident id velit. Reprehenderit laboris dolor aliqua sint ullamco irure incididunt.\r\n", + "registered": "2002-02-19T13:34:53+06:00", + "friends": [ + { + "id": 0, + "name": "Cline Armstrong" + }, + { + "id": 1, + "name": "Lyons Oneal" + }, + { + "id": 2, + "name": "Dale Sanders" + } + ] + }, + { + "id": 107, + "guid": "b02dbcb6-71ad-4ade-a538-6462a7fe0435", + "isActive": true, + "balance": "$2,306.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Jensen Moody", + "gender": "male", + "company": "Xsports", + "email": "jensenmoody@xsports.com", + "phone": "+1 (895) 568-2376", + "address": { + "street": 321, + "city": "Conway", + "state": "Florida", + "zip": 6644 + }, + "about": "Nostrud eu ipsum ut ullamco aliqua do consequat aliqua aute exercitation enim commodo. Occaecat eiusmod do esse qui incididunt deserunt quis aute enim eu sit tempor. Irure consequat nisi excepteur esse anim laborum labore id ipsum sunt magna. Voluptate commodo esse nulla fugiat. Cupidatat est pariatur aute irure culpa minim enim labore. Id consectetur ipsum ipsum ad tempor voluptate culpa amet cillum aute aliquip.\r\n", + "registered": "2006-12-19T23:01:33+06:00", + "friends": [ + { + "id": 0, + "name": "Cheri Hahn" + }, + { + "id": 1, + "name": "Wooten Jensen" + }, + { + "id": 2, + "name": "Jordan Crawford" + } + ] + }, + { + "id": 108, + "guid": "61867975-7317-46eb-a245-f584e547fdc1", + "isActive": true, + "balance": "$3,318.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Robles Sexton", + "gender": "male", + "company": "Kindaloo", + "email": "roblessexton@kindaloo.com", + "phone": "+1 (930) 553-2016", + "address": { + "street": 196, + "city": "Jennings", + "state": "Minnesota", + "zip": 3523 + }, + "about": "Quis voluptate elit in in. Ut occaecat Lorem duis incididunt do duis tempor veniam ut. Ad esse laborum quis qui non sunt sint nulla exercitation aute sint. Aute ullamco elit sunt in culpa irure enim voluptate labore et nisi ex.\r\n", + "registered": "2003-02-09T06:59:24+06:00", + "friends": [ + { + "id": 0, + "name": "Parks Waters" + }, + { + "id": 1, + "name": "Charlotte Simpson" + }, + { + "id": 2, + "name": "Michelle Ruiz" + } + ] + }, + { + "id": 109, + "guid": "275fa40e-1b71-4613-9e96-9238681bb4ec", + "isActive": false, + "balance": "$2,131.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "York Talley", + "gender": "male", + "company": "Terrago", + "email": "yorktalley@terrago.com", + "phone": "+1 (994) 507-3967", + "address": { + "street": 238, + "city": "Sanford", + "state": "Georgia", + "zip": 5683 + }, + "about": "Sit reprehenderit do culpa irure. In ad eu pariatur ullamco consequat aliqua ea adipisicing culpa ipsum sunt id. Eu exercitation esse sunt aliquip culpa fugiat incididunt ipsum do aliquip dolor proident sint id. Anim proident laborum eu consequat esse.\r\n", + "registered": "1994-11-04T01:32:25+05:00", + "friends": [ + { + "id": 0, + "name": "Barlow Klein" + }, + { + "id": 1, + "name": "Fern Coleman" + }, + { + "id": 2, + "name": "Casandra Reeves" + } + ] + }, + { + "id": 110, + "guid": "5d5557a3-b172-4aee-8bbf-451ae2fad5c5", + "isActive": true, + "balance": "$3,969.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Gamble Hudson", + "gender": "male", + "company": "Gushkool", + "email": "gamblehudson@gushkool.com", + "phone": "+1 (919) 424-3914", + "address": { + "street": 691, + "city": "Lacomb", + "state": "New Jersey", + "zip": 9812 + }, + "about": "Cupidatat fugiat exercitation eu enim sit aute enim culpa est excepteur tempor deserunt laborum voluptate. Ut consequat non magna consectetur incididunt mollit proident anim eu commodo ex incididunt. Voluptate adipisicing fugiat sint laborum.\r\n", + "registered": "1992-09-01T20:43:50+05:00", + "friends": [ + { + "id": 0, + "name": "Katy Hale" + }, + { + "id": 1, + "name": "Craig Allen" + }, + { + "id": 2, + "name": "Caitlin Faulkner" + } + ] + }, + { + "id": 111, + "guid": "5a299384-d247-4a41-a473-c3d60f4758ae", + "isActive": false, + "balance": "$2,626.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Lisa Mays", + "gender": "female", + "company": "Callflex", + "email": "lisamays@callflex.com", + "phone": "+1 (978) 564-2786", + "address": { + "street": 344, + "city": "Enlow", + "state": "Colorado", + "zip": 490 + }, + "about": "Reprehenderit anim sint dolor minim fugiat. Elit duis magna consequat proident ut voluptate incididunt mollit reprehenderit consequat dolore amet velit. Officia ea velit adipisicing sit ea duis tempor sit nisi amet esse voluptate dolore dolor.\r\n", + "registered": "2002-05-13T14:04:36+05:00", + "friends": [ + { + "id": 0, + "name": "Boyd Walters" + }, + { + "id": 1, + "name": "Massey Vasquez" + }, + { + "id": 2, + "name": "Lila Price" + } + ] + }, + { + "id": 112, + "guid": "32116a78-51f3-44ae-9e79-3032596c1a94", + "isActive": true, + "balance": "$2,458.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Keller Warren", + "gender": "male", + "company": "Amtas", + "email": "kellerwarren@amtas.com", + "phone": "+1 (871) 592-3511", + "address": { + "street": 240, + "city": "Biddle", + "state": "Rhode Island", + "zip": 9067 + }, + "about": "Anim minim esse nostrud sunt exercitation aliquip qui nisi adipisicing laborum excepteur velit minim. Quis laboris pariatur veniam ad aliqua fugiat eu eiusmod commodo minim mollit. Ipsum ex reprehenderit eu ex elit adipisicing ipsum culpa laborum do duis amet reprehenderit incididunt. Fugiat minim adipisicing voluptate fugiat consequat laboris adipisicing eu elit consectetur magna proident.\r\n", + "registered": "1999-12-08T09:12:52+06:00", + "friends": [ + { + "id": 0, + "name": "Deidre Wise" + }, + { + "id": 1, + "name": "Mooney Wooten" + }, + { + "id": 2, + "name": "Jacqueline Cervantes" + } + ] + }, + { + "id": 113, + "guid": "dac741bd-d86e-46a0-b6ad-0fcaa59221ec", + "isActive": true, + "balance": "$3,970.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Margie Kelly", + "gender": "female", + "company": "Digirang", + "email": "margiekelly@digirang.com", + "phone": "+1 (980) 450-2085", + "address": { + "street": 908, + "city": "Rivereno", + "state": "Virginia", + "zip": 338 + }, + "about": "Proident adipisicing ex dolor culpa ea amet. Nostrud aute exercitation culpa aliqua veniam magna quis sunt elit velit. Officia occaecat pariatur eiusmod esse Lorem ut adipisicing magna nulla.\r\n", + "registered": "1998-01-07T00:37:52+06:00", + "friends": [ + { + "id": 0, + "name": "Flowers Rodgers" + }, + { + "id": 1, + "name": "Sutton Mcintyre" + }, + { + "id": 2, + "name": "Rosario Charles" + } + ] + }, + { + "id": 114, + "guid": "12b61b13-bfd1-40aa-97d9-5d8bcc1d9be7", + "isActive": true, + "balance": "$2,444.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Frost Maldonado", + "gender": "male", + "company": "Xplor", + "email": "frostmaldonado@xplor.com", + "phone": "+1 (951) 468-2805", + "address": { + "street": 211, + "city": "Richmond", + "state": "Michigan", + "zip": 1464 + }, + "about": "Excepteur voluptate pariatur reprehenderit laborum excepteur ipsum. Deserunt dolore non velit Lorem dolore aute pariatur tempor. Enim fugiat occaecat proident cupidatat laborum consectetur dolor proident exercitation aute exercitation anim amet sit. Ex dolor reprehenderit labore in.\r\n", + "registered": "1988-10-16T10:56:48+05:00", + "friends": [ + { + "id": 0, + "name": "Le Trujillo" + }, + { + "id": 1, + "name": "Victoria Ray" + }, + { + "id": 2, + "name": "Harriett Stephens" + } + ] + }, + { + "id": 115, + "guid": "a90ff0fd-d857-4795-966c-095099570dc9", + "isActive": false, + "balance": "$2,667.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Shelton Collier", + "gender": "male", + "company": "Accusage", + "email": "sheltoncollier@accusage.com", + "phone": "+1 (863) 416-3835", + "address": { + "street": 166, + "city": "Shepardsville", + "state": "Maryland", + "zip": 2772 + }, + "about": "Fugiat incididunt excepteur consequat cupidatat esse quis non consectetur id quis aute laborum duis. Nisi enim anim velit dolore ea aliqua sit excepteur laborum dolor dolor. Consectetur officia amet consectetur deserunt sunt deserunt.\r\n", + "registered": "2003-01-01T05:04:19+06:00", + "friends": [ + { + "id": 0, + "name": "Price Wells" + }, + { + "id": 1, + "name": "Sabrina Haney" + }, + { + "id": 2, + "name": "Pearl Pena" + } + ] + }, + { + "id": 116, + "guid": "4cbc5b93-4af0-4002-84bd-6f1c214efceb", + "isActive": false, + "balance": "$2,570.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Robin Wynn", + "gender": "female", + "company": "Zytrax", + "email": "robinwynn@zytrax.com", + "phone": "+1 (983) 499-3723", + "address": { + "street": 392, + "city": "Montura", + "state": "Alabama", + "zip": 3920 + }, + "about": "Aliqua deserunt reprehenderit excepteur aliqua amet voluptate. Aliquip est labore reprehenderit irure voluptate nulla. Nostrud Lorem esse deserunt nostrud reprehenderit labore quis voluptate fugiat sint non nostrud et. Laborum aliqua nisi sit id Lorem duis anim consequat eiusmod esse mollit exercitation irure. Consequat deserunt ex mollit amet duis commodo cupidatat ullamco incididunt sunt adipisicing est amet consequat.\r\n", + "registered": "1993-11-04T14:29:14+05:00", + "friends": [ + { + "id": 0, + "name": "Mullins Sweeney" + }, + { + "id": 1, + "name": "Guadalupe Sweet" + }, + { + "id": 2, + "name": "Krystal Barr" + } + ] + }, + { + "id": 117, + "guid": "aca11976-9866-474f-a1e6-df61cf47d58f", + "isActive": true, + "balance": "$1,145.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Parrish Douglas", + "gender": "male", + "company": "Gynk", + "email": "parrishdouglas@gynk.com", + "phone": "+1 (809) 589-3992", + "address": { + "street": 118, + "city": "Marbury", + "state": "Connecticut", + "zip": 3878 + }, + "about": "Ipsum sit dolor esse anim fugiat cupidatat. Mollit amet culpa ut adipisicing esse exercitation non culpa enim reprehenderit ad minim. Consectetur consectetur aliqua magna id deserunt magna. Pariatur ullamco velit ipsum ut Lorem. Sunt officia mollit occaecat occaecat incididunt laborum. Magna ut et duis nulla minim.\r\n", + "registered": "1988-01-10T14:51:50+06:00", + "friends": [ + { + "id": 0, + "name": "Joyce Barlow" + }, + { + "id": 1, + "name": "Rodgers Melton" + }, + { + "id": 2, + "name": "Velazquez Yang" + } + ] + }, + { + "id": 118, + "guid": "1c76ccd1-8f3b-4ce1-a1d9-c2d3db1079dd", + "isActive": true, + "balance": "$2,683.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Summers Cooley", + "gender": "male", + "company": "Insuresys", + "email": "summerscooley@insuresys.com", + "phone": "+1 (919) 535-2065", + "address": { + "street": 676, + "city": "Woodlake", + "state": "West Virginia", + "zip": 7249 + }, + "about": "Ipsum qui anim cupidatat irure ipsum adipisicing quis velit fugiat. Sunt culpa laboris do elit cupidatat duis enim mollit non Lorem. Duis minim ad aliqua aliquip do et ut id laboris sit tempor ipsum. Velit amet occaecat culpa elit dolore non officia excepteur incididunt laborum. Magna cupidatat exercitation cupidatat sint anim tempor ipsum.\r\n", + "registered": "2011-12-25T23:47:25+06:00", + "friends": [ + { + "id": 0, + "name": "Sybil Mack" + }, + { + "id": 1, + "name": "Richards Norton" + }, + { + "id": 2, + "name": "Willie Norris" + } + ] + }, + { + "id": 119, + "guid": "788c6e0c-55f7-4f7a-9d93-80fa0f166436", + "isActive": true, + "balance": "$3,067.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Alyssa Glass", + "gender": "female", + "company": "Oceanica", + "email": "alyssaglass@oceanica.com", + "phone": "+1 (948) 460-2458", + "address": { + "street": 265, + "city": "Wilsonia", + "state": "California", + "zip": 4784 + }, + "about": "Quis adipisicing incididunt laborum non reprehenderit cupidatat Lorem eiusmod veniam consequat Lorem. Incididunt deserunt irure officia consequat ut ex in mollit fugiat eu. Aliquip proident commodo ut est enim pariatur exercitation enim. Ex qui id pariatur cillum aliqua non officia aute nisi aliqua cupidatat eu minim ad. Aliqua proident irure labore voluptate dolore ad sunt laboris commodo quis.\r\n", + "registered": "2008-12-05T02:30:30+06:00", + "friends": [ + { + "id": 0, + "name": "Olive Castaneda" + }, + { + "id": 1, + "name": "Lorena Mckee" + }, + { + "id": 2, + "name": "Roslyn Merritt" + } + ] + }, + { + "id": 120, + "guid": "094798a4-3e39-43d0-a11a-6c8c152686dc", + "isActive": true, + "balance": "$2,717.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Sheree Fisher", + "gender": "female", + "company": "Valreda", + "email": "shereefisher@valreda.com", + "phone": "+1 (853) 565-3536", + "address": { + "street": 281, + "city": "Oasis", + "state": "Massachusetts", + "zip": 5913 + }, + "about": "Aute cillum aliquip irure officia duis excepteur anim. Exercitation officia est excepteur et consectetur mollit. Eu exercitation qui magna adipisicing fugiat exercitation anim occaecat magna adipisicing ad. Occaecat officia anim tempor ipsum ipsum et eiusmod cillum reprehenderit veniam.\r\n", + "registered": "2013-07-25T16:42:40+05:00", + "friends": [ + { + "id": 0, + "name": "Yolanda Cline" + }, + { + "id": 1, + "name": "Christi Roberts" + }, + { + "id": 2, + "name": "Linda Day" + } + ] + }, + { + "id": 121, + "guid": "4c20ab78-43cb-450d-939c-6c00f4c31b2d", + "isActive": true, + "balance": "$2,285.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Karyn Holden", + "gender": "female", + "company": "Zolavo", + "email": "karynholden@zolavo.com", + "phone": "+1 (805) 542-3355", + "address": { + "street": 946, + "city": "Calvary", + "state": "Alaska", + "zip": 6142 + }, + "about": "Non consequat aliqua magna nisi laboris. Est qui eiusmod dolor labore labore. Ad officia irure velit officia ipsum Lorem ut dolore excepteur cupidatat ex enim velit. Reprehenderit velit eiusmod laboris fugiat do. Ex sint Lorem sunt laborum adipisicing consectetur consequat velit. Eu veniam nisi amet non magna culpa nisi.\r\n", + "registered": "1996-09-14T02:48:38+05:00", + "friends": [ + { + "id": 0, + "name": "Strickland Flores" + }, + { + "id": 1, + "name": "Katie Wiggins" + }, + { + "id": 2, + "name": "Payne Beach" + } + ] + }, + { + "id": 122, + "guid": "4fb735d4-aee7-4e9b-a6a0-e0b33a27139f", + "isActive": false, + "balance": "$3,642.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Lucas Gray", + "gender": "male", + "company": "Centuria", + "email": "lucasgray@centuria.com", + "phone": "+1 (897) 538-3001", + "address": { + "street": 835, + "city": "Lorraine", + "state": "Oklahoma", + "zip": 4843 + }, + "about": "Amet occaecat et anim nostrud sint ut nulla sunt ipsum commodo sit. Id sint qui dolor est deserunt in eu consequat elit sunt labore nisi. Lorem aliqua adipisicing Lorem ipsum ipsum ullamco voluptate exercitation sunt aliquip nulla quis sunt aute. Fugiat mollit ipsum tempor ipsum duis. Exercitation incididunt deserunt cupidatat laboris minim in fugiat aliqua exercitation excepteur do eu aute. Officia Lorem esse nisi Lorem do deserunt cupidatat occaecat sint consectetur incididunt.\r\n", + "registered": "1994-10-15T02:53:53+05:00", + "friends": [ + { + "id": 0, + "name": "Meadows Puckett" + }, + { + "id": 1, + "name": "Nora Bradley" + }, + { + "id": 2, + "name": "Riggs Hull" + } + ] + }, + { + "id": 123, + "guid": "4442acd6-e8dc-4156-866c-826c56c26c16", + "isActive": false, + "balance": "$2,205.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Letitia Alexander", + "gender": "female", + "company": "Gogol", + "email": "letitiaalexander@gogol.com", + "phone": "+1 (917) 494-3484", + "address": { + "street": 643, + "city": "Motley", + "state": "Illinois", + "zip": 4852 + }, + "about": "Do duis commodo irure laboris occaecat ex cillum aute proident. Eiusmod est sint ipsum qui Lorem et quis eu do quis consequat ipsum. Ut exercitation ullamco fugiat proident eu aliquip veniam esse esse in incididunt. Nulla proident eu sunt ex laboris ea veniam labore anim reprehenderit quis ea aute amet. Labore minim id et labore dolore eu fugiat ut quis laboris amet nulla. Qui dolor eu proident officia aliqua. Non laborum proident ipsum et dolor et laborum qui qui culpa.\r\n", + "registered": "2003-05-22T19:07:22+05:00", + "friends": [ + { + "id": 0, + "name": "Ayala Foreman" + }, + { + "id": 1, + "name": "Corine Campos" + }, + { + "id": 2, + "name": "Carlson Daugherty" + } + ] + }, + { + "id": 124, + "guid": "21fc5109-39c9-4008-bcd3-1b387d6793fe", + "isActive": false, + "balance": "$1,484.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Rowena Campbell", + "gender": "female", + "company": "Petigems", + "email": "rowenacampbell@petigems.com", + "phone": "+1 (819) 475-2084", + "address": { + "street": 757, + "city": "Verdi", + "state": "Nevada", + "zip": 3709 + }, + "about": "Do enim nulla minim Lorem adipisicing sint irure minim id eu reprehenderit ex dolore exercitation. Officia magna dolore ea do. Laboris ex laboris excepteur quis deserunt officia in officia quis pariatur. Aute enim eiusmod culpa ad est culpa in. Sit anim ad nostrud nisi irure. Tempor deserunt nisi in aute elit consectetur deserunt irure ex in velit Lorem aute mollit.\r\n", + "registered": "1990-09-04T21:34:09+05:00", + "friends": [ + { + "id": 0, + "name": "Suzette Yates" + }, + { + "id": 1, + "name": "Laura Dorsey" + }, + { + "id": 2, + "name": "Pauline Lindsay" + } + ] + }, + { + "id": 125, + "guid": "ef6eba35-3313-496f-a864-86a95c503c31", + "isActive": false, + "balance": "$1,631.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Roberta Nixon", + "gender": "female", + "company": "Grupoli", + "email": "robertanixon@grupoli.com", + "phone": "+1 (915) 570-3334", + "address": { + "street": 805, + "city": "Sunnyside", + "state": "New York", + "zip": 5442 + }, + "about": "Eu ad occaecat commodo qui officia. Proident sunt officia Lorem irure ut voluptate. Officia sunt ea occaecat laboris cillum. Deserunt proident consequat in ea ipsum duis aliquip do. Laboris culpa cillum veniam labore et veniam mollit laboris tempor.\r\n", + "registered": "1991-08-06T22:52:38+05:00", + "friends": [ + { + "id": 0, + "name": "Berta Perkins" + }, + { + "id": 1, + "name": "Potts Lynch" + }, + { + "id": 2, + "name": "Ora Love" + } + ] + }, + { + "id": 126, + "guid": "2ecc802a-6707-4ab2-a724-51ba7b8b6617", + "isActive": false, + "balance": "$2,628.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Flynn Carver", + "gender": "male", + "company": "Koogle", + "email": "flynncarver@koogle.com", + "phone": "+1 (986) 490-2718", + "address": { + "street": 766, + "city": "Advance", + "state": "Arizona", + "zip": 9968 + }, + "about": "Sint labore aliquip voluptate mollit anim excepteur nostrud non in ipsum. Quis quis est occaecat qui enim sint Lorem. Ut incididunt commodo aliqua do aliqua in Lorem ipsum fugiat ex aliqua sunt nostrud irure. Lorem labore mollit aliqua proident non magna sit Lorem.\r\n", + "registered": "2004-09-16T04:51:45+05:00", + "friends": [ + { + "id": 0, + "name": "Rosie Baldwin" + }, + { + "id": 1, + "name": "Cooper Avery" + }, + { + "id": 2, + "name": "Stuart Clements" + } + ] + }, + { + "id": 127, + "guid": "f193e270-5e3e-4c5b-ae52-32bb1358fbe8", + "isActive": false, + "balance": "$3,371.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Mack Cherry", + "gender": "male", + "company": "Anocha", + "email": "mackcherry@anocha.com", + "phone": "+1 (951) 545-2171", + "address": { + "street": 381, + "city": "Boling", + "state": "Idaho", + "zip": 2387 + }, + "about": "Commodo consectetur sunt aliquip ullamco in irure dolore. Deserunt officia deserunt nostrud eiusmod duis do deserunt exercitation. Ea consectetur cupidatat ea dolore elit sint Lorem commodo Lorem. Reprehenderit tempor in minim qui consequat est ullamco tempor adipisicing ea. Enim pariatur ullamco proident voluptate laboris sit commodo eiusmod. Ipsum consequat in eu voluptate minim Lorem nisi ut.\r\n", + "registered": "2012-04-10T21:45:02+05:00", + "friends": [ + { + "id": 0, + "name": "Mcconnell Garrett" + }, + { + "id": 1, + "name": "Vickie Riley" + }, + { + "id": 2, + "name": "Bartlett Berry" + } + ] + }, + { + "id": 128, + "guid": "1ca29695-c9ab-434b-8acc-f74619686a51", + "isActive": false, + "balance": "$3,828.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Browning Curtis", + "gender": "male", + "company": "Duflex", + "email": "browningcurtis@duflex.com", + "phone": "+1 (855) 435-2488", + "address": { + "street": 604, + "city": "Nord", + "state": "Montana", + "zip": 1732 + }, + "about": "Consectetur cillum est aute ullamco non occaecat cupidatat. Mollit enim ad sit quis mollit reprehenderit. Eu enim commodo quis est irure consequat et commodo duis ea duis proident fugiat ut. Pariatur eiusmod consectetur veniam magna tempor. Dolor dolor magna sunt aliquip deserunt sit reprehenderit nisi dolore duis dolor aliqua id. Lorem dolore nisi amet adipisicing veniam fugiat est consectetur irure magna culpa proident id ex.\r\n", + "registered": "2008-12-13T05:58:26+06:00", + "friends": [ + { + "id": 0, + "name": "Alisa Harmon" + }, + { + "id": 1, + "name": "Angie Long" + }, + { + "id": 2, + "name": "Sara Summers" + } + ] + }, + { + "id": 129, + "guid": "e48f3320-f619-4a9d-b00a-8e5a2229da02", + "isActive": false, + "balance": "$1,216.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Frank Huber", + "gender": "male", + "company": "Medmex", + "email": "frankhuber@medmex.com", + "phone": "+1 (917) 403-3466", + "address": { + "street": 328, + "city": "Stockwell", + "state": "Missouri", + "zip": 8952 + }, + "about": "Non ut exercitation veniam fugiat duis eiusmod sunt sit consectetur esse duis ad cupidatat. Nostrud laborum tempor mollit aliqua amet. Deserunt elit sit irure minim aute laboris. Ad culpa enim quis laborum tempor non adipisicing. Labore sit do minim adipisicing irure. Fugiat proident fugiat exercitation anim amet consectetur quis excepteur ut. Veniam duis laboris tempor aliquip consequat eiusmod aute ullamco deserunt fugiat minim id reprehenderit.\r\n", + "registered": "2011-09-14T20:27:29+05:00", + "friends": [ + { + "id": 0, + "name": "Cooke Durham" + }, + { + "id": 1, + "name": "Debora Gay" + }, + { + "id": 2, + "name": "Goodman Dixon" + } + ] + }, + { + "id": 130, + "guid": "eaac94f0-9467-4ab2-b5db-bdd7ea056d19", + "isActive": true, + "balance": "$1,143.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Clements Olson", + "gender": "male", + "company": "Kinetica", + "email": "clementsolson@kinetica.com", + "phone": "+1 (959) 457-3845", + "address": { + "street": 371, + "city": "Topaz", + "state": "South Dakota", + "zip": 613 + }, + "about": "Eiusmod do officia ipsum ut sit elit elit nulla ut Lorem. In et in anim id. Esse deserunt pariatur incididunt eu elit qui ex voluptate excepteur eiusmod. Elit dolor adipisicing dolore dolore et qui ex. Eu culpa laboris laboris deserunt et laboris mollit quis. Amet cillum dolore qui in est nisi mollit.\r\n", + "registered": "2007-03-04T16:06:41+06:00", + "friends": [ + { + "id": 0, + "name": "Johnson Miranda" + }, + { + "id": 1, + "name": "Fuller Key" + }, + { + "id": 2, + "name": "Marylou Madden" + } + ] + }, + { + "id": 131, + "guid": "62560091-6b89-4158-8057-5b52ca346d77", + "isActive": false, + "balance": "$3,162.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Hallie Schneider", + "gender": "female", + "company": "Kineticut", + "email": "hallieschneider@kineticut.com", + "phone": "+1 (864) 437-3755", + "address": { + "street": 349, + "city": "Campo", + "state": "Kansas", + "zip": 3724 + }, + "about": "Commodo veniam eiusmod ullamco pariatur esse pariatur occaecat anim eiusmod pariatur proident dolore incididunt. Eiusmod amet dolore duis dolor ullamco esse amet consectetur in ad occaecat consequat. Non id qui aute consequat aliquip veniam dolor ea officia laboris consectetur. In adipisicing exercitation commodo ullamco elit. Incididunt deserunt id veniam dolore incididunt eiusmod excepteur exercitation commodo anim et ipsum cupidatat. In occaecat eiusmod minim duis.\r\n", + "registered": "2007-06-07T22:04:27+05:00", + "friends": [ + { + "id": 0, + "name": "Jenkins Emerson" + }, + { + "id": 1, + "name": "Kerr Gonzales" + }, + { + "id": 2, + "name": "Aimee Cardenas" + } + ] + }, + { + "id": 132, + "guid": "d714458a-aa77-4652-aa1e-dcb2fcbcc0be", + "isActive": false, + "balance": "$1,213.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Jacquelyn Dean", + "gender": "female", + "company": "Zaj", + "email": "jacquelyndean@zaj.com", + "phone": "+1 (862) 426-2572", + "address": { + "street": 968, + "city": "Bannock", + "state": "South Carolina", + "zip": 7399 + }, + "about": "Minim nostrud minim nisi cillum velit est amet Lorem incididunt proident magna in esse. Velit incididunt esse excepteur et amet consequat ut mollit id. Nisi ex tempor aute anim consectetur deserunt id magna Lorem reprehenderit proident.\r\n", + "registered": "1988-11-09T17:54:58+06:00", + "friends": [ + { + "id": 0, + "name": "Glenn Acosta" + }, + { + "id": 1, + "name": "Morris Kennedy" + }, + { + "id": 2, + "name": "Manning Bird" + } + ] + }, + { + "id": 133, + "guid": "2f997187-3e41-451a-8bc1-1377f7f93ca3", + "isActive": false, + "balance": "$2,559.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Beck Mccall", + "gender": "male", + "company": "Ebidco", + "email": "beckmccall@ebidco.com", + "phone": "+1 (972) 519-3952", + "address": { + "street": 409, + "city": "Fillmore", + "state": "Louisiana", + "zip": 5367 + }, + "about": "Minim fugiat eiusmod amet pariatur ex eiusmod mollit. Anim consequat mollit ipsum nisi officia aliqua. Ullamco ullamco tempor ipsum enim aute do. Consectetur commodo non eu dolore adipisicing commodo sit ea deserunt non. Ut est cillum dolore qui tempor pariatur. Voluptate incididunt quis minim proident consectetur id. Irure ut voluptate qui et culpa.\r\n", + "registered": "2010-08-31T19:52:31+05:00", + "friends": [ + { + "id": 0, + "name": "Yesenia Hancock" + }, + { + "id": 1, + "name": "Rosa Perez" + }, + { + "id": 2, + "name": "Bridgette Wright" + } + ] + }, + { + "id": 134, + "guid": "70e8f207-c84c-41bf-aa00-d3f546c61463", + "isActive": true, + "balance": "$1,778.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Angelique Gardner", + "gender": "female", + "company": "Imperium", + "email": "angeliquegardner@imperium.com", + "phone": "+1 (879) 577-2860", + "address": { + "street": 556, + "city": "Bladensburg", + "state": "North Dakota", + "zip": 5974 + }, + "about": "Labore laboris Lorem mollit ut sit ex mollit. Amet eu mollit tempor consectetur Lorem tempor ipsum. Proident duis qui dolor dolore commodo anim est magna ad ipsum aliqua. Sunt eu pariatur incididunt sunt cillum proident cillum officia dolor culpa do. Ipsum aliqua eu id proident fugiat. Et commodo ea laborum sint.\r\n", + "registered": "1994-07-03T13:48:47+05:00", + "friends": [ + { + "id": 0, + "name": "Mai Webb" + }, + { + "id": 1, + "name": "Margo Figueroa" + }, + { + "id": 2, + "name": "Bray Ferguson" + } + ] + }, + { + "id": 135, + "guid": "b0765507-53b8-4756-82f4-8c9cd73e8faf", + "isActive": true, + "balance": "$2,133.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Penelope Foster", + "gender": "female", + "company": "Digifad", + "email": "penelopefoster@digifad.com", + "phone": "+1 (906) 565-2492", + "address": { + "street": 482, + "city": "Canoochee", + "state": "Vermont", + "zip": 1625 + }, + "about": "Pariatur dolore sint velit pariatur esse fugiat eiusmod culpa aute aute velit. Cillum ad aliquip cillum mollit ex nulla deserunt labore. Do sint dolor voluptate do culpa in et et reprehenderit quis aliqua consequat ea.\r\n", + "registered": "2011-09-02T22:07:52+05:00", + "friends": [ + { + "id": 0, + "name": "Strong Hodges" + }, + { + "id": 1, + "name": "Millicent Sosa" + }, + { + "id": 2, + "name": "Bonita Cole" + } + ] + }, + { + "id": 136, + "guid": "082165e2-84c2-45bd-85ab-6240cc79f343", + "isActive": false, + "balance": "$1,626.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Clarice Macias", + "gender": "female", + "company": "Visualix", + "email": "claricemacias@visualix.com", + "phone": "+1 (879) 423-3121", + "address": { + "street": 445, + "city": "Boyd", + "state": "North Carolina", + "zip": 9966 + }, + "about": "Duis magna pariatur ullamco irure do ea exercitation do. Voluptate cillum cupidatat nostrud ut culpa ipsum. Excepteur enim reprehenderit dolor mollit nisi do Lorem fugiat. Culpa eiusmod qui amet irure aliqua deserunt nulla nisi eu. Duis eiusmod sunt culpa pariatur non elit proident ut incididunt.\r\n", + "registered": "2005-02-28T21:34:57+06:00", + "friends": [ + { + "id": 0, + "name": "Jennings Bates" + }, + { + "id": 1, + "name": "Yvette Bryant" + }, + { + "id": 2, + "name": "Foster Bush" + } + ] + }, + { + "id": 137, + "guid": "c3203d03-d7a7-423a-ba9e-09460ebab11f", + "isActive": true, + "balance": "$1,367.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Boyle Dale", + "gender": "male", + "company": "Niquent", + "email": "boyledale@niquent.com", + "phone": "+1 (947) 596-2316", + "address": { + "street": 206, + "city": "Homeland", + "state": "Pennsylvania", + "zip": 4041 + }, + "about": "Dolor quis minim mollit irure excepteur nisi tempor dolor incididunt elit. Sunt officia proident sunt anim voluptate minim id. Ipsum cupidatat duis et qui nisi voluptate tempor laborum ut do mollit. Cillum adipisicing duis exercitation ipsum est occaecat. Irure magna deserunt fugiat ea eiusmod fugiat nisi esse. In amet eiusmod non mollit minim culpa elit consectetur cillum ad anim eiusmod sint aliqua. Ex fugiat aliqua labore et cupidatat occaecat mollit dolore pariatur id eu est est.\r\n", + "registered": "2006-12-25T07:16:06+06:00", + "friends": [ + { + "id": 0, + "name": "Wilkins Larsen" + }, + { + "id": 1, + "name": "Rosalyn Dennis" + }, + { + "id": 2, + "name": "Flossie Matthews" + } + ] + }, + { + "id": 138, + "guid": "51357561-ada6-4871-b001-3922205f23b1", + "isActive": true, + "balance": "$2,980.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Espinoza Brooks", + "gender": "male", + "company": "Flyboyz", + "email": "espinozabrooks@flyboyz.com", + "phone": "+1 (953) 476-2580", + "address": { + "street": 392, + "city": "Alamo", + "state": "Wisconsin", + "zip": 1626 + }, + "about": "Dolore irure consequat sunt Lorem officia pariatur ut ut et ea magna nulla non veniam. Cupidatat id amet elit incididunt adipisicing anim consectetur sunt aliqua. Id aliquip reprehenderit nostrud elit qui aute cupidatat aute id cillum nulla veniam amet.\r\n", + "registered": "1997-11-29T01:50:30+06:00", + "friends": [ + { + "id": 0, + "name": "Vang Cobb" + }, + { + "id": 1, + "name": "Brittney Morris" + }, + { + "id": 2, + "name": "Washington Beard" + } + ] + }, + { + "id": 139, + "guid": "b25fb618-922f-48f7-98d7-c526082b54ab", + "isActive": true, + "balance": "$2,337.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Dolly Miller", + "gender": "female", + "company": "Quarex", + "email": "dollymiller@quarex.com", + "phone": "+1 (935) 527-2943", + "address": { + "street": 249, + "city": "Chical", + "state": "Utah", + "zip": 8996 + }, + "about": "In excepteur nisi duis sunt esse cupidatat non. Deserunt voluptate commodo veniam laboris velit et aute non nulla duis exercitation. Enim anim dolor deserunt nulla esse anim aute id do aliquip duis enim minim ut. Irure nulla velit mollit sunt dolor velit labore consectetur est nulla nulla ullamco magna nulla. Pariatur id ut exercitation consequat non eiusmod esse anim. Tempor sint do nisi veniam.\r\n", + "registered": "1994-07-24T07:13:41+05:00", + "friends": [ + { + "id": 0, + "name": "Twila Powers" + }, + { + "id": 1, + "name": "Ryan Wyatt" + }, + { + "id": 2, + "name": "Burks Clark" + } + ] + }, + { + "id": 140, + "guid": "291d61ca-0235-4e94-9510-0b3689e7ef2f", + "isActive": false, + "balance": "$1,489.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Goodwin Alford", + "gender": "male", + "company": "Escenta", + "email": "goodwinalford@escenta.com", + "phone": "+1 (865) 481-3772", + "address": { + "street": 953, + "city": "Smeltertown", + "state": "Kentucky", + "zip": 604 + }, + "about": "Eiusmod enim culpa aliqua ea ex reprehenderit. Dolore quis cupidatat labore incididunt magna. Commodo magna voluptate reprehenderit aliquip ea. Irure aute proident officia occaecat non incididunt Lorem cupidatat nisi. Ad amet dolor consectetur ipsum occaecat esse consequat non reprehenderit esse laboris aliqua nulla. Qui do aliqua est officia adipisicing sunt anim dolor occaecat ullamco laborum velit ut.\r\n", + "registered": "1999-04-29T15:12:29+05:00", + "friends": [ + { + "id": 0, + "name": "Araceli Albert" + }, + { + "id": 1, + "name": "Jeanette Neal" + }, + { + "id": 2, + "name": "Woodard Sharp" + } + ] + }, + { + "id": 141, + "guid": "737fe951-f2e3-4778-acc6-2fef5158380e", + "isActive": false, + "balance": "$3,732.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Joan Preston", + "gender": "female", + "company": "Techtrix", + "email": "joanpreston@techtrix.com", + "phone": "+1 (972) 503-2155", + "address": { + "street": 711, + "city": "Oberlin", + "state": "Iowa", + "zip": 4383 + }, + "about": "Sit ullamco nisi quis ad non sint. Magna amet anim irure ad enim dolore. Commodo elit est sit veniam labore qui esse exercitation eu. Amet labore aliquip aute et in ipsum culpa voluptate ut exercitation sit exercitation.\r\n", + "registered": "2001-06-20T03:25:04+05:00", + "friends": [ + { + "id": 0, + "name": "Marquez Heath" + }, + { + "id": 1, + "name": "Roach Hubbard" + }, + { + "id": 2, + "name": "Karla Phillips" + } + ] + }, + { + "id": 142, + "guid": "5da94330-73c0-4b2d-a887-06e5f9a27dac", + "isActive": true, + "balance": "$2,473.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Kramer Booker", + "gender": "male", + "company": "Orbaxter", + "email": "kramerbooker@orbaxter.com", + "phone": "+1 (995) 524-3299", + "address": { + "street": 520, + "city": "Twilight", + "state": "Ohio", + "zip": 6151 + }, + "about": "Voluptate consequat pariatur nulla Lorem fugiat consequat deserunt anim eiusmod. Sunt reprehenderit amet ut enim fugiat tempor eiusmod. Veniam nulla tempor esse fugiat exercitation occaecat labore nisi incididunt. Nisi enim ipsum nulla quis duis qui in. Ipsum pariatur excepteur incididunt aliquip veniam sit anim qui et sunt ullamco eiusmod. Reprehenderit commodo nostrud sint cupidatat dolor veniam.\r\n", + "registered": "1993-08-15T13:12:28+05:00", + "friends": [ + { + "id": 0, + "name": "Charlene Wade" + }, + { + "id": 1, + "name": "Oliver Chang" + }, + { + "id": 2, + "name": "Sadie Dillard" + } + ] + }, + { + "id": 143, + "guid": "20a5a300-59e0-4dca-86af-e0916e367aef", + "isActive": false, + "balance": "$2,644.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Carpenter Hammond", + "gender": "male", + "company": "Tropolis", + "email": "carpenterhammond@tropolis.com", + "phone": "+1 (927) 583-3026", + "address": { + "street": 770, + "city": "Healy", + "state": "Maine", + "zip": 1750 + }, + "about": "Id nostrud consectetur sint labore irure cupidatat cupidatat aute. Lorem sint fugiat laboris officia laborum fugiat excepteur consequat nostrud ut laboris ad do ullamco. Elit nostrud labore ullamco ex elit velit sunt ullamco sit do ullamco quis commodo. Ex ipsum est reprehenderit amet esse est eu sunt. Minim proident ea Lorem et cillum id laborum eiusmod est exercitation ut.\r\n", + "registered": "2002-08-02T16:18:58+05:00", + "friends": [ + { + "id": 0, + "name": "Atkins Mueller" + }, + { + "id": 1, + "name": "Key Mcgee" + }, + { + "id": 2, + "name": "Rhoda Cantrell" + } + ] + }, + { + "id": 144, + "guid": "cb828595-cdd8-44a0-966b-aeb08300537d", + "isActive": true, + "balance": "$2,927.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Guthrie Stokes", + "gender": "male", + "company": "Polarax", + "email": "guthriestokes@polarax.com", + "phone": "+1 (808) 584-2974", + "address": { + "street": 280, + "city": "Vicksburg", + "state": "Hawaii", + "zip": 7206 + }, + "about": "Esse sit est ullamco proident dolor non occaecat aute. Lorem occaecat cillum sit do minim nulla adipisicing fugiat sunt. Eu esse commodo tempor ullamco non mollit eu ullamco laborum. Laboris exercitation dolor dolore nisi fugiat mollit ex amet proident dolor occaecat in aliquip ipsum. Tempor labore cillum excepteur irure veniam nulla. Excepteur eu Lorem nisi pariatur nostrud nulla et laborum ullamco nostrud magna. Aute elit proident mollit culpa ad.\r\n", + "registered": "2007-05-18T04:45:10+05:00", + "friends": [ + { + "id": 0, + "name": "Billie Juarez" + }, + { + "id": 1, + "name": "Rose Stone" + }, + { + "id": 2, + "name": "Lesa Gilmore" + } + ] + }, + { + "id": 145, + "guid": "e5e818c3-76af-4380-a90f-98761516986c", + "isActive": true, + "balance": "$1,844.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Gillespie Rojas", + "gender": "male", + "company": "Helixo", + "email": "gillespierojas@helixo.com", + "phone": "+1 (822) 458-3034", + "address": { + "street": 197, + "city": "Loyalhanna", + "state": "Arkansas", + "zip": 7453 + }, + "about": "Sunt incididunt eiusmod dolor commodo id voluptate culpa ipsum incididunt Lorem do tempor ea. Sunt sint duis est laboris nulla. Enim ut commodo nulla ea occaecat. Adipisicing culpa sit ullamco velit laboris quis. Dolor reprehenderit exercitation veniam ut sint nostrud eu nulla amet proident veniam fugiat Lorem ad. Irure dolore tempor commodo fugiat.\r\n", + "registered": "2011-02-28T21:28:26+06:00", + "friends": [ + { + "id": 0, + "name": "Santana Mason" + }, + { + "id": 1, + "name": "Bridgett Fowler" + }, + { + "id": 2, + "name": "Jana Rogers" + } + ] + }, + { + "id": 146, + "guid": "9e762266-b65e-40f3-9fa4-d1a1082abd3f", + "isActive": true, + "balance": "$1,332.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Burns Bishop", + "gender": "male", + "company": "Isbol", + "email": "burnsbishop@isbol.com", + "phone": "+1 (973) 470-2443", + "address": { + "street": 885, + "city": "Chalfant", + "state": "Nebraska", + "zip": 5554 + }, + "about": "Eiusmod sunt fugiat id non mollit aliquip esse sunt eiusmod qui. Enim ea Lorem ullamco ipsum. Laborum mollit consequat et mollit tempor tempor dolore officia. Veniam mollit nisi excepteur dolore non Lorem duis ipsum dolor irure consequat irure magna.\r\n", + "registered": "2013-10-11T20:36:28+05:00", + "friends": [ + { + "id": 0, + "name": "Chapman Owens" + }, + { + "id": 1, + "name": "Mccray Schmidt" + }, + { + "id": 2, + "name": "Tracy Blankenship" + } + ] + }, + { + "id": 147, + "guid": "60797637-17e0-485b-b9f0-bc6946d5ddfd", + "isActive": true, + "balance": "$3,658.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Nolan Romero", + "gender": "male", + "company": "Turnling", + "email": "nolanromero@turnling.com", + "phone": "+1 (897) 500-3920", + "address": { + "street": 913, + "city": "Ronco", + "state": "Delaware", + "zip": 7379 + }, + "about": "Magna labore consequat eiusmod cupidatat laboris eu esse officia exercitation magna. Ad eu consectetur duis incididunt adipisicing irure ipsum dolor exercitation laborum est sit velit. Ea eu ad reprehenderit pariatur reprehenderit commodo cillum ipsum. Cupidatat laboris incididunt consequat cillum eu irure excepteur Lorem minim consequat minim exercitation proident est. Incididunt occaecat velit commodo occaecat. Dolore eiusmod consequat deserunt incididunt ullamco nostrud laboris ad ut sit dolore enim fugiat.\r\n", + "registered": "2012-11-07T00:04:26+06:00", + "friends": [ + { + "id": 0, + "name": "Ofelia Herring" + }, + { + "id": 1, + "name": "Mann David" + }, + { + "id": 2, + "name": "Reese Knight" + } + ] + }, + { + "id": 148, + "guid": "4faee5bb-41e0-4ee7-b0b1-ef48b185d405", + "isActive": false, + "balance": "$1,913.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Mendoza Gilmore", + "gender": "male", + "company": "Undertap", + "email": "mendozagilmore@undertap.com", + "phone": "+1 (844) 524-3950", + "address": { + "street": 975, + "city": "Muir", + "state": "New Mexico", + "zip": 8309 + }, + "about": "Aliqua nulla proident excepteur est laborum adipisicing amet consequat ea duis aute occaecat ad. Ipsum anim et proident enim ex exercitation cillum sit excepteur. Ut nisi sit cupidatat sint anim do minim velit dolor cillum. Est irure ea culpa esse et eiusmod consectetur cillum quis.\r\n", + "registered": "2000-05-26T04:03:38+05:00", + "friends": [ + { + "id": 0, + "name": "Charity Frost" + }, + { + "id": 1, + "name": "Frost Walton" + }, + { + "id": 2, + "name": "Betty Miranda" + } + ] + }, + { + "id": 149, + "guid": "ed0f1742-1fad-4618-8aec-0b5d9d27db17", + "isActive": true, + "balance": "$2,222.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Barton Martinez", + "gender": "male", + "company": "Insuron", + "email": "bartonmartinez@insuron.com", + "phone": "+1 (945) 563-2527", + "address": { + "street": 671, + "city": "Hannasville", + "state": "Tennessee", + "zip": 5087 + }, + "about": "Culpa et aliquip ipsum labore id nisi cupidatat ut ea consequat ipsum exercitation. Ipsum ut mollit elit dolor eu esse excepteur in culpa minim aliqua fugiat cupidatat. Mollit anim consectetur anim officia.\r\n", + "registered": "1992-09-24T07:35:03+05:00", + "friends": [ + { + "id": 0, + "name": "Austin York" + }, + { + "id": 1, + "name": "Hess Andrews" + }, + { + "id": 2, + "name": "Danielle Horn" + } + ] + }, + { + "id": 150, + "guid": "ee9c49bc-f394-46fe-b308-22f51f439c19", + "isActive": false, + "balance": "$2,844.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Cecile Dorsey", + "gender": "female", + "company": "Tetratrex", + "email": "ceciledorsey@tetratrex.com", + "phone": "+1 (917) 564-2202", + "address": { + "street": 618, + "city": "Defiance", + "state": "California", + "zip": 9018 + }, + "about": "Laboris cupidatat fugiat consequat sit nisi et aliquip adipisicing dolore aliqua eiusmod Lorem ut proident. Nulla voluptate reprehenderit laboris elit eiusmod aliquip ad minim sit. Ex labore sit pariatur tempor pariatur culpa velit reprehenderit irure officia enim exercitation fugiat. Labore et Lorem minim do eu cupidatat excepteur dolor.\r\n", + "registered": "1991-10-15T08:24:05+05:00", + "friends": [ + { + "id": 0, + "name": "June Britt" + }, + { + "id": 1, + "name": "Ashley Tucker" + }, + { + "id": 2, + "name": "Mcintyre Maldonado" + } + ] + }, + { + "id": 151, + "guid": "cac4e84d-be79-4d96-981d-2eacb33909d0", + "isActive": true, + "balance": "$2,786.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Franks Herrera", + "gender": "male", + "company": "Arctiq", + "email": "franksherrera@arctiq.com", + "phone": "+1 (954) 417-2621", + "address": { + "street": 979, + "city": "Stewart", + "state": "Kansas", + "zip": 3408 + }, + "about": "Consectetur aliquip laborum in voluptate consectetur ipsum minim. Magna fugiat adipisicing magna veniam. Reprehenderit dolor reprehenderit consectetur enim in elit officia. Occaecat incididunt adipisicing velit et nostrud sit elit dolore. Deserunt qui aliquip eiusmod exercitation.\r\n", + "registered": "2005-12-25T03:15:50+06:00", + "friends": [ + { + "id": 0, + "name": "Ernestine Ashley" + }, + { + "id": 1, + "name": "Dudley Ballard" + }, + { + "id": 2, + "name": "Teresa Young" + } + ] + }, + { + "id": 152, + "guid": "fa07a404-6fdb-4cc4-a530-00b82160e80a", + "isActive": false, + "balance": "$2,711.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Francisca Foreman", + "gender": "female", + "company": "Petigems", + "email": "franciscaforeman@petigems.com", + "phone": "+1 (943) 511-3813", + "address": { + "street": 690, + "city": "Masthope", + "state": "New Hampshire", + "zip": 8290 + }, + "about": "Minim labore Lorem laborum fugiat sit ex esse excepteur laboris esse pariatur. Dolore eu laboris incididunt esse exercitation labore sit occaecat. Ut proident et magna veniam.\r\n", + "registered": "2010-07-31T00:34:25+05:00", + "friends": [ + { + "id": 0, + "name": "Bowman Harding" + }, + { + "id": 1, + "name": "Florine Butler" + }, + { + "id": 2, + "name": "Sherri Fry" + } + ] + }, + { + "id": 153, + "guid": "60cb20b3-63b0-4eea-80c3-0c3bcbf7adb1", + "isActive": true, + "balance": "$3,722.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Allie Gonzales", + "gender": "female", + "company": "Extremo", + "email": "alliegonzales@extremo.com", + "phone": "+1 (921) 427-3341", + "address": { + "street": 973, + "city": "Independence", + "state": "Arkansas", + "zip": 6163 + }, + "about": "Consequat laborum aliqua adipisicing excepteur laboris ex est adipisicing mollit. Nulla tempor voluptate duis occaecat dolor pariatur dolore officia ipsum pariatur in sint quis fugiat. Dolore ea proident aliquip deserunt aliqua aute.\r\n", + "registered": "1993-04-30T23:53:30+05:00", + "friends": [ + { + "id": 0, + "name": "Park Spence" + }, + { + "id": 1, + "name": "Bridgett Mccarty" + }, + { + "id": 2, + "name": "Johnson Schroeder" + } + ] + }, + { + "id": 154, + "guid": "215e1e5b-ec2e-4c3f-8399-a179326f25a6", + "isActive": true, + "balance": "$2,083.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Vance Hamilton", + "gender": "male", + "company": "Naxdis", + "email": "vancehamilton@naxdis.com", + "phone": "+1 (986) 416-2020", + "address": { + "street": 472, + "city": "Choctaw", + "state": "Colorado", + "zip": 4825 + }, + "about": "Consequat labore enim consectetur sunt anim aliqua ea qui consequat eu minim ad sit. Enim sit occaecat sint minim amet labore consectetur exercitation do incididunt id cupidatat amet nulla. Elit ullamco quis nisi ad officia aliquip occaecat dolor minim consectetur ut. Eu voluptate officia tempor laboris sunt ea elit cillum sint ipsum quis incididunt ut. Lorem dolor qui exercitation ex est adipisicing Lorem.\r\n", + "registered": "1993-04-11T15:45:35+05:00", + "friends": [ + { + "id": 0, + "name": "Waters Lamb" + }, + { + "id": 1, + "name": "Avis Terrell" + }, + { + "id": 2, + "name": "Wanda Dickson" + } + ] + }, + { + "id": 155, + "guid": "513ecccb-ce41-4be7-ad82-2fc1e2232673", + "isActive": true, + "balance": "$2,475.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Houston Park", + "gender": "male", + "company": "Lyria", + "email": "houstonpark@lyria.com", + "phone": "+1 (973) 453-3701", + "address": { + "street": 971, + "city": "Linganore", + "state": "Oregon", + "zip": 5912 + }, + "about": "In commodo aute minim ipsum qui. Deserunt irure qui excepteur irure Lorem. Laborum culpa et enim nostrud occaecat cillum nulla ullamco minim ipsum mollit irure culpa. Officia ea laboris nisi id sunt incididunt id aliquip excepteur. Eiusmod mollit duis nostrud qui et laborum. Ullamco deserunt fugiat ad fugiat laboris magna laboris incididunt. In ad Lorem id velit reprehenderit laborum ex voluptate aute mollit ea ipsum.\r\n", + "registered": "2013-01-01T23:23:45+06:00", + "friends": [ + { + "id": 0, + "name": "Leann Burt" + }, + { + "id": 1, + "name": "Atkins Thompson" + }, + { + "id": 2, + "name": "Bolton Fuentes" + } + ] + }, + { + "id": 156, + "guid": "6d721b2e-1dbe-4770-a2bc-e83dfe3adcf4", + "isActive": false, + "balance": "$1,638.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Sharon Meyers", + "gender": "female", + "company": "Hyplex", + "email": "sharonmeyers@hyplex.com", + "phone": "+1 (906) 529-3578", + "address": { + "street": 720, + "city": "Orick", + "state": "Florida", + "zip": 5865 + }, + "about": "Occaecat sint anim labore ea excepteur tempor consequat aliquip ullamco non. Sunt anim sit Lorem tempor ut sunt. Dolore sunt occaecat duis cupidatat.\r\n", + "registered": "2004-07-20T01:27:52+05:00", + "friends": [ + { + "id": 0, + "name": "Britt Coffey" + }, + { + "id": 1, + "name": "Kristina Myers" + }, + { + "id": 2, + "name": "Elinor Roach" + } + ] + }, + { + "id": 157, + "guid": "d81c7582-7780-4b7d-8fb2-d02051577e0f", + "isActive": true, + "balance": "$1,431.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Singleton Lyons", + "gender": "male", + "company": "Centregy", + "email": "singletonlyons@centregy.com", + "phone": "+1 (998) 424-3737", + "address": { + "street": 278, + "city": "Eureka", + "state": "Illinois", + "zip": 2200 + }, + "about": "Exercitation dolor nisi Lorem culpa exercitation minim. Dolore ullamco consequat in magna deserunt aliqua aute eiusmod. Eu proident dolor fugiat officia nostrud aliqua ut ex pariatur non aute.\r\n", + "registered": "2010-09-23T15:31:46+05:00", + "friends": [ + { + "id": 0, + "name": "Benton Mckenzie" + }, + { + "id": 1, + "name": "Patti Lloyd" + }, + { + "id": 2, + "name": "Cecelia Acosta" + } + ] + }, + { + "id": 158, + "guid": "bbbcaca1-a18a-4923-8b47-15ed88093c29", + "isActive": true, + "balance": "$3,010.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Snyder Becker", + "gender": "male", + "company": "Neptide", + "email": "snyderbecker@neptide.com", + "phone": "+1 (823) 406-3315", + "address": { + "street": 420, + "city": "Nadine", + "state": "Kentucky", + "zip": 2473 + }, + "about": "Velit irure in proident excepteur voluptate eu voluptate. Cillum eu aliqua minim ad. Aute irure adipisicing cillum anim dolore. Ea laborum reprehenderit excepteur aliqua in elit eiusmod quis proident. Consectetur sint aute do aute dolor nostrud.\r\n", + "registered": "2003-07-31T10:15:36+05:00", + "friends": [ + { + "id": 0, + "name": "Morrison Hahn" + }, + { + "id": 1, + "name": "Heather Stephenson" + }, + { + "id": 2, + "name": "Rosanna Brewer" + } + ] + }, + { + "id": 159, + "guid": "f996d7f6-57b8-4eea-8363-ac4357d0a97d", + "isActive": true, + "balance": "$2,073.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Velazquez Macdonald", + "gender": "male", + "company": "Earthwax", + "email": "velazquezmacdonald@earthwax.com", + "phone": "+1 (918) 473-2383", + "address": { + "street": 323, + "city": "Wedgewood", + "state": "Texas", + "zip": 7081 + }, + "about": "Quis ex non aliqua in. Sunt enim do fugiat sint cillum cupidatat commodo in quis deserunt. Duis esse amet id id. Quis commodo nulla sunt commodo quis ex irure cillum. Ut enim magna enim mollit fugiat.\r\n", + "registered": "1990-03-08T03:49:44+06:00", + "friends": [ + { + "id": 0, + "name": "Angelita Rocha" + }, + { + "id": 1, + "name": "Kirby Pace" + }, + { + "id": 2, + "name": "Judy Weaver" + } + ] + }, + { + "id": 160, + "guid": "81f7cb89-3bed-41fc-a98d-9f445eac8f1b", + "isActive": true, + "balance": "$2,226.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Corina Ayala", + "gender": "female", + "company": "Snacktion", + "email": "corinaayala@snacktion.com", + "phone": "+1 (949) 405-2957", + "address": { + "street": 897, + "city": "Ribera", + "state": "Louisiana", + "zip": 214 + }, + "about": "Labore proident do ullamco velit ipsum voluptate Lorem reprehenderit tempor laboris anim. Est irure cupidatat cupidatat pariatur. Consectetur adipisicing Lorem nostrud duis consequat officia proident culpa.\r\n", + "registered": "2003-08-27T03:31:51+05:00", + "friends": [ + { + "id": 0, + "name": "Wendi Pickett" + }, + { + "id": 1, + "name": "Nadia Kramer" + }, + { + "id": 2, + "name": "Hickman Wall" + } + ] + }, + { + "id": 161, + "guid": "d04357c5-2cb2-46b5-ba0e-65618ca75b04", + "isActive": false, + "balance": "$2,420.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Glenna Hardy", + "gender": "female", + "company": "Izzby", + "email": "glennahardy@izzby.com", + "phone": "+1 (849) 479-2064", + "address": { + "street": 970, + "city": "Nile", + "state": "Minnesota", + "zip": 8402 + }, + "about": "Eiusmod nisi sunt culpa Lorem anim. Amet laborum et ut et aliquip ex reprehenderit duis consequat. Id eiusmod nisi cillum amet anim ut aliquip dolore enim anim officia aliqua reprehenderit. Deserunt dolore aute reprehenderit dolor.\r\n", + "registered": "1994-01-21T23:28:40+06:00", + "friends": [ + { + "id": 0, + "name": "Weeks Grimes" + }, + { + "id": 1, + "name": "Olsen Stephens" + }, + { + "id": 2, + "name": "Kaye Newman" + } + ] + }, + { + "id": 162, + "guid": "b29c9ae0-e21a-4310-990e-af1fce2779bb", + "isActive": true, + "balance": "$3,956.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Justice Allen", + "gender": "male", + "company": "Geekosis", + "email": "justiceallen@geekosis.com", + "phone": "+1 (884) 557-2987", + "address": { + "street": 638, + "city": "Southmont", + "state": "Washington", + "zip": 4153 + }, + "about": "Laborum proident velit velit proident magna nostrud irure occaecat qui qui officia eiusmod deserunt. Exercitation duis incididunt esse laboris nulla esse ipsum. Veniam ut exercitation culpa fugiat commodo enim et ut ipsum qui cillum enim aute.\r\n", + "registered": "1995-06-11T13:27:38+05:00", + "friends": [ + { + "id": 0, + "name": "Wilder Frank" + }, + { + "id": 1, + "name": "Lily Munoz" + }, + { + "id": 2, + "name": "Beverley Leblanc" + } + ] + }, + { + "id": 163, + "guid": "22c7cce0-84ec-4c0f-93e1-e4d7a862bdb4", + "isActive": true, + "balance": "$2,568.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Randi Landry", + "gender": "female", + "company": "Obones", + "email": "randilandry@obones.com", + "phone": "+1 (959) 599-3666", + "address": { + "street": 296, + "city": "Rowe", + "state": "Idaho", + "zip": 1831 + }, + "about": "Mollit exercitation cupidatat aliquip deserunt. Sunt tempor esse ipsum non. Id ex labore deserunt tempor cillum dolor amet esse. Enim dolore veniam mollit dolor aliquip incididunt ex nostrud exercitation. Ea sint occaecat dolore cupidatat deserunt ea consequat duis qui laboris sunt aliquip velit incididunt. Duis irure ipsum sunt elit veniam cillum non do dolor duis ea. Exercitation ea mollit aliquip eiusmod eu id elit anim laboris ea incididunt sint laborum.\r\n", + "registered": "2000-05-12T22:47:11+05:00", + "friends": [ + { + "id": 0, + "name": "Perez Adams" + }, + { + "id": 1, + "name": "Jeanie English" + }, + { + "id": 2, + "name": "Mcfadden Sherman" + } + ] + }, + { + "id": 164, + "guid": "7bf28852-d33c-45ee-960c-eff8f00e9bbf", + "isActive": false, + "balance": "$1,570.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Gray Leach", + "gender": "male", + "company": "Infotrips", + "email": "grayleach@infotrips.com", + "phone": "+1 (929) 459-2028", + "address": { + "street": 466, + "city": "Hamilton", + "state": "North Dakota", + "zip": 6361 + }, + "about": "Enim in ex laborum pariatur fugiat aliquip adipisicing adipisicing. Dolore nostrud minim sint id ipsum aute sit deserunt. Velit irure anim nisi magna sunt incididunt nisi veniam. Nostrud tempor consectetur proident officia id esse sint quis commodo Lorem pariatur esse laborum aute. Ea officia est ut ea ex eiusmod officia laborum occaecat non nulla exercitation. Lorem incididunt quis Lorem officia sunt anim consectetur ut.\r\n", + "registered": "1996-09-08T17:06:30+05:00", + "friends": [ + { + "id": 0, + "name": "Patrice Davenport" + }, + { + "id": 1, + "name": "Paulette Dunlap" + }, + { + "id": 2, + "name": "Whitehead Stein" + } + ] + }, + { + "id": 165, + "guid": "7cf86794-ddc9-4f7c-a1b3-f29455ee7be4", + "isActive": false, + "balance": "$1,731.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Shelley Stanton", + "gender": "female", + "company": "Xoggle", + "email": "shelleystanton@xoggle.com", + "phone": "+1 (848) 491-3114", + "address": { + "street": 981, + "city": "Iberia", + "state": "Mississippi", + "zip": 1889 + }, + "about": "Culpa eiusmod incididunt exercitation dolor ad. Sunt eu pariatur minim exercitation officia Lorem. Labore duis sint irure ut sint irure. Amet adipisicing aliquip sunt id qui dolor sunt dolor. In fugiat mollit ad labore aliquip exercitation eu mollit quis in. Eu enim amet sit ex fugiat aliqua pariatur. Nisi fugiat ullamco tempor officia esse culpa dolor enim ipsum officia cupidatat.\r\n", + "registered": "2012-11-23T10:33:15+06:00", + "friends": [ + { + "id": 0, + "name": "Leta Duke" + }, + { + "id": 1, + "name": "Mabel Stevenson" + }, + { + "id": 2, + "name": "Burt Herman" + } + ] + }, + { + "id": 166, + "guid": "fb87f70f-8fd2-480c-ba0f-99000645d6fc", + "isActive": false, + "balance": "$1,769.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Roman Estrada", + "gender": "male", + "company": "Vetron", + "email": "romanestrada@vetron.com", + "phone": "+1 (920) 461-3525", + "address": { + "street": 350, + "city": "Cade", + "state": "Wyoming", + "zip": 8667 + }, + "about": "Sint adipisicing excepteur ut laboris excepteur ex fugiat officia Lorem eiusmod culpa minim veniam dolor. Eu et et qui magna exercitation magna officia nisi nostrud sint reprehenderit reprehenderit mollit ut. Amet cupidatat quis elit sint do non quis consectetur proident aliquip. Eu veniam ullamco ex anim ad commodo minim veniam ea laboris. Exercitation nisi ex ea esse.\r\n", + "registered": "2001-03-09T16:00:34+06:00", + "friends": [ + { + "id": 0, + "name": "Shawna Beck" + }, + { + "id": 1, + "name": "Mclean Wong" + }, + { + "id": 2, + "name": "Socorro Bell" + } + ] + }, + { + "id": 167, + "guid": "9ad3c18e-d49a-466d-87ad-5ede1c46f753", + "isActive": false, + "balance": "$1,056.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Blair Buckner", + "gender": "male", + "company": "Genmy", + "email": "blairbuckner@genmy.com", + "phone": "+1 (850) 434-2631", + "address": { + "street": 805, + "city": "Nettie", + "state": "Ohio", + "zip": 4630 + }, + "about": "Tempor dolore mollit minim excepteur amet velit ut pariatur commodo amet. Culpa reprehenderit ex ut esse. Pariatur dolore nulla pariatur non. Non ex culpa ut tempor laborum cillum veniam reprehenderit nisi culpa nulla do id qui.\r\n", + "registered": "1990-04-28T00:31:39+05:00", + "friends": [ + { + "id": 0, + "name": "Carla Bauer" + }, + { + "id": 1, + "name": "Annette Head" + }, + { + "id": 2, + "name": "Zimmerman Bradford" + } + ] + }, + { + "id": 168, + "guid": "a6ff56c2-e388-47f1-9e43-d7672d5b2cad", + "isActive": false, + "balance": "$3,155.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Greene May", + "gender": "male", + "company": "Digial", + "email": "greenemay@digial.com", + "phone": "+1 (901) 560-3153", + "address": { + "street": 950, + "city": "Fidelis", + "state": "Indiana", + "zip": 4254 + }, + "about": "Eiusmod qui in aliqua pariatur id elit. Irure occaecat irure ad consequat id voluptate velit veniam aliqua. Voluptate ex voluptate Lorem magna occaecat ullamco cillum nisi commodo aute. Sit nulla laborum esse quis pariatur nulla do enim eu commodo adipisicing nostrud irure exercitation. Enim tempor magna aliqua cillum enim elit mollit occaecat. Ipsum voluptate proident nulla sint commodo velit adipisicing laborum aliqua pariatur reprehenderit officia et ipsum. Elit in consectetur sint dolore veniam minim qui labore qui velit.\r\n", + "registered": "2008-12-21T22:22:22+06:00", + "friends": [ + { + "id": 0, + "name": "Bullock Nicholson" + }, + { + "id": 1, + "name": "Vaughan Beard" + }, + { + "id": 2, + "name": "Constance Hall" + } + ] + }, + { + "id": 169, + "guid": "066609b0-9b38-420f-816d-045e4cde0a8c", + "isActive": false, + "balance": "$3,121.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Eunice Soto", + "gender": "female", + "company": "Vertide", + "email": "eunicesoto@vertide.com", + "phone": "+1 (844) 524-2108", + "address": { + "street": 200, + "city": "Biehle", + "state": "Montana", + "zip": 6767 + }, + "about": "Esse aliquip quis do ad excepteur dolor incididunt deserunt dolor mollit consectetur in. Incididunt labore occaecat sit fugiat id id do qui tempor reprehenderit. Qui in voluptate nostrud laborum velit qui veniam excepteur ex mollit ullamco cillum enim.\r\n", + "registered": "1995-05-08T02:23:54+05:00", + "friends": [ + { + "id": 0, + "name": "Hoffman Leonard" + }, + { + "id": 1, + "name": "Cohen Stark" + }, + { + "id": 2, + "name": "Audra Alvarado" + } + ] + }, + { + "id": 170, + "guid": "a4e1c42d-a624-41f6-93ca-e91018eabb10", + "isActive": true, + "balance": "$1,111.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Jennie Garrett", + "gender": "female", + "company": "Marvane", + "email": "jenniegarrett@marvane.com", + "phone": "+1 (831) 402-3146", + "address": { + "street": 615, + "city": "Temperanceville", + "state": "Pennsylvania", + "zip": 4076 + }, + "about": "Dolore ea culpa amet ad. Lorem voluptate aute est proident culpa commodo. Exercitation deserunt voluptate proident duis ullamco adipisicing nulla nulla culpa. Lorem eiusmod occaecat ea pariatur occaecat dolore nostrud veniam officia Lorem culpa eu proident. Lorem Lorem id aute quis magna do adipisicing culpa magna et laborum cupidatat. Ullamco commodo esse consequat mollit. Mollit laboris nulla occaecat cupidatat amet elit id.\r\n", + "registered": "2006-10-07T17:56:54+05:00", + "friends": [ + { + "id": 0, + "name": "Patricia Barrera" + }, + { + "id": 1, + "name": "Gilliam Bonner" + }, + { + "id": 2, + "name": "Maldonado Mendez" + } + ] + }, + { + "id": 171, + "guid": "db2bbee3-fb70-46ef-b84d-62bd7cbaff70", + "isActive": true, + "balance": "$2,930.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Bessie Mack", + "gender": "female", + "company": "Velos", + "email": "bessiemack@velos.com", + "phone": "+1 (929) 470-3801", + "address": { + "street": 271, + "city": "Newkirk", + "state": "Alabama", + "zip": 944 + }, + "about": "Incididunt aliquip quis do enim commodo ipsum. Tempor eiusmod enim id exercitation commodo id proident exercitation dolore labore dolore excepteur. Commodo esse ea ipsum cupidatat ad officia exercitation nostrud ullamco. Elit adipisicing commodo ea fugiat labore consequat culpa. Commodo culpa irure voluptate laboris cillum veniam velit aute ut ea commodo ad dolore voluptate.\r\n", + "registered": "1992-06-21T10:25:21+05:00", + "friends": [ + { + "id": 0, + "name": "Dominguez Bruce" + }, + { + "id": 1, + "name": "Avila Mcpherson" + }, + { + "id": 2, + "name": "Rene Farmer" + } + ] + }, + { + "id": 172, + "guid": "a145ede2-392b-45b7-ae1e-78ed4f04e5c5", + "isActive": false, + "balance": "$3,984.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Travis Hogan", + "gender": "male", + "company": "Accidency", + "email": "travishogan@accidency.com", + "phone": "+1 (965) 437-2550", + "address": { + "street": 890, + "city": "Needmore", + "state": "New York", + "zip": 8979 + }, + "about": "Incididunt id ad aliqua ut minim officia amet et. Culpa ea deserunt ipsum aliquip ipsum id adipisicing non sint. Et duis aliquip est incididunt et et culpa ea ex laboris non. Duis aliquip voluptate deserunt consequat cupidatat voluptate laborum excepteur do proident enim velit occaecat. Sit esse adipisicing elit velit nostrud occaecat amet sit duis tempor nostrud.\r\n", + "registered": "1991-11-10T03:46:17+06:00", + "friends": [ + { + "id": 0, + "name": "Martin Townsend" + }, + { + "id": 1, + "name": "Abby Montgomery" + }, + { + "id": 2, + "name": "Snow Ayers" + } + ] + }, + { + "id": 173, + "guid": "ec91d751-d788-4be7-976f-4872e8ebf0a9", + "isActive": true, + "balance": "$1,066.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Jimmie Woods", + "gender": "female", + "company": "Slofast", + "email": "jimmiewoods@slofast.com", + "phone": "+1 (872) 423-2555", + "address": { + "street": 983, + "city": "Curtice", + "state": "Alaska", + "zip": 4841 + }, + "about": "Anim laboris dolore tempor id irure sunt proident anim excepteur. Aliquip eiusmod irure do laborum ex. Quis occaecat aliquip in adipisicing aute dolor eu proident est sint incididunt. Magna proident aliquip deserunt dolore qui exercitation aliquip ullamco et aliquip eiusmod sit. Sint exercitation nisi enim et quis sint ex et aliqua labore in exercitation. Lorem fugiat duis ipsum reprehenderit nostrud ea sit esse aliqua enim dolor velit sit.\r\n", + "registered": "2013-01-20T04:27:36+06:00", + "friends": [ + { + "id": 0, + "name": "Cobb Petty" + }, + { + "id": 1, + "name": "Stevenson Avery" + }, + { + "id": 2, + "name": "Robin Mcmillan" + } + ] + }, + { + "id": 174, + "guid": "d7c15d37-0b78-4569-a079-86546414a488", + "isActive": false, + "balance": "$2,496.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Lacey Moran", + "gender": "female", + "company": "Intradisk", + "email": "laceymoran@intradisk.com", + "phone": "+1 (994) 509-2235", + "address": { + "street": 723, + "city": "Campo", + "state": "Hawaii", + "zip": 6939 + }, + "about": "Do reprehenderit eu et dolor et consectetur adipisicing ipsum nulla excepteur. Aliqua occaecat consectetur amet Lorem dolor officia nisi nisi. Minim consectetur adipisicing ut in minim dolor id consequat ullamco ipsum non consequat. Et veniam id sunt nostrud consectetur officia aliqua minim.\r\n", + "registered": "2013-12-23T10:36:43+06:00", + "friends": [ + { + "id": 0, + "name": "Roberts Zamora" + }, + { + "id": 1, + "name": "Hunt Riddle" + }, + { + "id": 2, + "name": "Jeannine Puckett" + } + ] + }, + { + "id": 175, + "guid": "221b1357-736d-4442-a0a6-c7986f202b31", + "isActive": false, + "balance": "$1,746.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Leonard Vazquez", + "gender": "male", + "company": "Centree", + "email": "leonardvazquez@centree.com", + "phone": "+1 (943) 452-3837", + "address": { + "street": 988, + "city": "Coultervillle", + "state": "Georgia", + "zip": 8241 + }, + "about": "Et occaecat tempor esse esse nulla laboris dolor magna culpa deserunt voluptate adipisicing nisi. In aliquip occaecat adipisicing sint ut sunt. Culpa adipisicing veniam labore incididunt non aliqua nisi consectetur et veniam adipisicing esse. Do ex mollit laboris proident magna labore sunt Lorem nostrud culpa adipisicing sit ullamco sint. Reprehenderit sunt ut aliqua officia ut pariatur veniam.\r\n", + "registered": "1991-12-11T14:10:05+06:00", + "friends": [ + { + "id": 0, + "name": "Spence Graves" + }, + { + "id": 1, + "name": "Henrietta Padilla" + }, + { + "id": 2, + "name": "Mullen French" + } + ] + }, + { + "id": 176, + "guid": "bbc336de-2493-4f1d-8ffa-21cbaecd7b27", + "isActive": true, + "balance": "$2,770.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Pearson Villarreal", + "gender": "male", + "company": "Bleendot", + "email": "pearsonvillarreal@bleendot.com", + "phone": "+1 (871) 564-2674", + "address": { + "street": 192, + "city": "Stockdale", + "state": "Wisconsin", + "zip": 4395 + }, + "about": "Officia irure dolore proident nostrud ut velit. Mollit qui enim quis anim esse. Anim sit duis consequat pariatur nisi occaecat ipsum.\r\n", + "registered": "2002-02-06T14:18:52+06:00", + "friends": [ + { + "id": 0, + "name": "Penelope Wright" + }, + { + "id": 1, + "name": "Sophie Dalton" + }, + { + "id": 2, + "name": "Liza Conner" + } + ] + }, + { + "id": 177, + "guid": "3ef0d025-4e01-4c46-95c7-68e3e83fee0d", + "isActive": true, + "balance": "$1,155.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Zelma Pugh", + "gender": "female", + "company": "Mixers", + "email": "zelmapugh@mixers.com", + "phone": "+1 (968) 517-2277", + "address": { + "street": 996, + "city": "Gorst", + "state": "Arizona", + "zip": 1225 + }, + "about": "Labore do id esse elit laboris nostrud laboris. Irure ullamco reprehenderit adipisicing consectetur nisi aliqua eu mollit. Amet sit in id labore duis labore qui reprehenderit ex.\r\n", + "registered": "2013-02-05T00:04:39+06:00", + "friends": [ + { + "id": 0, + "name": "Summers Mason" + }, + { + "id": 1, + "name": "Perry Powell" + }, + { + "id": 2, + "name": "Matilda Branch" + } + ] + }, + { + "id": 178, + "guid": "977b1728-e402-46f8-9c17-158c495beea2", + "isActive": false, + "balance": "$2,043.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Buckner Barron", + "gender": "male", + "company": "Injoy", + "email": "bucknerbarron@injoy.com", + "phone": "+1 (863) 581-3015", + "address": { + "street": 700, + "city": "Bayview", + "state": "Nevada", + "zip": 8513 + }, + "about": "Reprehenderit sint cupidatat aliquip excepteur eu. Culpa cupidatat id occaecat laborum magna culpa ex do est. Cupidatat et et non voluptate aute sit do ad enim. Et quis commodo voluptate occaecat voluptate anim quis quis id ipsum do nostrud ut do. Aute do minim ad et aliqua fugiat sunt enim quis ipsum sint sit.\r\n", + "registered": "2012-01-30T06:51:49+06:00", + "friends": [ + { + "id": 0, + "name": "Marianne Gallegos" + }, + { + "id": 1, + "name": "Diann Kirk" + }, + { + "id": 2, + "name": "Mcbride Rivas" + } + ] + }, + { + "id": 179, + "guid": "f20f3ea4-9496-45be-ba29-1314fd2eb5d3", + "isActive": false, + "balance": "$1,616.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Allison Barrett", + "gender": "female", + "company": "Retrotex", + "email": "allisonbarrett@retrotex.com", + "phone": "+1 (961) 447-3111", + "address": { + "street": 380, + "city": "Bluffview", + "state": "Maryland", + "zip": 1215 + }, + "about": "Aliquip qui sunt non qui cillum officia aliquip magna id aliquip. Proident ullamco consequat eiusmod anim nisi eu Lorem ipsum minim minim sint est eiusmod est. Ut aliquip reprehenderit adipisicing nulla Lorem elit cupidatat labore adipisicing non et tempor incididunt. Consequat non cillum amet tempor sit nisi elit nostrud ea do aliqua Lorem consequat occaecat. Incididunt adipisicing Lorem nulla enim eu.\r\n", + "registered": "1996-07-30T07:46:07+05:00", + "friends": [ + { + "id": 0, + "name": "Janet Green" + }, + { + "id": 1, + "name": "Padilla Jordan" + }, + { + "id": 2, + "name": "Sabrina Huff" + } + ] + }, + { + "id": 180, + "guid": "6b1e25f6-4c04-47ca-8b2c-a95af3615147", + "isActive": false, + "balance": "$3,995.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Lorrie Barber", + "gender": "female", + "company": "Oatfarm", + "email": "lorriebarber@oatfarm.com", + "phone": "+1 (846) 562-3502", + "address": { + "street": 539, + "city": "Fruitdale", + "state": "Utah", + "zip": 455 + }, + "about": "Voluptate commodo ad aliqua do esse in. Do est amet veniam amet culpa pariatur incididunt quis fugiat. Laborum non aliqua sint officia eu duis sunt quis aute. Nisi Lorem consequat deserunt adipisicing sit tempor aliqua sunt sint adipisicing est amet adipisicing anim. Do nulla officia eiusmod ullamco.\r\n", + "registered": "1997-01-26T04:32:49+06:00", + "friends": [ + { + "id": 0, + "name": "Marcie Ware" + }, + { + "id": 1, + "name": "Amie Grant" + }, + { + "id": 2, + "name": "Buchanan Hood" + } + ] + }, + { + "id": 181, + "guid": "22637ac3-4eaa-40e0-8e56-0c82052e98ac", + "isActive": true, + "balance": "$3,884.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Hester Bolton", + "gender": "female", + "company": "Aquamate", + "email": "hesterbolton@aquamate.com", + "phone": "+1 (915) 574-2300", + "address": { + "street": 589, + "city": "Edinburg", + "state": "New Jersey", + "zip": 5206 + }, + "about": "Tempor ex ut est officia. Enim ea et do tempor commodo incididunt magna adipisicing reprehenderit dolor. Incididunt amet ullamco quis elit aute officia nisi. Id non eiusmod tempor Lorem enim consequat excepteur sit.\r\n", + "registered": "1993-06-16T04:22:55+05:00", + "friends": [ + { + "id": 0, + "name": "Bauer Bryant" + }, + { + "id": 1, + "name": "Brandie Blake" + }, + { + "id": 2, + "name": "Alvarez Willis" + } + ] + }, + { + "id": 182, + "guid": "232d12c1-de58-4c25-81d0-c5ee39ffafbd", + "isActive": true, + "balance": "$1,456.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Carroll Mcdonald", + "gender": "male", + "company": "Cofine", + "email": "carrollmcdonald@cofine.com", + "phone": "+1 (880) 575-2821", + "address": { + "street": 834, + "city": "Topanga", + "state": "Oklahoma", + "zip": 5869 + }, + "about": "Est tempor cupidatat ut amet velit ipsum consectetur voluptate. Culpa proident duis sunt tempor dolore ipsum in laboris dolor consequat proident pariatur occaecat aliqua. Ad et est consectetur mollit elit commodo ex consequat mollit. Lorem consequat exercitation qui quis culpa ex velit anim eiusmod ullamco. Ea aute deserunt veniam id occaecat anim ut aute. Ea est qui laborum qui deserunt nulla dolor duis tempor. Ullamco id ullamco eu sint sint commodo sunt est aliqua laborum.\r\n", + "registered": "2009-01-26T04:58:24+06:00", + "friends": [ + { + "id": 0, + "name": "Tameka Elliott" + }, + { + "id": 1, + "name": "Durham Mcneil" + }, + { + "id": 2, + "name": "Baker Delgado" + } + ] + }, + { + "id": 183, + "guid": "74241e91-71b0-4449-94a1-c9bd4e597b0f", + "isActive": false, + "balance": "$1,496.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "James Baxter", + "gender": "male", + "company": "Splinx", + "email": "jamesbaxter@splinx.com", + "phone": "+1 (957) 423-2917", + "address": { + "street": 558, + "city": "Byrnedale", + "state": "Michigan", + "zip": 8685 + }, + "about": "Duis dolore nisi mollit elit pariatur occaecat elit sint consequat laboris incididunt. Aliqua nostrud deserunt in sit et. Ullamco esse consectetur nostrud qui nostrud adipisicing elit. Ad nostrud cillum tempor mollit. Velit amet do deserunt fugiat. Dolore culpa laborum cillum mollit nulla excepteur Lorem eiusmod Lorem eu officia. Voluptate sint ea et ipsum ipsum.\r\n", + "registered": "2001-05-17T12:04:31+05:00", + "friends": [ + { + "id": 0, + "name": "Anita Lindsay" + }, + { + "id": 1, + "name": "Chelsea Singleton" + }, + { + "id": 2, + "name": "Hancock Wilson" + } + ] + }, + { + "id": 184, + "guid": "095eaf9a-7a9f-4917-b71c-257cf5aa6c81", + "isActive": true, + "balance": "$2,199.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Herring Rodriguez", + "gender": "male", + "company": "Paprikut", + "email": "herringrodriguez@paprikut.com", + "phone": "+1 (897) 435-3440", + "address": { + "street": 934, + "city": "Wilmington", + "state": "Massachusetts", + "zip": 6920 + }, + "about": "Consequat consectetur voluptate occaecat commodo quis pariatur culpa non veniam ipsum laborum enim et. Dolor id sit veniam cillum enim aute irure non laborum commodo. Veniam officia nostrud pariatur dolor dolor commodo commodo nulla magna commodo. Elit aliquip elit in proident fugiat deserunt commodo tempor laborum veniam. Ullamco eu deserunt velit aute.\r\n", + "registered": "2003-06-29T16:54:31+05:00", + "friends": [ + { + "id": 0, + "name": "Adrian Booth" + }, + { + "id": 1, + "name": "Lorene Williamson" + }, + { + "id": 2, + "name": "Frank Reeves" + } + ] + }, + { + "id": 185, + "guid": "b017bc09-33e2-4379-a464-317282935147", + "isActive": true, + "balance": "$2,933.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Tamika Franks", + "gender": "female", + "company": "Qaboos", + "email": "tamikafranks@qaboos.com", + "phone": "+1 (889) 441-3621", + "address": { + "street": 133, + "city": "Newry", + "state": "Virginia", + "zip": 2473 + }, + "about": "Anim est nulla deserunt in sit id non et sunt nostrud. Cupidatat fugiat incididunt occaecat dolore laboris qui amet ipsum. Aliqua quis qui irure aute esse. Culpa eiusmod magna veniam incididunt anim ea non deserunt. Eu ullamco veniam deserunt est. Elit id deserunt elit qui aliquip dolore occaecat incididunt reprehenderit duis amet. Amet consequat minim eiusmod proident.\r\n", + "registered": "1994-01-29T18:51:22+06:00", + "friends": [ + { + "id": 0, + "name": "Guzman Parsons" + }, + { + "id": 1, + "name": "Agnes Mercer" + }, + { + "id": 2, + "name": "Angie Bishop" + } + ] + }, + { + "id": 186, + "guid": "9ee3be7a-98b1-474d-8c57-ed32d2c11446", + "isActive": false, + "balance": "$3,573.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Davenport Moreno", + "gender": "male", + "company": "Caxt", + "email": "davenportmoreno@caxt.com", + "phone": "+1 (801) 416-3344", + "address": { + "street": 413, + "city": "Alden", + "state": "South Dakota", + "zip": 6715 + }, + "about": "Officia aute enim Lorem exercitation. In do sit labore et officia laborum. Ipsum sunt excepteur ut pariatur ut irure est voluptate aute sit veniam enim ea fugiat. Amet ipsum do amet nostrud adipisicing sint occaecat excepteur officia aliquip ad in. Cillum duis esse esse sint.\r\n", + "registered": "1996-11-20T10:51:20+06:00", + "friends": [ + { + "id": 0, + "name": "Gutierrez Mcleod" + }, + { + "id": 1, + "name": "Alyce Avila" + }, + { + "id": 2, + "name": "Liliana Hill" + } + ] + }, + { + "id": 187, + "guid": "0cca03e6-f6a3-431f-92cf-2ddb60cd8e5e", + "isActive": false, + "balance": "$3,075.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Dyer Rivera", + "gender": "male", + "company": "Comvey", + "email": "dyerrivera@comvey.com", + "phone": "+1 (889) 527-2885", + "address": { + "street": 646, + "city": "Derwood", + "state": "Missouri", + "zip": 2387 + }, + "about": "Excepteur ad consequat labore pariatur culpa labore amet fugiat laborum cillum. Dolore laborum eiusmod culpa aliqua mollit nulla sint dolore dolor velit commodo. Lorem veniam consequat non nulla commodo cupidatat. Non sint est anim exercitation laborum non minim nulla do. Ut dolor commodo do minim tempor commodo occaecat exercitation sunt mollit tempor do. Duis non excepteur exercitation nulla. Lorem adipisicing dolor sunt non magna sint pariatur anim magna.\r\n", + "registered": "2000-08-10T09:55:05+05:00", + "friends": [ + { + "id": 0, + "name": "Christi Trevino" + }, + { + "id": 1, + "name": "Vega Bailey" + }, + { + "id": 2, + "name": "Lizzie Rios" + } + ] + }, + { + "id": 188, + "guid": "8cf5734d-5f59-4402-a6a0-8c4d78501066", + "isActive": true, + "balance": "$2,076.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Chaney Carr", + "gender": "male", + "company": "Collaire", + "email": "chaneycarr@collaire.com", + "phone": "+1 (908) 543-2264", + "address": { + "street": 578, + "city": "Starks", + "state": "Nebraska", + "zip": 9933 + }, + "about": "Esse occaecat voluptate ut incididunt nostrud Lorem pariatur ea officia Lorem ut minim anim. Pariatur laborum aliquip cupidatat officia sint magna consequat. Ut officia pariatur voluptate aute anim magna. Aliqua excepteur dolor anim dolor id aliquip eu voluptate ea Lorem velit. Ea est qui est qui minim deserunt labore. Ea enim mollit culpa cillum dolor labore. Adipisicing magna incididunt consectetur aliquip.\r\n", + "registered": "2005-05-24T09:17:19+05:00", + "friends": [ + { + "id": 0, + "name": "Arnold Austin" + }, + { + "id": 1, + "name": "Giles Camacho" + }, + { + "id": 2, + "name": "Navarro Chapman" + } + ] + }, + { + "id": 189, + "guid": "9e2e669c-ba91-4ec7-ab0d-44a065c82332", + "isActive": true, + "balance": "$2,023.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Hinton Glover", + "gender": "male", + "company": "Netility", + "email": "hintonglover@netility.com", + "phone": "+1 (944) 419-3677", + "address": { + "street": 543, + "city": "Wiscon", + "state": "Vermont", + "zip": 1448 + }, + "about": "Ipsum amet consequat esse in Lorem adipisicing culpa fugiat. Ex laboris aute cupidatat non officia sunt. Esse duis incididunt duis reprehenderit quis ut mollit cillum ipsum cupidatat. Mollit eu officia non eu est laborum incididunt eu pariatur nostrud. Commodo deserunt elit laboris laborum ea consectetur fugiat ex. Sunt pariatur magna reprehenderit nulla qui amet. Qui consectetur cillum eu aliquip elit occaecat enim culpa mollit sint laboris.\r\n", + "registered": "2006-08-12T03:59:17+05:00", + "friends": [ + { + "id": 0, + "name": "Buck Richmond" + }, + { + "id": 1, + "name": "Mooney Mcmahon" + }, + { + "id": 2, + "name": "Mack Neal" + } + ] + }, + { + "id": 190, + "guid": "a10ede97-1c61-4588-8dc3-21db364f666b", + "isActive": false, + "balance": "$2,587.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Aimee Turner", + "gender": "female", + "company": "Quizka", + "email": "aimeeturner@quizka.com", + "phone": "+1 (967) 531-3979", + "address": { + "street": 371, + "city": "Gardiner", + "state": "South Carolina", + "zip": 6875 + }, + "about": "Nostrud do do qui velit officia labore pariatur do officia fugiat consequat amet Lorem. Anim Lorem ad proident commodo mollit consectetur nostrud. Ut magna occaecat commodo anim dolore elit culpa. Culpa est dolor officia labore cillum Lorem nostrud incididunt ad. Adipisicing ipsum sunt labore veniam in reprehenderit. Labore elit deserunt officia adipisicing laboris non laboris consequat incididunt consectetur adipisicing nostrud velit.\r\n", + "registered": "1995-02-10T22:59:48+06:00", + "friends": [ + { + "id": 0, + "name": "Florence Dyer" + }, + { + "id": 1, + "name": "Nichole Cote" + }, + { + "id": 2, + "name": "Angeline Gaines" + } + ] + }, + { + "id": 191, + "guid": "4877689e-f08e-4413-bb96-d73041787b14", + "isActive": false, + "balance": "$3,711.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Lenore Travis", + "gender": "female", + "company": "Zosis", + "email": "lenoretravis@zosis.com", + "phone": "+1 (934) 452-2240", + "address": { + "street": 223, + "city": "Dixie", + "state": "North Carolina", + "zip": 3608 + }, + "about": "Eu commodo voluptate culpa dolor tempor deserunt adipisicing proident mollit fugiat ullamco. Cupidatat ex laboris nisi ad tempor ex veniam. Occaecat non nisi aliquip aute proident esse duis consectetur ex sint excepteur. Anim officia ea sint esse ex laboris. Nulla proident magna ex et do ad id ipsum commodo in.\r\n", + "registered": "1994-01-09T14:31:44+06:00", + "friends": [ + { + "id": 0, + "name": "Mcneil Kent" + }, + { + "id": 1, + "name": "Erika Ortega" + }, + { + "id": 2, + "name": "Nikki Dillard" + } + ] + }, + { + "id": 192, + "guid": "a26fe7f8-82ed-48b8-8868-bd26ebff6212", + "isActive": false, + "balance": "$3,978.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Jacobs Buckley", + "gender": "male", + "company": "Grupoli", + "email": "jacobsbuckley@grupoli.com", + "phone": "+1 (867) 595-3840", + "address": { + "street": 666, + "city": "Rote", + "state": "Iowa", + "zip": 939 + }, + "about": "Sint dolore adipisicing aliqua eu. Velit excepteur ullamco officia fugiat consectetur. Magna veniam adipisicing velit consequat magna quis qui quis culpa esse. Consectetur nostrud fugiat aute veniam ea laboris tempor quis et incididunt voluptate ipsum sint irure. Aliquip cillum veniam enim consectetur dolore anim eiusmod occaecat. Pariatur sint quis ipsum eiusmod tempor incididunt consectetur anim deserunt ut ipsum. In tempor consequat cupidatat magna nostrud ex cupidatat voluptate deserunt laboris.\r\n", + "registered": "1997-05-20T12:46:48+05:00", + "friends": [ + { + "id": 0, + "name": "Lora Lawrence" + }, + { + "id": 1, + "name": "Welch Gonzalez" + }, + { + "id": 2, + "name": "Trina Rosa" + } + ] + }, + { + "id": 193, + "guid": "90b86e32-0224-44e7-b6eb-756b1f5b6795", + "isActive": false, + "balance": "$2,386.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Natasha Stafford", + "gender": "female", + "company": "Magneato", + "email": "natashastafford@magneato.com", + "phone": "+1 (885) 430-3912", + "address": { + "street": 694, + "city": "Chapin", + "state": "Rhode Island", + "zip": 6365 + }, + "about": "Lorem aliqua reprehenderit aliquip quis. Quis cupidatat deserunt adipisicing excepteur anim qui non pariatur culpa culpa. Proident in commodo voluptate in do occaecat aute qui est non incididunt.\r\n", + "registered": "1989-07-05T11:12:35+05:00", + "friends": [ + { + "id": 0, + "name": "Maude Hays" + }, + { + "id": 1, + "name": "Sharp Erickson" + }, + { + "id": 2, + "name": "Dennis Cleveland" + } + ] + }, + { + "id": 194, + "guid": "aa82dcba-7cf0-4ff1-a732-865203b9aabe", + "isActive": false, + "balance": "$2,307.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Camille Sexton", + "gender": "female", + "company": "Motovate", + "email": "camillesexton@motovate.com", + "phone": "+1 (896) 431-3993", + "address": { + "street": 797, + "city": "Bentley", + "state": "Maine", + "zip": 915 + }, + "about": "Sit aliquip ad consectetur ad pariatur commodo sit culpa. Proident eiusmod sint consectetur eiusmod ea ad aliquip anim magna aliqua cupidatat. Nulla amet eiusmod dolor elit Lorem occaecat dolore irure. Minim occaecat sint Lorem laborum.\r\n", + "registered": "2006-06-04T00:32:00+05:00", + "friends": [ + { + "id": 0, + "name": "Shannon Edwards" + }, + { + "id": 1, + "name": "Underwood Woodward" + }, + { + "id": 2, + "name": "Newman Pope" + } + ] + }, + { + "id": 195, + "guid": "e77ccbaf-dae2-40d9-9af4-cafcb913c814", + "isActive": true, + "balance": "$3,088.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Claudia Serrano", + "gender": "female", + "company": "Zilphur", + "email": "claudiaserrano@zilphur.com", + "phone": "+1 (932) 577-3765", + "address": { + "street": 539, + "city": "Sedley", + "state": "West Virginia", + "zip": 8992 + }, + "about": "Qui eiusmod sunt cupidatat proident cupidatat aute sit consequat laborum commodo aliquip nisi sint consectetur. Pariatur dolore est non elit velit ipsum ex excepteur nulla enim. Pariatur aliqua amet veniam cillum anim id minim elit. Cupidatat ea irure reprehenderit qui anim. Voluptate est aliquip qui eu ad aute laboris id quis aute. Nisi Lorem irure laboris voluptate quis.\r\n", + "registered": "1994-07-09T13:29:11+05:00", + "friends": [ + { + "id": 0, + "name": "Williamson Castro" + }, + { + "id": 1, + "name": "Ruthie Moore" + }, + { + "id": 2, + "name": "Browning Holman" + } + ] + }, + { + "id": 196, + "guid": "9f23787e-584f-4ef4-abbb-f94d5902cb8c", + "isActive": false, + "balance": "$2,167.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Koch Ramos", + "gender": "male", + "company": "Silodyne", + "email": "kochramos@silodyne.com", + "phone": "+1 (945) 574-3329", + "address": { + "street": 129, + "city": "Deltaville", + "state": "Wisconsin", + "zip": 2080 + }, + "about": "Culpa ut sunt ex et minim quis. Ipsum est consequat pariatur proident. Ex mollit id ullamco in adipisicing culpa id nulla elit qui. Non elit ipsum id ullamco fugiat officia cillum incididunt.\r\n", + "registered": "1994-04-05T11:02:13+05:00", + "friends": [ + { + "id": 0, + "name": "Mcpherson Frank" + }, + { + "id": 1, + "name": "Ashlee Madden" + }, + { + "id": 2, + "name": "Farmer Clay" + } + ] + }, + { + "id": 197, + "guid": "12621d60-9576-4aad-a46d-0f78456f3947", + "isActive": false, + "balance": "$3,937.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Mavis Steele", + "gender": "female", + "company": "Vixo", + "email": "mavissteele@vixo.com", + "phone": "+1 (977) 472-3028", + "address": { + "street": 263, + "city": "Leola", + "state": "New Jersey", + "zip": 7051 + }, + "about": "Eiusmod sunt cupidatat nostrud reprehenderit ullamco aliqua elit laborum dolor tempor consectetur et officia. Consequat sit et adipisicing cupidatat. Ex nulla laboris consequat consequat voluptate et in cupidatat tempor cupidatat dolore qui. Ea dolore Lorem veniam qui officia est nulla culpa veniam cillum mollit ut elit. Incididunt sunt cillum veniam ut amet Lorem. Qui fugiat esse consequat deserunt sint commodo non veniam ex quis nisi tempor ullamco. Duis aliquip adipisicing sint consectetur consectetur id irure.\r\n", + "registered": "1991-12-22T08:18:32+06:00", + "friends": [ + { + "id": 0, + "name": "Morgan Oneil" + }, + { + "id": 1, + "name": "Lana Cherry" + }, + { + "id": 2, + "name": "Eunice Haley" + } + ] + }, + { + "id": 198, + "guid": "18d129e9-22bb-43e9-812a-0a3e8248a9da", + "isActive": false, + "balance": "$2,624.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Maryellen Brennan", + "gender": "female", + "company": "Enjola", + "email": "maryellenbrennan@enjola.com", + "phone": "+1 (813) 592-3608", + "address": { + "street": 459, + "city": "Lynn", + "state": "Michigan", + "zip": 8602 + }, + "about": "Aliqua laborum cupidatat nulla cillum mollit ex quis non enim magna incididunt ut. Ullamco nisi dolore incididunt nulla est anim adipisicing pariatur irure proident tempor aliqua ex. Officia commodo ipsum laborum ad laborum consequat nostrud. Cillum aute ex amet ut incididunt officia ex ea pariatur incididunt officia aliquip laboris. Ipsum aliquip reprehenderit consequat eiusmod amet et laborum qui deserunt adipisicing ad.\r\n", + "registered": "2000-01-02T14:25:50+06:00", + "friends": [ + { + "id": 0, + "name": "Mamie Barry" + }, + { + "id": 1, + "name": "Kerr Dillon" + }, + { + "id": 2, + "name": "Vaughan Cash" + } + ] + }, + { + "id": 199, + "guid": "1367089b-a478-4fde-a355-fe82b92f4f66", + "isActive": true, + "balance": "$1,180.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Melissa Reeves", + "gender": "female", + "company": "Magnemo", + "email": "melissareeves@magnemo.com", + "phone": "+1 (879) 599-2180", + "address": { + "street": 150, + "city": "Hollins", + "state": "Missouri", + "zip": 5305 + }, + "about": "Sunt culpa sint dolor dolor eiusmod incididunt incididunt cupidatat do nisi reprehenderit laboris ad. Cupidatat irure consectetur deserunt proident pariatur nulla elit culpa ex qui amet. Velit aute sit veniam duis laborum commodo irure. Duis elit enim Lorem est cupidatat ipsum magna.\r\n", + "registered": "2008-06-17T00:48:02+05:00", + "friends": [ + { + "id": 0, + "name": "Barbara Fuentes" + }, + { + "id": 1, + "name": "Marcie Cooley" + }, + { + "id": 2, + "name": "Janet Thompson" + } + ] + }, + { + "id": 200, + "guid": "efed383b-f982-4fea-b99c-35f15acb16c4", + "isActive": false, + "balance": "$1,232.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Langley Parsons", + "gender": "male", + "company": "Pyrami", + "email": "langleyparsons@pyrami.com", + "phone": "+1 (918) 496-3263", + "address": { + "street": 682, + "city": "Suitland", + "state": "Alabama", + "zip": 3953 + }, + "about": "Exercitation in officia qui consectetur dolor quis labore ut elit. Cupidatat ipsum eu laboris excepteur aute. Eiusmod nostrud consequat non ullamco ex cillum anim excepteur veniam. Aliqua reprehenderit cupidatat non do reprehenderit ex irure sint do commodo.\r\n", + "registered": "1999-09-15T10:47:11+05:00", + "friends": [ + { + "id": 0, + "name": "Robinson Huber" + }, + { + "id": 1, + "name": "Edna Key" + }, + { + "id": 2, + "name": "Watkins Bryan" + } + ] + }, + { + "id": 201, + "guid": "d0b3f5d2-8b4f-4687-8459-4006a6e6b7da", + "isActive": true, + "balance": "$1,791.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Christy Cabrera", + "gender": "female", + "company": "Cytrak", + "email": "christycabrera@cytrak.com", + "phone": "+1 (906) 559-2087", + "address": { + "street": 882, + "city": "Sabillasville", + "state": "Texas", + "zip": 2187 + }, + "about": "Irure nostrud laboris commodo id ullamco exercitation cupidatat eu ad dolore. Deserunt nulla fugiat eu mollit dolore tempor ad ea consequat commodo anim Lorem pariatur occaecat. Nulla nulla laborum eiusmod adipisicing nulla Lorem excepteur. Ex tempor esse duis irure cillum minim do eiusmod est qui quis officia. Id do incididunt ut adipisicing do non labore.\r\n", + "registered": "2003-06-26T09:36:32+05:00", + "friends": [ + { + "id": 0, + "name": "Brady Harvey" + }, + { + "id": 1, + "name": "Chambers Harrell" + }, + { + "id": 2, + "name": "Lorena Hancock" + } + ] + }, + { + "id": 202, + "guid": "f3bc3f8b-b5f7-4de6-a6d2-f6f7ac0b44f6", + "isActive": false, + "balance": "$3,953.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Cruz Durham", + "gender": "male", + "company": "Comtest", + "email": "cruzdurham@comtest.com", + "phone": "+1 (884) 460-2269", + "address": { + "street": 673, + "city": "Keller", + "state": "Oklahoma", + "zip": 7737 + }, + "about": "Adipisicing culpa enim est aute incididunt aute nostrud non eiusmod aliquip reprehenderit exercitation. Non nostrud incididunt tempor fugiat elit elit aliqua ea eiusmod. Culpa tempor culpa aliqua deserunt exercitation non anim nostrud nostrud et ullamco esse nostrud. Sunt Lorem incididunt in mollit minim est cupidatat laboris et anim.\r\n", + "registered": "2005-03-11T23:12:43+06:00", + "friends": [ + { + "id": 0, + "name": "Williamson Dennis" + }, + { + "id": 1, + "name": "Matilda Griffin" + }, + { + "id": 2, + "name": "Emily Sparks" + } + ] + }, + { + "id": 203, + "guid": "42bda688-9a39-431a-bdfe-55ca5bdb299a", + "isActive": true, + "balance": "$1,494.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Hill Buckley", + "gender": "male", + "company": "Magmina", + "email": "hillbuckley@magmina.com", + "phone": "+1 (905) 523-3301", + "address": { + "street": 834, + "city": "Summerset", + "state": "Minnesota", + "zip": 8787 + }, + "about": "Excepteur mollit ex non do pariatur enim nostrud laborum cillum proident reprehenderit cillum. Anim anim nostrud mollit aute magna sint laborum pariatur nostrud sint anim veniam cupidatat occaecat. Enim occaecat culpa anim mollit Lorem incididunt duis ea sint dolore. Laborum mollit ex aliqua voluptate.\r\n", + "registered": "2002-03-02T08:48:07+06:00", + "friends": [ + { + "id": 0, + "name": "Mendoza Walton" + }, + { + "id": 1, + "name": "Terra Bush" + }, + { + "id": 2, + "name": "Reynolds Holden" + } + ] + }, + { + "id": 204, + "guid": "4007259f-33f2-47ad-a99d-f80727e067c6", + "isActive": true, + "balance": "$1,067.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Aisha Freeman", + "gender": "female", + "company": "Ecratic", + "email": "aishafreeman@ecratic.com", + "phone": "+1 (964) 408-3213", + "address": { + "street": 515, + "city": "Chical", + "state": "North Dakota", + "zip": 234 + }, + "about": "Veniam adipisicing proident Lorem quis voluptate laboris in enim qui ipsum adipisicing non incididunt consequat. Officia sunt dolore eu ipsum adipisicing mollit eiusmod nulla laborum magna duis. Eu nostrud consequat in laboris veniam dolor velit enim laborum magna.\r\n", + "registered": "2009-04-03T03:02:20+05:00", + "friends": [ + { + "id": 0, + "name": "Shawna Norman" + }, + { + "id": 1, + "name": "Britney Baldwin" + }, + { + "id": 2, + "name": "Kim Puckett" + } + ] + }, + { + "id": 205, + "guid": "94265a8f-b32e-44c5-bcd7-b81f6198adad", + "isActive": true, + "balance": "$2,533.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Simone Calhoun", + "gender": "female", + "company": "Prowaste", + "email": "simonecalhoun@prowaste.com", + "phone": "+1 (944) 472-2197", + "address": { + "street": 604, + "city": "Unionville", + "state": "Mississippi", + "zip": 9400 + }, + "about": "Incididunt minim esse cupidatat sint deserunt mollit. Officia dolore occaecat eiusmod mollit mollit magna nulla id do ullamco incididunt dolor est eu. Exercitation laboris aliquip ullamco ut ex ad velit velit irure nostrud sint tempor. Laboris consectetur ut ad velit voluptate. Id ut officia laboris nulla laboris quis.\r\n", + "registered": "1996-05-03T01:22:42+05:00", + "friends": [ + { + "id": 0, + "name": "Riddle Munoz" + }, + { + "id": 1, + "name": "Romero Stephens" + }, + { + "id": 2, + "name": "Lourdes Reese" + } + ] + }, + { + "id": 206, + "guid": "4cd1b5df-2eac-4058-9128-d761d6c57fa2", + "isActive": false, + "balance": "$1,924.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Bettie Chan", + "gender": "female", + "company": "Zillar", + "email": "bettiechan@zillar.com", + "phone": "+1 (967) 533-3936", + "address": { + "street": 458, + "city": "Eureka", + "state": "North Carolina", + "zip": 1169 + }, + "about": "Id ad amet in exercitation aliquip tempor labore voluptate laboris mollit id. Tempor nisi eiusmod aliqua sit enim minim deserunt sunt et tempor. Non ipsum nisi deserunt elit eu ad ut ex ex mollit cupidatat est adipisicing. Sunt officia qui aute nostrud officia cupidatat. Ex velit enim elit sunt labore nulla minim ut commodo culpa sit. Eu duis pariatur consequat anim nostrud duis eiusmod elit irure pariatur.\r\n", + "registered": "1999-12-08T21:25:28+06:00", + "friends": [ + { + "id": 0, + "name": "English Sosa" + }, + { + "id": 1, + "name": "Bettye Montgomery" + }, + { + "id": 2, + "name": "Virgie Nielsen" + } + ] + }, + { + "id": 207, + "guid": "bdea0421-a5a0-4400-bda2-609196b0c802", + "isActive": false, + "balance": "$3,788.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Ratliff Jacobs", + "gender": "male", + "company": "Tropolis", + "email": "ratliffjacobs@tropolis.com", + "phone": "+1 (900) 405-2758", + "address": { + "street": 183, + "city": "Lawrence", + "state": "Kentucky", + "zip": 321 + }, + "about": "Minim adipisicing ad cupidatat elit deserunt ea et cillum pariatur dolor non. Velit ea aute anim anim nisi in esse esse irure ea tempor. Commodo mollit amet consectetur dolor commodo esse est laborum adipisicing nostrud consectetur sit. Tempor labore incididunt anim officia eiusmod. Mollit cillum velit sit id ullamco commodo commodo. Cillum incididunt tempor nostrud reprehenderit veniam nisi nostrud. Ut proident ut voluptate exercitation dolore laboris minim ad Lorem.\r\n", + "registered": "2001-12-26T13:54:11+06:00", + "friends": [ + { + "id": 0, + "name": "Mathis Burris" + }, + { + "id": 1, + "name": "Callahan Colon" + }, + { + "id": 2, + "name": "Cathy Holmes" + } + ] + }, + { + "id": 208, + "guid": "3ef72e5a-ab18-474e-bad7-4cb3c04bdca0", + "isActive": false, + "balance": "$3,056.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Bond Michael", + "gender": "male", + "company": "Zilch", + "email": "bondmichael@zilch.com", + "phone": "+1 (881) 487-3679", + "address": { + "street": 905, + "city": "Bowden", + "state": "Arizona", + "zip": 7575 + }, + "about": "Minim et Lorem voluptate quis magna laboris adipisicing. Est minim labore esse consectetur aliqua commodo fugiat irure aute. Irure occaecat aute adipisicing minim tempor. Consequat do officia officia commodo esse sit adipisicing esse ullamco nostrud adipisicing. Dolor anim magna ipsum aute. Esse eu adipisicing officia aliquip id deserunt sunt fugiat nostrud. Reprehenderit consectetur officia enim do minim aliqua.\r\n", + "registered": "2008-01-05T00:45:39+06:00", + "friends": [ + { + "id": 0, + "name": "Carolyn Hamilton" + }, + { + "id": 1, + "name": "Nora Watson" + }, + { + "id": 2, + "name": "Carlene Johns" + } + ] + }, + { + "id": 209, + "guid": "818960a3-6e79-4ac0-8188-19effba97647", + "isActive": false, + "balance": "$3,503.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Hayden Cochran", + "gender": "male", + "company": "Jimbies", + "email": "haydencochran@jimbies.com", + "phone": "+1 (918) 448-2547", + "address": { + "street": 867, + "city": "Collins", + "state": "Maryland", + "zip": 6156 + }, + "about": "Mollit in proident consequat ea voluptate incididunt cillum. Nostrud velit irure esse velit nulla fugiat. Ut consequat excepteur deserunt sit nisi. Occaecat labore eu esse labore elit consectetur ad. Mollit id sint nisi officia culpa sunt Lorem consequat. Veniam tempor exercitation aute ut reprehenderit sit enim esse aliqua consequat et duis nisi. Tempor duis exercitation aute consectetur ea aute aliqua nulla.\r\n", + "registered": "1998-11-26T17:50:46+06:00", + "friends": [ + { + "id": 0, + "name": "Dixie Hughes" + }, + { + "id": 1, + "name": "Quinn Miles" + }, + { + "id": 2, + "name": "Petra Ayers" + } + ] + }, + { + "id": 210, + "guid": "a97708ba-a932-4633-af23-dcf6b8695ec2", + "isActive": false, + "balance": "$3,694.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Shelia Osborne", + "gender": "female", + "company": "Exoswitch", + "email": "sheliaosborne@exoswitch.com", + "phone": "+1 (999) 414-2735", + "address": { + "street": 525, + "city": "Downsville", + "state": "New Hampshire", + "zip": 8546 + }, + "about": "Nostrud aliquip anim anim elit est cillum dolor non. Tempor exercitation mollit ut eu irure sunt. Irure cillum labore mollit non et tempor velit velit Lorem consectetur dolore aliqua deserunt velit. Dolore nisi adipisicing veniam ea officia tempor reprehenderit tempor aute laboris.\r\n", + "registered": "1994-05-07T04:53:22+05:00", + "friends": [ + { + "id": 0, + "name": "Elisa Schroeder" + }, + { + "id": 1, + "name": "Noble Forbes" + }, + { + "id": 2, + "name": "Thelma Rodriquez" + } + ] + }, + { + "id": 211, + "guid": "930e10fa-d596-4b46-a986-74aca4ec4b6b", + "isActive": true, + "balance": "$2,566.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Phoebe Holder", + "gender": "female", + "company": "Zytrac", + "email": "phoebeholder@zytrac.com", + "phone": "+1 (924) 519-3800", + "address": { + "street": 504, + "city": "Fulford", + "state": "Florida", + "zip": 2157 + }, + "about": "Fugiat nisi do incididunt consequat voluptate irure est duis. Mollit magna officia occaecat dolore sint nulla ex velit cillum laborum. Ea sint reprehenderit consequat dolore qui et reprehenderit anim dolor id.\r\n", + "registered": "2000-03-06T23:12:36+06:00", + "friends": [ + { + "id": 0, + "name": "Moody Ball" + }, + { + "id": 1, + "name": "Bentley Gilbert" + }, + { + "id": 2, + "name": "Stout Parker" + } + ] + }, + { + "id": 212, + "guid": "96f28923-5186-489f-8eef-ca6041679272", + "isActive": false, + "balance": "$1,538.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Bishop Salinas", + "gender": "male", + "company": "Puria", + "email": "bishopsalinas@puria.com", + "phone": "+1 (865) 497-2145", + "address": { + "street": 362, + "city": "Kerby", + "state": "Idaho", + "zip": 4031 + }, + "about": "Mollit minim ipsum incididunt eiusmod qui cupidatat culpa pariatur occaecat. Ut elit commodo est quis exercitation nisi. Ex fugiat veniam tempor laboris anim.\r\n", + "registered": "1995-01-13T19:09:39+06:00", + "friends": [ + { + "id": 0, + "name": "Holder Bauer" + }, + { + "id": 1, + "name": "Brooks Logan" + }, + { + "id": 2, + "name": "Morrow Buchanan" + } + ] + }, + { + "id": 213, + "guid": "e9c625fa-f289-495b-adfd-9655cf1dd524", + "isActive": false, + "balance": "$3,415.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Hanson Rich", + "gender": "male", + "company": "Organica", + "email": "hansonrich@organica.com", + "phone": "+1 (842) 479-3227", + "address": { + "street": 377, + "city": "Bradenville", + "state": "Kansas", + "zip": 6383 + }, + "about": "Veniam exercitation commodo Lorem labore eiusmod sint est sunt cupidatat. Id ut anim adipisicing consequat eu. Velit aliqua Lorem sit occaecat sint cillum deserunt proident et.\r\n", + "registered": "2013-05-10T17:00:19+05:00", + "friends": [ + { + "id": 0, + "name": "Tracey Ryan" + }, + { + "id": 1, + "name": "Jerri Adams" + }, + { + "id": 2, + "name": "Fran Salas" + } + ] + }, + { + "id": 214, + "guid": "8cf7d57b-96b2-404e-9e36-45ec819d6608", + "isActive": true, + "balance": "$3,546.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Catalina Sherman", + "gender": "female", + "company": "Comvene", + "email": "catalinasherman@comvene.com", + "phone": "+1 (846) 514-3115", + "address": { + "street": 751, + "city": "Glenshaw", + "state": "New York", + "zip": 4877 + }, + "about": "Do fugiat ut consequat officia. Ex commodo proident eiusmod labore cillum cupidatat tempor est velit voluptate ea ut ullamco consequat. Consequat reprehenderit elit minim magna duis non nisi. Ad incididunt ullamco exercitation elit dolore commodo pariatur commodo ullamco. Ea nostrud qui excepteur irure duis laboris ipsum mollit ipsum consectetur qui nisi. Anim anim commodo occaecat cupidatat in consequat in deserunt esse duis pariatur fugiat aliqua eu. Ex sunt aute laboris officia enim anim anim dolore cillum eu.\r\n", + "registered": "2001-12-13T16:56:13+06:00", + "friends": [ + { + "id": 0, + "name": "Deanna Knox" + }, + { + "id": 1, + "name": "Traci Bailey" + }, + { + "id": 2, + "name": "Mcdowell Gallegos" + } + ] + }, + { + "id": 215, + "guid": "5918588e-7c56-4095-926c-fbea17aad80c", + "isActive": true, + "balance": "$3,433.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Golden Bond", + "gender": "male", + "company": "Shepard", + "email": "goldenbond@shepard.com", + "phone": "+1 (895) 478-2030", + "address": { + "street": 225, + "city": "Roderfield", + "state": "Montana", + "zip": 9429 + }, + "about": "Elit cupidatat quis mollit id. Cillum do aute commodo aute labore duis et cillum irure. Irure excepteur commodo deserunt reprehenderit aute quis consectetur consequat commodo minim occaecat nostrud.\r\n", + "registered": "2005-07-25T03:01:20+05:00", + "friends": [ + { + "id": 0, + "name": "Rowland Shannon" + }, + { + "id": 1, + "name": "Peters Kidd" + }, + { + "id": 2, + "name": "Naomi Mccullough" + } + ] + }, + { + "id": 216, + "guid": "d46ce717-4a98-4420-8317-4d0108596760", + "isActive": false, + "balance": "$1,870.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Singleton Oneill", + "gender": "male", + "company": "Datagen", + "email": "singletononeill@datagen.com", + "phone": "+1 (873) 431-3343", + "address": { + "street": 100, + "city": "Driftwood", + "state": "Georgia", + "zip": 8855 + }, + "about": "Ut ea mollit magna ullamco non nisi ex velit ipsum aliquip eu dolor. Eu non officia deserunt sit commodo sit labore non aliquip consectetur et. Fugiat dolor eiusmod sunt duis consequat laboris adipisicing minim. Proident aute reprehenderit aliquip culpa aute id laborum nostrud do est labore cillum.\r\n", + "registered": "2003-11-09T07:47:24+06:00", + "friends": [ + { + "id": 0, + "name": "Amber James" + }, + { + "id": 1, + "name": "Sarah Patrick" + }, + { + "id": 2, + "name": "Drake Mendez" + } + ] + }, + { + "id": 217, + "guid": "6835978b-a1f6-465c-a9c3-df5d808d1ab9", + "isActive": false, + "balance": "$3,179.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Lola Monroe", + "gender": "female", + "company": "Deviltoe", + "email": "lolamonroe@deviltoe.com", + "phone": "+1 (917) 538-2527", + "address": { + "street": 412, + "city": "Hayden", + "state": "Colorado", + "zip": 4152 + }, + "about": "Lorem do proident reprehenderit exercitation commodo minim dolore velit ipsum non eiusmod. Et labore adipisicing reprehenderit nostrud laboris proident aute qui consectetur magna elit ea minim tempor. Laborum anim velit veniam nulla laboris consequat occaecat sint eiusmod est in. Ea nostrud cillum aliquip amet sunt excepteur amet nostrud mollit. Aute irure sunt minim magna dolor.\r\n", + "registered": "1999-11-30T02:52:31+06:00", + "friends": [ + { + "id": 0, + "name": "Buck Boone" + }, + { + "id": 1, + "name": "Summers Morse" + }, + { + "id": 2, + "name": "Ware Barber" + } + ] + }, + { + "id": 218, + "guid": "1931b94a-a2c5-4712-b9b0-825b540878f5", + "isActive": true, + "balance": "$3,608.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Bethany Marks", + "gender": "female", + "company": "Talkalot", + "email": "bethanymarks@talkalot.com", + "phone": "+1 (986) 527-2806", + "address": { + "street": 698, + "city": "Diaperville", + "state": "Oregon", + "zip": 8777 + }, + "about": "Ad sit sint occaecat ea veniam cillum elit ex veniam cillum dolore incididunt consequat Lorem. In culpa eu proident occaecat duis. Ut anim exercitation cupidatat ullamco aliqua amet tempor. Aute mollit magna consectetur laborum amet minim commodo. Dolore non excepteur Lorem anim labore anim aliqua ex minim qui aliquip proident irure.\r\n", + "registered": "2010-06-01T11:37:04+05:00", + "friends": [ + { + "id": 0, + "name": "Dotson Weeks" + }, + { + "id": 1, + "name": "Townsend Rodgers" + }, + { + "id": 2, + "name": "Zamora Newton" + } + ] + }, + { + "id": 219, + "guid": "784f8eb6-2aa4-42d2-94c3-e21486a75d1f", + "isActive": false, + "balance": "$3,926.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Snider Palmer", + "gender": "male", + "company": "Klugger", + "email": "sniderpalmer@klugger.com", + "phone": "+1 (884) 438-2870", + "address": { + "street": 207, + "city": "Fairmount", + "state": "Illinois", + "zip": 9002 + }, + "about": "Qui dolor culpa amet ullamco aute esse. Ipsum mollit fugiat elit incididunt aliqua ex. Incididunt laborum fugiat Lorem Lorem in consequat nulla esse duis fugiat cillum cillum non consequat. Nulla in dolor laborum consectetur ipsum incididunt officia adipisicing consequat duis ipsum ullamco elit sunt.\r\n", + "registered": "1992-06-07T12:42:24+05:00", + "friends": [ + { + "id": 0, + "name": "Imelda Russell" + }, + { + "id": 1, + "name": "Coffey Moreno" + }, + { + "id": 2, + "name": "Figueroa Moran" + } + ] + }, + { + "id": 220, + "guid": "3fcfdc98-6feb-48cb-a97c-a22d7a3f23a7", + "isActive": false, + "balance": "$2,325.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Duran Callahan", + "gender": "male", + "company": "Netagy", + "email": "durancallahan@netagy.com", + "phone": "+1 (826) 476-3977", + "address": { + "street": 656, + "city": "Herlong", + "state": "Vermont", + "zip": 5377 + }, + "about": "Duis labore eu mollit excepteur qui fugiat proident consectetur veniam duis cillum esse. In laborum est velit do sunt commodo consectetur reprehenderit fugiat consequat culpa. Aliqua eu consequat aliquip ea esse reprehenderit sunt laborum deserunt anim reprehenderit culpa non consectetur. Amet veniam duis culpa dolor fugiat nisi veniam ex do sunt dolor. Aute amet quis dolore in sunt. Quis cillum consectetur labore nulla esse aute dolore cillum ad. Sint ex esse aute adipisicing anim ullamco.\r\n", + "registered": "1990-02-05T05:07:53+06:00", + "friends": [ + { + "id": 0, + "name": "Patricia Scott" + }, + { + "id": 1, + "name": "Frances Lamb" + }, + { + "id": 2, + "name": "Francis Berry" + } + ] + }, + { + "id": 221, + "guid": "a4817b76-0136-446e-bef0-698097c5f024", + "isActive": true, + "balance": "$2,578.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Sylvia Frazier", + "gender": "female", + "company": "Signity", + "email": "sylviafrazier@signity.com", + "phone": "+1 (897) 416-2203", + "address": { + "street": 173, + "city": "Leyner", + "state": "Maine", + "zip": 4865 + }, + "about": "Voluptate qui commodo quis deserunt aute in eu deserunt ad id voluptate sint sit. Sint esse aute pariatur anim occaecat minim qui aliqua. Elit ut consectetur laboris ipsum adipisicing dolor.\r\n", + "registered": "2006-02-05T16:39:58+06:00", + "friends": [ + { + "id": 0, + "name": "Clark Newman" + }, + { + "id": 1, + "name": "Rodriguez Smith" + }, + { + "id": 2, + "name": "Aurelia Hester" + } + ] + }, + { + "id": 222, + "guid": "9d391e0d-1f97-40a0-b6c2-8123b0dee843", + "isActive": false, + "balance": "$2,182.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Beulah Stanley", + "gender": "female", + "company": "Interloo", + "email": "beulahstanley@interloo.com", + "phone": "+1 (907) 454-3397", + "address": { + "street": 787, + "city": "Roland", + "state": "Alaska", + "zip": 8297 + }, + "about": "Aliquip consectetur mollit amet exercitation nulla tempor deserunt do. Exercitation velit enim velit culpa minim cillum incididunt sit sunt. Commodo laboris ut non culpa irure in consequat velit reprehenderit dolore laboris proident non.\r\n", + "registered": "2007-10-20T07:59:51+05:00", + "friends": [ + { + "id": 0, + "name": "Trujillo Walls" + }, + { + "id": 1, + "name": "Juliana Osborn" + }, + { + "id": 2, + "name": "Kramer Gordon" + } + ] + }, + { + "id": 223, + "guid": "c8c26d92-2bcc-4b12-ab15-f9417e8f1cb8", + "isActive": false, + "balance": "$1,900.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Delia Hopkins", + "gender": "female", + "company": "Aclima", + "email": "deliahopkins@aclima.com", + "phone": "+1 (863) 464-2709", + "address": { + "street": 445, + "city": "Connerton", + "state": "Nebraska", + "zip": 3212 + }, + "about": "Cupidatat quis qui elit consectetur quis sunt velit nisi nulla veniam qui ad. Enim consectetur Lorem non mollit eu nulla culpa voluptate minim ad adipisicing. Velit magna do irure laborum id. Ut fugiat nostrud officia duis exercitation ea esse ea nostrud consectetur sunt occaecat deserunt eu. Consequat sint exercitation esse consequat ex sint in cillum cupidatat velit duis Lorem. Laborum minim dolore est nostrud voluptate elit in nostrud et et labore sint.\r\n", + "registered": "2012-11-07T14:50:59+06:00", + "friends": [ + { + "id": 0, + "name": "Lowery Weaver" + }, + { + "id": 1, + "name": "Salinas Gentry" + }, + { + "id": 2, + "name": "Anne Santiago" + } + ] + }, + { + "id": 224, + "guid": "f90f6375-c412-4126-9c82-e873bad79cae", + "isActive": true, + "balance": "$1,833.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Melendez Branch", + "gender": "male", + "company": "Ziggles", + "email": "melendezbranch@ziggles.com", + "phone": "+1 (994) 413-3243", + "address": { + "street": 154, + "city": "Salunga", + "state": "South Dakota", + "zip": 4155 + }, + "about": "Qui deserunt aliquip laborum aute et tempor. Duis dolore id cupidatat voluptate minim veniam ad laboris ea ullamco pariatur qui cupidatat eu. Excepteur ut culpa et tempor.\r\n", + "registered": "2011-12-26T15:07:00+06:00", + "friends": [ + { + "id": 0, + "name": "Rachael Bird" + }, + { + "id": 1, + "name": "Zelma Wilson" + }, + { + "id": 2, + "name": "Rojas Gill" + } + ] + }, + { + "id": 225, + "guid": "4c288003-3e3f-49fd-9204-f2cd26cdd613", + "isActive": false, + "balance": "$3,150.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Contreras Walker", + "gender": "male", + "company": "Ebidco", + "email": "contreraswalker@ebidco.com", + "phone": "+1 (833) 569-2843", + "address": { + "street": 397, + "city": "Klondike", + "state": "Massachusetts", + "zip": 8266 + }, + "about": "Enim aliqua ea commodo labore aliqua ut exercitation Lorem. Ea culpa officia ipsum ex et adipisicing elit nisi anim nisi. Proident sunt esse sint velit dolor occaecat exercitation veniam do tempor est aute consectetur. Proident cillum aliqua reprehenderit aute dolor dolore veniam do ipsum qui labore sit. Non ut adipisicing mollit ad voluptate ea occaecat aliqua anim.\r\n", + "registered": "2012-12-14T19:22:00+06:00", + "friends": [ + { + "id": 0, + "name": "Schultz Ayala" + }, + { + "id": 1, + "name": "Snow Maxwell" + }, + { + "id": 2, + "name": "Ida Hodge" + } + ] + }, + { + "id": 226, + "guid": "eec7d9d3-347c-4e62-acbd-ab5145e583b7", + "isActive": true, + "balance": "$1,459.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Horn Mckinney", + "gender": "male", + "company": "Dognost", + "email": "hornmckinney@dognost.com", + "phone": "+1 (925) 594-3539", + "address": { + "street": 624, + "city": "Yettem", + "state": "Tennessee", + "zip": 4667 + }, + "about": "Quis cupidatat consectetur ad deserunt cillum cupidatat esse enim. Adipisicing nostrud aute ea sint reprehenderit eu aliquip. Laboris do aliqua laborum sint exercitation officia Lorem voluptate esse nulla nostrud. Id cupidatat quis nostrud consectetur sint eiusmod. Commodo ea esse officia aliquip ullamco tempor mollit fugiat sint in consectetur amet.\r\n", + "registered": "1988-05-05T02:39:25+05:00", + "friends": [ + { + "id": 0, + "name": "Carrillo Fletcher" + }, + { + "id": 1, + "name": "Lisa Hickman" + }, + { + "id": 2, + "name": "Ingram Mcmahon" + } + ] + }, + { + "id": 227, + "guid": "de9ef832-e7c6-4066-ba37-7f5d1a81fd66", + "isActive": true, + "balance": "$3,089.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Mercado Vaughn", + "gender": "male", + "company": "Telepark", + "email": "mercadovaughn@telepark.com", + "phone": "+1 (862) 557-2737", + "address": { + "street": 566, + "city": "Villarreal", + "state": "Delaware", + "zip": 946 + }, + "about": "Eiusmod adipisicing sunt laborum nostrud aliquip culpa minim. Ex anim nisi sunt eiusmod officia enim incididunt reprehenderit cillum est nisi sunt proident excepteur. Amet nisi officia in et sint labore dolor aliquip quis magna sunt et. Voluptate id dolore non dolore ea eu dolore ea enim ut voluptate in laborum. Velit minim sint consectetur nostrud Lorem. Nulla nostrud non duis commodo adipisicing non sint tempor in elit veniam exercitation. Sunt consequat ut est enim enim aliqua deserunt amet ex anim culpa dolore.\r\n", + "registered": "2004-02-24T01:11:12+06:00", + "friends": [ + { + "id": 0, + "name": "Audrey Alvarado" + }, + { + "id": 1, + "name": "Douglas Sellers" + }, + { + "id": 2, + "name": "Selma Williamson" + } + ] + }, + { + "id": 228, + "guid": "431a3c3d-8c1c-4a12-9a54-cd44427d31d5", + "isActive": false, + "balance": "$2,271.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Sondra Sanford", + "gender": "female", + "company": "Konnect", + "email": "sondrasanford@konnect.com", + "phone": "+1 (975) 530-2100", + "address": { + "street": 958, + "city": "Osage", + "state": "Nevada", + "zip": 1627 + }, + "about": "Est quis eu occaecat magna non. Deserunt quis irure nulla culpa mollit ex commodo minim dolor Lorem do. Ullamco reprehenderit laboris deserunt et anim eu. Fugiat eiusmod qui aute ullamco tempor occaecat dolore reprehenderit sit quis pariatur dolor elit occaecat.\r\n", + "registered": "1999-10-14T14:44:38+05:00", + "friends": [ + { + "id": 0, + "name": "Julia Mcfadden" + }, + { + "id": 1, + "name": "Aida Miller" + }, + { + "id": 2, + "name": "Faulkner Guthrie" + } + ] + }, + { + "id": 229, + "guid": "dc8e02ec-8814-4573-a2db-01df8b975b8e", + "isActive": false, + "balance": "$3,892.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Roberson Blevins", + "gender": "male", + "company": "Zytrek", + "email": "robersonblevins@zytrek.com", + "phone": "+1 (973) 512-3464", + "address": { + "street": 666, + "city": "Conestoga", + "state": "Indiana", + "zip": 155 + }, + "about": "Nisi aliquip do enim culpa. Do consectetur nostrud et nisi ipsum commodo eiusmod reprehenderit. Exercitation labore commodo excepteur ad occaecat non culpa aute ipsum voluptate reprehenderit deserunt consectetur est. Elit excepteur minim esse nostrud labore veniam laborum est.\r\n", + "registered": "2011-03-02T22:27:51+06:00", + "friends": [ + { + "id": 0, + "name": "Velazquez Shepard" + }, + { + "id": 1, + "name": "Krista Casey" + }, + { + "id": 2, + "name": "Maddox Talley" + } + ] + }, + { + "id": 230, + "guid": "7d9a528f-b3a0-40a5-b6a4-0e10274682f7", + "isActive": false, + "balance": "$2,470.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Loretta Joyce", + "gender": "female", + "company": "Thredz", + "email": "lorettajoyce@thredz.com", + "phone": "+1 (876) 459-3178", + "address": { + "street": 561, + "city": "Dodge", + "state": "Virginia", + "zip": 161 + }, + "about": "Commodo anim nisi eu qui sunt sunt. Dolore exercitation magna irure eiusmod esse officia minim consectetur. Mollit commodo fugiat consequat exercitation aliqua dolore eiusmod qui proident qui proident est nisi eu.\r\n", + "registered": "1999-12-30T03:53:17+06:00", + "friends": [ + { + "id": 0, + "name": "Dejesus Vincent" + }, + { + "id": 1, + "name": "Lucy Brady" + }, + { + "id": 2, + "name": "Jensen Mcdonald" + } + ] + }, + { + "id": 231, + "guid": "d039ed64-7858-42da-a624-239ddd865699", + "isActive": true, + "balance": "$3,537.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Atkins Lang", + "gender": "male", + "company": "Polarax", + "email": "atkinslang@polarax.com", + "phone": "+1 (917) 450-2491", + "address": { + "street": 664, + "city": "Lavalette", + "state": "Washington", + "zip": 1835 + }, + "about": "Ut ut labore cupidatat pariatur dolor mollit irure dolor nostrud ipsum excepteur eiusmod. Labore exercitation ad commodo ea amet ad est ad mollit irure aute. Voluptate elit occaecat pariatur amet officia nostrud ex.\r\n", + "registered": "2012-07-20T15:24:12+05:00", + "friends": [ + { + "id": 0, + "name": "Kelly Stevens" + }, + { + "id": 1, + "name": "Jessica Kelly" + }, + { + "id": 2, + "name": "Chandler Melendez" + } + ] + }, + { + "id": 232, + "guid": "32ac9c1a-412e-42b0-ac24-1444bfc3b74c", + "isActive": false, + "balance": "$1,661.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Rowena Morrison", + "gender": "female", + "company": "Enomen", + "email": "rowenamorrison@enomen.com", + "phone": "+1 (969) 427-3339", + "address": { + "street": 396, + "city": "Naomi", + "state": "Pennsylvania", + "zip": 1941 + }, + "about": "Consequat aliqua irure enim non exercitation. Ipsum exercitation reprehenderit dolor cupidatat nulla laboris culpa. Occaecat ad aute non proident eu sint aliqua magna elit magna irure exercitation.\r\n", + "registered": "1995-05-09T17:24:39+05:00", + "friends": [ + { + "id": 0, + "name": "Mcknight Ellis" + }, + { + "id": 1, + "name": "Caitlin Tyler" + }, + { + "id": 2, + "name": "Annette Shaffer" + } + ] + }, + { + "id": 233, + "guid": "97aee93d-be15-4141-880c-ad79fb42b465", + "isActive": false, + "balance": "$2,965.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Robyn Wagner", + "gender": "female", + "company": "Franscene", + "email": "robynwagner@franscene.com", + "phone": "+1 (833) 518-3609", + "address": { + "street": 695, + "city": "Dyckesville", + "state": "Connecticut", + "zip": 3746 + }, + "about": "Incididunt Lorem minim culpa esse amet eu dolore sunt laborum veniam. Sunt anim ea eu esse sit enim deserunt esse eiusmod fugiat tempor dolore sit. Ipsum velit duis velit aliquip incididunt tempor minim. Enim laboris minim pariatur incididunt. Mollit labore incididunt elit fugiat ea deserunt cupidatat labore nostrud qui. Est pariatur Lorem occaecat ullamco id anim consequat. Fugiat pariatur sunt magna duis adipisicing enim voluptate ex anim.\r\n", + "registered": "1997-03-29T05:52:58+05:00", + "friends": [ + { + "id": 0, + "name": "Arlene Singleton" + }, + { + "id": 1, + "name": "Chandra Grant" + }, + { + "id": 2, + "name": "Santos Fulton" + } + ] + }, + { + "id": 234, + "guid": "3d5231c7-3ff4-469c-80e0-dca4731fdfa4", + "isActive": true, + "balance": "$1,262.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Acevedo Anderson", + "gender": "male", + "company": "Endicil", + "email": "acevedoanderson@endicil.com", + "phone": "+1 (869) 406-2868", + "address": { + "street": 999, + "city": "Shindler", + "state": "Rhode Island", + "zip": 1303 + }, + "about": "Fugiat dolore labore esse eiusmod do qui culpa labore irure in elit incididunt nostrud. Ullamco excepteur nisi voluptate est magna tempor aute veniam ad non fugiat reprehenderit aute. Aliquip ipsum aute officia sint et fugiat nisi laboris cillum velit aliquip eiusmod adipisicing. Ex non incididunt enim excepteur ipsum irure tempor duis pariatur ullamco aliquip consectetur. Pariatur nisi esse duis irure eiusmod eiusmod anim aliquip cillum consequat dolor. Elit dolore exercitation tempor elit. Do excepteur nostrud cillum eu ullamco commodo consectetur anim et proident et ut.\r\n", + "registered": "1999-08-20T15:14:43+05:00", + "friends": [ + { + "id": 0, + "name": "Kaufman Hood" + }, + { + "id": 1, + "name": "Hawkins Bradshaw" + }, + { + "id": 2, + "name": "Hattie Cross" + } + ] + }, + { + "id": 235, + "guid": "eab85edf-d38f-47be-bf5f-1045748f8947", + "isActive": false, + "balance": "$3,442.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Davis Booth", + "gender": "male", + "company": "Amtap", + "email": "davisbooth@amtap.com", + "phone": "+1 (989) 462-3758", + "address": { + "street": 574, + "city": "Cowiche", + "state": "West Virginia", + "zip": 3329 + }, + "about": "Nisi amet cillum sit veniam aute est quis fugiat pariatur. Nisi laboris eu Lorem est cupidatat pariatur do commodo eu sunt incididunt velit minim. Voluptate sint sint aliqua nostrud laborum veniam elit. Veniam ad velit adipisicing veniam in aliqua tempor enim. Nulla minim laboris dolore officia. Aliquip eu Lorem eiusmod quis veniam sit. Labore incididunt ex labore id.\r\n", + "registered": "2003-11-03T00:10:53+06:00", + "friends": [ + { + "id": 0, + "name": "Helen Moore" + }, + { + "id": 1, + "name": "Erika Glover" + }, + { + "id": 2, + "name": "Wilcox Soto" + } + ] + }, + { + "id": 236, + "guid": "4a41cd30-411b-4178-9e1f-29acd29bdc05", + "isActive": false, + "balance": "$3,855.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Blake Richard", + "gender": "male", + "company": "Extro", + "email": "blakerichard@extro.com", + "phone": "+1 (950) 467-2674", + "address": { + "street": 283, + "city": "Sattley", + "state": "South Carolina", + "zip": 8737 + }, + "about": "In et cillum deserunt enim. Laboris aliquip officia nulla dolore nulla irure officia qui occaecat reprehenderit sint ea consectetur consectetur. Irure eu Lorem ut aliqua qui nostrud officia qui laboris consectetur consectetur eu mollit laborum. Eiusmod culpa sint cillum dolore nulla laborum sit laborum quis sit quis.\r\n", + "registered": "2001-11-23T15:49:22+06:00", + "friends": [ + { + "id": 0, + "name": "Walsh Mcdaniel" + }, + { + "id": 1, + "name": "Katy Solomon" + }, + { + "id": 2, + "name": "Jan Ford" + } + ] + }, + { + "id": 237, + "guid": "0a1d11e1-4942-4b14-adf9-6c972a0a02ae", + "isActive": true, + "balance": "$3,580.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Leonor Sims", + "gender": "female", + "company": "Isis", + "email": "leonorsims@isis.com", + "phone": "+1 (901) 412-2070", + "address": { + "street": 438, + "city": "Hobucken", + "state": "Utah", + "zip": 9959 + }, + "about": "Fugiat tempor elit laborum amet proident consectetur nulla. Consectetur est fugiat consequat dolore sint fugiat sit aute magna adipisicing occaecat. Incididunt ea excepteur laboris nulla ullamco et commodo incididunt aliquip. Sit ut id nostrud enim veniam esse esse sit adipisicing ad nostrud consequat eu.\r\n", + "registered": "1992-07-07T13:51:28+05:00", + "friends": [ + { + "id": 0, + "name": "Elliott Duffy" + }, + { + "id": 1, + "name": "Bowman Spencer" + }, + { + "id": 2, + "name": "Haley Thomas" + } + ] + }, + { + "id": 238, + "guid": "ec58fa1d-3081-4560-8914-8ec0e9ea6653", + "isActive": true, + "balance": "$2,017.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Clay Wong", + "gender": "male", + "company": "Twiist", + "email": "claywong@twiist.com", + "phone": "+1 (935) 525-3935", + "address": { + "street": 143, + "city": "Hall", + "state": "Iowa", + "zip": 1924 + }, + "about": "Ex qui dolore amet irure pariatur mollit reprehenderit pariatur non ullamco. Nulla in quis commodo labore. Elit in nostrud eu enim laborum amet minim aute anim tempor et officia ad. Do excepteur ad aliquip elit culpa irure. Id sunt labore non est pariatur non aute voluptate irure.\r\n", + "registered": "1997-06-15T04:12:25+05:00", + "friends": [ + { + "id": 0, + "name": "Bean Keller" + }, + { + "id": 1, + "name": "Mathews Church" + }, + { + "id": 2, + "name": "Wynn Sawyer" + } + ] + }, + { + "id": 239, + "guid": "16e06d99-b3f1-4ed2-b6d0-4a5574711d9e", + "isActive": false, + "balance": "$2,364.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Witt Pittman", + "gender": "male", + "company": "Bleeko", + "email": "wittpittman@bleeko.com", + "phone": "+1 (932) 407-2364", + "address": { + "street": 919, + "city": "Stagecoach", + "state": "Louisiana", + "zip": 116 + }, + "about": "Dolore officia consequat nulla anim adipisicing amet nisi officia cillum exercitation aliquip officia cupidatat. Lorem culpa eu mollit adipisicing minim. Ut quis qui tempor nisi dolor veniam. Fugiat duis sunt consectetur dolore reprehenderit ullamco ut magna fugiat. Ut fugiat occaecat esse ut officia. Esse aute id pariatur consectetur incididunt.\r\n", + "registered": "2008-01-02T13:03:33+06:00", + "friends": [ + { + "id": 0, + "name": "Sargent Norton" + }, + { + "id": 1, + "name": "Erna Joyner" + }, + { + "id": 2, + "name": "Cox Kirkland" + } + ] + }, + { + "id": 240, + "guid": "c9b867ee-5934-4e92-8c1d-9a3ed588cba0", + "isActive": false, + "balance": "$3,887.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Mccullough Zimmerman", + "gender": "male", + "company": "Unisure", + "email": "mcculloughzimmerman@unisure.com", + "phone": "+1 (823) 465-3586", + "address": { + "street": 585, + "city": "Delwood", + "state": "Arkansas", + "zip": 2617 + }, + "about": "Nulla id laborum reprehenderit incididunt est. Voluptate reprehenderit sit culpa mollit proident quis consectetur. Et officia et reprehenderit ullamco labore ullamco est. In magna id ea reprehenderit officia eiusmod. Nostrud aliqua cupidatat est sint excepteur id tempor ipsum enim enim quis eiusmod. Non cupidatat laborum nulla dolore in ea minim nostrud adipisicing reprehenderit Lorem qui id fugiat.\r\n", + "registered": "2007-09-05T21:16:48+05:00", + "friends": [ + { + "id": 0, + "name": "Stacey Mccall" + }, + { + "id": 1, + "name": "Clemons Tyson" + }, + { + "id": 2, + "name": "Lindsay Reilly" + } + ] + }, + { + "id": 241, + "guid": "198bc5ca-38ef-4c68-a418-ce197c61fadd", + "isActive": false, + "balance": "$1,425.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Velez Carpenter", + "gender": "male", + "company": "Kage", + "email": "velezcarpenter@kage.com", + "phone": "+1 (850) 580-3807", + "address": { + "street": 154, + "city": "Weedville", + "state": "New Mexico", + "zip": 7932 + }, + "about": "Duis voluptate aliquip consectetur tempor nostrud aliqua ad anim proident commodo id et sint aute. Reprehenderit veniam dolor officia ex. Irure cupidatat eu officia consectetur tempor qui consequat irure magna irure culpa. Sunt voluptate eu minim cillum voluptate adipisicing excepteur voluptate eiusmod.\r\n", + "registered": "2003-05-15T08:50:20+05:00", + "friends": [ + { + "id": 0, + "name": "Nielsen Boyle" + }, + { + "id": 1, + "name": "Carson Nicholson" + }, + { + "id": 2, + "name": "Fry Summers" + } + ] + }, + { + "id": 242, + "guid": "0bc132cb-5fed-4e7f-a7db-de273add69a2", + "isActive": true, + "balance": "$1,373.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Maritza Good", + "gender": "female", + "company": "Asimiline", + "email": "maritzagood@asimiline.com", + "phone": "+1 (850) 480-2579", + "address": { + "street": 944, + "city": "Crucible", + "state": "California", + "zip": 4669 + }, + "about": "Irure do eiusmod irure ea enim. Sit aliquip elit dolor duis id id mollit cillum. Excepteur aliqua et consectetur et consectetur id est duis nisi eiusmod. Laborum aute veniam ex amet nisi est duis minim pariatur. Nulla magna quis consequat cupidatat id nulla. Duis labore sit eu ipsum qui. Non in est commodo ex.\r\n", + "registered": "2006-01-08T19:02:50+06:00", + "friends": [ + { + "id": 0, + "name": "Hooper Stark" + }, + { + "id": 1, + "name": "Susie Gonzalez" + }, + { + "id": 2, + "name": "Vaughn Lester" + } + ] + }, + { + "id": 243, + "guid": "798f0be5-a214-4dea-8dbd-3c4dc7b5c51f", + "isActive": false, + "balance": "$2,286.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Maxine Odonnell", + "gender": "female", + "company": "Cyclonica", + "email": "maxineodonnell@cyclonica.com", + "phone": "+1 (971) 527-2484", + "address": { + "street": 429, + "city": "Walker", + "state": "Wyoming", + "zip": 9657 + }, + "about": "Ullamco consequat ullamco Lorem consequat laboris nulla officia ad nostrud incididunt id tempor. Sunt ullamco voluptate mollit id mollit nostrud labore duis magna cillum. Lorem ea consequat aute nisi.\r\n", + "registered": "2003-08-30T18:05:24+05:00", + "friends": [ + { + "id": 0, + "name": "Keith Porter" + }, + { + "id": 1, + "name": "Kristen Day" + }, + { + "id": 2, + "name": "Harrell Erickson" + } + ] + }, + { + "id": 244, + "guid": "9491c7a1-eb1d-497e-84dd-f01f5ab91c92", + "isActive": false, + "balance": "$1,737.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Shelton Cardenas", + "gender": "male", + "company": "Gink", + "email": "sheltoncardenas@gink.com", + "phone": "+1 (848) 558-3596", + "address": { + "street": 527, + "city": "Manchester", + "state": "Hawaii", + "zip": 2145 + }, + "about": "Veniam tempor aliqua commodo et reprehenderit deserunt et labore adipisicing anim amet tempor ad. Non anim eu nulla do reprehenderit duis amet in ea pariatur deserunt cillum. Do qui duis exercitation voluptate minim enim dolor ex irure. Reprehenderit tempor cupidatat mollit reprehenderit Lorem aliqua cillum proident officia Lorem mollit ipsum cillum ipsum. Non occaecat ullamco commodo in aliqua tempor dolore occaecat qui non ipsum aliqua. Amet aute consequat aliquip non proident laboris commodo. Consequat aliqua ullamco quis in nostrud proident enim irure dolor id.\r\n", + "registered": "1990-07-23T04:14:09+05:00", + "friends": [ + { + "id": 0, + "name": "Hinton Stein" + }, + { + "id": 1, + "name": "Stokes Conrad" + }, + { + "id": 2, + "name": "Sybil Schwartz" + } + ] + }, + { + "id": 245, + "guid": "ffa9943b-e0c7-4978-aa4f-b412188c2d06", + "isActive": false, + "balance": "$1,991.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Mcmillan Malone", + "gender": "male", + "company": "Melbacor", + "email": "mcmillanmalone@melbacor.com", + "phone": "+1 (879) 561-3007", + "address": { + "street": 249, + "city": "Drummond", + "state": "Missouri", + "zip": 7234 + }, + "about": "Cupidatat voluptate laborum ea dolore duis elit. Exercitation ipsum amet aliqua culpa dolore aliquip exercitation. Enim consectetur ullamco sunt et eu laboris ad magna ut laboris est irure proident. Eu incididunt esse occaecat officia labore culpa do. Adipisicing anim voluptate aute pariatur esse ullamco cupidatat exercitation deserunt irure eu sit ex. Enim mollit adipisicing enim elit. Excepteur duis do ullamco enim non velit voluptate qui pariatur enim fugiat qui cupidatat.\r\n", + "registered": "2011-01-17T21:41:08+06:00", + "friends": [ + { + "id": 0, + "name": "Lou Wilson" + }, + { + "id": 1, + "name": "Stacey Watson" + }, + { + "id": 2, + "name": "Tracie Henderson" + } + ] + }, + { + "id": 246, + "guid": "cda90226-71b7-495a-8a70-878cc34aa137", + "isActive": true, + "balance": "$1,349.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Mollie Miles", + "gender": "female", + "company": "Cogentry", + "email": "molliemiles@cogentry.com", + "phone": "+1 (992) 547-3436", + "address": { + "street": 350, + "city": "Caberfae", + "state": "Delaware", + "zip": 7320 + }, + "about": "Officia laborum aliqua non exercitation. Excepteur occaecat exercitation reprehenderit et sunt nulla dolore eu veniam aute quis. Occaecat dolore consequat aliqua sit consectetur excepteur. Eu irure ullamco dolore occaecat officia cillum. Ullamco minim pariatur ullamco esse ex aliqua cillum laboris veniam nostrud.\r\n", + "registered": "2005-10-14T07:20:05+05:00", + "friends": [ + { + "id": 0, + "name": "Bruce Barr" + }, + { + "id": 1, + "name": "Tracy Shannon" + }, + { + "id": 2, + "name": "Rosalyn Powers" + } + ] + }, + { + "id": 247, + "guid": "e4195d14-b88b-4155-bea5-0c3dac73ed49", + "isActive": true, + "balance": "$1,927.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Owens Gonzalez", + "gender": "male", + "company": "Puria", + "email": "owensgonzalez@puria.com", + "phone": "+1 (975) 408-3655", + "address": { + "street": 557, + "city": "Hasty", + "state": "New Mexico", + "zip": 1448 + }, + "about": "Eiusmod veniam ad duis magna sunt. Ea velit do magna anim exercitation sunt amet occaecat nostrud id et. Sunt laborum culpa eu cupidatat sit velit cupidatat irure consectetur nisi.\r\n", + "registered": "2012-07-08T20:00:21+05:00", + "friends": [ + { + "id": 0, + "name": "Garrett Singleton" + }, + { + "id": 1, + "name": "Huffman Burnett" + }, + { + "id": 2, + "name": "Monroe Knox" + } + ] + }, + { + "id": 248, + "guid": "d8c093cc-3233-4d7f-9a87-34e1ac1f855f", + "isActive": false, + "balance": "$1,376.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Rice Dillon", + "gender": "male", + "company": "Memora", + "email": "ricedillon@memora.com", + "phone": "+1 (808) 440-3794", + "address": { + "street": 448, + "city": "Carlos", + "state": "Kansas", + "zip": 8752 + }, + "about": "Aliqua ad adipisicing labore cupidatat. Et in Lorem veniam qui. Labore veniam sit do esse aute laborum commodo magna aute ullamco eiusmod aliquip amet.\r\n", + "registered": "1996-12-17T12:29:34+06:00", + "friends": [ + { + "id": 0, + "name": "Louise Burns" + }, + { + "id": 1, + "name": "Roach Mendoza" + }, + { + "id": 2, + "name": "Henrietta Frost" + } + ] + }, + { + "id": 249, + "guid": "ebf21fb1-60ec-4548-abb6-5a98a0abc480", + "isActive": false, + "balance": "$1,929.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Mcmillan Vega", + "gender": "male", + "company": "Artiq", + "email": "mcmillanvega@artiq.com", + "phone": "+1 (826) 541-3737", + "address": { + "street": 737, + "city": "Hinsdale", + "state": "Arizona", + "zip": 6603 + }, + "about": "Tempor qui id labore aute. Veniam veniam aute Lorem officia amet amet incididunt ex. Cillum sunt non ipsum quis pariatur quis fugiat cupidatat tempor. Officia ea sint sit fugiat commodo ipsum quis velit sint ut pariatur ullamco non.\r\n", + "registered": "2001-07-31T05:29:50+05:00", + "friends": [ + { + "id": 0, + "name": "Vilma Porter" + }, + { + "id": 1, + "name": "Reeves Kerr" + }, + { + "id": 2, + "name": "Swanson Joseph" + } + ] + }, + { + "id": 250, + "guid": "0d303bc9-0d1e-421d-a42e-cd0262d8f963", + "isActive": true, + "balance": "$3,799.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Fern Daniel", + "gender": "female", + "company": "Bisba", + "email": "ferndaniel@bisba.com", + "phone": "+1 (941) 550-2486", + "address": { + "street": 195, + "city": "Skyland", + "state": "Maine", + "zip": 1780 + }, + "about": "Consectetur qui ullamco cillum reprehenderit veniam tempor labore dolore sit voluptate in. Et duis in irure sint id duis tempor Lorem est. Culpa cillum id sint irure incididunt commodo consequat minim eiusmod ea ad amet adipisicing non. Culpa eiusmod magna tempor ex voluptate.\r\n", + "registered": "2005-10-12T01:58:09+05:00", + "friends": [ + { + "id": 0, + "name": "Buchanan Finch" + }, + { + "id": 1, + "name": "Todd Stanley" + }, + { + "id": 2, + "name": "Drake Merritt" + } + ] + }, + { + "id": 251, + "guid": "42774020-7d7e-49a7-8cab-d422bfd64cae", + "isActive": false, + "balance": "$1,998.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Estella Rowe", + "gender": "female", + "company": "Combogen", + "email": "estellarowe@combogen.com", + "phone": "+1 (961) 482-3629", + "address": { + "street": 443, + "city": "Albrightsville", + "state": "Michigan", + "zip": 1662 + }, + "about": "Occaecat magna ut enim et voluptate sunt est sint anim laboris consectetur anim. Nisi nulla irure culpa aliqua duis velit laboris aliqua adipisicing cupidatat culpa minim consectetur veniam. Enim elit irure ut ipsum sit mollit incididunt. Dolor eu Lorem irure proident officia. Duis laborum velit duis occaecat proident do exercitation occaecat eiusmod nisi. Nisi exercitation ea est eiusmod elit non pariatur magna et occaecat reprehenderit proident duis ullamco.\r\n", + "registered": "2006-08-07T17:03:55+05:00", + "friends": [ + { + "id": 0, + "name": "Maureen Hughes" + }, + { + "id": 1, + "name": "Gregory Evans" + }, + { + "id": 2, + "name": "Lourdes Horne" + } + ] + }, + { + "id": 252, + "guid": "b6a7a4c6-7749-42b3-b7bc-eb984687a0c3", + "isActive": false, + "balance": "$1,774.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Lula Blevins", + "gender": "female", + "company": "Kongle", + "email": "lulablevins@kongle.com", + "phone": "+1 (973) 487-2756", + "address": { + "street": 657, + "city": "Bellfountain", + "state": "Oregon", + "zip": 883 + }, + "about": "Laborum reprehenderit do et ad deserunt quis cupidatat. Dolor magna officia sunt labore deserunt consectetur do incididunt exercitation. Do est duis pariatur ad magna laboris quis Lorem duis ea nostrud esse et. Tempor minim id ea ad. Exercitation est labore ex dolor labore aliquip irure consequat deserunt irure occaecat mollit nulla. Exercitation eiusmod esse sunt laboris amet reprehenderit et elit est aliquip do.\r\n", + "registered": "2003-12-07T02:01:36+06:00", + "friends": [ + { + "id": 0, + "name": "Flora Fry" + }, + { + "id": 1, + "name": "Stella Patterson" + }, + { + "id": 2, + "name": "Hickman Smith" + } + ] + }, + { + "id": 253, + "guid": "fedf17f1-608e-4dc2-95b0-f5fd6b760066", + "isActive": false, + "balance": "$3,233.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Stewart Scott", + "gender": "male", + "company": "Illumity", + "email": "stewartscott@illumity.com", + "phone": "+1 (924) 502-2662", + "address": { + "street": 264, + "city": "Enetai", + "state": "Tennessee", + "zip": 6469 + }, + "about": "Laboris amet sint proident deserunt consectetur eu consectetur culpa labore labore quis velit occaecat. Ullamco ullamco minim aute laborum tempor dolor veniam amet ea cupidatat et minim dolor reprehenderit. Quis minim duis qui reprehenderit eiusmod tempor cupidatat esse magna et eu. Ullamco proident ad dolor reprehenderit Lorem cupidatat velit ipsum exercitation. Ullamco Lorem ea enim cupidatat laboris cillum est cupidatat dolor dolore occaecat aliquip. In id quis laboris deserunt. Esse mollit pariatur incididunt aliquip dolore in sunt velit mollit in ex aute est.\r\n", + "registered": "2009-12-08T00:07:05+06:00", + "friends": [ + { + "id": 0, + "name": "Combs Duran" + }, + { + "id": 1, + "name": "Corina Clements" + }, + { + "id": 2, + "name": "Karyn Burris" + } + ] + }, + { + "id": 254, + "guid": "8a67940c-2b31-421a-9f9c-72219e30b284", + "isActive": false, + "balance": "$3,733.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Jerry Holmes", + "gender": "female", + "company": "Bitrex", + "email": "jerryholmes@bitrex.com", + "phone": "+1 (888) 482-3467", + "address": { + "street": 672, + "city": "Bedias", + "state": "Nevada", + "zip": 1581 + }, + "about": "In elit sunt eu est. Amet irure cupidatat in irure. Consequat sint irure nulla pariatur exercitation quis velit velit et. Aliqua nisi consequat esse ut eu consectetur cupidatat ad consectetur irure Lorem voluptate Lorem. Veniam voluptate ex consectetur cupidatat eiusmod magna.\r\n", + "registered": "2009-05-28T07:05:39+05:00", + "friends": [ + { + "id": 0, + "name": "Roth Macdonald" + }, + { + "id": 1, + "name": "Hurst Brady" + }, + { + "id": 2, + "name": "Karen Nguyen" + } + ] + }, + { + "id": 255, + "guid": "cf81dbfa-76bb-494b-acc2-9e33ca92126c", + "isActive": true, + "balance": "$3,824.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Cain Wagner", + "gender": "male", + "company": "Tourmania", + "email": "cainwagner@tourmania.com", + "phone": "+1 (980) 517-2188", + "address": { + "street": 956, + "city": "Darrtown", + "state": "Maryland", + "zip": 946 + }, + "about": "Nulla id commodo qui velit laborum cupidatat excepteur irure tempor. Excepteur incididunt irure exercitation nulla eu ullamco. Sunt exercitation esse velit aute. Velit dolor exercitation voluptate reprehenderit deserunt occaecat tempor laborum est deserunt labore duis incididunt. Ut elit id nulla nostrud. Veniam fugiat ea dolor velit quis exercitation incididunt pariatur eiusmod occaecat quis labore enim nulla.\r\n", + "registered": "1989-09-24T06:33:54+05:00", + "friends": [ + { + "id": 0, + "name": "Sims Cochran" + }, + { + "id": 1, + "name": "Norris Petersen" + }, + { + "id": 2, + "name": "Elnora Kane" + } + ] + }, + { + "id": 256, + "guid": "9e401336-f2bd-4597-b7c8-62af74c72131", + "isActive": true, + "balance": "$1,149.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Crane Sandoval", + "gender": "male", + "company": "Utara", + "email": "cranesandoval@utara.com", + "phone": "+1 (847) 429-2442", + "address": { + "street": 276, + "city": "Chelsea", + "state": "Rhode Island", + "zip": 8029 + }, + "about": "Aute Lorem consectetur mollit reprehenderit. Eiusmod velit mollit est ad elit. Exercitation dolore culpa sint laboris Lorem et sunt ea culpa aliqua veniam exercitation. Veniam ad aute sint tempor esse esse excepteur irure do ipsum nisi sint cillum.\r\n", + "registered": "1991-08-18T04:48:18+05:00", + "friends": [ + { + "id": 0, + "name": "Marks Bernard" + }, + { + "id": 1, + "name": "Riggs Salas" + }, + { + "id": 2, + "name": "Rodriguez Wilder" + } + ] + }, + { + "id": 257, + "guid": "43a70162-6068-49c3-8afb-270b36d12ee6", + "isActive": true, + "balance": "$3,288.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Dena Rocha", + "gender": "female", + "company": "Satiance", + "email": "denarocha@satiance.com", + "phone": "+1 (852) 412-2776", + "address": { + "street": 330, + "city": "Bartonsville", + "state": "Iowa", + "zip": 2778 + }, + "about": "Proident voluptate anim nisi laborum excepteur. Consequat voluptate ipsum sint fugiat enim quis sunt. Laborum magna duis sunt nisi aliqua irure anim.\r\n", + "registered": "2004-12-05T09:33:37+06:00", + "friends": [ + { + "id": 0, + "name": "Mueller Fowler" + }, + { + "id": 1, + "name": "Alvarez Curry" + }, + { + "id": 2, + "name": "Shari Arnold" + } + ] + }, + { + "id": 258, + "guid": "b64b1693-2c94-4906-b902-ce8437f05b08", + "isActive": true, + "balance": "$1,222.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Goodwin Sampson", + "gender": "male", + "company": "Cytrek", + "email": "goodwinsampson@cytrek.com", + "phone": "+1 (900) 500-3402", + "address": { + "street": 977, + "city": "Rodanthe", + "state": "Colorado", + "zip": 366 + }, + "about": "Veniam cillum ea velit ex anim Lorem amet. Adipisicing enim amet velit qui amet officia mollit tempor laborum dolore consectetur elit. Voluptate nisi exercitation qui nostrud aute et. Amet ipsum esse aliqua eu et elit consectetur.\r\n", + "registered": "2009-05-01T00:01:00+05:00", + "friends": [ + { + "id": 0, + "name": "Margie Bowman" + }, + { + "id": 1, + "name": "Osborne Marshall" + }, + { + "id": 2, + "name": "Keri Rowland" + } + ] + }, + { + "id": 259, + "guid": "3d945edb-baed-4b08-8cd5-06fb31827b10", + "isActive": true, + "balance": "$1,879.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Ashlee Lamb", + "gender": "female", + "company": "Zilladyne", + "email": "ashleelamb@zilladyne.com", + "phone": "+1 (811) 544-2577", + "address": { + "street": 871, + "city": "Highland", + "state": "Mississippi", + "zip": 7695 + }, + "about": "Fugiat ullamco duis aute cillum elit fugiat velit incididunt. Commodo sit esse id fugiat ullamco pariatur culpa. Ut ut proident et cupidatat nisi id ex tempor laboris nostrud aliqua ipsum. Sint magna ut do ea est aliquip reprehenderit.\r\n", + "registered": "1997-02-08T18:04:30+06:00", + "friends": [ + { + "id": 0, + "name": "Daugherty Nichols" + }, + { + "id": 1, + "name": "Terrie Hickman" + }, + { + "id": 2, + "name": "Laverne Cross" + } + ] + }, + { + "id": 260, + "guid": "bdbffe5c-c78b-4f6c-bc1f-b167eacf2a6d", + "isActive": false, + "balance": "$3,838.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Underwood Dickerson", + "gender": "male", + "company": "Geekola", + "email": "underwooddickerson@geekola.com", + "phone": "+1 (882) 409-2976", + "address": { + "street": 112, + "city": "Brookfield", + "state": "New York", + "zip": 9362 + }, + "about": "Proident reprehenderit anim ut quis irure cillum fugiat nisi tempor quis sit consectetur. Ad incididunt ut cupidatat veniam minim voluptate ad culpa fugiat dolore sint. Esse fugiat reprehenderit irure velit non labore adipisicing incididunt velit proident duis. Laboris elit esse laborum ea. Consequat est esse in est irure anim nulla occaecat sunt ea proident enim ipsum ea.\r\n", + "registered": "1994-10-29T14:03:53+05:00", + "friends": [ + { + "id": 0, + "name": "Richardson Bates" + }, + { + "id": 1, + "name": "Atkinson Cervantes" + }, + { + "id": 2, + "name": "Jenkins Pearson" + } + ] + }, + { + "id": 261, + "guid": "ef681c1f-3dde-41d8-bdb1-cfcd089a8677", + "isActive": false, + "balance": "$3,811.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Ericka Lyons", + "gender": "female", + "company": "Eargo", + "email": "erickalyons@eargo.com", + "phone": "+1 (806) 416-2946", + "address": { + "street": 422, + "city": "Kilbourne", + "state": "New Hampshire", + "zip": 295 + }, + "about": "Aute laboris dolor dolore eiusmod nisi tempor ut exercitation sint nisi. Nulla esse minim velit minim in tempor tempor ipsum non voluptate. Ea duis eu consequat nulla eiusmod. Mollit aliqua aute sit dolore laboris esse ullamco. Aliqua minim quis ullamco proident exercitation.\r\n", + "registered": "1990-06-15T19:46:00+05:00", + "friends": [ + { + "id": 0, + "name": "Rios Casey" + }, + { + "id": 1, + "name": "Good Ramos" + }, + { + "id": 2, + "name": "Luisa Chavez" + } + ] + }, + { + "id": 262, + "guid": "902e644c-51fe-44a0-9a2c-8be1a45d0c07", + "isActive": true, + "balance": "$1,519.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Valeria Burke", + "gender": "female", + "company": "Oulu", + "email": "valeriaburke@oulu.com", + "phone": "+1 (939) 553-3290", + "address": { + "street": 847, + "city": "Columbus", + "state": "Arkansas", + "zip": 1769 + }, + "about": "Fugiat ea ut fugiat esse officia ea nisi amet esse excepteur. Exercitation tempor mollit reprehenderit est minim irure sunt nulla irure. Occaecat excepteur labore eu proident tempor amet qui tempor officia officia est est aliqua reprehenderit. Eiusmod et voluptate irure duis duis. Excepteur ullamco Lorem sint anim consequat nostrud anim laboris pariatur id ea culpa cillum.\r\n", + "registered": "2007-11-08T08:39:08+06:00", + "friends": [ + { + "id": 0, + "name": "Carrillo Colon" + }, + { + "id": 1, + "name": "Deanna West" + }, + { + "id": 2, + "name": "Julia Kirby" + } + ] + }, + { + "id": 263, + "guid": "cf5ce202-06a1-4e31-8a1d-3b5262ded0c2", + "isActive": true, + "balance": "$3,499.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Maribel Mcfadden", + "gender": "female", + "company": "Daido", + "email": "maribelmcfadden@daido.com", + "phone": "+1 (923) 575-3788", + "address": { + "street": 934, + "city": "Beaverdale", + "state": "North Dakota", + "zip": 4931 + }, + "about": "Sit quis quis quis amet aute eu exercitation occaecat nostrud sit. Nulla elit deserunt proident dolore ad excepteur voluptate aliquip qui consequat elit sit voluptate fugiat. Aute pariatur do aliqua proident. Veniam ut et officia culpa sint et. Velit deserunt commodo aute mollit. Tempor mollit reprehenderit proident commodo. Tempor velit do officia ad ea commodo eu nulla.\r\n", + "registered": "2007-04-16T09:01:42+05:00", + "friends": [ + { + "id": 0, + "name": "Corine Reyes" + }, + { + "id": 1, + "name": "Erin David" + }, + { + "id": 2, + "name": "Ruiz Silva" + } + ] + }, + { + "id": 264, + "guid": "dd524db9-5aec-4ed3-90c9-f802cc76e6cd", + "isActive": true, + "balance": "$1,869.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Wilson Dixon", + "gender": "male", + "company": "Coriander", + "email": "wilsondixon@coriander.com", + "phone": "+1 (908) 571-3309", + "address": { + "street": 441, + "city": "Fredericktown", + "state": "Massachusetts", + "zip": 1455 + }, + "about": "Ullamco culpa minim proident dolore est Lorem nulla. Aute commodo sit ad duis pariatur proident. Laborum ipsum ad officia et qui laborum.\r\n", + "registered": "2001-04-17T12:54:54+05:00", + "friends": [ + { + "id": 0, + "name": "Robinson Sparks" + }, + { + "id": 1, + "name": "Myrna Jordan" + }, + { + "id": 2, + "name": "Pacheco Bowen" + } + ] + }, + { + "id": 265, + "guid": "947c8770-7e8d-4350-8d61-d39795973e22", + "isActive": true, + "balance": "$3,359.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Iris Eaton", + "gender": "female", + "company": "Prosure", + "email": "iriseaton@prosure.com", + "phone": "+1 (871) 524-2765", + "address": { + "street": 176, + "city": "Veguita", + "state": "Pennsylvania", + "zip": 9869 + }, + "about": "Ad ad cillum elit dolor quis dolor nisi qui elit laboris consectetur culpa dolor. Dolore minim anim nisi pariatur ullamco officia dolor velit non do duis culpa laboris non. Cillum quis voluptate irure nulla eu nulla magna cillum adipisicing proident id ullamco sunt culpa. Cillum commodo tempor culpa esse laborum magna sit. Lorem amet tempor dolore et eu. Duis ex labore minim eiusmod quis do adipisicing.\r\n", + "registered": "1998-06-23T10:00:48+05:00", + "friends": [ + { + "id": 0, + "name": "Dixon Vaughan" + }, + { + "id": 1, + "name": "Mullins Riggs" + }, + { + "id": 2, + "name": "Queen Moran" + } + ] + }, + { + "id": 266, + "guid": "c21ee71b-6a25-4c35-a0a7-57a8e7529c61", + "isActive": true, + "balance": "$3,963.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Marci Campos", + "gender": "female", + "company": "Cosmetex", + "email": "marcicampos@cosmetex.com", + "phone": "+1 (882) 580-2316", + "address": { + "street": 289, + "city": "Harrison", + "state": "Louisiana", + "zip": 9268 + }, + "about": "Tempor commodo voluptate do nulla aliquip cupidatat duis enim minim culpa. Nostrud duis labore ipsum qui proident amet occaecat labore laborum commodo nostrud aliquip deserunt. Dolore reprehenderit veniam velit aute aute.\r\n", + "registered": "2002-09-18T23:00:45+05:00", + "friends": [ + { + "id": 0, + "name": "Houston Fields" + }, + { + "id": 1, + "name": "Leslie Lewis" + }, + { + "id": 2, + "name": "Becker Willis" + } + ] + }, + { + "id": 267, + "guid": "a4cc8d98-c225-4403-a815-b9bbd150460b", + "isActive": false, + "balance": "$1,876.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Juliette Koch", + "gender": "female", + "company": "Krog", + "email": "juliettekoch@krog.com", + "phone": "+1 (932) 515-3267", + "address": { + "street": 797, + "city": "Glasgow", + "state": "Kentucky", + "zip": 5276 + }, + "about": "Aliqua enim duis incididunt tempor adipisicing ullamco dolore aliquip incididunt consectetur enim. Ea veniam ex ea adipisicing ullamco cillum veniam dolor. Laborum ex sit anim cupidatat pariatur ad labore qui ad.\r\n", + "registered": "1988-12-24T19:03:24+06:00", + "friends": [ + { + "id": 0, + "name": "Donna Carr" + }, + { + "id": 1, + "name": "Yolanda Oliver" + }, + { + "id": 2, + "name": "Nolan Newton" + } + ] + }, + { + "id": 268, + "guid": "0468bd2f-e04b-4feb-9383-6161630d0e83", + "isActive": true, + "balance": "$2,640.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Barron Alford", + "gender": "male", + "company": "Medifax", + "email": "barronalford@medifax.com", + "phone": "+1 (982) 593-2268", + "address": { + "street": 928, + "city": "Weogufka", + "state": "Washington", + "zip": 3429 + }, + "about": "Ullamco et cillum sint reprehenderit eiusmod cupidatat. Dolor ullamco eu ipsum consequat pariatur ut cupidatat officia. Cupidatat excepteur eu laboris velit.\r\n", + "registered": "2007-09-06T05:39:18+05:00", + "friends": [ + { + "id": 0, + "name": "Christa Gilliam" + }, + { + "id": 1, + "name": "Aida Booth" + }, + { + "id": 2, + "name": "Tiffany Sloan" + } + ] + }, + { + "id": 269, + "guid": "80836f7d-a0da-49d3-ab63-1c33c9de06ad", + "isActive": false, + "balance": "$2,432.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "James Morin", + "gender": "male", + "company": "Frenex", + "email": "jamesmorin@frenex.com", + "phone": "+1 (918) 451-3074", + "address": { + "street": 527, + "city": "Hickory", + "state": "Minnesota", + "zip": 4876 + }, + "about": "Quis esse cillum laboris exercitation dolor ex exercitation deserunt qui. Culpa cillum occaecat labore laborum irure aute magna irure quis sunt. Ea exercitation occaecat aute voluptate sunt ex qui irure. Est pariatur commodo deserunt id officia sit cillum ad commodo amet enim culpa labore. Mollit anim laborum reprehenderit nisi ullamco qui ea qui.\r\n", + "registered": "2005-06-27T03:49:16+05:00", + "friends": [ + { + "id": 0, + "name": "Nelson Cohen" + }, + { + "id": 1, + "name": "Francisca Jefferson" + }, + { + "id": 2, + "name": "Katrina Morales" + } + ] + }, + { + "id": 270, + "guid": "1e31edf9-b87f-4f61-b2a5-6270e6e25a82", + "isActive": true, + "balance": "$2,398.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Leona Dotson", + "gender": "female", + "company": "Irack", + "email": "leonadotson@irack.com", + "phone": "+1 (856) 588-2822", + "address": { + "street": 469, + "city": "Soham", + "state": "South Carolina", + "zip": 4224 + }, + "about": "Aute minim ea non labore nostrud velit amet nostrud occaecat ipsum. Ex reprehenderit commodo nulla pariatur do nostrud in sint pariatur laboris elit amet pariatur. Quis et dolore eiusmod tempor. Voluptate aliqua ullamco consequat fugiat est in consequat proident minim adipisicing irure do ipsum aliquip. Ex aute anim enim id nostrud aute occaecat elit veniam. Magna velit deserunt aute adipisicing aliqua sunt nulla laborum et laborum tempor excepteur. Minim officia quis esse est ea deserunt ad fugiat.\r\n", + "registered": "2010-11-20T11:02:54+06:00", + "friends": [ + { + "id": 0, + "name": "Marlene Mcgee" + }, + { + "id": 1, + "name": "Ramos Sherman" + }, + { + "id": 2, + "name": "Olive Yates" + } + ] + }, + { + "id": 271, + "guid": "35922464-54f4-45e7-99b8-9193081fdae7", + "isActive": false, + "balance": "$1,059.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Berger Mckee", + "gender": "male", + "company": "Cofine", + "email": "bergermckee@cofine.com", + "phone": "+1 (846) 409-2677", + "address": { + "street": 772, + "city": "Ballico", + "state": "Virginia", + "zip": 3344 + }, + "about": "Consectetur amet consectetur nostrud commodo dolor culpa enim cupidatat. Ad officia laboris pariatur nostrud ad non dolor ea. Voluptate cupidatat minim nostrud dolore officia et pariatur velit aute enim nisi.\r\n", + "registered": "1992-07-26T00:33:24+05:00", + "friends": [ + { + "id": 0, + "name": "Angel Davenport" + }, + { + "id": 1, + "name": "Terri Mayo" + }, + { + "id": 2, + "name": "Patel Avery" + } + ] + }, + { + "id": 272, + "guid": "b8be2205-8d5a-412b-900a-8dd3557d2bf9", + "isActive": false, + "balance": "$3,527.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Conway Coffey", + "gender": "male", + "company": "Overplex", + "email": "conwaycoffey@overplex.com", + "phone": "+1 (987) 559-3047", + "address": { + "street": 834, + "city": "Barrelville", + "state": "Florida", + "zip": 4323 + }, + "about": "Id consequat aliqua qui consectetur magna adipisicing nostrud cupidatat est reprehenderit mollit occaecat eu. Do excepteur ea esse dolor et eu commodo veniam et exercitation in dolore. Voluptate enim adipisicing ea excepteur eu aliqua labore irure eiusmod occaecat ut sint. Ad id eiusmod nostrud esse aliquip. Consectetur enim duis cillum cupidatat officia incididunt. Laboris non veniam eiusmod velit minim sit. Eiusmod quis reprehenderit labore aliquip commodo incididunt consequat cillum pariatur do dolor irure in aliqua.\r\n", + "registered": "2011-10-18T18:28:52+05:00", + "friends": [ + { + "id": 0, + "name": "Sherrie Daniels" + }, + { + "id": 1, + "name": "Walter Pate" + }, + { + "id": 2, + "name": "Patti Hebert" + } + ] + }, + { + "id": 273, + "guid": "a899b929-06db-4eb3-a28a-12c42e0788f7", + "isActive": true, + "balance": "$2,066.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Justice Figueroa", + "gender": "male", + "company": "Geeknet", + "email": "justicefigueroa@geeknet.com", + "phone": "+1 (968) 468-2700", + "address": { + "street": 406, + "city": "Collins", + "state": "Georgia", + "zip": 9368 + }, + "about": "Consectetur fugiat aliquip ea aliquip occaecat enim proident veniam nulla esse aute amet cillum excepteur. Incididunt est esse non officia. Amet ut cillum dolor esse aute excepteur excepteur nostrud. Labore ut in non fugiat est. Pariatur et deserunt mollit nisi.\r\n", + "registered": "2005-01-28T07:12:08+06:00", + "friends": [ + { + "id": 0, + "name": "Briggs Padilla" + }, + { + "id": 1, + "name": "Cox Kelly" + }, + { + "id": 2, + "name": "George Valencia" + } + ] + }, + { + "id": 274, + "guid": "f5e00eef-9afb-4cb8-bd43-073e2317ea81", + "isActive": false, + "balance": "$2,981.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Holden Leon", + "gender": "male", + "company": "Kneedles", + "email": "holdenleon@kneedles.com", + "phone": "+1 (998) 481-3553", + "address": { + "street": 238, + "city": "Eagletown", + "state": "California", + "zip": 9014 + }, + "about": "Consectetur voluptate consectetur tempor nulla duis excepteur id. Do mollit nostrud non in magna officia in minim ipsum. Ex aute esse eu nisi mollit minim. Reprehenderit aute consequat do est tempor sit magna eiusmod minim anim eu officia magna eiusmod. Reprehenderit laborum Lorem veniam commodo aliquip ullamco ex Lorem laborum eiusmod.\r\n", + "registered": "2008-10-14T13:19:48+05:00", + "friends": [ + { + "id": 0, + "name": "Ines Martin" + }, + { + "id": 1, + "name": "Harper Reynolds" + }, + { + "id": 2, + "name": "Tommie Fernandez" + } + ] + }, + { + "id": 275, + "guid": "6dd0de9a-1dc5-41c0-9887-4217111e577f", + "isActive": false, + "balance": "$3,953.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Lora Brewer", + "gender": "female", + "company": "Marketoid", + "email": "lorabrewer@marketoid.com", + "phone": "+1 (836) 511-2614", + "address": { + "street": 455, + "city": "Tolu", + "state": "West Virginia", + "zip": 4487 + }, + "about": "Eu velit fugiat esse culpa excepteur qui sint aute id culpa est labore do. Ex aliquip fugiat pariatur sunt sunt. Anim dolor non commodo Lorem anim. Sint nisi tempor sint officia dolor esse incididunt pariatur commodo eiusmod.\r\n", + "registered": "1994-02-17T20:26:06+06:00", + "friends": [ + { + "id": 0, + "name": "Dale Navarro" + }, + { + "id": 1, + "name": "Alisa Hardy" + }, + { + "id": 2, + "name": "Elsa Kidd" + } + ] + }, + { + "id": 276, + "guid": "fcf48a67-5823-4821-9f8a-8aa00a13ecfe", + "isActive": false, + "balance": "$1,707.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Janie Mason", + "gender": "female", + "company": "Xerex", + "email": "janiemason@xerex.com", + "phone": "+1 (876) 515-3690", + "address": { + "street": 859, + "city": "Marbury", + "state": "Utah", + "zip": 4210 + }, + "about": "Consectetur nisi sint esse est commodo sunt proident fugiat officia dolor proident. Culpa cupidatat sit voluptate qui minim enim irure tempor magna amet veniam. Consequat velit consequat commodo id quis consequat aliqua ea. Minim est ipsum duis est qui anim exercitation nulla. Consectetur elit id ex ex aliquip irure enim non officia amet. Irure cupidatat ipsum ullamco qui ad incididunt magna incididunt. Amet incididunt veniam sunt ullamco irure.\r\n", + "registered": "2002-11-06T07:47:18+06:00", + "friends": [ + { + "id": 0, + "name": "Elinor Mitchell" + }, + { + "id": 1, + "name": "Hutchinson Gould" + }, + { + "id": 2, + "name": "Melba Jensen" + } + ] + }, + { + "id": 277, + "guid": "d3305cdc-7f8b-4ca3-939b-0da5085f0489", + "isActive": true, + "balance": "$2,583.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Ava Haney", + "gender": "female", + "company": "Buzzmaker", + "email": "avahaney@buzzmaker.com", + "phone": "+1 (913) 426-3098", + "address": { + "street": 717, + "city": "Walker", + "state": "Alabama", + "zip": 6547 + }, + "about": "Eu nostrud deserunt amet aute ipsum consequat adipisicing nulla laborum. Nisi deserunt ad exercitation proident irure do pariatur deserunt nostrud dolor nulla cillum. Duis mollit cillum duis aliqua ea dolor excepteur deserunt do laborum deserunt aliquip. Cupidatat elit pariatur excepteur non magna ad.\r\n", + "registered": "1994-08-07T01:35:32+05:00", + "friends": [ + { + "id": 0, + "name": "Glenn Preston" + }, + { + "id": 1, + "name": "Alicia Norman" + }, + { + "id": 2, + "name": "Higgins Bonner" + } + ] + }, + { + "id": 278, + "guid": "7dabb23e-e67f-4004-923f-37cca515731f", + "isActive": false, + "balance": "$2,115.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "English Mccoy", + "gender": "male", + "company": "Providco", + "email": "englishmccoy@providco.com", + "phone": "+1 (817) 574-3379", + "address": { + "street": 878, + "city": "Nanafalia", + "state": "Montana", + "zip": 8075 + }, + "about": "Labore velit pariatur commodo ea excepteur enim nostrud reprehenderit laborum nulla aute reprehenderit laborum. Non velit sint incididunt dolor fugiat sint Lorem veniam sint exercitation Lorem elit. Labore aliqua ut irure proident laboris nostrud deserunt. Fugiat est id duis nisi Lorem ea eu id. Ullamco qui pariatur magna enim occaecat incididunt nulla ut. Incididunt culpa est sit aute occaecat cupidatat sint incididunt ad culpa nostrud. Aliqua proident in aliquip ea anim cillum laborum quis.\r\n", + "registered": "1999-12-26T03:02:21+06:00", + "friends": [ + { + "id": 0, + "name": "Evangeline Pacheco" + }, + { + "id": 1, + "name": "Muriel Barlow" + }, + { + "id": 2, + "name": "Shelley Massey" + } + ] + }, + { + "id": 279, + "guid": "6d086aac-1645-4596-85de-91d5670280ea", + "isActive": false, + "balance": "$3,701.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Hoover Mcmahon", + "gender": "male", + "company": "Zosis", + "email": "hoovermcmahon@zosis.com", + "phone": "+1 (909) 516-3039", + "address": { + "street": 592, + "city": "Hatteras", + "state": "Connecticut", + "zip": 5754 + }, + "about": "Dolor exercitation voluptate eiusmod aute ex consectetur nulla. Esse deserunt irure ex enim non est officia sunt minim. Quis in in ipsum sunt reprehenderit officia nisi. Enim cupidatat ex nisi fugiat do cillum quis id duis ullamco nisi laboris nostrud. Amet irure dolore exercitation nisi laborum.\r\n", + "registered": "2001-09-13T14:51:16+05:00", + "friends": [ + { + "id": 0, + "name": "Rosario Mckenzie" + }, + { + "id": 1, + "name": "Adriana Potts" + }, + { + "id": 2, + "name": "Clarice Blanchard" + } + ] + }, + { + "id": 280, + "guid": "2ea6fddc-f5fb-41e8-9c99-3e0192ccd358", + "isActive": false, + "balance": "$1,492.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Cardenas Tucker", + "gender": "male", + "company": "Comtrail", + "email": "cardenastucker@comtrail.com", + "phone": "+1 (801) 582-2586", + "address": { + "street": 705, + "city": "Sardis", + "state": "South Dakota", + "zip": 212 + }, + "about": "Sit veniam aliquip do non dolore sit minim non cillum aliquip laborum mollit eu. Mollit nulla nostrud minim veniam sit in enim enim ex aliqua occaecat. Non nisi minim consectetur commodo elit cillum cupidatat aute occaecat dolore elit. Voluptate elit officia dolor mollit nostrud tempor. Velit Lorem minim laboris nostrud velit.\r\n", + "registered": "1988-04-23T01:16:05+05:00", + "friends": [ + { + "id": 0, + "name": "Trujillo Olson" + }, + { + "id": 1, + "name": "Ford Bailey" + }, + { + "id": 2, + "name": "Susie Mcclure" + } + ] + }, + { + "id": 281, + "guid": "a1a8993a-5b9a-432f-80db-8f049ca367de", + "isActive": false, + "balance": "$2,311.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Cynthia Case", + "gender": "female", + "company": "Furnitech", + "email": "cynthiacase@furnitech.com", + "phone": "+1 (932) 403-3459", + "address": { + "street": 290, + "city": "Martell", + "state": "Oklahoma", + "zip": 8803 + }, + "about": "Occaecat eiusmod nisi deserunt consequat mollit aliquip. Veniam Lorem laboris aliquip cillum dolor. Magna labore minim amet nulla laboris culpa exercitation cupidatat elit aliquip adipisicing tempor. Duis laboris commodo eu commodo laboris do qui mollit. Voluptate anim quis incididunt id do duis ex laboris qui nisi magna nostrud incididunt. Cillum laboris dolore cupidatat fugiat non exercitation.\r\n", + "registered": "1988-03-04T00:17:02+06:00", + "friends": [ + { + "id": 0, + "name": "Christian Petty" + }, + { + "id": 1, + "name": "Tania Parsons" + }, + { + "id": 2, + "name": "Phyllis Cotton" + } + ] + }, + { + "id": 282, + "guid": "a361da33-bdd6-49c9-a23a-6f3824877655", + "isActive": true, + "balance": "$3,191.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Snow Goodman", + "gender": "male", + "company": "Optyk", + "email": "snowgoodman@optyk.com", + "phone": "+1 (850) 557-2034", + "address": { + "street": 845, + "city": "Jamestown", + "state": "North Carolina", + "zip": 5553 + }, + "about": "Occaecat do dolor ut officia consequat eu nisi eiusmod elit. Anim Lorem anim laboris dolore anim sint laborum deserunt laboris labore nulla. Ad non occaecat laborum officia culpa ullamco aliqua est eu. Id nulla officia tempor enim nisi incididunt. Cupidatat laborum culpa consequat laboris eiusmod. Do id officia sit commodo officia irure voluptate voluptate laborum ea velit.\r\n", + "registered": "2001-05-01T22:29:52+05:00", + "friends": [ + { + "id": 0, + "name": "Pope Lawrence" + }, + { + "id": 1, + "name": "Lelia Baxter" + }, + { + "id": 2, + "name": "Denise Mcleod" + } + ] + }, + { + "id": 283, + "guid": "258f4faa-4d63-445d-b6d8-8097226e584d", + "isActive": false, + "balance": "$1,329.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Olivia Hubbard", + "gender": "female", + "company": "Overfork", + "email": "oliviahubbard@overfork.com", + "phone": "+1 (842) 414-3370", + "address": { + "street": 682, + "city": "Rossmore", + "state": "Idaho", + "zip": 4074 + }, + "about": "Culpa excepteur consequat velit eu Lorem ut sint quis. Consectetur ex ut anim velit officia irure non veniam commodo ut. Mollit ipsum non elit dolore sunt amet officia irure quis. Proident voluptate Lorem labore reprehenderit enim nostrud. Exercitation labore quis exercitation ipsum ea culpa in voluptate deserunt non. Laboris dolor irure esse sint proident et nulla cupidatat officia magna ad laboris.\r\n", + "registered": "1998-09-22T02:52:37+05:00", + "friends": [ + { + "id": 0, + "name": "Mayra Dominguez" + }, + { + "id": 1, + "name": "Rosalind Estes" + }, + { + "id": 2, + "name": "Savannah Trevino" + } + ] + }, + { + "id": 284, + "guid": "10e1fcef-511c-4d21-9bb7-d869dddac504", + "isActive": true, + "balance": "$2,486.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Snider Buckner", + "gender": "male", + "company": "Aquamate", + "email": "sniderbuckner@aquamate.com", + "phone": "+1 (908) 412-3613", + "address": { + "street": 532, + "city": "Hachita", + "state": "Vermont", + "zip": 5447 + }, + "about": "Exercitation nisi excepteur laborum occaecat ex reprehenderit excepteur aliquip adipisicing dolor do consectetur amet do. Commodo excepteur laboris adipisicing eu sint ut voluptate Lorem ad pariatur minim exercitation incididunt esse. Est velit exercitation cillum ad in pariatur occaecat aute.\r\n", + "registered": "2000-12-15T03:56:17+06:00", + "friends": [ + { + "id": 0, + "name": "Elaine Morse" + }, + { + "id": 1, + "name": "Rhonda Spears" + }, + { + "id": 2, + "name": "Palmer Cantrell" + } + ] + }, + { + "id": 285, + "guid": "3635493b-453a-41ca-a2e5-2d312085dc98", + "isActive": true, + "balance": "$3,365.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Rhoda Ryan", + "gender": "female", + "company": "Exodoc", + "email": "rhodaryan@exodoc.com", + "phone": "+1 (955) 578-3504", + "address": { + "street": 423, + "city": "Haena", + "state": "Alaska", + "zip": 5131 + }, + "about": "Aliqua ut nisi anim id qui do incididunt. Irure mollit nisi incididunt proident nostrud magna voluptate esse officia tempor laborum cillum cupidatat. Duis ipsum est est veniam. Sint elit consequat velit proident. Labore esse non ea consectetur pariatur dolor tempor est non velit. Enim cillum ipsum magna duis esse aliqua excepteur anim in do culpa aliquip.\r\n", + "registered": "1997-08-10T14:33:52+05:00", + "friends": [ + { + "id": 0, + "name": "Rebecca Holloway" + }, + { + "id": 1, + "name": "Jenifer Luna" + }, + { + "id": 2, + "name": "Douglas Slater" + } + ] + }, + { + "id": 286, + "guid": "cbaeb732-a403-47d7-9a8f-6dd87d0656a4", + "isActive": true, + "balance": "$2,455.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Cheryl Wilkerson", + "gender": "female", + "company": "Daisu", + "email": "cherylwilkerson@daisu.com", + "phone": "+1 (978) 551-2129", + "address": { + "street": 102, + "city": "Kingstowne", + "state": "Nebraska", + "zip": 5859 + }, + "about": "Nisi aute amet cupidatat sint do do proident nulla proident nulla enim ipsum. Pariatur magna laboris incididunt amet. Irure commodo deserunt fugiat eu velit ullamco aliquip. Deserunt est quis ut consequat nulla esse adipisicing ex do.\r\n", + "registered": "2002-01-23T23:36:16+06:00", + "friends": [ + { + "id": 0, + "name": "Mckinney Leach" + }, + { + "id": 1, + "name": "Dawn Randall" + }, + { + "id": 2, + "name": "Long Curtis" + } + ] + }, + { + "id": 287, + "guid": "415f567d-1f0b-43a6-aadf-6ba9a26bca1b", + "isActive": false, + "balance": "$1,231.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Larson Macias", + "gender": "male", + "company": "Opticom", + "email": "larsonmacias@opticom.com", + "phone": "+1 (985) 421-3396", + "address": { + "street": 796, + "city": "Indio", + "state": "Hawaii", + "zip": 9911 + }, + "about": "Pariatur incididunt incididunt consectetur ut tempor dolor in. Nisi velit ipsum mollit consequat deserunt consectetur aute. Occaecat amet eu aute elit Lorem officia exercitation elit dolore occaecat ex amet. Et non ad eiusmod est enim duis velit sit enim deserunt.\r\n", + "registered": "2008-12-22T09:03:15+06:00", + "friends": [ + { + "id": 0, + "name": "Gross Wright" + }, + { + "id": 1, + "name": "Ware Owen" + }, + { + "id": 2, + "name": "Terrell Nash" + } + ] + }, + { + "id": 288, + "guid": "f52197b6-7be4-406c-bcc3-8aac4fc34c24", + "isActive": true, + "balance": "$1,171.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Ruthie Elliott", + "gender": "female", + "company": "Nixelt", + "email": "ruthieelliott@nixelt.com", + "phone": "+1 (867) 462-2992", + "address": { + "street": 211, + "city": "Groton", + "state": "Indiana", + "zip": 2677 + }, + "about": "Cupidatat est nulla enim ad culpa consectetur quis voluptate minim laborum est nisi quis. Nostrud anim reprehenderit dolor do labore dolor laboris laboris quis et irure adipisicing aliqua. Cupidatat nostrud cillum elit sunt irure esse irure officia ullamco.\r\n", + "registered": "1999-10-11T11:44:51+05:00", + "friends": [ + { + "id": 0, + "name": "Whitfield Jacobs" + }, + { + "id": 1, + "name": "Hicks Manning" + }, + { + "id": 2, + "name": "Brady Buckley" + } + ] + }, + { + "id": 289, + "guid": "faf8c6c8-4280-48d8-b655-275a3a9f80e2", + "isActive": true, + "balance": "$3,158.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Gordon Poole", + "gender": "male", + "company": "Zolarex", + "email": "gordonpoole@zolarex.com", + "phone": "+1 (972) 507-3643", + "address": { + "street": 557, + "city": "Gratton", + "state": "Wyoming", + "zip": 4987 + }, + "about": "Nisi irure Lorem sunt eiusmod reprehenderit eiusmod consectetur magna do. Dolore duis culpa aute voluptate duis dolore. Voluptate eiusmod cupidatat et qui ad minim est mollit aliqua elit. Ipsum culpa mollit duis ullamco excepteur minim. Lorem proident non ea enim quis duis eiusmod pariatur magna dolore. Aliquip officia eiusmod reprehenderit nulla commodo. Magna consectetur sunt minim cillum ad officia id ullamco adipisicing anim.\r\n", + "registered": "2002-11-06T10:51:53+06:00", + "friends": [ + { + "id": 0, + "name": "Kane Osborne" + }, + { + "id": 1, + "name": "Bender Hester" + }, + { + "id": 2, + "name": "Morton Simmons" + } + ] + }, + { + "id": 290, + "guid": "4e577442-76a0-4cfb-9af7-1b001068a439", + "isActive": true, + "balance": "$1,177.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Pruitt Bartlett", + "gender": "male", + "company": "Wazzu", + "email": "pruittbartlett@wazzu.com", + "phone": "+1 (955) 570-2451", + "address": { + "street": 870, + "city": "Crown", + "state": "Wisconsin", + "zip": 1228 + }, + "about": "Quis nisi consequat mollit in mollit. In magna elit irure excepteur ad eu nostrud esse deserunt est consequat qui. Pariatur incididunt tempor officia proident. Labore et exercitation aute qui proident incididunt et incididunt voluptate ipsum. Nulla minim non adipisicing veniam commodo dolore proident culpa velit. Reprehenderit consequat labore dolor esse. Excepteur nulla id dolore id minim laboris irure ex ipsum proident non reprehenderit est.\r\n", + "registered": "2007-08-04T19:29:05+05:00", + "friends": [ + { + "id": 0, + "name": "Morse Morgan" + }, + { + "id": 1, + "name": "Bean Hodge" + }, + { + "id": 2, + "name": "Valenzuela Maxwell" + } + ] + }, + { + "id": 291, + "guid": "4c910806-45fa-4a20-8b63-726f01bf6e78", + "isActive": true, + "balance": "$3,499.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Laurel Nieves", + "gender": "female", + "company": "Exiand", + "email": "laurelnieves@exiand.com", + "phone": "+1 (805) 515-3251", + "address": { + "street": 706, + "city": "Templeton", + "state": "Texas", + "zip": 4926 + }, + "about": "Et officia dolor laborum Lorem aliqua reprehenderit quis veniam in qui excepteur. Nulla ipsum anim sint anim ad anim velit amet sint eiusmod ullamco eu minim incididunt. Ullamco sit nisi veniam ut ipsum ad irure ea in sunt proident ea aliquip. Adipisicing ea ea voluptate laboris ullamco.\r\n", + "registered": "1991-09-27T20:17:52+05:00", + "friends": [ + { + "id": 0, + "name": "Orr Mcgowan" + }, + { + "id": 1, + "name": "Hubbard Houston" + }, + { + "id": 2, + "name": "Church Wall" + } + ] + }, + { + "id": 292, + "guid": "7634ef79-ee53-4fec-8cf1-8578553daeec", + "isActive": true, + "balance": "$1,833.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Edwina England", + "gender": "female", + "company": "Apex", + "email": "edwinaengland@apex.com", + "phone": "+1 (815) 557-3539", + "address": { + "street": 684, + "city": "Maxville", + "state": "Illinois", + "zip": 782 + }, + "about": "Excepteur in voluptate consectetur aute officia et sit adipisicing. Labore qui aliqua deserunt et consectetur minim eu aliquip ea tempor. Consectetur sint laboris velit sit anim duis culpa proident. Amet ea incididunt incididunt adipisicing enim mollit laboris magna quis. Consequat fugiat mollit amet incididunt esse qui esse excepteur laborum.\r\n", + "registered": "1996-09-04T21:39:18+05:00", + "friends": [ + { + "id": 0, + "name": "Stark Shaw" + }, + { + "id": 1, + "name": "Baird Mills" + }, + { + "id": 2, + "name": "Dawson Coleman" + } + ] + }, + { + "id": 293, + "guid": "7991128c-fdb3-409e-8e2d-d12d09501d28", + "isActive": false, + "balance": "$1,282.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Nguyen Turner", + "gender": "male", + "company": "Olucore", + "email": "nguyenturner@olucore.com", + "phone": "+1 (959) 408-2244", + "address": { + "street": 827, + "city": "Dodge", + "state": "Ohio", + "zip": 5347 + }, + "about": "Adipisicing enim ea ullamco sint tempor tempor. Elit adipisicing nisi ipsum culpa quis laborum sunt commodo consectetur magna laboris anim duis. Ad culpa ex irure ullamco ipsum Lorem nostrud. Qui excepteur ex laborum velit officia aliquip. Velit culpa magna minim fugiat minim ipsum non sunt consequat occaecat adipisicing cupidatat minim. Amet officia labore aliquip qui. Deserunt consectetur pariatur ut sint sint fugiat et adipisicing culpa velit cupidatat.\r\n", + "registered": "1999-01-06T18:45:21+06:00", + "friends": [ + { + "id": 0, + "name": "Brenda Pennington" + }, + { + "id": 1, + "name": "Geraldine Johns" + }, + { + "id": 2, + "name": "Alyson Franks" + } + ] + }, + { + "id": 294, + "guid": "17c9e76e-3aed-42b3-8c17-96033e5bdfc1", + "isActive": false, + "balance": "$3,991.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Jan Cole", + "gender": "female", + "company": "Newcube", + "email": "jancole@newcube.com", + "phone": "+1 (864) 545-3072", + "address": { + "street": 451, + "city": "Cavalero", + "state": "Montana", + "zip": 5785 + }, + "about": "Pariatur tempor ipsum commodo nostrud ut commodo nostrud ut exercitation dolor tempor est aliqua. Velit occaecat aliqua amet incididunt sint anim. Tempor nulla exercitation irure veniam anim Lorem nulla. Mollit ad eu elit veniam irure deserunt sit consequat. In aliqua dolore consectetur est commodo eiusmod et duis. Amet est pariatur pariatur Lorem culpa velit excepteur adipisicing consectetur non amet dolor. Irure id ipsum consequat occaecat eu reprehenderit.\r\n", + "registered": "1998-06-13T19:59:00+05:00", + "friends": [ + { + "id": 0, + "name": "Jeanette Wolf" + }, + { + "id": 1, + "name": "Kane Holmes" + }, + { + "id": 2, + "name": "Sampson Stout" + } + ] + }, + { + "id": 295, + "guid": "d387db41-c09e-4209-ae8b-4458b986faec", + "isActive": false, + "balance": "$2,418.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Byrd Sears", + "gender": "male", + "company": "Datagen", + "email": "byrdsears@datagen.com", + "phone": "+1 (942) 469-2156", + "address": { + "street": 745, + "city": "Turpin", + "state": "Minnesota", + "zip": 6381 + }, + "about": "Duis dolor veniam sunt exercitation minim occaecat. Deserunt laborum exercitation fugiat Lorem irure ea sint do laborum non veniam quis ad. Aliqua dolore commodo labore duis nulla esse ea et laboris ipsum excepteur nisi qui. Nisi est exercitation commodo ut elit. Exercitation anim magna adipisicing ea amet. Lorem deserunt veniam est duis cupidatat mollit ex.\r\n", + "registered": "1995-05-06T20:34:50+05:00", + "friends": [ + { + "id": 0, + "name": "Janell Justice" + }, + { + "id": 1, + "name": "Donaldson Roberson" + }, + { + "id": 2, + "name": "Maricela Jordan" + } + ] + }, + { + "id": 296, + "guid": "9258bd4a-0129-4c8f-891c-8c3ea8c4be1d", + "isActive": false, + "balance": "$2,385.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Zelma Santos", + "gender": "female", + "company": "Futurize", + "email": "zelmasantos@futurize.com", + "phone": "+1 (986) 498-2815", + "address": { + "street": 259, + "city": "Klagetoh", + "state": "Oklahoma", + "zip": 5182 + }, + "about": "Ad eiusmod do excepteur sit mollit laborum adipisicing non. Laborum adipisicing consectetur mollit tempor consectetur aliqua. Ad sint anim sunt reprehenderit laboris exercitation nisi eu anim ad ut labore laboris. Proident in cupidatat commodo incididunt occaecat. Excepteur irure tempor eu quis. Sint exercitation proident exercitation proident consequat sunt deserunt sunt. Labore adipisicing pariatur occaecat mollit dolore id ipsum ex duis aliqua aliqua officia dolore ut.\r\n", + "registered": "1990-01-05T18:48:00+06:00", + "friends": [ + { + "id": 0, + "name": "Elisabeth Caldwell" + }, + { + "id": 1, + "name": "Hodge Wilkins" + }, + { + "id": 2, + "name": "Osborn Osborne" + } + ] + }, + { + "id": 297, + "guid": "c15f74e5-b183-4391-bd44-aace954efe0e", + "isActive": true, + "balance": "$2,717.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Aileen Ferrell", + "gender": "female", + "company": "Orbean", + "email": "aileenferrell@orbean.com", + "phone": "+1 (883) 586-3049", + "address": { + "street": 607, + "city": "Konterra", + "state": "Indiana", + "zip": 2355 + }, + "about": "Nulla exercitation reprehenderit cupidatat eu ipsum pariatur aliquip anim elit velit labore cillum deserunt magna. Nostrud irure sunt dolore irure do. Duis veniam pariatur in magna nulla nisi Lorem cillum occaecat et magna occaecat nulla dolor. Elit dolor eu dolore dolor irure mollit nulla ea. Fugiat minim est ex mollit Lorem sint aliqua est elit est in consequat.\r\n", + "registered": "1998-04-17T11:19:53+05:00", + "friends": [ + { + "id": 0, + "name": "Beulah Mckee" + }, + { + "id": 1, + "name": "Celeste Kaufman" + }, + { + "id": 2, + "name": "Harmon Parker" + } + ] + }, + { + "id": 298, + "guid": "e18ba81e-4942-4162-a865-7db1b8eef4da", + "isActive": false, + "balance": "$3,032.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Calderon Mccray", + "gender": "male", + "company": "Miraclis", + "email": "calderonmccray@miraclis.com", + "phone": "+1 (848) 551-3640", + "address": { + "street": 325, + "city": "Flintville", + "state": "Connecticut", + "zip": 7167 + }, + "about": "Sunt nulla deserunt minim veniam velit fugiat exercitation et ex fugiat duis sint pariatur. Fugiat reprehenderit laborum ex ex mollit. Ipsum pariatur ullamco eiusmod in exercitation deserunt. Labore cillum magna aute irure pariatur cillum proident mollit ullamco in do. Sunt eiusmod officia commodo eu do nisi sint duis eiusmod commodo.\r\n", + "registered": "2011-04-28T10:31:20+05:00", + "friends": [ + { + "id": 0, + "name": "Burch Avila" + }, + { + "id": 1, + "name": "Bush Cooper" + }, + { + "id": 2, + "name": "Logan Silva" + } + ] + }, + { + "id": 299, + "guid": "20dadc7a-d9e7-41cf-95ae-17fbe4ae327e", + "isActive": false, + "balance": "$1,147.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Anita Dotson", + "gender": "female", + "company": "Isologics", + "email": "anitadotson@isologics.com", + "phone": "+1 (952) 562-2933", + "address": { + "street": 361, + "city": "Sharon", + "state": "Nevada", + "zip": 6469 + }, + "about": "Laboris quis aliqua nisi id. Officia mollit proident id cillum velit est nulla esse amet. Adipisicing magna sit amet dolore sit Lorem elit nisi nostrud tempor eiusmod occaecat culpa labore. Eiusmod incididunt adipisicing sunt velit.\r\n", + "registered": "1995-04-27T20:49:13+05:00", + "friends": [ + { + "id": 0, + "name": "Lula Harvey" + }, + { + "id": 1, + "name": "Bernadine Edwards" + }, + { + "id": 2, + "name": "Edna Martin" + } + ] + }, + { + "id": 300, + "guid": "36878a19-5cd5-4125-94d6-27ad3df27238", + "isActive": false, + "balance": "$3,086.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Whitley Olsen", + "gender": "male", + "company": "Cyclonica", + "email": "whitleyolsen@cyclonica.com", + "phone": "+1 (885) 451-2332", + "address": { + "street": 703, + "city": "Rodanthe", + "state": "New Mexico", + "zip": 4925 + }, + "about": "Ullamco Lorem exercitation elit ad. Sit veniam id nisi ut velit enim dolore aliquip in ad amet officia cupidatat eu. Mollit est voluptate ut eiusmod tempor aute velit proident adipisicing esse exercitation. Proident fugiat qui quis est proident proident sit ullamco occaecat. Exercitation non est velit sit cillum amet reprehenderit do eiusmod amet irure consectetur. Eiusmod sit culpa esse nostrud enim ut quis excepteur. Irure ullamco dolore velit excepteur Lorem Lorem.\r\n", + "registered": "2010-09-13T21:53:13+05:00", + "friends": [ + { + "id": 0, + "name": "Reynolds Zimmerman" + }, + { + "id": 1, + "name": "Woodward Paul" + }, + { + "id": 2, + "name": "Deloris Lowe" + } + ] + }, + { + "id": 301, + "guid": "ab3c6e6d-2eb5-4226-9db3-fda8345bf0e1", + "isActive": false, + "balance": "$3,066.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Armstrong Santiago", + "gender": "male", + "company": "Waretel", + "email": "armstrongsantiago@waretel.com", + "phone": "+1 (840) 600-2836", + "address": { + "street": 696, + "city": "Gardners", + "state": "North Dakota", + "zip": 8921 + }, + "about": "Eu id esse reprehenderit Lorem laborum sunt tempor. Et adipisicing ipsum amet eiusmod incididunt incididunt id voluptate enim id. Culpa qui quis irure aliquip duis cillum incididunt do. Labore laborum occaecat nulla pariatur amet sint aliquip incididunt officia nisi qui exercitation quis incididunt. Aliqua sit commodo cupidatat reprehenderit non ullamco duis nisi officia ex. Consequat do anim duis ullamco incididunt labore ut eiusmod dolor sit.\r\n", + "registered": "1994-04-23T21:33:22+05:00", + "friends": [ + { + "id": 0, + "name": "Bender Frank" + }, + { + "id": 1, + "name": "Casey Olson" + }, + { + "id": 2, + "name": "Randi Buckley" + } + ] + }, + { + "id": 302, + "guid": "6a12e957-780b-4a34-83e8-fe214d322f68", + "isActive": false, + "balance": "$3,268.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Strickland Shepard", + "gender": "male", + "company": "Maxemia", + "email": "stricklandshepard@maxemia.com", + "phone": "+1 (994) 541-2785", + "address": { + "street": 512, + "city": "Takilma", + "state": "Alaska", + "zip": 1734 + }, + "about": "Sint quis excepteur consequat sunt reprehenderit dolor et ad. Aliqua aute aliqua duis sunt eu culpa. Labore velit sit et nulla ut aute ex exercitation exercitation cillum do pariatur. Est officia cupidatat culpa incididunt ut reprehenderit labore culpa amet mollit do.\r\n", + "registered": "1996-08-02T08:03:13+05:00", + "friends": [ + { + "id": 0, + "name": "Cunningham Summers" + }, + { + "id": 1, + "name": "Millicent Benjamin" + }, + { + "id": 2, + "name": "Laura Rice" + } + ] + }, + { + "id": 303, + "guid": "8da54354-0535-4bbf-8a96-58d6309bfcc7", + "isActive": false, + "balance": "$1,787.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Lowery Mercer", + "gender": "male", + "company": "Grainspot", + "email": "lowerymercer@grainspot.com", + "phone": "+1 (876) 533-3108", + "address": { + "street": 658, + "city": "Chamberino", + "state": "Texas", + "zip": 2644 + }, + "about": "Ut amet Lorem in ad. Consequat excepteur consequat amet id sit aliqua esse qui. Consectetur nisi incididunt Lorem eu ad nulla consequat irure mollit et ullamco ex cupidatat.\r\n", + "registered": "2003-02-22T04:38:52+06:00", + "friends": [ + { + "id": 0, + "name": "Roach Nicholson" + }, + { + "id": 1, + "name": "Sophia Morin" + }, + { + "id": 2, + "name": "Stanton Oneal" + } + ] + }, + { + "id": 304, + "guid": "1252f9ed-559b-4d37-ada7-cf42f227bf15", + "isActive": true, + "balance": "$2,976.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Nicole Livingston", + "gender": "female", + "company": "Tasmania", + "email": "nicolelivingston@tasmania.com", + "phone": "+1 (899) 473-2594", + "address": { + "street": 305, + "city": "Fontanelle", + "state": "Florida", + "zip": 8521 + }, + "about": "Cillum labore ipsum esse ad irure aute pariatur nisi amet eiusmod minim. Tempor deserunt sunt enim cupidatat mollit Lorem consequat veniam Lorem fugiat esse Lorem. Officia commodo mollit duis Lorem.\r\n", + "registered": "2000-10-13T17:22:44+05:00", + "friends": [ + { + "id": 0, + "name": "Freeman Emerson" + }, + { + "id": 1, + "name": "Jacklyn Giles" + }, + { + "id": 2, + "name": "Coleen Harper" + } + ] + }, + { + "id": 305, + "guid": "7e02c617-decb-4568-83a3-c45b866a0e9a", + "isActive": false, + "balance": "$3,773.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Bailey Hensley", + "gender": "male", + "company": "Glasstep", + "email": "baileyhensley@glasstep.com", + "phone": "+1 (950) 502-2295", + "address": { + "street": 409, + "city": "Motley", + "state": "Missouri", + "zip": 667 + }, + "about": "Duis id laboris nisi ea irure culpa. Excepteur commodo adipisicing deserunt incididunt laborum cillum irure aliquip est eiusmod enim nostrud elit qui. Ex dolore sunt commodo sunt excepteur commodo sit sint amet consequat et aliquip quis. Aliquip deserunt eiusmod minim eiusmod dolore excepteur est ea consectetur do. Aute veniam sit eiusmod cupidatat pariatur qui dolore adipisicing id nisi est.\r\n", + "registered": "1994-10-10T21:13:58+05:00", + "friends": [ + { + "id": 0, + "name": "Rachel Compton" + }, + { + "id": 1, + "name": "Lorie Gilbert" + }, + { + "id": 2, + "name": "Moss Calderon" + } + ] + }, + { + "id": 306, + "guid": "81fc2d66-9da8-433c-90d5-45a2b94a2859", + "isActive": false, + "balance": "$2,296.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Meyer Fuentes", + "gender": "male", + "company": "Flotonic", + "email": "meyerfuentes@flotonic.com", + "phone": "+1 (966) 589-2859", + "address": { + "street": 393, + "city": "Mayfair", + "state": "Tennessee", + "zip": 9950 + }, + "about": "Proident pariatur dolore cupidatat id ut tempor exercitation duis nisi. Elit laborum amet amet tempor voluptate duis irure nisi ad dolore adipisicing. Amet cupidatat consectetur duis officia excepteur in. Duis culpa velit quis deserunt elit tempor culpa.\r\n", + "registered": "2013-12-17T06:53:54+06:00", + "friends": [ + { + "id": 0, + "name": "Bernard Mcdonald" + }, + { + "id": 1, + "name": "Owen Castillo" + }, + { + "id": 2, + "name": "Jacobs Conrad" + } + ] + }, + { + "id": 307, + "guid": "0cd908dc-dbff-427c-9170-4cf36f8f8105", + "isActive": false, + "balance": "$3,328.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Lillie Goodwin", + "gender": "female", + "company": "Exposa", + "email": "lilliegoodwin@exposa.com", + "phone": "+1 (989) 514-2531", + "address": { + "street": 561, + "city": "Irwin", + "state": "South Carolina", + "zip": 1287 + }, + "about": "Sunt sit dolore aliqua aliquip aliquip nulla consequat qui eiusmod eu. Voluptate elit ad do aliquip et excepteur aliqua ut reprehenderit in anim amet nulla. Irure voluptate officia aute amet non non ex duis do aute. Proident veniam cillum est magna esse culpa cupidatat nisi laboris laborum pariatur dolore anim ea. Laborum ex et incididunt proident minim aliqua reprehenderit. Adipisicing proident magna proident dolore aute Lorem enim dolor enim ut officia do. Voluptate excepteur enim commodo consequat ea tempor incididunt aliqua laboris.\r\n", + "registered": "2010-08-20T02:07:16+05:00", + "friends": [ + { + "id": 0, + "name": "Powers Shaffer" + }, + { + "id": 1, + "name": "Patrice Wise" + }, + { + "id": 2, + "name": "David Dean" + } + ] + }, + { + "id": 308, + "guid": "e5f65913-6a63-4ce6-afdc-c0b294f289f8", + "isActive": false, + "balance": "$2,956.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Estelle Stephenson", + "gender": "female", + "company": "Automon", + "email": "estellestephenson@automon.com", + "phone": "+1 (847) 497-2868", + "address": { + "street": 571, + "city": "Longoria", + "state": "Louisiana", + "zip": 1005 + }, + "about": "Lorem est irure cupidatat sint nulla eu adipisicing deserunt Lorem officia. Anim nostrud amet mollit occaecat sunt incididunt. Qui duis sint Lorem sit eu mollit ad ea. Veniam id do Lorem do. Qui fugiat ullamco laborum mollit laboris non aliqua anim adipisicing ut nisi sit sint tempor. Non aliqua aliqua esse eiusmod amet ut nulla minim in anim elit dolor sunt.\r\n", + "registered": "2004-02-17T10:23:50+06:00", + "friends": [ + { + "id": 0, + "name": "Mitzi Greene" + }, + { + "id": 1, + "name": "Charmaine Warren" + }, + { + "id": 2, + "name": "Norris Graves" + } + ] + }, + { + "id": 309, + "guid": "0f3c91fe-421e-49e2-a14f-117a1f239180", + "isActive": false, + "balance": "$1,164.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Kim Good", + "gender": "male", + "company": "Zyple", + "email": "kimgood@zyple.com", + "phone": "+1 (986) 411-2791", + "address": { + "street": 660, + "city": "Murillo", + "state": "Idaho", + "zip": 1255 + }, + "about": "Culpa pariatur anim cillum nisi nostrud quis consectetur consectetur. Ut reprehenderit exercitation quis ea minim eu duis duis. Eiusmod voluptate incididunt veniam elit occaecat officia ullamco enim excepteur cupidatat. Exercitation sit consequat irure ex sunt. Eu ut pariatur sint consectetur fugiat incididunt voluptate Lorem irure dolore sunt deserunt et. Enim exercitation pariatur reprehenderit deserunt.\r\n", + "registered": "1988-11-08T07:57:20+06:00", + "friends": [ + { + "id": 0, + "name": "Bianca Mckay" + }, + { + "id": 1, + "name": "Ross Finley" + }, + { + "id": 2, + "name": "Lana Harrison" + } + ] + }, + { + "id": 310, + "guid": "b10471fc-1b99-4377-8a40-09406e2955b4", + "isActive": true, + "balance": "$2,674.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Tommie Fisher", + "gender": "female", + "company": "Zuvy", + "email": "tommiefisher@zuvy.com", + "phone": "+1 (892) 426-2828", + "address": { + "street": 808, + "city": "Sehili", + "state": "Virginia", + "zip": 3557 + }, + "about": "Amet nulla nulla minim nulla sit nostrud labore aliquip mollit eiusmod voluptate proident est commodo. Adipisicing consectetur et consectetur aliqua nostrud aliquip esse voluptate ad elit ipsum. Pariatur amet cillum sint nulla duis. Ipsum adipisicing pariatur voluptate occaecat eiusmod fugiat irure. Cupidatat voluptate nulla ipsum ut. Sunt anim do veniam cillum.\r\n", + "registered": "2009-10-14T19:22:03+05:00", + "friends": [ + { + "id": 0, + "name": "Lamb Cole" + }, + { + "id": 1, + "name": "Hess Murphy" + }, + { + "id": 2, + "name": "Clarissa Wood" + } + ] + }, + { + "id": 311, + "guid": "1ade711f-6356-4f2a-b725-2d5f88beb74b", + "isActive": true, + "balance": "$3,459.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Leila Sampson", + "gender": "female", + "company": "Intrawear", + "email": "leilasampson@intrawear.com", + "phone": "+1 (940) 407-3831", + "address": { + "street": 705, + "city": "Boonville", + "state": "Delaware", + "zip": 9360 + }, + "about": "Cupidatat ullamco est adipisicing ex in irure commodo velit Lorem elit. Irure velit amet ea quis labore fugiat anim nisi. Sint est eiusmod ut quis. Exercitation magna amet exercitation sit mollit commodo ea aliquip nostrud. Sit anim culpa excepteur laboris occaecat sit tempor anim minim anim officia sit.\r\n", + "registered": "2008-01-15T11:30:12+06:00", + "friends": [ + { + "id": 0, + "name": "Hurst Larsen" + }, + { + "id": 1, + "name": "Livingston Colon" + }, + { + "id": 2, + "name": "Kaufman Cannon" + } + ] + }, + { + "id": 312, + "guid": "a8e33185-d040-4ae1-8514-c7e7a82711a6", + "isActive": false, + "balance": "$3,670.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Macdonald Moreno", + "gender": "male", + "company": "Tropoli", + "email": "macdonaldmoreno@tropoli.com", + "phone": "+1 (958) 529-2705", + "address": { + "street": 723, + "city": "Haena", + "state": "Rhode Island", + "zip": 1375 + }, + "about": "Laborum sint ex do reprehenderit nulla est commodo nulla minim dolor laboris. Aliquip sit excepteur minim qui eiusmod ex incididunt eiusmod. Voluptate nisi ut pariatur officia cupidatat consectetur labore enim laboris fugiat. Mollit qui velit est cillum minim commodo culpa consectetur exercitation occaecat.\r\n", + "registered": "1999-07-22T10:32:54+05:00", + "friends": [ + { + "id": 0, + "name": "Gregory Maxwell" + }, + { + "id": 1, + "name": "Morgan Holt" + }, + { + "id": 2, + "name": "Woodard Woodard" + } + ] + }, + { + "id": 313, + "guid": "155c2474-c111-40f6-a722-3cc8dd4ebc76", + "isActive": false, + "balance": "$1,722.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Olson Cardenas", + "gender": "male", + "company": "Stelaecor", + "email": "olsoncardenas@stelaecor.com", + "phone": "+1 (801) 468-3005", + "address": { + "street": 127, + "city": "Bourg", + "state": "New York", + "zip": 8273 + }, + "about": "Labore velit magna aliqua aliquip mollit exercitation eiusmod veniam officia commodo commodo velit sit. Non deserunt reprehenderit cillum laboris do non do deserunt. Adipisicing minim reprehenderit duis adipisicing magna elit. Lorem laboris ex cupidatat sit.\r\n", + "registered": "2000-05-27T07:45:03+05:00", + "friends": [ + { + "id": 0, + "name": "Holloway Bush" + }, + { + "id": 1, + "name": "Wells Fowler" + }, + { + "id": 2, + "name": "Howell Parrish" + } + ] + }, + { + "id": 314, + "guid": "f1848e2a-b2de-4764-ad42-1de3ccd55d9f", + "isActive": false, + "balance": "$3,121.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Jarvis Shepherd", + "gender": "male", + "company": "Eclipto", + "email": "jarvisshepherd@eclipto.com", + "phone": "+1 (993) 465-2043", + "address": { + "street": 581, + "city": "Steinhatchee", + "state": "Hawaii", + "zip": 2097 + }, + "about": "Tempor cillum quis sunt ea incididunt. Voluptate irure deserunt sunt elit non. Enim quis veniam sunt do ut dolor officia. Et fugiat sint mollit et aliquip. Anim voluptate sint et eiusmod.\r\n", + "registered": "2013-10-12T14:37:29+05:00", + "friends": [ + { + "id": 0, + "name": "Jaclyn Allen" + }, + { + "id": 1, + "name": "Fay Buckner" + }, + { + "id": 2, + "name": "Carole Curtis" + } + ] + }, + { + "id": 315, + "guid": "b7c4ecf3-faa3-4fe7-a099-79a4cb32d038", + "isActive": true, + "balance": "$3,988.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Chrystal Riley", + "gender": "female", + "company": "Buzzmaker", + "email": "chrystalriley@buzzmaker.com", + "phone": "+1 (897) 523-3459", + "address": { + "street": 880, + "city": "Lafferty", + "state": "Iowa", + "zip": 8588 + }, + "about": "Tempor ad aute eu consequat sit aliqua ad labore mollit aliquip velit nisi commodo. Irure do ut anim laborum deserunt nostrud. Laboris ullamco ut qui Lorem aliqua quis cupidatat nostrud. Nostrud in aliqua eu laboris esse quis cupidatat fugiat ullamco duis veniam proident non. Sunt ad voluptate laborum voluptate sit duis nulla quis Lorem. Eiusmod amet minim anim in qui tempor qui voluptate non magna ad deserunt ex. Nisi id minim culpa ad magna ea minim ea cupidatat qui sint.\r\n", + "registered": "2007-10-04T15:57:25+05:00", + "friends": [ + { + "id": 0, + "name": "Hazel Mccullough" + }, + { + "id": 1, + "name": "Hendrix Gilmore" + }, + { + "id": 2, + "name": "Luz Logan" + } + ] + }, + { + "id": 316, + "guid": "58c016bb-f10a-40a9-b8de-97c2932b049d", + "isActive": false, + "balance": "$2,966.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Katie Salas", + "gender": "female", + "company": "Jamnation", + "email": "katiesalas@jamnation.com", + "phone": "+1 (849) 596-3673", + "address": { + "street": 309, + "city": "Canoochee", + "state": "Wisconsin", + "zip": 1685 + }, + "about": "Deserunt minim laborum esse non mollit eiusmod elit deserunt esse Lorem. Cillum laboris dolore voluptate est laboris reprehenderit ex. Ad mollit cupidatat aute tempor minim pariatur et cupidatat. Ad deserunt magna deserunt adipisicing. Lorem commodo anim officia deserunt ipsum excepteur qui adipisicing cillum aliqua dolore voluptate cillum. Ipsum sunt ex non qui esse reprehenderit pariatur aliquip laborum consequat. Minim aute ipsum ex ex est in esse ipsum.\r\n", + "registered": "2009-08-05T12:21:44+05:00", + "friends": [ + { + "id": 0, + "name": "Charity Mcguire" + }, + { + "id": 1, + "name": "Cochran Bond" + }, + { + "id": 2, + "name": "Banks Peck" + } + ] + }, + { + "id": 317, + "guid": "31ce61a7-e961-4ed7-bf43-0230fb40976f", + "isActive": false, + "balance": "$1,884.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Phyllis Joyner", + "gender": "female", + "company": "Telpod", + "email": "phyllisjoyner@telpod.com", + "phone": "+1 (996) 598-3102", + "address": { + "street": 573, + "city": "Lewis", + "state": "Ohio", + "zip": 3961 + }, + "about": "Commodo deserunt Lorem nostrud veniam occaecat aliqua magna. Elit aliqua aliquip ullamco excepteur mollit aute proident do deserunt cillum ipsum in. Officia amet incididunt fugiat sit ea nisi officia laborum esse anim veniam. Cupidatat ea sunt aliqua enim. Do eu amet reprehenderit adipisicing excepteur esse. Sunt occaecat eiusmod aute in sint laborum pariatur.\r\n", + "registered": "1999-01-13T11:51:18+06:00", + "friends": [ + { + "id": 0, + "name": "Rhoda Serrano" + }, + { + "id": 1, + "name": "Mccullough Swanson" + }, + { + "id": 2, + "name": "Tami Jensen" + } + ] + }, + { + "id": 318, + "guid": "fe4b5e9c-4131-4279-afa8-5886a008f4e7", + "isActive": true, + "balance": "$2,007.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Mary Boone", + "gender": "female", + "company": "Qot", + "email": "maryboone@qot.com", + "phone": "+1 (980) 457-3110", + "address": { + "street": 564, + "city": "Brownsville", + "state": "Nebraska", + "zip": 9685 + }, + "about": "Minim proident elit culpa culpa laborum fugiat id id culpa adipisicing occaecat laboris elit. Officia laborum cupidatat pariatur incididunt deserunt. Nostrud fugiat nisi officia deserunt nostrud voluptate ut ad. Officia cupidatat sint ipsum enim ad aliquip culpa incididunt adipisicing duis fugiat. Sit ea sint sit aliquip veniam irure. Aute adipisicing consequat nisi nulla Lorem quis exercitation sit nostrud consequat cupidatat tempor. Cillum sunt ullamco non enim.\r\n", + "registered": "2010-08-08T17:32:02+05:00", + "friends": [ + { + "id": 0, + "name": "Berg Wilcox" + }, + { + "id": 1, + "name": "Terri Nash" + }, + { + "id": 2, + "name": "Butler Jenkins" + } + ] + }, + { + "id": 319, + "guid": "2a59a595-cf5e-4f84-bd7e-dbf10017cb8e", + "isActive": false, + "balance": "$2,997.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Barbra Fitzpatrick", + "gender": "female", + "company": "Zipak", + "email": "barbrafitzpatrick@zipak.com", + "phone": "+1 (811) 410-3683", + "address": { + "street": 798, + "city": "Axis", + "state": "Maryland", + "zip": 5666 + }, + "about": "Pariatur occaecat consequat commodo aliquip anim. Elit officia culpa nulla excepteur. Labore et elit voluptate mollit. Nulla enim dolore laboris esse nisi.\r\n", + "registered": "1998-12-31T02:59:52+06:00", + "friends": [ + { + "id": 0, + "name": "Kinney Salazar" + }, + { + "id": 1, + "name": "Riggs Alexander" + }, + { + "id": 2, + "name": "Sandra Simon" + } + ] + }, + { + "id": 320, + "guid": "dd356c21-39c0-4679-8112-467044b4b92b", + "isActive": true, + "balance": "$2,097.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Delaney Alford", + "gender": "male", + "company": "Chillium", + "email": "delaneyalford@chillium.com", + "phone": "+1 (962) 432-2687", + "address": { + "street": 521, + "city": "Lisco", + "state": "New Hampshire", + "zip": 4009 + }, + "about": "Laborum adipisicing labore voluptate culpa adipisicing pariatur nulla minim. Ad minim velit non ea ullamco nisi ut consectetur officia ut non voluptate. Deserunt deserunt minim veniam ipsum mollit sit.\r\n", + "registered": "1992-02-22T11:46:32+06:00", + "friends": [ + { + "id": 0, + "name": "Herminia Lewis" + }, + { + "id": 1, + "name": "Zamora Dennis" + }, + { + "id": 2, + "name": "May Hendrix" + } + ] + }, + { + "id": 321, + "guid": "2d9ac6d1-f64d-4f47-bae6-009d9180c018", + "isActive": false, + "balance": "$1,518.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Reilly Foreman", + "gender": "male", + "company": "Repetwire", + "email": "reillyforeman@repetwire.com", + "phone": "+1 (860) 518-2356", + "address": { + "street": 115, + "city": "Freelandville", + "state": "New Jersey", + "zip": 4453 + }, + "about": "Aute aute ex laboris ea duis. Fugiat sint sit amet laborum proident ut proident Lorem amet deserunt veniam reprehenderit. Eu aute commodo cupidatat deserunt consectetur quis qui. Ut voluptate anim nisi minim anim sunt commodo nisi irure. Incididunt deserunt minim et cupidatat do voluptate pariatur qui.\r\n", + "registered": "2000-04-11T00:41:59+05:00", + "friends": [ + { + "id": 0, + "name": "Hunt Pope" + }, + { + "id": 1, + "name": "Norman Dudley" + }, + { + "id": 2, + "name": "Beverly Cabrera" + } + ] + }, + { + "id": 322, + "guid": "4f2ceb04-49d8-441d-940b-35341f4cbb5b", + "isActive": true, + "balance": "$1,984.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Madeline Branch", + "gender": "female", + "company": "Emtrac", + "email": "madelinebranch@emtrac.com", + "phone": "+1 (926) 598-3985", + "address": { + "street": 940, + "city": "Clinton", + "state": "Alabama", + "zip": 279 + }, + "about": "Incididunt enim cupidatat proident non magna ea incididunt est tempor velit officia. Non enim non ullamco esse elit. Amet cillum nulla non sint.\r\n", + "registered": "1992-05-14T07:37:02+05:00", + "friends": [ + { + "id": 0, + "name": "Stein Duncan" + }, + { + "id": 1, + "name": "Keri Witt" + }, + { + "id": 2, + "name": "Tabitha Suarez" + } + ] + }, + { + "id": 323, + "guid": "3ce856a7-d78a-4e8b-ae26-deb7af6600eb", + "isActive": true, + "balance": "$3,789.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Adeline Burt", + "gender": "female", + "company": "Comtrail", + "email": "adelineburt@comtrail.com", + "phone": "+1 (817) 434-3848", + "address": { + "street": 255, + "city": "Woodlake", + "state": "South Dakota", + "zip": 2669 + }, + "about": "Quis reprehenderit proident aliqua pariatur eu do aliqua consequat sunt consectetur incididunt ex velit. Duis sit tempor esse Lorem sit sint. Nulla ullamco ut excepteur mollit excepteur sit adipisicing cupidatat velit do qui sint. Reprehenderit eu Lorem pariatur ipsum ipsum non excepteur.\r\n", + "registered": "2002-03-13T15:10:30+05:00", + "friends": [ + { + "id": 0, + "name": "Schultz Morales" + }, + { + "id": 1, + "name": "Brandi Head" + }, + { + "id": 2, + "name": "Cantrell Medina" + } + ] + }, + { + "id": 324, + "guid": "4f195134-eb98-41e3-b2f1-61bb159b4856", + "isActive": true, + "balance": "$3,739.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Tammie Battle", + "gender": "female", + "company": "Zilidium", + "email": "tammiebattle@zilidium.com", + "phone": "+1 (969) 555-2332", + "address": { + "street": 392, + "city": "Swartzville", + "state": "Illinois", + "zip": 6940 + }, + "about": "Ea duis sint incididunt deserunt laborum elit do occaecat cillum ex nostrud officia. Anim et sit labore amet commodo. Amet id ut do sunt pariatur eiusmod elit proident anim proident. Exercitation proident duis sunt magna labore aute veniam labore dolore sit labore labore mollit. Consequat adipisicing mollit cupidatat nulla magna dolore tempor consequat do fugiat.\r\n", + "registered": "2001-03-17T14:28:39+05:00", + "friends": [ + { + "id": 0, + "name": "Knight Cross" + }, + { + "id": 1, + "name": "Burke Cooley" + }, + { + "id": 2, + "name": "Blackburn Richmond" + } + ] + }, + { + "id": 325, + "guid": "5677e95b-b6fb-4aee-b65f-35ba9f4c501a", + "isActive": true, + "balance": "$2,425.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Stella Rodriguez", + "gender": "female", + "company": "Autograte", + "email": "stellarodriguez@autograte.com", + "phone": "+1 (967) 431-3778", + "address": { + "street": 679, + "city": "Leyner", + "state": "Arizona", + "zip": 2240 + }, + "about": "Eu aliqua reprehenderit ipsum ea elit. Excepteur ex pariatur et eiusmod id officia aliqua consequat. Aliqua ea quis ea labore sit ad exercitation nisi. Do eu labore id velit laboris amet aute culpa amet velit nostrud aliquip. Nostrud quis aliqua enim officia nostrud aute. Incididunt esse qui consectetur ex sunt et ullamco pariatur culpa id reprehenderit consequat sit.\r\n", + "registered": "1994-05-18T21:19:23+05:00", + "friends": [ + { + "id": 0, + "name": "Holcomb Vaughan" + }, + { + "id": 1, + "name": "Whitaker Strickland" + }, + { + "id": 2, + "name": "Marisol Walsh" + } + ] + }, + { + "id": 326, + "guid": "2002cdfd-a56f-443f-b1e7-718c1800175c", + "isActive": false, + "balance": "$3,949.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Aurora Doyle", + "gender": "female", + "company": "Kinetica", + "email": "auroradoyle@kinetica.com", + "phone": "+1 (872) 430-3790", + "address": { + "street": 678, + "city": "Englevale", + "state": "Utah", + "zip": 9209 + }, + "about": "Sint consequat eu consequat ipsum elit laboris tempor minim laborum nostrud. Voluptate deserunt laborum sint eu qui laborum nulla commodo. Cupidatat pariatur aliquip sint et magna ut nostrud in est id quis non adipisicing id.\r\n", + "registered": "2008-09-20T08:42:42+05:00", + "friends": [ + { + "id": 0, + "name": "Isabel Lopez" + }, + { + "id": 1, + "name": "Richmond Hill" + }, + { + "id": 2, + "name": "Melba Camacho" + } + ] + }, + { + "id": 327, + "guid": "ae6cf862-fa9d-42d2-8fb1-b31efa1712ec", + "isActive": true, + "balance": "$3,259.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Huff Meyers", + "gender": "male", + "company": "Snorus", + "email": "huffmeyers@snorus.com", + "phone": "+1 (972) 529-3905", + "address": { + "street": 402, + "city": "Fidelis", + "state": "Mississippi", + "zip": 3242 + }, + "about": "Pariatur commodo cillum eu labore est amet. Veniam minim mollit officia tempor aliqua mollit sit eiusmod. Id commodo adipisicing aliquip commodo enim pariatur fugiat Lorem et aliqua sit nostrud deserunt. Non ipsum deserunt dolore ad minim Lorem amet eu ad elit tempor duis. Occaecat proident aute eu mollit cupidatat eiusmod ea.\r\n", + "registered": "1990-08-26T14:52:19+05:00", + "friends": [ + { + "id": 0, + "name": "Price Collier" + }, + { + "id": 1, + "name": "Murray Forbes" + }, + { + "id": 2, + "name": "Hester Singleton" + } + ] + }, + { + "id": 328, + "guid": "b69f52da-5e1d-4ce2-b2f9-a808bc295b5e", + "isActive": false, + "balance": "$3,812.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Maddox Cohen", + "gender": "male", + "company": "Mitroc", + "email": "maddoxcohen@mitroc.com", + "phone": "+1 (997) 420-2871", + "address": { + "street": 681, + "city": "Gouglersville", + "state": "Pennsylvania", + "zip": 1419 + }, + "about": "Eu ullamco incididunt aliqua magna quis sit ea irure. Ipsum ad do consequat duis culpa enim. Velit nostrud enim fugiat non. Officia et labore esse consequat tempor incididunt cupidatat. Sit officia amet irure aliquip. Ad consequat est proident irure est tempor anim incididunt fugiat dolor.\r\n", + "registered": "2012-02-15T07:34:06+06:00", + "friends": [ + { + "id": 0, + "name": "Mcknight Underwood" + }, + { + "id": 1, + "name": "Leticia Simpson" + }, + { + "id": 2, + "name": "Virginia Rosales" + } + ] + }, + { + "id": 329, + "guid": "37d3819a-6a3c-45ba-8798-0cc6861bc390", + "isActive": true, + "balance": "$3,346.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Anne Glover", + "gender": "female", + "company": "Bullzone", + "email": "anneglover@bullzone.com", + "phone": "+1 (950) 488-2211", + "address": { + "street": 789, + "city": "Moquino", + "state": "Kentucky", + "zip": 1226 + }, + "about": "Lorem fugiat pariatur aliquip proident pariatur irure. Adipisicing nulla nulla ex aute est. Aliqua in officia veniam nulla sint exercitation veniam. Sunt esse aliquip incididunt nisi consectetur commodo sit.\r\n", + "registered": "1992-03-14T03:37:44+05:00", + "friends": [ + { + "id": 0, + "name": "Ruiz Mills" + }, + { + "id": 1, + "name": "Christy Franklin" + }, + { + "id": 2, + "name": "Allen Foley" + } + ] + }, + { + "id": 330, + "guid": "e97fb3ab-454e-4e14-a575-242115e0a91e", + "isActive": false, + "balance": "$1,858.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Lily Little", + "gender": "female", + "company": "Temorak", + "email": "lilylittle@temorak.com", + "phone": "+1 (956) 546-3237", + "address": { + "street": 676, + "city": "Dale", + "state": "California", + "zip": 8337 + }, + "about": "Consequat id officia excepteur amet aute Lorem non aliquip enim tempor mollit mollit. Aliquip ad ullamco labore labore non ex. Lorem adipisicing veniam cillum ex nostrud incididunt qui. Nulla enim adipisicing labore dolor dolor sunt ut aute irure aliqua.\r\n", + "registered": "1996-07-12T01:06:06+05:00", + "friends": [ + { + "id": 0, + "name": "Cassandra Adams" + }, + { + "id": 1, + "name": "Jodi Ortega" + }, + { + "id": 2, + "name": "Greene Sutton" + } + ] + }, + { + "id": 331, + "guid": "10f0ca92-c0b1-4556-b144-3135b4d4f266", + "isActive": false, + "balance": "$2,652.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Chan Chaney", + "gender": "male", + "company": "Comtour", + "email": "chanchaney@comtour.com", + "phone": "+1 (840) 503-2829", + "address": { + "street": 357, + "city": "Coral", + "state": "Oregon", + "zip": 6076 + }, + "about": "Labore ex pariatur aute veniam laborum ex sint esse laborum et ad cillum veniam mollit. Do deserunt velit ipsum est occaecat pariatur ipsum fugiat ea sit. Ullamco magna exercitation voluptate amet labore aliqua labore fugiat incididunt. Irure exercitation amet esse aliqua nulla cupidatat duis culpa proident sint exercitation cillum adipisicing elit. Voluptate occaecat labore eu nulla irure exercitation. Elit nostrud occaecat incididunt labore excepteur consectetur deserunt Lorem. Esse deserunt mollit nulla reprehenderit aliqua officia tempor voluptate amet occaecat esse proident anim sint.\r\n", + "registered": "1995-11-13T04:23:38+06:00", + "friends": [ + { + "id": 0, + "name": "Estes Sheppard" + }, + { + "id": 1, + "name": "Barron Marshall" + }, + { + "id": 2, + "name": "Jayne Howell" + } + ] + }, + { + "id": 332, + "guid": "c8177515-76e0-4836-b0e2-12d1f9c5dcbb", + "isActive": true, + "balance": "$3,646.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Gaines Mcconnell", + "gender": "male", + "company": "Kongle", + "email": "gainesmcconnell@kongle.com", + "phone": "+1 (984) 590-3388", + "address": { + "street": 561, + "city": "Bainbridge", + "state": "Kansas", + "zip": 981 + }, + "about": "Veniam voluptate Lorem aute consectetur minim. Culpa tempor adipisicing dolore minim laboris pariatur aliqua amet nostrud. Consectetur esse eiusmod fugiat sint et velit ullamco eu laborum aliquip ad. Nisi cupidatat proident amet Lorem eiusmod cupidatat eiusmod elit eiusmod ex eiusmod. Dolore labore aliquip aliquip magna cillum commodo officia aute voluptate magna mollit. Velit eiusmod dolor proident deserunt in fugiat enim.\r\n", + "registered": "2006-09-29T04:39:48+05:00", + "friends": [ + { + "id": 0, + "name": "Josefa Fletcher" + }, + { + "id": 1, + "name": "Marie Estes" + }, + { + "id": 2, + "name": "Pope Wade" + } + ] + }, + { + "id": 333, + "guid": "696b0b53-c08e-4b66-8b6f-f1c0c704b8cd", + "isActive": true, + "balance": "$2,374.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Albert Mathews", + "gender": "male", + "company": "Essensia", + "email": "albertmathews@essensia.com", + "phone": "+1 (939) 485-2459", + "address": { + "street": 710, + "city": "Blende", + "state": "Massachusetts", + "zip": 657 + }, + "about": "Consectetur exercitation ipsum nulla deserunt elit ullamco. Voluptate ut officia dolor do reprehenderit sint ullamco. Ea incididunt eiusmod Lorem labore et.\r\n", + "registered": "1989-06-08T12:02:37+05:00", + "friends": [ + { + "id": 0, + "name": "Lynch Nelson" + }, + { + "id": 1, + "name": "Pamela Mcleod" + }, + { + "id": 2, + "name": "Guthrie Rodgers" + } + ] + }, + { + "id": 334, + "guid": "6002ce28-7c05-4aa2-b1c1-fe08ecb70278", + "isActive": true, + "balance": "$3,361.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Schmidt Haney", + "gender": "male", + "company": "Remotion", + "email": "schmidthaney@remotion.com", + "phone": "+1 (860) 587-3342", + "address": { + "street": 412, + "city": "Freeburn", + "state": "Georgia", + "zip": 6232 + }, + "about": "Magna voluptate duis laborum duis pariatur ad tempor tempor nostrud qui commodo. Minim Lorem sunt sint commodo excepteur adipisicing sunt anim. Aliquip cillum dolor consectetur non ex sunt Lorem adipisicing proident tempor deserunt anim. Duis minim ullamco irure anim nulla et in quis officia reprehenderit. Magna id eiusmod quis eu veniam commodo incididunt. Consectetur ea nulla ea pariatur adipisicing sint culpa. Aliqua aliqua duis pariatur mollit non labore est pariatur.\r\n", + "registered": "2013-09-24T09:23:14+05:00", + "friends": [ + { + "id": 0, + "name": "Tracy Patel" + }, + { + "id": 1, + "name": "Conrad Cervantes" + }, + { + "id": 2, + "name": "Craig Carpenter" + } + ] + }, + { + "id": 335, + "guid": "858c9fea-638e-4be0-8bda-3079a055b59c", + "isActive": true, + "balance": "$1,724.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Nannie Guerrero", + "gender": "female", + "company": "Rodeocean", + "email": "nannieguerrero@rodeocean.com", + "phone": "+1 (945) 454-3638", + "address": { + "street": 761, + "city": "Sandston", + "state": "Washington", + "zip": 315 + }, + "about": "Fugiat ea fugiat esse eu exercitation adipisicing eu tempor et commodo id aliquip ullamco. Cupidatat ea dolor do occaecat fugiat deserunt reprehenderit tempor Lorem dolor elit enim officia. Ad velit cupidatat officia fugiat ea esse proident esse occaecat laborum ex enim. Deserunt nostrud reprehenderit consectetur est excepteur aliqua duis laboris irure eiusmod ad.\r\n", + "registered": "1995-05-31T05:29:47+05:00", + "friends": [ + { + "id": 0, + "name": "Josefina Mcbride" + }, + { + "id": 1, + "name": "Booker Espinoza" + }, + { + "id": 2, + "name": "Lewis Acevedo" + } + ] + }, + { + "id": 336, + "guid": "a6f3e3c5-3613-4e8d-b34e-0bff7dedff90", + "isActive": true, + "balance": "$1,579.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Georgina Owen", + "gender": "female", + "company": "Fangold", + "email": "georginaowen@fangold.com", + "phone": "+1 (809) 492-2813", + "address": { + "street": 162, + "city": "Chestnut", + "state": "Michigan", + "zip": 6875 + }, + "about": "Exercitation laboris tempor incididunt occaecat cillum sit officia in. Nostrud tempor incididunt deserunt dolor cillum laborum cupidatat incididunt exercitation exercitation enim incididunt ea. Dolore officia do proident et aliquip laboris nostrud commodo amet. Ea mollit amet eiusmod consectetur magna exercitation. Laborum id ipsum adipisicing esse ea ipsum. Elit anim culpa laborum occaecat aute est eu non cillum. Cillum do exercitation labore exercitation amet occaecat ad fugiat excepteur Lorem Lorem amet consectetur.\r\n", + "registered": "2003-06-14T23:38:33+05:00", + "friends": [ + { + "id": 0, + "name": "Barnett Diaz" + }, + { + "id": 1, + "name": "Adrian Whitney" + }, + { + "id": 2, + "name": "Camacho Carver" + } + ] + }, + { + "id": 337, + "guid": "6b1a0af2-ce33-4c0f-a15a-afbced229811", + "isActive": false, + "balance": "$2,012.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Saundra Baldwin", + "gender": "female", + "company": "Accidency", + "email": "saundrabaldwin@accidency.com", + "phone": "+1 (873) 463-2971", + "address": { + "street": 345, + "city": "Hiwasse", + "state": "Wyoming", + "zip": 6747 + }, + "about": "Nostrud sunt cillum aliqua laborum ex voluptate nostrud exercitation excepteur fugiat nulla non esse. Commodo ex reprehenderit pariatur voluptate sit nulla laborum aliqua adipisicing. Duis minim tempor magna labore Lorem incididunt aute eu aute magna culpa aliquip. Reprehenderit aliqua duis eiusmod ad enim voluptate nisi. Laborum dolor culpa esse Lorem commodo deserunt. Culpa pariatur reprehenderit duis ipsum enim aute laborum cupidatat et id.\r\n", + "registered": "1990-07-04T13:50:23+05:00", + "friends": [ + { + "id": 0, + "name": "Hilda Contreras" + }, + { + "id": 1, + "name": "Mann Kramer" + }, + { + "id": 2, + "name": "Bonnie Dominguez" + } + ] + }, + { + "id": 338, + "guid": "18680345-09e7-4a10-bc60-6bbe6827e9db", + "isActive": true, + "balance": "$1,814.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Lorena Albert", + "gender": "female", + "company": "Cubicide", + "email": "lorenaalbert@cubicide.com", + "phone": "+1 (953) 446-2980", + "address": { + "street": 342, + "city": "Westwood", + "state": "West Virginia", + "zip": 6381 + }, + "about": "Ad quis exercitation magna Lorem Lorem duis enim id. Deserunt voluptate mollit incididunt tempor culpa fugiat eiusmod consequat duis duis. Eu nostrud nulla aliqua dolore eiusmod exercitation consequat elit enim enim sint occaecat Lorem. Mollit excepteur eiusmod reprehenderit exercitation qui magna veniam nisi in magna elit reprehenderit officia. Quis sit dolore laborum nisi. Eiusmod ad id nulla amet. Exercitation sunt cillum consectetur aliquip exercitation duis ut.\r\n", + "registered": "2013-11-12T15:28:20+06:00", + "friends": [ + { + "id": 0, + "name": "Bobbie Stafford" + }, + { + "id": 1, + "name": "Constance Barrett" + }, + { + "id": 2, + "name": "Pearl Taylor" + } + ] + }, + { + "id": 339, + "guid": "2d1b415d-e495-41a7-8bb3-805576ff1bee", + "isActive": true, + "balance": "$3,875.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Paige Levine", + "gender": "female", + "company": "Multiflex", + "email": "paigelevine@multiflex.com", + "phone": "+1 (842) 551-2693", + "address": { + "street": 644, + "city": "Blanco", + "state": "Arkansas", + "zip": 5674 + }, + "about": "Irure nulla id occaecat nisi excepteur velit enim commodo ex minim qui ipsum et. Ea id sit quis ex. Occaecat ipsum sit eiusmod quis occaecat dolor est. Voluptate amet cillum in magna aliquip nulla. Aute laborum dolor tempor consequat laboris amet incididunt nisi et duis nisi id reprehenderit mollit. Excepteur ullamco et est elit ipsum in mollit esse amet.\r\n", + "registered": "2006-05-09T21:50:14+05:00", + "friends": [ + { + "id": 0, + "name": "Deleon Obrien" + }, + { + "id": 1, + "name": "Ginger Wooten" + }, + { + "id": 2, + "name": "Prince Griffin" + } + ] + }, + { + "id": 340, + "guid": "72e115c2-8716-46ec-b124-af5c837a4a45", + "isActive": false, + "balance": "$2,215.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Hudson Hurst", + "gender": "male", + "company": "Tri@Tribalog", + "email": "hudsonhurst@tri@tribalog.com", + "phone": "+1 (930) 459-2700", + "address": { + "street": 189, + "city": "Martell", + "state": "Colorado", + "zip": 3548 + }, + "about": "Nulla irure duis quis aliqua aliquip officia laboris dolor dolor do et nisi qui ad. In labore dolore ipsum est tempor cupidatat incididunt et exercitation ullamco id do culpa velit. Do excepteur Lorem mollit nulla officia voluptate nulla consectetur culpa pariatur fugiat officia. Excepteur enim pariatur aute sunt sint qui esse. Tempor consectetur et velit in adipisicing occaecat tempor et reprehenderit anim ullamco nostrud. Duis esse nisi et laborum non quis qui in ipsum adipisicing amet in elit.\r\n", + "registered": "2005-06-10T07:34:46+05:00", + "friends": [ + { + "id": 0, + "name": "Richard Hopkins" + }, + { + "id": 1, + "name": "Mayra Wilkinson" + }, + { + "id": 2, + "name": "Delacruz Macdonald" + } + ] + }, + { + "id": 341, + "guid": "024261b8-be10-4f20-9843-19c7d7fd70b7", + "isActive": true, + "balance": "$2,513.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Tameka Oconnor", + "gender": "female", + "company": "Insurity", + "email": "tamekaoconnor@insurity.com", + "phone": "+1 (981) 536-2269", + "address": { + "street": 806, + "city": "Hilltop", + "state": "North Carolina", + "zip": 2436 + }, + "about": "Aliqua cupidatat dolor cupidatat sunt in pariatur sunt duis cupidatat. Cupidatat exercitation laborum sit fugiat velit in consequat velit. Ex proident culpa qui enim fugiat dolor voluptate mollit magna nisi qui. Consectetur aliqua mollit cupidatat ut anim elit aliquip commodo adipisicing et. Elit nulla et velit incididunt velit sint officia. Adipisicing anim aliquip consectetur ad dolor dolor enim.\r\n", + "registered": "1995-09-13T07:30:31+05:00", + "friends": [ + { + "id": 0, + "name": "Gallegos Lawrence" + }, + { + "id": 1, + "name": "Amber Mcknight" + }, + { + "id": 2, + "name": "Kerr Moran" + } + ] + }, + { + "id": 342, + "guid": "7bb56bf3-0e15-43a7-85b8-f855afe18871", + "isActive": false, + "balance": "$1,462.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Montgomery Sharp", + "gender": "male", + "company": "Plutorque", + "email": "montgomerysharp@plutorque.com", + "phone": "+1 (876) 417-2274", + "address": { + "street": 644, + "city": "Gadsden", + "state": "Vermont", + "zip": 9367 + }, + "about": "Quis sint veniam adipisicing veniam elit id id deserunt. Magna aliqua minim cupidatat esse aliqua sint anim est enim labore minim ex esse. Non aliquip aliquip eiusmod eiusmod velit non nulla id ex magna proident ut et cillum. Cillum veniam ea esse aute fugiat nisi excepteur cillum ipsum.\r\n", + "registered": "1992-11-08T05:07:47+06:00", + "friends": [ + { + "id": 0, + "name": "Sherrie Clements" + }, + { + "id": 1, + "name": "Bridget Case" + }, + { + "id": 2, + "name": "Phillips Trujillo" + } + ] + }, + { + "id": 343, + "guid": "145ee206-c143-4a42-87a2-520c443640c4", + "isActive": false, + "balance": "$3,282.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Hanson Rowland", + "gender": "male", + "company": "Oronoko", + "email": "hansonrowland@oronoko.com", + "phone": "+1 (911) 530-3817", + "address": { + "street": 394, + "city": "Waverly", + "state": "Pennsylvania", + "zip": 7319 + }, + "about": "Irure qui aute nulla ad qui ad duis exercitation nulla exercitation fugiat consectetur quis. Eu amet consectetur id labore. Labore deserunt ex Lorem non id proident id ea aute ullamco deserunt sint laborum. Sunt irure aute ad ad veniam.\r\n", + "registered": "2008-04-18T19:36:14+05:00", + "friends": [ + { + "id": 0, + "name": "Corrine Salazar" + }, + { + "id": 1, + "name": "Lori Irwin" + }, + { + "id": 2, + "name": "Wise Pitts" + } + ] + }, + { + "id": 344, + "guid": "83cdafae-b548-4a8a-9200-19c7dba48bb1", + "isActive": false, + "balance": "$3,999.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Figueroa Dennis", + "gender": "male", + "company": "Corpulse", + "email": "figueroadennis@corpulse.com", + "phone": "+1 (852) 489-2250", + "address": { + "street": 487, + "city": "Turpin", + "state": "Kansas", + "zip": 2897 + }, + "about": "Nisi ipsum excepteur elit excepteur qui proident tempor ullamco ut irure esse. Ex sint est mollit elit voluptate. Esse irure aute voluptate dolore veniam consequat.\r\n", + "registered": "2012-06-29T11:49:44+05:00", + "friends": [ + { + "id": 0, + "name": "Lorene Morse" + }, + { + "id": 1, + "name": "Sheppard Jefferson" + }, + { + "id": 2, + "name": "Sharpe Mcdaniel" + } + ] + }, + { + "id": 345, + "guid": "18c8cd08-e6d0-4aad-9de9-0b30db5bb565", + "isActive": false, + "balance": "$3,129.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Washington Acosta", + "gender": "male", + "company": "Ecraze", + "email": "washingtonacosta@ecraze.com", + "phone": "+1 (913) 487-2120", + "address": { + "street": 694, + "city": "Bartley", + "state": "Utah", + "zip": 5804 + }, + "about": "Eiusmod aute voluptate cupidatat cupidatat anim. Consequat Lorem do aliqua nulla fugiat do nulla duis velit nulla sint. Cillum pariatur id ut exercitation pariatur Lorem enim ad occaecat anim. Voluptate ad incididunt et elit minim anim duis irure et Lorem esse. Consequat velit consequat nulla exercitation consectetur dolor ipsum deserunt aliquip aliqua.\r\n", + "registered": "2013-09-13T16:19:29+05:00", + "friends": [ + { + "id": 0, + "name": "Owens Heath" + }, + { + "id": 1, + "name": "Christa Stephens" + }, + { + "id": 2, + "name": "Slater Franco" + } + ] + }, + { + "id": 346, + "guid": "0edf17be-aee2-483e-a78d-1be467ee04eb", + "isActive": false, + "balance": "$2,481.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Jeannette Lowe", + "gender": "female", + "company": "Fuelworks", + "email": "jeannettelowe@fuelworks.com", + "phone": "+1 (886) 562-3276", + "address": { + "street": 813, + "city": "Delshire", + "state": "Nevada", + "zip": 3498 + }, + "about": "Sint velit tempor veniam et est consequat officia dolore ipsum Lorem tempor fugiat. Laboris officia qui eiusmod adipisicing mollit non exercitation nulla officia aute exercitation voluptate. Reprehenderit sint deserunt commodo magna magna cillum aute cupidatat amet.\r\n", + "registered": "2002-03-23T17:17:39+05:00", + "friends": [ + { + "id": 0, + "name": "Jackie Burke" + }, + { + "id": 1, + "name": "Kellie Johns" + }, + { + "id": 2, + "name": "Enid Pena" + } + ] + }, + { + "id": 347, + "guid": "24cb4dfc-9ccd-47fd-b9ed-9ee0bdf36f35", + "isActive": false, + "balance": "$3,293.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Hilary Beasley", + "gender": "female", + "company": "Medifax", + "email": "hilarybeasley@medifax.com", + "phone": "+1 (936) 547-3843", + "address": { + "street": 121, + "city": "Concho", + "state": "North Dakota", + "zip": 654 + }, + "about": "Labore qui anim nostrud id dolor eiusmod tempor do duis qui non adipisicing veniam laborum. Amet qui voluptate tempor laborum laborum cillum commodo incididunt ad. Voluptate enim dolor tempor id esse aute sit ut. Ipsum incididunt ad sit dolor reprehenderit in ut ea et pariatur adipisicing.\r\n", + "registered": "1993-11-12T15:06:36+06:00", + "friends": [ + { + "id": 0, + "name": "Madeline Burton" + }, + { + "id": 1, + "name": "Bobbie Snider" + }, + { + "id": 2, + "name": "French Dean" + } + ] + }, + { + "id": 348, + "guid": "f6e07149-8dc5-4090-a97b-7200484c72d4", + "isActive": false, + "balance": "$3,202.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Veronica Livingston", + "gender": "female", + "company": "Biohab", + "email": "veronicalivingston@biohab.com", + "phone": "+1 (887) 493-2354", + "address": { + "street": 726, + "city": "Blackgum", + "state": "Ohio", + "zip": 5277 + }, + "about": "Ullamco adipisicing occaecat tempor cupidatat excepteur exercitation sint qui et. Elit eiusmod pariatur magna ad magna laborum nulla tempor eiusmod. Amet dolore ullamco nostrud mollit fugiat do esse elit duis nostrud incididunt sit esse. Officia exercitation ad in do eu dolore magna quis voluptate excepteur fugiat anim elit velit. Magna consequat eiusmod ut culpa labore commodo elit Lorem. Est adipisicing reprehenderit duis reprehenderit enim aute sit eu exercitation qui sit esse esse voluptate.\r\n", + "registered": "2003-10-03T08:30:37+05:00", + "friends": [ + { + "id": 0, + "name": "Mcdonald Erickson" + }, + { + "id": 1, + "name": "Marsha Vargas" + }, + { + "id": 2, + "name": "Hahn Benton" + } + ] + }, + { + "id": 349, + "guid": "3055c091-86b7-4032-89c8-afeb484804bc", + "isActive": false, + "balance": "$2,377.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Thelma Parker", + "gender": "female", + "company": "Cogentry", + "email": "thelmaparker@cogentry.com", + "phone": "+1 (945) 484-2408", + "address": { + "street": 278, + "city": "Bonanza", + "state": "Mississippi", + "zip": 527 + }, + "about": "Pariatur deserunt commodo officia ad quis. Pariatur consequat ad consectetur nulla amet in aliqua proident proident. Voluptate et occaecat nisi occaecat occaecat. In consequat ut mollit laborum sunt do ipsum sunt qui.\r\n", + "registered": "2004-12-05T21:07:46+06:00", + "friends": [ + { + "id": 0, + "name": "Trevino Barnett" + }, + { + "id": 1, + "name": "Whitfield Craft" + }, + { + "id": 2, + "name": "Maxwell Roberson" + } + ] + }, + { + "id": 350, + "guid": "2be73ea1-e3d2-464d-9684-91ca8a4483f0", + "isActive": true, + "balance": "$1,440.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Watson Blevins", + "gender": "male", + "company": "Xanide", + "email": "watsonblevins@xanide.com", + "phone": "+1 (831) 455-3039", + "address": { + "street": 349, + "city": "Townsend", + "state": "Arkansas", + "zip": 9320 + }, + "about": "Labore Lorem consectetur eiusmod enim ipsum culpa dolor officia. Consectetur nostrud cupidatat ex aliqua. Sint sint fugiat dolore quis dolore proident. Aute dolore nostrud sint elit occaecat culpa tempor sunt non.\r\n", + "registered": "2008-01-19T19:20:10+06:00", + "friends": [ + { + "id": 0, + "name": "Sondra Gilbert" + }, + { + "id": 1, + "name": "Lacey Sullivan" + }, + { + "id": 2, + "name": "Flowers Calderon" + } + ] + }, + { + "id": 351, + "guid": "ed3c7b60-0ada-42b4-a23c-bc7dbb7570f5", + "isActive": true, + "balance": "$3,594.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Cantu Cross", + "gender": "male", + "company": "Slambda", + "email": "cantucross@slambda.com", + "phone": "+1 (923) 530-3448", + "address": { + "street": 137, + "city": "Yonah", + "state": "Florida", + "zip": 9969 + }, + "about": "Veniam est velit sint sint pariatur aliqua elit. Fugiat nulla ullamco voluptate irure culpa nisi id amet do. Anim nisi esse esse officia pariatur elit. Incididunt magna proident ex in eu.\r\n", + "registered": "1998-03-25T07:00:58+05:00", + "friends": [ + { + "id": 0, + "name": "Claire Singleton" + }, + { + "id": 1, + "name": "Lenore Carson" + }, + { + "id": 2, + "name": "Sexton Rowe" + } + ] + }, + { + "id": 352, + "guid": "0053c7dc-c786-4925-996f-01afd3bf692f", + "isActive": false, + "balance": "$1,424.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Flynn Baird", + "gender": "male", + "company": "Kozgene", + "email": "flynnbaird@kozgene.com", + "phone": "+1 (847) 480-3135", + "address": { + "street": 769, + "city": "Ebro", + "state": "New Jersey", + "zip": 1686 + }, + "about": "Eiusmod voluptate ea minim ut sunt mollit esse aliquip pariatur velit Lorem sint. Tempor nulla dolor reprehenderit ad. Dolore aliquip incididunt ea est qui quis reprehenderit nostrud. Proident elit pariatur elit id eiusmod qui id cupidatat excepteur excepteur occaecat exercitation. Ex ipsum amet commodo nisi magna voluptate. Ut excepteur ut nisi ex duis ut velit incididunt nisi. Duis ut eu incididunt id.\r\n", + "registered": "1994-01-25T03:40:43+06:00", + "friends": [ + { + "id": 0, + "name": "David Gamble" + }, + { + "id": 1, + "name": "Frazier Rose" + }, + { + "id": 2, + "name": "Lauren Duncan" + } + ] + }, + { + "id": 353, + "guid": "da05d645-4e83-4865-bcc2-f72163c472c6", + "isActive": true, + "balance": "$1,891.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Diana Frye", + "gender": "female", + "company": "Bicol", + "email": "dianafrye@bicol.com", + "phone": "+1 (998) 510-2769", + "address": { + "street": 902, + "city": "Gibsonia", + "state": "New Hampshire", + "zip": 6709 + }, + "about": "Sunt laboris cupidatat aliqua consequat laboris ad pariatur ut minim veniam qui nostrud aliquip. Ullamco ad et tempor magna. Quis et sint veniam incididunt ipsum pariatur non ut occaecat sit.\r\n", + "registered": "2009-09-29T15:13:43+05:00", + "friends": [ + { + "id": 0, + "name": "Ruby Cummings" + }, + { + "id": 1, + "name": "Cotton Olsen" + }, + { + "id": 2, + "name": "Kelley Parrish" + } + ] + }, + { + "id": 354, + "guid": "ede66734-81b8-46fb-89a2-425ef40c9ce4", + "isActive": false, + "balance": "$3,969.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Brock Mcknight", + "gender": "male", + "company": "Octocore", + "email": "brockmcknight@octocore.com", + "phone": "+1 (821) 572-2559", + "address": { + "street": 430, + "city": "Deercroft", + "state": "Wyoming", + "zip": 3127 + }, + "about": "Quis nulla esse est aliquip sint veniam labore aliquip pariatur. Ex irure nostrud enim deserunt minim. Esse pariatur non qui incididunt culpa laboris laborum ex. Enim qui ex deserunt consectetur adipisicing eu non velit. Exercitation incididunt qui incididunt eiusmod exercitation mollit officia fugiat aute non nisi.\r\n", + "registered": "1988-08-27T14:28:43+05:00", + "friends": [ + { + "id": 0, + "name": "Chang Ware" + }, + { + "id": 1, + "name": "Mcfadden Gregory" + }, + { + "id": 2, + "name": "Adkins Ford" + } + ] + }, + { + "id": 355, + "guid": "e8d17092-2263-41b7-8efd-c880972fbe8a", + "isActive": true, + "balance": "$3,649.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Ophelia Evans", + "gender": "female", + "company": "Valpreal", + "email": "opheliaevans@valpreal.com", + "phone": "+1 (831) 544-2847", + "address": { + "street": 277, + "city": "Sardis", + "state": "California", + "zip": 9598 + }, + "about": "Amet nulla culpa exercitation ullamco cupidatat laborum ea. Qui reprehenderit sunt do qui deserunt dolor non dolor non. Ipsum tempor duis commodo magna magna reprehenderit reprehenderit. Amet qui consectetur mollit sunt elit culpa anim.\r\n", + "registered": "2004-06-16T01:09:14+05:00", + "friends": [ + { + "id": 0, + "name": "Graciela Leon" + }, + { + "id": 1, + "name": "Acosta Carlson" + }, + { + "id": 2, + "name": "Parsons Crosby" + } + ] + }, + { + "id": 356, + "guid": "37297f73-425e-4c2c-ab54-d1ad4d59e197", + "isActive": false, + "balance": "$1,220.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Boone Downs", + "gender": "male", + "company": "Datacator", + "email": "boonedowns@datacator.com", + "phone": "+1 (801) 471-2448", + "address": { + "street": 182, + "city": "Manila", + "state": "New Mexico", + "zip": 2491 + }, + "about": "Eu fugiat duis enim aute ex adipisicing. Incididunt dolore commodo tempor ipsum deserunt. Sint consectetur ipsum sit proident. Anim do eiusmod eiusmod labore minim ad reprehenderit nostrud ex pariatur occaecat ut ipsum cupidatat. Qui nulla commodo minim ut sint nisi ad fugiat reprehenderit quis laborum quis. Irure exercitation aliquip est incididunt enim laborum dolore qui non ad enim ipsum nisi in. Aute duis minim cillum pariatur.\r\n", + "registered": "2009-07-24T10:08:04+05:00", + "friends": [ + { + "id": 0, + "name": "Le Conrad" + }, + { + "id": 1, + "name": "Matthews Reeves" + }, + { + "id": 2, + "name": "Mccoy Craig" + } + ] + }, + { + "id": 357, + "guid": "e6b3d1ed-cdde-499b-9dce-18f21f4e8888", + "isActive": true, + "balance": "$2,703.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Jimenez Knapp", + "gender": "male", + "company": "Sustenza", + "email": "jimenezknapp@sustenza.com", + "phone": "+1 (959) 591-3878", + "address": { + "street": 658, + "city": "Finzel", + "state": "Vermont", + "zip": 5830 + }, + "about": "Enim tempor velit velit enim deserunt non labore aute labore elit ut. Deserunt do aute anim fugiat. Mollit ea Lorem duis magna aliquip sint tempor laboris deserunt et quis aute.\r\n", + "registered": "1995-07-22T06:59:16+05:00", + "friends": [ + { + "id": 0, + "name": "Tamika Pratt" + }, + { + "id": 1, + "name": "Cobb Pickett" + }, + { + "id": 2, + "name": "Harding Crawford" + } + ] + }, + { + "id": 358, + "guid": "b8a8b650-80f9-4572-9a8a-3475e3a74728", + "isActive": true, + "balance": "$2,957.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Cross Coleman", + "gender": "male", + "company": "Equicom", + "email": "crosscoleman@equicom.com", + "phone": "+1 (881) 580-2564", + "address": { + "street": 841, + "city": "Tibbie", + "state": "Illinois", + "zip": 4975 + }, + "about": "Voluptate duis eu proident laborum officia anim proident enim eu voluptate. Mollit labore culpa ad laboris sint ipsum et aliqua velit enim culpa aliquip laboris. Qui cillum culpa anim cillum commodo incididunt laborum ullamco id cillum Lorem.\r\n", + "registered": "2005-01-05T20:08:23+06:00", + "friends": [ + { + "id": 0, + "name": "Lester Rhodes" + }, + { + "id": 1, + "name": "Jenkins Navarro" + }, + { + "id": 2, + "name": "Glover Greer" + } + ] + }, + { + "id": 359, + "guid": "02f8ea8a-3eb9-4ed3-a0c3-8f3014c57013", + "isActive": true, + "balance": "$2,505.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Connie Stanton", + "gender": "female", + "company": "Comvey", + "email": "conniestanton@comvey.com", + "phone": "+1 (916) 444-3009", + "address": { + "street": 819, + "city": "Ronco", + "state": "Alaska", + "zip": 4631 + }, + "about": "Et tempor eu Lorem eu tempor do ex incididunt aliquip consequat. Culpa amet aute ex anim mollit ut mollit. Velit esse irure proident aute occaecat quis pariatur. Anim officia eiusmod qui id in elit dolore quis. Lorem ipsum sunt cillum aute adipisicing dolore nisi tempor cillum dolore commodo.\r\n", + "registered": "1991-08-20T09:00:58+05:00", + "friends": [ + { + "id": 0, + "name": "Rosalyn Tucker" + }, + { + "id": 1, + "name": "Holt Kline" + }, + { + "id": 2, + "name": "Spence Payne" + } + ] + }, + { + "id": 360, + "guid": "db7e22b5-8db6-40de-a925-51587b3b9628", + "isActive": false, + "balance": "$3,615.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Eva Petty", + "gender": "female", + "company": "Imkan", + "email": "evapetty@imkan.com", + "phone": "+1 (935) 504-2016", + "address": { + "street": 866, + "city": "Bend", + "state": "Oklahoma", + "zip": 7811 + }, + "about": "Nulla incididunt pariatur consectetur do laboris quis eiusmod sint mollit ullamco laborum voluptate labore. Proident adipisicing quis reprehenderit duis adipisicing tempor ut excepteur adipisicing. Ut irure non consectetur esse minim tempor aute elit ullamco irure exercitation non reprehenderit. Ut et aute eu reprehenderit nisi officia pariatur eu. Cupidatat reprehenderit fugiat ipsum pariatur irure amet nostrud pariatur eu et. Nulla laborum ullamco ipsum deserunt laboris reprehenderit.\r\n", + "registered": "1993-10-04T01:40:03+05:00", + "friends": [ + { + "id": 0, + "name": "Emilia Boone" + }, + { + "id": 1, + "name": "James Gomez" + }, + { + "id": 2, + "name": "Charles Boyd" + } + ] + }, + { + "id": 361, + "guid": "8ffb971d-0ad9-4038-b4c3-92bc05961599", + "isActive": true, + "balance": "$3,098.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Levine Todd", + "gender": "male", + "company": "Plasmosis", + "email": "levinetodd@plasmosis.com", + "phone": "+1 (883) 473-2671", + "address": { + "street": 539, + "city": "Coinjock", + "state": "Connecticut", + "zip": 5625 + }, + "about": "Fugiat ex proident aliquip enim consequat nisi est eiusmod tempor ex eiusmod Lorem et et. Occaecat sint nisi anim amet cillum laboris cupidatat sint enim occaecat. Anim elit irure incididunt qui sunt fugiat sunt ipsum. Adipisicing nulla dolore dolor esse non excepteur. Velit laborum elit ut aute ad esse officia anim aute aute adipisicing. Irure ad labore laboris aute quis culpa adipisicing sint occaecat magna officia minim est.\r\n", + "registered": "2004-10-11T13:15:11+05:00", + "friends": [ + { + "id": 0, + "name": "Shanna Dunlap" + }, + { + "id": 1, + "name": "Margaret Rutledge" + }, + { + "id": 2, + "name": "Rush Ruiz" + } + ] + }, + { + "id": 362, + "guid": "03ab30ab-10d9-4693-acef-3415c8832b1c", + "isActive": false, + "balance": "$2,288.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Rachelle Harrington", + "gender": "female", + "company": "Isoswitch", + "email": "rachelleharrington@isoswitch.com", + "phone": "+1 (811) 532-3342", + "address": { + "street": 734, + "city": "Boomer", + "state": "Arizona", + "zip": 9051 + }, + "about": "Enim exercitation dolor laborum ad dolor mollit duis elit dolor qui deserunt magna qui magna. Adipisicing mollit voluptate nulla ut cillum non ad non enim laborum consectetur. Incididunt non veniam tempor aute aliqua sint veniam.\r\n", + "registered": "1993-05-11T16:07:50+05:00", + "friends": [ + { + "id": 0, + "name": "Joann Foster" + }, + { + "id": 1, + "name": "Pugh Holman" + }, + { + "id": 2, + "name": "Carmen Sparks" + } + ] + }, + { + "id": 363, + "guid": "6b89f953-eb23-4273-bff0-a2dc00be41ad", + "isActive": false, + "balance": "$3,228.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Candy Burch", + "gender": "female", + "company": "Kenegy", + "email": "candyburch@kenegy.com", + "phone": "+1 (898) 516-2306", + "address": { + "street": 597, + "city": "Brethren", + "state": "Tennessee", + "zip": 3323 + }, + "about": "Consequat est nulla velit commodo ipsum ea fugiat dolor dolore sint in commodo sunt ut. Aliquip cillum amet excepteur excepteur aliqua minim id sit adipisicing ipsum aliquip occaecat veniam proident. Incididunt occaecat veniam esse exercitation voluptate enim. Ad magna nulla ex est et. Commodo ad enim aute consequat sint proident irure commodo dolor non.\r\n", + "registered": "1998-06-25T15:55:08+05:00", + "friends": [ + { + "id": 0, + "name": "Marietta Randall" + }, + { + "id": 1, + "name": "Thomas Quinn" + }, + { + "id": 2, + "name": "Simone Foley" + } + ] + }, + { + "id": 364, + "guid": "1eb793f3-5f19-43a9-b908-e4aaca932553", + "isActive": true, + "balance": "$3,772.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Cassandra Fields", + "gender": "female", + "company": "Ramjob", + "email": "cassandrafields@ramjob.com", + "phone": "+1 (949) 468-2077", + "address": { + "street": 439, + "city": "Mammoth", + "state": "Nebraska", + "zip": 6704 + }, + "about": "Aute fugiat elit nisi reprehenderit sunt mollit sit amet consequat. Pariatur mollit et reprehenderit ad mollit labore aute ex fugiat esse magna aliquip. Ipsum est ex ullamco pariatur. Reprehenderit cupidatat esse culpa ad. Nulla laborum anim nulla veniam ea mollit consequat qui reprehenderit exercitation. Consectetur aliquip elit adipisicing irure eu dolore aliquip esse. Laborum irure sit veniam tempor dolor aliqua ipsum adipisicing deserunt mollit.\r\n", + "registered": "2010-10-08T06:49:22+05:00", + "friends": [ + { + "id": 0, + "name": "Schultz Hayden" + }, + { + "id": 1, + "name": "Jaclyn Potter" + }, + { + "id": 2, + "name": "Finch Woodard" + } + ] + }, + { + "id": 365, + "guid": "2b929344-f0c2-4904-82a8-5b3ca887cecf", + "isActive": false, + "balance": "$2,948.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Frieda Riddle", + "gender": "female", + "company": "Exoswitch", + "email": "friedariddle@exoswitch.com", + "phone": "+1 (850) 547-3003", + "address": { + "street": 576, + "city": "Wells", + "state": "Massachusetts", + "zip": 5002 + }, + "about": "Voluptate ea nisi cillum qui ex id laboris voluptate cupidatat. Elit commodo sit do incididunt. Tempor elit aliquip esse ex ipsum mollit reprehenderit amet.\r\n", + "registered": "2009-07-25T13:00:06+05:00", + "friends": [ + { + "id": 0, + "name": "Gordon Mullins" + }, + { + "id": 1, + "name": "Jami Walters" + }, + { + "id": 2, + "name": "Dona Hawkins" + } + ] + }, + { + "id": 366, + "guid": "ca8ca8b9-4345-4224-9cab-7d8a1192d1d5", + "isActive": true, + "balance": "$2,565.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Latonya Kaufman", + "gender": "female", + "company": "Dreamia", + "email": "latonyakaufman@dreamia.com", + "phone": "+1 (931) 406-3111", + "address": { + "street": 602, + "city": "Orviston", + "state": "Oregon", + "zip": 4738 + }, + "about": "Proident veniam dolor non enim consectetur enim aliqua qui proident est ea in proident. Fugiat laborum esse cillum reprehenderit sint ut officia deserunt. Ipsum fugiat do dolor non nulla culpa officia proident ipsum amet do nisi. Lorem duis consectetur nostrud anim. Dolore dolor ullamco cupidatat tempor nulla excepteur nisi laborum eiusmod nulla. Aliquip labore consectetur consequat enim ullamco proident aliqua commodo dolor et non.\r\n", + "registered": "2011-12-19T17:07:57+06:00", + "friends": [ + { + "id": 0, + "name": "Hensley Blair" + }, + { + "id": 1, + "name": "Dillard Forbes" + }, + { + "id": 2, + "name": "Anne Nunez" + } + ] + }, + { + "id": 367, + "guid": "9c757bb8-c90d-48d5-a730-05e04456dc5c", + "isActive": false, + "balance": "$3,613.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Ericka Finch", + "gender": "female", + "company": "Neptide", + "email": "erickafinch@neptide.com", + "phone": "+1 (989) 488-3893", + "address": { + "street": 711, + "city": "Makena", + "state": "New York", + "zip": 3251 + }, + "about": "Officia reprehenderit est ipsum reprehenderit sit elit et nostrud proident incididunt. Consectetur laboris fugiat nulla anim amet dolor ut. Aliqua ex in eiusmod cupidatat nulla. Incididunt sunt elit et anim in dolore fugiat consectetur pariatur sunt consequat.\r\n", + "registered": "1993-06-24T04:30:26+05:00", + "friends": [ + { + "id": 0, + "name": "Beverly Mclaughlin" + }, + { + "id": 1, + "name": "Angelica Lowery" + }, + { + "id": 2, + "name": "Baxter Hahn" + } + ] + }, + { + "id": 368, + "guid": "25ddedf9-2066-4ddc-852d-ed16fb794458", + "isActive": false, + "balance": "$1,687.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Joan Jarvis", + "gender": "female", + "company": "Xylar", + "email": "joanjarvis@xylar.com", + "phone": "+1 (800) 593-3400", + "address": { + "street": 269, + "city": "Terlingua", + "state": "Washington", + "zip": 7764 + }, + "about": "Adipisicing minim cupidatat ea et voluptate reprehenderit ea minim. Sit ipsum non eu labore in est nostrud. Ut dolor ex dolor non cupidatat ipsum fugiat exercitation occaecat. Esse mollit non non velit minim nostrud aliqua anim cillum labore sunt ullamco.\r\n", + "registered": "1994-09-01T05:33:51+05:00", + "friends": [ + { + "id": 0, + "name": "Annie Neal" + }, + { + "id": 1, + "name": "Castaneda Gillespie" + }, + { + "id": 2, + "name": "Marjorie Peck" + } + ] + }, + { + "id": 369, + "guid": "c798bfe2-a7ee-4425-a185-dd404b54b2c2", + "isActive": true, + "balance": "$2,000.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Rebekah Shields", + "gender": "female", + "company": "Polarium", + "email": "rebekahshields@polarium.com", + "phone": "+1 (900) 485-2113", + "address": { + "street": 978, + "city": "Umapine", + "state": "Minnesota", + "zip": 9261 + }, + "about": "Exercitation in velit incididunt consectetur reprehenderit nulla. Culpa exercitation culpa amet pariatur velit nostrud exercitation dolore quis ullamco dolor ea. Id ad exercitation non commodo cillum dolor nisi nisi velit Lorem. Proident velit sint dolore aliqua eu aliquip ex et reprehenderit proident nisi minim.\r\n", + "registered": "2004-12-22T11:12:23+06:00", + "friends": [ + { + "id": 0, + "name": "Franks Spence" + }, + { + "id": 1, + "name": "Summer Brewer" + }, + { + "id": 2, + "name": "Young Patton" + } + ] + }, + { + "id": 370, + "guid": "4b8de02a-df1d-49ff-bdf8-3b742f481257", + "isActive": false, + "balance": "$1,467.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Brigitte Juarez", + "gender": "female", + "company": "Sonique", + "email": "brigittejuarez@sonique.com", + "phone": "+1 (984) 543-3045", + "address": { + "street": 725, + "city": "Muir", + "state": "Kentucky", + "zip": 5433 + }, + "about": "Ipsum et qui cillum ad veniam. Deserunt occaecat deserunt elit nostrud et laborum ullamco nisi Lorem enim. Ex ad ex ex consequat. Ipsum excepteur nostrud deserunt quis cillum dolor quis occaecat eiusmod aliquip. Nulla veniam amet dolore ex aliqua eiusmod esse dolore sit sit cillum sunt nulla. Et esse anim et qui non irure.\r\n", + "registered": "2012-06-02T21:12:33+05:00", + "friends": [ + { + "id": 0, + "name": "Velma Myers" + }, + { + "id": 1, + "name": "Linda Tanner" + }, + { + "id": 2, + "name": "Chasity Acevedo" + } + ] + }, + { + "id": 371, + "guid": "65698470-bb96-403c-9fbc-602cc48442a5", + "isActive": true, + "balance": "$3,393.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Chase Colon", + "gender": "male", + "company": "Xleen", + "email": "chasecolon@xleen.com", + "phone": "+1 (805) 426-3426", + "address": { + "street": 350, + "city": "Rosewood", + "state": "Rhode Island", + "zip": 7893 + }, + "about": "Non sit aliqua dolore eiusmod. Proident elit tempor fugiat reprehenderit id Lorem proident elit do deserunt irure nulla laborum deserunt. Eiusmod consequat aliqua ad exercitation anim elit magna.\r\n", + "registered": "1995-04-10T11:25:48+05:00", + "friends": [ + { + "id": 0, + "name": "Grace Jensen" + }, + { + "id": 1, + "name": "Barker Odom" + }, + { + "id": 2, + "name": "Chandler Robertson" + } + ] + }, + { + "id": 372, + "guid": "bbcb7300-694d-4a24-9e6e-c2fb62fbbd5e", + "isActive": true, + "balance": "$3,156.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Jacqueline Wilkinson", + "gender": "female", + "company": "Vinch", + "email": "jacquelinewilkinson@vinch.com", + "phone": "+1 (875) 596-3737", + "address": { + "street": 451, + "city": "Fulford", + "state": "Hawaii", + "zip": 744 + }, + "about": "Pariatur ullamco nulla aliquip officia aliquip qui ipsum. Mollit laborum eiusmod reprehenderit incididunt eiusmod amet id esse occaecat. Excepteur Lorem eu veniam labore officia ea nostrud laborum sunt eu reprehenderit eiusmod elit magna. Occaecat eu nisi velit laboris culpa duis elit. Quis anim laboris minim velit et laborum reprehenderit ex ut do aliqua proident. Ipsum sunt anim ea aliquip culpa. Adipisicing id aliquip eiusmod occaecat culpa et laboris id nisi sint qui enim dolor.\r\n", + "registered": "1997-12-16T13:30:17+06:00", + "friends": [ + { + "id": 0, + "name": "Kerri Goodwin" + }, + { + "id": 1, + "name": "Shari Vaughan" + }, + { + "id": 2, + "name": "Sybil Nelson" + } + ] + }, + { + "id": 373, + "guid": "bfa53a38-510b-49bb-96b7-ed165327a791", + "isActive": false, + "balance": "$2,712.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Elliott Elliott", + "gender": "male", + "company": "Enjola", + "email": "elliottelliott@enjola.com", + "phone": "+1 (969) 598-2178", + "address": { + "street": 725, + "city": "Darrtown", + "state": "West Virginia", + "zip": 2671 + }, + "about": "Proident minim aliquip fugiat fugiat duis minim elit tempor do incididunt quis. Culpa ex Lorem quis anim sit elit sint est veniam aliquip enim ea. Minim sit culpa consectetur nulla id aliqua exercitation.\r\n", + "registered": "1994-08-19T17:39:24+05:00", + "friends": [ + { + "id": 0, + "name": "Mills Thomas" + }, + { + "id": 1, + "name": "Tyler Sloan" + }, + { + "id": 2, + "name": "Ladonna Wilcox" + } + ] + }, + { + "id": 374, + "guid": "30b59f71-ea63-415f-bc56-94e768f4ee0f", + "isActive": true, + "balance": "$2,085.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Mcclure Sykes", + "gender": "male", + "company": "Zillan", + "email": "mccluresykes@zillan.com", + "phone": "+1 (852) 486-2324", + "address": { + "street": 704, + "city": "Blue", + "state": "Louisiana", + "zip": 9986 + }, + "about": "Et do commodo proident consectetur duis qui sint eu eiusmod. Qui culpa excepteur enim magna magna ex proident. In magna sit nisi excepteur amet ullamco consequat adipisicing sunt pariatur amet non.\r\n", + "registered": "2013-11-10T20:50:49+06:00", + "friends": [ + { + "id": 0, + "name": "Juanita Woods" + }, + { + "id": 1, + "name": "Laura Stafford" + }, + { + "id": 2, + "name": "Hunter Simmons" + } + ] + }, + { + "id": 375, + "guid": "8966ddc9-a43d-4ac0-9843-b4dfe0189d70", + "isActive": true, + "balance": "$3,665.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Brandi Jacobson", + "gender": "female", + "company": "Strozen", + "email": "brandijacobson@strozen.com", + "phone": "+1 (868) 445-2696", + "address": { + "street": 726, + "city": "Sparkill", + "state": "Delaware", + "zip": 2193 + }, + "about": "Ad nisi consequat eu ad deserunt ea officia ex et aliqua eu dolor. Deserunt deserunt fugiat ad anim esse excepteur deserunt nulla pariatur adipisicing fugiat est tempor. Enim ea velit dolore id voluptate commodo nostrud sint minim magna commodo. Sunt non laboris eu ex officia dolore qui aliquip commodo.\r\n", + "registered": "1996-08-01T13:42:16+05:00", + "friends": [ + { + "id": 0, + "name": "Blankenship Brock" + }, + { + "id": 1, + "name": "Davidson Sexton" + }, + { + "id": 2, + "name": "Mavis Mcgee" + } + ] + }, + { + "id": 376, + "guid": "4dea54ab-e4b5-4768-9bcd-59ac229aef5f", + "isActive": true, + "balance": "$2,324.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Irwin Watson", + "gender": "male", + "company": "Lunchpad", + "email": "irwinwatson@lunchpad.com", + "phone": "+1 (957) 437-3236", + "address": { + "street": 677, + "city": "Lithium", + "state": "Iowa", + "zip": 8734 + }, + "about": "Excepteur ullamco quis in ad incididunt laboris anim irure. Excepteur nulla adipisicing adipisicing ullamco aute in. Occaecat minim non qui incididunt dolor magna irure adipisicing Lorem. Do esse cupidatat magna est anim commodo cupidatat officia fugiat exercitation ipsum Lorem est. Ex labore exercitation et deserunt aliquip velit Lorem consequat id commodo et.\r\n", + "registered": "1999-01-14T22:28:42+06:00", + "friends": [ + { + "id": 0, + "name": "Elsa Kirby" + }, + { + "id": 1, + "name": "Noemi Camacho" + }, + { + "id": 2, + "name": "Beatrice Barlow" + } + ] + }, + { + "id": 377, + "guid": "96d0a24f-9c4e-431b-b0a2-e63b3cf3e95d", + "isActive": true, + "balance": "$1,117.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Rodgers Mcconnell", + "gender": "male", + "company": "Handshake", + "email": "rodgersmcconnell@handshake.com", + "phone": "+1 (918) 418-2172", + "address": { + "street": 254, + "city": "Denio", + "state": "Maine", + "zip": 3883 + }, + "about": "Ut velit laboris ipsum minim consequat culpa aute adipisicing ut aute elit. Consectetur anim Lorem laborum dolore deserunt tempor commodo deserunt. Culpa esse sunt irure culpa sunt occaecat laborum ex eiusmod commodo. Ullamco officia enim reprehenderit ullamco nostrud.\r\n", + "registered": "2006-05-15T23:54:32+05:00", + "friends": [ + { + "id": 0, + "name": "Candice Velazquez" + }, + { + "id": 1, + "name": "Martha Hammond" + }, + { + "id": 2, + "name": "Kate Hoover" + } + ] + }, + { + "id": 378, + "guid": "b5794967-5489-405f-b915-af81d771432b", + "isActive": true, + "balance": "$3,636.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Bridgette Pope", + "gender": "female", + "company": "Glasstep", + "email": "bridgettepope@glasstep.com", + "phone": "+1 (980) 416-2239", + "address": { + "street": 605, + "city": "Masthope", + "state": "Missouri", + "zip": 3940 + }, + "about": "Amet cillum exercitation irure adipisicing anim. Adipisicing quis velit id occaecat pariatur aute ipsum esse esse ipsum. Anim consequat duis fugiat culpa in duis veniam velit aliqua et nulla pariatur exercitation tempor.\r\n", + "registered": "1997-01-24T03:05:31+06:00", + "friends": [ + { + "id": 0, + "name": "May Stein" + }, + { + "id": 1, + "name": "Desiree Hopkins" + }, + { + "id": 2, + "name": "Holden Merritt" + } + ] + }, + { + "id": 379, + "guid": "1ee76f50-d37a-48a9-9940-5aaa026df472", + "isActive": false, + "balance": "$1,575.00", + "picture": "http://placehold.it/32x32", + "age": 32, + "name": "Horton Spears", + "gender": "male", + "company": "Virva", + "email": "hortonspears@virva.com", + "phone": "+1 (822) 512-2238", + "address": { + "street": 518, + "city": "Westmoreland", + "state": "Wisconsin", + "zip": 250 + }, + "about": "Tempor ut enim irure aliqua reprehenderit. Minim nulla occaecat non excepteur consequat sunt velit enim qui non nulla. Elit velit dolor elit dolor est laborum. Reprehenderit dolore dolor in voluptate non est anim ad mollit fugiat et mollit officia. Tempor magna esse Lorem nisi qui.\r\n", + "registered": "2007-08-28T09:53:30+05:00", + "friends": [ + { + "id": 0, + "name": "Long Taylor" + }, + { + "id": 1, + "name": "Colette Kidd" + }, + { + "id": 2, + "name": "Kirby Maldonado" + } + ] + }, + { + "id": 380, + "guid": "9751f183-f125-48b5-bd8c-445a70068af4", + "isActive": false, + "balance": "$2,343.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Audrey Mendez", + "gender": "female", + "company": "Pyramia", + "email": "audreymendez@pyramia.com", + "phone": "+1 (844) 570-2368", + "address": { + "street": 700, + "city": "Lupton", + "state": "Texas", + "zip": 7277 + }, + "about": "Duis incididunt nostrud quis aute ea adipisicing. Cupidatat cupidatat cillum exercitation voluptate voluptate eiusmod enim fugiat irure ut veniam aute. Duis Lorem excepteur esse cillum nulla fugiat culpa pariatur in voluptate aute. Ex duis commodo et sit ullamco officia adipisicing eiusmod id enim. Laborum officia sit laboris enim proident sit nisi elit exercitation adipisicing duis anim labore incididunt.\r\n", + "registered": "2001-06-29T23:47:14+05:00", + "friends": [ + { + "id": 0, + "name": "Bates Harrell" + }, + { + "id": 1, + "name": "Beth Baxter" + }, + { + "id": 2, + "name": "Geraldine Adkins" + } + ] + }, + { + "id": 381, + "guid": "46f3aeab-ad02-4ce9-8ff1-66ce74fb5d7e", + "isActive": true, + "balance": "$3,781.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Mccormick Mayer", + "gender": "male", + "company": "Quizka", + "email": "mccormickmayer@quizka.com", + "phone": "+1 (889) 597-3852", + "address": { + "street": 247, + "city": "Mooresburg", + "state": "Idaho", + "zip": 3133 + }, + "about": "Sunt sint ad deserunt quis et elit magna elit commodo magna. Incididunt labore laborum incididunt incididunt eu enim nisi. Minim minim est qui eu officia quis anim non id minim ullamco nostrud exercitation est. Sint deserunt ullamco elit ad proident veniam. Quis eu occaecat elit commodo.\r\n", + "registered": "2007-10-10T07:13:04+05:00", + "friends": [ + { + "id": 0, + "name": "Blackburn Bridges" + }, + { + "id": 1, + "name": "Verna Daniels" + }, + { + "id": 2, + "name": "Dolly Ashley" + } + ] + }, + { + "id": 382, + "guid": "d435a177-2c7b-4eab-8ff0-e2af75b7f192", + "isActive": false, + "balance": "$3,665.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Nettie Obrien", + "gender": "female", + "company": "Ovolo", + "email": "nettieobrien@ovolo.com", + "phone": "+1 (826) 450-3415", + "address": { + "street": 753, + "city": "Belgreen", + "state": "Montana", + "zip": 1739 + }, + "about": "Ad nisi Lorem dolor ex amet ea tempor ad labore et ut. Deserunt cupidatat voluptate est ex proident. Magna eu consectetur proident non. Nostrud cupidatat commodo sit fugiat elit minim. Anim consequat officia ut nisi dolore elit aliquip sit ad et reprehenderit tempor ut do.\r\n", + "registered": "1998-01-31T06:42:07+06:00", + "friends": [ + { + "id": 0, + "name": "Lynette Curry" + }, + { + "id": 1, + "name": "Rosa Hicks" + }, + { + "id": 2, + "name": "Bush Reyes" + } + ] + }, + { + "id": 383, + "guid": "464827ff-972d-4a53-b6c4-9ce01b09fc17", + "isActive": false, + "balance": "$3,640.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Eaton Cantrell", + "gender": "male", + "company": "Ecosys", + "email": "eatoncantrell@ecosys.com", + "phone": "+1 (956) 558-3640", + "address": { + "street": 707, + "city": "Wedgewood", + "state": "Maryland", + "zip": 1803 + }, + "about": "Fugiat consectetur anim dolor deserunt labore voluptate ex sit ad adipisicing. Nostrud duis culpa excepteur tempor veniam velit reprehenderit amet esse nostrud. Fugiat in occaecat consequat magna qui sunt exercitation amet quis duis fugiat laboris. Anim enim ex dolore dolore aute sunt do non mollit incididunt nostrud aliqua aliqua.\r\n", + "registered": "1994-07-11T12:27:06+05:00", + "friends": [ + { + "id": 0, + "name": "Carver Leblanc" + }, + { + "id": 1, + "name": "Gallagher Steele" + }, + { + "id": 2, + "name": "Eddie Tran" + } + ] + }, + { + "id": 384, + "guid": "200d6b77-6dae-48b9-84e6-7f2e4a1a3ea7", + "isActive": true, + "balance": "$2,031.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Wells Kirk", + "gender": "male", + "company": "Accufarm", + "email": "wellskirk@accufarm.com", + "phone": "+1 (802) 439-2322", + "address": { + "street": 513, + "city": "Dragoon", + "state": "South Carolina", + "zip": 8608 + }, + "about": "Incididunt cupidatat veniam incididunt labore id commodo do do. Excepteur occaecat quis veniam duis cillum qui aliqua labore ut sint. Ad eiusmod nisi nulla dolor tempor eiusmod ut fugiat sint do aute.\r\n", + "registered": "1995-01-11T18:38:09+06:00", + "friends": [ + { + "id": 0, + "name": "Chen Stuart" + }, + { + "id": 1, + "name": "Fernandez Cohen" + }, + { + "id": 2, + "name": "Sosa Jimenez" + } + ] + }, + { + "id": 385, + "guid": "e9813e7f-2ea6-4df0-8a22-d15ec83718ff", + "isActive": false, + "balance": "$1,730.00", + "picture": "http://placehold.it/32x32", + "age": 20, + "name": "Sharlene Lamb", + "gender": "female", + "company": "Nixelt", + "email": "sharlenelamb@nixelt.com", + "phone": "+1 (956) 561-3398", + "address": { + "street": 974, + "city": "Mayfair", + "state": "North Carolina", + "zip": 2318 + }, + "about": "Dolore non fugiat dolor culpa in. Consectetur pariatur eiusmod fugiat ut ad mollit consequat est tempor consectetur tempor eiusmod nisi ipsum. Anim tempor reprehenderit esse voluptate non duis. Do nulla eiusmod non aute aliqua incididunt consectetur aliqua excepteur eu voluptate eiusmod pariatur. Anim nostrud sit sunt sunt aliquip fugiat nisi laboris minim enim nostrud reprehenderit. Qui do dolor nisi amet fugiat commodo adipisicing enim quis consequat veniam Lorem amet. Pariatur fugiat aliqua proident consectetur ex eu eu culpa adipisicing velit sit ut ad duis.\r\n", + "registered": "2005-04-18T17:35:27+05:00", + "friends": [ + { + "id": 0, + "name": "Harper Mooney" + }, + { + "id": 1, + "name": "Whitehead Barry" + }, + { + "id": 2, + "name": "Rochelle Fischer" + } + ] + }, + { + "id": 386, + "guid": "0544708d-0dae-439e-a2b3-a5bcc825cc50", + "isActive": true, + "balance": "$1,566.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Lynda Knight", + "gender": "female", + "company": "Anocha", + "email": "lyndaknight@anocha.com", + "phone": "+1 (839) 579-3800", + "address": { + "street": 895, + "city": "Canoochee", + "state": "Georgia", + "zip": 9548 + }, + "about": "Adipisicing enim duis ipsum amet est ea magna qui tempor exercitation deserunt quis. Do duis laborum minim ullamco do eu enim nostrud dolor voluptate consectetur eu aliquip culpa. Reprehenderit non nisi nisi est exercitation eu ipsum Lorem mollit nulla cillum. Veniam deserunt reprehenderit ut mollit tempor aliquip duis ut. Ex do incididunt dolor enim. Fugiat laborum amet deserunt amet anim exercitation est.\r\n", + "registered": "2013-11-07T10:06:16+06:00", + "friends": [ + { + "id": 0, + "name": "Traci Calhoun" + }, + { + "id": 1, + "name": "Alice Joyce" + }, + { + "id": 2, + "name": "Bauer Reid" + } + ] + }, + { + "id": 387, + "guid": "059e107e-ef01-408e-87c6-e97ae729222c", + "isActive": false, + "balance": "$3,176.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Hardin Good", + "gender": "male", + "company": "Turnabout", + "email": "hardingood@turnabout.com", + "phone": "+1 (923) 588-2473", + "address": { + "street": 166, + "city": "Coral", + "state": "South Dakota", + "zip": 2566 + }, + "about": "Nostrud est fugiat incididunt veniam enim enim magna nulla. Nisi magna eiusmod magna deserunt dolore sit eu. Tempor aute esse cillum nostrud reprehenderit duis enim excepteur qui. Veniam anim et duis et laboris laboris do do sunt esse ipsum. Amet adipisicing esse non veniam voluptate minim exercitation esse ipsum aliquip dolore sunt. Ea dolor dolor culpa deserunt amet magna aliquip ea nostrud mollit fugiat.\r\n", + "registered": "2002-07-13T20:38:52+05:00", + "friends": [ + { + "id": 0, + "name": "Garrett Mathis" + }, + { + "id": 1, + "name": "Bonita Mack" + }, + { + "id": 2, + "name": "Lorrie Case" + } + ] + }, + { + "id": 388, + "guid": "e1e09f72-514a-4e14-acb1-c157153b82ff", + "isActive": false, + "balance": "$3,306.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Burns Howell", + "gender": "male", + "company": "Kage", + "email": "burnshowell@kage.com", + "phone": "+1 (913) 470-3976", + "address": { + "street": 483, + "city": "Connerton", + "state": "Colorado", + "zip": 2427 + }, + "about": "Non consequat nisi labore consectetur nostrud nisi. Eu esse et magna incididunt. Exercitation Lorem enim voluptate duis adipisicing commodo anim ut dolor. Irure qui minim nisi labore occaecat. Aliqua voluptate eiusmod voluptate cillum sint magna tempor sunt nostrud ea commodo minim ea.\r\n", + "registered": "1993-11-09T00:50:59+06:00", + "friends": [ + { + "id": 0, + "name": "Duke Battle" + }, + { + "id": 1, + "name": "Blanche Hinton" + }, + { + "id": 2, + "name": "Holly Walls" + } + ] + }, + { + "id": 389, + "guid": "e1f3c272-4f29-41d7-937c-4048a51854d2", + "isActive": true, + "balance": "$1,817.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Richard Roberts", + "gender": "male", + "company": "Zappix", + "email": "richardroberts@zappix.com", + "phone": "+1 (849) 515-2075", + "address": { + "street": 493, + "city": "Herald", + "state": "Virginia", + "zip": 441 + }, + "about": "Occaecat sit dolore aliquip nulla veniam ea duis anim labore cillum cupidatat. Eiusmod mollit ut aute ipsum non cupidatat. Qui deserunt ipsum voluptate fugiat do nisi cillum velit esse enim fugiat est. Ex irure veniam ea anim tempor enim ex magna. Culpa voluptate dolore ullamco proident tempor aute fugiat adipisicing mollit. Nostrud do officia consequat dolore ipsum excepteur irure ipsum nulla. Reprehenderit laboris aliqua deserunt aliquip dolore esse laboris consequat culpa.\r\n", + "registered": "1990-02-15T15:30:36+06:00", + "friends": [ + { + "id": 0, + "name": "Jennifer James" + }, + { + "id": 1, + "name": "Julie Stevens" + }, + { + "id": 2, + "name": "Griffith Melendez" + } + ] + }, + { + "id": 390, + "guid": "2e6c5f6a-4e13-48f9-867f-201ad575c3a0", + "isActive": true, + "balance": "$1,291.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Whitaker Graham", + "gender": "male", + "company": "Kengen", + "email": "whitakergraham@kengen.com", + "phone": "+1 (955) 454-3746", + "address": { + "street": 837, + "city": "Venice", + "state": "Michigan", + "zip": 4390 + }, + "about": "Officia sint est anim qui dolore sunt nostrud dolor sunt nostrud excepteur exercitation anim. Proident amet pariatur occaecat exercitation ad veniam eu. Ad cillum dolor consectetur nostrud do. Commodo et nostrud qui nulla anim cillum do. Qui labore ex est ex excepteur ullamco. Enim laborum sit nisi labore aliquip.\r\n", + "registered": "2004-06-15T13:24:24+05:00", + "friends": [ + { + "id": 0, + "name": "Ursula Holder" + }, + { + "id": 1, + "name": "Harrell Carrillo" + }, + { + "id": 2, + "name": "Sampson Chaney" + } + ] + }, + { + "id": 391, + "guid": "22316f09-0395-4946-a417-3eee3cc6ecbb", + "isActive": false, + "balance": "$3,872.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Blevins Newton", + "gender": "male", + "company": "Cytrex", + "email": "blevinsnewton@cytrex.com", + "phone": "+1 (988) 572-2413", + "address": { + "street": 311, + "city": "Fingerville", + "state": "Indiana", + "zip": 5341 + }, + "about": "Aute mollit esse nisi veniam. Proident ullamco ipsum eu nostrud veniam duis dolore occaecat aliqua dolore voluptate ipsum anim. Aute dolor ut consectetur ullamco amet dolor anim cupidatat consectetur magna anim.\r\n", + "registered": "2009-10-19T11:26:31+05:00", + "friends": [ + { + "id": 0, + "name": "Hopper Walker" + }, + { + "id": 1, + "name": "Boyle Spencer" + }, + { + "id": 2, + "name": "Janelle Figueroa" + } + ] + }, + { + "id": 392, + "guid": "583f5cda-e3a6-46a1-984e-25121907a0ce", + "isActive": false, + "balance": "$2,091.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Armstrong Sweeney", + "gender": "male", + "company": "Skinserve", + "email": "armstrongsweeney@skinserve.com", + "phone": "+1 (964) 587-3995", + "address": { + "street": 177, + "city": "Robinson", + "state": "Georgia", + "zip": 1995 + }, + "about": "Dolore et qui ea laborum anim sint fugiat ea nisi culpa elit. Qui laborum culpa fugiat cillum laboris do ipsum non duis amet ad. In ad adipisicing veniam aute cillum. Nulla exercitation sunt minim quis id cupidatat cillum dolore nostrud sint. Irure irure ipsum laborum sit mollit dolore fugiat amet. Enim cupidatat dolor occaecat deserunt eiusmod ad sint eu esse in mollit ullamco. Est ut consectetur anim ex et enim.\r\n", + "registered": "2008-11-17T02:30:29+06:00", + "friends": [ + { + "id": 0, + "name": "Ines Morrow" + }, + { + "id": 1, + "name": "Wade Pratt" + }, + { + "id": 2, + "name": "Rasmussen Robbins" + } + ] + }, + { + "id": 393, + "guid": "c4269a6f-7ddd-4545-b652-8312b62b3fe6", + "isActive": false, + "balance": "$3,420.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Fry Guerrero", + "gender": "male", + "company": "Ronelon", + "email": "fryguerrero@ronelon.com", + "phone": "+1 (941) 456-3863", + "address": { + "street": 429, + "city": "Boling", + "state": "Nebraska", + "zip": 1154 + }, + "about": "Adipisicing commodo occaecat et qui. Velit proident ullamco Lorem velit ex enim est culpa. Cupidatat proident non laborum Lorem. Exercitation deserunt aliquip labore ut laborum nulla ullamco ut. Amet ipsum ex do aliqua proident voluptate deserunt eiusmod pariatur ullamco ea laboris tempor. Deserunt minim non qui pariatur.\r\n", + "registered": "2009-12-04T06:16:24+06:00", + "friends": [ + { + "id": 0, + "name": "Jewell House" + }, + { + "id": 1, + "name": "Palmer Moss" + }, + { + "id": 2, + "name": "Vivian Nguyen" + } + ] + }, + { + "id": 394, + "guid": "29f23094-78dc-4059-825a-70f70391afa2", + "isActive": true, + "balance": "$1,327.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Rochelle Green", + "gender": "female", + "company": "Cinesanct", + "email": "rochellegreen@cinesanct.com", + "phone": "+1 (832) 492-3613", + "address": { + "street": 654, + "city": "Chical", + "state": "South Carolina", + "zip": 3171 + }, + "about": "Ex aliquip consectetur incididunt pariatur reprehenderit tempor ipsum magna. Minim culpa elit culpa sit id enim nostrud sit id aliquip quis occaecat est sint. Labore eu eiusmod incididunt Lorem ut mollit tempor. Occaecat nisi fugiat tempor esse enim aliquip aliqua ullamco ad eu tempor. Elit ipsum non non incididunt voluptate minim adipisicing pariatur duis Lorem occaecat quis.\r\n", + "registered": "1997-10-22T23:59:44+05:00", + "friends": [ + { + "id": 0, + "name": "Hunter Ayala" + }, + { + "id": 1, + "name": "Toni Kirk" + }, + { + "id": 2, + "name": "Cleveland Dennis" + } + ] + }, + { + "id": 395, + "guid": "f79ebb04-b152-4eb4-b5d5-9e391f896145", + "isActive": false, + "balance": "$1,030.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Terrell Maynard", + "gender": "male", + "company": "Coash", + "email": "terrellmaynard@coash.com", + "phone": "+1 (923) 412-2580", + "address": { + "street": 434, + "city": "Durham", + "state": "Vermont", + "zip": 2184 + }, + "about": "Aliquip anim est elit irure adipisicing culpa pariatur quis labore adipisicing nostrud proident qui. Ut ullamco fugiat pariatur deserunt amet proident id reprehenderit. Laborum tempor culpa pariatur officia ad sint velit deserunt officia deserunt ex ipsum officia. Elit officia reprehenderit duis consectetur eu officia id eu culpa nostrud magna. Sint ipsum ullamco duis velit.\r\n", + "registered": "2006-10-08T08:45:54+05:00", + "friends": [ + { + "id": 0, + "name": "Lawrence Daniels" + }, + { + "id": 1, + "name": "Manning Walker" + }, + { + "id": 2, + "name": "Annie Soto" + } + ] + }, + { + "id": 396, + "guid": "79b3c408-a7ab-4211-b7df-bf227183286e", + "isActive": true, + "balance": "$1,455.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Barr Walls", + "gender": "male", + "company": "Zensus", + "email": "barrwalls@zensus.com", + "phone": "+1 (820) 435-3575", + "address": { + "street": 566, + "city": "Whitewater", + "state": "Idaho", + "zip": 1863 + }, + "about": "Qui fugiat elit qui cillum tempor duis in magna exercitation. Aliquip nisi Lorem esse cupidatat sit fugiat et aliqua velit et nulla. Excepteur ut nulla pariatur in proident irure Lorem Lorem. Pariatur sint tempor cillum sunt ea eiusmod anim laboris quis ullamco labore officia incididunt labore. Enim cupidatat adipisicing sunt sint commodo non. Et nostrud est anim exercitation incididunt. Non nostrud quis laborum culpa non nostrud qui duis elit ullamco fugiat ex.\r\n", + "registered": "2013-09-06T09:21:36+05:00", + "friends": [ + { + "id": 0, + "name": "Willis Allen" + }, + { + "id": 1, + "name": "Lloyd Knowles" + }, + { + "id": 2, + "name": "Cathleen Weber" + } + ] + }, + { + "id": 397, + "guid": "75dc0b8e-c1e5-4173-aa7b-8a3db6283e57", + "isActive": true, + "balance": "$1,458.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Miranda Glass", + "gender": "female", + "company": "Rockyard", + "email": "mirandaglass@rockyard.com", + "phone": "+1 (982) 401-2227", + "address": { + "street": 612, + "city": "Joes", + "state": "Oregon", + "zip": 7524 + }, + "about": "Nisi labore deserunt magna velit amet Lorem. Occaecat duis consectetur aliqua veniam. Nisi excepteur labore nostrud esse consectetur excepteur ipsum deserunt Lorem sit. Voluptate consequat irure in veniam pariatur est voluptate officia ad enim ullamco. Ex consectetur et do ipsum consectetur quis ea cillum. Ullamco sit consequat ut nulla laboris anim.\r\n", + "registered": "1997-08-28T14:26:23+05:00", + "friends": [ + { + "id": 0, + "name": "Christine Hinton" + }, + { + "id": 1, + "name": "Rhodes Alston" + }, + { + "id": 2, + "name": "Carmen Mcdowell" + } + ] + }, + { + "id": 398, + "guid": "240db31d-a47e-4334-b900-fa4b4eec0076", + "isActive": true, + "balance": "$3,445.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Justine Mcfadden", + "gender": "female", + "company": "Quadeebo", + "email": "justinemcfadden@quadeebo.com", + "phone": "+1 (973) 551-2651", + "address": { + "street": 888, + "city": "Helen", + "state": "Virginia", + "zip": 9033 + }, + "about": "Eu ullamco laborum sunt culpa consequat dolor sit veniam. Laborum cupidatat magna occaecat labore quis sunt ipsum consectetur. Officia ipsum amet irure deserunt cillum exercitation sint nisi dolor. Proident ut minim reprehenderit mollit.\r\n", + "registered": "2011-09-04T22:40:41+05:00", + "friends": [ + { + "id": 0, + "name": "Elisa Sanchez" + }, + { + "id": 1, + "name": "Florence Peck" + }, + { + "id": 2, + "name": "Mona Avery" + } + ] + }, + { + "id": 399, + "guid": "1a0afc49-8fe4-4102-b924-a3115ceee67d", + "isActive": true, + "balance": "$1,182.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Eliza Avila", + "gender": "female", + "company": "Cablam", + "email": "elizaavila@cablam.com", + "phone": "+1 (867) 427-2739", + "address": { + "street": 470, + "city": "Glenville", + "state": "Kentucky", + "zip": 7538 + }, + "about": "Lorem fugiat exercitation id nulla veniam commodo eu id cupidatat cupidatat labore reprehenderit. Occaecat officia irure nisi irure anim irure Lorem pariatur anim magna. Sit non exercitation deserunt commodo ipsum labore velit commodo exercitation sint officia excepteur nisi qui. Incididunt ad sit veniam Lorem est exercitation.\r\n", + "registered": "2010-03-25T01:45:37+05:00", + "friends": [ + { + "id": 0, + "name": "Christa Hines" + }, + { + "id": 1, + "name": "Diane Barrera" + }, + { + "id": 2, + "name": "Harris Gallegos" + } + ] + }, + { + "id": 400, + "guid": "916568fc-9bf9-45b5-989e-ebc512c040af", + "isActive": false, + "balance": "$2,639.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Ashley Wheeler", + "gender": "female", + "company": "Enormo", + "email": "ashleywheeler@enormo.com", + "phone": "+1 (951) 535-3118", + "address": { + "street": 207, + "city": "Alderpoint", + "state": "Illinois", + "zip": 2708 + }, + "about": "Excepteur consectetur ipsum dolor do aliqua. Ullamco voluptate laboris laborum et quis. Veniam ullamco aliquip cupidatat sunt nulla nulla veniam consectetur aliqua minim occaecat eu. Ullamco do cupidatat sunt mollit voluptate voluptate.\r\n", + "registered": "2005-04-05T19:34:40+05:00", + "friends": [ + { + "id": 0, + "name": "Maude Terrell" + }, + { + "id": 1, + "name": "Laurie Cain" + }, + { + "id": 2, + "name": "Sutton Banks" + } + ] + }, + { + "id": 401, + "guid": "7065addc-0e35-4beb-a0d3-811ec331e04f", + "isActive": false, + "balance": "$2,326.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Alicia Chavez", + "gender": "female", + "company": "Stelaecor", + "email": "aliciachavez@stelaecor.com", + "phone": "+1 (973) 519-3035", + "address": { + "street": 267, + "city": "Titanic", + "state": "Pennsylvania", + "zip": 2292 + }, + "about": "Sint cupidatat proident anim duis nulla aute aute quis aliqua commodo. Velit aute id consequat esse eu. Consectetur nostrud nulla exercitation mollit. Irure duis ad ullamco nulla fugiat nulla commodo. Veniam irure est in ex ut excepteur qui nisi proident quis est sit veniam laborum. Ea sit culpa do ullamco consequat mollit. Proident exercitation cupidatat tempor incididunt labore ut dolore dolore ut in tempor esse.\r\n", + "registered": "2005-10-02T08:06:05+05:00", + "friends": [ + { + "id": 0, + "name": "Oneill Dean" + }, + { + "id": 1, + "name": "Mullins Case" + }, + { + "id": 2, + "name": "Smith Kirkland" + } + ] + }, + { + "id": 402, + "guid": "a8b0cfcd-f44c-464f-aeea-b8b2ec357dd1", + "isActive": false, + "balance": "$1,297.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Tiffany Hutchinson", + "gender": "female", + "company": "Pharmacon", + "email": "tiffanyhutchinson@pharmacon.com", + "phone": "+1 (971) 600-3477", + "address": { + "street": 681, + "city": "Ruffin", + "state": "Washington", + "zip": 5468 + }, + "about": "Eu aliquip veniam sit laborum tempor adipisicing esse aliqua consequat reprehenderit voluptate qui anim labore. Laboris exercitation minim anim officia aliqua laboris amet voluptate irure duis nisi elit Lorem. Nostrud amet duis eiusmod veniam proident ullamco. Aliquip ullamco amet ut elit aliquip nostrud incididunt nulla qui.\r\n", + "registered": "2013-12-24T09:31:45+06:00", + "friends": [ + { + "id": 0, + "name": "Georgette Maxwell" + }, + { + "id": 1, + "name": "Bowen Giles" + }, + { + "id": 2, + "name": "Klein Vincent" + } + ] + }, + { + "id": 403, + "guid": "bcd36ba2-e3df-4a14-a5f3-391d207ec09c", + "isActive": false, + "balance": "$2,319.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Rachel Hogan", + "gender": "female", + "company": "Coriander", + "email": "rachelhogan@coriander.com", + "phone": "+1 (945) 545-2620", + "address": { + "street": 120, + "city": "Evergreen", + "state": "Minnesota", + "zip": 635 + }, + "about": "Duis sunt pariatur enim enim veniam adipisicing dolor laborum do nulla irure aliqua. Minim excepteur excepteur aliqua id mollit occaecat cillum mollit veniam proident fugiat qui labore. Tempor deserunt ut do in aliqua dolor ipsum.\r\n", + "registered": "2006-08-12T09:19:58+05:00", + "friends": [ + { + "id": 0, + "name": "Aisha Ramos" + }, + { + "id": 1, + "name": "Tate Holcomb" + }, + { + "id": 2, + "name": "Stefanie Moon" + } + ] + }, + { + "id": 404, + "guid": "ee0d498a-0466-4e1d-b841-26d999e1710a", + "isActive": false, + "balance": "$2,827.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Jami Weeks", + "gender": "female", + "company": "Pasturia", + "email": "jamiweeks@pasturia.com", + "phone": "+1 (936) 600-3377", + "address": { + "street": 422, + "city": "Vernon", + "state": "Alaska", + "zip": 5165 + }, + "about": "Ut sint amet reprehenderit est officia in quis consequat commodo consequat do esse. Ex minim esse aliquip cupidatat deserunt adipisicing eu laboris nostrud. Enim anim sint dolore quis laboris occaecat mollit enim aute magna ipsum. Voluptate do cillum dolore eu elit nostrud enim labore. Occaecat aute veniam ullamco excepteur adipisicing consequat non ut dolore dolore veniam aliqua labore labore. Incididunt velit amet cupidatat ex anim aute cupidatat ad ad esse.\r\n", + "registered": "1990-07-30T14:36:47+05:00", + "friends": [ + { + "id": 0, + "name": "Nancy Crane" + }, + { + "id": 1, + "name": "Francesca Mcclain" + }, + { + "id": 2, + "name": "Goodwin Nolan" + } + ] + }, + { + "id": 405, + "guid": "be6d469c-5ff0-499d-83d4-b8762719e1c1", + "isActive": false, + "balance": "$1,373.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Ava Rosa", + "gender": "female", + "company": "Acium", + "email": "avarosa@acium.com", + "phone": "+1 (976) 595-3474", + "address": { + "street": 342, + "city": "Haring", + "state": "Indiana", + "zip": 1620 + }, + "about": "Ad minim aute aliqua laborum aliquip cupidatat incididunt reprehenderit aliquip dolore exercitation cupidatat occaecat. In ut mollit incididunt commodo ipsum fugiat est sit ipsum laborum irure quis et. Veniam occaecat commodo mollit labore consectetur ad tempor reprehenderit aute. Duis consequat et ex deserunt Lorem quis. Proident minim ad voluptate eu elit fugiat ex excepteur. Ipsum mollit deserunt officia magna cillum consequat tempor magna id duis labore.\r\n", + "registered": "1994-07-15T21:46:14+05:00", + "friends": [ + { + "id": 0, + "name": "Jacqueline Kirby" + }, + { + "id": 1, + "name": "Horne Marshall" + }, + { + "id": 2, + "name": "Jeri Mclaughlin" + } + ] + }, + { + "id": 406, + "guid": "3a0c9cbd-3113-4665-b755-273d1a91809c", + "isActive": false, + "balance": "$1,977.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Hudson Carter", + "gender": "male", + "company": "Conferia", + "email": "hudsoncarter@conferia.com", + "phone": "+1 (938) 525-3606", + "address": { + "street": 242, + "city": "Maxville", + "state": "Alabama", + "zip": 1161 + }, + "about": "Dolor dolore voluptate voluptate excepteur velit aliqua ipsum. Non in excepteur exercitation anim velit Lorem mollit enim sint sunt aute minim et dolor. Duis consequat ullamco et officia proident dolore culpa. Do consectetur qui quis aliqua sint id veniam culpa cupidatat enim dolor laborum aliqua pariatur.\r\n", + "registered": "1993-12-12T19:25:35+06:00", + "friends": [ + { + "id": 0, + "name": "Misty Hester" + }, + { + "id": 1, + "name": "Hubbard George" + }, + { + "id": 2, + "name": "Hicks Smith" + } + ] + }, + { + "id": 407, + "guid": "bf63259f-f434-496e-84af-89b7c1a59b96", + "isActive": false, + "balance": "$1,464.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Peggy Hodges", + "gender": "female", + "company": "Zilch", + "email": "peggyhodges@zilch.com", + "phone": "+1 (848) 451-3831", + "address": { + "street": 863, + "city": "Whipholt", + "state": "North Dakota", + "zip": 3221 + }, + "about": "Voluptate consequat consequat laboris tempor irure. Aute qui nulla elit laborum deserunt pariatur. Adipisicing velit mollit deserunt sit eu. Pariatur cillum sint pariatur mollit tempor quis id quis proident sunt est in.\r\n", + "registered": "2004-05-02T15:55:46+05:00", + "friends": [ + { + "id": 0, + "name": "Welch Zamora" + }, + { + "id": 1, + "name": "Barber Walter" + }, + { + "id": 2, + "name": "Tasha Mcbride" + } + ] + }, + { + "id": 408, + "guid": "0d438f8e-1c75-45d2-be03-987d197fd897", + "isActive": false, + "balance": "$3,210.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Chen Stout", + "gender": "male", + "company": "Ezentia", + "email": "chenstout@ezentia.com", + "phone": "+1 (897) 435-3773", + "address": { + "street": 258, + "city": "Cleary", + "state": "California", + "zip": 5228 + }, + "about": "Est ullamco laborum reprehenderit cillum amet ex tempor. Duis ut laborum veniam officia voluptate. Fugiat consectetur aliqua quis aliquip. Quis amet quis dolore Lorem deserunt quis ullamco mollit minim cillum mollit proident nulla et. Irure amet enim exercitation excepteur nostrud eu voluptate non irure aliquip sint. Quis ullamco enim consectetur aute labore consectetur dolor dolore nisi amet sunt. Ullamco officia culpa eu consectetur sunt aute ex sint anim tempor qui exercitation eiusmod.\r\n", + "registered": "2005-10-04T12:24:43+05:00", + "friends": [ + { + "id": 0, + "name": "Adele Clemons" + }, + { + "id": 1, + "name": "Mallory Johnson" + }, + { + "id": 2, + "name": "Moss Moran" + } + ] + }, + { + "id": 409, + "guid": "7b6c7c28-d7c8-42e5-97a9-14f1fe337d98", + "isActive": false, + "balance": "$3,706.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Juarez Rodriquez", + "gender": "male", + "company": "Zaggles", + "email": "juarezrodriquez@zaggles.com", + "phone": "+1 (861) 502-2931", + "address": { + "street": 722, + "city": "Marienthal", + "state": "New Jersey", + "zip": 9410 + }, + "about": "Mollit sunt anim ex ea ea aute amet ullamco eu. Irure veniam pariatur consequat dolore nulla qui irure pariatur aliqua. Nulla deserunt sint et in cupidatat ea nulla sunt in magna. Sit mollit do ad minim fugiat reprehenderit proident. Pariatur adipisicing fugiat veniam dolor anim incididunt laboris ut amet deserunt ut. Lorem magna mollit ea aute irure dolore Lorem est do mollit. Ut nostrud qui ex enim esse eiusmod.\r\n", + "registered": "1990-07-20T08:32:22+05:00", + "friends": [ + { + "id": 0, + "name": "Helga Brown" + }, + { + "id": 1, + "name": "Graves Tyler" + }, + { + "id": 2, + "name": "Best Cooper" + } + ] + }, + { + "id": 410, + "guid": "dc0b5e2e-85a0-4e21-a08f-c1011c5d1b82", + "isActive": false, + "balance": "$1,642.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Addie Fuller", + "gender": "female", + "company": "Zaphire", + "email": "addiefuller@zaphire.com", + "phone": "+1 (944) 532-2256", + "address": { + "street": 540, + "city": "Ryderwood", + "state": "Michigan", + "zip": 3914 + }, + "about": "Amet dolore proident pariatur ea labore incididunt sunt laboris. Duis est dolor laboris nostrud velit. Nulla irure excepteur consectetur aliquip consequat. Eiusmod dolor et elit voluptate duis.\r\n", + "registered": "2012-06-24T00:59:19+05:00", + "friends": [ + { + "id": 0, + "name": "Russo Bruce" + }, + { + "id": 1, + "name": "Nettie Porter" + }, + { + "id": 2, + "name": "Valerie Mcintyre" + } + ] + }, + { + "id": 411, + "guid": "f469138e-f17a-4624-bd73-d9aaa54fea80", + "isActive": true, + "balance": "$3,787.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Osborn Grant", + "gender": "male", + "company": "Harmoney", + "email": "osborngrant@harmoney.com", + "phone": "+1 (992) 402-3556", + "address": { + "street": 492, + "city": "Emerald", + "state": "Hawaii", + "zip": 9488 + }, + "about": "Quis cillum sunt commodo commodo ullamco. Ut cupidatat nostrud sit quis. Voluptate mollit ex voluptate eu excepteur voluptate cillum. Reprehenderit amet non est ipsum. Enim qui culpa irure culpa excepteur ad ea exercitation. Velit voluptate ea sint mollit est enim quis tempor nulla.\r\n", + "registered": "1989-09-01T10:33:52+05:00", + "friends": [ + { + "id": 0, + "name": "Ora Compton" + }, + { + "id": 1, + "name": "Jordan Rivera" + }, + { + "id": 2, + "name": "Kristie Dickerson" + } + ] + }, + { + "id": 412, + "guid": "2dbe8feb-7208-47a6-afb6-d19a27e01e2f", + "isActive": false, + "balance": "$3,944.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Hancock Ballard", + "gender": "male", + "company": "Flexigen", + "email": "hancockballard@flexigen.com", + "phone": "+1 (806) 517-3354", + "address": { + "street": 881, + "city": "Duryea", + "state": "Missouri", + "zip": 6615 + }, + "about": "Culpa aliqua laborum deserunt laboris Lorem aliqua consequat do et do cillum dolor incididunt est. Elit velit occaecat nostrud ex voluptate nulla ut cillum do labore amet. Sint ipsum adipisicing sunt ut adipisicing sint aute nulla consectetur magna officia esse minim. Sit qui pariatur id proident sint officia proident irure exercitation. Proident do commodo nisi proident mollit culpa aliquip cupidatat Lorem ex. Cillum cupidatat occaecat sit veniam qui proident commodo velit proident cupidatat. Id laboris irure in cupidatat et proident et elit mollit voluptate.\r\n", + "registered": "2010-01-07T17:17:09+06:00", + "friends": [ + { + "id": 0, + "name": "Dana Kim" + }, + { + "id": 1, + "name": "Hatfield Larsen" + }, + { + "id": 2, + "name": "Cara Gill" + } + ] + }, + { + "id": 413, + "guid": "3ac2e889-55c5-4aa3-b78d-107e7c6aa0c1", + "isActive": false, + "balance": "$1,152.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Angel Bauer", + "gender": "female", + "company": "Rodemco", + "email": "angelbauer@rodemco.com", + "phone": "+1 (890) 406-2360", + "address": { + "street": 970, + "city": "Templeton", + "state": "Wyoming", + "zip": 8494 + }, + "about": "Est tempor cupidatat est ea laborum excepteur deserunt cillum anim. Culpa laboris occaecat pariatur laboris deserunt nisi. Sunt do esse consequat amet eu velit aliqua nulla pariatur ex ex irure qui. Labore reprehenderit laborum nisi ipsum pariatur ea non aute. Sint qui ipsum veniam officia do veniam et qui amet minim magna mollit magna.\r\n", + "registered": "1998-05-19T05:36:48+05:00", + "friends": [ + { + "id": 0, + "name": "Araceli Whitley" + }, + { + "id": 1, + "name": "Vargas Rojas" + }, + { + "id": 2, + "name": "Watkins Brennan" + } + ] + }, + { + "id": 414, + "guid": "5d972a11-21ee-4425-8786-03f5c5f77804", + "isActive": false, + "balance": "$2,077.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Lorena Herrera", + "gender": "female", + "company": "Katakana", + "email": "lorenaherrera@katakana.com", + "phone": "+1 (898) 422-2223", + "address": { + "street": 853, + "city": "Chilton", + "state": "South Dakota", + "zip": 1029 + }, + "about": "Ea ipsum amet laborum magna dolore est ipsum consectetur voluptate quis enim esse occaecat. Cillum pariatur reprehenderit quis qui culpa. Amet cillum duis duis irure proident esse mollit anim magna proident voluptate culpa cupidatat. Laboris pariatur veniam tempor consequat cillum sit consequat veniam exercitation fugiat eu reprehenderit ex cupidatat. Consequat ut culpa ut voluptate Lorem et est dolore cupidatat elit ipsum occaecat. Ad non labore Lorem occaecat veniam aute do aliqua ad do commodo pariatur. Nostrud sint consectetur commodo cillum.\r\n", + "registered": "1997-12-23T16:01:46+06:00", + "friends": [ + { + "id": 0, + "name": "Jacklyn Byers" + }, + { + "id": 1, + "name": "Thornton Robinson" + }, + { + "id": 2, + "name": "Oliver Holman" + } + ] + }, + { + "id": 415, + "guid": "37537d17-c15a-4d71-be45-104ac05db02a", + "isActive": true, + "balance": "$2,479.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Concetta Oneal", + "gender": "female", + "company": "Jimbies", + "email": "concettaoneal@jimbies.com", + "phone": "+1 (884) 418-2374", + "address": { + "street": 715, + "city": "Hebron", + "state": "Maryland", + "zip": 2996 + }, + "about": "Veniam proident ea consectetur esse consectetur veniam incididunt aliquip aliquip cupidatat. Elit reprehenderit Lorem aute eiusmod labore occaecat ad. Reprehenderit exercitation reprehenderit culpa esse culpa. Sit deserunt deserunt incididunt irure proident ut nostrud.\r\n", + "registered": "2000-02-26T13:52:51+06:00", + "friends": [ + { + "id": 0, + "name": "Claudette Chase" + }, + { + "id": 1, + "name": "Sawyer Mcgowan" + }, + { + "id": 2, + "name": "Katheryn Blackwell" + } + ] + }, + { + "id": 416, + "guid": "262a4a1b-4fce-4e7b-96dc-853e884f0438", + "isActive": false, + "balance": "$3,392.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Clements Mercer", + "gender": "male", + "company": "Exodoc", + "email": "clementsmercer@exodoc.com", + "phone": "+1 (850) 402-2064", + "address": { + "street": 659, + "city": "Tivoli", + "state": "Iowa", + "zip": 9489 + }, + "about": "Non ullamco veniam labore excepteur exercitation. Commodo officia velit amet qui aliqua magna consequat elit dolor esse non dolore labore veniam. Ut fugiat mollit consectetur non nulla. Consequat sunt commodo cupidatat enim anim ea labore sunt. Elit exercitation ullamco dolore cillum aliquip aliqua. Veniam minim magna officia eu proident.\r\n", + "registered": "2002-08-28T12:28:15+05:00", + "friends": [ + { + "id": 0, + "name": "Glenn Carney" + }, + { + "id": 1, + "name": "Graciela Sargent" + }, + { + "id": 2, + "name": "Suarez Taylor" + } + ] + }, + { + "id": 417, + "guid": "19451b8d-fbc8-415b-8741-11bf4c2ed01b", + "isActive": false, + "balance": "$3,015.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Tammie Maldonado", + "gender": "female", + "company": "Zizzle", + "email": "tammiemaldonado@zizzle.com", + "phone": "+1 (874) 574-2562", + "address": { + "street": 889, + "city": "Sanders", + "state": "West Virginia", + "zip": 1375 + }, + "about": "Deserunt incididunt sunt in quis dolore Lorem pariatur occaecat anim consectetur. Sunt aliquip nisi sint excepteur commodo. Minim ex ullamco incididunt qui ea elit occaecat eu.\r\n", + "registered": "1994-11-19T04:07:20+06:00", + "friends": [ + { + "id": 0, + "name": "Ernestine Buck" + }, + { + "id": 1, + "name": "Mcknight Gibbs" + }, + { + "id": 2, + "name": "Jeannie Ortega" + } + ] + }, + { + "id": 418, + "guid": "5af35cd4-32bf-4ac0-b0cd-b0945ef5130c", + "isActive": false, + "balance": "$3,772.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Mcdonald Olson", + "gender": "male", + "company": "Quarx", + "email": "mcdonaldolson@quarx.com", + "phone": "+1 (928) 557-3710", + "address": { + "street": 914, + "city": "Benson", + "state": "Nevada", + "zip": 8782 + }, + "about": "Amet cillum deserunt aute exercitation labore officia elit elit voluptate laborum fugiat in. Aute non aliquip tempor in proident sit dolore laboris nostrud fugiat. Duis irure sint esse tempor ex eiusmod aute ea laboris sit ipsum cupidatat labore velit. Labore culpa duis nulla excepteur officia qui eiusmod ullamco proident dolor.\r\n", + "registered": "2004-06-18T03:49:03+05:00", + "friends": [ + { + "id": 0, + "name": "Ann Flynn" + }, + { + "id": 1, + "name": "Bradford Robertson" + }, + { + "id": 2, + "name": "Alyson Finch" + } + ] + }, + { + "id": 419, + "guid": "d0c02dca-1943-4575-aafe-ff79e37d774a", + "isActive": false, + "balance": "$3,473.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Lynne Griffin", + "gender": "female", + "company": "Exostream", + "email": "lynnegriffin@exostream.com", + "phone": "+1 (887) 490-3581", + "address": { + "street": 588, + "city": "Lupton", + "state": "Ohio", + "zip": 6493 + }, + "about": "Consectetur aliquip ex ex ex ipsum labore elit. Ut eu esse cillum enim esse enim laborum enim consectetur ad fugiat consectetur. Ea esse anim cillum consectetur velit id aliqua consequat veniam do non incididunt quis amet.\r\n", + "registered": "2007-07-20T13:25:03+05:00", + "friends": [ + { + "id": 0, + "name": "Booth Velazquez" + }, + { + "id": 1, + "name": "Phillips Chaney" + }, + { + "id": 2, + "name": "Moreno Burton" + } + ] + }, + { + "id": 420, + "guid": "5593973a-e608-47c7-ab27-5eea0329f576", + "isActive": false, + "balance": "$2,093.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Gentry Dickson", + "gender": "male", + "company": "Emoltra", + "email": "gentrydickson@emoltra.com", + "phone": "+1 (977) 500-2737", + "address": { + "street": 141, + "city": "Biehle", + "state": "Texas", + "zip": 5361 + }, + "about": "Deserunt reprehenderit proident esse exercitation consectetur dolore sint laboris nostrud officia minim consequat consectetur irure. Eu occaecat do ex minim ad. Officia adipisicing magna cillum magna. Est aute non laboris sit dolor ad culpa ipsum nisi eu non do excepteur elit.\r\n", + "registered": "2002-10-06T16:55:25+05:00", + "friends": [ + { + "id": 0, + "name": "Lakisha Snow" + }, + { + "id": 1, + "name": "Glenda Petty" + }, + { + "id": 2, + "name": "Kendra Diaz" + } + ] + }, + { + "id": 421, + "guid": "e2d4bb55-6d70-446d-b27b-ff3ab601f119", + "isActive": true, + "balance": "$3,576.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Duke Fowler", + "gender": "male", + "company": "Konnect", + "email": "dukefowler@konnect.com", + "phone": "+1 (974) 449-2378", + "address": { + "street": 596, + "city": "Draper", + "state": "Rhode Island", + "zip": 820 + }, + "about": "Commodo esse deserunt duis id elit id est commodo dolor nostrud. Cupidatat excepteur irure ea ea ipsum pariatur Lorem tempor tempor esse eu in reprehenderit. Sunt incididunt nulla est enim duis eu excepteur.\r\n", + "registered": "1993-06-24T16:58:20+05:00", + "friends": [ + { + "id": 0, + "name": "Mills Wallace" + }, + { + "id": 1, + "name": "Houston Pacheco" + }, + { + "id": 2, + "name": "Rachelle Castillo" + } + ] + }, + { + "id": 422, + "guid": "01d850ea-4182-4ef5-a86c-b03ae185ed69", + "isActive": true, + "balance": "$1,149.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Anna Potts", + "gender": "female", + "company": "Keengen", + "email": "annapotts@keengen.com", + "phone": "+1 (960) 445-3163", + "address": { + "street": 711, + "city": "Enetai", + "state": "Kansas", + "zip": 5243 + }, + "about": "Eiusmod anim anim eu occaecat. Adipisicing sunt nulla ex commodo voluptate consectetur aliqua duis aliquip Lorem quis velit. Nulla ut tempor velit aliquip exercitation ea incididunt consequat veniam consectetur irure occaecat nulla. Veniam ullamco sit elit quis exercitation. Magna ex eiusmod do qui dolor occaecat minim laborum esse dolore aliqua eu voluptate. Et commodo nostrud velit culpa duis ad. Incididunt officia magna quis est ad cupidatat proident occaecat.\r\n", + "registered": "1998-07-08T06:45:56+05:00", + "friends": [ + { + "id": 0, + "name": "Allison Preston" + }, + { + "id": 1, + "name": "Amber Cline" + }, + { + "id": 2, + "name": "Olsen Leach" + } + ] + }, + { + "id": 423, + "guid": "55133bfd-5909-43e0-af34-289024e5ca66", + "isActive": true, + "balance": "$1,015.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Veronica Alford", + "gender": "female", + "company": "Netbook", + "email": "veronicaalford@netbook.com", + "phone": "+1 (892) 547-2004", + "address": { + "street": 795, + "city": "Bartley", + "state": "Louisiana", + "zip": 6529 + }, + "about": "Id id amet ex aliquip nostrud tempor. Nulla ut incididunt et magna id. Aliqua minim consectetur duis duis veniam elit non adipisicing cillum ipsum sit esse id.\r\n", + "registered": "2011-06-20T09:23:02+05:00", + "friends": [ + { + "id": 0, + "name": "Kim Lopez" + }, + { + "id": 1, + "name": "Shelia Owen" + }, + { + "id": 2, + "name": "Sykes Doyle" + } + ] + }, + { + "id": 424, + "guid": "eb3e8991-3701-49ff-ad95-6bbec519e1b3", + "isActive": false, + "balance": "$3,515.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Gail Simmons", + "gender": "female", + "company": "Uplinx", + "email": "gailsimmons@uplinx.com", + "phone": "+1 (815) 432-2986", + "address": { + "street": 176, + "city": "Ezel", + "state": "Montana", + "zip": 4705 + }, + "about": "Cupidatat ea laborum reprehenderit exercitation duis quis ex qui reprehenderit laborum aliquip enim nulla ex. Magna laboris labore occaecat sit anim nostrud culpa culpa. Aliqua in et officia dolor anim proident nisi proident esse enim dolor nulla elit. Reprehenderit cupidatat duis elit dolor commodo tempor ipsum reprehenderit. Quis non culpa officia excepteur reprehenderit magna magna veniam eiusmod consectetur veniam consequat exercitation eiusmod. Proident veniam enim commodo enim ipsum veniam ex adipisicing laborum irure minim quis in.\r\n", + "registered": "2008-06-30T13:37:25+05:00", + "friends": [ + { + "id": 0, + "name": "Phyllis Mccarty" + }, + { + "id": 1, + "name": "Morgan Cherry" + }, + { + "id": 2, + "name": "Horn Savage" + } + ] + }, + { + "id": 425, + "guid": "3f94a290-2ab1-4d22-aa5a-ffe5610ab190", + "isActive": true, + "balance": "$1,603.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Martha Copeland", + "gender": "female", + "company": "Earthplex", + "email": "marthacopeland@earthplex.com", + "phone": "+1 (996) 548-2153", + "address": { + "street": 892, + "city": "Abrams", + "state": "Utah", + "zip": 6631 + }, + "about": "Quis velit nisi ut commodo cillum adipisicing ea minim officia. Cillum labore occaecat laborum nulla. In mollit excepteur dolore consectetur amet sunt minim. Aliquip consequat eu nulla sint fugiat est occaecat in adipisicing sint. Amet non nostrud qui minim dolor. Tempor labore laboris laboris id voluptate tempor. Deserunt nulla id dolore deserunt cillum laboris.\r\n", + "registered": "2009-05-31T15:24:33+05:00", + "friends": [ + { + "id": 0, + "name": "Rowland Bailey" + }, + { + "id": 1, + "name": "Mclean May" + }, + { + "id": 2, + "name": "Marguerite Holland" + } + ] + }, + { + "id": 426, + "guid": "0eae8bb5-d94b-40a2-91d1-85d2df68efe3", + "isActive": false, + "balance": "$1,895.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Witt Rios", + "gender": "male", + "company": "Eschoir", + "email": "wittrios@eschoir.com", + "phone": "+1 (968) 580-2559", + "address": { + "street": 609, + "city": "Ballico", + "state": "New York", + "zip": 5533 + }, + "about": "Sunt ipsum do anim et exercitation ullamco ea occaecat exercitation magna. Duis Lorem ex cillum exercitation mollit est sint tempor anim pariatur. Dolore officia incididunt sunt cillum ullamco cillum officia exercitation nulla exercitation ut. Do aliquip deserunt sint reprehenderit ad qui exercitation excepteur reprehenderit. Pariatur labore esse Lorem aliqua amet eiusmod voluptate excepteur aute cillum. Dolor consequat dolor ad nostrud incididunt laborum.\r\n", + "registered": "2007-04-26T00:47:49+05:00", + "friends": [ + { + "id": 0, + "name": "Marcie Boyle" + }, + { + "id": 1, + "name": "Tillman Phillips" + }, + { + "id": 2, + "name": "Sullivan Hebert" + } + ] + }, + { + "id": 427, + "guid": "353c0425-ae55-493e-97b7-42409f239cd4", + "isActive": true, + "balance": "$3,996.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Tammy Manning", + "gender": "female", + "company": "Kraggle", + "email": "tammymanning@kraggle.com", + "phone": "+1 (826) 506-2586", + "address": { + "street": 825, + "city": "Matthews", + "state": "Oklahoma", + "zip": 5096 + }, + "about": "Id ipsum reprehenderit reprehenderit duis cupidatat officia tempor. Mollit incididunt proident ex ut anim ipsum id aliquip officia excepteur labore. Velit enim est cillum magna excepteur.\r\n", + "registered": "1995-10-31T13:06:18+05:00", + "friends": [ + { + "id": 0, + "name": "Ward Huber" + }, + { + "id": 1, + "name": "Becker Mayo" + }, + { + "id": 2, + "name": "Langley Clarke" + } + ] + }, + { + "id": 428, + "guid": "0a1549b3-524c-4ab4-bd78-098865639a4a", + "isActive": false, + "balance": "$3,227.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Mable Spence", + "gender": "female", + "company": "Biospan", + "email": "mablespence@biospan.com", + "phone": "+1 (992) 598-3588", + "address": { + "street": 819, + "city": "Libertytown", + "state": "Arkansas", + "zip": 6810 + }, + "about": "Commodo amet consectetur consequat ullamco eu velit deserunt amet. Veniam duis nulla eiusmod sit ex proident mollit irure velit duis. Amet duis cillum aliqua consequat veniam minim eiusmod veniam ipsum eu incididunt proident irure. Do in reprehenderit do ex consequat velit id eiusmod consectetur irure magna.\r\n", + "registered": "2003-11-07T09:57:35+06:00", + "friends": [ + { + "id": 0, + "name": "Elvia Prince" + }, + { + "id": 1, + "name": "Rosalinda West" + }, + { + "id": 2, + "name": "Alba Mitchell" + } + ] + }, + { + "id": 429, + "guid": "e33f8c8d-febb-413b-bba1-763bb972da7b", + "isActive": false, + "balance": "$1,003.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Iva Hudson", + "gender": "female", + "company": "Netplax", + "email": "ivahudson@netplax.com", + "phone": "+1 (806) 577-3457", + "address": { + "street": 168, + "city": "Toftrees", + "state": "Connecticut", + "zip": 3848 + }, + "about": "Aliqua reprehenderit ad est nulla adipisicing dolore sunt enim nulla laboris excepteur reprehenderit quis. Cillum adipisicing commodo est tempor magna proident mollit amet enim. Est quis tempor aliqua cupidatat velit proident ullamco cupidatat magna. Duis veniam Lorem ad enim do sint duis enim velit labore proident culpa fugiat quis. Tempor irure veniam fugiat nulla eu cupidatat ut tempor. Velit magna esse eu do id consectetur dolore duis laborum. Veniam pariatur consequat veniam proident officia ex deserunt id.\r\n", + "registered": "2013-04-18T16:05:38+05:00", + "friends": [ + { + "id": 0, + "name": "Lora Foley" + }, + { + "id": 1, + "name": "Compton Nieves" + }, + { + "id": 2, + "name": "Melinda Leblanc" + } + ] + }, + { + "id": 430, + "guid": "0d5e5c91-9c6d-4b73-b696-10b022512a48", + "isActive": false, + "balance": "$2,887.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Pearl Colon", + "gender": "female", + "company": "Exovent", + "email": "pearlcolon@exovent.com", + "phone": "+1 (858) 550-3247", + "address": { + "street": 718, + "city": "Itmann", + "state": "Mississippi", + "zip": 1394 + }, + "about": "Ut mollit eu irure dolore nostrud irure cupidatat culpa esse laborum. Velit quis anim laboris ut ut et eu do dolor laborum amet labore magna ad. Amet aliqua dolore tempor commodo occaecat proident consequat est mollit.\r\n", + "registered": "1995-10-21T07:14:20+05:00", + "friends": [ + { + "id": 0, + "name": "Stanton Dunn" + }, + { + "id": 1, + "name": "Kim Lucas" + }, + { + "id": 2, + "name": "Patrick Stephens" + } + ] + }, + { + "id": 431, + "guid": "246d7af9-fd46-40a1-9b9e-d7b1ecb2f047", + "isActive": false, + "balance": "$2,803.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Ofelia Edwards", + "gender": "female", + "company": "Menbrain", + "email": "ofeliaedwards@menbrain.com", + "phone": "+1 (839) 597-3739", + "address": { + "street": 518, + "city": "Chelsea", + "state": "Florida", + "zip": 3940 + }, + "about": "Deserunt sunt anim veniam qui id cupidatat aliqua est. Irure veniam id dolor ipsum incididunt Lorem fugiat quis id. Lorem ipsum eu velit sint aliquip duis eu.\r\n", + "registered": "2013-08-08T07:19:56+05:00", + "friends": [ + { + "id": 0, + "name": "Davis Estrada" + }, + { + "id": 1, + "name": "Gracie Fernandez" + }, + { + "id": 2, + "name": "House Paul" + } + ] + }, + { + "id": 432, + "guid": "f9998290-c938-402d-b72b-ccd0405f394e", + "isActive": true, + "balance": "$3,832.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Prince Benton", + "gender": "male", + "company": "Zaj", + "email": "princebenton@zaj.com", + "phone": "+1 (934) 506-2158", + "address": { + "street": 630, + "city": "Omar", + "state": "Tennessee", + "zip": 495 + }, + "about": "Do adipisicing id dolore esse dolore fugiat dolor anim culpa non sint enim fugiat elit. Occaecat ex do ex velit proident sint id. Minim non consectetur Lorem laboris voluptate sint aute. Lorem id esse fugiat id ut ad est velit proident id ea ex velit aute. Do voluptate consequat eu nostrud officia.\r\n", + "registered": "2009-03-27T16:26:55+05:00", + "friends": [ + { + "id": 0, + "name": "Rosie Melton" + }, + { + "id": 1, + "name": "Slater Patton" + }, + { + "id": 2, + "name": "Lilian Benson" + } + ] + }, + { + "id": 433, + "guid": "f1dff9dd-c375-4b17-8ade-e40438434c7f", + "isActive": false, + "balance": "$3,976.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Maryanne Aguilar", + "gender": "female", + "company": "Plasto", + "email": "maryanneaguilar@plasto.com", + "phone": "+1 (848) 498-3221", + "address": { + "street": 842, + "city": "Hinsdale", + "state": "Arizona", + "zip": 2563 + }, + "about": "Exercitation excepteur enim mollit aliqua occaecat ut qui veniam sit sint eiusmod minim irure. Amet dolor in laborum culpa quis. Nostrud exercitation nostrud fugiat veniam incididunt Lorem laboris. Ad proident proident elit duis consectetur tempor veniam. Eiusmod deserunt non proident pariatur.\r\n", + "registered": "2001-07-28T01:05:27+05:00", + "friends": [ + { + "id": 0, + "name": "Cleo Schmidt" + }, + { + "id": 1, + "name": "Christie Reeves" + }, + { + "id": 2, + "name": "Webb Bass" + } + ] + }, + { + "id": 434, + "guid": "25356d31-f5bd-44de-9c41-7b50094f61ae", + "isActive": false, + "balance": "$2,732.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Kristy Ward", + "gender": "female", + "company": "Furnigeer", + "email": "kristyward@furnigeer.com", + "phone": "+1 (934) 598-2924", + "address": { + "street": 437, + "city": "Cascades", + "state": "Massachusetts", + "zip": 3966 + }, + "about": "Incididunt ad nulla non sunt. Laborum est veniam proident minim Lorem elit labore. Eiusmod quis id culpa consequat aute dolor sunt id exercitation. Eu mollit officia dolore ad. Id excepteur quis ut officia nisi laborum. Consectetur do aliquip ea Lorem eiusmod aliqua.\r\n", + "registered": "2010-05-04T11:14:23+05:00", + "friends": [ + { + "id": 0, + "name": "Eloise Kerr" + }, + { + "id": 1, + "name": "Keller Montgomery" + }, + { + "id": 2, + "name": "Dyer Page" + } + ] + }, + { + "id": 435, + "guid": "5d3898fa-4b9f-4f13-b3e1-caef8793511f", + "isActive": false, + "balance": "$3,844.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Blake Sharp", + "gender": "male", + "company": "Digigene", + "email": "blakesharp@digigene.com", + "phone": "+1 (997) 540-3371", + "address": { + "street": 745, + "city": "Kennedyville", + "state": "North Carolina", + "zip": 5613 + }, + "about": "Consectetur ea consequat elit eiusmod dolore. Do mollit ut irure occaecat. Sit officia laboris pariatur ullamco tempor cillum velit laborum est mollit deserunt. Magna ullamco esse do laboris non et incididunt ex ea dolore. In non tempor est minim nulla enim consequat. Qui deserunt excepteur esse cupidatat nisi anim ad adipisicing tempor.\r\n", + "registered": "2007-03-06T03:55:02+06:00", + "friends": [ + { + "id": 0, + "name": "Bonnie Garner" + }, + { + "id": 1, + "name": "Maldonado Bates" + }, + { + "id": 2, + "name": "Merrill Stone" + } + ] + }, + { + "id": 436, + "guid": "345b8fae-7994-42f8-a62a-7209caf25882", + "isActive": true, + "balance": "$1,360.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Kennedy Williams", + "gender": "male", + "company": "Twiggery", + "email": "kennedywilliams@twiggery.com", + "phone": "+1 (881) 508-2825", + "address": { + "street": 785, + "city": "Santel", + "state": "Wisconsin", + "zip": 5910 + }, + "about": "Nulla eiusmod incididunt dolor aute adipisicing mollit. Labore nulla qui esse qui est id elit nisi nostrud quis deserunt amet qui. Est incididunt incididunt minim nulla Lorem officia magna occaecat. Culpa nisi labore eiusmod amet occaecat eu eu enim. Laboris ipsum irure enim dolor incididunt. Incididunt dolore aute labore in incididunt eiusmod consectetur veniam duis incididunt officia ipsum.\r\n", + "registered": "2005-09-03T03:47:39+05:00", + "friends": [ + { + "id": 0, + "name": "Mathis Salas" + }, + { + "id": 1, + "name": "Wood Oliver" + }, + { + "id": 2, + "name": "Rose Conrad" + } + ] + }, + { + "id": 437, + "guid": "b25f2220-6943-46dd-b70a-9936d9aa7a90", + "isActive": true, + "balance": "$3,975.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Aurora Hill", + "gender": "female", + "company": "Yurture", + "email": "aurorahill@yurture.com", + "phone": "+1 (840) 544-3898", + "address": { + "street": 745, + "city": "Beyerville", + "state": "New Hampshire", + "zip": 8758 + }, + "about": "Ea cupidatat aliquip Lorem ea officia officia deserunt et nostrud consequat laboris consequat occaecat. Cupidatat in ut commodo sit sint pariatur anim anim ut laboris do magna. Veniam eiusmod cupidatat id non anim in ipsum cupidatat.\r\n", + "registered": "1996-08-18T12:27:29+05:00", + "friends": [ + { + "id": 0, + "name": "Cortez Berry" + }, + { + "id": 1, + "name": "Valeria Kinney" + }, + { + "id": 2, + "name": "Kenya Dawson" + } + ] + }, + { + "id": 438, + "guid": "a1cb3b16-66c5-420d-be76-cc869922d698", + "isActive": true, + "balance": "$1,883.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Laura Logan", + "gender": "female", + "company": "Vortexaco", + "email": "lauralogan@vortexaco.com", + "phone": "+1 (855) 480-2690", + "address": { + "street": 557, + "city": "Echo", + "state": "Maine", + "zip": 8928 + }, + "about": "Ex commodo elit reprehenderit esse fugiat. Reprehenderit esse irure irure minim commodo esse dolor id nostrud ad ipsum id pariatur. Consequat incididunt elit cupidatat magna proident nisi id eiusmod Lorem ad nisi. Non eiusmod cillum aliqua anim magna duis enim aute dolor commodo.\r\n", + "registered": "2009-02-08T12:42:11+06:00", + "friends": [ + { + "id": 0, + "name": "Caldwell Decker" + }, + { + "id": 1, + "name": "Ortiz Gay" + }, + { + "id": 2, + "name": "Banks Bright" + } + ] + }, + { + "id": 439, + "guid": "bd4043f5-3005-4e8d-9dbb-6690ce602d2c", + "isActive": false, + "balance": "$1,013.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Joy Rutledge", + "gender": "female", + "company": "Maximind", + "email": "joyrutledge@maximind.com", + "phone": "+1 (864) 478-3884", + "address": { + "street": 138, + "city": "Machias", + "state": "Delaware", + "zip": 1654 + }, + "about": "Irure commodo consequat adipisicing esse sint officia reprehenderit nostrud laboris elit nostrud dolor ea. Mollit esse ex cillum cupidatat consequat. Exercitation excepteur in fugiat veniam duis adipisicing fugiat veniam. Sint sit quis quis minim et fugiat pariatur aliqua magna pariatur pariatur voluptate. Aliquip velit incididunt non deserunt ad exercitation quis velit quis cupidatat ipsum elit. Ex nisi esse culpa non dolor sint tempor qui veniam dolore. Voluptate deserunt exercitation ullamco nulla mollit elit fugiat.\r\n", + "registered": "2011-10-03T20:26:17+05:00", + "friends": [ + { + "id": 0, + "name": "Manuela Ruiz" + }, + { + "id": 1, + "name": "Howe Hernandez" + }, + { + "id": 2, + "name": "Natasha Estes" + } + ] + }, + { + "id": 440, + "guid": "9cc9dda4-e78d-4cb3-9bb0-10d002a076c0", + "isActive": true, + "balance": "$3,251.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Felecia Butler", + "gender": "female", + "company": "Newcube", + "email": "feleciabutler@newcube.com", + "phone": "+1 (842) 457-3691", + "address": { + "street": 253, + "city": "Tryon", + "state": "Colorado", + "zip": 5792 + }, + "about": "Eu id non voluptate ullamco mollit eiusmod ut id minim minim sunt magna voluptate. Tempor in reprehenderit tempor in tempor ullamco amet. Consequat Lorem in eu velit reprehenderit ut reprehenderit duis voluptate cillum reprehenderit tempor cupidatat. Do consectetur quis adipisicing do laboris occaecat non aliqua eiusmod sit eu. Pariatur exercitation voluptate cillum eiusmod cillum. Commodo aliqua veniam pariatur elit aute fugiat magna aute laboris laboris ipsum cupidatat.\r\n", + "registered": "1993-08-09T06:05:06+05:00", + "friends": [ + { + "id": 0, + "name": "Angelia Romero" + }, + { + "id": 1, + "name": "Gayle Shannon" + }, + { + "id": 2, + "name": "Dale Haynes" + } + ] + }, + { + "id": 441, + "guid": "26b4f0e5-40e9-46f5-b045-75792224d3fb", + "isActive": false, + "balance": "$2,237.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Johanna Thornton", + "gender": "female", + "company": "Kidgrease", + "email": "johannathornton@kidgrease.com", + "phone": "+1 (923) 549-3711", + "address": { + "street": 120, + "city": "Thynedale", + "state": "Hawaii", + "zip": 4775 + }, + "about": "Consequat sunt ut consequat in mollit. Enim id ipsum proident cupidatat aliqua est proident aliqua nisi quis irure. Excepteur enim tempor ex nulla ad nostrud velit. Do culpa ad nostrud voluptate veniam occaecat est veniam exercitation tempor. Dolore duis non esse elit. Esse esse occaecat sit tempor Lorem aliqua tempor eu non elit sint duis amet dolore.\r\n", + "registered": "1990-11-30T00:23:29+06:00", + "friends": [ + { + "id": 0, + "name": "Mona Castro" + }, + { + "id": 1, + "name": "Deanna Andrews" + }, + { + "id": 2, + "name": "Amy Donaldson" + } + ] + }, + { + "id": 442, + "guid": "690a02ec-6f49-4529-a54f-b1d90c3ac7a3", + "isActive": false, + "balance": "$2,044.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Pate Henson", + "gender": "male", + "company": "Dragbot", + "email": "patehenson@dragbot.com", + "phone": "+1 (922) 414-3569", + "address": { + "street": 412, + "city": "Winston", + "state": "Georgia", + "zip": 9837 + }, + "about": "Non irure mollit dolore qui duis aute nulla excepteur anim ad ipsum Lorem aliquip. Velit dolor qui proident minim ea incididunt non esse mollit aliquip. Eu officia anim aute fugiat veniam aliqua aute in. Adipisicing elit elit deserunt adipisicing tempor mollit et et pariatur reprehenderit commodo. Eu aliqua magna occaecat voluptate consectetur ullamco. Ad eu dolore ea enim elit ad aliquip eu adipisicing anim velit culpa dolor sint. Et ullamco eiusmod aliquip aute nostrud.\r\n", + "registered": "1999-08-05T07:52:34+05:00", + "friends": [ + { + "id": 0, + "name": "Joy Avery" + }, + { + "id": 1, + "name": "Golden Bray" + }, + { + "id": 2, + "name": "Eliza Jennings" + } + ] + }, + { + "id": 443, + "guid": "a850549f-6cc2-4165-835f-f8474ce72a3d", + "isActive": false, + "balance": "$3,695.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Wilkerson Stark", + "gender": "male", + "company": "Skyplex", + "email": "wilkersonstark@skyplex.com", + "phone": "+1 (869) 411-3235", + "address": { + "street": 230, + "city": "Starks", + "state": "Arkansas", + "zip": 9060 + }, + "about": "Dolore irure proident labore aute duis. Deserunt veniam dolore labore magna et Lorem non mollit non eu nisi ipsum fugiat id. Do laborum officia quis pariatur tempor sit esse quis qui nostrud. Ullamco in aute dolor nulla exercitation consectetur laborum deserunt sunt ea consequat. Eu enim cillum mollit eiusmod magna ipsum minim nisi veniam tempor esse. Aliquip veniam do laborum reprehenderit irure duis fugiat occaecat.\r\n", + "registered": "2013-09-16T02:08:54+05:00", + "friends": [ + { + "id": 0, + "name": "Justine Smith" + }, + { + "id": 1, + "name": "Mindy Banks" + }, + { + "id": 2, + "name": "Jensen Levine" + } + ] + }, + { + "id": 444, + "guid": "0f7d5efe-4640-4846-a267-ba5bd900e02b", + "isActive": true, + "balance": "$3,924.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Marsh Dennis", + "gender": "male", + "company": "Interodeo", + "email": "marshdennis@interodeo.com", + "phone": "+1 (988) 459-3261", + "address": { + "street": 377, + "city": "Greenwich", + "state": "New Mexico", + "zip": 4945 + }, + "about": "Cupidatat aliqua sit occaecat tempor nostrud quis laboris culpa eiusmod eiusmod sint do mollit. Esse id non do ex dolore in qui velit eu dolore id et ex mollit. Eu mollit eiusmod commodo veniam cillum proident commodo pariatur ad magna ipsum fugiat deserunt magna. Dolor duis ad pariatur anim incididunt dolore amet culpa mollit. Cillum aute sint sit labore esse id.\r\n", + "registered": "2007-10-11T05:34:21+05:00", + "friends": [ + { + "id": 0, + "name": "Katharine Ortiz" + }, + { + "id": 1, + "name": "Vickie Buckner" + }, + { + "id": 2, + "name": "Tonia Hensley" + } + ] + }, + { + "id": 445, + "guid": "858de03d-ec0f-4e6f-918f-fb4fb321b543", + "isActive": false, + "balance": "$2,616.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Cummings Page", + "gender": "male", + "company": "Insource", + "email": "cummingspage@insource.com", + "phone": "+1 (802) 600-3508", + "address": { + "street": 418, + "city": "Allison", + "state": "New Jersey", + "zip": 2893 + }, + "about": "Culpa dolor duis fugiat laboris adipisicing laboris dolore fugiat officia laboris. Magna ut minim dolor magna non. Adipisicing do tempor deserunt cillum nostrud Lorem cupidatat ut incididunt nulla ipsum in pariatur amet.\r\n", + "registered": "1994-05-21T23:32:00+05:00", + "friends": [ + { + "id": 0, + "name": "Ernestine Farmer" + }, + { + "id": 1, + "name": "Gail Tucker" + }, + { + "id": 2, + "name": "Aurora Ferguson" + } + ] + }, + { + "id": 446, + "guid": "ee959ec8-146d-4e86-a464-de6745bc3e62", + "isActive": true, + "balance": "$2,838.00", + "picture": "http://placehold.it/32x32", + "age": 34, + "name": "Brigitte Jones", + "gender": "female", + "company": "Sunclipse", + "email": "brigittejones@sunclipse.com", + "phone": "+1 (818) 596-2599", + "address": { + "street": 922, + "city": "Wikieup", + "state": "Missouri", + "zip": 8358 + }, + "about": "Cillum labore exercitation non irure minim irure quis nulla pariatur. Adipisicing aliqua irure quis velit quis anim sit reprehenderit laborum. Eu cillum ad voluptate ullamco pariatur exercitation fugiat fugiat velit amet labore deserunt. Id incididunt anim deserunt irure ea Lorem aute consectetur. Fugiat duis qui ipsum aute officia. Irure anim et laborum non dolore sit id minim culpa enim.\r\n", + "registered": "1995-10-04T18:12:31+05:00", + "friends": [ + { + "id": 0, + "name": "Jerri Bates" + }, + { + "id": 1, + "name": "Hartman Craig" + }, + { + "id": 2, + "name": "Nash Hicks" + } + ] + }, + { + "id": 447, + "guid": "616220d4-4994-4c45-a031-712162381301", + "isActive": true, + "balance": "$3,193.00", + "picture": "http://placehold.it/32x32", + "age": 36, + "name": "Walton Weber", + "gender": "male", + "company": "Zisis", + "email": "waltonweber@zisis.com", + "phone": "+1 (950) 490-3427", + "address": { + "street": 551, + "city": "Baker", + "state": "Maine", + "zip": 3744 + }, + "about": "Sint anim enim enim laboris commodo qui in Lorem dolor incididunt. Ullamco excepteur sint mollit officia esse. Consequat ea nostrud duis Lorem. Dolor ex proident anim pariatur ad consectetur ullamco sint eiusmod nulla do velit quis. Tempor amet ullamco laboris voluptate. Quis do voluptate sint in adipisicing laborum fugiat ullamco. Eiusmod culpa tempor officia sunt qui cillum irure.\r\n", + "registered": "1993-04-07T10:59:52+05:00", + "friends": [ + { + "id": 0, + "name": "Marie Cardenas" + }, + { + "id": 1, + "name": "Bettie Sexton" + }, + { + "id": 2, + "name": "Richards Conley" + } + ] + }, + { + "id": 448, + "guid": "9dc1f87a-a745-4212-b3e3-f16970bcc172", + "isActive": false, + "balance": "$3,640.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Kathy Grant", + "gender": "female", + "company": "Bolax", + "email": "kathygrant@bolax.com", + "phone": "+1 (895) 563-2334", + "address": { + "street": 893, + "city": "Devon", + "state": "North Dakota", + "zip": 7627 + }, + "about": "Ex excepteur aliquip anim non occaecat cupidatat aute ex ex pariatur excepteur. Enim est velit sunt nulla minim amet ex proident aliqua nisi. Proident ullamco sint dolore officia et sunt aliquip. Irure excepteur velit voluptate tempor aliqua occaecat mollit esse cupidatat culpa aute duis fugiat culpa. Adipisicing culpa voluptate magna ipsum adipisicing sint cillum dolore occaecat veniam. Commodo duis reprehenderit eu nulla veniam esse do. Officia ex elit do occaecat aliquip.\r\n", + "registered": "2006-03-08T22:07:01+06:00", + "friends": [ + { + "id": 0, + "name": "Iris Vazquez" + }, + { + "id": 1, + "name": "Sanchez Jacobson" + }, + { + "id": 2, + "name": "Lana Benson" + } + ] + }, + { + "id": 449, + "guid": "f55b26dc-00d7-4087-8a84-7e2ba4df5e1e", + "isActive": false, + "balance": "$2,494.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Mattie Stone", + "gender": "female", + "company": "Ziggles", + "email": "mattiestone@ziggles.com", + "phone": "+1 (961) 465-2170", + "address": { + "street": 952, + "city": "Abiquiu", + "state": "Arizona", + "zip": 6833 + }, + "about": "Et nisi adipisicing minim est. Lorem ipsum non reprehenderit cupidatat velit quis veniam eiusmod Lorem proident nostrud. Eu quis occaecat ea dolor reprehenderit Lorem non pariatur in eu laborum et dolor.\r\n", + "registered": "2003-11-18T14:13:36+06:00", + "friends": [ + { + "id": 0, + "name": "Coleman Pruitt" + }, + { + "id": 1, + "name": "Faulkner Hebert" + }, + { + "id": 2, + "name": "Jewell Frederick" + } + ] + }, + { + "id": 450, + "guid": "edb733d5-0059-4edf-817e-e84eee726dbc", + "isActive": false, + "balance": "$2,498.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Erin Rivas", + "gender": "female", + "company": "Rugstars", + "email": "erinrivas@rugstars.com", + "phone": "+1 (989) 573-3149", + "address": { + "street": 344, + "city": "Sussex", + "state": "Iowa", + "zip": 2159 + }, + "about": "Reprehenderit veniam cillum irure nulla ipsum deserunt exercitation dolor adipisicing. Consequat nostrud culpa ea irure consectetur quis culpa anim eiusmod. Ut pariatur ut velit cupidatat magna. In culpa ea nostrud ex consectetur eu pariatur.\r\n", + "registered": "2008-01-30T17:09:11+06:00", + "friends": [ + { + "id": 0, + "name": "Suzette Best" + }, + { + "id": 1, + "name": "Victoria Atkinson" + }, + { + "id": 2, + "name": "Dina Erickson" + } + ] + }, + { + "id": 451, + "guid": "e7c0977d-6c34-4c43-a6eb-000608e8bead", + "isActive": true, + "balance": "$3,082.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Ursula Stanley", + "gender": "female", + "company": "Orbiflex", + "email": "ursulastanley@orbiflex.com", + "phone": "+1 (931) 504-2101", + "address": { + "street": 730, + "city": "Dawn", + "state": "Tennessee", + "zip": 1435 + }, + "about": "Anim Lorem nisi cillum nisi. Officia laboris consequat labore non elit. Ullamco qui consectetur pariatur laborum cupidatat pariatur incididunt velit eu. Consequat non proident laboris nostrud sit Lorem pariatur fugiat esse ea consequat sunt laboris. Id reprehenderit quis officia culpa officia deserunt officia elit eiusmod. Veniam magna magna et sunt magna ad cillum adipisicing. Occaecat ad deserunt eu minim velit irure culpa proident qui et fugiat velit.\r\n", + "registered": "1995-03-03T20:32:28+06:00", + "friends": [ + { + "id": 0, + "name": "Townsend Emerson" + }, + { + "id": 1, + "name": "Deanne Chapman" + }, + { + "id": 2, + "name": "Farmer Lucas" + } + ] + }, + { + "id": 452, + "guid": "ccdf33e1-5d7a-4d87-a1ed-140092939b31", + "isActive": false, + "balance": "$2,762.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Cheri Wilkerson", + "gender": "female", + "company": "Supportal", + "email": "cheriwilkerson@supportal.com", + "phone": "+1 (876) 530-2025", + "address": { + "street": 854, + "city": "Bethpage", + "state": "Pennsylvania", + "zip": 7686 + }, + "about": "Aliqua qui commodo consequat officia. Amet ad occaecat qui consequat duis ut commodo ex. Ut incididunt nostrud adipisicing enim amet quis ut incididunt excepteur tempor enim consectetur duis. Elit dolore voluptate cupidatat dolor exercitation eiusmod.\r\n", + "registered": "1988-09-28T12:56:54+05:00", + "friends": [ + { + "id": 0, + "name": "Paula Gomez" + }, + { + "id": 1, + "name": "Reva Miranda" + }, + { + "id": 2, + "name": "Malone Jefferson" + } + ] + }, + { + "id": 453, + "guid": "d6c21601-5ca8-445d-be11-5dbd5a62b39b", + "isActive": false, + "balance": "$3,767.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Pearson Mcfadden", + "gender": "male", + "company": "Xeronk", + "email": "pearsonmcfadden@xeronk.com", + "phone": "+1 (924) 458-3535", + "address": { + "street": 318, + "city": "Bancroft", + "state": "Connecticut", + "zip": 7147 + }, + "about": "Adipisicing sit anim sunt officia non duis eiusmod elit reprehenderit irure magna sint. Proident dolor mollit exercitation nostrud. Anim adipisicing sint reprehenderit commodo anim qui qui irure deserunt laborum. Dolore laborum amet elit ut culpa dolor pariatur anim commodo proident. Magna officia commodo dolor nulla veniam labore veniam duis mollit esse.\r\n", + "registered": "2010-01-05T17:54:38+06:00", + "friends": [ + { + "id": 0, + "name": "Frederick Mcguire" + }, + { + "id": 1, + "name": "Miller Hancock" + }, + { + "id": 2, + "name": "Horne Wyatt" + } + ] + }, + { + "id": 454, + "guid": "2f5fbe64-ca6c-46d5-af3f-e1f8724629ef", + "isActive": false, + "balance": "$3,452.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Natalia Moody", + "gender": "female", + "company": "Quarex", + "email": "nataliamoody@quarex.com", + "phone": "+1 (896) 550-3648", + "address": { + "street": 701, + "city": "Loveland", + "state": "Wisconsin", + "zip": 6577 + }, + "about": "Reprehenderit ullamco ut adipisicing nostrud. Labore eiusmod cupidatat aliqua veniam dolore ullamco fugiat laborum. Do occaecat veniam deserunt duis nisi voluptate tempor incididunt et ullamco. Excepteur qui officia sit ea est commodo ad aute magna. Incididunt minim anim nostrud reprehenderit aute eu consectetur officia.\r\n", + "registered": "2005-08-20T01:17:07+05:00", + "friends": [ + { + "id": 0, + "name": "Emma Walton" + }, + { + "id": 1, + "name": "Chris Parsons" + }, + { + "id": 2, + "name": "Sutton Bryant" + } + ] + }, + { + "id": 455, + "guid": "2d250eb5-ed6a-46d6-92e6-2d0479a60330", + "isActive": true, + "balance": "$3,894.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "May Martin", + "gender": "female", + "company": "Uneeq", + "email": "maymartin@uneeq.com", + "phone": "+1 (861) 556-2692", + "address": { + "street": 510, + "city": "Turpin", + "state": "Delaware", + "zip": 1148 + }, + "about": "Et velit consectetur id ipsum quis ex fugiat. Ipsum sit Lorem nisi Lorem pariatur irure magna. Nulla aliquip elit fugiat et incididunt adipisicing pariatur est eu culpa nisi culpa. Ad incididunt nostrud amet non aliquip aute et ipsum excepteur Lorem.\r\n", + "registered": "2008-02-17T13:38:06+06:00", + "friends": [ + { + "id": 0, + "name": "Curtis Olsen" + }, + { + "id": 1, + "name": "Belinda Mendez" + }, + { + "id": 2, + "name": "Michael Douglas" + } + ] + }, + { + "id": 456, + "guid": "ec01d483-dd7a-4342-a1af-971da2d44747", + "isActive": false, + "balance": "$1,819.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Russell Reid", + "gender": "male", + "company": "Pushcart", + "email": "russellreid@pushcart.com", + "phone": "+1 (839) 416-2743", + "address": { + "street": 830, + "city": "Sehili", + "state": "Louisiana", + "zip": 3415 + }, + "about": "Aliqua aliqua nulla in eiusmod consequat. Qui do proident incididunt aliquip. Esse ex minim deserunt labore aliquip non. Ut occaecat consequat quis duis amet. Laborum do exercitation velit nostrud incididunt quis non sunt sint magna.\r\n", + "registered": "1992-09-22T05:36:40+05:00", + "friends": [ + { + "id": 0, + "name": "Miranda Mccarty" + }, + { + "id": 1, + "name": "Effie Barnes" + }, + { + "id": 2, + "name": "Pearlie Chaney" + } + ] + }, + { + "id": 457, + "guid": "6c832171-3242-4e0d-9806-cfd17e67af8f", + "isActive": true, + "balance": "$3,829.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Taylor Dominguez", + "gender": "female", + "company": "Uplinx", + "email": "taylordominguez@uplinx.com", + "phone": "+1 (829) 507-3542", + "address": { + "street": 938, + "city": "Orick", + "state": "Nebraska", + "zip": 3593 + }, + "about": "Mollit non sunt ipsum reprehenderit. Id ullamco non magna ut culpa exercitation. Ullamco adipisicing adipisicing occaecat ipsum non. Adipisicing quis consequat Lorem amet. Ad enim consequat velit nostrud dolore dolore non. Cupidatat incididunt aliqua dolor minim ullamco qui aliquip labore elit duis sit do non.\r\n", + "registered": "1999-01-22T01:15:10+06:00", + "friends": [ + { + "id": 0, + "name": "Geneva Lester" + }, + { + "id": 1, + "name": "Roman Day" + }, + { + "id": 2, + "name": "Shannon Paul" + } + ] + }, + { + "id": 458, + "guid": "b86ba5a9-fb23-438f-b13b-cd0cdd08731b", + "isActive": true, + "balance": "$2,799.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Barber Little", + "gender": "male", + "company": "Suretech", + "email": "barberlittle@suretech.com", + "phone": "+1 (829) 521-2788", + "address": { + "street": 237, + "city": "Shaft", + "state": "Minnesota", + "zip": 2194 + }, + "about": "Lorem amet veniam duis quis excepteur ad non mollit. Laborum sunt fugiat exercitation amet qui ex aliquip est voluptate et officia pariatur fugiat anim. Ut nostrud ex aute mollit voluptate est ea elit nisi ad exercitation. Ut non dolor minim Lorem incididunt aute. Irure ut aute tempor amet adipisicing exercitation non amet culpa est dolor exercitation nostrud. Amet culpa velit qui cillum velit tempor esse. Proident minim qui cillum irure irure adipisicing do Lorem sit commodo ullamco sunt aliqua duis.\r\n", + "registered": "1993-05-06T07:36:14+05:00", + "friends": [ + { + "id": 0, + "name": "Garner Dudley" + }, + { + "id": 1, + "name": "Helga Dawson" + }, + { + "id": 2, + "name": "Malinda Fowler" + } + ] + }, + { + "id": 459, + "guid": "6720cc7a-6fd9-44dc-8e1e-2bd1e57b8f8c", + "isActive": false, + "balance": "$3,732.00", + "picture": "http://placehold.it/32x32", + "age": 21, + "name": "Parrish Bird", + "gender": "male", + "company": "Exiand", + "email": "parrishbird@exiand.com", + "phone": "+1 (856) 473-3815", + "address": { + "street": 965, + "city": "Kirk", + "state": "Wyoming", + "zip": 3878 + }, + "about": "Laboris anim in id adipisicing quis dolor. Esse est velit qui qui esse voluptate esse veniam quis sint cupidatat quis veniam consectetur. Eiusmod adipisicing anim dolore proident cupidatat eiusmod dolor dolore adipisicing duis aute. Quis qui amet id do labore do culpa magna esse est. Consectetur velit cupidatat in pariatur ullamco aute laborum id esse ipsum nulla. Proident aliquip magna ad occaecat qui commodo deserunt aliquip excepteur aute nulla proident nostrud.\r\n", + "registered": "2011-07-07T23:17:18+05:00", + "friends": [ + { + "id": 0, + "name": "Guy Holman" + }, + { + "id": 1, + "name": "Emily Carroll" + }, + { + "id": 2, + "name": "Adrian Rasmussen" + } + ] + }, + { + "id": 460, + "guid": "7c78c69e-f490-4ab5-9472-d436df7a48ac", + "isActive": true, + "balance": "$2,159.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Carpenter Monroe", + "gender": "male", + "company": "Zilodyne", + "email": "carpentermonroe@zilodyne.com", + "phone": "+1 (878) 529-3240", + "address": { + "street": 824, + "city": "Townsend", + "state": "Indiana", + "zip": 4801 + }, + "about": "Amet qui aliquip officia duis culpa Lorem ut sit. Et exercitation consequat proident anim labore deserunt. Duis eu cupidatat ipsum id ut elit voluptate. Proident non mollit excepteur ea ut nostrud commodo Lorem do ipsum dolore. Dolore Lorem aliqua laborum quis commodo mollit nisi. Mollit id in deserunt dolore veniam tempor irure cillum ea excepteur.\r\n", + "registered": "1994-01-14T10:43:29+06:00", + "friends": [ + { + "id": 0, + "name": "Raymond Hale" + }, + { + "id": 1, + "name": "Rowe Dean" + }, + { + "id": 2, + "name": "Douglas Lowery" + } + ] + }, + { + "id": 461, + "guid": "9cefadd1-c2bd-4c69-81a1-76ffba09a71e", + "isActive": true, + "balance": "$1,204.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Williams Sutton", + "gender": "male", + "company": "Ziore", + "email": "williamssutton@ziore.com", + "phone": "+1 (952) 461-3437", + "address": { + "street": 360, + "city": "Allamuchy", + "state": "Texas", + "zip": 2624 + }, + "about": "Ut magna cillum magna cupidatat aliquip anim laborum id laboris deserunt consectetur. Occaecat culpa veniam nostrud eiusmod irure non. Officia officia cillum esse sunt deserunt incididunt enim elit. Pariatur amet fugiat exercitation sit culpa commodo ea occaecat duis incididunt. Laborum ullamco sunt exercitation ex officia voluptate excepteur eiusmod nisi aliqua amet. Ipsum dolore Lorem est elit in.\r\n", + "registered": "1991-01-15T02:04:42+06:00", + "friends": [ + { + "id": 0, + "name": "Noelle Higgins" + }, + { + "id": 1, + "name": "Madelyn Willis" + }, + { + "id": 2, + "name": "Hines Daniels" + } + ] + }, + { + "id": 462, + "guid": "e22e9af9-4e01-44b1-857a-d634c658eec4", + "isActive": false, + "balance": "$3,477.00", + "picture": "http://placehold.it/32x32", + "age": 25, + "name": "Molly Kaufman", + "gender": "female", + "company": "Ecratic", + "email": "mollykaufman@ecratic.com", + "phone": "+1 (891) 400-2158", + "address": { + "street": 355, + "city": "Riceville", + "state": "Florida", + "zip": 8730 + }, + "about": "Sunt amet ex nostrud voluptate ullamco non sit excepteur ullamco ipsum incididunt incididunt. Occaecat dolor qui aliqua amet fugiat Lorem. Consectetur nostrud duis pariatur nostrud in ullamco ipsum sint. Sint velit excepteur exercitation dolore voluptate est aute eu consectetur ipsum culpa fugiat labore duis. Adipisicing exercitation consectetur dolor mollit non nulla reprehenderit amet eu. Consequat mollit commodo pariatur officia enim tempor aliquip in reprehenderit reprehenderit aliquip aliqua. Occaecat laborum do ea id cillum reprehenderit deserunt in irure magna.\r\n", + "registered": "1996-03-28T19:49:47+05:00", + "friends": [ + { + "id": 0, + "name": "Valentine Brock" + }, + { + "id": 1, + "name": "Ashlee Snyder" + }, + { + "id": 2, + "name": "Mckee Villarreal" + } + ] + }, + { + "id": 463, + "guid": "9e31f2a4-4c01-4523-a6a3-a8b67fa2720e", + "isActive": true, + "balance": "$1,436.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Jackson Mccullough", + "gender": "male", + "company": "Enersol", + "email": "jacksonmccullough@enersol.com", + "phone": "+1 (857) 405-3490", + "address": { + "street": 781, + "city": "Yukon", + "state": "Washington", + "zip": 3314 + }, + "about": "Labore fugiat elit laboris ipsum aliqua voluptate ad enim sunt qui. Adipisicing elit nulla nulla aute cillum veniam laborum. Laborum minim officia non dolore incididunt ex ex exercitation eu eiusmod labore do mollit magna. Tempor in sit fugiat magna enim nisi et velit labore. Lorem anim minim commodo culpa nostrud.\r\n", + "registered": "1995-04-25T07:30:35+05:00", + "friends": [ + { + "id": 0, + "name": "Mcfadden Gallagher" + }, + { + "id": 1, + "name": "Margery Jimenez" + }, + { + "id": 2, + "name": "Katie Charles" + } + ] + }, + { + "id": 464, + "guid": "258dd487-d1c9-4c8e-8f99-adea39321b06", + "isActive": true, + "balance": "$3,805.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Cochran Gross", + "gender": "male", + "company": "Proxsoft", + "email": "cochrangross@proxsoft.com", + "phone": "+1 (910) 497-2077", + "address": { + "street": 729, + "city": "Ellerslie", + "state": "Colorado", + "zip": 1771 + }, + "about": "Culpa dolore laborum fugiat est voluptate ex aute labore enim adipisicing consequat. Enim sint aliqua ad enim dolor est adipisicing anim nulla nulla. Enim sunt aliqua veniam tempor est pariatur id est. Nostrud dolor anim voluptate consectetur do nisi Lorem labore reprehenderit duis enim labore enim dolor. Tempor aute velit nostrud magna aute irure labore minim mollit in. Nulla sit magna anim cillum cillum consequat nostrud voluptate aliquip aute.\r\n", + "registered": "2006-10-10T02:22:56+05:00", + "friends": [ + { + "id": 0, + "name": "Gibbs Sullivan" + }, + { + "id": 1, + "name": "Campbell Haley" + }, + { + "id": 2, + "name": "Ola Pate" + } + ] + }, + { + "id": 465, + "guid": "397bada5-d015-4e82-b589-13b5a7fc63a5", + "isActive": false, + "balance": "$2,555.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Marilyn Alvarez", + "gender": "female", + "company": "Zilch", + "email": "marilynalvarez@zilch.com", + "phone": "+1 (999) 447-3827", + "address": { + "street": 658, + "city": "Eden", + "state": "California", + "zip": 4644 + }, + "about": "Qui ut aliqua tempor Lorem velit aliquip non fugiat proident eu. Eu incididunt nisi nisi in ex irure. Anim adipisicing ea ex eiusmod veniam qui irure dolore dolore veniam.\r\n", + "registered": "2008-02-20T03:05:03+06:00", + "friends": [ + { + "id": 0, + "name": "Robertson Duran" + }, + { + "id": 1, + "name": "Susana Harrell" + }, + { + "id": 2, + "name": "Beck Hernandez" + } + ] + }, + { + "id": 466, + "guid": "eed29d67-b451-4a29-a833-46e3fd93dcb5", + "isActive": true, + "balance": "$2,715.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "name": "Alissa Mcclure", + "gender": "female", + "company": "Kiggle", + "email": "alissamcclure@kiggle.com", + "phone": "+1 (842) 465-2486", + "address": { + "street": 904, + "city": "Islandia", + "state": "Alaska", + "zip": 3803 + }, + "about": "Dolore incididunt enim sunt consectetur laboris amet reprehenderit et anim laboris dolore cillum. Amet cillum reprehenderit ipsum deserunt tempor pariatur officia anim culpa pariatur id deserunt nulla nulla. Irure sunt adipisicing deserunt mollit exercitation occaecat sit pariatur anim aute tempor.\r\n", + "registered": "2011-08-20T02:49:33+05:00", + "friends": [ + { + "id": 0, + "name": "Scott Avila" + }, + { + "id": 1, + "name": "Woodward Mccall" + }, + { + "id": 2, + "name": "Helene Callahan" + } + ] + }, + { + "id": 467, + "guid": "ef6523bc-cb61-45a1-8a7c-0fef1611f6bf", + "isActive": false, + "balance": "$1,135.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Caroline Giles", + "gender": "female", + "company": "Jumpstack", + "email": "carolinegiles@jumpstack.com", + "phone": "+1 (844) 588-2757", + "address": { + "street": 605, + "city": "Greenbush", + "state": "Alabama", + "zip": 9434 + }, + "about": "Quis sint qui quis proident consectetur cillum voluptate. Proident sit cupidatat aliquip excepteur laborum enim laboris aliqua nisi ullamco in Lorem amet et. Et irure aliqua ipsum nisi.\r\n", + "registered": "2005-09-12T19:50:46+05:00", + "friends": [ + { + "id": 0, + "name": "Desiree Wilcox" + }, + { + "id": 1, + "name": "Dodson Rhodes" + }, + { + "id": 2, + "name": "Nellie Gates" + } + ] + }, + { + "id": 468, + "guid": "c4a932af-7251-42c0-ba6b-ea4c207e5d89", + "isActive": false, + "balance": "$2,746.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Wade Frye", + "gender": "male", + "company": "Kenegy", + "email": "wadefrye@kenegy.com", + "phone": "+1 (878) 440-3251", + "address": { + "street": 719, + "city": "Holcombe", + "state": "Rhode Island", + "zip": 3074 + }, + "about": "Non adipisicing esse laborum quis consectetur officia ut pariatur et est reprehenderit. Sunt ad aliquip in velit dolore laborum consectetur consequat ad dolore pariatur est Lorem amet. Reprehenderit velit quis velit pariatur cupidatat non ipsum ad sunt pariatur. Id aliquip pariatur dolore deserunt sit. Velit nisi minim veniam exercitation veniam. Nulla esse eiusmod Lorem exercitation ex ex. Fugiat elit aliquip occaecat amet exercitation ea mollit commodo.\r\n", + "registered": "2011-08-25T08:11:00+05:00", + "friends": [ + { + "id": 0, + "name": "Iva Bell" + }, + { + "id": 1, + "name": "Estrada Shaw" + }, + { + "id": 2, + "name": "Bradshaw Blackburn" + } + ] + }, + { + "id": 469, + "guid": "9427149f-f86d-4dc0-bde2-c121d2874adf", + "isActive": true, + "balance": "$2,990.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Rhoda Ortega", + "gender": "female", + "company": "Genekom", + "email": "rhodaortega@genekom.com", + "phone": "+1 (827) 567-3336", + "address": { + "street": 615, + "city": "Highland", + "state": "Idaho", + "zip": 9143 + }, + "about": "Nulla ea cillum sint reprehenderit aute quis non. Amet eiusmod quis excepteur ut commodo labore excepteur voluptate exercitation labore. Commodo pariatur elit cillum fugiat pariatur nulla dolore tempor fugiat.\r\n", + "registered": "2013-12-05T06:25:18+06:00", + "friends": [ + { + "id": 0, + "name": "Angelica Odonnell" + }, + { + "id": 1, + "name": "Merritt Combs" + }, + { + "id": 2, + "name": "Reyes Spears" + } + ] + }, + { + "id": 470, + "guid": "df5a7771-b825-4841-99ee-61704703ec6b", + "isActive": true, + "balance": "$1,865.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Phyllis Hess", + "gender": "female", + "company": "Rooforia", + "email": "phyllishess@rooforia.com", + "phone": "+1 (966) 547-2958", + "address": { + "street": 372, + "city": "Ilchester", + "state": "Massachusetts", + "zip": 2709 + }, + "about": "Consectetur fugiat sit et in velit cupidatat nulla culpa et velit. Dolore ad eu mollit consequat Lorem. Elit ullamco occaecat officia aliqua eiusmod duis excepteur sunt officia irure voluptate. Voluptate irure fugiat voluptate pariatur.\r\n", + "registered": "1997-08-07T15:23:15+05:00", + "friends": [ + { + "id": 0, + "name": "Sanders Frank" + }, + { + "id": 1, + "name": "Kristie Herman" + }, + { + "id": 2, + "name": "Audra Hewitt" + } + ] + }, + { + "id": 471, + "guid": "edf0db14-a2f6-404b-bc99-b1f89f395ece", + "isActive": true, + "balance": "$1,130.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Maude Barry", + "gender": "female", + "company": "Enervate", + "email": "maudebarry@enervate.com", + "phone": "+1 (928) 466-3982", + "address": { + "street": 393, + "city": "Cutter", + "state": "Mississippi", + "zip": 8609 + }, + "about": "Nostrud consequat sit laboris et enim ipsum do nisi proident dolore in non proident. Labore adipisicing labore nisi ipsum dolor mollit non eu quis. Officia commodo Lorem elit voluptate tempor. Pariatur et labore reprehenderit ullamco elit non ullamco. Ex sint ad elit aute.\r\n", + "registered": "2013-01-30T03:34:38+06:00", + "friends": [ + { + "id": 0, + "name": "Harvey Long" + }, + { + "id": 1, + "name": "Wilma Barrera" + }, + { + "id": 2, + "name": "Sophia Hansen" + } + ] + }, + { + "id": 472, + "guid": "dc1c589f-f8eb-4129-97ea-59503f31e74e", + "isActive": false, + "balance": "$1,894.00", + "picture": "http://placehold.it/32x32", + "age": 39, + "name": "Barnes Savage", + "gender": "male", + "company": "Providco", + "email": "barnessavage@providco.com", + "phone": "+1 (910) 499-3548", + "address": { + "street": 550, + "city": "Homeland", + "state": "Nevada", + "zip": 2661 + }, + "about": "Laborum est consequat pariatur consequat veniam culpa proident consequat sint. Cupidatat magna nulla ad non. Duis ex ullamco nisi eiusmod culpa eiusmod culpa labore eiusmod. Laboris commodo non excepteur nisi magna sint Lorem sunt. Do officia labore reprehenderit amet nulla anim.\r\n", + "registered": "1988-03-29T11:38:30+05:00", + "friends": [ + { + "id": 0, + "name": "Letitia Ramirez" + }, + { + "id": 1, + "name": "Brandy Grimes" + }, + { + "id": 2, + "name": "Conway Lee" + } + ] + }, + { + "id": 473, + "guid": "e4efd6bb-5985-47d2-a885-02f9525aa454", + "isActive": true, + "balance": "$2,151.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Rochelle Gonzalez", + "gender": "female", + "company": "Enaut", + "email": "rochellegonzalez@enaut.com", + "phone": "+1 (856) 462-2738", + "address": { + "street": 373, + "city": "Coldiron", + "state": "Vermont", + "zip": 9948 + }, + "about": "Deserunt laborum enim dolore ex labore ipsum do. Duis eu cillum ad quis. Esse ipsum irure ut laborum quis duis ipsum consectetur dolor qui consectetur enim nisi. Occaecat magna eiusmod do ipsum quis duis sit velit consequat.\r\n", + "registered": "1993-09-23T14:57:11+05:00", + "friends": [ + { + "id": 0, + "name": "Weiss Clayton" + }, + { + "id": 1, + "name": "Araceli Pickett" + }, + { + "id": 2, + "name": "Janine Mcintyre" + } + ] + }, + { + "id": 474, + "guid": "bd7bd8d0-ed5f-4462-a491-829483bc6c28", + "isActive": true, + "balance": "$1,394.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Sampson Chang", + "gender": "male", + "company": "Quility", + "email": "sampsonchang@quility.com", + "phone": "+1 (964) 584-3766", + "address": { + "street": 186, + "city": "Yogaville", + "state": "Kentucky", + "zip": 2117 + }, + "about": "Qui ad velit quis sint. Officia Lorem qui adipisicing nisi consequat esse amet non eiusmod sint. Proident ex et sunt occaecat do labore. Occaecat irure dolor aliqua amet officia laboris proident eiusmod sint laboris do incididunt. Tempor ullamco ex commodo magna. Excepteur officia consequat ex id in amet dolore minim sunt.\r\n", + "registered": "2001-01-28T04:26:27+06:00", + "friends": [ + { + "id": 0, + "name": "Herrera Hyde" + }, + { + "id": 1, + "name": "Osborne Holloway" + }, + { + "id": 2, + "name": "Watson Cain" + } + ] + }, + { + "id": 475, + "guid": "cc19d32f-4f7e-42ee-b6b0-14513287bcfd", + "isActive": false, + "balance": "$2,336.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Camille Ingram", + "gender": "female", + "company": "Idego", + "email": "camilleingram@idego.com", + "phone": "+1 (901) 414-2712", + "address": { + "street": 527, + "city": "Glenville", + "state": "North Carolina", + "zip": 7483 + }, + "about": "Eiusmod et dolor est incididunt tempor veniam ut laborum occaecat pariatur nostrud aliquip et enim. Veniam consectetur anim non duis pariatur consequat. Nulla occaecat mollit sunt velit quis aute enim consequat sit duis.\r\n", + "registered": "2007-07-30T15:09:52+05:00", + "friends": [ + { + "id": 0, + "name": "Antoinette Orr" + }, + { + "id": 1, + "name": "Murphy Pearson" + }, + { + "id": 2, + "name": "Carrie Cox" + } + ] + }, + { + "id": 476, + "guid": "971d5e6a-5754-4b40-9c97-3b111b2be0d7", + "isActive": false, + "balance": "$2,562.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Jenifer Irwin", + "gender": "female", + "company": "Ebidco", + "email": "jeniferirwin@ebidco.com", + "phone": "+1 (807) 556-2109", + "address": { + "street": 168, + "city": "Goochland", + "state": "Oregon", + "zip": 8998 + }, + "about": "Duis est reprehenderit laboris eu. Deserunt ea sunt ullamco commodo adipisicing minim velit qui ea laboris incididunt nulla. Reprehenderit exercitation velit proident ipsum qui et duis magna.\r\n", + "registered": "1992-09-23T04:31:37+05:00", + "friends": [ + { + "id": 0, + "name": "Vaughan Bolton" + }, + { + "id": 1, + "name": "Rosario Shepherd" + }, + { + "id": 2, + "name": "Preston Baker" + } + ] + }, + { + "id": 477, + "guid": "76985a08-2801-4c6d-aa2e-d64bd4ab492c", + "isActive": true, + "balance": "$2,885.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Kristy Curry", + "gender": "female", + "company": "Digique", + "email": "kristycurry@digique.com", + "phone": "+1 (932) 457-2841", + "address": { + "street": 713, + "city": "Groveville", + "state": "New Hampshire", + "zip": 4988 + }, + "about": "Excepteur eiusmod laborum aute eu cillum dolor minim mollit occaecat. Adipisicing laborum cillum est duis. Sunt labore et quis sit anim id adipisicing. Tempor reprehenderit ad do deserunt commodo consequat excepteur elit amet. Aliqua deserunt adipisicing deserunt culpa do ex reprehenderit dolore.\r\n", + "registered": "2004-03-20T20:15:04+05:00", + "friends": [ + { + "id": 0, + "name": "Caitlin Morton" + }, + { + "id": 1, + "name": "Mccall Haney" + }, + { + "id": 2, + "name": "Valeria Mcgowan" + } + ] + }, + { + "id": 478, + "guid": "cf577cf8-891e-42d4-abc9-fc22999e57d4", + "isActive": false, + "balance": "$1,942.00", + "picture": "http://placehold.it/32x32", + "age": 29, + "name": "Cooper Noble", + "gender": "male", + "company": "Isoternia", + "email": "coopernoble@isoternia.com", + "phone": "+1 (814) 485-2640", + "address": { + "street": 804, + "city": "Nelson", + "state": "New York", + "zip": 6977 + }, + "about": "Culpa qui in eu amet et aliquip. Duis exercitation reprehenderit ipsum et est non cupidatat dolor cupidatat mollit non proident consectetur. Amet ullamco exercitation in est ad occaecat Lorem. Proident irure voluptate minim aliqua aute exercitation enim anim. Occaecat esse veniam labore ex adipisicing aute nulla anim. Do nostrud sunt esse ullamco dolor est labore ut. Nulla in velit irure consectetur ut sit.\r\n", + "registered": "2013-02-06T09:23:03+06:00", + "friends": [ + { + "id": 0, + "name": "Bates Dickerson" + }, + { + "id": 1, + "name": "Rosalinda Riley" + }, + { + "id": 2, + "name": "Jeanie Howe" + } + ] + }, + { + "id": 479, + "guid": "9315bc20-51f0-4abf-af46-f1de93930bcb", + "isActive": false, + "balance": "$2,996.00", + "picture": "http://placehold.it/32x32", + "age": 35, + "name": "Bridgette Phillips", + "gender": "female", + "company": "Comverges", + "email": "bridgettephillips@comverges.com", + "phone": "+1 (888) 488-2656", + "address": { + "street": 709, + "city": "Longoria", + "state": "South Dakota", + "zip": 7085 + }, + "about": "In incididunt cupidatat duis incididunt et. Nulla aliqua enim pariatur incididunt amet. Sint veniam duis cupidatat eiusmod Lorem magna culpa non amet aliqua eu consequat. Pariatur ad occaecat velit nulla laboris consectetur dolor id labore. Voluptate officia sunt enim quis. Proident qui aliquip proident eu nisi laboris dolore. Quis aliquip ut non ipsum non cillum culpa incididunt.\r\n", + "registered": "2011-09-08T06:49:05+05:00", + "friends": [ + { + "id": 0, + "name": "Charlene Slater" + }, + { + "id": 1, + "name": "Rita Rich" + }, + { + "id": 2, + "name": "Ora Cantrell" + } + ] + }, + { + "id": 480, + "guid": "a4bbec4b-32b3-481d-9f10-fc92f76e74d7", + "isActive": false, + "balance": "$1,894.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Stefanie Mccarthy", + "gender": "female", + "company": "Bugsall", + "email": "stefaniemccarthy@bugsall.com", + "phone": "+1 (925) 597-2082", + "address": { + "street": 797, + "city": "Cotopaxi", + "state": "West Virginia", + "zip": 4808 + }, + "about": "Eiusmod aute adipisicing deserunt veniam. Irure duis est est ex pariatur. Laborum elit in et ex magna nostrud adipisicing sint. Labore commodo pariatur nisi incididunt consectetur deserunt dolor laboris. Consectetur elit occaecat magna culpa laboris ipsum aute esse voluptate Lorem commodo. Velit duis excepteur nulla consectetur do. Laborum esse veniam pariatur Lorem ipsum reprehenderit occaecat ex excepteur.\r\n", + "registered": "2008-12-18T07:36:29+06:00", + "friends": [ + { + "id": 0, + "name": "Agnes Walsh" + }, + { + "id": 1, + "name": "Clemons Tyson" + }, + { + "id": 2, + "name": "Saunders Bowers" + } + ] + }, + { + "id": 481, + "guid": "d93bd90b-5c43-4a93-aac2-688f3bde685b", + "isActive": false, + "balance": "$2,584.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Vilma Watson", + "gender": "female", + "company": "Neocent", + "email": "vilmawatson@neocent.com", + "phone": "+1 (973) 597-3714", + "address": { + "street": 782, + "city": "Wakulla", + "state": "Michigan", + "zip": 9812 + }, + "about": "Ex est cupidatat officia excepteur in ad quis duis minim pariatur mollit elit ut sint. Enim occaecat laborum aute nisi esse pariatur. Eu irure in occaecat nisi minim tempor cupidatat ut elit incididunt do incididunt sit.\r\n", + "registered": "2007-11-25T11:13:58+06:00", + "friends": [ + { + "id": 0, + "name": "West Cross" + }, + { + "id": 1, + "name": "Guadalupe Rivers" + }, + { + "id": 2, + "name": "Cara Farley" + } + ] + }, + { + "id": 482, + "guid": "64c7a58f-87b4-4dae-888f-db42706ca71c", + "isActive": true, + "balance": "$2,670.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Workman Knowles", + "gender": "male", + "company": "Medicroix", + "email": "workmanknowles@medicroix.com", + "phone": "+1 (819) 565-2956", + "address": { + "street": 597, + "city": "Barclay", + "state": "Montana", + "zip": 849 + }, + "about": "Elit dolor irure aliqua in nisi eu sunt. Laboris aliqua cupidatat ad adipisicing eiusmod qui do consectetur minim. Quis ipsum duis eiusmod nostrud dolore aliqua nulla ipsum aliquip sunt cupidatat dolore eu culpa. Laboris nisi mollit cillum eiusmod eu ut anim sint. Minim officia aliqua esse esse ut voluptate labore. Nulla id commodo duis proident.\r\n", + "registered": "1994-01-07T23:21:36+06:00", + "friends": [ + { + "id": 0, + "name": "Green Knapp" + }, + { + "id": 1, + "name": "Reynolds Mayo" + }, + { + "id": 2, + "name": "Margie Patton" + } + ] + }, + { + "id": 483, + "guid": "d463c57e-7197-4a98-ba8a-af68bd0e5fbd", + "isActive": false, + "balance": "$2,269.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Tonya Sharpe", + "gender": "female", + "company": "Applideck", + "email": "tonyasharpe@applideck.com", + "phone": "+1 (844) 443-2753", + "address": { + "street": 788, + "city": "Blairstown", + "state": "Kansas", + "zip": 5260 + }, + "about": "Cupidatat duis esse consequat fugiat exercitation nulla nostrud consequat culpa tempor anim occaecat ut elit. Cupidatat nisi est consequat incididunt voluptate nulla excepteur esse duis fugiat proident ea. Commodo commodo amet nostrud veniam nostrud mollit sint excepteur.\r\n", + "registered": "1994-09-21T00:28:09+05:00", + "friends": [ + { + "id": 0, + "name": "Amber Hays" + }, + { + "id": 1, + "name": "Chandra Bright" + }, + { + "id": 2, + "name": "Woodard Rice" + } + ] + }, + { + "id": 484, + "guid": "e1a7f5ec-b477-4af3-a0c8-11ac008bc7bb", + "isActive": true, + "balance": "$2,750.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "William Shelton", + "gender": "male", + "company": "Honotron", + "email": "williamshelton@honotron.com", + "phone": "+1 (977) 553-3810", + "address": { + "street": 306, + "city": "Lund", + "state": "Oklahoma", + "zip": 6035 + }, + "about": "Incididunt deserunt velit deserunt sint et cillum velit veniam. Qui qui velit elit esse reprehenderit commodo id pariatur. Dolor enim id esse laboris aliqua sint enim est cillum pariatur veniam consequat. Commodo ullamco fugiat proident irure irure magna ex.\r\n", + "registered": "2007-09-13T01:58:32+05:00", + "friends": [ + { + "id": 0, + "name": "Nadine Simmons" + }, + { + "id": 1, + "name": "Olive Short" + }, + { + "id": 2, + "name": "Cristina Macias" + } + ] + }, + { + "id": 485, + "guid": "81366490-38bc-4450-be48-0f37b0ac1125", + "isActive": true, + "balance": "$1,641.00", + "picture": "http://placehold.it/32x32", + "age": 28, + "name": "Reba Miles", + "gender": "female", + "company": "Tetak", + "email": "rebamiles@tetak.com", + "phone": "+1 (952) 449-3879", + "address": { + "street": 808, + "city": "Gorham", + "state": "Utah", + "zip": 5536 + }, + "about": "Adipisicing nisi officia labore labore velit id reprehenderit sunt ullamco cupidatat. Ullamco id id qui non cillum id commodo consequat exercitation aute reprehenderit. Ullamco officia ex aute consequat ad culpa nisi ex ullamco in id. Ex ad dolor exercitation dolore et ipsum. Elit exercitation eu qui mollit adipisicing.\r\n", + "registered": "1993-07-26T15:43:35+05:00", + "friends": [ + { + "id": 0, + "name": "Leta Daugherty" + }, + { + "id": 1, + "name": "Jeri Conrad" + }, + { + "id": 2, + "name": "Jarvis Pitts" + } + ] + }, + { + "id": 486, + "guid": "4a1bdf87-6151-40df-9545-ee6e6359652d", + "isActive": true, + "balance": "$1,324.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Christie Kerr", + "gender": "female", + "company": "Aquamate", + "email": "christiekerr@aquamate.com", + "phone": "+1 (820) 594-2951", + "address": { + "street": 232, + "city": "Brownsville", + "state": "Maryland", + "zip": 7212 + }, + "about": "Qui anim do sit officia eiusmod dolor tempor culpa mollit sunt incididunt anim ullamco. Qui eiusmod sit commodo qui. Sint esse cupidatat cillum est deserunt duis. Reprehenderit incididunt aute reprehenderit commodo Lorem do cillum. Reprehenderit ullamco minim labore anim voluptate culpa veniam elit mollit consectetur anim. Consectetur incididunt fugiat sint anim deserunt do Lorem eiusmod. Cupidatat ea fugiat reprehenderit esse anim consequat consequat nostrud in anim ex.\r\n", + "registered": "1993-08-28T23:47:50+05:00", + "friends": [ + { + "id": 0, + "name": "Rollins Kline" + }, + { + "id": 1, + "name": "Esther Reilly" + }, + { + "id": 2, + "name": "Jaime Mckenzie" + } + ] + }, + { + "id": 487, + "guid": "a1f13c2a-db68-48cc-800b-05d7539548f9", + "isActive": true, + "balance": "$1,005.00", + "picture": "http://placehold.it/32x32", + "age": 30, + "name": "Selma Guerrero", + "gender": "female", + "company": "Apextri", + "email": "selmaguerrero@apextri.com", + "phone": "+1 (809) 533-3543", + "address": { + "street": 334, + "city": "Flintville", + "state": "South Carolina", + "zip": 7083 + }, + "about": "Reprehenderit eu magna quis non irure eiusmod tempor. Dolore elit aliquip est adipisicing quis deserunt Lorem magna eu cupidatat. Minim in voluptate est ea.\r\n", + "registered": "2001-04-28T20:40:08+05:00", + "friends": [ + { + "id": 0, + "name": "Justice Mccormick" + }, + { + "id": 1, + "name": "Castillo Powers" + }, + { + "id": 2, + "name": "Knowles Kelley" + } + ] + }, + { + "id": 488, + "guid": "734ee2e0-f302-4d15-b956-21e1e7e2f415", + "isActive": false, + "balance": "$3,325.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Michele Vinson", + "gender": "female", + "company": "Interfind", + "email": "michelevinson@interfind.com", + "phone": "+1 (843) 549-2392", + "address": { + "street": 582, + "city": "Sattley", + "state": "Virginia", + "zip": 5500 + }, + "about": "Do esse in in est. Velit proident duis adipisicing eu minim nostrud laboris aliquip eu. Laboris culpa tempor in anim laborum exercitation sit laboris minim occaecat et quis ex.\r\n", + "registered": "2001-06-11T03:51:24+05:00", + "friends": [ + { + "id": 0, + "name": "Munoz Mercado" + }, + { + "id": 1, + "name": "Shelby Woodard" + }, + { + "id": 2, + "name": "Collier Weiss" + } + ] + }, + { + "id": 489, + "guid": "4000e1f6-ec7d-4984-b12d-cc65f11e30de", + "isActive": false, + "balance": "$1,597.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "name": "Hansen Palmer", + "gender": "male", + "company": "Neptide", + "email": "hansenpalmer@neptide.com", + "phone": "+1 (927) 497-2069", + "address": { + "street": 930, + "city": "Hiko", + "state": "Illinois", + "zip": 7355 + }, + "about": "Sunt consectetur nisi nisi incididunt nisi est velit pariatur ullamco. Minim est fugiat sint amet. Cillum occaecat id amet velit et incididunt occaecat duis laboris do et. Est quis dolore pariatur cillum excepteur nostrud eu nisi minim tempor. Cillum ad Lorem nostrud cillum incididunt.\r\n", + "registered": "2010-07-11T07:49:34+05:00", + "friends": [ + { + "id": 0, + "name": "Glover Madden" + }, + { + "id": 1, + "name": "Nieves Fernandez" + }, + { + "id": 2, + "name": "Mcdowell Sharp" + } + ] + }, + { + "id": 490, + "guid": "e3e18815-3b60-46e1-8d16-9714b9164b8c", + "isActive": false, + "balance": "$3,922.00", + "picture": "http://placehold.it/32x32", + "age": 27, + "name": "Sykes Woodward", + "gender": "male", + "company": "Capscreen", + "email": "sykeswoodward@capscreen.com", + "phone": "+1 (835) 592-3867", + "address": { + "street": 634, + "city": "Frystown", + "state": "North Carolina", + "zip": 3510 + }, + "about": "Duis laboris qui fugiat laborum dolore quis officia mollit culpa et. Incididunt irure proident consectetur laborum nisi sunt non eu deserunt in esse. Labore commodo quis officia elit non ullamco culpa nulla ex Lorem dolore ad. Culpa non minim amet elit labore. Eu officia ullamco eu esse anim ipsum est dolor est minim amet et velit irure. Commodo consequat ipsum cillum nisi do. Aliqua in ipsum culpa dolor officia magna magna amet sunt laborum.\r\n", + "registered": "1995-10-16T21:15:53+05:00", + "friends": [ + { + "id": 0, + "name": "Socorro Andrews" + }, + { + "id": 1, + "name": "Richmond Howell" + }, + { + "id": 2, + "name": "Katie Gillespie" + } + ] + }, + { + "id": 491, + "guid": "7f3f1f93-f334-490d-9637-cdc2b2f208ea", + "isActive": false, + "balance": "$2,721.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Bartlett Benjamin", + "gender": "male", + "company": "Aquasseur", + "email": "bartlettbenjamin@aquasseur.com", + "phone": "+1 (958) 419-2609", + "address": { + "street": 668, + "city": "Homestead", + "state": "Oklahoma", + "zip": 9336 + }, + "about": "Officia nulla aliquip ex non est do. Incididunt aliquip id eiusmod velit aute. Enim labore nostrud tempor mollit.\r\n", + "registered": "2006-06-07T19:14:59+05:00", + "friends": [ + { + "id": 0, + "name": "Knox Murray" + }, + { + "id": 1, + "name": "Alana Garrett" + }, + { + "id": 2, + "name": "Mollie Chan" + } + ] + }, + { + "id": 492, + "guid": "eb57372f-78ef-420a-862c-7be576287e15", + "isActive": false, + "balance": "$3,263.00", + "picture": "http://placehold.it/32x32", + "age": 23, + "name": "Morris Manning", + "gender": "male", + "company": "Manufact", + "email": "morrismanning@manufact.com", + "phone": "+1 (844) 577-2596", + "address": { + "street": 149, + "city": "Ferney", + "state": "Maryland", + "zip": 2427 + }, + "about": "Elit quis deserunt duis reprehenderit aliquip sunt ut sint in Lorem velit aliqua. Culpa officia adipisicing excepteur minim minim voluptate excepteur esse nisi aute do ex. Consectetur elit minim quis consectetur nulla. Ipsum occaecat deserunt esse consequat officia ullamco nisi in officia.\r\n", + "registered": "2010-06-08T21:28:48+05:00", + "friends": [ + { + "id": 0, + "name": "Tasha Lamb" + }, + { + "id": 1, + "name": "Golden Reynolds" + }, + { + "id": 2, + "name": "Myers Hayes" + } + ] + }, + { + "id": 493, + "guid": "92532339-7f6d-49fe-ad52-d02ecb2ab941", + "isActive": true, + "balance": "$2,468.00", + "picture": "http://placehold.it/32x32", + "age": 37, + "name": "Avila Riggs", + "gender": "male", + "company": "Vidto", + "email": "avilariggs@vidto.com", + "phone": "+1 (898) 576-3105", + "address": { + "street": 583, + "city": "Delwood", + "state": "Illinois", + "zip": 914 + }, + "about": "Consectetur minim magna amet in ipsum Lorem sint ex sit mollit dolor veniam veniam. Ut pariatur aliqua est in anim fugiat quis. Nisi deserunt aliquip reprehenderit excepteur excepteur irure nostrud et amet magna exercitation exercitation culpa adipisicing.\r\n", + "registered": "2007-12-20T10:51:48+06:00", + "friends": [ + { + "id": 0, + "name": "Patterson Blair" + }, + { + "id": 1, + "name": "Olsen Pitts" + }, + { + "id": 2, + "name": "Emma Madden" + } + ] + }, + { + "id": 494, + "guid": "6300e171-0cc1-45a9-aea1-9ec8ec3820ec", + "isActive": true, + "balance": "$3,769.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Moon Tran", + "gender": "male", + "company": "Proxsoft", + "email": "moontran@proxsoft.com", + "phone": "+1 (828) 539-2341", + "address": { + "street": 502, + "city": "Bordelonville", + "state": "California", + "zip": 5023 + }, + "about": "Voluptate laboris magna aliqua nulla minim eu pariatur aliqua officia fugiat ad. Tempor Lorem irure magna deserunt magna minim occaecat. Commodo minim in pariatur proident cupidatat qui est consequat aliqua. Et dolore ipsum laboris nisi et deserunt. Irure labore nisi est deserunt mollit laboris. Incididunt pariatur velit ea in aliquip sint mollit cupidatat id sit pariatur proident excepteur.\r\n", + "registered": "2003-05-02T01:41:33+05:00", + "friends": [ + { + "id": 0, + "name": "Kasey Simon" + }, + { + "id": 1, + "name": "Sheree Blankenship" + }, + { + "id": 2, + "name": "Lee Oconnor" + } + ] + }, + { + "id": 495, + "guid": "5a77fc33-0781-411a-8336-2c03dc15664c", + "isActive": false, + "balance": "$3,330.00", + "picture": "http://placehold.it/32x32", + "age": 26, + "name": "Effie Cantrell", + "gender": "female", + "company": "Megall", + "email": "effiecantrell@megall.com", + "phone": "+1 (803) 515-3375", + "address": { + "street": 244, + "city": "Chalfant", + "state": "Arkansas", + "zip": 343 + }, + "about": "Commodo elit commodo ea aute incididunt laboris exercitation labore culpa ad. Enim officia minim incididunt id nostrud tempor. Ad est commodo qui adipisicing amet. Minim reprehenderit occaecat laboris esse sunt.\r\n", + "registered": "2007-10-07T06:22:19+05:00", + "friends": [ + { + "id": 0, + "name": "Frederick Fry" + }, + { + "id": 1, + "name": "Huber Perry" + }, + { + "id": 2, + "name": "Burns Franks" + } + ] + }, + { + "id": 496, + "guid": "fcfe7484-9d2f-4749-89a4-44944754ca66", + "isActive": true, + "balance": "$3,970.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "name": "Atkinson Forbes", + "gender": "male", + "company": "Vurbo", + "email": "atkinsonforbes@vurbo.com", + "phone": "+1 (988) 585-3525", + "address": { + "street": 442, + "city": "Loyalhanna", + "state": "Louisiana", + "zip": 9507 + }, + "about": "Incididunt velit nostrud do ipsum deserunt magna id cupidatat Lorem dolor nulla ex duis. Esse adipisicing et pariatur occaecat sint do officia id aliqua. Ut nisi enim deserunt est magna ullamco voluptate anim cillum.\r\n", + "registered": "2013-07-03T00:49:30+05:00", + "friends": [ + { + "id": 0, + "name": "Nicholson Leach" + }, + { + "id": 1, + "name": "Wade Schultz" + }, + { + "id": 2, + "name": "Jacquelyn Mcdaniel" + } + ] + }, + { + "id": 497, + "guid": "86474dbe-5949-47a3-a90b-41c082ae728b", + "isActive": false, + "balance": "$1,551.00", + "picture": "http://placehold.it/32x32", + "age": 24, + "name": "Whitfield Humphrey", + "gender": "male", + "company": "Deminimum", + "email": "whitfieldhumphrey@deminimum.com", + "phone": "+1 (908) 437-3139", + "address": { + "street": 585, + "city": "Edgewater", + "state": "Ohio", + "zip": 9405 + }, + "about": "Elit minim ea duis laborum sit eiusmod. Elit quis magna elit ut qui officia amet et qui enim cupidatat ut eiusmod. Aute deserunt do duis cupidatat sint voluptate consectetur et minim eiusmod est. Excepteur anim ullamco occaecat eu eiusmod. Consequat sit mollit eiusmod reprehenderit eiusmod.\r\n", + "registered": "1991-12-07T07:16:59+06:00", + "friends": [ + { + "id": 0, + "name": "Ford Henry" + }, + { + "id": 1, + "name": "Ronda Warren" + }, + { + "id": 2, + "name": "Anthony Weaver" + } + ] + }, + { + "id": 498, + "guid": "d2845bc9-94ed-46d5-8241-c0ca9c891b46", + "isActive": false, + "balance": "$3,071.00", + "picture": "http://placehold.it/32x32", + "age": 40, + "name": "Jocelyn Cobb", + "gender": "female", + "company": "Cytrex", + "email": "jocelyncobb@cytrex.com", + "phone": "+1 (963) 430-2757", + "address": { + "street": 639, + "city": "Frank", + "state": "Minnesota", + "zip": 4316 + }, + "about": "Est id laboris ea aliquip anim laboris amet nostrud pariatur excepteur. Ullamco aliqua est qui cupidatat deserunt sint consequat elit labore laborum eu. Elit sunt labore elit proident. Adipisicing sunt ex ad quis ex id et cupidatat dolor veniam ipsum ex mollit. Esse in laboris labore do commodo velit velit quis consectetur duis. Consequat veniam sit incididunt anim consequat sunt. Sunt ipsum adipisicing aute magna commodo consequat enim eu aliqua Lorem.\r\n", + "registered": "1996-11-30T01:37:54+06:00", + "friends": [ + { + "id": 0, + "name": "Reese Owen" + }, + { + "id": 1, + "name": "Bass Welch" + }, + { + "id": 2, + "name": "Hickman Lyons" + } + ] + }, + { + "id": 499, + "guid": "29dff816-4f3d-4f4a-85ec-d56c0dbbf7d6", + "isActive": true, + "balance": "$1,467.00", + "picture": "http://placehold.it/32x32", + "age": 38, + "name": "Marci Emerson", + "gender": "female", + "company": "Thredz", + "email": "marciemerson@thredz.com", + "phone": "+1 (988) 560-2140", + "address": { + "street": 182, + "city": "Mulino", + "state": "Montana", + "zip": 9710 + }, + "about": "Laborum commodo velit fugiat voluptate ut sit occaecat veniam do voluptate adipisicing reprehenderit incididunt. Minim incididunt fugiat ullamco labore in ullamco Lorem eiusmod ad duis dolore adipisicing. Nulla ullamco proident nisi est ullamco aliquip nisi mollit consectetur consequat veniam ipsum. Ex eu deserunt aute esse. Ut aliquip quis commodo ullamco esse incididunt velit aliquip laboris tempor ut ipsum.\r\n", + "registered": "1994-08-15T22:58:01+05:00", + "friends": [ + { + "id": 0, + "name": "Brooks Hickman" + }, + { + "id": 1, + "name": "Mara Everett" + }, + { + "id": 2, + "name": "Mable Flores" + } + ] + } +] \ No newline at end of file diff --git a/data/50_columns.json b/data/50_columns.json new file mode 100644 index 000000000..e358038f4 --- /dev/null +++ b/data/50_columns.json @@ -0,0 +1 @@ +[{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"},{"col1":"blah","col2":"blah","col3":"blah","col4":"blah","col5":"blah","col6":"blah","col7":"blah","col8":"blah","col9":"blah","col10":"blah","col11":"blah","col12":"blah","col13":"blah","col14":"blah","col15":"blah","col16":"blah","col17":"blah","col18":"blah","col19":"blah","col20":"blah","col21":"blah","col22":"blah","col23":"blah","col24":"blah","col25":"blah","col26":"blah","col27":"blah","col28":"blah","col29":"blah","col30":"blah","col31":"blah","col32":"blah","col33":"blah","col34":"blah","col35":"blah","col36":"blah","col37":"blah","col38":"blah","col39":"blah","col40":"blah","col41":"blah","col42":"blah","col43":"blah","col44":"blah","col45":"blah","col46":"blah","col47":"blah","col48":"blah","col49":"blah","col50":"blah"}] \ No newline at end of file diff --git a/data/dataTemplates.txt b/data/dataTemplates.txt new file mode 100644 index 000000000..63f6b3746 --- /dev/null +++ b/data/dataTemplates.txt @@ -0,0 +1,34 @@ + +http://www.json-generator.com/ +//500 complex +[ + '{{repeat(500)}}', + { + id: '{{index}}', + guid: '{{guid}}', + isActive: '{{bool}}', + balance: '{{numeric(1000,4000,%=$0,0.00)}}', + picture: 'http://placehold.it/32x32', + age: '{{numeric(20,40)}}', + name: '{{firstName}} {{surname}}', + gender: '{{gender}}', + company: '{{company}}', + email: '{{email}}', + phone: '+1 {{phone}}', + address: { + street: '{{numeric(100,999)}}', + city: '{{city}}', + state:'{{state}}', + zip: '{{numeric(100,10000)}}' + }, + about: '{{lorem(1,paragraphs)}}', + registered: '{{date(YYYY-MM-ddThh:mm:ss Z)}}', + friends: [ + '{{repeat(3)}}', + { + id: '{{index}}', + name: '{{firstName}} {{surname}}' + } + ] + } +] \ No newline at end of file diff --git a/docs/css/animations.css b/docs/css/animations.css new file mode 100644 index 000000000..7bf1e2e8b --- /dev/null +++ b/docs/css/animations.css @@ -0,0 +1,62 @@ +.reveal.ng-enter { + -webkit-transition:1s linear all; + -moz-transition:1s linear all; + -o-transition:1s linear all; + transition:1s linear all; + + opacity:0; +} +.reveal.ng-enter.ng-enter-active { + opacity:1; +} + +.nav-list { + padding: 0; +} + +.nav-list li { + margin:0!important; + padding:2px 15px; + overflow:hidden; + line-height:1.1em; +} + +.slide-reveal.ng-enter { + -webkit-transition:0.5s linear all; + -moz-transition:0.5s linear all; + -o-transition:0.5s linear all; + transition:0.5s linear all; + + opacity:0.5; + position:relative; + opacity:0; + top:10px; +} +.slide-reveal.ng-enter.ng-enter-active { + top:0; + opacity:1; +} + +.foldout.ng-enter, +.foldout.ng-move, +.foldout.ng-hide-add, +.foldout.ng-hide-remove { + -webkit-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; + -moz-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; + -o-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; + transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +} + +.foldout.ng-hide-remove, +.foldout.ng-hide-add.ng-hide-active, +.foldout.ng-enter, +.foldout.ng-move { + opacity:0; +} + +.foldout.ng-move.ng-move-active, +.foldout.ng-hide-remove.ng-hide-remove-active, +.foldout.ng-hide-add, +.foldout.ng-enter.ng-enter-active { + opacity:1; +} diff --git a/docs/css/bootstrap-flatly.css b/docs/css/bootstrap-flatly.css new file mode 100644 index 000000000..a25da48a4 --- /dev/null +++ b/docs/css/bootstrap-flatly.css @@ -0,0 +1,6864 @@ +@import url("//fonts.googleapis.com/css?family=Lato:400,700,900,400italic"); + +/*! + * Bootstrap v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +body { + margin: 0; + font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 15px; + line-height: 20px; + color: #2c3e50; + background-color: #ffffff; +} + +a { + color: #1abc9c; + text-decoration: none; +} + +a:hover, +a:focus { + color: #1dd2af; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 22.5px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #b4bcc2; +} + +a.muted:hover, +a.muted:focus { + color: #98a3ab; +} + +.text-warning { + color: #e6bb0d; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #b6940a; +} + +.text-error { + color: #e74c3c; +} + +a.text-error:hover, +a.text-error:focus { + color: #d62c1a; +} + +.text-info { + color: #3498db; +} + +a.text-info:hover, +a.text-info:focus { + color: #217dbb; +} + +.text-success { + color: #18bc9c; +} + +a.text-success:hover, +a.text-success:focus { + color: #128f76; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #b4bcc2; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 41.25px; +} + +h2 { + font-size: 33.75px; +} + +h3 { + font-size: 26.25px; +} + +h4 { + font-size: 18.75px; +} + +h5 { + font-size: 15px; +} + +h6 { + font-size: 12.75px; +} + +h1 small { + font-size: 26.25px; +} + +h2 small { + font-size: 18.75px; +} + +h3 small { + font-size: 15px; +} + +h4 small { + font-size: 15px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #ecf0f1; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + padding-right: 5px; + padding-left: 5px; + *zoom: 1; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #ecf0f1; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #b4bcc2; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #ecf0f1; +} + +blockquote p { + margin-bottom: 0; + font-size: 18.75px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #b4bcc2; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #ecf0f1; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 13px; + color: #7b8a8b; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 14px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 22.5px; + line-height: 40px; + color: #7b8a8b; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #b4bcc2; +} + +label, +input, +button, +select, +textarea { + font-size: 15px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 15px; + line-height: 20px; + color: #95a5a6; + vertical-align: middle; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #dce4ec; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #dce4ec; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #b4bcc2; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #dce4ec; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #b4bcc2; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #b4bcc2; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #b4bcc2; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eaeded; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #e6bb0d; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #e6bb0d; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #e6bb0d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #b6940a; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f6d963; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f6d963; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f6d963; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #e6bb0d; + background-color: #e6bb0d; + border-color: #e6bb0d; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #e74c3c; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #e74c3c; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #e74c3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #d62c1a; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f29f97; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f29f97; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f29f97; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #e74c3c; + background-color: #e74c3c; + border-color: #e74c3c; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #18bc9c; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #18bc9c; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #18bc9c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #128f76; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #51e9cb; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #51e9cb; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #51e9cb; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #18bc9c; + background-color: #18bc9c; + border-color: #18bc9c; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3498db; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3498db; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3498db; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #217dbb; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #8bc4ea; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #8bc4ea; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #8bc4ea; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3498db; + background-color: #3498db; + border-color: #3498db; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #476481; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 10px; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 15px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 15px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #ecf0f1; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #7eefd9; + border-color: #18bc9c; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success > td { + background-color: #18bc9c; +} + +.table tbody tr.error > td { + background-color: #e74c3c; +} + +.table tbody tr.warning > td { + background-color: #e6bb0d; +} + +.table tbody tr.info > td { + background-color: #3498db; +} + +.table-hover tbody tr.success:hover > td { + background-color: #15a589; +} + +.table-hover tbody tr.error:hover > td { + background-color: #e43725; +} + +.table-hover tbody tr.warning:hover > td { + background-color: #cea70c; +} + +.table-hover tbody tr.info:hover > td { + background-color: #258cd1; +} + +/*[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +}*/ + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +/*.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +}*/ + +/*.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +}*/ + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #2c3e50; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: rgba(0, 0, 0, 0.2); + border-bottom: 1px solid rgba(0, 0, 0, 0.2); +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #ffffff; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #17b394; + background-image: -moz-linear-gradient(top, #18bc9c, #15a589); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#18bc9c), to(#15a589)); + background-image: -webkit-linear-gradient(top, #18bc9c, #15a589); + background-image: -o-linear-gradient(top, #18bc9c, #15a589); + background-image: linear-gradient(to bottom, #18bc9c, #15a589); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff18bc9c', endColorstr='#ff15a589', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #17b394; + background-image: -moz-linear-gradient(top, #18bc9c, #15a589); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#18bc9c), to(#15a589)); + background-image: -webkit-linear-gradient(top, #18bc9c, #15a589); + background-image: -o-linear-gradient(top, #18bc9c, #15a589); + background-image: linear-gradient(to bottom, #18bc9c, #15a589); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff18bc9c', endColorstr='#ff15a589', GradientType=0); +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #b4bcc2; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #080b0e; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #ecf0f1; + border: 1px solid #d7e0e2; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 15px; + line-height: 20px; + color: #7b8a8b; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #bfc6cb; + *background-color: #d0d5d9; + background-image: -moz-linear-gradient(top, #b4bcc2, #d0d5d9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b4bcc2), to(#d0d5d9)); + background-image: -webkit-linear-gradient(top, #b4bcc2, #d0d5d9); + background-image: -o-linear-gradient(top, #b4bcc2, #d0d5d9); + background-image: linear-gradient(to bottom, #b4bcc2, #d0d5d9); + background-repeat: repeat-x; + border: 1px solid #dddddd; + *border: 0; + border-color: #d0d5d9 #d0d5d9 #a6afb7; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #c4c4c4; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffb4bcc2', endColorstr='#ffd0d5d9', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #7b8a8b; + background-color: #d0d5d9; + *background-color: #c2c9cd; +} + +.btn:active, +.btn.active { + background-color: #b4bcc2 \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #7b8a8b; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 18px 36px; + font-size: 18.75px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 12px; + font-size: 12.75px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 1px 8px; + font-size: 11.25px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #33485d; + *background-color: #3e5771; + background-image: -moz-linear-gradient(top, #2c3e50, #3e5771); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#2c3e50), to(#3e5771)); + background-image: -webkit-linear-gradient(top, #2c3e50, #3e5771); + background-image: -o-linear-gradient(top, #2c3e50, #3e5771); + background-image: linear-gradient(to bottom, #2c3e50, #3e5771); + background-repeat: repeat-x; + border-color: #3e5771 #3e5771 #233140; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2c3e50', endColorstr='#ff3e5771', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #3e5771; + *background-color: #354b60; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #2c3e50 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #f4a425; + *background-color: #f5b043; + background-image: -moz-linear-gradient(top, #f39c12, #f5b043); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f39c12), to(#f5b043)); + background-image: -webkit-linear-gradient(top, #f39c12, #f5b043); + background-image: -o-linear-gradient(top, #f39c12, #f5b043); + background-image: linear-gradient(to bottom, #f39c12, #f5b043); + background-repeat: repeat-x; + border-color: #f5b043 #f5b043 #e08e0b; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff39c12', endColorstr='#fff5b043', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f5b043; + *background-color: #f4a62a; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #f39c12 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #e95d4e; + *background-color: #ed7669; + background-image: -moz-linear-gradient(top, #e74c3c, #ed7669); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e74c3c), to(#ed7669)); + background-image: -webkit-linear-gradient(top, #e74c3c, #ed7669); + background-image: -o-linear-gradient(top, #e74c3c, #ed7669); + background-image: linear-gradient(to bottom, #e74c3c, #ed7669); + background-repeat: repeat-x; + border-color: #ed7669 #ed7669 #e43725; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe74c3c', endColorstr='#ffed7669', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #ed7669; + *background-color: #ea6153; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #e74c3c \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #1dccaa; + *background-color: #24e3be; + background-image: -moz-linear-gradient(top, #18bc9c, #24e3be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#18bc9c), to(#24e3be)); + background-image: -webkit-linear-gradient(top, #18bc9c, #24e3be); + background-image: -o-linear-gradient(top, #18bc9c, #24e3be); + background-image: linear-gradient(to bottom, #18bc9c, #24e3be); + background-repeat: repeat-x; + border-color: #24e3be #24e3be #15a589; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff18bc9c', endColorstr='#ff24e3be', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #24e3be; + *background-color: #1bd3af; +} + +.btn-success:active, +.btn-success.active { + background-color: #18bc9c \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #45a1de; + *background-color: #5faee3; + background-image: -moz-linear-gradient(top, #3498db, #5faee3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#3498db), to(#5faee3)); + background-image: -webkit-linear-gradient(top, #3498db, #5faee3); + background-image: -o-linear-gradient(top, #3498db, #5faee3); + background-image: linear-gradient(to bottom, #3498db, #5faee3); + background-repeat: repeat-x; + border-color: #5faee3 #5faee3 #258cd1; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3498db', endColorstr='#ff5faee3', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #5faee3; + *background-color: #4aa3df; +} + +.btn-info:active, +.btn-info.active { + background-color: #3498db \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #2c2c2c; + *background-color: #3c3c3c; + background-image: -moz-linear-gradient(top, #222222, #3c3c3c); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#3c3c3c)); + background-image: -webkit-linear-gradient(top, #222222, #3c3c3c); + background-image: -o-linear-gradient(top, #222222, #3c3c3c); + background-image: linear-gradient(to bottom, #222222, #3c3c3c); + background-repeat: repeat-x; + border-color: #3c3c3c #3c3c3c #151515; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff3c3c3c', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #3c3c3c; + *background-color: #2f2f2f; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #222222 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #1abc9c; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover, +.btn-link:focus { + color: #1dd2af; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #7b8a8b; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 15px; +} + +.btn-group > .btn-mini { + font-size: 11.25px; +} + +.btn-group > .btn-small { + font-size: 12.75px; +} + +.btn-group > .btn-large { + font-size: 18.75px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 10px; + border-bottom-left-radius: 10px; + -webkit-border-top-left-radius: 10px; + border-top-left-radius: 10px; + -moz-border-radius-bottomleft: 10px; + -moz-border-radius-topleft: 10px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 10px; + border-top-right-radius: 10px; + -webkit-border-bottom-right-radius: 10px; + border-bottom-right-radius: 10px; + -moz-border-radius-topright: 10px; + -moz-border-radius-bottomright: 10px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #d0d5d9; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #3e5771; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f5b043; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #ed7669; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #24e3be; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #5faee3; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #3c3c3c; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 10px 10px 0 0; + -moz-border-radius: 10px 10px 0 0; + border-radius: 10px 10px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 10px 10px; + -moz-border-radius: 0 0 10px 10px; + border-radius: 0 0 10px 10px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #e6bb0d; + border: 1px solid transparent; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.alert, +.alert h4 { + color: #e6bb0d; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #18bc9c; + background-color: #18bc9c; + border-color: transparent; +} + +.alert-success h4 { + color: #18bc9c; +} + +.alert-danger, +.alert-error { + color: #e74c3c; + background-color: #e74c3c; + border-color: transparent; +} + +.alert-danger h4, +.alert-error h4 { + color: #e74c3c; +} + +.alert-info { + color: #3498db; + background-color: #3498db; + border-color: transparent; +} + +.alert-info h4 { + color: #3498db; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #ecf0f1; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #b4bcc2; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #1abc9c; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #ecf0f1 #ecf0f1 #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #95a5a6; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #1abc9c; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #1abc9c; + border-bottom-color: #1abc9c; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #1dd2af; + border-bottom-color: #1dd2af; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #95a5a6; + border-bottom-color: #95a5a6; +} + +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #b4bcc2; + border-color: #b4bcc2; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #b4bcc2; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #ecf0f1 #dddddd #ecf0f1 #ecf0f1; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #ecf0f1 #ecf0f1 #ecf0f1 #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #b4bcc2; +} + +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 50px; + padding-right: 20px; + padding-left: 20px; + background-color: #2c3e50; + background-image: -moz-linear-gradient(top, #2c3e50, #2c3e50); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#2c3e50), to(#2c3e50)); + background-image: -webkit-linear-gradient(top, #2c3e50, #2c3e50); + background-image: -o-linear-gradient(top, #2c3e50, #2c3e50); + background-image: linear-gradient(to bottom, #2c3e50, #2c3e50); + background-repeat: repeat-x; + border: 1px solid #233140; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2c3e50', endColorstr='#ff2c3e50', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 15px 20px 15px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #ffffff; + text-shadow: 0 1px 0 #2c3e50; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 50px; + color: #ffffff; +} + +.navbar-link { + color: #ffffff; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #1abc9c; +} + +.navbar .divider-vertical { + height: 50px; + margin: 0 9px; + border-right: 1px solid #2c3e50; + border-left: 1px solid #2c3e50; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 10px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 10px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 10px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 15px 15px 15px; + color: #ffffff; + text-decoration: none; + text-shadow: 0 1px 0 #2c3e50; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #1abc9c; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #1abc9c; + text-decoration: none; + background-color: #233140; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #233140; + *background-color: #233140; + background-image: -moz-linear-gradient(top, #233140, #233140); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#233140), to(#233140)); + background-image: -webkit-linear-gradient(top, #233140, #233140); + background-image: -o-linear-gradient(top, #233140, #233140); + background-image: linear-gradient(to bottom, #233140, #233140); + background-repeat: repeat-x; + border-color: #233140 #233140 #080b0e; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff233140', endColorstr='#ff233140', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #233140; + *background-color: #1a242f; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #11181f \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #2c3e50; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #2c3e50; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #1abc9c; + border-bottom-color: #1abc9c; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #1abc9c; + background-color: #233140; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #1abc9c; + border-bottom-color: #1abc9c; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #18bc9c; + background-image: -moz-linear-gradient(top, #18bc9c, #18bc9c); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#18bc9c), to(#18bc9c)); + background-image: -webkit-linear-gradient(top, #18bc9c, #18bc9c); + background-image: -o-linear-gradient(top, #18bc9c, #18bc9c); + background-image: linear-gradient(to bottom, #18bc9c, #18bc9c); + background-repeat: repeat-x; + border-color: #15a589; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff18bc9c', endColorstr='#ff18bc9c', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #2c3e50; +} + +.navbar-inverse .brand { + color: #ffffff; +} + +.navbar-inverse .navbar-text { + color: #ffffff; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #2c3e50; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #2c3e50; + background-color: #15a589; +} + +.navbar-inverse .navbar-link { + color: #ffffff; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #2c3e50; +} + +.navbar-inverse .divider-vertical { + border-right-color: #18bc9c; + border-left-color: #18bc9c; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #2c3e50; + background-color: #15a589; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #2c3e50; + border-bottom-color: #2c3e50; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #2c3e50; + border-bottom-color: #2c3e50; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #ffffff; + border-color: #b4bcc2; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #95a5a6; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #95a5a6; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #95a5a6; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #7b8a8b; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #15a589; + *background-color: #15a589; + background-image: -moz-linear-gradient(top, #15a589, #15a589); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#15a589), to(#15a589)); + background-image: -webkit-linear-gradient(top, #15a589, #15a589); + background-image: -o-linear-gradient(top, #15a589, #15a589); + background-image: linear-gradient(to bottom, #15a589, #15a589); + background-repeat: repeat-x; + border-color: #15a589 #15a589 #0c6251; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff15a589', endColorstr='#ff15a589', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #15a589; + *background-color: #128f76; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #0f7864 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #b4bcc2; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #ecf0f1; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #b4bcc2; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #b4bcc2; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 18px 36px; + font-size: 18.75px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 10px; + border-bottom-left-radius: 10px; + -webkit-border-top-left-radius: 10px; + border-top-left-radius: 10px; + -moz-border-radius-bottomleft: 10px; + -moz-border-radius-topleft: 10px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 10px; + border-top-right-radius: 10px; + -webkit-border-bottom-right-radius: 10px; + border-bottom-right-radius: 10px; + -moz-border-radius-topright: 10px; + -moz-border-radius-bottomright: 10px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 12px; + font-size: 12.75px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 1px 8px; + font-size: 11.25px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #b4bcc2; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} + +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} + +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} + +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #2c3e50; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #2c3e50; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #2c3e50; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #2c3e50; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #2c3e50; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #2c3e50; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #2c3e50; + border-bottom: 1px solid #233140; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-title:empty { + display: none; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #2c3e50; + border-bottom-width: 0; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #2c3e50; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #2c3e50; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #2c3e50; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #1abc9c; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #95a5a6; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 12.69px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #b4bcc2; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #e74c3c; +} + +.label-important[href], +.badge-important[href] { + background-color: #d62c1a; +} + +.label-warning, +.badge-warning { + background-color: #f39c12; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c87f0a; +} + +.label-success, +.badge-success { + background-color: #18bc9c; +} + +.label-success[href], +.badge-success[href] { + background-color: #128f76; +} + +.label-info, +.badge-info { + background-color: #3498db; +} + +.label-info[href], +.badge-info[href] { + background-color: #217dbb; +} + +.label-inverse, +.badge-inverse { + background-color: #7b8a8b; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #636f70; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #f5ae3e; + background-image: -moz-linear-gradient(top, #f7ba5b, #f39c12); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f7ba5b), to(#f39c12)); + background-image: -webkit-linear-gradient(top, #f7ba5b, #f39c12); + background-image: -o-linear-gradient(top, #f7ba5b, #f39c12); + background-image: linear-gradient(to bottom, #f7ba5b, #f39c12); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff7ba5b', endColorstr='#fff39c12', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #f7ba5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #7b8a8b; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #ecf0f1; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} + +h1 { + font-size: 48px; + font-weight: 900; +} + +h2 { + font-size: 36px; + font-weight: 700; +} + +h3 { + font-size: 28px; + font-weight: 700; +} + +h4 { + font-size: 24px; + font-weight: 500; +} + +h5 { + font-size: 16px; + font-weight: 500; +} + +h6 { + font-size: 13px; + font-weight: 500; + text-transform: none; +} + +p { + margin-bottom: 1em; +} + +.page-header { + border-bottom: none; +} + +.navbar .brand { + text-shadow: none; +} + +.navbar .brand:hover { + color: #1dd2af; +} + +.navbar .navbar-inner { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.navbar .nav > li > a { + text-shadow: none; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.navbar .navbar-search .search-query { + line-height: normal; + border: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.navbar .btn-navbar { + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 6px; +} + +.navbar-inverse .brand:hover { + color: #2c3e50; +} + +.navbar-inverse .navbar-search .search-query { + line-height: normal; + color: #2c3e50; + border-color: transparent; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.navbar-inverse .navbar-search .search-query:focus { + padding: 4px 14px; + color: #2c3e50; +} + +div.subnav { + background-color: #ecf0f1; + background-image: none; + border-color: transparent; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +div.subnav-fixed { + top: 50px; +} + +div.subnav .nav > li > a { + color: #2c3e50; + border-color: transparent; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +div.subnav .nav > .active > a, +div.subnav .nav > .active > a:hover { + color: #2c3e50; + background-color: #cfd9db; + border-color: transparent; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.nav-list > li > a, +.nav-list > .active > a, +.nav-list .nav-header { + text-shadow: none; +} + +.nav-list .divider { + background: none; + border-bottom: 2px solid rgba(0, 0, 0, 0.2); +} + +.nav-pills .open .dropdown-toggle { + background-color: #2c3e50; +} + +.pagination ul { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.pagination ul > li > a { + color: #ffffff; + background-color: #18bc9c; + border-color: transparent; +} + +.pagination ul > li > a:hover { + background-color: #24e3be; +} + +.pagination ul > .active > a, +.pagination ul > .active > a:hover { + color: #2c3e50; + background-color: #ecf0f1; +} + +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover { + color: #ffffff; + background-color: #24e3be; +} + +.pager li > a, +.pager li > span { + color: #ffffff; + background-color: #18bc9c; + border: none; +} + +.pager li > a:hover, +.pager li > span:hover { + background-color: #24e3be; +} + +.pager .disabled > a, +.pager .disabled > span, +.pager .disabled > a:hover, +.pager .disabled > span:hover { + color: #ffffff; + background-color: #24e3be; +} + +.breadcrumb > li { + text-shadow: none; +} + +.btn { + padding: 9px 20px; + color: #ffffff; + text-decoration: none; + text-shadow: none; + background-image: none; + border: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-transition: 0.25s; + -moz-transition: 0.25s; + transition: 0.25s; +} + +.btn:hover, +.btn:focus { + color: white; + -webkit-transition: 0.25s; + -moz-transition: 0.25s; + transition: 0.25s; +} + +.btn:active, +.btn.active { + color: rgba(255, 255, 255, 0.75); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn.disabled, +.btn[disabled] { + color: white; +} + +.btn-large { + padding: 18px 36px; +} + +.btn-small { + padding: 2px 12px; +} + +.btn-mini { + padding: 1px 8px; +} + +.table tbody tr.success > td, +.table tbody tr.error > td, +.table tbody tr.warning > td, +.table tbody tr.info > td { + color: #ffffff; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + padding: 7px 6px; + text-indent: 1px; + border: 2px solid #dce4ec; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +textarea:-moz-placeholder, +input[type="text"]:-moz-placeholder, +input[type="password"]:-moz-placeholder, +input[type="datetime"]:-moz-placeholder, +input[type="datetime-local"]:-moz-placeholder, +input[type="date"]:-moz-placeholder, +input[type="month"]:-moz-placeholder, +input[type="time"]:-moz-placeholder, +input[type="week"]:-moz-placeholder, +input[type="number"]:-moz-placeholder, +input[type="email"]:-moz-placeholder, +input[type="url"]:-moz-placeholder, +input[type="search"]:-moz-placeholder, +input[type="tel"]:-moz-placeholder, +input[type="color"]:-moz-placeholder, +.uneditable-input:-moz-placeholder { + color: #acb6c0; +} + +textarea:-ms-input-placeholder, +input[type="text"]:-ms-input-placeholder, +input[type="password"]:-ms-input-placeholder, +input[type="datetime"]:-ms-input-placeholder, +input[type="datetime-local"]:-ms-input-placeholder, +input[type="date"]:-ms-input-placeholder, +input[type="month"]:-ms-input-placeholder, +input[type="time"]:-ms-input-placeholder, +input[type="week"]:-ms-input-placeholder, +input[type="number"]:-ms-input-placeholder, +input[type="email"]:-ms-input-placeholder, +input[type="url"]:-ms-input-placeholder, +input[type="search"]:-ms-input-placeholder, +input[type="tel"]:-ms-input-placeholder, +input[type="color"]:-ms-input-placeholder, +.uneditable-input:-ms-input-placeholder { + color: #acb6c0; +} + +textarea::-webkit-input-placeholder, +input[type="text"]::-webkit-input-placeholder, +input[type="password"]::-webkit-input-placeholder, +input[type="datetime"]::-webkit-input-placeholder, +input[type="datetime-local"]::-webkit-input-placeholder, +input[type="date"]::-webkit-input-placeholder, +input[type="month"]::-webkit-input-placeholder, +input[type="time"]::-webkit-input-placeholder, +input[type="week"]::-webkit-input-placeholder, +input[type="number"]::-webkit-input-placeholder, +input[type="email"]::-webkit-input-placeholder, +input[type="url"]::-webkit-input-placeholder, +input[type="search"]::-webkit-input-placeholder, +input[type="tel"]::-webkit-input-placeholder, +input[type="color"]::-webkit-input-placeholder, +.uneditable-input::-webkit-input-placeholder { + color: #acb6c0; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: #1abc9c; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-prepend input, +.input-append input, +.input-prepend select, +.input-append select, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend input + .btn-group .btn, +.input-append input + .btn-group .btn, +.input-prepend select + .btn-group .btn, +.input-append select + .btn-group .btn, +.input-prepend .uneditable-input + .btn-group .btn, +.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-prepend .add-on:first-child, +.input-append .add-on:first-child, +.input-prepend .btn:first-child, +.input-append .btn:first-child { + -webkit-border-radius: 6px 0 0 6px; + -moz-border-radius: 6px 0 0 6px; + border-radius: 6px 0 0 6px; +} + +.input-prepend .add-on:last-child, +.input-append .add-on:last-child, +.input-prepend .btn:last-child, +.input-append .btn:last-child { + -webkit-border-radius: 0 6px 6px 0; + -moz-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.input-append .add-on, +.input-prepend .add-on { + padding: 9px 5px; + text-shadow: none; + border: none; +} + +.control-group.error, +.control-group.error input:focus, +.control-group.error textarea:focus { + border-color: #e74c3c; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.control-group.success, +.control-group.success input:focus, +.control-group.success textarea:focus { + border-color: #2ecc71; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.control-group.warning, +.control-group.warning input:focus, +.control-group.warning textarea:focus { + border-color: #f1c40f; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.control-group.info, +.control-group.info input:focus, +.control-group.info textarea:focus { + border-color: #3498db; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +input[disabled], +input[readonly], +textarea[disabled], +textarea[readonly] { + color: #cad2d3; + cursor: default; + background-color: #eaeded; + border-color: transparent; +} + +input[type="file"] { + line-height: 16px; +} + +legend { + color: #2c3e50; + border-bottom: none; +} + +.form-actions { + background-color: #dde4e6; + border-top: none; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.alert { + color: #ffffff; + text-shadow: none; + background-color: #f39c12; +} + +.alert h1, +.alert h2, +.alert h3, +.alert h4, +.alert h5, +.alert h6 { + color: #ffffff; +} + +.alert-error { + background-color: #e74c3c; +} + +.alert-success { + background-color: #18bc9c; +} + +.alert-info { + background-color: #3498db; +} + +.label { + padding: 6px 10px; + text-shadow: none; +} + +.badge { + padding: 6px 10px; + text-shadow: none; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; +} + +.well { + border: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.progress { + height: 12px; + background: #ecf0f1; + border-radius: 32px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.progress .bar { + background-color: #2c3e50; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.progress .bar + .bar { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.progress-striped .bar { + background-color: #2c3e50; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress-success.progress-striped .bar, +.progress .bar-success { + background-color: #18bc9c; +} + +.progress-warning .bar, +.progress-warning.progress-striped .bar, +.progress .bar-warning { + background-color: #e6bb0d; +} + +.progress-danger .bar, +.progress-danger.progress-striped .bar, +.progress .bar-danger { + background-color: #e74c3c; +} + +.progress-info .bar, +.progress-info.progress-striped .bar, +.progress .bar-info { + background-color: #3498db; +} + +.tooltip.in { + opacity: 1; +} + +.popover { + color: #ffffff; +} + +.popover-title { + border-bottom: 2px solid rgba(0, 0, 0, 0.2); +} + +.modal-header { + color: #ffffff; + background-color: #2c3e50; + border-bottom: none; +} + +.modal-footer { + background-color: #ecf0f1; + border-top: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.close { + text-shadow: none; +} + +@media (max-width: 767px) { + div.subnav .nav > li:first-child > a, + div.subnav .nav > li + li > a { + border-color: transparent; + } + div.subnav .nav > li:first-child > a:hover, + div.subnav .nav > li + li > a:hover { + background-color: #cfd9db; + } + div.subnav .nav > li:last-child > a { + border-radius: 0 0 4px 4px; + } + .input-append .add-on, + .input-prepend .add-on, + .input-append .btn, + .input-prepend .btn { + padding: 5px; + } +} + +@media (max-width: 979px) { + .navbar .nav-collapse .nav > li > a { + color: #ffffff; + } + .navbar .nav-collapse .nav > li > a:hover { + background-color: #18bc9c; + } +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} + + +/* Customizations */ +[source-edit] a { + border-radius: 6px 6px 0px 0px !important; +} \ No newline at end of file diff --git a/docs/css/bootstrap-flatly.min.css b/docs/css/bootstrap-flatly.min.css new file mode 100644 index 000000000..32879dd4a --- /dev/null +++ b/docs/css/bootstrap-flatly.min.css @@ -0,0 +1,7 @@ +@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");/*! + * bootswatch v3.2.0 + * Homepage: http://bootswatch.com + * Copyright 2012-2014 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.table td,.table th{background-color:#fff !important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#18bc9c;text-decoration:none}a:hover,a:focus{color:#18bc9c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;width:100% \9;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #ecf0f1}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#b4bcc2}h1,.h1,h2,.h2,h3,.h3{margin-top:21px;margin-bottom:10.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10.5px;margin-bottom:10.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:39px}h2,.h2{font-size:32px}h3,.h3{font-size:26px}h4,.h4{font-size:19px}h5,.h5{font-size:15px}h6,.h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}small,.small{font-size:86%}cite{font-style:normal}mark,.mark{background-color:#f39c12;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#b4bcc2}.text-primary{color:#2c3e50}a.text-primary:hover{color:#1a242f}.text-success{color:#ffffff}a.text-success:hover{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover{color:#e6e6e6}.bg-primary{color:#fff;background-color:#2c3e50}a.bg-primary:hover{background-color:#1a242f}.bg-success{background-color:#18bc9c}a.bg-success:hover{background-color:#128f76}.bg-info{background-color:#3498db}a.bg-info:hover{background-color:#217dbb}.bg-warning{background-color:#f39c12}a.bg-warning:hover{background-color:#c87f0a}.bg-danger{background-color:#e74c3c}a.bg-danger:hover{background-color:#d62c1a}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid transparent}ul,ol{margin-top:0;margin-bottom:10.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #b4bcc2}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #ecf0f1}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#b4bcc2}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #ecf0f1;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#7b8a8b;background-color:#ecf0f1;border:1px solid #cccccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ecf0f1}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ecf0f1}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ecf0f1}.table .table{background-color:#ffffff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#ecf0f1}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#ecf0f1}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#dde4e6}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#18bc9c}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#15a589}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#3498db}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#258cd1}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f39c12}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#e08e0b}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#e74c3c}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#e43725}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ecf0f1;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#2c3e50;border:0;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:11px;font-size:15px;line-height:1.42857143;color:#2c3e50}.form-control{display:block;width:100%;height:43px;padding:10px 15px;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff;background-image:none;border:1px solid #dce4ec;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#2c3e50;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6)}.form-control::-moz-placeholder{color:#acb6c0;opacity:1}.form-control:-ms-input-placeholder{color:#acb6c0}.form-control::-webkit-input-placeholder{color:#acb6c0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#ecf0f1;opacity:1}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:43px;line-height:1.42857143 \0}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm{line-height:33px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg{line-height:64px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:21px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:11px;padding-bottom:11px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-sm{height:33px;line-height:33px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:64px;padding:18px 27px;font-size:19px;line-height:1.33;border-radius:6px}select.input-lg{height:64px;line-height:64px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:53.75px}.form-control-feedback{position:absolute;top:26px;right:0;z-index:2;display:block;width:43px;height:43px;line-height:43px;text-align:center}.input-lg+.form-control-feedback{width:64px;height:64px;line-height:64px}.input-sm+.form-control-feedback{width:33px;height:33px;line-height:33px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#18bc9c}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#f39c12}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#e74c3c}.has-error .form-control-feedback{color:#ffffff}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#597ea2}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:11px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:32px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:11px}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:24.94px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:7px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:10px 15px;font-size:15px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#ffffff;background-color:#95a5a6;border-color:#95a5a6}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#95a5a6;border-color:#95a5a6}.btn-default .badge{color:#95a5a6;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#2c3e50;border-color:#2c3e50}.btn-primary .badge{color:#2c3e50;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#18bc9c;border-color:#18bc9c}.btn-success .badge{color:#18bc9c;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#3498db;border-color:#3498db}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#3498db;border-color:#3498db}.btn-info .badge{color:#3498db;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f39c12;border-color:#f39c12}.btn-warning .badge{color:#f39c12;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#e74c3c;border-color:#e74c3c}.btn-danger .badge{color:#e74c3c;background-color:#ffffff}.btn-link{color:#18bc9c;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#18bc9c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#b4bcc2;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:18px 27px;font-size:19px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#ffffff;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#7b8a8b;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#2c3e50}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#2c3e50}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#b4bcc2}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#b4bcc2;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{position:absolute;z-index:-1;opacity:0;filter:alpha(opacity=0)}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:64px;padding:18px 27px;font-size:19px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:64px;line-height:64px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:33px;line-height:33px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:10px 15px;font-size:15px;font-weight:normal;line-height:1;color:#2c3e50;text-align:center;background-color:#ecf0f1;border:1px solid #dce4ec;border-radius:4px}.input-group-addon.input-sm{padding:6px 9px;font-size:13px;border-radius:3px}.input-group-addon.input-lg{padding:18px 27px;font-size:19px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#ecf0f1}.nav>li.disabled>a{color:#b4bcc2}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#b4bcc2;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#ecf0f1;border-color:#18bc9c}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ecf0f1}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#ecf0f1 #ecf0f1 #ecf0f1}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#2c3e50;background-color:#ffffff;border:1px solid #ecf0f1;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#ffffff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:#2c3e50}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#ffffff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:60px;margin-bottom:21px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:19.5px 15px;font-size:19px;line-height:21px;height:60px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:13px;margin-bottom:13px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:9.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:19.5px;padding-bottom:19.5px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8.5px;margin-bottom:8.5px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8.5px;margin-bottom:8.5px}.navbar-btn.btn-sm{margin-top:13.5px;margin-bottom:13.5px}.navbar-btn.btn-xs{margin-top:19px;margin-bottom:19px}.navbar-text{margin-top:19.5px;margin-bottom:19.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#2c3e50;border-color:transparent}.navbar-default .navbar-brand{color:#ffffff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-text{color:#777777}.navbar-default .navbar-nav>li>a{color:#ffffff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#1a242f}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#1a242f}.navbar-default .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#1a242f;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#ffffff}.navbar-default .navbar-link:hover{color:#18bc9c}.navbar-default .btn-link{color:#ffffff}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#18bc9c}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#18bc9c;border-color:transparent}.navbar-inverse .navbar-brand{color:#ffffff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-text{color:#ffffff}.navbar-inverse .navbar-nav>li>a{color:#ffffff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#128f76}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#128f76}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#149c82}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#15a589;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#ffffff}.navbar-inverse .navbar-link:hover{color:#2c3e50}.navbar-inverse .btn-link{color:#ffffff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#2c3e50}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#cccccc}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#ecf0f1;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#95a5a6}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:10px 15px;line-height:1.42857143;text-decoration:none;color:#ffffff;background-color:#18bc9c;border:1px solid transparent;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#ffffff;background-color:#0f7864;border-color:transparent}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#ffffff;background-color:#0f7864;border-color:transparent;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#ecf0f1;background-color:#3be6c4;border-color:transparent;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:18px 27px;font-size:19px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:6px 9px;font-size:13px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#18bc9c;border:1px solid transparent;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#0f7864}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#ffffff;background-color:#18bc9c;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#95a5a6}.label-default[href]:hover,.label-default[href]:focus{background-color:#798d8f}.label-primary{background-color:#2c3e50}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#1a242f}.label-success{background-color:#18bc9c}.label-success[href]:hover,.label-success[href]:focus{background-color:#128f76}.label-info{background-color:#3498db}.label-info[href]:hover,.label-info[href]:focus{background-color:#217dbb}.label-warning{background-color:#f39c12}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c87f0a}.label-danger{background-color:#e74c3c}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#d62c1a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#2c3e50;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2c3e50;background-color:#ffffff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#ecf0f1}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#cfd9db}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:67.5px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#18bc9c}.thumbnail .caption{padding:9px;color:#2c3e50}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#18bc9c;border-color:#18bc9c;color:#ffffff}.alert-success hr{border-top-color:#15a589}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#3498db;border-color:#3498db;color:#ffffff}.alert-info hr{border-top-color:#258cd1}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#f39c12;border-color:#f39c12;color:#ffffff}.alert-warning hr{border-top-color:#e08e0b}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#e74c3c;border-color:#e74c3c;color:#ffffff}.alert-danger hr{border-top-color:#e43725}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#ecf0f1;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:13px;line-height:21px;color:#ffffff;text-align:center;background-color:#2c3e50;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{color:#b4bcc2;min-width:30px;background-color:transparent;background-image:none;box-shadow:none}.progress-bar-success{background-color:#18bc9c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#3498db}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#e74c3c}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#ffffff;border:1px solid #ecf0f1}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555555}a.list-group-item .list-group-item-heading{color:#333333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;color:#555555;background-color:#ecf0f1}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#ecf0f1;color:#b4bcc2}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#b4bcc2}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#8aa4be}.list-group-item-success{color:#ffffff;background-color:#18bc9c}a.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#ffffff;background-color:#15a589}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#3498db}a.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#ffffff;background-color:#258cd1}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#f39c12}a.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#ffffff;background-color:#e08e0b}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#e74c3c}a.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#ffffff;background-color:#e43725}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#ffffff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#ecf0f1;border-top:1px solid #ecf0f1;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ecf0f1}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ecf0f1}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ecf0f1}.panel-default{border-color:#ecf0f1}.panel-default>.panel-heading{color:#2c3e50;background-color:#ecf0f1;border-color:#ecf0f1}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ecf0f1}.panel-default>.panel-heading .badge{color:#ecf0f1;background-color:#2c3e50}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ecf0f1}.panel-primary{border-color:#2c3e50}.panel-primary>.panel-heading{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#2c3e50}.panel-primary>.panel-heading .badge{color:#2c3e50;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#2c3e50}.panel-success{border-color:#18bc9c}.panel-success>.panel-heading{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#18bc9c}.panel-success>.panel-heading .badge{color:#18bc9c;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#18bc9c}.panel-info{border-color:#3498db}.panel-info>.panel-heading{color:#ffffff;background-color:#3498db;border-color:#3498db}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#3498db}.panel-info>.panel-heading .badge{color:#3498db;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#3498db}.panel-warning{border-color:#f39c12}.panel-warning>.panel-heading{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f39c12}.panel-warning>.panel-heading .badge{color:#f39c12;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f39c12}.panel-danger{border-color:#e74c3c}.panel-danger>.panel-heading{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e74c3c}.panel-danger>.panel-heading .badge{color:#e74c3c;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e74c3c}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#ecf0f1;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:22.5px;font-weight:bold;line-height:1;color:#000000;text-shadow:none;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate3d(0, -25%, 0);transform:translate3d(0, -25%, 0);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#ffffff;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;visibility:visible;font-size:13px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:rgba(0,0,0,0.9);border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,0.9)}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,0.9)}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,0.9)}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:rgba(0,0,0,0.9)}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:rgba(0,0,0,0.9)}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;background-clip:padding-box;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.navbar{border-width:0}.navbar-default .badge{background-color:#fff;color:#2c3e50}.navbar-inverse .badge{background-color:#fff;color:#18bc9c}.navbar-brand{padding:18.5px 15px 20.5px}.btn:active{-webkit-box-shadow:none;box-shadow:none}.btn-group.open .dropdown-toggle{-webkit-box-shadow:none;box-shadow:none}.text-primary,.text-primary:hover{color:#2c3e50}.text-success,.text-success:hover{color:#18bc9c}.text-danger,.text-danger:hover{color:#e74c3c}.text-warning,.text-warning:hover{color:#f39c12}.text-info,.text-info:hover{color:#3498db}table a:not(.btn),.table a:not(.btn){text-decoration:underline}table .success,.table .success,table .warning,.table .warning,table .danger,.table .danger,table .info,.table .info{color:#fff}table .success a,.table .success a,table .warning a,.table .warning a,table .danger a,.table .danger a,table .info a,.table .info a{color:#fff}table>thead>tr>th,.table>thead>tr>th,table>tbody>tr>th,.table>tbody>tr>th,table>tfoot>tr>th,.table>tfoot>tr>th,table>thead>tr>td,.table>thead>tr>td,table>tbody>tr>td,.table>tbody>tr>td,table>tfoot>tr>td,.table>tfoot>tr>td{border:none}table-bordered>thead>tr>th,.table-bordered>thead>tr>th,table-bordered>tbody>tr>th,.table-bordered>tbody>tr>th,table-bordered>tfoot>tr>th,.table-bordered>tfoot>tr>th,table-bordered>thead>tr>td,.table-bordered>thead>tr>td,table-bordered>tbody>tr>td,.table-bordered>tbody>tr>td,table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.form-control,input{border-width:2px;-webkit-box-shadow:none;box-shadow:none}.form-control:focus,input:focus{-webkit-box-shadow:none;box-shadow:none}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning .form-control-feedback{color:#f39c12}.has-warning .form-control,.has-warning .form-control:focus{border:2px solid #f39c12}.has-warning .input-group-addon{border-color:#f39c12}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error .form-control-feedback{color:#e74c3c}.has-error .form-control,.has-error .form-control:focus{border:2px solid #e74c3c}.has-error .input-group-addon{border-color:#e74c3c}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success .form-control-feedback{color:#18bc9c}.has-success .form-control,.has-success .form-control:focus{border:2px solid #18bc9c}.has-success .input-group-addon{border-color:#18bc9c}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{border-color:transparent}.pager a,.pager a:hover{color:#fff}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{background-color:#3be6c4}.close{color:#fff;text-decoration:none;opacity:0.4}.close:hover,.close:focus{color:#fff;opacity:1}.alert .alert-link{color:#fff;text-decoration:underline}.progress{height:10px;-webkit-box-shadow:none;box-shadow:none}.progress .progress-bar{font-size:10px;line-height:10px}.well{-webkit-box-shadow:none;box-shadow:none}.panel-default .close{color:#2c3e50}.modal .close{color:#2c3e50}.popover{color:#2c3e50} \ No newline at end of file diff --git a/docs/css/bootstrap.min.css b/docs/css/bootstrap.min.css new file mode 100644 index 000000000..b725064aa --- /dev/null +++ b/docs/css/bootstrap.min.css @@ -0,0 +1,6167 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +a.muted:hover, +a.muted:focus { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover, +a.text-error:focus { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover, +a.text-info:focus { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover, +a.text-success:focus { + color: #356635; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 38.5px; +} + +h2 { + font-size: 31.5px; +} + +h3 { + font-size: 24.5px; +} + +h4 { + font-size: 17.5px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11.9px; +} + +h1 small { + font-size: 24.5px; +} + +h2 small { + font-size: 17.5px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + padding-right: 5px; + padding-left: 5px; + *zoom: 1; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 10px; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success > td { + background-color: #dff0d8; +} + +.table tbody tr.error > td { + background-color: #f2dede; +} + +.table tbody tr.warning > td { + background-color: #fcf8e3; +} + +.table tbody tr.info > td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover > td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover > td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover > td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover > td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover, +.btn-link:focus { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 10.5px; +} + +.btn-group > .btn-small { + font-size: 11.9px; +} + +.btn-group > .btn-large { + font-size: 17.5px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert, +.alert h4 { + color: #c09853; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success h4 { + color: #468847; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info h4 { + color: #3a87ad; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} + +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} + +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} + +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-title:empty { + display: none; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} diff --git a/docs/css/doc_widgets.css b/docs/css/doc_widgets.css new file mode 100644 index 000000000..b0348b221 --- /dev/null +++ b/docs/css/doc_widgets.css @@ -0,0 +1,150 @@ +ul.doc-example { + list-style-type: none; + position: relative; + font-size: 14px; +} + +ul.doc-example > li { + border: 2px solid gray; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + background-color: white; + margin-bottom: 20px; +} + +ul.doc-example > li.doc-example-heading { + border: none; + border-radius: none; + margin-bottom: -10px; +} + +span.nojsfiddle { + float: right; + font-size: 14px; + margin-right:10px; + margin-top: 10px; +} + +form.jsfiddle { + position: absolute; + right: 0; + z-index: 1; + height: 14px; +} + +form.jsfiddle button { + cursor: pointer; + padding: 4px 10px; + margin: 10px; + background-color: #FFF; + font-weight: bold; + color: #7989D6; + border-color: #7989D6; + -moz-border-radius: 8px; + -webkit-border-radius:8px; + border-radius: 8px; +} + +form.jsfiddle textarea, form.jsfiddle input { + display: none; +} + +li.doc-example-live { + padding: 10px; + font-size: 1.2em; +} + +div.syntaxhighlighter { + padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars http://is.gd/gSMgC */ +} + +/* TABS - tutorial environment navigation */ + +div.tabs-nav { + height: 25px; + position: relative; +} + +div.tabs-nav ul li { + list-style: none; + display: inline-block; + padding: 5px 10px; +} + +div.tabs-nav ul li.current a { + color: white; + text-decoration: none; +} + +div.tabs-nav ul li.current { + background: #7989D6; + -moz-box-shadow: 4px 4px 6px #48577D; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + box-shadow: 4px 4px 6px #48577D; + border-radius-topright: 8px; + border-radius-topleft: 8px; + -webkit-box-shadow: 4px 4px 6px #48577D; + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + border-top-right-radius: 8px; + border-top-left-radius: 8px; +} + +div.tabs-content { + padding: 4px; + position: relative; + background: #7989D6; + -moz-border-radius: 8px; + border-radius: 8px; + -webkit-border-radius: 8px; +} + +div.tabs-content-inner { + margin: 1px; + padding: 10px; + background: white; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; +} + + +/* Tutorial Nav Bar */ + +#tutorial-nav { + margin: 0.5em 0 1em 0; + padding: 0; + list-style-type: none; + background: #7989D6; + + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + border-radius: 15px; + + -moz-box-shadow: 4px 4px 6px #48577D; + -webkit-box-shadow: 4px 4px 6px #48577D; + box-shadow: 4px 4px 6px #48577D; +} + + +#tutorial-nav li { + display: inline; +} + + +#tutorial-nav a:link, #tutorial-nav a:visited { + font-size: 1.2em; + color: #FFF; + text-decoration: none; + text-align: center; + display: inline-block; + width: 11em; + padding: 0.2em 0; +} + + +#tutorial-nav a:hover { + color: #000; +} diff --git a/docs/css/docs.css b/docs/css/docs.css new file mode 100644 index 000000000..b3d5f3de0 --- /dev/null +++ b/docs/css/docs.css @@ -0,0 +1,358 @@ +img.AngularJS-small { + width: 95px; + height: 25px; +} + +/* this is here to avoid the display=block shuffling of ngShow */ +.breadcrumb li > * { + float:left; + margin:0 2px 0 0; +} + +.breadcrumb { + padding-top: 6px; + padding-bottom: 0; + line-height: 18px +} + +.header img { + max-height: 40px; + padding-right: 20px; +} + +.header img+.brand { + padding: 10px 20px 10px 10px; +} + +.clear-navbar { + margin-top: 70px; /* increased for Bootstrap 3 */ +} + +.footer { + padding-top: 2em; + background-color: #333; + color: white; + padding-bottom: 2em; +} + +.spacer { + height: 1em; +} + + +.icon-cog { + line-height: 13px; +} + +/* ============================= */ +/* Bootstrap 3 overrides and patches */ + +.navbar-default .navbar-nav>.active>a, + .navbar-default .navbar-nav>.active>a:hover, + .navbar-default .navbar-nav>.active>a:focus { + color: #1abc9c; + background-color: #2c3e50; +} + +.form-control { + /*height: 30px;*/ + margin-bottom: 10px; +} + +.breadcrumb li > * { + float: none !important; + overflow: hidden !important; + display: inline-block; +} + +/* limit container to tablet width - phone users need to scroll */ +.container-fluid { + min-width: 769px; +} + +/*control responsive navbar using ng-show, as though it is an "if" in html using 2 media sizes */ +@media (max-width: 767px) { + .for-sm-view-hide { + display: none; + } +} + +@media (min-width: 768px) { + .for-lg-view-hide { + display: none; + } +} + +/* nav-list was deprecated in the upgrade to BS3, but all doc styling uses it - so copied in css from Bootstrap Flatly 2.3.2 */ +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #1abc9c; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +/* =============================== */ + +.form-search { + margin-right: 10px; +} + +.form-search .search-query { + width: 180px; + width: 200px \9; +} + +.form-search .dropdown-menu { + margin-left: 10px; +} + +.form-search .code { + font-family: monospace; + font-weight: bold; + font-size: 13px; + color: black; +} + +.form-search > ul.nav > li > a { + margin: 0; +} + +.form-search > ul.nav > li.module { + background-color: #d3d3d3; +} + +.form-search > ul.nav > li.section { + background-color: #ebebeb; + min-height: 14px; +} + +.form-search > ul.nav > li.first { + padding-top: 6px; +} + +.form-search > ul.nav > li.last { + padding-bottom: 6px; +} + +.form-search > ul.nav > li.last + li.api-list-item { + margin-top: -6px; + padding-bottom: 6px; +} + +.form-search .well { + border-color: #d3d3d3; + padding: 0; + margin-bottom: 15px; +} + +.form-search .well .nav-header { + text-transform: none; + padding: 3px 1px; + margin: 0; +} + +.form-search .well .nav-header a { + text-transform: none; + color: black; +} +.form-search .well .nav-header a:hover { + background-color: inherit; +} + +.form-search .well li { + line-height: 14px; +} + +.form-search .well li a:focus { + outline: none; +} + +.form-search .well .guide { + float: right; + padding-top: 0; + color: gray; +} + +.form-search .module .guide { + line-height: 20px; + color: black; + font-size: 80%; +} + +.form-search > ul.nav > li > a { + margin: 0; + padding: 3px 15px; + display: inline-block; +} + +.form-control:focus { + border-color: #1abc9c; +} + +a { + color: #1abc9c; + text-decoration: none; +} + +a:hover, +a:focus { + color: #1dd2af; + text-decoration: underline; +} + +.guide { + font-size: 80%; +} + +.match > a, .nav > .match > a:hover { + background-color: #dbeaf4; +} + +/* =============================== */ +/* Content */ +/* =============================== */ + +.improve-docs { + float: right; +} + +.hint { + font-size: .6em; + color: #c0c0c0; +} + +.content code { + background-color: inherit; + color: inherit; + border: none; + padding: 0; + font-size: inherit; + font-family: monospace; +} + +.content h2, +.content h3, +.content h4, +.content h5 { + margin: 1em 0 5px; +} + +.content h1 { + font-size: 30px; + line-height: 36px; +} + +.content h2 { + font-size: 24px; + line-height: 36px; +} + +.content h3 { + line-height: 27px; + font-size: 18px; +} + +.content h4 { + font-size: 15px; +} + +ul.parameters > li > p, +.returns > p { + display: inline; +} + +ul.methods > li, +ul.properties > li, +ul.events > li { + list-style: none; + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.member.method > h2, +.member.property > h2, +.member.event > h2 { + margin-bottom: .5em; +} + +ul.methods > li > h3, +ul.properties > li > h3, +ul.events > li > h3 { + margin: -19px -19px 1em -19px; + padding: .25em 19px; + background-color: #d3d3d3; + font-family: monospace; +} + +.center { + display: block; + margin: 2em auto; +} + +.diagram { + display: block; + margin: 2em auto; + padding: 1em; + border: 1px solid black; + + -moz-box-shadow: 4px 4px 6px #48577D; + -webkit-box-shadow: 4px 4px 6px #48577D; + box-shadow: 4px 4px 6px #48577D; + + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + border-radius: 15px; +} + +.tutorial-nav { + margin-left: 175px; + color: black; + margin-top: 2em; + margin-bottom: 2em; +} + +.tutorial-nav a { + color: white; +} + +.tutorial-nav a:hover { + color: white; + text-decoration: none; +} + +.clear { + clear: both; +} diff --git a/docs/css/font-awesome.css b/docs/css/font-awesome.css new file mode 100644 index 000000000..db4fd90d1 --- /dev/null +++ b/docs/css/font-awesome.css @@ -0,0 +1,1268 @@ +/*! + * Font Awesome 3.1.0 + * the iconic font designed for Bootstrap + * ------------------------------------------------------- + * The full suite of pictographic icons, examples, and documentation + * can be found at: http://fontawesome.io + * + * License + * ------------------------------------------------------- + * - The Font Awesome font is licensed under the SIL Open Font License v1.1 - + * http://scripts.sil.org/OFL + * - Font Awesome CSS, LESS, and SASS files are licensed under the MIT License - + * http://opensource.org/licenses/mit-license.html + * - Font Awesome documentation licensed under CC BY 3.0 License - + * http://creativecommons.org/licenses/by/3.0/ + * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: + * "Font Awesome by Dave Gandy - http://fontawesome.io" + + * Contact + * ------------------------------------------------------- + * Email: dave@fontawesome.io + * Twitter: http://twitter.com/fortaweso_me + * Work: Lead Product Designer @ http://kyruus.com + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../font/fontawesome-webfont.eot?v=3.1.0'); + src: url('../font/fontawesome-webfont.eot?#iefix&v=3.1.0') format('embedded-opentype'), url('../font/fontawesome-webfont.woff?v=3.1.0') format('woff'), url('../font/fontawesome-webfont.ttf?v=3.1.0') format('truetype'), url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.1.0') format('svg'); + font-weight: normal; + font-style: normal; +} +/* FONT AWESOME CORE + * -------------------------- */ +[class^="icon-"], +[class*=" icon-"] { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; +} +[class^="icon-"]:before, +[class*=" icon-"]:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: -10%; + font-size: 1.3333333333333333em; +} +/* makes sure icons active on rollover in links */ +a [class^="icon-"], +a [class*=" icon-"], +a [class^="icon-"]:before, +a [class*=" icon-"]:before { + display: inline; +} +/* increased font size for icon-large */ +[class^="icon-"].icon-fixed-width, +[class*=" icon-"].icon-fixed-width { + display: inline-block; + width: 1.2857142857142858em; + text-align: center; +} +[class^="icon-"].icon-fixed-width.icon-large, +[class*=" icon-"].icon-fixed-width.icon-large { + width: 1.5714285714285714em; +} +ul.icons-ul { + list-style-type: none; + text-indent: -0.7142857142857143em; + margin-left: 2.142857142857143em; +} +ul.icons-ul > li .icon-li { + width: 0.7142857142857143em; + display: inline-block; + text-align: center; +} +[class^="icon-"].hide, +[class*=" icon-"].hide { + display: none; +} +.icon-muted { + color: #eeeeee; +} +.icon-light { + color: #ffffff; +} +.icon-dark { + color: #333333; +} +.icon-border { + border: solid 1px #eeeeee; + padding: .2em .25em .15em; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.icon-2x { + font-size: 2em; +} +.icon-2x.icon-border { + border-width: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.icon-3x { + font-size: 3em; +} +.icon-3x.icon-border { + border-width: 3px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.icon-4x { + font-size: 4em; +} +.icon-4x.icon-border { + border-width: 4px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.icon-5x { + font-size: 5em; +} +.icon-5x.icon-border { + border-width: 5px; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left { + margin-right: .3em; +} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right { + margin-left: .3em; +} +/* BOOTSTRAP SPECIFIC CLASSES + * -------------------------- */ +/* Bootstrap 2.0 sprites.less reset */ +[class^="icon-"], +[class*=" icon-"] { + display: inline; + width: auto; + height: auto; + line-height: normal; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin-top: 0; +} +/* more sprites.less reset */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: none; +} +/* keeps Bootstrap styles with and without icons the same */ +.btn [class^="icon-"].icon-large, +.nav [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].icon-spin, +.nav [class^="icon-"].icon-spin, +.btn [class*=" icon-"].icon-spin, +.nav [class*=" icon-"].icon-spin { + display: inline-block; +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"], +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].pull-left.icon-2x, +.btn [class*=" icon-"].pull-left.icon-2x, +.btn [class^="icon-"].pull-right.icon-2x, +.btn [class*=" icon-"].pull-right.icon-2x { + margin-top: .18em; +} +.btn [class^="icon-"].icon-spin.icon-large, +.btn [class*=" icon-"].icon-spin.icon-large { + line-height: .8em; +} +.btn.btn-small [class^="icon-"].pull-left.icon-2x, +.btn.btn-small [class*=" icon-"].pull-left.icon-2x, +.btn.btn-small [class^="icon-"].pull-right.icon-2x, +.btn.btn-small [class*=" icon-"].pull-right.icon-2x { + margin-top: .25em; +} +.btn.btn-large [class^="icon-"], +.btn.btn-large [class*=" icon-"] { + margin-top: 0; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x, +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-top: .05em; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x { + margin-right: .2em; +} +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-left: .2em; +} +/* EXTRAS + * -------------------------- */ +/* Stacked and layered icon */ +.icon-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: -35%; +} +.icon-stack [class^="icon-"], +.icon-stack [class*=" icon-"] { + display: block; + text-align: center; + position: absolute; + width: 100%; + height: 100%; + font-size: 1em; + line-height: inherit; + *line-height: 2em; +} +.icon-stack .icon-stack-base { + font-size: 2em; + *line-height: 1em; +} +/* Animated rotating icon */ +.icon-spin { + display: inline-block; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +/* Icon rotations and mirroring */ +.icon-rotate-90:before { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); +} +.icon-rotate-180:before { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); +} +.icon-rotate-270:before { + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); +} +.icon-flip-horizontal:before { + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.icon-flip-vertical:before { + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { + content: "\f000"; +} +.icon-music:before { + content: "\f001"; +} +.icon-search:before { + content: "\f002"; +} +.icon-envelope:before { + content: "\f003"; +} +.icon-heart:before { + content: "\f004"; +} +.icon-star:before { + content: "\f005"; +} +.icon-star-empty:before { + content: "\f006"; +} +.icon-user:before { + content: "\f007"; +} +.icon-film:before { + content: "\f008"; +} +.icon-th-large:before { + content: "\f009"; +} +.icon-th:before { + content: "\f00a"; +} +.icon-th-list:before { + content: "\f00b"; +} +.icon-ok:before { + content: "\f00c"; +} +.icon-remove:before { + content: "\f00d"; +} +.icon-zoom-in:before { + content: "\f00e"; +} +.icon-zoom-out:before { + content: "\f010"; +} +.icon-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-cog:before { + content: "\f013"; +} +.icon-trash:before { + content: "\f014"; +} +.icon-home:before { + content: "\f015"; +} +.icon-file:before { + content: "\f016"; +} +.icon-time:before { + content: "\f017"; +} +.icon-road:before { + content: "\f018"; +} +.icon-download-alt:before { + content: "\f019"; +} +.icon-download:before { + content: "\f01a"; +} +.icon-upload:before { + content: "\f01b"; +} +.icon-inbox:before { + content: "\f01c"; +} +.icon-play-circle:before { + content: "\f01d"; +} +.icon-repeat:before, +.icon-rotate-right:before { + content: "\f01e"; +} +/* F020 doesn't work in Safari. all shifted one down */ +.icon-refresh:before { + content: "\f021"; +} +.icon-list-alt:before { + content: "\f022"; +} +.icon-lock:before { + content: "\f023"; +} +.icon-flag:before { + content: "\f024"; +} +.icon-headphones:before { + content: "\f025"; +} +.icon-volume-off:before { + content: "\f026"; +} +.icon-volume-down:before { + content: "\f027"; +} +.icon-volume-up:before { + content: "\f028"; +} +.icon-qrcode:before { + content: "\f029"; +} +.icon-barcode:before { + content: "\f02a"; +} +.icon-tag:before { + content: "\f02b"; +} +.icon-tags:before { + content: "\f02c"; +} +.icon-book:before { + content: "\f02d"; +} +.icon-bookmark:before { + content: "\f02e"; +} +.icon-print:before { + content: "\f02f"; +} +.icon-camera:before { + content: "\f030"; +} +.icon-font:before { + content: "\f031"; +} +.icon-bold:before { + content: "\f032"; +} +.icon-italic:before { + content: "\f033"; +} +.icon-text-height:before { + content: "\f034"; +} +.icon-text-width:before { + content: "\f035"; +} +.icon-align-left:before { + content: "\f036"; +} +.icon-align-center:before { + content: "\f037"; +} +.icon-align-right:before { + content: "\f038"; +} +.icon-align-justify:before { + content: "\f039"; +} +.icon-list:before { + content: "\f03a"; +} +.icon-indent-left:before { + content: "\f03b"; +} +.icon-indent-right:before { + content: "\f03c"; +} +.icon-facetime-video:before { + content: "\f03d"; +} +.icon-picture:before { + content: "\f03e"; +} +.icon-pencil:before { + content: "\f040"; +} +.icon-map-marker:before { + content: "\f041"; +} +.icon-adjust:before { + content: "\f042"; +} +.icon-tint:before { + content: "\f043"; +} +.icon-edit:before { + content: "\f044"; +} +.icon-share:before { + content: "\f045"; +} +.icon-check:before { + content: "\f046"; +} +.icon-move:before { + content: "\f047"; +} +.icon-step-backward:before { + content: "\f048"; +} +.icon-fast-backward:before { + content: "\f049"; +} +.icon-backward:before { + content: "\f04a"; +} +.icon-play:before { + content: "\f04b"; +} +.icon-pause:before { + content: "\f04c"; +} +.icon-stop:before { + content: "\f04d"; +} +.icon-forward:before { + content: "\f04e"; +} +.icon-fast-forward:before { + content: "\f050"; +} +.icon-step-forward:before { + content: "\f051"; +} +.icon-eject:before { + content: "\f052"; +} +.icon-chevron-left:before { + content: "\f053"; +} +.icon-chevron-right:before { + content: "\f054"; +} +.icon-plus-sign:before { + content: "\f055"; +} +.icon-minus-sign:before { + content: "\f056"; +} +.icon-remove-sign:before { + content: "\f057"; +} +.icon-ok-sign:before { + content: "\f058"; +} +.icon-question-sign:before { + content: "\f059"; +} +.icon-info-sign:before { + content: "\f05a"; +} +.icon-screenshot:before { + content: "\f05b"; +} +.icon-remove-circle:before { + content: "\f05c"; +} +.icon-ok-circle:before { + content: "\f05d"; +} +.icon-ban-circle:before { + content: "\f05e"; +} +.icon-arrow-left:before { + content: "\f060"; +} +.icon-arrow-right:before { + content: "\f061"; +} +.icon-arrow-up:before { + content: "\f062"; +} +.icon-arrow-down:before { + content: "\f063"; +} +.icon-share-alt:before, +.icon-mail-forward:before { + content: "\f064"; +} +.icon-resize-full:before { + content: "\f065"; +} +.icon-resize-small:before { + content: "\f066"; +} +.icon-plus:before { + content: "\f067"; +} +.icon-minus:before { + content: "\f068"; +} +.icon-asterisk:before { + content: "\f069"; +} +.icon-exclamation-sign:before { + content: "\f06a"; +} +.icon-gift:before { + content: "\f06b"; +} +.icon-leaf:before { + content: "\f06c"; +} +.icon-fire:before { + content: "\f06d"; +} +.icon-eye-open:before { + content: "\f06e"; +} +.icon-eye-close:before { + content: "\f070"; +} +.icon-warning-sign:before { + content: "\f071"; +} +.icon-plane:before { + content: "\f072"; +} +.icon-calendar:before { + content: "\f073"; +} +.icon-random:before { + content: "\f074"; +} +.icon-comment:before { + content: "\f075"; +} +.icon-magnet:before { + content: "\f076"; +} +.icon-chevron-up:before { + content: "\f077"; +} +.icon-chevron-down:before { + content: "\f078"; +} +.icon-retweet:before { + content: "\f079"; +} +.icon-shopping-cart:before { + content: "\f07a"; +} +.icon-folder-close:before { + content: "\f07b"; +} +.icon-folder-open:before { + content: "\f07c"; +} +.icon-resize-vertical:before { + content: "\f07d"; +} +.icon-resize-horizontal:before { + content: "\f07e"; +} +.icon-bar-chart:before { + content: "\f080"; +} +.icon-twitter-sign:before { + content: "\f081"; +} +.icon-facebook-sign:before { + content: "\f082"; +} +.icon-camera-retro:before { + content: "\f083"; +} +.icon-key:before { + content: "\f084"; +} +.icon-cogs:before { + content: "\f085"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-thumbs-up:before { + content: "\f087"; +} +.icon-thumbs-down:before { + content: "\f088"; +} +.icon-star-half:before { + content: "\f089"; +} +.icon-heart-empty:before { + content: "\f08a"; +} +.icon-signout:before { + content: "\f08b"; +} +.icon-linkedin-sign:before { + content: "\f08c"; +} +.icon-pushpin:before { + content: "\f08d"; +} +.icon-external-link:before { + content: "\f08e"; +} +.icon-signin:before { + content: "\f090"; +} +.icon-trophy:before { + content: "\f091"; +} +.icon-github-sign:before { + content: "\f092"; +} +.icon-upload-alt:before { + content: "\f093"; +} +.icon-lemon:before { + content: "\f094"; +} +.icon-phone:before { + content: "\f095"; +} +.icon-check-empty:before { + content: "\f096"; +} +.icon-bookmark-empty:before { + content: "\f097"; +} +.icon-phone-sign:before { + content: "\f098"; +} +.icon-twitter:before { + content: "\f099"; +} +.icon-facebook:before { + content: "\f09a"; +} +.icon-github:before { + content: "\f09b"; +} +.icon-unlock:before { + content: "\f09c"; +} +.icon-credit-card:before { + content: "\f09d"; +} +.icon-rss:before { + content: "\f09e"; +} +.icon-hdd:before { + content: "\f0a0"; +} +.icon-bullhorn:before { + content: "\f0a1"; +} +.icon-bell:before { + content: "\f0a2"; +} +.icon-certificate:before { + content: "\f0a3"; +} +.icon-hand-right:before { + content: "\f0a4"; +} +.icon-hand-left:before { + content: "\f0a5"; +} +.icon-hand-up:before { + content: "\f0a6"; +} +.icon-hand-down:before { + content: "\f0a7"; +} +.icon-circle-arrow-left:before { + content: "\f0a8"; +} +.icon-circle-arrow-right:before { + content: "\f0a9"; +} +.icon-circle-arrow-up:before { + content: "\f0aa"; +} +.icon-circle-arrow-down:before { + content: "\f0ab"; +} +.icon-globe:before { + content: "\f0ac"; +} +.icon-wrench:before { + content: "\f0ad"; +} +.icon-tasks:before { + content: "\f0ae"; +} +.icon-filter:before { + content: "\f0b0"; +} +.icon-briefcase:before { + content: "\f0b1"; +} +.icon-fullscreen:before { + content: "\f0b2"; +} +.icon-group:before { + content: "\f0c0"; +} +.icon-link:before { + content: "\f0c1"; +} +.icon-cloud:before { + content: "\f0c2"; +} +.icon-beaker:before { + content: "\f0c3"; +} +.icon-cut:before { + content: "\f0c4"; +} +.icon-copy:before { + content: "\f0c5"; +} +.icon-paper-clip:before { + content: "\f0c6"; +} +.icon-save:before { + content: "\f0c7"; +} +.icon-sign-blank:before { + content: "\f0c8"; +} +.icon-reorder:before { + content: "\f0c9"; +} +.icon-list-ul:before { + content: "\f0ca"; +} +.icon-list-ol:before { + content: "\f0cb"; +} +.icon-strikethrough:before { + content: "\f0cc"; +} +.icon-underline:before { + content: "\f0cd"; +} +.icon-table:before { + content: "\f0ce"; +} +.icon-magic:before { + content: "\f0d0"; +} +.icon-truck:before { + content: "\f0d1"; +} +.icon-pinterest:before { + content: "\f0d2"; +} +.icon-pinterest-sign:before { + content: "\f0d3"; +} +.icon-google-plus-sign:before { + content: "\f0d4"; +} +.icon-google-plus:before { + content: "\f0d5"; +} +.icon-money:before { + content: "\f0d6"; +} +.icon-caret-down:before { + content: "\f0d7"; +} +.icon-caret-up:before { + content: "\f0d8"; +} +.icon-caret-left:before { + content: "\f0d9"; +} +.icon-caret-right:before { + content: "\f0da"; +} +.icon-columns:before { + content: "\f0db"; +} +.icon-sort:before { + content: "\f0dc"; +} +.icon-sort-down:before { + content: "\f0dd"; +} +.icon-sort-up:before { + content: "\f0de"; +} +.icon-envelope-alt:before { + content: "\f0e0"; +} +.icon-linkedin:before { + content: "\f0e1"; +} +.icon-undo:before, +.icon-rotate-left:before { + content: "\f0e2"; +} +.icon-legal:before { + content: "\f0e3"; +} +.icon-dashboard:before { + content: "\f0e4"; +} +.icon-comment-alt:before { + content: "\f0e5"; +} +.icon-comments-alt:before { + content: "\f0e6"; +} +.icon-bolt:before { + content: "\f0e7"; +} +.icon-sitemap:before { + content: "\f0e8"; +} +.icon-umbrella:before { + content: "\f0e9"; +} +.icon-paste:before { + content: "\f0ea"; +} +.icon-lightbulb:before { + content: "\f0eb"; +} +.icon-exchange:before { + content: "\f0ec"; +} +.icon-cloud-download:before { + content: "\f0ed"; +} +.icon-cloud-upload:before { + content: "\f0ee"; +} +.icon-user-md:before { + content: "\f0f0"; +} +.icon-stethoscope:before { + content: "\f0f1"; +} +.icon-suitcase:before { + content: "\f0f2"; +} +.icon-bell-alt:before { + content: "\f0f3"; +} +.icon-coffee:before { + content: "\f0f4"; +} +.icon-food:before { + content: "\f0f5"; +} +.icon-file-alt:before { + content: "\f0f6"; +} +.icon-building:before { + content: "\f0f7"; +} +.icon-hospital:before { + content: "\f0f8"; +} +.icon-ambulance:before { + content: "\f0f9"; +} +.icon-medkit:before { + content: "\f0fa"; +} +.icon-fighter-jet:before { + content: "\f0fb"; +} +.icon-beer:before { + content: "\f0fc"; +} +.icon-h-sign:before { + content: "\f0fd"; +} +.icon-plus-sign-alt:before { + content: "\f0fe"; +} +.icon-double-angle-left:before { + content: "\f100"; +} +.icon-double-angle-right:before { + content: "\f101"; +} +.icon-double-angle-up:before { + content: "\f102"; +} +.icon-double-angle-down:before { + content: "\f103"; +} +.icon-angle-left:before { + content: "\f104"; +} +.icon-angle-right:before { + content: "\f105"; +} +.icon-angle-up:before { + content: "\f106"; +} +.icon-angle-down:before { + content: "\f107"; +} +.icon-desktop:before { + content: "\f108"; +} +.icon-laptop:before { + content: "\f109"; +} +.icon-tablet:before { + content: "\f10a"; +} +.icon-mobile-phone:before { + content: "\f10b"; +} +.icon-circle-blank:before { + content: "\f10c"; +} +.icon-quote-left:before { + content: "\f10d"; +} +.icon-quote-right:before { + content: "\f10e"; +} +.icon-spinner:before { + content: "\f110"; +} +.icon-circle:before { + content: "\f111"; +} +.icon-reply:before, +.icon-mail-reply:before { + content: "\f112"; +} +.icon-folder-close-alt:before { + content: "\f114"; +} +.icon-folder-open-alt:before { + content: "\f115"; +} +.icon-expand-alt:before { + content: "\f116"; +} +.icon-collapse-alt:before { + content: "\f117"; +} +.icon-smile:before { + content: "\f118"; +} +.icon-frown:before { + content: "\f119"; +} +.icon-meh:before { + content: "\f11a"; +} +.icon-gamepad:before { + content: "\f11b"; +} +.icon-keyboard:before { + content: "\f11c"; +} +.icon-flag-alt:before { + content: "\f11d"; +} +.icon-flag-checkered:before { + content: "\f11e"; +} +.icon-terminal:before { + content: "\f120"; +} +.icon-code:before { + content: "\f121"; +} +.icon-reply-all:before { + content: "\f122"; +} +.icon-mail-reply-all:before { + content: "\f122"; +} +.icon-star-half-full:before, +.icon-star-half-empty:before { + content: "\f123"; +} +.icon-location-arrow:before { + content: "\f124"; +} +.icon-crop:before { + content: "\f125"; +} +.icon-code-fork:before { + content: "\f126"; +} +.icon-unlink:before { + content: "\f127"; +} +.icon-question:before { + content: "\f128"; +} +.icon-info:before { + content: "\f129"; +} +.icon-exclamation:before { + content: "\f12a"; +} +.icon-superscript:before { + content: "\f12b"; +} +.icon-subscript:before { + content: "\f12c"; +} +.icon-eraser:before { + content: "\f12d"; +} +.icon-puzzle-piece:before { + content: "\f12e"; +} +.icon-microphone:before { + content: "\f130"; +} +.icon-microphone-off:before { + content: "\f131"; +} +.icon-shield:before { + content: "\f132"; +} +.icon-calendar-empty:before { + content: "\f133"; +} +.icon-fire-extinguisher:before { + content: "\f134"; +} +.icon-rocket:before { + content: "\f135"; +} +.icon-maxcdn:before { + content: "\f136"; +} +.icon-chevron-sign-left:before { + content: "\f137"; +} +.icon-chevron-sign-right:before { + content: "\f138"; +} +.icon-chevron-sign-up:before { + content: "\f139"; +} +.icon-chevron-sign-down:before { + content: "\f13a"; +} +.icon-html5:before { + content: "\f13b"; +} +.icon-css3:before { + content: "\f13c"; +} +.icon-anchor:before { + content: "\f13d"; +} +.icon-unlock-alt:before { + content: "\f13e"; +} +.icon-bullseye:before { + content: "\f140"; +} +.icon-ellipsis-horizontal:before { + content: "\f141"; +} +.icon-ellipsis-vertical:before { + content: "\f142"; +} +.icon-rss-sign:before { + content: "\f143"; +} +.icon-play-sign:before { + content: "\f144"; +} +.icon-ticket:before { + content: "\f145"; +} +.icon-minus-sign-alt:before { + content: "\f146"; +} +.icon-check-minus:before { + content: "\f147"; +} +.icon-level-up:before { + content: "\f148"; +} +.icon-level-down:before { + content: "\f149"; +} +.icon-check-sign:before { + content: "\f14a"; +} +.icon-edit-sign:before { + content: "\f14b"; +} +.icon-external-link-sign:before { + content: "\f14c"; +} +.icon-share-sign:before { + content: "\f14d"; +} diff --git a/docs/css/prettify.css b/docs/css/prettify.css new file mode 100644 index 000000000..16e0cafbf --- /dev/null +++ b/docs/css/prettify.css @@ -0,0 +1,51 @@ +.pln { color: #000 } /* plain text */ + +@media screen { + .str { color: #080 } /* string content */ + .kwd { color: #008 } /* a keyword */ + .com { color: #800 } /* a comment */ + .typ { color: #606 } /* a type name */ + .lit { color: #066 } /* a literal value */ + /* punctuation, lisp open bracket, lisp close bracket */ + .pun, .opn, .clo { color: #660 } + .tag { color: #008 } /* a markup tag name */ + .atn { color: #606 } /* a markup attribute name */ + .atv { color: #080 } /* a markup attribute value */ + .dec, .var { color: #606 } /* a declaration; a variable name */ + .fun { color: red } /* a function name */ +} + +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { color: #060 } + .kwd { color: #006; font-weight: bold } + .com { color: #600; font-style: italic } + .typ { color: #404; font-weight: bold } + .lit { color: #044 } + .pun, .opn, .clo { color: #440 } + .tag { color: #006; font-weight: bold } + .atn { color: #404 } + .atv { color: #060 } +} + +pre.prettyprint { + padding: 8px; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre.prettyprint.linenums { + -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; + -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; + box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; +} +ol.linenums { + margin: 0 0 0 33px; /* IE indents via margin-left */ +} +ol.linenums li { + padding-left: 12px; + font-size:12px; + color: #bebec5; + line-height: 18px; + text-shadow: 0 1px 0 #fff; + list-style-type:decimal!important; +} diff --git a/docs/css/ui-grid.css b/docs/css/ui-grid.css new file mode 100644 index 000000000..43b99dcdc --- /dev/null +++ b/docs/css/ui-grid.css @@ -0,0 +1,102 @@ +.ui-grid { + border: 1px solid #d4d4d4; +} +.ui-grid-vertical-bar { + position: absolute; + right: 0; + width: 0; +} +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar, +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar { + width: 1px; + background-color: #d4d4d4; +} +.ui-grid-top-panel { + position: relative; + background-color: #eaeaea; + border-bottom: 1px solid #d4d4d4; + overflow: hidden; + font-weight: bold; +} +.ui-grid-header-cell { + position: absolute; + top: 0; + bottom: 0; + background-color: inherit; +} +.ui-grid-body { + position: relative; + overflow: hidden; +} +.ui-grid-scrollbar-box { + position: static; +} +.ui-grid-viewport { + min-height: 20px; + position: relative; + overflow: hidden; +} +.ui-grid-viewport :focus { + outline: none; +} +.ui-grid-canvas { + position: relative; +} +.ui-grid-row:nth-child(odd) .ui-grid-cell { + background-color: #fdfdfd; +} +.ui-grid-row:nth-child(even) .ui-grid-cell { + background-color: #f3f3f3; +} +.ui-grid-row:last-child .ui-grid-cell { + border-bottom-color: #d4d4d4; + border-bottom-style: solid; +} +.ui-grid-cell { + overflow: hidden; + position: absolute; + background-color: inherit; +} +.ui-grid-cell-contents { + padding: 5px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + white-space: nowrap; + -ms-text-overflow: ellipsis; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + overflow: hidden; +} +.ui-grid-scrollbar { + top: 0; + z-index: 10; + position: absolute; + background: rgba(0, 0, 0, 0.5); + opacity: 1; + cursor: pointer; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; + -webkit-box-shadow: 0 0 1px #ffffff; + -moz-box-shadow: 0 0 1px #ffffff; + box-shadow: 0 0 1px #ffffff; +} +.ui-grid-scrollbar-vertical { + width: 7px; + margin-top: 4px; + margin-bottom: 4px; + right: 4px; +} +.ui-grid-pinned.left { + float: left; +} +.ui-grid-pinned.right { + float: right; +} +/*--------------------------------------------------- + LESS Elements 0.9 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 000000000..70f69aef1 Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/font/FontAwesome.otf b/docs/font/FontAwesome.otf new file mode 100644 index 000000000..32dd8b1cd Binary files /dev/null and b/docs/font/FontAwesome.otf differ diff --git a/docs/font/fontawesome-webfont.eot b/docs/font/fontawesome-webfont.eot new file mode 100644 index 000000000..c080283bd Binary files /dev/null and b/docs/font/fontawesome-webfont.eot differ diff --git a/docs/font/fontawesome-webfont.svg b/docs/font/fontawesome-webfont.svg new file mode 100644 index 000000000..10a1e1bbf --- /dev/null +++ b/docs/font/fontawesome-webfont.svg @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/font/fontawesome-webfont.ttf b/docs/font/fontawesome-webfont.ttf new file mode 100644 index 000000000..908f69ec9 Binary files /dev/null and b/docs/font/fontawesome-webfont.ttf differ diff --git a/docs/font/fontawesome-webfont.woff b/docs/font/fontawesome-webfont.woff new file mode 100644 index 000000000..a33af950a Binary files /dev/null and b/docs/font/fontawesome-webfont.woff differ diff --git a/docs/grunt-scripts/csv.js b/docs/grunt-scripts/csv.js new file mode 100644 index 000000000..7adf84454 --- /dev/null +++ b/docs/grunt-scripts/csv.js @@ -0,0 +1,354 @@ +/* + CSV-JS - A Comma-Separated Values parser for JS + + Built to rfc4180 standard, with options for adjusting strictness: + - optional carriage returns for non-microsoft sources + - automatically type-cast numeric an boolean values + - relaxed mode which: ignores blank lines, ignores gargabe following quoted tokens, does not enforce a consistent record length + + Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + Author Greg Kindel (twitter @gkindel), 2013 + */ + +(function () { + 'use strict'; + /** + * @name CSV + * @namespace + */ + // implemented as a singleton because JS is single threaded + var CSV = {}; + CSV.RELAXED = false; + CSV.IGNORE_RECORD_LENGTH = false; + CSV.IGNORE_QUOTES = false; + CSV.LINE_FEED_OK = true; + CSV.CARRIAGE_RETURN_OK = true; + CSV.DETECT_TYPES = true; + CSV.IGNORE_QUOTE_WHITESPACE = true; + CSV.DEBUG = false; + + CSV.COLUMN_SEPARATOR = ","; + + CSV.ERROR_EOF = "UNEXPECTED_END_OF_FILE"; + CSV.ERROR_CHAR = "UNEXPECTED_CHARACTER"; + CSV.ERROR_EOL = "UNEXPECTED_END_OF_RECORD"; + CSV.WARN_SPACE = "UNEXPECTED_WHITESPACE"; // not per spec, but helps debugging + + var QUOTE = "\"", + CR = "\r", + LF = "\n", + SPACE = " ", + TAB = "\t"; + + // states + var PRE_TOKEN = 0, + MID_TOKEN = 1, + POST_TOKEN = 2, + POST_RECORD = 4; + /** + * @name CSV.parse + * @function + * @description rfc4180 standard csv parse + * with options for strictness and data type conversion + * By default, will automatically type-cast numeric an boolean values. + * @param {String} str A CSV string + * @return {Array} An array records, each of which is an array of scalar values. + * @example + * // simple + * var rows = CSV.parse("one,two,three\nfour,five,six") + * // rows equals [["one","two","three"],["four","five","six"]] + * @example + * // Though not a jQuery plugin, it is recommended to use with the $.ajax pipe() method: + * $.get("csv.txt") + * .pipe( CSV.parse ) + * .done( function(rows) { + * for( var i =0; i < rows.length; i++){ + * console.log(rows[i]) + * } + * }); + * @see http://www.ietf.org/rfc/rfc4180.txt + */ + CSV.parse = function (str) { + var result = CSV.result = []; + CSV.offset = 0; + CSV.str = str; + CSV.record_begin(); + + CSV.debug("parse()", str); + + var c; + while( 1 ){ + // pull char + c = str[CSV.offset++]; + CSV.debug("c", c); + + // detect eof + if (c == null) { + if( CSV.escaped ) + CSV.error(CSV.ERROR_EOF); + + if( CSV.record ){ + CSV.token_end(); + CSV.record_end(); + } + + CSV.debug("...bail", c, CSV.state, CSV.record); + CSV.reset(); + break; + } + + if( CSV.record == null ){ + // if relaxed mode, ignore blank lines + if( CSV.RELAXED && (c == LF || c == CR && str[CSV.offset + 1] == LF) ){ + continue; + } + CSV.record_begin(); + } + + // pre-token: look for start of escape sequence + if (CSV.state == PRE_TOKEN) { + + if ( (c === SPACE || c === TAB) && CSV.next_nonspace() == QUOTE ){ + if( CSV.RELAXED || CSV.IGNORE_QUOTE_WHITESPACE ) { + continue; + } + else { + // not technically an error, but ambiguous and hard to debug otherwise + CSV.warn(CSV.WARN_SPACE); + } + } + + if (c == QUOTE && ! CSV.IGNORE_QUOTES) { + CSV.debug("...escaped start", c); + CSV.escaped = true; + CSV.state = MID_TOKEN; + continue; + } + CSV.state = MID_TOKEN; + } + + // mid-token and escaped, look for sequences and end quote + if (CSV.state == MID_TOKEN && CSV.escaped) { + if (c == QUOTE) { + if (str[CSV.offset] == QUOTE) { + CSV.debug("...escaped quote", c); + CSV.token += QUOTE; + CSV.offset++; + } + else { + CSV.debug("...escaped end", c); + CSV.escaped = false; + CSV.state = POST_TOKEN; + } + } + else { + CSV.token += c; + CSV.debug("...escaped add", c, CSV.token); + } + continue; + } + + // fall-through: mid-token or post-token, not escaped + if (c == CR ) { + if( str[CSV.offset] == LF ) + CSV.offset++; + else if( ! CSV.CARRIAGE_RETURN_OK ) + CSV.error(CSV.ERROR_CHAR); + CSV.token_end(); + CSV.record_end(); + } + else if (c == LF) { + if( ! (CSV.LINE_FEED_OK || CSV.RELAXED) ) + CSV.error(CSV.ERROR_CHAR); + CSV.token_end(); + CSV.record_end(); + } + else if (c == CSV.COLUMN_SEPARATOR) { + CSV.token_end(); + } + else if( CSV.state == MID_TOKEN ){ + CSV.token += c; + CSV.debug("...add", c, CSV.token); + } + else if ( c === SPACE || c === TAB) { + if (! CSV.IGNORE_QUOTE_WHITESPACE ) + CSV.error(CSV.WARN_SPACE ); + } + else if( ! CSV.RELAXED ){ + CSV.error(CSV.ERROR_CHAR); + } + } + return result; + }; + + CSV.json = function () { + var s = new require('stream').Transform({objectMode: true}) + s._transform = function(chunk, encoding, done) { + s.push(JSON.stringify(chunk.toString())+require('os').EOL) + done() + } + return s + } + + /** + * @name CSV.stream + * @function + * @description stream a CSV file + * @example + * node -e "c=require('CSV-JS');require('fs').createReadStream('csv.txt').pipe(c.stream()).pipe(c.json()).pipe(process.stdout)" + */ + CSV.stream = function () { + var s = new require('stream').Transform({objectMode: true}) + s.EOL = '\n' + s.prior = "" + s.emitter = function(s) { + return function(e) { + s.push(CSV.parse(e+s.EOL)) + } + }(s); + + s._transform = function(chunk, encoding, done) { + var lines = (this.prior == "") ? + chunk.toString().split(this.EOL) : + (this.prior + chunk.toString()).split(this.EOL) + this.prior = lines.pop(); + lines.forEach(this.emitter) + done() + } + + s._flush = function(done) { + if (this.prior != "") { + this.emitter(this.prior) + this.prior = "" + } + done() + } + return s + } + + CSV.reset = function () { + CSV.state = null; + CSV.token = null; + CSV.escaped = null; + CSV.record = null; + CSV.offset = null; + CSV.result = null; + CSV.str = null; + }; + + CSV.next_nonspace = function () { + var i = CSV.offset; + var c; + while( i < CSV.str.length ) { + c = CSV.str[i++]; + if( !( c == SPACE || c === TAB ) ){ + return c; + } + } + return null; + }; + + CSV.record_begin = function () { + CSV.escaped = false; + CSV.record = []; + CSV.token_begin(); + CSV.debug("record_begin"); + }; + + CSV.record_end = function () { + CSV.state = POST_RECORD; + if( ! (CSV.IGNORE_RECORD_LENGTH || CSV.RELAXED) && CSV.result.length > 0 && CSV.record.length != CSV.result[0].length ){ + CSV.error(CSV.ERROR_EOL); + } + CSV.result.push(CSV.record); + CSV.debug("record end", CSV.record); + CSV.record = null; + }; + + CSV.resolve_type = function (token) { + if( token.match(/^\d+(\.\d+)?$/) ){ + token = parseFloat(token); + } + else if( token.match(/^(true|false)$/i) ){ + token = Boolean( token.match(/true/i) ); + } + else if(token === "undefined" ){ + token = undefined; + } + else if(token === "null" ){ + token = null; + } + return token; + }; + + CSV.token_begin = function () { + CSV.state = PRE_TOKEN; + // considered using array, but http://www.sitepen.com/blog/2008/05/09/string-performance-an-analysis/ + CSV.token = ""; + }; + + CSV.token_end = function () { + if( CSV.DETECT_TYPES ) { + CSV.token = CSV.resolve_type(CSV.token); + } + CSV.record.push(CSV.token); + CSV.debug("token end", CSV.token); + CSV.token_begin(); + }; + + CSV.debug = function (){ + if( CSV.DEBUG ) + console.log(arguments); + }; + + CSV.dump = function (msg) { + return [ + msg , "at char", CSV.offset, ":", + CSV.str.substr(CSV.offset- 50, 50) + .replace(/\r/mg,"\\r") + .replace(/\n/mg,"\\n") + .replace(/\t/mg,"\\t") + ].join(" "); + }; + + CSV.error = function (err){ + var msg = CSV.dump(err); + CSV.reset(); + throw msg; + }; + + CSV.warn = function (err){ + var msg = CSV.dump(err); + try { + console.warn( msg ); + return; + } catch (e) {} + + try { + console.log( msg ); + } catch (e) {} + + }; + + (function(name, context, definition) { + var define; + if (typeof module != 'undefined' && module.exports) module.exports = definition(); + else if (typeof define == 'function' && typeof define.amd == 'object') define(definition); + else context[name] = definition(); + }('CSV', Function('return this')(), function() + { return CSV; } + ) + ); + +})(); diff --git a/docs/grunt-scripts/marked.js b/docs/grunt-scripts/marked.js new file mode 100644 index 000000000..7a07c8ae1 --- /dev/null +++ b/docs/grunt-scripts/marked.js @@ -0,0 +1,1165 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ + +;(function() { + +/** + * Block-Level Grammar + */ + +var block = { + newline: /^\n+/, + code: /^( {4}[^\n]+\n*)+/, + fences: noop, + hr: /^( *[-*_]){3,} *(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, + nptable: noop, + lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, + blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, + list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, + def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, + table: noop, + paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, + text: /^[^\n]+/ +}; + +block.bullet = /(?:[*+-]|\d+\.)/; +block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; +block.item = replace(block.item, 'gm') + (/bull/g, block.bullet) + (); + +block.list = replace(block.list) + (/bull/g, block.bullet) + ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/) + (); + +block._tag = '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' + + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b'; + +block.html = replace(block.html) + ('comment', //) + ('closed', /<(tag)[\s\S]+?<\/\1>/) + ('closing', /])*?>/) + (/tag/g, block._tag) + (); + +block.paragraph = replace(block.paragraph) + ('hr', block.hr) + ('heading', block.heading) + ('lheading', block.lheading) + ('blockquote', block.blockquote) + ('tag', '<' + block._tag) + ('def', block.def) + (); + +/** + * Normal Block Grammar + */ + +block.normal = merge({}, block); + +/** + * GFM Block Grammar + */ + +block.gfm = merge({}, block.normal, { + fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, + paragraph: /^/ +}); + +block.gfm.paragraph = replace(block.paragraph) + ('(?!', '(?!' + + block.gfm.fences.source.replace('\\1', '\\2') + '|' + + block.list.source.replace('\\1', '\\3') + '|') + (); + +/** + * GFM + Tables Block Grammar + */ + +block.tables = merge({}, block.gfm, { + nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, + table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ +}); + +/** + * Block Lexer + */ + +function Lexer(options) { + this.tokens = []; + this.tokens.links = {}; + this.options = options || marked.defaults; + this.rules = block.normal; + + if (this.options.gfm) { + if (this.options.tables) { + this.rules = block.tables; + } else { + this.rules = block.gfm; + } + } +} + +/** + * Expose Block Rules + */ + +Lexer.rules = block; + +/** + * Static Lex Method + */ + +Lexer.lex = function(src, options) { + var lexer = new Lexer(options); + return lexer.lex(src); +}; + +/** + * Preprocessing + */ + +Lexer.prototype.lex = function(src) { + src = src + .replace(/\r\n|\r/g, '\n') + .replace(/\t/g, ' ') + .replace(/\u00a0/g, ' ') + .replace(/\u2424/g, '\n'); + + return this.token(src, true); +}; + +/** + * Lexing + */ + +Lexer.prototype.token = function(src, top) { + var src = src.replace(/^ +$/gm, '') + , next + , loose + , cap + , bull + , b + , item + , space + , i + , l; + + while (src) { + // newline + if (cap = this.rules.newline.exec(src)) { + src = src.substring(cap[0].length); + if (cap[0].length > 1) { + this.tokens.push({ + type: 'space' + }); + } + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + cap = cap[0].replace(/^ {4}/gm, ''); + this.tokens.push({ + type: 'code', + text: !this.options.pedantic + ? cap.replace(/\n+$/, '') + : cap + }); + continue; + } + + // fences (gfm) + if (cap = this.rules.fences.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'code', + lang: cap[2], + text: cap[3] + }); + continue; + } + + // heading + if (cap = this.rules.heading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[1].length, + text: cap[2] + }); + continue; + } + + // table no leading pipe (gfm) + if (top && (cap = this.rules.nptable.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/\n$/, '').split('\n') + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i].split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + + // lheading + if (cap = this.rules.lheading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[2] === '=' ? 1 : 2, + text: cap[1] + }); + continue; + } + + // hr + if (cap = this.rules.hr.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'hr' + }); + continue; + } + + // blockquote + if (cap = this.rules.blockquote.exec(src)) { + src = src.substring(cap[0].length); + + this.tokens.push({ + type: 'blockquote_start' + }); + + cap = cap[0].replace(/^ *> ?/gm, ''); + + // Pass `top` to keep the current + // "toplevel" state. This is exactly + // how markdown.pl works. + this.token(cap, top); + + this.tokens.push({ + type: 'blockquote_end' + }); + + continue; + } + + // list + if (cap = this.rules.list.exec(src)) { + src = src.substring(cap[0].length); + bull = cap[2]; + + this.tokens.push({ + type: 'list_start', + ordered: bull.length > 1 + }); + + // Get each top-level item. + cap = cap[0].match(this.rules.item); + + next = false; + l = cap.length; + i = 0; + + for (; i < l; i++) { + item = cap[i]; + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) +/, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (this.options.smartLists && i !== l - 1) { + b = block.bullet.exec(cap[i + 1])[0]; + if (bull !== b && !(bull.length > 1 && b.length > 1)) { + src = cap.slice(i + 1).join('\n') + src; + i = l - 1; + } + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } + + this.tokens.push({ + type: loose + ? 'loose_item_start' + : 'list_item_start' + }); + + // Recurse. + this.token(item, false); + + this.tokens.push({ + type: 'list_item_end' + }); + } + + this.tokens.push({ + type: 'list_end' + }); + + continue; + } + + // html + if (cap = this.rules.html.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: this.options.sanitize + ? 'paragraph' + : 'html', + pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', + text: cap[0] + }); + continue; + } + + // def + if (top && (cap = this.rules.def.exec(src))) { + src = src.substring(cap[0].length); + this.tokens.links[cap[1].toLowerCase()] = { + href: cap[2], + title: cap[3] + }; + continue; + } + + // table (gfm) + if (top && (cap = this.rules.table.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i] + .replace(/^ *\| *| *\| *$/g, '') + .split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + + // top-level paragraph + if (top && (cap = this.rules.paragraph.exec(src))) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'paragraph', + text: cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1] + }); + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + // Top-level should never reach here. + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'text', + text: cap[0] + }); + continue; + } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return this.tokens; +}; + +/** + * Inline-Level Grammar + */ + +var inline = { + escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, + autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, + url: noop, + tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, + link: /^!?\[(inside)\]\(href\)/, + reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, + nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, + strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, + em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, + code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, + br: /^ {2,}\n(?!\s*$)/, + del: noop, + text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; + +inline.link = replace(inline.link) + ('inside', inline._inside) + ('href', inline._href) + (); + +inline.reflink = replace(inline.reflink) + ('inside', inline._inside) + (); + +/** + * Normal Inline Grammar + */ + +inline.normal = merge({}, inline); + +/** + * Pedantic Inline Grammar + */ + +inline.pedantic = merge({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ +}); + +/** + * GFM Inline Grammar + */ + +inline.gfm = merge({}, inline.normal, { + escape: replace(inline.escape)('])', '~|])')(), + url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, + del: /^~~(?=\S)([\s\S]*?\S)~~/, + text: replace(inline.text) + (']|', '~]|') + ('|', '|https?://|') + () +}); + +/** + * GFM + Line Breaks Inline Grammar + */ + +inline.breaks = merge({}, inline.gfm, { + br: replace(inline.br)('{2,}', '*')(), + text: replace(inline.gfm.text)('{2,}', '*')() +}); + +/** + * Inline Lexer & Compiler + */ + +function InlineLexer(links, options) { + this.options = options || marked.defaults; + this.links = links; + this.rules = inline.normal; + + if (!this.links) { + throw new + Error('Tokens array requires a `links` property.'); + } + + if (this.options.gfm) { + if (this.options.breaks) { + this.rules = inline.breaks; + } else { + this.rules = inline.gfm; + } + } else if (this.options.pedantic) { + this.rules = inline.pedantic; + } +} + +/** + * Expose Inline Rules + */ + +InlineLexer.rules = inline; + +/** + * Static Lexing/Compiling Method + */ + +InlineLexer.output = function(src, links, options) { + var inline = new InlineLexer(links, options); + return inline.output(src); +}; + +/** + * Lexing/Compiling + */ + +InlineLexer.prototype.output = function(src) { + var out = '' + , link + , text + , href + , cap; + + while (src) { + // escape + if (cap = this.rules.escape.exec(src)) { + src = src.substring(cap[0].length); + out += cap[1]; + continue; + } + + // autolink + if (cap = this.rules.autolink.exec(src)) { + src = src.substring(cap[0].length); + if (cap[2] === '@') { + text = cap[1].charAt(6) === ':' + ? this.mangle(cap[1].substring(7)) + : this.mangle(cap[1]); + href = this.mangle('mailto:') + text; + } else { + text = escape(cap[1]); + href = text; + } + out += '' + + text + + ''; + continue; + } + + // url (gfm) + if (cap = this.rules.url.exec(src)) { + src = src.substring(cap[0].length); + text = escape(cap[1]); + href = text; + out += '' + + text + + ''; + continue; + } + + // tag + if (cap = this.rules.tag.exec(src)) { + src = src.substring(cap[0].length); + out += this.options.sanitize + ? escape(cap[0]) + : cap[0]; + continue; + } + + // link + if (cap = this.rules.link.exec(src)) { + src = src.substring(cap[0].length); + out += this.outputLink(cap, { + href: cap[2], + title: cap[3] + }); + continue; + } + + // reflink, nolink + if ((cap = this.rules.reflink.exec(src)) + || (cap = this.rules.nolink.exec(src))) { + src = src.substring(cap[0].length); + link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = this.links[link.toLowerCase()]; + if (!link || !link.href) { + out += cap[0].charAt(0); + src = cap[0].substring(1) + src; + continue; + } + out += this.outputLink(cap, link); + continue; + } + + // strong + if (cap = this.rules.strong.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + this.output(cap[2] || cap[1]) + + ''; + continue; + } + + // em + if (cap = this.rules.em.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + this.output(cap[2] || cap[1]) + + ''; + continue; + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + escape(cap[2], true) + + ''; + continue; + } + + // br + if (cap = this.rules.br.exec(src)) { + src = src.substring(cap[0].length); + out += '
    '; + continue; + } + + // del (gfm) + if (cap = this.rules.del.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + this.output(cap[1]) + + ''; + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + src = src.substring(cap[0].length); + out += escape(this.smartypants(cap[0])); + continue; + } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return out; +}; + +/** + * Compile Link + */ + +InlineLexer.prototype.outputLink = function(cap, link) { + if (cap[0].charAt(0) !== '!') { + return '' + + this.output(cap[1]) + + ''; + } else { + return ''
+      + escape(cap[1])
+      + ''; + } +}; + +/** + * Smartypants Transformations + */ + +InlineLexer.prototype.smartypants = function(text) { + if (!this.options.smartypants) return text; + return text + // em-dashes + .replace(/--/g, '\u2014') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); +}; + +/** + * Mangle Links + */ + +InlineLexer.prototype.mangle = function(text) { + var out = '' + , l = text.length + , i = 0 + , ch; + + for (; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +}; + +/** + * Parsing & Compiling + */ + +function Parser(options) { + this.tokens = []; + this.token = null; + this.options = options || marked.defaults; +} + +/** + * Static Parse Method + */ + +Parser.parse = function(src, options) { + var parser = new Parser(options); + return parser.parse(src); +}; + +/** + * Parse Loop + */ + +Parser.prototype.parse = function(src) { + this.inline = new InlineLexer(src.links, this.options); + this.tokens = src.reverse(); + + var out = ''; + while (this.next()) { + out += this.tok(); + } + + return out; +}; + +/** + * Next Token + */ + +Parser.prototype.next = function() { + return this.token = this.tokens.pop(); +}; + +/** + * Preview Next Token + */ + +Parser.prototype.peek = function() { + return this.tokens[this.tokens.length - 1] || 0; +}; + +/** + * Parse Text Tokens + */ + +Parser.prototype.parseText = function() { + var body = this.token.text; + + while (this.peek().type === 'text') { + body += '\n' + this.next().text; + } + + return this.inline.output(body); +}; + +/** + * Parse Current Token + */ + +Parser.prototype.tok = function() { + switch (this.token.type) { + case 'space': { + return ''; + } + case 'hr': { + return '
    \n'; + } + case 'heading': { + return '' + + this.inline.output(this.token.text) + + '\n'; + } + case 'code': { + if (this.options.highlight) { + var code = this.options.highlight(this.token.text, this.token.lang); + if (code != null && code !== this.token.text) { + this.token.escaped = true; + this.token.text = code; + } + } + + if (!this.token.escaped) { + this.token.text = escape(this.token.text, true); + } + + return '
    '
    +        + this.token.text
    +        + '
    \n'; + } + case 'table': { + var body = '' + , heading + , i + , row + , cell + , j; + + // header + body += '\n\n'; + for (i = 0; i < this.token.header.length; i++) { + heading = this.inline.output(this.token.header[i]); + body += '\n'; + } + body += '\n\n'; + + // body + body += '\n' + for (i = 0; i < this.token.cells.length; i++) { + row = this.token.cells[i]; + body += '\n'; + for (j = 0; j < row.length; j++) { + cell = this.inline.output(row[j]); + body += '\n'; + } + body += '\n'; + } + body += '\n'; + + return '\n' + + body + + '
    \n'; + } + case 'blockquote_start': { + var body = ''; + + while (this.next().type !== 'blockquote_end') { + body += this.tok(); + } + + return '
    \n' + + body + + '
    \n'; + } + case 'list_start': { + var type = this.token.ordered ? 'ol' : 'ul' + , body = ''; + + while (this.next().type !== 'list_end') { + body += this.tok(); + } + + return '<' + + type + + '>\n' + + body + + '\n'; + } + case 'list_item_start': { + var body = ''; + + while (this.next().type !== 'list_item_end') { + body += this.token.type === 'text' + ? this.parseText() + : this.tok(); + } + + return '
  • ' + + body + + '
  • \n'; + } + case 'loose_item_start': { + var body = ''; + + while (this.next().type !== 'list_item_end') { + body += this.tok(); + } + + return '
  • ' + + body + + '
  • \n'; + } + case 'html': { + return !this.token.pre && !this.options.pedantic + ? this.inline.output(this.token.text) + : this.token.text; + } + case 'paragraph': { + return '

    ' + + this.inline.output(this.token.text) + + '

    \n'; + } + case 'text': { + return '

    ' + + this.parseText() + + '

    \n'; + } + } +}; + +/** + * Helpers + */ + +function escape(html, encode) { + return html + .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + +function replace(regex, opt) { + regex = regex.source; + opt = opt || ''; + return function self(name, val) { + if (!name) return new RegExp(regex, opt); + val = val.source || val; + val = val.replace(/(^|[^\[])\^/g, '$1'); + regex = regex.replace(name, val); + return self; + }; +} + +function noop() {} +noop.exec = noop; + +function merge(obj) { + var i = 1 + , target + , key; + + for (; i < arguments.length; i++) { + target = arguments[i]; + for (key in target) { + if (Object.prototype.hasOwnProperty.call(target, key)) { + obj[key] = target[key]; + } + } + } + + return obj; +} + +/** + * Marked + */ + +function marked(src, opt, callback) { + if (callback || typeof opt === 'function') { + if (!callback) { + callback = opt; + opt = null; + } + + opt = merge({}, marked.defaults, opt || {}); + + var highlight = opt.highlight + , tokens + , pending + , i = 0; + + try { + tokens = Lexer.lex(src, opt) + } catch (e) { + return callback(e); + } + + pending = tokens.length; + + var done = function() { + var out, err; + + try { + out = Parser.parse(tokens, opt); + } catch (e) { + err = e; + } + + opt.highlight = highlight; + + return err + ? callback(err) + : callback(null, out); + }; + + if (!highlight || highlight.length < 3) { + return done(); + } + + delete opt.highlight; + + if (!pending) return done(); + + for (; i < tokens.length; i++) { + (function(token) { + if (token.type !== 'code') { + return --pending || done(); + } + return highlight(token.text, token.lang, function(err, code) { + if (code == null || code === token.text) { + return --pending || done(); + } + token.text = code; + token.escaped = true; + --pending || done(); + }); + })(tokens[i]); + } + + return; + } + try { + if (opt) opt = merge({}, marked.defaults, opt); + return Parser.parse(Lexer.lex(src, opt), opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/chjj/marked.'; + if ((opt || marked.defaults).silent) { + return '

    An error occured:

    '
    +        + escape(e.message + '', true)
    +        + '
    '; + } + throw e; + } +} + +/** + * Options + */ + +marked.options = +marked.setOptions = function(opt) { + merge(marked.defaults, opt); + return marked; +}; + +marked.defaults = { + gfm: true, + tables: true, + breaks: false, + pedantic: false, + sanitize: false, + smartLists: false, + silent: false, + highlight: null, + langPrefix: 'lang-', + smartypants: false +}; + +/** + * Expose + */ + +marked.Parser = Parser; +marked.parser = Parser.parse; + +marked.Lexer = Lexer; +marked.lexer = Lexer.lex; + +marked.InlineLexer = InlineLexer; +marked.inlineLexer = InlineLexer.output; + +marked.parse = marked; + +if (typeof exports === 'object') { + module.exports = marked; +} else if (typeof define === 'function' && define.amd) { + define(function() { return marked; }); +} else { + this.marked = marked; +} + +}).call(function() { + return this || (typeof window !== 'undefined' ? window : global); +}()); diff --git a/docs/grunt-scripts/pdfmake.js b/docs/grunt-scripts/pdfmake.js new file mode 100644 index 000000000..1fe810d4d --- /dev/null +++ b/docs/grunt-scripts/pdfmake.js @@ -0,0 +1,32944 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pdfMake = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = require('util/'); + +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":39}],3:[function(require,module,exports){ + +},{}],4:[function(require,module,exports){ +'use strict'; + + +var TYPED_OK = (typeof Uint8Array !== 'undefined') && + (typeof Uint16Array !== 'undefined') && + (typeof Int32Array !== 'undefined'); + + +exports.assign = function (obj /*from1, from2, from3, ...*/) { + var sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + var source = sources.shift(); + if (!source) { continue; } + + if (typeof(source) !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (var p in source) { + if (source.hasOwnProperty(p)) { + obj[p] = source[p]; + } + } + } + + return obj; +}; + + +// reduce buffer size, avoiding mem copy +exports.shrinkBuf = function (buf, size) { + if (buf.length === size) { return buf; } + if (buf.subarray) { return buf.subarray(0, size); } + buf.length = size; + return buf; +}; + + +var fnTyped = { + arraySet: function (dest, src, src_offs, len, dest_offs) { + if (src.subarray && dest.subarray) { + dest.set(src.subarray(src_offs, src_offs+len), dest_offs); + return; + } + // Fallback to ordinary array + for(var i=0; i>> 16) & 0xffff) |0 + , n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return (s1 | (s2 << 16)) |0; +} + + +module.exports = adler32; +},{}],6:[function(require,module,exports){ +module.exports = { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + //Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type +}; +},{}],7:[function(require,module,exports){ +'use strict'; + +// Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. + + +// Use ordinary array, since untyped makes no boost here +function makeTable() { + var c, table = []; + + for(var n =0; n < 256; n++){ + c = n; + for(var k =0; k < 8; k++){ + c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; + } + + return table; +} + +// Create table on load. Just 255 signed longs. Not a problem. +var crcTable = makeTable(); + + +function crc32(crc, buf, len, pos) { + var t = crcTable + , end = pos + len; + + crc = crc ^ (-1); + + for (var i = pos; i < end; i++ ) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return (crc ^ (-1)); // >>> 0; +} + + +module.exports = crc32; +},{}],8:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils/common'); +var trees = require('./trees'); +var adler32 = require('./adler32'); +var crc32 = require('./crc32'); +var msg = require('./messages'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +var Z_NO_FLUSH = 0; +var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +//var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +//var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +//var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + + +/* compression levels */ +//var Z_NO_COMPRESSION = 0; +//var Z_BEST_SPEED = 1; +//var Z_BEST_COMPRESSION = 9; +var Z_DEFAULT_COMPRESSION = -1; + + +var Z_FILTERED = 1; +var Z_HUFFMAN_ONLY = 2; +var Z_RLE = 3; +var Z_FIXED = 4; +var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +//var Z_BINARY = 0; +//var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + + +/* The deflate compression method */ +var Z_DEFLATED = 8; + +/*============================================================================*/ + + +var MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_MEM_LEVEL = 8; + + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ +var LITERALS = 256; +/* number of literal bytes 0..255 */ +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ +var D_CODES = 30; +/* number of distance codes */ +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + +var PRESET_DICT = 0x20; + +var INIT_STATE = 42; +var EXTRA_STATE = 69; +var NAME_STATE = 73; +var COMMENT_STATE = 91; +var HCRC_STATE = 103; +var BUSY_STATE = 113; +var FINISH_STATE = 666; + +var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ +var BS_BLOCK_DONE = 2; /* block flush performed */ +var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ +var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + +var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +function err(strm, errorCode) { + strm.msg = msg[errorCode]; + return errorCode; +} + +function rank(f) { + return ((f) << 1) - ((f) > 4 ? 9 : 0); +} + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ +function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +} + + +function flush_block_only (s, last) { + trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +} + + +function put_byte(s, b) { + s.pending_buf[s.pending++] = b; +} + + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +function putShortMSB(s, b) { +// put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +} + + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ +function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + utils.arraySet(buf, strm.input, strm.next_in, len, start); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } + + else if (strm.state.wrap === 2) { + strm.adler = crc32(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; +} + + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +function longest_match(s, cur_match) { + var chain_length = s.max_chain_length; /* max hash chain length */ + var scan = s.strstart; /* current string */ + var match; /* matched string */ + var len; /* length of current match */ + var best_len = s.prev_length; /* best match length so far */ + var nice_match = s.nice_match; /* stop if match long enough */ + var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + var _win = s.window; // shortcut + + var wmask = s.w_mask; + var prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + var strend = s.strstart + MAX_MATCH; + var scan_end1 = _win[scan + best_len - 1]; + var scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; +} + + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +function fill_window(s) { + var _w_size = s.w_size; + var p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + utils.arraySet(s.window, s.window, _w_size, _w_size, 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = (m >= _w_size ? m - _w_size : 0); + } while (--n); + + n = _w_size; + p = n; + do { + m = s.prev[--p]; + s.prev[p] = (m >= _w_size ? m - _w_size : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// var curr = s.strstart + s.lookahead; +// var init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); +// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || +// s.block_start >= s.w_size)) { +// throw new Error("slide too late"); +// } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); +// if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +function deflate_fast(s, flush) { + var hash_head; /* head of the hash chain */ + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; + +//#if MIN_MATCH != 3 +// Call UPDATE_HASH() MIN_MATCH-3 more times +//#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1); + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +function deflate_slow(s, flush) { + var hash_head; /* head of hash chain */ + var bflush; /* set if current block must be flushed */ + + var max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH-1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length-1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH-1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; +} + + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +function deflate_rle(s, flush) { + var bflush; /* set if current block must be flushed */ + var prev; /* byte at distance one to match */ + var scan, strend; /* scan goes up to strend for length of run */ + + var _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +function deflate_huff(s, flush) { + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +var Config = function (good_length, max_lazy, nice_length, max_chain, func) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +}; + +var configuration_table; + +configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ +]; + + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +function lm_init(s) { + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +} + + +function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); + this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2); + this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new utils.Buf16(MAX_BITS+1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + + +function deflateResetKeep(strm) { + var s; + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = (s.wrap ? INIT_STATE : BUSY_STATE); + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH; + trees._tr_init(s); + return Z_OK; +} + + +function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === Z_OK) { + lm_init(strm.state); + } + return ret; +} + + +function deflateSetHeader(strm, head) { + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } + strm.state.gzhead = head; + return Z_OK; +} + + +function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR; + } + var wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION) { + level = 6; + } + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR); + } + + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + var s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new utils.Buf8(s.w_size * 2); + s.head = new utils.Buf16(s.hash_size); + s.prev = new utils.Buf16(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + s.pending_buf = new utils.Buf8(s.pending_buf_size); + + s.d_buf = s.lit_bufsize >> 1; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); +} + +function deflateInit(strm, level) { + return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} + + +function deflate(strm, flush) { + var old_flush, s; + var beg, val; // for gzip header write only + + if (!strm || !strm.state || + flush > Z_BLOCK || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; + } + + s = strm.state; + + if (!strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); + } + + s.strm = strm; /* just in case */ + old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + if (s.wrap === 2) { // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } + else // DEFLATE header + { + var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } + +//#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } + else { + s.status = NAME_STATE; + } + } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg){ + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } + else { + s.status = COMMENT_STATE; + } + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.status = HCRC_STATE; + } + } + else { + s.status = HCRC_STATE; + } + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } + } + else { + s.status = BUSY_STATE; + } + } +//#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH) { + return err(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { + var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : + (s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + trees._tr_align(s); + } + else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + + trees._tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH) { return Z_OK; } + if (s.wrap <= 0) { return Z_STREAM_END; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK : Z_STREAM_END; +} + +function deflateEnd(strm) { + var status; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR); + } + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state + */ +//function deflateCopy(dest, source) { +// +//} + +exports.deflateInit = deflateInit; +exports.deflateInit2 = deflateInit2; +exports.deflateReset = deflateReset; +exports.deflateResetKeep = deflateResetKeep; +exports.deflateSetHeader = deflateSetHeader; +exports.deflate = deflate; +exports.deflateEnd = deflateEnd; +exports.deflateInfo = 'pako deflate (from Nodeca project)'; + +/* Not implemented +exports.deflateBound = deflateBound; +exports.deflateCopy = deflateCopy; +exports.deflateSetDictionary = deflateSetDictionary; +exports.deflateParams = deflateParams; +exports.deflatePending = deflatePending; +exports.deflatePrime = deflatePrime; +exports.deflateTune = deflateTune; +*/ +},{"../utils/common":4,"./adler32":5,"./crc32":7,"./messages":12,"./trees":13}],9:[function(require,module,exports){ +'use strict'; + +// See state defs from inflate.js +var BAD = 30; /* got a data error -- remain here until reset */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ +module.exports = function inflate_fast(strm, start) { + var state; + var _in; /* local strm.input */ + var last; /* have enough input while in < last */ + var _out; /* local strm.output */ + var beg; /* inflate()'s initial strm.output */ + var end; /* while out < end, enough space available */ +//#ifdef INFLATE_STRICT + var dmax; /* maximum distance from zlib header */ +//#endif + var wsize; /* window size or zero if not using window */ + var whave; /* valid bytes in the window */ + var wnext; /* window write index */ + var window; /* allocated sliding window, if wsize != 0 */ + var hold; /* local strm.hold */ + var bits; /* local strm.bits */ + var lcode; /* local strm.lencode */ + var dcode; /* local strm.distcode */ + var lmask; /* mask for first level of length codes */ + var dmask; /* mask for first level of distance codes */ + var here; /* retrieved table entry */ + var op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + var len; /* match length, unused bytes */ + var dist; /* match distance */ + var from; /* where to copy match from */ + var from_source; + + + var input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); +//#ifdef INFLATE_STRICT + dmax = state.dmax; +//#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: + do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: + for (;;) { // Goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + if (op === 0) { /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff/*here.val*/; + } + else if (op & 16) { /* length base */ + len = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + len += hold & ((1 << op) - 1); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + here = dcode[hold & dmask]; + + dodist: + for (;;) { // goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + + if (op & 16) { /* distance base */ + dist = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + dist += hold & ((1 << op) - 1); +//#ifdef INFLATE_STRICT + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } +//#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = _out - beg; /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// if (len <= op - whave) { +// do { +// output[_out++] = 0; +// } while (--len); +// continue top; +// } +// len -= op - whave; +// do { +// output[_out++] = 0; +// } while (--op > whave); +// if (op === 0) { +// from = _out - dist; +// do { +// output[_out++] = output[from++]; +// } while (--len); +// continue top; +// } +//#endif + } + from = 0; // window index + from_source = window; + if (wnext === 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = 0; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + if (len) { + output[_out++] = from_source[from++]; + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } + else { + from = _out - dist; /* copy direct from output */ + do { /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + if (len) { + output[_out++] = output[from++]; + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } + else if ((op & 64) === 0) { /* 2nd level distance code */ + here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dodist; + } + else { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } + else if ((op & 64) === 0) { /* 2nd level length code */ + here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dolen; + } + else if (op & 32) { /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE; + break top; + } + else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); + strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); + state.hold = hold; + state.bits = bits; + return; +}; + +},{}],10:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); +var adler32 = require('./adler32'); +var crc32 = require('./crc32'); +var inflate_fast = require('./inffast'); +var inflate_table = require('./inftrees'); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +//var Z_NO_FLUSH = 0; +//var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +//var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + +/* The deflate compression method */ +var Z_DEFLATED = 8; + + +/* STATES ====================================================================*/ +/* ===========================================================================*/ + + +var HEAD = 1; /* i: waiting for magic header */ +var FLAGS = 2; /* i: waiting for method and flags (gzip) */ +var TIME = 3; /* i: waiting for modification time (gzip) */ +var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ +var EXLEN = 5; /* i: waiting for extra length (gzip) */ +var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ +var NAME = 7; /* i: waiting for end of file name (gzip) */ +var COMMENT = 8; /* i: waiting for end of comment (gzip) */ +var HCRC = 9; /* i: waiting for header crc (gzip) */ +var DICTID = 10; /* i: waiting for dictionary check value */ +var DICT = 11; /* waiting for inflateSetDictionary() call */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ +var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ +var STORED = 14; /* i: waiting for stored size (length and complement) */ +var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ +var COPY = 16; /* i/o: waiting for input or output to copy stored block */ +var TABLE = 17; /* i: waiting for dynamic block table lengths */ +var LENLENS = 18; /* i: waiting for code length code lengths */ +var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ +var LEN_ = 20; /* i: same as LEN below, but only first time in */ +var LEN = 21; /* i: waiting for length/lit/eob code */ +var LENEXT = 22; /* i: waiting for length extra bits */ +var DIST = 23; /* i: waiting for distance code */ +var DISTEXT = 24; /* i: waiting for distance extra bits */ +var MATCH = 25; /* o: waiting for output space to copy string */ +var LIT = 26; /* o: waiting for output space to write literal */ +var CHECK = 27; /* i: waiting for 32-bit check value */ +var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ +var DONE = 29; /* finished check, done -- remain here until reset */ +var BAD = 30; /* got a data error -- remain here until reset */ +var MEM = 31; /* got an inflate() memory error -- remain here until reset */ +var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + +/* ===========================================================================*/ + + + +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_WBITS = MAX_WBITS; + + +function ZSWAP32(q) { + return (((q >>> 24) & 0xff) + + ((q >>> 8) & 0xff00) + + ((q & 0xff00) << 8) + + ((q & 0xff) << 24)); +} + + +function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = null; /* starting table for length/literal codes */ + this.distcode = null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ + this.work = new utils.Buf16(288); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ + this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ +} + +function inflateResetKeep(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if (state.wrap) { /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null/*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); + state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +function inflateReset(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); + +} + +function inflateReset2(strm, windowBits) { + var wrap; + var state; + + /* get the state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; + if (windowBits < 48) { + windowBits &= 15; + } + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR; + } + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; + } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); +} + +function inflateInit2(strm, windowBits) { + var ret; + var state; + + if (!strm) { return Z_STREAM_ERROR; } + //strm.msg = Z_NULL; /* in case we return an error */ + + state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null/*Z_NULL*/; + ret = inflateReset2(strm, windowBits); + if (ret !== Z_OK) { + strm.state = null/*Z_NULL*/; + } + return ret; +} + +function inflateInit(strm) { + return inflateInit2(strm, DEF_WBITS); +} + + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +var virgin = true; + +var lenfix, distfix; // We have no pointers in JS, so keep tables separate + +function fixedtables(state) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + var sym; + + lenfix = new utils.Buf32(512); + distfix = new utils.Buf32(32); + + /* literal/length table */ + sym = 0; + while (sym < 144) { state.lens[sym++] = 8; } + while (sym < 256) { state.lens[sym++] = 9; } + while (sym < 280) { state.lens[sym++] = 7; } + while (sym < 288) { state.lens[sym++] = 8; } + + inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9}); + + /* distance table */ + sym = 0; + while (sym < 32) { state.lens[sym++] = 5; } + + inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5}); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +} + + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +function updatewindow(strm, src, end, copy) { + var dist; + var state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new utils.Buf8(state.wsize); + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state.wsize) { + utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0); + state.wnext = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.wnext; + if (dist > copy) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + utils.arraySet(state.window,src, end - copy, dist, state.wnext); + copy -= dist; + if (copy) { + //zmemcpy(state->window, end - copy, copy); + utils.arraySet(state.window,src, end - copy, copy, 0); + state.wnext = copy; + state.whave = state.wsize; + } + else { + state.wnext += dist; + if (state.wnext === state.wsize) { state.wnext = 0; } + if (state.whave < state.wsize) { state.whave += dist; } + } + } + return 0; +} + +function inflate(strm, flush) { + var state; + var input, output; // input/output buffers + var next; /* next input INDEX */ + var put; /* next output INDEX */ + var have, left; /* available input and output */ + var hold; /* bit buffer */ + var bits; /* bits in bit buffer */ + var _in, _out; /* save starting available input and output */ + var copy; /* number of stored or match bytes to copy */ + var from; /* where to copy match bytes from */ + var from_source; + var here = 0; /* current decoding table entry */ + var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //var last; /* parent table entry */ + var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + var len; /* length to copy for repeats, bits to drop */ + var ret; /* return code */ + var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ + var opts; + + var n; // temporary var for NEED_BITS + + var order = /* permutation of code lengths */ + [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + + + if (!strm || !strm.state || !strm.output || + (!strm.input && strm.avail_in !== 0)) { + return Z_STREAM_ERROR; + } + + state = strm.state; + if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ + + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ + state.check = 0/*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head) { + state.head.done = false; + } + if (!(state.wrap & 1) || /* check if zlib header allowed */ + (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = (hold & 0x0f)/*BITS(4)*/ + 8; + if (state.wbits === 0) { + state.wbits = len; + } + else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if (state.head) { + state.head.text = ((hold >> 8) & 1); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.time = hold; + } + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + hbuf[2] = (hold >>> 16) & 0xff; + hbuf[3] = (hold >>> 24) & 0xff; + state.check = crc32(state.check, hbuf, 4, 0); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.xflags = (hold & 0xff); + state.head.os = (hold >> 8); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length = hold; + if (state.head) { + state.head.extra_len = hold; + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + else if (state.head) { + state.head.extra = null/*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) { copy = have; } + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + if (!state.head.extra) { + // Use untyped array for more conveniend processing later + state.head.extra = new Array(state.head.extra_len); + } + utils.arraySet( + state.head.extra, + input, + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + copy, + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) { break inf_leave; } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.name_max*/)) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.comm_max*/)) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if (state.head) { + state.head.hcrc = ((state.flags >> 9) & 1); + state.head.done = true; + } + strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + strm.adler = state.check = ZSWAP32(hold); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT; + } + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } + /* falls through */ + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.last = (hold & 0x01)/*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ((hold & 0x03)/*BITS(2)*/) { + case 0: /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = LEN_; /* decode codes */ + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2: /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if (copy) { + if (copy > have) { copy = have; } + if (copy > left) { copy = left; } + if (copy === 0) { break inf_leave; } + //--- zmemcpy(put, next, copy); --- + utils.arraySet(output, input, next, copy, put); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// +//#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } +//#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = {bits: state.lenbits}; + ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[state.have++] = here_val; + } + else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03);//BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } + else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + (hold & 0x7f);//BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while (copy--) { + state.lens[state.have++] = len; + } + } + } + + /* handle error breaks in while */ + if (state.mode === BAD) { break; } + + /* check for end-of-block code (better have one) */ + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = {bits: state.lenbits}; + ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = {bits: state.distbits}; + ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inflate_fast(strm, _out); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if (state.mode === TYPE) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.lencode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.distcode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = (here_op) & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } +//#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +//#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if (left === 0) { break inf_leave; } + copy = _out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// Trace((stderr, "inflate.c too far\n")); +// copy -= state.whave; +// if (copy > state.length) { copy = state.length; } +// if (copy > left) { copy = left; } +// left -= copy; +// state.length -= copy; +// do { +// output[put++] = 0; +// } while (--copy); +// if (state.length === 0) { state.mode = LEN; } +// break; +//#endif + } + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } + else { + from = state.wnext - copy; + } + if (copy > state.length) { copy = state.length; } + from_source = state.window; + } + else { /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if (copy > left) { copy = left; } + left -= copy; + state.length -= copy; + do { + output[put++] = from_source[from++]; + } while (--copy); + if (state.length === 0) { state.mode = LEN; } + break; + case LIT: + if (left === 0) { break inf_leave; } + output[put++] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + // Use '|' insdead of '+' to make sure that result is signed + hold |= input[next++] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); + + } + _out = left; + // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too + if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR; + break inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && + (state.mode < CHECK || flush !== Z_FINISH))) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if (state.wrap && _out) { + strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); + } + strm.data_type = state.bits + (state.last ? 64 : 0) + + (state.mode === TYPE ? 128 : 0) + + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { + ret = Z_BUF_ERROR; + } + return ret; +} + +function inflateEnd(strm) { + + if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { + return Z_STREAM_ERROR; + } + + var state = strm.state; + if (state.window) { + state.window = null; + } + strm.state = null; + return Z_OK; +} + +function inflateGetHeader(strm, head) { + var state; + + /* check state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK; +} + + +exports.inflateReset = inflateReset; +exports.inflateReset2 = inflateReset2; +exports.inflateResetKeep = inflateResetKeep; +exports.inflateInit = inflateInit; +exports.inflateInit2 = inflateInit2; +exports.inflate = inflate; +exports.inflateEnd = inflateEnd; +exports.inflateGetHeader = inflateGetHeader; +exports.inflateInfo = 'pako inflate (from Nodeca project)'; + +/* Not implemented +exports.inflateCopy = inflateCopy; +exports.inflateGetDictionary = inflateGetDictionary; +exports.inflateMark = inflateMark; +exports.inflatePrime = inflatePrime; +exports.inflateSetDictionary = inflateSetDictionary; +exports.inflateSync = inflateSync; +exports.inflateSyncPoint = inflateSyncPoint; +exports.inflateUndermine = inflateUndermine; +*/ +},{"../utils/common":4,"./adler32":5,"./crc32":7,"./inffast":9,"./inftrees":11}],11:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); + +var MAXBITS = 15; +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +var lbase = [ /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +]; + +var lext = [ /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 +]; + +var dbase = [ /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0 +]; + +var dext = [ /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64 +]; + +module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) +{ + var bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + var len = 0; /* a code's length in bits */ + var sym = 0; /* index of code symbols */ + var min = 0, max = 0; /* minimum and maximum code lengths */ + var root = 0; /* number of index bits for root table */ + var curr = 0; /* number of index bits for current table */ + var drop = 0; /* code bits to drop for sub-table */ + var left = 0; /* number of prefix codes available */ + var used = 0; /* code entries in table used */ + var huff = 0; /* Huffman code */ + var incr; /* for incrementing code, index */ + var fill; /* index for replicating entries */ + var low; /* low bits for current root entry */ + var mask; /* mask for low root bits */ + var next; /* next available space in table */ + var base = null; /* base value table to use */ + var base_index = 0; +// var shoextra; /* extra bits table to use */ + var end; /* use base and extra for symbol > end */ + var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ + var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ + var extra = null; + var extra_index = 0; + + var here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { break; } + } + if (root > max) { + root = max; + } + if (max === 0) { /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) { + if (count[min] !== 0) { break; } + } + if (root < min) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) { + return -1; + } /* over-subscribed */ + } + if (left > 0 && (type === CODES || max !== 1)) { + return -1; /* incomplete set */ + } + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; + } + } + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if (type === CODES) { + base = extra = work; /* dummy value--not used */ + end = 19; + } else if (type === LENS) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + } else { /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + var i=0; + /* process all codes and make table entries */ + for (;;) { + i++; + /* create table entry */ + here_bits = len - drop; + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; + } + else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; + } + else { + here_op = 32 + 64; /* end of block */ + here_val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << (len - drop); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; + } while (fill !== 0); + + /* backwards increment the len-bit code huff */ + incr = 1 << (len - 1); + while (huff & incr) { + incr >>= 1; + } + if (incr !== 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--count[len] === 0) { + if (len === max) { break; } + len = lens[lens_index + work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) { break; } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; + } + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; +}; + +},{"../utils/common":4}],12:[function(require,module,exports){ +'use strict'; + +module.exports = { + '2': 'need dictionary', /* Z_NEED_DICT 2 */ + '1': 'stream end', /* Z_STREAM_END 1 */ + '0': '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; +},{}],13:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +//var Z_FILTERED = 1; +//var Z_HUFFMAN_ONLY = 2; +//var Z_RLE = 3; +var Z_FIXED = 4; +//var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +var Z_BINARY = 0; +var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + +/*============================================================================*/ + + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + +// From zutil.h + +var STORED_BLOCK = 0; +var STATIC_TREES = 1; +var DYN_TREES = 2; +/* The three kinds of block type */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +/* The minimum and maximum match lengths */ + +// From deflate.h +/* =========================================================================== + * Internal compression state. + */ + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +var LITERALS = 256; +/* number of literal bytes 0..255 */ + +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ + +var D_CODES = 30; +/* number of distance codes */ + +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ + +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ + +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var Buf_size = 16; +/* size of bit buffer in bi_buf */ + + +/* =========================================================================== + * Constants + */ + +var MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +var END_BLOCK = 256; +/* end of block literal code */ + +var REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +var REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +var REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +var extra_lbits = /* extra bits for each length code */ + [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; + +var extra_dbits = /* extra bits for each distance code */ + [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; + +var extra_blbits = /* extra bits for each bit length code */ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; + +var bl_order = + [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +// We pre-fill arrays with 0 to avoid uninitialized gaps + +var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + +// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 +var static_ltree = new Array((L_CODES+2) * 2); +zero(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +var static_dtree = new Array(D_CODES * 2); +zero(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +var _dist_code = new Array(DIST_CODE_LEN); +zero(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +var _length_code = new Array(MAX_MATCH-MIN_MATCH+1); +zero(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +var base_length = new Array(LENGTH_CODES); +zero(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +var base_dist = new Array(D_CODES); +zero(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + + +var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) { + + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; +}; + + +var static_l_desc; +var static_d_desc; +var static_bl_desc; + + +var TreeDesc = function(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ +}; + + + +function d_code(dist) { + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +} + + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +function put_short (s, w) { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +} + + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +function send_bits(s, value, length) { + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } +} + + +function send_code(s, c, tree) { + send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/); +} + + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +function bi_reverse(code, len) { + var res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; +} + + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +function bi_flush(s) { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +} + + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +function gen_bitlen(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var max_code = desc.max_code; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var extra = desc.stat_desc.extra_bits; + var base = desc.stat_desc.extra_base; + var max_length = desc.stat_desc.max_length; + var h; /* heap index */ + var n, m; /* iterate over the tree elements */ + var bits; /* bit length */ + var xbits; /* extra bits */ + var f; /* frequency */ + var overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max+1; h < HEAP_SIZE; h++) { + n = s.heap[h]; + bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n*2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n-base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits); + } + } + if (overflow === 0) { return; } + + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m*2 + 1]/*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/; + tree[m*2 + 1]/*.Len*/ = bits; + } + n--; + } + } +} + + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +function gen_codes(tree, max_code, bl_count) +// ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ +{ + var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */ + var code = 0; /* running code value */ + var bits; /* bit index */ + var n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n*2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n*2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n*2 + 1]/*.Len*/ = 5; + static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); + static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); + + //static_init_done = true; +} + + +/* =========================================================================== + * Initialize a new block. + */ +function init_block(s) { + var n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; } + + s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; +} + + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +function bi_windup(s) +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +function copy_block(s, buf, len, header) +//DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } +// while (len--) { +// put_byte(s, *buf++); +// } + utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); + s.pending += len; +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +function smaller(tree, n, m, depth) { + var _n2 = n*2; + var _m2 = m*2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); +} + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +function pqdownheap(s, tree, k) +// deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ +{ + var v = s.heap[k]; + var j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j+1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; +} + + +// inlined manually +// var SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +function compress_block(s, ltree, dtree) +// deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ +{ + var dist; /* distance of matched string */ + var lc; /* match length or unmatched char (if dist == 0) */ + var lx = 0; /* running index in l_buf */ + var code; /* the code to send */ + var extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]); + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); +} + + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +function build_tree(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var elems = desc.stat_desc.elems; + var n, m; /* iterate over heap elements */ + var max_code = -1; /* largest code with non zero frequency */ + var node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + + } else { + tree[n*2 + 1]/*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node*2 + 1]/*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ + + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); + + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); +} + + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +function scan_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6*2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10*2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138*2]/*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +function send_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count-11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +function build_bl_tree(s) { + var max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3*(max_blindex+1) + 5+5+4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +} + + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +function send_all_trees(s, lcodes, dcodes, blcodes) +// deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + var rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +function detect_data_type(s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + var black_mask = 0xf3ffc07f; + var n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) { + return Z_BINARY; + } + } + + /* Check for textual ("white-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + + +var static_init_done = false; + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +function _tr_init(s) +{ + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); +} + + +/* =========================================================================== + * Send a stored block + */ +function _tr_stored_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +function _tr_align(s) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +} + + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +function _tr_flush_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len+3+7) >>> 3; + static_lenb = (s.static_len+3+7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +function _tr_tally(s, dist, lc) +// deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + //var out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc*2]/*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility + +//#ifdef TRUNCATE_BLOCK +// /* Try to guess if it is profitable to stop the current block here */ +// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { +// /* Compute an upper bound for the compressed length */ +// out_length = s.last_lit*8; +// in_length = s.strstart - s.block_start; +// +// for (dcode = 0; dcode < D_CODES; dcode++) { +// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); +// } +// out_length >>>= 3; +// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", +// // s->last_lit, in_length, out_length, +// // 100L - out_length*100L/in_length)); +// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { +// return true; +// } +// } +//#endif + + return (s.last_lit === s.lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +exports._tr_init = _tr_init; +exports._tr_stored_block = _tr_stored_block; +exports._tr_flush_block = _tr_flush_block; +exports._tr_tally = _tr_tally; +exports._tr_align = _tr_align; +},{"../utils/common":4}],14:[function(require,module,exports){ +'use strict'; + + +function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; +} + +module.exports = ZStream; +},{}],15:[function(require,module,exports){ +(function (process,Buffer){ +var msg = require('pako/lib/zlib/messages'); +var zstream = require('pako/lib/zlib/zstream'); +var zlib_deflate = require('pako/lib/zlib/deflate.js'); +var zlib_inflate = require('pako/lib/zlib/inflate.js'); +var constants = require('pako/lib/zlib/constants'); + +for (var key in constants) { + exports[key] = constants[key]; +} + +// zlib modes +exports.NONE = 0; +exports.DEFLATE = 1; +exports.INFLATE = 2; +exports.GZIP = 3; +exports.GUNZIP = 4; +exports.DEFLATERAW = 5; +exports.INFLATERAW = 6; +exports.UNZIP = 7; + +/** + * Emulate Node's zlib C++ layer for use by the JS layer in index.js + */ +function Zlib(mode) { + if (mode < exports.DEFLATE || mode > exports.UNZIP) + throw new TypeError("Bad argument"); + + this.mode = mode; + this.init_done = false; + this.write_in_progress = false; + this.pending_close = false; + this.windowBits = 0; + this.level = 0; + this.memLevel = 0; + this.strategy = 0; + this.dictionary = null; +} + +Zlib.prototype.init = function(windowBits, level, memLevel, strategy, dictionary) { + this.windowBits = windowBits; + this.level = level; + this.memLevel = memLevel; + this.strategy = strategy; + // dictionary not supported. + + if (this.mode === exports.GZIP || this.mode === exports.GUNZIP) + this.windowBits += 16; + + if (this.mode === exports.UNZIP) + this.windowBits += 32; + + if (this.mode === exports.DEFLATERAW || this.mode === exports.INFLATERAW) + this.windowBits = -this.windowBits; + + this.strm = new zstream(); + + switch (this.mode) { + case exports.DEFLATE: + case exports.GZIP: + case exports.DEFLATERAW: + var status = zlib_deflate.deflateInit2( + this.strm, + this.level, + exports.Z_DEFLATED, + this.windowBits, + this.memLevel, + this.strategy + ); + break; + case exports.INFLATE: + case exports.GUNZIP: + case exports.INFLATERAW: + case exports.UNZIP: + var status = zlib_inflate.inflateInit2( + this.strm, + this.windowBits + ); + break; + default: + throw new Error("Unknown mode " + this.mode); + } + + if (status !== exports.Z_OK) { + this._error(status); + return; + } + + this.write_in_progress = false; + this.init_done = true; +}; + +Zlib.prototype.params = function() { + throw new Error("deflateParams Not supported"); +}; + +Zlib.prototype._writeCheck = function() { + if (!this.init_done) + throw new Error("write before init"); + + if (this.mode === exports.NONE) + throw new Error("already finalized"); + + if (this.write_in_progress) + throw new Error("write already in progress"); + + if (this.pending_close) + throw new Error("close is pending"); +}; + +Zlib.prototype.write = function(flush, input, in_off, in_len, out, out_off, out_len) { + this._writeCheck(); + this.write_in_progress = true; + + var self = this; + process.nextTick(function() { + self.write_in_progress = false; + var res = self._write(flush, input, in_off, in_len, out, out_off, out_len); + self.callback(res[0], res[1]); + + if (self.pending_close) + self.close(); + }); + + return this; +}; + +// set method for Node buffers, used by pako +function bufferSet(data, offset) { + for (var i = 0; i < data.length; i++) { + this[offset + i] = data[i]; + } +} + +Zlib.prototype.writeSync = function(flush, input, in_off, in_len, out, out_off, out_len) { + this._writeCheck(); + return this._write(flush, input, in_off, in_len, out, out_off, out_len); +}; + +Zlib.prototype._write = function(flush, input, in_off, in_len, out, out_off, out_len) { + this.write_in_progress = true; + + if (flush !== exports.Z_NO_FLUSH && + flush !== exports.Z_PARTIAL_FLUSH && + flush !== exports.Z_SYNC_FLUSH && + flush !== exports.Z_FULL_FLUSH && + flush !== exports.Z_FINISH && + flush !== exports.Z_BLOCK) { + throw new Error("Invalid flush value"); + } + + if (input == null) { + input = new Buffer(0); + in_len = 0; + in_off = 0; + } + + if (out._set) + out.set = out._set; + else + out.set = bufferSet; + + var strm = this.strm; + strm.avail_in = in_len; + strm.input = input; + strm.next_in = in_off; + strm.avail_out = out_len; + strm.output = out; + strm.next_out = out_off; + + switch (this.mode) { + case exports.DEFLATE: + case exports.GZIP: + case exports.DEFLATERAW: + var status = zlib_deflate.deflate(strm, flush); + break; + case exports.UNZIP: + case exports.INFLATE: + case exports.GUNZIP: + case exports.INFLATERAW: + var status = zlib_inflate.inflate(strm, flush); + break; + default: + throw new Error("Unknown mode " + this.mode); + } + + if (status !== exports.Z_STREAM_END && status !== exports.Z_OK) { + this._error(status); + } + + this.write_in_progress = false; + return [strm.avail_in, strm.avail_out]; +}; + +Zlib.prototype.close = function() { + if (this.write_in_progress) { + this.pending_close = true; + return; + } + + this.pending_close = false; + + if (this.mode === exports.DEFLATE || this.mode === exports.GZIP || this.mode === exports.DEFLATERAW) { + zlib_deflate.deflateEnd(this.strm); + } else { + zlib_inflate.inflateEnd(this.strm); + } + + this.mode = exports.NONE; +}; + +Zlib.prototype.reset = function() { + switch (this.mode) { + case exports.DEFLATE: + case exports.DEFLATERAW: + var status = zlib_deflate.deflateReset(this.strm); + break; + case exports.INFLATE: + case exports.INFLATERAW: + var status = zlib_inflate.inflateReset(this.strm); + break; + } + + if (status !== exports.Z_OK) { + this._error(status); + } +}; + +Zlib.prototype._error = function(status) { + this.onerror(msg[status] + ': ' + this.strm.msg, status); + + this.write_in_progress = false; + if (this.pending_close) + this.close(); +}; + +exports.Zlib = Zlib; + +}).call(this,require('_process'),require("buffer").Buffer) +},{"_process":24,"buffer":17,"pako/lib/zlib/constants":6,"pako/lib/zlib/deflate.js":8,"pako/lib/zlib/inflate.js":10,"pako/lib/zlib/messages":12,"pako/lib/zlib/zstream":14}],16:[function(require,module,exports){ +(function (process,Buffer){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Transform = require('_stream_transform'); + +var binding = require('./binding'); +var util = require('util'); +var assert = require('assert').ok; + +// zlib doesn't provide these, so kludge them in following the same +// const naming scheme zlib uses. +binding.Z_MIN_WINDOWBITS = 8; +binding.Z_MAX_WINDOWBITS = 15; +binding.Z_DEFAULT_WINDOWBITS = 15; + +// fewer than 64 bytes per chunk is stupid. +// technically it could work with as few as 8, but even 64 bytes +// is absurdly low. Usually a MB or more is best. +binding.Z_MIN_CHUNK = 64; +binding.Z_MAX_CHUNK = Infinity; +binding.Z_DEFAULT_CHUNK = (16 * 1024); + +binding.Z_MIN_MEMLEVEL = 1; +binding.Z_MAX_MEMLEVEL = 9; +binding.Z_DEFAULT_MEMLEVEL = 8; + +binding.Z_MIN_LEVEL = -1; +binding.Z_MAX_LEVEL = 9; +binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION; + +// expose all the zlib constants +Object.keys(binding).forEach(function(k) { + if (k.match(/^Z/)) exports[k] = binding[k]; +}); + +// translation table for return codes. +exports.codes = { + Z_OK: binding.Z_OK, + Z_STREAM_END: binding.Z_STREAM_END, + Z_NEED_DICT: binding.Z_NEED_DICT, + Z_ERRNO: binding.Z_ERRNO, + Z_STREAM_ERROR: binding.Z_STREAM_ERROR, + Z_DATA_ERROR: binding.Z_DATA_ERROR, + Z_MEM_ERROR: binding.Z_MEM_ERROR, + Z_BUF_ERROR: binding.Z_BUF_ERROR, + Z_VERSION_ERROR: binding.Z_VERSION_ERROR +}; + +Object.keys(exports.codes).forEach(function(k) { + exports.codes[exports.codes[k]] = k; +}); + +exports.Deflate = Deflate; +exports.Inflate = Inflate; +exports.Gzip = Gzip; +exports.Gunzip = Gunzip; +exports.DeflateRaw = DeflateRaw; +exports.InflateRaw = InflateRaw; +exports.Unzip = Unzip; + +exports.createDeflate = function(o) { + return new Deflate(o); +}; + +exports.createInflate = function(o) { + return new Inflate(o); +}; + +exports.createDeflateRaw = function(o) { + return new DeflateRaw(o); +}; + +exports.createInflateRaw = function(o) { + return new InflateRaw(o); +}; + +exports.createGzip = function(o) { + return new Gzip(o); +}; + +exports.createGunzip = function(o) { + return new Gunzip(o); +}; + +exports.createUnzip = function(o) { + return new Unzip(o); +}; + + +// Convenience methods. +// compress/decompress a string or buffer in one step. +exports.deflate = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new Deflate(opts), buffer, callback); +}; + +exports.deflateSync = function(buffer, opts) { + return zlibBufferSync(new Deflate(opts), buffer); +}; + +exports.gzip = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new Gzip(opts), buffer, callback); +}; + +exports.gzipSync = function(buffer, opts) { + return zlibBufferSync(new Gzip(opts), buffer); +}; + +exports.deflateRaw = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new DeflateRaw(opts), buffer, callback); +}; + +exports.deflateRawSync = function(buffer, opts) { + return zlibBufferSync(new DeflateRaw(opts), buffer); +}; + +exports.unzip = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new Unzip(opts), buffer, callback); +}; + +exports.unzipSync = function(buffer, opts) { + return zlibBufferSync(new Unzip(opts), buffer); +}; + +exports.inflate = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new Inflate(opts), buffer, callback); +}; + +exports.inflateSync = function(buffer, opts) { + return zlibBufferSync(new Inflate(opts), buffer); +}; + +exports.gunzip = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new Gunzip(opts), buffer, callback); +}; + +exports.gunzipSync = function(buffer, opts) { + return zlibBufferSync(new Gunzip(opts), buffer); +}; + +exports.inflateRaw = function(buffer, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + return zlibBuffer(new InflateRaw(opts), buffer, callback); +}; + +exports.inflateRawSync = function(buffer, opts) { + return zlibBufferSync(new InflateRaw(opts), buffer); +}; + +function zlibBuffer(engine, buffer, callback) { + var buffers = []; + var nread = 0; + + engine.on('error', onError); + engine.on('end', onEnd); + + engine.end(buffer); + flow(); + + function flow() { + var chunk; + while (null !== (chunk = engine.read())) { + buffers.push(chunk); + nread += chunk.length; + } + engine.once('readable', flow); + } + + function onError(err) { + engine.removeListener('end', onEnd); + engine.removeListener('readable', flow); + callback(err); + } + + function onEnd() { + var buf = Buffer.concat(buffers, nread); + buffers = []; + callback(null, buf); + engine.close(); + } +} + +function zlibBufferSync(engine, buffer) { + if (typeof buffer === 'string') + buffer = new Buffer(buffer); + if (!Buffer.isBuffer(buffer)) + throw new TypeError('Not a string or buffer'); + + var flushFlag = binding.Z_FINISH; + + return engine._processChunk(buffer, flushFlag); +} + +// generic zlib +// minimal 2-byte header +function Deflate(opts) { + if (!(this instanceof Deflate)) return new Deflate(opts); + Zlib.call(this, opts, binding.DEFLATE); +} + +function Inflate(opts) { + if (!(this instanceof Inflate)) return new Inflate(opts); + Zlib.call(this, opts, binding.INFLATE); +} + + + +// gzip - bigger header, same deflate compression +function Gzip(opts) { + if (!(this instanceof Gzip)) return new Gzip(opts); + Zlib.call(this, opts, binding.GZIP); +} + +function Gunzip(opts) { + if (!(this instanceof Gunzip)) return new Gunzip(opts); + Zlib.call(this, opts, binding.GUNZIP); +} + + + +// raw - no header +function DeflateRaw(opts) { + if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts); + Zlib.call(this, opts, binding.DEFLATERAW); +} + +function InflateRaw(opts) { + if (!(this instanceof InflateRaw)) return new InflateRaw(opts); + Zlib.call(this, opts, binding.INFLATERAW); +} + + +// auto-detect header. +function Unzip(opts) { + if (!(this instanceof Unzip)) return new Unzip(opts); + Zlib.call(this, opts, binding.UNZIP); +} + + +// the Zlib class they all inherit from +// This thing manages the queue of requests, and returns +// true or false if there is anything in the queue when +// you call the .write() method. + +function Zlib(opts, mode) { + this._opts = opts = opts || {}; + this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK; + + Transform.call(this, opts); + + if (opts.flush) { + if (opts.flush !== binding.Z_NO_FLUSH && + opts.flush !== binding.Z_PARTIAL_FLUSH && + opts.flush !== binding.Z_SYNC_FLUSH && + opts.flush !== binding.Z_FULL_FLUSH && + opts.flush !== binding.Z_FINISH && + opts.flush !== binding.Z_BLOCK) { + throw new Error('Invalid flush flag: ' + opts.flush); + } + } + this._flushFlag = opts.flush || binding.Z_NO_FLUSH; + + if (opts.chunkSize) { + if (opts.chunkSize < exports.Z_MIN_CHUNK || + opts.chunkSize > exports.Z_MAX_CHUNK) { + throw new Error('Invalid chunk size: ' + opts.chunkSize); + } + } + + if (opts.windowBits) { + if (opts.windowBits < exports.Z_MIN_WINDOWBITS || + opts.windowBits > exports.Z_MAX_WINDOWBITS) { + throw new Error('Invalid windowBits: ' + opts.windowBits); + } + } + + if (opts.level) { + if (opts.level < exports.Z_MIN_LEVEL || + opts.level > exports.Z_MAX_LEVEL) { + throw new Error('Invalid compression level: ' + opts.level); + } + } + + if (opts.memLevel) { + if (opts.memLevel < exports.Z_MIN_MEMLEVEL || + opts.memLevel > exports.Z_MAX_MEMLEVEL) { + throw new Error('Invalid memLevel: ' + opts.memLevel); + } + } + + if (opts.strategy) { + if (opts.strategy != exports.Z_FILTERED && + opts.strategy != exports.Z_HUFFMAN_ONLY && + opts.strategy != exports.Z_RLE && + opts.strategy != exports.Z_FIXED && + opts.strategy != exports.Z_DEFAULT_STRATEGY) { + throw new Error('Invalid strategy: ' + opts.strategy); + } + } + + if (opts.dictionary) { + if (!Buffer.isBuffer(opts.dictionary)) { + throw new Error('Invalid dictionary: it should be a Buffer instance'); + } + } + + this._binding = new binding.Zlib(mode); + + var self = this; + this._hadError = false; + this._binding.onerror = function(message, errno) { + // there is no way to cleanly recover. + // continuing only obscures problems. + self._binding = null; + self._hadError = true; + + var error = new Error(message); + error.errno = errno; + error.code = exports.codes[errno]; + self.emit('error', error); + }; + + var level = exports.Z_DEFAULT_COMPRESSION; + if (typeof opts.level === 'number') level = opts.level; + + var strategy = exports.Z_DEFAULT_STRATEGY; + if (typeof opts.strategy === 'number') strategy = opts.strategy; + + this._binding.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, + level, + opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, + strategy, + opts.dictionary); + + this._buffer = new Buffer(this._chunkSize); + this._offset = 0; + this._closed = false; + this._level = level; + this._strategy = strategy; + + this.once('end', this.close); +} + +util.inherits(Zlib, Transform); + +Zlib.prototype.params = function(level, strategy, callback) { + if (level < exports.Z_MIN_LEVEL || + level > exports.Z_MAX_LEVEL) { + throw new RangeError('Invalid compression level: ' + level); + } + if (strategy != exports.Z_FILTERED && + strategy != exports.Z_HUFFMAN_ONLY && + strategy != exports.Z_RLE && + strategy != exports.Z_FIXED && + strategy != exports.Z_DEFAULT_STRATEGY) { + throw new TypeError('Invalid strategy: ' + strategy); + } + + if (this._level !== level || this._strategy !== strategy) { + var self = this; + this.flush(binding.Z_SYNC_FLUSH, function() { + self._binding.params(level, strategy); + if (!self._hadError) { + self._level = level; + self._strategy = strategy; + if (callback) callback(); + } + }); + } else { + process.nextTick(callback); + } +}; + +Zlib.prototype.reset = function() { + return this._binding.reset(); +}; + +// This is the _flush function called by the transform class, +// internally, when the last chunk has been written. +Zlib.prototype._flush = function(callback) { + this._transform(new Buffer(0), '', callback); +}; + +Zlib.prototype.flush = function(kind, callback) { + var ws = this._writableState; + + if (typeof kind === 'function' || (kind === void 0 && !callback)) { + callback = kind; + kind = binding.Z_FULL_FLUSH; + } + + if (ws.ended) { + if (callback) + process.nextTick(callback); + } else if (ws.ending) { + if (callback) + this.once('end', callback); + } else if (ws.needDrain) { + var self = this; + this.once('drain', function() { + self.flush(callback); + }); + } else { + this._flushFlag = kind; + this.write(new Buffer(0), '', callback); + } +}; + +Zlib.prototype.close = function(callback) { + if (callback) + process.nextTick(callback); + + if (this._closed) + return; + + this._closed = true; + + this._binding.close(); + + var self = this; + process.nextTick(function() { + self.emit('close'); + }); +}; + +Zlib.prototype._transform = function(chunk, encoding, cb) { + var flushFlag; + var ws = this._writableState; + var ending = ws.ending || ws.ended; + var last = ending && (!chunk || ws.length === chunk.length); + + if (!chunk === null && !Buffer.isBuffer(chunk)) + return cb(new Error('invalid input')); + + // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag. + // If it's explicitly flushing at some other time, then we use + // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression + // goodness. + if (last) + flushFlag = binding.Z_FINISH; + else { + flushFlag = this._flushFlag; + // once we've flushed the last of the queue, stop flushing and + // go back to the normal behavior. + if (chunk.length >= ws.length) { + this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH; + } + } + + var self = this; + this._processChunk(chunk, flushFlag, cb); +}; + +Zlib.prototype._processChunk = function(chunk, flushFlag, cb) { + var availInBefore = chunk && chunk.length; + var availOutBefore = this._chunkSize - this._offset; + var inOff = 0; + + var self = this; + + var async = typeof cb === 'function'; + + if (!async) { + var buffers = []; + var nread = 0; + + var error; + this.on('error', function(er) { + error = er; + }); + + do { + var res = this._binding.writeSync(flushFlag, + chunk, // in + inOff, // in_off + availInBefore, // in_len + this._buffer, // out + this._offset, //out_off + availOutBefore); // out_len + } while (!this._hadError && callback(res[0], res[1])); + + if (this._hadError) { + throw error; + } + + var buf = Buffer.concat(buffers, nread); + this.close(); + + return buf; + } + + var req = this._binding.write(flushFlag, + chunk, // in + inOff, // in_off + availInBefore, // in_len + this._buffer, // out + this._offset, //out_off + availOutBefore); // out_len + + req.buffer = chunk; + req.callback = callback; + + function callback(availInAfter, availOutAfter) { + if (self._hadError) + return; + + var have = availOutBefore - availOutAfter; + assert(have >= 0, 'have should not go down'); + + if (have > 0) { + var out = self._buffer.slice(self._offset, self._offset + have); + self._offset += have; + // serve some output to the consumer. + if (async) { + self.push(out); + } else { + buffers.push(out); + nread += out.length; + } + } + + // exhausted the output buffer, or used all the input create a new one. + if (availOutAfter === 0 || self._offset >= self._chunkSize) { + availOutBefore = self._chunkSize; + self._offset = 0; + self._buffer = new Buffer(self._chunkSize); + } + + if (availOutAfter === 0) { + // Not actually done. Need to reprocess. + // Also, update the availInBefore to the availInAfter value, + // so that if we have to hit it a third (fourth, etc.) time, + // it'll have the correct byte counts. + inOff += (availInBefore - availInAfter); + availInBefore = availInAfter; + + if (!async) + return true; + + var newReq = self._binding.write(flushFlag, + chunk, + inOff, + availInBefore, + self._buffer, + self._offset, + self._chunkSize); + newReq.callback = callback; // this same function + newReq.buffer = chunk; + return; + } + + if (!async) + return false; + + // finished with the chunk. + cb(); + } +}; + +util.inherits(Deflate, Zlib); +util.inherits(Inflate, Zlib); +util.inherits(Gzip, Zlib); +util.inherits(Gunzip, Zlib); +util.inherits(DeflateRaw, Zlib); +util.inherits(InflateRaw, Zlib); +util.inherits(Unzip, Zlib); + +}).call(this,require('_process'),require("buffer").Buffer) +},{"./binding":15,"_process":24,"_stream_transform":34,"assert":2,"buffer":17,"util":39}],17:[function(require,module,exports){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +var base64 = require('base64-js') +var ieee754 = require('ieee754') +var isArray = require('is-array') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 +Buffer.poolSize = 8192 // not used by this implementation + +var kMaxLength = 0x3fffffff +var rootParent = {} + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Note: + * + * - Implementation must support adding new properties to `Uint8Array` instances. + * Firefox 4-29 lacked support, fixed in Firefox 30+. + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. + * + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they will + * get the Object implementation, which is slower but will work correctly. + */ +Buffer.TYPED_ARRAY_SUPPORT = (function () { + try { + var buf = new ArrayBuffer(0) + var arr = new Uint8Array(buf) + arr.foo = function () { return 42 } + return arr.foo() === 42 && // typed array instances can be augmented + typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` + new Uint8Array(1).subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` + } catch (e) { + return false + } +})() + +/** + * Class: Buffer + * ============= + * + * The Buffer constructor returns instances of `Uint8Array` that are augmented + * with function properties for all the node `Buffer` API functions. We use + * `Uint8Array` so that square bracket notation works as expected -- it returns + * a single octet. + * + * By augmenting the instances, we can avoid modifying the `Uint8Array` + * prototype. + */ +function Buffer (subject, encoding, noZero) { + if (!(this instanceof Buffer)) + return new Buffer(subject, encoding, noZero) + + var type = typeof subject + + // Find the length + var length + if (type === 'number') { + length = +subject + } else if (type === 'string') { + length = Buffer.byteLength(subject, encoding) + } else if (type === 'object' && subject !== null) { // assume object is array-like + if (subject.type === 'Buffer' && isArray(subject.data)) + subject = subject.data + length = +subject.length + } else { + throw new TypeError('must start with number, buffer, array or string') + } + + if (length > kMaxLength) + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + kMaxLength.toString(16) + ' bytes') + + if (length < 0) + length = 0 + else + length >>>= 0 // Coerce to uint32. + + var self = this + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Preferred: Return an augmented `Uint8Array` instance for best performance + /*eslint-disable consistent-this */ + self = Buffer._augment(new Uint8Array(length)) + /*eslint-enable consistent-this */ + } else { + // Fallback: Return THIS instance of Buffer (created by `new`) + self.length = length + self._isBuffer = true + } + + var i + if (Buffer.TYPED_ARRAY_SUPPORT && typeof subject.byteLength === 'number') { + // Speed optimization -- use set if we're copying from a typed array + self._set(subject) + } else if (isArrayish(subject)) { + // Treat array-ish objects as a byte array + if (Buffer.isBuffer(subject)) { + for (i = 0; i < length; i++) + self[i] = subject.readUInt8(i) + } else { + for (i = 0; i < length; i++) + self[i] = ((subject[i] % 256) + 256) % 256 + } + } else if (type === 'string') { + self.write(subject, 0, encoding) + } else if (type === 'number' && !Buffer.TYPED_ARRAY_SUPPORT && !noZero) { + for (i = 0; i < length; i++) { + self[i] = 0 + } + } + + if (length > 0 && length <= Buffer.poolSize) + self.parent = rootParent + + return self +} + +function SlowBuffer (subject, encoding, noZero) { + if (!(this instanceof SlowBuffer)) + return new SlowBuffer(subject, encoding, noZero) + + var buf = new Buffer(subject, encoding, noZero) + delete buf.parent + return buf +} + +Buffer.isBuffer = function (b) { + return !!(b != null && b._isBuffer) +} + +Buffer.compare = function (a, b) { + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) + throw new TypeError('Arguments must be Buffers') + + if (a === b) return 0 + + var x = a.length + var y = b.length + for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {} + if (i !== len) { + x = a[i] + y = b[i] + } + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'binary': + case 'base64': + case 'raw': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function (list, totalLength) { + if (!isArray(list)) throw new TypeError('Usage: Buffer.concat(list[, length])') + + if (list.length === 0) { + return new Buffer(0) + } else if (list.length === 1) { + return list[0] + } + + var i + if (totalLength === undefined) { + totalLength = 0 + for (i = 0; i < list.length; i++) { + totalLength += list[i].length + } + } + + var buf = new Buffer(totalLength) + var pos = 0 + for (i = 0; i < list.length; i++) { + var item = list[i] + item.copy(buf, pos) + pos += item.length + } + return buf +} + +Buffer.byteLength = function (str, encoding) { + var ret + str = str + '' + switch (encoding || 'utf8') { + case 'ascii': + case 'binary': + case 'raw': + ret = str.length + break + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + ret = str.length * 2 + break + case 'hex': + ret = str.length >>> 1 + break + case 'utf8': + case 'utf-8': + ret = utf8ToBytes(str).length + break + case 'base64': + ret = base64ToBytes(str).length + break + default: + ret = str.length + } + return ret +} + +// pre-set for values that may exist in the future +Buffer.prototype.length = undefined +Buffer.prototype.parent = undefined + +// toString(encoding, start=0, end=buffer.length) +Buffer.prototype.toString = function (encoding, start, end) { + var loweredCase = false + + start = start >>> 0 + end = end === undefined || end === Infinity ? this.length : end >>> 0 + + if (!encoding) encoding = 'utf8' + if (start < 0) start = 0 + if (end > this.length) end = this.length + if (end <= start) return '' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'binary': + return binarySlice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) + throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.equals = function (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + if (this.length > 0) { + str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') + if (this.length > max) + str += ' ... ' + } + return '' +} + +Buffer.prototype.compare = function (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return 0 + return Buffer.compare(this, b) +} + +// `get` will be removed in Node 0.13+ +Buffer.prototype.get = function (offset) { + console.log('.get() is deprecated. Access using array indexes instead.') + return this.readUInt8(offset) +} + +// `set` will be removed in Node 0.13+ +Buffer.prototype.set = function (v, offset) { + console.log('.set() is deprecated. Access using array indexes instead.') + return this.writeUInt8(v, offset) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + // must be an even number of digits + var strLen = string.length + if (strLen % 2 !== 0) throw new Error('Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; i++) { + var byte = parseInt(string.substr(i * 2, 2), 16) + if (isNaN(byte)) throw new Error('Invalid hex string') + buf[offset + i] = byte + } + return i +} + +function utf8Write (buf, string, offset, length) { + var charsWritten = blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) + return charsWritten +} + +function asciiWrite (buf, string, offset, length) { + var charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length) + return charsWritten +} + +function binaryWrite (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + var charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length) + return charsWritten +} + +function utf16leWrite (buf, string, offset, length) { + var charsWritten = blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) + return charsWritten +} + +Buffer.prototype.write = function (string, offset, length, encoding) { + // Support both (string, offset, length, encoding) + // and the legacy (string, encoding, offset, length) + if (isFinite(offset)) { + if (!isFinite(length)) { + encoding = length + length = undefined + } + } else { // legacy + var swap = encoding + encoding = offset + offset = length + length = swap + } + + offset = Number(offset) || 0 + + if (length < 0 || offset < 0 || offset > this.length) + throw new RangeError('attempt to write outside buffer bounds') + + var remaining = this.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + encoding = String(encoding || 'utf8').toLowerCase() + + var ret + switch (encoding) { + case 'hex': + ret = hexWrite(this, string, offset, length) + break + case 'utf8': + case 'utf-8': + ret = utf8Write(this, string, offset, length) + break + case 'ascii': + ret = asciiWrite(this, string, offset, length) + break + case 'binary': + ret = binaryWrite(this, string, offset, length) + break + case 'base64': + ret = base64Write(this, string, offset, length) + break + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + ret = utf16leWrite(this, string, offset, length) + break + default: + throw new TypeError('Unknown encoding: ' + encoding) + } + return ret +} + +Buffer.prototype.toJSON = function () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + var res = '' + var tmp = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; i++) { + if (buf[i] <= 0x7F) { + res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]) + tmp = '' + } else { + tmp += '%' + buf[i].toString(16) + } + } + + return res + decodeUtf8Char(tmp) +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; i++) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function binarySlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; i++) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; i++) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) + } + return res +} + +Buffer.prototype.slice = function (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) + start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) + end = 0 + } else if (end > len) { + end = len + } + + if (end < start) + end = start + + var newBuf + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = Buffer._augment(this.subarray(start, end)) + } else { + var sliceLen = end - start + newBuf = new Buffer(sliceLen, undefined, true) + for (var i = 0; i < sliceLen; i++) { + newBuf[i] = this[i + start] + } + } + + if (newBuf.length) + newBuf.parent = this.parent || this + + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) + throw new RangeError('offset is not uint') + if (offset + ext > length) + throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) + val += this[offset + i] * mul + + return val +} + +Buffer.prototype.readUIntBE = function (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkOffset(offset, byteLength, this.length) + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) + val += this[offset + --byteLength] * mul + + return val +} + +Buffer.prototype.readUInt8 = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) + val += this[offset + i] * mul + mul *= 0x80 + + if (val >= mul) + val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) + val += this[offset + --i] * mul + mul *= 0x80 + + if (val >= mul) + val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) + return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function (offset, noAssert) { + if (!noAssert) + checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') + if (value > max || value < min) throw new RangeError('value is out of bounds') + if (offset + ext > buf.length) throw new RangeError('index out of range') +} + +Buffer.prototype.writeUIntLE = function (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) + this[offset + i] = (value / mul) >>> 0 & 0xFF + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) + checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) + this[offset + i] = (value / mul) >>> 0 & 0xFF + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 1, 0xff, 0) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + this[offset] = value + return offset + 1 +} + +function objectWriteUInt16 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { + buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8 + } +} + +Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value + this[offset + 1] = (value >>> 8) + } else objectWriteUInt16(this, value, offset, true) + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = value + } else objectWriteUInt16(this, value, offset, false) + return offset + 2 +} + +function objectWriteUInt32 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { + buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff + } +} + +Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = value + } else objectWriteUInt32(this, value, offset, true) + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = value + } else objectWriteUInt32(this, value, offset, false) + return offset + 4 +} + +Buffer.prototype.writeIntLE = function (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkInt(this, + value, + offset, + byteLength, + Math.pow(2, 8 * byteLength - 1) - 1, + -Math.pow(2, 8 * byteLength - 1)) + } + + var i = 0 + var mul = 1 + var sub = value < 0 ? 1 : 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkInt(this, + value, + offset, + byteLength, + Math.pow(2, 8 * byteLength - 1) - 1, + -Math.pow(2, 8 * byteLength - 1)) + } + + var i = byteLength - 1 + var mul = 1 + var sub = value < 0 ? 1 : 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 1, 0x7f, -0x80) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + if (value < 0) value = 0xff + value + 1 + this[offset] = value + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value + this[offset + 1] = (value >>> 8) + } else objectWriteUInt16(this, value, offset, true) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = value + } else objectWriteUInt16(this, value, offset, false) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + } else objectWriteUInt32(this, value, offset, true) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) + checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = value + } else objectWriteUInt32(this, value, offset, false) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (value > max || value < min) throw new RangeError('value is out of bounds') + if (offset + ext > buf.length) throw new RangeError('index out of range') + if (offset < 0) throw new RangeError('index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function (target, target_start, start, end) { + var self = this // source + + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (target_start >= target.length) target_start = target.length + if (!target_start) target_start = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || self.length === 0) return 0 + + // Fatal error conditions + if (target_start < 0) + throw new RangeError('targetStart out of bounds') + if (start < 0 || start >= self.length) throw new RangeError('sourceStart out of bounds') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) + end = this.length + if (target.length - target_start < end - start) + end = target.length - target_start + start + + var len = end - start + + if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < len; i++) { + target[i + target_start] = this[i + start] + } + } else { + target._set(this.subarray(start, start + len), target_start) + } + + return len +} + +// fill(value, start=0, end=buffer.length) +Buffer.prototype.fill = function (value, start, end) { + if (!value) value = 0 + if (!start) start = 0 + if (!end) end = this.length + + if (end < start) throw new RangeError('end < start') + + // Fill 0 bytes; we're done + if (end === start) return + if (this.length === 0) return + + if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') + if (end < 0 || end > this.length) throw new RangeError('end out of bounds') + + var i + if (typeof value === 'number') { + for (i = start; i < end; i++) { + this[i] = value + } + } else { + var bytes = utf8ToBytes(value.toString()) + var len = bytes.length + for (i = start; i < end; i++) { + this[i] = bytes[i % len] + } + } + + return this +} + +/** + * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. + * Added in Node 0.12. Only available in browsers that support ArrayBuffer. + */ +Buffer.prototype.toArrayBuffer = function () { + if (typeof Uint8Array !== 'undefined') { + if (Buffer.TYPED_ARRAY_SUPPORT) { + return (new Buffer(this)).buffer + } else { + var buf = new Uint8Array(this.length) + for (var i = 0, len = buf.length; i < len; i += 1) { + buf[i] = this[i] + } + return buf.buffer + } + } else { + throw new TypeError('Buffer.toArrayBuffer not supported in this browser') + } +} + +// HELPER FUNCTIONS +// ================ + +var BP = Buffer.prototype + +/** + * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods + */ +Buffer._augment = function (arr) { + arr.constructor = Buffer + arr._isBuffer = true + + // save reference to original Uint8Array get/set methods before overwriting + arr._get = arr.get + arr._set = arr.set + + // deprecated, will be removed in node 0.13+ + arr.get = BP.get + arr.set = BP.set + + arr.write = BP.write + arr.toString = BP.toString + arr.toLocaleString = BP.toString + arr.toJSON = BP.toJSON + arr.equals = BP.equals + arr.compare = BP.compare + arr.copy = BP.copy + arr.slice = BP.slice + arr.readUIntLE = BP.readUIntLE + arr.readUIntBE = BP.readUIntBE + arr.readUInt8 = BP.readUInt8 + arr.readUInt16LE = BP.readUInt16LE + arr.readUInt16BE = BP.readUInt16BE + arr.readUInt32LE = BP.readUInt32LE + arr.readUInt32BE = BP.readUInt32BE + arr.readIntLE = BP.readIntLE + arr.readIntBE = BP.readIntBE + arr.readInt8 = BP.readInt8 + arr.readInt16LE = BP.readInt16LE + arr.readInt16BE = BP.readInt16BE + arr.readInt32LE = BP.readInt32LE + arr.readInt32BE = BP.readInt32BE + arr.readFloatLE = BP.readFloatLE + arr.readFloatBE = BP.readFloatBE + arr.readDoubleLE = BP.readDoubleLE + arr.readDoubleBE = BP.readDoubleBE + arr.writeUInt8 = BP.writeUInt8 + arr.writeUIntLE = BP.writeUIntLE + arr.writeUIntBE = BP.writeUIntBE + arr.writeUInt16LE = BP.writeUInt16LE + arr.writeUInt16BE = BP.writeUInt16BE + arr.writeUInt32LE = BP.writeUInt32LE + arr.writeUInt32BE = BP.writeUInt32BE + arr.writeIntLE = BP.writeIntLE + arr.writeIntBE = BP.writeIntBE + arr.writeInt8 = BP.writeInt8 + arr.writeInt16LE = BP.writeInt16LE + arr.writeInt16BE = BP.writeInt16BE + arr.writeInt32LE = BP.writeInt32LE + arr.writeInt32BE = BP.writeInt32BE + arr.writeFloatLE = BP.writeFloatLE + arr.writeFloatBE = BP.writeFloatBE + arr.writeDoubleLE = BP.writeDoubleLE + arr.writeDoubleBE = BP.writeDoubleBE + arr.fill = BP.fill + arr.inspect = BP.inspect + arr.toArrayBuffer = BP.toArrayBuffer + + return arr +} + +var INVALID_BASE64_RE = /[^+\/0-9A-z\-]/g + +function base64clean (str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') +} + +function isArrayish (subject) { + return isArray(subject) || Buffer.isBuffer(subject) || + subject && typeof subject === 'object' && + typeof subject.length === 'number' +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + var i = 0 + + for (; i < length; i++) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (leadSurrogate) { + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } else { + // valid surrogate pair + codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000 + leadSurrogate = null + } + } else { + // no lead yet + + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else { + // valid lead + leadSurrogate = codePoint + continue + } + } + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = null + } + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x200000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; i++) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; i++) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; i++) { + if ((i + offset >= dst.length) || (i >= src.length)) + break + dst[i + offset] = src[i] + } + return i +} + +function decodeUtf8Char (str) { + try { + return decodeURIComponent(str) + } catch (err) { + return String.fromCharCode(0xFFFD) // UTF 8 invalid char + } +} + +},{"base64-js":18,"ieee754":19,"is-array":20}],18:[function(require,module,exports){ +var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +;(function (exports) { + 'use strict'; + + var Arr = (typeof Uint8Array !== 'undefined') + ? Uint8Array + : Array + + var PLUS = '+'.charCodeAt(0) + var SLASH = '/'.charCodeAt(0) + var NUMBER = '0'.charCodeAt(0) + var LOWER = 'a'.charCodeAt(0) + var UPPER = 'A'.charCodeAt(0) + var PLUS_URL_SAFE = '-'.charCodeAt(0) + var SLASH_URL_SAFE = '_'.charCodeAt(0) + + function decode (elt) { + var code = elt.charCodeAt(0) + if (code === PLUS || + code === PLUS_URL_SAFE) + return 62 // '+' + if (code === SLASH || + code === SLASH_URL_SAFE) + return 63 // '/' + if (code < NUMBER) + return -1 //no match + if (code < NUMBER + 10) + return code - NUMBER + 26 + 26 + if (code < UPPER + 26) + return code - UPPER + if (code < LOWER + 26) + return code - LOWER + 26 + } + + function b64ToByteArray (b64) { + var i, j, l, tmp, placeHolders, arr + + if (b64.length % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + var len = b64.length + placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 + + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(b64.length * 3 / 4 - placeHolders) + + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? b64.length - 4 : b64.length + + var L = 0 + + function push (v) { + arr[L++] = v + } + + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) + push((tmp & 0xFF0000) >> 16) + push((tmp & 0xFF00) >> 8) + push(tmp & 0xFF) + } + + if (placeHolders === 2) { + tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) + push(tmp & 0xFF) + } else if (placeHolders === 1) { + tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) + push((tmp >> 8) & 0xFF) + push(tmp & 0xFF) + } + + return arr + } + + function uint8ToBase64 (uint8) { + var i, + extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes + output = "", + temp, length + + function encode (num) { + return lookup.charAt(num) + } + + function tripletToBase64 (num) { + return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) + } + + // go through the array every three bytes, we'll deal with trailing stuff later + for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { + temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + output += tripletToBase64(temp) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + switch (extraBytes) { + case 1: + temp = uint8[uint8.length - 1] + output += encode(temp >> 2) + output += encode((temp << 4) & 0x3F) + output += '==' + break + case 2: + temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) + output += encode(temp >> 10) + output += encode((temp >> 4) & 0x3F) + output += encode((temp << 2) & 0x3F) + output += '=' + break + } + + return output + } + + exports.toByteArray = b64ToByteArray + exports.fromByteArray = uint8ToBase64 +}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) + +},{}],19:[function(require,module,exports){ +exports.read = function(buffer, offset, isLE, mLen, nBytes) { + var e, m, + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + nBits = -7, + i = isLE ? (nBytes - 1) : 0, + d = isLE ? -1 : 1, + s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity); + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; + +exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c, + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), + i = isLE ? 0 : (nBytes - 1), + d = isLE ? 1 : -1, + s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); + + buffer[offset + i - d] |= s * 128; +}; + +},{}],20:[function(require,module,exports){ + +/** + * isArray + */ + +var isArray = Array.isArray; + +/** + * toString + */ + +var str = Object.prototype.toString; + +/** + * Whether or not the given `val` + * is an array. + * + * example: + * + * isArray([]); + * // > true + * isArray(arguments); + * // > false + * isArray(''); + * // > false + * + * @param {mixed} val + * @return {bool} + */ + +module.exports = isArray || function (val) { + return !! val && '[object Array]' == str.call(val); +}; + +},{}],21:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],22:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],23:[function(require,module,exports){ +module.exports = Array.isArray || function (arr) { + return Object.prototype.toString.call(arr) == '[object Array]'; +}; + +},{}],24:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; + +function drainQueue() { + if (draining) { + return; + } + draining = true; + var currentQueue; + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + var i = -1; + while (++i < len) { + currentQueue[i](); + } + len = queue.length; + } + draining = false; +} +process.nextTick = function (fun) { + queue.push(fun); + if (!draining) { + setTimeout(drainQueue, 0); + } +}; + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],25:[function(require,module,exports){ +module.exports = require("./lib/_stream_duplex.js") + +},{"./lib/_stream_duplex.js":26}],26:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. + +module.exports = Duplex; + +/**/ +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; +} +/**/ + + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +var Readable = require('./_stream_readable'); +var Writable = require('./_stream_writable'); + +util.inherits(Duplex, Readable); + +forEach(objectKeys(Writable.prototype), function(method) { + if (!Duplex.prototype[method]) + Duplex.prototype[method] = Writable.prototype[method]; +}); + +function Duplex(options) { + if (!(this instanceof Duplex)) + return new Duplex(options); + + Readable.call(this, options); + Writable.call(this, options); + + if (options && options.readable === false) + this.readable = false; + + if (options && options.writable === false) + this.writable = false; + + this.allowHalfOpen = true; + if (options && options.allowHalfOpen === false) + this.allowHalfOpen = false; + + this.once('end', onend); +} + +// the no-half-open enforcer +function onend() { + // if we allow half-open state, or if the writable side ended, + // then we're ok. + if (this.allowHalfOpen || this._writableState.ended) + return; + + // no more data can be written. + // But allow more writes to happen in this tick. + process.nextTick(this.end.bind(this)); +} + +function forEach (xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} + +}).call(this,require('_process')) +},{"./_stream_readable":28,"./_stream_writable":30,"_process":24,"core-util-is":31,"inherits":22}],27:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. + +module.exports = PassThrough; + +var Transform = require('./_stream_transform'); + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +util.inherits(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) + return new PassThrough(options); + + Transform.call(this, options); +} + +PassThrough.prototype._transform = function(chunk, encoding, cb) { + cb(null, chunk); +}; + +},{"./_stream_transform":29,"core-util-is":31,"inherits":22}],28:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +module.exports = Readable; + +/**/ +var isArray = require('isarray'); +/**/ + + +/**/ +var Buffer = require('buffer').Buffer; +/**/ + +Readable.ReadableState = ReadableState; + +var EE = require('events').EventEmitter; + +/**/ +if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { + return emitter.listeners(type).length; +}; +/**/ + +var Stream = require('stream'); + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +var StringDecoder; + + +/**/ +var debug = require('util'); +if (debug && debug.debuglog) { + debug = debug.debuglog('stream'); +} else { + debug = function () {}; +} +/**/ + + +util.inherits(Readable, Stream); + +function ReadableState(options, stream) { + var Duplex = require('./_stream_duplex'); + + options = options || {}; + + // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + var hwm = options.highWaterMark; + var defaultHwm = options.objectMode ? 16 : 16 * 1024; + this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; + + // cast to ints. + this.highWaterMark = ~~this.highWaterMark; + + this.buffer = []; + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; + + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; + + // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + + + // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + this.objectMode = !!options.objectMode; + + if (stream instanceof Duplex) + this.objectMode = this.objectMode || !!options.readableObjectMode; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // when piping, we only care about 'readable' events that happen + // after read()ing all the bytes and not getting any pushback. + this.ranOut = false; + + // the number of writers that are awaiting a drain event in .pipe()s + this.awaitDrain = 0; + + // if true, a maybeReadMore has been scheduled + this.readingMore = false; + + this.decoder = null; + this.encoding = null; + if (options.encoding) { + if (!StringDecoder) + StringDecoder = require('string_decoder/').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + var Duplex = require('./_stream_duplex'); + + if (!(this instanceof Readable)) + return new Readable(options); + + this._readableState = new ReadableState(options, this); + + // legacy + this.readable = true; + + Stream.call(this); +} + +// Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. +Readable.prototype.push = function(chunk, encoding) { + var state = this._readableState; + + if (util.isString(chunk) && !state.objectMode) { + encoding = encoding || state.defaultEncoding; + if (encoding !== state.encoding) { + chunk = new Buffer(chunk, encoding); + encoding = ''; + } + } + + return readableAddChunk(this, state, chunk, encoding, false); +}; + +// Unshift should *always* be something directly out of read() +Readable.prototype.unshift = function(chunk) { + var state = this._readableState; + return readableAddChunk(this, state, chunk, '', true); +}; + +function readableAddChunk(stream, state, chunk, encoding, addToFront) { + var er = chunkInvalid(state, chunk); + if (er) { + stream.emit('error', er); + } else if (util.isNullOrUndefined(chunk)) { + state.reading = false; + if (!state.ended) + onEofChunk(stream, state); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (state.ended && !addToFront) { + var e = new Error('stream.push() after EOF'); + stream.emit('error', e); + } else if (state.endEmitted && addToFront) { + var e = new Error('stream.unshift() after end event'); + stream.emit('error', e); + } else { + if (state.decoder && !addToFront && !encoding) + chunk = state.decoder.write(chunk); + + if (!addToFront) + state.reading = false; + + // if we want the data now, just emit it. + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) + state.buffer.unshift(chunk); + else + state.buffer.push(chunk); + + if (state.needReadable) + emitReadable(stream); + } + + maybeReadMore(stream, state); + } + } else if (!addToFront) { + state.reading = false; + } + + return needMoreData(state); +} + + + +// if it's past the high water mark, we can push in some more. +// Also, if we have no data yet, we can stand some +// more bytes. This is to work around cases where hwm=0, +// such as the repl. Also, if the push() triggered a +// readable event, and the user called read(largeNumber) such that +// needReadable was set, then we ought to push more, so that another +// 'readable' event will be triggered. +function needMoreData(state) { + return !state.ended && + (state.needReadable || + state.length < state.highWaterMark || + state.length === 0); +} + +// backwards compatibility. +Readable.prototype.setEncoding = function(enc) { + if (!StringDecoder) + StringDecoder = require('string_decoder/').StringDecoder; + this._readableState.decoder = new StringDecoder(enc); + this._readableState.encoding = enc; + return this; +}; + +// Don't raise the hwm > 128MB +var MAX_HWM = 0x800000; +function roundUpToNextPowerOf2(n) { + if (n >= MAX_HWM) { + n = MAX_HWM; + } else { + // Get the next highest power of 2 + n--; + for (var p = 1; p < 32; p <<= 1) n |= n >> p; + n++; + } + return n; +} + +function howMuchToRead(n, state) { + if (state.length === 0 && state.ended) + return 0; + + if (state.objectMode) + return n === 0 ? 0 : 1; + + if (isNaN(n) || util.isNull(n)) { + // only flow one buffer at a time + if (state.flowing && state.buffer.length) + return state.buffer[0].length; + else + return state.length; + } + + if (n <= 0) + return 0; + + // If we're asking for more than the target buffer level, + // then raise the water mark. Bump up to the next highest + // power of 2, to prevent increasing it excessively in tiny + // amounts. + if (n > state.highWaterMark) + state.highWaterMark = roundUpToNextPowerOf2(n); + + // don't have that much. return null, unless we've ended. + if (n > state.length) { + if (!state.ended) { + state.needReadable = true; + return 0; + } else + return state.length; + } + + return n; +} + +// you can override either this method, or the async _read(n) below. +Readable.prototype.read = function(n) { + debug('read', n); + var state = this._readableState; + var nOrig = n; + + if (!util.isNumber(n) || n > 0) + state.emittedReadable = false; + + // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + if (n === 0 && + state.needReadable && + (state.length >= state.highWaterMark || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) + endReadable(this); + else + emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); + + // if we've ended, and we're now clear, then finish it up. + if (n === 0 && state.ended) { + if (state.length === 0) + endReadable(this); + return null; + } + + // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + + // if we need a readable event, then we need to do some reading. + var doRead = state.needReadable; + debug('need readable', doRead); + + // if we currently have less than the highWaterMark, then also read some + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } + + // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } + + if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; + // if the length is currently zero, then we *need* a readable event. + if (state.length === 0) + state.needReadable = true; + // call internal read method + this._read(state.highWaterMark); + state.sync = false; + } + + // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + if (doRead && !state.reading) + n = howMuchToRead(nOrig, state); + + var ret; + if (n > 0) + ret = fromList(n, state); + else + ret = null; + + if (util.isNull(ret)) { + state.needReadable = true; + n = 0; + } + + state.length -= n; + + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (state.length === 0 && !state.ended) + state.needReadable = true; + + // If we tried to read() past the EOF, then emit end on the next tick. + if (nOrig !== n && state.ended && state.length === 0) + endReadable(this); + + if (!util.isNull(ret)) + this.emit('data', ret); + + return ret; +}; + +function chunkInvalid(state, chunk) { + var er = null; + if (!util.isBuffer(chunk) && + !util.isString(chunk) && + !util.isNullOrUndefined(chunk) && + !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + return er; +} + + +function onEofChunk(stream, state) { + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + state.ended = true; + + // emit 'readable' now to make sure it gets picked up. + emitReadable(stream); +} + +// Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. +function emitReadable(stream) { + var state = stream._readableState; + state.needReadable = false; + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + if (state.sync) + process.nextTick(function() { + emitReadable_(stream); + }); + else + emitReadable_(stream); + } +} + +function emitReadable_(stream) { + debug('emit readable'); + stream.emit('readable'); + flow(stream); +} + + +// at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + process.nextTick(function() { + maybeReadMore_(stream, state); + }); + } +} + +function maybeReadMore_(stream, state) { + var len = state.length; + while (!state.reading && !state.flowing && !state.ended && + state.length < state.highWaterMark) { + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) + // didn't get any data, stop spinning. + break; + else + len = state.length; + } + state.readingMore = false; +} + +// abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. +Readable.prototype._read = function(n) { + this.emit('error', new Error('not implemented')); +}; + +Readable.prototype.pipe = function(dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + case 1: + state.pipes = [state.pipes, dest]; + break; + default: + state.pipes.push(dest); + break; + } + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + + var doEnd = (!pipeOpts || pipeOpts.end !== false) && + dest !== process.stdout && + dest !== process.stderr; + + var endFn = doEnd ? onend : cleanup; + if (state.endEmitted) + process.nextTick(endFn); + else + src.once('end', endFn); + + dest.on('unpipe', onunpipe); + function onunpipe(readable) { + debug('onunpipe'); + if (readable === src) { + cleanup(); + } + } + + function onend() { + debug('onend'); + dest.end(); + } + + // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + + function cleanup() { + debug('cleanup'); + // cleanup event handlers once the pipe is broken + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', cleanup); + src.removeListener('data', ondata); + + // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + if (state.awaitDrain && + (!dest._writableState || dest._writableState.needDrain)) + ondrain(); + } + + src.on('data', ondata); + function ondata(chunk) { + debug('ondata'); + var ret = dest.write(chunk); + if (false === ret) { + debug('false write response, pause', + src._readableState.awaitDrain); + src._readableState.awaitDrain++; + src.pause(); + } + } + + // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EE.listenerCount(dest, 'error') === 0) + dest.emit('error', er); + } + // This is a brutally ugly hack to make sure that our error handler + // is attached before any userland ones. NEVER DO THIS. + if (!dest._events || !dest._events.error) + dest.on('error', onerror); + else if (isArray(dest._events.error)) + dest._events.error.unshift(onerror); + else + dest._events.error = [onerror, dest._events.error]; + + + + // Both close and finish should trigger unpipe, but only once. + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + dest.once('close', onclose); + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } + + // tell the dest that it's being piped to + dest.emit('pipe', src); + + // start the flow if it hasn't been started already. + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function() { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) + state.awaitDrain--; + if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + + +Readable.prototype.unpipe = function(dest) { + var state = this._readableState; + + // if we're not piping anywhere, then do nothing. + if (state.pipesCount === 0) + return this; + + // just one destination. most common case. + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) + return this; + + if (!dest) + dest = state.pipes; + + // got a match. + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) + dest.emit('unpipe', this); + return this; + } + + // slow case. multiple pipe destinations. + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) + dests[i].emit('unpipe', this); + return this; + } + + // try to find the right one. + var i = indexOf(state.pipes, dest); + if (i === -1) + return this; + + state.pipes.splice(i, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) + state.pipes = state.pipes[0]; + + dest.emit('unpipe', this); + + return this; +}; + +// set up data events if they are asked for +// Ensure readable listeners eventually get something +Readable.prototype.on = function(ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + + // If listening to data, and it has not explicitly been paused, + // then call resume to start the flow of data on the next tick. + if (ev === 'data' && false !== this._readableState.flowing) { + this.resume(); + } + + if (ev === 'readable' && this.readable) { + var state = this._readableState; + if (!state.readableListening) { + state.readableListening = true; + state.emittedReadable = false; + state.needReadable = true; + if (!state.reading) { + var self = this; + process.nextTick(function() { + debug('readable nexttick read 0'); + self.read(0); + }); + } else if (state.length) { + emitReadable(this, state); + } + } + } + + return res; +}; +Readable.prototype.addListener = Readable.prototype.on; + +// pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. +Readable.prototype.resume = function() { + var state = this._readableState; + if (!state.flowing) { + debug('resume'); + state.flowing = true; + if (!state.reading) { + debug('resume read 0'); + this.read(0); + } + resume(this, state); + } + return this; +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + process.nextTick(function() { + resume_(stream, state); + }); + } +} + +function resume_(stream, state) { + state.resumeScheduled = false; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) + stream.read(0); +} + +Readable.prototype.pause = function() { + debug('call pause flowing=%j', this._readableState.flowing); + if (false !== this._readableState.flowing) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } + return this; +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + if (state.flowing) { + do { + var chunk = stream.read(); + } while (null !== chunk && state.flowing); + } +} + +// wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. +Readable.prototype.wrap = function(stream) { + var state = this._readableState; + var paused = false; + + var self = this; + stream.on('end', function() { + debug('wrapped end'); + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) + self.push(chunk); + } + + self.push(null); + }); + + stream.on('data', function(chunk) { + debug('wrapped data'); + if (state.decoder) + chunk = state.decoder.write(chunk); + if (!chunk || !state.objectMode && !chunk.length) + return; + + var ret = self.push(chunk); + if (!ret) { + paused = true; + stream.pause(); + } + }); + + // proxy all the other methods. + // important when wrapping filters and duplexes. + for (var i in stream) { + if (util.isFunction(stream[i]) && util.isUndefined(this[i])) { + this[i] = function(method) { return function() { + return stream[method].apply(stream, arguments); + }}(i); + } + } + + // proxy certain important events. + var events = ['error', 'close', 'destroy', 'pause', 'resume']; + forEach(events, function(ev) { + stream.on(ev, self.emit.bind(self, ev)); + }); + + // when we try to consume some more bytes, simply unpause the + // underlying stream. + self._read = function(n) { + debug('wrapped _read', n); + if (paused) { + paused = false; + stream.resume(); + } + }; + + return self; +}; + + + +// exposed for testing purposes only. +Readable._fromList = fromList; + +// Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +function fromList(n, state) { + var list = state.buffer; + var length = state.length; + var stringMode = !!state.decoder; + var objectMode = !!state.objectMode; + var ret; + + // nothing in the list, definitely empty. + if (list.length === 0) + return null; + + if (length === 0) + ret = null; + else if (objectMode) + ret = list.shift(); + else if (!n || n >= length) { + // read it all, truncate the array. + if (stringMode) + ret = list.join(''); + else + ret = Buffer.concat(list, length); + list.length = 0; + } else { + // read just some of it. + if (n < list[0].length) { + // just take a part of the first list item. + // slice is the same for buffers and strings. + var buf = list[0]; + ret = buf.slice(0, n); + list[0] = buf.slice(n); + } else if (n === list[0].length) { + // first list is a perfect match + ret = list.shift(); + } else { + // complex case. + // we have enough to cover it, but it spans past the first buffer. + if (stringMode) + ret = ''; + else + ret = new Buffer(n); + + var c = 0; + for (var i = 0, l = list.length; i < l && c < n; i++) { + var buf = list[0]; + var cpy = Math.min(n - c, buf.length); + + if (stringMode) + ret += buf.slice(0, cpy); + else + buf.copy(ret, c, 0, cpy); + + if (cpy < buf.length) + list[0] = buf.slice(cpy); + else + list.shift(); + + c += cpy; + } + } + } + + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + + // If we get here before consuming all the bytes, then that is a + // bug in node. Should never happen. + if (state.length > 0) + throw new Error('endReadable called on non-empty stream'); + + if (!state.endEmitted) { + state.ended = true; + process.nextTick(function() { + // Check that we didn't get one last unshift. + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + } + }); + } +} + +function forEach (xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} + +function indexOf (xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; + } + return -1; +} + +}).call(this,require('_process')) +},{"./_stream_duplex":26,"_process":24,"buffer":17,"core-util-is":31,"events":21,"inherits":22,"isarray":23,"stream":36,"string_decoder/":37,"util":3}],29:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. + +module.exports = Transform; + +var Duplex = require('./_stream_duplex'); + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +util.inherits(Transform, Duplex); + + +function TransformState(options, stream) { + this.afterTransform = function(er, data) { + return afterTransform(stream, er, data); + }; + + this.needTransform = false; + this.transforming = false; + this.writecb = null; + this.writechunk = null; +} + +function afterTransform(stream, er, data) { + var ts = stream._transformState; + ts.transforming = false; + + var cb = ts.writecb; + + if (!cb) + return stream.emit('error', new Error('no writecb in Transform class')); + + ts.writechunk = null; + ts.writecb = null; + + if (!util.isNullOrUndefined(data)) + stream.push(data); + + if (cb) + cb(er); + + var rs = stream._readableState; + rs.reading = false; + if (rs.needReadable || rs.length < rs.highWaterMark) { + stream._read(rs.highWaterMark); + } +} + + +function Transform(options) { + if (!(this instanceof Transform)) + return new Transform(options); + + Duplex.call(this, options); + + this._transformState = new TransformState(options, this); + + // when the writable side finishes, then flush out anything remaining. + var stream = this; + + // start out asking for a readable event once data is transformed. + this._readableState.needReadable = true; + + // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + this._readableState.sync = false; + + this.once('prefinish', function() { + if (util.isFunction(this._flush)) + this._flush(function(er) { + done(stream, er); + }); + else + done(stream); + }); +} + +Transform.prototype.push = function(chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; + +// This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. +Transform.prototype._transform = function(chunk, encoding, cb) { + throw new Error('not implemented'); +}; + +Transform.prototype._write = function(chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || + rs.needReadable || + rs.length < rs.highWaterMark) + this._read(rs.highWaterMark); + } +}; + +// Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. +Transform.prototype._read = function(n) { + var ts = this._transformState; + + if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { + ts.transforming = true; + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + + +function done(stream, er) { + if (er) + return stream.emit('error', er); + + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + var ws = stream._writableState; + var ts = stream._transformState; + + if (ws.length) + throw new Error('calling transform done when ws.length != 0'); + + if (ts.transforming) + throw new Error('calling transform done when still transforming'); + + return stream.push(null); +} + +},{"./_stream_duplex":26,"core-util-is":31,"inherits":22}],30:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// A bit simpler than readable streams. +// Implement an async ._write(chunk, cb), and it'll handle all +// the drain event emission and buffering. + +module.exports = Writable; + +/**/ +var Buffer = require('buffer').Buffer; +/**/ + +Writable.WritableState = WritableState; + + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +var Stream = require('stream'); + +util.inherits(Writable, Stream); + +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; +} + +function WritableState(options, stream) { + var Duplex = require('./_stream_duplex'); + + options = options || {}; + + // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + var hwm = options.highWaterMark; + var defaultHwm = options.objectMode ? 16 : 16 * 1024; + this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; + + // object stream flag to indicate whether or not this stream + // contains buffers or objects. + this.objectMode = !!options.objectMode; + + if (stream instanceof Duplex) + this.objectMode = this.objectMode || !!options.writableObjectMode; + + // cast to ints. + this.highWaterMark = ~~this.highWaterMark; + + this.needDrain = false; + // at the start of calling end() + this.ending = false; + // when end() has been called, and returned + this.ended = false; + // when 'finish' is emitted + this.finished = false; + + // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + this.length = 0; + + // a flag to see when we're in the middle of a write. + this.writing = false; + + // when true all writes will be buffered until .uncork() call + this.corked = 0; + + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; + + // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + this.bufferProcessing = false; + + // the callback that's passed to _write(chunk,cb) + this.onwrite = function(er) { + onwrite(stream, er); + }; + + // the callback that the user supplies to write(chunk,encoding,cb) + this.writecb = null; + + // the amount that is being written when _write is called. + this.writelen = 0; + + this.buffer = []; + + // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + this.pendingcb = 0; + + // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + this.prefinished = false; + + // True if the error was already emitted and should not be thrown again + this.errorEmitted = false; +} + +function Writable(options) { + var Duplex = require('./_stream_duplex'); + + // Writable ctor is applied to Duplexes, though they're not + // instanceof Writable, they're instanceof Readable. + if (!(this instanceof Writable) && !(this instanceof Duplex)) + return new Writable(options); + + this._writableState = new WritableState(options, this); + + // legacy. + this.writable = true; + + Stream.call(this); +} + +// Otherwise people can pipe Writable streams, which is just wrong. +Writable.prototype.pipe = function() { + this.emit('error', new Error('Cannot pipe. Not readable.')); +}; + + +function writeAfterEnd(stream, state, cb) { + var er = new Error('write after end'); + // TODO: defer error events consistently everywhere, not just the cb + stream.emit('error', er); + process.nextTick(function() { + cb(er); + }); +} + +// If we get something that is not a buffer, string, null, or undefined, +// and we're not in objectMode, then that's an error. +// Otherwise stream chunks are all considered to be of length=1, and the +// watermarks determine how many objects to keep in the buffer, rather than +// how many bytes or characters. +function validChunk(stream, state, chunk, cb) { + var valid = true; + if (!util.isBuffer(chunk) && + !util.isString(chunk) && + !util.isNullOrUndefined(chunk) && + !state.objectMode) { + var er = new TypeError('Invalid non-string/buffer chunk'); + stream.emit('error', er); + process.nextTick(function() { + cb(er); + }); + valid = false; + } + return valid; +} + +Writable.prototype.write = function(chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + + if (util.isFunction(encoding)) { + cb = encoding; + encoding = null; + } + + if (util.isBuffer(chunk)) + encoding = 'buffer'; + else if (!encoding) + encoding = state.defaultEncoding; + + if (!util.isFunction(cb)) + cb = function() {}; + + if (state.ended) + writeAfterEnd(this, state, cb); + else if (validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, chunk, encoding, cb); + } + + return ret; +}; + +Writable.prototype.cork = function() { + var state = this._writableState; + + state.corked++; +}; + +Writable.prototype.uncork = function() { + var state = this._writableState; + + if (state.corked) { + state.corked--; + + if (!state.writing && + !state.corked && + !state.finished && + !state.bufferProcessing && + state.buffer.length) + clearBuffer(this, state); + } +}; + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && + state.decodeStrings !== false && + util.isString(chunk)) { + chunk = new Buffer(chunk, encoding); + } + return chunk; +} + +// if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. +function writeOrBuffer(stream, state, chunk, encoding, cb) { + chunk = decodeChunk(state, chunk, encoding); + if (util.isBuffer(chunk)) + encoding = 'buffer'; + var len = state.objectMode ? 1 : chunk.length; + + state.length += len; + + var ret = state.length < state.highWaterMark; + // we must ensure that previous needDrain will not be reset to false. + if (!ret) + state.needDrain = true; + + if (state.writing || state.corked) + state.buffer.push(new WriteReq(chunk, encoding, cb)); + else + doWrite(stream, state, false, len, chunk, encoding, cb); + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (writev) + stream._writev(chunk, state.onwrite); + else + stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + if (sync) + process.nextTick(function() { + state.pendingcb--; + cb(er); + }); + else { + state.pendingcb--; + cb(er); + } + + stream._writableState.errorEmitted = true; + stream.emit('error', er); +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + + onwriteStateUpdate(state); + + if (er) + onwriteError(stream, state, sync, er, cb); + else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(stream, state); + + if (!finished && + !state.corked && + !state.bufferProcessing && + state.buffer.length) { + clearBuffer(stream, state); + } + + if (sync) { + process.nextTick(function() { + afterWrite(stream, state, finished, cb); + }); + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) + onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} + +// Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} + + +// if there's something in the buffer waiting, then process it +function clearBuffer(stream, state) { + state.bufferProcessing = true; + + if (stream._writev && state.buffer.length > 1) { + // Fast case, write everything using _writev() + var cbs = []; + for (var c = 0; c < state.buffer.length; c++) + cbs.push(state.buffer[c].callback); + + // count the one we are adding, as well. + // TODO(isaacs) clean this up + state.pendingcb++; + doWrite(stream, state, true, state.length, state.buffer, '', function(err) { + for (var i = 0; i < cbs.length; i++) { + state.pendingcb--; + cbs[i](err); + } + }); + + // Clear buffer + state.buffer = []; + } else { + // Slow case, write chunks one-by-one + for (var c = 0; c < state.buffer.length; c++) { + var entry = state.buffer[c]; + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + + doWrite(stream, state, false, len, chunk, encoding, cb); + + // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + if (state.writing) { + c++; + break; + } + } + + if (c < state.buffer.length) + state.buffer = state.buffer.slice(c); + else + state.buffer.length = 0; + } + + state.bufferProcessing = false; +} + +Writable.prototype._write = function(chunk, encoding, cb) { + cb(new Error('not implemented')); + +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function(chunk, encoding, cb) { + var state = this._writableState; + + if (util.isFunction(chunk)) { + cb = chunk; + chunk = null; + encoding = null; + } else if (util.isFunction(encoding)) { + cb = encoding; + encoding = null; + } + + if (!util.isNullOrUndefined(chunk)) + this.write(chunk, encoding); + + // .end() fully uncorks + if (state.corked) { + state.corked = 1; + this.uncork(); + } + + // ignore unnecessary end() calls. + if (!state.ending && !state.finished) + endWritable(this, state, cb); +}; + + +function needFinish(stream, state) { + return (state.ending && + state.length === 0 && + !state.finished && + !state.writing); +} + +function prefinish(stream, state) { + if (!state.prefinished) { + state.prefinished = true; + stream.emit('prefinish'); + } +} + +function finishMaybe(stream, state) { + var need = needFinish(stream, state); + if (need) { + if (state.pendingcb === 0) { + prefinish(stream, state); + state.finished = true; + stream.emit('finish'); + } else + prefinish(stream, state); + } + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + if (cb) { + if (state.finished) + process.nextTick(cb); + else + stream.once('finish', cb); + } + state.ended = true; +} + +}).call(this,require('_process')) +},{"./_stream_duplex":26,"_process":24,"buffer":17,"core-util-is":31,"inherits":22,"stream":36}],31:[function(require,module,exports){ +(function (Buffer){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +function isBuffer(arg) { + return Buffer.isBuffer(arg); +} +exports.isBuffer = isBuffer; + +function objectToString(o) { + return Object.prototype.toString.call(o); +} +}).call(this,require("buffer").Buffer) +},{"buffer":17}],32:[function(require,module,exports){ +module.exports = require("./lib/_stream_passthrough.js") + +},{"./lib/_stream_passthrough.js":27}],33:[function(require,module,exports){ +exports = module.exports = require('./lib/_stream_readable.js'); +exports.Stream = require('stream'); +exports.Readable = exports; +exports.Writable = require('./lib/_stream_writable.js'); +exports.Duplex = require('./lib/_stream_duplex.js'); +exports.Transform = require('./lib/_stream_transform.js'); +exports.PassThrough = require('./lib/_stream_passthrough.js'); + +},{"./lib/_stream_duplex.js":26,"./lib/_stream_passthrough.js":27,"./lib/_stream_readable.js":28,"./lib/_stream_transform.js":29,"./lib/_stream_writable.js":30,"stream":36}],34:[function(require,module,exports){ +module.exports = require("./lib/_stream_transform.js") + +},{"./lib/_stream_transform.js":29}],35:[function(require,module,exports){ +module.exports = require("./lib/_stream_writable.js") + +},{"./lib/_stream_writable.js":30}],36:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +module.exports = Stream; + +var EE = require('events').EventEmitter; +var inherits = require('inherits'); + +inherits(Stream, EE); +Stream.Readable = require('readable-stream/readable.js'); +Stream.Writable = require('readable-stream/writable.js'); +Stream.Duplex = require('readable-stream/duplex.js'); +Stream.Transform = require('readable-stream/transform.js'); +Stream.PassThrough = require('readable-stream/passthrough.js'); + +// Backwards-compat with node 0.4.x +Stream.Stream = Stream; + + + +// old-style streams. Note that the pipe method (the only relevant +// part of this class) is overridden in the Readable class. + +function Stream() { + EE.call(this); +} + +Stream.prototype.pipe = function(dest, options) { + var source = this; + + function ondata(chunk) { + if (dest.writable) { + if (false === dest.write(chunk) && source.pause) { + source.pause(); + } + } + } + + source.on('data', ondata); + + function ondrain() { + if (source.readable && source.resume) { + source.resume(); + } + } + + dest.on('drain', ondrain); + + // If the 'end' option is not supplied, dest.end() will be called when + // source gets the 'end' or 'close' events. Only dest.end() once. + if (!dest._isStdio && (!options || options.end !== false)) { + source.on('end', onend); + source.on('close', onclose); + } + + var didOnEnd = false; + function onend() { + if (didOnEnd) return; + didOnEnd = true; + + dest.end(); + } + + + function onclose() { + if (didOnEnd) return; + didOnEnd = true; + + if (typeof dest.destroy === 'function') dest.destroy(); + } + + // don't leave dangling pipes when there are errors. + function onerror(er) { + cleanup(); + if (EE.listenerCount(this, 'error') === 0) { + throw er; // Unhandled stream error in pipe. + } + } + + source.on('error', onerror); + dest.on('error', onerror); + + // remove all the event listeners that were added. + function cleanup() { + source.removeListener('data', ondata); + dest.removeListener('drain', ondrain); + + source.removeListener('end', onend); + source.removeListener('close', onclose); + + source.removeListener('error', onerror); + dest.removeListener('error', onerror); + + source.removeListener('end', cleanup); + source.removeListener('close', cleanup); + + dest.removeListener('close', cleanup); + } + + source.on('end', cleanup); + source.on('close', cleanup); + + dest.on('close', cleanup); + + dest.emit('pipe', source); + + // Allow for unix-like usage: A.pipe(B).pipe(C) + return dest; +}; + +},{"events":21,"inherits":22,"readable-stream/duplex.js":25,"readable-stream/passthrough.js":32,"readable-stream/readable.js":33,"readable-stream/transform.js":34,"readable-stream/writable.js":35}],37:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Buffer = require('buffer').Buffer; + +var isBufferEncoding = Buffer.isEncoding + || function(encoding) { + switch (encoding && encoding.toLowerCase()) { + case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; + default: return false; + } + } + + +function assertEncoding(encoding) { + if (encoding && !isBufferEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); + } +} + +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. CESU-8 is handled as part of the UTF-8 encoding. +// +// @TODO Handling all encodings inside a single object makes it very difficult +// to reason about this code, so it should be split up in the future. +// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code +// points as used by CESU-8. +var StringDecoder = exports.StringDecoder = function(encoding) { + this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); + assertEncoding(encoding); + switch (this.encoding) { + case 'utf8': + // CESU-8 represents each of Surrogate Pair by 3-bytes + this.surrogateSize = 3; + break; + case 'ucs2': + case 'utf16le': + // UTF-16 represents each of Surrogate Pair by 2-bytes + this.surrogateSize = 2; + this.detectIncompleteChar = utf16DetectIncompleteChar; + break; + case 'base64': + // Base-64 stores 3 bytes in 4 chars, and pads the remainder. + this.surrogateSize = 3; + this.detectIncompleteChar = base64DetectIncompleteChar; + break; + default: + this.write = passThroughWrite; + return; + } + + // Enough space to store all bytes of a single character. UTF-8 needs 4 + // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). + this.charBuffer = new Buffer(6); + // Number of bytes received for the current incomplete multi-byte character. + this.charReceived = 0; + // Number of bytes expected for the current incomplete multi-byte character. + this.charLength = 0; +}; + + +// write decodes the given buffer and returns it as JS string that is +// guaranteed to not contain any partial multi-byte characters. Any partial +// character found at the end of the buffer is buffered up, and will be +// returned when calling write again with the remaining bytes. +// +// Note: Converting a Buffer containing an orphan surrogate to a String +// currently works, but converting a String to a Buffer (via `new Buffer`, or +// Buffer#write) will replace incomplete surrogates with the unicode +// replacement character. See https://codereview.chromium.org/121173009/ . +StringDecoder.prototype.write = function(buffer) { + var charStr = ''; + // if our last write ended with an incomplete multibyte character + while (this.charLength) { + // determine how many remaining bytes this buffer has to offer for this char + var available = (buffer.length >= this.charLength - this.charReceived) ? + this.charLength - this.charReceived : + buffer.length; + + // add the new bytes to the char buffer + buffer.copy(this.charBuffer, this.charReceived, 0, available); + this.charReceived += available; + + if (this.charReceived < this.charLength) { + // still not enough chars in this buffer? wait for more ... + return ''; + } + + // remove bytes belonging to the current character from the buffer + buffer = buffer.slice(available, buffer.length); + + // get the character that was split + charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); + + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + var charCode = charStr.charCodeAt(charStr.length - 1); + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + this.charLength += this.surrogateSize; + charStr = ''; + continue; + } + this.charReceived = this.charLength = 0; + + // if there are no more bytes in this buffer, just emit our char + if (buffer.length === 0) { + return charStr; + } + break; + } + + // determine and set charLength / charReceived + this.detectIncompleteChar(buffer); + + var end = buffer.length; + if (this.charLength) { + // buffer the incomplete character bytes we got + buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); + end -= this.charReceived; + } + + charStr += buffer.toString(this.encoding, 0, end); + + var end = charStr.length - 1; + var charCode = charStr.charCodeAt(end); + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + var size = this.surrogateSize; + this.charLength += size; + this.charReceived += size; + this.charBuffer.copy(this.charBuffer, size, 0, size); + buffer.copy(this.charBuffer, 0, 0, size); + return charStr.substring(0, end); + } + + // or just emit the charStr + return charStr; +}; + +// detectIncompleteChar determines if there is an incomplete UTF-8 character at +// the end of the given buffer. If so, it sets this.charLength to the byte +// length that character, and sets this.charReceived to the number of bytes +// that are available for this character. +StringDecoder.prototype.detectIncompleteChar = function(buffer) { + // determine how many bytes we have to check at the end of this buffer + var i = (buffer.length >= 3) ? 3 : buffer.length; + + // Figure out if one of the last i bytes of our buffer announces an + // incomplete char. + for (; i > 0; i--) { + var c = buffer[buffer.length - i]; + + // See http://en.wikipedia.org/wiki/UTF-8#Description + + // 110XXXXX + if (i == 1 && c >> 5 == 0x06) { + this.charLength = 2; + break; + } + + // 1110XXXX + if (i <= 2 && c >> 4 == 0x0E) { + this.charLength = 3; + break; + } + + // 11110XXX + if (i <= 3 && c >> 3 == 0x1E) { + this.charLength = 4; + break; + } + } + this.charReceived = i; +}; + +StringDecoder.prototype.end = function(buffer) { + var res = ''; + if (buffer && buffer.length) + res = this.write(buffer); + + if (this.charReceived) { + var cr = this.charReceived; + var buf = this.charBuffer; + var enc = this.encoding; + res += buf.slice(0, cr).toString(enc); + } + + return res; +}; + +function passThroughWrite(buffer) { + return buffer.toString(this.encoding); +} + +function utf16DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 2; + this.charLength = this.charReceived ? 2 : 0; +} + +function base64DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 3; + this.charLength = this.charReceived ? 3 : 0; +} + +},{"buffer":17}],38:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],39:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":38,"_process":24,"inherits":22}],40:[function(require,module,exports){ +(function (global){ +/** + * @license + * lodash 3.1.0 (Custom Build) + * Build: `lodash modern -d -o ./index.js` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.7.0 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '3.1.0'; + + /** Used to compose bitmasks for wrapper metadata. */ + var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + CURRY_BOUND_FLAG = 4, + CURRY_FLAG = 8, + CURRY_RIGHT_FLAG = 16, + PARTIAL_FLAG = 32, + PARTIAL_RIGHT_FLAG = 64, + REARG_FLAG = 128, + ARY_FLAG = 256; + + /** Used as default options for `_.trunc`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect when a function becomes hot. */ + var HOT_COUNT = 150, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 0, + LAZY_MAP_FLAG = 1, + LAZY_WHILE_FLAG = 2; + + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + + var arrayBufferTag = '[object ArrayBuffer]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, + reUnescapedHtml = /[&<>"'`]/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** + * Used to match ES template delimiters. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components) + * for more details. + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect named functions. */ + var reFuncName = /^\s*function[ \n\r\t]+\w/; + + /** Used to detect hexadecimal string values. */ + var reHexPrefix = /^0[xX]/; + + /** Used to detect host constructors (Safari > 5). */ + var reHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ + var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** + * Used to match `RegExp` special characters. + * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special) + * for more details. + */ + var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + + /** Used to detect functions containing a `this` reference. */ + var reThis = /\bthis\b/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to match words to create compound words. */ + var reWords = (function() { + var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', + lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; + + return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); + }()); + + /** Used to detect and test for whitespace. */ + var whitespace = ( + // Basic whitespace characters. + ' \t\x0b\f\xa0\ufeff' + + + // Line terminators. + '\n\r\u2028\u2029' + + + // Unicode category "Zs" space separators. + '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' + ); + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', + 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document', + 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + 'window', 'WinRTError' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dateTag] = typedArrayTags[errorTag] = + typedArrayTags[funcTag] = typedArrayTags[mapTag] = + typedArrayTags[numberTag] = typedArrayTags[objectTag] = + typedArrayTags[regexpTag] = typedArrayTags[setTag] = + typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = + cloneableTags[dateTag] = cloneableTags[float32Tag] = + cloneableTags[float64Tag] = cloneableTags[int8Tag] = + cloneableTags[int16Tag] = cloneableTags[int32Tag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[stringTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[mapTag] = cloneableTags[setTag] = + cloneableTags[weakMapTag] = false; + + /** Used as an internal `_.debounce` options object by `_.throttle`. */ + var debounceOptions = { + 'leading': false, + 'maxWait': 0, + 'trailing': false + }; + + /** Used to map latin-1 supplementary letters to basic latin letters. */ + var deburredLetters = { + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '`': '`' + }; + + /** Used to determine if values are of the language type `Object`. */ + var objectTypes = { + 'function': true, + 'object': true + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** + * Used as a reference to the global object. + * + * The `this` value is used if it is the global object to avoid Greasemonkey's + * restricted `window` object, otherwise the `window` object is used. + */ + var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this; + + /** Detect free variable `exports`. */ + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */ + var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { + root = freeGlobal; + } + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + + /*--------------------------------------------------------------------------*/ + + /** + * The base implementation of `compareAscending` which compares values and + * sorts them in ascending order without guaranteeing a stable sort. + * + * @private + * @param {*} value The value to compare to `other`. + * @param {*} other The value to compare to `value`. + * @returns {number} Returns the sort order indicator for `value`. + */ + function baseCompareAscending(value, other) { + if (value !== other) { + var valIsReflexive = value === value, + othIsReflexive = other === other; + + if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) { + return 1; + } + if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) { + return -1; + } + } + return 0; + } + + /** + * The base implementation of `_.indexOf` without support for binary searches. + * + * @private + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return indexOfNaN(array, fromIndex); + } + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer` + * to define the sort order of `array` and replaces criteria objects with their + * corresponding values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * Converts `value` to a string if it is not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); + } + + /** + * Used by `_.max` and `_.min` as the default callback for string values. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the code unit of the first character of the string. + */ + function charAtCallback(string) { + return string.charCodeAt(0); + } + + /** + * Used by `_.trim` and `_.trimLeft` to get the index of the first character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the first character not found in `chars`. + */ + function charsLeftIndex(string, chars) { + var index = -1, + length = string.length; + + while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimRight` to get the index of the last character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the last character not found in `chars`. + */ + function charsRightIndex(string, chars) { + var index = string.length; + + while (index-- && chars.indexOf(string.charAt(index)) > -1) {} + return index; + } + + /** + * Used by `_.sortBy` to compare transformed elements of a collection and stable + * sort them in ascending order. + * + * @private + * @param {Object} object The object to compare to `other`. + * @param {Object} other The object to compare to `object`. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareAscending(object, other) { + return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); + } + + /** + * Used by `_.sortByAll` to compare multiple properties of each element + * in a collection and stable sort them in ascending order. + * + * @private + * @param {Object} object The object to compare to `other`. + * @param {Object} other The object to compare to `object`. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultipleAscending(object, other) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length; + + while (++index < length) { + var result = baseCompareAscending(objCriteria[index], othCriteria[index]); + if (result) { + return result; + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://code.google.com/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + function deburrLetter(letter) { + return deburredLetters[letter]; + } + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeHtmlChar(chr) { + return htmlEscapes[chr]; + } + + /** + * Used by `_.template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the index at which the first occurrence of `NaN` is found in `array`. + * If `fromRight` is provided elements of `array` are iterated from right to left. + * + * @private + * @param {Array} array The array to search. + * @param {number} [fromIndex] The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched `NaN`, else `-1`. + */ + function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1); + + while ((fromRight ? index-- : ++index < length)) { + var other = array[index]; + if (other !== other) { + return index; + } + } + return -1; + } + + /** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ + function isObjectLike(value) { + return (value && typeof value == 'object') || false; + } + + /** + * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a + * character code is whitespace. + * + * @private + * @param {number} charCode The character code to inspect. + * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. + */ + function isSpace(charCode) { + return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 || + (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + if (array[index] === placeholder) { + array[index] = PLACEHOLDER; + result[++resIndex] = index; + } + } + return result; + } + + /** + * An implementation of `_.uniq` optimized for sorted arrays without support + * for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ + function sortedUniq(array, iteratee) { + var seen, + index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (!index || seen !== computed) { + seen = computed; + result[++resIndex] = value; + } + } + return result; + } + + /** + * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the first non-whitespace character. + */ + function trimmedLeftIndex(string) { + var index = -1, + length = string.length; + + while (++index < length && isSpace(string.charCodeAt(index))) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ + function trimmedRightIndex(string) { + var index = string.length; + + while (index-- && isSpace(string.charCodeAt(index))) {} + return index; + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + function unescapeHtmlChar(chr) { + return htmlUnescapes[chr]; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the given `context` object. + * + * @static + * @memberOf _ + * @category Utility + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'add': function(a, b) { return a + b; } }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'sub': function(a, b) { return a - b; } }); + * + * _.isFunction(_.add); + * // => true + * _.isFunction(_.sub); + * // => false + * + * lodash.isFunction(lodash.add); + * // => false + * lodash.isFunction(lodash.sub); + * // => true + * + * // using `context` to mock `Date#getTime` use in `_.now` + * var mock = _.runInContext({ + * 'Date': function() { + * return { 'getTime': getTimeMock }; + * } + * }); + * + * // or creating a suped-up `defer` in Node.js + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + function runInContext(context) { + // Avoid issues with some ES3 environments that attempt to use values, named + // after built-in constructors like `Object`, for the creation of literals. + // ES5 clears this up by stating that literals must use built-in constructors. + // See https://es5.github.io/#x11.1.5 for more details. + context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; + + /** Native constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Number = context.Number, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for native method references. */ + var arrayProto = Array.prototype, + objectProto = Object.prototype; + + /** Used to detect DOM support. */ + var document = (document = context.window) && document.document; + + /** Used to resolve the decompiled source of functions. */ + var fnToString = Function.prototype.toString; + + /** Used to the length of n-tuples for `_.unzip`. */ + var getLength = baseProperty('length'); + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ + var objToString = objectProto.toString; + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = context._; + + /** Used to detect if a method is native. */ + var reNative = RegExp('^' + + escapeRegExp(objToString) + .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Native method references. */ + var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer, + bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice, + ceil = Math.ceil, + clearTimeout = context.clearTimeout, + floor = Math.floor, + getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, + push = arrayProto.push, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + Set = isNative(Set = context.Set) && Set, + setTimeout = context.setTimeout, + splice = arrayProto.splice, + Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array, + unshift = arrayProto.unshift, + WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap; + + /** Used to clone array buffers. */ + var Float64Array = (function() { + // Safari 5 errors when using an array buffer to initialize a typed array + // where the array buffer's `byteLength` is not a multiple of the typed + // array's `BYTES_PER_ELEMENT`. + try { + var func = isNative(func = context.Float64Array) && func, + result = new func(new ArrayBuffer(10), 0, 1) && func; + } catch(e) {} + return result; + }()); + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, + nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, + nativeIsFinite = context.isFinite, + nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = isNative(nativeNow = Date.now) && nativeNow, + nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite, + nativeParseInt = context.parseInt, + nativeRandom = Math.random; + + /** Used as references for `-Infinity` and `Infinity`. */ + var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, + POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used as the size, in bytes, of each `Float64Array` element. */ + var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; + + /** + * Used as the maximum length of an array-like value. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * for more details. + */ + var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable intuitive chaining. + * Methods that operate on and return arrays, collections, and functions can + * be chained together. Methods that return a boolean or single value will + * automatically end the chain returning the unwrapped value. Explicit chaining + * may be enabled using `_.chain`. The execution of chained methods is lazy, + * that is, execution is deferred until `_#value` is implicitly or explicitly + * called. + * + * Lazy evaluation allows several methods to support shortcut fusion. Shortcut + * fusion is an optimization that merges iteratees to avoid creating intermediate + * arrays and reduce the number of iteratee executions. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers also have the following `Array` methods: + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, + * and `unshift` + * + * The wrapper functions that support shortcut fusion are: + * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`, + * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where` + * + * The chainable wrapper functions are: + * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, + * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`, + * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`, + * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`, + * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, + * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`, + * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`, + * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`, + * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`, + * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`, + * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, + * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`, + * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, + * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`, + * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject` + * + * The wrapper functions that are **not** chainable by default are: + * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`, + * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, + * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`, + * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, + * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`, + * `isFunction`, `isMatch`, `isNative`, `isNaN`, `isNull`, `isNumber`, + * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, + * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`, + * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, + * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`, + * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, + * `startCase`, `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, + * `trunc`, `unescape`, `uniqueId`, `value`, and `words` + * + * The wrapper function `sample` will return a wrapped value when `n` is provided, + * otherwise an unwrapped value is returned. + * + * @name _ + * @constructor + * @category Chain + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + * @example + * + * var wrapped = _([1, 2, 3]); + * + * // returns an unwrapped value + * wrapped.reduce(function(sum, n) { return sum + n; }); + * // => 6 + * + * // returns a wrapped value + * var squares = wrapped.map(function(n) { return n * n; }); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__)); + } + } + return new LodashWrapper(value); + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable chaining for all wrapper methods. + * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. + */ + function LodashWrapper(value, chainAll, actions) { + this.__actions__ = actions || []; + this.__chain__ = !!chainAll; + this.__wrapped__ = value; + } + + /** + * An object environment feature flags. + * + * @static + * @memberOf _ + * @type Object + */ + var support = lodash.support = {}; + + (function(x) { + + /** + * Detect if functions can be decompiled by `Function#toString` + * (all but Firefox OS certified apps, older Opera mobile browsers, and + * the PlayStation 3; forced `false` for Windows 8 apps). + * + * @memberOf _.support + * @type boolean + */ + support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext); + + /** + * Detect if `Function#name` is supported (all but IE). + * + * @memberOf _.support + * @type boolean + */ + support.funcNames = typeof Function.name == 'string'; + + /** + * Detect if the DOM is supported. + * + * @memberOf _.support + * @type boolean + */ + try { + support.dom = document.createDocumentFragment().nodeType === 11; + } catch(e) { + support.dom = false; + } + + /** + * Detect if `arguments` object indexes are non-enumerable. + * + * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object + * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat + * `arguments` object indexes as non-enumerable and fail `hasOwnProperty` + * checks for indexes that exceed their function's formal parameters with + * associated values of `0`. + * + * @memberOf _.support + * @type boolean + */ + try { + support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1); + } catch(e) { + support.nonEnumArgs = true; + } + }(0, 0)); + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB). Change the following template settings to use + * alternative delimiters. + * + * @static + * @memberOf _ + * @type Object + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type string + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type Object + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type Function + */ + '_': lodash + } + }; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.actions = null; + this.dir = 1; + this.dropCount = 0; + this.filtered = false; + this.iteratees = null; + this.takeCount = POSITIVE_INFINITY; + this.views = null; + this.wrapped = value; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var actions = this.actions, + iteratees = this.iteratees, + views = this.views, + result = new LazyWrapper(this.wrapped); + + result.actions = actions ? arrayCopy(actions) : null; + result.dir = this.dir; + result.dropCount = this.dropCount; + result.filtered = this.filtered; + result.iteratees = iteratees ? arrayCopy(iteratees) : null; + result.takeCount = this.takeCount; + result.views = views ? arrayCopy(views) : null; + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.filtered) { + var result = new LazyWrapper(this); + result.dir = -1; + result.filtered = true; + } else { + result = this.clone(); + result.dir *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.wrapped.value(); + if (!isArray(array)) { + return baseWrapperValue(array, this.actions); + } + var dir = this.dir, + isRight = dir < 0, + view = getView(0, array.length, this.views), + start = view.start, + end = view.end, + length = end - start, + dropCount = this.dropCount, + takeCount = nativeMin(length, this.takeCount - dropCount), + index = isRight ? end : start - 1, + iteratees = this.iteratees, + iterLength = iteratees ? iteratees.length : 0, + resIndex = 0, + result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + computed = iteratee(value, index, array), + type = data.type; + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + if (dropCount) { + dropCount--; + } else { + result[resIndex++] = value; + } + } + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a cache object to store key/value pairs. + * + * @private + * @static + * @name Cache + * @memberOf _.memoize + */ + function MapCache() { + this.__data__ = {}; + } + + /** + * Removes `key` and its value from the cache. + * + * @private + * @name delete + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. + */ + function mapDelete(key) { + return this.has(key) && delete this.__data__[key]; + } + + /** + * Gets the cached value for `key`. + * + * @private + * @name get + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to get. + * @returns {*} Returns the cached value. + */ + function mapGet(key) { + return key == '__proto__' ? undefined : this.__data__[key]; + } + + /** + * Checks if a cached value for `key` exists. + * + * @private + * @name has + * @memberOf _.memoize.Cache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapHas(key) { + return key != '__proto__' && hasOwnProperty.call(this.__data__, key); + } + + /** + * Adds `value` to `key` of the cache. + * + * @private + * @name set + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to cache. + * @param {*} value The value to cache. + * @returns {Object} Returns the cache object. + */ + function mapSet(key, value) { + if (key != '__proto__') { + this.__data__[key] = value; + } + return this; + } + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates a cache object to store unique values. + * + * @private + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var length = values ? values.length : 0; + + this.data = { 'hash': nativeCreate(null), 'set': new Set }; + while (length--) { + this.push(values[length]); + } + } + + /** + * Checks if `value` is in `cache` mimicking the return signature of + * `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache to search. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var data = cache.data, + result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; + + return result ? 0 : -1; + } + + /** + * Adds `value` to the cache. + * + * @private + * @name push + * @memberOf SetCache + * @param {*} value The value to cache. + */ + function cachePush(value) { + var data = this.data; + if (typeof value == 'string' || isObject(value)) { + data.set.add(value); + } else { + data.hash[value] = true; + } + } + + /*------------------------------------------------------------------------*/ + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function arrayCopy(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * callback shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[++resIndex] = value; + } + } + return result; + } + + /** + * A specialized version of `_.map` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * A specialized version of `_.max` for arrays without support for iteratees. + * + * @private + * @param {Array} array The array to iterate over. + * @returns {*} Returns the maximum value. + */ + function arrayMax(array) { + var index = -1, + length = array.length, + result = NEGATIVE_INFINITY; + + while (++index < length) { + var value = array[index]; + if (value > result) { + result = value; + } + } + return result; + } + + /** + * A specialized version of `_.min` for arrays without support for iteratees. + * + * @private + * @param {Array} array The array to iterate over. + * @returns {*} Returns the minimum value. + */ + function arrayMin(array) { + var index = -1, + length = array.length, + result = POSITIVE_INFINITY; + + while (++index < length) { + var value = array[index]; + if (value < result) { + result = value; + } + } + return result; + } + + /** + * A specialized version of `_.reduce` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initFromArray) { + var index = -1, + length = array.length; + + if (initFromArray && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * callback shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the last element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initFromArray) { + var length = array.length; + if (initFromArray && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignDefaults(objectValue, sourceValue) { + return typeof objectValue == 'undefined' ? sourceValue : objectValue; + } + + /** + * Used by `_.template` to customize its `_.assign` use. + * + * **Note:** This method is like `assignDefaults` except that it ignores + * inherited property values when checking if a property is `undefined`. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @param {string} key The key associated with the object and source values. + * @param {Object} object The destination object. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignOwnDefaults(objectValue, sourceValue, key, object) { + return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key)) + ? sourceValue + : objectValue; + } + + /** + * The base implementation of `_.assign` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize assigning values. + * @returns {Object} Returns the destination object. + */ + function baseAssign(object, source, customizer) { + var props = keys(source); + if (!customizer) { + return baseCopy(source, object, props); + } + var index = -1, + length = props.length + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ((result === result ? result !== value : value === value) || + (typeof value == 'undefined' && !(key in object))) { + object[key] = result; + } + } + return object; + } + + /** + * The base implementation of `_.at` without support for strings and individual + * key arguments. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {number[]|string[]} [props] The property names or indexes of elements to pick. + * @returns {Array} Returns the new array of picked elements. + */ + function baseAt(collection, props) { + var index = -1, + length = collection.length, + isArr = isLength(length), + propsLength = props.length, + result = Array(propsLength); + + while(++index < propsLength) { + var key = props[index]; + if (isArr) { + key = parseFloat(key); + result[index] = isIndex(key, length) ? collection[key] : undefined; + } else { + result[index] = collection[key]; + } + } + return result; + } + + /** + * Copies the properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Object} [object={}] The object to copy properties to. + * @param {Array} props The property names to copy. + * @returns {Object} Returns `object`. + */ + function baseCopy(source, object, props) { + if (!props) { + props = object; + object = {}; + } + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; + } + return object; + } + + /** + * The base implementation of `_.bindAll` without support for individual + * method name arguments. + * + * @private + * @param {Object} object The object to bind and assign the bound methods to. + * @param {string[]} methodNames The object method names to bind. + * @returns {Object} Returns `object`. + */ + function baseBindAll(object, methodNames) { + var index = -1, + length = methodNames.length; + + while (++index < length) { + var key = methodNames[index]; + object[key] = createWrapper(object[key], BIND_FLAG, object); + } + return object; + } + + /** + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return (typeof thisArg != 'undefined' && isBindable(func)) + ? bindCallback(func, thisArg, argCount) + : func; + } + if (func == null) { + return identity; + } + // Handle "_.property" and "_.matches" style callback shorthands. + return type == 'object' + ? baseMatches(func) + : baseProperty(func + ''); + } + + /** + * The base implementation of `_.clone` without support for argument juggling + * and `this` binding `customizer` functions. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The object `value` belongs to. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { + var result; + if (customizer) { + result = object ? customizer(value, key, object) : customizer(value); + } + if (typeof result != 'undefined') { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return arrayCopy(value, result); + } + } else { + var tag = objToString.call(value), + isFunc = tag == funcTag; + + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = initCloneObject(isFunc ? {} : value); + if (!isDeep) { + return baseCopy(value, result, keys(value)); + } + } else { + return cloneableTags[tag] + ? initCloneByTag(value, tag, isDeep) + : (object ? value : {}); + } + } + // Check for circular references and return corresponding clone. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; + } + } + // Add the source value to the stack of traversed objects and associate it with its clone. + stackA.push(value); + stackB.push(result); + + // Recursively populate clone (susceptible to call stack limits). + (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { + result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); + }); + return result; + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function Object() {} + return function(prototype) { + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || context.Object(); + }; + }()); + + /** + * The base implementation of `_.delay` and `_.defer` which accepts an index + * of where to slice the arguments to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Object} args The `arguments` object to slice and provide to `func`. + * @returns {number} Returns the timer id. + */ + function baseDelay(func, wait, args, fromIndex) { + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait); + } + + /** + * The base implementation of `_.difference` which accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values) { + var length = array ? array.length : 0, + result = []; + + if (!length) { + return result; + } + var index = -1, + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf, + cache = isCommon && values.length >= 200 && createCache(values), + valuesLength = values.length; + + if (cache) { + indexOf = cacheIndexOf; + isCommon = false; + values = cache; + } + outer: + while (++index < length) { + var value = array[index]; + + if (isCommon && value === value) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === value) { + continue outer; + } + } + result.push(value); + } + else if (indexOf(values, value) < 0) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ + function baseEach(collection, iteratee) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + return baseForOwn(collection, iteratee); + } + var index = -1, + iterable = toObject(collection); + + while (++index < length) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + } + + /** + * The base implementation of `_.forEachRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ + function baseEachRight(collection, iteratee) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + return baseForOwnRight(collection, iteratee); + } + var iterable = toObject(collection); + while (length--) { + if (iteratee(iterable[length], length, iterable) === false) { + break; + } + } + return collection; + } + + /** + * The base implementation of `_.every` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of `_.filter` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, + * without support for callback shorthands and `this` binding, which iterates + * over `collection` using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to search. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @param {boolean} [retKey] Specify returning the key of the found element + * instead of the element itself. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFind(collection, predicate, eachFunc, retKey) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = retKey ? key : value; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with added support for restricting + * flattening and specifying the start index. + * + * @private + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects. + * @param {number} [fromIndex=0] The index to start from. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, isDeep, isStrict, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + + if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) { + if (isDeep) { + // Recursively flatten arrays (susceptible to call stack limits). + value = baseFlatten(value, isDeep, isStrict); + } + var valIndex = -1, + valLength = value.length; + + result.length += valLength; + while (++valIndex < valLength) { + result[++resIndex] = value[valIndex]; + } + } else if (!isStrict) { + result[++resIndex] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iterator functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + function baseFor(object, iteratee, keysFunc) { + var index = -1, + iterable = toObject(object), + props = keysFunc(object), + length = props.length; + + while (++index < length) { + var key = props[index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + } + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + function baseForRight(object, iteratee, keysFunc) { + var iterable = toObject(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[length]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + } + + /** + * The base implementation of `_.forIn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForIn(object, iteratee) { + return baseFor(object, iteratee, keysIn); + } + + /** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from those provided. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the new array of filtered property names. + */ + function baseFunctions(object, props) { + var index = -1, + length = props.length, + resIndex = -1, + result = []; + + while (++index < length) { + var key = props[index]; + if (isFunction(object[key])) { + result[++resIndex] = key; + } + } + return result; + } + + /** + * The base implementation of `_.invoke` which requires additional arguments + * to be provided as an array of arguments rather than individually. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|string} methodName The name of the method to invoke or + * the function invoked per iteration. + * @param {Array} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + */ + function baseInvoke(collection, methodName, args) { + var index = -1, + isFunc = typeof methodName == 'function', + length = collection ? collection.length : 0, + result = isLength(length) ? Array(length) : []; + + baseEach(collection, function(value) { + var func = isFunc ? methodName : (value != null && value[methodName]); + result[++index] = func ? func.apply(value, args) : undefined; + }); + return result; + } + + /** + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) { + // Exit early for identical values. + if (value === other) { + // Treat `+0` vs. `-0` as not equal. + return value !== 0 || (1 / value == 1 / other); + } + var valType = typeof value, + othType = typeof other; + + // Exit early for unlike primitive values. + if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') || + value == null || other == null) { + // Return `false` unless both values are `NaN`. + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = arrayTag, + othTag = arrayTag; + + if (!objIsArr) { + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } + } + if (!othIsArr) { + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } + } + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); + } + var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (valWrapped || othWrapped) { + return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB); + } + if (!isSameTag) { + return false; + } + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB); + + stackA.pop(); + stackB.pop(); + + return result; + } + + /** + * The base implementation of `_.isMatch` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Object} source The object to inspect. + * @param {Array} props The source property names to match. + * @param {Array} values The source values to match. + * @param {Array} strictCompareFlags Strict comparison flags for source values. + * @param {Function} [customizer] The function to customize comparing objects. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, props, values, strictCompareFlags, customizer) { + var length = props.length; + if (object == null) { + return !length; + } + var index = -1, + noCustomizer = !customizer; + + while (++index < length) { + if ((noCustomizer && strictCompareFlags[index]) + ? values[index] !== object[props[index]] + : !hasOwnProperty.call(object, props[index]) + ) { + return false; + } + } + index = -1; + while (++index < length) { + var key = props[index]; + if (noCustomizer && strictCompareFlags[index]) { + var result = hasOwnProperty.call(object, key); + } else { + var objValue = object[key], + srcValue = values[index]; + + result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (typeof result == 'undefined') { + result = baseIsEqual(srcValue, objValue, customizer, true); + } + } + if (!result) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.map` without support for callback shorthands + * or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var result = []; + baseEach(collection, function(value, key, collection) { + result.push(iteratee(value, key, collection)); + }); + return result; + } + + /** + * The base implementation of `_.matches` which supports specifying whether + * `source` should be cloned. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new function. + */ + function baseMatches(source) { + var props = keys(source), + length = props.length; + + if (length == 1) { + var key = props[0], + value = source[key]; + + if (isStrictComparable(value)) { + return function(object) { + return object != null && value === object[key] && hasOwnProperty.call(object, key); + }; + } + } + var values = Array(length), + strictCompareFlags = Array(length); + + while (length--) { + value = source[props[length]]; + values[length] = value; + strictCompareFlags[length] = isStrictComparable(value); + } + return function(object) { + return baseIsMatch(object, props, values, strictCompareFlags); + }; + } + + /** + * The base implementation of `_.merge` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {Object} Returns the destination object. + */ + function baseMerge(object, source, customizer, stackA, stackB) { + var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source)); + + (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + } + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = typeof result == 'undefined'; + + if (isCommon) { + result = srcValue; + } + if ((isSrcArr || typeof result != 'undefined') && + (isCommon || (result === result ? result !== value : value === value))) { + object[key] = result; + } + }); + return object; + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { + var length = stackA.length, + srcValue = source[key]; + + while (length--) { + if (stackA[length] == srcValue) { + object[key] = stackB[length]; + return; + } + } + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = typeof result == 'undefined'; + + if (isCommon) { + result = srcValue; + if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) { + result = isArray(value) + ? value + : (value ? arrayCopy(value) : []); + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + result = isArguments(value) + ? toPlainObject(value) + : (isPlainObject(value) ? value : {}); + } + else { + isCommon = false; + } + } + // Add the source value to the stack of traversed objects and associate + // it with its merged value. + stackA.push(srcValue); + stackB.push(result); + + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); + } else if (result === result ? result !== value : value === value) { + object[key] = result; + } + } + + /** + * The base implementation of `_.property` which does not coerce `key` to a string. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * index arguments. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + */ + function basePullAt(array, indexes) { + var length = indexes.length, + result = baseAt(array, indexes); + + indexes.sort(baseCompareAscending); + while (length--) { + var index = parseFloat(indexes[length]); + if (index != previous && isIndex(index)) { + var previous = index; + splice.call(array, index, 1); + } + } + return result; + } + + /** + * The base implementation of `_.random` without support for argument juggling + * and returning floating-point numbers. + * + * @private + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} Returns the random number. + */ + function baseRandom(min, max) { + return min + floor(nativeRandom() * (max - min + 1)); + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight` without support + * for callback shorthands or `this` binding, which iterates over `collection` + * using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initFromCollection Specify using the first or last element + * of `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initFromCollection + ? (initFromCollection = false, value) + : iteratee(accumulator, value, index, collection) + }); + return accumulator; + } + + /** + * The base implementation of `setData` without support for hot loop detection. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + start = start == null ? 0 : (+start || 0); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (typeof end == 'undefined' || end > length) ? length : (+end || 0); + if (end < 0) { + end += length; + } + length = start > end ? 0 : (end - start) >>> 0; + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for callback shorthands + * or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.uniq` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ + function baseUniq(array, iteratee) { + var index = -1, + indexOf = getIndexOf(), + length = array.length, + isCommon = indexOf == baseIndexOf, + isLarge = isCommon && length >= 200, + seen = isLarge && createCache(), + result = []; + + if (seen) { + indexOf = cacheIndexOf; + isCommon = false; + } else { + isLarge = false; + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (isCommon && value === value) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (indexOf(seen, computed) < 0) { + if (iteratee || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * returned by `keysFunc`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + var index = -1, + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to peform to resolve the unwrapped value. + * @returns {*} Returns the resolved unwrapped value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + var index = -1, + length = actions.length; + + while (++index < length) { + var args = [result], + action = actions[index]; + + push.apply(args, action.args); + result = action.func.apply(action.thisArg, args); + } + return result; + } + + /** + * Performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest, instead + * of the lowest, index at which a value should be inserted into `array`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndex(array, value, retHighest) { + var low = 0, + high = array ? array.length : low; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (retHighest ? (computed <= value) : (computed < value)) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return binaryIndexBy(array, value, identity, retHighest); + } + + /** + * This function is like `binaryIndex` except that it invokes `iteratee` for + * `value` and each element of `array` to compute their sort ranking. The + * iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [retHighest] Specify returning the highest, instead + * of the lowest, index at which a value should be inserted into `array`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array ? array.length : 0, + valIsNaN = value !== value, + valIsUndef = typeof value == 'undefined'; + + while (low < high) { + var mid = floor((low + high) / 2), + computed = iteratee(array[mid]), + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || typeof computed != 'undefined'); + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (typeof thisArg == 'undefined') { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; + } + + /** + * Creates a clone of the given array buffer. + * + * @private + * @param {ArrayBuffer} buffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function bufferClone(buffer) { + return bufferSlice.call(buffer, 0); + } + if (!bufferSlice) { + // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`. + bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) { + var byteLength = buffer.byteLength, + floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, + offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, + result = new ArrayBuffer(byteLength); + + if (floatLength) { + var view = new Float64Array(result, 0, floatLength); + view.set(new Float64Array(buffer, 0, floatLength)); + } + if (byteLength != offset) { + view = new Uint8Array(result, offset); + view.set(new Uint8Array(buffer, offset)); + } + return result; + }; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders) { + var holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + leftIndex = -1, + leftLength = partials.length, + result = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + while (argsLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders) { + var holdersIndex = -1, + holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + rightIndex = -1, + rightLength = partials.length, + result = Array(argsLength + rightLength); + + while (++argsIndex < argsLength) { + result[argsIndex] = args[argsIndex]; + } + var pad = argsIndex; + while (++rightIndex < rightLength) { + result[pad + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + result[pad + holders[holdersIndex]] = args[argsIndex++]; + } + return result; + } + + /** + * Creates a function that aggregates a collection, creating an accumulator + * object composed from the results of running each element in the collection + * through an iteratee. The `setter` sets the keys and values of the accumulator + * object. If `initializer` is provided initializes the accumulator object. + * + * @private + * @param {Function} setter The function to set keys and values of the accumulator object. + * @param {Function} [initializer] The function to initialize the accumulator object. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee, thisArg) { + var result = initializer ? initializer() : {}; + iteratee = getCallback(iteratee, thisArg, 3); + + if (isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + setter(result, value, iteratee(value, index, collection), collection); + } + } else { + baseEach(collection, function(value, key, collection) { + setter(result, value, iteratee(value, key, collection), collection); + }); + } + return result; + }; + } + + /** + * Creates a function that assigns properties of source object(s) to a given + * destination object. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return function() { + var length = arguments.length, + object = arguments[0]; + + if (length < 2 || object == null) { + return object; + } + if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) { + length = 2; + } + // Juggle arguments. + if (length > 3 && typeof arguments[length - 2] == 'function') { + var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5); + } else if (length > 2 && typeof arguments[length - 1] == 'function') { + customizer = arguments[--length]; + } + var index = 0; + while (++index < length) { + var source = arguments[index]; + if (source) { + assigner(object, source, customizer); + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` and invokes it with the `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new bound function. + */ + function createBindWrapper(func, thisArg) { + var Ctor = createCtorWrapper(func); + + function wrapper() { + return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments); + } + return wrapper; + } + + /** + * Creates a `Set` cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [values] The values to cache. + * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. + */ + var createCache = !(nativeCreate && Set) ? constant(null) : function(values) { + return new SetCache(values); + }; + + /** + * Creates a function that produces compound words out of the words in a + * given string. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + var index = -1, + array = words(deburr(string)), + length = array.length, + result = ''; + + while (++index < length) { + result = callback(result, array[index], index); + } + return result; + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtorWrapper(Ctor) { + return function() { + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, arguments); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that gets the extremum value of a collection. + * + * @private + * @param {Function} arrayFunc The function to get the extremum value from an array. + * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum, + * extremum value. + * @returns {Function} Returns the new extremum function. + */ + function createExtremum(arrayFunc, isMin) { + return function(collection, iteratee, thisArg) { + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = null; + } + var func = getCallback(), + noIteratee = iteratee == null; + + if (!(func === baseCallback && noIteratee)) { + noIteratee = false; + iteratee = func(iteratee, thisArg, 3); + } + if (noIteratee) { + var isArr = isArray(collection); + if (!isArr && isString(collection)) { + iteratee = charAtCallback; + } else { + return arrayFunc(isArr ? collection : toIterable(collection)); + } + } + return extremumBy(collection, iteratee, isMin); + }; + } + + /** + * Creates a function that wraps `func` and invokes it with optional `this` + * binding of, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & ARY_FLAG, + isBind = bitmask & BIND_FLAG, + isBindKey = bitmask & BIND_KEY_FLAG, + isCurry = bitmask & CURRY_FLAG, + isCurryBound = bitmask & CURRY_BOUND_FLAG, + isCurryRight = bitmask & CURRY_RIGHT_FLAG; + + var Ctor = !isBindKey && createCtorWrapper(func), + key = func; + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it to other functions. + var length = arguments.length, + index = length, + args = Array(length); + + while (index--) { + args[index] = arguments[index]; + } + if (partials) { + args = composeArgs(args, partials, holders); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight); + } + if (isCurry || isCurryRight) { + var placeholder = wrapper.placeholder, + argsHolders = replaceHolders(args, placeholder); + + length -= argsHolders.length; + if (length < arity) { + var newArgPos = argPos ? arrayCopy(argPos) : null, + newArity = nativeMax(arity - length, 0), + newsHolders = isCurry ? argsHolders : null, + newHoldersRight = isCurry ? null : argsHolders, + newPartials = isCurry ? args : null, + newPartialsRight = isCurry ? null : args; + + bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); + + if (!isCurryBound) { + bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); + } + var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity); + result.placeholder = placeholder; + return result; + } + } + var thisBinding = isBind ? thisArg : this; + if (isBindKey) { + func = thisBinding[key]; + } + if (argPos) { + args = reorder(args, argPos); + } + if (isAry && ary < args.length) { + args.length = ary; + } + return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates the pad required for `string` based on the given padding length. + * The `chars` string may be truncated if the number of padding characters + * exceeds the padding length. + * + * @private + * @param {string} string The string to create padding for. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the pad for `string`. + */ + function createPad(string, length, chars) { + var strLength = string.length; + length = +length; + + if (strLength >= length || !nativeIsFinite(length)) { + return ''; + } + var padLength = length - strLength; + chars = chars == null ? ' ' : (chars + ''); + return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength); + } + + /** + * Creates a function that wraps `func` and invokes it with the optional `this` + * binding of `thisArg` and the `partials` prepended to those provided to + * the wrapper. + * + * @private + * @param {Function} func The function to partially apply arguments to. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to the new function. + * @returns {Function} Returns the new bound function. + */ + function createPartialWrapper(func, bitmask, thisArg, partials) { + var isBind = bitmask & BIND_FLAG, + Ctor = createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it `func`. + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & BIND_KEY_FLAG; + if (!isBindKey && !isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); + partials = holders = null; + } + length -= (holders ? holders.length : 0); + if (bitmask & PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = null; + } + var data = !isBindKey && getData(func), + newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; + + if (data && data !== true) { + mergeData(newData, data); + bitmask = newData[1]; + arity = newData[9]; + } + newData[9] = arity == null + ? (isBindKey ? 0 : func.length) + : (nativeMax(arity - length, 0) || 0); + + if (bitmask == BIND_FLAG) { + var result = createBindWrapper(newData[0], newData[2]); + } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { + result = createPartialWrapper.apply(null, newData); + } else { + result = createHybridWrapper.apply(null, newData); + } + var setter = data ? baseSetData : setData; + return setter(result, newData); + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) { + var index = -1, + arrLength = array.length, + othLength = other.length, + result = true; + + if (arrLength != othLength && !(isWhere && othLength > arrLength)) { + return false; + } + // Deep compare the contents, ignoring non-numeric properties. + while (result && ++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + result = undefined; + if (customizer) { + result = isWhere + ? customizer(othValue, arrValue, index) + : customizer(arrValue, othValue, index); + } + if (typeof result == 'undefined') { + // Recursively compare arrays (susceptible to call stack limits). + if (isWhere) { + var othIndex = othLength; + while (othIndex--) { + othValue = other[othIndex]; + result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB); + if (result) { + break; + } + } + } else { + result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB); + } + } + } + return !!result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} value The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag) { + switch (tag) { + case boolTag: + case dateTag: + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; + + case errorTag: + return object.name == other.name && object.message == other.message; + + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return (object != +object) + ? other != +other + // But, treat `-0` vs. `+0` as not equal. + : (object == 0 ? ((1 / object) == (1 / other)) : object == +other); + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. + return object == (other + ''); + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) { + var objProps = keys(object), + objLength = objProps.length, + othProps = keys(other), + othLength = othProps.length; + + if (objLength != othLength && !isWhere) { + return false; + } + var hasCtor, + index = -1; + + while (++index < objLength) { + var key = objProps[index], + result = hasOwnProperty.call(other, key); + + if (result) { + var objValue = object[key], + othValue = other[key]; + + result = undefined; + if (customizer) { + result = isWhere + ? customizer(othValue, objValue, key) + : customizer(objValue, othValue, key); + } + if (typeof result == 'undefined') { + // Recursively compare objects (susceptible to call stack limits). + result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB); + } + } + if (!result) { + return false; + } + hasCtor || (hasCtor = key == 'constructor'); + } + if (!hasCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { + return false; + } + } + return true; + } + + /** + * Gets the extremum value of `collection` invoking `iteratee` for each value + * in `collection` to generate the criterion by which the value is ranked. + * The `iteratee` is invoked with three arguments; (value, index, collection). + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [isMin] Specify returning the minimum, instead of the + * maximum, extremum value. + * @returns {*} Returns the extremum value. + */ + function extremumBy(collection, iteratee, isMin) { + var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY, + computed = exValue, + result = computed; + + baseEach(collection, function(value, index, collection) { + var current = iteratee(value, index, collection); + if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) { + computed = current; + result = value; + } + }); + return result; + } + + /** + * Gets the appropriate "callback" function. If the `_.callback` method is + * customized this function returns the custom method, otherwise it returns + * the `baseCallback` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function} Returns the chosen function or its result. + */ + function getCallback(func, thisArg, argCount) { + var result = lodash.callback || callback; + result = result === callback ? baseCallback : result; + return argCount ? result(func, thisArg, argCount) : result; + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized this function returns the custom method, otherwise it returns + * the `baseIndexOf` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function|number} Returns the chosen function or its result. + */ + function getIndexOf(collection, target, fromIndex) { + var result = lodash.indexOf || indexOf; + result = result === indexOf ? baseIndexOf : result; + return collection ? result(collection, target, fromIndex) : result; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} [transforms] The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms ? transforms.length : 0; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add array properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + var Ctor = object.constructor; + if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { + Ctor = Object; + } + return new Ctor; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return bufferClone(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + var buffer = object.buffer; + return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + var result = new Ctor(object.source, reFlags.exec(object)); + result.lastIndex = object.lastIndex; + } + return result; + } + + /** + * Checks if `func` is eligible for `this` binding. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is eligible, else `false`. + */ + function isBindable(func) { + var support = lodash.support, + result = !(support.funcNames ? func.name : support.funcDecomp); + + if (!result) { + var source = fnToString.call(func); + if (!support.funcNames) { + result = !reFuncName.test(source); + } + if (!result) { + // Check if `func` references the `this` keyword and store the result. + result = reThis.test(source) || isNative(func); + baseSetData(func, result); + } + } + return result; + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + value = +value; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; + } + + /** + * Checks if the provided arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number') { + var length = object.length, + prereq = isLength(length) && isIndex(index, length); + } else { + prereq = type == 'string' && index in object; + } + return prereq && object[index] === value; + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on ES `ToLength`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) + * for more details. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ + function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value)); + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers required to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` + * augment function arguments, making the order in which they are executed important, + * preventing the merging of metadata. However, we make an exception for a safe + * common case where curried functions have `_.ary` and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask; + + var arityFlags = ARY_FLAG | REARG_FLAG, + bindFlags = BIND_FLAG | BIND_KEY_FLAG, + comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG; + + var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG), + isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG), + argPos = (isRearg ? data : source)[7], + ary = (isAry ? data : source)[8]; + + var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) && + !(bitmask > bindFlags && srcBitmask >= REARG_FLAG); + + var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) && + (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = arrayCopy(value); + } + // Use source `ary` if it's smaller. + if (srcBitmask & ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * A specialized version of `_.pick` that picks `object` properties specified + * by the `props` array. + * + * @private + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. + */ + function pickByArray(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + return result; + } + + /** + * A specialized version of `_.pick` that picks `object` properties `predicate` + * returns truthy for. + * + * @private + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. + */ + function pickByCallback(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = arrayCopy(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity function + * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = (function() { + var count = 0, + lastCalled = 0; + + return function(key, value) { + var stamp = now(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return key; + } + } else { + count = 0; + } + return baseSetData(key, value); + }; + }()); + + /** + * A fallback implementation of `_.isPlainObject` which checks if `value` + * is an object created by the `Object` constructor or has a `[[Prototype]]` + * of `null`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + */ + function shimIsPlainObject(value) { + var Ctor, + support = lodash.support; + + // Exit early for non `Object` objects. + if (!(isObjectLike(value) && objToString.call(value) == objectTag) || + (!hasOwnProperty.call(value, 'constructor') && + (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { + return false; + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + var result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + baseForIn(value, function(subValue, key) { + result = key; + }); + return typeof result == 'undefined' || hasOwnProperty.call(value, result); + } + + /** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + */ + function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length, + support = lodash.support; + + var allowIndexes = length && isLength(length) && + (isArray(object) || (support.nonEnumArgs && isArguments(object))); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to an array-like object if it is not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array|Object} Returns the array-like object. + */ + function toIterable(value) { + if (value == null) { + return []; + } + if (!isLength(value.length)) { + return values(value); + } + return isObject(value) ? value : Object(value); + } + + /** + * Converts `value` to an object if it is not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ + function toObject(value) { + return isObject(value) ? value : Object(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `collection` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to process. + * @param {numer} [size=1] The length of each chunk. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new array containing chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if (guard ? isIterateeCall(array, size, guard) : size == null) { + size = 1; + } else { + size = nativeMax(+size || 1, 1); + } + var index = 0, + length = array ? array.length : 0, + resIndex = -1, + result = Array(ceil(length / size)); + + while (index < length) { + result[++resIndex] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array ? array.length : 0, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[++resIndex] = value; + } + } + return result; + } + + /** + * Creates an array excluding all values of the provided arrays using + * `SameValueZero` for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The arrays of values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.difference([1, 2, 3], [5, 2, 10]); + * // => [1, 3] + */ + function difference() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var value = arguments[index]; + if (isArray(value) || isArguments(value)) { + break; + } + } + return baseDifference(value, baseFlatten(arguments, false, true, ++index)); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; }); + * // => [1] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': false }, + * { 'user': 'fred', 'status': 'busy', 'active': true }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.dropRightWhile(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user'); + * // => ['barney', 'fred'] + */ + function dropRightWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + predicate = getCallback(predicate, thisArg, 3); + while (length-- && predicate(array[length], length, array)) {} + return baseSlice(array, 0, length + 1); + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropWhile([1, 2, 3], function(n) { return n < 3; }); + * // => [3] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': true }, + * { 'user': 'fred', 'status': 'busy', 'active': false }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.dropWhile(users, 'active'), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user'); + * // => ['pebbles'] + */ + function dropWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + var index = -1; + predicate = getCallback(predicate, thisArg, 3); + while (++index < length && predicate(array[index], index, array)) {} + return baseSlice(array, index); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for, instead of the element itself. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.findIndex(users, function(chr) { return chr.age < 40; }); + * // => 0 + * + * // using the "_.matches" callback shorthand + * _.findIndex(users, { 'age': 1 }); + * // => 2 + * + * // using the "_.property" callback shorthand + * _.findIndex(users, 'active'); + * // => 1 + */ + function findIndex(array, predicate, thisArg) { + var index = -1, + length = array ? array.length : 0; + + predicate = getCallback(predicate, thisArg, 3); + while (++index < length) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.findLastIndex(users, function(chr) { return chr.age < 40; }); + * // => 2 + * + * // using the "_.matches" callback shorthand + * _.findLastIndex(users, { 'age': 40 }); + * // => 1 + * + * // using the "_.property" callback shorthand + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, thisArg) { + var length = array ? array.length : 0; + predicate = getCallback(predicate, thisArg, 3); + while (length--) { + if (predicate(array[length], length, array)) { + return length; + } + } + return -1; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @alias head + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.first([1, 2, 3]); + * // => 1 + * + * _.first([]); + * // => undefined + */ + function first(array) { + return array ? array[0] : undefined; + } + + /** + * Flattens a nested array. If `isDeep` is `true` the array is recursively + * flattened, otherwise it is only flattened a single level. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, [[4]]]; + * + * // using `isDeep` + * _.flatten([1, [2], [3, [[4]]]], true); + * // => [1, 2, 3, 4]; + */ + function flatten(array, isDeep, guard) { + var length = array ? array.length : 0; + if (guard && isIterateeCall(array, isDeep, guard)) { + isDeep = false; + } + return length ? baseFlatten(array, isDeep) : []; + } + + /** + * Recursively flattens a nested array. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to recursively flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, 4]; + */ + function flattenDeep(array) { + var length = array ? array.length : 0; + return length ? baseFlatten(array, true) : []; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using `SameValueZero` for equality comparisons. If `fromIndex` is negative, + * it is used as the offset from the end of `array`. If `array` is sorted + * providing `true` for `fromIndex` performs a faster binary search. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 3, 1, 2, 3], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 4 + * + * // performing a binary search + * _.indexOf([4, 4, 5, 5, 6, 6], 5, true); + * // => 2 + */ + function indexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + } else if (fromIndex) { + var index = binaryIndex(array, value), + other = array[index]; + + return (value === value ? value === other : other !== other) ? index : -1; + } + return baseIndexOf(array, value, fromIndex); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + return dropRight(array, 1); + } + + /** + * Creates an array of unique values in all provided arrays using `SameValueZero` + * for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of shared values. + * @example + * + * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2] + */ + function intersection() { + var args = [], + argsIndex = -1, + argsLength = arguments.length, + caches = [], + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf; + + while (++argsIndex < argsLength) { + var value = arguments[argsIndex]; + if (isArray(value) || isArguments(value)) { + args.push(value); + caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value)); + } + } + argsLength = args.length; + var array = args[0], + index = -1, + length = array ? array.length : 0, + result = [], + seen = caches[0]; + + outer: + while (++index < length) { + value = array[index]; + if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) { + argsIndex = argsLength; + while (--argsIndex) { + var cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { + continue outer; + } + } + if (seen) { + seen.push(value); + } + result.push(value); + } + } + return result; + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array ? array.length : 0; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=array.length-1] The index to search from + * or `true` to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); + * // => 4 + * + * // using `fromIndex` + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 1 + * + * // performing a binary search + * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true); + * // => 3 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = length; + if (typeof fromIndex == 'number') { + index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; + } else if (fromIndex) { + index = binaryIndex(array, value, true) - 1; + var other = array[index]; + return (value === value ? value === other : other !== other) ? index : -1; + } + if (value !== value) { + return indexOfNaN(array, index, true); + } + while (index--) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * Removes all provided values from `array` using `SameValueZero` for equality + * comparisons. + * + * **Notes:** + * - Unlike `_.without`, this method mutates `array`. + * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`, + * except that `NaN` matches `NaN`. See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3, 1, 2, 3]; + * _.pull(array, 2, 3); + * console.log(array); + * // => [1, 1] + */ + function pull() { + var array = arguments[0]; + if (!(array && array.length)) { + return array; + } + var index = 0, + indexOf = getIndexOf(), + length = arguments.length; + + while (++index < length) { + var fromIndex = 0, + value = arguments[index]; + + while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * Removes elements from `array` corresponding to the given indexes and returns + * an array of the removed elements. Indexes may be specified as an array of + * indexes or as individual arguments. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove, + * specified as individual indexes or arrays of indexes. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [5, 10, 15, 20]; + * var evens = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => [5, 15] + * + * console.log(evens); + * // => [10, 20] + */ + function pullAt(array) { + return basePullAt(array || [], baseFlatten(arguments, false, false, 1)); + } + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is bound to + * `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** Unlike `_.filter`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { return n % 2 == 0; }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate, thisArg) { + var index = -1, + length = array ? array.length : 0, + result = []; + + predicate = getCallback(predicate, thisArg, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + splice.call(array, index--, 1); + length--; + } + } + return result; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @alias tail + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.rest([1, 2, 3]); + * // => [2, 3] + */ + function rest(array) { + return drop(array, 1); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This function is used instead of `Array#slice` to support node + * lists in IE < 9 and to ensure dense arrays are returned. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` should + * be inserted into `array` in order to maintain its sort order. If an iteratee + * function is provided it is invoked for `value` and each element of `array` + * to compute their sort ranking. The iteratee is bound to `thisArg` and + * invoked with one argument; (value). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + * + * _.sortedIndex([4, 4, 5, 5, 6, 6], 5); + * // => 2 + * + * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; + * + * // using an iteratee function + * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { + * return this.data[word]; + * }, dict); + * // => 1 + * + * // using the "_.property" callback shorthand + * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); + * // => 1 + */ + function sortedIndex(array, value, iteratee, thisArg) { + var func = getCallback(iteratee); + return (func === baseCallback && iteratee == null) + ? binaryIndex(array, value) + : binaryIndexBy(array, value, func(iteratee, thisArg, 1)); + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value, iteratee, thisArg) { + var func = getCallback(iteratee); + return (func === baseCallback && iteratee == null) + ? binaryIndex(array, value, true) + : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true); + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is bound to `thisArg` + * and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; }); + * // => [2, 3] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': false }, + * { 'user': 'fred', 'status': 'busy', 'active': true }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.takeRightWhile(users, 'active'), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user'); + * // => ['pebbles'] + */ + function takeRightWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + predicate = getCallback(predicate, thisArg, 3); + while (length-- && predicate(array[length], length, array)) {} + return baseSlice(array, length + 1); + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is bound to + * `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeWhile([1, 2, 3], function(n) { return n < 3; }); + * // => [1, 2] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': true }, + * { 'user': 'fred', 'status': 'busy', 'active': false }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.takeWhile(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user'); + * // => ['barney', 'fred'] + */ + function takeWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + var index = -1; + predicate = getCallback(predicate, thisArg, 3); + while (++index < length && predicate(array[index], index, array)) {} + return baseSlice(array, 0, index); + } + + /** + * Creates an array of unique values, in order, of the provided arrays using + * `SameValueZero` for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2, 3, 5, 4] + */ + function union() { + return baseUniq(baseFlatten(arguments, false, true)); + } + + /** + * Creates a duplicate-value-free version of an array using `SameValueZero` + * for equality comparisons. Providing `true` for `isSorted` performs a faster + * search algorithm for sorted arrays. If an iteratee function is provided it + * is invoked for each value in the array to generate the criterion by which + * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked + * with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @alias unique + * @category Array + * @param {Array} array The array to inspect. + * @param {boolean} [isSorted] Specify the array is sorted. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new duplicate-value-free array. + * @example + * + * _.uniq([1, 2, 1]); + * // => [1, 2] + * + * // using `isSorted` + * _.uniq([1, 1, 2], true); + * // => [1, 2] + * + * // using an iteratee function + * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math); + * // => [1, 2.5] + * + * // using the "_.property" callback shorthand + * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniq(array, isSorted, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + // Juggle arguments. + if (typeof isSorted != 'boolean' && isSorted != null) { + thisArg = iteratee; + iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted; + isSorted = false; + } + var func = getCallback(); + if (!(func === baseCallback && iteratee == null)) { + iteratee = func(iteratee, thisArg, 3); + } + return (isSorted && getIndexOf() == baseIndexOf) + ? sortedUniq(array, iteratee) + : baseUniq(array, iteratee); + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-`_.zip` + * configuration. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + * + * _.unzip(zipped); + * // => [['fred', 'barney'], [30, 40], [true, false]] + */ + function unzip(array) { + var index = -1, + length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0, + result = Array(length); + + while (++index < length) { + result[index] = arrayMap(array, baseProperty(index)); + } + return result; + } + + /** + * Creates an array excluding all provided values using `SameValueZero` for + * equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to filter. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); + * // => [2, 3, 4] + */ + function without(array) { + return baseDifference(array, baseSlice(arguments, 1)); + } + + /** + * Creates an array that is the symmetric difference of the provided arrays. + * See [Wikipedia](https://en.wikipedia.org/wiki/Symmetric_difference) for + * more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of values. + * @example + * + * _.xor([1, 2, 3], [5, 2, 1, 4]); + * // => [3, 5, 4] + * + * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); + * // => [1, 4, 5] + */ + function xor() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var array = arguments[index]; + if (isArray(array) || isArguments(array)) { + var result = result + ? baseDifference(result, array).concat(baseDifference(array, result)) + : array; + } + } + return result ? baseUniq(result) : []; + } + + /** + * Creates an array of grouped elements, the first of which contains the first + * elements of the given arrays, the second of which contains the second elements + * of the given arrays, and so on. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + */ + function zip() { + var length = arguments.length, + array = Array(length); + + while (length--) { + array[length] = arguments[length]; + } + return unzip(array); + } + + /** + * Creates an object composed from arrays of property names and values. Provide + * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]` + * or two arrays, one of property names and one of corresponding values. + * + * @static + * @memberOf _ + * @alias object + * @category Array + * @param {Array} props The property names. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } + */ + function zipObject(props, values) { + var index = -1, + length = props ? props.length : 0, + result = {}; + + if (length && !values && !isArray(props[0])) { + values = []; + } + while (++index < length) { + var key = props[index]; + if (values) { + result[key] = values[index]; + } else if (key) { + result[key[0]] = key[1]; + } + } + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object that wraps `value` with explicit method + * chaining enabled. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` object. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _.chain(users) + * .sortBy('age') + * .map(function(chr) { return chr.user + ' is ' + chr.age; }) + * .first() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor is + * bound to `thisArg` and invoked with one argument; (value). The purpose of + * this method is to "tap into" a method chain in order to perform operations + * on intermediate results within the chain. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { array.pop(); }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor, thisArg) { + interceptor.call(thisArg, value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _([1, 2, 3]) + * .last() + * .thru(function(value) { return [value]; }) + * .value(); + * // => [3] + */ + function thru(value, interceptor, thisArg) { + return interceptor.call(thisArg, value); + } + + /** + * Enables explicit method chaining on the wrapper object. + * + * @name chain + * @memberOf _ + * @category Chain + * @returns {*} Returns the `lodash` object. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // without explicit chaining + * _(users).first(); + * // => { 'user': 'barney', 'age': 36 } + * + * // with explicit chaining + * _(users).chain() + * .first() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Reverses the wrapped array so the first element becomes the last, the + * second element becomes the second to last, and so on. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new reversed `lodash` object. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + if (this.__actions__.length) { + value = new LazyWrapper(this); + } + return new LodashWrapper(value.reverse()); + } + return this.thru(function(value) { + return value.reverse(); + }); + } + + /** + * Produces the result of coercing the unwrapped value to a string. + * + * @name toString + * @memberOf _ + * @category Chain + * @returns {string} Returns the coerced string value. + * @example + * + * _([1, 2, 3]).toString(); + * // => '1,2,3' + */ + function wrapperToString() { + return (this.value() + ''); + } + + /** + * Executes the chained sequence to extract the unwrapped value. + * + * @name value + * @memberOf _ + * @alias toJSON, valueOf + * @category Chain + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements corresponding to the given keys, or indexes, + * of `collection`. Keys may be specified as individual arguments or as arrays + * of keys. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(number|number[]|string|string[])} [props] The property names + * or indexes of elements to pick, specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); + * // => ['a', 'c', 'e'] + * + * _.at(['fred', 'barney', 'pebbles'], 0, 2); + * // => ['fred', 'pebbles'] + */ + function at(collection) { + var length = collection ? collection.length : 0; + if (isLength(length)) { + collection = toIterable(collection); + } + return baseAt(collection, baseFlatten(arguments, false, false, 1)); + } + + /** + * Checks if `value` is in `collection` using `SameValueZero` for equality + * comparisons. If `fromIndex` is negative, it is used as the offset from + * the end of `collection`. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @alias contains, include + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {*} target The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {boolean} Returns `true` if a matching element is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); + * // => true + * + * _.includes('pebbles', 'eb'); + * // => true + */ + function includes(collection, target, fromIndex) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + collection = values(collection); + length = collection.length; + } + if (!length) { + return false; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + } else { + fromIndex = 0; + } + return (typeof collection == 'string' || !isArray(collection) && isString(collection)) + ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1) + : (getIndexOf(collection, target, fromIndex) > -1); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the number of times the key was returned by `iteratee`. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); }); + * // => { '4': 1, '6': 2 } + * + * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math); + * // => { '4': 1, '6': 2 } + * + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * The predicate is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias all + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes']); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // using the "_.property" callback shorthand + * _.every(users, 'age'); + * // => true + * + * // using the "_.matches" callback shorthand + * _.every(users, { 'age': 36 }); + * // => false + */ + function every(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (typeof predicate != 'function' || typeof thisArg != 'undefined') { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias select + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; }); + * // => [2, 4] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.filter(users, 'active'), 'user'); + * // => ['fred'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.filter(users, { 'age': 36 }), 'user'); + * // => ['barney'] + */ + function filter(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = getCallback(predicate, thisArg, 3); + return func(collection, predicate); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias detect + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user'); + * // => 'barney' + * + * // using the "_.matches" callback shorthand + * _.result(_.find(users, { 'age': 1 }), 'user'); + * // => 'pebbles' + * + * // using the "_.property" callback shorthand + * _.result(_.find(users, 'active'), 'user'); + * // => 'fred' + */ + function find(collection, predicate, thisArg) { + if (isArray(collection)) { + var index = findIndex(collection, predicate, thisArg); + return index > -1 ? collection[index] : undefined; + } + predicate = getCallback(predicate, thisArg, 3); + return baseFind(collection, predicate, baseEach); + } + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; }); + * // => 3 + */ + function findLast(collection, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + return baseFind(collection, predicate, baseEachRight); + } + + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning the first element that has equivalent property + * values. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'status': 'busy' }, + * { 'user': 'fred', 'age': 40, 'status': 'busy' } + * ]; + * + * _.result(_.findWhere(users, { 'status': 'busy' }), 'user'); + * // => 'barney' + * + * _.result(_.findWhere(users, { 'age': 40 }), 'user'); + * // => 'fred' + */ + function findWhere(collection, source) { + return find(collection, baseMatches(source)); + } + + /** + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). Iterator functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEach(function(n) { console.log(n); }).value(); + * // => logs each value from left to right and returns the array + * + * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); }); + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + */ + function forEach(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) + ? arrayEach(collection, iteratee) + : baseEach(collection, bindCallback(iteratee, thisArg, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias eachRight + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(','); + * // => logs each value from right to left and returns the array + */ + function forEachRight(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) + ? arrayEachRight(collection, iteratee) + : baseEachRight(collection, bindCallback(iteratee, thisArg, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is an array of the elements responsible for generating the key. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); }); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * // using the "_.property" callback shorthand + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + result[key] = [value]; + } + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the last element responsible for generating the key. The + * iteratee function is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var keyData = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.indexBy(keyData, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + */ + var indexBy = createAggregator(function(result, value, key) { + result[key] = value; + }); + + /** + * Invokes the method named by `methodName` on each element in `collection`, + * returning an array of the results of each invoked method. Any additional + * arguments are provided to each invoked method. If `methodName` is a function + * it is invoked for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|string} methodName The name of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invoke([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + function invoke(collection, methodName) { + return baseInvoke(collection, methodName, baseSlice(arguments, 2)); + } + + /** + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias collect + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new mapped array. + * @example + * + * _.map([1, 2, 3], function(n) { return n * 3; }); + * // => [3, 6, 9] + * + * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; }); + * // => [3, 6, 9] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // using the "_.property" callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = getCallback(iteratee, thisArg, 3); + return func(collection, iteratee); + } + + /** + * Gets the maximum value of `collection`. If `collection` is empty or falsey + * `-Infinity` is returned. If an iteratee function is provided it is invoked + * for each value in `collection` to generate the criterion by which the value + * is ranked. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the maximum value. + * @example + * + * _.max([4, 2, 8, 6]); + * // => 8 + * + * _.max([]); + * // => -Infinity + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.max(users, function(chr) { return chr.age; }); + * // => { 'user': 'fred', 'age': 40 }; + * + * // using the "_.property" callback shorthand + * _.max(users, 'age'); + * // => { 'user': 'fred', 'age': 40 }; + */ + var max = createExtremum(arrayMax); + + /** + * Gets the minimum value of `collection`. If `collection` is empty or falsey + * `Infinity` is returned. If an iteratee function is provided it is invoked + * for each value in `collection` to generate the criterion by which the value + * is ranked. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the minimum value. + * @example + * + * _.min([4, 2, 8, 6]); + * // => 2 + * + * _.min([]); + * // => Infinity + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.min(users, function(chr) { return chr.age; }); + * // => { 'user': 'barney', 'age': 36 }; + * + * // using the "_.property" callback shorthand + * _.min(users, 'age'); + * // => { 'user': 'barney', 'age': 36 }; + */ + var min = createExtremum(arrayMin, true); + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * _.partition([1, 2, 3], function(n) { return n % 2; }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math); + * // => [[1, 3], [2]] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * // using the "_.matches" callback shorthand + * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); }); + * // => [['pebbles'], ['barney', 'fred']] + * + * // using the "_.property" callback shorthand + * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); }); + * // => [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Gets the value of `key` from all elements in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {string} key The key of the property to pluck. + * @returns {Array} Returns the property values. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.pluck(users, 'user'); + * // => ['barney', 'fred'] + * + * var userIndex = _.indexBy(users, 'user'); + * _.pluck(userIndex, 'age'); + * // => [36, 40] (iteration order is not guaranteed) + */ + function pluck(collection, key) { + return map(collection, baseProperty(key + '')); + } + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` through `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not provided the first element of `collection` is used as the initial + * value. The `iteratee` is bound to `thisArg`and invoked with four arguments; + * (accumulator, value, index|key, collection). + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; }); + * // => 6 + * + * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) { + * result[key] = n * 3; + * return result; + * }, {}); + * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator, thisArg) { + var func = isArray(collection) ? arrayReduce : baseReduce; + return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias foldr + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator, thisArg) { + var func = isArray(collection) ? arrayReduceRight : baseReduce; + return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; }); + * // => [1, 3] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.reject(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.reject(users, { 'age': 36 }), 'user'); + * // => ['fred'] + */ + function reject(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = getCallback(predicate, thisArg, 3); + return func(collection, function(value, index, collection) { + return !predicate(value, index, collection); + }); + } + + /** + * Gets a random element or `n` random elements from a collection. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to sample. + * @param {number} [n] The number of elements to sample. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {*} Returns the random sample(s). + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + * + * _.sample([1, 2, 3, 4], 2); + * // => [3, 1] + */ + function sample(collection, n, guard) { + if (guard ? isIterateeCall(collection, n, guard) : n == null) { + collection = toIterable(collection); + var length = collection.length; + return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; + } + var result = shuffle(collection); + result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length); + return result; + } + + /** + * Creates an array of shuffled values, using a version of the Fisher-Yates + * shuffle. See [Wikipedia](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle) + * for more details. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + collection = toIterable(collection); + + var index = -1, + length = collection.length, + result = Array(length); + + while (++index < length) { + var rand = baseRandom(0, index); + if (index != rand) { + result[index] = result[rand]; + } + result[rand] = collection[index]; + } + return result; + } + + /** + * Gets the size of `collection` by returning `collection.length` for + * array-like values or the number of own enumerable properties for objects. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the size of `collection`. + * @example + * + * _.size([1, 2]); + * // => 2 + * + * _.size({ 'one': 1, 'two': 2, 'three': 3 }); + * // => 3 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + var length = collection ? collection.length : 0; + return isLength(length) ? length : keys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * The function returns as soon as it finds a passing value and does not iterate + * over the entire collection. The predicate is bound to `thisArg` and invoked + * with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias any + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.some(users, 'active'); + * // => true + * + * // using the "_.matches" callback shorthand + * _.some(users, { 'age': 1 }); + * // => false + */ + function some(collection, predicate, thisArg) { + var func = isArray(collection) ? arraySome : baseSome; + if (typeof predicate != 'function' || typeof thisArg != 'undefined') { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection through `iteratee`. This method performs + * a stable sort, that is, it preserves the original sort order of equal elements. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|Function|Object|string} [iteratee=_.identity] The function + * invoked per iteration. If a property name or an object is provided it is + * used to create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new sorted array. + * @example + * + * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); }); + * // => [3, 1, 2] + * + * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math); + * // => [3, 1, 2] + * + * var users = [ + * { 'user': 'fred' }, + * { 'user': 'pebbles' }, + * { 'user': 'barney' } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.sortBy(users, 'user'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ + function sortBy(collection, iteratee, thisArg) { + var index = -1, + length = collection ? collection.length : 0, + result = isLength(length) ? Array(length) : []; + + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = null; + } + iteratee = getCallback(iteratee, thisArg, 3); + baseEach(collection, function(value, key, collection) { + result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value }; + }); + return baseSortBy(result, compareAscending); + } + + /** + * This method is like `_.sortBy` except that it sorts by property names + * instead of an iteratee function. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(string|string[])} props The property names to sort by, + * specified as individual property names or arrays of property names. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 26 }, + * { 'user': 'fred', 'age': 30 } + * ]; + * + * _.map(_.sortByAll(users, ['user', 'age']), _.values); + * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] + */ + function sortByAll(collection) { + var args = arguments; + if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) { + args = [collection, args[1]]; + } + var index = -1, + length = collection ? collection.length : 0, + props = baseFlatten(args, false, false, 1), + result = isLength(length) ? Array(length) : []; + + baseEach(collection, function(value, key, collection) { + var length = props.length, + criteria = Array(length); + + while (length--) { + criteria[length] = value == null ? undefined : value[props[length]]; + } + result[++index] = { 'criteria': criteria, 'index': index, 'value': value }; + }); + return baseSortBy(result, compareMultipleAscending); + } + + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning an array of all elements that have equivalent + * property values. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {Array} Returns the new filtered array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] }, + * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] } + * ]; + * + * _.pluck(_.where(users, { 'age': 36 }), 'user'); + * // => ['barney'] + * + * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); + * // => ['fred'] + * + * _.pluck(_.where(users, { 'status': 'busy' }), 'user'); + * // => ['barney', 'fred'] + */ + function where(collection, source) { + return filter(collection, baseMatches(source)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = nativeNow || function() { + return new Date().getTime(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it is called `n` or more times. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => logs 'done saving!' after the two async saves have completed + */ + function after(n, func) { + if (!isFunction(func)) { + if (isFunction(n)) { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + n = nativeIsFinite(n = +n) ? n : 0; + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that accepts up to `n` arguments ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + if (guard && isIterateeCall(func, n, guard)) { + n = null; + } + n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); + return createWrapper(func, ARY_FLAG, null, null, null, null, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it is called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery('#add').on('click', _.before(5, addContactToList)); + * // => allows adding up to 4 contacts to the list + */ + function before(n, func) { + var result; + if (!isFunction(func)) { + if (isFunction(n)) { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } else { + func = null; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and prepends any additional `_.bind` arguments to those provided to the + * bound function. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind` this method does not set the `length` + * property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var greet = function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * }; + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // using placeholders + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + function bind(func, thisArg) { + var bitmask = BIND_FLAG; + if (arguments.length > 2) { + var partials = baseSlice(arguments, 2), + holders = replaceHolders(partials, bind.placeholder); + + bitmask |= PARTIAL_FLAG; + } + return createWrapper(func, bitmask, thisArg, partials, holders); + } + + /** + * Binds methods of an object to the object itself, overwriting the existing + * method. Method names may be specified as individual arguments or as arrays + * of method names. If no method names are provided all enumerable function + * properties, own and inherited, of `object` are bound. + * + * **Note:** This method does not set the `length` property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object to bind and assign the bound methods to. + * @param {...(string|string[])} [methodNames] The object method names to bind, + * specified as individual method names or arrays of method names. + * @returns {Object} Returns `object`. + * @example + * + * var view = { + * 'label': 'docs', + * 'onClick': function() { console.log('clicked ' + this.label); } + * }; + * + * _.bindAll(view); + * jQuery('#docs').on('click', view.onClick); + * // => logs 'clicked docs' when the element is clicked + */ + function bindAll(object) { + return baseBindAll(object, + arguments.length > 1 + ? baseFlatten(arguments, false, false, 1) + : functions(object) + ); + } + + /** + * Creates a function that invokes the method at `object[key]` and prepends + * any additional `_.bindKey` arguments to those provided to the bound function. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. + * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object the method belongs to. + * @param {string} key The key of the method. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // using placeholders + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + function bindKey(object, key) { + var bitmask = BIND_FLAG | BIND_KEY_FLAG; + if (arguments.length > 2) { + var partials = baseSlice(arguments, 2), + holders = replaceHolders(partials, bindKey.placeholder); + + bitmask |= PARTIAL_FLAG; + } + return createWrapper(key, bitmask, object, partials, holders); + } + + /** + * Creates a function that accepts one or more arguments of `func` that when + * called either invokes `func` returning its result, if all `func` arguments + * have been provided, or returns a function that accepts one or more of the + * remaining `func` arguments, and so on. The arity of `func` may be specified + * if `func.length` is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the `length` property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = null; + } + var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the `length` property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = null; + } + var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a function that delays invoking `func` until after `wait` milliseconds + * have elapsed since the last time it was invoked. The created function comes + * with a `cancel` method to cancel delayed invocations. Provide an options + * object to indicate that `func` should be invoked on the leading and/or + * trailing edge of the `wait` timeout. Subsequent calls to the debounced + * function return the result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} wait The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it is invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : wait; + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + var isCalled = trailingCall; + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + if (timeoutId) { + clearTimeout(timeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (trailing || (maxWait !== wait)) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + return result; + } + debounced.cancel = cancel; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { console.log(text); }, 'deferred'); + * // logs 'deferred' after one or more milliseconds + */ + function defer(func) { + return baseDelay(func, 1, arguments, 1); + } + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { console.log(text); }, 1000, 'later'); + * // => logs 'later' after one second + */ + function delay(func, wait) { + return baseDelay(func, wait, arguments, 2); + } + + /** + * Creates a function that returns the result of invoking the provided + * functions with the `this` binding of the created function, where each + * successive invocation is supplied the return value of the previous. + * + * @static + * @memberOf _ + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flow(add, square); + * addSquare(1, 2); + * // => 9 + */ + function flow() { + var funcs = arguments, + length = funcs.length; + + if (!length) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = 0, + result = funcs[index].apply(this, arguments); + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + } + + /** + * This method is like `_.flow` except that it creates a function that + * invokes the provided functions from right to left. + * + * @static + * @memberOf _ + * @alias backflow, compose + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flowRight(square, add); + * addSquare(1, 2); + * // => 9 + */ + function flowRight() { + var funcs = arguments, + fromIndex = funcs.length - 1; + + if (fromIndex < 0) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = fromIndex, + result = funcs[index].apply(this, arguments); + + while (index--) { + result = funcs[index].call(this, result); + } + return result; + }; + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is coerced to a string and used as the + * cache key. The `func` is invoked with the `this` binding of the memoized + * function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the ES `Map` method interface + * of `get`, `has`, and `set`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object) + * for more details. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoizing function. + * @example + * + * var upperCase = _.memoize(function(string) { + * return string.toUpperCase(); + * }); + * + * upperCase('fred'); + * // => 'FRED' + * + * // modifying the result cache + * upperCase.cache.set('fred', 'BARNEY'); + * upperCase('fred'); + * // => 'BARNEY' + * + * // replacing `_.memoize.Cache` + * var object = { 'user': 'fred' }; + * var other = { 'user': 'barney' }; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'fred' } + * + * _.memoize.Cache = WeakMap; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'barney' } + */ + function memoize(func, resolver) { + if (!isFunction(func) || (resolver && !isFunction(resolver))) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var cache = memoized.cache, + key = resolver ? resolver.apply(this, arguments) : arguments[0]; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, arguments); + cache.set(key, result); + return result; + }; + memoized.cache = new memoize.Cache; + return memoized; + } + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (!isFunction(predicate)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + return !predicate.apply(this, arguments); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first call. The `func` is invoked + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @type Function + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // `initialize` invokes `createApplication` once + */ + function once(func) { + return before(func, 2); + } + + /** + * Creates a function that invokes `func` with `partial` arguments prepended + * to those provided to the new function. This method is like `_.bind` except + * it does **not** alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the `length` property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // using placeholders + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + function partial(func) { + var partials = baseSlice(arguments, 1), + holders = replaceHolders(partials, partial.placeholder); + + return createWrapper(func, PARTIAL_FLAG, null, partials, holders); + } + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to those provided to the new function. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the `length` property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // using placeholders + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + function partialRight(func) { + var partials = baseSlice(arguments, 1), + holders = replaceHolders(partials, partialRight.placeholder); + + return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders); + } + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified indexes where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes, + * specified as individual indexes or arrays of indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, 2, 0, 1); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + * + * var map = _.rearg(_.map, [1, 0]); + * map(function(n) { return n * 3; }, [1, 2, 3]); + * // => [3, 6, 9] + */ + function rearg(func) { + var indexes = baseFlatten(arguments, false, false, 1); + return createWrapper(func, REARG_FLAG, null, null, null, indexes); + } + + /** + * Creates a function that only invokes `func` at most once per every `wait` + * milliseconds. The created function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the throttled function return the result of the last + * `func` call. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the throttled function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to throttle. + * @param {number} wait The number of milliseconds to throttle invocations to. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=true] Specify invoking on the leading + * edge of the timeout. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // avoid excessively updating the position while scrolling + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }) + * jQuery('.interactive').on('click', throttled); + * + * // cancel a trailing throttled call + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (options === false) { + leading = false; + } else if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + debounceOptions.leading = leading; + debounceOptions.maxWait = +wait; + debounceOptions.trailing = trailing; + return debounce(func, wait, debounceOptions); + } + + /** + * Creates a function that provides `value` to the wrapper function as its + * first argument. Any additional arguments provided to the function are + * appended to those provided to the wrapper function. The wrapper is invoked + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @category Function + * @param {*} value The value to wrap. + * @param {Function} wrapper The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

    ' + func(text) + '

    '; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

    fred, barney, & pebbles

    ' + */ + function wrap(value, wrapper) { + wrapper = wrapper == null ? identity : wrapper; + return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, + * otherwise they are assigned by reference. If `customizer` is provided it is + * invoked to produce the cloned values. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is bound to + * `thisArg` and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the structured clone algorithm. + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var shallow = _.clone(users); + * shallow[0] === users[0]; + * // => true + * + * var deep = _.clone(users, true); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var body = _.clone(document.body, function(value) { + * return _.isElement(value) ? value.cloneNode(false) : undefined; + * }); + * + * body === document.body + * // => false + * body.nodeName + * // => BODY + * body.childNodes.length; + * // => 0 + */ + function clone(value, isDeep, customizer, thisArg) { + // Juggle arguments. + if (typeof isDeep != 'boolean' && isDeep != null) { + thisArg = customizer; + customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep; + isDeep = false; + } + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); + return baseClone(value, isDeep, customizer); + } + + /** + * Creates a deep clone of `value`. If `customizer` is provided it is invoked + * to produce the cloned values. If `customizer` returns `undefined` cloning + * is handled by the method instead. The `customizer` is bound to `thisArg` + * and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the structured clone algorithm. + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the deep cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var deep = _.cloneDeep(users); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var el = _.cloneDeep(document.body, function(value) { + * return _.isElement(value) ? value.cloneNode(true) : undefined; + * }); + * + * body === document.body + * // => false + * body.nodeName + * // => BODY + * body.childNodes.length; + * // => 20 + */ + function cloneDeep(value, customizer, thisArg) { + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); + return baseClone(value, true, customizer); + } + + /** + * Checks if `value` is classified as an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * (function() { return _.isArguments(arguments); })(); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + function isArguments(value) { + var length = isObjectLike(value) ? value.length : undefined; + return (isLength(length) && objToString.call(value) == argsTag) || false; + } + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * (function() { return _.isArray(arguments); })(); + * // => false + */ + var isArray = nativeIsArray || function(value) { + return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false; + }; + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false; + } + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + function isDate(value) { + return (isObjectLike(value) && objToString.call(value) == dateTag) || false; + } + + /** + * Checks if `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return (value && value.nodeType === 1 && isObjectLike(value) && + objToString.call(value).indexOf('Element') > -1) || false; + } + // Fallback for environments without DOM support. + if (!support.dom) { + isElement = function(value) { + return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false; + }; + } + + /** + * Checks if a value is empty. A value is considered empty unless it is an + * `arguments` object, array, string, or jQuery-like collection with a length + * greater than `0` or an object with own enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {Array|Object|string} value The value to inspect. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + var length = value.length; + if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) || + (isObjectLike(value) && isFunction(value.splice)))) { + return !length; + } + return !keys(value).length; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. If `customizer` is provided it is invoked to compare values. + * If `customizer` returns `undefined` comparisons are handled by the method + * instead. The `customizer` is bound to `thisArg` and invoked with three + * arguments; (value, other [, index|key]). + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes + * are **not** supported. Provide a customizer function to extend support + * for comparing other values. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * object == other; + * // => false + * + * _.isEqual(object, other); + * // => true + * + * // using a customizer callback + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqual(array, other, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); + * // => true + */ + function isEqual(value, other, customizer, thisArg) { + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); + if (!customizer && isStrictComparable(value) && isStrictComparable(other)) { + return value === other; + } + var result = customizer ? customizer(value, other) : undefined; + return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false; + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on ES `Number.isFinite`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(10); + * // => true + * + * _.isFinite('10'); + * // => false + * + * _.isFinite(true); + * // => false + * + * _.isFinite(Object(10)); + * // => false + * + * _.isFinite(Infinity); + * // => false + */ + var isFinite = nativeNumIsFinite || function(value) { + return typeof value == 'number' && nativeIsFinite(value); + }; + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + // Avoid a Chakra JIT bug in compatibility modes of IE 11. + // See https://github.com/jashkenas/underscore/issues/1621 for more details. + return typeof value == 'function' || false; + } + // Fallback for environments that return incorrect `typeof` operator results. + if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) { + isFunction = function(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return objToString.call(value) == funcTag; + }; + } + + /** + * Checks if `value` is the language type of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * **Note:** See the [ES5 spec](https://es5.github.io/#x8) for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return type == 'function' || (value && type == 'object') || false; + } + + /** + * Performs a deep comparison between `object` and `source` to determine if + * `object` contains equivalent property values. If `customizer` is provided + * it is invoked to compare values. If `customizer` returns `undefined` + * comparisons are handled by the method instead. The `customizer` is bound + * to `thisArg` and invoked with three arguments; (value, other, index|key). + * + * **Note:** This method supports comparing properties of arrays, booleans, + * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions + * and DOM nodes are **not** supported. Provide a customizer function to extend + * support for comparing other values. + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} source The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparing values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.isMatch(object, { 'age': 40 }); + * // => true + * + * _.isMatch(object, { 'age': 36 }); + * // => false + * + * // using a customizer callback + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatch(object, source, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); + * // => true + */ + function isMatch(object, source, customizer, thisArg) { + var props = keys(source), + length = props.length; + + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); + if (!customizer && length == 1) { + var key = props[0], + value = source[key]; + + if (isStrictComparable(value)) { + return object != null && value === object[key] && hasOwnProperty.call(object, key); + } + } + var values = Array(length), + strictCompareFlags = Array(length); + + while (length--) { + value = values[length] = source[props[length]]; + strictCompareFlags[length] = isStrictComparable(value); + } + return baseIsMatch(object, props, values, strictCompareFlags, customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is not the same as native `isNaN` which returns `true` + * for `undefined` and other non-numeric values. See the [ES5 spec](https://es5.github.io/#x15.1.2.4) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some host objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reNative.test(fnToString.call(value)); + } + return (isObjectLike(value) && reHostCtor.test(value)) || false; + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isNumber(8.4); + * // => true + * + * _.isNumber(NaN); + * // => true + * + * _.isNumber('8.4'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false; + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * **Note:** This method assumes objects created by the `Object` constructor + * have no inherited enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { + if (!(value && objToString.call(value) == objectTag)) { + return false; + } + var valueOf = value.valueOf, + objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + + return objProto + ? (value == objProto || getPrototypeOf(value) == objProto) + : shimIsPlainObject(value); + }; + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + function isRegExp(value) { + return (isObjectLike(value) && objToString.call(value) == regexpTag) || false; + } + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false; + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + function isTypedArray(value) { + return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false; + } + + /** + * Checks if `value` is `undefined`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return typeof value == 'undefined'; + } + + /** + * Converts `value` to an array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3); + * // => [2, 3] + */ + function toArray(value) { + var length = value ? value.length : 0; + if (!isLength(length)) { + return values(value); + } + if (!length) { + return []; + } + return arrayCopy(value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable + * properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return baseCopy(value, keysIn(value)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * If `customizer` is provided it is invoked to produce the assigned values. + * The `customizer` is bound to `thisArg` and invoked with five arguments; + * (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } + * + * // using a customizer callback + * var defaults = _.partialRight(_.assign, function(value, other) { + * return typeof value == 'undefined' ? other : value; + * }); + * + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var assign = createAssigner(baseAssign); + + /** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties, guard) { + var result = baseCreate(prototype); + if (guard && isIterateeCall(prototype, properties, guard)) { + properties = null; + } + return properties ? baseCopy(properties, result, keys(properties)) : result; + } + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional defaults of the same property are ignored. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + function defaults(object) { + if (object == null) { + return object; + } + var args = arrayCopy(arguments); + args.push(assignDefaults); + return assign.apply(undefined, args); + } + + /** + * This method is like `_.findIndex` except that it returns the key of the + * first element `predicate` returns truthy for, instead of the element itself. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(chr) { return chr.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // using the "_.matches" callback shorthand + * _.findKey(users, { 'age': 1 }); + * // => 'pebbles' + * + * // using the "_.property" callback shorthand + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + return baseFind(object, predicate, baseForOwn, true); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(chr) { return chr.age < 40; }); + * // => returns `pebbles` assuming `_.findKey` returns `barney` + * + * // using the "_.matches" callback shorthand + * _.findLastKey(users, { 'age': 36 }); + * // => 'barney' + * + * // using the "_.property" callback shorthand + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + return baseFind(object, predicate, baseForOwnRight, true); + } + + /** + * Iterates over own and inherited enumerable properties of an object invoking + * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked + * with three arguments; (value, key, object). Iterator functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) + */ + function forIn(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return baseFor(object, iteratee, keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' + */ + function forInRight(object, iteratee, thisArg) { + iteratee = bindCallback(iteratee, thisArg, 3); + return baseForRight(object, iteratee, keysIn); + } + + /** + * Iterates over own enumerable properties of an object invoking `iteratee` + * for each property. The `iteratee` is bound to `thisArg` and invoked with + * three arguments; (value, key, object). Iterator functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) { + * console.log(key); + * }); + * // => logs '0', '1', and 'length' (iteration order is not guaranteed) + */ + function forOwn(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return baseForOwn(object, iteratee); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) { + * console.log(key); + * }); + * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' + */ + function forOwnRight(object, iteratee, thisArg) { + iteratee = bindCallback(iteratee, thisArg, 3); + return baseForRight(object, iteratee, keys); + } + + /** + * Creates an array of function property names from all enumerable properties, + * own and inherited, of `object`. + * + * @static + * @memberOf _ + * @alias methods + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property names. + * @example + * + * _.functions(_); + * // => ['all', 'any', 'bind', ...] + */ + function functions(object) { + return baseFunctions(object, keysIn(object)); + } + + /** + * Checks if `key` exists as a direct property of `object` instead of an + * inherited property. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @param {string} key The key to check. + * @returns {boolean} Returns `true` if `key` is a direct property, else `false`. + * @example + * + * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); + * // => true + */ + function has(object, key) { + return object ? hasOwnProperty.call(object, key) : false; + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite property + * assignments of previous values unless `multiValue` is `true`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to invert. + * @param {boolean} [multiValue] Allow multiple values per key. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new inverted object. + * @example + * + * _.invert({ 'first': 'fred', 'second': 'barney' }); + * // => { 'fred': 'first', 'barney': 'second' } + * + * // without `multiValue` + * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }); + * // => { 'fred': 'third', 'barney': 'second' } + * + * // with `multiValue` + * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true); + * // => { 'fred': ['first', 'third'], 'barney': ['second'] } + */ + function invert(object, multiValue, guard) { + if (guard && isIterateeCall(object, multiValue, guard)) { + multiValue = null; + } + var index = -1, + props = keys(object), + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index], + value = object[key]; + + if (multiValue) { + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + } + else { + result[value] = key; + } + } + return result; + } + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + var keys = !nativeKeys ? shimKeys : function(object) { + if (object) { + var Ctor = object.constructor, + length = object.length; + } + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && (length && isLength(length)))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; + }; + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype == object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated by + * running each own enumerable property of `object` through `iteratee`. The + * iteratee function is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * If a property name is provided for `iteratee` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `iteratee` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the new mapped object. + * @example + * + * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * // using the "_.property" callback shorthand + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee, thisArg) { + var result = {}; + iteratee = getCallback(iteratee, thisArg, 3); + + baseForOwn(object, function(value, key, object) { + result[key] = iteratee(value, key, object); + }); + return result; + } + + /** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * overwrite property assignments of previous sources. If `customizer` is + * provided it is invoked to produce the merged values of the destination and + * source properties. If `customizer` returns `undefined` merging is handled + * by the method instead. The `customizer` is bound to `thisArg` and invoked + * with five arguments; (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize merging properties. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; + * + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; + * + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } + * + * // using a customizer callback + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(object, other, function(a, b) { + * return _.isArray(a) ? a.concat(b) : undefined; + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + */ + var merge = createAssigner(baseMerge); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that are not omitted. + * Property names may be specified as individual arguments or as arrays of + * property names. If `predicate` is provided it is invoked for each property + * of `object` omitting the properties `predicate` returns truthy for. The + * predicate is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to omit, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.omit(object, 'age'); + * // => { 'user': 'fred' } + * + * _.omit(object, _.isNumber); + * // => { 'user': 'fred' } + */ + function omit(object, predicate, thisArg) { + if (object == null) { + return {}; + } + if (typeof predicate != 'function') { + var props = arrayMap(baseFlatten(arguments, false, false, 1), String); + return pickByArray(object, baseDifference(keysIn(object), props)); + } + predicate = bindCallback(predicate, thisArg, 3); + return pickByCallback(object, function(value, key, object) { + return !predicate(value, key, object); + }); + } + + /** + * Creates a two dimensional array of the key-value pairs for `object`, + * e.g. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) + */ + function pairs(object) { + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } + return result; + } + + /** + * Creates an object composed of the picked `object` properties. Property + * names may be specified as individual arguments or as arrays of property + * names. If `predicate` is provided it is invoked for each property of `object` + * picking the properties `predicate` returns truthy for. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, key, object). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to pick, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.pick(object, 'user'); + * // => { 'user': 'fred' } + * + * _.pick(object, _.isString); + * // => { 'user': 'fred' } + */ + function pick(object, predicate, thisArg) { + if (object == null) { + return {}; + } + return typeof predicate == 'function' + ? pickByCallback(object, bindCallback(predicate, thisArg, 3)) + : pickByArray(object, baseFlatten(arguments, false, false, 1)); + } + + /** + * Resolves the value of property `key` on `object`. If the value of `key` is + * a function it is invoked with the `this` binding of `object` and its result + * is returned, else the property value is returned. If the property value is + * `undefined` the `defaultValue` is used in its place. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {string} key The key of the property to resolve. + * @param {*} [defaultValue] The value returned if the property value + * resolves to `undefined`. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'user': 'fred', 'age': _.constant(40) }; + * + * _.result(object, 'user'); + * // => 'fred' + * + * _.result(object, 'age'); + * // => 40 + * + * _.result(object, 'status', 'busy'); + * // => 'busy' + * + * _.result(object, 'status', _.constant('busy')); + * // => 'busy' + */ + function result(object, key, defaultValue) { + var value = object == null ? undefined : object[key]; + if (typeof value == 'undefined') { + value = defaultValue; + } + return isFunction(value) ? value.call(object) : value; + } + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own enumerable + * properties through `iteratee`, with each invocation potentially mutating + * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked + * with four arguments; (accumulator, value, key, object). Iterator functions + * may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Array|Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) { + * n *= n; + * if (n % 2) { + * return result.push(n) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) { + * result[key] = n * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function transform(object, iteratee, accumulator, thisArg) { + var isArr = isArray(object) || isTypedArray(object); + iteratee = getCallback(iteratee, thisArg, 4); + + if (accumulator == null) { + if (isArr || isObject(object)) { + var Ctor = object.constructor; + if (isArr) { + accumulator = isArray(object) ? new Ctor : []; + } else { + accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype); + } + } else { + accumulator = {}; + } + } + (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Creates an array of the own enumerable property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable property values + * of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Produces a random number between `min` and `max` (inclusive). If only one + * argument is provided a number between `0` and the given number is returned. + * If `floating` is `true`, or either `min` or `max` are floats, a floating-point + * number is returned instead of an integer. + * + * @static + * @memberOf _ + * @category Number + * @param {number} [min=0] The minimum possible value. + * @param {number} [max=1] The maximum possible value. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(min, max, floating) { + if (floating && isIterateeCall(min, max, floating)) { + max = floating = null; + } + var noMin = min == null, + noMax = max == null; + + if (floating == null) { + if (noMax && typeof min == 'boolean') { + floating = min; + min = 1; + } + else if (typeof max == 'boolean') { + floating = max; + noMax = true; + } + } + if (noMin && noMax) { + max = 1; + noMax = false; + } + min = +min || 0; + if (noMax) { + max = min; + min = 0; + } else { + max = +max || 0; + } + if (floating || min % 1 || max % 1) { + var rand = nativeRandom(); + return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); + } + return baseRandom(min, max); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to camel case. + * See [Wikipedia](https://en.wikipedia.org/wiki/CamelCase) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar'); + * // => 'fooBar' + * + * _.camelCase('__foo_bar__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word); + }); + + /** + * Capitalizes the first character of `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('fred'); + * // => 'Fred' + */ + function capitalize(string) { + string = baseToString(string); + return string && (string.charAt(0).toUpperCase() + string.slice(1)); + } + + /** + * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters. + * See [Wikipedia](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = baseToString(string); + return string && string.replace(reLatin1, deburrLetter); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to search. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search from. + * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = baseToString(string); + target = (target + ''); + + var length = string.length; + position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length; + return position >= 0 && string.indexOf(target, position) == position; + } + + /** + * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to + * their corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional characters + * use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't require escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. + * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * Backticks are escaped because in Internet Explorer < 9, they can break out + * of attribute values or HTML comments. See [#102](https://html5sec.org/#102), + * [#108](https://html5sec.org/#108), and [#133](https://html5sec.org/#133) of + * the [HTML5 Security Cheatsheet](https://html5sec.org/) for more details. + * + * When working with HTML you should always quote attribute values to reduce + * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping) + * for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + // Reset `lastIndex` because in IE < 9 `String#replace` does not. + string = baseToString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*", + * "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; + } + + /** + * Converts `string` to kebab case (a.k.a. spinal case). + * See [Wikipedia](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles) for + * more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__foo_bar__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Pads `string` on the left and right sides if it is shorter then the given + * padding length. The `chars` string may be truncated if the number of padding + * characters can't be evenly divided by the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = baseToString(string); + length = +length; + + var strLength = string.length; + if (strLength >= length || !nativeIsFinite(length)) { + return string; + } + var mid = (length - strLength) / 2, + leftLength = floor(mid), + rightLength = ceil(mid); + + chars = createPad('', rightLength, chars); + return chars.slice(0, leftLength) + string + chars; + } + + /** + * Pads `string` on the left side if it is shorter then the given padding + * length. The `chars` string may be truncated if the number of padding + * characters exceeds the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padLeft('abc', 6); + * // => ' abc' + * + * _.padLeft('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padLeft('abc', 3); + * // => 'abc' + */ + function padLeft(string, length, chars) { + string = baseToString(string); + return string && (createPad(string, length, chars) + string); + } + + /** + * Pads `string` on the right side if it is shorter then the given padding + * length. The `chars` string may be truncated if the number of padding + * characters exceeds the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padRight('abc', 6); + * // => 'abc ' + * + * _.padRight('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padRight('abc', 3); + * // => 'abc' + */ + function padRight(string, length, chars) { + string = baseToString(string); + return string && (string + createPad(string, length, chars)); + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, + * in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the ES5 implementation of `parseInt`. + * See the [ES5 spec](https://es5.github.io/#E) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} string The string to convert. + * @param {number} [radix] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard && isIterateeCall(string, radix, guard)) { + radix = 0; + } + return nativeParseInt(string, radix); + } + // Fallback for environments with pre-ES5 implementations. + if (nativeParseInt(whitespace + '08') != 8) { + parseInt = function(string, radix, guard) { + // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. + // Chrome fails to trim leading whitespace characters. + // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. + if (guard ? isIterateeCall(string, radix, guard) : radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + string = trim(string); + return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10)); + }; + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=0] The number of times to repeat the string. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n) { + var result = ''; + string = baseToString(string); + n = +n; + if (n < 1 || !string || !nativeIsFinite(n)) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = floor(n / 2); + string += string; + } while (n); + + return result; + } + + /** + * Converts `string` to snake case. + * See [Wikipedia](https://en.wikipedia.org/wiki/Snake_case) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--foo-bar'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Converts `string` to start case. + * See [Wikipedia](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage) + * for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__foo_bar__'); + * // => 'Foo Bar' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to search. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = baseToString(string); + position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length); + return string.lastIndexOf(target, position) == position; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is provided it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging. + * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for more details. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options] The options object. + * @param {RegExp} [options.escape] The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate] The "evaluate" delimiter. + * @param {Object} [options.imports] An object to import into the template as free variables. + * @param {RegExp} [options.interpolate] The "interpolate" delimiter. + * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. + * @param {string} [options.variable] The data object variable name. + * @param- {Object} [otherOptions] Enables the legacy `options` param signature. + * @returns {Function} Returns the compiled template function. + * @example + * + * // using the "interpolate" delimiter to create a compiled template + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // using the HTML "escape" delimiter to escape data property values + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': '} + *
  • define style rules. See the example page for examples. + *
  • mark the {@code
    } and {@code } tags in your source with
    + *    {@code class=prettyprint.}
    + *    You can also use the (html deprecated) {@code } tag, but the pretty
    + *    printer needs to do more substantial DOM manipulations to support that, so
    + *    some css styles may not be preserved.
    + * </ol>
    + * That's it.  I wanted to keep the API as simple as possible, so there's no
    + * need to specify which language the code is in, but if you wish, you can add
    + * another class to the {@code <pre>} or {@code <code>} element to specify the
    + * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
    + * starts with "lang-" followed by a file extension, specifies the file type.
    + * See the "lang-*.js" files in this directory for code that implements
    + * per-language file handlers.
    + * <p>
    + * Change log:<br>
    + * cbeust, 2006/08/22
    + * <blockquote>
    + *   Java annotations (start with "@") are now captured as literals ("lit")
    + * </blockquote>
    + * @requires console
    + */
    +
    +// JSLint declarations
    +/*global console, document, navigator, setTimeout, window, define */
    +
    +/** @define {boolean} */
    +var IN_GLOBAL_SCOPE = true;
    +
    +/**
    + * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
    + * UI events.
    + * If set to {@code false}, {@code prettyPrint()} is synchronous.
    + */
    +window['PR_SHOULD_USE_CONTINUATION'] = true;
    +
    +/**
    + * Pretty print a chunk of code.
    + * @param {string} sourceCodeHtml The HTML to pretty print.
    + * @param {string} opt_langExtension The language name to use.
    + *     Typically, a filename extension like 'cpp' or 'java'.
    + * @param {number|boolean} opt_numberLines True to number lines,
    + *     or the 1-indexed number of the first line in sourceCodeHtml.
    + * @return {string} code as html, but prettier
    + */
    +var prettyPrintOne;
    +/**
    + * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
    + * {@code class=prettyprint} and prettify them.
    + *
    + * @param {Function} opt_whenDone called when prettifying is done.
    + * @param {HTMLElement|HTMLDocument} opt_root an element or document
    + *   containing all the elements to pretty print.
    + *   Defaults to {@code document.body}.
    + */
    +var prettyPrint;
    +
    +
    +(function () {
    +  var win = window;
    +  // Keyword lists for various languages.
    +  // We use things that coerce to strings to make them compact when minified
    +  // and to defeat aggressive optimizers that fold large string constants.
    +  var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"];
    +  var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," + 
    +      "double,enum,extern,float,goto,inline,int,long,register,short,signed," +
    +      "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];
    +  var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," +
    +      "new,operator,private,protected,public,this,throw,true,try,typeof"];
    +  var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool," +
    +      "concept,concept_map,const_cast,constexpr,decltype,delegate," +
    +      "dynamic_cast,explicit,export,friend,generic,late_check," +
    +      "mutable,namespace,nullptr,property,reinterpret_cast,static_assert," +
    +      "static_cast,template,typeid,typename,using,virtual,where"];
    +  var JAVA_KEYWORDS = [COMMON_KEYWORDS,
    +      "abstract,assert,boolean,byte,extends,final,finally,implements,import," +
    +      "instanceof,interface,null,native,package,strictfp,super,synchronized," +
    +      "throws,transient"];
    +  var CSHARP_KEYWORDS = [JAVA_KEYWORDS,
    +      "as,base,by,checked,decimal,delegate,descending,dynamic,event," +
    +      "fixed,foreach,from,group,implicit,in,internal,into,is,let," +
    +      "lock,object,out,override,orderby,params,partial,readonly,ref,sbyte," +
    +      "sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort," +
    +      "var,virtual,where"];
    +  var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," +
    +      "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," +
    +      "throw,true,try,unless,until,when,while,yes";
    +  var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,
    +      "debugger,eval,export,function,get,null,set,undefined,var,with," +
    +      "Infinity,NaN"];
    +  var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +
    +      "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +
    +      "sub,undef,unless,until,use,wantarray,while,BEGIN,END";
    +  var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "and,as,assert,class,def,del," +
    +      "elif,except,exec,finally,from,global,import,in,is,lambda," +
    +      "nonlocal,not,or,pass,print,raise,try,with,yield," +
    +      "False,True,None"];
    +  var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," +
    +      "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," +
    +      "rescue,retry,self,super,then,true,undef,unless,until,when,yield," +
    +      "BEGIN,END"];
    +   var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "as,assert,const,copy,drop," +
    +      "enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv," +
    +      "pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"];
    +  var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," +
    +      "function,in,local,set,then,until"];
    +  var ALL_KEYWORDS = [
    +      CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,
    +      PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];
    +  var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;
    +
    +  // token style names.  correspond to css classes
    +  /**
    +   * token style for a string literal
    +   * @const
    +   */
    +  var PR_STRING = 'str';
    +  /**
    +   * token style for a keyword
    +   * @const
    +   */
    +  var PR_KEYWORD = 'kwd';
    +  /**
    +   * token style for a comment
    +   * @const
    +   */
    +  var PR_COMMENT = 'com';
    +  /**
    +   * token style for a type
    +   * @const
    +   */
    +  var PR_TYPE = 'typ';
    +  /**
    +   * token style for a literal value.  e.g. 1, null, true.
    +   * @const
    +   */
    +  var PR_LITERAL = 'lit';
    +  /**
    +   * token style for a punctuation string.
    +   * @const
    +   */
    +  var PR_PUNCTUATION = 'pun';
    +  /**
    +   * token style for plain text.
    +   * @const
    +   */
    +  var PR_PLAIN = 'pln';
    +
    +  /**
    +   * token style for an sgml tag.
    +   * @const
    +   */
    +  var PR_TAG = 'tag';
    +  /**
    +   * token style for a markup declaration such as a DOCTYPE.
    +   * @const
    +   */
    +  var PR_DECLARATION = 'dec';
    +  /**
    +   * token style for embedded source.
    +   * @const
    +   */
    +  var PR_SOURCE = 'src';
    +  /**
    +   * token style for an sgml attribute name.
    +   * @const
    +   */
    +  var PR_ATTRIB_NAME = 'atn';
    +  /**
    +   * token style for an sgml attribute value.
    +   * @const
    +   */
    +  var PR_ATTRIB_VALUE = 'atv';
    +
    +  /**
    +   * A class that indicates a section of markup that is not code, e.g. to allow
    +   * embedding of line numbers within code listings.
    +   * @const
    +   */
    +  var PR_NOCODE = 'nocode';
    +
    +  
    +  
    +  /**
    +   * A set of tokens that can precede a regular expression literal in
    +   * javascript
    +   * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html
    +   * has the full list, but I've removed ones that might be problematic when
    +   * seen in languages that don't support regular expression literals.
    +   *
    +   * <p>Specifically, I've removed any keywords that can't precede a regexp
    +   * literal in a syntactically legal javascript program, and I've removed the
    +   * "in" keyword since it's not a keyword in many languages, and might be used
    +   * as a count of inches.
    +   *
    +   * <p>The link above does not accurately describe EcmaScript rules since
    +   * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
    +   * very well in practice.
    +   *
    +   * @private
    +   * @const
    +   */
    +  var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*';
    +  
    +  // CAVEAT: this does not properly handle the case where a regular
    +  // expression immediately follows another since a regular expression may
    +  // have flags for case-sensitivity and the like.  Having regexp tokens
    +  // adjacent is not valid in any language I'm aware of, so I'm punting.
    +  // TODO: maybe style special characters inside a regexp as punctuation.
    +
    +  /**
    +   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
    +   * matches the union of the sets of strings matched by the input RegExp.
    +   * Since it matches globally, if the input strings have a start-of-input
    +   * anchor (/^.../), it is ignored for the purposes of unioning.
    +   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
    +   * @return {RegExp} a global regex.
    +   */
    +  function combinePrefixPatterns(regexs) {
    +    var capturedGroupIndex = 0;
    +  
    +    var needToFoldCase = false;
    +    var ignoreCase = false;
    +    for (var i = 0, n = regexs.length; i < n; ++i) {
    +      var regex = regexs[i];
    +      if (regex.ignoreCase) {
    +        ignoreCase = true;
    +      } else if (/[a-z]/i.test(regex.source.replace(
    +                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
    +        needToFoldCase = true;
    +        ignoreCase = false;
    +        break;
    +      }
    +    }
    +  
    +    var escapeCharToCodeUnit = {
    +      'b': 8,
    +      't': 9,
    +      'n': 0xa,
    +      'v': 0xb,
    +      'f': 0xc,
    +      'r': 0xd
    +    };
    +  
    +    function decodeEscape(charsetPart) {
    +      var cc0 = charsetPart.charCodeAt(0);
    +      if (cc0 !== 92 /* \\ */) {
    +        return cc0;
    +      }
    +      var c1 = charsetPart.charAt(1);
    +      cc0 = escapeCharToCodeUnit[c1];
    +      if (cc0) {
    +        return cc0;
    +      } else if ('0' <= c1 && c1 <= '7') {
    +        return parseInt(charsetPart.substring(1), 8);
    +      } else if (c1 === 'u' || c1 === 'x') {
    +        return parseInt(charsetPart.substring(2), 16);
    +      } else {
    +        return charsetPart.charCodeAt(1);
    +      }
    +    }
    +  
    +    function encodeEscape(charCode) {
    +      if (charCode < 0x20) {
    +        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
    +      }
    +      var ch = String.fromCharCode(charCode);
    +      return (ch === '\\' || ch === '-' || ch === ']' || ch === '^')
    +          ? "\\" + ch : ch;
    +    }
    +  
    +    function caseFoldCharset(charSet) {
    +      var charsetParts = charSet.substring(1, charSet.length - 1).match(
    +          new RegExp(
    +              '\\\\u[0-9A-Fa-f]{4}'
    +              + '|\\\\x[0-9A-Fa-f]{2}'
    +              + '|\\\\[0-3][0-7]{0,2}'
    +              + '|\\\\[0-7]{1,2}'
    +              + '|\\\\[\\s\\S]'
    +              + '|-'
    +              + '|[^-\\\\]',
    +              'g'));
    +      var ranges = [];
    +      var inverse = charsetParts[0] === '^';
    +  
    +      var out = ['['];
    +      if (inverse) { out.push('^'); }
    +  
    +      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
    +        var p = charsetParts[i];
    +        if (/\\[bdsw]/i.test(p)) {  // Don't muck with named groups.
    +          out.push(p);
    +        } else {
    +          var start = decodeEscape(p);
    +          var end;
    +          if (i + 2 < n && '-' === charsetParts[i + 1]) {
    +            end = decodeEscape(charsetParts[i + 2]);
    +            i += 2;
    +          } else {
    +            end = start;
    +          }
    +          ranges.push([start, end]);
    +          // If the range might intersect letters, then expand it.
    +          // This case handling is too simplistic.
    +          // It does not deal with non-latin case folding.
    +          // It works for latin source code identifiers though.
    +          if (!(end < 65 || start > 122)) {
    +            if (!(end < 65 || start > 90)) {
    +              ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
    +            }
    +            if (!(end < 97 || start > 122)) {
    +              ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
    +            }
    +          }
    +        }
    +      }
    +  
    +      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
    +      // -> [[1, 12], [14, 14], [16, 17]]
    +      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
    +      var consolidatedRanges = [];
    +      var lastRange = [];
    +      for (var i = 0; i < ranges.length; ++i) {
    +        var range = ranges[i];
    +        if (range[0] <= lastRange[1] + 1) {
    +          lastRange[1] = Math.max(lastRange[1], range[1]);
    +        } else {
    +          consolidatedRanges.push(lastRange = range);
    +        }
    +      }
    +  
    +      for (var i = 0; i < consolidatedRanges.length; ++i) {
    +        var range = consolidatedRanges[i];
    +        out.push(encodeEscape(range[0]));
    +        if (range[1] > range[0]) {
    +          if (range[1] + 1 > range[0]) { out.push('-'); }
    +          out.push(encodeEscape(range[1]));
    +        }
    +      }
    +      out.push(']');
    +      return out.join('');
    +    }
    +  
    +    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
    +      // Split into character sets, escape sequences, punctuation strings
    +      // like ('(', '(?:', ')', '^'), and runs of characters that do not
    +      // include any of the above.
    +      var parts = regex.source.match(
    +          new RegExp(
    +              '(?:'
    +              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
    +              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
    +              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
    +              + '|\\\\[0-9]+'  // a back-reference or octal escape
    +              + '|\\\\[^ux0-9]'  // other escape sequence
    +              + '|\\(\\?[:!=]'  // start of a non-capturing group
    +              + '|[\\(\\)\\^]'  // start/end of a group, or line start
    +              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
    +              + ')',
    +              'g'));
    +      var n = parts.length;
    +  
    +      // Maps captured group numbers to the number they will occupy in
    +      // the output or to -1 if that has not been determined, or to
    +      // undefined if they need not be capturing in the output.
    +      var capturedGroups = [];
    +  
    +      // Walk over and identify back references to build the capturedGroups
    +      // mapping.
    +      for (var i = 0, groupIndex = 0; i < n; ++i) {
    +        var p = parts[i];
    +        if (p === '(') {
    +          // groups are 1-indexed, so max group index is count of '('
    +          ++groupIndex;
    +        } else if ('\\' === p.charAt(0)) {
    +          var decimalValue = +p.substring(1);
    +          if (decimalValue) {
    +            if (decimalValue <= groupIndex) {
    +              capturedGroups[decimalValue] = -1;
    +            } else {
    +              // Replace with an unambiguous escape sequence so that
    +              // an octal escape sequence does not turn into a backreference
    +              // to a capturing group from an earlier regex.
    +              parts[i] = encodeEscape(decimalValue);
    +            }
    +          }
    +        }
    +      }
    +  
    +      // Renumber groups and reduce capturing groups to non-capturing groups
    +      // where possible.
    +      for (var i = 1; i < capturedGroups.length; ++i) {
    +        if (-1 === capturedGroups[i]) {
    +          capturedGroups[i] = ++capturedGroupIndex;
    +        }
    +      }
    +      for (var i = 0, groupIndex = 0; i < n; ++i) {
    +        var p = parts[i];
    +        if (p === '(') {
    +          ++groupIndex;
    +          if (!capturedGroups[groupIndex]) {
    +            parts[i] = '(?:';
    +          }
    +        } else if ('\\' === p.charAt(0)) {
    +          var decimalValue = +p.substring(1);
    +          if (decimalValue && decimalValue <= groupIndex) {
    +            parts[i] = '\\' + capturedGroups[decimalValue];
    +          }
    +        }
    +      }
    +  
    +      // Remove any prefix anchors so that the output will match anywhere.
    +      // ^^ really does mean an anchored match though.
    +      for (var i = 0; i < n; ++i) {
    +        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
    +      }
    +  
    +      // Expand letters to groups to handle mixing of case-sensitive and
    +      // case-insensitive patterns if necessary.
    +      if (regex.ignoreCase && needToFoldCase) {
    +        for (var i = 0; i < n; ++i) {
    +          var p = parts[i];
    +          var ch0 = p.charAt(0);
    +          if (p.length >= 2 && ch0 === '[') {
    +            parts[i] = caseFoldCharset(p);
    +          } else if (ch0 !== '\\') {
    +            // TODO: handle letters in numeric escapes.
    +            parts[i] = p.replace(
    +                /[a-zA-Z]/g,
    +                function (ch) {
    +                  var cc = ch.charCodeAt(0);
    +                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
    +                });
    +          }
    +        }
    +      }
    +  
    +      return parts.join('');
    +    }
    +  
    +    var rewritten = [];
    +    for (var i = 0, n = regexs.length; i < n; ++i) {
    +      var regex = regexs[i];
    +      if (regex.global || regex.multiline) { throw new Error('' + regex); }
    +      rewritten.push(
    +          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
    +    }
    +  
    +    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
    +  }
    +
    +  /**
    +   * Split markup into a string of source code and an array mapping ranges in
    +   * that string to the text nodes in which they appear.
    +   *
    +   * <p>
    +   * The HTML DOM structure:</p>
    +   * <pre>
    +   * (Element   "p"
    +   *   (Element "b"
    +   *     (Text  "print "))       ; #1
    +   *   (Text    "'Hello '")      ; #2
    +   *   (Element "br")            ; #3
    +   *   (Text    "  + 'World';")) ; #4
    +   * </pre>
    +   * <p>
    +   * corresponds to the HTML
    +   * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>
    +   *
    +   * <p>
    +   * It will produce the output:</p>
    +   * <pre>
    +   * {
    +   *   sourceCode: "print 'Hello '\n  + 'World';",
    +   *   //                     1          2
    +   *   //           012345678901234 5678901234567
    +   *   spans: [0, #1, 6, #2, 14, #3, 15, #4]
    +   * }
    +   * </pre>
    +   * <p>
    +   * where #1 is a reference to the {@code "print "} text node above, and so
    +   * on for the other text nodes.
    +   * </p>
    +   *
    +   * <p>
    +   * The {@code} spans array is an array of pairs.  Even elements are the start
    +   * indices of substrings, and odd elements are the text nodes (or BR elements)
    +   * that contain the text for those substrings.
    +   * Substrings continue until the next index or the end of the source.
    +   * </p>
    +   *
    +   * @param {Node} node an HTML DOM subtree containing source-code.
    +   * @param {boolean} isPreformatted true if white-space in text nodes should
    +   *    be considered significant.
    +   * @return {Object} source code and the text nodes in which they occur.
    +   */
    +  function extractSourceSpans(node, isPreformatted) {
    +    var nocode = /(?:^|\s)nocode(?:\s|$)/;
    +  
    +    var chunks = [];
    +    var length = 0;
    +    var spans = [];
    +    var k = 0;
    +  
    +    function walk(node) {
    +      var type = node.nodeType;
    +      if (type == 1) {  // Element
    +        if (nocode.test(node.className)) { return; }
    +        for (var child = node.firstChild; child; child = child.nextSibling) {
    +          walk(child);
    +        }
    +        var nodeName = node.nodeName.toLowerCase();
    +        if ('br' === nodeName || 'li' === nodeName) {
    +          chunks[k] = '\n';
    +          spans[k << 1] = length++;
    +          spans[(k++ << 1) | 1] = node;
    +        }
    +      } else if (type == 3 || type == 4) {  // Text
    +        var text = node.nodeValue;
    +        if (text.length) {
    +          if (!isPreformatted) {
    +            text = text.replace(/[ \t\r\n]+/g, ' ');
    +          } else {
    +            text = text.replace(/\r\n?/g, '\n');  // Normalize newlines.
    +          }
    +          // TODO: handle tabs here?
    +          chunks[k] = text;
    +          spans[k << 1] = length;
    +          length += text.length;
    +          spans[(k++ << 1) | 1] = node;
    +        }
    +      }
    +    }
    +  
    +    walk(node);
    +  
    +    return {
    +      sourceCode: chunks.join('').replace(/\n$/, ''),
    +      spans: spans
    +    };
    +  }
    +
    +  /**
    +   * Apply the given language handler to sourceCode and add the resulting
    +   * decorations to out.
    +   * @param {number} basePos the index of sourceCode within the chunk of source
    +   *    whose decorations are already present on out.
    +   */
    +  function appendDecorations(basePos, sourceCode, langHandler, out) {
    +    if (!sourceCode) { return; }
    +    var job = {
    +      sourceCode: sourceCode,
    +      basePos: basePos
    +    };
    +    langHandler(job);
    +    out.push.apply(out, job.decorations);
    +  }
    +
    +  var notWs = /\S/;
    +
    +  /**
    +   * Given an element, if it contains only one child element and any text nodes
    +   * it contains contain only space characters, return the sole child element.
    +   * Otherwise returns undefined.
    +   * <p>
    +   * This is meant to return the CODE element in {@code <pre><code ...>} when
    +   * there is a single child element that contains all the non-space textual
    +   * content, but not to return anything where there are multiple child elements
    +   * as in {@code <pre><code>...</code><code>...</code></pre>} or when there
    +   * is textual content.
    +   */
    +  function childContentWrapper(element) {
    +    var wrapper = undefined;
    +    for (var c = element.firstChild; c; c = c.nextSibling) {
    +      var type = c.nodeType;
    +      wrapper = (type === 1)  // Element Node
    +          ? (wrapper ? element : c)
    +          : (type === 3)  // Text Node
    +          ? (notWs.test(c.nodeValue) ? element : wrapper)
    +          : wrapper;
    +    }
    +    return wrapper === element ? undefined : wrapper;
    +  }
    +
    +  /** Given triples of [style, pattern, context] returns a lexing function,
    +    * The lexing function interprets the patterns to find token boundaries and
    +    * returns a decoration list of the form
    +    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
    +    * where index_n is an index into the sourceCode, and style_n is a style
    +    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
    +    * all characters in sourceCode[index_n-1:index_n].
    +    *
    +    * The stylePatterns is a list whose elements have the form
    +    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
    +    *
    +    * Style is a style constant like PR_PLAIN, or can be a string of the
    +    * form 'lang-FOO', where FOO is a language extension describing the
    +    * language of the portion of the token in $1 after pattern executes.
    +    * E.g., if style is 'lang-lisp', and group 1 contains the text
    +    * '(hello (world))', then that portion of the token will be passed to the
    +    * registered lisp handler for formatting.
    +    * The text before and after group 1 will be restyled using this decorator
    +    * so decorators should take care that this doesn't result in infinite
    +    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
    +    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
    +    * '<script>foo()<\/script>', which would cause the current decorator to
    +    * be called with '<script>' which would not match the same rule since
    +    * group 1 must not be empty, so it would be instead styled as PR_TAG by
    +    * the generic tag rule.  The handler registered for the 'js' extension would
    +    * then be called with 'foo()', and finally, the current decorator would
    +    * be called with '<\/script>' which would not match the original rule and
    +    * so the generic tag rule would identify it as a tag.
    +    *
    +    * Pattern must only match prefixes, and if it matches a prefix, then that
    +    * match is considered a token with the same style.
    +    *
    +    * Context is applied to the last non-whitespace, non-comment token
    +    * recognized.
    +    *
    +    * Shortcut is an optional string of characters, any of which, if the first
    +    * character, gurantee that this pattern and only this pattern matches.
    +    *
    +    * @param {Array} shortcutStylePatterns patterns that always start with
    +    *   a known character.  Must have a shortcut string.
    +    * @param {Array} fallthroughStylePatterns patterns that will be tried in
    +    *   order if the shortcut ones fail.  May have shortcuts.
    +    *
    +    * @return {function (Object)} a
    +    *   function that takes source code and returns a list of decorations.
    +    */
    +  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
    +    var shortcuts = {};
    +    var tokenizer;
    +    (function () {
    +      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
    +      var allRegexs = [];
    +      var regexKeys = {};
    +      for (var i = 0, n = allPatterns.length; i < n; ++i) {
    +        var patternParts = allPatterns[i];
    +        var shortcutChars = patternParts[3];
    +        if (shortcutChars) {
    +          for (var c = shortcutChars.length; --c >= 0;) {
    +            shortcuts[shortcutChars.charAt(c)] = patternParts;
    +          }
    +        }
    +        var regex = patternParts[1];
    +        var k = '' + regex;
    +        if (!regexKeys.hasOwnProperty(k)) {
    +          allRegexs.push(regex);
    +          regexKeys[k] = null;
    +        }
    +      }
    +      allRegexs.push(/[\0-\uffff]/);
    +      tokenizer = combinePrefixPatterns(allRegexs);
    +    })();
    +
    +    var nPatterns = fallthroughStylePatterns.length;
    +
    +    /**
    +     * Lexes job.sourceCode and produces an output array job.decorations of
    +     * style classes preceded by the position at which they start in
    +     * job.sourceCode in order.
    +     *
    +     * @param {Object} job an object like <pre>{
    +     *    sourceCode: {string} sourceText plain text,
    +     *    basePos: {int} position of job.sourceCode in the larger chunk of
    +     *        sourceCode.
    +     * }</pre>
    +     */
    +    var decorate = function (job) {
    +      var sourceCode = job.sourceCode, basePos = job.basePos;
    +      /** Even entries are positions in source in ascending order.  Odd enties
    +        * are style markers (e.g., PR_COMMENT) that run from that position until
    +        * the end.
    +        * @type {Array.<number|string>}
    +        */
    +      var decorations = [basePos, PR_PLAIN];
    +      var pos = 0;  // index into sourceCode
    +      var tokens = sourceCode.match(tokenizer) || [];
    +      var styleCache = {};
    +
    +      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
    +        var token = tokens[ti];
    +        var style = styleCache[token];
    +        var match = void 0;
    +
    +        var isEmbedded;
    +        if (typeof style === 'string') {
    +          isEmbedded = false;
    +        } else {
    +          var patternParts = shortcuts[token.charAt(0)];
    +          if (patternParts) {
    +            match = token.match(patternParts[1]);
    +            style = patternParts[0];
    +          } else {
    +            for (var i = 0; i < nPatterns; ++i) {
    +              patternParts = fallthroughStylePatterns[i];
    +              match = token.match(patternParts[1]);
    +              if (match) {
    +                style = patternParts[0];
    +                break;
    +              }
    +            }
    +
    +            if (!match) {  // make sure that we make progress
    +              style = PR_PLAIN;
    +            }
    +          }
    +
    +          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
    +          if (isEmbedded && !(match && typeof match[1] === 'string')) {
    +            isEmbedded = false;
    +            style = PR_SOURCE;
    +          }
    +
    +          if (!isEmbedded) { styleCache[token] = style; }
    +        }
    +
    +        var tokenStart = pos;
    +        pos += token.length;
    +
    +        if (!isEmbedded) {
    +          decorations.push(basePos + tokenStart, style);
    +        } else {  // Treat group 1 as an embedded block of source code.
    +          var embeddedSource = match[1];
    +          var embeddedSourceStart = token.indexOf(embeddedSource);
    +          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
    +          if (match[2]) {
    +            // If embeddedSource can be blank, then it would match at the
    +            // beginning which would cause us to infinitely recurse on the
    +            // entire token, so we catch the right context in match[2].
    +            embeddedSourceEnd = token.length - match[2].length;
    +            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
    +          }
    +          var lang = style.substring(5);
    +          // Decorate the left of the embedded source
    +          appendDecorations(
    +              basePos + tokenStart,
    +              token.substring(0, embeddedSourceStart),
    +              decorate, decorations);
    +          // Decorate the embedded source
    +          appendDecorations(
    +              basePos + tokenStart + embeddedSourceStart,
    +              embeddedSource,
    +              langHandlerForExtension(lang, embeddedSource),
    +              decorations);
    +          // Decorate the right of the embedded section
    +          appendDecorations(
    +              basePos + tokenStart + embeddedSourceEnd,
    +              token.substring(embeddedSourceEnd),
    +              decorate, decorations);
    +        }
    +      }
    +      job.decorations = decorations;
    +    };
    +    return decorate;
    +  }
    +
    +  /** returns a function that produces a list of decorations from source text.
    +    *
    +    * This code treats ", ', and ` as string delimiters, and \ as a string
    +    * escape.  It does not recognize perl's qq() style strings.
    +    * It has no special handling for double delimiter escapes as in basic, or
    +    * the tripled delimiters used in python, but should work on those regardless
    +    * although in those cases a single string literal may be broken up into
    +    * multiple adjacent string literals.
    +    *
    +    * It recognizes C, C++, and shell style comments.
    +    *
    +    * @param {Object} options a set of optional parameters.
    +    * @return {function (Object)} a function that examines the source code
    +    *     in the input job and builds the decoration list.
    +    */
    +  function sourceDecorator(options) {
    +    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
    +    if (options['tripleQuotedStrings']) {
    +      // '''multi-line-string''', 'single-line-string', and double-quoted
    +      shortcutStylePatterns.push(
    +          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
    +           null, '\'"']);
    +    } else if (options['multiLineStrings']) {
    +      // 'multi-line-string', "multi-line-string"
    +      shortcutStylePatterns.push(
    +          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
    +           null, '\'"`']);
    +    } else {
    +      // 'single-line-string', "single-line-string"
    +      shortcutStylePatterns.push(
    +          [PR_STRING,
    +           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
    +           null, '"\'']);
    +    }
    +    if (options['verbatimStrings']) {
    +      // verbatim-string-literal production from the C# grammar.  See issue 93.
    +      fallthroughStylePatterns.push(
    +          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
    +    }
    +    var hc = options['hashComments'];
    +    if (hc) {
    +      if (options['cStyleComments']) {
    +        if (hc > 1) {  // multiline hash comments
    +          shortcutStylePatterns.push(
    +              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
    +        } else {
    +          // Stop C preprocessor declarations at an unclosed open comment
    +          shortcutStylePatterns.push(
    +              [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
    +               null, '#']);
    +        }
    +        // #include <stdio.h>
    +        fallthroughStylePatterns.push(
    +            [PR_STRING,
    +             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,
    +             null]);
    +      } else {
    +        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
    +      }
    +    }
    +    if (options['cStyleComments']) {
    +      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
    +      fallthroughStylePatterns.push(
    +          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
    +    }
    +    var regexLiterals = options['regexLiterals'];
    +    if (regexLiterals) {
    +      /**
    +       * @const
    +       */
    +      var regexExcls = regexLiterals > 1
    +        ? ''  // Multiline regex literals
    +        : '\n\r';
    +      /**
    +       * @const
    +       */
    +      var regexAny = regexExcls ? '.' : '[\\S\\s]';
    +      /**
    +       * @const
    +       */
    +      var REGEX_LITERAL = (
    +          // A regular expression literal starts with a slash that is
    +          // not followed by * or / so that it is not confused with
    +          // comments.
    +          '/(?=[^/*' + regexExcls + '])'
    +          // and then contains any number of raw characters,
    +          + '(?:[^/\\x5B\\x5C' + regexExcls + ']'
    +          // escape sequences (\x5C),
    +          +    '|\\x5C' + regexAny
    +          // or non-nesting character sets (\x5B\x5D);
    +          +    '|\\x5B(?:[^\\x5C\\x5D' + regexExcls + ']'
    +          +             '|\\x5C' + regexAny + ')*(?:\\x5D|$))+'
    +          // finally closed by a /.
    +          + '/');
    +      fallthroughStylePatterns.push(
    +          ['lang-regex',
    +           RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
    +           ]);
    +    }
    +
    +    var types = options['types'];
    +    if (types) {
    +      fallthroughStylePatterns.push([PR_TYPE, types]);
    +    }
    +
    +    var keywords = ("" + options['keywords']).replace(/^ | $/g, '');
    +    if (keywords.length) {
    +      fallthroughStylePatterns.push(
    +          [PR_KEYWORD,
    +           new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'),
    +           null]);
    +    }
    +
    +    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
    +
    +    var punctuation =
    +      // The Bash man page says
    +
    +      // A word is a sequence of characters considered as a single
    +      // unit by GRUB. Words are separated by metacharacters,
    +      // which are the following plus space, tab, and newline: { }
    +      // | & $ ; < >
    +      // ...
    +      
    +      // A word beginning with # causes that word and all remaining
    +      // characters on that line to be ignored.
    +
    +      // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a
    +      // comment but empirically
    +      // $ echo {#}
    +      // {#}
    +      // $ echo \$#
    +      // $#
    +      // $ echo }#
    +      // }#
    +
    +      // so /(?:^|[|&;<>\s])/ is more appropriate.
    +
    +      // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3
    +      // suggests that this definition is compatible with a
    +      // default mode that tries to use a single token definition
    +      // to recognize both bash/python style comments and C
    +      // preprocessor directives.
    +
    +      // This definition of punctuation does not include # in the list of
    +      // follow-on exclusions, so # will not be broken before if preceeded
    +      // by a punctuation character.  We could try to exclude # after
    +      // [|&;<>] but that doesn't seem to cause many major problems.
    +      // If that does turn out to be a problem, we should change the below
    +      // when hc is truthy to include # in the run of punctuation characters
    +      // only when not followint [|&;<>].
    +      '^.[^\\s\\w.$@\'"`/\\\\]*';
    +    if (options['regexLiterals']) {
    +      punctuation += '(?!\s*\/)';
    +    }
    +
    +    fallthroughStylePatterns.push(
    +        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
    +        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
    +        [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null],
    +        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
    +        [PR_LITERAL,
    +         new RegExp(
    +             '^(?:'
    +             // A hex number
    +             + '0x[a-f0-9]+'
    +             // or an octal or decimal number,
    +             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
    +             // possibly in scientific notation
    +             + '(?:e[+\\-]?\\d+)?'
    +             + ')'
    +             // with an optional modifier like UL for unsigned long
    +             + '[a-z]*', 'i'),
    +         null, '0123456789'],
    +        // Don't treat escaped quotes in bash as starting strings.
    +        // See issue 144.
    +        [PR_PLAIN,       /^\\[\s\S]?/, null],
    +        [PR_PUNCTUATION, new RegExp(punctuation), null]);
    +
    +    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
    +  }
    +
    +  var decorateSource = sourceDecorator({
    +        'keywords': ALL_KEYWORDS,
    +        'hashComments': true,
    +        'cStyleComments': true,
    +        'multiLineStrings': true,
    +        'regexLiterals': true
    +      });
    +
    +  /**
    +   * Given a DOM subtree, wraps it in a list, and puts each line into its own
    +   * list item.
    +   *
    +   * @param {Node} node modified in place.  Its content is pulled into an
    +   *     HTMLOListElement, and each line is moved into a separate list item.
    +   *     This requires cloning elements, so the input might not have unique
    +   *     IDs after numbering.
    +   * @param {boolean} isPreformatted true iff white-space in text nodes should
    +   *     be treated as significant.
    +   */
    +  function numberLines(node, opt_startLineNum, isPreformatted) {
    +    var nocode = /(?:^|\s)nocode(?:\s|$)/;
    +    var lineBreak = /\r\n?|\n/;
    +  
    +    var document = node.ownerDocument;
    +  
    +    var li = document.createElement('li');
    +    while (node.firstChild) {
    +      li.appendChild(node.firstChild);
    +    }
    +    // An array of lines.  We split below, so this is initialized to one
    +    // un-split line.
    +    var listItems = [li];
    +  
    +    function walk(node) {
    +      var type = node.nodeType;
    +      if (type == 1 && !nocode.test(node.className)) {  // Element
    +        if ('br' === node.nodeName) {
    +          breakAfter(node);
    +          // Discard the <BR> since it is now flush against a </LI>.
    +          if (node.parentNode) {
    +            node.parentNode.removeChild(node);
    +          }
    +        } else {
    +          for (var child = node.firstChild; child; child = child.nextSibling) {
    +            walk(child);
    +          }
    +        }
    +      } else if ((type == 3 || type == 4) && isPreformatted) {  // Text
    +        var text = node.nodeValue;
    +        var match = text.match(lineBreak);
    +        if (match) {
    +          var firstLine = text.substring(0, match.index);
    +          node.nodeValue = firstLine;
    +          var tail = text.substring(match.index + match[0].length);
    +          if (tail) {
    +            var parent = node.parentNode;
    +            parent.insertBefore(
    +              document.createTextNode(tail), node.nextSibling);
    +          }
    +          breakAfter(node);
    +          if (!firstLine) {
    +            // Don't leave blank text nodes in the DOM.
    +            node.parentNode.removeChild(node);
    +          }
    +        }
    +      }
    +    }
    +  
    +    // Split a line after the given node.
    +    function breakAfter(lineEndNode) {
    +      // If there's nothing to the right, then we can skip ending the line
    +      // here, and move root-wards since splitting just before an end-tag
    +      // would require us to create a bunch of empty copies.
    +      while (!lineEndNode.nextSibling) {
    +        lineEndNode = lineEndNode.parentNode;
    +        if (!lineEndNode) { return; }
    +      }
    +  
    +      function breakLeftOf(limit, copy) {
    +        // Clone shallowly if this node needs to be on both sides of the break.
    +        var rightSide = copy ? limit.cloneNode(false) : limit;
    +        var parent = limit.parentNode;
    +        if (parent) {
    +          // We clone the parent chain.
    +          // This helps us resurrect important styling elements that cross lines.
    +          // E.g. in <i>Foo<br>Bar</i>
    +          // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.
    +          var parentClone = breakLeftOf(parent, 1);
    +          // Move the clone and everything to the right of the original
    +          // onto the cloned parent.
    +          var next = limit.nextSibling;
    +          parentClone.appendChild(rightSide);
    +          for (var sibling = next; sibling; sibling = next) {
    +            next = sibling.nextSibling;
    +            parentClone.appendChild(sibling);
    +          }
    +        }
    +        return rightSide;
    +      }
    +  
    +      var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);
    +  
    +      // Walk the parent chain until we reach an unattached LI.
    +      for (var parent;
    +           // Check nodeType since IE invents document fragments.
    +           (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {
    +        copiedListItem = parent;
    +      }
    +      // Put it on the list of lines for later processing.
    +      listItems.push(copiedListItem);
    +    }
    +  
    +    // Split lines while there are lines left to split.
    +    for (var i = 0;  // Number of lines that have been split so far.
    +         i < listItems.length;  // length updated by breakAfter calls.
    +         ++i) {
    +      walk(listItems[i]);
    +    }
    +  
    +    // Make sure numeric indices show correctly.
    +    if (opt_startLineNum === (opt_startLineNum|0)) {
    +      listItems[0].setAttribute('value', opt_startLineNum);
    +    }
    +  
    +    var ol = document.createElement('ol');
    +    ol.className = 'linenums';
    +    var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;
    +    for (var i = 0, n = listItems.length; i < n; ++i) {
    +      li = listItems[i];
    +      // Stick a class on the LIs so that stylesheets can
    +      // color odd/even rows, or any other row pattern that
    +      // is co-prime with 10.
    +      li.className = 'L' + ((i + offset) % 10);
    +      if (!li.firstChild) {
    +        li.appendChild(document.createTextNode('\xA0'));
    +      }
    +      ol.appendChild(li);
    +    }
    +  
    +    node.appendChild(ol);
    +  }
    +  /**
    +   * Breaks {@code job.sourceCode} around style boundaries in
    +   * {@code job.decorations} and modifies {@code job.sourceNode} in place.
    +   * @param {Object} job like <pre>{
    +   *    sourceCode: {string} source as plain text,
    +   *    sourceNode: {HTMLElement} the element containing the source,
    +   *    spans: {Array.<number|Node>} alternating span start indices into source
    +   *       and the text node or element (e.g. {@code <BR>}) corresponding to that
    +   *       span.
    +   *    decorations: {Array.<number|string} an array of style classes preceded
    +   *       by the position at which they start in job.sourceCode in order
    +   * }</pre>
    +   * @private
    +   */
    +  function recombineTagsAndDecorations(job) {
    +    var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent);
    +    isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;
    +    var newlineRe = /\n/g;
    +  
    +    var source = job.sourceCode;
    +    var sourceLength = source.length;
    +    // Index into source after the last code-unit recombined.
    +    var sourceIndex = 0;
    +  
    +    var spans = job.spans;
    +    var nSpans = spans.length;
    +    // Index into spans after the last span which ends at or before sourceIndex.
    +    var spanIndex = 0;
    +  
    +    var decorations = job.decorations;
    +    var nDecorations = decorations.length;
    +    // Index into decorations after the last decoration which ends at or before
    +    // sourceIndex.
    +    var decorationIndex = 0;
    +  
    +    // Remove all zero-length decorations.
    +    decorations[nDecorations] = sourceLength;
    +    var decPos, i;
    +    for (i = decPos = 0; i < nDecorations;) {
    +      if (decorations[i] !== decorations[i + 2]) {
    +        decorations[decPos++] = decorations[i++];
    +        decorations[decPos++] = decorations[i++];
    +      } else {
    +        i += 2;
    +      }
    +    }
    +    nDecorations = decPos;
    +  
    +    // Simplify decorations.
    +    for (i = decPos = 0; i < nDecorations;) {
    +      var startPos = decorations[i];
    +      // Conflate all adjacent decorations that use the same style.
    +      var startDec = decorations[i + 1];
    +      var end = i + 2;
    +      while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {
    +        end += 2;
    +      }
    +      decorations[decPos++] = startPos;
    +      decorations[decPos++] = startDec;
    +      i = end;
    +    }
    +  
    +    nDecorations = decorations.length = decPos;
    +  
    +    var sourceNode = job.sourceNode;
    +    var oldDisplay;
    +    if (sourceNode) {
    +      oldDisplay = sourceNode.style.display;
    +      sourceNode.style.display = 'none';
    +    }
    +    try {
    +      var decoration = null;
    +      while (spanIndex < nSpans) {
    +        var spanStart = spans[spanIndex];
    +        var spanEnd = spans[spanIndex + 2] || sourceLength;
    +  
    +        var decEnd = decorations[decorationIndex + 2] || sourceLength;
    +  
    +        var end = Math.min(spanEnd, decEnd);
    +  
    +        var textNode = spans[spanIndex + 1];
    +        var styledText;
    +        if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s
    +            // Don't introduce spans around empty text nodes.
    +            && (styledText = source.substring(sourceIndex, end))) {
    +          // This may seem bizarre, and it is.  Emitting LF on IE causes the
    +          // code to display with spaces instead of line breaks.
    +          // Emitting Windows standard issue linebreaks (CRLF) causes a blank
    +          // space to appear at the beginning of every line but the first.
    +          // Emitting an old Mac OS 9 line separator makes everything spiffy.
    +          if (isIE8OrEarlier) {
    +            styledText = styledText.replace(newlineRe, '\r');
    +          }
    +          textNode.nodeValue = styledText;
    +          var document = textNode.ownerDocument;
    +          var span = document.createElement('span');
    +          span.className = decorations[decorationIndex + 1];
    +          var parentNode = textNode.parentNode;
    +          parentNode.replaceChild(span, textNode);
    +          span.appendChild(textNode);
    +          if (sourceIndex < spanEnd) {  // Split off a text node.
    +            spans[spanIndex + 1] = textNode
    +                // TODO: Possibly optimize by using '' if there's no flicker.
    +                = document.createTextNode(source.substring(end, spanEnd));
    +            parentNode.insertBefore(textNode, span.nextSibling);
    +          }
    +        }
    +  
    +        sourceIndex = end;
    +  
    +        if (sourceIndex >= spanEnd) {
    +          spanIndex += 2;
    +        }
    +        if (sourceIndex >= decEnd) {
    +          decorationIndex += 2;
    +        }
    +      }
    +    } finally {
    +      if (sourceNode) {
    +        sourceNode.style.display = oldDisplay;
    +      }
    +    }
    +  }
    +
    +  /** Maps language-specific file extensions to handlers. */
    +  var langHandlerRegistry = {};
    +  /** Register a language handler for the given file extensions.
    +    * @param {function (Object)} handler a function from source code to a list
    +    *      of decorations.  Takes a single argument job which describes the
    +    *      state of the computation.   The single parameter has the form
    +    *      {@code {
    +    *        sourceCode: {string} as plain text.
    +    *        decorations: {Array.<number|string>} an array of style classes
    +    *                     preceded by the position at which they start in
    +    *                     job.sourceCode in order.
    +    *                     The language handler should assigned this field.
    +    *        basePos: {int} the position of source in the larger source chunk.
    +    *                 All positions in the output decorations array are relative
    +    *                 to the larger source chunk.
    +    *      } }
    +    * @param {Array.<string>} fileExtensions
    +    */
    +  function registerLangHandler(handler, fileExtensions) {
    +    for (var i = fileExtensions.length; --i >= 0;) {
    +      var ext = fileExtensions[i];
    +      if (!langHandlerRegistry.hasOwnProperty(ext)) {
    +        langHandlerRegistry[ext] = handler;
    +      } else if (win['console']) {
    +        console['warn']('cannot override language handler %s', ext);
    +      }
    +    }
    +  }
    +  function langHandlerForExtension(extension, source) {
    +    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
    +      // Treat it as markup if the first non whitespace character is a < and
    +      // the last non-whitespace character is a >.
    +      extension = /^\s*</.test(source)
    +          ? 'default-markup'
    +          : 'default-code';
    +    }
    +    return langHandlerRegistry[extension];
    +  }
    +  registerLangHandler(decorateSource, ['default-code']);
    +  registerLangHandler(
    +      createSimpleLexer(
    +          [],
    +          [
    +           [PR_PLAIN,       /^[^<?]+/],
    +           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
    +           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
    +           // Unescaped content in an unknown language
    +           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
    +           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
    +           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
    +           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
    +           // Unescaped content in javascript.  (Or possibly vbscript).
    +           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
    +           // Contains unescaped stylesheet content
    +           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
    +           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
    +          ]),
    +      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
    +  registerLangHandler(
    +      createSimpleLexer(
    +          [
    +           [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
    +           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
    +           ],
    +          [
    +           [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
    +           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
    +           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
    +           [PR_PUNCTUATION,  /^[=<>\/]+/],
    +           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
    +           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
    +           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
    +           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
    +           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
    +           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
    +           ]),
    +      ['in.tag']);
    +  registerLangHandler(
    +      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': CPP_KEYWORDS,
    +          'hashComments': true,
    +          'cStyleComments': true,
    +          'types': C_TYPES
    +        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': 'null,true,false'
    +        }), ['json']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': CSHARP_KEYWORDS,
    +          'hashComments': true,
    +          'cStyleComments': true,
    +          'verbatimStrings': true,
    +          'types': C_TYPES
    +        }), ['cs']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': JAVA_KEYWORDS,
    +          'cStyleComments': true
    +        }), ['java']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': SH_KEYWORDS,
    +          'hashComments': true,
    +          'multiLineStrings': true
    +        }), ['bash', 'bsh', 'csh', 'sh']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': PYTHON_KEYWORDS,
    +          'hashComments': true,
    +          'multiLineStrings': true,
    +          'tripleQuotedStrings': true
    +        }), ['cv', 'py', 'python']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': PERL_KEYWORDS,
    +          'hashComments': true,
    +          'multiLineStrings': true,
    +          'regexLiterals': 2  // multiline regex literals
    +        }), ['perl', 'pl', 'pm']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': RUBY_KEYWORDS,
    +          'hashComments': true,
    +          'multiLineStrings': true,
    +          'regexLiterals': true
    +        }), ['rb', 'ruby']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': JSCRIPT_KEYWORDS,
    +          'cStyleComments': true,
    +          'regexLiterals': true
    +        }), ['javascript', 'js']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': COFFEE_KEYWORDS,
    +          'hashComments': 3,  // ### style block comments
    +          'cStyleComments': true,
    +          'multilineStrings': true,
    +          'tripleQuotedStrings': true,
    +          'regexLiterals': true
    +        }), ['coffee']);
    +  registerLangHandler(sourceDecorator({
    +          'keywords': RUST_KEYWORDS,
    +          'cStyleComments': true,
    +          'multilineStrings': true
    +        }), ['rc', 'rs', 'rust']);
    +  registerLangHandler(
    +      createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
    +
    +  function applyDecorator(job) {
    +    var opt_langExtension = job.langExtension;
    +
    +    try {
    +      // Extract tags, and convert the source code to plain text.
    +      var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);
    +      /** Plain text. @type {string} */
    +      var source = sourceAndSpans.sourceCode;
    +      job.sourceCode = source;
    +      job.spans = sourceAndSpans.spans;
    +      job.basePos = 0;
    +
    +      // Apply the appropriate language handler
    +      langHandlerForExtension(opt_langExtension, source)(job);
    +
    +      // Integrate the decorations and tags back into the source code,
    +      // modifying the sourceNode in place.
    +      recombineTagsAndDecorations(job);
    +    } catch (e) {
    +      if (win['console']) {
    +        console['log'](e && e['stack'] || e);
    +      }
    +    }
    +  }
    +
    +  /**
    +   * Pretty print a chunk of code.
    +   * @param sourceCodeHtml {string} The HTML to pretty print.
    +   * @param opt_langExtension {string} The language name to use.
    +   *     Typically, a filename extension like 'cpp' or 'java'.
    +   * @param opt_numberLines {number|boolean} True to number lines,
    +   *     or the 1-indexed number of the first line in sourceCodeHtml.
    +   */
    +  function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
    +    var container = document.createElement('div');
    +    // This could cause images to load and onload listeners to fire.
    +    // E.g. <img onerror="alert(1337)" src="nosuchimage.png">.
    +    // We assume that the inner HTML is from a trusted source.
    +    // The pre-tag is required for IE8 which strips newlines from innerHTML
    +    // when it is injected into a <pre> tag.
    +    // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
    +    // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
    +    container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';
    +    container = container.firstChild;
    +    if (opt_numberLines) {
    +      numberLines(container, opt_numberLines, true);
    +    }
    +
    +    var job = {
    +      langExtension: opt_langExtension,
    +      numberLines: opt_numberLines,
    +      sourceNode: container,
    +      pre: 1
    +    };
    +    applyDecorator(job);
    +    return container.innerHTML;
    +  }
    +
    +   /**
    +    * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
    +    * {@code class=prettyprint} and prettify them.
    +    *
    +    * @param {Function} opt_whenDone called when prettifying is done.
    +    * @param {HTMLElement|HTMLDocument} opt_root an element or document
    +    *   containing all the elements to pretty print.
    +    *   Defaults to {@code document.body}.
    +    */
    +  function $prettyPrint(opt_whenDone, opt_root) {
    +    var root = opt_root || document.body;
    +    var doc = root.ownerDocument || document;
    +    function byTagName(tn) { return root.getElementsByTagName(tn); }
    +    // fetch a list of nodes to rewrite
    +    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
    +    var elements = [];
    +    for (var i = 0; i < codeSegments.length; ++i) {
    +      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
    +        elements.push(codeSegments[i][j]);
    +      }
    +    }
    +    codeSegments = null;
    +
    +    var clock = Date;
    +    if (!clock['now']) {
    +      clock = { 'now': function () { return +(new Date); } };
    +    }
    +
    +    // The loop is broken into a series of continuations to make sure that we
    +    // don't make the browser unresponsive when rewriting a large page.
    +    var k = 0;
    +    var prettyPrintingJob;
    +
    +    var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/;
    +    var prettyPrintRe = /\bprettyprint\b/;
    +    var prettyPrintedRe = /\bprettyprinted\b/;
    +    var preformattedTagNameRe = /pre|xmp/i;
    +    var codeRe = /^code$/i;
    +    var preCodeXmpRe = /^(?:pre|code|xmp)$/i;
    +    var EMPTY = {};
    +
    +    function doWork() {
    +      var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?
    +                     clock['now']() + 250 /* ms */ :
    +                     Infinity);
    +      for (; k < elements.length && clock['now']() < endTime; k++) {
    +        var cs = elements[k];
    +
    +        // Look for a preceding comment like
    +        // <?prettify lang="..." linenums="..."?>
    +        var attrs = EMPTY;
    +        {
    +          for (var preceder = cs; (preceder = preceder.previousSibling);) {
    +            var nt = preceder.nodeType;
    +            // <?foo?> is parsed by HTML 5 to a comment node (8)
    +            // like <!--?foo?-->, but in XML is a processing instruction
    +            var value = (nt === 7 || nt === 8) && preceder.nodeValue;
    +            if (value
    +                ? !/^\??prettify\b/.test(value)
    +                : (nt !== 3 || /\S/.test(preceder.nodeValue))) {
    +              // Skip over white-space text nodes but not others.
    +              break;
    +            }
    +            if (value) {
    +              attrs = {};
    +              value.replace(
    +                  /\b(\w+)=([\w:.%+-]+)/g,
    +                function (_, name, value) { attrs[name] = value; });
    +              break;
    +            }
    +          }
    +        }
    +
    +        var className = cs.className;
    +        if ((attrs !== EMPTY || prettyPrintRe.test(className))
    +            // Don't redo this if we've already done it.
    +            // This allows recalling pretty print to just prettyprint elements
    +            // that have been added to the page since last call.
    +            && !prettyPrintedRe.test(className)) {
    +
    +          // make sure this is not nested in an already prettified element
    +          var nested = false;
    +          for (var p = cs.parentNode; p; p = p.parentNode) {
    +            var tn = p.tagName;
    +            if (preCodeXmpRe.test(tn)
    +                && p.className && prettyPrintRe.test(p.className)) {
    +              nested = true;
    +              break;
    +            }
    +          }
    +          if (!nested) {
    +            // Mark done.  If we fail to prettyprint for whatever reason,
    +            // we shouldn't try again.
    +            cs.className += ' prettyprinted';
    +
    +            // If the classes includes a language extensions, use it.
    +            // Language extensions can be specified like
    +            //     <pre class="prettyprint lang-cpp">
    +            // the language extension "cpp" is used to find a language handler
    +            // as passed to PR.registerLangHandler.
    +            // HTML5 recommends that a language be specified using "language-"
    +            // as the prefix instead.  Google Code Prettify supports both.
    +            // http://dev.w3.org/html5/spec-author-view/the-code-element.html
    +            var langExtension = attrs['lang'];
    +            if (!langExtension) {
    +              langExtension = className.match(langExtensionRe);
    +              // Support <pre class="prettyprint"><code class="language-c">
    +              var wrapper;
    +              if (!langExtension && (wrapper = childContentWrapper(cs))
    +                  && codeRe.test(wrapper.tagName)) {
    +                langExtension = wrapper.className.match(langExtensionRe);
    +              }
    +
    +              if (langExtension) { langExtension = langExtension[1]; }
    +            }
    +
    +            var preformatted;
    +            if (preformattedTagNameRe.test(cs.tagName)) {
    +              preformatted = 1;
    +            } else {
    +              var currentStyle = cs['currentStyle'];
    +              var defaultView = doc.defaultView;
    +              var whitespace = (
    +                  currentStyle
    +                  ? currentStyle['whiteSpace']
    +                  : (defaultView
    +                     && defaultView.getComputedStyle)
    +                  ? defaultView.getComputedStyle(cs, null)
    +                  .getPropertyValue('white-space')
    +                  : 0);
    +              preformatted = whitespace
    +                  && 'pre' === whitespace.substring(0, 3);
    +            }
    +
    +            // Look for a class like linenums or linenums:<n> where <n> is the
    +            // 1-indexed number of the first line.
    +            var lineNums = attrs['linenums'];
    +            if (!(lineNums = lineNums === 'true' || +lineNums)) {
    +              lineNums = className.match(/\blinenums\b(?::(\d+))?/);
    +              lineNums =
    +                lineNums
    +                ? lineNums[1] && lineNums[1].length
    +                  ? +lineNums[1] : true
    +                : false;
    +            }
    +            if (lineNums) { numberLines(cs, lineNums, preformatted); }
    +
    +            // do the pretty printing
    +            prettyPrintingJob = {
    +              langExtension: langExtension,
    +              sourceNode: cs,
    +              numberLines: lineNums,
    +              pre: preformatted
    +            };
    +            applyDecorator(prettyPrintingJob);
    +          }
    +        }
    +      }
    +      if (k < elements.length) {
    +        // finish up in a continuation
    +        setTimeout(doWork, 250);
    +      } else if ('function' === typeof opt_whenDone) {
    +        opt_whenDone();
    +      }
    +    }
    +
    +    doWork();
    +  }
    +
    +  /**
    +   * Contains functions for creating and registering new language handlers.
    +   * @type {Object}
    +   */
    +  var PR = win['PR'] = {
    +        'createSimpleLexer': createSimpleLexer,
    +        'registerLangHandler': registerLangHandler,
    +        'sourceDecorator': sourceDecorator,
    +        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
    +        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
    +        'PR_COMMENT': PR_COMMENT,
    +        'PR_DECLARATION': PR_DECLARATION,
    +        'PR_KEYWORD': PR_KEYWORD,
    +        'PR_LITERAL': PR_LITERAL,
    +        'PR_NOCODE': PR_NOCODE,
    +        'PR_PLAIN': PR_PLAIN,
    +        'PR_PUNCTUATION': PR_PUNCTUATION,
    +        'PR_SOURCE': PR_SOURCE,
    +        'PR_STRING': PR_STRING,
    +        'PR_TAG': PR_TAG,
    +        'PR_TYPE': PR_TYPE,
    +        'prettyPrintOne':
    +           IN_GLOBAL_SCOPE
    +             ? (win['prettyPrintOne'] = $prettyPrintOne)
    +             : (prettyPrintOne = $prettyPrintOne),
    +        'prettyPrint': prettyPrint =
    +           IN_GLOBAL_SCOPE
    +             ? (win['prettyPrint'] = $prettyPrint)
    +             : (prettyPrint = $prettyPrint)
    +      };
    +
    +  // Make PR available via the Asynchronous Module Definition (AMD) API.
    +  // Per https://github.com/amdjs/amdjs-api/wiki/AMD:
    +  // The Asynchronous Module Definition (AMD) API specifies a
    +  // mechanism for defining modules such that the module and its
    +  // dependencies can be asynchronously loaded.
    +  // ...
    +  // To allow a clear indicator that a global define function (as
    +  // needed for script src browser loading) conforms to the AMD API,
    +  // any global define function SHOULD have a property called "amd"
    +  // whose value is an object. This helps avoid conflict with any
    +  // other existing JavaScript code that could have defined a define()
    +  // function that does not conform to the AMD API.
    +  if (typeof define === "function" && define['amd']) {
    +    define("google-code-prettify", [], function () {
    +      return PR; 
    +    });
    +  }
    +})();
    diff --git a/docs/grunt-scripts/ui-grid.js b/docs/grunt-scripts/ui-grid.js
    new file mode 100644
    index 000000000..55bb3c26f
    --- /dev/null
    +++ b/docs/grunt-scripts/ui-grid.js
    @@ -0,0 +1,787 @@
    +/*! ui-grid - v2.0.7-g7aeb576 - 2013-12-18
    +* Copyright (c) 2013 ; Licensed MIT */
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid.body', []);
    +
    +app.directive('uiGridBody', ['$log', 'GridUtil', function($log, GridUtil) {
    +  return {
    +    replace: true,
    +    priority: 1000,
    +    templateUrl: 'ui-grid/ui-grid-body',
    +    require: '?^uiGrid',
    +    scope: {
    +      tableClass: '=uiGridTableClass'
    +    },
    +    link: function(scope, elm, attrs, uiGridCtrl) {
    +      $log.debug('body postlink scope', scope.$id);
    +
    +      if (uiGridCtrl === undefined) {
    +        $log.warn('[ui-grid-body] uiGridCtrl is undefined!');
    +      }
    +
    +      if (uiGridCtrl && typeof(uiGridCtrl.columns) !== 'undefined' && uiGridCtrl.columns) {
    +        scope.columns = uiGridCtrl.columns;
    +      }
    +      if (uiGridCtrl && typeof(uiGridCtrl.gridData) !== 'undefined' && uiGridCtrl.gridData) {
    +        scope.gridData = uiGridCtrl.gridData;
    +      }
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid.header', ['ui.grid.util']);
    +
    +app.directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'GridUtil', function($log, $templateCache, $compile, GridUtil) {
    +  return {
    +    restrict: 'EA',
    +    // templateUrl: 'ui-grid/ui-grid-header',
    +    // replace: true,
    +    priority: 1000,
    +    require: '?^uiGrid',
    +    scope: {
    +      tableClass: '=uiGridTableClass'
    +    },
    +    compile: function (elm, attrs) {
    +      $log.debug('header compile');
    +
    +      // If the contents of the grid element are empty, use the default grid template
    +      var tmpl;
    +      if (elm.html() === '' || /^\s*$/.test(elm.html())) {
    +        tmpl = $templateCache.get('ui-grid/ui-grid-header');
    +      }
    +
    +      var preLink = function (scope, elm, attrs) {
    +        $log.debug('header prelink scope', scope.$id);
    +
    +        if (tmpl) {
    +          elm.append(tmpl);
    +        }
    +        $compile(elm.contents())(scope);
    +      };
    +
    +      var postLink = function(scope, elm, attrs, uiGridCtrl) {
    +        $log.debug('header postlink scope', scope.$id);
    +
    +        if (uiGridCtrl === undefined) {
    +          $log.warn('[ui-grid-header] uiGridCtrl is undefined!');
    +        }
    +
    +        // Get the column defs from the parent grid controller
    +        if (uiGridCtrl && typeof(uiGridCtrl.columns) !== 'undefined' && uiGridCtrl.columns) {
    +          scope.columns = uiGridCtrl.columns;
    +        }
    +
    +        // if (tmpl) {
    +        //   elm.append(tmpl);
    +        //   $compile(elm.contents())(scope);
    +        // }
    +
    +        // scope.$watch('columns', function(n, o) {
    +        //    $log.debug('columns change', n, o);
    +        //    var contents = elm.contents();
    +        //    $compile(contents)(scope);
    +        // });
    +      };
    +
    +      return {
    +        pre: preLink,
    +        post: postLink
    +      };
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.style.directive:uiGridStyle
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    +   <example module="app">
    +     <file name="app.js">
    +       var app = angular.module('app', ['ui.grid']);
    +       
    +       app.controller('MainCtrl', ['$scope', function ($scope) {
    +         $scope.myStyle = '.blah { color: red }';
    +       }]);
    +     </file>
    +     <file name="index.html">
    +       <div ng-controller="MainCtrl">
    +         <style ui-grid-style>{{ myStyle }}</style>
    +         <span class="blah">I am red.</span>
    +       </div>
    +     </file>
    +   </example>
    + */
    +
    +var app = angular.module('ui.grid.style', []);
    +
    +app.directive('uiGridStyle', ['$interpolate', '$sce', function($interpolate, $sce) {
    +  return {
    +    // restrict: 'A',
    +    priority: 1000,
    +    link: function(scope, element) {
    +      var interpolateFn = $interpolate(element.text(), true);
    +
    +      if (interpolateFn) {
    +        scope.$watch(interpolateFn, function(value) {
    +          element.text(value);
    +        });
    +      }
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid', ['ui.grid.header', 'ui.grid.body', 'ui.grid.style', 'ui.virtual-repeat']);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {array} uiGrid Array of rows to display in the grid
    + *  
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="data"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +app.directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    '$log',
    +    'GridUtil',
    +  function(
    +    $compile,
    +    $templateCache,
    +    $log,
    +    GridUtil
    +  ) {
    +
    +    function preLink(scope, elm, attrs) {
    +      var options = scope.uiGrid;
    +
    +      // Create an ID for this grid
    +      scope.gridId = GridUtil.newId();
    +
    +      // Get the grid dimensions from the element
    +
    +      // Initialize the grid
    +
    +      // Get the column definitions
    +        // Put a watch on them
    +
    +      console.log('gridId', scope.gridId);
    +
    +      elm.on('$destroy', function() {
    +        // Remove columnDefs watch
    +      });
    +    }
    +    
    +    return {
    +      templateUrl: 'ui-grid/ui-grid',
    +      scope: {
    +        uiGrid: '='
    +      },
    +      compile: function () {
    +        return {
    +          pre: preLink
    +        };
    +      },
    +      controller: function ($scope, $element, $attrs) {
    +        
    +      }
    +    };
    +  }
    +]);
    +
    +})();
    +(function(){
    +'use strict';
    +  
    +// (part of the sf.virtualScroll module).
    +var mod = angular.module('ui.virtual-repeat', []);
    +
    +var DONT_WORK_AS_VIEWPORTS = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +var DONT_WORK_AS_CONTENT = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +var DONT_SET_DISPLAY_BLOCK = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +
    +// Utility to clip to range
    +function clip(value, min, max){
    +  if (angular.isArray(value)) {
    +    return angular.forEach(value, function(v) {
    +      return clip(v, min, max);
    +    });
    +  }
    +
    +  return Math.max(min, Math.min(value, max));
    +}
    +
    +mod.directive('uiVirtualRepeat', ['$log', '$rootElement', function($log, $rootElement){
    +
    +  // Turn the expression supplied to the directive:
    +  //
    +  //     a in b
    +  //
    +  // into `{ value: "a", collection: "b" }`
    +  function parseRepeatExpression(expression) {
    +    var match = expression.match(/^\s*([\$\w]+)\s+in\s+([\S\s]*)$/);
    +    if (! match) {
    +      throw new Error("Expected uiVirtualRepeat in form of '_item_ in _collection_' but got '" + expression + "'.");
    +    }
    +    return {
    +      value: match[1],
    +      collection: match[2]
    +    };
    +  }
    +
    +  // Utility to filter out elements by tag name
    +  function isTagNameInList(element, list) {
    +    var t,
    +        tag = element.tagName.toUpperCase();
    +
    +    for (t = 0; t < list.length; t++) {
    +      if (list[t] === tag) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +
    +  // Utility to find the viewport/content elements given the start element:
    +  function findViewportAndContent(startElement) {
    +    /*jshint eqeqeq:false, curly:false */
    +    var root = $rootElement[0];
    +    var e, n;
    +
    +    // Somewhere between the grandparent and the root node
    +    for (e = startElement.parent().parent()[0]; e !== root; e = e.parentNode) {
    +      // is an element
    +      if (e.nodeType != 1) break;
    +      // that isn't in the blacklist (tables etc.),
    +      if (isTagNameInList(e, DONT_WORK_AS_VIEWPORTS)) continue;
    +      // has a single child element (the content),
    +      if (e.childElementCount != 1) continue;
    +      // which is not in the blacklist
    +      if (isTagNameInList(e.firstElementChild, DONT_WORK_AS_CONTENT)) continue;
    +      // and no text.
    +      for (n = e.firstChild; n; n = n.nextSibling) {
    +        if (n.nodeType == 3 && /\S/g.test(n.textContent)) {
    +          break;
    +        }
    +      }
    +
    +      if (n == null) {
    +        // That element should work as a viewport.
    +        return {
    +          viewport: angular.element(e),
    +          content: angular.element(e.firstElementChild)
    +        };
    +      }
    +    }
    +
    +    throw new Error("No suitable viewport element");
    +  }
    +
    +  // Apply explicit height and overflow styles to the viewport element.
    +  //
    +  // If the viewport has a max-height (inherited or otherwise), set max-height.
    +  // Otherwise, set height from the current computed value or use
    +  // window.innerHeight as a fallback
    +  //
    +  function setViewportCSS(viewport) {
    +    var viewportCSS = {'overflow': 'auto'};
    +
    +    var style = window.getComputedStyle ?
    +                window.getComputedStyle(viewport[0]) :
    +                viewport[0].currentStyle;
    +
    +    var maxHeight = style && style.getPropertyValue('max-height');
    +    var height = style && style.getPropertyValue('height');
    +
    +    if (maxHeight && maxHeight !== '0px') {
    +      viewportCSS.maxHeight = maxHeight;
    +    }
    +    else if (height && height !== '0px') {
    +      viewportCSS.height = height;
    +    }
    +    else {
    +      viewportCSS.height = window.innerHeight;
    +    }
    +
    +    viewport.css(viewportCSS);
    +  }
    +
    +  // Apply explicit styles to the content element to prevent pesky padding
    +  // or borders messing with our calculations:
    +  function setContentCSS(content) {
    +    var contentCSS = {
    +      margin: 0,
    +      padding: 0,
    +      border: 0,
    +      'box-sizing': 'border-box'
    +    };
    +
    +    content.css(contentCSS);
    +  }
    +
    +  // TODO: compute outerHeight (padding + border unless box-sizing is border)
    +  function computeRowHeight(element) {
    +    var style = window.getComputedStyle ?
    +                window.getComputedStyle(element) :
    +                element.currentStyle;
    +
    +    var maxHeight = style && style.getPropertyValue('max-height');
    +    var height = style && style.getPropertyValue('height');
    +
    +    if (height && height !== '0px' && height !== 'auto') {
    +      // $log.info('Row height is "%s" from css height', height);
    +    }
    +    else if (maxHeight && maxHeight !== '0px' && maxHeight !== 'none') {
    +      height = maxHeight;
    +      // $log.info('Row height is "%s" from css max-height', height);
    +    }
    +    else if (element.clientHeight) {
    +      height = element.clientHeight + 'px';
    +      // $log.info('Row height is "%s" from client height', height);
    +    }
    +    else {
    +      //throw new Error("Unable to compute height of row");
    +      return;
    +    }
    +
    +    angular.element(element).css('height', height);
    +
    +    return parseInt(height, 10);
    +  }
    +
    +  // The compile gathers information about the declaration. There's not much
    +  // else we could do in the compile step as we need a viewport parent that
    +  // is exculsively ours - this is only available at link time.
    +  function uiVirtualRepeatCompile(element, attr, linker) {
    +    var ident = parseRepeatExpression(attr.uiVirtualRepeat);
    +    
    +    // ----
    +
    +    // Set up the initial value for our watch expression (which is just the
    +    // start and length of the active rows and the collection length) and
    +    // adds a listener to handle child scopes based on the active rows.
    +    function sfVirtualRepeatPostLink(scope, iterStartElement, attrs) {
    +
    +      var rendered = [];
    +          scope.rendered = rendered;
    +
    +      var rowHeight = 0;
    +      var sticky = false;
    +      var dom = findViewportAndContent(iterStartElement);
    +      // The list structure is controlled by a few simple (visible) variables:
    +      var state = 'ngModel' in attrs ? scope.$eval(attrs.ngModel) : {};
    +      //  - The index of the first active element
    +      state.firstActive = 0;
    +      //  - The index of the first visible element
    +      state.firstVisible = 0;
    +      //  - The number of elements visible in the viewport.
    +      state.visible = 0;
    +      // - The number of active elements
    +      state.active = 0;
    +      // - The total number of elements
    +      state.total = 0;
    +      // - The point at which we add new elements
    +      state.lowWater = state.lowWater || 10;
    +      // - The point at which we remove old elements
    +      state.highWater = state.highWater || 20;
    +      // TODO: now watch the water marks
    +
    +      setContentCSS(dom.content);
    +      setViewportCSS(dom.viewport);
    +      // When the user scrolls, we move the `state.firstActive`
    +      dom.viewport.bind('scroll', sfVirtualRepeatOnScroll);
    +
    +      // The watch on the collection is just a watch on the length of the
    +      // collection. We don't care if the content changes.
    +      scope.$watch(sfVirtualRepeatWatchExpression, sfVirtualRepeatListener, true);
    +
    +      // and that's the link done! All the action is in the handlers...
    +      
    +      // ----
    +
    +      // Apply explicit styles to the item element
    +      function setElementCSS(element) {
    +        var elementCSS = {
    +          // no margin or it'll screw up the height calculations.
    +          margin: '0'
    +        };
    +
    +        if (!isTagNameInList(element[0], DONT_SET_DISPLAY_BLOCK)) {
    +          // display: block if it's safe to do so
    +          elementCSS.display = 'block';
    +        }
    +
    +        if (rowHeight) {
    +          elementCSS.height = rowHeight + 'px';
    +        }
    +
    +        element.css(elementCSS);
    +      }
    +
    +      function makeNewScope (idx, collection, containerScope) {
    +        var childScope = containerScope.$new();
    +        childScope[ident.value] = collection[idx];
    +        childScope.$index = idx;
    +        childScope.$first = (idx === 0);
    +        childScope.$last = (idx === (collection.length - 1));
    +        childScope.$middle = !(childScope.$first || childScope.$last);
    +        childScope.$watch(function updateChildScopeItem(){
    +          childScope[ident.value] = collection[idx];
    +        });
    +        return childScope;
    +      }
    +
    +      function addElements (start, end, collection, containerScope, insPoint) {
    +        var frag = document.createDocumentFragment();
    +        var newElements = [], element, idx, childScope;
    +
    +        for (idx = start; idx !== end; idx++) {
    +          childScope = makeNewScope(idx, collection, containerScope);
    +          element = linker(childScope, angular.noop);
    +          setElementCSS(element);
    +          newElements.push(element);
    +          frag.appendChild(element[0]);
    +        }
    +
    +        insPoint.after(frag);
    +        return newElements;
    +      }
    +
    +      function recomputeActive() {
    +        // We want to set the start to the low water mark unless the current
    +        // start is already between the low and high water marks.
    +        var start = clip(state.firstActive, state.firstVisible - state.lowWater, state.firstVisible - state.highWater);
    +        // Similarly for the end
    +        var end = clip(state.firstActive + state.active,
    +                       state.firstVisible + state.visible + state.lowWater,
    +                       state.firstVisible + state.visible + state.highWater );
    +        state.firstActive = Math.max(0, start);
    +        state.active = Math.min(end, state.total) - state.firstActive;
    +      }
    +
    +      function sfVirtualRepeatOnScroll(evt) {
    +        if (!rowHeight) {
    +          return;
    +        }
    +
    +        // Enter the angular world for the state change to take effect.
    +        scope.$apply(function() {
    +          state.firstVisible = Math.floor(evt.target.scrollTop / rowHeight);
    +          state.visible = Math.ceil(dom.viewport[0].clientHeight / rowHeight);
    +
    +          // $log.log('scroll to row %o', state.firstVisible);
    +          sticky = evt.target.scrollTop + evt.target.clientHeight >= evt.target.scrollHeight;
    +
    +          recomputeActive();
    +          // $log.log(' state is now %o', state);
    +          // $log.log(' sticky = %o', sticky);
    +        });
    +      }
    +
    +      function sfVirtualRepeatWatchExpression(scope) {
    +        var coll = scope.$eval(ident.collection);
    +
    +        if (coll.length !== state.total) {
    +          state.total = coll.length;
    +          recomputeActive();
    +        }
    +
    +        return {
    +          start: state.firstActive,
    +          active: state.active,
    +          len: coll.length
    +        };
    +      }
    +
    +      function destroyActiveElements (action, count) {
    +        var dead,
    +            ii,
    +            remover = Array.prototype[action];
    +
    +        for (ii = 0; ii < count; ii++) {
    +          dead = remover.call(rendered);
    +          dead.scope().$destroy();
    +          dead.remove();
    +        }
    +      }
    +
    +      // When the watch expression for the repeat changes, we may need to add
    +      // and remove scopes and elements
    +      function sfVirtualRepeatListener(newValue, oldValue, scope) {
    +        var oldEnd = oldValue.start + oldValue.active,
    +            collection = scope.$eval(ident.collection),
    +            newElements;
    +
    +        if (newValue === oldValue) {
    +          // $log.info('initial listen');
    +          newElements = addElements(newValue.start, oldEnd, collection, scope, iterStartElement);
    +          rendered = newElements;
    +
    +          if (rendered.length) {
    +            rowHeight = computeRowHeight(newElements[0][0]);
    +          }
    +        }
    +        else {
    +          var newEnd = newValue.start + newValue.active;
    +          var forward = newValue.start >= oldValue.start;
    +          var delta = forward ? newValue.start - oldValue.start
    +                              : oldValue.start - newValue.start;
    +          var endDelta = newEnd >= oldEnd ? newEnd - oldEnd : oldEnd - newEnd;
    +          var contiguous = delta < (forward ? oldValue.active : newValue.active);
    +          // $log.info('change by %o,%o rows %s', delta, endDelta, forward ? 'forward' : 'backward');
    +
    +          if (!contiguous) {
    +            // $log.info('non-contiguous change');
    +            destroyActiveElements('pop', rendered.length);
    +            rendered = addElements(newValue.start, newEnd, collection, scope, iterStartElement);
    +          }
    +          else {
    +            if (forward) {
    +              // $log.info('need to remove from the top');
    +              destroyActiveElements('shift', delta);
    +            }
    +            else if (delta) {
    +              // $log.info('need to add at the top');
    +              newElements = addElements(
    +                newValue.start,
    +                oldValue.start,
    +                collection, scope, iterStartElement);
    +              rendered = newElements.concat(rendered);
    +            }
    +
    +            if (newEnd < oldEnd) {
    +              // $log.info('need to remove from the bottom');
    +              destroyActiveElements('pop', oldEnd - newEnd);
    +            }
    +            else if (endDelta) {
    +              var lastElement = rendered[rendered.length-1];
    +              // $log.info('need to add to the bottom');
    +              newElements = addElements(
    +                oldEnd,
    +                newEnd,
    +                collection, scope, lastElement);
    +
    +              rendered = rendered.concat(newElements);
    +            }
    +          }
    +
    +          if (!rowHeight && rendered.length) {
    +            rowHeight = computeRowHeight(rendered[0][0]);
    +          }
    +
    +          dom.content.css({'padding-top': newValue.start * rowHeight + 'px'});
    +        }
    +
    +        dom.content.css({'height': newValue.len * rowHeight + 'px'});
    +
    +        if (sticky) {
    +          dom.viewport[0].scrollTop = dom.viewport[0].clientHeight + dom.viewport[0].scrollHeight;
    +        }
    +
    +        scope.rendered = rendered;
    +      }
    +
    +      return;
    +    }
    +
    +    return {
    +      post: sfVirtualRepeatPostLink
    +    };
    +  }
    +
    +  var directive =  {
    +    require: '?ngModel',
    +    transclude: 'element',
    +    priority: 1000,
    +    // terminal: true,
    +    compile: uiVirtualRepeatCompile,
    +    controller: ['$scope', function ($scope) {
    +      this.visibleRows = 0;
    +      this.visibleRows = this.visibleRows + 1;
    +    }]
    +  };
    +
    +  return directive;
    +}]);
    +
    +}());
    +(function() {
    +
    +var app = angular.module('ui.grid.util', []);
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.util.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +app.service('GridUtil', function () {
    +
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.util.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid.util']);
    +
    +          app.controller('MainCtrl', ['$scope', 'GridUtil', function ($scope, GridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return GridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.util.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data) {
    +      var columnDefs = [];
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item, function (prop, propName) {
    +        columnDefs.push({
    +          field: propName,
    +          name: s.readableColumnName(propName)
    +        });
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.util.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +  };
    +
    +  return s;
    +});
    +
    +})();
    \ No newline at end of file
    diff --git a/docs/grunt-scripts/vfs_fonts.js b/docs/grunt-scripts/vfs_fonts.js
    new file mode 100644
    index 000000000..f5fd30a82
    --- /dev/null
    +++ b/docs/grunt-scripts/vfs_fonts.js
    @@ -0,0 +1 @@
    +window.pdfMake = window.pdfMake || {}; window.pdfMake.vfs = {"LICENSE.txt":"DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBcGFjaGUgTGljZW5zZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNA0KICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLw0KDQogICBURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04NCg0KICAgMS4gRGVmaW5pdGlvbnMuDQoNCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sDQogICAgICBhbmQgZGlzdHJpYnV0aW9uIGFzIGRlZmluZWQgYnkgU2VjdGlvbnMgMSB0aHJvdWdoIDkgb2YgdGhpcyBkb2N1bWVudC4NCg0KICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkNCiAgICAgIHRoZSBjb3B5cmlnaHQgb3duZXIgdGhhdCBpcyBncmFudGluZyB0aGUgTGljZW5zZS4NCg0KICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbA0KICAgICAgb3RoZXIgZW50aXRpZXMgdGhhdCBjb250cm9sLCBhcmUgY29udHJvbGxlZCBieSwgb3IgYXJlIHVuZGVyIGNvbW1vbg0KICAgICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwNCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQ0KICAgICAgZGlyZWN0aW9uIG9yIG1hbmFnZW1lbnQgb2Ygc3VjaCBlbnRpdHksIHdoZXRoZXIgYnkgY29udHJhY3Qgb3INCiAgICAgIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQ0KICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4NCg0KICAgICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQ0KICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4NCg0KICAgICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsDQogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uDQogICAgICBzb3VyY2UsIGFuZCBjb25maWd1cmF0aW9uIGZpbGVzLg0KDQogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbA0KICAgICAgdHJhbnNmb3JtYXRpb24gb3IgdHJhbnNsYXRpb24gb2YgYSBTb3VyY2UgZm9ybSwgaW5jbHVkaW5nIGJ1dA0KICAgICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLA0KICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLg0KDQogICAgICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcg0KICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQ0KICAgICAgY29weXJpZ2h0IG5vdGljZSB0aGF0IGlzIGluY2x1ZGVkIGluIG9yIGF0dGFjaGVkIHRvIHRoZSB3b3JrDQogICAgICAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLg0KDQogICAgICAiRGVyaXZhdGl2ZSBXb3JrcyIgc2hhbGwgbWVhbiBhbnkgd29yaywgd2hldGhlciBpbiBTb3VyY2Ugb3IgT2JqZWN0DQogICAgICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlDQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zDQogICAgICByZXByZXNlbnQsIGFzIGEgd2hvbGUsIGFuIG9yaWdpbmFsIHdvcmsgb2YgYXV0aG9yc2hpcC4gRm9yIHRoZSBwdXJwb3Nlcw0KICAgICAgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluDQogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsDQogICAgICB0aGUgV29yayBhbmQgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mLg0KDQogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZw0KICAgICAgdGhlIG9yaWdpbmFsIHZlcnNpb24gb2YgdGhlIFdvcmsgYW5kIGFueSBtb2RpZmljYXRpb25zIG9yIGFkZGl0aW9ucw0KICAgICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5DQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyDQogICAgICBvciBieSBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eSBhdXRob3JpemVkIHRvIHN1Ym1pdCBvbiBiZWhhbGYgb2YNCiAgICAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIg0KICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudA0KICAgICAgdG8gdGhlIExpY2Vuc29yIG9yIGl0cyByZXByZXNlbnRhdGl2ZXMsIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8NCiAgICAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsDQogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQ0KICAgICAgTGljZW5zb3IgZm9yIHRoZSBwdXJwb3NlIG9mIGRpc2N1c3NpbmcgYW5kIGltcHJvdmluZyB0aGUgV29yaywgYnV0DQogICAgICBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZQ0KICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iDQoNCiAgICAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5DQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQNCiAgICAgIHN1YnNlcXVlbnRseSBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrLg0KDQogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YNCiAgICAgIHRoaXMgTGljZW5zZSwgZWFjaCBDb250cmlidXRvciBoZXJlYnkgZ3JhbnRzIHRvIFlvdSBhIHBlcnBldHVhbCwNCiAgICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlDQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwNCiAgICAgIHB1YmxpY2x5IGRpc3BsYXksIHB1YmxpY2x5IHBlcmZvcm0sIHN1YmxpY2Vuc2UsIGFuZCBkaXN0cmlidXRlIHRoZQ0KICAgICAgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4NCg0KICAgMy4gR3JhbnQgb2YgUGF0ZW50IExpY2Vuc2UuIFN1YmplY3QgdG8gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mDQogICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsDQogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQ0KICAgICAgKGV4Y2VwdCBhcyBzdGF0ZWQgaW4gdGhpcyBzZWN0aW9uKSBwYXRlbnQgbGljZW5zZSB0byBtYWtlLCBoYXZlIG1hZGUsDQogICAgICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywNCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlDQogICAgICBieSBzdWNoIENvbnRyaWJ1dG9yIHRoYXQgYXJlIG5lY2Vzc2FyaWx5IGluZnJpbmdlZCBieSB0aGVpcg0KICAgICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKQ0KICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UNCiAgICAgIGluc3RpdHV0ZSBwYXRlbnQgbGl0aWdhdGlvbiBhZ2FpbnN0IGFueSBlbnRpdHkgKGluY2x1ZGluZyBhDQogICAgICBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrDQogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdA0KICAgICAgb3IgY29udHJpYnV0b3J5IHBhdGVudCBpbmZyaW5nZW1lbnQsIHRoZW4gYW55IHBhdGVudCBsaWNlbnNlcw0KICAgICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlDQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuDQoNCiAgIDQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlDQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQNCiAgICAgIG1vZGlmaWNhdGlvbnMsIGFuZCBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0sIHByb3ZpZGVkIHRoYXQgWW91DQogICAgICBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoNCg0KICAgICAgKGEpIFlvdSBtdXN0IGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFdvcmsgb3INCiAgICAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7IGFuZA0KDQogICAgICAoYikgWW91IG11c3QgY2F1c2UgYW55IG1vZGlmaWVkIGZpbGVzIHRvIGNhcnJ5IHByb21pbmVudCBub3RpY2VzDQogICAgICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxlczsgYW5kDQoNCiAgICAgIChjKSBZb3UgbXVzdCByZXRhaW4sIGluIHRoZSBTb3VyY2UgZm9ybSBvZiBhbnkgRGVyaXZhdGl2ZSBXb3Jrcw0KICAgICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQNCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLA0KICAgICAgICAgIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8gbm90IHBlcnRhaW4gdG8gYW55IHBhcnQgb2YNCiAgICAgICAgICB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kDQoNCiAgICAgIChkKSBJZiB0aGUgV29yayBpbmNsdWRlcyBhICJOT1RJQ0UiIHRleHQgZmlsZSBhcyBwYXJ0IG9mIGl0cw0KICAgICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QNCiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQNCiAgICAgICAgICB3aXRoaW4gc3VjaCBOT1RJQ0UgZmlsZSwgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QNCiAgICAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpbiBhdCBsZWFzdCBvbmUNCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZA0KICAgICAgICAgIGFzIHBhcnQgb2YgdGhlIERlcml2YXRpdmUgV29ya3M7IHdpdGhpbiB0aGUgU291cmNlIGZvcm0gb3INCiAgICAgICAgICBkb2N1bWVudGF0aW9uLCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwNCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kDQogICAgICAgICAgd2hlcmV2ZXIgc3VjaCB0aGlyZC1wYXJ0eSBub3RpY2VzIG5vcm1hbGx5IGFwcGVhci4gVGhlIGNvbnRlbnRzDQogICAgICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3JtYXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZA0KICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uDQogICAgICAgICAgbm90aWNlcyB3aXRoaW4gRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbG9uZ3NpZGUNCiAgICAgICAgICBvciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlkZWQNCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQNCiAgICAgICAgICBhcyBtb2RpZnlpbmcgdGhlIExpY2Vuc2UuDQoNCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZA0KICAgICAgbWF5IHByb3ZpZGUgYWRkaXRpb25hbCBvciBkaWZmZXJlbnQgbGljZW5zZSB0ZXJtcyBhbmQgY29uZGl0aW9ucw0KICAgICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24gb2YgWW91ciBtb2RpZmljYXRpb25zLCBvcg0KICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsDQogICAgICByZXByb2R1Y3Rpb24sIGFuZCBkaXN0cmlidXRpb24gb2YgdGhlIFdvcmsgb3RoZXJ3aXNlIGNvbXBsaWVzIHdpdGgNCiAgICAgIHRoZSBjb25kaXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuDQoNCiAgIDUuIFN1Ym1pc3Npb24gb2YgQ29udHJpYnV0aW9ucy4gVW5sZXNzIFlvdSBleHBsaWNpdGx5IHN0YXRlIG90aGVyd2lzZSwNCiAgICAgIGFueSBDb250cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yaw0KICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YNCiAgICAgIHRoaXMgTGljZW5zZSwgd2l0aG91dCBhbnkgYWRkaXRpb25hbCB0ZXJtcyBvciBjb25kaXRpb25zLg0KICAgICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBoZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQ0KICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQNCiAgICAgIHdpdGggTGljZW5zb3IgcmVnYXJkaW5nIHN1Y2ggQ29udHJpYnV0aW9ucy4NCg0KICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQ0KICAgICAgbmFtZXMsIHRyYWRlbWFya3MsIHNlcnZpY2UgbWFya3MsIG9yIHByb2R1Y3QgbmFtZXMgb2YgdGhlIExpY2Vuc29yLA0KICAgICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkgdXNlIGluIGRlc2NyaWJpbmcgdGhlDQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4NCg0KICAgNy4gRGlzY2xhaW1lciBvZiBXYXJyYW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yDQogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoDQogICAgICBDb250cmlidXRvciBwcm92aWRlcyBpdHMgQ29udHJpYnV0aW9ucykgb24gYW4gIkFTIElTIiBCQVNJUywNCiAgICAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvcg0KICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMNCiAgICAgIG9mIFRJVExFLCBOT04tSU5GUklOR0VNRU5ULCBNRVJDSEFOVEFCSUxJVFksIG9yIEZJVE5FU1MgRk9SIEENCiAgICAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQ0KICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55DQogICAgICByaXNrcyBhc3NvY2lhdGVkIHdpdGggWW91ciBleGVyY2lzZSBvZiBwZXJtaXNzaW9ucyB1bmRlciB0aGlzIExpY2Vuc2UuDQoNCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LA0KICAgICAgd2hldGhlciBpbiB0b3J0IChpbmNsdWRpbmcgbmVnbGlnZW5jZSksIGNvbnRyYWN0LCBvciBvdGhlcndpc2UsDQogICAgICB1bmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQ0KICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUNCiAgICAgIGxpYWJsZSB0byBZb3UgZm9yIGRhbWFnZXMsIGluY2x1ZGluZyBhbnkgZGlyZWN0LCBpbmRpcmVjdCwgc3BlY2lhbCwNCiAgICAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdlcyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQ0KICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQ0KICAgICAgV29yayAoaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0byBkYW1hZ2VzIGZvciBsb3NzIG9mIGdvb2R3aWxsLA0KICAgICAgd29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFuZCBhbGwNCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3INCiAgICAgIGhhcyBiZWVuIGFkdmlzZWQgb2YgdGhlIHBvc3NpYmlsaXR5IG9mIHN1Y2ggZGFtYWdlcy4NCg0KICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZw0KICAgICAgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mLCBZb3UgbWF5IGNob29zZSB0byBvZmZlciwNCiAgICAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9yLCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksDQogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcw0KICAgICAgTGljZW5zZS4gSG93ZXZlciwgaW4gYWNjZXB0aW5nIHN1Y2ggb2JsaWdhdGlvbnMsIFlvdSBtYXkgYWN0IG9ubHkNCiAgICAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3BvbnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmDQogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksDQogICAgICBkZWZlbmQsIGFuZCBob2xkIGVhY2ggQ29udHJpYnV0b3IgaGFybWxlc3MgZm9yIGFueSBsaWFiaWxpdHkNCiAgICAgIGluY3VycmVkIGJ5LCBvciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24NCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5Lg0KDQogICBFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMNCg0KICAgQVBQRU5ESVg6IEhvdyB0byBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLg0KDQogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZw0KICAgICAgYm9pbGVycGxhdGUgbm90aWNlLCB3aXRoIHRoZSBmaWVsZHMgZW5jbG9zZWQgYnkgYnJhY2tldHMgIltdIg0KICAgICAgcmVwbGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1ZGUNCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlDQogICAgICBjb21tZW50IHN5bnRheCBmb3IgdGhlIGZpbGUgZm9ybWF0LiBXZSBhbHNvIHJlY29tbWVuZCB0aGF0IGENCiAgICAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24gb2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUNCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcg0KICAgICAgaWRlbnRpZmljYXRpb24gd2l0aGluIHRoaXJkLXBhcnR5IGFyY2hpdmVzLg0KDQogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0NCg0KICAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7DQogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuDQogICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQNCg0KICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMA0KDQogICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlDQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLA0KICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuDQogICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kDQogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4NCg==","Roboto-Italic.ttf":"AAEAAAAOAIAAAwBgR0RFRgsuCy8AATmYAAAASEdQT1OC3T4oAAE54AAAkPhHU1VCeolvLwABytgAAANsT1MvMrivKS4AAAFoAAAAYFZETVhu6nZPAAASPAAABeBjbWFwg/CFnwAAGBwAAA7yZ2x5ZqugYnAAACcQAADhjGhlYWQVl+THAAAA7AAAADZoaGVhK3TmIgAAASQAAAAkaG10eH7tDo8AAAHIAAAQdGxvY2H/CzayAAEInAAACDxtYXhwBDwA9gAAAUgAAAAgbmFtZW3ArcAAARDYAAAEb3Bvc3QJy9dbAAEVSAAAJE0AAQAAAAEAAERFNtJfDzz1AAkIAAAAAADE8BEuAAAAAM2Cslz6t9PdKU8IYgACAAkAAgAAAAAAAAABAAAHbP4MAAAJA/q32vUpTwABAAAAAAAAAAAAAAAAAAAEHQABAAAEHQCWABYAXgAFAAEAAAAAAAAAAAAAAAAAAwABAAMEQQGQAAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAAAAAAAAAAAAAAA4AAC/1AAIFsAAAAgAAAAAHB5cnMAAQAA//0GAP4AAGYHmgIAIAABn08BAAAEOgWwAAAAIAACAeMAAAAAAAAB4wAAAeMAAAJ1AMUErABDBDoARwV7ANMErAAbAVcAxgKBAFcCiP+MA0AAoQRCAHIBgf+YAhUAPgIGAEYDH/+mBDoAUAQ6AXAEOgAtBDoANQQ6ACcEOgBoBDoAZwQ6ANgEOgA1BDoAfwHpAEYB8f/GA9EAZQQ6AI4D7gBWA5IAwga0ABME/v/VBMsAWATBAGIE8ABYBGIAWARfAFgFJgBoBVgAWAIkAGIEJQAPBH4APgQgAFgGkgBYBVkAWAUcAF4EzQBYBTsAXgT4AFcEjQBDBHoA7AUSAGcE3QDNBpUA7AS9//wEpgDuBDIAIAIKABIDHAD3Agr/lwMnAHwDa/+WAl0A8wQgADoERAA1A/wARwREAEQD+QBHApsAigRDADcERAA1AegARAH2/x0D2QA2AegARAaLADUERAA1BEQARgRE/+IERABEAqQANQPuADsCaQBvBEQAWgPIAJcFrACyA8j/6QPI/7wDyAAIApEAUQHhADYCkf+pBRgAggHh/+sEHQBXBGAALQVVACYEjgBxAdkAAQSc/8gDvwEnBd4AUgNeAMIDjABwBCsApgXfAFIDewEDAtABBQQGAE4DMQCnAzgAqgJoAPsERP/rA7EAhwH/AMMB4//OAg8BBANtAM8DiwA1BdUBDgY7ARsGgQC6A7f/8wcF/54EBABIBR0AJgRvAEgEeQAwBlIABARnACYESgBqBEUATARY/+sFRABVAegAPgQxAD4D8wBJAhEARwUwAEYERAA1BygATwbHAEQB6ABEApb/ZgUjAFkETgBGBToAZwSuAFoB7/8bA/kAPAOWAUgDYgFeAzgBCwINAUECkQEiAhP/twOXAQgCzwEHAnoAHQAK/fIACv5BAAr9WAAK/kYACv1LAAr83AHzAWQD1AFBAgAAwwQuAFcFS//MBR0ATwTs/94ETQAiBVoAWARN//EFXwBXBS8AigUAAB0EPwBABHL/9QPIALMERABBBAsAKQPsAIsERAA1BEYAVgJ5AH4EKv/RA7AAOgR6AHAERP/iBAsASQREAEMD7gC3BBwAWgVNAD8FRABDBisAXQSiAFoD/wCzBeEAZAWfANsFEgBmCAj/3ggTAFcGGgDyBVoAVwS7AEgFqv+WBtP/ygR0ACAFWQBYBU//3gS3AKMF0QBbBX8AVwUnANEHDgBXB0cAVwWrAMkGggBXBLkASAURAIcGrABiBM4ADAQnAEQETgBAAygAPgSQ/5oFvP/DA9IAHgRaAEAEFQBABFv/1QWSAEAEWQBABFoAQAOfAJAFbwBABHkAQAQYAH8GEgBABjoANQSlAIYF2ABABBYAQAQLADMGHgBABCH/1QRFADUEDABRBlj/1QZzAEAERQA1BFoAQAaRAGgFtwBFBBQAPga2AGMFmQA8BIb/2AQF/7wGmAB0BaoAXQZrADoFigA6CHsAYgddAD4D5f/HA5//xgUdAF0ERQBGBL4A6APIALMFHQBPBEUARgaLAGwFtwBIBpIAaAW4AEUE5ABkBAgASgSyAFUACv09AAr9ZAAK/m8ACv6QAAr6twAK+tYEFAA+BMsAVwRD/+IEHwBIA1wANQSXAFcDyQA1BL0ASAQ+AD4GJADzBTQApQdEAFcFVQA1B6kAVwaGADUFjQBlBIkATga/AOgFCwCIBR0A0QQmAJcFHQDQBc8ArgR0ACUEvQBIBBsAPgVYAFcERAA1BSsARgRgADYEYP/tBHIACgMY//sEtQA2BjQANgZzAEAF7wDoBNkAiAQIAM8DywC8B0H/8QYM/+wHfQBOBjUANQSoAGAD3gBGBVIA1wTPAKwFEQBqA9UAAAehAAAD1QAAB6EAAAKSAAAB7wAAAU4AAAQ4AAACEwAAAY8AAADMAAAACgAABS8A6QYSAQADb/9oAY0A1gGNALEBjP+kAY7/YQK7ANYCwgC9Aqn/pAQkAJUESQAQApAArwOPAEcFDABHByYArgJGAIACRgAhA24ACQN0AIsDLgCjBGAALQYmAEkD/gBgBYkA4wOXAGcIOABOBLQBIwTGAHwGUAD+BtwArAcIAKoGbQEeBFkAJgU/ADkEZ/+7BEoAzwSIAGgHqABJAfL/OwQ7AFAD7wCOA/YASAP9AEcDyQBnAjYAjwJ1AJQB7f/mBC0AaAAKAAAHq/+1B6wAhwPfAB8DXAAnBDoAUQLg/+AB6P8dAhH/egF+/8IDbQE3A2wBNwNsATcDyAEPA9ABCwPIAF8DxwEXA20BDQHrAS8Eb//UBDIAPgRJAE0EYAA+BAQAPgPfAD4EhgBKBKsAPgHoAD4DzwALBBwAPgOEAD4FlwA+BMoAPgR/AE0ElQBNBGMAPgQrACMD7gC9BLMAWARwAL4FoQDUBEH/4wQcALUD/v/5BDMASgJNAKwDqQAPA9YAIAQjACUEJQAeA+8ATgOEAL0D7gAjA+cAbQIPAH8DKAAiAzgAJQLTAO0DRwArA0gAQALjAI8DTwAuAzgAZANtAD4DZwC5ApEBKwMbAPUEOgAuBDoAJwQ6AGEESwBkA/n/kQQBAOsEMP/OBDoANQR7AEAERABBBPAAWAQgADcE3gBXBNMAWAPZADYE7ABYA9gANgQ6AH0EMgA+AzgBCwHjAAACFQA+BTMAXgUzAF4EYgBTBHoA7AJpAAcE/v/VBP7/1QT+/9UE/v/VBP7/1QT+/9UE/v/VBMsAYgRiAFgEYgBYBGIAWARiAFgCJABiAiQAYgIkAGICJABiBVkAWAU7AF4FOwBeBTsAXgU7AF4FOwBeBRIAZwUSAGcFEgBnBRIAZwSmAO4EIAA6BCAAOgQgADoEIAA6BCAAOgQgADoEIAA6A/wARwP5AEcD+QBHA/kARwP5AEcB6AA+AegAPgHoAD4B6AA+BEQANQREAEYERABGBEQARgREAEYERABGBEQAWgREAFoERABaBEQAWgPI/7wDyP+8BP7/1QQgADoE/v/VBCAAOgT+/9UEIAA6BMsAYgP8AEcEywBiA/wARwTLAGID/ABHBMsAYgP8AEcFFQBYBNoARARiAFgD+QBHBGIAWAP5AEcEYgBYA/kARwRiAFgD+QBHBGIAWAP5AEcFJgBoBEMANwUmAGgEQwA3BSYAaARDADcFJgBoBEMANwVYAFgERAA1AiQAYgHoAD4CJABiAegAPgIkAGIB6AA+AiT/mgHo/3sCJABiBkkAYgPeAEQEJQAPAe//GwTTAD4D2QA2BCAAWAHoAEQEIABYAej/qAQgAFgCfgBEBCAAWALEAEQFWQBYBEQANQVZAFgERAA1BVkAWAREADUERAA1BTsAXgREAEYFOwBeBEQARgU7AF4ERABGBPgAVwKkADUE+ABXAqT/pgT4AFcCpAA1BJgAQwPuADsEmABDA+4AOwSYAEMD7gA7BJgAQwPuADsEmABDA+4AOwR6AOwCaQBFBHoA7AJpAG8EegDsApEAbwUSAGcERABaBRIAZwREAFoFEgBnBEQAWgUSAGcERABaBRIAZwREAFoFEgBnBEQAWgaVAOwFrACyBKYA7gPI/7wEpgDuBH0AIAPIAAgEfQAgA8gACAR9ACADyAAIBwX/ngZSAAQFHQAmBEUATARgAAsEYAALA+4AvQRv/9QEb//UBG//1ARv/9QEb//UBG//1ARv/9QESQBNBAQAPgQEAD4EBAA+BAQAPgHoAD4B6AA+AegAPgHoAD4EygA+BH8ATQR/AE0EfwBNBH8ATQR/AE0EswBYBLMAWASzAFgEswBYBBwAtQRv/9QEb//UBG//1ARJAE0ESQBNBEkATQRJAE0EYAA+BAQAPgQEAD4EBAA+BAQAPgQEAD4EhgBKBIYASgSGAEoEhgBKBKsAPgHoAD4B6AA+AegAPgHo/3MB6AA+A88ACwQcAD4DhAA+A4QAPgOEAD4DhAA+BMoAPgTKAD4EygA+BH8ATQR/AE0EfwBNBGMAPgRjAD4EYwA+BCsAIwQrACMEKwAjBCsAIwPuAJcD7gC9BLMAWASzAFgEswBYBLMAWASzAFgEswBYBaEA1AQcALUEHAC1A/7/+QP+//kD/v/5CFYAIwT+/9UExgCbBbwAvAKIAMYFTwByBQoASQUUADECeQBsBP7/1QTLAFgEYgBYBH0AIAVYAFgCJABiBNMAPgaSAFgFWQBYBTsAXgTNAFgEegDsBKYA7gS9//wCJABiBKYA7gQ/AEAECwApBEQANQJ5AH4EHABaBDEAPgREAEYERP/rA8gAlwPI/+kCeQB+BBwAWgREAEYEHABaBisAXQRiAFgELgBXBJgAQwIkAGICJABiBCUADwTTAD4E0wA+BLcAowT+/9UEywBYBC4AVwRiAFgFWQBYBpIAWAVYAFgFOwBeBVoAWATNAFgEywBiBHoA7AS9//wEIAA6A/kARwRaAEAERABGBET/4gP8AEcDyP+8A8j/6QP5AEcDKAA+A+4AOwHoAEQB6AA+Afb/HQQVAEADyP+8BpUA7AWsALIGlQDsBawAsgaVAOwFrACyBKYA7gPI/7wBVwDGAnUAxQP6AE8EgwCKAe//GwGNALEGkgBYBosANQT+/9UEIAA6BTsAAQbIAIoHHgCKBGIAWAVZAFgD+QBHBFoAQAUvAIoFRABDBL4A6APIALMIDABGCQMAXgR0ACAD0gAeBMsAYgP8AEcEpgDuA8gAswIkAGIG0//KBbz/wwIkAGIE/v/VBCAAOgT+/9UEIAA6BwX/ngZSAAQEYgBYA/kARwUrAEYD+QA8A/kAPAbT/8oFvP/DBHQAIAPSAB4FWQBYBFoAQAVZAFgEWgBABTsAXgREAEYFHQBdBEUARgUdAF0ERQBGBREAhwQLADMEtwCjA8j/vAS3AKMDyP+8BLcAowPI/7wFJwDRBBgAfwaCAFcF2ABABL3//API/+kERABEBU//3gRb/9UE/v/VBCAAOgT+/9UEIAA6BP7/1QQgADoE/v/VBCAAOgT+/9UEIAA6BP7/1QQgADoE/v/VBCAAOgT+/9UEIAA6BP7/1QQgADoE/v/VBCAAOgT+/9UEIAA6BP7/1QQgADoEYgBYA/kARwRiAFgD+QBHBGIAWAP5AEcEYgBYA/kARwRiAFgD+QBHBGIAWAP5AEcEYgBYA/kARwRiAFgD+QBHAiQAYgHoAD4CJAAXAej/+gU7AF4ERABGBTsAXgREAEYFOwBeBEQARgU7AF4ERABGBTsAXgREAEYFOwBeBEQARgU7AF4ERABGBSMAWQROAEYFIwBZBE4ARgUjAFkETgBGBSMAWQROAEYFIwBZBE4ARgUSAGcERABaBRIAZwREAFoFOgBnBK4AWgU6AGcErgBaBToAZwSuAFoFOgBnBK4AWgU6AGcErgBaBKYA7gPI/7wEpgDuA8j/vASmAO4DyP+8BGIARARiABME0wA+BBUAQAVYAFgEWQBABHoA7AOfAJAEvf/8A8j/6QUnANEEGAB/BScA0QQYAH8ELgBXAygAPgbT/8oFvP/DBc8ArgR0ACUERAA1BLkASAS5AEgELgA0AygACgTnAFID7QBKBVkAWARaAEAFWABYBFkAQAaSAFgFkgBABU//3gRb/9UEpgDuA8gAbQS9//wDyP/pBAsAKQRf//wGEgEAAAoAAAAKAAAB/QBPAAAAAQABAQEBAQAMAPgI/wAIAAj//gAJAAn//QAKAAr//QALAAv//QAMAAz//QANAA3//AAOAA7//AAPAA///AAQABD//AARABH/+wASABL/+wATABP/+wAUABT/+wAVABT/+gAWABX/+gAXABb/+gAYABf/+gAZABj/+QAaABn/+QAbABr/+QAcABv/+QAdABz/+AAeAB3/+AAfAB7/+AAgAB//+AAhACD/9wAiACH/9wAjACL/9wAkACP/9wAlACT/9gAmACX/9gAnACb/9gAoACf/9gApACf/9QAqACj/9QArACn/9QAsACr/9QAtACv/9AAuACz/9AAvAC3/9AAwAC7/9AAxAC//8wAyADD/8wAzADH/8wA0ADL/8wA1ADP/8gA2ADT/8gA3ADX/8gA4ADb/8gA5ADf/8QA6ADj/8QA7ADn/8QA8ADr/8QA9ADr/8AA+ADv/8AA/ADz/8ABAAD3/8ABBAD7/7wBCAD//7wBDAED/7wBEAEH/7wBFAEL/7gBGAEP/7gBHAET/7gBIAEX/7gBJAEb/7QBKAEf/7QBLAEj/7QBMAEn/7QBNAEr/7ABOAEv/7ABPAEz/7ABQAE3/7ABRAE3/6wBSAE7/6wBTAE//6wBUAFD/6wBVAFH/6gBWAFL/6gBXAFP/6gBYAFT/6gBZAFX/6QBaAFb/6QBbAFf/6QBcAFj/6QBdAFn/6ABeAFr/6ABfAFv/6ABgAFz/6ABhAF3/5wBiAF7/5wBjAF//5wBkAGD/5wBlAGD/5gBmAGH/5gBnAGL/5gBoAGP/5gBpAGT/5QBqAGX/5QBrAGb/5QBsAGf/5QBtAGj/5ABuAGn/5ABvAGr/5ABwAGv/5ABxAGz/4wByAG3/4wBzAG7/4wB0AG//4wB1AHD/4gB2AHH/4gB3AHL/4gB4AHP/4gB5AHP/4QB6AHT/4QB7AHX/4QB8AHb/4QB9AHf/4AB+AHj/4AB/AHn/4ACAAHr/4ACBAHv/3wCCAHz/3wCDAH3/3wCEAH7/3wCFAH//3gCGAID/3gCHAIH/3gCIAIL/3gCJAIP/3QCKAIT/3QCLAIX/3QCMAIb/3QCNAIb/3ACOAIf/3ACPAIj/3ACQAIn/3ACRAIr/2wCSAIv/2wCTAIz/2wCUAI3/2wCVAI7/2gCWAI//2gCXAJD/2gCYAJH/2gCZAJL/2QCaAJP/2QCbAJT/2QCcAJX/2QCdAJb/2ACeAJf/2ACfAJj/2ACgAJn/2AChAJn/1wCiAJr/1wCjAJv/1wCkAJz/1wClAJ3/1gCmAJ7/1gCnAJ//1gCoAKD/1gCpAKH/1QCqAKL/1QCrAKP/1QCsAKT/1QCtAKX/1ACuAKb/1ACvAKf/1ACwAKj/1ACxAKn/0wCyAKr/0wCzAKv/0wC0AKz/0wC1AKz/0gC2AK3/0gC3AK7/0gC4AK//0gC5ALD/0QC6ALH/0QC7ALL/0QC8ALP/0QC9ALT/0AC+ALX/0AC/ALb/0ADAALf/0ADBALj/zwDCALn/zwDDALr/zwDEALv/zwDFALz/zgDGAL3/zgDHAL7/zgDIAL//zgDJAL//zQDKAMD/zQDLAMH/zQDMAML/zQDNAMP/zADOAMT/zADPAMX/zADQAMb/zADRAMf/ywDSAMj/ywDTAMn/ywDUAMr/ywDVAMv/ygDWAMz/ygDXAM3/ygDYAM7/ygDZAM//yQDaAND/yQDbANH/yQDcANL/yQDdANL/yADeANP/yADfANT/yADgANX/yADhANb/xwDiANf/xwDjANj/xwDkANn/xwDlANr/xgDmANv/xgDnANz/xgDoAN3/xgDpAN7/xQDqAN//xQDrAOD/xQDsAOH/xQDtAOL/xADuAOP/xADvAOT/xADwAOX/xADxAOX/wwDyAOb/wwDzAOf/wwD0AOj/wwD1AOn/wgD2AOr/wgD3AOv/wgD4AOz/wgD5AO3/wQD6AO7/wQD7AO//wQD8APD/wQD9APH/wAD+APL/wAD/APP/wAAAAAMAAAADAAAIjAABAAAAAAAcAAMAAQAAAiYABgIKAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAABAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAADBBwABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAAAH1AfYB+AH6AgECBgIKAg0CDAIOAhACDwIRAhMCFQIUAhYCFwIZAhgCGgIbAhwCHgIdAh8CIQIgAiMCIgIkAiUBbABvAGIAYwBnAW4AdQCDAG0AaQF9AHMAaAGLAH8AgQGIAHABjAGNAGUAdAGDAYUBhADBAYkAagB5ALUAhACHAH4AYQBsAYcAkwGKAK0AawB6AXAAAwHxAfQCBQCQAJEBYgFjAWkBagFlAWYAhgGOAicClgF0AXkBcgFzAZIDUAFtAHYBZwFrAXEB8wH7AfIB/AH5Af4B/wIAAf0CAwIEAAACAgIIAgkCBwCKAJoAoABuAJwAnQCeAHcAoQCfAJsABAZmAAAA7ACAAAYAbAAAAAIACQANACEAfgCgAKwArQC/AMYAzwDmAO8A/gEPAREBJQEnATABOAFAAVMBXwFnAX4BfwGSAaEBsAHwAfsB/wIZAhsCNwJZArwCxwLJAt0C8wMBAwMDCQMPAyMDigOMA5IDoQOwA7kDyQPOA9ID1gQlBC8ERQRPBGIEbwR5BIYEzgTXBOEE9QUBBRAFEx4BHj8ehR7xHvMe+R9NIAsgFSAeICIgJiAwIDMgOiA8IEQgdCB/IKQgpyCsIQUhEyEWISIhJiEuIV4iAiIGIg8iEiIaIh4iKyJIImAiZSXK7gL2w/sE/v///f//AAAAAAACAAkADQAgACIAoAChAK0ArgDAAMcA0ADnAPAA/wEQARIBJgEoATEBOQFBAVQBYAFoAX8BkgGgAa8B8AH6AfwCGAIaAjcCWQK8AsYCyQLYAvMDAAMDAwkDDwMjA4QDjAOOA5MDowOxA7oDygPRA9YEAAQmBDAERgRQBGMEcAR6BIgEzwTYBOIE9gUCBREeAB4+HoAeoB7yHvQfTSAAIBMgFyAgICUgMCAyIDkgPCBEIHQgfyCjIKcgqyEFIRMhFiEiISYhLiFbIgIiBiIPIhEiGiIeIisiSCJgImQlyu4B9sP7Af7///z//wABBBgEEv/1AAD/4gAA/8AAAP+/AAABMQAAASwAAAEoAAABJgAAASQAAAEiAAABHAAAAR4AAP8B/vT+5wFhAAAAoQBkAGb+Yf5AAJb91P2l/cT9r/2j/aL9nf2Y/YUAAP9w/28AAAAA/QUAAP9Q/Pn89gAA/LUAAPytAAD8ogAA/JwAAP6eAAD+mwAA/EUAAOVV5RXkxeT45Fnk9uQK4VYAAOFN4UzhSuFB4xvhOeMT4TDhAeD3AADg0QAA4HXgaOBm4Fvfj+BQ4CTfgd6n33XfdN9t32rfXt9C3yvfKNvEE44KzgAAApQBmAABAAAAAAAAAAAA5AAAAOQAAADiAAAA4AAAAOoAAAEUAAABLgAAAS4AAAEuAAABOgAAAVwAAAFoAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEAAAAAAFMAWgAAAGAAAAAAAAAAZgAAAHgAAACCAAAAioAAAI6AAACxAAAAtQAAALoAAAAAAAAAAAAAAAAAAAAAALcAAAAAAAAAAAAAAAAAAAAAAAAAAACzAAAAswAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqYAAAAAAAAAAwQcAeoB6wHxAfIB8wH0AfUB9gB/Ae0CAQICAgMCBAIFAgYAgACBAgcCCAIJAgoCCwCCAIMCDAINAg4CDwIQAhEAhACFAhwCHQIeAh8CIAIhAIYAhwIiAiMCJAIlAiYAiAHsA/AAiQHuAIoCVQJWAlcCWAJZAloAiwCMAI0CYwJkAmUCZgJnAmgCaQCOAI8CagJrAmwCbQJuAm8AkACRAn4CfwKCAoMChAKFAe8B8ACSAfcCEgCpAKoC+ACrAvkC+gL7AKwArQMCAwMDBACuAwUDBgCvAwcDCACwAwkAsQMKALIDCwMMALMDDQC0ALUDDgMPAxADEQMSAxMDFAMVAL8DFwMYAMADFgDBAMIAwwDEAMUAxgDHAxkAyADJA1oDHwDNAyAAzgMhAyIDIwMkAM8A0ADRAyYDWwMnANIDKADTAykDKgDUAysA1QDWANcDLAMlANgDLQMuAy8DMAMxAzIDMwDZANoDNAM1AOUA5gDnAOgDNgDpAOoA6wM3AOwA7QDuAO8DOADwAzkDOgDxAzsA8gM8A1wDPQD9Az4A/gM/A0ADQQNCAP8BAAEBA0MDXQNEAQIBAwEEBAYDXgNfARIBEwEUARUDYANhA2MDYgEjASQECwQMBAUBJQEmAScBKAEpBAcECAEqASsEAAQBA2QDZQPyA/MBLAEtBAkECgEuAS8D9AP1ATABMQEyATMBNAE1A2YDZwP2A/cDaANpBBMEFAP4A/kBNgE3A/oD+wE4ATkBOgQEATsBPAQCBAMDagNrA2wBPQE+BBEEEgE/AUAEDQQOA/wD/QQPBBABQQN3A3YDeAN5A3oDewN8AUIBQwP+A/8DkQOSAUQBRQOTA5QEFQQWAUYDlQQXA5YDlwFiAWMEGQQYAXcD8QF5AZIDUANYA1kABAZmAAAA7ACAAAYAbAAAAAIACQANACEAfgCgAKwArQC/AMYAzwDmAO8A/gEPAREBJQEnATABOAFAAVMBXwFnAX4BfwGSAaEBsAHwAfsB/wIZAhsCNwJZArwCxwLJAt0C8wMBAwMDCQMPAyMDigOMA5IDoQOwA7kDyQPOA9ID1gQlBC8ERQRPBGIEbwR5BIYEzgTXBOEE9QUBBRAFEx4BHj8ehR7xHvMe+R9NIAsgFSAeICIgJiAwIDMgOiA8IEQgdCB/IKQgpyCsIQUhEyEWISIhJiEuIV4iAiIGIg8iEiIaIh4iKyJIImAiZSXK7gL2w/sE/v///f//AAAAAAACAAkADQAgACIAoAChAK0ArgDAAMcA0ADnAPAA/wEQARIBJgEoATEBOQFBAVQBYAFoAX8BkgGgAa8B8AH6AfwCGAIaAjcCWQK8AsYCyQLYAvMDAAMDAwkDDwMjA4QDjAOOA5MDowOxA7oDygPRA9YEAAQmBDAERgRQBGMEcAR6BIgEzwTYBOIE9gUCBREeAB4+HoAeoB7yHvQfTSAAIBMgFyAgICUgMCAyIDkgPCBEIHQgfyCjIKcgqyEFIRMhFiEiISYhLiFbIgIiBiIPIhEiGiIeIisiSCJgImQlyu4B9sP7Af7///z//wABBBgEEv/1AAD/4gAA/8AAAP+/AAABMQAAASwAAAEoAAABJgAAASQAAAEiAAABHAAAAR4AAP8B/vT+5wFhAAAAoQBkAGb+Yf5AAJb91P2l/cT9r/2j/aL9nf2Y/YUAAP9w/28AAAAA/QUAAP9Q/Pn89gAA/LUAAPytAAD8ogAA/JwAAP6eAAD+mwAA/EUAAOVV5RXkxeT45Fnk9uQK4VYAAOFN4UzhSuFB4xvhOeMT4TDhAeD3AADg0QAA4HXgaOBm4Fvfj+BQ4CTfgd6n33XfdN9t32rfXt9C3yvfKNvEE44KzgAAApQBmAABAAAAAAAAAAAA5AAAAOQAAADiAAAA4AAAAOoAAAEUAAABLgAAAS4AAAEuAAABOgAAAVwAAAFoAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEAAAAAAFMAWgAAAGAAAAAAAAAAZgAAAHgAAACCAAAAioAAAI6AAACxAAAAtQAAALoAAAAAAAAAAAAAAAAAAAAAALcAAAAAAAAAAAAAAAAAAAAAAAAAAACzAAAAswAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqYAAAAAAAAAAwQcAeoB6wHxAfIB8wH0AfUB9gB/Ae0CAQICAgMCBAIFAgYAgACBAgcCCAIJAgoCCwCCAIMCDAINAg4CDwIQAhEAhACFAhwCHQIeAh8CIAIhAIYAhwIiAiMCJAIlAiYAiAHsA/AAiQHuAIoCVQJWAlcCWAJZAloAiwCMAI0CYwJkAmUCZgJnAmgCaQCOAI8CagJrAmwCbQJuAm8AkACRAn4CfwKCAoMChAKFAe8B8ACSAfcCEgCpAKoC+ACrAvkC+gL7AKwArQMCAwMDBACuAwUDBgCvAwcDCACwAwkAsQMKALIDCwMMALMDDQC0ALUDDgMPAxADEQMSAxMDFAMVAL8DFwMYAMADFgDBAMIAwwDEAMUAxgDHAxkAyADJA1oDHwDNAyAAzgMhAyIDIwMkAM8A0ADRAyYDWwMnANIDKADTAykDKgDUAysA1QDWANcDLAMlANgDLQMuAy8DMAMxAzIDMwDZANoDNAM1AOUA5gDnAOgDNgDpAOoA6wM3AOwA7QDuAO8DOADwAzkDOgDxAzsA8gM8A1wDPQD9Az4A/gM/A0ADQQNCAP8BAAEBA0MDXQNEAQIBAwEEBAYDXgNfARIBEwEUARUDYANhA2MDYgEjASQECwQMBAUBJQEmAScBKAEpBAcECAEqASsEAAQBA2QDZQPyA/MBLAEtBAkECgEuAS8D9AP1ATABMQEyATMBNAE1A2YDZwP2A/cDaANpBBMEFAP4A/kBNgE3A/oD+wE4ATkBOgQEATsBPAQCBAMDagNrA2wBPQE+BBEEEgE/AUAEDQQOA/wD/QQPBBABQQN3A3YDeAN5A3oDewN8AUIBQwP+A/8DkQOSAUQBRQOTA5QEFQQWAUYDlQQXA5YDlwFiAWMEGQQYAXcD8QF5AZIDUANYA1kAAAACAMUEFAK9BhgABQALAAABAyMTNzMFAyMTNzMBiGpZOhiIAQdrWjwXiQWN/ocBcJSL/ocBd40AAAIAQwAABM8FsAAbAB8AAAEjAyMTIzczEyM3IRMzAzMTMwMzByMDMwcjAyMDMxMjApnvnIuc3Bv1ie8bAQifi5/vn4yfuRvTic8b552MHu6J7gGa/mYBmocBZokBoP5gAaD+YIn+mof+ZgIhAWYAAAABAEf/MAQ+BpsAKwAAATYmJy4BNz4BPwEzBx4BByM2JiMiBgcGFhceAQcOAQ8BIzcuATczBhYzMjYDEQ9fhbacHBvNoiORJJaIILQYWG1rhhERW4+4lRse2LAekR6brSK1G3lvdp4BdmF6NT/Gra3IFNrcGuvJkqJ+bGhzOUS/rLXCEr/AE9TVpnx+AAUA0//rBTAFxQANABsAKQA3ADsAABM+ATMyFg8BDgEjIiY3MwYWMzI2PwE2JiMiBgcBPgEzMhYPAQ4BIyImNzMGFjMyNj8BNiYjIgYHBScBF/wbtIR5fBkPHLODen0ahxE2SUFiEA8QNEhCZA8BZRu1g3l8GQ8cs4N6fRqHETZJQmIQDxA1SEJkD/4BWAN6WASYiqOuf02Koa1+UWNpS01RZWtL/M2Jo65+TouhrX9SY2lMTlFkakv2QQRyQQAAAAMAG//rBIQFxQAgACsAOAAAEz4BNy4BNz4BMzIWBw4BDwETPgE3Mw4BBxcjJw4BIyImBTI2NwEHDgEHBhYTBhYXNz4BNzYmIyIGORSdmDwuDh3Lo5CeFRFycHX8M0IPohZpVYzYQFa7YsbQAa1Di0P+8yljSQkTa5YJHymQPDIKC0pLS2UBhoGuX2aZVLKss4BohUxT/mNCmlqL1lrkaD4/404yMgG4HUl7NXiOA+k4ckVhJ1g4QltxAAAAAQDGBCMBqAYYAAUAAAEDIxM3MwGWd1k8FZEFqP57AXWAAAAAAQBX/ioDHwZqAA8AABMSADcXBgADBwISFwcmAhOZQgF0vxGT/vo4AjtuczaZzEACTwGfAhJqeGz+K/6gDv6R/j14b2cCJAGQAAAAAAH/jP4qAlUGagAPAAABAgAHJzYAEzcSAic3FhIDAhRD/oy9FJEBCTkCOnZrOJfMPwJF/l/98GpvbAHdAWEOAWoBzHRvZ/3Z/nMAAAABAKECYgOgBbAADgAAASU3FxMzAyUXBRMHCwEnAaP+/kv9PJVPASYP/tR/jG/daAPYW5RwAVn+oXCWXP7wXQEh/uZaAAEAcgCSBDUEtgALAAABIQchAyMTITchEzMCwAF1I/6MXLZc/oojAXVWtgMLrP4zAc2sAasAAAAAAf+Y/swBAADaAAkAADcOAQcnPgE/ATPiFn9eVzxGER+2RmvHSEhKkFWXAAABAD4CIQIjArYAAwAAASE3IQIF/jkeAccCIZUAAQBGAAABIwDFAAMAADMjNzP8tie2xQAAAf+m/4MDsQWwAAMAABcjATNBmwNymX0GLQAAAAIAUP/rBGEFxQANABsAAAECACMiAhsBEgAzMhIDJzYmIyIGBwMGFjMyNjcD5T3+7dC/tjhFPAEV0L+0N60pV39zrSZUKll+dKsnAiz+0P7vASoBFwFXAS4BFP7V/uko0bPEwP5b0bXEwgAAAAEBcAAAA14FsAAFAAAhIxMFNyUCO7X5/vEYAdYE3Ah3ZQAAAAEALQAABDMFxQAYAAApATcBPgE3NiYjIgYHIzYkMzIWBw4BBwEhA5r8kxUCEZFsDxNdZYqiF7UhARPcsrkcFaGU/lICk4MCE5GnW3aQnI/L9uKzf+CT/lcAAAAAAQA1/+sEKAXFACoAAAE/ATMyNjc2JiMiBgcjNiQzMhYHDgEHHgEHBgQjIiY3MwYWMzI2NzYmKwEBmQsHn3h/ExVddWqZErUcAQbAucAgEYBwc0wSIv7xw7fUH7YUandznRYXXoSfAsNGJ4Z2hX6Jc7Te1chirS8ttnLT19e/fIWJiJF6AAAAAAIAJwAABBwFsAAKAA8AAAEzByMDIxMhNwEzASETJwcDWrweu0S0RP2eFQMhv/zrAZ+MAyAB6JX+rQFTawPy/DgCvAE6AAAAAAEAaP/rBD4FsAAfAAAbASEHIQMXPgE3NhIHDgEjIiY3MwYWMzI2NzYmIyIGB8vOAqUb/fRuAy1vR7+pJSb716nJIasVaGpyoBoYY3ZqcCMCkQMfqf5gASItAgL+++To/cnLgH+xnZetSEoAAAIAZ//rBBkFxQAaACcAAAEyFhcHLgEjIgYPAT4BMzISBwYAIyICGwESABMiBg8BBhYzMjY3NiYDHkWFKD4pXkWO3SAERaFbsq8hJv71xcPYLi4uAVA4XpExEiN5fG+hGRlmBcUiG5EaHvjLGDc7/vTS7v7xATIBGwEfASYBSP1zVEl118/Ompy0AAAAAQDYAAAEhAWwAAwAAAEAAgMHIzcSABMhNyEEbP7T9WAntidgATPy/R8YA5QFGv7F/iH+mZmZAWICGAEHlgAAAAMANf/rBFgFxQAXACMALwAAAQ4BBx4BBwYEIyImNz4BNy4BNz4BMzIWATYmIyIGBwYWMzI2EzYmIyIGBwYWMzI2BDIalXBraBct/u/Mv9EpGqyEXVYXKvu9q7/+whpxdW61GBtvfG2xexdfZF+ZFxleaFyaBDV+pigvt3rbw9TKiLYpLadx0b/Q/JiEkZt6iIWQAyF3h4tze36IAAIAf//rBDcFxQAbACgAACUyNj8BJw4BIyICNzYAMzISCwECACMiJic3HgETMjY/ATYmIyIGBwYWAa6ExiQFAzaSV8G/JiYBHbTQyyw5MP7R3EePNzM1cLVlmCwYIGaIZLEaG2OA2NghAUVDAQbu8QEW/uf+6v6c/tX+5BwfkB0ZAd9jTpjNus6jp7j//wBGAAAB1AQ6ACYAEAAAAAcAEACxA3X////G/swB1QQ6ACcAEACyA3UABgAOLgAAAQBlAMUDxQRJAAoAAAEPARcFBwE/AQEHAWVPAUgB2yf9VBcGA0MmApsVAxTpwQF7ch0BesEAAAACAI4BkAQIA80AAwAHAAABITchAyE3IQPo/PkgAwdz/PkgAwcDL579w54AAAEAVgDGA9oESgALAAATNwEPAgE3JTc1J+QmAtAGEQb8mSUCX1JJA4+7/oYdVR3+hbzyFQMWAAAAAgDCAAAD5gXFABkAHQAAAT4BNz4BNzYmIyIGByM+ATMyFgcOAQcOAQcDIzczAU0eQHN7XxMXT2ZSjxO3JPyrrqskHJySPSYSTL4pvgGZk2lef3VddmtnYqnAybONu4A2VF7+Z8sAAAACABP+OwbGBZYAMwBDAAABBgAjIiYnDgEjIiY3EgAzMhYXBzMDBhYzMjY3EgIhIAADAhIhMjY3Fw4BIyAAExIAISAAAQYWMzI2Nz4BNxMuASMiBgZgNf760kFTBkGTW3BVOEsBDpxcdTgEBaMgKDBsvixd0P7B/u7+OFhe3QEqT7NCD0rGXf6v/tJnaAINAWEBUAEm+9koHkc6cDgCBgSXFzEecKwB99v+z1VOVE/xxAEIATM2NAT9uHNS5rEBhwGj/jH+jP6A/lArI2grLgHzAbABsAII/g39/ZKVNEQMGQ8CHQwO3QAAAv/VAAAEfwWwAAcACwAAASEDIwEzEyMBIQMnA5H9ztK4Ay+b4Ln96gHNXAMBhP58BbD6UAIZAqABAAAAAwBYAAAE0AWwAA8AGAAhAAAzASEyFgcOAQcVHgEHBgQjCwEhMjY3NiYjJSEyNjc2JiMhWAEjAbjL0icWjGV0YRss/vLXtWsBPnitGRtWff7FASljnRcab4r+/QWwxMVqlCIDG8eI2cECrf3oh3yMiZV6b4JtAAAAAQBi/+sE+AXFABsAAAEGBCMiABsBEgAzMhIHIzYmIyICBwMGEjMyNjcEdUP+89/f/vs2MzsBNezZ+Be3C4qZkNooMyyYoouhNwG/4PQBagELAQEBKAE8/vLgo7X+/8v+/dj++JinAAACAFgAAAUdBbAACQATAAAzASEgAAMHAgAhCwEhMhI/ATYCI1gBIwF6AQABKDcnPv6s/u8K5wEPsfMrKCy/xwWw/pT+7cX+zf7HBRr7ewEB1sjeAQgAAAAAAQBYAAAE8gWwAAsAAAEhAyEHIQEhByEDIQQC/ZJpAswe/H8BIwN3Hv0+YAJuAqb975UFsJb+IgABAFgAAAT5BbAACQAAASEDIwEhByEDIQP5/ZWBtQEjA34e/TdmAmsCiP14BbCW/gQAAAAAAQBo/+sFDwXFAB8AACUGBCMiABsBEgAzMhYHIzYmIyIGBwMGFjMyNjcTITchBFtA/vvC6P78NTs5AV3z2NYLtQJ0mpT6Jjwrn6ttqidD/tUeAeC/UYMBTwEKASkBIAE48smInf3D/tXV70QqAVCVAAEAWAAABXkFsAALAAAhIxMhAyMBMwMhEzMEVrWB/WyBtQEjtYQClIS1Aob9egWw/WsClQABAGIAAAI6BbAAAwAAISMBMwEXtQEjtQWwAAAAAQAP/+sEUgWwAA8AAAEzAwYEIyImNzMGFjMyNjcDnbXSK/74vrvFKrUeYnthoxoFsPvk1NXW0JZ7ln4AAQA+AAAFNQWwAAwAAAEjAyMBMwMzATMJASMCAomEtwEjt3+TAiPm/WsBhM8Clf1rBbD9hAJ8/Sj9KAAAAQBYAAADrQWwAAUAACUhByEBMwErAoIe/MkBI7WVlQWwAAAAAQBYAAAGswWwABEAAAETMwEzASMbAScBIwMjCwEjAQJkwgMCouj+3bV1iQP9WnnOA2R1tQEjBbD7UwSt+lACRwJUAftkBJj9r/25BbAAAAABAFgAAAV6BbAACwAAISMBIwMjATMBMxMzBFe2/lID47UBI7UBrgPjtgRw+5AFsPuRBG8AAgBe/+sFNgXFAA0AGwAAAQIAIyIAGwESADMyAAMnNiYjIgYHAwYWMzI2NwTOPP6y/eX+/DYzOwFE9OwBEDW0K6qzl98pMy2gqqHoKgJO/tr+wwFrAQoBAQEmAT7+k/73Atr++M7+/dz+99EAAgBYAAAFGAWwAAoAEwAAAQMjASEyFgcGBCMlITI2NzYmIyEBgnW1ASMCBM7LJyv+7OH+zwFPg7EZGmaP/rECSv22BbDww9bdlaN5hZoAAAACAF7/DAU2BcUAEwAhAAABDgEHFwcnDgEjIgAbARIAMzIAAyc2JiMiBgcDBhYzMjY3BM4kl3Kqk8MrVS7l/vw2MzsBRPTsARA1tCuqs5ffKTMtoKqh6CoCTrH9TtNz9gsMAWsBCgEBASYBPv6T/vcC2v74zv793P730QAAAgBXAAAFAgWvABoAIwAAAQMjASEyFgcOAQceAQ8BBhYXByMmNj8BNiYjJSEyNjc2JiMhAYt+tgEjAerUyikZkHlmRhkbDwccBbseBQ8bGWBx/s0BI5OrGxtnk/7MAnr9hgWv08p8oC8prn2JSWYjGCN+S4WCh5WDgod/AAEAQ//rBMAFxQAlAAABNiYnLgE3NiQzMhYHIzYmIyIGBwYWFx4BBwYEIyIkNzMGFjMyNgN+GHCz1rEoIwEFw9jpKrYciZJpnREaZrvbsCcl/vXM2f7jMLUjuJpqqwFMd4RCSMvGsbLs1ouhdFd/d0dPx8O4q9brq4FyAAABAOwAAAULBbAABwAAASEBIwEhNyEE7f5a/vu1AQX+Wh4EAQUa+uYFGpYAAAEAZ//rBVcFsAARAAABAwIEIyImNxMzAwYWMzI2NxMFV8U0/r7y1u0wxbbFJYqWkeIixQWw/CX+/ef87gPb/CW2n62oA9sAAAEAzQAABVcFsAAJAAABHwE3ATMBIwEzAkAMAzMCEcT9IJ3+88QBXnIBcwRS+lAFsAAAAAABAOwAAAbsBbAAFQAAAQczNwEzEx8BNwEzASMDJyMHASMDMwHDBANGAZOhYQgDOwFUtf3homkEAy/+TqJMtQHvv78Dwfw/wAHBA8H6UAP9iYn8AwWwAAAAAf/8AAAFHQWwAAsAAAkBMwkBIwMBIwkBMwKnAZvb/d4BQtfr/l3cAi3+xtkDcwI9/S79IgJI/bgC3gLSAAAAAAEA7gAABVMFsAAIAAAJATMBAyMTATMCjQH3z/1oZ7Rp/uXQAs0C4/xU/fwCDwOhAAEAIAAABFsFsAAJAAA3IQchNwEhNyEH+QK0HvyRCQNE/ZAeA0AblZWNBI2WiAAAAAEAEv7IArQGgAAHAAABIwEzByEBIQKcr/70rxj+mgE8AWYF6vl0lge4AAAAAQD3/4MCnAWwAAMAABMzEyP3rPmsBbD50wAAAAH/l/7IAjkGgAAHAAATIQEhNzMBI9MBZv7E/poYsQEMsQaA+EiWBowAAAAAAQB8AtkDIgWwAAkAAAEjATMTIwMnIwcBJKgBp3uEp0YCAx8C2QLX/SkBqkxMAAAAAf+W/2sDDQAAAAMAAAUhNyEC7/ynHgNZlZUAAAEA8wS7AkgFxQADAAABIwMzAkiTwtsEuwEKAAACADr/7AP3BE4AIAArAAAhNDY3Jw4BIyImNzYkOwE3NiYjIgYHIzYkMzIWBwMOARclMjY/ASMiBgcGFgKgBAUDQq5dlokeIgEB0L4WFVdnWI4OtRsBALaktSJoDQkE/jlXrS8ow2ukEBFBMz4fAUhdrJaoom5paWRGhbu7r/32PWY3i2BEyXtTUE8AAAIANf/rBCcGGAASACAAAAEOASMiJicHIwEzAxc+ATMyEgMjNiYjIgYHAx4BMzI2NwPvM+i+WY0rM50BOLZ0AziOV7GnM7UnXIdPfTJgGW9ae5chAeL/+GBWoQYY/b0BPD7+rP79yvNeUf4gS1W3pgABAEf/7AP7BE4AGwAAJTI2NzMGBCMiAj8BNgAzMhYHIzYmIyIGDwEGFgHxWqAPrBn+8qbXuyUHJwER4a7BGqwQameNpBoHHFWBeFyazwEy6ir1ASfeqmyG4qQqsdYAAAACAET/6wSVBhgAEgAgAAATGgEzMhYXEzMBIzcnDgEjIgI3MwYWMzI2NxMuASMiBgd3OO7BV4greLX+yJ0JAzyQWLCuL7YkYYlMdTNlG2tUfJ8mAh4BHAEUSEQCVvnoaAI/QAE06rPRU08B+kRP2b0AAgBH/+wD6wROABUAHQAABSICPwE2ADMyEg8BIQYWMzI2NxcOAQMiBgchNzYmAePOzicHJwEptMerIxP9bBhrh1qXPDNAuQFaoCkB2gQTWRQBKvEt9QEl/vvdea3FOTJ7OksDzKqGGn2ZAAAAAQCKAAADhwYtABcAADMTIzczNz4BMzIWFwcuASMiBg8BMwcjA4q8nRydHCXFnB5AJTMQLRtNaBMc0hzSvAOtjYu7rQsKkQUGamOLjfxTAAACADf+SwQ9BE4AHgAsAAATGgEzMhYXNzMDBgQjIiYnNx4BMzI2PwEnDgEjIgI3MwYWMzI2NxMuASMiBgd6OPHCXIwrLJnVLv752kWkOUwsg0V+oRwPAziKU7GxL7UkZYlNdjNkG2tVfaMlAh4BHAEUUEyI+9Tk3ysklB8kmItNATg5ATXpstJUUAH2RVDavAABADUAAAQZBhgAFAAAARc+ATMyFgcDIxM2JiMiBgcDIwEzAaoDQKRem48rh7WIHk9vSY85nrYBOLYDuwJITdDZ/VsCp5Z3VEj86AYYAAAAAAIARAAAAjEGGAADAAcAADMjEzMTIzcz+bXYtTi1KLUEOgEYxgAAAAAC/x3+SwI5BhgADwATAAABAw4BIyImJzceATMyNjcbASM3MwHe6iW5lRswGSsNMQ48WhXq6bYntgQ6+222pgkJlgUIW2YEkwEcwgAAAQA2AAAEKAYYAAwAAAEjAyMBMwMzATMJASMByHhktgE4trZ2AW7W/kMBFtYB9v4KBhj8dQGt/hP9swAAAQBEAAACMQYYAAMAADMjATP5tQE4tQYYAAAAAAEANQAABlsETgAkAAABFz4BMzIWFz4BMzIWBwMjEzYmIw4BBxUDIxM2JiMiBgcDIxMzAaECQKVmXn0UQq9vk4stgraCI0hqY5AgiraDIUtpUn4unbbYowOyAUxRYmNeZ+Dk/XYCi7F4AZFuA/1PAo2ngFNL/OoEOgAAAAABADUAAAQYBE4AFAAAARc+ATMyFgcDIxM2JiMiBgcDIxMzAZ8CQaZkm5EqibaIIE5xTI04nLbYowOoAVJVzNf9VQKnn25ZTfzyBDoAAgBG/+wEHAROAA0AGwAAEzYAMzISDwEGACMiAjczBhYzMjY/ATYmIyIGB3EpARrWzcUmBCn+5tbNxie2HmOJga4cBB1jiIGvGwIo/gEo/szyGP/+2wEx87fY4a4YtdvkrAAAAAL/4v5gBCYETgASACAAAAEOASMiJicDIwEzBxc+ATMyEgMjNiYjIgYHAx4BMzI2NwPuM+i+W4starYBK5wIAzuUWrKnNLYoYolJdjBqG2tWfJ8hAeH/90RD/e4F2m4BQEP+rP78yfVSSP3xQ0i8pQACAET+YAQrBE4AEgAgAAATGgEzMhYXNzMBIxMnDgEjIgI3MwYWMzI2NxMuASMiBgd3OO7BWYcsJZz+1bVjAzeETrCuL7YkYIlGbzJtHGhQfJ8mAh4BHAEURUR1+iYB8gI0NQE06rTVTUcCIj1F3L4AAQA1AAADDQROABAAAAEnIgYHAyMTMwcXPgEzMhYXAtJnR3QsmbbYow0DOYxVFC4LA5MGUEr9AQQ6jgFPVAcEAAEAO//sA8kETgAlAAABNiYnLgE3PgEzMhYHIzYmIyIGBwYWFx4BBw4BIyImNzMGFjMyNgK8C01/s58VFuesrLYXtQ1cX19yCgxGgLueFBnttbzBGLUMd11hfwEeRlIgLI+Bi7HBkE1uXkJFRx8tlIGXqNCQbF9WAAEAb//sAqQFQQAXAAABAzMHIwMGFjMyNjcHDgEjIiY3EyM3MxMCGjW/HL+EEiQrFDMTAhxdLGNjIISNHI01BUH++Y39alY5CAWDERWPnAKWjQEHAAEAWv/sBDsEOgAUAAAhNycOASMiJjcTMwMGFjMyNjcTMwMCwRICP6RknZMwf7Z/JkNpX5Mzm7XYkQFSVOHwAn39gb53W1MDBvvGAAABAJcAAAQKBDoACQAAARczNwEzASMDMwHFBQMgAWS5/eCJyrkBOlNTAwD7xgQ6AAABALIAAAX6BDoAFQAAAQcXNwEzExUzNwEzASMDLwEHASMDMwGEBQM4AVOSPwM8ASm0/gSSPgYDT/67k0y1AYaKAYsCtP1Mm5sCtPvGApu7Abz9ZQQ6AAAAAf/pAAAD8QQ6AAsAAAkBMwETIwMBIwEDMwIGARjT/mT40J7+3dMBqfLRAqcBk/3p/d0Bnv5iAiMCFwAAAf+8/ksEKgQ6ABUAAAEfAQEzAQ4BIyImJzcmFjMyNj8BAzMBtwcDAZ7L/V8/qXsVQhMxJGkLOEw+RaTLAYaFAQM6+x9vnwsFlQMIT2d1BCQAAAAAAQAIAAAD3wQ6AAkAADchByE3ASE3IQf7Akoe/OEbAsP94h4C+RmVlYUDHpeBAAAAAQBR/pADHAY9AB8AAAEuAT8BNiYjPwEyNj8BPgE3Fw4BDwEOAQceAQ8BBhYXAc+wcB0hEkhmEwRhdBMhHLnEEm5yFSETZlpJNxAhFzhj/pA4667Pd3h4F3xy0LTkOXEls4jQcJ4rL51nz4ytJgAAAAEANv7yAdwFsAADAAATIwEzyJIBFJL+8ga+AAAB/6n+kAJ2Bj0AHwAABz4BPwE+ATcuAT8BNiYnNx4BDwEGFjMPASIGDwEOAQdXbnIXIRJsYVE9EiEWOWI4r28cIRNJZxIFYnUSIR64wv4lsojPcpwqK51s0IyvJXE46q/QeHZwH35xz7TlOAABAIIBkwTMAyEAGQAAAQ4BIyImJy4BIyIGByc+ATMyFhceATMyNjcEzBe8fVF+Ry9QMD5rDIAXuX5Qg0MvUDE8bg0C5JDBQkoyMGtOEo+4RkY0LnNQAAAAAv/r/ooBxAQ6AAMABwAAEyMTMxMjNzOhtsS2N7Yotv6KA9IBEswAAAEAV/8LBAAFJgAhAAAlMjY3Mw4BDwEjNyYCPwE2Ej8BMwceAQcjNiYjIgYPAQYWAftaoA+sF+OWLbYwmX0fByPpwC22LoCCFawQameNpBoHHFWBeFyLxhTl8SsBHMUq3QEeG97lI8uNbIbipCqx1gABAC0AAAR/BcUAIQAAAQcOAQchByE3Mz4BPwEjNzMTPgEzMhYHIzYmIyIGBwMhBwG7GRU8JwKsH/x2HgkwUxYZmR2ULSz1tbGtI7caW2FYjhsuAYUdAmqYY6A6lZUNxWuYlQER3djTsIRpl4j+75UAAgAm/+UFjATxACMALwAAJQ4BIyImJwcnNy4BNz4BNyc3Fz4BMzIWFzcXBx4BBw4BBxcHAQYWMzIANzYmIyIAA8dWt2NbmT2bZaQiERUVWEJommVSsF5Vlj6rZrEkExQWUjtkm/0vK6qnlwEeJymppZn+4Wc+PUNCi4WTT7BjbrtPkoaONzlAO5qHoFC0ZmuyTIyGAnvQ+wEMv876/vUAAAEAcQAABS4FsAAWAAAJATMBIQchByEHIQMjEyE3ITchNyEDMwKLAdPQ/egBJRj+myIBZRj+m0G1Qf6iGAFeIv6iGAEk+NADGwKV/S94q3b+ugFGdqt4AtEAAAAAAgAB/vICEAWwAAMABwAAGwEzAxMjEzMBnraewraXtv7yAxb86gPIAvYAAAAC/8j+EQTBBcUAMQBDAAABDgEHHgEHBgQjIiY/AQYWMzI2NzYmJy4BNz4BNy4BNzYkMzIWByM2JiMiBgcGFhceASUuAScOAQcGFhceARc+ATc2JgQxFnFbOCYUJv7u2sf4LbchlIZ5sRMTabrWqiQUcFs3IxQkARbZz9AptRpyh4GqEhdiwtmn/hgpRR9IXQ0XY8AoQx5JYg8TawGvZ4gmM4VjurTN4gKge3ldZVxBQbO0Y4koM4dis7vhzoKXelxtWj1Fr1QLGA4UY0ZvXD8OFwwVY0ZkYgACAScE7APFBbAAAwAHAAABIzczBSM3MwOmyh/K/i3LH8sE7MTExAAAAwBS/+sF4AXEABsAJwAzAAABDgEjIiY/AT4BMzIWByM2JiMiBg8BBhYzMjY3JQIAMzIAExIAIyIAAxIAISAAAwIAISAABC4at5eSkB0THcuZj44YjhBEV1Z5EhMVR1tTYxD9VS4BAuzfAYArLP7/6+H+gZk1AboBHQEMAUIyNv5F/ub+8f6+AlSkltOwd7fMnptnU490eH6HWGSF/uX+ogFsAQ0BGQFc/pb+9QFOAZ3+U/7C/rH+YQGvAAACAMICtAN+BcUAIAArAAABJjQ3Jw4BIyImNz4BOwE3NiYjIgYHJz4BMzIWBwMOARclMjY/ASMiBgcGFgJ3AwMDKXFJaWYWF62cgQsOJzk8UwqbFrKHd3obPwsFBP67LXEbF4BDXwkKKwLCFi4WAS47e2l2bzVHQTg0Dm57job+xjVSLnk7JXNDLzMu//8AcAB3A5MDkQAmAXLw3QAHAXIBJv/dAAEApgF4A84DHwAHAAABBwMjEyE3IQO/ETW2Nf2uIAMIAtVV/vgBCJ8AAAAABABS/+sF4AXEAAsAFwAyADsAABMSACEgAAMCACEgABMCADMyABMSACMiAAEDIxMhMhYHDgEHHgEPAQ4BFwcjJjY/ATYmIyczPgE3NiYrAYY1AboBHAENAUIyNv5F/uX+8v6+oy4BAezgAX8rLP7/6+H+ggFpNoqIAQSLjRMLTEM6KAwJBwMGAo0GCQcIDTJKgI0+XQoMPV56AtkBTgGd/lP+wv6x/mEBrwE//uX+ogFsAQ0BGQFc/pb+rP6sA1KBf0JbIBxoSjgrPxUQFlIoNk5AfgE/O084AAAAAAEBAwUjA7gFsAADAAABITchA6H9YhcCngUjjQACAQUDwQMIBcUACwAXAAABPgEzMhYHDgEjIiY3BhYzMjY3NiYjIgYBGhemZlxvFRihZF5zjgw1My5TDAwyMi9XBMFzkZpqdYuVaz1FSjg9SE0AAAACAE4ACQP4BPMACwAPAAABIQchAyMTITchEzMTITchAqkBTxj+sUKjQv6eGAFiQ6Nq/PgeAwgDVpb+YQGflgGd+xaVAAEApwKbA1EFxwAZAAABITcBPgE3NiYjIgYHIz4BMzIWBw4BDwEXIQLM/dsZAU1ONwkLJzk8VQqdFrOIeHoXEl6LsAEBVQKbfgEIPkosNzxCNHCFf3RXYnCPAwAAAQCqAo8DYwXGACkAAAEzMjY3NiYjIgYHIz4BMzIWBw4BBx4BBw4BIyImNzMGFjMyNjc2JisBNwGjeztKCwo2QzFPCJ8VsHuAixYNUUA7NAwZuI1ymBefCjk+QF0KDTZGexEEbzs1MTczKWxvd248WhgaXEN5cnV0NDc8MkU1VQABAPsEvAKsBcYAAwAAATMBIwHR2/7XiAXG/vYAAf/r/mAEMwQ6ABcAAAEDNwYWMzI2NxMzAyM3Jw4BIyImJwMjAQHLfQEqSmVagS+fttijCwI0f1FBXiBetQErBDr9jwLRek9OAx37xmEBPDsjKP4qBdoAAAEAhwAAA9wFsAAKAAAhEyMiAjc2JDMhAQIDaE7PxyosARrhAQT+3QIIAQTQ4PT6UAAAAAABAMMCcAGkA0EAAwAAASM3MwF6tyq3AnDRAAAAAf/O/k0BIwAAAA8AADMHHgEHDgEjNzI2NzYmJze/Fzw/EBWjjQ5AXwsKOFQ5NQtQUmdqajIyNSMHhgAAAQEEApkCRgXFAAUAAAEjEwc3JQGkoIR3GgEbApkClAGCFwAAAgDPArMDowXFAA0AGwAAAT4BMzIWDwEOASMiJjczBhYzMjY/ATYmIyIGBwEEIMyXjJAdFyDLmIyRHp8UPFNKbRIXEjtSS20RBHagr7uUdaKsupRhZW1ZdV1nb1UAAAD//wA1AJkDYQO0ACYBcxQAAAcBcwFUAAD//wEOAAAFYAXEACcByQDXApgAJwF0AQUACAAHAZcCiQAAAAD//wEbAAAFvQXEACcBdAESAAgAJwHJANcCmAAHAcoC8QAAAAD//wC6AAAGEQXHACcBdAGyAAgAJwGXAzoAAAAHAcsAlQKbAAAAAv/z/nYDFgQ7ABkAHQAAAQ4BBw4BBwYWMzI2NzMOASMiJjc+ATc+ATcTMwcjAo0gQHJ8XxIYUGZRkBS1JPyqr6okHJySPSYTTL4pvgKhlGpcgHVbdmtnYqnAybOLvIA1VF8BmswAAAAC/54AAAd1BbAADwATAAApARMhASMBIQchAyEHIQMhARMnAQaL/MI5/fr+/N4EVgOBHv19TAIkHf3hVgKP/Ph0A/3tAWL+ngWwlv4mlf3qAXkC0AH9LwAAAQBIAOIEFwR2AAsAABMBAzcTARcBEwcDAUgBde+N7QFzXP6K8I3u/o0BXAFQAVB6/rMBTXr+sP6wegFN/rMAAAMAJv+jBWsF7AAZACQALwAAAQIAIyImJwcjNy4BNxMSADMyFhc3MwceAQcBBhYXAS4BIyICByE2JicBHgEzMgA3BNA6/pL9TYA1eYq3PigbMzkBZPRUjzttiq05JBj8RBMFFgK/J2pGmP0nAtQPAxL9RSNdPKEBBykCV/7j/rEsLaH0WOOFAQEBHAFRNjOQ5lfaff7/WpM8A6YqK/71xFCHOvxfIyEBCscAAAACAEgAAAR6BbAADAAVAAABAzMyFgcGBCsBAyMBEwMzMjY3NiYjAiE7+83MJCn+6t/7P7YBI11u/IGxFxlmjgWw/trtu83b/sYFsP5F/dqgcX2YAAABADD/7AQrBg8AJwAAMyMTPgEzMhYHDgEHBgAHDgEjIiYnNx4BMzI2NzYANz4BNzYmIyIGB+W12DD/s46gIRqhCxMBDRwl2a1IoR9IIm47YXYRE/7zHhKtEBRIQV6bHwQ68OWrpYPOOl7+8Iy0misdmR0vYFBhARKSXNJMZmSmmgAAAAADAAT/6wZgBE4ALAA3AD8AAAUiJicOASMiJjc+ATsBNzYmIyIGByc+ATMyFhc+ATMyEg8BIQYWMzI2NxcOASUyNj8BIyIGBwYWASIGByE3NiYEQXirL0XjmpeSHyLt1dYRF0VfXY0QsB7xuWOQI0uyZL6sLRf9ZSBnl1uUSyM6u/yoRK01LNRrmhARSQPIZKYsAeEGGk8VZF5Tb6+VrKBVdnJwUBKaqk9NTU/+/eN1s8A7MIUuTZVYOt90UlNYAzitix+GkwAAAAIAJv/rBKsF7QAgAC4AAAEWEg8BAgAjIgI3NgAzMhYXNzYmJwUnJS4BJzceARc3FwEuASMiBgcGFjMyNj8BA8hLKCkTNf7E0cHWKjEBLs9MgCsDBSst/tw0AQgfQiZWQm4v9TP+vBSCcXXHHh1vh3fRIxQFCHv+us9h/vb+3gEYzvkBB0U6AXKpQKBjkRglEJ4XRTCGY/0rPU/Tl5DB57BjAAAAAwBqALcELgSvAAMABwALAAABITchJSM3MwMjNzMECvxgJAOg/ri2KLbLtie2Alq02sf8CMcAAAADAEz/eQQ4BLkAGQAkAC8AABM2ADMyFhc3MwceAQ8BBgAjIiYnByM3LgE3MwYWFwEuASMiBgchNiYnAR4BMzI2N3EpARrWPGQrbHeZPy0VBCn+5tYzVydmdo1MOBi2DwseAb0bQyqBrxsCGQwGEv5OFzUjga4cAij+ASgdHKTnTdmEGP/+2xQUm9ZL5pBfljUCpBYY5KxPhDX9bA4N4a4AAv/r/mAELwYYABUAIwAAAQ4BIyImJwMjEzcbATMDFz4BMzISAyM2JiMiBgcDHgEzMjY3A/cz6L5biy1qtlMQyGC1cwM6jFWypzS2KGKJSXYwaRpqV3yfIQHh//dEQv3vAaBTA+cB3v3EATg7/qz+/Mn1UUj98EJJvKUAAAIAVQAABcMFsAATABcAAAEzByMDIxMhAyMTIzczEzMDIRMzASE3IQU8hxyHzbWB/WyBtcyHHIc7tToCkzu1/DMClC39bQSNjfwAAob9egQAjQEj/t0BI/1r5QAAAQA+AAABzQQ6AAMAADMjEzP1t9i3BDoAAQA+AAAEYAQ6AAwAAAEjAyMTMwMzATMJASMBrl5ctti2XFABxdv97wFY5AHP/jEEOv41Acv9+P3OAAAAAQBJAAADngWwAA0AAAElBwUDIQchEwc/ARMzAaYBDB/+82oCgh78yXx8IHyHtQNJVp9W/euVAmwnnycCpQAAAAEARwAAAlMGGAALAAABNw8BAyMTBz8BEzMBu5ggmI61f5AgkJm1A2g6oDr9OAJ+N6A3AvoAAAAAAQBG/ksFaQWwABgAAAkBDgEjIiYnNx4BMzI2PwEBIwMjATMBMxMFaf7LJbuVHC8aKgw9EDZYExL+TwPgtgEjtgGwA+EFsPn3tacJCZEFCGldWQRj+50FsPudBGMAAAAAAQA1/ksEEAROACAAAAEXPgEzMhYHAw4BIyImJzceATMyNjcTNiYjIgYHAyMTMwGgAkCiYZuQK5olupQcMhktDDwSN1QTmSBOck6CM6G22KMDsQFOUM3Y/P61pwkJmgUHYFwC/qBvSUP82AQ6AAAAAAIAT//rB4MFxQAXACUAACkBDgEjIgIbARIAMzIWFyEHIQMhByEDIQUyNjcTLgEjIgYHAwYWBmr8vVl5P97pNT05AVPyPYhGAzke/T5gAm4e/ZJpAsz7rDBqOOk0ZDWX6is9L4UKCwFLAQoBMAEgATUMCZb+Ipb97xUICQSOCAnn1/7O69UAAAADAET/6wbVBE4AIQAvADcAABMSADMyFhc+ATMyEg8BIQYWMzI2NxcOASMiJicOASMiAjczBhYzMjY/ATYmIyIGBwEiBgchNzYmeTQBI9dyoytQy2zBpisY/WsgZIdYnTwwQr2AdKUsTs9/x74xtSZZin28IwQlWYp9vCIEIlipLgHZBRlSAigBBQEhbmRmbP7523mwwzoyeztLamNmZwE08bvV5KwYudfmqgGQq4UagJYAAAABAEQAAANBBi0ADwAAMxM+ATMyFhcHLgEjIgYHA0T0JsSdHUEkMhMmGE5wE/QExbutDAmMBQZvY/s7AAAB/2b+SwNHBi0AIwAAASMDDgEjIiYnNx4BMzI2NxMjNzM3PgEzMhYXBy4BIyIGDwEzAoy2pR23kxwvGSQMPBA3URClnhaeFh3Amx8/Ji4QLhpQXxAWtgOt+/qxqwkJkQUIaV0EBo2LtrILCpEFBmlkiwAAAAIAWf/rBiUGNgAXACUAAAECACMiAhsBEgAzMhYXPgE3Mw4BBx4BByc2JiMiAgcDBhYzMgA3BMw6/pL94O41MzkBZPRpqT1XcRmjI5uAHgwStCqTr5j9JzQsiaahAQcpAlf+4/6xAWYBBgEBARwBUVJLCYl8r7wdTKtfAtb5/vXE/v3Y+QEKxwACAEb/7AUJBLAAFwAlAAATNgAzMhYXMjY3Mw4BBx4BDwEGACMiAjczBhYzMjY/ATYmIyIGB3EpARrWX5EyWVoZkSKFfhYJDQQp/ubWzcYnth5jiYGuHAQdY4iBrxsCKP4BKEhEd3ekpRNCllQY//7bATHzt9jhrhi12+SsAAAAAAEAZ//rBqUGDQAZAAABBz4BNzMOAQcDAgQjIiY3EzMDBhYzMjY3EwVXKFVkGqMqvKyBNP6+8tbtMMW2xSWKlpHiIsUFsMoakXzRzhT9e/795/zuA9v8JbafragD2wAAAAEAWv/sBVcEkQAcAAABDgEHAyM3Jw4BIyImNxMzAwYWMzI2NxMzBz4BNwVXJI2cp6ISAj+kZJ2TMH+2fyZDaV+TM5u1HFVLFwSRsJEI/LiRAVJU4fACff2BvndbUwMGigpmcQAB/xv+SwHcBDoADwAAAQMOASMiJic3HgEzMjY3EwHc6iW5lRowGioNPA83VhPqBDr7bbamCQmRBQhpXQSTAAAAAgA8/+wD9gRPABUAHQAAATISDwEGACciAj8BITYmIyIGByc+AQMyNjchBwYWAmnGxy8JM/7OtcKmLBkClR1jhVqdPC5BvSZXqi/+JwUaUgRP/tLuLf3+4wEBBtt5r8Q8MXw6TPwzqYYZgZUAAQFIBOQDhwXpAAgAAAEHIycHIzclMwOHBZRrppUFARZuBPwYlpYZ7AAAAAABAV4E5AOpBekACAAAATczBwUjJzczAmamnQT+4G26BJkFU5YS8/EUAAAAAAEBCwSlA08FsAANAAABDgEjIiY3MwYWMzI2NwNPFKuEfoMUkwsxR0JRCwWwf4ySeUZQVEIAAAAAAQFBBOoCMQWwAAMAAAEjNzMCCsknyQTqxgAAAAIBIgRfAsEF4AALABcAAAE+ATMyFgcOASMiJjcGFjMyNjc2JiMiBgEzEYJUS1wQE35TTV5wCSwpJUYJCSopJ0cFHlpob1NcY2pVLzg7LDA5PQAAAAH/t/5QAScANwATAAAhDgEHBhYzMjY3Bw4BIyImNz4BNwEnV2IJBhsoGTAXByBMMk9XDg+OjD5kPCUlEQt4ExljWlmVPAAAAAEBCATiA68F8QATAAABDgEjIiYjIgYHJz4BMzIWMzI2NwOvEIBWQIAyJkIHYA9/VzONMiZDCAXSYnxfQi8aYoFgQTEAAgEHBOQD7wXuAAQACAAAATMXASMDMwEjAxjWAf6xpBLJ/uWRBe4D/vkBCv72AAAAAgAd/ocBV/+rAAsAFwAAFz4BMzIWBw4BIyImNwYWMzI2NzYmIyIGKg5jPzhFDQ5ePjpJYAYdHBcrBgYaGhou6UVPVEBETFE/HSMlGyAkJgAB/fIEuv7KBhMAAwAAASMDM/7KeGCsBLoBWQAAAf5BBLv/owYUAAMAAAEzAyP++6jzbwYU/qcA///9WATi//8F8QAHAKD8UAAAAAAAAf5GBNn/lQZzAA8AAAE3PgE3NiYjNzIWBw4BDwH+Rh1NPwcJTUIcjnsTDl5BDwTZlwUdKSgnaV5dSEgJRgAAAAL9SwTk/8sF7gADAAcAAAEjAzMBIwMz/tak59sBpZGuyATkAQr+9gEKAAAAAfzc/rH9y/92AAMAAAEjNzP9pMgnyP6xxQAAAAEBZAT4AqoGeAADAAABMwMjAenB8FYGeP6AAAADAUEE7QP5BogAAwAHAAsAAAEjNzMFIzczNzMDIwPStye3/gG5J7mdyqqCBO3Dw8PY/vj//wDDAnABpANBAAYAdgAAAAEAVwAABLkFsAAFAAABIQEjASEEm/13/vu2ASMDPwUa+uYFsAAAAAAC/8wAAAS+BbAAAwAHAAABEyEJASEDIwPJ9fsOA2H9sAMQpAMFsPpQBbD65QQkAAADAE//6wUnBcUAAwARAB8AAAEhNyEXAgAjIgAbARIAMzIAAyc2JiMiBgcDBhYzMjY3A7D+JR4B2/E8/rL95f78NjM7AUT07AEQNbQrqrOX3ykzLaCqoegqApSW3P7a/sMBawEKAQEBJgE+/pP+9wLa/vjO/v3c/vfRAAAAAf/eAAAEXQWwAAcAAAEnASMBMxMjAwoD/ZG6AxSdzroEmAH7ZwWw+lAAAAADACIAAAShBbAAAwAHAAsAADchByETIQchEyEHIUADZx78mfQCwx79PU4DWx78pZWVAzyWAwqWAAEAWAAABXsFsAAHAAAhIwEhASMBIQRYtQEF/Wr++7UBIwQABRr65gWwAAAAAf/xAAAEoAWwAAwAAAkBIQchNwkBNyEHIQEDAP3nAuIe/EYcAjX+thwDjB79TQE2As79yJaOAk0CR46W/c0AAAMAVwAABX0FsAAVAB4AJwAAATMyEgcCACsBByM3IyICNxIAOwE3MwEiBgcGFjsBEzMDMzI2NzYmIwOzBdH0LzX+qeUFI7YjB9LyMTMBVuUHJbb/AJjhIyiApQeftp8HluElJ4GjBPb+zu/++/7hsbEBMfEBAwEguv6x2LbHxgMb/OXYt8TIAAABAIoAAAWSBbAAFwAAAT4BNxMzAwIABwMjEyYCNxMzAwYWFxMzAvKO0SJqtWo1/sfnSLZIyMsxarRqJm6EvbYCAxvUrAIS/e7+9v7rFf6WAWscASXyAhL97rvKFwOuAAABAB0AAAUIBcUAKAAAJT8BNhITNzYmIyIGDwECEhcPAiE3MyYCPwESADMyEgMHBgIHFzMHIQJjFwGLyTQXM4Cll+0uFzhbhwEXB/4zHt9ZOyMXPQFY8d3lOBclrXkB2B7+MyJzBhsBGwECdv7o/Op2/uz+9xsGcyKVYwEvrHQBNAFK/p7+5HS2/thdA5UAAAACAED/6wQ0BE4AHAAqAAABAwYWMzI2NwcOASMiJicOASMiAj8BEgAzMhYXNwEGFjMyNjcTLgEjIgYHBDSdExgjBxIGBSA5IkBIBEKeY6+gLwQ4AQTCWn0kLv2LJVSHT4E5XBRbUH22JQQ6/OxdOwMDiBMOS1RQTwEg6hUBGwEpU1CP/bu1wGBYAc1VXvK8AAAC//X+fwRwBcQAFAArAAABMhYHDgEHHgEHBgQjIiYnAyMBNiQDPwEzMjY3NiYjIgYHAx4BMzI2NzYmIwMLrLkiFHleZFcYLv7zxEqFMFy3ASMkAR04EA5MbIwXFFdqYKgWqB93VXOxGhhWbAXE261kli0vwH/i2S8w/jQFsbXf/P9QRXxsaIaRbfy6NDWggnulAAAAAQCz/mAEJgQ6AAsAAAEzAQMjEwMzExczNwNtuf3XYLZhlblXAQMkBDr8BP4iAeQD9v0AU1MAAAACAEH/7AQqBhwAIQAvAAABPgEzMhYXBy4BIyIGBwYWFxYSDwEGACMiAj8BPgE/AS4BAwYWMzI2PwE2JiciBgcBfB3TrEONQkIxfkRKawwLRXG6iSkEM/7f18jBLwQm1o0GU0dCJVyKfLkhBB1ldn28IAT2k5MtKIAXJEk/NlosS/7uzhf8/uwBKOgXvOsjCyeM/WGyytikF5HSGtyhAAAAAQAp/+0D/QRMACkAABM+ATcuATc+ATMyFgcjNiYjIgYHBhY7AQ8BIyIGBwYWMzI2NzMGBCMiJkgTeWZKRQ8h7sSizhy1D2phaIsNEFFwwggVwmyIERFpc2SjELUk/u+0tNABMGR9HyV2SKOWsI9OXmJEUlEmaldZUl9yTrSerAABAIv+gQRYBbAAIAAAAQcBDgEHBhYfAR4BBw4BByc+ATc2Ji8BLgE3NhI3ASE3BFgX/mualBwWKUpzhlcVEYpGTzk7Cgc3SU6aXCEauK0BRf2vHgWwdv5Snd6QalsTJixDbUqpM1M3Uy0nLxYXL56hgAEvrwFAlgABADX+YQQSBE4AFAAAARc+ATMyFgcDIxM2JiMiBgcDIxMzAaACQKJhno8t27XaIE5yToEzorbYowOxAU5QxOH7uAREoHNKRPzWBDoAAwBW/+sEZwXFAA0AFgAfAAABAgAjIgIbARIAMzISAwUhNzYmIyIGBwEhBwYWMzI2NwPrPf7t0L+2OEU8ARXQv7Q3/UQB8xwpV39zrSYBuf4NGipZfnSrJwIs/tD+7wEqARcBVwEuART+1f7pY4vRs8TA/uCF0bXEwgAAAAEAfv/rAfwEOQAPAAABAwYWMzI2NxcOASMiJjcTAfSiESUtFTAWDjBUM2tcIaAEOfzUVDQOC4AeFY6eAyIAAAAB/9H/8AO3Be4AIQAAMyMBJy4BIyIGIzc+ATMyFhcTHgEzOgE3Bw4BIyImJwMjB5vKAjgsCiUnCRwIHBFGGVVPCbsHHx8LEQgZDikVVVYTZAMzBALuOi4CjAQIU1X7qDUrApQFB1F9Al5zAAABADr+dwQbBcMAMwAAAS4BIyIGBwYWOwEHMwcjIgYHBhYfAR4BBw4BByc+ATc2Ji8BLgE3PgE3NS4BNzYkMzIWFwPjOF4zgqgQFnSfhAgBF4So3CAcbW1jgF4VEYlGTz8yDAk1TjLIpSsgvZVjXhQiAQ7cPIEoBQoRE21QcWsnb6CjiYsdFyNKbUmmNFM8RjcuJxMNNMDUosErAyuUXa+nFxAAAAEAcP/rBJcEOgAXAAABIwMGFjMyNjcXDgEjIiY3EyEDIxMjNyEEeXGEESUtFTAWDjBUM2tcIYL+jbq2unceA8YDpP1pVDQOC4AeFY6eAo38XAOklgAAAAAC/+L+YAQmBE4AEAAeAAABCgEjIiYnAyMTNRIkMzISAyM2JiMiBgcDHgEzMjY3A+0z+b9YgCpotsc1ARm8yao1tSlJh22uGz4XXlN8siEB9f8A/vc/QP31A+ICAQz+/sP++c7g64v+zUVJz6UAAAAAAQBJ/ooD/wROACEAAAEyFgcjNiYjIgYPAQYWFx4BBw4BByc+ATc2JicuAT8BNgACoae3JKsXVW96uB8IH3ihiWQWEIpGTj4yDAkzUNmtKwgxASAETtG3c3/qnCqWrTEsTW5IqDNTPUQ3MCcUNP7WKvYBJgACAEP/7ASzBDoAEAAeAAABIR4BDwEGACMiAj8BNgA3IQEGFjMyNj8BNiYjIgYHBJX+/EwzGgUu/trUx78xBDIBIdcCEfx3JlmKfbwjBCNciX26IAOjStGFF+X+5QE08Bj7ARYB/da71OOsGK/M2qEAAQC3/+sEHgQ6ABMAAAEhAwYWMzI2NxcOASMiJjcTITchBAH+qoQRJS0VMBYOMFQza1whgv7BHQNKA6b9Z1Q0DguAHhWOngKPlAAAAAEAWv/rA/QEOgAVAAABAwYWMzISNzYmJzMeAQcCACMiJjcTAcGDIkRZds8iFgkYvhsGHzb+5N+rny6DBDr9b6iBAQmogfuNbf2f/vT+xtvlAo8AAAIAP/4iBUAEOgAZACMAAAUmAjc+ATcXDgEHBhYXEz4BMzISBwYABQMjAT4BNzYmIyIGBwHq7b4vJKSNSV5vGyNnoZAWlXG01y0y/tP+7Fy2ATCo2R4cYYEaKAUQHAFB5rf2WoNKyHKq5hwC0XBy/svl9f7bF/4zAmYc6ZOh4ikcAAAAAAEAQ/4pBS4EOgAbAAABAz4BNzYmJzMeAQcCAAUDIxMmAhsBMwMGFhcTA3O9qNsgFgoavRwKHzX+1f7oWrZb2sU5YbZhL3GMvQQ5/E8f9ZyA+4ds+pz+/P7PFf47AcgcASwBGwHm/hjm0BYDswAAAAABAF3/6wXsBDoAKQAAAQ4BBwYWMzI2NxMzAwYWMzI2NzYCJzMeAQcKASMiJi8BDgEjIgI3PgE3AjNZeB0qMGpYkCQ8tzwnSmFglScWEiO/IxEfOOjFaIERAz2sdbZ6MiJxUwQ6iP+EzuGkswEr/tXClfG+hAEAh2/9n/7u/s51cgF4cAFJ+6vwcAAAAAIAWv/rBQoFxQAZACQAACUyNjcuAT8BPgEzMhYHAwIAIyICGwE3AwYWAQYWFxM2JiMiBgcCJZPoK8DNJg0l0JKLhyNmPf6y8NPZNoS3hSx0AYwbaoFIFyxEO2IVhvDTCvq/Pry/yrH+Av7T/swBWQEIApgC/Wba7AOEhZkIAWZ4Z3BvAAEAswAABNgFuwAjAAABPgEzMhYXBy4BIyIGBwEDIxMDLgEjIgYHNz4BMzIWFxMXMzcDW0mETR4vFjQFEwweOxn+aXS0dJYIKx8OFgQJGTAgR2EYVQQDIgTXfmYKDpIDBSUs/X79ugJEAoQtJAUDkg4KZ33+aEpKAAIAZP/rBjQEOgAXAC0AAAEjFgYHCgEjIiYvAQ4BIyICNz4BNyM3IQE2JichDgEHBhYzMjY/ATMHBhYzMjYGFn4MBRU42LFpgBADPat1pGgyFkEtaR4FZf6gEAEP/Qs2ShQqIFZXkSQztzMnSWJNgwOjVLZq/u/+zXZyAXlwAUn7cbJRl/31XbdgYrZczeKks/z8wpXyAAAAAQDb//UFfwWwABsAAAEhAz4BMzIWBwYEIzcyNjc2JiMiBgcDIwEhNyEE9/4eXVGQM9rZLC/+8+kaj6ocHHWYN5RIibYBBf58HgQcBRr+LRcd8Nvn1I+ckJaWGhb9VAUalgAAAAEAZv/sBPwFxgAfAAABBgQjIgAbARIAMzISByM2JiMiAg8BIQchBwYSMzI2NwR5Q/7z39/++zYzOwE17Nn4F7cLipmQ2igLAhke/ecKLJiii6E3AcDg9AFqAQsBAQEoATz+8uCjtf7/yzmVNdj++JinAAAAAv/eAAAH4wWwABYAHwAAAQMhMhYHBgQjIQEhAwIAKwE3MzISGwEBAyEyNjc2JiMFcXIBTs3JJyv+6t/9+wEF/itrVf717TEeJoW6RokCsXUBToG0GRpmjQWw/cX3xNbkBRr96/5k/peVAR8BUQKr/TD9tax7gqIAAgBXAAAH6AWwABIAGwAAASETMwMhMhYHBgQjIRMhAyMBMwEDITI2NzYmIwGxApV/tnwBT87MJSn+7OD9/Ib9a4a2ASO2ArJqAU6DrxcYaI8DNwJ5/Zbku8zbAqL9XgWw/QH97phye40AAAAAAQDyAAAFqgWwABcAAAEhAz4BMzIWBwMjEzYmIyIGBwMjASE3IQUP/hRZT5Rh1sYvW7VbJGSWT6FUjrUBBf6EHgQdBRr+RRQU0+3+OQHHtnQWFP05BRqWAAEAV/6aBXsFsAALAAABMwEhATMBIQMjEyEBerb++wKVAQW2/t3+YUi1SP5TBbD65QUb+lD+mgFmAAAAAAIASAAABKoFsAAMABYAAAEhAyEyFgcGBCMhASEBBwMhMjY3NiYjBIz9d1oBTs/MJyv+7eH9/AEjAz/84R9QAU6DsBkZZ48FGv4+5sLU3AWw/ROe/nCjeoCRAAAAAv+W/poFhQWwAA4AFQAAASMTIQMjEzM2EhsBIQEzAQYCByETIQTTtUf8Lki1ZnNaukKTAy3++7j9RDqnZQKV5/41/psBZf6aAftYAVABLQJG+uUC1fj+lnMEhQAB/8oAAAddBbAAFQAAASMDIxMjASMJATMTMxMzAzMBMwkBIwSJkIa1hpX9/uMCYf7o1OKZf7V/kgHg1P3VAS7iAp/9YQKf/WEDAQKv/YQCfP2EAnz9U/z9AAAAAAEAIP/rBLAFxQApAAABDgEHHgEHBgQjIiY3MwYWMzI2NzYmKwE/ATMyNjc2JiMiBgcjNiQzMhYEiReUdGxcGCz+zei7+Cu1GoKJjc0YHXqdmA0RmIqsFxh1l3DBFbUnASjK098EJ3CjLSyqfNnR1tN/lZd6k3c/V4Z0e4mQbMXN1wAAAAEAWAAABXoFsAALAAABMwEjEycBIwEzAxcExLb+3bbgA/yPtQEjteADBbD6UARfAfugBbD7oQEAAf/eAAAFcQWwAA8AAAkBIwEhAwoBKwE3MzISGwEFcf7dtwEF/iR5YfjgMB4lealPmwWw+lAFGv3r/l7+nZUBGQFXAqsAAAAAAQCj/+sFRQWwABUAAAEXMwEzAQ4BIyImJzceATMyNj8BAzMCbB8DAeTT/TNVlo8WPgchCT0QPlAyNu7LAvu4A237QIZ/BgOQAgJOTlQEQAADAFv/xAX2BewAFQAeACcAAAEzMgADAgArAQcjNyMiABMSADsBNzMBIgYHBhY7ARMzAzMyNjc2JiMD+RngAQQzOP6R9BontSca4f79NDcBbvUbKbX+6aj5Jy2OuBuvta8bpvgpK461BR7+uP8A/uj+zMbGAUgBAgEWATTO/p3ux9zZA2r8lu3K2NsAAAEAV/6hBXoFsAALAAABMwEhATMBMwMjEyEBerX++wKWAQW1/vuNd6FG/CcFsPrlBRv66f4IAV8AAQDRAAAFSAWwABMAAAkBIxMOASMiJjcTMwMGFjMyNjcTBUj+3bV6Yqdy18cwW7dbJWOXW71jiwWw+lACYR0a0u4Bxv46t3McHAK4AAEAVwAABzAFsAALAAAJASEBMwEhATMBIQECMP77AcwBBbX++wHJAQW2/t36SgEjBbD65QUb+uUFG/pQBbAAAAABAFf+oQcwBbAADwAACQEhATMBIQEzATMDIxMhAQIw/vsBzAEFtf77AckBBbb++5B2o0b6bwEjBbD65QUb+uUFG/rl/gwBXwWwAAAAAgDJAAAFgQWwAAwAFQAAEyEDITIWBwYEIyEBIQEDITI2NzYmI+cCKXgBTs/MJyv+7eH9/AEF/o0BsW8BToOwGRlnjwWw/ajmwtTcBRv9qP3So3qAkQAAAAMAVwAABqIFsAAKABMAFwAAASEyFgcGBCMhATMLASEyNjc2JiMBIwEzAbgBTs/MJyv+7eH9/AEjtpZvAU6DsBkZZ48Cl7UBI7UDWObC1NwFsP0T/dKjeoCR/T0FsAAAAAIASAAABJIFsAAKABMAAAEhMhYHBgQjIQEzCwEhMjY3NiYjAakBTs/MJyv+7eH9/AEjtpZvAU6DsBkZZ48DWObC1NwFsP0T/dKjeoCRAAAAAQCH/+wFNAXGAB8AAAE2ADMyEgsBAgAjIgI3MwYWMzISPwEhNyE3NiYjIgYHAR0tAUDr2+Q2Mzv+qO/c5i21I4GgkfUpC/3oHgIXCyt+n5PTHwPf4wEE/qD+8/7//tv+uQEF36qlAQzJOJU22/y0nQAAAAACAGL/6wblBcUAFQAjAAABAgAjIgATNyMDIwEzAzM3EgAzMgADJzYmIyIGBwMGFjMyNjcGfTz+sv3l/vw2BrN/tQEjtYayEDsBRPTsARA1tCuqs5ffKTMtoKqh6CoCTv7a/sMBawEKH/2BBbD9ZE0BJgE+/pP+9wLa/vjO/v3c/vfRAAACAAwAAATxBbAADQAWAAAzIwEuATc2JDMhASMTIQEjIgYHBhY7Ac3BAbt+XyApATbWAbL+3bdy/tEBwvuXrh0bf4j8Am82upvR5fpQAjwC3o2RhKYAAAAAAgBE/+sEUAYRABwAKgAAATISDwEGACMiAj8CEgA3PgE3Mw4BBw4BBxc+ARciBg8BBhYzMjY/ATYmAqG8uCIEKP7o1szJJgEVNgEo4H11DJQerriDzTcCS68kgKoXBBxjiYGuGwQYaAP7/u/YGPX+5gEm6QiAAVYBaiwZQEq4aCAYpKQBQEuVw5EYrc3VpRiaugAAAAMAQAAABCoEOgAPABgAIQAAMxMhMhYHDgEHFR4BBw4BIwsBITI2NzYmIyczPgE3NiYrAUDYAYy/xx4RaFRYSxIh4sG3QgEWYn8QEVVr+eFshhARZHvWBDqUlVJzHQMYh1qkjwHc/rdWT1VPkgFNTFVJAAAAAQA+AAADlQQ6AAUAAAEhAyMTIQN3/je6ttgCfwOj/F0EOgAAAv+a/sIETgQ6AA4AFQAANz4BNxMhAzMDIxMhAyMTAQ4BByETIUhieTtgApC7hl61QP1KQLZfAhovflAByZn+05VizuABlfxb/i0BPv7CAdMCELv8WQL8AAH/wwAABgEEOgAVAAABIwMjEyMBIwEDMxMzEzMDMwEzARMjA7R1XrZedf6U5QHd5Nugclq2WnMBVNv+UPjlAdj+KAHY/igCPgH8/j8Bwf4/AcH+A/3DAAABAB7/7QPEBEwAKwAAATMyNjc2JiMiBgcjPgEzMhYHDgEHHgEHDgEjIiY3MwYWMzI2NzYmKwE/AgFtr1xpEA9KZVOQDrQf+aqorh4QaVNOQxIh8bme0iK1EmNlX4kPE01rrwgJBQJ1UkxLW2RInKOil1F3IiJ9WqSfq6dUbGVMYUoqLRgAAAAAAQBAAAAERwQ6AAsAAAEzAyMTJwEjEzMDFwORtti2mwP9pLXYtZsDBDr7xgMJAfz2BDr89wEAAAABAEAAAARhBDoADAAAASMDIxMzAzMBMwkBIwHKeFy22LZcbAGp2v4JAT/mAc/+MQQ6/jUBy/36/cwAAAAB/9UAAARJBDoADwAAAQMjEyEDCgErAT8BMjYbAQRJ2Le6/rZKUse+NCQmW3M+bgQ6+8YDo/7H/rH+5aIBxwEAAdAAAAEAQAAABX8EOgAOAAAlATMDIxMnASMDIwMjEzMCpwH149i1mAL+LX2jA5y22OvyA0j7xgL8Af0DAwv89QQ6AAABAEAAAARGBDoACwAAISMTIQMjEzMDIRMzA262XP4+XLbYtl4Bwl62AdD+MAQ6/ioB1gAAAQBAAAAERwQ6AAcAACEjEyEDIxMhA2+2uv49urbYAy8Do/xdBDoAAAEAkAAAA/cEOgAHAAABIQMjEyE3IQPa/rK6tbr+uR0DSgOm/FoDppQAAAAAAwBA/mAFVwYYAB8ALQA7AAATGgEzMhYXEzMDPgEzMhIDBwoBIyImJwMjEw4BIyICNyU2JiMiBgcDHgEzMjY3IQYWMzI2NxMuASMiBgdzOfK3JkAbYrViI0wtqIg1BDPttSxIHlW1VCFFKKaNLwP9KUR+HDEXnhMuH3OjIfy9JUN9Gi0WnhIrGXOjJgIKAR0BJw8OAef+Fw8Q/sL++hX/AP72ERD+VAGlDQ0BHuwVzeELCfzrCAfPpre+CAgDGQcI8L4AAAEAQP6/BEcEOgALAAABMwMhEzMDMwMjEyEBGLa6AcO6trt7cKJA/QsEOvxbA6X8W/4qAUEAAAAAAQB/AAAEBgQ7ABMAACEjEw4BIyImNxMzAwYWMzI2NxMzAy62TjlwQa+uKj+1Px5ObDp0PWu2AYgQD8zMATr+xpFwEBACGgAAAQBAAAAGAgQ6AAsAAAEDIRMzAyETMwMhEwHOugFkura6AWS6ttj7FtgEOvxbA6X8WwOl+8YEOgABADX+vwX3BDoADwAAAQMhEzMDIRMzAzMDIxMhEwHDugFkura6AWS6truRcKFA+znYBDr8WwOl/FsDpfxb/ioBQQQ6AAIAhgAABIEEOgAMABUAABMhAzMyFgcOASMhEyEBAzMyNjc2JiOjAd1L+6qnHiPmuP5Quv7aAZFR+l97ERJEZwQ6/orDm6q8A6X+iv5mdVVbdQAAAAMAQAAABasEOgAKAA4AFwAAATMyFgcOASMhEzMBIxMzAQMzMjY3NiYjAYP7qqceI+a4/lDYtgMFt9i3+7pR+l97ERJEZwLEw5uqvAQ6+8YEOv31/mZ1VVt1AAAAAgBAAAADzwQ6AAoAEwAAATMyFgcOASMhEzMLATMyNjc2JiMBg/uqpx4j5rj+UNi2aVH6X3sREkRnAsTDm6q8BDr99f5mdVVbdQAAAAEAM//rA+kETgAdAAABIgYHIzYkMzISDwEGACMiJjczBhYzMjY3ITchNiYCUlOhEq0fARGhwbgtCDL+4NKjuiKtF2Bjb68o/pIeAW0SWQO4eluezf7G4ir4/tvfqHCCypKVlLMAAAAAAgBA/+wF9QROABMAIQAAATM2JDMyEg8BBgAjIgI3IwMjEzMBBhYzMjY/ATYmIyIGBwFz5TUBEMbNxSYEKf7m1sDHFOpet9i3AS0eY4mBrhwEHWOIga8bAm7h//7M8hj//tsBDt7+KAQ6/da32OGuGLXb5KwAAAAAAv/VAAAEDgQ6AA0AFgAAAQMjEyMBIwEuATc+ATMBBhYzIRMjIgYEDti2VPf+vMQBXFhMFh/pu/7zEEVeAQZJ8mCCBDr7xgGm/loBxSibaJ2t/rRRYgFrbgAAAAABADX+SwQZBhgALAAAASEHFz4BMzIWDwEzAw4BIyImJzceATMyNj8BEzc2JiMiBgcDIxMjNzM3MwchAt7+/zMDQKRem48rLQJtJbqUHTMXLAs9EDZXExJbLR5Pb0mPOZ628pwenCi2KAEBBLr/AkhN0Nnf/eG1pwgJkgUJal1ZAcbhlndUSPzoBLqVyckAAAABAFH/7AQFBE4AHQAAJTI2NzMGBCMiAj8BNgAzMhYHIzYmIyIGByEHIQYWAftaoA+sGf7ypte7JQcnARHhrsEarBBqZ4GfIQFxHv6VEV6BeFyazwEy6ir1ASfeqmyGvpOVm7YAAv/VAAAGIQQ6ABYAHwAAAQMzMhYHDgEjIRMhAwoBKwE/ATI2NxMBAzMyNjc2JiMEJVP7qqodIOW4/k+6/tc+RtTHMyEnX4UyXAIlSvpefBAPR2cEOv5juZKgsgOj/sf+qf7tmAHb9gHQ/c7+i3NOUWMAAAACAEAAAAZCBDoAEgAbAAABIRMzAzMyFgcOASMhEyEDIxMzAQMzMjY3NiYjAXwBwlK2U/uqqh0g5Ln+UGj+Pmi22LYCB0r6XnwQD0dnAqABmv5iuJKgsgIM/fQEOv3O/otzTlFjAAAAAAEANQAABBkGGAAcAAABIQMXPgEzMhYHAyMTNiYjIgYHAyMTIzczNzMHIQL1/uk0A0CkXpuPK4e1iB5Pb0mPOZ6284Yehie2JwEXBL/+/AJITdDZ/VsCp5Z3VEj86AS/lcTEAAABAED+nARHBDoACwAAAQMhEzMDIQMjEyETAc66AcO6ttj+xke2R/7B2AQ6/FsDpfvG/pwBZAQ6AAEAaP/rBskFsAAgAAABAw4BIyImJw4BIyImNxMzAwYWMzI2NxMzAwYWMzI2NxMGydQt9LVgih5Bs3GhqSnUttQdTFphmhvUu9QdVmNYkBvUBbD72dzCVlhcUtPLBCf72Y18h4IEJ/vZjXyHggQnAAABAEX/6wXIBDoAIAAAAQMOASMiJicOASMiJjcTMwMGFjMyNjcTMwMGFjMyNjcTBciRKN6kUngdOptikpgmkbWRGTxKUIIXkbaRGUZSSHgXkQQ6/SnIsEdITEO/uQLX/Sl5anNwAtf9KXlqc3AC1wAAAgA+AAAD1AYYABIAGwAAASEDMzIWBw4BIyETIzczEzMDIQEDMzI2NzYmIwL3/tZD+aumISTouf5Q2LAesEK3QgEq/ldZ+V99ExNCZwQ6/q7MpLLGBDqVAUn+t/2E/kJ/XWKAAAEAY//sBp8FxgAnAAABMzcSADMyEgcjNiYjIgIPASEHIQcGEjMyNjczBgQjIgATNyMDIwEzAb6tBzsBNezZ+Be3C4qZkNooBwIBHv3/DiyYoouhN7dD/vPf3/77Ng6tiLUBI7UDQCIBKAE8/vLgo7X+/8sklknY/viYp+D0AWoBC0n9VgWwAAABADz/7AWRBE4AIwAAATM2ADMyFgcjNiYjIgYHIQchBhYzMjY3MwYEIyICNyMDIxMzAW6lMAEL1K7BGqwQameBnyEBlx7+bxFeiVqgD6wZ/vKmyb4Tq1232LcCZ98BCN6qbIa+k5Wbtnhcms8BD9f+LgQ6AAL/2AAABDsFsAALAA8AAAEjAyMTIwMjATMTIwEhAyMDTpdYtFiL57kDDJu8uf5IAXJCAwG6/kYBuv5GBbD6UAJYAjwAAv+8AAADjgQ6AAsAEQAAASMDIxMjAyMBMxMjASEDJyMHAqBkO7U7aam5AnKcxLr+nwETNgQDIgEr/tUBK/7VBDr7xgHBAT1KSgAAAAIAdAAABicFsAATABcAAAEhATMTIwMjAyMTIwMjEyEDIwEzASEDIwGhAWUBypu8uTSXWLRYi+e57f7QWLUBI7UBawFxQgMCWQNX+lABuv5GAbr+RgG6/kYFsPyoAjwAAAIAXQAABS4EOgATABkAAAEzATMTIwMjAyMTIwMjEyMDIxMzASEDJyMHAW3zAW6cxLo0ZDu1O2mpua26O7fYtwEnARM2BAMiAcECefvGASv+1QEr/tUBK/7VBDr9hwE9SkoAAAACADoAAAY8BbAAIQAlAAABMzchATMyFgcDIxM2JisBBwMjEycjIgYHAyMTNiQ7AQMzEzMBIQKtAwMDif4QGdXGL0q1SiNjlW8efLV/CnuJoCBKtkoyAQHqJu7Q3wQBcf3gBaMN/XvO6f6MAXSxcCj9kwJ7Gn6j/owBdPy7AoX9ewHvAAACADoAAAUOBDoAGwAeAAABHgEPASM3NiYrAQcDIxMnIyIGDwEjNz4BNwMhARMhA6KwnyshtiEjUoEuDle1WQM4d44gIbYhMOXJrAOB/eHo/rECWgrP3KWlsXAS/kwBvgh+o6Wl9LwGAd/+JwFDAAAAAgBiAAAISgWwACkALQAAIRM+ATchAyMBMwMhOwEDMxczNyEBMzIWBwMjEzYmKwEHAyMTJyMiBgcDATMBIQJIShM9Lf6MhLUBI7WBAuEVJu7QBAMDA4n+EBnVxi9KtUojY5VvHny1fwp7iaAgSgKYBAFx/eABdGGNNP1qBbD9ewKFDQ39e87p/owBdLFwKP2TAnsafqP+jAMrAe8AAgA+AAAG4gQ6ACIAJQAAITc+ATchAyMTMwMhAyEBHgEPASM3NiYrAQcDIxMnIw4BDwEBEyECDiETOyr+qFq32LdgAp+rA4H+lLCfKyG2ISNSgS4OV7VZA0NzhyAhAf/o/rGlYYw0/joEOv4iAd7+IArP3KWlsXAS/kwBvggDf5+lAmEBQwAAAAL/x/5HBEcHcAAtADYAAAEyFgcOAQceAQcGBCsBIgYHBhYXBy4BNz4BOwEyNjc2JisBPwEzMjY3NiYjITcBNzMHBSMnNzMCZbzXJBeXd25gGSv+6M0vRE8KEEM7YV9vFRy2nSdzsRgdepqFBxaFiaoXF2iG/uYeAbmmnQT+4G26BJkFsNS1caEqLKx92NE8NUxOIHsvn3CKc5d5kn0jcoJzcX+VASqWEvPxFAAC/8b+RwO+BhsALQA2AAABMhYHDgEHHgEHDgErASIGBwYWFwcuATc+ATsBMjY3NiYrAT8BMzI2NzYmIyE3ATczBwUjJzczAhiqyxwRdV9aURAh+rstRFAKEEM8YV9vFRy1nSZijxAScIeFBxeFdo0QDmBw/uceAXymnQT+4G26BJkEOqaOUXUiI3dUo6A8NUxNIXsvn3CKc15MW0wjclZMSFKWAUuWEvPxFAAAAwBd/+sFNwXFAA0AFgAfAAABAgAjIgIbARIAMzISAwUhNzYmIyICBwUhBwYWMzIANwTQOv6S/eDuNTM5AWT06Pk0/GsC1A0qk6+Y/ScCqf0sCSyJpqEBBykCV/7j/rEBZgEGAQEBHAFR/pn++j5A1vn+9cTWLdj5AQrHAAMARv/sBBwETgANABQAGwAAEzYAMzISDwEGACMiAjcBMjY3IQYWEyIGByE2JnEpARrWzcUmBCn+5tbNxicBhHWmJf3rEGf/dKQlAhMLZwIo/gEo/szyGP/+2wEx8/5xvpmgtwM3uJOZsgAAAAEA6AAABVwFxAARAAABFzM3AT4BMxcHIyIGBwEjAzMCFQcDOQGRTpBmLyIMLUcq/aqbt8QBcXt7AzSegQGjP1T7cwWwAAAAAAEAswAABEsETQAVAAABFzM3Ez4BMzIWFwcuASMiBgcBIwMzAa4CAyT5QY5NHS8TMQUSDB1CFf5Eioq5ATpVVQIjfnIKDpIDBTIr/LIEOgAABABP/3MFJwY1AAMABwAVACMAAAEjEzMBIxMzAQIAIyIAGwESADMyAAMnNiYjIgYHAwYWMzI2NwOFtU21/qa1TrUB+Tz+sv3l/vw2MzsBRPTsARA1tCuqs5ffKTMtoKqh6CoEtQGA+T4BiQFS/tr+wwFrAQoBAQEmAT7+k/73Atr++M7+/dz+99EAAAAEAEb/iAQcBLYAAwAHABUAIwAAASMTMwEjEzMBNgAzMhIPAQYAIyICNzMGFjMyNj8BNiYjIgYHAtC1SbX+97VJtf4YKQEa1s3FJgQp/ubWzcYnth5jiYGuHAQdY4iBrxsDSAFu+tIBbgEy/gEo/szyGP/+2wEx87fY4a4YtdvkrAAAAAADAGz/6waVB1QALAA+AEQAAAEyFgcDDgEjIiYnDgEjIiY3Ez4BMwciBgcDBhYzMjY3EzMDBhYzMjY3EzYmIxMHIyIkIyIGDwEjNz4BMzIWMwEnPwEzBwVRn6UrczHurmSRIUGxcKGlLHMv77AeUosdcyBIWmGaG1e2Vx1ea1GLHnMfSFm4GStw/v0rLUQKBHsIFoNuPfpt/g89TRytGQWv59v9wO7UVVZbUObcAkDt1ZWak/3AoI2HggG0/kyNfJmUAkCfjgG7fX85NhIkdWV//lJAdIx8AAADAEj/6wWfBfEALAA+AEQAAAEyFgcDDgEjIiYnDgEjIiY3Ez4BMwciBgcDBhYzMjY/ATMHBhYzMjY3EzYmIxMHIyIkIyIGDwEjNz4BMzIWMwUHJz8BMwR6kJUoOizXnld/IDqcYpKUKTor158dRHIZOhw4SlCCFy+1LxhPWUJxGjobN0j7GStx/v4qLUQKBHwHF4NvPPpu/s7APk4brgRE08n+39vBSElNRNLKASHZw5WHgP7fjXpzcOvreWqFggEhjHsBwn1/ODYSI3VmgOrEQHSMAAIAaP/rBskHAwAHACgAAAE3IQchByM3BQMOASMiJjcTIwMOASMiJjcTIwMGFjMyNjceATMyNjcTArcVAvsV/s0ZpRkCOtQbkFhjVh3Uu9QbmmFaTB3UttQpqaFxs0EeimC19C3UBplqan196fvZgod8jQQn+9mCh3yNBCf72cvTUlxYVsLcBCcAAAAAAgBF/+sFyAWxAAcAKAAAATchByEHIzcBAw4BIyImNxMjAw4BIyImNxMjAwYWMzI2Nx4BMzI2NxMCIRUC+hL+yhmkGQHPkRd4SFJGGZG2kReCUEo8GZG1kSaYkmKbOh14UqTeKJEFR2pqgID+8/0pcHNqeQLX/Slwc2p5Atf9Kbm/Q0xIR7DIAtcAAAABAGT+gwUNBcUAGAAAASMTJgI3ExIAMzISByM2JiMiAgcDBhY7AQJDtUm8tzIzOwFZ79vmLLYigJ+S9Sg0LICgav6DAW4fAVL1AQEBJQFI/vneqab+88j+/dv8AAEASv6DA/sETgAYAAABIxMmAj8BNgAzMhYHIzYmIyIGDwEGFjsBAdu2SpyJKQgxASHUobkhqxZiYHq5HwgjUodi/oMBciIBKMkq9gEm4advg+qcKq7aAAABAFUAAATCBT4AEwAAARcHJwMjASc3FwEnNxcTMwEXBycCOuta7emgASHrWe8BBetc7e6e/trtXekBvax5qv6+AY6reasBb6t7qwFN/mereKoAAAAB/T0EpwAcBfsABwAAAQcnNyE3Fwf9+BmiMAH5FKIrBSV+AedsAdUAAf1kBRcAQwYVABEAAAEyJDMyFg8BIzc2JiMiBCsBN/2mbQErPG9aFgd8AwstLSv+zHArGQWVgGZ1IxI2OH99AAH+bwUY/zcGWAAFAAABNzMHFwf+bxmsHB9XBdx8jHRAAAAAAAH+kAUY/6cGWAAFAAABJz8BMwf+zT1NG68ZBRhAdIx8AAAAAAj6t/7EAdoFrwANABsAKQA3AEUAUwBhAG8AAAE+ATMyFgcjNiYjIgYHAT4BMzIWByM2JiMiBgcDPgEzMhYHIzYmIyIGBwE+ATMyFgcjNiYjIgYHAT4BMzIWByM2JiMiBgcBPgEzMhYHIzYmIyIGBwE+ATMyFgcjNiYjIgYHAz4BMzIWByM2JiMiBgf+DBN5XVZZEWgKIDErOwkBhRJ6XFZaEGkJITErOgghEnpdVlkQaQkfMSw7CP56EnlcVlkQaAkgMSs6Cf1HE3ldVloRaAkgMSs7Cf6DE3pdVlkRaAohMSs5Cv6NE3pcV1kRaQofMis7CTYSe1xWWxFpCiAyKzoJBPNaYmlTLzY6K/7rWmJpUy82Oiv+CVpiaVMvNjor/flaYmlTLzY7Kv7kW2FoVDA1OisFGlpiaVMvNjor/glaYmlTLzY6K/35WmJpUy82OyoAAAAI+tb+YwGOBcYABAAJAA4AEwAZAB4AIwAoAAAFFwMjGwEnEzMDATcFByUFByU3BQE3JRcGBQEHBSclEycDNxMBFxMHA/4YB7VaibcJtlmIAZQPAR0U/sz7vA/+4xQBMwOxBgFHMyj+7/x5Bf63MgE6bBBISn0CghBKTHs8Dv6tAWEEog4BUv6g/hEMfGJHOwx8YkcBrhCZRBex/I4RmUXIAuQCAUZF/tX84wL+u0cBKwAAAAACAD4AAAPUBnAAEgAbAAABIQMzMhYHDgEjIQEjNzM3MwchAQMzMjY3NiYjAyT+1nD5q6YhJOi5/lABBbAesCe3JwEq/ipZ+V99ExNCZwUa/c7MpLLGBRqWwMD8o/5Cf11igAAAAwBXAAAFFwWwAAMADgAXAAABBwE3AQMjASEyFgcGBCMlITI2NzYmIyEEr3/+9n/93HW1ASMCBM7LJyv+7OH+zwFPg7EZGmaP/rECPmQBk2X+eP22BbDww9bdlaN5hZoAA//i/mAEJgROAAMAFgAkAAAlBwM3JQ4BIyImJwMjATMHFz4BMzISAyM2JiMiBgcDHgEzMjY3A5OA7n8BSjPovluLLWq2ASucCAM7lFqypzS2KGKJSXYwahtrVnyfIQ1lAXVlX//3REP97gXabgFAQ/6s/vzJ9VJI/fFDSLylAAABAEgAAATwBwEACQAAASMVIQEjASETMwSOAv13/vu2ASMCjES1BRsB+uYFsAFRAAABADUAAAPRBXgACQAAASMVIQMjEyETMwNzBf43urbYAc5AtgOkAfxdBDoBPgAAAAABAFf+3gS5BbAAFQAAASEDMzISAwIAIzcyNjc2JisBAyMBIQSb/Xdfqvv0Njj+8N8bhasmKY2/qoa2ASMDPwUa/ib+0P7v/uf++JHSvtLQ/V8FsAABADX+5QOMBDoAFQAAASEDMzIWBwYCByc+ATc2JisBAyMTIQNu/jc5aMnfLB7ovBOChxcdfYdoYbbYAn8Do/7i/t2M/uskkCKedZmj/hoEOgAAAAABAEgAAAVQBbAAFAAACQIjAyMHIzcjAyMBMwMzEzMDMwEFUP4CAQLiu0gxkTFchLYBI7aBXDSRNEYBqgWw/U/9AQKV9/f9awWw/XoBAv7+AoYAAAABAD4AAASfBDoAFAAACQETIwMjByM3IwMjEzMDMzczBzMBBJ/+XevloCknkCdZXLbYtlxZK5ArJAFHBDr9//3HAc/ExP4xBDr+NdbWAcsAAAEA8wAABoYFsAAOAAABIwMjASE3IQMzATMJASMDU4mEtwEF/l8eAlh/kwIj5v1rAYTPApX9awUblf2EAnz9KP0oAAAAAQClAAAFjAQ6AA4AAAEjAyMTITchAzMBMwkBIwL1eFy2uv6AHgI2XGwBqdr+CQE/5gHP/jEDpJb+NQHL/fr9zAAAAAABAFcAAAfIBbAADQAAASETIQchASMTIQMjATMBqwKUhAMFHv2w/vu1gf1sgbUBI7UDGwKVlfrlAob9egWwAAAAAQA1AAAFjgQ6AA0AAAEhEyEHIQMjEyEDIxMzAWUBwl4CCR7+rbq2XP4+XLbYtgJkAdaW/FwB0P4wBDoAAQBX/t8HWgWwABcAAAEzMhIDAgAjNzI2NzYmKwEDIwEhASMBIQT9bvv0Njj+8N8bhasmKY2/boa1AQX9av77tQEjBAADQf7Q/u/+5/74kdK+0tD9XgUa+uYFsAABADX+5QY8BDoAFwAAATMyFgcGAgcnPgE3NiYrAQMjEyEDIxMhA+Sd0uksHui9EoKGFx2GkJxhtrr+Pbq22AMvAoX+3Yz+6ySQIp51maP+GgOj/F0EOgAAAgBl/+IFxAXFACkANwAABSImJw4BIyICEzcSADMHIgIPAQISMzI2NyYCPwE2ADMyEg8BBgIHHgEzAQYWFz4BPwE2JiMiBgcE4GCoSkudVfL6PCI6ASfDHmq+KCM0lrgiRCJkSyIuMgEJsKOdMDIimXIsYjz+ISE4WWyUHTMlP2FXnyAeJSYiIAGOASyqASUBUZz+9Mys/v/+4gkLZQERqOb/AST+zvH6q/74XQ0KAjmk5khL5o/9vMrgpgACAE7/6wR8BE8AKQA4AAAFIiYnDgEjIgITNzYSMwciBg8BBhYzMjY3LgE/AT4BMzIWDwEOAQceATMDNzYmIyIGDwEGFhc+ATcD+1mTPj16P9S5OAsp9IsfRm4eDCdseRQnFEcuHBUl2IGMbSoVF2dLJFIvkRUZHjQ6VhoVFSo8NUkUDBwdISEBOgETO80BDpummD289gQFTdaKZ73v7tNpcL9NDg0Bl2x+pYqFa2ejOzeXYgABAOj+oQZkBbAADwAAASE3IQchAyEBMwEzAyMTIQJG/qIeA3ce/pznApYBBbX++413oUb8JwUblZX7egUb+un+CAFfAAEAiP6/BM8EOwAPAAABIzchByMDIRMzAzMDIxMhAYL6HgKTHuOcAcO6trt7cKJA/QsDppWV/O8Dpfxb/ioBQQACANEAAAVIBbAAAwAXAAABIxMzCQEjEw4BIyImNxMzAwYWMzI2NxMC1ZGMkQHn/t21emKnctfHMFu3WyVjl1u9Y4sBQAK8AbT6UAJhHRrS7gHG/jq3cxwcArgAAAIAlwAABB4EOwADABcAACUjEzMTIxMOASMiJjcTMwMGFjMyNjcTMwI3kXGRnrZOOXBBr64qP7U/Hk5sOnQ9a7bmAjX85QGIEA/MzAE6/saRcBAQAhoAAAABANAAAAVGBbAAEwAAMwEzAz4BMzIWBwMjEzYmIyIGBwPQASO1el+odNbHL1u3WyRjll27Y4sFsP2eHBzT7f46Aca2dB0b/UgAAAAAAgCu/+kF7gXDAB4AJwAABSACEzcuATczBhYXNxIAMzISAwchBwYWMzI2NxcOAQEhNzYmIyICBwNa/v74OBaJdyCRFTJMAjsBXd3qxT0V/McULonOX6VGEza9/psChAYtY7CO6igXAVgBGWwXwZtldhIHASYBSv6e/sttZeX3MSaGJkADWSHh6f7wygACACX/7ARRBE4AHAAkAAAFIgI/AS4BNzMGFhc2JDMyEg8BIQYWMzI2NxcOAQMiBgchNzYmAknOzicCYk8akA4SIz0BEJzHqyMT/WwYa4dalzwzQLkBWqApAdoEE1kUASrxECGpgUdcGcXj/vvdea3FOTJ7OksDzKqGGn2ZAAAAAAEASP7ZBVAFsAAWAAAzIwEzAzMBMwEWEgcCACM3MjY3NiYrAf62ASO2fncCY9P9ktrKMjn+8d8bhawmKI3A9wWw/YsCdf2HGP7X/P7n/viR0r7R0AAAAAABAD7+/QRfBDoAFgAAAR4BBwYCByc+ATc2JisBAyMTMwMzATMCgKOiJR3luxKAhBcciJOdXLbYtlxQAcXaAmIf3LmH/vkjkCGSbpaL/jEEOv41AcsAAAAAAQBX/ksFegWwABcAAAEDIRMzAQ4BIyImJzceATMyNjcTIQMjAQIwhAKThLf+yyW7lBwwGisMPBE2VhOT/W2BtgEjBbD9awKV+fe1pwkJkQUIaV0C3/16BbAAAAABADX+SwQ7BDoAFwAAAQMhEzMDDgEjIiYnNx4BMzI2NxMhAyMTAcNeAcJetuolupUcMBorDDwRNlcTb/4+XbbYBDr+KgHW+221pwkJkQUIaV0CKf4wBDoAAgBG/+sFQAXFABYAHgAAASAAAwcCACMgAhM3ITc2AiMiBgcnPgEDMhI3IQcGFgMmARMBBzshQP6L7f7z7z4WA6oMMZngZK5KEjfGN5n/Mf0NBy2FBcX+j/7Vo/7D/qIBYAE2bzn4AQ4yJYYlQvq7ARfWI+LoAAAAAQA2/+sEhQWwABsAAAkBITchBwEeAQcGBCMiJjczBhYzMjY3NiYrATcB0wG//a0eAygW/hzDvSgs/uDVrOArtxpsdnu5GCF1nIcdA1MBx5Z1/hEO4sfZ0dbTf5WXeqqDkAAAAAH/7f51BDoEOgAcAAAJASE3IQcBHgEHBgQjIiY3MwYWMzI2NzYmKwE/AQGGAa39wR4DKBb+Kb21Jyv+39Ws3im3Gmx2e7kYInadiAcWAdwBx5d1/g8R4cTX0tfRfZWXeKqDI20AAAD//wAK/ksE/QWwACYArEQAACYB08BAAAcBmgDtAAAAAP////v+SwPkBDoAJgDnTwAAJgHTnY4ABwGaAN4AAAAAAAIANgAABPMFsAAKABMAAAETMwEhIiY3NiQzGwEhIgYHBhYzA8p0tf7d/f3PyCcrARHjvXP+soSwFxxljwNsAkT6UPXF1d39KQJCpHeHoAAAAgA2AAAGCwWwABgAIQAAISImNzYkMyETMwE3PgE3PgEnMx4BBwYEIycTISIGBwYWMwHNz8gnKwER4wFOdLX++lBlhh0RBAywCgMRLv75puZz/rKEsBccZY/1xdXdAkT65AEBjIJOpVJpkkrP1ZUCQqR3h6AAAAAAAgBA/+kGMAYYACIAMwAAExIAMzIWFxMzAwYWMz4BNz4BJzcWBgcCACMGJicOASMiAjcBLgEjIgYPAQYWMzI2Nz4BN3M4AQTCUnUmdrbzFjxKgbEpFQsIrwcFFDn+zMFxgxVEpGmvoC8C0RhcS322JQQkU4hMfTQCAwMCCgEbASlDQQJO+0FkdQHRv2TGaAF6u17+8f7pAlReWVcBIOoBPj1E77sVtLxMRhUcEQAAAAABAOj/6AWbBbAALQAAATc2JisBNzMyNjc2JiMhNyEyFgcOAQceAQ8BBhYzPgE3PgEnMxYGBwIAIwYmNwJ7DRpgcLIef5OsGxpolP6zHgFN1MwoGox3ZUQZDhE3QG6hKBULCLAGBBM6/t+xmIEcATJBgoiWgIWEfpbSyH6gLymufUVQYAHVu2THaIawXf7z/ucDmq4AAQCI/+MEpQQ6AC4AACUGFjM+ATc+ASczHgEHBgQjBiY/ATYmKwE3MzI2NzYmKwE3MzIWBw4BBxUeAQ8BApIKGi1miiAPBAywCwQQMf71p4NnFA8PT1/EG6tqgBARVHPzF/m2uR4SbGBTPREP1i0vApmOTqFQbItI2+IDb4RMT0qUVk5YW5Sql1ltIgMceVZOAAAAAAIAz/7EA7sFsAAhACsAABM3MzI2NzYmKwE3MzIWBw4BBx4BDwEGFhcHIyY2PwE2JiMBDgEHJz4BPwEzzx6WlasbG2aU/x7/08soGot4ZUYZGw8IHAW6HwUPGxlgcQGuFn9eVzxGER+2AnqWgoKIf5XUyX2fLymvfYhJZSQZJHxNhIKH/cRrx0hISpBVlwAAAAIAvP61A20EOgAiACwAABM3MzI2NzYmIyE3ITIWBw4BBxUeAQ8BBhYXByMmNj8BNiYjAQ4BByc+AT8BM7wew2t/EBJTdP77HAEGtrgeEm5iVD0SFAoKHAS7HgILExFOYAGcFn9eVzxGER+2AbqUVk9aWZSomFtuIgMeg15hMVIWExdjM19YVv51a8dISEqQVZcAAAAB//H/6AcfBbAAIQAAASEDAgArATczMhIbASEDBhYzPgE3PgEnNxYGBwIAIwYmNwSQ/kdrV/7+8TEeJoS8QokDJN4VPEqAsSkVCwivBwUUOf7MwKKFHgUa/eb+Uv6ulQEiAUkCsPupZXQB0b9kxmgBerte/vH+6QOtxAAAAf/s/+gF8wQ6ACEAAAEDBhYzPgE3PgEnMxYGBwYAIwYmNxMhAwoBKwE/ATI2NxMEMpMVO0llkSUUCQmvBwITNf7vqKCGH3X+4D5F1MY1IyhfhDFcBDr9H2R1AbmpXrxjeK1Y+P8AA63EAkr+y/6o/uqiAdf0AcwAAQBO/+gHJgWwAB0AAAEDBhYzPgE3PgEnNxYGBwIAIwYmNxMhAyMBMwMhEwVq3hU7SoGxKhQLB68HBBQ6/svBoIYfPP1ygbYBI7aEAo6EBbD7qWR1AdG/Y8ZpAXy5Xv7x/ukDrcQBLf16BbD9awKVAAEANf/oBgUEOgAdAAABIQMjEzMDIRMzAwYWMz4BNz4BJzMWBgcGACMGJjcDEv40XLXYtV4BzF62kxU7SWaRJRMJCK4HARM1/u+poIYfAc/+MQQ6/ikB1/0fZHUBualdvGR7qlj4/wADrcQAAAEAYP/rBJsFxQAhAAAFIgIbARIAMzIWFwcuASMiAAcDBhYzPgE3PgEnMxYGBwYEAjXk8TU1OgFj+WOhN1M4flCc/wAnNSyLqoGnHxILBLABAxEw/tYVAV4BDAEGASIBSC0qgyIi/vPF/vjZ/AGajlWxY518UNziAAEARv/rA5oETgAhAAAlPgE3PgE3Mw4BBw4BIyICPwE2ADMyFhcHLgEjIgYPAQYWAfJbWRQMDQOvAQoLJNqdy8MuCDEBINNTgiVGJ2pBebkfCCNcgAFVVz1zPEVxNqKgATviKvQBKCMfjRse7JoqrNwAAAAAAQDX/+gFJAWwABkAAAEhNyEHIQMGFjM+ATc+ASc3FgYHAgAjBiY3Ao7+SR4ELx7+PsAWPEqBsCsUCwivBwQVOf7MwaCGHgUalpb8P2R1AdG/Y8ZpAX24Xv7x/ukDrcQAAQCs/+gEfAQ6ABkAAAEhNyEHIQMGFjM+ATc+ASczHgEHBgQjBiY3AfT+uB0DTB3+snUWO0xliiAQBgyuCwQRMP71qKGGHgOmlJT9s2tuAZuPUKZQaJRK3eMDrcQAAAAAAQBq/+sFQwXFAC0AAAEHIyIGBwYWMzI2NzMGBCMiJDc+ATcuATc2JDMyFgcjNiYjIgYHBhY7AQczDwEDgAaqoswbG5qsi+EYtS7+tN3l/vsoG6WMZ2EVKgEx+cf9JLYXlYqdzRcZfaqqBwEKBwK7IIOHhI2fdeTF4siLqCcxo2TYxt21dYeTcX58Ii8lAAD//wDpAowFAAMhAEYBhtwAUzNAAP//AQACjAYJAyEARgGGtQBmZkAA////aP5uAxEAAAAnAEH/0v8DAAYAQQQAAAEA1gQCAkUGKwAJAAATPgE3Fw4BDwEj+RV/X1k9SBEktQSxa8dIR0qQVrIAAQCxA+cCIAYYAAkAAAEOAQcnPgE/ATMB+xV+X1g7RxIltgVhbMdHSEiRVroAAAAAAf+k/tYBEAD6AAkAADcOAQcnPgE/ATPuFn9eVztGEiO2T2vHR0dIkVauAP///2ED5wDQBhgARwFmAYEAAMABQAAAAP//ANYEAgNyBisAJgFlAAAABwFlAS0AAP//AL0D5wNSBhgAJgFmDAAABwFmATIAAAAC/6T+1gItAPoACQATAAA3DgEHJz4BPwEzFw4BByc+AT8BM+4Wf15XO0YSI7b7Fn9fVztHEiO2T2vHR0dIkVauq2vHR0dJkVWuAAAAAQCVAAAERgWwAAsAAAEhAyMTITchEzMDIQQu/oyVtpX+kRgBbzy2PAF0A6P8XQOjlwF2/ooAAAABABD+YARVBbAAEwAAKQEDIxMhNyETITchEzMDIQchAyEDqP6LQrZC/pMYAW1+/pIYAW48tjwBdBj+jH4Bdf5gAaCVAw6XAXb+ipf88gAAAAEArwIYAl8D3gANAAATPgEzMhYPAQ4BIyImN80Se1tUVhEMFHhcU1gSAxheaG9XPV9kbFcAAAD//wBHAAACvgDFACYAEAEAAAcAEAGbAAD//wBHAAAERADFACYAEAEAACcAEAGbAAAABwAQAyEAAAAGAK7/6wbhBcUAGQAnADUAQwBRAFUAAAE+ATMyFhc+ATMyFg8BDgEjIiYnDgEjIiY3AT4BMzIWDwEOASMiJjcBBhYzMjY/ATYmIyIGBwUGFjMyNj8BNiYjIgYHAQYWMzI2PwE2JiMiBgcTJwEXAvEbtYNBXhoteEp5fBkPHLODQl8ZLnhIen0a/fUbtIR5fBkPHLODen0aAqERNklCYhAPEDVIQmQPAZkRNklBYxAPEDVIQmQP/C8RNklCYhAPEDVIQmQPElgDelgBZYmjPzc5Pa5+TouhPTg5PK1/A4GKo65/TYqhrX78zFJjaUxOUWRqS05SY2lMTlFkaksC5lFjaUtNUmRrS/vXQQRyQQAAAAEAgACaAm0DtAAHAAABEyMDPwEBMwEvn4jGAwEBYYgCJ/5zAYQNBgGDAAAAAQAhAJkCDQO0AAgAAAETBzMHASMBAwFJxAIBA/6hiQE8nQO0/nwGDf58AY0BjgAAAQAJAG8D2wUiAAMAADcnARdhWAN6WG9BBHJBAAIAiwIwA3UFxQAKAA8AAAEzByMHIzchNwEzATMTJwcC6osZiyWfJf5ZDwImo/3t+04DFANmfbm5XgJ+/aEBhgIeAAAAAQCjAosDewW6ABQAAAEfAT4BMzIWBwMjEzYmIyIGBwMjEwHABAMsckVtZB9mpmAWLkAwUR5wpqAFq28BPkGWnf4EAd1xUzs1/c8DIAAAAAABAC0AAAR/BcUAJwAAAQ4BByEHITczPgE3IzczNyM3Mzc+ATMyFgcjNiYjIgYPASEHIQchBwGeFTkmAqwf/HYeCS5PGJ8emhiUHo4ZLPW1sa0jtxpbYViOGxkBiB7+fRkBfx4Bvl2VN5WVDbJqlpGWld3Y07CEaZeIlZaRlgAAAAMASf/sBiEFsAAKABMAKwAAAQMjASEyFgcGBCMnMzI2NzYmKwElAzMHIwMGFjMyNjcHDgEjIiY3EyM3MxMBb3G1ASMBSc3KJyv+6eB2lIKzGRtljpQDlDW/HL+EEiQrFDMTAhxdLGNjIISNHI01Ajb9ygWw+MXX5pareoakJv75jf1qVjkIBYMRFY+cApaNAQcAAAABAGD/6wRiBcUAKQAAASEGFjMyNjcHDgEjIgI3IzczNyM3MzcSADMyFhcHLgEjIgYPASEHIQchA2n+NSd2jjNtNAw6cjrN2TKJGIkhiBiIBDUBNN81bDsxMGM2g84jBAHLGP41IgHLAgK/wxERmA8QASL1eKl6EQEJAQ4QD5oQE9CvE3qpAAAABADj/+sFMAXFABsAKQA3ADsAAAEOASMiJj8BPgEzMhYHIzYmIyIGDwEGFjMyNjcTBhYzMjY/ATYmIyIGBzM+ATMyFg8BDgEjIiY3AScBFwL/FrBvfWocDxm3cXpuF4cMMzo/VBAPEDE7PU0MYRp9eoOzHA8ZfHmDtRuHD2RCSDUQDxBiQkk2EQF/WPyGWAQebJKhik1/rot0OU9kUk1Kakw7/Pl/raGLTn6uo4lLamRRTkxpY1IDykH7jkEAAAAAAgBn/+sD6wXFABoAJgAABSImPwEOASM3MjY3Ez4BMzIWDwEGAA8BBhYzEzc2JiMiBgcDPgE3AkjEjS4DMF8yIzReL2AjwXt2ax8IIP8AthQdQminCQ8bIDJCF01lfhgV3+UQDg2uDA0B37HKn50qm/66aWaRmAPXLE9RZnn+gErQeQAABABOAAAIaQXAAAMAEQAfACsAAAEhNyEBPgEzMhYPAQ4BIyImNzMGFjMyNj8BNiYjIgYHASMBIwMjATMBMxMzB3X9+RwCB/46IMuYjI8dFyDLl42QHp8UPFRJbRIXEjxRS2wS/eO2/lID47UBI7UBrgPjtgFrjQJ5oa67lHWirLmVYWRtWHVeZm5W+48EcPuQBbD7kQRvAAACASMDlwTkBbAADgAWAAABEzMDIxMnAyMDIwMjEzMHIwMjEyM3IQOU6mZrVkUC1S9KA0lXa2zEh1tXW4cQAWUEIAGQ/ecBXwH+oAFs/pQCGVH+OAHIUQAAAgB8/+wEjwROABUAHgAAJQ4BIyICNzYAMzISDwEhAx4BMzI2NwMiBgcDIRMuAQOQXrdaweQuMQFjw7fXLgn9NkIrdElUvl20QpRBNwH2OShyXjg6AUno9gE7/srnL/64Njg8PgMqQTn+6wEeNjsA//8A/v/1BgUFsgAnAckAjgKGACcBdAD1AAAABwHQAxAAAAAA//8ArP/1BpAFwAAnAcsAhwKUACcBdAGfAAAABwHQA5sAAAAA//8Aqv/1Br0FrwAnAc0AfwKOACcBdAHTAAAABwHQA8gAAAAA//8BHv/1BiMFrwAnAc8AjwKOACcBdAEhAAAABwHQAy4AAAAAAAIAJv/rBFoF7QAUACEAAAEWEgMHAgAjIgI3NgAzMhYXNzYmJwMyNj8BLgEjIgYHBhYCpOvLRRY1/sTRwdYqMgEV01KNLgMJoJVvd9EjFRGJeXmuHx1vBe1L/j3+qHD+9v7eARjO/QEDQTsB2eM9+zHnsGpRac2dkMEAAAABADn/KgVBBbAABwAABSMTIQMjASEENrXz/W7ztgELA/3WBfD6EAaGAAAAAAH/u/7zBOQFsAAMAAAJASEHITcJATchByEBA1z9UgNEHvvnHALH/locA9Ae/QQBlwJB/UiWjQLOAtSOlv1AAAABAM8CjAP1AyEAAwAAASE3IQPX/PgeAwgCjJUAAQBoAAAFKQWwAAsAAAEVFzcBMwEjAyM3IQH1AyUCU7n834lqrR4BMAFPWAFZBGH6UAJ1lwAAAAADAEn/6weABE4AGQAnADUAAAEGACMiJicGBCMiAj8BNgAzMhYXNiQzMhIHBQYWMzIAPwEmAiMiBgchNiYjIgAPARYSMzI2NwdGMf7nxZGyMWr++J23tC0OMAEYxpGzMWwBB5+0syz51yVRe3gBBy8IBoqEb6shBWYjUHd6/vkwCAWKhG+rIgH68/7k2p+g2QEw30TyAR7cnqDa/s7eRLfDASBoKmwBGtOntcX+4Wcqb/7n0akAAAAAAf87/ksDHQYtABwAAAUOASMiJic3HgEzMjY3Ez4BMzIWFwcuASMiBgcDAQUdtZQbMBkkDTwPOFEQ0R3Amx9AJS4RJxlPaRDRWbGrCQmRBQhpXQUetrILCowFBm5k+uIAAgBQARoEPgP7ABsANwAAEz4BMzYWFx4BMzI2NxcHDgEjIiYnLgEHIgYHJwM+ATM2FhceATMyNjcXBw4BIyImJy4BByIGByfFPIA+QTNWSjU+OYQ4Axg8gDw6Q0FUNUE6hTYDRzyAPUE0Vk4wPjmFNwMXPYA9OkBCWy5COoQ2AwNoRkwBFzMuF0xCAaNHSxwpMhgBTUEB/vpGTAEXMzAWTUIBpEdLHCk2FQFNQgEAAAABAI4ApAQIBN8AEwAAATMHIQMhByEHJzcjNyETITchExcDS70g/vWyAYog/iikR3u/IAENs/5zIAHav0cDzZ7+/57sOrKeAQGeARI7AAAA//8ASAACBDkEjQBnAB4AdACyQAA5mgAHAYb/ef12AAD//wBHAAAEEgSgAGcAIAA4AMRAADmaAAcBhv94/XQAAAACAGcAAAPaBbAABQAPAAABMxMBIwMhAy8BBwETHwE3Am2I5f38ieYCuokGAx7+sIkGAx4FsP0n/SkC1wIDNwE4/f39/jcBOP//AI8AsgIbBOsAJwAQAEkAsgAHABAA+AQmAAAAAgCUAnoCngQ6AAMABwAAASMTMxMjEzMBHYlZic+JWYkCegHA/kABwAAAAAAB/+b/LwEjAOwACQAAJQ4BByc+AT8BMwEOFGpSWDA6EBatgGKvQEg/e0xvAAIAaAAABBcGLQAXABsAADMTIzczNz4BMzIWFwcuASMiBg8BMwcjAyEjEzNovJ4cnhgn5Lc7ekc+LGk8aHsWGMkcybwCIbbYtgOtjXfFtyAdmhYda213jfxTBDoAFv+1/nIIMwWuAA0AHQArADsAQQBHAE0AUwBcAGAAZABoAGwAcAB0AH0AgQCFAIkAjQCRAJUAAAE2JiMiBg8BBhYzMjY3FzI2NzYmLwE+ATc2JisBAycOASMiJj8BPgEzMhYHBQ4BIyImNyMGFjMyNjcTIwETMwczByE3MzczAwETIQcjByU3IQMjNwEyFgcOASsBNwE3IQchNyEHITchBxM3IQchNyEHITchBwEzMhYHDgEHIwUjNzM3IzczAyM3MyUjNzM3IzczAyM3MwMkE2RaZIkVFhRjXWKJFt9abBEJIicBJzEJD1xar25oD1Y4QDQPFg1YOT40DgNYCT8kMSgLVhFVUk9wEUxW+UM/aSi2FwTMF7koZz/6LzkBHxe2IgWkFwEgOWci/GkxJggIPC11IgHgFwECF/2LFwEBF/2MFwEAF4oXAQIX/YsXAQEX/YwXAQAXAY5XOywICDwvYf0KaTNpGWkyaclpMmkGu2czZxlnMmfJZzJnAkRge3JpcGJ5cWrYSFMtRA0DDjorS0v929hFTkhLcERPSUqbLDYpMlJSVlUBevtPATvKcXHK/sUGHwEddKmpdP7jqfy2KysoK6kDSnR0dHR0dPk4cXFxcXFxBFsdKiYpAZb8fvr8Ffl+/H76/BX5AAAABQCH/dUHfAhiAAMAHQAhACUAKQAACQMFPgE3PgE3NiYjIgYHMz4BMzIWBw4BBw4BBxcjBzMDMwcjATMHIwTDArn7wf1KA5ULIixMcBEbe456vBy9C0ApMCwKCzswVUcTqrwivNAEAQQCGgQBBAZS/DH8MQPP8To3GyiAUIyLg4c0M0A0NkgdOVZaW6r9TAQKjQQAAAEAH//vA84EjQAeAAAbASEHIQM+ATc2FgcOASMiJj8BBhYzMjY3NiYjIgYHk8YCdSD+KF4pcDatkiYn4tKgxiG4E1xhaYkXF01iW24gAfkClJ7+wRomAgPGvMHDoaIOXWF+cXZ2PDUAAgAnAAAC1wMhAAoADwAAATMHIwcjNyE3ATMBMxMnBwJhdhl2H50f/nwMAfag/hjjQAMUARh+mppiAiX99wFCARsAAAACAFH/6wRiBcUADQAbAAABAgAjIgIbARIAMzISAyc2JiMiBgcDBhYzMjY3A+Y9/uzQvrY4RTwBFNDAtDeuKVd/c6wmVCpYfnSrJwIs/tH+7gEqARcBVwEuART+1f7pKNGzxMD+W9G1xcEAAAAB/+D+3wKzA0EADwAAETMyEgMCACM3MjY3NiYrAcT79DY4/vDfG4WrJimNv8QDQf7Q/u/+5/74kdK+0tAAAAAAAf8d/ksBJACYAA8AACUHDgEjIiYnNx4BMzI2PwEBJDAluZUbMBksDDsROFMTMJjxtqYJCZoFB2Bc8QAAAf96/mYBPgBAABMAADceAQcOASMiJic3HgEzMjY3NiYnpFhCDxaKYzpZHzYdLB82PwkKLDJANIxNaWQaEncMDzEpNk8zAAAAAf/C/pkA3wCaAAMAABMjEzN4tme2/pkCAQAAAAIBNwTZA6EGzgANACEAAAEOASMiJjczBhYzMjY3Ew4BIyImIyIGByc+ATMyFjMyNjcDdRWog3mFE5MMMUY/UQu+EWpFMGcoHjcHSw9qRSdvKR04CAWuaG12XzhARDQBCVFiTDQlFU5nTDMmAAIBNwTgA2wHAgANAB0AAAEOASMiJjcjBhYzMjY3JTc+ATc2JiM3MhYHDgEPAQLdClA+RjILjhOEeIGkFP68GEg8BwZLPxeIeQ4LVj0OBbAzQT03XXNrZRB8AxcgHx1QSEc3Ngg+AAAAAgE3BN8DgQaJAA0AEQAAAQ4BIyImNzMGFjMyNjcnMwcjA4EUq4Z9iBOUCzRIQFMKK5S/YwWwZWxzXjc+QjPZxgAAAAACAQ8E5APABtIABwAbAAABIycHIyclMzcOASMiJiMiBgcnPgEzMhYzMjY3A8Ckl9eeAQFIf+EOaUAtXSUcPAVFDWpAI2clGzoGBOSfnwPw5URYSDAcE0JeRiwdAAIBCwTkBKkGzgAGABYAAAEjATM3FzMnNz4BNzYmIzcyFgcOAQ8BAvW2/syj3ZGkNxlCNQgGQjcWemsQDVA3DQXp/vu6uomDBRYkIiFcUVA/Pgc8AAIAXwTSA70GgAAHAAsAAAEjJwcjJwEzBSMDMwO9v3y8uQEBQZL+kIeJwgTSn58DAQJYAQEAAAAAAgEXBOQFHgaSAAcACwAAATMTIycHIycBMwMjAlqT2796vLsBA0TD8IkF6f77n58DAav+/wAAAAACAQ0EpwOfBnkADQARAAABDgEjIiY3MwYWMzI2NwcjJzMDnxrCloqWGJIOQFxSZw5ckZzRBbCBiJJ3R01TQQXOAAAAAAEBLwSQAkYGFwAFAAABNzMPASMBTKBaRxu1BSP0/YoAAv/UAAAD6ASNAAcACwAAASEDIwEzEyMBIQMnAwH+J5i8Ap6ry7v+TQFwUQMBEP7wBI37cwGkAfsBAAAAAwA+AAAEGgSNAA8AGAAhAAAzEyEyFgcOAQcVHgEHDgEjCwEzMjY3NiYjJzMyNjc2JisBPukBcrzFHxNtVlpKEyTjv5JM+2GAExNSaeC7b48SEl9/uwSNnp9bfh4DGZJjsJgCC/6IYFpgXolbV19BAAEATf/vBEIEnQAbAAABBgQjIgI/ATYAMzIWByM2JiMiBg8BBhYzMjY3A9w4/vPAuNIuIzABMMi5wxu2DV92bskeIyJteG6aKgGO0M8BH+Ks9AEN0suKf9GbrarEgooAAAIAPgAABEkEjQAJABMAADMTITISDwEGBCMLATMyNj8BNiYjPukBiLrgKiou/svMBq7RcNAcKx18egSN/vPR0uT5A/n8mr2N05eyAAABAD4AAAQdBI0ACwAAASEDIQchEyEHIQMhA0/+EE0CPx39CukC9h79wUMB7wIV/n6TBI2U/rAAAAEAPgAABB8EjQAJAAABIQMjEyEHIQMhA0r+EGW36QL4Hv2/SAHwAfj+CASNlP6UAAEASv/vBF4EnQAfAAAlDgEjIgI/ATYkMzIWDwE2JiMiBg8BBhYzMjY/ASM3IQPNOPKrzeEqMS0BN9rBuhG0CGV2fdMbMSB9jl2QITLxHgGlnUJsAQnV8+X4xqQBbWq7jfScry0c/JUAAQA+AAAEpASNAAsAACEjEyEDIxMzAyETMwO7tmP98GO36bdpAhBptgHu/hIEjf31AgsAAAEAPgAAAd0EjQADAAAzIxMz9LbptgSNAAEAC//vA9EEjQAPAAABMwMOASMiJjczBhYzMjY3Ax20oiXxqa63I7YXV2lPihUEjfzUuLqyr3Fde2QAAAEAPgAABHEEjQAMAAABIwMjEzMDMwEzCQEjAbRaZbfpt2ZOAdHa/eQBU+UB+P4IBI3+AgH+/dH9ogAAAAEAPgAAAvsEjQAFAAAlIQchEzMBEgHpHf1g6beTkwSNAAAAAAEAPgAABY4EjQAPAAAlFwEzAyMTJwEjAyMDIxMzAqQDAgTj6bWkA/4ifZcDp7fp6/cBA5f7cwM1AfzKA0T8vASNAAAAAQA+AAAEvgSNAAsAACEjASMDIxMzATMTMwPVtP6EA6236bcBewOutANh/J8EjfydA2MAAAIATf/vBG8EnQANABsAAAEGACMiAj8BNgAzMhIHJzYmIyIGDwEGFjMyNjcEHzL+09jH1C4jMQEu2MbULbUlb4t+xCIjJm+Lf8MjAfD6/vkBG+as+AEJ/uTlAbqywautvLLBrQACAE3/iwRvBJ0AEwAhAAABDgEHFwcnDgEjIgI/ATYAMzISByc2JiMiBg8BBhYzMjY3BB8WUTx7knw7f0fH1C4jMQEu2MbULbUlb4t+xCIjJm+Lf8MjAfBsp0Gib6AfHQEb5qz4AQn+5OUBurLBq628ssGtAAIAPgAABD8EjQAaACMAAAEDIxMhMhYHDgEHHgEPAQ4BFwcjJjY/ATYmIyczMjY3NiYrAQFVYLfpAa21tiAVcmVYPhQUDAETBLsSCQwUE0tf9fZrgRIUUXT2AeL+HgSNs6JjeCYgjmdlNlwYExppO2NjXpVhWWRkAAEAI//vBDIEnQAlAAABNiYnLgE3PgEzMhYHIzYmIyIGBwYWFx4BBwYEIyImNzMGFjMyNgMAD12Wx5weIPrHusAitRRhc2+RDxBWpMGbHSL+/tO25Sa1GIF0dKEBL05RLDuRl5+hu6xlbmBLUEsuO5eTp5qqvXhcYQAAAAABAL0AAAQlBI0ABwAAASEDIxMhNyEEB/6zy7XL/rgeA0oD+fwHA/mUAAAAAAEAWP/vBLwEjQARAAABAwYEIyImNxMzAwYWMzI2NxMEvJkr/t/ZxeEombSZHH+Ee78amQSN/QHVytzDAv/9AYiEjn4C/wAAAAEAvgAABMoEjQAJAAABHwE3ATMBIwMzAf0GAycB28L9ZanIwwEgVQFUA2/7cwSNAAEA1AAABfIEjQATAAABNzMHATMTNzMHATMBIwMjASMDMwGMAgICAYGpGgICAgFbw/4FqCcD/n6mKcIBCQkHA4L8fAkHA4L7cwNd/KMEjQAAAf/jAAAEhQSNAAsAAAkBMwETIwMBIwEDMwJTAVzW/iH/1LT+ntgB7fzWAtcBtv2//bQBv/5BAkwCQQAAAQC1AAAEgQSNAAgAAAkBMwEDIxMDMwIoAY7L/dtStVT0ywJNAkD9Dv5lAaUC6AAAAf/5AAAEFgSNAAkAADchByE3ASE3IQfvAnEd/LYXAw79xh4DFBaTk3IDh5RuAAAAAgBK/+8EIASdAA0AGwAAAQYEIyImNxM2JDMyFgcnNiYjIgYHAwYWMzI2NwO0K/76w7TCKEUqAQjEssEntRtecWijGUUcYXFnohkBm9fV58UBV9TX58QBiY2Yfv6oio+ZgAAAAAEArAAAAk0EnQAFAAAhIxMHNyUBYbXEwBsBggPTA4hFAAAAAAEADwAAA6YEnQAYAAApATcBPgE3NiYjIgYHIz4BMzIWBw4BBwEhAuX9Kh0BzHVVDRI9VFuGEbYg8bSbniIYd8X+3QH1kwGYZXFAXWt1VqC/tqh3f7D++gABACD/7wPJBJ0AKQAAATMyNjc2JiMiBgcjPgEzMhYHDgEHHgEHDgEjIiY3MwYWMzI2NzYmKwE3AXWcXHUSEE9lTIQOtR/uo6mzHxNyWVJHEyP3upfHIrQRWF5fjxIWUmucFQKaYlVUZGJKnaOroFmDJCWHYa+nq6hXaW9UbVhpAAIAJQAAA8kEjQAKAA4AAAEzByMHIzchNwEzARMnAQMStx63L7Uv/eYUArq7/q9pA/5EAYKV7e12Ayr89QIJAf32AAAAAQAeAAAEVQXFABgAACkBNwE+ATc2JiMiBgcjNiQzMhYHDgEHASEDi/yTGgIml3MTF1Zmhq0btSkBGt6ttCMapp3+QQKTgwITkadbeY2ejdDx5LGC2pb+VwAAAAACAE7/7wO7BJ0AGwAoAAABMhYXBy4BIyIGDwEXPgEzMhYHDgEjIiY3EzYkEyIGDwEGFjMyNjc2JgLBO4c4OjJjRmu4GRQDNoxUpJojJf24prwnPyoBIitPgSgIHFpkXZcUF08EnRsYjxkVpYBhAjE0x7K5xfjEATfU5/20Qjoqip+IY3RwAAAAAQC9AAADwwSNAAwAAAEGAgMHIzcSADchNyEDpePUOCW1JTsBAsT9ux4C6AP57f7I/uW5uQEpAVbBlAAAAwAj/+8D3wSdABcAIwAvAAABDgEHHgEHDgEjIiY3PgE3LgE3PgEzMhYBNiYjIgYHBhYzMjYTNiYjIgYHBhYzMjYDwBR2W1hVEyP+tKzRIRSObk5JESHwr5m4/uESaF5epBAUb2hYmVsQWFBTixASYFlKhQNdYIEjKYxesKe1omiNJCeBVqaap/1UXWpxVmFnbgJpU11gUFZeZQAAAgBt/+8DyASdABsAKAAAJTI2PwEnDgEjIiY3NiQzMhYHAwYEIyImJzceARMyNj8BNiYjIgYHBhYBhmCqFxUDMXxFrawjJAECt6S2JkUo/vC8PIc5ODRlq02GJQsbWGFamhMXUIKXcGoCLy3PrrXS98T+qMXWGhiQGhUBpU03N4mell1wfwAAAAEAfwAAAcEDLAAFAAAhIxMHNyUBH6CEdxoBGwKUAYIXAAAAAAEAIgAAAswDLAAZAAApATcBPgE3NiYjIgYHIz4BMzIWBw4BDwEXIQJH/dsZAU1ONwkLJzk8VQqdFrOIeHoXEl6LsAEBVX4BCD5KLDc8QjRwhX90V2JwjwMAAAAAAQAl//UC3gMsACkAAAEzMjY3NiYjIgYHIz4BMzIWBw4BBx4BBw4BIyImNzMGFjMyNjc2JisBNwEeeztKCwo2QzFPCJ8VsHuAixYNUUA7NAwZuI1ymBefCjk+QF0KDTZGexEB1Ts1MTczKWxvd248WhgaXEN5cnV0NDc8MkU1VQABAO0AAALSBbAABQAAISMTBTclAa+1+f76GAHNBNwId2UAAAABACv/9QLoAyEAHgAAGwEhByEHPgE3NhYHDgEjIiY/AQYWMzI2NzYmIyIGB32LAeAa/qw8Hk4pfmwaG6igepsXnwxBQ0ZYDg41QTpKFAFaAceBvxIZAQKOgoSGbm8LNzNHREpMJB8AAAIAQP/1AscDLAAbACgAAAEyFhcHLgEjIgYPARc+ATMyFgcOASMiJj8BPgETIgYPAQYWMzI2NzYmAg4vZCQzI0cxSXoQDAMlYz11chgZvot9kBsrHdcpOVkXARI9Qj9hDA41AywTEHsQD2BQOwIgIox6f4iqh9aTnf5ZLygIVl1NPEdCAAEAjwAAAswDIQAMAAABDgEPASM3PgE3ITchArOgjiUZnhkotnL+fRkCJAKioca8f3/I92R/AAAAAwAu//UC9QMsABcAIwAvAAABDgEHHgEHDgEjIiY3PgE3LgE3PgEzMhYDNiYjIgYHBhYzMjYTNiYjIgYHBhYzMjYC4A1VQj8+DBi8iYKgFw1mTzk1DBezhHSO5AtGPz5rCwxMRjpjOgo6NjZYCQtAOjBUAlBBWRkdYT56cnxwRWEbHFg6cmpz/i46P0Q1Ojo+AZczMjUwMzc6AAAAAgBk//UC5gMsABsAKAAAJTI2PwEnDgEjIiY3PgEzMhYPAQ4BIyImJzceARMyNj8BNiYjIgYHBhYBQUBuDgwDIFEugYIZGMCKeo0aLxvMji1lKzIlSX01VxMFETxAPGAKDzVzVkU/Ah4ckHp8kayG64eTEhB7Eg0BGDMlF1VeVTlITAAAAgA+//UDGAMsAA0AGwAAAQ4BIyImPwE+ATMyFgcnNiYjIgYPAQYWMzI2NwLPHsWSh5UcLx3EkoeVGqAQQEtGZw8vEkBNRGcRARuTk56I65GVoIYBVFJYTuxXUVhQAAAAAQC5AowDKgMhAAMAAAEhNyEDDP2tHgJTAoyVAAMBKwRCAz0GcwAEABAAHAAAATMXByMHPgEzMhYHDgEjIiY3BhYzMjY3NiYjIgYCirIB8G6lD29HPksOD2pEQVFhCCYjHTkHCCIhIDwGcwO1101ZX0dNVVtHJy0wJCgwMwAAAAACAPUEcANuBdYABQAPAAABEzMHASMnPgE3Fw4BDwEjAgWpwAT+7VX8EnBeOzI4DhCkBIMBQhX+wlRchS86LmdHUAAAAAEALv/rBEsFxQArAAABPwIzMjY3NiYjIgYHIzYkMzIWBw4BBx4BBwYEIyImNzMGFjMyNjc2JisBAaYLAwifdIkYG1h2Z6EXtSQBDMK0vCcVh3RuSBUs/uzFstAmthpmeHClGx5ZhZ8CwzcPJ4d1iHuKcrja1sdlrS4utm/Y0ti+f4KKh5V2AAACACcAAAQcBbAACgAPAAABMwcjAyMTITcBMwEhEycHA1q8HrtEtET9nhUDIb/86wGfjAMgAeiV/q0BU2sD8vw4ArwBOgAAAAABAGH/6wRpBbAAHwAAGwEhByEDFz4BNzYSBwYEIyImNzMGFjMyNjc2JiMiBgfW7gKlIv30fwMwcEe+ny0w/v3ZpMUpqxtja2+pIB9cd2d2JQKRAx+p/mABIywCAv775O34ysqEe7Kcm6lJSQACAGT/6wQ5BcUAGwAoAAABMhYXBy4BIyIGDwEXPgEzMhIHBgAjIgIbARIAEyIGDwEGFjMyNjc2JgNKQ4YmQylcRYvqKAQDRKJbrKspMf7tx77QOTk8AVkgXJczFyxxfWutHx9eBcUjGpEaHvnKEgE0Of7y0PP+9gE0ARkBHwEtAUH9c1ZKctzK0JigsAAAAAAD/5H+SgRTBE4ALwA/AE0AAAEjHgEPAQYEIyImJw4BBwYWOwEyFgcGBCMiJjc+ATcuATc+ATcuAT8BPgEzMhYXIQEiJicOAQcGFjMyNjc2JiMDBhYzMjY/ATYmIyIGBwQ4lhUNCgUh/wC1JkIeGyUHCjU6oLKyHhz+yefC0BcUc1MWEQkPUDxFOhMFIf65Iz8gAWH84xQjEDNNCxBsgYjRDg9KdLESYmVamBEFEmFkXZgQA6orYTYWo8IKDBQ0JDEjkpOIzKJ0ZH8nFjsmTl8lMpVYFqm9Cgr79AIEF109TVd6RU9BAqRadn1TFl1zelYAAAAAAQDrAAAEiwWwAAwAAAEIAQMHIzcSABMhNyEEbf7Q/wBtLbYtbQFA8/0xHgOCBRr+xf4i/piZmQFhAhgBCJYAAAH/zv5MBFoESQAjAAABMhYfAQEzARMeATMyNjcHDgEjIiYnAwEjAQMuASMiBiM3PgEBRW9ZGjMBSrb+LGIPLCkMDBQhCyMNY10eQP6QwAIETQ08OQo0AhwWOQRJlHf7Aff9L/4hS00CA5wGCX+QAT39yQMTAYFUZAWSBQoAAAAAAwA1/+sEWAXFABcAIwAvAAABDgEHHgEHBgQjIiY3PgE3LgE3PgEzMhYBNiYjIgYHBhYzMjYTNiYjIgYHBhYzMjYEMhqVcGtoFy3+78y/0SkarIRdVhcq+72rv/7CGnF1brUYG298bbF7F19kX5kXGV5oXJoENX6mKC+3etvD1MqItiktp3HRv9D8mISRm3qIhZADIXeHi3N7fogAAgBA/+sEkQROABQAIgAAJScOASMiAj8BEgAzMhYXMzczCwEjAQYWMzI2PwE2JiMiBgcDHwNJw4GvoC8EOAEEwneRHQNMrNACrP4SJVSHZalCCApPbX22JeABeX0BIOoVARsBKYB55f3i/eQB9bXA2LAmrN7yvAAAAgBB090pTwWwABoAKwAAAQchFgABFhIPAQYAIyICPwE2JDc6ARcmAic3AwYWMzI2PwE2JicuASMiBgcERR3+Xg8mutnNiXMfBDP+39jHwS8EKQEO0ggPCgbXKheIJVyKfLshBBk6PhMnGIbDHwWwkh3O3DB8nv73nhj9/uwBKegYzPkZAQcBBUFy/EyyytmjGH2qNgYG0JkAAAAAAgBYAAAE+QWwAAkAEwAAMwEhIBIDBwIAIRMDMzI2PwE2JiNYASMBXgEu8jwxQv62/rZc56nX/i4xMZTqBbD+z/7S8/62/uwFGvt74+b2988AAAAAAgA3/+sD/QROACAAKwAAITQ2NycOASMiJjc+ATsBNzYmIyIGByM+ATMyFgcDDgEXJTI2PwEjIgYHBhYCoAMDAkGtXZqIIST/2bUcFFdsZYAPtRzi07WqI20NCQT+OVerLC67e5sTEDosNxsBQFSgobaWiWZRYUmOsp+w/ds9ZjeKUTnkbmJTSwAAAAACAFcAAATuBa8ADgAXAAABDgEHEwcjAyEDIwEhMhYBITI2NzYmIyEExh2efcQEy6v+sHu2ASMB2NLK/LgBJIGsGhtnkf7eBAuLuy/9fBICav2WBa/a/iqOgIiFAAEAWAAABVgFsAANAAABBwMjATMDFzcBMwkBIwIuu2a1ASO1kAO4Ai3Q/WkBtuMCq63+AgWw/TECrQIk/YP8zQABADYAAAQxBhgADQAAAQcDIwEzAxc3ATMJASMBvIVLtgE4tr4DdgF52f4bATXWAfB4/ogGGPxLAXIBZv45/Y0AAQBYAAAFVgWwAAsAAAEDIwEzAzMBMwkBIwGXirUBI7WCDAK74f0JAfrfArL9TgWw/XgCiP05/RcAAAAAAQA2AAAEFAYYAAwAAAEjAyMBMwMXATMJASMBVARktgE4trUDAbfr/eoBZt8B9P4MBhj8eAEBq/4O/bgAAgB9/+sEVwXFABsAKAAAJTI2PwEnDgEjIgI3NgAzMhILAQIAIyImJzceARMyNj8BNiYjIgYHBhYBpYDTKwYDOZNXvLowMQEktsvENkg+/svfRZA1ODRwx2KeMB4qX4liuyAjWoDZ1x0BREABCOz3ARD+5f7s/pz+zf7sHB+QHRkB32RNmNK1z6KsswACAD4AAARDBI0ACgATAAABAyMTITIWBw4BIyczMjY3NiYrAQFJVLfpAbKyuCAl98Pe/GiQEhRUcfsBpv5aBI3QpLPAlIJbZX0AAAD//wELBKUDTwWwAgYAnAAA//8AAAAAAAAAAAIGAAMAAP//AD4CIQIjArYCBgAPAAAAAgBeAAAFOwWwAA0AGwAAMxMjNzMTISAAAwcCACETIQMhMhI/ATYCKwEDIXaFnR6dgAF6AQABKDcnPv6s/u93/v9nAQ+x8ysoLL/HxWIBAQKalQKB/pT+7cX+zf7HApr9+wEB1sjeAQj+FQAAAgBeAAAFOwWwAA0AGwAAMxMjNzMTISAAAwcCACETIQMhMhI/ATYCKwEDIXaFnR6dgAF6AQABKDcnPv6s/u93/v9nAQ+x8ysoLL/HxWIBAQKalQKB/pT+7cX+zf7HApr9+wEB1sjeAQj+FQAAAQBTAAAENwYYABwAAAEjAxc+ATMyFgcDIxM2JiMiBgcDIxMjNzM3MwczAvz8OANApF6bjyuHtYgeT29JjzmetvehHqAktiT9BNL+6QJITdDZ/VsCp5Z3VEj86ATSlbGxAAAAAAEA7AAABQsFsAAPAAABIwMjEyM3MxMhNyEHIQMzA7HLpLWk0x7TQ/5aHgQBHv5aQ8sDNvzKAzaVAU+Wlv6xAAABAAf/7AKkBUEAHwAAAQMzByMHMwcjAwYWMzI2NwcOASMiJjcTIzczNyM3MxMCGjW/HL8m1R7VQBIkKxQzEwIcXSxjYyBAyB7IJo0cjTUFQf75jb6V/r1WOQgFgxEVj5wBQ5W+jQEH////1QAABH8HIgImACMAAAAHAEIBawFd////1QAABMMHHwImACMAAAAHAHMCFwFZ////1QAABI0HRgImACMAAAAHAJoBBgFd////1QAABNQHUQImACMAAAAHAKABJQFg////1QAABMwHDAImACMAAAAHAGgBBwFc////1QAABH8HiAImACMAAAAHAJ4BkgGo////1QAABMYHnwImACMAAAAHAdQBiQEs//8AYv5EBPgFxQAmACUAAAAHAHcBt//3//8AWAAABPIHIgImACcAAAAHAEIBNwFd//8AWAAABPIHHwImACcAAAAHAHMB4wFZ//8AWAAABPIHRgImACcAAAAHAJoA0gFd//8AWAAABPIHDAImACcAAAAHAGgA0wFc//8AYgAAAkQHIgImACsAAAAHAEL//AFd//8AYgAAA1MHHwImACsAAAAHAHMApwFZ//8AYgAAAx4HRgImACsAAAAHAJr/lwFd//8AYgAAA10HDAImACsAAAAHAGj/mAFc//8AWAAABXoHUQImADAAAAAHAKABTgFg//8AXv/rBTYHNwAmADEAAAAHAEIBjAFy//8AXv/rBTYHNAAmADEAAAAHAHMCOAFu//8AXv/rBTYHWwAmADEAAAAHAJoBJwFy//8AXv/rBTYHZgAmADEAAAAHAKABRgF1//8AXv/rBTYHIQAmADEAAAAHAGgBKAFx//8AZ//rBVcHIgImADcAAAAHAEIBdwFd//8AZ//rBVcHHwImADcAAAAHAHMCIwFZ//8AZ//rBVcHRgImADcAAAAHAJoBEgFd//8AZ//rBVcHDAImADcAAAAHAGgBEwFc//8A7gAABVMHHQImADsAAAAHAHMB6QFX//8AOv/sA/cF4AImAEMAAAAHAEIAswAb//8AOv/sBAsF3QImAEMAAAAHAHMBXwAX//8AOv/sA/cGBAImAEMAAAAGAJpOGwAA//8AOv/sBBwGDwImAEMAAAAGAKBtHgAA//8AOv/sBBQFygImAEMAAAAGAGhPGgAA//8AOv/sA/cGRgImAEMAAAAHAJ4A2gBm//8AOv/sBA4GXgImAEMAAAAHAdQA0f/r//8AR/5EA/sETgImAEUAAAAHAHcBOf/3//8AR//sA+sF4QImAEcAAAAHAEIAkQAc//8AR//sA+sF3gImAEcAAAAHAHMBPQAY//8AR//sA+sGBQImAEcAAAAGAJosHAAA//8AR//sA/IFywImAEcAAAAGAGgtGwAA//8APgAAAd0FywImAIoAAAAGAEKVBgAA//8APgAAAuwFyAImAIoAAAAGAHNAAgAA//8APgAAArcF7wImAIoAAAAHAJr/MAAG//8APgAAAvYFtQImAIoAAAAHAGj/MQAF//8ANQAABDIGDwImAFAAAAAHAKAAgwAe//8ARv/sBBwF4AImAFEAAAAHAEIApwAb//8ARv/sBBwF3QImAFEAAAAHAHMBUwAX//8ARv/sBBwGBAImAFEAAAAGAJpCGwAA//8ARv/sBBwGDwImAFEAAAAGAKBhHgAA//8ARv/sBBwFygImAFEAAAAGAGhDGgAA//8AWv/sBDsFywImAFcAAAAHAEIAxgAG//8AWv/sBDsFyAImAFcAAAAHAHMBcgAC//8AWv/sBDsF7wImAFcAAAAGAJphBgAA//8AWv/sBDsFtQImAFcAAAAGAGhiBQAA////vP5LBCoFyAImAFsAAAAHAHMBNQAC////vP5LBCoFtQImAFsAAAAGAGglBQAA////1QAABN4G+gImACMAAAAHAG4BJgFK//8AOv/sBCYFuAImAEMAAAAGAG5uCAAA////1QAABLAHTAImACMAAAAHAJwBYQGc//8AOv/sA/gGCgImAEMAAAAHAJwAqQBaAAL/1f5QBH8FsAAaAB4AAAEzEyMOAQcGFjMyNjcHDgEjIiY3PgE3AyEDIwEhAycDBJvgJVdiCQYbKBkwFwcgTDJPWA8LY180/c7SuAHbAc1cAwWw+lA+ZDwlJRELeBMZY1pJfTYBe/58AhkCoAEAAAACADr+UAP3BE4ANAA/AAAhNDY3Jw4BIyImNzYkOwE3NiYjIgYHIzYkMzIWBwMOARcjDgEHBhYzMjY3Bw4BIyImNz4BNyUyNj8BIyIGBwYWAqAEBQNCrl2WiR4iAQHQvhYVV2dYjg61GwEAtqS1ImgNCQQTV2IJBhsoGTAXByBMMk9YDwtbWP7wV60vKMNrpBARQTM+HwFIXayWqKJuaWlkRoW7u6/99j1mNz5kPCUlEQt4ExljWkZ5NItgRMl7U1BPAAD//wBi/+sE+Ac0ACYAJQAAAAcAcwIhAW7//wBH/+wD+wXdAiYARQAAAAcAcwEqABf//wBi/+sE+AdbACYAJQAAAAcAmgEQAXL//wBH/+wD+wYEAiYARQAAAAYAmhkbAAD//wBi/+sE+AciACYAJQAAAAcAnQHRAXL//wBH/+wD+wXLAiYARQAAAAcAnQDaABv//wBi/+sE+AdcACYAJQAAAAcAmwEmAXP//wBH/+wD+wYFAiYARQAAAAYAmy8cAAD//wBYAAAFHQdHACYAJgAAAAcAmwDgAV7//wBE/+sFwwYYACYARgAAAAcBkQSgBSz//wBYAAAE8gb6AiYAJwAAAAcAbgDyAUr//wBH/+wEBAW5AiYARwAAAAYAbkwJAAD//wBYAAAE8gdMAiYAJwAAAAcAnAEtAZz//wBH/+wD6wYLAiYARwAAAAcAnACHAFv//wBYAAAE8gcNAiYAJwAAAAcAnQGTAV3//wBH/+wD6wXMAiYARwAAAAcAnQDtABwAAQBY/lAE8gWwACAAAAEhAyEHIw4BBwYWMzI2NwcOASMiJjc+ATcnIQEhByEDIQQC/ZJpAsweNFdiCQYbKBkwFwcgTDJPWA8LWlQB/V0BIwN3Hv0+YAJuAqb975U+ZDwlJRELeBMZY1pGeDIDBbCW/iIAAAACAEf+ZAPrBE4AKQAxAAAlDgEHDgEHBhYzMjY3Bw4BIyImNz4BNycmAj8BNgAzMhIPASEGFjMyNjcDIgYHITc2JgNbIVM0U14IBhsoGTAXByBMMk9YDwg/OQHIyicHJwEptMerIxP9bBhrh1qXPMdaoCkB2gQTWXEeMxI7YjslJRELeBMZY1o5YywDAwEp7y31ASX++915rcU5MgLMqoYafZkA//8AWAAABPIHRwImACcAAAAHAJsA6AFe//8AR//sA+sGBgImAEcAAAAGAJtCHQAA//8AaP/rBQ8HWwImACkAAAAHAJoBBgFy//8AN/5LBD0GBAImAEkAAAAGAJpWGwAA//8AaP/rBQ8HYQImACkAAAAHAJwBYQGx//8AN/5LBD0GCgImAEkAAAAHAJwAsQBa//8AaP/rBQ8HIgImACkAAAAHAJ0BxwFy//8AN/5LBD0FywImAEkAAAAHAJ0BFwAb//8AaP3lBQ8FxQImACkAAAAHAZEBRv62//8AN/5LBD0GbQImAEkAAAAHAaUBKABW//8AWAAABXkHRgImACoAAAAHAJoBKQFd//8ANQAABBkHRQImAEoAAAAHAJoAYwFc//8AYgAAA2UHUQImACsAAAAHAKD/tgFg//8APgAAAv4F+gImAIoAAAAHAKD/TwAJ//8AYgAAA28G+gImACsAAAAHAG7/twFK//8APgAAAwgFpAImAIoAAAAHAG7/UP/0//8AYgAAA0EHTAImACsAAAAHAJz/8gGc//8APgAAAtoF9QImAIoAAAAGAJyLRQAA////mv5YAjoFsAImACsAAAAGAJ/jCAAA////e/5QAjEGGAImAEsAAAAGAJ/EAAAA//8AYgAAAogHDQImACsAAAAHAJ0AVwFd//8AYv/rBnYFsAAmACsAAAAHACwCJAAA//8ARP5LBCEGGAAmAEsAAAAHAEwB6AAA//8AD//rBSwHOQImACwAAAAHAJoBpQFQ////G/5LAsQF3AImAJgAAAAHAJr/Pf/z//8APv31BTUFsAAmAC0AAAAHAZEBIP7G//8ANv33BCgGGAImAE0AAAAHAZEAxP7I//8AWAAAA60G4AImAC4AAAAHAHMAjwEa//8ARAAAA0MHXAImAE4AAAAHAHMAlwGW//8AWP33A60FsAImAC4AAAAHAZEBGv7I////qP33AjEGGAImAE4AAAAHAZH/wv7I//8AWAAAA9UFsQImAC4AAAAHAZECsgTF//8ARAAAA3IGGAAmAE4AAAAHAZECTwUs//8AWAAAA60FsAImAC4AAAAHAJ0BNP3F//8ARAAAAukGGAAmAE4AAAAHAJ0AuP23//8AWAAABXoHHwImADAAAAAHAHMCQAFZ//8ANQAABCEF3QImAFAAAAAHAHMBdQAX//8AWP33BXoFsAImADAAAAAHAZEBd/7I//8ANf33BBgETgImAFAAAAAHAZEA7P7I//8AWAAABXoHRwImADAAAAAHAJsBRQFe//8ANQAABCMGBQImAFAAAAAGAJt6HAAA//8ANQAABBgGGAImAFAAAAAHAZEAiwUs//8AXv/rBTYHDwAmADEAAAAHAG4BRwFf//8ARv/sBBwFuAImAFEAAAAGAG5iCAAA//8AXv/rBTYHYQAmADEAAAAHAJwBggGx//8ARv/sBBwGCgImAFEAAAAHAJwAnQBa//8AXv/rBZkHYAAmADEAAAAHAKEBqgFy//8ARv/sBLQGCQImAFEAAAAHAKEAxQAb//8AVwAABQIHHwImADQAAAAHAHMB3AFZ//8ANQAAA4cF3QImAFQAAAAHAHMA2wAX//8AV/33BQIFrwImADQAAAAHAZEBE/7I////pv33Aw0ETgImAFQAAAAHAZH/wP7I//8AVwAABQIHRwImADQAAAAHAJsA4QFe//8ANQAAA4oGBQImAFQAAAAGAJvhHAAA//8AQ//rBMAHNAAmADUAAAAHAHMB1gFu//8AO//sA9MF3QImAFUAAAAHAHMBJwAX//8AQ//rBMAHWwAmADUAAAAHAJoAxQFy//8AO//sA8kGBAImAFUAAAAGAJoWGwAA//8AQ/5EBMAFxQAmADUAAAAHAHcBbP/3//8AO/5FA8kETgImAFUAAAAHAHcBN//4//8AQ/3jBMAFxQAmADUAAAAHAZEBBP60//8AO/3kA8kETgImAFUAAAAHAZEAz/61//8AQ//rBMAHXAAmADUAAAAHAJsA2wFz//8AO//sA9UGBQImAFUAAAAGAJssHAAA//8A7P31BQsFsAImADYAAAAHAZEBDP7G//8ARf3tAqQFQQImAFYAAAAHAZEAX/6+//8A7P5VBQsFsAImADYAAAAHAHcBdAAI//8Ab/5NAqQFQQImAFYAAAAHAHcAxwAA//8A7AAABQsHRgImADYAAAAHAJsA2gFd//8Ab//sA7QGMQAmAFYAAAAHAZECkQVF//8AZ//rBVcHUQImADcAAAAHAKABMQFg//8AWv/sBDsF+gImAFcAAAAHAKAAgAAJ//8AZ//rBVcG+gImADcAAAAHAG4BMgFK//8AWv/sBDsFpAImAFcAAAAHAG4Agf/0//8AZ//rBVcHTAImADcAAAAHAJwBbQGc//8AWv/sBDsF9QImAFcAAAAHAJwAvABF//8AZ//rBVcHiAImADcAAAAHAJ4BngGo//8AWv/sBDsGMQImAFcAAAAHAJ4A7QBR//8AZ//rBYQHSwImADcAAAAHAKEBlQFd//8AWv/sBNMF9AImAFcAAAAHAKEA5AAGAAEAZ/5uBVcFsAAoAAABAw4BBw4BBwYWMzI2NwcOASMiJjc+ATcnIgYjIiY3EzMDBhYzMjY3EwVXxSW4jE5cCQYbKBkwFwcgTDJPWA8IOTQBBBYG1u0wxbbFJYqWkeIixQWw/CW22jI3YzklJRELeBMZY1o2XioDAfzuA9v8JbafragD2wAAAAABAFr+UAQ7BDoAJwAAIQ4BBwYWMzI2NwcOASMiJjc+AT8BJw4BIyImNxMzAwYWMzI2NxMzAwNiV2IJBhsoGTAXByBMMk9YDwpeWRIDP6JlnZMwf7Z/JkNpX5Mzm7XYPmQ8JSURC3gTGWNaRno1jwFSVOHwAn39gb53W1MDBvvG//8A7AAABuwHRgImADkAAAAHAJoBnAFd//8AsgAABfoF7wImAFkAAAAHAJoBFQAG//8A7gAABVMHRAImADsAAAAHAJoA2AFb////vP5LBCoF7wImAFsAAAAGAJokBgAA//8A7gAABVMHCgImADsAAAAHAGgA2QFa//8AIAAABH0HHwAmADwAAAAHAHMB0QFZ//8ACAAAA+oFyAImAFwAAAAHAHMBPgAC//8AIAAABFsHDQAmADwAAAAHAJ0BgQFd//8ACAAAA98FtgImAFwAAAAHAJ0A7gAG//8AIAAABH8HRwAmADwAAAAHAJsA1gFe//8ACAAAA+wF8AImAFwAAAAGAJtDBwAA////ngAAB3UHHwImAH8AAAAHAHMDAQFZ//8ABP/rBmAF3gImAIQAAAAHAHMCegAY//8AJv+jBWsHXQImAIEAAAAHAHMCMQGX//8ATP95BDgF3AImAIcAAAAHAHMBUAAW//8ACwAABEkEjQImAakAAAAHAdP/Uv97//8ACwAABEkEjQImAakAAAAHAdP/Uv97//8AvQAABCUEjQImAbgAAAAGAdMo9wAA////1AAAA+gF3wImAaYAAAAHAEIA2QAa////1AAABDEF3AImAaYAAAAHAHMBhQAW////1AAAA/sGAwImAaYAAAAGAJp0GgAA////1AAABEIGDgImAaYAAAAHAKAAkwAd////1AAABDoFyQImAaYAAAAGAGh1GQAA////1AAAA+gGRQImAaYAAAAHAJ4BAABl////1AAABDQGXQImAaYAAAAHAdQA9//q//8ATf5HBEIEnQImAagAAAAHAHcBU//6//8APgAABB0F3wImAaoAAAAHAEIAqgAa//8APgAABB0F3AImAaoAAAAHAHMBVgAW//8APgAABB0GAwImAaoAAAAGAJpFGgAA//8APgAABB0FyQImAaoAAAAGAGhGGQAA//8APgAAAd8F3wImAa4AAAAGAEKXGgAA//8APgAAAu4F3AImAa4AAAAGAHNCFgAA//8APgAAArkGAwImAa4AAAAHAJr/MgAa//8APgAAAvgFyQImAa4AAAAHAGj/MwAZ//8APgAABL4GDgImAbMAAAAHAKAAsQAd//8ATf/vBG8F7wImAbQAAAAHAEIA3QAq//8ATf/vBG8F7AImAbQAAAAHAHMBiQAm//8ATf/vBG8GEwImAbQAAAAGAJp4KgAA//8ATf/vBG8GHgImAbQAAAAHAKAAlwAt//8ATf/vBG8F2QImAbQAAAAGAGh5KQAA//8AWP/vBLwF4AImAbkAAAAHAEIA9QAb//8AWP/vBLwF3QImAbkAAAAHAHMBoQAX//8AWP/vBLwGBAImAbkAAAAHAJoAkAAb//8AWP/vBLwFygImAbkAAAAHAGgAkQAa//8AtQAABIEF2wImAb0AAAAHAHMBWAAV////1AAABEwFtwImAaYAAAAHAG4AlAAH////1AAABB4GCQImAaYAAAAHAJwAzwBZAAL/1P5QA+gEjQAaAB4AAAETIw4BBwYWMzI2NwcOASMiJjc+ATcnIQMjAQMhAycDHcs3V2IJBhsoGTAXByBMMk9YDwtqZin+J5i8Ap74AXBRAwSN+3M+ZDwlJRELeBMZY1pMgDj//vAEjf0XAfsBAP//AE3/7wRCBewCJgGoAAAABwBzAXoAJv//AE3/7wRCBhMCJgGoAAAABgCaaSoAAP//AE3/7wRCBdoCJgGoAAAABwCdASoAKv//AE3/7wRCBhQCJgGoAAAABgCbfysAAP//AD4AAARJBgQCJgGpAAAABgCbLhsAAP//AD4AAAQdBbcCJgGqAAAABgBuZQcAAP//AD4AAAQdBgkCJgGqAAAABwCcAKAAWf//AD4AAAQdBcoCJgGqAAAABwCdAQYAGgABAD7+UAQdBI0AIAAAASEDIQcjDgEHBhYzMjY3Bw4BIyImNz4BNychEyEHIQMhA0/+EE0CPx1CV2IJBhsoGTAXByBMMk9YDwtaVAH99ukC9h79wUMB7wIV/n6TPmQ8JSURC3gTGWNaRngyAwSNlP6wAAAA//8APgAABB0GBAImAaoAAAAGAJtbGwAA//8ASv/vBF4GEwImAawAAAAGAJpzKgAA//8ASv/vBF4GGQImAawAAAAHAJwAzgBp//8ASv/vBF4F2gImAawAAAAHAJ0BNAAq//8ASv3nBF4EnQImAawAAAAHAZEA9/64//8APgAABKQGAwImAa0AAAAGAJp7GgAA//8APgAAAwAGDgImAa4AAAAHAKD/UQAd//8APgAAAwoFtwImAa4AAAAHAG7/UgAH//8APgAAAtwGCQImAa4AAAAGAJyNWQAA////c/5QAd0EjQImAa4AAAAGAJ+8AAAA//8APgAAAiQFygImAa4AAAAGAJ3zGgAA//8AC//vBKYF+QImAa8AAAAHAJoBHwAQ//8APv3zBHEEjQImAbAAAAAHAZEArP7E//8APgAAAvsFwQImAbEAAAAGAHND+wAA//8APv31AvsEjQImAbEAAAAHAZEAjP7G//8APgAAAxAEjgImAbEAAAAHAZEB7QOi//8APgAAAvsEjQImAbEAAAAHAJ0Aif0m//8APgAABL4F3AImAbMAAAAHAHMBowAW//8APv31BL4EjQImAbMAAAAHAZEBGv7G//8APgAABL4GBAImAbMAAAAHAJsAqAAb//8ATf/vBG8FxwImAbQAAAAHAG4AmAAX//8ATf/vBG8GGQImAbQAAAAHAJwA0wBp//8ATf/vBOoGGAImAbQAAAAHAKEA+wAq//8APgAABD8F3AImAbYAAAAHAHMBOQAW//8APv31BD8EjQImAbYAAAAHAZEAsP7G//8APgAABD8GBAImAbYAAAAGAJs+GwAA//8AI//vBDIF7AImAbcAAAAHAHMBZAAm//8AI//vBDIGEwImAbcAAAAGAJpTKgAA//8AI/5HBDIEnQImAbcAAAAHAHcBPf/6//8AI//vBDIGFAImAbcAAAAGAJtpKwAA//8Al/31BCUEjQImAbgAAAAHAZEAsf7G//8AvQAABCUGAwImAbgAAAAGAJs/GgAA//8AWP/vBLwGDwImAbkAAAAHAKAArwAe//8AWP/vBLwFuAImAbkAAAAHAG4AsAAI//8AWP/vBLwGCgImAbkAAAAHAJwA6wBa//8AWP/vBLwGRgImAbkAAAAHAJ4BHABm//8AWP/vBQIGCQImAbkAAAAHAKEBEwAbAAEAWP57BLwEjQAoAAABAw4BBw4BBwYWMzI2NwcOASMiJjc+ATcnIgYjIiY3EzMDBhYzMjY3EwS8mR2QcFBbCAYbKBkwFwcgTDJPWA8HNC4BBQ0LxeEombSZHH+Ee78amQSN/QGLszA5YDolJRELeBMZY1ozWigDAdzDAv/9AYiEjn4C/wAAAP//ANQAAAXyBgMCJgG7AAAABwCaAQwAGv//ALUAAASBBgICJgG9AAAABgCaRxkAAP//ALUAAASBBcgCJgG9AAAABgBoSBgAAP////kAAAQWBdwCJgG+AAAABwBzATcAFv////kAAAQWBcoCJgG+AAAABwCdAOcAGv////kAAAQWBgQCJgG+AAAABgCbPBsAAP//ACP/7whdBJ0AJgG3AAAABwG3BCsAAP///9UAAAR/BngCJgAjAAAABgCpPAAAAP//AJsAAAVWBnoAJgAnZAAABwCp/zcAAv//ALwAAAXdBnoAJgAqZAAABwCp/2MAAv//AMYAAAKeBnkAJgArZAAABwCp/2cAAf//AHL/6wVKBngAJgAxFAAABgCpmgAAAP//AEkAAAW3BngAJgA7ZAAABwCp/uUAAP//ADEAAAUcBngAJgC1FAAABgCphAAAAP//AGz/6wMkBj8CJgC+AAAABwCq/yv/t////9UAAAR/BbACBgAjAAD//wBYAAAE0AWwAgYAJAAA//8AWAAABPIFsAIGACcAAP//ACAAAARbBbAABgA8AAD//wBYAAAFeQWwAgYAKgAA//8AYgAAAjoFsAIGACsAAP//AD4AAAU1BbAABgAtAAD//wBYAAAGswWwAgYALwAA//8AWAAABXoFsAIGADAAAP//AF7/6wU2BcUABgAxAAD//wBYAAAFGAWwAgYAMgAA//8A7AAABQsFsAIGADYAAP//AO4AAAVTBbACBgA7AAD////8AAAFHQWwAgYAOgAA//8AYgAAA10HDAImACsAAAAHAGj/mAFc//8A7gAABVMHCgImADsAAAAHAGgA2QFa//8AQP/rBDQGegImALYAAAAHAKkBWwAC//8AKf/tA/0GeQImALoAAAAHAKkBFgAB//8ANf5hBBIGegImALwAAAAHAKkBMAAC//8Afv/rAtQGZgImAL4AAAAGAKkq7gAA//8AWv/rBAUGPwImAMYAAAAGAKoMtwAA//8APgAABGAEOgIGAIsAAP//AEb/7AQcBE4CBgBRAAD////r/mAEMwQ6AgYAdAAA//8AlwAABAoEOgIGAFgAAP///+kAAAPxBDoCBgBaAAD//wB+/+sDJQW1AiYAvgAAAAcAaP9gAAX//wBa/+sEBgW1AiYAxgAAAAYAaEEFAAD//wBG/+wEHAZ6AiYAUQAAAAcAqQEOAAL//wBa/+sD9AZmAiYAxgAAAAcAqQEM/+7//wBd/+sF7AZjAiYAyQAAAAcAqQIj/+v//wBYAAAE8gcMAiYAJwAAAAcAaADTAVz//wBXAAAEuQcfAiYArAAAAAcAcwHhAVkAAQBD/+sEwAXFACUAAAE2JicuATc2JDMyFgcjNiYjIgYHBhYXHgEHBgQjIiQ3MwYWMzI2A34YcLPWsSgjAQXD2OkqthyJkmmdERpmu9uwJyX+9czZ/uMwtSO4mmqrAUx3hEJIy8axsuzWi6F0V393R0/Hw7ir1uurgXIA//8AYgAAAjoFsAIGACsAAP//AGIAAANdBwwCJgArAAAABwBo/5gBXP//AA//6wRSBbACBgAsAAD//wA+AAAFNQWwAAYALQAA//8APgAABTUGxwAmAC0AAAAHAHMBxQEB//8Ao//rBUUHTAImANkAAAAHAJwBPgGc////1QAABH8FsAIGACMAAP//AFgAAATQBbACBgAkAAD//wBXAAAEuQWwAgYArAAA//8AWAAABPIFsAIGACcAAP//AFgAAAV6B0wCJgDXAAAABwCcAY4BnP//AFgAAAazBbACBgAvAAD//wBYAAAFeQWwAgYAKgAA//8AXv/rBTYFxQAGADEAAP//AFgAAAV7BbACBgCxAAD//wBYAAAFGAWwAgYAMgAA//8AYv/rBPgFxQAGACUAAP//AOwAAAULBbACBgA2AAD////8AAAFHQWwAgYAOgAA//8AOv/sA/cETgIGAEMAAP//AEf/7APrBE4CBgBHAAD//wBAAAAERwX1AiYA6wAAAAcAnADIAEX//wBG/+wEHAROAgYAUQAA////4v5gBCYETgIGAFIAAAABAEf/7AP7BE4AGwAAJTI2NzMGBCMiAj8BNgAzMhYHIzYmIyIGDwEGFgHxWqAPrBn+8qbXuyUHJwER4a7BGqwQameNpBoHHFWBeFyazwEy6ir1ASfeqmyG4qQqsdYAAP///7z+SwQqBDoCBgBbAAD////pAAAD8QQ6AgYAWgAA//8AR//sA/IFywImAEcAAAAGAGgtGwAA//8APgAAA5UFyAImAOcAAAAHAHMA5wAC//8AO//sA8kETgIGAFUAAP//AEQAAAIxBhgCBgBLAAD//wA+AAAC9gW1AiYAigAAAAcAaP8xAAX///8d/ksCOQYYAgYATAAA//8AQAAABGEFxwImAOwAAAAHAHMBTQAB////vP5LBCoF9QImAFsAAAAGAJx/RQAA//8A7AAABuwHIgImADkAAAAHAEICAQFd//8AsgAABfoFywImAFkAAAAHAEIBegAG//8A7AAABuwHHwImADkAAAAHAHMCrQFZ//8AsgAABfoFyAImAFkAAAAHAHMCJgAC//8A7AAABuwHDAImADkAAAAHAGgBnQFc//8AsgAABfoFtQImAFkAAAAHAGgBFgAF//8A7gAABVMHIAImADsAAAAHAEIBPQFb////vP5LBCoFywImAFsAAAAHAEIAiQAG//8AxgQjAagGGAIGAAkAAP//AMUEFAK9BhgCBgAEAAD//wBPAAAEJQWwACYEHAAAAAcEHAH9AAD//wCKAAAEzAYtACYASAAAAAcATgKbAAD///8b/ksC/AXdAiYAmAAAAAcAm/9T//T//wCxA+cCIAYYAgYBZgAA//8AWAAABrMHHwImAC8AAAAHAHMC3wFZ//8ANQAABlsF3QImAE8AAAAHAHMCrwAX////1f6HBH8FsAImACMAAAAHAKIBOQAA//8AOv6HA/cETgImAEMAAAAHAKIAkgAA//8AAf/rBTYGogAmADEAAAAHAdX/DADM//8AigAABrIGLQAmAEgAAAAHAZICmwAA//8AigAAB2cGLQAmAEgAAAAnAEgCmwAAAAcATgU2AAD//wBYAAAE8gciAiYAJwAAAAcAQgE3AV3//wBYAAAFegciAiYA1wAAAAcAQgGYAV3//wBH/+wD6wXhAiYARwAAAAcAQgCRABz//wBAAAAERwXLAiYA6wAAAAcAQgDSAAb//wCKAAAFkgWwAgYAtAAA//8AQ/4pBS4EOgIGAMgAAP//AOgAAAVcB0cCJgEUAAAABwCnBDEBWf//ALMAAARLBh8CJgEVAAAABwCnA5gAMf//AEb+SwhuBE4AJgBRAAAABwBbBEQAAP//AF7+SwllBcUAJgAxAAAABwBbBTsAAP//ACD+UQSwBcUCJgDWAAAABwGcAXD/uP//AB7+UgPEBEwCJgDqAAAABwGcASD/uf//AGL+UQT4BcUAJgAlAAAABwGcAb//uP//AEf+UQP7BE4CJgBFAAAABwGcAUH/uP//AO4AAAVTBbACBgA7AAD//wCz/mAEJgQ6AgYAuAAA//8AYgAAAjoFsAIGACsAAP///8oAAAddB0wCJgDVAAAABwCcAkwBnP///8MAAAYBBfUCJgDpAAAABwCcAaQARf//AGIAAAI6BbACBgArAAD////VAAAEsAdMAiYAIwAAAAcAnAFhAZz//wA6/+wD+AYKAiYAQwAAAAcAnACpAFr////VAAAEzAcMAiYAIwAAAAcAaAEHAVz//wA6/+wEFAXKAiYAQwAAAAYAaE8aAAD///+eAAAHdQWwAgYAfwAA//8ABP/rBmAETgIGAIQAAP//AFgAAATyB0wCJgAnAAAABwCcAS0BnP//AEf/7APrBgsCJgBHAAAABwCcAIcAW///AEb/6wVABt4CJgFBAAAABwBoAMsBLv//ADz/7AP2BE8CBgCZAAD//wA8/+wEFgXLAiYAmQAAAAYAaFEbAAD////KAAAHXQcMAiYA1QAAAAcAaAHyAVz////DAAAGAQW1AiYA6QAAAAcAaAFKAAX//wAg/+sEsAchAiYA1gAAAAcAaADCAXH//wAe/+0D8gXJAiYA6gAAAAYAaC0ZAAD//wBYAAAFegb6AiYA1wAAAAcAbgFTAUr//wBAAAAERwWkAiYA6wAAAAcAbgCN//T//wBYAAAFegcMAiYA1wAAAAcAaAE0AVz//wBAAAAERwW1AiYA6wAAAAYAaG4FAAD//wBe/+sFNgchACYAMQAAAAcAaAEoAXH//wBG/+wEHAXKAiYAUQAAAAYAaEMaAAD//wBd/+sFNwXFAgYBEgAA//8ARv/sBBwETgIGARMAAP//AF3/6wU3BwcCJgESAAAABwBoAScBV///AEb/7AQeBeYCJgETAAAABgBoWTYAAP//AIf/7AU0ByICJgDiAAAABwBoARQBcv//ADP/6wQNBcoCJgD6AAAABgBoSBoAAP//AKP/6wVFBvoCJgDZAAAABwBuAQMBSv///7z+SwQqBaQCJgBbAAAABgBuRPQAAP//AKP/6wVFBwwCJgDZAAAABwBoAOQBXP///7z+SwQqBbUCJgBbAAAABgBoJQUAAP//AKP/6wVVB0sCJgDZAAAABwChAWYBXf///7z+SwSWBfQCJgBbAAAABwChAKcABv//ANEAAAVIBwwCJgDcAAAABwBoAQsBXP//AH8AAAQGBbUCJgD0AAAABgBoLwUAAP//AFcAAAaiBwwAJgDhDwAAJwArBGgAAAAHAGgByAFc//8AQAAABasFtQAmAPkAAAAnAIoD3gAAAAcAaAEjAAX////8/ksFHQWwAiYAOgAAAAcBmgN+AAD////p/ksD8QQ6AiYAWgAAAAcBmgKWAAD//wBE/+sElQYYAgYARgAA////3v5LBXEFsAImANgAAAAHAZoD/AAA////1f5LBEkEOgImAO0AAAAHAZoDHwAA////1f6xBH8FsAImACMAAAAHAKgErAAA//8AOv6xA/cETgImAEMAAAAHAKgEBQAA////1QAABH8HxgImACMAAAAHAKYE5QFT//8AOv/sA/cGhAImAEMAAAAHAKYELQAR////1QAABg4HqAImACMAAAAHAaMA8AEW//8AOv/sBVYGZwImAEMAAAAGAaM41QAA////1QAABLcHpQImACMAAAAHAaIA+gEl//8AOv/sA/8GZAImAEMAAAAGAaJC5AAA////1QAABZ4H2wImACMAAAAHAaEA9QEN//8AOv/sBOYGmgImAEMAAAAGAaE9zAAA////1QAABLYH5QImACMAAAAHAaAA9gET//8AOv/sA/4GpAImAEMAAAAGAaA+0gAA////1f6xBI0HRgImACMAAAAnAJoBBgFdAAcAqASsAAD//wA6/rED9wYEAiYAQwAAACYAmk4bAAcAqAQFAAAAAP///9UAAASqB90CJgAjAAAABwGfASkBVP//ADr/7AP3BpsCJgBDAAAABgGfcRIAAP///9UAAATOB+ACJgAjAAAABwGkAS8BZ///ADr/7AQWBp4CJgBDAAAABgGkdyUAAP///9UAAASVCEsCJgAjAAAABwGeASkBSf//ADr/7AP3BwkCJgBDAAAABgGecQcAAP///9UAAATMCB8CJgAjAAAABwGdASsBUf//ADr/7AQUBt0CJgBDAAAABgGdcw8AAP///9X+sQSwB0wCJgAjAAAAJwCcAWEBnAAHAKgErAAA//8AOv6xA/gGCgImAEMAAAAnAJwAqQBaAAcAqAQFAAD//wBY/rsE8gWwAiYAJwAAAAcAqAR3AAr//wBH/rED6wROAiYARwAAAAcAqARRAAD//wBYAAAE8gfGAiYAJwAAAAcApgSxAVP//wBH/+wD6waFAiYARwAAAAcApgQLABL//wBYAAAE8gdRAiYAJwAAAAcAoADxAWD//wBH/+wD+gYQAiYARwAAAAYAoEsfAAD//wBYAAAF2geoAiYAJwAAAAcBowC8ARb//wBH/+wFNAZoAiYARwAAAAYBoxbWAAD//wBYAAAE8gelAiYAJwAAAAcBogDGASX//wBH/+wD6wZlAiYARwAAAAYBoiDlAAD//wBYAAAFagfbAiYAJwAAAAcBoQDBAQ3//wBH/+wExAabAiYARwAAAAYBoRvNAAD//wBYAAAE8gflAiYAJwAAAAcBoADCARP//wBH/+wD6walAiYARwAAAAYBoBzTAAD//wBY/rsE8gdGAiYAJwAAACcAmgDSAV0ABwCoBHcACv//AEf+sQPrBgUCJgBHAAAAJgCaLBwABwCoBFEAAAAA//8AYgAAAwoHxgImACsAAAAHAKYDdQFT//8APgAAAqMGcAImAIoAAAAHAKYDDv/9//8AF/65AjoFsAImACsAAAAHAKgDOwAI////+v67AjEGGAImAEsAAAAHAKgDHgAK//8AXv6pBTYFxQAmADEAAAAHAKgEw//4//8ARv6oBBwETgImAFEAAAAHAKgEV//3//8AXv/rBTYH2wAmADEAAAAHAKYFBgFo//8ARv/sBBwGhAImAFEAAAAHAKYEIQAR//8AXv/rBi8HvQAmADEAAAAHAaMBEQEr//8ARv/sBUoGZwImAFEAAAAGAaMs1QAA//8AXv/rBTYHugAmADEAAAAHAaIBGwE6//8ARv/sBBwGZAImAFEAAAAGAaI25AAA//8AXv/rBb8H8AAmADEAAAAHAaEBFgEi//8ARv/sBNoGmgImAFEAAAAGAaExzAAA//8AXv/rBTYH+gAmADEAAAAHAaABFwEo//8ARv/sBBwGpAImAFEAAAAGAaAy0gAA//8AXv6pBTYHWwAmADEAAAAnAJoBJwFyAAcAqATD//j//wBG/qgEHAYEAiYAUQAAACYAmkIbAAcAqARX//cAAP//AFn/6wYlBw8CJgCUAAAABwBzAiQBSf//AEb/7AUJBd0CJgCVAAAABwBzAXgAF///AFn/6wYlBxICJgCUAAAABwBCAXgBTf//AEb/7AUJBeACJgCVAAAABwBCAMwAG///AFn/6wYlB7YCJgCUAAAABwCmBPIBQ///AEb/7AUJBoQCJgCVAAAABwCmBEYAEf//AFn/6wYlB0ECJgCUAAAABwCgATIBUP//AEb/7AUJBg8CJgCVAAAABwCgAIYAHv//AFn+sQYlBjYCJgCUAAAABwCoBLEAAP//AEb+qAUJBLACJgCVAAAABwCoBEj/9///AGf+qgVXBbACJgA3AAAABwCoBLL/+f//AFr+sQQ7BDoCJgBXAAAABwCoBAsAAP//AGf/6wVXB8YCJgA3AAAABwCmBPEBU///AFr/7AQ7BnACJgBXAAAABwCmBED//f//AGf/6walBx8CJgCWAAAABwBzAiIBWf//AFr/7AVXBcgCJgCXAAAABwBzAXIAAv//AGf/6walByICJgCWAAAABwBCAXYBXf//AFr/7AVXBcsCJgCXAAAABwBCAMYABv//AGf/6walB8YCJgCWAAAABwCmBPABU///AFr/7AVXBnACJgCXAAAABwCmBED//f//AGf/6walB1ECJgCWAAAABwCgATABYP//AFr/7AVXBfoCJgCXAAAABwCgAIAACf//AGf+qQalBg0CJgCWAAAABwCoBLH/+P//AFr+sQVXBJECJgCXAAAABwCoBAsAAP//AO7+uwVTBbACJgA7AAAABwCoBH0ACv///7z+FAQqBDoCJgBbAAAABwCoBKj/Y///AO4AAAVTB8QCJgA7AAAABwCmBLcBUf///7z+SwQqBnACJgBbAAAABwCmBAP//f//AO4AAAVTB08CJgA7AAAABwCgAPcBXv///7z+SwQqBfoCJgBbAAAABgCgQwkAAAACAET/6wUmBhgAGgAoAAABIwMjNycOASMiAj8BGgEzMhYXEyM3MzczBzMBBhYzMjY3Ey4BIyIGBwUItPedCQM8kFiwri8EOO7BWIcrN+oe6SS1JLX8AyRhiUx1M2Uba1R8nyYE0vsuaAI/QAE06hUBHAEUSEUBEZWxsfyis9FTTwH6RE/ZvQD//wAT/u4FJgYYACYARgAAACcB0wH8AkYABgBBfYMAAP//AD7+mQU1BbAAJgAtAAAABwGcA/QAAP//AED+mQRhBDoCJgDsAAAABwGcAxMAAP//AFj+mQV5BbACJgAqAAAABwGcBBwAAP//AED+mQRGBDoCJgDvAAAABwGcAzQAAP//AOz+mQULBbACJgA2AAAABwGcAggAAP//AJD+mQP3BDoCJgDxAAAABwGcAZgAAP////z+mQUdBbACJgA6AAAABwGcA5YAAP///+n+mQPxBDoCJgBaAAAABwGcAq4AAP//ANH+mQVIBbACJgDcAAAABwGcA+sAAP//AH/+mQQGBDsCJgD0AAAABwGcAvMAAP//ANH+mQVIBbACJgDcAAAABwGcAt8AAP//AH/+mQQGBDsCJgD0AAAABwGcAeYAAP//AFf+mQS5BbACJgCsAAAABwGcANMAAP//AD7+mQOVBDoCJgDnAAAABwGcAJsAAP///8r+mQddBbACJgDVAAAABwGcBeEAAP///8P+mQYBBDoCJgDpAAAABwGcBKoAAP//AK7+VAXuBcMCJgE7AAAABwGcAsn/u///ACX+WARRBE4CJgE8AAAABwGcAdL/v///ADUAAAQZBhgCBgBKAAAAAgBIAAAEkgWwABIAGwAAASMHITIWBwYEIyETIzczNzMHMwEDITI2NzYmIwKv1TEBTs/MJyv+7eH9/NzIHsgptinV/r5vAU6DsBkZZ48EUPjmwtTcBFCVy8v93v3So3qAkQAAAAIASAAABJIFsAASABsAAAEjByEyFgcGBCMhEyM3MzczBzMBAyEyNjc2JiMCr9UxAU7PzCcr/u3h/fzcyB7IKbYp1f6+bwFOg7AZGWePBFD45sLU3ARQlcvL/d790qN6gJEAAAABADQAAAS5BbAADQAAASMDIxMjNzMTIQchAzMCh/KItoirHqt9Az8e/Xdf8gKs/VQCrJUCb5b+JwAAAAABAAoAAAOVBDoADQAAASEDIxMjNzMTIQchAyECXf72X7Zfkx6TWwJ/Hv43PQEKAd/+IQHflQHGl/7RAAABAFIAAAVJBbAAFAAAASMDIxMjNzM3MwczByMDMwEzCQEjAhaJhLfnrB6sHrce8B7wRJQCI+b9awGEzwKV/WsEhZWWlpX+rwJ8/Sj9KAAAAAEASgAABDwGGAAUAAABIwMjEyM3MzczBzMHIwMzATMJASMB3HhktvPGHsYntifXHtdxdgFu1v5DARbWAfb+CgTBlcLClf3MAa3+E/2zAAD//wBY/ooFegdMAiYA1wAAACcAnAGOAZwABwAOBCz/vv//AED+igRHBfUCJgDrAAAAJwCcAMgARQAHAA4DRP++//8AWP6KBXkFsAImACoAAAAHAA4EK/++//8AQP6KBEYEOgImAO8AAAAHAA4DQ/++//8AWP6KBrMFsAImAC8AAAAHAA4FZf++//8AQP6KBX8EOgImAO4AAAAHAA4EfP++////3v6KBXEFsAImANgAAAAHAA4EI/++////1f6KBEkEOgImAO0AAAAHAA4DRv++AAEA7gAABVMFsAAQAAAJATMBMwcjBwMjEycjNzMDMwKNAffP/dpyHr0JZ7RqAdsekO7QAs0C4/z2lQ39/AIQAZUDCgAAAQBt/mAEJgQ6ABEAAAUjAyMTIzczAzMTFzM3ATMBMwLA0lG2Ucses4u5VwEDJAGCuf3/uQz+bAGUlQOx/QBTUwMA/E8AAAAAAf/8AAAFHQWwABEAAAEjASMDASMBIzczATMTATMBMwO0nQEm1+v+XdwB/Jcehf7r2d8Bm9v+HpcCnv1iAkj9uAKelQJ9/cMCPf2DAAH/6QAAA/EEOgARAAABIxMjAwEjASM3MwMzEwEzATMDDpva0J7+3dMBdaMek8zRlQEY0/6klwHh/h8Bnv5iAeGVAcT+bQGT/jwAAP//ACn/7QP9BEwCBgC6AAD////8AAAE+QWwAiYAKAAAAAcB0/9D/n7//wEAAowGCQMhAEYBhrUAZmZAAAACAE8AAAIoBbAAAwAHAAABIxMzASM3MwFltsO2/t22KLYB3gPS+lDIAAAAAAAAAAAAAAAAAAAcAFQAmgD6AVgBagGQAbYB2AH0AgoCGAIkAjICaAJ6AqgC7AMQA0YDjAOsA/oEQARMBFgEdASKBKYE2gVOBWwFqAXcBggGJAY+BnYGkAaeBrwG2gbsBxQHLgdkB4wHyggICEYIXAiACJoIxgjmCP4JFgksCToJUAloCXYJhAnKCgIKMgpqCqAKyAsQCzgLTAtyC5ALngvcDAIMNAxsDKQMxA0ADSoNUA1oDZQNsg3cDfQOLA46DnAOnA6wDugPIA9wD54PtBAgEDQQkhDYEOQQ+hFoEXYRoBHCEfASMBI+EmoShBKSErASwhLyEv4TEBMiEzQTaBOUE7QUChQ0FHYU2hUsFUgVmBXWFgQWEBYuFk4WahaaFtIXFhdwF44XyBgMGEwYfBiuGM4ZBBkaGTAZTBlaGYQZqBnKGeIaChoYGiYaMBpQGmYadBqCGpwapBq4GtAbDhskG0AbVht2G7ob6hwyHHocxBzgHTAdcB2sHdIeEB4wHmYeuB7kHxwfVh+OH7Qf3iAgIFggniDgIRwhaCGaIdQiECJGInIikCK+IuwjGiNcI3gjnCPEJAokJiRMJGwkkiS+JO4lFiVQJZIlviYIJkImVCaAJqwm8CcMJyonTCdsJ4YnmiewKBIoLihSKG4okCi6KOgpDilCKX4prCn0KiYqYCqUKsYq4isaK1IrhCvILAIsJCxKLHosrCzuLSYtdC24Lg4uZC6iLtgu/C8kL2ovrDAYMIIwyDEOMTwxaDGSMaYxxjHYMeoylDLuMyAzUDOQM6gzwDPqNBQ0PjRmNIg0qjTKNOg1FjVCNaA1+jYcNjw2ajaWNrw3AjdCN243mjfIN/Q4MDhiOJY4pji2ON45GjlyObw6BjpOOpg61jsSO0o7gDu8O/Y8JjxWPJ48njyePJ48njyePJ48njyePJ48njyePJ48qDyyPL481DzsPQI9Dj0aPSY9TD1oPZA9rD24Pcg+UD5mPn4+jD6uPtY/Fj9gP6RABEBGQJJAvkD2QQhBGkEsQT5BfEGSQbJBwEHcQjhCaELAQuhC+EMIQyxDOkNQQ2ZDlEOURIpE1EUIRSpFYEWARZ5FwkXQRgZGOkZcRopGtEbQRuxHDkceRzxHdEekR8pH5kf+SDJITEhYSHZIlEimSMhI4kkUSU5JiknISd5KAkoaSkJKYEp4SpBKwkrUSwBLQEtiS5BL1EvyTEBMhEyWTMRNBE0WTUpNjE2oTfZOOE5oTnZOqE7KTw5PMk9oT7BQKlBKUIpQ2FEUUWJRjFHSUgBSIFJAUl5SfFLCUuhS8FL4UwBTNlNsU55TvlPyU/5UClQWVCJULlQ6VEZUUlReVGpUdlSCVI5UmlSmVLJUvlTKVNZU4lTuVPpVBlUSVR5VKlU2VUJVTlVaVWZVclV+VYpVllWiVa5VulXGVdJV3lXqVfZWAlYOVhpWJlYyVj5WSlZWVmJWblZ6VoZWklaeVqpWtlbuV1BXXFdoV3RXgFeMV5hXpFewV7xXyFfUV+BX7Ff4WARYEFhKWJxYqFi0WMBYzFjYWORY8Fj8WQhZFFkgWSxZOFlEWVBZXFloWXRZgFmMWZhZpFmwWbxZyFnUWeBZ7Fn4WgRaEFocWihaNFpAWkxaWFpkWnBafFqIWpRaoFqsWrhaxFrQWtxa6Fr0WwBbDFsYWyRbMFs8W0hbVFtgW2xbeFuEW5BbnFuoW7RbwFvMW9hb5FvwW/xcCFwUXCBcLFw4XERcUFxcXKBc4FzsXPhdBF0QXRxdKF00XUBdTF1YXWRdcF18XYhdlF2gXaxduF3EXdBd3F3oXfReAF4MXhheJF4wXjxeSF5UXmBebF54XoRekF6cXqhetF7AXsxe2F7kXvBe/F8IXxRfTF9YX2RfcF98X4hflF+gX6xf5l/yX/5gCmAWYCJgLmA6YEZgUmBeYGpgdmCCYI5gmmCmYLJgvmDKYNZg4mDuYPphBmESYR5hKmE2YUJhTmFaYWZhcmF+YYphlmGiYeZh8mH+YgpiFmIiYi5iOmJGYlJiXmJqYnZigmKOYppiomKqYrJiumLCYspi0mLaYuJi6mLyYvpjAmMKYxZjImMuYzpjRmNSY15jZmNuY3ZjfmOGY5JjnmOqY7ZjwmPOY9pkGGQgZCxkNGQ8ZEhkVGRcZGRkbGR0ZIBkiGSQZJhkoGSoZLBkuGTAZMhk0GTcZORk7GUcZSRlLGU4ZURlTGVUZWBlaGV0ZYBljGWYZaRlsGW8Zchl1GXgZehl8GX8ZghmFGYcZihmNGZAZkxmWGZkZnRmgGaMZphmpGasZrRmwGbMZthm5GbwZvxnCGcUZxxnJGcsZzhnRGdMZ1hnZGdwZ3xnhGeMZ5hnpGewZ7hnxGfQZ9xn6Gf0aABoDGgYaCRoMGg8aERoTGhYaGRocGh8aIholGigaKxouGjEaNBo3GjsaPxpCGkUaRxpKGk0aUBpTGlYaWRpcGl8aYhplGmgaaxpuGnEadRp5GnwafxqCGoUaiBqLGo4akRqVGpkanBqfGqIapRqoGqsarhqxGrQatxq6Gr0awBrDGscayxrOGtEa1BrXGtoa3RrgGuMa5hrpGuwa7xryGvUa+Br7Gv8bAxsGGwkbDBsPGxIbFRsYGxsbHhshGyQbJxsqGy0bMBszGzYbORs8Gz8bQhtFG0gbSxtOG1EbVBtXG1obXRtuG3IbdRt4G3sbfhuBG4QbhxuKG40bkBuTG5YbmRucG58bohulG6gbqhu2m8MbypvSG9wb5hvqG+4b8Rv0G/cb+hv9HAAcCJwRnBscJJwmnCmcLBwsHCwcMYAAAAbAUoAAQAAAAAAAAAfAAAAAQAAAAAAAQAGAB8AAQAAAAAAAgAGACUAAQAAAAAAAwASACsAAQAAAAAABAANAD0AAQAAAAAABQAWAEoAAQAAAAAABgANAGAAAQAAAAAABwAgAG0AAQAAAAAACQAGAI0AAQAAAAAACwAKAJMAAQAAAAAADAATAJ0AAQAAAAAADQAuALAAAQAAAAAADgAqAN4AAQAAAAAAEgANAQgAAwABBAkAAAA+ARUAAwABBAkAAQAMAVMAAwABBAkAAgAMAV8AAwABBAkAAwAkAWsAAwABBAkABAAaAY8AAwABBAkABQAsAakAAwABBAkABgAaAdUAAwABBAkABwBAAe8AAwABBAkACQAMAi8AAwABBAkACwAUAjsAAwABBAkADAAmAk8AAwABBAkADQBcAnUAAwABBAkADgBUAtFGb250IGRhdGEgY29weXJpZ2h0IEdvb2dsZSAyMDEzUm9ib3RvSXRhbGljR29vZ2xlOlJvYm90bzoyMDEzUm9ib3RvIEl0YWxpY1ZlcnNpb24gMS4yMDAzMTA7IDIwMTNSb2JvdG8tSXRhbGljUm9ib3RvIGlzIGEgdHJhZGVtYXJrIG9mIEdvb2dsZS5Hb29nbGVHb29nbGUuY29tQ2hyaXN0aWFuIFJvYmVydHNvbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBSb2JvdG8gSXRhbGljAEYAbwBuAHQAIABkAGEAdABhACAAYwBvAHAAeQByAGkAZwBoAHQAIABHAG8AbwBnAGwAZQAgADIAMAAxADMAUgBvAGIAbwB0AG8ASQB0AGEAbABpAGMARwBvAG8AZwBsAGUAOgBSAG8AYgBvAHQAbwA6ADIAMAAxADMAUgBvAGIAbwB0AG8AIABJAHQAYQBsAGkAYwBWAGUAcgBzAGkAbwBuACAAMQAuADIAMAAwADMAMQAwADsAIAAyADAAMQAzAFIAbwBiAG8AdABvAC0ASQB0AGEAbABpAGMAUgBvAGIAbwB0AG8AIABpAHMAIABhACAAdAByAGEAZABlAG0AYQByAGsAIABvAGYAIABHAG8AbwBnAGwAZQAuAEcAbwBvAGcAbABlAEcAbwBvAGcAbABlAC4AYwBvAG0AQwBoAHIAaQBzAHQAaQBhAG4AIABSAG8AYgBlAHIAdABzAG8AbgBMAGkAYwBlAG4AcwBlAGQAIAB1AG4AZABlAHIAIAB0AGgAZQAgAEEAcABhAGMAaABlACAATABpAGMAZQBuAHMAZQAsACAAVgBlAHIAcwBpAG8AbgAgADIALgAwAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBhAHAAYQBjAGgAZQAuAG8AcgBnAC8AbABpAGMAZQBuAHMAZQBzAC8ATABJAEMARQBOAFMARQAtADIALgAwAAACAAAAAAAA/2oAZAAAAAAAAAAAAAAAAAAAAAAAAAAABB0AAAECAAIAAwAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAYQCjAIQAhQC9AJYA6ACGAI4AiwCdAKkApACKAQMAgwCTAPIA8wCNAJcAiAEEAN4A8QCeAKoA9QD0APYAogCQAPAAkQDtAIkAoADqALgAoQDuAQUA1wEGAOIA4wEHAQgAsACxAQkApgEKAQsBDAENAQ4BDwDYAOEA2wDcAN0A4ADZAN8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgCfASMBJAElASYBJwEoASkBKgErASwBLQCbAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0AsgCzAc4AtgC3AMQBzwC0ALUAxQCCAMIAhwHQAKsAxgC+AL8AvAHRAdIB0wHUAdUB1gHXAdgAjAHZAdoB2wHcAd0AmACaAJkA7wClAJIAnACnAI8AlACVALkB3gHfAeAAwAHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgILAgwCDQIOAg8CEAIRAhICEwIUAhUCFgIXAhgCGQIaAhsCHAIdAh4CHwIgAiECIgIjAiQCJQImAicCKAIpAioCKwIsAi0CLgIvAjACMQIyAjMCNAI1AjYCNwCsAjgCOQDpAjoCOwI8AK0AyQDHAK4AYgBjAj0AZADLAGUAyADKAM8AzADNAM4AZgDTANAA0QCvAGcA1gDUANUAaADrAGoAaQBrAG0AbABuAj4AbwBxAHAAcgBzAHUAdAB2AHcAeAB6AHkAewB9AHwAfwB+AIAAgQDsALoCPwJAAkECQgJDAkQA/QD+AkUCRgJHAkgA/wEAAkkCSgJLAkwCTQJOAk8CUAJRAlICUwJUAlUCVgD4APkCVwJYAlkCWgJbAlwCXQJeAl8CYAJhAmICYwJkAmUCZgJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfgJ/AoACgQKCAoMChAKFAoYChwKIAokCigD7APwCiwKMAOQA5QKNAo4CjwKQApECkgKTApQClQKWApcCmAKZApoCmwKcAp0CngKfAqACoQKiALsCowKkAqUCpgDmAOcCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CvwLAAsECwgLDAsQCxQLGAscCyALJAsoCywLMAs0CzgLPAtAC0QLSAtMC1ALVAtYC1wLYAtkC2gLbAtwC3QLeAt8C4ALhAuIC4wLkAuUC5gLnAugC6QLqAusC7ALtAu4C7wLwAvEC8gLzAvQC9QL2AvcC+AL5AvoC+wL8Av0C/gL/AwADAQMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMvAzADMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTANNA04DTwNQA1EDUgNTA1QDVQNWA1cDWANZA1oDWwNcA10DXgNfA2ADYQNiA2MDZANlA2YDZwNoA2kDagNrA2wDbQNuA28DcANxA3IDcwN0A3UDdgN3A3gDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgOPA5ADkQOSA5MDlAOVA5YDlwOYA5kDmgObA5wDnQOeA58DoAOhA6IDowOkA6UDpgOnA6gDqQOqA6sDrAOtA64DrwOwA7EDsgOzA7QDtQO2A7cDuAO5A7oDuwO8A70DvgO/A8ADwQPCA8MDxAPFA8YDxwPIA8kDygPLA8wDzQPOA88D0APRA9ID0wPUA9UD1gPXA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6APpA+oD6wPsA+0D7gPvA/AD8QPyA/MD9AP1A/YD9wP4A/kD+gP7A/wD/QP+A/8EAAQBBAIEAwQEBAUEBgQHBAgECQQKBAsEDAQNBA4EDwQQBBEEEgQTBBQEFQQWBBcEGAQZBBoEGwQcBB0EHgQfBCAEIQD3BCIEIwQkAAQETlVMTAZtYWNyb24OcGVyaW9kY2VudGVyZWQESGJhcgxrZ3JlZW5sYW5kaWMDRW5nA2VuZwVsb25ncwVPaG9ybgVvaG9ybgVVaG9ybgV1aG9ybgd1bmkwMjM3BXNjaHdhB3VuaTAyRjMJZ3JhdmVjb21iCWFjdXRlY29tYgl0aWxkZWNvbWIEaG9vawd1bmkwMzBGCGRvdGJlbG93BXRvbm9zDWRpZXJlc2lzdG9ub3MJYW5vdGVsZWlhBUdhbW1hBURlbHRhBVRoZXRhBkxhbWJkYQJYaQJQaQVTaWdtYQNQaGkDUHNpBWFscGhhBGJldGEFZ2FtbWEFZGVsdGEHZXBzaWxvbgR6ZXRhA2V0YQV0aGV0YQRpb3RhBmxhbWJkYQJ4aQNyaG8Gc2lnbWExBXNpZ21hA3RhdQd1cHNpbG9uA3BoaQNwc2kFb21lZ2EHdW5pMDNEMQd1bmkwM0QyB3VuaTAzRDYHdW5pMDQwMgd1bmkwNDA0B3VuaTA0MDkHdW5pMDQwQQd1bmkwNDBCB3VuaTA0MEYHdW5pMDQxMQd1bmkwNDE0B3VuaTA0MTYHdW5pMDQxNwd1bmkwNDE4B3VuaTA0MUIHdW5pMDQyMwd1bmkwNDI0B3VuaTA0MjYHdW5pMDQyNwd1bmkwNDI4B3VuaTA0MjkHdW5pMDQyQQd1bmkwNDJCB3VuaTA0MkMHdW5pMDQyRAd1bmkwNDJFB3VuaTA0MkYHdW5pMDQzMQd1bmkwNDMyB3VuaTA0MzMHdW5pMDQzNAd1bmkwNDM2B3VuaTA0MzcHdW5pMDQzOAd1bmkwNDNBB3VuaTA0M0IHdW5pMDQzQwd1bmkwNDNEB3VuaTA0M0YHdW5pMDQ0Mgd1bmkwNDQ0B3VuaTA0NDYHdW5pMDQ0Nwd1bmkwNDQ4B3VuaTA0NDkHdW5pMDQ0QQd1bmkwNDRCB3VuaTA0NEMHdW5pMDQ0RAd1bmkwNDRFB3VuaTA0NEYHdW5pMDQ1Mgd1bmkwNDU0B3VuaTA0NTkHdW5pMDQ1QQd1bmkwNDVCB3VuaTA0NUYHdW5pMDQ2MAd1bmkwNDYxB3VuaTA0NjMHdW5pMDQ2NAd1bmkwNDY1B3VuaTA0NjYHdW5pMDQ2Nwd1bmkwNDY4B3VuaTA0NjkHdW5pMDQ2QQd1bmkwNDZCB3VuaTA0NkMHdW5pMDQ2RAd1bmkwNDZFB3VuaTA0NkYHdW5pMDQ3Mgd1bmkwNDczB3VuaTA0NzQHdW5pMDQ3NQd1bmkwNDdBB3VuaTA0N0IHdW5pMDQ3Qwd1bmkwNDdEB3VuaTA0N0UHdW5pMDQ3Rgd1bmkwNDgwB3VuaTA0ODEHdW5pMDQ4Mgd1bmkwNDgzB3VuaTA0ODQHdW5pMDQ4NQd1bmkwNDg2B3VuaTA0ODgHdW5pMDQ4OQd1bmkwNDhEB3VuaTA0OEUHdW5pMDQ4Rgd1bmkwNDkwB3VuaTA0OTEHdW5pMDQ5NAd1bmkwNDk1B3VuaTA0OUMHdW5pMDQ5RAd1bmkwNEEwB3VuaTA0QTEHdW5pMDRBNAd1bmkwNEE1B3VuaTA0QTYHdW5pMDRBNwd1bmkwNEE4B3VuaTA0QTkHdW5pMDRCNAd1bmkwNEI1B3VuaTA0QjgHdW5pMDRCOQd1bmkwNEJBB3VuaTA0QkMHdW5pMDRCRAd1bmkwNEMzB3VuaTA0QzQHdW5pMDRDNwd1bmkwNEM4B3VuaTA0RDgHdW5pMDRFMAd1bmkwNEUxB3VuaTA0RkEHdW5pMDRGQgd1bmkwNTAwB3VuaTA1MDIHdW5pMDUwMwd1bmkwNTA0B3VuaTA1MDUHdW5pMDUwNgd1bmkwNTA3B3VuaTA1MDgHdW5pMDUwOQd1bmkwNTBBB3VuaTA1MEIHdW5pMDUwQwd1bmkwNTBEB3VuaTA1MEUHdW5pMDUwRgd1bmkwNTEwB3VuaTIwMDAHdW5pMjAwMQd1bmkyMDAyB3VuaTIwMDMHdW5pMjAwNAd1bmkyMDA1B3VuaTIwMDYHdW5pMjAwNwd1bmkyMDA4B3VuaTIwMDkHdW5pMjAwQQd1bmkyMDBCDXVuZGVyc2NvcmVkYmwNcXVvdGVyZXZlcnNlZAd1bmkyMDI1B3VuaTIwNzQJbnN1cGVyaW9yBGxpcmEGcGVzZXRhBEV1cm8HdW5pMjEwNQd1bmkyMTEzB3VuaTIxMTYJZXN0aW1hdGVkCW9uZWVpZ2h0aAx0aHJlZWVpZ2h0aHMLZml2ZWVpZ2h0aHMMc2V2ZW5laWdodGhzCmNvbG9uLmxudW0JcXVvdGVkYmx4C2NvbW1hYWNjZW50B3VuaUZFRkYHdW5pRkZGQwd1bmlGRkZECWZpdmUuc21jcAhmb3VyLnN1cAl6ZXJvLmxudW0ObGFyZ2VyaWdodGhvb2sMY3lyaWxsaWNob29rEGN5cmlsbGljaG9va2xlZnQLY3lyaWxsaWN0aWMOYnJldmV0aWxkZWNvbWINYnJldmVob29rY29tYg5icmV2ZWFjdXRlY29tYhNjaXJjdW1mbGV4dGlsZGVjb21iEmNpcmN1bWZsZXhob29rY29tYhNjaXJjdW1mbGV4Z3JhdmVjb21iE2NpcmN1bWZsZXhhY3V0ZWNvbWIOYnJldmVncmF2ZWNvbWIRY29tbWFhY2NlbnRyb3RhdGUGQS5zbWNwBkIuc21jcAZDLnNtY3AGRC5zbWNwBkUuc21jcAZGLnNtY3AGRy5zbWNwBkguc21jcAZJLnNtY3AGSi5zbWNwBksuc21jcAZMLnNtY3AGTS5zbWNwBk4uc21jcAZPLnNtY3AGUS5zbWNwBlIuc21jcAZTLnNtY3AGVC5zbWNwBlUuc21jcAZWLnNtY3AGVy5zbWNwBlguc21jcAZZLnNtY3AGWi5zbWNwCXplcm8uc21jcAhvbmUuc21jcAh0d28uc21jcAp0aHJlZS5zbWNwCWZvdXIuc21jcAh0d28ubG51bQhzaXguc21jcApzZXZlbi5zbWNwCmVpZ2h0LnNtY3AJbmluZS5zbWNwB29uZS5zdXAHdHdvLnN1cAl0aHJlZS5zdXAIb25lLmxudW0IZml2ZS5zdXAHc2l4LnN1cAlzZXZlbi5zdXAJZWlnaHQuc3VwCG5pbmUuc3VwCHplcm8uc3VwCGNyb3NzYmFyCXJpbmdhY3V0ZQlkYXNpYW94aWEKdGhyZWUubG51bQlmb3VyLmxudW0JZml2ZS5sbnVtCHNpeC5sbnVtBWcuYWx0CnNldmVuLmxudW0HY2hpLmFsdAplaWdodC5sbnVtCWFscGhhLmFsdAlkZWx0YS5hbHQERC5jbgRhLmNuBVIuYWx0BUsuYWx0BWsuYWx0BksuYWx0MgZrLmFsdDIJbmluZS5sbnVtBlAuc21jcA1jeXJpbGxpY2JyZXZlB3VuaTAwQUQGRGNyb2F0BGhiYXIEVGJhcgR0YmFyCkFyaW5nYWN1dGUKYXJpbmdhY3V0ZQdBbWFjcm9uB2FtYWNyb24GQWJyZXZlBmFicmV2ZQdBb2dvbmVrB2FvZ29uZWsLQ2NpcmN1bWZsZXgLY2NpcmN1bWZsZXgHdW5pMDEwQQd1bmkwMTBCBkRjYXJvbgZkY2Fyb24HRW1hY3JvbgdlbWFjcm9uBkVicmV2ZQZlYnJldmUKRWRvdGFjY2VudAplZG90YWNjZW50B0VvZ29uZWsHZW9nb25lawZFY2Fyb24GZWNhcm9uC0djaXJjdW1mbGV4C2djaXJjdW1mbGV4B3VuaTAxMjAHdW5pMDEyMQxHY29tbWFhY2NlbnQMZ2NvbW1hYWNjZW50C0hjaXJjdW1mbGV4C2hjaXJjdW1mbGV4Bkl0aWxkZQZpdGlsZGUHSW1hY3JvbgdpbWFjcm9uBklicmV2ZQZpYnJldmUHSW9nb25lawdpb2dvbmVrCklkb3RhY2NlbnQCSUoCaWoLSmNpcmN1bWZsZXgLamNpcmN1bWZsZXgMS2NvbW1hYWNjZW50DGtjb21tYWFjY2VudAZMYWN1dGUGbGFjdXRlDExjb21tYWFjY2VudAxsY29tbWFhY2NlbnQGTGNhcm9uBmxjYXJvbgRMZG90BGxkb3QGTmFjdXRlBm5hY3V0ZQxOY29tbWFhY2NlbnQMbmNvbW1hYWNjZW50Bk5jYXJvbgZuY2Fyb24LbmFwb3N0cm9waGUHT21hY3JvbgdvbWFjcm9uBk9icmV2ZQZvYnJldmUNT2h1bmdhcnVtbGF1dA1vaHVuZ2FydW1sYXV0BlJhY3V0ZQZyYWN1dGUMUmNvbW1hYWNjZW50DHJjb21tYWFjY2VudAZSY2Fyb24GcmNhcm9uBlNhY3V0ZQZzYWN1dGULU2NpcmN1bWZsZXgLc2NpcmN1bWZsZXgHdW5pMDIxOAd1bmkwMjE5B3VuaTAyMUEHdW5pMDIxQgd1bmkwMTYyB3VuaTAxNjMGVGNhcm9uBnRjYXJvbgZVdGlsZGUGdXRpbGRlB1VtYWNyb24HdW1hY3JvbgZVYnJldmUGdWJyZXZlBVVyaW5nBXVyaW5nDVVodW5nYXJ1bWxhdXQNdWh1bmdhcnVtbGF1dAdVb2dvbmVrB3VvZ29uZWsLV2NpcmN1bWZsZXgLd2NpcmN1bWZsZXgLWWNpcmN1bWZsZXgLeWNpcmN1bWZsZXgGWmFjdXRlBnphY3V0ZQpaZG90YWNjZW50Cnpkb3RhY2NlbnQHQUVhY3V0ZQdhZWFjdXRlC09zbGFzaGFjdXRlC29zbGFzaGFjdXRlC0Rjcm9hdC5zbWNwCEV0aC5zbWNwCVRiYXIuc21jcAtBZ3JhdmUuc21jcAtBYWN1dGUuc21jcBBBY2lyY3VtZmxleC5zbWNwC0F0aWxkZS5zbWNwDkFkaWVyZXNpcy5zbWNwCkFyaW5nLnNtY3APQXJpbmdhY3V0ZS5zbWNwDUNjZWRpbGxhLnNtY3ALRWdyYXZlLnNtY3ALRWFjdXRlLnNtY3AQRWNpcmN1bWZsZXguc21jcA5FZGllcmVzaXMuc21jcAtJZ3JhdmUuc21jcAtJYWN1dGUuc21jcBBJY2lyY3VtZmxleC5zbWNwDklkaWVyZXNpcy5zbWNwC050aWxkZS5zbWNwC09ncmF2ZS5zbWNwC09hY3V0ZS5zbWNwEE9jaXJjdW1mbGV4LnNtY3ALT3RpbGRlLnNtY3AOT2RpZXJlc2lzLnNtY3ALVWdyYXZlLnNtY3ALVWFjdXRlLnNtY3AQVWNpcmN1bWZsZXguc21jcA5VZGllcmVzaXMuc21jcAtZYWN1dGUuc21jcAxBbWFjcm9uLnNtY3ALQWJyZXZlLnNtY3AMQW9nb25lay5zbWNwC0NhY3V0ZS5zbWNwEENjaXJjdW1mbGV4LnNtY3AMdW5pMDEwQS5zbWNwC0NjYXJvbi5zbWNwC0RjYXJvbi5zbWNwDEVtYWNyb24uc21jcAtFYnJldmUuc21jcA9FZG90YWNjZW50LnNtY3AMRW9nb25lay5zbWNwC0VjYXJvbi5zbWNwEEdjaXJjdW1mbGV4LnNtY3ALR2JyZXZlLnNtY3AMdW5pMDEyMC5zbWNwEUdjb21tYWFjY2VudC5zbWNwEEhjaXJjdW1mbGV4LnNtY3ALSXRpbGRlLnNtY3AMSW1hY3Jvbi5zbWNwC0licmV2ZS5zbWNwDElvZ29uZWsuc21jcA9JZG90YWNjZW50LnNtY3AQSmNpcmN1bWZsZXguc21jcBFLY29tbWFhY2NlbnQuc21jcAtMYWN1dGUuc21jcBFMY29tbWFhY2NlbnQuc21jcAtMY2Fyb24uc21jcAlMZG90LnNtY3ALTmFjdXRlLnNtY3ARTmNvbW1hYWNjZW50LnNtY3ALTmNhcm9uLnNtY3AMT21hY3Jvbi5zbWNwC09icmV2ZS5zbWNwEk9odW5nYXJ1bWxhdXQuc21jcAtSYWN1dGUuc21jcBFSY29tbWFhY2NlbnQuc21jcAtSY2Fyb24uc21jcAtTYWN1dGUuc21jcBBTY2lyY3VtZmxleC5zbWNwDVNjZWRpbGxhLnNtY3ALU2Nhcm9uLnNtY3ARVGNvbW1hYWNjZW50LnNtY3ALVGNhcm9uLnNtY3ALVXRpbGRlLnNtY3AMVW1hY3Jvbi5zbWNwC1VicmV2ZS5zbWNwClVyaW5nLnNtY3ASVWh1bmdhcnVtbGF1dC5zbWNwDFVvZ29uZWsuc21jcBBXY2lyY3VtZmxleC5zbWNwEFljaXJjdW1mbGV4LnNtY3AOWWRpZXJlc2lzLnNtY3ALWmFjdXRlLnNtY3APWmRvdGFjY2VudC5zbWNwC1pjYXJvbi5zbWNwD2dlcm1hbmRibHMuc21jcApBbHBoYXRvbm9zDEVwc2lsb250b25vcwhFdGF0b25vcwlJb3RhdG9ub3MMT21pY3JvbnRvbm9zDFVwc2lsb250b25vcwpPbWVnYXRvbm9zEWlvdGFkaWVyZXNpc3Rvbm9zBUFscGhhBEJldGEHRXBzaWxvbgRaZXRhA0V0YQRJb3RhBUthcHBhAk11Ak51B09taWNyb24DUmhvA1RhdQdVcHNpbG9uA0NoaQxJb3RhZGllcmVzaXMPVXBzaWxvbmRpZXJlc2lzCmFscGhhdG9ub3MMZXBzaWxvbnRvbm9zCGV0YXRvbm9zCWlvdGF0b25vcxR1cHNpbG9uZGllcmVzaXN0b25vcwVrYXBwYQdvbWljcm9uB3VuaTAzQkMCbnUDY2hpDGlvdGFkaWVyZXNpcw91cHNpbG9uZGllcmVzaXMMb21pY3JvbnRvbm9zDHVwc2lsb250b25vcwpvbWVnYXRvbm9zB3VuaTA0MDEHdW5pMDQwMwd1bmkwNDA1B3VuaTA0MDYHdW5pMDQwNwd1bmkwNDA4B3VuaTA0MUEHdW5pMDQwQwd1bmkwNDBFB3VuaTA0MTAHdW5pMDQxMgd1bmkwNDEzB3VuaTA0MTUHdW5pMDQxOQd1bmkwNDFDB3VuaTA0MUQHdW5pMDQxRQd1bmkwNDFGB3VuaTA0MjAHdW5pMDQyMQd1bmkwNDIyB3VuaTA0MjUHdW5pMDQzMAd1bmkwNDM1B3VuaTA0MzkHdW5pMDQzRQd1bmkwNDQwB3VuaTA0NDEHdW5pMDQ0Mwd1bmkwNDQ1B3VuaTA0NTEHdW5pMDQ1Mwd1bmkwNDU1B3VuaTA0NTYHdW5pMDQ1Nwd1bmkwNDU4B3VuaTA0NUMHdW5pMDQ1RQZXZ3JhdmUGd2dyYXZlBldhY3V0ZQZ3YWN1dGUJV2RpZXJlc2lzCXdkaWVyZXNpcwZZZ3JhdmUGeWdyYXZlBm1pbnV0ZQZzZWNvbmQJZXhjbGFtZGJsB3VuaUZCMDIHdW5pMDFGMAd1bmkwMkJDB3VuaTFFM0UHdW5pMUUzRgd1bmkxRTAwB3VuaTFFMDEHdW5pMUY0RAd1bmlGQjAzB3VuaUZCMDQHdW5pMDQwMAd1bmkwNDBEB3VuaTA0NTAHdW5pMDQ1RAd1bmkwNDcwB3VuaTA0NzEHdW5pMDQ3Ngd1bmkwNDc3B3VuaTA0NzkHdW5pMDQ3OAd1bmkwNDk4B3VuaTA0OTkHdW5pMDRBQQd1bmkwNEFCB3VuaTA0QUUHdW5pMDRBRgd1bmkwNEMwB3VuaTA0QzEHdW5pMDRDMgd1bmkwNENGB3VuaTA0RDAHdW5pMDREMQd1bmkwNEQyB3VuaTA0RDMHdW5pMDRENAd1bmkwNEQ1B3VuaTA0RDYHdW5pMDRENwd1bmkwNERBB3VuaTA0RDkHdW5pMDREQgd1bmkwNERDB3VuaTA0REQHdW5pMDRERQd1bmkwNERGB3VuaTA0RTIHdW5pMDRFMwd1bmkwNEU0B3VuaTA0RTUHdW5pMDRFNgd1bmkwNEU3B3VuaTA0RTgHdW5pMDRFOQd1bmkwNEVBB3VuaTA0RUIHdW5pMDRFQwd1bmkwNEVEB3VuaTA0RUUHdW5pMDRFRgd1bmkwNEYwB3VuaTA0RjEHdW5pMDRGMgd1bmkwNEYzB3VuaTA0RjQHdW5pMDRGNQd1bmkwNEY4B3VuaTA0RjkHdW5pMDRGQwd1bmkwNEZEB3VuaTA1MDEHdW5pMDUxMgd1bmkwNTEzB3VuaTFFQTAHdW5pMUVBMQd1bmkxRUEyB3VuaTFFQTMHdW5pMUVBNAd1bmkxRUE1B3VuaTFFQTYHdW5pMUVBNwd1bmkxRUE4B3VuaTFFQTkHdW5pMUVBQQd1bmkxRUFCB3VuaTFFQUMHdW5pMUVBRAd1bmkxRUFFB3VuaTFFQUYHdW5pMUVCMAd1bmkxRUIxB3VuaTFFQjIHdW5pMUVCMwd1bmkxRUI0B3VuaTFFQjUHdW5pMUVCNgd1bmkxRUI3B3VuaTFFQjgHdW5pMUVCOQd1bmkxRUJBB3VuaTFFQkIHdW5pMUVCQwd1bmkxRUJEB3VuaTFFQkUHdW5pMUVCRgd1bmkxRUMwB3VuaTFFQzEHdW5pMUVDMgd1bmkxRUMzB3VuaTFFQzQHdW5pMUVDNQd1bmkxRUM2B3VuaTFFQzcHdW5pMUVDOAd1bmkxRUM5B3VuaTFFQ0EHdW5pMUVDQgd1bmkxRUNDB3VuaTFFQ0QHdW5pMUVDRQd1bmkxRUNGB3VuaTFFRDAHdW5pMUVEMQd1bmkxRUQyB3VuaTFFRDMHdW5pMUVENAd1bmkxRUQ1B3VuaTFFRDYHdW5pMUVENwd1bmkxRUQ4B3VuaTFFRDkHdW5pMUVEQQd1bmkxRURCB3VuaTFFREMHdW5pMUVERAd1bmkxRURFB3VuaTFFREYHdW5pMUVFMAd1bmkxRUUxB3VuaTFFRTIHdW5pMUVFMwd1bmkxRUU0B3VuaTFFRTUHdW5pMUVFNgd1bmkxRUU3B3VuaTFFRTgHdW5pMUVFOQd1bmkxRUVBB3VuaTFFRUIHdW5pMUVFQwd1bmkxRUVEB3VuaTFFRUUHdW5pMUVFRgd1bmkxRUYwB3VuaTFFRjEHdW5pMUVGNAd1bmkxRUY1B3VuaTFFRjYHdW5pMUVGNwd1bmkxRUY4B3VuaTFFRjkGZGNyb2F0B3VuaTIwQUIHdW5pMDQ5QQd1bmkwNDlCB3VuaTA0QTIHdW5pMDRBMwd1bmkwNEFDB3VuaTA0QUQHdW5pMDRCMgd1bmkwNEIzB3VuaTA0QjYHdW5pMDRCNwd1bmkwNENCB3VuaTA0Q0MHdW5pMDRGNgd1bmkwNEY3B3VuaTA0OTYHdW5pMDQ5Nwd1bmkwNEJFB3VuaTA0QkYHdW5pMDRCQgd1bmkwNDhDB3VuaTA0NjIHdW5pMDQ5Mgd1bmkwNDkzB3VuaTA0OUUHdW5pMDQ5Rgd1bmkwNDhBB3VuaTA0OEIHdW5pMDRDOQd1bmkwNENBB3VuaTA0Q0QHdW5pMDRDRQd1bmkwNEM1B3VuaTA0QzYHdW5pMDRCMAd1bmkwNEIxB3VuaTA0RkUHdW5pMDRGRgd1bmkwNTExB3VuaTIwMTUHdW5pMDAwMgd1bmkwMDA5AAAAAAEAAAAMAAAAAAAAAAIACADKAMoAAQEeASQAAQFWAWEAAQF2AXYAAQF7AXwAAQF+AX4AAQGTAZUAAQHVAdUAAQAAAAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAA//8AAQAAAAFrZXJuAAgAAAABAAAAAQAEAAIAAAAEAA5NaFUGc1wAAXrYAAQAAAGtA2QDagNwA3YD6APyBAQEKgRABEoEbASOBJQE4gUQBTIFVAV6BaAFpgaMBpIGuAbeB0AH0gf0CBIILAgyCEAIRghMCFIIeAiSCKAIvgjECOII/AkCCcQKNgpcCs4K1AreCuQK6grwCw4LHAtGC0wLYgt8C4ILnAuiC6gL3gvkC+4MHAxCDGgMigysDM4M/A1eDXQNlg24DgIOJA5GDngOng7EDs4O2A7yDwQPDg8oDy4PRA+SD6wPxg/cD/4QIBA6EEAQYhCEEKYRGBE+EWQRghGcEl4SaBK2EwQTDhMUExoTIBMmEywTUhNcE2ITdBOeE7QTxhPYE/4UBBQaFCQUNhRcFHIUeBR+FJgUnhTEFOoV0BZCFrQXJheYGAoYfBjuGQAZFhksGUIZWBl6GZwZvhngGgIaKBpOGnQamhrAGsYazBrSGtgbahuIG6YbxBviHAAcHhw8HEIcSBxOHFQcWhyAHKYczBzyHRgdNh1UHcYd5B5WHnQe5h8EHxYfKB86H0wfch+IH44fpB+qH8Afxh/cH+If+B/+ICAgJiBIIGogjCCuINAg1iEkIVIhgCGuIdwh/iIEIiYiLCJOIlQiWiKAIqYizCLyIxgjPiNMI1ojaCROJTQmGiYgJiYmLCYyJjgmPiZkJvYnFCemJ8gn6igMKH4olCi2KNgo/imQKgIqDCoiKkQqZiqIKtYq+CsaK0ArZixMLN4tQC1iLfQt+i4gLj4uZC56LzwvXi+AL4Yv1DAiMGww3jDoMaoxwDHiMgQyKjJQMmIzSDOqM8gzzjP0NA40LDQyNDg0QjRgNIY0rDTSNWQ1gjWINY41lDW2Nbw2LjZMNnI2iDaONrQ20jbkN3Y3lDe2OBg4HjhAOLI40DlCOWA5djl8OYI5iDnqOfA6Fjo8OmI6fDrGOuQ7LjtMO5Y7tDwWPBw8jjysPR49PD2uPcw+Pj5cPs4+7D9eP3w/7kAMQH5AnEEOQSxBnkG8Qi5CTEK+QtxC8kL4Qw5DFEMqQzBDRkNMQ2JDaEN+Q4RDmkOgQ7ZDvEPeRABEJkRMRHJEmES+RORFCkUwRVZFfEWiRchF7kYURjpGQEZGRthG9keIR6ZIOEhWSKRIxkmsSg5KFErWSuBLQktIS05LdEw2TIRMpkzIAAEAWQALAAEAWQALAAEAEf8gABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAIBDAALAVP/5gAEAAv/5gA///QAX//vATz/7QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AACAFT/5gGn/8AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAaf/6wATAFn/wQCz/8UAxf+0AOX/1wDx/7kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAan/6AGt/+YBtf/nAbb/5wALAFn/pAGnABMBqf/zAa3/8QG1//IBtv/xAbn/OwG6/9oBu/9UAbz/kQG+/z8ACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAVgAOAH//nwC//94Awv/lANT/qADo/8oBRv/jAaf/xgHf//UAAQGnAA4AOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQABAaf/6wAJAAsAFAA/ABEAVP/iAF8AEwGn/7QBqf/ZAa3/2QG1/9kBtv/ZAAkACwAPAD8ADABU/+sAXwAOAaf/ywGp/+kBrf/nAbX/5wG2/+cAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAgAWf/lALP/ywDI/+QBpwANAan/7QGt/+sBtf/sAbb/7AAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oAAEA8f/1AAMACwAUAD8AEgBfABMAAQDx/8AAAQDx/8AAAQDx/8AACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oAAMASAAPAFYAIABZABEABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAAQEX//EABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UABgDF/+oA6P/uAPH/sAEv/+wBVP/sAdz/6AABAPH/9QAwAFT/bQBZ/4wAa/2/AHr+fQB//rwAhP8rAIf/SwCz/2EAuv8PAL7+6ADB/x8Awv7lAMX/RgDH/u0AyP79AMn+2QDU/1IA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPr/EwD8/wcBAv8OAQT/EQEX/zwBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/1kB3/+PABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAAQC/AA0AAgCz/8IAvwAQAAEAv//iAAEAwv/yAAEAvwAOAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAMAxf/tAPH/wAHc/+wACgC6/+YAvf/rAL7/6QDA//AAwf/nAMX/4wDH/84AyP/UAMn/2wHf/+4AAQDx/8AABQC9/+wAvwAPAMH/6gDF/8QAx//nAAYASP/pAL3/7gC/ABAAwf/sAMX/IAHc/9oAAQC/AA8ABgDF/+oA6P/uAPH/qwEv/+wBVP/sAdz/6AABAPH/1QABAMUACwANAEgADADBAAsAxQAMAaf/vwGp/+4Brf/sAbX/7QG2/+wBuP/1AbkADgG7AA0BvgANAd//7QABAPH/2AACAPH/qgHc/+EACwDh/9QA8f/JAQT/5QEb/+MBL//EATj/4QFJ/9QBSv/1AUv/5wFT/9IBVP/JAAkA4f/DAPH/zwEv/84BOP/nATv/3wFJ/9EBS//sAVP/oAFU/9EACQDh/8MA8f/PAS//zgE4/+cBO//fAUn/0QFL/+wBU/+gAVT/0QAIAOH/yQDx/98BBP/tARv/6wEv/98BO//pAUr/9QFU/+AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA4f/mAPH/0AEv/84BOP/oAUn/5wFL/+0BU//mAVT/0AALANQAFADh/+AA6AATATj/4QE5/+ABPP/hAUH/6QFJ/98BS//eAVP/3wFV//IAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AAFABn/8gDh//EBSf/yAUv/8gFT//IACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AASANT/rgDhABIA5v/gAOj/rQDq/9YA+P/fAPz/0gEC/+ABF//OASf/3QEp/+IBLf/gATP/4AE5/+kBPP/aAUb/vQFQ/98BUwARAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QADADUABMA4f/mAOL/9ADoABIA8f/nAS//5wE4/+UBOf/oAUn/5gFL/+YBU//mAVT/5wAJAOH/wwDx/88BL//OATj/5wE7/98BSf/RAUv/7AFT/6ABVP/RAAkA4f/DAPH/zwEv/84BOP/nATv/3wFJ/9EBS//sAVP/oAFU/9EAAgDU/+IBU//kAAIA1P/hAOj/5AAGAOj/7gDx/+4BBP/0ARv/8QEv/+8BVP/vAAQA8f/0AQT/9QEv//UBVP/1AAIA6P/JARf/7gAGAOgAFADx/+0A9//iAS//7QE5/+0BVP/tAAEBF//xAAUBF//rAan/6wGt/+kBtf/rAbb/6wATAEgADQDC/6sAw//AAMf/1QDo/6oBF//iARsADAFKAAsBTAALAaf/vwGp/+4Brf/sAbX/7QG2/+wBuP/1AbkADgG7AA0BvgANAd//sAAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oAAYA6AAUAPH/8AD8AAwBL//wATn/5gFU//AABQDoADoA8f/jAS//4gE5/+MBVP/jAAgA8f+6AQT/zwEb/9sBL/9QATn/nQFK//ABTP/yAVT/TAAIAPH/ugEE/88BG//bAS//UAE5/50BSv/wAUz/8gFU/0wABgDF/+oA6P/uAPH/sAEv/+wBVP/sAdz/6AABAOj/7wAIAPH/ugEE/88BG//bAS//UAE5/50BSv/wAUz/8gFU/0wACADx/7oBBP/PARv/2wEv/1ABOf+dAUr/8AFM//IBVP9MAAgA8f+6AQT/zwEb/9sBL/9QATn/nQFK//ABTP/yAVT/TAAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkACwAUAD8AEQBU/+IAXwATAaf/tAGp/9kBrf/ZAbX/2QG2/9kABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UABgDF/+oA6P/uAPH/sAEv/+wBVP/sAdz/6AAwAFT/bQBZ/4wAa/2/AHr+fQB//rwAhP8rAIf/SwCz/2EAuv8PAL7+6ADB/x8Awv7lAMX/RgDH/u0AyP79AMn+2QDU/1IA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPr/EwD8/wcBAv8OAQT/EQEX/zwBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/1kB3/+PAAIA6P/JARf/7gATAFn/wQCz/8UAxf+0AOX/1wDx/7kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAan/6AGt/+YBtf/nAbb/5wATAFn/wQCz/8UAxf+0AOX/1wDx/7kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAan/6AGt/+YBtf/nAbb/5wACAOj/yQEX/+4AAQBZAAsAAQBZAAsAAQBZAAsAAQBZAAsAAQBZAAsACQGp//IBrf/yAbX/8gG2//IBuf/AAbr/7AG7/8cBvP/YAb7/vwACAbv/7gG8//UAAQGn/9IABAGp/+sBrf/pAbX/6wG2/+sACgGnABEBqf/wAa3/7gG1/+8Btv/wAbn/uwG6/+wBu/+3Abz/1QG+/7QABQGn//MBuf/uAbv/8QG9/+wBvv/qAAQBuf/pAbv/6wG8//EBvv/lAAQBuf/yAbv/8QG8//UBvv/uAAkBp/+/Aan/7gGt/+wBtf/tAbb/7AG4//UBuQAOAbsADQG+AA0AAQGn/+8ABQGn/8cBqf/yAa3/8AG1//ABtv/wAAIBp//cAbkADgAEAan/7QGt/+sBtf/rAbb/6wAJAaf/wAGp/+0Brf/rAbX/6wG2/+sBuQAPAbsAEAG8AA0BvgAQAAUBpwAMAan/8AGt//ABtf/wAbb/8AABAdf/agABAdf/FQAGAEgACwC6//IAx//xAMn/7wHcAA8B3//uAAEBp//VAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QA5AFT/tQBZ/8cAa/64AHr/KAB//00AhP+OAIf/oQCz/64Auv9+AL7/ZwDB/4cAwv9lAMX/ngDH/2oAyP9zAMn/XgDU/6UA4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APr/gAD8/3kBAv99AQT/fwEX/5gBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGn/68Bqf+5Aa3/uQG1/7kBtv+5Abj/vAG5//EBvP/xAb3/7QHc/6kB3//JABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAQAC//mAD//9ABf/+8BPP/tAAUASP/uAFn/6gG7//ABvP/tAb7/8AAFAEj/7gBZ/+oBu//wAbz/7QG+//AABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAUASP/uAFn/6gG7//ABvP/tAb7/8AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QABAaf/6wABAaf/6wABAaf/6wABAaf/6wAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAEA8f/1AAEA8f/1AAEA8f/1AAEA8f/1AAEA8f/AAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAEAAv/5gA///QAX//vATz/7QAEAAv/5gA///QAX//vATz/7QAEAAv/5gA///QAX//vATz/7QAEAAv/5gA///QAX//vATz/7QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEA8f/AAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQGn/+sAEwBZ/8EAs//FAMX/tADl/9cA8f+5AQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGp/+gBrf/mAbX/5wG2/+cACwBZ/6QBpwATAan/8wGt//EBtf/yAbb/8QG5/zsBuv/aAbv/VAG8/5EBvv8/AAsAWf+kAacAEwGp//MBrf/xAbX/8gG2//EBuf87Abr/2gG7/1QBvP+RAb7/PwALAFn/pAGnABMBqf/zAa3/8QG1//IBtv/xAbn/OwG6/9oBu/9UAbz/kQG+/z8ACwBZ/6QBpwATAan/8wGt//EBtf/yAbb/8QG5/zsBuv/aAbv/VAG8/5EBvv8/AAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAPH/wAAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/8AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEA8f/AAAEA8f/AAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAMASAAPAFYAIABZABEAAwBIAA8AVgAgAFkAEQADAEgADwBWACAAWQARADkAVP+1AFn/xwBr/rgAev8oAH//TQCE/44Ah/+hALP/rgC6/34Avv9nAMH/hwDC/2UAxf+eAMf/agDI/3MAyf9eANT/pQDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+v+AAPz/eQEC/30BBP9/ARf/mAEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAaf/rwGp/7kBrf+5AbX/uQG2/7kBuP+8Abn/8QG8//EBvf/tAdz/qQHf/8kAOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQA5AFT/tQBZ/8cAa/64AHr/KAB//00AhP+OAIf/oQCz/64Auv9+AL7/ZwDB/4cAwv9lAMX/ngDH/2oAyP9zAMn/XgDU/6UA4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APr/gAD8/3kBAv99AQT/fwEX/5gBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGn/68Bqf+5Aa3/uQG1/7kBtv+5Abj/vAG5//EBvP/xAb3/7QHc/6kB3//JAAEBp//rAAEBp//rAAEBp//rAAEBp//rAAEBp//rAAEBp//rAAkACwAPAD8ADABU/+sAXwAOAaf/ywGp/+kBrf/nAbX/5wG2/+cAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAgAWf/lALP/ywDI/+QBpwANAan/7QGt/+sBtf/sAbb/7AAIAFn/5QCz/8sAyP/kAacADQGp/+0Brf/rAbX/7AG2/+wACABZ/+UAs//LAMj/5AGnAA0Bqf/tAa3/6wG1/+wBtv/sABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAUASP/uAFn/6gG7//ABvP/tAb7/8AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAACAQwACwFT/+YABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAgAWf/lALP/ywDI/+QBpwANAan/7QGt/+sBtf/sAbb/7AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAFYADgB//58Av//eAML/5QDU/6gA6P/KAUb/4wGn/8YB3//1ADkAVP+1AFn/xwBr/rgAev8oAH//TQCE/44Ah/+hALP/rgC6/34Avv9nAMH/hwDC/2UAxf+eAMf/agDI/3MAyf9eANT/pQDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+v+AAPz/eQEC/30BBP9/ARf/mAEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAaf/rwGp/7kBrf+5AbX/uQG2/7kBuP+8Abn/8QG8//EBvf/tAdz/qQHf/8kAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAEA8f/AAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAFAEj/7gBZ/+oBu//wAbz/7QG+//AAMABU/20AWf+MAGv9vwB6/n0Af/68AIT/KwCH/0sAs/9hALr/DwC+/ugAwf8fAML+5QDF/0YAx/7tAMj+/QDJ/tkA1P9SAOEABQDl/70A5v9JAOj+/gDq/xMA8f9oAPj/DgD6/xMA/P8HAQL/DgEE/xEBF/88ARv/rAEn/xUBKf88AS3/DgEv/2oBM/9JATn/DAE7/z8BPP7xAUH/wAFG/u8BSv8xAUz/XwFQ/woBUwAFAVT/MAFV/9UB3P9ZAd//jwAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEBp//rABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAAgEMAAsBU//mADAAVP9tAFn/jABr/b8Aev59AH/+vACE/ysAh/9LALP/YQC6/w8Avv7oAMH/HwDC/uUAxf9GAMf+7QDI/v0Ayf7ZANT/UgDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+v8TAPz/BwEC/w4BBP8RARf/PAEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/WQHf/48ABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAFYADgB//58Av//eAML/5QDU/6gA6P/KAUb/4wGn/8YB3//1AAQAC//mAD//9ABf/+8BPP/tADkAVP+1AFn/xwBr/rgAev8oAH//TQCE/44Ah/+hALP/rgC6/34Avv9nAMH/hwDC/2UAxf+eAMf/agDI/3MAyf9eANT/pQDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+v+AAPz/eQEC/30BBP9/ARf/mAEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAaf/rwGp/7kBrf+5AbX/uQG2/7kBuP+8Abn/8QG8//EBvf/tAdz/qQHf/8kAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wABAPH/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAYAxf/qAOj/7gDx/7ABL//sAVT/7AHc/+gABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAAQEX//EAAQDx//UAAgDo/8kBF//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAkACwAPAD8ADABU/+sAXwAOAaf/ywGp/+kBrf/nAbX/5wG2/+cACQALAA8APwAMAFT/6wBfAA4Bp//LAan/6QGt/+cBtf/nAbb/5wAJAAsADwA/AAwAVP/rAF8ADgGn/8sBqf/pAa3/5wG1/+cBtv/nACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAAQBZAAsAAQBZAAsAAQBZAAsACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEA8f/AABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAkACwAUAD8AEQBU/+IAXwATAaf/tAGp/9kBrf/ZAbX/2QG2/9kABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UABAAL/+YAP//0AF//7wE8/+0AJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AABARf/8QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAEA8f/1AAEA8f/1ABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAan/6QGt/+cBtf/nAbb/6QHf//AAAQEX//EACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oABgDF/+oA6P/uAPH/sAEv/+wBVP/sAdz/6AASANT/rgDhABIA5v/gAOj/rQDq/9YA+P/fAPz/0gEC/+ABF//OASf/3QEp/+IBLf/gATP/4AE5/+kBPP/aAUb/vQFQ/98BUwARAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAEgDU/64A4QASAOb/4ADo/60A6v/WAPj/3wD8/9IBAv/gARf/zgEn/90BKf/iAS3/4AEz/+ABOf/pATz/2gFG/70BUP/fAVMAEQAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAEBF//xABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gABAaf/6wABAaf/6wAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QATAFn/wQCz/8UAxf+0AOX/1wDx/7kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAan/6AGt/+YBtf/nAbb/5wAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAEBF//xADAAVP9tAFn/jABr/b8Aev59AH/+vACE/ysAh/9LALP/YQC6/w8Avv7oAMH/HwDC/uUAxf9GAMf+7QDI/v0Ayf7ZANT/UgDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+v8TAPz/BwEC/w4BBP8RARf/PAEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/WQHf/48AAgDo/8kBF//uABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAan/6QGt/+cBtf/nAbb/6QHf//AAAQEX//EAAQDx/8AACQDh/8MA8f/PAS//zgE4/+cBO//fAUn/0QFL/+wBU/+gAVT/0QAwAFT/bQBZ/4wAa/2/AHr+fQB//rwAhP8rAIf/SwCz/2EAuv8PAL7+6ADB/x8Awv7lAMX/RgDH/u0AyP79AMn+2QDU/1IA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPr/EwD8/wcBAv8OAQT/EQEX/zwBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/1kB3/+PABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gABMLIABAAAAAoAHgB0A6YEJASOBNAF7gbkB0IHXAAVADgAFAA5ABIAOwAWARQAFAILABYCkgASApQAFgKWABYC/QAWAwwAFgMPABYDRQASA0cAEgNJABIDSwAWA2AAFANoABYD6gAWA+wAFgPuABYEEwAWAMwADv8WABD/FgAj/1YALP74ADYAFABD/94ARf/rAEb/6wBH/+sASf/rAFH/6wBT/+sAV//qAFj/6ABb/+gAkf/rAJX/6wCX/+oArf9WAK//VgC2/+sAuP/oAMP/6wDE/+sAxv/qAM0AFADRABQA8v/rAP7/6wEI/1YBE//rARX/6AEZ/+sBHf/rAS4AFAE1/+sBNgAUAUf/6wFI/+sBUv/rAWf/FgFr/xYBb/8WAXD/FgHx/1YB8v9WAfP/VgH0/1YB9f9WAfb/VgH3/1YCDP/eAg3/3gIO/94CD//eAhD/3gIR/94CEv/eAhP/6wIU/+sCFf/rAhb/6wIX/+sCHf/rAh7/6wIf/+sCIP/rAiH/6wIi/+oCI//qAiT/6gIl/+oCJv/oAif/6AIo/1YCKf/eAir/VgIr/94CLP9WAi3/3gIv/+sCMf/rAjP/6wI1/+sCN//rAjn/6wI7/+sCPf/rAj//6wJB/+sCQ//rAkX/6wJH/+sCSf/rAlf++AJr/+sCbf/rAm//6wKAABQCggAUAoQAFAKH/+oCif/qAov/6gKN/+oCj//qApH/6gKV/+gC+P9WAwD/VgMQ/+sDFP/qAxb/6wMY/+gDG//qAxz/6wMd/+oDJP74Ayj/VgMzABQDNf/eAzb/6wM4/+sDOv/rAzv/6AM9/+sDRP/oA0z/6ANV/1YDVv/eA1z/6wNh/+gDYv/rA2f/6wNp/+gDbv9WA2//3gNw/1YDcf/eA3X/6wN3/+sDeP/rA4L/6wOE/+sDhv/rA4r/6AOM/+gDjv/oA5X/6wOY/1YDmf/eA5r/VgOb/94DnP9WA53/3gOe/1YDn//eA6D/VgOh/94Dov9WA6P/3gOk/1YDpf/eA6b/VgOn/94DqP9WA6n/3gOq/1YDq//eA6z/VgOt/94Drv9WA6//3gOx/+sDs//rA7X/6wO3/+sDuf/rA7v/6wO9/+sDv//rA8X/6wPH/+sDyf/rA8v/6wPN/+sDz//rA9H/6wPT/+sD1f/rA9f/6wPZ/+sD2//rA93/6gPf/+oD4f/qA+P/6gPl/+oD5//qA+n/6gPr/+gD7f/oA+//6AP2ABQAHwA2/9UAOP/kADn/7AA7/90Azf/VANH/1QEU/+QBLv/VATb/1QIL/90CgP/VAoL/1QKE/9UCkv/sApT/3QKW/90C/f/dAwz/3QMP/90DM//VA0X/7ANH/+wDSf/sA0v/3QNg/+QDaP/dA+r/3QPs/90D7v/dA/b/1QQT/90AGgA2/7AAOP/tADv/0ADN/7AA0f+wART/7QEu/7ABNv+wAgv/0AKA/7ACgv+wAoT/sAKU/9AClv/QAv3/0AMM/9ADD//QAzP/sANL/9ADYP/tA2j/0APq/9AD7P/QA+7/0AP2/7AEE//QABAALP/uADf/7gIH/+4CCP/uAgn/7gIK/+4CV//uAob/7gKI/+4Civ/uAoz/7gKO/+4CkP/uAyT/7gPc/+4D3v/uAEcABAAQAAkAEABF/+gARv/oAEf/6ABJ/+gAU//oAJH/6ACV/+gAtv/oAMP/6ADE/+gA8v/oAP7/6AEZ/+gBHf/oATX/6AFH/+gBSP/oAVL/6AFlABABZgAQAWgAEAFpABABagAQAhP/6AIU/+gCFf/oAhb/6AIX/+gCL//oAjH/6AIz/+gCNf/oAjf/6AI5/+gCO//oAj3/6AI//+gCQf/oAkP/6AJF/+gCR//oAkn/6AMQ/+gDNv/oAzr/6AM9/+gDTQAQA04AEANSABADXP/oA2L/6ANn/+gDdf/oA3f/6AN4/+gDhP/oA5X/6AOx/+gDs//oA7X/6AO3/+gDuf/oA7v/6AO9/+gDv//oA9P/6APV/+gD1//oA9v/6AA9AEX/7ABG/+wAR//sAEn/7ABT/+wAkf/sAJX/7AC2/+wAw//sAMT/7ADy/+wA/v/sARn/7AEd/+wBNf/sAUf/7AFI/+wBUv/sAhP/7AIU/+wCFf/sAhb/7AIX/+wCL//sAjH/7AIz/+wCNf/sAjf/7AI5/+wCO//sAj3/7AI//+wCQf/sAkP/7AJF/+wCR//sAkn/7AMQ/+wDNv/sAzr/7AM9/+wDXP/sA2L/7ANn/+wDdf/sA3f/7AN4/+wDhP/sA5X/7AOx/+wDs//sA7X/7AO3/+wDuf/sA7v/7AO9/+wDv//sA9P/7APV/+wD1//sA9v/7AAXAFH/7AET/+wCHf/sAh7/7AIf/+wCIP/sAiH/7AJr/+wCbf/sAm//7AMW/+wDHP/sAzj/7AOC/+wDhv/sA8X/7APH/+wDyf/sA8v/7APN/+wDz//sA9H/7APZ/+wABgAO/4QAEP+EAWf/hAFr/4QBb/+EAXD/hAAQACz/7AA3/+wCB//sAgj/7AIJ/+wCCv/sAlf/7AKG/+wCiP/sAor/7AKM/+wCjv/sApD/7AMk/+wD3P/sA97/7AABKSwABAAAACIATgDEAaoCkANqBAQGnghkCTYKLAvyDCQMVgzUDroPMBACEhQSyhQwFOoVcBXOFpAXBhcYF0IYlBrSGvQcChyIHLIc3AAdAAT/8gAJ//IAWP/zAFv/8wC4//MBFf/zAWX/8gFm//IBaP/yAWn/8gFq//ICJv/zAif/8wKV//MDGP/zAzv/8wNE//MDTP/zA03/8gNO//IDUv/yA2H/8wNp//MDiv/zA4z/8wOO//MD6//zA+3/8wPv//MAOQAl//MAKf/zADH/8wAz//MAgf/zAJD/8wCU//MArv/zAM7/8wED//MBEv/zARb/8wEY//MBGv/zARz/8wE0//MBUf/zAfj/8wIC//MCA//zAgT/8wIF//MCBv/zAi7/8wIw//MCMv/zAjT/8wJC//MCRP/zAkb/8wJI//MCav/zAmz/8wJu//MCn//zAvz/8wMJ//MDL//zAzL/8wNX//MDY//zA2b/8wOB//MDg//zA4X/8wPE//MDxv/zA8j/8wPK//MDzP/zA87/8wPQ//MD0v/zA9T/8wPW//MD2P/zA9r/8wA5ACX/5gAp/+YAMf/mADP/5gCB/+YAkP/mAJT/5gCu/+YAzv/mAQP/5gES/+YBFv/mARj/5gEa/+YBHP/mATT/5gFR/+YB+P/mAgL/5gID/+YCBP/mAgX/5gIG/+YCLv/mAjD/5gIy/+YCNP/mAkL/5gJE/+YCRv/mAkj/5gJq/+YCbP/mAm7/5gKf/+YC/P/mAwn/5gMv/+YDMv/mA1f/5gNj/+YDZv/mA4H/5gOD/+YDhf/mA8T/5gPG/+YDyP/mA8r/5gPM/+YDzv/mA9D/5gPS/+YD1P/mA9b/5gPY/+YD2v/mADYAI//kADr/0gA7/9MArf/kAK//5ADV/9IBCP/kAfH/5AHy/+QB8//kAfT/5AH1/+QB9v/kAff/5AIL/9MCKP/kAir/5AIs/+QClP/TApb/0wL4/+QC/f/TAwD/5AMM/9MDDf/SAw//0wMo/+QDNP/SA0v/0wNV/+QDaP/TA2v/0gNu/+QDcP/kA3n/0gOT/9IDmP/kA5r/5AOc/+QDnv/kA6D/5AOi/+QDpP/kA6b/5AOo/+QDqv/kA6z/5AOu/+QD6v/TA+z/0wPu/9MD+P/SBAD/0gQT/9MAJgAO/x4AEP8eACP/zQCt/80Ar//NAQj/zQFn/x4Ba/8eAW//HgFw/x4B8f/NAfL/zQHz/80B9P/NAfX/zQH2/80B9//NAij/zQIq/80CLP/NAvj/zQMA/80DKP/NA1X/zQNu/80DcP/NA5j/zQOa/80DnP/NA57/zQOg/80Dov/NA6T/zQOm/80DqP/NA6r/zQOs/80Drv/NAKYARf/cAEb/3ABH/9wASf/cAE//8wBQ//MAUf/WAFL/8wBT/9wAV//dAFj/4QBb/+EAkf/cAJX/3ACX/90Atv/cALj/4QC8//MAw//cAMT/3ADG/90A5//zAOv/8wDs//MA7v/zAO//8wDw//MA8v/cAPP/8wD1//MA9v/zAPn/8wD7//MA/v/cAQD/8wET/9YBFf/hARn/3AEd/9wBMf/zATX/3AFA//MBRf/zAUf/3AFI/9wBUv/cAhP/3AIU/9wCFf/cAhb/3AIX/9wCHP/zAh3/1gIe/9YCH//WAiD/1gIh/9YCIv/dAiP/3QIk/90CJf/dAib/4QIn/+ECL//cAjH/3AIz/9wCNf/cAjf/3AI5/9wCO//cAj3/3AI//9wCQf/cAkP/3AJF/9wCR//cAkn/3AJk//MCZv/zAmj/8wJp//MCa//WAm3/1gJv/9YCh//dAon/3QKL/90Cjf/dAo//3QKR/90Clf/hAxD/3AMS//MDFP/dAxb/1gMY/+EDG//dAxz/1gMd/90DNv/cAzf/8wM4/9YDOf/zAzr/3AM7/+EDPf/cAz7/8wND//MDRP/hA0z/4QNU//MDXP/cA13/8wNh/+EDYv/cA2f/3ANp/+EDdf/cA3f/3AN4/9wDfv/zA4D/8wOC/9YDhP/cA4b/1gOK/+EDjP/hA47/4QOS//MDlf/cA7H/3AOz/9wDtf/cA7f/3AO5/9wDu//cA73/3AO//9wDxf/WA8f/1gPJ/9YDy//WA83/1gPP/9YD0f/WA9P/3APV/9wD1//cA9n/1gPb/9wD3f/dA9//3QPh/90D4//dA+X/3QPn/90D6f/dA+v/4QPt/+ED7//hA/P/8wP1//MD///zBAz/8wQO//MEEP/zAHEABP/aAAn/2gBF//AARv/wAEf/8ABJ//AAU//wAFf/7wBY/9wAW//cAJH/8ACV//AAl//vALb/8AC4/9wAw//wAMT/8ADG/+8A8v/wAP7/8AEV/9wBGf/wAR3/8AE1//ABR//wAUj/8AFS//ABZf/aAWb/2gFo/9oBaf/aAWr/2gIT//ACFP/wAhX/8AIW//ACF//wAiL/7wIj/+8CJP/vAiX/7wIm/9wCJ//cAi//8AIx//ACM//wAjX/8AI3//ACOf/wAjv/8AI9//ACP//wAkH/8AJD//ACRf/wAkf/8AJJ//ACh//vAon/7wKL/+8Cjf/vAo//7wKR/+8Clf/cAxD/8AMU/+8DGP/cAxv/7wMd/+8DNv/wAzr/8AM7/9wDPf/wA0T/3ANM/9wDTf/aA07/2gNS/9oDXP/wA2H/3ANi//ADZ//wA2n/3AN1//ADd//wA3j/8AOE//ADiv/cA4z/3AOO/9wDlf/wA7H/8AOz//ADtf/wA7f/8AO5//ADu//wA73/8AO///AD0//wA9X/8APX//AD2//wA93/7wPf/+8D4f/vA+P/7wPl/+8D5//vA+n/7wPr/9wD7f/cA+//3AA0AAT/oAAJ/6AAV//xAFj/xQBb/8UAl//xALj/xQDG//EBFf/FAWX/oAFm/6ABaP+gAWn/oAFq/6ACIv/xAiP/8QIk//ECJf/xAib/xQIn/8UCh//xAon/8QKL//ECjf/xAo//8QKR//EClf/FAxT/8QMY/8UDG//xAx3/8QM7/8UDRP/FA0z/xQNN/6ADTv+gA1L/oANh/8UDaf/FA4r/xQOM/8UDjv/FA93/8QPf//ED4f/xA+P/8QPl//ED5//xA+n/8QPr/8UD7f/FA+//xQA9AEX/5wBG/+cAR//nAEn/5wBT/+cAkf/nAJX/5wC2/+cAw//nAMT/5wDy/+cA/v/nARn/5wEd/+cBNf/nAUf/5wFI/+cBUv/nAhP/5wIU/+cCFf/nAhb/5wIX/+cCL//nAjH/5wIz/+cCNf/nAjf/5wI5/+cCO//nAj3/5wI//+cCQf/nAkP/5wJF/+cCR//nAkn/5wMQ/+cDNv/nAzr/5wM9/+cDXP/nA2L/5wNn/+cDdf/nA3f/5wN4/+cDhP/nA5X/5wOx/+cDs//nA7X/5wO3/+cDuf/nA7v/5wO9/+cDv//nA9P/5wPV/+cD1//nA9v/5wBxAAQADAAJAAwARf/oAEb/6ABH/+gASf/oAFH/6gBT/+gAWAALAFsACwCR/+gAlf/oALb/6AC4AAsAw//oAMT/6ADy/+gA/v/oARP/6gEVAAsBGf/oAR3/6AE1/+gBR//oAUj/6AFS/+gBZQAMAWYADAFoAAwBaQAMAWoADAIT/+gCFP/oAhX/6AIW/+gCF//oAh3/6gIe/+oCH//qAiD/6gIh/+oCJgALAicACwIv/+gCMf/oAjP/6AI1/+gCN//oAjn/6AI7/+gCPf/oAj//6AJB/+gCQ//oAkX/6AJH/+gCSf/oAmv/6gJt/+oCb//qApUACwMQ/+gDFv/qAxgACwMc/+oDNv/oAzj/6gM6/+gDOwALAz3/6ANEAAsDTAALA00ADANOAAwDUgAMA1z/6ANhAAsDYv/oA2f/6ANpAAsDdf/oA3f/6AN4/+gDgv/qA4T/6AOG/+oDigALA4wACwOOAAsDlf/oA7H/6AOz/+gDtf/oA7f/6AO5/+gDu//oA73/6AO//+gDxf/qA8f/6gPJ/+oDy//qA83/6gPP/+oD0f/qA9P/6APV/+gD1//oA9n/6gPb/+gD6wALA+0ACwPvAAsADABa/+0AXP/tAOn/7QKY/+0Cmv/tApz/7QM8/+0DbP/tA3r/7QOU/+0D+f/tBAH/7QAMAFr/8gBc//IA6f/yApj/8gKa//ICnP/yAzz/8gNs//IDev/yA5T/8gP5//IEAf/yAB8AWP/0AFr/8gBb//QAXP/zALj/9ADp//IBFf/0Aib/9AIn//QClf/0Apj/8wKa//MCnP/zAxj/9AM7//QDPP/yA0T/9ANM//QDYf/0A2n/9ANs//IDev/yA4r/9AOM//QDjv/0A5T/8gPr//QD7f/0A+//9AP5//IEAf/yAHkABP/KAAn/ygA2/9IAOP/UADr/9AA7/9MAT//RAFD/0QBS/9EAWP/mAFr/7wBb/+YAuP/mALz/0QDN/9IA0f/SANX/9ADZ/+0A3P/hAOf/0QDp/+8A6//RAOz/0QDu/9EA7//RAPD/0QDz/9EA9f/RAPb/0QD5/9EA+//RAQD/0QEU/9QBFf/mAS7/0gEx/9EBNv/SAUD/0QFF/9EBZf/KAWb/ygFo/8oBaf/KAWr/ygIL/9MCHP/RAib/5gIn/+YCZP/RAmb/0QJo/9ECaf/RAoD/0gKC/9IChP/SApT/0wKV/+YClv/TAv3/0wMM/9MDDf/0Aw//0wMS/9EDGP/mAyf/7QMz/9IDNP/0Azf/0QM5/9EDO//mAzz/7wM+/9EDQ//RA0T/5gNL/9MDTP/mA03/ygNO/8oDUv/KA1T/0QNd/9EDYP/UA2H/5gNo/9MDaf/mA2v/9ANs/+8Def/0A3r/7wN+/9EDgP/RA4n/7QOK/+YDi//tA4z/5gON/+0Djv/mA4//4QOS/9EDk//0A5T/7wPq/9MD6//mA+z/0wPt/+YD7v/TA+//5gPz/9ED9f/RA/b/0gP4//QD+f/vA/r/4QP8/+ED///RBAD/9AQB/+8EDP/RBA7/0QQQ/9EEE//TAB0ANv++AFj/7wBb/+8AuP/vAM3/vgDR/74BFf/vAS7/vgE2/74CJv/vAif/7wKA/74Cgv++AoT/vgKV/+8DGP/vAzP/vgM7/+8DRP/vA0z/7wNh/+8Daf/vA4r/7wOM/+8Djv/vA+v/7wPt/+8D7//vA/b/vgA0ADb/5gA4/+cAOv/yADv/5wBa//EAzf/mANH/5gDV//IA2f/uANz/6ADp//EBFP/nAS7/5gE2/+YCC//nAoD/5gKC/+YChP/mApT/5wKW/+cC/f/nAwz/5wMN//IDD//nAyf/7gMz/+YDNP/yAzz/8QNL/+cDYP/nA2j/5wNr//IDbP/xA3n/8gN6//EDif/uA4v/7gON/+4Dj//oA5P/8gOU//ED6v/nA+z/5wPu/+cD9v/mA/j/8gP5//ED+v/oA/z/6AQA//IEAf/xBBP/5wCEACMAEAAl/+gAKf/oADH/6AAz/+gANv/gADj/4AA7/98Agf/oAJD/6ACU/+gArQAQAK7/6ACvABAAzf/gAM7/6ADPABAA0f/gANgAEADc/+EA7QAQAPT/4AD/ABABA//oAQgAEAES/+gBFP/gARb/6AEY/+gBGv/oARz/6AEu/+ABNP/oATb/4AFNABABUf/oAfEAEAHyABAB8wAQAfQAEAH1ABAB9gAQAfcAEAH4/+gCAv/oAgP/6AIE/+gCBf/oAgb/6AIL/98CKAAQAioAEAIsABACLv/oAjD/6AIy/+gCNP/oAkL/6AJE/+gCRv/oAkj/6AJq/+gCbP/oAm7/6AKA/+ACgv/gAoT/4AKU/98Clv/fAp//6AL4ABAC/P/oAv3/3wMAABADCf/oAwz/3wMP/98DKAAQAy//6AMy/+gDM//gA0v/3wNVABADV//oA2D/4ANj/+gDZv/oA2j/3wNuABADcAAQA4H/6AOD/+gDhf/oA4//4QOQ/+ADlgAQA5cAEAOYABADmgAQA5wAEAOeABADoAAQA6IAEAOkABADpgAQA6gAEAOqABADrAAQA64AEAPE/+gDxv/oA8j/6APK/+gDzP/oA87/6APQ/+gD0v/oA9T/6APW/+gD2P/oA9r/6APq/98D7P/fA+7/3wP2/+AD+v/hA/v/4AP8/+ED/f/gBBEAEAQSABAEE//fAC0ANv/xADj/9AA6//QAO//wAM3/8QDP//UA0f/xANX/9ADY//UA2f/zART/9AEu//EBNv/xAU3/9QIL//ACgP/xAoL/8QKE//EClP/wApb/8AL9//ADDP/wAw3/9AMP//ADJ//zAzP/8QM0//QDS//wA2D/9ANo//ADa//0A3n/9AOJ//MDi//zA43/8wOT//QDlv/1A+r/8APs//AD7v/wA/b/8QP4//QEAP/0BBH/9QQT//AAWQAjAA8ANv/mADj/5gA6AA4AO//mAK0ADwCvAA8Azf/mAM8ADgDR/+YA1QAOANgADgDZAAsA3P/lAO0ADwD0/+gA/wAPAQgADwEU/+YBLv/mATb/5gFNAA4B8QAPAfIADwHzAA8B9AAPAfUADwH2AA8B9wAPAgv/5gIoAA8CKgAPAiwADwKA/+YCgv/mAoT/5gKU/+YClv/mAvgADwL9/+YDAAAPAwz/5gMNAA4DD//mAycACwMoAA8DM//mAzQADgNL/+YDVQAPA2D/5gNo/+YDawAOA24ADwNwAA8DeQAOA4kACwOLAAsDjQALA4//5QOQ/+gDkwAOA5YADgOXAA8DmAAPA5oADwOcAA8DngAPA6AADwOiAA8DpAAPA6YADwOoAA8DqgAPA6wADwOuAA8D6v/mA+z/5gPu/+YD9v/mA/gADgP6/+UD+//oA/z/5QP9/+gEAAAOBBEADgQSAA8EE//mAC4ANv/jADr/5QA7/+QAzf/jAM//5QDR/+MA1f/lANj/5QDZ/+kA7f/qAP//6gEu/+MBNv/jAU3/5QIL/+QCgP/jAoL/4wKE/+MClP/kApb/5AL9/+QDDP/kAw3/5QMP/+QDJ//pAzP/4wM0/+UDS//kA2j/5ANr/+UDef/lA4n/6QOL/+kDjf/pA5P/5QOW/+UDl//qA+r/5APs/+QD7v/kA/b/4wP4/+UEAP/lBBH/5QQS/+oEE//kACEANv/iADr/5ADN/+IAz//kANH/4gDV/+QA2P/kANn/6QDt/+sA///rAS7/4gE2/+IBTf/kAoD/4gKC/+IChP/iAw3/5AMn/+kDM//iAzT/5ANr/+QDef/kA4n/6QOL/+kDjf/pA5P/5AOW/+QDl//rA/b/4gP4/+QEAP/kBBH/5AQS/+sAFwA2/+sAO//zAM3/6wDR/+sBLv/rATb/6wIL//MCgP/rAoL/6wKE/+sClP/zApb/8wL9//MDDP/zAw//8wMz/+sDS//zA2j/8wPq//MD7P/zA+7/8wP2/+sEE//zADAAT//vAFD/7wBS/+8AWv/wALz/7wDn/+8A6f/wAOv/7wDs/+8A7v/vAO//7wDw/+8A8//vAPX/7wD2/+8A+f/vAPv/7wEA/+8BMf/vAUD/7wFF/+8CHP/vAmT/7wJm/+8CaP/vAmn/7wMS/+8DN//vAzn/7wM8//ADPv/vA0P/7wNU/+8DXf/vA2z/8AN6//ADfv/vA4D/7wOS/+8DlP/wA/P/7wP1/+8D+f/wA///7wQB//AEDP/vBA7/7wQQ/+8AHQAE//IACf/yAFj/9QBb//UAuP/1ARX/9QFl//IBZv/yAWj/8gFp//IBav/yAib/9QIn//UClf/1Axj/9QM7//UDRP/1A0z/9QNN//IDTv/yA1L/8gNh//UDaf/1A4r/9QOM//UDjv/1A+v/9QPt//UD7//1AAQA9P/tA5D/7QP7/+0D/f/tAAoABP/1AAn/9QFl//UBZv/1AWj/9QFp//UBav/1A03/9QNO//UDUv/1AFQARf/wAEb/8ABH//AASf/wAFH/6wBT//AAkf/wAJX/8AC2//AAw//wAMT/8ADy//AA/v/wARP/6wEZ//ABHf/wATX/8AFH//ABSP/wAVL/8AIT//ACFP/wAhX/8AIW//ACF//wAh3/6wIe/+sCH//rAiD/6wIh/+sCL//wAjH/8AIz//ACNf/wAjf/8AI5//ACO//wAj3/8AI///ACQf/wAkP/8AJF//ACR//wAkn/8AJr/+sCbf/rAm//6wMQ//ADFv/rAxz/6wM2//ADOP/rAzr/8AM9//ADXP/wA2L/8ANn//ADdf/wA3f/8AN4//ADgv/rA4T/8AOG/+sDlf/wA7H/8AOz//ADtf/wA7f/8AO5//ADu//wA73/8AO///ADxf/rA8f/6wPJ/+sDy//rA83/6wPP/+sD0f/rA9P/8APV//AD1//wA9n/6wPb//AAjwAEAA0ACQANAEP/8ABF/7AARv+wAEf/sABJ/7AAUf/WAFP/sABYAAsAWwALAJH/sACV/7AAtv+wALgACwDE/7AA7f+vAPL/sAD+/7AA//+vARP/1gEVAAsBGf+wAR3/sAE1/7ABR/+wAUj/sAFS/7ABZQANAWYADQFoAA0BaQANAWoADQIM//ACDf/wAg7/8AIP//ACEP/wAhH/8AIS//ACE/+wAhT/sAIV/7ACFv+wAhf/sAId/9YCHv/WAh//1gIg/9YCIf/WAiYACwInAAsCKf/wAiv/8AIt//ACL/+wAjH/sAIz/7ACNf+wAjf/sAI5/7ACO/+wAj3/sAI//7ACQf+wAkP/sAJF/7ACR/+wAkn/sAJr/9YCbf/WAm//1gKVAAsDEP+wAxb/1gMYAAsDHP/WAzX/8AM2/7ADOP/WAzr/sAM7AAsDPf+wA0QACwNMAAsDTQANA04ADQNSAA0DVv/wA1z/sANhAAsDYv+wA2f/sANpAAsDb//wA3H/8AN1/7ADd/+wA3j/sAOC/9YDhP+wA4b/1gOKAAsDjAALA44ACwOV/7ADl/+vA5n/8AOb//ADnf/wA5//8AOh//ADo//wA6X/8AOn//ADqf/wA6v/8AOt//ADr//wA7H/sAOz/7ADtf+wA7f/sAO5/7ADu/+wA73/sAO//7ADxf/WA8f/1gPJ/9YDy//WA83/1gPP/9YD0f/WA9P/sAPV/7AD1/+wA9n/1gPb/7AD6wALA+0ACwPvAAsEEv+vAAgA7QAQAPT/8AD/ABADkP/wA5cAEAP7//AD/f/wBBIAEABFAEUADABGAAwARwAMAEkADABTAAwAkQAMAJUADAC2AAwAwwAMAMQADADtABgA8gAMAPT/9wD+AAwA/wAYARkADAEdAAwBNQAMAUcADAFIAAwBUgAMAhMADAIUAAwCFQAMAhYADAIXAAwCLwAMAjEADAIzAAwCNQAMAjcADAI5AAwCOwAMAj0ADAI/AAwCQQAMAkMADAJFAAwCRwAMAkkADAMQAAwDNgAMAzoADAM9AAwDXAAMA2IADANnAAwDdQAMA3cADAN4AAwDhAAMA5D/9wOVAAwDlwAYA7EADAOzAAwDtQAMA7cADAO5AAwDuwAMA70ADAO/AAwD0wAMA9UADAPXAAwD2wAMA/v/9wP9//cEEgAYAB8AWP/0AFr/8ABb//QAuP/0AOn/8ADt//MA///zARX/9AIm//QCJ//0ApX/9AMY//QDO//0Azz/8ANE//QDTP/0A2H/9ANp//QDbP/wA3r/8AOK//QDjP/0A47/9AOU//ADl//zA+v/9APt//QD7//0A/n/8AQB//AEEv/zAAoABP/WAAn/1gFl/9YBZv/WAWj/1gFp/9YBav/WA03/1gNO/9YDUv/WAAoABP/1AAn/9QFl//UBZv/1AWj/9QFp//UBav/1A03/9QNO//UDUv/1AF4ABAALAAkACwBF/+sARv/rAEf/6wBJ/+sAUf/pAFP/6wCR/+sAlf/rALb/6wDD/+sAxP/rAPL/6wD+/+sBE//pARn/6wEd/+sBNf/rAUf/6wFI/+sBUv/rAWUACwFmAAsBaAALAWkACwFqAAsCE//rAhT/6wIV/+sCFv/rAhf/6wId/+kCHv/pAh//6QIg/+kCIf/pAi//6wIx/+sCM//rAjX/6wI3/+sCOf/rAjv/6wI9/+sCP//rAkH/6wJD/+sCRf/rAkf/6wJJ/+sCa//pAm3/6QJv/+kDEP/rAxb/6QMc/+kDNv/rAzj/6QM6/+sDPf/rA00ACwNOAAsDUgALA1z/6wNi/+sDZ//rA3X/6wN3/+sDeP/rA4L/6QOE/+sDhv/pA5X/6wOx/+sDs//rA7X/6wO3/+sDuf/rA7v/6wO9/+sDv//rA8X/6QPH/+kDyf/pA8v/6QPN/+kDz//pA9H/6QPT/+sD1f/rA9f/6wPZ/+kD2//rAAILHgAEAAAN5hU6ACEAHQAAABH/zv+PABL/9f/v/4j/9P+7/3//9QAM/6n/ov/JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/lAAAAAP/o/8kAAP/zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAA/+UAEQAAAAAAAAAAAAD/4wAAAAAAAP/k/+QAAAASABEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+EAAAAAAAAAAAAAAAAAAAAA/+UAAAAA/+r/1QAAAAD/6//q/5r/6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/mAAAAAAAAAAAAAP/tAAAAFP/vAAAAAAAAAAAAAAAAAAAAAAAA/+0AAAAAAAAAAAAAAAAAAAAA/8v/uP98/37/5AAAAAD/nQAPABD/of/EABAAEAAAAAD/sQAA/yYAAP+d/7P/GP+T//D/j/+M/xAAAP+S/3L/DP8P/70AAAAA/0QABQAH/0v/hgAHAAcAAAAA/z4AAP56AAD/RP9q/mL/M//R/yz/JwAAAAAAAAAAAAD/2AAAAAAAAP/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+wAAAAAAAAAAAAAAAAAAAAAAAD/2P+jAAD/4QAAAAD/5QAAAAD/6QAAAAAAAAAAAAAAAAAAAAAAAP/mAAD/wP/pAAAAAAAAAAAAAAAA/3sAAAAA/7//yv92AAD/cf7t/9QAAP9R/xEAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/yQAPAAD/2QAAAAAAAP/zAAAAAAAAAAAAAAAAAAAAAP92/+H+vP/m//MAAAAAAAAAAP/1AAD/OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/6gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//UAAAAA//MAAAAA/9IAAAAA/+QAAAAAAAAAAAAA/7UAAP8fAAD/1AAA/9sAAAAA/9IAAAAAAAAAEf/h/9EAEf/nAAAAAP/rAAAAAP/rAAAADgAAAAAAAAAAAAAAAAAA/+YAAP/SAAAAAAAAAAAAAAAAAAD/7AAAAAD/4/+gAAD/vwARABH/2f/iABIAEgAAAAD/ogAN/y0AAP+//+n/zP/Y//D/t//G/6AAAAAAAAAAAAAAAAAAAAAA/+EAAAAO/+0AAAAAAAAAAAAA/9UAAP+FAAD/4QAA/8QAAAAA/98AAAAAAAAAAP/lAAAAAP/mAAAAAP/rAAAAAP/tAAAAAAAAAAAAAAANAAAAAAAA/+sAAAAAAAAAAAAAAAAAAAAA/8oAAP/p/7v/6QAAAAD/vQAAABIAAAAAAAAAEgAAAAD/pQAA/m0AAP+9AAD/if+aAAD/kf/SAAAAAAAA//EAAAAAAAAAAP+9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9QAA//IAAAAA/+MAAAAAAAAAAP/xAAAAAAAAAAAAAAAAAAAAAAAA//EAAAAAAAAAAAAAAAAAAAAA//MAAAAAAAAAAP/yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8QAA//AAAAAA/+wAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAA/+sAAAAAAAAAAAAAAAAAAAAAAAAAAP/XAAAAAAAP//EAAAAAAAAAAAAAAAAAAAAAAAAAAP+VAAD/8wAAAAAAAAAA//EAAAAAAAAAAAASAAAAAAAAAAAAEP/sAAAAAAAAAAAAAAAAAAAAAAAAAAD/hQAA/+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/lf/DAAAAAAAAAAAAAAAAAAAAAP+IAAAAAAAA/8UAAAAA/+wAAP/O/7AAAAAAAAAAAAAAAAAAAAAA/1YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/1AAAAAAAAAAAAAP/AAAAAAP71AAAAAP/I/63/5//rAAD/8AAAAAAAAP/JAAAAAAAAAAAAAAAAAAAAAP/d/9kAAAAAAAD/eQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9QAAAAAAAAAAAAAAAAACAIgABAAEAAAACQAJAAEAEQARAAIAIwAoAAMAKgAzAAkANgA8ABMAQwBEABoARwBIABwASgBKAB4ATwBSAB8AVABUACMAWABYACQAWgBbACUAiACIACcAmQCZACgArACwACkAsgC0AC4AtgC2ADEAuAC5ADIAuwC8ADQAvgDAADYAwgDHADkAzQDNAD8AzwDZAEAA2wDbAEsA3QDfAEwA4QDjAE8A5QDpAFIA7ADsAFcA8QDzAFgA9gD3AFsA+QD7AF0A/wEAAGABBQEFAGIBCAEIAGMBEwEVAGQBJwEpAGcBLAEsAGoBLgEuAGsBRQFFAGwBZQFmAG0BaAFqAG8BpgGmAHIBqQGpAHMBqwGrAHQBsAGxAHUBtAG2AHcBuAG+AHoBxAHEAIEB2wHcAIIB6AHoAIQB7AHtAIUB7wHvAIcB8QISAIgCFAIXAKoCHAIhAK4CJgIuALQCMAIwAL0CMgIyAL4CNAI0AL8CNgI2AMACOAJBAMECSgJMAMsCTgJOAM4CUAJQAM8CUgJSANACVAJUANECVwJXANICWQJZANMCWwJbANQCXQJdANUCXwJfANYCYQJhANcCYwJvANgCcQJxAOUCcwJzAOYCdQJ1AOcCgAKAAOgCggKCAOkChAKEAOoChgKGAOsCiAKIAOwCigKKAO0CjAKMAO4CjgKOAO8CkAKQAPACkgKSAPEClAKXAPICmQKZAPYCmwKbAPcC+AL9APgDAAMPAP4DEgMSAQ4DFgMWAQ8DGAMYARADHAMcAREDHwMgARIDIgMrARQDLQMvAR4DMQM2ASEDOAM5AScDOwM+ASkDRANFAS0DRwNHAS8DSQNJATADSwNOATEDUgNXATUDWgNaATsDXANcATwDYANhAT0DZgNmAT8DaANxAUADdAN1AUoDdwN6AUwDgQOCAVADhgOGAVIDiAOOAVMDkwOUAVoDmAPAAVwDwgPCAYUDxAPRAYYD2QPZAZQD3APcAZUD3gPeAZYD6gPvAZcD8gPyAZ0D9AP0AZ4D9gP2AZ8D+AP5AaAD/gQBAaIEBAQEAaYEBgQHAacECQQJAakEDQQNAaoEDwQPAasEEwQTAawAAQAKAAoAKAAzADQAPQBIAE0AVgBZAF0AAQAiAJkAsACyALMAtAC7AL4AvwDAAMUAxwDIAMkAzQDRANMA1ADWAN4A4gDjAOQA5QDmAOgA6gDsAPEA8wD2APsA/gEdAdwAAgB2AAQABAAAAAkACQABAA4ADgACABAAEAADACMAJwAEACoAMgAJADYAPAASAEMARQAZAEcARwAcAEoASgAdAE8AUgAeAFQAVAAiAFgAWAAjAFoAXAAkAIgAiAAnAKwArwAoALgAuAAsALwAvAAtAMIAwgAuAM8A0AAvANIA0gAxANUA1QAyANcA2QAzANsA2wA2AN0A3QA3AN8A3wA4AOEA4QA5AOcA5wA6AOkA6QA7APIA8gA8APcA9wA9APkA+gA+AP8BAABAAQUBBQBCAQgBCABDARMBFQBEAScBKQBHASwBLABKAS4BLgBLAUUBRQBMAWUBawBNAW8BcABUAewB7QBWAe8B7wBYAfECFwBZAhwCIQCAAiYCNgCGAjgCQQCXAkoCTAChAk4CTgCkAlACUAClAlICUgCmAlQCVACnAlcCVwCoAlkCWQCpAlsCWwCqAl0CXQCrAl8CXwCsAmECYQCtAmMCbwCuAnECcQC7AnMCcwC8AnUCdQC9AoACgAC+AoICggC/AoQChADAAoYChgDBAogCiADCAooCigDDAowCjADEAo4CjgDFApACkADGApICkgDHApQCnADIAvgC/QDRAwADDwDXAxIDEgDnAxYDFgDoAxgDGADpAxwDHADqAx8DIADrAyIDKwDtAy0DLwD3AzEDNgD6AzgDPgEAA0QDRQEHA0cDRwEJA0kDSQEKA0sDTgELA1IDVwEPA1oDWgEVA1wDXAEWA2ADYQEXA2YDcQEZA3QDdQElA3cDegEnA4EDggErA4YDhgEtA4gDjgEuA5MDlAE1A5gDwAE3A8IDwgFgA8QD0QFhA9kD2QFvA9wD3AFwA94D3gFxA+oD7wFyA/ID8gF4A/QD9AF5A/YD9gF6A/gD+QF7A/4EAQF9BAQEBAGBBAYEBwGCBAkECQGEBA0EDQGFBA8EDwGGBBMEEwGHAAIBOAAEAAQAHQAJAAkAHQAOAA4AHgAQABAAHgAkACQAAQAlACUABAAmACYAAwAnACcABQAqACsAAgAsACwADAAtAC0ACQAuAC4ACgAvADAAAgAxADEAAwAyADIACwA2ADYABgA3ADcADAA4ADgADQA5ADkAEAA6ADoADgA7ADsADwA8ADwAEQBDAEMAEwBEAEQAFQBFAEUAFABHAEcAFgBKAEoAFwBPAFAAFwBRAFEAGABSAFIAFQBUAFQAGgBYAFgAGQBaAFoAGwBbAFsAGQBcAFwAHACIAIgAFQCsAKwABwCuAK4AAwC4ALgAGQC8ALwAFwDCAMIAFQDPANAAHwDSANIAAgDVANUADgDXANgAAgDZANkAEgDbANsAAgDdAN0AAgDfAN8AHwDhAOEAHwDnAOcACADpAOkAGwDyAPIAFQD3APcAIAD5APkAIAD6APoAFQD/AQAAIAEFAQUAIAETARMAGAEUARQADQEVARUAGQEnAScAFQEoASgABwEpASkACAEsASwACQEuAS4ACQFFAUUACAFlAWYAHQFnAWcAHgFoAWoAHQFrAWsAHgFvAXAAHgHsAe0AAwHvAe8ABgH4AfgABAH5AfwABQH9AgEAAgICAgYAAwIHAgoADAILAgsADwIMAhIAEwITAhMAFAIUAhcAFgIcAhwAFwIdAiEAGAImAicAGQIpAikAEwIrAisAEwItAi0AEwIuAi4ABAIvAi8AFAIwAjAABAIxAjEAFAIyAjIABAIzAjMAFAI0AjQABAI1AjUAFAI2AjYAAwI4AjgABQI5AjkAFgI6AjoABQI7AjsAFgI8AjwABQI9Aj0AFgI+Aj4ABQI/Aj8AFgJAAkAABQJBAkEAFgJKAkoAAgJLAksAFwJMAkwAAgJOAk4AAgJQAlAAAgJSAlIAAgJUAlQAAgJXAlcADAJZAlkACQJbAlsACgJdAl0ACgJfAl8ACgJhAmEACgJjAmMAAgJkAmQAFwJlAmUAAgJmAmYAFwJnAmcAAgJoAmkAFwJqAmoAAwJrAmsAGAJsAmwAAwJtAm0AGAJuAm4AAwJvAm8AGAJxAnEAGgJzAnMAGgJ1AnUAGgKAAoAABgKCAoIABgKEAoQABgKGAoYADAKIAogADAKKAooADAKMAowADAKOAo4ADAKQApAADAKSApIAEAKUApQADwKVApUAGQKWApYADwKXApcAEQKYApgAHAKZApkAEQKaApoAHAKbApsAEQKcApwAHAL5AvkABQL6AvsAAgL8AvwAAwL9Av0ADwMBAwEAAQMCAwIABQMDAwMAEQMEAwUAAgMGAwYACQMHAwgAAgMJAwkAAwMKAwoACwMLAwsABgMMAwwADwMNAw0ADgMOAw4AAgMPAw8ADwMSAxIAFwMWAxYAGAMYAxgAGQMcAxwAGAMfAx8ABQMgAyAABwMiAyMAAgMkAyQADAMlAyYACQMnAycAEgMpAykAAQMqAyoABwMrAysABQMtAy4AAgMvAy8AAwMxAzEACwMyAzIABAMzAzMABgM0AzQADgM1AzUAEwM2AzYAFgM4AzgAGAM5AzkAFQM6AzoAFAM7AzsAGQM8AzwAGwM9Az0AFgM+Az4ACANEA0QAGQNFA0UAEANHA0cAEANJA0kAEANLA0sADwNMA0wAGQNNA04AHQNSA1IAHQNTA1MAAgNUA1QAFwNWA1YAEwNXA1cAAwNaA1oABQNcA1wAFgNgA2AADQNhA2EAGQNmA2YABANnA2cAFANoA2gADwNpA2kAGQNqA2oAAgNrA2sADgNsA2wAGwNtA20AAgNvA28AEwNxA3EAEwN0A3QABQN1A3UAFgN3A3gAFgN5A3kADgN6A3oAGwOBA4EAAwOCA4IAGAOGA4YAGAOIA4gAFQOJA4kAEgOKA4oAGQOLA4sAEgOMA4wAGQONA40AEgOOA44AGQOTA5MADgOUA5QAGwOZA5kAEwObA5sAEwOdA50AEwOfA58AEwOhA6EAEwOjA6MAEwOlA6UAEwOnA6cAEwOpA6kAEwOrA6sAEwOtA60AEwOvA68AEwOwA7AABQOxA7EAFgOyA7IABQOzA7MAFgO0A7QABQO1A7UAFgO2A7YABQO3A7cAFgO4A7gABQO5A7kAFgO6A7oABQO7A7sAFgO8A7wABQO9A70AFgO+A74ABQO/A78AFgPAA8AAAgPCA8IAAgPEA8QAAwPFA8UAGAPGA8YAAwPHA8cAGAPIA8gAAwPJA8kAGAPKA8oAAwPLA8sAGAPMA8wAAwPNA80AGAPOA84AAwPPA88AGAPQA9AAAwPRA9EAGAPZA9kAGAPcA9wADAPeA94ADAPqA+oADwPrA+sAGQPsA+wADwPtA+0AGQPuA+4ADwPvA+8AGQPyA/IACQP0A/QAAgP2A/YABgP4A/gADgP5A/kAGwP+A/4ABwP/A/8ACAQABAAADgQBBAEAGwQEBAQAFwQGBAYAHwQHBAcABwQJBAkACQQNBA0AAgQPBA8AAgQTBBMADwABAAQEFgAHAAAAAAAAAAAABwAAAAAAAAAAABMAFwATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEAAAAFAAAAAAAAAAUAAAAAABwAAAAAAAAAAAAFAAAABQAAABkACgAGAA0ACQASAA4AFAAAAAAAAAAAAAAAAAAaAAAAFQAVABUAAAAVAAAAAAAAAAAAAAAYABgACAAYABUAAAAbAAAACwACAAAAFgACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAVAAAAAAAFABUAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEABQARAAAAAAAAAAAAAAAAABUAAAACAAAAAAAAABgAAAAAAAAAAAAAAAAAFQAVAAAACwAAAAAAAAAAAAAAAAAKAAUAAQAAAAoAAAAAAAAAEgAAAAAAAQAQAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAABYAAAAYABgABAAYABgAGAAAABUAGAADABgAGAAAAAAAGAAAABgAAAAAABUABAAYAAAAAAAFAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAFAAgADQACAAUAAAAFABUABQAAAAUAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAABgAAAAAAAUAFQAKAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAYAAAAFQAVAAAAAAAAAAAAAQAAAAAAAAAFABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFwAXAAAABwAHABMABwAHAAcAEwAAAAAAAAATABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAAAAAAAAAAAAAABEAEQARABEAEQARABEABQAAAAAAAAAAAAAAAAAAAAAAAAAFAAUABQAFAAUABgAGAAYABgAOABoAGgAaABoAGgAaABoAFQAVABUAFQAVAAAAAAAAAAAAGAAIAAgACAAIAAgACwALAAsACwACAAIAEQAaABEAGgARABoABQAVAAUAFQAFABUABQAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAUAFQAFABUABQAVAAUAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAABgAAAAYABgABQAIAAUACAAFAAgAAAAAAAAAAAAAAAAAGQAbABkAGwAZABsAGQAbABkAGwAKAAAACgAAAAoAAAAGAAsABgALAAYACwAGAAsABgALAAYACwAJAAAADgACAA4AFAAMABQADAAUAAwAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAUADgAAAAAAEQAAAAAAFAAAAAAAAAAAAAAABQAAAAAADgASAAAADgAVAAAAGAAAAAsAAAAIAAAAAgAAAAAACwAIAAsAAAAAAAAAAAAAAAAAHAAAAAAAEAARAAAAAAAAAAAAAAAAAAUAAAAAAAUACgASABoAFQAYAAgAGAAVAAIAFgAVABgAGwAAAAAAAAAYAAIACQAAAAkAAAAJAAAADgACAAcABwAAAAAAAAAHAAAAGAARABoABQAAAAAAAAAAABUAGAAAAAAADQACABUABQAAAAAABQAVAA4AAgAAABIAFgAAABEAGgARABoAAAAAAAAAFQAAABUAFQASABYAAAAAAAAAGAAAABgABQAIAAUAFQAFAAgAAAAAABAAAgAQAAIAEAACAA8AAwAAABgAEgAWABUAAQAEABEAGgARABoAEQAaABEAGgARABoAEQAaABEAGgARABoAEQAaABEAGgARABoAEQAaAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAAAAAAAAAFAAgABQAIAAUACAAFAAgABQAIAAUACAAFAAgABQAVAAUAFQAFABUABQAIAAUAFQAGAAsABgALAAAACwAAAAsAAAALAAAACwAAAAsADgACAA4AAgAOAAIAAAAAAAAAGAAAABgACgAAABIAFgAPAAMADwADAAAAGAASABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAGAAAABgAAQAEAA4AAAAAAAAAAAAAABcAAQAAAAoALACOAAFERkxUAAgABAAAAAD//wAIAAAAAQACAAMABAAFAAYABwAIbGlnYQAybG51bQA4c21jcAA+c3MwMQBEc3MwMgBKc3MwMwBQc3MwNABWc3MwNQBcAAAAAQABAAAAAQACAAAAAQAAAAAAAQADAAAAAQAEAAAAAQAFAAAAAQAGAAAAAQAHAAgAEgAaACIAKgAyADoAQgBKAAEAAAABAEAABAAAAAEB9gABAAAAAQIAAAEAAAABAhIAAQAAAAECEAABAAAAAQIOAAEAAAABAgwAAQAAAAECDgACAhAA3AGmAacBqAGpAaoBqwGsAa0BrgGvAbABsQGyAbMBtAHoAbUBtgG3AbgBuQG6AbsBvAG9Ab4BpgGnAagBqQGqAasBrAGtAa4BrwGwAbEBsgGzAbQB6AG1AbYBtwG4AbkBugG7AbwBvQG+AvcCogKhAqICowKjAqQCpQKmAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArYCtwK4ArkCugK7ArwCvQK+AqQCpQKmAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArYCtwK4ArkCugK7ArwCvQK+AvMCvwK/AsACwALBAsECwgLCAsMCwwLFAsUCxgLGAscCxwLIAsgCyQLJAsoCygLLAssCzALMAs0CzQLPAs8C0ALQAtEC0QLSAtIC0wLTAtQC1ALVAtYC1gLXAtcC2ALYAtkC2QLaAtoC2wLbAtwC3ALdAt0C3gLeAt8C3wLgAuAC4QLhAuIC4gLjAuMC5ALkAuUC5QLmAuYC5wLnAugC6P////8C6gLqAusC6wLsAuwC7QLtAu4C7gLvAu8C8ALwAvEC8QLyAvIC8wL0AvQC9QL1AvYC9gKhAAEApAABAAgAAQAEAZIAAgBLAAIAmAAKAZgBzAHEAdYB1wHYAdkB2wHdAecAAQCIAZEAAQCIASgAAQCIAa4AAgCIAAIB4wHkAAIAfgACAeUB5gACAA0AIwA8AAAAQwBcABoAgwCDADQAhQCFADUB7AHtADYB7wIxADgCNAJFAHsCSAJUAI0CVwJoAJoCagJ7AKwCfgJ/AL4CggKcAMAD8APwANsAAQABAEgAAgABABIAGwAAAAEAAQBJAAEAAQC2AAEAAQA0AAEAAgAtAE0=","Roboto-Medium.ttf":"AAEAAAAOAIAAAwBgR0RFRgsuCy8AASxgAAAASEdQT1OQeyOPAAEsqAAAl/pHU1VCeolvLwABxKQAAANsT1MvMrkTKcoAAAFoAAAAYFZETVhu6nZPAAASOAAABeBjbWFwf76BZgAAGBgAAA7iZ2x5Zm8zqQ4AACb8AADUQGhlYWT1Pw7VAAAA7AAAADZoaGVhCx4JIwAAASQAAAAkaG10eLpNNCcAAAHIAAAQcGxvY2EEms7QAAD7PAAACDptYXhwBDsA9gAAAUgAAAAgbmFtZb10XwMAAQN4AAAEn3Bvc3Tfb5xiAAEIGAAAJEYAAQAAAAEAAF5SMstfDzz1AAkIAAAAAADE8BEuAAAAAM2CsnL6JP3VCYsIYgAAAAkAAgAAAAAAAAABAAAHbP4MAAAJnfok/V0JiwABAAAAAAAAAAAAAAAAAAAEHAABAAAEHACXABYAXQAFAAEAAAAAAAAAAAAAAAAAAwABAAME3gH0AAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAAAAAAAAAAAAAAA4AAC/1AAIFsAAAAgAAAAAHB5cnMAAAAA//0GAP4AAGYHmgIAIAABn08BAAAEOgWwAAAAIAACAf4AAAAAAAAB/gAAAf4AAAKYAFIE4gA8BIwAZAXgAGQFHQA+AVoAUgK3AIACvAARA38AGwR1AEQBwgAnAqAARwI8AJkDKgACBIwAaASMAMoEjABRBIwATwSMADgEjACBBIwAdASMAEUEjABhBIwAUgIlAJkCIABRBBEAPwSOAJEEKgCAA+QAKQchAEoFQgAaBSAAnwUgAHQFYgCfBKMAnwShAJ8FbQB0BbAAnwJNAK0EfAA6BSgAnwRkAJ8HAgCfBbAAnwWPAHQFKwCfBZAAdAVFAJ8E8wBTBOoANQV0AIYFKwAaBwIARAUUAC8FAwATBMAAWAIxAIQDVwAVAjEADANrADUDnAADApQASgRaAF4EiACABDMAUQSIAFMEPABZAs8AMQSIAFQEiAB9AhMAkAIZ/7AEMACBAhMAkAb1AIAEiAB+BIgAUwSIAIAEiABTAtoAgAQpAFECnQAZBIgAewQOACAF+gAlBA4AIQQOABAEDgBVAq8AOAICAK4CrwAbBVEAdQIeAI8EfQBoBLUAUQWdAF0E4AAaAfwAiAT4AFoEHgCkBkQAVwORAHQD4gBUBG0AfwZEAFcD2wCHAwoAfwRLAF8DYQBtA2MAYQKxAHgEuwCSBBAAPgJCAKACEABtAjUAZAOnAHcD4gBcBgwAmwZmAJMG0wBmBAEAYAeF//YERABNBXoAaQTKAJQE5wCIBsEANAS6ADwEkQBDBIkAUwSXAIcFogAYAhoAjwSYAI4EJAAbAj8AGwWSAJMEiAB+B7QAZQc6AFsCDACLAtD/3QWJAGYEnwBSBaUAhgTyAHsCJv+1BDwAWQPmAJsDsAB5A3wAdQJPAJoCsgCCAk0AKQPYAIADLwB6ApwAqwAA/NsAAP02AAD8eQAA/T4AAPwMAAD9IgJdANcEPACdAkIAoAR1AJ8FvQAaBXsAZgU5ACMEkQBwBbEAnwSRAEcF6wBLBacASAVbAGwEhABWBMYAlgQOACAEiABUBGAAYAQaAGEEiAB+BKIAcwKmAKkEagAWBBMAZAT3AE8EiACABDcAUgSQAFIELgBABGAAgAXQAEQFyQBPBpQAZgUuAHUEdf/uBnEAMwX/ACQFPgByCIoALgiRAJ8GXwA1BasAmQUIAJQGBwAmB5oAGATTAEoFqgCaBakALgUKAD8GYABPBfYAmQWIAI8HmgCeB/oAngYaABgG+QCfBQcAlAU8AIgHVACqBPsALQR9AFsEjwCPA1oAhQT2ACcGdgAXBBYATQSYAIYEbgCPBJoAHwYDAI8ElwCGBJgAhgP1ACMF0wBUBNMAhgRmAF8GjgCGBuwAfgUYAB8GbwCPBGgAjwQ8AFEGhACQBHAAJwSJ/+EEPQBYBtEAHwbkAIYEif/1BJgAhgdDAI0GTwBwBGf/4AcpAKIGAQCGBQcAIARgAAoHQgC2BjYAnQbtAIQF5gCCCTIArQf5AI8EIQApA/AAMwV7AGoEiQBSBRkAEQQOACAFewBqBIkAUwc+AI0GRAB0B0MAjQZQAHAFHQBqBEoAXAT/AG0AAPxmAAD8cwAA/XsAAP2lAAD6JP7p+k0EZ//gBRQAnwSHAIAEagCUA6IAfgS3AJ8EIAB+BSoAlASrAI4GlgA0BaQAPgfRAJ8FqwB+CEcAnwb1AH4GJQBpBP8AYQcyAC4FcQAmBXUAggRzAHQFhwCKBiYAIATE/84FHwCUBHgAjgWwAJ8EiAB+BYgAUwSmAF0EpgBdBMcAOwNTADQFBwBUBusAZgbdAF4GUwA7BSgALwR7AEkEPwB1B74AQwadAD8H/gCYBp4AdwUDAGIELABVBaoAIgUdAEQFVwCHBBQAAAgpAAAEFAAACCkAAAK5AAACCgAAAVwAAAR/AAACMAAAAaIAAADRAAAAAAAABYcArQaBALIDnQAEAcAAYAG8ADMBzgAyAagARwMUAGIDGwBAAwgAMgRdAEAEmQBcAssAiAP6AJwFpgCcB6gASwJyAGwCaQBUA5wALQOpAD8DXABpBLUATwa4AJkETQBLBeUAcQPiAEUIyACYBQkAZAUUAJYGyQBpB2EAageRAGoG7wBqBLsAQwWWAKYE2QBABIMAngSyADsIRQBkAiH/sgSOAGUETACYBEYAqgRLAKAEGgAkAlsAswKYAGMB8QBFBKgAGAAAAAAIMABZCDUAXAQyAE0DiwBNBJMAbAMn/58CEP+wAk0AGAGzAFwDoQB1A6EAdQOhAHUECwB5BAsAdQQL/0wECwB6A6EAWwIFAJAEyAAcBIwAjgSUAGgErwCOBEcAjgQqAI4E2wBoBRIAjgIVAI4EFwAuBHcAjgO9AI4GBgCOBSEAjgTKAGYE3QBoBKgAjgRwAE8EMgA8BQAAfgSxABwGDgA0BIwALARVABMETQBKBIYAbQKFAD4D/wBSBCIATQRlADkEfABRBD0AbQOvADwEQwBSBCoAPwIzAFcDVQBrA2YAYAL9ADgDdgBoA3YAcAMAAFIDgwBoA2YAYAOfAHADuQCXArIAlgNCAGwEjABPBIwAOASMAIEEmAB0BDsACgQ0ADIEYgA+BIwAYQS7AFYEiABTBUkAnwRaAGAFMgCfBSgAnwQwAIEFOgCfBC0AgQSNAFIEjACOA3wAdQH+AAACoABHBYAAJAWAACQEpv/9BOoANQKd/+cFQgAaBUIAGgVCABoFQgAaBUIAGgVCABoFQgAaBSAAdASjAJ8EowCfBKMAnwSjAJ8CTf/MAk0ArQJN/9gCTf+9BbAAnwWPAHQFjwB0BY8AdAWPAHQFjwB0BXQAhgV0AIYFdACGBXQAhgUDABMEWgBeBFoAXgRaAF4EWgBeBFoAXgRaAF4EWgBeBDMAUQQ8AFkEPABZBDwAWQQ8AFkCGv+vAhoAjwIa/7sCGv+gBIgAfgSIAFMEiABTBIgAUwSIAFMEiABTBIgAewSIAHsEiAB7BIgAewQOABAEDgAQBUIAGgRaAF4FQgAaBFoAXgVCABoEWgBeBSAAdAQzAFEFIAB0BDMAUQUgAHQEMwBRBSAAdAQzAFEFYgCfBR4AUwSjAJ8EPABZBKMAnwQ8AFkEowCfBDwAWQSjAJ8EPABZBKMAnwQ8AFkFbQB0BIgAVAVtAHQEiABUBW0AdASIAFQFbQB0BIgAVAWwAJ8EiAB9Ak3/vwIa/6ICTf+/Ahr/ogJN/+UCGv/IAk0AHAIT//4CTQCjBskArQQsAJAEfAA6Aib/tQUoAJ8EMACBBGQAnwITAJAEZACfAhMAWARkAJ8CqQCQBGQAnwLvAJAFsACfBIgAfgWwAJ8EiAB+BbAAnwSIAH4EiP/VBY8AdASIAFMFjwB0BIgAUwWPAHQEiABTBUUAnwLaAIAFRQCfAtoAVgVFAJ8C2gBDBPMAUwQpAFEE8wBTBCkAUQTzAFMEKQBRBPMAUwQpAFEE8wBTBCkAUQTqADUCnQAZBOoANQKdABkE6gA1AsUAGQV0AIYEiAB7BXQAhgSIAHsFdACGBIgAewV0AIYEiAB7BXQAhgSIAHsFdACGBIgAewcCAEQF+gAlBQMAEwQOABAFAwATBMAAWAQOAFUEwABYBA4AVQTAAFgEDgBVB4X/9gbBADQFegBpBIkAUwSv/+oEr//qBDIAPATIABwEyAAcBMgAHATIABwEyAAcBMgAHATIABwElABoBEcAjgRHAI4ERwCOBEcAjgIV/6wCFQCOAhX/uAIV/50FIQCOBMoAZgTKAGYEygBmBMoAZgTKAGYFAAB+BQAAfgUAAH4FAAB+BFUAEwTIABwEyAAcBMgAHASUAGgElABoBJQAaASUAGgErwCOBEcAjgRHAI4ERwCOBEcAjgRHAI4E2wBoBNsAaATbAGgE2wBoBRIAjgIV/58CFf+fAhX/xQIV//kCFQCEBBcALgR3AI4DvQCOA70AjgO9AI4DvQCOBSEAjgUhAI4FIQCOBMoAZgTKAGYEygBmBKgAjgSoAI4EqACOBHAATwRwAE8EcABPBHAATwQyADwEMgA8BQAAfgUAAH4FAAB+BQAAfgUAAH4FAAB+Bg4ANARVABMEVQATBE0ASgRNAEoETQBKCOAATwVCABoFB/+vBhT/3AKx/+MFowAqBWf/ZwVvABMCpv+wBUIAGgUgAJ8EowCfBMAAWAWwAJ8CTQCtBSgAnwcCAJ8FsACfBY8AdAUrAJ8E6gA1BQMAEwUUAC8CTf+9BQMAEwSEAFYEYABgBIgAfgKmAKkEYACABJgAjgSIAFMEuwCSBA4AIAQOACECpv/EBGAAgASIAFMEYACABpQAZgSjAJ8EdQCfBPMAUwJNAK0CTf+9BHwAOgUoAJ8FKACfBQoAPwVCABoFIACfBHUAnwSjAJ8FqgCaBwIAnwWwAJ8FjwB0BbEAnwUrAJ8FIAB0BOoANQUUAC8EWgBeBDwAWQSYAIYEiABTBIgAgAQzAFEEDgAQBA4AIQQ8AFkDWgCFBCkAUQITAJACGv+gAhn/sARuAI8EDgAQBwIARAX6ACUHAgBEBfoAJQcCAEQF+gAlBQMAEwQOABABWgBSApgAUgRKAJoE4gAxAib/tQG8ADMHAgCfBvUAgAVCABoEWgBeBY//PQd3ADEHsQAxBKMAnwWqAJoEPABZBJgAhgWnAEgFyQBPBRkAEQQO/+MIlgBTCZ0AdATTAEoEFgBNBSAAdAQzAFEFAwATBA4AIAJNAK0HmgAYBnYAFwJNAK0FQgAaBFoAXgVCABoEWgBeB4X/9gbBADQEowCfBDwAWQWIAFMEPABZBDwAWQeaABgGdgAXBNMASgQWAE0FqgCaBJgAhgWqAJoEmACGBY8AdASIAFMFewBqBIkAUgV7AGoEiQBSBTwAiAQ8AFEFCgA/BA4AEAUKAD8EDgAQBQoAPwQOABAFiACPBGYAXwb5AJ8GbwCPBRQALwQOACEEiABTBakALgSaAB8FQgAaBFoAXgVCABoEWgBeBUIAGgRaAF4FQgAEBFr/iQVCABoEWgBeBUIAGgRaAF4FQgAaBFoAXgVCABoEWgBeBUIAGgRaAF4FQgAaBFoAXgVCABoEWgBeBUIAGgRaAF4EowCfBDwAWQSjAJ8EPABZBKMAnwQ8AFkEowCfBDwAWQSj/8wEPP+LBKMAnwQ8AFkEowCfBDwAWQSjAJ8EPABZAk0ArQIaAI8CTQCfAhMAggWPAHQEiABTBY8AdASIAFMFjwB0BIgAUwWPACsEiP+mBY8AdASIAFMFjwB0BIgAUwWPAHQEiABTBYkAZgSfAFIFiQBmBJ8AUgWJAGYEnwBSBYkAZgSfAFIFiQBmBJ8AUgV0AIYEiAB7BXQAhgSIAHsFpQCGBPIAewWlAIYE8gB7BaUAhgTyAHsFpQCGBPIAewWlAIYE8gB7BQMAEwQOABAFAwATBA4AEAUDABMEDgAQBKYAUwSmAFMFKACfBG4AjwWwAJ8ElwCGBOoANQP1ACMFFAAvBA4AIQWIAI8EZgBfBYgAjwRmAF8EdQCfA1oAhQeaABgGdgAXBiYAIATE/84EiAB9BQf/1wUH/9cEdf/3A1r/6QU8/90ERP/MBaoAmgSYAIYFsACfBJcAhgcCAJ8GAwCPBakALgSaAB8FAwATBA4AIAUUAC8EDgAhBGAAYAShABYGgQCyAAAAAAIlAJoAAAABAAEBAQEBAAwA+Aj/AAgACP/+AAkACf/9AAoACv/9AAsAC//9AAwADP/9AA0ADf/8AA4ADv/8AA8AD//8ABAAEP/8ABEAEf/7ABIAEv/7ABMAE//7ABQAFP/7ABUAFP/6ABYAFf/6ABcAFv/6ABgAF//6ABkAGP/5ABoAGf/5ABsAGv/5ABwAG//5AB0AHP/4AB4AHf/4AB8AHv/4ACAAH//4ACEAIP/3ACIAIf/3ACMAIv/3ACQAI//3ACUAJP/2ACYAJf/2ACcAJv/2ACgAJ//2ACkAJ//1ACoAKP/1ACsAKf/1ACwAKv/1AC0AK//0AC4ALP/0AC8ALf/0ADAALv/0ADEAL//zADIAMP/zADMAMf/zADQAMv/zADUAM//yADYANP/yADcANf/yADgANv/yADkAN//xADoAOP/xADsAOf/xADwAOv/xAD0AOv/wAD4AO//wAD8APP/wAEAAPf/wAEEAPv/vAEIAP//vAEMAQP/vAEQAQf/vAEUAQv/uAEYAQ//uAEcARP/uAEgARf/uAEkARv/tAEoAR//tAEsASP/tAEwASf/tAE0ASv/sAE4AS//sAE8ATP/sAFAATf/sAFEATf/rAFIATv/rAFMAT//rAFQAUP/rAFUAUf/qAFYAUv/qAFcAU//qAFgAVP/qAFkAVf/pAFoAVv/pAFsAV//pAFwAWP/pAF0AWf/oAF4AWv/oAF8AW//oAGAAXP/oAGEAXf/nAGIAXv/nAGMAX//nAGQAYP/nAGUAYP/mAGYAYf/mAGcAYv/mAGgAY//mAGkAZP/lAGoAZf/lAGsAZv/lAGwAZ//lAG0AaP/kAG4Aaf/kAG8Aav/kAHAAa//kAHEAbP/jAHIAbf/jAHMAbv/jAHQAb//jAHUAcP/iAHYAcf/iAHcAcv/iAHgAc//iAHkAc//hAHoAdP/hAHsAdf/hAHwAdv/hAH0Ad//gAH4AeP/gAH8Aef/gAIAAev/gAIEAe//fAIIAfP/fAIMAff/fAIQAfv/fAIUAf//eAIYAgP/eAIcAgf/eAIgAgv/eAIkAg//dAIoAhP/dAIsAhf/dAIwAhv/dAI0Ahv/cAI4Ah//cAI8AiP/cAJAAif/cAJEAiv/bAJIAi//bAJMAjP/bAJQAjf/bAJUAjv/aAJYAj//aAJcAkP/aAJgAkf/aAJkAkv/ZAJoAk//ZAJsAlP/ZAJwAlf/ZAJ0Alv/YAJ4Al//YAJ8AmP/YAKAAmf/YAKEAmf/XAKIAmv/XAKMAm//XAKQAnP/XAKUAnf/WAKYAnv/WAKcAn//WAKgAoP/WAKkAof/VAKoAov/VAKsAo//VAKwApP/VAK0Apf/UAK4Apv/UAK8Ap//UALAAqP/UALEAqf/TALIAqv/TALMAq//TALQArP/TALUArP/SALYArf/SALcArv/SALgAr//SALkAsP/RALoAsf/RALsAsv/RALwAs//RAL0AtP/QAL4Atf/QAL8Atv/QAMAAt//QAMEAuP/PAMIAuf/PAMMAuv/PAMQAu//PAMUAvP/OAMYAvf/OAMcAvv/OAMgAv//OAMkAv//NAMoAwP/NAMsAwf/NAMwAwv/NAM0Aw//MAM4AxP/MAM8Axf/MANAAxv/MANEAx//LANIAyP/LANMAyf/LANQAyv/LANUAy//KANYAzP/KANcAzf/KANgAzv/KANkAz//JANoA0P/JANsA0f/JANwA0v/JAN0A0v/IAN4A0//IAN8A1P/IAOAA1f/IAOEA1v/HAOIA1//HAOMA2P/HAOQA2f/HAOUA2v/GAOYA2//GAOcA3P/GAOgA3f/GAOkA3v/FAOoA3//FAOsA4P/FAOwA4f/FAO0A4v/EAO4A4//EAO8A5P/EAPAA5f/EAPEA5f/DAPIA5v/DAPMA5//DAPQA6P/DAPUA6f/CAPYA6v/CAPcA6//CAPgA7P/CAPkA7f/BAPoA7v/BAPsA7//BAPwA8P/BAP0A8f/AAP4A8v/AAP8A8//AAAAAAwAAAAMAAAiEAAEAAAAAABwAAwABAAACJgAGAgoAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAEAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAMEGwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYAAAAfUB9gH4AfoCAQIGAgoCDQIMAg4CEAIPAhECEwIVAhQCFgIXAhkCGAIaAhsCHAIeAh0CHwIhAiACIwIiAiQCJQFsAG8AYgBjAGcBbgB1AIMAbQBpAX0AcwBoAYsAfwCBAYgAcAGMAY0AZQB0AYMBhQGEAMEBiQBqAHkAtQCEAIcAfgBhAGwBhwCTAYoArQBrAHoBcAADAfEB9AIFAJAAkQFiAWMBaQFqAWUBZgCGAY4CJwKWAXQBeQFyAXMBkgNQAW0AdgFnAWsBcQHzAfsB8gH8AfkB/gH/AgAB/QIDAgQAAAICAggCCQIHAIoAmgCgAG4AnACdAJ4AdwChAJ8AmwAEBl4AAADqAIAABgBqAAAAAgANACEAfgCgAKwArQC/AMYAzwDmAO8A/gEPAREBJQEnATABOAFAAVMBXwFnAX4BfwGSAaEBsAHwAfsB/wIZAhsCNwJZArwCxwLJAt0C8wMBAwMDCQMPAyMDigOMA5IDoQOwA7kDyQPOA9ID1gQlBC8ERQRPBGIEbwR5BIYEzgTXBOEE9QUBBRAFEx4BHj8ehR7xHvMe+R9NIAsgFSAeICIgJiAwIDMgOiA8IEQgdCB/IKQgpyCsIQUhEyEWISIhJiEuIV4iAiIGIg8iEiIaIh4iKyJIImAiZSXK7gL2w/sE/v///f//AAAAAAACAA0AIAAiAKAAoQCtAK4AwADHANAA5wDwAP8BEAESASYBKAExATkBQQFUAWABaAF/AZIBoAGvAfAB+gH8AhgCGgI3AlkCvALGAskC2ALzAwADAwMJAw8DIwOEA4wDjgOTA6MDsQO6A8oD0QPWBAAEJgQwBEYEUARjBHAEegSIBM8E2ATiBPYFAgURHgAePh6AHqAe8h70H00gACATIBcgICAlIDAgMiA5IDwgRCB0IH8goyCnIKshBSETIRYhIiEmIS4hWyICIgYiDyIRIhoiHiIrIkgiYCJkJcruAfbD+wH+///8//8AAQQY//UAAP/iAAD/wAAA/78AAAExAAABLAAAASgAAAEmAAABJAAAASIAAAEcAAABHgAA/wH+9P7nAWEAAAChAGQAZv5h/kAAlv3U/aX9xP2v/aP9ov2d/Zj9hQAA/3D/bwAAAAD9BQAA/1D8+fz2AAD8tQAA/K0AAPyiAAD8nAAA/p4AAP6bAAD8RQAA5VXlFeTF5PjkWeT25ArhVgAA4U3hTOFK4UHjG+E54xPhMOEB4PcAAODRAADgdeBo4GbgW9+P4FDgJN+B3qffdd90323fat9e30LfK98o28QTjgrOAAAClAGYAAEAAAAAAAAA5AAAAOQAAADiAAAA4AAAAOoAAAEUAAABLgAAAS4AAAEuAAABOgAAAVwAAAFoAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEAAAAAAFMAWgAAAGAAAAAAAAAAZgAAAHgAAACCAAAAioAAAI6AAACxAAAAtQAAALoAAAAAAAAAAAAAAAAAAAAAALcAAAAAAAAAAAAAAAAAAAAAAAAAAACzAAAAswAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqYAAAAAAAAAAwQbAeoB6wHxAfIB8wH0AfUB9gB/Ae0CAQICAgMCBAIFAgYAgACBAgcCCAIJAgoCCwCCAIMCDAINAg4CDwIQAhEAhACFAhwCHQIeAh8CIAIhAIYAhwIiAiMCJAIlAiYAiAHsA/AAiQHuAIoCVQJWAlcCWAJZAloAiwCMAI0CYwJkAmUCZgJnAmgCaQCOAI8CagJrAmwCbQJuAm8AkACRAn4CfwKCAoMChAKFAe8B8ACSAfcCEgCpAKoC+ACrAvkC+gL7AKwArQMCAwMDBACuAwUDBgCvAwcDCACwAwkAsQMKALIDCwMMALMDDQC0ALUDDgMPAxADEQMSAxMDFAMVAL8DFwMYAMADFgDBAMIAwwDEAMUAxgDHAxkAyADJA1oDHwDNAyAAzgMhAyIDIwMkAM8A0ADRAyYDWwMnANIDKADTAykDKgDUAysA1QDWANcDLAMlANgDLQMuAy8DMAMxAzIDMwDZANoDNAM1AOUA5gDnAOgDNgDpAOoA6wM3AOwA7QDuAO8DOADwAzkDOgDxAzsA8gM8A1wDPQD9Az4A/gM/A0ADQQNCAP8BAAEBA0MDXQNEAQIBAwEEBAYDXgNfARIBEwEUARUDYANhA2MDYgEjASQECwQMBAUBJQEmAScBKAEpBAcECAEqASsEAAQBA2QDZQPyA/MBLAEtBAkECgEuAS8D9AP1ATABMQEyATMBNAE1A2YDZwP2A/cDaANpBBMEFAP4A/kBNgE3A/oD+wE4ATkBOgQEATsBPAQCBAMDagNrA2wBPQE+BBEEEgE/AUAEDQQOA/wD/QQPBBABQQN3A3YDeAN5A3oDewN8AUIBQwP+A/8DkQOSAUQBRQOTA5QEFQQWAUYDlQQXA5YDlwFiAWMEGQQYAXcD8QF5AZIDUANYA1kABAZeAAAA6gCAAAYAagAAAAIADQAhAH4AoACsAK0AvwDGAM8A5gDvAP4BDwERASUBJwEwATgBQAFTAV8BZwF+AX8BkgGhAbAB8AH7Af8CGQIbAjcCWQK8AscCyQLdAvMDAQMDAwkDDwMjA4oDjAOSA6EDsAO5A8kDzgPSA9YEJQQvBEUETwRiBG8EeQSGBM4E1wThBPUFAQUQBRMeAR4/HoUe8R7zHvkfTSALIBUgHiAiICYgMCAzIDogPCBEIHQgfyCkIKcgrCEFIRMhFiEiISYhLiFeIgIiBiIPIhIiGiIeIisiSCJgImUlyu4C9sP7BP7///3//wAAAAAAAgANACAAIgCgAKEArQCuAMAAxwDQAOcA8AD/ARABEgEmASgBMQE5AUEBVAFgAWgBfwGSAaABrwHwAfoB/AIYAhoCNwJZArwCxgLJAtgC8wMAAwMDCQMPAyMDhAOMA44DkwOjA7EDugPKA9ED1gQABCYEMARGBFAEYwRwBHoEiATPBNgE4gT2BQIFER4AHj4egB6gHvIe9B9NIAAgEyAXICAgJSAwIDIgOSA8IEQgdCB/IKMgpyCrIQUhEyEWISIhJiEuIVsiAiIGIg8iESIaIh4iKyJIImAiZCXK7gH2w/sB/v///P//AAEEGP/1AAD/4gAA/8AAAP+/AAABMQAAASwAAAEoAAABJgAAASQAAAEiAAABHAAAAR4AAP8B/vT+5wFhAAAAoQBkAGb+Yf5AAJb91P2l/cT9r/2j/aL9nf2Y/YUAAP9w/28AAAAA/QUAAP9Q/Pn89gAA/LUAAPytAAD8ogAA/JwAAP6eAAD+mwAA/EUAAOVV5RXkxeT45Fnk9uQK4VYAAOFN4UzhSuFB4xvhOeMT4TDhAeD3AADg0QAA4HXgaOBm4Fvfj+BQ4CTfgd6n33XfdN9t32rfXt9C3yvfKNvEE44KzgAAApQBmAABAAAAAAAAAOQAAADkAAAA4gAAAOAAAADqAAABFAAAAS4AAAEuAAABLgAAAToAAAFcAAABaAAAAAAAAAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABRAAAAAABTAFoAAABgAAAAAAAAAGYAAAB4AAAAggAAAIqAAACOgAAAsQAAALUAAAC6AAAAAAAAAAAAAAAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAswAAALMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmAAAAAAAAAAMEGwHqAesB8QHyAfMB9AH1AfYAfwHtAgECAgIDAgQCBQIGAIAAgQIHAggCCQIKAgsAggCDAgwCDQIOAg8CEAIRAIQAhQIcAh0CHgIfAiACIQCGAIcCIgIjAiQCJQImAIgB7APwAIkB7gCKAlUCVgJXAlgCWQJaAIsAjACNAmMCZAJlAmYCZwJoAmkAjgCPAmoCawJsAm0CbgJvAJAAkQJ+An8CggKDAoQChQHvAfAAkgH3AhIAqQCqAvgAqwL5AvoC+wCsAK0DAgMDAwQArgMFAwYArwMHAwgAsAMJALEDCgCyAwsDDACzAw0AtAC1Aw4DDwMQAxEDEgMTAxQDFQC/AxcDGADAAxYAwQDCAMMAxADFAMYAxwMZAMgAyQNaAx8AzQMgAM4DIQMiAyMDJADPANAA0QMmA1sDJwDSAygA0wMpAyoA1AMrANUA1gDXAywDJQDYAy0DLgMvAzADMQMyAzMA2QDaAzQDNQDlAOYA5wDoAzYA6QDqAOsDNwDsAO0A7gDvAzgA8AM5AzoA8QM7APIDPANcAz0A/QM+AP4DPwNAA0EDQgD/AQABAQNDA10DRAECAQMBBAQGA14DXwESARMBFAEVA2ADYQNjA2IBIwEkBAsEDAQFASUBJgEnASgBKQQHBAgBKgErBAAEAQNkA2UD8gPzASwBLQQJBAoBLgEvA/QD9QEwATEBMgEzATQBNQNmA2cD9gP3A2gDaQQTBBQD+AP5ATYBNwP6A/sBOAE5AToEBAE7ATwEAgQDA2oDawNsAT0BPgQRBBIBPwFABA0EDgP8A/0EDwQQAUEDdwN2A3gDeQN6A3sDfAFCAUMD/gP/A5EDkgFEAUUDkwOUBBUEFgFGA5UEFwOWA5cBYgFjBBkEGAF3A/EBeQGSA1ADWANZAAAAAgBSA/wCPwYYAAQACQAAAQMjETMFAyMRMwEBOHevAT44d68Fj/5tAhyJ/m0CHAAAAgA8AAAEmAWwABsAHwAAASMDIxMjNSETIzUhEzMDMxMzAzMVIwMzFSMDIwMzEyMCq+FMp0znAQU68wERTqdO4E6oTtDuOt37TKd34TrhAZr+ZgGangE5nwGg/mABoP5gn/7Hnv5mAjgBOQAAAQBk/y0EJgabACsAAAE0JicuATU0Njc1MxUeARUjNCYjIgYVFBYXHgEVFAYHFSM1LgE1MxQWMzI2AzNshdfPx7Cgr73ybmRoZGiO18rPuZ+25fOJanF4AXxXbS9JxrOq0RXa3Brty4CPa15YaTJNw7KwyxPDwhPb3pF3agAAAAAFAGT/6wWJBcUADQAbACkANwA7AAATNDYzMhYdARQGIyImNTMUFjMyNj0BNCYjIgYVATQ2MzIWHQEUBiMiJjUzFBYzMjY9ATQmIyIGFQUnARdkopKToqKRk6OpSEVDRkdEREcCE6ORkqOikZKkqUpDR0NIRERH/gV9Asd9BJiDqqqDTYOoqYJCV1dCTUJZWUL8zYKqqoJOg6mpg0FZVUVOQVlZQfhIBHJIAAAAAwA+/+sE+AXFACAAKwA4AAATNDY3LgE1NDYzMhYVFAYPAQE+ATUzFAYHFyEnDgEjIiYFMjY3AQcOARUUFgMUFhc3PgE1NCYjIgY+hYtLRsqzosRlYGQBMSksxUhLyf7nUVO4at79AeJAdzj+uB5KLnwMMDFyOiZURktOAYl6rVxhl1GvwbyKZJZGSP6WQJNWi+Jc7V87OeIgIyQBgxY5ZjFmfgOrMWQ/TCZPMjdUYQABAFIEBAELBhgABAAAAQMjETMBC0J3uQWb/mkCFAAAAAEAgP4xAqIGXwAPAAATEAA3FwYCERUQEhcHJgARgAE1vTCJvLuKML3+ywJQAZECIV2OaP5H/qIU/qL+R2+HXgIfAZIAAQAR/jECOwZfAA8AAAEQAAcnNhIRNRACJzcWABECO/7EvTGHvsKDMb0BPAJA/nP93F6HaAG/AV8UAVoBwWqIXf3Z/nUAAAAAAQAbAk8DYgWwAA4AAAElNwUDMwMlFwUTBwsBJwFF/tY1ASgNrg8BIzX+0cONsa6PA8xZqXUBV/6ic6tY/vZpAR/+6WYAAAAAAQBEAJIEKgS2AAsAAAEhFSERIxEhNSERMwKuAXz+hOz+ggF+7AMh3v5PAbHeAZUAAQAn/qsBZADrAAkAACUUBgcnPgE9ATMBY2hVfyws5Tdn3ElOSJNbvAAAAAABAEcCCQJUAs0AAwAAASE1IQJU/fMCDQIJxAAAAQCZAAABiwDpAAMAACEjNTMBi/Ly6QAAAQAC/4MC/gWwAAMAABcjATPBvwI9v30GLQAAAAIAaP/rBCMFxQANABsAAAEQAiMiAhkBEBIzMhIRJzQmIyIGFREUFjMyNjUEI/vh4f784eH983Z1dXV3dXV0AjH+3v7cASUBIQFNASEBJv7a/t8ltqmptv5ruKmouQAAAAEAygAAAt4FsAAFAAAhIxEhNSUC3vP+3wIUBKCfcQAAAQBRAAAENAXFABgAACkBNQE+ATU0JiMiBhUjNAAzMhYVFAYHASEENPw5Adp2VnBjgnrzAQXq1vCKl/63ApinAgWCn09kgo2BygEH5L+A3qb+pAAAAQBP/+sEFgXFACgAAAEzMjY1NCYjIgYVIzQkMzIWFRQGBx4BFRQEIyIkNTMUFjMyNjU0JisBAYapeWVub2V78wECztn6b2x/cv7x2s7+8POAbnOAdX+pA0ZzbWtxb16v4dTLX6sxLbB2zOHUx2N2eHJ+cgACADgAAARZBbAACgAPAAABMxUjESMRIScBMwEhEScHA6G4uPL9jwYCb/r9hwGHAxcCB8T+vQFDlQPY/FcCVgExAAAAAAEAgf/rBCYFsAAeAAAbASEVIQM+ATc2EhUUAiMiJDU3FBYzMjY1NCYjIgYHnFQDAf3JLCxvSNHk8OvE/vrremVzdXhzZl4XAosDJdL+kyApAgP+/Ora/vTRyQhsdJ2FhqM/PwACAHT/6wRGBcUAGgAnAAABMhYXBy4BIyIGHQE+ATMyEhUUAiMiABkBEAATIgYHFRQWMzI2NTQmAqhQjTouOWdIlK89nWDH3//Y4v7nATy0XX4jkndtd34FxSAcvBgb3cMHODv+89fk/ucBMgEeARYBIgFS/UpAOWi9xLOIhaIAAAEARQAABDMFsAAMAAABAAIDByM3GgE3ITUhBDP/AKsoD/MPJ+bO/P0D7gTt/tP+Mv6ompoBUAIP9MMAAAMAYf/rBCoFxQAXACMALwAAARQGBx4BFRQEIyIkNTQ2Ny4BNTQ2MzIWAzQmIyIGFRQWMzI2AzQmIyIGFRQWMzI2BAV1anqK/vnc3/75iHxqdPHNy/XNh2xug4JxbYQmcF1fbG1gXW4EMHGmLi+1es/T0897tDAtpnHGz8/8o22Eg25wfH0C/WJ5dWZldXUAAAIAUv/rBBcFxQAbACgAACUyNj0BJw4BIyICNTQAMzIAGQEQACMiJic3HgETMjY3NTQmIyIGFRQWAgOFnQMwilXV7AEKy+cBCf7c8EyeRCBAfXhdfSGAemSCdq29vSMBQUIBBPHmASL+3P7k/qv+5v7VHh64GxcB2EY7nLGvt46SpgAA//8AmQAAAYsEOgAmABAAAAAHABAAAANR//8AUf6rAY4EOgAnABD//QNRAAYADioAAAEAPwCkA4QETgAJAAABBxUXBRUBNQEVAUIREQJC/LsDRQJ9BAQE2vMBdcEBdPMAAAIAkQFkA+8D1gADAAcAAAEhNSERITUhA+/8ogNe/KIDXgMMyv2OyQABAIAApQPgBE4ACQAAEzUBFQE1JT8BJ4ADYPygAl0QAREDX+/+jMH+jO/iBAMFAAACACkAAAOgBcUAGQAdAAABPgE3PgE1NCYjIgYVIz4BMzIWFRQGBw4BFRMjNTMBVAE+cFBaZ2NVcvMC8sbW55FyOhwE+PgBnJJ2X06HVmNpWVu5xtPBgdVcM1hY/mTpAAACAEr+OwbTBZAAMwBDAAABBgIjIiYnDgEjIiY3GgEzMhYXBzMDBhYzMjY3EgAhIAADAgAhMjY3Fw4BIyAAExIAISAAAQYWMzI2NzwBNxMuASMiBgbDCeHqTGsZMIdeh44TGeSqcINSAwUzCDMseYwJEf7N/rL+yP6XDxIBRQE8WbFBJkTMZf51/mIREwHLAYMBhgGR+/4KOkc9YSgCLRgzHHl5Afvc/sxST1JN68gBBgEwMzcE/b1nStqtAXcBkv5N/o3+jP5jKCGCKy4B6gG5AbECAf4c/fSIhzBACA8NAgMJC8kAAAAAAgAaAAAFKAWwAAcACwAAASEDIwEzASMBIQMjA7r9z3j3AhfnAhD3/ZsBrNQDAVz+pAWw+lACHwJrAAAAAwCfAAAEvAWwAA8AGAAhAAAzESEyBBUUBgcVHgEVFAQjAREhMjY1NCYjJSEyNjU0JisBnwHo9QEJb2OBiP798f7KATZ+hHB6/rIBD3N+hIf1BbDDymSZJgMcvoHR0QKW/ix0bHZ+tWhlbmcAAQB0/+sE2AXFABsAAAEGACMgABkBEAAhIAAXIy4BIyIGFREUFjMyNjcE1xb+5f3+/f7OATUBAAECARUY8xOPmpirqZqXkRMB2Ob++QFRAREBFQEPAVT+/fCYmOi2/um555SXAAIAnwAABO4FsAAJABMAADMRISAAERUQACEDETMyNj0BNCYjnwHKASoBW/6i/szKw9nNys8FsP6m/uLB/uD+qQTt+9Xqy8PN5gAAAAABAJ8AAAR1BbAACwAAASERIRUhESEVIREhBA/9gwLj/CoDz/0kAn0Cj/4zwgWww/5lAAAAAQCfAAAEcgWwAAkAAAEhESMRIRUhESEEDP2G8wPT/SACegJt/ZMFsMP+QwABAHT/6wTiBcUAHwAAJQYEIyAAGQEQACEgBBcjLgEjIgYVERQWMzI2NxEhNSEE4jz+/NP+8/6yATwBAgEGAQsf7xiPlpq2xaR0iiL+3gIVvlKBAUgBDQEwAQ0BSPTagIvesv7OtN80JQEktgABAJ8AAAUQBbAACwAAISMRIREjETMRIREzBRDy/XTz8wKM8gJt/ZMFsP2AAoAAAAABAK0AAAGgBbAAAwAAISMRMwGg8/MFsAABADr/6wPmBbAADwAAATMRFAQjIiY1MxQWMzI2NQLz8/8A0N/983V0ZncFsPv10OrX239xgnYAAAEAnwAABS8FsAAMAAABIxEjETMRMwEhCQEhAjqo8/OLAckBIP30AjX+1wJ2/YoFsP2XAmn9Sf0HAAAAAAEAnwAABC8FsAAFAAAlIRUhETMBkgKd/HDzwsIFsAAAAQCfAAAGYgWwABAAAAkCIREjERMjASMBIxMRIxEB2gGmAacBO/MZA/5Mo/5OAxnzBbD7mARo+lAB8AKA+5AEbf2D/hAFsAAAAQCfAAAFEAWwAAsAACEjAQcRIxEzATcRMwUQ8v13A/PzAokD8gQrAfvWBbD71gEEKQAAAAIAdP/rBRsFxQANABsAAAEQACEgABkBEAAhIAARJzQmIyIGFREUFjMyNjUFG/61/vH+9v69AUIBCgEPAUzzwKijt7ijqb4CVf7z/qMBXgEMAQYBCwFf/qH+9QK16+q2/vi46+u4AAAAAgCfAAAE2gWwAAoAEwAAAREjESEyBBUUBCMlITI2NTQmIyEBkvMCOfYBDP709v66AUaKhYWK/roCKP3YBbD1z9Hzw45xcZIAAgB0/wkFJwXFABMAIQAAARQGBxcHJQ4BIyAAGQEQACEgABEnNCYjIgYVERQWMzI2NQUbdGvroP7tLFgv/vb+vQFCAQoBDwFM88Coo7e4o6m+AlWZ+1fSj/oLDQFeAQwBBgELAV/+of71ArXr6rb++Ljr67gAAAAAAgCfAAAE8AWwABoAIwAAAREjESEyFhUUBgceAR0BFBYXFSMuAT0BNCYjJSEyNjU0JiMhAZLzAiX3/Ht5fmkfJ/kpFntx/sYBGpWDfon+1QJc/aQFsNXQdp4yKayGeUF0Ihoii0Z1c4HDbnVxegAAAAEAU//rBKAFxQAlAAABNCYnJiQ1NCQzMgAVIzQmIyIGFRQWFx4BFRQEIyIkNTMUFjMyNgOtg676/v4BH+r0ASLzlo+HjZe47+/+4fHp/qzztJaJlAF2XHMuQs6us+H/AL1yiXNdVWsyQdiwudTu24eBawAAAQA1AAAEtQWwAAcAAAEhESMRITUhBLX+OfP+OgSABO37EwTtwwAAAAEAhv/rBPEFsAARAAABERQEISIkNREzERQWMzI2NREE8f7J/vz//s/zqZSZrwWw/DD3/v/2A9D8MJyXl5wD0AABABoAAAUQBbAACQAAARczNwEhASMBIQJ4HAMbAVsBA/355/34AQQBfW1rBDX6UAWwAAAAAQBEAAAGuwWwABMAAAE1MzUBMwEVPwETMwEjASMBIwEzAgMDARnAARwDAc7u/r7c/uQD/uTc/r7uAYQCAQQp+9QDAQUEKfpQBBz75AWwAAABAC8AAATqBbAACwAACQEhCQEhCQEhCQEhAoYBNAEf/kEB0P7d/sP+xP7hAcn+QQEdA5YCGv0u/SICI/3dAt4C0gAAAAEAEwAABO8FsAAIAAAJASEBESMRASECgAFgAQ/+B/L+DwEPAuwCxPxN/gMCDAOkAAEAWAAABHEFsAAJAAAlIRUhNQEhNSEVAXkC+PvnAtv9KwP6wsKYBFXDkgAAAQCE/rwCHAaOAAcAAAEjETMVIREhAhylpf5oAZgF0PmpvQfSAAAAAAEAFf+DA2EFsAADAAATMwEjFewCYOwFsPnTAAABAAz+vAGmBo4ABwAAEyERITUzESMMAZr+ZqenBo74Lr0GVwABADUC2QM1BbAACQAAASMBMwEjAycjBwEDzgErqwEqzaUNBA0C2QLX/SkBnTw8AAABAAP/QQOYAAAAAwAABSE1IQOY/GsDlb+/AAAAAQBKBLwCFwXGAAMAAAEjASECF8T+9wEUBLwBCgAAAAACAF7/7AQBBE4AHwAqAAAhLgEnDgEjIiY1NDY7ATU0JiMiBhUjNDYzMhYVERQWFyUyNjc1IyIGFRQWAwsLDwQ3nGKns/TlsWRgWGTz9cnB5xEV/exUhSK1bXVOIkQkRlirmqCsX1ZfT0CIxL23/h9FeDyvSDa4Z0k/RwAAAgCA/+wENgYYABIAIAAAARQCIyImJwcjETMRFz4BMzISESM0JiMiBgcRHgEzMjY1BDbZzWaRMxTS8wMxiV7P2fNxgVJsICFtUoFvAfny/uVPT4oGGP2sAURH/sn+963MR0H+N0BErZoAAAAAAQBR/+wD9wROABsAACUyNjUzFAQjIgI9ATQSMzIWFSM0JiMiBh0BFBYCO1t85f7/uPT5+fPH8+V1Yotsaq5nUaDaAS7xI/ABMOG3W3rDmiOdwAAAAgBT/+wEAwYYABIAIAAAExASMzIWFzcRMxEjJw4BIyICNTMUFjMyNjcRLgEjIgYVU9rNWocyA/PSFDWPYcva83F/TmkjI2lMf3MCDgEIAThEQQECTvnohExMARzxma5APgHYPULOqwACAFn/7AP4BE8AFQAdAAAFIgA9ATQAFzISHQEhHgEzMjY3Fw4BAyIGByE1NCYCUOr+8wEL0ODk/VYKiX5kiUJHPcKiW3QSAbRnFAEo8CjxATIB/vvjj4eiLy2mNUMDn411GWmAAAAAAAEAMQAAAuAGLQAXAAAzESM1MzU0NjMyFhcHLgEjIgYdATMVIxHWpaW/syRHLRgWLx1RTNzcA4a0fra/Cwq8BAZYVn60/HoAAAIAVP5MBAgETgAeACwAABMQEjMyFhc3MxEUBCMiJic3HgEzMjY9AScOASMiAjUzFBYzMjY3ES4BIyIGFVTezWKPNBTQ/wDsVbdPNEOPTIR+AzKIW8ve83SAUGkhImlNgHYCDgEHATlQTYn73djzLSqwISaNf1MBQEABHfCYrz8+Ado9Qc+qAAABAH0AAAQMBhgAFAAAARc+ATMyFhURIxE0JiMiBgcRIxEzAXADNZdgsL3zZGhJbibz8wOzAUtR1Of9bQKVgnA6NfzoBhgAAAACAJAAAAGDBhgAAwAHAAAhIxEzESM1MwGD8/Pz8wQ6AQnVAAAC/7D+SwGOBhgADwATAAABERQGIyImJzceATMyNjUREyM1MwGOt6klOCEOEjEVP0bt8/MEOvuHt78ICcIFB1NcBHkBDNIAAAABAIEAAAQ1BhgADAAAASMRIxEzETMBIQkBIQHib/LyaQEPARz+nwGP/uYB2f4nBhj8hAGe/hH9tQAAAAABAJAAAAGDBhgAAwAAISMRMwGD8/MGGAABAIAAAAZ1BE4AJgAAARczPgEzMhYXPgEzMhYVESMRNCYjIgYHFBYVESMRNCYjIgYHESMRAV4NAjSda2yVJzOhcKe5815gUGkZAvNgX0tmHvMEOolMUV5iW2Xb5/10Ao2NbVJJDxYK/UMCjYdzODX85gQ6AAEAfgAABAsETgAUAAABHwE+ATMyFhURIxE0JiMiBgcRIxEBXA4CNZ5mrbnzY2lJbSXzBDqXAVJayd39WAKmfWQ+OPzvBDoAAAIAU//sBDQETgANABsAABM0ADMyAB0BFAAjIgA1MxQWMzI2PQE0JiMiBhVTAQTr7QEF/vzs7f7883qEgnx8hIJ6Aif2ATH+0PcV+P7SAS74osLDoRWexsaeAAAAAgCA/mAENAROABIAIAAAARQCIyImJwcRIxEzFz4BMzISESM0JiMiBgcRHgEzMjY1BDTayl6KMgPz2RA0j2HM2/J6f01pICBoUH94Afnx/uQ/PwH99wXagkpM/sj++KnQQDv+Fzo7s5gAAAAAAgBT/mAD/AROABIAIAAAExASMzIWFzczESMRJw4BIyICNTMUFjMyNjcRLgEjIgYVU9rNXos0E9LzAzGEWcva83F/S2YiI2VJf3MCDgEIAThJSH36JgIDATw8ARzxmbI6OAH4NzzRrAABAIAAAALDBE4AEAAAASciBgcRIxEzFzM+ATMyFhcCpnNIXhrz3g8DKX5VGDAPA1wEOjf9EQQ6mFFbBwUAAAAAAQBR/+wDzwROACUAAAE0JicuATU0NjMyFhUjNCYjIgYVFBYXHgEVFAYjIiY1Mx4BMzI2AuBdhsbD47/K5/JkW1paVIjQwe3J1/HrBH5eYGQBJjlIHSqUhIu9wZhEX046OkEbK5WHlbLWk2BTRgAAAAEAGf/sAnAFQQAXAAABETMVIxEUFjMyNjcXDgEjIiY1ESM1MxEBocPDMSsZLBQaIV4xg4+VlQVB/vm0/apFNgcGshAUmasCVrQBBwABAHv/7AQKBDoAFAAAJScOASMiJjURMxEUFjMyNjcRMxEjAyICNJhnssDyWl9ZdSPz2JABUVTY7wKH/XeRbj48Aw77xgAAAAABACAAAAP1BDoACQAAARczNxMzASMBMwH4FAMU1/v+gNP+fvsBbl9fAsz7xgQ6AAABACUAAAXQBDoAFQAAARczNxMzExczNxMzASMDJyMHAyMBMwGzCgMN1bHWDgMPnun+2MfPFwMWzsf+2OkBdkhGAsb9OlNaAr/7xgKbaGf9ZAQ6AAABACEAAAPtBDoACwAAARMhCQEhCwEhCQEhAgTIARf+rAFe/uzR0f7qAV7+rAEUAscBc/3p/d0BfP6EAiMCFwAAAQAQ/ksD/AQ6ABUAAAEXMxMhAQ4BIyImJzceATMyNj8BASEB5xkD7wEK/kAqmpIeRSAbDi4NRUAlKP53AQkBsnEC+fsicaAMCLwBBEBVYgQtAAAAAQBVAAADxAQ6AAkAACUhFSE1ASE1IRUBggJC/JECIv3pA0rCwp8C18SaAAABADj+mAKRBj0AHgAAAS4BPQE0JiM1MjY9ATQ2NxcOAR0BFAYHHgEdARQWFwJhx6FdZGRdoccwZE9UWVlUT2T+mDjsrstqcrJybMuu6ziMIqR/y2qeLjCeaMt/pCIAAAABAK7+8gFVBbAAAwAAASMRMwFVp6f+8ga+AAAAAQAb/pgCdQY9AB4AABc+AT0BNDY3LgE9ATQmJzceAR0BFBYzFSIGHQEUBgcbY1FXX19XUWMwxqJcZmZcosbbIqR/y2udLSyebct/pCKMOOqvy2xysnJqy6/rOAABAHUBgwTcAy8AGQAAARQGIyImJy4BIyIGFSc0NjMyFhceATMyNjUE3K2IWY1VOVUvPVOqqolXlFI3VDA8VQLumtE/SS4sZUoWmcpCRTAqa0wAAAACAI/+igGCBDoAAwAHAAABIxEzESM1MwGC8/Pz8/6KA8QBAesAAAAAAQBo/wsEDgUmACEAACUyNjUzFAYHFSM1JgI9ATQSNzUzFR4BFSM0JiMiBh0BFBYCUlt85caZyL/AwL/Ior3ldWKLbGquZ1GLzBvp6yMBH9Mj0QEhJOLfG9efW3rDmiOdwAAAAAEAUQAABGsFxQAhAAABFxQGByEHITUzPgE1JyM1Myc0NjMyFhUjNCYjIgYVFyEVAecFLCsC1gH8JgowLgWimwnkx9Pi82tXV2EJAYUCV3FTljvCwg2vYHnE7tPp17prY4F47sQAAAAAAgBd/+UFTwTxACMALwAAJQ4BIyImJwcnNy4BNTQ2Nyc3Fz4BMzIWFzcXBx4BFRQGBxcHARQWMzI2NTQmIyIGBD1OtmZntE2BjYcyMjc2kI2OTKxjYq5NkY6UNDcyMIuO/Hjsrq3s7K2v62s/QEA+hJCJTq9kZ7ZQk5CRODs8OZSRl0+0ZmOtTY2RAnu9/v69u/39AAEAGgAABL4FsAAWAAAJASEBIRUhFSEVIREjESE1ITUhNSEBIQJsAUMBD/5zART+nQFj/p3z/psBZf6bAR/+cQEQAzACgP02k4+S/s4BMpKPkwLKAAIAiP7yAW0FsAADAAcAABMRMxkBIxEziOXl5f7yAxv85QPIAvYAAAACAFr+JASMBcUAMQBDAAABFAYHHgEVFAQjIiQ1NxQWMzI2NTQmJy4BNTQ2Ny4BNTQkMzIEFSM0JiMiBhUUFhceASUuAScOARUUFhceARc+ATU0JgSMV1REQ/707Of+0fKofH2Jgr/34FZTREEBDuvzAQnzin+FgXbI+eD9zSpOJTg0eMY2RCE4O4UBx1+HKzOHY7PCx+MBfGxhT09XOUG1slyJLTOIY63K3dFnhGNPWFM1RLQpCxgOFVQ7Wlk4EBULFlQ6UV8AAAIApATkA3kFsAADAAcAAAEjNTMFIzUzA3ny8v4c8fEE5MzMzAAAAAADAFf/6wXiBcQAGwAnADMAAAEUBiMiJj0BNDYzMhYVIzQmIyIGHQEUFjMyNjUlEAAzMgAREAAjIgADEAAhIAAREAAhIAAEXq6hpLm6o6CwnFhcYGNjYFxX/Q8BUvr5AVL+rvn7/q96AZgBLgEsAZn+Z/7U/tL+aAJUnpzRsnew056cX1SIc3h2hlFihf7z/pwBZAENAQwBYv6e/vQBQQGq/lb+v/6+/lQBqwAAAgB0ArQDEQXFAB8AKgAAAS4BJw4BIyImNTQ2OwE1NCYjIgYVJzQ2MzIWFREUFhclMjY3NSMiBhUUFgJgCAoDIm1PeYCmpYk5O0NHraiPiZoLD/6HNGkTiExROQLCFS8aMDx4bHF2Mz9AMzAOaIGMiP7GNFYrgjkkaT8vLCwAAP//AFQAdAOFA5MAJgFy6N0ABwFyAVL/3QABAH8BdgPCAyUABQAAASMRITUhA8LI/YUDQwF2AQSrAAQAV//rBeIFxAALABcAMgA7AAATEAAhIAAREAAhIAATEAAzMgAREAAjIgABESMRITIWFRQGBx4BHQEUFhcVIy4BPQE0JiMnMzI2NTQmKwFXAZgBLgEsAZn+Z/7U/tL+aHoBUvr5AVL+rvn7/q8BvJcBGZqrPDw/NgcKmwkEQU6ej0VdTGOCAtkBQQGq/lb+v/6+/lQBqwFD/vP+nAFkAQ0BDAFi/p7+qP6vA1KDgTxZHx1qTDgqQBUQFk8rNklChjw4SjgAAAAAAQCHBRIDXgWwAAMAAAEhNSEDXv0pAtcFEp4AAAIAfwOwAosFxQALABcAABM0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBn+Zb22Xl21vmYtINTRGRjQ1SAS4cJ2dcHGXmHA2RkU3N0lJAAACAF8AAAPzBQoACwAPAAABIRUhESMRITUhETMBITUhApwBV/6p1/6aAWbXASj8vQNDA4rH/nUBi8cBgPr2xAAAAQBtApsC1wXHABgAAAEhNQE+ATU0JiMiBhUjNDYzMhYVFAYPASEC1/2hATFCJjI3Pj++qpSOmF96iAFnApuRAQA3RCotNzsxbZGAd1Nya3QAAAAAAQBhAo8C7AXGACgAAAEyNjU0JiMiBhUjNDYzMhYVFAYHHgEVFAYjIiY1MxQWMzI2NTQmKwE1AaJCPEA/Nj6/q4WYqUY+R0qxmIq4v0Q+QkpFR3sEczQxKDQsImh4dXA4WRoYXkVyenh3LDIzLjk2gwAAAAABAHgEvAJMBcYAAwAAASEBIwE3ARX+6b0Fxv72AAAAAAEAkv5gBB8EOgAVAAABERQWMzI2NxEzESMnDgEjIiYnESMRAYRiY1lsHvPfBy50TT9gJ/IEOv2UqnU8PQMS+8ZWNjUaHf4+BdoAAAABAD4AAANwBbAACgAAIREjIiY1NBIzIRECfVPu/v/tAUYCCP/V0wEB+lAAAAEAoAJSAZIDQgADAAABIzUzAZLy8gJS8AAAAAABAG3+QQHJAAMADwAAJQceARUUBiMnMjY1NCYnNwE+C0FVpqEHP0pDVCADNgtRUWh3iSwtLSMFiwAAAAABAGQCmQGjBcUABQAAASMRIzUlAaPAfwE/ApkCf5YXAAIAdwKzAywFxQANABsAABM0NjMyFh0BFAYjIiY1MxQWMzI2PQE0JiMiBhV3uaGiubmgorqvVldUVldVVVYEdpe4uJd1mLa2mFdlZVd1VGdnVAAA//8AXACXA5kDtgAmAXMIAAAHAXMBfgAA//8AmwAABccFxAAnAckARAKYACcBdAD8AAgABwGXAqIAAAAA//8AkwAABdkFxAAnAXQBAQAIACcByQA8ApgABwHKAwQAAAAA//8AZgAABoMFxwAnAXQBwgAIACcBlwNeAAAABwHLAAYCmwAAAAIAYP52A9gEOgAZAB0AAAEOAQcOARUUFjMyNjczDgEjIiY1NDY3PgE1AzMVIwKsAj1wUlhmZVNyAvMD88TY5pBzOR4E+PgCnZN1XlGFVWNpWlu6xdLAgdZbMlhZAZ3pAAL/9gAAB1cFsAAPABMAACkBAyEDIQEhFSETIRUhEyEBIQMnB1f8fg/+Crj+3gNDA+D9ehECJP3kFAKX+u0BeRsDAVT+rAWwxf5oxf42AWcCggEAAAEATQDWA+wEhgALAAATCQE3CQEXCQEHCQFNATz+xJQBOwE8lP7EATyU/sT+xQFsAUIBQpb+vgFClv6+/r6WAUH+vwAAAwBp/6EFEAXuABkAJAAvAAABEAAhIiYnByM3LgE1ERAAITIWFzczBx4BFQEUFhcBLgEjIgYVITQmJwEeATMyNjUFEP61/vFVkkFYlIVdYQFCAQphpklRlIJSVvxLISIB+i9wRKO3AsIZGf4NKF44qb4CVf7z/qMmJpbiV+2OAQYBCwFfMS+J3Ffegv76TYM2A1woKuq2PnAy/K8dHeu4AAIAlAAABH4FsAAMABUAAAERMzIEFRQEKwERIxETETMyNjU0JiMBh/b3AQr+9vf28/P2ioSEigWw/ujvx8ju/tQFsP4l/hqJaGqLAAABAIj/7ASbBh8AJwAAISMRNDYzMhYVFAYVFAAVFAYjIiYnNx4BMzI2NTQANTQ2NTQmIyIGFQF68vLOrdh2AUTWyVGoKDEsdkBfXP67fl5AXW0EReX1tLB0yz9F/uiNt7AjG8QaJlFITQERlFbPTVFgkocAAAMANP/rBoQETgAsADcAPwAABSImJw4BIyImNTQ2OwE1NCYjIgYVJzQ2MzIWFz4BMzISHQEhHgEzMjY3Fw4BJTI2NzUjIgYVFBYBIgYHITU0JgTmh8hEPdGYuMHt685bWF5q8u/Nbqc5QKVm2uj9UAiKjmR6U0k6xvxuRZApzG94WQNCanMOAb1kFVdVS2GwnaGpR11lWUITk7hBQUBC/v7ojYufLS+lLku5SDK9YEdCTgLnjnsebH8AAAAAAgA8/+sETgXtACEAMQAAARYSHQEQACMiADU0ADMyFhc3LgEnByc3LgEnNx4BFzM3FwM0JjUuASMiBhUUFjMyNjUDcWty/tjl6P7jAQ3iUIs4AxdQOfxO2CNIJ0tRj0IB2k7YASSOaICRlIJ/lwUDef7ExVf++v6/ARXU5wESNS4CWY86jm16FCENxBVFMXtt/RsDDwQxP7KLe6zYrQAAAAMAQwCqBDcEtgADAAcACwAAASE1ISUjNTMRIzUzBDf8DAP0/oHz8/PzAkbUv9379N0AAAADAFP/dgQ0BLwAGQAkAC8AABM0ADMyFhc3MwceAR0BFAAjIiYnByM3LgE1MxQWFwEuASMiBhUhNCYnAR4BMzI2NVMBBOs2YS5IkGhdYP787DFZKkiQZmVm8x0gASoYNR6CegH8Ghr+2xMtG4J8Aif2ATETEZLTS+WSFfj+0g8Ok89J65lPgDACYAsNxp5Gdy/9qwkHw6EAAAIAh/5gBDsGGAATACEAAAEUAiMiJicHESMRMxEXPgEzMhIRIzQmIyIGBxEeATMyNjUEO9rKXooyA/PzAzGKXMzb8np/TWkgIGhQf3gB+fH+5D8/Af33B7j9sgFBRP7I/vip0EA7/hc6O7OYAAIAGAAABZYFsAATABcAAAEzFSMRIxEhESMRIzUzETMRIREzASE1IQUPh4fy/XTzhobzAozy/IICjP10BKSi+/4Cbf2TBAKiAQz+9AEM/YDSAAAAAAEAjwAAAYIEOgADAAAhIxEzAYLz8wQ6AAEAjgAABGsEOgAMAAABIxEjETMRMwEhCQEhAe9v8vJVAVABLP5cAb7+ywGs/lQEOv5QAbD9+v3MAAAAAAEAGwAABCAFsAANAAABJRUFESEVIREHNTcRMwGDAQL+/gKd/HB1dfMDYU64Tv4ZwgJfI7gjApkAAQAbAAACKAYYAAsAAAE3FQcRIxEHNTcRMwGXkZHziYnzA3s0uDT9PQJtMbgxAvMAAQCT/ksFBAWwABgAAAERFAYjIiYnNx4BMzI2PQEBBxEjETMBNxEFBLipJTkhDhE8FjxA/XgD8/MCiAMFsPoRtsAICb8FCF1WPwQdAfvkBbD74wEEHAAAAAEAfv5LBAYETgAgAAABHwE+ATMyFhURFAYjIiYnNx4BMzI2NRE0JiMiBgcRIxEBXA0DNZtkrbm4qSQ6IQ4SOxY8QGBmTGwk8wQ6kQFPV8vi/SC2wAgJxgUHVlUC3oBoNTL84AQ6AAAAAgBl/+sHVgXFABcAJQAAKQEOASMgABkBEAAhMhYXIRUhESEVIREhBTI2NxEuASMiBhURFBYHVvx1XX9E/vf+wwE7AQlGjFADhP0kAn39gwLj+1U3aTU7ZzWjr7EKCwFGAQ8BMAEOAUcMCcP+ZcP+MxQICAQ0BwnJx/7OyMoAAAADAFv/6wbyBE4AIQAvADcAABM0ADMyFhc+ATMyEh0BIR4BMzI2NxcOASMiJicOASMiADUzFBYzMjY9ATQmIyIGFQEiBgchNTQmWwED7H6/QkK1buDk/VYKiX5kikFPQMSIfsFEQr587f788nuEgnt8g4J7A+FbdBIBtWgCJ/cBMFtWVlv+++OPh6MvLp84SFlVVVkBL/iiw8ShFZ7Gxp4BZI50GWiBAAABAIsAAAKVBi0ADwAAMxE0NjMyFhcHLgEjIgYVEYu/syRHLRkXKRxRUgS4tr8LCrkFBlxW+0gAAAH/3f5LAtMGLQAjAAABIxEUBiMiJic3HgEzMjY1ESM1MzU0NjMyFhcHLgEjIgYdATMChMm3qSU5IA8ROhY7QKWlwLMkRi4ZFDEcUU3JA4b8O7e/CAm/BQhdVgPFtH62vwsKvAQGWFZ+AAAAAAIAZv/rBa8GLgAXACUAAAEQACEgABkBEAAhMhYXPgE1MxQGBx4BFSc0JiMiBhURFBYzMjY1BQ3+tf7x/vb+vQFCAQqB1FNTRrx2eiYo88Coo7e4o6m+AlX+8/6jAV4BDAEGAQsBX1dRDYZ+p8slSJ1XArXr6rb++Ljr67gAAAAAAgBS/+wEvASpABcAJQAAEzQAMzIWFz4BNTMUBgceAR0BFAAjIgA1MxQWMzI2PQE0JiMiBhVSAQTrc7NCQCuoXmkeIP787O3+/PN6hIJ8fISCegIn9gExTUgTcmuQriJCj1EV+P7SAS74osLDoRWexsaeAAABAIb/6wZLBhAAGQAAARU+ATUzFAYHERQEISIkNREzERQWMzI2NREE8V1BvKC6/sn+/P/+z/OplJmvBbDNFo6J0eAV/Zb3/v/2A9D8MJyXl5wD0AABAHv/7AUpBJQAHAAAARQGBxEjLwEOASMiJjURMxEUFjMyNjcRMxU+ATUFKX6h2BACNJhnssDyWl9ZdSPzVDAElKunDvzMkAFRVNjvAof9d5FuPjwDDosNZXMAAAH/tf5LAZMEOgAPAAABERQGIyImJzceATMyNjURAZO3qSQ5IQ8SORY7QQQ6+4e3vwgJvwUIXVYEeQAAAAIAWf/sA/gEUAAVAB0AAAEyAB0BFAAnIgI9ASEuASMiBgcnPgETMjY3IRUUFgIA6gEO/vTP4eMCqgyJfGWJQU8/xaVZdBT+S2cEUP7W8Cjy/tABAQPkj4akMC2fN0r8X4x2GWmAAAAAAQCbBOQDPAXuAAgAAAEVIycHIzUlMwM8vJaVugEIjwT8GJKSGvAAAAEAeQTkAy0F8QAIAAABNzMVBSMlNTMB0ovQ/vSd/vXOBWKPEfz6EwABAHUElQL7BbAADQAAARQGIyImNTMUFjMyNjUC+62Wl6y2Q0pJQwWwgpmZgj9MTD8AAAAAAQCaBNcBnQW2AAMAAAEhNSEBnf79AQME198AAAIAggRUAiYF3AALABcAABM0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBoJ6Wlh4d1lbeW46LCs3NyssOgUWVnBwVldra1csOTgtLjo7AAABACn+UgGhADwAEwAAIQ4BFRQWMzI2NxcOASMiJjU0NjcBjFBRICcaKhYVIU03XnV6hjNcOCEjDQqOExlpYFWROwAAAAEAgATWA1EF9wATAAABFAYjIiYjIgYVJzQ2MzIWMzI2NQNRdlxJojQoNYN1XDqwNSc3BdBhhFlALiNgiVk/LwACAHoE5AObBe4AAwAHAAABIQEjAzMDIwKbAQD+1cpu8vW7Be7+9gEK/vYAAAIAq/5+Afr/uAALABcAABc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBqthSUZfXkdKYGUnHhsmJhseJ+dGWVlGRVZWRR0mJxwfJycAAAAB/NsEs/4qBf0AAwAAASMDM/4qmbbQBLMBSgAAAf02BLb+hgYBAAMAAAEzAyP9uM6+kgYB/rUA///8eQTW/0oF9wAHAKD7+QAAAAAAAf0+BOb+mQZ/AA8AAAEnPgE1NCYjNzIWFRQGBxX9UQdNPU5IB6mrVUEE5pIEHSMnIXtlW0VHCEUAAAAAAvwMBOT/NAXuAAMABwAAASMBIQEjAzP+B9D+1QEGAiLD9foE5AEK/vYBCgAB/SL+pf4w/4QAAwAAASE1If4w/vIBDv6l3wAAAQDXBPYCDQZwAAMAAAEzAyMBG/LAdgZw/oYAAAMAnQTkA44GpAADAAcACwAAASM1MwUjNTM3MwMjA47a2v3p2tp4+JWSBOTMzMz0/tcAAP//AKACUgGSA0ICBgB2AAAAAQCfAAAENwWwAAUAAAEhESMRIQQ3/VvzA5gE7fsTBbAAAAAAAgAaAAAFmAWwAAMABgAAATMBISUhAQJz5wI++oIBSALy/pAFsPpQwgPOAAADAGb/6wUNBcUAAwARAB8AAAEhNSEFEAAhIAAZARAAISAAESc0JiMiBhURFBYzMjY1A6P+QAHAAWr+tf7x/vb+vQFCAQoBDwFM88Coo7e4o6m+AnnD5/7z/qMBXgEMAQYBCwFf/qH+9QK16+q2/vi46+u4AAEAIwAABREFsAAHAAABIwEjATMBIwKbA/6G+wID5wIE/AR0+4wFsPpQAAAAAwBwAAAELQWwAAMABwALAAA3IRUhEyEVIQMhFSFwA738Q2AC9/0JVgOa/GbCwgNMvwMjwwAAAAABAJ8AAAURBbAABwAAISMRIREjESEFEfL9c/MEcgTt+xMFsAABAEcAAARMBbAADAAACQEhFSE1CQE1IRUhAQMW/m0Cyfv7Ac7+MgPf/V4BkgLP/fTDmAJBAj+Yw/32AAADAEsAAAWjBbAAEQAYAB8AAAEWABUUAAcVIzUmADU0ADc1MwEUFhcRDgEFNCYnET4BA3H5ATn+x/ny/P7IATj88v3JqJ2dqAN5p5uaqAT+BP7S+vr+1AKqqgEBK/r7ATADsv0gprQBAr4CuKeotgP9QgG2AAEASAAABVEFsAAXAAABPgE1ETMREAAHESMRJgAZATMRFBYXETMDQoqS8/7m9fLz/uvykYXyAjgXwakB9/4J/v7+1Rn+jQFyGAErAQQB9/4JpsEZA3cAAAABAGwAAATaBcUAJAAAJTYSPQE0JiMiBh0BFBIXFSE1MzcmAj0BEAAhIAARFRQCBzMVIQLfeYGilZWghHz+DOcBcoMBNQEBAQEBN4Vy8f4LyB0BDPhp1tjY1mn5/vQcyMQDXgEho2cBHAFZ/qf+5Gek/uBhxAAAAAACAFb/6wR5BE4AHAArAAABERQWMzI2NxcOASMiJicOASMiAj0BEBIzMhYXNwEUFjMyNjc1ES4BIyIGFQP9JSQHDgYYHzomUmsaM5Bky9vbzV6KNBP+HHF/TGQiImRKf3MEOf0KTzsCArQRDU1UUVABHfEVAQgBOE1Lg/3AmbNGQw0BukVJ0awAAgCW/ncEagXEABQAKgAAATIWFRQGBx4BFRQGIyImJxEjETQkEzI2NTQmIyIGFREeATMyNjU0JisBNQJp0fBhWnqB8tFQkj3yAQ3CbmRrY2N+KnxPdoR3bHkFxNK4YJoxLbqD1eQoK/44Bai37v2ZbWdXeX5k/OEoKodvbpK5AAABACD+XwP1BDoACwAAATMBESMRATMTFzM3Avr7/o/z/o/73RQDFAQ6+/D+NQHQBAv9NF9fAAAAAAIAVP/sBDgGIAAhAC8AABM0NjMyFhcHLgEjIgYVFBYXFhIdARQAIyIAPQE0Nj8BLgETFBYzMjY9ATQmJyIGFdDRwEyYUiw6h0ZQWFBv5Nn++uru/vqyiQReZXZ/g39/jHKBgQTqk6MsKKMWIj00KlAmUf7s0xTw/tgBJO4UqvMjCymI/X2cwsKcFHjKGMOXAAEAYP/sBAwETQAoAAATNDY3LgE1NDYzMhYVIzQmIyIGFRQWOwEVIyIGFRQWMzI2NTMUBCMiJGBmZVlf9NbA/vJ4W2hoYmfHx25ud2xofPL+8cDW/vkBMlx9IiR3SpmisJY9TlI6QEetSE5AVlpBqqusAAAAAQBh/n4DygWwACAAAAEVAQ4BFRQWHwEeARUOAQcnPgE1NCYvAS4BNTQSNxMhNQPK/qN6ZURRbJt5AX5NfTAtPUlSs5CGkOv9xAWwkf5bjsqLXlkTIC5RcU61PGU2UyQjMBIVL6iejQEoqwEOwwAAAAEAfv5hBAYETgAUAAABHwE+ATMyFhURIxE0JiMiBgcRIxEBXA0DNZtkr7fzYWVMbCTzBDqRAU9Xxej7wAQ+gWs3M/zfBDoAAAMAc//rBC4FxQANABYAHwAAARACIyICGQEQEjMyEhEDIRUUFjMyNjUBITU0JiMiBhUELvvh4f784eH98/4rd3V1dP4rAdV2dXV1AjH+3v7cASUBIQFNASEBJv7a/t/+/Gy4qai5ASprtqmptgAAAAABAKn/6wJ+BDkADwAAAREUFjMyNjcXDgEjIiY1EQGcMC4bKRomL1Y3i44EOfzvRDILC7EZE5qqAwoAAAABABb/7gRKBfQAIQAAKQEBJy4BIyIGByc+ATMyFhcBHgEzOgE3Fw4BIyImJwMjBwEf/vcBgVYWOCsRGAsDGFUhZ2sfAbAULCMMEAcEFDAab3YtzwMXBA7IMSoBAbUGCk5V+8QxLQHABAZYfAIkZwAAAQBk/nYD1AXEADEAAAEuASMiBhUUFjsBFSMiBhUUFh8BHgEVDgEHJz4BNTQmLwEuATU0Njc1LgE1NCQzMhYXA4NKYDeDf4OQko+wr4tyapSCAn9MfTQpO0su7uGck293AQHkUoc9BNsTEVpIWGDGjJFvgBgYIlpzTrY6ZDpJLSkqEQszvtaRwS8DJ41hrb4XFAAAAAEAT//rBOoEOgAXAAABIxEUFjMyNjcXDgEjIiY1ESERIxEjNSEEj4cwLhspGiYvVjeLjv628ooEQAN9/atEMgsLsRkTmqoCTvyDA329AAAAAgCA/mAEMQROAA8AHQAAARQCIyImJxEjETQAMzISESM0JiMiBhURHgEzMjY1BDHYyV2LNfMBAtTp8vNxfXBtIGhQfnUB+fL+5Ts8/f0D3/YBGf7K/vat0MuN/vA6O7KZAAAAAAEAUv6KA+kETgAhAAABMhYVIzQmIyIGHQEUFhceARcOAQcnPgE1NCYnLgE9ATQSAjjG6+RnZn91j5+lfgMBfU1/NCk8RvLl/QRO1sJed8mUI4WZLDBVc062O2U6Si0oKw8699gj7QEzAAAAAAIAUv/sBH0EOgARAB8AAAEhBx4BHQEUACMiAD0BNAAzIQEUFjMyNj0BNCYjIgYVBH3++wFVYf785e3++wEE7AI7/Mh6hX54eX+DegN2A0S/chXb/t4BLvgV7gEl/diiwsOhFZW6upUAAQBA/+sD7QQ6ABMAAAEhERQWMzI2NxcOASMiJjURITUhA+3+lTAuGykaJi9WN4uO/rEDrQN5/a9EMgsLsRkTmqoCSsEAAAAAAQCA/+sECAQ6ABUAAAERFBYzMjY1LgEnMx4BFRACIyImNREBclVMeIoDOjTxND/098nUBDr9bYZ07J1/+4pq/pz+/P651+cCkQAAAAIARP4iBYUEQQAZACMAAAUkADU0EjcXDgEHFBYXETQ2MzIAFRQABREjEz4BNS4BIyIGFQJl/uD+/3t2mExHA4yim3/qARz++P7b8/OmlAOGeh4ZDh8BQvGkAQNVkkm7ZpjUIAKEdZD+x+Hl/ssc/jEClB3IjJTCIhcAAAABAE/+IgV+BDoAGwAAARE+ATUuASczHgEVFAAFESMRJAAZATMRFBYXEQNSpZUDPTXuN0L++/7Z8/7+/vLzlYgEOvx9H9aYfPSGaPeX9f69HP4yAdAeASUBHAHp/hW6wRwDggAAAQBm/+sGLQQ6ACgAAAEOAQcUFjMyNjURMxEUFjMyNjUuASczHgEVEAIjIiYnDgEjIgIRNDY3AeVCSANXYldk+2RXYlcESEDxQE3C3nSiLi+gc+DBTEEEOof8gbDZkKMBRf67o5DYsYD9h2r+nP70/sFvb29vAT8BDJz+agAAAAACAHX/7AThBcQAGQAkAAAlMjY3LgE9ATQ2MzIWFREQACEgABkBNxEUFhMUFhcRNCYjIgYVAqmVpgTJ9rubp7v+zP78/wD+zPqm8nVsODk0PLbHtgzvuVu0zs28/gT+7f7AAU0BBgKlAv1ZsdgDL2WECwFZVlJUVAAB/+4AAASFBcIAIwAAAT4BMzIWFwcuASMiBgcBESMRAS4BIyIGByc+ATMyFhcTFzM3AvI5hWogMxgYBBsNIzcR/tvy/twSNiIPGgMXFzEiaoQ5pRMEEwTEjnAJDMACAysn/W398wISAo4nKwMCwAwJbY7+d1VVAAACADP/6wZUBDoAFgAsAAABIx4BFRACIyImJw4BIyICETQ2NyM1IQEuASchDgEHFBYzMjY9ATMVFBYzMjYGVIAaHbbQeKUtLqV30LUbG28GIf7FAyAe/MYeIAJKVFpp+mdbU0sDg02jXf70/sFxcnJxAT8BDF2kTLf9/FOjV1ekUrDZkKPi4qOQ2AAAAAEAJP/xBbsFsAAbAAABIRE+ATMyBBUUBiEnMjY1LgEjIgYHESMRITUhBJH+D06EOPwBFf/+9QGgeAGPjkKFQ/P+dwRtBO3+ZhMY6d/U8bqIfH2HEBD9bQTtwwAAAQBy/+wE1gXGAB8AAAEGACMgABkBEAAhIAAXIy4BIyIGHQEhFSEVFBYzMjY3BNUW/uX9/v3+zgE1AQABAgEVGPMTj5qYqwIB/f+pmpeREwHZ5v75AVEBEQEVAQ8BVP798JiY6LYmwy6555SXAAAAAAIALgAACEMFsAAWAB8AAAERITIEFRQEIyERIREQAiEjNTMyEhkBAREhMjY1NCYjBQoBNPUBEP7w9f3Z/kDs/vMwKJh3A6UBNImKiYoFsP3r/dHR/ATt/iD+Xf6WwgEDAUgCo/0o/eqac3GYAAIAnwAACEoFsAASABsAAAEhETMRITIEFRQEIyERIREjETMBESEyNjU0JiMBkgKM8wE09gEP/vH2/dn9dPPzA38BNIqJiYoDRAJs/cnwycz0AoH9fwWw/Qb+FIttaooAAAEANQAABcsFsAAXAAABIRE+ATMgBBURIxE0JiMiBgcRIxEhNSEEmP4LQ4xPAQEBCfKClkeQR/P+hQRjBO3+jw4P2vX+NgHKmnEQDv1JBO3DAAAAAAEAmf6YBQsFsAALAAATMxEhETMRIREjESGZ8wKM8/5K8/43BbD7EgTu+lD+mAFoAAIAlAAABMEFsAAMABUAAAEhESEyBBUUBCMhESEBESEyNjU0JiMELP1bATT4AQ7+8ff92QOY/VsBNIqJiIsE7f6Q7M7Q8wWw/Qr+CJFybocAAgAm/pkF2wWwAA4AFQAAASMRIREjAzM2EhsBIREzAQYCByERIQXR6fwx7Ad3T3gIJQOPu/yGCVtLAnv+S/6aAWb+mQIpTgEtAR8CVPsSApro/r5wBCsAAAEAGAAAB4kFsAAVAAABIxEjESMBIQkBIQEzETMRMwEhCQEhBPCi8qn+k/7SAdf+SgEkAWGe8pgBXgEk/k0B1P7SAnv9hQJ7/YUDBwKp/ZwCZP2cAmT9WPz4AAAAAQBK/+sEewXFACgAAAEyNjU0JiMiBhUjNCQzMgQVFAYHHgEVFAQjIiQ1MxQWMzI2NTQmKwE1AmiKgI2NcpTzASDZ+AEVeG58gP7V+Nr+zPOcf5CgjpKqA0dza2F8d1673dTMZqMwLKl/zeDU1WSDgWl9csEAAAAAAQCaAAAFCwWwAAsAAAEzESMRIwEjETMRMwQY8/MD/Xjz8wMFsPpQBBj76AWw++kAAQAuAAAFCgWwAA8AAAERIxEhAwoBKwE1Mz4BGwEFCvP+OREPzvY+KIliDBgFsPpQBO3+IP5W/p3CBfYBUAKjAAEAP//rBNkFsAAVAAABFzMBIQEOASMiJic3HgEzMjY/AQEhAmgzAwEvAQz+Cj6WnxlCDAIKPBFMRCAf/g4BCgMekgMk+1KMiwQCwAICRkpFBC4AAAMAT//EBhkF7AAVAB4AJwAAATMgABEQACEjFSM1IyAAERAAITM1MwEiBhUUFjsBETMRMzI2NTQmIwOvDwELAVD+r/72D/MT/vX+sQFPAQsT8/76r7u6sBPzEa28u64FJv66/vL+9P69v78BQQEMAQ8BR8b+cM6+u8gDD/zxyru9zQAAAAEAmf6hBbYFsAALAAATMxEhETMRMwMjESGZ8wKM86sU3fvUBbD7EgTu+xX93AFfAAEAjwAABOkFsAATAAABESMRDgEjICQ1ETMRFBYzMjY3EQTp81CrYf7+/vfzgZdVs1QFsPpQAkEWFdr1Acv+NZtwFhYCqgAAAAEAngAABvwFsAALAAABESERMxEhETMRIREBkQHF8gHB8/miBbD7EgTu+xIE7vpQBbAAAAABAJ7+oQetBbAADwAAAREhETMRIREzETMDIxEhEQGRAcXyAcHzsRTd+eIFsPsSBO77EgTu+xP93gFfBbAAAAAAAgAYAAAF0wWwAAwAFQAAEyERITIEFRQEIyERIQERITI2NTQmIxgCgQE0+AEO/vH3/dn+cgKBATSKiYiLBbD9zezO0PME7f3N/giRcm6HAAADAJ8AAAZZBbAACgAOABcAAAEhMgQVFAQjIREzASMRMwERITI2NTQmIwGSATT4AQ7+8ff92fMEx/Pz+zkBNIqJiIsDfezO0PMFsPpQBbD9Cv4IkXJuhwAAAgCUAAAEwQWwAAoAEwAAASEyBBUUBCMhETMZASEyNjU0JiMBhwE0+AEO/vH3/dnzATSKiYiLA33sztDzBbD9Cv4IkXJuhwAAAQCI/+wE1wXGAB8AABM0ADMyABkBEAAjIAA1MxQWMzI2PQEhNSE1NCYjIgYViAEj//4BL/7R/v79/uHyl5mVpP3zAg2klZiXA9TkAQ7+rf7w/uv+7/6vAQHulZjmuCnDK7jompUAAAACAKr/6wcABcUAFQAjAAABEAAhIAARNSMRIxEzETM1EAAhIAARJzQmIyIGFREUFjMyNjUHAP61/vH+9v69vPPzvAFCAQoBDwFM88Coo7e4o6m+AlX+8/6jAV4BDAj9owWw/XE6AQsBX/6h/vUCtevqtv74uOvruAACAC0AAARiBbAADQAWAAApAQEuATU0JDMhESMRIQEjIgYVFBY7AQEx/vwBSIOBARL7AeTz/t4BIvGPjI2O8QJsOsGO2eL6UAIlAsiFfICKAAIAW//rBDwGEwAbACkAAAEyEh0BFAAjIgA9ARAANz4BNTMUBgcOAQcXPgEXIgYdARQWMzI2PQE0JgJz2fD+/Ozt/vwBBuN6ZsS0znOfIwNFnzKCenqEgnx9A/7+7d8V7f7hASTvZwFlAY0sFzZDxXojFI+GAjhAw6mGFZW1tZUVhqkAAAMAjwAABDoEOgAPABgAIQAAMxEhMhYVFAYHFR4BFRQGIwERITI2NTQmIyUzMjY1NCYrAY8Bt9vrXFduc9zS/vYBCmBbWmH+9shqZWhrxAQ6lJhNdB8DGIRam5oBzf7zQ0NBRq48PkRAAAAAAAEAhQAAA00EOgAFAAABIREjESEDTf4q8gLIA3b8igQ6AAAAAAIAJ/6+BMUEOgAOABUAADc+ATcTIREzESMRIREjEwEOAQchESGBXE0LCwLvlvL9SvYBAgAJRjwBoP7ww2bHyQGB/Ij9/AFC/r4CBQH2rPNYAqcAAAEAFwAABl8EOgAVAAABIxEjESMDIQkBIRMzETMRMxMhCQEhBDSA84D2/swBb/6rASzycvNz8gEt/qoBb/7LAbP+TQGz/k0CQQH5/lcBqf5XAan+B/2/AAABAE3/7APEBE0AKAAAARQGBx4BFRQGIyIkNTMUFjMyNjU0JisBNTMyNjU0JiMiBhUjNDYzMhYDsFZQXF7yy7j+/vJwYGBiWmKurltOVFxUavLxuMveAxJKdyQhfV2bq6uqQVpVQU9Gr0RCPFBOPZawoQAAAAEAhgAABBIEOgALAAABMxEjEScBIxEzERcDIPLyA/5b8vIDBDr7xgLUAf0rBDr9LgEAAAABAI8AAARlBDoADAAAASMRIxEzETMBIQkBIQH9e/PzawErASz+eQGo/sQBrP5UBDr+UAGw/fr9zAAAAAABAB8AAAQUBDoADwAAAREjESEDCgErATczMjY3EwQU8/7QCw+m3jQBJGY+CxQEOvvGA3b+9/6y/uHNqfcBzQAAAQCPAAAFbwQ6AA4AAAkBIREjEScBIwEHESMRIQL/AUABMPMD/tml/tgD8wEyASsDD/vGAsQB/TsCyQH9OAQ6AAEAhgAABBEEOgALAAAhIxEhESMRMxEhETMEEfP+W/PzAaXzAbX+SwQ6/j0BwwAAAAEAhgAABBIEOgAHAAAhIxEhESMRIQQS8/5a8wOMA3b8igQ6AAEAIwAAA9AEOgAHAAABIREjESE1IQPQ/qHz/qUDrQN5/IcDecEAAAADAFT+YAV/BhgAHwAtADsAABMQEjMyFhcRMxE+ATMyEhEVFAIjIiYnESMRDgEjIgI1JTQmIyIGBxEeATMyNjUhFBYzMjY3ES4BIyIGFVTKwidDIPIgSS3Cy8vALUoh8h9FKMDKBDhqdBgoEhEpGnNp/LpidBclEhIlFXRkAg4BCQE3Dg4B5v4WEBD+yf73FfL+5BAO/lcBpQ0NARzyFazRBwb9OQYEs5mbsQQGAsoEBs+uAAABAIb+vwSlBDoACwAAEzMRIREzETMDIxEhhvMBpvOTFN380gQ6/IgDePyI/f0BQQABAF8AAAPgBDsAEwAAISMRDgEjIiY1ETMRFBYzMjY3ETMD4PMxYjPd6/NlcDVfMvMBaQsLytIBTP60dmILDAIMAAAAAAEAhgAABgMEOgALAAABESERMxEhETMRIREBeQFS8wFT8vqDBDr8iAN4/IgDePvGBDoAAAABAH7+vwa1BDoADwAAAREhETMRIREzETMDIxEhEQFxAVLzAVPyuhTd+roEOvyIA3j8iAN4/Ij9/QFBBDoAAAAAAgAfAAAE6gQ6AAwAFQAAATMyFhUUBiMhESE1IRkBMzI2NTQmIwJK7dDj5M/+IP7IAivtZFxcZALiyKimzAN3w/3l/qNgS0xmAAAAAAMAjwAABckEOgAKAA4AFwAAATMyFhUUBiMhETMBIxEzAREzMjY1NCYjAYLt0OPkz/4g8wRH8/P7ue1kXFxkAuLIqKbMBDr7xgQ6/eX+o2BLTGYAAAIAjwAABCIEOgAKABMAAAEzMhYVFAYjIREzGQEzMjY1NCYjAYLt0OPkz/4g8+1kXFxkAuLIqKbMBDr95f6jYEtMZgAAAQBR/+sD6AROAB0AAAEiBhUjNDYzMhIdARQCIyImNTMUFjMyNjchNSEuAQIBV3Tl/LTo///nw+7lcFxwdQv+rAFTD3MDi2hQn9z+ze0j7v7O4LdbeqKBqHyXAAACAJD/7AYvBE4AEwAhAAABMz4BMzIAHQEUACMiJicjESMRMwEUFjMyNj0BNCYjIgYVAYPRGv3S7QEF/vzs2f8Vz/PzAb56hIJ8fISCegKI0Pb+0PcV+P7S/9n+PAQ6/diiwsOhFZ7Gxp4AAAACACcAAAPfBDoADQAWAAABESMRIwMjEy4BNTQ2MwMUFjsBESMiBgPf8uPn/P9maefPw1tb7eBiYQQ6+8YBjf5zAbUqmmebv/6gQFkBOF4AAAH/4f5LBAwGGAAoAAABIRUXPgEzMhYVERQGIyImJzceATMyNjURNCYjIgYHESMRIzUzNTMVIQJw/wADNZdgsL22qSU6IQ8ROxY7QGRoSW4m85yc8wEABK77AUtR1Of9Lre/CAm/BQhcVwLUgnA6NfzoBK6qwMAAAAEAWP/sA/4ETgAdAAAlMjY1MxQEIyICPQE0EjMyFhUjNCYjIgYHIRUhHgECQlt85f7/uPT5+fPH8+V1YnxwCQFW/qsLbq5nUaDaAS7xI/ABMOG3W3qegqiAlQAAAgAfAAAGmgQ6ABYAHwAAAREzMhYVFAYjIREhERACKwE/ATI2NREBETMyNjU0JiMD+u3Q4+PQ/iD+7b7jNAEkZFkC+e1jXVxkBDr+h7+foMMDdv73/r3+1sUByN8Bzf3F/sFeR0NXAAACAIYAAAaxBDoAEgAbAAABIREzETMyFhUUBiMhESERIxEzAREzMjY1NCYjAXkBpfPt0OPj0P4g/lvz8wKY7WNdXWMCnwGb/oe/n6DDAd3+IwQ6/cX+wV9GQ1cAAAH/9QAABAwGGAAcAAABIREXPgEzMhYVESMRNCYjIgYHESMRIzUzNTMVIQKE/uwDNZdgsL3zZGhJbibziIjzARQEtf7+AUtR1Of9bQKVgnA6NfzoBLWqubkAAAAAAQCG/poEEgQ6AAsAAAERIREzESERIxEhEQF5Aabz/rXz/rIEOvyIA3j7xv6aAWYEOgAAAAEAjf/rBrIFsAAgAAABERQGIyImJw4BIyImNREzERQWMzI2NREzERQWMzI2NREGsvbOcKo2OLBxye/zaVxod/dwY2JvBbD79drgUlRUUuDaBAv79X17en4EC/v1fXt6fgQLAAABAHD/6wXtBDoAIAAAAREUBiMiJicOASMiJjURMxEUFjMyNjURMxEUFjMyNjURBe3du2KVMDSaY7fW81BKV2L0WFNOVwQ6/VHN00ZISEbSzgKv/VFybG1xAq/9UXJsbXECrwAAAv/gAAAEIQYYABIAGwAAASERMzIWFRQGIyERIzUzETMRIQERMzI2NTQmIwKj/t7t0OPj0P4grq7zASL+3u1kXF1jBDn+ytGur9UEOasBNP7M/Vz+gmpUUW8AAAABAKL/7Aa2BcYAJwAAATM1EAAhIAAXIy4BIyIGHQEhFSEVFBYzMjY3MwYAIyAAETUjESMRMwGVvQE1AQABAgEVGPMTj5qYqwHs/hSpmpeRE/MW/uX9/v3+zr3z8wNQEwEPAVT+/fCYmOi2FcQ+ueeUl+b++QFRARE+/XQFsAAAAAEAhv/sBb4ETgAjAAABMzYSMzIWFSM0JiMiBgchFSEeATMyNjUzFAQjIgInIxEjETMBeaES9+HH8+V1YnpwCgF4/ocKb3xbfOX+/7ji9xKh8/MCctcBBeG3W3qaf6uCl2dRoNoBBNf+OQQ6AAIAIAAABQ4FsAALAA8AAAEjESMRIwMjATMBIwEhAyMDhITdd5H7AgfnAgD7/dgBW6sDAaz+VAGs/lQFsPpQAmcB/wAAAgAKAAAERQQ6AAsAEQAAASMRIxEjAyMBMwEjATMDJyMHAuRdw1to9wGp5wGr9/5c+GQXBBcBF/7pARf+6QQ6+8YBxAEGXl4AAgC2AAAHJwWwABMAFwAAASEBMwEjAyMRIxEjAyMTIREjETMBIQMjAakBawEs5wIA+4+E3XeR+5j+2PPzAlsBW6sDAmcDSfpQAaz+VAGs/lQBrP5UBbD8twH/AAACAJ0AAAYYBDoAEwAZAAABMxMzASMDIxEjESMDIxMjESMRMwEzAycjBwGQ/vjnAav3al3DW2j3bbrz8wHt+GQXBBcBxAJ2+8YBF/7pARf+6QEX/ukEOv2KAQZeXgAAAAACAIQAAAZpBbAAHAAfAAABHgEVESMRNCYrAQcRIxEnIyIGFREjETQ2ITMBIQETIQR0+vvzfZBpCfICgJB88/8BAAz+hQTc/ZLy/hwDKwPS8v6cAWSVbRH9qwJjA22V/pwBZPXSAoX9hgG1AAACAIIAAAVkBDoAGgAdAAAzNTQ2NwEhAR4BHQEjNTQmKwEHESMRIyIGHQEBEyGCycr+6wP0/urCxPNmdiQB8i13ZQGFlf7Wqd3MDQHb/iQQzNmpqZBrA/5fAaRrkKkCaQEiAAAAAgCtAAAIrgWwACQAJwAAIRE0NjchESMRMxEhOwEBIQEeARURIxE0JisBBxEjEScjIgYVEQETIQLJGx7+nvPzAxAYDP6FBNz+hPr7832QaQnyAoCQfAIL8v4cAWRRfjT9mQWw/XsChf17A9Ly/pwBZJVtEf2rAmMDbZX+nAM2AbUAAAAAAgCPAAAHdwQ6ACEAJAAAITU0NjchESMRMxEhASEBHgEdASM1NCYrAQcRIxEjIgYdAQETIQKVGhz+t/PzAqT+7QP0/urCxPNmdiQB8i13ZQGFlf7WqVB8M/5YBDr+KAHY/iQQzNmpqZBrA/5fAaRrkKkCaQEiAAAAAgAp/kADqgd4AC0ANgAAATI2NTQmIyE1ITIEFRQGBxUeARUUBCsBIgYVFBYXBy4BJzQ2OwEyNjU0JisBNQE3MxUFIyU1MwGQiH5/gP7lARvmAQx5b4KH/vfgNUU9VkJRhqEBtKkzeIaWlY8BBYvQ/vSd/vXOA05vZFtuxse9caAsAyqqgM7fNjFCSx6ZKbOBjYh8Znp5xwObjxH8+hMAAAIAM/5HA4gGCwAtADYAAAEyNjU0JiMhNSEyFhUUBgcVHgEVFAYrASIGFRQWFwcuASc0NjsBMjY1NCYrATUTNzMVBSMlNTMBl3Rqb2/+5QEb1vpeV2lt880xSUBTPlJ6nwGuoTBreIGAl9eL0P70nf71zgJvS0Q8R7mdlFB2IwMhd1WbqjYxQkseki+ueYWBT0FKSakDDY8R/PoTAAMAav/rBREFxQANABYAHwAAARAAISAAGQEQACEgABEFITU0JiMiBhUFIRUUFjMyNjUFEf61/vH+9v69AUIBCgEPAUz8SwLCwKijtwLC/T64o6m+AlX+8/6jAV4BDAEGAQsBX/6h/vUxM7Xr6rbeKrjr67gAAwBS/+wEMwROAA0AFAAbAAATNAAzMgAdARQAIyIANQEyNjchHgETIgYHIS4BUgEE6+0BBf787O3+/AHxcnoO/gsNenJxeQ4B8w97Aif2ATH+0PcV+P7SAS74/pyXhISXAt2XgICXAAABABEAAATvBcMAEQAAARczNxM+ATMXByMiBgcBIwEhAlwbAxvpNJJ9LgEULzsW/pLn/gwBBAGLcG4C/aiVAdA9RPuPBbAAAAABACAAAAQYBE4AFQAAARczNxM+ATMyFhcHLgEjIgYHASMBMwHjEgQSei6SaSExGBcEGw0jOg3+9tP+kvsBblpaAb6UjgkNwAIENir84gQ6AAQAav92BREGLgADAAcAFQAjAAABIxEzEyMRMwEQACEgABkBEAAhIAARJzQmIyIGFREUFjMyNjUDIMbGAcXFAfD+tf7x/vb+vQFCAQoBDwFM88Coo7e4o6m+BIQBqvlIAbQBK/7z/qMBXgEMAQYBCwFf/qH+9QK16+q2/vi46+u4AAAAAAQAU/+IBDQEtAADAAcAFQAjAAABIxEzAyMRMyU0ADMyAB0BFAAjIgA1MxQWMzI2PQE0JiMiBhUCori4A7e3/bQBBOvtAQX+/Ozt/vzzeoSCfHyEgnoDGwGZ+tQBoP/2ATH+0PcV+P7SAS74osLDoRWexsaeAAAAAAMAjf/rBqcHRAAsAD4ARAAAATIWFREUBiMiJicOASMiJjURNDYzFSIGFREUFjMyNjURMxEUFjMyNjURNCYjExUjIiQjIgYdASM1NDYzMgQzASc3JzMVBO7J8PDJcK03Oa1vye/vyVxpaVxod+x1aVxqalxqJIT+0CoyN4Z4c0gBKnL+N1E6AboFsO/m/eTm7k9RUU/u5gIc5fDDiIr95IuHen4Bi/51fnqHiwIciogB34Z4MjQSJW9qeP5LPXCPfQAAAAADAHT/6wXRBeMALAA+AEQAAAEyFh0BFAYjIiYnDgEjIiY9ATQ2MxUiBh0BFBYzMjY9ATMVFBYzMjY9ATQmIxMVIyIkIyIGHQEjNTQ2MzIEMwUHJzcnMwQ6ud7Ws2GUMTKUX7XU3LtOVk9HUV7sXVNGUFdNvSSF/tAqMjaHeHNJASly/tmiUToBugRH3tb119xHSklI3Nf11t7Dd3r1e3ZtccbGcW13evV6dwHnhngyNBIlb2p48L49b4kAAAIAjf/rBrIHBwAHACgAAAE1IRchFSM1BREUBiMiJjURIxEUBiMiJjURIxEUFjMyNjceATMyNjURAesDVQH+prUCjW9iY3D3d2hcafPvyXGwODaqcM72BpdwcH9/5/v1fnp7fQQL+/V+ent9BAv79drgUlRUUuDaBAsAAAACAHD/6wXtBbEABwAoAAABNSEXIRUjNQERFAYjIiY1ESMRFAYjIiY1ESMRFBYzMjY3HgEzMjY1EQGXAzgF/rG1AipXTlNY9GJXSlDz1rdjmjQwlWK73QVBcHB/f/75/VFxbWxyAq/9UXFtbHICr/1RztJGSEhG080CrwAAAQBq/ooEuAXFABgAAAEjESYCNREQACEgABUjNCYjIgYVERQWOwEDMPLa+gEwAQABAQEd85OYl6enl5b+igFoIAFF9gEVARABU/797ZWY57f+6bnnAAAAAAEAXP6JA/METgAYAAABIxEmAj0BNBIzMhYVIzQmIyIGHQEUFjsBAtXzvcn+6MLv5XBcf3RzgZL+iQFqIQEk0yPtATPitlt6yZQjmMYAAAAAAQBtAAAEkwU+ABMAAAEFByUDIxMlNwUTJTcFEzMDBQclAlsBIUj+3bWv4f7fRwElyv7eSQEjuazkASVM/uABwayAqv7BAY6rgKsBaKuCqwFG/murf6oAAAH8ZgSi/zkF/QAHAAABFSc3IScXFf0XsQECIgGxBSB+Ae5sAdwAAAAB/HMFF/9tBhUAEQAAATIkMzIWHQEjNTQmIyIEKwE1/JV0AS1JdXmIODIr/s2GJAWdeGpvJRI0MniGAAAB/XsFFv5yBmAABQAAATUzBxcH/Xu9ATtSBdyElnBEAAH9pQUW/pwGYAAFAAABJzcnMxX991I7Ab0FFkRwloQACPok/sQBvwWvAA0AGwApADcARQBTAGEAbwAAATQ2MzIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFRM0NjMyFhUjNCYjIgYVATQ2MzIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFQE0NjMyFhUjNCYjIgYVATQ2MzIWFSM0JiMiBhUTNDYzMhYVIzQmIyIGFf0RcGJjcHAvNDIvAd5xYGJycS80MS5IcGJicXAvNDMu/stxYGJxcC80MS/9T3BiY3BwLzQyL/1NcWJjcHAvNDIv/t5xYWNwcC41Mi81cWFjcXEuNTIuBPNVZ2dVLDk5LP7rVWdnVSw5OSz+CVVnZ1UsOTks/flVZ2dVLDk5LP7kVmZmVi04OC0FGlVnZ1UsOTks/glVZ2dVLDk5LP35VWdnVSw5OSwAAAAI+k3+YwGMBcYABAAJAA4AEwAZAB4AIwAoAAAFFwMjEwMnEzMDATcFFSUFByU1BQE3JRcGBQEHBSclAycDNxMBFxMHA/5QC3pgRjoMemBGAh0NAU3+pvt1Df6zAVoDnAIBQEQl/wD88wL+wEUBJisRlEHGA2ARlELEPA7+rQFhBKIOAVL+oP4RDHxiRzsMfGJHAa4QmUQXsfyOEZlFyALkAgFGRf7V/OMC/rtHASsAAAL/4AAABCEGYgASABsAAAEhETMyFhUUBiMhESM1MzUzFSEBETMyNjU0JiMCo/7e7dDj49D+IK6u8wEi/t7tZFxdYwUF/f7Rrq/VBQWrsrL8kP6CalRRbwADAJ8AAATaBbAAAwAOABcAAAEHATcBESMRITIEFRQEIyUhMjY1NCYjIQTabv5sbv5M8wI59gEM/vT2/roBRoqFhYr+ugIjZAG/ZP5G/dgFsPXP0fPDjnFxkgAAAAMAgP5gBDQETgADABYAJAAAJQcBNyUUAiMiJicHESMRMxc+ATMyEhEjNCYjIgYHER4BMzI2NQQtb/6XbwFw2speijID89kQNI9hzNvyen9NaSAgaFB/eA1jAaFkSvH+5D8/Af33BdqCSkz+yP74qdBAO/4XOjuzmAAAAAABAJQAAAQ0BxAABwAAASERIxEhETMENP1T8wKt8wTt+xMFsAFgAAAAAQB+AAADXAV0AAcAAAEhESMRIREzA1z+FPIB6/MDdvyKBDoBOgAAAAEAn/7GBJ0FsAAVAAABIREzIAAREAIhJzI2NS4BKwERIxEhBDf9W7EBIAE6+f78AZhzAbC2sfMDmATt/lb+1f7k/vv+z7rKq8PB/YcFsAAAAQB+/uID2wQ6ABUAAAEhFTMyBBUUAgcnPgE1NCYrAREjESEDRv4qU/UBI76+VHVonIlT8gLIA3bl+umL/vAxrSiLbImQ/jkEOgAAAAEAlAAABSwFsAAUAAAJAiEBIxUjNSMRIxEzETM1MxUzAQUE/nsBrf7O/s1Do1rz81qjOwEhBbD9Wfz3AnTq6v2MBbD9lf7+AmsAAAABAI4AAASuBDoAFAAACQIhAyMVIzUjESMRMxEzNTMVMxMElP7EAVb+y9gvm1fy8lebJ88EOv3+/cgBrLKy/lQEOv5Qx8cBsAABADQAAAahBbAADgAAASMRIxEhNSERMwEhCQEhA6yo8/4jAtCLAckBIP30AjX+1wJ2/YoE7cP9lwJp/Un9BwAAAQA+AAAFqQQ6AA4AAAEjESMRITUhETMBIQkBIQNBe/P+awKIawErASz+eQGo/sQBrP5UA3bE/lABsP36/cwAAAEAnwAAB4QFsAANAAABIREhFSERIxEhESMRMwGSAowDZv2M8v108/MDMAKAw/sTAm39kwWwAAAAAQB+AAAFZwQ6AA0AAAEhESEVIREjESERIxEzAXEBpQJR/qLz/lvz8wJ3AcPE/IoBtf5LBDoAAAABAJ/+xAfvBbAAFwAAATMgABEQAiEnMjY1LgErAREjESERIxEhBRGEASABOvn+/AGYcwGwtoTy/XPzBHIDQf7V/uT++/7Pusqrw8H9iQTt+xMFsAABAH7+5Qa7BDoAFwAAATMyBBUUAgcnPgE1LgErAREjESERIxEhBAqE/wEuvr5VdGoBppOE8/5a8wOMApX66Yz+8DGuJ4xsiY/+NgN2/IoEOgAAAAACAGn/6AXMBcUAKQA3AAAFIiYnDgEjIAARNRAAMxUiBh0BFBIzMjY3JgI9ATQSMzISERUUBgceATMBFBYXPgE9ATQmIyIGFQXMcsZaS6Fa/tn+nAEI22181bwYLhhxdOW+xexhXi5kOP2NZmdSVmFdWF8YIyUjIgGEAS+2AREBYMzpurjb/vMEBGMBB6LU8QE0/sb+/9SX/GELCgIdi9VJRs6B5a6ytqMAAAAAAgBh/+sEyQROACkAOAAABSImJw4BIyIAPQE0EjMVDgEdARQWMzI2Ny4BPQE0NjMyFh0BFAYHHgEzATU0JiMiBh0BFBYXPgE1BMlhpEg9g0rv/t7VsEJJlIMIEQxIR7GZm7hCPyZRLv7pOjQ1ODw8MTISGhwdHAFB/EvRAQrKBJN4TabMAQFKum5/vOn+x35rtEgJCAGAgGqIemWEVos1MIRTAAABAC7+oQaxBbAADwAAASE1IRUhESERMxEzAyMRIQGU/poDvf6cAozzqxTd+9QE7cPD+9UE7vsV/dwBXwABACb+vwU6BDsADwAAASM1IRUjESERMxEzAyMRIQEb9QLE3AGm85MU3fzSA3fExP1LA3j8iP39AUEAAAACAIIAAATcBbAAAwAXAAABIxEzAREjEQ4BIyAkNREzERQWMzI2NxEDLqOjAa7zUKth/v7+9/OBl1WzVAEsAtsBqfpQAkEWFdr1Acv+NZtwFhYCqgACAHQAAAP1BDsAAwAXAAAlIxEzASMRDgEjIiY1ETMRFBYzMjY3ETMCjaSkAWjzMWIz3evzZXA1XzLzzAJf/NUBaQsLytIBTP60dmILDAIMAAEAigAABOQFsAATAAAzETMRPgEzIAQVESMRNCYjIgYHEYrzUKthAQEBCvOCllezUgWw/b4VF9v0/jUBy5pxGBT9VgAAAgAg/+kFwAXEAB0AJgAABSAAETUuATUzFBYXEAAXIAARFSEVFBYzMjY3Fw4BASE1NCYjIgYVA+L+yf63oKKyRUsBQfUBEQEX/JW90G6eTzE1xf3hAniPppuoFwFUASJKF86sWnIVARMBWAH+nf6/hDzD6CghvCA4A2kftdHptwAC/87/7AR2BE8AGwAjAAAFIgAnLgE1MxQWFz4BFzISHQEhHgEzMjY3Fw4BAyIGByE1NCYCzub+9AWEhaoyNiH8teDk/VYKiX5kiUJHPcKiW3QSAbRnFAEd6R68l0pjGMXsAf7744+Hoi8tpjVDA5+NdRlpgAAAAAABAJT+xATnBbAAGAAAASMRIxEzETMBIQEWEhUQAiEnMjY1LgErAQGYEfPzcwHCAST+Gu7/+f78AZh0AbG29QJ4/YgFsP2hAl/9ix7+3P7++/7Ousqsw8AAAQCO/uoEQwQ6ABYAAAEeARUUAgcnPgE1LgEnIxEjETMRMwEhAs2tvr2+VXVpAZGGrvLyVQFBAS0CYSnbtYj++S+tJoRnfn4I/lQEOv5QAbAAAAAAAQCf/ksFEAWwABcAAAERIREzERQGIyImJzceATMyNjURIREjEQGSAozyt6klOiAOETsWPEH9dPMFsP2AAoD6EbbACAm/BQhdVgKs/ZMFsAABAH7+SwQJBDoAFwAAAREhETMRFAYjIiYnNx4BMzI2NREhESMRAXEBpfO4qSQ6IQ8ROxY7Qf5b8wQ6/j0Bw/uHtsAICb8FCF1WAfT+SwQ6AAIAU//qBRsFxQAWAB4AAAEgABEVEAAlIAARNSE1NCYjIgYHJz4BEzI2NyEVFBYCcwFKAV7+q/7+/sn+xgPW0uR2p1IxN8/robgL/R6wBcX+lv7Mov7X/o4BAWEBQoQV0/8pILwfOvrx6L0fttAAAAABAF3/6wRGBbAAGgAAARcBHgEVFAQjIiQ1MxQWMzI2NTQmKwE1ASE1BBsB/n/Q2/7o6cz+5POGb3+PlJmOAWr9kAWwm/5FGOPHzeDU1WSDgWmVhasBkcMAAQBd/nUERgQ6ABoAAAEhNSEXAR4BFRQEIyIkNTMUFjMyNjU0JisBNQL0/ZsDjAH+iMzW/ujpzP7k84Zvf4+UmY8DdsSb/kMZ48XL4dTUYoOCZ5WEqwAA//8AO/5LBIkFsAAmAKxSAAAmAdOkKQAHAZoBNQAAAAD//wA0/kkDogQ6ACYA51UAACcB0/+d/3oABwGaAQv//gACAFQAAASABbAACgATAAABETMRISIkNTQkMwERISIGFRQWMwOO8v3Z9v7xAQ73ATX+y4uHiIoDlAIc+lD80dD3/S4CD5Jwc5oAAAAAAgBmAAAGpQWwABgAIQAAISIkNTQkMyERMxE3PgE3NiYnMx4BBwYEIyURISIGFRQWMwJr9v7xAQ73ATXyTGVpBAEfHuwiIwIE/wDB/sL+y4uHiIr80dD3Ahz7EgEBdm9OolBlkknR2MICD5Jwc5oAAAIAXv/pBn4GGAAiADMAABMQEjMyFhcRMxEGFjM+ATc2JiczHgEHAgAjBiYnDgEjIgI1AS4BIyIGHQEUFjMyNjcuATVe2s1UgTPzAk1Ed38EAR4f7CIjAgT+6tOAqiw1l2rL2gKvI2NEf3Nxf0lmIwMDAg4BCAE4PTsCQvtPU2UBuahjyGiBtV3+8f7pAlVgWVoBHfEBJjI2zqsVma86OA8iEwAAAQA7/+gF4QWwAC0AAAE0JisBNTMyNjU0JiMhNSEyBBUUBgcXHgEdAQYWMz4BNzYmJzMeAQcCACMGJicCpntr1JuehYCP/qABYP4BBHx6AYJvAT42anIEAR4f7CMiAgT+9cunsAgBeG2BxW55aXDF0c90ojADJaiARD1KAbipY8hoiK9c/vD+6gOdsQABAC//4gT/BDoALgAAJQYWMz4BNzYmJzMeAQcOASMGJic1NCYrASczMjY1NCYjISchMhYVFAYHFx4BHQEDAQEhLFpfBAEfH+wjIwIF77WjmwhRTukCt2ddXmb++gYBDNbhVlYBZFbrKy0BjYJNoVFoj0jb4wNwhEs8QL1EQ0ZQw6ecUW8jAxp1WT4AAAIASf6sBCQFsAAhACsAABMnMzI2NTQmIyEnITIEFRQGBx4BHQEUFhcVIy4BPQE0JiMBFAYHJz4BPQEzlwHIlYSBiv7gAwEj9wEGc3N+aiAm+ikWfXICmmhVfyws5QJcw291b3vD2M9zoDMorYR4QXgiFyKLR3Rzgf3cZ9xJTkiTW7wAAAIAdf6cBAsEOgAhACsAABM1MzI2NTQmIyEnITIWFRQGBx4BHQEUFhcVIy4BPQE0JiMBFAYHJz4BPQEzs+VpZGZn/uEEASPW61dXYVMXHfsdDmJfAl5oVX8sLOUBnLNJRUdVwa+gUnMoIYJhVSdZFBEUYTFTT1T+jGfcSU5Ik1u8AAAAAAEAQ//oB34FsAAhAAABIREQAiEjNTMyEhkBIREGFjM+ATc2JiczHgEHAgAjBiYnBA3+VN3+9DUpjHcDkQFNRHd+BAEeH+wiIwIE/uvTuMIJBOv+Ff5q/pbEAQUBNwKw+7dUZAG5qGPIaIG1Xf7x/ukDtMsAAQA//+gGWQQ6ACEAAAERBhYzPgE3NiYnMx4BBwYCIwYmJxEhERACKwE/ATI2NREECgFRR11iBAEeH+wiIwIE97u7xgn+/7jfQAQpZFMEOv0tVGQBopZevWJ6q1j7/v4DtMsCDf76/rz+1tMBu98BzAAAAAABAJj/6AeFBbAAHQAAAREGFjM+ATc2JiczHgEHAgAjBiYnESERIxEzESERBQYBTUR4fgQBHx/sIiQCBf7r07fCCf138/MCiQWw+7dTZQG4qWPHaX+2Xv7x/ukDtMsBBv2TBbD9gAKAAAEAd//oBlwEOgAdAAABIREjETMRIREzEQYWMz4BNzYmJzMeAQcGAiMGJicDGv5Q8/MBsPMCUEheYwQBHx7rIyICBPe8usYJAbr+RgQ6/kMBvf0tU2UBopZdvWOBpVf7/v4DtMsAAAAAAQBi/+sEtgXFACEAAAUgABkBEAAhMhYXBy4BIyIGFREUFjM+ATc2JiczHgEHBgQCu/7w/rcBSQEQdK1GP0SOVqe/v6d/hQQBGhnrJhQBBP7jFQFYARIBBgERAVksLbAiIu61/vi57QGFe1OtYqpqTuDlAAABAFX/6wPlBE4AIQAAJT4BNzQmJzMeARUOASMiAD0BNAAzMhYXBy4BIyIGHQEUFgJaU0IDCgnrDQ4E1bL1/vABBupgizAuMHhFgH2GrwFERzdxNkZnMamnATXoKucBNSIgvRwey4wqj8oAAAABACL/6AVYBbAAGQAAASE1IRUhEQYWMz4BNzYmJzMeAQcCACMGJicB5/47BID+OAFNRHd/BAEfH+wjIgIE/uvTt8MJBOvFxfx8U2UBuKljx2l/t13+8f7pA7TLAAEARP/oBMwEOgAZAAABITUhFSERBhYzPgE3NiYnMx4BBw4BIwYmJwGJ/rsDi/6tAVFHXWMEAR8e6yMjAgT4u7rGCgN3w8P98FRkAYF4SptMY4lF2+MDtMsAAAAAAQCH/+sFAQXFACkAAAEiBhUUFjMyNjUzFAQjICQ1NDY3NS4BNTQkITIEFSM0JiMiBhUUFjsBFQLCp6G0pI2v8/656P70/sGGhHSAASoBC+YBNfOpf6KgkqC+AoZyfWmBg2TV1ODNf6krAy6jZszU3bted3xha3PBAAAA//8ArQJtBOoDMQBGAYbgAFMzQAD//wCyAm0F6gMxAEYBhrYAZmZAAP//AAT+PwOZAAAAJwBBAAH+/gAGAEEBAAABAGAD8wGWBjIACQAAEzQ2NxcOAR0BI2BkUoAuK90ErGbYSE1Ik1y7AAAAAAEAMwPWAWkGGAAJAAABFAYHJz4BPQEzAWllUn8tLN0FXGfYR01Hk12+AAAAAQAy/sIBaAENAAkAACUUBgcnPgE9ATMBZ2RSfyws3kdl2EhOSJNbxwAAAP//AEcD1gF9BhgARwFmAbAAAMABQAAAAP//AGID8wLlBjIAJgFlAgAABwFlAU8AAP//AEAD1gLABhgAJgFmDQAABwFmAVcAAAACADL+wgKqAQ0ACQATAAAlFAYHJz4BPQEzBRQGByc+AT0BMwFnZFJ/LCzeAUJlUn8sLN5HZdhITkiTW8fGZdhITkiTW8cAAAABAEAAAAQeBbAACwAAASERIxEhNSERMxEhBB7+iPP+jQFz8wF4A3L8jgNyyAF2/ooAAAAAAQBc/mAEOQWwABMAACkBESMRITUhESE1IREzESEVIREhBDn+iPP+jgFy/o4BcvMBeP6IAXj+YAGgwgK0xAF2/orE/UwAAAAAAQCIAf8CRAP4AA0AABM0NjMyFh0BFAYjIiY1iHZnaHd2aGh2AyFgd3ZhTWF0dGH//wCcAAADWADpACYAEAMAAAcAEAHNAAD//wCcAAAFEQDpACYAEAMAACcAEAHNAAAABwAQA4YAAAAGAEv/6wdgBcUAGQAnADUAQwBRAFUAAAE0NjMyFhc+ATMyFh0BFAYjIiYnDgEjIiY1ATQ2MzIWHQEUBiMiJjUBFBYzMjY9ATQmIyIGFQUUFjMyNj0BNCYjIgYVARQWMzI2PQE0JiMiBhUTJwEXAzClj0tyJiZyTI+mpY5NdCUmcUqRpf0boYyQpaWOjaIDjklER0JHREVGAcdKQ0ZDR0RFRvtNR0ZDR0hERUbqfQLHfQFlgas6NTU6q4FOgqo5NTU5qoIDgYKrq4JNgqmpgvzMQlhVRU5BWVlBTkFZVkROQVlZQQLmQldXQk1CWVlC+9VIBHJIAAAAAAEAbACXAjMDtgAGAAABEyMBNQEzATz3p/7gASCnAib+cQGGEwGGAAABAFQAlwIbA7YABgAAEwEVASMTA/sBIP7gp/f3A7b+ehP+egGPAZAAAQAtAG0DcQUnAAMAADcnAReqfQLHfW1IBHJIAAIAPwIwA1YFxQAKAA4AAAEzFSMVIzUhJwEzAxEnAwLUgoLE/jMEAczJxAP3A3iYsLBwAnX9swFOAf6xAAEAaQKMAv8FugATAAABFz4BMzIWFREjETQmIyIGBxEjEQEBICRuSX6FxUFBNEMTxQWseUFGk6D+BQHJZ1cvKv3SAyAAAQBPAAAEawXFACcAAAEOAQchByE1Mz4BNyM1MycjNTMnNDYzMhYVIzQmIyIGFRchFSEXIRUB6wIgHwLBAfwmCi8tAqehBZ6YBOTH0+Lza1dXYQQBiP5+BQF/AcBNfzLCwg2VXKaAp3zT6de6a2OBeHyngKYAAAAAAwCZ/+wGSQWwAAoAEwArAAABESMRITIEFRQEIyczMjY1NCYrASURMxUjERQWMzI2NxcOASMiJjURIzUzEQGT+gF49wEL/vX3fn6GgoKGfgPnw8MxKxksFBohXjGDj5WVAhz95AWw+c3T+8ySbmyQXf75tP2qRTYHBrIQFJmrAla0AQcAAQBL/+sD4AXFACsAAAEhFRQWMzI2NxcOASMiAD0BIzUzNSM1MzU0ADMyFhcHLgEjIgYdASEVIRUhA5z+NJeIO201FDp4P/L+4JKSkpIBH/E9ckQUN246h5YBzP40AcwB8AKapxERxQ8QARLxAo6cjgz2ARsQD8cQE7CcDo6cAAAEAHH/6wWJBcUAGwApADcAOwAAARQGIyImPQE0NjMyFhUjNCYjIgYdARQWMzI2NQEUFjMyNj0BNCYjIgYVMzQ2MzIWHQEUBiMiJjUTJwEXArGXh4mZmIiImKk9Ojs8PTw5PAEYpJKRoqOSkaOpR0RESENHQ0rBff05fQQlcZSpgk2DqpZxMURZQk1CV0Qv/PKDqamDToKqqoJBWVlBTkVVWUEDyEj7jkgAAAAAAgBF/+sDkAXFABoAJgAABSImPQEOASM1MjY3ETQ2MzIWHQEUAgcVFBYzAzU0JiMiBhURPgE1Atvq5DFiNTdhMLCfi6nPul13MCkiLSxSUhXs2AcLCbsLCwGyxtqxmiqY/sBnRYeBA4osPUJdYf6zR7ZjAAAEAJgAAAhPBcAAAwARAB8AKwAAASE1IQE0NjMyFh0BFAYjIiY1MxQWMzI2PQE0JiMiBhUBIwEHESMRMwE3ETMIEP3GAjr9irmhorm5oKK6r1ZXVFZXVVVW/sDy/XcD8/MCiQPyAXyVAmCXuLiXdZi2tphXZWVXdVRnZ1T7jwQrAfvWBbD71gEEKQAAAAIAZAOUBGIFsAAOABYAAAEnAyMDBxEjETMbATMRIwEjESMRIzUhA/QDhD2JA2+JkJGDbv33inWIAYcE2QH+ugFSAf6vAhz+gwF9/eQBvf5FAbtfAAIAlv/sBJEETgAVAB4AACUOASMiADU0ADMyAB0BIREeATMyNjcBIgYHESERLgEEFFm4Yd7+0gE/zdMBHP0AOYlPYbZZ/pBLizsCHDeIXjg6AUTt5gFL/s7rL/64Njg7PwMqQDr+6wEeNjsA//8Aaf/1Bl8FsgAnAckAEgKGACcBdAEMAAAABwHQA1EAAAAA//8Aav/1BvYFwAAnAcsACgKUACcBdAHFAAAABwHQA+gAAAAA//8Aav/1ByYFrwAnAc0AAgKOACcBdAH9AAAABwHQBBgAAAAA//8Aav/1BoUFrwAnAc8AGAKOACcBdAFCAAAABwHQA3cAAAAAAAIAQ//rBE4F7QAUACIAAAEEABEVFAAjIgA1NBIzMhYXNy4BJwEuASMiBhUUFjMyNj0BAegBGQFN/tjl5f7n+OJSkTkDL9mXAb4llW+AfJB/e5sF7Ub+Nv6kZP3+ywEV1OoBDy8rAqnNMf1rPE6tkHqtz6FmAAAAAAEApv8bBPQFsAAHAAAFIxEhESMRIQT01/1f1gRO5QXU+iwGlQAAAAABAED+8wTBBbAADAAACQEhFSE1CQE1IRUhAQOP/e4DRPt/Ak/9sQRH/PYCEgJD/XPDlwLIAsaYw/1zAAABAJ4CbQPhAzEAAwAAASE1IQPh/L0DQwJtxAAAAQA7AAAEiwWwAAsAAAEXMzcBMwEjAyM1IQIiHQMcAVvS/he+2NEBYwF8hYUENPpQAkHFAAMAZP/rB9kETgAZACcANQAAARQAIyImJw4BIyIAPQE0ADMyFhc+ATMyABUjNCYjIgYHFR4BMzI2NSEUFjMyNjc1LgEjIgYVB9n++uGi409P5KHi/vwBA+Gi5U9O5aPgAQXzeniHuhgVvIZ5e/pxeHuFvBYXu4d5eAH/6/7XwJaWwAEp6zrqASu+k5O+/tXqmrj4YSRi/7WdnbX/YiRg+bebAAAAAf+y/ksCqAYtABwAAAUUBiMiJic3HgEzMjY1ETQ2MzIWFwcuASMiBhURAZC3qSU4IQ8SORY7Qb+zJEctGRcpHFFSP7e/CAm/BQhdVgT3tr8LCrkFBlxW+wkAAAACAGUA/QQiBAEAGwA3AAATPgEzNhYXHgEzMjY3HwEOASMiJicuAQciBgcnBz4BMzYWFx4BMzI2Nx8BDgEjIiYnLgEHIgYHJ28weUNHSl9RTERBeS8DCjF5QkRMUV9KR0J5LgMUMHlDR0pfUUxEQXkvAwoxeUJETFFfSkdCeS4DA21GTAIcLyobSkQBwUdLGyovHAJLQwHtRkwCHC8qG0pEAcFHSxsqLxwCS0MBAAAAAAEAmACBA/YEwgATAAABMxUhByEVIQcnNyM1ITchNSE3FwM6vP7TfAGp/eh+ZFq+AS18/lcCGoNkA9bK38njQaLJ38rsQQAA//8AqgAVBBYErwBnAB4AkgDQQAA5mgAHAYYADP2oAAD//wCgABMEAATDAGcAIAAgAORAADmaAAcBhgAI/aYAAAACACQAAAP5BbAABQAPAAABMwkBIwEhAycjBwMTFzM3AaTSAYP+gNP+fgLZ3BQDFNfdEwMUBbD9J/0pAtcB30FB/iH+IkBAAP//ALMAtgGlBPAAJwAQABoAtgAHABAAGgQHAAAAAgBjAn8CPgQ5AAMABwAAASMRMwEjETMBAJ2dAT6dnQJ/Abr+RgG6AAEARf83AVoBBgAJAAAlFAYHJz4BPQEzAVpQRYAmJsmbYMNBTj9/UHMAAAAAAgAYAAAEFwYtABcAGwAAMxEjNTM1NDYzMhYXBy4BIyIGHQEzFSMRISMRM72lpeLTSopeJT92R3Bj1dUCZ/PzA4a0XMfQHh7JFhpfY1y0/HoEOgAAFgBZ/nIH7AWuAA0AHQArADsAQQBHAE0AUwBdAGEAZQBpAG0AcQB1AH4AggCGAIoAjgCSAJYAAAE0JiMiBh0BFBYzMjY1BTI2NTQmJzU+ATU0JisBEScUBiMiJj0BNDYzMhYVBRQGIyImNSMUFjMyNjURIwERMxUzFSE1MzUzEQERIRUjFSU1IREjNQEzHgEVFAYrATUBNSEVITUhFSE1IRUBNSEVITUhFSE1IRUTMzIWFRQGKwEFIzUzNSM1MxEjNTMlIzUzNSM1MxEjNTMDN39oaH5+amh9ASBeZzQtJSptZ7yfSEFDSUhCQUoDujYpMzVdaF1TaFz5xHHEBSjHb/htATXEBewBNm/82gUwMjQzfgFOARb9WwEV/VwBFAIKARb9WwEV/VwBFLxdPjg6PF388XFxcXFxcQcib29vb29vAkRieXlicGR3d2TYTk0uRA0DDjwoTEr929hHTExHcEVOTkWbLDYsL1NRW1ABevtPATvKcXHK/sUGHwEddKmpdP7jqfy2Ai0nKSqpA0p0dHR0dHT5OHFxcXFxcQRbHygpJ5b8fvr8Ffl+/H76/BX5AAAAAAUAXP3VB9cIYgADAB0AIQAlACkAAAkDBTQ2Nz4BNTQmIyIGBzM+ATMyFhUUBgcOARUXIxUzAzMVIwMzFSMEGAO//EH8RAQPGSlJXaaWi6UCywE6LDc6MitQOsrKyksEBAIEBAZS/DH8MQPP8TY7GyiAUIOUgYk0Mz42Mk0cOVZaW6r9TAQKjQQAAAAAAQBN/+8DygSNAB4AABsBIRUhAz4BNzYWFRQGIyImNTcUFjMyNjU0JiMiBgd8RwLJ/gwdJmo7usrY58L88m9daWNlXFlYFAH4ApXG/vMWIAIDx7u1z6KnEEZTamBday4oAAAAAAIATQAAAyUDIQAKAA8AAAEzFSMVIzUhJwEzATMRIwcCs3Jyv/5jCgGmwP5g4QMPASKRkZF0Ahz+AQEbGAAAAAACAGz/6wQnBcUADQAbAAABEAIjIgIZARASMzISESc0JiMiBhURFBYzMjY1BCf74eH+/OHh/fN2dXV1dnZ1dAIx/t7+3AElASEBTQEhASb+2v7fJbapqbb+a7ipqLkAAAAB/5/+xQLtA0IADwAAAzMgABEQAiEnMjY1LgErAWH0ASABOvn+/AGYcwGwtvQDQv7V/uT++/7Pusqrw8EAAAAAAf+w/ksBjgDNAA8AACURFAYjIiYnNx4BMzI2NREBjrepJTghDhE5FzxAzf70t78ICcYFB1ZVAQwAAAAAAQAY/l8B0wBCABMAACUeARUUBiMiJic3HgEzMjY1NCYnAQ9lX4lsQ1wnIx0vITouOjhCNYtNZ28ZE44KDS0jME0xAAABAFz+mgFPALYAAwAAASMRMwFP8/P+mgIcAAAAAgB1BNAC9wbcAA0AIQAAARQGIyImNTMUFjMyNjUTFAYjIiYjIgYVJzQ2MzIWMzI2NQL3rJWWq69ETkxGkF5IOYEpICloXUktiyseLAWwZ3l6ZjI9PTIBD01pRzIlG0tuRzElAAIAdQTVAvYHCAANAB0AAAEUBiMiJjUjFBYzMjY1JSc+ATU0JiM3MhYVFAYPAQJIR0tNR62ql5Wr/nMIST5NRQecoVJAAQWwMTw8MWV2dmUZdgIWGx0ZYE5GNTUHOgAAAAIAdQTTAwAGfgANABEAAAEUBiMiJjUzFBYzMjY1JzMHIwMAr5aZrbFGT0xHZbapgAWwZXh4ZTI+PjLOwAAAAAACAHkE5wNYBtEACAAcAAABByMnByMnJTM3FAYjIiYjIgYVJzQ2MzIWMzI2NQNYAbyzsrwBASaTulc/M3glHChaVEEogiUbKwTqA46OA+rfP15CLBsYP2FBLRwAAAIAdQTnBAoGywAGABYAAAEjBTM3FzMvAT4BNTQmIzcyFhUUBg8BAka7/urBsrPBXQdBNkQ9B4iNSTgBBeH6oqKGfQQZHSEdaVdNOz0HOwAAAv9MBNoDXAaDAAYACgAAASMnByMlMwUjAzMDXNWfn9QBI6H+h53X3QTajo76XAELAAAAAAIAegTnBIsGkAAGAAoAAAEzBSMnByMBMwMjAZ2hASPUn5/VAzPe2J0F4fqOjgGp/vUAAAACAFsElQMVBpgADQARAAABFAYjIiY1MxQWMzI2NScjJzMDFbuio7q1UFhWUDq/0vsFsIKZmYI7SUk7FdMAAAAAAQCQBGkBhQYMAAUAABM3MwMVI5B3fhvaBQ3//veaAAACABwAAASsBI0ABwAKAAAlIQcjATMBIwEhAwNX/hlW/gHM+AHM/v4KAVes6ekEjftzAasBzQAAAAMAjgAABC4EjQAPABgAIQAAMxEhMhYVFAYHFR4BFRQGIwERITI2NTQmIyUzMjY1NCYrAY4BrdvrYFpxdtzS/wABAGJZWmH/ALtqaWVuuwSNnqNUgCADGo5jpqQB+v7GS01PU6hISE4+AAAAAAEAaP/vBDIEnQAbAAABDgEjIgA9ATQAMzIWFyMuASMiBh0BFBYzMjY3BDEP+NXb/u4BEtvZ9BDzEG1tc4iJcnFoEAGU1NEBFOS+4wEV0dJ3a62Jv4quaXwAAAAAAgCOAAAEQgSNAAkAEwAAMxEhMgAdARQAIwMRMzI2PQE0JiOOAbfeAR/+4d7FxXSWlnQEjf741tLX/voDzPz0oH3Te6EAAAAAAQCOAAADzgSNAAsAAAEhESEVIREhFSERIQN4/ggCTvzAA0D9sgH4Afz+xMAEjcH+8gAAAAEAjgAAA9oEjQAJAAABIREjESEVIREhA4P9/fIDTP2mAgMB3v4iBI3B/tQAAQBo/+8EXwSdAB8AACUOASMiAD0BNAAzMhYXIy4BIyIGHQEUFjMyNjc1IzUhBF8577/v/t8BH+nh7hPyDnNvf5eYhmJ0H+8B4Z9IaAEF2fPXAQbCtF1Ynn30gJ4fF9SxAAAAAAEAjgAABHoEjQALAAAhIxEhESMRMxEhETMEevT9+vLyAgb0Adj+KASN/g0B8wAAAAEAjgAAAYAEjQADAAAhIxEzAYDy8gSNAAEALv/uA4wEjQAPAAABMxEUBiMiJjUzFBYzMjY1Apry6b3P6fNpXE9lBI385bXPubpbWGpaAAAAAQCOAAAEXQSNAAwAAAEjESMRMxEzASEJASEB62vy8lUBQQEt/mQBtv7LAdX+KwSN/iAB4P3V/Z4AAAAAAQCOAAADeQSNAAUAACUhFSERMwGAAfn9FfLAwASNAAABAI4AAAVuBI0ADgAACQEhESMRIwEjASMRIxEhAv4BQAEw8wP+2KX+2APyATIBKwNi+3MC/v0CAwH8/wSNAAAAAQCOAAAEhQSNAAsAACEjAQcRIxEzATcRMwSF8v3wA/LyAhAD8gMeAfzjBI385AEDGwAAAAIAZv/uBGQEnQANABsAAAEUACMiAD0BNAAzMgAVJzQmIyIGHQEUFjMyNjUEZP7p6Of+6AEW6OcBGfOOf4CLjX9/jQHn5f7sARTlvuQBFP7s5AGPp6ePv5GoqJEAAgBo/38ElASdABMAIQAAARQGBxcHJw4BIyIAPQE0ADMyABUnNCYjIgYdARQWMzI2NQRmODacoaE3c0Hn/ugBFujnARnzjn+AjI2Af40B52OlQZ2CoBkYARTlvuQBFP7s5AGPp6aQv5GoqJEAAgCOAAAESQSNABsAJAAAAREjESEyFhUUBgcVHgEdARQWFxUjLgE9ATQmIyczMjY1NCYrAQGA8gHO1uphYGxcERX6FQpgYPDcaWRlaNwBvf5DBI22pl6CKQMejWtWLGYXEBZsOFRWWcJUT05cAAAAAAEAT//uBBkEnQAlAAABNCYnLgE1NDYzMhYVIzQmIyIGFRQWFx4BFRQEIyIkNTMeATMyNgMnbJPlyfLV2u/yam1uZ2Sj28v/AN/d/vLyAYlvd3YBOz5NITSWoJa2v69RXEw+QUgkM5uanrG4uV9STQABADwAAAPpBI0ABwAAASERIxEhNSED6f6g8/6mA60DzPw0A8zBAAAAAQB+/+4EewSNABEAAAERFAQjIiQ1ETMRFBYzMjY1EQR7/uvp6f7q8o5/f40Ejf0KzN3dzAL2/Qpyd3dyAvYAAAEAHAAABIsEjQAJAAABFzM3ASEBIwEhAkARAxEBJQEB/kP3/kUBAQE1R0QDW/tzBI0AAAABADQAAAXXBI0ADwAAATMTIQEjAyMDIwEhEzMTMwQ4A5sBAf7j580DzOf+5AEAnAPK0gFZAzT7cwMM/PQEjfzJAzcAAAEALAAABFEEjQALAAABEyEJASELASEJASECPPEBG/6KAX/+5/n4/uUBgP6JARkC+AGV/b/9tAGd/mMCTAJBAAABABMAAAQ8BI0ACAAACQEhAREjEQEhAigBCQEL/mLz/mgBCwJvAh79Cv5pAaIC6wABAEoAAAPrBI0ACQAAJSEVITUBITUhFQF+Am38XwJZ/cgDcMDAegNSwXUAAAIAbf/vBBMEnQANABsAAAEUBiMiJjURNDYzMhYVJzQmIyIGFREUFjMyNjUEE/3V1v781tX/83dqaXZ3aml2AZvI5OTIAVfH5OTHAWx9fmv+qG5+fW8AAAABAD4AAAHzBJ0ABQAAISMRIzUlAfPzwgG1A6e6PAAAAAEAUgAAA5IEnQAYAAApATUBPgE1NCYjIgYVIzQ2MzIWFRQGDwEhA5L80QGeVkNMTlph8+bIvc6DntMB+8ABg1FrOEZfZE6j0LmteKuNxwAAAQBN/+8DuwSdACgAAAEyNjU0JiMiBhUjNDYzMhYVFAYHHgEVFAYjIiY1MxQWMzI2NTQmKwE1AgZcVFxaTmLy6LPL5F5WYmX2zLP58WpYXWtfY7kCq09LQFdMPpmyqaNSgicjh2Wls6ytQVhdRVpPsQAAAAACADkAAAQYBI0ACgAPAAABMxUjFSM1IScBMwEhEScHA3Gnp/L9xQsCQ/X9yQFFAwIBm8PY2J8DFv0OAboBBAAAAQBRAAAENAXFABgAACkBNQE+ATU0JiMiBhUjNAAzMhYVFAYHASEENPw5Adp2VnBjgnrzAQXq1vCKl/63ApinAgWCn09kgo2BygEH5L+A3qb+pAAAAgBt/+8D8ASdABoAJwAAATIWFwcuASMiBh0BPgEzMhYVFAYjIiY1ETQkEyIGBxUUFjMyNjU0JgJcSotDJzltSHKNModVvcX1zMX9ARexT2sbeV5ba2AEnRoYuhcUi3VWMTTCsrLW+MoBKc71/ZIyLh5wkm5UW2MAAQA8AAADZgSNAAwAAAEGAhEVIzUQEjchNSEDZriW8+OE/bADKgPM5f7e/vS5uQEHAYqCwQAAAAADAFL/7wPnBJ0AFwAjAC8AAAEUBgceARUUBiMiJDU0NjcuATU0NjMyFgM0JiMiBhUUFjMyNgM0JiMiBhUUFjMyNgPEZFlpd/3Fzf76em1eZvC/t+nQeVdgf39hWHcjZElSa21RSWMDXFeCJymMX6W0tKVfjCkngVicpaX9XUlcXElLW1sCREBOTEJBUVEAAAACAD//7wO1BJ0AGgAnAAAlMjY9AQ4BIyImNTQ2MzIWFREUBCMiJic3HgETMjY3NTQmIyIGFRQWAeFify1xQsjb98nA9v79ykiaRyY+c2JKZRt0WllqZa9/YVoqKs20qd75yv62u+YaGLgXEwGUNCpAbY57UFtzAAABAFcAAAGWAywABQAAISMRIzUlAZbAfwE/An+WFwAAAAEAawAAAtUDLAAYAAApATUBPgE1NCYjIgYVIzQ2MzIWFRQGDwEhAtX9oQExQiYyNz4/vqqUjphfeogBZ5EBADdEKi03OzFtkYB3U3JrdAAAAQBg//UC6wMsACgAAAEyNjU0JiMiBhUjNDYzMhYVFAYHHgEVFAYjIiY1MxQWMzI2NTQmKwE1AaFCPEA/Nj6/q4WYqUY+R0qxmIq4v0Q+QkpFR3sB2TQxKDQsImh4dXA4WRoYXkVyenh3LDIzLjk2gwAAAAABADgAAAJGBbAABQAAISMRITUlAkbz/uUCDgSgpmoAAAEAaP/1AwEDIQAeAAAbASEVIQc+ATc2FhUUBiMiJjU3FBYzMjY1NCYjIgYHiTQCFP6VFRxMLIeVoayRu75NQUpERj0+Pw8BWgHHkqoRFgECi4CAj290DC0xPjw/SR4ZAAIAcP/1AwoDLAAaACcAAAEyFhcHLgEjIgYdAT4BMzIWFRQGIyImPQE0NhMiBgcVFBYzMjY1NCYB4DdnLiApTzJRYiViP4iNtpeTus6DNkoSUkBCSUQDLBIRjQ8PWE0zICKHeXuUqo3Ij6n+Sx8cEEtbQTc6PwAAAAEAUgAAAqQDIQAMAAABDgEdASM1NBI3ITUhAqSHaL+aWf5pAlICj6C7tX9/tAELUZIAAAADAGj/9QMOAywAFwAjAC8AAAEUBgceARUUBiMiJjU0NjcuATU0NjMyFgM0JiMiBhUUFjMyNgM0JiMiBhUUFjMyNgL2SUBLVrqSmMJYT0RLs46IraZTPENYWEQ9URpDMjlISjgxQwJQO1obHWFAcnt7ckBhHRtaO2txcf4wMDs7MC82NgGIKC4tKSoyMgAAAAACAGD/9QLwAywAGgAnAAAlMjY9AQ4BIyImNTQ2MzIWHQEUBiMiJic3HgETMjY3NTQmIyIGFRQWAZVEWCBRLZOgs5KRusOYNW40ICtTSzVGD1E+PUdFhk5AOyAfkH91mK2M3oKeERGOEQ4BESUeGUpdSzU7SAAAAAACAHD/9QMkAywADQAbAAABFAYjIiY9ATQ2MzIWFSc0JiMiBh0BFBYzMjY1AyS7n5+7up+evb9SSkpQUEtJUgEnkKKikNGPpaWPAktVVUvTTlNTTgABAJcChwMmAzEAAwAAASE1IQMm/XECjwKHqgAAAwCWBEgCngaVAAQAEAAcAAABMxcHIwc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBgG84QHxlYJrUU5qaU9Ra2MzJiQwMCQmMwaVA7/eTWVkTk1gYE0mMDAmJzMzAAACAGwEbwLMBdcABQAPAAABEzMVAyMlNDY3Fw4BHQEjAYpv0+Zc/uJbVVAqJbEEhQFAFf7BVlqKLEgpYURSAAAAAQBP/+sEFgXFACgAAAEzMjY1NCYjIgYVIzQkMzIWFRQGBx4BFRQEIyIkNTMUFjMyNjU0JisBAYapeWVub2V78wECztn6b2x/cv7x2s7+8POAbnOAdX+pA0ZzbWtxb16v4dTLX6sxLbB2zOHUx2N2eHJ+cgACADgAAARZBbAACgAPAAABMxUjESMRIScBMwEhEScHA6G4uPL9jwYCb/r9hwGHAxcCB8T+vQFDlQPY/FcCVgExAAAAAAEAgf/rBCYFsAAeAAAbASEVIQM+ATc2EhUUAiMiJDU3FBYzMjY1NCYjIgYHnFQDAf3JLCxvSNHk8OvE/vrremVzdXhzZl4XAosDJdL+kyApAgP+/Ora/vTRyQhsdJ2FhqM/PwACAHT/6wRGBcUAGgAnAAABMhYXBy4BIyIGHQE+ATMyEhUUAiMiABkBEAATIgYHFRQWMzI2NTQmAqhQjTouOWdIlK89nWDH3//Y4v7nATy0XX4jkndtd34FxSAcvBgb3cMHODv+89fk/ucBMgEeARYBIgFS/UpAOWi9xLOIhaIAAAMACv5KBBsETgAvAD8ATQAAASMeAR0BFAYjIiYnDgEVFBY7ATIWFRQEIyImNTQ2Ny4BNTQ2Ny4BPQE0NjMyFhchASImJw4BFRQWMzI2NTQmIwEUFjMyNj0BNCYjIgYVBBuKHB73yipJIxITQj2xxc3+1vno/GNTGRk/Nlxi9s0rTicBcf2GGCoUJy59fZCiUGX+zHNgXXJzXl9yA6AqXzUWnc8IChEoGSsilJWF2552WXwpFzwnQ18mMZxhFqPJCgr73gMEFUYwPlFiPDo7ArRJaGhJFktlZUsAAAABADIAAAP3BbAADAAAAQoBAwcjNxoBNyE1IQP3+KQnD/MPJ9zH/ScDxQTt/tP+NP6mmpoBUgIO88MAAAABAD7+TQREBEoAIwAAEzIWHwETMwETHgEXOgE3Bw4BJy4BLwEDIwEDLgEjIgYHJz4BwYxzPVvh9f6fxRo9KxARDwcTNhdxeT9l+PgBfKccWTwMKA8CH0IESoqGzgHO/Sj+QT1EBQLGBgYBBZST5v4AAwwBgEVRBAG6CAsAAwBh/+sEKgXFABcAIwAvAAABFAYHHgEVFAQjIiQ1NDY3LgE1NDYzMhYDNCYjIgYVFBYzMjYDNCYjIgYVFBYzMjYEBXVqeor++dzf/vmIfGp08c3L9c2HbG6DgnFthCZwXV9sbWBdbgQwcaYuL7V6z9PTz3u0MC2mccbPz/yjbYSDbnB8fQL9Ynl1ZmV1dQAAAgBW/+sEXwROABQAIgAAJScOASMiAj0BEBIzMhYXPwEzAxMjARQWMzI2NzUuASMiBhUDZAM2qn7O397Reqc3AxvdbHPd/cdxf21vFxFzbX9zvwFpbAEd8RUBCAE4bGcBvv3i/eQB+Zmzt5ovm8PRrAAAAAACAFP/6wQ0BbAAGgArAAABFSEeARcWEh0BFAAjIgA9ATQSNzI2My4BJzUTFBYzMjY9ATQmJy4BIyIGFQPD/lQaZzqvs/787Oz+++bHCQwMgZI3b3qEgnxgSBMjFYmABbDBG1gul/77nxXw/t0BHegVwwEHHAF0iD+J/E6ZuLmYFW6pMAQEupUAAgCfAAAEyAWwAAkAEwAAMxEhIAARFRAAIQMRMzI2PQE0JiOfAZ4BUwE4/sj+rauk57i45wWw/tH+z/H+z/7SBO371cXY89XGAAAAAAIAYP/rA/4ETgAfACoAACEuAScOASMiJjU0NjsBNTQmIyIGFSM0NjMyFhURFBYXJTI2NzUjIgYVFBYDCAkMAzefYqys8+qrX2VjWfPd4dHXDxT98lSDIa96bUcdNRw6SaKiqqR6VEZMQ5S4oLn+BEZ4O647K9FdVUJDAAACAJ8AAAT+BbAADgAXAAABFAYHARUhASERIxEhMgQBITI2NTQmIyEEqn93AUr+9f7d/sLzAg34AQb86AEbhoSCif7mBAaGwDX9iBMCS/21BbDa/jh7dXB/AAAAAAEAnwAABS8FsAAMAAABBxEjETMRNwEhCQEhAieV8/OSAasBIP3eAmL+zAKApf4lBbD9X6sB9v2J/McAAAEAgQAABDwGGAANAAABBxEjETMRFzcBIQkBIQHgbfLyA1ABLQEe/m0Bvv7mAc9z/qQGGPxxAWEBUf5A/YYAAAABAJ8AAAURBbAACwAAAREjETMRMwEhCQEhAZLz8wcCJgEt/ZsCiv7TAp/9YQWw/X8Cgf02/RoAAAEAgQAABCIGGAAMAAABBxEjETMRFwEhCQEhAXYD8vIDAVYBKv5QAdz+2wHnAf4aBhj8iAEBm/4M/boAAAIAUv/rBBcFxQAbACgAACUyNj0BJw4BIyICNTQAMzIAGQEQACMiJic3HgETMjY3NTQmIyIGFRQWAgOFnQMwilXV7AEKy+cBCf7c8EyeRCBAfXhdfSGAemSCdq29vSMBQUIBBPHmASL+3P7k/qv+5v7VHh64GxcB2EY7nLGvt46SpgAAAAIAjgAABEAEjQAKABMAAAERIxEhMhYVFAYjJzMyNjU0JisBAYDyAePY9/fY8fFscHBs8QGG/noEjdaur9TCblFTcgD//wB1BJUC+wWwAgYAnAAA//8AAAAAAAAAAAIGAAMAAP//AEcCCQJUAs0CBgAPAAAAAgAkAAAFDAWwAA0AGwAAMxEjNTMRISAAERUQACETIREzMjY9ATQmKwERIb2ZmQHKASoBW/6i/sw5/v3D2c3Kz9ABAwKRqgJ1/qb+4sH+4P6pApH+MerLw83m/k4AAAAAAgAkAAAFDAWwAA0AGwAAMxEjNTMRISAAERUQACETIREzMjY9ATQmKwERIb2ZmQHKASoBW/6i/sw5/v3D2c3Kz9ABAwKRqgJ1/qb+4sH+4P6pApH+MerLw83m/k4AAAAAAf/9AAAEKgYYABwAAAEjERc+ATMyFhURIxE0JiMiBgcRIxEjNTM1MxUzAoz+AzWXYLC982RoSW4m856e8/4Ex/7sAUtR1Of9bQKVgnA6NfzoBMeqp6cAAAEANQAABLUFsAAPAAABIxEjESM1MxEhNSEVIREzA73P883N/joEgP45zwMS/O4DEqoBMcPD/s8AAf/n/+wCdgVBAB8AAAERMxUjFTMVIxEUFjMyNjcXDgEjIiY1ESM1MzUjNTMRAaHDw9XVMSsZLBQaIV4xg4/Hx5WVBUH++bSlqv75RTYHBrIQFJmrAQeqpbQBB///ABoAAAUoByICJgAjAAAABwBCAPwBXP//ABoAAAUoByECJgAjAAAABwBzAbMBW///ABoAAAUoB0cCJgAjAAAABwCaALcBWf//ABoAAAUoB2MCJgAjAAAABwCgALkBbP//ABoAAAUoBw0CJgAjAAAABwBoAJMBXf//ABoAAAUoB48CJgAjAAAABwCeAUwBs///ABoAAAUoB70CJgAjAAAABwHUAVIBKP//AHT+PATYBcUCJgAlAAAABwB3Acb/+///AJ8AAAR1ByICJgAnAAAABwBCAMQBXP//AJ8AAAR1ByECJgAnAAAABwBzAXsBW///AJ8AAAR1B0cCJgAnAAAABwCaAH8BWf//AJ8AAAR1Bw0CJgAnAAAABwBoAFsBXf///8wAAAGgByICJgArAAAABwBC/4IBXP//AK0AAAKEByECJgArAAAABwBzADgBW////9gAAAJ5B0cCJgArAAAABwCa/z0BWf///70AAAKSBw0CJgArAAAABwBo/xkBXf//AJ8AAAUQB2MCJgAwAAAABwCgAO4BbP//AHT/6wUbBzcCJgAxAAAABwBCASMBcf//AHT/6wUbBzYCJgAxAAAABwBzAdoBcP//AHT/6wUbB1wCJgAxAAAABwCaAN4Bbv//AHT/6wUbB3gCJgAxAAAABwCgAOABgf//AHT/6wUbByICJgAxAAAABwBoALoBcv//AIb/6wTxByICJgA3AAAABwBCARcBXP//AIb/6wTxByECJgA3AAAABwBzAc4BW///AIb/6wTxB0cCJgA3AAAABwCaANIBWf//AIb/6wTxBw0CJgA3AAAABwBoAK4BXf//ABMAAATvByECJgA7AAAABwBzAZYBW///AF7/7AQBBeACJgBDAAAABwBCAIEAGv//AF7/7AQBBd8CJgBDAAAABwBzATgAGf//AF7/7AQBBgUCJgBDAAAABgCaPBcAAP//AF7/7AQBBiECJgBDAAAABgCgPioAAP//AF7/7AQBBcsCJgBDAAAABgBoGBsAAP//AF7/7AQBBk0CJgBDAAAABwCeANEAcf//AF7/7AQBBnwCJgBDAAAABwHUANf/5///AFH+PAP3BE4CJgBFAAAABwB3AT7/+///AFn/7AP4BeECJgBHAAAABwBCAIMAG///AFn/7AP4BeACJgBHAAAABwBzAToAGv//AFn/7AP4BgYCJgBHAAAABgCaPhgAAP//AFn/7AP4BcwCJgBHAAAABgBoGhwAAP///68AAAGCBcsCJgCKAAAABwBC/2UABf//AI8AAAJnBcoCJgCKAAAABgBzGwQAAP///7sAAAJcBfACJgCKAAAABwCa/yAAAv///6AAAAJ1BbYCJgCKAAAABwBo/vwABv//AH4AAAQLBiECJgBQAAAABgCgWSoAAP//AFP/7AQ0BeACJgBRAAAABwBCAJ4AGv//AFP/7AQ0Bd8CJgBRAAAABwBzAVUAGf//AFP/7AQ0BgUCJgBRAAAABgCaWRcAAP//AFP/7AQ0BiECJgBRAAAABgCgWyoAAP//AFP/7AQ0BcsCJgBRAAAABgBoNRsAAP//AHv/7AQKBcsCJgBXAAAABwBCAJ0ABf//AHv/7AQKBcoCJgBXAAAABwBzAVQABP//AHv/7AQKBfACJgBXAAAABgCaWAIAAP//AHv/7AQKBbYCJgBXAAAABgBoNAYAAP//ABD+SwP8BcoCJgBbAAAABwBzARgABP//ABD+SwP8BbYCJgBbAAAABgBo+QYAAP//ABoAAAUoBvYCJgAjAAAABwBuALIBRv//AF7/7AQBBbQCJgBDAAAABgBuNwQAAP//ABoAAAUoB1wCJgAjAAAABwCcAOoBrP//AF7/7AQBBhoCJgBDAAAABgCcb2oAAAACABr+UgUoBbAAGgAeAAAJASMOARUUFjMyNjcXDgEjIiY1NDY3AyEDIwEDIQMjAxgCEERQUSAnGioWFSFNN151UVlx/c949wIXZQGs1AMFsPpQM1w4ISMNCo4TGWlgRno1AUz+pAWw/G8CawACAF7+UgQBBE4AMwA+AAAhLgEnDgEjIiY1NDY7ATU0JiMiBhUjNDYzMhYVERQWFyMOARUUFjMyNjcXDgEjIiY1NDY3JTI2NzUjIgYVFBYDCwsPBDecYqez9OWxZGBYZPP1ycHnERUiUFEgJxoqFhUhTTdedUVM/uBUhSK1bXVOIkQkRlirmqCsX1ZfT0CIxL23/h9FeDwzXDghIw0KjhMZaWBBcTOvSDa4Z0k/RwAA//8AdP/rBNgHNgImACUAAAAHAHMBvwFw//8AUf/sA/cF3wImAEUAAAAHAHMBKAAZ//8AdP/rBNgHXAImACUAAAAHAJoAwwFu//8AUf/sA/cGBQImAEUAAAAGAJosFwAA//8AdP/rBNgHNgImACUAAAAHAJ0BkAGA//8AUf/sA/cF3wImAEUAAAAHAJ0A+QAp//8AdP/rBNgHYwImACUAAAAHAJsA2gFy//8AUf/sA/cGDAImAEUAAAAGAJtDGwAA//8AnwAABO4HTgImACYAAAAHAJsAjQFd//8AU//sBVcGGAAmAEYAAAAHAZED/QUS//8AnwAABHUG9gImACcAAAAHAG4AegFG//8AWf/sA/gFtQImAEcAAAAGAG45BQAA//8AnwAABHUHXAImACcAAAAHAJwAsgGs//8AWf/sA/gGGwImAEcAAAAGAJxxawAA//8AnwAABHUHIQImACcAAAAHAJ0BTAFr//8AWf/sA/gF4AImAEcAAAAHAJ0BCwAqAAEAn/5SBHUFsAAgAAABIREhFSMOARUUFjMyNjcXDgEjIiY1NDY3JyERIRUhESEED/2DAuNAUFEgJxoqFhUhTTdedURJAf1BA8/9JAJ9Ao/+M8IzXDghIw0KjhMZaWBAcTEDBbDD/mUAAgBZ/mAD+ARPACkAMQAAJQ4BBzMOARUUFjMyNjcXDgEjIiY1NDY3JgA9ATQAFzISHQEhHgEzMjY3ASIGByE1NCYD1R5OMgFQUSAnGioWFSFNN151MDXh/wABC9Dg5P1WCol+ZIlC/qZbdBIBtGdkGiwQM1w4ISMNCo4TGWlgNmEtCAEk6yjxATIB/vvjj4eiLy0CgY11GWmAAAD//wCfAAAEdQdOAiYAJwAAAAcAmwCWAV3//wBZ/+wD+AYNAiYARwAAAAYAm1UcAAD//wB0/+sE4gdcAiYAKQAAAAcAmgC6AW7//wBU/kwECAYFAiYASQAAAAYAmkYXAAD//wB0/+sE4gdxAiYAKQAAAAcAnADtAcH//wBU/kwECAYaAiYASQAAAAYAnHlqAAD//wB0/+sE4gc2AiYAKQAAAAcAnQGHAYD//wBU/kwECAXfAiYASQAAAAcAnQETACn//wB0/eIE4gXFAiYAKQAAAAcBkQG2/qv//wBU/kwECAaKAiYASQAAAAcBpQEtAH7//wCfAAAFEAdHAiYAKgAAAAcAmgDoAVn//wB9AAAEDAdiAiYASgAAAAcAmgAbAXT///+/AAACkAdjAiYAKwAAAAcAoP8/AWz///+iAAACcwYMAiYAigAAAAcAoP8iABX///+/AAAClgb2AiYAKwAAAAcAbv84AUb///+iAAACeQWgAiYAigAAAAcAbv8b//D////lAAACawdcAiYAKwAAAAcAnP9wAaz////IAAACTgYFAiYAigAAAAcAnP9TAFX//wAc/lwBoAWwAiYAKwAAAAYAn/MKAAD////+/lIBgwYYAiYASwAAAAYAn9UAAAD//wCjAAABpgchAiYAKwAAAAcAnQAJAWv//wCt/+sGMwWwACYAKwAAAAcALAJNAAD//wCQ/ksDoQYYACYASwAAAAcATAITAAD//wA6/+sEsgc/AiYALAAAAAcAmgF2AVH///+1/ksCZAXjAiYAmAAAAAcAmv8o//X//wCf/fAFLwWwAiYALQAAAAcBkQGK/rn//wCB/fIENQYYAiYATQAAAAcBkQEv/rv//wCfAAAELwb4AiYALgAAAAcAcwAqATL//wCQAAACZwdfAiYATgAAAAcAcwAbAZn//wCf/fIELwWwAiYALgAAAAcBkQF1/rv//wBY/fIBgwYYAiYATgAAAAcBkQAT/rv//wCfAAAELwWyAiYALgAAAAcBkQIEBKz//wCQAAAC6AYYACYATgAAAAcBkQGOBRL//wCfAAAELwWwAiYALgAAAAcAnQG7/dT//wCQAAAC9wYYACYATgAAAAcAnQFa/a///wCfAAAFEAchAiYAMAAAAAcAcwHoAVv//wB+AAAECwXfAiYAUAAAAAcAcwFTABn//wCf/fIFEAWwAiYAMAAAAAcBkQHg/rv//wB+/fIECwROAiYAUAAAAAcBkQFL/rv//wCfAAAFEAdOAiYAMAAAAAcAmwEDAV3//wB+AAAECwYMAiYAUAAAAAYAm24bAAD////VAAAECwYYAiYAUAAAAAcBkf+QBRL//wB0/+sFGwcLAiYAMQAAAAcAbgDZAVv//wBT/+wENAW0AiYAUQAAAAYAblQEAAD//wB0/+sFGwdxAiYAMQAAAAcAnAERAcH//wBT/+wENAYaAiYAUQAAAAcAnACMAGr//wB0/+sFGwdgAiYAMQAAAAcAoQFDAXL//wBT/+wEWQYJAiYAUQAAAAcAoQC+ABv//wCfAAAE8AchAiYANAAAAAcAcwGDAVv//wCAAAAC+gXfAiYAVAAAAAcAcwCuABn//wCf/fIE8AWwAiYANAAAAAcBkQF7/rv//wBW/fICwwROAiYAVAAAAAcBkQAR/rv//wCfAAAE8AdOAiYANAAAAAcAmwCeAV3//wBDAAAC9wYMAiYAVAAAAAYAm8obAAD//wBT/+sEoAc2AiYANQAAAAcAcwGBAXD//wBR/+wDzwXfAiYAVQAAAAcAcwEiABn//wBT/+sEoAdcAiYANQAAAAcAmgCFAW7//wBR/+wDzwYFAiYAVQAAAAYAmiYXAAD//wBT/jgEoAXFAiYANQAAAAcAdwGW//f//wBR/jgDzwROAiYAVQAAAAcAdwEv//f//wBT/d4EoAXFAiYANQAAAAcBkQGB/qf//wBR/d4DzwROAiYAVQAAAAcBkQEa/qf//wBT/+sEoAdjAiYANQAAAAcAmwCcAXL//wBR/+wDzwYMAiYAVQAAAAYAmz0bAAD//wA1/fIEtQWwAiYANgAAAAcBkQGB/rv//wAZ/egCcAVBAiYAVgAAAAcBkQC5/rH//wA1/ksEtQWwAiYANgAAAAcAdwGWAAr//wAZ/kEClwVBAiYAVgAAAAcAdwDOAAD//wA1AAAEtQdOAiYANgAAAAcAmwCkAV3//wAZ/+wDLwY2ACYAVgAAAAcBkQHVBTD//wCG/+sE8QdjAiYANwAAAAcAoADUAWz//wB7/+wECgYMAiYAVwAAAAYAoFoVAAD//wCG/+sE8Qb2AiYANwAAAAcAbgDNAUb//wB7/+wECgWgAiYAVwAAAAYAblPwAAD//wCG/+sE8QdcAiYANwAAAAcAnAEFAaz//wB7/+wECgYFAiYAVwAAAAcAnACLAFX//wCG/+sE8QePAiYANwAAAAcAngFnAbP//wB7/+wECgY4AiYAVwAAAAcAngDtAFz//wCG/+sE8QdLAiYANwAAAAcAoQE3AV3//wB7/+wEWAX0AiYAVwAAAAcAoQC9AAYAAQCG/nkE8QWwACcAAAERFAYHDgEVFBYzMjY3Fw4BIyImNTQ2NyIGIyIkNREzERQWMzI2NREE8YyBUFEgJxoqFhUhTTdedSMnBA4D//7P86mUma8FsPwwo9o8M1w4ISMNCo4TGWlgLlQoAf/2A9D8MJyXl5wD0AAAAQB7/lIEEAQ6ACcAACEOARUUFjMyNjcXDgEjIiY1NDY3LwEOASMiJjURMxEUFjMyNjcRMxED+1BRICcaKhYVIU03XnVJUA8CNJhnssDyWl9ZdSPzM1w4ISMNCo4TGWlgQnUziwFRVNjvAof9d5FuPjwDDvvGAAD//wBEAAAGuwdHAiYAOQAAAAcAmgGVAVn//wAlAAAF0AXwAiYAWQAAAAcAmgERAAL//wATAAAE7wdHAiYAOwAAAAcAmgCaAVn//wAQ/ksD/AXwAiYAWwAAAAYAmhwCAAD//wATAAAE7wcNAiYAOwAAAAcAaAB2AV3//wBYAAAEcQciAiYAPAAAAAcAcwFvAVz//wBVAAADxAXKAiYAXAAAAAcAcwEeAAT//wBYAAAEcQciAiYAPAAAAAcAnQFAAWz//wBVAAADxAXKAiYAXAAAAAcAnQDvABT//wBYAAAEcQdPAiYAPAAAAAcAmwCKAV7//wBVAAADxAX3AiYAXAAAAAYAmzkGAAD////2AAAHVwchAiYAfwAAAAcAcwK4AVv//wA0/+sGhAXgAiYAhAAAAAcAcwJuABr//wBp/6EFEAdfAiYAgQAAAAcAcwHSAZn//wBT/3YENAXcAiYAhwAAAAcAcwEuABb////qAAAEQgSNAiYBqQAAAAcB0/9T/3f////qAAAEQgSNAiYBqQAAAAcB0/9T/3f//wA8AAAD6QSNAiYBuAAAAAYB0y3eAAD//wAcAAAErAXfAiYBpgAAAAcAQgC6ABn//wAcAAAErAXeAiYBpgAAAAcAcwFxABj//wAcAAAErAYEAiYBpgAAAAYAmnUWAAD//wAcAAAErAYgAiYBpgAAAAYAoHcpAAD//wAcAAAErAXKAiYBpgAAAAYAaFEaAAD//wAcAAAErAZMAiYBpgAAAAcAngEKAHD//wAcAAAErAZ7AiYBpgAAAAcB1AEQ/+b//wBo/j4EMgSdAiYBqAAAAAcAdwFi//3//wCOAAADzgXfAiYBqgAAAAYAQnsZAAD//wCOAAADzgXeAiYBqgAAAAcAcwEyABj//wCOAAADzgYEAiYBqgAAAAYAmjYWAAD//wCOAAADzgXKAiYBqgAAAAYAaBIaAAD///+sAAABgAXfAiYBrgAAAAcAQv9iABn//wCOAAACZAXeAiYBrgAAAAYAcxgYAAD///+4AAACWQYEAiYBrgAAAAcAmv8dABb///+dAAACcgXKAiYBrgAAAAcAaP75ABr//wCOAAAEhQYgAiYBswAAAAcAoACQACn//wBm/+4EZAXwAiYBtAAAAAcAQgCxACr//wBm/+4EZAXvAiYBtAAAAAcAcwFoACn//wBm/+4EZAYVAiYBtAAAAAYAmmwnAAD//wBm/+4EZAYxAiYBtAAAAAYAoG46AAD//wBm/+4EZAXbAiYBtAAAAAYAaEgrAAD//wB+/+4EewXhAiYBuQAAAAcAQgDKABv//wB+/+4EewXgAiYBuQAAAAcAcwGBABr//wB+/+4EewYGAiYBuQAAAAcAmgCFABj//wB+/+4EewXMAiYBuQAAAAYAaGEcAAD//wATAAAEPAXeAiYBvQAAAAcAcwE4ABj//wAcAAAErAWzAiYBpgAAAAYAbnADAAD//wAcAAAErAYZAiYBpgAAAAcAnACoAGkAAgAc/lIErASNABoAHQAAATMBIw4BFRQWMzI2NxcOASMiJjU0NjcnIQcjASEDAej4AcxQUFEgJxoqFhUhTTdedVNbUP4ZVv4BnAFXrASN+3MzXDghIw0KjhMZaWBHezXX6QGrAc0AAP//AGj/7wQyBe4CJgGoAAAABwBzAVoAKP//AGj/7wQyBhQCJgGoAAAABgCaXiYAAP//AGj/7wQyBe4CJgGoAAAABwCdASsAOP//AGj/7wQyBhsCJgGoAAAABgCbdSoAAP//AI4AAARCBgsCJgGpAAAABgCbJRoAAP//AI4AAAPOBbMCJgGqAAAABgBuMQMAAP//AI4AAAPOBhkCJgGqAAAABgCcaWkAAP//AI4AAAPOBd4CJgGqAAAABwCdAQMAKAABAI7+UgPOBI0AIAAAASERIRUjDgEVFBYzMjY3Fw4BIyImNTQ2NychESEVIREhA3j+CAJOQ1BRICcaKhYVIU03XnVESQH92gNA/bIB+AH8/sTAM1w4ISMNCo4TGWlgQHExAwSNwf7y//8AjgAAA84GCwImAaoAAAAGAJtNGgAA//8AaP/vBF8GFAImAawAAAAGAJpuJgAA//8AaP/vBF8GKQImAawAAAAHAJwAoQB5//8AaP/vBF8F7gImAawAAAAHAJ0BOwA4//8AaP3kBF8EnQImAawAAAAHAZEBaf6t//8AjgAABHoGBAImAa0AAAAHAJoAggAW////nwAAAnAGIAImAa4AAAAHAKD/HwAp////nwAAAnYFswImAa4AAAAHAG7/GAAD////xQAAAksGGQImAa4AAAAHAJz/UABp////+f5SAYAEjQImAa4AAAAGAJ/QAAAA//8AhAAAAYcF3gImAa4AAAAGAJ3qKAAA//8ALv/uBF4GAAImAa8AAAAHAJoBIgAS//8Ajv3uBF0EjQImAbAAAAAHAZEBG/63//8AjgAAA3kFywImAbEAAAAGAHMXBQAA//8Ajv3wA3kEjQImAbEAAAAHAZEA7f65//8AjgAAA3kEjwImAbEAAAAHAZEBkAOJ//8AjgAAA3kEjQImAbEAAAAHAJ0BSv0y//8AjgAABIUF3gImAbMAAAAHAHMBigAY//8Ajv3wBIUEjQImAbMAAAAHAZEBgv65//8AjgAABIUGCwImAbMAAAAHAJsApQAa//8AZv/uBGQFxAImAbQAAAAGAG5nFAAA//8AZv/uBGQGKgImAbQAAAAHAJwAnwB6//8AZv/uBGwGGQImAbQAAAAHAKEA0QAr//8AjgAABEkF3gImAbYAAAAHAHMBIQAY//8Ajv3wBEkEjQImAbYAAAAHAZEBGf65//8AjgAABEkGCwImAbYAAAAGAJs8GgAA//8AT//uBBkF8AImAbcAAAAHAHMBPQAq//8AT//uBBkGFgImAbcAAAAGAJpBKAAA//8AT/47BBkEnQImAbcAAAAHAHcBSv/6//8AT//uBBkGHQImAbcAAAAGAJtYLAAA//8APP3wA+kEjQImAbgAAAAHAZEBFv65//8APAAAA+kGCwImAbgAAAAGAJs5GgAA//8Afv/uBHsGIgImAbkAAAAHAKAAhwAr//8Afv/uBHsFtQImAbkAAAAHAG4AgAAF//8Afv/uBHsGGwImAbkAAAAHAJwAuABr//8Afv/uBHsGTgImAbkAAAAHAJ4BGgBy//8Afv/uBIUGCgImAbkAAAAHAKEA6gAcAAEAfv58BHsEjQAmAAABERQGBzMOARUUFjMyNjcXDgEjIiY1NDY3IyIkNREzERQWMzI2NREEe3NsAVBRICcaKhYVIU03XnUjJgbp/uryjn9/jQSN/QqBtjYzXDghIw0KjhMZaWAuVCfdzAL2/Qpyd3dyAvb//wA0AAAF1wYEAiYBuwAAAAcAmgEWABb//wATAAAEPAYEAiYBvQAAAAYAmjwWAAD//wATAAAEPAXKAiYBvQAAAAYAaBgaAAD//wBKAAAD6wXfAiYBvgAAAAcAcwEoABn//wBKAAAD6wXfAiYBvgAAAAcAnQD5ACn//wBKAAAD6wYMAiYBvgAAAAYAm0MbAAD//wBP/+4IiQSdACYBtwAAAAcBtwRwAAD//wAaAAAFKAZwAiYAIwAAAAYAqeUAAAD///+vAAAE2QZyACYAJ2QAAAcAqf7YAAL////cAAAFdAZwACYAKmQAAAcAqf8FAAD////jAAACBAZyACYAK2QAAAcAqf8MAAL//wAq/+sFLwZwACYAMRQAAAcAqf9TAAD///9nAAAFUwZwACYAO2QAAAcAqf6QAAD//wATAAAE7gZwACYAtRQAAAcAqf88AAD///+w/+sCoQZfAiYAvgAAAAcAqv8T/7v//wAaAAAFKAWwAgYAIwAA//8AnwAABLwFsAIGACQAAP//AJ8AAAR1BbACBgAnAAD//wBYAAAEcQWwAgYAPAAA//8AnwAABRAFsAIGACoAAP//AK0AAAGgBbACBgArAAD//wCfAAAFLwWwAgYALQAA//8AnwAABmIFsAIGAC8AAP//AJ8AAAUQBbACBgAwAAD//wB0/+sFGwXFAgYAMQAA//8AnwAABNoFsAIGADIAAP//ADUAAAS1BbACBgA2AAD//wATAAAE7wWwAgYAOwAA//8ALwAABOoFsAIGADoAAP///70AAAKSBw0CJgArAAAABwBo/xkBXf//ABMAAATvBw0CJgA7AAAABwBoAHYBXf//AFb/6wR5BlwCJgC2AAAABwCpAUT/7P//AGD/7AQMBlsCJgC6AAAABwCpAQ3/6///AH7+YQQGBlwCJgC8AAAABwCpARf/7P//AKn/6wJ+BkYCJgC+AAAABgCpA9YAAP//AID/6wQIBmACJgDGAAAABgCqGLwAAP//AI4AAARrBDoCBgCLAAD//wBT/+wENAROAgYAUQAA//8Akv5gBB8EOgIGAHQAAP//ACAAAAP1BDoCBgBYAAD//wAhAAAD7QQ6AgYAWgAA////xP/rApkFtQImAL4AAAAHAGj/IAAF//8AgP/rBAgFtgImAMYAAAAGAGglBgAA//8AU//sBDQGXAImAFEAAAAHAKkBGf/s//8AgP/rBAgGRwImAMYAAAAHAKkBCf/X//8AZv/rBi0GRQImAMkAAAAHAKkCIf/V//8AnwAABHUHDQImACcAAAAHAGgAWwFd//8AnwAABDcHIQImAKwAAAAHAHMBfQFbAAEAU//rBKAFxQAlAAABNCYnJiQ1NCQzMgAVIzQmIyIGFRQWFx4BFRQEIyIkNTMUFjMyNgOtg676/v4BH+r0ASLzlo+HjZe47+/+4fHp/qzztJaJlAF2XHMuQs6us+H/AL1yiXNdVWsyQdiwudTu24eBawD//wCtAAABoAWwAgYAKwAA////vQAAApIHDQImACsAAAAHAGj/GQFd//8AOv/rA+YFsAIGACwAAP//AJ8AAAUvBbACBgAtAAD//wCfAAAFLwbJAiYALQAAAAcAcwFzAQP//wA//+sE2QdcAiYA2QAAAAcAnADPAaz//wAaAAAFKAWwAgYAIwAA//8AnwAABLwFsAIGACQAAP//AJ8AAAQ3BbACBgCsAAD//wCfAAAEdQWwAgYAJwAA//8AmgAABQsHXAImANcAAAAHAJwBHQGs//8AnwAABmIFsAIGAC8AAP//AJ8AAAUQBbACBgAqAAD//wB0/+sFGwXFAgYAMQAA//8AnwAABREFsAIGALEAAP//AJ8AAATaBbACBgAyAAD//wB0/+sE2AXFAgYAJQAA//8ANQAABLUFsAIGADYAAP//AC8AAATqBbACBgA6AAD//wBe/+wEAQROAgYAQwAA//8AWf/sA/gETwIGAEcAAP//AIYAAAQSBgUCJgDrAAAABwCcAJUAVf//AFP/7AQ0BE4CBgBRAAD//wCA/mAENAROAgYAUgAAAAEAUf/sA/cETgAbAAAlMjY1MxQEIyICPQE0EjMyFhUjNCYjIgYdARQWAjtbfOX+/7j0+fnzx/PldWKLbGquZ1Gg2gEu8SPwATDht1t6w5ojncAA//8AEP5LA/wEOgIGAFsAAP//ACEAAAPtBDoCBgBaAAD//wBZ/+wD+AXMAiYARwAAAAYAaBocAAD//wCFAAADTQXKAiYA5wAAAAcAcwC+AAT//wBR/+wDzwROAgYAVQAA//8AkAAAAYMGGAIGAEsAAP///6AAAAJ1BbYCJgCKAAAABwBo/vwABv///7D+SwGOBhgCBgBMAAD//wCPAAAEZQXJAiYA7AAAAAcAcwE8AAP//wAQ/ksD/AYFAiYAWwAAAAYAnE9VAAD//wBEAAAGuwciAiYAOQAAAAcAQgHaAVz//wAlAAAF0AXLAiYAWQAAAAcAQgFWAAX//wBEAAAGuwchAiYAOQAAAAcAcwKRAVv//wAlAAAF0AXKAiYAWQAAAAcAcwINAAT//wBEAAAGuwcNAiYAOQAAAAcAaAFxAV3//wAlAAAF0AW2AiYAWQAAAAcAaADtAAb//wATAAAE7wciAiYAOwAAAAcAQgDfAVz//wAQ/ksD/AXLAiYAWwAAAAYAQmEFAAD//wBSBAQBCwYYAgYACQAA//8AUgP8Aj8GGAIGAAQAAP//AJoAAAOyBbAAJgQbAAAABwQbAiUAAP//ADEAAARSBi0AJgBIAAAABwBOAs8AAP///7X+SwJsBeoCJgCYAAAABwCb/z//+f//ADMD1gFpBhgCBgFmAAD//wCfAAAGYgchAiYALwAAAAcAcwKSAVv//wCAAAAGdQXfAiYATwAAAAcAcwKhABn//wAa/n4FKAWwAiYAIwAAAAcAogFIAAD//wBe/oUEAQROAiYAQwAAAAcAogCQAAf///89/+sFGwasAiYAMQAAAAcB1f7RANX//wAxAAAG5gYtACYASAAAAAcBkgLPAAD//wAxAAAHIQYtACYASAAAACcASALPAAAABwBOBZ4AAP//AJ8AAAR1ByICJgAnAAAABwBCAMQBXP//AJoAAAULByICJgDXAAAABwBCAS8BXP//AFn/7AP4BeECJgBHAAAABwBCAIMAG///AIYAAAQSBcsCJgDrAAAABwBCAKcABf//AEgAAAVRBbACBgC0AAD//wBP/iIFfgQ6AgYAyAAA//8AEQAABO8HRAImARQAAAAHAKcEOwFW////4wAABBgGMgImARUAAAAHAKcD1wBE//8AU/5LCIQETgAmAFEAAAAHAFsEiAAA//8AdP5LCYsFxQAmADEAAAAHAFsFjwAA//8ASv46BHsFxQImANYAAAAHAZwBkv+g//8ATf47A8QETQImAOoAAAAHAZwBOf+h//8AdP4+BNgFxQImACUAAAAHAZwB0/+k//8AUf4+A/cETgImAEUAAAAHAZwBS/+k//8AEwAABO8FsAIGADsAAP//ACD+XwP1BDoCBgC4AAD//wCtAAABoAWwAgYAKwAA//8AGAAAB4kHXAImANUAAAAHAJwCHAGs//8AFwAABl8GBQImAOkAAAAHAJwBpQBV//8ArQAAAaAFsAIGACsAAP//ABoAAAUoB1wCJgAjAAAABwCcAOoBrP//AF7/7AQBBhoCJgBDAAAABgCcb2oAAP//ABoAAAUoBw0CJgAjAAAABwBoAJMBXf//AF7/7AQBBcsCJgBDAAAABgBoGBsAAP////YAAAdXBbACBgB/AAD//wA0/+sGhAROAgYAhAAA//8AnwAABHUHXAImACcAAAAHAJwAsgGs//8AWf/sA/gGGwImAEcAAAAGAJxxawAA//8AU//qBRsG2gImAUEAAAAHAGgAcwEq//8AWf/sA/gEUAIGAJkAAP//AFn/7AP4BcwCJgCZAAAABgBoGhwAAP//ABgAAAeJBw0CJgDVAAAABwBoAcUBXf//ABcAAAZfBbYCJgDpAAAABwBoAU4ABv//AEr/6wR7ByICJgDWAAAABwBoAFgBcv//AE3/7APEBcoCJgDqAAAABgBoABoAAP//AJoAAAULBvYCJgDXAAAABwBuAOUBRv//AIYAAAQSBaACJgDrAAAABgBuXfAAAP//AJoAAAULBw0CJgDXAAAABwBoAMYBXf//AIYAAAQSBbYCJgDrAAAABgBoPgYAAP//AHT/6wUbByICJgAxAAAABwBoALoBcv//AFP/7AQ0BcsCJgBRAAAABgBoNRsAAP//AGr/6wURBcUCBgESAAD//wBS/+wEMwROAgYBEwAA//8Aav/rBREHCAImARIAAAAHAGgAxgFY//8AUv/sBDMF5wImARMAAAAGAGghNwAA//8AiP/sBNcHIwImAOIAAAAHAGgAjwFz//8AUf/rA+gFywImAPoAAAAGAGgPGwAA//8AP//rBNkG9gImANkAAAAHAG4AlwFG//8AEP5LA/wFoAImAFsAAAAGAG4X8AAA//8AP//rBNkHDQImANkAAAAHAGgAeAFd//8AEP5LA/wFtgImAFsAAAAGAGj5BgAA//8AP//rBNkHSwImANkAAAAHAKEBAQFd//8AEP5LBBwF9AImAFsAAAAHAKEAgQAG//8AjwAABOkHDQImANwAAAAHAGgAwgFd//8AXwAAA+AFtgImAPQAAAAGAGgNBgAA//8AnwAABlkHDQAmAOELAAAnACsEuQAAAAcAaAFuAV3//wCPAAAFyQW2ACYA+QAAACcAigRHAAAABwBoAR8ABv//AC/+SwVUBbACJgA6AAAABwGaA8YAAP//ACH+SwRYBDoCJgBaAAAABwGaAsoAAP//AFP/7AQDBhgCBgBGAAD//wAu/ksF/QWwAiYA2AAAAAcBmgRvAAD//wAf/ksFBwQ6AiYA7QAAAAcBmgN5AAD//wAa/qUFKAWwAiYAIwAAAAcAqAT8AAD//wBe/qwEAQROAiYAQwAAAAcAqAREAAf//wAaAAAFKAfHAiYAIwAAAAcApgT5AUj//wBe/+wEAQaFAiYAQwAAAAcApgR+AAb//wAaAAAFPgejAiYAIwAAAAcBowCzARP//wBe/+wEwwZiAiYAQwAAAAYBozjSAAD//wAEAAAFKAegAiYAIwAAAAcBogC4AR3///+J/+wEAQZfAiYAQwAAAAYBoj3cAAD//wAaAAAFKAfWAiYAIwAAAAcBoQC3AQv//wBe/+wERgaVAiYAQwAAAAYBoTzKAAD//wAaAAAFKAfiAiYAIwAAAAcBoAC4ARH//wBe/+wEAQahAiYAQwAAAAYBoD3QAAD//wAa/qUFKAdHAiYAIwAAACcAmgC3AVkABwCoBPwAAP//AF7+rAQBBgUCJgBDAAAAJgCaPBcABwCoBEQABwAA//8AGgAABSgHzgImACMAAAAHAZ8A4wFQ//8AXv/sBAEGjAImAEMAAAAGAZ9oDgAA//8AGgAABSgIFwImACMAAAAHAaQA6AF///8AXv/sBAEG1QImAEMAAAAGAaRtPQAA//8AGgAABSgISgImACMAAAAHAZ4A4gFC//8AXv/sBAEHCAImAEMAAAAGAZ5nAAAA//8AGgAABSgIJAImACMAAAAHAZ0A5QFI//8AXv/sBAEG4gImAEMAAAAGAZ1qBgAA//8AGv6lBSgHXAImACMAAAAnAJwA6gGsAAcAqAT8AAD//wBe/qwEAQYaAiYAQwAAACYAnG9qAAcAqAREAAcAAP//AJ/+rwR1BbACJgAnAAAABwCoBMAACv//AFn+pQP4BE8CJgBHAAAABwCoBJUAAP//AJ8AAAR1B8cCJgAnAAAABwCmBMEBSP//AFn/7AP4BoYCJgBHAAAABwCmBIAAB///AJ8AAAR1B2MCJgAnAAAABwCgAIEBbP//AFn/7AP4BiICJgBHAAAABgCgQCsAAP//AJ8AAAUGB6MCJgAnAAAABwGjAHsBE///AFn/7ATFBmMCJgBHAAAABgGjOtMAAP///8wAAAR1B6ACJgAnAAAABwGiAIABHf///4v/7AP4BmACJgBHAAAABgGiP90AAP//AJ8AAASJB9YCJgAnAAAABwGhAH8BC///AFn/7ARIBpYCJgBHAAAABgGhPssAAP//AJ8AAAR1B+ICJgAnAAAABwGgAIABEf//AFn/7AP4BqICJgBHAAAABgGgP9EAAP//AJ/+rwR1B0cCJgAnAAAAJwCaAH8BWQAHAKgEwAAK//8AWf6lA/gGBgImAEcAAAAmAJo+GAAHAKgElQAAAAD//wCtAAACFwfHAiYAKwAAAAcApgN+AUj//wCPAAAB+gZxAiYAigAAAAcApgNh//L//wCf/q8BrQWwAiYAKwAAAAcAqAN9AAr//wCC/q8BkAYYAiYASwAAAAcAqANgAAr//wB0/pwFGwXFAiYAMQAAAAcAqAUf//f//wBT/pwENAROAiYAUQAAAAcAqASb//f//wB0/+sFGwfcAiYAMQAAAAcApgUgAV3//wBT/+wENAaFAiYAUQAAAAcApgSbAAb//wB0/+sFZQe4AiYAMQAAAAcBowDaASj//wBT/+wE4AZiAiYAUQAAAAYBo1XSAAD//wAr/+sFGwe1AiYAMQAAAAcBogDfATL///+m/+wENAZfAiYAUQAAAAYBolrcAAD//wB0/+sFGwfrAiYAMQAAAAcBoQDeASD//wBT/+wEYwaVAiYAUQAAAAYBoVnKAAD//wB0/+sFGwf3AiYAMQAAAAcBoADfASb//wBT/+wENAahAiYAUQAAAAYBoFrQAAD//wB0/pwFGwdcAiYAMQAAACcAmgDeAW4ABwCoBR//9///AFP+nAQ0BgUCJgBRAAAAJgCaWRcABwCoBJv/9wAA//8AZv/rBa8HEwImAJQAAAAHAHMB1QFN//8AUv/sBLwF3wImAJUAAAAHAHMBVgAZ//8AZv/rBa8HFAImAJQAAAAHAEIBHgFO//8AUv/sBLwF4AImAJUAAAAHAEIAnwAa//8AZv/rBa8HuQImAJQAAAAHAKYFGwE6//8AUv/sBLwGhQImAJUAAAAHAKYEnAAG//8AZv/rBa8HVQImAJQAAAAHAKAA2wFe//8AUv/sBLwGIQImAJUAAAAGAKBcKgAA//8AZv6lBa8GLgImAJQAAAAHAKgFCwAA//8AUv6cBLwEqQImAJUAAAAHAKgEm//3//8Ahv6cBPEFsAImADcAAAAHAKgFE//3//8Ae/6lBAoEOgImAFcAAAAHAKgERQAA//8Ahv/rBPEHxwImADcAAAAHAKYFFAFI//8Ae//sBAoGcQImAFcAAAAHAKYEmv/y//8Ahv/rBksHIQImAJYAAAAHAHMB1AFb//8Ae//sBSkFygImAJcAAAAHAHMBVAAE//8Ahv/rBksHIgImAJYAAAAHAEIBHQFc//8Ae//sBSkFywImAJcAAAAHAEIAnQAF//8Ahv/rBksHxwImAJYAAAAHAKYFGgFI//8Ae//sBSkGcQImAJcAAAAHAKYEmv/y//8Ahv/rBksHYwImAJYAAAAHAKAA2gFs//8Ae//sBSkGDAImAJcAAAAGAKBaFQAA//8Ahv6cBksGEAImAJYAAAAHAKgFGf/3//8Ae/6lBSkElAImAJcAAAAHAKgERQAA//8AE/6vBO8FsAImADsAAAAHAKgE2wAK//8AEP3/A/wEOgImAFsAAAAHAKgFOv9a//8AEwAABO8HxwImADsAAAAHAKYE3AFI//8AEP5LA/wGcQImAFsAAAAHAKYEXv/y//8AEwAABO8HYwImADsAAAAHAKAAnAFs//8AEP5LA/wGDAImAFsAAAAGAKAeFQAAAAIAU//sBK8GGAAaACgAAAEjESMnDgEjIgI9ARASMzIWFzc1IzUzNTMVMwEUFjMyNjcRLgEjIgYVBK+s0hQ1j2HL2trNWocyA/Dw86z8l3F/TmkjI2lMf3MEyfs3hExMARzxFQEIAThEQQH/qqWl/IaZrkA+Adg9Qs6rAP//AFP+xASvBhgAJgBGAAAAJwHTAYkCQgAHAEEAm/+D//8An/6aBWcFsAImAC0AAAAHAZwEGAAA//8Aj/6aBKEEOgImAOwAAAAHAZwDUgAA//8An/6aBbMFsAImACoAAAAHAZwEZAAA//8Ahv6aBLQEOgImAO8AAAAHAZwDZQAA//8ANf6aBLUFsAImADYAAAAHAZwCQgAA//8AI/6aA9AEOgImAPEAAAAHAZwBxQAA//8AL/6aBQQFsAImADoAAAAHAZwDtQAA//8AIf6aBAgEOgImAFoAAAAHAZwCuQAA//8Aj/6aBYwFsAImANwAAAAHAZwEPQAA//8AX/6aBIMEOwImAPQAAAAHAZwDNAAA//8Aj/6aBOkFsAImANwAAAAHAZwC8QAA//8AX/6aA+AEOwImAPQAAAAHAZwB6AAA//8An/6aBDcFsAImAKwAAAAHAZwA5gAA//8Ahf6aA00EOgImAOcAAAAHAZwApQAA//8AGP6aB+QFsAImANUAAAAHAZwGlQAA//8AF/6aBpMEOgImAOkAAAAHAZwFRAAA//8AIP5DBcAFxAImATsAAAAHAZwC7f+p////zv5HBHYETwImATwAAAAHAZwB9f+t//8AfQAABAwGGAIGAEoAAAAC/9cAAATBBbAAEgAbAAABIxUhMgQVFAQjIREjNTM1MxUzAxEhMjY1NCYjAmbfATT4AQ7+8ff92b2989/fATSKiYiLBEfK7M7Q8wRHqr+//cn+CJFybocAAv/XAAAEwQWwABIAGwAAASMVITIEFRQEIyERIzUzNTMVMwMRITI2NTQmIwJm3wE0+AEO/vH3/dm9vfPf3wE0iomIiwRHyuzO0PMER6q/v/3J/giRcm6HAAH/9wAABDcFsAANAAABIxEjESM1MxEhFSERMwKG9POoqAOY/Vv0Ap/9YQKfqgJnw/5cAAAB/+kAAANNBDoADQAAASERIxEjNTMRIRUhFSECeP7/8pycAsj+KgEBAdH+LwHRqgG/xPsAAf/dAAAFQwWwABQAAAEjESMRIzUzNTMVMxUjETMBIQkBIQJOqPPW1vPGxosByQEg/fQCNf7XAnb9igR6qoyMqv7NAmn9Sf0HAAAAAAH/zAAABEkGGAAUAAABIxEjESM1MzUzFTMVIxEzASEJASEB9m/yycny1NRpAQ8BHP6fAY/+5gHZ/icEu6qzs6r94QGe/hH9tQAAAP//AJr+bwX3B1wCJgDXAAAAJwCcAR0BrAAHAA4Ek//E//8Ahv5vBP4GBQImAOsAAAAnAJwAlQBVAAcADgOa/8T//wCf/m8F/AWwAiYAKgAAAAcADgSY/8T//wCG/m8E/QQ6AiYA7wAAAAcADgOZ/8T//wCf/m8HTgWwAiYALwAAAAcADgXq/8T//wCP/m8GWwQ6AiYA7gAAAAcADgT3/8T//wAu/m8F9gWwAiYA2AAAAAcADgSS/8T//wAf/m8FAAQ6AiYA7QAAAAcADgOc/8QAAQATAAAE7wWwAA8AAAkBIQEzFSMHESMRIzUzASECgAFgAQ/+aWzHB/LPdf5pAQ8C7ALE/QWqDv4DAguqAvsAAAEAIP5fA/UEOgARAAAFIxEjESM1MwEzExczNxMzATMDWdXzx5v+u/vdFAMU1/v+vKgB/mABoKoDkf00X18CzPxvAAAAAQAvAAAE6gWwABEAAAEjASEJASEBIzUzASEJASEBMwPXjwGi/t3+w/7E/uEBm4J0/n0BHQEwATQBH/59gQKV/WsCI/3dApWqAnH95gIa/Y8AAAAAAQAhAAAD7QQ6ABEAAAEjASELASEBIzUzASEbASEBMwNRkgEu/uzR0f7qAS2Mgf7oARTFyAEX/ueHAdf+KQF8/oQB16oBuf6NAXP+RwAAAP//AGD/7AQMBE0CBgC6AAD//wAWAAAEcgWwAiYAKAAAAAcB0/9//m7//wCyAm0F6gMxAEYBhrYAZmZAAAACAJoAAAGNBbAAAwAHAAABIxEzESM1MwGN8/Pz8wHrA8X6UOoAAAAAAAAAAAAAAAAAABgATgCOAOQBPAFMAW4BkgG2Ac4B5AHyAf4CDAI8AkwCdgKwAtIDBANEA2IDqgPsA/gEBAQcBDAESAR4BOwFCgVABXIFmAWyBcgF/gYWBiIGPgZcBmwGkAaqBt4HAgc+B3YHsAfEB+QH/ggmCEgIYAh2CIoImAiqCMII0AjgCR4JVAl+CbIJ5goKCk4KcgqECqgKxgrSCwwLMAteC5QLyAvoDCAMRgxqDIIMrAzMDPYNDA08DUoNeA2iDbYN6A4cDmYOkA6kDwgPHA9yD7IPvg/OEDIQQBBmEIYQsBDqEPoRIBE2EUQRYhFyEZwRqBG6EcwR3hIOEjgSWhKqEtATChNoE7gT0hQeFFQUfhSKFKgUxBTcFQgVPBV8FdAV7BYiFmIWnBbGFvQXEhdGF1oXbheIF5YXvBfeF/4YFBg6GEgYVhhgGH4YlBiiGLAYyhjSGOQY+hk0GUoZZhl4GZYZ0Bn8GjgafBq8GtgbIBtaG5IbthvuHAwcRByOHLYc6B0eHVIddh2cHdoeDB5MHogexB8KHzgfcB+mH9YgACAYIEAgbCCaINYg7iEOITgheiGSIbYh0CHwIhgiRCJoIpwi2CMAI0IjeCOKI7Qj4CQaJDQkUiRyJJIkqiS8JNAlKiVCJWQlfiWeJcQl7iYQJj4mdCacJtgnBic6J2gnliewJ+IoFChCKIIouCjaKP4pLClcKZIpxCoGKkIqkirgKxorTityK5or3CwYLHos2C0WLVQtgC2oLdQt6C4GLhYuJi7ALxgvRC9yL7AvxC/YMAAwJjBMMHAwkDCwMMww6DESMTwxkjHkMgIyIDJKMnIylDLUMxAzPDNmM44ztjPuNBo0RjRWNGY0jDTENRY1XDWiNeQ2JjZgNpo2zjcCNzw3cjegN844DDgMOAw4DDgMOAw4DDgMOAw4DDgMOAw4DDgWOCA4LDhCOFg4bjh6OIY4kji2ONA49DkMORg5KDmkObg5zDnaOfg6GjpWOpg62DsuO2g7rjvYPA48IDwyPEQ8VjySPKY8xDzSPOw9Pj1sPcQ96D34Pgg+LD46Pk4+ZD6OPo4/aD+uP+BAAEAwQFBAbkCQQJ5A0EEAQSBBTkF2QZBBqkHKQdpB9kIsQlpCfkKYQq5C4EL4QwRDIEM+Q05DbkOIQ7ZD7EQkRFxEcESQRKpEzETsRQRFGkVGRVZFfkW4RdhGAkY+RlpGokbeRu5HFkdQR2BHkEfMR+ZILkhqSJRIokjQSPBJKklMSX5JvkosSkpKiErQSwpLTkt0S7JL4Ev+TB5MOkxYTJpMvEzETMxM1E0ETTRNYE18TapNtk3CTc5N2k3mTfJN/k4KThZOIk4uTjpORk5STl5Oak52ToJOjk6aTqZOsk6+TspO1k7iTu5O+k8GTxJPHk8qTzZPQk9OT1pPZk9yT35Pik+WT6JPrk+6T8ZP0k/eT+pP9lACUA5QGlAmUDJQPlBKUFZQYlBuUKRQ/FEIURRRIFEsUThRRFFQUVxRaFF0UYBRjFGYUaRRsFG8UfBSPlJKUlZSYlJuUnpShlKSUp5SqlK2UsJSzlLaUuZS8lL+UwpTFlMiUy5TOlNGU1JTXlNqU3ZTglOOU5pTplOyU75TylPWU+JT7lP6VAZUElQeVCpUNlRCVE5UWlRmVHJUflSKVJZUolSuVLpUxlTSVN5U6lT2VQJVDlUaVSZVMlU+VUpVVlViVW5VelWGVZJVnlWqVbZVwlXOVdpV5lXyVf5WOlZ2VoJWjlaaVqZWsla+VspW1lbiVu5W+lcGVxJXHlcqVzZXQldOV1pXZldyV35XileWV6JXrle6V8ZX0lfeV+pX9lgCWA5YGlgmWDJYPlhKWFZYYlhuWHpYhliSWJ5YqljeWOpY9lkCWQ5ZGlkmWTJZPllyWX5ZilmWWaJZrlm6WcZZ0lneWepZ9loCWg5aGlomWjJaPlpKWlZaYlpuWnpahlqSWp5aqlq2WsJazlraWuZa8lr+WwpbFlsiWy5baFt0W4BbjFuYW6RbsFu8W8hb1FvgW+xb+FwEXBBcHFwkXCxcNFw8XERcTFxUXFxcZFxsXHRcfFyEXIxcmFykXLBcvFzIXNRc4FzoXPBc+F0AXQhdFF0gXSxdOF1EXVBdXF2WXZ5dql2yXbpdxl3SXdpd4l3qXfJd/l4GXg5eFl4eXiZeLl42Xj5eRl5OXlpeYl5qXpRenF6kXrBevF7EXsxe2F7gXuxe+F8EXxBfHF8oXzRfQF9MX1hfYF9oX3RfgF+MX5RfoF+sX7hfxF/QX9xf7F/4YARgEGAcYCRgLGA4YERgUGBcYGhgdGCAYIxglGCcYKRgsGC8YMRg0GDcYOhg9GD8YQRhEGEcYShhMGE8YUhhVGFgYWxheGGEYZBhnGGoYbRhvGHEYdBh3GHoYfRiAGIMYhhiJGIwYjxiSGJUYmRidGKAYoxilGKgYqxiuGLEYtBi3GLoYvRjAGMMYxhjJGMwYzxjTGNcY2hjdGOAY4xjmGOkY7BjvGPMY9xj6GP0ZABkDGQYZCRkMGQ8ZEhkVGRgZGxkeGSEZJRkpGSwZLxkyGTUZOBk7GT4ZQRlEGUcZShlNGVAZUxlWGVkZXRlhGWQZZxlqGW0ZcBlzGXYZeRl8GX8ZghmFGYgZixmOGZEZlBmXGZoZnRmgGaMZphmpGawZrxmyGbUZuBm7GcqZzpnRmdSZ15namd2Z4JnjmeaZ6Znsme+Z8pn1mfiZ+5n+mgGaBJoGmhGaHJojGimaMxo8mkCaRJpHmkqaTZpQmlOaVppemmcacZp7mn2agJqDGoMaiAAAAAAAB0BYgABAAAAAAAAAB8AAAABAAAAAAABAAYAHwABAAAAAAACAAYAJQABAAAAAAADABIAKwABAAAAAAAEAA0APQABAAAAAAAFABYASgABAAAAAAAGAA0AYAABAAAAAAAHACAAbQABAAAAAAAJAAYAjQABAAAAAAALAAoAkwABAAAAAAAMABMAnQABAAAAAAANAC4AsAABAAAAAAAOACoA3gABAAAAAAASAA0BCAADAAEECQAAAD4BFQADAAEECQABAAwBUwADAAEECQACAAwBXwADAAEECQADACQBawADAAEECQAEABoBjwADAAEECQAFACwBqQADAAEECQAGABoB1QADAAEECQAHAEAB7wADAAEECQAJAAwCLwADAAEECQALABQCOwADAAEECQAMACYCTwADAAEECQANAFwCdQADAAEECQAOAFQC0QADAAEECQAQAAwDJQADAAEECQARAAwDMUZvbnQgZGF0YSBjb3B5cmlnaHQgR29vZ2xlIDIwMTNSb2JvdG9NZWRpdW1Hb29nbGU6Um9ib3RvOjIwMTNSb2JvdG8gTWVkaXVtVmVyc2lvbiAxLjIwMDMxMDsgMjAxM1JvYm90by1NZWRpdW1Sb2JvdG8gaXMgYSB0cmFkZW1hcmsgb2YgR29vZ2xlLkdvb2dsZUdvb2dsZS5jb21DaHJpc3RpYW4gUm9iZXJ0c29uTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFJvYm90byBNZWRpdW0ARgBvAG4AdAAgAGQAYQB0AGEAIABjAG8AcAB5AHIAaQBnAGgAdAAgAEcAbwBvAGcAbABlACAAMgAwADEAMwBSAG8AYgBvAHQAbwBNAGUAZABpAHUAbQBHAG8AbwBnAGwAZQA6AFIAbwBiAG8AdABvADoAMgAwADEAMwBSAG8AYgBvAHQAbwAgAE0AZQBkAGkAdQBtAFYAZQByAHMAaQBvAG4AIAAxAC4AMgAwADAAMwAxADAAOwAgADIAMAAxADMAUgBvAGIAbwB0AG8ALQBNAGUAZABpAHUAbQBSAG8AYgBvAHQAbwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAEcAbwBvAGcAbABlAC4ARwBvAG8AZwBsAGUARwBvAG8AZwBsAGUALgBjAG8AbQBDAGgAcgBpAHMAdABpAGEAbgAgAFIAbwBiAGUAcgB0AHMAbwBuAEwAaQBjAGUAbgBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAQQBwAGEAYwBoAGUAIABMAGkAYwBlAG4AcwBlACwAIABWAGUAcgBzAGkAbwBuACAAMgAuADAAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAcABhAGMAaABlAC4AbwByAGcALwBsAGkAYwBlAG4AcwBlAHMALwBMAEkAQwBFAE4AUwBFAC0AMgAuADAAUgBvAGIAbwB0AG8ATQBlAGQAaQB1AG0AAAIAAAAAAAD/agBkAAAAAAAAAAAAAAAAAAAAAAAAAAAEHAAAAQIAAgADAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAKMAhACFAL0AlgDoAIYAjgCLAJ0AqQCkAIoBAwCDAJMA8gDzAI0AlwCIAQQA3gDxAJ4AqgD1APQA9gCiAJAA8ACRAO0AiQCgAOoAuAChAO4BBQDXAQYA4gDjAQcBCACwALEBCQCmAQoBCwEMAQ0BDgEPANgA4QDbANwA3QDgANkA3wEQAREBEgETARQBFQEWARcBGAEZARoBGwEcAR0BHgEfASABIQEiAJ8BIwEkASUBJgEnASgBKQEqASsBLAEtAJsBLgEvATABMQEyATMBNAE1ATYBNwE4ATkBOgE7ATwBPQE+AT8BQAFBAUIBQwFEAUUBRgFHAUgBSQFKAUsBTAFNAU4BTwFQAVEBUgFTAVQBVQFWAVcBWAFZAVoBWwFcAV0BXgFfAWABYQFiAWMBZAFlAWYBZwFoAWkBagFrAWwBbQFuAW8BcAFxAXIBcwF0AXUBdgF3AXgBeQF6AXsBfAF9AX4BfwGAAYEBggGDAYQBhQGGAYcBiAGJAYoBiwGMAY0BjgGPAZABkQGSAZMBlAGVAZYBlwGYAZkBmgGbAZwBnQGeAZ8BoAGhAaIBowGkAaUBpgGnAagBqQGqAasBrAGtAa4BrwGwAbEBsgGzAbQBtQG2AbcBuAG5AboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQCyALMBzgC2ALcAxAHPALQAtQDFAIIAwgCHAdAAqwDGAL4AvwC8AdEB0gHTAdQB1QHWAdcB2ACMAdkB2gHbAdwB3QCYAJoAmQDvAKUAkgCcAKcAjwCUAJUAuQHeAd8B4ADAAeEB4gHjAeQB5QHmAecB6AHpAeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+Af8CAAIBAgICAwIEAgUCBgIHAggCCQIKAgsCDAINAg4CDwIQAhECEgITAhQCFQIWAhcCGAIZAhoCGwIcAh0CHgIfAiACIQIiAiMCJAIlAiYCJwIoAikCKgIrAiwCLQIuAi8CMAIxAjICMwI0AjUCNgI3AKwCOAI5AOkCOgI7AjwArQDJAMcArgBiAGMCPQBkAMsAZQDIAMoAzwDMAM0AzgBmANMA0ADRAK8AZwDWANQA1QBoAOsAagBpAGsAbQBsAG4CPgBvAHEAcAByAHMAdQB0AHYAdwB4AHoAeQB7AH0AfAB/AH4AgACBAOwAugI/AkACQQJCAkMCRAD9AP4CRQJGAkcCSAD/AQACSQJKAksCTAJNAk4CTwJQAlECUgJTAlQCVQJWAPgA+QJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAmcCaAJpAmoCawJsAm0CbgJvAnACcQJyAnMCdAJ1AnYCdwJ4AnkCegJ7AnwCfQJ+An8CgAKBAoICgwKEAoUChgKHAogCiQKKAPsA/AKLAowA5ADlAo0CjgKPApACkQKSApMClAKVApYClwKYApkCmgKbApwCnQKeAp8CoAKhAqIAuwKjAqQCpQKmAOYA5wKnAqgCqQKqAqsCrAKtAq4CrwKwArECsgKzArQCtQK2ArcCuAK5AroCuwK8Ar0CvgK/AsACwQLCAsMCxALFAsYCxwLIAskCygLLAswCzQLOAs8C0ALRAtIC0wLUAtUC1gLXAtgC2QLaAtsC3ALdAt4C3wLgAuEC4gLjAuQC5QLmAucC6ALpAuoC6wLsAu0C7gLvAvAC8QLyAvMC9AL1AvYC9wL4AvkC+gL7AvwC/QL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZAxoDGwMcAx0DHgMfAyADIQMiAyMDJAMlAyYDJwMoAykDKgMrAywDLQMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRQNGA0cDSANJA0oDSwNMA00DTgNPA1ADUQNSA1MDVANVA1YDVwNYA1kDWgNbA1wDXQNeA18DYANhA2IDYwNkA2UDZgNnA2gDaQNqA2sDbANtA24DbwNwA3EDcgNzA3QDdQN2A3cDeAN5A3oDewN8A30DfgN/A4ADgQOCA4MDhAOFA4YDhwOIA4kDigOLA4wDjQOOA48DkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDogOjA6QDpQOmA6cDqAOpA6oDqwOsA60DrgOvA7ADsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+A78DwAPBA8IDwwPEA8UDxgPHA8gDyQPKA8sDzAPNA84DzwPQA9ED0gPTA9QD1QPWA9cD2APZA9oD2wPcA90D3gPfA+AD4QPiA+MD5APlA+YD5wPoA+kD6gPrA+wD7QPuA+8D8APxA/ID8wP0A/UD9gP3A/gD+QP6A/sD/AP9A/4D/wQABAEEAgQDBAQEBQQGBAcECAQJBAoECwQMBA0EDgQPBBAEEQQSBBMEFAQVBBYEFwQYBBkEGgQbBBwEHQQeBB8EIAQhAPcEIgQjAAQHdW5pMDAwOQZtYWNyb24OcGVyaW9kY2VudGVyZWQESGJhcgxrZ3JlZW5sYW5kaWMDRW5nA2VuZwVsb25ncwVPaG9ybgVvaG9ybgVVaG9ybgV1aG9ybgd1bmkwMjM3BXNjaHdhB3VuaTAyRjMJZ3JhdmVjb21iCWFjdXRlY29tYgl0aWxkZWNvbWIEaG9vawd1bmkwMzBGCGRvdGJlbG93BXRvbm9zDWRpZXJlc2lzdG9ub3MJYW5vdGVsZWlhBUdhbW1hBURlbHRhBVRoZXRhBkxhbWJkYQJYaQJQaQVTaWdtYQNQaGkDUHNpBWFscGhhBGJldGEFZ2FtbWEFZGVsdGEHZXBzaWxvbgR6ZXRhA2V0YQV0aGV0YQRpb3RhBmxhbWJkYQJ4aQNyaG8Gc2lnbWExBXNpZ21hA3RhdQd1cHNpbG9uA3BoaQNwc2kFb21lZ2EHdW5pMDNEMQd1bmkwM0QyB3VuaTAzRDYHdW5pMDQwMgd1bmkwNDA0B3VuaTA0MDkHdW5pMDQwQQd1bmkwNDBCB3VuaTA0MEYHdW5pMDQxMQd1bmkwNDE0B3VuaTA0MTYHdW5pMDQxNwd1bmkwNDE4B3VuaTA0MUIHdW5pMDQyMwd1bmkwNDI0B3VuaTA0MjYHdW5pMDQyNwd1bmkwNDI4B3VuaTA0MjkHdW5pMDQyQQd1bmkwNDJCB3VuaTA0MkMHdW5pMDQyRAd1bmkwNDJFB3VuaTA0MkYHdW5pMDQzMQd1bmkwNDMyB3VuaTA0MzMHdW5pMDQzNAd1bmkwNDM2B3VuaTA0MzcHdW5pMDQzOAd1bmkwNDNBB3VuaTA0M0IHdW5pMDQzQwd1bmkwNDNEB3VuaTA0M0YHdW5pMDQ0Mgd1bmkwNDQ0B3VuaTA0NDYHdW5pMDQ0Nwd1bmkwNDQ4B3VuaTA0NDkHdW5pMDQ0QQd1bmkwNDRCB3VuaTA0NEMHdW5pMDQ0RAd1bmkwNDRFB3VuaTA0NEYHdW5pMDQ1Mgd1bmkwNDU0B3VuaTA0NTkHdW5pMDQ1QQd1bmkwNDVCB3VuaTA0NUYHdW5pMDQ2MAd1bmkwNDYxB3VuaTA0NjMHdW5pMDQ2NAd1bmkwNDY1B3VuaTA0NjYHdW5pMDQ2Nwd1bmkwNDY4B3VuaTA0NjkHdW5pMDQ2QQd1bmkwNDZCB3VuaTA0NkMHdW5pMDQ2RAd1bmkwNDZFB3VuaTA0NkYHdW5pMDQ3Mgd1bmkwNDczB3VuaTA0NzQHdW5pMDQ3NQd1bmkwNDdBB3VuaTA0N0IHdW5pMDQ3Qwd1bmkwNDdEB3VuaTA0N0UHdW5pMDQ3Rgd1bmkwNDgwB3VuaTA0ODEHdW5pMDQ4Mgd1bmkwNDgzB3VuaTA0ODQHdW5pMDQ4NQd1bmkwNDg2B3VuaTA0ODgHdW5pMDQ4OQd1bmkwNDhEB3VuaTA0OEUHdW5pMDQ4Rgd1bmkwNDkwB3VuaTA0OTEHdW5pMDQ5NAd1bmkwNDk1B3VuaTA0OUMHdW5pMDQ5RAd1bmkwNEEwB3VuaTA0QTEHdW5pMDRBNAd1bmkwNEE1B3VuaTA0QTYHdW5pMDRBNwd1bmkwNEE4B3VuaTA0QTkHdW5pMDRCNAd1bmkwNEI1B3VuaTA0QjgHdW5pMDRCOQd1bmkwNEJBB3VuaTA0QkMHdW5pMDRCRAd1bmkwNEMzB3VuaTA0QzQHdW5pMDRDNwd1bmkwNEM4B3VuaTA0RDgHdW5pMDRFMAd1bmkwNEUxB3VuaTA0RkEHdW5pMDRGQgd1bmkwNTAwB3VuaTA1MDIHdW5pMDUwMwd1bmkwNTA0B3VuaTA1MDUHdW5pMDUwNgd1bmkwNTA3B3VuaTA1MDgHdW5pMDUwOQd1bmkwNTBBB3VuaTA1MEIHdW5pMDUwQwd1bmkwNTBEB3VuaTA1MEUHdW5pMDUwRgd1bmkwNTEwB3VuaTIwMDAHdW5pMjAwMQd1bmkyMDAyB3VuaTIwMDMHdW5pMjAwNAd1bmkyMDA1B3VuaTIwMDYHdW5pMjAwNwd1bmkyMDA4B3VuaTIwMDkHdW5pMjAwQQd1bmkyMDBCDXVuZGVyc2NvcmVkYmwNcXVvdGVyZXZlcnNlZAd1bmkyMDI1B3VuaTIwNzQJbnN1cGVyaW9yBGxpcmEGcGVzZXRhBEV1cm8HdW5pMjEwNQd1bmkyMTEzB3VuaTIxMTYJZXN0aW1hdGVkCW9uZWVpZ2h0aAx0aHJlZWVpZ2h0aHMLZml2ZWVpZ2h0aHMMc2V2ZW5laWdodGhzCmNvbG9uLmxudW0JcXVvdGVkYmx4C2NvbW1hYWNjZW50B3VuaUZFRkYHdW5pRkZGQwd1bmlGRkZECWZpdmUuc21jcAhmb3VyLnN1cAl6ZXJvLmxudW0ObGFyZ2VyaWdodGhvb2sMY3lyaWxsaWNob29rEGN5cmlsbGljaG9va2xlZnQLY3lyaWxsaWN0aWMOYnJldmV0aWxkZWNvbWINYnJldmVob29rY29tYg5icmV2ZWFjdXRlY29tYhNjaXJjdW1mbGV4dGlsZGVjb21iEmNpcmN1bWZsZXhob29rY29tYhNjaXJjdW1mbGV4Z3JhdmVjb21iE2NpcmN1bWZsZXhhY3V0ZWNvbWIOYnJldmVncmF2ZWNvbWIRY29tbWFhY2NlbnRyb3RhdGUGQS5zbWNwBkIuc21jcAZDLnNtY3AGRC5zbWNwBkUuc21jcAZGLnNtY3AGRy5zbWNwBkguc21jcAZJLnNtY3AGSi5zbWNwBksuc21jcAZMLnNtY3AGTS5zbWNwBk4uc21jcAZPLnNtY3AGUS5zbWNwBlIuc21jcAZTLnNtY3AGVC5zbWNwBlUuc21jcAZWLnNtY3AGVy5zbWNwBlguc21jcAZZLnNtY3AGWi5zbWNwCXplcm8uc21jcAhvbmUuc21jcAh0d28uc21jcAp0aHJlZS5zbWNwCWZvdXIuc21jcAh0d28ubG51bQhzaXguc21jcApzZXZlbi5zbWNwCmVpZ2h0LnNtY3AJbmluZS5zbWNwB29uZS5zdXAHdHdvLnN1cAl0aHJlZS5zdXAIb25lLmxudW0IZml2ZS5zdXAHc2l4LnN1cAlzZXZlbi5zdXAJZWlnaHQuc3VwCG5pbmUuc3VwCHplcm8uc3VwCGNyb3NzYmFyCXJpbmdhY3V0ZQlkYXNpYW94aWEKdGhyZWUubG51bQlmb3VyLmxudW0JZml2ZS5sbnVtCHNpeC5sbnVtBWcuYWx0CnNldmVuLmxudW0HY2hpLmFsdAplaWdodC5sbnVtCWFscGhhLmFsdAlkZWx0YS5hbHQERC5jbgRhLmNuBVIuYWx0BUsuYWx0BWsuYWx0BksuYWx0MgZrLmFsdDIJbmluZS5sbnVtBlAuc21jcA1jeXJpbGxpY2JyZXZlB3VuaTAwQUQGRGNyb2F0BGhiYXIEVGJhcgR0YmFyCkFyaW5nYWN1dGUKYXJpbmdhY3V0ZQdBbWFjcm9uB2FtYWNyb24GQWJyZXZlBmFicmV2ZQdBb2dvbmVrB2FvZ29uZWsLQ2NpcmN1bWZsZXgLY2NpcmN1bWZsZXgHdW5pMDEwQQd1bmkwMTBCBkRjYXJvbgZkY2Fyb24HRW1hY3JvbgdlbWFjcm9uBkVicmV2ZQZlYnJldmUKRWRvdGFjY2VudAplZG90YWNjZW50B0VvZ29uZWsHZW9nb25lawZFY2Fyb24GZWNhcm9uC0djaXJjdW1mbGV4C2djaXJjdW1mbGV4B3VuaTAxMjAHdW5pMDEyMQxHY29tbWFhY2NlbnQMZ2NvbW1hYWNjZW50C0hjaXJjdW1mbGV4C2hjaXJjdW1mbGV4Bkl0aWxkZQZpdGlsZGUHSW1hY3JvbgdpbWFjcm9uBklicmV2ZQZpYnJldmUHSW9nb25lawdpb2dvbmVrCklkb3RhY2NlbnQCSUoCaWoLSmNpcmN1bWZsZXgLamNpcmN1bWZsZXgMS2NvbW1hYWNjZW50DGtjb21tYWFjY2VudAZMYWN1dGUGbGFjdXRlDExjb21tYWFjY2VudAxsY29tbWFhY2NlbnQGTGNhcm9uBmxjYXJvbgRMZG90BGxkb3QGTmFjdXRlBm5hY3V0ZQxOY29tbWFhY2NlbnQMbmNvbW1hYWNjZW50Bk5jYXJvbgZuY2Fyb24LbmFwb3N0cm9waGUHT21hY3JvbgdvbWFjcm9uBk9icmV2ZQZvYnJldmUNT2h1bmdhcnVtbGF1dA1vaHVuZ2FydW1sYXV0BlJhY3V0ZQZyYWN1dGUMUmNvbW1hYWNjZW50DHJjb21tYWFjY2VudAZSY2Fyb24GcmNhcm9uBlNhY3V0ZQZzYWN1dGULU2NpcmN1bWZsZXgLc2NpcmN1bWZsZXgHdW5pMDIxOAd1bmkwMjE5B3VuaTAyMUEHdW5pMDIxQgd1bmkwMTYyB3VuaTAxNjMGVGNhcm9uBnRjYXJvbgZVdGlsZGUGdXRpbGRlB1VtYWNyb24HdW1hY3JvbgZVYnJldmUGdWJyZXZlBVVyaW5nBXVyaW5nDVVodW5nYXJ1bWxhdXQNdWh1bmdhcnVtbGF1dAdVb2dvbmVrB3VvZ29uZWsLV2NpcmN1bWZsZXgLd2NpcmN1bWZsZXgLWWNpcmN1bWZsZXgLeWNpcmN1bWZsZXgGWmFjdXRlBnphY3V0ZQpaZG90YWNjZW50Cnpkb3RhY2NlbnQHQUVhY3V0ZQdhZWFjdXRlC09zbGFzaGFjdXRlC29zbGFzaGFjdXRlC0Rjcm9hdC5zbWNwCEV0aC5zbWNwCVRiYXIuc21jcAtBZ3JhdmUuc21jcAtBYWN1dGUuc21jcBBBY2lyY3VtZmxleC5zbWNwC0F0aWxkZS5zbWNwDkFkaWVyZXNpcy5zbWNwCkFyaW5nLnNtY3APQXJpbmdhY3V0ZS5zbWNwDUNjZWRpbGxhLnNtY3ALRWdyYXZlLnNtY3ALRWFjdXRlLnNtY3AQRWNpcmN1bWZsZXguc21jcA5FZGllcmVzaXMuc21jcAtJZ3JhdmUuc21jcAtJYWN1dGUuc21jcBBJY2lyY3VtZmxleC5zbWNwDklkaWVyZXNpcy5zbWNwC050aWxkZS5zbWNwC09ncmF2ZS5zbWNwC09hY3V0ZS5zbWNwEE9jaXJjdW1mbGV4LnNtY3ALT3RpbGRlLnNtY3AOT2RpZXJlc2lzLnNtY3ALVWdyYXZlLnNtY3ALVWFjdXRlLnNtY3AQVWNpcmN1bWZsZXguc21jcA5VZGllcmVzaXMuc21jcAtZYWN1dGUuc21jcAxBbWFjcm9uLnNtY3ALQWJyZXZlLnNtY3AMQW9nb25lay5zbWNwC0NhY3V0ZS5zbWNwEENjaXJjdW1mbGV4LnNtY3AMdW5pMDEwQS5zbWNwC0NjYXJvbi5zbWNwC0RjYXJvbi5zbWNwDEVtYWNyb24uc21jcAtFYnJldmUuc21jcA9FZG90YWNjZW50LnNtY3AMRW9nb25lay5zbWNwC0VjYXJvbi5zbWNwEEdjaXJjdW1mbGV4LnNtY3ALR2JyZXZlLnNtY3AMdW5pMDEyMC5zbWNwEUdjb21tYWFjY2VudC5zbWNwEEhjaXJjdW1mbGV4LnNtY3ALSXRpbGRlLnNtY3AMSW1hY3Jvbi5zbWNwC0licmV2ZS5zbWNwDElvZ29uZWsuc21jcA9JZG90YWNjZW50LnNtY3AQSmNpcmN1bWZsZXguc21jcBFLY29tbWFhY2NlbnQuc21jcAtMYWN1dGUuc21jcBFMY29tbWFhY2NlbnQuc21jcAtMY2Fyb24uc21jcAlMZG90LnNtY3ALTmFjdXRlLnNtY3ARTmNvbW1hYWNjZW50LnNtY3ALTmNhcm9uLnNtY3AMT21hY3Jvbi5zbWNwC09icmV2ZS5zbWNwEk9odW5nYXJ1bWxhdXQuc21jcAtSYWN1dGUuc21jcBFSY29tbWFhY2NlbnQuc21jcAtSY2Fyb24uc21jcAtTYWN1dGUuc21jcBBTY2lyY3VtZmxleC5zbWNwDVNjZWRpbGxhLnNtY3ALU2Nhcm9uLnNtY3ARVGNvbW1hYWNjZW50LnNtY3ALVGNhcm9uLnNtY3ALVXRpbGRlLnNtY3AMVW1hY3Jvbi5zbWNwC1VicmV2ZS5zbWNwClVyaW5nLnNtY3ASVWh1bmdhcnVtbGF1dC5zbWNwDFVvZ29uZWsuc21jcBBXY2lyY3VtZmxleC5zbWNwEFljaXJjdW1mbGV4LnNtY3AOWWRpZXJlc2lzLnNtY3ALWmFjdXRlLnNtY3APWmRvdGFjY2VudC5zbWNwC1pjYXJvbi5zbWNwD2dlcm1hbmRibHMuc21jcApBbHBoYXRvbm9zDEVwc2lsb250b25vcwhFdGF0b25vcwlJb3RhdG9ub3MMT21pY3JvbnRvbm9zDFVwc2lsb250b25vcwpPbWVnYXRvbm9zEWlvdGFkaWVyZXNpc3Rvbm9zBUFscGhhBEJldGEHRXBzaWxvbgRaZXRhA0V0YQRJb3RhBUthcHBhAk11Ak51B09taWNyb24DUmhvA1RhdQdVcHNpbG9uA0NoaQxJb3RhZGllcmVzaXMPVXBzaWxvbmRpZXJlc2lzCmFscGhhdG9ub3MMZXBzaWxvbnRvbm9zCGV0YXRvbm9zCWlvdGF0b25vcxR1cHNpbG9uZGllcmVzaXN0b25vcwVrYXBwYQdvbWljcm9uB3VuaTAzQkMCbnUDY2hpDGlvdGFkaWVyZXNpcw91cHNpbG9uZGllcmVzaXMMb21pY3JvbnRvbm9zDHVwc2lsb250b25vcwpvbWVnYXRvbm9zB3VuaTA0MDEHdW5pMDQwMwd1bmkwNDA1B3VuaTA0MDYHdW5pMDQwNwd1bmkwNDA4B3VuaTA0MUEHdW5pMDQwQwd1bmkwNDBFB3VuaTA0MTAHdW5pMDQxMgd1bmkwNDEzB3VuaTA0MTUHdW5pMDQxOQd1bmkwNDFDB3VuaTA0MUQHdW5pMDQxRQd1bmkwNDFGB3VuaTA0MjAHdW5pMDQyMQd1bmkwNDIyB3VuaTA0MjUHdW5pMDQzMAd1bmkwNDM1B3VuaTA0MzkHdW5pMDQzRQd1bmkwNDQwB3VuaTA0NDEHdW5pMDQ0Mwd1bmkwNDQ1B3VuaTA0NTEHdW5pMDQ1Mwd1bmkwNDU1B3VuaTA0NTYHdW5pMDQ1Nwd1bmkwNDU4B3VuaTA0NUMHdW5pMDQ1RQZXZ3JhdmUGd2dyYXZlBldhY3V0ZQZ3YWN1dGUJV2RpZXJlc2lzCXdkaWVyZXNpcwZZZ3JhdmUGeWdyYXZlBm1pbnV0ZQZzZWNvbmQJZXhjbGFtZGJsB3VuaUZCMDIHdW5pMDFGMAd1bmkwMkJDB3VuaTFFM0UHdW5pMUUzRgd1bmkxRTAwB3VuaTFFMDEHdW5pMUY0RAd1bmlGQjAzB3VuaUZCMDQHdW5pMDQwMAd1bmkwNDBEB3VuaTA0NTAHdW5pMDQ1RAd1bmkwNDcwB3VuaTA0NzEHdW5pMDQ3Ngd1bmkwNDc3B3VuaTA0NzkHdW5pMDQ3OAd1bmkwNDk4B3VuaTA0OTkHdW5pMDRBQQd1bmkwNEFCB3VuaTA0QUUHdW5pMDRBRgd1bmkwNEMwB3VuaTA0QzEHdW5pMDRDMgd1bmkwNENGB3VuaTA0RDAHdW5pMDREMQd1bmkwNEQyB3VuaTA0RDMHdW5pMDRENAd1bmkwNEQ1B3VuaTA0RDYHdW5pMDRENwd1bmkwNERBB3VuaTA0RDkHdW5pMDREQgd1bmkwNERDB3VuaTA0REQHdW5pMDRERQd1bmkwNERGB3VuaTA0RTIHdW5pMDRFMwd1bmkwNEU0B3VuaTA0RTUHdW5pMDRFNgd1bmkwNEU3B3VuaTA0RTgHdW5pMDRFOQd1bmkwNEVBB3VuaTA0RUIHdW5pMDRFQwd1bmkwNEVEB3VuaTA0RUUHdW5pMDRFRgd1bmkwNEYwB3VuaTA0RjEHdW5pMDRGMgd1bmkwNEYzB3VuaTA0RjQHdW5pMDRGNQd1bmkwNEY4B3VuaTA0RjkHdW5pMDRGQwd1bmkwNEZEB3VuaTA1MDEHdW5pMDUxMgd1bmkwNTEzB3VuaTFFQTAHdW5pMUVBMQd1bmkxRUEyB3VuaTFFQTMHdW5pMUVBNAd1bmkxRUE1B3VuaTFFQTYHdW5pMUVBNwd1bmkxRUE4B3VuaTFFQTkHdW5pMUVBQQd1bmkxRUFCB3VuaTFFQUMHdW5pMUVBRAd1bmkxRUFFB3VuaTFFQUYHdW5pMUVCMAd1bmkxRUIxB3VuaTFFQjIHdW5pMUVCMwd1bmkxRUI0B3VuaTFFQjUHdW5pMUVCNgd1bmkxRUI3B3VuaTFFQjgHdW5pMUVCOQd1bmkxRUJBB3VuaTFFQkIHdW5pMUVCQwd1bmkxRUJEB3VuaTFFQkUHdW5pMUVCRgd1bmkxRUMwB3VuaTFFQzEHdW5pMUVDMgd1bmkxRUMzB3VuaTFFQzQHdW5pMUVDNQd1bmkxRUM2B3VuaTFFQzcHdW5pMUVDOAd1bmkxRUM5B3VuaTFFQ0EHdW5pMUVDQgd1bmkxRUNDB3VuaTFFQ0QHdW5pMUVDRQd1bmkxRUNGB3VuaTFFRDAHdW5pMUVEMQd1bmkxRUQyB3VuaTFFRDMHdW5pMUVENAd1bmkxRUQ1B3VuaTFFRDYHdW5pMUVENwd1bmkxRUQ4B3VuaTFFRDkHdW5pMUVEQQd1bmkxRURCB3VuaTFFREMHdW5pMUVERAd1bmkxRURFB3VuaTFFREYHdW5pMUVFMAd1bmkxRUUxB3VuaTFFRTIHdW5pMUVFMwd1bmkxRUU0B3VuaTFFRTUHdW5pMUVFNgd1bmkxRUU3B3VuaTFFRTgHdW5pMUVFOQd1bmkxRUVBB3VuaTFFRUIHdW5pMUVFQwd1bmkxRUVEB3VuaTFFRUUHdW5pMUVFRgd1bmkxRUYwB3VuaTFFRjEHdW5pMUVGNAd1bmkxRUY1B3VuaTFFRjYHdW5pMUVGNwd1bmkxRUY4B3VuaTFFRjkGZGNyb2F0B3VuaTIwQUIHdW5pMDQ5QQd1bmkwNDlCB3VuaTA0QTIHdW5pMDRBMwd1bmkwNEFDB3VuaTA0QUQHdW5pMDRCMgd1bmkwNEIzB3VuaTA0QjYHdW5pMDRCNwd1bmkwNENCB3VuaTA0Q0MHdW5pMDRGNgd1bmkwNEY3B3VuaTA0OTYHdW5pMDQ5Nwd1bmkwNEJFB3VuaTA0QkYHdW5pMDRCQgd1bmkwNDhDB3VuaTA0NjIHdW5pMDQ5Mgd1bmkwNDkzB3VuaTA0OUUHdW5pMDQ5Rgd1bmkwNDhBB3VuaTA0OEIHdW5pMDRDOQd1bmkwNENBB3VuaTA0Q0QHdW5pMDRDRQd1bmkwNEM1B3VuaTA0QzYHdW5pMDRCMAd1bmkwNEIxB3VuaTA0RkUHdW5pMDRGRgd1bmkwNTExB3VuaTIwMTUHdW5pMDAwMgAAAAEAAAAMAAAAAAAAAAIACADKAMoAAQEeASQAAQFWAWEAAQF2AXYAAQF7AXwAAQF+AX4AAQGTAZUAAQHVAdUAAQAAAAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAA//8AAQAAAAFrZXJuAAgAAAABAAAAAQAEAAIAAAAEAA5PUFUOekAAAYG8AAQAAAGtA2QDagNwA3YD7AP2BAgELgREBE4EcASSBJgE6gUYBToFXAWCBagFrgacBqIGyAbuB1AH4ggECCYIRAhKCFgIXghkCGoIkAiuCLwI2gjgCP4JHAkiCewKYgqICv4LBAsOCxQLGgsgCz4LaAtuC4QLiguoC64LtAvuC/QL/gwwDFoMhAyqDMwM8g0gDYINmA26DdwOJg5IDmoOoA7KDvQO/g8IDyYPPA9GD2QPag+AD84P7BAKECgQThB0EJIQnBDCEOgRDhGEEaoR0BHuEgwS1hLgEzIThBOOE5QTmhOgE6YTrBPSE9wT4hP0FB4UNBRGFFgUfhSEFJoUpBS2FNwU8hT4FP4VBBUeFSwVMhVYFX4WbBbiF1gXzhhEGLoZMBmmGbgZzhnkGfoaEBoyGlQadhqYGroa4BsGGywbUht4G34bhBuKG5AcIhxEHGYciByqHMwc7h0QHRYdHB0iHSgdLh1UHXodoB3GHeweCh4oHp4ewB82H1gfzh/wIAIgFCAmIDggXiB0IHogkCCWIKwgsiDIIM4g5CDqIQwhEiE0IVYheCGaIbwhwiIUIkIicCKeIswi7iL0IxYjHCM+I0QjSiNwI5YjvCPiJAgkLiQ8JEokWCVGJjQnIicoJy4nNCc6J0AnRidsJ/4oHCiuKNAo8ikUKYopoCnCKeQqCiqcKxIrHCsyK1QrdiuYK+osDCwuLFQsei1oLfouXC5+LxAvFi88L1ovgC+WMGAwgjCkMKow/DFOMZgyDjIYMuIy+DMaMzwzYjOIM5o0iDTqNQw1EjU4NVY1dDV6NYA1ijWoNc419DYaNqw2yjbQNtY23Db+NwQ3ejecN8I32DfeOAQ4Ijg0OMY45DkGOWg5bjmQOgY6KDqeOsA61jrcOuI66DtKO1A7djucO8I74DwqPEg8kjywPPo9GD16PYA99j4YPo4+sD8mP0g/vj/gQFZAeEDuQRBBhkGoQh5CQEK2QthDTkNwQ+ZECER+RKBEtkS8RNJE2ETuRPRFCkUQRSZFLEVCRUhFXkVkRXpFgEWiRcRF6kYQRjZGXEaCRqhGzkb0RxpHQEdmR4xHskfYR/5IBEgKSJxIuklMSWpJ/EoaSmxKjkt8S95L5EyuTLhNGk0gTSZNUE4aTmxOjk6wAAEAWQALAAEAWQALAAEAEf8IAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAACAQwACwFT/+YABAAL/+YAP//0AF//7wE8/+0ACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAFAEj/7gBZ/+oBuv/wAbv/7QG9//AAAgBU/+YBpv/AAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQGm/+sAFABZ/8EAs//FAMX/tADl/9cA8f+5APn/6QEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8BqP/oAaz/5gG0/+cBtf/nAAsAWf/MAaYAEwGo//MBrP/xAbT/8gG1//IBuP+9Abn/7gG6/7gBu//XAb3/twAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQBWAA4Af/7XAL//mADC/8cA1P8SAOj/UgFG/88Bpv+AAd//1wABAaYADgA7AFT/vwBZ/9EAa/9sAHr/bgB//0MAhP+sAIf/oQCz/7gAuv9+AL7/ewDB/5sAwv95AMX/sgDH/34AyP99AMn/fADU/68A4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APn/sgD6/4AA/P95AP0AKAEC/30BBP9/ARf/ZgEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAab/rwGo/7kBrP+5AbT/uQG1/7kBt/+8Abj/8QG7//EBvP/tAdz/swHf//EAAQGm/+sACQALABQAPwARAFT/4gBfABMBpv+0Aaj/2QGs/9kBtP/ZAbX/2QAJAAsADwA/AAwAVP/rAF8ADgGm/8sBqP/pAaz/5wG0/+cBtf/nABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAaj/6QGs/+cBtP/nAbX/6QHf//AAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAab/qwGo/80BrP/LAbT/ywG1/8sBuP/zAbv/8wG8/+8B3P/AAd//7gAIAFn/5QCz/8sAyP/kAaYADQGo/+0BrP/rAbT/7AG1/+wACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAcAxf/qAOj/7gDx/9YA+f/tAS//7AFU/+wB3P/oAAEA8f/1AAMACwAUAD8AEgBfABMAAQDx/9YAAQDx/9YAAQDx/9YACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAHAMX/6gDo/+4A8f/WAPn/7QEv/+wBVP/sAdz/6AADAEgAFABWABgAWQARAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAEBF//xAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAcAxf/qAOj/7gDx/9YA+f/tAS//7AFU/+wB3P/oAAEA8f/1ADIAVP9+AFn/nQBr/vEAev70AH/+qwCE/14Ah/9LALP/cgC6/w8Avv8KAMH/QQDC/wcAxf9oAMf/DwDI/w4Ayf8MANT/YwDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+f9oAPr/EwD8/wcA/QAwAQL/DgEE/xEBF/7nARv/rAEn/xUBKf88AS3/DgEv/2oBM/9JATn/DAE7/z8BPP7xAUH/wAFG/u8BSv8xAUz/XwFQ/woBUwAFAVT/MAFV/9UB3P9qAd//0wAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QAAQC/AA0AAgCz/8IAvwAQAAEAv//iAAEAwv/yAAEAvwAOAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAoAuv/mAL3/6wC+/+kAwP/wAMH/5wDF/+MAx//OAMj/1ADJ/9sB3//uAAEA8f/WAAUAvf/sAL8ADwDB/+oAxf/OAMf/5wABAL8ADwAHAMX/6gDo/+4A8f/VAPn/7QEv/+wBVP/sAdz/6AABAPH/wAABAMUAIAAOAEgADAC//5AAwQALAMUADAGm/78BqP/uAaz/7AG0/+0Btf/sAbf/9QG4AA4BugANAb0ADQHf/+0AAQDx/+IAAgDx/8AB3P/hAAwA4f/UAPH/yQD5/9EBBP/lARv/4wEv/8QBOP/hAUn/1AFK//UBS//nAVP/ZAFU/8kACgDh/8EA8f/NAPn/0gEv/8wBOP/lATv/3wFJ/84BS//qAVP/ngFU/84ACgDh/8IA8f/GAPn/zwEv/8ABOP/hATv/3wFJ/80BS//oAVP/nwFU/8YACQDh/8kA8f/fAPn/4QEE/+0BG//rAS//3wE7/+kBSv/1AVT/4AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQDh/+YA8f/QAPn/1gEv/84BOP/oAUn/5wFL/+0BU//mAVT/0AALANQAFADh/+AA6AATATj/4QE5/+ABPP/hAUH/6QFJ/98BS//eAVP/3wFV//IAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqP/pAaz/5wG0/+cBtf/pAd//8AAFABn/8gDh//EBSf/yAUv/8gFT//IACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AASANT/rgDhABIA5v/gAOj/rQDq/9YA+P/fAPz/0gEC/+ABF//OASf/3QEp/+IBLf/gATP/4AE5/+kBPP/aAUb/vQFQ/98BUwARAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QADQDUABMA4f/mAOL/9ADoABIA8f/nAPn/5wEv/+cBOP/lATn/6AFJ/+YBS//mAVP/5gFU/+cACgDh/8QA8f/NAPn/1QEv/8wBOP/mATv/3wFJ/9EBS//sAVP/oQFU/88ACgDh/8MA8f/PAPn/1AEv/84BOP/nATv/3wFJ/9EBS//sAVP/oAFU/9EAAgDU/+IBU//kAAIA1P/hAOj/5AAHAOj/7gDx/+4A+f/vAQT/9AEb//EBL//vAVT/7wAFAPH/9AD5//QBBP/1AS//9QFU//UAAgDo/2gBF//uAAcA6AAUAPH/7QD3/9AA+f/uAS//7QE5/+0BVP/tAAEBF//xAAUBF//rAaj/6wGs/+kBtP/rAbX/6wATAEgADQDC/9YAw//AAMf/1QDo/8gBF//sARsADAFKAAsBTAALAab/vwGo/+4BrP/sAbT/7QG1/+wBt//1AbgADgG6AA0BvQANAd//xAAHAMX/6gDo/+4A8f/WAPn/7QEv/+wBVP/sAdz/6AAHAOgAFADx//AA+f/wAPwAFgEv/+YBOf/cAVT/8AAHAOgAEgDx/+MA9/+4APn/4wEv/7oBOf/ZAVT/4wAJAPH/gAD5//ABBP/bARv/3AEv/0cBOf/uAUoABwFM//QBVP9/AAkA8f9qAPn/xgEE/9kBG//bAS//HgE5/+0BSv/wAUz/8gFU/1YABwDF/+oA6P/uAPH/1gD5/+0BL//sAVT/7AHc/+gAAgDo/+8A+f/uAAkA8f92APn/0wEE/9kBG//bAS//HgE5/+0BSv/wAUz/8gFU/1YACQDx/2QA+f/ZAQT/2QEb/9sBL/8eATn/7QFK//ABTP/yAVT/VgAJAPH/agD5/8YBBP/ZARv/2wEv/x4BOf/tAUr/8AFM//IBVP9WAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkACwAUAD8AEQBU/+IAXwATAab/tAGo/9kBrP/ZAbT/2QG1/9kABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UABwDF/+oA6P/uAPH/1gD5/+0BL//sAVT/7AHc/+gAMgBU/34AWf+dAGv+8QB6/vQAf/6rAIT/XgCH/0sAs/9yALr/DwC+/woAwf9BAML/BwDF/2gAx/8PAMj/DgDJ/wwA1P9jAOEABQDl/70A5v9JAOj+/gDq/xMA8f9oAPj/DgD5/2gA+v8TAPz/BwD9ADABAv8OAQT/EQEX/ucBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/2oB3//TAAIA6P9oARf/7gAUAFn/wQCz/8UAxf+0AOX/1wDx/7kA+f/pAQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGo/+gBrP/mAbT/5wG1/+cAFABZ/8EAs//FAMX/tADl/9cA8f+5APn/6QEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8BqP/oAaz/5gG0/+cBtf/nAAIA6P9oARf/7gABAFkACwABAFkACwABAFkACwABAFkACwABAFkACwAJAaj/8gGs//IBtP/yAbX/8gG4/8ABuf/sAbr/xwG7/9gBvf+/AAIBuv/uAbv/9QABAab/0gAEAaj/6wGs/+kBtP/rAbX/6wAKAaYAEQGo//ABrP/uAbT/7wG1//ABuP+7Abn/7AG6/7cBu//VAb3/tAAFAab/8wG4/+4Buv/xAbz/7AG9/+oABAG4/+kBuv/rAbv/8QG9/+UABAG4//IBuv/xAbv/9QG9/+4ACQGm/78BqP/uAaz/7AG0/+0Btf/sAbf/9QG4AA4BugANAb0ADQABAab/7wAFAab/xwGo//IBrP/wAbT/8AG1//AAAgGm/9wBuAAOAAQBqP/tAaz/6wG0/+sBtf/rAAkBpv/AAaj/7QGs/+sBtP/rAbX/6wG4AA8BugAQAbsADQG9ABAABQGmAAwBqP/wAaz/8AG0//ABtf/wAAEB1//VAAEBxP/VAAEB1/9AAAYASAALALr/8gDH//EAyf/vAdwADwHf/+4AAwDF/+0A8f/VAdz/7AABAab/1QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UAOwBU/78AWf/RAGv/bAB6/24Af/9DAIT/rACH/6EAs/+4ALr/fgC+/3sAwf+bAML/eQDF/7IAx/9+AMj/fQDJ/3wA1P+vAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD5/7IA+v+AAPz/eQD9ACgBAv99AQT/fwEX/2YBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGm/68BqP+5Aaz/uQG0/7kBtf+5Abf/vAG4//EBu//xAbz/7QHc/7MB3//xAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAEAAv/5gA///QAX//vATz/7QAFAEj/7gBZ/+oBuv/wAbv/7QG9//AABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAUASP/uAFn/6gG6//ABu//tAb3/8AAFAEj/7gBZ/+oBuv/wAbv/7QG9//AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UAAQGm/+sAAQGm/+sAAQGm/+sAAQGm/+sAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAab/qwGo/80BrP/LAbT/ywG1/8sBuP/zAbv/8wG8/+8B3P/AAd//7gAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EAAQDx//UAAQDx//UAAQDx//UAAQDx//UAAQDx/9YACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAxf/qAOj/uADx/+IBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QAFAEj/7gBZ/+oBuv/wAbv/7QG9//AAAQDx//UABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/9YACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAab/6wAUAFn/wQCz/8UAxf+0AOX/1wDx/7kA+f/pAQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGo/+gBrP/mAbT/5wG1/+cACwBZ/8wBpgATAaj/8wGs//EBtP/yAbX/8gG4/70Buf/uAbr/uAG7/9cBvf+3AAsAWf/MAaYAEwGo//MBrP/xAbT/8gG1//IBuP+9Abn/7gG6/7gBu//XAb3/twALAFn/zAGmABMBqP/zAaz/8QG0//IBtf/yAbj/vQG5/+4Buv+4Abv/1wG9/7cACwBZ/8wBpgATAaj/8wGs//EBtP/yAbX/8gG4/70Buf/uAbr/uAG7/9cBvf+3AAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAPH/1gAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/9YACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEA8f/WAAEA8f/WAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAxf/qAOj/uADx/+IBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAMASAAUAFYAGABZABEAAwBIABQAVgAYAFkAEQADAEgAFABWABgAWQARADsAVP+/AFn/0QBr/2wAev9uAH//QwCE/6wAh/+hALP/uAC6/34Avv97AMH/mwDC/3kAxf+yAMf/fgDI/30Ayf98ANT/rwDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+f+yAPr/gAD8/3kA/QAoAQL/fQEE/38BF/9mARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBpv+vAaj/uQGs/7kBtP+5AbX/uQG3/7wBuP/xAbv/8QG8/+0B3P+zAd//8QA7AFT/vwBZ/9EAa/9sAHr/bgB//0MAhP+sAIf/oQCz/7gAuv9+AL7/ewDB/5sAwv95AMX/sgDH/34AyP99AMn/fADU/68A4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APn/sgD6/4AA/P95AP0AKAEC/30BBP9/ARf/ZgEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAab/rwGo/7kBrP+5AbT/uQG1/7kBt/+8Abj/8QG7//EBvP/tAdz/swHf//EAOwBU/78AWf/RAGv/bAB6/24Af/9DAIT/rACH/6EAs/+4ALr/fgC+/3sAwf+bAML/eQDF/7IAx/9+AMj/fQDJ/3wA1P+vAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD5/7IA+v+AAPz/eQD9ACgBAv99AQT/fwEX/2YBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGm/68BqP+5Aaz/uQG0/7kBtf+5Abf/vAG4//EBu//xAbz/7QHc/7MB3//xAAEBpv/rAAEBpv/rAAEBpv/rAAEBpv/rAAEBpv/rAAEBpv/rAAkACwAPAD8ADABU/+sAXwAOAab/ywGo/+kBrP/nAbT/5wG1/+cAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAab/qwGo/80BrP/LAbT/ywG1/8sBuP/zAbv/8wG8/+8B3P/AAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBpv+rAaj/zQGs/8sBtP/LAbX/ywG4//MBu//zAbz/7wHc/8AB3//uAAgAWf/lALP/ywDI/+QBpgANAaj/7QGs/+sBtP/sAbX/7AAIAFn/5QCz/8sAyP/kAaYADQGo/+0BrP/rAbT/7AG1/+wACABZ/+UAs//LAMj/5AGmAA0BqP/tAaz/6wG0/+wBtf/sAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAFAEj/7gBZ/+oBuv/wAbv/7QG9//AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1ACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGm/6sBqP/NAaz/ywG0/8sBtf/LAbj/8wG7//MBvP/vAdz/wAHf/+4AHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAIBDAALAVP/5gAFAEj/7gBZ/+oBuv/wAbv/7QG9//AACABZ/+UAs//LAMj/5AGmAA0BqP/tAaz/6wG0/+wBtf/sAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAFABZ/8EAs//FAMX/tADl/9cA8f+5APn/6QEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8BqP/oAaz/5gG0/+cBtf/nAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAFYADgB//tcAv/+YAML/xwDU/xIA6P9SAUb/zwGm/4AB3//XADsAVP+/AFn/0QBr/2wAev9uAH//QwCE/6wAh/+hALP/uAC6/34Avv97AMH/mwDC/3kAxf+yAMf/fgDI/30Ayf98ANT/rwDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+f+yAPr/gAD8/3kA/QAoAQL/fQEE/38BF/9mARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBpv+vAaj/uQGs/7kBtP+5AbX/uQG3/7wBuP/xAbv/8QG8/+0B3P+zAd//8QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBpv+rAaj/zQGs/8sBtP/LAbX/ywG4//MBu//zAbz/7wHc/8AB3//uABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAaj/6QGs/+cBtP/nAbX/6QHf//AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGm/6sBqP/NAaz/ywG0/8sBtf/LAbj/8wG7//MBvP/vAdz/wAHf/+4AAQDx/9YACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAUASP/uAFn/6gG6//ABu//tAb3/8AAyAFT/fgBZ/50Aa/7xAHr+9AB//qsAhP9eAIf/SwCz/3IAuv8PAL7/CgDB/0EAwv8HAMX/aADH/w8AyP8OAMn/DADU/2MA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPn/aAD6/xMA/P8HAP0AMAEC/w4BBP8RARf+5wEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/agHf/9MACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAab/6wAUAFn/wQCz/8UAxf+0AOX/1wDx/7kA+f/pAQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGo/+gBrP/mAbT/5wG1/+cAFABZ/8EAs//FAMX/tADl/9cA8f+5APn/6QEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8BqP/oAaz/5gG0/+cBtf/nABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAIBDAALAVP/5gAyAFT/fgBZ/50Aa/7xAHr+9AB//qsAhP9eAIf/SwCz/3IAuv8PAL7/CgDB/0EAwv8HAMX/aADH/w8AyP8OAMn/DADU/2MA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPn/aAD6/xMA/P8HAP0AMAEC/w4BBP8RARf+5wEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/agHf/9MABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAFYADgB//tcAv/+YAML/xwDU/xIA6P9SAUb/zwGm/4AB3//XAAQAC//mAD//9ABf/+8BPP/tADsAVP+/AFn/0QBr/2wAev9uAH//QwCE/6wAh/+hALP/uAC6/34Avv97AMH/mwDC/3kAxf+yAMf/fgDI/30Ayf98ANT/rwDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+f+yAPr/gAD8/3kA/QAoAQL/fQEE/38BF/9mARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBpv+vAaj/uQGs/7kBtP+5AbX/uQG3/7wBuP/xAbv/8QG8/+0B3P+zAd//8QAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGo/+kBrP/nAbT/5wG1/+kB3//wAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QABAPH/9QAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAcAxf/qAOj/7gDx/9YA+f/tAS//7AFU/+wB3P/oAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAEBF//xAAEA8f/1AAIA6P9oARf/7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAJAAsADwA/AAwAVP/rAF8ADgGm/8sBqP/pAaz/5wG0/+cBtf/nAAkACwAPAD8ADABU/+sAXwAOAab/ywGo/+kBrP/nAbT/5wG1/+cACQALAA8APwAMAFT/6wBfAA4Bpv/LAaj/6QGs/+cBtP/nAbX/5wAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBpv+rAaj/zQGs/8sBtP/LAbX/ywG4//MBu//zAbz/7wHc/8AB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAEAWQALAAEAWQALAAEAWQALAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAPH/1gAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAkACwAUAD8AEQBU/+IAXwATAab/tAGo/9kBrP/ZAbT/2QG1/9kABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UABAAL/+YAP//0AF//7wE8/+0AJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAab/qwGo/80BrP/LAbT/ywG1/8sBuP/zAbv/8wG8/+8B3P/AAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqP/pAaz/5wG0/+cBtf/pAd//8AABARf/8QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QABAPH/9QABAPH/9QAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGo/+kBrP/nAbT/5wG1/+kB3//wAAEBF//xAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAcAxf/qAOj/7gDx/9YA+f/tAS//7AFU/+wB3P/oABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAEgDU/64A4QASAOb/4ADo/60A6v/WAPj/3wD8/9IBAv/gARf/zgEn/90BKf/iAS3/4AEz/+ABOf/pATz/2gFG/70BUP/fAVMAEQAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QASANT/rgDhABIA5v/gAOj/rQDq/9YA+P/fAPz/0gEC/+ABF//OASf/3QEp/+IBLf/gATP/4AE5/+kBPP/aAUb/vQFQ/98BUwARAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAaj/6QGs/+cBtP/nAbX/6QHf//AAAQEX//EAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EAHQAh/68AVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAPn/0AEv/4EBOP9lATn/hQE7/2YBPP/dAUH/8gFJ/7EBS//KAVP/qQFU/8gBrP/1AbT/9QG4/8cBuf/xAbr/zQG7/90Bvf/EAAgA8f/wAPn/8AEE//EBG//zAS//8QFK//MBTP/zAVT/8QAdACH/rwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oA+f/QAS//gQE4/2UBOf+FATv/ZgE8/90BQf/yAUn/sQFL/8oBU/+pAVT/yAGs//UBtP/1Abj/xwG5//EBuv/NAbv/3QG9/8QACADx//AA+f/wAQT/8QEb//MBL//xAUr/8wFM//MBVP/xAB0AIf+vAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygD5/9ABL/+BATj/ZQE5/4UBO/9mATz/3QFB//IBSf+xAUv/ygFT/6kBVP/IAaz/9QG0//UBuP/HAbn/8QG6/80Bu//dAb3/xAAIAPH/8AD5//ABBP/xARv/8wEv//EBSv/zAUz/8wFU//EABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QAFAEj/7gBZ/+oBuv/wAbv/7QG9//AAAQDx//UABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QAFAEj/7gBZ/+oBuv/wAbv/7QG9//AAAQDx//UABQBI/+4AWf/qAbr/8AG7/+0Bvf/wAAEA8f/1AAUASP/uAFn/6gG6//ABu//tAb3/8AABAPH/9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAxf/qAOj/uADx/+IBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGm/+0BvP/1AAkAxf/qAOj/uADx/+IBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABpv/tAbz/9QAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAab/7QG8//UACQDF/+oA6P+4APH/4gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/iAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAEBpv/rAAEBpv/rACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGm/6sBqP/NAaz/ywG0/8sBtf/LAbj/8wG7//MBvP/vAdz/wAHf/+4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAab/qwGo/80BrP/LAbT/ywG1/8sBuP/zAbv/8wG8/+8B3P/AAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBpv+rAaj/zQGs/8sBtP/LAbX/ywG4//MBu//zAbz/7wHc/8AB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABQAWf/BALP/xQDF/7QA5f/XAPH/uQD5/+kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAaj/6AGs/+YBtP/nAbX/5wAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAOwBU/78AWf/RAGv/bAB6/24Af/9DAIT/rACH/6EAs/+4ALr/fgC+/3sAwf+bAML/eQDF/7IAx/9+AMj/fQDJ/3wA1P+vAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD5/7IA+v+AAPz/eQD9ACgBAv99AQT/fwEX/2YBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGm/68BqP+5Aaz/uQG0/7kBtf+5Abf/vAG4//EBu//xAbz/7QHc/7MB3//xABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAaj/6QGs/+cBtP/nAbX/6QHf//AAAQEX//EAMgBU/34AWf+dAGv+8QB6/vQAf/6rAIT/XgCH/0sAs/9yALr/DwC+/woAwf9BAML/BwDF/2gAx/8PAMj/DgDJ/wwA1P9jAOEABQDl/70A5v9JAOj+/gDq/xMA8f9oAPj/DgD5/2gA+v8TAPz/BwD9ADABAv8OAQT/EQEX/ucBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/2oB3//TAAIA6P9oARf/7gAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGo/+kBrP/nAbT/5wG1/+kB3//wAAEBF//xAAEA8f/WAAoA4f/DAPH/zwD5/9QBL//OATj/5wE7/98BSf/RAUv/7AFT/6ABVP/RADIAVP9+AFn/nQBr/vEAev70AH/+qwCE/14Ah/9LALP/cgC6/w8Avv8KAMH/QQDC/wcAxf9oAMf/DwDI/w4Ayf8MANT/YwDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+f9oAPr/EwD8/wcA/QAwAQL/DgEE/xEBF/7nARv/rAEn/xUBKf88AS3/DgEv/2oBM/9JATn/DAE7/z8BPP7xAUH/wAFG/u8BSv8xAUz/XwFQ/woBUwAFAVT/MAFV/9UB3P9qAd//0wAUAFn/wQCz/8UAxf+0AOX/1wDx/7kA+f/pAQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGo/+gBrP/mAbT/5wG1/+cACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBpv+rAaj/zQGs/8sBtP/LAbX/ywG4//MBu//zAbz/7wHc/8AB3//uAAE1wAAEAAAABgAWAGwDngQcBIYEyAAVADgAFAA5ACYAOwAWARQAFAILABYCkgAmApQAFgKWABYC/QAWAwwAFgMPABYDRQAmA0cAJgNJACYDSwAWA2AAFANoABYD6gAWA+wAFgPuABYEEwAWAMwADv7uABD+7gAj/0AALP8wADYAFABD/94ARf/rAEb/6wBH/+sASf/rAFH/6wBT/+sAV//qAFj/6ABb/+gAkf/rAJX/6wCX/+oArf9AAK//QAC2/+sAuP/oAMP/6wDE/+sAxv/qAM0AFADRABQA8v/rAP7/6wEI/0ABE//rARX/6AEZ/+sBHf/rAS4AFAE1/+sBNgAUAUf/6wFI/+sBUv/rAWf+7gFr/u4Bb/7uAXD+7gHx/0AB8v9AAfP/QAH0/0AB9f9AAfb/QAH3/0ACDP/eAg3/3gIO/94CD//eAhD/3gIR/94CEv/eAhP/6wIU/+sCFf/rAhb/6wIX/+sCHf/rAh7/6wIf/+sCIP/rAiH/6wIi/+oCI//qAiT/6gIl/+oCJv/oAif/6AIo/0ACKf/eAir/QAIr/94CLP9AAi3/3gIv/+sCMf/rAjP/6wI1/+sCN//rAjn/6wI7/+sCPf/rAj//6wJB/+sCQ//rAkX/6wJH/+sCSf/rAlf/MAJr/+sCbf/rAm//6wKAABQCggAUAoQAFAKH/+oCif/qAov/6gKN/+oCj//qApH/6gKV/+gC+P9AAwD/QAMQ/+sDFP/qAxb/6wMY/+gDG//qAxz/6wMd/+oDJP8wAyj/QAMzABQDNf/eAzb/6wM4/+sDOv/rAzv/6AM9/+sDRP/oA0z/6ANV/0ADVv/eA1z/6wNh/+gDYv/rA2f/6wNp/+gDbv9AA2//3gNw/0ADcf/eA3X/6wN3/+sDeP/rA4L/6wOE/+sDhv/rA4r/6AOM/+gDjv/oA5X/6wOY/0ADmf/eA5r/QAOb/94DnP9AA53/3gOe/0ADn//eA6D/QAOh/94Dov9AA6P/3gOk/0ADpf/eA6b/QAOn/94DqP9AA6n/3gOq/0ADq//eA6z/QAOt/94Drv9AA6//3gOx/+sDs//rA7X/6wO3/+sDuf/rA7v/6wO9/+sDv//rA8X/6wPH/+sDyf/rA8v/6wPN/+sDz//rA9H/6wPT/+sD1f/rA9f/6wPZ/+sD2//rA93/6gPf/+oD4f/qA+P/6gPl/+oD5//qA+n/6gPr/+gD7f/oA+//6AP2ABQAHwA2/98AOP/kADn/7AA7/90Azf/fANH/3wEU/+QBLv/fATb/3wIL/90CgP/fAoL/3wKE/98Ckv/sApT/3QKW/90C/f/dAwz/3QMP/90DM//fA0X/7ANH/+wDSf/sA0v/3QNg/+QDaP/dA+r/3QPs/90D7v/dA/b/3wQT/90AGgA2/84AOP/tADv/0ADN/84A0f/OART/7QEu/84BNv/OAgv/0AKA/84Cgv/OAoT/zgKU/9AClv/QAv3/0AMM/9ADD//QAzP/zgNL/9ADYP/tA2j/0APq/9AD7P/QA+7/0AP2/84EE//QABAALP/uADf/7gIH/+4CCP/uAgn/7gIK/+4CV//uAob/7gKI/+4Civ/uAoz/7gKO/+4CkP/uAyT/7gPc/+4D3v/uAD0ARf/oAEb/6ABH/+gASf/oAFP/6ACR/+gAlf/oALb/6ADD/+gAxP/oAPL/6AD+/+gBGf/oAR3/6AE1/+gBR//oAUj/6AFS/+gCE//oAhT/6AIV/+gCFv/oAhf/6AIv/+gCMf/oAjP/6AI1/+gCN//oAjn/6AI7/+gCPf/oAj//6AJB/+gCQ//oAkX/6AJH/+gCSf/oAxD/6AM2/+gDOv/oAz3/6ANc/+gDYv/oA2f/6AN1/+gDd//oA3j/6AOE/+gDlf/oA7H/6AOz/+gDtf/oA7f/6AO5/+gDu//oA73/6AO//+gD0//oA9X/6APX/+gD2//oAAEwEgAEAAAALABiAIwBggHgAfoCPAKyA5gEfgVYBfIIjApSC2ANJg1YDYoOCA9OENgSbhOAFO4XABe2GRwZ0hqMGxIbcBwuHKQdUh18Hs4hDCEuIkQioiMgI0ojfCOOI7gACgAEABAACQAQAWUAEAFmABABaAAQAWkAEAFqABADTQAQA04AEANSABAAPQBF/+wARv/sAEf/7ABJ/+wAU//sAJH/7ACV/+wAtv/sAMP/7ADE/+wA8v/sAP7/7AEZ/+wBHf/sATX/7AFH/+wBSP/sAVL/7AIT/+wCFP/sAhX/7AIW/+wCF//sAi//7AIx/+wCM//sAjX/7AI3/+wCOf/sAjv/7AI9/+wCP//sAkH/7AJD/+wCRf/sAkf/7AJJ/+wDEP/sAzb/7AM6/+wDPf/sA1z/7ANi/+wDZ//sA3X/7AN3/+wDeP/sA4T/7AOV/+wDsf/sA7P/7AO1/+wDt//sA7n/7AO7/+wDvf/sA7//7APT/+wD1f/sA9f/7APb/+wAFwBR/+IBE//iAh3/4gIe/+ICH//iAiD/4gIh/+ICa//iAm3/4gJv/+IDFv/iAxz/4gM4/+IDgv/iA4b/4gPF/+IDx//iA8n/4gPL/+IDzf/iA8//4gPR/+ID2f/iAAYADv+EABD/hAFn/4QBa/+EAW//hAFw/4QAEAAs/+wAN//sAgf/7AII/+wCCf/sAgr/7AJX/+wChv/sAoj/7AKK/+wCjP/sAo7/7AKQ/+wDJP/sA9z/7APe/+wAHQAE//IACf/yAFj/8wBb//MAuP/zARX/8wFl//IBZv/yAWj/8gFp//IBav/yAib/8wIn//MClf/zAxj/8wM7//MDRP/zA0z/8wNN//IDTv/yA1L/8gNh//MDaf/zA4r/8wOM//MDjv/zA+v/8wPt//MD7//zADkAJf/zACn/8wAx//MAM//zAIH/8wCQ//MAlP/zAK7/8wDO//MBA//zARL/8wEW//MBGP/zARr/8wEc//MBNP/zAVH/8wH4//MCAv/zAgP/8wIE//MCBf/zAgb/8wIu//MCMP/zAjL/8wI0//MCQv/zAkT/8wJG//MCSP/zAmr/8wJs//MCbv/zAp//8wL8//MDCf/zAy//8wMy//MDV//zA2P/8wNm//MDgf/zA4P/8wOF//MDxP/zA8b/8wPI//MDyv/zA8z/8wPO//MD0P/zA9L/8wPU//MD1v/zA9j/8wPa//MAOQAl/+YAKf/mADH/5gAz/+YAgf/mAJD/5gCU/+YArv/mAM7/5gED/+YBEv/mARb/5gEY/+YBGv/mARz/5gE0/+YBUf/mAfj/5gIC/+YCA//mAgT/5gIF/+YCBv/mAi7/5gIw/+YCMv/mAjT/5gJC/+YCRP/mAkb/5gJI/+YCav/mAmz/5gJu/+YCn//mAvz/5gMJ/+YDL//mAzL/5gNX/+YDY//mA2b/5gOB/+YDg//mA4X/5gPE/+YDxv/mA8j/5gPK/+YDzP/mA87/5gPQ/+YD0v/mA9T/5gPW/+YD2P/mA9r/5gA2ACP/5AA6/9IAO//TAK3/5ACv/+QA1f/SAQj/5AHx/+QB8v/kAfP/5AH0/+QB9f/kAfb/5AH3/+QCC//TAij/5AIq/+QCLP/kApT/0wKW/9MC+P/kAv3/0wMA/+QDDP/TAw3/0gMP/9MDKP/kAzT/0gNL/9MDVf/kA2j/0wNr/9IDbv/kA3D/5AN5/9IDk//SA5j/5AOa/+QDnP/kA57/5AOg/+QDov/kA6T/5AOm/+QDqP/kA6r/5AOs/+QDrv/kA+r/0wPs/9MD7v/TA/j/0gQA/9IEE//TACYADv9GABD/RgAj/80Arf/NAK//zQEI/80BZ/9GAWv/RgFv/0YBcP9GAfH/zQHy/80B8//NAfT/zQH1/80B9v/NAff/zQIo/80CKv/NAiz/zQL4/80DAP/NAyj/zQNV/80Dbv/NA3D/zQOY/80Dmv/NA5z/zQOe/80DoP/NA6L/zQOk/80Dpv/NA6j/zQOq/80DrP/NA67/zQCmAEX/3ABG/9wAR//cAEn/3ABP/8EAUP/BAFH/1gBS/8EAU//cAFf/3QBY/+EAW//hAJH/3ACV/9wAl//dALb/3AC4/+EAvP/BAMP/3ADE/9wAxv/dAOf/wQDr/8EA7P/BAO7/wQDv/8EA8P/BAPL/3ADz/8EA9f/BAPb/wQD5/8EA+//BAP7/3AEA/8EBE//WARX/4QEZ/9wBHf/cATH/wQE1/9wBQP/BAUX/wQFH/9wBSP/cAVL/3AIT/9wCFP/cAhX/3AIW/9wCF//cAhz/wQId/9YCHv/WAh//1gIg/9YCIf/WAiL/3QIj/90CJP/dAiX/3QIm/+ECJ//hAi//3AIx/9wCM//cAjX/3AI3/9wCOf/cAjv/3AI9/9wCP//cAkH/3AJD/9wCRf/cAkf/3AJJ/9wCZP/BAmb/wQJo/8ECaf/BAmv/1gJt/9YCb//WAof/3QKJ/90Ci//dAo3/3QKP/90Ckf/dApX/4QMQ/9wDEv/BAxT/3QMW/9YDGP/hAxv/3QMc/9YDHf/dAzb/3AM3/8EDOP/WAzn/wQM6/9wDO//hAz3/3AM+/8EDQ//BA0T/4QNM/+EDVP/BA1z/3ANd/8EDYf/hA2L/3ANn/9wDaf/hA3X/3AN3/9wDeP/cA37/wQOA/8EDgv/WA4T/3AOG/9YDiv/hA4z/4QOO/+EDkv/BA5X/3AOx/9wDs//cA7X/3AO3/9wDuf/cA7v/3AO9/9wDv//cA8X/1gPH/9YDyf/WA8v/1gPN/9YDz//WA9H/1gPT/9wD1f/cA9f/3APZ/9YD2//cA93/3QPf/90D4f/dA+P/3QPl/90D5//dA+n/3QPr/+ED7f/hA+//4QPz/8ED9f/BA///wQQM/8EEDv/BBBD/wQBxAAT/2gAJ/9oARf/wAEb/8ABH//AASf/wAFP/8ABX/+8AWP/cAFv/3ACR//AAlf/wAJf/7wC2//AAuP/cAMP/8ADE//AAxv/vAPL/8AD+//ABFf/cARn/8AEd//ABNf/wAUf/8AFI//ABUv/wAWX/2gFm/9oBaP/aAWn/2gFq/9oCE//wAhT/8AIV//ACFv/wAhf/8AIi/+8CI//vAiT/7wIl/+8CJv/cAif/3AIv//ACMf/wAjP/8AI1//ACN//wAjn/8AI7//ACPf/wAj//8AJB//ACQ//wAkX/8AJH//ACSf/wAof/7wKJ/+8Ci//vAo3/7wKP/+8Ckf/vApX/3AMQ//ADFP/vAxj/3AMb/+8DHf/vAzb/8AM6//ADO//cAz3/8ANE/9wDTP/cA03/2gNO/9oDUv/aA1z/8ANh/9wDYv/wA2f/8ANp/9wDdf/wA3f/8AN4//ADhP/wA4r/3AOM/9wDjv/cA5X/8AOx//ADs//wA7X/8AO3//ADuf/wA7v/8AO9//ADv//wA9P/8APV//AD1//wA9v/8APd/+8D3//vA+H/7wPj/+8D5f/vA+f/7wPp/+8D6//cA+3/3APv/9wAQwAOAAwAEAAMAEX/5wBG/+cAR//nAEn/5wBT/+cAkf/nAJX/5wC2/+cAw//nAMT/5wDy/+cA/v/nARn/5wEd/+cBNf/nAUf/5wFI/+cBUv/nAWcADAFrAAwBbwAMAXAADAIT/+cCFP/nAhX/5wIW/+cCF//nAi//5wIx/+cCM//nAjX/5wI3/+cCOf/nAjv/5wI9/+cCP//nAkH/5wJD/+cCRf/nAkf/5wJJ/+cDEP/nAzb/5wM6/+cDPf/nA1z/5wNi/+cDZ//nA3X/5wN3/+cDeP/nA4T/5wOV/+cDsf/nA7P/5wO1/+cDt//nA7n/5wO7/+cDvf/nA7//5wPT/+cD1f/nA9f/5wPb/+cAcQAEAAwACQAMAEX/6ABG/+gAR//oAEn/6ABR/+oAU//oAFgACwBbAAsAkf/oAJX/6AC2/+gAuAALAMP/6ADE/+gA8v/oAP7/6AET/+oBFQALARn/6AEd/+gBNf/oAUf/6AFI/+gBUv/oAWUADAFmAAwBaAAMAWkADAFqAAwCE//oAhT/6AIV/+gCFv/oAhf/6AId/+oCHv/qAh//6gIg/+oCIf/qAiYACwInAAsCL//oAjH/6AIz/+gCNf/oAjf/6AI5/+gCO//oAj3/6AI//+gCQf/oAkP/6AJF/+gCR//oAkn/6AJr/+oCbf/qAm//6gKVAAsDEP/oAxb/6gMYAAsDHP/qAzb/6AM4/+oDOv/oAzsACwM9/+gDRAALA0wACwNNAAwDTgAMA1IADANc/+gDYQALA2L/6ANn/+gDaQALA3X/6AN3/+gDeP/oA4L/6gOE/+gDhv/qA4oACwOMAAsDjgALA5X/6AOx/+gDs//oA7X/6AO3/+gDuf/oA7v/6AO9/+gDv//oA8X/6gPH/+oDyf/qA8v/6gPN/+oDz//qA9H/6gPT/+gD1f/oA9f/6APZ/+oD2//oA+sACwPtAAsD7wALAAwAWv/tAFz/7QDp/+0CmP/tApr/7QKc/+0DPP/tA2z/7QN6/+0DlP/tA/n/7QQB/+0ADABa//IAXP/yAOn/8gKY//ICmv/yApz/8gM8//IDbP/yA3r/8gOU//ID+f/yBAH/8gAfAFj/9ABa//IAW//0AFz/8wC4//QA6f/yARX/9AIm//QCJ//0ApX/9AKY//MCmv/zApz/8wMY//QDO//0Azz/8gNE//QDTP/0A2H/9ANp//QDbP/yA3r/8gOK//QDjP/0A47/9AOU//ID6//0A+3/9APv//QD+f/yBAH/8gBRAAT/ygAJ/8oANv/SADj/1AA6//QAO//TAFj/5gBa/+8AW//mALj/5gDN/9IA0f/SANX/9ADZ/+0A3P/hAOn/7wEU/9QBFf/mAS7/0gE2/9IBZf/KAWb/ygFo/8oBaf/KAWr/ygIL/9MCJv/mAif/5gKA/9ICgv/SAoT/0gKU/9MClf/mApb/0wL9/9MDDP/TAw3/9AMP/9MDGP/mAyf/7QMz/9IDNP/0Azv/5gM8/+8DRP/mA0v/0wNM/+YDTf/KA07/ygNS/8oDYP/UA2H/5gNo/9MDaf/mA2v/9ANs/+8Def/0A3r/7wOJ/+0Div/mA4v/7QOM/+YDjf/tA47/5gOP/+EDk//0A5T/7wPq/9MD6//mA+z/0wPt/+YD7v/TA+//5gP2/9ID+P/0A/n/7wP6/+ED/P/hBAD/9AQB/+8EE//TAGIABP/AAAn/wAA2/50AOP/HADr/8AA7/6sAT//SAFD/0gBS/9IAvP/SAM3/nQDP//UA0f+dANX/8ADY//UA2f/qANz/5QDn/9IA6//SAOz/0gDu/9IA7//SAPD/0gDz/9IA9f/SAPb/0gD7/9IBAP/SART/xwEu/50BMf/SATb/nQFA/9IBRf/SAU3/9QFl/8ABZv/AAWj/wAFp/8ABav/AAgv/qwIc/9ICZP/SAmb/0gJo/9ICaf/SAoD/nQKC/50ChP+dApT/qwKW/6sC/f+rAwz/qwMN//ADD/+rAxL/0gMn/+oDM/+dAzT/8AM3/9IDOf/SAz7/0gND/9IDS/+rA03/wANO/8ADUv/AA1T/0gNd/9IDYP/HA2j/qwNr//ADef/wA37/0gOA/9IDif/qA4v/6gON/+oDj//lA5L/0gOT//ADlv/1A+r/qwPs/6sD7v+rA/P/0gP1/9ID9v+dA/j/8AP6/+UD/P/lA///0gQA//AEDP/SBA7/0gQQ/9IEEf/1BBP/qwBlAAT/sQAJ/7EANv+eADj/xQA6//IAO/+oAE//zwBQ/88AUv/PAFr/7wC8/88Azf+eANH/ngDV//IA2f/sANz/4QDn/88A6f/vAOv/zwDs/88A7v/PAO//zwDw/88A8//PAPX/zwD2/88A+//PAQD/zwEU/8UBLv+eATH/zwE2/54BQP/PAUX/zwFl/7EBZv+xAWj/sQFp/7EBav+xAgv/qAIc/88CZP/PAmb/zwJo/88Caf/PAoD/ngKC/54ChP+eApT/qAKW/6gC/f+oAwz/qAMN//IDD/+oAxL/zwMn/+wDM/+eAzT/8gM3/88DOf/PAzz/7wM+/88DQ//PA0v/qANN/7EDTv+xA1L/sQNU/88DXf/PA2D/xQNo/6gDa//yA2z/7wN5//IDev/vA37/zwOA/88Dif/sA4v/7AON/+wDj//hA5L/zwOT//IDlP/vA+r/qAPs/6gD7v+oA/P/zwP1/88D9v+eA/j/8gP5/+8D+v/hA/z/4QP//88EAP/yBAH/7wQM/88EDv/PBBD/zwQT/6gARAA2/74AT//hAFD/4QBS/+EAWP/vAFv/7wC4/+8AvP/hAM3/vgDR/74A5//hAOv/4QDs/+EA7v/hAO//4QDw/+EA8//hAPX/4QD2/+EA+//hAQD/4QEV/+8BLv++ATH/4QE2/74BQP/hAUX/4QIc/+ECJv/vAif/7wJk/+ECZv/hAmj/4QJp/+ECgP++AoL/vgKE/74Clf/vAxL/4QMY/+8DM/++Azf/4QM5/+EDO//vAz7/4QND/+EDRP/vA0z/7wNU/+EDXf/hA2H/7wNp/+8Dfv/hA4D/4QOK/+8DjP/vA47/7wOS/+ED6//vA+3/7wPv/+8D8//hA/X/4QP2/74D///hBAz/4QQO/+EEEP/hAFsANv/mADj/5wA6//IAO//nAE//1gBQ/9YAUv/WAFr/8QC8/9YAzf/mANH/5gDV//IA2f/uANz/6ADn/9YA6f/xAOv/1gDs/9YA7v/WAO//1gDw/9YA8//WAPX/1gD2/9YA+//WAQD/1gEU/+cBLv/mATH/1gE2/+YBQP/WAUX/1gIL/+cCHP/WAmT/1gJm/9YCaP/WAmn/1gKA/+YCgv/mAoT/5gKU/+cClv/nAv3/5wMM/+cDDf/yAw//5wMS/9YDJ//uAzP/5gM0//IDN//WAzn/1gM8//EDPv/WA0P/1gNL/+cDVP/WA13/1gNg/+cDaP/nA2v/8gNs//EDef/yA3r/8QN+/9YDgP/WA4n/7gOL/+4Djf/uA4//6AOS/9YDk//yA5T/8QPq/+cD7P/nA+7/5wPz/9YD9f/WA/b/5gP4//ID+f/xA/r/6AP8/+gD///WBAD/8gQB//EEDP/WBA7/1gQQ/9YEE//nAIQAIwAQACX/6AAp/+gAMf/oADP/6AA2/+AAOP/gADv/3wCB/+gAkP/oAJT/6ACtABAArv/oAK8AEADN/+AAzv/oAM8AEADR/+AA2AAQANz/4QDtABAA9P/gAP8AEAED/+gBCAAQARL/6AEU/+ABFv/oARj/6AEa/+gBHP/oAS7/4AE0/+gBNv/gAU0AEAFR/+gB8QAQAfIAEAHzABAB9AAQAfUAEAH2ABAB9wAQAfj/6AIC/+gCA//oAgT/6AIF/+gCBv/oAgv/3wIoABACKgAQAiwAEAIu/+gCMP/oAjL/6AI0/+gCQv/oAkT/6AJG/+gCSP/oAmr/6AJs/+gCbv/oAoD/4AKC/+AChP/gApT/3wKW/98Cn//oAvgAEAL8/+gC/f/fAwAAEAMJ/+gDDP/fAw//3wMoABADL//oAzL/6AMz/+ADS//fA1UAEANX/+gDYP/gA2P/6ANm/+gDaP/fA24AEANwABADgf/oA4P/6AOF/+gDj//hA5D/4AOWABADlwAQA5gAEAOaABADnAAQA54AEAOgABADogAQA6QAEAOmABADqAAQA6oAEAOsABADrgAQA8T/6APG/+gDyP/oA8r/6APM/+gDzv/oA9D/6APS/+gD1P/oA9b/6APY/+gD2v/oA+r/3wPs/98D7v/fA/b/4AP6/+ED+//gA/z/4QP9/+AEEQAQBBIAEAQT/98ALQA2//EAOP/0ADr/9AA7//AAzf/xAM//9QDR//EA1f/0ANj/9QDZ//MBFP/0AS7/8QE2//EBTf/1Agv/8AKA//ECgv/xAoT/8QKU//AClv/wAv3/8AMM//ADDf/0Aw//8AMn//MDM//xAzT/9ANL//ADYP/0A2j/8ANr//QDef/0A4n/8wOL//MDjf/zA5P/9AOW//UD6v/wA+z/8APu//AD9v/xA/j/9AQA//QEEf/1BBP/8ABZACMADwA2/+YAOP/mADoADgA7/+YArQAPAK8ADwDN/+YAzwAOANH/5gDVAA4A2AAOANkACwDc/+UA7QAPAPT/6AD/AA8BCAAPART/5gEu/+YBNv/mAU0ADgHxAA8B8gAPAfMADwH0AA8B9QAPAfYADwH3AA8CC//mAigADwIqAA8CLAAPAoD/5gKC/+YChP/mApT/5gKW/+YC+AAPAv3/5gMAAA8DDP/mAw0ADgMP/+YDJwALAygADwMz/+YDNAAOA0v/5gNVAA8DYP/mA2j/5gNrAA4DbgAPA3AADwN5AA4DiQALA4sACwONAAsDj//lA5D/6AOTAA4DlgAOA5cADwOYAA8DmgAPA5wADwOeAA8DoAAPA6IADwOkAA8DpgAPA6gADwOqAA8DrAAPA64ADwPq/+YD7P/mA+7/5gP2/+YD+AAOA/r/5QP7/+gD/P/lA/3/6AQAAA4EEQAOBBIADwQT/+YALQAE/78ACf+/ADb/nwA4/8kAO/+tAM3/nwDR/58A2f/sANz/5gEU/8kBLv+fATb/nwFl/78BZv+/AWj/vwFp/78Bav+/Agv/rQKA/58Cgv+fAoT/nwKU/60Clv+tAv3/rQMM/60DD/+tAyf/7AMz/58DS/+tA03/vwNO/78DUv+/A2D/yQNo/60Dif/sA4v/7AON/+wDj//mA+r/rQPs/60D7v+tA/b/nwP6/+YD/P/mBBP/rQAuADb/4wA6/+UAO//kAM3/4wDP/+UA0f/jANX/5QDY/+UA2f/pAO3/6gD//+oBLv/jATb/4wFN/+UCC//kAoD/4wKC/+MChP/jApT/5AKW/+QC/f/kAwz/5AMN/+UDD//kAyf/6QMz/+MDNP/lA0v/5ANo/+QDa//lA3n/5QOJ/+kDi//pA43/6QOT/+UDlv/lA5f/6gPq/+QD7P/kA+7/5AP2/+MD+P/lBAD/5QQR/+UEEv/qBBP/5AAhADb/4gA6/+QAzf/iAM//5ADR/+IA1f/kANj/5ADZ/+kA7f/rAP//6wEu/+IBNv/iAU3/5AKA/+ICgv/iAoT/4gMN/+QDJ//pAzP/4gM0/+QDa//kA3n/5AOJ/+kDi//pA43/6QOT/+QDlv/kA5f/6wP2/+ID+P/kBAD/5AQR/+QEEv/rABcANv/rADv/8wDN/+sA0f/rAS7/6wE2/+sCC//zAoD/6wKC/+sChP/rApT/8wKW//MC/f/zAwz/8wMP//MDM//rA0v/8wNo//MD6v/zA+z/8wPu//MD9v/rBBP/8wAvAE//7wBQ/+8AUv/vAFr/8AC8/+8A5//vAOn/8ADr/+8A7P/vAO7/7wDv/+8A8P/vAPP/7wD1/+8A9v/vAPv/7wEA/+8BMf/vAUD/7wFF/+8CHP/vAmT/7wJm/+8CaP/vAmn/7wMS/+8DN//vAzn/7wM8//ADPv/vA0P/7wNU/+8DXf/vA2z/8AN6//ADfv/vA4D/7wOS/+8DlP/wA/P/7wP1/+8D+f/wA///7wQB//AEDP/vBA7/7wQQ/+8AHQAE//IACf/yAFj/9QBb//UAuP/1ARX/9QFl//IBZv/yAWj/8gFp//IBav/yAib/9QIn//UClf/1Axj/9QM7//UDRP/1A0z/9QNN//IDTv/yA1L/8gNh//UDaf/1A4r/9QOM//UDjv/1A+v/9QPt//UD7//1ACsAT//uAFD/7gBS/+4AvP/uAOf/7gDr/+4A7P/uAO7/7gDv/+4A8P/uAPP/7gD0/+0A9f/uAPb/7gD7/+4BAP/uATH/7gFA/+4BRf/uAhz/7gJk/+4CZv/uAmj/7gJp/+4DEv/uAzf/7gM5/+4DPv/uA0P/7gNU/+4DXf/uA37/7gOA/+4DkP/tA5L/7gPz/+4D9f/uA/v/7QP9/+0D///uBAz/7gQO/+4EEP/uAAoABP/1AAn/9QFl//UBZv/1AWj/9QFp//UBav/1A03/9QNO//UDUv/1AFQARf/wAEb/8ABH//AASf/wAFH/xwBT//AAkf/wAJX/8AC2//AAw//wAMT/8ADy//AA/v/wARP/xwEZ//ABHf/wATX/8AFH//ABSP/wAVL/8AIT//ACFP/wAhX/8AIW//ACF//wAh3/xwIe/8cCH//HAiD/xwIh/8cCL//wAjH/8AIz//ACNf/wAjf/8AI5//ACO//wAj3/8AI///ACQf/wAkP/8AJF//ACR//wAkn/8AJr/8cCbf/HAm//xwMQ//ADFv/HAxz/xwM2//ADOP/HAzr/8AM9//ADXP/wA2L/8ANn//ADdf/wA3f/8AN4//ADgv/HA4T/8AOG/8cDlf/wA7H/8AOz//ADtf/wA7f/8AO5//ADu//wA73/8AO///ADxf/HA8f/xwPJ/8cDy//HA83/xwPP/8cD0f/HA9P/8APV//AD1//wA9n/xwPb//AAjwAEAA0ACQANAEP/8ABF/8AARv/AAEf/wABJ/8AAUf/iAFP/wABYAAsAWwALAJH/wACV/8AAtv/AALgACwDE/8AA7f/XAPL/wAD+/8AA///XARP/4gEVAAsBGf/AAR3/wAE1/8ABR//AAUj/wAFS/8ABZQANAWYADQFoAA0BaQANAWoADQIM//ACDf/wAg7/8AIP//ACEP/wAhH/8AIS//ACE//AAhT/wAIV/8ACFv/AAhf/wAId/+ICHv/iAh//4gIg/+ICIf/iAiYACwInAAsCKf/wAiv/8AIt//ACL//AAjH/wAIz/8ACNf/AAjf/wAI5/8ACO//AAj3/wAI//8ACQf/AAkP/wAJF/8ACR//AAkn/wAJr/+ICbf/iAm//4gKVAAsDEP/AAxb/4gMYAAsDHP/iAzX/8AM2/8ADOP/iAzr/wAM7AAsDPf/AA0QACwNMAAsDTQANA04ADQNSAA0DVv/wA1z/wANhAAsDYv/AA2f/wANpAAsDb//wA3H/8AN1/8ADd//AA3j/wAOC/+IDhP/AA4b/4gOKAAsDjAALA44ACwOV/8ADl//XA5n/8AOb//ADnf/wA5//8AOh//ADo//wA6X/8AOn//ADqf/wA6v/8AOt//ADr//wA7H/wAOz/8ADtf/AA7f/wAO5/8ADu//AA73/wAO//8ADxf/iA8f/4gPJ/+IDy//iA83/4gPP/+ID0f/iA9P/wAPV/8AD1//AA9n/4gPb/8AD6wALA+0ACwPvAAsEEv/XAAgA7QAQAPT/8AD/ABADkP/wA5cAEAP7//AD/f/wBBIAEABFAEX/7gBG/+4AR//uAEn/7gBT/+4Akf/uAJX/7gC2/+4Aw//uAMT/7gDtAA4A8v/uAPT/4wD+/+4A/wAOARn/7gEd/+4BNf/uAUf/7gFI/+4BUv/uAhP/7gIU/+4CFf/uAhb/7gIX/+4CL//uAjH/7gIz/+4CNf/uAjf/7gI5/+4CO//uAj3/7gI//+4CQf/uAkP/7gJF/+4CR//uAkn/7gMQ/+4DNv/uAzr/7gM9/+4DXP/uA2L/7gNn/+4Ddf/uA3f/7gN4/+4DhP/uA5D/4wOV/+4DlwAOA7H/7gOz/+4Dtf/uA7f/7gO5/+4Du//uA73/7gO//+4D0//uA9X/7gPX/+4D2//uA/v/4wP9/+MEEgAOABcAWP/AAFv/wAC4/8AA9P/uARX/wAIm/8ACJ//AApX/wAMY/8ADO//AA0T/wANM/8ADYf/AA2n/wAOK/8ADjP/AA47/wAOQ/+4D6//AA+3/wAPv/8AD+//uA/3/7gAfAFj/9ABa//AAW//0ALj/9ADp//AA7f/zAP//8wEV//QCJv/0Aif/9AKV//QDGP/0Azv/9AM8//ADRP/0A0z/9ANh//QDaf/0A2z/8AN6//ADiv/0A4z/9AOO//QDlP/wA5f/8wPr//QD7f/0A+//9AP5//AEAf/wBBL/8wAKAAT/1gAJ/9YBZf/WAWb/1gFo/9YBaf/WAWr/1gNN/9YDTv/WA1L/1gAMAFr/4ADp/+AA9P/CAzz/4ANs/+ADev/gA5D/wgOU/+AD+f/gA/v/wgP9/8IEAf/gAAQA9P/SA5D/0gP7/9ID/f/SAAoABP/XAAn/1wFl/9cBZv/XAWj/1wFp/9cBav/XA03/1wNO/9cDUv/XAF4ABAALAAkACwBF/+sARv/rAEf/6wBJ/+sAUf/pAFP/6wCR/+sAlf/rALb/6wDD/+sAxP/rAPL/6wD+/+sBE//pARn/6wEd/+sBNf/rAUf/6wFI/+sBUv/rAWUACwFmAAsBaAALAWkACwFqAAsCE//rAhT/6wIV/+sCFv/rAhf/6wId/+kCHv/pAh//6QIg/+kCIf/pAi//6wIx/+sCM//rAjX/6wI3/+sCOf/rAjv/6wI9/+sCP//rAkH/6wJD/+sCRf/rAkf/6wJJ/+sCa//pAm3/6QJv/+kDEP/rAxb/6QMc/+kDNv/rAzj/6QM6/+sDPf/rA00ACwNOAAsDUgALA1z/6wNi/+sDZ//rA3X/6wN3/+sDeP/rA4L/6QOE/+sDhv/pA5X/6wOx/+sDs//rA7X/6wO3/+sDuf/rA7v/6wO9/+sDv//rA8X/6QPH/+kDyf/pA8v/6QPN/+kDz//pA9H/6QPT/+sD1f/rA9f/6wPZ/+kD2//rAAILPAAEAAAOBBVYACEAHQAAAAwAEf/f//T/zv/1/7P/7//Q/2r/iP+n//X/yf/ZABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/oAAAAAP/JAAD/5QAAAAAAAAAA//MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR/+UAAAAAAAAAAAAAAAD/5AAA/+MAAP/kAAAAEQAAABIAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4QAAAAAAAAAA/+oAAAAA/9UAAP/lAAAAAAAAAAAAAP/r/+r/6f+GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7f/mAAAAAAAAAAAAAAAAABT/7wAAAAAAAAAAAAAAAAAAAAD/7QAAAAAAAAAAAAAAAAAA/8T/y/98/7H/rv/kABAAAP+nABAAAAAQ/78AAAAP/34AAP+TAAAAAP7+/6f/s/+0/vD/8P+t/ygAAP+G/5L/DP9m/2H/vQAHAAD/VQAHAAAAB/9+AAAABf8PAAD/MwAAAAD+Nv9V/2r/a/4e/9H/XwAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/2AAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAP+j/+X/2P/hAAAAAAAAAAAAAAAA/+kAAAAAAAAAAAAAAAAAAAAA/+YAAAAA/1wAAAAAAAAAAAAAAAAAAAAA/4X/5/8y/+gAAP7p/v7/M//yAAD/owAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9vAAD/8wAPAAAAAAAAAAAAAAAAAAAAAAAAAAD/pwAA/07/zf/c/mz/8wAAAAAAAAAA//X/SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/qAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/S//X/8wAAAAAAAAAAAAAAAP/kAAAAAAAAAAD/tQAAAAD/Kf/UAAAAAP9jAAD/0gAAAAAAAAAR/9H/6//h/+cADgAAAAAAAAAAAAD/6wAAAAAAEQAAAAAAAAAAAAD/5gAAAAD/ZAAAAAAAAAAA/+IAAAAA/7//7P/jABL/oP/YABIAAAAR/9kAAAARAAAAAP9qAA0AAP8Z/7//6f/G/2j/8P/B/6AAAAAAAAAAAP/hAAAAAAAAAAAAAAAAAAAADv/tAAAAAAAAAAD/1QAAAAD/cf/hAAAAAP/EAAD/3wAAAAAAAAAAAAD/6//l/+YAAAAAAAAAAAAAAAD/7QAAAAAAAAAAAA0AAAAAAAD/6wAAAAAAAAAAAAAAAAAAAAD/yv/p/70AAP/pAAAAAP+uABIAAAASAAAAAAAA/7sAAP+lAAAAAP53/70AAP/S/zkAAP+vAAAAAAAAAAAAAAAA//EAAAAAAAAAAAAA/+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//EAAAAAAAD/9QAAAAAAAAAAAAD/4wAAAAAAAAAA//IAAAAAAAAAAAAAAAD/8QAAAAAAAAAAAAAAAAAAAAAAAAAA//MAAAAAAAAAAAAA//IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAD/8QAAAAAAAAAAAAD/7AAAAAAAAAAA//AAAAAAAAAAAAAAAAD/6wAAAAAAAAAAAAAAAAAAAAAAAP/xAAAAAAAAAAAAAAAAAA8AAAAAAAAAAP/XAAAAAAAAAAD/Wf/zAAAAAAAAAAD/8QAAAAAAAAAAAAD/7AASAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAA/1P/7QAAAAAAAAAA/+wAAAAAAAAAAAAA/9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+wAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAD/pQAAAAAAAAAA/+wAAP/bAAAAAAAAAAAAAAAA/4gAAAAAAAD/xQAA/6QAAAAA/84AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/IAAAAAP+t/8D/nwAA/+cAAAAA/+sAAAAAAAAAAAAA/8kAAAAAAAAAAAAAAAAAAAAA/+MAAP+1AAAAAAAAAAAAAP95AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/rAAAAAAAAAAAAAAACAIsABAAEAAAACQAJAAEAEQARAAIAIwAoAAMAKgAzAAkANgA8ABMAQwBEABoARwBIABwASgBKAB4ATwBSAB8AVABUACMAWABYACQAWgBbACUAiACIACcAmQCZACgArACwACkAsgC0AC4AtgC2ADEAuAC4ADIAuwC8ADMAvgC+ADUAwADAADYAwgDHADcAzQDNAD0AzwDZAD4A2wDbAEkA3QDfAEoA4QDjAE0A5QDpAFAA7ADsAFUA8QDzAFYA9gD3AFkA+QD7AFsA/wEAAF4BBQEFAGABCAEIAGEBEwEVAGIBJwEpAGUBLAEsAGgBLgEuAGkBRQFFAGoBZQFmAGsBaAFqAG0BpgGmAHABqQGpAHEBqwGrAHIBsAGxAHMBtAG2AHUBuAG+AHgBxAHEAH8B1wHXAIAB2wHcAIEB3wHfAIMB6AHoAIQB7AHtAIUB7wHvAIcB8QISAIgCFAIXAKoCHAIhAK4CJgIuALQCMAIwAL0CMgIyAL4CNAI0AL8CNgI2AMACOAJBAMECSgJMAMsCTgJOAM4CUAJQAM8CUgJSANACVAJUANECVwJXANICWQJZANMCWwJbANQCXQJdANUCXwJfANYCYQJhANcCYwJvANgCcQJxAOUCcwJzAOYCdQJ1AOcCgAKAAOgCggKCAOkChAKEAOoChgKGAOsCiAKIAOwCigKKAO0CjAKMAO4CjgKOAO8CkAKQAPACkgKSAPEClAKXAPICmQKZAPYCmwKbAPcC+AL9APgDAAMPAP4DEgMSAQ4DFgMWAQ8DGAMYARADHAMcAREDHwMgARIDIgMrARQDLQMvAR4DMQM2ASEDOAM5AScDOwM+ASkDRANFAS0DRwNHAS8DSQNJATADSwNOATEDUgNXATUDWgNaATsDXANcATwDYANhAT0DZgNmAT8DaANxAUADdAN1AUoDdwN6AUwDgQOCAVADhgOGAVIDiAOOAVMDkwOUAVoDmAPAAVwDwgPCAYUDxAPRAYYD2QPZAZQD3APcAZUD3gPeAZYD6gPvAZcD8gPyAZ0D9AP0AZ4D9gP2AZ8D+AP5AaAD/gQBAaIEBAQEAaYEBgQHAacECQQJAakEDQQNAaoEDwQPAasEEwQTAawAAQAGAAoAKAAzADQAPQBIAAEALABIAE0AVgBZAF0AmQCwALIAswC0ALsAvgDAAMUAxwDIAMkAzQDPANAA0QDTANQA1gDeAN8A4gDjAOQA5QDmAOgA6gDsAPEA8wD2APcA+wD+AP8BAAEdAdwAAgB2AAQABAAAAAkACQABAA4ADgACABAAEAADACMAJwAEACoAMgAJADYAPAASAEMARQAZAEcARwAcAEoASgAdAE8AUgAeAFQAVAAiAFgAWAAjAFoAXAAkAIgAiAAnAKwArwAoALgAuAAsALwAvAAtAMIAwgAuAM8A0AAvANIA0gAxANUA1QAyANcA2QAzANsA2wA2AN0A3QA3AN8A3wA4AOEA4QA5AOcA5wA6AOkA6QA7APIA8gA8APcA9wA9APkA+gA+AP8BAABAAQUBBQBCAQgBCABDARMBFQBEAScBKQBHASwBLABKAS4BLgBLAUUBRQBMAWUBawBNAW8BcABUAewB7QBWAe8B7wBYAfECFwBZAhwCIQCAAiYCNgCGAjgCQQCXAkoCTAChAk4CTgCkAlACUAClAlICUgCmAlQCVACnAlcCVwCoAlkCWQCpAlsCWwCqAl0CXQCrAl8CXwCsAmECYQCtAmMCbwCuAnECcQC7AnMCcwC8AnUCdQC9AoACgAC+AoICggC/AoQChADAAoYChgDBAogCiADCAooCigDDAowCjADEAo4CjgDFApACkADGApICkgDHApQCnADIAvgC/QDRAwADDwDXAxIDEgDnAxYDFgDoAxgDGADpAxwDHADqAx8DIADrAyIDKwDtAy0DLwD3AzEDNgD6AzgDPgEAA0QDRQEHA0cDRwEJA0kDSQEKA0sDTgELA1IDVwEPA1oDWgEVA1wDXAEWA2ADYQEXA2YDcQEZA3QDdQElA3cDegEnA4EDggErA4YDhgEtA4gDjgEuA5MDlAE1A5gDwAE3A8IDwgFgA8QD0QFhA9kD2QFvA9wD3AFwA94D3gFxA+oD7wFyA/ID8gF4A/QD9AF5A/YD9gF6A/gD+QF7A/4EAQF9BAQEBAGBBAYEBwGCBAkECQGEBA0EDQGFBA8EDwGGBBMEEwGHAAIBOAAEAAQAHQAJAAkAHQAOAA4AHgAQABAAHgAkACQAAQAlACUABAAmACYAAwAnACcABQAqACsAAgAsACwADAAtAC0ACQAuAC4ACgAvADAAAgAxADEAAwAyADIACwA2ADYABgA3ADcADAA4ADgADQA5ADkAEAA6ADoADgA7ADsADwA8ADwAEQBDAEMAEwBEAEQAFQBFAEUAFABHAEcAFgBKAEoAFwBPAFAAFwBRAFEAGABSAFIAFQBUAFQAGgBYAFgAGQBaAFoAGwBbAFsAGQBcAFwAHACIAIgAFQCsAKwABwCuAK4AAwC4ALgAGQC8ALwAFwDCAMIAFQDPANAAHwDSANIAAgDVANUADgDXANgAAgDZANkAEgDbANsAAgDdAN0AAgDfAN8AHwDhAOEAHwDnAOcACADpAOkAGwDyAPIAFQD3APcAIAD5APkAIAD6APoAFQD/AQAAIAEFAQUAIAETARMAGAEUARQADQEVARUAGQEnAScAFQEoASgABwEpASkACAEsASwACQEuAS4ACQFFAUUACAFlAWYAHQFnAWcAHgFoAWoAHQFrAWsAHgFvAXAAHgHsAe0AAwHvAe8ABgH4AfgABAH5AfwABQH9AgEAAgICAgYAAwIHAgoADAILAgsADwIMAhIAEwITAhMAFAIUAhcAFgIcAhwAFwIdAiEAGAImAicAGQIpAikAEwIrAisAEwItAi0AEwIuAi4ABAIvAi8AFAIwAjAABAIxAjEAFAIyAjIABAIzAjMAFAI0AjQABAI1AjUAFAI2AjYAAwI4AjgABQI5AjkAFgI6AjoABQI7AjsAFgI8AjwABQI9Aj0AFgI+Aj4ABQI/Aj8AFgJAAkAABQJBAkEAFgJKAkoAAgJLAksAFwJMAkwAAgJOAk4AAgJQAlAAAgJSAlIAAgJUAlQAAgJXAlcADAJZAlkACQJbAlsACgJdAl0ACgJfAl8ACgJhAmEACgJjAmMAAgJkAmQAFwJlAmUAAgJmAmYAFwJnAmcAAgJoAmkAFwJqAmoAAwJrAmsAGAJsAmwAAwJtAm0AGAJuAm4AAwJvAm8AGAJxAnEAGgJzAnMAGgJ1AnUAGgKAAoAABgKCAoIABgKEAoQABgKGAoYADAKIAogADAKKAooADAKMAowADAKOAo4ADAKQApAADAKSApIAEAKUApQADwKVApUAGQKWApYADwKXApcAEQKYApgAHAKZApkAEQKaApoAHAKbApsAEQKcApwAHAL5AvkABQL6AvsAAgL8AvwAAwL9Av0ADwMBAwEAAQMCAwIABQMDAwMAEQMEAwUAAgMGAwYACQMHAwgAAgMJAwkAAwMKAwoACwMLAwsABgMMAwwADwMNAw0ADgMOAw4AAgMPAw8ADwMSAxIAFwMWAxYAGAMYAxgAGQMcAxwAGAMfAx8ABQMgAyAABwMiAyMAAgMkAyQADAMlAyYACQMnAycAEgMpAykAAQMqAyoABwMrAysABQMtAy4AAgMvAy8AAwMxAzEACwMyAzIABAMzAzMABgM0AzQADgM1AzUAEwM2AzYAFgM4AzgAGAM5AzkAFQM6AzoAFAM7AzsAGQM8AzwAGwM9Az0AFgM+Az4ACANEA0QAGQNFA0UAEANHA0cAEANJA0kAEANLA0sADwNMA0wAGQNNA04AHQNSA1IAHQNTA1MAAgNUA1QAFwNWA1YAEwNXA1cAAwNaA1oABQNcA1wAFgNgA2AADQNhA2EAGQNmA2YABANnA2cAFANoA2gADwNpA2kAGQNqA2oAAgNrA2sADgNsA2wAGwNtA20AAgNvA28AEwNxA3EAEwN0A3QABQN1A3UAFgN3A3gAFgN5A3kADgN6A3oAGwOBA4EAAwOCA4IAGAOGA4YAGAOIA4gAFQOJA4kAEgOKA4oAGQOLA4sAEgOMA4wAGQONA40AEgOOA44AGQOTA5MADgOUA5QAGwOZA5kAEwObA5sAEwOdA50AEwOfA58AEwOhA6EAEwOjA6MAEwOlA6UAEwOnA6cAEwOpA6kAEwOrA6sAEwOtA60AEwOvA68AEwOwA7AABQOxA7EAFgOyA7IABQOzA7MAFgO0A7QABQO1A7UAFgO2A7YABQO3A7cAFgO4A7gABQO5A7kAFgO6A7oABQO7A7sAFgO8A7wABQO9A70AFgO+A74ABQO/A78AFgPAA8AAAgPCA8IAAgPEA8QAAwPFA8UAGAPGA8YAAwPHA8cAGAPIA8gAAwPJA8kAGAPKA8oAAwPLA8sAGAPMA8wAAwPNA80AGAPOA84AAwPPA88AGAPQA9AAAwPRA9EAGAPZA9kAGAPcA9wADAPeA94ADAPqA+oADwPrA+sAGQPsA+wADwPtA+0AGQPuA+4ADwPvA+8AGQPyA/IACQP0A/QAAgP2A/YABgP4A/gADgP5A/kAGwP+A/4ABwP/A/8ACAQABAAADgQBBAEAGwQEBAQAFwQGBAYAHwQHBAcABwQJBAkACQQNBA0AAgQPBA8AAgQTBBMADwABAAQEFgALAAAAAAAAAAAACwAAAAAAAAAAABUAGQAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAGAAAAAAAAAAYAAAAAABwAAAAAAAAAAAAGAAAABgAAABoADAAIAAcADwATAAoAFAAAAAAAAAAAAAAAAAAbAAAAFgAWABYAAAAWAAAAAAAAAAAAAAAJAAkABAAJABYAAAAYAAAADQAFAAAAFwAFAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAWAAAAAAAGABYAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIABgASAAAAAAAAAAAAAAAAABYAAAAFAAAAAAAAAAkAAAAAAAAAAAAAAAAAFgAWAAAADQAAAAAAAAAAAAAAAAAMAAYAAgAAAAwAAAAAAAAAEwAAAAAAAgARAAAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAABcAAAAJAAkAEAAJAAkACQAAABYACQADAAkACQAAAAAACQAAAAkAAAAAABYAEAAJAAAAAAAGAAAAAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAGAAQABwAFAAYAAAAGABYABgAAAAYAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAkAAAAAAAYAFgAMAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAJAAAAFgAWAAAAAAAAAAAAAgAAAAAAAAAGABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAZAAAACwALABUACwALAAsAFQAAAAAAAAAVABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAAAAAAAAAAABIAEgASABIAEgASABIABgAAAAAAAAAAAAAAAAAAAAAAAAAGAAYABgAGAAYACAAIAAgACAAKABsAGwAbABsAGwAbABsAFgAWABYAFgAWAAAAAAAAAAAACQAEAAQABAAEAAQADQANAA0ADQAFAAUAEgAbABIAGwASABsABgAWAAYAFgAGABYABgAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAYAFgAGABYABgAWAAYAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAkAAAAJAAkABgAEAAYABAAGAAQAAAAAAAAAAAAAAAAAGgAYABoAGAAaABgAGgAYABoAGAAMAAAADAAAAAwAAAAIAA0ACAANAAgADQAIAA0ACAANAAgADQAPAAAACgAFAAoAFAABABQAAQAUAAEAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAYACgAAAAAAEgAAAAAAFAAAAAAAAAAAAAAABgAAAAAACgATAAAACgAWAAAACQAAAA0AAAAEAAAABQAAAAAADQAEAA0AAAAAAAAAAAAAAAAAHAAAAAAAEQASAAAAAAAAAAAAAAAAAAYAAAAAAAYADAATABsAFgAJAAQACQAWAAUAFwAWAAkAGAAAAAAAAAAJAAUADwAAAA8AAAAPAAAACgAFAAsACwAAAAAAAAALAAAACQASABsABgAAAAAAAAAAABYACQAAAAAABwAFABYABgAAAAAABgAWAAoABQAAABMAFwAAABIAGwASABsAAAAAAAAAFgAAABYAFgATABcAAAAAAAAACQAAAAkABgAEAAYAFgAGAAQAAAAAABEABQARAAUAEQAFAA4AAwAAAAkAEwAXABYAAgAQABIAGwASABsAEgAbABIAGwASABsAEgAbABIAGwASABsAEgAbABIAGwASABsAEgAbAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAAAAAAAAAGAAQABgAEAAYABAAGAAQABgAEAAYABAAGAAQABgAWAAYAFgAGABYABgAEAAYAFgAIAA0ACAANAAAADQAAAA0AAAANAAAADQAAAA0ACgAFAAoABQAKAAUAAAAAAAAACQAAAAkADAAAABMAFwAOAAMADgADAAAACQATABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAACQAAAAkAAgAQAAoAAAAAAAAAAAAAABkAAAABAAAACgAsAI4AAURGTFQACAAEAAAAAP//AAgAAAABAAIAAwAEAAUABgAHAAhsaWdhADJsbnVtADhzbWNwAD5zczAxAERzczAyAEpzczAzAFBzczA0AFZzczA1AFwAAAABAAEAAAABAAIAAAABAAAAAAABAAMAAAABAAQAAAABAAUAAAABAAYAAAABAAcACAASABoAIgAqADIAOgBCAEoAAQAAAAEAQAAEAAAAAQH2AAEAAAABAgAAAQAAAAECEgABAAAAAQIQAAEAAAABAg4AAQAAAAECDAABAAAAAQIOAAICEADcAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AegBtQG2AbcBuAG5AboBuwG8Ab0BvgGmAacBqAGpAaoBqwGsAa0BrgGvAbABsQGyAbMBtAHoAbUBtgG3AbgBuQG6AbsBvAG9Ab4C9wKiAqECogKjAqMCpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4C8wK/Ar8CwALAAsECwQLCAsICwwLDAsUCxQLGAsYCxwLHAsgCyALJAskCygLKAssCywLMAswCzQLNAs8CzwLQAtAC0QLRAtIC0gLTAtMC1ALUAtUC1gLWAtcC1wLYAtgC2QLZAtoC2gLbAtsC3ALcAt0C3QLeAt4C3wLfAuAC4ALhAuEC4gLiAuMC4wLkAuQC5QLlAuYC5gLnAucC6ALo/////wLqAuoC6wLrAuwC7ALtAu0C7gLuAu8C7wLwAvAC8QLxAvIC8gLzAvQC9AL1AvUC9gL2AqEAAQCkAAEACAABAAQBkgACAEsAAgCYAAoBmAHMAcQB1gHXAdgB2QHbAd0B5wABAIgBkQABAIgBKAABAIgBrgACAIgAAgHjAeQAAgB+AAIB5QHmAAIADQAjADwAAABDAFwAGgCDAIMANACFAIUANQHsAe0ANgHvAjEAOAI0AkUAewJIAlQAjQJXAmgAmgJqAnsArAJ+An8AvgKCApwAwAPwA/AA2wABAAEASAACAAEAEgAbAAAAAQABAEkAAQABALYAAQABADQAAQACAC0ATQ==","Roboto-Regular.ttf":"AAEAAAAOAIAAAwBgR0RFRgsuCy8AASx0AAAASEdQT1OC3T4oAAEsvAAAkPhHU1VCeolvLwABvbQAAANsT1MvMrivKcMAAAFoAAAAYFZETVhu6nZPAAASOAAABeBjbWFwf76BZgAAGBgAAA7iZ2x5ZusE9WMAACb8AADUeGhlYWT1kQ7EAAAA7AAAADZoaGVhC3AJkwAAASQAAAAkaG10eJaDaacAAAHIAAAQcGxvY2EvrvnGAAD7dAAACDptYXhwBDsA9gAAAUgAAAAgbmFtZbs83bQAAQOwAAAEeXBvc3Tfb5xiAAEILAAAJEYAAQAAAAEAAHdFsyVfDzz1AAkIAAAAAADE8BEuAAAAAM2CsmH6jf3VCXQIYgAAAAkAAgAAAAAAAAABAAAHbP4MAAAJkvqN/dgJdAABAAAAAAAAAAAAAAAAAAAEHAABAAAEHACXABYAXQAFAAEAAAAAAAAAAAAAAAAAAwABAAMElwGQAAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAAAAAAAAAAAAAAA4AAC/1AAIFsAAAAgAAAAAHB5cnMAQAAA//0GAP4AAGYHmgIAIAABn08BAAAEOgWwAAAAIAACAfsAAAAAAAAB+wAAAfsAAAKPAGkE+wBGBH4AbgXcAGkE+QBEAWUAZwKhAIUCqgAIA3IAHASJAE4BkgAdAjUAJQIbAKIDTAASBH4AcgR+ANcEfgBdBH4AXgR+ADkEfgCaBH4AhwR+AE0EfgBmBH4AVAH4AKACAABKBBEASASAAJgELgCGA8cAOgcvAGEFSgAnBRcAtgUeAIMFaQC2BKoAtgSnALYFfgCFBbMAtgI/AMMEagA/BSQAtgRgALYHAwC2BbQAtgWQAIIFGQC2BZAAggVMALUE4wBaBMYAOwVoAJYFKQAnBw0ASAUJAEEE8gAeBMkAYQIfAJIDSAAoAh8ACQNYAEADnAAEAnkATwRiAHIEiACRBDsAYQSIAGQENwBiAr4AQgSIAGYEiACRAfwAoQIL/7YEEwCSAfwAoQcCAJAEiACRBIgAYASIAJEEiABkAsoAkQQrAGYCjAAdBIgAjQQCAC4GDgAwBAIALgQCABsEAgBeArUAQAHzAK8CtQATBXEAggHzAJAEYQBuBKYARgW0AGkE2AAgAesAkwToAFoD9ACpBkkAWwOTAHoDwQBmBG4AfwZKAFoDqgB4Av0AggRHAGEDXwBxA2gAaQKCAIEEiACaA+kAQgIWAKIB+wB0AiYAXgOjAHoDwABvBjYAtAaWALQG6wB7A+0AcQd6//IERABZBXIAcwS6AKYEwgCLBsEAPQSwAEwEkQBHBIkAYAScAJoFmwAeAfoAmwRzAJoEMwAmAioAIwWLAKQEiACRB6EAaQdEAGEB/ACgArn/5AV/AHEEkwBgBZAAlgTzAI0CA/+0BDcAYgPEAKkDjQCMA2oAgQIhAKACtQCLAioAMgPGAIIC/ABoAp0AtgAA/NoAAP13AAD8kwAA/V4AAPwnAAD9QwINAMMECwChAhcAogRzALUFpAAgBXIAcwU+ADQEkQB6BbUAtgSRAEUFuwBOBYkAXQVSAHIEhQBkBL0AoAQCAC4EiABgBFAAYwQlAG0EiACRBI8AegKXAMMEbgAlA+wAZQTFAE8EiACRBE0AZQSIAGAELABRBF0AjwWjAFcFmgBfBpcAegTwAHQEQv/nBkgASgX/ACsFZQCHCJkAMgikALUGggBABbQAtQULAKYGBAA0B0MAGwS/AFEFtAC2BakAMAUHAFEGLQBTBdkAtAV6AJcHhwC0B8AAtAYSABEG6wC1BQUApgVkALEHJwDDBRgAYwRsAGEEkgCdA1sAmgTUAC4GIAAVBBAAWASeAJwEUgCcBKAAKAXvAJ0EnQCcBJ4AnAPYACgFzQBkBL0AnARZAGcGeACcBp8AkQT3AB4GNgCdBFgAnQRNAGQGiACdBGQALwSJ/+cETgBsBskAJwbkAJwEif/9BJ4AnAcIAJ8GKwCBBFb/3AcsAMQF+QCZBNIAKgRGAA8HDADWBgwAvAbRAJYF4QCWCQUAwwfRAJsEJABQA9sATAVyAHMEjABgBQoAFwQDAC4FcgBzBIkAYAcBAJ8GJAB+BwkAnwYsAIEFMgB4BEcAZAT9AHQAAPxnAAD8cQAA/WYAAP2kAAD6jQAA+qQEVv/cBRsAtQSKAJEEZACmA5AAkQTbALUEBgCRBQkApgR+AJoGjABFBYQAPgfPALUFtACRCDEAtAb0AJEF7gBzBNMAbQctADQFXAAfBXAAlwRrAIMFcACOBi8ARwS+/+MFCQCmBFoAmgWyALUEiACRBYcAXwSoAGkEqABpBLcAOgNJADsE9gBZBpQAWQbkAGQGVgA2BSsAMQRKAFMECAB5B8EARQZ1AD8H+wCtBqEAkAT2AHkEHQBlBa0AJAUgAEYFZACbBBQAAAgpAAAEFAAACCkAAAK5AAACCgAAAVwAAAR/AAACMAAAAaIAAADRAAAAAAAABYgAswZ9ALsDpgANAZkAYAGZADABlwAkAZoAUALUAGAC2wA8AsEAJARpAEYEjwBXArIAigPEAKYFWgCmB6oARAJmAGwCZgBZA6MAOwOrAEgDYAB6BKYARgaRAKcEPgBPBegAewPOAGgIywCrBQEAZgUXAJgGuwBvB1AAawd/AGwG2wBrBKIATAWOAKkErwBFBJIAqATFAD8IOgBrAgz/tASCAGUELQCYBDYAngQ8AJkECAArAkwAxwKPAG4CAwBcBG4AHwAAAAAIMwBbCDUAXAQcAFwDjQBXBIAAcwML/6IB/P+2AiUAGwGRAGcDpACDA54AgQOfAIED9ABtBA4AaQPz/14D7wBuA6QAWwH9AJ8EtQApBHUAmwSPAHIEpgCbBEMAmwQdAJsEzwByBPYAmwH6AJsECwBBBF0AmwO5AJsF9ACbBRkAmwTLAHIE4QByBKkAmwRvAF0ELABHBQIAjAS4ACoGBQBBBIQAOAReACAEPgBOBHcAewJpAEID4QBaBBIAWQRkAEcEaQBdBC0AegO5AEcELQBcBCcASwInAF4DVQBxA2gAaQL8AEoDeQByA3oAewMMAF4DggByA2sAaQOkAHwDlgCPArUAngNHAG8EfgBeBH4AOQR+AJoEjwCHBDoAHgRCADsEbwBaBH4AZgTDAGQEiABgBUQAtgRiAHIFLwC1BSQAtgQTAJIFPQC2BA8AkgR+AFQEdQCbA2oAgQH7AAACNQAlBYcALgWHAC4EpgAGBMYAOwKM/+MFSgAnBUoAJwVKACcFSgAnBUoAJwVKACcFSgAnBR4AgwSqALYEqgC2BKoAtgSqALYCP//cAj8AwwI///ICP//MBbQAtgWQAIIFkACCBZAAggWQAIIFkACCBWgAlgVoAJYFaACWBWgAlgTyAB4EYgByBGIAcgRiAHIEYgByBGIAcgRiAHIEYgByBDsAYQQ3AGIENwBiBDcAYgQ3AGIB+v+1AfoAmwH6/8sB+v+lBIgAkQSIAGAEiABgBIgAYASIAGAEiABgBIgAjQSIAI0EiACNBIgAjQQCABsEAgAbBUoAJwRiAHIFSgAnBGIAcgVKACcEYgByBR4AgwQ7AGEFHgCDBDsAYQUeAIMEOwBhBR4AgwQ7AGEFaQC2BR4AZASqALYENwBiBKoAtgQ3AGIEqgC2BDcAYgSqALYENwBiBKoAtgQ3AGIFfgCFBIgAZgV+AIUEiABmBX4AhQSIAGYFfgCFBIgAZgWzALYEiACRAj//xQH6/54CP/+/Afr/mAI///UB+v/OAj8AIQH8AAACPwC3BqkAwwQHAKEEagA/AgP/tAUkALYEEwCSBGAAtgH8AKEEYAC2AfwAWwRgALYCkgChBGAAtgLYAKEFtAC2BIgAkQW0ALYEiACRBbQAtgSIAJEEiP/SBZAAggSIAGAFkACCBIgAYAWQAIIEiABgBUwAtQLKAJEFTAC1AsoAWAVMALUCygBpBOMAWgQrAGYE4wBaBCsAZgTjAFoEKwBmBOMAWgQrAGYE4wBaBCsAZgTGADsCjAAdBMYAOwKMAB0ExgA7ArQAHQVoAJYEiACNBWgAlgSIAI0FaACWBIgAjQVoAJYEiACNBWgAlgSIAI0FaACWBIgAjQcNAEgGDgAwBPIAHgQCABsE8gAeBMkAYQQCAF4EyQBhBAIAXgTJAGEEAgBeB3r/8gbBAD0FcgBzBIkAYASm//MEpv/zBCwARwS1ACkEtQApBLUAKQS1ACkEtQApBLUAKQS1ACkEjwByBEMAmwRDAJsEQwCbBEMAmwH6/7MB+gCbAfr/yQH6/6MFGQCbBMsAcgTLAHIEywByBMsAcgTLAHIFAgCMBQIAjAUCAIwFAgCMBF4AIAS1ACkEtQApBLUAKQSPAHIEjwByBI8AcgSPAHIEpgCbBEMAmwRDAJsEQwCbBEMAmwRDAJsEzwByBM8AcgTPAHIEzwByBPYAmwH6/5wB+v+WAfr/zAH6//cB+gCPBAsAQQRdAJsDuQCbA7kAmwO5AJsDuQCbBRkAmwUZAJsFGQCbBMsAcgTLAHIEywByBKkAmwSpAJsEqQCbBG8AXQRvAF0EbwBdBG8AXQQsAEcELABHBQIAjAUCAIwFAgCMBQIAjAUCAIwFAgCMBgUAQQReACAEXgAgBD4ATgQ+AE4EPgBOCN4AXQVKACcFDv/mBhcAEwKjABkFpABSBVb/jQVmAD8Cl//IBUoAJwUXALYEqgC2BMkAYQWzALYCPwDDBSQAtgcDALYFtAC2BZAAggUZALYExgA7BPIAHgUJAEECP//MBPIAHgSFAGQEUABjBIgAkQKXAMMEXQCPBHMAmgSIAGAEiACaBAIALgQCAC4Cl//TBF0AjwSIAGAEXQCPBpcAegSqALYEcwC1BOMAWgI/AMMCP//MBGoAPwUkALYFJAC2BQcAUQVKACcFFwC2BHMAtQSqALYFtAC2BwMAtgWzALYFkACCBbUAtgUZALYFHgCDBMYAOwUJAEEEYgByBDcAYgSeAJwEiABgBIgAkQQ7AGEEAgAbBAIALgQ3AGIDWwCaBCsAZgH8AKEB+v+lAgv/tgRSAJwEAgAbBw0ASAYOADAHDQBIBg4AMAcNAEgGDgAwBPIAHgQCABsBZQBnAo8AaQQeAKkEugBCAgP/tAGZADAHAwC2BwIAkAVKACcEYgByBZD/PgcsAEIHeABCBKoAtgW0ALYENwBiBJ4AnAWJAF0FmgBfBQoAFwQD//kIigBgCZIAggS/AFEEEABYBR4AgwQ7AGEE8gAeBAIALgI/AMMHQwAbBiAAFQI/AMMFSgAnBGIAcgVKACcEYgByB3r/8gbBAD0EqgC2BDcAYgWHAF8ENwBiBDcAYgdDABsGIAAVBL8AUQQQAFgFtAC2BJ4AnAW0ALYEngCcBZAAggSIAGAFcgBzBIwAYAVyAHMEjABgBWQAsQRNAGQFBwBRBAIAGwUHAFEEAgAbBQcAUQQCABsFegCXBFkAZwbrALUGNgCdBQkAQQQCAC4EiABkBakAMASgACgFSgAnBGIAcgVKACcEYgByBUoAJwRiAHIFSgAnBGL/rgVKACcEYgByBUoAJwRiAHIFSgAnBGIAcgVKACcEYgByBUoAJwRiAHIFSgAnBGIAcgVKACcEYgByBUoAJwRiAHIEqgC2BDcAYgSqALYENwBiBKoAtgQ3AGIEqgC2BDcAYgSq//gEN/+zBKoAtgQ3AGIEqgC2BDcAYgSqALYENwBiAj8AwwH6AJsCPwC3AfwAlgWQAIIEiABgBZAAggSIAGAFkACCBIgAYAWQAEwEiP/LBZAAggSIAGAFkACCBIgAYAWQAIIEiABgBX8AcQSTAGAFfwBxBJMAYAV/AHEEkwBgBX8AcQSTAGAFfwBxBJMAYAVoAJYEiACNBWgAlgSIAI0FkACWBPMAjQWQAJYE8wCNBZAAlgTzAI0FkACWBPMAjQWQAJYE8wCNBPIAHgQCABsE8gAeBAIAGwTyAB4EAgAbBKYAZASmAGQFJAC2BFIAnAWzALYEnQCcBMYAOwPYACgFCQBBBAIALgV6AJcEWQBnBXoAlwRZAGcEcwC1A1sAmgdDABsGIAAVBi8ARwS+/+MEiACRBQX/1AUF/9QEcwADA1v//AU4//UEJ//YBbQAtgSeAJwFswC2BJ0AnAcDALYF7wCdBakAMASgACgE8gAeBAIALgUJAEEEAgAuBFAAYwSnABsGfQC7AAAAAAIPAKkAAAABAAEBAQEBAAwA+Aj/AAgACP/+AAkACf/9AAoACv/9AAsAC//9AAwADP/9AA0ADf/8AA4ADv/8AA8AD//8ABAAEP/8ABEAEf/7ABIAEv/7ABMAE//7ABQAFP/7ABUAFP/6ABYAFf/6ABcAFv/6ABgAF//6ABkAGP/5ABoAGf/5ABsAGv/5ABwAG//5AB0AHP/4AB4AHf/4AB8AHv/4ACAAH//4ACEAIP/3ACIAIf/3ACMAIv/3ACQAI//3ACUAJP/2ACYAJf/2ACcAJv/2ACgAJ//2ACkAJ//1ACoAKP/1ACsAKf/1ACwAKv/1AC0AK//0AC4ALP/0AC8ALf/0ADAALv/0ADEAL//zADIAMP/zADMAMf/zADQAMv/zADUAM//yADYANP/yADcANf/yADgANv/yADkAN//xADoAOP/xADsAOf/xADwAOv/xAD0AOv/wAD4AO//wAD8APP/wAEAAPf/wAEEAPv/vAEIAP//vAEMAQP/vAEQAQf/vAEUAQv/uAEYAQ//uAEcARP/uAEgARf/uAEkARv/tAEoAR//tAEsASP/tAEwASf/tAE0ASv/sAE4AS//sAE8ATP/sAFAATf/sAFEATf/rAFIATv/rAFMAT//rAFQAUP/rAFUAUf/qAFYAUv/qAFcAU//qAFgAVP/qAFkAVf/pAFoAVv/pAFsAV//pAFwAWP/pAF0AWf/oAF4AWv/oAF8AW//oAGAAXP/oAGEAXf/nAGIAXv/nAGMAX//nAGQAYP/nAGUAYP/mAGYAYf/mAGcAYv/mAGgAY//mAGkAZP/lAGoAZf/lAGsAZv/lAGwAZ//lAG0AaP/kAG4Aaf/kAG8Aav/kAHAAa//kAHEAbP/jAHIAbf/jAHMAbv/jAHQAb//jAHUAcP/iAHYAcf/iAHcAcv/iAHgAc//iAHkAc//hAHoAdP/hAHsAdf/hAHwAdv/hAH0Ad//gAH4AeP/gAH8Aef/gAIAAev/gAIEAe//fAIIAfP/fAIMAff/fAIQAfv/fAIUAf//eAIYAgP/eAIcAgf/eAIgAgv/eAIkAg//dAIoAhP/dAIsAhf/dAIwAhv/dAI0Ahv/cAI4Ah//cAI8AiP/cAJAAif/cAJEAiv/bAJIAi//bAJMAjP/bAJQAjf/bAJUAjv/aAJYAj//aAJcAkP/aAJgAkf/aAJkAkv/ZAJoAk//ZAJsAlP/ZAJwAlf/ZAJ0Alv/YAJ4Al//YAJ8AmP/YAKAAmf/YAKEAmf/XAKIAmv/XAKMAm//XAKQAnP/XAKUAnf/WAKYAnv/WAKcAn//WAKgAoP/WAKkAof/VAKoAov/VAKsAo//VAKwApP/VAK0Apf/UAK4Apv/UAK8Ap//UALAAqP/UALEAqf/TALIAqv/TALMAq//TALQArP/TALUArP/SALYArf/SALcArv/SALgAr//SALkAsP/RALoAsf/RALsAsv/RALwAs//RAL0AtP/QAL4Atf/QAL8Atv/QAMAAt//QAMEAuP/PAMIAuf/PAMMAuv/PAMQAu//PAMUAvP/OAMYAvf/OAMcAvv/OAMgAv//OAMkAv//NAMoAwP/NAMsAwf/NAMwAwv/NAM0Aw//MAM4AxP/MAM8Axf/MANAAxv/MANEAx//LANIAyP/LANMAyf/LANQAyv/LANUAy//KANYAzP/KANcAzf/KANgAzv/KANkAz//JANoA0P/JANsA0f/JANwA0v/JAN0A0v/IAN4A0//IAN8A1P/IAOAA1f/IAOEA1v/HAOIA1//HAOMA2P/HAOQA2f/HAOUA2v/GAOYA2//GAOcA3P/GAOgA3f/GAOkA3v/FAOoA3//FAOsA4P/FAOwA4f/FAO0A4v/EAO4A4//EAO8A5P/EAPAA5f/EAPEA5f/DAPIA5v/DAPMA5//DAPQA6P/DAPUA6f/CAPYA6v/CAPcA6//CAPgA7P/CAPkA7f/BAPoA7v/BAPsA7//BAPwA8P/BAP0A8f/AAP4A8v/AAP8A8//AAAAAAwAAAAMAAAiEAAEAAAAAABwAAwABAAACJgAGAgoAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAEAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAMEGwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYAAAAfUB9gH4AfoCAQIGAgoCDQIMAg4CEAIPAhECEwIVAhQCFgIXAhkCGAIaAhsCHAIeAh0CHwIhAiACIwIiAiQCJQFsAG8AYgBjAGcBbgB1AIMAbQBpAX0AcwBoAYsAfwCBAYgAcAGMAY0AZQB0AYMBhQGEAMEBiQBqAHkAtQCEAIcAfgBhAGwBhwCTAYoArQBrAHoBcAADAfEB9AIFAJAAkQFiAWMBaQFqAWUBZgCGAY4CJwKWAXQBeQFyAXMBkgNQAW0AdgFnAWsBcQHzAfsB8gH8AfkB/gH/AgAB/QIDAgQAAAICAggCCQIHAIoAmgCgAG4AnACdAJ4AdwChAJ8AmwAEBl4AAADqAIAABgBqAAAAAgANACEAfgCgAKwArQC/AMYAzwDmAO8A/gEPAREBJQEnATABOAFAAVMBXwFnAX4BfwGSAaEBsAHwAfsB/wIZAhsCNwJZArwCxwLJAt0C8wMBAwMDCQMPAyMDigOMA5IDoQOwA7kDyQPOA9ID1gQlBC8ERQRPBGIEbwR5BIYEzgTXBOEE9QUBBRAFEx4BHj8ehR7xHvMe+R9NIAsgFSAeICIgJiAwIDMgOiA8IEQgdCB/IKQgpyCsIQUhEyEWISIhJiEuIV4iAiIGIg8iEiIaIh4iKyJIImAiZSXK7gL2w/sE/v///f//AAAAAAACAA0AIAAiAKAAoQCtAK4AwADHANAA5wDwAP8BEAESASYBKAExATkBQQFUAWABaAF/AZIBoAGvAfAB+gH8AhgCGgI3AlkCvALGAskC2ALzAwADAwMJAw8DIwOEA4wDjgOTA6MDsQO6A8oD0QPWBAAEJgQwBEYEUARjBHAEegSIBM8E2ATiBPYFAgURHgAePh6AHqAe8h70H00gACATIBcgICAlIDAgMiA5IDwgRCB0IH8goyCnIKshBSETIRYhIiEmIS4hWyICIgYiDyIRIhoiHiIrIkgiYCJkJcruAfbD+wH+///8//8AAQQY//UAAP/iAAD/wAAA/78AAAExAAABLAAAASgAAAEmAAABJAAAASIAAAEcAAABHgAA/wH+9P7nAWEAAAChAGQAZv5h/kAAlv3U/aX9xP2v/aP9ov2d/Zj9hQAA/3D/bwAAAAD9BQAA/1D8+fz2AAD8tQAA/K0AAPyiAAD8nAAA/p4AAP6bAAD8RQAA5VXlFeTF5PjkWeT25ArhVgAA4U3hTOFK4UHjG+E54xPhMOEB4PcAAODRAADgdeBo4GbgW9+P4FDgJN+B3qffdd90323fat9e30LfK98o28QTjgrOAAAClAGYAAEAAAAAAAAA5AAAAOQAAADiAAAA4AAAAOoAAAEUAAABLgAAAS4AAAEuAAABOgAAAVwAAAFoAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEAAAAAAFMAWgAAAGAAAAAAAAAAZgAAAHgAAACCAAAAioAAAI6AAACxAAAAtQAAALoAAAAAAAAAAAAAAAAAAAAAALcAAAAAAAAAAAAAAAAAAAAAAAAAAACzAAAAswAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqYAAAAAAAAAAwQbAeoB6wHxAfIB8wH0AfUB9gB/Ae0CAQICAgMCBAIFAgYAgACBAgcCCAIJAgoCCwCCAIMCDAINAg4CDwIQAhEAhACFAhwCHQIeAh8CIAIhAIYAhwIiAiMCJAIlAiYAiAHsA/AAiQHuAIoCVQJWAlcCWAJZAloAiwCMAI0CYwJkAmUCZgJnAmgCaQCOAI8CagJrAmwCbQJuAm8AkACRAn4CfwKCAoMChAKFAe8B8ACSAfcCEgCpAKoC+ACrAvkC+gL7AKwArQMCAwMDBACuAwUDBgCvAwcDCACwAwkAsQMKALIDCwMMALMDDQC0ALUDDgMPAxADEQMSAxMDFAMVAL8DFwMYAMADFgDBAMIAwwDEAMUAxgDHAxkAyADJA1oDHwDNAyAAzgMhAyIDIwMkAM8A0ADRAyYDWwMnANIDKADTAykDKgDUAysA1QDWANcDLAMlANgDLQMuAy8DMAMxAzIDMwDZANoDNAM1AOUA5gDnAOgDNgDpAOoA6wM3AOwA7QDuAO8DOADwAzkDOgDxAzsA8gM8A1wDPQD9Az4A/gM/A0ADQQNCAP8BAAEBA0MDXQNEAQIBAwEEBAYDXgNfARIBEwEUARUDYANhA2MDYgEjASQECwQMBAUBJQEmAScBKAEpBAcECAEqASsEAAQBA2QDZQPyA/MBLAEtBAkECgEuAS8D9AP1ATABMQEyATMBNAE1A2YDZwP2A/cDaANpBBMEFAP4A/kBNgE3A/oD+wE4ATkBOgQEATsBPAQCBAMDagNrA2wBPQE+BBEEEgE/AUAEDQQOA/wD/QQPBBABQQN3A3YDeAN5A3oDewN8AUIBQwP+A/8DkQOSAUQBRQOTA5QEFQQWAUYDlQQXA5YDlwFiAWMEGQQYAXcD8QF5AZIDUANYA1kABAZeAAAA6gCAAAYAagAAAAIADQAhAH4AoACsAK0AvwDGAM8A5gDvAP4BDwERASUBJwEwATgBQAFTAV8BZwF+AX8BkgGhAbAB8AH7Af8CGQIbAjcCWQK8AscCyQLdAvMDAQMDAwkDDwMjA4oDjAOSA6EDsAO5A8kDzgPSA9YEJQQvBEUETwRiBG8EeQSGBM4E1wThBPUFAQUQBRMeAR4/HoUe8R7zHvkfTSALIBUgHiAiICYgMCAzIDogPCBEIHQgfyCkIKcgrCEFIRMhFiEiISYhLiFeIgIiBiIPIhIiGiIeIisiSCJgImUlyu4C9sP7BP7///3//wAAAAAAAgANACAAIgCgAKEArQCuAMAAxwDQAOcA8AD/ARABEgEmASgBMQE5AUEBVAFgAWgBfwGSAaABrwHwAfoB/AIYAhoCNwJZArwCxgLJAtgC8wMAAwMDCQMPAyMDhAOMA44DkwOjA7EDugPKA9ED1gQABCYEMARGBFAEYwRwBHoEiATPBNgE4gT2BQIFER4AHj4egB6gHvIe9B9NIAAgEyAXICAgJSAwIDIgOSA8IEQgdCB/IKMgpyCrIQUhEyEWISIhJiEuIVsiAiIGIg8iESIaIh4iKyJIImAiZCXK7gH2w/sB/v///P//AAEEGP/1AAD/4gAA/8AAAP+/AAABMQAAASwAAAEoAAABJgAAASQAAAEiAAABHAAAAR4AAP8B/vT+5wFhAAAAoQBkAGb+Yf5AAJb91P2l/cT9r/2j/aL9nf2Y/YUAAP9w/28AAAAA/QUAAP9Q/Pn89gAA/LUAAPytAAD8ogAA/JwAAP6eAAD+mwAA/EUAAOVV5RXkxeT45Fnk9uQK4VYAAOFN4UzhSuFB4xvhOeMT4TDhAeD3AADg0QAA4HXgaOBm4Fvfj+BQ4CTfgd6n33XfdN9t32rfXt9C3yvfKNvEE44KzgAAApQBmAABAAAAAAAAAOQAAADkAAAA4gAAAOAAAADqAAABFAAAAS4AAAEuAAABLgAAAToAAAFcAAABaAAAAAAAAAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABRAAAAAABTAFoAAABgAAAAAAAAAGYAAAB4AAAAggAAAIqAAACOgAAAsQAAALUAAAC6AAAAAAAAAAAAAAAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAswAAALMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmAAAAAAAAAAMEGwHqAesB8QHyAfMB9AH1AfYAfwHtAgECAgIDAgQCBQIGAIAAgQIHAggCCQIKAgsAggCDAgwCDQIOAg8CEAIRAIQAhQIcAh0CHgIfAiACIQCGAIcCIgIjAiQCJQImAIgB7APwAIkB7gCKAlUCVgJXAlgCWQJaAIsAjACNAmMCZAJlAmYCZwJoAmkAjgCPAmoCawJsAm0CbgJvAJAAkQJ+An8CggKDAoQChQHvAfAAkgH3AhIAqQCqAvgAqwL5AvoC+wCsAK0DAgMDAwQArgMFAwYArwMHAwgAsAMJALEDCgCyAwsDDACzAw0AtAC1Aw4DDwMQAxEDEgMTAxQDFQC/AxcDGADAAxYAwQDCAMMAxADFAMYAxwMZAMgAyQNaAx8AzQMgAM4DIQMiAyMDJADPANAA0QMmA1sDJwDSAygA0wMpAyoA1AMrANUA1gDXAywDJQDYAy0DLgMvAzADMQMyAzMA2QDaAzQDNQDlAOYA5wDoAzYA6QDqAOsDNwDsAO0A7gDvAzgA8AM5AzoA8QM7APIDPANcAz0A/QM+AP4DPwNAA0EDQgD/AQABAQNDA10DRAECAQMBBAQGA14DXwESARMBFAEVA2ADYQNjA2IBIwEkBAsEDAQFASUBJgEnASgBKQQHBAgBKgErBAAEAQNkA2UD8gPzASwBLQQJBAoBLgEvA/QD9QEwATEBMgEzATQBNQNmA2cD9gP3A2gDaQQTBBQD+AP5ATYBNwP6A/sBOAE5AToEBAE7ATwEAgQDA2oDawNsAT0BPgQRBBIBPwFABA0EDgP8A/0EDwQQAUEDdwN2A3gDeQN6A3sDfAFCAUMD/gP/A5EDkgFEAUUDkwOUBBUEFgFGA5UEFwOWA5cBYgFjBBkEGAF3A/EBeQGSA1ADWANZAAAAAgBpBBQCHwYYAAUACgAAAQMjEzUzBQMjETMCHy9eAYz+1i9djAWN/ocBd42L/ocCBAAAAAIARgAABKIFsAAbAB8AAAEhAyMTIzUhEyE1IRMzAyETMwMzFSMDMxUjAyMDIRMhAsz++FCPUO8BCUb+/QEeUY9RAQhRkFHL5kbh+1CQngEIRv74AZr+ZgGahwFmiQGg/mABoP5gif6ah/5mAiEBZgABAG7/MAQRBpsAKwAAATQmJy4BNTQ2NzUzFR4BFSM0JiMiBhUUFhceARUUBgcVIzUuATUzFBYzMjYDWH+bz8m8qpWst7iAeHx5eabRwsu3lLDduaB4hpMBdl1/ND/GrajMFdrbGOnOjKh8bmV3OES/rK/IEr+/EdPZoIJ8AAAAAAUAaf/rBYMFxQANABsAKQA3ADsAABM0NjMyFh0BFAYjIiY1MxQWMzI2PQE0JiMiBhUBNDYzMhYdARQGIyImNTMUFjMyNj0BNCYjIgYVBScBF2mgioqhoImLoYtST01RUk5OUQI6oIqKoaCJi6GLUk9OUVJPTlH+EmgCx2gEmIKrq4JNgaqqgU1nZ01NTWlpTfzNgaurgU6CqqqCTWhnTk5NaGhN9kEEckEAAAADAET/6wTRBcUAIAArADgAABM0NjcuATU0NjMyFhUUBg8BAT4BNTMUBgcXIycOASMiJgUyNjcBBw4BFRQWAxQWFzc+ATU0JiMiBkSMj1BKvayfvmVmcwFcLC+mTEu+3VtTv2zc+wHXTI5A/o8qYTyQDzc4kDopYFJXWQGGfLRgYptUq7OxgmOLS1X+XkSdXIXcW+NsQEHgSzIyAbofSXw0dJID6Td0R2QnWTdAXXAAAAEAZwQjAP0GGAAFAAATAyMTNTP9OV0BlQWo/nsBdYAAAQCF/ioClQZqAA8AABMQADcXBgIRFRASFwcmABGFATW1Jo3KyY4mtv7MAk8BjwInZXhs/iz+nw7+n/4sdW9mAiQBkQABAAj+KgIYBmoADwAAARAAByc2EhE1EAInNxYAEQIY/su0J4vM0oUntAE1AkX+b/3cZm9rAd0BYg4BXAHfb29m/dn+cgAAAAABABwCYgNVBbAADgAAASU3BQMzAyUXBRMHCwEnAUr+0i4BLgmZCgEpLv7Nxny6tH0D2FuUcAFZ/qFwllz+8F0BIf7mWgAAAAABAE4AkgQ0BLYACwAAASEVIREjESE1IREzAp4Blv5quv5qAZa6Awus/jMBzawBqwABAB3+zAE0ANoACQAAJRQGByc+AT0BMwE0XFJpMC65RmTPR0hJkVWXAAAAAAEAJQIhAg0CtgADAAABITUhAg3+GAHoAiGVAAABAKIAAAFeAMUAAwAAISM1MwFevLzFAAABABL/gwMQBbAAAwAAFyMBM7GfAmCefQYtAAAAAgBy/+sEDAXFAA0AGwAAARACIyICGQEQEjMyEhEnNCYjIgYVERQWMzI2NQQM8dva9PLa2/O5i4qJioyJiokCLP7j/twBJQEcAVcBHAEm/tr+5CjEwMDE/lvEwsDGAAAAAQDXAAACuQWwAAUAACEjEQU1JQK5uf7XAeIE3Ah3ZQABAF0AAAQjBcUAGAAAKQE1AT4BNTQmIyIGFSM0NjMyFhUUBgcBIQQj/FYB3YRagXCckbn+6MbljIP+eQLLgwITkqdacpSakcP+4LV56ZD+VwAAAAABAF7/6wP6BcUAKAAAATMyNjU0JiMiBhUjNDYzMhYVFAYHHgEVFAQjIiQ1MxQWMzI2NTQmKwEBhqeKc36BeY659srO6m5wh27/AM7K/vy6koKFkISQpwMwhHiBgoh0reXTyl2wMCu2dcvf1cF3ioeKi4AAAAIAOQAABFEFsAAKAA8AAAEzFSMRIxEhNQEzASERIwcDhM3NuP1tAofE/X0BywMbAeiV/q0BU2sD8vw4AslGAAABAJr/6wQRBbAAHgAAGwEhFSEDPgE3NhIVFAIjIiY1MxQWMzI2NTQmIyIGB7FUAtX9xzAwclHK4+TlvPKvi3SEjI2AemwaApEDH6n+XCUtAgL+++Tg/vvHzXyDr5+Rs0ZMAAAAAgCH/+sEMwXFABoAJwAAATIWFwcuASMiBh0BPgEzMhIVFAIjIgAZARAAEyIGBxUUFjMyNjU0JgKfTJEyKDRpSqC/QaVjx+Pz0Nj+7wEwqWqRJaqGgIqSBcUiG5EaHvXOIjtB/vfV5f7oAS8BHgEfARsBU/1zVUpzztjMnJa6AAABAE0AAAQiBbAADAAAAQACAwcjNxoBEyE1IQQi/ve+KQ+6Dyvw2PziA9UFGv7B/hv+o5mZAWICFwEIlgADAGb/6wQYBcUAGAAkADAAAAEUBgceARUUBCMiJDU0Njc1LgE1NDYzMhYDNCYjIgYVFBYzMjYDNCYjIgYVFBYzMjYD8H9vgZX+/tba/wCRf2166cbD75Gif4Kdm4aBnimKbnCGh3FvhwQ1dakrLbh+zdHQzn65LAMpqXTEzM38lXuamXyAjY4DI3COiXVzhoYAAAAAAgBU/+sD/QXFABsAKAAAJTI2PQEnDgEjIgI1NAAzMgAZARAAIyImJzceARMyNjc1NCYjIgYVFBYB/5auAzCWXtfxAQLA5gEB/uroT5tCHT9+b3KUIZWSdJqOgNbaLAFJSgED8egBH/7q/uf+nP7g/tkcH5AeGAHfYE2cxcLMpaG+AAD//wCgAAABXQQ6ACYAEP4AAAcAEP//A3X//wBK/swBYQQ6ACcAEAAAA3UABgAOLQAAAQBIAMUDegRJAAkAAAEHFRcFFQE1ARUBQk9PAjj8zgMyApsUBBTpwQF7jwF6wQAAAgCYAZAD2gPNAAMABwAAASE1IREhNSED2vy+A0L8vgNCAy+e/cOeAAEAhgDGA9wESgAJAAATNQEVATUlNzUnhgNW/KoCXFJSA4+7/oaP/oW88hUDFgAAAAIAOgAAA28FxQAZAB0AAAE+ATc+ATU0JiMiBhUjPgEzMhYVFAYHDgEVEyM1MwFnAS1mZlRybmGAugLjtsbUiXg4FgjExAGZk2pddn5db3JlZKnAxbeE0HQ2VF7+Z8sAAAIAYf47BtgFlgAzAEMAAAEGAiMiJicOASMiJjcaATMyFhcHMwMGFjMyNjcSACEgAAMCACEyNjcXDgEjIAATEgAhIAABBhYzMjY3PAE3Ey4BIyIGBscJ2d9LaRY0jmKBhxIY4qhqekwEBjMJPzSAlAkR/sP+pv7E/ogQEgFOAURasUAlRctk/n3+aBITAcYBfAGEAYz78AxDT0RuLgIvGzwigYgB99r+zlROU0/tyAEIATMzNwT9uHJT4rUBhwGj/jj+hf6A/lAqJGgrLgHqAbkBrwIJ/hf985KVNUYQFQwCGg0Q2QAAAAACACcAAAUiBbAABwAKAAABIQMjATMBIwEhAwPY/ZuPvQIyoAIpvf1FAfj6AYT+fAWw+lACGQKyAAMAtgAABKkFsAAPABgAIQAAMxEhMhYVFAYHFR4BFRQGIwERITI2NTQmIyUhPgE1NCYjIbYB0+j9eWODlP7h/qUBW42ZgYn+iQFMc4eXlf7mBbDByGSYJAMbx4jLzwKt/eiFfoOSlQN3b3p1AAEAg//rBMkFxQAbAAABBgAjIgAZARAAMzIEFyMuASMiAhURFBIzMjY3BMkY/u/x/P7QATD89QENGLkZo6Wsx8espqIZAc3c/voBWAEUAQEBEwFa/eimqf73zP79zv73pKkAAAACALYAAATnBbAACQATAAAzESEgABEVEAAhAxEzMhI9ATQmI7YBuwEiAVT+qP7Q8PDo5uLaBbD+pv7kxf7i/qkFGvt7AQXbx9//AAAAAQC2AAAEdQWwAAsAAAEhESEVIREhFSERIQQP/WADBvxBA7X9BAKgAqb975UFsJb+IgAAAAEAtgAABHMFsAAJAAABIREjESEVIREhBA39YrkDvfz8Ap4CiP14BbCW/gQAAQCF/+sE2wXFAB8AACUOASMgABkBEAAhMgQXIy4BIyIGFREUFjMyNjcRITUhBNs0/c/+9/6zATcBAPgBCB+5GqOpr87kuIKiI/62AgO/UIQBSgEPASkBDwFJ7c6HnvnH/tXJ+0IsAVCVAAAAAQC2AAAE/QWwAAsAACEjESERIxEzESERMwT9uf0rubkC1bkChv16BbD9awKVAAAAAQDDAAABfAWwAAMAACEjETMBfLm5BbAAAQA//+sDwAWwAA8AAAEzERQGIyImNTMUFjMyNjUDB7nyx9XzuYqFco4FsPvkyOHS1IyFlIAAAAABALYAAAUcBbAADAAAASMRIxEzETMBMwkBIwIfsLm5nwIR1P3DAmbjApT9bAWw/XkCh/0+/RIAAAEAtgAABCUFsAAFAAAlIRUhETMBbwK2/JG5lZUFsAAAAQC2AAAGTQWwABAAAAkCMxEjERMjASMBIxMRIxEBpAHdAd7uuRMD/ht8/hwDE7kFsPtPBLH6UAJHAmP7VgSo/Z/9uQWwAAAAAQC2AAAE/gWwAAsAACEjASMRIxEzATMRMwT+uf0tA7m5AtMDuQR7+4UFsPuGBHoAAgCC/+sFDQXFAA0AGwAAARAAISAAGQEQACEgABEnNAIjIgIVERQSMzISNQUN/rv+9v7+/sYBOgECAQoBRbnavLTPz7S92QJX/vT+oAFgAQwBAQELAWL+nv71AskBBv76yf79y/76AQXMAAAAAgC2AAAExAWwAAoAEwAAAREjESEyFhUUBiMlITI2NTQmIyEBb7kCJO39/e3+lQFrnJWVnP6VAkr9tgWw68jK6ZWffX6hAAAAAgCC/wwFDQXFABMAIQAAARQCBxcHJQ4BIyAAGQEQACEgABEnNAIjIgIVERQSMzISNQUNfHPuf/7yL18z/v7+xgE6AQIBCgFFudq8tM/PtL3ZAleh/vtW3HP9DhABYAEMAQEBCwFi/p7+9QLJAQb++sn+/cv++gEFzAAAAAIAtQAABOIFrwAaACMAAAERIxEhMhYVFAYHHgEdARQWFxUjLgE9ATQmIyUhMjY1NCYjIQFuuQIK8/d5dXtpHiW/KBaMfP6RAT6vlZKf/q8Cev2GBa/PznKkMiirhIlGaSMYI4NGhXqPlYCFf4cAAAABAFr/6wSKBcUAJQAAATQmJy4BNTQkMzIAFSM0JiMiBhUUFhceARUUBCMiJDUzFBYzMjYD0JbH7P4BE+HxARi5rKSboKnI6u3+5evf/rW5056csAFuaIUxONClrd/+/raEnoVuYn8xO9ins9Loz5GRfgAAAAEAOwAABIoFsAAHAAABIREjESE1IQSK/jW5/jUETwUa+uYFGpYAAAABAJb/6wTXBbAAEQAAAREUBCMiJDURMxEUFjMyNjURBNf+0vv0/ty6vaGpxwWw/CXy+PjyA9v8JauqqqsD2wAAAQAnAAAFAgWwAAkAAAEXMzcBMwEjATMCciEEIQGCyP3jof3jyQFednYEUvpQBbAAAQBIAAAGwgWwABUAAAEXMzcBMwEXMzcTMwEjAScjBwEjATMB0x8DLAERpQETKwMhz7r+rqb+2x0DHf7Xpv6vuQHvysoDwfw/zMwDwfpQA/2RkfwDBbAAAAEAQQAABNAFsAALAAAJATMJASMJASMJATMChgFg3/4vAdzc/pb+l+AB3P4v3gNzAj39Lv0iAkj9uALeAtIAAAABAB4AAATTBbAACAAACQEzAREjEQEzAngBh9T9/rj+BdQCvgLy/FL9/gIPA6EAAAABAGEAAARtBbAACQAAJSEVITUBITUhFQE1Azj79AMU/PkD3pWVjQSNlogAAAEAkv7IAgsGgAAHAAABIxEzFSERIQILv7/+hwF5Ber5dJYHuAAAAAABACj/gwM4BbAAAwAAEzMBIyiwAmCwBbD50wAAAQAJ/sgBgwaAAAcAABMhESE1MxEjCQF6/obBwQaA+EiWBowAAQBAAtkDFAWwAAkAABMjATMBIwMnIwfsrAErfwEqq6sTBBMC2QLX/SkBqlVVAAAAAQAE/2sDmAAAAAMAAAUhNSEDmPxsA5SVlQAAAAEATwS7AeQFxQADAAABIwMzAeSY/eIEuwEKAAACAHL/7APsBE4AHwAqAAAhLgEnDgEjIiY1NDY7ATU0JiMiBhUjNDYzMhYVERQWFyUyNjc1IyIGFRQWAy0KCgI6rGerrfjc0XpxaYG57r+73wwQ/flopSXXgZRdM0IkTGGpmZ6sbmNvY0d9w7iy/fY6ajaLYEbHeVVLVAAAAgCR/+wEJQYYABIAIAAAARQCIyImJwcjETMRFz4BMzISESM0JiMiBgcRHgEzMjY1BCXbyW2cNRKgugMylmnL27mKkWF/Jid/YpGIAfXw/udSUpAGGP2gAUpN/sb+9sDqWk/+JVBaxqkAAAAAAQBh/+wD8gROABsAACUyNjczDgEjIgI9ATQSMzIWFyMuASMiBh0BFBYCQ2eXAbAB/6/u9PTuv+8BsAGOcKGHhoF4XJTVAS/tKuwBMNysaIrfpyqr3AAAAAIAZP/sA/AGGAASACAAABMQEjMyFhc3ETMRIycOASMiAjUzFBYzMjY3ES4BIyIGFWTazGSSNAO5oRA2mGnJ27mHkl56KSh8W5OIAgoBCgE6SEYBAlf56IdOTQEa76rFUkwB9khS6sAAAgBi/+wD6QROABUAHQAABSIAPQE0ADMyEh0BIR4BMzI2NxcOAQMiBgchNTQmAk7k/vgBD7/c3f0zBJ2RZZM7STu5pmmRFAIOgBQBJ/Qt7AEu/v7geabMODN7OksDzKmHGnmdAAEAQgAAAs4GLQAXAAAzESM1MzU0NjMyFhcHLgEjIgYdATMVIxHsqqqvoyJDKxcTMh1aVebmA62Ni6+5CwqRBQZoZYuN/FMAAAIAZv5MA/cETgAeACwAABMQEjMyFhc3MxEUBiMiJic3HgEzMjY9AScOASMiAjUzFBYzMjY3ES4BIyIGFWbezWqYNhKc8uRUs00vQpVMk4wDNJRkyt+5ipNeeyknfF2TjAIKAQoBOlJRj/vU1uwsKoohKZ2PaQFGRgEa76nGU04B8EpT678AAAABAJEAAAP6BhgAFAAAARc+ATMyFhURIxE0JiMiBgcRIxEzAUsDN6Jnsbu5dHdXiCy6ugOnAVBYzN39WwKnjYBSSPzmBhgAAAACAKEAAAFaBhgAAwAHAAAhIxEzESM1MwFaubm5uQQ6ARjGAAAC/7b+SwFnBhgADwATAAABERQGIyImJzceATMyNjUREyM1MwFnp5sgMh0ODzURRk+zubkEOvttqrIJCZYFCFpnBJMBHMIAAAABAJIAAAQUBhgADAAAASMRIxEzETMBMwkBIwHNgbq6fgE72/6GAa7bAfb+CgYY/HUBrf4T/bMAAAEAoQAAAVoGGAADAAAhIxEzAVq5uQYYAAEAkAAABnIETgAkAAABHwE+ATMyFhc+ATMyFhURIxE0JiMOAQcVESMRNCYjIgYHESMRATcNAzShcHGaJzSndam7um9xb4ALunJwYXcgugQ6kAFPVmVqYW7c6P12AoulhAGSbwH9TwKNnYpQSvzmBDoAAAAAAQCRAAAD+AROABQAAAEfAT4BMzIWFREjETQmIyIGBxEjEQE4DQM1o2uxvLpxeVuFKboEOqIBV2DI2/1VAqeVeFZN/O8EOgAAAgBg/+wEJwROAA0AGwAAEzQAMzIAHQEUACMiADUzFBYzMjY9ATQmIyIGFWABAOLkAQH/AOPk/wC6lJaUlpeVlJQCKPUBMf7P9Rj2/tIBLvax3t+wGK7i4q4AAAACAJH+YAQkBE4AEgAgAAABFAIjIiYnBxEjETMXPgEzMhIRIzQmIyIGBxEeATMyNjUEJNvJZ5Y1A7qfEjaaa8zbupCTW3smKHldko8B9fD+50NDAf3vBdqKTlD+x/71v+tQRv32R0zLqQAAAAACAGT+YAPmBE4AEgAgAAATEBIzMhYXNzMRIxEnDgEjIgI1MxQWMzI2NxEuASMiBhVk2sxkkzYPoLkDNI5gydu5h5JYdikpd1WTiAIKAQoBOklIffomAgoBQD8BGu+qykpGAhpCS+3BAAEAkQAAArEETgAQAAABJyIGBxEjETMfAT4BMzIWFwKYbFVuHrqmEgMtiFwYLw0DkwZOSfz+BDqdAVReBwQAAAABAGb/7APCBE4AJQAAATQmJy4BNTQ2MzIWFSM0JiMiBhUUFhceARUUBiMiJjUzHgEzMjYDCWSRyMHatsDcuXppbmlaks/D47/R6bkGlGdweQEeRFUfK5CBhra/kkpxXUNDSR8tlIGSrc2TbV5VAAAAAQAd/+wCTgVBABcAAAERMxUjERQWMzI2NxcOASMiJjURIzUzEQFy0NA2LxgxFRkaXS5xgJubBUH++Y39alA/BwaDERWNngKWjQEHAAEAjf/sA/YEOgAUAAAlJw4BIyImNREzERQWMzI2NxEzESMDQwMynm20wrpocXCJJLmmngFXXN30An39gbKDV1MDCvvGAAAAAAEALgAAA98EOgAJAAABFzM3ATMBIwEzAfIWAxcBAL3+cI3+bL0BOl1dAwD7xgQ6AAEAMAAABdgEOgAVAAABHwE3EzMTFzM3EzMBIwMnIwcDIwEzAaAbAyHaltojAyKvuP7GltYvAy3Sl/7GuQGGlgGXArT9TKSkArT7xgKbwcH9ZQQ6AAEALgAAA88EOgALAAABEzMJASMLASMJATMB/PDY/p8BbNX6+tgBbf6e1gKnAZP96f3dAZ7+YgIjAhcAAAEAG/5LA+QEOgAVAAABFzMBMwEOASMiJic3JhYzMjY/AQEzAdkmAwETz/42KZSEGEYUEwNOC0M+LjH+a88BhpADRPsfb58LBZUBBktrdQQkAAAAAAEAXgAAA7gEOgAJAAAlIRUhNQEhNSEVAT4CevymAlH9twMulZWFAx6XgQAAAQBA/pACngY9AB4AAAEuAT0BNCYjNTI2PQE0NjcXDgEdARQGBx4BHQEUFhcCeMSgZm5uZp/FJnNeUldXUl5z/pA4667Pc3yPenTQrus4cSWziNBrni0unmrPh7MlAAAAAQCv/vIBRAWwAAMAAAEjETMBRJWV/vIGvgAAAAEAE/6QAnIGPQAeAAAXPgE9ATQ2Ny4BPQE0Jic3HgEdARQWMxUiBh0BFAYHE3JgV19fV19yJsSgZW9vZaDE/iWzh89unCsqnm/QiLMlcTjqr9B0eo98c8+u6zgAAQCCAZME7wMhABkAAAEUBiMiJicuASMiBhUnNDYzMhYXHgEzMjY1BO+qg1uOWjxhNEZfh6eFWpJXPGA1RWEC5IvGQUsyMGpPEoq9REg1LXJRAAAAAgCQ/ooBTQQ6AAMABwAAASMRMxMjNTMBS7m5Ar29/ooD0gESzAAAAAEAbv8LA/8FJgAhAAAlMjY3Mw4BBxUjNSYCPQE0Ejc1MxUeARcjLgEjIgYdARQWAlBnlwGwAcqWurq8vLq6oMABsAGOcKGHhoF4XILIGOjsIwEfzyrNAR8l494Y0phoit+nKqvcAAAAAQBGAAAEUQXFACEAAAEXFAYHIQchNTM+ATUnIzUzAzQ2MzIWFSM0JiMiBhUTIRUBqQYhIALjAfw2CjQyBqqkCtu+ytW6fWhpdgoBpwJqmF2jPZWVDcVrmJUBEdDlz7R8cZSL/u+VAAACAGn/5QVbBPEAIwAvAAAlDgEjIiYnByc3LgE1NDY3JzcXPgEzMhYXNxcHHgEVFAYHFwcBFBIzMhI1NAIjIgIET0+5aGm3ToaCjDQ1OTiUgpNMsWRksU6VhJg2OTUxj4T8YPS0svT0srT0cEFDQkCIhY5Os2ZpuVGXhpY7PT47mIebULdoZLJOkYYCe8P++AEIw8EBB/75AAEAIAAABKsFsAAWAAAJATMBIRUhFSEVIREjESE1ITUhNSEBMwJmAXHU/loBP/57AYX+e7n+gwF9/oMBPv5Z1QMNAqP9L3irdv66AUZ2q3gC0QAAAAIAk/7yAU0FsAADAAcAABMRMxkBIxEzk7q6uv7yAxb86gPIAvYAAAACAFr+EQR4BcUAMQBDAAABFAYHHgEVFAQjIiQ1NxQWMzI2NTQmJy4BNTQ2Ny4BNTQkMzIEFSM0JiMiBhUUFhceASUuAScOARUUFhceARc+ATU0JgR4YFtJRv785OH+17rDjY+fjdL13l5aR0QBBuPsAQC5oZKZloPa+dv94jROIlBMh9sxTCNPVJIBr2CJKTSFZa7Ay+QClYZ3X19jQEGztF2LKjOHZKjG3dJ7nndfZ2E8Ra9UDRgOE2NJaGU9DhgMFGNIXmoAAAIAqQTsA1IFsAADAAcAAAEjNTMFIzUzA1LT0/4r1NQE7MTExAAAAAADAFv/6wXmBcQAGwAnADMAAAEUBiMiJj0BNDYzMhYVIzQmIyIGHQEUFjMyNjUlEAAzMgAREAAjIgADEAAhIAAREAAhIAAEX62eori4op6ukltfY2dnY19a/QEBVv37AVf+qfv9/qpzAZgBLgEsAZn+Z/7U/tL+aAJUnpzRsnew052cY1eNdnh5jFZmhf7w/pcBaQEQAQ4BZ/6Z/vIBQQGq/lb+v/6+/lQBqwAAAgB6ArQDDwXFAB8AKgAAAS4BJw4BIyImNTQ2OwE1NCYjIgYVJzQ2MzIWFREUFhclMjY3NSMiBhUUFgJqCAoDInBQeYCko5E9P0hMoaeOh5gMDv6LN24TkE9WPALCFTAaMTx4bG92NUNFNzUOaIGMiP7GM1creTsmckIwMDEAAP//AGYAdwNkA5EAJgFy+t0ABwFyAUT/3QABAH8BeAO+Ax8ABQAAASMRITUhA766/XsDPwF4AQifAAQAWv/rBeUFxAALABcAMgA7AAATEAAhIAAREAAhIAATEAAzMgAREAAjIgABESMRITIWFRQGBx4BHQEUFhcVIy4BPQE0JiMnMz4BNTQmKwFaAZgBLgEsAZn+Z/7U/tL+aHMBVv38AVb+qvz9/qoBwI0BFJqoQkBDOgcKkQoEQ1CjnEVbTmeHAtkBQQGq/lb+v/6+/lQBqwFD/vD+lwFpARABDgFn/pn+qf6sA1KAgD9dIBtoTDgqQBUQFk8rNktDfgE/O0w7AAAAAQB4BSMDQgWwAAMAAAEhNSEDQv02AsoFI40AAAIAggPBAnwFxQALABcAABM0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBoKUa2mSkmlrlH1KODdJSTc3SwTBbJiYbG2Tk205SUg6OktMAAACAGEACQP1BPMACwAPAAABIRUhESMRITUhETMBITUhAooBa/6Vp/5+AYKnAUz8vQNDA1aW/mEBn5YBnfsWlQAAAQBxApsCxgXHABgAAAEhNQE+ATU0JiMiBhUjNDYzMhYVFAYPASECxv20AS9ILDo/SEqhpI+IlFd1qAF6Apt+AQg+Siw0P0E1aYx9dlBtbJIAAAAAAQBpAo8C4AXGACgAAAEyNjU0JiMiBhUjNDYzMhYVFAYHHgEVFAYjIiY1MxQWMzI2NTQmKwE1AadIQUlKO0qip4CSo0U/SEqwk4C0o01ETVRKTYMEbzo2LjoyKmV2dXA4WhoYXUZxenR1MTo7M0E5egAAAAABAIEEvAIeBcYAAwAAATMBIwE94f7wjQXG/vYAAQCa/mAD7gQ6ABYAAAERFBYzMjY3ETMRIy8BDgEjIiYnESMRAVNxa2p7ILqmCgMrgVhMbiq5BDr9kcOITUwDIfvGbgFBQyIo/isF2gAAAAABAEIAAAM/BbAACgAAIREjIiY1NBIzIREChVfu/v/tARECCP/V0wEB+lAAAAEAogJwAWEDQQADAAABIzUzAWG/vwJw0QAAAAABAHT+TQGqAAAADwAAIQceARUUBiMnMjY1NCYnNwEdDENWm5QHSlxIWiA1C1BSYXBqMTMyJgeGAAEAXgKZAYQFxQAFAAABIxEHNSUBhKSCASYCmQKUAYIXAAAAAAIAegKzAycFxQANABsAABM0NjMyFh0BFAYjIiY1MxQWMzI2PQE0JiMiBhV6t5+gt7afoLijWltYWltZWVoEdpa5uJd1mLa3l1tra1t1WGxsWAAA//8AbwCZA3gDtAAmAXMWAAAHAXMBagAA//8AtAAABdwFxAAnAckAVgKYACcBdAEVAAgABwGXArgAAAAA//8AtAAABe4FxAAnAXQBIgAIACcByQBWApgABwHKAygAAAAA//8AewAABp0FxwAnAXQB0QAIACcBlwN5AAAABwHLABICmwAAAAIAcf52A6YEOwAZAB0AAAEOAQcOARUUFjMyNjczDgEjIiY1NDY3PgE1AzMVIwJ6Ai1mZ1Nxb2CBAbkD47XH04h5NxcIxMQCoZRpXXd9XG9yZWSpwMW3gtB1NVRfAZrMAAL/8gAAB1cFsAAPABMAACkBAyEDIwEhFSETIRUhEyEBIQMjB1f8jQ/9zM3iA3ADt/1NFAJO/bgXAsD6rQHKHwMBYv6eBbCW/iaV/eoBeQLcAAAAAAEAWQDiA90EdgALAAATCQE3CQEXCQEHCQFZAUr+uHcBSQFJd/63AUt3/rX+tQFcAVEBT3r+sQFPev6x/q96AVH+rwAAAwBz/6ME/gXsABkAJAAvAAABEAAhIiYnByM3LgE1ERAAITIWFzczBx4BFQEUFhcBLgEjIgIVITQmJwEeATMyEjUE/v67/vZWlUJdj4xWWQE6AQJip0lUj4ZOUvwuKSoCLDR9S7TPAxkkIv3XLmtAvdkCV/70/qAqKpzqV+iLAQEBCwFiNTKO4Ffcgf7/WJg9A6UsLv76yU2JO/xhIyMBBcwAAAACAKYAAARdBbAADAAVAAABESEyFhUUBiMhESMRExEhMjY1NCYjAWABFer+/ur+67q6ARWZlZWZBbD+2ujAwef+xgWw/kX92px1dp8AAQCL/+wEagYPACcAACEjETQ2MzIWFRQGFRQAFRQGIyImJzceATMyNjU0ADU0NjU0JiMiBhUBRLniuqHEgAFez7JTsSgrKoNAcmr+oopnRW5/BDrh9Kiod9g8VP7ojqmlKx2ZHS9eUlcBGpRT2U5fa6ScAAADAD3/6wZ8BE4ALAA3AD8AAAUiJicOASMiJjU0NjsBNTQmIyIGFSc0NjMyFhc+ATMyFh0BIR4BMzI2NxcOASUyNjc1IyIGFRQWASIGByE1NCYE7ovKQznao6224d/qaWdvfbjiwnWsMkGuadji/S4EnaNqhkxAObX8SFCnLOiAiWcDZXeNEAIVexVhXVJsq5miqlVweG5SEpC0UlJQVP/ndarJODOFL0yVWDrfcVVOXQM4q40ffpsAAgBM/+sELQXtACAAMAAAARYSHQEUACMiADU0ADMyFhc3LgEnBSc3LgEnNx4BFzcXAzQmNS4BIyIGFRQWMzI2NQNTanD+59rd/u8BDtpXlzkDF1Y+/utJ+iZPKzlMhj3sSbgBJKB7jKOnkoyqBQd8/rvOYfr+zgET0+oBFkA3AWqmQZ5jjxgnEJ4XRTGHY/z2CCIJPVHPm4jJ47QAAwBHALcELQSvAAMABwALAAABITUhJSM1MxEjNTMELfwaA+b+bb29vb0CWrTax/wIxwAAAAMAYP95BCcEuQAZACQALwAAEzQAMzIWFzczBx4BHQEUACMiJicHIzcuATUzFBYXAS4BIyIGFSE0JicBHgEzMjY1YAEA4jpmMEp7aFpe/wDjNVsrSXtkZGW6LC8BVx9EJ5SUAlQnJ/6uGjkjlJYCKPUBMRcVl9JL5JAY9v7SERGVy0nqmWCbNwK3ERLirlaROP1SDQvfsAAAAgCa/mAELQYYABMAIQAAARQCIyImJwcRIxEzERc+ATMyEhEjNCYjIgYHER4BMzI2NQQt28lnljUDurkDNJZmzNu6kJNbeicoeV2SjwH18P7nQ0MB/e8HuP2oAUZJ/sf+9b/rUEb99kdMy6kAAgAeAAAFiQWwABMAFwAAATMVIxEjESERIxEjNTMRMxEhETMBITUhBPeSkrn9K7mSkrkC1bn8cgLV/SsEjY38AAKG/XoEAI0BI/7dASP9a+UAAAAAAQCbAAABVQQ6AAMAACEjETMBVbq6BDoAAQCaAAAEPwQ6AAwAAAEjESMRMxEzATMJASMBvmq6ulsBjd/+NwHt6QHP/jEEOv41Acv9+P3OAAABACYAAAQVBbAADQAAASUVBREhFSERBzU3ETMBXwEU/uwCtvyRgIC5A0dYn1j97ZUCbSifKAKkAAEAIwAAAgsGGAALAAABNxUHESMRBzU3ETMBcZqauZWVuQNnO6A7/TkCgDmgOQL4AAEApP5LBO0FsAAYAAABERQGIyImJzceATMyNj0BASMRIxEzATMRBO2omyAzHQ4OQhJCSP0tA7q6AtMDBbD596qyCQmRBQhnX1kEb/uRBbD7kQRvAAEAkf5LA/AETgAgAAABHwE+ATMyFhURFAYjIiYnNx4BMzI2NRE0JiMiBgcRIxEBNw0DNZ5psbynmyA1Hg4OQxRCR3N5XH0nugQ6lQFRWcnc/P6qsgkJmgUHX10C/pZ5RkH80wQ6AAAAAgBp/+sHOAXFABcAJQAAKQEOASMiABkBEAAzMhYXIRUhESEVIREhBTI2NxEuASMiBhURFBYHOPyCXoFF/f7QAS79R45RA3T9BAKg/WADBvteOHE6OnE6scHDCgsBRgEPATABDgFHDAmW/iKW/e8VCAkEjQgK49v+ztzkAAMAYf/rBwAETgAhAC8ANwAAEzQSMzIWFz4BMzISHQEhHgEzMjY3Fw4BIyImJw4BIyIANTMUFjMyNj0BNCYjIgYVASIGByE1NCZh/+OHyEBCwnHc3f0yBJ2QZ5U4Sjy6iIfMQEHFheT/ALmVlpSVlpWVlAQtapEUAg6AAij1ATFxaGdy/v3feabNOTN7O0ttZ2dtAS/2sd/fsRiv4eKuAZCphxp5nQAAAAEAoAAAAoIGLQAPAAAzETQ2MzIWFwcuASMiBhURoLCjIkMqFxUsGltcBMWwuAsKjAUGbWX7OwAAAf/k/ksCvAYtACMAAAEjERQGIyImJzceATMyNjURIzUzNTQ2MzIWFwcuASMiBh0BMwJgy6ebIDMcDg5AE0FHq6uvoyJDKhYUMhxaVcsDrfv6qrIJCZEFCGdfBAaNi6+5CwqRBQZoZYsAAAAAAgBx/+sFnQY2ABcAJQAAARAAISAAGQEQACEyFhc+ATUzFAYHHgEVJzQCIyICFREUEjMyEjUE/P67/vb+/v7GAToBAnrKUGFUp32ALS+52ry0z8+0vdkCV/70/qABYAEMAQEBCwFiUUwKhn6jwyBMrGACyQEG/vrJ/v3L/voBBcwAAAAAAgBg/+wEugSwABcAJQAAEzQAMzIWFz4BNTMUBgceAR0BFAAjIgA1MxQWMzI2PQE0JiMiBhVgAQDia6hBVziVZHUjI/8A4+T/ALqUlpSWl5WUlAIo9QExR0QIcnOUqRpCmFcY9v7SAS72sd7fsBiu4uKuAAABAJb/6wYmBg0AGQAAARU+ATUzFAYHERQEIyIkNREzERQWMzI2NREE115Kp5+w/tL79P7cur2hqccFsM0WkITG1xb9e/L4+PID2/wlq6qqqwPbAAABAI3/7AUQBJEAHAAAARQGBxEjLwEOASMiJjURMxEUFjMyNjcRMxU+ATUFEHqgpg0DMp5ttMK6aHFwiSS5YDUEkaWbCfy4ngFXXN30An39gbKDV1MDCooJYnYAAAH/tP5LAWUEOgAPAAABERQGIyImJzceATMyNjURAWWnmx8yHg4OQBNBSAQ6+22qsgkJkQUIaF4EkwAAAAIAYv/sA+kETwAVAB0AAAEyAB0BFAAnIgI9ASEuASMiBgcnPgETMjY3IRUUFgH/4gEI/vG/3dwCzQWdjmmUOEk7uqVpkBX9838ET/7X8y3t/tMBAQHgeaXOOjN8Okz8M6eIGXqcAAAAAQCpBOQDBgXpAAgAAAEVIycHIzU3MwMGmZaVmfR0BPwYlpYZ7AAAAAEAjATkAvcF6QAIAAABNzMVByMnNTMBwJWi/nP6ngVTlhLz8RQAAAABAIEEpQLYBbAADQAAARQGIyImNTMUFjMyNjUC2KCLjKCXRk9NSAWwepGRekRSU0MAAAAAAQCgBOoBbwWwAAMAAAEjNTMBb8/PBOrGAAAAAAIAiwRfAhwF4AALABcAABM0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBot0VlRzclVXc2M8Kys5OSsrPAUeVG5uVFZpaVYsOzotLTw8AAABADL+UAGSADcAEwAAIQ4BFRQWMzI2NxcOASMiJjU0NjcBflNYIysdLxgNIEo2V2mAhz1lPCQmEAx4ExliW1aYPAAAAAEAggTiAzQF8QATAAABFAYjIiYjIgYVJzQ2MzIWMzI2NQM0dFtJlzUsOmhyXDukNis8BdJff19BMBpehWBBMQACAGgE5ANIBe4AAwAHAAABMwEjAzMDIwJn4f7OqUfO9pYF7v72AQr+9gAAAAIAtv6HAen/qwALABcAABc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBrZZQ0BXV0BDWVcnHhsmJhseJ+lBU1NBQFBQQBslJBweJiYAAAAB/NoEuv4HBhMAAwAAASMDM/4HfbCxBLoBWQAAAf13BLv+pAYUAAMAAAEzAyP99625dAYU/qcA///8kwTi/0UF8QAHAKD8EQAAAAAAAf1eBNn+lAZzAA8AAAEnPgE1NCYjNzIWFRQGDwH9dAFQQVpMB5SbVkUBBNmXBR8nKSZpZFdISAlGAAAAAvwnBOT/BwXuAAMABwAAASMBMwEjAzP+Aqn+zuEB/5b2zgTkAQr+9gEKAAAB/UP+sf4S/3YAAwAAASM1M/4Sz8/+scUAAAAAAQDDBPgBygZ4AAMAAAEzAyMBAsitWgZ4/oAAAAMAoQTtA1wGiAADAAcACwAAASM1MwUjNTM3MwMjA1zAwP4GwcF/036FBO3Dw8PY/vgAAP//AKICcAFhA0EABgB2AAAAAQC1AAAEMAWwAAUAAAEhESMRIQQw/T65A3sFGvrmBbAAAAAAAgAgAAAFbQWwAAMABgAAATMBITchAQKJoQJD+rP7A1v+YQWw+lCVBDcAAAADAHP/6wT+BcUAAwARAB8AAAEhNSEFEAAhIAAZARAAISAAESc0AiMiAhURFBIzMhI1A8D9/AIEAT7+u/72/v7+xgE6AQIBCgFFudq8tM/PtL3ZApSW0/70/qABYAEMAQEBCwFi/p7+9QLJAQb++sn+/cv++gEFzAABADQAAAUCBbAABwAAASMBIwEzASMCnQT+Wb4CFqICFr4EqPtYBbD6UAAAAAMAegAABCAFsAADAAcACwAANyEVIRMhFSEDIRUhegOm/FpVAvP9DVMDlvxqlZUDPJYDCpYAAAAAAQC2AAAE/wWwAAcAACEjESERIxEhBP+5/Sm5BEkFGvrmBbAAAQBFAAAERAWwAAwAAAkBIRUhNQkBNSEVIQEC7v46Axz8AQHl/hsDzf0XAcUCzv3Ilo4CTQJHjpb9zQAAAwBOAAAFbAWwABUAHgAnAAABMzIAFRQAKwEVIzUjIgA1NAA7ATUzAyIGFRQWOwERMxEzMjY1NCYjAzoF9AE5/sbzBboH9P7JATf0B7rBtL++tQe6B7LAwLIE9v7T9PX+0bGxAS319AEvuv6x1Lq70gMb/OXUu7nTAAAAAAEAXQAABRgFsAAXAAABPgE1ETMRFAAHESMRJgA1ETMRFBYXETMDD52zuf7n8Lrp/vG4qpa6AgEX1LICEv3u+v7dF/6WAWoYASL6AhL97rHTGQOvAAEAcgAABM0FxQAjAAAlNhIRNTQmIyIGHQEQEhcVITUzJgI9ARAAMzIAERUUAgczFSEC4ZCfw7CxwaOT/hXwc4EBLv38ATGBcvb+FJsbARwBAXbu+Pjudv7//uMam5VjAS+sdAEhAV3+o/7fdKz+0WOVAAAAAgBk/+sEdwROABwAKgAAAREUFjMyNjcXDgEjIiYnDgEjIgI9ARASMzIWFzcBFBYzMjY3ES4BIyIGFQPuKiYJEgcXHTkkSlsUNppsydvazGiYNhH9zIeSXXkpKXlbk4gEOvzsV0EDA4gTDkxYUlIBG+8VAQoBOlFPjP27qstgWgHBWmPtwQAAAAIAoP5/BE0FxAAUACoAAAEyFhUUBgceARUUBiMiJicRIxE0JBMyNjU0JiMiBhURHgEzMjY1NCYrATUCXcXnYll7hPjOVps8ugEDtoF2f3Rxki2QXYmXiHiPBcTXsV2XLyzChNTnLjH+NAWxqur9lHpuYoyPb/zENzydhXWrlQAAAQAu/mAD3wQ6AAsAAAEzAREjEQEzARczNwMivf6Fuv6EvQEHFgMXBDr7//4nAeAD+v0AXV0AAAACAGD/7AQnBhwAIQAvAAATNDYzMhYXBy4BIyIGFRQWFxYSHQEUACMiAD0BNDY/AS4BExQWMzI2PQE0JiciBhXdxrRNm1ApPYxKWGNihdjQ/wDi5f8Au4wEZWk+lJaTlaODlZcE9oqcLSiAGCNIQDNdLEv+7s4X7f7dASPtF7D4Igsni/1iqNTUqBeH3BrXpgABAGP/7QPsBEwAKQAAASIGFRQWMzI2NTMUBCMiJjU0Njc1LgE1NDYzMhYVIzQmIyIGFRQWOwEVAhuBfIx9eJS5/va7zfdlZFdf5M26+bmPa3x7cHvNAeBVW01kcFCpqamaXn0gAyN3S5mgrZJKYmBGTVaQAAEAbf6BA8MFsAAgAAABFQEOARUUFh8BHgEVDgEHJz4BNTQmLwEuATU0EjcBITUDw/6igm5HWYGXbAJvQGIzL0dSWrKHhZIBGf2BBbB2/lKa4JFkYRMmLENtSqg0UzpRLCQyFhcvn6B6ATisAUCWAAABAJH+YQPwBE4AFAAAAR8BPgEzMhYVESMRNCYjIgYHESMRATcNAzWeabS5uXR4XH0nugQ6lQFRWcDl+7gERJd8SEL80gQ6AAADAHr/6wQUBcUADQAWAB8AAAEQAiMiAhkBEBIzMhIRBSE1NCYjIgYVASEVFBYzMjY1BBTx29r08trb8/0fAiiLiomKAij92IyJiokCLP7j/twBJQEcAVcBHAEm/tr+5GOLxMDAxP7ghcTCwMYAAAAAAQDD/+sCawQ5AA8AAAERFBYzMjY3Fw4BIyImNREBfDcyGS4WKS1UNHt4BDn81E85DQyAHhWLoQMiAAAAAQAl//AEOwXuACEAADMjAScuASMiBiMnPgEzMhYXAR4BMzoBNxcOASMiJicDIwfzzgGKYBg0LQocCQERRhplXh0BsxQtJA0SBwYOKhZiZi/vAyAEBes6LgKMBAhQWPuoNSsClAQIT38CZ3wAAQBl/ncDqQXDADEAAAEuASMiBhUUFjsBFSMiBhUUFh8BHgEVDgEHJz4BNTQmLwEuATU0Nj8BLgE1NCQzMhYXA3I/azeal5qrjY3CxJ59a5B0AW9AYjkoRVY35N2hlQF2gAED50SIMQUKERNrUmpylp2mgJUcFyJLbUmkNlNCQTYrKxINNMDUlsYuAymWYaSyFhEAAAEAT//rBM4EOgAXAAABIxEUFjMyNjcXDgEjIiY1ESERIxEjNSEEXX43MhkuFiktVDR7eP5luoIEDgOk/WlPOQ0MgB4Vi6ECjfxcA6SWAAAAAgCR/mAEHwROABEAHwAAARQCIyImJxEjETMnNBIzMhIRIzQmIyIGFREeATMyNjUEH9fIZpc4ugEB+8Tl6rmFkYOCKHldkYwB9fD+5z0//fgD4gL7AQ/+yf7zwuzlkf7SR0zLqQAAAAABAGX+igPhBE4AIQAAATIWFSM0JiMiBh0BFBYXHgEVDgEHJz4BNTQmJy4BPQE0EgI9vuavfneQj661m3oCbj9iOChDWfTw+gROzrpshuWhKo23MCtObkinNFNBQTYtKhQ0/tYq6AE0AAIAYP/sBHkEOgARACAAAAEhBx4BHQEUACMiAD0BNAAzIQEUFjMyNj0BNCYrAQ4BFQR5/usBX2X+/N/k/wABAOICN/yhlJaUlpeVAZSTA6MDSNCFF9j+2AEu9hjsASb91rHe37AYpdYB1aUAAAEAUf/rA9kEOgATAAABIREUFjMyNjcXDgEjIiY1ESE1IQPZ/o03MhkuFiktVDR7eP6kA4gDpv1nTzkNDIAeFYuhAo+UAAAAAAEAj//rA/YEOgAVAAABERQWMzISNS4BJzMeARUUAiMiJjURAUlqX42eA0A4wzM+8OvBywQ6/W+djAEDroH8jG79nv3+t9fpAo8AAAACAFf+IgVMBDoAGQAjAAAFJAI1NBI3Fw4BBxQWFxE0NjMyABUUAAURIxM+ATUuASMiBhUCbP7p/n+BZVdQBKS3iHPMARn+9/7iubm9sQScjCAiERkBO/CsAQNYg0vIcaLwGwLSaHr+z+nn/s0X/jMCZBnnmqHiKRwAAAAAAQBf/ikFQwQ6ABsAAAERPgE1LgEnMx4BFRQABREjESYAGQEzERQWFxEDHL+vA0I6wjVB/vv+3rn8/vi6rZ0EOfxNGvOlgPmJbfmc9v7CFv47AccZASgBIwHm/hjZ2hgDsgAAAAEAev/rBhkEOgApAAABDgEHFBYzMjY1ETMRFBYzMjY1LgEnMx4BFRACIyImJyMOASMiAhE0NjcBxENLA2h0Z3a7dWhzaQRLQsM9SrzPeaIoAymieNC7ST4EOon/g8LtobYBK/7VtqHsw4P/iW/9n/7+/r51dXV1AUIBAp//bQAAAgB0/+sEqQXFABkAJAAAJTI2NyYkPQE0NjMyFhUREAAjIgAZATcRFBYTFBYXETQmIyIGFQKFrL4B3v76uJeesP7X+/D+37q24puPSktGT4br2An2xD6wy8e0/gL+5f66AVQBDQKYAv1mzfkDhH2hCAFmcW5ucQAAAf/nAAAEWQW7ACMAAAE+ATMyFhcHLgEjIgYHAREjEQEuASMiBgcnPgEzMhYXExczNwLsNHhTIjIaFwYXDyQ5FP7XuP7WFTkjEBYFFxgxI1N3NrQXAxcE139lCg6SAwUkLf18/bwCRAKELSQFA5IOCmV//mhUVAAAAgBK/+sGGwQ6ABcALQAAASMeARUQAiMiJicjDgEjIgIRNDY3IzUhAS4BJyEOAQcUFjMyNj0BMxUUFjMyNgYbiR8irLt5oicEKKF4vKshIHUF0f7+Aygk/LwlKAJYYGd1u3RpXlgDo1W1av7+/r52dXV2AUIBAmq1VZf99V23YGK2XMLtobb8/Lah7AABACv/9QWwBbAAGwAAASERPgEzMgQVFAYjJzI2NS4BIyIGBxEjESE1IQSV/fNSmTn4AQz49QKojgKkpUKaSLr+XQRqBRr+LBce7N/Z4o+Zk5aWGhf9VQUalgAAAAEAh//sBM0FxgAfAAABBgAjIgAZARAAMzIEFyMuASMiAh0BIRUhFRQSMzI2NwTNGP7v8fz+0AEw/PUBDRi5GaOlrMcCO/3Fx6ymohkBztz++gFYARQBAQETAVr96Kap/vfMMJU+zv73pKkAAAIAMgAACEUFsAAWAB8AAAERITIWFRQGIyERIQMKASsBNTMyEhsBAREhMjY1NCYjBPQBaOz9/ez93v3/AwTO/zMonIMEBANzAWialpaaBbD9xfLJyfEFGv3r/mP+mJUBFwFZAqv9MP21qH98qAAAAAACALUAAAhPBbAAEgAbAAABIREzESEyFhUUBiMhESERIxEzAREhMjY1NCYjAW4C17kBaO38/ez93/0pubkDkAFonJWVnAM3Ann9lt/AwOcCov1eBbD9Af3ulXV0lAAAAAABAEAAAAXWBbAAFwAAASERPgEzMhYVESMRNCYjIgYHESMRITUhBKv961CeavT0uY6hXKRYuf5jBGsFGv5DFRXP8f45AceqgBYV/ToFGpYAAAEAtf6aBP4FsAALAAATMxEhETMRIREjESG1uQLXuf4/uf4xBbD65QUb+lD+mgFmAAIApgAABLEFsAAMABUAAAEhESEyFhUUBiMhESEBESEyNjU0JiMEIf0+AWju/P3t/d8De/0+AWiclJScBRr+PuHHyOgFsP0T/dKffnmYAAAAAgA0/poFyQWwAA4AFQAAJTMRIxEhESMRMzYSGwEhAQYCByERIQUIwbn73bl5T4MIIANh/ToJaFQC0v4Jlf4GAWX+mgH7WgFOAS0CRv269/6WdASFAAAAAAEAGwAABygFsAAVAAABIxEjESMBIwkBMwEzETMRMwEzCQEjBJ2buaL+XOgB7v472QGGprmfAYbZ/joB7ucCn/1hAp/9YQMAArD9hAJ8/YQCfP1R/P8AAAABAFH/6wRnBcUAKAAAATI2NTQmIyIGFSM0JDMyBBUUBgceARUUBCMiJDUzFBYzMjY1NCYrATUCXqSWoqWErrkBGNPyAQ58coGD/t3z1f7VubOUprenqaUDMYN3dJCObrja08topDArqoHM3tTVd52VfIqAlgAAAAABALYAAAT+BbAACwAAATMRIxEjASMRMxEzBEW5uQP9Lbm5AwWw+lAEb/uRBbD7kgABADAAAAT0BbAADwAAAREjESEDCgErATUzMhIbAQT0uv3xEQ677jMojHEMFgWw+lAFGv3r/l3+npUBEQFfAqsAAQBR/+sEyAWwABQAAAEXATMBDgEjIiYnNx4BMzI2PwEBMwJOSwFY1/38PIiaGUEKBgpAEktCKCr+DtAC+8MDePtAhIEGA5ACAkpSVgQ+AAADAFP/xAXjBewAFQAeACcAAAEzIAAREAAhIxUjNSMgABEQACEzNTMDIgYVFBY7AREzETMyNjU0JiMDeBsBAgFO/rL+/hu5Hf79/rQBTAEDHbnWxtHRxh25HcTS0sQFHv69/vv++f67xsYBQwEHAQUBRc7+nenMzucDavyW6c7L6AAAAAABALT+oQWSBbAACwAAEzMRIREzETMDIxEhtLkC17mVEqX72QWw+uUFG/rp/ggBXwABAJcAAATEBbAAEwAAAREjEQ4BIyImNREzERQWMzI2NxEExLlhsHv187qMomm8ZwWw+lACYR0azvIBxv46q38cHAK4AAEAtAAABtIFsAALAAABESERMxEhETMRIREBbgH6uQH4ufniBbD65QUb+uUFG/pQBbAAAAABALT+oQdrBbAADwAAAREhETMRIREzETMDIxEhEQFuAfq5Afi5mRKm+gEFsPrlBRv65QUb+uX+DAFfBbAAAAAAAgARAAAFuAWwAAwAFQAAEyERITIWFRQGIyERIQERITI2NTQmIxECVQFo7vz97f3f/mQCVQFonJSUnAWw/ajhx8joBRv9qP3Sn355mAAAAAADALUAAAY1BbAACgATABcAAAEhMhYVFAYjIREzGQEhMjY1NCYjASMRMwFuAWju/P3t/d+5AWiclJScA1+5uQNY4cfI6AWw/RP90p9+eZj9PQWwAAACAKYAAASxBbAACgATAAABITIWFRQGIyERMxkBITI2NTQmIwFfAWju/P3t/d+5AWiclJScA1jhx8joBbD9E/3Sn355mAAAAAABALH/7AT2BcYAHwAAEzQAMzIAGQEQACMiADUzFBYzMhI9ASE1ITU0AiMiBhWxAST2+wEw/tD7+/7hubWsq8f9uwJFx6ustQPf1QES/qb+7f7//uz+qAEB46CvAQjNOJU2zgEJsKEAAAIAw//rBt4FxQAVACMAAAEQACEgABE1IxEjETMRMzUQACEgABEnNAIjIgIVERQSMzISNQbe/rv+9v7+/sbXubnXAToBAgEKAUW52ry0z8+0vdkCV/70/qABYAEMKP2BBbD9ZEQBCwFi/p7+9QLJAQb++sn+/cv++gEFzAACAGMAAARnBbAADQAWAAAhIwEuATU0JDMhESMRIQEhIgYVFBYzIQEoxQFVkJABC/UBz7r+qwFV/uujpKSdARsCbzbDktTi+lACPALeloiHowAAAAACAGH/6wQoBhEAGwApAAABMhIdARQAIyIAPQEQADc+ATUzFAYHDgEHFz4BFyIGHQEUFjMyNj0BNCYCZ9Pu/wDj5P8AAQPmhnOYsLqNwx4DRrJFlJSVlZSWlwP7/vLbGOz+3QEj7IgBSgF3KxlASrFxHhipqgJGUZXAlBin09OnGJTAAAADAJ0AAAQpBDoADwAYACEAADMRITIWFRQGBxUeARUUBiMBESEyNjU0JiMlMz4BNTQmKwGdAabY51lUZW/Yyf7OATJ0c3N0/s77fXuChO0EOpKXTnUfAxiHWpqZAdz+t1RRUFSSAUxNUE4AAAABAJoAAANHBDoABQAAASERIxEhA0f+DboCrQOj/F0EOgAAAAACAC7+wgSTBDoADgAVAAA3PgE3EyERMxEjESERIxMBDgEHIREhg1VYDxACuYu5/Q25AQHJC1BCAfT+s5Vkzd8Blfxb/i0BPv7CAdMCELv9WAL8AAABABUAAAYEBDoAFQAAASMRIxEjASMJATMBMxEzETMBMwkBIwPqgbmC/tHqAYz+meABF3+5fgEZ4P6YAYzqAdj+KAHY/igCOwH//j8Bwf4/AcH+Af3FAAAAAQBY/+0DrARMACgAAAEUBgceARUUBiMiJjUzFBYzMjY1NCYrATUzMjY1NCYjIgYVIzQ2MzIWA5hXUl5f5MKz+7iIbnJ6ana5uXBdaXBig7jsscHRAxNLeCQhfV6aqaqoUHBjTltQmlBOSF5jSZGunwAAAAABAJwAAAQBBDoACwAAATMRIxEjASMRMxEzA0i5uQP+ELm5AwQ6+8YDF/zpBDr86gABAJwAAAQ/BDoADAAAASMRIxEzETMBMwkBIwHdh7q6eQFs4P5SAdLrAc/+MQQ6/jUBy/35/c0AAAEAKAAABAMEOgAPAAABESMRIQMKASsBPwEyNhsBBAO6/pEND5fJNgQoaUoNFAQ6+8YDo/7H/rL+5KIBwQEGAdAAAAAAAQCdAAAFUgQ6AA4AACUBMxEjESMBIwEjESMRMwL7AXDnuQP+pYD+ngO58PIDSPvGAwz89AMd/OMEOgAAAQCcAAAEAAQ6AAsAACEjESERIxEzESERMwQAuf4PuroB8bkB0P4wBDr+KgHWAAAAAQCcAAAEAQQ6AAcAACEjESERIxEhBAG5/g66A2UDo/xdBDoAAQAoAAADsAQ6AAcAAAEhESMRITUhA7D+lbn+nAOIA6b8WgOmlAAAAAMAZP5gBWkGGAAfAC0AOwAAExASMzIWFxEzET4BMzISERUUAiMiJicRIxEOASMiAjUlNCYjIgYHER4BMzI2NSEUFjMyNjcRLgEjIgYVZMjBK0khuSJQMsHJyb8yUSO5IUosvskETICHIjYWFjcjh378bXWHHzMXFzIeiHYCCgEMATgPDgHn/hMREv7I/vQV8f7nEQ/+VQGoDg8BGfEVwe0LCfztCQjKq63ICQkDFQgJ6sQAAAEAnP6/BIIEOgALAAATMxEhETMRMwMjESGcugHyuYESpvzSBDr8WwOl/Fv+KgFBAAEAZwAAA70EOwATAAAhIxEOASMiJjURMxEUFjMyNjcRMwO9uj53RcrYuXJ3RXk8ugGKERDI0AE6/saJeBARAhkAAAAAAQCcAAAF4AQ6AAsAAAERIREzESERMxEhEQFWAYy5AYu6+rwEOvxbA6X8WwOl+8YEOgAAAAEAkf6/Bm0EOgAPAAABESERMxEhETMRMwMjESERAUsBjLkBi7qYEqX62wQ6/FsDpfxbA6X8W/4qAUEEOgAAAAACAB4AAAS/BDoADAAVAAATIREhMhYVFAYjIREhAREhMjY1NCYjHgH6ARPD0dLC/jT+vwH6ARNyaGlxBDr+ir+foMYDpf6K/mZyWFZ6AAAAAAMAnQAABX8EOgAKAA4AFwAAASEyFhUUBiMhETMBIxEzAREhMjY1NCYjAVYBE8PR0sL+NLkEKbq6+9cBE3JoaXECxL+foMYEOvvGBDr99f5mclhWegAAAAACAJ0AAAP9BDoACgATAAABITIWFRQGIyERMxkBITI2NTQmIwFWARPD0dLC/jS5ARNyaGlxAsS/n6DGBDr99f5mclhWegAAAAABAGT/6wPgBE4AHQAAASIGFSM0NjMyEh0BFAIjIiY1MxQWMzI2NyE1IS4BAghikrD7qd76+t6567CKaoWNC/5qAZUPjAO4eVyU1/7M6Crp/szcq2mJx5WVjrkAAAIAnf/sBiMETgATACEAAAEhNhIzMgAdARQAIyICJyERIxEzARQWMzI2PQE0JiMiBhUBVwEIE/zQ5AEB/wDj1v0P/vm6ugG/lJaUlpeVlJQCbtkBB/7P9Rj2/tIBDOD+KAQ6/dax3t+wGK7i4q4AAAACAC8AAAPHBDoADQAWAAABESMRIQEjAS4BNTQ2MwMUFjMhESEiBgPHuv7q/wDIARFqbtfE4WNnASH+9nJvBDr7xgGm/loBwSWdbZS2/rRMZwFrawAB/+f+SwP7BhgAKgAAASERFz4BMzIWHQEzERQGIyImJzceATMyNjURNCYjIgYHESMRIzUzNTMVIQJj/ugDN6JnsbsBp5siNRwPDUQTQUd0d1eILLqqqroBGAS6/u0BUFjM3d/94aqyCAmSBQloXwMAjYBSSPzmBLqVyckAAQBs/+wD/QROAB0AACUyNjczDgEjIgI9ATQSMzIWFyMuASMiBgchFSEeAQJOZ5cBsAH/r+709O6/7wGwAY5wk4oKAZD+cQqIgXhclNUBL+0q7AEw3KxoiryVlZe6AAAAAgAnAAAGhgQ6ABYAHwAAAREhMhYVFAYjIREhERACKwE/ATI2NREBESEyNjU0JiMD3wETw9HSwv4z/rCqzjYDKW1cAsMBE3BqaXEEOv5jtZaXuwOj/sf+vP7amAHW+wHQ/c7+i3FQTGgAAAAAAgCcAAAGpwQ6ABIAGwAAASERMxEhMhYVFAYjIREhESMRMwERITI2NTQmIwFWAfG5ARPD0dLC/jT+D7q6AqoBE3BqaXECoAGa/mK0lpe7Agz99AQ6/c7+i3FQTGgAAAAAAf/9AAAD+gYYABwAAAEhERc+ATMyFhURIxE0JiMiBgcRIxEjNTM1MxUhAnn+0gM3omexu7l0d1eILLqUlLoBLgS//ugBUFjM3f1bAqeNgFJI/OYEv5XExAAAAAABAJz+nAQBBDoACwAAAREhETMRIREjESERAVYB8rn+rbn+pwQ6/FsDpfvG/pwBZAQ6AAAAAQCf/+sGaQWwACAAAAERFAYjIiYnDgEjIiY1ETMRFBYzMjY1ETMRFBYzMjY1EQZp4b1xpzAzrnW317pyYnGHv31qaXwFsPvZztBYWlpY0M4EJ/vZhIWFhAQn+9mEhYWEBCcAAAEAgf/rBa0EOgAgAAABERQGIyImJw4BIyImNREzERQWMzI2NREzERQWMzI2NREFrc2rYpEsMJhlpsK5XVJfcrpnWldoBDr9Kbu9SUxMSby8Atf9KXJxcnEC1/0pcnFycQLXAAAC/9wAAAP8BhgAEgAbAAABIREhMhYVFAYjIREjNTMRMxEhAREhMjY1NCYjApb+vwESxNHTwv40v7+6AUH+vwEScmhpcQQ6/q7Jp6jQBDqVAUn+t/2E/kJ8YF2FAAEAxP/sBpEFxgAnAAABMzUQADMyBBcjLgEjIgIdASEVIRUUEjMyNjczBgAjIgARNSMRIxEzAX3OATD89QENGLkZo6WsxwIa/ebHrKaiGbkY/u/x/P7Qzrm5A0AZARMBWv3opqn+98wbllLO/vekqdz++gFYARRS/VYFsAABAJn/7AWnBE4AIwAAATM2EjMyFhcjLgEjIgYHIRUhHgEzMjY3Mw4BIyICJyMRIxEzAVPEDvTfv+8BsAGOcJOKCgGx/lAKiJRnlwGwAf+v4PIPxLq6AmfYAQ/crGiKvJWVl7p4XJTVAQza/i4EOgAAAgAqAAAE3gWwAAsADwAAASMRIxEjAyMBMwEjASEDIwOJrrihmr4CD6ACBb39mAGaygMBuv5GAbr+RgWw+lACWAJNAAACAA8AAAQlBDoACwARAAABIxEjESMDIwEzASMBIQMnIwcC7XW5e3i9AbqfAb2+/hkBMIEWBBYBK/7VASv+1QQ6+8YBwQE9U1MAAAAAAgDWAAAG7wWwABMAFwAAASEBMwEjAyMRIxEjAyMTIREjETMBIQMjAY8BhQE2oAIFvZiuuKGavqD+tLm5AjsBmsoDAlkDV/pQAbr+RgG6/kYBuv5GBbD8qAJNAAACALwAAAXkBDoAEwAZAAABIQEzASMDIxEjESMDIxMjESMRMwEhAycjBwF2AQ8BA58Bvb56dbl7eL160rq6AckBMIEWBBYBwQJ5+8YBK/7VASv+1QEr/tUEOv2HAT1TUwACAJYAAAY7BbAAIQAlAAABNzUhATMyFhURIxE0JisBBxEjEScjIgYVESMRNDY7AQEzATMBIQHzAwPQ/nUf8fC5ip57F7kRh5+Iuu/yK/521QF6EQEi/asFpQEK/XvK7f6MAXSmeyf9kgJ6G3um/owBdO3KAoX9ewHvAAAAAgCWAAAFSwQ6ABsAHwAAAR4BHQEjNTQmKwEHESMRJyMiBh0BIzU0NjcBIQEzEyEDtcnNuniLMwu5Bj6Md7rR0f7fA7/+HgW4/ooCWgnM4KWlpnsT/k0BvQl7pqWl5coGAeD+IQFJAAACAMMAAAhuBbAAKQAtAAAhETQ2NyERIxEzESE7AQEzFzc1IQEzMhYVESMRNCYrAQcRIxEnIyIGFREBMwEhAsknKf5jubkDFxcr/nbVBgMD0P51H/HwuYqeexe5EYefiAIXEQEi/asBdF+NNv1qBbD9ewKFCwEK/XvK7f6MAXSmeyf9kgJ6G3um/owDKwHvAAACAJsAAAc7BDoAIgAmAAAhNTQ2NyERIxEzESEBIQEeAR0BIzU0JisBBxEjEScjIgYdAQETIRMChiQm/oW6ugLS/uADv/7fyc26eIszC7kGPox3Aam5/om5pV6NNv46BDr+IgHe/iAJzOClpaZ7E/5NAb0Je6alAlsBSf63AAAAAAIAUP5HA6oHcAAtADYAAAEyNjU0JiMhNSEyBBUUBgcVHgEVFAQrASIGFRQWFwcuASc0NjsBMjY1NCYrATUBNzMVByMnNTMBoqOVkpL+zgEy2AEGf3OChv742DVQRV5DSm6YAaqjLYqdqKeNAQqVov5z+p4DNn92a4WV0LlpoisDKayDyt86N0dVHnsvoG+BfJV7ioWVA6SWEvPxFAAAAAACAEz+RwN3BhsALQA2AAABMjY1NCYjITUhMhYVFAYHFR4BFRQGKwEiBhUUFhcHLgEnNDY7ATI2NTQmKwE1EzczFQcjJzUzAZqNgH18/tMBLcTvZFpobPHFMFBFXkNKbpgBqqIpdoaRko3BlaL+c/qeAmhUTkRWlqSQS3UjAyB5V5mqOjdHVR57L6BvgXxcTlZRlQMdlhLz8RQAAAADAHP/6wT+BcUADQAWAB8AAAEQACEgABkBEAAhIAARBSE1NAIjIgIVBSEVFBIzMhI1BP7+u/72/v7+xgE6AQIBCgFF/C4DGdq8tM8DGfznz7S92QJX/vT+oAFgAQwBAQELAWL+nv71PkDJAQb++snWLcv++gEFzAADAGD/7AQnBE4ADQAUABsAABM0ADMyAB0BFAAjIgA1ATI2NyEeARMiBgchLgFgAQDi5AEB/wDj5P8AAeSHkw39sQyTh4SSDwJND5QCKPUBMf7P9Rj2/tIBLvb+cbybm7wDN7aVlbYAAAEAFwAABNoFxAARAAABFzM3AT4BMxcHIyIGBwEjATMCPyIDIgEFMYFuLwEMNUEd/nig/gXJAXF+fgM0noEBoz5V+3MFsAAAAAEALgAABAsETQAVAAABFzM3Ez4BMzIWFwcuASMiBgcBIwEzAdsWAxedKX5SIjAYFQUYDSE7D/7Xjf6DvQE6XV0CI35yCg6SAwUxLPyyBDoABABz/3ME/gY1AAMABwAVACMAAAEjETMRIxEzARAAISAAGQEQACEgABEnNAIjIgIVERQSMzISNQMWubm5uQHo/rv+9v7+/sYBOgECAQoBRbnavLTPz7S92QS1AYD5PgGJAVv+9P6gAWABDAEBAQsBYv6e/vUCyQEG/vrJ/v3L/voBBcwABABg/4gEJwS2AAMABwAVACMAAAEjETMRIxEzATQAMzIAHQEUACMiADUzFBYzMjY9ATQmIyIGFQKhubm5uf2/AQDi5AEB/wDj5P8AupSWlJaXlZSUA0gBbvrSAW4BMvUBMf7P9Rj2/tIBLvax3t+wGK7i4q4AAAAAAwCf/+sGZAdUACwAPgBEAAABMhYVERQGIyImJw4BIyImNRE0NjMVIgYVERQWMzI2NREzERQWMzI2NRE0JiMTFSMiJCMiBh0BIzU0NjMyBDMBJzc1MxUE1rbY2LZ1rTM0rXO319e3YnJyYnGHuoVyYXR0YWgshf7dLjY8f3l0SwEec/5BTDq0Ba/k3v3A3+NWWVlW498CQN7klZiV/cCWl4WEAbT+TISFl5YCQJWYAbt9fzg3EiRubH/+UkB0jHwAAwB+/+sFqgXxACwAPgBEAAABMhYVERQGIyImJw4BIyImNRE0NjMVIgYVERQWMzI2PQEzFRQWMzI2NRE0JiMTFSMiJCMiBh0BIzU0NjMyBDMFByc3JzMEQqXDw6VnmS8vmWWmwsKmUl1dUl9yuXJgUF5eUKoshf7dLTc7gHp0SgEedP7ioU07AbQERNDM/t/Nz0pMTErPzQEhzNCVhIP+34SDcnHr63Fyg4QBIYOEAcJ9fzc3EiNubYDqxEB0jAAAAgCf/+sGaQcDAAcAKAAAATUhFyEVIzUFERQGIyImNREjERQGIyImNREjERQWMzI2Nx4BMzI2NREB3QMrAf61qAKafGlqfb+HcWJyute3da4zMKdxveEGmWpqfX3p+9mEhYWEBCf72YSFhYQEJ/vZztBYWlpY0M4EJwAAAAIAgf/rBa0FsQAHACgAAAE1IRchFSM1AREUBiMiJjURIxEUBiMiJjURIxEUFjMyNjceATMyNjURAYgDKwP+s6gCM2hXWme6cl9SXbnCpmWYMCyRYqvNBUdqaoCA/vP9KXFycXIC1/0pcXJxcgLX/Sm8vElMTEm9uwLXAAABAHj+gwS+BcUAGAAAASMRJgA1ERAAMzIAFSM0JiMiAhURFBI7AQMRud3+/QEw/PoBILq1q6zHx6xt/oMBbRwBTv0BAQETAVr+/eKfsP73zP79zv73AAAAAQBk/oMD4AROABgAAAEjESYCPQE0EjMyFhUjNCYjIgYdARQWOwECorm7yvrfuOuvjGiRj46SZf6DAW8fASbRKugBNN2raIrloSqk5AAAAAABAHQAAASQBT4AEwAAAQUHJQMjEyU3BRMlNwUTMwMFByUCWAEhRP7dtqjh/t9EASXN/t5GASO8pecBJUj+4AG9rHmq/r4Bjqt5qwFvq3urAU3+Z6t4qgAAAfxnBKf/JwX7AAcAAAEVJzchJxcV/Q2mAQIbAaUFJX4B52wB1QAAAAH8cQUX/2QGFQARAAABMiQzMhYdASM1NCYjIgQrATX8m3MBHkp0eoA7Ny3+3YUsBZWAbW4jEjc3f30AAAH9ZgUY/lQGWAAFAAABNTMVFwf9ZrM7TQXcfIx0QAAAAf2kBRj+kwZYAAUAAAEnNyczFf3xTTsBtQUYQHSMfAAI+o3+xAIoBa8ADQAbACkANwBFAFMAYQBvAAABNDYzMhYVIzQmIyIGFQE0NjMyFhUjNCYjIgYVEzQ2MzIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFQE0NjMyFhUjNCYjIgYVATQ2MzIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFRM0NjMyFhUjNCYjIgYV/XpwYmNwcC80Mi8B3m9iYnJxLzQzLUlwYmJxcC80My7+y29iYnFwLzQzLv1QcGJjcHAvNDIv/U1xYmNwcC80Mi/+3nFhY3BwLjUyLzVxYWNxcS41Mi4E81VnZ1UsOTks/utVZ2dVLDk5LP4JVWdnVSw5OSz9+VVnZ1UsOTks/uRWZmZWLTg4LQUaVWdnVSw5OSz+CVVnZ1UsOTks/flVZ2dVLDk5LAAAAAj6pP5jAeMFxgAEAAkADgATABkAHgAjACgAAAUXAyMTAycTMwMBNwUVJQUHJTUFATclFwYFAQcFJyUDJwM3EwEXEwcD/qcLemBGOgx6YEYCHQ0BTf6m+3UN/rMBWgOcAgFARCX/APzzAv7ARQEmKxGUQcYDXxGVQsQ8Dv6tAWEEog4BUv6g/hEMfGJHOwx8YkcBrhCZRBex/I4RmUXIAuQCAUZF/tX84wL+u0cBKwAAAv/cAAAD/AZwABIAGwAAASERITIWFRQGIyERIzUzNTMVIQERITI2NTQmIwKW/r8BEsTR08L+NL+/ugFB/r8BEnJoaXEFGv3Oyaeo0AUalsDA/KP+QnxgXYUAAAADALUAAATYBbAAAwAOABcAAAEHATcBESMRITIWFRQGIyUhMjY1NCYjIQTYbv6Rbf4GuQIk7f397f6VAWuclZWc/pUCPmQBk2X+eP22BbDryMrplZ99fqEAAwCR/mAEJAROAAMAFgAkAAAlBwE3JRQCIyImJwcRIxEzFz4BMzISESM0JiMiBgcRHgEzMjY1BCNu/rZuAUvbyWeWNQO6nxI2mmvM27qQk1t7Jih5XZKPDWUBdWVz8P7nQ0MB/e8F2opOUP7H/vW/61BG/fZHTMupAAAAAAEApgAABCMHAQAJAAABIxUhESMRIREzBCMC/T65AsS5BRsB+uYFsAFRAAAAAQCRAAADQwV4AAkAAAEjFSERIxEhETMDQwX+DboB+LoDpAH8XQQ6AT4AAAABALX+3gR8BbAAFQAAASERMyAAERACIycyNjUuASsBESMRIQQw/T65AR8BNu/qApyFAcvPubkDewUa/ib+1f7q/vf+6JHNw9HR/V8FsAAAAAEAkf7lA74EOgAVAAABIREzMgQVBgIHJz4BNS4BKwERIxEhAz7+DXTnARgBvcIxh3EBsJV0ugKtA6P+4vrhjP7rJJAinnWZo/4aBDoAAAAAAQCmAAAE+AWwABQAAAkCIwEjFSM1IxEjETMRMxEzETMBBMv+bgG/5/6cUJVpublplU8BRwWw/U79AgKV9/f9awWw/XoBAv7+AoYAAAEAmgAABH8EOgAUAAAJAiMBIxUjNSMRIxEzETM1MxUzAQRa/q0BeOv+6jGUZbq6ZZQqAQMEOv3+/cgBz8TE/jEEOv411tYBywAAAAABAEUAAAaJBbAADgAAASMRIxEhNSERMwEzCQEjA4ywuf4iApefAhHU/cMCZuMClP1sBRuV/XkCh/0+/RIAAAAAAQA+AAAFfAQ6AA4AAAEjESMRITUhETMBMwkBIwMah7r+ZQJVeQFs4P5SAdLrAc/+MQOklv41Acv9+f3NAAAAAAEAtQAAB4QFsAANAAABIREhFSERIxEhESMRMwFuAtUDQf14uf0rubkDGwKVlfrlAob9egWwAAAAAQCRAAAFagQ6AA0AAAEhESEVIREjESERIxEzAUsB8QIu/ou5/g+6ugJkAdaW/FwB0P4wBDoAAAABALT+3wfNBbAAFwAAATMgABEQAiMnMjY1LgErAREjESERIxEhBP17AR8BNu/qApyFAcvPe7n9KbkESQNB/tX+6v73/uiRzcPR0f1eBRr65gWwAAABAJH+5QawBDoAFwAAATMyBBUGAgcnPgE1LgErAREjESERIxEhA/ao8AEiAb3DMIdxAbqeqLn+DroDZQKF+uGM/uskkCKddpmj/hoDo/xdBDoAAAACAHP/4gWaBcUAKQA3AAAFIiYnDgEjIAARNRASMxciAh0BFBIzMjY3JgI9ATQSMzISHQEUAgceATMBFBYXPgE9ATQmIyIGFQWab8FZR5pX/un+sfjOAX6Q5sckQSB+g9+5ut9wajNxQv18eHllaXZqaHceJSUhIAGIATKqARMBY5z++dGs8v7TBwhjARSs5vABM/7T9vqi/vdhDg0COZ/sSknmlP2x1durAAAAAgBt/+sEnARPACkAOAAABSImJw4BIyIAETU0EjMVIgYdARQWMzI2Ny4BPQE0NjMyFh0BFAYHHgEzAzU0JiMiBh0BFBYXPgE1BJxbnEc7gUnf/vPAoE1Zo48YLRdhYqiUk6tCQChYMulGP0FCT080NgwcHSEhAUoBAzvRAQqbsY09wfEFB1DXg2fB6/vGaXPBTgsKAZdsgKOSfWtrpzo5nWEAAAABADT+oQaOBbAADwAAASE1IRUhESERMxEzAyMRIQGw/oQDuf58Ate5lRKl+9kFG5WV+3oFG/rp/ggBXwABAB/+vwUXBDsADwAAASE1IRUjESERMxEzAyMRIQEx/u4CxPgB8rmBEqb80gOmlZX87wOl/Fv+KgFBAAACAJcAAATEBbAAAwAXAAABIxEzAREjEQ4BIyImNREzERQWMzI2NxEDF5WVAa25YbB79fO6jKJpvGcBQAK8AbT6UAJhHRrO8gHG/jqrfxwcArgAAAACAIMAAAPZBDsAAwAXAAAlIxEzASMRDgEjIiY1ETMRFBYzMjY3ETMChpWVAVO6PndFyti5cndFeTy65gI1/OUBihEQyNABOv7GiXgQEQIZAAEAjgAABLsFsAATAAAzETMRPgEzMhYVESMRNCYjIgYHEY65Ya989PS6jaFqvGYFsP2eHBzP8f46AcaqgB0c/UkAAAAAAgBH/+kFwAXDAB4AJwAABSAAETUuATUzFBYXNRAAMyAAERUhFRQSMzI2NxcOAQEhNTQmIyICFQPt/tj+waCflVJYATTpAQwBEfyAz95wnUowOLz9wALHpr6puhcBUgEfaxS/oWB5FAcBFAFc/qX+xG1l2f79LyiGJz8DWSHU9v71zwAAAv/j/+wEWQROABwAJAAABSIAPQEuATUzFBYXPgEzMhIdASEeATMyNjcXDgEDIgYHITU0JgK+5P74eHeUMDQg/qfc3f0zBJ2RZZM7STu5pmmRFAIOgBQBJ/QMHKqJSWEZwu3+/uB5psw4M3s6SwPMqYcaeZ0AAAAAAQCm/tkEywWwABYAAAEWABEQAiMnMjY1LgEjIREjETMRMwEzArr9AQ3u6wKdhQLK0P7wubmHAg3YAzgV/tn+/v73/uiRzcPQ0f1lBbD9iwJ1AAAAAQCa/v0EGQQ6ABYAAAEeARUGAgcnPgE1LgErAREjETMRMwEzAn291gG8wzCHcQG2oqu6ulsBiuACZB3av4f++SOQIZJulov+MQQ6/jUBywABALX+SwT9BbAAFwAAAREhETMRFAYjIiYnNx4BMzI2NREhESMRAW4C1bqomx80HQ4OQhJCR/0ruQWw/WsClfn3qrIJCZEFCGdfAt/9egWwAAEAkf5LA/UEOgAXAAABESERMxEUBiMiJic3HgEzMjY1ESERIxEBSwHxuaibHzQdDw1CEkJI/g+6BDr+KgHW+22qsgkJkQUIZ18CKf4wBDoAAgBf/+sFEAXFABYAHgAAASAAERUQACMgABE1ITU0AiMiBgcnPgETMhI3IRUUFgKCAToBVP60+f7N/scD+OTxdqdOLzrG47XPB/zDyQXF/pb+zqP+1/6OAVoBPG856gEcMCeGJkH6uwES2yPV9QAAAAEAaf/rBCgFsAAaAAABITUhFwEeARUUBCMiJDUzFBYzMjY1NCYrATUDIP10A2UB/mTg6v703sP+7rqbgJGgoaaOBRqWdf4SDd/My9/U1XedlXyfjpUAAAABAGn+dQQoBDoAGgAAASE1IRcBHgEVFAQjIiQ1MxQWMzI2NTQmKwE1Awz9iANlAf5x2eT+9N7D/u66m4CRoKSmjQOjl3X+EBHeyMng1dN1nZV6n46VAAD//wA6/ksEdAWwACYArEQAACYB06tAAAcBmgDwAAAAAP//ADv+SwOWBDoAJgDnTwAAJgHTrI4ABwGaAOEAAAAAAAIAWQAABGMFsAAKABMAAAERMxEhIiY1NDYzAREhIgYVFBYzA6q5/d/t/PvuAWj+mJyUlJwDbAJE+lDxycjq/SkCQqB7f6gAAAIAWQAABl4FsAAYACEAACEiJjU0NjMhETMRNz4BNzYmJzMeAQcOASMlESEiBhUUFjMCQu38++4BaLlab3MEAR8esyEjAgTrsP7t/piclJSc8cnI6gJE+uQBAYyCT6VRZpVKz9WVAkKge3+oAAIAZP/pBm4GGAAjADQAABMQEjMyFhc3ETMRBhYzPgE3NiYnNx4BBwIAIwYmJw4BIyICNQEuASMiBh0BFBYzMjY3LgE1ZNrMXo0zA7kCXFGMlAQBHx+zIiMCBP71znmfKDagccnbAscodlWTiIeSWncpAwICCgEKATpBPgECSPtBZHUB0b9jxmkBfLle/vH+6QJWYVtaARvvAThAR+rAFarGTEcVHBAAAAEANv/oBdIFsAAsAAABNCYrATUzMjY1NCYjITUhMhYVFAYHHgEdAQYWMz4BNzYmJzMeAQcKASMGJicCw4h5v4yslZKh/pkBZ/P5dXR4ZAFSSHqDBAEfH7QjIgIE+b6gqggBc3qQln2IfYWWzsx0pTEorINFUGAB1btjx2mIr1z+8/7nA5quAAABADH/4wTpBDoALgAAJQYWMz4BNzYmJzMeAQcOASMGJic1NCYrASczMjY1NCYjISchMhYVFAYHFR4BHQEC5wEpNXB1BAEgH7QjIwIF7LKLhgZrZ9MCu3tydnv++gYBDNDcXVthVdUtLgKZjk2iUGiPSNviA2+ETEpPlFVPU2CUpptTcSIDHHdaTgAAAAIAU/7EA9AFsAAhACsAABM1MzI2NTQmIyE1ITIWFRQGBx4BHQEUFhcVIy4BPQE0JiMBFAYHJz4BPQEzsKKvlpGg/u0BE/P3dHN7aB8lvikWjHwCRVxSaTAuuQJ6ln+FgIeVz85zpDEorISIRWojGSSCR4R6j/3EZM9HSEmRVZcAAgB5/rUDuQQ6ACIALAAAEzUzMjY1NCYjITUhMhYVFAYHFR4BHQEUFhcVIy4BPQE0JiMBFAYHJz4BPQEzwtR+cnJ+/uMBHc/bXl1kVhoivyQSa2gCBlxSaTAuuQG6lFRRVV6UpZtUcyIDHYFjYS9UFhMXYjRfU1v+dWTPR0hJkVWXAAAAAQBF/+gHbwWwACEAAAERBhYzPgE3NiYnNx4BBwIAIwYmJxEhERACKwE1MzISGQEE5QFcUYyTBAEfH7MiIwIE/vXNqrMI/hnQ+zUpmoQFsPupZHUB0b9jxmkBfLle/vH+6QOtxAPB/eb+av6WlQEbAVACsAABAD//6AY5BDoAIQAAAREGFjM+ATc2JiczHgEHDgEjBiYnESEREAIrAT8BMjY1EQPqAVpQcXYEAR8fsyIjAgTstKiyCP69qsw5AypuWwQ6/R9kdQG5qV68Y3qrWPn/A63EAkr+y/69/tWiAdL5AcwAAQCt/+gHcQWwAB0AAAERBhYzPgE3NiYnNx4BBwIAIwYmJxEhESMRMxEhEQTmAVtRjJQEAR8fsyIkAgX+9c6pswj9Obm5AscFsPupZXQB0b9ixWsBf7Ze/vD+6gOtxAEt/XoFsP1rApUAAAAAAQCQ/+gGTAQ6AB0AAAEhESMRMxEhETMRBhYzPgE3NiYnMx4BBw4BIwYmJwND/ga5uQH6uQFaUHF3BAEfH7IjIwIE7LWosggBz/4xBDr+KQHX/R9kdQG5qV28ZH2pV/n/A63EAAEAef/rBJ0FxQAhAAAFIAAZARAAITIWFwcuASMiAhURFBIzPgE3NiYnMx4BBwYEArn++/7FATsBBXKsRTtEjla20dC3j5YEARoZtCYTAQT+8BUBWAESAQYBEQFZLCuDIiL+98n++M3++AGajlWxY7VlT9ziAAAAAAEAZf/rA8YETgAhAAAlPgE3NCYnMx4BFQ4BIyIAPQE0EjMyFhcHLgEjIgYdARQWAlFnUgMLCbINDgTIqen+/fneX4owLDB3RpCOl4ABVVc5eTpGcDaioAE16CrnATUiII0bHuefKqPlAAAAAAEAJP/oBUUFsAAZAAABITUhFSERBhYzPgE3NiYnNx4BBwIAIwYmJwIC/iIEgP4YAlxRjJQEASAfsyMiAgT+9c2ptAgFGpaW/D9kdQHRv2LGagF/t13+8f7pA63EAAAAAAEARv/oBLgEOgAZAAABITUhFSERBhYzPgE3NiYnMx4BBw4BIwYmJwGs/poDi/6VAVtRcXYEAR8esiMjAgTttKm0CAOmlJT9s2V0AZuPTqVTapJK3eMDrcQAAAAAAQCb/+sFAAXFACkAAAEiBhUUFjMyNjUzFAQjICQ1NDY3NS4BNTQkITIEFSM0JiMiBhUUFjsBFQLMv7nLuqXJuf6+5f76/siKiXmEASMBBeQBL7nGlLq1qbm3ApuAinyVnXfV1N7MgaoqAy6kaMrU2rhujpB0d4OWAAAA//8AswKMBPADIQBGAYbZAFMzQAD//wC7AowF8wMhAEYBhq8AZmZAAP//AA3+bgOhAAAAJwBBAAn/AwAGAEEJAAABAGAEAgF4BisACQAAEzQ2NxcOAR0BI2BcUmoyLbkEsWTPR0dKkFayAAAAAAEAMAPnAUcGGAAJAAABFAYHJz4BPQEzAUdcUmkwLrkFYWXPRkhIkVa6AAAAAQAk/tYBOwD6AAkAACUUBgcnPgE9ATMBO1xSaTAuuU9kz0ZHSZFVrgAAAP//AFAD5wFnBhgARwFmAZcAAMABQAAAAP//AGAEAgKyBisAJgFlAAAABwFlAToAAP//ADwD5wKGBhgAJgFmDAAABwFmAT8AAAACACT+1gJkAPoACQATAAAlFAYHJz4BPQEzBRQGByc+AT0BMwE7XFJpMC65ASldUmkwLrpPZM9GR0mRVa6rZM9GR0mRVa4AAAABAEYAAAQkBbAACwAAASERIxEhNSERMxEhBCT+bLr+cAGQugGUA6P8XQOjlwF2/ooAAAAAAQBX/mAENAWwABMAACkBESMRITUhESE1IREzESEVIREhBDT+arr+cwGN/nMBjboBlv5qAZb+YAGglQMOlwF2/oqX/PIAAAAAAQCKAhgCIgPeAA0AABM0NjMyFh0BFAYjIiY1im1eYG1tX19tAxhZbW1ZPVlqaln//wCmAAADFwDFACYAEAQAAAcAEAG5AAD//wCmAAAEtgDFACYAEAQAACcAEAG5AAAABwAQA1gAAAAGAET/6wdXBcUAGQAnADUAQwBRAFUAAAE0NjMyFhc+ATMyFh0BFAYjIiYnDgEjIiY1ATQ2MzIWHQEUBiMiJjUBFBYzMjY9ATQmIyIGFQUUFjMyNj0BNCYjIgYVARQWMzI2PQE0JiMiBhUTJwEXAzegikx0JiVzTYqhoIlOdCUlc0yLof0NoIqKoZ+Ki6EDflJPTlFST05RAcpST01SUk9OUftDUk9OUVNOTlH8aALHaAFlgatAOTlAq4FOgqo+Ojo+qoIDgYKrq4JNgqmqgfzMTWhnTk5NaGhNTk1oZ05OTWhoTQLmTWdnTU1NaWlN+9dBBHJBAAAAAAEAbACaAiADtAAGAAAJASMBNQEzAR4BAo3+2QEnjQIn/nMBhBMBgwABAFkAmQIOA7QABgAAEwEVASMJAecBJ/7ZjgEC/v4DtP58E/58AY0BjgAAAAEAOwBvA2oFIgADAAA3JwEXo2gCx2hvQQRyQQACAEgCMANSBcUACgAPAAABMxUjFSM1IScBMwEhEScHArqYmKP+NQQByan+QgEbAxEDZn25uV4Cfv2hAYsBIgAAAQB6AosC+AW6ABMAABMXPgEzMhYVESMRNCYjIgYHESMR+h4lbkl+hqpKRjlMFaoFq3pCR5Og/gQB3WpaOTP9ywMgAAABAEYAAARRBcUAJwAAAQ4BByEHITUzPgE3IzUzJyM1Myc0NjMyFhUjNCYjIgYVFyEVIRchFQGvAyAeAuMB/DYKMTIDsKsGpJ4F277K1bp9aGl2BQGm/mAFAZwBvliYOZWVDbNplpGWldDlz7R8cZSLlZaRlgAAAAADAKf/7AYMBbAACgATACsAAAERIxEhMhYVFAYjJzMyNjU0JisBJREzFSMRFBYzMjY3Fw4BIyImNREjNTMRAWC5AV/s/v7spqablZWbpgPQ0NA2LxgxFRkaXS5xgJubAjb9ygWw9MnK85anfn+rJv75jf1qUD8HBoMRFY2eApaNAQcAAAABAE//6wPUBcUAKQAAASEUFjMyNjcXDgEjIgA1IzUzNSM1MzU0ADMyFhcHLgEjIgYdASEVIRUhA5L+DK6ZO201Ejp3Pur+6paWlpYBFOo8cUQSN246mawB9P4MAfQCArTOERGYDxABHfp4qXoR+QEeEA+aEBPMsxN6qQAABAB7/+sFgwXFABsAKQA3ADsAAAEUBiMiJj0BNDYzMhYVIzQmIyIGHQEUFjMyNjUBFBYzMjY9ATQmIyIGFTM0NjMyFh0BFAYjIiY1EycBFwKplX+CmJeBgJaLR0RFSEpFQ0YBEKGLiaChioqgi1FOT1JRTk9Sy2j9OWgEHm6QqoFNgaySbTpOaU1NTGhPOPz5gqqqgk6Bq6uBTWhoTU5OZ2hNA8pB+45BAAAAAAIAaP/rA2oFxQAaACYAAAUiJj0BDgEjNTI2NxE0NjMyFh0BFAIHFRQWMwM1NCYjIgYVET4BNQLMzMgzZTg6ZjCYi3qVx7JhehsuKDY0YGAV7NgPDgyuDg4B3LTHqZMqpP6zZVqVlAPXLFFPbnH+gkzScwAABACrAAAISgXAAAMAEQAfACsAAAEhNSEBNDYzMhYdARQGIyImNTMUFjMyNj0BNCYjIgYVASMBIxEjETMBMxEzCAz90wIt/ZK3n5+3tp6ht6NaW1haW1laWf6yuf0tA7m5AtMDuQFrjQJ5l7i4l3WYtraYW2pqW3VYbGtZ+48Ee/uFBbD7hgR6AAIAZgOXBFwFsAAOABYAAAEjAyMDIxEjETMbATMRIwEjESMRIzUhBAIDmzOgA1pxpadrWv3kkluTAYAE/P6bAXL+jgIZ/nABkP3nAcj+OAHIUQAAAAIAmP/sBJMETgAVAB4AACUOASMiADU0ADMyAB0BIREeATMyNjcBIgYHESERLgEEFlm4Yd7+0gE/zdMBHP0AOYlPYbZZ/pBLizsCHDeIXjg6AUTt5gFL/s7rL/64Njg7PwMqQDr+6wEeNjsA//8Ab//1Bk8FsgAnAckAEQKGACcBdAEJAAAABwHQA0wAAAAA//8Aa//1BuIFwAAnAcsAAgKUACcBdAG8AAAABwHQA98AAAAA//8AbP/1BxIFrwAnAc3/+gKOACcBdAH0AAAABwHQBA8AAAAA//8Aa//1Bm8FrwAnAc8ADQKOACcBdAE3AAAABwHQA2wAAAAAAAIATP/rBC0F7QAUACEAAAEEABEVFAAjIgA1NBIzMhYXNy4BJxMyNj0BLgEjIgYVFBYB6AENATj+59rd/u/13l6jPAMp4qWPjKolrISQiqcF7Uv+Pv6ncPr+zgET0+8BETw5AsnwOPsx47RlUm3JoYjJAAAAAQCp/yoE5QWwAAcAAAUjESERIxEhBOW5/Ta5BDzWBfD6EAaGAAAAAAEARf7zBKsFsAAMAAAJASEVITUJATUhFSEBA2v9uQOH+5oCYf2fBBn8xQJIAkH9SJaNAs4C1I6W/UAAAAEAqAKMA+sDIQADAAABITUhA+v8vQNDAoyVAAABAD8AAASYBbAACwAAARczNwEzASMDIzUhAh4VAxcBjr394o32uAE7AU9iYgRh+lACdZcAAwBr/+sHwgROABkAJwA1AAABFAIjIiYnDgEjIgI9ATQSMzIWFz4BMzISFQUUFjMyEjc1JgIjIgYVITQmIyICBxUWEjMyNjUHwvXRq+tQUOup0/T00arsUVDsq8/1+WKHh5PSHB3Tk4WHBeWIg5XTHBvTlIWIAfrk/tXZoaHZASrlROMBLdqgoNr+0+NErc0BGW8qbQEZz6urz/7nbSpv/ufNrQAB/7T+SwKOBi0AHAAABRQGIyImJzceATMyNjURNDYzMhYXBy4BIyIGFREBZaebIDIdDg5AE0FIr6MiRCoYFCwbWlxZqrIJCZEFCGheBR6vuQsKjAUGbWX64gAAAAIAZQEaBBQD+wAbADcAABM+ATM2FhceATMyNjcfAQ4BIyImJy4BByIGBycDPgEzNhYXHgEzMjY3HwEOASMiJicuAQciBgcnbzB5Q0Y9Z1g/Q0F5LwMJMXlCQz9YZz1GQnkuAxMweUNGPWdbPENBeS8DCTF5QkM/WGs5RkJ5LgMDaEZMARczLRhKRAGjR0sYLTMXAUtDAf76RkwBFzMvF0tEAaRHSxgtNRYBTEMBAAAAAQCYAKQD2gTfABMAAAEzFSEDIRUhByc3IzUhEyE1IRMXAw/L/t2OAbH994NTY8YBHY/+VAIEmFMDzZ7+/57sOrKeAQGeARI7AAAA//8AngACA+YEjQBnAB4AVgCyQAA5mgAHAYb/+/12AAD//wCZAAAD7wSgAGcAIAATAMRAADmaAAcBhv/6/XQAAAACACsAAAPcBbAABQAPAAABMwkBIwEhAScjBwkBFzM3AbyMAZT+cI3+bAL0/vkWAxb/AAEGFgMWBbD9J/0pAtcCAz4+/f39/j8/AAD//wDHALIBgwTrACcAEAAlALIABwAQACUEJgAAAAIAbgJ6AjMEOgADAAcAABMjETMBIxEz+42NATiNjQJ6AcD+QAHAAAABAFz/LwFXAOwACQAAJRQGByc+AT0BMwFXS0dpJiSxgFy2P0g/e0xvAAAAAAIAHwAAA80GLQAXABsAADMRIzUzNTQ2MzIWFwcuASMiBh0BMxUjESEjETPKq6vOvkSCVR83dUJ4aN3dAkm6ugOtjXe5wx8emhYdaHB3jfxTBDoAABYAW/5yB+4FrgANAB0AKwA7AEEARwBNAFMAXQBhAGUAaQBtAHEAdQB+AIIAhgCKAI4AkgCWAAABNCYjIgYdARQWMzI2NQUyNjU0Jic1PgE1NCYrAREnFAYjIiY9ATQ2MzIWFQUUBiMiJjUjFBYzMjY1ESMBETMVMxUhNTM1MxEBESEVIxUlNSERIzUBMx4BFRQGKwE1ATUhFSE1IRUhNSEVATUhFSE1IRUhNSEVEzMyFhUUBisBBSM1MzUjNTMRIzUzJSM1MzUjNTMRIzUzAzl/aGh+fmpofQEgXmc0LSUqbWe8n0hBQ0lIQkFKA7o2KTM1XWhdU2hc+cRxxAUox2/4bQE1xAXsATZv/NoFMDI0M34BTgEW/VsBFf1cARQCCgEW/VsBFf1cARS8XT44Ojxd/PFxcXFxcXEHIm9vb29vbwJEYnl5YnBkd3dk2E5NLkQNAw48KExK/dvYR0xMR3BFTk5Fmyw2LC9TUVtQAXr7TwE7ynFxyv7FBh8BHXSpqXT+46n8tgItJykqqQNKdHR0dHR0+ThxcXFxcXEEWx8oKSeW/H76/BX5fvx++vwV+QAAAAAFAFz91QfXCGIAAwAdACEAJQApAAAJAwU0Njc+ATU0JiMiBgczPgEzMhYVFAYHDgEVFyMVMwMzFSMDMxUjBBgDv/xB/EQEDxkpSV2mloulAssBOiw3OjIrUDrKyspLBAQCBAQGUvwx/DEDz/E2OxsogFCDlIGJNDM+NjJNHDlWWluq/UwECo0EAAAAAAEAXP/vA6QEjQAeAAAbASEVIQM+ATc2FhUUBiMiJjU3FBYzMjY1NCYjIgYHiEcCof4AIyhxP7fIzN216rl9aXx0cmpsZRkB+QKUnv7BGyUCA8a8ts6fpA5XZ3xzb305OAAAAAACAFcAAAMkAyEACgAPAAABMxUjFSM1IScBMwEzEScHAqKCgqH+XQcBpqX+Y/wDEgEYfpqaYgIl/fcBRgEfAAAAAgBz/+sEDQXFAA0AGwAAARACIyICGQEQEjMyEhEnNCYjIgYVERQWMzI2NQQN8dva9PLa2/O6i4mJioyJiYkCLP7j/twBJQEcAVcBHAEm/tr+5CjEwMDE/lvEwsDGAAAAAf+i/t8CzANBAA8AAAMzIAAREAIjJzI2NS4BKwFe1QEfATbv6gKchQHLz9UDQf7V/ur+9/7okc3D0dEAAf+2/ksBZwCYAA8AACUVFAYjIiYnNx4BMzI2PQEBZ6ebIDIdDg4/FEJHmPGqsgkJmgUHX13xAAABABv+ZgHCAEAAEwAANx4BFRQGIyImJzceATMyNjU0Jif4ZmR/ZENbJh8jMCM9NEQ9QDSMTWJrGRN3DQ4wKjJWMAAAAAEAZ/6ZASEAmgADAAABIxEzASG6uv6ZAgEAAAACAIME2QLSBs4ADQAhAAABFAYjIiY1MxQWMzI2NRMUBiMiJiMiBhUnNDYzMhYzMjY1AtKeiYqelkVNS0aNXkg6eSojL1NcSS+DKyIxBa5hdHRhNkJDNQEJTGdMMyYVSmtMMyYAAgCBBOACygcCAA0AHQAAARQGIyImNSMUFjMyNjUlJz4BNTQmIzcyFhUUBg8BAjdGS01GkpyJiJz+pAFMQFdJB4+VU0IBBbA0QEA0X3FxXxB8AxkeHx1QTEM3Nwc+AAAAAgCBBN8C4AaJAA0AEQAAARQGIyImNTMUFjMyNjUnMwcjAuCijY+hmEhQTUlgmaRmBbBgcXFgNUBBNNnGAAAAAAIAbQTkA0IG0gAIABwAAAEHIycHIyclMzcUBiMiJiMiBhUnNDYzMhYzMjY1A0IBpcXFpAEBKYPDXkM2bycgM01dQyt5KB80BOcDn58D8OU/XUgwHBM+YkYsHQAAAgBpBOQD7AbOAAYAFgAAASMBMzcXMy8BPgE1NCYjNzIWFRQGDwECNbz+8KnFxapTAUU3TUAFf4dLOwEF6f77urqJgwQZIiMgXFZLPz4HPAAC/14E0gNGBoAABgAKAAABIycHIwEzBSMDMwNGxaqqxAEimP6PjMjHBNKfnwEFWAEBAAAAAgBuBOQEWAaSAAYACgAAATMBIycHIwEzAyMBkpgBIsWpqsYDIsjJjQXp/vufnwGu/v8AAAIAWwSnAv8GeQANABEAAAEUBiMiJjUzFBYzMjY1ByMnMwL/tZ2etJZYZGFaZ5fS2AWweZCQeUNRUkIFzgAAAAABAJ8EkAFwBhcABQAAEzczBxUjn3NeGLkFI/T9igAAAAIAKQAABIMEjQAHAAoAAAEhAyMBMwEjASEDA1r9+GnAAdavAdW//ccBlswBEP7wBI37cwGkAg0AAwCbAAAECQSNAA8AGAAhAAAzESEyFhUUBgcVHgEVFAYjAREhMjY1NCYjJTMyNjU0JisBmwGK1+dcVmZy2Mf+6wEVc3Jzcv7r0IKDfYjQBI2coVaBIAMYlGKkpAIL/ohfW1pkiVlZWUcAAAAAAQBy/+8EJASdABsAAAEOASMiAD0BNAAzMhYXIy4BIyIGHQEUFjMyNjcEIw70ztL+8QEP0tTvDroOhoOCpaWCg4UOAY7QzwEb5qzlARzOz4p/zZ+toM5/jQAAAAACAJsAAAQtBI0ACQATAAAzESEyAB0BFAAjAxEzMjY9ATQmI5sBotUBG/7l1ejohLKyhASN/vfV0tb++QP5/Jq7j9OOuwAAAAABAJsAAAPHBI0ACwAAASERIRUhESEVIREhA3D95QJy/NQDLP2OAhsCFf5+kwSNlP6wAAAAAQCbAAADyASNAAkAAAEhESMRIRUhESEDcf3kugMt/Y0CHAH4/ggEjZT+lAABAHL/7wRHBJ0AHwAAJQ4BIyIAPQE0ADMyFhcHLgEjIgYdARQWMzI2NzUhNSEERy7st+r+5gEb5N7hErgOh4SSs7GZb4sf/vgBwJ1CbAEF2fPXAQbBqQFtariQ9JO4LB38lQAAAQCbAAAEVQSNAAsAACEjESERIxEzESERMwRVuv26uroCRroB7v4SBI399QILAAAAAQCbAAABVASNAAMAACEjETMBVLm5BI0AAQBB/+8DcQSNAA8AAAEzERQGIyImNTMUFjMyNjUCubjdscXdunZyXXkEjfzUrcWvsmpkeWYAAAABAJsAAARABI0ADAAAASMRIxEzETMBMwkBIwG+abq6WwGN3/4zAfHqAfj+CASN/gIB/v3P/aQAAAEAmwAAA2oEjQAFAAAlIRUhETMBVQIV/TG6k5MEjQAAAQCbAAAFUASNAA4AACUBMxEjEScBIwEHESMRMwL5AXDnuQP+pYD+nwO68PIDm/tzA0YB/LkDWQH8qASNAAAAAAEAmwAABHIEjQALAAAhIwEHESMRMwE3ETMEcrj9ngO6ugJiA7gDbwH8kgSN/JABA28AAAACAHL/7wRXBJ0ADQAbAAABFAAjIgA9ATQAMzIAFSc0JiMiBh0BFBYzMjY1BFf+8ePj/vABD+LjARG5ppWUo6SVlaQB8Ov+6gEX6qzpARj+6OkBr72+rq2wvr2xAAIAcv+LBJoEnQATACEAAAEUBgcXBycOASMiAD0BNAAzMgAVJzQmIyIGHQEUFjMyNjUEVzY0rX+uO4JL4/7wAQ/i4wERuaaVlKOklZWkAfBlp0Kob6ciIQEX6qzpARj+6OkBr72+rq2wvr2xAAIAmwAABDoEjQAbACQAAAERIxEhMhYVFAYHFR4BHQEUFhcVIy4BPQE0JiMlITI2NTQmIyEBVboBy8/bYF9nWBIYvxgMa2f+0AERf3Fyfv7vAeL+HgSNsKVbfSUDHo1rZTNfGBMaazljXWSVXlxfaQABAF3/7wQNBJ0AJQAAATQmJy4BNTQ2MzIWFSM0JiMiBhUUFhceARUUBiMiJDUzFBYzMjYDVHur4sbt0NXouYd9hIByudzH+d3N/vO5pnuKkwEvSVcrPJCXlau4r2BzXk1MUC07l5Ocpai/cGRfAAAAAQBHAAADzwSNAAcAAAEhESMRITUhA8/+lbn+nAOIA/n8BwP5lAAAAAEAjP/vBHAEjQARAAABERQEIyIkNREzERQWMzI2NREEcP7w4uH+77isjpCqBI39AcfY2McC//0BgIyMgAL/AAABACoAAAR9BI0ACQAAARczNwEzASMBMwI6GQMYAUnG/i2u/i7HASBZVwNv+3MEjQABAEEAAAXABI0AEwAAARczNxMzExczNxMzASMDIwMjATMBwwMDA9+t4AMDA7jH/tes6QPqq/7XxgEJFBYDgvx8FBYDgvtzA2z8lASNAAAAAAEAOAAABD4EjQALAAAJATMJASMJASMJATMCOQEg2/51AZXZ/tb+2dwBlv5z2gLXAbb9v/20Ab/+QQJMAkEAAAABACAAAAQwBI0ACAAACQEzAREjEQEzAigBOND+Urn+V9ACQgJL/Q3+ZgGjAuoAAAABAE4AAAPYBI0ACQAAJSEVITUBITUhFQEyAqb8dgKM/ZYDUJOTcgOHlG4AAAIAe//vA/YEnQANABsAAAEUBiMiJjURNDYzMhYVJzQmIyIGFREUFjMyNjUD9vHLzfLwzczyuYp7eoqMenqJAZvJ4+PJAVfI4+THAYGVlYH+qIKXl4IAAAABAEIAAAHLBJ0ABQAAISMRBzUlAcu50AGJA9MDiEUAAAEAWgAAA3AEnQAYAAApATUBPgE1NCYjIgYVIzQ2MzIWFRQGBwEhA3D89QGbaUReXWxzudu9scR0nv74AiOTAZhlcUBYcHNYl8izq2+Wof76AAAAAAEAWf/vA50EnQAoAAABMjY1NCYjIgYVIzQ2MzIWFRQGBx4BFRQGIyImNTMUFjMyNjU0JisBNQH+bmVvb1t1ud+qwNhfV2Nl6cGr77h8ZnF/cXSnAppgV1BoYUuTramiU4MnIohmpLKpqlJubVZmX5AAAAAAAgBHAAAEEQSNAAoADgAAATMVIxUjNSEnATMDEScBA0nIyLn9uwQCQsC5A/6IAYKV7e12Ayr89QIRAf3uAAAAAAEAXQAABCMFxQAYAAApATUBPgE1NCYjIgYVIzQ2MzIWFRQGBwEhBCP8VgHdhFqBcJyRuf7oxuWMg/55AsuDAhOSp1pylJqRw/7gtXnpkP5XAAAAAAIAev/vA9IEnQAaACcAAAEyFhcHLgEjIgYdAT4BMzIWFRQGIyImNRE0JBMiBgcVFBYzMjY1NCYCTUSRQh87b0x+nTOPXL3D6sC98QEKplx9HYhsb4JzBJ0bGI8ZFaOCcTc8w7at0fTIATfH9P20QjoqgqeGZW13AAEARwAAA2MEjQAMAAABBgIRFSM1EBI3ITUhA2PBornkkf2LAxwD+ev+xv7lubkBFQGSmZQAAAAAAwBc/+8DxQSdABcAIwAvAAABFAYHHgEVFAYjIiY1NDY3LgE1NDYzMhYDNCYjIgYVFBYzMjYDNCYjIgYVFBYzMjYDomRZaXfxu8T5eW1dZ+S1rd6XjWdulJNxZ4sjeldifoBiWHcDXVmDJSeOYaSzs6Rhjiclg1mbpaX9Uldwb1hbbW0Cak5iX1FQZGQAAAAAAgBL/+8DnQSdABoAJwAAJTI2PQEOASMiJjU0NjMyFhURFAYjIiYnNx4BEzI2NzU0JiMiBhUUFgHec5IvgE3G1urAvOz6xUSRRB09clxdfRyHaWyCdoKUc3o1Ncyxqt30x/6ouOMaGJAaFQGlSjg5gKeTYGqFAAAAAQBeAAABhAMsAAUAACEjEQc1JQGEpIIBJgKUAYIXAAABAHEAAALGAywAGAAAKQE1AT4BNTQmIyIGFSM0NjMyFhUUBg8BIQLG/bQBL0gsOj9ISqGkj4iUV3WoAXp+AQg+Siw0P0E1aYx9dlBtbJIAAAEAaf/1AuADLAAoAAABMjY1NCYjIgYVIzQ2MzIWFRQGBx4BFRQGIyImNTMUFjMyNjU0JisBNQGnSEFJSjtKoqeAkqNFP0hKsJOAtKNNRE1USk2DAdU6Ni46MipldnVwOFoaGF1GcXp0dTE6OzNBOXoAAAAAAQBKAAACIwWwAAUAACEjEQU1JQIjuf7gAdkE3Ah3ZQABAHL/9QLxAyEAHgAAGwEhFSEHPgE3NhYVFAYjIiY1NxQWMzI2NTQmIyIGB5MzAgD+kBkdUC6Gk5unirOhVEhUTE5HRUUQAVoBx4G/EhkBAo6CfY1tcAszN0VGRVEjIAACAHv/9QMAAywAGgAnAAABMhYXBy4BIyIGHQE+ATMyFhUUBiMiJj0BNDYTIgYHFRQWMzI2NTQmAd02aiwdKFA1V2skZkKGkbGRj7TIgkNWD1lIS1ZMAywTEHsQD19RRyQoiX13kKeK1oqm/lktKApRYks+Q0YAAAABAF4AAAKoAyEADAAAAQ4BHQEjNTQSNyE1IQKoim6imF3+WwJKAqKgx7x/f7sBEVd/AAAAAwBy//UDAwMsABcAIwAvAAABFAYHHgEVFAYjIiY1NDY3LgE1NDYzMhYDNCYjIgYVFBYzMjYDNCYjIgYVFBYzMjYC60hASla0jpS7WE5DSqyJhKeJXkRKY2JMRVwaTTtBUlRAOU4CUDxaGxxiQHJ6enJAYhwbWjxrcXH+LDZDQzY3PT0BmC82NDEwOjoAAAAAAgBp//UC6AMsABoAJwAAJTI2PQEOASMiJjU0NjMyFh0BFAYjIiYnNx4BEzI2NzU0JiMiBhUUFgGWTWEgVjKToLCRi7O+lDNsMxsrU0g/Ug5ZRkdTTXNVRkwjIo58dZipiet/mxERexEOARgwJBtQY1Q6RFAAAAAAAgB8//UDGwMsAA0AGwAAARQGIyImPQE0NjMyFhUnNCYjIgYdARQWMzI2NQMbtpmatrWZmrejXFJSWltTUloBG4qcnIrriZ2diQFPV1dP7FFXV1EAAQCPAowDCwMhAAMAAAEhNSEDC/2EAnwCjJUAAAMAngRCAmsGcwAEABAAHAAAATMXByMHNDYzMhYVFAYjIiY3FBYzMjY1NCYjIgYBsbkB2XKCY0lHYGBHSWNVMiUjMDAjJTIGcwO110heXUlJWVpIJDAwJCYyMwAAAgBvBHACvgXWAAUADwAAARMzFQMjJTQ2NxcOAR0BIwGGdMTfWf7pWlhJLCeoBIMBQhX+wlRXiy46LmdHUAAAAAEAXv/rA/oFxQAoAAABMzI2NTQmIyIGFSM0NjMyFhUUBgceARUUBCMiJDUzFBYzMjY1NCYrAQGGp4pzfoF5jrn2ys7qbnCHbv8Azsr+/LqSgoWQhJCnAzCEeIGCiHSt5dPKXbAwK7Z1y9/VwXeKh4qLgAAAAgA5AAAEUQWwAAoADwAAATMVIxEjESE1ATMBIREjBwOEzc24/W0Ch8T9fQHLAxsB6JX+rQFTawPy/DgCyUYAAAEAmv/rBBEFsAAeAAAbASEVIQM+ATc2EhUUAiMiJjUzFBYzMjY1NCYjIgYHsVQC1f3HMDByUcrj5OW88q+LdISMjYB6bBoCkQMfqf5cJS0CAv775OD++8fNfIOvn5GzRkwAAAACAIf/6wQzBcUAGgAnAAABMhYXBy4BIyIGHQE+ATMyEhUUAiMiABkBEAATIgYHFRQWMzI2NTQmAp9MkTIoNGlKoL9ApWTH4/PQ2P7vATCpapElqoaAipIFxSIbkRoe9c4jPEH+99Xl/ugBLwEeAR8BGwFT/XNVSnPO2MyclroAAAMAHv5KBBEETgAvAD8ATQAAASMeAR0BFAYjIiYnDgEVFBY7ATIWFRQEIyImNTQ2Ny4BNTQ2Ny4BPQE0NjMyFhchASImJw4BFRQWMzI2NTQmIwEUFjMyNj0BNCYjIgYVBBGZHh/tvStJIxkcQzytytH+3PTe8mFSHB0/NVVa68EoSyQBb/2MFSYTNUGLjKC/ZH7+q4dua4aGbW6FA6orYDcWmcwKCxQ0Iy4mj5aA1J54XIEqFzsoRmEmMZdcFp/HCgr79AIEGFw9SFx4R0tFAqRVe3tVFlh4eFgAAAABADsAAAP8BbAADAAAAQoBAwcjNxoBEyE1IQP8/7YnD7oPKefP/PYDwQUa/sH+G/6jmZkBYgIXAQiWAAABAFr+TARHBEkAIwAAEzIWFxsBMwETHgEzMjY3Bw4BIyImJwMBIwEDLgEjIgYjJz4Bwn9uO3P/u/6g0SFBLQ4OFAILJA5vc0KP/ufEAYOoI1M+CzcCARU8BEmJgv74AgT9L/4hS00CA5wGCXmWAUf9vwMQAYRWYgWSBQoAAwBm/+sEGAXFABgAJAAwAAABFAYHHgEVFAQjIiQ1NDY3NS4BNTQ2MzIWAzQmIyIGFRQWMzI2AzQmIyIGFRQWMzI2A/B/b4GV/v7W2v8AkX9teunGw++Ron+CnZuGgZ4pim5whodxb4cENXWpKy24fs3R0M5+uSwDKal0xMzN/JV7mpl8gI2OAyNwjol1c4aGAAAAAAIAZP/rBFgETgAUACIAACUjDgEjIgI9ARASMzIWFz8BMwMTIwEUFjMyNjc1LgEjIgYVA4MDNbeMydvazIm1NQMhsGpxsP11h5J3giIahnmTiOt+ggEb7xUBCgE6gHsB5v3i/eQB9arL07UmrN7twQACAGD/6wQnBbAAGwAsAAABFSEeARcWEh0BFAAjIgA9ATQSNzoBMzcmJCc1ExQWMzI2PQE0JicuASMiBhUDtP40HHRMsbL/AOPk/wDz2gkUCgEW/ug5LJWVlJZnSxcwHJ+gBbCSH2ZAnf73nxjt/twBJO0YwAEGGAIU9kBy/Eyo1NWnGHO1NQYGzJ0AAAIAtgAABLYFsAAJABMAADMRISAAERUQACEDETMyNj0BNCYjtgF3AVgBMf7P/qi+vvnX1/kFsP7W/svz/sv+1wUa+3ve6/bo3gAAAAACAHL/6wPsBE4AHwAqAAAhLgEnDgEjIiY1NDY7ATU0JiMiBhUjNDYzMhYVERQWFyUyNjc1IyIGFRQWAy0JCQI7rGivqfrjyHZ1d3O50dzNzQwQ/flopiTOkoxVKzsfRFadpKuhiWBXX0uFu5yz/ds6ajaKUTvia2VOUAAAAgC1AAAE8gWvAA4AFwAAARQGBwEVIwEhESMRITIWASEyNjU0JiMhBJeHfAFez/7A/ou5Afrv+fzXAUaWlJOc/r8EC4LDMP18EgJq/ZYFr9b+JouDf44AAAEAtgAABR0FsAAMAAABBxEjETMRNwEzCQEjAhanubmoAevV/bwCiugCrbH+BAWw/Sa2AiT9g/zNAAAAAAEAkgAABBQGGAAMAAABBxEjETMRNwEzCQEjAcN3urprAVTe/lQB19sB8nz+igYY/EN5AWb+Of2NAAAAAAEAtgAABPkFsAALAAABESMRMxEzATMJASMBb7m5DAJu5/1jAsbkArf9SQWw/XgCiP08/RQAAAAAAQCSAAAD8QYYAAwAAAEjESMRMxEzATMJASMBUQW6ugEBivD+KgIA5AH0/gwGGPxzAa/+Df25AAACAFT/6wP9BcUAGwAoAAAlMjY9AScOASMiAjU0ADMyABkBEAAjIiYnNx4BEzI2NzU0JiMiBhUUFgH/lq4DMJZe1/EBAsDmAQH+6uhPm0IdP35vcpQhlZJ0mo6A1tosAUlKAQPx6AEf/ur+5/6c/uD+2RwfkB4YAd9gTZzFwsylob4AAAACAJsAAAQZBI0ACgATAAABESMRITIWFRQGIyUhMjY1NCYjIQFVugHPzOPizf7rARV7enp7/usBpv5aBI3Np6nKlH9eYIIAAP//AIEEpQLYBbACBgCcAAD//wAAAAAAAAAAAgYAAwAA//8AJQIhAg0CtgIGAA8AAAACAC4AAAUFBbAADQAbAAAzESM1MxEhIAARFRAAIRMhETMyEj0BNCYjIREh1KamAbsBIgFU/qj+0C3+4/Do5uLa/v4BHQKalQKB/qb+5MX+4v6pApr9+wEF28ff//4VAAACAC4AAAUFBbAADQAbAAAzESM1MxEhIAARFRAAIRMhETMyEj0BNCYjIREh1KamAbsBIgFU/qj+0C3+4/Do5uLa/v4BHQKalQKB/qb+5MX+4v6pApr9+wEF28ff//4VAAABAAYAAAQYBhgAHAAAASERFz4BMzIWFREjETQmIyIGBxEjESM1MzUzFSECgv7nAzeiZ7G7uXR3V4gsuqmpugEZBNL+1QFQWMzd/VsCp42AUkj85gTSlbGxAAAAAAEAOwAABIoFsAAPAAABIxEjESM1MxEhNSEVIREzA5zduebm/jUET/413QM2/MoDNpUBT5aW/rEAAf/j/+wCXwVBAB8AAAERMxUjFTMVIxEUFjMyNjcXDgEjIiY1ESM1MzUjNTMRAXLQ0O3tNi8YMRUZGl0ucYDV1ZubBUH++Y2+lf69UD8HBoMRFY2eAUOVvo0BB///ACcAAAUiByICJgAjAAAABwBCARQBXf//ACcAAAUiBx8CJgAjAAAABwBzAc4BWf//ACcAAAUiB0YCJgAjAAAABwCaANABXf//ACcAAAUiB1ECJgAjAAAABwCgAMoBYP//ACcAAAUiBwwCJgAjAAAABwBoAKoBXP//ACcAAAUiB4gCJgAjAAAABwCeAVEBqP//ACcAAAUiB58CJgAjAAAABwHUAWEBLP//AIP+RATJBcUCJgAlAAAABwB3Adv/9///ALYAAAR1ByICJgAnAAAABwBCAOABXf//ALYAAAR1Bx8CJgAnAAAABwBzAZoBWf//ALYAAAR1B0YCJgAnAAAABwCaAJwBXf//ALYAAAR1BwwCJgAnAAAABwBoAHYBXP///9wAAAF8ByICJgArAAAABwBC/40BXf//AMMAAAJkBx8CJgArAAAABwBzAEYBWf////IAAAJPB0YCJgArAAAABwCa/0kBXf///8wAAAJ1BwwCJgArAAAABwBo/yMBXP//ALYAAAT+B1ECJgAwAAAABwCgAPsBYP//AIL/6wUNBzcCJgAxAAAABwBCATQBcv//AIL/6wUNBzQCJgAxAAAABwBzAe4Bbv//AIL/6wUNB1sCJgAxAAAABwCaAPABcv//AIL/6wUNB2YCJgAxAAAABwCgAOoBdf//AIL/6wUNByECJgAxAAAABwBoAMoBcf//AJb/6wTXByICJgA3AAAABwBCASYBXf//AJb/6wTXBx8CJgA3AAAABwBzAeABWf//AJb/6wTXB0YCJgA3AAAABwCaAOIBXf//AJb/6wTXBwwCJgA3AAAABwBoALwBXP//AB4AAATTBx0CJgA7AAAABwBzAaABV///AHL/7APsBeACJgBDAAAABwBCAJYAG///AHL/7APsBd0CJgBDAAAABwBzAVAAF///AHL/7APsBgQCJgBDAAAABgCaUhsAAP//AHL/7APsBg8CJgBDAAAABgCgTB4AAP//AHL/7APsBcoCJgBDAAAABgBoLBoAAP//AHL/7APsBkYCJgBDAAAABwCeANMAZv//AHL/7APsBl4CJgBDAAAABwHUAOP/6///AGH+RAPyBE4CJgBFAAAABwB3AUX/9///AGL/7APpBeECJgBHAAAABwBCAJsAHP//AGL/7APpBd4CJgBHAAAABwBzAVUAGP//AGL/7APpBgUCJgBHAAAABgCaVxwAAP//AGL/7APpBcsCJgBHAAAABgBoMRsAAP///7UAAAFVBcsCJgCKAAAABwBC/2YABv//AJsAAAI9BcgCJgCKAAAABgBzHwIAAP///8sAAAIoBe8CJgCKAAAABwCa/yIABv///6UAAAJOBbUCJgCKAAAABwBo/vwABf//AJEAAAP4Bg8CJgBQAAAABgCgZR4AAP//AGD/7AQnBeACJgBRAAAABwBCALMAG///AGD/7AQnBd0CJgBRAAAABwBzAW0AF///AGD/7AQnBgQCJgBRAAAABgCabxsAAP//AGD/7AQnBg8CJgBRAAAABgCgaR4AAP//AGD/7AQnBcoCJgBRAAAABgBoSRoAAP//AI3/7AP2BcsCJgBXAAAABwBCALEABv//AI3/7AP2BcgCJgBXAAAABwBzAWsAAv//AI3/7AP2Be8CJgBXAAAABgCabQYAAP//AI3/7AP2BbUCJgBXAAAABgBoRwUAAP//ABv+SwPkBcgCJgBbAAAABwBzASkAAv//ABv+SwPkBbUCJgBbAAAABgBoBQUAAP//ACcAAAUiBvoCJgAjAAAABwBuAM4BSv//AHL/7APsBbgCJgBDAAAABgBuUAgAAP//ACcAAAUiB0wCJgAjAAAABwCcAPsBnP//AHL/7APsBgoCJgBDAAAABgCcfVoAAAACACf+UAUiBbAAGgAdAAABMwEjDgEVFBYzMjY3Fw4BIyImNTQ2NwMhAyMBIQMCWaACKSVTWCMrHS8YDSBKNldpVVuJ/ZuPvQGDAfj6BbD6UD1lPCQmEAx4ExliW0d+NwF7/nwCGQKyAAIAcv5QA+0ETgAzAD4AACEuAScOASMiJjU0NjsBNTQmIyIGFSM0NjMyFhURFBYXIw4BFRQWMzI2NxcOASMiJjU0NjclMjY3NSMiBhUUFgMtCgoCOqxnq6343NF6cWmBue6/u98MEBNTWCMrHS8YDSBKNldpTlP+t2ilJdeBlF0zQiRMYamZnqxuY29jR33DuLL99jpqNj1lPCQmEAx4ExliW0R6NYtgRsd5VUtUAAD//wCD/+sEyQc0AiYAJQAAAAcAcwHXAW7//wBh/+wD8gXdAiYARQAAAAcAcwFBABf//wCD/+sEyQdbAiYAJQAAAAcAmgDZAXL//wBh/+wD8gYEAiYARQAAAAYAmkMbAAD//wCD/+sEyQciAiYAJQAAAAcAnQGoAXL//wBh/+wD8gXLAiYARQAAAAcAnQESABv//wCD/+sEyQdcAiYAJQAAAAcAmwDvAXP//wBh/+wD8gYFAiYARQAAAAYAm1kcAAD//wC2AAAE5wdHAiYAJgAAAAcAmwCoAV7//wBk/+wFMAYYACYARgAAAAcBkQPZBSz//wC2AAAEdQb6AiYAJwAAAAcAbgCaAUr//wBi/+wD6QW5AiYARwAAAAYAblUJAAD//wC2AAAEdQdMAiYAJwAAAAcAnADHAZz//wBi/+wD6QYLAiYARwAAAAcAnACCAFv//wC2AAAEdQcNAiYAJwAAAAcAnQFrAV3//wBi/+wD6QXMAiYARwAAAAcAnQEmABwAAQC2/lAEdQWwACAAAAEhESEVIw4BFRQWMzI2NxcOASMiJjU0NjcnIREhFSERIQQP/WADBjhTWCMrHS8YDSBKNldpTVAB/SkDtf0EAqACpv3vlT1lPCQmEAx4ExliW0N6MwMFsJb+IgACAGL+ZAPpBE4AKQAxAAAFIgA9ATQAMzISHQEhHgEzMjY3Fw4BBw4BFRQWMzI2NxcOASMiJjU0NjcDIgYHITU0JgJO5P74AQ+/3N39MwSdkWWTO0keSzBRVyMrHS8YDSBKNldpNDgkaZEUAg6AFAEn9C3sAS7+/uB5psw4M3sdMRE7ZTwkJhAMeBMZYls3ZS8DzKmHGnmd//8AtgAABHUHRwImACcAAAAHAJsAsgFe//8AYv/sA+kGBgImAEcAAAAGAJttHQAA//8Ahf/rBNsHWwImACkAAAAHAJoA0QFy//8AZv5MA/cGBAImAEkAAAAGAJpdGwAA//8Ahf/rBNsHYQImACkAAAAHAJwA/AGx//8AZv5MA/cGCgImAEkAAAAHAJwAiABa//8Ahf/rBNsHIgImACkAAAAHAJ0BoAFy//8AZv5MA/cFywImAEkAAAAHAJ0BLAAb//8Ahf3lBNsFxQImACkAAAAHAZEBq/62//8AZv5MA/cGbQImAEkAAAAHAaUBMwBW//8AtgAABP0HRgImACoAAAAHAJoA+gFd//8AkQAAA/oHRQImAEoAAAAHAJoAIwFc////xQAAAncHUQImACsAAAAHAKD/QwFg////ngAAAlAF+gImAIoAAAAHAKD/HAAJ////vwAAAokG+gImACsAAAAHAG7/RwFK////mAAAAmIFpAImAIoAAAAHAG7/IP/0////9QAAAkwHTAImACsAAAAHAJz/dAGc////zgAAAiUF9QImAIoAAAAHAJz/TQBF//8AIf5YAYEFsAImACsAAAAGAJ/vCAAA//8AAP5QAWAGGAImAEsAAAAGAJ/OAAAA//8AtwAAAYYHDQImACsAAAAHAJ0AFwFd//8Aw//rBf8FsAAmACsAAAAHACwCPwAA//8Aof5LA2MGGAAmAEsAAAAHAEwB/AAA//8AP//rBIsHOQImACwAAAAHAJoBhQFQ////tP5LAjkF3AImAJgAAAAHAJr/M//z//8Atv31BRwFsAImAC0AAAAHAZEBev7G//8Akv33BBQGGAImAE0AAAAHAZEBGP7I//8AtgAABCUG4AImAC4AAAAHAHMANwEa//8AoQAAAkMHXAImAE4AAAAHAHMAJQGW//8Atv33BCUFsAImAC4AAAAHAZEBdP7I//8AW/33AVoGGAImAE4AAAAHAZH///7I//8AtgAABCUFsQImAC4AAAAHAZEB2QTF//8AoQAAAq0GGAAmAE4AAAAHAZEBVgUs//8AtgAABCUFsAImAC4AAAAHAJ0Bxf3F//8AoQAAAq0GGAAmAE4AAAAHAJ0BPv23//8AtgAABP4HHwImADAAAAAHAHMB/wFZ//8AkQAAA/gF3QImAFAAAAAHAHMBaQAX//8Atv33BP4FsAImADAAAAAHAZEB2P7I//8Akf33A/gETgImAFAAAAAHAZEBQv7I//8AtgAABP4HRwImADAAAAAHAJsBFwFe//8AkQAAA/gGBQImAFAAAAAHAJsAgQAc////0gAAA/gGGAImAFAAAAAHAZH/dgUs//8Agv/rBQ0HDwImADEAAAAHAG4A7gFf//8AYP/sBCcFuAImAFEAAAAGAG5tCAAA//8Agv/rBQ0HYQImADEAAAAHAJwBGwGx//8AYP/sBCcGCgImAFEAAAAHAJwAmgBa//8Agv/rBQ0HYAImADEAAAAHAKEBdwFy//8AYP/sBD4GCQImAFEAAAAHAKEA9gAb//8AtQAABOIHHwImADQAAAAHAHMBkgFZ//8AkQAAAuIF3QImAFQAAAAHAHMAxAAX//8Atf33BOIFrwImADQAAAAHAZEBa/7I//8AWP33ArEETgImAFQAAAAHAZH//P7I//8AtQAABOIHRwImADQAAAAHAJsAqgFe//8AaQAAAtQGBQImAFQAAAAGAJvdHAAA//8AWv/rBIoHNAImADUAAAAHAHMBiQFu//8AZv/sA8IF3QImAFUAAAAHAHMBPAAX//8AWv/rBIoHWwImADUAAAAHAJoAiwFy//8AZv/sA8IGBAImAFUAAAAGAJo+GwAA//8AWv5EBIoFxQImADUAAAAHAHcBjf/3//8AZv5FA8IETgImAFUAAAAHAHcBQP/4//8AWv3jBIoFxQImADUAAAAHAZEBYv60//8AZv3kA8IETgImAFUAAAAHAZEBFf61//8AWv/rBIoHXAImADUAAAAHAJsAoQFz//8AZv/sA8IGBQImAFUAAAAGAJtUHAAA//8AO/31BIoFsAImADYAAAAHAZEBZf7G//8AHf3tAk4FQQImAFYAAAAHAZEArP6+//8AO/5VBIoFsAImADYAAAAHAHcBkAAI//8AHf5NAoEFQQImAFYAAAAHAHcA1wAA//8AOwAABIoHRgImADYAAAAHAJsApAFd//8AHf/sAuwGMQAmAFYAAAAHAZEBlQVF//8Alv/rBNcHUQImADcAAAAHAKAA3AFg//8Ajf/sA/YF+gImAFcAAAAGAKBnCQAA//8Alv/rBNcG+gImADcAAAAHAG4A4AFK//8Ajf/sA/YFpAImAFcAAAAGAG5r9AAA//8Alv/rBNcHTAImADcAAAAHAJwBDQGc//8Ajf/sA/YF9QImAFcAAAAHAJwAmABF//8Alv/rBNcHiAImADcAAAAHAJ4BYwGo//8Ajf/sA/YGMQImAFcAAAAHAJ4A7gBR//8Alv/rBNcHSwImADcAAAAHAKEBaQFd//8Ajf/sBDwF9AImAFcAAAAHAKEA9AAGAAEAlv5uBNcFsAAnAAABERQGBw4BFRQWMzI2NxcOASMiJjU0NjciBiMiJDURMxEUFjMyNjURBNeRhFNYIysdLxgNIEo2V2kuMgcbBvT+3Lq9oanHBbD8JaXaOD1lPCQmEAx4ExliWzRhLAH48gPb/CWrqqqrA9sAAAEAjf5QBAkEOgAnAAAhDgEVFBYzMjY3Fw4BIyImNTQ2Ny8BDgEjIiY1ETMRFBYzMjY3ETMRA/VTWCMrHS8YDSBKNldpUFYMAzKebbTCumhxcIkkuT1lPCQmEAx4ExliW0R8NpsBV1zd9AJ9/YGyg1dTAwr7xgAA//8ASAAABsIHRgImADkAAAAHAJoBrQFd//8AMAAABdgF7wImAFkAAAAHAJoBLgAG//8AHgAABNMHRAImADsAAAAHAJoAogFb//8AG/5LA+QF7wImAFsAAAAGAJorBgAA//8AHgAABNMHCgImADsAAAAHAGgAfAFa//8AYQAABG0HHwImADwAAAAHAHMBiAFZ//8AXgAAA7gFyAImAFwAAAAHAHMBMwAC//8AYQAABG0HDQImADwAAAAHAJ0BWQFd//8AXgAAA7gFtgImAFwAAAAHAJ0BBAAG//8AYQAABG0HRwImADwAAAAHAJsAoAFe//8AXgAAA7gF8AImAFwAAAAGAJtLBwAA////8gAAB1cHHwImAH8AAAAHAHMC0QFZ//8APf/rBnwF3gImAIQAAAAHAHMCggAY//8Ac/+jBP4HXQImAIEAAAAHAHMB4gGX//8AYP95BCcF3AImAIcAAAAHAHMBQAAW////8wAABC0EjQImAakAAAAHAdP/ZP97////8wAABC0EjQImAakAAAAHAdP/ZP97//8ARwAAA88EjQImAbgAAAAGAdMx9wAA//8AKQAABIMF3wImAaYAAAAHAEIAvwAa//8AKQAABIMF3AImAaYAAAAHAHMBeQAW//8AKQAABIMGAwImAaYAAAAGAJp7GgAA//8AKQAABIMGDgImAaYAAAAGAKB1HQAA//8AKQAABIMFyQImAaYAAAAGAGhVGQAA//8AKQAABIMGRQImAaYAAAAHAJ4A/ABl//8AKQAABIMGXQImAaYAAAAHAdQBDP/q//8Acv5HBCQEnQImAagAAAAHAHcBb//6//8AmwAAA8cF3wImAaoAAAAHAEIAjgAa//8AmwAAA8cF3AImAaoAAAAHAHMBSAAW//8AmwAAA8cGAwImAaoAAAAGAJpKGgAA//8AmwAAA8cFyQImAaoAAAAGAGgkGQAA////swAAAVQF3wImAa4AAAAHAEL/ZAAa//8AmwAAAjsF3AImAa4AAAAGAHMdFgAA////yQAAAiYGAwImAa4AAAAHAJr/IAAa////owAAAkwFyQImAa4AAAAHAGj++gAZ//8AmwAABHIGDgImAbMAAAAHAKAAlgAd//8Acv/vBFcF7wImAbQAAAAHAEIAwAAq//8Acv/vBFcF7AImAbQAAAAHAHMBegAm//8Acv/vBFcGEwImAbQAAAAGAJp8KgAA//8Acv/vBFcGHgImAbQAAAAGAKB2LQAA//8Acv/vBFcF2QImAbQAAAAGAGhWKQAA//8AjP/vBHAF4AImAbkAAAAHAEIA4AAb//8AjP/vBHAF3QImAbkAAAAHAHMBmgAX//8AjP/vBHAGBAImAbkAAAAHAJoAnAAb//8AjP/vBHAFygImAbkAAAAGAGh2GgAA//8AIAAABDAF2wImAb0AAAAHAHMBSQAV//8AKQAABIMFtwImAaYAAAAGAG55BwAA//8AKQAABIMGCQImAaYAAAAHAJwApgBZAAIAKf5QBIMEjQAaAB0AAAEzASMOARUUFjMyNjcXDgEjIiY1NDY3JyEDIwEhAwH/rwHVN1NYIysdLxgNIEo2V2lcYWP9+GnAAWIBlswEjftzPWU8JCYQDHgTGWJbSYM4//7wAaQCDQD//wBy/+8EJAXsAiYBqAAAAAcAcwFrACb//wBy/+8EJAYTAiYBqAAAAAYAmm0qAAD//wBy/+8EJAXaAiYBqAAAAAcAnQE8ACr//wBy/+8EJAYUAiYBqAAAAAcAmwCDACv//wCbAAAELQYEAiYBqQAAAAYAmy8bAAD//wCbAAADxwW3AiYBqgAAAAYAbkgHAAD//wCbAAADxwYJAiYBqgAAAAYAnHVZAAD//wCbAAADxwXKAiYBqgAAAAcAnQEZABoAAQCb/lADxwSNACAAAAEhESEVIw4BFRQWMzI2NxcOASMiJjU0NjcnIREhFSERIQNw/eUCckhTWCMrHS8YDSBKNldpTVAB/cwDLP2OAhsCFf5+kz1lPCQmEAx4ExliW0N6MwMEjZT+sP//AJsAAAPHBgQCJgGqAAAABgCbYBsAAP//AHL/7wRHBhMCJgGsAAAABgCadSoAAP//AHL/7wRHBhkCJgGsAAAABwCcAKAAaf//AHL/7wRHBdoCJgGsAAAABwCdAUQAKv//AHL95wRHBJ0CJgGsAAAABwGRAVL+uP//AJsAAARVBgMCJgGtAAAABwCaAIMAGv///5wAAAJOBg4CJgGuAAAABwCg/xoAHf///5YAAAJgBbcCJgGuAAAABwBu/x4AB////8wAAAIjBgkCJgGuAAAABwCc/0sAWf////f+UAFXBI0CJgGuAAAABgCfxQAAAP//AI8AAAFeBcoCJgGuAAAABgCd7xoAAP//AEH/7wQ9BfkCJgGvAAAABwCaATcAEP//AJv98wRABI0CJgGwAAAABwGRAP/+xP//AJsAAANqBcECJgGxAAAABgBzI/sAAP//AJv99QNqBI0CJgGxAAAABwGRANz+xv//AJsAAANqBI4CJgGxAAAABwGRAUUDov//AJsAAANqBI0CJgGxAAAABwCdATH9Jv//AJsAAARyBdwCJgGzAAAABwBzAZoAFv//AJv99QRyBI0CJgGzAAAABwGRAXP+xv//AJsAAARyBgQCJgGzAAAABwCbALIAG///AHL/7wRXBccCJgG0AAAABgBuehcAAP//AHL/7wRXBhkCJgG0AAAABwCcAKcAaf//AHL/7wRXBhgCJgG0AAAABwChAQMAKv//AJsAAAQ6BdwCJgG2AAAABwBzASYAFv//AJv99QQ6BI0CJgG2AAAABwGRAP/+xv//AJsAAAQ6BgQCJgG2AAAABgCbPhsAAP//AF3/7wQNBewCJgG3AAAABwBzAVQAJv//AF3/7wQNBhMCJgG3AAAABgCaVioAAP//AF3+RwQNBJ0CJgG3AAAABwB3AVj/+v//AF3/7wQNBhQCJgG3AAAABgCbbCsAAP//AEf99QPPBI0CJgG4AAAABwGRAQP+xv//AEcAAAPPBgMCJgG4AAAABgCbQhoAAP//AIz/7wRwBg8CJgG5AAAABwCgAJYAHv//AIz/7wRwBbgCJgG5AAAABwBuAJoACP//AIz/7wRwBgoCJgG5AAAABwCcAMcAWv//AIz/7wRwBkYCJgG5AAAABwCeAR0AZv//AIz/7wRwBgkCJgG5AAAABwChASMAGwABAIz+ewRwBI0AJwAAAREUBgcOARUUFjMyNjcXDgEjIiY1NDY3IgYjIiQ1ETMRFBYzMjY1EQRwcGhTWCMrHS8YDSBKNldpKi0HGAbh/u+4rI6QqgSN/QF9sjQ9ZTwkJhAMeBMZYlsyWysB2McC//0BgIyMgAL/AP//AEEAAAXABgMCJgG7AAAABwCaASEAGv//ACAAAAQwBgICJgG9AAAABgCaSxkAAP//ACAAAAQwBcgCJgG9AAAABgBoJRgAAP//AE4AAAPYBdwCJgG+AAAABwBzAScAFv//AE4AAAPYBcoCJgG+AAAABwCdAPgAGv//AE4AAAPYBgQCJgG+AAAABgCbPxsAAP//AF3/7wh8BJ0AJgG3AAAABwG3BG8AAP//ACcAAAUiBngCJgAjAAAABgCpOgAAAP///+YAAATZBnoAJgAnZAAABwCp/yMAAv//ABMAAAVhBnoAJgAqZAAABwCp/1AAAv//ABkAAAHgBnkAJgArZAAABwCp/1YAAf//AFL/6wUhBngAJgAxFAAABgCpjwAAAP///40AAAU3BngAJgA7ZAAABwCp/soAAP//AD8AAAThBngAJgC1FAAABwCp/3wAAP///8j/6wKDBj8CJgC+AAAABwCq/yf/t///ACcAAAUiBbACBgAjAAD//wC2AAAEqQWwAgYAJAAA//8AtgAABHUFsAIGACcAAP//AGEAAARtBbACBgA8AAD//wC2AAAE/QWwAgYAKgAA//8AwwAAAXwFsAIGACsAAP//ALYAAAUcBbACBgAtAAD//wC2AAAGTQWwAgYALwAA//8AtgAABP4FsAIGADAAAP//AIL/6wUNBcUCBgAxAAD//wC2AAAExAWwAgYAMgAA//8AOwAABIoFsAIGADYAAP//AB4AAATTBbACBgA7AAD//wBBAAAE0AWwAgYAOgAA////zAAAAnUHDAImACsAAAAHAGj/IwFc//8AHgAABNMHCgImADsAAAAHAGgAfAFa//8AZP/rBHcGegImALYAAAAHAKkBdQAC//8AY//tA+wGeQImALoAAAAHAKkBKwAB//8Akf5hA/AGegImALwAAAAHAKkBRgAC//8Aw//rAmsGZgImAL4AAAAGAKkq7gAA//8Aj//rA/YGPwImAMYAAAAGAKoetwAA//8AmgAABD8EOgIGAIsAAP//AGD/7AQnBE4CBgBRAAD//wCa/mAD7gQ6AgYAdAAA//8ALgAAA98EOgIGAFgAAP//AC4AAAPPBDoCBgBaAAD////T/+sCfAW1AiYAvgAAAAcAaP8qAAX//wCP/+sD9gW1AiYAxgAAAAYAaCEFAAD//wBg/+wEJwZ6AiYAUQAAAAcAqQFKAAL//wCP/+sD9gZmAiYAxgAAAAcAqQEi/+7//wB6/+sGGQZjAiYAyQAAAAcAqQJT/+v//wC2AAAEdQcMAiYAJwAAAAcAaAB2AVz//wC1AAAEMAcfAiYArAAAAAcAcwGYAVkAAQBa/+sEigXFACUAAAE0JicuATU0JDMyABUjNCYjIgYVFBYXHgEVFAQjIiQ1MxQWMzI2A9CWx+z+ARPh8QEYuaykm6CpyOrt/uXr3/61udOenLABbmiFMTjQpa3f/v62hJ6FbmJ/MTvYp7PS6M+RkX4AAP//AMMAAAF8BbACBgArAAD////MAAACdQcMAiYAKwAAAAcAaP8jAVz//wA//+sDwAWwAgYALAAA//8AtgAABRwFsAIGAC0AAP//ALYAAAUcBscCJgAtAAAABwBzAYwBAf//AFH/6wTIB0wCJgDZAAAABwCcANoBnP//ACcAAAUiBbACBgAjAAD//wC2AAAEqQWwAgYAJAAA//8AtQAABDAFsAIGAKwAAP//ALYAAAR1BbACBgAnAAD//wC2AAAE/gdMAiYA1wAAAAcAnAExAZz//wC2AAAGTQWwAgYALwAA//8AtgAABP0FsAIGACoAAP//AIL/6wUNBcUCBgAxAAD//wC2AAAE/wWwAgYAsQAA//8AtgAABMQFsAIGADIAAP//AIP/6wTJBcUCBgAlAAD//wA7AAAEigWwAgYANgAA//8AQQAABNAFsAIGADoAAP//AHL/7APsBE4CBgBDAAD//wBi/+wD6QROAgYARwAA//8AnAAABAEF9QImAOsAAAAHAJwAogBF//8AYP/sBCcETgIGAFEAAP//AJH+YAQkBE4CBgBSAAAAAQBh/+wD8gROABsAACUyNjczDgEjIgI9ATQSMzIWFyMuASMiBh0BFBYCQ2eXAbAB/6/u9PTuv+8BsAGOcKGHhoF4XJTVAS/tKuwBMNysaIrfpyqr3AAA//8AG/5LA+QEOgIGAFsAAP//AC4AAAPPBDoCBgBaAAD//wBi/+wD6QXLAiYARwAAAAYAaDEbAAD//wCaAAADRwXIAiYA5wAAAAcAcwDVAAL//wBm/+wDwgROAgYAVQAA//8AoQAAAVoGGAIGAEsAAP///6UAAAJOBbUCJgCKAAAABwBo/vwABf///7b+SwFnBhgCBgBMAAD//wCcAAAEPwXHAiYA7AAAAAcAcwFDAAH//wAb/ksD5AX1AiYAWwAAAAYAnFZFAAD//wBIAAAGwgciAiYAOQAAAAcAQgHxAV3//wAwAAAF2AXLAiYAWQAAAAcAQgFyAAb//wBIAAAGwgcfAiYAOQAAAAcAcwKrAVn//wAwAAAF2AXIAiYAWQAAAAcAcwIsAAL//wBIAAAGwgcMAiYAOQAAAAcAaAGHAVz//wAwAAAF2AW1AiYAWQAAAAcAaAEIAAX//wAeAAAE0wcgAiYAOwAAAAcAQgDmAVv//wAb/ksD5AXLAiYAWwAAAAYAQm8GAAD//wBnBCMA/QYYAgYACQAA//8AaQQUAh8GGAIGAAQAAP//AKkAAAN1BbAAJgQbAAAABwQbAg8AAP//AEIAAAQYBi0AJgBIAAAABwBOAr4AAP///7T+SwJABd0CJgCYAAAABwCb/0n/9P//ADAD5wFHBhgCBgFmAAD//wC2AAAGTQcfAiYALwAAAAcAcwKpAVn//wCQAAAGcgXdAiYATwAAAAcAcwK7ABf//wAn/ocFIgWwAiYAIwAAAAcAogFPAAD//wBy/ocD7AROAiYAQwAAAAcAogCeAAD///8+/+sFDQaiAiYAMQAAAAcB1f7PAMz//wBCAAAGiwYtACYASAAAAAcBkgK+AAD//wBCAAAG1gYtACYASAAAACcASAK+AAAABwBOBXwAAP//ALYAAAR1ByICJgAnAAAABwBCAOABXf//ALYAAAT+ByICJgDXAAAABwBCAUoBXf//AGL/7APpBeECJgBHAAAABwBCAJsAHP//AJwAAAQBBcsCJgDrAAAABwBCALsABv//AF0AAAUYBbACBgC0AAD//wBf/ikFQwQ6AgYAyAAA//8AFwAABNoHRwImARQAAAAHAKcENwFZ////+QAABAsGHwImARUAAAAHAKcD0gAx//8AYP5LCGwETgAmAFEAAAAHAFsEiAAA//8Agv5LCXQFxQAmADEAAAAHAFsFkAAA//8AUf5RBGcFxQImANYAAAAHAZwBnP+4//8AWP5SA6wETAImAOoAAAAHAZwBQ/+5//8Ag/5RBMkFxQImACUAAAAHAZwB7v+4//8AYf5RA/IETgImAEUAAAAHAZwBWP+4//8AHgAABNMFsAIGADsAAP//AC7+YAPfBDoCBgC4AAD//wDDAAABfAWwAgYAKwAA//8AGwAABygHTAImANUAAAAHAJwB+AGc//8AFQAABgQF9QImAOkAAAAHAJwBjQBF//8AwwAAAXwFsAIGACsAAP//ACcAAAUiB0wCJgAjAAAABwCcAPsBnP//AHL/7APsBgoCJgBDAAAABgCcfVoAAP//ACcAAAUiBwwCJgAjAAAABwBoAKoBXP//AHL/7APsBcoCJgBDAAAABgBoLBoAAP////IAAAdXBbACBgB/AAD//wA9/+sGfAROAgYAhAAA//8AtgAABHUHTAImACcAAAAHAJwAxwGc//8AYv/sA+kGCwImAEcAAAAHAJwAggBb//8AX//rBRAG3gImAUEAAAAHAGgAfQEu//8AYv/sA+kETwIGAJkAAP//AGL/7APpBcsCJgCZAAAABgBoMRsAAP//ABsAAAcoBwwCJgDVAAAABwBoAacBXP//ABUAAAYEBbUCJgDpAAAABwBoATwABf//AFH/6wRnByECJgDWAAAABwBoAGEBcf//AFj/7QOsBckCJgDqAAAABgBoCBkAAP//ALYAAAT+BvoCJgDXAAAABwBuAQQBSv//AJwAAAQBBaQCJgDrAAAABgBudfQAAP//ALYAAAT+BwwCJgDXAAAABwBoAOABXP//AJwAAAQBBbUCJgDrAAAABgBoUQUAAP//AIL/6wUNByECJgAxAAAABwBoAMoBcf//AGD/7AQnBcoCJgBRAAAABgBoSRoAAP//AHP/6wT+BcUCBgESAAD//wBg/+wEJwROAgYBEwAA//8Ac//rBP4HBwImARIAAAAHAGgA0gFX//8AYP/sBCcF5gImARMAAAAGAGgyNgAA//8Asf/sBPYHIgImAOIAAAAHAGgAtwFy//8AZP/rA+AFygImAPoAAAAGAGgmGgAA//8AUf/rBMgG+gImANkAAAAHAG4ArQFK//8AG/5LA+QFpAImAFsAAAAGAG4p9AAA//8AUf/rBMgHDAImANkAAAAHAGgAiQFc//8AG/5LA+QFtQImAFsAAAAGAGgFBQAA//8AUf/rBMgHSwImANkAAAAHAKEBNgFd//8AG/5LA/oF9AImAFsAAAAHAKEAsgAG//8AlwAABMQHDAImANwAAAAHAGgAswFc//8AZwAAA70FtQImAPQAAAAGAGgOBQAA//8AtQAABjUHDAAmAOEPAAAnACsEuQAAAAcAaAF9AVz//wCdAAAFfwW1ACYA+QAAACcAigQqAAAABwBoARcABf//AEH+SwUXBbACJgA6AAAABwGaA7AAAP//AC7+SwQfBDoCJgBaAAAABwGaArgAAP//AGT/7APwBhgCBgBGAAD//wAw/ksFrAWwAiYA2AAAAAcBmgRFAAD//wAo/ksEuwQ6AiYA7QAAAAcBmgNUAAD//wAn/rEFIgWwAiYAIwAAAAcAqAUBAAD//wBy/rED7AROAiYAQwAAAAcAqARQAAD//wAnAAAFIgfGAiYAIwAAAAcApgT1AVP//wBy/+wD7AaEAiYAQwAAAAcApgR3ABH//wAnAAAFIgeoAiYAIwAAAAcBowDKARb//wBy/+wEpAZnAiYAQwAAAAYBo0zVAAD//wAnAAAFIgelAiYAIwAAAAcBogDOASX///+u/+wD7AZkAiYAQwAAAAYBolDkAAD//wAnAAAFIgfbAiYAIwAAAAcBoQDPAQ3//wBy/+wEPQaaAiYAQwAAAAYBoVHMAAD//wAnAAAFIgflAiYAIwAAAAcBoADOARP//wBy/+wD7AakAiYAQwAAAAYBoFDSAAD//wAn/rEFIgdGAiYAIwAAACcAmgDQAV0ABwCoBQEAAP//AHL+sQPsBgQCJgBDAAAAJgCaUhsABwCoBFAAAAAA//8AJwAABSIH3QImACMAAAAHAZ8A8QFU//8Acv/sA+wGmwImAEMAAAAGAZ9zEgAA//8AJwAABSIH4AImACMAAAAHAaQA9QFn//8Acv/sA+wGngImAEMAAAAGAaR3JQAA//8AJwAABSIISwImACMAAAAHAZ4A9QFJ//8Acv/sA+wHCQImAEMAAAAGAZ53BwAA//8AJwAABSIIHwImACMAAAAHAZ0A9QFR//8Acv/sA+wG3QImAEMAAAAGAZ13DwAA//8AJ/6xBSIHTAImACMAAAAnAJwA+wGcAAcAqAUBAAD//wBy/rED7AYKAiYAQwAAACYAnH1aAAcAqARQAAAAAP//ALb+uwR1BbACJgAnAAAABwCoBMgACv//AGL+sQPpBE4CJgBHAAAABwCoBJIAAP//ALYAAAR1B8YCJgAnAAAABwCmBMEBU///AGL/7APpBoUCJgBHAAAABwCmBHwAEv//ALYAAAR1B1ECJgAnAAAABwCgAJYBYP//AGL/7APpBhACJgBHAAAABgCgUR8AAP//ALYAAATuB6gCJgAnAAAABwGjAJYBFv//AGL/7ASpBmgCJgBHAAAABgGjUdYAAP////gAAAR1B6UCJgAnAAAABwGiAJoBJf///7P/7APpBmUCJgBHAAAABgGiVeUAAP//ALYAAASHB9sCJgAnAAAABwGhAJsBDf//AGL/7ARCBpsCJgBHAAAABgGhVs0AAP//ALYAAAR1B+UCJgAnAAAABwGgAJoBE///AGL/7APpBqUCJgBHAAAABgGgVdMAAP//ALb+uwR1B0YCJgAnAAAAJwCaAJwBXQAHAKgEyAAK//8AYv6xA+kGBQImAEcAAAAmAJpXHAAHAKgEkgAAAAD//wDDAAACAQfGAiYAKwAAAAcApgNtAVP//wCbAAAB2gZwAiYAigAAAAcApgNG//3//wC3/rkBhgWwAiYAKwAAAAcAqAN0AAj//wCW/rsBZQYYAiYASwAAAAcAqANTAAr//wCC/qkFDQXFAiYAMQAAAAcAqAUd//j//wBg/qgEJwROAiYAUQAAAAcAqASb//f//wCC/+sFDQfbAiYAMQAAAAcApgUVAWj//wBg/+wEJwaEAiYAUQAAAAcApgSUABH//wCC/+sFQge9AiYAMQAAAAcBowDqASv//wBg/+wEwQZnAiYAUQAAAAYBo2nVAAD//wBM/+sFDQe6AiYAMQAAAAcBogDuATr////L/+wEJwZkAiYAUQAAAAYBom3kAAD//wCC/+sFDQfwAiYAMQAAAAcBoQDvASL//wBg/+wEWgaaAiYAUQAAAAYBoW7MAAD//wCC/+sFDQf6AiYAMQAAAAcBoADuASj//wBg/+wEJwakAiYAUQAAAAYBoG3SAAD//wCC/qkFDQdbAiYAMQAAACcAmgDwAXIABwCoBR3/+P//AGD+qAQnBgQCJgBRAAAAJgCabxsABwCoBJv/9wAA//8Acf/rBZ0HDwImAJQAAAAHAHMB5gFJ//8AYP/sBLoF3QImAJUAAAAHAHMBbQAX//8Acf/rBZ0HEgImAJQAAAAHAEIBLAFN//8AYP/sBLoF4AImAJUAAAAHAEIAswAb//8Acf/rBZ0HtgImAJQAAAAHAKYFDQFD//8AYP/sBLoGhAImAJUAAAAHAKYElAAR//8Acf/rBZ0HQQImAJQAAAAHAKAA4gFQ//8AYP/sBLoGDwImAJUAAAAGAKBpHgAA//8Acf6xBZ0GNgImAJQAAAAHAKgFCQAA//8AYP6oBLoEsAImAJUAAAAHAKgEm//3//8Alv6qBNcFsAImADcAAAAHAKgFDP/5//8Ajf6xA/YEOgImAFcAAAAHAKgEVwAA//8Alv/rBNcHxgImADcAAAAHAKYFBwFT//8Ajf/sA/YGcAImAFcAAAAHAKYEkv/9//8Alv/rBiYHHwImAJYAAAAHAHMB3QFZ//8Ajf/sBRAFyAImAJcAAAAHAHMBawAC//8Alv/rBiYHIgImAJYAAAAHAEIBIwFd//8Ajf/sBRAFywImAJcAAAAHAEIAsQAG//8Alv/rBiYHxgImAJYAAAAHAKYFBAFT//8Ajf/sBRAGcAImAJcAAAAHAKYEkv/9//8Alv/rBiYHUQImAJYAAAAHAKAA2QFg//8Ajf/sBRAF+gImAJcAAAAGAKBnCQAA//8Alv6pBiYGDQImAJYAAAAHAKgFCf/4//8Ajf6xBRAEkQImAJcAAAAHAKgEVwAA//8AHv67BNMFsAImADsAAAAHAKgEzgAK//8AG/4UA+QEOgImAFsAAAAHAKgFIv9j//8AHgAABNMHxAImADsAAAAHAKYExwFR//8AG/5LA+QGcAImAFsAAAAHAKYEUP/9//8AHgAABNMHTwImADsAAAAHAKAAnAFe//8AG/5LA+QF+gImAFsAAAAGAKAlCQAAAAIAZP/sBLEGGAAaACgAAAEjESMnDgEjIgI9ARASMzIWFzcRITUhNTMVMwEUFjMyNjcRLgEjIgYVBLHBoRA2mGnJ29rMZJI0A/7+AQK5wfxsh5JeeikofFuTiATS+y6HTk0BGu8VAQoBOkhGAQERlbGx/I6qxVJMAfZIUurAAAD//wBk/u4EsQYYACYARgAAACcB0wGmAkYABwBBAKP/g///ALb+mQVbBbACJgAtAAAABwGcBDoAAP//AJz+mQRpBDoCJgDsAAAABwGcA0gAAP//ALb+mQWHBbACJgAqAAAABwGcBGYAAP//AJz+mQSKBDoCJgDvAAAABwGcA2kAAP//ADv+mQSKBbACJgA2AAAABwGcAigAAP//ACj+mQOwBDoCJgDxAAAABwGcAa4AAP//AEH+mQTpBbACJgA6AAAABwGcA8gAAP//AC7+mQPxBDoCJgBaAAAABwGcAtAAAP//AJf+mQVOBbACJgDcAAAABwGcBC0AAP//AGf+mQRGBDsCJgD0AAAABwGcAyUAAP//AJf+mQTEBbACJgDcAAAABwGcAxkAAP//AGf+mQO9BDsCJgD0AAAABwGcAhAAAP//ALX+mQQwBbACJgCsAAAABwGcANcAAP//AJr+mQNHBDoCJgDnAAAABwGcAJ4AAP//ABv+mQdqBbACJgDVAAAABwGcBkkAAP//ABX+mQYlBDoCJgDpAAAABwGcBQQAAP//AEf+VAXABcMCJgE7AAAABwGcAwb/u////+P+WARZBE4CJgE8AAAABwGcAgH/v///AJEAAAP6BhgCBgBKAAAAAv/UAAAEsQWwABIAGwAAASMVITIWFRQGIyERIzUzNTMVMwMRITI2NTQmIwJQ8QFo7vz97f3f0tK58fEBaJyUlJwEUPjhx8joBFCVy8v93v3Sn355mAAAAAL/1AAABLEFsAASABsAAAEjFSEyFhUUBiMhESM1MzUzFTMDESEyNjU0JiMCUPEBaO78/e3939LSufHxAWiclJScBFD44cfI6ARQlcvL/d790p9+eZgAAAABAAMAAAQwBbAADQAAASERIxEjNTMRIRUhESECf/7vubKyA3v9PgERAqz9VAKslQJvlv4nAAAAAAH//AAAA0cEOgANAAABIREjESM1MxEhFSERIQJ4/ty6np4Crf4NASQB3/4hAd+VAcaX/tEAAAAAAf/1AAAFMAWwABQAAAEjESMRIzUzNTMVMxUjETMBMwkBIwIzsLnV1bnu7p8CEdT9wwJm4wKU/WwEhZWWlpX+pAKH/T79EgAAAf/YAAAEKAYYABQAAAEjESMRIzUzNTMVMxUjETMBMwkBIwHhgbrOzrr09H4BO9v+hgGu2wH2/goEwZXCwpX9zAGt/hP9swD//wC2/ooFtwdMAiYA1wAAACcAnAExAZwABwAOBIP/vv//AJz+igS6BfUCJgDrAAAAJwCcAKIARQAHAA4Dhv++//8Atv6KBbYFsAImACoAAAAHAA4Egv++//8AnP6KBLkEOgImAO8AAAAHAA4Dhf++//8Atv6KBwYFsAImAC8AAAAHAA4F0v++//8Anf6KBgsEOgImAO4AAAAHAA4E1/++//8AMP6KBa0FsAImANgAAAAHAA4Eef++//8AKP6KBLwEOgImAO0AAAAHAA4DiP++AAEAHgAABNMFsAAQAAAJATMBMxUjBxEjEScjNTMBMwJ4AYfU/ld+zwi4Aeya/ljUAr4C8vz2lQ/9/gIPApUDCgABAC7+YAPfBDoAEQAABSMRIxEjNTMBMwEXMzcBMwEzA0rmutzB/p+9AQcWAxcBAL3+oskM/mwBlJUDsf0AXl4DAPxPAAEAQQAABNAFsAARAAABIwEjCQEjASM1MwEzCQEzATMDzbABs9z+lv6X4AGyopX+Zt4BXAFg3/5lowKe/WICSP24Ap6VAn39wwI9/YMAAAAAAQAuAAADzwQ6ABEAAAEjASMLASMBIzUzATMbATMBMwM+rwFA1fr62AFBraL+1dbt8Nj+1qQB4f4fAZ7+YgHhlQHE/m0Bk/48AAAA//8AY//tA+wETAIGALoAAP//ABsAAARzBbACJgAoAAAABwHT/4z+fv//ALsCjAXzAyEARgGGrwBmZkAAAAIAqQAAAWYFsAADAAcAAAEjETMTIzUzAWS5uQK9vQHeA9L6UMgAAAAAAAAAAAAAAAAAGgBSAJIA6AFAAVABcgGWAboB0gHoAfYCAgIQAkACUAJ6ArQC1AMGA0YDZAOuA/AD/AQIBCAENARMBHwE8AUMBUIFdAWaBbQFygYABhgGJAZABlwGbAaQBqgG3gcCB0AHeAeyB8YH5gf+CCoISghiCHgIjAiaCKwIxAjSCOAJHglUCYAJtAnmCgoKTgpyCoQKqArECtALCgsuC1wLkgvGC+YMHgxEDGgMgAyqDMgM8g0IDTgNRg10DZ4Nsg3mDhoOZg6QDqQPCA8cD3IPsg++D84QMhBAEGYQhhCwEOoQ+BEgETYRRBFgEXIRnBGoEboRzBHeEg4SOBJaEqwS0hMME2gTthPQFBwUUhR8FIgUpBTAFNgVAhU2FXQVyBXkFhoWXBaWFsAW7hcMF0AXVBdoF4IXkBe2F9gX+BgOGDQYQhhQGFoYeBiOGJwYqhjEGMwY3hj0GTAZRhliGXQZkhnQGfoaNBp4Grga1BscG1YbjhuyG+ocCBw+HIgcsBzkHRgdTh1yHZgd1h4IHkgehB7AHwYfNB9qH6If0h/6IBIgOiBmIJIgziDmIQYhLiFwIYghqiHEIeQiDCI2IloijiLMIvYjOCNuI4AjqiPWJBAkKCREJGYkhCScJK4kwiUcJTQlViVwJZAluCXkJggmNiZuJpgm1icGJzwnbCeaJ7Qn5igYKEYohCi8KN4pBCkyKWIpoCnUKhwqXCqsKvorNitqK44rtiv4LDQslCz0LTItcC2cLcQt8C4ELiIuMi5CLtwvNC9iL44vzC/iL/gwIDBIMG4wlDC0MNQw8DEMMTYxYDG2MggyJjJEMm4yljK4MvozNjNgM4gzsDPYNBA0PDRoNHg0iDSsNOI1NjV6NcA2ADZCNnw2tDbqNxw3WDeON7437DgqOCo4KjgqOCo4KjgqOCo4KjgqOCo4KjgqODQ4PjhKOGA4djiMOJg4pDiwONQ47jkSOSo5NjlGOcI51jnsOfo6Gjo8Ong6ujr4O047iDvMO/Y8LDw+PFA8Yjx0PK48wjzgPO49CD1aPYg94D4GPhY+Jj5MPlo+bj6EPq4+rj+IP85AAEAgQFBAbkCKQKxAukDsQRxBPEFqQZJBrEHGQeZB9kISQkhCdkKaQrRCykL8QxRDIEM8Q1hDaEOIQ6JD0EQGRD5EdkSKRKpEwkTqRQpFIkU4RWRFdEWeRdhF+EYiRl5GekbCRv5HDkc2R3BHgEewR+xIBkhOSIpItEjCSPBJEElKSWpJnEncSkpKaEqmSvBLKEtuS5RL0kv+TBxMOkxWTHJMtEzYTOBM6EzwTSBNUE1+TZpNyE3UTeBN7E34TgROEE4cTihONE5ATkxOWE5kTnBOfE6ITpROoE6sTrhOxE7QTtxO6E70TwBPDE8YTyRPME88T0hPVE9gT2xPeE+ET5BPnE+oT7RPwE/MT9hP5E/wT/xQCFAUUCBQLFA4UERQUFBcUGhQdFCAUIxQwFEYUSRRMFE8UUhRVFFgUWxReFGEUZBRnFGoUbRRwFHMUdhSDFJYUmRScFJ8UohSlFKgUqxSuFLEUtBS3FLoUvRTAFMMUxhTJFMwUzxTSFNUU2BTbFN4U4RTkFOcU6hTtFPAU8xT2FPkU/BT/FQIVBRUIFQsVDhURFRQVFxUaFR0VIBUjFSYVKRUsFS8VMhU1FTgVOxU+FUEVRBVHFUoVTRVQFVMVVhVZFVwVXxViFWUVaBVrFW4VcRV0FXcVehV9FYAVgxWGFZUVpBWnFaoVrRWwFbMVthW5FbwVvxXCFcUVyBXLFc4V0RXUFdcV2hXdFeAV4xXmFekV7BXvFfIV9RX4FfsV/hYBFgQWBxYKFg0WEBYTFhYWGRYcFh8WIhYlFigWKxYuFjEWPhZBFkQWRxZKFk0WUBZTFlYWYxZmFmkWbBZvFnIWdRZ4FnsWfhaBFoQWhxaKFo0WkBaTFpYWmRacFp8WohalFqgWqxauFrEWtBa3FroWvRbAFsMWxhbJFswWzxbSFuEW5BbnFuoW7RbwFvMW9hb5FvwW/xcCFwUXCBcLFw4XEBcSFxQXFhcYFxoXHBceFyAXIhckFyYXKBcqFy0XMBczFzYXORc8Fz8XQRdDF0UXRxdJF0wXTxdSF1UXWBdbF14XbJdul3GXc5d1l3iXe5d9l3+XgZeDl4aXiJeKl4yXjpeQl5KXlJeWl5iXmpedl5+XoZesl66XsJezl7aXuJe6l72Xv5fCl8WXyJfLl86X0ZfUl9eX2pfdl9+X4Zfkl+eX6pfsl++X8pf1l/iX+5f+mAKYBZgImAuYDpgQmBKYFZgYmBuYHpghmCSYJ5gqmCyYLpgwmDOYNpg4mDuYPphBmESYRphImEuYTphRmFOYVphZmFyYX5himGWYaJhrmG6YcZh0mHaYeJh7mH6YgZiEmIeYipiNmJCYk5iWmJmYnJigmKSYp5iqmKyYr5iymLWYuJi7mL6YwZjEmMeYypjNmNCY05jWmNqY3pjhmOSY55jqmO2Y8JjzmPaY+pj+mQGZBJkHmQqZDZkQmROZFpkZmRyZH5kimSWZKJksmTCZM5k2mTmZPJk/mUKZRZlImUuZTplRmVSZV5lamV2ZYJlkmWiZa5lumXGZdJl3mXqZfZmAmYOZhpmJmYyZj5mSmZWZmJmbmZ6ZoZmkmaeZqpmtmbCZs5m2mbmZvJm/mcKZ0pnWmdmZ3JnfmeKZ5ZnomeuZ7pnxmfSZ95n6mf2aAJoDmgaaCZoMmg6aGZokmiuaMpo7mkSaSJpMmk+aUppVmliaW5pemmaabxp5GoKahJqHmooaihqPAAAAAAAGwFKAAEAAAAAAAAAHwAAAAEAAAAAAAEABgAfAAEAAAAAAAIABwAlAAEAAAAAAAMAEgAsAAEAAAAAAAQADgA+AAEAAAAAAAUAFgBMAAEAAAAAAAYADgBiAAEAAAAAAAcAIABwAAEAAAAAAAkABgCQAAEAAAAAAAsACgCWAAEAAAAAAAwAEwCgAAEAAAAAAA0ALgCzAAEAAAAAAA4AKgDhAAEAAAAAABIADgELAAMAAQQJAAAAPgEZAAMAAQQJAAEADAFXAAMAAQQJAAIADgFjAAMAAQQJAAMAJAFxAAMAAQQJAAQAHAGVAAMAAQQJAAUALAGxAAMAAQQJAAYAHAHdAAMAAQQJAAcAQAH5AAMAAQQJAAkADAI5AAMAAQQJAAsAFAJFAAMAAQQJAAwAJgJZAAMAAQQJAA0AXAJ/AAMAAQQJAA4AVALbRm9udCBkYXRhIGNvcHlyaWdodCBHb29nbGUgMjAxM1JvYm90b1JlZ3VsYXJHb29nbGU6Um9ib3RvOjIwMTNSb2JvdG8gUmVndWxhclZlcnNpb24gMS4yMDAzMTA7IDIwMTNSb2JvdG8tUmVndWxhclJvYm90byBpcyBhIHRyYWRlbWFyayBvZiBHb29nbGUuR29vZ2xlR29vZ2xlLmNvbUNocmlzdGlhbiBSb2JlcnRzb25MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4waHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wUm9ib3RvIFJlZ3VsYXIARgBvAG4AdAAgAGQAYQB0AGEAIABjAG8AcAB5AHIAaQBnAGgAdAAgAEcAbwBvAGcAbABlACAAMgAwADEAMwBSAG8AYgBvAHQAbwBSAGUAZwB1AGwAYQByAEcAbwBvAGcAbABlADoAUgBvAGIAbwB0AG8AOgAyADAAMQAzAFIAbwBiAG8AdABvACAAUgBlAGcAdQBsAGEAcgBWAGUAcgBzAGkAbwBuACAAMQAuADIAMAAwADMAMQAwADsAIAAyADAAMQAzAFIAbwBiAG8AdABvAC0AUgBlAGcAdQBsAGEAcgBSAG8AYgBvAHQAbwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAEcAbwBvAGcAbABlAC4ARwBvAG8AZwBsAGUARwBvAG8AZwBsAGUALgBjAG8AbQBDAGgAcgBpAHMAdABpAGEAbgAgAFIAbwBiAGUAcgB0AHMAbwBuAEwAaQBjAGUAbgBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAQQBwAGEAYwBoAGUAIABMAGkAYwBlAG4AcwBlACwAIABWAGUAcgBzAGkAbwBuACAAMgAuADAAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAcABhAGMAaABlAC4AbwByAGcALwBsAGkAYwBlAG4AcwBlAHMALwBMAEkAQwBFAE4AUwBFAC0AMgAuADAAAAAAAgAAAAAAAP9qAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAQcAAABAgACAAMABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAowCEAIUAvQCWAOgAhgCOAIsAnQCpAKQAigEDAIMAkwDyAPMAjQCXAIgBBADeAPEAngCqAPUA9AD2AKIAkADwAJEA7QCJAKAA6gC4AKEA7gEFANcBBgDiAOMBBwEIALAAsQEJAKYBCgELAQwBDQEOAQ8A2ADhANsA3ADdAOAA2QDfARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIAnwEjASQBJQEmAScBKAEpASoBKwEsAS0AmwEuAS8BMAExATIBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwFAAUEBQgFDAUQBRQFGAUcBSAFJAUoBSwFMAU0BTgFPAVABUQFSAVMBVAFVAVYBVwFYAVkBWgFbAVwBXQFeAV8BYAFhAWIBYwFkAWUBZgFnAWgBaQFqAWsBbAFtAW4BbwFwAXEBcgFzAXQBdQF2AXcBeAF5AXoBewF8AX0BfgF/AYABgQGCAYMBhAGFAYYBhwGIAYkBigGLAYwBjQGOAY8BkAGRAZIBkwGUAZUBlgGXAZgBmQGaAZsBnAGdAZ4BnwGgAaEBogGjAaQBpQGmAacBqAGpAaoBqwGsAa0BrgGvAbABsQGyAbMBtAG1AbYBtwG4AbkBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNALIAswHOALYAtwDEAc8AtAC1AMUAggDCAIcB0ACrAMYAvgC/ALwB0QHSAdMB1AHVAdYB1wHYAIwB2QHaAdsB3AHdAJgAmgCZAO8ApQCSAJwApwCPAJQAlQC5Ad4B3wHgAMAB4QHiAeMB5AHlAeYB5wHoAekB6gHrAewB7QHuAe8B8AHxAfIB8wH0AfUB9gH3AfgB+QH6AfsB/AH9Af4B/wIAAgECAgIDAgQCBQIGAgcCCAIJAgoCCwIMAg0CDgIPAhACEQISAhMCFAIVAhYCFwIYAhkCGgIbAhwCHQIeAh8CIAIhAiICIwIkAiUCJgInAigCKQIqAisCLAItAi4CLwIwAjECMgIzAjQCNQI2AjcArAI4AjkA6QI6AjsCPACtAMkAxwCuAGIAYwI9AGQAywBlAMgAygDPAMwAzQDOAGYA0wDQANEArwBnANYA1ADVAGgA6wBqAGkAawBtAGwAbgI+AG8AcQBwAHIAcwB1AHQAdgB3AHgAegB5AHsAfQB8AH8AfgCAAIEA7AC6Aj8CQAJBAkICQwJEAP0A/gJFAkYCRwJIAP8BAAJJAkoCSwJMAk0CTgJPAlACUQJSAlMCVAJVAlYA+AD5AlcCWAJZAloCWwJcAl0CXgJfAmACYQJiAmMCZAJlAmYCZwJoAmkCagJrAmwCbQJuAm8CcAJxAnICcwJ0AnUCdgJ3AngCeQJ6AnsCfAJ9An4CfwKAAoECggKDAoQChQKGAocCiAKJAooA+wD8AosCjADkAOUCjQKOAo8CkAKRApICkwKUApUClgKXApgCmQKaApsCnAKdAp4CnwKgAqECogC7AqMCpAKlAqYA5gDnAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArYCtwK4ArkCugK7ArwCvQK+Ar8CwALBAsICwwLEAsUCxgLHAsgCyQLKAssCzALNAs4CzwLQAtEC0gLTAtQC1QLWAtcC2ALZAtoC2wLcAt0C3gLfAuAC4QLiAuMC5ALlAuYC5wLoAukC6gLrAuwC7QLuAu8C8ALxAvIC8wL0AvUC9gL3AvgC+QL6AvsC/AL9Av4C/wMAAwEDAgMDAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYAxkDGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNUA1UDVgNXA1gDWQNaA1sDXANdA14DXwNgA2EDYgNjA2QDZQNmA2cDaANpA2oDawNsA20DbgNvA3ADcQNyA3MDdAN1A3YDdwN4A3kDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DngOfA6ADoQOiA6MDpAOlA6YDpwOoA6kDqgOrA6wDrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPDA8QDxQPGA8cDyAPJA8oDywPMA80DzgPPA9AD0QPSA9MD1APVA9YD1wPYA9kD2gPbA9wD3QPeA98D4APhA+ID4wPkA+UD5gPnA+gD6QPqA+sD7APtA+4D7wPwA/ED8gPzA/QD9QP2A/cD+AP5A/oD+wP8A/0D/gP/BAAEAQQCBAMEBAQFBAYEBwQIBAkECgQLBAwEDQQOBA8EEAQRBBIEEwQUBBUEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEA9wQiBCMABAd1bmkwMDA5Bm1hY3Jvbg5wZXJpb2RjZW50ZXJlZARIYmFyDGtncmVlbmxhbmRpYwNFbmcDZW5nBWxvbmdzBU9ob3JuBW9ob3JuBVVob3JuBXVob3JuB3VuaTAyMzcFc2Nod2EHdW5pMDJGMwlncmF2ZWNvbWIJYWN1dGVjb21iCXRpbGRlY29tYgRob29rB3VuaTAzMEYIZG90YmVsb3cFdG9ub3MNZGllcmVzaXN0b25vcwlhbm90ZWxlaWEFR2FtbWEFRGVsdGEFVGhldGEGTGFtYmRhAlhpAlBpBVNpZ21hA1BoaQNQc2kFYWxwaGEEYmV0YQVnYW1tYQVkZWx0YQdlcHNpbG9uBHpldGEDZXRhBXRoZXRhBGlvdGEGbGFtYmRhAnhpA3JobwZzaWdtYTEFc2lnbWEDdGF1B3Vwc2lsb24DcGhpA3BzaQVvbWVnYQd1bmkwM0QxB3VuaTAzRDIHdW5pMDNENgd1bmkwNDAyB3VuaTA0MDQHdW5pMDQwOQd1bmkwNDBBB3VuaTA0MEIHdW5pMDQwRgd1bmkwNDExB3VuaTA0MTQHdW5pMDQxNgd1bmkwNDE3B3VuaTA0MTgHdW5pMDQxQgd1bmkwNDIzB3VuaTA0MjQHdW5pMDQyNgd1bmkwNDI3B3VuaTA0MjgHdW5pMDQyOQd1bmkwNDJBB3VuaTA0MkIHdW5pMDQyQwd1bmkwNDJEB3VuaTA0MkUHdW5pMDQyRgd1bmkwNDMxB3VuaTA0MzIHdW5pMDQzMwd1bmkwNDM0B3VuaTA0MzYHdW5pMDQzNwd1bmkwNDM4B3VuaTA0M0EHdW5pMDQzQgd1bmkwNDNDB3VuaTA0M0QHdW5pMDQzRgd1bmkwNDQyB3VuaTA0NDQHdW5pMDQ0Ngd1bmkwNDQ3B3VuaTA0NDgHdW5pMDQ0OQd1bmkwNDRBB3VuaTA0NEIHdW5pMDQ0Qwd1bmkwNDREB3VuaTA0NEUHdW5pMDQ0Rgd1bmkwNDUyB3VuaTA0NTQHdW5pMDQ1OQd1bmkwNDVBB3VuaTA0NUIHdW5pMDQ1Rgd1bmkwNDYwB3VuaTA0NjEHdW5pMDQ2Mwd1bmkwNDY0B3VuaTA0NjUHdW5pMDQ2Ngd1bmkwNDY3B3VuaTA0NjgHdW5pMDQ2OQd1bmkwNDZBB3VuaTA0NkIHdW5pMDQ2Qwd1bmkwNDZEB3VuaTA0NkUHdW5pMDQ2Rgd1bmkwNDcyB3VuaTA0NzMHdW5pMDQ3NAd1bmkwNDc1B3VuaTA0N0EHdW5pMDQ3Qgd1bmkwNDdDB3VuaTA0N0QHdW5pMDQ3RQd1bmkwNDdGB3VuaTA0ODAHdW5pMDQ4MQd1bmkwNDgyB3VuaTA0ODMHdW5pMDQ4NAd1bmkwNDg1B3VuaTA0ODYHdW5pMDQ4OAd1bmkwNDg5B3VuaTA0OEQHdW5pMDQ4RQd1bmkwNDhGB3VuaTA0OTAHdW5pMDQ5MQd1bmkwNDk0B3VuaTA0OTUHdW5pMDQ5Qwd1bmkwNDlEB3VuaTA0QTAHdW5pMDRBMQd1bmkwNEE0B3VuaTA0QTUHdW5pMDRBNgd1bmkwNEE3B3VuaTA0QTgHdW5pMDRBOQd1bmkwNEI0B3VuaTA0QjUHdW5pMDRCOAd1bmkwNEI5B3VuaTA0QkEHdW5pMDRCQwd1bmkwNEJEB3VuaTA0QzMHdW5pMDRDNAd1bmkwNEM3B3VuaTA0QzgHdW5pMDREOAd1bmkwNEUwB3VuaTA0RTEHdW5pMDRGQQd1bmkwNEZCB3VuaTA1MDAHdW5pMDUwMgd1bmkwNTAzB3VuaTA1MDQHdW5pMDUwNQd1bmkwNTA2B3VuaTA1MDcHdW5pMDUwOAd1bmkwNTA5B3VuaTA1MEEHdW5pMDUwQgd1bmkwNTBDB3VuaTA1MEQHdW5pMDUwRQd1bmkwNTBGB3VuaTA1MTAHdW5pMjAwMAd1bmkyMDAxB3VuaTIwMDIHdW5pMjAwMwd1bmkyMDA0B3VuaTIwMDUHdW5pMjAwNgd1bmkyMDA3B3VuaTIwMDgHdW5pMjAwOQd1bmkyMDBBB3VuaTIwMEINdW5kZXJzY29yZWRibA1xdW90ZXJldmVyc2VkB3VuaTIwMjUHdW5pMjA3NAluc3VwZXJpb3IEbGlyYQZwZXNldGEERXVybwd1bmkyMTA1B3VuaTIxMTMHdW5pMjExNgllc3RpbWF0ZWQJb25lZWlnaHRoDHRocmVlZWlnaHRocwtmaXZlZWlnaHRocwxzZXZlbmVpZ2h0aHMKY29sb24ubG51bQlxdW90ZWRibHgLY29tbWFhY2NlbnQHdW5pRkVGRgd1bmlGRkZDB3VuaUZGRkQJZml2ZS5zbWNwCGZvdXIuc3VwCXplcm8ubG51bQ5sYXJnZXJpZ2h0aG9vawxjeXJpbGxpY2hvb2sQY3lyaWxsaWNob29rbGVmdAtjeXJpbGxpY3RpYw5icmV2ZXRpbGRlY29tYg1icmV2ZWhvb2tjb21iDmJyZXZlYWN1dGVjb21iE2NpcmN1bWZsZXh0aWxkZWNvbWISY2lyY3VtZmxleGhvb2tjb21iE2NpcmN1bWZsZXhncmF2ZWNvbWITY2lyY3VtZmxleGFjdXRlY29tYg5icmV2ZWdyYXZlY29tYhFjb21tYWFjY2VudHJvdGF0ZQZBLnNtY3AGQi5zbWNwBkMuc21jcAZELnNtY3AGRS5zbWNwBkYuc21jcAZHLnNtY3AGSC5zbWNwBkkuc21jcAZKLnNtY3AGSy5zbWNwBkwuc21jcAZNLnNtY3AGTi5zbWNwBk8uc21jcAZRLnNtY3AGUi5zbWNwBlMuc21jcAZULnNtY3AGVS5zbWNwBlYuc21jcAZXLnNtY3AGWC5zbWNwBlkuc21jcAZaLnNtY3AJemVyby5zbWNwCG9uZS5zbWNwCHR3by5zbWNwCnRocmVlLnNtY3AJZm91ci5zbWNwCHR3by5sbnVtCHNpeC5zbWNwCnNldmVuLnNtY3AKZWlnaHQuc21jcAluaW5lLnNtY3AHb25lLnN1cAd0d28uc3VwCXRocmVlLnN1cAhvbmUubG51bQhmaXZlLnN1cAdzaXguc3VwCXNldmVuLnN1cAllaWdodC5zdXAIbmluZS5zdXAIemVyby5zdXAIY3Jvc3NiYXIJcmluZ2FjdXRlCWRhc2lhb3hpYQp0aHJlZS5sbnVtCWZvdXIubG51bQlmaXZlLmxudW0Ic2l4LmxudW0FZy5hbHQKc2V2ZW4ubG51bQdjaGkuYWx0CmVpZ2h0LmxudW0JYWxwaGEuYWx0CWRlbHRhLmFsdARELmNuBGEuY24FUi5hbHQFSy5hbHQFay5hbHQGSy5hbHQyBmsuYWx0MgluaW5lLmxudW0GUC5zbWNwDWN5cmlsbGljYnJldmUHdW5pMDBBRAZEY3JvYXQEaGJhcgRUYmFyBHRiYXIKQXJpbmdhY3V0ZQphcmluZ2FjdXRlB0FtYWNyb24HYW1hY3JvbgZBYnJldmUGYWJyZXZlB0FvZ29uZWsHYW9nb25lawtDY2lyY3VtZmxleAtjY2lyY3VtZmxleAd1bmkwMTBBB3VuaTAxMEIGRGNhcm9uBmRjYXJvbgdFbWFjcm9uB2VtYWNyb24GRWJyZXZlBmVicmV2ZQpFZG90YWNjZW50CmVkb3RhY2NlbnQHRW9nb25lawdlb2dvbmVrBkVjYXJvbgZlY2Fyb24LR2NpcmN1bWZsZXgLZ2NpcmN1bWZsZXgHdW5pMDEyMAd1bmkwMTIxDEdjb21tYWFjY2VudAxnY29tbWFhY2NlbnQLSGNpcmN1bWZsZXgLaGNpcmN1bWZsZXgGSXRpbGRlBml0aWxkZQdJbWFjcm9uB2ltYWNyb24GSWJyZXZlBmlicmV2ZQdJb2dvbmVrB2lvZ29uZWsKSWRvdGFjY2VudAJJSgJpagtKY2lyY3VtZmxleAtqY2lyY3VtZmxleAxLY29tbWFhY2NlbnQMa2NvbW1hYWNjZW50BkxhY3V0ZQZsYWN1dGUMTGNvbW1hYWNjZW50DGxjb21tYWFjY2VudAZMY2Fyb24GbGNhcm9uBExkb3QEbGRvdAZOYWN1dGUGbmFjdXRlDE5jb21tYWFjY2VudAxuY29tbWFhY2NlbnQGTmNhcm9uBm5jYXJvbgtuYXBvc3Ryb3BoZQdPbWFjcm9uB29tYWNyb24GT2JyZXZlBm9icmV2ZQ1PaHVuZ2FydW1sYXV0DW9odW5nYXJ1bWxhdXQGUmFjdXRlBnJhY3V0ZQxSY29tbWFhY2NlbnQMcmNvbW1hYWNjZW50BlJjYXJvbgZyY2Fyb24GU2FjdXRlBnNhY3V0ZQtTY2lyY3VtZmxleAtzY2lyY3VtZmxleAd1bmkwMjE4B3VuaTAyMTkHdW5pMDIxQQd1bmkwMjFCB3VuaTAxNjIHdW5pMDE2MwZUY2Fyb24GdGNhcm9uBlV0aWxkZQZ1dGlsZGUHVW1hY3Jvbgd1bWFjcm9uBlVicmV2ZQZ1YnJldmUFVXJpbmcFdXJpbmcNVWh1bmdhcnVtbGF1dA11aHVuZ2FydW1sYXV0B1VvZ29uZWsHdW9nb25lawtXY2lyY3VtZmxleAt3Y2lyY3VtZmxleAtZY2lyY3VtZmxleAt5Y2lyY3VtZmxleAZaYWN1dGUGemFjdXRlClpkb3RhY2NlbnQKemRvdGFjY2VudAdBRWFjdXRlB2FlYWN1dGULT3NsYXNoYWN1dGULb3NsYXNoYWN1dGULRGNyb2F0LnNtY3AIRXRoLnNtY3AJVGJhci5zbWNwC0FncmF2ZS5zbWNwC0FhY3V0ZS5zbWNwEEFjaXJjdW1mbGV4LnNtY3ALQXRpbGRlLnNtY3AOQWRpZXJlc2lzLnNtY3AKQXJpbmcuc21jcA9BcmluZ2FjdXRlLnNtY3ANQ2NlZGlsbGEuc21jcAtFZ3JhdmUuc21jcAtFYWN1dGUuc21jcBBFY2lyY3VtZmxleC5zbWNwDkVkaWVyZXNpcy5zbWNwC0lncmF2ZS5zbWNwC0lhY3V0ZS5zbWNwEEljaXJjdW1mbGV4LnNtY3AOSWRpZXJlc2lzLnNtY3ALTnRpbGRlLnNtY3ALT2dyYXZlLnNtY3ALT2FjdXRlLnNtY3AQT2NpcmN1bWZsZXguc21jcAtPdGlsZGUuc21jcA5PZGllcmVzaXMuc21jcAtVZ3JhdmUuc21jcAtVYWN1dGUuc21jcBBVY2lyY3VtZmxleC5zbWNwDlVkaWVyZXNpcy5zbWNwC1lhY3V0ZS5zbWNwDEFtYWNyb24uc21jcAtBYnJldmUuc21jcAxBb2dvbmVrLnNtY3ALQ2FjdXRlLnNtY3AQQ2NpcmN1bWZsZXguc21jcAx1bmkwMTBBLnNtY3ALQ2Nhcm9uLnNtY3ALRGNhcm9uLnNtY3AMRW1hY3Jvbi5zbWNwC0VicmV2ZS5zbWNwD0Vkb3RhY2NlbnQuc21jcAxFb2dvbmVrLnNtY3ALRWNhcm9uLnNtY3AQR2NpcmN1bWZsZXguc21jcAtHYnJldmUuc21jcAx1bmkwMTIwLnNtY3ARR2NvbW1hYWNjZW50LnNtY3AQSGNpcmN1bWZsZXguc21jcAtJdGlsZGUuc21jcAxJbWFjcm9uLnNtY3ALSWJyZXZlLnNtY3AMSW9nb25lay5zbWNwD0lkb3RhY2NlbnQuc21jcBBKY2lyY3VtZmxleC5zbWNwEUtjb21tYWFjY2VudC5zbWNwC0xhY3V0ZS5zbWNwEUxjb21tYWFjY2VudC5zbWNwC0xjYXJvbi5zbWNwCUxkb3Quc21jcAtOYWN1dGUuc21jcBFOY29tbWFhY2NlbnQuc21jcAtOY2Fyb24uc21jcAxPbWFjcm9uLnNtY3ALT2JyZXZlLnNtY3AST2h1bmdhcnVtbGF1dC5zbWNwC1JhY3V0ZS5zbWNwEVJjb21tYWFjY2VudC5zbWNwC1JjYXJvbi5zbWNwC1NhY3V0ZS5zbWNwEFNjaXJjdW1mbGV4LnNtY3ANU2NlZGlsbGEuc21jcAtTY2Fyb24uc21jcBFUY29tbWFhY2NlbnQuc21jcAtUY2Fyb24uc21jcAtVdGlsZGUuc21jcAxVbWFjcm9uLnNtY3ALVWJyZXZlLnNtY3AKVXJpbmcuc21jcBJVaHVuZ2FydW1sYXV0LnNtY3AMVW9nb25lay5zbWNwEFdjaXJjdW1mbGV4LnNtY3AQWWNpcmN1bWZsZXguc21jcA5ZZGllcmVzaXMuc21jcAtaYWN1dGUuc21jcA9aZG90YWNjZW50LnNtY3ALWmNhcm9uLnNtY3APZ2VybWFuZGJscy5zbWNwCkFscGhhdG9ub3MMRXBzaWxvbnRvbm9zCEV0YXRvbm9zCUlvdGF0b25vcwxPbWljcm9udG9ub3MMVXBzaWxvbnRvbm9zCk9tZWdhdG9ub3MRaW90YWRpZXJlc2lzdG9ub3MFQWxwaGEEQmV0YQdFcHNpbG9uBFpldGEDRXRhBElvdGEFS2FwcGECTXUCTnUHT21pY3JvbgNSaG8DVGF1B1Vwc2lsb24DQ2hpDElvdGFkaWVyZXNpcw9VcHNpbG9uZGllcmVzaXMKYWxwaGF0b25vcwxlcHNpbG9udG9ub3MIZXRhdG9ub3MJaW90YXRvbm9zFHVwc2lsb25kaWVyZXNpc3Rvbm9zBWthcHBhB29taWNyb24HdW5pMDNCQwJudQNjaGkMaW90YWRpZXJlc2lzD3Vwc2lsb25kaWVyZXNpcwxvbWljcm9udG9ub3MMdXBzaWxvbnRvbm9zCm9tZWdhdG9ub3MHdW5pMDQwMQd1bmkwNDAzB3VuaTA0MDUHdW5pMDQwNgd1bmkwNDA3B3VuaTA0MDgHdW5pMDQxQQd1bmkwNDBDB3VuaTA0MEUHdW5pMDQxMAd1bmkwNDEyB3VuaTA0MTMHdW5pMDQxNQd1bmkwNDE5B3VuaTA0MUMHdW5pMDQxRAd1bmkwNDFFB3VuaTA0MUYHdW5pMDQyMAd1bmkwNDIxB3VuaTA0MjIHdW5pMDQyNQd1bmkwNDMwB3VuaTA0MzUHdW5pMDQzOQd1bmkwNDNFB3VuaTA0NDAHdW5pMDQ0MQd1bmkwNDQzB3VuaTA0NDUHdW5pMDQ1MQd1bmkwNDUzB3VuaTA0NTUHdW5pMDQ1Ngd1bmkwNDU3B3VuaTA0NTgHdW5pMDQ1Qwd1bmkwNDVFBldncmF2ZQZ3Z3JhdmUGV2FjdXRlBndhY3V0ZQlXZGllcmVzaXMJd2RpZXJlc2lzBllncmF2ZQZ5Z3JhdmUGbWludXRlBnNlY29uZAlleGNsYW1kYmwHdW5pRkIwMgd1bmkwMUYwB3VuaTAyQkMHdW5pMUUzRQd1bmkxRTNGB3VuaTFFMDAHdW5pMUUwMQd1bmkxRjREB3VuaUZCMDMHdW5pRkIwNAd1bmkwNDAwB3VuaTA0MEQHdW5pMDQ1MAd1bmkwNDVEB3VuaTA0NzAHdW5pMDQ3MQd1bmkwNDc2B3VuaTA0NzcHdW5pMDQ3OQd1bmkwNDc4B3VuaTA0OTgHdW5pMDQ5OQd1bmkwNEFBB3VuaTA0QUIHdW5pMDRBRQd1bmkwNEFGB3VuaTA0QzAHdW5pMDRDMQd1bmkwNEMyB3VuaTA0Q0YHdW5pMDREMAd1bmkwNEQxB3VuaTA0RDIHdW5pMDREMwd1bmkwNEQ0B3VuaTA0RDUHdW5pMDRENgd1bmkwNEQ3B3VuaTA0REEHdW5pMDREOQd1bmkwNERCB3VuaTA0REMHdW5pMDRERAd1bmkwNERFB3VuaTA0REYHdW5pMDRFMgd1bmkwNEUzB3VuaTA0RTQHdW5pMDRFNQd1bmkwNEU2B3VuaTA0RTcHdW5pMDRFOAd1bmkwNEU5B3VuaTA0RUEHdW5pMDRFQgd1bmkwNEVDB3VuaTA0RUQHdW5pMDRFRQd1bmkwNEVGB3VuaTA0RjAHdW5pMDRGMQd1bmkwNEYyB3VuaTA0RjMHdW5pMDRGNAd1bmkwNEY1B3VuaTA0RjgHdW5pMDRGOQd1bmkwNEZDB3VuaTA0RkQHdW5pMDUwMQd1bmkwNTEyB3VuaTA1MTMHdW5pMUVBMAd1bmkxRUExB3VuaTFFQTIHdW5pMUVBMwd1bmkxRUE0B3VuaTFFQTUHdW5pMUVBNgd1bmkxRUE3B3VuaTFFQTgHdW5pMUVBOQd1bmkxRUFBB3VuaTFFQUIHdW5pMUVBQwd1bmkxRUFEB3VuaTFFQUUHdW5pMUVBRgd1bmkxRUIwB3VuaTFFQjEHdW5pMUVCMgd1bmkxRUIzB3VuaTFFQjQHdW5pMUVCNQd1bmkxRUI2B3VuaTFFQjcHdW5pMUVCOAd1bmkxRUI5B3VuaTFFQkEHdW5pMUVCQgd1bmkxRUJDB3VuaTFFQkQHdW5pMUVCRQd1bmkxRUJGB3VuaTFFQzAHdW5pMUVDMQd1bmkxRUMyB3VuaTFFQzMHdW5pMUVDNAd1bmkxRUM1B3VuaTFFQzYHdW5pMUVDNwd1bmkxRUM4B3VuaTFFQzkHdW5pMUVDQQd1bmkxRUNCB3VuaTFFQ0MHdW5pMUVDRAd1bmkxRUNFB3VuaTFFQ0YHdW5pMUVEMAd1bmkxRUQxB3VuaTFFRDIHdW5pMUVEMwd1bmkxRUQ0B3VuaTFFRDUHdW5pMUVENgd1bmkxRUQ3B3VuaTFFRDgHdW5pMUVEOQd1bmkxRURBB3VuaTFFREIHdW5pMUVEQwd1bmkxRUREB3VuaTFFREUHdW5pMUVERgd1bmkxRUUwB3VuaTFFRTEHdW5pMUVFMgd1bmkxRUUzB3VuaTFFRTQHdW5pMUVFNQd1bmkxRUU2B3VuaTFFRTcHdW5pMUVFOAd1bmkxRUU5B3VuaTFFRUEHdW5pMUVFQgd1bmkxRUVDB3VuaTFFRUQHdW5pMUVFRQd1bmkxRUVGB3VuaTFFRjAHdW5pMUVGMQd1bmkxRUY0B3VuaTFFRjUHdW5pMUVGNgd1bmkxRUY3B3VuaTFFRjgHdW5pMUVGOQZkY3JvYXQHdW5pMjBBQgd1bmkwNDlBB3VuaTA0OUIHdW5pMDRBMgd1bmkwNEEzB3VuaTA0QUMHdW5pMDRBRAd1bmkwNEIyB3VuaTA0QjMHdW5pMDRCNgd1bmkwNEI3B3VuaTA0Q0IHdW5pMDRDQwd1bmkwNEY2B3VuaTA0RjcHdW5pMDQ5Ngd1bmkwNDk3B3VuaTA0QkUHdW5pMDRCRgd1bmkwNEJCB3VuaTA0OEMHdW5pMDQ2Mgd1bmkwNDkyB3VuaTA0OTMHdW5pMDQ5RQd1bmkwNDlGB3VuaTA0OEEHdW5pMDQ4Qgd1bmkwNEM5B3VuaTA0Q0EHdW5pMDRDRAd1bmkwNENFB3VuaTA0QzUHdW5pMDRDNgd1bmkwNEIwB3VuaTA0QjEHdW5pMDRGRQd1bmkwNEZGB3VuaTA1MTEHdW5pMjAxNQd1bmkwMDAyAAAAAQAAAAwAAAAAAAAAAgAIAMoAygABAR4BJAABAVYBYQABAXYBdgABAXsBfAABAX4BfgABAZMBlQABAdUB1QABAAAAAAAAAAAAAQAAAAoAHgAsAAFERkxUAAgABAAAAAD//wABAAAAAWtlcm4ACAAAAAEAAAABAAQAAgAAAAQADk1oVQZzXAABetgABAAAAa0DZANqA3ADdgPoA/IEBAQqBEAESgRsBI4ElATiBRAFMgVUBXoFoAWmBowGkga4Bt4HQAfSB/QIEggsCDIIQAhGCEwIUgh4CJIIoAi+CMQI4gj8CQIJxAo2ClwKzgrUCt4K5ArqCvALDgscC0YLTAtiC3wLggucC6ILqAveC+QL7gwcDEIMaAyKDKwMzgz8DV4NdA2WDbgOAg4kDkYOeA6eDsQOzg7YDvIPBA8ODygPLg9ED5IPrA/GD9wP/hAgEDoQQBBiEIQQphEYET4RZBGCEZwSXhJoErYTBBMOExQTGhMgEyYTLBNSE1wTYhN0E54TtBPGE9gT/hQEFBoUJBQ2FFwUchR4FH4UmBSeFMQU6hXQFkIWtBcmF5gYChh8GO4ZABkWGSwZQhlYGXoZnBm+GeAaAhooGk4adBqaGsAaxhrMGtIa2BtqG4gbphvEG+IcABweHDwcQhxIHE4cVBxaHIAcphzMHPIdGB02HVQdxh3kHlYedB7mHwQfFh8oHzofTB9yH4gfjh+kH6ofwB/GH9wf4h/4H/4gICAmIEggaiCMIK4g0CDWISQhUiGAIa4h3CH+IgQiJiIsIk4iVCJaIoAipiLMIvIjGCM+I0wjWiNoJE4lNCYaJiAmJiYsJjImOCY+JmQm9icUJ6YnyCfqKAwofiiUKLYo2Cj+KZAqAioMKiIqRCpmKogq1ir4KxorQCtmLEws3i1ALWIt9C36LiAuPi5kLnovPC9eL4Avhi/UMCIwbDDeMOgxqjHAMeIyBDIqMlAyYjNIM6ozyDPOM/Q0DjQsNDI0ODRCNGA0hjSsNNI1ZDWCNYg1jjWUNbY1vDYuNkw2cjaINo42tDbSNuQ3djeUN7Y4GDgeOEA4sjjQOUI5YDl2OXw5gjmIOeo58DoWOjw6Yjp8OsY65DsuO0w7lju0PBY8HDyOPKw9Hj08Pa49zD4+Plw+zj7sP14/fD/uQAxAfkCcQQ5BLEGeQbxCLkJMQr5C3ELyQvhDDkMUQypDMENGQ0xDYkNoQ35DhEOaQ6BDtkO8Q95EAEQmRExEckSYRL5E5EUKRTBFVkV8RaJFyEXuRhRGOkZARkZG2Eb2R4hHpkg4SFZIpEjGSaxKDkoUStZK4EtCS0hLTkt0TDZMhEymTMgAAQBZAAsAAQBZAAsAAQAR/yAAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAAgEMAAsBU//mAAQAC//mAD//9ABf/+8BPP/tAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAIAVP/mAaf/wAAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEBp//rABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nAAsAWf+kAacAEwGp//MBrf/xAbX/8gG2//EBuf87Abr/2gG7/1QBvP+RAb7/PwAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQBWAA4Af/+fAL//3gDC/+UA1P+oAOj/ygFG/+MBp//GAd//9QABAacADgA5AFT/tQBZ/8cAa/64AHr/KAB//00AhP+OAIf/oQCz/64Auv9+AL7/ZwDB/4cAwv9lAMX/ngDH/2oAyP9zAMn/XgDU/6UA4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APr/gAD8/3kBAv99AQT/fwEX/5gBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGn/68Bqf+5Aa3/uQG1/7kBtv+5Abj/vAG5//EBvP/xAb3/7QHc/6kB3//JAAEBp//rAAkACwAUAD8AEQBU/+IAXwATAaf/tAGp/9kBrf/ZAbX/2QG2/9kACQALAA8APwAMAFT/6wBfAA4Bp//LAan/6QGt/+cBtf/nAbb/5wAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ACABZ/+UAs//LAMj/5AGnAA0Bqf/tAa3/6wG1/+wBtv/sAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAYAxf/qAOj/7gDx/7ABL//sAVT/7AHc/+gAAQDx//UAAwALABQAPwASAF8AEwABAPH/wAABAPH/wAABAPH/wAAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAYAxf/qAOj/7gDx/7ABL//sAVT/7AHc/+gAAwBIAA8AVgAgAFkAEQAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QABARf/8QAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oAAEA8f/1ADAAVP9tAFn/jABr/b8Aev59AH/+vACE/ysAh/9LALP/YQC6/w8Avv7oAMH/HwDC/uUAxf9GAMf+7QDI/v0Ayf7ZANT/UgDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+v8TAPz/BwEC/w4BBP8RARf/PAEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/WQHf/48AHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAABAL8ADQACALP/wgC/ABAAAQC//+IAAQDC//IAAQC/AA4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAAwDF/+0A8f/AAdz/7AAKALr/5gC9/+sAvv/pAMD/8ADB/+cAxf/jAMf/zgDI/9QAyf/bAd//7gABAPH/wAAFAL3/7AC/AA8Awf/qAMX/xADH/+cABgBI/+kAvf/uAL8AEADB/+wAxf8gAdz/2gABAL8ADwAGAMX/6gDo/+4A8f+rAS//7AFU/+wB3P/oAAEA8f/VAAEAxQALAA0ASAAMAMEACwDFAAwBp/+/Aan/7gGt/+wBtf/tAbb/7AG4//UBuQAOAbsADQG+AA0B3//tAAEA8f/YAAIA8f+qAdz/4QALAOH/1ADx/8kBBP/lARv/4wEv/8QBOP/hAUn/1AFK//UBS//nAVP/0gFU/8kACQDh/8MA8f/PAS//zgE4/+cBO//fAUn/0QFL/+wBU/+gAVT/0QAJAOH/wwDx/88BL//OATj/5wE7/98BSf/RAUv/7AFT/6ABVP/RAAgA4f/JAPH/3wEE/+0BG//rAS//3wE7/+kBSv/1AVT/4AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADh/+YA8f/QAS//zgE4/+gBSf/nAUv/7QFT/+YBVP/QAAsA1AAUAOH/4ADoABMBOP/hATn/4AE8/+EBQf/pAUn/3wFL/94BU//fAVX/8gAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAUAGf/yAOH/8QFJ//IBS//yAVP/8gAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAMANQAEwDh/+YA4v/0AOgAEgDx/+cBL//nATj/5QE5/+gBSf/mAUv/5gFT/+YBVP/nAAkA4f/DAPH/zwEv/84BOP/nATv/3wFJ/9EBS//sAVP/oAFU/9EACQDh/8MA8f/PAS//zgE4/+cBO//fAUn/0QFL/+wBU/+gAVT/0QACANT/4gFT/+QAAgDU/+EA6P/kAAYA6P/uAPH/7gEE//QBG//xAS//7wFU/+8ABADx//QBBP/1AS//9QFU//UAAgDo/8kBF//uAAYA6AAUAPH/7QD3/+IBL//tATn/7QFU/+0AAQEX//EABQEX/+sBqf/rAa3/6QG1/+sBtv/rABMASAANAML/qwDD/8AAx//VAOj/qgEX/+IBGwAMAUoACwFMAAsBp/+/Aan/7gGt/+wBtf/tAbb/7AG4//UBuQAOAbsADQG+AA0B3/+wAAYAxf/qAOj/7gDx/7ABL//sAVT/7AHc/+gABgDoABQA8f/wAPwADAEv//ABOf/mAVT/8AAFAOgAOgDx/+MBL//iATn/4wFU/+MACADx/7oBBP/PARv/2wEv/1ABOf+dAUr/8AFM//IBVP9MAAgA8f+6AQT/zwEb/9sBL/9QATn/nQFK//ABTP/yAVT/TAAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oAAEA6P/vAAgA8f+6AQT/zwEb/9sBL/9QATn/nQFK//ABTP/yAVT/TAAIAPH/ugEE/88BG//bAS//UAE5/50BSv/wAUz/8gFU/0wACADx/7oBBP/PARv/2wEv/1ABOf+dAUr/8AFM//IBVP9MABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQALABQAPwARAFT/4gBfABMBp/+0Aan/2QGt/9kBtf/ZAbb/2QAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oADAAVP9tAFn/jABr/b8Aev59AH/+vACE/ysAh/9LALP/YQC6/w8Avv7oAMH/HwDC/uUAxf9GAMf+7QDI/v0Ayf7ZANT/UgDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+v8TAPz/BwEC/w4BBP8RARf/PAEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/WQHf/48AAgDo/8kBF//uABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nAAIA6P/JARf/7gABAFkACwABAFkACwABAFkACwABAFkACwABAFkACwAJAan/8gGt//IBtf/yAbb/8gG5/8ABuv/sAbv/xwG8/9gBvv+/AAIBu//uAbz/9QABAaf/0gAEAan/6wGt/+kBtf/rAbb/6wAKAacAEQGp//ABrf/uAbX/7wG2//ABuf+7Abr/7AG7/7cBvP/VAb7/tAAFAaf/8wG5/+4Bu//xAb3/7AG+/+oABAG5/+kBu//rAbz/8QG+/+UABAG5//IBu//xAbz/9QG+/+4ACQGn/78Bqf/uAa3/7AG1/+0Btv/sAbj/9QG5AA4BuwANAb4ADQABAaf/7wAFAaf/xwGp//IBrf/wAbX/8AG2//AAAgGn/9wBuQAOAAQBqf/tAa3/6wG1/+sBtv/rAAkBp//AAan/7QGt/+sBtf/rAbb/6wG5AA8BuwAQAbwADQG+ABAABQGnAAwBqf/wAa3/8AG1//ABtv/wAAEB1/9qAAEB1/8VAAYASAALALr/8gDH//EAyf/vAdwADwHf/+4AAQGn/9UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1ADkAVP+1AFn/xwBr/rgAev8oAH//TQCE/44Ah/+hALP/rgC6/34Avv9nAMH/hwDC/2UAxf+eAMf/agDI/3MAyf9eANT/pQDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+v+AAPz/eQEC/30BBP9/ARf/mAEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAaf/rwGp/7kBrf+5AbX/uQG2/7kBuP+8Abn/8QG8//EBvf/tAdz/qQHf/8kAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABAAL/+YAP//0AF//7wE8/+0ABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAUASP/uAFn/6gG7//ABvP/tAb7/8AAFAEj/7gBZ/+oBu//wAbz/7QG+//AABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAEBp//rAAEBp//rAAEBp//rAAEBp//rACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAAQDx//UAAQDx//UAAQDx//UAAQDx//UAAQDx/8AACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAQAC//mAD//9ABf/+8BPP/tAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/8AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAaf/6wATAFn/wQCz/8UAxf+0AOX/1wDx/7kBBP+yARf/0gEb/8gBL/+gATn/xQFB/+QBSv/MAUz/zAFU/8sBVf/vAan/6AGt/+YBtf/nAbb/5wALAFn/pAGnABMBqf/zAa3/8QG1//IBtv/xAbn/OwG6/9oBu/9UAbz/kQG+/z8ACwBZ/6QBpwATAan/8wGt//EBtf/yAbb/8QG5/zsBuv/aAbv/VAG8/5EBvv8/AAsAWf+kAacAEwGp//MBrf/xAbX/8gG2//EBuf87Abr/2gG7/1QBvP+RAb7/PwALAFn/pAGnABMBqf/zAa3/8QG1//IBtv/xAbn/OwG6/9oBu/9UAbz/kQG+/z8ACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAEA8f/AAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AABAPH/wAAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/8AAAQDx/8AACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oAAwBIAA8AVgAgAFkAEQADAEgADwBWACAAWQARAAMASAAPAFYAIABZABEAOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQA5AFT/tQBZ/8cAa/64AHr/KAB//00AhP+OAIf/oQCz/64Auv9+AL7/ZwDB/4cAwv9lAMX/ngDH/2oAyP9zAMn/XgDU/6UA4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APr/gAD8/3kBAv99AQT/fwEX/5gBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGn/68Bqf+5Aa3/uQG1/7kBtv+5Abj/vAG5//EBvP/xAb3/7QHc/6kB3//JADkAVP+1AFn/xwBr/rgAev8oAH//TQCE/44Ah/+hALP/rgC6/34Avv9nAMH/hwDC/2UAxf+eAMf/agDI/3MAyf9eANT/pQDhAA8A5f/kAOb/oADo/3QA6v+AAPH/sgD4/30A+v+AAPz/eQEC/30BBP9/ARf/mAEb/9oBJ/+BASn/mAEt/30BL/+zATP/oAE5/3wBO/+aATz/bAFB/+YBRv9rAUr/kgFM/60BUP97AVMADwFU/5EBVf/yAaf/rwGp/7kBrf+5AbX/uQG2/7kBuP+8Abn/8QG8//EBvf/tAdz/qQHf/8kAAQGn/+sAAQGn/+sAAQGn/+sAAQGn/+sAAQGn/+sAAQGn/+sACQALAA8APwAMAFT/6wBfAA4Bp//LAan/6QGt/+cBtf/nAbb/5wAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ACABZ/+UAs//LAMj/5AGnAA0Bqf/tAa3/6wG1/+wBtv/sAAgAWf/lALP/ywDI/+QBpwANAan/7QGt/+sBtf/sAbb/7AAIAFn/5QCz/8sAyP/kAacADQGp/+0Brf/rAbX/7AG2/+wAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uABwAIf/DAFb/7wBZ/98Alv/uALP/5QC0/9EAvwARAMX/yADUABMA4f/FAPH/ygEv/58BOP9RATn/ewE7/8oBPP/dAUH/8gFJ/3UBS//KAVP/TwFU/4wBrf/1AbX/9QG5/8cBuv/xAbv/zQG8/90Bvv/EAAIBDAALAVP/5gAFAEj/7gBZ/+oBu//wAbz/7QG+//AACABZ/+UAs//LAMj/5AGnAA0Bqf/tAa3/6wG1/+wBtv/sAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAEwBZ/8EAs//FAMX/tADl/9cA8f+5AQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGp/+gBrf/mAbX/5wG2/+cACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAVgAOAH//nwC//94Awv/lANT/qADo/8oBRv/jAaf/xgHf//UAOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAan/6QGt/+cBtf/nAbb/6QHf//AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4AAQDx/8AACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAUASP/uAFn/6gG7//ABvP/tAb7/8AAwAFT/bQBZ/4wAa/2/AHr+fQB//rwAhP8rAIf/SwCz/2EAuv8PAL7+6ADB/x8Awv7lAMX/RgDH/u0AyP79AMn+2QDU/1IA4QAFAOX/vQDm/0kA6P7+AOr/EwDx/2gA+P8OAPr/EwD8/wcBAv8OAQT/EQEX/zwBG/+sASf/FQEp/zwBLf8OAS//agEz/0kBOf8MATv/PwE8/vEBQf/AAUb+7wFK/zEBTP9fAVD/CgFTAAUBVP8wAVX/1QHc/1kB3/+PAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQGn/+sAEwBZ/8EAs//FAMX/tADl/9cA8f+5AQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGp/+gBrf/mAbX/5wG2/+cAEwBZ/8EAs//FAMX/tADl/9cA8f+5AQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGp/+gBrf/mAbX/5wG2/+cAEgDU/64A4QASAOb/4ADo/60A6v/WAPj/3wD8/9IBAv/gARf/zgEn/90BKf/iAS3/4AEz/+ABOf/pATz/2gFG/70BUP/fAVMAEQAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAACAQwACwFT/+YAMABU/20AWf+MAGv9vwB6/n0Af/68AIT/KwCH/0sAs/9hALr/DwC+/ugAwf8fAML+5QDF/0YAx/7tAMj+/QDJ/tkA1P9SAOEABQDl/70A5v9JAOj+/gDq/xMA8f9oAPj/DgD6/xMA/P8HAQL/DgEE/xEBF/88ARv/rAEn/xUBKf88AS3/DgEv/2oBM/9JATn/DAE7/z8BPP7xAUH/wAFG/u8BSv8xAUz/XwFQ/woBUwAFAVT/MAFV/9UB3P9ZAd//jwAFAEj/7gBZ/+oBu//wAbz/7QG+//AACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAVgAOAH//nwC//94Awv/lANT/qADo/8oBRv/jAaf/xgHf//UABAAL/+YAP//0AF//7wE8/+0AOQBU/7UAWf/HAGv+uAB6/ygAf/9NAIT/jgCH/6EAs/+uALr/fgC+/2cAwf+HAML/ZQDF/54Ax/9qAMj/cwDJ/14A1P+lAOEADwDl/+QA5v+gAOj/dADq/4AA8f+yAPj/fQD6/4AA/P95AQL/fQEE/38BF/+YARv/2gEn/4EBKf+YAS3/fQEv/7MBM/+gATn/fAE7/5oBPP9sAUH/5gFG/2sBSv+SAUz/rQFQ/3sBUwAPAVT/kQFV//IBp/+vAan/uQGt/7kBtf+5Abb/uQG4/7wBuf/xAbz/8QG9/+0B3P+pAd//yQAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAcA8f/wAQT/8QEb//MBL//xAUr/8wFM/+kBVP/TAAEA8f/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oABgDF/+oA6P/uAPH/sAEv/+wBVP/sAdz/6AAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QABARf/8QABAPH/9QACAOj/yQEX/+4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UACQALAA8APwAMAFT/6wBfAA4Bp//LAan/6QGt/+cBtf/nAbb/5wAJAAsADwA/AAwAVP/rAF8ADgGn/8sBqf/pAa3/5wG1/+cBtv/nAAkACwAPAD8ADABU/+sAXwAOAaf/ywGp/+kBrf/nAbX/5wG2/+cAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QABAFkACwABAFkACwABAFkACwAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QAAQDx/8AAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UACQALABQAPwARAFT/4gBfABMBp/+0Aan/2QGt/9kBtf/ZAbb/2QAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAEAAv/5gA///QAX//vATz/7QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1AAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAYALP/1AC9/+0AvwARAMX/4ADH/+cAyP/lAMn/7gDUABIA5f/pAPH/1wEv/9cBOf/TATv/1gE8/8UBQf/nAUkADQFLAAwBVP/WAVX/8gGp/+kBrf/nAbX/5wG2/+kB3//wAAEBF//xAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAcACH/wwBW/+8AWf/fAJb/7gCz/+UAtP/RAL8AEQDF/8gA1AATAOH/xQDx/8oBL/+fATj/UQE5/3sBO//KATz/3QFB//IBSf91AUv/ygFT/08BVP+MAa3/9QG1//UBuf/HAbr/8QG7/80BvP/dAb7/xAAHAPH/8AEE//EBG//zAS//8QFK//MBTP/pAVT/0wAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UAAQDx//UAAQDx//UAGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AABARf/8QAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAGAMX/6gDo/+4A8f+wAS//7AFU/+wB3P/oABIA1P+uAOEAEgDm/+AA6P+tAOr/1gD4/98A/P/SAQL/4AEX/84BJ//dASn/4gEt/+ABM//gATn/6QE8/9oBRv+9AVD/3wFTABEABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAEgDU/64A4QASAOb/4ADo/60A6v/WAPj/3wD8/9IBAv/gARf/zgEn/90BKf/iAS3/4AEz/+ABOf/pATz/2gFG/70BUP/fAVMAEQAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QASANT/rgDhABIA5v/gAOj/rQDq/9YA+P/fAPz/0gEC/+ABF//OASf/3QEp/+IBLf/gATP/4AE5/+kBPP/aAUb/vQFQ/98BUwARAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAan/6QGt/+cBtf/nAbb/6QHf//AAAQEX//EAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MAHAAh/8MAVv/vAFn/3wCW/+4As//lALT/0QC/ABEAxf/IANQAEwDh/8UA8f/KAS//nwE4/1EBOf97ATv/ygE8/90BQf/yAUn/dQFL/8oBU/9PAVT/jAGt//UBtf/1Abn/xwG6//EBu//NAbz/3QG+/8QABwDx//ABBP/xARv/8wEv//EBSv/zAUz/6QFU/9MABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAFAEj/7gBZ/+oBu//wAbz/7QG+//AAAQDx//UABQBI/+4AWf/qAbv/8AG8/+0Bvv/wAAEA8f/1AAUASP/uAFn/6gG7//ABvP/tAb7/8AABAPH/9QAIANQAFQDoABUBOP/kATn/5QE7/+QBSf/jAUv/4gFT/+QACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAH//3wCw//MAsv/wAL//6gDU/98A4f/gAVP/4AGn/+0Bvf/1AAkAxf/qAOj/uADx/+oBBP/wARv/8QEv/+sBSv/1AVT/7AHc/+oACQB//98AsP/zALL/8AC//+oA1P/fAOH/4AFT/+ABp//tAb3/9QAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAkAf//fALD/8wCy//AAv//qANT/3wDh/+ABU//gAaf/7QG9//UACQDF/+oA6P+4APH/6gEE//ABG//xAS//6wFK//UBVP/sAdz/6gAJAMX/6gDo/7gA8f/qAQT/8AEb//EBL//rAUr/9QFU/+wB3P/qAAEBp//rAAEBp//rACQACP/iAAsAFAAM/88APwASAEj/6gBU/9gAVv/qAF8AEwBr/64Aev/NAH//oACE/8EAh//AALP/0AC3/+oAuv/GALsADQC9/+kAvv/WAMH/6ADC/7oAxf/pAMf/ywDI/9oAyf/HAW7/0wGn/6sBqf/NAa3/ywG1/8sBtv/LAbn/8wG8//MBvf/vAdz/6AHf/+4ABwBIAA0AwQALAML/6gDFAAwA6P/IARf/8QHf//UAJAAI/+IACwAUAAz/zwA/ABIASP/qAFT/2ABW/+oAXwATAGv/rgB6/80Af/+gAIT/wQCH/8AAs//QALf/6gC6/8YAuwANAL3/6QC+/9YAwf/oAML/ugDF/+kAx//LAMj/2gDJ/8cBbv/TAaf/qwGp/80Brf/LAbX/ywG2/8sBuf/zAbz/8wG9/+8B3P/oAd//7gAHAEgADQDBAAsAwv/qAMUADADo/8gBF//xAd//9QAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAcASAANAMEACwDC/+oAxQAMAOj/yAEX//EB3//1ABMAWf/BALP/xQDF/7QA5f/XAPH/uQEE/7IBF//SARv/yAEv/6ABOf/FAUH/5AFK/8wBTP/MAVT/ywFV/+8Bqf/oAa3/5gG1/+cBtv/nAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AA5AFT/tQBZ/8cAa/64AHr/KAB//00AhP+OAIf/oQCz/64Auv9+AL7/ZwDB/4cAwv9lAMX/ngDH/2oAyP9zAMn/XgDU/6UA4QAPAOX/5ADm/6AA6P90AOr/gADx/7IA+P99APr/gAD8/3kBAv99AQT/fwEX/5gBG//aASf/gQEp/5gBLf99AS//swEz/6ABOf98ATv/mgE8/2wBQf/mAUb/awFK/5IBTP+tAVD/ewFTAA8BVP+RAVX/8gGn/68Bqf+5Aa3/uQG1/7kBtv+5Abj/vAG5//EBvP/xAb3/7QHc/6kB3//JABgAs//UAL3/7QC/ABEAxf/gAMf/5wDI/+UAyf/uANQAEgDl/+kA8f/XAS//1wE5/9MBO//WATz/xQFB/+cBSQANAUsADAFU/9YBVf/yAan/6QGt/+cBtf/nAbb/6QHf//AAAQEX//EAMABU/20AWf+MAGv9vwB6/n0Af/68AIT/KwCH/0sAs/9hALr/DwC+/ugAwf8fAML+5QDF/0YAx/7tAMj+/QDJ/tkA1P9SAOEABQDl/70A5v9JAOj+/gDq/xMA8f9oAPj/DgD6/xMA/P8HAQL/DgEE/xEBF/88ARv/rAEn/xUBKf88AS3/DgEv/2oBM/9JATn/DAE7/z8BPP7xAUH/wAFG/u8BSv8xAUz/XwFQ/woBUwAFAVT/MAFV/9UB3P9ZAd//jwACAOj/yQEX/+4AGACz/9QAvf/tAL8AEQDF/+AAx//nAMj/5QDJ/+4A1AASAOX/6QDx/9cBL//XATn/0wE7/9YBPP/FAUH/5wFJAA0BSwAMAVT/1gFV//IBqf/pAa3/5wG1/+cBtv/pAd//8AABARf/8QABAPH/wAAJAOH/wwDx/88BL//OATj/5wE7/98BSf/RAUv/7AFT/6ABVP/RADAAVP9tAFn/jABr/b8Aev59AH/+vACE/ysAh/9LALP/YQC6/w8Avv7oAMH/HwDC/uUAxf9GAMf+7QDI/v0Ayf7ZANT/UgDhAAUA5f+9AOb/SQDo/v4A6v8TAPH/aAD4/w4A+v8TAPz/BwEC/w4BBP8RARf/PAEb/6wBJ/8VASn/PAEt/w4BL/9qATP/SQE5/wwBO/8/ATz+8QFB/8ABRv7vAUr/MQFM/18BUP8KAVMABQFU/zABVf/VAdz/WQHf/48AEwBZ/8EAs//FAMX/tADl/9cA8f+5AQT/sgEX/9IBG//IAS//oAE5/8UBQf/kAUr/zAFM/8wBVP/LAVX/7wGp/+gBrf/mAbX/5wG2/+cACADUABUA6AAVATj/5AE5/+UBO//kAUn/4wFL/+IBU//kAAgA1AAVAOgAFQE4/+QBOf/lATv/5AFJ/+MBS//iAVP/5AAkAAj/4gALABQADP/PAD8AEgBI/+oAVP/YAFb/6gBfABMAa/+uAHr/zQB//6AAhP/BAIf/wACz/9AAt//qALr/xgC7AA0Avf/pAL7/1gDB/+gAwv+6AMX/6QDH/8sAyP/aAMn/xwFu/9MBp/+rAan/zQGt/8sBtf/LAbb/ywG5//MBvP/zAb3/7wHc/+gB3//uAAEwsgAEAAAACgAeAHQDpgQkBI4E0AXuBuQHQgdcABUAOAAUADkAEgA7ABYBFAAUAgsAFgKSABIClAAWApYAFgL9ABYDDAAWAw8AFgNFABIDRwASA0kAEgNLABYDYAAUA2gAFgPqABYD7AAWA+4AFgQTABYAzAAO/xYAEP8WACP/VgAs/vgANgAUAEP/3gBF/+sARv/rAEf/6wBJ/+sAUf/rAFP/6wBX/+oAWP/oAFv/6ACR/+sAlf/rAJf/6gCt/1YAr/9WALb/6wC4/+gAw//rAMT/6wDG/+oAzQAUANEAFADy/+sA/v/rAQj/VgET/+sBFf/oARn/6wEd/+sBLgAUATX/6wE2ABQBR//rAUj/6wFS/+sBZ/8WAWv/FgFv/xYBcP8WAfH/VgHy/1YB8/9WAfT/VgH1/1YB9v9WAff/VgIM/94CDf/eAg7/3gIP/94CEP/eAhH/3gIS/94CE//rAhT/6wIV/+sCFv/rAhf/6wId/+sCHv/rAh//6wIg/+sCIf/rAiL/6gIj/+oCJP/qAiX/6gIm/+gCJ//oAij/VgIp/94CKv9WAiv/3gIs/1YCLf/eAi//6wIx/+sCM//rAjX/6wI3/+sCOf/rAjv/6wI9/+sCP//rAkH/6wJD/+sCRf/rAkf/6wJJ/+sCV/74Amv/6wJt/+sCb//rAoAAFAKCABQChAAUAof/6gKJ/+oCi//qAo3/6gKP/+oCkf/qApX/6AL4/1YDAP9WAxD/6wMU/+oDFv/rAxj/6AMb/+oDHP/rAx3/6gMk/vgDKP9WAzMAFAM1/94DNv/rAzj/6wM6/+sDO//oAz3/6wNE/+gDTP/oA1X/VgNW/94DXP/rA2H/6ANi/+sDZ//rA2n/6ANu/1YDb//eA3D/VgNx/94Ddf/rA3f/6wN4/+sDgv/rA4T/6wOG/+sDiv/oA4z/6AOO/+gDlf/rA5j/VgOZ/94Dmv9WA5v/3gOc/1YDnf/eA57/VgOf/94DoP9WA6H/3gOi/1YDo//eA6T/VgOl/94Dpv9WA6f/3gOo/1YDqf/eA6r/VgOr/94DrP9WA63/3gOu/1YDr//eA7H/6wOz/+sDtf/rA7f/6wO5/+sDu//rA73/6wO//+sDxf/rA8f/6wPJ/+sDy//rA83/6wPP/+sD0f/rA9P/6wPV/+sD1//rA9n/6wPb/+sD3f/qA9//6gPh/+oD4//qA+X/6gPn/+oD6f/qA+v/6APt/+gD7//oA/YAFAAfADb/1QA4/+QAOf/sADv/3QDN/9UA0f/VART/5AEu/9UBNv/VAgv/3QKA/9UCgv/VAoT/1QKS/+wClP/dApb/3QL9/90DDP/dAw//3QMz/9UDRf/sA0f/7ANJ/+wDS//dA2D/5ANo/90D6v/dA+z/3QPu/90D9v/VBBP/3QAaADb/sAA4/+0AO//QAM3/sADR/7ABFP/tAS7/sAE2/7ACC//QAoD/sAKC/7AChP+wApT/0AKW/9AC/f/QAwz/0AMP/9ADM/+wA0v/0ANg/+0DaP/QA+r/0APs/9AD7v/QA/b/sAQT/9AAEAAs/+4AN//uAgf/7gII/+4CCf/uAgr/7gJX/+4Chv/uAoj/7gKK/+4CjP/uAo7/7gKQ/+4DJP/uA9z/7gPe/+4ARwAEABAACQAQAEX/6ABG/+gAR//oAEn/6ABT/+gAkf/oAJX/6AC2/+gAw//oAMT/6ADy/+gA/v/oARn/6AEd/+gBNf/oAUf/6AFI/+gBUv/oAWUAEAFmABABaAAQAWkAEAFqABACE//oAhT/6AIV/+gCFv/oAhf/6AIv/+gCMf/oAjP/6AI1/+gCN//oAjn/6AI7/+gCPf/oAj//6AJB/+gCQ//oAkX/6AJH/+gCSf/oAxD/6AM2/+gDOv/oAz3/6ANNABADTgAQA1IAEANc/+gDYv/oA2f/6AN1/+gDd//oA3j/6AOE/+gDlf/oA7H/6AOz/+gDtf/oA7f/6AO5/+gDu//oA73/6AO//+gD0//oA9X/6APX/+gD2//oAD0ARf/sAEb/7ABH/+wASf/sAFP/7ACR/+wAlf/sALb/7ADD/+wAxP/sAPL/7AD+/+wBGf/sAR3/7AE1/+wBR//sAUj/7AFS/+wCE//sAhT/7AIV/+wCFv/sAhf/7AIv/+wCMf/sAjP/7AI1/+wCN//sAjn/7AI7/+wCPf/sAj//7AJB/+wCQ//sAkX/7AJH/+wCSf/sAxD/7AM2/+wDOv/sAz3/7ANc/+wDYv/sA2f/7AN1/+wDd//sA3j/7AOE/+wDlf/sA7H/7AOz/+wDtf/sA7f/7AO5/+wDu//sA73/7AO//+wD0//sA9X/7APX/+wD2//sABcAUf/sARP/7AId/+wCHv/sAh//7AIg/+wCIf/sAmv/7AJt/+wCb//sAxb/7AMc/+wDOP/sA4L/7AOG/+wDxf/sA8f/7APJ/+wDy//sA83/7APP/+wD0f/sA9n/7AAGAA7/hAAQ/4QBZ/+EAWv/hAFv/4QBcP+EABAALP/sADf/7AIH/+wCCP/sAgn/7AIK/+wCV//sAob/7AKI/+wCiv/sAoz/7AKO/+wCkP/sAyT/7APc/+wD3v/sAAEpLAAEAAAAIgBOAMQBqgKQA2oEBAaeCGQJNgosC/IMJAxWDNQOug8wEAISFBLKFDAU6hVwFc4WkBcGFxgXQhiUGtIa9BwKHIgcshzcAB0ABP/yAAn/8gBY//MAW//zALj/8wEV//MBZf/yAWb/8gFo//IBaf/yAWr/8gIm//MCJ//zApX/8wMY//MDO//zA0T/8wNM//MDTf/yA07/8gNS//IDYf/zA2n/8wOK//MDjP/zA47/8wPr//MD7f/zA+//8wA5ACX/8wAp//MAMf/zADP/8wCB//MAkP/zAJT/8wCu//MAzv/zAQP/8wES//MBFv/zARj/8wEa//MBHP/zATT/8wFR//MB+P/zAgL/8wID//MCBP/zAgX/8wIG//MCLv/zAjD/8wIy//MCNP/zAkL/8wJE//MCRv/zAkj/8wJq//MCbP/zAm7/8wKf//MC/P/zAwn/8wMv//MDMv/zA1f/8wNj//MDZv/zA4H/8wOD//MDhf/zA8T/8wPG//MDyP/zA8r/8wPM//MDzv/zA9D/8wPS//MD1P/zA9b/8wPY//MD2v/zADkAJf/mACn/5gAx/+YAM//mAIH/5gCQ/+YAlP/mAK7/5gDO/+YBA//mARL/5gEW/+YBGP/mARr/5gEc/+YBNP/mAVH/5gH4/+YCAv/mAgP/5gIE/+YCBf/mAgb/5gIu/+YCMP/mAjL/5gI0/+YCQv/mAkT/5gJG/+YCSP/mAmr/5gJs/+YCbv/mAp//5gL8/+YDCf/mAy//5gMy/+YDV//mA2P/5gNm/+YDgf/mA4P/5gOF/+YDxP/mA8b/5gPI/+YDyv/mA8z/5gPO/+YD0P/mA9L/5gPU/+YD1v/mA9j/5gPa/+YANgAj/+QAOv/SADv/0wCt/+QAr//kANX/0gEI/+QB8f/kAfL/5AHz/+QB9P/kAfX/5AH2/+QB9//kAgv/0wIo/+QCKv/kAiz/5AKU/9MClv/TAvj/5AL9/9MDAP/kAwz/0wMN/9IDD//TAyj/5AM0/9IDS//TA1X/5ANo/9MDa//SA27/5ANw/+QDef/SA5P/0gOY/+QDmv/kA5z/5AOe/+QDoP/kA6L/5AOk/+QDpv/kA6j/5AOq/+QDrP/kA67/5APq/9MD7P/TA+7/0wP4/9IEAP/SBBP/0wAmAA7/HgAQ/x4AI//NAK3/zQCv/80BCP/NAWf/HgFr/x4Bb/8eAXD/HgHx/80B8v/NAfP/zQH0/80B9f/NAfb/zQH3/80CKP/NAir/zQIs/80C+P/NAwD/zQMo/80DVf/NA27/zQNw/80DmP/NA5r/zQOc/80Dnv/NA6D/zQOi/80DpP/NA6b/zQOo/80Dqv/NA6z/zQOu/80ApgBF/9wARv/cAEf/3ABJ/9wAT//zAFD/8wBR/9YAUv/zAFP/3ABX/90AWP/hAFv/4QCR/9wAlf/cAJf/3QC2/9wAuP/hALz/8wDD/9wAxP/cAMb/3QDn//MA6//zAOz/8wDu//MA7//zAPD/8wDy/9wA8//zAPX/8wD2//MA+f/zAPv/8wD+/9wBAP/zARP/1gEV/+EBGf/cAR3/3AEx//MBNf/cAUD/8wFF//MBR//cAUj/3AFS/9wCE//cAhT/3AIV/9wCFv/cAhf/3AIc//MCHf/WAh7/1gIf/9YCIP/WAiH/1gIi/90CI//dAiT/3QIl/90CJv/hAif/4QIv/9wCMf/cAjP/3AI1/9wCN//cAjn/3AI7/9wCPf/cAj//3AJB/9wCQ//cAkX/3AJH/9wCSf/cAmT/8wJm//MCaP/zAmn/8wJr/9YCbf/WAm//1gKH/90Cif/dAov/3QKN/90Cj//dApH/3QKV/+EDEP/cAxL/8wMU/90DFv/WAxj/4QMb/90DHP/WAx3/3QM2/9wDN//zAzj/1gM5//MDOv/cAzv/4QM9/9wDPv/zA0P/8wNE/+EDTP/hA1T/8wNc/9wDXf/zA2H/4QNi/9wDZ//cA2n/4QN1/9wDd//cA3j/3AN+//MDgP/zA4L/1gOE/9wDhv/WA4r/4QOM/+EDjv/hA5L/8wOV/9wDsf/cA7P/3AO1/9wDt//cA7n/3AO7/9wDvf/cA7//3APF/9YDx//WA8n/1gPL/9YDzf/WA8//1gPR/9YD0//cA9X/3APX/9wD2f/WA9v/3APd/90D3//dA+H/3QPj/90D5f/dA+f/3QPp/90D6//hA+3/4QPv/+ED8//zA/X/8wP///MEDP/zBA7/8wQQ//MAcQAE/9oACf/aAEX/8ABG//AAR//wAEn/8ABT//AAV//vAFj/3ABb/9wAkf/wAJX/8ACX/+8Atv/wALj/3ADD//AAxP/wAMb/7wDy//AA/v/wARX/3AEZ//ABHf/wATX/8AFH//ABSP/wAVL/8AFl/9oBZv/aAWj/2gFp/9oBav/aAhP/8AIU//ACFf/wAhb/8AIX//ACIv/vAiP/7wIk/+8CJf/vAib/3AIn/9wCL//wAjH/8AIz//ACNf/wAjf/8AI5//ACO//wAj3/8AI///ACQf/wAkP/8AJF//ACR//wAkn/8AKH/+8Cif/vAov/7wKN/+8Cj//vApH/7wKV/9wDEP/wAxT/7wMY/9wDG//vAx3/7wM2//ADOv/wAzv/3AM9//ADRP/cA0z/3ANN/9oDTv/aA1L/2gNc//ADYf/cA2L/8ANn//ADaf/cA3X/8AN3//ADeP/wA4T/8AOK/9wDjP/cA47/3AOV//ADsf/wA7P/8AO1//ADt//wA7n/8AO7//ADvf/wA7//8APT//AD1f/wA9f/8APb//AD3f/vA9//7wPh/+8D4//vA+X/7wPn/+8D6f/vA+v/3APt/9wD7//cADQABP+gAAn/oABX//EAWP/FAFv/xQCX//EAuP/FAMb/8QEV/8UBZf+gAWb/oAFo/6ABaf+gAWr/oAIi//ECI//xAiT/8QIl//ECJv/FAif/xQKH//ECif/xAov/8QKN//ECj//xApH/8QKV/8UDFP/xAxj/xQMb//EDHf/xAzv/xQNE/8UDTP/FA03/oANO/6ADUv+gA2H/xQNp/8UDiv/FA4z/xQOO/8UD3f/xA9//8QPh//ED4//xA+X/8QPn//ED6f/xA+v/xQPt/8UD7//FAD0ARf/nAEb/5wBH/+cASf/nAFP/5wCR/+cAlf/nALb/5wDD/+cAxP/nAPL/5wD+/+cBGf/nAR3/5wE1/+cBR//nAUj/5wFS/+cCE//nAhT/5wIV/+cCFv/nAhf/5wIv/+cCMf/nAjP/5wI1/+cCN//nAjn/5wI7/+cCPf/nAj//5wJB/+cCQ//nAkX/5wJH/+cCSf/nAxD/5wM2/+cDOv/nAz3/5wNc/+cDYv/nA2f/5wN1/+cDd//nA3j/5wOE/+cDlf/nA7H/5wOz/+cDtf/nA7f/5wO5/+cDu//nA73/5wO//+cD0//nA9X/5wPX/+cD2//nAHEABAAMAAkADABF/+gARv/oAEf/6ABJ/+gAUf/qAFP/6ABYAAsAWwALAJH/6ACV/+gAtv/oALgACwDD/+gAxP/oAPL/6AD+/+gBE//qARUACwEZ/+gBHf/oATX/6AFH/+gBSP/oAVL/6AFlAAwBZgAMAWgADAFpAAwBagAMAhP/6AIU/+gCFf/oAhb/6AIX/+gCHf/qAh7/6gIf/+oCIP/qAiH/6gImAAsCJwALAi//6AIx/+gCM//oAjX/6AI3/+gCOf/oAjv/6AI9/+gCP//oAkH/6AJD/+gCRf/oAkf/6AJJ/+gCa//qAm3/6gJv/+oClQALAxD/6AMW/+oDGAALAxz/6gM2/+gDOP/qAzr/6AM7AAsDPf/oA0QACwNMAAsDTQAMA04ADANSAAwDXP/oA2EACwNi/+gDZ//oA2kACwN1/+gDd//oA3j/6AOC/+oDhP/oA4b/6gOKAAsDjAALA44ACwOV/+gDsf/oA7P/6AO1/+gDt//oA7n/6AO7/+gDvf/oA7//6APF/+oDx//qA8n/6gPL/+oDzf/qA8//6gPR/+oD0//oA9X/6APX/+gD2f/qA9v/6APrAAsD7QALA+8ACwAMAFr/7QBc/+0A6f/tApj/7QKa/+0CnP/tAzz/7QNs/+0Dev/tA5T/7QP5/+0EAf/tAAwAWv/yAFz/8gDp//ICmP/yApr/8gKc//IDPP/yA2z/8gN6//IDlP/yA/n/8gQB//IAHwBY//QAWv/yAFv/9ABc//MAuP/0AOn/8gEV//QCJv/0Aif/9AKV//QCmP/zApr/8wKc//MDGP/0Azv/9AM8//IDRP/0A0z/9ANh//QDaf/0A2z/8gN6//IDiv/0A4z/9AOO//QDlP/yA+v/9APt//QD7//0A/n/8gQB//IAeQAE/8oACf/KADb/0gA4/9QAOv/0ADv/0wBP/9EAUP/RAFL/0QBY/+YAWv/vAFv/5gC4/+YAvP/RAM3/0gDR/9IA1f/0ANn/7QDc/+EA5//RAOn/7wDr/9EA7P/RAO7/0QDv/9EA8P/RAPP/0QD1/9EA9v/RAPn/0QD7/9EBAP/RART/1AEV/+YBLv/SATH/0QE2/9IBQP/RAUX/0QFl/8oBZv/KAWj/ygFp/8oBav/KAgv/0wIc/9ECJv/mAif/5gJk/9ECZv/RAmj/0QJp/9ECgP/SAoL/0gKE/9IClP/TApX/5gKW/9MC/f/TAwz/0wMN//QDD//TAxL/0QMY/+YDJ//tAzP/0gM0//QDN//RAzn/0QM7/+YDPP/vAz7/0QND/9EDRP/mA0v/0wNM/+YDTf/KA07/ygNS/8oDVP/RA13/0QNg/9QDYf/mA2j/0wNp/+YDa//0A2z/7wN5//QDev/vA37/0QOA/9EDif/tA4r/5gOL/+0DjP/mA43/7QOO/+YDj//hA5L/0QOT//QDlP/vA+r/0wPr/+YD7P/TA+3/5gPu/9MD7//mA/P/0QP1/9ED9v/SA/j/9AP5/+8D+v/hA/z/4QP//9EEAP/0BAH/7wQM/9EEDv/RBBD/0QQT/9MAHQA2/74AWP/vAFv/7wC4/+8Azf++ANH/vgEV/+8BLv++ATb/vgIm/+8CJ//vAoD/vgKC/74ChP++ApX/7wMY/+8DM/++Azv/7wNE/+8DTP/vA2H/7wNp/+8Div/vA4z/7wOO/+8D6//vA+3/7wPv/+8D9v++ADQANv/mADj/5wA6//IAO//nAFr/8QDN/+YA0f/mANX/8gDZ/+4A3P/oAOn/8QEU/+cBLv/mATb/5gIL/+cCgP/mAoL/5gKE/+YClP/nApb/5wL9/+cDDP/nAw3/8gMP/+cDJ//uAzP/5gM0//IDPP/xA0v/5wNg/+cDaP/nA2v/8gNs//EDef/yA3r/8QOJ/+4Di//uA43/7gOP/+gDk//yA5T/8QPq/+cD7P/nA+7/5wP2/+YD+P/yA/n/8QP6/+gD/P/oBAD/8gQB//EEE//nAIQAIwAQACX/6AAp/+gAMf/oADP/6AA2/+AAOP/gADv/3wCB/+gAkP/oAJT/6ACtABAArv/oAK8AEADN/+AAzv/oAM8AEADR/+AA2AAQANz/4QDtABAA9P/gAP8AEAED/+gBCAAQARL/6AEU/+ABFv/oARj/6AEa/+gBHP/oAS7/4AE0/+gBNv/gAU0AEAFR/+gB8QAQAfIAEAHzABAB9AAQAfUAEAH2ABAB9wAQAfj/6AIC/+gCA//oAgT/6AIF/+gCBv/oAgv/3wIoABACKgAQAiwAEAIu/+gCMP/oAjL/6AI0/+gCQv/oAkT/6AJG/+gCSP/oAmr/6AJs/+gCbv/oAoD/4AKC/+AChP/gApT/3wKW/98Cn//oAvgAEAL8/+gC/f/fAwAAEAMJ/+gDDP/fAw//3wMoABADL//oAzL/6AMz/+ADS//fA1UAEANX/+gDYP/gA2P/6ANm/+gDaP/fA24AEANwABADgf/oA4P/6AOF/+gDj//hA5D/4AOWABADlwAQA5gAEAOaABADnAAQA54AEAOgABADogAQA6QAEAOmABADqAAQA6oAEAOsABADrgAQA8T/6APG/+gDyP/oA8r/6APM/+gDzv/oA9D/6APS/+gD1P/oA9b/6APY/+gD2v/oA+r/3wPs/98D7v/fA/b/4AP6/+ED+//gA/z/4QP9/+AEEQAQBBIAEAQT/98ALQA2//EAOP/0ADr/9AA7//AAzf/xAM//9QDR//EA1f/0ANj/9QDZ//MBFP/0AS7/8QE2//EBTf/1Agv/8AKA//ECgv/xAoT/8QKU//AClv/wAv3/8AMM//ADDf/0Aw//8AMn//MDM//xAzT/9ANL//ADYP/0A2j/8ANr//QDef/0A4n/8wOL//MDjf/zA5P/9AOW//UD6v/wA+z/8APu//AD9v/xA/j/9AQA//QEEf/1BBP/8ABZACMADwA2/+YAOP/mADoADgA7/+YArQAPAK8ADwDN/+YAzwAOANH/5gDVAA4A2AAOANkACwDc/+UA7QAPAPT/6AD/AA8BCAAPART/5gEu/+YBNv/mAU0ADgHxAA8B8gAPAfMADwH0AA8B9QAPAfYADwH3AA8CC//mAigADwIqAA8CLAAPAoD/5gKC/+YChP/mApT/5gKW/+YC+AAPAv3/5gMAAA8DDP/mAw0ADgMP/+YDJwALAygADwMz/+YDNAAOA0v/5gNVAA8DYP/mA2j/5gNrAA4DbgAPA3AADwN5AA4DiQALA4sACwONAAsDj//lA5D/6AOTAA4DlgAOA5cADwOYAA8DmgAPA5wADwOeAA8DoAAPA6IADwOkAA8DpgAPA6gADwOqAA8DrAAPA64ADwPq/+YD7P/mA+7/5gP2/+YD+AAOA/r/5QP7/+gD/P/lA/3/6AQAAA4EEQAOBBIADwQT/+YALgA2/+MAOv/lADv/5ADN/+MAz//lANH/4wDV/+UA2P/lANn/6QDt/+oA///qAS7/4wE2/+MBTf/lAgv/5AKA/+MCgv/jAoT/4wKU/+QClv/kAv3/5AMM/+QDDf/lAw//5AMn/+kDM//jAzT/5QNL/+QDaP/kA2v/5QN5/+UDif/pA4v/6QON/+kDk//lA5b/5QOX/+oD6v/kA+z/5APu/+QD9v/jA/j/5QQA/+UEEf/lBBL/6gQT/+QAIQA2/+IAOv/kAM3/4gDP/+QA0f/iANX/5ADY/+QA2f/pAO3/6wD//+sBLv/iATb/4gFN/+QCgP/iAoL/4gKE/+IDDf/kAyf/6QMz/+IDNP/kA2v/5AN5/+QDif/pA4v/6QON/+kDk//kA5b/5AOX/+sD9v/iA/j/5AQA/+QEEf/kBBL/6wAXADb/6wA7//MAzf/rANH/6wEu/+sBNv/rAgv/8wKA/+sCgv/rAoT/6wKU//MClv/zAv3/8wMM//MDD//zAzP/6wNL//MDaP/zA+r/8wPs//MD7v/zA/b/6wQT//MAMABP/+8AUP/vAFL/7wBa//AAvP/vAOf/7wDp//AA6//vAOz/7wDu/+8A7//vAPD/7wDz/+8A9f/vAPb/7wD5/+8A+//vAQD/7wEx/+8BQP/vAUX/7wIc/+8CZP/vAmb/7wJo/+8Caf/vAxL/7wM3/+8DOf/vAzz/8AM+/+8DQ//vA1T/7wNd/+8DbP/wA3r/8AN+/+8DgP/vA5L/7wOU//AD8//vA/X/7wP5//AD///vBAH/8AQM/+8EDv/vBBD/7wAdAAT/8gAJ//IAWP/1AFv/9QC4//UBFf/1AWX/8gFm//IBaP/yAWn/8gFq//ICJv/1Aif/9QKV//UDGP/1Azv/9QNE//UDTP/1A03/8gNO//IDUv/yA2H/9QNp//UDiv/1A4z/9QOO//UD6//1A+3/9QPv//UABAD0/+0DkP/tA/v/7QP9/+0ACgAE//UACf/1AWX/9QFm//UBaP/1AWn/9QFq//UDTf/1A07/9QNS//UAVABF//AARv/wAEf/8ABJ//AAUf/rAFP/8ACR//AAlf/wALb/8ADD//AAxP/wAPL/8AD+//ABE//rARn/8AEd//ABNf/wAUf/8AFI//ABUv/wAhP/8AIU//ACFf/wAhb/8AIX//ACHf/rAh7/6wIf/+sCIP/rAiH/6wIv//ACMf/wAjP/8AI1//ACN//wAjn/8AI7//ACPf/wAj//8AJB//ACQ//wAkX/8AJH//ACSf/wAmv/6wJt/+sCb//rAxD/8AMW/+sDHP/rAzb/8AM4/+sDOv/wAz3/8ANc//ADYv/wA2f/8AN1//ADd//wA3j/8AOC/+sDhP/wA4b/6wOV//ADsf/wA7P/8AO1//ADt//wA7n/8AO7//ADvf/wA7//8APF/+sDx//rA8n/6wPL/+sDzf/rA8//6wPR/+sD0//wA9X/8APX//AD2f/rA9v/8ACPAAQADQAJAA0AQ//wAEX/sABG/7AAR/+wAEn/sABR/9YAU/+wAFgACwBbAAsAkf+wAJX/sAC2/7AAuAALAMT/sADt/68A8v+wAP7/sAD//68BE//WARUACwEZ/7ABHf+wATX/sAFH/7ABSP+wAVL/sAFlAA0BZgANAWgADQFpAA0BagANAgz/8AIN//ACDv/wAg//8AIQ//ACEf/wAhL/8AIT/7ACFP+wAhX/sAIW/7ACF/+wAh3/1gIe/9YCH//WAiD/1gIh/9YCJgALAicACwIp//ACK//wAi3/8AIv/7ACMf+wAjP/sAI1/7ACN/+wAjn/sAI7/7ACPf+wAj//sAJB/7ACQ/+wAkX/sAJH/7ACSf+wAmv/1gJt/9YCb//WApUACwMQ/7ADFv/WAxgACwMc/9YDNf/wAzb/sAM4/9YDOv+wAzsACwM9/7ADRAALA0wACwNNAA0DTgANA1IADQNW//ADXP+wA2EACwNi/7ADZ/+wA2kACwNv//ADcf/wA3X/sAN3/7ADeP+wA4L/1gOE/7ADhv/WA4oACwOMAAsDjgALA5X/sAOX/68Dmf/wA5v/8AOd//ADn//wA6H/8AOj//ADpf/wA6f/8AOp//ADq//wA63/8AOv//ADsf+wA7P/sAO1/7ADt/+wA7n/sAO7/7ADvf+wA7//sAPF/9YDx//WA8n/1gPL/9YDzf/WA8//1gPR/9YD0/+wA9X/sAPX/7AD2f/WA9v/sAPrAAsD7QALA+8ACwQS/68ACADtABAA9P/wAP8AEAOQ//ADlwAQA/v/8AP9//AEEgAQAEUARQAMAEYADABHAAwASQAMAFMADACRAAwAlQAMALYADADDAAwAxAAMAO0AGADyAAwA9P/3AP4ADAD/ABgBGQAMAR0ADAE1AAwBRwAMAUgADAFSAAwCEwAMAhQADAIVAAwCFgAMAhcADAIvAAwCMQAMAjMADAI1AAwCNwAMAjkADAI7AAwCPQAMAj8ADAJBAAwCQwAMAkUADAJHAAwCSQAMAxAADAM2AAwDOgAMAz0ADANcAAwDYgAMA2cADAN1AAwDdwAMA3gADAOEAAwDkP/3A5UADAOXABgDsQAMA7MADAO1AAwDtwAMA7kADAO7AAwDvQAMA78ADAPTAAwD1QAMA9cADAPbAAwD+//3A/3/9wQSABgAHwBY//QAWv/wAFv/9AC4//QA6f/wAO3/8wD///MBFf/0Aib/9AIn//QClf/0Axj/9AM7//QDPP/wA0T/9ANM//QDYf/0A2n/9ANs//ADev/wA4r/9AOM//QDjv/0A5T/8AOX//MD6//0A+3/9APv//QD+f/wBAH/8AQS//MACgAE/9YACf/WAWX/1gFm/9YBaP/WAWn/1gFq/9YDTf/WA07/1gNS/9YACgAE//UACf/1AWX/9QFm//UBaP/1AWn/9QFq//UDTf/1A07/9QNS//UAXgAEAAsACQALAEX/6wBG/+sAR//rAEn/6wBR/+kAU//rAJH/6wCV/+sAtv/rAMP/6wDE/+sA8v/rAP7/6wET/+kBGf/rAR3/6wE1/+sBR//rAUj/6wFS/+sBZQALAWYACwFoAAsBaQALAWoACwIT/+sCFP/rAhX/6wIW/+sCF//rAh3/6QIe/+kCH//pAiD/6QIh/+kCL//rAjH/6wIz/+sCNf/rAjf/6wI5/+sCO//rAj3/6wI//+sCQf/rAkP/6wJF/+sCR//rAkn/6wJr/+kCbf/pAm//6QMQ/+sDFv/pAxz/6QM2/+sDOP/pAzr/6wM9/+sDTQALA04ACwNSAAsDXP/rA2L/6wNn/+sDdf/rA3f/6wN4/+sDgv/pA4T/6wOG/+kDlf/rA7H/6wOz/+sDtf/rA7f/6wO5/+sDu//rA73/6wO//+sDxf/pA8f/6QPJ/+kDy//pA83/6QPP/+kD0f/pA9P/6wPV/+sD1//rA9n/6QPb/+sAAgseAAQAAA3mFToAIQAdAAAAEf/O/48AEv/1/+//iP/0/7v/f//1AAz/qf+i/8kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+UAAAAA/+j/yQAA//MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAD/5QARAAAAAAAAAAAAAP/jAAAAAAAA/+T/5AAAABIAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4QAAAAAAAAAAAAAAAAAAAAD/5QAAAAD/6v/VAAAAAP/r/+r/mv/pAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+YAAAAAAAAAAAAA/+0AAAAU/+8AAAAAAAAAAAAAAAAAAAAAAAD/7QAAAAAAAAAAAAAAAAAAAAD/y/+4/3z/fv/kAAAAAP+dAA8AEP+h/8QAEAAQAAAAAP+xAAD/JgAA/53/s/8Y/5P/8P+P/4z/EAAA/5L/cv8M/w//vQAAAAD/RAAFAAf/S/+GAAcABwAAAAD/PgAA/noAAP9E/2r+Yv8z/9H/LP8nAAAAAAAAAAAAAP/YAAAAAAAA/+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAP/Y/6MAAP/hAAAAAP/lAAAAAP/pAAAAAAAAAAAAAAAAAAAAAAAA/+YAAP/A/+kAAAAAAAAAAAAAAAD/ewAAAAD/v//K/3YAAP9x/u3/1AAA/1H/EQAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/JAA8AAP/ZAAAAAAAA//MAAAAAAAAAAAAAAAAAAAAA/3b/4f68/+b/8wAAAAAAAAAA//UAAP84AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/qAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9QAAAAD/8wAAAAD/0gAAAAD/5AAAAAAAAAAAAAD/tQAA/x8AAP/UAAD/2wAAAAD/0gAAAAAAAAAR/+H/0QAR/+cAAAAA/+sAAAAA/+sAAAAOAAAAAAAAAAAAAAAAAAD/5gAA/9IAAAAAAAAAAAAAAAAAAP/sAAAAAP/j/6AAAP+/ABEAEf/Z/+IAEgASAAAAAP+iAA3/LQAA/7//6f/M/9j/8P+3/8b/oAAAAAAAAAAAAAAAAAAAAAD/4QAAAA7/7QAAAAAAAAAAAAD/1QAA/4UAAP/hAAD/xAAAAAD/3wAAAAAAAAAA/+UAAAAA/+YAAAAA/+sAAAAA/+0AAAAAAAAAAAAAAA0AAAAAAAD/6wAAAAAAAAAAAAAAAAAAAAD/ygAA/+n/u//pAAAAAP+9AAAAEgAAAAAAAAASAAAAAP+lAAD+bQAA/70AAP+J/5oAAP+R/9IAAAAAAAD/8QAAAAAAAAAA/70AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/1AAD/8gAAAAD/4wAAAAAAAAAA//EAAAAAAAAAAAAAAAAAAAAAAAD/8QAAAAAAAAAAAAAAAAAAAAD/8wAAAAAAAAAA//IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/xAAD/8AAAAAD/7AAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAD/6wAAAAAAAAAAAAAAAAAAAAAAAAAA/9cAAAAAAA//8QAAAAAAAAAAAAAAAAAAAAAAAAAA/5UAAP/zAAAAAAAAAAD/8QAAAAAAAAAAABIAAAAAAAAAAAAQ/+wAAAAAAAAAAAAAAAAAAAAAAAAAAP+FAAD/7QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+V/8MAAAAAAAAAAAAAAAAAAAAA/4gAAAAAAAD/xQAAAAD/7AAA/87/sAAAAAAAAAAAAAAAAAAAAAD/VgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//UAAAAAAAAAAAAA/8AAAAAA/vUAAAAA/8j/rf/n/+sAAP/wAAAAAAAA/8kAAAAAAAAAAAAAAAAAAAAA/93/2QAAAAAAAP95AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/1AAAAAAAAAAAAAAAAAAIAiAAEAAQAAAAJAAkAAQARABEAAgAjACgAAwAqADMACQA2ADwAEwBDAEQAGgBHAEgAHABKAEoAHgBPAFIAHwBUAFQAIwBYAFgAJABaAFsAJQCIAIgAJwCZAJkAKACsALAAKQCyALQALgC2ALYAMQC4ALkAMgC7ALwANAC+AMAANgDCAMcAOQDNAM0APwDPANkAQADbANsASwDdAN8ATADhAOMATwDlAOkAUgDsAOwAVwDxAPMAWAD2APcAWwD5APsAXQD/AQAAYAEFAQUAYgEIAQgAYwETARUAZAEnASkAZwEsASwAagEuAS4AawFFAUUAbAFlAWYAbQFoAWoAbwGmAaYAcgGpAakAcwGrAasAdAGwAbEAdQG0AbYAdwG4Ab4AegHEAcQAgQHbAdwAggHoAegAhAHsAe0AhQHvAe8AhwHxAhIAiAIUAhcAqgIcAiEArgImAi4AtAIwAjAAvQIyAjIAvgI0AjQAvwI2AjYAwAI4AkEAwQJKAkwAywJOAk4AzgJQAlAAzwJSAlIA0AJUAlQA0QJXAlcA0gJZAlkA0wJbAlsA1AJdAl0A1QJfAl8A1gJhAmEA1wJjAm8A2AJxAnEA5QJzAnMA5gJ1AnUA5wKAAoAA6AKCAoIA6QKEAoQA6gKGAoYA6wKIAogA7AKKAooA7QKMAowA7gKOAo4A7wKQApAA8AKSApIA8QKUApcA8gKZApkA9gKbApsA9wL4Av0A+AMAAw8A/gMSAxIBDgMWAxYBDwMYAxgBEAMcAxwBEQMfAyABEgMiAysBFAMtAy8BHgMxAzYBIQM4AzkBJwM7Az4BKQNEA0UBLQNHA0cBLwNJA0kBMANLA04BMQNSA1cBNQNaA1oBOwNcA1wBPANgA2EBPQNmA2YBPwNoA3EBQAN0A3UBSgN3A3oBTAOBA4IBUAOGA4YBUgOIA44BUwOTA5QBWgOYA8ABXAPCA8IBhQPEA9EBhgPZA9kBlAPcA9wBlQPeA94BlgPqA+8BlwPyA/IBnQP0A/QBngP2A/YBnwP4A/kBoAP+BAEBogQEBAQBpgQGBAcBpwQJBAkBqQQNBA0BqgQPBA8BqwQTBBMBrAABAAoACgAoADMANAA9AEgATQBWAFkAXQABACIAmQCwALIAswC0ALsAvgC/AMAAxQDHAMgAyQDNANEA0wDUANYA3gDiAOMA5ADlAOYA6ADqAOwA8QDzAPYA+wD+AR0B3AACAHYABAAEAAAACQAJAAEADgAOAAIAEAAQAAMAIwAnAAQAKgAyAAkANgA8ABIAQwBFABkARwBHABwASgBKAB0ATwBSAB4AVABUACIAWABYACMAWgBcACQAiACIACcArACvACgAuAC4ACwAvAC8AC0AwgDCAC4AzwDQAC8A0gDSADEA1QDVADIA1wDZADMA2wDbADYA3QDdADcA3wDfADgA4QDhADkA5wDnADoA6QDpADsA8gDyADwA9wD3AD0A+QD6AD4A/wEAAEABBQEFAEIBCAEIAEMBEwEVAEQBJwEpAEcBLAEsAEoBLgEuAEsBRQFFAEwBZQFrAE0BbwFwAFQB7AHtAFYB7wHvAFgB8QIXAFkCHAIhAIACJgI2AIYCOAJBAJcCSgJMAKECTgJOAKQCUAJQAKUCUgJSAKYCVAJUAKcCVwJXAKgCWQJZAKkCWwJbAKoCXQJdAKsCXwJfAKwCYQJhAK0CYwJvAK4CcQJxALsCcwJzALwCdQJ1AL0CgAKAAL4CggKCAL8ChAKEAMAChgKGAMECiAKIAMICigKKAMMCjAKMAMQCjgKOAMUCkAKQAMYCkgKSAMcClAKcAMgC+AL9ANEDAAMPANcDEgMSAOcDFgMWAOgDGAMYAOkDHAMcAOoDHwMgAOsDIgMrAO0DLQMvAPcDMQM2APoDOAM+AQADRANFAQcDRwNHAQkDSQNJAQoDSwNOAQsDUgNXAQ8DWgNaARUDXANcARYDYANhARcDZgNxARkDdAN1ASUDdwN6AScDgQOCASsDhgOGAS0DiAOOAS4DkwOUATUDmAPAATcDwgPCAWADxAPRAWED2QPZAW8D3APcAXAD3gPeAXED6gPvAXID8gPyAXgD9AP0AXkD9gP2AXoD+AP5AXsD/gQBAX0EBAQEAYEEBgQHAYIECQQJAYQEDQQNAYUEDwQPAYYEEwQTAYcAAgE4AAQABAAdAAkACQAdAA4ADgAeABAAEAAeACQAJAABACUAJQAEACYAJgADACcAJwAFACoAKwACACwALAAMAC0ALQAJAC4ALgAKAC8AMAACADEAMQADADIAMgALADYANgAGADcANwAMADgAOAANADkAOQAQADoAOgAOADsAOwAPADwAPAARAEMAQwATAEQARAAVAEUARQAUAEcARwAWAEoASgAXAE8AUAAXAFEAUQAYAFIAUgAVAFQAVAAaAFgAWAAZAFoAWgAbAFsAWwAZAFwAXAAcAIgAiAAVAKwArAAHAK4ArgADALgAuAAZALwAvAAXAMIAwgAVAM8A0AAfANIA0gACANUA1QAOANcA2AACANkA2QASANsA2wACAN0A3QACAN8A3wAfAOEA4QAfAOcA5wAIAOkA6QAbAPIA8gAVAPcA9wAgAPkA+QAgAPoA+gAVAP8BAAAgAQUBBQAgARMBEwAYARQBFAANARUBFQAZAScBJwAVASgBKAAHASkBKQAIASwBLAAJAS4BLgAJAUUBRQAIAWUBZgAdAWcBZwAeAWgBagAdAWsBawAeAW8BcAAeAewB7QADAe8B7wAGAfgB+AAEAfkB/AAFAf0CAQACAgICBgADAgcCCgAMAgsCCwAPAgwCEgATAhMCEwAUAhQCFwAWAhwCHAAXAh0CIQAYAiYCJwAZAikCKQATAisCKwATAi0CLQATAi4CLgAEAi8CLwAUAjACMAAEAjECMQAUAjICMgAEAjMCMwAUAjQCNAAEAjUCNQAUAjYCNgADAjgCOAAFAjkCOQAWAjoCOgAFAjsCOwAWAjwCPAAFAj0CPQAWAj4CPgAFAj8CPwAWAkACQAAFAkECQQAWAkoCSgACAksCSwAXAkwCTAACAk4CTgACAlACUAACAlICUgACAlQCVAACAlcCVwAMAlkCWQAJAlsCWwAKAl0CXQAKAl8CXwAKAmECYQAKAmMCYwACAmQCZAAXAmUCZQACAmYCZgAXAmcCZwACAmgCaQAXAmoCagADAmsCawAYAmwCbAADAm0CbQAYAm4CbgADAm8CbwAYAnECcQAaAnMCcwAaAnUCdQAaAoACgAAGAoICggAGAoQChAAGAoYChgAMAogCiAAMAooCigAMAowCjAAMAo4CjgAMApACkAAMApICkgAQApQClAAPApUClQAZApYClgAPApcClwARApgCmAAcApkCmQARApoCmgAcApsCmwARApwCnAAcAvkC+QAFAvoC+wACAvwC/AADAv0C/QAPAwEDAQABAwIDAgAFAwMDAwARAwQDBQACAwYDBgAJAwcDCAACAwkDCQADAwoDCgALAwsDCwAGAwwDDAAPAw0DDQAOAw4DDgACAw8DDwAPAxIDEgAXAxYDFgAYAxgDGAAZAxwDHAAYAx8DHwAFAyADIAAHAyIDIwACAyQDJAAMAyUDJgAJAycDJwASAykDKQABAyoDKgAHAysDKwAFAy0DLgACAy8DLwADAzEDMQALAzIDMgAEAzMDMwAGAzQDNAAOAzUDNQATAzYDNgAWAzgDOAAYAzkDOQAVAzoDOgAUAzsDOwAZAzwDPAAbAz0DPQAWAz4DPgAIA0QDRAAZA0UDRQAQA0cDRwAQA0kDSQAQA0sDSwAPA0wDTAAZA00DTgAdA1IDUgAdA1MDUwACA1QDVAAXA1YDVgATA1cDVwADA1oDWgAFA1wDXAAWA2ADYAANA2EDYQAZA2YDZgAEA2cDZwAUA2gDaAAPA2kDaQAZA2oDagACA2sDawAOA2wDbAAbA20DbQACA28DbwATA3EDcQATA3QDdAAFA3UDdQAWA3cDeAAWA3kDeQAOA3oDegAbA4EDgQADA4IDggAYA4YDhgAYA4gDiAAVA4kDiQASA4oDigAZA4sDiwASA4wDjAAZA40DjQASA44DjgAZA5MDkwAOA5QDlAAbA5kDmQATA5sDmwATA50DnQATA58DnwATA6EDoQATA6MDowATA6UDpQATA6cDpwATA6kDqQATA6sDqwATA60DrQATA68DrwATA7ADsAAFA7EDsQAWA7IDsgAFA7MDswAWA7QDtAAFA7UDtQAWA7YDtgAFA7cDtwAWA7gDuAAFA7kDuQAWA7oDugAFA7sDuwAWA7wDvAAFA70DvQAWA74DvgAFA78DvwAWA8ADwAACA8IDwgACA8QDxAADA8UDxQAYA8YDxgADA8cDxwAYA8gDyAADA8kDyQAYA8oDygADA8sDywAYA8wDzAADA80DzQAYA84DzgADA88DzwAYA9AD0AADA9ED0QAYA9kD2QAYA9wD3AAMA94D3gAMA+oD6gAPA+sD6wAZA+wD7AAPA+0D7QAZA+4D7gAPA+8D7wAZA/ID8gAJA/QD9AACA/YD9gAGA/gD+AAOA/kD+QAbA/4D/gAHA/8D/wAIBAAEAAAOBAEEAQAbBAQEBAAXBAYEBgAfBAcEBwAHBAkECQAJBA0EDQACBA8EDwACBBMEEwAPAAEABAQWAAcAAAAAAAAAAAAHAAAAAAAAAAAAEwAXABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAUAAAAAAAAABQAAAAAAHAAAAAAAAAAAAAUAAAAFAAAAGQAKAAYADQAJABIADgAUAAAAAAAAAAAAAAAAABoAAAAVABUAFQAAABUAAAAAAAAAAAAAABgAGAAIABgAFQAAABsAAAALAAIAAAAWAAIADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFABUAAAAAAAUAFQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAFABEAAAAAAAAAAAAAAAAAFQAAAAIAAAAAAAAAGAAAAAAAAAAAAAAAAAAVABUAAAALAAAAAAAAAAAAAAAAAAoABQABAAAACgAAAAAAAAASAAAAAAABABAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAFgAAABgAGAAEABgAGAAYAAAAFQAYAAMAGAAYAAAAAAAYAAAAGAAAAAAAFQAEABgAAAAAAAUAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAUACAANAAIABQAAAAUAFQAFAAAABQAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAGAAAAAAABQAVAAoAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAABgAAAAVABUAAAAAAAAAAAABAAAAAAAAAAUAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXABcAAAAHAAcAEwAHAAcABwATAAAAAAAAABMAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFwAAAAAAAAAAAAAAEQARABEAEQARABEAEQAFAAAAAAAAAAAAAAAAAAAAAAAAAAUABQAFAAUABQAGAAYABgAGAA4AGgAaABoAGgAaABoAGgAVABUAFQAVABUAAAAAAAAAAAAYAAgACAAIAAgACAALAAsACwALAAIAAgARABoAEQAaABEAGgAFABUABQAVAAUAFQAFABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUABQAVAAUAFQAFABUABQAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAGAAAABgAGAAFAAgABQAIAAUACAAAAAAAAAAAAAAAAAAZABsAGQAbABkAGwAZABsAGQAbAAoAAAAKAAAACgAAAAYACwAGAAsABgALAAYACwAGAAsABgALAAkAAAAOAAIADgAUAAwAFAAMABQADAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEAAAAAAAAABQAOAAAAAAARAAAAAAAUAAAAAAAAAAAAAAAFAAAAAAAOABIAAAAOABUAAAAYAAAACwAAAAgAAAACAAAAAAALAAgACwAAAAAAAAAAAAAAAAAcAAAAAAAQABEAAAAAAAAAAAAAAAAABQAAAAAABQAKABIAGgAVABgACAAYABUAAgAWABUAGAAbAAAAAAAAABgAAgAJAAAACQAAAAkAAAAOAAIABwAHAAAAAAAAAAcAAAAYABEAGgAFAAAAAAAAAAAAFQAYAAAAAAANAAIAFQAFAAAAAAAFABUADgACAAAAEgAWAAAAEQAaABEAGgAAAAAAAAAVAAAAFQAVABIAFgAAAAAAAAAYAAAAGAAFAAgABQAVAAUACAAAAAAAEAACABAAAgAQAAIADwADAAAAGAASABYAFQABAAQAEQAaABEAGgARABoAEQAaABEAGgARABoAEQAaABEAGgARABoAEQAaABEAGgARABoAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAAAAAAAAAAAUACAAFAAgABQAIAAUACAAFAAgABQAIAAUACAAFABUABQAVAAUAFQAFAAgABQAVAAYACwAGAAsAAAALAAAACwAAAAsAAAALAAAACwAOAAIADgACAA4AAgAAAAAAAAAYAAAAGAAKAAAAEgAWAA8AAwAPAAMAAAAYABIAFgAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAYAAAAGAABAAQADgAAAAAAAAAAAAAAFwABAAAACgAsAI4AAURGTFQACAAEAAAAAP//AAgAAAABAAIAAwAEAAUABgAHAAhsaWdhADJsbnVtADhzbWNwAD5zczAxAERzczAyAEpzczAzAFBzczA0AFZzczA1AFwAAAABAAEAAAABAAIAAAABAAAAAAABAAMAAAABAAQAAAABAAUAAAABAAYAAAABAAcACAASABoAIgAqADIAOgBCAEoAAQAAAAEAQAAEAAAAAQH2AAEAAAABAgAAAQAAAAECEgABAAAAAQIQAAEAAAABAg4AAQAAAAECDAABAAAAAQIOAAICEADcAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AegBtQG2AbcBuAG5AboBuwG8Ab0BvgGmAacBqAGpAaoBqwGsAa0BrgGvAbABsQGyAbMBtAHoAbUBtgG3AbgBuQG6AbsBvAG9Ab4C9wKiAqECogKjAqMCpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4C8wK/Ar8CwALAAsECwQLCAsICwwLDAsUCxQLGAsYCxwLHAsgCyALJAskCygLKAssCywLMAswCzQLNAs8CzwLQAtAC0QLRAtIC0gLTAtMC1ALUAtUC1gLWAtcC1wLYAtgC2QLZAtoC2gLbAtsC3ALcAt0C3QLeAt4C3wLfAuAC4ALhAuEC4gLiAuMC4wLkAuQC5QLlAuYC5gLnAucC6ALo/////wLqAuoC6wLrAuwC7ALtAu0C7gLuAu8C7wLwAvAC8QLxAvIC8gLzAvQC9AL1AvUC9gL2AqEAAQCkAAEACAABAAQBkgACAEsAAgCYAAoBmAHMAcQB1gHXAdgB2QHbAd0B5wABAIgBkQABAIgBKAABAIgBrgACAIgAAgHjAeQAAgB+AAIB5QHmAAIADQAjADwAAABDAFwAGgCDAIMANACFAIUANQHsAe0ANgHvAjEAOAI0AkUAewJIAlQAjQJXAmgAmgJqAnsArAJ+An8AvgKCApwAwAPwA/AA2wABAAEASAACAAEAEgAbAAAAAQABAEkAAQABALYAAQABADQAAQACAC0ATQ==","sampleImage.jpg":"/9j/4RC5RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAgAAAAcgEyAAIAAAAUAAAAkodpAAQAAAABAAAAqAAAANQACvyAAAAnEAAK/IAAACcQQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaAAyMDE0OjAzOjE5IDAzOjAyOjI2AAAAAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAregAwAEAAAAAQAAATYAAAAAAAAABgEDAAMAAAABAAYAAAEaAAUAAAABAAABIgEbAAUAAAABAAABKgEoAAMAAAABAAIAAAIBAAQAAAABAAABMgICAAQAAAABAAAPfwAAAAAAAABIAAAAAQAAAEgAAAAB/9j/7QAMQWRvYmVfQ00AAf/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAEcAoAMBIgACEQEDEQH/3QAEAAr/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEyBhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80YnlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBTUBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTVKMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/2gAMAwEAAhEDEQA/AO9gJbfNShKFatpsfcPNRJd31RITEJWpGH2A6Ex4KJPkilqbajYRqikpiPLXxRCxNtTrUjIP+1SG8cBPBT7dPPxStCVrslrQ5jdzBzw6FH7VaHSII7wOFCXARJA8FEiU0RHUBcZHoSn+1vPYfM/3qFmW94iI+CFt7dkmhoI3at7gcoiER0VxyPVmy2sCXyT4awpG9rj7Xlo7hQln5o2jxOqi41xLZJHc8flR4RfVXFpuFw92rnu0/NH96Gbn7uyR3Hkp20veJER5p1AbosnZg615/wByGSTyilkHmfgmhOBC031f/9D0X0H+B/BRNTx2VuJGibXwT/cLEcQae1w7JiPEK9BPITGuSj7ngj2uzS0SA3GByrbDXbu9Mts2OLX7TMOH0mP2/n/yU5YD2R9zwR7Xi0oTbJPCtuobOmiQpEzyUfcCPbLWYGQQ5m49j/BRLY5aFc2tA1H8U2yuZiZ7hLj808GjRI+SaFedTVOg7eJ/vUDUBwJThkC04i1NqYtVr0xPh8UtidxrfbLT2+SW1Wy1zR218lAsPgPkiJoMGtt+acNPafvRjWfBMKXeCPEFcJ7MRXqCYPknOODJbB8giCt4HA+9OGxyhxeK4R7h/9H0oOrJ0BkrKt+tf1aqkftKl7hI21v36jT832/9JXMfJqvxq8tocaLam3ca7Ht9SHfu+1ebV9K+vEAOz8MjQCK6NPvwv3ETKu31WgfyD1nUfrl0+7Dvx8O4tttrc1l5urrLCdBYwsdbZ7Vy7uo51vtyeqeuwGWtOXEGNu7+b/e9T/z3/wAIiYPS/rPvsPUcyl1XpONIx2Ywf62noeo63B/mPper/hFa6hg9XdjbenXVY+UXja+2ui2st2nfU5rsc+n7/f63v/0f+EQ4vGP8v8FRjfSX8v8ACaRynwWtzIaXF4aMsD3kbfUftq99n8tEZ1Tr24OZ1na9rmuaXXeq2AWy2ynaxtjH7bWfS/P/AOCV+vAzgykWuY6wCoXlooAc4N/WfT/Vvb6ln82sf6wvb0+thzzb+sY11eB9nc1hbmNLXm/I+zfY/wBV9F+P+js9f3+p+gTgSSBcde3/AKKigNalp3/9GenwfrK7HuvttvrubkHe6uyyGsf7W7qHbXenV6bPdR9D/DfT9b1bbvrphMfse7Ha/TT1XmZIa2HNoc125zmrygdRyw0l2RcWgSYsfMf5y1s7q31n6DRh05FuMx17C6ptNNZb6Iaz0t7m7avV93vZ6Pqf6W23/BGWMxIF3xfT/vlCYIJqq+r6APrv00jd6uOQYg+q/udjf8B+/wC1IfXfpZBd62PGkn1X95j/AAH8hy5vo3Vep5tIs9VucxzKnPvrqNba7X6ZHT3Ctu227EZsust/4VXWZnWDXW77HZvc6tr2fpJYHu2XWT6fubjs/Su/fTSCP/Ro/wDepsfyjJ12/XXpbo2247p4i1x7Od/oP3a3op+tOGOfRkcgXa/jUsO276xPAqxML1LrC1ostn06w71PWyLfWayt7cVlbLPTsf8ApPU/6zdh59HUbOq3VsuvZWAw2OqbY9lTjUyxtThhBzHOs+n+hZ/hEo2TV19YlE5AC6v/AAZPQdU691HJua7EzqsSoNLRWy2JcfznGH7vd/0FUHVOsguI6n7nd/XHA+hzT+7+6sjo7uo2ZIx2utbn12B11d9gLBjt2/bcd7Mh1lf2raf0T/T3s/01a231dXlxaKg0B4AJoJneDX/g/d+g3MTttLj/AIX/AKKs31qX+D/6Mh/afWWOcaupBhedzybgZMMYHH9D/oq9n+vv1em/WO6jGFebfVlW+oXG02iSwx+i+gz6KoCnqQquFjqha994xnA0FoDh/k9lkV/Srf8Azu7/AMGSNPUzdXHpCsPJtbux5dWai1rWONf0vteyz/i/+20r/rQ/l/gpArpL6/8AozvD609NPMsHjvpP4C5EH1gwHAFpJB1BBq/9Lrna6uoAsNoYWgs9QB1APBFv5jXN/SbHLhupY3Sq+qZdHUaX29QrD7sqyq6prHWemcq30mVYzWbXf8G1C+xifLVI8RIeb7FV1Kq8MNYJFhIafb23fuPf+4im0+C4j6o9Qpoqr6fSPTwcKy9ofY7c8Q9+nsrYxzH22vc36di6L9t9PLnMFji5oBPscNHFwb7nhrfzHJQnoeKtD+CZRNiuz//So9P6t9lyvVZYdzWw7ffW6sHIAxq77La273Mp+0faXv2Pr/R/y61rW9Uof0u7Hq610+nqLg4VZLMkOrYd+5jt17rMj+Y/Ru9n01yHoBzrnfaHO+02ltjHs3F1VTD6LtK9m+2/0/0dLdlf6JZ7sKxtRfXjudYWPEtaT9L2Tua33e1yhjkjKJuUeIa1p6lvuAeP1e8t6i111j6vrBgsqdblvrYchntqupbV0ur/ANp+ZuybP+h6yVPUA2yp1v1gwbK2WYLrWjIr1ZRW5nV2/m/8p3/pK/8AwT0FwFXRszc26rFve1jg8ltDnCB7vptDmtRcfp2f6D/8mPe703kuNNhLvUdWx0kfS+zfTq/cUnCLriG29xTx+Bez+15rcQVH6z9P+0/ZfT9U3sg5H2n7T9r1bu2fsv8AUfo/T/wez9Ms/wDxg9SwModOGFfRlAPySfSsbb6YIx9v8y921/8AXXL4+Pa59RGF61T7W+nc+pzt7WN9F7Q4bGur/wAJsQXYWc1jLnY11eOwBrH+m4Md3cN8bfplKFcUSSB9YolOwRSZr5BG0vEGWjkgCXLR+tVmT9k6WMrqOP1O1oui7Gsa8MZtxvTx7BU1np2Vx+cqbcLIZiW5Ty2p1BINFpDbPaBqa3uZZ+dsbtZ9NaZ+qPT7cfbXlWNc0eqS/wBMQXtrcW27jX6fsZ/hXVqTJmx2JcYIhd0jHA0RXzVTd+p2Zk19IeMO3GpJuyTa3KtrDjb9noHT31Nt2foftf8AP/8ABroreo9R3H0Mrp4b+n27rqp/mK/2d+f/AOWXr/af+62xcfT9TulvL9+Y+ahLmudjVvH0tu6qy93q7q632/on2f8AFItv1J6d6DjXdk7thNbnMqDSfcWOc7d9BRGcJeoSBEtQWQAjStnr6uqZLMtrvtmAynfb7zfUNrPSr+yvd7zu2Zn2p13/AAXpLk+rue/qD3PvryXFtc30P31uOxo3V2sDGv8Ab7PooeJ9UacXJrttuBYJaRsDnOkW0xXTFvrPe70/0Xvs9/p/zivt6J0xtftyrxVUIkY73Na2SYL2VbW+47PejCUAdx9iyYMtK/Fn9V8vp2Jm7svZS8iwtzLbRWxjTWR6T22fo3Otd+et93VunHI3N6vhCo21PFf2lk+m1rhfXs1/nbNrvpf9crXP09N6bh9RpvGbacioE14z8Z1jXkhzJOOaX+t9P9z6f/CLHzvqu9nVMmvD+0XYlBcym9oL3OIDfz6WbPd+k3bNnpv+miZxJNHcVsgAgVWxv5v0v3fS9mOq4LWtbZ1nCL2ioPP2pp9zbN2Q76P+Eo/Rf+fP9Ig3dUrdU9tXX+nMsNdja3m0ECx14ux7CB+ZXgbsR/8AwvvWIei9Nx+nY7jj3WZDy9uTYWXFzWNtG+l7aR6fqOwnbX+33/p/T/SIWTi9Jrvx2YvRbcqm7+dt25bTUJj1Nrm/p2bHb/0aackSdfP5YhNVp4dZF6N/WcM2WFvWunitz8g1t9Yghjwz9nsJ93vxnNt+0O/7YXJZlfW39Qz3MutzK7LLXU5NJcWWNspu9I02e3fW2z0WN/4VJrayBP1WtDy/aW7skkN/0n0Vft6N0H7Xv/ZlrsU1vDpx8wOddvbsfJj2ej6nt/fSM4j/AHop+z7VsCy/p+Hm5OZQ47X3Xem/b7g4Ndv/AEgtY79I51n6Suz+aQXfXLCAhmExsN3Of+jBc1w9P/B4zPT99jXfo0+TV07Ccw4uC4Yz6bqvstldzPVvea/TZ6lm29vq07v8J/N1WqtQOmm7FOR0ZtGM+suyHD1niff6FQ3WHfTvbRY2ytD3IjU6691E+IH1f//T5lv7d/SFpyJIA1Do0+jLWt2/R+h6f5ikLetj2tF4siXEtkxHf2Ljklln2uvB/wA1qa+L1zr+pydzX7dd0tgydNf0f7qeh3Uy57i6xhcRIa0nQfR0LPbYuQSQPtUa4f8Amo1e1st6o4PFrrAOHbqwD/1H/f1Oo9TdYfTdYD/JBBn+wxrVw6SjPt1pw/8ANVr4vbi3qpLQPWEiG+0zHj7Wu9iEcnPEw1xAJDj6cDj3ep7P+qXGpJw9rrX/ADVavZi7Oa6WD3RqGMBdB+ju9n/mCduRcWtc4bdCA19bPLwZ/wCYLi0kvR4X9Favb13Zjmba/olx+gwDXvDhXt3JPuubra1jmtjcHsGzy3abVxCSaeG+n9qtXvqM7Elotx2SeIazU6bYhu5v8hWmWYj90MrAH0hAB/tbfztq83SUc6/RXC/B9JD8cPmptLrB9ICNxJ/ejanDmuZu2NYCBoD7QB2hpe3uvNUkxWr6W5w3htgZvj6RHb5u3KJFjhEsaBHplnh+Z9H6f530l5skiFPojxVuJN1Qsc7RvpSOP+i701EV4wc8NsYbDt3eQn9HG0Nf/VXnqSdqj7H/2f/tF+hQaG90b3Nob3AgMy4wADhCSU0EJQAAAAAAEAAAAAAAAAAAAAAAAAAAAAA4QklNBDoAAAAAAJMAAAAQAAAAAQAAAAAAC3ByaW50T3V0cHV0AAAABQAAAABDbHJTZW51bQAAAABDbHJTAAAAAFJHQkMAAAAASW50ZWVudW0AAAAASW50ZQAAAABDbHJtAAAAAE1wQmxib29sAQAAAA9wcmludFNpeHRlZW5CaXRib29sAAAAAAtwcmludGVyTmFtZVRFWFQAAAABAAAAOEJJTQQ7AAAAAAGyAAAAEAAAAAEAAAAAABJwcmludE91dHB1dE9wdGlvbnMAAAASAAAAAENwdG5ib29sAAAAAABDbGJyYm9vbAAAAAAAUmdzTWJvb2wAAAAAAENybkNib29sAAAAAABDbnRDYm9vbAAAAAAATGJsc2Jvb2wAAAAAAE5ndHZib29sAAAAAABFbWxEYm9vbAAAAAAASW50cmJvb2wAAAAAAEJja2dPYmpjAAAAAQAAAAAAAFJHQkMAAAADAAAAAFJkICBkb3ViQG/gAAAAAAAAAAAAR3JuIGRvdWJAb+AAAAAAAAAAAABCbCAgZG91YkBv4AAAAAAAAAAAAEJyZFRVbnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAA4QklNA+0AAAAAABAASAAAAAEAAgBIAAAAAQACOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAB4OEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0EAAAAAAAAAgABOEJJTQQCAAAAAAAEAAAAADhCSU0EMAAAAAAAAgEBOEJJTQQtAAAAAAAGAAEAAAACOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4QklNBBoAAAAAA0sAAAAGAAAAAAAAAAAAAAE2AAACtwAAAAsAQgBlAHoAIABuAGEAegB3AHkALQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAK3AAABNgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAABNgAAAABSZ2h0bG9uZwAAArcAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAATYAAAAAUmdodGxvbmcAAAK3AAAAA3VybFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZhdWx0AAAACXZlcnRBbGlnbmVudW0AAAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1bHQAAAALYmdDb2xvclR5cGVlbnVtAAAAEUVTbGljZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9wT3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91dHNldGxvbmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcAAAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAAAAAAOEJJTQQoAAAAAAAMAAAAAj/wAAAAAAAAOEJJTQQUAAAAAAAEAAAAAjhCSU0EDAAAAAAPmwAAAAEAAACgAAAARwAAAeAAAIUgAAAPfwAYAAH/2P/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgARwCgAwEiAAIRAQMRAf/dAAQACv/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A72Alt81KEoVq2mx9w81El3fVEhMQlakYfYDoTHgok+SKWptqNhGqKSmI8tfFELE21OtSMg/7VIbxwE8FPt08/FK0JWuyWtDmN3MHPDoUftVodIgjvA4UJcBEkDwUSJTREdQFxkehKf7W89h8z/eoWZb3iIj4IW3t2SaGgjdq3uByiIRHRXHI9WbLawJfJPhrCkb2uPteWjuFCWfmjaPE6qLjXEtkkdzx+VHhF9VcWm4XD3aue7T80f3oZufu7JHceSnbS94kRHmnUBuiydmDrXn/AHIZJPKKWQeZ+CaE4ELTfV//0PRfQf4H8FE1PHZW4kaJtfBP9wsRxBp7XDsmI8Qr0E8hMa5KPueCPa7NLRIDcYHKtsNdu70y2zY4tftMw4fSY/b+f/JTlgPZH3PBHteLShNsk8K26hs6aJCkTPJR9wI9stZgZBDmbj2P8FEtjloVza0DUfxTbK5mJnuEuPzTwaNEj5JoV51NU6Dt4n+9QNQHAlOGQLTiLU2pi1WvTE+HxS2J3Gt9stPb5JbVbLXNHbXyUCw+A+SImgwa235pw09p+9GNZ8Ewpd4I8QVwnsxFeoJg+Sc44MlsHyCIK3gcD704bHKHF4rhHuH/0fSg6snQGSsq361/VqqR+0qXuEjbW/fqNPzfb/0lcx8mq/Gry2hxotqbdxrse31Id+77V5tX0r68QA7PwyNAIro0+/C/cRMq7fVaB/IPWdR+uXT7sO/Hw7i222tzWXm6ussJ0FjCx1tntXLu6jnW+3J6p67AZa05cQY27v5v971P/Pf/AAiJg9L+s++w9RzKXVek40jHZjB/raeh6jrcH+Y+l6v+EVrqGD1d2Nt6ddVj5ReNr7a6Lay3ad9Tmuxz6fv9/re//R/4RDi8Y/y/wVGN9Jfy/wAJpHKfBa3MhpcXhoywPeRt9R+2r32fy0RnVOvbg5nWdr2ua5pdd6rYBbLbKdrG2MfttZ9L8/8A4JX68DODKRa5jrAKheWigBzg39Z9P9W9vqWfzax/rC9vT62HPNv6xjXV4H2dzWFuY0teb8j7N9j/AFX0X4/6Oz1/f6n6BOBJIFx17f8AoqKA1qWnf/0Z6fB+srse6+22+u5uQd7q7LIax/tbuodtd6dXps91H0P8N9P1vVtu+umEx+x7sdr9NPVeZkhrYc2hzXbnOavKB1HLDSXZFxaBJix8x/nLWzurfWfoNGHTkW4zHXsLqm001lvohrPS3ubtq9X3e9no+p/pbbf8EZYzEgXfF9P++UJggmqr6voA+u/TSN3q45BiD6r+52N/wH7/ALUh9d+lkF3rY8aSfVf3mP8AAfyHLm+jdV6nm0iz1W5zHMqc++uo1trtfpkdPcK27bbsRmy6y3/hVdZmdYNdbvsdm9zq2vZ+klge7ZdZPp+5uOz9K799NII/9Gj/AN6mx/KMnXb9delujbbjuniLXHs53+g/drein604Y59GRyBdr+NSw7bvrE8CrEwvUusLWiy2fTrDvU9bIt9ZrK3txWVss9Ox/wCk9T/rN2Hn0dRs6rdWy69lYDDY6ptj2VONTLG1OGEHMc6z6f6Fn+ESjZNXX1iUTkALq/8ABk9B1Tr3Ucm5rsTOqxKg0tFbLYlx/OcYfu93/QVQdU6yC4jqfud39ccD6HNP7v7qyOju6jZkjHa61ufXYHXV32AsGO3b9tx3syHWV/atp/RP9Pez/TVrbfV1eXFoqDQHgAmgmd4Nf+D936DcxO20uP8Ahf8AoqzfWpf4P/oyH9p9ZY5xq6kGF53PJuBkwxgcf0P+ir2f6+/V6b9Y7qMYV5t9WVb6hcbTaJLDH6L6DPoqgKepCq4WOqFr33jGcDQWgOH+T2WRX9Kt/wDO7v8AwZI09TN1cekKw8m1u7Hl1ZqLWtY41/S+17LP+L/7bSv+tD+X+CkCukvr/wCjO8PrT008yweO+k/gLkQfWDAcAWkkHUEGr/0uudrq6gCw2hhaCz1AHUA8EW/mNc39JscuG6ljdKr6pl0dRpfb1CsPuyrKrqmsdZ6ZyrfSZVjNZtd/wbUL7GJ8tUjxEh5vsVXUqrww1gkWEhp9vbd+49/7iKbT4LiPqj1Cmiqvp9I9PBwrL2h9jtzxD36eytjHMfba9zfp2Lov2308ucwWOLmgE+xw0cXBvueGt/MclCeh4q0P4JlE2K7P/9Kj0/q32XK9Vlh3NbDt99bqwcgDGrvstrbvcyn7R9pe/Y+v9H/LrWtb1Sh/S7serrXT6eouDhVksyQ6th37mO3XusyP5j9G72fTXIegHOud9oc77TaW2MezcXVVMPou0r2b7b/T/R0t2V/olnuwrG1F9eO51hY8S1pP0vZO5rfd7XKGOSMom5R4hrWnqW+4B4/V7y3qLXXWPq+sGCyp1uW+thyGe2q6ltXS6v8A2n5m7Js/6HrJU9QDbKnW/WDBsrZZgutaMivVlFbmdXb+b/ynf+kr/wDBPQXAVdGzNzbqsW97WODyW0OcIHu+m0Oa1Fx+nZ/oP/yY97vTeS402Eu9R1bHSR9L7N9Or9xScIuuIbb3FPH4F7P7XmtxBUfrP0/7T9l9P1TeyDkfaftP2vVu7Z+y/wBR+j9P/B7P0yz/APGD1LAyh04YV9GUA/JJ9KxtvpgjH2/zL3bX/wBdcvj49rn1EYXrVPtb6dz6nO3tY30XtDhsa6v/AAmxBdhZzWMudjXV47AGsf6bgx3dw3xt+mUoVxRJIH1iiU7BFJmvkEbS8QZaOSAJctH61WZP2TpYyuo4/U7Wi6Lsaxrwxm3G9PHsFTWenZXH5yptwshmJblPLanUEg0WkNs9oGpre5ln52xu1n01pn6o9Ptx9teVY1zR6pL/AExBe2txbbuNfp+xn+FdWpMmbHYlxgiF3SMcDRFfNVN36nZmTX0h4w7cakm7JNrcq2sONv2egdPfU23Z+h+1/wA//wAGuit6j1HcfQyunhv6fbuuqn+Yr/Z35/8A5Zev9p/7rbFx9P1O6W8v35j5qEua52NW8fS27qrL3erurrfb+ifZ/wAUi2/Unp3oONd2Tu2E1ucyoNJ9xY5zt30FEZwl6hIES1BZACNK2evq6pksy2u+2YDKd9vvN9Q2s9Kv7K93vO7ZmfanXf8ABekuT6u57+oPc++vJcW1zfQ/fW47GjdXawMa/wBvs+ih4n1Rpxcmu224FglpGwOc6RbTFdMW+s97vT/Re+z3+n/OK+3onTG1+3KvFVQiRjvc1rZJgvZVtb7js96MJQB3H2LJgy0r8Wf1Xy+nYmbuy9lLyLC3MttFbGNNZHpPbZ+jc6135633dW6ccjc3q+EKjbU8V/aWT6bWuF9ezX+ds2u+l/1ytc/T03puH1Gm8ZtpyKgTXjPxnWNeSHMk45pf630/3Pp/8IsfO+q72dUya8P7RdiUFzKb2gvc4gN/PpZs936Tds2em/6aJnEk0dxWyACBVbG/m/S/d9L2Y6rgta1tnWcIvaKg8/amn3Ns3ZDvo/4Sj9F/58/0iDd1St1T21df6cyw12NrebQQLHXi7HsIH5leBuxH/wDC+9Yh6L03H6djuOPdZkPL25NhZcXNY20b6XtpHp+o7Cdtf7ff+n9P9IhZOL0mu/HZi9Ftyqbv523bltNQmPU2ub+nZsdv/RppyRJ18/liE1Wnh1kXo39ZwzZYW9a6eK3PyDW31iCGPDP2ewn3e/Gc237Q7/thclmV9bf1DPcy63MrsstdTk0lxZY2ym70jTZ7d9bbPRY3/hUmtrIE/Va0PL9pbuySQ3/SfRV+3o3Qfte/9mWuxTW8OnHzA5129ux8mPZ6Pqe399IziP8Aein7PtWwLL+n4ebk5lDjtfdd6b9vuDg12/8ASC1jv0jnWfpK7P5pBd9csICGYTGw3c5/6MFzXD0/8HjM9P32Nd+jT5NXTsJzDi4LhjPpuq+y2V3M9W95r9NnqWbb2+rTu/wn83Vaq1A6absU5HRm0Yz6y7IcPWeJ9/oVDdYd9O9tFjbK0PciNTrr3UT4gfV//9PmW/t39IWnIkgDUOjT6Mta3b9H6Hp/mKQt62Pa0XiyJcS2TEd/YuOSWWfa68H/ADWpr4vXOv6nJ3Nft13S2DJ01/R/up6HdTLnuLrGFxEhrSdB9HQs9ti5BJA+1Rrh/wCajV7Wy3qjg8WusA4durAP/Uf9/U6j1N1h9N1gP8kEGf7DGtXDpKM+3WnD/wA1Wvi9uLeqktA9YSIb7TMePta72IRyc8TDXEAkOPpwOPd6ns/6pcaknD2utf8ANVq9mLs5rpYPdGoYwF0H6O72f+YJ25Fxa1zht0IDX1s8vBn/AJguLSS9Hhf0Vq9vXdmOZtr+iXH6DANe8OFe3ck+65utrWOa2NwewbPLdptXEJJp4b6f2q1e+ozsSWi3HZJ4hrNTptiG7m/yFaZZiP3QysAfSEAH+1t/O2rzdJRzr9FcL8H0kPxw+am0usH0gI3En96NqcOa5m7Y1gIGgPtAHaGl7e681STFavpbnDeG2Bm+PpEdvm7cokWOESxoEemWeH5n0fp/nfSXmySIU+iPFW4k3VCxztG+lI4/6LvTURXjBzw2xhsO3d5Cf0cbQ1/9VeepJ2qPsf/ZADhCSU0EIQAAAAAAWQAAAAEBAAAADwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAAABUAQQBkAG8AYgBlACAAUABoAG8AdABvAHMAaABvAHAAIABDAFMANQAuADEAAAABADhCSU0EBgAAAAAABwAEAAAAAQEA/+EN3Gh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjEgNjQuMTQwOTQ5LCAyMDEwLzEyLzA3LTEwOjU3OjAxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxNC0wMy0xOVQwMzowMjoyNiswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxNC0wMy0xOVQwMzowMjoyNiswMTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTQtMDMtMTlUMDM6MDI6MjYrMDE6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMTg3MUY4MTMxRkI2RTY4OTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMTg3MUY4MTMxRkI2RTY4OTgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExODcxRjgxMzFGQjZFNjg5OCIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE4NzFGODEzMUZCNkU2ODk4IiBzdEV2dDp3aGVuPSIyMDE0LTAzLTE5VDAzOjAyOjI2KzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowMjgwMTE3NDA3MjA2ODExODcxRjgxMzFGQjZFNjg5OCIgc3RFdnQ6d2hlbj0iMjAxNC0wMy0xOVQwMzowMjoyNiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJPRklMRQABAQAADEhMaW5vAhAAAG1udHJSR0IgWFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAAAAABAAD21gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAAFHJYWVoAAAIYAAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALEAAAAiHZ1ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAAJHRlY2gAAAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRleHQAAAAAQ29weXJpZ2h0IChjKSAxOTk4IEhld2xldHQtUGFja2FyZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmlldwAAAAAAE6T+ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFzAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23////uAA5BZG9iZQBkAAAAAAH/2wCEAAYEBAQFBAYFBQYJBgUGCQsIBgYICwwKCgsKCgwQDAwMDAwMEAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBwcHDQwNGBAQGBQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIATYCtwMBEQACEQEDEQH/3QAEAFf/xAGiAAAABwEBAQEBAAAAAAAAAAAEBQMCBgEABwgJCgsBAAICAwEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAgEDAwIEAgYHAwQCBgJzAQIDEQQABSESMUFRBhNhInGBFDKRoQcVsUIjwVLR4TMWYvAkcoLxJUM0U5KismNzwjVEJ5OjszYXVGR0w9LiCCaDCQoYGYSURUaktFbTVSga8uPzxNTk9GV1hZWltcXV5fVmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6PgpOUlZaXmJmam5ydnp+So6SlpqeoqaqrrK2ur6EQACAgECAwUFBAUGBAgDA20BAAIRAwQhEjFBBVETYSIGcYGRMqGx8BTB0eEjQhVSYnLxMyQ0Q4IWklMlomOywgdz0jXiRIMXVJMICQoYGSY2RRonZHRVN/Kjs8MoKdPj84SUpLTE1OT0ZXWFlaW1xdXl9UZWZnaGlqa2xtbm9kdXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6Pg5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6vr/2gAMAwEAAhEDEQA/AO70YnNo6pqrA9cUO5v440rfPxrjSthwdq40l3IdK4KYku2wq0GI2rUYquDKDQgfPpkSGVr/AFSo+EkU+nBwp4nC6lIoW/DHgC8ZaMs/XkTjwhPEWxcSeJ+WPAF4y5rhidjQ48ATxFct01NzjwBeNY0rnrXCIhBkSpcpB+0flkqYEtCWQHrvjwhIkvFzIOorg4AjxFVL4jvTInG2DKrJqFRQ7jIeEy8VSlmDbBvoOSEUEoUlgadMtpoNtFm+nFRa0pKN6U8MKaLvjpu2+FC0hgRU7eIxVsueWxNMSFbaRya128MeFbcxFQRUDwGNJta5NTSowhCwnxJwsbW716nCriD44otbVgeu2KLXiaQH4TTBQTxFxdmNSanCAkEtFqeOKbXLJseu+DhW2jQ9zXwwsVypX9v78BLKlQRU/bGRJZBVBoKc8jTYHDlWof8AHBSEVbyUPxNlUotsSjVMTD7X0ZSQWwFr0oi1akHDbKlX01A61yNp4VJyiHfpkhugrFcNuv3YSGJXiQjtgISCqpNQg1+jIEM7VTdDtvkOBeJYZmY0yQim1prkqQSpujE9SMQqqkZHU4kpc23fAgqbSUB3yQDEyQ8lwQNjXJiLAyQb3NTlwi1GakZ98mIo4mjcLTY48LHiaWSp2bDS2rJKa7A5AhkCUQCxHSn05W2ArubKOv0YKTbYuvfHgRxLXuQcPAvGFM3A8foyXAjjUzOPfJCK8Sm0+S4WBkt9Qk0JJrhpFr1B71wJtplXxxWljcQP44QghT9Q9B0yVKvV/bAQtrmYH2xCkqbsabH78IDFYQw75JBCw07E4UKbuw6ZIBiSos57k5OmNrPWp4n6cNMeJYZHPenthpbcCfHFFv8A/9DvlM2Vuoa4jG1aKjG1aKA4bVaY/DDabdwNcVbo3hjYVaSRvhQ1WvXFXUxQ4DfFbVFlK9hkSGXE2bg9wMeBPGptID+yMIixMlnIV2JB+/JUxBbWVsFJ4my9R0xRxLSRhW1pY0w0qznvhAQ2j0PTAQm0QNxUb+2RLO2mZlWpG2IUlTaSuGmNtCVqUGGk2VpY4aQt5YVaL+2KLdyxRbdcNLa5pKjBS2tWjHfFQqmOMLWtTkbLKgosB2ybArMUOpirsVaIOFWhyGKrgTWmBVwG9anFILjTxwMrXKB3NcSoVUWMAb0r2yBZhUG26iv05Flbfr0Fa0OPDa8Tk1BlIqa4DiXxkYmo7eOVHE2jKpzXyuDko46RLIoJeLHuD9OTOO2HGu/SW/Xrg8JfFVorlm3B28ciYU2CdqyzHvue2Q4WQk01w6ipoBiIp410dyCK8qHEwTxhprhxvXbAIIMm0vPHpicaibbXKkbmnhgEEmaHeVSeuWCLAyCGmmNevXLYxapSUOa+OTphbXMN0/HDS2qJBy3ArXIkqIoqGxjG8n3DKpTLdGPeiQsXRRldkswtZB44VUJ+QHw5OLCSDkkl7jLgGokuSOVxUniMTSAFxQgGprgZUhZZWDEA7ZaItRkpCSU7DfDQRxFF20bFg7E/LK5FsjurTzKppWmRiGZlSibqOnX6clwMTNRe7FdhkhBici360D028cnwLxuW5IwcCOJxuiemPAjiWGZ69cPCjiWNK56tkuFBkVplbxw8K2saUnvkgEWsZmOLElrCxbG+K22KdPngSH//0e+ZsXUF2Kuwq1iyb3xRTsCHYq0Vr1w2q1o6kU2w8SrSrDCtNYUU7FDRAOKKa44qtpvhV2FLqnwxpacKU6Y0tLSBiq0rhtacBTClcrsp2ORpVxkLbNjSrMKrab1wq1Uk+2KGgN8VXFcVdTFFLSMKKdvihoYq3VqdcUupirZFDimnMvh0xQVmKHYq7FXYq3U4q6u+KurTFIK4N41wEJ4lVJlXod8iYshJbI3IeJwgKSohd/bvkmCKV4SoHceGVkFtBDYjhY05EYLKdkPPEUOxqMsibYSipZJrVlmYDbI8IZcS4XEnY4OAMxIrjPUUclsHCvEt9Q9jTwx4Vtf6zUoTtjwp4it9cjv9+PCgyd9ZenWmPAjjWtOfGuHhXiWGUEb7nJAMSVMk+OFja5AOtcBSEwsyOJPanXKJuRjXyTx9iT75ERbDIOW5Aw8CONv6yp2rjwJ4nGQHauPCtrCFPXphtiQGtgaYUFRmYAZKIYSOyAarHbvl4aVa2XiQSMhIsohG8lVdsrbkLMpkNa75OOzXIIWRQvf6MtBaypE5NDqjFFuBwLbeK24nCqw1rhQ1irRG+KrcKtjFFN7YFcOv0Ypf/9LvZzZOqcMUOGKurXFadXFabocCHYq7FXYq7DatUxtVpj8MNopaVIG+FaaoMUU7iMbQ0Vw2rXE4VaK064q1TDaXccVaoMVa474UtFSMbV2KtYVaIPyxVunviinUwWtOGKXUxtXUxtFO4DDaKWkUxtS6hwsab+KmBk0Sx64oa413GFFOKgDrv4YqtxVUCVHbBbKlvpv2GG0UuEZB+Ibd8BKRFeEtyNyQcjZZcIXxwoP2tsBkyEQi4ILd6cqHKZSIbYwCIbSLd0PD4a98h4xDPwgUJNo8iNVDVO/zy0ZwWqWCkIYHjNHUjLRIFrMCGmoPsj78IQs5k98ICCWuKnen04bRTXAYopw2xUFUDLTcYCyC5Xj/AJQcibZWF1YD7e2O62FkypQEEYRaJKDEZNrW7Yq3irRxVsf5jFVT15AKA8R4YOEMhIrDM/c4aRZa9ZvHGk24TNWuNKJLvXf6MeFPEV63L136ZHhCRIr/AKxQeOPCy4lJ5FfxrhApBWoorhRSulAMgWQWNLxrUYRFSaUHnZthsMsEWsyUyK9ckwU2rkgrsKtrgKG8CCtO/wBGSCQ3QnFVpBGKtYq7jXFWiKYq6mK04Yq//9PvebJ1JbwIdTFWqDCm26eBpitu59sCG8CuIGG1dTbFXUxVrFXYq7CrRUHG1Wem3jhVogjqPpxRTqfdhRTVBihxAw2rRG2Nq1TCrRAxVxXFNtU36Y2rRXDaWihGNqtySuwFXYFdireKt4q0cVb3xRTWK03itNbfLDaWiBhtFNcRja03tTpgSvWQjbrgIVt5amoFMFKsDkUwqCuaQt1A+jDSqkOzA7/LISDKKaQXDBQAajwzFlByoyakv6NxphGNZZEHNKHHX7sujGmmUrQcgoeuWtJWqVB3GGkWuafaijGlMlPl49ckAi1nNGYhSCV+0B2xYt1xV1cVtxbFVpJPfbwwrbWKuocVdirvbFXcW8MU0uCeJ3wWkBv0icbTwt/Vx442y4Vph8DhBRTRjUDrhRS0ca9cbTS4CppgSvWIVrgJSAvoAcFq1z7Y0tqErA98mAwkVLJsG8WK0qDhBVopQbYbVobYlW8CuxV2KupjatcRhtWivhjauIrhS1T78VcBvir/AP/U75mxdQ7FXYq4A98VbpgtNOp7YbQ44Fa3FMVbxV2KupXCrqYq1Q4q7FXYq7FVpAwppor4YUUtp9+FiQ7AimsKuIxtWqYbVrCrsVapim3UBxtK3hjatFThVricVdQ4q6uKt4q7FXYq0TirWKuxVvFWsVXBCae+NquaFgadcFppaSw2O4wodyH8owq1yatRtgpVwlevU4KTZbeQt418caW1nI1rhQ0aHrvXCEFYyjsa5IMGqYq7FVqRRoXZFCtIeUhH7RoBU/QMVtdirsVdscVaphVrFXYq2Kk4qiI7UlCT17ZWZtwxu9B++PEogvWBh+z9OAyTwuZHxtNKThhkgxJWUrtXrkmKrLYsq1D8iciJs+BDiFgx5ZLiY0qVAPTfFVrTN0AxAUyU2kbxyVNZKmzMd65IBbW4UN4ot2KHYq7FWqDG1dxxVog4VaOKuxV2KuxVsUxV1BhtXBN8bS//1e+ZsXUOpthTTYHvgWm6YFDgcUu2xV1MUU1XFadihvFLWKHYq7FNOIrhtDqYq1TFWqYUuxV3zxVoouG0U1wxtBC0imKKdhQ1scVdxxtLuGG1pbSmFDsVdtitupittU9sWTVBjatcffG1aIIwq1uMVaxVv3xVrFW6Yq6hwq2CVOBV4farYFWMRTbocKrcVdirsVbxV2KuIw2gtGv3YQxpojFadxHH3wrS2hxQ7FWn5BCVXkwGy1pU+FTirogWUErwYjdSQSD4VG2KaXEUPjihor37Yq4rthTSIt0RSGbK5lsjQR63MAHyyjhLkcYUXuY6/CPpyQgWJyBDtcsx75PhazkUmlJP8MnTHiaRHlNANvHtiTSx3REdooHvkDNsEUR6aEAM4FPHK7LZspSRwAGkgJycSWBpASEA0DZcGklTyTBawrhQt4nCrsKl2BFOwrTsVpviSKjBaadwOC1pv0277Y2tOKEY2tLaZJFNUGK07jitNEYVp1DitOrimm98Uv8A/9bvtN82NuqdvjauwK4HfClvfpgQ1vhV2BV3emKlxGBi0a4Vd9GKXYq7FDWKuxV2KuoMVdTDau4jxxtNraHCtu6Yq7bvitOoMUU1wHbG0ENcSMNrTVDirsVaoMKu4jG0U1xOG1pbQ4UU6mKtUxW3UxTbqYrbuIxRbRQY2tuCjFkuFKdMCLdhtDRFcVdTFXEA42q3ga7YU2tIOKWsVbGKt4q7FXYq7CimjitNcR9GFjS2mKKdTFXCoxV3XFWwK7V38MVDuIp1wsmq++NItqpxRbsVcS3Y4rblIHXFKpHMU6dMBDKMqae5lJNDQYBAJM1Lmx2Jrk6YEtHFCw1PXCrsKuxVsYpapvitN7YFcAtaHG1pWitufQH3yJlSRG0Utivfp4HKzkbBBd9Vjr8I+/BxsuAKTxKu5O2TEmBCHkK7gZMMSpGlDkrYLCD4YbVo18MVdhV2Nq1xGNpbAxV//9f0BTM91Tq0xQ11xV3HG1brih2K21QYrbqDFFu2xV1MUu3xV1MVtojFW6DFVprkgyC0++GkU2DvgpaXYEOocVdirVBhtXUGNq7iMbVojwxS1vhV2KuIU9cUU1xGK01xPbDa00a+GKGiaYVdsfnja0sOFi7CrhXFW+JwLTVMU07FaditOpitOpitOwrTsVp2KHYqt4DG1top4Y2m2uDY2tuoa0wpdvirqbYq7FXYq6gw2inUGNo4XYrwrSCR4YUUs3BwocScVdirWKt4q7FWjvirRGKtYVdirsVcRirXHDauK+GNq1QjemKXYVdQ4FVo1G1QMiSkIiN+PemVkMxsrLLXr08cjTO2nc9sQFtCylyp7DLAGuRQ9NjTc5YwLVKe2Nq6o7b42hxHjjaXbdKYUONAPDFVhpXDauGKv//Q9A75nurprFDsVdirqYrTsVpo4op1DiimqnCtN1ONLTt/DAtO3xWnYrTsU04rXDaQsK4bVuhxtVwpTIodTFFOxV2KupirqYq4jauFWqE9NxjaXe2KGiuG1a442lxBGKtVOFXYq0VBHTFVpSnvkrRS3jhRTfyGBacDU79MLKlSK2eVwqVNfuyEpgM447XvaSxvx6++AZAQyOIhs2rkUNB74PER4ZUzbSg79clxsTByW0jKWHQdceNfDLvQiD7knHiK8Kn6bA7KfbJWjhb9JiPi2xtBisK0+jDbAhrCh2KuxV2KuxW1pB+jG1tor4YbSC4An/PwxTbVD4b4q6h8MVt2KuxVqmG0ENcR4Y2imioxtadww2tNFcNop3A42imuJ8MVp1DitOKkdsbVqmKuC42rXE4q7Crq4q6mKtcRirXD3xtVy1HfAtrubdsaTbfqP44KXiLvWbGk8TYLNtTrhUFxiFTQ/RgtNLTFvvvhtaXJEa7dMBKiKobf+bBxJ4VKSIDY7eGSEkGKlxbwyVop3pt4Y2tO4GvTG1p//9H0MY2rmbbrStMXjjaCFpj98NrTfpjxxtaaKGu2K01Q4UNYq7FaaoMUN4q7FXYq7FXYq7FXYq1TFWxtirq4q7bFXCgxVvbFadTFaaIxWmt8WLqYq4jFXbYq4jw2xtNtFcIK2tIGFXYVpqoxVxI8MVpv0mIqBXHiZcLQA+kYsSitPl4ScSNj0yrKLDdikjXCOzVpXtlI2cjYqErcSVGWRYFCO78wT36jLAGqRc9x8HFdq9TiIsTNQ50NMmwtWBRAD1ORLMELZZgRsPnhEUSkoU2ybSWuOG0OpirWFXYq7FXYq7FXYq7FXVxVriuKtFfDDa2tNRim2q4pdXFXVxV2Ku2xRTqe+G0U1xHXvjau+P54ULa06jFXEjww0hscT3p88CuIGG0reIxWnccUO44VdirYXfwwFQGygAr1xZUtoPDFDa8DtT6cSoX7L075EslhDHocISuVXP0d8BKgKqCh75EskSSpTbqMiyUWUbmlThCCFIxnwpkrRSzgR0GESQQ4K3hhtD//0vRW+ZVuuouKnuMbC8Ja2HbDaaLVBXbG0UXcd/fG1orTGd8NppoIDjxKWim+2StFLTGcbWmiMKKaocUU6mK07FDsUOxV2KuxV2KuxV2KuxV2KuxV2KuxV1CADTY9DgtPCXYUO2xWnUGK01iimqYUuIxBVbxwpb442q6N+PIeORIZiWywg1675NrpyllNQd8BSFVJjy+I9e4yBizjNt2Zj12xASSpMHrU5MMStoK7jDbWQ4KOvTG0NcduuG0hZwamEFWqkYUU4EYKY03itNUxtDVMNq4jG1apirqHFXYVdirsVdirsVcd8VWlFxTbXp4bW3FKdMbW1mKXYq7FWwcVdih1PEYbRTRQYbWncBja06m42xtNONMUFrFDsNrTRUHG0U1xOBNLgMUrginrjaaaZD4fTjaeFeqFhv8ARkSUgKyxADYb5G2XC7hJX2wWmm+mNrTccbkkgYkpiFZYRWhGQMmdNvAOgxEl4VJ4CoyQkgwUinxDbJWw4X//0/TKop6CmWEtFNlBTxyNp4Wgu5/VhtFOMMZ+0BXHiKRAFY0KdsIkgwWG3WlRucPEx4VMwSdKD55LiDHhWm2lUVp065ITDEwKz02PbDbHgbFuxHQU8ceJeBY0TDthEl4Vvpt4YeJFNGJvDDxLwtGI+GNhHCtETnoK4bC8DjGw6g42EGJW/hhRwl1DiinUOKuxV2K06mK06mK06mK07fFI5owEulCKjwHbKXI5oedVVqAUp1yyJtomKU8kxccVcKk7Yq2QQd8bWmiMbWnYq4D2xWl6qgUnjvgtnSwr9+EFjTXAnpvhtNN+i3hg4k8KosRO1RgJZU36Mf7Tfdg4lpaRD0GIJQYhYUU9MmCx4Qs9L4tj9GNrwtFaHbDbExW0PhhtFNFARhtaWhD44bY01uO2K02AT2xRTqHwxWnUPhja06h8MFrTXH2w2inccbWncR44bWnca42tNcDja07icbWncTitNYULtiBgVaUr2w2lrgMUOMftjad1vpnxxtLuB9sNq7ia42i2qHwxtNthSTTpirRFD44q1htXUGNoprjhtadx98bWmwMFrTeKWwCTgVU3GBkFwpTAleCQP14CkFdyr8sDINV3xVf6tBQCmClBWCY8t9wMeFPEiFlDbnbI0ziWyVI64KZWsKpUYbYv/9T0wtRXw98mWndUqDkWVtcPc4qQt4gNuaYSUALqL41yLJsBSNsbQspvQ4rTiCVI8clFiVojWvSpw2ilxjU7FdsFp4VrRLt2w8SOFvglOmG08KlWgPw4bYkOEXJSTsMeJHCpj4PnkrRS5pqihGIVYFVmqV2w2il4gjJoB88TJPCHLbRk1pUYONeANGONagIB74gqYhSdI+pJH0ZMFgYhr6sp+yTiZrwKq20NNwa5HjLIYwse2i5UrQ+GHjKDjC2S2jH2WwiZRwNrG4Witt4YCUiNKbwyHrkhJgYkrDA4FcnxMTBaUI642jhbSoOKgKwNRXjUnIM1jCpJbt0GEFipld+mStFKiRilTvgJZCKoANi3TrTIkswKcyKy1ApgBVuOJQWI6jpiZJAXJFUEtgtIis9Msx8cNopzxKF64iS8KgyEdAcmJMCHem9RtthtABXeltv18MHEnhU2+E0OSYlaXjPVakYQq0lfDCxaoK7Y2vC2VPhjaDF3E1xtFO4Y2oDYjwWy4Xelja8LvTOG14Wiu+NseF3EV/hja03QY2kh1B442xpoqK42kBsqtK0xtaW+mnhhtHC2I17Y2vC16Nehx4k8Nti3wcSRBVEIYU7jBbLgWmzFNsRNeAKMluyioyYk1ygp8WHY/PJWx4XHG0NYq0VBw2rRVRtTG0tEJhtVtBXFXfPFXbYq7FXcj22xVcHPfAq/4O4wMlwKjrX2GKVQfhkWYab2xtBWqW79MKHbV6YqqI4p0yJDYCu5kmgwUydU1rTFX//V9OEE9BiwaCV69sNrwl32Qe+BaaLVyVILW2AoC4FR0xoptx4k74EtgDFQFoWh64qV1AtTihaaHFLioqPDFW+FenTFacVoMILEhaUFKU2yVopZ6APsMPEjhXegtOmDiTTloCRvv3xRTgAuwwEshFzKCNxjxLTXBOvHEyKeELgo8AMILGlwA47AVwFkpmNC3IjfHiY8IaaJD02OESUhrgAaGmStjTRjLDYAe+G00ta3NOuIkxMVH0SOvXwyfExMVhFDuuStgQ4EV6GnyxULvgPiD3wJpaAK7YSildFFNup6nIEtkQvKAilBkbLLhcsagHpiSoC4QioPTAZJ4W2jalB0xtPCp+mVJJ6HDaKX8ErvgtVjqrbDYeOEWghUCxKKAVIwWUgKbx8vDDaCFwtIK147+JwHIUjGFzwQ03UDBGRUwCg8EfbY5aJFgYLFgUGvUfjjxI4XNGKeGESUxUmgr0yXEwMGjEqmhOHiXhbACntjaab4BgSMFrS0xN4bYbQQpvGR16+GEFjS0Jt4ZK0U6gG1cUEN+mp3BwErTYjXxONp4W/RT+bBxJ4Q4hR3xVaWQDwwgK0HOGkO9VhjS8TfrsR0x4V43eu2NI42jMx7bd8NLxLeYJ3xpi3RfDbFVpCfy4bRQWmNCfDCCtLTHTDbGlhQHww2tNemO+Nopb6a+Jw2rvTHjjauCb742rYUdsVdTFkAuBGApVBTrtkWQVFZQCQBXwwUya9TfoMaUFolSOgxCdmggrXavjhJQAvAU5Hdku4qNxjuydXAh//W9OBx2NMNNdrga98DMFo4qWiAaY2xU2AXYfCPHrkgWBDlJ7MGGEoHNsUrkC2NsjHZfvwimJU6srfEemSACLXgqR12wUkF1U6Vx4U2vFKbZFVwOLIFpqHFStKjthtjTRBxWm+LHAmmgp77YbRwt8aYFWk7dMmi2lNe2K8S7I2l2JKttTjgVbXY4QgrCDIcmxXqhUUwWycVr1OIKFJkNaAVOStFLghpja070z36YLQQsENRU98lxIoLvq0fQCmPGU8LvQoaqcHEngWksDTCFLW1cJYhes3I8enuciQyBX8qbE4E2uBU9KHBRStKVOG0LTEw6HHiWm0U/tfRiim+C1674pAXgVyBZguZRhDEhRZAP2voyYKC4RFtxSnjhtDfpIDVjXBakKbIO2StBCm0ZO9ATkrY8KwxnuKZIFHCp8itRTChcHNRttjSuKqevjgQQtEan3w2jhd6KHxx4ikRbMFB8OG08LRRu+/vjaCGuB8MbRwrSntXDaOFaYmOEFFFr0Gr1pjxI4XeicbXhWshGEFBitNfDCx4S754UU4jFVtPfFLRLYULanGlbq3jhCtYVaqBihojFWgDirdMVp1Dilvgx74rTXpsMbTTY5dCMUN74pdyI7VwJbDOdgN8BSF4DE0pgtmAuMeC002kZPUYLSA36e+Npp//1/ThRD1yTCg7ilKdsBSuAFMCWipPQkYqQt4t41+eKKaoR2+7DaKcFB6jAtrq70ofnihorXvhtat3DtXG08LXoDxw8S8K4R075FPC3w98VpumKadQYrTXHeuK07FIbxUhaQT2xYOKjFFO4g4bWmqHCpao3bpkUt8SepxVpkNCMIQXIpB6YSVC/IqspQ5IFXVI7bYkpa3yNrTitevTCCxpb6fauStFLgtNq1OKQ4A1yDJxWo3yQLEhaIkrk7RTjFTpucbWmgxA+JcCFM0rsTkgFbSdgadcTFQVQyq+335GqTamVABwqtHINWu2SKFQF6+I98iWQVRWm/4ZFko8QzkE7VybFc4VRQbnAtKYAJ3JwoXMi02NcbVbwP8ANjaKWtEx/bwiSCFpi+HZt8lbHhWenJXDa8LXFgdzja8LZ8fxwsXAqTscUhs08d8AZW1vSuFebt8UELeGLGm6HtitOp44q7FCw9emSBStNPDCCgtcVPUYbY0704/vxteELTGnhjaCGjEpxteF3pJh4l4GjEPCuIkpgpmHfJcTHhb9Hxx4l4WvRYdseNeFv0tsHEyEWxATsMeJPA36DDtjxLwLvQb6cjxLwLhEwFKY8SRFv0h4YOJPC70RjxMuFxQDalcHEjha4ivSmPEinBRhtk3t0xVokdsVaB3rhV//0PSxcVpTbLGq2hKFGwpjwoBXLMO+AxSCvEynvTHhZW36ifzYOFHE7mvjgpbb5CmCltvDS26oxpILq40m3V9sC26vtim2wCdwDituofA4rbdG8MUWlPmO/wDqukXUkdwIZ0C8SCvIEsB0PzwgIJSZfzJ0c/8AHtcj5hP8nwb/ACsPCkFd/wArH0jvbXP/AAKf5X+V/k48KeJ53aT+Zh+e9zGJ71dNe8RBCJHMHpekWYcalQhPtk5DZqxmyXtGo3sdhYzXkykxwIZGVaciFFaLWm+V022x3/lYujVA9C5qTTZU/m4/zYeFbCYaL5r0/V7praCKWORY/UrIFAI+HYUJ3+LAQtpyQfDAxbofDFDqHwxVrFWmdVUsxAVRVidgAO+KoWy1jSb8stjeQXTJ9oRSK5H3HGlRVSain04q1xxVdiq1hvilbUA0yYVeK0yJQtNe+EBXChNe+FLTmgwsStCVFSTja0taPfbCCpDvRPj9GNsaa4EbHG0tqi1rU42mlxVR742mlveo2xVvk3TApWFO+G0U7iR0NcNoWkPXbDau+OtMdkN/Ecdktd8VdhVpq9sUO+E9RihaeBxBQt+DwyatHjirTNGiszGigVJ8AMBTEXyUbO9s763W5s5kuLd68JomDKaGhoR4HG2UokGir9MbY01yxtBCncXcFvbyTysEjjUu7HYAAV74krAGRpLvLfmfSvMOkrqencxbPJJFSQcWDRNxYEVOIDPNjOOXCU09SKngThprJWkJ442imiF8cIKKa4EnbfDYWm/TfwwcQXhbCHHiWm+D+GDiTTQVxsRXHiWnen3OPGvC2IxgM08LZT2wcS8LqbYeJIi1THiWm8HEmnDDa07Da00dsUU0WAGKrSzeOJKGjkUU7DaKaJqMbULcmCloncZJX//R9KmJvCuW21Ut9GSvTDxLS703Hvgtaa4N4Y2rRjbrTG0UtKMD0Iw7Ip1XHjirhz8ThoK7kw/aI+eCkrg7DviQm16zEHepwGKgrvXXwyPCtvD/AM3PMF/ZecjDbahcWq/VoiIYp3jU1rVuKsB/ssnRaZTNlg7efLtaq3mCUMmxBvnBJ8P7zHhLHjK0efL4gf8AOwTUPU/Xn29v7zBwpEyh7rzLHflhPqf1l5RxIkui9VHahfHhWyprd6epqXXbZf3rbn3+LBwlfEXC904bmdTTc/vm8On2seBj4hRMfmIR3hu49QaO5O7Ti5YP4btyr9nDw2mOSl195vmvIPRutWlmhYgmKS6crUdCQWw+GviFAfpHTBubhNj19c+P+tkfDUzKIttct7WYT218YJlFUljuCrAkEbENjwJGQo7/AB1qtR/ueuCT4Xj0/wCJ4eBPEWv8dasAD+nrkEGh/wBMf/mvBwrxFtvPWtcSRr1yPA/W36f8Fh4UHIzj8sPzssEkbQvM2oAAMfqGpzEmvf0pX35f8VSftfYbIyjTdGVvRb78wvJK2cx/S0MgZGWkQaRviFNlA98AZEGnjH5X3+k+ULrVdSlmBufqbrZRmFvjlqCqnhU9viyRkCURBAe8eU/M1l5i0SDUbd09R1UXUCtyMMvEFo27qd/2v2cr6sqTmorTJUha1K9cFK19O2GkuPHvhVwdR3wEFXcgTirRemGlWE1ySLXK60pvgIW1xYUqN/bGlWl2+WKrTyJxUhrcYUgNlvHAlbXCxJdUDFi2DXFmGicCC1yOLG3V3xQ6rHvhtVtCOuStLXIg79MbVsMuRtUu1nWYbFRGgEl44+CPsB/M/gv/ABLAZKA8nvfOXmmK/njXV3ASVlVOMWw5dKccnHcW0TO6kfO/mwhv9yz+3wRf805JjxIe380eYbaQNFqsoJBJ5cWqfpBxXiXXPnPzRNbmCXVn9OUFZAFiWqmoIqFr0xSMpBsIbRvMes6Hpy6dpeoGC0iZnjiCxsAXPJt2Bb7RxTPNKRs80ePzB82cj/uWqKd44a/8RxphxlY3n3zY6qDqxHLrSOIH7wMFLxlTufOXma5sZLW41ATQP8LBo460rt8VK1wkWoyEGwh9H8za3osEtrpt4sEDu0pj4K9ZH+03xct2xplLNKRs80dF5983pTjqfLkKnlFG2/tUYsfEK7/lYPnUCv6STc0AMEX9MFJ4y4/mF51PKmoq3EV2gip0+WFfELKPy+8069qusTW+p3azQrbmSOMRpH8QcCtVFehwFMZG3oBcUyNtyFs7uWa4u45AFEEiqg6mjRq25Hu2ElF7oqoyKXVGKuLDFVpbCrRceOHhVrkMaW2ua48K27muPCtuDjGkN8gemHdNtVrjurXLbtjZVpmxCreWSVrkcUFrFDVcQruW+HiV/9L05y9sm1u5eIwFXGhxVbTGldQYVd8sKuIJ69MC0tKeGG0UtMbeGG1poxnDa0tKcRVjQeJ2GNoSy98yeX7JS1zqMC8dioYOa+FE5HGwrx/8wPO1tP5wgu7HTry7t4LFreRxGqUb1udR6jLVSoy7HkiBu42XFKRNPOtJ1+Wzso7ebyWt5KXlcXDiDnJzkZ6nkjHYN/NkjniowSoBCW+rSx+ZbrVm8nK9tNbx2qWdIOKSI9S4+DiS32dlweMEjBIAphda8Z7i09Pyd+jzZ3MVzNcQi3LhI6kj4VT7X+tiM0UHBJkX+NlJVf0NfcmFQPTi6D/Z5MZ4NfgSKyy85QpbKraNfkl3AYRxEEs5O3x4DmjaRp5UoXvm23dpz+h76noNExMcWzFgez+GP5iLE6aRVv8AFmnFuJ0W/rQmhhj6f8HkhqAv5WSna+brKNX/ANw99SaQvFSGPcFR/l+2A6iKjTSCWeY/MlteSadLH5fubuKzuWkuLeeKJUflE0YHxFwSGcHpg8eLKOCQKW6zrEF5pd5aQeSfq08sLIswS3rGWBAf4UB29sHjQT4E12laxbwWFpayeR/XmjhRWkKWxLlFAL/Eld/fEZoMjgnfNUh1T/cFrtpF5fubaXU3m+qwQxRGNDJEsaryUqPtKa0XD40GB08zTHNC8u+YtP1fTJUsZv0fzBlBFTbuq1NaVojncA5hznYc7HGnr9hqUtOJJBWnXrmPbkBN4b3kBU7+NcKkK3lbWJ9E8w3l81lPcWtyhT9xJGOTVHEujsu6Ubif8rJxlQYcLMP+VlQU/wCOPe7f5Vv/ANVMPiBh4Tv+Vl25/wClRfD6YP8Aqpj4oXwnD8yLev8AxyL6n/PD/qpj4oXwy5vzItyf+ORe/wDJD/qpkvEivAWx+ZFt30m+H0Qf9VMfEivAVw/Me17aVffdD/1UweJFeErh+Ylt30q++6D/AKq4+JFeAt/8rEsx/wBKq++6H/qrg8QI8Mt/8rEs/wDq13w/2MP/AFVx8QJ4C2PzCs/+rbe/8DD/ANVMPiRXhLh+YNmf+lbe/wDAw/8AVTB4kV4C2PzAsq/8c69/4GL/AKqY+KF4S3/j+w/6t97/AMDF/wBVMfFCeBo+fbE/8eF5/wABH/1Ux8QLwFr/AB7YjpYXn/ARf9VMfECPDLv8fWB62F5/wEf/ADXj4oTwF3+P9PA/3gvf+Aj/AOqmPiBPAWv8f6dXewvvn6af814+IGPAW/8AH2mn/jxvf+Raf814+IF8Mtp570ok1trxKeMa/wAGOHjCOArj520kn+5ut/8Air/m7HxAjhLX+NtKB2iuf+RX9uHxYo4Sv/xxpQG8Nz/yK/tx8SKeEpXL+YF0LidUsZDAVAt3KioavxFhXf4dxlZyMhFh3mTzLczapHaQLPZ2twvK91RlVpgBUFYkr/eN/vw/DH+yuRjKymQoPL79fL6ReZ7eDS7hzcyTHTJJLSWVyrQhVPqlSwPqAmpb/KzaYZxEaLrs0JGdhFQ3fkQRxiTy5NzCryP6NY7gUPbxyZnBr8KSD0qfyZCl0Lvy/M7PdTPATp7vSF2rGvTbiP2f2ceOCnFJfb3Pk9de+sJo0sNn9UMbK2nyAGX1QwPEI37H7WEZIsTjmmF3qHk028ippjcyPhpp0o7+Pp5LxYI8OaodW8iVr+jyP+3dL/1SweLBBxzQkeo+ShOhfTyFBmLE2EvRmBT/AHX4Y+LBfDmvvNU8jNbSrHYnmV+ECwlG/wDyLw+JBPhzVf0p5BJr9S2r/wAsEv8A1Tx8SCBjmk1ld+RkmvzeaVLL6l1I9vILKYj0SF4gUUUoeXw5EzgyMMim9z5F/TaSfoiYWP1ZlkT6nPT1ualTxp/Jy+LETgvBkXajdeSZI7b9H6TNFKl1A7t9TnUeksgMoJI3HD9n9rESxqY5KZ9+WvmfQtL8wawtjp7kX0NsLd1iNvvH6nqAGRV8UJplGfJHo3aeEhzelN59pT/cbKT3BkQZjeKHM4Cg4POZivLq4OmyN67IygTJsFjCGo6dsfFCPDkzGxujdWcNzwMZmRX9M7leQrSoyfNirBxTqMaUF3PDSkrSxxpBaLYVWlziq3kcKu5+OKHcjgS7mfHCttFz4/RirXP54q7meldsaRbRfDS2t9UdsICLd6mPCtteoRh4Vtwkx4Uv/9P0h9YfLaaW/Xf5YeFXeu3jjwq16z+ONJbErHvh4UW4zsoqx4jxOw/HBSbS+880aLZsEuNQhRz0jDhnNP8AJWpxoMeJJbv8y9DiD+iJ7gJsWVOC18AXKk/QuOzLdJ7n80dSccLOxjhciv75zJwX+ZuPAf7GuAkLwlJ7vz75nuWBF4YYifgSBFRpDTsSCwT6cjaQEnu7+9uWdrm6llb/AHdK7syr/kICftYCWQih1DLxVECsBWKM9EH87/5WKUNNHGwqQXjJ6/tTP/zT/n9nBa0oPaqWerAOBW4lGwUdQi/5/wCVgQpfVB8BVAGpS3j/AJR3dsUtfVIgu45Qqdz1Mslf6/58VxQu+pkllLAMRWdx0VR0QH/P+bFQG1tmqhVeLH4YEp9lf5iP8/5cUrGtUAO1YYjuepeSv47/APD4sW/qRPJD9t/inYdFX+UYUgNfViT6oFGk+CBT2X+b+P8AwOBabNogHSsUHTxZ/wDM/wDBYopv6hUiJ92f95cEeHYfLt/qriq9Laqc12eY8IvZfH9bYCkBVEEMdWUfu7cUA8WIw2mkRbRMgSIn4z+8lPvXp9+ApRHMsvJqO0r0jBFaDx+4VwUm1dXhXm1Cqx9SN96VpQ5HhZAoqKVKhQwLEV49DSuKbRMcjDr9GAhKus46UyBCCvV1PhjSrgwHhjSF1Vr2xS3QE1xpWyfAY0ri46HbBS24v02xVxcg0AxV3InxwK3ybrTfvgVcCepHXCq0nsBuMbS2Q1B1wq6jdxirhy32xV1SNqbnFDRJA36eOKtqCy1p1wrS4J4jFFBTkuLSI0eQBv5Qan7hiIkoNBDvqQp+6iJ3pyf4R925yYxljxISa5upK8m4Ab8UFNvmd8sGMMeJDyW6nelSw2Y7n7zkqDElDGI0qdwdmwoIWG3alPD7J8R4Y2ilv1XwNFY1+nG1pY1qxPIncfCflimm/qrmq19x742tNC2NN+/68Fopr6sw69R1wgrTTWxI2O3bCSimvq7bD7t8bWnLCwqKVJO4ONqu9HerD4um/fBa0u+rg9uhw2mkTbx8eYPtWmC1CKDSrTix+/Y/24KDO1wnJJDAH36ffTHgTxKbPqFWEV/cRRtsIlIYKPatNssEyOTUcYJUVtb5hQ6nJU9mUD8emPjS7gvgjvRFuuv24b6vqc6q3XhSn4HIHNLuSMI70Rb6n5mt5RJ+lppOP7EoV16d1ORGUsvCCL/xR5oPW8i9v3CYfFK+EHf4n8z/APLXF9MC/wBcHilPghr/ABP5or/vXFT/AIwL/XHxSjwR3t/4m8zf8tUR/wCeC/1x8Yr4I72v8SeZv+WqE/OBf4HD4xXwR3tHzL5prtdQ/wDIgf8ANWDxivgjvTmy1TVZrWN5blfUI+IrGoB++uUS1EmccIVWub1lNbtx/qhB/wAa5H8xLvZ+DFU0Kad5r9ZZnm4SqI+ZrxUoDQbDvmdpshlHdxM0QJUE155ktTueKtcjhVqpxVsE4LW3/9T0VRa7A5bbU2DthtDq1xtW6YLV5V+c/mfXNMS3j0fW4raK4SSOe2REkkDJSp58uSHfpTAS1E+p5W3nDWpggur95SCSQ5LAkbAnkx6DI0WziUh5r1GkgFx9pvjbiAaV6LQ7bY8PmnjLl84aly5GZQQv7peI4j3pXrjwp8Qr28z6gvGM3FVryc8RVjT9rfBwr4hbXzRqTiQi54yN8NeO6rWnw77YOBfE8lx80agsvH1xxiX4F4ClT3Pxb48HmnxPJYnmrUWVUNz/AHh5THgKnatK8unbHg80eIe5z+adTAlmFyOQHFBwFAKdhyw8PmnxFh803XKNBdDgoLEGMVZtqcvi38ceHzR4nk1/im+KPW7XnI3xsEFQtaUHxbbYBDzXxT3NjzXe8uXrp8C0iX09hXvSuHh80DI2vmi9CIhuFKk8pSU3JpWh3wcA71OU9yofNF+VaQXK+o5IrwFVUDbjvjwp8Qt/4oulkUfWF9OMVUcBu3TffHgXxT3NL5ovDGAbhayNWWiCtK9OvTHhXxGx5pvCZpBcJyA4xDhsBStevjjwr4ionmG6rEhuVKKCx+AVLCnXf3x4V8XyXJ5gvJI243K85Xp/djYVpTr4YOFHiFuXXtbE5EMkDFCkSh1IHxhmJ25fyYCyEyrx3XmMxxj6zaUryaquST1328cCnIvN75jHqn61acjt9l9hTttjunxAq/W/MYkX/SbMBFoq8JKdvpx3XxFovPM3pgG7tKM/I/u5Kn4sd18QLjf+ZQ8h+tWgJUAfBIaUrgT4gcupeaF9JVvbYBVNBwkp0774r4qFbz1q+j30Lau0M+nyzenPLEHDxq2/JVPw8V/a/wAnHhtMc1ml+s2MVxr2oXtx5dudZt7j0TZ3UBRk4LEAwFZU/a/ycyMU4gbtWWEidkjvdBebVtOntvKN/FYQmU30Pwgy8lpGKetvxbfMjxcbQcWVV1bQPW0u6hsPKOowX0kbC2mPEBHI2NRMenywHLjQMORFW2jWyWsKS+TdQedUUSybfE4UBj/fdzg8bGpxZUJpOhTW8moHUPKeo3CTXLSWQG/pwFQAn98OjcsfExp8LIjbfTHTUTJb+W7+zg+pzxMHQvymcqY2A9R/sgN8WHxcaDiyLNN0eIWdvFd+UdSa4SJFnlox5SKoDN/fD7RwHLjTHFl6lB6fod5Deag115V1KWCWcPYp8X7uLiBw/vdvi3wjLjQcWVu90K/k1Owlt/K+px2MRkN7B8Q9QMlE29X9lsfFxKMebvVdT0a7l025isfKuqQXbxsLeX4gFemzf3x6HD4uJRjzd6KttKpawJN5T1Z51jUTOeW7hQGP993OQGTEnw8vehLrQNYk0xIV0PUwv195WgTmkotiDxX1BJ2NPh55bHNhHNicea9ig77ytqTaZOln5f1yPUGU+hK9xMURuxI9Y1/4HDLLg6Moxz9SmcGlzJDEsvlbVmkVFEjAyGrBRyP993OV+JhYnHn70Ho+lX8UNwuo+W9Xmla4leFlMh4wMR6aH96PsjHxMTLw83eqw6Lz18y3nlzXf0P9W4pbwSTRuLnnXmaTD4eG32sicmLozjDL1TVdL0lLzT5NN8u+YLaSK5Vrp7t55oTBxYMpjaaQMeRX9jBx42RhMhNtTLTzejp8EltJEgZ/rCSRKpDBh8NRXkBgOaPINZxz5lDwzeYImXi9uaDYt6h+ffKyLT4pCoup+ZlVTztRU/ytjwr4pd+lfNPxnnbH+UcW8K48JZeN5O/Sfmv4avbe+z74DEo8YNHVPNXpseVtsaDZ/ltjwp8Zr6/5oJofq3TcUbHhScvksi1PzMXX1mtxGepUMWr1HWm2SEGJzeSJ+v6uWaksR8AUPWnzw8CPFLX17WQF/ewmn2vgP9cBgvilo6hrQr8cNR0+A9PvxGNfGLf6Q1jkKyQhT/kHr9+PAvilr9Iazx3khqPtEqen34eBHilpr/WKmkkQP7HwH+uPAnxStbUNX2PqQ8f2vgPX78Hhr4pa/Ses0PxQ1rt8B6ffh4F8UtnU9XqPigp1Hwt1HXvg4EeM1+k9a415wV/a+Bv64eBfG8m11jW15ANBUfZHFv648C+KVzazrpK8Wh413qrf1wcC+M3+mNc6MYOVd/hbp9+HgXxW/wBL64K0MHT4fhb+uPAnxXfpnWqDeGnfZuv348C+K4azrgqawV6nZumDw18Yrhr+v1+1ER+zUMa/fg8IJ8cqcmueZA0ZjitnRfthi61PgaA4DiXxykt7+dXl/S7mWx1a2uRfW7mOcwRhouVK/AzOCdjkfDLkRnYUP+hgPJH++L7/AJFJ/wA14PDLLicP+cgfJHUwX3/IpP8AmvHwyvE3/wBDBeSP98X1P+MSf814fDK8Tv8AoYHyOTX0L7/kUn/NeDwyvEHqnk/zBZa75cs9WsuYtbpS0YkAVwFYqagE9xmHkiQWyErCecvDwytmraEQLvUVP88TfembLSfS4Gp+tOPh8czQ0tbeOFWiQO+BLXIU642hoEeOBX//1fRu3t92WNK2q16YFd8PvirvhrtiryPztqHkzSdfuRrklnZXFwxlQ3KorOh25gkfF0zGyA23YyDskI82/lV/1dNL++L+mV7ttBcPNX5WOKDU9LPtWP8Apg3TQcfMn5XGn+5DTPpMX9MbK8IcPMX5WHf9JaV/wUWG14Wj5h/K7/q46UK9+UWNp4F36e/Kv/q4aV/wUWNlHC79N/lZT4dQ0o/7KLBa8DY1n8rKf73aUT/rRY8S8K4av+Vlf97tJ/4KLDZXhC79LflbX/e3SfnyhxsoEQ2NX/K3/lu0n/g4cbK0Hfpf8rDWt7pO/i0OC14Q1+k/yrp/vbpIH+vDhtPCHfpL8qD/AMfukf8ABw4bRwhv6/8AlVWv1zSNv8uH+uNleENi/wDypJr9c0in+vD/AFxJKOENfX/yqr/vZpFf9eH+uNrwho6h+Vf/AC2aSP8AZw/1xteENNfflXwbheaUTSnwyRV/XiCVlEU8R/x1f2d7dWlusMlrDcSpCx5t8CuQu4bcUzYwxAh18juiofPupPyHpRHl12f5eOW/lwWHEih501djX0IunQCT+uH8sE8a5fOepHb6vHtvWknjXxwHTBHEuPnHUSSfQj8NhJ/XB+V81E3DzfqWx9GPbYDjJ/XH8r5rxpp5VeDzHrcVjq9vG9pR5WUGRDyAAHxE++Y+oxcEbb8FEvVrfyxotnZiC0mnggiUrHGly4CjsAKnMK3M5KdjdSFzbXBrc29A7dOan7MgH+V3/wAvlhSmAlFD74oXrIcVXJP2IrgWmzcrUVNB74rTRv4lYBmAG/fFaXPfQ0DBxU/LAtLF1FQ9GIp0BwJpVW/hJpyH34rRWm/QkgMKAb74rTZvohvyArv1GC1pqTUYwh3BNN9xja06PUYyCAR7bjCtL0uot/iArhWl3rx1FWrXYU3JJ6AUwJR2r6BNaWlnNcyyRXFxzJiRuIRQAQD4vv8AFhDEsQ8y2sWn6Hf6hbScrqJDKObcwxqK1HU1GWwu2udU8wHnjWBT9xbmnT4ZP65ncDr7aPnbWCB+4t69fsyb/jjwIto+dtbqaRW4rt/dvt+OPAkFy+dtaotYoHC9Ko/8Dg4Ftsed9YANYYADufhkH8ceBeJUj8+6lUco7Y0H+X/XAYM4m3p+n3HlWTyzod3fvZQXl5bvJMHlVWLGZwuzty+yNswjI3TmCMatUD+S6/70WX/I2P8A5qw3JeGHk4HyYynjcWTAbAiVKbbdmw+tHDDybY+TQByuLJSTQVmjFT4CrYCZJEYt8PKFP7+zr/xmT/mrD6kVB1PJxr/pNnXoaTJ1/wCCxuSeGPktc+TVoWu7JR2JnQfrbG5LwhsjyeaEXNmQe4mQj/iWNyTwx8myPKFafWLOvgJkrT/gsbkvDFaR5QA5NcWYVdyTMlPxbBckcEfJ1PJ53E9mQe4lTp/wWSuSKj5NV8oA0FxZhvD1krT/AILBck8MfJph5PVam4swOpJmQf8AG2NyXhj5NKfJzDktzZsOlVnQ/qbG5I4Yt08n/wDLRaVPQGZKn/hsfUtR8ncPKVf7+0r/AMZk/wCasfWvDHyaX/B53+sWZHSvrIf+NsfUioNcvJwIBuLIHsDMn4fFj6k1DyWtJ5NA3urMAf8AFyf81Y+peGLyr897TTb7TNH/AEE0N0yzSmdLWRHoGReLNxJ+/LMPFe6ZcIDx0aBrPT6nLt7Zk008QcPL+s9Pqclfl/biniDX+H9aPSzl+4f1wUvEHf4f1v8A5Ypfuw0vEH1J+SE4X8v9PsZCFvLT1RPb1HNA0rsvIDpyG4zW6kHibsB2Pvegh/vzHb1XRWA1C/Feqwt+DDNjpD6XB1P1BOua065l7tDRYUxStJHjitNcl8cVpoOK4Vf/1vRQ33ybS3hVrFWiK9emBXy1/wA5TRrP52tI2Ab09PjoG95HO2XCNhx4mpF4RNpkdSAAD7YPDb+IojR9Mpec6qypx/Fqd8HCAVMjSZzQr9SmAQE8P5R+zCxOW8IabNrorOGOwt1MSsWiRuVB14n/AJqyMQGUpG0MLW3bUg3pr8KoAOI7sckIhHEaU72K3GnykIvLiQCFAp8Z9sJiERkbZr+TP5d6N5lsdSur6KSVoZ0hhCMFH2eR6g+ODHp4S5ss2WUapm3nr8lfK2jeTb3V0SRZ7cwmNXdSvxzIhBHHwbI+BAHZgMuTa2Zw6PpCQLGtjbcVUKv7mPoPoywANc5G1HTtL0r6zqBNlb0+sAU9GPtEnthIDGJNMb/NzTtMh/L7VpYrOCOUCLi6RIrCsq9CBXISqimJPFH3vmPMN2bMfyxsre485aGssSSo9x8aOoZSArGhBqD0y2ADVM830suh6JX/AI51p7fuIv8AmnMkAODZS3Q9G0c6ajfULY8pJjUwxf7+f/Jw0EAlKta0bSW86+WkFlbhCt8zqIowDSFaVAXelcEwKZYzuWS/oHQyP+Oda/P0Iv8AmnHZBtL/AC5o2jfosN+j7U1nudzBGTT6xIB1XBQTZoMG/PjTdMh8v6Wbe0hgdrtwWijRCR6R2PEDIkAs8ciJPUPy6sLNfI2ggQRD/QoSfgXclak9O+V2me5YD+e8MEd/owjRErFOTxolfiTwzIwcmrq8yQkftCvs5y9krrNtvx/4M4oVFlQmnJQf+MhxSvDddx/yMOBUs8w3U1vZLPC/F4pAQQ5NdiKEZj6mNxbcBIkhbTzdVAXnKN0IJIp+OaiWEuzE2V65+ZQ1Xy5Y+ldtHrllN6UskTsrS27KaMeJFfiC8v8AK+LMrTQ33aM8ttkrh8z69IARqF1Sm/7yT/mrM/w49zh8cu9WTzJr/bULr5epJ/zVh8OPcx8SSw+bNaUkfpK5quxo8h3+hsHhx7k+LLvZh+WPnHQ/rupf4t1RFi9KP6mL6Rqcizc+HIntSuYmoiARQcjDO+b0NfMn5Skcvr1ga96n+mY9NtjvbHmX8om2Ooad4Ecjjw+Sb81w8x/k6SFOo6by7Ly3+7GvJbXjX/yhFSL/AE4e9SP4Y15LfmvXX/yiFf8AT9ONepqf6YDHyW3DzL+TXLidT0sOP2S4r9xwcB7k2u/xH+TxFf0nplPdxjwHuW/N36d/KCtf0hpn0OMeA9y35t/4j/KHtqWmmmxpJWlO2AxPcniRNn+Yf5PaJN+km1KxD2itJGkR5SswX7Manq57ZUQTyZgvNfMnnO48+al+m9Sv0t7aK4hj0jREY14GZd3Heo+1X7WZGCB4g1Zcg4SAyTzzpdjHoE0kMCROkikMihTtWoqMzzEOuhIvMiSd6/8AD4bQ7w/5ryQFoJA3LiCKkggePI4Tjl3NQzw7w6oAG/X/AC8g2orTArahaBgGQzxBlLcgQXHbvhgN0T5PTP0fp5be1goP+K0/pmSQHGsvGrG0toPzdkCRqqx6qojUAUUFjsB2GY0YjicycjwPfo0hNCVX7hlhaRLZjWjKiDUFAApqV6dgO87H+OWR5NUuaR/mIqGPy8xAPHWLc1oPfBLmzgTwy9zLSqVNVH3YXHtKdAWPlqo4j/jo3FRQdwh/jhplI7sY/OWCN/LNoSo2vB1A7xtleQCw5OCR3egeS7e3bydojcFJ+o2/Yf77GMhu1h0dpAPOUw4L8Wmx9h+zcP8A1xBSeiG/MG0hPkvW14L/ALySHoOwrjLkzhsUL5UWNvLOkniN7OHt/kDLSHHaWGP/ABXL8I+LT496fyzv/XAAk9EP57t4m8mawOA/3mY9B2IOQkNm3EfUEp/Je3ifyaw4D4buXt7KcIiAGOQ3Msi8xW0SS6O3EVGoRilB+1HIP45IDdhP6SmHopUfCPuGJRRpKfLUMY0114gcLq6XoP8AlofFTzK++ijHmDRDxG7XS1IHeGv/ABrgWXL4p20ERRgUXcEdB4ZA8myPMPGfK3kOTUdIS5SeONfUkUKykn4WI7HMSeYQNU5oxGScD8spa/71xD/Yn+uQ/NDuZ/lyv/5Vi9Km8j/4A/1wfmh3J/Lnvb/5VjMOl1HT/UP9cfzQ7kflz3tj8sZ+puo/+BP9cfzQ7kjTnvZZ5G0u68q/XOJjuvrfCu5Tj6fL2b+bMbNPjbcOMxNsqHmi9DA/VY9v+LD/AM05R4bkcTIfLFw1xczTOoRpYImKqagHkw6kDMzS7CnF1G5BZDTMu2imq74LSA1UY2mmiRjxIpwbfpthtaf/1+1eUvM2m6xYcbS/N/Na0S5laJoWqa8eSsOtB2xojmg0d0+EmHiY8LYYY8S8LjJtjxI4Xz/+a/lbWvNPmRtQ063jUIiwH60y1Kx16ca/tVxjnAKBhPMMHH5R+bCJfUgsieNI/iIo1R19qVwnUjzZeEVGL8n/ADetyjtb2LRApzCyMCVDVNN/DpjLURQMJ6q8/wCVfnNbcpb2tkSY5Iwsz8lUOpSg3b9lvtfzZH8xFgMBbl/KfzUVtVjtbQenCiTcpG+2Bvxofs5IZwEywm1Afk/5t5SSPaWXrMVCESPQIAa13+1yOD8yF8Eqbfk35se3eB7KyIKMFpM/2qfBU16cvtZL8yE+CWcflh5S1nypo9xaXtiv1ma4M1bOYemV4Kor6jcuWxycdUAiWEmk6882/mHXvK13o9nY/vZzHx+syII/3civ8XA8/wBnH8zFgcErCpBD5gFrGJbOk4QeoqshXnTfiSwNMrGoCZYCVK2tNeikuna0P72X1E4mPccVXer9dsl+YFsfyxpbqVhql9p8lnd6NDfQSEFre44MhANd6SDpTlkcmexszx4CDuwTzp+W195hgpp3lqwtb61EcCzRyfV4lCAExlI2HLirU5ZjRmerkmKC8pflN5v0XzBpt8+n2iW1qQ8zpK7yBjGQ3EM1D8TbVy8ZhTXLGS9VaHVhQi3JI9l/5qywagNEtOUHpuna3b2SQyW1JFLkhOJFWct3bwOH8zFj+WkgrzRvMM3mHStRSyDRWUdysjFlDqZlVV4jnRunxVxOpFUmGnkLTZItc5UNo3EHYnhX/iWR/MRX8tJAadp3mS1s0gayAIeVm4utPjldx1avRhXJDURU6aSQ/mL5R8xeY9KtbdbIE20jyuS6ghTGwqlG3blx+1+zg/MjkyjgI5oXyz+dPlfSdA0/Srqzvzd2ECW1x6cKsvqRDi9Dz3HIZZwEtcgxf8x/POl+bL2wl06G5hS0ikWT6zGEqzsCONGbsMyMII5tRjuxNWPv/wACMuQqAt/lU/1Bilurd+X/AAAxVeruPslv+AxVuTQtV19JbGwtHvbkL6ghXihPE/zE5j5yAN23EDa7Rvyc80HUoW1jy7eJpyuPrPpzR8vToalaBj8NMwDIU5gCb+Y4vykg0CCG30u4sLxhcmwnDytIZEbgwmDL8S+oPh5fs4cUpk7BjkApgdtJRRUD/gTmyi4ZR0UgPYf8CckinuH5VQo/k62NBvJcf8nmyiUmBG7zf894kHmu2XahsVP/AA74OY3bIbPX9KUfomyouwt4e3b01yQaSo6fEn+mniP96Zuw8RkmLHdQVP8AlZejMFApp11XYfzDIy3LZH6SyHWFB0e/qBvazdv8g4kMAmMdunox0UABV7e2R4k08hlhiH55MSopXwH/ACyDDQtmSeB6nqcEb6Rd/u1r6EvYf77OJaxyRMMEZtovhH2F6gfyjBxJILHvKiQx33mAlAeOrykrQb/uojTJEWE8iLeX/mymu3+ow3uqtEsPqSxWdlASyRIhFSSQtXb9psxI4qcvx+LkzDy9pWoSeS4Tb2M8xadJIzHEzchHMjNxNKGgGThkALVKEiz+7ez1S0khvbO9itQ6tIHhMRIFdvjpsfHI5M1cmzFgPV5x5hs/LFsI20a9uLlnPxpLHGQo/wBZKfRtk8eQnojJCIS7TfivowRUUOxSnQeObDSAGdOj7YNYPizrTfLVrf8AlrVdTkkdZbJW4RALxaicviqK98zNRnMZiFbSdJo9GMmKWS6ON5paO5hSprUDquaqQ3etx/SEdbXK288Uzq7JFIkjKiVYhWBPH32wA0WUhYZePP2jkk/Vr2n/ABg/5uy3xA0+DJj58gedv8ZDzNHo8p068uItQtVLxLK8DHkCVL/CzL+y2Yo1EQXLOCRi9EW719R/yj17/wAHbf8AVXLDqoFgNNJLLCDzLbteep5fuyJ7ue4Ti9uaLK3IA/vOvjiNXCkS0syUu816J5s1eLTkttBuUazvobpzJJbiqRVqBSQ/FvgOqgmOlkLTwjzEST+gLzc95Lb/AKq5L83BqOimg9MsfM9rJfM+g3JF1dPcR0lttldUWh/edarj+aik6OaWee/LHm7zFo0VjaaNLFLHOsvOaWALQKwI+F2P7WROpi249NKLJvLa+YtM8vadpk+hXDz2dvHDI6TWxUlBSorIDTInUxX8tJEWqan+n31O8064tLYWX1ZRWKVy/qmTlRHICqvi2RnqwOTIaU3u35pt7jU/LV7Y6dZ3VxdXlu8S81iijBdaKxZpPs/6obIx1gPMNn5WuqUaDY+Z9O0SxsJ9Dnaa1hSJ2Sa3KkqKVFZBmR+bg4v5Sdtmz8z/AKaF+NCuPS+q/VyvrW3Ll6nOv95SlMH5uCTpJ7Kev2fmjUdEvtPi0C4WW6heJHea24gsKAmkhOJ1UCyhppA2lv5f6B5x8s6HJp93ok08jztMHhmt+IDKop8Tqa/Dg/NRqkHSyMiU21WDzTe/U/T0C4U211HcNymtt1QMCBSTr8WI1UVOllSK9XzIP+meuv8Akda/9VMkdXBH5SaC0q380WcEsUnl64cyXE8y8Zrb7MshcA1k6iuP5uCPyk7XXlt5pmv9Nuo/L84WykkeQNPbVKvE0dB+88WyP5uNpOklSY/XfMnfy7cnx/f2v/VTAdVFI00nnlvoXnby15W1h75ZLNDKkli6PE4j5v8AH0r9quYs5RnJzIgxBYdqnm7zfb2plj1i45cgD9jof9jl3gxaoZ5Ero/NXm97NZf0zccmTl1TrT/VwHDEMfHlbI/MOu+YI9N0CaDUp4XubBJLhkKj1JNqu232sqxwBJbckyIilkHmDzGfIOo3g1Sb9IwagkSXLcWZYiq/BuKU3wHGOKmeOZIJWfl5feZ/MMV5cat5omtLeEtHEsSxPLzUA82T4f3QrTr8TZXlAi2RlZZUuk3qSqI/Nl5eEipj9H0h16c1ZxlPEGb1vyfG0EixFi5FpHyZjVieR3JPzzI00ubj5hyZOzgfaIHzzKtrpRe9sozR541PuwGC000t7aMKrOhWvUMMbC0tfUbFPtXEY/2QyJkGQionXdLBA9cGvcA0/Vg8QJ8Mv//QmH5GSrLZ60yspKXEcb8TWh4E0Pgd8nlNljEVB6ZLdQQ8PWlWP1GCR82C8mPRRXvldItV5b4aW3F9sC2wMsDK/jyb9ZzHPNyI8lC5llELmAKZuJ9PlXjyptypvTIsqXws/pL6oAfiOdNxWm9MWJC31Lj6yAFQ23Dc1PPnXw6caYpAVWc0biByp8IbpXCqy2knMCG5VVm4gyiMkrX/ACa/FTArriS4AQ26o5ZwJOZIAT9oigPxeGKq3MbV2p92KqSS3H1mUMqfVwq+m4J5E/tVHT5YrS6aWQQyGAKZgpMavUKWptWm9MNquSRzEpkAV6AsF3ANN8UUseW59UCNUMHpklyTy512FP5ae+BNJd5e+vC2uTqDRfWzcymT0QQnYDjy36YpTK3luWVhOioQzcOB5ApX4Sagb0+1htBbuZJ0t3a2VZJgP3auSqk17kAn8MbULxJQb7V64oKmJLj6068F+rcAUcN8Zap5AilKdKb4FCozkK3HdwDxU7AntXG1pq3lkaBDOgSUqDIqnkoam9DQVGFVt44FjOQK/A2/0YRzRLk+OppgdSuzUCs8p+0e7nNxjOzrZBExyjxX58jltsCrowPQrt35nCqopFeq/wDBnFVQMKj4l/4M4quDA919vjOFWdfk7v5qlNQaW7dGJ6svjmDreQcrS8y9ydgIm3oaZrnLfOn53WaS3dnfRQC2gRmhC9DI0lZHcqN0YMOLA5l6Y9GjOHnULgU6f8NmcC4pCLjmA+XzOTtFMl0L8zPNWg6cmnWCWb2sTO0ZlSQv+8YuakMB1OUyxpFMp8s+X7380UvdZ1W++oXNoyWSLZxjgYwvqVPqEnlV8x8kzE03Qx29Tg8q3EVtHAt5URoqBim5CgCvX2yPjlfy4ag8pTx+rS85eq7SGq9OXYb4+OUflx3oK4/LyabWLfVBqbJJbwvAIhGChEhqWNTWuPjFPgbVaLm8j3U0EkTakQsqMjER7gMKVHxYnOWI0w70bH5UugKfXaigH934f7LKjmLMacJH/wAqiQ+ZG199Wl9diG9ARrwFI/ToDXl03yQ1BZeAKpPpfJskts8BvSFkRkLBKkcl4169sTqCxGmConlKVEVBefZAFSvWm3jkfHKfy470BbflvLBLePHqj/6bO1ywMYPFmVVotCPh+Dvh/NFZaUHqvtfyR0vWtatJdYvpbqxtmklkswqosnKnws1S3HKpamRZx08YvRPNFna2a6fa2sKwW0ELJFDGAqKqkUAAyHVu5MT13iNKum41ohNB128MbV4JoWktq93NbRs4aO3muFCVct6QqFpVePKv2v2c2IlQdaRck9H5bayHCjUrCO6ST6v6QujzF2U9T6t9n++9M8+P8uShmo2GGXSicakLCvD5d/MBtGbTLfV4qXSwyXekJLGtysd03CN5SIw3Fjt9v7OSnnMpWWOLRQhAxiKBQS+Q7W2076w+swP6dzJaObblPEHiRWKhlo3ME8XXj8OWYRxk006zMMEQSxiGYOgI29i5yqQot+M2AUfAVIG46fznKZt0eb6IglQ6RotSBXTLXv8A8V5g3u7ADZvlFTqPwwrSFSKVbqaT6wGjfjwhNKLQUND742ghE+rGKVIH0jFab9WIioZfvGBaQgjmF1LN9YDRSABYTSikdSD/AJWG1IV1mjpQkD6RgtivEsRH2l+8YbZUg72Jnk9ZLgqixurQAgq3IdT7jtgtQFPRr+K60u2n4tGrIAFkHBvh+GvE70NKr/k4QWJG6O9SA7h1+8Y2mkPdxtK0LR3HpCNuTKpWjilOJr2wcS0qrKFFGZT7gjCChsTwH9tfvGBKneKs9s8Mdx6DuKCVGHJfcYpdHIEQB5VcgUJqKnFivNxCR9tQfcjCqjehbi3aKO5ELNSkiMvIUNdsFsgG45FVfikRqd+Q3xsIYh+b10ifl5q8kbq0kaIwWoPSRfDJwO6a2L5bfV7u6t3WXdCwNAo2p75nwlbhHGAUyt9YgWzSIxSFgnHYCnT54S1cG7I/Ot7Mvl7ylJCzqHsSDSn7PDxyjF9RciQ9Kpol2W/LTXHlDsY72Fm6Fjy4DBI+sJxjYqf5WIksusA/AGib7XYHft8shqAyx83puhKhhRgCobcBhQj5jMVvZ4muNauktqw5NAEd9vhoa9DksVi2M43SBu9b1C4Yubg79CAAfwGWmSiIQ8V1O0oZpWJPXc9MFppjOi3N23mCUSu7olxKFqWIC8TT22wsTzZb67Dv2wEsqXJOeJ3/AGT+rEckv//RZZajBbys+nXQtzIxJa3k9PkVNCTwI5EZXuyBFJxD5w80QlSmovKFPwiZUmFf9kpP44eIqYpvb/mf5hiUevDbXA7/AAtGfvUkf8Lh40GAZt5W8xvr2mS3bW4tjG5j4h+YNFBqDRfHDxMZQrdIdzU06nMY826PJSIo1D88DJeSB8+wxRTqCu3XEJXcT3G3uMJChoL1C4KRTqAHfqMUruJ8DTCtNItG2G5FcCuKbksOvTFVyqeNACRirVN6d8VQumgmO5YjY3M2/wAmpiVRaqewrTFXFfEb++KFyq3gd++JVpRuaDrirZUdwfbGlbHFQADsOgxKqOocf0fct4RtT7sYndjLk+NnZje3J33mkPQfznN1Dk6+SKiLbfaH0DJsCikLUp8X3DCxVlZuo5e2wyQVcGf/ACtvYYFVAXI/a+4Y2rOvyfD/AOJpia7W56gD9seGYWtOwcrS9XtkpPoNt2Oa4FzXhn598fR05qkNzAO5ApxY9OmZem5uPneRI3v/AMNmc4pV1kPY/wDDZJWpJjTc/L4sBQ9w/wCceJD/AId1Y13N6vev+6lzB1HNysXJ60rimUtjreL0lKh2epLVcliORrTft4YqvaPlIj8mBSvwg0U1/mHfFVcgMhBJFRSo64CUNwj041jBLBQAGY1Y08T3yBZAtlf3wl5tUKV41+Hehrx8cDJc8nKMrUgEUqNiPkcVWRt6cax8i/ABeTGrGm1ST1OKto3GZpBI3xADgT8IpXoO3XfIkJCKg1y4syDbRLLMxCIHNF37k9aDK2SaebNMQ2lrLdSNPcyMQ0lSoA414ooNFXJgMSWF6xp0CWMzJX4RUAs3Y/PJhiXheiatd6VeS3NrIkcrQyQVliLrxkoG2UrvTfNgRs4ANFGt5y1lbtrz17czvqC6xx+ryBfrKwi34/a+xwH/ADdgpkZL/wDHWtvBGGltPrkHpiC/NkfrAELc4/j5U+D7Iqv2ceFPGoap5u1fUo0tzJZ2Nssjy8La0MQaWUfvJXAZvjPjl+HLLGbHVw9XpYZwBLlEpHbqyIBUmnfiMgTe7dGAiKCYQepT9r/gRlM2yPN7t5StLefyLoDzRiSQpdAu4BY8bhgKk+A6ZhEbubA7I86XZnpEn/AjFO639F21aCBT8lGNIsuOmWw2MCj/AGIxpbLf6Mt6f7zr/wACMNLa39G2h/3Qp/2IxpbcdMtB1gUD3UY0vEXfou0O4t1p/qjBS8RabTbUVpAgIr+yKjbGlsqNnptsbG3ZoFqY0JJUd1GGltVGmWpG0Cf8CP6Y0ttnTLXb9wg/2I/pgpC06bbAVMCf8CP6YeFNuGm2h6QIf9iMeFFtHTbTp6CV8OIwUm2jptoKfuE3/wAkf0w0i1w0+zPSFPoUY0rv0ba/74T/AIEYgJtx0+1H+6E2/wAkY0EML/NePRIPK7RX06afb3sn1c3PEGhZS2wp/k4YjfZIGzxRfLvkS59O3/xOGdiEjVI1BJY7dBmSMsnHGMI6fQPJ2mTPYXXmYwTW54PE0Sll2rQ/CcfGkQnwBaa6va+UX8vaIk+vG3sYopIrO44BvXVSFYkFTTiRlcJkFJhYpAtaeXbfyBr9voepnUl5wSzMVK8G9RQB0XqFw2TIJjEAFL/yp2vdWRqb27Hb/UY5LUBhi+p6fpbHitcxHKKbSve+mq2drJdzHb0ohU08T7ZOLFDxWPnebj6fl2ZVYAN6ksScfHqd8bC279Ged6MphsbWVdv3tyHoQDWoQV2OFFqUPl7zcsnNtT06FWHJ0ijmkatNyGJp9qv7OSQbRsehawwQS60OQ6tFbjfan7bEdemNBO6ne6TLaTWrjUbmT6xN6ZSkQReS0+zxrt1+3hCv/9KJR6TfxPbepAT6Aui5FD8UzMVp7/FiJBrMT9iGEV7bWQHGWKWOwKCnKvrVBAFOr4dkm0xgv74amsHrOYjNFGVbccfRZn6+LAZGQFMok29y/LCg8usR+1cv+AUZGLLLyYD5S8v6BqEes32qW0c8tzrGocZZdyI0nMaqCTsq8egzN4A4IkeEbovydZeXojPdaRIhW4MnOJKHgqysF6VbttyzD1EKczTyJG7Ja7e/jmM5CQfmDcNB5I1idWo6W5I3I/aHcZPGLk15pVHZ5h+Umt3F75yihkjRFSCZyV512BH7TMMv1GMAbNemkSTar+fl/d2+u6YLeaSP/Q5HYI7KD+98AfbDp4AjdrzTILOPyemkl8jwzSuXeSedqseRALdKnwynMPW5Y+gPEdM1HU5PNNrEbqYxy36gqZHIobhduvgcy5QAg4eGZ4w9e/PvUbiw8kLPbyNHIbyJeSMVNCHJFRmFjG7fmJY9/wA496vd6lcas9zK0gihhVOTFty7VO/yxzABlivhNpP+Z+qahF5+1BY7mWOBBCvEOwUViWtADQZkYwOFxpzIL0+SeVPyle4Dt6q6OX9Wp5cvQJry61zGPNy8h2eZ+StVvZ/zcsrRruUwRpVoS7FWP1SpLCtPtb4yGzVhJMym3/ORWo39o2gG0uZLfl9Y5+k7JWnCleJFcMeTHLMgp9+QN3c3nk24nuZnuJDfSKrysWNFjj2qcjPYt0CTAPHdf8269H521K1iunWAX0qBSxNB6pFBvl3CKaYzNvefzavp7DyHcXMTFXjmtgCCR1kAIqKdcqxCy2aiRA2Yf+Seu3epa9eJcSFhHakgVJFTIviTlmUU16eRkDb2UEUym3ICG1IkaZdf8YziBuiXJ8qpfaFFIVk0WOZuTepM0jjkanfNgLp10uaFvZ9PlugbO2S2hVACgZjViSaktXMjET1YkNLwA/Y+85axIVFK1pRPvPXCELgy7fZp/rHCqorL1+GnzOKrG1m/0u8tp7G4e2dmZXMMjKWXj0PEjauY+eII3bMUiLIZBpHnLzJfarYW0mo3Qje5QMVmk3XeqnfcHMGWIByceYkpv+e8oa308GvMTNUjYUCsBk9NzZZ3kaknep29xma4xCsGNB1+VRk0IyDRtWurcXFvAXhatH5oOhodjlEswBpbe1/kJYXlnoOpRXKcGkvFYCobb0gO2YuWVlysXJOrD83NButbi0dLS5FxJMLdXb0+HItwr9quQMSoyRJpOPOX5gaV5SFob6CaYXnqemYApp6fGteTL15YxiSspiPNHeXPNtjr+gHW7SKWO2BlBjk48/3P2vskjftvgIo0yiQRaSeXPzf0DXtYtdLtbS6jnuuXpvKI+I4oXNeLE9BkpYyBbCOQE0jvNn5l6L5Xv4LG/imeS4j9VHj4cQORXcswPUZAQJZmQB3TKDzZYTeVv8SKkn1L0WuPTPHnxQlT349vHI8JumfEEq8rfmdonmXU206yt54pkieYtLw4cUKgj4WY1+LJzxGIssIZRI0FLzJ+aOj6Dqs2mXNrPJNAiSO8ZTjSQVFOTA4I4jIWFllETum2q+abPT/LY16WKR7YxxSiJSvOk3HiNzx25ZARJNNnEKtbpfmaO9lXhCQ3pJcKC6t8LnYHj0OQMaKiVor80fM948/lqOG6khilnmjnjhdo0Yek3GpG54kDLcO53a88iI7ML+u3/wBbSNr25uIncIUedmWhPUiv68yJQAi4kMsjJ5kwHI7gePxnMiPJiebR4EUPH2+M5IIdSIbfD/wZyNq2qpTenv8AGcbVE2MNvLeQRyAGOSVFdQ7VKs4BAp7YQN0E7PUh5F8qh/hsmArQfvpv+a8yTCNNMZS72daFZQ2PlbTbWAFYYpb0RKSWopuWIFWJbvmklzLuIfSiajIpY551iWWztlYtxExNFZl/YP8AKRmx7NhGWSpC3A7RyGGOwa3QnkSJYbrUgrMYyLcqrOzgH94CRyJpWgyztTFGEgIjha+zsspxPEbY95ttl+satKEmkmrLxEUjq1aUHEclUcczdNhgcHFW7ianPMZ64qDMdVUy+VlRyWDRQczUgn7Pcb5qNNEHKAXZ55EYiQd6STyraLD5gUpyCNayhl5sVJEkZFQSRXrmf2jijGIoOD2fllKR4jav5gsbKfXJWnj5twjA+JgKcelARh0GKMsdkdWWuzSjMAGhSYeXkdPJ1vGzMWSFlDMSW2ZgNzU9BmszxAyEOwwm4gsU0Syij8w6TPEGVvXkEtGahDQSdQTT7VM2mqxQGAEB1elzSOYglMPzE1zTdIurRryJ5VlhYpwptxbvUr1rmv0kbJdhqiQBSafl/qMGo+XDcwK0cUk8wRH3IoQPE5XnjUqTpzcWBaN5q0641qws/SmjlkuYkVzQiocdaNmXKI4HHBkJsq/NPW4NG0/T7mWAzJJM8ZVG4kHgGruPbMTT1e7kZ74Nl/5X61ZatZX9zaKyRpOiFXpUN6YJpQnDqKvZjpZGt2O6nrWiJqV3DJeQrcLPIhjLUfmHIpTrWuZEAOBoyykMnNmnna4tLXRklupFii+sIhdzReTBgAcxcAHG5WckY7CX+Rbm1nurxraWOVPTh5GNgw+0/hlmpABFNOmkTaA1GKE6tdclBPrPX/gjmVhgDDk055kTO7wv82iy32nxBiIxA6lamhaOeRA1OnKnfK5xADk4CTe7DNHkKatZVOwuIiT8nGUW3S5Mh8/ov+OtV5iqtIhpudii4cPJE+ibaqts/kHy00ilwpuFUBS1Pj9vlgh9TX/Cfev8q/Vj5R82x8SsfpQMQQQaA/f2wS5hljH3L/ypkj/TOpLGfhNtJTr/ACN445zYTj2kHp2myfCuYhchmXk+X/cqBXqjA+PbD0YHmxOL80/NkmneY5p7uC3bSdRgtYZY4V+GGRpVfkG58m+Bfiy44hswyZCDID+EMot7n6xGl0W5tOiSmSlORdQ1ae9cBDKEuIAlWVwFB8K4GSS6h5hmtbyyt4Y0Kz8+TsTVeJUUAFK154bWWwRusbtYH+W6T8QcIQeT/9OJR+do3jSSSNPitzduqlqheVEFKH7dcrIpPH0R9t5ktbmSVHiZGtYkmuQp5FPVHwpSn28x8+YQiDamYHNfb61YTXQt1D+pz9NSQCKqvPrXwy6O8QVjIHkjI/OV7pt7HpdpcMkkkiiOFX41eSlNvfMjHQjbVI8RpJE8lfmBHbmB9L9RjPLNJJ9aQBzLMZOh+eSGpDX4BqmTflP5X1ny+dV/SloLV7t0ePg6yAkci32enXMfPkEuTl4o8MaL0LkP7cptmkHn7T9Q1LyfqWn6dD9YvLmNUii5KtfjUndiB0GSxmjbDLGwwD8r/JPmnRPNRvtW0/6ta/V5Y/UEiP8AG/Ggopr/ADZdmzCQoMMEDG7VPzg8meaPMWu2tzpFkbm2htDC8nqIlHZmNKMQe+OHKIjdhmxmUmY/lppeoaN5Ot7DUIDb3sTTF4aqxozErQqabjKckgZW5I+mnk+iflp56t/Mdjd3WllbaK7jmlf1ojRBKGY0DeAzJnnBjTjYsRErL0f85/LeseZfK8Gm6Rbm4nF2ksihlSiKrCvxEd2zGxEDm25QSdko/JHyZ5i8rS6qNZtvq6XKwC1+JXqEL8vsk0+1jkILLH9O6UfmJ5I856t5o1K703S2kt5mT6vciWJeQWNV3BYGlR3yYls488ZJehXem6k35Zy6PFCzao2lC0W3qoJmMQQrUnj9r3ymPNyZ7jZ5/wCTfInmS0/M+PzBcWbJpSCSP1uSHcQ+l9kHl9sUyyRBDDFGibTP88PJnmfzRNpI0SyNzHapN6780QKZGXiPiI/lxxkUwyRJNp5+S/lzV/LXlJ9O1eD6vd/XJJuFQwKsqAEFSR+zkMhst4+mnkurflJ+YF15rudTXTG+rS3zzqfUiqYzMWBpy/ly7iFNEYkF7J+a+j6rrvkmfTdKt2uLySeBhECq/Cj8mNWIG2VY5cJZ5o8Q2Yl+THk7zH5d1m/n1ize2Se2EcTsyMCwcEj4WJyzNMS5McEDEG3sINem+UFuCH1ZuOl3R/4rOGPNE+T4zmuJprmR0jk4Emg28fnmyjE068x81exLqXLq6liOoHauXwBDAhMFfru33DLEFesj1J3+dBixXiQ9at9wwqqLK5Famg67DCq+HQtX1u8ghsLWa6MPKSZYghZVIoDRmUdffMfUSADZjiTbIdI8i+cLTW7O5bRLmKygmSR2JjdgADU0VqnMIzFN2PCQUT+eMyvHp5U1/et28FINQffDpebbleUpXao27bDM0OOV9T4f8KMkxpF2WrXsUYhW4dIlLUVWKgVNemUSiDugh7n+RF3JcaFqDO5creKoLGp/u1OY2QUdnJwj0vNPLsyH8xLEhhy/SgBFRWvrnLSPS48B62df85AMjNoQcgLW5Jqabfu8hhbdQNmQ/lRMrflpIy0C8r2gHQUByE/qbMX0vKfyem5fmLpAr09bv/xS+ZGWuBoxD1Mk/wCcgh/ud06U0IFpwpUAgmRjWnhkcDLUR3Zfpcn/ACAQGv8A0qpt/wDZPlUvrboj0MG/Iadn86XHL/lhl71/3ZHl2oPpaMA9SH/Ou4KeebxAwUSW1uCe+yHI4JVFdQLls9I84Sov5Ro7fZW0sSd6ftRd8oiam5BHoSj8q9SWeWdTOsi29lCteQPEeq3XDm5oxcmTfmBY6tqFrodxpdlNfpa3EjzGAKaAoy9WKjIYjRZZomQoJBaW3mP9IWpm0a6t7cSqZp5RHxVQOp4uT+GZE5iqcXFhkDZYGeVd+R/2Iy8HZgebjyp0P/AjDaG6tTowI/yRgVsBv8r/AIEYqqwTtDIk/B3MTLJxULVuJBoPuwg0UU9Aj/NfSWbfSNQ3/wAmH/mvJzzLHE9J8u6pFqnlHTL+GGS3jllvAsU1OYpN34kjNXI7uyjyRg3FcCUg85QapLY2/wCjbI30yS1eESJEQpUjlyfbrmXo84xysuJrMByQoITyZBq8Ut2dS05rDmIxGDLHKH48q/Y6Urk9dqY5SCGvRYDiBBSfX7DzS+q3zWujG5tpHYxTi5hTkrDrwPxL9OZWn18YY+EuPqNCZ5OIMn1FL9vLPpW1t618sUIFqXVCWUryXmar2O+a7Fk4cnF0c+eMygYpP5ag8wpqqyahpZsoBE6+r68cvxMVovFNx9nrmVq9XHKKDjaXSnHK3eZ4PMR1cyadpX122MaVl+sRw0YVBXiwr9OHR6wYo0QjWaM5JWE20SG8Xy/HBcwfV7vg4eAurhSzMQA4+E9euYWbIJTJDmaeBjEAsZ0Sy8xjV7WabSxHYJIzC6FwjHhxZVb06cvir/sczsutjLFwU4GPRyjl47VfzI8va5rItBpdotyFjdJS0qxcCWDLswPLpmHgy8Dm5ocQTT8vtP1XTNCFrq0CW90J5H4RsrrxYgihWmRzZOI2uCBiKLzfR/y086WPmG0v5bSI28F4s70uVb92JOVQvEb8e1ct8YGNNZxHitm/5peWNU8yaPZWunRLNLDcGV1eUQgKUK1qVavyynHLhO7dOPFGlD8qPK2seWrHULbVIViNzOk0PpyCUUCcTUgL3GOWYkww4zHmwnzL+VHnG+8z6hqdrBAbee7eeBmnAPEvyFV47fflsMoAphlwkyt6J+Y+gan5k8pSabp6R/XJJoZQkz8FAQkt8QB33ymMwJW3mNxpIvyl8leYfK9xqX6WjhCXaw+m8MnOhiL1BFF/nyeXJxNWHEYm0TfaD5zTWNQmtrO2urSe5ea2eS6MbBGp8JX02pvX9rLsep4Y015tOZTsPJ/zc8kearbTYtc1KK3htrY+gyRTGVi00ryA0KJ/NTE5hIU24sRjby2xbjfW7ntKh+5hlbOXIsm/MdjH50vpBvyELU9zGvXHGdlIsBN5ZkP5eaCzUH+kXKD/AIInDD6muQqJVPJ8iHR/NkddvqkbV7bVwT5hOIb/AAU/yqkDeZL1VNQ9vLQ+PwNgzckw5h6dpkg4rTMQuQmdz5ll8t2E2sRQi4eCg9JmKAhzT7Qrk8cbNMSWNwfm9aJHP6XlfTUFywkuAan1HBJDP8PxNueuZPg+bV4m/Jbcfm3cegLpdNhVXPEwq7KqcTxotB0xGNfErkhz+bt8UamnwjsP3j9PfbHw0+Ig9U88NObC6Foi+kpZRzbcyUqDUdAUxjjRKeyvdfmdql2YS1tBGIZVnUIX3Me/Fia/Cf2skMdI8R//1I1/hfy0kjTSKURI0RyHYj04mDItByP7I7Zg6zNwQJ6lGQiItj2t3mg20sjSTTI17MJrr02CsKDilahabbrH/wALmrxXkIveMXDJEjRKdaT5btbO5t7yK7lmVS8oEgB5euoG/f4QM3GGQMduTmwjQS+X0m/MXTg7KALu3G7U7KfD+OZY+hpgf3r3trq2rT1U/wCCX+uYbmqZubYmolTw+0P64opoTQmo9RP+CGK0uEsAIPqJ/wAEP64lNLnuoCP7xf8Agh/XHmrS3EIG0i0rueQxC00J4t/3iGv+UP64qAv9eLjTmte+4xpSHLLEK/Gv0EY0u7jMh/aB+kYVpeJYgteQ+8YFpaHjJX4huR3GJRVITSZR9RSpH25D18ZGxCaRquo3qPfcY0tO5qd6g777480U2WQLQnfGkUt5D+hwUtODL0xpabDDFO6X6/dJHpVwjGjSRvw360FTjGVSDGfJ8dwSAlqkdT3Pjm6iXXyCLj4+x+k5YGKJUpt9n/gjhpBVFC+K0PucCheOHio2/mOKCqR8OI+zT/WOFD0f8lFB1++IA2t16En9vMHW8g5mm6vbGU8DscwLDl08K/5yMgt47mxZEAdpnBanZYkIH3scyNMd2jKHjKsPD7wcz3HpeGHh+BwhClJHGaniK/I5ExDISL3L/nHo8fLOqAbf6cP+TS5hZebkQeiReXPLkdwtxHpdolwjc1mWGMOGrXkGpWte+Qsp4AjL7StK1H0zf2cN36dfT9eNZOPLrTkDStMbIUi1W0sdPs7Y2tpbRW9seVYI0CoeX2vhApvgSBSlaaBoNpMk9rp1tBNH9iWOFFZaimxABGSJNIEQFW90bRr+RZb6xt7qRRxV5o0dgvgCwO2RshJAKqljYJZfUEt4lsuJT6sEURcTuV4U40yHVQNqULTRNEsZvXsrC2tp6FfUhiRG4nqKqBthJJURAWXmh6HezGe80+3uJyADLLEjtQdBVgTiCQnhCtNZ2Etn9Slt45LOgX6syKY6L0HEim1NsimlGx0bQ7OQm0sbeBpKB/TiReQBqA1AK0OA2tAMuWp09QBsJB0/1TiqW6stNPnPHoh/Vh6q+cWMZ/lJ/wBY5shydcebiV22X/gjihw4Gmyj/ZHFWwY+4X/gjiq5WQHcLv7nBaomGSIdePXxOVzZh7n5EngHkDSOUiKPWvAAWA/3aPHMI83NhyTf6xbV/vo/+CX+uKXGe3p/eoP9kv8AXFId9Yt6U9aP/g1/rirX1m17zRg/66/1wq19as+88X/Br/XAVWteWHVrmEHtWRB/HFaUzqOnjrdwf8jU/rimmhqel1A+uW9f+Msf9cbWkLp+p6YlhAkl5bqyqAwaaMEEbdCcWFK51jRx11C1A954/wDmrJIorTreiA76jaf8j4v+asFlFNPr2hbD9J2n/SRF/wA1YppZ/iDy+Kg6pZ/9JEX/ADViVAK0+ZfLqmn6Wsh/0cRf81YsqWnzN5Zp/wAdayH/AEcw/wDNWKrR5q8rr11ix/6SYf8AmrFNNHzZ5W3/ANzNiP8Ao5h/5qxtSHf4w8ojrrdh/wBJUP8AzVjSKYR+c13p2vfl9d22j3cGo3P1i3dYraVJGoH32Untk4c90XzD53Xyl5hV1YadOKEHcDxy0yDUbIZN578taxqHmGS5tLKaaOSKIc048SyoAepyMJAJN0Fa48s63L5B07T/AKjI13b3ksjwDiGVGBoxqab1xEgJLRVPJ/lXX7XTvMcFxYyQtfWRitVYpV33ouxp374JyCY81b8tvKXmbTPMJnvrF4YGidC5ZD1U/wArHHJKwgDdnlhb3iqoeMgUBrtmOQ3Wo+cz/wA6pqRYGiRq1KVOzDLMWxQXjsWt2yxiscvh9j+3MzicWkUt4j6JNOA3BZCQKfF1HbACit0F+m7cKB6Uu/8Akj+uSJDKkc98F0WG4ZWZeQotKtQse2RBYgWhk1y36enLQgkfCPA++TteF//V5noWm6la6xqd3LE0UCW9nArSKaFQiiULuKEcT8WabtbIOAR6yacxqO/exq8lt18wTuGE1vM5khfkFMQ6kKK9V/ZwYwTjH8JH1OJEWGWeU2vWv7JZDOYRFctIHJ4luSBa/s+JXM3T7Rc/Cdku8z6gLbzBclnPpq1AtW2/dp2HfM6MbDROQEixS6ZhcSXHpCcyAqBMvNaH2Pf3wnE2Qy7JA1lcKe9MBgz41Nobhf5seBImjtB0q41DU4YKkRg85mqQAg65javKMUCUHI7Xw7arOyNUMa1Umnh3w6UXjDHHPZL+MvicyeBnxu4zeJx8NeN37/8Amb7zjwJ40fo1lNe3yxO7iJfikIJGw98x9TPw42xlkoKN9bXlrcNE7k03BVuQofcHJYpCYsLHJYQ4e5/nf7zl3AWXEujN20iIJHBZgAanqTgMF4k082PdjzLqYMjFhcOCQT1BpjwIE0BaJdz3EcfOQhmAbiSSBXfbIZPTG0HImvmc3H1xXilcKqhCoLAgLsCfmMxNEbjRa8eW7tJfVvP9+v8A8Ef65n+G28bvWvP9/Sf8E2Phrxt+te/7+k/4Jv64+GvGqW/6SnlWKKWQuxoByb+uRmBEWUHJTI7ljZWEdikrNcSR0uXLNUtXkB1245rMcjknxdAfS4xyklKbeGQdj9wzoYjZEkZGJRtQ/cMsYKwSTwb7hhtSqqrDqH+4YFCotRuQ4+gYrSZaVe3NstzHHDC4mhdGkmjDuAVpRDWi1/mpkZRtkCkd7NqkHD6rO8UpBBdWaOvw+MZB265RnjYbcMqSs+Z/NMMhX9LXisp/5aJevX+bMThDlCZTfzpr2uX9roialePd8rJbnlLu5kkd0JLfab4I0XLMUaYSNsaV/wDPfMkFrIXhzT28N8LEhosaYCkBN/L/AJ781eXLeW20e9+rQTP6sienG9XoFrV1Y9BmPOLbEpr/AMrn/Mb/AKug/wCREH/NGV8IZWvH51/mQOmpr/yIg/5ox4Qtt/8AK7fzI/6ua/8ASPB/zRg4AttH87PzJ/6ugH/PCD/mjDwrbv8Aldn5lf8AV2H/ACIg/wCaMHAFtr/ldf5l/wDV3/5IQf8AVPHgCeJw/On8y2NP0v1/4og/6p4+GEGbZ/OT8yz/ANLb/khB/wBU8fCC+Itb84/zK76sf+RMH/VPD4ajIjtA/NL8x9Q1WK1/Sx+MMT+5gH2VJ7JkTjCTlKprHmvzu96EudevWod1EroA3YBUAHfI8DA5SifIWseZLzzHDZ3l1c3P+kGVZJJ5TQQox9PiW4MjftDjkjBfFRYZt68q9vs5mDk4Z5uJYn9r7lxQ1WTanP8A4XFW6sBSj/8AC4q4Ox2+P/hcFJDbGanRx92R2ZLLKz1ea6NzY2Ul7LAKbw/WFTl0PGhCtt8JymeIFsjlI2SfUtF1bT7cLqcEtrayTtKZbiJlLSOKEcmoaU/ZyHAs8prZBTTWp5IJVeMfDGWc7Cle4x4GvxSltxRTJwkhaIoaoWq9adtgPlkuAMhlKto0zTR27SyRn06JSQnkd9utdt8jKCZTlacQrpRMhJX1FB22NGHTt0yowYHKUn1axN3cqxoaRqCU6dT45Zig2RmaQ99aPdNH6iIghjEUaRqEUKvsO5O5OXDEg5SoRaQgmSo2DLX78lwI8Qpx5x8u+n5i1SUFWR7uaig1YDmacsx8WSMpcPUMpZKKR/ogV6ZkcCPELX6JHhjwL4hd+iB4fjjwL4pd+iB4Y8CPFLv0QD2pjwL4hd+iF8Pxw8CfFLf6IXw/HBwI8QoqO3jRET0FJReNeRAPXcinvgOK0+KVBNIjruB9+SGNj4hTrS/McXllGAtPXFzQij8ePD6G68shlgzwmzaOb82EJB/Rh2/4u/5syrgcgFVH5wAKB+iqkd/X/wCvePAtrl/OQhq/ogEeHrn/AKp4PCW1Vfzmfto9G8fXr/xoMIwljab+XvzUn1TWLbT49MELXD8BJ6vKhIp04jBLFSRMWmMXne/NoZUsIyEb00VpSCxHUj4cxJZwJiPUsiQDSrrd9d6j5M1aS4gWB/qzURGLbAj2GZEeaebwfk/Dv198yWqhafWLE+WLsDYgn9YOHow/iSIySFVrWm9OuNllwhPpef8AhNCQRQjiaEbc6YOIHkiI3KRo78ht+w3j4HDxMqD/AP/W5Xc+dL6+0DUo54IYJHYRR8GZudTUjce2arWYbyQN7BxtTKwGCSlklinvVWX1FqI42ClT0oRQjtmTGiCIsYgcg9C0jzTNZeX4pUtykK7r8ZkcmvRqgUGa/URkJCMSylkpDG90TVoob68kuI7meQiVIZOKg0p04nwXNhizyiOE7lrlEFIZ4oTK3HjQMePIkmldq++bYbhkAttYYkuY3KI/E1p16DwyMhsyBUbqzgM8tFQDk1APngA2W0XodmFNwIgpd1FSCRQdeozV9pigCeTGRsJJcPAsjpLGrOK8mA3Jr/TMnSHZEOSEuIxHPEvENyQVG/Wv68yJ30bQdlVLZPrLDgFoSKV2yrFIkreylG1qsSlwpbiC1RU19Tp/wOZYpBtNtAljSN6KKymgoDuB1WmaztCNxBYZDtSB1NuUsCFArcgtAKbf5WDS80YeRZD5W0HTLy2unurdZmWXjG5LbAKppsR45dqJEFM5GkJrWl2NrrMMFrCIk/dGgLE8mk9ycniJMSnHIksw1Lyrot1e3lxNaAyM8sjyBn3NSa7EZSJm6RKRBed2Ui213BIQAjLRm+IgciNyBvXwyesiZQpJ3CLvXVb2TmC877AgkjrT4q+2YOG+EVyaoJ7o/lXTJ9Btrqe25zS8mL8mFRX2PhlmXNIGgW2UklXSbR/MC2YjAga4KekGboFJpWtczeM+FdrE2U51vy1pNrp1zJHbBZokUo4ZtizUrucpw5ZGkGSSaXCkLSTBV5RAMr1Pw12yztA+mu9hI7KepSQzTBlkcsoJYnpyNBUd8wcAMQxhySSW7mSXiNuO1Kk/xzYxma5uXGAITXTnZoS70BqKAkjala5lYCSN2mYRYYDf4SfDkcyGtWDJ/k+3xHFK7klADTf/ACjiqtBKoqBxpSg+I4QhK9eNLXkhCsCB8LEnfKc3Jsxc2NkkmpNTmE5bIPNVeGiDw0q3/F5DlmNBSRf898vYFeKf5nFCpGoI32rWm58cxJ5SCxJamWP1GVegA3r3+nJ4iZDdMSaUfTH+ZyzhZ8SvbRQsGDx8+hDciKe22VT2LCcyGpYIhKAoovw8gSe5wRlsVjM0ip7Oz+ru0ScWQDcsSTvTplcZm6YDJK1GCKzCVmWpBINCQfwycpG2UpS6Ie6SNXb09krRR9GSvZnA2ttByuEB9/1YxO7KfJM0toPRDOWLOdqHYbnKpZKLimRtqztIpnkV6mkbstD3DAA/dlhkQLbAU/8AIllF/iu1RSTyjuK8TVtoj098jjJkWMp1ElmR+o3ttLNE84aI8ZoW3lQk03UA5dLEQ0w1MZBJvLssml+Zprjd2tmm4oxNCeJXelPHAI9HJtGGNASKp18DlsRs0nm16ajuv3HDSuVE7so/2JxpDYjTfdf+BOKqdzGos5zUV9J9+Br9k98B5JDEhuoqWpTxP9cxLLa9a/JjWdP0rTNVju5mie6KcGCNJspYN0I/m23zKwYpTGzg6rWY8J9f8Sl+dutabe+ULG1tbl5ZbafkG9No6JxCgVYsa/M5LPp5QFldHr8WU8MOjym65t5Y0mMeoeV1cBTXdyeApWnbMWR9Ic7vSuKAFpBK7oyg9+hHY5T4hBYmS2GEGKMxs4csAxBoOvbCch4me9rri1mhvZIiZFCnduRrxO4JP+UMMp7KU/0a3BZohx+JY+L/ABEsWJFWqTQ5PHmsbhhRZrJ+VWuj/d0G4DUHLuK5MaiLI4ZKL/ljrMKiSW4t0TkBU1G56DIz1MQGPhSQ+p6Feav511OziuI0k9eXjG4PRW6mma/T5AJ3SJxJlSNH5Ua1Wn1mDf8AyWzY/mYpGGS4flNrJ/4+4B/sD/XH81FPgSXj8pdR9Ir9ai9UsCrcTTiBuONetcfzMU+BJaPyj1cj/e2Ef7A/1x/NRXwJO/5VHqx2F5D/AMAf64fzMV8CTv8AlUerkf72Q0Hbgf64PzI7l8CTh+UerHf65EKf5B/rj+ZHcvgSXf8AKo9SrT67Hv8A5H9uP5kdy+BJev5S6hT/AHuT2/d/24fzQ7l8AobUfyWvb1YwdRRClTX069f9l7ZGWpB6MoYpRSu8/JL6hbvdXmrqtvFvIREa0/4LMfNrBGNgM5CQChpX5SWesBn0/VgAv2opI/jXtvRsGDWiQ3G7CMpFMf8AlQ1yDtqaU7Vj/wCbsv8AzA7mRhNsfkXdV31FNv8Aiv8A5ux/MDuR4ck48r/lZFoGsQ6xd6grR2aySrVKAOqMUr1qOVNsyNMRllwkNWWMo0brdi19rrW2qepLxaFwskEEI+AGejOafzb0zQTw+s1zElnM8VvR5PLM13o81qLhFivYSnIVJUOAfppmfCXVyokkWwtvyDQf9LY0J2/db0/4LLvFCKkjbb8mVg0+az/SJZJiavwAIr7Vx8byY+GbtDL+Q1iFHPVJCQasQgG3y3yE8/CLZUVOz8nWGuTS6J9ZkS2tkVIGUhmCqT9o0KjcfZzXaPUEmz/E0gESpMIfyH0RUbnfXDuVZVcFFAJBFSOBr9+bLxW/gL//1+e6loWjaHpd24qbllMkUcnJqGuwFDszdf8AU/181GsyGRjEd7TqgAGHeWNGbW9UntXZlnkjcrKVJTqAd9+gqP2ctnsBTDFh4gnvmPR5dK0KK2nHpdIxFGSVfh0etT1/lbMW5HKCWOWFEKPk7y9puoWU6yyfv4HJ4LIwNGH2iAR+rMsT9TdHEJC0rOzELzABIFAOx983cOTSURp8fqahbRsHIeVFYUWhDMAa4Zckx5rb9FF5cBVdVErhQAtKcjTEDZiCrRXS2WmyyxR8pn+Es5AAqaDbbNF2hEzyCJ+ljM9GKRNNdzyJxqQKFhT6My8MKIpsiKCLudPnnkSSjKY1CkEDsa5nmNqDTcNnOshdgxDVqBTrkceERKTLZBPot2Budv8AVyzhXjCZ6Z6ljaOQvJ4xuzbKKnb8c12vgSAC1ZJWl7SvcXbgMKqQZDQktQ1NK46XGAQyiKCb6frusabDLBaGP0ZXMjepHVqkAda+2ZmTT8RUkHm5Lm/1LVrZ7rjzeSGNSi8RQSDr9+Sji4YllEAHZMtV80a/HqN5DE0XorNKiAx1PHkR1yEcHVZSBKSadBS8jmdeSQJuDUb9jtmP2hA+GxJ2UtTvXF8REoVpwAO9ATU/TmDgxXHfoxhG90bbeY/MdtaR2cEsXoRCiAxVNK13Nc2P5EHdsMgg1utQS5W8Vl+urKZeXD4KkEdPpzI8H08KBIApte6nq915fM9w0fOe5+ryBUI/dxoJBSp+1ybIQwCMlJFJabgQWjs0lK/ZQjr2Ncx9aOKQDXVpMZBIHkA4moAp45VVbNojWyu9i7SrI0cTEdRxcBtu9Dmbjw7JGShSKgWVC9VVATXjGCFFBT9ok5k448LXI2rcm267ewyy2K+rnryNOmww2raliKfER40GDiCd1USkAAV+4YgqnHl7y3a+Y5prW8keOONVcFKA1rTwOY2py8LfhhafH8lvLldrq4/4NP8AmnMHx/JyfDPeitW/K7QrqS2WaeYLa20NrEQwFQicv5TU1b9nJRz10QcZ70sv/wAmbR7crp80sVwSCHmKsvHv8IoanJ/mwx8MpJYflTe3xnEN6I2tpDFIrJUlh1YfENjlePXA82IxkoxfyY1gUI1CP4agfuq7H/Z4yyxO7M4Cibf8orSxheTVriSfnIio1vxjCg1BLAl65IZ65L4JTWL8oPK8oqLm5FfF1/5pw/mivg+aqv5N+XVrxuLk12+2B/xrkJZr6IOFsfkt5cbrLcknYjmP+acRl25MhhV/+VL6F6fEvdcTTo3gf9XB4nkx8ALf+VJ+Xjtyu/EktQb+9MJy+SfB80Drv5QaRZ6bLc2sVxcSoQeDvVd9qkAxk/8ABrko5L2Xw63YfZ+S9Z9cyLoUZWJS7n1iKKNixrPt1ywNMiT0TLT/ACPqF5M0U9hBDCkcsgKyPIRxVm7TjIGIu0RhZ5LbHyXrDzpBbWunrM6soDy3BqtOR/b2+z45MkVSeE9yY+S/Jltd+YYIr1rMI6ScRbPOsvLgaULtQCvX4WxjMQ3DCen448JZxpPkCCxme6Dl7lk4qpclAWALV2BbfJ5NYDs0YOzzDe2rX8u4E1K5vJHHG5SYSqrEkepGeXGop1+zlEsoOznDG0vkIOQ3qmjb7seh38MkNQx8G1w/L9OVWlPGvZ2rTH8ynwHJ+Xyb8pKjvR2x/Mr4Dl/L+Po0p37Bn69u+D8yvgOb8vIpIpIzIaOpXZ377b7+GJ1CjAla/k5ZEGtwa7cd3p71+LK/GCfBKd6H+X40jg1vMheNw6Fw7Lsa7gt45kYdd4YIrYuDrey/GMTdGKd6f+Wuj67qYi11RdW0vqSNCheNeRoQdmrschqe0vEiIhjouxximZk/U8p/NHQLOwlttH0mAwW9neyC1iTlIazJG7k1LM24zGhM9XOyjh2YXPY3MkIkmdJATSOSu1KGvbESDQCKTbyr5bgvtA+tx7X3rmKJxJTiQocVQ/DRt0/2WGc92+BBBRvlfQrG81+5XVYGuIprd5oFYFQxDcV4kUPUcciZsOZpHWfly1tdflt4yUjNzFEqjoq+qRtUnplgl6S2Sju9+13SbSy00yoCbiJxHIxJowC7GnaoGYgkbcrhFMI128jTTGJoEqPVL7KBUHc/s4zFhhPkxvRLa2b8ydamb966kvEFFVQualmJ7/srTBAbtHD6rZ3z+nLm9dyVasa8QKnv74Cl5+Pzh8v2M9zBqQuDKs0gjMMYZfTr8O7Mpw4oGTWJC3H88PJY29O99v3Kf9VMt8KTLjCZ6p+YWm6TZxarepOdPvVgazWONTIPVjMnxAsvYfzZCMLNMrCUf8rz8oCn7m+6/wC+o/8Aqrk/BkjiCbab+aOgX1lc3kMNysNvBLcssiIHZIqcuIDsO/dspP1cKBkBNJL/AMr58qA7WV+R/qQ/9VctGEp4gnflH8ytG80X01jY29zDJDEZmecRheIYLT4XY1q2CeMgLxBlYY1rWop1yq2VMf8AP15Ja+VruRI1kXjSQNXZT+1sD3yjMCaDXk+lhf5Lw3Us9/eyrIIwAiSk0jJO/EDuRl5gAdnGxDfZ6qX3G/ti5q0t1xWleyuXgukkjCFjVKOodfiFPsnJRkQdmMogvnHWrMpeFUjeVg/wotAVVCRTj9qtB/xtlMTubcLJHcl623mkaV5OOrtbCWC1iiEcMTgcgSqH4iDxoxyzELcnDyYkfz8tf2dGk+m4H/VPMjwmfEGUeSfzCTzPBqMqWJtv0eqtRpA5fmGNPsrT7GQnClErlTGIPztt9QkNo2mNbCccPW9cNx96emMp1mnJxmmM8lBE+QPMMUnmg2MMXITRSSGUEV+DcGlK7jr8WY+nwGMbLVH6renpfXSo8SFQj0DbAmg3oD75lW5L/9DnPm689SF42q/rOBcTqQZAvKu3Tb5fs5zkZCWSx0aNSQSmHlKbQrOyS3troPdMOUykmg+g/CoFcyBl6lycU4gKnnO3lv7NYIZF2q5U7V2oCDXvlOXUQEwXH1MwSFHyxYWGjaPcTSNH9auXPqPGakqB8Ip269Ms/NCrZjLGMPexO4j05maCyt55JxyPqsxKmlOR4qOm+Z2n1uQyBkYxi4USTuu0y0uE1K3keOkcE8fqtyPw8WBNc2GTWY4jctgmAVC9hBuJSjK7c2JCuf2jX+OHDq4yYiVoK4/3kmViF5KampYmngMp1Y4qI6FmRaX2UkFqFidxzlqSaHev2d8qxTPFfRv4dkdX4qDifH4jm0EgQ0UV427Lt0+M4bVaSQegP+zONopZPMY7GcIgLOADRiTQZg6zGZEHoGJCV6fCziSYheTbLvQgDrlmniA2SG1IplYdVHv8RzLtrITPysofzLpSMAytdRAqSSD8YyOQjhbMY9SG1Y11W7IAoZ5P2j/McMDswI3XWRSGJp3ViK0UAkj7huc1+vPEKbYQsJM0DPfFnqygFgxBWtTUdcjpwDQU7BEVJ6j/AIY5sxINJDdQN6bd9zhsKmcjD/DEB7G+lpue0Mf9ch/EylyCU3SvLAVWlRvuScpzQ4t0RO6XxAySqiqBwNS3T78xowstpGyZc6UFNvZjmyFAU0t8q9t/mcbC0vDk7fxOFU+8l6MNY1yO34rII19X0iwAkIICx/EQvxMcxNXqI44WeTk6XTyyE0PpZ9qGn+eouIhgmRYzSKOK4gQL/sQyrmrhqMBFm24xyeTFdb0jzBIxj1eH/csE9eICSMlrcGhZirUqpFOuXYNXjB9J9Ky08zGyu/Lm5CahcsaCsa96nqfHMvVmwGvTino6yyyVBPFOzMBX6F/5q/4HMLipyqVuMYvJl7qIlUmlaeih6/TkJzVFAUPJRUjp06+GAmgkCylc9trunzxLp1rBDp8pZ5uL2omckVLVcklgx6H7K/Dmrhk00pESMuNyJ4ssNgNkubV/Ni6grTx8tOd1+rIfQEoK9Vf0zv6i8v8AJRuGXRzYBKsZN/xIhiyyB4hsnGsqbuwihQrFLNJGEEh6tvRfh5fEx+Ff8rNhA2ebRLZMbfSvzFsVa307ywJrLjtcOiNKz1B+Lk47bcczY4hXNwpZZdAsaPz5EJJ9X0oaZAv2JioEYA/35xZyrb9hjkgANizx5T1UJvMV0lrbyxSUZ1Ik27g7VzFFuS3/AIjuZNMmeQqZVniC1H7LJJWgH+qMd1pu3165ayvea/GgiaKgP89Gp9Bw2UUpxajdXFleo8Hqsbd2hjJKgyIQy1NNsQd1IQGiR3Ut1LDeaascNzBLGxWYtU8eSjZVoOS9ckSx4WtB0tFv4zc6fHGkwaGVo5C54yqUOxA8cFhab07y7Y2d/HPFbKpRyCw68SCpoa+B8MBK8KItPK9hp2p+vbjg0DkRkU3A23PywWKRwbp/SO3At05MsSKoYncjiKYgsyrSfCHANQYXYH5o2EHdBCnaF3tYGP2mjQkj3UYCkK4U7bYUu4niaDAinEe22JVwU+GQJK0W+QFCcCRErw4rQkVyMmQiU58tMp1SMBhXi3f2yktjx38zB6Xmb61HP6UttfCRQYfVUkQigPxLtTM/DEVbh5QOJgkegpMfh1MhRWi/VwAP+Hy3gHc0HHae+UNPt9MElj9aNxC9X4vEqjl8NKHkTtxyE4DmzhFuJLldRgv4NSVHtkeGGMWqlAju0hrWT4jykb4sTEMyASnvleeGw1K6v9QlGpvclCsbRJEEKuXJXd+tcryQsbNkeb1TWtbttU8nvq6MIlNRMhI+AryPxHb7OY1UWy9nl1xrGjXMbwTT280Eg4vG8kZDA9tzTLhEtct1CC6tbHzxrsTXSWyrLSkjooZQBQb77ZXwniaSKkyAeYtH6fX7ce5lT+uXcJbbVR5j0RQWOoW3/I5NvxwGJRYeBfmKLceY5vqrpJAatzi+JCzMdw29aimW6YUGFC2M7nxrmUVeiee9Qs7jyZo8UVxG8yRWPOJWBYFbZ1aoG+x65jQB4iz6POt6DMlgzTy0sEnljUZZpY4mt4LlI1aXg7F4tgEG71Y5hTx/vLawPVbCwD4ZmNls+/JzU7DTtfvJL6dLaJ7MqryHiC3qoaD3plWYEjZQd3r/APjTysKf7lIK9/iP9MxeCXc3cQQ175t8oXdpNbTalC0UylGALdCPYZDJiMhTEyCVeUte8r6Ho/1GXULZZFd2bgZD1O3LkPtU8PhyUMUq3a8YEU3bz/5SqK6jF7UD/wDNOTOOXc28YWN+YPlOgrqMfXeiv/zTg4Jdy8YVtO88+WLnVLa2ivlaSaVERQripcgAfZ98RjlfJEph5p5n1HTF80W7x0Yqvp6gGDcao3Fq06/Z3yqUDu4+Y7p35182+W7zypqGnWM4Z3iVYYUidFqsimgHEAdMyMeOQPJuhKIDxf0Zv5G+45lEFjxB6D+VPmDTtFh1hNSkaBbpIhDRGbkVEgboD/MMqyQJTGQBtg9i13bXIkSN67qRQjZtuuHJDijRYSILNPJmu2Ol+a7W8uTILeO1mhkkCl/jZSFUADpyzHxYzwn3oga5vSE/MzytQgyz1od/RfrQ4fBk3cYf/9HnIjiuozOk/CJCysJECkGuwIbbf55yEiYmiN3WHvXW+lTyyOZoViUx1VYmHJviqORUjb/JxnmobFIulIaPrhDPIeMs6kcQxaNAppRqj2/ZwnPj5DlH/TINr7Hy7cfDFNJ6rSHnOkfKgGwpvt2+LI5dUOYQSqyeW9ThuWNhDJC7A1kd0kSn7IAUAhf8nEamBFS3WJIUj5evLkq2rK0yo3P04gUSneo35fZyf5kR+j/ZKAoL5SsrfT5beBGa4lLSNdyVLJGCCFQUpy36Yfz0pSBPIfwqSSiz5E09baKO4iN08Q5RSuzKwr8R4hR3/lIwDtKXEa2BbIyIQB8oaULeJTachGS1xIVcyeKqv7PxH/J+zlo1875szmJKrH5b8h3jRNf6VdW8zNRmgdkQitCWBVu/XMjFrskNieINkcw6o+y/Lz8sZ3Ag+tSBjuWnICgEg1rCOmZMu1Ijns2eJE9Uav5P/lw7sPXuFp1/0pQKnpSsOTHaUO9mJx70Dffll+W9oDxe9lboQLlAFPcn9yP9jlcu1O7dEpjogpvy78ievboi3vpuObH105Ffpj6H9n4crHa1bkNfigFHxfld+XcsBuFW/CKxT0zOnInxA9L+OTPa8atn4sau0R5b/L7yUmtx3VpFfJdWMomiMsqehVDVeRWIH8f9ljh7TE+ey4coJVdR/KXyT6nqXMt291dSHk0My8fUY8jsI24j5nLJ9p4xte4ZGosQ17yPPa3QtdOWRNKXZpiwkIBFSealfir+zxXKf5Qxne7LCWUBf5e8k+WbmQWeqSXLzN0ZJFjRqUrQGNun+thPaNeqlhO+eyZ6v+XPkjTGg+rrc3NzIQ6RNOjJQGlG/drjPtK43EscuSuRSpPKvkuGVo9Rsr6GZQCfQuIilG8VdGYUG5w4+0CRfNhDMOqY3nlDyhBZR2EKXdzbxObpwZQ0itMip+xGg40QHIZO0p36aWeU9EPZfl75RupZK22pJBGGFVmh5M6j9nlH92VnteUa4q3QM+6c235QeRLpG9G7vOYA5xtPCHWvSoMfXtmZj7RhIXbkRMSLBQGo/lf5QsZPhN7cKOXMepETUDelFXpmLPte5VFoyZaOzHl8nyXfBotHeC0LkrIGKTcAftsH5Gn8u2TOvEDvPf8A2LXHIb5siv8A8vvL9m6CGO6uWFGVX9P06gUUuVXfp45Tk7TN1EimWXIRsF2l2V7o7y6lDZlTwWN47RkEpHMMv2K0qe3/AAWY+TUDIOAy5/zmzS6k4jt1ZCdc8wtJwYSrECoaYojAMTv8KjmeP81MojIiNCX+a5w1uM7lj2u3+vXjTyrYzTekvBpn2Do5IqFHGo3PLfLtPwRq5bycTNrJHaPJBeTvL9kmpNeXcVzpptvTlijh4LHKUapDeqwqB/rZszrQBRILHBk7yzfVvNFjBbj6h6ks/Hm8ZVD8INKfC56775RLUg/S2S1A6Iuy1WO8WO9ZWSGVEYFVRiP3YWp+Jd6r/wADkZ5RCV2zGQc0xhv7WOSG4ZnaNGDt8EdGANaU9T9qmVZtWDEi22OYA30QLec/0heSyRaE9hal3KSSegoFDQ8Y4jX4v9X4s5+eilH1eJxSP83ic6famKuqGvtWjkhkdbEtMi1jnAjY1Y8f3dasG4j/ACclhwyEgeL72ufakeAgBIk/MKzstV0r6/aO0Npdwzcq/tQmoBA6jxXOk08snOxQdWNQSd2b3/50SXTo8Gm6t6EqP6UsF3LErAGtQgdaDj+3T/VzPGugOZptOWPehtb893MltBZQ/XjLexBFnaSS8FueaszS+seLEIXIZv8AUymHasJiX8PD/skSlEb2t0zXNLmn+oveNcXKkKJzAilix7qpCrTMUdodTsEwzxJpOJTpiRK55SHoUWNSwPiVrk4doQJq24yAQslzpBcDgVr1aWICn3HBk18Qdi1HPFQvb7SbSBneJnKgFQsZQUI926fRhlrQB5rPOAoQa95daISyTGCXosXxVr23B74jXCrKBqIoix1LQ7uYxxXbRuo5KAGBHHr32OAdoDqmOYFbqFzDZSK1JzCVL+uR8NQeg3O+HNrxHkLTKdJdrvmOOwEbRLNcyzfEVZQDQ7k7A/ZGUfn5TlUaoNGTUUdm5fIujeYI31y5uLqKS5VWYGaSEmi8QFRXC9F8MzRrOGO9NwlYu0ss7HSm8xJdyy3kJ0iIJC/NzFIUUokcimoP2qu2YuPtMg3KqaBmPFudkFF+X3k2eX975l1WG4YqXh5gIGc9E+A/DX7OZmPtTHIcmQzDvTmT8j/LiCsnmbVl+c0f/NOXHXYwN6bfixu/8l/l/Z3aWzeYtalLEKWSSMgE/Ne3fKP5TBO0dmk5hdWn3l3y15Ei0fWbS31+/kS/iSC4a4kjEkXFiwMfw9/5viwz7QiBZDYJiuaUp5D8jRaWdUj1fULuZAQbCSccC4rsSqq/Qcspy9oE49vTMtU5+nYsee30q6QR3Ma2qmhMcTlZFQn4fjJYKxHxfFmPHPkibszcOOeYN2Uw0vyn+W+o6tHpsNzrTSSKWXncQhiAKkhQn2f9lmd+dlz4fS5sNRxHmz3yt5T8k+S9ci1uyn1K4vLdHQQTuGWko4NVQg8f5sjk1sSHIGQDqlGuan5Z1jXLiPUp59Pkeb1FZVSRdl40IahAp3ODFr6jdbOPPODJEaf5U8lXY52+uPISPiXjGCO2+2ZA7QiWUeE9UXF5O8rI7MmpyxmM0JVYt6j3BOR/PRPNmCO9Yvkvyd6iIuqTfF8TOBEKClRuFyGTtGEVuPK1O6tPLeiE2yzT3EbOqvOyxOSJKABW4028PtZg5dZHJMEEsZZRHZOtPTyxLol/o6ajcyWl4CtxG/ANGxUq3E8QOVP9bMyGrgd+TOGUEc2G3P5OeW4KPbX1z6DEHlOi9zRfiXY5LJqJDlIU0yxHnxIjXfImlapqWo6xLLJ6kshYwooLcafDWu1SMxc2vlEcUSEZO+0ptPJHlSURrJNLHI5+GBl+Kv0ZVHtHLL+Joib6psv5UaCyclvXow+IcU798vGsyfz4tvhf0kFcflr5ei4SNdTSRluEnFI34b9wK/qyEtfOJu4rKB70Qn5X+VPS5reM4NKkJH1+Vcme0p19QUQ80Qn5S6BLG00dxL6Y2qVi2p2oT1yyGsyEXxRZeGe9TH5S6IYg31xkUn4eSQb/APDDJR10qsyijwfNRh/LPQZWpFqMzjcOqJBRSDTerrlf5+zdhRDzXp+W3lj1nie7nBipyJWFd2NOPXrjDtCZJFxCBAXzRiflV5aozrPO/HdgphBFfpyz81kP8cWYxX1Xn8tPLYm9JnnLjb7cY7dPtZV+anf1xXwvNGH8ofLhZY0uVdyoYxGYK4r2NaD8cP5jJ/PCfB81Gb8rtGhLyvbTuBUyN6sTj/hWyuepyjnJEsKg3kTyq3BFtpz4jYNQ9xR/iysarJ0kw4AojyN5S9T0nt5lB2H7xamm5254/nMt7yTwea6z8u+RbPV7d42dbu3kSVYmlUHlGwYVBb2yX56Y34jXuYmIvcpZq/ljywsF3qM0LvdBmdmEgCksxbpyrx37ZGWslI7FZ0WIQX+nXssQTTolsjxS4lDFXVq0opqN6DLzLJHnM8TikkJvqI8jWcqJBp17OgAZ5SzKFB7bAr18TkBqc8jtIU2mYTTTdD8lT6WLue0lVpB6kSiQ0ZD0+02xyk9o5I3En1LCYPNA+j5IaV4xZO/w1jdJmA8KMev3Lhjq84FkoEwFkmmeWYFkaa3JC0KLykB+I9BuOW+QGuznYFBmpWVz5cla5A0zi0a86MWIKUIqK5bPPmFermg5N3//0ohF5k0QTOj+msPIsIwlRyG34++cRPS5C67ZJ9W833McxFo8cdsjkh2QK4BoCAcysOjBjUhugSTODzlYXFujSOtOQFFqtQNq+GY89FIGmRkETL5k0y3jWITlvVryCCpUEfD/AC7f8NlcdJM7p2QqeZtNZuEUsqLsGY1FPl1yw6SQQaVTqtk7/urksNquSVIApkPBkOiLCutxYLRri8ZkmBY7gAVNRypkeE8gE2FZNc0aFEj9SrVqKVJqe9TXbB4EzuzEgqNrFojcjcCpHVQSfwGA4ZMCQhH1K1lVjE7STqwI59K9+oOS4JCkGQVIr+2YhXYRPwPNAQVFO1fnjKBKbBWRXfrtVJYwYqGjPQE08R/L2wiBioUdRv4Y4SEMUkrU5RMQVZt8ljgSfJBk5NSt5oGEsKLMq8YyOh4/ZB26YmBCJbpNe6/eRXKtIVZIyGXkKb0oVWh2GZWPAJBjuE80/WLCezWVmRHHwmMcjSgoKMeu5zFyYCDTMSVP0tZD4kuuRX4eDdd/Db9nrkfAPcvErWWp2F0hVp4wsbmiMRUkmtatSpOQlhI6JRlxdWSxhy684x/d7FgB4Gm3+VkBGXQMiVOSTTZAqoOUvLirKwBqu/w164RGTEgLL+XT4UHAxer6n963E9FoadetaZKEZBEqStbu4a/VkCURgBCGCihJHKtcu4BW6IojUrmaG4t04RxggtHKzjiWqOQO+Qx4QQUl1xf3FsAEECBqFmUrXia7mp98MYdEA1yVJPMcENVKxc2FCQQahd6jr8siNMSpLcfmKzPSaOJW+EF6/E/dq/yjE6YrHZx1nTDO0clws5koPT/ZJO1RU8cIwT5opfJqGnszLBwElAFAKgVB3I99sfCkyruUWuIkYMJoEaRQSjOOQC9aVB7nDHEUCJVJtXX0Vhlkio5IYMygU38OnjgGA9Ay5NJqllcK4j9Jo6HkC3Y9qdcJxkLYaWz00uWkto25jisiGjCg+yDXGJlytIIDoZbNbcJCiLDHReIfYAfT4YzEiWRkF9vqMV1KsaMskYFREXBJG/7O32chPEQGHFeylLp+ntLLPMvosikIoYhdzxPQjxwwkaphS1Y7Q8lt26kry9WrUU0DfENuuSkDbIkdFGLSbdKTGKB5BVJHkIZgvTam3tXJnJKqsqEXyQFzI0TBFJWE0VVX+VaeIyoxKbRcj28loqSBY4pR8ILca0HQg77ZAYyDakghDC0sOScE4SkghwNzvsK/LLakgABEfVLz1PVe+V0pu3EKaUIXp/LXBKI7mRsdUKdLnuJ5FF2si9OK7Ny2NOVckDQ5MS4abfqOSz+oI19Liep4n4uW56eGRkR3JJXrpSQ0J4KC3Op4n4m/a3+ziZEsCFCy0xIfVnjuYgi19Z1Cs5HXenv1yUiTzZAJvaxlbeONJSUjHw0+yK7vtvlcgbbRM8rU2jpEGEwJHx/F14/LpXBwMeEIJrjmWjjulAbf0033Pf38ct4O9BKq1u7WpE85WNalkAAb6e/yyG3cxMtqQ0iaZxXmr8IwVAC70O/I/wA3TJAFja0rplxGsYvJY+TVUftDlseu/TJDbdIk5vLUE0Txw3isJqci6BjUEGoZgG7YRmo8mQpExaDb2kkxSdQ0lOcQQ8dhTr8WQlk4uaCFi+WtKuIQzMzKx+LiSA1du3h44RlIRGKx/KumOxlMIaUsBU0AIXalKfZwjUSqrTQKIHlq1EkdwlYp+ZLzKQGNRTiG/ZFP5cAzSqk8KI/RnwBC7NMBTm9CwoKV5EU2yviJK0Vp8u+uknqAMz0HFgNjTryO9TkuMjkjgbstHhtnKC3C8T8NBsaihqNsEpE80xjTo7GSByTIuwJ5Ur8VdiOvviWYQ62gNw/qzmjkqqqdgPeg64CA0rp9HMoj/ec0iIZEZv2gO9Ou+Mdr82VWp/4agaC4nf4jLR5KfZXwIP2h0yfHLaujIQbtNNijRbT1CI670mJHjUchscZ2d2PRMYtHtY4puDMpkasgZi3IDY0PbIEX8GQipppUlamdI4geKqOtO1T1yPCGPCsuoJLOP1mq6R7VA5HhXeg2riMYUgrbA2U8jlJldD8XwbfH4GvxHp8WSMCEA7rrhGkT/RyFlRt1rtWoFSenemAQFsjy2XW8NyIF+syhXc/CoPICSm/TEgA7KCURJ6ckvppyUMo5CgAJ6daYBBPEUHc6Fp7RuJGdVcFTRiDXr277bZOM6Y8K2z0zTAX9ISersJXlJJLDw+jJSkSilZtJDSExTH1EWiKWoCdyK198rBSLX6XpBMjyXgkNSPVRZf5dqAjf/WyQEeZ6JiCTuiLrSLOSUXFm0qxk09NpCxSu25OSkRzDOYrkls0WmQJNHKGAl+Fzzbff26ZGywGQhuOWzhcsKVRaIF6U8BTr0wCJtESirawS6WqAPzX6zHI8gUcR136hqD7GWjGSmiUlNpost09wlvG0przahqq1rUnHjkBVtR5tx2WkSMfrFseAYiOnIg1BB5YiZHJmA1BovlzTrZoLKCWWIuXLAcveu+5AyWTLKZsndSBe26rNa6MYvTaoe54KkTfCWYdPh8aZGyOXRjYQ0h4l4QqBFQqqk7KWXbb/AGORqzaLpAWGk2Md16qWwSJCUkkib9nb7S16++ZE80iKJWUrKa3senmz9UQlkK9K8SeR23OY4Jtl0Q1vcaeySIbUC4RCU32LEfFvt8stIPexf//T4c8N4wAhIaQFuTtQUVT0BzS3Gzbqg208E8YWY0qN2OwJH68iIkHZCIttOWGMjmvE7py7D6PHK55rKktahJCnBSzPQUWnUU+eOIEoU7f0rklreVkII5I4oCPn7ZKdx+oJBKOMEsUikOSd/hB6/PKOIEKVdjMsZWRlao6eAyAq9kIWSS4knKwzKkMY3G1QewHfrloAA3G621ELppf70oVbchq7eIwnhA5LaMWahIDni1KmtTXKTFFqM96to6iSWryHYdqE+PbJxx8Q2DIFb6Uc10twZkZUaiVqRWnXam+GzGNUqJYoVFXVmBFDsd+mVC1Q99fi3RVkLHY0IPQV+eWY8XFyVAJJBeOv76h/Z2Jr/rHLyDAckkUmUMMsQFZeTrUKKUFKUzHlIHoxJU4X1ZJg0oR4qGiqK1Pv4ZKQxkbc1tXVZANlFD8XIdRXwrkLCQVkSgljyYAHjxqBv3O3z64ZFNr1imZQUkLAbFvn3yJkB0Y2oSM8TgOCwagZj238BlgohbXpC0klCxpu3cewyJlQTaIksTyD8i3Aj4Sdqg7ZAZEW2fUWQh4w22xpWlR1ONik8SoJFAP7sFjsRx32yO56otdIC1WQBD4dSPowA0xtqMqCRQlkGzUG5HSmJJTa2SYHZoeRJ2oOnfCB5ptZ6Cs/IghS3TtSlAN8lxGlte6gtyXjXo602P35G0ElTMkyPWKJA46PSlR4DJgDqyBX/WCUHqrwb9oE7V69Dg4d9kEro2Q0HU7swAFBkSEKX7uKUyQsQ5FGcHfr298luRRSNlX1nZgrNVCtfiNSfDY4OFNqhuIEDKQTXoB02yJiSUWoXLQvCCpIkDAluRpSn4ZKGyb2UbNzHC3ryBqUovsa06/LJzFnZFohmtpal5XfiKorN8IJpgG3RNr47ekgJuHCk/D3oeux7YDLyTaJqnGQCVyrCgofv+7Kvgi0uWC+iukk+s/A4JYn22HTLyYmNUto0SzxtyMjRMaV4EknbenzyvhC24zFpVdJnoB8VRTenXp1x4QE2px3MXqmNmARgeQHw15deWHh6qCiYpZoSF9ZUWhCAGhow6YDEdy2hJ0D1EkzMUY1WhNCdqHtvko0Oir44LYc5Y4zzABFKqdvlglM8mNoiK6EcBVnk4n9ksWFfp8KZWRaSV312cssbSSlwKBa7Lt4HAQi2zcIjlkpzSlGZqb9+njkeG02mEGrrEih4fVoAABThQnfc5A4mXEjYZ45i0LyTJb8aBAR33JDAg/DkOGkiaYWvG3URxytO0hBVn6KKjYLtlcrLKJ3Xp+kYbglY+SN4bAKTX33qd/8nEbMuqOhEzfFJwCrWqg7iuwPbGmQBdduEQsGPEnYBRWopvgpBQ8t1bKm8j+owqqg9TXr498kAjiCks6qysPWfkeIB6qDua+IxIRxK884oDHGvqtQoDsa0rucBDIleZFEYfgqt1Kgg9u1cCLCHjjij5tHGGB+MndTXw6nwxJKBSvJPGiFvUPpKRULtyI3IJxBLLjQd3fqkIaGBpTUBoH2NCRuKihyUR3sbCNGowFOYQs1K0rQ1H8cFrxhTGpxPGzxwMkgrVWIArsa8gTikzCg1xbXCFZLdmr1qSQK/I40UcS9LfR7dIwtuIubMW4A1JO5JpvhJJ5sdlGRIFldYRGqgByHFVJDU3yIJSCpGRY5VKNGF3JG5FKePbfDw2GNoqLVoQvPirlaF6LQ7ioFScQGQkF7XySLxEY226/FxHxGhGAimRLRu4yUaRY3G3JVBoK1r07j3xFptCpqpEoRYkElRymI+KhHw0rXvjwkMeKipT61dxrIqwJyWokPKoqaUO3jXfJCLEzWWt7LMgeWMAbVYCo3HYVNMapRO1Ux2MxWR2+JVoF6AbdvY4CuxQWoTCJFkiHJQQoVB9kE0I37UyUBbBfPdwxqqGYBuJqCVqO5FOm2JiSyHkgY9QtbeZXD8wlXMjfEQSOpNN8n4ZLGlzPN65nVSYACzlTRSdievWnIfDgrZatauvfU7tIooDHJJzDlgxqCKkKwpxqP8nJjESLXipWt7i3uTxmYnmOYrTlQDfcGvQf8DkOEhQXCysrluCylFVeK1ovKlRsD8Rw8VLzbtdJtbepS7k4yVEnwAmij4Sa4ZZCeieFEk2VqiqiMY2+Lc/CeWx6CmQJtlwoe3n08SPcCzZwY2JZzsOoqp8cs3Twh/9TjE9xxfglOVTSvY1365z4j3unIU59PjmZC9OJJb1FNOIpvhjlI5JulaGhkihDGRFFefjkJciVUp4GNweYNaGvZhy2GTjLZbULe1hgl9IMQ/E8anfrk5TMhaTJGLUgL6hpX4Sdvpyk+5i3MAkocyckHTcEUI6mmMdxVIU4GieYsK8SD2ou23X2yUgQEuiEVtI5L1JFQNyQD06YJXILTa8lj5UJHXY0NSe/XE81pDX1ks1JGanHvWgJO9OmW4slbJBIX2kBihI9QGIKabd/EYJys+a2rLb3HEOsgWMLyDEgUY5XxDuQh5bKa4hKLJ0apJqeR8N6Uy2OQRKYmm7fTLqKSMswFDxZa0HI9ME80SCtpwljVoy7F0pV9+3htmGcvNBVrWyS15py5jdgpNaZCeQy3VdIbUsYiCWf4hvTYd8A4uaLQ7R2bExrJxrsQepGWAy50i7X/AKNDjlDOYoqbgHxweNXMWUqkcQVqvKvEHiF9/p+WAm+QS2ArPzVixUcgB0I6VOR5BStSP4W9Q78eRHia4Se5gCpw2U4kr6xIO5Fex98lLIK5JJREelSTTLSRkrUniw3K7mhPU7fDkDmAHJlGNqk9vEkJaFJXl9YxCPYsUK15Gnh+1gjIk71w0yOPbZCvcRx8QwoDUKCaE9qjLBAlgApJcR3Sc4w2wpXwPyyRgYmikBpo3jcGKUhhRQO/LwyQLMSAV0g5o3xDkaV8fnlRnTGRtzQyqAoJO+/H2P34bQh7pY+aRzV5yklifs+HU5OBPMIUhHEpeTmxMg4Kp8BSmw22AyZkTspK2Cr1jU0Irx5V6de22Mtt1BXRJcMVJZeNfi5GlPvp4YnhSq/UtUcqAOAPau5H09sHFEKrfUrqCF2dA7V2X2pU5HjBKqRKqHEkXFqgsD0qdgu+Kr60CVhHMV4oKct/ngrzQQow6okhaNkCkA7FgK18NqZOWEjdbR9tJUclj4q3QVBp36DKJCkhWNy05ROAAjJVeIFdzyNfvxpLTq9RxoaA7npvgGyhTWB1lpUEkhSRuSaZK1LS28hYhCGUddh160rhBRTc1sSih6FlOx67Dp0xEkhyQMo+EkA1NRWgp12wcSktCZOfpF2DDcKAaH5k/PExNWhWiZWkT4nVBvQ7jfb6OuRspDkAkZjx5FWNGHcD3OE7MSpzRICOLBnBowpTYb1yQVtYkY8KsisteR78abADE7JC9JZo6ULbA9TsKfLI8KolNSdyGRwnbiDt92RliBZAo2HXXBCer+8I+yTQ+9MrliTxJkuqSoBRuRP7TEUP30yvgZcRVY9RcMxkYfF8Kim47+ODhY8TbXCcVeiPyYmoNCPAFjkSVtUM8pK+pHRmP2gQeK/TTIpVXt+CIyVYvX9qpHXwwkqXOJw/H0y0ZG7AhgdqmqjBYSQ0Udj6gjNWJ4AVIG3th4gilG4S4KenursdyegpWgp/NT/hsFpLUVtcA0kqPSoUY0J6b9NjhkGNFCSOAwtiGKUJ3B38STt3yKKQtlqkLyC2QOpWjKqrWnWtaVH35bKBAtCZFrQyPEJ2UqQZuW3EnfqRkK2Z7KohgRy8cvqCMlGWoruKH7hkaARThZvyUsw9MqSHFANz36kHESTW6mlpDydeXwVHwEbkmpAyQkEUqPaiFEZ1UF/gINKk/s+++DiZGFLf3Mboi/CCvIKOqnfx36YbWlryNIvJUBTmKuDUV67/ADxCOFFLbyrC7NErSAlwincAU8O3I1wlnGNoK6XVmWR4bWP4QzqqniCuyhAB8VeWGNXuWXh2FCwaeZmhngkSWhYuaFAan4UII6ZKUAORauEq9vp1y8TbhEIKsWrsQdqZAFeEr57C9MkTF1KKy+pCVNXTqTt/N/k5IEDmngV5dP0mdi8cC15VFasfs0wcfczq3W2nKLThBaxxpuHjAoCQd9vDBxEsQOiLaJ1Q/Z+GgCU34r/bTBaRCkNcafbytG71QqK812Ox6NhEypAQw0a19WirTaqsTxJPfcDvvhMkCCtJpnp/GT8Sg7nqB1+EZE2yMacbWJo1TmRI5+JjQe+StG6ndWc3oLCFUuzUKdQBSpYVwEqonT4vgdY2rxbmp2/ZPEUrTDxIf//V41erak/bVWq1D8RPXftmghxW6kqSxL6Kcphxp4NSn/A/fhJ3U0q2MUIuAI5izdSaMB8umRy3W6oq7U82KODJStKGlPDplOOuvJiUMyRNx5OiS9qVpX6A2+Wj7E0tuILf6tzW4T6wAtY1EnJg1e/EABP2slDn5JAU/SrabzKBtzIFfi+kYb9SNkRAjegvoSIU8AG+mldsrlV7pKnKqhjV1JpQg8qU7HcZKKlT/ecqbdNzU/0yVBi16bGZKSkEUryDcT49iMdqSLRTiMKKlSKHjXYdTlYClCy+tROdDBtWta09tq5ZER+KNmoUBZBG7CMyfaPLY9ui/qwy865Kio0b0pKutanmfiryrt1HhlRqwqvGs44+m4MfGg+1SvY9MrPD15pKJpcggEqZeI378a9tsrqPwQsCziVW5IdtlbrX22yXppQAl9xGhdDJIBRySo5b+I2HjmRDlsu1pnB6gtE9KhavxDfx98xpAcW5UqJEfKL1Ch3JWv8AN3G+SrnSUTb/AG3MfGtBQDpSuVyG26Gz6vqFmoQQeadgK+JwUKQVsoueElGBHfjXrUUpt4ZKIjswKMtzdiMEKC/da/xymQjfNsCtp3I3hEQIuOD/ABIRXhx+PYj+XI5AOHc7NkLSK7Nvyb1VWo+yVJqT7Uo2ZsAehauq/TBBWcxH9r94orTl33I/Vhy3taV05vQqmMIxB3Wu5+WRiI3uVU7UXRnJcqr7bDkTw964ZCNbIVbo3YRvQUMxIE1DSnv92RiI3uVS29BKL6xVQKemX5Enw7UpXMjGBeyqsZuDbgMAsXYgk99698gRG+e7EoaIXRIrQD4qA18evTLCIqEcIoyq85lWI/b4gkBvoGU382Saxq/KHi1RQUrWvT5eGYprdV1wLkSfaBXYsWr49MEQEoG/DmT4ywlPLdK1B9uIy/EGO6BCt9Xbmx6UTjy5cduR3HKuXbWhRjigBoJyzb8XIcHj32IyciUprpq0T4W5Kft0rQD35DMbKGYRh9WrelT1KniB14967dchtSDyUIHu6kGNTAAAhqKn3/mwkRrnuoVJOAjH2WqfiIJFKnalB9oZGIVZMGD1SjbjkDUCn3YYhSrW5uBCgRVLEncno307ZGQF81XWR1MMTOqMNgASeNd9xXb50xyCPQqi0KG4HIRqNqk+GVUaSW7kERngQ0lfg7b9qVwQG+6EucS8T6Z/eileFaH58RTMgAKW4OJHxgLJv4kV4nwxrfZQ2irQfEpNSDy5bbbnpgkqyWIs4ZJikatUoikhvauWROyUQFgFQrcpiBua0A9qjISu0Ier14qq0q3JifirXbtXGh3qEVMJTAPXZVkrRQvIj5nbIGrVHRc/QFOm9ORNOu/auVTAtUdBzMfwUXcGux7nZq9spoMgioyjbFeA3oQanpvkCEhMYTF6JCCjcqhiSTWmy0pgDPoheUnqEcD6nEfGD8+NQNsjIDvYm1WNnJUsoV6KCKkmm+5ptuOuNBLrh72gM8a8qqI1JNAOJ3/l6UyZA6JKnKlx6WzktyUyEV5V22+EZFibWP6ProDx4hPjZtiTTYEUOTUqGnRWIuC1rMGu6EBCCDuTxIJHQfF1yU7pApXZLAzH1pEW55Dn6oJOx2rUdz/wuV7suu7Xo2Zc/VrhlUMQCA/EtyBJ+z9GE2pV7mFeJZrj91yUhCrfaDCgqB0PfAqlCn72UTO3qjjzJrUgMePbuciQxHNq8jt3uSbmYQychRaM3xjoBtTfv/lYYhlNSmjsfUYCat2JCasG5FeO4oBk+it2KxDn8aMhPwCQNQGu/KoC1riyFplai7+sSm2P78bSg8iDsDVqjpTBRZxvoqrzCMGo0ZBoRUUT4eXvg2tMTKlBfWHIR8CA9eRrU7bgDqMQDbA23HwEu+9UcjqFHWoG3XCQjdDKl0ySESemwIIVwzArT4gNulf9jgARu1YgCesBJJQ8lFaA16EkdMK7rrd9a9N+UY5LUL9kclr1O5pkiB3qOJDRtraFlCiR1ZjzrTnUjYA0Aof9jgqPej1ISZvMPq/vkHpAjkFK/F8VNiP+CyYEK5o9SZqLtZ3qeabGIioPTpTpkJBI4lCdL43C/GFkK/FzDGg79skFNqEolChWYNIKVdeVCe9BTbHZiqypKQtXoApKkh6Up0ag6fPAeagd7cf1urFKenQhweXTx33/AONsI5p3f//Z"};
    \ No newline at end of file
    diff --git a/docs/index.html b/docs/index.html
    new file mode 100644
    index 000000000..e83ee3f9c
    --- /dev/null
    +++ b/docs/index.html
    @@ -0,0 +1,266 @@
    +<!doctype html>
    +<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7 ng-app: docsApp;" lang="en" ng-controller="DocsController"> <![endif]-->
    +<!--[if IE 7]>    <html class="no-js lt-ie9 lt-ie8 ng-app: docsApp;" lang="en" ng-controller="DocsController"> <![endif]-->
    +<!--[if IE 8]>    <html class="no-js lt-ie9 ng-app: docsApp;" lang="en" ng-controller="DocsController"> <![endif]-->
    +<!--[if gt IE 8]><!--> <html class="no-js" ng-app="docsApp" lang="en" ng-controller="DocsController"> <!--<![endif]-->
    +<head>
    +  <meta charset="utf-8">
    +  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    +  <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    +  <meta name="Description"
    +        content="AngularJS is what HTML would have been, had it been designed for building web-apps.
    +                 Declarative templates with data-binding, MVC, dependency injection and great
    +                 testability story all implemented with pure client-side JavaScript!">
    +  <meta name="fragment" content="!">
    +  <title ng-bind-template="UI Grid: {{partialTitle}}">Docs</title>
    +  <script type="text/javascript">
    +    // dynamically add base tag as well as css and javascript files.
    +    // we can't add css/js the usual way, because some browsers (FF) eagerly prefetch resources
    +    // before the base attribute is added, causing 404 and terribly slow loading of the docs app.
    +    (function() {
    +      var indexFile = (location.pathname.match(/\/(index[^\.]*\.html)/) || ['', ''])[1],
    +          rUrl = /(#!\/|api|tutorial|index[^\.]*\.html).*$/,
    +          baseUrl = location.href.replace(rUrl, indexFile),
    +          headEl = document.getElementsByTagName('head')[0],
    +          sync = true;
    +
    +      addTag('base', {href: baseUrl});
    +      addTag('link', {rel: 'stylesheet', href: 'css/bootstrap-flatly.min.css', type: 'text/css'});
    +      addTag('link', {rel: 'stylesheet', href: 'css/font-awesome.css', type: 'text/css'});
    +      addTag('link', {rel: 'stylesheet', href: 'css/docs.css', type: 'text/css'});
    +      addTag('link', {rel: 'stylesheet', href: 'css/animations.css', type: 'text/css'});
    +      
    +         addTag('link', {rel: 'stylesheet', href: 'css/prettify.css', type: 'text/css'}, sync);
    +      
    +      
    +        addTag('script', {src: '//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js'}, sync);
    +      
    +        addTag('script', {src: '//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-touch.js'}, sync);
    +      
    +        addTag('script', {src: '//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-animate.js'}, sync);
    +      
    +        addTag('script', {src: 'grunt-scripts/csv.js'}, sync);
    +      
    +        addTag('script', {src: 'grunt-scripts/pdfmake.js'}, sync);
    +      
    +        addTag('script', {src: 'grunt-scripts/vfs_fonts.js'}, sync);
    +      
    +      
    +        addTag('script', {src: '//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-animate.js'}, sync);
    +      
    +        addTag('script', {src: 'grunt-scripts/prettify.js'}, sync);
    +      
    +        addTag('script', {src: 'grunt-scripts/marked.js'}, sync);
    +      
    +      addTag('script', {src: 'js/angular-bootstrap.js'}, sync);
    +      addTag('script', {src: 'js/angular-bootstrap-prettify.js'}, sync);
    +      addTag('script', {src: 'js/docs-setup.js'}, sync);
    +      addTag('script', {src: 'js/docs.js'}, sync);
    +
    +      function addTag(name, attributes, sync) {
    +        var el = document.createElement(name),
    +            attrName;
    +
    +        for (attrName in attributes) {
    +          el.setAttribute(attrName, attributes[attrName]);
    +        }
    +
    +        sync ? document.write(outerHTML(el)) : headEl.appendChild(el);
    +      }
    +
    +      function outerHTML(node){
    +        // if IE, Chrome take the internal method otherwise build one
    +        return node.outerHTML || (
    +            function(n){
    +                var div = document.createElement('div'), h;
    +                div.appendChild(n);
    +                h = div.innerHTML;
    +                div = null;
    +                return h;
    +            })(node);
    +      }
    +    })();
    +
    +    // GA asynchronous tracker
    +    var _gaq = _gaq || [];
    +    _gaq.push(['_setAccount', 'UA-46391685-1']);
    +    _gaq.push(['_setDomainName', 'ui-grid.info']);
    +
    +    (function() {
    +      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    +      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    +      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    +    })();
    +
    +  </script>
    +</head>
    +
    +<body>
    +  <div class="container">
    +    <div class="navbar navbar-default navbar-fixed-top" role="navigation">
    +      <div class="container">
    +        <div class="navbar-header">
    +          <button type="button" class="navbar-toggle" ng-click="isExpanded = !isExpanded">
    +            <span class="sr-only">Toggle navigation</span>
    +            <span class="icon-bar"></span>
    +            <span class="icon-bar"></span>
    +            <span class="icon-bar"></span>
    +          </button>
    +          
    +          
    +            <a  href="http://ui-grid.info"  class="navbar-brand">UI Grid</a>
    +          
    +        </div>
    +
    +        <div class="for-lg-view-hide">
    +          <div class="navbar-collapse" ng-show="isExpanded" ng-click="isExpanded = false">
    +            <ul class="nav navbar-nav">
    +              <li ng-repeat="(url, name) in sections" ng-class="{active: isActivePath(url)}">
    +                <a ng-href="{{url}}"><i class="icon-book icon-white"></i> {{name}}</a>
    +              </li>
    +            </ul>
    +            <div>
    +              <ul class="nav navbar-nav navbar-right">
    +  <li><a href="https://github.com/angular-ui/ng-grid/">Github</a></li>
    +</ul>
    +            </div>
    +          </div>
    +        </div>
    + 
    +        <div class="for-sm-view-hide">
    +          <div class="navbar-collapse" >
    +            <ul class="nav navbar-nav">
    +              <li ng-repeat="(url, name) in sections" ng-class="{active: isActivePath(url)}">
    +                <a ng-href="{{url}}"><i class="icon-book icon-white"></i> {{name}}</a>
    +              </li>
    +            </ul>
    +            <div class="navbar-right">
    +              <ul class="nav navbar-nav navbar-right">
    +  <li><a href="https://github.com/angular-ui/ng-grid/">Github</a></li>
    +</ul>
    +            </div>
    +          </div>
    +        </div>
    +
    +      </div>
    +    </div>
    +  </div>
    +
    +  <div role="main" class="container-fluid">
    +    <div class="row clear-navbar"></div>
    +
    +    <div class="row">
    +      <div class="col-xs-12">
    +        <!--[if lt IE 7]>
    +        <p class="alert alert-error">Your browser is <em>ancient!</em>
    +          <a href="http://browsehappy.com/">Upgrade to a different browser</a> or
    +          <a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to
    +          experience this site.
    +        </p>
    +        <![endif]-->
    +
    +        <!--[if lt IE 9]>
    +        <div class="alert">
    +          You are using an old version of Internet Explorer.
    +          For better and safer browsing experience please <a href="http://www.microsoft.com/IE9">upgrade IE</a>
    +          or install <a href="http://google.com/chrome">Google Chrome browser</a>.
    +        </div>
    +        <![endif]-->
    +      </div>
    +
    +    </div>
    +
    +    <div class="row">
    +      <div class="col-xs-4 col-sm-3">
    +        <div ng-show="versionedFiles">
    +          <select class="form-control" name="docsVersion" ng-model="currentVersion" ng-init="currentVersion = versionedFiles.default" ng-options="key as key for (key, value) in versionedFiles.versions"  ng-change="changeVersion(currentVersion)"></select>
    +          <div id="versionedFiles">
    +            <script ng-repeat="s in versionedScripts" ng-src="{{ s.src }}"></script>
    +
    +            <link ng-repeat="l in versionedCSS" rel="stylesheet" ng-href="{{ l.src }}" />
    +          </div>
    +        </div>
    +        
    +        <form class="form-search" ng-submit="submitForm()">
    +          
    +          <input type="text" class="form-control" ng-model="search" placeholder="search the docs"
    +                 tabindex="1" accesskey="s" class="search-query" focused="focused">
    +          
    +          <div class="spacer"></div>
    +
    +          <ul class="nav nav-list well" ng-show="pages">
    +            <li ng-repeat="page in pages track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
    +            </li>
    +          </ul>
    +
    +          <ul class="nav nav-list well" ng-repeat="module in modules track by module.url" class="api-list-item">
    +            <li class="nav-header module">
    +              <a class="guide">module</a>
    +              <a class="code" href="{{module.url}}">{{module.name}}</a>
    +            </li>
    +
    +            <li ng-repeat="page in module.others track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
    +            </li>
    +
    +            <li class="nav-header section" ng-show="module.directives">
    +              <a class="guide">directive</a>
    +            </li>
    +            <li ng-repeat="page in module.directives track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
    +            </li>
    +
    +            <li class="nav-header section" ng-show="module.filters">
    +              <a class="guide">filter</a>
    +            </li>
    +            <li ng-repeat="page in module.filters track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
    +            </li>
    +
    +            <li class="nav-header section" ng-show="module.services">
    +              <a class="guide">service</a>
    +            </li>
    +            <li ng-repeat="service in module.services track by service.instance.url" ng-animate="'expand'" ng-class="navClass(service.instance, service.provider)" class="api-list-item">
    +              <a ng-show="service.provider" class="pull-right" href="{{service.provider.url}}" tabindex="2"><i class="icon-cog"></i></a>
    +              <a href="{{service.instance.url}}" tabindex="2">{{service.name}}</a>
    +            </li>
    +
    +            <li class="nav-header section" ng-show="module.types">
    +              <a class="guide">Types</a>
    +            </li>
    +            <li ng-repeat="page in module.types track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
    +            </li>
    +
    +            <li class="nav-header section" ng-show="module.globals">
    +              <a class="global guide">global APIs</a>
    +              &nbsp;
    +            </li>
    +            <li ng-repeat="page in module.globals track by page.url" ng-animate="'expand'" ng-class="navClass(page)" class="api-list-item">
    +              <a href="{{page.url}}" tabindex="2">{{page.id}}</a>
    +            </li>
    +
    +          </ul>
    +
    +        </form>
    +      </div>
    +      <div class="col-xs-8 col-sm-9">
    +        <ul class="breadcrumb">
    +          <li ng-repeat="crumb in breadcrumb">
    +            <div ng-hide="crumb.url">{{crumb.name}}</div>
    +            <a ng-show="crumb.url" href="{{crumb.url}}">{{crumb.name}}</a>
    +            <div ng-show="crumb.url"></div>
    +          </li>
    +        </ul>
    +
    +        <div id="loading" ng-show="loading">Loading...</div>
    +
    +        <div ng-hide="loading" ng-include src="currentPage.partialUrl" onload="afterPartialLoaded()" autoscroll class="content" ng-animate="{enter: 'slide-reveal'}" ></div>
    +
    +      </div>
    +    </div>
    +  </div>
    +
    +</body>
    +</html>
    diff --git a/docs/js/angular-bootstrap-prettify.js b/docs/js/angular-bootstrap-prettify.js
    new file mode 100644
    index 000000000..e14861056
    --- /dev/null
    +++ b/docs/js/angular-bootstrap-prettify.js
    @@ -0,0 +1,320 @@
    +'use strict';
    +
    +var directive = {};
    +var service = { value: {} };
    +
    +var DEPENDENCIES = {
    +  'angular.js': 'http://code.angularjs.org/' + angular.version.full + '/angular.min.js',
    +  'angular-resource.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-resource.min.js',
    +  'angular-route.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-route.min.js',
    +  'angular-animate.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-animate.min.js',
    +  'angular-sanitize.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-sanitize.min.js',
    +  'angular-cookies.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-cookies.min.js'
    +};
    +
    +
    +function escape(text) {
    +  return text.
    +    replace(/\&/g, '&amp;').
    +    replace(/\</g, '&lt;').
    +    replace(/\>/g, '&gt;').
    +    replace(/"/g, '&quot;');
    +}
    +
    +/**
    + * http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
    + * http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
    + */
    +function setHtmlIe8SafeWay(element, html) {
    +  var newElement = angular.element('<pre>' + html + '</pre>');
    +
    +  element.html('');
    +  element.append(newElement.contents());
    +  return element;
    +}
    +
    +
    +directive.jsFiddle = function(getEmbeddedTemplate, escape, script) {
    +  return {
    +    terminal: true,
    +    link: function(scope, element, attr) {
    +      var name = '',
    +        stylesheet = '<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">\n',
    +        fields = {
    +          html: '',
    +          css: '',
    +          js: ''
    +        };
    +
    +      angular.forEach(attr.jsFiddle.split(' '), function(file, index) {
    +        var fileType = file.split('.')[1];
    +
    +        if (fileType == 'html') {
    +          if (index == 0) {
    +            fields[fileType] +=
    +              '<div ng-app' + (attr.module ? '="' + attr.module + '"' : '') + '>\n' +
    +                getEmbeddedTemplate(file, 2);
    +          } else {
    +            fields[fileType] += '\n\n\n  <!-- CACHE FILE: ' + file + ' -->\n' +
    +              '  <script type="text/ng-template" id="' + file + '">\n' +
    +              getEmbeddedTemplate(file, 4) +
    +              '  </script>\n';
    +          }
    +        } else {
    +          fields[fileType] += getEmbeddedTemplate(file) + '\n';
    +        }
    +      });
    +
    +      fields.html += '</div>\n';
    +
    +      setHtmlIe8SafeWay(element,
    +        '<form class="jsfiddle" method="post" action="http://jsfiddle.net/api/post/library/pure/" target="_blank">' +
    +          hiddenField('title', 'AngularJS Example: ' + name) +
    +          hiddenField('css', '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
    +            stylesheet +
    +            script.angular +
    +            (attr.resource ? script.resource : '') +
    +            '<style>\n' +
    +            fields.css) +
    +          hiddenField('html', fields.html) +
    +          hiddenField('js', fields.js) +
    +          '<button class="btn btn-primary"><i class="icon-white icon-pencil"></i> Edit Me</button>' +
    +          '</form>');
    +
    +      function hiddenField(name, value) {
    +        return '<input type="hidden" name="' +  name + '" value="' + escape(value) + '">';
    +      }
    +    }
    +  }
    +};
    +
    +
    +directive.code = function() {
    +  return {restrict: 'E', terminal: true};
    +};
    +
    +
    +directive.prettyprint = ['reindentCode', function(reindentCode) {
    +  return {
    +    restrict: 'C',
    +    compile: function(element) {
    +      var html = element.html();
    +      //ensure that angular won't compile {{ curly }} values
    +      html = html.replace(/\{\{/g, '<span>{{</span>')
    +                 .replace(/\}\}/g, '<span>}}</span>');
    +      if (window.RUNNING_IN_NG_TEST_RUNNER) {
    +        element.html(html);
    +      }
    +      else {
    +        element.html(window.prettyPrintOne(reindentCode(html), undefined, true));
    +      }
    +    }
    +  };
    +}];
    +
    +
    +directive.ngSetText = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
    +  return {
    +    restrict: 'CA',
    +    priority: 10,
    +    compile: function(element, attr) {
    +      setHtmlIe8SafeWay(element, escape(getEmbeddedTemplate(attr.ngSetText)));
    +    }
    +  }
    +}]
    +
    +
    +directive.ngHtmlWrap = ['reindentCode', 'templateMerge', function(reindentCode, templateMerge) {
    +  return {
    +    compile: function(element, attr) {
    +      var properties = {
    +            head: '',
    +            module: '',
    +            body: element.text()
    +          },
    +        html = "<!doctype html>\n<html ng-app{{module}}>\n  <head>\n{{head:4}}  </head>\n  <body>\n{{body:4}}  </body>\n</html>";
    +
    +      angular.forEach((attr.ngHtmlWrap || '').split(' '), function(dep) {
    +        if (!dep) return;
    +        dep = DEPENDENCIES[dep] || dep;
    +
    +        var ext = dep.split(/\./).pop();
    +
    +        if (ext == 'css') {
    +          properties.head += '<link rel="stylesheet" href="' + dep + '" type="text/css">\n';
    +        } else if(ext == 'js') {
    +          properties.head += '<script src="' + dep + '"></script>\n';
    +        } else {
    +          properties.module = '="' + dep + '"';
    +        }
    +      });
    +
    +      setHtmlIe8SafeWay(element, escape(templateMerge(html, properties)));
    +    }
    +  }
    +}];
    +
    +
    +directive.ngSetHtml = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
    +  return {
    +    restrict: 'CA',
    +    priority: 10,
    +    compile: function(element, attr) {
    +      setHtmlIe8SafeWay(element, getEmbeddedTemplate(attr.ngSetHtml));
    +    }
    +  }
    +}];
    +
    +
    +directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
    +  return {
    +    compile: function (element, attr) {
    +      var fileNames = attr.ngEvalJavascript.split(' ');
    +      angular.forEach(fileNames, function(fileName) {
    +        var script = getEmbeddedTemplate(fileName);
    +        try {
    +          if (window.execScript) { // IE
    +            window.execScript(script || '""'); // IE complains when evaling empty string
    +          } else {
    +            window.eval(script + '//@ sourceURL=' + fileName);
    +          }
    +        } catch (e) {
    +          if (window.console) {
    +            window.console.log(script, '\n', e);
    +          } else {
    +            window.alert(e);
    +          }
    +        }
    +      });
    +    }
    +  };
    +}];
    +
    +
    +directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', '$sniffer', '$animate',
    +                function($templateCache,   $browser,  docsRootScope, $location,   $sniffer,   $animate) {
    +  return {
    +    terminal: true,
    +    link: function(scope, element, attrs) {
    +      var modules = ['ngAnimate'],
    +          embedRootScope,
    +          deregisterEmbedRootScope;
    +
    +      modules.push(['$provide', function($provide) {
    +        $provide.value('$templateCache', $templateCache);
    +        $provide.value('$anchorScroll', angular.noop);
    +        $provide.value('$browser', $browser);
    +        $provide.value('$sniffer', $sniffer);
    +        $provide.value('$animate', $animate);
    +        $provide.provider('$location', function() {
    +          this.$get = ['$rootScope', function($rootScope) {
    +            docsRootScope.$on('$locationChangeSuccess', function(event, oldUrl, newUrl) {
    +              $rootScope.$broadcast('$locationChangeSuccess', oldUrl, newUrl);
    +            });
    +            return $location;
    +          }];
    +          this.html5Mode = angular.noop;
    +        });
    +
    +        // NOTE(c0bra): Why the hell is it doing this???
    +        // $provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
    +        //   return angular.extend(function(fn, delay) {
    +        //     if (delay && delay > 50) {
    +        //       return setTimeout(function() {
    +        //         $rootScope.$apply(fn);
    +        //       }, delay);
    +        //     } else {
    +        //       return $delegate.apply(this, arguments);
    +        //     }
    +        //   }, $delegate);
    +        // }]);
    +        
    +        $provide.decorator('$rootScope', ['$delegate', function($delegate) {
    +          embedRootScope = $delegate;
    +
    +          // Since we are teleporting the $animate service, which relies on the $$postDigestQueue
    +          // we need the embedded scope to use the same $$postDigestQueue as the outer scope
    +          embedRootScope.$$postDigestQueue = docsRootScope.$$postDigestQueue;
    +
    +          deregisterEmbedRootScope = docsRootScope.$watch(function embedRootScopeDigestWatch() {
    +            embedRootScope.$digest();
    +          });
    +
    +          return embedRootScope;
    +        }]);
    +      }]);
    +      if (attrs.ngEmbedApp)  modules.push(attrs.ngEmbedApp);
    +
    +      element.on('click', function(event) {
    +        if (event.target.attributes.getNamedItem('ng-click')) {
    +          event.preventDefault();
    +        }
    +      });
    +
    +      element.bind('$destroy', function() {
    +        deregisterEmbedRootScope();
    +        embedRootScope.$destroy();
    +      });
    +
    +      element.data('$injector', null);
    +      angular.bootstrap(element, modules);
    +    }
    +  };
    +}];
    +
    +service.reindentCode = function() {
    +  return function (text, spaces) {
    +    if (!text) return text;
    +    var lines = text.split(/\r?\n/);
    +    var prefix = '      '.substr(0, spaces || 0);
    +    var i;
    +
    +    // remove any leading blank lines
    +    while (lines.length && lines[0].match(/^\s*$/)) lines.shift();
    +    // remove any trailing blank lines
    +    while (lines.length && lines[lines.length - 1].match(/^\s*$/)) lines.pop();
    +    var minIndent = 999;
    +    for (i = 0; i < lines.length; i++) {
    +      var line = lines[0];
    +      var reindentCode = line.match(/^\s*/)[0];
    +      if (reindentCode !== line && reindentCode.length < minIndent) {
    +        minIndent = reindentCode.length;
    +      }
    +    }
    +
    +    for (i = 0; i < lines.length; i++) {
    +      lines[i] = prefix + lines[i].substring(minIndent);
    +    }
    +    lines.push('');
    +    return lines.join('\n');
    +  }
    +};
    +
    +service.templateMerge = ['reindentCode', function(indentCode) {
    +  return function(template, properties) {
    +    return template.replace(/\{\{(\w+)(?:\:(\d+))?\}\}/g, function(_, key, indent) {
    +      var value = properties[key];
    +
    +      if (indent) {
    +        value = indentCode(value, indent);
    +      }
    +
    +      return value == undefined ? '' : value;
    +    });
    +  };
    +}];
    +
    +service.getEmbeddedTemplate = ['reindentCode', function(reindentCode) {
    +  return function (id) {
    +    var element = document.getElementById(id);
    +
    +    if (!element) {
    +      return null;
    +    }
    +
    +    return reindentCode(angular.element(element).html(), 0);
    +  }
    +}];
    +
    +
    +angular.module('bootstrapPrettify', []).directive(directive).factory(service);
    diff --git a/docs/js/angular-bootstrap-prettify.min.js b/docs/js/angular-bootstrap-prettify.min.js
    new file mode 100644
    index 000000000..15b132abc
    --- /dev/null
    +++ b/docs/js/angular-bootstrap-prettify.min.js
    @@ -0,0 +1,41 @@
    +/*
    + AngularJS v1.1.5
    + (c) 2010-2012 Google, Inc. http://angularjs.org
    + License: MIT
    +*/
    +(function(v,t,H){'use strict';function F(d){return d.replace(/\&/g,"&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;").replace(/"/g,"&quot;")}function A(d,f){var a=t.element("<pre>"+f+"</pre>");d.html("");d.append(a.contents());return d}var s={},w={value:{}},K={"angular.js":"http://code.angularjs.org/"+t.version.full+"/angular.min.js","angular-resource.js":"http://code.angularjs.org/"+t.version.full+"/angular-resource.min.js","angular-sanitize.js":"http://code.angularjs.org/"+t.version.full+"/angular-sanitize.min.js",
    +"angular-cookies.js":"http://code.angularjs.org/"+t.version.full+"/angular-cookies.min.js"};s.jsFiddle=function(d,f,a){return{terminal:!0,link:function(o,c,l){function b(a,c){return'<input type="hidden" name="'+a+'" value="'+f(c)+'">'}var r={html:"",css:"",js:""};t.forEach(l.jsFiddle.split(" "),function(a,c){var b=a.split(".")[1];r[b]+=b=="html"?c==0?"<div ng-app"+(l.module?'="'+l.module+'"':"")+">\n"+d(a,2):"\n\n\n  <\!-- CACHE FILE: "+a+' --\>\n  <script type="text/ng-template" id="'+a+'">\n'+d(a,
    +4)+"  <\/script>\n":d(a)+"\n"});r.html+="</div>\n";A(c,'<form class="jsfiddle" method="post" action="http://jsfiddle.net/api/post/library/pure/" target="_blank">'+b("title","AngularJS Example: ")+b("css",'</style> <\!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --\> \n<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">\n'+a.angular+(l.resource?a.resource:"")+"<style>\n"+r.css)+b("html",r.html)+b("js",r.js)+'<button class="btn btn-primary"><i class="icon-white icon-pencil"></i> Edit Me</button></form>')}}};
    +s.code=function(){return{restrict:"E",terminal:!0}};s.prettyprint=["reindentCode",function(d){return{restrict:"C",terminal:!0,compile:function(f){f.html(v.prettyPrintOne(d(f.html()),H,!0))}}}];s.ngSetText=["getEmbeddedTemplate",function(d){return{restrict:"CA",priority:10,compile:function(f,a){A(f,F(d(a.ngSetText)))}}}];s.ngHtmlWrap=["reindentCode","templateMerge",function(d,f){return{compile:function(a,d){var c={head:"",module:"",body:a.text()};t.forEach((d.ngHtmlWrap||"").split(" "),function(a){if(a){var a=
    +K[a]||a,b=a.split(/\./).pop();b=="css"?c.head+='<link rel="stylesheet" href="'+a+'" type="text/css">\n':b=="js"?c.head+='<script src="'+a+'"><\/script>\n':c.module='="'+a+'"'}});A(a,F(f("<!doctype html>\n<html ng-app{{module}}>\n  <head>\n{{head:4}}  </head>\n  <body>\n{{body:4}}  </body>\n</html>",c)))}}}];s.ngSetHtml=["getEmbeddedTemplate",function(d){return{restrict:"CA",priority:10,compile:function(f,a){A(f,d(a.ngSetHtml))}}}];s.ngEvalJavascript=["getEmbeddedTemplate",function(d){return{compile:function(f,
    +a){var o=d(a.ngEvalJavascript);try{v.execScript?v.execScript(o||'""'):v.eval(o)}catch(c){v.console?v.console.log(o,"\n",c):v.alert(c)}}}}];s.ngEmbedApp=["$templateCache","$browser","$rootScope","$location","$sniffer",function(d,f,a,o,c){return{terminal:!0,link:function(l,b,r){l=[];l.push(["$provide",function(b){b.value("$templateCache",d);b.value("$anchorScroll",t.noop);b.value("$browser",f);b.value("$sniffer",c);b.provider("$location",function(){this.$get=["$rootScope",function(b){a.$on("$locationChangeSuccess",
    +function(a,c,d){b.$broadcast("$locationChangeSuccess",c,d)});return o}];this.html5Mode=t.noop});b.decorator("$timeout",["$rootScope","$delegate",function(a,b){return t.extend(function(c,d){return d&&d>50?setTimeout(function(){a.$apply(c)},d):b.apply(this,arguments)},b)}]);b.decorator("$rootScope",["$delegate",function(b){a.$watch(function(){b.$digest()});return b}])}]);r.ngEmbedApp&&l.push(r.ngEmbedApp);b.bind("click",function(a){a.target.attributes.getNamedItem("ng-click")&&a.preventDefault()});
    +t.bootstrap(b,l)}}}];w.reindentCode=function(){return function(d,f){if(!d)return d;for(var a=d.split(/\r?\n/),o="      ".substr(0,f||0),c;a.length&&a[0].match(/^\s*$/);)a.shift();for(;a.length&&a[a.length-1].match(/^\s*$/);)a.pop();var l=999;for(c=0;c<a.length;c++){var b=a[0],r=b.match(/^\s*/)[0];if(r!==b&&r.length<l)l=r.length}for(c=0;c<a.length;c++)a[c]=o+a[c].substring(l);a.push("");return a.join("\n")}};w.templateMerge=["reindentCode",function(d){return function(f,a){return f.replace(/\{\{(\w+)(?:\:(\d+))?\}\}/g,
    +function(f,c,l){f=a[c];l&&(f=d(f,l));return f==H?"":f})}}];w.getEmbeddedTemplate=["reindentCode",function(d){return function(f){f=document.getElementById(f);return!f?null:d(t.element(f).html(),0)}}];t.module("bootstrapPrettify",[]).directive(s).factory(w);v.PR_SHOULD_USE_CONTINUATION=!0;(function(){function d(a){function b(i){var a=i.charCodeAt(0);if(a!==92)return a;var k=i.charAt(1);return(a=O[k])?a:"0"<=k&&k<="7"?parseInt(i.substring(1),8):k==="u"||k==="x"?parseInt(i.substring(2),16):i.charCodeAt(1)}
    +function E(i){if(i<32)return(i<16?"\\x0":"\\x")+i.toString(16);i=String.fromCharCode(i);return i==="\\"||i==="-"||i==="]"||i==="^"?"\\"+i:i}function c(i){var a=i.substring(1,i.length-1).match(/\\u[0-9A-Fa-f]{4}|\\x[0-9A-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\s\S]|-|[^-\\]/g),i=[],k=a[0]==="^",e=["["];k&&e.push("^");for(var k=k?1:0,g=a.length;k<g;++k){var j=a[k];if(/\\[bdsw]/i.test(j))e.push(j);else{var j=b(j),h;k+2<g&&"-"===a[k+1]?(h=b(a[k+2]),k+=2):h=j;i.push([j,h]);h<65||j>122||(h<65||j>90||
    +i.push([Math.max(65,j)|32,Math.min(h,90)|32]),h<97||j>122||i.push([Math.max(97,j)&-33,Math.min(h,122)&-33]))}}i.sort(function(i,a){return i[0]-a[0]||a[1]-i[1]});a=[];g=[];for(k=0;k<i.length;++k)j=i[k],j[0]<=g[1]+1?g[1]=Math.max(g[1],j[1]):a.push(g=j);for(k=0;k<a.length;++k)j=a[k],e.push(E(j[0])),j[1]>j[0]&&(j[1]+1>j[0]&&e.push("-"),e.push(E(j[1])));e.push("]");return e.join("")}function d(i){for(var a=i.source.match(RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)",
    +"g")),e=a.length,b=[],g=0,j=0;g<e;++g){var h=a[g];h==="("?++j:"\\"===h.charAt(0)&&(h=+h.substring(1))&&(h<=j?b[h]=-1:a[g]=E(h))}for(g=1;g<b.length;++g)-1===b[g]&&(b[g]=++f);for(j=g=0;g<e;++g)h=a[g],h==="("?(++j,b[j]||(a[g]="(?:")):"\\"===h.charAt(0)&&(h=+h.substring(1))&&h<=j&&(a[g]="\\"+b[h]);for(g=0;g<e;++g)"^"===a[g]&&"^"!==a[g+1]&&(a[g]="");if(i.ignoreCase&&y)for(g=0;g<e;++g)h=a[g],i=h.charAt(0),h.length>=2&&i==="["?a[g]=c(h):i!=="\\"&&(a[g]=h.replace(/[a-zA-Z]/g,function(a){a=a.charCodeAt(0);
    +return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var f=0,y=!1,n=!1,q=0,e=a.length;q<e;++q){var m=a[q];if(m.ignoreCase)n=!0;else if(/[a-z]/i.test(m.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){y=!0;n=!1;break}}for(var O={b:8,t:9,n:10,v:11,f:12,r:13},p=[],q=0,e=a.length;q<e;++q){m=a[q];if(m.global||m.multiline)throw Error(""+m);p.push("(?:"+d(m)+")")}return RegExp(p.join("|"),n?"gi":"g")}function f(a,b){function c(a){switch(a.nodeType){case 1:if(d.test(a.className))break;
    +for(var e=a.firstChild;e;e=e.nextSibling)c(e);e=a.nodeName.toLowerCase();if("br"===e||"li"===e)f[n]="\n",y[n<<1]=l++,y[n++<<1|1]=a;break;case 3:case 4:e=a.nodeValue,e.length&&(e=b?e.replace(/\r\n?/g,"\n"):e.replace(/[ \t\r\n]+/g," "),f[n]=e,y[n<<1]=l,l+=e.length,y[n++<<1|1]=a)}}var d=/(?:^|\s)nocode(?:\s|$)/,f=[],l=0,y=[],n=0;c(a);return{sourceCode:f.join("").replace(/\n$/,""),spans:y}}function a(a,b,c,d){b&&(a={sourceCode:b,basePos:a},c(a),d.push.apply(d,a.decorations))}function o(b,c){var E={},
    +f;(function(){for(var a=b.concat(c),n=[],q={},e=0,m=a.length;e<m;++e){var l=a[e],p=l[3];if(p)for(var i=p.length;--i>=0;)E[p.charAt(i)]=l;l=l[1];p=""+l;q.hasOwnProperty(p)||(n.push(l),q[p]=null)}n.push(/[\0-\uffff]/);f=d(n)})();var l=c.length,t=function(b){for(var d=b.basePos,G=[d,"pln"],e=0,m=b.sourceCode.match(f)||[],s={},p=0,i=m.length;p<i;++p){var x=m[p],k=s[x],u=void 0,g;if(typeof k==="string")g=!1;else{var j=E[x.charAt(0)];if(j)u=x.match(j[1]),k=j[0];else{for(g=0;g<l;++g)if(j=c[g],u=x.match(j[1])){k=
    +j[0];break}u||(k="pln")}if((g=k.length>=5&&"lang-"===k.substring(0,5))&&!(u&&typeof u[1]==="string"))g=!1,k="src";g||(s[x]=k)}j=e;e+=x.length;if(g){g=u[1];var h=x.indexOf(g),D=h+g.length;u[2]&&(D=x.length-u[2].length,h=D-g.length);k=k.substring(5);a(d+j,x.substring(0,h),t,G);a(d+j+h,g,r(k,g),G);a(d+j+D,x.substring(D),t,G)}else G.push(d+j,k)}b.decorations=G};return t}function c(a){var b=[],c=[];a.tripleQuotedStrings?b.push(["str",/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
    +null,"'\""]):a.multiLineStrings?b.push(["str",/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):b.push(["str",/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);a.verbatimStrings&&c.push(["str",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);var d=a.hashComments;d&&(a.cStyleComments?(d>1?b.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"]):b.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
    +null,"#"]),c.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])):b.push(["com",/^#[^\r\n]*/,null,"#"]));a.cStyleComments&&(c.push(["com",/^\/\/[^\r\n]*/,null]),c.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,null]));a.regexLiterals&&c.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)")]);
    +(d=a.types)&&c.push(["typ",d]);a=(""+a.keywords).replace(/^ | $/g,"");a.length&&c.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),null]);b.push(["pln",/^\s+/,null," \r\n\t\u00a0"]);c.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,null],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],["pln",/^[a-z_$][a-z_$@0-9]*/i,null],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],["pln",/^\\[\s\S]?/,null],["pun",/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);
    +return o(b,c)}function l(a,b,c){function d(a){switch(a.nodeType){case 1:if(l.test(a.className))break;if("br"===a.nodeName)f(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)d(a);break;case 3:case 4:if(c){var b=a.nodeValue,e=b.match(t);if(e){var m=b.substring(0,e.index);a.nodeValue=m;(b=b.substring(e.index+e[0].length))&&a.parentNode.insertBefore(n.createTextNode(b),a.nextSibling);f(a);m||a.parentNode.removeChild(a)}}}}function f(a){function b(a,c){var e=c?a.cloneNode(!1):
    +a,h=a.parentNode;if(h){var h=b(h,1),d=a.nextSibling;h.appendChild(e);for(var i=d;i;i=d)d=i.nextSibling,h.appendChild(i)}return e}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),c;(c=a.parentNode)&&c.nodeType===1;)a=c;e.push(a)}for(var l=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,n=a.ownerDocument,q=n.createElement("li");a.firstChild;)q.appendChild(a.firstChild);for(var e=[q],m=0;m<e.length;++m)d(e[m]);b===(b|0)&&e[0].setAttribute("value",b);var s=n.createElement("ol");s.className=
    +"linenums";for(var b=Math.max(0,b-1|0)||0,m=0,p=e.length;m<p;++m)q=e[m],q.className="L"+(m+b)%10,q.firstChild||q.appendChild(n.createTextNode("\u00a0")),s.appendChild(q);a.appendChild(s)}function b(a,b){for(var c=b.length;--c>=0;){var d=b[c];I.hasOwnProperty(d)?s.console&&console.warn("cannot override language handler %s",d):I[d]=a}}function r(a,b){if(!a||!I.hasOwnProperty(a))a=/^\s*</.test(b)?"default-markup":"default-code";return I[a]}function t(a){var b=a.langExtension;try{var c=f(a.sourceNode,
    +a.pre),d=c.sourceCode;a.sourceCode=d;a.spans=c.spans;a.basePos=0;r(b,d)(a);var l=/\bMSIE\s(\d+)/.exec(navigator.userAgent),l=l&&+l[1]<=8,b=/\n/g,o=a.sourceCode,y=o.length,c=0,n=a.spans,q=n.length,d=0,e=a.decorations,m=e.length,v=0;e[m]=y;var p,i;for(i=p=0;i<m;)e[i]!==e[i+2]?(e[p++]=e[i++],e[p++]=e[i++]):i+=2;m=p;for(i=p=0;i<m;){for(var x=e[i],k=e[i+1],u=i+2;u+2<=m&&e[u+1]===k;)u+=2;e[p++]=x;e[p++]=k;i=u}e.length=p;var g=a.sourceNode,j;if(g)j=g.style.display,g.style.display="none";try{for(;d<q;){var h=
    +n[d+2]||y,D=e[v+2]||y,u=Math.min(h,D),C=n[d+1],J;if(C.nodeType!==1&&(J=o.substring(c,u))){l&&(J=J.replace(b,"\r"));C.nodeValue=J;var A=C.ownerDocument,w=A.createElement("span");w.className=e[v+1];var B=C.parentNode;B.replaceChild(w,C);w.appendChild(C);c<h&&(n[d+1]=C=A.createTextNode(o.substring(u,h)),B.insertBefore(C,w.nextSibling))}c=u;c>=h&&(d+=2);c>=D&&(v+=2)}}finally{if(g)g.style.display=j}}catch(z){s.console&&console.log(z&&z.stack?z.stack:z)}}var s=v,B=["break,continue,do,else,for,if,return,while"],
    +z=[[B,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],A=[z,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
    +w=[z,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],F=[w,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],z=[z,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],
    +L=[B,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],M=[B,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],B=[B,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],N=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
    +K=/\S/,P=c({keywords:[A,F,z,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+L,M,B],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),I={};b(P,["default-code"]);b(o([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
    +/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);b(o([["pln",/^[\s]+/,null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
    +["pun",/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);b(o([],[["atv",/^[\s\S]+/]]),["uq.val"]);b(c({keywords:A,hashComments:!0,cStyleComments:!0,types:N}),["c","cc","cpp","cxx","cyc","m"]);b(c({keywords:"null,true,false"}),["json"]);b(c({keywords:F,hashComments:!0,cStyleComments:!0,
    +verbatimStrings:!0,types:N}),["cs"]);b(c({keywords:w,cStyleComments:!0}),["java"]);b(c({keywords:B,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);b(c({keywords:L,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py"]);b(c({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl",
    +"pl","pm"]);b(c({keywords:M,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);b(c({keywords:z,cStyleComments:!0,regexLiterals:!0}),["js"]);b(c({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);b(o([],[["str",/^[\s\S]+/]]),["regex"]);var Q=s.PR={createSimpleLexer:o,
    +registerLangHandler:b,sourceDecorator:c,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:s.prettyPrintOne=function(a,b,c){var d=document.createElement("div");d.innerHTML="<pre>"+a+"</pre>";d=d.firstChild;c&&l(d,c,!0);t({langExtension:b,numberLines:c,sourceNode:d,pre:1});return d.innerHTML},prettyPrint:s.prettyPrint=
    +function(a){function b(){var u;for(var c=s.PR_SHOULD_USE_CONTINUATION?n.now()+250:Infinity;q<d.length&&n.now()<c;q++){var g=d[q],j=g.className;if(v.test(j)&&!p.test(j)){for(var h=!1,f=g.parentNode;f;f=f.parentNode)if(k.test(f.tagName)&&f.className&&v.test(f.className)){h=!0;break}if(!h){g.className+=" prettyprinted";var j=j.match(m),o;if(h=!j){for(var h=g,f=H,r=h.firstChild;r;r=r.nextSibling)var w=r.nodeType,f=w===1?f?h:r:w===3?K.test(r.nodeValue)?h:f:f;h=(o=f===h?H:f)&&x.test(o.tagName)}h&&(j=o.className.match(m));
    +j&&(j=j[1]);u=i.test(g.tagName)?1:(h=(h=g.currentStyle)?h.whiteSpace:document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(g,null).getPropertyValue("white-space"):0)&&"pre"===h.substring(0,3),h=u;(f=(f=g.className.match(/\blinenums\b(?::(\d+))?/))?f[1]&&f[1].length?+f[1]:!0:!1)&&l(g,f,h);e={langExtension:j,sourceNode:g,numberLines:f,pre:h};t(e)}}}q<d.length?setTimeout(b,250):a&&a()}for(var c=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),
    +document.getElementsByTagName("xmp")],d=[],f=0;f<c.length;++f)for(var o=0,r=c[f].length;o<r;++o)d.push(c[f][o]);var c=null,n=Date;n.now||(n={now:function(){return+new Date}});var q=0,e,m=/\blang(?:uage)?-([\w.]+)(?!\S)/,v=/\bprettyprint\b/,p=/\bprettyprinted\b/,i=/pre|xmp/i,x=/^code$/i,k=/^(?:pre|code|xmp)$/i;b()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Q})})()})(window,window.angular);angular.element(document).find("head").append('<style type="text/css">.com{color:#93a1a1;}.lit{color:#195f91;}.pun,.opn,.clo{color:#93a1a1;}.fun{color:#dc322f;}.str,.atv{color:#D14;}.kwd,.linenums .tag{color:#1e347b;}.typ,.atn,.dec,.var{color:teal;}.pln{color:#48484c;}.prettyprint{padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8;}.prettyprint.linenums{-webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;-moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;}ol.linenums{margin:0 0 0 33px;}ol.linenums li{padding-left:12px;color:#bebec5;line-height:18px;text-shadow:0 1px 0 #fff;}</style>');
    diff --git a/docs/js/angular-bootstrap.js b/docs/js/angular-bootstrap.js
    new file mode 100644
    index 000000000..f610bfb44
    --- /dev/null
    +++ b/docs/js/angular-bootstrap.js
    @@ -0,0 +1,392 @@
    +'use strict';
    +
    +var directive = {};
    +
    +directive.dropdownToggle =
    +          ['$document', '$location', '$window',
    +  function ($document,   $location,   $window) {
    +    var openElement = null, close;
    +    return {
    +      restrict: 'C',
    +      link: function(scope, element, attrs) {
    +        scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
    +          close && close();
    +        });
    +
    +        element.parent().on('click', function(event) {
    +          close && close();
    +        });
    +
    +        element.on('click', function(event) {
    +          event.preventDefault();
    +          event.stopPropagation();
    +
    +          var iWasOpen = false;
    +
    +          if (openElement) {
    +            iWasOpen = openElement === element;
    +            close();
    +          }
    +
    +          if (!iWasOpen){
    +            element.parent().addClass('open');
    +            openElement = element;
    +
    +            close = function (event) {
    +              event && event.preventDefault();
    +              event && event.stopPropagation();
    +              $document.off('click', close);
    +              element.parent().removeClass('open');
    +              close = null;
    +              openElement = null;
    +            }
    +
    +            $document.on('click', close);
    +          }
    +        });
    +      }
    +    };
    +  }];
    +
    +directive.syntax = function() {
    +  return {
    +    restrict: 'A',
    +    link: function(scope, element, attrs) {
    +      function makeLink(type, text, link, icon) {
    +        return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' + 
    +                '<span class="' + icon + '"></span> ' + text +
    +               '</a>';
    +      };
    +
    +      var html = '';
    +      var types = {
    +        'github' : {
    +          text : 'View on Github',
    +          key : 'syntaxGithub',
    +          icon : 'icon-github'
    +        },
    +        'plunkr' : {
    +          text : 'View on Plunkr',
    +          key : 'syntaxPlunkr',
    +          icon : 'icon-arrow-down'
    +        },
    +        'jsfiddle' : {
    +          text : 'View on JSFiddle',
    +          key : 'syntaxFiddle',
    +          icon : 'icon-cloud'
    +        }
    +      };
    +      for(var type in types) {
    +        var data = types[type];
    +        var link = attrs[data.key];
    +        if(link) {
    +          html += makeLink(type, data.text, link, data.icon);
    +        }
    +      };
    +
    +      var nav = document.createElement('nav');
    +      nav.className = 'syntax-links';
    +      nav.innerHTML = html;
    +
    +      var node = element[0];
    +      var par = node.parentNode;
    +      par.insertBefore(nav, node);
    +    }
    +  }
    +}
    +
    +directive.tabbable = function() {
    +  return {
    +    restrict: 'C',
    +    compile: function(element) {
    +      var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
    +          tabContent = angular.element('<div class="tab-content"></div>');
    +
    +      tabContent.append(element.contents());
    +      element.append(navTabs).append(tabContent);
    +    },
    +    controller: ['$scope', '$element', function($scope, $element) {
    +      var navTabs = $element.contents().eq(0),
    +          ngModel = $element.controller('ngModel') || {},
    +          tabs = [],
    +          selectedTab;
    +
    +      ngModel.$render = function() {
    +        var $viewValue = this.$viewValue;
    +
    +        if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
    +          if(selectedTab) {
    +            selectedTab.paneElement.removeClass('active');
    +            selectedTab.tabElement.removeClass('active');
    +            selectedTab = null;
    +          }
    +          if($viewValue) {
    +            for(var i = 0, ii = tabs.length; i < ii; i++) {
    +              if ($viewValue == tabs[i].value) {
    +                selectedTab = tabs[i];
    +                break;
    +              }
    +            }
    +            if (selectedTab) {
    +              selectedTab.paneElement.addClass('active');
    +              selectedTab.tabElement.addClass('active');
    +            }
    +          }
    +
    +        }
    +      };
    +
    +      this.addPane = function(element, attr) {
    +        var li = angular.element('<li><a href></a></li>'),
    +            a = li.find('a'),
    +            tab = {
    +              paneElement: element,
    +              paneAttrs: attr,
    +              tabElement: li
    +            };
    +
    +        tabs.push(tab);
    +
    +        attr.$observe('value', update)();
    +        attr.$observe('title', function(){ update(); a.text(tab.title); })();
    +
    +        function update() {
    +          tab.title = attr.title;
    +          tab.value = attr.value || attr.title;
    +          if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
    +            // we are not part of angular
    +            ngModel.$viewValue = tab.value;
    +          }
    +          ngModel.$render();
    +        }
    +
    +        navTabs.append(li);
    +        li.on('click', function(event) {
    +          event.preventDefault();
    +          event.stopPropagation();
    +          if (ngModel.$setViewValue) {
    +            $scope.$apply(function() {
    +              ngModel.$setViewValue(tab.value);
    +              ngModel.$render();
    +            });
    +          } else {
    +            // we are not part of angular
    +            ngModel.$viewValue = tab.value;
    +            ngModel.$render();
    +          }
    +        });
    +
    +        return function() {
    +          tab.tabElement.remove();
    +          for(var i = 0, ii = tabs.length; i < ii; i++ ) {
    +            if (tab == tabs[i]) {
    +              tabs.splice(i, 1);
    +            }
    +          }
    +        };
    +      }
    +    }]
    +  };
    +};
    +
    +directive.table = function() {
    +  return {
    +    restrict: 'E',
    +    link: function(scope, element, attrs) {
    +      if (!attrs.class) {
    +        element.addClass('table table-bordered table-striped code-table');
    +      }
    +    }
    +  };
    +};
    +
    +var popoverElement = function() {
    +  var object = {
    +    init : function() {
    +      this.element = angular.element(
    +        '<div class="popover popover-incode top">' +
    +          '<div class="arrow"></div>' +
    +          '<div class="popover-inner">' +
    +            '<div class="popover-title"><code></code></div>' +
    +            '<div class="popover-content"></div>' +
    +          '</div>' +
    +        '</div>'
    +      );
    +      this.node = this.element[0];
    +      this.element.css({
    +        'display':'block',
    +        'position':'absolute'
    +      });
    +      angular.element(document.body).append(this.element);
    +
    +      var inner = this.element.children()[1];
    +      this.titleElement   = angular.element(inner.childNodes[0].firstChild);
    +      this.contentElement = angular.element(inner.childNodes[1]);
    +
    +      //stop the click on the tooltip
    +      this.element.bind('click', function(event) {
    +        event.preventDefault();
    +        event.stopPropagation();
    +      });
    +
    +      var self = this;
    +      angular.element(document.body).bind('click',function(event) {
    +        if(self.visible()) self.hide();
    +      });
    +    },
    +
    +    show : function(x,y) {
    +      this.element.addClass('visible');
    +      this.position(x || 0, y || 0);
    +    },
    +
    +    hide : function() {
    +      this.element.removeClass('visible');
    +      this.position(-9999,-9999);
    +    },
    +
    +    visible : function() {
    +      return this.position().y >= 0;
    +    },
    +
    +    isSituatedAt : function(element) {
    +      return this.besideElement ? element[0] == this.besideElement[0] : false;
    +    },
    +
    +    title : function(value) {
    +      return this.titleElement.html(value);
    +    },
    +
    +    content : function(value) { 
    +      if(value && value.length > 0) {
    +        value = marked(value);
    +      }
    +      return this.contentElement.html(value);
    +    },
    +
    +    positionArrow : function(position) {
    +      this.node.className = 'popover ' + position;
    +    },
    +
    +    positionAway : function() {
    +      this.besideElement = null;
    +      this.hide();
    +    },
    +
    +    positionBeside : function(element) {
    +      this.besideElement = element;
    +
    +      var elm = element[0];
    +      var x = elm.offsetLeft;
    +      var y = elm.offsetTop;
    +      x -= 30;
    +      y -= this.node.offsetHeight + 10;
    +      this.show(x,y);
    +    },
    +
    +    position : function(x,y) {
    +      if(x != null && y != null) {
    +        this.element.css('left',x + 'px');
    +        this.element.css('top', y + 'px');
    +      }
    +      else {
    +        return {
    +          x : this.node.offsetLeft,
    +          y : this.node.offsetTop
    +        };
    +      }
    +    }
    +  };
    +
    +  object.init();
    +  object.hide();
    +
    +  return object;
    +};
    +
    +directive.popover = ['popoverElement', function(popover) {
    +  return {
    +    restrict: 'A',
    +    priority : 500,
    +    link: function(scope, element, attrs) {
    +      element.bind('click',function(event) {
    +        event.preventDefault();
    +        event.stopPropagation();
    +        if(popover.isSituatedAt(element) && popover.visible()) {
    +          popover.title('');
    +          popover.content('');
    +          popover.positionAway();
    +        }
    +        else {
    +          popover.title(attrs.title);
    +          popover.content(attrs.content);
    +          popover.positionBeside(element);
    +        }
    +      });
    +    }
    +  }
    +}];
    +
    +directive.tabPane = function() {
    +  return {
    +    require: '^tabbable',
    +    restrict: 'C',
    +    link: function(scope, element, attrs, tabsCtrl) {
    +      element.on('$remove', tabsCtrl.addPane(element, attrs));
    +    }
    +  };
    +};
    +
    +directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
    +  return {
    +    restrict: 'A',
    +    priority : 500,
    +    link: function(scope, element, attrs) {
    +      var container, loading, url = attrs.url;
    +      if(/\/build\//.test($window.location.href)) {
    +        url = '/build/docs' + url;
    +      }
    +      element.bind('click',function() {
    +        scope.$apply(function() {
    +          if(!container) {
    +            if(loading) return;
    +
    +            loading = true;
    +            var par = element.parent();
    +            container = angular.element('<div class="foldout">loading...</div>');
    +            $animate.enter(container, null, par);
    +
    +            $http.get(url, { cache : true }).success(function(html) {
    +              loading = false;
    +
    +              html = '<div class="foldout-inner">' +
    +                      '<div calss="foldout-arrow"></div>' +
    +                      html +
    +                     '</div>';
    +              container.html(html);
    +
    +              //avoid showing the element if the user has already closed it
    +              if(container.css('display') == 'block') {
    +                container.css('display','none');
    +                $animate.addClass(container, 'ng-hide');
    +              }
    +            });
    +          }
    +          else {
    +            container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
    +          }
    +        });
    +      });
    +    }
    +  }
    +}];
    +
    +angular.module('bootstrap', [])
    +  .directive(directive)
    +  .factory('popoverElement', popoverElement)
    +  .run(function() {
    +    marked.setOptions({
    +      gfm: true,
    +      tables: true
    +    });
    +  });
    diff --git a/docs/js/angular-bootstrap.min.js b/docs/js/angular-bootstrap.min.js
    new file mode 100644
    index 000000000..133b04f80
    --- /dev/null
    +++ b/docs/js/angular-bootstrap.min.js
    @@ -0,0 +1,11 @@
    +/*
    + AngularJS v1.1.5
    + (c) 2010-2012 Google, Inc. http://angularjs.org
    + License: MIT
    +*/
    +(function(n,i){'use strict';i.module("bootstrap",[]).directive({dropdownToggle:["$document","$location","$window",function(e,a){var d=null,b;return{restrict:"C",link:function(f,c){f.$watch(function(){return a.path()},function(){b&&b()});c.parent().bind("click",function(){b&&b()});c.bind("click",function(a){a.preventDefault();a.stopPropagation();a=!1;d&&(a=d===c,b());a||(c.parent().addClass("open"),d=c,b=function(a){a&&a.preventDefault();a&&a.stopPropagation();e.unbind("click",b);c.parent().removeClass("open");
    +d=b=null},e.bind("click",b))})}}}],syntax:function(){return{restrict:"A",link:function(e,a,d){var e="",b={github:{text:"View on Github",key:"syntaxGithub",icon:"icon-github"},plunkr:{text:"View on Plunkr",key:"syntaxPlunkr",icon:"icon-arrow-down"},jsfiddle:{text:"View on JSFiddle",key:"syntaxFiddle",icon:"icon-cloud"}},f;for(f in b){var c=b[f],k=d[c.key];k&&(e+='<a href="'+k+'" class="btn syntax-'+f+'" target="_blank" rel="nofollow"><span class="'+c.icon+'"></span> '+c.text+"</a>")}d=document.createElement("nav");
    +d.className="syntax-links";d.innerHTML=e;a=a[0];a.parentNode.insertBefore(d,a)}}},tabbable:function(){return{restrict:"C",compile:function(e){var a=i.element('<ul class="nav nav-tabs"></ul>'),d=i.element('<div class="tab-content"></div>');d.append(e.contents());e.append(a).append(d)},controller:["$scope","$element",function(e,a){var d=a.contents().eq(0),b=a.controller("ngModel")||{},f=[],c;b.$render=function(){var a=this.$viewValue;if(c?c.value!=a:a)if(c&&(c.paneElement.removeClass("active"),c.tabElement.removeClass("active"),
    +c=null),a){for(var b=0,d=f.length;b<d;b++)if(a==f[b].value){c=f[b];break}c&&(c.paneElement.addClass("active"),c.tabElement.addClass("active"))}};this.addPane=function(a,h){function l(){g.title=h.title;g.value=h.value||h.title;if(!b.$setViewValue&&(!b.$viewValue||g==c))b.$viewValue=g.value;b.$render()}var j=i.element("<li><a href></a></li>"),m=j.find("a"),g={paneElement:a,paneAttrs:h,tabElement:j};f.push(g);h.$observe("value",l)();h.$observe("title",function(){l();m.text(g.title)})();d.append(j);j.bind("click",
    +function(a){a.preventDefault();a.stopPropagation();b.$setViewValue?e.$apply(function(){b.$setViewValue(g.value);b.$render()}):(b.$viewValue=g.value,b.$render())});return function(){g.tabElement.remove();for(var a=0,b=f.length;a<b;a++)g==f[a]&&f.splice(a,1)}}}]}},table:function(){return{restrict:"E",link:function(e,a){a[0].className="table table-bordered table-striped code-table"}}},tabPane:function(){return{require:"^tabbable",restrict:"C",link:function(e,a,d,b){a.bind("$remove",b.addPane(a,d))}}}})})(window,
    +window.angular);
    diff --git a/docs/js/angular.min.js b/docs/js/angular.min.js
    new file mode 100644
    index 000000000..ac033dc89
    --- /dev/null
    +++ b/docs/js/angular.min.js
    @@ -0,0 +1,178 @@
    +/*
    + AngularJS v1.1.5
    + (c) 2010-2012 Google, Inc. http://angularjs.org
    + License: MIT
    +*/
    +(function(M,T,p){'use strict';function lc(){var b=M.angular;M.angular=mc;return b}function Xa(b){return!b||typeof b.length!=="number"?!1:typeof b.hasOwnProperty!="function"&&typeof b.constructor!="function"?!0:b instanceof R||ga&&b instanceof ga||Ea.call(b)!=="[object Object]"||typeof b.callee==="function"}function n(b,a,c){var d;if(b)if(H(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==n)b.forEach(a,c);else if(Xa(b))for(d=
    +0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function qb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function nc(b,a,c){for(var d=qb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function rb(b){return function(a,c){b(c,a)}}function Fa(){for(var b=ba.length,a;b;){b--;a=ba[b].charCodeAt(0);if(a==57)return ba[b]="A",ba.join("");if(a==90)ba[b]="0";else return ba[b]=String.fromCharCode(a+1),ba.join("")}ba.unshift("0");
    +return ba.join("")}function sb(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function t(b){var a=b.$$hashKey;n(arguments,function(a){a!==b&&n(a,function(a,c){b[c]=a})});sb(b,a);return b}function N(b){return parseInt(b,10)}function tb(b,a){return t(new (t(function(){},{prototype:b})),a)}function q(){}function qa(b){return b}function S(b){return function(){return b}}function C(b){return typeof b=="undefined"}function B(b){return typeof b!="undefined"}function L(b){return b!=null&&typeof b=="object"}function E(b){return typeof b==
    +"string"}function Ya(b){return typeof b=="number"}function ra(b){return Ea.apply(b)=="[object Date]"}function F(b){return Ea.apply(b)=="[object Array]"}function H(b){return typeof b=="function"}function sa(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function U(b){return E(b)?b.replace(/^\s*/,"").replace(/\s*$/,""):b}function oc(b){return b&&(b.nodeName||b.bind&&b.find)}function Za(b,a,c){var d=[];n(b,function(b,g,i){d.push(a.call(c,b,g,i))});return d}function Ga(b,a){if(b.indexOf)return b.indexOf(a);
    +for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function ta(b,a){var c=Ga(b,a);c>=0&&b.splice(c,1);return a}function V(b,a){if(sa(b)||b&&b.$evalAsync&&b.$watch)throw Error("Can't copy Window or Scope");if(a){if(b===a)throw Error("Can't copy equivalent objects or arrays");if(F(b))for(var c=a.length=0;c<b.length;c++)a.push(V(b[c]));else{c=a.$$hashKey;n(a,function(b,c){delete a[c]});for(var d in b)a[d]=V(b[d]);sb(a,c)}}else(a=b)&&(F(b)?a=V(b,[]):ra(b)?a=new Date(b.getTime()):L(b)&&(a=V(b,{})));
    +return a}function pc(b,a){var a=a||{},c;for(c in b)b.hasOwnProperty(c)&&c.substr(0,2)!=="$$"&&(a[c]=b[c]);return a}function ia(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&c=="object")if(F(b)){if((c=b.length)==a.length){for(d=0;d<c;d++)if(!ia(b[d],a[d]))return!1;return!0}}else if(ra(b))return ra(a)&&b.getTime()==a.getTime();else{if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||sa(b)||sa(a))return!1;c={};for(d in b)if(!(d.charAt(0)===
    +"$"||H(b[d]))){if(!ia(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c[d]&&d.charAt(0)!=="$"&&a[d]!==p&&!H(a[d]))return!1;return!0}return!1}function $a(b,a){var c=arguments.length>2?ka.call(arguments,2):[];return H(a)&&!(a instanceof RegExp)?c.length?function(){return arguments.length?a.apply(b,c.concat(ka.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function qc(b,a){var c=a;/^\$+/.test(b)?c=p:sa(a)?c="$WINDOW":a&&T===a?c="$DOCUMENT":a&&a.$evalAsync&&
    +a.$watch&&(c="$SCOPE");return c}function ha(b,a){return JSON.stringify(b,qc,a?"  ":null)}function ub(b){return E(b)?JSON.parse(b):b}function ua(b){b&&b.length!==0?(b=I(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;return b}function va(b){b=w(b).clone();try{b.html("")}catch(a){}var c=w("<div>").append(b).html();try{return b[0].nodeType===3?I(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+I(b)})}catch(d){return I(c)}}function vb(b){var a={},c,d;n((b||
    +"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=B(c[1])?decodeURIComponent(c[1]):!0)});return a}function wb(b){var a=[];n(b,function(b,d){a.push(wa(d,!0)+(b===!0?"":"="+wa(b,!0)))});return a.length?a.join("&"):""}function ab(b){return wa(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function wa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function rc(b,
    +a){function c(a){a&&d.push(a)}var d=[b],e,g,i=["ng:app","ng-app","x-ng-app","data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;n(i,function(a){i[a]=!0;c(T.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(n(b.querySelectorAll("."+a),c),n(b.querySelectorAll("."+a+"\\:"),c),n(b.querySelectorAll("["+a+"]"),c))});n(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):n(a.attributes,function(b){if(!e&&i[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])}
    +function xb(b,a){var c=function(){b=w(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");var c=yb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animator",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)});e.enabled(!0)}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(M&&!d.test(M.name))return c();M.name=M.name.replace(d,"");Ha.resumeBootstrap=function(b){n(b,function(b){a.push(b)});c()}}function bb(b,a){a=a||"_";return b.replace(sc,
    +function(b,d){return(d?a:"")+b.toLowerCase()})}function cb(b,a,c){if(!b)throw Error("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function xa(b,a,c){c&&F(b)&&(b=b[b.length-1]);cb(H(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function tc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,
    +d,e){return function(){b[e||"push"]([c,d,arguments]);return m}}if(!e)throw Error("No module: "+d);var b=[],c=[],j=a("$injector","invoke"),m={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animationProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider",
    +"directive"),config:j,run:function(a){c.push(a);return this}};g&&j(g);return m})}})}function Ia(b){return b.replace(uc,function(a,b,d,e){return e?d.toUpperCase():d}).replace(vc,"Moz$1")}function db(b,a){function c(){var e;for(var b=[this],c=a,i,f,h,j,m,k;b.length;){i=b.shift();f=0;for(h=i.length;f<h;f++){j=w(i[f]);c?j.triggerHandler("$destroy"):c=!c;m=0;for(e=(k=j.children()).length,j=e;m<j;m++)b.push(ga(k[m]))}}return d.apply(this,arguments)}var d=ga.fn[b],d=d.$original||d;c.$original=d;ga.fn[b]=
    +c}function R(b){if(b instanceof R)return b;if(!(this instanceof R)){if(E(b)&&b.charAt(0)!="<")throw Error("selectors not implemented");return new R(b)}if(E(b)){var a=T.createElement("div");a.innerHTML="<div>&#160;</div>"+b;a.removeChild(a.firstChild);eb(this,a.childNodes);this.remove()}else eb(this,b)}function fb(b){return b.cloneNode(!0)}function ya(b){zb(b);for(var a=0,b=b.childNodes||[];a<b.length;a++)ya(b[a])}function Ab(b,a,c){var d=ca(b,"events");ca(b,"handle")&&(C(a)?n(d,function(a,c){gb(b,
    +c,a);delete d[c]}):C(c)?(gb(b,a,d[a]),delete d[a]):ta(d[a],c))}function zb(b){var a=b[Ja],c=Ka[a];c&&(c.handle&&(c.events.$destroy&&c.handle({},"$destroy"),Ab(b)),delete Ka[a],b[Ja]=p)}function ca(b,a,c){var d=b[Ja],d=Ka[d||-1];if(B(c))d||(b[Ja]=d=++wc,d=Ka[d]={}),d[a]=c;else return d&&d[a]}function Bb(b,a,c){var d=ca(b,"data"),e=B(c),g=!e&&B(a),i=g&&!L(a);!d&&!i&&ca(b,"data",d={});if(e)d[a]=c;else if(g)if(i)return d&&d[a];else t(d,a);else return d}function La(b,a){return(" "+b.className+" ").replace(/[\n\t]/g,
    +" ").indexOf(" "+a+" ")>-1}function Cb(b,a){a&&n(a.split(" "),function(a){b.className=U((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+U(a)+" "," "))})}function Db(b,a){a&&n(a.split(" "),function(a){if(!La(b,a))b.className=U(b.className+" "+U(a))})}function eb(b,a){if(a)for(var a=!a.nodeName&&B(a.length)&&!sa(a)?a:[a],c=0;c<a.length;c++)b.push(a[c])}function Eb(b,a){return Ma(b,"$"+(a||"ngController")+"Controller")}function Ma(b,a,c){b=w(b);for(b[0].nodeType==9&&(b=b.find("html"));b.length;){if(c=
    +b.data(a))return c;b=b.parent()}}function Fb(b,a){var c=Na[a.toLowerCase()];return c&&Gb[b.nodeName]&&c}function xc(b,a){var c=function(c,e){if(!c.preventDefault)c.preventDefault=function(){c.returnValue=!1};if(!c.stopPropagation)c.stopPropagation=function(){c.cancelBubble=!0};if(!c.target)c.target=c.srcElement||T;if(C(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented||
    +c.returnValue==!1};n(a[e||c.type],function(a){a.call(b,c)});Z<=8?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function la(b){var a=typeof b,c;if(a=="object"&&b!==null)if(typeof(c=b.$$hashKey)=="function")c=b.$$hashKey();else{if(c===p)c=b.$$hashKey=Fa()}else c=b;return a+":"+c}function za(b){n(b,this.put,this)}function Hb(b){var a,c;if(typeof b=="function"){if(!(a=b.$inject))a=
    +[],c=b.toString().replace(yc,""),c=c.match(zc),n(c[1].split(Ac),function(b){b.replace(Bc,function(b,c,d){a.push(d)})}),b.$inject=a}else F(b)?(c=b.length-1,xa(b[c],"fn"),a=b.slice(0,c)):xa(b,"fn",!0);return a}function yb(b){function a(a){return function(b,c){if(L(b))n(b,rb(a));else return a(b,c)}}function c(a,b){if(H(b)||F(b))b=k.instantiate(b);if(!b.$get)throw Error("Provider "+a+" must define $get factory method.");return m[a+f]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[];n(a,function(a){if(!j.get(a))if(j.put(a,
    +!0),E(a)){var c=Aa(a);b=b.concat(e(c.requires)).concat(c._runBlocks);try{for(var d=c._invokeQueue,c=0,f=d.length;c<f;c++){var g=d[c],o=k.get(g[0]);o[g[1]].apply(o,g[2])}}catch(h){throw h.message&&(h.message+=" from "+a),h;}}else if(H(a))try{b.push(k.invoke(a))}catch(l){throw l.message&&(l.message+=" from "+a),l;}else if(F(a))try{b.push(k.invoke(a))}catch(i){throw i.message&&(i.message+=" from "+String(a[a.length-1])),i;}else xa(a,"module")});return b}function g(a,b){function c(d){if(typeof d!=="string")throw Error("Service name expected");
    +if(a.hasOwnProperty(d)){if(a[d]===i)throw Error("Circular dependency: "+h.join(" <- "));return a[d]}else try{return h.unshift(d),a[d]=i,a[d]=b(d)}finally{h.shift()}}function d(a,b,e){var f=[],j=Hb(a),g,o,h;o=0;for(g=j.length;o<g;o++)h=j[o],f.push(e&&e.hasOwnProperty(h)?e[h]:c(h));a.$inject||(a=a[g]);switch(b?-1:f.length){case 0:return a();case 1:return a(f[0]);case 2:return a(f[0],f[1]);case 3:return a(f[0],f[1],f[2]);case 4:return a(f[0],f[1],f[2],f[3]);case 5:return a(f[0],f[1],f[2],f[3],f[4]);
    +case 6:return a(f[0],f[1],f[2],f[3],f[4],f[5]);case 7:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6]);case 8:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7]);case 9:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]);case 10:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]);default:return a.apply(b,f)}}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(F(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return L(e)?e:c},get:c,annotate:Hb,has:function(b){return m.hasOwnProperty(b+
    +f)||a.hasOwnProperty(b)}}}var i={},f="Provider",h=[],j=new za,m={$provide:{provider:a(c),factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,S(b))}),constant:a(function(a,b){m[a]=b;l[a]=b}),decorator:function(a,b){var c=k.get(a+f),d=c.$get;c.$get=function(){var a=u.invoke(d,c);return u.invoke(b,null,{$delegate:a})}}}},k=m.$injector=g(m,function(){throw Error("Unknown provider: "+h.join(" <- "));}),l={},u=l.$injector=
    +g(l,function(a){a=k.get(a+f);return u.invoke(a.$get,a)});n(e(b),function(a){u.invoke(a||q)});return u}function Cc(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;n(a,function(a){!b&&I(a.nodeName)==="a"&&(b=a)});return b}function g(){var b=c.hash(),d;b?(d=i.getElementById(b))?d.scrollIntoView():(d=e(i.getElementsByName(b)))?d.scrollIntoView():b==="top"&&a.scrollTo(0,0):a.scrollTo(0,0)}var i=a.document;b&&d.$watch(function(){return c.hash()},
    +function(){d.$evalAsync(g)});return g}]}function Ib(b){this.register=function(a,c){b.factory(Ia(a)+"Animation",c)};this.$get=["$injector",function(a){return function(b){if(b&&(b=Ia(b)+"Animation",a.has(b)))return a.get(b)}}]}function Dc(b,a,c,d){function e(a){try{a.apply(null,ka.call(arguments,1))}finally{if(o--,o===0)for(;z.length;)try{z.pop()()}catch(b){c.error(b)}}}function g(a,b){(function s(){n(r,function(a){a()});y=b(s,a)})()}function i(){x!=f.url()&&(x=f.url(),n(v,function(a){a(f.url())}))}
    +var f=this,h=a[0],j=b.location,m=b.history,k=b.setTimeout,l=b.clearTimeout,u={};f.isMock=!1;var o=0,z=[];f.$$completeOutstandingRequest=e;f.$$incOutstandingRequestCount=function(){o++};f.notifyWhenNoOutstandingRequests=function(a){n(r,function(a){a()});o===0?a():z.push(a)};var r=[],y;f.addPollFn=function(a){C(y)&&g(100,k);r.push(a);return a};var x=j.href,W=a.find("base");f.url=function(a,b){if(a){if(x!=a)return x=a,d.history?b?m.replaceState(null,"",a):(m.pushState(null,"",a),W.attr("href",W.attr("href"))):
    +b?j.replace(a):j.href=a,f}else return j.href.replace(/%27/g,"'")};var v=[],A=!1;f.onUrlChange=function(a){A||(d.history&&w(b).bind("popstate",i),d.hashchange?w(b).bind("hashchange",i):f.addPollFn(i),A=!0);v.push(a);return a};f.baseHref=function(){var a=W.attr("href");return a?a.replace(/^https?\:\/\/[^\/]*/,""):""};var G={},D="",$=f.baseHref();f.cookies=function(a,b){var d,e,f,j;if(a)if(b===p)h.cookie=escape(a)+"=;path="+$+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(E(b))d=(h.cookie=escape(a)+
    +"="+escape(b)+";path="+$).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!")}else{if(h.cookie!==D){D=h.cookie;d=D.split("; ");G={};for(f=0;f<d.length;f++)e=d[f],j=e.indexOf("="),j>0&&(a=unescape(e.substring(0,j)),G[a]===p&&(G[a]=unescape(e.substring(j+1))))}return G}};f.defer=function(a,b){var c;o++;c=k(function(){delete u[c];e(a)},b||0);u[c]=!0;return c};f.defer.cancel=function(a){return u[a]?(delete u[a],l(a),e(q),!0):!1}}function Ec(){this.$get=
    +["$window","$log","$sniffer","$document",function(b,a,c,d){return new Dc(b,d,a,c)}]}function Fc(){this.$get=function(){function b(b,d){function e(a){if(a!=k){if(l){if(l==a)l=a.n}else l=a;g(a.n,a.p);g(a,k);k=a;k.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw Error("cacheId "+b+" taken");var i=0,f=t({},d,{id:b}),h={},j=d&&d.capacity||Number.MAX_VALUE,m={},k=null,l=null;return a[b]={put:function(a,b){var c=m[a]||(m[a]={key:a});e(c);if(!C(b))return a in h||i++,h[a]=b,i>j&&this.remove(l.key),
    +b},get:function(a){var b=m[a];if(b)return e(b),h[a]},remove:function(a){var b=m[a];if(b){if(b==k)k=b.p;if(b==l)l=b.n;g(b.n,b.p);delete m[a];delete h[a];i--}},removeAll:function(){h={};i=0;m={};k=l=null},destroy:function(){m=f=h=null;delete a[b]},info:function(){return t({},f,{size:i})}}}var a={};b.info=function(){var b={};n(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function Gc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Jb(b){var a=
    +{},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ",i=/^\s*(https?|ftp|mailto|file):/;this.directive=function h(d,e){E(d)?(cb(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];n(a[d],function(a){try{var g=b.invoke(a);if(H(g))g={compile:S(g)};else if(!g.compile&&g.link)g.compile=S(g.link);g.priority=g.priority||0;g.name=g.name||d;g.require=
    +g.require||g.controller&&g.name;g.restrict=g.restrict||"A";e.push(g)}catch(h){c(h)}});return e}])),a[d].push(e)):n(d,rb(h));return this};this.urlSanitizationWhitelist=function(a){return B(a)?(i=a,this):i};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document",function(b,j,m,k,l,u,o,z,r){function y(a,b,c){a instanceof w||(a=w(a));n(a,function(b,c){b.nodeType==3&&b.nodeValue.match(/\S+/)&&(a[c]=w(b).wrap("<span></span>").parent()[0])});
    +var d=W(a,b,a,c);return function(b,c){cb(b,"scope");for(var e=c?Ba.clone.call(a):a,j=0,g=e.length;j<g;j++){var h=e[j];(h.nodeType==1||h.nodeType==9)&&e.eq(j).data("$scope",b)}x(e,"ng-scope");c&&c(e,b);d&&d(b,e,e);return e}}function x(a,b){try{a.addClass(b)}catch(c){}}function W(a,b,c,d){function e(a,c,d,g){var h,i,k,l,o,m,u,z=[];o=0;for(m=c.length;o<m;o++)z.push(c[o]);u=o=0;for(m=j.length;o<m;u++)i=z[u],c=j[o++],h=j[o++],c?(c.scope?(k=a.$new(L(c.scope)),w(i).data("$scope",k)):k=a,(l=c.transclude)||
    +!g&&b?c(h,k,i,d,function(b){return function(c){var d=a.$new();d.$$transcluded=!0;return b(d,c).bind("$destroy",$a(d,d.$destroy))}}(l||b)):c(h,k,i,p,g)):h&&h(a,i.childNodes,p,g)}for(var j=[],g,h,k,i=0;i<a.length;i++)h=new ma,g=v(a[i],[],h,d),h=(g=g.length?A(g,a[i],h,b,c):null)&&g.terminal||!a[i].childNodes||!a[i].childNodes.length?null:W(a[i].childNodes,g?g.transclude:b),j.push(g),j.push(h),k=k||g||h;return k?e:null}function v(a,b,c,j){var g=c.$attr,h;switch(a.nodeType){case 1:G(b,da(hb(a).toLowerCase()),
    +"E",j);var i,k,l;h=a.attributes;for(var o=0,m=h&&h.length;o<m;o++)if(i=h[o],i.specified)k=i.name,l=da(k),Y.test(l)&&(k=l.substr(6).toLowerCase()),l=da(k.toLowerCase()),g[l]=k,c[l]=i=U(Z&&k=="href"?decodeURIComponent(a.getAttribute(k,2)):i.value),Fb(a,l)&&(c[l]=!0),s(a,b,i,l),G(b,l,"A",j);a=a.className;if(E(a)&&a!=="")for(;h=e.exec(a);)l=da(h[2]),G(b,l,"C",j)&&(c[l]=U(h[3])),a=a.substr(h.index+h[0].length);break;case 3:P(b,a.nodeValue);break;case 8:try{if(h=d.exec(a.nodeValue))l=da(h[1]),G(b,l,"M",
    +j)&&(c[l]=U(h[2]))}catch(u){}}b.sort(K);return b}function A(a,b,c,d,e){function h(a,b){if(a)a.require=s.require,z.push(a);if(b)b.require=s.require,ea.push(b)}function i(a,b){var c,d="data",e=!1;if(E(a)){for(;(c=a.charAt(0))=="^"||c=="?";)a=a.substr(1),c=="^"&&(d="inheritedData"),e=e||c=="?";c=b[d]("$"+a+"Controller");if(!c&&!e)throw Error("No controller: "+a);}else F(a)&&(c=[],n(a,function(a){c.push(i(a,b))}));return c}function k(a,d,e,g,h){var l,v,r,D,x;l=b===e?c:pc(c,new ma(w(e),c.$attr));v=l.$$element;
    +if(K){var y=/^\s*([@=&])(\??)\s*(\w*)\s*$/,s=d.$parent||d;n(K.scope,function(a,b){var c=a.match(y)||[],e=c[3]||b,g=c[2]=="?",c=c[1],h,k,i;d.$$isolateBindings[b]=c+e;switch(c){case "@":l.$observe(e,function(a){d[b]=a});l.$$observers[e].$$scope=s;l[e]&&(d[b]=j(l[e])(s));break;case "=":if(g&&!l[e])break;k=u(l[e]);i=k.assign||function(){h=d[b]=k(s);throw Error(Kb+l[e]+" (directive: "+K.name+")");};h=d[b]=k(s);d.$watch(function(){var a=k(s);a!==d[b]&&(a!==h?h=d[b]=a:i(s,a=h=d[b]));return a});break;case "&":k=
    +u(l[e]);d[b]=function(a){return k(s,a)};break;default:throw Error("Invalid isolate scope definition for directive "+K.name+": "+a);}})}q&&n(q,function(a){var b={$scope:d,$element:v,$attrs:l,$transclude:h};x=a.controller;x=="@"&&(x=l[a.name]);v.data("$"+a.name+"Controller",o(x,b))});g=0;for(r=z.length;g<r;g++)try{D=z[g],D(d,v,l,D.require&&i(D.require,v))}catch(Hc){m(Hc,va(v))}a&&a(d,e.childNodes,p,h);g=0;for(r=ea.length;g<r;g++)try{D=ea[g],D(d,v,l,D.require&&i(D.require,v))}catch(J){m(J,va(v))}}for(var l=
    +-Number.MAX_VALUE,z=[],ea=[],r=null,K=null,W=null,J=c.$$element=w(b),s,A,Y,G,P=d,q,na,t,B=0,C=a.length;B<C;B++){s=a[B];Y=p;if(l>s.priority)break;if(t=s.scope)O("isolated scope",K,s,J),L(t)&&(x(J,"ng-isolate-scope"),K=s),x(J,"ng-scope"),r=r||s;A=s.name;if(t=s.controller)q=q||{},O("'"+A+"' controller",q[A],s,J),q[A]=s;if(t=s.transclude)O("transclusion",G,s,J),G=s,l=s.priority,t=="element"?(Y=w(b),J=c.$$element=w(T.createComment(" "+A+": "+c[A]+" ")),b=J[0],ja(e,w(Y[0]),b),P=y(Y,d,l)):(Y=w(fb(b)).contents(),
    +J.html(""),P=y(Y,d));if(s.template)if(O("template",W,s,J),W=s,t=H(s.template)?s.template(J,c):s.template,t=Lb(t),s.replace){Y=w("<div>"+U(t)+"</div>").contents();b=Y[0];if(Y.length!=1||b.nodeType!==1)throw Error(g+t);ja(e,J,b);A={$attr:{}};a=a.concat(v(b,a.splice(B+1,a.length-(B+1)),A));D(c,A);C=a.length}else J.html(t);if(s.templateUrl)O("template",W,s,J),W=s,k=$(a.splice(B,a.length-B),k,J,c,e,s.replace,P),C=a.length;else if(s.compile)try{na=s.compile(J,c,P),H(na)?h(null,na):na&&h(na.pre,na.post)}catch(I){m(I,
    +va(J))}if(s.terminal)k.terminal=!0,l=Math.max(l,s.priority)}k.scope=r&&r.scope;k.transclude=G&&P;return k}function G(d,e,j,g){var l=!1;if(a.hasOwnProperty(e))for(var k,e=b.get(e+c),i=0,o=e.length;i<o;i++)try{if(k=e[i],(g===p||g>k.priority)&&k.restrict.indexOf(j)!=-1)d.push(k),l=!0}catch(u){m(u)}return l}function D(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;n(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});n(b,function(b,j){j=="class"?(x(e,b),a["class"]=
    +(a["class"]?a["class"]+" ":"")+b):j=="style"?e.attr("style",e.attr("style")+";"+b):j.charAt(0)!="$"&&!a.hasOwnProperty(j)&&(a[j]=b,d[j]=c[j])})}function $(a,b,c,d,e,j,h){var i=[],o,m,u=c[0],z=a.shift(),r=t({},z,{controller:null,templateUrl:null,transclude:null,scope:null}),z=H(z.templateUrl)?z.templateUrl(c,d):z.templateUrl;c.html("");k.get(z,{cache:l}).success(function(l){var k,z,l=Lb(l);if(j){z=w("<div>"+U(l)+"</div>").contents();k=z[0];if(z.length!=1||k.nodeType!==1)throw Error(g+l);l={$attr:{}};
    +ja(e,c,k);v(k,a,l);D(d,l)}else k=u,c.html(l);a.unshift(r);o=A(a,k,d,h);for(m=W(c[0].childNodes,h);i.length;){var ea=i.shift(),l=i.shift();z=i.shift();var x=i.shift(),y=k;l!==u&&(y=fb(k),ja(z,w(l),y));o(function(){b(m,ea,y,e,x)},ea,y,e,x)}i=null}).error(function(a,b,c,d){throw Error("Failed to load template: "+d.url);});return function(a,c,d,e,j){i?(i.push(c),i.push(d),i.push(e),i.push(j)):o(function(){b(m,c,d,e,j)},c,d,e,j)}}function K(a,b){return b.priority-a.priority}function O(a,b,c,d){if(b)throw Error("Multiple directives ["+
    +b.name+", "+c.name+"] asking for "+a+" on: "+va(d));}function P(a,b){var c=j(b,!0);c&&a.push({priority:0,compile:S(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);x(d.data("$binding",e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function s(a,b,c,d){var e=j(c,!0);e&&b.push({priority:100,compile:S(function(a,b,c){b=c.$$observers||(c.$$observers={});if(e=j(c[d],!0))c[d]=e(a),(b[d]||(b[d]=[])).$$inter=!0,(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,
    +a)})})})}function ja(a,b,c){var d=b[0],e=d.parentNode,j,g;if(a){j=0;for(g=a.length;j<g;j++)if(a[j]==d){a[j]=c;break}}e&&e.replaceChild(c,d);c[w.expando]=d[w.expando];b[0]=c}var ma=function(a,b){this.$$element=a;this.$attr=b||{}};ma.prototype={$normalize:da,$set:function(a,b,c,d){var e=Fb(this.$$element[0],a),j=this.$$observers;e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=bb(a,"-"));if(hb(this.$$element[0])==="A"&&a==="href")q.setAttribute("href",
    +b),e=q.href,e.match(i)||(this[a]=b="unsafe:"+e);c!==!1&&(b===null||b===p?this.$$element.removeAttr(d):this.$$element.attr(d,b));j&&n(j[a],function(a){try{a(b)}catch(c){m(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);z.$evalAsync(function(){e.$$inter||b(c[a])});return b}};var q=r[0].createElement("a"),ea=j.startSymbol(),J=j.endSymbol(),Lb=ea=="{{"||J=="}}"?qa:function(a){return a.replace(/\{\{/g,ea).replace(/}}/g,J)},Y=/^ngAttr[A-Z]/;return y}]}
    +function da(b){return Ia(b.replace(Ic,""))}function Jc(){var b={},a=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,d){L(a)?t(b,a):b[a]=d};this.$get=["$injector","$window",function(c,d){return function(e,g){var i,f;E(e)&&(f=e.match(a),i=f[1],f=f[3],e=b.hasOwnProperty(i)?b[i]:ib(g.$scope,i,!0)||ib(d,i,!0),xa(e,i,!0));i=c.instantiate(e,g);if(f){if(typeof g.$scope!=="object")throw Error('Can not export controller as "'+f+'". No scope object provided!');g.$scope[f]=i}return i}}]}function Kc(){this.$get=
    +["$window",function(b){return w(b.document)}]}function Lc(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Mc(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler",function(c,d){function e(e,h){for(var j,m,k=0,l=[],u=e.length,o=!1,z=[];k<u;)(j=e.indexOf(b,k))!=-1&&(m=e.indexOf(a,j+g))!=-1?(k!=j&&l.push(e.substring(k,j)),l.push(k=c(o=e.substring(j+g,
    +m))),k.exp=o,k=m+i,o=!0):(k!=u&&l.push(e.substring(k)),k=u);if(!(u=l.length))l.push(""),u=1;if(!h||o)return z.length=u,k=function(a){try{for(var b=0,c=u,j;b<c;b++){if(typeof(j=l[b])=="function")j=j(a),j==null||j==p?j="":typeof j!="string"&&(j=ha(j));z[b]=j}return z.join("")}catch(g){d(Error("Error while interpolating: "+e+"\n"+g.toString()))}},k.exp=e,k.parts=l,k}var g=b.length,i=a.length;e.startSymbol=function(){return b};e.endSymbol=function(){return a};return e}]}function Mb(b){for(var b=b.split("/"),
    +a=b.length;a--;)b[a]=ab(b[a]);return b.join("/")}function Nb(b,a){var c=jb.exec(b);a.$$protocol=c[1];a.$$host=c[3];a.$$port=N(c[5])||Oa[c[1]]||null}function Ob(b,a){var c=Pb.exec(b);a.$$path=decodeURIComponent(c[1]);a.$$search=vb(c[3]);a.$$hash=decodeURIComponent(c[5]||"");if(a.$$path&&a.$$path.charAt(0)!="/")a.$$path="/"+a.$$path}function fa(b,a,c){return a.indexOf(b)==0?a.substr(b.length):c}function Ca(b){var a=b.indexOf("#");return a==-1?b:b.substr(0,a)}function kb(b){return b.substr(0,Ca(b).lastIndexOf("/")+
    +1)}function Qb(b,a){var a=a||"",c=kb(b);this.$$parse=function(a){var b={};Nb(a,b);var g=fa(c,a);if(!E(g))throw Error('Invalid url "'+a+'", missing path prefix "'+c+'".');Ob(g,b);t(this,b);if(!this.$$path)this.$$path="/";this.$$compose()};this.$$compose=function(){var a=wb(this.$$search),b=this.$$hash?"#"+ab(this.$$hash):"";this.$$url=Mb(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;if((e=fa(b,d))!==p)return d=e,(e=fa(a,e))!==p?c+(fa("/",e)||e):
    +b+d;else if((e=fa(c,d))!==p)return c+e;else if(c==d+"/")return c}}function lb(b,a){var c=kb(b);this.$$parse=function(d){Nb(d,this);var e=fa(b,d)||fa(c,d);if(!E(e))throw Error('Invalid url "'+d+'", does not start with "'+b+'".');e=e.charAt(0)=="#"?fa(a,e):e;if(!E(e))throw Error('Invalid url "'+d+'", missing hash prefix "'+a+'".');Ob(e,this);this.$$compose()};this.$$compose=function(){var c=wb(this.$$search),e=this.$$hash?"#"+ab(this.$$hash):"";this.$$url=Mb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=
    +b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(Ca(b)==Ca(a))return a}}function Rb(b,a){lb.apply(this,arguments);var c=kb(b);this.$$rewrite=function(d){var e;if(b==Ca(d))return d;else if(e=fa(c,d))return b+a+e;else if(c===d+"/")return c}}function Pa(b){return function(){return this[b]}}function Sb(b,a){return function(c){if(C(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Nc(){var b="",a=!1;this.hashPrefix=function(a){return B(a)?(b=a,this):b};this.html5Mode=function(b){return B(b)?
    +(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function i(a){c.$broadcast("$locationChangeSuccess",f.absUrl(),a)}var f,h=d.baseHref(),j=d.url();a?(h=h?j.substring(0,j.indexOf("/",j.indexOf("//")+2))+h:j,e=e.history?Qb:Rb):(h=Ca(j),e=lb);f=new e(h,"#"+b);f.$$parse(f.$$rewrite(j));g.bind("click",function(a){if(!a.ctrlKey&&!(a.metaKey||a.which==2)){for(var b=w(a.target);I(b[0].nodeName)!=="a";)if(b[0]===g[0]||!(b=b.parent())[0])return;var e=b.prop("href"),
    +j=f.$$rewrite(e);e&&!b.attr("target")&&j&&!a.isDefaultPrevented()&&(a.preventDefault(),j!=d.url()&&(f.$$parse(j),c.$apply(),M.angular["ff-684208-preventDefault"]=!0))}});f.absUrl()!=j&&d.url(f.absUrl(),!0);d.onUrlChange(function(a){f.absUrl()!=a&&(c.$broadcast("$locationChangeStart",a,f.absUrl()).defaultPrevented?d.url(f.absUrl()):(c.$evalAsync(function(){var b=f.absUrl();f.$$parse(a);i(b)}),c.$$phase||c.$digest()))});var m=0;c.$watch(function(){var a=d.url(),b=f.$$replace;if(!m||a!=f.absUrl())m++,
    +c.$evalAsync(function(){c.$broadcast("$locationChangeStart",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=!1;return m});return f}]}function Oc(){var b=!0,a=this;this.debugEnabled=function(a){return B(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=
    +c.console||{},e=b[a]||b.log||q;return e.apply?function(){var a=[];n(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,b)}}return{log:e("log"),warn:e("warn"),info:e("info"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function Pc(b,a){function c(a){return a.indexOf(r)!=-1}function d(a){a=a||1;return o+a<b.length?b.charAt(o+a):!1}function e(a){return"0"<=a&&a<="9"}function g(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||
    +a=="\u000b"||a=="\u00a0"}function i(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function f(a){return a=="-"||a=="+"||e(a)}function h(a,c,d){d=d||o;throw Error("Lexer Error: "+a+" at column"+(B(c)?"s "+c+"-"+o+" ["+b.substring(c,d)+"]":" "+d)+" in expression ["+b+"].");}function j(){for(var a="",c=o;o<b.length;){var j=I(b.charAt(o));if(j=="."||e(j))a+=j;else{var g=d();if(j=="e"&&f(g))a+=j;else if(f(j)&&g&&e(g)&&a.charAt(a.length-1)=="e")a+=j;else if(f(j)&&(!g||!e(g))&&a.charAt(a.length-
    +1)=="e")h("Invalid exponent");else break}o++}a*=1;l.push({index:c,text:a,json:!0,fn:function(){return a}})}function m(){for(var c="",d=o,f,j,h,k;o<b.length;){k=b.charAt(o);if(k=="."||i(k)||e(k))k=="."&&(f=o),c+=k;else break;o++}if(f)for(j=o;j<b.length;){k=b.charAt(j);if(k=="("){h=c.substr(f-d+1);c=c.substr(0,f-d);o=j;break}if(g(k))j++;else break}d={index:d,text:c};if(Da.hasOwnProperty(c))d.fn=d.json=Da[c];else{var m=Tb(c,a);d.fn=t(function(a,b){return m(a,b)},{assign:function(a,b){return Ub(a,c,b)}})}l.push(d);
    +h&&(l.push({index:f,text:".",json:!1}),l.push({index:f+1,text:h,json:!1}))}function k(a){var c=o;o++;for(var d="",e=a,f=!1;o<b.length;){var j=b.charAt(o);e+=j;if(f)j=="u"?(j=b.substring(o+1,o+5),j.match(/[\da-f]{4}/i)||h("Invalid unicode escape [\\u"+j+"]"),o+=4,d+=String.fromCharCode(parseInt(j,16))):(f=Qc[j],d+=f?f:j),f=!1;else if(j=="\\")f=!0;else if(j==a){o++;l.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}else d+=j;o++}h("Unterminated quote",c)}for(var l=[],u,o=0,z=[],
    +r,y=":";o<b.length;){r=b.charAt(o);if(c("\"'"))k(r);else if(e(r)||c(".")&&e(d()))j();else if(i(r)){if(m(),"{,".indexOf(y)!=-1&&z[0]=="{"&&(u=l[l.length-1]))u.json=u.text.indexOf(".")==-1}else if(c("(){}[].,;:?"))l.push({index:o,text:r,json:":[,".indexOf(y)!=-1&&c("{[")||c("}]:,")}),c("{[")&&z.unshift(r),c("}]")&&z.shift(),o++;else if(g(r)){o++;continue}else{var x=r+d(),n=x+d(2),v=Da[r],A=Da[x],G=Da[n];G?(l.push({index:o,text:n,fn:G}),o+=3):A?(l.push({index:o,text:x,fn:A}),o+=2):v?(l.push({index:o,
    +text:r,fn:v,json:"[,:".indexOf(y)!=-1&&c("+-")}),o+=1):h("Unexpected next character ",o,o+1)}y=r}return l}function Rc(b,a,c,d){function e(a,c){throw Error("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}function g(){if(O.length===0)throw Error("Unexpected end of expression: "+b);return O[0]}function i(a,b,c,d){if(O.length>0){var e=O[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,
    +c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),O.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function j(a,b){return t(function(c,d){return a(c,d,b)},{constant:b.constant})}function m(a,b,c){return t(function(d,e){return a(d,e)?b(d,e):c(d,e)},{constant:a.constant&&b.constant&&c.constant})}function k(a,b,c){return t(function(d,e){return b(d,e,a,c)},{constant:a.constant&&c.constant})}function l(){for(var a=[];;)if(O.length>0&&!i("}",")",";","]")&&a.push(w()),
    +!f(";"))return a.length==1?a[0]:function(b,c){for(var d,e=0;e<a.length;e++){var f=a[e];f&&(d=f(b,c))}return d}}function u(){for(var a=f(),b=c(a.text),d=[];;)if(a=f(":"))d.push(P());else{var e=function(a,c,e){for(var e=[e],f=0;f<d.length;f++)e.push(d[f](a,c));return b.apply(a,e)};return function(){return e}}}function o(){var a=z(),b,c;if(f("?"))if(b=o(),c=f(":"))return m(a,b,o());else e("expected :",c);else return a}function z(){for(var a=r(),b;;)if(b=f("||"))a=k(a,b.fn,r());else return a}function r(){var a=
    +y(),b;if(b=f("&&"))a=k(a,b.fn,r());return a}function y(){var a=x(),b;if(b=f("==","!=","===","!=="))a=k(a,b.fn,y());return a}function x(){var a;a=n();for(var b;b=f("+","-");)a=k(a,b.fn,n());if(b=f("<",">","<=",">="))a=k(a,b.fn,x());return a}function n(){for(var a=v(),b;b=f("*","/","%");)a=k(a,b.fn,v());return a}function v(){var a;return f("+")?A():(a=f("-"))?k($,a.fn,v()):(a=f("!"))?j(a.fn,v()):A()}function A(){var a;if(f("("))a=w(),h(")");else if(f("["))a=G();else if(f("{"))a=D();else{var b=f();(a=
    +b.fn)||e("not a primary expression",b);if(b.json)a.constant=a.literal=!0}for(var c;b=f("(","[",".");)b.text==="("?(a=s(a,c),c=null):b.text==="["?(c=a,a=ma(a)):b.text==="."?(c=a,a=ja(a)):e("IMPOSSIBLE");return a}function G(){var a=[],b=!0;if(g().text!="]"){do{var c=P();a.push(c);c.constant||(b=!1)}while(f(","))}h("]");return t(function(b,c){for(var d=[],e=0;e<a.length;e++)d.push(a[e](b,c));return d},{literal:!0,constant:b})}function D(){var a=[],b=!0;if(g().text!="}"){do{var c=f(),c=c.string||c.text;
    +h(":");var d=P();a.push({key:c,value:d});d.constant||(b=!1)}while(f(","))}h("}");return t(function(b,c){for(var d={},e=0;e<a.length;e++){var f=a[e];d[f.key]=f.value(b,c)}return d},{literal:!0,constant:b})}var $=S(0),K,O=Pc(b,d),P=function(){var a=o(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+b.substring(0,d.index)+"] can not be assigned to",d),c=o(),function(b,d){return a.assign(b,c(b,d),d)}):a},s=function(a,b){var c=[];if(g().text!=")"){do c.push(P());while(f(","))}h(")");return function(d,
    +e){for(var f=[],j=b?b(d,e):d,g=0;g<c.length;g++)f.push(c[g](d,e));g=a(d,e,j)||q;return g.apply?g.apply(j,f):g(f[0],f[1],f[2],f[3],f[4])}},ja=function(a){var b=f().text,c=Tb(b,d);return t(function(b,d,e){return c(e||a(b,d),d)},{assign:function(c,d,e){return Ub(a(c,e),b,d)}})},ma=function(a){var b=P();h("]");return t(function(c,d){var e=a(c,d),f=b(c,d),j;if(!e)return p;if((e=e[f])&&e.then){j=e;if(!("$$v"in e))j.$$v=p,j.then(function(a){j.$$v=a});e=e.$$v}return e},{assign:function(c,d,e){return a(c,
    +e)[b(c,e)]=d}})},w=function(){for(var a=P(),b;;)if(b=f("|"))a=k(a,b.fn,u());else return a};a?(P=z,s=ja=ma=w=function(){e("is not valid json",{text:b,index:0})},K=A()):K=l();O.length!==0&&e("is an unexpected token",O[0]);K.literal=!!K.literal;K.constant=!!K.constant;return K}function Ub(b,a,c){for(var a=a.split("."),d=0;a.length>1;d++){var e=a.shift(),g=b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function ib(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;i<g;i++)d=a[i],b&&(b=
    +(e=b)[d]);return!c&&H(b)?$a(e,b):b}function Vb(b,a,c,d,e){return function(g,i){var f=i&&i.hasOwnProperty(b)?i:g,h;if(f===null||f===p)return f;if((f=f[b])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!a||f===null||f===p)return f;if((f=f[a])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!c||f===null||f===p)return f;if((f=f[c])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!d||f===null||f===p)return f;if((f=
    +f[d])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!e||f===null||f===p)return f;if((f=f[e])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}return f}}function Tb(b,a){if(mb.hasOwnProperty(b))return mb[b];var c=b.split("."),d=c.length,e;if(a)e=d<6?Vb(c[0],c[1],c[2],c[3],c[4]):function(a,b){var e=0,j;do j=Vb(c[e++],c[e++],c[e++],c[e++],c[e++])(a,b),b=p,a=j;while(e<d);return j};else{var g="var l, fn, p;\n";n(c,function(a,b){g+="if(s === null || s === undefined) return s;\nl=s;\ns="+
    +(b?"s":'((k&&k.hasOwnProperty("'+a+'"))?k:s)')+'["'+a+'"];\nif (s && s.then) {\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n'});g+="return s;";e=Function("s","k",g);e.toString=function(){return g}}return mb[b]=e}function Sc(){var b={};this.$get=["$filter","$sniffer",function(a,c){return function(d){switch(typeof d){case "string":return b.hasOwnProperty(d)?b[d]:b[d]=Rc(d,!1,a,c.csp);case "function":return d;default:return q}}}]}function Tc(){this.$get=
    +["$rootScope","$exceptionHandler",function(b,a){return Uc(function(a){b.$evalAsync(a)},a)}]}function Uc(b,a){function c(a){return a}function d(a){return i(a)}var e=function(){var f=[],h,j;return j={resolve:function(a){if(f){var c=f;f=p;h=g(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],h.then(a[0],a[1])})}},reject:function(a){j.resolve(i(a))},promise:{then:function(b,j){var g=e(),i=function(d){try{g.resolve((b||c)(d))}catch(e){a(e),g.reject(e)}},o=function(b){try{g.resolve((j||
    +d)(b))}catch(c){a(c),g.reject(c)}};f?f.push([i,o]):h.then(i,o);return g.promise},always:function(a){function b(a,c){var d=e();c?d.resolve(a):d.reject(a);return d.promise}function d(e,f){var j=null;try{j=(a||c)()}catch(g){return b(g,!1)}return j&&j.then?j.then(function(){return b(e,f)},function(a){return b(a,!1)}):b(e,f)}return this.then(function(a){return d(a,!0)},function(a){return d(a,!1)})}}}},g=function(a){return a&&a.then?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},
    +i=function(a){return{then:function(c,j){var g=e();b(function(){g.resolve((j||d)(a))});return g.promise}}};return{defer:e,reject:i,when:function(f,h,j){var m=e(),k,l=function(b){try{return(h||c)(b)}catch(d){return a(d),i(d)}},u=function(b){try{return(j||d)(b)}catch(c){return a(c),i(c)}};b(function(){g(f).then(function(a){k||(k=!0,m.resolve(g(a).then(l,u)))},function(a){k||(k=!0,m.resolve(u(a)))})});return m.promise},all:function(a){var b=e(),c=0,d=F(a)?[]:{};n(a,function(a,e){c++;g(a).then(function(a){d.hasOwnProperty(e)||
    +(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});c===0&&b.resolve(d);return b.promise}}}function Vc(){var b={};this.when=function(a,c){b[a]=t({reloadOnSearch:!0,caseInsensitiveMatch:!1},c);if(a){var d=a[a.length-1]=="/"?a.substr(0,a.length-1):a+"/";b[d]={redirectTo:a}}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache",function(a,c,d,e,g,i,f){function h(a,b,c){for(var b=
    +"^"+b.replace(/[-\/\\^$:*+?.()|[\]{}]/g,"\\$&")+"$",d="",e=[],f={},j=/\\([:*])(\w+)/g,g,i=0;(g=j.exec(b))!==null;){d+=b.slice(i,g.index);switch(g[1]){case ":":d+="([^\\/]*)";break;case "*":d+="(.*)"}e.push(g[2]);i=j.lastIndex}d+=b.substr(i);var h=a.match(RegExp(d,c.caseInsensitiveMatch?"i":""));h&&n(e,function(a,b){f[a]=h[b+1]});return h?f:null}function j(){var b=m(),j=u.current;if(b&&j&&b.$$route===j.$$route&&ia(b.pathParams,j.pathParams)&&!b.reloadOnSearch&&!l)j.params=b.params,V(j.params,d),a.$broadcast("$routeUpdate",
    +j);else if(b||j)l=!1,a.$broadcast("$routeChangeStart",b,j),(u.current=b)&&b.redirectTo&&(E(b.redirectTo)?c.path(k(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams,c.path(),c.search())).replace()),e.when(b).then(function(){if(b){var a=t({},b.resolve),c;n(a,function(b,c){a[c]=E(b)?g.get(b):g.invoke(b)});if(B(c=b.template))H(c)&&(c=c(b.params));else if(B(c=b.templateUrl))if(H(c)&&(c=c(b.params)),B(c))b.loadedTemplateUrl=c,c=i.get(c,{cache:f}).then(function(a){return a.data});
    +B(c)&&(a.$template=c);return e.all(a)}}).then(function(c){if(b==u.current){if(b)b.locals=c,V(b.params,d);a.$broadcast("$routeChangeSuccess",b,j)}},function(c){b==u.current&&a.$broadcast("$routeChangeError",b,j,c)})}function m(){var a,d;n(b,function(b,e){if(!d&&(a=h(c.path(),e,b)))d=tb(b,{params:t({},c.search(),a),pathParams:a}),d.$$route=b});return d||b[null]&&tb(b[null],{params:{},pathParams:{}})}function k(a,b){var c=[];n((a||"").split(":"),function(a,d){if(d==0)c.push(a);else{var e=a.match(/(\w+)(.*)/),
    +f=e[1];c.push(b[f]);c.push(e[2]||"");delete b[f]}});return c.join("")}var l=!1,u={routes:b,reload:function(){l=!0;a.$evalAsync(j)}};a.$on("$locationChangeSuccess",j);return u}]}function Wc(){this.$get=S({})}function Xc(){var b=10;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){function e(){this.$id=Fa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;
    +this["this"]=this.$root=this;this.$$destroyed=!1;this.$$asyncQueue=[];this.$$listeners={};this.$$isolateBindings={}}function g(a){if(h.$$phase)throw Error(h.$$phase+" already in progress");h.$$phase=a}function i(a,b){var c=d(a);xa(c,b);return c}function f(){}e.prototype={$new:function(a){if(H(a))throw Error("API-CHANGE: Use $controller to instantiate controllers.");a?(a=new e,a.$root=this.$root):(a=function(){},a.prototype=this,a=new a,a.$id=Fa());a["this"]=a;a.$$listeners={};a.$parent=this;a.$$watchers=
    +a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,c){var d=i(a,"watch"),e=this.$$watchers,g={fn:b,last:f,get:d,exp:a,eq:!!c};if(!H(b)){var h=i(b||q,"listener");g.fn=function(a,b,c){h(c)}}if(typeof a=="string"&&d.constant){var r=g.fn;g.fn=function(a,b,c){r.call(this,a,b,c);ta(e,g)}}if(!e)e=this.$$watchers=[];e.unshift(g);return function(){ta(e,
    +g)}},$watchCollection:function(a,b){var c=this,e,f,g=0,i=d(a),h=[],n={},x=0;return this.$watch(function(){f=i(c);var a,b;if(L(f))if(Xa(f)){if(e!==h)e=h,x=e.length=0,g++;a=f.length;if(x!==a)g++,e.length=x=a;for(b=0;b<a;b++)e[b]!==f[b]&&(g++,e[b]=f[b])}else{e!==n&&(e=n={},x=0,g++);a=0;for(b in f)f.hasOwnProperty(b)&&(a++,e.hasOwnProperty(b)?e[b]!==f[b]&&(g++,e[b]=f[b]):(x++,e[b]=f[b],g++));if(x>a)for(b in g++,e)e.hasOwnProperty(b)&&!f.hasOwnProperty(b)&&(x--,delete e[b])}else e!==f&&(e=f,g++);return g},
    +function(){b(f,e,c)})},$digest:function(){var a,d,e,i,u=this.$$asyncQueue,o,z,r=b,n,x=[],p,v;g("$digest");do{z=!1;for(n=this;u.length;)try{n.$eval(u.shift())}catch(A){c(A)}do{if(i=n.$$watchers)for(o=i.length;o--;)try{if(a=i[o],(d=a.get(n))!==(e=a.last)&&!(a.eq?ia(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))z=!0,a.last=a.eq?V(d):d,a.fn(d,e===f?d:e,n),r<5&&(p=4-r,x[p]||(x[p]=[]),v=H(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,v+="; newVal: "+ha(d)+"; oldVal: "+ha(e),x[p].push(v))}catch(G){c(G)}if(!(i=
    +n.$$childHead||n!==this&&n.$$nextSibling))for(;n!==this&&!(i=n.$$nextSibling);)n=n.$parent}while(n=i);if(z&&!r--)throw h.$$phase=null,Error(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+ha(x));}while(z||u.length);h.$$phase=null},$destroy:function(){if(!(h==this||this.$$destroyed)){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==this)a.$$childTail=this.$$prevSibling;
    +if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{h.$$phase=null;try{h.$digest()}catch(d){throw c(d),d;}}},$on:function(a,b){var c=this.$$listeners[a];
    +c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[Ga(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,i={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){i.defaultPrevented=!0},defaultPrevented:!1},h=[i].concat(ka.call(arguments,1)),n,x;do{e=f.$$listeners[a]||d;i.currentScope=f;n=0;for(x=e.length;n<x;n++)if(e[n])try{if(e[n].apply(null,h),g)return i}catch(p){c(p)}else e.splice(n,1),n--,x--;f=f.$parent}while(f);return i},$broadcast:function(a,b){var d=
    +this,e=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(ka.call(arguments,1)),i,h;do{d=e;f.currentScope=d;e=d.$$listeners[a]||[];i=0;for(h=e.length;i<h;i++)if(e[i])try{e[i].apply(null,g)}catch(n){c(n)}else e.splice(i,1),i--,h--;if(!(e=d.$$childHead||d!==this&&d.$$nextSibling))for(;d!==this&&!(e=d.$$nextSibling);)d=d.$parent}while(d=e);return f}};var h=new e;return h}]}function Yc(){this.$get=["$window","$document",function(b,a){var c=
    +{},d=N((/android (\d+)/.exec(I((b.navigator||{}).userAgent))||[])[1]),e=a[0]||{},g,i=/^(Moz|webkit|O|ms)(?=[A-Z])/,f=e.body&&e.body.style,h=!1,j=!1;if(f){for(var m in f)if(h=i.exec(m)){g=h[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}h=!!("transition"in f||g+"Transition"in f);j=!!("animation"in f||g+"Animation"in f)}return{history:!(!b.history||!b.history.pushState||d<4),hashchange:"onhashchange"in b&&(!e.documentMode||e.documentMode>7),hasEvent:function(a){if(a=="input"&&Z==9)return!1;if(C(c[a])){var b=
    +e.createElement("div");c[a]="on"+a in b}return c[a]},csp:e.securityPolicy?e.securityPolicy.isActive:!1,vendorPrefix:g,transitions:h,animations:j}}]}function Zc(){this.$get=S(M)}function Wb(b){var a={},c,d,e;if(!b)return a;n(b.split("\n"),function(b){e=b.indexOf(":");c=I(U(b.substr(0,e)));d=U(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function $c(b,a){var c=ad.exec(b);if(c==null)return!0;var d={protocol:c[2],host:c[4],port:N(c[6])||Oa[c[2]]||null,relativeProtocol:c[2]===p||c[2]===""},
    +c=jb.exec(a),c={protocol:c[1],host:c[3],port:N(c[5])||Oa[c[1]]||null};return(d.protocol==c.protocol||d.relativeProtocol)&&d.host==c.host&&(d.port==c.port||d.relativeProtocol&&c.port==Oa[c.protocol])}function Xb(b){var a=L(b)?b:p;return function(c){a||(a=Wb(b));return c?a[I(c)]||null:a}}function Yb(b,a,c){if(H(c))return c(b,a);n(c,function(c){b=c(b,a)});return b}function bd(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults=
    +{transformResponse:[function(d){E(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=ub(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Ea.apply(a)!=="[object File]"?ha(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:d,put:d,patch:d},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},g=this.interceptors=[],i=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,k,l){function u(a){function c(a){var b=
    +t({},a,{data:Yb(a.data,a.headers,d.transformResponse)});return 200<=a.status&&a.status<300?b:k.reject(b)}var d={transformRequest:e.transformRequest,transformResponse:e.transformResponse},f={};t(d,a);d.headers=f;d.method=oa(d.method);t(f,e.headers.common,e.headers[I(d.method)],a.headers);(a=$c(d.url,b.url())?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:p)&&(f[d.xsrfHeaderName||e.xsrfHeaderName]=a);var g=[function(a){var b=Yb(a.data,Xb(f),a.transformRequest);C(a.data)&&delete f["Content-Type"];if(C(a.withCredentials)&&
    +!C(e.withCredentials))a.withCredentials=e.withCredentials;return o(a,b,f).then(c,c)},p],j=k.when(d);for(n(y,function(a){(a.request||a.requestError)&&g.unshift(a.request,a.requestError);(a.response||a.responseError)&&g.push(a.response,a.responseError)});g.length;)var a=g.shift(),i=g.shift(),j=j.then(a,i);j.success=function(a){j.then(function(b){a(b.data,b.status,b.headers,d)});return j};j.error=function(a){j.then(null,function(b){a(b.data,b.status,b.headers,d)});return j};return j}function o(b,c,g){function j(a,
    +b,c){n&&(200<=a&&a<300?n.put(s,[a,b,Wb(c)]):n.remove(s));i(b,a,c);d.$$phase||d.$apply()}function i(a,c,d){c=Math.max(c,0);(200<=c&&c<300?l.resolve:l.reject)({data:a,status:c,headers:Xb(d),config:b})}function h(){var a=Ga(u.pendingRequests,b);a!==-1&&u.pendingRequests.splice(a,1)}var l=k.defer(),o=l.promise,n,p,s=z(b.url,b.params);u.pendingRequests.push(b);o.then(h,h);if((b.cache||e.cache)&&b.cache!==!1&&b.method=="GET")n=L(b.cache)?b.cache:L(e.cache)?e.cache:r;if(n)if(p=n.get(s))if(p.then)return p.then(h,
    +h),p;else F(p)?i(p[1],p[0],V(p[2])):i(p,200,{});else n.put(s,o);p||a(b.method,s,c,j,g,b.timeout,b.withCredentials,b.responseType);return o}function z(a,b){if(!b)return a;var c=[];nc(b,function(a,b){a==null||a==p||(F(a)||(a=[a]),n(a,function(a){L(a)&&(a=ha(a));c.push(wa(b)+"="+wa(a))}))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var r=c("$http"),y=[];n(g,function(a){y.unshift(E(a)?l.get(a):l.invoke(a))});n(i,function(a,b){var c=E(a)?l.get(a):l.invoke(a);y.splice(b,0,{response:function(a){return c(k.when(a))},
    +responseError:function(a){return c(k.reject(a))}})});u.pendingRequests=[];(function(a){n(arguments,function(a){u[a]=function(b,c){return u(t(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){n(arguments,function(a){u[a]=function(b,c,d){return u(t(d||{},{method:a,url:b,data:c}))}})})("post","put");u.defaults=e;return u}]}function cd(){this.$get=["$browser","$window","$document",function(b,a,c){return dd(b,ed,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}
    +function dd(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;Z?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=d;e.body.appendChild(c);return d}return function(e,h,j,m,k,l,u,o){function z(){p=-1;t&&t();v&&v.abort()}function r(a,d,e,f){var j=(h.match(jb)||["",g])[1];A&&c.cancel(A);t=v=null;d=j=="file"?e?200:404:d;a(d==1223?204:d,e,f);b.$$completeOutstandingRequest(q)}
    +var p;b.$$incOutstandingRequestCount();h=h||b.url();if(I(e)=="jsonp"){var x="_"+(d.counter++).toString(36);d[x]=function(a){d[x].data=a};var t=i(h.replace("JSON_CALLBACK","angular.callbacks."+x),function(){d[x].data?r(m,200,d[x].data):r(m,p||-2);delete d[x]})}else{var v=new a;v.open(e,h,!0);n(k,function(a,b){a&&v.setRequestHeader(b,a)});v.onreadystatechange=function(){if(v.readyState==4){var a=v.getAllResponseHeaders(),b=["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified",
    +"Pragma"];a||(a="",n(b,function(b){var c=v.getResponseHeader(b);c&&(a+=b+": "+c+"\n")}));r(m,p||v.status,v.responseType?v.response:v.responseText,a)}};if(u)v.withCredentials=!0;if(o)v.responseType=o;v.send(j||"")}if(l>0)var A=c(z,l);else l&&l.then&&l.then(z)}}function fd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",
    +posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",
    +mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function gd(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var j=c.defer(),m=j.promise,k=B(h)&&!h,f=a.defer(function(){try{j.resolve(e())}catch(a){j.reject(a),d(a)}k||b.$apply()},f),h=function(){delete g[m.$$timeoutId]};m.$$timeoutId=f;g[f]=j;m.then(h,h);return m}var g={};e.cancel=function(b){return b&&b.$$timeoutId in
    +g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):!1};return e}]}function Zb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",$b);a("date",ac);a("filter",hd);a("json",id);a("limitTo",jd);a("lowercase",kd);a("number",bc);a("orderBy",cc);a("uppercase",ld)}function hd(){return function(b,a,c){if(!F(b))return b;var d=[];d.check=function(a){for(var b=0;b<d.length;b++)if(!d[b](a))return!1;
    +return!0};switch(typeof c){case "function":break;case "boolean":if(c==!0){c=function(a,b){return Ha.equals(a,b)};break}default:c=function(a,b){b=(""+b).toLowerCase();return(""+a).toLowerCase().indexOf(b)>-1}}var e=function(a,b){if(typeof b=="string"&&b.charAt(0)==="!")return!e(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if(d.charAt(0)!=="$"&&e(a[d],b))return!0}return!1;case "array":for(d=
    +0;d<a.length;d++)if(e(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var g in a)g=="$"?function(){if(a[g]){var b=g;d.push(function(c){return e(c,a[b])})}}():function(){if(a[g]){var b=g;d.push(function(c){return e(ib(c,b),a[b])})}}();break;case "function":d.push(a);break;default:return b}for(var i=[],f=0;f<b.length;f++){var h=b[f];d.check(h)&&i.push(h)}return i}}function $b(b){var a=b.NUMBER_FORMATS;return function(b,
    +d){if(C(d))d=a.CURRENCY_SYM;return dc(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function bc(b){var a=b.NUMBER_FORMATS;return function(b,d){return dc(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function dc(b,a,c,d,e){if(isNaN(b)||!isFinite(b))return"";var g=b<0,b=Math.abs(b),i=b+"",f="",h=[],j=!1;if(i.indexOf("e")!==-1){var m=i.match(/([\d\.]+)e(-?)(\d+)/);m&&m[2]=="-"&&m[3]>e+1?i="0":(f=i,j=!0)}if(!j){i=(i.split(ec)[1]||"").length;C(e)&&(e=Math.min(Math.max(a.minFrac,i),
    +a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(ec),i=b[0],b=b[1]||"",j=0,m=a.lgSize,k=a.gSize;if(i.length>=m+k)for(var j=i.length-m,l=0;l<j;l++)(j-l)%k===0&&l!==0&&(f+=c),f+=i.charAt(l);for(l=j;l<i.length;l++)(i.length-l)%m===0&&l!==0&&(f+=c),f+=i.charAt(l);for(;b.length<e;)b+="0";e&&e!=="0"&&(f+=d+b.substr(0,e))}h.push(g?a.negPre:a.posPre);h.push(f);h.push(g?a.negSuf:a.posSuf);return h.join("")}function nb(b,a,c){var d="";b<0&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=
    +b.substr(b.length-a));return d+b}function Q(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(c>0||e>-c)e+=c;e===0&&c==-12&&(e=12);return nb(e,a,d)}}function Qa(b,a){return function(c,d){var e=c["get"+b](),g=oa(a?"SHORT"+b:b);return d[g][e]}}function ac(b){function a(a){var b;if(b=a.match(c)){var a=new Date(0),g=0,i=0,f=b[8]?a.setUTCFullYear:a.setFullYear,h=b[8]?a.setUTCHours:a.setHours;b[9]&&(g=N(b[9]+b[10]),i=N(b[9]+b[11]));f.call(a,N(b[1]),N(b[2])-1,N(b[3]));g=N(b[4]||0)-g;i=N(b[5]||0)-i;f=
    +N(b[6]||0);b=Math.round(parseFloat("0."+(b[7]||0))*1E3);h.call(a,g,i,f,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;E(c)&&(c=md.test(c)?N(c):a(c));Ya(c)&&(c=new Date(c));if(!ra(c))return c;for(;e;)(h=nd.exec(e))?(i=i.concat(ka.call(h,1)),e=i.pop()):(i.push(e),e=null);n(i,function(a){f=od[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,
    +"").replace(/''/g,"'")});return g}}function id(){return function(b){return ha(b,!0)}}function jd(){return function(b,a){if(!F(b)&&!E(b))return b;a=N(a);if(E(b))return a?a>=0?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function cc(b){return function(a,c,d){function e(a,b){return ua(b)?function(b,c){return a(c,b)}:a}if(!F(a))return a;if(!c)return a;for(var c=F(c)?c:[c],c=
    +Za(c,function(a){var c=!1,d=a||qa;if(E(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")c=a.charAt(0)=="-",a=a.substring(1);d=b(a)}return e(function(a,b){var c;c=d(a);var e=d(b),f=typeof c,g=typeof e;f==g?(f=="string"&&(c=c.toLowerCase()),f=="string"&&(e=e.toLowerCase()),c=c===e?0:c<e?-1:1):c=f<g?-1:1;return c},c)}),g=[],i=0;i<a.length;i++)g.push(a[i]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(e!==0)return e}return 0},d))}}function aa(b){H(b)&&(b={link:b});b.restrict=b.restrict||
    +"AC";return S(b)}function fc(b,a){function c(a,c){c=c?"-"+bb(c,"-"):"";b.removeClass((a?Ra:Sa)+c).addClass((a?Sa:Ra)+c)}var d=this,e=b.parent().controller("form")||Ta,g=0,i=d.$error={},f=[];d.$name=a.name;d.$dirty=!1;d.$pristine=!0;d.$valid=!0;d.$invalid=!1;e.$addControl(d);b.addClass(pa);c(!0);d.$addControl=function(a){f.push(a);a.$name&&!d.hasOwnProperty(a.$name)&&(d[a.$name]=a)};d.$removeControl=function(a){a.$name&&d[a.$name]===a&&delete d[a.$name];n(i,function(b,c){d.$setValidity(c,!0,a)});ta(f,
    +a)};d.$setValidity=function(a,b,f){var k=i[a];if(b){if(k&&(ta(k,f),!k.length)){g--;if(!g)c(b),d.$valid=!0,d.$invalid=!1;i[a]=!1;c(!0,a);e.$setValidity(a,!0,d)}}else{g||c(b);if(k){if(Ga(k,f)!=-1)return}else i[a]=k=[],g++,c(!1,a),e.$setValidity(a,!1,d);k.push(f);d.$valid=!1;d.$invalid=!0}};d.$setDirty=function(){b.removeClass(pa).addClass(Ua);d.$dirty=!0;d.$pristine=!1;e.$setDirty()};d.$setPristine=function(){b.removeClass(Ua).addClass(pa);d.$dirty=!1;d.$pristine=!0;n(f,function(a){a.$setPristine()})}}
    +function X(b){return C(b)||b===""||b===null||b!==b}function Va(b,a,c,d,e,g){var i=function(){var e=a.val();if(ua(c.ngTrim||"T"))e=U(e);d.$viewValue!==e&&b.$apply(function(){d.$setViewValue(e)})};if(e.hasEvent("input"))a.bind("input",i);else{var f,h=function(){f||(f=g.defer(function(){i();f=null}))};a.bind("keydown",function(a){a=a.keyCode;a===91||15<a&&a<19||37<=a&&a<=40||h()});a.bind("change",i);e.hasEvent("paste")&&a.bind("paste cut",h)}d.$render=function(){a.val(X(d.$viewValue)?"":d.$viewValue)};
    +var j=c.ngPattern,m=function(a,b){return X(b)||a.test(b)?(d.$setValidity("pattern",!0),b):(d.$setValidity("pattern",!1),p)};j&&((e=j.match(/^\/(.*)\/([gim]*)$/))?(j=RegExp(e[1],e[2]),e=function(a){return m(j,a)}):e=function(a){var c=b.$eval(j);if(!c||!c.test)throw Error("Expected "+j+" to be a RegExp but was "+c);return m(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var k=N(c.ngMinlength),e=function(a){return!X(a)&&a.length<k?(d.$setValidity("minlength",!1),p):(d.$setValidity("minlength",
    +!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var l=N(c.ngMaxlength),e=function(a){return!X(a)&&a.length>l?(d.$setValidity("maxlength",!1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}}function ob(b,a){b="ngClass"+b;return aa(function(c,d,e){function g(b){if(a===!0||c.$index%2===a)h&&!ia(b,h)&&i(h),f(b);h=V(b)}function i(a){L(a)&&!F(a)&&(a=Za(a,function(a,b){if(a)return b}));d.removeClass(F(a)?a.join(" "):a)}function f(a){L(a)&&!F(a)&&(a=Za(a,
    +function(a,b){if(a)return b}));a&&d.addClass(F(a)?a.join(" "):a)}var h=p;c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",function(d,g){var h=d&1;h!==g&1&&(h===a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var I=function(b){return E(b)?b.toLowerCase():b},oa=function(b){return E(b)?b.toUpperCase():b},Z=N((/msie (\d+)/.exec(I(navigator.userAgent))||[])[1]),w,ga,ka=[].slice,Wa=[].push,Ea=Object.prototype.toString,mc=M.angular,Ha=M.angular||(M.angular=
    +{}),Aa,hb,ba=["0","0","0"];q.$inject=[];qa.$inject=[];hb=Z<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?oa(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var sc=/[A-Z]/g,pd={full:"1.1.5",major:1,minor:1,dot:5,codeName:"triangle-squarification"},Ka=R.cache={},Ja=R.expando="ng-"+(new Date).getTime(),wc=1,gc=M.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},gb=
    +M.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},uc=/([\:\-\_]+(.))/g,vc=/^moz([A-Z])/,Ba=R.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;T.readyState==="complete"?setTimeout(a):(this.bind("DOMContentLoaded",a),R(M).bind("load",a))},toString:function(){var b=[];n(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?w(this[b]):w(this[this.length+b])},length:0,push:Wa,sort:[].sort,
    +splice:[].splice},Na={};n("multiple,selected,checked,disabled,readOnly,required,open".split(","),function(b){Na[I(b)]=b});var Gb={};n("input,select,option,textarea,button,form,details".split(","),function(b){Gb[oa(b)]=!0});n({data:Bb,inheritedData:Ma,scope:function(b){return Ma(b,"$scope")},controller:Eb,injector:function(b){return Ma(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:La,css:function(b,a,c){a=Ia(a);if(B(c))b.style[a]=c;else{var d;Z<=8&&(d=b.currentStyle&&b.currentStyle[a],
    +d===""&&(d="auto"));d=d||b.style[a];Z<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=I(a);if(Na[d])if(B(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||q).specified?d:p;else if(B(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(B(c))b[a]=c;else return b[a]},text:t(Z<9?function(b,a){if(b.nodeType==1){if(C(a))return b.innerText;b.innerText=a}else{if(C(a))return b.nodeValue;
    +b.nodeValue=a}}:function(b,a){if(C(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(C(a))return b.value;b.value=a},html:function(b,a){if(C(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)ya(d[c]);b.innerHTML=a}},function(b,a){R.prototype[a]=function(a,d){var e,g;if((b.length==2&&b!==La&&b!==Eb?a:d)===p)if(L(a)){for(e=0;e<this.length;e++)if(b===Bb)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}else{if(this.length)return b(this[0],a,d)}else{for(e=0;e<
    +this.length;e++)b(this[e],a,d);return this}return b.$dv}});n({removeData:zb,dealoc:ya,bind:function a(c,d,e){var g=ca(c,"events"),i=ca(c,"handle");g||ca(c,"events",g={});i||ca(c,"handle",i=xc(c,g));n(d.split(" "),function(d){var h=g[d];if(!h){if(d=="mouseenter"||d=="mouseleave"){var j=T.body.contains||T.body.compareDocumentPosition?function(a,c){var d=a.nodeType===9?a.documentElement:a,e=c&&c.parentNode;return a===e||!(!e||!(e.nodeType===1&&(d.contains?d.contains(e):a.compareDocumentPosition&&a.compareDocumentPosition(e)&
    +16)))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};g[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;(!c||c!==this&&!j(this,c))&&i(a,d)})}else gc(c,d,i),g[d]=[];h=g[d]}h.push(e)})},unbind:Ab,replaceWith:function(a,c){var d,e=a.parentNode;ya(a);n(new R(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];n(a.childNodes,function(a){a.nodeType===1&&c.push(a)});return c},contents:function(a){return a.childNodes||
    +[]},append:function(a,c){n(new R(c),function(c){(a.nodeType===1||a.nodeType===11)&&a.appendChild(c)})},prepend:function(a,c){if(a.nodeType===1){var d=a.firstChild;n(new R(c),function(c){d?a.insertBefore(c,d):(a.appendChild(c),d=c)})}},wrap:function(a,c){var c=w(c)[0],d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){ya(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;n(new R(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:Db,
    +removeClass:Cb,toggleClass:function(a,c,d){C(d)&&(d=!La(a,c));(d?Db:Cb)(a,c)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;for(a=a.nextSibling;a!=null&&a.nodeType!==1;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName(c)},clone:fb,triggerHandler:function(a,c){var d=(ca(a,"events")||{})[c];n(d,function(c){c.call(a,{preventDefault:q})})}},function(a,c){R.prototype[c]=function(c,e){for(var g,
    +i=0;i<this.length;i++)g==p?(g=a(this[i],c,e),g!==p&&(g=w(g))):eb(g,a(this[i],c,e));return g==p?this:g}});za.prototype={put:function(a,c){this[la(a)]=c},get:function(a){return this[la(a)]},remove:function(a){var c=this[a=la(a)];delete this[a];return c}};var zc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,Ac=/,/,Bc=/^\s*(_?)(\S+?)\1\s*$/,yc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;Ib.$inject=["$provide"];var qd=function(){var a="$ngAnimateController",c={running:!0};this.$get=["$animation","$window","$sniffer","$rootElement",
    +"$rootScope",function(d,e,g,i){i.data(a,c);i=function(c,i){function j(j,k,o){return function(m,r,p){function x(a){var c=0,a=E(a)?a.split(/\s*,\s*/):[];n(a,function(a){c=Math.max(parseFloat(a)||0,c)});return c}function t(){m.addClass(K);if($)$(m,v,P);else if(H(e.getComputedStyle)){var a=g.vendorPrefix+"Animation",c=g.vendorPrefix+"Transition",d=0;n(m,function(f){if(f.nodeType==1){var g="transition",i=c,j=1,h=e.getComputedStyle(f)||{};if(parseFloat(h.animationDuration)>0||parseFloat(h[a+"Duration"])>
    +0)g="animation",i=a,j=Math.max(parseInt(h[g+"IterationCount"])||0,parseInt(h[i+"IterationCount"])||0,j);f=Math.max(x(h[g+"Delay"]),x(h[i+"Delay"]));g=Math.max(x(h[g+"Duration"]),x(h[i+"Duration"]));d=Math.max(f+j*g,d)}});e.setTimeout(v,d*1E3)}else v()}function v(){if(!v.run)v.run=!0,o(m,r,p),m.removeClass(w),m.removeClass(K),m.removeData(a)}var A=c.$eval(i.ngAnimate),w=A?L(A)?A[j]:A+"-"+j:"",D=d(w),A=D&&D.setup,$=D&&D.start,D=D&&D.cancel;if(w){var K=w+"-active";r||(r=p?p.parent():m.parent());if(!g.transitions&&
    +!A&&!$||(r.inheritedData(a)||q).running)k(m,r,p),o(m,r,p);else{var O=m.data(a)||{};O.running&&((D||q)(m),O.done());m.data(a,{running:!0,done:v});m.addClass(w);k(m,r,p);if(m.length==0)return v();var P=(A||q)(m);e.setTimeout(t,1)}}else k(m,r,p),o(m,r,p)}}function m(a,c,d){d?d.after(a):c.append(a)}var k={};k.enter=j("enter",m,q);k.leave=j("leave",q,function(a){a.remove()});k.move=j("move",function(a,c,d){m(a,c,d)},q);k.show=j("show",function(a){a.css("display","")},q);k.hide=j("hide",q,function(a){a.css("display",
    +"none")});k.animate=function(a,c){j(a,q,q)(c)};return k};i.enabled=function(a){if(arguments.length)c.running=!a;return!c.running};return i}]},Kb="Non-assignable model expression: ";Jb.$inject=["$provide"];var Ic=/^(x[\:\-_]|data[\:\-_])/i,jb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,Pb=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Oa={http:80,https:443,ftp:21};Rb.prototype=lb.prototype=Qb.prototype={$$replace:!1,absUrl:Pa("$$absUrl"),url:function(a,c){if(C(a))return this.$$url;
    +var d=Pb.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Pa("$$protocol"),host:Pa("$$host"),port:Pa("$$port"),path:Sb("$$path",function(a){return a.charAt(0)=="/"?a:"/"+a}),search:function(a,c){if(C(a))return this.$$search;B(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=E(a)?vb(a):a;this.$$compose();return this},hash:Sb("$$hash",qa),replace:function(){this.$$replace=!0;return this}};var Da={"null":function(){return null},
    +"true":function(){return!0},"false":function(){return!1},undefined:q,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return B(d)?B(e)?d+e:d:B(e)?e:p},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(B(d)?d:0)-(B(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":q,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,
    +c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Qc={n:"\n",f:"\u000c",r:"\r",
    +t:"\t",v:"\u000b","'":"'",'"':'"'},mb={},ad=/^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/,ed=M.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw Error("This browser does not support XMLHttpRequest.");};Zb.$inject=["$provide"];$b.$inject=["$locale"];bc.$inject=["$locale"];var ec=".",od={yyyy:Q("FullYear",4),yy:Q("FullYear",
    +2,0,!0),y:Q("FullYear",1),MMMM:Qa("Month"),MMM:Qa("Month",!0),MM:Q("Month",2,1),M:Q("Month",1,1),dd:Q("Date",2),d:Q("Date",1),HH:Q("Hours",2),H:Q("Hours",1),hh:Q("Hours",2,-12),h:Q("Hours",1,-12),mm:Q("Minutes",2),m:Q("Minutes",1),ss:Q("Seconds",2),s:Q("Seconds",1),sss:Q("Milliseconds",3),EEEE:Qa("Day"),EEE:Qa("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){var a=-1*a.getTimezoneOffset(),c=a>=0?"+":"";c+=nb(Math[a>0?"floor":"ceil"](a/60),2)+nb(Math.abs(a%60),
    +2);return c}},nd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,md=/^\d+$/;ac.$inject=["$locale"];var kd=S(I),ld=S(oa);cc.$inject=["$parse"];var rd=S({restrict:"E",compile:function(a,c){Z<=8&&(!c.href&&!c.name&&c.$set("href",""),a.append(T.createComment("IE fix")));return function(a,c){c.bind("click",function(a){c.attr("href")||a.preventDefault()})}}}),pb={};n(Na,function(a,c){var d=da("ng-"+c);pb[d]=function(){return{priority:100,compile:function(){return function(a,
    +g,i){a.$watch(i[d],function(a){i.$set(c,!!a)})}}}}});n(["src","srcset","href"],function(a){var c=da("ng-"+a);pb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),Z&&e.prop(a,g[a]))})}}}});var Ta={$addControl:q,$removeControl:q,$setValidity:q,$setDirty:q,$setPristine:q};fc.$inject=["$element","$attrs","$scope"];var Wa=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:fc,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h=
    +function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};gc(d[0],"submit",h);d.bind("$destroy",function(){c(function(){gb(d[0],"submit",h)},0,!1)})}var j=d.parent().controller("form"),m=i.name||i.ngForm;m&&(a[m]=f);j&&d.bind("$destroy",function(){j.$removeControl(f);m&&(a[m]=p);t(f,Ta)})}}}};return a?t(V(d),{restrict:"EAC"}):d}]},sd=Wa(),td=Wa(!0),ud=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,vd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,
    +wd=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,hc={text:Va,number:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);e.$parsers.push(function(a){var c=X(a);return c||wd.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return X(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!X(a)&&a<f?(e.$setValidity("min",!1),p):(e.$setValidity("min",!0),a)};e.$parsers.push(a);e.$formatters.push(a)}if(d.max){var h=parseFloat(d.max),
    +d=function(a){return!X(a)&&a>h?(e.$setValidity("max",!1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return X(a)||Ya(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);a=function(a){return X(a)||ud.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);a=function(a){return X(a)||vd.test(a)?
    +(e.$setValidity("email",!0),a):(e.$setValidity("email",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){C(d.name)&&c.attr("name",Fa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;E(g)||(g=!0);E(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});
    +e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:i})},hidden:q,button:q,submit:q,reset:q},ic=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(hc[I(g.type)]||hc.text)(d,e,g,i,c,a)}}}],Sa="ng-valid",Ra="ng-invalid",pa="ng-pristine",Ua="ng-dirty",xd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+bb(c,"-"):"";
    +e.removeClass((a?Ra:Sa)+c).addClass((a?Sa:Ra)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw Error(Kb+d.ngModel+" ("+va(e)+")");this.$render=q;var j=e.inheritedData("$formController")||Ta,m=0,k=this.$error={};e.addClass(pa);i(!0);this.$setValidity=function(a,c){if(k[a]!==!c){if(c){if(k[a]&&m--,!m)i(!0),this.$valid=
    +!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,m++;k[a]=!c;i(c,a);j.$setValidity(a,c,this)}};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;e.removeClass(Ua).addClass(pa)};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(pa).addClass(Ua),j.$setDirty();n(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),n(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};
    +var l=this;a.$watch(function(){var c=f(a);if(l.$modelValue!==c){var d=l.$formatters,e=d.length;for(l.$modelValue=c;e--;)c=d[e](c);if(l.$viewValue!==c)l.$viewValue=c,l.$render()}})}],yd=function(){return{require:["ngModel","^?form"],controller:xd,link:function(a,c,d,e){var g=e[0],i=e[1]||Ta;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},zd=S({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),jc=function(){return{require:"?ngModel",
    +link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(X(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}},Ad=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&n(a.split(g),function(a){a&&c.push(U(a))});return c});e.$formatters.push(function(a){return F(a)?
    +a.join(", "):p})}}},Bd=/^(true|false|\d+)$/,Cd=function(){return{priority:100,compile:function(a,c){return Bd.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},Dd=aa(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),Ed=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",
    +c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],Fd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,function(a){c.html(a||"")})}}],Gd=ob("",!0),Hd=ob("Odd",0),Id=ob("Even",1),Jd=aa({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Kd=[function(){return{scope:!0,controller:"@"}}],Ld=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],kc={};n("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress".split(" "),
    +function(a){var c=da("ng-"+a);kc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(I(a),function(a){e.$apply(function(){f(e,{$event:a})})})}}]});var Md=aa(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Nd=["$animator",function(a){return{transclude:"element",priority:1E3,terminal:!0,restrict:"A",compile:function(c,d,e){return function(c,d,f){var h=a(c,f),j,m;c.$watch(f.ngIf,function(a){j&&(h.leave(j),j=p);m&&(m.$destroy(),m=p);ua(a)&&(m=c.$new(),e(m,function(a){j=
    +a;h.enter(a,d.parent(),d)}))})}}}}],Od=["$http","$templateCache","$anchorScroll","$compile","$animator",function(a,c,d,e,g){return{restrict:"ECA",terminal:!0,compile:function(i,f){var h=f.ngInclude||f.src,j=f.onload||"",m=f.autoscroll;return function(f,i,n){var o=g(f,n),p=0,r,t=function(){r&&(r.$destroy(),r=null);o.leave(i.contents(),i)};f.$watch(h,function(g){var h=++p;g?(a.get(g,{cache:c}).success(function(a){h===p&&(r&&r.$destroy(),r=f.$new(),o.leave(i.contents(),i),a=w("<div/>").html(a).contents(),
    +o.enter(a,i),e(a)(r),B(m)&&(!m||f.$eval(m))&&d(),r.$emit("$includeContentLoaded"),f.$eval(j))}).error(function(){h===p&&t()}),f.$emit("$includeContentRequested")):t()})}}}}],Pd=aa({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Qd=aa({terminal:!0,priority:1E3}),Rd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),j=i.offset||0,m=e.$eval(h),k={},l=c.startSymbol(),p=c.endSymbol();n(m,function(a,e){k[e]=
    +c(a.replace(d,l+f+"-"+j+p))});e.$watch(function(){var c=parseFloat(e.$eval(f));return isNaN(c)?"":(c in m||(c=a.pluralCat(c-j)),k[c](e,g,!0))},function(a){g.text(a)})}}}],Sd=["$parse","$animator",function(a,c){return{transclude:"element",priority:1E3,terminal:!0,compile:function(d,e,g){return function(d,e,h){var j=c(d,h),m=h.ngRepeat,k=m.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),l,p,o,z,r,t={$id:la};if(!k)throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '"+
    +m+"'.");h=k[1];o=k[2];(k=k[4])?(l=a(k),p=function(a,c,e){r&&(t[r]=a);t[z]=c;t.$index=e;return l(d,t)}):p=function(a,c){return la(c)};k=h.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!k)throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '"+h+"'.");z=k[3]||k[1];r=k[2];var x={};d.$watchCollection(o,function(a){var c,h,k=e,l,o={},t,q,w,s,B,y,C=[];if(Xa(a))B=a;else{B=[];for(w in a)a.hasOwnProperty(w)&&w.charAt(0)!="$"&&B.push(w);B.sort()}t=B.length;h=
    +C.length=B.length;for(c=0;c<h;c++)if(w=a===B?c:B[c],s=a[w],l=p(w,s,c),x.hasOwnProperty(l))y=x[l],delete x[l],o[l]=y,C[c]=y;else if(o.hasOwnProperty(l))throw n(C,function(a){a&&a.element&&(x[a.id]=a)}),Error("Duplicates in a repeater are not allowed. Repeater: "+m+" key: "+l);else C[c]={id:l},o[l]=!1;for(w in x)if(x.hasOwnProperty(w))y=x[w],j.leave(y.element),y.element[0].$$NG_REMOVED=!0,y.scope.$destroy();c=0;for(h=B.length;c<h;c++){w=a===B?c:B[c];s=a[w];y=C[c];if(y.element){q=y.scope;l=k[0];do l=
    +l.nextSibling;while(l&&l.$$NG_REMOVED);y.element[0]!=l&&j.move(y.element,null,k);k=y.element}else q=d.$new();q[z]=s;r&&(q[r]=w);q.$index=c;q.$first=c===0;q.$last=c===t-1;q.$middle=!(q.$first||q.$last);y.element||g(q,function(a){j.enter(a,null,k);k=a;y.scope=q;y.element=a;o[y.id]=y})}x=o})}}}}],Td=["$animator",function(a){return function(c,d,e){var g=a(c,e);c.$watch(e.ngShow,function(a){g[ua(a)?"show":"hide"](d)})}}],Ud=["$animator",function(a){return function(c,d,e){var g=a(c,e);c.$watch(e.ngHide,
    +function(a){g[ua(a)?"hide":"show"](d)})}}],Vd=aa(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&n(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Wd=["$animator",function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,g){var i=a(c,e),f,h,j=[];c.$watch(e.ngSwitch||e.on,function(a){for(var d=0,l=j.length;d<l;d++)j[d].$destroy(),i.leave(h[d]);h=[];j=[];if(f=g.cases["!"+a]||g.cases["?"])c.$eval(e.change),n(f,function(a){var d=
    +c.$new();j.push(d);a.transclude(d,function(c){var d=a.element;h.push(c);i.enter(c,d.parent(),d)})})})}}}],Xd=aa({transclude:"element",priority:500,require:"^ngSwitch",compile:function(a,c,d){return function(a,g,i,f){f.cases["!"+c.ngSwitchWhen]=f.cases["!"+c.ngSwitchWhen]||[];f.cases["!"+c.ngSwitchWhen].push({transclude:d,element:g})}}}),Yd=aa({transclude:"element",priority:500,require:"^ngSwitch",compile:function(a,c,d){return function(a,c,i,f){f.cases["?"]=f.cases["?"]||[];f.cases["?"].push({transclude:d,
    +element:c})}}}),Zd=aa({controller:["$transclude","$element",function(a,c){a(function(a){c.append(a)})}]}),$d=["$http","$templateCache","$route","$anchorScroll","$compile","$controller","$animator",function(a,c,d,e,g,i,f){return{restrict:"ECA",terminal:!0,link:function(a,c,m){function k(){var f=d.current&&d.current.locals,k=f&&f.$template;if(k){o.leave(c.contents(),c);l&&(l.$destroy(),l=null);k=w("<div></div>").html(k).contents();o.enter(k,c);var k=g(k),m=d.current;l=m.scope=a.$new();if(m.controller)f.$scope=
    +l,f=i(m.controller,f),m.controllerAs&&(l[m.controllerAs]=f),c.children().data("$ngControllerController",f);k(l);l.$emit("$viewContentLoaded");l.$eval(n);e()}else o.leave(c.contents(),c),l&&(l.$destroy(),l=null)}var l,n=m.onload||"",o=f(a,m);a.$on("$routeChangeSuccess",k);k()}}}],ae=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],be=S({terminal:!0}),ce=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
    +e={$setViewValue:q};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var h=this,j={},m=e,k;h.databound=d.ngModel;h.init=function(a,c,d){m=a;k=d};h.addOption=function(c){j[c]=!0;m.$viewValue==c&&(a.val(c),k.parent()&&k.remove())};h.removeOption=function(a){this.hasOption(a)&&(delete j[a],m.$viewValue==a&&this.renderUnknownOption(a))};h.renderUnknownOption=function(c){c="? "+la(c)+" ?";k.val(c);a.prepend(k);a.val(c);k.prop("selected",!0)};h.hasOption=
    +function(a){return j.hasOwnProperty(a)};c.$on("$destroy",function(){h.renderUnknownOption=q})}],link:function(e,i,f,h){function j(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(v.parent()&&v.remove(),c.val(a),a===""&&t.prop("selected",!0)):C(a)&&t?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){v.parent()&&v.remove();d.$setViewValue(c.val())})})}function m(a,c,d){var e;d.$render=function(){var a=new za(d.$viewValue);n(c.find("option"),function(c){c.selected=
    +B(a.get(c.value))})};a.$watch(function(){ia(e,d.$viewValue)||(e=V(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];n(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function k(e,f,g){function i(){var a={"":[]},c=[""],d,h,q,v,s;q=g.$modelValue;v=u(e)||[];var z=l?qb(v):v,B,y,A;y={};s=!1;var C,D;if(o)if(t&&F(q)){s=new za([]);for(h=0;h<q.length;h++)y[k]=q[h],s.put(t(e,y),q[h])}else s=new za(q);for(A=0;B=z.length,A<B;A++){y[k]=v[l?y[l]=
    +z[A]:A];d=m(e,y)||"";if(!(h=a[d]))h=a[d]=[],c.push(d);o?d=s.remove(t?t(e,y):n(e,y))!=p:(t?(d={},d[k]=q,d=t(e,d)===t(e,y)):d=q===n(e,y),s=s||d);C=j(e,y);C=C===p?"":C;h.push({id:t?t(e,y):l?z[A]:A,label:C,selected:d})}o||(r||q===null?a[""].unshift({id:"",label:"",selected:!s}):s||a[""].unshift({id:"?",label:"",selected:!0}));y=0;for(z=c.length;y<z;y++){d=c[y];h=a[d];if(w.length<=y)q={element:E.clone().attr("label",d),label:h.label},v=[q],w.push(v),f.append(q.element);else if(v=w[y],q=v[0],q.label!=d)q.element.attr("label",
    +q.label=d);C=null;A=0;for(B=h.length;A<B;A++)if(d=h[A],s=v[A+1]){C=s.element;if(s.label!==d.label)C.text(s.label=d.label);if(s.id!==d.id)C.val(s.id=d.id);if(C[0].selected!==d.selected)C.prop("selected",s.selected=d.selected)}else d.id===""&&r?D=r:(D=x.clone()).val(d.id).attr("selected",d.selected).text(d.label),v.push({element:D,label:d.label,id:d.id,selected:d.selected}),C?C.after(D):q.element.append(D),C=D;for(A++;v.length>A;)v.pop().element.remove()}for(;w.length>y;)w.pop()[0].element.remove()}
    +var h;if(!(h=q.match(d)))throw Error("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?' but got '"+q+"'.");var j=c(h[2]||h[1]),k=h[4]||h[6],l=h[5],m=c(h[3]||""),n=c(h[2]?h[1]:k),u=c(h[7]),t=h[8]?c(h[8]):null,w=[[{element:f,label:""}]];r&&(a(r)(e),r.removeClass("ng-scope"),r.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=u(e)||[],d={},h,i,j,m,q,r;if(o){i=[];m=0;for(r=w.length;m<r;m++){a=w[m];j=1;for(q=a.length;j<
    +q;j++)if((h=a[j].element)[0].selected){h=h.val();l&&(d[l]=h);if(t)for(var s=0;s<c.length;s++){if(d[k]=c[s],t(e,d)==h)break}else d[k]=c[h];i.push(n(e,d))}}}else if(h=f.val(),h=="?")i=p;else if(h=="")i=null;else if(t)for(s=0;s<c.length;s++){if(d[k]=c[s],t(e,d)==h){i=n(e,d);break}}else d[k]=c[h],l&&(d[l]=h),i=n(e,d);g.$setViewValue(i)})});g.$render=i;e.$watch(i)}if(h[1]){for(var l=h[0],u=h[1],o=f.multiple,q=f.ngOptions,r=!1,t,x=w(T.createElement("option")),E=w(T.createElement("optgroup")),v=x.clone(),
    +h=0,A=i.children(),G=A.length;h<G;h++)if(A[h].value==""){t=r=A.eq(h);break}l.init(u,r,v);if(o&&(f.required||f.ngRequired)){var D=function(a){u.$setValidity("required",!f.required||a&&a.length);return a};u.$parsers.push(D);u.$formatters.unshift(D);f.$observe("required",function(){D(u.$viewValue)})}q?k(e,i,u):o?m(e,i,u):j(e,i,u,l)}}}}],de=["$interpolate",function(a){var c={addOption:q,removeOption:q};return{restrict:"E",priority:100,compile:function(d,e){if(C(e.value)){var g=a(d.text(),!0);g||e.$set("value",
    +d.text())}return function(a,d,e){var j=d.parent(),m=j.data("$selectController")||j.parent().data("$selectController");m&&m.databound?d.prop("selected",!1):m=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&m.removeOption(c);m.addOption(a)}):m.addOption(e.value);d.bind("$destroy",function(){m.removeOption(e.value)})}}}}],ee=S({restrict:"E",terminal:!0});(ga=M.jQuery)?(w=ga,t(ga.fn,{scope:Ba.scope,controller:Ba.controller,injector:Ba.injector,inheritedData:Ba.inheritedData}),db("remove",!0),db("empty"),
    +db("html")):w=R;Ha.element=w;(function(a){t(a,{bootstrap:xb,copy:V,extend:t,equals:ia,element:w,forEach:n,injector:yb,noop:q,bind:$a,toJson:ha,fromJson:ub,identity:qa,isUndefined:C,isDefined:B,isString:E,isFunction:H,isObject:L,isNumber:Ya,isElement:oc,isArray:F,version:pd,isDate:ra,lowercase:I,uppercase:oa,callbacks:{counter:0},noConflict:lc});Aa=tc(M);try{Aa("ngLocale")}catch(c){Aa("ngLocale",[]).provider("$locale",fd)}Aa("ng",["ngLocale"],["$provide",function(a){a.provider("$compile",Jb).directive({a:rd,
    +input:ic,textarea:ic,form:sd,script:ae,select:ce,style:ee,option:de,ngBind:Dd,ngBindHtmlUnsafe:Fd,ngBindTemplate:Ed,ngClass:Gd,ngClassEven:Id,ngClassOdd:Hd,ngCsp:Ld,ngCloak:Jd,ngController:Kd,ngForm:td,ngHide:Ud,ngIf:Nd,ngInclude:Od,ngInit:Pd,ngNonBindable:Qd,ngPluralize:Rd,ngRepeat:Sd,ngShow:Td,ngSubmit:Md,ngStyle:Vd,ngSwitch:Wd,ngSwitchWhen:Xd,ngSwitchDefault:Yd,ngOptions:be,ngView:$d,ngTransclude:Zd,ngModel:yd,ngList:Ad,ngChange:zd,required:jc,ngRequired:jc,ngValue:Cd}).directive(pb).directive(kc);
    +a.provider({$anchorScroll:Cc,$animation:Ib,$animator:qd,$browser:Ec,$cacheFactory:Fc,$controller:Jc,$document:Kc,$exceptionHandler:Lc,$filter:Zb,$interpolate:Mc,$http:bd,$httpBackend:cd,$location:Nc,$log:Oc,$parse:Sc,$route:Vc,$routeParams:Wc,$rootScope:Xc,$q:Tc,$sniffer:Yc,$templateCache:Gc,$timeout:gd,$window:Zc})}])})(Ha);w(T).ready(function(){rc(T,xb)})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
    diff --git a/docs/js/docs-setup.js b/docs/js/docs-setup.js
    new file mode 100644
    index 000000000..345f093ae
    --- /dev/null
    +++ b/docs/js/docs-setup.js
    @@ -0,0 +1,1279 @@
    +NG_DOCS={
    +  "sections": {
    +    "api": "API",
    +    "tutorial": "Tutorial"
    +  },
    +  "pages": [
    +    {
    +      "section": "api",
    +      "id": "index",
    +      "shortName": "Index",
    +      "type": "overview",
    +      "keywords": "$scope add additional and any api at but can choose class columndef columndefs columns configuration configure consists core documentation each edit enablecelledit enablecelleditonfocus enabled enablesorting example extend false feature features field1 field2 field3 for found general grid gridoptions had have if in index is ll mechanism might module name of on options overview plus same set settings so some still that the then therefore these through to true ui ui-grid use visible wanted will would you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.autoResize",
    +      "shortName": "autoResize",
    +      "type": "overview",
    +      "keywords": "api auto-resizing autoresize functionality grid module overview provides this to ui ui-grid"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "allowcellfocus api are available be cell cellnav class column columndef columndefs definitions enable feature focus for grid gridoptions object on set the these this to true ui ui-grid using within"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "api are available be cell cellnav class ctrlkey enable false feature for grid gridoptions modifierkeystomultiselectcells multiple object only or selection set shiftkey the these to ui ui-grid using when"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.api:GridRow",
    +      "shortName": "GridRow",
    +      "type": "object",
    +      "keywords": "allowcellfocus an api are as available be by can cell cellnav cells enable example false feature features focus focused for grid gridrow group header if in internally no object on only other row rows set settings then these this to true ui within would"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "already an and api array brings cell cellnav col coldef column containing current data does empty evaluate feature focus focused for fully function getcurrentselection getfocusedcell grid gridoptions has have if in index instance into is isn it last make no not null object occurred order public returns row rowcol rowcolselectindex rowentity scrollto scrolltofocus selected selection set sets should specified that the to ui value view visible was we which"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.constant:uiGridCellNavConstants",
    +      "shortName": "uiGridCellNavConstants",
    +      "type": "object",
    +      "keywords": "api available cellnav constant constants grid in object ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.directive:uiCellNav",
    +      "shortName": "uiCellNav",
    +      "type": "directive",
    +      "keywords": "$scope adds angular api app bob cell cellnav ceo columndefs columns controller data developer directive div ea features frank function grid html index js lowly mainctrl module name navigation ng-controller the title to ui ui-grid ui-grid-cellnav var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.directive:uiGridCell",
    +      "shortName": "uiGridCell",
    +      "type": "directive",
    +      "keywords": "api cell cellnav directive div grid navigation of on provide stacks to top ui uigridcell"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.object:CellNav",
    +      "shortName": "CellNav",
    +      "type": "object",
    +      "keywords": "api cellnav colcontainer column container for function grid left leftcolcontainer object of parent prototype returns right rightcolcontainer rowcontainer rows the to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.cellNav.service:uiGridCellNavService",
    +      "shortName": "uiGridCellNavService",
    +      "type": "service",
    +      "keywords": "act add adds already an and angular any api apportion apportionment are array available based but calc calculating case cell cellnav cellnavcolumnbuilder cells certain coldef column columnbuilder columns combo completely current data deal decoraterendercontainers decorates decorator determines direction docs don drawn event exclude extra features first focus for formula from function functions get getdirection getleftwidth given go grid gridapi gridcol gridoptions gridrow have height if in include including index instance is it key keydown last like list load make maps maths method navigation need needed normal not numbered numbers of on one or our overall override promise properties re rendercontainers resolved return row rowentity rows same screen scroll scrolls scrollto scrolltofocus scrolltoifnecessary scrolltointernal service services set so somewhere specified such takes templates that the this to total totalnumbercols trying tweak ui up upon uptocol use usually view visible want wanting we when which whole width will with within would you zero"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:Grid",
    +      "shortName": "Grid",
    +      "type": "function",
    +      "keywords": "$parent $parse-able $scope access accessor according add added additional addrowheadercolumn adds all already alter always an and any api appended application appscope appscopeprovider are array as asc ascending assign assigned assignment assigntypes at automatically based be been behavior being block boolean browser build buildcolumndefsfromdata buildcolumns building buildstyles by callback callbacks calldatachangecallbacks called calls can cannot canvas cell chance change changed class col coldef column columnbuilder columnbuilders columndef columndefinition columndefs columnrefreshcallback columns columnsprocessor completes considered container containers contains controller count created createleftcontainer createrightcontainer creates criteria current currently data datachange datachangecallback debounced declared def default defaults defined definitions deregister desc descending direction directions directive document doesn down each edit either element emits etc event exclude exist existing exists expected false field fires first flag flags flagscrollinghorizontally flagscrollingvertically for from function functional further getcellvalue getcoldef getcolumn getcolumnsorting getgridqualifiedcolfield getrow gets given grid gridcolumn gridoptions gridrow handlewindowresize handling has hasleftcontainer hasleftcontainercolumns hasrightcontainercolumns having header height horizontally id identified if in indicate inform informed instance intended into is isrtl isscrollinghorizontally isscrollingvertically it iterate its js left leftcontainer load long main maintain map matching method methods modified modifyrows must name needed newrawdata none not note notices notified notifies notifydatachange number object objects occurred occurs of on one only optional optionally options or order other our override parameter parent particular pass per percentage pick populates position precompilecelltemplates precompiles present process processes processor processors processrowbuilders processrowscallback promise properties property prototype provided public queuerefresh recalculated redraw redrawcanvas reference refresh refreshed refreshes refreshing refreshrows register registercolumnbuilder registercolumnsprocessor registerdatachangecallback registered registerrowbuilder registerrowsprocessor registerstylecomputation remove removed removerowsprocessor removes render renderable rendered reorder reset resetcolumnsorting resetting resizes resolved resources return returns right rightcontainer righttoleft row rowbuilder rowbuilders rowentity rowequality rows rules scope screen scroll scrolldirection scrolling set sets some sort sortchanged sortcolumn sorted sorting specifically specified state stylecomputation supplies tbd tell tells templates that the their they this through to todo triggered triggers true type types ui ui-grid uigridconstants unsorted up update updatecanvasheight updated us use used users uses using value values ve vertically via viewmodel visible want watch watches we when whenever which will window with within you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridApi",
    +      "shortName": "GridApi",
    +      "type": "function",
    +      "keywords": "$log $on $scope _this ability acol add again all allow allowed and api arguments array as be binds call callback callbackfn cellnav class components context defaults dereg deregister destroy destroyed disables disabling enables event eventname eventnameone eventnametwo eventobjectmap events execute executes feature featurename features for format from function functions funtion get given grid gridapi gridoptions if in inside is it listen listener listenerfunc listenerfuncs listenerfunctions listeners log map method methodname methodnameone methodnametwo methods must name names navigate navigation necessary new no not objectmap of oldrowcol omitted on onregisterapi optional or other our owns prepended provides public raise raises reference register registerevent registereventsfromobject registermethod registermethodsfromobject registers remove removed returns same scope scopes scrollto simple something specified still suppress suppressevents takes that the then these this to ui use used var variable via were when while will you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridColumn",
    +      "shortName": "GridColumn",
    +      "type": "function",
    +      "keywords": "address against aggregation aggregationhidelabel aggregationlabel algorithm allocate allocated although an and angular any api appropriate are aren array as associate backward based baz be being belongs bind binding body bound by can cannot casesensitive city class classname coldef column columndef columns compatibility complex condition container copied create created current data deciding def default defaultvalue defined definition display displayname docs doesn down each element elements ends ends_with evaluates existing expression expressions false field filter filters flags foo for found from function generated getaggregationtext getaggregationvalue getcolclass getcolclassdefinition getfulladdress getrendercontainer gets grid gridcolumn have header hidecolumn hides i18n if immutable in includes including index initializes input instead is isnew items label like look lookup makes method methods moves must name needed newly ngmodel normal not object of omitted on one onto options or parameters passed placeholder position prefixdot present properties property propname prototype provide provided re reference render represents return returns see set setpropertyordefault sets setting settings should shouldn showcolumn shown some sort sorting sortingalgorithm source specifically specified starts starts_with state such takes term text th that the then they this to true type ui uid uigridconstants unique updatecolumndef updating use using value viewmodel visible we whether will wish with you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "function",
    +      "keywords": "$delegate $provide $resource $scope $translate acting action active add added adding adds addtogridmenu adjusted advantage again aggregates all allow allowing allows also altering alternative always am an and angular angular-translate angularjs any api app application appscope appscopeprovider aquamarine are array as assign assigned at attribute attributes auto-generating automatically available background-color backwards be becomes been behaviour being better binding boolean boxes but by callback called can case cases center changes class col colcontainer coldef column columndef columndefs columnfooterheight columns columnvirtualizationthreshold common compare compared compatibility complex conditions config configure contain content context controller controls converts copy core could current custom customisation data decorator default defaults define defined described developer disable disabled display displayname displays div do documented does doesn dynamic each either element elements empty enablecolumnmenus enabled enablefiltering enablehorizontalscrollbar enablerowhashing enablesorting enableverticalscrollbar end entire entitya entityb equality event events example excesscolumns excessrows exclude excludeproperties executing existing exists external extra factory false features field field1 field2 file filter filterchange filtering fired fires first fnone follow footer footer_template footertemplate for format from function functions generate get getrowidentity getsafetext github goes grid gridapi gridmenu gridmenucustomitems gridmenushowhidecolumns gridmenutitlefilter gridoptions grids gridutil handle handles has have header header_template headerrowheight headers headertemplate height helps hide hit horizontal horizontalscrollthreshold how html i18nservice id identical identifying identity if ignore ignored implemented in include included individual infinite infinitescrollpercentage information initialize initoptions inline instantiated integer interact internal internationalization into inverse is it item items large list listen logic look maintain management maxvisiblecolumncount may menu menus method minimum minimumcolumnsize minrowstoshow modified modify more most multiple must mydata name names necessary needed never nextuid ng-click ng-repeat no not note null number numbers object objects of often on once one only onregisterapi operate option options or out outside over overlaid overridden parent pass percentage performance pixels place places point precompiled present pretty prevents process programatically promise properties property provide provided provides providing query rather refer reference remove removefromgridmenu render rendered renderedcolumns renderingcomplete replace request requested required resulting return returns row row_template rowequality rowheight rowidentity rows rowtemplate scope scroll scrollbar scrollbars scrolling scrollthreshold scrollthrottle second section selectallrows selection server set setting settings should show showcolumnfooter showgridfooter showheader shown simplify smaller smoothness some sort sorter sorting source sourced specify speeding standard starting state static still string stripped style supported suppresses tailor take takes template text-align than that the their then they this throttle time title to tojson total track true turn tutorial ui ui-grid ui-grid-bottom-panel ui-grid-cell ui-grid-header ui-grid-top-panel uigrid uigridconstants unique uniquely up updated use used useexternalfiltering useexternalsorting users uses using value values var vastly vertical viewport virtualization virtualizationthreshold visibility visible want way we what when whenever where whether which while widgets will with within working x_ you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridOptions.columnDef",
    +      "shortName": "columnDef",
    +      "type": "object",
    +      "keywords": "$scope aa about action active add address adds against aggregation aggregationhidelabel alert algorithm allowing alongside although an and angular any api append apply are arguments array as asc attribute auto available backward be bind binding blargh boolean by call can case casesensitive cell cellclass cellfilter cellnav celltemplate cellvalue chosen city class clicked col colrenderindex column columndef columndefs compatibility complex condition configuration consists constants contain content context control controls currently custom data date default defaults defined defines definition definitions desc determine direction displayed displayname div docs doesn don each either element enablecolumnmenu enablecolumnmenus enabled enablefiltering enablehiding enablesorting ends ends_with evaluate evaluates even everywhere example expression expressions false feature field field1 field2 field3 fields filter filtering filters flag flags focus following footer footercellclass footercellfilter footercelltemplate for from function functionality generated get getfulladdress gets grid gridoptions gridutil guess guessing guesstype have header headercellclass headercellfilter headercelltemplate hides hiding how icon id if in individual irrespective is it item items just knows label like list many matching maximum maxwidth menu menuitems menus method minimum minwidth multiple must name no normal not noterm null number object of off omitted on one only option options or outer overall override parameters pass passed percentage placeholder pre-populated present prevents property provided receive refer removesort require return returns row rowrenderindex rows run satisfaction scope see selected sensitive service set sets setting settings should show shown single so sort sorting sortingalgorithm source specific specify specifying starts starts_with string supply supported suppressremovesort takes template term text that the then this title to too translate true turn turned tutorial type typically ui ui-grid ui-grid-icon-info-circled uigridconstants use used user using value values ve visible want when where whether which widgets width will wish with within work would xx xxx you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridRenderContainer",
    +      "shortName": "GridRenderContainer",
    +      "type": "function",
    +      "keywords": "ability adjust adjuster adjusters adjustment all allowing always an and api appropriately are available based be body boolean calculated canvas canvasheight canvasheightshouldupdate class columns consuming container containers destroyed element else false flag func function getcanvasheight gets getviewportadjustment grid has hash have height if in is it last left left-to-right may name negative of on only options or pinned recalculate recalculates register registers registerviewportadjuster remove removes removeviewportadjuster render returns right right-to-left rows should signal size something space tell that the then there to total ui used usually value values viewportadjusters visible want we when width will your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:GridRow",
    +      "shortName": "GridRow",
    +      "type": "function",
    +      "keywords": "action against all always an and any api array as back be calculations calls can canvas changed changing class clear clearrowinvisible clears col column current currently data each emits entity evaluated event exists field fielda filter findrow flag for force forces found from function getentityqualifiedcolfield getqualifiedcolfield grid gridoptions gridrow height ie if in index individual instance invisible is it item logical marks minus name necessarily needs normal not object of on one one-to-one override parent path position qualified recalculate reference refresh refreshes relation rendercontainers rendered resulting returning returns right row rowsvisiblechanged scope setrowinvisible sets that the their then this to todo true ui uid uniqueid using viewmodel visibility visible which will your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:RowSorter",
    +      "shortName": "RowSorter",
    +      "type": "object",
    +      "keywords": "algorithm algorithms allow an and any api applying appropriate are array as assigns at attempting available back based basicsort be before bit boolean bottom but by cache caching called calling case chosen class col colsortfncache column columns consider considered core criteria currently data date decide default descending determine do each enough error failing false find first for from function future get getsortfn grid gridapi guess guesses guessing guesssortfn handlenulls handles have if in including infrastructure inspect intensive internal is it itemtype itself larger look looks make mechanisms method might multiple name need no none normal note null nulls number numbers numerical object of on one or other otherwise parses passed place pointless precedence present presumably priority prioritysort processor provide provides puts returns row rows rowsorter seems sense should sort sortalpha sortbool sortdate sorted sorters sorthandlenulls sorting sortingalgorithm sortnumber sortnumberstr sorts stored string strings take than that the their them themselves there this through thrown to true type types ui undefined unused use used using value values via we were what when where which will work would"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.class:ScrollEvent",
    +      "shortName": "ScrollEvent",
    +      "type": "function",
    +      "keywords": "all an api available back be calculates can class core directive entity event fires firescrollingevent firethrottledscrollingevent for from function functionname getnewscrollleft getnewscrolltop grid if isn it limited model new newscrollleft newscrolltop null object of or owns property raise reference returns scroll scrollevent scrollevents scrolleventsources source sourcecolcontainer sourcerowcontainer string that the throttled to ui uigridconstants using value values"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.core.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "$scope acting active add added addrowheadercolumn adds addtogridmenu advantage again all allowing also always an and any api are aren array as assumes at back based be better both building but by calculations call called calls can cases cell change changed circumstances classes clearrowinvisible clears code column columndef columns columnvisibilitychanged complete completes config core criteria currently custom data datachange def described desired do does edit else emits enabled end event feature features field filter filtering fire for format found from function functional functions get getcolumnsorting getting getvisiblerows grid gridapi gridcolumns gridmenuscope gridoptions gridrow handle handlewindowresize handling has have header headercellclasses here id if in included instance invisible is isn it item items itself just last like make management manually menu method might more most must mysortfn necessary no normal normally not note nothing noticing notify notifydatachange null nulls object obtain occurred of on one only onregisterapi or order other otherwise out output override parameter parameters particularly passed picked present priority problem promise provide provided provides public re-evaluated refresh refreshes refreshrows registeredmenuitems relevant remove removefromgridmenu removes render rendered rendering renderingcomplete resize resolved result return returned returns row rowentity rows rowsvisiblechanged same screen set setrowinvisible sets should shown silently simplify size so some something sort sortchanged sortcolumns sorted sorthandlenulls sorting sorts specified specify still stopping tells that the their them then there they this those time timing to todo trigger tutorial type ui uigridconstants unique up us use used users using value values var ve visibility visible want was watch way we were when where which will window with within without would you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.directive:uiGrid",
    +      "shortName": "uiGrid",
    +      "type": "directive",
    +      "keywords": "$scope angular api app basic bob ceo controller create data developer directive div ea for frank function grid html index js lowly mainctrl module name ng-controller options the title to ui ui-grid uigrid use var very"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.directive:uiGridColumnMenu",
    +      "shortName": "uiGridColumnMenu",
    +      "type": "directive",
    +      "keywords": "$columnelement $scope again allows already an angular animate api app as ask asks assumption below break broadcast broadcasttrigger by calculate calls can case column controller default directive displayed do doesn don element elements expressions from function get grid hidden hide hidemenu hides ie8 if in infinite interpolate is it itself ll loop mainctrl make menu method module ng-controller on once place position repositions right show showmenu shown shows size style the then this to triggered true ui ui-grid-menu us var want we were which whilst width will"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.directive:uiGridColumnMenu",
    +      "shortName": "uiGridColumnMenu",
    +      "type": "directive",
    +      "keywords": "api column directive framework grid leverages menu provides the ui uigridmenu underneath"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.directive:uiGridStyle",
    +      "shortName": "uiGridStyle",
    +      "type": "directive",
    +      "keywords": "$scope allows am angular api app apply as blah border box break by can class controller css default directive do doesn element elements expect expressions function getcssvalue grid ie8 in interpolate it mainctrl module mystyle ng-controller right should solid style the then this to tocontain ui ui-grid-style us var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.e2eTestLibrary",
    +      "shortName": "e2eTestLibrary",
    +      "type": "overview",
    +      "keywords": "also api are associated be e2etestlibrary end functions grid it may necessary overview test the these to tutorial ui update updated whenever"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.e2eTestLibrary.api:gridTest",
    +      "shortName": "gridTest",
    +      "type": "service",
    +      "keywords": "about adding adjust all also alternatively although an and any api are array as ascending associated at based be body border box boxes break browser but button by can cancel cancelfilterincolumn cancels cell cellvalue cellvalue1 cellvalue3 change changed check checks click clickcolumnmenu clickcolumnmenuhide clickcolumnmenuremovesort clickcolumnmenusortasc clickcolumnmenusortdesc clickgridmenuitem clickheadercell clicking clicks clickvisiblegridmenuitem col colnumber colnumber-1 cols column columns constant container could count cumbersome data datacell dataset default descending develop does doing drag drags e2etestlibrary each easily element end enter enterfilterincolumn enters error every exists expect expectcellvaluematch expectcolumncount expectedcol expectednumcols expectednumrows expectedrow expectedvalue expectedvaluearray expectfilterboxincolumn expectfootercellvaluematch expectfootercolumncount expectheadercellvaluematch expectheadercolumncount expectheaderleftcolumncount expectitems expectrowcount expectrowvaluesmatch expectvisiblecolumnmenuitems expectvisiblegridmenuitems feels fetchcol fetchrow filter filtervalue find finds footer footercell footervalue for fragile from functional functions given go greater grid gridid gridtestutils has have header headercell headervalue helpers hide how i18n id if in increase individual inspect internal into is it item itemnumber items left less ll look lots many matches may meaning menu menuitemnumber menus method methods myelement mygrid necessary none not note number numbered numbers numerical of on only option or ordering perform pinned quite reason recommended regex regexes remove render rendered repeater resizeheadercell resizer resizing result return returns row rows same script second see service shift-clicks shiftclickheadercell simple size small so some sort specified standard string strings takes test tests text than that the then there therefore these this to towards tutorial typically ui ui-grid underlying update updated used useful using usually value values verify virtualisation visible visiblecolumnmenuitems want when whenever which will wish with within would wrap write you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit",
    +      "shortName": "edit",
    +      "type": "overview",
    +      "keywords": "allow and api arrow be below beside capability cell cellnav cells data doc-module-components edit editing emulate enter entry full get goal grid in key keyboard keying module or overview provides really should spreadsheet spreadsheet-like tab the then this to ui used user via was will"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "$scope active allowed an and angular-translate api apply are array as available backing bars baz be before both can cell celleditablecondition cellnav class code col coldef column columndef columndefs containing default defaults definition dependent determine dropdown edit editablecelltemplate editdropdownfilter editdropdownidlabel editdropdownoptionsarray editdropdownrowentityoptionsarraypath editdropdownvaluelabel editing editor either enable enablecelledit enablecelleditonfocus enabled_ entity evaluated example false falsy feature field filter focus foo for format function grid gridoptions id if ignored in inactive into invoked is label like list might not object of on options or path populate populated property receives return row set soon specified status template text that the then these this to translate true ui ui-grid url used using value values were when which will would xxx you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "$scope all allowed and api are as available be before by cell celleditablecondition cellnav celltemplate class col coldef coldefs columns configuration configuring default defaults defined determine each edit editable editablecelltemplate editing editor either enablecelledit enablecelleditonfocus enabled_ entity false falsy feature flag focus for function grid gridoptions if individual invoked is not object of on options or receives return row set sets soon specified the their then these to true ui ui-grid undefined use used using value"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.api:GridRow",
    +      "shortName": "GridRow",
    +      "type": "object",
    +      "keywords": "api are available be by disable edit editing enable enablecelledit example feature features for grid gridrow group grouping header internally might object on only options other row rows set these to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "api edit feature for grid object public ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.constant:uiGridEditConstants",
    +      "shortName": "uiGridEditConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants edit grid in module object ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.directive:input",
    +      "shortName": "input",
    +      "type": "directive",
    +      "keywords": "$valid and angular api between binding date directive edit element enclosing entered false for form format grid if input invalid is it model ng-model of or property provide set similar supported the to ui value will wrong yyyy-mm-dd"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.directive:uiGridCell",
    +      "shortName": "uiGridCell",
    +      "type": "directive",
    +      "keywords": "actions and angular api appended back be been begin binds blur by cancel cancelled capabilities cell celleditor columndef dblclick default dependent directive div do edit editablecelltemplate editing element emit end ended enter esc etc event events f2 fire grid grid_scroll gridcell has html if in-line initial input invoke is it key keydown model needed of on original provide recognizes respond selection set should specific stacks standards start steps that the to top ui uigridcell uigridconstants uigrideditconstants using value when will with"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.directive:uiGridEdit",
    +      "shortName": "uiGridEdit",
    +      "type": "directive",
    +      "keywords": "$scope adds angular api app bob ceo columndefs controller data developer directive div edit editing enablecelledit features frank function grid html index js lowly mainctrl module name ng-controller the title to true ui ui-grid ui-grid-edit var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.directive:uiGridEditDropdown",
    +      "shortName": "uiGridEditDropdown",
    +      "type": "directive",
    +      "keywords": "and any api blur cancel canceledit directive div dropdown edit editable editing editor end endedit enter esc events fields for grid keydown left nav provides that ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.directive:uiGridEditor",
    +      "shortName": "uiGridEditor",
    +      "type": "directive",
    +      "keywords": "and api blur cancel canceledit directive div edit editable editing editor end endedit enter esc events fields for grid input keydown provides that ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.edit.service:uiGridEditService",
    +      "shortName": "uiGridEditService",
    +      "type": "service",
    +      "keywords": "adds an angular any api column columnbuilder decorate decorator determines docs edit editcolumnbuilder editing event events evt features for function grid if in isstarteditkey key keydown keypress load needed override own promise properties resolved see service services should start templates that this to true ui when will with your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable",
    +      "shortName": "expandable",
    +      "type": "overview",
    +      "keywords": "ability api create doc-module-components expand expandable grid module overview provides row show subgrid subgrids the this to ui with"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "$scope _this_ allows and api application are available be buttons class collapsing column configuring custom defaults enableexpandable enableexpandablerowheader expandable expandablerowheaderwidth expandablerowheight expandablerowtemplate expanded expanding false feature for going grid gridoptions grids height html if implies in mandatory method modes not object of off on options or pixels provide re row rowheader set show specific subgrid subgrids template the then these to true turn ui ui-grid use using whether width within you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "all api collapse collapseallrows data entity expand expandable expandallrows feature for grid gridapi method object public row rowentity specific subgrids the to toggle toggleallrows togglerowexpansion ui want you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.class:Grid",
    +      "shortName": "Grid",
    +      "type": "directive",
    +      "keywords": "added additional api by class directive expandable expanded grid module object owns parent parentrow properties reference row that the this to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.directive:uiGrid",
    +      "shortName": "uiGrid",
    +      "type": "directive",
    +      "keywords": "api child created directive expandable grid is on parent register row stacks the to ui uigrid when with"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.directive:uiGridExpandableRow",
    +      "shortName": "uiGridExpandableRow",
    +      "type": "directive",
    +      "keywords": "api directive expandable grid render row template the to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.directive:uiGridRow",
    +      "shortName": "uiGridRow",
    +      "type": "directive",
    +      "keywords": "add api directive expandable for grid on rows stacks support the to ui uigridrow"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.directive:uiGridViewport",
    +      "shortName": "uiGridViewport",
    +      "type": "directive",
    +      "keywords": "api append default directive elements expandable grid gridrow html on row stacks template the to ui uigridviewport"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.expandable.service:uiGridExpandableService",
    +      "shortName": "uiGridExpandableService",
    +      "type": "service",
    +      "keywords": "api expandable for grid service services the ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter",
    +      "shortName": "exporter",
    +      "type": "overview",
    +      "keywords": "ability all and api appropriate as be caller can columns data doc-module-components enable exported exporter formats from grid gridmenu in is module no of or overview own provide provided provides range rows selected should the their this to ui visible with"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "alignment and any api be by can center column columndef expandable export exported exporter exporterpdfalign exportersuppressexport for grid into left like object option or other pdf pdfmake property right selection settings specific suppresses the this ui used valid when you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "$translate a4 accordingly add adding adjusted alignment allowing allows already an and angular-translate any api applied apply are array as automatically available be before behaviour being black bold browsers but button buttons by call callback called calling can cannot case changed changes character class codes col color column columns com comes complete complex content context controls convert csv current currentpage custom data date decodes decodestatus default defaults definition display displayname displaynames docdefinition document don download downloaded each example export exported exporter exportercsvcolumnseparator exportercsvfilename exporterfieldcallback exporterheaderfilter exporterheaderfilterusename exportermenucsv exportermenulabel exportermenupdf exporterpdfcustomformatter exporterpdfdefaultstyle exporterpdffooter exporterpdfheader exporterpdfmaxgridwidth exporterpdforientation exporterpdfpagesize exporterpdftableheaderstyle exporterpdftablelayout exporterpdftablestyle exportersuppresscolumns exportersuppressmenu exporting exports false feature field filename filters fixed fontsize footer footerstyle for format from function grid gridcol gridlines gridoptions gridrow had have header headerfilter https if implying in instant instead internationalisation into is it items js landscape layout leads left letter like link list margin massaged massaging match maxium means menu method more must my name names need no not note null numbers object of on once only or orientation other our output own page pagecount paper part pass passed pdf pdfmake portrait present promise provide provides raw ready require return returns right roll routine row saving scaled section selectionrowheader separator set should shouldn show shown simple size sizes so some specific status style styles styling supported suppressed synchronous system table tableheader tablelayout takes text that the their then these this through to tostring true ui ui-grid updated use useful user using usually valid value we were when which width will with work you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.api:GridRow",
    +      "shortName": "GridRow",
    +      "type": "object",
    +      "keywords": "api don export exporter exporterenableexporting false for grid gridrow if notwithstanding object or other row set settings then this to true ui visible"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "all api are based been browser coltypes columns csv csvexport data dependency export exported exporter exports feature for format from function going grid has in installed is new note object on opens options pdf pdfexport pdfmake provided public resulting rows rowtypes selected that the this to ui uigridexporterconstants valid values visible well which window you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.constant:uiGridExporterConstants",
    +      "shortName": "uiGridExporterConstants",
    +      "type": "object",
    +      "keywords": "all api available be can coltypes columns constant constants data either export exporter for grid in including is module not object of only or property rowtypes selected selection set some supported ui visible"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.directive:uiGridExporter",
    +      "shortName": "uiGridExporter",
    +      "type": "directive",
    +      "keywords": "$scope adds angular api app bob ceo columndefs controller data developer directive div enablecelledit enablegridmenu exporter exportermenucsv false features frank function grid gridoptions html index js lowly mainctrl module name ng-controller title to true ui ui-grid ui-grid-exporter var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.exporter.service:uiGridExporterService",
    +      "shortName": "uiGridExporterService",
    +      "type": "service",
    +      "keywords": "add adds addtomenu adjust align alignment all allow allowing an and any api applied appropriate are around array as at attributes base based basic be browser by calculatepdfheaderwidths call casting cellfilters cells checks colleagues coltypes column columns com consumable content contribute csv csv-ified csvcontent csvexport current data definition dependency determines different displayname document don download downloadfile drawn drawnwidth each everything export exportcolumnheaders exportdata exported exporter exporterenableexporting exportheaders exports extra false feature field file filename for format formatascsv formatfieldascsv formatrowascsv formatrowaspdf formats formatted from function generation getcolumnheaders getdata gets given got grid gridwidth has have header headercellfilters headers heuristic his https ie if in including information installed into is isie issue it items like logic mainly marked may maybe meaning menu must name need new not note numeric object objects of on only opens options or our overall pass pdf pdf-able pdfexport pdfmake plus provided quotes ready renderaspdf renders resulting returns row rows rowtypes select selected sends service services should single so string string-ified strings take that the them then they this title to triggers turned type ui uigridexporterconstants use used user valid value values version visible we when where whether which width widths will window with"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.gridMenuService",
    +      "shortName": "gridMenuService",
    +      "type": "service",
    +      "keywords": "$scope added adding addmenuitem adds addtogridmenu all allowing always an and any api appropriate are array as associated be been by can change changed coldef column columndef columndefs columns combination contains context core decides default directly displayname dynamically each expects features field find for from get getmenuitems grid gridcol gridcolumn gridmenu gridmenucustomitems gridmenuscope gridmenuservice gridmenutitlefilter handles has have hide if importantly in included individual information initialize into is it item items ll menu menuitem method methods most name need not object of on one only onto operate options or otherwise our passed promise property provided put putting re recalculated reference refresh register reject removefromgridmenu resolve response result returns scope second service setmenuitemtitle sets show showhidecolumns shown string that the then these they this through title to toggle togglecolumnvisibility toggles two typically ui up upon us using visibility visible waiting want we when whenever which with within working"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.i18n",
    +      "shortName": "i18n",
    +      "type": "overview",
    +      "keywords": "and any api application doc-module-components functions grid i18n it module overview provides that this to ui use wants"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.i18n.constant:i18nConstants",
    +      "shortName": "i18nConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants grid i18n in module object ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.i18n.service:i18nService",
    +      "shortName": "i18nService",
    +      "type": "service",
    +      "keywords": "$broadcasts $rootscope add adds aggregate all and api application ascending by cache column current currently decorate description drag drop en for found fr from get getalllangs getcurrentlang getsafetext grid group grouped grouppanel header here i18n i18nservice if in is it items label1 label2 lang language languages loaded map maps missing more names not of on or path property retrieving return returns service services set setcurrentlang sets some sort specified string stringmaps strings text that the this to translation ui update_event use used"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer",
    +      "shortName": "importer",
    +      "type": "overview",
    +      "keywords": "$resource ability added allows also although an and another any api application as attributes be been belongs callback calls can class column configured copies created creates csv currently data default defs displayname displays doesn don each enabled entities errors feature file files for formats from grid has header headings identification if import imported importer imports in instance internationalised into is it json just made makes match matching menu module must name names new newly object objects of on only optionally or other out over overview particularly process properties provides provision put relies requesting row rowedit save sees specified that the then these this those time to type ui ui-grid-importer use used useful user uses using way which within work your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "$resource $scope $translate about active add adds after alert an and any api appended application are array as automatically available back be before behaviour both box break browser but by call callback can case change class code column columns commonly concat console consolemessage content context create created csv custom data decode decoded defaults different directly discarded display displayname does doesn doing don each element enabled enableimporter english entity error errorkey errors event example false feature field file fileapi filter filtered first for foreach from function generally given grid gridoptions handle handling has have header headerarray headers i18n if import importer importerdataaddcallback importererrorcallback importerheaderfilter importernewobject importerobjectcallback importerprocessheaders importershowmenu importing in inactive index inserting instant internal internationalise internationalised into invalidcsv invalidjson is it item itself javascript jsonnotarray keys knows language like log logging logic mandatory massages match matching may means menu message messages method might modified modify mydata myheadercols myheadercolumns myloggingroutine myres myspeciallookupfunction myuserdisplayroutine name names necessarily need needs new newobject newobjects noheaders non-matching noobjects not nothing null object objects occur of often on one or order otherwise passed position positioning process processheaders processing property provide provides push rather re recognises required respond return returned returning routine row rowedit rows same save seeks server set should show single some source standard status stored support switch text than that the their then therefore these this thiscol through tidier to translate translated triggered true typically ui ui-grid use used useful user using value vanilla var version want way we when where whether which will would write written you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "api as bypasses feature file fileobject for function grid import importer importfile imports into javascript menu object provided public the to ui using want we"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.constant:uiGridImporterConstants",
    +      "shortName": "uiGridImporterConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants grid importer in module object ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.directive:uiGridImporter",
    +      "shortName": "uiGridImporter",
    +      "type": "directive",
    +      "keywords": "adds api directive div features grid importer to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.directive:uiGridImporterMenuItem",
    +      "shortName": "uiGridImporterMenuItem",
    +      "type": "directive",
    +      "keywords": "api directive div file from grid handles importer is item menu once processing selected the ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.importer.service:uiGridImporterService",
    +      "shortName": "uiGridImporterService",
    +      "type": "service",
    +      "keywords": "added addobjects adds addtomenu again against alert alerterror allowing an and api are array arrays as attribute attributes based be being by bypasses callback called calls checker code column columns com comes condition console content converts create createcsvobjects creates creating csv data datachanges defined definitions defs deregister deregisters destroy determines diagnostic dirty displayname displays does doesn don downstream either empty enabled error essentially event failure feature field file fileobject first for from function get grid gridoptions have header headerrow headers https if import importcsvclosure imported importer importererrorcallback importernewobject importerprocessheaders importfile importing importjson imports importthisfile in including individual insert inserts instead internationalised into is it item itself javascript js jscs json license logic logs makes maps marked match matching menu message method mit modified name named names native never new newobject newobjects next not noted object objects of on onload optionally or order other our parse parsecsv parsed parsejson parses pass present processheaders processing provided provides re reader registering remaining represents request result resulting returned returns routine routines row rowedit rows run service services set sets should specified that the then this time to type ui under used user uses using waiting want watch we when which will wish with yoda"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.infiniteScroll",
    +      "shortName": "infiniteScroll",
    +      "type": "overview",
    +      "keywords": "api functionality grid infinite infinitescroll module overview provides scroll this to ui ui-grid"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.infiniteScroll.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "api are available be class enable enableinfinitescroll feature for grid gridoptions infinite infinitescroll object scroll scrolling set the these this to true ui ui-grid using"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.infiniteScroll.api:PublicAPI",
    +      "shortName": "PublicAPI",
    +      "type": "object",
    +      "keywords": "api as data dataloaded example feature finished for function grid infinite infinite_scroll infinitescroll is loading ngdoc object of promise public scroll see this ui usage used when"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.infiniteScroll.directive:uiGridInfiniteScroll",
    +      "shortName": "uiGridInfiniteScroll",
    +      "type": "directive",
    +      "keywords": "$scope adds alex angular api app car columndefs controller data directive div features function grid html index infinite infinitescroll js lexus mainctrl module name ng-controller sam scroll to toyota ui ui-grid ui-grid-infinite-scroll var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.infiniteScroll.service:uiGridInfiniteScrollService",
    +      "shortName": "uiGridInfiniteScrollService",
    +      "type": "service",
    +      "keywords": "and api based calls checks checkscroll event events features fires for function grid infinite infinitescroll infinitescrollpercentage initializegrid inside into loaddata method methods needloadmoredata needloadmoredatatop on or position public reaches register scroll scrolldirection service this ui when"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns",
    +      "shortName": "moveColumns",
    +      "type": "overview",
    +      "keywords": "api capability change column columns doc-module-components enables grid it module movecolumns moving of overview position provides the this to ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "api are available be class column columndef columndefs definition enable enablecolumnmoving feature for grid gridoptions move movecolumns moving object set the these to ui ui-grid using"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "api are available be class coldefs colmovable column configuration configuring default defaults defined each enablecolumnmoving feature flag for grid gridoptions if individual is move movecolumns not object on options set sets the their these to true ui ui-grid using value"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "api be can change colmovable column feature finalposition for grid gridapi method movecolumn movecolumns moving newposition object of originalposition position public the to ui used"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.directive:uiGridHeaderCell",
    +      "shortName": "uiGridHeaderCell",
    +      "type": "directive",
    +      "keywords": "able also and api as at be capability case cell cloned cloning column directive div event events exists extreme grid header headercell horizontal in invoke is it left mouse mousedown mousemove mouseup move movecolumns moved movement moves moving now of on or position provide reaches receiving released removed reposition repositioned repositioning right scroll scrolling stacks that the to top triggered ui uigridheadercell where"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.directive:uiGridMoveColumns",
    +      "shortName": "uiGridMoveColumns",
    +      "type": "directive",
    +      "keywords": "$scope adds age angular api app bob ceo class column columndefs controller css data developer directive div features frank function grid height highly html index jenny js lowly main mainctrl module movecolumns moving name ng-controller the title to ui ui-grid ui-grid-move-columns var width"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.moveColumns.service:uiGridMoveColumnService",
    +      "shortName": "uiGridMoveColumnService",
    +      "type": "service",
    +      "keywords": "api column feature for grid movecolumns moving service ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination",
    +      "shortName": "pagination",
    +      "type": "overview",
    +      "keywords": "api grid module overview pagination provides support this to ui ui-grid"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "and api are array at automatically available be bottom by class client controls current custom data defaults disables empty enablepagination enablepaginationcontrols enables event false feature first for grid gridoptions handle if implement in is item items needs number object of off or outside own page pager pagination paginationchanged paginationcurrentpage paginationpagesize paginationpagesizes paginationtemplate paginator property server set side size sizes template the these this to total totalitems true turn ui ui-grid useexternalpagination user using want when you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination.api:PublicAPI",
    +      "shortName": "PublicAPI",
    +      "type": "object",
    +      "keywords": "api be current displayed feature first for getpage gettotalpages grid if method moves next nextpage not number object of on page pages pagination possible previous previouspage public re requested returns seek should that the to total ui we"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination.directive:uiGridPager",
    +      "shortName": "uiGridPager",
    +      "type": "directive",
    +      "keywords": "api directive div for grid handling pagination panel ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination.directive:uiGridPagination",
    +      "shortName": "uiGridPagination",
    +      "type": "directive",
    +      "keywords": "$scope acura adds alex amy angular api app audi benz bmw bob brian buick car cindy columndefs controller data dave directive div dodge features ford function grid gridoptions html index joe js lexus mainctrl malcom mercedes module name ng-controller pagination paginationpagesize paginationpagesizes ryan sam scott stacey to toyota ui ui-grid ui-grid-pagination var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pagination.service:uiGridPaginationService",
    +      "shortName": "uiGridPaginationService",
    +      "type": "service",
    +      "keywords": "and api attaches calls certain changed client currentpage feature for grid initializegrid method number page pagesize pagination paginationchanged raises refresh requested service side size the to ui uigridpaginationservice want we which with work"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pinning",
    +      "shortName": "pinning",
    +      "type": "overview",
    +      "keywords": "api column doc-module-components end grid header in menu module options overview pinning provides the this to ui user via"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pinning.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "api are available be class column columndef columndefs enable enablepinning false feature for grid gridoptions individual is left object pinned pinnedleft pinnedright pinning rendered right set the these to true ui ui-grid using when"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.pinning.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "api are available be class enable enablepinning entire feature for grid gridoptions object pinning set the these to true ui ui-grid using"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.resizeColumns.api:ColumnDef",
    +      "shortName": "ColumnDef",
    +      "type": "object",
    +      "keywords": "an api are available be class column columndef columndefs enable enablecolumnresizing feature for grid gridoptions individual object on resizecolumns resizing set the these to ui ui-grid using"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.resizeColumns.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "api are available be class column enable enablecolumnresizing entire feature for grid gridoptions object on resizecolumns resizing set the these to true ui ui-grid using"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.resizeColumns.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "api column feature for grid object public resize resizecolumns ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.resizeColumns.directive:uiGridColumnResizer",
    +      "shortName": "uiGridColumnResizer",
    +      "type": "directive",
    +      "keywords": "$scope and angular api app be beryl class claudine column company controller controls data directive div draggable e2e enablecolumnresizing enersol ethel event female fired function geekko gender gonzales grid gridopts handle horizontal mainctrl male maxwidth minwidth module name neal ng-controller obey post-resize price resizecolumns resizing rice scroll sealoud should specs testgrid that todo true ui ui-grid var velity wilder"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.resizeColumns.directive:uiGridResizeColumns",
    +      "shortName": "uiGridResizeColumns",
    +      "type": "directive",
    +      "keywords": "$scope all allow angular api app beryl but can class claudine column columndef columns company controller data directive div enables enersol entire ethel explicitly false female for function geekko gender gonzales grid gridopts if individual mainctrl male module name neal ng-controller not of on option options prevents price reason regardless resizecolumns resizing rice sealoud set some testgrid the this to ui ui-grid ui-grid-resize-columns use var velity want wilder you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit",
    +      "shortName": "rowEdit",
    +      "type": "overview",
    +      "keywords": "also and api benefits best data depends edit editing experience extends feature from full grid here how information is module more of on overview provide provides rowedit rows saving spreadsheet-like the this to tracking tutorial ui ui-grid-cellnav ui-grid-edit usage use used"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "$scope another api are available be before by call change class configuring feature flushdirtyrows for grid gridoptions how if interval long manually milliseconds never object on options property row rowedit roweditwaitinterval save saves seconds set setting should that the then these this timer to triggered triggering ui ui-grid user using wait will"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "$digest $interval $timeout aggregate all an api are array associated away be been before button call calls could currently cycle data datarows dirty each entities error errored event fails feature flushdirtyrows for from function getdirtyrows geterrorrows grid gridapi gridrows handler has have if in individual initiated inserted into is it just mandatory method mydatarows navigates need note object of often only or page passed present presses promise promises public rejected represents resolved returning returns row rowedit rowentity rows save savepromise saverow set setrowsdirty sets setsavepromise should so somewhere successful that the this to triggers ui used user wait when where which will with would wrap you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.constant:uiGridRowEditConstants",
    +      "shortName": "uiGridRowEditConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants edit grid in module object row rowedit ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.directive:uiGridEdit",
    +      "shortName": "uiGridEdit",
    +      "type": "directive",
    +      "keywords": "adds api directive div editing features grid row rowedit the to ui ui-grid-edit"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.directive:uiGridViewport",
    +      "shortName": "uiGridViewport",
    +      "type": "directive",
    +      "keywords": "allow alter and api attributes coloring directive div error for grid of on row rowedit rows saving stacks the to top ui uigridviewport used"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.rowEdit.service:uiGridRowEditService",
    +      "shortName": "uiGridRowEditService",
    +      "type": "service",
    +      "keywords": "$digest $interval $timeout adjusted aftercelledit aggregate all already although an and any api appropriate are array as associated automatically available away be been before begincelledit begineditcell button by cache call callback called calls cancel cancelcelledit canceleditcell cancelled cancels canceltimer cell cellnav changed checks column commenced consider considersettimer could currently cycle data datarows delete dirty dirtyrows does each edit edited editing either endeditcell entities entity error errorrows event failed fails features flags flushdirtyrows flushed for from function given grid gridapi gridrow gridrows had handler handling has have if in individual initiated inserted into is isn isrowpresent it itself just left look looked mandatory method mydatarows navigate navigates need new newrowcol not note nothing now of often old oldrowcol on only or other page parameter params passed present presses processed processerrorpromise processes processing processsuccesspromise promise promises provided receives rejected relating remove removed removerow removes represents resolution resolved restarts returned returning returns row rowarray rowedit roweditsavetimers rowentity rows running same save saved savepromise saverow saves saving selected service services set setrowsdirty sets setsavepromise setting should silently similar so somewhere specified start still stop success successful tells that the then there this timer to triggers turn ui us used user using wait was we were when where whether which will with would wrap you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState",
    +      "shortName": "saveState",
    +      "type": "overview",
    +      "keywords": "ability and api appropriate as be caller doc-module-components events grid is it module navigate no overview own page provide provided provides restore returns save save-state savestate should state the their this to ui used user usually when would"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "actually again also and anything api are as attempt available be been before business by callback called can cell cellnav changed class column columns concatenate current currently data default define defined deleted different disabled do does each element enabled example exists false feature field fields filter find focus focused for from function give grid gridoptions has have however id if in instead is isn it list little ll make makes mean-time might move not note nothing number object of on one only option or order passing percentage position preferred presuming provided reorder resize results return returning returns row rowentity rows same save saved savefilter savefocus saveorder saverowidentity saves savescroll saveselection savesort savestate savevisible savewidths scroll scrolled select selected selection sense set should show significantly simply so some sort specific state still that the their then these this to true ui ui-grid undefined unique unless use used user using value ve visible want way we when whether which widths will with within won wrong you your"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "$scope an and api as be broadcast can current feature for function grid into it javascript object of on packages provided provides public restore restored restores save saved savestate saving scope should state that the to ui user we"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState.constant:uiGridSaveStateConstants",
    +      "shortName": "uiGridSaveStateConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants grid in module object save savestate state ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState.directive:uiGridSaveState",
    +      "shortName": "uiGridSaveState",
    +      "type": "directive",
    +      "keywords": "$scope adds angular api app bob ceo columndefs controller data developer directive div enablecelledit features frank function grid gridoptions html index js lowly mainctrl module name ng-controller savestate title to true ui ui-grid ui-grid-save-state var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.saveState.service:uiGridSaveStateService",
    +      "shortName": "uiGridSaveStateService",
    +      "type": "service",
    +      "keywords": "$scope an and any anyway api applies approximates are back be before broadcast caller can cell cellnav column columns columnsstate containing current currently does each either enabled false feature filters find findrowbyidentity finds first flag focus focused for found function getrowval gets given grid gridrow had helper identity if in including into is isn it like list matches module more name no none not nothing null object of on one only or order ordering otherwise passes position present provided ready restore restorecolumns restored restores restorescrollfocus restoreselection return returns row rowidentity rownum rownumber rows rowval save savecolumns saved savefocus saverowidentity saves savescroll savescrollfocus saveselection savestate scope scroll scrollfocusstate scrolls selected selection selectionstate selects service services sets setup sort specified state stores storing than that the their them then through to true ui using value visible visiblerownum want was we whose width widths with without works you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection",
    +      "shortName": "selection",
    +      "type": "overview",
    +      "keywords": "api doc-module-components grid module overview provides row selection this ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.api:GridOptions",
    +      "shortName": "GridOptions",
    +      "type": "object",
    +      "keywords": "all allow also always and api are at available be being bulk called can cause changed checkbox class column conjunction create ctrlkey custom different each either enable enablefootertotalselected enablerowheaderselection enablerowselection enableselectall enableselection enableselectionbatchevent entire evaluates event false feature fired footer for from grid gridapi gridoptions header if in instead is isrowselectable it items its makes method modifierkeystomultiselect multiple multiselect must nounselect number object of only option or possible prevent property requires row rows rowselectionchanged select selectall selected selection selectionrowheader selectionrowheaderwidth selectrow separate set sets setting shiftkey showfooter shows single specify that the then these this times to top total true ui ui-grid unselect unselected used using via when width will with works you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.api:GridRow",
    +      "shortName": "GridRow",
    +      "type": "object",
    +      "keywords": "added and any api be by changes code enable enableselection example false feature for function functions grid gridrow group grouping header internal isselected made make might not object of only property prototype readonly row rows selectable selected selectedcount selection selelected set sets setselected settable should state the this to true ui updates using value via"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.api:PublicApi",
    +      "shortName": "PublicApi",
    +      "type": "object",
    +      "keywords": "add all allow an and api are array as automatically by call check checkbox clearselectedrows context ctrlkey current currently data does doesn entity event explicitly extra false feature filtered first for from function get getselectallstate getselectedgridrows getselectedrows grid gridoption gridoptions gridrows if in index instance is it ll means modifierkeystomultiselect multiple multiselect need not nothing object of on only or public raised rather references rendered returns row rowentity rows rowsvisible screen select selectall selectallrows selectallvisiblerows selected selectedrow selection selectrow selectrowbyvisibleindex selects set setmodifierkeystomultiselect setmultiselect sets setvisible shiftkey so specified specify than that the then theoretically this those ticked to togglerowselection toggles true ui unselect unselected unselectrow unselects used using visible when whether within you"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.constant:uiGridSelectionConstants",
    +      "shortName": "uiGridSelectionConstants",
    +      "type": "object",
    +      "keywords": "api available constant constants grid in module object selection ui"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.directive:uiGridCell",
    +      "shortName": "uiGridCell",
    +      "type": "directive",
    +      "keywords": "api directive div feature grid of on provide selection stacks to top ui uigridcell"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.directive:uiGridSelection",
    +      "shortName": "uiGridSelection",
    +      "type": "directive",
    +      "keywords": "$scope adds angular api app bob ceo columndefs controller data developer directive div enablecelledit features frank function grid html index js lowly mainctrl module name ng-controller selection title to true ui ui-grid ui-grid-selection var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.directive:uiGridViewport",
    +      "shortName": "uiGridViewport",
    +      "type": "directive",
    +      "keywords": "alter api attributes directive div for grid of on row selection stacks the to top ui uigridviewport used"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.grid:selection",
    +      "shortName": "selection",
    +      "type": "object",
    +      "keywords": "added and api count current for functions grid object of properties rows selected selectedcount selection ui var"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.selection.service:uiGridSelectionService",
    +      "shortName": "uiGridSelectionService",
    +      "type": "service",
    +      "keywords": "all an and api append array as at batch be can cannot changed changedrows clears clearselectedrows clicked decideraiseselectionevent decides deselect do does doing event events false features for from function getselectedrows grid group has if is it key last multiselect need nothing nounselect object of one only or populated raise raised raises raiseselectionevent re resulting returns row rows select selected selection selects service services shift shiftselect single that the then this time to togglerowselection toggles true ui unselected using we whether which"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.service:gridClassFactory",
    +      "shortName": "gridClassFactory",
    +      "type": "object",
    +      "keywords": "an and api applies col coldef column core created creategrid creates defaultcolumnbuilder definition definitions designtime dom each factory features for function grid gridcol gridoptions have id instance instances into map method new object of options pass processes reference return service specific the them to ui unique will"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.service:GridUtil",
    +      "shortName": "GridUtil",
    +      "type": "service",
    +      "keywords": "$log $scope accessor account accounting adapted after alert allow allowing always an and angular any anything apart api app appropriately are argument arguments array as at attempt be before bind binding binds bob boolean borders bound bracket browser browsers but by cache calculation called calling calls can capitalized characters choose column columndefs columnname com comes consistent console contents controller converts copied correctly createboundedwrapper current currently data date debounce debounced debouncedfunc debug decorated decorates deep definitions delay denormalize denormalizes desired different direction do does dom dommousescroll either element elementheight elementwidth else ends ensures environment error etc evaluate event examine excludeproperties execute executed field first firstname following for frank from func function functions get getcolumnsfromdata gettemplate given grid gridutil guesses guesstype handle height html http https id if immediate in inconsistent index inside iow is it item its jones jquery js keep keys last lastname list log log_debug_messages log_error_messages log_warn_messages logdebug logerror logged logmessage logs logwarn mainctrl make margin margins matter means message messages method milliseconds modifier module most-recent mouse mousewheel mozmousepixelscroll multiple name names nested newid ng-bind ng-controller ng-model no normalize normalized normalizes normalizescrollleft normalizewheelevent not notation number object of on one only optional or param params path performs pixels points potential preeval present promise prop-erty property queues readablecolumnname regardless representing request resolving resulting return returns right rtl scale scrollleft see service set smith so special split stays string sure takes template that the them then this throttle throttled throttledfunc time times to trailing treatment trigger true truthy type ui ui-grid uigridconstants unique updates url us use utility value values var variable wait warning ways we what wheel whether width with within wrapper wraps"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.service:rowSearcher",
    +      "shortName": "rowSearcher",
    +      "type": "service",
    +      "keywords": "across against all an and any api apply array as asterisk based be beginning but can cell col column columns condition conditions constant contains could data defaults do don else ending ends_with everywhere exp filter filters flags for foreach from function get getterm given grid gridcolumns gridrows guess guesscondition has here if in inside instance into invisible it its leading less loops marking match matches matching meets module much new not object of on one or parsed parsing passed performance pre-parsed pre-processing preparsed process provided re reg remove representing return returning row rows run runcolumnfilter runs search searchcolumn searching sensitive service setupfilters since single specific starting starts_with stays store stored strings stripped stripterm term test that the there this to trailing trims true ui use uses using value visible want was we whether whitespace with working"
    +    },
    +    {
    +      "section": "api",
    +      "id": "ui.grid.service:uiGridColumnMenuService",
    +      "shortName": "uiGridColumnMenuService",
    +      "type": "service",
    +      "keywords": "$columnelement $elm $scope active again allow and api at based be before below by called calling can checking child code col column columndef containing current currently default defaults determines direction easier element enablehiding factored fix for from getcolumnelementposition getdefaultmenuitems gets grid guess has hash have header height hidden hideable highlighting if in information initialize is isactivesort it items later left ll make menu menuitems menus method needed needs new no nodes not offset on option out place position positiondata puts re reference removesort reposition repositionmenu requested returns selected service services set setcolmenuitemwatch sets setup should sort sortable suppress suppressremovesort that the then this to top ui uigridcolumnmenu uigridcontroller uigridctrl underneath understand update us visible want watch we whether width with working"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "index",
    +      "shortName": "Index",
    +      "type": "overview",
    +      "keywords": "according advanced and answer any are ask basic case combined common complexity developers do don encouraged features for grid help here href https if im in index lot needed numbered of on overview particular pr provide real see set should submit the then this to tutorial tutorials ui-grid use-cases using way what world you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "098_contributing_to_ui-grid",
    +      "shortName": "098 Contributing to ui-grid",
    +      "type": "overview",
    +      "keywords": "_demonstrable accessible account add adjust aim all allow already always an and angularjs answer answers appropriate are area aren as ask assist assisting at be before bits both branch bug build but button by can channels click code coding collate com come commit commits complete complex configuration continue contribute contributing contributions contributors copy core could courteous covered create default demonstrates described detail development diagnose dive do documentation don each easier easiest edit end-to-end enough everywhere existing expected extended familiar features find first fix follow for freeing friendly from generally get github gitter good grid guide guides happen hard have help helping high if in including increase indent information instead intentions into is issue issues it key know knowledge large least ll long look looking looks lot make match may md members minimum more most much must new ngdoc ngdocs not number of on once one only open or other others our out outside overview paste patches people place places plunkr point possible pro problem problems_ project projects pros provide providing prs pull push pushed quality questions raising re read reasonably refer register remember report request requests requires resolve right run same save sections short should similarly single small so some source spaces squash squashing start started straight style submission submit submitting take team tell tests that the them then there these they things think this through time timer timers to tools tracker tried tutorial tutorials ui-grid unit up updates url us used using value valued ve version volunteers want watch way ways we welcomes well what where which who will with work working yet you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "099_upgrading_from_2",
    +      "shortName": "099 Upgrading",
    +      "type": "overview",
    +      "keywords": "$scope access accessible accessing adding additional adjusting again all allowing along also an and angular any api application appscope are as backward base be becomes been behaviour both btn-small but button by can cell cells celltemplate change changed changes choose class code col column columndefs columns compatible concepts configuration controller core covers default define definition defs derived directive directives directly displayname documentation each edit editbtn editing element elements enable enabled entity example faster feature features field filtering filteroptions filters for from get getcellvalue getproperty grid gridoptions gridstyle had has have having id if in include included including inclusion individual instead integrate into is isolate kept key longer majority many may meaning module modules moved multiple must mycoldefs name navigation need neither ng-click ng-grid nggrid no not now of on one only onto optionally options or overview parent per-column place possible present previously priority property provision rather refer relevant require requires resizing rewritten row scope selection separate shifted similarly single smaller some somewhat sort sorting sortoptions stored string substantial substantially supported template than that the this to tutorial type ui ui-grid ui-grid-edit ui-grid-selection update upgrade upgrading use used uses using value values ways when where whole widgets will wish with within would you your yourapplication"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "100_preReqs",
    +      "shortName": "100 Prerequisites",
    +      "type": "overview",
    +      "keywords": "_blank browsers com current href https labs list of overview prerequisites target tested tutorial"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "101_intro",
    +      "shortName": "101 Intro to UI-Grid",
    +      "type": "overview",
    +      "keywords": "$scope actually add allows an and angular angularjs app are around array as asc basic be better bulk but can carney cell cells change checking class columns com company complex comveyer contents controller convenient core cox create css custom data dependencies dependency desc designed dimensions directive directives employed enormo errors example executing expectcellvaluematch expected expectheadercellvaluematch expectheadercolumncount expectrowcount expectrowvaluesmatch extra false features filtering first firstname focused four fuelton function functions get gives googleapis grid grid1 gridtestutils have header height href html http id in index individual informative intro is it js json keeps knows label last lastname layered less lorraine main mainctrl margin module modules most mydata mygrid name nancy need next ng-controller ng-grid ngtouch no none object of on only other overview possible properties property referencing rel release rendered require row rows scenario script should small so some sorting spec specify src stack states steps style stylesheet templates than the them there this three to trace translations true tutorial two ui ui-grid uigrid use usually values var very viewport visible waters we when while width wise with write written you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "102_sorting",
    +      "shortName": "102 Sorting",
    +      "type": "overview",
    +      "keywords": "$http $scope accessing action add additive alert alert-warning alexander alisha all allows an and angular another anthony any api app application are around as asc at automatically away be behind below beryl but button by calling calls can change changed class claudine click clickcolumnmenuremovesort clickcolumnmenusortasc clickcolumnmenusortdesc clickheadercell clicking clicks col-xs-12 column columndefs columns company controller core css cycle data datachange def default defining definitions demonstrate desc describe direction disabled don edit element else enable enablesorting ethel example existing expect expectcellvaluematch expected expectheadercellvaluematch expectheadercolumncount expectvisiblecolumnmenuitems false feature female field first flag foley for from fry function gender get gets gonzales grid grid1 grid1api grid2 grid2api gridapi gridoptions1 gridoptions2 gridtestutils has have header headers height html id if in include index initial is it joyner js json key last let level live main mainctrl male menu menus module more move multiple must myers name neal need ng-click ng-controller nganimate ngtouch no not notify notifydatachange null nulls of on one onregisterapi option options order original other overview page parsons pick prevent price priority property provide rather recalculated redisplay remove removed removes removing replacing require required return reverse rice rows says scenario scenes second see set setting shift shift-click shift-clicking shiftclickheadercell should slide so sort sorted sorthandlenulls sorting sortingalgorithm sorts spec state sub-property success suppressremovesort take than that the then third this three through to toggle togglegender toggles top true tutorial twice two ui ui-grid uigridconstants undisplay unless unsorted up use user using values var velma visible want way we what when which width wilder will woods you your yvonne"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "103_filtering",
    +      "shortName": "103 Filtering",
    +      "type": "overview",
    +      "keywords": "$http $scope above accomplished actually add age alias all allows also an and angular any app are array as asterisks at attribute automatically based basic be below best bishop booleanresult box broken built-in but by can cancel cancelfilterincolumn carr cellvalue chosen class clay code column columndefs columns com comes company compare condition conditions conditon contains contents controller create css custom data def default defined defines describe digirang digits disabled do doesn each element elements email enablefiltering ends ends_with enterfilterincolumn even every everything example examples except expectcellvaluematch expectfilterboxincolumn expectheadercolumncount expectrowcount fact false field fields filter filtered filtering filters first flag following for function fuzz-match gender get gets greater greater_than grid grid1 gridoptions gridtestutils guess has hatfield have height how however html hudson id if in index indexof input inside instead introduced is it javascript js json just less less_than level logic main mainctrl makes male match matching may module more multiple mycustomsorter name ng-controller nganimate ngtouch no noterm now number object occasionally of off on one optionally options or out out-of-the-box overview own page passes phone placeholder pre-populated previous property provide provided re replace require requires return returns row rows run same scenario search see set setting setup several should show shown signature simple single six spec specifies specify still strip strippedvalue success such supported sure take term terry than that the their third this to true tutorial two ui ui-grid uigridconstants use user var variable visible want when where which width wildcard will with within xxx you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "104_i18n",
    +      "shortName": "104 i18n",
    +      "type": "overview",
    +      "keywords": "$http $scope add after allowed an and angular angular-translate another app attribute can change class co columndefs company contains controller css current currently data default description directive div does easiest enablefiltering example existing false field filter for fr function gender get getalllangs grid gridoptions grouppanel have header headers height html http i18n i18nservice in index is js json lang langs language main mainctrl menu method module more name ng-controller ng-model ng-options ngtouch nl no not note one only option or overview per provides refer rendered see service set setcurrentlang setting so stored success text than that the there to todo translate translations tutorial ui ui-grid ui-i18n ui-t use using var way width you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "105_footer",
    +      "shortName": "105 Footer",
    +      "type": "overview",
    +      "keywords": "$filter $http $scope address age agemax agemin aggregation aggregationhidelabel aggregationtype aggregationtypes also an and angular app are as avg background-color be below bound btn btn-success but can cellfilter check class col column columndef columndefs columns controller copy core count create css custom customcelltemplate data datachange date default demonstrated describe display displayed displayname displays done each enablefiltering enterfilterincolumn enum evaluate ever example expect expectfootercellvaluematch expectfootercolumncount expectheadercolumncount feature field filter filtered footer footerbutton footercell footercellfilter footercelltemplate footers footertemplate for foreach from function functions get getaggregationvalue getmaxdatestring grid grid1 gridapi gridoptions gridtestutils has have height html id if in index inject injector is it item js json label logic main mainctrl max maxdate maxdateformattedstring maxfootercell min mmm module name need ng-click ng-controller ngtouch not notifydatachange number of on onregisterapi option options or order override overview own parse pass point recalculate red refer registered require return row rows scenario selected set should show showcolumnfooter showgridfooter shown six source spec specific starting street style success sum supported supports template the then third this to todo total true tutorial ui ui-grid ui-grid-cell-contents ui-grid-footer ui-grid-selection uigridconstants use using value values var visible what which white width will wish with without you your yyyy"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "106_binding",
    +      "shortName": "106 Binding examples",
    +      "type": "overview",
    +      "keywords": "$scope access address and angular any anytime app array as ave be binding can celltemplates characters city class col coldef columndefs columns complex controller cox css custom data dove edit edited element enablecelledit enablesorting entity examples expected expectheadercellvaluematch expectheadercolumncount expectrowcount expectrowvaluesmatch field first first-name firstname for four friend friend0 friends function get getcellvalue getzip grid grid1 gridoptions gridtestutils have headers height html id in index it js laurel main mainctrl model module name need nested ng-controller ng-model ngtouch not note object one overview properties property readonly replaced require row scenario should shows spec special specified supports that the this to true tutorial two-way ui ui-grid ui-grid-edit use used value values var visible which width will with you your zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "108_hidden_grids",
    +      "shortName": "108 Hidden Grids",
    +      "type": "overview",
    +      "keywords": "$http $scope above accordion active actually add again all allowed alter always amount amounts an and angular any app appear appears appends are around as assumes at auto automatically autoresize be because becomes before behind being below best better big browser btn btn-success built but button by calculate calculates called can cannot case cause changes cheating check class clone cloned co columns common container controller created creates crippling css currently cycle data default demonstrating display displaying div do does dom don draw easier effect either element elements empty end essentially even everything example except expression extra fact fake feature figure fit fix flickering flow for fraction from function get gets give giving going good grid gridoptions grids ground-up has have height heights here hidden hide hidegrid high hold how html idea if image imagine improvement in incorrectly index initial innovation inside instead is issue it its itself jquery js json just know knows large let like linked ll load log looks main mainctrl make manifesto may means measures minimum minrowstoshow module move name need needed needs ng-click ng-controller ng-hide ng-if ng-show ngtouch no none not nothing number of offsetwidth often on once only option options or order other out outside overview page parent place please plunker port present prevent problem process property pull put putting question re really redraw removes rendered rendering representation request resize resizes result right room rows safe same scenario screen scrolling see set should show simply small smoother so some something space specific specified squished start still submit success such supply supposed tab tabset take takes tell tells that the their them then there they this through tiny to told too traversing true tutorial type ui ui-grid unexpected unrendered until up usable use user using valid value values var variable very view viewport virtualization visibility visible want way we well were what when whether which while wide width widths will with work would you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "109_multiple_grids",
    +      "shortName": "109 Multiple Grids per Page",
    +      "type": "overview",
    +      "keywords": "$http $scope all and angular app at by check class click columnmenu columns controller correct count css data element expect expectheadercolumncount four function get grid grid1 grid2 gridoptions1 gridoptions2 grids gridtestutils has have headercell height html id in index is it item items js json least list main mainctrl menu menuitems menus module multiple name ng-controller ngtouch on over overview page per repeater require row scenario should show showing single somewhere span4 spec success three tobegreaterthan tutorial ui ui-grid ui-grid-column-menu ui-grid-column-menu-button using var visible width"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "110_grid_in_modal",
    +      "shortName": "110 Grid in a Modal",
    +      "type": "overview",
    +      "keywords": "$compile $http $rootscope $scope and angular app block body btn btn-primary btn-success button buttonclose by class click close columns controller css data display element elm enersol ethel expectheadercolumncount expectrowvaluesmatch factory female function get grid grid1 gridoptions gridtestutils height hidegrid html id if in index it js json main mainctrl modal modal-body modal-content modal-dialog modal-footer modal-header modalstyle module mymodal name new ng-click ng-controller ng-style ngtouch open overview popup prepend price remove require return scenario should show showbutton showmodal some spec success three true tutorial ui ui-grid using var width with"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "111_cellClass",
    +      "shortName": "111 CellClass",
    +      "type": "overview",
    +      "keywords": "$http $scope acusage and angular app as assigned background background-color be blue by can cell cellclass check class clickheadercell col color colour colrenderindex column columndef columndefs columns company controller css data datacell describe each enablesorting equals example expect expectcellvaluematch expectheadercolumncount field first for formatted function get getcellvalue getcssvalue grid grid1 gridoptions gridtestutils has have height html id if in index is it js json longer main mainctrl module name ng-controller nganimate ngtouch no on one or override overview red require return returning rgba row rowrenderindex same scenario should shouldn so sort spec success text the this to toequal true tutorial two ui ui-grid var velity visible we which width will yellow"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "112_swapping_data",
    +      "shortName": "112 Add/Delete/Swap Data",
    +      "type": "overview",
    +      "keywords": "$scope abc acium add adddata and angular app bond brainquil btn btn-success button by can carney changes class click cline columndefs columndefs1 columndefs2 columns company comveyer controller copy cox cruz css data data1 data2 describe different element else employed enormo expectheadercolumncount expectrowcount expectrowvaluesmatch false female first firstname four fuelton function gender grid grid1 gridopts gridtestutils have height hopper html id if in index it js kongene kramer lastname length letpro lorraine main mainctrl male marcy marqet mclean misty module name nancy new ng-click ng-controller ngtouch oneill origdata1 origdata2 out overview parleynet person pickett providing push reference remove removefirstrow require reset row scenario shepherd should simply spec splice swap swapdata swapping tania the true tutorial type ui ui-grid var visible waters width wise you zamora zomboid"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "113_adding_and_removing_columns",
    +      "shortName": "113 Adding and removing columns",
    +      "type": "overview",
    +      "keywords": "$http $scope able accordingly add adding alter although an and angular api app appear appropriately are arrives be btn button button_add button_remove button_splice button_toggle_display_name button_toggle_visible button_unsplice by call can change changing class click clicking column columndefs columns company controller core css data datachange def default defs describe disappear display displayname dynamically element else enablesorting end expectheadercellvaluematch expectheadercolumncount false feature field force from function gender get grid grid1 gridapi gridoptions gridtestutils have header height html id if in index insert it js json last length-1 main mainctrl make middle module move name ng-click ng-controller nganimate ngtouch notifydatachange of on onregisterapi order other overview properties push remove removing require scenario should shown some spec splice success that the to toggle toggledisplayname togglevisible true try tutorial two ui ui-grid uigridconstants undefined unsplice update updates user var visible watches width will with you"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "114_row_header",
    +      "shortName": "114 Adding a row header",
    +      "type": "overview",
    +      "keywords": "$http $scope add adding addrowheadercolumn and angular app can celltemplate class column columndefs columns console container controller core could css data describe displayname enablesorting expectheadercolumncount expectheaderleftcolumncount field function gender get goes grid grid1 gridapi gridoptions gridtestutils have header height here html id implementations index into it js json left log main mainctrl module name ng-controller nganimate ngtouch on one onregisterapi overview own pinned require row rowheadercol rtl scenario should spec success template the true tutorial two ui ui-grid use var visible which width you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "115_headerCellClass",
    +      "shortName": "115 HeaderCellClass",
    +      "type": "overview",
    +      "keywords": "$http $scope and angular app asc assigned background background-color be blue but can cell class classes clickheadercell col color coloring colors colrenderindex column columndef columndefs columns company conditionally controller core css data datachange describe direction each enablesorting example expect expectheadercolumncount field font for foreground function get getcssvalue grid grid1 gridapi gridoptions gridtestutils have header headercell headercellclass height highlight html id if in index is it js json main mainctrl module name ng-controller nganimate ngtouch no normal notifydatachange of on onregisterapi or overview red require return returning rgba row rowrenderindex scenario set should sort sortchanged spec starts success the this to toequal true tutorial two ui ui-grid uigridconstants var visible we when width will with yellow"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "116_fonts_and_installation",
    +      "shortName": "116 Fonts and Installation",
    +      "type": "overview",
    +      "keywords": "__never__ about addresses all an and application are as assets at automatically basics be been being blocks build but buttons can character chinese chrome co come config configuration configure configuring copied copying correctly cross-domain css date defect derivative developer diagnose diagnosed different do doesn don download dropdown each end environment eot error fact files first folder font font-awesome fontello fonts for form found four from generally get getting gives goal gruntfile gulp have here how icons if in info inserted install installation instructions into is isn issue issued it itself js key last like likely ll local location look looking lot make manually many menu method misconfigured need network not now of on one or other out overview page pages pain plunkr plunkrs point points problems process questions re request requests resource see seeking seems series serve served setup should show showing similar some step still svg that the then these they this to tools try ttf tutorial typically ui-grid used user users usually various via we when where which why will with woff won work working works you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "120_RTL",
    +      "shortName": "120 RTL Support",
    +      "type": "overview",
    +      "keywords": "$http $scope angular app class columndefs company controller css data dir field field1 field10 field11 field12 field13 field14 field15 field2 field3 field4 field5 field6 field7 field8 field9 function gender get grid gridoptions height html index js json languages main mainctrl module name ng-controller ngtouch overview pinning resizecolumns rtl selection success support supports the tutorial ui ui-grid ui-grid-pinning ui-grid-resize-columns var width"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "190_large_dataset",
    +      "shortName": "190 Large Dataset",
    +      "type": "overview",
    +      "keywords": "$http $scope address again age angular app as backwards be beaverdale can city class column columndefs columns compatibility complex controller couple css cummings data dataset demonstrates describe different example expected expectheadercellvaluematch expectheadercolumncount expectrowvaluesmatch field first five following for function get glendale grid grid1 gridoptions gridtestutils have headers height html huff id in index instead it js json large length listed main mainctrl module name ng-controller ngtouch number of on overview place properties ramsey records require rows scenario set should showing spec stefanie success the this tutorial twice ui ui-grid use uses var visible width with you"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "191_horizontal_scrolling",
    +      "shortName": "191 Horizontal Scrolling",
    +      "type": "overview",
    +      "keywords": "$scope $timeout amount an and angular app cells check class col col0 col1 col2 colcount colindex columndefs columns controller couple css data demonstrating describe element enablesorting expectcellvaluematch expectheadercellvaluematch first floor for function get grid grid1 gridoptions gridtestutils has headers height horizontal how html id index it js large length main mainctrl make math module name ng-controller ngtouch number of out overview protractor push r0c0 r0c1 r1c0 r1c1 r2c0 random rendered require right row rowcount rowindex scenario scroll scrolling spec still sure to true tutorial ui ui-grid var width widths with working"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "200_features",
    +      "shortName": "200 Features",
    +      "type": "overview",
    +      "keywords": "allows alongside also an and angular application are as be certain class complex contains core dependency directive each enable feature feature1 feature2 features for grid gridoptions grids have in include included instance into many module modules more must needed only overview separated the this to tutorial ui ui-grid ui-grid-feature1 ui-grid-feature2 you your yourapp"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "201_editable",
    +      "shortName": "201 Edit Feature",
    +      "type": "overview",
    +      "keywords": "$apply $http $scope __columndef _note about active address addressformatter adjusted aftercelledit age all allow allowing allows also alternative although an and angular angular-bootstrap angular-translate any app apply array arrows as available aware backing bar be begin_cell_edit boolean bootstrap box browser browsers but by called can cancel_cell_edit cat cell celleditablecondition cellfilter cellnav cellscope changed checkbox city class code coldef column columndef columndefs columns compatible compiled contain content contents controller controls css custom data datatype date datepicker default definitions depend determine directive directives disable displayname does dog don double-click dropdown edit editable editablecelltemplate editdropdownfilter editdropdownidlabel editdropdownoptionsarray editdropdownrowentityoptionsarraypath editdropdownvaluelabel edited editing editor editors element else enable enablecelledit enablecelleditonfocus enabled end_cell_edit ends enter entity esc events example f2 false feature female field fields fields_ filter fish focus following foo for function functionality gender genderhash get grid gridapi gridoptions hamster happens has having height html html5 id ideal if implement implements in include including index inline input instead intent invoke invoked is isactive isn it itself js json key label labels lastcelledited left length likely logic main mainctrl male mapgender medium mode module msg must name native need needs new newvalue next ng-controller ngtouch non-navigable not note number numeric object of oldvalue on only onregisterapi option options options__ or other overview pet picker point populated property provide provided purposes registered reprocess respectively return returns right roadmap row rowentity rowrenderindex rows scope set setting should similar simple so some soon sorting specified start state street string success tab tags templatecache templates term text than that the them then there these this those through to translate true tutorial two type types typing ui ui-grid ui-grid-edit uigrideditor url use used uses using valid value values var variable via way were when which widgets width will with within without won would xxx xxxxxxx you your yyyy-mm-dd zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "202_cellnav",
    +      "shortName": "202 Cell Navigation",
    +      "type": "overview",
    +      "keywords": "$http $log $scope add address age allowcellfocus allowing allows an and angular api app around arrow back balance be btn btn-success button callback cell cellnav cells city class click col coldef colindex column columndefs combined company continue controller css current currentfocused currentselection data deep directive displayname down edit editable editing element email enable enter entity event example extract false feature focus focusable focused for function get getcurrentfocus getcurrentselection getfocusedcell grid gridapi gridoptions guid height here html id if in include index info is js json key keys left left-right length log main mainctrl margin-top mode modifierkeystomultiselectcells module move msg must name navigate navigated navigation new newrowcol ng-bind ng-click ng-controller ng-model ngtouch null of old oldrowcol on on_cellnav onregisterapi option or overview page pg-down pg-up phone pinning placeholder position print printselection programatically provides push re register remembering requesting returns right row rowcol rowindex scroll scrolling scrollto scrolltofocus selected selection setting shift-enter shift-tab specific state subsumed success tab text that the this to tojson tostring true tutorial type ui ui-grid ui-grid-cellnav ui-grid-pinning up useful user uses using utilizing values var when width will with within you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "203_pinning",
    +      "shortName": "203 Pinning",
    +      "type": "overview",
    +      "keywords": "$http $log $scope about address age allows also and angular app below city class column columndefs company controller css data definition directive disable displayname element email enable enablepinning example feature friend friends function get grid gridoptions height html id in include index is it js json left level main mainctrl module must name ng-controller ngtouch note on or overview phone pin pinnedleft pinnedright pinning possible right state street success the to tutorial ui ui-grid ui-grid-pinning user var width you your zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "204_column_resizing",
    +      "shortName": "204 Column Resizing",
    +      "type": "overview",
    +      "keywords": "$http $scope according allow allows and angular any app be but by can class coldef column columndefs columns company constraints contents controller css data definition directive disable each element enable enablecolumnresizing enablesorting entire explicitly false feature field for function gender get give grid gridoptions height html if in include index individual it its js json main mainctrl maxwidth minwidth module movecolumns must name ng-controller ngtouch not obey of on option options or overview prevents property reason regardless rendered resize resizecolumns resized resizing separator set setting size some success the this to true tutorial ui ui-grid ui-grid-move-columns ui-grid-resize-columns use var want width will you your yourapp"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "205_row_editable",
    +      "shortName": "205 Row Edit Feature",
    +      "type": "overview",
    +      "keywords": "$http $interval $q $resource $scope active address addressformatter after aftercelledit again age all almost also an and angular another any app application are array as at attempts avoid back basic be because been before boolean but button by callback callbacks called calling can causing cell celleditablecondition cellfilter cellnav city class clean clicks columndefs columns commences complete completing configurable controller controls create css currently data date deals defer delay destroyed dirty displayed displayname doesn during each easily edit editable edited editing edits either else enablecelledit enabled error errored errors event example exceptions experience extends extent fake faked false feature field fields filter flag flushdirtyrows flushes for four from function gender generate get getdirtyrows geterrorrows give go grey greyed grid gridapi gridoptions gridrows has hasn have height how html id if in index input invisible is isactive isdirty iserror issaving js json last length local locking long made main mainctrl male manually method methods might module more moving ms must name navigation never new ng-controller ngtouch no non-editable normally not number object occassionally occurs of off on one only onregisterapi operate operation option optionally or other otherwise out overview page perspective point pressing promise properties provided ready red regime registered reject rejected request resolve resolved return returned returns row rowedit roweditwaitinterval rowentity rowrenderindex rows same save saved saverow saves savetimer saving scope seconds seek server set setfocus setsavepromise shown similar since situations so some spreadsheet state states status still street success successfully sufficient support tabs take that the then they this time timeout timer to trigger triggered tutorial type ui ui-grid ui-grid-cellnav ui-grid-edit ui-grid-row-edit updated upon use used user using var wait were when whenever where which whichever whilst width will wish with within yet you yyyy-mm-dd zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "206_exporting_data",
    +      "shortName": "206 Exporting Data With Native UI",
    +      "type": "overview",
    +      "keywords": "$http $scope adds all allows and angular api app as at available be bold both bower buttons can class color columndefs company controller css csv currentpage custom-csv-link-location data directive docdefinition element enable enablegridmenu enableselectall example export exported exporter exportercsvfilename exportercsvlinkelement exporterpdfcustomformatter exporterpdfdefaultstyle exporterpdffooter exporterpdfheader exporterpdfmaxgridwidth exporterpdforientation exporterpdfpagesize exporterpdftableheaderstyle exporterpdftablestyle exporting false feature field fontsize footerstyle for format found from function gender get grid gridapi gridoption gridoptions have header headerstyle height html if in include index install installed is italics items js json letter main mainctrl menu module must my myfile name native need ng-controller nganimate ngtouch note of on only onregisterapi option options or overview pagecount pdf pdfmake portrait queryselectorall red return rows selected selection show style styles success text that the this through to tostring true tutorial ui ui-grid ui-grid-exporter ui-grid-selection use using var visible want we width with you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "207_importing_data",
    +      "shortName": "207 Importing Data With Native UI",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope $translate ability accept adding adds allows also an and angular angular-translate api app are array as assumed at attributes auto-populate be been bower by called can cellheaderfilter class column columndefs columns com company concat configure controller copy could created css csv csv-js custom data define defs demand detect_types directive displayname documentation doe doing each either elements empty enable enablegridmenu entity example exists extended false fasttruck fasttrucks feature female field file files filter for format formats found from front function gender globals grid gridapi gridoption gridoptions has have headers heading headings height html if illustrates immediate implement implemented import imported importer importerdataaddcallback importerheaderfiltercallback importerobjectcallback importershowmenu importing imports in include index information install installed instant instead internationalisation into is it items jane john js json library loaded main mainctrl male mandatory many mapped maps match menu module more must name native need needing newobjects ng-controller nganimate ngtouch not objects of off on once onregisterapi optionally options or other overview pass picker promise provide provided received refer return routine row setting smith so start system test testicon text that the then this through to translated translation true try turn tutorial type ui ui-grid ui-grid-importer up use used user uses using var via we width will with within would you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "208_save_state",
    +      "shortName": "208 Saving and restoring the state of the grid",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope adjust alexander all allows also an and angular another app application apply are as back btn btn-success button by calling can cancelfilterincolumn cell cellnav class click clickcolumnmenuhide clickcolumnmenuremovesort clickcolumnmenusortasc column columndefs columns company control controller cookie core css current data database default deliberately describe did different element enablefiltering enterfilterincolumn ethel example expect expectcellvaluematch expectheadercellvaluematch expectheadercolumncount false feature female filter filters first foley for freda function functionality gee gender get grid grid1 gridapi gridoptions gridtestutils had have height held hide html id in index information into is isn it js json layout left like look main mainctrl mason may methods might modify module movecolumns must name navigate ng-click ng-controller nganimate ngtouch nor note object of onregisterapi options order out overview packages page permits price provide provides remove render reorder require resizecolumns responsible restore restorestate restoring returning returns save saved savefilter savefocus saveorder savescroll savesort savestate savevisible savewidths saving scenario select selection session set sets some something somewhere sort sorts spec specific state store stored stores storing success takes that the their them then there they this time to transient true tutorial two type ui ui-grid ui-grid-cellnav ui-grid-move-columns ui-grid-resize-columns ui-grid-save-state ui-grid-selection upon use user var was way we what when where which width widths wish with you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "210_selection",
    +      "shortName": "210 Selection",
    +      "type": "overview",
    +      "keywords": "$http $interval $log $scope add added additional address after age all allow allowcellfocus allowing allows always an and angular another api app are at batch be been box btn btn-success but button by call callback can cannot cause changed changes check checkboxes city class clearall clearselectedrows click clicking client cmd-key column columndefs console controller core could css ctrl-key current currently data datachange default demonstrates different digest directive disabled displayname divide does doing dynamically element enable enablerowheaderselection enablerowselection enableselectall enableselectionbatchevent event events example examples false feature first focusable for function gave get getselectallstate grid grid1 gridapi gridoption gridoptions has have header height hidden html id if in include index individual individually info instead into is isselected it javascript js json just least length log looking loop main mainctrl manually may mean means modifierkeystomultiselect module msg multi-select multiple multiselect must name necessary need new ng-bind ng-click ng-controller ng-disabled ngtouch not note notifydatachange nounselect of off on one only onregisterapi open option options or other overview page processing programatically provide provided rather re register result row rowheader rowheaderselection rowheight rows rowselection rowselectionchanged rowselectionchangedbatch scope second secondctrl see select selectall selectallrows selectallvisiblerows selected selecting selection selectionrowheaderwidth selectrow server set setmodifierkeystomultiselect setmultiselect setting shift-key showgridfooter shown side single so success than that the them then there this ticked time to toggled togglemodifierkeystomultiselect togglemultiselect togglerow1 togglerowselection top true tutorial two type ui ui-grid ui-grid-selection uigridconstants unselect upon used useful uses using var visible wait watch we when which whilst width will with without you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "211_two_grids",
    +      "shortName": "211 Two grids on a page",
    +      "type": "overview",
    +      "keywords": "$http $log $scope an and angular app are btn btn-success button cellnav check class colindex columndefs controller correct css data demonstrates describe display each element example expectheadercolumncount first firstgrid from function get grid gridapi gridoptions grids gridtestutils has height how html id index isolated it js json main mainctrl menus module name ng-click ng-controller ngtouch on onregisterapi other out over overview page protractor puts rendered require row rowindex same scenario scroll scrollto second secondctrl secondgrid selection spec still success that the they this to tutorial two type ui ui-grid ui-grid-cellnav ui-grid-selection var width working"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "212_infinite_scroll",
    +      "shortName": "212 Infinite scroll",
    +      "type": "overview",
    +      "keywords": "$http $log $scope age allows angular app at by class columndefs concat controller controls css data dataloaded error feature for function get getdata getdataup grid gridapi gridoptions height html id index infinite infinitescroll infinitescrollpercentage is js json lazy length load main mainctrl module more name needloadmoredata needloadmoredatatop ng-controller ngtouch of on onregisterapi overview page pageup percentage property push requested res return reverse scroll setting should specify success the their this to trigger tutorial ui ui-grid ui-grid-infinite-scroll user var what when width"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "213_auto_resizing",
    +      "shortName": "213 Auto-Resizing",
    +      "type": "overview",
    +      "keywords": "$http $log $scope about add adding address affect age and angular app application auto-resize auto-resizing autoresize btn btn-success button by changed changes checker city class columndefs company container controller could css data dependencies directive displayname element email enable feature floor friend friends function get getelementsbyclassname grid gridoptions has height html id if in include index interval it its itself js json main mainctrl math module name negatively newheight newwidth ng-click ng-controller ngtouch of on or overview performance phone pinnedleft pinnedright potentially px random randomsize resize sees site size state street success that the this to tutorial type ui ui-grid ui-grid-auto-resize use var when width will works your zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "214_pagination",
    +      "shortName": "214 Pagination",
    +      "type": "overview",
    +      "keywords": "$http $scope angular api app be browsed btn btn-success built button can class columndefs company controlled controller controls css data displayed enabled enablepaginationcontrols false function gender get getpage gettotalpages go grid gridapi gridapi2 gridoptions1 gridoptions2 html in index is js json main mainctrl module name native next nextpage ng-click ng-controller ngtouch of onregisterapi overview page pages pagination paginationpagesize paginationpagesizes previous previouspage seek selector success that the to tutorial type ui ui-grid ui-grid-pagination using var via when width with"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "301_custom_row_template",
    +      "shortName": "301 Custom Row Template",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope $timeout access almost angular app appscope aquamarine are as background-color basic but by can cancel class col colcontainer coldef console controller create css custom data date details done elements fnone for from function functions get grid gridoptions height html in index js json log main mainctrl module more most name new ng-bind ng-click ng-controller ng-repeat ngtouch on one outside overview parseint renderedcolumns return row rowtemplate same scope scopes sec start style success template the to track tutorial ui ui-grid ui-grid-cell use var wait waiting width with you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "301_editableOnFocus",
    +      "shortName": "301 Edit On Focus",
    +      "type": "overview",
    +      "keywords": "$http $scope address age and angular api app be btn btn-success button can cell cellnav city class col coldef columndefs combine controller css current currentfocused data default displayname docs edit editing enable enablecelledit enablecelleditonfocus entity false focus focused for function get getcurrentfocus getfocusedcell gets grid gridapi gridoptions height how html id if index js json keys main mainctrl module must name navigation ng-bind ng-click ng-controller ngtouch null on onregisterapi options override overview row rowcol see set success the to true tutorial type ui ui-grid ui-grid-cellnav ui-grid-edit var when width with you"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "302_custom_header",
    +      "shortName": "302 Custom Header",
    +      "type": "overview",
    +      "keywords": "$http $scope almost am angular app as basic bob but center ceo class controller create css custom data developer frank function grid gridoptions header header-template headertemplate height html index js lowly main mainctrl module most name ng-controller ngtouch one overview same style text-align the title tutorial ui ui-grid ui-grid-top-panel var width with"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "303_customizing_column_menu",
    +      "shortName": "303 Customizing Column Menu",
    +      "type": "overview",
    +      "keywords": "$http $scope ability accessible action actions active add added alert all alongside also an and angular app as asc available based be being below between blargh browser builder but button by called can class click clicked clickheadercell col column columndef columndefs columnmenu columns company conditions context contexts controller could count css custom customize customizing data default definition desc describe determines direction disable display displayed displayname each effect element enablecolumnmenu enablecolumnmenus enablehiding enablesorting entirely every example expect expectcellvaluematch expectheadercolumncount expectvisiblecolumnmenuitems false female field finished first for from function functionality gender get grid grid1 gridcolumn gridmenu gridmenutitlefilter gridoptions gridtestutils have header headercell height hidden hide highlights html i18n icon id implying in including index is isdisplayed it item items js json just left like long long-press main mainctrl male menu menuitems menus merged module mousedown name ng-controller nganimate ngtouch no not null object on opens option or outer overview own pass perform press prevent property protractor provide reference remove require return rotates scenario scope second see setting should show shown sleep some sort spec success supply supplying suppressed suppressremovesort test that the then third this three through title to toequal toggle too true tutorial type ui ui-grid ui-grid-column-menu ui-grid-column-menu-button ui-grid-icon-info-circled ui-grid-menu-inner uigridconstants usage use user using var via visible when whether which width will with work would you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "304_grid_menu",
    +      "shortName": "304 Grid Menu",
    +      "type": "overview",
    +      "keywords": "$http $interval $q $scope ability above absolute access accessible action actions active added additional adds addtogridmenu allow alongside also an and angular app are as at available be below box-shadow but by called can changed changedcolumn class clicked clickgridmenuitem col coldef column columnchanged columndef columndefs columns columnvisibilitychanged company company_hide company_show context contexts controller core create css csv custom customised customize data default defer deferred defined describe determines directive display displayed dynamic each effect either element enabled enablegridmenu enablehiding example expectheadercellvaluematch expectheadercolumncount expectvisiblegridmenuitems export exporter exportermenucsv fake fakei18n false feature filter floats for function functionality gender get gives grid grid1 gridapi gridmenucustomitems gridmenushowhidecolumns gridmenutitlefilter gridoption gridoptions gridtestutils have header headers height hidden hide highlights html i18n i18nservice icon id if in index individual initialized internationalization internationalized interval is it item items js json just least like main mainctrl menu menus module my-custom-menu name needs ng-controller ng-if ngtouch none not of on one only onregisterapi option or overview own padding pass position prefixes promise property provide reference require resolve return right rotate rotated row rows scenario second see selected selection set setting settings should show shown some sort spec string success supplying suppress suppresses that the them then there this three through title titles to toggle toggleclass top transform translate true tutorial type ui ui-grid ui-grid-exporter ui-grid-menu ui-grid-menu-inner ui-grid-selection use used using var visibility visible waits want we when whether which width will with you your zero"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "305_appScope",
    +      "shortName": "305 Accessing Scope in templates",
    +      "type": "overview",
    +      "keywords": "$http $log $parent $scope abc access accessing alert all angular another app application appscope appscopeprovider assigned assignment available be btn by can carney cell celltemplate class columndefs company comveyer controller cox css data default element employed enormo false firstname from fuelton function gender get grid gridoptions height html if in index is isolate js json lastname lorraine main mainctrl me module name named nancy need ng-click ng-controller ngtouch no of on or other override overview parent primary property reference row scope showme showscope so someotherreference someprop success template templates than that the then there this to true tutorial ui ui-grid use uses using var variables waters width will wise wish you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "306_expandable_grid",
    +      "shortName": "306 Expandable grid",
    +      "type": "overview",
    +      "keywords": "$http $log $scope access added address adds age all and angular api app as available be btn btn-small button can checkboxes city class collapse collapseallrows columndefs company control-group controller css data done each enablerowselection entity events expand expandable expandablerowheight expandablerowscope expandablerowtemplate expandablescope expandallrows expanded expanding feature field fired following for fos friends from function gender get grid gridapi gridoptions height html id if in index is isexpanded its js json left length levels main mainctrl methods module multiple name need nesting ng-click ng-controller ngtouch object of on onregisterapi option overview pinnedleft pinning pins provide provided render retrieve row rowexpandabletemplate rowexpandedstatechanged rows scope secondctrl selection show style subgrid subgridoptions subgrids subgridscopevariable subgridvariable success template that the then these thirdctrl to true tutorial type ui ui-grid ui-grid-expandable ui-grid-pinning ui-grid-selection upto used value var variables when width will with works you"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "307_external_sorting",
    +      "shortName": "307 External Sorting",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope above achieve after allow an and angular app are as asc atkinson be being beryl bored break bruce by can case changed class claudine clickheadercell clicking client column columndefs columns company controller core css custom data default desc describe direction disabled editing effect either else emulate enablesorting ethel even event example expectcellvaluematch expected expectheadercellvaluematch expectheadercolumncount external externally false files first firstly function functions further gender get gonzales got grid grid1 gridapi gridoptions gridtestutils has have header height however html id if ignored ignores illustrate in index indicator internal is it js json last length main mainctrl manually me module name native neal ng-controller ngtouch no not of off on one onregisterapi or original our over overview part picking price priority property provides removed requested require retrieve return reverse rice routine routines rows scenario second secondly server should show so sometimes sort sortchanged sortcolumns sorted sorting spec strong success support suppress switch tells that the their this those three to true turn tutorial two ui ui-grid uigridconstants undefined unsorted useexternalsorting user using valarie values var visible want we when width wilder with you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "308_external_filtering",
    +      "shortName": "308 External Filtering",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope after all an and angular app as bored by changed class client columndefs columns company controller core css custom data deleted editing either else emulate enablefiltering event example external externally false female file files filter filterchanged filtered filtering filters first firstly function functions further gender get got grid gridapi gridoptions has height html if illustrate in index internal is js json main mainctrl male manually me module name native ng-controller ngtouch not of off on one onregisterapi or other overview part picking property provides requested retrieve routine routines rows secondly server show so sometimes sorted sorting success support suppress tells term that the their this three to true turn tutorial two ui ui-grid uigridconstants useexternalfiltering user using var want we when width you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "309_editable_with_cellnav",
    +      "shortName": "309 Edit Feature With Cellnav",
    +      "type": "overview",
    +      "keywords": "$apply $http $scope active address addressformatter aftercelledit age an and angular app basics boolean cell celleditablecondition cellfilter cellnav city class coldef column columndefs combining controller css data date displayname dropdown edit editable editdropdownoptionsarray editdropdownvaluelabel edited editing edittype else enablecelledit enablecelleditonfocus example experience false feature female filter for function gender genderhash get give grid gridapi gridoptions height html id if index input isactive js json lastcelledited length main mainctrl male mapgender module more msg name new newvalue ng-controller ngtouch number object of oldvalue on onregisterapi overview provides refer registered return row rowentity rowrenderindex rows scope spreadsheet-like state street success the this to true tutorial type ui ui-grid ui-grid-cellnav ui-grid-edit var width with yyyy-mm-dd zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "310_column_moving",
    +      "shortName": "310 Column Moving",
    +      "type": "overview",
    +      "keywords": "$http $scope age all allows also alternatively and angular app be by can class colmovable column columndefs columns controller css data default definitions different directive disable dragging dropping either element email enable enablecolumnmoving enabled feature for from function gender get grid gridapi gridoptions height html id in include index it js json leftmost main mainctrl method module move movecolumn movecolumns moving must name newposition ng-controller ngtouch number of on options or overview position property ranging repositioned rightmost specific specifically success the them to tutorial ui ui-grid ui-grid-move-columns up used var visible width will you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "311_importing_data_with_rowedit",
    +      "shortName": "311 Importing Data With Row Edit",
    +      "type": "overview",
    +      "keywords": "$http $interval $q $resource $scope accept accepted addeventlistener allow allows also an and angular any app are as at auto-save automatically be before by call can cannot change choosers class company concat consider console continue controller create created css csv custom data defer delay document doe edit edited else enablegridmenu end error errors event example fake false fasttruck fasttrucks feature female file file-chooser filechooser fileobject files flushdirtyrows for form format found from function gender give google grid gridapi gridoptions handlefileselect has height html id if implemented import imported importer importerdataaddcallback importfile importing in index into is item jane john js json kick length log look made main mainctrl male manually menu module name native newobjects ng-controller nganimate ngtouch normally not occurs of off on once onregisterapi or overview picker promise queryselectorall records reject request require reset resolve return returned row rowedit roweditwaitinterval rowentity rows save saverow saves seconds server setsavepromise setting show smith srcelement suppress target testicon that the they this to todo together trigger true tutorial type ui ui-grid ui-grid-edit ui-grid-importer ui-grid-row-edit use user validation var want we well were which whilst why width will with within without work you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "312_exporting_data_complex",
    +      "shortName": "312 Exporting Data With Custom UI",
    +      "type": "overview",
    +      "keywords": "$http $scope align all allows also and angular api app apply as at available be below bold bower break calling can case cellfilter class coded col color column columndefs columns company controller css csv csvexport custom custom-csv-link-location data decode default different directive displayname element else example export export_column_type export_format export_row_type exported exporter exporterfieldcallback exporterheaderfilter exporterlinklabel exporterpdfalign exporterpdfdefaultstyle exporterpdfmaxgridwidth exporterpdforientation exporterpdfpagesize exporterpdftableheaderstyle exporterpdftablestyle exporting false feature female field filter for foreach format found from function gender get grid gridapi gridoptions have headers height here html if in include index input install installed internationalisation italics js json layout letter like main mainctrl male mapgender module must myelement name need ng-click ng-controller ng-model nganimate ngtouch on onregisterapi options or overview pdf pdfexport pdfmake person portrait provide queryselectorall red reprocess return right row rows selected selection should show styles success switch tailor than the this through to true tutorial ui ui-grid ui-grid-exporter ui-grid-exporter-csv-link ui-grid-selection unknown use value var visible want we width will with would you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "313_custom_interpolation_symbols",
    +      "shortName": "313 Custom Interpolation Symbols",
    +      "type": "overview",
    +      "keywords": "$http $interpolate $interpolateprovider $scope and angular angularjs any app application automatically break change changing class columndefs combining company config controller css custom custom-interpolation-symbol data default detect else enablesorting endsym endsymbol event expecting false field foo for frameworks function gender get grid gridoptions height html in index inside interpolation it js json like likely main mainctrl means module name ng-controller nganimate ngtouch normal or other overview re requires signify something sometimes startsym startsymbol stuff success symbols templates that the then this to transform true tutorial ui ui-grid unlikely use uses values var whoohoo width will with you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "314_external_pagination",
    +      "shortName": "314 External Pagination",
    +      "type": "overview",
    +      "keywords": "$http $scope able above all allow also and angular any app application asc be break browsed built calculate call callback called can case class client client-side code columndefs combined company contain containing controller core correct count css data default desc direction displayed else enabled enablesorting entire exist external false fetch fetched firstrow for from function gender get getpage grid gridapi gridoptions have html if implement in index information is it js json length main mainctrl may mentioned module name newpage ng-controller ngtouch not null number of on onregisterapi other overview pagenumber pages pagesize pagination paginationchanged paginationoptions paginationpagesize paginationpagesizes parameters query requires rest retrieve rows selector server server-side set should shows since slice sort sortchanged sortcolumns sorting specific state subset success sufficient switch that the they this to total totalitems true tutorial ui ui-grid ui-grid-pagination uigridconstants update url used useexternalpagination useexternalsorting using utilize var variable variables were when width will with within your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "315_editable_cascading_dropdown",
    +      "shortName": "315 Edit Feature With Cascading Dropdowns",
    +      "type": "overview",
    +      "keywords": "$http $scope aftercelledit and angular app array build cascading cell cellfilter class clothes code coded coldef columndefs company controller css data default depend displayname dropdown dropdowns edit editablecelltemplate editdropdownoptionsarray editdropdownrowentityoptionsarraypath editdropdownvaluelabel edited else feature female femalesizedropdownoptions filter first floor for function gender genderhash get give grid gridapi gridoptions height html id if in index is it js json lastcelledited length main mainctrl male malesizedropdownoptions mapgender mapsize massage math module name newvalue ng-controller ngtouch number oldvalue on onregisterapi options overview possible random return rowentity sample scope second selection setup size sizehash sizeoptions sm success thanks the to tutorial ui ui-grid ui-grid-edit us use var where width with xl xxl"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "316_dynamic_data_changes",
    +      "shortName": "316 Dynamic Data Changes and Watchers",
    +      "type": "overview",
    +      "keywords": "actually adding aim aims all amount and angularjs anything approach approaches appropriate are aren as automatically avoid be because been being binding calculated call called calls can cell cellclasses cells change changed changes changing columns content cycle data development different digest doesn don dynamic each edited elements evaluated event every examples expect explicitly fake first for found frequent full general gitter grid has have if illusion improve in includes instances intended is it large length like ll looks made main maintain manual manually missing more need needed needs notifydatachange number numbers occurs of on once only other overview performance place plus properties quickly rather recalculated reduce referred removing render rendered rendering row rows rowtemplates scroll scrollbar scrolling see seeks set so some such takes tell than that the there therefore they this those times to tutorial tutorials two ui-grid unworkable updated updates upshot via virtualisation visibility visible watchers watches way we were when whenever work would you your"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "401_AllFeatures",
    +      "shortName": "401 All Features",
    +      "type": "overview",
    +      "keywords": "$http $interval $scope $timeout about address age agetemplate aggregationtype aggregationtypes all also an angular app appends are avg btn btn-success button by callspending callspending-- cancel cellnav celltemplate city class click column columndefs company controller css data date describe displayname duplicate edit element email emulates enablecelledit enablecolumnresizing enabled enablefiltering enablegridmenu error every example expectvisiblecolumnmenuitems features field for foreach friend friends from function get getrowidentity grid grid1 gridoptions gridtestutils height html id idea index it iter js json left length loading main mainctrl menu module movecolumns mydata name new ng-bind ng-click ng-controller ngtouch not object of on options overview pages pending performance phone pinning push refreshbutton refreshdata require resizecolumns resizeheadercell resizing return row rowidentity rows scenario scope sec seconds selection server setting should showcolumnfooter showgridfooter spec specifies start state street string success that the this to true tutorial type ui ui-grid ui-grid-cell-contents ui-grid-cellnav ui-grid-edit ui-grid-move-columns ui-grid-pinning ui-grid-resize-columns ui-grid-selection uigridconstants value var watch when width with your zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "402_GridIsScrolling",
    +      "shortName": "402 Grid Scrolling",
    +      "type": "overview",
    +      "keywords": "$http $scope about address age agetemplate angular app can celltemplate city class columndefs company controller css data displayname email enablecelledit event field friend friends function get grid gridapi gridoptions height horizontally html id if in index is isscrollinghorizontally isscrollingvertically js json main mainctrl module name ng-controller ngtouch onregisterapi overview phone property reference scroll scrolling see state street success to true tutorial ui ui-grid ui-grid-cell-contents var vertically width you zip"
    +    },
    +    {
    +      "section": "tutorial",
    +      "id": "403_end_to_end_testing",
    +      "shortName": "403 End to End Testing",
    +      "type": "overview",
    +      "keywords": "abstracts and api are as assist at available be can cell check checking clicking com complex could counting declaring documentation e2e e2etestlibrary each elements end expectrowcount file folder for functions get git github grid gridtest gridtestutil gridtestutils held helper https in involves is it itself js key latest library methods mygrid of or order out overview potential project protractor provided provides refer require requires rows scenario some specific specified such synch test testing tests that the then there therefore this to top tutorial use value var version with within worthwhile you your"
    +    }
    +  ],
    +  "apis": {
    +    "api": true,
    +    "tutorial": false
    +  },
    +  "html5Mode": false,
    +  "startPage": "/api",
    +  "scripts": [
    +    "angular.js",
    +    "angular-touch.js",
    +    "angular-animate.js",
    +    "csv.js",
    +    "pdfmake.js",
    +    "vfs_fonts.js"
    +  ]
    +}; VERSIONED_FILES={
    +  "default": "unstable",
    +  "waitEval": "(function() { var ret = true; try { angular.module('ui.grid'); } catch (e) { ret = false; } return ret; })()",
    +  "versions": {
    +    "stable": [
    +      {
    +        "src": "/release/ui-grid.js",
    +        "type": "script"
    +      },
    +      {
    +        "src": "/release/ui-grid.css",
    +        "type": "css"
    +      }
    +    ],
    +    "unstable": [
    +      {
    +        "src": "/release/ui-grid-unstable.js",
    +        "type": "script"
    +      },
    +      {
    +        "src": "/release/ui-grid-unstable.css",
    +        "type": "css"
    +      }
    +    ]
    +  }
    +}; 
    \ No newline at end of file
    diff --git a/docs/js/docs.js b/docs/js/docs.js
    new file mode 100644
    index 000000000..714d46c5b
    --- /dev/null
    +++ b/docs/js/docs.js
    @@ -0,0 +1,651 @@
    +var docsApp = {
    +  controller: {},
    +  directive: {},
    +  serviceFactory: {}
    +};
    +
    +docsApp.directive.ngHtmlWrapLoaded = function(reindentCode, templateMerge, loadedUrls) {
    +  function escape(text) {
    +    return text.
    +      replace(/\&/g, '&amp;').
    +      replace(/\</g, '&lt;').
    +      replace(/\>/g, '&gt;').
    +      replace(/"/g, '&quot;');
    +  }
    +
    +  function setHtmlIe8SafeWay(element, html) {
    +    var newElement = angular.element('<pre>' + html + '</pre>');
    +
    +    element.html('');
    +    element.append(newElement.contents());
    +    return element;
    +  }
    +
    +  return {
    +    compile: function(element, attr) {
    +      var properties = {
    +            head: '',
    +            module: '',
    +            body: element.text()
    +          },
    +        html = "<!doctype html>\n<html ng-app{{module}}>\n  <head>\n{{head:4}}  </head>\n  <body>\n{{body:4}}  </body>\n</html>";
    +
    +      angular.forEach(loadedUrls.base, function(dep) {
    +        properties.head += '<script src="' + dep + '"></script>\n';
    +      });
    +
    +      angular.forEach((attr.ngHtmlWrapLoaded || '').split(' '), function(dep) {
    +        if (!dep) return;
    +        var ext = dep.split(/\./).pop();
    +
    +        if (ext == 'css') {
    +          properties.head += '<link rel="stylesheet" href="' + dep + '" type="text/css">\n';
    +        } else if(ext == 'js' && dep !== 'angular.js') {
    +          properties.head += '<script src="' + (loadedUrls[dep] || dep) + '"></script>\n';
    +        } else if (dep !== 'angular.js') {
    +          properties.module = '="' + dep + '"';
    +        }
    +      });
    +
    +      setHtmlIe8SafeWay(element, escape(templateMerge(html, properties)));
    +    }
    +  };
    +};
    +
    +
    +docsApp.directive.focused = function($timeout) {
    +  return function(scope, element, attrs) {
    +    element[0].focus();
    +    element.bind('focus', function() {
    +      scope.$apply(attrs.focused + '=true');
    +    });
    +    element.bind('blur', function() {
    +      // have to use $timeout, so that we close the drop-down after the user clicks,
    +      // otherwise when the user clicks we process the closing before we process the click.
    +      $timeout(function() {
    +        scope.$eval(attrs.focused + '=false');
    +      });
    +    });
    +    scope.$eval(attrs.focused + '=true');
    +  };
    +};
    +
    +
    +docsApp.directive.code = function() {
    +  return { restrict:'E', terminal: true };
    +};
    +
    +
    +docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
    +  return {
    +    template: '<div class="btn-group pull-right">' +
    +        '<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
    +        '  <i class="icon-pencil icon-white"></i> Edit <span class="caret"></span>' +
    +        '</a>' +
    +        '<ul class="dropdown-menu">' +
    +        '  <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
    +        '  <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
    +        '</ul>' +
    +        '</div>',
    +    scope: true,
    +    controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
    +      var sources = {
    +        module: $attrs.sourceEdit,
    +        deps: read($attrs.sourceEditDeps),
    +        html: read($attrs.sourceEditHtml),
    +        css: read($attrs.sourceEditCss),
    +        js: read($attrs.sourceEditJs),
    +        unit: read($attrs.sourceEditUnit),
    +        scenario: read($attrs.sourceEditScenario)
    +      };
    +      $scope.fiddle = function(e) {
    +        e.stopPropagation();
    +        openJsFiddle(sources);
    +      };
    +      $scope.plunkr = function(e) {
    +        e.stopPropagation();
    +        openPlunkr(sources);
    +      };
    +    }
    +  };
    +
    +  function read(text) {
    +    var files = [];
    +    angular.forEach(text ? text.split(' ') : [], function(refId) {
    +      // refId is index.html-343, so we need to strip the unique ID when exporting the name
    +      files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
    +    });
    +    return files;
    +  }
    +};
    +
    +
    +docsApp.serviceFactory.loadedUrls = function($document, versionedFiles) {
    +  var urls = {};
    +
    +  angular.forEach($document.find('script'), function(script) {
    +    var match = script.src.match(/^.*\/([^\/]*\.js)$/);
    +    if (match) {
    +      urls[match[1].replace(/(\-\d.*)?(\.min)?\.js$/, '.js')] = match[0];
    +    }
    +  });
    +
    +  urls.base = [];
    +  angular.forEach(NG_DOCS.scripts, function(script) {
    +    var match = urls[script.replace(/(\-\d.*)?(\.min)?\.js$/, '.js')];
    +    if (match) {
    +      urls.base.push(match);
    +    }
    +  });
    +
    +  angular.forEach(versionedFiles.files, function(file) {
    +    urls.base.push(file.src);
    +  });
    +
    +  return urls;
    +};
    +
    +docsApp.serviceFactory.versionedFiles = function() {
    +  return {
    +    files: []
    +  };
    +};
    +
    +docsApp.serviceFactory.formPostData = function($document) {
    +  return function(url, fields) {
    +    var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="_blank"></form>');
    +    angular.forEach(fields, function(value, name) {
    +      var input = angular.element('<input type="hidden" name="' +  name + '">');
    +      input.attr('value', value);
    +      form.append(input);
    +    });
    +    $document.find('body').append(form);
    +    form[0].submit();
    +    form.remove();
    +  };
    +};
    +
    +docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, loadedUrls) {
    +  return function(content) {
    +    var allFiles = [].concat(content.js, content.css, content.html);
    +    var indexHtmlContent = '<!doctype html>\n' +
    +        '<html ng-app="{{module}}">\n' +
    +        '  <head>\n' +
    +        '{{scriptDeps}}' +
    +        '  </head>\n' +
    +        '  <body>\n\n' +
    +        '{{indexContents}}\n\n' +
    +        '{{postScriptDeps}}' +
    +        '  </body>\n' +
    +        '</html>\n';
    +    var scriptDeps = '';
    +    var postScriptDeps = '';
    +    angular.forEach(loadedUrls.base, function(url) {
    +      url = url.replace(/(\/release.+?$)/g, "http://ui-grid.info$1");
    +
    +      // scriptDeps += '    <script src="' + url + '"></script>\n';
    +      var ext = url.split(/\./).pop();
    +      if (ext == 'css') {
    +        scriptDeps += '    <link rel="stylesheet" href="' + url + '" type="text/css">\n';
    +      }
    +      else {
    +        scriptDeps += '    <script src="' + url + '"></script>\n';
    +      }
    +    });
    +    angular.forEach(allFiles, function(file) {
    +      var ext = file.name.split(/\./).pop();
    +          if (ext == 'css') {
    +            scriptDeps += '    <link rel="stylesheet" href="' + file.name + '" type="text/css">\n';
    +          }
    +          else if (ext == 'js' && file.name !== 'angular.js') {
    +            if (file.name === 'app.js') {
    +              postScriptDeps += '    <script src="' + file.name + '"></script>\n';
    +            }
    +            else {
    +              scriptDeps += '    <script src="' + file.name + '"></script>\n';
    +            }
    +          }
    +    });
    +
    +    indexProp = {
    +      module: content.module,
    +      scriptDeps: scriptDeps,
    +      postScriptDeps: postScriptDeps,
    +      indexContents: content.html[0].content
    +    };
    +
    +    var postData = {};
    +    angular.forEach(allFiles, function(file, index) {
    +      if (file.content && file.name != 'index.html') {
    +        if (file.name === 'app.js') {
    +          var contents = file.content;
    +          contents = contents.replace(/(\/data.+?\.json)/g, "https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages$1");
    +          postData['files[' + file.name + ']'] = contents;
    +        }
    +        else {
    +          postData['files[' + file.name + ']'] = file.content;
    +        }
    +      }
    +    });
    +
    +    postData['files[index.html]'] = templateMerge(indexHtmlContent, indexProp);
    +    postData['tags[]'] = "angularjs";
    +
    +    postData.private = true;
    +    postData.description = 'AngularJS Example Plunkr';
    +
    +    formPostData('http://plnkr.co/edit/?p=preview', postData);
    +  };
    +};
    +
    +docsApp.serviceFactory.openJsFiddle = function(templateMerge, formPostData, loadedUrls) {
    +
    +  var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
    +      SCRIPT_CACHE = '\n\n<!-- {{name}} -->\n<script type="text/ng-template" id="{{name}}">\n{{content:2}}</script>';
    +
    +  return function(content) {
    +    var prop = {
    +          module: content.module,
    +          html: '',
    +          css: '',
    +          script: ''
    +        };
    +
    +    angular.forEach(content.html, function(file, index) {
    +      if (index) {
    +        prop.html += templateMerge(SCRIPT_CACHE, file);
    +      } else {
    +        prop.html += file.content;
    +      }
    +    });
    +
    +    angular.forEach(content.js, function(file, index) {
    +      prop.script += file.content;
    +    });
    +
    +    angular.forEach(content.css, function(file, index) {
    +      prop.css += file.content;
    +    });
    +
    +    formPostData("http://jsfiddle.net/api/post/library/pure/dependencies/more/", {
    +      title: 'AngularJS Example',
    +      html: templateMerge(HTML, prop),
    +      js: prop.script,
    +      css: prop.css,
    +      resources: loadedUrls.base.join(','),
    +      wrap: 'b'
    +    });
    +  };
    +};
    +
    +
    +docsApp.serviceFactory.sections = function serviceFactory() {
    +  var sections = {
    +    getPage: function(sectionId, partialId) {
    +      var pages = sections[sectionId];
    +
    +      partialId = partialId || 'index';
    +
    +      for (var i = 0, ii = pages.length; i < ii; i++) {
    +        if (pages[i].id == partialId) {
    +          return pages[i];
    +        }
    +      }
    +      return null;
    +    }
    +  };
    +
    +  angular.forEach(NG_DOCS.pages, function(page) {
    +    var url = page.section + '/' +  page.id;
    +    if (page.id == 'angular.Module') {
    +      page.partialUrl = 'partials/api/angular.IModule.html';
    +    } else {
    +      page.partialUrl = 'partials/' + url.replace(':', '.') + '.html';
    +    }
    +    page.url = (NG_DOCS.html5Mode ? '' : '#/') + url;
    +    if (!sections[page.section]) { sections[page.section] = []; }
    +    sections[page.section].push(page);
    +  });
    +
    +  return sections;
    +};
    +
    +
    +docsApp.controller.DocsController = function($scope, $location, $window, $timeout, sections, versionedFiles) {
    +  var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/,
    +      GLOBALS = /^angular\.([^\.]+)$/,
    +      MODULE = /^([^\.]+)$/,
    +      MODULE_MOCK = /^angular\.mock\.([^\.]+)$/,
    +      MODULE_DIRECTIVE = /^(.+)\.directive:([^\.]+)$/,
    +      MODULE_DIRECTIVE_INPUT = /^(.+)\.directive:input\.([^\.]+)$/,
    +      MODULE_FILTER = /^(.+)\.filter:([^\.]+)$/,
    +      MODULE_CUSTOM = /^(.+)\.([^\.]+):([^\.]+)$/,
    +      MODULE_SERVICE = /^(.+)\.([^\.]+?)(Provider)?$/,
    +      MODULE_TYPE = /^([^\.]+)\..+\.([A-Z][^\.]+)$/;
    +
    +
    +  /**********************************
    +   Publish methods
    +   ***********************************/
    +
    +  $scope.navClass = function(page1, page2) {
    +    return {
    +      first: this.$first,
    +      last: this.$last,
    +      active: page1 && this.currentPage == page1 || page2 && this.currentPage == page2,
    +      match: this.focused && this.currentPage != page1 &&
    +             this.bestMatch.rank > 0 && this.bestMatch.page == page1
    +             
    +    };
    +  };
    +
    +  $scope.isActivePath = function(url) {
    +    if (url.charAt(0) == '#') {
    +      url = url.substring(1, url.length);
    +    }
    +    return $location.path().indexOf(url) > -1;
    +  };
    +
    +  $scope.submitForm = function() {
    +    if ($scope.bestMatch) {
    +      var url =  $scope.bestMatch.page.url;
    +      $location.path(NG_DOCS.html5Mode ? url : url.substring(1));
    +    }
    +  };
    +
    +  $scope.afterPartialLoaded = function() {
    +    var currentPageId = $location.path();
    +    $scope.partialTitle = $scope.currentPage.shortName;
    +    $window._gaq && $window._gaq.push(['_trackPageview', currentPageId]);
    +    loadDisqus(currentPageId);
    +  };
    +
    +  $scope.versionedFiles = VERSIONED_FILES;
    +
    +  $scope.setVersion = function (version) {
    +    if (!version) {
    +      version = $scope.versionedFiles.default;
    +    };
    +
    +    var versionFiles = $scope.versionedFiles.versions[version];
    +
    +    $scope.versionedScripts = [];
    +    $scope.versionedCSS = [];
    +
    +    angular.forEach(versionFiles, function (file) {
    +      if (file.type === 'script') {
    +        $scope.versionedScripts.push(file);
    +      }
    +      else if (file.type === 'css') {
    +        $scope.versionedCSS.push(file);
    +      }
    +    });
    +
    +    versionedFiles.files = versionFiles;
    +  };
    +
    +  $scope.changeVersion = function(version) {
    +    $scope.setVersion(version);
    +    // $timeout(function() {
    +      $location.path(NG_DOCS.startPage);
    +    // }, 0);
    +  };
    +
    +  $scope.setVersion();
    +
    +  /**********************************
    +   Watches
    +   ***********************************/
    +
    +  $scope.sections = {};
    +  angular.forEach(NG_DOCS.sections, function(section, url) {
    +    $scope.sections[(NG_DOCS.html5Mode ? '' : '#/') + url] = section;
    +  });
    +  $scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
    +
    +    if ($scope.versionedFiles.waitEval) {
    +      function evaler() {
    +        if (! eval($scope.versionedFiles.waitEval)) {
    +          $timeout(evaler, 200);
    +        }
    +        else {
    +          update();
    +        }
    +      };
    +      evaler();
    +    }
    +    else {
    +      update();
    +    }
    +
    +    function update() {
    +      // Set default version
    +
    +      var parts = path.split('/'),
    +        sectionId = parts[1],
    +        partialId = parts[2],
    +        page, sectionName = $scope.sections[(NG_DOCS.html5Mode ? '' : '#/') + sectionId];
    +
    +      if (!sectionName) { return; }
    +
    +      $scope.currentPage = page = sections.getPage(sectionId, partialId);
    +
    +      if (!$scope.currentPage) {
    +        $scope.partialTitle = 'Error: Page Not Found!';
    +      }
    +
    +      updateSearch();
    +
    +
    +      // Update breadcrumbs
    +      var breadcrumb = $scope.breadcrumb = [],
    +        match, sectionPath = (NG_DOCS.html5Mode ? '' : '#/') +  sectionId;
    +
    +      if (partialId) {
    +        breadcrumb.push({ name: sectionName, url: sectionPath });
    +        if (partialId == 'angular.Module') {
    +          breadcrumb.push({ name: 'angular.Module' });
    +        } else if (match = partialId.match(GLOBALS)) {
    +          breadcrumb.push({ name: partialId });
    +        } else if (match = partialId.match(MODULE)) {
    +          breadcrumb.push({ name: match[1] });
    +        } else if (match = partialId.match(MODULE_FILTER)) {
    +          breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +          breadcrumb.push({ name: match[2] });
    +        } else if (match = partialId.match(MODULE_DIRECTIVE)) {
    +          breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +          breadcrumb.push({ name: match[2] });
    +        } else if (match = partialId.match(MODULE_DIRECTIVE_INPUT)) {
    +          breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +          breadcrumb.push({ name: 'input' });
    +          breadcrumb.push({ name: match[2] });
    +        } else if (match = partialId.match(MODULE_CUSTOM)) {
    +          breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +          breadcrumb.push({ name: match[3] });
    +        } else if (match = partialId.match(MODULE_TYPE)) {
    +          breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +          breadcrumb.push({ name: match[2] });
    +        }  else if (match = partialId.match(MODULE_SERVICE)) {
    +          if ( page.type === 'overview') {
    +            // module name with dots looks like a service
    +            breadcrumb.push({ name: partialId });
    +          } else {
    +            breadcrumb.push({ name: match[1], url: sectionPath + '/' + match[1] });
    +            breadcrumb.push({ name: match[2] + (match[3] || '') });
    +          }
    +        } else if (match = partialId.match(MODULE_MOCK)) {
    +          breadcrumb.push({ name: 'angular.mock.' + match[1] });
    +        } else {
    +          breadcrumb.push({ name: page.shortName });
    +        }
    +      } else {
    +        breadcrumb.push({ name: sectionName });
    +      }
    +    }
    +  });
    +
    +  $scope.$watch('search', updateSearch);
    +
    +
    +
    +  /**********************************
    +   Initialize
    +   ***********************************/
    +
    +  $scope.versionNumber = angular.version.full;
    +  $scope.version = angular.version.full + "  " + angular.version.codeName;
    +  $scope.subpage = false;
    +  $scope.futurePartialTitle = null;
    +  $scope.loading = 0;
    +
    +  if (!$location.path() || INDEX_PATH.test($location.path())) {
    +    $location.path(NG_DOCS.startPage).replace();
    +  }
    +  // bind escape to hash reset callback
    +  angular.element(window).bind('keydown', function(e) {
    +    if (e.keyCode === 27) {
    +      $scope.$apply(function() {
    +        $scope.subpage = false;
    +      });
    +    }
    +  });
    +
    +  /**********************************
    +   Private methods
    +   ***********************************/
    +
    +  function updateSearch() {
    +    var cache = {},
    +        pages = sections[$location.path().split('/')[1]],
    +        modules = $scope.modules = [],
    +        otherPages = $scope.pages = [],
    +        search = $scope.search,
    +        bestMatch = {page: null, rank:0};
    +
    +    angular.forEach(pages, function(page) {
    +      var match,
    +        id = page.id,
    +        section = page.section;
    +
    +      if (!(match = rank(page, search))) return;
    +
    +      if (match.rank > bestMatch.rank) {
    +        bestMatch = match;
    +      }
    +
    +      if (page.id == 'index') {
    +        //skip
    +      } else if (!NG_DOCS.apis[section]) {
    +        otherPages.push(page);
    +      } else if (id == 'angular.Module') {
    +        module('ng', section).types.push(page);
    +      } else if (match = id.match(GLOBALS)) {
    +        module('ng', section).globals.push(page);
    +      } else if (match = id.match(MODULE)) {
    +        module(match[1], section);
    +      } else if (match = id.match(MODULE_FILTER)) {
    +        module(match[1], section).filters.push(page);
    +      } else if (match = id.match(MODULE_DIRECTIVE)) {
    +        module(match[1], section).directives.push(page);
    +      } else if (match = id.match(MODULE_DIRECTIVE_INPUT)) {
    +        module(match[1], section).directives.push(page);
    +      } else if (match = id.match(MODULE_CUSTOM)) {
    +        module(match[1], section).others.push(page);
    +      } else if (match = id.match(MODULE_TYPE)) {
    +        module(match[1], section).types.push(page);
    +      } else if (match = id.match(MODULE_SERVICE)) {
    +        if (page.type === 'overview') {
    +          module(id, section);
    +        } else {
    +          module(match[1], section).service(match[2])[match[3] ? 'provider' : 'instance'] = page;
    +        }
    +      } else if (match = id.match(MODULE_MOCK)) {
    +        module('ngMock', section).globals.push(page);
    +      }
    +
    +    });
    +
    +    $scope.bestMatch = bestMatch;
    +
    +    /*************/
    +
    +    function module(name, section) {
    +      var module = cache[name];
    +      if (!module) {
    +        module = cache[name] = {
    +          name: name,
    +          url: (NG_DOCS.html5Mode ? '' : '#/') + section + '/' + name,
    +          globals: [],
    +          directives: [],
    +          services: [],
    +          others: [],
    +          service: function(name) {
    +            var service =  cache[this.name + ':' + name];
    +            if (!service) {
    +              service = {name: name};
    +              cache[this.name + ':' + name] = service;
    +              this.services.push(service);
    +            }
    +            return service;
    +          },
    +          types: [],
    +          filters: []
    +        };
    +        modules.push(module);
    +      }
    +      return module;
    +    }
    +
    +    function rank(page, terms) {
    +      var ranking = {page: page, rank:0},
    +        keywords = page.keywords,
    +        title = page.shortName.toLowerCase();
    +
    +      terms && angular.forEach(terms.toLowerCase().split(' '), function(term) {
    +        var index;
    +
    +        if (ranking) {
    +          if (keywords.indexOf(term) == -1) {
    +            ranking = null;
    +          } else {
    +            ranking.rank ++; // one point for each term found
    +            if ((index = title.indexOf(term)) != -1) {
    +              ranking.rank += 20 - index; // ten points if you match title
    +            }
    +          }
    +        }
    +      });
    +      return ranking;
    +    }
    +  }
    +
    +
    +  function loadDisqus(currentPageId) {
    +    if (!NG_DOCS.discussions) { return; }
    +    // http://docs.disqus.com/help/2/
    +    window.disqus_shortname = NG_DOCS.discussions.shortName;
    +    window.disqus_identifier = currentPageId;
    +    window.disqus_url = NG_DOCS.discussions.url + currentPageId;
    +    window.disqus_developer = NG_DOCS.discussions.dev;
    +
    +    // http://docs.disqus.com/developers/universal/
    +    (function() {
    +      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
    +      dsq.src = 'http://angularjs.disqus.com/embed.js';
    +      (document.getElementsByTagName('head')[0] ||
    +        document.getElementsByTagName('body')[0]).appendChild(dsq);
    +    })();
    +
    +    angular.element(document.getElementById('disqus_thread')).html('');
    +  }
    +};
    +
    +angular.module('docsApp', ['bootstrap', 'bootstrapPrettify']).
    +  config(function($locationProvider) {
    +    if (NG_DOCS.html5Mode) {
    +      $locationProvider.html5Mode(true).hashPrefix('!');
    +    }
    +  }).
    +  factory(docsApp.serviceFactory).
    +  directive(docsApp.directive).
    +  controller(docsApp.controller);
    \ No newline at end of file
    diff --git a/docs/partials/api/Grid.html b/docs/partials/api/Grid.html
    new file mode 100644
    index 000000000..00decfe57
    --- /dev/null
    +++ b/docs/partials/api/Grid.html
    @@ -0,0 +1,57 @@
    +<h1><code ng:non-bindable="">Grid</code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Grid defines a logical grid.  Any non-dom properties and elements needed by the grid should
    +be defined in this class</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">Grid(id);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">id – {string} – </code>
    +<p>id to assign to grid</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="buildColumns">buildColumns()</h3>
    +<div class="buildcolumns"><p>creates GridColumn objects from the columnDefinition.  Calls each registered
    +columnBuilder to further process the column</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Promise}</code>
    +– <p>a promise to load any needed column resources</p></div>
    +</div>
    +</li>
    +<li><h3 id="buildStyles">buildStyles()</h3>
    +<div class="buildstyles"><p>calls each styleComputation function</p></div>
    +</li>
    +<li><h3 id="getColumn">getColumn(field)</h3>
    +<div class="getcolumn"><p>returns a grid column for the field name</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">field – {string} – </code>
    +<p>field name</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="modifyRows">modifyRows()</h3>
    +<div class="modifyrows"><p>creates or removes GridRow objects from the newRawData array.  Calls each registered
    +rowBuilder to further process the row</p>
    +
    +<p>Rows are identified using the gridOptions.rowEquality function</p></div>
    +</li>
    +<li><h3 id="processRowBuilders">processRowBuilders()</h3>
    +<div class="processrowbuilders"><p>processes all RowBuilders for the gridRow</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{GridRow}</code>
    +– <p>the gridRow with all additional behaivor added</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerColumnBuilder">registerColumnBuilder(columnsProcessor)</h3>
    +<div class="registercolumnbuilder"><p>When the build creates columns from column definitions, the columnbuilders will be called to add
    +additional properties to the column.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">columnsProcessor – {function(colDef, col, gridOptions)} – </code>
    +<p>function to be called</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerStyleComputation">registerStyleComputation()</h3>
    +<div class="registerstylecomputation"><p>registered a styleComputation function</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/GridColumn.html b/docs/partials/api/GridColumn.html
    new file mode 100644
    index 000000000..66cfd0970
    --- /dev/null
    +++ b/docs/partials/api/GridColumn.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">GridColumn</code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Wrapper for the GridOptions.colDefs items.  Allows for needed properties and functions
    +to be assigned to a grid column</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridColumn(colDef, index);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {ColDef} – </code>
    +<p>Column definition</p></li>
    +<li><code ng:non-bindable="">index – {number} – </code>
    +<p>the current position of the column in the array</p></li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/GridOptions.html b/docs/partials/api/GridOptions.html
    new file mode 100644
    index 000000000..f6f5d7440
    --- /dev/null
    +++ b/docs/partials/api/GridOptions.html
    @@ -0,0 +1,38 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +over this object.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridOptions(id);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">id – {string} – </code>
    +<p>id to assign to grid</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="rowEquality">rowEquality(entityA, entityB)</h3>
    +<div class="rowequality"><p>By default, rows are compared using object equality.  This option can be overridden
    +to compare on any data item property or function</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">entityA – {object} – </code>
    +<p>First Data Item to compare</p></li>
    +<li><code ng:non-bindable="">entityB – {object} – </code>
    +<p>Second Data Item to compare</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="columnDefs">columnDefs</h3>
    +<div class="columndefs"><p>(optional) Array of columnDef objects.  Only required property is field</p><h4 id="Example">Example</h4>
    +<div class="example"><p>var columnDefs = [{field:'field1'}, {field:'field2'}];</p></div>
    +</div>
    +</li>
    +<li><h3 id="data">data</h3>
    +<div class="data"><p>Array of data to be rendered to grid.  Array can contain complex objects</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/GridRow.html b/docs/partials/api/GridRow.html
    new file mode 100644
    index 000000000..c8c967beb
    --- /dev/null
    +++ b/docs/partials/api/GridRow.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Wrapper for the GridOptions.data rows.  Allows for needed properties and functions
    +to be assigned to a grid row</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridRow(entity, index);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">entity – {object} – </code>
    +<p>the array item from GridOptions.data</p></li>
    +<li><code ng:non-bindable="">index – {number} – </code>
    +<p>the current position of the row in the array</p></li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/index.html b/docs/partials/api/index.html
    new file mode 100644
    index 000000000..297d5582e
    --- /dev/null
    +++ b/docs/partials/api/index.html
    @@ -0,0 +1,39 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The ui-grid API consists of the core ui.grid documentation, plus documentation for each of the features that
    +you can choose to add to the grid.</p>
    +
    +<p>In general the features will extend the core ui-grid configuration.  So, for example, if you wanted to configure
    +the core ui-grid, you might choose to set some options and columns on your grid (the documentation for these is 
    +found in <a href="#/api/ui.grid.class:GridOptions">gridOptions</a> and <a href="#/api/ui.grid.class:GridOptions.columnDef">columnDef</a>.</p>
    +
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions = {
    +    enableSorting: true,
    +    columnDefs: [ 
    +      { name: 'field1', enableSorting: false },
    +      { name: 'field2' },
    +      { name: 'field3', visible: false }
    +    ]
    +  };
    +</pre>
    +
    +<p>If you had enabled the edit feature, then the columnDefs and gridOptions would have additional settings, the documentation
    +for these is at <a href="#/api/ui.grid.edit.api:ColumnDef">columnDef</a> and <a href="#/api/ui.grid.edit.api:GridOptions">gridOptions</a>, but you
    +still set these through the same mechanism:</p>
    +
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions = {
    +    enableSorting: true,
    +    enableCellEditOnFocus: true,
    +    columnDefs: [ 
    +      { name: 'field1', enableSorting: false, enableCellEdit: false },
    +      { name: 'field2' },
    +      { name: 'field3', visible: false }
    +    ]
    +  };
    +</pre>
    +
    +<p>In general you'll therefore use the documentation for the core ui.grid module, and then the additional documentation
    +for any feature that you have enabled.</p></div>
    diff --git a/docs/partials/api/ui.grid.autoResize.html b/docs/partials/api/ui.grid.autoResize.html
    new file mode 100644
    index 000000000..a1fb2aa85
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.autoResize.html
    @@ -0,0 +1,6 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridautoresize">ui.grid.autoResize</h2>
    +
    +<p>This module provides auto-resizing functionality to ui-grid</p></div>
    diff --git a/docs/partials/api/ui.grid.cellNav.api.ColDef.html b/docs/partials/api/ui.grid.cellNav.api.ColDef.html
    new file mode 100644
    index 000000000..2c02df09b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.api.ColDef.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">ColDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Column Definitions for cellNav feature</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.api.ColumnDef.html b/docs/partials/api/ui.grid.cellNav.api.ColumnDef.html
    new file mode 100644
    index 000000000..089c96cd7
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.api.ColumnDef.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Column Definitions for cellNav feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions.columnDef">gridOptions.columnDefs</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="allowCellFocus">allowCellFocus</h3>
    +<div class="allowcellfocus"><p>Enable focus on a cell within this column.
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.api.GridOptions.html b/docs/partials/api/ui.grid.cellNav.api.GridOptions.html
    new file mode 100644
    index 000000000..400486f6a
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.api.GridOptions.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for cellNav feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="modifierKeysToMultiSelectCells">modifierKeysToMultiSelectCells</h3>
    +<div class="modifierkeystomultiselectcells"><p>Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +<br/>Defaults to false</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.api.GridRow.html b/docs/partials/api/ui.grid.cellNav.api.GridRow.html
    new file mode 100644
    index 000000000..ef3c8e410
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.api.GridRow.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridRow settings for cellNav feature, these are available to be
    +set only internally (for example, by other features)</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="allowCellFocus">allowCellFocus</h3>
    +<div class="allowcellfocus"><p>Enable focus on a cell within this row.  If set to false then no cells
    +in this row can be focused - group header rows as an example would set this to false.
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.api.PublicApi.html b/docs/partials/api/ui.grid.cellNav.api.PublicApi.html
    new file mode 100644
    index 000000000..9a581f4bf
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.api.PublicApi.html
    @@ -0,0 +1,71 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for cellNav feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getCurrentSelection">getCurrentSelection()</h3>
    +<div class="getcurrentselection"><p>returns an array containing the current selection
    +<br> array is empty if no selection has occurred</p></div>
    +</li>
    +<li><h3 id="getFocusedCell">getFocusedCell()</h3>
    +<div class="getfocusedcell"><p>returns the current (or last if Grid does not have focus) focused row and column
    +<br> value is null if no selection has occurred</p></div>
    +</li>
    +<li><h3 id="rowColSelectIndex">rowColSelectIndex(rowCol)</h3>
    +<div class="rowcolselectindex"><p>returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +isn't selected</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowCol – {object} – </code>
    +<p>the rowCol to evaluate</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollTo">scrollTo(rowEntity, colDef)</h3>
    +<div class="scrollto"><p>brings the specified row and column into view</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance to make visible</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>to make visible</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollToFocus">scrollToFocus(rowEntity, colDef)</h3>
    +<div class="scrolltofocus"><p>brings the specified row and column into view, and sets focus
    +to that cell</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance to make visible and set focus</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>to make visible and set focus</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollToFocus">scrollToFocus(row, col)</h3>
    +<div class="scrolltofocus"><p>brings the specified row and column fully into view if it isn't already</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>grid row that we should make fully visible</p></li>
    +<li><code ng:non-bindable="">col – {GridCol} – </code>
    +<p>grid col to make fully visible</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="navigate">navigate</h3>
    +<div class="navigate"><p>raised when the active cell is changed
    +<pre class="prettyprint linenums">
    +     gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">newRowCol – {object} – </code>
    +<p>new position</p></li>
    +<li><code ng:non-bindable="">oldRowCol – {object} – </code>
    +<p>old position</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.constant.uiGridCellNavConstants.html b/docs/partials/api/ui.grid.cellNav.constant.uiGridCellNavConstants.html
    new file mode 100644
    index 000000000..c4fc6cb01
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.constant.uiGridCellNavConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridCellNavConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in cellNav</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.constant.uiGridEditConstants.html b/docs/partials/api/ui.grid.cellNav.constant.uiGridEditConstants.html
    new file mode 100644
    index 000000000..ceacfeaf6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.constant.uiGridEditConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridEditConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in cellNav</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.directive.uiCellNav.html b/docs/partials/api/ui.grid.cellNav.directive.uiCellNav.html
    new file mode 100644
    index 000000000..f3efb7042
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.directive.uiCellNav.html
    @@ -0,0 +1,45 @@
    +<h1><code ng:non-bindable="">uiCellNav</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds cell navigation features to the grid columns</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as element:<pre class="prettyprint linenums">&lt;ui-cell-nav&gt;
    +&lt;/ui-cell-nav&gt;</pre>
    +as attribute<pre class="prettyprint linenums">&lt;div ui-cell-nav&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Bob', title: 'CEO' },
    +         { name: 'Frank', title: 'Lowly Developer' }
    +   ];
    +
    +   $scope.columnDefs = [
    +     {name: 'name'},
    +     {name: 'title'}
    +   ];
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.directive.uiGridCell.html b/docs/partials/api/ui.grid.cellNav.directive.uiGridCell.html
    new file mode 100644
    index 000000000..7c0af1ef0
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.directive.uiGridCell.html
    @@ -0,0 +1,12 @@
    +<h1><code ng:non-bindable="">uiGridCell</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridCell to provide cell navigation</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-cell&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.object.CellNav.html b/docs/partials/api/ui.grid.cellNav.object.CellNav.html
    new file mode 100644
    index 000000000..bdd1c2132
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.object.CellNav.html
    @@ -0,0 +1,20 @@
    +<h1><code ng:non-bindable="">CellNav</code>
    +<span class="hint">(object in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>returns a CellNav prototype function</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">object:CellNav(rowContainer, colContainer, leftColContainer, rightColContainer);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">rowContainer – {object} – </code>
    +<p>container for rows</p></li>
    +<li><code ng:non-bindable="">colContainer – {object} – </code>
    +<p>parent column container</p></li>
    +<li><code ng:non-bindable="">leftColContainer – {object} – </code>
    +<p>column container to the left of parent</p></li>
    +<li><code ng:non-bindable="">rightColContainer – {object} – </code>
    +<p>column container to the right of parent</p></li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.service.uiGridCellNavService.html b/docs/partials/api/ui.grid.cellNav.service.uiGridCellNavService.html
    new file mode 100644
    index 000000000..53f9e0cf0
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.service.uiGridCellNavService.html
    @@ -0,0 +1,112 @@
    +<h1><code ng:non-bindable="">uiGridCellNavService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for cell navigation features. If you don't like the key maps we use,
    +or the direction cells navigation, override with a service decorator (see angular docs)</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="cellNavColumnBuilder">cellNavColumnBuilder()</h3>
    +<div class="cellnavcolumnbuilder"><p>columnBuilder function that adds cell navigation properties to grid column</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that will load any needed templates when resolved</p></div>
    +</div>
    +</li>
    +<li><h3 id="decorateRenderContainers">decorateRenderContainers()</h3>
    +<div class="decoraterendercontainers"><p>decorates grid renderContainers with cellNav functions</p></div>
    +</li>
    +<li><h3 id="getDirection">getDirection()</h3>
    +<div class="getdirection"><p>determines which direction to for a given keyDown event</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{uiGridCellNavConstants.direction}</code>
    +– <p>direction</p></div>
    +</div>
    +</li>
    +<li><h3 id="getLeftWidth">getLeftWidth(grid, upToCol)</h3>
    +<div class="getleftwidth"><p>Get the current drawn width of the columns in the
    +grid up to the numbered column, and add an apportionment for the
    +column that we're on.  So if we are on column 0, we want to scroll
    +0% (i.e. exclude this column from calc).  If we're on the last column
    +we want to scroll to 100% (i.e. include this column in the calc). So
    +we include (thisColIndex / totalNumberCols) % of this column width</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you'd like to act upon, usually available
    +from gridApi.grid</p></li>
    +<li><code ng:non-bindable="">upToCol – {gridCol} – </code>
    +<p>the column to total up to and including</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollTo">scrollTo(grid, rowEntity, colDef)</h3>
    +<div class="scrollto"><p>Scroll the grid such that the specified
    +row and column is in view</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you'd like to act upon, usually available
    +from gridApi.grid</p></li>
    +<li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance to make visible</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>to make visible</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollToFocus">scrollToFocus(grid, rowEntity, colDef)</h3>
    +<div class="scrolltofocus"><p>Scroll the grid such that the specified
    +row and column is in view, and set focus to the cell in that row and column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you'd like to act upon, usually available
    +from gridApi.grid</p></li>
    +<li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance to make visible and set focus to</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>to make visible and set focus to</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollToIfNecessary">scrollToIfNecessary(grid, gridRow, gridCol)</h3>
    +<div class="scrolltoifnecessary"><p>Scrolls the grid to make a certain row and column combo visible,
    +in the case that it is not completely visible on the screen already.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you'd like to act upon, usually available
    +from gridApi.grid</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>row to make visible</p></li>
    +<li><code ng:non-bindable="">gridCol – {GridCol} – </code>
    +<p>column to make visible</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="scrollToInternal">scrollToInternal(grid, gridRow, gridCol)</h3>
    +<div class="scrolltointernal"><p>Like scrollTo, but takes gridRow and gridCol.
    +In calculating the scroll height we have to deal with wanting
    +0% for the first row, and 100% for the last row.  Normal maths
    +for a 10 row list would return 1/10 = 10% for the first row, so
    +we need to tweak the numbers to add an extra 10% somewhere.  The
    +formula if we're trying to get to row 0 in a 10 row list (assuming our
    +index is zero based, so the last row is row 9) is:
    +<pre class="prettyprint linenums">
    +  0 + 0 / 10 = 0%
    +</pre>
    +
    +<p>To get to row 9 (i.e. the last row) in the same list, we want to
    +go to:
    +<pre class="prettyprint linenums">
    + ( 9 + 1 ) / 10 = 100%
    +</pre>
    +So we need to apportion one whole row within the overall grid scroll,
    +the formula is:
    +<pre class="prettyprint linenums">
    +  ( index + ( index / (total rows - 1) ) / total rows
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you'd like to act upon, usually available
    +from gridApi.grid</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>row to make visible</p></li>
    +<li><code ng:non-bindable="">gridCol – {GridCol} – </code>
    +<p>column to make visible</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.cellNav.service.uiGridNavService.html b/docs/partials/api/ui.grid.cellNav.service.uiGridNavService.html
    new file mode 100644
    index 000000000..04a62e0d1
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.cellNav.service.uiGridNavService.html
    @@ -0,0 +1,8 @@
    +<h1><code ng:non-bindable="">uiGridNavService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.cellNav</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for editing features. If you don't like the key maps we use,
    +override with a service decorator (see angular docs)</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.Grid.html b/docs/partials/api/ui.grid.class.Grid.html
    new file mode 100644
    index 000000000..25702444e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.Grid.html
    @@ -0,0 +1,343 @@
    +<h1><code ng:non-bindable="">Grid</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +this prototype.  One instance of Grid is created per Grid directive instance.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">Grid(options);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">options – {object} – </code>
    +<p>Object map of options to pass into the grid. An 'id' property is expected.</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="addRowHeaderColumn">addRowHeaderColumn(column)</h3>
    +<div class="addrowheadercolumn"><p>adds a row header column to the grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">column – {object} – </code>
    +<p>def</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="assignTypes">assignTypes()</h3>
    +<div class="assigntypes"><p>uses the first row of data to assign colDef.type for any types not defined.</p></div>
    +</li>
    +<li><h3 id="buildColumnDefsFromData">buildColumnDefsFromData(rowBuilder)</h3>
    +<div class="buildcolumndefsfromdata"><p>Populates columnDefs from the provided data</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowBuilder – {function(colDef, col, gridOptions)} – </code>
    +<p>function to be called</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="buildColumns">buildColumns(options)</h3>
    +<div class="buildcolumns"><p>creates GridColumn objects from the columnDefinition.  Calls each registered
    +columnBuilder to further process the column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">options – {object} – </code>
    +<p>An object contains options to use when building columns</p>
    +
    +<ul>
    +<li><strong>orderByColumnDefs</strong>: defaults to <strong>false</strong>. When true, <code>buildColumns</code> will reorder existing columns according to the order within the column definitions.</li>
    +</ul></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Promise}</code>
    +– <p>a promise to load any needed column resources</p></div>
    +</div>
    +</li>
    +<li><h3 id="buildStyles">buildStyles()</h3>
    +<div class="buildstyles"><p>calls each styleComputation function</p></div>
    +</li>
    +<li><h3 id="callDataChangeCallbacks">callDataChangeCallbacks(type)</h3>
    +<div class="calldatachangecallbacks"><p>Calls the callbacks based on the type of data change that
    +has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +event type is matching, or if the type is ALL.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">type – {number} – </code>
    +<p>the type of event that occurred - one of the 
    +uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="columnRefreshCallback">columnRefreshCallback(name)</h3>
    +<div class="columnrefreshcallback"><p>refreshes the grid when a column refresh
    +is notified, which triggers handling of the visible flag. 
    +This is called on uiGridConstants.dataChange.COLUMN, and is 
    +registered as a dataChangeCallback in grid.js</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">name – {string} – </code>
    +<p>column name</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="createLeftContainer">createLeftContainer()</h3>
    +<div class="createleftcontainer"><p>creates the left render container if it doesn't already exist</p></div>
    +</li>
    +<li><h3 id="createRightContainer">createRightContainer()</h3>
    +<div class="createrightcontainer"><p>creates the right render container if it doesn't already exist</p></div>
    +</li>
    +<li><h3 id="flagScrollingHorizontally">flagScrollingHorizontally()</h3>
    +<div class="flagscrollinghorizontally"><p>sets isScrollingHorizontally to true and sets it to false in a debounced function</p></div>
    +</li>
    +<li><h3 id="flagScrollingVertically">flagScrollingVertically()</h3>
    +<div class="flagscrollingvertically"><p>sets isScrollingVertically to true and sets it to false in a debounced function</p></div>
    +</li>
    +<li><h3 id="getCellValue">getCellValue(row, col)</h3>
    +<div class="getcellvalue"><p>Gets the value of a cell for a particular row and column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>Row to access</p></li>
    +<li><code ng:non-bindable="">col – {GridColumn} – </code>
    +<p>Column to access</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getColDef">getColDef(name)</h3>
    +<div class="getcoldef"><p>returns a grid colDef for the column name</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">name – {string} – </code>
    +<p>column.field</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getColumn">getColumn(name)</h3>
    +<div class="getcolumn"><p>returns a grid column for the column name</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">name – {string} – </code>
    +<p>column name</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getColumnSorting">getColumnSorting()</h3>
    +<div class="getcolumnsorting"><p>Return the columns that the grid is currently being sorted by</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Array[GridColumn]}</code>
    +– <p>An array of GridColumn objects</p></div>
    +</div>
    +</li>
    +<li><h3 id="getGridQualifiedColField">getGridQualifiedColField(col)</h3>
    +<div class="getgridqualifiedcolfield"><p>Returns the $parse-able accessor for a column within its $scope</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">col – {GridColumn} – </code>
    +<p>col object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getRow">getRow(rowEntity)</h3>
    +<div class="getrow"><p>returns the GridRow that contains the rowEntity</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the gridOptions.data array element instance</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="handleWindowResize">handleWindowResize()</h3>
    +<div class="handlewindowresize"><p>Triggered when the browser window resizes; automatically resizes the grid</p></div>
    +</li>
    +<li><h3 id="hasLeftContainer">hasLeftContainer()</h3>
    +<div class="hasleftcontainer"><p>returns true if leftContainer exists</p></div>
    +</li>
    +<li><h3 id="hasLeftContainer">hasLeftContainer()</h3>
    +<div class="hasleftcontainer"><p>returns true if rightContainer exists</p></div>
    +</li>
    +<li><h3 id="hasLeftContainerColumns">hasLeftContainerColumns()</h3>
    +<div class="hasleftcontainercolumns"><p>returns true if leftContainer has columns</p></div>
    +</li>
    +<li><h3 id="hasRightContainerColumns">hasRightContainerColumns()</h3>
    +<div class="hasrightcontainercolumns"><p>returns true if rightContainer has columns</p></div>
    +</li>
    +<li><h3 id="isRTL">isRTL()</h3>
    +<div class="isrtl"><p>Returns true if grid is RightToLeft</p></div>
    +</li>
    +<li><h3 id="modifyRows">modifyRows()</h3>
    +<div class="modifyrows"><p>creates or removes GridRow objects from the newRawData array.  Calls each registered
    +rowBuilder to further process the row</p>
    +
    +<p>Rows are identified using the gridOptions.rowEquality function</p></div>
    +</li>
    +<li><h3 id="notifyDataChange">notifyDataChange(type)</h3>
    +<div class="notifydatachange"><p>Notifies us that a data change has occurred, used in the public
    +api for users to tell us when they've changed data or some other event that 
    +our watches cannot pick up</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">type – {string} – </code>
    +<p>the type of event that occurred - one of the 
    +uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="preCompileCellTemplates">preCompileCellTemplates()</h3>
    +<div class="precompilecelltemplates"><p>precompiles all cell templates</p></div>
    +</li>
    +<li><h3 id="processRowBuilders">processRowBuilders(gridRow)</h3>
    +<div class="processrowbuilders"><p>processes all RowBuilders for the gridRow</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>reference to gridRow</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{GridRow}</code>
    +– <p>the gridRow with all additional behavior added</p></div>
    +</div>
    +</li>
    +<li><h3 id="processRowsCallback">processRowsCallback(name)</h3>
    +<div class="processrowscallback"><p>calls the row processors, specifically
    +intended to reset the sorting when an edit is called,
    +registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">name – {string} – </code>
    +<p>column name</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="queueRefresh">queueRefresh()</h3>
    +<div class="queuerefresh"><p>todo: @c0bra can you document this method?</p></div>
    +</li>
    +<li><h3 id="redrawCanvas">redrawCanvas()</h3>
    +<div class="redrawcanvas"><p>TBD</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that is resolved when the canvas
    +has been refreshed</p></div>
    +</div>
    +</li>
    +<li><h3 id="redrawCanvas">redrawCanvas([rowsAdded])</h3>
    +<div class="redrawcanvas"><p>Redraw the rows and columns based on our current scroll position</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">[rowsAdded] – {boolean} – </code>
    +<p>Optional to indicate rows are added and the scroll percentage must be recalculated</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="refresh">refresh()</h3>
    +<div class="refresh"><p>Refresh the rendered grid on screen.</p></div>
    +</li>
    +<li><h3 id="refreshRows">refreshRows()</h3>
    +<div class="refreshrows"><p>Refresh the rendered rows on screen?  Note: not functional at present </p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that is resolved when render completes?</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerColumnBuilder">registerColumnBuilder(columnsProcessor)</h3>
    +<div class="registercolumnbuilder"><p>When the build creates columns from column definitions, the columnbuilders will be called to add
    +additional properties to the column.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">columnsProcessor – {function(colDef, col, gridOptions)} – </code>
    +<p>function to be called</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerColumnsProcessor">registerColumnsProcessor(rows)</h3>
    +<div class="registercolumnsprocessor"><p>Register a "columns processor" function. When the columns are updated,
    +the grid calls each registered "columns processor", which has a chance
    +to alter the set of columns, as long as the count is not modified.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rows – {function(renderableColumns)} – </code>
    +<p>processor function</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Array[GridColumn]}</code>
    +– <p>Updated renderable columns</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerDataChangeCallback">registerDataChangeCallback(callback, types)</h3>
    +<div class="registerdatachangecallback"><p>When a data change occurs, the data change callbacks of the specified type
    +will be called.  The rules are:</p>
    +
    +<ul>
    +<li>when the data watch fires, that is considered a ROW change (the data watch only notices
    +added or removed rows)</li>
    +<li>when the api is called to inform us of a change, the declared type of that change is used</li>
    +<li>when a cell edit completes, the EDIT callbacks are triggered</li>
    +<li>when the columnDef watch fires, the COLUMN callbacks are triggered</li>
    +<li>when the options watch fires, the OPTIONS callbacks are triggered</li>
    +</ul>
    +
    +<p>For a given event:
    +- ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +- ROW calls ROW and ALL callbacks
    +- EDIT calls EDIT and ALL callbacks
    +- COLUMN calls COLUMN and ALL callbacks
    +- OPTIONS calls OPTIONS and ALL callbacks</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">callback – {function(grid)} – </code>
    +<p>function to be called</p></li>
    +<li><code ng:non-bindable="">types – {array} – </code>
    +<p>the types of data change you want to be informed of.  Values from 
    +the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +ALL </p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>deregister function - a function that can be called to deregister this callback</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerRowBuilder">registerRowBuilder(rowBuilder)</h3>
    +<div class="registerrowbuilder"><p>When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +additional properties to the row.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowBuilder – {function(row, gridOptions)} – </code>
    +<p>function to be called</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerRowsProcessor">registerRowsProcessor(rows)</h3>
    +<div class="registerrowsprocessor"><p>Register a "rows processor" function. When the rows are updated,
    +the grid calls each registered "rows processor", which has a chance
    +to alter the set of rows (sorting, etc) as long as the count is not
    +modified.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rows – {function(renderableRows)} – </code>
    +<p>processor function</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Array[GridRow]}</code>
    +– <p>Updated renderable rows</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerStyleComputation">registerStyleComputation(styleComputation)</h3>
    +<div class="registerstylecomputation"><p>registered a styleComputation function</p>
    +
    +<p>If the function returns a value it will be appended into the grid's <code>&lt;style&gt;</code> block</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">styleComputation – {function($scope)} – </code>
    +<p>function</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="removeRowsProcessor">removeRowsProcessor(rows)</h3>
    +<div class="removerowsprocessor"><p>Remove a registered rows processor</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rows – {function(renderableRows)} – </code>
    +<p>processor function</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="resetColumnSorting">resetColumnSorting([excludedColumn])</h3>
    +<div class="resetcolumnsorting"><p>Return the columns that the grid is currently being sorted by</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">[excludedColumn] – {GridColumn} – </code>
    +<p>Optional GridColumn to exclude from having its sorting reset</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="sortColumn">sortColumn(column, [direction], [add])</h3>
    +<div class="sortcolumn"><p>Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +Emits the sortChanged event whenever the sort criteria are changed.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">column – {GridColumn} – </code>
    +<p>Column to set the sorting on</p></li>
    +<li><code ng:non-bindable="">[direction] – {uiGridConstants.ASC|uiGridConstants.DESC} – </code>
    +<p>Direction to sort by, either descending or ascending.
    +If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.</p></li>
    +<li><code ng:non-bindable="">[add] – {boolean} – </code>
    +<p>Add this column to the sorting. If not provided or set to <code>false</code>, the Grid will reset any existing sorting and sort
    +by this column only</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Promise}</code>
    +– <p>A resolved promise that supplies the column.</p></div>
    +</div>
    +</li>
    +<li><h3 id="updateCanvasHeight">updateCanvasHeight()</h3>
    +<div class="updatecanvasheight"><p>flags all render containers to update their canvas height</p></div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="appScope">appScope</h3>
    +<div class="appscope"><p>reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +<br/>
    +use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference</p></div>
    +</li>
    +<li><h3 id="isScrollingHorizontally">isScrollingHorizontally</h3>
    +<div class="isscrollinghorizontally"><p>set to true when Grid is scrolling horizontally. Set to false via debounced method</p></div>
    +</li>
    +<li><h3 id="isScrollingVertically">isScrollingVertically</h3>
    +<div class="isscrollingvertically"><p>set to true when Grid is scrolling vertically. Set to false via debounced method</p></div>
    +</li>
    +<li><h3 id="scrollDirection">scrollDirection</h3>
    +<div class="scrolldirection"><p>set one of the uiGridConstants.scrollDirection values (UP, DOWN, LEFT, RIGHT, NONE), which tells
    +us which direction we are scrolling. Set to NONE via debounced method</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridApi.html b/docs/partials/api/ui.grid.class.GridApi.html
    new file mode 100644
    index 000000000..b713e42d8
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridApi.html
    @@ -0,0 +1,124 @@
    +<h1><code ng:non-bindable="">GridApi</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridApi provides the ability to register public methods events inside the grid and allow
    +for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +<br/>
    +To listen to events, you must add a callback to gridOptions.onRegisterApi
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions.onRegisterApi = function(gridApi){
    +     gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         $log.log('navigation event');
    +     });
    +  };
    +</pre></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridApi(grid);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>grid that owns api</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="registerEvent">registerEvent(featureName, eventName)</h3>
    +<div class="registerevent"><p>Registers a new event for the given feature.  The event will get a
    +.raise and .on prepended to it
    +<br>
    +.raise.eventName() - takes no arguments
    +<br/>
    +<br/>
    +.on.eventName(scope, callBackFn, _this)
    +<br/>
    +scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +<br/>
    +callBackFn - The function to call
    +<br/>
    +_this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +<br/>
    +.on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +will be removed when the scope is destroyed.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">featureName – {string} – </code>
    +<p>name of the feature that raises the event</p></li>
    +<li><code ng:non-bindable="">eventName – {string} – </code>
    +<p>name of the event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerEventsFromObject">registerEventsFromObject(eventObjectMap)</h3>
    +<div class="registereventsfromobject"><p>Registers features and events from a simple objectMap.
    +eventObjectMap must be in this format (multiple features allowed)
    +<pre class="prettyprint linenums">
    +{featureName:
    +       {
    +         eventNameOne:function(args){},
    +         eventNameTwo:function(args){}
    +       }
    + }
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">eventObjectMap – {object} – </code>
    +<p>map of feature/event names</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerMethod">registerMethod(featureName, methodName, callBackFn, _this)</h3>
    +<div class="registermethod"><p>Registers a new event for the given feature</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">featureName – {string} – </code>
    +<p>name of the feature</p></li>
    +<li><code ng:non-bindable="">methodName – {string} – </code>
    +<p>name of the method</p></li>
    +<li><code ng:non-bindable="">callBackFn – {object} – </code>
    +<p>function to execute</p></li>
    +<li><code ng:non-bindable="">_this – {object} – </code>
    +<p>binds callBackFn 'this' to _this.  Defaults to gridApi.grid</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerMethodsFromObject">registerMethodsFromObject(eventObjectMap, _this)</h3>
    +<div class="registermethodsfromobject"><p>Registers features and methods from a simple objectMap.
    +eventObjectMap must be in this format (multiple features allowed)
    +<br>
    +{featureName:
    +       {
    +         methodNameOne:function(args){},
    +         methodNameTwo:function(args){}
    +       }</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">eventObjectMap – {object} – </code>
    +<p>map of feature/event names</p></li>
    +<li><code ng:non-bindable="">_this – {object} – </code>
    +<p>binds this to _this for all functions.  Defaults to gridApi.grid</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="suppressEvents">suppressEvents(listenerFuncs, callBackFn)</h3>
    +<div class="suppressevents"><p>Used to execute a function while disabling the specified event listeners.
    +Disables the listenerFunctions, executes the callbackFn, and then enables
    +the listenerFunctions again</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">listenerFuncs – {object} – </code>
    +<p>listenerFunc or array of listenerFuncs to suppress. These must be the same
    +functions that were used in the .on.eventName method</p></li>
    +<li><code ng:non-bindable="">callBackFn – {object} – </code>
    +<p>function to execute</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var navigate = function (newRowCol, oldRowCol){
    +   //do something on navigate
    +}
    +
    +gridApi.cellNav.on.navigate(scope,navigate);
    +
    +
    +//call the scrollTo event and suppress our navigate listener
    +//scrollTo will still raise the event for other listeners
    +gridApi.suppressEvents(navigate, function(){
    +   gridApi.cellNav.scrollTo(aRow, aCol);
    +});
    +
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridColumn.html b/docs/partials/api/ui.grid.class.GridColumn.html
    new file mode 100644
    index 000000000..b9f44e1ff
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridColumn.html
    @@ -0,0 +1,133 @@
    +<h1><code ng:non-bindable="">GridColumn</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +are defined on this prototype</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridColumn(colDef, index, grid);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {ColDef} – </code>
    +<p>Column definition.</p></li>
    +<li><code ng:non-bindable="">index – {number} – </code>
    +<p>the current position of the column in the array</p></li>
    +<li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>reference to the grid</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="GridColumn">GridColumn(colDef, uid, grid)</h3>
    +<div class="gridcolumn"><p>Initializes a gridColumn</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {ColumnDef} – </code>
    +<p>the column def to associate with this column</p></li>
    +<li><code ng:non-bindable="">uid – {number} – </code>
    +<p>the unique and immutable uid we'd like to allocate to this column</p></li>
    +<li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we'd like to create this column in</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getAggregationText">getAggregationText(label)</h3>
    +<div class="getaggregationtext"><p>Gets the aggregation label from colDef.aggregationLabel if
    +specified or by using i18n, including deciding whether or not to display
    +based on colDef.aggregationHideLabel.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">label – {string} – </code>
    +<p>the i18n lookup value to use for the column label</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getAggregationValue">getAggregationValue()</h3>
    +<div class="getaggregationvalue"><p>gets the aggregation value based on the aggregation type for this column</p></div>
    +</li>
    +<li><h3 id="getColClass">getColClass(prefixDot)</h3>
    +<div class="getcolclass"><p>Returns the class name for the column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">prefixDot – {bool} – </code>
    +<p>if true, will return .className instead of className</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getColClassDefinition">getColClassDefinition()</h3>
    +<div class="getcolclassdefinition"><p>Returns the class definition for th column</p></div>
    +</li>
    +<li><h3 id="getRenderContainer">getRenderContainer()</h3>
    +<div class="getrendercontainer"><p>Returns the render container object that this column belongs to.</p>
    +
    +<p>Columns will be default be in the <code>body</code> render container if they aren't allocated to one specifically.</p></div>
    +</li>
    +<li><h3 id="hideColumn">hideColumn()</h3>
    +<div class="hidecolumn"><p>Hides the column by setting colDef.visible = false</p></div>
    +</li>
    +<li><h3 id="setPropertyOrDefault">setPropertyOrDefault(colDef, propName, defaultValue)</h3>
    +<div class="setpropertyordefault"><p>Sets a property on the column using the passed in columnDef, and
    +setting the defaultValue if the value cannot be found on the colDef</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {ColumnDef} – </code>
    +<p>the column def to look in for the property value</p></li>
    +<li><code ng:non-bindable="">propName – {string} – </code>
    +<p>the property name we'd like to set</p></li>
    +<li><code ng:non-bindable="">defaultValue – {object} – </code>
    +<p>the value to use if the colDef doesn't provide the setting</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="showColumn">showColumn()</h3>
    +<div class="showcolumn"><p>Makes the column visible by setting colDef.visible = true</p></div>
    +</li>
    +<li><h3 id="updateColumnDef">updateColumnDef(colDef, isNew)</h3>
    +<div class="updatecolumndef"><p>Moves settings from the columnDef down onto the column,
    +and sets properties as appropriate</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {ColumnDef} – </code>
    +<p>the column def to look in for the property value</p></li>
    +<li><code ng:non-bindable="">isNew – {boolean} – </code>
    +<p>whether the column is being newly created, if not
    +we're updating an existing column, and some items such as the sort shouldn't
    +be copied down</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="displayName">displayName</h3>
    +<div class="displayname"><p>Column name that will be shown in the header.  If displayName is not
    +provided then one is generated using the name.</p></div>
    +</li>
    +<li><h3 id="field">field</h3>
    +<div class="field"><p>field must be provided if you wish to bind to a 
    +property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +See the angular docs on binding expressions.</p></div>
    +</li>
    +<li><h3 id="filter">filter</h3>
    +<div class="filter"><p>Filter on this column.  </p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre></div>
    +</div>
    +</li>
    +<li><h3 id="filters">filters</h3>
    +<div class="filters"><p>Filters for this column. Includes 'term' property bound to filter input elements.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">[
    +{
    +  term: 'foo', // ngModel for &lt;input&gt;
    +  condition: uiGridConstants.filter.STARTS_WITH,
    +  placeholder: 'starts with...',
    +  flags: { caseSensitive: false }
    +},
    +{
    +  term: 'baz',
    +  condition: uiGridConstants.filter.ENDS_WITH,
    +  placeholder: 'ends with...'
    +}
    +] </pre></div>
    +</div>
    +</li>
    +<li><h3 id="name">name</h3>
    +<div class="name"><p>(mandatory) each column should have a name, although for backward
    +compatibility with 2.x name can be omitted if field is present</p></div>
    +</li>
    +<li><h3 id="sortingAlgorithm">sortingAlgorithm</h3>
    +<div class="sortingalgorithm"><p>Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +like any normal sorting function.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridEvents.html b/docs/partials/api/ui.grid.class.GridEvents.html
    new file mode 100644
    index 000000000..2160b8441
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridEvents.html
    @@ -0,0 +1,41 @@
    +<h1><code ng:non-bindable="">GridEvents</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridEvents provides the ability to register public events inside the grid and allow
    +for other components to subscribe to these events via featureName.on.eventName(function(args){}</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridEvents(grid);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>grid that owns these events</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="registerEvent">registerEvent(featureName, eventName)</h3>
    +<div class="registerevent"><p>Registers a new event for the given feature</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">featureName – {string} – </code>
    +<p>name of the feature that raises the event</p></li>
    +<li><code ng:non-bindable="">eventName – {string} – </code>
    +<p>name of the event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="registerEventsFromObject">registerEventsFromObject(eventObjectMap)</h3>
    +<div class="registereventsfromobject"><p>Registers features and events from a simple objectMap.
    +eventObjectMap must be in this format (multiple features allowed)
    +<br>
    +{featureName:
    +       {
    +         eventNameOne:function(args){},
    +         eventNameTwo:function(args){}
    +       }</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">eventObjectMap – {object} – </code>
    +<p>map of feature/event names</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridOptions.columnDef.html b/docs/partials/api/ui.grid.class.GridOptions.columnDef.html
    new file mode 100644
    index 000000000..af9504d9b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridOptions.columnDef.html
    @@ -0,0 +1,228 @@
    +<h1><code ng:non-bindable="">columnDef</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.class:GridOptions</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Definition / configuration of an individual column, which would typically be
    +one of many column definitions within the gridOptions.columnDefs array</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="aggregationHideLabel">aggregationHideLabel</h3>
    +<div class="aggregationhidelabel"><p>defaults to false, if set to true hides the label text
    +in the aggregation footer, so only the value is displayed.</p></div>
    +</li>
    +<li><h3 id="cellClass">cellClass</h3>
    +<div class="cellclass"><p>cellClass can be a string specifying the class to append to a cell
    +or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name</p></div>
    +</li>
    +<li><h3 id="cellFilter">cellFilter</h3>
    +<div class="cellfilter"><p>cellFilter is a filter to apply to the content of each cell</p><h4 id="Example">Example</h4>
    +<div class="example"><p><pre>
    +gridOptions.columnDefs[0].cellFilter = 'date'</p></div>
    +</div>
    +</li>
    +<li><h3 id="cellTemplate">cellTemplate</h3>
    +<div class="celltemplate"><p>a custom template for each cell in this column.  The default
    +is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +must contain a div that can receive focus.</p></div>
    +</li>
    +<li><h3 id="displayName">displayName</h3>
    +<div class="displayname"><p>Column name that will be shown in the header.  If displayName is not
    +provided then one is generated using the name.</p></div>
    +</li>
    +<li><h3 id="enableColumnMenu">enableColumnMenu</h3>
    +<div class="enablecolumnmenu"><p>if column menus are enabled, controls the column menus for this specific
    +column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +using this option. If gridOptions.enableColumnMenus === false then you get no column
    +menus irrespective of the value of this option ).  Defaults to true.</p></div>
    +</li>
    +<li><h3 id="enableColumnMenus">enableColumnMenus</h3>
    +<div class="enablecolumnmenus"><p>Override for column menus everywhere - if set to false then you get no
    +column menus.  Defaults to true.</p></div>
    +</li>
    +<li><h3 id="enableFiltering">enableFiltering</h3>
    +<div class="enablefiltering"><p>turn off filtering for an individual column, where
    +you've turned on filtering for the overall grid</p><h4 id="Example">Example</h4>
    +<div class="example"><p><pre>
    +gridOptions.columnDefs[0].enableFiltering = false;</p></div>
    +</div>
    +</li>
    +<li><h3 id="enableHiding">enableHiding</h3>
    +<div class="enablehiding"><p>(optional) True by default. When set to false, this setting prevents a user from hiding the column
    +using the column menu or the grid menu.</p></div>
    +</li>
    +<li><h3 id="enableSorting">enableSorting</h3>
    +<div class="enablesorting"><p>(optional) True by default. When enabled, this setting adds sort
    +widgets to the column header, allowing sorting of the data in the individual column.</p></div>
    +</li>
    +<li><h3 id="field">field</h3>
    +<div class="field"><p>field must be provided if you wish to bind to a 
    +property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *</p></div>
    +</li>
    +<li><h3 id="filter">filter</h3>
    +<div class="filter"><p>Specify a single filter field on this column.</p>
    +
    +<p>A filter consists of a condition, a term, and a placeholder:</p>
    +
    +<ul>
    +<li>condition defines how rows are chosen as matching the filter term. This can be set to
    +one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +that gets passed the following arguments: [searchTerm, cellValue, row, column].</li>
    +<li>term: If set, the filter field will be pre-populated
    +with this value.</li>
    +<li>placeholder: String that will be set to the <code>&lt;input&gt;.placeholder</code> attribute.</li>
    +<li>noTerm: set this to true if you have defined a custom function in condition, and
    +your custom function doesn't require a term (so it can run even when the term is null)</li>
    +<li>flags: only flag currently available is <code>caseSensitive</code>, set to false if you don't want
    +case sensitive matching</li>
    +</ul><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">$scope.gridOptions.columnDefs = [ 
    +{
    +  field: 'field1',
    +  filter: {
    +    term: 'xx',
    +    condition: uiGridConstants.filter.STARTS_WITH,
    +    placeholder: 'starts with...',
    +    flags: { caseSensitive: false }
    +  }
    +}
    +]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="filters">filters</h3>
    +<div class="filters"><p>Specify multiple filter fields.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">$scope.gridOptions.columnDefs = [ 
    +{
    +  field: 'field1', filters: [
    +    {
    +      term: 'aa',
    +      condition: uiGridConstants.filter.STARTS_WITH,
    +      placeholder: 'starts with...',
    +      flags: { caseSensitive: false }
    +    },
    +    {
    +      condition: uiGridConstants.filter.ENDS_WITH,
    +      placeholder: 'ends with...'
    +    }
    +  ]
    +}
    +]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="footerCellClass">footerCellClass</h3>
    +<div class="footercellclass"><p>footerCellClass can be a string specifying the class to append to a cell
    +or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name</p></div>
    +</li>
    +<li><h3 id="footerCellFilter">footerCellFilter</h3>
    +<div class="footercellfilter"><p>footerCellFilter is a filter to apply to the content of the column footer</p><h4 id="Example">Example</h4>
    +<div class="example"><p><pre>
    +gridOptions.columnDefs[0].footerCellFilter = 'date'</p></div>
    +</div>
    +</li>
    +<li><h3 id="footerCellTemplate">footerCellTemplate</h3>
    +<div class="footercelltemplate"><p>a custom template for the footer for this column.  The default
    +is ui-grid/uiGridFooterCell</p></div>
    +</li>
    +<li><h3 id="headerCellClass">headerCellClass</h3>
    +<div class="headercellclass"><p>headerCellClass can be a string specifying the class to append to a cell
    +or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name</p></div>
    +</li>
    +<li><h3 id="headerCellFilter">headerCellFilter</h3>
    +<div class="headercellfilter"><p>headerCellFilter is a filter to apply to the content of the column header</p><h4 id="Example">Example</h4>
    +<div class="example"><p><pre>
    +gridOptions.columnDefs[0].headerCellFilter = 'translate'</p></div>
    +</div>
    +</li>
    +<li><h3 id="headerCellTemplate">headerCellTemplate</h3>
    +<div class="headercelltemplate"><p>a custom template for the header for this column.  The default
    +is ui-grid/uiGridHeaderCell</p></div>
    +</li>
    +<li><h3 id="maxWidth">maxWidth</h3>
    +<div class="maxwidth"><p>sets the maximum column width.  Should be a number.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="menuItems">menuItems</h3>
    +<div class="menuitems"><p>used to add menu items to a column.  Refer to the tutorial on this 
    +functionality.  A number of settings are supported:</p>
    +
    +<ul>
    +<li>title: controls the title that is displayed in the menu</li>
    +<li>icon: the icon shown alongside that title</li>
    +<li>action: the method to call when the menu is clicked</li>
    +<li>shown: a function to evaluate to determine whether or not to show the item</li>
    +<li>active: a function to evaluate to determine whether or not the item is currently selected</li>
    +<li>context: context to pass to the action function??</li>
    +</ul><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ 
    +{ field: 'field1', menuItems: [
    +  {
    +    title: 'Outer Scope Alert',
    +    icon: 'ui-grid-icon-info-circled',
    +    action: function($event) {
    +      this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    },
    +    shown: function() { return true; },
    +    active: function() { return true; },
    +    context: $scope
    +  },
    +  {
    +    title: 'Grid ID',
    +    action: function() {
    +      alert('Grid ID: ' + this.grid.id);
    +    }
    +  }
    +] }]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="minWidth">minWidth</h3>
    +<div class="minwidth"><p>sets the minimum column width.  Should be a number.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="name">name</h3>
    +<div class="name"><p>(mandatory) each column should have a name, although for backward
    +compatibility with 2.x name can be omitted if field is present</p></div>
    +</li>
    +<li><h3 id="sort">sort</h3>
    +<div class="sort"><p>Can be used to set the sort direction for the column, values are
    +uiGridConstants.ASC or uiGridConstants.DESC</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre></div>
    +</div>
    +</li>
    +<li><h3 id="sortingAlgorithm">sortingAlgorithm</h3>
    +<div class="sortingalgorithm"><p>Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +like any normal sorting function.</p></div>
    +</li>
    +<li><h3 id="suppressRemoveSort">suppressRemoveSort</h3>
    +<div class="suppressremovesort"><p>(optional) False by default. When enabled, this setting hides the removeSort option
    +in the menu.</p></div>
    +</li>
    +<li><h3 id="type">type</h3>
    +<div class="type"><p>the type of the column, used in sorting.  If not provided then the 
    +grid will guess the type.  Add this only if the grid guessing is not to your
    +satisfaction.  Refer to <a href="#/api/ui.grid.service:GridUtil.guessType">gridUtil.guessType</a> for
    +a list of values the grid knows about.</p></div>
    +</li>
    +<li><h3 id="visible">visible</h3>
    +<div class="visible"><p>sets whether or not the column is visible
    +</br>Default is true</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ 
    +{ field: 'field1', visible: true},
    +{ field: 'field2', visible: false }
    +]; </pre></div>
    +</div>
    +</li>
    +<li><h3 id="width">width</h3>
    +<div class="width"><p>sets the column width.  Can be either 
    +a number or a percentage, or an * for auto.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +{ field: 'field2', width: '20%'},
    +{ field: 'field3', width: '*' }]; </pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><pre class="prettyprint linenums">{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridOptions.html b/docs/partials/api/ui.grid.class.GridOptions.html
    new file mode 100644
    index 000000000..e9a8ca927
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridOptions.html
    @@ -0,0 +1,279 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +over this object.  Setting gridOptions within your controller is the most common method for an application 
    +developer to configure the behaviour of their ui-grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridOptions();</pre>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getRowIdentity">getRowIdentity()</h3>
    +<div class="getrowidentity"><p>This function returns the identity value uniquely identifying this row, if one is not present it does not set it.</p>
    +
    +<p>By default it returns the <code>$$hashKey</code> property but can be overridden to use any property or set of properties you want.</p></div>
    +</li>
    +<li><h3 id="rowEquality">rowEquality(entityA, entityB)</h3>
    +<div class="rowequality"><p>By default, rows are compared using object equality.  This option can be overridden
    +to compare on any data item property or function</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">entityA – {object} – </code>
    +<p>First Data Item to compare</p></li>
    +<li><code ng:non-bindable="">entityB – {object} – </code>
    +<p>Second Data Item to compare</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="rowIdentity">rowIdentity()</h3>
    +<div class="rowidentity"><p>This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).</p>
    +
    +<p>By default it returns the <code>$$hashKey</code> property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one</p></div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="addToGridMenu">addToGridMenu</h3>
    +<div class="addtogridmenu"><p>add items to the grid menu.  Used by features
    +to add their menu items if they are enabled, can also be used by
    +end users to add menu items.  This method has the advantage of allowing
    +remove again, which can simplify management of which items are included
    +in the menu when.  (Noting that in most cases the shown and active functions
    +provide a better way to handle visibility of menu items)</p></div>
    +</li>
    +<li><h3 id="appScopeProvider">appScopeProvider</h3>
    +<div class="appscopeprovider"><p>by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +this property allows you to assign any reference you want to grid.appScope</p></div>
    +</li>
    +<li><h3 id="columnDefs">columnDefs</h3>
    +<div class="columndefs"><p>Array of columnDef objects.  Only required property is name.
    +The individual options available in columnDefs are documented in the
    +<a href="#/api/ui.grid.class:GridOptions.columnDef">columnDef</a> section
    +</br><em>field property can be used in place of name for backwards compatibility with 2.x</em></p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">var columnDefs = [{name:'field1'}, {name:'field2'}];</pre></div>
    +</div>
    +</li>
    +<li><h3 id="columnFooterHeight">columnFooterHeight</h3>
    +<div class="columnfooterheight"><p>The height of the footer rows (column footer and grid footer) in pixels</p></div>
    +</li>
    +<li><h3 id="columnVirtualizationThreshold">columnVirtualizationThreshold</h3>
    +<div class="columnvirtualizationthreshold"><p>Turn virtualization on when number of columns goes over this number, defaults to 10</p></div>
    +</li>
    +<li><h3 id="data">data</h3>
    +<div class="data"><p>(mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +an angularJS $resource query request.  The array can also contain complex objects.</p></div>
    +</li>
    +<li><h3 id="enableColumnMenus">enableColumnMenus</h3>
    +<div class="enablecolumnmenus"><p>True by default. When enabled, this setting displays a column
    +menu within each column.</p></div>
    +</li>
    +<li><h3 id="enableFiltering">enableFiltering</h3>
    +<div class="enablefiltering"><p>False by default. When enabled, this setting adds filter 
    +boxes to each column header, allowing filtering within the column for the entire grid.
    +Filtering can then be disabled on individual columns using the columnDefs. </p></div>
    +</li>
    +<li><h3 id="enableHorizontalScrollbar">enableHorizontalScrollbar</h3>
    +<div class="enablehorizontalscrollbar"><p>uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER</p></div>
    +</li>
    +<li><h3 id="enableRowHashing">enableRowHashing</h3>
    +<div class="enablerowhashing"><p>True by default. When enabled, this setting allows uiGrid to add
    +<code>$$hashKey</code>-type properties (similar to Angular) to elements in the <code>data</code> array. This allows
    +the grid to maintain state while vastly speeding up the process of altering <code>data</code> by adding/moving/removing rows.</p>
    +
    +<p>Note that this DOES add properties to your data that you may not want, but they are stripped out when using <code>angular.toJson()</code>. IF
    +you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +and are altering the data set often.</p></div>
    +</li>
    +<li><h3 id="enableSorting">enableSorting</h3>
    +<div class="enablesorting"><p>True by default. When enabled, this setting adds sort
    +widgets to the column headers, allowing sorting of the data for the entire grid.
    +Sorting can then be disabled on individual columns using the columnDefs.</p></div>
    +</li>
    +<li><h3 id="enableVerticalScrollbar">enableVerticalScrollbar</h3>
    +<div class="enableverticalscrollbar"><p>uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER</p></div>
    +</li>
    +<li><h3 id="excessColumns">excessColumns</h3>
    +<div class="excesscolumns"><p>Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +Defaults to 4</p></div>
    +</li>
    +<li><h3 id="excessRows">excessRows</h3>
    +<div class="excessrows"><p>Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +Defaults to 4</p></div>
    +</li>
    +<li><h3 id="excludeProperties">excludeProperties</h3>
    +<div class="excludeproperties"><p>Array of property names in data to ignore when auto-generating column names.  Provides the
    +inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +to exclude. </p>
    +
    +<p>If columnDefs is defined, this will be ignored.</p>
    +
    +<p>Defaults to ['$$hashKey']</p></div>
    +</li>
    +<li><h3 id="footerTemplate">footerTemplate</h3>
    +<div class="footertemplate"><p>(optional) Null by default. When provided, this setting uses a custom footer
    +template. Can be set to either the name of a template file 'footer_template.html', inline html
    +<pre class="prettyprint linenums">'&lt;div class="ui-grid-bottom-panel" style="text-align: center"&gt;I am a Custom Grid Footer&lt;/div&gt;'</pre>, or the id
    +of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.</p></div>
    +</li>
    +<li><h3 id="gridMenuCustomItems">gridMenuCustomItems</h3>
    +<div class="gridmenucustomitems"><p>(optional) An array of menu items that should be added to
    +the gridMenu.  Follow the format documented in the tutorial for column
    +menu customisation.  The context provided to the action function will 
    +include context.grid.  An alternative if working with dynamic menus is to use the 
    +provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +some of the management of items for you.</p></div>
    +</li>
    +<li><h3 id="gridMenuShowHideColumns">gridMenuShowHideColumns</h3>
    +<div class="gridmenushowhidecolumns"><p>true by default, whether the grid menu should allow hide/show
    +of columns</p></div>
    +</li>
    +<li><h3 id="gridMenuTitleFilter">gridMenuTitleFilter</h3>
    +<div class="gridmenutitlefilter"><p>(optional) A function that takes a title string 
    +(usually the col.displayName), and converts it into a display value.  The function
    +must return either a string or a promise.</p>
    +
    +<p>Used for internationalization of the grid menu column names - for angular-translate
    +you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +function</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions = {
    +  gridMenuTitleFilter: $translate
    +}
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="headerRowHeight">headerRowHeight</h3>
    +<div class="headerrowheight"><p>The height of the header in pixels, defaults to 30</p></div>
    +</li>
    +<li><h3 id="headerTemplate">headerTemplate</h3>
    +<div class="headertemplate"><p>Null by default. When provided, this setting uses a custom header
    +template, rather than the default template. Can be set to either the name of a template file:
    +<pre class="prettyprint linenums">  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +inline html 
    +<pre class="prettyprint linenums">  $scope.gridOptions.headerTemplate = '&lt;div class="ui-grid-top-panel" style="text-align: center"&gt;I am a Custom Grid Header&lt;/div&gt;'</pre>
    +or the id of a precompiled template (TBD how to use this). <br />
    +</br>Refer to the custom header tutorial for more information.
    +If you want no header at all, you can set to an empty div:
    +<pre class="prettyprint linenums">  $scope.gridOptions.headerTemplate = '&lt;div&gt;&lt;/div&gt;';</pre>
    +
    +<p>If you want to only have a static header, then you can set to static content.  If
    +you want to tailor the existing column headers, then you should look at the
    +current 'ui-grid-header.html' template in github as your starting point.</p></div>
    +</li>
    +<li><h3 id="horizontalScrollThreshold">horizontalScrollThreshold</h3>
    +<div class="horizontalscrollthreshold"><p>Defaults to 4</p></div>
    +</li>
    +<li><h3 id="infiniteScrollPercentage">infiniteScrollPercentage</h3>
    +<div class="infinitescrollpercentage"><p>This setting controls at what percentage of the scroll more data
    +is requested by the infinite scroll</p></div>
    +</li>
    +<li><h3 id="maxVisibleColumnCount">maxVisibleColumnCount</h3>
    +<div class="maxvisiblecolumncount"><p>Defaults to 200</p></div>
    +</li>
    +<li><h3 id="minRowsToShow">minRowsToShow</h3>
    +<div class="minrowstoshow"><p>Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".</p></div>
    +</li>
    +<li><h3 id="minimumColumnSize">minimumColumnSize</h3>
    +<div class="minimumcolumnsize"><p>Columns can't be smaller than this, defaults to 10 pixels</p></div>
    +</li>
    +<li><h3 id="onRegisterApi">onRegisterApi</h3>
    +<div class="onregisterapi"><p>A callback that returns the gridApi once the grid is instantiated, which is 
    +then used to interact with the grid programatically.</p>
    +
    +<p>Note that the gridApi.core.renderingComplete event is identical to this 
    +callback, but has the advantage that it can be called from multiple places
    +if needed</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +  $scope.gridApi = gridApi;
    +  $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +};
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="rowHeight">rowHeight</h3>
    +<div class="rowheight"><p>The height of the row in pixels, defaults to 30</p></div>
    +</li>
    +<li><h3 id="rowTemplate">rowTemplate</h3>
    +<div class="rowtemplate"><p>'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +custom row template.  Can be set to either the name of a template file:
    +<pre class="prettyprint linenums"> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +inline html 
    +<pre class="prettyprint linenums">  $scope.gridOptions.rowTemplate = '&lt;div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell&gt;&lt;/div&gt;';</pre>
    +or the id of a precompiled template (TBD how to use this) can be provided. <br />
    +</br>Refer to the custom row template tutorial for more information.</p></div>
    +</li>
    +<li><h3 id="scrollThreshold">scrollThreshold</h3>
    +<div class="scrollthreshold"><p>Defaults to 4</p></div>
    +</li>
    +<li><h3 id="scrollThrottle">scrollThrottle</h3>
    +<div class="scrollthrottle"><p>Default time to throttle scroll events to, defaults to 70ms</p></div>
    +</li>
    +<li><h3 id="showColumnFooter">showColumnFooter</h3>
    +<div class="showcolumnfooter"><p>Whether or not to show the column footer, defaults to false
    +The column footer displays column aggregates</p></div>
    +</li>
    +<li><h3 id="showGridFooter">showGridFooter</h3>
    +<div class="showgridfooter"><p>Whether or not to show the footer, defaults to false
    +The footer display Total Rows and Visible Rows (filtered rows)</p></div>
    +</li>
    +<li><h3 id="showHeader">showHeader</h3>
    +<div class="showheader"><p>True by default. When set to false, this setting will replace the
    +standard header template with '<div>
    +</div>', resulting in no header being shown.</p>
    +
    +<p>It will also set the <code>headerRowHeight</code> option to 0.</p></div>
    +</li>
    +<li><h3 id="useExternalFiltering">useExternalFiltering</h3>
    +<div class="useexternalfiltering"><p>False by default. When enabled, this setting suppresses the internal filtering.
    +All UI logic will still operate, allowing filter conditions to be set and modified.</p>
    +
    +<p>The external filter logic can listen for the <code>filterChange</code> event, which fires whenever
    +a filter has been adjusted.</p></div>
    +</li>
    +<li><h3 id="useExternalSorting">useExternalSorting</h3>
    +<div class="useexternalsorting"><p>Prevents the internal sorting from executing.  Events will
    +still be fired when the sort changes, and the sort information on
    +the columns will be updated, allowing an external sorter (for example,
    +server sorting) to be implemented.  Defaults to false. </p></div>
    +</li>
    +<li><h3 id="virtualizationThreshold">virtualizationThreshold</h3>
    +<div class="virtualizationthreshold"><p>Turn virtualization on when number of data elements goes over this number, defaults to 20</p></div>
    +</li>
    +</ul>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><p>To define your gridOptions within your controller:
    +<pre class="prettyprint linenums">$scope.gridOptions = {
    +  data: $scope.myData,
    +  columnDefs: [ 
    +    { name: 'field1', displayName: 'pretty display name' },
    +    { name: 'field2', visible: false }
    + ]
    +};</pre>
    +
    +<p>You can then use this within your html template, when you define your grid:
    +<pre class="prettyprint linenums">&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +
    +<p>To provide default options for all of the grids within your application, use an angular
    +decorator to modify the GridOptions factory.
    +<pre class="prettyprint linenums">
    +app.config(function($provide){
    +  $provide.decorator('GridOptions',function($delegate){
    +    var gridOptions;
    +    gridOptions = angular.copy($delegate);
    +    gridOptions.initialize = function(options) {
    +      var initOptions;
    +      initOptions = $delegate.initialize(options);
    +      initOptions.enableColumnMenus = false;
    +      return initOptions;
    +    };
    +    return gridOptions;
    +  });
    +});
    +</pre></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridRenderContainer.html b/docs/partials/api/ui.grid.class.GridRenderContainer.html
    new file mode 100644
    index 000000000..f3b741cf6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridRenderContainer.html
    @@ -0,0 +1,60 @@
    +<h1><code ng:non-bindable="">GridRenderContainer</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +is right-to-left then there may be a right render container, if left-to-right then there may 
    +be a left render container.  There is always a body render container.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridRenderContainer(name, grid, options);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">name – {string} – </code>
    +<p>The name of the render container ('body', 'left', or 'right')</p></li>
    +<li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid the render container is in</p></li>
    +<li><code ng:non-bindable="">options – {object} – </code>
    +<p>the render container options</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getCanvasHeight">getCanvasHeight()</h3>
    +<div class="getcanvasheight"><p>Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>total height of all the visible rows in the container</p></div>
    +</div>
    +</li>
    +<li><h3 id="getViewportAdjustment">getViewportAdjustment()</h3>
    +<div class="getviewportadjustment"><p>Gets the adjustment based on the viewportAdjusters.  </p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>a hash of { height: x, width: y }.  Usually the values will be negative</p></div>
    +</div>
    +</li>
    +<li><h3 id="registerViewportAdjuster">registerViewportAdjuster(func)</h3>
    +<div class="registerviewportadjuster"><p>Registers an adjuster to the render container's available width or height.  Adjusters are used
    +to tell the render container that there is something else consuming space, and to adjust it's size
    +appropriately.  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">func – {function} – </code>
    +<p>the adjuster function we want to register</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="removeViewportAdjuster">removeViewportAdjuster(func)</h3>
    +<div class="removeviewportadjuster"><p>Removes an adjuster, should be used when your element is destroyed</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">func – {function} – </code>
    +<p>the adjuster function we want to remove</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="canvasHeight">canvasHeight</h3>
    +<div class="canvasheight"><p>last calculated canvas height value</p></div>
    +</li>
    +<li><h3 id="canvasHeightShouldUpdate">canvasHeightShouldUpdate</h3>
    +<div class="canvasheightshouldupdate"><p>flag to signal that container should recalculate the canvas size</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.GridRow.html b/docs/partials/api/ui.grid.class.GridRow.html
    new file mode 100644
    index 000000000..89ab4c44b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.GridRow.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +relation to gridOptions.data.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">GridRow(entity, index, reference);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">entity – {object} – </code>
    +<p>the array item from GridOptions.data</p></li>
    +<li><code ng:non-bindable="">index – {number} – </code>
    +<p>the current position of the row in the array</p></li>
    +<li><code ng:non-bindable="">reference – {Grid} – </code>
    +<p>to the parent grid</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="clearRowInvisible">clearRowInvisible(row)</h3>
    +<div class="clearrowinvisible"><p>Clears any override on the row visibility, returning it 
    +to normal visibility calculations.  If the row is currently invisible
    +then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +event
    +TODO: if filter in action, then is this right?</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>row clear force invisible, needs to be a GridRow,
    +which can be found from your data entity using grid.findRow</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getEntityQualifiedColField">getEntityQualifiedColField(col)</h3>
    +<div class="getentityqualifiedcolfield"><p>returns the qualified field name minus the row path
    +ie: entity.fieldA</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">col – {GridCol} – </code>
    +<p>column instance</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>resulting name that can be evaluated against a row</p></div>
    +</div>
    +</li>
    +<li><h3 id="getQualifiedColField">getQualifiedColField(col)</h3>
    +<div class="getqualifiedcolfield"><p>returns the qualified field name as it exists on scope
    +ie: row.entity.fieldA</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">col – {GridCol} – </code>
    +<p>column instance</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>resulting name that can be evaluated on scope</p></div>
    +</div>
    +</li>
    +<li><h3 id="setRowInvisible">setRowInvisible(row)</h3>
    +<div class="setrowinvisible"><p>Sets an override on the row that forces it to always
    +be invisible, and if the row is currently visible then marks it
    +as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +event if it changed the row visibility</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>row to force invisible, needs to be a GridRow,
    +which can be found from your data entity using grid.findRow</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="entity">entity</h3>
    +<div class="entity"><p>A reference to an item in gridOptions.data[]</p></div>
    +</li>
    +<li><h3 id="grid">grid</h3>
    +<div class="grid"><p>A reference back to the grid</p></div>
    +</li>
    +<li><h3 id="height">height</h3>
    +<div class="height"><p>height of each individual row. changing the height will flag all
    +row renderContainers to recalculate their canvas height</p></div>
    +</li>
    +<li><h3 id="uid">uid</h3>
    +<div class="uid"><p>UniqueId of row</p></div>
    +</li>
    +<li><h3 id="visible">visible</h3>
    +<div class="visible"><p>If true, the row will be rendered</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.RowSorter.html b/docs/partials/api/ui.grid.class.RowSorter.html
    new file mode 100644
    index 000000000..3ac2206cd
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.RowSorter.html
    @@ -0,0 +1,164 @@
    +<h1><code ng:non-bindable="">RowSorter</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>RowSorter provides the default sorting mechanisms, 
    +including guessing column types and applying appropriate sort 
    +algorithms</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="basicSort">basicSort(a, b)</h3>
    +<div class="basicsort"><p>Sorts any values that provide the &lt; method, including strings
    +or numbers.  Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="getSortFn">getSortFn(grid, col, rows)</h3>
    +<div class="getsortfn"><p>Get the sort function for the column.  Looks first in 
    +rowSorter.colSortFnCache using the column name, failing that it
    +looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +it guesses the sort algorithm based on the data type.</p>
    +
    +<p>The cache currently seems a bit pointless, as none of the work we do is
    +processor intensive enough to need caching.  Presumably in future we might
    +inspect the row data itself to guess the sort function, and in that case
    +it would make sense to have a cache, the infrastructure is in place to allow
    +that.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid to consider</p></li>
    +<li><code ng:non-bindable="">col – {GridCol} – </code>
    +<p>the column to find a function for</p></li>
    +<li><code ng:non-bindable="">rows – {array} – </code>
    +<p>an array of grid rows.  Currently unused, but presumably in future
    +we might inspect the rows themselves to decide what sort of data might be there</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>the sort function chosen for the column</p></div>
    +</div>
    +</li>
    +<li><h3 id="guessSortFn">guessSortFn(itemType)</h3>
    +<div class="guesssortfn"><p>Assigns a sort function to use based on the itemType in the column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">itemType – {string} – </code>
    +<p>one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +error will be thrown for any other type.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>a sort function that will sort that type</p></div>
    +</div>
    +</li>
    +<li><h3 id="handleNulls">handleNulls(a, b)</h3>
    +<div class="handlenulls"><p>Sorts nulls and undefined to the bottom (top when
    +descending).  Called by each of the internal sorters before
    +attempting to sort.  Note that this method is available on the core api
    +via gridApi.core.sortHandleNulls</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>null if there were no nulls/undefineds, otherwise returns
    +a sort value that should be passed back from the sort function</p></div>
    +</div>
    +</li>
    +<li><h3 id="prioritySort">prioritySort(a, b)</h3>
    +<div class="prioritysort"><p>Used where multiple columns are present in the sort criteria,
    +we determine which column should take precedence in the sort by sorting
    +the columns based on their sort.priority</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {gridColumn} – </code>
    +<p>column a</p></li>
    +<li><code ng:non-bindable="">b – {gridColumn} – </code>
    +<p>column b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="sort">sort(grid, rows, columns)</h3>
    +<div class="sort"><p>sorts the grid </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Object} – </code>
    +<p>the grid itself</p></li>
    +<li><code ng:non-bindable="">rows – {Object} – </code>
    +<p>the rows to be sorted</p></li>
    +<li><code ng:non-bindable="">columns – {Object} – </code>
    +<p>the columns in which to look
    +for sort criteria</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="sortAlpha">sortAlpha(a, b)</h3>
    +<div class="sortalpha"><p>Sorts string values. Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="sortBool">sortBool(a, b)</h3>
    +<div class="sortbool"><p>Sorts boolean values, true is considered larger than false. 
    +Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="sortDate">sortDate(a, b)</h3>
    +<div class="sortdate"><p>Sorts date values. Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="sortNumber">sortNumber(a, b)</h3>
    +<div class="sortnumber"><p>Sorts numerical values.  Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +<li><h3 id="sortNumberStr">sortNumberStr(a, b)</h3>
    +<div class="sortnumberstr"><p>Sorts numerical values that are stored in a string (i.e. parses them to numbers first). <br />
    +Handles nulls and undefined through calling handleNulls </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>normal sort function, returns -ve, 0, +ve</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.class.ScrollEvent.html b/docs/partials/api/ui.grid.class.ScrollEvent.html
    new file mode 100644
    index 000000000..7bc30b6f1
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.class.ScrollEvent.html
    @@ -0,0 +1,44 @@
    +<h1><code ng:non-bindable="">ScrollEvent</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Model for all scrollEvents</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage"><pre class="prettyprint linenums">ScrollEvent(grid, sourceRowContainer, sourceColContainer, source);</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>that owns the scroll event</p></li>
    +<li><code ng:non-bindable="">sourceRowContainer – {GridRenderContainer} – </code>
    +<p>that owns the scroll event. Can be null</p></li>
    +<li><code ng:non-bindable="">sourceColContainer – {GridRenderContainer} – </code>
    +<p>that owns the scroll event. Can be null</p></li>
    +<li><code ng:non-bindable="">source – {string} – </code>
    +<p>the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName</p></li>
    +</ul>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="fireScrollingEvent">fireScrollingEvent()</h3>
    +<div class="firescrollingevent"><p>fires an event using grid.api.core.raise.scrollEvent</p></div>
    +</li>
    +<li><h3 id="fireThrottledScrollingEvent">fireThrottledScrollingEvent()</h3>
    +<div class="firethrottledscrollingevent"><p>fires a throttled event using grid.api.core.raise.scrollEvent</p></div>
    +</li>
    +<li><h3 id="getNewScrollLeft">getNewScrollLeft()</h3>
    +<div class="getnewscrollleft"><p>returns newScrollLeft property if available; calculates a new value if it isn't</p></div>
    +</li>
    +<li><h3 id="getNewScrollTop">getNewScrollTop()</h3>
    +<div class="getnewscrolltop"><p>returns newScrollTop property if available; calculates a new value if it isn't</p></div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="entity">entity</h3>
    +<div class="entity"><p>the source of the scroll event. limited to values from uiGridConstants.scrollEventSources</p></div>
    +</li>
    +<li><h3 id="grid">grid</h3>
    +<div class="grid"><p>A reference back to the grid</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.core.api.PublicApi.html b/docs/partials/api/ui.grid.core.api.PublicApi.html
    new file mode 100644
    index 000000000..25cbe7f5c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.core.api.PublicApi.html
    @@ -0,0 +1,231 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.core</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for the core grid features</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="addRowHeaderColumn">addRowHeaderColumn(column)</h3>
    +<div class="addrowheadercolumn"><p>adds a row header column to the grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">column – {object} – </code>
    +<p>def</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="addToGridMenu">addToGridMenu(grid, items)</h3>
    +<div class="addtogridmenu"><p>add items to the grid menu.  Used by features
    +to add their menu items if they are enabled, can also be used by
    +end users to add menu items.  This method has the advantage of allowing
    +remove again, which can simplify management of which items are included
    +in the menu when.  (Noting that in most cases the shown and active functions
    +provide a better way to handle visibility of menu items)</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid on which we are acting</p></li>
    +<li><code ng:non-bindable="">items – {array} – </code>
    +<p>menu items in the format as described in the tutorial, with 
    +the added note that if you want to use remove you must also specify an <code>id</code> field,
    +which is provided when you want to remove an item.  The id should be unique.</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="clearRowInvisible">clearRowInvisible(rowEntity)</h3>
    +<div class="clearrowinvisible"><p>Clears any override on visibility for the row so that it returns to 
    +using normal filtering and other visibility calculations. <br />
    +If the row is currently invisible then sets it to visible and calls
    +both grid refresh and emits the rowsVisibleChanged event
    +TODO: if a filter is active then we can't just set it to visible?</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="columnVisibilityChanged">columnVisibilityChanged(column)</h3>
    +<div class="columnvisibilitychanged"><p>The visibility of a column has changed,
    +the column itself is passed out as a parameter of the event. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>the column that changed</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridApi.core.on.columnVisibilityChanged( $scope, function (column) {
    +  // do something
    +} );
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="getVisibleRows">getVisibleRows(grid)</h3>
    +<div class="getvisiblerows"><p>Returns all visible rows</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid you want to get visible rows from</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>an array of gridRow</p></div>
    +</div>
    +</li>
    +<li><h3 id="handleWindowResize">handleWindowResize()</h3>
    +<div class="handlewindowresize"><p>Trigger a grid resize, normally this would be picked
    +up by a watch on window size, but in some circumstances it is necessary
    +to call this manually</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that is resolved when render completes?</p></div>
    +</div>
    +</li>
    +<li><h3 id="notifyDataChange">notifyDataChange(type)</h3>
    +<div class="notifydatachange"><p>Notify the grid that a data or config change has occurred,
    +where that change isn't something the grid was otherwise noticing.  This 
    +might be particularly relevant where you've changed values within the data
    +and you'd like cell classes to be re-evaluated, or changed config within 
    +the columnDef and you'd like headerCellClasses to be re-evaluated.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">type – {string} – </code>
    +<p>one of the 
    +uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +us which refreshes to fire.</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="refresh">refresh()</h3>
    +<div class="refresh"><p>Refresh the rendered grid on screen.</p></div>
    +</li>
    +<li><h3 id="refreshRows">refreshRows()</h3>
    +<div class="refreshrows"><p>Refresh the rendered grid on screen?  Note: not functional at present</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that is resolved when render completes?</p></div>
    +</div>
    +</li>
    +<li><h3 id="removeFromGridMenu">removeFromGridMenu(grid, id)</h3>
    +<div class="removefromgridmenu"><p>Remove an item from the grid menu based on a provided id. Assumes
    +that the id is unique, removes only the last instance of that id. Does nothing if
    +the specified id is not found</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid on which we are acting</p></li>
    +<li><code ng:non-bindable="">id – {string} – </code>
    +<p>the id we'd like to remove from the menu</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="removeFromGridMenu">removeFromGridMenu(grid, id)</h3>
    +<div class="removefromgridmenu"><p>Remove an item from the grid menu based on a provided id.  Assumes
    +that the id is unique, removes only the last instance of that id.  Does nothing if
    +the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +then do nothing silently - the desired result is those menu items not be present and they
    +aren't.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid on which we are acting</p></li>
    +<li><code ng:non-bindable="">id – {string} – </code>
    +<p>the id we'd like to remove from the menu</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="renderingComplete">renderingComplete(gridApi)</h3>
    +<div class="renderingcomplete"><p>Rendering is complete, called at the same
    +time as <code>onRegisterApi</code>, but provides a way to obtain
    +that same event within features without stopping end
    +users from getting at the onRegisterApi method.</p>
    +
    +<p>Included in gridApi so that it's always there - otherwise
    +there is still a timing problem with when a feature can
    +call this. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridApi – {GridApi} – </code>
    +<p>the grid api, as normally 
    +returned in the onRegisterApi method</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridApi.core.on.renderingComplete( grid );
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="setRowInvisible">setRowInvisible(rowEntity)</h3>
    +<div class="setrowinvisible"><p>Sets an override on the row to make it always invisible,
    +which will override any filtering or other visibility calculations. <br />
    +If the row is currently visible then sets it to invisible and calls
    +both grid refresh and emits the rowsVisibleChanged event</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="sortChanged">sortChanged(grid, sortColumns)</h3>
    +<div class="sortchanged"><p>The sort criteria on one or more columns has
    +changed.  Provides as parameters the grid and the output of
    +getColumnSorting, which is an array of gridColumns
    +that have sorting on them, sorted in priority order. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid</p></li>
    +<li><code ng:non-bindable="">sortColumns – {array} – </code>
    +<p>an array of columns with 
    +sorts on them, in priority order</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridApi.core.on.sortChanged( grid, sortColumns );
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="sortHandleNulls">sortHandleNulls(a, b)</h3>
    +<div class="sorthandlenulls"><p>A null handling method that can be used when building custom sort
    +functions</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">a – {object} – </code>
    +<p>sort value a</p></li>
    +<li><code ng:non-bindable="">b – {object} – </code>
    +<p>sort value b</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>null if there were no nulls/undefineds, otherwise returns
    +a sort value that should be passed back from the sort function</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +mySortFn = function(a, b) {
    +var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +if ( nulls !== null ){
    +  return nulls;
    +} else {
    +  // your code for sorting here
    +};
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="canvasHeightChanged">canvasHeightChanged</h3>
    +<div class="canvasheightchanged"><p>is raised when the canvas height has changed
    +<br/>
    +arguments: oldHeight, newHeight</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +<li><h3 id="filterChanged">filterChanged</h3>
    +<div class="filterchanged"><p>is raised after the filter is changed.  The nature
    +of the watch expression doesn't allow notification of what changed,
    +so the receiver of this event will need to re-extract the filter 
    +conditions from the columns.</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +<li><h3 id="rowsRendered">rowsRendered</h3>
    +<div class="rowsrendered"><p>is raised after the cache of visible rows is changed.</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +<li><h3 id="rowsVisibleChanged">rowsVisibleChanged</h3>
    +<div class="rowsvisiblechanged"><p>is raised after the rows that are visible
    +change.  The filtering is zero-based, so it isn't possible
    +to say which rows changed (unlike in the selection feature).
    +We can plausibly know which row was changed when setRowInvisible
    +is called, but in that situation the user already knows which row
    +they changed.  When a filter runs we don't know what changed,
    +and that is the one that would have been useful.</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +<li><h3 id="scrollEvent">scrollEvent</h3>
    +<div class="scrollevent"><p>is raised on a scroll Event.  Called frequently so be careful what you do with it</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.core.html b/docs/partials/api/ui.grid.core.html
    new file mode 100644
    index 000000000..ddf7a58bc
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.core.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">core</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Not sure this needs to be defined, I'll see</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.directive.uiGrid.html b/docs/partials/api/ui.grid.directive.uiGrid.html
    new file mode 100644
    index 000000000..6ff15c41a
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.directive.uiGrid.html
    @@ -0,0 +1,45 @@
    +<h1><code ng:non-bindable="">uiGrid</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Create a very basic grid.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as element:<pre class="prettyprint linenums">&lt;ui-grid
    +       uiGrid="{Object}"&gt;
    +&lt;/ui-grid&gt;</pre>
    +as attribute<pre class="prettyprint linenums">&lt;div ui-grid="{Object}"&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +<h3 id="Parameters">Parameters</h3>
    +<ul class="parameters"><li><code ng:non-bindable="">uiGrid – {Object} – </code>
    +<p>Options for the grid to use</p></li>
    +</ul>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-17" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-17" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-17">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="{ data: data }"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.data = [
    +      { name: 'Bob', title: 'CEO' },
    +      { name: 'Frank', title: 'Lowly Developer' }
    +    ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-17" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.directive.uiGridColumnMenu.html b/docs/partials/api/ui.grid.directive.uiGridColumnMenu.html
    new file mode 100644
    index 000000000..2887cbbbc
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.directive.uiGridColumnMenu.html
    @@ -0,0 +1,67 @@
    +<h1><code ng:non-bindable="">uiGridColumnMenu</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Allows us to interpolate expressions in <code>&lt;style&gt;</code> elements. Angular doesn't do this by default as it can/will/might? break in IE8.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;style ui-grid-column-menu&gt;
    +   ...
    +&lt;/style&gt;</pre>
    +</div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="hideMenu">hideMenu(broadcastTrigger)</h3>
    +<div class="hidemenu"><p>Hides the column menu.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">broadcastTrigger – {boolean} – </code>
    +<p>true if we were triggered by a broadcast
    +from the menu itself - in which case don't broadcast again as we'll get
    +an infinite loop</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="showMenu">showMenu(column, $columnElement)</h3>
    +<div class="showmenu"><p>Shows the column menu.  If the menu is already displayed it
    +calls the menu to ask it to hide (it will animate), then it repositions the menu
    +to the right place whilst hidden (it will make an assumption on menu width), 
    +then it asks the menu to show (it will animate), then it repositions the menu again 
    +once we can calculate it's size.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>the column we want to position below</p></li>
    +<li><code ng:non-bindable="">$columnElement – {element} – </code>
    +<p>the column element we want to position below</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js script.js" source-edit-html="index.html-12" source-edit-css="" source-edit-js="script.js-11" source-edit-unit="" source-edit-scenario="scenario.js-13"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-12" ng-html-wrap-loaded="app angular.js script.js"></pre>
    +<script type="text/ng-template" id="index.html-12">
    +
    +
    +<div ng-controller="MainCtrl">
    +  <div ui-grid-menu shown="true"  ></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="script.js">
    +<pre class="prettyprint linenums" ng-set-text="script.js-11"></pre>
    +<script type="text/ng-template" id="script.js-11">
    +var app = angular.module('app', ['ui.grid']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +  
    +}]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-13"></pre>
    +<script type="text/ng-template" id="scenario.js-13">
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-12" ng-eval-javascript="script.js-11"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.directive.uiGridStyle.html b/docs/partials/api/ui.grid.directive.uiGridStyle.html
    new file mode 100644
    index 000000000..6f18a6b62
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.directive.uiGridStyle.html
    @@ -0,0 +1,49 @@
    +<h1><code ng:non-bindable="">uiGridStyle</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Allows us to interpolate expressions in <code>&lt;style&gt;</code> elements. Angular doesn't do this by default as it can/will/might? break in IE8.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;style ui-grid-style&gt;
    +   ...
    +&lt;/style&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js script.js" source-edit-html="index.html-15" source-edit-css="" source-edit-js="script.js-14" source-edit-unit="" source-edit-scenario="scenario.js-16"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-15" ng-html-wrap-loaded="app angular.js script.js"></pre>
    +<script type="text/ng-template" id="index.html-15">
    +
    +
    +<div ng-controller="MainCtrl">
    +<style ui-grid-style>{{ myStyle }}</style>
    +<span class="blah">I am in a box.</span>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="script.js">
    +<pre class="prettyprint linenums" ng-set-text="script.js-14"></pre>
    +<script type="text/ng-template" id="script.js-14">
    +var app = angular.module('app', ['ui.grid']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +       $scope.myStyle = '.blah { border: 1px solid }';
    +     }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-16"></pre>
    +<script type="text/ng-template" id="scenario.js-16">
    +it('should apply the right class to the element', function () {
    +     element(by.css('.blah')).getCssValue('border')
    +       .then(function(c) {
    +         expect(c).toContain('1px solid');
    +       });
    +   });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-15" ng-eval-javascript="script.js-14"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.e2eTestLibrary.api.gridTest.html b/docs/partials/api/ui.grid.e2eTestLibrary.api.gridTest.html
    new file mode 100644
    index 000000000..a2fa6242e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.e2eTestLibrary.api.gridTest.html
    @@ -0,0 +1,423 @@
    +<h1><code ng:non-bindable="">gridTest</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.e2eTestLibrary</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>End to end test functions.  Whenever these are updated, it may also be necessary
    +to update the associated tutorial.</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="cancelFilterInColumn">cancelFilterInColumn(gridId, colNumber)</h3>
    +<div class="cancelfilterincolumn"><p>Cancels the filter in a column  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to cancel the filter in</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.cancelFilterInColumn('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickColumnMenu">clickColumnMenu(gridId, colNumber, menuItemNumber)</h3>
    +<div class="clickcolumnmenu"><p>Clicks on the specified option in the specified column
    +menu.  Using this method is fragile, as any change to menu ordering
    +will break all the tests.  For this reason it is recommended to wrap
    +this into "clickColumnMenu<ItemName>" methods, each with a constant
    +for the item you want to click on.  You could alternatively develop
    +a method that finds a menu item by text value, but given that
    +ui-grid has i18n, the text values could also change easily</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to sort on</p></li>
    +<li><code ng:non-bindable="">menuItemNumber – {integer} – </code>
    +<p>the number of the item in the menu that
    +you want to click on</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickColumnMenu('myGrid', 0, 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickColumnMenuHide">clickColumnMenuHide(gridId, colNumber)</h3>
    +<div class="clickcolumnmenuhide"><p>Clicks on the hide item within the specified
    +column menu.  Although it feels cumbersome to write lots of individual
    +"click this menu item" helpers, it is quite useful if the column menus are
    +changed to not have to go to every test script and change the menu item number  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to hide</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickColumnMenuHide('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickColumnMenuRemoveSort">clickColumnMenuRemoveSort(gridId, colNumber)</h3>
    +<div class="clickcolumnmenuremovesort"><p>Clicks on the remove sort item within the specified
    +column menu.  Although it feels cumbersome to write lots of individual
    +"click this menu item" helpers, it is quite useful if the column menus are
    +changed to not have to go to every test script and change the menu item number  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to remove the sort from</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickColumnMenuRemoveSort('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickColumnMenuSortAsc">clickColumnMenuSortAsc(gridId, colNumber)</h3>
    +<div class="clickcolumnmenusortasc"><p>Clicks on the sort ascending item within the specified
    +column menu.  Although it feels cumbersome to write lots of individual
    +"click this menu item" helpers, it is quite useful if the column menus are
    +changed to not have to go to every test script and change the menu item number  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to sort on</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickColumnMenuSortAsc('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickColumnMenuSortDesc">clickColumnMenuSortDesc(gridId, colNumber)</h3>
    +<div class="clickcolumnmenusortdesc"><p>Clicks on the sort descending item within the specified
    +column menu.  Although it feels cumbersome to write lots of individual
    +"click this menu item" helpers, it is quite useful if the column menus are
    +changed to not have to go to every test script and change the menu item number  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to sort on</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickColumnMenuSortDesc('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickGridMenuItem">clickGridMenuItem(gridId, itemNumber)</h3>
    +<div class="clickgridmenuitem"><p>Clicks on a numbered grid menu item.  Note that it's clicking
    +the item based on the underlying repeater - and that some of the items will
    +not be visible.  So the item you want to click on may not be the same
    +as the item number when you look at the ui   </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">itemNumber – {integer} – </code>
    +<p>the number of visible items you expect</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickVisibleGridMenuItem('myGrid', 9);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="clickHeaderCell">clickHeaderCell(gridId, colNumber)</h3>
    +<div class="clickheadercell"><p>Clicks on the header of the specified column,
    +which would usually result in a sort </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to click on</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.clickHeaderCell('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="dataCell">dataCell(gridId, fetchRow, fetchCol)</h3>
    +<div class="datacell"><p>Internal method used to return a dataCell element
    +given the grid and column, note it only returns from the 'body'
    +render container</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">fetchRow – {integer} – </code>
    +<p>the number of the row (within the visible rows)
    +that you want to return</p></li>
    +<li><code ng:non-bindable="">fetchCol – {integer} – </code>
    +<p>the number of the col (within the visible cols)
    +that you want to return</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +myElement = gridTestUtils.dataCell('myGrid', 2, 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="enterFilterInColumn">enterFilterInColumn(gridId, colNumber, filterValue)</h3>
    +<div class="enterfilterincolumn"><p>Enters a filter in a column  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to enter the filter in</p></li>
    +<li><code ng:non-bindable="">filterValue – {string} – </code>
    +<p>the value you want to enter into the filter</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.cancelFilterInColumn('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectCellValueMatch">expectCellValueMatch(gridId, expectedRow, expectedCol, expectedValue)</h3>
    +<div class="expectcellvaluematch"><p>Checks that a cell matches the specified value,
    +takes a regEx or a simple string.  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedRow – {integer} – </code>
    +<p>the number of the row (within the visible rows)
    +that you want to check the value of</p></li>
    +<li><code ng:non-bindable="">expectedCol – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to check the value of</p></li>
    +<li><code ng:non-bindable="">expectedValue – {string} – </code>
    +<p>a regex or string of the value you expect in that cell</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectCellValueMatch('myGrid', 0, 2, 'CellValue');
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectFilterBoxInColumn">expectFilterBoxInColumn(gridId, colNumber, count)</h3>
    +<div class="expectfilterboxincolumn"><p>Checks that a filter box exists in the specified column  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to verify the filter box is in</p></li>
    +<li><code ng:non-bindable="">count – {integer} – </code>
    +<p>the number filter boxes you expect - 0 meaning none, 1 meaning
    +a standard filter, 2 meaning a numerical filter with greater than / less than.</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectFilterBoxInColumn('myGrid', 0, 0);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectFooterCellValueMatch">expectFooterCellValueMatch(gridId, expectedCol, expectedValue)</h3>
    +<div class="expectfootercellvaluematch"><p>Checks that a footer cell matches the specified value,
    +takes a regEx or a simple string.  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedCol – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to check the value of</p></li>
    +<li><code ng:non-bindable="">expectedValue – {string} – </code>
    +<p>a regex or string of the value you expect in that footer</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectFooterCellValueMatch('myGrid', 2, 'FooterValue');
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectFooterColumnCount">expectFooterColumnCount(gridId, expectedNumCols)</h3>
    +<div class="expectfootercolumncount"><p>Checks that a grid footer has the specified number of rows.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedNumCols – {integer} – </code>
    +<p>the number of visible columns you expect the
    +grid to have</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectColumnCount('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectHeaderCellValueMatch">expectHeaderCellValueMatch(gridId, expectedCol, expectedValue)</h3>
    +<div class="expectheadercellvaluematch"><p>Checks that a header cell matches the specified value,
    +takes a regEx or a simple string.  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedCol – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to check the value of</p></li>
    +<li><code ng:non-bindable="">expectedValue – {string} – </code>
    +<p>a regex or string of the value you expect in that header</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectHeaderCellValueMatch('myGrid', 2, 'HeaderValue');
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectHeaderColumnCount">expectHeaderColumnCount(gridId, expectedNumCols)</h3>
    +<div class="expectheadercolumncount"><p>Checks that a grid header body render container (the default render container)
    +has the specified number of columns.  If you are using pinned columns then you may also want
    +to check expectHeaderLeftColumnCount</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedNumCols – {integer} – </code>
    +<p>the number of visible columns you expect the
    +body to have</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectHeaderColumnCount('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectHeaderLeftColumnCount">expectHeaderLeftColumnCount(gridId, expectedNumCols)</h3>
    +<div class="expectheaderleftcolumncount"><p>Checks that a grid header left render container has the specified number of columns.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedNumCols – {integer} – </code>
    +<p>the number of visible columns you expect the
    +left render container to have</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectHeaderLeftColumnCount('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectRowCount">expectRowCount(gridId, expectedNumRows)</h3>
    +<div class="expectrowcount"><p>Checks that a grid has the specified number of rows. Note
    +that this only returns the number of rendered rows, and the grid does
    +row virtualisation - that is that the browser can only see the rendered
    +rows, not all the rows in the dataset.  This method is useful when doing
    +functional tests with small numbers of data, but typically with numbers
    +greater than about 10 you'll find that some of the rows are not rendered
    +and therefore an error is given.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedNumRows – {integer} – </code>
    +<p>the number of visible rows you expect the
    +grid to have</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectRowCount('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectRowValuesMatch">expectRowValuesMatch(gridId, expectedRow, expectedValueArray)</h3>
    +<div class="expectrowvaluesmatch"><p>Checks that a row matches the specified values,
    +takes an array of regExes or simple strings.  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectedRow – {integer} – </code>
    +<p>the number of the row (within the visible rows)
    +that you want to check the value of</p></li>
    +<li><code ng:non-bindable="">expectedValueArray – {array} – </code>
    +<p>an array of regexes or strings of the values you expect in that row</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectRowValuesMatch('myGrid', 0, [ 'CellValue1', '^cellvalue2', 'cellValue3$' ]);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectVisibleColumnMenuItems">expectVisibleColumnMenuItems(gridId, colNumber, expectItems)</h3>
    +<div class="expectvisiblecolumnmenuitems"><p>Checks how many visible menu items there are in the column menu   </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to check the count for</p></li>
    +<li><code ng:non-bindable="">expectItems – {integer} – </code>
    +<p>the number of visible items you expect</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.visibleColumnMenuItems('myGrid', 0, 3);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="expectVisibleGridMenuItems">expectVisibleGridMenuItems(gridId, expectItems)</h3>
    +<div class="expectvisiblegridmenuitems"><p>Checks how many visible menu items there are in the grid menu   </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">expectItems – {integer} – </code>
    +<p>the number of visible items you expect</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.expectVisibleGridMenuItems('myGrid', 3);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="footerCell">footerCell(gridId, col)</h3>
    +<div class="footercell"><p>Internal method used to return a footerCell element
    +given the grid and column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">col – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to return</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.headerCell('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="headerCell">headerCell(gridId, col)</h3>
    +<div class="headercell"><p>Internal method used to return a headerCell element
    +given the grid and column</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">col – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to return</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.headerCell('myGrid', 2);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="resizeHeaderCell">resizeHeaderCell(gridId, colNumber)</h3>
    +<div class="resizeheadercell"><p>Drags the left resizer border towards the column menu button,
    +which will perform a column resizing.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to adjust</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +which left resizer border you wish to drag (this will increase the size of colNumber-1).</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.resizeHeaderCell('myGrid', 1);
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="shiftClickHeaderCell">shiftClickHeaderCell(gridId, colNumber)</h3>
    +<div class="shiftclickheadercell"><p>Shift-clicks on the header of the specified column,
    +which would usually result in adding a second column to the sort </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridId – {string} – </code>
    +<p>the id of the grid that you want to inspect</p></li>
    +<li><code ng:non-bindable="">colNumber – {integer} – </code>
    +<p>the number of the column (within the visible columns)
    +that you want to click on</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridTestUtils.shiftClickHeaderCell('myGrid', 0);
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.e2eTestLibrary.html b/docs/partials/api/ui.grid.e2eTestLibrary.html
    new file mode 100644
    index 000000000..389958f80
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.e2eTestLibrary.html
    @@ -0,0 +1,5 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>End to end test functions.  Whenever these are updated, it may also be necessary
    +to update the associated tutorial.</p></div>
    diff --git a/docs/partials/api/ui.grid.edit.api.ColDef.html b/docs/partials/api/ui.grid.edit.api.ColDef.html
    new file mode 100644
    index 000000000..3af37bb77
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.api.ColDef.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">ColDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Column Definitions for edit feature</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.api.ColumnDef.html b/docs/partials/api/ui.grid.edit.api.ColumnDef.html
    new file mode 100644
    index 000000000..b8afed735
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.api.ColumnDef.html
    @@ -0,0 +1,96 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Column Definition for edit feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions.columnDef">gridOptions.columnDefs</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="cellEditableCondition">cellEditableCondition</h3>
    +<div class="celleditablecondition"><p>If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +function($scope){
    +  //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +  return true;
    +}
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editDropdownFilter">editDropdownFilter</h3>
    +<div class="editdropdownfilter"><p>A filter that you would like to apply to the values in the options list
    +of the dropdown.  For example if you were using angular-translate you might set this
    +to <code>'translate'</code></p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  columnDefs: [
    +    {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +      editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +      editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +  ],
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editDropdownIdLabel">editDropdownIdLabel</h3>
    +<div class="editdropdownidlabel"><p>the label for the "id" field
    +in the editDropdownOptionsArray.  Defaults
    +to 'id'</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  columnDefs: [
    +    {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +      editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +      editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +  ],
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editDropdownOptionsArray">editDropdownOptionsArray</h3>
    +<div class="editdropdownoptionsarray"><p>an array of values in the format
    +[ {id: xxx, value: xxx} ], which is populated
    +into the edit dropdown</p></div>
    +</li>
    +<li><h3 id="editDropdownRowEntityOptionsArrayPath">editDropdownRowEntityOptionsArrayPath</h3>
    +<div class="editdropdownrowentityoptionsarraypath"><p>a path to a property on row.entity containing an
    +array of values in the format
    +[ {id: xxx, value: xxx} ], which will be used to populate
    +the edit dropdown.  This can be used when the dropdown values are dependent on
    +the backing row entity.
    +If this property is set then editDropdownOptionsArray will be ignored.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  columnDefs: [
    +    {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +      editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +      editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +  ],
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editDropdownValueLabel">editDropdownValueLabel</h3>
    +<div class="editdropdownvaluelabel"><p>the label for the "value" field
    +in the editDropdownOptionsArray.  Defaults
    +to 'value'</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  columnDefs: [
    +    {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +      editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +      editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +  ],
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editableCellTemplate">editableCellTemplate</h3>
    +<div class="editablecelltemplate"><p>cell template to be used when editing this column. Can be Url or text template
    +<br/>Defaults to gridOptions.editableCellTemplate</p></div>
    +</li>
    +<li><h3 id="enableCellEdit">enableCellEdit</h3>
    +<div class="enablecelledit"><p>enable editing on column</p></div>
    +</li>
    +<li><h3 id="enableCellEditOnFocus">enableCellEditOnFocus</h3>
    +<div class="enablecelleditonfocus"><p>If true, then editor is invoked as soon as cell receives focus. Default false.
    +<br><em>requires both the cellNav feature and the edit feature to be enabled</em></p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.api.GridOptions.html b/docs/partials/api/ui.grid.edit.api.GridOptions.html
    new file mode 100644
    index 000000000..e797170d9
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.api.GridOptions.html
    @@ -0,0 +1,34 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Options for configuring the edit feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="cellEditableCondition">cellEditableCondition</h3>
    +<div class="celleditablecondition"><p>If specified, either a value or function to be used by all columns before editing.
    +If falsy, then editing of cell is not allowed.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +function($scope){
    +  //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +  return true;
    +}
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="editableCellTemplate">editableCellTemplate</h3>
    +<div class="editablecelltemplate"><p>If specified, cellTemplate to use as the editor for all columns.
    +<br/> defaults to 'ui-grid/cellTextEditor'</p></div>
    +</li>
    +<li><h3 id="enableCellEdit">enableCellEdit</h3>
    +<div class="enablecelledit"><p>If defined, sets the default value for the editable flag on each individual colDefs
    +if their individual enableCellEdit configuration is not defined. Defaults to undefined.</p></div>
    +</li>
    +<li><h3 id="enableCellEditOnFocus">enableCellEditOnFocus</h3>
    +<div class="enablecelleditonfocus"><p>If true, then editor is invoked as soon as cell receives focus. Default false.
    +<br/><em>requires cellNav feature and the edit feature to be enabled</em></p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.api.GridRow.html b/docs/partials/api/ui.grid.edit.api.GridRow.html
    new file mode 100644
    index 000000000..3fed08a89
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.api.GridRow.html
    @@ -0,0 +1,14 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridRow options for edit feature, these are available to be
    +set internally only, by other features</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableCellEdit">enableCellEdit</h3>
    +<div class="enablecelledit"><p>enable editing on row, grouping for example might disable editing on group header rows</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.api.PublicApi.html b/docs/partials/api/ui.grid.edit.api.PublicApi.html
    new file mode 100644
    index 000000000..606cfa23d
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.api.PublicApi.html
    @@ -0,0 +1,56 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for edit feature</p></div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="afterCellEdit">afterCellEdit</h3>
    +<div class="aftercelledit"><p>raised when cell editing is complete
    +<pre class="prettyprint linenums">
    +     gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the options.data element that was edited</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the column that was edited</p></li>
    +<li><code ng:non-bindable="">newValue – {object} – </code>
    +<p>new value</p></li>
    +<li><code ng:non-bindable="">oldValue – {object} – </code>
    +<p>old value</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="beginCellEdit">beginCellEdit</h3>
    +<div class="begincelledit"><p>raised when cell editing starts on a cell
    +<pre class="prettyprint linenums">
    +     gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the options.data element that was edited</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the column that was edited</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="cancelCellEdit">cancelCellEdit</h3>
    +<div class="cancelcelledit"><p>raised when cell editing is cancelled on a cell
    +<pre class="prettyprint linenums">
    +     gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the options.data element that was edited</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the column that was edited</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.constant.uiGridEditConstants.html b/docs/partials/api/ui.grid.edit.constant.uiGridEditConstants.html
    new file mode 100644
    index 000000000..18b618943
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.constant.uiGridEditConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridEditConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in edit module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.input.html b/docs/partials/api/ui.grid.edit.directive.input.html
    new file mode 100644
    index 000000000..708e37984
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.input.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">input</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>directive to provide binding between input[date] value and ng-model for angular 1.2
    +It is similar to input[date] directive of angular 1.3</p>
    +
    +<p>Supported date format for input is 'yyyy-MM-dd'
    +The directive will set the $valid property of input element and the enclosing form to false if
    +model is invalid date or value of input is entered wrong.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as element:<pre class="prettyprint linenums">&lt;input&gt;
    +&lt;/input&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.uiGridCell.html b/docs/partials/api/ui.grid.edit.directive.uiGridCell.html
    new file mode 100644
    index 000000000..b2f3e2a1c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.uiGridCell.html
    @@ -0,0 +1,41 @@
    +<h1><code ng:non-bindable="">uiGridCell</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +Editing Actions.</p>
    +
    +<p>Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +with the columnDef.editableCellTemplate element ('cellEditor.html' by default).</p>
    +
    +<p>The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN_CELL_EDIT angular event
    +and do the initial steps needed to edit the cell (setfocus on input element, etc).</p>
    +
    +<p>When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +it should emit the uiGridEditConstants.events.END_CELL_EDIT event.</p>
    +
    +<p>If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +it should emit the uiGridEditConstants.events.CANCEL_CELL_EDIT event.  The original value
    +will be set back on the model by the uiGridCell directive.</p>
    +
    +<p>Events that invoke editing:
    +  - dblclick
    +  - F2 keydown (when using cell selection)</p>
    +
    +<p>Events that end editing:
    +  - Dependent on the specific editableCellTemplate
    +  - Standards should be blur and enter keydown</p>
    +
    +<p>Events that cancel editing:
    +  - Dependent on the specific editableCellTemplate
    +  - Standards should be Esc keydown</p>
    +
    +<p>Grid Events that end editing:
    +  - uiGridConstants.events.GRID_SCROLL</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-cell&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.uiGridEdit.html b/docs/partials/api/ui.grid.edit.directive.uiGridEdit.html
    new file mode 100644
    index 000000000..715731dbc
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.uiGridEdit.html
    @@ -0,0 +1,43 @@
    +<h1><code ng:non-bindable="">uiGridEdit</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds editing features to the ui-grid directive.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-edit&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-0" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-0" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-0">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Bob', title: 'CEO' },
    +         { name: 'Frank', title: 'Lowly Developer' }
    +   ];
    +
    +   $scope.columnDefs = [
    +     {name: 'name', enableCellEdit: true},
    +     {name: 'title', enableCellEdit: true}
    +   ];
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-0" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.uiGridEditDropdown.html b/docs/partials/api/ui.grid.edit.directive.uiGridEditDropdown.html
    new file mode 100644
    index 000000000..64c8304aa
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.uiGridEditDropdown.html
    @@ -0,0 +1,19 @@
    +<h1><code ng:non-bindable="">uiGridEditDropdown</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>dropdown editor for editable fields.
    +Provides EndEdit and CancelEdit events</p>
    +
    +<p>Events that end editing:
    +   blur and enter keydown, and any left/right nav</p>
    +
    +<p>Events that cancel editing:
    +  - Esc keydown</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-edit-dropdown&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.uiGridEditor.html b/docs/partials/api/ui.grid.edit.directive.uiGridEditor.html
    new file mode 100644
    index 000000000..6ca3aa5c4
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.uiGridEditor.html
    @@ -0,0 +1,19 @@
    +<h1><code ng:non-bindable="">uiGridEditor</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>input editor directive for editable fields.
    +Provides EndEdit and CancelEdit events</p>
    +
    +<p>Events that end editing:
    +   blur and enter keydown</p>
    +
    +<p>Events that cancel editing:
    +  - Esc keydown</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-editor&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.directive.uiGridTextEditor.html b/docs/partials/api/ui.grid.edit.directive.uiGridTextEditor.html
    new file mode 100644
    index 000000000..40c46908f
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.directive.uiGridTextEditor.html
    @@ -0,0 +1,19 @@
    +<h1><code ng:non-bindable="">uiGridTextEditor</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>input editor directive for editable fields.
    +Provides EndEdit and CancelEdit events</p>
    +
    +<p>Events that end editing:
    +   blur and enter keydown</p>
    +
    +<p>Events that cancel editing:
    +  - Esc keydown</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-text-editor&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.html b/docs/partials/api/ui.grid.edit.html
    new file mode 100644
    index 000000000..56cda94b6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.html
    @@ -0,0 +1,14 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridedit">ui.grid.edit</h2>
    +
    +<p>This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +a keyboard.
    +<br/>
    +<br/>
    +To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +user to key data and then tab, arrow, or enter to the cells beside or below.</p>
    +
    +<div doc-module-components="ui.grid.edit">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.edit.service.uiGridEditService.html b/docs/partials/api/ui.grid.edit.service.uiGridEditService.html
    new file mode 100644
    index 000000000..c63c10006
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.service.uiGridEditService.html
    @@ -0,0 +1,27 @@
    +<h1><code ng:non-bindable="">uiGridEditService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for editing features</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="editColumnBuilder">editColumnBuilder()</h3>
    +<div class="editcolumnbuilder"><p>columnBuilder function that adds edit properties to grid column</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>promise that will load any needed templates when resolved</p></div>
    +</div>
    +</li>
    +<li><h3 id="isStartEditKey">isStartEditKey(evt)</h3>
    +<div class="isstarteditkey"><p>Determines if a keypress should start editing.  Decorate this service to override with your
    +own key events.  See service decorator in angular docs.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">evt – {Event} – </code>
    +<p>keydown event</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{boolean}</code>
    +– <p>true if an edit should start</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.edit.service.uiGridExpandableService.html b/docs/partials/api/ui.grid.edit.service.uiGridExpandableService.html
    new file mode 100644
    index 000000000..8b681c759
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.edit.service.uiGridExpandableService.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridExpandableService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.edit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for the expandable grid</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.api.GridOptions.html b/docs/partials/api/ui.grid.expandable.api.GridOptions.html
    new file mode 100644
    index 000000000..fc80abbd4
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.api.GridOptions.html
    @@ -0,0 +1,59 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Options for configuring the expandable feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3></h3>
    +<div class=""><p>Width in pixels of the expandable column. Defaults to 40</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  expandableRowHeaderWidth: 40
    +}
    +</pre>  </p></div>
    +</div>
    +</li>
    +<li><h3 id="enableExpandable">enableExpandable</h3>
    +<div class="enableexpandable"><p>Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +within your application, or in specific modes on <em>this</em> grid. Defaults to true.  </p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableExpandable: false
    +}
    +</pre>  </p></div>
    +</div>
    +</li>
    +<li><h3 id="enableExpandableRowHeader">enableExpandableRowHeader</h3>
    +<div class="enableexpandablerowheader"><p>Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableExpandableRowHeader: false
    +}
    +</pre>  </p></div>
    +</div>
    +</li>
    +<li><h3 id="expandableRowHeight">expandableRowHeight</h3>
    +<div class="expandablerowheight"><p>Height in pixels of the expanded subgrid.  Defaults to
    +150</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  expandableRowHeight: 150
    +}
    +</pre>  </p></div>
    +</div>
    +</li>
    +<li><h3 id="expandableRowTemplate">expandableRowTemplate</h3>
    +<div class="expandablerowtemplate"><p>Mandatory. The template for your expanded row</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  expandableRowTemplate: 'expandableRowTemplate.html'
    +}
    +</pre>  </p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.api.PublicApi.html b/docs/partials/api/ui.grid.expandable.api.PublicApi.html
    new file mode 100644
    index 000000000..9b44615bc
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.api.PublicApi.html
    @@ -0,0 +1,53 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for expandable feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="collapseAllRows">collapseAllRows()</h3>
    +<div class="collapseallrows"><p>Collapse all subgrids.
    +<pre class="prettyprint linenums">
    +     gridApi.expandable.collapseAllRows();
    +</pre></div>
    +</li>
    +<li><h3 id="expandAllRows">expandAllRows()</h3>
    +<div class="expandallrows"><p>Expand all subgrids.
    +<pre class="prettyprint linenums">
    +     gridApi.expandable.expandAllRows();
    +</pre></div>
    +</li>
    +<li><h3 id="toggleAllRows">toggleAllRows()</h3>
    +<div class="toggleallrows"><p>Toggle all subgrids.
    +<pre class="prettyprint linenums">
    +     gridApi.expandable.toggleAllRows();
    +</pre></div>
    +</li>
    +<li><h3 id="toggleRowExpansion">toggleRowExpansion(rowEntity)</h3>
    +<div class="togglerowexpansion"><p>Toggle a specific row
    +<pre class="prettyprint linenums">
    +     gridApi.expandable.toggleRowExpansion(rowEntity);
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the data entity for the row you want to expand</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="rowExpandedStateChanged">rowExpandedStateChanged</h3>
    +<div class="rowexpandedstatechanged"><p>raised when cell editing is complete
    +<pre class="prettyprint linenums">
    +     gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>the row that was expanded</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.class.Grid.html b/docs/partials/api/ui.grid.expandable.class.Grid.html
    new file mode 100644
    index 000000000..0273ec61d
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.class.Grid.html
    @@ -0,0 +1,21 @@
    +<h1><code ng:non-bindable="">Grid</code>
    +<span class="hint">(class in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Additional Grid properties added by expandable module</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;ANY grid&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;ANY class="grid"&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="parentRow">parentRow</h3>
    +<div class="parentrow"><p>reference to the expanded parent row that owns this grid</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.directive.uiGrid.html b/docs/partials/api/ui.grid.expandable.directive.uiGrid.html
    new file mode 100644
    index 000000000..52dad03da
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.directive.uiGrid.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">uiGrid</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>stacks on the uiGrid directive to register child grid with parent row when child is created</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;ANY ui-grid&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;ANY class="ui-grid"&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.directive.uiGridExpandableRow.html b/docs/partials/api/ui.grid.expandable.directive.uiGridExpandableRow.html
    new file mode 100644
    index 000000000..567316a76
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.directive.uiGridExpandableRow.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">uiGridExpandableRow</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>directive to render the expandable row template</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;ANY ui-grid-expandable-row&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;ANY class="ui-grid-expandable-row"&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.directive.uiGridRow.html b/docs/partials/api/ui.grid.expandable.directive.uiGridRow.html
    new file mode 100644
    index 000000000..59b2b6cd7
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.directive.uiGridRow.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">uiGridRow</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>stacks on the uiGridRow directive to add support for expandable rows</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;ANY ui-grid-row&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;ANY class="ui-grid-row"&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.directive.uiGridViewport.html b/docs/partials/api/ui.grid.expandable.directive.uiGridViewport.html
    new file mode 100644
    index 000000000..18251ced6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.directive.uiGridViewport.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">uiGridViewport</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>stacks on the uiGridViewport directive to append the expandable row html elements to the
    +default gridRow template</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;ANY ui-grid-viewport&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;ANY class="ui-grid-viewport"&gt;
    +   ...
    +&lt;/ANY&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.expandable.html b/docs/partials/api/ui.grid.expandable.html
    new file mode 100644
    index 000000000..f4510cff2
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.html
    @@ -0,0 +1,10 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridexpandable">ui.grid.expandable</h2>
    +
    +<p>This module provides the ability to create subgrids with the ability to expand a row
    +to show the subgrid.</p>
    +
    +<div doc-module-components="ui.grid.expandable">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.expandable.service.uiGridExpandableService.html b/docs/partials/api/ui.grid.expandable.service.uiGridExpandableService.html
    new file mode 100644
    index 000000000..b1321da2c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.expandable.service.uiGridExpandableService.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridExpandableService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.expandable</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for the expandable grid</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.api.ColumnDef.html b/docs/partials/api/ui.grid.exporter.api.ColumnDef.html
    new file mode 100644
    index 000000000..c7bcd079c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.api.ColumnDef.html
    @@ -0,0 +1,18 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColumnDef settings for exporter</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="exporterPdfAlign">exporterPdfAlign</h3>
    +<div class="exporterpdfalign"><p>the alignment you'd like for this specific column when
    +exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +valid pdfMake alignment option.</p></div>
    +</li>
    +<li><h3 id="exporterSuppressExport">exporterSuppressExport</h3>
    +<div class="exportersuppressexport"><p>Suppresses export for this column.  Used by selection and expandable.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.api.GridOptions.columnDef.html b/docs/partials/api/ui.grid.exporter.api.GridOptions.columnDef.html
    new file mode 100644
    index 000000000..21891b1ac
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.api.GridOptions.columnDef.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">columnDef</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.exporter.api:GridOptions</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColumnDef settings for exporter</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="exporterPdfAlign">exporterPdfAlign</h3>
    +<div class="exporterpdfalign"><p>the alignment you'd like for this specific column when
    +exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +valid pdfMake alignment option.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.api.GridOptions.html b/docs/partials/api/ui.grid.exporter.api.GridOptions.html
    new file mode 100644
    index 000000000..c47fcec38
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.api.GridOptions.html
    @@ -0,0 +1,198 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for exporter feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="exporterCsvColumnSeparator">exporterCsvColumnSeparator</h3>
    +<div class="exportercsvcolumnseparator"><p>The character to use as column separator
    +link
    +<br/>Defaults to ','</p></div>
    +</li>
    +<li><h3 id="exporterCsvFilename">exporterCsvFilename</h3>
    +<div class="exportercsvfilename"><p>The default filename to use when saving the downloaded csv. <br />
    +This will only work in some browsers.
    +<br/>Defaults to 'download.csv'</p></div>
    +</li>
    +<li><h3 id="exporterFieldCallback">exporterFieldCallback</h3>
    +<div class="exporterfieldcallback"><p>A function to call for each field before exporting it.  Allows 
    +massaging of raw data into a display format, for example if you have applied 
    +filters to convert codes into decodes, or you require
    +a specific date format in the exported content.</p>
    +
    +<p>The method is called once for each field exported, and provides the grid, the
    +gridCol and the GridRow for you to use as context in massaging the data.</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>you must return the massaged value ready for exporting</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +  if ( col.name === 'status' ){
    +    value = decodeStatus( value );
    +  }
    +  return value;
    +}
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="exporterHeaderFilter">exporterHeaderFilter</h3>
    +<div class="exporterheaderfilter"><p>A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +for example if you were using angular-translate you'd set this to <code>$translate.instant</code>.  Note that this
    +call must be synchronous, it cannot be a call that returns a promise.</p>
    +
    +<p>Behaviour can be changed to pass in <code>name</code> instead of <code>displayName</code> through use of <code>exporterHeaderFilterUseName: true</code>.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +</pre>
    +OR
    +<pre class="prettyprint linenums">
    +gridOptions.exporterHeaderFilter = $translate.instant;
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="exporterHeaderFilterUseName">exporterHeaderFilterUseName</h3>
    +<div class="exporterheaderfilterusename"><p>Defaults to false, which leads to <code>displayName</code> being passed into the headerFilter.
    +If set to true, then will pass <code>name</code> instead.</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions.exporterHeaderFilterUseName = true;
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="exporterMenuCsv">exporterMenuCsv</h3>
    +<div class="exportermenucsv"><p>Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.</p></div>
    +</li>
    +<li><h3 id="exporterMenuLabel">exporterMenuLabel</h3>
    +<div class="exportermenulabel"><p>The text to show on the exporter menu button
    +link
    +<br/>Defaults to 'Export'</p></div>
    +</li>
    +<li><h3 id="exporterMenuPdf">exporterMenuPdf</h3>
    +<div class="exportermenupdf"><p>Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.</p></div>
    +</li>
    +<li><h3 id="exporterPdfCustomFormatter">exporterPdfCustomFormatter</h3>
    +<div class="exporterpdfcustomformatter"><p>A custom callback routine that changes the pdf document, adding any
    +custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +must return an updated docDefinition ready for pdfMake.</p><h4 id="Example">Example</h4>
    +<div class="example"><p>In this example we add a style to the style array, so that we can use it in our
    +footer definition.
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +    docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +    return docDefinition;
    +  }
    +
    +  gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="exporterPdfDefaultStyle">exporterPdfDefaultStyle</h3>
    +<div class="exporterpdfdefaultstyle"><p>The default style in pdfMake format
    +<br/>Defaults to:
    +<pre class="prettyprint linenums">
    +  {
    +    fontSize: 11
    +  }
    +</pre></div>
    +</li>
    +<li><h3 id="exporterPdfFooter">exporterPdfFooter</h3>
    +<div class="exporterpdffooter"><p>The header section for pdf exports.  Can be
    +simple text:
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfFooter = 'My Footer';
    +</pre>
    +Can be a more complex object in pdfMake format:
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfFooter = {
    +    columns: [
    +      'Left part',
    +      { text: 'Right part', alignment: 'right' }
    +    ]
    +  };
    +</pre>
    +Or can be a function, allowing page numbers and the like
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +</pre></div>
    +</li>
    +<li><h3 id="exporterPdfHeader">exporterPdfHeader</h3>
    +<div class="exporterpdfheader"><p>The header section for pdf exports.  Can be
    +simple text:
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfHeader = 'My Header';
    +</pre>
    +Can be a more complex object in pdfMake format:
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfHeader = {
    +    columns: [
    +      'Left part',
    +      { text: 'Right part', alignment: 'right' }
    +    ]
    +  };
    +</pre>
    +Or can be a function, allowing page numbers and the like
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +</pre></div>
    +</li>
    +<li><h3 id="exporterPdfMaxGridWidth">exporterPdfMaxGridWidth</h3>
    +<div class="exporterpdfmaxgridwidth"><p>The maxium grid width - the current grid width 
    +will be scaled to match this, with any fixed width columns
    +being adjusted accordingly.
    +<br/>Defaults to 720 (for A4 landscape), use 670 for LETTER </p></div>
    +</li>
    +<li><h3 id="exporterPdfOrientation">exporterPdfOrientation</h3>
    +<div class="exporterpdforientation"><p>The orientation, should be a valid pdfMake value,
    +'landscape' or 'portrait'
    +<br/>Defaults to landscape</p></div>
    +</li>
    +<li><h3 id="exporterPdfPageSize">exporterPdfPageSize</h3>
    +<div class="exporterpdfpagesize"><p>The orientation, should be a valid pdfMake
    +paper size, usually 'A4' or 'LETTER'
    +<a href="https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js">pdfMake page sizes</a>
    +<br/>Defaults to A4</p></div>
    +</li>
    +<li><h3 id="exporterPdfTableHeaderStyle">exporterPdfTableHeaderStyle</h3>
    +<div class="exporterpdftableheaderstyle"><p>The tableHeader style in pdfMake format
    +<br/>Defaults to:
    +<pre class="prettyprint linenums">
    +  {
    +    bold: true,
    +    fontSize: 12,
    +    color: 'black'
    +  }
    +</pre></div>
    +</li>
    +<li><h3 id="exporterPdfTableLayout">exporterPdfTableLayout</h3>
    +<div class="exporterpdftablelayout"><p>A tableLayout in pdfMake format, 
    +controls gridlines and the like.  We use the default
    +layout usually.
    +<br/>Defaults to null, which means no layout </p></div>
    +</li>
    +<li><h3 id="exporterPdfTableStyle">exporterPdfTableStyle</h3>
    +<div class="exporterpdftablestyle"><p>The table style in pdfMake format
    +<br/>Defaults to:
    +<pre class="prettyprint linenums">
    +  {
    +    margin: [0, 5, 0, 15]
    +  }
    +</pre></div>
    +</li>
    +<li><h3 id="exporterSuppressColumns">exporterSuppressColumns</h3>
    +<div class="exportersuppresscolumns"><p>Columns that should not be exported.  The selectionRowHeader is already automatically
    +suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +output then add it in this list.  You should provide an array of column names.
    +<br/>Defaults to: []
    +<pre class="prettyprint linenums">
    +  gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +</pre></div>
    +</li>
    +<li><h3 id="exporterSuppressMenu">exporterSuppressMenu</h3>
    +<div class="exportersuppressmenu"><p>Don't show the export menu button, implying the user
    +will roll their own UI for calling the exporter
    +<br/>Defaults to false</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.api.GridRow.html b/docs/partials/api/ui.grid.exporter.api.GridRow.html
    new file mode 100644
    index 000000000..e8cab429b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.api.GridRow.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridRow settings for exporter</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="exporterEnableExporting">exporterEnableExporting</h3>
    +<div class="exporterenableexporting"><p>If set to false, then don't export this row, notwithstanding visible or 
    +other settings
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.api.PublicApi.html b/docs/partials/api/ui.grid.exporter.api.PublicApi.html
    new file mode 100644
    index 000000000..14653f76f
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.api.PublicApi.html
    @@ -0,0 +1,39 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for exporter feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="csvExport">csvExport(rowTypes, colTypes)</h3>
    +<div class="csvexport"><p>Exports rows from the grid in csv format, 
    +the data exported is selected based on the provided options</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowTypes – {string} – </code>
    +<p>which rows to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="pdfExport">pdfExport(rowTypes, colTypes)</h3>
    +<div class="pdfexport"><p>Exports rows from the grid in pdf format, 
    +the data exported is selected based on the provided options
    +Note that this function has a dependency on pdfMake, all
    +going well this has been installed for you.
    +The resulting pdf opens in a new browser window.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowTypes – {string} – </code>
    +<p>which rows to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.constant.uiGridExporterConstants.html b/docs/partials/api/ui.grid.exporter.constant.uiGridExporterConstants.html
    new file mode 100644
    index 000000000..8d62ee49c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.constant.uiGridExporterConstants.html
    @@ -0,0 +1,23 @@
    +<h1><code ng:non-bindable="">uiGridExporterConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in exporter module</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="ALL">ALL</h3>
    +<div class="all"><p>export all data, including data not visible.  Can
    +be set for either rowTypes or colTypes</p></div>
    +</li>
    +<li><h3 id="SELECTED">SELECTED</h3>
    +<div class="selected"><p>export all data, including data not visible.  Can
    +be set only for rowTypes, selection of only some columns is 
    +not supported</p></div>
    +</li>
    +<li><h3 id="VISIBLE">VISIBLE</h3>
    +<div class="visible"><p>export only visible data, including data not visible.  Can
    +be set for either rowTypes or colTypes</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.directive.uiGridExporter.html b/docs/partials/api/ui.grid.exporter.directive.uiGridExporter.html
    new file mode 100644
    index 000000000..6c1649291
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.directive.uiGridExporter.html
    @@ -0,0 +1,48 @@
    +<h1><code ng:non-bindable="">uiGridExporter</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds exporter features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-exporter&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-1" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-1" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-1">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="gridOptions" ui-grid-exporter></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Bob', title: 'CEO' },
    +         { name: 'Frank', title: 'Lowly Developer' }
    +   ];
    +
    +   $scope.gridOptions = {
    +     enableGridMenu: true,
    +     exporterMenuCsv: false,
    +     columnDefs: [
    +       {name: 'name', enableCellEdit: true},
    +       {name: 'title', enableCellEdit: true}
    +     ],
    +     data: $scope.data
    +   };
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-1" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.exporter.html b/docs/partials/api/ui.grid.exporter.html
    new file mode 100644
    index 000000000..1c6ad3da6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.html
    @@ -0,0 +1,19 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridexporter">ui.grid.exporter</h2>
    +
    +<p>This module provides the ability to exporter data from the grid.  </p>
    +
    +<p>Data can be exported in a range of formats, and all data, visible 
    +data, or selected rows can be exported, with all columns or visible
    +columns.</p>
    +
    +<p>No UI is provided, the caller should provide their own UI/buttons 
    +as appropriate, or enable the gridMenu</p>
    +
    +<p><br/>
    +<br/></p>
    +
    +<div doc-module-components="ui.grid.exporter">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.exporter.service.uiGridExporterService.html b/docs/partials/api/ui.grid.exporter.service.uiGridExporterService.html
    new file mode 100644
    index 000000000..f2a74c9c6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.exporter.service.uiGridExporterService.html
    @@ -0,0 +1,208 @@
    +<h1><code ng:non-bindable="">uiGridExporterService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.exporter</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for exporter feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="addToMenu">addToMenu(grid)</h3>
    +<div class="addtomenu"><p>Adds export items to the grid menu,
    +allowing the user to select export options </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="calculatePdfHeaderWidths">calculatePdfHeaderWidths(grid, exportHeaders)</h3>
    +<div class="calculatepdfheaderwidths"><p>Determines the column widths base on the 
    +widths we got from the grid.  If the column is drawn
    +then we have a drawnWidth.  If the column is not visible
    +then we have '*', 'x%' or a width.  When columns are
    +not visible they don't contribute to the overall gridWidth,
    +so we need to adjust to allow for extra columns</p>
    +
    +<p>Our basic heuristic is to take the current gridWidth, plus 
    +numeric columns and call this the base gridwidth.</p>
    +
    +<p>To that we add 100 for any '*' column, and x% of the base gridWidth
    +for any column that is a %</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">exportHeaders – {object} – </code>
    +<p>array of header information </p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>an array of header widths</p></div>
    +</div>
    +</li>
    +<li><h3 id="csvExport">csvExport(grid, rowTypes, colTypes)</h3>
    +<div class="csvexport"><p>Exports rows from the grid in csv format, 
    +the data exported is selected based on the provided options</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">rowTypes – {string} – </code>
    +<p>which rows to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="downloadFile">downloadFile(fileName, csvContent)</h3>
    +<div class="downloadfile"><p>Triggers download of a csv file.  Logic provided
    +by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">fileName – {string} – </code>
    +<p>the filename we'd like our file to be
    +given</p></li>
    +<li><code ng:non-bindable="">csvContent – {string} – </code>
    +<p>the csv content that we'd like to 
    +download as a file</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="formatAsCSV">formatAsCSV(exportColumnHeaders, exportData)</h3>
    +<div class="formatascsv"><p>Formats the column headers and data as a CSV, 
    +and sends that data to the user</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">exportColumnHeaders – {array} – </code>
    +<p>an array of column headers, 
    +where each header is an object with name, width and maybe alignment</p></li>
    +<li><code ng:non-bindable="">exportData – {array} – </code>
    +<p>an array of rows, where each row is
    +an array of column data</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>csv the formatted csv as a string</p></div>
    +</div>
    +</li>
    +<li><h3 id="formatFieldAsCsv">formatFieldAsCsv(field)</h3>
    +<div class="formatfieldascsv"><p>Renders a single field as a csv field, including
    +quotes around the value</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">field – {field} – </code>
    +<p>the field to be turned into a csv string,
    +may be of any type</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>a csv-ified version of the field</p></div>
    +</div>
    +</li>
    +<li><h3 id="formatFieldAsCsv">formatFieldAsCsv(field)</h3>
    +<div class="formatfieldascsv"><p>Renders a single field as a pdf-able field, which
    +is different from a csv field only in that strings don't have quotes
    +around them</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">field – {field} – </code>
    +<p>the field to be turned into a pdf string,
    +may be of any type</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>a string-ified version of the field</p></div>
    +</div>
    +</li>
    +<li><h3 id="formatRowAsCsv">formatRowAsCsv(exporter, row)</h3>
    +<div class="formatrowascsv"><p>Renders a single field as a csv field, including
    +quotes around the value</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">exporter – {exporterService} – </code>
    +<p>pass in exporter </p></li>
    +<li><code ng:non-bindable="">row – {array} – </code>
    +<p>the row to be turned into a csv string</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>a csv-ified version of the row</p></div>
    +</div>
    +</li>
    +<li><h3 id="formatRowAsPdf">formatRowAsPdf(exporter, row)</h3>
    +<div class="formatrowaspdf"><p>Renders a row in a format consumable by PDF,
    +mainly meaning casting everything to a string</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">exporter – {exporterService} – </code>
    +<p>pass in exporter </p></li>
    +<li><code ng:non-bindable="">row – {array} – </code>
    +<p>the row to be turned into a csv string</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>a csv-ified version of the row</p></div>
    +</div>
    +</li>
    +<li><h3 id="getColumnHeaders">getColumnHeaders(grid, colTypes)</h3>
    +<div class="getcolumnheaders"><p>Gets the column headers from the grid to use
    +as a title row for the exported file, all headers have 
    +headerCellFilters applied as appropriate.</p>
    +
    +<p>Column headers are an array of objects, each object has
    +name, displayName, width and align attributes.  Only name is
    +used for csv, all attributes are used for pdf.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getData">getData(grid, rowTypes, colTypes)</h3>
    +<div class="getdata"><p>Gets data from the grid based on the provided options,
    +all cells have cellFilters applied as appropriate.  Any rows marked
    +<code>exporterEnableExporting: false</code> will not be exported</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">rowTypes – {string} – </code>
    +<p>which rows to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="isIE">isIE()</h3>
    +<div class="isie"><p>Checks whether current browser is IE and returns it's version if it is</p></div>
    +</li>
    +<li><h3 id="pdfExport">pdfExport(grid, rowTypes, colTypes)</h3>
    +<div class="pdfexport"><p>Exports rows from the grid in pdf format, 
    +the data exported is selected based on the provided options.
    +Note that this function has a dependency on pdfMake, which must
    +be installed.  The resulting pdf opens in a new
    +browser window.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">rowTypes – {string} – </code>
    +<p>which rows to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +<li><code ng:non-bindable="">colTypes – {string} – </code>
    +<p>which columns to export, valid values are
    +uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +uiGridExporterConstants.SELECTED</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="renderAsPdf">renderAsPdf(grid, exportColumnHeaders, exportData)</h3>
    +<div class="renderaspdf"><p>Renders the data into a pdf, and opens that pdf.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid from which data should be exported</p></li>
    +<li><code ng:non-bindable="">exportColumnHeaders – {array} – </code>
    +<p>an array of column headers, 
    +where each header is an object with name, width and maybe alignment</p></li>
    +<li><code ng:non-bindable="">exportData – {array} – </code>
    +<p>an array of rows, where each row is
    +an array of column data</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>a pdfMake format document definition, ready 
    +for generation</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.gridMenuService.html b/docs/partials/api/ui.grid.gridMenuService.html
    new file mode 100644
    index 000000000..03b84bfe6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.gridMenuService.html
    @@ -0,0 +1,76 @@
    +<h1><code ng:non-bindable="">gridMenuService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Methods for working with the grid menu</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getMenuItems">getMenuItems($scope)</h3>
    +<div class="getmenuitems"><p>Decides the menu items to show in the menu.  This is a
    +combination of:</p>
    +
    +<ul>
    +<li>the default menu items that are always included, </li>
    +<li>any menu items that have been provided through the addMenuItem api. These
    +are typically added by features within the grid</li>
    +<li>any menu items included in grid.options.gridMenuCustomItems.  These can be
    +changed dynamically, as they're always recalculated whenever we show the
    +menu</li>
    +</ul><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the scope of this gridMenu, from which we can find all 
    +the information that we need</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>an array of menu items that can be shown </p></div>
    +</div>
    +</li>
    +<li><h3 id="initialize">initialize($scope, grid)</h3>
    +<div class="initialize"><p>Sets up the gridMenu. Most importantly, sets our
    +scope onto the grid object as grid.gridMenuScope, allowing us
    +to operate when passed only the grid.  Second most importantly, 
    +we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +on the core api.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the scope of this gridMenu</p></li>
    +<li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid to which this gridMenu is associated</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setMenuItemTitle">setMenuItemTitle(menuItem, colDef, grid)</h3>
    +<div class="setmenuitemtitle"><p>Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +putting the result into the title </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">menuItem – {object} – </code>
    +<p>the menuItem we want to put the title on</p></li>
    +<li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the colDef from which we can get displayName, name or field</p></li>
    +<li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid, from which we can get the options.gridMenuTitleFilter</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="showHideColumns">showHideColumns($scope)</h3>
    +<div class="showhidecolumns"><p>Adds two menu items for each of the columns in columnDefs.  One
    +menu item for hide, one menu item for show.  Each is visible when appropriate
    +(show when column is not visible, hide when column is visible).  Each toggles
    +the visible property on the columnDef using toggleColumnVisibility</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>of a gridMenu, which contains a reference to the grid</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="toggleColumnVisibility">toggleColumnVisibility(gridCol)</h3>
    +<div class="togglecolumnvisibility"><p>Toggles the visibility of an individual column.  Expects to be
    +provided a context that has on it a gridColumn, which is the column that
    +we'll operate upon.  We change the visibility, and refresh the grid as appropriate</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">gridCol – {GridCol} – </code>
    +<p>the column that we want to toggle</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.i18n.constant.i18nConstants.html b/docs/partials/api/ui.grid.i18n.constant.i18nConstants.html
    new file mode 100644
    index 000000000..ccaba41dd
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.i18n.constant.i18nConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">i18nConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.i18n</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in i18n module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.i18n.html b/docs/partials/api/ui.grid.i18n.html
    new file mode 100644
    index 000000000..dfcb3392a
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.i18n.html
    @@ -0,0 +1,9 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridi18n">ui.grid.i18n</h2>
    +
    +<p>This module provides i18n functions to ui.grid and any application that wants to use it</p>
    +
    +<div doc-module-components="ui.grid.i18n">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.i18n.service.i18nService.html b/docs/partials/api/ui.grid.i18n.service.i18nService.html
    new file mode 100644
    index 000000000..fc2ef1df8
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.i18n.service.i18nService.html
    @@ -0,0 +1,80 @@
    +<h1><code ng:non-bindable="">i18nService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.i18n</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for i18n</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="add">add(lang, stringMaps)</h3>
    +<div class="add"><p>Adds the languages and strings to the cache. Decorate this service to
    +add more translation strings</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">lang – {string} – </code>
    +<p>language to add</p></li>
    +<li><code ng:non-bindable="">stringMaps – {object} – </code>
    +<p>of strings to add grouped by property names</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +i18nService.add('en', {
    +   aggregate: {
    +           label1: 'items',
    +           label2: 'some more items'
    +           }
    +   },
    +   groupPanel: {
    +        description: 'Drag a column header here and drop it to group by that column.'
    +     }
    +}
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="get">get(lang)</h3>
    +<div class="get"><p>return all currently loaded languages</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">lang – {string} – </code>
    +<p>to return.  If not specified, returns current language</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the translation string maps for the language</p></div>
    +</div>
    +</li>
    +<li><h3 id="getAllLangs">getAllLangs()</h3>
    +<div class="getalllangs"><p>return all currently loaded languages</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>string</p></div>
    +</div>
    +</li>
    +<li><h3 id="getCurrentLang">getCurrentLang()</h3>
    +<div class="getcurrentlang"><p>returns the current language used in the application</p></div>
    +</li>
    +<li><h3 id="getSafeText">getSafeText(path, lang)</h3>
    +<div class="getsafetext"><p>returns the text specified in the path or a Missing text if text is not found</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">path – {string} – </code>
    +<p>property path to use for retrieving text from string map</p></li>
    +<li><code ng:non-bindable="">lang – {string} – </code>
    +<p>to return.  If not specified, returns current language</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the translation for the path</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +i18nService.getSafeText('sort.ascending')
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="setCurrentLang">setCurrentLang(lang)</h3>
    +<div class="setcurrentlang"><p>sets the current language to use in the application
    +$broadcasts the Update_Event on the $rootScope</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">lang – {string} – </code>
    +<p>to set</p></li>
    +</ul>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +i18nService.setCurrentLang('fr');
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.api.GridOptions.html b/docs/partials/api/ui.grid.importer.api.GridOptions.html
    new file mode 100644
    index 000000000..729170ff4
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.api.GridOptions.html
    @@ -0,0 +1,166 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for importer feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="importerDataAddCallback">importerDataAddCallback(grid, newObjects)</h3>
    +<div class="importerdataaddcallback"><p>A mandatory callback function that adds data to the source data array.  The grid
    +generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +callback.</p>
    +
    +<pre class="prettyprint linenums">
    +     gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +       $scope.myData = $scope.myData.concat( newObjects );
    +     })
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into, may be useful in some way</p></li>
    +<li><code ng:non-bindable="">newObjects – {array} – </code>
    +<p>an array of new objects that you should add to your data</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="importerErrorCallback">importerErrorCallback(grid, errorKey, consoleMessage, context)</h3>
    +<div class="importererrorcallback"><p>A callback function that provides custom error handling, rather
    +than the standard grid behaviour of an alert box and a console message.  You 
    +might use this to internationalise the console log messages, or to write to a 
    +custom logging routine that returned errors to the server.</p>
    +
    +<pre class="prettyprint linenums">
    +     gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +       myUserDisplayRoutine( errorKey );
    +       myLoggingRoutine( consoleMessage, context );
    +     })
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into, may be useful if you're positioning messages
    +in some way</p></li>
    +<li><code ng:non-bindable="">errorKey – {string} – </code>
    +<p>one of the i18n keys the importer can return - importer.noHeaders, 
    +importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray</p></li>
    +<li><code ng:non-bindable="">consoleMessage – {string} – </code>
    +<p>the English console message that importer would have written</p></li>
    +<li><code ng:non-bindable="">context – {object} – </code>
    +<p>the context data that importer would have appended to that console message,
    +often the file content itself or the element that is in error</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="importerHeaderFilter">importerHeaderFilter(displayName)</h3>
    +<div class="importerheaderfilter"><p>A callback function that will filter (usually translate) a single
    +header.  Used when you want to match the passed in column names to the column
    +displayName after the header filter.</p>
    +
    +<p>Your callback routine needs to return the filtered header value. 
    +<pre class="prettyprint linenums">
    +     gridOptions.importerHeaderFilter: function( displayName ) {
    +       return $translate.instant( displayName );
    +     })
    +</pre>
    +
    +<p>or:
    +<pre class="prettyprint linenums">
    +     gridOptions.importerHeaderFilter: $translate.instant
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">displayName – {string} – </code>
    +<p>the displayName that we'd like to translate</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>the translated name</p></div>
    +</div>
    +</li>
    +<li><h3 id="importerObjectCallback">importerObjectCallback(grid, newObject)</h3>
    +<div class="importerobjectcallback"><p>A callback that massages the data for each object.  For example,
    +you might have data stored as a code value, but display the decode.  This callback
    +can be used to change the decoded value back into a code.  Defaults to doing nothing.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>in case you need it</p></li>
    +<li><code ng:non-bindable="">newObject – {object} – </code>
    +<p>the new object as importer has created it, modify it
    +then return the modified version</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the modified object</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +  switch newObject.status {
    +    case 'Active':
    +      newObject.status = 1;
    +      break;
    +    case 'Inactive':
    +      newObject.status = 2;
    +      break;
    +  }
    +  return newObject;
    +};
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="importerProcessHeaders">importerProcessHeaders(grid, headerArray)</h3>
    +<div class="importerprocessheaders"><p>A callback function that will process headers using custom
    +logic.  Set this callback function if the headers that your user will provide in their 
    +import file don't necessarily match the grid header or field names.  This might commonly
    +occur where your application is internationalised, and therefore the field names
    +that the user recognises are in a different language than the field names that
    +ui-grid knows about.</p>
    +
    +<p>Defaults to the internal <code>processHeaders</code> method, which seeks to match using both
    +displayName and column.name.  Any non-matching columns are discarded.</p>
    +
    +<p>Your callback routine should respond by processing the header array, and returning an array
    +of matching column names.  A null value in any given position means "don't import this column"</p>
    +
    +<pre class="prettyprint linenums">
    +     gridOptions.importerProcessHeaders: function( headerArray ) {
    +       var myHeaderColumns = [];
    +       var thisCol;
    +       headerArray.forEach( function( value, index ) {
    +         thisCol = mySpecialLookupFunction( value );
    +         myHeaderColumns.push( thisCol.name ); 
    +       });
    +       
    +       return myHeaderCols;
    +     })
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +<li><code ng:non-bindable="">headerArray – {array} – </code>
    +<p>an array of the text from the first row of the csv file,
    +which you need to match to column.names</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>array of matching column names, in the same order as the headerArray</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableImporter">enableImporter</h3>
    +<div class="enableimporter"><p>Whether or not importer is enabled.  Automatically set
    +to false if the user's browser does not support the required fileApi.
    +Otherwise defaults to true.</p></div>
    +</li>
    +<li><h3 id="importerNewObject">importerNewObject</h3>
    +<div class="importernewobject"><p>An object on which we call <code>new</code> to create each new row before inserting it into
    +the data array.  Typically this would be a $resource entity, which means that if you're using 
    +the rowEdit feature, you can directly call save on this entity when the save event is triggered.</p>
    +
    +<p>Defaults to a vanilla javascript object</p><h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridOptions.importerNewObject = MyRes;
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="importerShowMenu">importerShowMenu</h3>
    +<div class="importershowmenu"><p>Whether or not to show an item in the grid menu.  Defaults to true.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.api.PublicApi.html b/docs/partials/api/ui.grid.importer.api.PublicApi.html
    new file mode 100644
    index 000000000..0272ebca8
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.api.PublicApi.html
    @@ -0,0 +1,19 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for importer feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="importFile">importFile(fileObject)</h3>
    +<div class="importfile"><p>Imports a file into the grid using the file object 
    +provided.  Bypasses the grid menu</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">fileObject – {File} – </code>
    +<p>the file we want to import, as a javascript
    +File object</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.constant.uiGridImporterConstants.html b/docs/partials/api/ui.grid.importer.constant.uiGridImporterConstants.html
    new file mode 100644
    index 000000000..d104315fb
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.constant.uiGridImporterConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridImporterConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in importer module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.directive.uiGridImporter.html b/docs/partials/api/ui.grid.importer.directive.uiGridImporter.html
    new file mode 100644
    index 000000000..73a1d17f3
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.directive.uiGridImporter.html
    @@ -0,0 +1,12 @@
    +<h1><code ng:non-bindable="">uiGridImporter</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds importer features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-importer&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.directive.uiGridImporterMenuItem.html b/docs/partials/api/ui.grid.importer.directive.uiGridImporterMenuItem.html
    new file mode 100644
    index 000000000..6c1b8f3a8
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.directive.uiGridImporterMenuItem.html
    @@ -0,0 +1,13 @@
    +<h1><code ng:non-bindable="">uiGridImporterMenuItem</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Handles the processing from the importer menu item - once a file is
    +selected</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-importer-menu-item&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.importer.html b/docs/partials/api/ui.grid.importer.html
    new file mode 100644
    index 000000000..588c9aa80
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.html
    @@ -0,0 +1,30 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridimporter">ui.grid.importer</h2>
    +
    +<p>This module provides the ability to import data into the grid. It
    +uses the column defs to work out which data belongs in which column, 
    +and creates entities from a configured class (typically a $resource).</p>
    +
    +<p>If the rowEdit feature is enabled, it also calls save on those newly 
    +created objects, and then displays any errors in the imported data.  </p>
    +
    +<p>Currently the importer imports only CSV and json files, although provision has been
    +made to process other file formats, and these can be added over time.  </p>
    +
    +<p>For json files, the properties within each object in the json must match the column names
    +(to put it another way, the importer doesn't process the json, it just copies the objects
    +within the json into a new instance of the specified object type)</p>
    +
    +<p>For CSV import, the default column identification relies on each column in the
    +header row matching a column.name or column.displayName. Optionally, a column identification 
    +callback can be used.  This allows matching using other attributes, which is particularly
    +useful if your application has internationalised column headings (i.e. the headings that 
    +the user sees don't match the column names).</p>
    +
    +<p>The importer makes use of the grid menu as the UI for requesting an
    +import. </p>
    +
    +<div ui-grid-importer>
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.importer.service.uiGridImporterService.html b/docs/partials/api/ui.grid.importer.service.uiGridImporterService.html
    new file mode 100644
    index 000000000..890224e2b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.importer.service.uiGridImporterService.html
    @@ -0,0 +1,154 @@
    +<h1><code ng:non-bindable="">uiGridImporterService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.importer</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for importer feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="addObjects">addObjects(grid, newObjects)</h3>
    +<div class="addobjects"><p>Inserts our new objects into the grid data, and
    +sets the rows to dirty if the rowEdit feature is being used</p>
    +
    +<p>Does this by registering a watch on dataChanges, which essentially
    +is waiting on the result of the grid data watch, and downstream processing.</p>
    +
    +<p>When the callback is called, it deregisters itself - we don't want to run
    +again next time data is added.</p>
    +
    +<p>If we never get called, we deregister on destroy.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +<li><code ng:non-bindable="">newObjects – {array} – </code>
    +<p>the objects we want to insert into the grid data</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the new object</p></div>
    +</div>
    +</li>
    +<li><h3 id="addToMenu">addToMenu(grid)</h3>
    +<div class="addtomenu"><p>Adds import menu item to the grid menu,
    +allowing the user to request import of a file </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid into which data should be imported</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="alertError">alertError(grid, headerRow)</h3>
    +<div class="alerterror"><p>Provides an internationalised user alert for the failure,
    +and logs a console message including diagnostic content.
    +Optionally, if the the <code>gridOptions.importerErrorCallback</code> routine
    +is defined, then calls that instead, allowing user specified error routines</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +<li><code ng:non-bindable="">headerRow – {array} – </code>
    +<p>the header row that we wish to match against
    +the column definitions</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="createCsvObjects">createCsvObjects(grid, importFile)</h3>
    +<div class="createcsvobjects"><p>Converts an array of arrays (representing the csv file)
    +into a set of objects.  Uses the provided <code>gridOptions.importerNewObject</code>
    +to create the objects, and maps the header row into the individual columns 
    +using either <code>gridOptions.importerProcessHeaders</code>, or by using a native method
    +of matching to either the displayName, column name or column field of
    +the columns in the column defs.  The resulting objects will have attributes
    +that are named based on the column.field or column.name, in that order.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid that we want to import into </p></li>
    +<li><code ng:non-bindable="">importFile – {FileObject} – </code>
    +<p>the file that we want to import, as a 
    +file object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="importCsvClosure">importCsvClosure(grid, importFile)</h3>
    +<div class="importcsvclosure"><p>Creates a function that imports a csv file into the grid
    +(allowing it to be used in the reader.onload event)</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid that we want to import into </p></li>
    +<li><code ng:non-bindable="">importFile – {FileObject} – </code>
    +<p>the file that we want to import, as 
    +a file object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="importJson">importJson(grid, importFile)</h3>
    +<div class="importjson"><p>Creates a function that imports a json file into the grid.
    +The json data is imported into new objects of type <code>gridOptions.importerNewObject</code>,
    +and if the rowEdit feature is enabled the rows are marked as dirty</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we want to import into</p></li>
    +<li><code ng:non-bindable="">importFile – {FileObject} – </code>
    +<p>the file that we want to import, as 
    +a FileObject</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="importThisFile">importThisFile(grid, fileObject)</h3>
    +<div class="importthisfile"><p>Imports the provided file into the grid using the file object 
    +provided.  Bypasses the grid menu</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +<li><code ng:non-bindable="">fileObject – {File} – </code>
    +<p>the file we want to import, as returned from the File
    +javascript object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="newObject">newObject(grid)</h3>
    +<div class="newobject"><p>Makes a new object based on <code>gridOptions.importerNewObject</code>,
    +or based on an empty object if not present</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the new object</p></div>
    +</div>
    +</li>
    +<li><h3 id="parseCsv">parseCsv(importFile)</h3>
    +<div class="parsecsv"><p>Parses a csv file into an array of arrays, with the first
    +array being the headers, and the remaining arrays being the data.
    +The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +checker</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">importFile – {FileObject} – </code>
    +<p>the file that we want to import, as a 
    +file object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="parseJson">parseJson(grid, importFile)</h3>
    +<div class="parsejson"><p>Parses a json file, returns the parsed data.
    +Displays an error if file doesn't parse</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid that we want to import into </p></li>
    +<li><code ng:non-bindable="">importFile – {FileObject} – </code>
    +<p>the file that we want to import, as 
    +a FileObject</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>array of objects from the imported json</p></div>
    +</div>
    +</li>
    +<li><h3 id="processHeaders">processHeaders(grid, headerRow)</h3>
    +<div class="processheaders"><p>Determines the columns that the header row from
    +a csv (or other) file represents.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're importing into</p></li>
    +<li><code ng:non-bindable="">headerRow – {array} – </code>
    +<p>the header row that we wish to match against
    +the column definitions</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>an array of the attribute names that should be used
    +for that column, based on matching the headers or creating the headers</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.infiniteScroll.api.GridOptions.html b/docs/partials/api/ui.grid.infiniteScroll.api.GridOptions.html
    new file mode 100644
    index 000000000..2752b09cd
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.infiniteScroll.api.GridOptions.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.infiniteScroll</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for infinite scroll feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableInfiniteScroll">enableInfiniteScroll</h3>
    +<div class="enableinfinitescroll"><p>Enable infinite scrolling for this grid
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.infiniteScroll.api.PublicAPI.html b/docs/partials/api/ui.grid.infiniteScroll.api.PublicAPI.html
    new file mode 100644
    index 000000000..4906e1fce
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.infiniteScroll.api.PublicAPI.html
    @@ -0,0 +1,29 @@
    +<h1><code ng:non-bindable="">PublicAPI</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.infiniteScroll</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public API for infinite scroll feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="dataLoaded">dataLoaded()</h3>
    +<div class="dataloaded"><p>This function is used as a promise when data finished loading.
    +See infinite_scroll ngdoc for example of usage</p></div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="needLoadMoreData">needLoadMoreData</h3>
    +<div class="needloadmoredata"><p>This event fires when scroll reached bottom percentage of grid
    +and needs to load data</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +<li><h3 id="needLoadMoreDataTop">needLoadMoreDataTop</h3>
    +<div class="needloadmoredatatop"><p>This event fires when scroll reached top percentage of grid
    +and needs to load data</p><div class="inline"></div>
    +<div class="inline"></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.infiniteScroll.directive.uiGridInfiniteScroll.html b/docs/partials/api/ui.grid.infiniteScroll.directive.uiGridInfiniteScroll.html
    new file mode 100644
    index 000000000..f934edaf3
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.infiniteScroll.directive.uiGridInfiniteScroll.html
    @@ -0,0 +1,43 @@
    +<h1><code ng:non-bindable="">uiGridInfiniteScroll</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.infiniteScroll</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds infinite scroll features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-infinite-scroll&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-2" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-2" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-2">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Alex', car: 'Toyota' },
    +         { name: 'Sam', car: 'Lexus' }
    +   ];
    +
    +   $scope.columnDefs = [
    +     {name: 'name'},
    +     {name: 'car'}
    +   ];
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-2" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.infiniteScroll.html b/docs/partials/api/ui.grid.infiniteScroll.html
    new file mode 100644
    index 000000000..19b1bbcd8
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.infiniteScroll.html
    @@ -0,0 +1,6 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridinfinitescroll">ui.grid.infiniteScroll</h2>
    +
    +<p>This module provides infinite scroll functionality to ui-grid</p></div>
    diff --git a/docs/partials/api/ui.grid.infiniteScroll.service.uiGridInfiniteScrollService.html b/docs/partials/api/ui.grid.infiniteScroll.service.uiGridInfiniteScrollService.html
    new file mode 100644
    index 000000000..07e675b25
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.infiniteScroll.service.uiGridInfiniteScrollService.html
    @@ -0,0 +1,20 @@
    +<h1><code ng:non-bindable="">uiGridInfiniteScrollService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.infiniteScroll</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Service for infinite scroll features</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="checkScroll">checkScroll()</h3>
    +<div class="checkscroll"><p>This function checks scroll position inside grid and
    +calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'</p></div>
    +</li>
    +<li><h3 id="initializeGrid">initializeGrid()</h3>
    +<div class="initializegrid"><p>This method register events and methods into grid public API</p></div>
    +</li>
    +<li><h3 id="loadData">loadData()</h3>
    +<div class="loaddata"><p>This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.api.ColumnDef.html b/docs/partials/api/ui.grid.moveColumns.api.ColumnDef.html
    new file mode 100644
    index 000000000..da1ade86b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.api.ColumnDef.html
    @@ -0,0 +1,14 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Column Definition for move column feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions.columnDef">gridOptions.columnDefs</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableColumnMoving">enableColumnMoving</h3>
    +<div class="enablecolumnmoving"><p>Enable column moving for the column.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.api.GridOptions.html b/docs/partials/api/ui.grid.moveColumns.api.GridOptions.html
    new file mode 100644
    index 000000000..4485769b1
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.api.GridOptions.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Options for configuring the move column feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableColumnMoving">enableColumnMoving</h3>
    +<div class="enablecolumnmoving"><p>If defined, sets the default value for the colMovable flag on each individual colDefs
    +if their individual enableColumnMoving configuration is not defined. Defaults to true.</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.api.PublicApi.html b/docs/partials/api/ui.grid.moveColumns.api.PublicApi.html
    new file mode 100644
    index 000000000..515431556
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.api.PublicApi.html
    @@ -0,0 +1,41 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for column moving feature.</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="moveColumn">moveColumn(originalPosition, finalPosition)</h3>
    +<div class="movecolumn"><p>Method can be used to change column position.
    +<pre class="prettyprint linenums">
    +     gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">originalPosition – {integer} – </code>
    +<p>of the column</p></li>
    +<li><code ng:non-bindable="">finalPosition – {integer} – </code>
    +<p>of the column</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="columnPositionChanged">columnPositionChanged</h3>
    +<div class="columnpositionchanged"><p>raised when column is moved
    +<pre class="prettyprint linenums">
    +     gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the column that was moved</p></li>
    +<li><code ng:non-bindable="">originalPosition – {integer} – </code>
    +<p>of the column</p></li>
    +<li><code ng:non-bindable="">finalPosition – {integer} – </code>
    +<p>of the column</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.directive.uiGridHeaderCell.html b/docs/partials/api/ui.grid.moveColumns.directive.uiGridHeaderCell.html
    new file mode 100644
    index 000000000..5b7c7c8c1
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.directive.uiGridHeaderCell.html
    @@ -0,0 +1,25 @@
    +<h1><code ng:non-bindable="">uiGridHeaderCell</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.</p>
    +
    +<p>On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    + In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    + On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.</p>
    +
    +<p>Events that invoke cloning of header cell:
    +   - mousedown</p>
    +
    +<p>Events that invoke movement of cloned header cell:
    +   - mousemove</p>
    +
    +<p>Events that invoke repositioning of column:
    +   - mouseup</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-header-cell&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.directive.uiGridMoveColumns.html b/docs/partials/api/ui.grid.moveColumns.directive.uiGridMoveColumns.html
    new file mode 100644
    index 000000000..354509cc5
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.directive.uiGridMoveColumns.html
    @@ -0,0 +1,52 @@
    +<h1><code ng:non-bindable="">uiGridMoveColumns</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds column moving features to the ui-grid directive.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-move-columns&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-3" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-3" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-3">
    +<div ng-controller="MainCtrl">
    +<div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +.grid {
    +   width: 100%;
    +   height: 150px;
    + }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +     $scope.data = [
    +       { name: 'Bob', title: 'CEO', age: 45 },
    +       { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +       { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +     ];
    +     $scope.columnDefs = [
    +       {name: 'name'},
    +       {name: 'title'},
    +       {name: 'age'}
    +     ];
    +   }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-3" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.html b/docs/partials/api/ui.grid.moveColumns.html
    new file mode 100644
    index 000000000..9c986f8cb
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.html
    @@ -0,0 +1,9 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridmovecolumns">ui.grid.moveColumns</h2>
    +
    +<p>This module provides column moving capability to ui.grid. It enables to change the position of columns.</p>
    +
    +<div doc-module-components="ui.grid.moveColumns">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.moveColumns.service.uiGridMoveColumnService.html b/docs/partials/api/ui.grid.moveColumns.service.uiGridMoveColumnService.html
    new file mode 100644
    index 000000000..0ef62c175
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.moveColumns.service.uiGridMoveColumnService.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridMoveColumnService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.moveColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Service for column moving feature.</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pagination.api.GridOptions.html b/docs/partials/api/ui.grid.pagination.api.GridOptions.html
    new file mode 100644
    index 000000000..67cd108d5
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.api.GridOptions.html
    @@ -0,0 +1,38 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.pagination</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for the pagination feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enablePagination">enablePagination</h3>
    +<div class="enablepagination"><p>Enables pagination, defaults to true</p></div>
    +</li>
    +<li><h3 id="enablePaginationControls">enablePaginationControls</h3>
    +<div class="enablepaginationcontrols"><p>Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +own controls outside the grid.</p></div>
    +</li>
    +<li><h3 id="paginationCurrentPage">paginationCurrentPage</h3>
    +<div class="paginationcurrentpage"><p>Current page number, defaults to 1</p></div>
    +</li>
    +<li><h3 id="paginationPageSize">paginationPageSize</h3>
    +<div class="paginationpagesize"><p>Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty</p></div>
    +</li>
    +<li><h3 id="paginationPageSizes">paginationPageSizes</h3>
    +<div class="paginationpagesizes"><p>Array of page sizes, defaults to <code>[250, 500, 1000]</code></p></div>
    +</li>
    +<li><h3 id="paginationTemplate">paginationTemplate</h3>
    +<div class="paginationtemplate"><p>A custom template for the pager, defaults to <code>ui-grid/pagination</code></p></div>
    +</li>
    +<li><h3 id="totalItems">totalItems</h3>
    +<div class="totalitems"><p>Total number of items, set automatically when client side pagination, needs set by user
    +for server side pagination</p></div>
    +</li>
    +<li><h3 id="useExternalPagination">useExternalPagination</h3>
    +<div class="useexternalpagination"><p>Disables client side pagination. When true, handle the paginationChanged event and set data
    +and totalItems, defaults to <code>false</code></p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pagination.api.PublicAPI.html b/docs/partials/api/ui.grid.pagination.api.PublicAPI.html
    new file mode 100644
    index 000000000..b25b87e0c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.api.PublicAPI.html
    @@ -0,0 +1,43 @@
    +<h1><code ng:non-bindable="">PublicAPI</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.pagination</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public API for the pagination feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getPage">getPage()</h3>
    +<div class="getpage"><p>Returns the number of the current page</p></div>
    +</li>
    +<li><h3 id="getTotalPages">getTotalPages()</h3>
    +<div class="gettotalpages"><p>Returns the total number of pages</p></div>
    +</li>
    +<li><h3 id="nextPage">nextPage()</h3>
    +<div class="nextpage"><p>Moves to the next page, if possible</p></div>
    +</li>
    +<li><h3 id="previousPage">previousPage()</h3>
    +<div class="previouspage"><p>Moves to the previous page, if we're not on the first page</p></div>
    +</li>
    +<li><h3 id="seek">seek(page)</h3>
    +<div class="seek"><p>Moves to the requested page</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">page – {int} – </code>
    +<p>The number of the page that should be displayed</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="paginationChanged">paginationChanged</h3>
    +<div class="paginationchanged"><p>This event fires when the pageSize or currentPage changes</p><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">currentPage – {int} – </code>
    +<p>requested page number</p></li>
    +<li><code ng:non-bindable="">pageSize – {int} – </code>
    +<p>requested page size</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pagination.directive.uiGridPager.html b/docs/partials/api/ui.grid.pagination.directive.uiGridPager.html
    new file mode 100644
    index 000000000..13405e816
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.directive.uiGridPager.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">uiGridPager</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.pagination</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Panel for handling pagination</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-pager&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;div class="ui-grid-pager"&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pagination.directive.uiGridPagination.html b/docs/partials/api/ui.grid.pagination.directive.uiGridPagination.html
    new file mode 100644
    index 000000000..96891b8d9
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.directive.uiGridPagination.html
    @@ -0,0 +1,58 @@
    +<h1><code ng:non-bindable="">uiGridPagination</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.pagination</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds pagination features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-pagination&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-4" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-4" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-4">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="gridOptions" ui-grid-pagination></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Alex', car: 'Toyota' },
    +     { name: 'Sam', car: 'Lexus' },
    +     { name: 'Joe', car: 'Dodge' },
    +     { name: 'Bob', car: 'Buick' },
    +     { name: 'Cindy', car: 'Ford' },
    +     { name: 'Brian', car: 'Audi' },
    +     { name: 'Malcom', car: 'Mercedes Benz' },
    +     { name: 'Dave', car: 'Ford' },
    +     { name: 'Stacey', car: 'Audi' },
    +     { name: 'Amy', car: 'Acura' },
    +     { name: 'Scott', car: 'Toyota' },
    +     { name: 'Ryan', car: 'BMW' },
    +   ];
    +
    +   $scope.gridOptions = {
    +     data: 'data',
    +     paginationPageSizes: [5, 10, 25],
    +     paginationPageSize: 5,
    +     columnDefs: [
    +       {name: 'name'},
    +       {name: 'car'}
    +     ];
    +    }
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-4" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pagination.html b/docs/partials/api/ui.grid.pagination.html
    new file mode 100644
    index 000000000..8902fc5c3
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.html
    @@ -0,0 +1,6 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridpagination">ui.grid.pagination</h2>
    +
    +<p>This module provides pagination support to ui-grid</p></div>
    diff --git a/docs/partials/api/ui.grid.pagination.service.uiGridPaginationService.html b/docs/partials/api/ui.grid.pagination.service.uiGridPaginationService.html
    new file mode 100644
    index 000000000..4fc30ed40
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pagination.service.uiGridPaginationService.html
    @@ -0,0 +1,28 @@
    +<h1><code ng:non-bindable="">uiGridPaginationService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.pagination</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Service for the pagination feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="initializeGrid">initializeGrid(grid)</h3>
    +<div class="initializegrid"><p>Attaches the service to a certain grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>The grid we want to work with</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="uiGridPaginationService">uiGridPaginationService(grid, currentPage, pageSize)</h3>
    +<div class="uigridpaginationservice"><p>Raises paginationChanged and calls refresh for client side pagination</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid for which the pagination changed</p></li>
    +<li><code ng:non-bindable="">currentPage – {int} – </code>
    +<p>requested page number</p></li>
    +<li><code ng:non-bindable="">pageSize – {int} – </code>
    +<p>requested page size</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.paging.api.PublicAPI.html b/docs/partials/api/ui.grid.paging.api.PublicAPI.html
    new file mode 100644
    index 000000000..dafb886a9
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.paging.api.PublicAPI.html
    @@ -0,0 +1,21 @@
    +<h1><code ng:non-bindable="">PublicAPI</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.paging</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public API for the paging feature</p></div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="pagingChanged">pagingChanged</h3>
    +<div class="pagingchanged"><p>This event fires when the pageSize or currentPage changes</p><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">requested – {currentPage} – </code>
    +<p>page number</p></li>
    +<li><code ng:non-bindable="">requested – {pageSize} – </code>
    +<p>page size </p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.paging.directive.uiGridPager.html b/docs/partials/api/ui.grid.paging.directive.uiGridPager.html
    new file mode 100644
    index 000000000..657e4cb13
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.paging.directive.uiGridPager.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">uiGridPager</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.paging</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Panel for handling paging</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-pager&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;div class="ui-grid-pager"&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.paging.directive.uiGridPaging.html b/docs/partials/api/ui.grid.paging.directive.uiGridPaging.html
    new file mode 100644
    index 000000000..9628c43d6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.paging.directive.uiGridPaging.html
    @@ -0,0 +1,58 @@
    +<h1><code ng:non-bindable="">uiGridPaging</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.paging</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds paging features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-paging&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-4" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-4" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-4">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="gridOptions" ui-grid-paging></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.paging']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Alex', car: 'Toyota' },
    +     { name: 'Sam', car: 'Lexus' },
    +     { name: 'Joe', car: 'Dodge' },
    +     { name: 'Bob', car: 'Buick' },
    +     { name: 'Cindy', car: 'Ford' },
    +     { name: 'Brian', car: 'Audi' },
    +     { name: 'Malcom', car: 'Mercedes Benz' },
    +     { name: 'Dave', car: 'Ford' },
    +     { name: 'Stacey', car: 'Audi' },
    +     { name: 'Amy', car: 'Acura' },
    +     { name: 'Scott', car: 'Toyota' },
    +     { name: 'Ryan', car: 'BMW' },
    +   ];
    +
    +   $scope.gridOptions = {
    +     data: 'data',
    +     pagingPageSizes: [5, 10, 25],
    +     pagingPageSize: 5,
    +     columnDefs: [
    +       {name: 'name'},
    +       {name: 'car'}
    +     ];
    +    }
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-4" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.paging.html b/docs/partials/api/ui.grid.paging.html
    new file mode 100644
    index 000000000..4f26851ee
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.paging.html
    @@ -0,0 +1,6 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridpaging">ui.grid.paging</h2>
    +
    +<p>This module provides paging support to ui-grid</p></div>
    diff --git a/docs/partials/api/ui.grid.paging.service.uiGridPagingService.html b/docs/partials/api/ui.grid.paging.service.uiGridPagingService.html
    new file mode 100644
    index 000000000..111e6351d
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.paging.service.uiGridPagingService.html
    @@ -0,0 +1,28 @@
    +<h1><code ng:non-bindable="">uiGridPagingService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.paging</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Service for the paging feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="initializeGrid">initializeGrid(grid)</h3>
    +<div class="initializegrid"><p>Attaches the service to a certain grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>The grid we want to work with</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="uiGridPagingService">uiGridPagingService(the, requested, requested)</h3>
    +<div class="uigridpagingservice"><p>Raises pagingChanged and calls refresh for client side paging</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">the – {grid} – </code>
    +<p>grid for which the paging changed</p></li>
    +<li><code ng:non-bindable="">requested – {currentPage} – </code>
    +<p>page number</p></li>
    +<li><code ng:non-bindable="">requested – {pageSize} – </code>
    +<p>page size </p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pinning.api.ColDef.html b/docs/partials/api/ui.grid.pinning.api.ColDef.html
    new file mode 100644
    index 000000000..1e0249139
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pinning.api.ColDef.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">ColDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.pinning</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColDef for pinning feature</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pinning.api.ColumnDef.html b/docs/partials/api/ui.grid.pinning.api.ColumnDef.html
    new file mode 100644
    index 000000000..dab24d44e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pinning.api.ColumnDef.html
    @@ -0,0 +1,23 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.pinning</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColumnDef for pinning feature, these are available to be 
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions.columnDef">gridOptions.columnDefs</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enablePinning">enablePinning</h3>
    +<div class="enablepinning"><p>Enable pinning for the individual column. <br />
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="pinnedLeft">pinnedLeft</h3>
    +<div class="pinnedleft"><p>Column is pinned left when grid is rendered
    +<br/>Defaults to false</p></div>
    +</li>
    +<li><h3 id="pinnedRight">pinnedRight</h3>
    +<div class="pinnedright"><p>Column is pinned right when grid is rendered
    +<br/>Defaults to false</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pinning.api.GridOptions.html b/docs/partials/api/ui.grid.pinning.api.GridOptions.html
    new file mode 100644
    index 000000000..d47e3f93b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pinning.api.GridOptions.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.pinning</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for pinning feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enablePinning">enablePinning</h3>
    +<div class="enablepinning"><p>Enable pinning for the entire grid. <br />
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.pinning.html b/docs/partials/api/ui.grid.pinning.html
    new file mode 100644
    index 000000000..b358e3e57
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.pinning.html
    @@ -0,0 +1,11 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridpinning">ui.grid.pinning</h2>
    +
    +<p>This module provides column pinning to the end user via menu options in the column header
    +<br/>
    +<br/></p>
    +
    +<div doc-module-components="ui.grid.pinning">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.api.ColDef.html b/docs/partials/api/ui.grid.resizeColumns.api.ColDef.html
    new file mode 100644
    index 000000000..83a0a5dcd
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.api.ColDef.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">ColDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColDef for resizeColumns feature</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.api.ColumnDef.html b/docs/partials/api/ui.grid.resizeColumns.api.ColumnDef.html
    new file mode 100644
    index 000000000..c6df3843d
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.api.ColumnDef.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">ColumnDef</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>ColumnDef for resizeColumns feature, these are available to be 
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions.columnDef">gridOptions.columnDefs</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableColumnResizing">enableColumnResizing</h3>
    +<div class="enablecolumnresizing"><p>Enable column resizing on an individual column
    +<br/>Defaults to GridOptions.enableColumnResizing</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.api.GridOptions.html b/docs/partials/api/ui.grid.resizeColumns.api.GridOptions.html
    new file mode 100644
    index 000000000..973208ae7
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.api.GridOptions.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for resizeColumns feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableColumnResizing">enableColumnResizing</h3>
    +<div class="enablecolumnresizing"><p>Enable column resizing on the entire grid 
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.api.PublicApi.html b/docs/partials/api/ui.grid.resizeColumns.api.PublicApi.html
    new file mode 100644
    index 000000000..bb2d9442e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.api.PublicApi.html
    @@ -0,0 +1,24 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for column resize feature.</p></div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="columnSizeChanged">columnSizeChanged</h3>
    +<div class="columnsizechanged"><p>raised when column is resized
    +<pre class="prettyprint linenums">
    +     gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>the column that was resized</p></li>
    +<li><code ng:non-bindable="">delta – {integer} – </code>
    +<p>of the column size change</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.directive.uiGridColumnResizer.html b/docs/partials/api/ui.grid.resizeColumns.directive.uiGridColumnResizer.html
    new file mode 100644
    index 000000000..a32a92528
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.directive.uiGridColumnResizer.html
    @@ -0,0 +1,54 @@
    +<h1><code ng:non-bindable="">uiGridColumnResizer</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Draggable handle that controls column resizing.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-column-resizer&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js script.js" source-edit-html="index.html-7" source-edit-css="" source-edit-js="script.js-6" source-edit-unit="" source-edit-scenario="scenario.js-8"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-7" ng-html-wrap-loaded="app angular.js script.js"></pre>
    +<script type="text/ng-template" id="index.html-7">
    +  
    +
    +  <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="script.js">
    +<pre class="prettyprint linenums" ng-set-text="script.js-6"></pre>
    +<script type="text/ng-template" id="script.js-6">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +     $scope.gridOpts = {
    +       enableColumnResizing: true,
    +       data: [
    +         { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +         { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +         { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +         { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +       ]
    +     };
    +   }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-8"></pre>
    +<script type="text/ng-template" id="scenario.js-8">
    + // TODO: e2e specs?
    +   // TODO: Obey minWidth and maxWIdth;
    +
    + // TODO: post-resize a horizontal scroll event should be fired
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-7" ng-eval-javascript="script.js-6"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.resizeColumns.directive.uiGridResizeColumns.html b/docs/partials/api/ui.grid.resizeColumns.directive.uiGridResizeColumns.html
    new file mode 100644
    index 000000000..b1fddf973
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.resizeColumns.directive.uiGridResizeColumns.html
    @@ -0,0 +1,51 @@
    +<h1><code ng:non-bindable="">uiGridResizeColumns</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.resizeColumns</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-resize-columns&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js script.js" source-edit-html="index.html-5" source-edit-css="" source-edit-js="script.js" source-edit-unit="" source-edit-scenario="scenario.js"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-5" ng-html-wrap-loaded="app angular.js script.js"></pre>
    +<script type="text/ng-template" id="index.html-5">
    +
    +
    +<div ng-controller="MainCtrl">
    +<div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="script.js">
    +<pre class="prettyprint linenums" ng-set-text="script.js"></pre>
    +<script type="text/ng-template" id="script.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +       $scope.gridOpts = {
    +         data: [
    +           { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +           { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +           { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +           { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +         ]
    +       };
    +     }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js"></pre>
    +<script type="text/ng-template" id="scenario.js">
    +
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-5" ng-eval-javascript="script.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.api.GridOptions.html b/docs/partials/api/ui.grid.rowEdit.api.GridOptions.html
    new file mode 100644
    index 000000000..2bd1b245d
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.api.GridOptions.html
    @@ -0,0 +1,22 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Options for configuring the rowEdit feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="rowEditWaitInterval">rowEditWaitInterval</h3>
    +<div class="roweditwaitinterval"><p>How long the grid should wait for another change on this row
    +before triggering a save (in milliseconds).  If set to -1, then saves are 
    +never triggered by timer (implying that the user will call flushDirtyRows() 
    +manually)</p><h4 id="Example">Example</h4>
    +<div class="example"><p>Setting the wait interval to 4 seconds
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.api.PublicApi.html b/docs/partials/api/ui.grid.rowEdit.api.PublicApi.html
    new file mode 100644
    index 000000000..3361e265f
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.api.PublicApi.html
    @@ -0,0 +1,100 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for rowEdit feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="flushDirtyRows">flushDirtyRows()</h3>
    +<div class="flushdirtyrows"><p>Triggers a save event for all currently dirty rows, could
    +be used where user presses a save button or navigates away from the page
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.flushDirtyRows(grid)
    +</pre><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>a promise that represents the aggregate of all
    +of the individual save promises - i.e. it will be resolved when all
    +the individual save promises have been resolved.</p></div>
    +</div>
    +</li>
    +<li><h3 id="getDirtyRows">getDirtyRows()</h3>
    +<div class="getdirtyrows"><p>Returns all currently dirty rows
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.getDirtyRows(grid)
    +</pre><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>An array of gridRows that are currently dirty</p></div>
    +</div>
    +</li>
    +<li><h3 id="getErrorRows">getErrorRows()</h3>
    +<div class="geterrorrows"><p>Returns all currently errored rows
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.getErrorRows(grid)
    +</pre><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>An array of gridRows that are currently in error</p></div>
    +</div>
    +</li>
    +<li><h3 id="setRowsDirty">setRowsDirty(dataRows)</h3>
    +<div class="setrowsdirty"><p>Sets each of the rows passed in dataRows
    +to be dirty.  note that if you have only just inserted the
    +rows into your data you will need to wait for a $digest cycle
    +before the gridRows are present - so often you would wrap this
    +call in a $interval or $timeout
    +<pre class="prettyprint linenums">
    +     $interval( function() {
    +       gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +     }, 0, 1);
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">dataRows – {array} – </code>
    +<p>the data entities for which the gridRows
    +should be set dirty.  </p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setSavePromise">setSavePromise(rowEntity, savePromise)</h3>
    +<div class="setsavepromise"><p>Sets the promise associated with the row save, mandatory that
    +the saveRow event handler calls this method somewhere before returning.
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>a data row from the grid for which a save has
    +been initiated</p></li>
    +<li><code ng:non-bindable="">savePromise – {promise} – </code>
    +<p>the promise that will be resolved when the
    +save is successful, or rejected if the save fails</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="saveRow">saveRow</h3>
    +<div class="saverow"><p>raised when a row is ready for saving.  Once your
    +row has saved you may need to use angular.extend to update the
    +data entity with any changed data from your save (for example, 
    +lock version information if you're using optimistic locking,
    +or last update time/user information).</p>
    +
    +<p>Your method should call setSavePromise somewhere in the body before
    +returning control.  The feature will then wait, with the gridRow greyed out 
    +whilst this promise is being resolved.</p>
    +
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +</pre>
    +and somewhere within the event handler:
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +</pre><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the options.data element that was edited</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.constant.uiGridRowEditConstants.html b/docs/partials/api/ui.grid.rowEdit.constant.uiGridRowEditConstants.html
    new file mode 100644
    index 000000000..f722b72a9
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.constant.uiGridRowEditConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridRowEditConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in row edit module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.directive.uiGridEdit.html b/docs/partials/api/ui.grid.rowEdit.directive.uiGridEdit.html
    new file mode 100644
    index 000000000..807adfc1f
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.directive.uiGridEdit.html
    @@ -0,0 +1,12 @@
    +<h1><code ng:non-bindable="">uiGridEdit</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds row editing features to the ui-grid-edit directive.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-edit&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.directive.uiGridViewport.html b/docs/partials/api/ui.grid.rowEdit.directive.uiGridViewport.html
    new file mode 100644
    index 000000000..101171555
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.directive.uiGridViewport.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">uiGridViewport</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +for the grid row to allow coloring of saving and error rows</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-viewport&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;div class="ui-grid-viewport"&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.html b/docs/partials/api/ui.grid.rowEdit.html
    new file mode 100644
    index 000000000..17f8f3cc9
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.html
    @@ -0,0 +1,12 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridrowedit">ui.grid.rowEdit</h2>
    +
    +<p>This module extends the edit feature to provide tracking and saving of rows
    +of data.  The tutorial provides more information on how this feature is best
    +used <a href="#/tutorial/205_row_editable">here</a>.
    +<br/>
    +This feature depends on usage of the ui-grid-edit feature, and also benefits
    +from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +experience</p></div>
    diff --git a/docs/partials/api/ui.grid.rowEdit.service.uiGridRowEditService.html b/docs/partials/api/ui.grid.rowEdit.service.uiGridRowEditService.html
    new file mode 100644
    index 000000000..51c3afd73
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.rowEdit.service.uiGridRowEditService.html
    @@ -0,0 +1,193 @@
    +<h1><code ng:non-bindable="">uiGridRowEditService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.rowEdit</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for row editing features</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="beginEditCell">beginEditCell(rowEntity)</h3>
    +<div class="begineditcell"><p>Receives a beginCellEdit event from the edit function,
    +and cancels any rowEditSaveTimers if present, as the user is still editing
    +this row.  Only the rowEntity parameter
    +is processed, although other params are available.  Grid
    +is automatically provided by the gridApi. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the data entity for which the cell
    +editing has commenced</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="cancelEditCell">cancelEditCell(rowEntity)</h3>
    +<div class="canceleditcell"><p>Receives a cancelCellEdit event from the edit function,
    +and if the row was already dirty, restarts the save timer.  If the row
    +was not already dirty, then it's not dirty now either and does nothing.</p>
    +
    +<p>Only the rowEntity parameter
    +is processed, although other params are available.  Grid
    +is automatically provided by the gridApi.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the data entity for which the cell
    +editing was cancelled</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="cancelTimer">cancelTimer(grid, gridRow)</h3>
    +<div class="canceltimer"><p>cancel the $interval for any timer running on this row
    +then delete the timer itself</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which we are processing</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row for which the timer should be adjusted</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="considerSetTimer">considerSetTimer(grid, gridRow)</h3>
    +<div class="considersettimer"><p>Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +dirty and not currently saving then set a new timer</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which we are processing</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row for which the timer should be adjusted</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="endEditCell">endEditCell(rowEntity)</h3>
    +<div class="endeditcell"><p>Receives an afterCellEdit event from the edit function,
    +and sets flags as appropriate.  Only the rowEntity parameter
    +is processed, although other params are available.  Grid
    +is automatically provided by the gridApi. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>the data entity for which the cell
    +was edited</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="flushDirtyRows">flushDirtyRows(grid)</h3>
    +<div class="flushdirtyrows"><p>Triggers a save event for all currently dirty rows, could
    +be used where user presses a save button or navigates away from the page
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.flushDirtyRows(grid)
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which dirty rows should be flushed</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{promise}</code>
    +– <p>a promise that represents the aggregate of all
    +of the individual save promises - i.e. it will be resolved when all
    +the individual save promises have been resolved.</p></div>
    +</div>
    +</li>
    +<li><h3 id="isRowPresent">isRowPresent(rowArray, gridRow)</h3>
    +<div class="isrowpresent"><p>Checks whether a row is already present
    +in the given array </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowArray – {array} – </code>
    +<p>the array in which to look for the row</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row that should be looked for</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="navigate">navigate(newRowCol, oldRowCol)</h3>
    +<div class="navigate"><p>cellNav tells us that the selected cell has changed.  If
    +the new row had a timer running, then stop it similar to in a beginCellEdit
    +call.  If the old row is dirty and not the same as the new row, then 
    +start a timer on it.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">newRowCol – {object} – </code>
    +<p>the row and column that were selected</p></li>
    +<li><code ng:non-bindable="">oldRowCol – {object} – </code>
    +<p>the row and column that was left</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="processErrorPromise">processErrorPromise(grid, gridRow)</h3>
    +<div class="processerrorpromise"><p>Returns a function that processes the failed
    +resolution of a save promise  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which the promise should be processed</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row that is now in error</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>the error handling function</p></div>
    +</div>
    +</li>
    +<li><h3 id="processSuccessPromise">processSuccessPromise(grid, gridRow)</h3>
    +<div class="processsuccesspromise"><p>Returns a function that processes the successful
    +resolution of a save promise  </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which the promise should be processed</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row that has been saved</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>the success handling function</p></div>
    +</div>
    +</li>
    +<li><h3 id="removeRow">removeRow(rowArray, gridRow)</h3>
    +<div class="removerow"><p>Removes a row from a cache of rows - either
    +grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +is not present silently does nothing. </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowArray – {array} – </code>
    +<p>the array from which to remove the row</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row that should be removed</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="saveRow">saveRow(grid, gridRow)</h3>
    +<div class="saverow"><p>Returns a function that saves the specified row from the grid,
    +and returns a promise</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which dirty rows should be flushed</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row that should be saved</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>the saveRow function returns a function.  That function
    +in turn, when called, returns a promise relating to the save callback</p></div>
    +</div>
    +</li>
    +<li><h3 id="setRowsDirty">setRowsDirty(grid, dataRows)</h3>
    +<div class="setrowsdirty"><p>Sets each of the rows passed in dataRows
    +to be dirty.  note that if you have only just inserted the
    +rows into your data you will need to wait for a $digest cycle
    +before the gridRows are present - so often you would wrap this
    +call in a $interval or $timeout
    +<pre class="prettyprint linenums">
    +     $interval( function() {
    +       gridApi.rowEdit.setRowsDirty( myDataRows);
    +     }, 0, 1);
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which rows should be set dirty</p></li>
    +<li><code ng:non-bindable="">dataRows – {array} – </code>
    +<p>the data entities for which the gridRows
    +should be set dirty.  </p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setSavePromise">setSavePromise(grid, rowEntity, savePromise)</h3>
    +<div class="setsavepromise"><p>Sets the promise associated with the row save, mandatory that
    +the saveRow event handler calls this method somewhere before returning.
    +<pre class="prettyprint linenums">
    +     gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +</pre><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {object} – </code>
    +<p>the grid for which dirty rows should be returned</p></li>
    +<li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>a data row from the grid for which a save has
    +been initiated</p></li>
    +<li><code ng:non-bindable="">savePromise – {promise} – </code>
    +<p>the promise that will be resolved when the
    +save is successful, or rejected if the save fails</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.saveState.api.GridOptions.html b/docs/partials/api/ui.grid.saveState.api.GridOptions.html
    new file mode 100644
    index 000000000..1b9d41f9b
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.api.GridOptions.html
    @@ -0,0 +1,93 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.saveState</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for saveState feature, these are available to be <br />
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="saveFilter">saveFilter</h3>
    +<div class="savefilter"><p>Save the current filter state for each column</p>
    +
    +<p><br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="saveFocus">saveFocus</h3>
    +<div class="savefocus"><p>Save the current focused cell.  On returning
    +to this focused cell we'll also scroll.  This option is
    +preferred to the saveScroll option, so is set to true by
    +default.  If saveScroll is set to true then this option will 
    +be disabled.  </p>
    +
    +<p>By default this option saves the current row number and column 
    +number, and returns to that row and column.  However, if you define
    +a saveRowIdentity function, then it will return you to the currently 
    +selected column within that row (in a business sense - so if some
    +rows have been deleted, it will still find the same data, presuming it 
    +still exists in the list.  If it isn't in the list then it will instead
    +return to the same row number - i.e. scroll percentage)</p>
    +
    +<p>Note that this option will do nothing if the cellNav
    +feature is not enabled.</p>
    +
    +<p><br/>Defaults to true (unless saveScroll is true)</p></div>
    +</li>
    +<li><h3 id="saveOrder">saveOrder</h3>
    +<div class="saveorder"><p>Save the current column order.  Note that unless
    +you've provided the user with some way to reorder their columns (for
    +example the move columns feature), this makes little sense.
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="saveRowIdentity">saveRowIdentity</h3>
    +<div class="saverowidentity"><p>A function that can be called, passing in a rowEntity, 
    +and that will return a unique id for that row.  This might simply 
    +return the <code>id</code> field from that row (if you have one), or it might
    +concatenate some fields within the row to make a unique value.</p>
    +
    +<p>This value will be used to find the same row again and set the focus 
    +to it, if it exists when we return.</p>
    +
    +<p><br/>Defaults to undefined</p></div>
    +</li>
    +<li><h3 id="saveScroll">saveScroll</h3>
    +<div class="savescroll"><p>Save the current scroll position.  Note that this
    +is saved as the percentage of the grid scrolled - so if your
    +user returns to a grid with a significantly different number of 
    +rows (perhaps some data has been deleted) then the scroll won't 
    +actually show the same rows as before.  If you want to scroll to
    +a specific row then you should instead use the saveFocus option, which
    +is the default.</p>
    +
    +<p>Note that this element will only be saved if the cellNav feature is
    +enabled
    +<br/>Defaults to false</p></div>
    +</li>
    +<li><h3 id="saveSelection">saveSelection</h3>
    +<div class="saveselection"><p>Save the currently selected rows.  If the <code>saveRowIdentity</code> callback
    +is defined, then it will save the id of the row and select that.  If not, then
    +it will attempt to select the rows by row number, which will give the wrong results
    +if the data set has changed in the mean-time.</p>
    +
    +<p>Note that this option only does anything
    +if the selection feature is enabled.  </p>
    +
    +<p><br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="saveSort">saveSort</h3>
    +<div class="savesort"><p>Save the current sort state for each column</p>
    +
    +<p><br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="saveVisible">saveVisible</h3>
    +<div class="savevisible"><p>Save whether or not columns are visible.</p>
    +
    +<p><br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="saveWidths">saveWidths</h3>
    +<div class="savewidths"><p>Save the current column widths.  Note that unless
    +you've provided the user with some way to resize their columns (say
    +the resize columns feature), then this makes little sense.
    +<br/>Defaults to true</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.saveState.api.PublicApi.html b/docs/partials/api/ui.grid.saveState.api.PublicApi.html
    new file mode 100644
    index 000000000..656cfc35c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.api.PublicApi.html
    @@ -0,0 +1,26 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.saveState</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for saveState feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="restore">restore($scope, state)</h3>
    +<div class="restore"><p>Restores the provided state into the grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {scope} – </code>
    +<p>a scope that we can broadcast on</p></li>
    +<li><code ng:non-bindable="">state – {object} – </code>
    +<p>the state that should be restored into the grid</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="save">save()</h3>
    +<div class="save"><p>Packages the current state of the grid into 
    +an object, and provides it to the user for saving</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the state as a javascript object that can be saved</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.saveState.constant.uiGridSaveStateConstants.html b/docs/partials/api/ui.grid.saveState.constant.uiGridSaveStateConstants.html
    new file mode 100644
    index 000000000..59235627e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.constant.uiGridSaveStateConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridSaveStateConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.saveState</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in save state module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.saveState.directive.uiGridSaveState.html b/docs/partials/api/ui.grid.saveState.directive.uiGridSaveState.html
    new file mode 100644
    index 000000000..66a89fe42
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.directive.uiGridSaveState.html
    @@ -0,0 +1,46 @@
    +<h1><code ng:non-bindable="">uiGridSaveState</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.saveState</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds saveState features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-save-state&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-9" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-9" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-9">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="gridOptions" ui-grid-save-state></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Bob', title: 'CEO' },
    +     { name: 'Frank', title: 'Lowly Developer' }
    +   ];
    +
    +   $scope.gridOptions = {
    +     columnDefs: [
    +       {name: 'name'},
    +       {name: 'title', enableCellEdit: true}
    +     ],
    +     data: $scope.data
    +   };
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-9" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.saveState.html b/docs/partials/api/ui.grid.saveState.html
    new file mode 100644
    index 000000000..753e7bd9c
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.html
    @@ -0,0 +1,17 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridsavestate">ui.grid.saveState</h2>
    +
    +<p>This module provides the ability to save the grid state, and restore
    +it when the user returns to the page.  </p>
    +
    +<p>No UI is provided, the caller should provide their own UI/buttons 
    +as appropriate. Usually the navigate events would be used to save
    +the grid state and restore it.</p>
    +
    +<p><br/>
    +<br/></p>
    +
    +<div doc-module-components="ui.grid.save-state">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.saveState.service.uiGridSaveStateService.html b/docs/partials/api/ui.grid.saveState.service.uiGridSaveStateService.html
    new file mode 100644
    index 000000000..137956fb6
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.saveState.service.uiGridSaveStateService.html
    @@ -0,0 +1,136 @@
    +<h1><code ng:non-bindable="">uiGridSaveStateService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.saveState</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for saveState feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="findRowByIdentity">findRowByIdentity(grid, rowVal)</h3>
    +<div class="findrowbyidentity"><p>Finds a row given it's identity value, returns the first found row
    +if any are found, otherwise returns null if no rows are found.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to restore</p></li>
    +<li><code ng:non-bindable="">rowVal – {object} – </code>
    +<p>the row we'd like to find</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{gridRow}</code>
    +– <p>the found row, or null if none found</p></div>
    +</div>
    +</li>
    +<li><h3 id="getRowVal">getRowVal(grid, gridRow)</h3>
    +<div class="getrowval"><p>Helper function that gets either the rowNum or
    +the saveRowIdentity, given a gridRow </p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid the row is in</p></li>
    +<li><code ng:non-bindable="">gridRow – {GridRow} – </code>
    +<p>the row we want the rowNum for</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>an object containing { identity: true/false, row: rowNumber/rowIdentity }</p></div>
    +</div>
    +</li>
    +<li><h3 id="restore">restore(grid, $scope, state)</h3>
    +<div class="restore"><p>Applies the provided state to the grid</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to restore</p></li>
    +<li><code ng:non-bindable="">$scope – {scope} – </code>
    +<p>a scope that we can broadcast on</p></li>
    +<li><code ng:non-bindable="">state – {object} – </code>
    +<p>the state we'd like to restore</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="restoreColumns">restoreColumns(grid, columnsState)</h3>
    +<div class="restorecolumns"><p>Restores the columns, including order, visible, width
    +sort and filters.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to restore</p></li>
    +<li><code ng:non-bindable="">columnsState – {object} – </code>
    +<p>the list of columns we had before, with their state</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="restoreScrollFocus">restoreScrollFocus(grid, $scope, scrollFocusState)</h3>
    +<div class="restorescrollfocus"><p>Scrolls to the position that was saved.  If focus is true, then
    +sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +specified row/col.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to restore</p></li>
    +<li><code ng:non-bindable="">$scope – {scope} – </code>
    +<p>a scope that we can broadcast on</p></li>
    +<li><code ng:non-bindable="">scrollFocusState – {object} – </code>
    +<p>the scroll/focus state ready to be restored</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="restoreSelection">restoreSelection(grid, selectionState)</h3>
    +<div class="restoreselection"><p>Selects the rows that are provided in the selection
    +state.  If you are using <code>saveRowIdentity</code> and more than one row matches the identity
    +function then only the first is selected.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to restore</p></li>
    +<li><code ng:non-bindable="">selectionState – {object} – </code>
    +<p>the selection state ready to be restored</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="save">save(grid)</h3>
    +<div class="save"><p>Saves the current grid state into an object, and
    +passes that object back to the caller</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to save</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the state ready to be saved</p></div>
    +</div>
    +</li>
    +<li><h3 id="saveColumns">saveColumns(grid)</h3>
    +<div class="savecolumns"><p>Saves the column setup, including sort, filters, ordering
    +and column widths.</p>
    +
    +<p>Works through the current columns, storing them in order.  Stores the
    +column name, then the visible flag, width, sort and filters for each column.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to save</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>the columns state ready to be saved</p></div>
    +</div>
    +</li>
    +<li><h3 id="saveScrollFocus">saveScrollFocus(grid)</h3>
    +<div class="savescrollfocus"><p>Saves the currently scroll or focus.</p>
    +
    +<p>If cellNav isn't present then does nothing - we can't return
    +to the scroll position without cellNav anyway.</p>
    +
    +<p>If the cellNav module is present, and saveFocus is true, then
    +it saves the currently focused cell.  If rowIdentity is present
    +then saves using rowIdentity, otherwise saves visibleRowNum.</p>
    +
    +<p>If the cellNav module is not present, and saveScroll is true, then
    +it approximates the current scroll row and column, and saves that.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to save</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the selection state ready to be saved</p></div>
    +</div>
    +</li>
    +<li><h3 id="saveSelection">saveSelection(grid)</h3>
    +<div class="saveselection"><p>Saves the currently selected rows, if the selection feature is enabled</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid whose state we'd like to save</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>the selection state ready to be saved</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.api.GridOptions.html b/docs/partials/api/ui.grid.selection.api.GridOptions.html
    new file mode 100644
    index 000000000..8145dea55
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.api.GridOptions.html
    @@ -0,0 +1,57 @@
    +<h1><code ng:non-bindable="">GridOptions</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridOptions for selection feature, these are available to be
    +set using the ui-grid <a href="#/api/ui.grid.class:GridOptions">gridOptions</a></p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableFooterTotalSelected">enableFooterTotalSelected</h3>
    +<div class="enablefootertotalselected"><p>Shows the total number of selected items in footer if true.
    +<br/>Defaults to true.
    +<br/>GridOptions.showFooter must also be set to true.</p></div>
    +</li>
    +<li><h3 id="enableRowHeaderSelection">enableRowHeaderSelection</h3>
    +<div class="enablerowheaderselection"><p>Enable a row header to be used for selection
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="enableRowSelection">enableRowSelection</h3>
    +<div class="enablerowselection"><p>Enable row selection for entire grid.
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="enableSelectAll">enableSelectAll</h3>
    +<div class="enableselectall"><p>Enable the select all checkbox at the top of the selectionRowHeader
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="enableSelectionBatchEvent">enableSelectionBatchEvent</h3>
    +<div class="enableselectionbatchevent"><p>If selected rows are changed in bulk, either via the API or
    +via the selectAll checkbox, then a separate event is fired.  Setting this
    +option to false will cause the rowSelectionChanged event to be called multiple times
    +instead
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="isRowSelectable">isRowSelectable</h3>
    +<div class="isrowselectable"><p>Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.</p></div>
    +</li>
    +<li><h3 id="modifierKeysToMultiSelect">modifierKeysToMultiSelect</h3>
    +<div class="modifierkeystomultiselect"><p>Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +<br/>Defaults to false</p></div>
    +</li>
    +<li><h3 id="multiSelect">multiSelect</h3>
    +<div class="multiselect"><p>Enable multiple row selection for entire grid
    +<br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="noUnselect">noUnselect</h3>
    +<div class="nounselect"><p>Prevent a row from being unselected.  Works in conjunction
    +with <code>multiselect = false</code> and <code>gridApi.selection.selectRow()</code> to allow
    +you to create a single selection only grid - a row is always selected, you
    +can only select different rows, you can't unselect the row.
    +<br/>Defaults to false</p></div>
    +</li>
    +<li><h3 id="selectionRowHeaderWidth">selectionRowHeaderWidth</h3>
    +<div class="selectionrowheaderwidth"><p>can be used to set a custom width for the row header selection column
    +<br/>Defaults to 30px</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.api.GridRow.html b/docs/partials/api/ui.grid.selection.api.GridRow.html
    new file mode 100644
    index 000000000..10ab5c4d2
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.api.GridRow.html
    @@ -0,0 +1,31 @@
    +<h1><code ng:non-bindable="">GridRow</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>GridRow prototype functions added for selection</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="setSelected">setSelected(selelected)</h3>
    +<div class="setselected"><p>Sets the isSelected property and updates the selectedCount
    +Changes to isSelected state should only be made via this function</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">selelected – {bool} – </code>
    +<p>value to set</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="enableSelection">enableSelection</h3>
    +<div class="enableselection"><p>Enable row selection for this row, only settable by internal code.</p>
    +
    +<p>The grouping feature, for example, might set group header rows to not be selectable.
    + <br/>Defaults to true</p></div>
    +</li>
    +<li><h3 id="isSelected">isSelected</h3>
    +<div class="isselected"><p>Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +<br/>Defaults to false</p></div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.api.PublicApi.html b/docs/partials/api/ui.grid.selection.api.PublicApi.html
    new file mode 100644
    index 000000000..52614ca51
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.api.PublicApi.html
    @@ -0,0 +1,124 @@
    +<h1><code ng:non-bindable="">PublicApi</code>
    +<span class="hint">(api in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Public Api for selection feature</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="clearSelectedRows">clearSelectedRows(event)</h3>
    +<div class="clearselectedrows"><p>Unselects all rows</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getSelectAllState">getSelectAllState()</h3>
    +<div class="getselectallstate"><p>Returns whether or not the selectAll checkbox is currently ticked.  The
    +grid doesn't automatically select rows when you add extra data - so when you add data
    +you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +if it is</p></div>
    +</li>
    +<li><h3 id="getSelectedGridRows">getSelectedGridRows()</h3>
    +<div class="getselectedgridrows"><p>returns all selectedRow's as gridRows</p></div>
    +</li>
    +<li><h3 id="getSelectedRows">getSelectedRows()</h3>
    +<div class="getselectedrows"><p>returns all selectedRow's entity references</p></div>
    +</li>
    +<li><h3 id="selectAllRows">selectAllRows(event)</h3>
    +<div class="selectallrows"><p>Selects all rows.  Does nothing if multiSelect = false</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="selectAllVisibleRows">selectAllVisibleRows(event)</h3>
    +<div class="selectallvisiblerows"><p>Selects all visible rows.  Does nothing if multiSelect = false</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="selectRow">selectRow(rowEntity, event)</h3>
    +<div class="selectrow"><p>Select the data row</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="selectRowByVisibleIndex">selectRowByVisibleIndex(index, event)</h3>
    +<div class="selectrowbyvisibleindex"><p>Select the specified row by visible index (i.e. if you
    +specify row 0 you'll get the first visible row selected).  In this context
    +visible means of those rows that are theoretically visible (i.e. not filtered),
    +rather than rows currently rendered on the screen.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">index – {number} – </code>
    +<p>index within the rowsVisible array</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setModifierKeysToMultiSelect">setModifierKeysToMultiSelect(modifierKeysToMultiSelect)</h3>
    +<div class="setmodifierkeystomultiselect"><p>Sets the current gridOption.modifierKeysToMultiSelect to true or false</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">modifierKeysToMultiSelect – {bool} – </code>
    +<p>true to only allow multiple rows when using ctrlKey or shiftKey is used</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setMultiSelect">setMultiSelect(multiSelect)</h3>
    +<div class="setmultiselect"><p>Sets the current gridOption.multiSelect to true or false</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">multiSelect – {bool} – </code>
    +<p>true to allow multiple rows</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="toggleRowSelection">toggleRowSelection(rowEntity, event)</h3>
    +<div class="togglerowselection"><p>Toggles data row as selected or unselected</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="unSelectRow">unSelectRow(rowEntity, event)</h3>
    +<div class="unselectrow"><p>UnSelect the data row</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rowEntity – {object} – </code>
    +<p>gridOptions.data[] array instance</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +<div class="member event"><h2 id="Events">Events</h2>
    +<ul class="events"><li><h3 id="rowSelectionChanged">rowSelectionChanged</h3>
    +<div class="rowselectionchanged"><p>is raised after the row.isSelected state is changed</p><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>the row that was selected/deselected</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="rowSelectionChangedBatch">rowSelectionChangedBatch</h3>
    +<div class="rowselectionchangedbatch"><p>is raised after the row.isSelected state is changed
    +in bulk, if the <code>enableSelectionBatchEvent</code> option is set to true
    +(which it is by default).  This allows more efficient processing
    +of bulk events.</p><div class="inline"></div>
    +<div class="inline"></div>
    +<h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">rows – {array} – </code>
    +<p>the rows that were selected/deselected</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.constant.uiGridSelectionConstants.html b/docs/partials/api/ui.grid.selection.constant.uiGridSelectionConstants.html
    new file mode 100644
    index 000000000..3ade0bb34
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.constant.uiGridSelectionConstants.html
    @@ -0,0 +1,7 @@
    +<h1><code ng:non-bindable="">uiGridSelectionConstants</code>
    +<span class="hint">(constant in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>constants available in selection module</p></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.directive.uiGridCell.html b/docs/partials/api/ui.grid.selection.directive.uiGridCell.html
    new file mode 100644
    index 000000000..d246b0fa4
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.directive.uiGridCell.html
    @@ -0,0 +1,12 @@
    +<h1><code ng:non-bindable="">uiGridCell</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridCell to provide selection feature</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-cell&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.directive.uiGridSelection.html b/docs/partials/api/ui.grid.selection.directive.uiGridSelection.html
    new file mode 100644
    index 000000000..36e9967ba
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.directive.uiGridSelection.html
    @@ -0,0 +1,43 @@
    +<h1><code ng:non-bindable="">uiGridSelection</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Adds selection features to grid</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-selection&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-10" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-10" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-10">
    +<div ng-controller="MainCtrl">
    +<div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +   $scope.data = [
    +     { name: 'Bob', title: 'CEO' },
    +         { name: 'Frank', title: 'Lowly Developer' }
    +   ];
    +
    +   $scope.columnDefs = [
    +     {name: 'name', enableCellEdit: true},
    +     {name: 'title', enableCellEdit: true}
    +   ];
    + }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-10" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.directive.uiGridViewport.html b/docs/partials/api/ui.grid.selection.directive.uiGridViewport.html
    new file mode 100644
    index 000000000..2b0009d31
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.directive.uiGridViewport.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable="">uiGridViewport</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +for the grid row</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;div ui-grid-viewport&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +as class<pre class="prettyprint linenums">&lt;div class="ui-grid-viewport"&gt;
    +   ...
    +&lt;/div&gt;</pre>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.grid.selection.html b/docs/partials/api/ui.grid.selection.grid.selection.html
    new file mode 100644
    index 000000000..d42b4f658
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.grid.selection.html
    @@ -0,0 +1,15 @@
    +<h1><code ng:non-bindable="">selection</code>
    +<span class="hint">(grid in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Grid properties and functions added for selection</p></div>
    +<div class="member property"><h2 id="Properties">Properties</h2>
    +<ul class="properties"><li><h3 id="selectedCount">selectedCount</h3>
    +<div class="selectedcount"><p>Current count of selected rows</p><h4 id="Example">Example</h4>
    +<div class="example"><p>var count = grid.selection.selectedCount</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.selection.html b/docs/partials/api/ui.grid.selection.html
    new file mode 100644
    index 000000000..05deb5de2
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.html
    @@ -0,0 +1,11 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h1 id="uigridselection">ui.grid.selection</h2>
    +
    +<p>This module provides row selection
    +<br/>
    +<br/></p>
    +
    +<div doc-module-components="ui.grid.selection">
    +</div></div>
    diff --git a/docs/partials/api/ui.grid.selection.service.uiGridSelectionService.html b/docs/partials/api/ui.grid.selection.service.uiGridSelectionService.html
    new file mode 100644
    index 000000000..e7891f63e
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.selection.service.uiGridSelectionService.html
    @@ -0,0 +1,81 @@
    +<h1><code ng:non-bindable="">uiGridSelectionService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.selection</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for selection features</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="clearSelectedRows">clearSelectedRows(grid, event)</h3>
    +<div class="clearselectedrows"><p>Clears all selected rows</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="decideRaiseSelectionEvent">decideRaiseSelectionEvent(grid, row, changedRows, event)</h3>
    +<div class="decideraiseselectionevent"><p>Decides whether to raise a single event or a batch event</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +<li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>row that has changed</p></li>
    +<li><code ng:non-bindable="">changedRows – {array} – </code>
    +<p>an array to which we can append the changed</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event
    +row if we're doing batch events</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="getSelectedRows">getSelectedRows(grid)</h3>
    +<div class="getselectedrows"><p>Returns all the selected rows</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="raiseSelectionEvent">raiseSelectionEvent(grid, changedRows, event)</h3>
    +<div class="raiseselectionevent"><p>Decides whether we need to raise a batch event, and
    +raises it if we do.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +<li><code ng:non-bindable="">changedRows – {array} – </code>
    +<p>an array of changed rows, only populated</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event
    +if we're doing batch events</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="shiftSelect">shiftSelect(grid, clicked, event, multiSelect)</h3>
    +<div class="shiftselect"><p>selects a group of rows from the last selected row using the shift key</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +<li><code ng:non-bindable="">clicked – {GridRow} – </code>
    +<p>row</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if raised from an event</p></li>
    +<li><code ng:non-bindable="">multiSelect – {bool} – </code>
    +<p>if false, does nothing this is for multiSelect only</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="toggleRowSelection">toggleRowSelection(grid, row, event, multiSelect, noUnselect)</h3>
    +<div class="togglerowselection"><p>Toggles row as selected or unselected</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>grid object</p></li>
    +<li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>row to select or deselect</p></li>
    +<li><code ng:non-bindable="">event – {Event} – </code>
    +<p>object if resulting from event</p></li>
    +<li><code ng:non-bindable="">multiSelect – {bool} – </code>
    +<p>if false, only one row at time can be selected</p></li>
    +<li><code ng:non-bindable="">noUnselect – {bool} – </code>
    +<p>if true then rows cannot be unselected</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.service.GridUtil.html b/docs/partials/api/ui.grid.service.GridUtil.html
    new file mode 100644
    index 000000000..cdc5955ac
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.service.GridUtil.html
    @@ -0,0 +1,284 @@
    +<h1><code ng:non-bindable="">GridUtil</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Grid utility functions</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="createBoundedWrapper">createBoundedWrapper(Object, Method)</h3>
    +<div class="createboundedwrapper"><p>Binds given method to given object.</p>
    +
    +<p>By means of a wrapper, ensures that <code>method</code> is always bound to
    +<code>object</code> regardless of its calling environment.
    +Iow, inside <code>method</code>, <code>this</code> always points to <code>object</code>.</p>
    +
    +<p>See http://alistapart.com/article/getoutbindingsituations</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">Object – {object} – </code>
    +<p>to bind 'this' to</p></li>
    +<li><code ng:non-bindable="">Method – {method} – </code>
    +<p>to bind</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Function}</code>
    +– <p>The wrapper that performs the binding</p></div>
    +</div>
    +</li>
    +<li><h3 id="debounce">debounce(func, wait, immediate)</h3>
    +<div class="debounce"><p>Copied from https://github.com/shahata/angular-debounce
    +Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">func – {function} – </code>
    +<p>function to debounce</p></li>
    +<li><code ng:non-bindable="">wait – {number} – </code>
    +<p>milliseconds to delay</p></li>
    +<li><code ng:non-bindable="">immediate – {bool} – </code>
    +<p>execute before delay</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>A function that can be executed as debounced function</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +debouncedFunc();
    +debouncedFunc();
    +debouncedFunc();
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="elementHeight">elementHeight(element, [extra])</h3>
    +<div class="elementheight"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>DOM element</p></li>
    +<li><code ng:non-bindable="">[extra] – {string} – </code>
    +<p>Optional modifier for calculation. Use 'margin' to account for margins on element</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>Element height in pixels, accounting for any borders, etc.</p></div>
    +</div>
    +</li>
    +<li><h3 id="elementWidth">elementWidth(element, [extra])</h3>
    +<div class="elementwidth"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>DOM element</p></li>
    +<li><code ng:non-bindable="">[extra] – {string} – </code>
    +<p>Optional modifier for calculation. Use 'margin' to account for margins on element</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>Element width in pixels, accounting for any borders, etc.</p></div>
    +</div>
    +</li>
    +<li><h3 id="getColumnsFromData">getColumnsFromData(data)</h3>
    +<div class="getcolumnsfromdata"><p>Return a list of column names, given a data set</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">data – {string} – </code>
    +<p>Data array for grid</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Object}</code>
    +– <p>Column definitions with field accessor and column name</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var data = [
    +  { firstName: 'Bob', lastName: 'Jones' },
    +  { firstName: 'Frank', lastName: 'Smith' }
    +];
    +
    +var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +columnDefs == [
    + {
    +   field: 'firstName',
    +   name: 'First Name'
    + },
    + {
    +   field: 'lastName',
    +   name: 'Last Name'
    + }
    +];
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="getTemplate">getTemplate(Either)</h3>
    +<div class="gettemplate"><p>Get's template from cache / element / url</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">Either – {string|element|promise} – </code>
    +<p>a string representing the template id, a string representing the template url,
    +an jQuery/Angualr element, or a promise that returns the template contents to use.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>a promise resolving to template contents</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +GridUtil.getTemplate(url).then(function (contents) {
    +     alert(contents);
    +   })
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="guessType">guessType(item)</h3>
    +<div class="guesstype"><p>guesses the type of an argument</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">item – {string/number/bool/object} – </code>
    +<p>variable to examine</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>one of the following
    +'string'
    +'boolean'
    +'number'
    +'date'
    +'object'</p></div>
    +</div>
    +</li>
    +<li><h3 id="logDebug">logDebug()</h3>
    +<div class="logdebug"><p>wraps the $log method, allowing us to choose different
    +treatment within ui-grid if we so desired.  At present we only log
    +debug messages if uiGridConstants.LOG<em>DEBUG</em>MESSAGES is set to true</p></div>
    +</li>
    +<li><h3 id="logError">logError(logMessage)</h3>
    +<div class="logerror"><p>wraps the $log method, allowing us to choose different
    +treatment within ui-grid if we so desired.  At present we only log
    +error messages if uiGridConstants.LOG<em>ERROR</em>MESSAGES is set to true</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">logMessage – {string} – </code>
    +<p>message to be logged to the console</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="logWarn">logWarn(logMessage)</h3>
    +<div class="logwarn"><p>wraps the $log method, allowing us to choose different
    +treatment within ui-grid if we so desired.  At present we only log
    +warning messages if uiGridConstants.LOG<em>WARN</em>MESSAGES is set to true</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">logMessage – {string} – </code>
    +<p>message to be logged to the console</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="newId">newId()</h3>
    +<div class="newid"><p>Return a unique ID string</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>Unique string</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var id = GridUtil.newId();
    +
    +# 1387305700482;
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="normalizeScrollLeft">normalizeScrollLeft(element)</h3>
    +<div class="normalizescrollleft"><p>Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>The element to get the <code>scrollLeft</code> from.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{int}</code>
    +– <p>A normalized scrollLeft value for the current browser.</p></div>
    +</div>
    +</li>
    +<li><h3 id="normalizeScrollLeft">normalizeScrollLeft(element, scrollLeft)</h3>
    +<div class="normalizescrollleft"><p>Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>The element to normalize the <code>scrollLeft</code> value for</p></li>
    +<li><code ng:non-bindable="">scrollLeft – {int} – </code>
    +<p>The <code>scrollLeft</code> value to denormalize.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{int}</code>
    +– <p>A normalized scrollLeft value for the current browser.</p></div>
    +</div>
    +</li>
    +<li><h3 id="normalizeWheelEvent">normalizeWheelEvent(event)</h3>
    +<div class="normalizewheelevent"><p>Given an event from this list:</p>
    +
    +<p><code>wheel, mousewheel, DomMouseScroll, MozMousePixelScroll</code></p>
    +
    +<p>"normalize" it
    +so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">event – {event} – </code>
    +<p>A mouse wheel event</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{event}</code>
    +– <p>A normalized event</p></div>
    +</div>
    +</li>
    +<li><h3 id="preEval">preEval(path)</h3>
    +<div class="preeval"><p>Takes a field path and converts it to bracket notation to allow for special characters in path</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">path – {string} – </code>
    +<p>Path to evaluate</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>A path that is normalized.</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +gridUtil.preEval('property') == 'property'
    +gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="readableColumnName">readableColumnName(columnName)</h3>
    +<div class="readablecolumnname"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">columnName – {string} – </code>
    +<p>Column name as a string</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>Column name appropriately capitalized and split apart</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><h6>Source</h6>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-18" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-18" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-18">
    +   <div ng-controller="MainCtrl">
    +     <strong>Column name:</strong> <input ng-model="name" />
    +     <br>
    +     <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +   </div>
    + </script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +     $scope.name = 'firstName';
    +     $scope.columnName = function(name) {
    +       return gridUtil.readableColumnName(name);
    +     };
    +   }]);
    + </script>
    +</div>
    +</div><h6>Demo</h6>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-18" ng-eval-javascript="app.js"></div></div>
    +</div>
    +</li>
    +<li><h3 id="throttle">throttle(func, wait, params)</h3>
    +<div class="throttle"><p>Adapted from debounce function (above)
    +Potential keys for Params Object are:
    +   trailing (bool) - whether to trigger after throttle time ends if called multiple times</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">func – {function} – </code>
    +<p>function to throttle</p></li>
    +<li><code ng:non-bindable="">wait – {number} – </code>
    +<p>milliseconds to delay after first trigger</p></li>
    +<li><code ng:non-bindable="">params – {Object} – </code>
    +<p>to use in throttle.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{function}</code>
    +– <p>A function that can be executed as throttled function</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +throttledFunc(); //=&gt; logs throttled
    +throttledFunc(); //=&gt; queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +throttledFunc(); //=&gt; updates arguments to keep most-recent request, but does not do anything else.
    +</pre></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.service.gridClassFactory.html b/docs/partials/api/ui.grid.service.gridClassFactory.html
    new file mode 100644
    index 000000000..f8a53a718
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.service.gridClassFactory.html
    @@ -0,0 +1,32 @@
    +<h1><code ng:non-bindable="">gridClassFactory</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>factory to return dom specific instances of a grid</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="createGrid">createGrid(options)</h3>
    +<div class="creategrid"><p>Creates a new grid instance. Each instance will have a unique id</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">options – {object} – </code>
    +<p>An object map of options to pass into the created grid instance.</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Grid}</code>
    +– <p>grid</p></div>
    +</div>
    +</li>
    +<li><h3 id="defaultColumnBuilder">defaultColumnBuilder(colDef, col, gridOptions)</h3>
    +<div class="defaultcolumnbuilder"><p>Processes designTime column definitions and applies them to col for the
    +core grid features</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">colDef – {object} – </code>
    +<p>reference to column definition</p></li>
    +<li><code ng:non-bindable="">col – {GridColumn} – </code>
    +<p>reference to gridCol</p></li>
    +<li><code ng:non-bindable="">gridOptions – {object} – </code>
    +<p>reference to grid options</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.service.rowSearcher.html b/docs/partials/api/ui.grid.service.rowSearcher.html
    new file mode 100644
    index 000000000..45d9136dd
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.service.rowSearcher.html
    @@ -0,0 +1,105 @@
    +<h1><code ng:non-bindable="">rowSearcher</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Service for searching/filtering rows based on column value conditions.</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getTerm">getTerm(filter)</h3>
    +<div class="getterm"><p>Get the term from a filter
    +Trims leading and trailing whitespace</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">filter – {object} – </code>
    +<p>object to use</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>Parsed term</p></div>
    +</div>
    +</li>
    +<li><h3 id="guessCondition">guessCondition(filter)</h3>
    +<div class="guesscondition"><p>Guess the condition for a filter based on its term
    +<br>
    +Defaults to STARTS<em>WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +Uses STARTS</em>WITH for strings ending with * (bo<em>). Uses ENDS_WITH for strings starting with * (</em>ob).</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">filter – {object} – </code>
    +<p>object to use</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{uiGridConstants.filter&lt;int&gt;}</code>
    +– <p>Value representing the condition constant value</p></div>
    +</div>
    +</li>
    +<li><h3 id="runColumnFilter">runColumnFilter(grid, row, column, filter)</h3>
    +<div class="runcolumnfilter"><p>Runs a single pre-parsed filter against a cell, returning true
    +if the cell matches that one filter.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>the grid we're working against</p></li>
    +<li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>the row we're matching against</p></li>
    +<li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>the column that we're working against</p></li>
    +<li><code ng:non-bindable="">filter – {object} – </code>
    +<p>the specific, preparsed, filter that we want to test</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{boolean}</code>
    +– <p>true if we match (row stays visible)</p></div>
    +</div>
    +</li>
    +<li><h3 id="search">search(grid, rows, columns)</h3>
    +<div class="search"><p>Run a search across the given rows and columns, marking any rows that don't 
    +match the stored col.filters or col.filter as invisible.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>Grid instance to search inside</p></li>
    +<li><code ng:non-bindable="">rows – {Array[GridRow]} – </code>
    +<p>GridRows to filter</p></li>
    +<li><code ng:non-bindable="">columns – {Array[GridColumn]} – </code>
    +<p>GridColumns with filters to process</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="searchColumn">searchColumn(grid, row, column, filters)</h3>
    +<div class="searchcolumn"><p>Process provided filters on provided column against a given row. If the row meets 
    +the conditions on all the filters, return true.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">grid – {Grid} – </code>
    +<p>Grid to search in</p></li>
    +<li><code ng:non-bindable="">row – {GridRow} – </code>
    +<p>Row to search on</p></li>
    +<li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>Column with the filters to use</p></li>
    +<li><code ng:non-bindable="">filters – {array} – </code>
    +<p>array of pre-parsed/preprocessed filters to apply</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{boolean}</code>
    +– <p>Whether the column matches or not.</p></div>
    +</div>
    +</li>
    +<li><h3 id="setupFilters">setupFilters(filters)</h3>
    +<div class="setupfilters"><p>For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +do all the parsing and pre-processing and store that data into a new filters object.  The object
    +has the condition, the flags, the stripped term, and a parsed reg exp if there was one.</p>
    +
    +<p>We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +for loops everywhere else in this module...</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">filters – {array} – </code>
    +<p>the filters from the column (col.filters or [col.filter])</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{array}</code>
    +– <p>An array of parsed/preprocessed filters</p></div>
    +</div>
    +</li>
    +<li><h3 id="stripTerm">stripTerm(filter)</h3>
    +<div class="stripterm"><p>Remove leading and trailing asterisk (*) from the filter's term</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">filter – {object} – </code>
    +<p>object to use</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{uiGridConstants.filter&lt;int&gt;}</code>
    +– <p>Value representing the condition constant value</p></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.service.uiGridColumnMenuService.html b/docs/partials/api/ui.grid.service.uiGridColumnMenuService.html
    new file mode 100644
    index 000000000..a700c2c68
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.service.uiGridColumnMenuService.html
    @@ -0,0 +1,104 @@
    +<h1><code ng:non-bindable="">uiGridColumnMenuService</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Services for working with column menus, factored out
    +to make the code easier to understand</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="getColumnElementPosition">getColumnElementPosition($scope, column, $columnElement)</h3>
    +<div class="getcolumnelementposition"><p>gets the position information needed to place the column
    +menu below the column header</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +<li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>the column we want to position below</p></li>
    +<li><code ng:non-bindable="">$columnElement – {element} – </code>
    +<p>the column element we want to position below</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{hash}</code>
    +– <p>containing left, top, offset, height, width</p></div>
    +</div>
    +</li>
    +<li><h3 id="getDefaultMenuItems">getDefaultMenuItems($scope)</h3>
    +<div class="getdefaultmenuitems"><p>returns the default menu items for a column menu</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="hideable">hideable($scope)</h3>
    +<div class="hideable"><p>determines whether a column can be hidden, by checking the enableHiding columnDef option</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="initialize">initialize($scope, uiGridCtrl)</h3>
    +<div class="initialize"><p>Sets defaults, puts a reference to the $scope on 
    +the uiGridController</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +<li><code ng:non-bindable="">uiGridCtrl – {controller} – </code>
    +<p>the uiGridController for the grid
    +we're on</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="isActiveSort">isActiveSort($scope, direction)</h3>
    +<div class="isactivesort"><p>determines whether the requested sort direction is current active, to 
    +allow highlighting in the menu</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +<li><code ng:non-bindable="">direction – {string} – </code>
    +<p>the direction that we'd have selected for us to be active</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="repositionMenu">repositionMenu($scope, column, positionData, $elm, $columnElement)</h3>
    +<div class="repositionmenu"><p>Reposition the menu below the new column.  If the menu has no child nodes 
    +(i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +later to fix it</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +<li><code ng:non-bindable="">column – {GridCol} – </code>
    +<p>the column we want to position below</p></li>
    +<li><code ng:non-bindable="">positionData – {hash} – </code>
    +<p>a hash containing left, top, offset, height, width</p></li>
    +<li><code ng:non-bindable="">$elm – {element} – </code>
    +<p>the column menu element that we want to reposition</p></li>
    +<li><code ng:non-bindable="">$columnElement – {element} – </code>
    +<p>the column element that we want to reposition underneath</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="setColMenuItemWatch">setColMenuItemWatch($scope, uiGridCtrl)</h3>
    +<div class="setcolmenuitemwatch"><p>Setup a watch on $scope.col.menuItems, and update
    +menuItems based on this.  $scope.col needs to be set by the column
    +before calling the menu.</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +<li><code ng:non-bindable="">uiGridCtrl – {controller} – </code>
    +<p>the uiGridController for the grid
    +we're on</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="sortable">sortable($scope)</h3>
    +<div class="sortable"><p>determines whether this column is sortable</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +</ul>
    +</div>
    +</li>
    +<li><h3 id="suppressRemoveSort">suppressRemoveSort($scope)</h3>
    +<div class="suppressremovesort"><p>determines whether we should suppress the removeSort option</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">$scope – {$scope} – </code>
    +<p>the $scope from the uiGridColumnMenu</p></li>
    +</ul>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.style.directive.uiGridStyle.html b/docs/partials/api/ui.grid.style.directive.uiGridStyle.html
    new file mode 100644
    index 000000000..6f36f65a1
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.style.directive.uiGridStyle.html
    @@ -0,0 +1,49 @@
    +<h1><code ng:non-bindable="">uiGridStyle</code>
    +<span class="hint">(directive in module <code ng:non-bindable="">ui.grid.style</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Allows us to interpolate expressions in <code>&lt;style&gt;</code> elements. Angular doesn't do this by default as it can/will/might? break in IE8.</p></div>
    +<h2 id="Usage">Usage</h2>
    +<div class="usage">as attribute<pre class="prettyprint linenums">&lt;style ui-grid-style&gt;
    +   ...
    +&lt;/style&gt;</pre>
    +</div>
    +<h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js script.js" source-edit-html="index.html-0" source-edit-css="" source-edit-js="script.js" source-edit-unit="" source-edit-scenario="scenario.js"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-0" ng-html-wrap-loaded="app angular.js script.js"></pre>
    +<script type="text/ng-template" id="index.html-0">
    +
    +
    +<div ng-controller="MainCtrl">
    +<style ui-grid-style>{{ myStyle }}</style>
    +<span class="blah">I am in a box.</span>
    +</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="script.js">
    +<pre class="prettyprint linenums" ng-set-text="script.js"></pre>
    +<script type="text/ng-template" id="script.js">
    +var app = angular.module('app', ['ui.grid']);
    +
    +app.controller('MainCtrl', ['$scope', function ($scope) {
    +       $scope.myStyle = '.blah { border: 1px solid }';
    +     }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js"></pre>
    +<script type="text/ng-template" id="scenario.js">
    +it('should apply the right class to the element', function () {
    +     element(by.css('.blah')).getCssValue('border')
    +       .then(function(c) {
    +         expect(c).toContain('1px solid');
    +       });
    +   });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-0" ng-eval-javascript="script.js"></div></div>
    +</div>
    diff --git a/docs/partials/api/ui.grid.util.service.GridUtil.html b/docs/partials/api/ui.grid.util.service.GridUtil.html
    new file mode 100644
    index 000000000..760edd892
    --- /dev/null
    +++ b/docs/partials/api/ui.grid.util.service.GridUtil.html
    @@ -0,0 +1,141 @@
    +<h1><code ng:non-bindable="">GridUtil</code>
    +<span class="hint">(service in module <code ng:non-bindable="">ui.grid.util</code>
    +)</span>
    +</h1>
    +<div><h2 id="Description">Description</h2>
    +<div class="description"><p>Grid utility functions</p></div>
    +<div class="member method"><h2 id="Methods">Methods</h2>
    +<ul class="methods"><li><h3 id="elementHeight">elementHeight(element, [extra])</h3>
    +<div class="elementheight"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>DOM element</p></li>
    +<li><code ng:non-bindable="">[extra] – {string} – </code>
    +<p>Optional modifier for calculation. Use 'margin' to account for margins on element</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>Element height in pixels, accounting for any borders, etc.</p></div>
    +</div>
    +</li>
    +<li><h3 id="elementWidth">elementWidth(element, [extra])</h3>
    +<div class="elementwidth"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">element – {element} – </code>
    +<p>DOM element</p></li>
    +<li><code ng:non-bindable="">[extra] – {string} – </code>
    +<p>Optional modifier for calculation. Use 'margin' to account for margins on element</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{number}</code>
    +– <p>Element width in pixels, accounting for any borders, etc.</p></div>
    +</div>
    +</li>
    +<li><h3 id="getColumnsFromData">getColumnsFromData(data)</h3>
    +<div class="getcolumnsfromdata"><p>Return a list of column names, given a data set</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">data – {string} – </code>
    +<p>Data array for grid</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{Object}</code>
    +– <p>Column definitions with field accessor and column name</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var data = [
    +  { firstName: 'Bob', lastName: 'Jones' },
    +  { firstName: 'Frank', lastName: 'Smith' }
    +];
    +
    +var columnDefs = GridUtil.getColumnsFromData(data);
    +
    +columnDefs == [
    + {
    +   field: 'firstName',
    +   name: 'First Name'
    + },
    + {
    +   field: 'lastName',
    +   name: 'Last Name'
    + }
    +];
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="getTemplate">getTemplate()</h3>
    +<div class="gettemplate"><p>Get's template from Url</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{object}</code>
    +– <p>a promise resolving to template contents</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +GridUtil.getTemplate(url).then(function (contents) {
    +     alert(contents);
    +   })
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="newId">newId()</h3>
    +<div class="newid"><p>Return a unique ID string</p><h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>Unique string</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><pre class="prettyprint linenums">
    +var id = GridUtil.newId();
    +
    +# 1387305700482;
    +</pre></div>
    +</div>
    +</li>
    +<li><h3 id="normalizeWheelEvent">normalizeWheelEvent(event)</h3>
    +<div class="normalizewheelevent"><p>Given an event from this list:</p>
    +
    +<p><code>wheel, mousewheel, DomMouseScroll, MozMousePixelScroll</code></p>
    +
    +<p>"normalize" it
    +so that it stays consistent no matter what browser it comes from (i.e. scale it correctl and make sure the direction is right.)</p><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">event – {event} – </code>
    +<p>A mouse wheel event</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{event}</code>
    +– <p>A normalized event</p></div>
    +</div>
    +</li>
    +<li><h3 id="readableColumnName">readableColumnName(columnName)</h3>
    +<div class="readablecolumnname"><h4 id="Parameters">Parameters</h4>
    +<ul class="parameters"><li><code ng:non-bindable="">columnName – {string} – </code>
    +<p>Column name as a string</p></li>
    +</ul>
    +<h4 id="Returns">Returns</h4>
    +<div class="returns"><code ng:non-bindable="">{string}</code>
    +– <p>Column name appropriately capitalized and split apart</p></div>
    +<h4 id="Example">Example</h4>
    +<div class="example"><h6>Source</h6>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-2" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-2" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-2">
    +   <div ng-controller="MainCtrl">
    +     <strong>Column name:</strong> <input ng-model="name" />
    +     <br>
    +     <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +   </div>
    + </script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +   var app = angular.module('app', ['ui.grid.util']);
    +
    +   app.controller('MainCtrl', ['$scope', 'GridUtil', function ($scope, GridUtil) {
    +     $scope.name = 'firstName';
    +     $scope.columnName = function(name) {
    +       return GridUtil.readableColumnName(name);
    +     };
    +   }]);
    + </script>
    +</div>
    +</div><h6>Demo</h6>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-2" ng-eval-javascript="app.js"></div></div>
    +</div>
    +</li>
    +</ul>
    +</div>
    +</div>
    diff --git a/docs/partials/tutorial/001_start.html b/docs/partials/tutorial/001_start.html
    new file mode 100644
    index 000000000..1fe03a499
    --- /dev/null
    +++ b/docs/partials/tutorial/001_start.html
    @@ -0,0 +1,114 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Ui-Grid 3.0 (formerly ng-grid), is a 100% angular grid written with no dependencies other than AngularJS. It is designed around
    +a core grid module and features are layered on as angular modules and directives.  This keeps the core small and focused
    +while executing very complex features only when you need them.</p>
    +
    +<p>In the core module, you get:</p>
    +
    +<ul>
    + <li>Virtualized rows and columns - only the rows and columns visible in the viewport (+ some extra margin) are actually rendered</li>
    + <li>Bind cells to complex properties and functions</li>
    + <li>Column sorting with three states: Asc, Desc, None</li>
    + <li>Column filtering</li>
    + <li>Ability to change header and cell contents with custom templates</li>
    +</ul>
    +
    +<p>In this example we create the most basic grid possible.</p>
    +
    +<p>Steps:</p>
    +
    +<ul>
    + <li>Include uiGrid in your script and css
    +  <pre class="prettyprint linenums">
    +      &lt;link rel="styleSheet" href="release/ui-grid-unstable.css"/&gt;
    +      &lt;script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"&gt;&lt;/script&gt;
    +      &lt;script src="/release/ui-grid-unstable.js"&gt;&lt;/script&gt;
    +  </pre>
    + </li>
    + <li>Include ui.grid module as a dependency in your app
    +   <pre class="prettyprint linenums">
    +       var app = angular.module('app', ['ui.grid']);
    +   </pre>
    + </li>
    + <li>
    +   Add a css style to your app css so the grid knows it's dimensions
    +   <pre class="prettyprint linenums">
    +     .myGrid {
    +         width: 500px;
    +         height: 250px;
    +       }
    +   </pre>
    + </li>
    + <li>
    +  Add an array of data to a property on your $scope
    +     <pre class="prettyprint linenums">
    +     $scope.myData = [
    +             {
    +                 "firstName": "Cox",
    +                 "lastName": "Carney"...
    +     </pre>
    + </li>
    + <li>
    + Use the ui-grid directive and specify a json object with a data property referencing your $scope.myData property.
    + <pre class="prettyprint linenums">
    +     &lt;div ng-controller="MainCtrl"&gt;
    +       &lt;div ui-grid="{ data: myData }" class="myGrid"&gt;&lt;/div&gt;
    +     &lt;/div&gt;
    + </pre>
    +
    + </li>
    +</ul><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-14" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-14" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-14">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="{ data: myData }" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +
    +    $scope.myData = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      }
    +  ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-14" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/098_contributing_to_ui-grid.html b/docs/partials/tutorial/098_contributing_to_ui-grid.html
    new file mode 100644
    index 000000000..c5ee9e42f
    --- /dev/null
    +++ b/docs/partials/tutorial/098_contributing_to_ui-grid.html
    @@ -0,0 +1,79 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="contributing">Contributing</h3>
    +
    +<p>The ui-grid team is reasonably small, and this is a large project.  We are always looking for
    +contributors to assist to make this the default grid for all angularJS projects.</p>
    +
    +<p>There are a number of ways you can contribute, all of which add value to the team:</p>
    +
    +<ol>
    +<li>Raising high quality issues in the issue tracker, and helping to diagnose and resolve them</li>
    +<li>Assisting with documentation updates and helping others who have issues in the issue tracker</li>
    +<li>Providing patches for point issues through submission of pull requests</li>
    +<li>Contributing features or core development to the project</li>
    +</ol>
    +
    +<p>We are a friendly project that welcomes new members, and we have tried to provide guides that 
    +allow both open source pros and first timers to open source to contribute to the project.</p>
    +
    +<h2 id="issuesintheissuetracker">Issues in the issue tracker</h3>
    +
    +<p>Refer to <a href="https://github.com/angular-ui/ng-grid/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a>, 
    +in the issue tracker and bug report sections.</p>
    +
    +<p>In short, the issue tracker should be used for <em>demonstrable problems</em> in the code.  You should
    +tell us what version you're using, what the problem is that you have, what you expected to happen
    +instead, and if possible provide a plunkr that demonstrates the problem.</p>
    +
    +<p>The easiest way to get a plunkr is to start with one of the tutorials, click the "edit" button,
    +and then adjust it in the plunkr to match the configuration in your code.  Then click the save 
    +button, and copy and paste the url into your issue.</p>
    +
    +<p>There is a lot more detail in <a href="https://github.com/angular-ui/ng-grid/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a>,
    +read it and follow it.</p>
    +
    +<h2 id="documentationupdatesandhelpingwithotherpeoplesissues">Documentation updates and helping with other people's issues</h3>
    +
    +<p>As you get more familiar with ui-grid, you'll find that some things in the documentation aren't
    +described as well as you think they could be, or you'll start to build knowledge that is enough
    +to answer questions.</p>
    +
    +<p>Register for gitter, and get a github account.  Answer questions where you have the knowledge to 
    +do so, freeing up the core team to work on the more complex issues.  Remember that you don't have to
    +always be right, this is an open source project run by volunteers.  So long as you have good intentions
    +and your courteous, then your contributions will be valued.  The only way to increase your knowledge is
    +to start, and we all started in the same place.</p>
    +
    +<p>If you want to contribute documentation updates, these are the easiest area of pull requests to submit.
    +Take a look at the <a href="https://github.com/angular-ui/ng-grid/blob/master/FIRST_TIMER.md">first timers guide</a>,
    +and do your first pull request.  It's not as hard as it looks from the outside!!</p>
    +
    +<h2 id="providingpatchescontributingfeaturescoredevelopment">Providing patches, contributing features, core development</h3>
    +
    +<p>If you're already a pro with open source, github and the development tools, dive straight in.  Look
    +at <a href="https://github.com/angular-ui/ng-grid/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a> and 
    +<a href="https://github.com/angular-ui/ng-grid/blob/master/DEVELOPER.md">DEVELOPER.md</a>, and get working!!</p>
    +
    +<p>Key things to watch out for are:</p>
    +
    +<ol>
    +<li>We don't have unit tests everywhere as yet, but we want to.  Pull requests should have run the
    +unit tests before submission, and all unit tests should be working.  Ask for help if you can't fix 
    +them.  </li>
    +<li>All new PRs should come with unit tests</li>
    +<li>Similarly, we don't yet have ngdoc everywhere, but we have it in most places.  All new pull requests
    +should come with ngdocs, and where appropriate, a new or extended tutorial</li>
    +<li>End-to-end tests are least complete, but at a minimum the existing end-to-end tests must continue to
    +run, so run them before submitting</li>
    +<li>Squash all your commits - each pull request should have only a single commit.  It's much easier to 
    +do this before you push to github - once you've pushed to github then squashing your commits generally
    +requires you to create a new branch.</li>
    +<li>Follow the coding style, including 2 spaces for indent</li>
    +</ol>
    +
    +<p>If you're more of a first timer with open source, then look at <a href="https://github.com/angular-ui/ng-grid/blob/master/FIRST_TIMER.md">First time guide</a>.
    +Some of it you'll already know, other bits may be new.  Our aim with this guide is to collate as much as possible of the
    +questions and answers that we've covered through gitter and other channels, and make that information
    +accessible to new contributors.</p></div>
    diff --git a/docs/partials/tutorial/099_upgrading_from_2.html b/docs/partials/tutorial/099_upgrading_from_2.html
    new file mode 100644
    index 000000000..953153bd8
    --- /dev/null
    +++ b/docs/partials/tutorial/099_upgrading_from_2.html
    @@ -0,0 +1,151 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="upgradingfrom2xto30">Upgrading from 2.x to 3.0</h3>
    +
    +<p>ui-grid 3.0 is a substantial upgrade from ng-grid 2.x, with the majority of the code base having 
    +been rewritten.  Where possible the configuration is backward compatible, but some concepts have
    +changed in ways that require code change to integrate.</p>
    +
    +<p>This tutorial covers the key elements that may require adjusting in your application.</p>
    +
    +<h3 id="modulename">Module Name</h4>
    +
    +<p>Previously you included the grid within your application using:
    +<pre class="prettyprint linenums">
    +  angular.module( 'yourApplication', [
    +    'ngGrid'
    +  ]);
    +</pre>
    +
    +<p>You now include ui.grid instead, and may optionally also include the modules for features
    +that you choose to enable:
    +<pre class="prettyprint linenums">
    +  angular.module( 'yourApplication', [
    +    'ui.grid',
    +    'ui.grid.edit'
    +  ]);
    +</pre>
    +
    +<h3 id="griddirective">Grid Directive</h4>
    +
    +<p>Similarly, the directive name has changed, and you may choose to include additional features
    +within your grid.</p>
    +
    +<p>Previously you had:
    +<pre class="prettyprint linenums">
    +  &lt;div class="gridStyle" ng-grid="gridOptions"&gt;&lt;/div&gt;
    +</pre>
    +
    +<p>You now include multiple directives for each of the features you wish to use:
    +<pre class="prettyprint linenums">
    +  &lt;div class="gridStyle" ui-grid="gridOptions" ui-grid-edit&gt;&lt;/div&gt;
    +</pre>
    +
    +<h3 id="updatecolumndefs">Update columnDefs</h4>
    +
    +<p>All columns must have a name or a field.  If you have columns that have neither
    +you need to define one.  Name will be derived from field if not present.
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +    columnDefs: [
    +      {field: 'id', displayName: 'Id'},
    +      {field: 'name', displayName: 'Name'},
    +      {displayName: 'Edit', cellTemplate: '&lt;button id="editBtn" type="button" class="btn-small" &gt;Edit&lt;/button&gt; '}
    +    ]    
    +  };
    +</pre>
    +
    +<p>Becomes:
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +    columnDefs: [
    +      {field: 'id', displayName: 'Id'},
    +      {field: 'name', displayName: 'Name'},
    +      {name: 'edit', displayName: 'Edit', cellTemplate: '&lt;button id="editBtn" type="button" class="btn-small" ng-click="edit(row.entity)" &gt;Edit&lt;/button&gt; '}
    +    ]    
    +  };
    +</pre>
    +
    +<p>String values are no longer supported for columns defs:
    +<pre class="prettyprint linenums">
    +  $scope.myColDefs = {[...]};
    +  $scope.gridOptions.columnDefs = 'myColDefs'
    +</pre>
    +
    +<pre class="prettyprint linenums">
    +$scope.gridOptions.columnDefs = $scope.myColDefs = [...];
    +</pre>
    +or
    +<pre class="prettyprint linenums">
    +$scope.gridOptions.columnDefs = [...];
    +</pre>
    +
    +<h3 id="accessingcellvalues">Accessing cell values</h4>
    +
    +<p>In 2.x you would use <code>row.getProperty(col.field)</code> within a cellTemplate to get the value of a cell. In 3.0 this has changed to <code>grid.getCellValue(row, col)</code>.</p>
    +
    +<h3 id="gridnowusesisolatescope">Grid now uses isolate scope</h4>
    +
    +<p>The grid now uses an isolate scope, meaning that the scope on your controller is not directly accessible
    +to widgets that you include in the grid.  You can get the parent scope used by the ui-grid element in any template
    +with the grid.appScope property.  {{grid.appScope}}</p>
    +
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +    columnDefs: [
    +      {field: 'id', displayName: 'Id'},
    +      {field: 'name', displayName: 'Name'},
    +      {name: 'edit', displayName: 'Edit', cellTemplate: '&lt;button id="editBtn" type="button" class="btn-small" ng-click="edit(row.entity)" &gt;Edit&lt;/button&gt; '}
    +    ]    
    +  };
    +</pre>
    +
    +<p>becomes:
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +    columnDefs: [
    +      {field: 'id', displayName: 'Id'},
    +      {field: 'name', displayName: 'Name'},
    +      {name: 'edit', displayName: 'Edit', cellTemplate: '&lt;button id="editBtn" type="button" class="btn-small" ng-click="grid.appScope.edit(row.entity)" &gt;Edit&lt;/button&gt; '}
    +    ]    
    +  };
    +</pre>
    +
    +<h3 id="separatefeatures">Separate features</h4>
    +
    +<p>Many elements included by default in ng-grid have now been shifted into separate features, allowing the
    +core ng-grid to be kept smaller and faster.  Features are enabled only when included, inclusion of a feature
    +requires both including the module in your application and adding the feature directive onto the grid
    +definition.</p>
    +
    +<p>Features include:</p>
    +
    +<ul>
    +<li>column resizing</li>
    +<li>selection</li>
    +<li>cell navigation and selection of individual cells</li>
    +<li>editing in place</li>
    +</ul>
    +
    +<p>For example, to include the selection feature, you would include the module:
    +<pre class="prettyprint linenums">
    +  angular.module( 'yourApplication', [
    +    'ui.grid',
    +    'ui.grid.selection'
    +  ]);
    +</pre>
    +
    +<p>and include the relevant directive on the grid that you wish to have access to the feature:
    +<pre class="prettyprint linenums">
    +  &lt;div class="gridStyle" ui-grid="gridOptions" ui-grid-edit ui-grid-selection&gt;&lt;/div&gt;
    +</pre>
    +
    +<h3 id="filteringandsorting">Filtering and Sorting</h4>
    +
    +<p>The filtering api changes substantially, as filters are now per-column rather than for the grid as
    +a whole.  Refer the filtering documentation, the key change is that filters are now stored on the
    +individual columns rather than as a single filterOptions element.</p>
    +
    +<p>Sorting behaviour changes somewhat, and again sort options are moved onto the individual columns,
    +along with provision of a "priority" element within the sortOptions.</p></div>
    diff --git a/docs/partials/tutorial/100_preReqs.html b/docs/partials/tutorial/100_preReqs.html
    new file mode 100644
    index 000000000..27405fe1d
    --- /dev/null
    +++ b/docs/partials/tutorial/100_preReqs.html
    @@ -0,0 +1,21 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2>Browsers</h2>
    +
    +<p>Current list of tested browsers: <a href='https://saucelabs.com/u/nggrid' target="_blank">Sauce Labs</a></p>
    +
    +<ul>
    + <li>IE9+</li>
    + <li>Chrome</li>
    + <li>Firefox</li>
    + <li>Safari 5+</li>
    + <li>Opera</li>
    + <li>Android 4+</li>
    +</ul>
    +
    +<h2>AngularJS</h2>
    +
    +<ul>
    + <li>1.2.10+</li>
    +</ul></div>
    diff --git a/docs/partials/tutorial/101_intro.html b/docs/partials/tutorial/101_intro.html
    new file mode 100644
    index 000000000..60d3c738a
    --- /dev/null
    +++ b/docs/partials/tutorial/101_intro.html
    @@ -0,0 +1,149 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid 3.0 (formerly ng-grid), is a 100% angular grid written with no dependencies other than AngularJS. It is designed around
    +a core grid module and features are layered on as angular modules and directives.  This keeps the core small and focused
    +while executing very complex features only when you need them.</p>
    +
    +<p>In the core module, you get:</p>
    +
    +<ul>
    + <li>Virtualized rows and columns - only the rows and columns visible in the viewport (+ some extra margin) are actually rendered</li>
    + <li>Bind cells to complex properties and functions</li>
    + <li>Column sorting with three states: Asc, Desc, None</li>
    + <li>Column filtering</li>
    + <li>Ability to change header and cell contents with custom templates</li>
    + <li>i18nService allows label translations</li>
    +</ul>
    +
    +<p>In this example we create the most basic grid possible.</p>
    +
    +<p>Steps:</p>
    +
    +<ul>
    + <li>Include uiGrid in your script and css
    +  <pre class="prettyprint linenums">
    +      &lt;link rel="styleSheet" href="release/ui-grid-unstable.css"/&gt;
    +      &lt;script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"&gt;&lt;/script&gt;
    +      &lt;script src="/release/ui-grid-unstable.js"&gt;&lt;/script&gt;
    +  </pre>
    + </li>
    + <li>Include ui.grid module as a dependency in your app
    +   <pre class="prettyprint linenums">
    +       var app = angular.module('app', ['ui.grid']);
    +   </pre>
    + </li>
    + <li>
    +   Add a css style to your app css so the grid knows it's dimensions
    +   <pre class="prettyprint linenums">
    +     .myGrid {
    +         width: 500px;
    +         height: 250px;
    +       }
    +   </pre>
    + </li>
    + <li>
    +  Add an array of data to a property on your $scope
    +     <pre class="prettyprint linenums">
    +     $scope.myData = [
    +             {
    +                 "firstName": "Cox",
    +                 "lastName": "Carney"...
    +     </pre>
    + </li>
    + <li>
    + Use the ui-grid directive and specify a json object with a data property referencing your $scope.myData property.
    + <pre class="prettyprint linenums">
    +     &lt;div ng-controller="MainCtrl"&gt;
    +       &lt;div ui-grid="{ data: myData }" class="myGrid"&gt;&lt;/div&gt;
    +     &lt;/div&gt;
    + </pre>
    +
    + </li>
    +</ul><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-19" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-20"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-19" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-19">
    +  <div ng-controller="MainCtrl">
    +    <div id="grid1" ui-grid="{ data: myData }" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +
    +    $scope.myData = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      }
    +  ];
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-20"></pre>
    +<script type="text/ng-template" id="scenario.js-20">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  it('grid should have three visible rows', function () {
    +    gridTestUtils.expectRowCount( 'grid1', 3 );
    +  });
    +
    +  it('grid should have four visible columns', function () {
    +    gridTestUtils.expectHeaderColumnCount( 'grid1', 4 );
    +  });
    +
    +  it('header values should be as expected', function () {
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'First Name' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Last Name' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 3, 'Employed' );
    +  });
    +
    +  it('first row cell values should be as expected', function () {
    +    // checking individual cells usually gives a better stack trace when there are errors
    +    gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Cox' );
    +    gridTestUtils.expectCellValueMatch( 'grid1', 0, 1, 'Carney' );
    +    gridTestUtils.expectCellValueMatch( 'grid1', 0, 2, 'Enormo' );
    +    gridTestUtils.expectCellValueMatch( 'grid1', 0, 3, 'true' );
    +  });
    +
    +  it('next two row cell values should be as expected', function () {
    +    // checking in bulk is convenient to write, but can be less informative with errors
    +    gridTestUtils.expectRowValuesMatch( 'grid1', 1, [ 'Lorraine', 'Wise', 'Comveyer', 'false' ] );
    +    gridTestUtils.expectRowValuesMatch( 'grid1', 2, [ 'Nancy', 'Waters', 'Fuelton', 'false' ] );
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-19" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/102_sorting.html b/docs/partials/tutorial/102_sorting.html
    new file mode 100644
    index 000000000..51c2db4dc
    --- /dev/null
    +++ b/docs/partials/tutorial/102_sorting.html
    @@ -0,0 +1,268 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid allows you to sort rows. The feature is on by default. You can set the <code>enableSorting</code> flag in your grid options to enable/disable it.</p>
    +
    +<p><span class="col-xs-12 alert alert-warning">
    +  <strong>Note:</strong> You can sort columns by accessing the column menu. You must include ngAnimate in your application if you want the menu to slide up/down, but it's not required.
    +</span></p>
    +
    +<p>Sorting can be disabled at the column level by setting <code>enableSorting: false</code> in the column def. See the last column below for an example.</p>
    +
    +<p>Multiple columns can be sorted by shift-clicking on the 2-n columns.  To see it in action, sort Gender then shift-click Name.</p>
    +
    +<p>When sorting using the menus, the sorts are additive.  So if you have one column sorted and you pick another sort
    +from a column menu, it will add on to the existing sort rather than replacing it.  You need to use the 'remove sort' option
    +on the existing column if you don't want to sort by it any more.  </p>
    +
    +<p>When sorting using the headers, clicking on a header removes all other sorts unless you shift-click.</p>
    +
    +<p>The sort is automatically recalculated when you edit a field (the edit feature calls the dataChange api to notify of a data change).  If
    +you change the data "behind the scenes" and want the sort to be recalculated, you can notify the grid that your
    +data has changed by calling <code>gridApi.core.notifyDataChange( uiGridConstants.dataChange.EDIT )</code></p>
    +
    +<p>If you set a default sort, you can prevent the user from removing that sort by setting <code>suppressRemoveSort: true</code>
    +for that column.  This will let the user change the direction of the sort, but take away the option to remove the sort.</p>
    +
    +<h3>Source</h3>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-21" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-22"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-21" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-21">
    +    <div ng-controller="MainCtrl">
    +      Click on a column header to sort by that column. (The third column has sorting disabled.)
    +      To demonstrate the live sorting we provide a button that toggles the gender of Alexander Foley.
    +      Sort by gender (ASC - so click twice) then name (using shift click), so that Alexander is at the top of the grid,
    +      then click the toggleGender button.
    +
    +      <br>
    +      <br>
    +      <button id='toggleGender' ng-click='toggleGender()'>Toggle Gender</button>
    +      <div id="grid1" ui-grid="gridOptions1" class="grid"></div>
    +
    +      <br>
    +      You can set an initial sort state for the grid by defining the `sort` property on your column definitions. 
    +      The `direction` sub-property says which way to sort, and the `priority` says what order to sort the columns 
    +      in (lower priority gets sorted first).
    +      <br>
    +      <br>
    +
    +      <div id="grid2" ui-grid="gridOptions2" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 200px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
    +      $scope.gridOptions1 = {
    +        enableSorting: true,
    +        columnDefs: [
    +          { field: 'name' },
    +          { field: 'gender' },
    +          { field: 'company', enableSorting: false }
    +        ],
    +        onRegisterApi: function( gridApi ) {
    +          $scope.grid1Api = gridApi;
    +        }
    +      };
    +      
    +      $scope.toggleGender = function() {
    +        if( $scope.gridOptions1.data[64].gender === 'male' ) {
    +          $scope.gridOptions1.data[64].gender = 'female';
    +        } else {
    +          $scope.gridOptions1.data[64].gender = 'male';
    +        };
    +        $scope.grid1Api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +      };
    +
    +       $scope.gridOptions2 = {
    +        enableSorting: true,
    +        onRegisterApi: function( gridApi ) {
    +          $scope.grid2Api = gridApi;
    +        },
    +        columnDefs: [
    +          {
    +            field: 'name',
    +            sort: {
    +              direction: uiGridConstants.DESC,
    +              priority: 1
    +            }
    +          },
    +          {
    +            field: 'gender',
    +            sort: {
    +              direction: uiGridConstants.ASC,
    +              priority: 0,
    +            },
    +            suppressRemoveSort: true,
    +            sortingAlgorithm: function(a, b) {
    +              var nulls = $scope.grid2Api.core.sortHandleNulls(a, b);
    +              if( nulls !== null ) {
    +                return nulls;
    +              } else {
    +                if( a === b ) {
    +                  return 0;
    +                }
    +                if( a === 'male' ) {
    +                  return 1;
    +                }
    +                if( b === 'male' ) {
    +                  return -1;
    +                }
    +                if( a == 'female' ) {
    +                  return 1;
    +                }
    +                if( b === 'female' ) {
    +                  return -1;
    +                }
    +                return 0;
    +              }
    +            }
    +          },
    +          { field: 'company', enableSorting: false  }
    +        ]
    +      };
    +
    +     $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions1.data = data;
    +          $scope.gridOptions2.data = data;
    +        });
    +    }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-22"></pre>
    +<script type="text/ng-template" id="scenario.js-22">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +    
    +    describe('first grid on the page, no default sort', function() {
    +      it('grid should have three visible columns', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      });
    +  
    +      it('header values should be as expected', function () {
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +      });
    +  
    +      it('grid should be unsorted by default', function () {
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +
    +      it('sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alexander Foley' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Alisha Myers' );
    +      });
    +
    +      it('reverse sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Yvonne Parsons' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Woods Key' );
    +      });
    +      
    +      it('return to original sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +      
    +      it('sort asc by clicking menu', function() {
    +        gridTestUtils.clickColumnMenuSortAsc( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alexander Foley' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Alisha Myers' );        
    +      });
    +
    +      it('sort desc by clicking menu, then remove sort', function() {
    +        gridTestUtils.clickColumnMenuSortDesc( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Yvonne Parsons' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Woods Key' );
    +
    +        gridTestUtils.clickColumnMenuRemoveSort( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +      
    +      it('sort two columns, gender then name, by shift clicking', function() {
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        gridTestUtils.shiftClickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alisha Myers' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Beryl Rice' );
    +      });
    +
    +      it('sort disabled on last column', function() {
    +        gridTestUtils.clickHeaderCell( 'grid1', 2 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +
    +      it('click one menu, then click another menu, expect undisplay and redisplay on second click', function() {
    +        gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 0, 3 );
    +        gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 1, 3 );
    +      });
    +
    +      it('toggle gender, expect Alexander Foley to move around', function() {
    +        // sort gender asc, then name
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        gridTestUtils.shiftClickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alexander Foley' );
    +        element(by.id('toggleGender')).click();
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Anthony Joyner' );
    +        element(by.id('toggleGender')).click();
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alexander Foley' );
    +      });
    +
    +    });
    +
    +
    +    describe('second grid on the page, has default sort', function() {
    +      it('grid should have three visible columns', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid2', 3 );
    +      });
    +  
    +      it('header values should be as expected', function () {
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid2', 0, 'Name' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid2', 1, 'Gender' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid2', 2, 'Company' );
    +      });
    +  
    +      it('grid should be sorted by default', function () {
    +        gridTestUtils.expectCellValueMatch( 'grid2', 0, 0, 'Yvonne Parsons' );
    +        gridTestUtils.expectCellValueMatch( 'grid2', 1, 0, 'Velma Fry' );
    +      });
    +      
    +      it('sort on second column can\'t be removed when cycle through header clicks', function () {
    +        gridTestUtils.clickHeaderCell( 'grid2', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid2', 0, 0, 'Ethel Price' );
    +
    +        gridTestUtils.clickHeaderCell( 'grid2', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid2', 0, 0, 'Wilder Gonzales' );
    +        
    +        gridTestUtils.clickHeaderCell( 'grid2', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid2', 0, 0, 'Ethel Price' );
    +      });
    +    });
    +
    +  </script>
    +</div>
    +</div><h3>Demo</h3>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-21" ng-eval-javascript="app.js"></div></div>
    diff --git a/docs/partials/tutorial/103_filtering.html b/docs/partials/tutorial/103_filtering.html
    new file mode 100644
    index 000000000..264899c8d
    --- /dev/null
    +++ b/docs/partials/tutorial/103_filtering.html
    @@ -0,0 +1,169 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h3 id="simplesetup">Simple setup</h4>
    +
    +<p>UI-Grid allows you to filter rows. Just set the <code>enableFiltering</code> flag in your grid options (it is off by default).</p>
    +
    +<p>Filtering can be disabled at the column level by setting <code>enableFiltering: false</code> in the column def. See the "company" column below for an example.</p>
    +
    +<p>The filter field can be pre-populated by setting <code>filter: { term: 'xxx' }</code> in the column def.  See the "gender" column below.</p>
    +
    +<h3 id="conditon">Conditon</h4>
    +
    +<p>The <code>filter</code> object introduced above may also specify a <code>condition</code>, which defines how rows are chosen as matching the filter term. UI-Grid comes with several conditions
    +out-of-the-box, which are defined by <code>uiGridConstants.filter.*</code>. See the "email" column below. </p>
    +
    +<p>If no condition is set, UI-Grid will take a best guess based on the contents of the filter field. Even basic wildcard (*) use is supported!</p>
    +
    +<p>If you want to create your own filtering logic, the <code>condition</code> field of the <code>filter</code> object can also be a function that gets run for each 
    +row. Such a function has the following signature:</p>
    +
    +<pre><code class="Javascript">function myCustomSorter(searchTerm, cellValue, row, column) {
    +  // Custom logic that returns true if `row`
    +  // passes the filter and false if it should
    +  // be filtered out
    +  return booleanResult;
    +}
    +</code></pre>
    +
    +<p>For an example of this, see the "phone" column below for an example of this; the custom filter condition makes sure to strip the phone number of everything
    +except digits to compare to the search term.</p>
    +
    +<p>You can also optionally create a custom filter condition that doesn't require a term to be provided by the user - for example if you're matching 
    +to a variable that you're setting within your code.  If you want to do this, you can set <code>noTerm: true</code> inside the filter, and the filter will
    +run even when no term is provided.  The filter box will, however, still be shown.   </p>
    +
    +<h3 id="placeholder">Placeholder</h4>
    +
    +<p>Set the <code>placeholder</code> property on the <code>filter</code> object to add a <code>placeholder=""</code> attribute to the input element. This is set for the "email" and "age" columns below.</p>
    +
    +<h3 id="multiplefilterfields">Multiple filter fields</h4>
    +
    +<p>Occasionally, you may want to provide two or more filters for a single column. This can be accomplished by setting a <code>filters</code> array instead of a <code>filter</code> object.
    +The elements of this array are the same as the contents of the <code>filter</code> object in all the previous examples. In fact, <code>filter: { term: 'xxx' }</code> is just an alias 
    +for <code>filters: [{ term: 'xxx' }]</code>. See the "age" column below for an example.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-23" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-24"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-23" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-23">
    +  <div ng-controller="MainCtrl">
    +    You can use asterisks to fuzz-match, i.e. use "*z*" as your filter to show any row where that column contains a "z".
    +    <br>
    +    <br>
    +    <strong>Note:</strong> The third column has the filter input disabled, but actually has a filter set in code that requires every company to have an 'a' in their name.
    +    <br>
    +    <br>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 650px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
    +    $scope.gridOptions = {
    +      enableFiltering: true,
    +      columnDefs: [
    +        // default
    +        { field: 'name' },
    +        // pre-populated search field
    +        { field: 'gender', filter: { term: 'male' } },
    +        // no filter input
    +        { field: 'company', enableFiltering: false, filter: {
    +          noTerm: true,
    +          condition: function(searchTerm, cellValue) {
    +            return cellValue.match(/a/);
    +          }
    +        }},
    +        // specifies one of the built-in conditions
    +        // and a placeholder for the input
    +        {
    +          field: 'email',
    +          filter: {
    +            condition: uiGridConstants.filter.ENDS_WITH,
    +            placeholder: 'ends with'
    +          }
    +        },
    +        // custom condition function
    +        {
    +          field: 'phone',
    +          filter: {
    +            condition: function(searchTerm, cellValue) {
    +              var strippedValue = (cellValue + '').replace(/[^\d]/g, '');
    +              return strippedValue.indexOf(searchTerm) >= 0;
    +            }
    +          }
    +        },
    +        // multiple filters
    +        { field: 'age', filters: [
    +          {
    +            condition: uiGridConstants.filter.GREATER_THAN,
    +            placeholder: 'greater than'
    +          },
    +          {
    +            condition: uiGridConstants.filter.LESS_THAN,
    +            placeholder: 'less than'
    +          }
    +        ]}
    +      ]
    +    };
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-24"></pre>
    +<script type="text/ng-template" id="scenario.js-24">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  
    +  describe('first grid on the page, filtered by male by default', function() {
    +    it('grid should have six visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 6 );
    +    });
    +
    +    it('filter on 4 columns, filter with greater than/less than on one, one with no filter', function () {
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 0, 1 );
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 1, 1 );
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 2, 0 );
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 3, 1 );
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 4, 1 );
    +      gridTestUtils.expectFilterBoxInColumn( 'grid1', 5, 2 );
    +    });
    +
    +    it('third row should be Hatfield Hudson - will be Terry Clay if filtering broken', function () {
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 0, 'Hatfield Hudson' );
    +    });
    +    
    +    it('cancel filter on gender column, should now see Bishop Carr in third row', function() {
    +      gridTestUtils.cancelFilterInColumn( 'grid1', 1 );        
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 0, 'Bishop Carr' );
    +    });
    +
    +    it('filter on email column, should automatically do "ends with"', function() {
    +      gridTestUtils.cancelFilterInColumn( 'grid1', 1 );        
    +      gridTestUtils.enterFilterInColumn( 'grid1', 3, 'digirang.com' );        
    +      gridTestUtils.expectRowCount( 'grid1', 2 );
    +    });
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-23" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/104_i18n.html b/docs/partials/tutorial/104_i18n.html
    new file mode 100644
    index 000000000..f9b156ba7
    --- /dev/null
    +++ b/docs/partials/tutorial/104_i18n.html
    @@ -0,0 +1,78 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid provides an i18nService that you can use to change the default language, add translations, 
    +or change existing translations.</p>
    +
    +<p>The easiest way to set language is to use the ui-i18n directive in a div that contains the grid.
    +<pre class="prettyprint linenums">
    +&lt;div ui-i18n="{{lang}}"&gt;
    +</pre>
    +Only one ui-i18n directive is allowed.  The current language setting is stored in the i18n service (singleton) 
    +so there is currently no way to have more than one language per app.</p>
    +
    +<p>Another option is to use the i18nService and use the setCurrentLang method
    +<pre class="prettyprint linenums">
    +   i18nService.setCurrentLang('fr');
    +</pre>
    +
    +<p>For an example using angular-translate to translate your headers, refer to http://plnkr.co/edit/KnrKTst5dWXvlZNeIy9c?p=preview</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-25" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-25" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-25">
    +  <div ng-controller="MainCtrl">
    +    <select ng-model="lang" ng-options="l for l in langs"></select><br>
    +
    +    <div ui-i18n="{{lang}}">
    +       <p>Using attribute:</p>
    +       <p ui-t="groupPanel.description"></p>
    +       <br/>
    +       <p>Using Filter:</p>
    +       <p>{{"groupPanel.description" | t}}</p>
    +
    +       <p>Click the header menu to see language. NOTE: TODO: header text does not change after grid is rendered. </p>
    +
    +       <div ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', 'i18nService', '$http', function ($scope, i18nService, $http) {
    +    $scope.langs = i18nService.getAllLangs();
    +    $scope.lang = 'nl';
    +
    +    $scope.gridOptions = {
    +      columnDefs: [
    +        { field: 'name' },
    +        { field: 'gender' },
    +        { field: 'company', enableFiltering: false  }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-25" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/105_footer.html b/docs/partials/tutorial/105_footer.html
    new file mode 100644
    index 000000000..5e1778627
    --- /dev/null
    +++ b/docs/partials/tutorial/105_footer.html
    @@ -0,0 +1,134 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h3 id="gridfooter">Grid Footer</h4>
    +
    +<p>The grid supports a grid footer row, which can be displayed if showGridFooter option is set to true (default=false). This footer displays
    +Total rows in the grid and the number of filtered rows.  Selected rows will be shown if using ui-grid-selection feature.
    +<br/></p>
    +
    +<h3 id="columnfooter">Column Footer</h4>
    +
    +<p>The grid also has column footer, which can be displayed if showColumnFooter option is set to true (default=false).
    +You can set an aggregation function for each column or use a custom footer template to display 
    +what ever aggregation you wish.
    +Aggregation functions supported are: sum, avg, row count, min, max.
    +You need to inject the uiGridConstants in order to use aggregationTypes enum.
    +You can also pass in a function in order to create your own aggregation logic.
    +If you set the <code>aggregationHideLabel</code> option on the columnDef to true, then the column will
    +show the aggregation but without a label.  Refer the third column in the example below.</p>
    +
    +<p><br/>
    +You can override the default grid footer template with gridOptions.footerTemplate.  Copy the default ui-grid-footer.html from the source as your starting point.  <i>This is not demonstrated in this tutorial.</i></p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-26" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-27"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-26" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-26">
    +  <div ng-controller="MainCtrl">
    +    <button id="footerButton" class="btn btn-success" ng-click="gridOptions.showGridFooter = !gridOptions.showGridFooter; $scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.OPTIONS);">Toggle Grid Footer</button>
    +    <button class="btn btn-success" ng-click="gridOptions.showColumnFooter = !gridOptions.showColumnFooter; $scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.OPTIONS);">Toggle Column Footer</button>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 100%;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope','uiGridConstants', '$http', function ($scope, uiGridConstants, $http) {
    +  var data = [];
    +
    +  $scope.gridOptions = {
    +      showGridFooter: true,
    +      showColumnFooter: true,
    +      enableFiltering: true,
    +      columnDefs: [
    +          { field: 'name', width: '13%' },
    +          { field: 'address.street',aggregationType: uiGridConstants.aggregationTypes.sum, width: '13%' },
    +          { field: 'age', aggregationType: uiGridConstants.aggregationTypes.avg, aggregationHideLabel: true, width: '13%' },
    +          { name: 'ageMin', field: 'age', aggregationType: uiGridConstants.aggregationTypes.min, width: '13%', displayName: 'Age for min' },
    +          { name: 'ageMax', field: 'age', aggregationType: uiGridConstants.aggregationTypes.max, width: '13%', displayName: 'Age for max' },
    +          { name: 'customCellTemplate', field: 'age', width: '14%', footerCellTemplate: '<div class="ui-grid-cell-contents" style="background-color: Red;color: White">custom template</div>' },
    +          { name: 'registered', field: 'registered', width: '20%', cellFilter: 'date', footerCellFilter: 'date', aggregationType: uiGridConstants.aggregationTypes.max }
    +      ],
    +      data: data,
    +      onRegisterApi: function(gridApi) {
    +              $scope.gridApi = gridApi;
    +      }
    +  }
    +
    +  $http.get('/data/500_complex.json')
    +    .success(function(data) {
    +      angular.forEach(data, function(row) {
    +        row.registered = Date.parse(row.registered);
    +      });
    +      $scope.gridOptions.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-27"></pre>
    +<script type="text/ng-template" id="scenario.js-27">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '105 footer', function() {
    +    /*
    +    var $filter = angular.module('[app]').injector().get('$filter');
    +
    +    function getMaxDateString() {
    +      // Get the bound value for the max date
    +      var maxFooterCell = gridTestUtils.footerCell( 'grid1', 6 );
    +      var maxDate =  maxFooterCell.evaluate('col.getAggregationValue()');
    +      var maxDateFormattedString = $filter('date')(maxDate, 'MMM d, yyyy');
    +
    +      return maxDateFormattedString;
    +    }
    +    */
    +
    +    it('grid should have six visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 7 );
    +    });
    +
    +    it('grid should have six visible columns in footer', function () {
    +      gridTestUtils.expectFooterColumnCount( 'grid1', 7 );
    +    });
    +
    +    it('grid should have footers with specific values', function () {
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 0, '' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 1, 'total: 281568' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 2, '30.196' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 3, 'min: 20' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 4, 'max: 40' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 5, 'custom template' );
    +      // gridTestUtils.expectFooterCellValueMatch( 'grid1', 6, 'max: ' + getMaxDateString() );
    +      // TODO: need to check item count, not done
    +    });
    +
    +    it('filter and expect recalculate', function () {
    +      gridTestUtils.enterFilterInColumn( 'grid1', 1, '3' );        
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 0, '' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 1, 'total: 19805' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 2, '29.375' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 3, 'min: 20' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 4, 'max: 39' );
    +      gridTestUtils.expectFooterCellValueMatch( 'grid1', 5, 'custom template' );
    +      // gridTestUtils.expectFooterCellValueMatch( 'grid1', 6, 'max: ' + getMaxDateString() );
    +      // TODO: need to check item count, not done
    +    });
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-26" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/106_binding.html b/docs/partials/tutorial/106_binding.html
    new file mode 100644
    index 000000000..d0bd13aff
    --- /dev/null
    +++ b/docs/partials/tutorial/106_binding.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid supports complex object binding in the colDef.field.</p>
    +
    +<p>This tutorial shows two-way binding to properties with special characters, array element, nested property, and function.</p>
    +
    +<p>Note that a function can not be edited.</p>
    +
    +<p>In your custom cellTemplates, you can use:
    +<br/>
    +COL_FIELD which will be replaced with grid.getCellValue(row). This should be used for any cellTemplates that need readonly access to the field value
    +<br/>
    +MODEL_COL_FIELD which will be replaced with row.entity.field.  Use MODEL_COL_FIELD anytime you need ng-model='field'</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-28" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-29"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-28" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-28">
    +  <div ng-controller="MainCtrl">
    +    <div id="grid1" ui-grid="gridOptions" ui-grid-edit class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +
    +  $scope.gridOptions = {
    +          enableSorting: true,
    +          columnDefs: [
    +            { name:'firstName', field: 'first-name' },
    +            { name:'1stFriend', field: 'friends[0]' },
    +            { name:'city', field: 'address.city'},
    +            { name:'getZip', field: 'getZip()', enableCellEdit:false}
    +          ],
    +          data : [      {
    +                             "first-name": "Cox",
    +                             "friends": ["friend0"],
    +                             "address": {street:"301 Dove Ave", city:"Laurel", zip:"39565"},
    +                             "getZip" : function() {return this.address.zip;}
    +                         }
    +                     ]
    +        };
    +
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-29"></pre>
    +<script type="text/ng-template" id="scenario.js-29">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  it('grid should have one visible row and four columns', function () {
    +    gridTestUtils.expectRowCount( 'grid1', 1 );
    +    gridTestUtils.expectHeaderColumnCount( 'grid1', 4 );
    +  });
    +
    +  it('headers as specified', function () {
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'First Name' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, '1st Friend' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'City' );
    +    gridTestUtils.expectHeaderCellValueMatch( 'grid1', 3, 'Get Zip' );
    +  });
    +
    +  it('row values should be as expected', function () {
    +    gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Cox', 'friend0', 'Laurel', '39565' ]);
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-28" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/108_hidden_grids.html b/docs/partials/tutorial/108_hidden_grids.html
    new file mode 100644
    index 000000000..2fc5d6dcf
    --- /dev/null
    +++ b/docs/partials/tutorial/108_hidden_grids.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h3>A Hidden Grid Manifesto</h3>
    +
    +<p>A common problem when using UI Grid is the need to put the grid in a place that is <strong>not visible on initial page load</strong>, such as in a tab in a tabset, or inside an accordion.
    +The end result is often a grid that appears to be rendered "incorrectly" with squished columns or unexpected widths or heights. Let's start with this scenario:</p>
    +
    +<p>Imagine you have a container <code>&lt;div&gt;</code> that you're going to put your grid in. This container has no width or height, it's simply going to hold your grid. You supply the grid
    +no CSS class so its <code>height</code> and <code>width</code> CSS values  are set to <code>auto</code>, which means the browser will calculate them automatically.</p>
    +
    +<p>UI Grid is built from the ground-up to
    +make displaying and traversing large amounts of data easier. It does this through a process called "virtualization". This means that if you have 10,000 rows and 50 columns,
    +instead of rendering 500,000 DOM elements and crippling the browser, UI Grid will do its best to only display the minimum amount it needs to, and "fake" the representation to
    +the user. To them it looks like all the data is right there on the screen when in fact a tiny fraction is being rendered.</p>
    +
    +<p>This becomes a problem in the scenario we created above, because while we may have told UI Grid that we have 10,000 rows and 50 columns, it knows that we don't actually want
    +to display them all at once, so it has to figure out the visible space it's allowed to "draw" in. This space is called the "viewport". It's the "port" through which we "view"
    +the data. Everything outside this viewport is essentially empty space, except for some extra rows and columns that we add to let scrolling appear smoother.</p>
    +
    +<p>When you put the grid in a container <code>div</code> that has no height specified, and the grid has no height specified with CSS, then it has no idea how big you want it to be.
    +Do you want to see 5 rows? 100? It cannot tell. Currently it just assumes that 10 rows is a good default value and resizes itself to fit that number of rows in its viewport.
    +You can alter this value with the <code>minRowsToShow</code> option.</p>
    +
    +<p>What if you give the grid a height of <code>100%</code> but its parent container <code>div</code> has no height? Then once again it has no idea how big it's supposed to be. 100% of what? Nothing?
    +Once again, it will simply resize itself to fit the number of rows specified by <code>minRowsToShow</code>.  You can fix this problem by either giving the grid a specific height, or a variable height and then giving its container a valid height or putting other elements in the container that are present before the grid is linked up, i.e if there's an image in the same container as the grid and the image is 500px high, and the grid is specified to have <code>height: 50%</code>, then it will be 250px high.</p>
    +
    +<p>Let's move on to the case of a grid that is hidden , whether in an tab or an accordion or behind an <code>ng-show</code> expression. Hidden elements have no height or width, because they are unrendered. If you were to take an element with the CSS property <code>display: none</code> on it, and log out its <code>offsetWidth</code> property, it would be 0. Even if when it is visible it's 1000px high, when it's hidden it has no height.  UI Grid gets around this in the same way that jQuery does: cheating. It creates a "fake" clone of the element in question, changes <code>display: none</code> to <code>visibility: hidden</code> (which means it is not visible but still takes up space), appends this cloned element to the <code>&lt;body&gt;</code>, calculates its height, then removes it. The <code>&lt;body&gt;</code> is the only safe place to do this because when a hidden element takes up space it can move the flow other elements around and cause a "flickering" effect.</p>
    +
    +<p>So when you put the grid in a place that's not rendered, and don't give the grid any specific CSS to tell it how big it has to be, when it creates this cloned element and measures it, it will have 0 height and 0 width. The grid will do its best to resize, i.e. 0px is too small to be usable so it'll resize its height as above, but there's really no way to tell how wide it should be, so the columns all end up being their minimum width (30px or so), the viewport will be tiny, and it looks like the grid has rendered incorrectly because while the viewport is very small the grid element itself will just take up the
    +width of the parent container, which is what the <code>auto</code> value for width tells elements to do.</p>
    +
    +<p>In order to fix this you <strong>must</strong> give the grid something to work with. Here are some options:</p>
    +
    +<ol>
    +<li>Give the grid a specific height and width as in the example below.</li>
    +<li>Use an <code>ng-if</code> to prevent the grid from being rendered until the element it is in (tab/accordion/etc) is active, as in <a href="http://plnkr.co/edit/LtpFnDUTofuxitb4Vh9x?p=preview">this plunker</a>.</li>
    +<li>Use the <code>autoResize</code> feature let the grid redraw itself as needed. This may cause some flickering as the check is on a 250ms cycle. <a href="http://plnkr.co/edit/fwdXMamTBrR1yKVwcohZ?p=preview">Here's is a plunker demonstrating this</a>.</li>
    +</ol>
    +
    +<p>It's all up to you. And if you know a better way then please submit it in an issue or a pull request. There's always room for improvement and innovation.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-30" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-30" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-30">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="hideGrid = !hideGrid">
    +      {{ hideGrid && 'Show' || 'Hide' }} Grid
    +    </button>
    +
    +    <div class="well" ng-hide="hideGrid">
    +      <div ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.hideGrid = true;
    +
    +    $scope.gridOptions = {  };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-30" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/109_multiple_grids.html b/docs/partials/tutorial/109_multiple_grids.html
    new file mode 100644
    index 000000000..ec42b4fb9
    --- /dev/null
    +++ b/docs/partials/tutorial/109_multiple_grids.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Using multiple grids on a single page</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-31" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-32"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-31" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-31">
    +  <div ng-controller="MainCtrl">
    +    <div class="row">
    +      <div class="span4">
    +        <div id="grid1" ui-grid="gridOptions1" class="grid"></div>
    +      </div>
    +      
    +      <div class="span4">
    +        <div id="grid2" ui-grid="gridOptions2" class="grid"></div>
    +      </div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 250px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions1 = {};
    +    $scope.gridOptions2 = {};
    +
    +    $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions1.data = data;
    +    });
    +
    +    $http.get('/data/500.json')
    +    .success(function(data) {
    +      $scope.gridOptions2.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-32"></pre>
    +<script type="text/ng-template" id="scenario.js-32">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  it('grid1 should have three visible columns, grid2 has four', function () {
    +    gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +    gridTestUtils.expectHeaderColumnCount( 'grid2', 4 );
    +  });
    +
    +  it('menus should show over correct grid', function () {
    +    // click on menu in grid 1
    +    var headerCell = gridTestUtils.headerCell( 'grid1', 0 );
    +    headerCell.element( by.css( '.ui-grid-column-menu-button' ) ).click();
    +    
    +    // check a menu list is showing somewhere in grid1, and has at least 2 items
    +    var columnMenu = element( by.id( 'grid1' ) ).element( by.css( '.ui-grid-column-menu' ));
    +    expect( columnMenu.all( by.repeater('item in menuItems') ).count() ).toBeGreaterThan(2);
    +
    +    // click on menu in grid 2
    +    var headerCell = gridTestUtils.headerCell( 'grid2', 0 );
    +    headerCell.element( by.css( '.ui-grid-column-menu-button' ) ).click();
    +    
    +    // check a menu list is showing somewhere in grid2, and has at least 2 items
    +    var columnMenu = element( by.id( 'grid2' ) ).element( by.css( '.ui-grid-column-menu' ));
    +    expect( columnMenu.all( by.repeater('item in menuItems') ).count() ).toBeGreaterThan(2);
    +  });
    +
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-31" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/10_pinning.html b/docs/partials/tutorial/10_pinning.html
    new file mode 100644
    index 000000000..7b6004dc8
    --- /dev/null
    +++ b/docs/partials/tutorial/10_pinning.html
    @@ -0,0 +1,58 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-19" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-19" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-19">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" ui-grid-pinning></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.pinning']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50 },
    +      { name:'name', width:100 },
    +      { name:'age', width:100  },
    +      { name:'address.street', width:150  },
    +      { name:'address.city', width:150 },
    +      { name:'address.state', width:50 },
    +      { name:'address.zip', width:50 },
    +      { name:'company', width:100 },
    +      { name:'email', width:100 },
    +      { name:'phone', width:200 },
    +      { name:'about', width:300 },
    +      { name:'friends[0].name', displayName:'1st friend', width:150 },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150 },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150 },
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-19" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/110_grid_in_modal.html b/docs/partials/tutorial/110_grid_in_modal.html
    new file mode 100644
    index 000000000..577d43885
    --- /dev/null
    +++ b/docs/partials/tutorial/110_grid_in_modal.html
    @@ -0,0 +1,90 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Using a grid in a modal popup</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-33" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-34"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-33" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-33">
    +  <div ng-controller="MainCtrl">
    +    <button id="showButton" class="btn btn-success" ng-click="showModal()">Show Modal</button>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 300px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$rootScope', '$scope', '$http', 'modal', function ($rootScope, $scope, $http, modal) {
    +    var myModal = new modal();
    +
    +    $scope.hideGrid = true;
    +
    +    $rootScope.gridOptions = {  };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $rootScope.gridOptions.data = data;
    +      });
    +
    +    $scope.showModal = function() {
    +      myModal.open();
    +    };
    +  }]);
    +
    +  app.factory('modal', ['$compile', '$rootScope', function ($compile, $rootScope) {
    +    return function() {
    +      var elm;
    +      var modal = {
    +        open: function() {
    +
    +          var html = '<div class="modal" ng-style="modalStyle">{{modalStyle}}<div class="modal-dialog"><div class="modal-content"><div class="modal-header"></div><div class="modal-body"><div id="grid1" ui-grid="gridOptions" class="grid"></div></div><div class="modal-footer"><button id="buttonClose" class="btn btn-primary" ng-click="close()">Close</button></div></div></div></div>';
    +          elm = angular.element(html);
    +          angular.element(document.body).prepend(elm);
    +
    +          $rootScope.close = function() {
    +            modal.close();
    +          };
    +          
    +          $rootScope.modalStyle = {"display": "block"};
    +
    +          $compile(elm)($rootScope);
    +        },
    +        close: function() {
    +          if (elm) {
    +            elm.remove();
    +          }
    +        }
    +      };
    +
    +      return modal;
    +    };
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-34"></pre>
    +<script type="text/ng-template" id="scenario.js-34">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  it('click modal button, grid should show with three columns and some data', function () {
    +    element( by.id ( 'showButton' ) ).click();
    +    gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +    gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Ethel Price', 'female', 'Enersol' ]);
    +    element( by.id ( 'buttonClose' ) ).click();
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-33" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/111_cellClass.html b/docs/partials/tutorial/111_cellClass.html
    new file mode 100644
    index 000000000..0a9a403d7
    --- /dev/null
    +++ b/docs/partials/tutorial/111_cellClass.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>A class name or function returning a class name can be assigned to each columnDef.</p>
    +
    +<p>In this example, we will override the color and background for the first column and color the company text blue if it equals 'Velity'.</p>
    +
    +<h3>Source</h3>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-35" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-36"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-35" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-35">
    +    <div ng-controller="MainCtrl">
    +      <br>
    +      <br>
    +      <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 200px;
    +    }
    +    .red { color: red;  background-color: yellow !important; }
    +    .blue { color: blue;  }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +      $scope.gridOptions = {
    +        enableSorting: true,
    +        columnDefs: [
    +          { field: 'name', cellClass:'red' },
    +          { field: 'company',
    +            cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
    +              if (grid.getCellValue(row,col) === 'Velity') {
    +                return 'blue';
    +              }
    +            }
    +          }
    +        ]
    +      };
    +
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +    }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-36"></pre>
    +<script type="text/ng-template" id="scenario.js-36">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +    describe( '111 cell class', function() {
    +      it('grid should have two visible columns', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      });
    +  
    +      it('column one formatted color red, background yellow', function () {
    +        // red on yellow background for 0,0
    +        expect( gridTestUtils.dataCell( 'grid1', 0, 0 ).getCssValue('background-color')).toEqual('rgba(255, 255, 0, 1)');
    +        expect( gridTestUtils.dataCell( 'grid1', 0, 0 ).getCssValue('color')).toEqual('rgba(255, 0, 0, 1)');
    +        
    +        // color blue for 2,1, which has company name 'Velity'
    +        gridTestUtils.expectCellValueMatch( 'grid1', 2, 1, 'Velity' );
    +        expect( gridTestUtils.dataCell( 'grid1', 2, 1 ).getCssValue('color')).toEqual('rgba(0, 0, 255, 1)');
    +        
    +        // sort by company, 2,1 is no longer Velity so shouldn't be blue, check it's the same colour as row 1
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 2, 1, 'Acusage' );
    +        expect( gridTestUtils.dataCell( 'grid1', 1, 1 ).getCssValue('color')).toEqual('rgba(44, 62, 80, 1)');
    +        expect( gridTestUtils.dataCell( 'grid1', 2, 1 ).getCssValue('color')).toEqual('rgba(44, 62, 80, 1)');
    +      });
    +    });    
    +  </script>
    +</div>
    +</div><h3>Demo</h3>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-35" ng-eval-javascript="app.js"></div></div>
    diff --git a/docs/partials/tutorial/112_swapping_data.html b/docs/partials/tutorial/112_swapping_data.html
    new file mode 100644
    index 000000000..f93dcfad5
    --- /dev/null
    +++ b/docs/partials/tutorial/112_swapping_data.html
    @@ -0,0 +1,212 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can swap out data in the grid by simply providing a different reference.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-37" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-38"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-37" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-37">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" id="swapData" class="btn btn-success" ng-click="swapData()">Swap Data</button>
    +    <button type="button" id="addData" class="btn btn-success" ng-click="addData()">Add Data</button>
    +    <button type="button" id="removeFirstRow" class="btn btn-success" ng-click="removeFirstRow()">Remove First Row</button>
    +    <button type="button" id="reset" class="btn btn-success" ng-click="reset()">Reset</button>
    +    <br>
    +    <br>
    +    <div id="grid1" ui-grid="gridOpts" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.swapData = function() {
    +      if ($scope.gridOpts.data === data1) {
    +        $scope.gridOpts.data = data2;
    +        $scope.gridOpts.columnDefs = columnDefs2;
    +      }
    +      else {
    +        $scope.gridOpts.data = data1;
    +        $scope.gridOpts.columnDefs = columnDefs1;
    +      }
    +    };
    +
    +    $scope.addData = function() {
    +      var n = $scope.gridOpts.data.length + 1;
    +      $scope.gridOpts.data.push({
    +                  "firstName": "New " + n,
    +                  "lastName": "Person " + n,
    +                  "company": "abc",
    +                  "employed": true,
    +                  "gender": "male"
    +                });
    +    };
    +
    +    $scope.removeFirstRow = function() {
    +      //if($scope.gridOpts.data.length > 0){
    +         $scope.gridOpts.data.splice(0,1);
    +      //}
    +    };
    +
    +    $scope.reset = function () {
    +      data1 = angular.copy(origdata1);
    +      data2 = angular.copy(origdata2);
    +
    +      $scope.gridOpts.data = data1;
    +      $scope.gridOpts.columnDefs = columnDefs1;
    +    }
    +
    +    var columnDefs1 = [
    +      { name: 'firstName' },
    +      { name: 'lastName' },
    +      { name: 'company' },
    +      { name: 'gender' }
    +    ];
    +    
    +    var data1 = [
    +      {
    +        "firstName": "Cox",
    +        "lastName": "Carney",
    +        "company": "Enormo",
    +        "gender": "male"
    +      },
    +      {
    +        "firstName": "Lorraine",
    +        "lastName": "Wise",
    +        "company": "Comveyer",
    +        "gender": "female"
    +      },
    +      {
    +        "firstName": "Nancy",
    +        "lastName": "Waters",
    +        "company": "Fuelton",
    +        "gender": "female"
    +      },
    +      {
    +        "firstName": "Misty",
    +        "lastName": "Oneill",
    +        "company": "Letpro",
    +        "gender": "female"
    +      }
    +    ];
    +
    +    var origdata1 = angular.copy(data1);
    +
    +    var columnDefs2 = [
    +      { name: 'firstName' },
    +      { name: 'lastName' },
    +      { name: 'company' },
    +      { name: 'employed' }
    +    ];
    +
    +    var data2 = [
    +      {
    +        "firstName": "Waters",
    +        "lastName": "Shepherd",
    +        "company": "Kongene",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Hopper",
    +        "lastName": "Zamora",
    +        "company": "Acium",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Marcy",
    +        "lastName": "Mclean",
    +        "company": "Zomboid",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Tania",
    +        "lastName": "Cruz",
    +        "company": "Marqet",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Kramer",
    +        "lastName": "Cline",
    +        "company": "Parleynet",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Bond",
    +        "lastName": "Pickett",
    +        "company": "Brainquil",
    +        "employed": false
    +      }
    +    ];
    +
    +    var origdata2 = angular.copy(data2);
    +
    +    $scope.gridOpts = {
    +      columnDefs: columnDefs1,
    +      data: data1
    +    };
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-38"></pre>
    +<script type="text/ng-template" id="scenario.js-38">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '112 swapping data', function() {
    +    it('grid should have four visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 4 );
    +    });
    +
    +    it('swap data and data changes', function () {
    +      gridTestUtils.expectRowCount( 'grid1', 4 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Cox', 'Carney', 'Enormo', 'male' ] );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 1, [ 'Lorraine', 'Wise', 'Comveyer', 'female' ] );
    +      
    +      element( by.id( "swapData" ) ).click();
    +      gridTestUtils.expectRowCount( 'grid1', 6 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Waters', 'Shepherd', 'Kongene', 'true' ] );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 1, [ 'Hopper', 'Zamora', 'Acium', 'true' ] );
    +
    +      element( by.id( "swapData" ) ).click();
    +      gridTestUtils.expectRowCount( 'grid1', 4 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Cox', 'Carney', 'Enormo', 'male' ] );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 1, [ 'Lorraine', 'Wise', 'Comveyer', 'female' ] );
    +    });
    +    
    +    it('add data and data changes', function () {
    +      gridTestUtils.expectRowCount( 'grid1', 4 );
    +      
    +      element( by.id( "addData" ) ).click();
    +      gridTestUtils.expectRowCount( 'grid1', 5 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 4, [ 'New 5', 'Person 5', 'abc', 'male' ] );
    +
    +      element( by.id( "addData" ) ).click();
    +      gridTestUtils.expectRowCount( 'grid1', 6 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 5, [ 'New 6', 'Person 6', 'abc', 'male' ] );
    +    });
    +
    +    it('remove data and data changes', function () {
    +      gridTestUtils.expectRowCount( 'grid1', 4 );
    +      
    +      element( by.id( "removeFirstRow" ) ).click();
    +      gridTestUtils.expectRowCount( 'grid1', 3 );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ 'Lorraine', 'Wise', 'Comveyer', 'female' ] );
    +    });      
    +  });    
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-37" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/113_adding_and_removing_columns.html b/docs/partials/tutorial/113_adding_and_removing_columns.html
    new file mode 100644
    index 000000000..6a6eebb95
    --- /dev/null
    +++ b/docs/partials/tutorial/113_adding_and_removing_columns.html
    @@ -0,0 +1,146 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can dynamically add and remove columns, the grid watches the column defs and
    +updates appropriately.  The columns are by default shown in the order of the columnDefs,
    +although if/when the column move feature arrives the end user will be able to alter 
    +that default.</p>
    +
    +<p>You can dynamically change the display name on a column (along with some other column
    +def properties), and call the notifyDataChange api to force an update. </p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-39" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-40"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-39" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-39">
    +  <div ng-controller="MainCtrl">
    +    Try clicking the Add button to add the company column.
    +    Try clicking the Remove button to remove the last column.
    +    Try clicking the Splice button to insert a column in the middle.
    +    <br>
    +    <br>
    +    <button id="button_add" class="btn" ng-click="add()">Add</button>
    +    <button id="button_remove" class="btn" ng-click="remove()">Remove Last</button>
    +    <button id="button_splice" class="btn" ng-click="splice()">Splice</button>
    +    <button id="button_unsplice" class="btn" ng-click="unsplice()">Remove Middle</button>
    +    <button id="button_toggle_visible" class="btn" ng-click="toggleVisible()">Toggle Visible</button>
    +    <button id="button_toggle_display_name" class="btn" ng-click="toggleDisplayName()">Toggle Display Name</button>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +  
    +  app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
    +    $scope.columns = [{ field: 'name' }, { field: 'gender' }];
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: $scope.columns,
    +      onRegisterApi: function(gridApi) {
    +        $scope.gridApi = gridApi;
    +      }
    +    };
    +    
    +    $scope.remove = function() {
    +      $scope.columns.splice($scope.columns.length-1, 1);
    +    }
    +    
    +    $scope.add = function() {
    +      $scope.columns.push({ field: 'company', enableSorting: false });
    +    }
    +
    +    $scope.splice = function() {
    +      $scope.columns.splice(1, 0, { field: 'company', enableSorting: false });
    +    }
    +  
    +    $scope.unsplice = function() {
    +      $scope.columns.splice(1, 1);
    +    }
    +    
    +    $scope.toggleDisplayName = function() {
    +      if( $scope.columns[1].displayName === 'GENDER' ){
    +        $scope.columns[1].displayName = 'Gender';
    +      } else {
    +        $scope.columns[1].displayName = 'GENDER';
    +      }
    +      $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +    }
    +    
    +    $scope.toggleVisible = function() {
    +      $scope.columns[0].visible = !($scope.columns[0].visible || $scope.columns[0].visible === undefined);
    +      $scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.COLUMN);
    +    }
    +  
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-40"></pre>
    +<script type="text/ng-template" id="scenario.js-40">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '113 dynamically changing columns', function() {
    +    it('grid should have two visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +    });
    +
    +    it('add and remove columns from end, grid updates accordingly', function () {
    +      element(by.id('button_add')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +
    +      element(by.id('button_remove')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +    });      
    +
    +    it('add and remove columns in middle, grid updates accordingly', function () {
    +      element(by.id('button_splice')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Company' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Gender' );
    +
    +      element(by.id('button_unsplice')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +    }); 
    +    
    +    it('toggle column 0 visible should make column appear and disappear', function () {
    +      element(by.id('button_toggle_visible')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 1 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Gender' );
    +
    +      element(by.id('button_toggle_visible')).click();
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +    });     
    +
    +    it('toggle display name should change column header', function () {
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +      element(by.id('button_toggle_display_name')).click();
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'GENDER' );
    +      element(by.id('button_toggle_display_name')).click();
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +    });     
    +  });    
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-39" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/114_row_header.html b/docs/partials/tutorial/114_row_header.html
    new file mode 100644
    index 000000000..3963b82ba
    --- /dev/null
    +++ b/docs/partials/tutorial/114_row_header.html
    @@ -0,0 +1,64 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can add a row header column, which goes into the left pinned container 
    +(right pinned container on RTL implementations).</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-41" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-42"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-41" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-41">
    +  <div ng-controller="MainCtrl">
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +  
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.columns = [{ field: 'name' }, { field: 'gender' }];
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: $scope.columns,
    +      onRegisterApi: function( gridApi ) { 
    +        $scope.gridApi = gridApi;
    +        var cellTemplate = 'ui-grid/selectionRowHeader';   // you could use your own template here
    +        $scope.gridApi.core.addRowHeaderColumn( { name: 'rowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate} );
    +      }
    +    };
    +    
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +        console.log(data)
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-42"></pre>
    +<script type="text/ng-template" id="scenario.js-42">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '114 add row header', function() {
    +    it('grid should have two visible columns, and one pinned column', function () {
    +      gridTestUtils.expectHeaderLeftColumnCount( 'grid1', 1 );
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +    });
    +  });    
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-41" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/115_headerCellClass.html b/docs/partials/tutorial/115_headerCellClass.html
    new file mode 100644
    index 000000000..4115a45ff
    --- /dev/null
    +++ b/docs/partials/tutorial/115_headerCellClass.html
    @@ -0,0 +1,89 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>A class name or function returning a class name can be assigned to each columnDef.</p>
    +
    +<p>In this example, we will set the font color of header column 0 to blue, and conditionally
    +set the background and foreground color of the header if the sort direction is ASC</p>
    +
    +<h3>Source</h3>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-43" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-44"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-43" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-43">
    +    <div ng-controller="MainCtrl">
    +      <br>
    +      <br>
    +      <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 200px;
    +    }
    +    .red { color: red;  background-color: yellow !important; }
    +    .blue { color: blue;  }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
    +      $scope.gridOptions = {
    +        enableSorting: true,
    +        columnDefs: [
    +          { field: 'name', headerCellClass: 'blue' },
    +          { field: 'company',
    +            headerCellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
    +              if (col.sort.direction === uiGridConstants.ASC) {
    +                return 'red';
    +              }
    +            }
    +          }
    +        ],
    +        onRegisterApi: function( gridApi ) {
    +          $scope.gridApi = gridApi;
    +          $scope.gridApi.core.on.sortChanged( $scope, function( grid, sort ) {
    +            $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +          })
    +        }
    +      };
    +
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +    }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-44"></pre>
    +<script type="text/ng-template" id="scenario.js-44">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +    describe( '115 header cell class', function() {
    +      it('grid should have two visible columns', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      });
    +  
    +      it('cell classes', function () {
    +        // blue for header 0
    +        expect( gridTestUtils.headerCell( 'grid1', 0 ).getCssValue('color')).toEqual('rgba(0, 0, 255, 1)');
    +
    +        // header 2 starts with no coloring, but colors when sort is ASC
    +        expect( gridTestUtils.headerCell( 'grid1', 1 ).getCssValue('color')).toEqual('rgba(44, 62, 80, 1)', 'normal foreground');
    +
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        expect( gridTestUtils.headerCell( 'grid1', 1 ).getCssValue('color')).toEqual('rgba(255, 0, 0, 1)', 'red highlight');
    +        
    +      });
    +    });    
    +  </script>
    +</div>
    +</div><h3>Demo</h3>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-43" ng-eval-javascript="app.js"></div></div>
    diff --git a/docs/partials/tutorial/116_fonts_and_installation.html b/docs/partials/tutorial/116_fonts_and_installation.html
    new file mode 100644
    index 000000000..990382f51
    --- /dev/null
    +++ b/docs/partials/tutorial/116_fonts_and_installation.html
    @@ -0,0 +1,43 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>We get a lot of questions about fonts, and it seems to be a pain point for many users.  To date all
    +of these problems have been diagnosed to a misconfigured build setup for the end user.</p>
    +
    +<p>This tutorial addresses the basics of the configuration.</p>
    +
    +<p>Key points here are:</p>
    +
    +<ol>
    +<li>Fonts are a derivative of font-awesome via fontello, and are used for the dropdown icons and 
    +various menu buttons and the like.  When they're not working they show a "chinese looking" character.  </li>
    +<li>The tutorial pages generally show the fonts correctly.  If a tutorial page, when served from
    +ui-grid.info is not showing fonts correctly, then this is likely a defect with ui-grid.  If it's 
    +working on ui-grid.info, but not in your application, then it's likely a defect in your build configuration</li>
    +<li>The fonts <strong>never</strong> work on plunkrs.  This isn't a defect, it's a configuration issue where the
    +plunkr blocks "cross-domain" resource requests - it won't serve fonts from ui-grid.info when
    +the plunkr itself is on <code>plunkr.co</code>.  The fact that plunkrs don't show fonts doesn't make this 
    +an issue with ui-grid, it's still likely an issue with your configuration.  :-)</li>
    +</ol>
    +
    +<p>When you download and install ui-grid, you'll get a series of files:</p>
    +
    +<ul>
    +<li><code>ui-grid.js</code></li>
    +<li><code>ui-grid.css</code></li>
    +<li><code>ui-grid.eot</code></li>
    +<li><code>ui-grid.svg</code></li>
    +<li><code>ui-grid.ttf</code></li>
    +<li><code>ui-grid.woff</code></li>
    +</ul>
    +
    +<p>The last four files are the font files.  These generally need to be inserted into your local build process,
    +as they will need to be copied to your <code>assets</code> folder, your <code>fonts</code> folder or some other similar location. 
    +The instructions for configuring this are different for each build setup, but your build environment should
    +have come with some method for configuring this - usually a Gruntfile.js, a build.config.js, or some form of
    +gulp configuration.</p>
    +
    +<p>If you are seeking to diagnose why you're not getting your fonts, you can typically look at your Chrome developer
    +tools, and you'll see a network request being issued for one of the font files, which then gives an error not
    +found.  As a first step, try manually copying the font files into that location.  If your application now works,
    +then your goal is to work out how to configure your build process to do that automatically for you.</p></div>
    diff --git a/docs/partials/tutorial/120_RTL.html b/docs/partials/tutorial/120_RTL.html
    new file mode 100644
    index 000000000..19cbbe69a
    --- /dev/null
    +++ b/docs/partials/tutorial/120_RTL.html
    @@ -0,0 +1,59 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The grid supports RTL languages</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-45" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-45" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-45">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" dir="rtl" ui-grid-pinning ui-grid-resize-columns></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.selection', 'ui.grid.pinning']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      columnDefs: [
    +        { name: 'field1', field: 'name', width: 200 },
    +        { name: 'field2', field: 'gender', width: 200 },
    +        { name: 'field3', field: 'company', width: 200 },
    +        { name: 'field4', field: 'name', width: 200 },
    +        { name: 'field5', field: 'gender', width: 200 },
    +        { name: 'field6', field: 'company', width: 200 },
    +        { name: 'field7', field: 'name', width: 200 },
    +        { name: 'field8', field: 'gender', width: 200 },
    +        { name: 'field9', field: 'company', width: 200 },
    +        { name: 'field10', field: 'name', width: 200 },
    +        { name: 'field11', field: 'gender', width: 200 },
    +        { name: 'field12', field: 'company', width: 200 },
    +        { name: 'field13', field: 'name', width: 200 },
    +        { name: 'field14', field: 'gender', width: 200 },
    +        { name: 'field15', field: 'company', width: 200 }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-45" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/12_i18n.html b/docs/partials/tutorial/12_i18n.html
    new file mode 100644
    index 000000000..a4f843839
    --- /dev/null
    +++ b/docs/partials/tutorial/12_i18n.html
    @@ -0,0 +1,45 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>i18n</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-16" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-16" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-16">
    +  <div ng-controller="MainCtrl">
    +    <select ng-model="lang" ng-options="l for l in langs"></select><br>
    +
    +    <div ui-i18n="{{lang}}">
    +       <p>Using attribute:</p>
    +       <p ui-t="groupPanel.description"></p>
    +       <br/>
    +       <p>Using Filter:</p>
    +       <p>{{"groupPanel.description" | t}}</p>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', 'i18nService', function ($scope, i18nService) {
    +      $scope.langs = i18nService.getAllLangs();
    +      $scope.lang = 'en';
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-16" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/190_large_dataset.html b/docs/partials/tutorial/190_large_dataset.html
    new file mode 100644
    index 000000000..90df67c26
    --- /dev/null
    +++ b/docs/partials/tutorial/190_large_dataset.html
    @@ -0,0 +1,85 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses a data set of 10,000 records.</p>
    +
    +<p>Demonstrates the following:</p>
    +
    +<ul>
    +   <li>binding complex column properties on Address.City.</li>
    +   <li>same field can be listed twice in the grid with a different name</li>
    +   <li>using field instead of name for backwards compatibility with 2.x</li>
    + </ul><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-46" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-47"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-46" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-46">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <br>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +    };
    +
    +    $scope.gridOptions.columnDefs = [
    +      {name:'id'},
    +      {name:'name'},
    +      {field:'age'}, // showing backwards compatibility with 2.x.  you can use field in place of name
    +      {name: 'address.city'},
    +      {name: 'age again', field:'age'}
    +    ];
    +
    +    $http.get('/data/10000_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-47"></pre>
    +<script type="text/ng-template" id="scenario.js-47">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '190 large dataset', function() {
    +    it('grid should have five visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 5 );
    +    });
    +
    +    it('column headers as expected', function () {
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Id' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Name' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Age' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 3, 'Address.City' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 4, 'Age Again' );
    +    });
    +
    +    it('first couple of rows as expected', function () {
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 0, [ '0', 'Ramsey Cummings', '52', 'Glendale', '52' ] );
    +      gridTestUtils.expectRowValuesMatch( 'grid1', 1, [ '1', 'Stefanie Huff', '70', 'Beaverdale', '70' ] );
    +    });
    +  });    
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-46" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/190_swapping_data.html b/docs/partials/tutorial/190_swapping_data.html
    new file mode 100644
    index 000000000..1661cff33
    --- /dev/null
    +++ b/docs/partials/tutorial/190_swapping_data.html
    @@ -0,0 +1,146 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can swap out data in the grid by simply providing a different reference.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-36" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-36" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-36">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="swapData()">Swap Data</button>
    +    <button type="button" class="btn btn-success" ng-click="addData()">Add Data</button>
    +    <button type="button" class="btn btn-success" ng-click="removeFirstRow()">Remove First Row</button>
    +    <button type="button" class="btn btn-success" ng-click="reset()">Reset</button>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOpts" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.swapData = function() {
    +      if ($scope.gridOpts.data === data1) {
    +        $scope.gridOpts.data = data2;
    +      }
    +      else {
    +        $scope.gridOpts.data = data1;
    +      }
    +    };
    +
    +    $scope.addData = function() {
    +      var n = $scope.gridOpts.data.length + 1;
    +      $scope.gridOpts.data.push({
    +                  "firstName": "New " + n,
    +                  "lastName": "Person " + n,
    +                  "company": "abc",
    +                  "employed": true
    +                });
    +    };
    +
    +    $scope.removeFirstRow = function() {
    +      //if($scope.gridOpts.data.length > 0){
    +         $scope.gridOpts.data.splice(0,1);
    +      //}
    +    };
    +
    +    $scope.reset = function () {
    +      data1 = angular.copy(origdata1);
    +      data2 = angular.copy(origdata2);
    +
    +      $scope.gridOpts.data = data1;
    +    }
    +
    +    var data1 = [
    +      {
    +        "firstName": "Cox",
    +        "lastName": "Carney",
    +        "company": "Enormo",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Lorraine",
    +        "lastName": "Wise",
    +        "company": "Comveyer",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Nancy",
    +        "lastName": "Waters",
    +        "company": "Fuelton",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Misty",
    +        "lastName": "Oneill",
    +        "company": "Letpro",
    +        "employed": false
    +      }
    +    ];
    +
    +    var origdata1 = angular.copy(data1);
    +
    +    var data2 = [
    +      {
    +        "firstName": "Waters",
    +        "lastName": "Shepherd",
    +        "company": "Kongene",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Hopper",
    +        "lastName": "Zamora",
    +        "company": "Acium",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Marcy",
    +        "lastName": "Mclean",
    +        "company": "Zomboid",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Tania",
    +        "lastName": "Cruz",
    +        "company": "Marqet",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Kramer",
    +        "lastName": "Cline",
    +        "company": "Parleynet",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Bond",
    +        "lastName": "Pickett",
    +        "company": "Brainquil",
    +        "employed": false
    +      }
    +    ];
    +
    +    var origdata2 = angular.copy(data2);
    +
    +    $scope.gridOpts = {
    +      data: data1
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-36" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/191_horizontal_scrolling.html b/docs/partials/tutorial/191_horizontal_scrolling.html
    new file mode 100644
    index 000000000..a9d9abed4
    --- /dev/null
    +++ b/docs/partials/tutorial/191_horizontal_scrolling.html
    @@ -0,0 +1,93 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Demonstrating scrolling with large amount of columns</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-48" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-49"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-48" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-48">
    +  <div ng-controller="MainCtrl">
    +    <strong>{{ gridOptions.columnDefs.length | number }} Columns with Random Widths</strong>
    +    <br>
    +    <br>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
    +    $scope.gridOptions = {
    +      enableSorting: true
    +    };
    +
    +    var colCount = 500;
    +    var rowCount = 500;
    +
    +    $scope.gridOptions.columnDefs = [];
    +    $timeout( function() {
    +      for (var colIndex = 0; colIndex < colCount; colIndex++) {
    +        $scope.gridOptions.columnDefs.push({
    +          name: 'col' + colIndex,
    +          width: Math.floor(Math.random() * (120 - 50 + 1)) + 50
    +        });
    +      }
    +    });
    +    
    +    var data = [];
    +
    +    $timeout( function() {
    +      for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    +        var row = {};
    +
    +        for (var colIndex = 0; colIndex < colCount; colIndex++) {
    +          row['col' + colIndex] = 'r' + rowIndex + 'c' + colIndex;
    +        }
    +
    +        data.push(row);
    +      }
    +    });
    +
    +    $scope.gridOptions.data = data;
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-49"></pre>
    +<script type="text/ng-template" id="scenario.js-49">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '191 horizontal scrolling', function() {
    +    it('check first couple of headers and cells - make sure grid has rendered', function () {
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Col0' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Col1' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Col2' );
    +      
    +      gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'r0c0' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'r1c0' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 0, 'r2c0' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 0, 1, 'r0c1' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 1, 1, 'r1c1' );
    +    });
    +
    +//      it('scroll right', function () {
    +      // still working out how to get protractor to scroll an element
    +//      });
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-48" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/1_basic_grid.html b/docs/partials/tutorial/1_basic_grid.html
    new file mode 100644
    index 000000000..7172edba2
    --- /dev/null
    +++ b/docs/partials/tutorial/1_basic_grid.html
    @@ -0,0 +1,342 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>In this example we create the most basic grid possible.</p>
    +
    +<p><br> We are using the optional <code>external-scopes="{myViewModel:myViewModel}"</code> attribute
    +to give us access to the view model via $scope.getExternalScopes() function.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-16" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-16" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-16">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="{ data: data }" external-scopes="{myViewModel:myViewModel}" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.myViewModel = {code:'abc'};
    +
    +    $scope.data = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Misty",
    +          "lastName": "Oneill",
    +          "company": "Letpro",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Jefferson",
    +          "lastName": "Cohen",
    +          "company": "Slambda",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Gladys",
    +          "lastName": "Maldonado",
    +          "company": "Ramjob",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Glenn",
    +          "lastName": "Cole",
    +          "company": "Austex",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Waters",
    +          "lastName": "Shepherd",
    +          "company": "Kongene",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Hopper",
    +          "lastName": "Zamora",
    +          "company": "Acium",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Marcy",
    +          "lastName": "Mclean",
    +          "company": "Zomboid",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Tania",
    +          "lastName": "Cruz",
    +          "company": "Marqet",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Kramer",
    +          "lastName": "Cline",
    +          "company": "Parleynet",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Bond",
    +          "lastName": "Pickett",
    +          "company": "Brainquil",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Pauline",
    +          "lastName": "Cervantes",
    +          "company": "Slumberia",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Pittman",
    +          "lastName": "Reilly",
    +          "company": "Zolavo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Bartlett",
    +          "lastName": "Schwartz",
    +          "company": "Momentia",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Berg",
    +          "lastName": "Cherry",
    +          "company": "Eargo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Hazel",
    +          "lastName": "Doyle",
    +          "company": "Koogle",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Amie",
    +          "lastName": "Mathis",
    +          "company": "Buzzness",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Walker",
    +          "lastName": "Molina",
    +          "company": "Medmex",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Elnora",
    +          "lastName": "Schroeder",
    +          "company": "Undertap",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Grant",
    +          "lastName": "Fletcher",
    +          "company": "Comvoy",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Violet",
    +          "lastName": "Ferrell",
    +          "company": "Multiflex",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Nettie",
    +          "lastName": "David",
    +          "company": "Waab",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mosley",
    +          "lastName": "Dunn",
    +          "company": "Sloganaut",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Puckett",
    +          "lastName": "Jarvis",
    +          "company": "Printspan",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Emma",
    +          "lastName": "Holcomb",
    +          "company": "Techmania",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Clara",
    +          "lastName": "Mueller",
    +          "company": "Microluxe",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Tanya",
    +          "lastName": "Hull",
    +          "company": "Buzzmaker",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Brandy",
    +          "lastName": "Berger",
    +          "company": "Ludak",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Bennett",
    +          "lastName": "Fischer",
    +          "company": "Zedalis",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Sallie",
    +          "lastName": "Vance",
    +          "company": "Voipa",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Celeste",
    +          "lastName": "Harrington",
    +          "company": "Steelfab",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Dunn",
    +          "lastName": "Mccoy",
    +          "company": "Ontagene",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mindy",
    +          "lastName": "Vang",
    +          "company": "Quadeebo",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Benton",
    +          "lastName": "Boyle",
    +          "company": "Flexigen",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Kristine",
    +          "lastName": "Hunt",
    +          "company": "Egypto",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Daugherty",
    +          "lastName": "Barber",
    +          "company": "Vinch",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Mays",
    +          "lastName": "Fuentes",
    +          "company": "Memora",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Maribel",
    +          "lastName": "Bush",
    +          "company": "Brainclip",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Brittney",
    +          "lastName": "Morse",
    +          "company": "Gonkle",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Fernandez",
    +          "lastName": "Sutton",
    +          "company": "Zeam",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Valeria",
    +          "lastName": "Owens",
    +          "company": "Zentix",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Gretchen",
    +          "lastName": "Dorsey",
    +          "company": "Sultrax",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mona",
    +          "lastName": "Hart",
    +          "company": "Exostream",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Skinner",
    +          "lastName": "Vincent",
    +          "company": "Konnect",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Hardy",
    +          "lastName": "Casey",
    +          "company": "Xylar",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mccullough",
    +          "lastName": "Irwin",
    +          "company": "Joviold",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Barnett",
    +          "lastName": "Melton",
    +          "company": "Intergeek",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Michael",
    +          "lastName": "Hooper",
    +          "company": "Confrenzy",
    +          "employed": true
    +      }
    +  ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-16" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/2.1_appending_data.html b/docs/partials/tutorial/2.1_appending_data.html
    new file mode 100644
    index 000000000..2e3c37986
    --- /dev/null
    +++ b/docs/partials/tutorial/2.1_appending_data.html
    @@ -0,0 +1,108 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Appends data to the grid every .2 seconds for 15 seconds.  This emulates loading pages of data from the server. It's also an example
    +of setting gridOptions.data to a string value that specifies an object on your scope to watch.
    +<br></p>
    +
    +<p>All features are enabled to get an idea of performance</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-19" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-19" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-19">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="refreshData()">Refresh Data</button>  <strong>Calls Pending:</strong> <span ng-bind="callsPending"></span>
    +    <br>
    +    <br>
    +    <strong>{{ myData.length }} rows</strong>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-cellNav ui-grid-edit ui-grid-resize-columns class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 500px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav', 'ui.grid.edit', 'ui.grid.resizeColumns']);
    +
    +  app.controller('MainCtrl',  ['$scope', '$http', '$timeout', '$interval', function ($scope, $http, $timeout, $interval) {
    +
    +    $scope.gridOptions = {};
    +    $scope.gridOptions.data = 'myData';
    +    $scope.gridOptions.enableColumnResizing = true;
    +    
    +    $scope.gridOptions.rowIdentity = function(row) {
    +      return row.id;
    +    };
    +    $scope.gridOptions.getRowIdentity = function(row) {
    +      return row.id;
    +    };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50 },
    +      { name:'name', width:100 },
    +      { name:'age', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.street', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Street:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.city', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>City:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.state', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>State:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.zip', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Zip:{{COL_FIELD}}</span></div>'  },
    +      { name:'company', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Company:{{COL_FIELD}}</span></div>'  },
    +      { name:'email', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Email:{{COL_FIELD}}</span></div>'  },
    +      { name:'phone', width:200, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Phone:{{COL_FIELD}}</span></div>'  },
    +      { name:'about', width:300, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>AAbout:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[0].name', displayName:'1st friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend0:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend1:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend2:{{COL_FIELD}}</span></div>'  },
    +      { name:'agetemplate',field:'age', width:100, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age 2:{{COL_FIELD}}</span></div>' }
    +    ];
    +
    +    $scope.callsPending = 0;
    +
    +    var i = 0;
    +    $scope.refreshData = function(){
    +      $scope.myData = [];
    +
    +      var start = new Date();
    +      var sec = $interval(function () {
    +        $scope.callsPending++;
    +        
    +        $http.get('/data/500_complex.json')
    +          .success(function(data) {
    +            $scope.callsPending--;
    +
    +            data.forEach(function(row){
    +              row.name = row.name + ' iter ' + i;
    +              row.id = i;
    +              i++;
    +              $scope.myData.push(row);
    +            });
    +          })
    +          .error(function() {
    +            $scope.callsPending--
    +          });
    +      }, 200);
    +
    +
    +      $timeout(function() {
    +         $interval.cancel(sec);
    +         $scope.left = '';
    +      }, 2000);
    +
    +    };
    +
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-19" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/200_features.html b/docs/partials/tutorial/200_features.html
    new file mode 100644
    index 000000000..d60d1ff8b
    --- /dev/null
    +++ b/docs/partials/tutorial/200_features.html
    @@ -0,0 +1,14 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The core module, ui.grid, contains only the core features needed.  More complex features are separated into feature modules and must be included in your application module.</p>
    +
    +<p>You must include each feature as a dependency for your application module.
    +<pre class="prettyprint linenums">
    +angular.module('yourApp', ['ui.grid', 'ui.grid.feature1', 'ui.grid.feature2']);
    +</pre>
    +
    +<p>Each feature directive must also be included in alongside the ui-grid directive.  This allows you to have many grids in an application and enable certain features for each grid instance.
    +<pre class="prettyprint linenums">
    +&lt;div ui-grid="gridOptions" class="grid" ui-grid-feature1 ui-grid-feature2&gt;&lt;/div&gt;
    +</pre></div>
    diff --git a/docs/partials/tutorial/201_editable.html b/docs/partials/tutorial/201_editable.html
    new file mode 100644
    index 000000000..bd7d2b189
    --- /dev/null
    +++ b/docs/partials/tutorial/201_editable.html
    @@ -0,0 +1,180 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The ui.grid.edit feature allows inline editing of grid data.  To enable, you must include the <code>'ui.grid.edit'</code> module
    +and you must include the <code>ui-grid-edit</code> directive on your grid element.</p>
    +
    +<p>You can use the <code>enableCellEdit</code> options in your column definitions to allow a column to be editable.</p>
    +
    +<p>Editing is invoked via double-click, f2, or start typing any non-navigable key. Cell editing ends on tab, enter or esc (cancel)
    +on an input editor, and tab, left or right arrows, enter or esc for a dropdown.</p>
    +
    +<p>By default an input element is provided, with numeric, date and checkbox editors for fields specified as <code>'number'</code>, <code>'date'</code>
    +and <code>'boolean'</code> types, for all other fields a simple text editor is provided. (A point to note about date editors is that for date editors
    +to be enabled the datatype of the variable should also be "Date").</p>
    +
    +<p>A dropdown editor is also available, through setting the <code>editableCellTemplate</code> on the <code>columnDef</code> to <code>'ui-grid/dropdownEditor'</code>.
    +When using a dropdown editor you need to provide an options array through the <code>editDropDownOptionsArray</code> property on the <code>columnDef</code>.
    +This array by default should be an array of <code>{id: xxx, value: xxx}</code>, although the field tags can be changed through
    +using the <code>editDropdownIdLabel</code> and <code>editDropdownValueLabel</code> options.</p>
    +
    +<p>Custom edit templates should be used for any editor other than the default editors, but be aware that you will likely also
    +need to provide a custom directive similar to the uiGridEditor directive so as to provide <code>BEGIN_CELL_EDIT, CANCEL_CELL_EDIT
    +and END_CELL_EDIT</code> events.</p>
    +
    +<p><strong>ColumnDef Options</strong>:</p>
    +
    +<ul>
    +<li><code>editableCellTemplate</code> (default: <code>'ui-grid/cellEditor'</code>) - Valid html, templateCache Id,  or url that returns html
    +content to be compiled when edit mode is invoked.</li>
    +<li><code>enableCellEdit</code> (default: <code>false</code> for columns of type <code>'object'</code>, <code>true</code> for all other columns) - <code>true</code> will enable
    +editing and <code>false</code> will disable it.</li>
    +<li><code>cellEditableCondition</code>  (default: <code>true</code>)  Can be set to a boolean or a function that will be called with the cellScope
    +to determine if the cell should be invoked in edit mode.</li>
    +<li><code>type</code> (default: <code>'string'</code>) If set to <code>'number'</code>, <code>'boolean'</code> or <code>'date'</code> the default editor provided for editing will be numeric
    +or boolean or date editor respectively.  If set to <code>'object'</code> the column will not be editable by default.  Be aware that this
    +<code>type</code> column is also used for other purposes within ui-grid, including the sorting logic.</li>
    +<li><code>editDropdownOptionsArray</code> If a dropdown, needs to be populated with an array of values, by default those values should be
    +<code>{id: xxx, value: xxx}</code>, the labels can be adjusted with the next two options</li>
    +<li><code>editDropdownIdLabel</code> (default: <code>'id'</code>) Controls the id label in the options array - so if your array happens to contain
    +<code>'code'</code> instead you can use it without having to reprocess the array</li>
    +<li><code>editDropdownValueLabel</code> (default: <code>'value'</code>) Controls the value label in the options array - if your array happens to
    +contain <code>'name'</code> instead you can use it without having to reprocess the array</li>
    +<li><code>editDropdownRowEntityOptionsArrayPath</code> can be used as an alternative to editDropdownOptionsArray when the contents of the dropdown depend on the entity backing the row.</li>
    +<li><code>editDropdownFilter</code> (default: <code>''</code>) Allows you to apply a filter to the values in the edit dropdown options, for example
    +if you were using angular-translate you would set this to <code>'translate'</code></li>
    +</ul>
    +
    +<p>The following option is available only if using cellNav feature</p>
    +
    +<ul>
    +<li><code>enableCellEditOnFocus</code> - <code>true</code> to invoke editor as soon as cell has focus</li>
    +</ul>
    +
    +<p><em>Note that the edit functionality uses native html5 edit widgets - the date picker, the dropdown and the input box
    +itself.  If your browser does not implement these widgets, then you won't get them.  If your browser implements these
    +widgets in a way that isn't ideal (for example, some browsers don't allow number fields to start with '.', so you can't 
    +type in '.5'), then you need to provide a custom editor instead.  On the medium term roadmap there is intent
    +to provide a bootstrap feature, which would provide directives that were compatible with angular-bootstrap directives, 
    +allowing use of the bootstrap datepicker and input fields</em></p>
    +
    +<pre class="prettyprint linenums">
    +$scope.gridOptions.columnDefs = [
    +   { name: 'name', enableCellEdit: true, editableCellTemplate: 'xxxxxxx' },
    +   { name: 'age', enableCellEdit: true, type: 'number'},
    +   { name: 'registered', displayName: 'Registered' , type: 'date'},
    +   { name: 'address', displayName: 'Address', type: 'object'},
    +   { name: 'address.city', enableCellEdit: true, displayName: 'Address (even rows editable)', cellEditableCondition: function($scope){return $scope.rowRenderIndex%2} }
    +   { name: 'isActive', enableCellEdit: true, type: 'boolean'},
    +]
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-50" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-50" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-50">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <strong>Last Cell Edited:</strong> {{msg.lastCellEdited}}
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit', 'addressFormatter']);
    +
    +  angular.module('addressFormatter', []).filter('address', function () {
    +    return function (input) {
    +        return input.street + ', ' + input.city + ', ' + input.state + ', ' + input.zip;
    +    };
    +  });
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', enableCellEdit: false, width: '10%' },
    +      { name: 'name', displayName: 'Name (editable)', width: '20%' },
    +      { name: 'age', displayName: 'Age' , type: 'number', width: '10%' },
    +      { name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
    +        cellFilter: 'mapGender', editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
    +        { id: 1, gender: 'male' },
    +        { id: 2, gender: 'female' }
    +      ] },
    +      { name: 'registered', displayName: 'Registered' , type: 'date', cellFilter: 'date:"yyyy-MM-dd"', width: '20%' },
    +      { name: 'address', displayName: 'Address', type: 'object', cellFilter: 'address', width: '30%' },
    +      { name: 'address.city', displayName: 'Address (even rows editable)', width: '20%',
    +           cellEditableCondition: function($scope){
    +           return $scope.rowRenderIndex%2
    +           }
    +      },
    +      { name: 'isActive', displayName: 'Active', type: 'boolean', width: '10%' },
    +      { name: 'pet', displayName: 'Pet', width: '20%', editableCellTemplate: 'ui-grid/dropdownEditor',
    +        editDropdownRowEntityOptionsArrayPath: 'foo.bar[0].options', editDropdownIdLabel: 'value'
    +      }
    +    ];
    +
    +
    +
    +   $scope.msg = {};
    +
    +   $scope.gridOptions.onRegisterApi = function(gridApi){
    +            //set gridApi on scope
    +            $scope.gridApi = gridApi;
    +            gridApi.edit.on.afterCellEdit($scope,function(rowEntity, colDef, newValue, oldValue){
    +              $scope.msg.lastCellEdited = 'edited row id:' + rowEntity.id + ' Column:' + colDef.name + ' newValue:' + newValue + ' oldValue:' + oldValue ;
    +              $scope.$apply();
    +            });
    +          };
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        for(i = 0; i < data.length; i++){
    +          data[i].registered = new Date(data[i].registered);
    +          data[i].gender = data[i].gender==='male' ? 1 : 2;
    +          if (i % 2) {
    +            data[i].pet = 'fish'
    +            data[i].foo = {bar: [{baz: 2, options: [{value: 'fish'}, {value: 'hamster'}]}]}
    +          }
    +          else {
    +            data[i].pet = 'dog'
    +            data[i].foo = {bar: [{baz: 2, options: [{value: 'dog'}, {value: 'cat'}]}]}
    +          }
    +        }
    +        $scope.gridOptions.data = data;
    +      });
    +  }])
    +
    +  .filter('mapGender', function() {
    +    var genderHash = {
    +      1: 'male',
    +      2: 'female'
    +    };
    +
    +    return function(input) {
    +      if (!input){
    +        return '';
    +      } else {
    +        return genderHash[input];
    +      }
    +    };
    +  })
    +});
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-50" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/202_cellnav.html b/docs/partials/tutorial/202_cellnav.html
    new file mode 100644
    index 000000000..a8a6231ee
    --- /dev/null
    +++ b/docs/partials/tutorial/202_cellnav.html
    @@ -0,0 +1,123 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses the ui-grid-cellNav directive to add cell navigation. To enable, you must include the 'ui.grid.cellNav' 
    +module and you must include the ui-grid-cellNav directive on your grid element.</p>
    +
    +<p>CellNav allows you to navigate around the grid using the arrow keys, pg-down and pg-up, enter (moves down),
    +shift-enter (moves up), tab (moves right) and shift-tab (moves left).  When combined with the editable feature, the 
    +left-right arrow keys will be subsumed when in "deep edit" mode, allowing you to move around within the text you're editing. <br />
    +The tab key and shift-tab keys continue to function.</p>
    +
    +<p>Uses the gridOptions.onRegisterApi callback to register the on_cellNav event and log when the cell is navigated.</p>
    +
    +<p>Provides an example of requesting a scroll to a specific row or column programatically - useful for
    +remembering the state of a page and scrolling back to that position when a user returns.</p>
    +
    +<p>Provides an example of scrolling to and setting the focus on a specific cell, using the scrollToFocus api.</p>
    +
    +<p>Provides an example of utilizing the modifierKeysToMultiSelectCells option and getCurrentSelection API function to
    +extract values of selected cells.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-51" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-51" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-51">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="scrollTo(20,0)">Scroll To Row 20</button>
    +    <button type="button" class="btn btn-success" ng-click="scrollTo(0,7)">Scroll To Balance</button>
    +    <button type="button" class="btn btn-success" ng-click="scrollTo(50,7)">Scroll To Row 50, Balance</button>
    +    <button type="button" class="btn btn-success" ng-click="scrollToFocus(50,7)">Focus Row 50, Balance</button>
    +    <button type="button" class="btn btn-success" ng-click="getCurrentFocus()">Get Current focused cell</button>  <span ng-bind="currentFocused"></span>
    +    <button type="button" class="btn btn-success" ng-click="getCurrentSelection()">Get Current focused cell values</button>
    +    <input type="text" ng-model="printSelection" placeholder="Click the 'Get current focused cell values' button to print cell values of selection here" class="printSelection">
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-cellNav ui-grid-pinning class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +  .printSelection {
    +      width: 600px;
    +      margin-top: 10px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.cellNav', 'ui.grid.pinning']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +    $scope.gridOptions.modifierKeysToMultiSelectCells = true;
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', width:'150' },
    +      { name: 'name', width:'200' },
    +      { name: 'age', displayName: 'Age (not focusable)', allowCellFocus : false, width:'100' },
    +      { name: 'address.city', width:'200' },
    +      { name: 'phone', width:'150' },
    +      { name: 'company', width:'150' },
    +      { name: 'email', width:'150' },
    +      { name: 'balance', width:'100' },
    +      { name: 'guid', width:'100' }
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.info = {};
    +
    +      $scope.currentFocused = "";
    +
    +      $scope.getCurrentFocus = function(){
    +        var rowCol = $scope.gridApi.cellNav.getFocusedCell();
    +        if(rowCol !== null) {
    +            $scope.currentFocused = 'Row Id:' + rowCol.row.entity.id + ' col:' + rowCol.col.colDef.name;
    +        }
    +      };
    +
    +      $scope.getCurrentSelection = function() {
    +        var values = [];
    +        var currentSelection = $scope.gridApi.cellNav.getCurrentSelection();
    +        for (var i = 0; i < currentSelection.length; i++) {
    +          values.push(currentSelection[i].row.entity[currentSelection[i].col.name])
    +        }
    +        $scope.printSelection = values.toString();
    +      };
    +      
    +      $scope.scrollTo = function( rowIndex, colIndex ) {
    +        $scope.gridApi.cellNav.scrollTo( $scope.gridOptions.data[rowIndex], $scope.gridOptions.columnDefs[colIndex]);
    +      };
    +
    +      $scope.scrollToFocus = function( rowIndex, colIndex ) {
    +        $scope.gridApi.cellNav.scrollToFocus( $scope.gridOptions.data[rowIndex], $scope.gridOptions.columnDefs[colIndex]);
    +      };
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +         $scope.gridApi = gridApi;
    +         gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +               // var rowCol = {row: newRowCol.row.index, col:newRowCol.col.colDef.name};
    +               // var msg = 'New RowCol is ' + angular.toJson(rowCol);
    +               // if(oldRowCol){
    +               //    rowCol = {row: oldRowCol.row.index, col:oldRowCol.col.colDef.name};
    +               //    msg += ' Old RowCol is ' + angular.toJson(rowCol);
    +               // }
    +                $log.log('navigation event');
    +              });
    +      };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-51" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/202_externalScopes.html b/docs/partials/tutorial/202_externalScopes.html
    new file mode 100644
    index 000000000..9db627aa7
    --- /dev/null
    +++ b/docs/partials/tutorial/202_externalScopes.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid uses isolate scope, so there is no access to your application scope variables from a row or cell template.</p>
    +
    +<p>To access your application data within UI-Grid, use the external-scopes attribute.  Give the attribute a
    +property that exists on your scope.
    +<pre class="prettyprint linenums">
    + $scope.myViewModel.showMe = function(){...};
    + &lt;div ui-grid="{ data: myData }" external-scopes="myViewModel" class="grid"&gt;&lt;/div&gt;
    +</pre>
    +
    +<p>Then in a template, you access the scope using getExternalScopes() function.
    +<pre class="prettyprint linenums">
    +    ng-click="getExternalScopes().showMe()"
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-20" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-20" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-20">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$log', function ($scope, $log) {
    +
    +   $scope.myViewModel = {
    +      someProp:'abc',
    +      showMe : function(){
    +         alert(this.someProp);
    +      }
    +   };
    +
    +   $scope.gridOptions = {};
    +
    +     $scope.gridOptions.columnDefs = [
    +           { name: 'firstName' },
    +           { name: 'lastName'},
    +           { name: 'ShowScope',
    +               cellTemplate:'<button class="btn primary" ng-click="getExternalScopes().showMe()">Click Me</button>' }
    +         ];
    +
    +   $scope.gridOptions.data = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      }
    +  ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-20" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/203_pinning.html b/docs/partials/tutorial/203_pinning.html
    new file mode 100644
    index 000000000..c6899b30c
    --- /dev/null
    +++ b/docs/partials/tutorial/203_pinning.html
    @@ -0,0 +1,60 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The pinning feature allows the user to pin a column to left or right. To enable, you must include the 'ui.grid.pinning' module and you must include the ui-grid-pinning directive on your grid element.</p>
    +
    +<p>It is also possible to disable pinning on column level. Note the 'id' column definition in the example below.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-52" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-52" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-52">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" ui-grid-pinning></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 100%;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.pinning']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50, enablePinning:false },
    +      { name:'name', width:100, pinnedLeft:true },
    +      { name:'age', width:100, pinnedRight:true  },
    +      { name:'address.street', width:150  },
    +      { name:'address.city', width:150 },
    +      { name:'address.state', width:50 },
    +      { name:'address.zip', width:50 },
    +      { name:'company', width:100 },
    +      { name:'email', width:100 },
    +      { name:'phone', width:200 },
    +      { name:'about', width:300 },
    +      { name:'friends[0].name', displayName:'1st friend', width:150 },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150 },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150 },
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-52" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/204_column_resizing.html b/docs/partials/tutorial/204_column_resizing.html
    new file mode 100644
    index 000000000..bdd91c25a
    --- /dev/null
    +++ b/docs/partials/tutorial/204_column_resizing.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The Resize Columns feature allows each column to be resized.</p>
    +
    +<p>To enable, you must include the 'ui.grid.resizeColumns' module and you must include the ui-grid-resize-columns directive on your grid element.</p>
    +
    +<pre class="prettyprint linenums">
    +angular.module('yourApp', ['ui.grid', 'ui.grid.resizeColumns']);
    +</pre>
    +
    +<pre class="prettyprint linenums">
    +&lt;div ui-grid="gridOptions" class="grid" ui-grid-resize-columns&gt;&lt;/div&gt;
    +</pre>
    +<br>
    +<br>
    +If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +option to false. This prevents resizing for the entire grid, regardless of individual colDef options.
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableColumnResizing: false
    +};
    +</pre>
    +<br>
    +<br>
    +You can disable it on a column by setting the <code>enableColumnResizing</code> property to false in its column definition.
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableColumnResizing: true,
    +  columnDefs: [
    +    { field: 'name' },
    +    { field: 'gender', enableColumnResizing: false },
    +    { field: 'company' }
    +  ]
    +};
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-53" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-53" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-53">
    +  <div ng-controller="MainCtrl">
    +    <strong>Drag</strong> a the column separator to resize; <strong>double-click</strong> to size according to rendered column contents.
    +    <br>
    +    <br>
    +    The column will obey any <i>minWidth</i> or <i>maxWidth</i> constraints you give it.
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid" ui-grid-resize-columns ui-grid-move-columns></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.moveColumns']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: [
    +        { field: 'name', minWidth: 200, width: '50%', enableColumnResizing: false },
    +        { field: 'gender', width: '30%', maxWidth: 200, minWidth: 70 },
    +        { field: 'company', width: '20%' }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-53" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/205_row_editable.html b/docs/partials/tutorial/205_row_editable.html
    new file mode 100644
    index 000000000..0503a5770
    --- /dev/null
    +++ b/docs/partials/tutorial/205_row_editable.html
    @@ -0,0 +1,136 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The ui.grid.rowedit extends the edit feature to support callbacks for server saving of the data,
    +with that data saved "row at a time."  This feature attempts to give a user an experience similar
    +to a spreadsheet - in that they can edit whichever fields they wish, and the feature will seek to
    +save the data "row at a time".  To the extent that the data doesn't generate errors, from a user
    +perspective the saving is almost invisible - rows occassionally go grey (saving) and can't be edited whilst
    +grey, but otherwise the user edits as if the data were local.  </p>
    +
    +<p>Each row is in one of four states at any point in time:</p>
    +
    +<ul>
    +<li>clean:  No edits have been made (or no edits since the last save)</li>
    +<li><code>isDirty</code>:  Edits have been made, but the data has not yet been saved, either because the 
    +user is still editing the row or because the timer hasn't triggered as yet</li>
    +<li><code>isSaving</code>: The callback to save the row has been called and has not yet returned.  The row is
    +not editable during this time, and is shown as greyed out, so as to avoid the user 
    +causing locking exceptions by editing the row again</li>
    +<li><code>isError</code>: The save callback returned an error.  The row still has the updated data displayed,
    +but will be shown in red</li>
    +</ul>
    +
    +<p>The basic method of operation is that whenever a cell is edited (identified using the <code>edit.afterCellEdit</code>
    +event) an <code>isDirty</code> flag is set on the row, and a <code>saveTimer</code> is set.  If another cell in the same row commences
    +editing within 2 seconds (or other configurable time), then the timer will be destroyed again.  Otherwise
    +upon the timer completing the row will be set to a status of <code>isSaving</code> and greyed out, and the <code>saveRow</code>
    +event will be called.  The function called by this event must return a promise, and the rowedit feature
    +will wait on that promise.</p>
    +
    +<p>If the cellNav feature is also enabled, then a setFocus on a cell within the row is sufficient to delay
    +the timer (this more easily deals with situations where only some columns are editable, and a user tabs
    +or clicks to a non-editable field on the same row).</p>
    +
    +<p>If the promise is successfully resolved then the row is set back to clean.  If the promise is rejected then the 
    +row is set to a status of <code>isError</code>.</p>
    +
    +<p>Optionally, the calling application can request <code>flushDirtyRows</code>, which will trigger the save event for all
    +currently dirty rows.  If the <code>rowEditWaitInterval</code> grid option is set to -1, then saves will never be triggered
    +by timer, and only be triggered when manually called.</p>
    +
    +<p>Methods and properties are provided to operate with this regime:</p>
    +
    +<ul>
    +<li><code>getDirtyRows()</code>: returns an array of gridRows of all currently dirty rows</li>
    +<li><code>getErrorRows()</code>: returns an array of gridRows of all currently errored rows</li>
    +<li><code>flushDirtyRows()</code>: flushes all currently dirty rows to the server, might be used 
    +on a page navigation request or pressing of a save button</li>
    +<li><code>saveRow( rowEntity )</code>: event called when a row is ready for saving</li>
    +<li><code>rowEditWaitInterval</code>: grid option that controls how long a wait will be before a save is triggered (in ms)</li>
    +</ul><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example rows are saved 2 seconds after moving off, and the save is faked using a timeout of 3 seconds, so 
    +each save will take 3 seconds to complete.  Any row saved with a gender of "male" will error.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-54" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-54" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-54">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-edit ui-grid-row-edit ui-grid-cellNav class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 600px;
    +      height: 450px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit', 'ui.grid.rowEdit', 'ui.grid.cellNav', 'addressFormatter']);
    +
    +    angular.module('addressFormatter', []).filter('address', function () {
    +      return function (input) {
    +          return input.street + ', ' + input.city + ', ' + input.state + ', ' + input.zip;
    +      };
    +    });
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$q', '$interval', function ($scope, $http, $q, $interval) {
    +      $scope.gridOptions = {};
    +
    +      $scope.gridOptions.columnDefs = [
    +        { name: 'id', enableCellEdit: false },
    +        { name: 'name', displayName: 'Name (editable)' },
    +        { name: 'gender' },
    +        { name: 'age', displayName: 'Age' , type: 'number'},
    +        { name: 'registered', displayName: 'Registered' , type: 'date', cellFilter: 'date:"yyyy-MM-dd"'},
    +        { name: 'address', displayName: 'Address', type: 'object', cellFilter: 'address'},
    +        { name: 'address.city', displayName: 'Address (even rows editable)',
    +             cellEditableCondition: function($scope){
    +             return $scope.rowRenderIndex%2
    +             }
    +        },
    +        { name: 'isActive', displayName: 'Active', type: 'boolean'}
    +      ];
    +
    +      $scope.saveRow = function( rowEntity ) {
    +        // create a fake promise - normally you'd use the promise returned by $http or $resource
    +        var promise = $q.defer();
    +        $scope.gridApi.rowEdit.setSavePromise( rowEntity, promise.promise );
    +       
    +        // fake a delay of 3 seconds whilst the save occurs, return error if gender is "male"
    +        $interval( function() {
    +          if (rowEntity.gender === 'male' ){
    +            promise.reject();
    +          } else {
    +            promise.resolve();
    +          }
    +        }, 3000, 1);
    +      }; 
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +        //set gridApi on scope
    +        $scope.gridApi = gridApi;
    +        gridApi.rowEdit.on.saveRow($scope, $scope.saveRow);
    +      };
    +  
    +      $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        for(i = 0; i < data.length; i++){
    +          data[i].registered = new Date(data[i].registered);
    +        }
    +        $scope.gridOptions.data = data;
    +      });
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-54" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/206_exporting_data.html b/docs/partials/tutorial/206_exporting_data.html
    new file mode 100644
    index 000000000..a77817005
    --- /dev/null
    +++ b/docs/partials/tutorial/206_exporting_data.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The exporter feature allows data to be exported from the grid in 
    +csv or pdf format.  The exporter can export all data, visible data or selected data.</p>
    +
    +<p>To use the exporter you need to include the ui-grid-exporter directive on
    +your grid.  If you want to export selected rows you must include the ui-grid-selection
    +directive on your grid.  If you want to export as PDF you need to have installed pdfMake, 
    +available through:
    +<pre class="prettyprint linenums">  bower install pdfmake  </pre>
    +
    +<p>The options and API for exporter can be found at <a href="#/api/ui.grid.exporter">ui.grid.exporter</a>.</p>
    +
    +<p>The exporter adds menu items to the grid menu, to use the native UI you need to enable
    +the grid menu using the gridOption <code>enableGridMenu</code></p>
    +
    +<p>Note that the option to export selected data is only visible if you have data selected.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we use the native grid menu buttons, and we show both the pdf and csv export options.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-55" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-55" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-55">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.exporter']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          { field: 'name' },
    +          { field: 'gender', visible: false},
    +          { field: 'company' }
    +        ],
    +        enableGridMenu: true,
    +        enableSelectAll: true,
    +        exporterCsvFilename: 'myFile.csv',
    +        exporterPdfDefaultStyle: {fontSize: 9},
    +        exporterPdfTableStyle: {margin: [30, 30, 30, 30]},
    +        exporterPdfTableHeaderStyle: {fontSize: 10, bold: true, italics: true, color: 'red'},
    +        exporterPdfHeader: { text: "My Header", style: 'headerStyle' },
    +        exporterPdfFooter: function ( currentPage, pageCount ) {
    +          return { text: currentPage.toString() + ' of ' + pageCount.toString(), style: 'footerStyle' };
    +        },
    +        exporterPdfCustomFormatter: function ( docDefinition ) {
    +          docDefinition.styles.headerStyle = { fontSize: 22, bold: true }; 
    +          docDefinition.styles.footerStyle = { fontSize: 10, bold: true }; 
    +          return docDefinition;
    +        },
    +        exporterPdfOrientation: 'portrait',
    +        exporterPdfPageSize: 'LETTER',
    +        exporterPdfMaxGridWidth: 500,
    +        exporterCsvLinkElement: angular.element(document.querySelectorAll(".custom-csv-link-location")),
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +        }
    +      };
    +      
    +      $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +        
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-55" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/207_importing_data.html b/docs/partials/tutorial/207_importing_data.html
    new file mode 100644
    index 000000000..c8e6d851d
    --- /dev/null
    +++ b/docs/partials/tutorial/207_importing_data.html
    @@ -0,0 +1,99 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The importer feature allows data to be imported into the grid in 
    +csv or json format.  The importer can use the native grid menu, or can accept a 
    +file from a custom file picker implemented by the user.</p>
    +
    +<p>The importer imports files in json or csv format, with the ability to be extended
    +to other file formats if demand exists.</p>
    +
    +<p>For json format files the received elements are assumed to match the column.field 
    +attributes in your columnDefs, and are loaded into the provided entity.  </p>
    +
    +<p>For csv files the data is mapped to the columnDefs, with columns in the heading row in the 
    +csv needing to match either the column.name or column.displayName.  Optionally you can
    +provide a custom function that maps headings to column.name, and this will be used instead, 
    +you could use this to implement a custom "column picker" type routine.  If you are using
    +internationalisation on the headers (say, via adding a cellHeaderFilter), then you can
    +also optionally pass a filter function into the <code>importerHeaderFilterCallback</code> routine.
    +This routine will be called on the displayName to try to match the translated text, if
    +you provide this routine it must return an immediate translation, not a promise - so if 
    +using angular-translate you need to use <code>$translate.instant</code>.</p>
    +
    +<p>Optionally you can provide a custom function that maps the data within each entity as it is 
    +imported, refer the documentation for <code>importerObjectCallback</code>.</p>
    +
    +<p>To use the importer you need to include the ui-grid-importer directive on
    +your grid, and you must provide a <code>gridOptions.importerDataAddCallback</code> function that adds
    +the created objects into your data array.  You also need to have installed the csv-js library,
    +<code>bower install --savedev csv-js</code>.  You can configure the csv-js library through use of globals,
    +for example <code>CSV.DETECT_TYPES = false;</code>, refer to the {https://github.com/gkindel/CSV-JS csv-js documentation} 
    +for more information. </p>
    +
    +<p>The options and API for importer can be found at <a href="#/api/ui.grid.importer">ui.grid.importer</a>.</p>
    +
    +<p>The importer adds menu items to the grid menu, to use the native UI you need to enable
    +the grid menu using the gridOption <code>enableGridMenu</code>.  You can turn the menu items off by
    +setting <code>importerShowMenu: false</code>.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we use the native grid menu to import a file.  You need to provide a file
    +from your file system to use the tutorial, you can copy either import.json or import.csv
    +as a test file.</p>
    +
    +<p>The grid will start empty, and will auto-populate the column defs and data once the file 
    +has been imported (in many uses you would define the column defs up front, this example
    +illustrates that doing so is not mandatory).</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-56" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-56" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-56">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-importer class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.importer']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', function ($scope, $http, $interval) {
    +      $scope.data = [];
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        data: 'data',
    +        importerDataAddCallback: function ( grid, newObjects ) {
    +          $scope.data = $scope.data.concat( newObjects );
    +        },
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +        }
    +      };
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-56" ng-eval-javascript="app.js"></div>
    +import.json:
    +<pre class="prettyprint linenums">
    +[{"Name":"John Smith","Gender":"male","Company":"TestIcon"},{"Name":"Jane Doe","Gender":"female","Company":"FastTruck"}]
    +</pre>
    +
    +<p>import.csv
    +<pre class="prettyprint linenums">
    +"Name","Gender","Company"
    +"John Smith","male","TestIcon"
    +"Jane Doe","female","FastTrucks"
    +</pre></div>
    +</div>
    diff --git a/docs/partials/tutorial/208_save_state.html b/docs/partials/tutorial/208_save_state.html
    new file mode 100644
    index 000000000..5a86a156d
    --- /dev/null
    +++ b/docs/partials/tutorial/208_save_state.html
    @@ -0,0 +1,133 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The save state feature allows you to save the current look of the grid
    +and restore it upon returning to the grid.</p>
    +
    +<p>For example, you may have an application where your user can reorder the columns,
    +adjust column widths, apply sorts and filters, and select a specific cell.  The user
    +might adjust their grid to look as they wish, and then navigate to another page.  When 
    +the user returns to the page with the grid, they might expect it to look like it
    +did when they left.  The save state feature permits this.</p>
    +
    +<p>There are two core methods:</p>
    +
    +<ul>
    +<li>save, which packages the current grid state into an object which the calling application 
    +then stores somewhere (a cookie, session state, a database)</li>
    +<li>restore, which takes a grid state object, and returns the grid to the state that 
    +is stored in that object</li>
    +</ul>
    +
    +<p>Note that the saveState functionality deliberately sets out to store the transient state - 
    +the information that isn't held in gridOptions nor columnDefs.  The calling application is responsible for
    +storing gridOptions and columnDefs (and must have had them in order to render the grid the first time).</p>
    +
    +<p>The feature also provides some options that control what is saved.  All options are true by
    +default:</p>
    +
    +<ul>
    +<li>saveWidths</li>
    +<li>saveOrder</li>
    +<li>saveScroll</li>
    +<li>saveFocus</li>
    +<li>saveVisible</li>
    +<li>saveSort</li>
    +<li>saveFilter</li>
    +</ul><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we provide a button to save the grid state.  You can then modify the grid layout
    +to something different, and use the restore button to set the grid back the way it was.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-57" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-58"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-57" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-57">
    +    <div ng-controller="MainCtrl">
    +      <div id="grid1" ui-grid="gridOptions" ui-grid-save-state ui-grid-selection ui-grid-cellNav ui-grid-resize-columns ui-grid-move-columns class="grid"></div>
    +      <button id="save" type="button" class="btn btn-success" ng-click="saveState()">Save</button>
    +      <button id="restore" type="button" class="btn btn-success" ng-click="restoreState()">Restore</button>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.saveState', 'ui.grid.selection', 'ui.grid.cellNav', 'ui.grid.resizeColumns', 'ui.grid.moveColumns' ]);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', function ($scope, $http, $interval) {
    +      $scope.gridOptions = {
    +        saveFocus: false,
    +        saveScroll: true,
    +        enableFiltering: true,
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +        }
    +      };
    +      $scope.state = {};
    +      
    +      $scope.saveState = function() {
    +        $scope.state = $scope.gridApi.saveState.save();
    +      };
    +
    +      $scope.restoreState = function() {
    +        $scope.gridApi.saveState.restore( $scope, $scope.state );
    +      };
    + 
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +    }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-58"></pre>
    +<script type="text/ng-template" id="scenario.js-58">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +    describe( '208 save state', function() {
    +      it('Set a sort and a filter, save state, hide a column and remove sort and filter, set another sort and filter, restore the state', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        
    +        gridTestUtils.clickColumnMenuSortAsc( 'grid1', 2 );
    +        gridTestUtils.enterFilterInColumn( 'grid1', 1, 'female' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Freda Mason' );
    +        
    +        element(by.id('save')).click();
    +        
    +        gridTestUtils.clickColumnMenuRemoveSort( 'grid1', 2 );
    +        gridTestUtils.cancelFilterInColumn( 'grid1', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +
    +        gridTestUtils.clickColumnMenuSortAsc( 'grid1', 0 );
    +        gridTestUtils.enterFilterInColumn( 'grid1', 2, 'Gee' );
    +        gridTestUtils.clickColumnMenuHide( 'grid1', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Alexander Foley' );
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +        
    +        element(by.id('restore')).click();
    +        
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Freda Mason' );
    +      });
    +  
    +    });
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-57" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/210_selection.html b/docs/partials/tutorial/210_selection.html
    new file mode 100644
    index 000000000..2d64eae03
    --- /dev/null
    +++ b/docs/partials/tutorial/210_selection.html
    @@ -0,0 +1,175 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses the ui-grid-selection directive to row selection. To enable, you must include the 'ui.grid.selection' 
    +module and you must include the ui-grid-selection directive on your grid element.</p>
    +
    +<p>Uses the gridOptions.onRegisterApi callback to register the rowSelectionChanged event and log when the row is selected.
    +By default the selection feature will divide selection changes into batch events and single events, there are
    +two different events provided in the api.  By setting <code>enableSelectionBatchEvent: false</code> you can cause it to 
    +instead just call the single event in a loop - which may be useful if you're doing client rather than server
    +side processing of the changes.</p>
    +
    +<p>By default the module will provide a row header with checkboxes that allow selection of individual rows.  If you set
    +the <code>enableRowHeaderSelection</code> gridOption to false, then the row header is hidden and a click on the row will
    +result in selection of that row.  You can see that in this tutorial for grid1 by looking at your javascript console.</p>
    +
    +<p>Setting the <code>multiSelect</code> gridOption to true will allow selecting multiple rows, setting to false will allow selection
    +of only one row at a time.</p>
    +
    +<p>If you have <code>multiSelect: false</code>, then an additional option <code>noUnselect</code> will mean that a row is always selected.  You
    +can select a different row (which will unselect the current row), but you cannot manually unselect the current row
    +by clicking on it.  This means that at least one row is always selected, other than when you first open the grid.  If 
    +necessary you could programatically select the first row upon page open.  The second grid demonstrates this.</p>
    +
    +<p>If <code>multiSelect: true</code>, another option <code>modifierKeysToMultiSelect</code> may be used. If set to true this will allow selecting 
    +multiple rows only if the Ctrl-Key, Cmd-Key (Mac) or the Shift-Key is used when selecting, if set to false then it allows
    +selecting multiple rows by individually clicking them.</p>
    +
    +<p>By default a selectAll box is shown at the top of the rowHeader.  If <code>multiSelect: true</code> is set then this will allow
    +you to select all visible rows.  Note that the selectAll does not watch for new data, so if you are using the selectAll
    +function and you add data to the grid, you need to check <code>grid.api.selection.getSelectAllState</code>, and if it is currently
    +ticked, then manually call <code>grid.api.selection.selectAllVisibleRows</code> after your data has been added.</p>
    +
    +<p>The selectAll box can be disabled by setting <code>enableSelectAll</code> to false.</p>
    +
    +<p>You can set the selection row header column width by setting 'selectionRowHeaderWidth' option.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>Two examples are provided, the first with rowHeaderSelection and multi-select, the second without.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-59" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-59" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-59">
    +    <div ng-controller="MainCtrl">
    +      <button type="button" class="btn btn-success" ng-click="toggleMultiSelect()">Toggle multiSelect</button>  <strong>MultiSelect:</strong> <span ng-bind="gridApi.grid.options.multiSelect"></span>
    +      <button type="button" class="btn btn-success" ng-click="toggleRow1()">Toggle Row 0</button>
    +      <br/>
    +      <br/>
    +      <button type="button" class="btn btn-success" ng-click="toggleModifierKeysToMultiSelect()">Toggle modifierKeysToMultiSelect</button>  <strong>ModifierKeysToMultiSelect:</strong> <span ng-bind="gridApi.grid.options.modifierKeysToMultiSelect"> </span>     
    +      <br/>
    +      <br/>
    +      <button type="button" class="btn btn-success" ng-disabled="!gridApi.grid.options.multiSelect" ng-click="selectAll()">Select All</button>
    +      <button type="button" class="btn btn-success" ng-click="clearAll()">Clear All</button>
    +      <br/>
    +
    +      <div ui-grid="gridOptions" ui-grid-selection class="grid"></div>
    +    </div>
    +    <div ng-controller="SecondCtrl">
    +      Single selection grid without rowHeader, and allowing rowSelection to be toggled on and off dynamically:
    +      <br/>
    +      <button type="button" class="btn btn-success" ng-click="toggleRowSelection()">Toggle rowSelection</button>  <strong>rowSelection:</strong> <span ng-bind="gridApi.grid.options.enableRowSelection"></span>
    +      <div ui-grid="gridOptions" ui-grid-selection class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 100%;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.selection']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +      $scope.gridOptions = { 
    +        enableRowSelection: true,
    +        enableSelectAll: true,
    +        selectionRowHeaderWidth: 35,
    +        rowHeight: 35,
    +        showGridFooter:true
    +      };
    +
    +      $scope.gridOptions.columnDefs = [
    +        { name: 'id' },
    +        { name: 'name'},
    +        { name: 'age', displayName: 'Age (not focusable)', allowCellFocus : false },
    +        { name: 'address.city' }
    +      ];
    +
    +      $scope.gridOptions.multiSelect = true;
    +
    +      $http.get('/data/500_complex.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +
    +        $scope.info = {};
    +
    +        $scope.toggleMultiSelect = function() {
    +          $scope.gridApi.selection.setMultiSelect(!$scope.gridApi.grid.options.multiSelect);
    +        };
    +
    +        $scope.toggleModifierKeysToMultiSelect = function() {
    +          $scope.gridApi.selection.setModifierKeysToMultiSelect(!$scope.gridApi.grid.options.modifierKeysToMultiSelect);
    +        };
    +
    +        $scope.selectAll = function() {
    +          $scope.gridApi.selection.selectAllRows();
    +        };
    +
    +        $scope.clearAll = function() {
    +          $scope.gridApi.selection.clearSelectedRows();
    +        };
    +
    +        $scope.toggleRow1 = function() {
    +          $scope.gridApi.selection.toggleRowSelection($scope.gridOptions.data[0]);
    +        };
    +
    +        $scope.gridOptions.onRegisterApi = function(gridApi){
    +          //set gridApi on scope
    +          $scope.gridApi = gridApi;
    +          gridApi.selection.on.rowSelectionChanged($scope,function(row){
    +            var msg = 'row selected ' + row.isSelected;
    +            $log.log(msg);
    +          });
    +
    +          gridApi.selection.on.rowSelectionChangedBatch($scope,function(rows){
    +            var msg = 'rows changed ' + rows.length;
    +            $log.log(msg);
    +          });
    +        };
    +    }]);
    +    
    +    app.controller('SecondCtrl', ['$scope', '$http', '$interval', 'uiGridConstants', function ($scope, $http, $interval, uiGridConstants) {
    +      $scope.gridOptions = { enableRowSelection: true, enableRowHeaderSelection: false };
    +
    +      $scope.gridOptions.columnDefs = [
    +        { name: 'id' },
    +        { name: 'name'},
    +        { name: 'age', displayName: 'Age (not focusable)', allowCellFocus : false },
    +        { name: 'address.city' }
    +      ];
    +
    +      $scope.gridOptions.multiSelect = false;
    +      $scope.gridOptions.modifierKeysToMultiSelect = false;
    +      $scope.gridOptions.noUnselect = true;
    +      $scope.gridOptions.onRegisterApi = function( gridApi ) {
    +        $scope.gridApi = gridApi;
    +      };
    +
    +      $scope.toggleRowSelection = function() {
    +        $scope.gridApi.selection.clearSelectedRows();
    +        $scope.gridOptions.enableRowSelection = !$scope.gridOptions.enableRowSelection;
    +        $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.OPTIONS);
    +      };
    +
    +      $http.get('/data/500_complex.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +          
    +          // $interval whilst we wait for the grid to digest the data we just gave it
    +          $interval( function() {$scope.gridApi.selection.selectRow($scope.gridOptions.data[0]);}, 0, 1);
    +        });
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-59" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/211_two_grids.html b/docs/partials/tutorial/211_two_grids.html
    new file mode 100644
    index 000000000..569a234f5
    --- /dev/null
    +++ b/docs/partials/tutorial/211_two_grids.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example puts two grids on the same page, and demonstrates that they are isolated from
    +each other.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-60" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-61"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-60" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-60">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="scrollTo(20,0)">Scroll To Row 20</button>
    +    <div id="firstGrid" ui-grid="gridOptions" ui-grid-selection ui-grid-cellNav class="grid"></div>
    +  </div>
    +  <div ng-controller="SecondCtrl">
    +    <div id="secondGrid" ui-grid="gridOptions" ui-grid-selection ui-grid-cellNav class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 300px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {
    +      onRegisterApi: function(gridApi){
    +        $scope.gridApi = gridApi;
    +      }
    +    };
    +    
    +    $scope.scrollTo = function( rowIndex, colIndex ) {
    +      $scope.gridApi.cellNav.scrollTo( $scope.gridOptions.data[rowIndex], $scope.gridOptions.columnDefs[colIndex]);
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +  }]);
    +
    +  app.controller('SecondCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-61"></pre>
    +<script type="text/ng-template" id="scenario.js-61">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe( '211 two grids', function() {
    +    it('check first grid has rendered', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'firstGrid', 3 );
    +    });
    +
    +    it('check second grid has rendered', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'secondGrid', 3 );
    +    });
    +
    +//      it('check that menus display over the correct grid', function () {
    +      // still working out how to get protractor to scroll an element
    +//      });
    +  });    
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-60" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/212_infinite_scroll.html b/docs/partials/tutorial/212_infinite_scroll.html
    new file mode 100644
    index 000000000..b28e83afe
    --- /dev/null
    +++ b/docs/partials/tutorial/212_infinite_scroll.html
    @@ -0,0 +1,105 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The infinite scroll feature allows the user to lazy load their data to gridOptions.data</p>
    +
    +<p>Specify percentage when lazy load should trigger:
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions.infiniteScroll = 20;
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-62" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-62" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-62">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" ui-grid-infinite-scroll></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.infiniteScroll']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +  /**
    +    * @ngdoc property
    +    * @name infiniteScrollPercentage
    +    * @propertyOf ui.grid.class:GridOptions
    +    * @description This setting controls at what percentage of the scroll more data
    +    * is requested by the infinite scroll
    +    */
    +    $scope.gridOptions.infiniteScrollPercentage = 15;
    +    
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id'},
    +      { name:'name' },
    +      { name:'age' }
    +    ];
    +    var page = 0;
    +    var pageUp = 0;
    +    var getData = function(data, page) {
    +      var res = [];
    +      for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
    +        res.push(data[i]);
    +      }
    +      return res;
    +    };
    +
    +    var getDataUp = function(data, page) {
    +      var res = [];
    +      for (var i = data.length - (page * 100) - 1; (data.length - i) < ((page + 1) * 100) && (data.length - i) > 0; --i) {
    +        data[i].id = -(data.length - data[i].id)
    +        res.push(data[i]);
    +      }
    +      return res;
    +    };
    +
    +    $http.get('/data/10000_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = getData(data, page);
    +        ++page;
    +      });
    +
    +    $scope.gridOptions.onRegisterApi = function(gridApi){
    +      gridApi.infiniteScroll.on.needLoadMoreData($scope,function(){
    +        $http.get('/data/10000_complex.json')
    +          .success(function(data) {
    +            $scope.gridOptions.data = $scope.gridOptions.data.concat(getData(data, page));
    +            ++page;
    +            gridApi.infiniteScroll.dataLoaded();
    +          })
    +          .error(function() {
    +            gridApi.infiniteScroll.dataLoaded();
    +          });
    +      });
    +      gridApi.infiniteScroll.on.needLoadMoreDataTop($scope,function(){
    +        $http.get('/data/10000_complex.json')
    +          .success(function(data) {
    +            $scope.gridOptions.data = getDataUp(data, pageUp).reverse().concat($scope.gridOptions.data);
    +            ++pageUp;
    +            gridApi.infiniteScroll.dataLoaded();
    +          })
    +          .error(function() {
    +            gridApi.infiniteScroll.dataLoaded();
    +          });
    +      });
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-62" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/213_auto_resizing.html b/docs/partials/tutorial/213_auto_resizing.html
    new file mode 100644
    index 000000000..b8a641ed3
    --- /dev/null
    +++ b/docs/partials/tutorial/213_auto_resizing.html
    @@ -0,0 +1,73 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The auto-resize feature will enable the grid to resize itself when its container changes size.</p>
    +
    +<p>To use, include the <code>'ui.grid.autoResize'</code> module in your angular app's dependencies, and add the <code>ui-grid-auto-resize</code> directive to your grid element.</p>
    +
    +<p><strong>Note:</strong> This works by adding a checker on 250ms interval that sees if the grid element has changed in size. It could potentially affect the performance of your site or application negatively.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-63" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-63" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-63">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="randomSize()">Change to Random Size</button>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid" ui-grid-auto-resize></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.autoResize']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50 },
    +      { name:'name', width:100, pinnedLeft:true },
    +      { name:'age', width:100, pinnedRight:true  },
    +      { name:'address.street', width:150  },
    +      { name:'address.city', width:150 },
    +      { name:'address.state', width:50 },
    +      { name:'address.zip', width:50 },
    +      { name:'company', width:100 },
    +      { name:'email', width:100 },
    +      { name:'phone', width:200 },
    +      { name:'about', width:300 },
    +      { name:'friends[0].name', displayName:'1st friend', width:150 },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150 },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150 },
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +    $scope.randomSize = function () {
    +      var newHeight = Math.floor(Math.random() * (300 - 100 + 1) + 300);
    +      var newWidth = Math.floor(Math.random() * (600 - 200 + 1) + 200);
    +
    +      angular.element(document.getElementsByClassName('grid')[0]).css('height', newHeight + 'px');
    +      angular.element(document.getElementsByClassName('grid')[0]).css('width', newWidth + 'px');
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-63" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/214_pagination.html b/docs/partials/tutorial/214_pagination.html
    new file mode 100644
    index 000000000..11a530098
    --- /dev/null
    +++ b/docs/partials/tutorial/214_pagination.html
    @@ -0,0 +1,77 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>When pagination is enabled, the data is displayed in pages that can be browsed using using the built in pagination selector.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-64" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-64" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-64">
    +  <div ng-controller="MainCtrl">
    +    <p><strong>Grid with native pagination controls</strong></p>
    +    <div ui-grid="gridOptions1" ui-grid-pagination class="grid"></div>
    +    <br /><br />
    +    <p><strong>Grid pagination controlled via the API</strong></p>
    +    <div ui-grid="gridOptions2" ui-grid-pagination class="grid"></div>
    +    <p>Current page: {{ gridApi2.pagination.getPage() }} of {{ gridApi2.pagination.getTotalPages() }}</p>
    +    <button type="button" class="btn btn-success" ng-click="gridApi2.pagination.previousPage()">
    +      previous page
    +    </button>
    +    <button type="button" class="btn btn-success" ng-click="gridApi2.pagination.nextPage()">
    +      next page
    +    </button>
    +    <button type="button" class="btn btn-success" ng-click="gridApi2.pagination.seek(3)">
    +      go to page 3
    +    </button>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.pagination']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions1 = {
    +      paginationPageSizes: [25, 50, 75],
    +      paginationPageSize: 25,
    +      columnDefs: [
    +        { name: 'name' },
    +        { name: 'gender' },
    +        { name: 'company' }
    +      ]
    +    };
    +
    +    $scope.gridOptions2 = {
    +      enablePaginationControls: false,
    +      paginationPageSize: 25,
    +      columnDefs: [
    +        { name: 'name' },
    +        { name: 'gender' },
    +        { name: 'company' }
    +      ]
    +    };
    +
    +    $scope.gridOptions2.onRegisterApi = function (gridApi) {
    +      $scope.gridApi2 = gridApi;
    +    }
    +
    +    $http.get('/data/100.json')
    +    .success(function (data) {
    +      $scope.gridOptions1.data = data;
    +      $scope.gridOptions2.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-64" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/215_paging.html b/docs/partials/tutorial/215_paging.html
    new file mode 100644
    index 000000000..188c95c40
    --- /dev/null
    +++ b/docs/partials/tutorial/215_paging.html
    @@ -0,0 +1,48 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>When paging is enabled, the data is displayed in pages that can be browsed using using the built in paging selector.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-65" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-65" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-65">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" ui-grid-paging class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.paging']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      pagingPageSizes: [25, 50, 75],
    +      pagingPageSize: 25,
    +      columnDefs: [
    +        { name: 'name' },
    +        { name: 'gender' },
    +        { name: 'company' }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +    .success(function (data) {
    +      $scope.gridOptions.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-65" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/299_RTL.html b/docs/partials/tutorial/299_RTL.html
    new file mode 100644
    index 000000000..6750bc5bb
    --- /dev/null
    +++ b/docs/partials/tutorial/299_RTL.html
    @@ -0,0 +1,59 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The grid supports RTL languages</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-21" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-21" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-21">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" dir="rtl" ui-grid-pinning></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      columnDefs: [
    +        { name: 'field1', field: 'name', width: 200 },
    +        { name: 'field2', field: 'gender', width: 200 },
    +        { name: 'field3', field: 'company', width: 200 },
    +        { name: 'field4', field: 'name', width: 200 },
    +        { name: 'field5', field: 'gender', width: 200 },
    +        { name: 'field6', field: 'company', width: 200 },
    +        { name: 'field7', field: 'name', width: 200 },
    +        { name: 'field8', field: 'gender', width: 200 },
    +        { name: 'field9', field: 'company', width: 200 },
    +        { name: 'field10', field: 'name', width: 200 },
    +        { name: 'field11', field: 'gender', width: 200 },
    +        { name: 'field12', field: 'company', width: 200 },
    +        { name: 'field13', field: 'name', width: 200 },
    +        { name: 'field14', field: 'gender', width: 200 },
    +        { name: 'field15', field: 'company', width: 200 }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-21" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/2_swapping_data.html b/docs/partials/tutorial/2_swapping_data.html
    new file mode 100644
    index 000000000..63b8aa2b4
    --- /dev/null
    +++ b/docs/partials/tutorial/2_swapping_data.html
    @@ -0,0 +1,146 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can swap out data in the grid by simply providing a different reference.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-22" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-22" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-22">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="swapData()">Swap Data</button>
    +    <button type="button" class="btn btn-success" ng-click="addData()">Add Data</button>
    +    <button type="button" class="btn btn-success" ng-click="removeFirstRow()">Remove First Row</button>
    +    <button type="button" class="btn btn-success" ng-click="reset()">Reset</button>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOpts" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.swapData = function() {
    +      if ($scope.gridOpts.data === data1) {
    +        $scope.gridOpts.data = data2;
    +      }
    +      else {
    +        $scope.gridOpts.data = data1;
    +      }
    +    };
    +
    +    $scope.addData = function() {
    +      var n = $scope.gridOpts.data.length + 1;
    +      $scope.gridOpts.data.push({
    +                  "firstName": "New " + n,
    +                  "lastName": "Person " + n,
    +                  "company": "abc",
    +                  "employed": true
    +                });
    +    };
    +
    +    $scope.removeFirstRow = function() {
    +      //if($scope.gridOpts.data.length > 0){
    +         $scope.gridOpts.data.splice(0,1);
    +      //}
    +    };
    +
    +    $scope.reset = function () {
    +      data1 = angular.copy(origdata1);
    +      data2 = angular.copy(origdata2);
    +
    +      $scope.gridOpts.data = data1;
    +    }
    +
    +    var data1 = [
    +      {
    +        "firstName": "Cox",
    +        "lastName": "Carney",
    +        "company": "Enormo",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Lorraine",
    +        "lastName": "Wise",
    +        "company": "Comveyer",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Nancy",
    +        "lastName": "Waters",
    +        "company": "Fuelton",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Misty",
    +        "lastName": "Oneill",
    +        "company": "Letpro",
    +        "employed": false
    +      }
    +    ];
    +
    +    var origdata1 = angular.copy(data1);
    +
    +    var data2 = [
    +      {
    +        "firstName": "Waters",
    +        "lastName": "Shepherd",
    +        "company": "Kongene",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Hopper",
    +        "lastName": "Zamora",
    +        "company": "Acium",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Marcy",
    +        "lastName": "Mclean",
    +        "company": "Zomboid",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Tania",
    +        "lastName": "Cruz",
    +        "company": "Marqet",
    +        "employed": true
    +      },
    +      {
    +        "firstName": "Kramer",
    +        "lastName": "Cline",
    +        "company": "Parleynet",
    +        "employed": false
    +      },
    +      {
    +        "firstName": "Bond",
    +        "lastName": "Pickett",
    +        "company": "Brainquil",
    +        "employed": false
    +      }
    +    ];
    +
    +    var origdata2 = angular.copy(data2);
    +
    +    $scope.gridOpts = {
    +      data: data1
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-22" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/301_custom_row_template.html b/docs/partials/tutorial/301_custom_row_template.html
    new file mode 100644
    index 000000000..1ea8dc30e
    --- /dev/null
    +++ b/docs/partials/tutorial/301_custom_row_template.html
    @@ -0,0 +1,72 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Create a grid almost the same as the most basic one, but with a custom row template.</p>
    +
    +<p>You can use <a href="/docs/#/tutorial/305_appScope">grid.appScope</a> in your row template to access
    +elements in your controller's scope. More details are on
    +the <a href="/docs/#/tutorial/305_appScope">external scopes</a> tutorial.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-65" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-65" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-65">
    +  <div ng-controller="MainCtrl">
    +    <strong ng-bind="waiting"></strong> <strong>{{ wait }}</strong>
    +    <br>
    +    <div class="grid" ui-grid="gridOptions" ></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 300px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$timeout', '$interval', function ($scope, $http, $timeout, $interval) {
    +    var start = new Date();
    +    var sec = $interval(function () {
    +      var wait = parseInt(((new Date()) - start) / 1000, 10);
    +      $scope.wait = wait + 's';
    +    }, 1000);
    +
    +    function rowTemplate() {
    +      return $timeout(function() {
    +        $scope.waiting = 'Done!';
    +        $interval.cancel(sec);
    +        $scope.wait = '';
    +        return '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';
    +      }, 6000);
    +    }
    +
    +    // Access outside scope functions from row template
    +    $scope.fnOne =  function(row) {
    +        console.log(row);
    +     };
    +
    +    $scope.waiting = 'Waiting for row template...';
    +
    +    $http.get('/data/100.json')
    +      .success(function (data) {
    +        $scope.data = data;
    +      });
    +
    +    $scope.gridOptions = {
    +      rowTemplate: rowTemplate(),
    +      data: 'data'
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-65" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/301_editableOnFocus.html b/docs/partials/tutorial/301_editableOnFocus.html
    new file mode 100644
    index 000000000..90603b480
    --- /dev/null
    +++ b/docs/partials/tutorial/301_editableOnFocus.html
    @@ -0,0 +1,68 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Combine ui.grid.edit with ui.grid.cellNav, you can enable editing when the cell gets focus.
    +grid.options.enableCellEditOnFocus must be set to true.
    +<br/>
    +See api docs for default navigation keys and how you can override.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-66" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-66" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-66">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="getCurrentFocus()">Get Current focused cell</button>  <span ng-bind="currentFocused"></span>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit ui-grid-cellnav class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +    $scope.gridOptions.enableCellEditOnFocus = true;
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', enableCellEdit: false },
    +      { name: 'age', enableCellEditOnFocus:false, displayName:'age (f2/dblClick edit)', width: 200  },
    +      { name: 'address.city', enableCellEdit: true, width: 300 },
    +      { name: 'name', displayName: 'Name (editOnFocus)', width: 200}
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.currentFocused = "";
    +
    +      $scope.getCurrentFocus = function(){
    +        var rowCol = $scope.gridApi.cellNav.getFocusedCell();
    +        if(rowCol !== null) {
    +            $scope.currentFocused = 'Row Id:' + rowCol.row.entity.id + ' col:' + rowCol.col.colDef.name;
    +        }
    +      }
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +         $scope.gridApi = gridApi;
    +      };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-66" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/302_custom_header.html b/docs/partials/tutorial/302_custom_header.html
    new file mode 100644
    index 000000000..979c0353c
    --- /dev/null
    +++ b/docs/partials/tutorial/302_custom_header.html
    @@ -0,0 +1,48 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Create a grid almost the same as the most basic one, but with a custom header</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-67 header-template.html" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-67" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-67">
    +  <div ng-controller="MainCtrl">
    +    <div class="grid" ui-grid="gridOptions"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="header-template.html">
    +<pre class="prettyprint linenums" ng-set-text="header-template.html"></pre>
    +<script type="text/ng-template" id="header-template.html">
    +  <div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      headerTemplate: 'header-template.html',
    +      data: [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ]
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-67" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/303_customizing_column_menu.html b/docs/partials/tutorial/303_customizing_column_menu.html
    new file mode 100644
    index 000000000..14156b2ca
    --- /dev/null
    +++ b/docs/partials/tutorial/303_customizing_column_menu.html
    @@ -0,0 +1,180 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can customize a column's menu and provide your own functionality.  Each menu item can have:</p>
    +
    +<ul>
    +<li><code>shown</code>: a function that determines whether or not to display the item</li>
    +<li><code>title</code>: the title you'd like to have displayed for the menu item (note that you can also 
    +use i18n on this through the <code>gridMenuTitleFilter</code> setting)</li>
    +<li><code>icon</code>: an icon you'd like displayed alongside the item</li>
    +<li><code>action</code>: a function that will be called when the menu is clicked</li>
    +<li><code>active</code>: a function that highlights the item (giving a toggle type effect - see the sort on the column menus for an example)</li>
    +<li><code>context</code>: by default, the <code>action</code>, <code>shown</code> and <code>active</code>'s' contexts will have a reference to the grid added as the 
    +property <code>grid</code> (accessible through <code>this.grid</code>.  You can pass in your own context by supplying 
    +the <code>context</code> property to your menu item. It will be accessible through <code>this.context</code>.</li>
    +</ul>
    +
    +<p>The column menu will add the column's <code>GridColumn</code> object to the context as <code>this.context.col</code>. 
    +You can then show/hide the the menu item based on conditions that use the grid and column.  You could 
    +also use a custom column builder to add some item to the every column definition.</p>
    +
    +<p>You can remove the column hide option using the <code>enableHiding: false</code> columnDef option, which will also prevent
    +this column being hidden in the gridMenu (once it is finished and merged).  You can disable
    +the column menu entirely using the <code>enableColumnMenu: false</code> columnDef option.</p>
    +
    +<p>You can disable all column menus using the <code>enableColumnMenus: false</code> grid option.</p>
    +
    +<p>You can supply an icon class with the <code>icon</code> property.</p>
    +
    +<p>See the example below for usage.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-68" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-69"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-68" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-68">
    +  <div ng-controller="MainCtrl">
    +    Click on the third column header to test custom menu items.  The first column should have no
    +    column menu available, including via a long-press.  The second column should have a menu, but the
    +    ability to remove the sort is suppressed - the user can toggle between ASC and DESC but not remove
    +    the sort.
    +    <br>
    +    <br>
    +    <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
    +    $scope.blargh = function() {
    +      alert("I'm in the outer scope!");
    +    };
    +
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: [
    +        { field: 'name', enableColumnMenu: false },
    +        { field: 'gender', enableHiding: false, suppressRemoveSort: true, sort: { direction: uiGridConstants.ASC } },
    +        {
    +          field: 'company',
    +          menuItems: [
    +            {
    +              title: 'Outer Scope Alert',
    +              icon: 'ui-grid-icon-info-circled',
    +              action: function($event) {
    +                this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +              },
    +              context: $scope
    +            },
    +            {
    +              title: 'Grid ID',
    +              action: function() {
    +                alert('Grid ID: ' + this.grid.id);
    +              }
    +            },
    +            {
    +              title: 'Column Title Alert',
    +              shown: function () {
    +                return this.context.col.displayName === 'Company';
    +              },
    +              action: function() {
    +                alert(this.context.col.displayName);
    +              }
    +            }
    +          ]
    +        }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-69"></pre>
    +<script type="text/ng-template" id="scenario.js-69">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe('column menus', function() {
    +    it('grid1 should have three visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +    });
    +
    +    it('no column menu on first column, including from long press', function () {
    +      var headerCell = gridTestUtils.headerCell( 'grid1', 0 );
    +      expect( headerCell.all( by.css( '.ui-grid-column-menu-button' ) ).count()).toEqual(0);
    +      
    +      browser.actions()
    +        .mouseDown(headerCell, protractor.Button.LEFT)
    +        .perform();
    +      browser.sleep(550);  // 500ms for long press
    +      
    +      var columnMenu = element( by.id( 'grid1' ) ).element( by.css( '.ui-grid-column-menu' ) ).all( by.css( '.ui-grid-menu-inner' ));
    +      expect(columnMenu.count()).toEqual(0);
    +    });
    +
    +    it('2 menu items in second column, implying no hide option and no remove sort option', function () {
    +      gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 1, 2 );        
    +    });      
    +
    +    it('Long press opens menu in second column', function () {
    +      var headerCell = gridTestUtils.headerCell( 'grid1', 1 );
    +
    +      browser.actions()
    +        .mouseDown(headerCell, protractor.Button.LEFT)
    +        .perform();
    +      browser.sleep(550);  // 500ms for long press
    +      
    +      var columnMenu = element( by.id( 'grid1' ) ).element( by.css( '.ui-grid-column-menu' ) ).element( by.css( '.ui-grid-menu-inner' ));
    +      expect(columnMenu.isDisplayed()).toEqual(true, 'column menu should be displayed');
    +    });      
    +
    +    it('Column 2 rotates through sort ASC and sort DESC, but no sort null', function () {
    +      gridTestUtils.expectCellValueMatch( 'grid1', 0, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 1, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 3, 1, 'female' );
    +
    +      gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 0, 1, 'male' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 1, 1, 'male' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 1, 'male' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 3, 1, 'male' );
    +
    +      gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 0, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 1, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 2, 1, 'female' );
    +      gridTestUtils.expectCellValueMatch( 'grid1', 3, 1, 'female' );
    +    });      
    +
    +    it('6 visible items in the third column, implying hide option', function () {
    +      gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 2, 6 );        
    +    });
    +
    +    it('click header to sort third column, 7 visible items in the third column, implying remove sort option', function () {
    +      gridTestUtils.clickHeaderCell( 'grid1', 2 );
    +      gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 2, 7 );        
    +    });
    +  });
    +
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-68" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/304_custom_grid_menu.html b/docs/partials/tutorial/304_custom_grid_menu.html
    new file mode 100644
    index 000000000..a5d8853e7
    --- /dev/null
    +++ b/docs/partials/tutorial/304_custom_grid_menu.html
    @@ -0,0 +1,107 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-60" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-60" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-60">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-info" ng-click="openMyMenu()">Open Menu</button>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid">
    +      <div class="my-custom-menu" my-custom-menu ui-grid-menu menu-items="menuItems"></div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +
    +  .my-custom-menu {
    +    position: absolute;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu {
    +    padding: 0px;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu-inner {
    +    -webkit-box-shadow: none;
    +    box-shadow: none;
    +  }
    +
    +  .rotated {
    +    transform: rotate(180deg);
    +    -webkit-transform: rotate(180deg);
    +    -ms-transform: rotate(180deg);
    +    -moz-transform: rotate(180deg);
    +    -o-transform: rotate(180deg);
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {};
    +
    +    $scope.menuItems = [
    +      {
    +        title: 'Rotate Grid',
    +        action: function ($event) {
    +          this.grid.element.toggleClass('rotated');
    +        }
    +      }
    +    ];
    +
    +    $scope.openMyMenu = function () {
    +      $scope.$broadcast('openMyMenu');
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +
    +  app.directive('myCustomMenu', function ($timeout, gridUtil) {
    +    return {
    +      restrict: 'A',
    +      scope: true,
    +      require: ['^uiGrid', 'uiGridMenu'],
    +      link: function ($scope, $elm, $attr, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var uiGridMenuCtrl = controllers[1];
    +
    +        $scope.$on('openMyMenu', function () {
    +          uiGridMenuCtrl.showMenu();
    +
    +          $timeout(function () {
    +            var grid = uiGridCtrl.grid.element
    +            var width = gridUtil.elementWidth(grid, true);
    +
    +            // Put the menu just to the right of the grid
    +            $elm.css('left', width + 'px');
    +
    +            // Put the menu at the top of the grid but adjust for the border
    +            $elm.css('top', '-1px');
    +          });
    +        });
    +      }
    +    };
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-60" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/304_grid_menu.html b/docs/partials/tutorial/304_grid_menu.html
    new file mode 100644
    index 000000000..a4d144c99
    --- /dev/null
    +++ b/docs/partials/tutorial/304_grid_menu.html
    @@ -0,0 +1,166 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The grid menu can be enabled through setting the gridOption <code>enableGridMenu</code>.  This 
    +adds a settings icon in the top right of the grid, which floats above the column header.  The
    +menu by default gives access to show/hide columns, but can be customised to show additional
    +actions.  </p>
    +
    +<p>You can customize a the menu and provide your own functionality.  Each menu item can have:</p>
    +
    +<ul>
    +<li><code>shown</code>: a function that determines whether or not to display the item</li>
    +<li><code>title</code>: the title you'd like to have displayed for the menu item (note that you can also 
    +use i18n on this through the <code>gridMenuTitleFilter</code> setting)</li>
    +<li><code>icon</code>: an icon you'd like displayed alongside the item</li>
    +<li><code>action</code>: a function that will be called when the menu is clicked</li>
    +<li><code>active</code>: a function that highlights the item (giving a toggle type effect - see the sort on the column menus for an example)</li>
    +<li><code>context</code>: by default, the <code>action</code>, <code>shown</code> and <code>active</code>'s' contexts will have a reference to the grid added as the 
    +property <code>grid</code> (accessible through <code>this.grid</code>.  You can pass in your own context by supplying 
    +the <code>context</code> property to your menu item. It will be accessible through <code>this.context</code>.</li>
    +</ul>
    +
    +<p>The exporter feature also adds menu items to this menu.  The <code>exporterMenuCsv</code> option is set
    +to false, which suppresses csv export.  The 'export selected rows' option is only available
    +if at least one row is selected.</p>
    +
    +<p>The column titles can have a custom filter defined using <code>gridMenuTitleFilter</code>, used when your
    +column headers have an internationalization filter (angular translate or i18nService), and you
    +want them also internationalized in the grid menu.  The translate needs to return either a string,
    +or a promise that will resolve to a string.  In the example below we create a fake 
    +internationalization function that waits 1 second then prefixes each column with "col: ".</p>
    +
    +<p>You can suppress the ability to show and hide columns by setting the gridOption <code>gridMenuShowHideColumns: false</code>,
    +you can suppress the ability to hide individual columns by setting <code>enableHiding</code> on that columnDef to false.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-70" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-71"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-70" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-70">
    +  <div ng-controller="MainCtrl">
    +    <div id="grid1" ui-grid="gridOptions" ui-grid-exporter ui-grid-selection class="grid"></div>
    +    <div ng-if='columnChanged'>
    +      Column Visibility Changed - name: {{ columnChanged.name }} visible: {{ columnChanged.visible }}
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +
    +  .my-custom-menu {
    +    position: absolute;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu {
    +    padding: 0px;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu-inner {
    +    -webkit-box-shadow: none;
    +    box-shadow: none;
    +  }
    +
    +  .rotated {
    +    transform: rotate(180deg);
    +    -webkit-transform: rotate(180deg);
    +    -ms-transform: rotate(180deg);
    +    -moz-transform: rotate(180deg);
    +    -o-transform: rotate(180deg);
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.exporter', 'ui.grid.selection']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$interval', '$q', function ($scope, $http, $interval, $q) {
    +    var fakeI18n = function( title ){
    +      var deferred = $q.defer();
    +      $interval( function() {
    +        deferred.resolve( 'col: ' + title );
    +      }, 1000, 1);
    +      return deferred.promise;
    +    };
    +  
    +    $scope.gridOptions = {
    +      exporterMenuCsv: false,
    +      enableGridMenu: true,
    +      gridMenuTitleFilter: fakeI18n,
    +      columnDefs: [
    +        { name: 'name' },
    +        { name: 'gender', enableHiding: false },
    +        { name: 'company' }
    +      ],
    +      gridMenuCustomItems: [
    +        {
    +          title: 'Rotate Grid',
    +          action: function ($event) {
    +            this.grid.element.toggleClass('rotated');
    +          }
    +        }
    +      ],
    +      onRegisterApi: function( gridApi ){
    +        $scope.gridApi = gridApi;
    +        
    +        // interval of zero just to allow the directive to have initialized
    +        $interval( function() {
    +          gridApi.core.addToGridMenu( gridApi.grid, [{ title: 'Dynamic item'}]);
    +        }, 0, 1);
    +        
    +        gridApi.core.on.columnVisibilityChanged( $scope, function( changedColumn ){
    +          $scope.columnChanged = { name: changedColumn.colDef.name, visible: changedColumn.colDef.visible };
    +        });
    +      }
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-71"></pre>
    +<script type="text/ng-template" id="scenario.js-71">
    +  var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +  describe('grid menu', function() {
    +    it('grid1 should have three visible columns', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +    });
    +
    +    it('grid1 grid menu should have 8 items', function () {
    +      gridTestUtils.expectVisibleGridMenuItems( 'grid1', 7 );
    +    });
    +    
    +    it('grid1 hide then show company column', function () {
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +
    +      gridTestUtils.clickGridMenuItem( 'grid1', 11 );  // there are some hidden menu items, this is company_hide
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 2 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +
    +      gridTestUtils.clickGridMenuItem( 'grid1', 12 );  // there are some hidden menu items, this is company_show
    +      gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +      gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +    });
    +  });
    +
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-70" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/305_appScope.html b/docs/partials/tutorial/305_appScope.html
    new file mode 100644
    index 000000000..b737263f0
    --- /dev/null
    +++ b/docs/partials/tutorial/305_appScope.html
    @@ -0,0 +1,94 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid uses isolate scope, so there is no access to your application scope variables from a row or cell template.
    +By default, the parent scope of the ui-grid element is assigned to a property on $scope.grid named appScope.
    +<br/>
    +<br/>
    +If you need another reference other than $scope.$parent, then use gridOptions.appScopeProvider. This reference
    +will be assigned to grid.appScope.
    +<br/>
    +<br/>
    +$scope.grid.appScope is available in all templates that the grid uses.
    +<br/>
    +In a template, you access the scope using grid.appScope property
    +<pre class="prettyprint linenums">
    +    ng-click="grid.appScope.showMe()"
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-72" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-72" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-72">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$log', '$http', function ($scope, $log, $http) {
    +
    +
    +   $scope.someProp = 'abc',
    +   $scope.showMe = function(){
    +                     alert($scope.someProp);
    +                  };
    +
    +   $scope.gridOptions = {};
    +
    +   //you can override the default assignment if you wish
    +   //$scope.gridOptions.appScopeProvider = someOtherReference;
    +
    +     $scope.gridOptions.columnDefs = [
    +           { name: 'name' },
    +           { name: 'gender'},
    +           { name: 'ShowScope',
    +               cellTemplate:'<button class="btn primary" ng-click="grid.appScope.showMe()">Click Me</button>' }
    +         ];
    +   /*
    +   $scope.gridOptions.data = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      }
    +  ];
    +  */
    +
    +  $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions.data = data;
    +    });
    +
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-72" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/305_externalScopes.html b/docs/partials/tutorial/305_externalScopes.html
    new file mode 100644
    index 000000000..655244a98
    --- /dev/null
    +++ b/docs/partials/tutorial/305_externalScopes.html
    @@ -0,0 +1,91 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid uses isolate scope, so there is no access to your application scope variables from a row or cell template.</p>
    +
    +<p>To access your application data within UI-Grid, use the external-scopes attribute.  Give the attribute a
    +property that exists on your scope.
    +<pre class="prettyprint linenums">
    + $scope.myViewModel.showMe = function(){...};
    + &lt;div ui-grid="{ data: myData }" external-scopes="myViewModel" class="grid"&gt;&lt;/div&gt;
    +</pre>
    +
    +<p>Then in a template, you access the scope using getExternalScopes() function.
    +<pre class="prettyprint linenums">
    +    ng-click="getExternalScopes().showMe()"
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-72" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-72" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-72">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$log', '$http', function ($scope, $log, $http) {
    +
    +   $scope.myViewModel = {
    +      someProp:'abc',
    +      showMe : function(){
    +         alert(this.someProp);
    +      }
    +   };
    +
    +   $scope.gridOptions = {};
    +
    +     $scope.gridOptions.columnDefs = [
    +           { name: 'name' },
    +           { name: 'gender'},
    +           { name: 'ShowScope',
    +               cellTemplate:'<button class="btn primary" ng-click="getExternalScopes().showMe()">Click Me</button>' }
    +         ];
    +   /*
    +   $scope.gridOptions.data = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      }
    +  ];
    +  */
    +
    +  $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions.data = data;
    +    });
    +
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-72" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/306_expandable_grid.html b/docs/partials/tutorial/306_expandable_grid.html
    new file mode 100644
    index 000000000..c233ac8bb
    --- /dev/null
    +++ b/docs/partials/tutorial/306_expandable_grid.html
    @@ -0,0 +1,179 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Module 'ui.grid.expandable' adds the subgrid feature to grid. To show the subgrid you need to provide following grid option:</p>
    +
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions = {
    +    //This is the template that will be used to render subgrid.
    +    expandableRowTemplate: 'expandableRowTemplate.html',
    +    //This will be the height of the subgrid
    +    expandableRowHeight: 140,
    +    //Variables of object expandableScope will be available in the scope of the expanded subgrid
    +    expandableRowScope: expandableScope
    +  }
    +</pre>
    +
    +<p>rowExpandableTemplate will be template for subgrid and expandableRowHeight will be height of the subgrid, expandableRowScope can be used
    +to added variables to scope of expanded grid. These variables can then be access from expandableRowTemplate. The grid api
    +provided following events and methods fos subGrids:</p>
    +
    +<pre class="prettyprint linenums">
    +    //rowExpandedStateChanged is fired for each row as its expanded:
    +    gridApi.expandable.on.rowExpandedStateChanged($scope,function(row){
    +    });
    +    //Following methods can be used to expand/ collapse all rows of the grid:
    +    gridApi.expandable.expandAllRows();
    +    gridApi.expandable.collapseAllRows();
    +</pre>
    +
    +<p>SubGrid nesting can be done upto multiple levels.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-73 expandableRowTemplate.html" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-73" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-73">
    +  <div ng-controller="MainCtrl">
    +    <div class="control-group">
    +      <input type="button" class="btn btn-small" ng-click="expandAllRows()" value="Expand All"/>
    +      <input type="button" class="btn btn-small" ng-click="collapseAllRows()" value="Collapse All"/>
    +    </div>
    +    <div ui-grid="gridOptions" ui-grid-pinning ui-grid-expandable class="grid"></div>
    +  </div>
    +  Expandable rows works with checkboxes from selection and left pins
    +  <div ng-controller="SecondCtrl">
    +     <div ui-grid="gridOptions" ui-grid-pinning ui-grid-expandable ui-grid-selection class="grid"></div>
    +  </div>
    +  Retrieve data for subGrid when expanding
    +  <div ng-controller="ThirdCtrl">
    +     <div ui-grid="gridOptions" ui-grid-expandable class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="expandableRowTemplate.html">
    +<pre class="prettyprint linenums" ng-set-text="expandableRowTemplate.html"></pre>
    +<script type="text/ng-template" id="expandableRowTemplate.html">
    +  <div ui-grid="row.entity.subGridOptions" style="height:140px;"></div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 100%;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.expandable', 'ui.grid.selection', 'ui.grid.pinning']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {
    +      expandableRowTemplate: 'expandableRowTemplate.html',
    +      expandableRowHeight: 150,
    +      //subGridVariable will be available in subGrid scope
    +      expandableRowScope: {
    +        subGridVariable: 'subGridScopeVariable'
    +      }
    +    }
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id' },
    +      { name: 'name'},
    +      { name: 'age'},
    +      { name: 'address.city'}
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        for(i = 0; i < data.length; i++){
    +          data[i].subGridOptions = {
    +            columnDefs: [ {name:"Id", field:"id"},{name:"Name", field:"name"} ],
    +            data: data[i].friends
    +          }
    +        }
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +        $scope.gridApi = gridApi;
    +      };
    +
    +      $scope.expandAllRows = function() {
    +        $scope.gridApi.expandable.expandAllRows();
    +      }
    +
    +      $scope.collapseAllRows = function() {
    +        $scope.gridApi.expandable.collapseAllRows();
    +      }
    +  }]);
    +
    +  app.controller('SecondCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +        $scope.gridOptions = {
    +          enableRowSelection: true,
    +          expandableRowTemplate: 'expandableRowTemplate.html',
    +          expandableRowHeight: 150
    +        }
    +
    +        $scope.gridOptions.columnDefs = [
    +          { name: 'id', pinnedLeft:true },
    +          { name: 'name'},
    +          { name: 'age'},
    +          { name: 'address.city'}
    +        ];
    +
    +        $http.get('/data/500_complex.json')
    +          .success(function(data) {
    +            for(i = 0; i < data.length; i++){
    +              data[i].subGridOptions = {
    +                columnDefs: [ {name:"Id", field:"id"},{name:"Name", field:"name"} ],
    +                data: data[i].friends
    +              }
    +            }
    +            $scope.gridOptions.data = data;
    +          });
    +      }]);
    +      
    +  app.controller('ThirdCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +        $scope.gridOptions = {
    +          expandableRowTemplate: 'expandableRowTemplate.html',
    +          expandableRowHeight: 150,
    +          onRegisterApi: function (gridApi) {
    +              gridApi.expandable.on.rowExpandedStateChanged($scope, function (row) {
    +                  if (row.isExpanded) {
    +                    row.entity.subGridOptions = {
    +                      columnDefs: [
    +                      { name: 'name'},
    +                      { name: 'gender'},
    +                      { name: 'company'}
    +                    ]};
    +                  
    +                    $http.get('/data/100.json')
    +                      .success(function(data) {
    +                        row.entity.subGridOptions.data = data;
    +                      });
    +                  }
    +              });
    +          }
    +        }
    +
    +        $scope.gridOptions.columnDefs = [
    +          { name: 'id', pinnedLeft:true },
    +          { name: 'name'},
    +          { name: 'age'},
    +          { name: 'address.city'}
    +        ];
    +
    +        $http.get('/data/500_complex.json')
    +          .success(function(data) {
    +            $scope.gridOptions.data = data;
    +          });
    +      }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-73" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/306_exporting_data_complex.html b/docs/partials/tutorial/306_exporting_data_complex.html
    new file mode 100644
    index 000000000..f58865b91
    --- /dev/null
    +++ b/docs/partials/tutorial/306_exporting_data_complex.html
    @@ -0,0 +1,102 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The exporter feature allows data to be exported from the grid in 
    +csv or pdf format.  The exporter can export all data, visible data or selected data.</p>
    +
    +<p>To use the exporter you need to include the ui-grid-exporter directive on
    +your grid.  If you want to export selected rows you must include the ui-grid-selection
    +directive on your grid.  If you want to export as PDF you need to have installed pdfMake, 
    +available through:
    +<pre class="prettyprint linenums">  bower install pdfmake  </pre>
    +
    +<p>The options and API for exporter can be found at <a href="#/api/ui.grid.exporter">ui.grid.exporter</a>.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we provide a custom UI for calling the exporter, and we tailor
    +the way the returned data behaves.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-67" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-67" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-67">
    +    <div ng-controller="MainCtrl">
    +      <label>Which columns should we export?</label>
    +      <select ng-model="export_column_type"</select>
    +        <option value='all'>All</option>
    +        <option value='visible'>Visible</option>
    +      </select>
    +      <label>Which rows should we export?</label>
    +      <select ng-model="export_row_type"</select>
    +        <option value='all'>All</option>
    +        <option value='visible'>Visible</option>
    +        <option value='selected'>Selected</option>
    +      </select>
    +      <label>What format would you like?</label>
    +      <select ng-model="export_format"</select>
    +        <option value='csv'>CSV</option>
    +        <option value='pdf'>PDF</option>
    +      </select>
    +      <button ng-click="export()">Export</button>
    +      <div class="custom-csv-link-location">
    +        <label>Your CSV will show below:</label>
    +        <span class="ui-grid-exporter-csv-link">&nbsp</span>
    +      </div>
    +      
    +      <div ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ui.grid', 'ui.grid.selection', 'ui.grid.exporter']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          { field: 'name' },
    +          { field: 'gender', visible: false},
    +          { field: 'company' }
    +        ],
    +        exporterLinkLabel: 'get your csv here',
    +        exporterPdfDefaultStyle: {fontSize: 9},
    +        exporterPdfTableStyle: {margin: [30, 30, 30, 30]},
    +        exporterPdfTableHeaderStyle: {fontSize: 10, bold: true, italics: true, color: 'red'},
    +        exporterPdfOrientation: 'portrait',
    +        exporterPdfPageSize: 'LETTER',
    +        exporterPdfMaxGridWidth: 500,
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +        }
    +      };
    +      
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +        
    +      
    +        
    +      $scope.export = function(){
    +        if ($scope.export_format == 'csv') {
    +          var myElement = angular.element(document.querySelectorAll(".custom-csv-link-location"));
    +          $scope.gridApi.exporter.csvExport( $scope.export_row_type, $scope.export_column_type, myElement );
    +        } else if ($scope.export_format == 'pdf') {
    +          $scope.gridApi.exporter.pdfExport( $scope.export_row_type, $scope.export_column_type );
    +        };
    +      };
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-67" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/307_external_sorting.html b/docs/partials/tutorial/307_external_sorting.html
    new file mode 100644
    index 000000000..a54b30dad
    --- /dev/null
    +++ b/docs/partials/tutorial/307_external_sorting.html
    @@ -0,0 +1,157 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Sometimes you want to sort data externally, either on the client using custom sort routines (that are over and
    +above those you can achieve with <a href="#/tutorial/xxxxxx">custom sort functions</a>, or on the server as part of
    +your data retrieve.</p>
    +
    +<p>UI-Grid provides two functions that support this, firstly a sortChanged event that tells you when a user has
    +changed their requested sort using the grid ui, and secondly a useExternalSorting property to turn off
    +the grid native sorting.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we suppress the internal sorting, and emulate an external sort by picking one of three 
    +json files to show - one sorted ASC, one sorted DESC, and one not sorted.  To further illustrate that this
    +is using external sorting, the external sort routine (consisting of me manually editing json files) got bored
    +of sorting after the first 10 or so rows.</p>
    +
    +<p>We allow sorting by the first and second columns, so that we can show a default sort and that default sort
    +indicator being removed even when using external sorting.  Our external sort routine ignores that second
    +column however, so sorting by it has no effect. </p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-74" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-75"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-74" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-74">
    +    <div ng-controller="MainCtrl">
    +      <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 250px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', 'uiGridConstants', function ($scope, $http, $interval, uiGridConstants) {
    +
    +      $scope.gridOptions = {
    +        useExternalSorting: true,
    +        columnDefs: [
    +          { name: 'name' },
    +          { name: 'gender', sort: {
    +              direction: uiGridConstants.DESC,
    +              priority: 1
    +            }
    +          },
    +          { name: 'company', enableSorting: false}
    +        ],
    +        onRegisterApi: function( gridApi ) {
    +          $scope.gridApi = gridApi;
    +          $scope.gridApi.core.on.sortChanged( $scope, function( grid, sortColumns ) {
    +            if( sortColumns.length === 0 || sortColumns[0].name !== $scope.gridOptions.columnDefs[0].name ){
    +              $http.get('/data/100.json')
    +              .success(function(data) {
    +                $scope.gridOptions.data = data;
    +              });
    +            } else {
    +              switch( sortColumns[0].sort.direction ) {
    +                case uiGridConstants.ASC:
    +                  $http.get('/data/100_ASC.json')
    +                  .success(function(data) {
    +                    $scope.gridOptions.data = data;
    +                  });
    +                  break;
    +                case uiGridConstants.DESC:
    +                  $http.get('/data/100_DESC.json')
    +                  .success(function(data) {
    +                    $scope.gridOptions.data = data;
    +                  });
    +                  break;
    +                case undefined:
    +                  $http.get('/data/100.json')
    +                  .success(function(data) {
    +                    $scope.gridOptions.data = data;
    +                  });
    +                  break;
    +              }
    +            }
    +          });
    +        }
    +      };
    +      
    +      $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +      
    +    }]);
    +  </script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-75"></pre>
    +<script type="text/ng-template" id="scenario.js-75">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +    
    +    describe('307 tutorial', function() {
    +      it('grid should have three visible columns', function () {
    +        gridTestUtils.expectHeaderColumnCount( 'grid1', 3 );
    +      });
    +  
    +      it('header values should be as expected', function () {
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 0, 'Name' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 1, 'Gender' );
    +        gridTestUtils.expectHeaderCellValueMatch( 'grid1', 2, 'Company' );
    +      });
    +  
    +      it('grid should be unsorted by default', function () {
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +
    +      it('sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Beryl Rice' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Bruce Strong' );
    +      });
    +
    +      it('reverse sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Wilder Gonzales' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Valarie Atkinson' );
    +      });
    +      
    +      it('return to original sort by name by clicking header', function () {
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.clickHeaderCell( 'grid1', 0 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +      
    +      it('sort ignored on second column', function() {
    +        gridTestUtils.clickHeaderCell( 'grid1', 1 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +
    +      it('sort disabled on last column', function() {
    +        gridTestUtils.clickHeaderCell( 'grid1', 2 );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 0, 0, 'Ethel Price' );
    +        gridTestUtils.expectCellValueMatch( 'grid1', 1, 0, 'Claudine Neal' );
    +      });
    +    });
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-74" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/308_external_filtering.html b/docs/partials/tutorial/308_external_filtering.html
    new file mode 100644
    index 000000000..acb03c3ff
    --- /dev/null
    +++ b/docs/partials/tutorial/308_external_filtering.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Sometimes you want to filter data externally, either on the client using custom filter routines, or on 
    +the server as part of your data retrieve.</p>
    +
    +<p>UI-Grid provides two functions that support this, firstly a filterChanged event that tells you when a user has
    +changed their requested filter using the grid ui, and secondly a useExternalFiltering property to turn off
    +the grid native filtering.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we suppress the internal filtering, and emulate an external filter by picking one of three 
    +json files to show - one filtered by gender 'male', one filtered by gender 'female', and one not sorted.  </p>
    +
    +<p>To further illustrate that this is using external sorting, the external filter routine (consisting of me manually 
    +editing json files) got bored of filtering after the first 10 or so rows, and deleted all other rows in the file.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-76" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-76" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-76">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 250px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', 'uiGridConstants', function ($scope, $http, $interval, uiGridConstants) {
    +
    +      $scope.gridOptions = {
    +        enableFiltering: true,
    +        useExternalFiltering: true,
    +        columnDefs: [
    +          { name: 'name', enableFiltering: false },
    +          { name: 'gender' },
    +          { name: 'company', enableFiltering: false}
    +        ],
    +        onRegisterApi: function( gridApi ) {
    +          $scope.gridApi = gridApi;
    +            $scope.gridApi.core.on.filterChanged( $scope, function() {
    +              var grid = this.grid;
    +              if( grid.columns[1].filters[0].term === 'male' ) {
    +                $http.get('/data/100_male.json')
    +                .success(function(data) {
    +                  $scope.gridOptions.data = data;
    +                });
    +              } else if ( grid.columns[1].filters[0].term === 'female' ) {
    +                $http.get('/data/100_female.json')
    +                .success(function(data) {
    +                  $scope.gridOptions.data = data;
    +                });
    +              } else {
    +                $http.get('/data/100.json')
    +                .success(function(data) {
    +                  $scope.gridOptions.data = data;
    +                });
    +              }
    +            });
    +        }
    +      };
    +      
    +      $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +      
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-76" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/309_editable_with_cellnav.html b/docs/partials/tutorial/309_editable_with_cellnav.html
    new file mode 100644
    index 000000000..c7e8b95c9
    --- /dev/null
    +++ b/docs/partials/tutorial/309_editable_with_cellnav.html
    @@ -0,0 +1,104 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>For the basics of editing refer <a href="#/tutorial/201_editable">201 editable</a>, this tutorial provides an example
    +of combining cellNav and edit to give a more spreadsheet-like experience.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-77" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-77" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-77">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <strong>Last Cell Edited:</strong> {{msg.lastCellEdited}}
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit ui-grid-cellNav class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit', 'ui.grid.cellNav', 'addressFormatter']);
    +
    +  angular.module('addressFormatter', []).filter('address', function () {
    +    return function (input) {
    +        return input.street + ', ' + input.city + ', ' + input.state + ', ' + input.zip;
    +    };
    +  });
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = { enableCellEditOnFocus: true };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', enableCellEdit: false, width: '10%' },
    +      { name: 'name', displayName: 'Name (editable)', width: '20%' },
    +      { name: 'age', displayName: 'Age' , type: 'number', width: '10%' },
    +      { name: 'gender', displayName: 'Gender', editType: 'dropdown', width: '20%', 
    +        cellFilter: 'mapGender', editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
    +        { id: 1, gender: 'male' }, 
    +        { id: 2, gender: 'female' } 
    +      ] }, 
    +      { name: 'registered', displayName: 'Registered' , type: 'date', cellFilter: 'date:"yyyy-MM-dd"', width: '20%' },
    +      { name: 'address', displayName: 'Address', type: 'object', cellFilter: 'address', width: '30%' },
    +      { name: 'address.city', displayName: 'Address (even rows editable)', width: '20%',
    +           cellEditableCondition: function($scope){
    +           return $scope.rowRenderIndex%2
    +           }
    +      },
    +      { name: 'isActive', displayName: 'Active', type: 'boolean', width: '10%' }
    +    ];
    +
    +
    +
    +   $scope.msg = {};
    +
    +   $scope.gridOptions.onRegisterApi = function(gridApi){
    +            //set gridApi on scope
    +            $scope.gridApi = gridApi;
    +            gridApi.edit.on.afterCellEdit($scope,function(rowEntity, colDef, newValue, oldValue){
    +              $scope.msg.lastCellEdited = 'edited row id:' + rowEntity.id + ' Column:' + colDef.name + ' newValue:' + newValue + ' oldValue:' + oldValue ;
    +              $scope.$apply();
    +            });
    +          };
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        for(i = 0; i < data.length; i++){
    +          data[i].registered = new Date(data[i].registered);
    +          data[i].gender = data[i].gender==='male' ? 1 : 2;
    +        }
    +        $scope.gridOptions.data = data;
    +      });
    +  }])
    +
    +  .filter('mapGender', function() {
    +    var genderHash = {
    +      1: 'male',
    +      2: 'female'
    +    };
    +    
    +    return function(input) {
    +      if (!input){
    +        return '';
    +      } else {
    +        return genderHash[input];
    +      }
    +    };
    +  })
    +});
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-77" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/310_column_moving.html b/docs/partials/tutorial/310_column_moving.html
    new file mode 100644
    index 000000000..23ee63a20
    --- /dev/null
    +++ b/docs/partials/tutorial/310_column_moving.html
    @@ -0,0 +1,58 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Feature ui.grid.moveColumns allows moving column to a different position. To enable, you must include the <code>ui.grid.moveColumns</code> module
    +and you must include the <code>ui-grid-move-columns</code> directive on your grid element.</p>
    +
    +<p>By default column moving will be enabled for all the columns of the grid. To disable it for all columns of grid property <code>enableColumnMoving</code>
    +of grid options can be used. To specifically enable or disable column moving for a specific column property <code>enableColumnMoving</code>
    +of column definitions can be used.</p>
    +
    +<p>Columns can be repositioned by either dragging and dropping them to specific position. Alternatively, gridApi method
    +<code>gridApi.colMovable.moveColumn(oldPosition, newPosition)</code> can also be used to move columns. The column position ranging from 0
    +(in the leftmost) up to number of visible columns in the grid (in the rightmost).</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-78" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-78" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-78">
    +  <div ng-controller="MainCtrl">
    +  <div class="grid" ui-grid="gridOptions" ui-grid-move-columns></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 100%;
    +    height: 400;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.moveColumns']);
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +    };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id'},
    +      { name: 'name'},
    +      { name: 'age'},
    +      { name: 'gender'},
    +      { name: 'email'},
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-78" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/310_column_moving_grid.html b/docs/partials/tutorial/310_column_moving_grid.html
    new file mode 100644
    index 000000000..c59079547
    --- /dev/null
    +++ b/docs/partials/tutorial/310_column_moving_grid.html
    @@ -0,0 +1,57 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Feature ui.grid.moveColumns allows moving column to a different position. To enable, you must include the <code>ui.grid.moveColumns</code> module
    +and you must include the <code>ui-grid-move-columns</code> directive on your grid element.</p>
    +
    +<p>By default column moving will be enabled for all the columns of the grid. To disable it for all columns of grid property <code>enableColumnMoving</code>
    +of grid options can be used. To specifically enable or disable column moving for a specific column property <code>enableColumnMoving</code>
    +of column definitions can be used.</p>
    +
    +<p>Columns can be repositioned by either dragging and dropping them to specific position or by using this gridApi method
    +<code>gridApi.colMovable.moveColumn(oldPosition, newPosition)</code>.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-71" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-71" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-71">
    +  <div ng-controller="MainCtrl">
    +  <div class="grid" ui-grid="gridOptions" ui-grid-move-columns></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 100%;
    +    height: 400;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +    };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id'},
    +      { name: 'name'},
    +      { name: 'age'},
    +      { name: 'gender'},
    +      { name: 'email'},
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-71" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/310_importing_data_with_rowedit.html b/docs/partials/tutorial/310_importing_data_with_rowedit.html
    new file mode 100644
    index 000000000..aba44c8f0
    --- /dev/null
    +++ b/docs/partials/tutorial/310_importing_data_with_rowedit.html
    @@ -0,0 +1,83 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The importer feature allows data to be imported into the grid in 
    +csv or json format.  The importer can use the native grid menu, or can accept a 
    +file from a custom file picker implemented by the user.</p>
    +
    +<p>The importer can work together with the rowEdit feature to automatically save the
    +imported rows to your server, and show validation errors for any rows that were
    +not accepted by the server.</p>
    +
    +<p>If you want to allow the user to look at the data before the saves kick off, consider
    +setting the rowEditWaitInterval to -1, which will suppress the auto-save, and require
    +you to manually call flushDirtyRows() once the user has made a save request.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we use the rowEdit feature to save the rows as they are created.
    +As with the rowEdit tutorial, any records with a gender of 'male' give an error,
    +and can be edited to save without error.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-72" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-72" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-72">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-importer class="grid" ui-grid-edit ui-grid-row-edit></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ui.grid', 'ui.grid.importer', 'ui.grid.rowEdit', 'ui.grid.edit']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', '$q', function ($scope, $http, $interval, $q) {
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +          gridApi.rowEdit.on.saveRow($scope, $scope.saveRow);
    +        }
    +      };
    +
    +      $scope.saveRow = function( rowEntity ) {
    +        // create a fake promise - normally you'd use the promise returned by $http or $resource
    +        var promise = $q.defer();
    +        $scope.gridApi.rowEdit.setSavePromise( $scope.gridApi.grid, rowEntity, promise.promise );
    +       
    +        // fake a delay of 3 seconds whilst the save occurs, return error if gender is "male"
    +        $interval( function() {
    +          if (rowEntity.Gender === 'male' ){
    +            promise.reject();
    +          } else {
    +            promise.resolve();
    +          }
    +        }, 3000, 1);
    +      }; 
    +
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-72" ng-eval-javascript="app.js"></div>
    +import.json:
    +<pre class="prettyprint linenums">
    +[{"name":"John Smith","gender":"male","company":"TestIcon"},{"name":"Jane Doe","gender":"female","company":"FastTruck"}]
    +</pre>
    +
    +<p>import.csv
    +<pre class="prettyprint linenums">
    +"Name","Gender","Company"
    +"John Smith","male","TestIcon"
    +"Jane Doe","female","FastTrucks"
    +</pre></div>
    +</div>
    diff --git a/docs/partials/tutorial/311_importing_data_with_rowedit.html b/docs/partials/tutorial/311_importing_data_with_rowedit.html
    new file mode 100644
    index 000000000..276d0e829
    --- /dev/null
    +++ b/docs/partials/tutorial/311_importing_data_with_rowedit.html
    @@ -0,0 +1,109 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The importer feature allows data to be imported into the grid in 
    +csv or json format.  The importer can use the native grid menu, or can accept a 
    +file from a custom file picker implemented by the user.</p>
    +
    +<p>The importer can work together with the rowEdit feature to automatically save the
    +imported rows to your server, and show validation errors for any rows that were
    +not accepted by the server.</p>
    +
    +<p>If you want to allow the user to look at the data before the saves kick off, consider
    +setting the rowEditWaitInterval to -1, which will suppress the auto-save, and require
    +you to manually call flushDirtyRows() once the user has made a save request.</p>
    +
    +<p>In this example we also use a custom file picker to trigger the import, as well
    +as the grid menu.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we use the rowEdit feature to save the rows as they are created.
    +As with the rowEdit tutorial, any records with a gender of 'male' give an error,
    +and can be edited to save without error.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-79" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-79" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-79">
    +    <div ng-controller="MainCtrl">
    +      <form><input type="file" class="file-chooser" id="files" name="files[]" /></form>
    +      <div ui-grid="gridOptions" ui-grid-importer class="grid" ui-grid-edit ui-grid-row-edit></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.importer', 'ui.grid.rowEdit', 'ui.grid.edit']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interval', '$q', function ($scope, $http, $interval, $q) {
    +      $scope.data = [];
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        importerDataAddCallback: function( grid, newObjects ) {
    +          $scope.data = $scope.data.concat( newObjects );
    +        },
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +          gridApi.rowEdit.on.saveRow($scope, $scope.saveRow);
    +        },
    +        data: 'data'
    +      };
    +
    +      $scope.saveRow = function( rowEntity ) {
    +        // create a fake promise - normally you'd use the promise returned by $http or $resource
    +        var promise = $q.defer();
    +        $scope.gridApi.rowEdit.setSavePromise( rowEntity, promise.promise );
    +       
    +        // fake a delay of 3 seconds whilst the save occurs, return error if gender is "male"
    +        $interval( function() {
    +          if (rowEntity.Gender === 'male' ){
    +            promise.reject();
    +          } else {
    +            promise.resolve();
    +          }
    +        }, 3000, 1);
    +      };
    +      
    +      var handleFileSelect = function( event ){
    +        var target = event.srcElement || event.target;
    +        
    +        if (target && target.files && target.files.length === 1) {
    +          var fileObject = target.files[0];
    +          $scope.gridApi.importer.importFile( fileObject );
    +          target.form.reset();
    +        }
    +      };
    +
    +      var fileChooser = document.querySelectorAll('.file-chooser');
    +      
    +      if ( fileChooser.length !== 1 ){
    +        console.log('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +      } else {
    +        fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +      }
    +    }]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-79" ng-eval-javascript="app.js"></div>
    +import.json:
    +<pre class="prettyprint linenums">
    +[{"name":"John Smith","gender":"male","company":"TestIcon"},{"name":"Jane Doe","gender":"female","company":"FastTruck"}]
    +</pre>
    +
    +<p>import.csv
    +<pre class="prettyprint linenums">
    +"Name","Gender","Company"
    +"John Smith","male","TestIcon"
    +"Jane Doe","female","FastTrucks"
    +</pre></div>
    +</div>
    diff --git a/docs/partials/tutorial/312_exporting_data_complex.html b/docs/partials/tutorial/312_exporting_data_complex.html
    new file mode 100644
    index 000000000..3a5af8cbb
    --- /dev/null
    +++ b/docs/partials/tutorial/312_exporting_data_complex.html
    @@ -0,0 +1,154 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The exporter feature allows data to be exported from the grid in 
    +csv or pdf format.  The exporter can export all data, visible data or selected data.</p>
    +
    +<p>To use the exporter you need to include the ui-grid-exporter directive on
    +your grid.  If you want to export selected rows you must include the ui-grid-selection
    +directive on your grid.  If you want to export as PDF you need to have installed pdfMake, 
    +available through:
    +<pre class="prettyprint linenums">  bower install pdfmake  </pre>
    +
    +<p>The options and API for exporter can be found at <a href="#/api/ui.grid.exporter">ui.grid.exporter</a>.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>In this example we provide a custom UI for calling the exporter, and we tailor
    +the pdf layout to have different styles than the default.</p>
    +
    +<p>We also apply a filter to the headers (simulating internationalisation), and we reprocess the grid
    +data to apply a filter to decode coded data.</p>
    +
    +<p>We also right align the gender column.</p>
    +
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-80" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-80" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-80">
    +    <div ng-controller="MainCtrl">
    +      <label>Which columns should we export?</label>
    +      <select ng-model="export_column_type"</select>
    +        <option value='all'>All</option>
    +        <option value='visible'>Visible</option>
    +      </select>
    +      <label>Which rows should we export?</label>
    +      <select ng-model="export_row_type"</select>
    +        <option value='all'>All</option>
    +        <option value='visible'>Visible</option>
    +        <option value='selected'>Selected</option>
    +      </select>
    +      <label>What format would you like?</label>
    +      <select ng-model="export_format"</select>
    +        <option value='csv'>CSV</option>
    +        <option value='pdf'>PDF</option>
    +      </select>
    +      <button ng-click="export()">Export</button>
    +      <div class="custom-csv-link-location">
    +        <label>Your CSV will show below:</label>
    +        <span class="ui-grid-exporter-csv-link">&nbsp</span>
    +      </div>
    +      
    +      <div ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 400px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.exporter']);
    +
    +    app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          { field: 'name' },
    +          { field: 'gender', cellFilter: 'mapGender', exporterPdfAlign: 'right' },
    +          { field: 'company', visible: false }
    +        ],
    +        exporterLinkLabel: 'get your csv here',
    +        exporterPdfDefaultStyle: {fontSize: 9},
    +        exporterPdfTableStyle: {margin: [30, 30, 30, 30]},
    +        exporterPdfTableHeaderStyle: {fontSize: 10, bold: true, italics: true, color: 'red'},
    +        exporterPdfOrientation: 'portrait',
    +        exporterPdfPageSize: 'LETTER',
    +        exporterPdfMaxGridWidth: 500,
    +        exporterHeaderFilter: function( displayName ) { 
    +          if( displayName === 'Name' ) { 
    +            return 'Person Name'; 
    +          } else { 
    +            return displayName;
    +          } 
    +        },
    +        exporterFieldCallback: function( grid, row, col, input ) {
    +          if( col.name == 'gender' ){
    +            switch( input ){
    +              case 1:
    +                return 'female';
    +                break;
    +              case 2:
    +                return 'male';
    +                break;
    +              default:
    +                return 'unknown';
    +                break;
    +            }
    +          } else {
    +            return input;
    +          }
    +        },
    +        onRegisterApi: function(gridApi){ 
    +          $scope.gridApi = gridApi;
    +        }
    +      };
    +      
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          angular.forEach( data, function( row, index ) {
    +            if( row.gender === 'female' ){
    +              row.gender = 1;
    +            } else {
    +              row.gender = 2;
    +            }
    +          });
    +          $scope.gridOptions.data = data;
    +        });
    +        
    +      
    +        
    +      $scope.export = function(){
    +        if ($scope.export_format == 'csv') {
    +          var myElement = angular.element(document.querySelectorAll(".custom-csv-link-location"));
    +          $scope.gridApi.exporter.csvExport( $scope.export_row_type, $scope.export_column_type, myElement );
    +        } else if ($scope.export_format == 'pdf') {
    +          $scope.gridApi.exporter.pdfExport( $scope.export_row_type, $scope.export_column_type );
    +        };
    +      };
    +    }])
    +    
    +    .filter('mapGender', function() {
    +      return function( input ) {
    +        switch( input ){
    +          case 1:
    +            return 'female';
    +            break;
    +          case 2:
    +            return 'male';
    +            break;
    +          default:
    +            return 'unknown';
    +            break;
    +        }
    +      };
    +    });
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-80" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/313_custom_interpolation_symbols.html b/docs/partials/tutorial/313_custom_interpolation_symbols.html
    new file mode 100644
    index 000000000..c37b57310
    --- /dev/null
    +++ b/docs/partials/tutorial/313_custom_interpolation_symbols.html
    @@ -0,0 +1,64 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Combining AngularJS with other frameworks/tools sometimes requires changing the normal interpolation symbols (<code>{{</code> and <code>}}</code>) to something else, like <code>[[</code> or <code>%</code>.
    +<br>
    +<br>
    +UI Grid will automatically detect the change and transform any default symbols in the templates it uses to the custom values. This means that in the unlikely event
    +you're expecting to use <code>{{</code> or <code>}}</code> to signify something in your custom-interpolation-symbol application, then inside the grid your stuff will likely break.</p>
    +
    +<h3>Source</h3>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-81" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-81" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-81">
    +    <div ng-controller="MainCtrl">
    +      This app uses [[ startSym ]] and [[ endSym ]] for interpolation symbols: [[ foo ]]
    +      <br>
    +      <br>
    +      <div ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 500px;
    +      height: 300px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);
    +
    +    app.config(function($interpolateProvider) {
    +        $interpolateProvider.startSymbol('[[');
    +        $interpolateProvider.endSymbol(']]');
    +    });
    +
    +    app.controller('MainCtrl', ['$scope', '$http', '$interpolate', function ($scope, $http, $interpolate) {
    +      $scope.foo = 'whoohoo!';
    +      $scope.startSym = $interpolate.startSymbol();
    +      $scope.endSym = $interpolate.endSymbol();
    +
    +      $scope.gridOptions = {
    +        enableSorting: true,
    +        columnDefs: [
    +          { field: 'name' },
    +          { field: 'gender' },
    +          { field: 'company', enableSorting: false }
    +        ]
    +      };
    +
    +      $http.get('/data/100.json')
    +        .success(function(data) {
    +          $scope.gridOptions.data = data;
    +        });
    +    }]);
    +  </script>
    +</div>
    +</div><h3>Demo</h3>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-81" ng-eval-javascript="app.js"></div></div>
    diff --git a/docs/partials/tutorial/314_external_pagination.html b/docs/partials/tutorial/314_external_pagination.html
    new file mode 100644
    index 000000000..bb3b6c9cb
    --- /dev/null
    +++ b/docs/partials/tutorial/314_external_pagination.html
    @@ -0,0 +1,108 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>When pagination is enabled, the data is displayed in pages that can be browsed using using the built in 
    +pagination selector.</p>
    +
    +<p>For external pagination, implement the <code>gridApi.pagination.on.paginationChanged</code> callback function. The callback 
    +may contain code to update any pagination state variables your application may utilize, e.g. variables containing 
    +the <code>pageNumber</code> and <code>pageSize</code>. The REST call used to fetch the data from the server should be called from within 
    +this callback. The URL of the call should contain query parameters that will allow the server-side code to have 
    +sufficient information to be able to retrieve the specific subset of data that the client requires from the 
    +entire set.</p>
    +
    +<p>It should also update the <code>$scope.gridOptions.totalItems</code> variable with the total count of rows that exist (but 
    +were not all fetched in the REST call mentioned above since they exist in other pages of data).</p>
    +
    +<p>This will allow ui-grid to calculate the correct number of pages on the client-side.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>This shows combined external pagination and sorting.
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-82" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-82" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-82">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-pagination class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 600px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.pagination']);
    +
    +    app.controller('MainCtrl', [
    +    '$scope', '$http', 'uiGridConstants', function($scope, $http, uiGridConstants) {
    +
    +      var paginationOptions = {
    +        pageNumber: 1,
    +        pageSize: 25,
    +        sort: null
    +      };
    +
    +      $scope.gridOptions = {
    +        paginationPageSizes: [25, 50, 75],
    +        paginationPageSize: 25,
    +        useExternalPagination: true,
    +        useExternalSorting: true,
    +        columnDefs: [
    +          { name: 'name' },
    +          { name: 'gender', enableSorting: false },
    +          { name: 'company', enableSorting: false }
    +        ],
    +        onRegisterApi: function(gridApi) {
    +          $scope.gridApi = gridApi;
    +          $scope.gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
    +            if (sortColumns.length == 0) {
    +              paginationOptions.sort = null;
    +            } else {
    +              paginationOptions.sort = sortColumns[0].sort.direction;
    +            }
    +            getPage();
    +          });
    +          gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) {
    +            paginationOptions.pageNumber = newPage;
    +            paginationOptions.pageSize = pageSize;
    +            getPage();
    +          });
    +        }
    +      };
    +
    +      var getPage = function() {
    +        var url;
    +        switch(paginationOptions.sort) {
    +          case uiGridConstants.ASC:
    +            url = '/data/100_ASC.json';
    +            break;
    +          case uiGridConstants.DESC:
    +            url = '/data/100_DESC.json';
    +            break;
    +          default:
    +            url = '/data/100.json';
    +            break;
    +        }
    +
    +        $http.get(url)
    +        .success(function (data) {
    +          $scope.gridOptions.totalItems = 100;
    +          var firstRow = (paginationOptions.pageNumber - 1) * paginationOptions.pageSize;
    +          $scope.gridOptions.data = data.slice(firstRow, firstRow + paginationOptions.pageSize);
    +        });
    +      };
    +
    +      getPage();
    +    }
    +    ]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-82" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/314_external_paging.html b/docs/partials/tutorial/314_external_paging.html
    new file mode 100644
    index 000000000..07bda97b5
    --- /dev/null
    +++ b/docs/partials/tutorial/314_external_paging.html
    @@ -0,0 +1,97 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>When paging is enabled, the data is displayed in pages that can be browsed using using the built in paging selector.</p>
    +
    +<p>For external paging, handle the <code>pagingChanged' to load the page. Set the</code>gridOptions.totalItems' in the callback.</p><h2 id="Example">Example</h2>
    +<div class="example"><p>This shows combined external paging and sorting.
    +<h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-83" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-83" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-83">
    +    <div ng-controller="MainCtrl">
    +      <div ui-grid="gridOptions" ui-grid-paging class="grid"></div>
    +    </div>
    +  </script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +    .grid {
    +      width: 600px;
    +    }
    +  </style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +    var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.paging']);
    +
    +    app.controller('MainCtrl', [
    +    '$scope', '$http', 'uiGridConstants', function($scope, $http, uiGridConstants) {
    +
    +      var pagingOptions = {
    +        pageNumber: 1,
    +        pageSize: 25,
    +        sort: null
    +      };
    +
    +      $scope.gridOptions = {
    +        pagingPageSizes: [25, 50, 75],
    +        pagingPageSize: 25,
    +        useExternalPaging: true,
    +        useExternalSorting: true,
    +        columnDefs: [
    +          { name: 'name' },
    +          { name: 'gender', enableSorting: false },
    +          { name: 'company', enableSorting: false }
    +        ],
    +        onRegisterApi: function(gridApi) {
    +          $scope.gridApi = gridApi;
    +          $scope.gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
    +            if (sortColumns.length == 0) {
    +              pagingOptions.sort = null;
    +            } else {
    +              pagingOptions.sort = sortColumns[0].sort.direction;
    +            }
    +            getPage();
    +          });
    +          gridApi.paging.on.pagingChanged($scope, function (newPage, pageSize) {
    +            pagingOptions.pageNumber = newPage;
    +            pagingOptions.pageSize = pageSize;
    +            getPage();
    +          });
    +        }
    +      };
    +
    +      var getPage = function() {
    +        var url;
    +        switch(pagingOptions.sort) {
    +          case uiGridConstants.ASC:
    +            url = '/data/100_ASC.json';
    +            break;
    +          case uiGridConstants.DESC:
    +            url = '/data/100_DESC.json';
    +            break;
    +          default:
    +            url = '/data/100.json';
    +            break;
    +        }
    +
    +        $http.get(url)
    +        .success(function (data) {
    +          $scope.gridOptions.totalItems = 100;
    +          var firstRow = (pagingOptions.pageNumber - 1) * pagingOptions.pageSize;
    +          $scope.gridOptions.data = data.slice(firstRow, firstRow + pagingOptions.pageSize);
    +        });
    +      };
    +
    +      getPage();
    +    }
    +    ]);
    +  </script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-83" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/315_editable_cascading_dropdown.html b/docs/partials/tutorial/315_editable_cascading_dropdown.html
    new file mode 100644
    index 000000000..e1cf5c52d
    --- /dev/null
    +++ b/docs/partials/tutorial/315_editable_cascading_dropdown.html
    @@ -0,0 +1,141 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>It is possible to use the edit feature and the dropdown options array to build a cascading
    +dropdown setup, where the options in the second dropdown depend on the selection in the 
    +first dropdown.  Thanks to @ajain27 for the sample code.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-83" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-83" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-83">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <strong>Last Cell Edited:</strong> {{msg.lastCellEdited}}
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'name', displayName: 'Name', width: '20%' },
    +      { name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
    +        cellFilter: 'mapGender', editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
    +          { id: 1, gender: 'male' },
    +          { id: 2, gender: 'female' }
    +        ] 
    +      },
    +      { name: 'company', displayName: 'Company', width: '30%' },
    +      { name: 'size', displayName: 'Clothes Size', width: '20%', editableCellTemplate: 'ui-grid/dropdownEditor',
    +        cellFilter: 'mapSize', editDropdownValueLabel: 'size', editDropdownRowEntityOptionsArrayPath: 'sizeOptions' }
    +    ];
    +    
    +    $scope.maleSizeDropdownOptions = [
    +      { id: 1, size: 'SM' },
    +      { id: 2, size: 'M' },
    +      { id: 3, size: 'L' },
    +      { id: 4, size: 'XL' },
    +      { id: 5, size: 'XXL' }
    +    ];
    +
    +    $scope.femaleSizeDropdownOptions = [
    +      { id: 6, size: '8' },
    +      { id: 7, size: '10' },
    +      { id: 8, size: '12' },
    +      { id: 9, size: '14' },
    +      { id: 10, size: '16' }
    +    ];
    +
    +   $scope.gridOptions.onRegisterApi = function(gridApi){
    +      //set gridApi on scope
    +      $scope.gridApi = gridApi;
    +      gridApi.edit.on.afterCellEdit($scope,function(rowEntity, colDef, newValue, oldValue){
    +        if( colDef.name === 'gender' ){
    +          if( newValue === 1 ){
    +            rowEntity.sizeOptions = $scope.maleSizeDropdownOptions;
    +          } else {
    +            rowEntity.sizeOptions = $scope.femaleSizeDropdownOptions;
    +          }
    +        }
    +      });
    +    };
    +
    +    $http.get('/data/100.json')
    +    .success(function(data) {
    +      // massage the default data to give us a coded gender and a size
    +      for(i = 0; i < data.length; i++){
    +        if ( data[i].gender === 'male' ) {
    +          data[i].gender = 1;
    +          data[i].size = Math.floor(Math.random() * (5 - 1)) + 1;
    +          data[i].sizeOptions = $scope.maleSizeDropdownOptions;
    +        } else {
    +          data[i].gender = 2;
    +          data[i].size = Math.floor(Math.random() * (10 - 5)) + 5;
    +          data[i].sizeOptions = $scope.femaleSizeDropdownOptions;
    +        }
    +      }
    +      $scope.gridOptions.data = data;
    +    });
    +  }])
    +
    +  .filter('mapGender', function() {
    +    var genderHash = {
    +      1: 'male',
    +      2: 'female'
    +    };
    +
    +    return function(input) {
    +      if (!input){
    +        return '';
    +      } else {
    +        return genderHash[input];
    +      }
    +    };
    +  })
    +
    +  .filter('mapSize', function() {
    +    var sizeHash = {
    +      1: 'SM',
    +      2: 'M',
    +      3: 'L',
    +      4: 'XL',
    +      5: 'XXL',
    +      6: '8',
    +      7: '10',
    +      8: '12',
    +      9: '14',
    +      10: '16'
    +    };
    +
    +    return function(input) {
    +      if (!input){
    +        return '';
    +      } else {
    +        return sizeHash[input];
    +      }
    +    };
    +  })
    +});
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-83" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/316_dynamic_data_changes.html b/docs/partials/tutorial/316_dynamic_data_changes.html
    new file mode 100644
    index 000000000..2804d95d9
    --- /dev/null
    +++ b/docs/partials/tutorial/316_dynamic_data_changes.html
    @@ -0,0 +1,38 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The general AngularJS approach is two way data binding.  On every digest cycle every binding is evaluated
    +to see if anything has changed, and updates made as appropriate.</p>
    +
    +<p>ui-grid explicitly seeks to avoid this.  The grid is intended to render large numbers of rows (10K plus), and
    +if all of those rows were evaluated on every digest cycle the performance would be unworkable.  There are
    +two different approaches that ui-grid takes to improve performance:</p>
    +
    +<ul>
    +<li>virtualisation.  ui-grid doesn't render every cell in the data set, rather it aims to only render those
    +cells that are actually visible, and to fake the scrollbar length so that it looks like there are more cells
    +than have actually been rendered.  Whenever a scroll event occurs ui-grid therefore needs to quickly render
    +the missing cells to maintain the illusion that the full grid is rendered</li>
    +<li>manual binding/calculation.  Elements of the rendering that we don't expect to change are calculated once,
    +when a row is first rendered.  They aren't automatically recalculated when the data changes, rather they are 
    +only recalculated when explicitly called via <code>notifyDataChange</code>.  This includes elements such as cellClasses
    +and rowTemplates</li>
    +</ul>
    +
    +<p>If you frequent the development gitter you'll see this referred to as "removing watches" - the aim being to 
    +reduce the amount of work needed in each digest cycle, because scrolling calls digest a large number of times.</p>
    +
    +<p>The main upshot of this is that in some instances you'll need to explicitly tell ui-grid that your data has changed.
    +This includes:</p>
    +
    +<ul>
    +<li>when you have updated the content of your data.  The grid automatically calls <code>notifyDataChange</code> when data is edited
    +in place, for other changes to the data you need to call <code>notifyDataChange</code> manually  </li>
    +<li>changing visibility and some other properties on columns</li>
    +</ul>
    +
    +<p>Examples of notifyDataChange can be found in other tutorials:</p>
    +
    +<ul>
    +<li><a href="#/tutorial/113_adding_and_removing_columns">113 adding and removing columns</a></li>
    +</ul></div>
    diff --git a/docs/partials/tutorial/3_large_dataset.html b/docs/partials/tutorial/3_large_dataset.html
    new file mode 100644
    index 000000000..ce7dc51c0
    --- /dev/null
    +++ b/docs/partials/tutorial/3_large_dataset.html
    @@ -0,0 +1,60 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses a data set of 10,000 records.</p>
    +
    +<p>Demonstrates the following:</p>
    +
    +<ul>
    +   <li>binding complex column properties on Address.City.</li>
    +   <li>same field can be listed twice in the grid with a different name</li>
    +   <li>using field instead of name for backwards compatibility with 2.x</li>
    + </ul><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-23" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-23" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-23">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +
    +    $scope.gridOptions.columnDefs = [
    +      {name:'id'},
    +      {name:'name'},
    +      {field:'age'}, // showing backwards compatibility with 2.x.  you can use field in place of name
    +      {name: 'address.city'},
    +      {name: 'age again', field:'age'}
    +    ];
    +
    +    $http.get('/data/10000_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-23" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/4.1_custom_row_template.html b/docs/partials/tutorial/4.1_custom_row_template.html
    new file mode 100644
    index 000000000..6e34ced7d
    --- /dev/null
    +++ b/docs/partials/tutorial/4.1_custom_row_template.html
    @@ -0,0 +1,75 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Create a grid almost the same as the most basic one, but with a custom row template.</p>
    +
    +<p>You can use <a href="/docs/#/tutorial/202_externalScopes">external scopes</a> in your row template to access elements in your controller's scope. The <code>external-scopes</code> attribute on the grid will expose the property on your <code>$scope</code> with that name in the grid's isolate scope. You can then use <code>getExternalScopes()</code> in your row template to access that. More details are on the <a href="/docs/#/tutorial/202_externalScopes">external scopes</a> tutorial.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-24" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-24" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-24">
    +  <div ng-controller="MainCtrl">
    +    <strong ng-bind="waiting"></strong> <strong>{{ wait }}</strong>
    +    <br>
    +    <br>
    +    //make sure to set the controller variable in the attribute like so:
    +    <div class="grid" ui-grid="gridOptions" external-scopes="myNewModel"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 300px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$timeout', '$interval', function ($scope, $http, $timeout, $interval) {
    +    var start = new Date();
    +    var sec = $interval(function () {
    +      var wait = parseInt(((new Date()) - start) / 1000, 10);
    +      $scope.wait = wait + 's';
    +    }, 1000);
    +
    +    function rowTemplate() {
    +      return $timeout(function() {
    +        $scope.waiting = 'Done!';
    +        $interval.cancel(sec);
    +        $scope.wait = '';
    +        // Calling the externalScopes() method will allow you to reach up to the controller scope
    +        return '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';
    +      }, 6000);
    +    }
    +
    +    // Access outside scope functions from row template
    +    $scope.myNewModel = {
    +      fnOne: function(row) {
    +        console.log(row);
    +      }
    +    };
    +
    +    $scope.waiting = 'Waiting for row template...';
    +
    +    $http.get('/data/100.json')
    +      .success(function (data) {
    +        $scope.data = data;
    +      });
    +
    +    $scope.gridOptions = {
    +      rowTemplate: rowTemplate(),
    +      data: 'data'
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-24" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/401_AllFeatures.html b/docs/partials/tutorial/401_AllFeatures.html
    new file mode 100644
    index 000000000..46be48cd2
    --- /dev/null
    +++ b/docs/partials/tutorial/401_AllFeatures.html
    @@ -0,0 +1,128 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Appends data to the grid every .2 seconds for 15 seconds.  This emulates loading pages of data from the server. It's also an example
    +of setting gridOptions.data to a string value that specifies an object on your scope to watch.
    +<br></p>
    +
    +<p>All features are enabled to get an idea of performance</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-84" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario="scenario.js-85"></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-84" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-84">
    +  <div ng-controller="MainCtrl">
    +    <button id="refreshButton" type="button" class="btn btn-success" ng-click="refreshData()">Refresh Data</button>  <strong>Calls Pending:</strong> <span ng-bind="callsPending"></span>
    +    <br>
    +    <br>
    +    <strong>{{ myData.length }} rows</strong>
    +    <br>
    +    <div id="grid1" ui-grid="gridOptions" ui-grid-cellNav ui-grid-edit ui-grid-resize-columns ui-grid-pinning ui-grid-selection ui-grid-move-columns class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 500px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.cellNav', 'ui.grid.edit', 'ui.grid.resizeColumns', 'ui.grid.pinning', 'ui.grid.selection', 'ui.grid.moveColumns']);
    +
    +  app.controller('MainCtrl',  ['$scope', '$http', '$timeout', '$interval', 'uiGridConstants',
    +   function ($scope, $http, $timeout, $interval, uiGridConstants) {
    +
    +    $scope.gridOptions = {};
    +    $scope.gridOptions.data = 'myData';
    +    $scope.gridOptions.enableColumnResizing = true;
    +    $scope.gridOptions.enableFiltering = true;
    +    $scope.gridOptions.enableGridMenu = true;
    +    $scope.gridOptions.showGridFooter = true;
    +    $scope.gridOptions.showColumnFooter = true;
    +
    +    $scope.gridOptions.rowIdentity = function(row) {
    +      return row.id;
    +    };
    +    $scope.gridOptions.getRowIdentity = function(row) {
    +      return row.id;
    +    };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50 },
    +      { name:'name', width:100 },
    +      { name:'age', width:100, enableCellEdit: true, aggregationType:uiGridConstants.aggregationTypes.avg,
    +       cellTemplate: '<div class="ui-grid-cell-contents"><span>Age:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.street', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Street:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.city', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>City:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.state', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>State:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.zip', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Zip:{{COL_FIELD}}</span></div>'  },
    +      { name:'company', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Company:{{COL_FIELD}}</span></div>'  },
    +      { name:'email', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Email:{{COL_FIELD}}</span></div>'  },
    +      { name:'phone', width:200, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Phone:{{COL_FIELD}}</span></div>'  },
    +      { name:'about', width:300, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>AAbout:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[0].name', displayName:'1st friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend0:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend1:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend2:{{COL_FIELD}}</span></div>'  },
    +      { name:'agetemplate',field:'age', width:150, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age 2:{{COL_FIELD}}</span></div>' }
    +    ];
    +
    +    $scope.callsPending = 0;
    +
    +    var i = 0;
    +    $scope.refreshData = function(){
    +      $scope.myData = [];
    +
    +      var start = new Date();
    +      var sec = $interval(function () {
    +        $scope.callsPending++;
    +        
    +        $http.get('/data/500_complex.json')
    +          .success(function(data) {
    +            $scope.callsPending--;
    +
    +            data.forEach(function(row){
    +              row.name = row.name + ' iter ' + i;
    +              row.id = i;
    +              i++;
    +              $scope.myData.push(row);
    +            });
    +          })
    +          .error(function() {
    +            $scope.callsPending--
    +          });
    +      }, 200);
    +
    +
    +      $timeout(function() {
    +         $interval.cancel(sec);
    +         $scope.left = '';
    +      }, 2000);
    +
    +    };
    +
    +  }]);
    +</script>
    +</div>
    +<div class="tab-pane" title="End to end test">
    +<pre class="prettyprint linenums" ng-set-text="scenario.js-85"></pre>
    +<script type="text/ng-template" id="scenario.js-85">
    +    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');
    +
    +    describe('a grid with all features', function () {
    +      it('should not duplicate the menu options for pinning when resizing a column', function () {
    +        element( by.id('refreshButton') ).click();
    +        gridTestUtils.resizeHeaderCell( 'grid1', 1 );
    +        gridTestUtils.expectVisibleColumnMenuItems( 'grid1', 1, 5)
    +      });
    +    });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-84" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/402_GridIsScrolling.html b/docs/partials/tutorial/402_GridIsScrolling.html
    new file mode 100644
    index 000000000..bbf7f5c77
    --- /dev/null
    +++ b/docs/partials/tutorial/402_GridIsScrolling.html
    @@ -0,0 +1,67 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can reference a property to see if grid is in a scroll event.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-86" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-86" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-86">
    +  <div ng-controller="MainCtrl">
    +    <strong>Scrolling Vertically</strong> {{ gridApi.grid.isScrollingVertically }}
    +    <br>
    +    <strong>Scrolling Horizontally</strong> {{ gridApi.grid.isScrollingHorizontally }}
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngTouch', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id', width:50 },
    +      { name:'name', width:100 },
    +      { name:'age', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.street', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Street:{{COL_FIELD}}</span></div>'   },
    +      { name:'address.city', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>City:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.state', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>State:{{COL_FIELD}}</span></div>'  },
    +      { name:'address.zip', width:50, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Zip:{{COL_FIELD}}</span></div>'  },
    +      { name:'company', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Company:{{COL_FIELD}}</span></div>'  },
    +      { name:'email', width:100, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Email:{{COL_FIELD}}</span></div>'  },
    +      { name:'phone', width:200, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Phone:{{COL_FIELD}}</span></div>'  },
    +      { name:'about', width:300, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>AAbout:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[0].name', displayName:'1st friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend0:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[1].name', displayName:'2nd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend1:{{COL_FIELD}}</span></div>'  },
    +      { name:'friends[2].name', displayName:'3rd friend', width:150, enableCellEdit: true, cellTemplate: '<div class="ui-grid-cell-contents"><span>Friend2:{{COL_FIELD}}</span></div>'  },
    +      { name:'agetemplate',field:'age', width:100, cellTemplate: '<div class="ui-grid-cell-contents"><span>Age 2:{{COL_FIELD}}</span></div>' }
    +    ];
    +
    +     $scope.gridOptions.onRegisterApi = function(gridApi){
    +               $scope.gridApi = gridApi;
    +            };
    +
    +    $http.get('/data/10000_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-86" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/403_end_to_end_testing.html b/docs/partials/tutorial/403_end_to_end_testing.html
    new file mode 100644
    index 000000000..19ab55d88
    --- /dev/null
    +++ b/docs/partials/tutorial/403_end_to_end_testing.html
    @@ -0,0 +1,24 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Testing the grid with protractor can be complex.  In order to assist the project provides a 
    +<code>gridTestUtil.scenario.js</code> helper library that abstracts some of the key functions, such as
    +checking the value of a specified cell in the grid, counting the rows in the grid, or
    +clicking specific elements of the grid.</p>
    +
    +<p>The latest version of this is held in git, and there is potential it could get out of 
    +synch with this tutorial, it is therefore worthwhile to check that file itself at
    +<a href="https://github.com/angular-ui/ng-grid/tree/master/test/e2e">github e2e test folder</a></p>
    +
    +<p>The use of this library involves declaring it at the top of each scenario that requires
    +grid test functions:
    +<pre class="prettyprint linenums">
    +  var gridTestUtils = require( './gridTestUtils.scenario.js');
    +</pre>
    +
    +<p>Within your tests you can then use the helper methods that are provided:
    +<pre class="prettyprint linenums">
    +  gridTestUtils.expectRowCount( 'myGrid', 3 );
    +</pre>
    +
    +<p>For documentation of the available methods, refer to <a href="#/api/ui.grid.e2eTestLibrary.api:gridTest">gridTest</a></p></div>
    diff --git a/docs/partials/tutorial/4_custom_header.html b/docs/partials/tutorial/4_custom_header.html
    new file mode 100644
    index 000000000..d9ef006f8
    --- /dev/null
    +++ b/docs/partials/tutorial/4_custom_header.html
    @@ -0,0 +1,48 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Create a grid almost the same as the most basic one, but with a custom header</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-26 header-template.html" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-26" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-26">
    +  <div ng-controller="MainCtrl">
    +    <div class="grid" ui-grid="gridOptions"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="header-template.html">
    +<pre class="prettyprint linenums" ng-set-text="header-template.html"></pre>
    +<script type="text/ng-template" id="header-template.html">
    +  <div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      headerTemplate: 'header-template.html',
    +      data: [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ]
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-26" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/5.1.1_Filtering.html b/docs/partials/tutorial/5.1.1_Filtering.html
    new file mode 100644
    index 000000000..dc21e0984
    --- /dev/null
    +++ b/docs/partials/tutorial/5.1.1_Filtering.html
    @@ -0,0 +1,53 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid allows you to filter rows. Just set the <code>enableFiltering</code> flag in your grid options (it is off by default).</p>
    +
    +<p>Sorting can be disabled at the column level by setting <code>enableFiltering: false</code> in the column def. See the last column below for an example.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-22" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-22" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-22">
    +  <div ng-controller="MainCtrl">
    +    Click on a column header to open the menu and then filter by that column. (The third column has filtering disabled.)
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      enableFiltering: true,
    +      columnDefs: [
    +        { field: 'name' },
    +        { field: 'gender' },
    +        { field: 'company', enableFiltering: false  }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-22" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/5.1_sorting.html b/docs/partials/tutorial/5.1_sorting.html
    new file mode 100644
    index 000000000..f0d65776c
    --- /dev/null
    +++ b/docs/partials/tutorial/5.1_sorting.html
    @@ -0,0 +1,59 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>UI-Grid allows you to sort rows. The feature is on by default. You can set the <code>enableSorting</code> flag in your grid options to enable/disable it.</p>
    +
    +<p><span class="span8 alert alert-warning">
    +  <strong>Note:</strong> You must include ngAnimate in your application if you want the menu to slide up/down, but it's not required.
    +</span></p>
    +
    +<p>Sorting can be disabled at the column level by setting <code>enableSorting: false</code> in the column def. See the last column below for an example.</p>
    +
    +<p>Multiple columns can be sorted by shift-clicking on the 2-n columns.  To see it in action, sort Gender then shift-click Name.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-23" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-23" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-23">
    +  <div ng-controller="MainCtrl">
    +    Click on a column header to sort by that column. (The third column has sorting disabled.)
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: [
    +        { field: 'name' },
    +        { field: 'gender' },
    +        { field: 'company',enableSorting: false  }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-23" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/5.2_customizing_column_menu.html b/docs/partials/tutorial/5.2_customizing_column_menu.html
    new file mode 100644
    index 000000000..3fcc61b59
    --- /dev/null
    +++ b/docs/partials/tutorial/5.2_customizing_column_menu.html
    @@ -0,0 +1,92 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can customize a column's menu and provide your own functionality.</p>
    +
    +<p>By default, the <code>action</code> and <code>shown</code>'s' contexts will have a reference to the grid added as the property <code>grid</code> (accessible through <code>this.grid</code>.
    +You can pass in your own context by supplying the <code>context</code> property to your menu item. It will be accessible through <code>this.context</code>.</p>
    +
    +<p>The column menu will add the column's <code>GridColumn</code> object to the context as <code>this.context.col</code>. You can then show/hide the the menu item based
    +on conditions that use the grid and column.  You could also use a custom column builder to add some item to the every column definition.</p>
    +
    +<p>You can supply an icon class with the <code>icon</code> property.</p>
    +
    +<p>See the example below for usage.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-27" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-27" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-27">
    +  <div ng-controller="MainCtrl">
    +    Click on the third column header to test custom menu items.
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.blargh = function() {
    +      alert("I'm in the outer scope!");
    +    };
    +
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: [
    +        { field: 'name' },
    +        { field: 'gender' },
    +        {
    +          field: 'company',
    +          menuItems: [
    +            {
    +              title: 'Outer Scope Alert',
    +              icon: 'ui-grid-icon-info-circled',
    +              action: function($event) {
    +                this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +              },
    +              context: $scope
    +            },
    +            {
    +              title: 'Grid ID',
    +              action: function() {
    +                alert('Grid ID: ' + this.grid.id);
    +              }
    +            },
    +            {
    +              title: 'Column Title Alert',
    +              shown: function () {
    +                return this.context.col.displayName === 'Company';
    +              },
    +              action: function() {
    +                alert(this.context.col.displayName);
    +              }
    +            }
    +          ]
    +        }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-27" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/5.3_custom_grid_menu.html b/docs/partials/tutorial/5.3_custom_grid_menu.html
    new file mode 100644
    index 000000000..9c25bd2ac
    --- /dev/null
    +++ b/docs/partials/tutorial/5.3_custom_grid_menu.html
    @@ -0,0 +1,107 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-28" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-28" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-28">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-info" ng-click="openMyMenu()">Open Menu</button>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid">
    +      <div class="my-custom-menu" my-custom-menu ui-grid-menu menu-items="menuItems"></div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +
    +  .my-custom-menu {
    +    position: absolute;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu {
    +    padding: 0px;
    +  }
    +
    +  .my-custom-menu .ui-grid-menu-inner {
    +    -webkit-box-shadow: none;
    +    box-shadow: none;
    +  }
    +
    +  .rotated {
    +    transform: rotate(180deg);
    +    -webkit-transform: rotate(180deg);
    +    -ms-transform: rotate(180deg);
    +    -moz-transform: rotate(180deg);
    +    -o-transform: rotate(180deg);
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ngAnimate', 'ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {};
    +
    +    $scope.menuItems = [
    +      {
    +        title: 'Rotate Grid',
    +        action: function ($event) {
    +          this.grid.element.toggleClass('rotated');
    +        }
    +      }
    +    ];
    +
    +    $scope.openMyMenu = function () {
    +      $scope.$broadcast('openMyMenu');
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +
    +  app.directive('myCustomMenu', function ($timeout, gridUtil) {
    +    return {
    +      restrict: 'A',
    +      scope: true,
    +      require: ['^uiGrid', 'uiGridMenu'],
    +      link: function ($scope, $elm, $attr, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var uiGridMenuCtrl = controllers[1];
    +
    +        $scope.$on('openMyMenu', function () {
    +          uiGridMenuCtrl.showMenu();
    +
    +          $timeout(function () {
    +            var grid = uiGridCtrl.grid.element
    +            var width = gridUtil.elementWidth(grid, true);
    +
    +            // Put the menu just to the right of the grid
    +            $elm.css('left', width + 'px');
    +
    +            // Put the menu at the top of the grid but adjust for the border
    +            $elm.css('top', '-1px');
    +          });
    +        });
    +      }
    +    };
    +  });
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-28" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/5_100 data points.html b/docs/partials/tutorial/5_100 data points.html
    new file mode 100644
    index 000000000..b239adbb6
    --- /dev/null
    +++ b/docs/partials/tutorial/5_100 data points.html	
    @@ -0,0 +1,44 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses a data set of 100 records</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-27" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-27" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-27">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {};
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-27" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/6_editable.html b/docs/partials/tutorial/6_editable.html
    new file mode 100644
    index 000000000..205f87695
    --- /dev/null
    +++ b/docs/partials/tutorial/6_editable.html
    @@ -0,0 +1,106 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can use the <code>enableCellEdit</code> options in your column definitions to allow a column to be editable.</p>
    +
    +<p>Editing is invoked via double-click, f2, or start typing any non-navigable key. By default numeric, date and checkbox editors are
    +provided for fields specified as number, date and boolean types, for all other fields a simple text editor is provided.
    +Custom edit templates should be used for any editor other than the default editors.</p>
    +
    +<p>ColumnDef Options:
    +<br/><code>editableCellTemplate</code> (default: 'ui-grid/cellEditor') - Valid html, templateCache Id,  or url that returns html content to be compiled when edit mode is invoked.
    +<br/><code>enableCellEdit</code> (default: false for columns of type 'object', true for all other columns) - true will enable editing and false will disable it.
    +<br/><code>cellEditableCondition</code>  (default: true)  Can be set to a boolean or a function that will be called with the cellScope to determine if the cell should be invoked in edit mode.
    +<br/><code>type</code> (default: 'string') If set to 'number', 'boolean' or 'date' the default editor provided for editing will be numeric or boolean or date editor respectively.
    +If set to 'object' the column will not be editable by default.
    +<br/>
    +The following option is available only if using cellNav feature
    +<br/><code>enableCellEditOnFocus</code> - true to invoke editor as soon as cell has focus</p>
    +
    +<pre class="prettyprint linenums">
    +$scope.gridOptions.columnDefs = [
    +   { name: 'name', enableCellEdit: true, editableCellTemplate },
    +   { name: 'age', enableCellEdit: true, type: 'number'},
    +   { name: 'registered', displayName: 'Registered' , type: 'date'},
    +   { name: 'address', displayName: 'Address', type: 'object'},
    +   { name: 'address.city', enableCellEdit: true, displayName: 'Address (even rows editable)', cellEditableCondition: function($scope){return $scope.rowRenderIndex%2} }
    +   { name: 'isActive', enableCellEdit: true, type: 'boolean'},
    +]
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-29" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-29" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-29">
    +  <div ng-controller="MainCtrl">
    +    <strong>Data Length:</strong> {{ gridOptions.data.length | number }}
    +    <br>
    +    <strong>Last Cell Edited:</strong> {{msg.lastCellEdited}}
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 600px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.edit', 'addressFormatter']);
    +
    +  angular.module('addressFormatter', []).filter('address', function () {
    +    return function (input) {
    +        return input.street + ', ' + input.city + ', ' + input.state + ', ' + input.zip;
    +    };
    +  });
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', enableCellEdit: false },
    +      { name: 'name', displayName: 'Name (editable)' },
    +      { name: 'age', displayName: 'Age' , type: 'number'},
    +      { name: 'registered', displayName: 'Registered' , type: 'date', cellFilter: 'date:"yyyy-MM-dd"'},
    +      { name: 'address', displayName: 'Address', type: 'object', cellFilter: 'address'},
    +      { name: 'address.city', displayName: 'Address (even rows editable)',
    +           cellEditableCondition: function($scope){
    +           return $scope.rowRenderIndex%2
    +           }
    +      },
    +      { name: 'isActive', displayName: 'Active', type: 'boolean'}
    +    ];
    +
    +
    +
    +   $scope.msg = {};
    +
    +   $scope.gridOptions.onRegisterApi = function(gridApi){
    +            //set gridApi on scope
    +            $scope.gridApi = gridApi;
    +            gridApi.edit.on.afterCellEdit($scope,function(rowEntity, colDef, newValue, oldValue){
    +              $scope.msg.lastCellEdited = 'edited row id:' + rowEntity.id + ' Column:' + colDef.name + ' newValue:' + newValue + ' oldValue:' + oldValue ;
    +              $scope.$apply();
    +            });
    +          };
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        for(i = 0; i < data.length; i++){
    +          data[i].registered = new Date(data[i].registered);
    +        }
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-29" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/6_hidden_grids.html b/docs/partials/tutorial/6_hidden_grids.html
    new file mode 100644
    index 000000000..1706ebaec
    --- /dev/null
    +++ b/docs/partials/tutorial/6_hidden_grids.html
    @@ -0,0 +1,49 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Hiding grids in tabs or modals</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-30" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-30" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-30">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="hideGrid = !hideGrid">
    +      {{ hideGrid && 'Show' || 'Hide' }} Grid
    +    </button>
    +
    +    <div class="well" ng-hide="hideGrid">
    +      <div ui-grid="gridOptions" class="grid"></div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.hideGrid = true;
    +
    +    $scope.gridOptions = {  };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-30" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/6a_editableOnFocus.html b/docs/partials/tutorial/6a_editableOnFocus.html
    new file mode 100644
    index 000000000..f2a262f8b
    --- /dev/null
    +++ b/docs/partials/tutorial/6a_editableOnFocus.html
    @@ -0,0 +1,68 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Combine ui.grid.edit with ui.grid.cellNav, you can enable editing when the cell gets focus.
    +grid.options.enableCellEditOnFocus must be set to true.
    +<br/>
    +See api docs for default navigation keys and how you can override.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-31" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-31" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-31">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="getCurrentFocus()">Get Current focused cell</button>  <span ng-bind="currentFocused"></span>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-edit ui-grid-cellnav class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 450px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +    $scope.gridOptions.enableCellEditOnFocus = true;
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id', enableCellEdit: false },
    +      { name: 'name', displayName: 'Name (editOnFocus)'},
    +      { name: 'age', enableCellEditOnFocus:false, displayName:'age (f2/dblClick edit)'  },
    +      { name: 'address.city', enableCellEdit: false }
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.currentFocused = "";
    +
    +      $scope.getCurrentFocus = function(){
    +        var rowCol = $scope.gridApi.cellNav.getFocusedCell();
    +        if(rowCol !== null) {
    +            $scope.currentFocused = 'Row Id:' + rowCol.row.entity.id + ' col:' + rowCol.col.colDef.name;
    +        }
    +      }
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +         $scope.gridApi = gridApi;
    +      };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-31" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/7_multiple_grids.html b/docs/partials/tutorial/7_multiple_grids.html
    new file mode 100644
    index 000000000..4c0986c74
    --- /dev/null
    +++ b/docs/partials/tutorial/7_multiple_grids.html
    @@ -0,0 +1,55 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Using multiple grids on a single page</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-32" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-32" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-32">
    +  <div ng-controller="MainCtrl">
    +    <div class="row">
    +      <div class="span4">
    +        <div ui-grid="gridOptions1" class="grid"></div>
    +      </div>
    +      
    +      <div class="span4">
    +        <div ui-grid="gridOptions2" class="grid"></div>
    +      </div>
    +    </div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 250px;
    +    height: 150px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions1 = {};
    +    $scope.gridOptions2 = {};
    +
    +    $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions1.data = data;
    +    });
    +
    +    $http.get('/data/500.json')
    +    .success(function(data) {
    +      $scope.gridOptions2.data = data;
    +    });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-32" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/8_grid_in_modal.html b/docs/partials/tutorial/8_grid_in_modal.html
    new file mode 100644
    index 000000000..ccf65a20d
    --- /dev/null
    +++ b/docs/partials/tutorial/8_grid_in_modal.html
    @@ -0,0 +1,104 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Using a grid in a modal popup</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-33" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-33" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-33">
    +  <div ng-controller="MainCtrl">
    +    <button class="btn btn-success" ng-click="showModal()">Show Modal</button>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .modal {
    +    position: fixed;
    +    top: 50%;
    +    left: 50%;
    +    width: 50%;
    +    max-width: 550px;
    +    min-width: 330px;
    +    height: auto;
    +    z-index: 2000;
    +    -webkit-transform: translateX(-50%) translateY(-50%);
    +    -moz-transform: translateX(-50%) translateY(-50%);
    +    -ms-transform: translateX(-50%) translateY(-50%);
    +    transform: translateX(-50%) translateY(-50%);
    +
    +    border: 1px solid #333;
    +    background-color: #fafafa;
    +
    +    padding: 15px;
    +  }
    +
    +  .modal-close {
    +    position: absolute;
    +    top: 10px;
    +    right: 10px;
    +    color: #000;
    +    font-weight: bold;
    +  }
    +
    +  .grid {
    +    width: 300px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$rootScope', '$scope', '$http', 'modal', function ($rootScope, $scope, $http, modal) {
    +    var myModal = new modal();
    +
    +    $scope.hideGrid = true;
    +
    +    $rootScope.gridOptions = {  };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $rootScope.gridOptions.data = data;
    +      });
    +
    +    $scope.showModal = function() {
    +      myModal.open();
    +    };
    +  }]);
    +
    +  app.factory('modal', ['$compile', '$rootScope', function ($compile, $rootScope) {
    +    return function() {
    +      var elm;
    +      var modal = {
    +        open: function() {
    +          var html = '<div class="modal"><a class="modal-close" href ng-click="close()">X</a><div ui-grid="gridOptions" class="grid"></div></div>';
    +
    +          elm = angular.element(html);
    +          angular.element(document.body).prepend(elm);
    +
    +          $rootScope.close = function() {
    +            modal.close();
    +          };
    +
    +          $compile(elm)($rootScope);
    +        },
    +        close: function() {
    +          if (elm) {
    +            elm.remove();
    +          }
    +        }
    +      };
    +
    +      return modal;
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-33" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/9.1_selection.html b/docs/partials/tutorial/9.1_selection.html
    new file mode 100644
    index 000000000..f26af4831
    --- /dev/null
    +++ b/docs/partials/tutorial/9.1_selection.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses the ui-grid-selection directive to row selection.</p>
    +
    +<p>Uses the gridOptions.onRegisterApi callback to register the rowSelectionChanged event and log when the row is selected.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-34" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-34" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-34">
    +  <div ng-controller="MainCtrl">
    +   <button type="button" class="btn btn-success" ng-click="toggleMultiSelect()">Toggle multiSelect</button>  <strong>MultiSelect:</strong> <span ng-bind="gridApi.grid.options.multiSelect"></span>
    +    <button type="button" class="btn btn-success" ng-click="toggleRow1()">Toggle Row 0</button> </span>
    +    <br/>
    +    <br/>
    +    <button type="button" class="btn btn-success" ng-disabled="!gridApi.grid.options.multiSelect" ng-click="selectAll()">Select All</button> </span>
    +    <button type="button" class="btn btn-success" ng-click="clearAll()">Clear All</button> </span>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-selection class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id' },
    +      { name: 'name'},
    +      { name: 'age', displayName: 'Age (not focusable)', allowCellFocus : false },
    +      { name: 'address.city' }
    +    ];
    +
    +    $scope.gridOptions.multiSelect = true;
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.info = {};
    +
    +      $scope.toggleMultiSelect = function() {
    +         $scope.gridApi.selection.setMultiSelect(!$scope.gridApi.grid.options.multiSelect);
    +      };
    +
    +      $scope.selectAll = function() {
    +                 $scope.gridApi.selection.selectAllRows();
    +      };
    +
    +       $scope.clearAll = function() {
    +                       $scope.gridApi.selection.clearSelectedRows();
    +            };
    +
    +      $scope.toggleRow1 = function() {
    +                       $scope.gridApi.selection.toggleRowSelection($scope.gridOptions.data[0]);
    +      };
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +        //set gridApi on scope
    +        $scope.gridApi = gridApi;
    +        gridApi.selection.on.rowSelectionChanged($scope,function(row){
    +          var msg = 'row selected ' + row.isSelected;
    +          $log.log(msg);
    +        });
    +      };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-34" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/91_column_row_customization.html b/docs/partials/tutorial/91_column_row_customization.html
    new file mode 100644
    index 000000000..1ba953c21
    --- /dev/null
    +++ b/docs/partials/tutorial/91_column_row_customization.html
    @@ -0,0 +1,48 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Customize rows and columns.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-35" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-35" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-35">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { field: 'id', width: '40' },
    +      { field: 'name' },
    +      { field: 'age', width: '40' },
    +      { field: 'address.city' }
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-35" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/92_horizontal_scrolling.html b/docs/partials/tutorial/92_horizontal_scrolling.html
    new file mode 100644
    index 000000000..620ae344d
    --- /dev/null
    +++ b/docs/partials/tutorial/92_horizontal_scrolling.html
    @@ -0,0 +1,64 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Demonstrating scrolling with large amount of columns</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-36" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-36" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-36">
    +  <div ng-controller="MainCtrl">
    +    <strong>{{ gridOptions.columnDefs.length | number }} Columns with Random Widths</strong>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      enableSorting: true
    +    };
    +    $scope.gridOptions.columnDefs = [];
    +
    +    var colCount = 500;
    +
    +    for (var colIndex = 0; colIndex < colCount; colIndex++) {
    +      $scope.gridOptions.columnDefs.push({
    +        name: 'col' + colIndex,
    +        width: Math.floor(Math.random() * (120 - 50 + 1)) + 50
    +      });
    +    }
    +
    +    var data = [];
    +    for (var rowIndex = 0; rowIndex < 500; rowIndex++) {
    +      var row = {};
    +
    +      for (var colIndex = 0; colIndex < colCount; colIndex++) {
    +        row['col' + colIndex] = 'r' + rowIndex + 'c' + colIndex;
    +      }
    +
    +      data.push(row);
    +    }
    +
    +    $scope.gridOptions.data = data;
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-36" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/93_column_resizing.html b/docs/partials/tutorial/93_column_resizing.html
    new file mode 100644
    index 000000000..24f73e5dd
    --- /dev/null
    +++ b/docs/partials/tutorial/93_column_resizing.html
    @@ -0,0 +1,86 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>You can add column resizing by including the <code>ui.grid.resizeColumns</code> feature module in your application's dependencies.
    +<pre class="prettyprint linenums">
    +angular.module('yourApp', ['ui.grid', 'ui.grid.resizeColumns']);
    +</pre>
    +
    +<p>Also, you must add the directive to your grid element.  We do this so that you can have several grids on a
    +page and only pay the resizing overhead if the grid is actually using resizing.  Once you use this directive, all
    +columns automatically allow resizing
    +<pre class="prettyprint linenums">
    +&lt;div ui-grid="gridOptions" class="grid" ui-grid-resize-columns&gt;&lt;/div&gt;
    +</pre>
    +<br>
    +<br>
    +If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +option to false. This prevents resizing for the entire grid, regardless of individual colDef options.
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableColumnResizing: false
    +};
    +</pre>
    +<br>
    +<br>
    +You can disable it on a column by setting the <code>enableColumnResizing</code> property to false in its column definition.
    +<pre class="prettyprint linenums">
    +$scope.gridOptions = {
    +  enableColumnResizing: true,
    +  columnDefs: [
    +    { field: 'name' },
    +    { field: 'gender', enableColumnResizing: false },
    +    { field: 'company' }
    +  ]
    +};
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-37" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-37" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-37">
    +  <div ng-controller="MainCtrl">
    +    <strong>Drag</strong> a the column separator to resize; <strong>double-click</strong> to size according to rendered column contents.
    +    <br>
    +    <br>
    +    The column will obey any <i>minWidth</i> or <i>maxWidth</i> constraints you give it.
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" class="grid" ui-grid-resize-columns></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {
    +      enableSorting: true,
    +      columnDefs: [
    +        { field: 'name', minWidth: 200, width: '50%' },
    +        { field: 'gender', width: '30%', enableColumnResizing: false },
    +        { field: 'company', width: '20%' }
    +      ]
    +    };
    +
    +    $http.get('/data/100.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-37" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/9_cellnav.html b/docs/partials/tutorial/9_cellnav.html
    new file mode 100644
    index 000000000..0d91c35fe
    --- /dev/null
    +++ b/docs/partials/tutorial/9_cellnav.html
    @@ -0,0 +1,77 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses the ui-grid-cellNav directive to add cell navigation.</p>
    +
    +<p>Uses the gridOptions.onRegisterApi callback to register the on_cellNav event and log when the cell is navigated.</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-38" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-38" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-38">
    +  <div ng-controller="MainCtrl">
    +    <button type="button" class="btn btn-success" ng-click="getCurrentFocus()">Get Current focused cell</button>  <span ng-bind="currentFocused"></span>
    +    <br>
    +    <br>
    +    <div ui-grid="gridOptions" ui-grid-cellNav class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +    $scope.gridOptions.columnDefs = [
    +      { name: 'id' },
    +      { name: 'name'},
    +      { name: 'age', displayName: 'Age (not focusable)', allowCellFocus : false },
    +      { name: 'address.city' }
    +    ];
    +
    +    $http.get('/data/500_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +
    +      $scope.info = {};
    +
    +      $scope.currentFocused = "";
    +
    +      $scope.getCurrentFocus = function(){
    +        var rowCol = $scope.gridApi.cellNav.getFocusedCell();
    +        if(rowCol !== null) {
    +            $scope.currentFocused = 'Row Id:' + rowCol.row.entity.id + ' col:' + rowCol.col.colDef.name;
    +        }
    +      }
    +
    +      $scope.gridOptions.onRegisterApi = function(gridApi){
    +         $scope.gridApi = gridApi;
    +         gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +               // var rowCol = {row: newRowCol.row.index, col:newRowCol.col.colDef.name};
    +               // var msg = 'New RowCol is ' + angular.toJson(rowCol);
    +               // if(oldRowCol){
    +               //    rowCol = {row: oldRowCol.row.index, col:oldRowCol.col.colDef.name};
    +               //    msg += ' Old RowCol is ' + angular.toJson(rowCol);
    +               // }
    +                $log.log('navigation event');
    +              });
    +      };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-38" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/basic_grid.html b/docs/partials/tutorial/basic_grid.html
    new file mode 100644
    index 000000000..aee854174
    --- /dev/null
    +++ b/docs/partials/tutorial/basic_grid.html
    @@ -0,0 +1,337 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>In this example we create the most basic grid possible. Our </p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-2" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-2" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-2">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="{ data: data }" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.data = [
    +      {
    +          "firstName": "Cox",
    +          "lastName": "Carney",
    +          "company": "Enormo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Lorraine",
    +          "lastName": "Wise",
    +          "company": "Comveyer",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Nancy",
    +          "lastName": "Waters",
    +          "company": "Fuelton",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Misty",
    +          "lastName": "Oneill",
    +          "company": "Letpro",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Jefferson",
    +          "lastName": "Cohen",
    +          "company": "Slambda",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Gladys",
    +          "lastName": "Maldonado",
    +          "company": "Ramjob",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Glenn",
    +          "lastName": "Cole",
    +          "company": "Austex",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Waters",
    +          "lastName": "Shepherd",
    +          "company": "Kongene",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Hopper",
    +          "lastName": "Zamora",
    +          "company": "Acium",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Marcy",
    +          "lastName": "Mclean",
    +          "company": "Zomboid",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Tania",
    +          "lastName": "Cruz",
    +          "company": "Marqet",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Kramer",
    +          "lastName": "Cline",
    +          "company": "Parleynet",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Bond",
    +          "lastName": "Pickett",
    +          "company": "Brainquil",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Pauline",
    +          "lastName": "Cervantes",
    +          "company": "Slumberia",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Pittman",
    +          "lastName": "Reilly",
    +          "company": "Zolavo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Bartlett",
    +          "lastName": "Schwartz",
    +          "company": "Momentia",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Berg",
    +          "lastName": "Cherry",
    +          "company": "Eargo",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Hazel",
    +          "lastName": "Doyle",
    +          "company": "Koogle",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Amie",
    +          "lastName": "Mathis",
    +          "company": "Buzzness",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Walker",
    +          "lastName": "Molina",
    +          "company": "Medmex",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Elnora",
    +          "lastName": "Schroeder",
    +          "company": "Undertap",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Grant",
    +          "lastName": "Fletcher",
    +          "company": "Comvoy",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Violet",
    +          "lastName": "Ferrell",
    +          "company": "Multiflex",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Nettie",
    +          "lastName": "David",
    +          "company": "Waab",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mosley",
    +          "lastName": "Dunn",
    +          "company": "Sloganaut",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Puckett",
    +          "lastName": "Jarvis",
    +          "company": "Printspan",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Emma",
    +          "lastName": "Holcomb",
    +          "company": "Techmania",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Clara",
    +          "lastName": "Mueller",
    +          "company": "Microluxe",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Tanya",
    +          "lastName": "Hull",
    +          "company": "Buzzmaker",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Brandy",
    +          "lastName": "Berger",
    +          "company": "Ludak",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Bennett",
    +          "lastName": "Fischer",
    +          "company": "Zedalis",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Sallie",
    +          "lastName": "Vance",
    +          "company": "Voipa",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Celeste",
    +          "lastName": "Harrington",
    +          "company": "Steelfab",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Dunn",
    +          "lastName": "Mccoy",
    +          "company": "Ontagene",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mindy",
    +          "lastName": "Vang",
    +          "company": "Quadeebo",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Benton",
    +          "lastName": "Boyle",
    +          "company": "Flexigen",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Kristine",
    +          "lastName": "Hunt",
    +          "company": "Egypto",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Daugherty",
    +          "lastName": "Barber",
    +          "company": "Vinch",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Mays",
    +          "lastName": "Fuentes",
    +          "company": "Memora",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Maribel",
    +          "lastName": "Bush",
    +          "company": "Brainclip",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Brittney",
    +          "lastName": "Morse",
    +          "company": "Gonkle",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Fernandez",
    +          "lastName": "Sutton",
    +          "company": "Zeam",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Valeria",
    +          "lastName": "Owens",
    +          "company": "Zentix",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Gretchen",
    +          "lastName": "Dorsey",
    +          "company": "Sultrax",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mona",
    +          "lastName": "Hart",
    +          "company": "Exostream",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Skinner",
    +          "lastName": "Vincent",
    +          "company": "Konnect",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Hardy",
    +          "lastName": "Casey",
    +          "company": "Xylar",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Mccullough",
    +          "lastName": "Irwin",
    +          "company": "Joviold",
    +          "employed": true
    +      },
    +      {
    +          "firstName": "Barnett",
    +          "lastName": "Melton",
    +          "company": "Intergeek",
    +          "employed": false
    +      },
    +      {
    +          "firstName": "Michael",
    +          "lastName": "Hooper",
    +          "company": "Confrenzy",
    +          "employed": true
    +      }
    +  ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-2" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/custom_header.html b/docs/partials/tutorial/custom_header.html
    new file mode 100644
    index 000000000..c8d61b14b
    --- /dev/null
    +++ b/docs/partials/tutorial/custom_header.html
    @@ -0,0 +1,47 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>Create a grid almost the same as the most basic one, but with a custom header</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-3" source-edit-css="" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-3" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-3">
    +  <div ng-controller="MainCtrl">
    +
    +    <div ui-grid="data">
    +      <div ui-grid-header>
    +        Scope: {{ columns | json }}
    +        <div>
    +          <table class="table">
    +            <thead>
    +              <tr>
    +                <th ng-repeat="col in columns">{{ col.name | uppercase }}</th>
    +              </tr>
    +            </thead>
    +          </table>
    +        </div>
    +      </div>
    +
    +      <div ui-grid-body></div>
    +    </div>
    +
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.virtual-repeat']);
    +
    +  app.controller('MainCtrl', ['$scope', function ($scope) {
    +    $scope.data = [
    +      { name: 'Bob', title: 'CEO' },
    +      { name: 'Frank', title: 'Lowly Developer' }
    +    ];
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-3" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/index.html b/docs/partials/tutorial/index.html
    new file mode 100644
    index 000000000..6acfeb225
    --- /dev/null
    +++ b/docs/partials/tutorial/index.html
    @@ -0,0 +1,16 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This set of tutorials should help you on your way to using ui-grid, and provide answer for a lot of common use-cases.
    +If you don't see your particular case here then ask on <a href="https://gitter.im/angular-ui/ng-grid">gitter</a>.</p>
    +
    +<p>Developers are encouraged to submit PR's for any needed tutorials.</p>
    +
    +<p>The tutorials are numbered according to complexity:</p>
    +
    +<ul>
    +<li>100-199: Basic Grid (Freshman)</li>
    +<li>200-299: Basic Features (Sophomore)</li>
    +<li>300-399: Advanced Features / Combined Features  (Junior)</li>
    +<li>400-499: What you do in the real world (Senior)</li>
    +</ul></div>
    diff --git a/docs/partials/tutorial/infinite_scroll.html b/docs/partials/tutorial/infinite_scroll.html
    new file mode 100644
    index 000000000..ca3967134
    --- /dev/null
    +++ b/docs/partials/tutorial/infinite_scroll.html
    @@ -0,0 +1,84 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>The infinite scroll feature allows the user to lazy load their data to gridOptions.data</p>
    +
    +<p>Specify percentage when lazy load should trigger:
    +<pre class="prettyprint linenums">
    +  $scope.gridOptions.infiniteScroll = 20;
    +</pre><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-45" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-45" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-45">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid" ui-grid-infinite-scroll></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 400px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
    +    $scope.gridOptions = {};
    +
    +  /**
    +    * @ngdoc property
    +    * @name infiniteScrollPercentage
    +    * @propertyOf ui.grid.class:GridOptions
    +    * @description This setting controls at what percentage of the scroll more data
    +    * is requested by the infinite scroll
    +    */
    +    $scope.gridOptions.infiniteScrollPercentage = 15;
    +    
    +    $scope.gridOptions.columnDefs = [
    +      { name:'id'},
    +      { name:'name' },
    +      { name:'age' }
    +    ];
    +    var page = 1;
    +    var getData = function(data, page) {
    +      var res = [];
    +      for (var i = 0; i < page * 100 && i < data.length; ++i) {
    +        res.push(data[i]);
    +      }
    +      return res;
    +    };
    +
    +    $http.get('/data/10000_complex.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = getData(data, page);
    +        ++page;
    +      });
    +
    +    $scope.gridOptions.onRegisterApi = function(gridApi){
    +      gridApi.infiniteScroll.on.needLoadMoreData($scope,function(){
    +        $http.get('/data/10000_complex.json')
    +          .success(function(data) {
    +            $scope.gridOptions.data = getData(data, page);
    +            ++page;
    +            gridApi.infiniteScroll.dataLoaded();
    +          })
    +          .error(function() {
    +            gridApi.infiniteScroll.dataLoaded();
    +          });
    +      });
    +    };
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-45" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/docs/partials/tutorial/large_dataset.html b/docs/partials/tutorial/large_dataset.html
    new file mode 100644
    index 000000000..87c31ffb2
    --- /dev/null
    +++ b/docs/partials/tutorial/large_dataset.html
    @@ -0,0 +1,41 @@
    +<h1><code ng:non-bindable=""></code>
    +<span class="hint"></span>
    +</h1>
    +<div><p>This grid example uses a data set of 10,000 records</p><h2 id="Example">Example</h2>
    +<div class="example"><h4>Source</h4>
    +<div source-edit="app" source-edit-deps="angular.js app.js" source-edit-html="index.html-4" source-edit-css="main.css" source-edit-js="app.js" source-edit-unit="" source-edit-scenario=""></div>
    +<div class="tabbable"><div class="tab-pane" title="index.html">
    +<pre class="prettyprint linenums" ng-set-text="index.html-4" ng-html-wrap-loaded="app angular.js app.js"></pre>
    +<script type="text/ng-template" id="index.html-4">
    +  <div ng-controller="MainCtrl">
    +    <div ui-grid="gridOptions" class="grid"></div>
    +  </div>
    +</script>
    +</div>
    +<div class="tab-pane" title="main.css">
    +<pre class="prettyprint linenums" ng-set-text="main.css"></pre>
    +<style type="text/css" id="main.css">
    +  .grid {
    +    width: 500px;
    +    height: 250px;
    +  }
    +</style>
    +</div>
    +<div class="tab-pane" title="app.js">
    +<pre class="prettyprint linenums" ng-set-text="app.js"></pre>
    +<script type="text/ng-template" id="app.js">
    +  var app = angular.module('app', ['ui.grid']);
    +
    +  app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
    +    $scope.gridOptions = {  };
    +
    +    $http.get('/data/500.json')
    +      .success(function(data) {
    +        $scope.gridOptions.data = data;
    +      });
    +  }]);
    +</script>
    +</div>
    +</div><h4>Demo</h4>
    +<div class="well doc-example-live animator-container" ng-embed-app="app" ng-set-html="index.html-4" ng-eval-javascript="app.js"></div></div>
    +</div>
    diff --git a/googlec19fc6b166e5b8af.html b/googlec19fc6b166e5b8af.html
    new file mode 100644
    index 000000000..86b43ce0e
    --- /dev/null
    +++ b/googlec19fc6b166e5b8af.html
    @@ -0,0 +1 @@
    +google-site-verification: googlec19fc6b166e5b8af.html
    diff --git a/images/bg_hr.png b/images/bg_hr.png
    new file mode 100644
    index 000000000..7973bd698
    Binary files /dev/null and b/images/bg_hr.png differ
    diff --git a/images/blacktocat.png b/images/blacktocat.png
    new file mode 100644
    index 000000000..6e264fe57
    Binary files /dev/null and b/images/blacktocat.png differ
    diff --git a/images/icon_download.png b/images/icon_download.png
    new file mode 100644
    index 000000000..a2a287f64
    Binary files /dev/null and b/images/icon_download.png differ
    diff --git a/images/sprite_download.png b/images/sprite_download.png
    new file mode 100644
    index 000000000..f2babd575
    Binary files /dev/null and b/images/sprite_download.png differ
    diff --git a/index.html b/index.html
    new file mode 100644
    index 000000000..6b1479ad1
    --- /dev/null
    +++ b/index.html
    @@ -0,0 +1,414 @@
    +<!doctype html>
    +<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
    +<!--[if IE 7]>    <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
    +<!--[if IE 8]>    <html class="no-js lt-ie9" lang="en"> <![endif]-->
    +<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
    +<head>
    +  <meta charset="utf-8">
    +  <meta name="viewport" content="width=device-width, initial-scale=1.0">
    +  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    +  <!-- <link rel="stylesheet" href="/docs/css/bootstrap.min.css" /> -->
    +  <!-- <link rel="stylesheet" href="/css/bootstrap-responsive.min.css" /> -->
    +  <link rel="stylesheet" href="/docs/css/bootstrap-flatly.min.css" />
    +  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" />
    +  <link rel="stylesheet" href="/css/site.css" />
    +  <link rel="stylesheet" href="//ui-grid.info/release/ui-grid-unstable.min.css" />
    +</head>
    +<body>
    +  <div class="navbar navbar-default navbar-fixed-top">
    +    <div class="nav navbar-header">
    +      <a href="/" class="navbar-brand">UI Grid</a>
    +      <ul class="nav navbar-nav">
    +        <li class="dropdown">
    +          <a href="#" class="dropdown-toggle" data-toggle="dropdown">
    +            Learn
    +            <b class="caret"></b>
    +          </a>
    +          <ul class="dropdown-menu" role="menu">
    +            <li>
    +              <a href="/docs/#/api">Docs</a>
    +            </li>
    +            <li>
    +              <a href="/docs/#/tutorial">Tutorial</a>
    +            </li>
    +          </ul>
    +        </li>
    +      </ul>
    +    </div>
    +    <div class="navbar-header navbar-right">
    +      <p class="navbar-text hidden-phone">
    +        <iframe class="nav-ghbtn" src="http://ghbtns.com/github-btn.html?user=angular-ui&repo=ng-grid&type=watch&count=true"
    +              allowtransparency="true" frameborder="0" scrolling="0" width="120" height="20"></iframe>
    +        <iframe class="nav-ghbtn" src="http://ghbtns.com/github-btn.html?user=angular-ui&repo=ng-grid&type=fork&count=true"
    +              allowtransparency="true" frameborder="0" scrolling="0" width="120" height="20"></iframe>
    +      </p>
    +    </div>
    +  </div>
    +
    +  <div class="intro">
    +    <div class="jumbotron">
    +      <div class="description">
    +        <h1 class="text-center">Angular UI Grid</h1>
    +        <p class="lead text-center">A data grid for <strong>AngularJS</strong>, part of the <strong><a href="http://angular-ui.github.io/">AngularUI</a></strong> suite</p>
    +        <ul class="benefits text-left">
    +          <li>Native AngularJS implementation, no jQuery</li>
    +          <li>Performs well with large data sets; even <strong>10,000+</strong> rows</li>
    +          <li>Plugin architecture allows you to use only the features you need</li>
    +        </ul>
    +        <p class="btn-group2 text-center">
    +          <a class="btn btn-success btn-large" href="https://github.com/angular-ui/ng-grid" title="Code on Github">
    +            <i class="fa fa-github fa-fw"></i>
    +              Code on Github
    +          </a>
    +      
    +          <a class="btn btn-danger btn-large" href="https://github.com/angular-ui/ui-grid.info/tree/gh-pages/release" title="Download 3.0.0-rc.20-5f155b2">
    +            <i class="fa fa-download fa-fw"></i>
    +            <!-- Download <small>( 2.0.14 / 3.0.0-rc.20-5f155b2 )</small> --> <!-- TODO(c0bra): note: not showing stable version till 3.0.0 is released -->
    +
    +            Download <small>( 3.0.0-rc.20-5f155b2 )</small>
    +          </a>
    +      
    +          <a class="btn btn-success btn-large" href="http://ui-grid.info/docs/#/tutorial" title="Tutorial">
    +            <i class="fa fa-gears fa-fw"></i>
    +            Tutorial
    +          </a>
    +        </p>
    +      </div>
    +    </div>
    +  </div>
    +  
    +  <div class="container-fluid">   
    +    <div class="row">
    +      <div class="col-xs-12 col-sm-6 col-lg-3">
    +        <div class="feature">
    +          <div class="feature-heading">
    +            <i class="fa fa-4x fa-wrench"></i>
    +          </div>
    +          <h4 class="feature-heading">Configurable</h4>
    +          <ul>
    +            <li>Customizeable templates</li>
    +            <li>Change look and feel with CSS and the <a href="/customizer">customizer</a></li>
    +            <li>Drop-in plugin system</li>
    +          </ul>
    +        </div>
    +      </div>
    +      <div class="col-xs-12 col-sm-6 col-lg-3">
    +        <div class="feature">
    +          <div class="feature-heading">
    +            <i class="fa fa-4x fa-gear"></i>
    +          </div>
    +          <h4 class="feature-heading">Standard Features</h4>
    +          <ul>
    +            <li>Sorting</li>
    +            <li>Filtering</li>
    +            <li>User interaction</li>
    +          </ul>
    +          <h4 class="feature-heading">Advanced Features</h4>
    +          <ul>
    +            <li>Virtualization</li>
    +            <li>Column pinning</li>
    +            <li>Grouping</li>
    +            <li>Edit in place</li>
    +            <li>Expandable rows</li>
    +            <li>Internationalisation</li>
    +          </ul>
    +        </div>
    +      </div>
    +      <div class="col-xs-12 col-sm-12 col-lg-6">
    +        <div class="feature" ng-app="demo">
    +          <div class="feature-heading">
    +            <i class="fa fa-4x fa-certificate"></i>
    +          </div>
    +          <h4 class="feature-heading">Basic Example</h4>
    +          <div class="grid" ui-grid="gridOptionsSimple"></div>
    +          
    +          <h4 class="feature-heading">Complex Example</h4>
    +          <div class="grid" ui-grid="gridOptionsComplex" ui-grid-edit ui-grid-resize-columns></div>
    +        </div>
    +      </div>
    +    </div>
    +  </div>
    + 
    +
    +  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    +  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    +  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.js"></script>
    +  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.js"></script>
    +  <script src="//ui-grid.info/release/ui-grid-unstable.min.js"></script>
    +  <script>
    +    angular.module('demo', ['ngAnimate', 'ui.grid', 'ui.grid.edit', 'ui.grid.resizeColumns'])
    +    .run(function($rootScope, uiGridConstants) {
    +      $rootScope.gridOptionsSimple = {
    +        data: [
    +          {
    +              "name": "Ethel Price",
    +              "gender": "female",
    +              "company": "Enersol"
    +          },
    +          {
    +              "name": "Claudine Neal",
    +              "gender": "female",
    +              "company": "Sealoud"
    +          },
    +          {
    +              "name": "Beryl Rice",
    +              "gender": "female",
    +              "company": "Velity"
    +          },
    +          {
    +              "name": "Wilder Gonzales",
    +              "gender": "male",
    +              "company": "Geekko"
    +          },
    +          {
    +              "name": "Georgina Schultz",
    +              "gender": "female",
    +              "company": "Suretech"
    +          },
    +          {
    +              "name": "Carroll Buchanan",
    +              "gender": "male",
    +              "company": "Ecosys"
    +          },
    +          {
    +              "name": "Valarie Atkinson",
    +              "gender": "female",
    +              "company": "Hopeli"
    +          },
    +          {
    +              "name": "Schroeder Mathews",
    +              "gender": "male",
    +              "company": "Polarium"
    +          },
    +          {
    +              "name": "Lynda Mendoza",
    +              "gender": "female",
    +              "company": "Dogspa"
    +          },
    +          {
    +              "name": "Sarah Massey",
    +              "gender": "female",
    +              "company": "Bisba"
    +          },
    +          {
    +              "name": "Robles Boyle",
    +              "gender": "male",
    +              "company": "Comtract"
    +          },
    +          {
    +              "name": "Evans Hickman",
    +              "gender": "male",
    +              "company": "Parleynet"
    +          },
    +          {
    +              "name": "Dawson Barber",
    +              "gender": "male",
    +              "company": "Dymi"
    +          },
    +          {
    +              "name": "Bruce Strong",
    +              "gender": "male",
    +              "company": "Xyqag"
    +          },
    +          {
    +              "name": "Nellie Whitfield",
    +              "gender": "female",
    +              "company": "Exospace"
    +          },
    +          {
    +              "name": "Jackson Macias",
    +              "gender": "male",
    +              "company": "Aquamate"
    +          },
    +          {
    +              "name": "Pena Pena",
    +              "gender": "male",
    +              "company": "Quarx"
    +          },
    +          {
    +              "name": "Lelia Gates",
    +              "gender": "female",
    +              "company": "Proxsoft"
    +          },
    +          {
    +              "name": "Letitia Vasquez",
    +              "gender": "female",
    +              "company": "Slumberia"
    +          },
    +          {
    +              "name": "Trevino Moreno",
    +              "gender": "male",
    +              "company": "Conjurica"
    +          }
    +        ]
    +      };
    +      
    +      $rootScope.gridOptionsComplex = {
    +        enableFiltering: true,
    +        showGridFooter: true,
    +        showColumnFooter: true,
    +        columnDefs: [
    +          { name: 'name', aggregationType: uiGridConstants.aggregationTypes.count, width: 150 },
    +          { name: 'gender', filter: { term: 'male' }, width: 150, enableCellEdit: false, 
    +            cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
    +              if (grid.getCellValue(row,col) === 'male') {
    +                return 'blue';
    +              } else if (grid.getCellValue(row,col) === 'female') {
    +                return 'pink';
    +              }
    +            } 
    +          },
    +          { name: 'age', aggregationType: uiGridConstants.aggregationTypes.avg, width: 100 },
    +          { name: 'company', enableFiltering: false, width: 200 }
    +        ],
    +        data: [
    +          {
    +              "name": "Ethel Price",
    +              "gender": "female",
    +              "company": "Enersol",
    +              "age": 25
    +          },
    +          {
    +              "name": "Claudine Neal",
    +              "gender": "female",
    +              "company": "Sealoud",
    +              "age": 19
    +          },
    +          {
    +              "name": "Beryl Rice",
    +              "gender": "female",
    +              "company": "Velity",
    +              "age": 44
    +          },
    +          {
    +              "name": "Wilder Gonzales",
    +              "gender": "male",
    +              "company": "Geekko",
    +              "age": 26
    +          },
    +          {
    +              "name": "Georgina Schultz",
    +              "gender": "female",
    +              "company": "Suretech",
    +              "age": 53
    +          },
    +          {
    +              "name": "Carroll Buchanan",
    +              "gender": "male",
    +              "company": "Ecosys",
    +              "age": 64
    +          },
    +          {
    +              "name": "Valarie Atkinson",
    +              "gender": "female",
    +              "company": "Hopeli",
    +              "age": 35
    +          },
    +          {
    +              "name": "Schroeder Mathews",
    +              "gender": "male",
    +              "company": "Polarium",
    +              "age": 29
    +          },
    +          {
    +              "name": "Lynda Mendoza",
    +              "gender": "female",
    +              "company": "Dogspa",
    +              "age": 49
    +          },
    +          {
    +              "name": "Sarah Massey",
    +              "gender": "female",
    +              "company": "Bisba",
    +              "age": 40
    +          },
    +          {
    +              "name": "Robles Boyle",
    +              "gender": "male",
    +              "company": "Comtract",
    +              "age": 32
    +          },
    +          {
    +              "name": "Evans Hickman",
    +              "gender": "male",
    +              "company": "Parleynet",
    +              "age": 38
    +          },
    +          {
    +              "name": "Dawson Barber",
    +              "gender": "male",
    +              "company": "Dymi",
    +              "age": 21
    +          },
    +          {
    +              "name": "Bruce Strong",
    +              "gender": "male",
    +              "company": "Xyqag",
    +              "age": 61
    +          },
    +          {
    +              "name": "Nellie Whitfield",
    +              "gender": "female",
    +              "company": "Exospace",
    +              "age": 54
    +          },
    +          {
    +              "name": "Jackson Macias",
    +              "gender": "male",
    +              "company": "Aquamate",
    +              "age": 49
    +          },
    +          {
    +              "name": "Pena Pena",
    +              "gender": "male",
    +              "company": "Quarx",
    +              "age": 25
    +          },
    +          {
    +              "name": "Lelia Gates",
    +              "gender": "female",
    +              "company": "Proxsoft",
    +              "age": 54
    +          },
    +          {
    +              "name": "Alfred Oscar",
    +              "gender": "male",
    +              "company": "Transprop",
    +              "age": 34
    +          },
    +          {
    +              "name": "John Alfred",
    +              "gender": "male",
    +              "company": "Haymans",
    +              "age": 70
    +          },
    +          {
    +              "name": "Leonie Warren",
    +              "gender": "female",
    +              "company": "Hilltop",
    +              "age": 25
    +          },
    +          {
    +              "name": "Belinda Gosford",
    +              "gender": "female",
    +              "company": "Archison",
    +              "age": 42
    +          },
    +          {
    +              "name": "Tracey Misoni",
    +              "gender": "female",
    +              "company": "Verizona",
    +              "age": 34
    +          },
    +          {
    +              "name": "Trevino Moreno",
    +              "gender": "male",
    +              "company": "Conjurica",
    +              "age": 31
    +          }
    +        ]
    +      };      
    +    });
    +  </script>
    +</body>
    +</html>
    \ No newline at end of file
    diff --git a/info.ini b/info.ini
    new file mode 100644
    index 000000000..c13fde307
    --- /dev/null
    +++ b/info.ini
    @@ -0,0 +1,4 @@
    +author = "UI Grid Team"
    +github = "https://github.com/angular-ui/bower-ui-grid.git"
    +homepage = "http://ui-grid.info/"
    +description = "An AngularJS data grid"
    diff --git a/javascripts/main.js b/javascripts/main.js
    new file mode 100644
    index 000000000..d8135d37b
    --- /dev/null
    +++ b/javascripts/main.js
    @@ -0,0 +1 @@
    +console.log('This would be the main JS file.');
    diff --git a/js/bootstrap.min.js b/js/bootstrap.min.js
    new file mode 100644
    index 000000000..7c1561a8b
    --- /dev/null
    +++ b/js/bootstrap.min.js
    @@ -0,0 +1,6 @@
    +/*!
    + * Bootstrap v3.2.0 (http://getbootstrap.com)
    + * Copyright 2011-2014 Twitter, Inc.
    + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
    + */
    +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f+', [role="menu"], [role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.2.0",c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.$body.addClass("modal-open"),this.setScrollbar(),this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(c.$body),c.$element.show().scrollTop(0),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one("bsTransitionEnd",function(){c.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(300):c.$element.trigger("focus").trigger(e)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.$body.removeClass("modal-open"),this.resetScrollbar(),this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;if(this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;e?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(150):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var f=function(){c.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",f).emulateTransitionEnd(150):f()}else b&&b()},c.prototype.checkScrollbar=function(){document.body.clientWidth>=window.innerWidth||(this.scrollbarWidth=this.scrollbarWidth||this.measureScrollbar())},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.scrollbarWidth&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.2.0",c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var c=a.contains(document.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!c)return;var d=this,e=this.tip(),f=this.getUID(this.type);this.setContent(),e.attr("id",f),this.$element.attr("aria-describedby",f),this.options.animation&&e.addClass("fade");var g="function"==typeof this.options.placement?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,h=/\s?auto?\s?/i,i=h.test(g);i&&(g=g.replace(h,"")||"top"),e.detach().css({top:0,left:0,display:"block"}).addClass(g).data("bs."+this.type,this),this.options.container?e.appendTo(this.options.container):e.insertAfter(this.$element);var j=this.getPosition(),k=e[0].offsetWidth,l=e[0].offsetHeight;if(i){var m=g,n=this.$element.parent(),o=this.getPosition(n);g="bottom"==g&&j.top+j.height+l-o.scroll>o.height?"top":"top"==g&&j.top-o.scroll-l<0?"bottom":"right"==g&&j.right+k>o.width?"left":"left"==g&&j.left-k<o.left?"right":g,e.removeClass(m).addClass(g)}var p=this.getCalculatedOffset(g,j,k,l);this.applyPlacement(p,g);var q=function(){d.$element.trigger("shown.bs."+d.type),d.hoverState=null};a.support.transition&&this.$tip.hasClass("fade")?e.one("bsTransitionEnd",q).emulateTransitionEnd(150):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=k.left?2*k.left-e+i:2*k.top-f+j,m=k.left?"left":"top",n=k.left?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(l,d[0][n],m)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach(),c.$element.trigger("hidden.bs."+c.type)}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.removeAttr("aria-describedby"),this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one("bsTransitionEnd",b).emulateTransitionEnd(150):b(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName;return a.extend({},"function"==typeof c.getBoundingClientRect?c.getBoundingClientRect():null,{scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop(),width:d?a(window).width():b.outerWidth(),height:d?a(window).height():b.outerHeight()},d?{top:0,left:0}:b.offset())},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.2.0",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").empty()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.2.0",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.2.0",c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.closest("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},c.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one("bsTransitionEnd",e).emulateTransitionEnd(150):e(),f.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault(),b.call(a(this),"show")})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.2.0",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=a(document).height(),d=this.$target.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=b-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){null!=this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:b-this.$element.height()-h}))}}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},d.offsetBottom&&(d.offset.bottom=d.offsetBottom),d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
    \ No newline at end of file
    diff --git a/js/customizer.js b/js/customizer.js
    new file mode 100644
    index 000000000..373b9053a
    --- /dev/null
    +++ b/js/customizer.js
    @@ -0,0 +1,243 @@
    +(function() {
    +
    +var app = angular.module('customizer', ['ui.grid']);
    +
    +app.run(function($log, $rootScope, $http) {
    +});
    +
    +app.controller('Main', function($log, $http, $scope, less, Theme) {
    +  // Create grid
    +  $scope.gridOptions = {};
    +  $http.get('/data/100.json')
    +    .success(function(data) {
    +      $scope.gridOptions.data = data;
    +    });
    +
    +  // Fetch initial less file
    +  $http.get('/less/ui-grid.less')
    +    .success(function (data) {
    +      $scope.source = data;
    +      $scope.variables = less.parseVariables(data);
    +      $scope.trueDefaultVariables = angular.copy($scope.variables);
    +      $scope.defaultVariables = angular.copy($scope.trueDefaultVariables);
    +    });
    +
    +  // function() { return { a: $scope.source, b: $scope.compress }; }
    +  $scope.$watch('source', function(n, o) {
    +    if (n) {
    +      $scope.updateCSS();
    +    }
    +  });
    +
    +  // Get themes
    +  Theme.getThemes()
    +    .then(function (themes) {
    +      $scope.themes = themes.themeList;
    +      $scope.themeHash = themes.themeHash;
    +    });
    +
    +  // Reset variables to defaults
    +  $scope.resetVariables = function() {
    +    if ($scope.defaultCustomLess) {
    +      $scope.customLess = $scope.defaultCustomLess;
    +    }
    +
    +    $scope.variables = angular.copy($scope.defaultVariables);
    +    $scope.updateCSS();
    +  };
    +
    +  $scope.updateCSS = function(compress) {
    +    $scope.compress = compress;
    +    var fullSrc = $scope.source + ' ' + $scope.customLess;
    +    var src = less.replaceVariables(fullSrc, $scope.variables);
    +    less.process(src, $scope.compress)
    +      .then(
    +        function(css) {
    +          $scope.css = css;
    +          $scope.cssErr = null;
    +        },
    +        function(err) {
    +          $scope.cssErr = err;
    +        }
    +      );
    +  };
    +
    +  $scope.cssSize = function() {
    +    return (unescape(encodeURIComponent( $scope.css )).length / 1000).toFixed(2) + 'kB';
    +  };
    +
    +  $scope.setTheme = function(theme) {
    +    $scope.theme = theme;
    +    if (theme) {
    +      var themeData = $scope.themeHash[theme];
    +
    +      angular.forEach(themeData.variables, function (val, name) {
    +        var matches = _.where($scope.defaultVariables, { name: name });
    +        matches[0].value = val
    +        // $scope.defaultVariables[name] = val;
    +      });
    +
    +      if (themeData.customLess) {
    +        $scope.defaultCustomLess = themeData.customLess;
    +        $scope.customLess = themeData.customLess;
    +      }
    +
    +      $scope.resetVariables();
    +    }
    +    else {
    +      $scope.defaultVariables = angular.copy($scope.trueDefaultVariables);
    +      $scope.defaultCustomLess = '';
    +      $scope.customLess = '';
    +      $scope.resetVariables();
    +    }
    +  };
    +
    +  // $scope.clipboard = function() {
    +  //   client.setText($scope.css);
    +  // };
    +});
    +
    +app.service('Theme', function($q, $http) {
    +  return {
    +    getThemes: function() {
    +      var p = $q.defer();
    +
    +      $http.get('/customizer/themes/themes.json')
    +        .success(function (themeList) {
    +          var promises = [];
    +          var themes = {};
    +          angular.forEach(themeList, function(theme) {
    +            var tp = $http.get('/customizer/themes/' + theme + '.json');
    +            tp.success(function (data) {
    +              themes[theme] = data;
    +            });
    +            promises.push(tp);
    +          });
    +
    +          $q.all(promises)
    +            .then(function() {
    +              p.resolve({
    +                themeList: themeList,
    +                themeHash: themes
    +              });
    +            });
    +        });
    +
    +      return p.promise;
    +    }
    +  };
    +});
    +
    +app.service('less', function($log, $q) {
    +  var variableBlockRe = /\/\*-- VARIABLES.+?--\*\/([\s\S]+?)\/\*-- END VARIABLES.+?--\*\//m;
    +
    +  var sectionRe = /\/\*\*([\s\S])*?\*\//mg;
    +
    +  var variableRe = /(\@\w+)\: (.+?);/g;
    +
    +  var lessService = {
    +    parseVariables: function (src) {
    +      var groups = src.match(variableBlockRe);
    +      var variableText = groups[1];
    +
    +      // var sections = [];
    +      var variables = [];
    +
    +      // var sectionMatch;
    +      // while (sectionMatch = sectionRe.exec(variableText) {
    +      //   var sectionName = 
    +
    +        var varMatch;
    +        while (varMatch = variableRe.exec(variableText)) {
    +          variables.push({ name: varMatch[1], value: varMatch[2] });
    +        }
    +      // });
    +
    +      return variables;
    +    },
    +
    +    replaceVariableBlock: function(src, replacement) {
    +      return src.replace(variableBlockRe, replacement);
    +    },
    +
    +    replaceVariables: function(src, vars) {
    +      angular.forEach(vars, function (variable) {
    +        var re = new RegExp('(' + variable.name + ')\: (.+?);', 'g');
    +        src = src.replace(re, '$1: ' + variable.value + ';');
    +      });
    +
    +      return src;
    +    },
    +
    +    process: function (src, compress) {
    +      var comp;
    +      if (compress) {
    +        comp = true;
    +      }
    +
    +      var parser = new less.Parser();
    +
    +      var p = $q.defer();
    +      try {
    +        parser.parse(src, function(err, tree) {
    +          if (err) {
    +            p.reject(err.message);
    +          }
    +          else {
    +            // $log.debug('tree', tree);
    +            var css = tree.toCSS({ compress: comp });
    +            p.resolve(css);
    +          }
    +        });
    +      }
    +      catch (e) {
    +        // $log.debug('catch e', e);
    +        p.reject(e.message);
    +      }
    +
    +      return p.promise;
    +    }
    +  };
    +
    +  return lessService;
    +});
    +
    +app.directive('hoverSelect', function() {
    +  
    +  return {
    +    link: function(scope, elm, attrs) {
    +      elm.on('mouseover', function() {
    +        var startPos = 0, endPos = elm.val().length;
    +
    +         // Chrome / Firefox
    +        if(typeof(elm[0].selectionStart) != "undefined") {
    +          elm.focus();
    +          elm[0].selectionStart = startPos;
    +          elm[0].selectionEnd = endPos;
    +          return true;
    +        }
    +
    +        // IE
    +        if (document.selection && document.selection.createRange) {
    +            elm.focus();
    +            elm.select();
    +            var range = document.selection.createRange();
    +            range.collapse(true);
    +            range.moveEnd("character", endPos);
    +            range.moveStart("character", startPos);
    +            range.select();
    +            return true;
    +        }
    +      });
    +    }
    +  };
    +});
    +
    +app.filter('capitalize', function() {
    +    return function(input, scope) {
    +        if (input!=null)
    +            return input.substring(0,1).toUpperCase()+input.substring(1);
    +    };
    +});
    +
    +})();
    \ No newline at end of file
    diff --git a/less/ui-grid.less b/less/ui-grid.less
    new file mode 100644
    index 000000000..848e5a819
    --- /dev/null
    +++ b/less/ui-grid.less
    @@ -0,0 +1,1005 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20-5f155b2 - 2015-03-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +
    +
    +.ui-grid-render-container {
    +  position: inherit;
    +  // overflow: hidden;
    +
    +  .border-radius(0, @gridBorderRadius, @gridBorderRadius, 0);
    +
    +  // Prevent an outline from showing if we focus the render container element
    +  &:focus {
    +    outline: none;
    +  }
    +}
    +
    +.ui-grid-viewport {
    +  // overflow: auto; // TODO(c0bra): turn back on when virtual repeater is hooked up
    +  min-height: 20px;
    +  position: relative;
    +  overflow-y: scroll;
    +  -webkit-overflow-scrolling: touch;
    +
    +  // requested in #2312, IE9 compatibility with exporter.  I have no ability to test this, so assuming it's needed PaulL
    +  :focus {
    +    outline: none;
    +  }
    +}
    +
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top:1px; //to prevent canvas from absorbing the 1st rendered row's margin
    +}
    +
    +.ui-grid-row {
    +  //position: absolute;
    +  // border-bottom: 1px solid @borderColor;
    +
    +  &:nth-child(odd) .ui-grid-cell {
    +    background-color: @rowColorOdd; //rgb(253, 253, 253);
    +  }
    +
    +  &:nth-child(even) .ui-grid-cell {
    +    background-color: @rowColorEven;
    +  }
    +
    +  &:last-child .ui-grid-cell {
    +    border-bottom-color: @borderColor;
    +    border-bottom-style: solid;
    +
    +  }
    +}
    +
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +
    +  .ui-grid-top-panel-background;
    +  .border-radius(@gridBorderRadius);
    +  border: @gridBorderWidth solid @borderColor;
    +
    +  font-size: 2em;
    +  text-align: center;
    +
    +  > * {
    +    position: absolute;
    +    display: table;
    +    margin: auto 0;
    +    width: 100%;
    +    top: 0;
    +    bottom: 0;
    +    left: 0;
    +    right: 0;
    +    opacity: 0.66;
    +  }
    +}
    +
    +
    +.ui-grid-cell {
    +  overflow: hidden;
    +  // position: absolute;
    +  // position: relative; // NOTE: removing so border is visible
    +  float: left;
    +  background-color: inherit;
    +  border-right: @gridBorderWidth solid;
    +  border-color: @borderColor;
    +  box-sizing: border-box;
    +
    +  &:last-child {
    +    border-right: 0;
    +  }
    +}
    +
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +  // width: 100%;
    +}
    +
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height:0;
    +  display: none;
    +}
    +
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid @gridBorderWidth @borderColor;
    +}
    +
    +
    +.gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) {
    +  background: @color;
    +  background: -webkit-gradient(linear,
    +                               left bottom,
    +                               left top,
    +                               color-stop(0, @start),
    +                               color-stop(1, @stop));
    +  background: -ms-linear-gradient(bottom,
    +                                  @start,
    +                                  @stop);
    +  background: -moz-linear-gradient(center bottom,
    +                                   @start 0%,
    +                                   @stop 100%);
    +  background: -o-linear-gradient(@stop,
    +                                 @start);
    +  filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@stop,@start));
    +}
    +.bw-gradient(@color: #F5F5F5, @start: 0, @stop: 255) {
    +  background: @color;
    +  background: -webkit-gradient(linear,
    +                               left bottom,
    +                               left top,
    +                               color-stop(0, rgb(@start,@start,@start)),
    +                               color-stop(1, rgb(@stop,@stop,@stop)));
    +  background: -ms-linear-gradient(bottom,
    +                                  rgb(@start,@start,@start) 0%,
    +                                  rgb(@stop,@stop,@stop) 100%);
    +  background: -moz-linear-gradient(center bottom,
    +                                   rgb(@start,@start,@start) 0%,
    +                                   rgb(@stop,@stop,@stop) 100%);
    +  background: -o-linear-gradient(rgb(@stop,@stop,@stop),
    +                                 rgb(@start,@start,@start));
    +  filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",rgb(@stop,@stop,@stop),rgb(@start,@start,@start)));
    +}
    +.bordered(@top-color: #EEE, @right-color: #EEE, @bottom-color: #EEE, @left-color: #EEE) {
    +  border-top: solid 1px @top-color;
    +  border-left: solid 1px @left-color;
    +  border-right: solid 1px @right-color;
    +  border-bottom: solid 1px @bottom-color;
    +}
    +.drop-shadow(@x-axis: 0, @y-axis: 1px, @blur: 2px, @alpha: 0.1) {
    +  -webkit-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
    +  -moz-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
    +  box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
    +}
    +.rounded(@radius: 2px) {
    +  -webkit-border-radius: @radius;
    +  -moz-border-radius: @radius;
    +  border-radius: @radius;
    +}
    +.border-radius(@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) {
    +  -webkit-border-top-right-radius: @topright;
    +  -webkit-border-bottom-right-radius: @bottomright;
    +  -webkit-border-bottom-left-radius: @bottomleft;
    +  -webkit-border-top-left-radius: @topleft;
    +  -moz-border-radius-topright: @topright;
    +  -moz-border-radius-bottomright: @bottomright;
    +  -moz-border-radius-bottomleft: @bottomleft;
    +  -moz-border-radius-topleft: @topleft;
    +  border-top-right-radius: @topright;
    +  border-bottom-right-radius: @bottomright;
    +  border-bottom-left-radius: @bottomleft;
    +  border-top-left-radius: @topleft;
    +  .background-clip(padding-box);
    +}
    +.opacity(@opacity: 0.5) {
    +  -moz-opacity: @opacity;
    +  -khtml-opacity: @opacity;
    +  -webkit-opacity: @opacity;
    +  opacity: @opacity;
    +  @opperc: @opacity * 100;
    +  -ms-filter: ~"progid:DXImageTransform.Microsoft.Alpha(opacity=@{opperc})";
    +  filter: ~"alpha(opacity=@{opperc})";
    +}
    +.transition-duration(@duration: 0.2s) {
    +  -moz-transition-duration: @duration;
    +  -webkit-transition-duration: @duration;
    +  -o-transition-duration: @duration;
    +  transition-duration: @duration;
    +}
    +.transform(...) {
    +  -webkit-transform: @arguments;
    +  -moz-transform: @arguments;
    +  -o-transform: @arguments;
    +  -ms-transform: @arguments;
    +  transform: @arguments;
    +}
    +.rotation(@deg:5deg){
    +  .transform(rotate(@deg));
    +}
    +.scale(@ratio:1.5){
    +  .transform(scale(@ratio));
    +}
    +.transition(@type:all, @duration:0.2s, @ease:ease-out) {
    +  -webkit-transition: @type @duration @ease;
    +  -moz-transition: @type @duration @ease;
    +  -o-transition: @type @duration @ease;
    +  transition: @type @duration @ease;
    +}
    +.inner-shadow(@horizontal:0, @vertical:1px, @blur:2px, @alpha: 0.4) {
    +  -webkit-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
    +  -moz-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
    +  box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
    +}
    +.box-shadow(@arguments) {
    +  -webkit-box-shadow: @arguments;
    +  -moz-box-shadow: @arguments;
    +  box-shadow: @arguments;
    +}
    +.box-sizing(@sizing: border-box) {
    +  -ms-box-sizing: @sizing;
    +  -moz-box-sizing: @sizing;
    +  -webkit-box-sizing: @sizing;
    +  box-sizing: @sizing;
    +}
    +.user-select(@argument: none) {
    +  -webkit-user-select: @argument;
    +  -moz-user-select: @argument;
    +  -ms-user-select: @argument;
    +  user-select: @argument;
    +}
    +.columns(@colwidth: 250px, @colcount: 0, @colgap: 50px, @columnRuleColor: #EEE, @columnRuleStyle: solid, @columnRuleWidth: 1px) {
    +  -moz-column-width: @colwidth;
    +  -moz-column-count: @colcount;
    +  -moz-column-gap: @colgap;
    +  -moz-column-rule-color: @columnRuleColor;
    +  -moz-column-rule-style: @columnRuleStyle;
    +  -moz-column-rule-width: @columnRuleWidth;
    +  -webkit-column-width: @colwidth;
    +  -webkit-column-count: @colcount;
    +  -webkit-column-gap: @colgap;
    +  -webkit-column-rule-color: @columnRuleColor;
    +  -webkit-column-rule-style: @columnRuleStyle;
    +  -webkit-column-rule-width: @columnRuleWidth;
    +  column-width: @colwidth;
    +  column-count: @colcount;
    +  column-gap: @colgap;
    +  column-rule-color: @columnRuleColor;
    +  column-rule-style: @columnRuleStyle;
    +  column-rule-width: @columnRuleWidth;
    +}
    +.translate(@x:0, @y:0) {
    +  .transform(translate(@x, @y));
    +}
    +.background-clip(@argument: padding-box) {
    +  -moz-background-clip: @argument;
    +  -webkit-background-clip: @argument;
    +  background-clip: @argument;
    +}
    +
    +.ui-grid-footer-panel-background {
    +  .gradient(@headerBackgroundColor, @headerGradientStart, @headerGradientStop);
    +}
    +
    +@topPanelRadius: @gridBorderRadius - @gridBorderWidth;
    +.ui-grid-footer-panel {
    +  position: relative;
    +  // z-index: 1;
    +  // background-color: @darkGray; // #EAEAEA
    +  border-bottom: 1px solid @borderColor; // #D4D4D4
    +  border-top: 1px solid @borderColor;
    +  overflow: hidden;  // Disable so menus show up
    +  font-weight: bold;
    +
    +  // .gradient(@headerBackgroundColor, @headerGradientStart, @headerGradientStop);
    +  .ui-grid-footer-panel-background;
    +
    +  .border-radius(@topPanelRadius, 0, 0, @topPanelRadius);
    +}
    +
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +
    +.ui-grid-footer-viewport {
    +  overflow: hidden; // Disable so menus show up
    +}
    +
    +.ui-grid-footer-canvas {
    +  position: relative;
    +
    +  // Clearfix for floating header cells
    +  &:before, &:after {
    +    content: "";
    +    display: table;
    +    line-height: 0;
    +  }
    +
    +  &:after {
    +    clear:both;
    +  }
    +
    +  // .border-radius(@gridBorderRadius, 0, 0, @gridBorderRadius);
    +}
    +
    +.ui-grid-footer-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +
    +.ui-grid-footer-cell-row {
    +  display: table-row;
    +}
    +
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  // position: relative; // NOTE: removing so border is visible
    +  background-color: inherit;
    +  border-right: @gridBorderWidth solid;
    +  border-color: @borderColor;
    +  box-sizing: border-box;
    +  display: table-cell;
    +
    +  &:last-child {
    +    border-right: 0;
    +  }
    +}
    +
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +
    +  border: @gridBorderWidth solid  @borderColor;
    +  .border-radius(@gridBorderRadius);
    +
    +  &:hover {
    +    border: @gridBorderWidth solid  @borderColor;
    +  }
    +}
    +
    +@topPanelRadius: @gridBorderRadius - @gridBorderWidth;
    +
    +.ui-grid-group-panel {
    +  .gradient(@headerBackgroundColor, @headerGradientStart, @headerGradientStop);
    +  border-bottom: 1px solid @borderColor; // #D4D4D4
    +  .border-radius(@topPanelRadius, 0, 0, @topPanelRadius);
    +  min-height: 30px;
    +}
    +  .ui-grid-group-panel .hidden {
    +    display: none;
    +  }
    +  .ui-grid-group-panel .description {
    +    margin-top: 5px;
    +    margin-left: 5px;
    +  }
    +
    +.ui-grid-group-list {
    +  list-style-type: none;
    +  margin: 0;
    +  padding: 0;
    +}
    +
    +.ui-grid {
    +  border: @gridBorderWidth solid @borderColor;
    +  box-sizing: content-box; // If bootstrap (or another included library) makes the default sizing on element "border-box", then calculations get messed up
    +
    +  .rounded(@gridBorderRadius);
    +
    +  .transform(translateZ(0));
    +
    +}
    +
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar, .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: @gridBorderWidth;
    +}
    +
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: @headerVerticalBarColor;
    +}
    +
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: @verticalBarColor;
    +}
    +
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px; // TODO(c0bra): Should this be grid width? Test column resizing with custom grid border width
    +  width: @gridBorderWidth;
    +  background-color: @headerVerticalBarColor;
    +}
    +
    +// .ui-grid-vertical-bar-visible {
    +//   width: 1px;
    +//   background-color: @borderColor;
    +// }
    +
    +.ui-grid-clearfix {
    +  &:before, &:after {
    +    content: "";
    +    display: table;
    +  }
    +
    +  &:after {
    +    clear:both;
    +  }
    +}
    +
    +.ui-grid-invisible {
    +  visibility: hidden;;
    +}
    +
    +.ui-grid-top-panel-background {
    +  .gradient(@headerBackgroundColor, @headerGradientStart, @headerGradientStop);  
    +}
    +
    +@topPanelRadius: @gridBorderRadius - @gridBorderWidth;
    +
    +.ui-grid-header {
    +  border-bottom: 1px solid @borderColor;
    +  box-sizing: content-box;
    +}
    +
    +.ui-grid-top-panel {
    +    position: relative;
    +    // border-bottom: 1px solid @borderColor; // #D4D4D4
    +
    +    overflow: hidden;  // Disable so menus show up
    +    font-weight: bold;
    +
    +    // .gradient(@headerBackgroundColor, @headerGradientStart, @headerGradientStop);  
    +    .ui-grid-top-panel-background;
    +
    +    .border-radius(@topPanelRadius, 0, 0, @topPanelRadius);
    +}
    +
    +
    +.ui-grid-header-viewport {
    +  overflow: hidden; // Disable so menus show up
    +}
    +
    +.ui-grid-header-canvas {
    +
    +  // Clearfix for floating header cells
    +  &:before, &:after {
    +    content: "";
    +    display: table;
    +    line-height: 0;
    +  }
    +
    +  &:after {
    +    clear:both;
    +  }
    +
    +  // .border-radius(@gridBorderRadius, 0, 0, @gridBorderRadius);
    +}
    +
    +.ui-grid-header-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +
    +.ui-grid-header-cell-row {
    +  display: table-row;
    +}
    +
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  background-color: inherit;
    +  border-right: @gridBorderWidth solid;
    +  border-color: @headerVerticalBarColor;
    +  display: table-cell;
    +
    +  &:last-child {
    +    border-right: 0;
    +  }
    +
    +  .user-select(none);
    +
    +  // Default to width 0 so header height can calculate right. Otherwise
    +  //  the header cells will flow onto the next line of the header container
    +  //  and cause the header height to be calculated as twice the height
    +  //  it should be. The column widths are calculated dynamically
    +  width: 0;
    +
    +  .sortable {
    +    cursor: pointer;
    +  }
    +}
    +
    +// Make vertical bar in header row fill the height of the cell completely
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: @gridBorderWidth; // So it doesn't overlay the vertical bar
    +  top: 0;
    +  // bottom: 0;
    +  // .ui-grid-top-panel-background;
    +
    +  .ui-grid-icon-angle-down {
    +    vertical-align: sub;
    +  }
    +}
    +
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid {
    +  &.ng-hide-add, &.ng-hide-remove {
    +    .transition(all, 0.05s, linear);
    +    display: block !important;
    +  }
    +  
    +  &.ng-hide-add.ng-hide-add-active,
    +  &.ng-hide-remove {
    +    .transform(translateY(-100%));
    +  }
    +   
    +  &.ng-hide-add,
    +  &.ng-hide-remove.ng-hide-remove-active {
    +    .transform(translateY(0));
    +  }
    +}
    +
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  &.ng-hide-add, &.ng-hide-remove {
    +    .transition(all, 0.05s, linear);
    +    display: block !important;
    +  }
    +  
    +  &.ng-hide-add.ng-hide-add-active,
    +  &.ng-hide-remove {
    +    .transform(translateY(-100%));
    +  }
    +   
    +  &.ng-hide-add,
    +  &.ng-hide-remove.ng-hide-remove-active {
    +    .transform(translateY(0));
    +  }
    +}
    +
    +
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +
    +  .ui-grid-filter-button {
    +    position: absolute;
    +    top: 0;
    +    bottom: 0;
    +    right: 0;
    +
    +    [class^="ui-grid-icon"] {
    +      position: absolute;
    +      top: 50%;
    +      line-height: 32px;
    +      margin-top: -16px;
    +      right: 10px;
    +      opacity: 0.66;
    +
    +      &:hover {
    +        opacity: 1;
    +      }
    +    }
    +  }
    +}
    +
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +
    +  border: @gridBorderWidth solid  @borderColor;
    +  .border-radius(@gridBorderRadius);
    +
    +  &:hover {
    +    border: @gridBorderWidth solid  @borderColor;
    +  }
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('@{font-path}ui-grid.eot');
    +  src: url('@{font-path}ui-grid.eot#iefix') format('embedded-opentype'),
    +       url('@{font-path}ui-grid.woff') format('woff'),
    +       url('@{font-path}ui-grid.ttf?') format('truetype'),
    +       url('@{font-path}ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    + 
    + [class^="ui-grid-icon"]:before, [class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    + 
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    + 
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +     
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    + 
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    + 
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    + 
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: @headerBackgroundColor;
    +  border: @gridBorderWidth solid @borderColor;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +  .ui-grid-menu-mid {
    +    overflow-y: scroll;
    +    max-height: 300px;
    +    border: @gridBorderWidth solid @borderColor;
    +  }
    +}
    +
    +.ui-grid-menu {
    +  z-index: 2; // So it shows up over grid canvas
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: @headerBackgroundColor;
    +  border: @gridBorderWidth solid @borderColor;
    +  position: relative;
    +  white-space: nowrap;
    +
    +  .rounded(@gridBorderRadius);
    +  .box-shadow(e("0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)"));
    +}
    +
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +
    +  li {
    +    padding: 8px;
    +    cursor: pointer;
    +
    +    // Show a shadow when hovering over a menu item
    +    &:hover {
    +      // background-color: negation(@headerBackgroundColor, #fff);
    +      .inner-shadow(@vertical: 0, @blur: 14px, @alpha: 0.2);
    +    }
    +
    +    &.ui-grid-menu-item-active {
    +      .inner-shadow(@vertical: 0, @blur: 14px, @alpha: 0.2);
    +      background-color: @selectedColor;
    +    }
    +  }
    +
    +  // Show a bottom border on all but the last menu item
    +  li:not(:last-child) {
    +    border-bottom: @gridBorderWidth solid @borderColor;
    +  }
    +}
    +
    +.ui-grid[dir=rtl] {
    +
    +  .ui-grid-header-cell,
    +  .ui-grid-footer-cell,
    +  .ui-grid-cell {
    +    float: right !important;
    +  }
    +
    +  .ui-grid-column-menu-button {
    +    position: absolute;
    +    left: 1px;
    +    top: 0;
    +    right: inherit;
    +  }
    +
    +  .ui-grid-cell:first-child,
    +  .ui-grid-header-cell:first-child,
    +  .ui-grid-footer-cell:first-child {
    +    border-right: 0;
    +  }
    +
    +  .ui-grid-cell:last-child, .ui-grid-header-cell:last-child  {
    +    border-right: @gridBorderWidth solid @borderColor;
    +    border-left: 0;
    +  }
    +
    +  .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +  .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +  .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +    width: 0;
    +  }
    +
    +  .ui-grid-menu-button {
    +    z-index: 2;
    +    position: absolute;
    +    left: 0;
    +    right: auto;
    +    background: @headerBackgroundColor;
    +    border: @gridBorderWidth solid @borderColor;
    +    cursor: pointer;
    +    min-height: 27px;
    +    font-weight: normal;
    +  }
    +
    +  .ui-grid-menu-button .ui-grid-menu {
    +    left: 0;
    +    right: auto;
    +  }
    +
    +  // Position filter-cancel button on the left for rtl grids
    +  .ui-grid-filter-container .ui-grid-filter-button {
    +    right: initial;
    +    left: 0;
    +
    +    [class^="ui-grid-icon"] {
    +      right: initial;
    +      left: 10px;
    +    }
    +  }
    +
    +}
    +// .ui-grid-sortarrow {
    +//   fill: @sortArrowBackgroundColor; 
    +//   stroke: @sortArrowBorderColor; 
    +//   stroke-linejoin:miter;
    +// }
    +
    +// .ui-grid-sortarrow.down {
    +//   -webkit-transform: rotate(180deg);
    +//   -moz-transform: rotate(180deg);
    +//   -ms-transform: rotate(180deg);
    +//   -o-transform: rotate(180deg);
    +//   transform: rotate(180deg); 
    +// }
    +
    +
    +@sortArrowWidth: 20px;
    +
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: @sortArrowWidth;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +
    +  &.down {
    +    .transform(rotate(180deg));
    +  }
    +}
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/**
    +* @section Grid styles
    +*/
    +@gridBorderWidth: 1px;
    +@gridBorderRadius: 0px;
    +@borderColor: #d4d4d4;
    +
    +
    +/**
    +* @section Header styles
    +*/
    +
    +/** @description Colors for header gradient */
    +@headerBackgroundColor: #f3f3f3;
    +@headerGradientStart: #eee;
    +@headerGradientStop: #fff;
    +@headerVerticalBarColor: @borderColor;
    +
    +/**
    +* @section Grid body styles
    +*/
    +
    +/** @description Colors used for row alternation */
    +@verticalBarColor: @borderColor;
    +@rowColorEven: #f3f3f3;
    +@rowColorOdd: #fdfdfd;
    +
    +// TODO: colors for buttons
    +
    +/**
    +* @section Sort arrow colors
    +*/
    +
    +@sortArrowBackgroundColor: #aaaaaa;
    +@sortArrowBorderColor: #777777;
    +
    +
    +// TODO: color for menu background
    +
    +@rowSelected: #C9DDE1;
    +@rowSavingForeground: #848484;
    +@rowErrorForeground: #FF0000;
    +@rowDirtyForeground: #610B38;
    +
    +// TODO: color for cell selections
    +@focusedCell: #b3c4c7;
    +
    +// Color to use for enabled or selected settings/items/cells, etc. Should probably override the one above
    +@selectedColor: #cecece;
    +
    +/**
    +* @section Scrollbar styles
    +*/
    +@scrollbarBackground: darken(@rowColorEven, 15%);
    +@scrollbarBackgroundHover: darken(@scrollbarBackground, 15%);
    +@scrollbarBackgroundScrolling: darken(@scrollbarBackgroundHover, 15%);
    +@scrollbarWidth: 10px;
    +@scrollbarBorderRadius: 2px;
    +@scrollbarShadow: 0 0 0px #fff;
    +@scrollbarBorder: 1px solid darken(@scrollbarBackground, 15%);
    +@scrollbarBorderScrolling: 1px solid darken(@scrollbarBackgroundScrolling, 15%);
    +
    +//Border to be applied to editors when the input value or invalid
    +@invalidValueBorder: 1px solid rgb(252, 143, 143);
    +@validValueBorder: 1px solid @borderColor;
    +
    +/**
    +* @section font library path
    +*/
    +@font-path: '';
    +
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    \ No newline at end of file
    diff --git a/package.json b/package.json
    new file mode 100644
    index 000000000..f72fb3205
    --- /dev/null
    +++ b/package.json
    @@ -0,0 +1,20 @@
    +{
    +  "name": "ui-grid.info",
    +  "private": true,
    +  "version": "0.0.0",
    +  "description": "ui-grid.info",
    +  "dependencies": {
    +    "grunt-contrib-connect": "^0.9.0",
    +    "grunt": "^0.4.5",
    +    "grunt-contrib-watch": "^0.6.1",
    +    "grunt-contrib-stylus": "^0.20.0",
    +    "grunt-shell": "^1.1.2"
    +  },
    +  "devDependencies": {},
    +  "repository": {
    +    "type": "git",
    +    "url": "https://github.com/angular-ui/ui-grid.info.git"
    +  },
    +  "author": "",
    +  "license": "MIT"
    +}
    diff --git a/params.json b/params.json
    new file mode 100644
    index 000000000..a92b6cde4
    --- /dev/null
    +++ b/params.json
    @@ -0,0 +1 @@
    +{"name":"Ui-grid.info","tagline":"Website for ui-grid","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `<a>` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.css b/release/3.0.0-RC.18-7774d30/ui-grid.css
    new file mode 100644
    index 000000000..ffaf44185
    --- /dev/null
    +++ b/release/3.0.0-RC.18-7774d30/ui-grid.css
    @@ -0,0 +1,1313 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-7774d30 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top: 1px;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  overflow-y: scroll;
    +  max-height: 300px;
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child {
    +  border-left: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.eot b/release/3.0.0-RC.18-7774d30/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-RC.18-7774d30/ui-grid.eot differ
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.js b/release/3.0.0-RC.18-7774d30/ui-grid.js
    new file mode 100644
    index 000000000..eb9507018
    --- /dev/null
    +++ b/release/3.0.0-RC.18-7774d30/ui-grid.js
    @@ -0,0 +1,19668 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-7774d30 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart', // For any item being dragged
    +      COLUMN_HEADER_CLICK: 'uiGridColumnHeaderClick'
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      PG_UP: 33,
    +      PG_DOWN: 34,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column',
    +      OPTIONS: 'options'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1
    +      //WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var initColClass = $scope.col.getColClass(false);
    +          $elm.addClass(initColClass);
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          // watch the col and row to see if they change - which would indicate that we've scrolled or sorted or otherwise
    +          // changed the row/col that this cell relates to, and we need to re-evaluate cell classes and maybe other things
    +          var cellChangeFunction = function( n, o ){
    +            if ( n !== o ) {
    +              if ( classAdded || $scope.col.cellClass ){
    +                updateClass();
    +              }
    +
    +              // See if the column's internal class has changed
    +              var newColClass = $scope.col.getColClass(false);
    +              if (newColClass !== initColClass) {
    +                $elm.removeClass(initColClass);
    +                $elm.addClass(newColClass);
    +                initColClass = newColClass;
    +              }
    +            }
    +          };
    +
    +          // TODO(c0bra): Turn this into a deep array watch
    +          var colWatchDereg = $scope.$watch( 'col', cellChangeFunction );
    +          var rowWatchDereg = $scope.$watch( 'row', cellChangeFunction );
    +          
    +          
    +          var deregisterFunction = function() {
    +            dataChangeDereg();
    +            colWatchDereg();
    +            rowWatchDereg(); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +          $elm.on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +        $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            var footerTemplate = ($scope.grid.options.gridFooterTemplate) ? $scope.grid.options.gridFooterTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 'ScrollEvent',
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, ScrollEvent) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            var initColClass = $scope.col.getColClass(false);
    +            $elm.addClass(initColClass);
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +              
    +              var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
    +              $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
    +            };
    +
    +            $scope.$watch('col', function (n, o) {
    +              if (n !== o) {
    +                // See if the column's internal class has changed
    +                var newColClass = $scope.col.getColClass(false);
    +                if (newColClass !== initColClass) {
    +                  $elm.removeClass(initColClass);
    +                  $elm.addClass(newColClass);
    +                  initColClass = newColClass;
    +                }
    +              }
    +            });
    +  
    +            updateClass();
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(event) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (event.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ($scope.sortable || $scope.colMenu) {
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +
    +              var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
    +              $contentsElm.on(downEvent, function(event) {
    +                event.stopPropagation();
    +
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +
    +                uiGridCtrl.fireEvent(uiGridConstants.events.COLUMN_HEADER_CLICK, {event: event, columnName: $scope.col.colDef.name});
    +              });
    +        
    +              var upEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'mouseup';
    +              $contentsElm.on(upEvent, function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });
    +            }
    +
    +
    +            $scope.toggleMenu = function(event) {
    +              event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
    +              $contentsElm.on(clickEvent, function(event) {
    +                event.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(event);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh()
    +                      .then(function () {
    +                        if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                          var scrollEvent = new ScrollEvent(uiGridCtrl.grid,null,null,'uiGridHeaderCell.toggleMenu');
    +                          scrollEvent.y.percentage = uiGridCtrl.prevScrollArgs.y.percentage;
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +                      });
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              //if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +              //  availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              //}
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              //if (grid.verticalScrollbarWidth) {
    +              //  canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              //}
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', 'uiGridConstants', function( gridUtil, i18nService, uiGridConstants ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +      gridCol.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      if (uiGridCtrl) {
    +       $scope.$on('$destroy', uiGridCtrl.grid.api.core.on.scrollEvent($scope, applyHideMenu ));
    +      }
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil', 'ScrollEvent',
    +    function($timeout, $document, uiGridConstants, gridUtil, ScrollEvent) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              grid.api.core.on.scrollEvent($scope,scrollHandler);
    +            }
    +
    +            function scrollHandler (args) {
    +              // exit if not for this grid
    +              if (args.grid && args.grid.id !== grid.id){
    +                return;
    +              }
    +
    +              
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var newScrollTop = args.getNewScrollTop(rowContainer,containerCtrl.viewport);
    +
    +                //only set scrollTop if we coming from something other than viewPort scrollBar or
    +                //another column container
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll ||
    +                    args.sourceColContainer !== colContainer) {
    +                  containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                }
    +
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +                var newScrollLeft = args.getNewScrollLeft(colContainer,containerCtrl.viewport);
    +
    +                // Make the current horizontal scroll position available in the $scope
    +                $scope.newScrollLeft = newScrollLeft;                
    +
    +                if (containerCtrl.headerViewport) {
    +                  containerCtrl.headerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  containerCtrl.footerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                //scroll came from somewhere else, so the viewport must be positioned
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll) {
    +                  containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                }
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +
    +              var newEvent = gridUtil.normalizeWheelEvent(evt);
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerMouseWheel);
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / rowContainer.getVerticalScrollLength();
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = gridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +
    +              // todo: this isn't working when scrolling down.  it works fine for up.  tested on Chrome
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +                if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1 && containerCtrl.viewport[0].scrollTop !== 0 ) ||
    +                    (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +                  evt.preventDefault();
    +              }
    +
    +              scrollEvent.fireThrottledScrollingEvent();
    +            });
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / rowContainer.getVerticalScrollLength();
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              scrollEvent.fireScrollingEvent();
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              //function decelerate() {
    +              //  $timeout(function() {
    +              //    var args = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +              //
    +              //    if (scrollYLength !== 0) {
    +              //      var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / rowContainer.getVerticalScrollLength();
    +              //
    +              //      args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +              //    }
    +              //
    +              //    if (scrollXLength !== 0) {
    +              //      var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              //      args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +              //    }
    +              //
    +              //    uiGridCtrl.fireScrollingEvent(args);
    +              //
    +              //    decelerateCount = decelerateCount -1;
    +              //    scrollYLength = scrollYLength / 2;
    +              //    scrollXLength = scrollXLength / 2;
    +              //
    +              //    if (decelerateCount > 0) {
    +              //      decelerate();
    +              //    }
    +              //    else {
    +              //      uiGridCtrl.scrollbars.forEach(function (sbar) {
    +              //        sbar.removeClass('ui-grid-scrollbar-visible');
    +              //        sbar.removeClass('ui-grid-scrolling');
    +              //      });
    +              //    }
    +              //  }, decelerateInterval);
    +              //}
    +
    +              // decelerate();
    +            }
    +
    +            if (gridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +
    +              //add additional height for scrollbar on left and right container
    +              if ($scope.containerId !== 'body') {
    +                canvasHeight += grid.scrollbarHeight;
    +              }
    +
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + (canvasWidth + grid.scrollbarWidth) + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + grid.scrollbarWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          //gridUtil.logDebug('margin-top ' + hiddenRowWidth );
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            // Function for attaching the template to this scope
    +            var clonedElement, cloneScope;
    +            function compileTemplate() {
    +              $scope.row.getRowTemplateFn.then(function (compiledElementFn) {
    +                // var compiledElementFn = $scope.row.compiledElementFn;
    +
    +                // Create a new scope for the contents of this row, so we can destroy it later if need be
    +                var newScope = $scope.$new();
    +
    +                compiledElementFn(newScope, function (newElm, scope) {
    +                  // If we already have a cloned element, we need to remove it and destroy its scope
    +                  if (clonedElement) {
    +                    clonedElement.remove();
    +                    cloneScope.$destroy();
    +                  }
    +
    +                  // Empty the row and append the new element
    +                  $elm.empty().append(newElm);
    +
    +                  // Save the new cloned element and scope
    +                  clonedElement = newElm;
    +                  cloneScope = newScope;
    +                });
    +              });
    +            }
    +
    +            // Initially attach the compiled template to this scope
    +            compileTemplate();
    +
    +            // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
    +            $scope.$watch('row.getRowTemplateFn', function (newFunc, oldFunc) {
    +              if (newFunc !== oldFunc) {
    +                compileTemplate();
    +              }
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent',
    +    function(gridUtil, ScrollEvent) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              grid.flagScrollingHorizontally();
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              if (horizScrollLength !== 0) {
    +                horizScrollPercentage = newScrollLeft / horizScrollLength;
    +              }
    +              else {
    +                horizScrollPercentage = 0;
    +              }
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              grid.flagScrollingVertically();
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +
    +              var vertScrollLength = rowContainer.getVerticalScrollLength();
    +
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
    +              scrollEvent.newScrollLeft = newScrollLeft;
    +              scrollEvent.newScrollTop = newScrollTop;
    +              if ( horizScrollPercentage > -1 ){
    +                scrollEvent.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                scrollEvent.y = { percentage: vertScrollPercentage };
    +              }
    +              scrollEvent.fireScrollingEvent();
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +
    +      //assign $scope.$parent if appScope not already assigned
    +      self.grid.appScope = self.grid.appScope || $scope.$parent;
    +
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns({ orderByColumnDefs: true })
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '='
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.calcFooterHeight();
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.refreshCanvas(true);
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth || col.width || 0;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 || !myWidth ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +
    +    /**
    +     * @ngdoc object
    +     * @name appScope
    +     * @propertyOf ui.grid.class:Grid
    +     * @description reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +     * <br/>
    +     * use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference
    +     */
    +    self.appScope = self.options.appScopeProvider;
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +
    +
    +    self.footerHeight = self.calcFooterHeight();
    +
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +  
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +    }, 300);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +    }, 300);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +
    +    self.scrollbarHeight = 0;
    +    self.scrollbarWidth = 0;
    +    if (self.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarHeight = gridUtil.getScrollbarWidth();
    +    }
    +
    +    if (self.options.enableVerticalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarWidth = gridUtil.getScrollbarWidth();
    +    }
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +
    +    self.registerStyleComputation({
    +      priority: 10,
    +      func: self.getFooterStyles
    +    });
    +  };
    +
    +   Grid.prototype.calcFooterHeight = function () {
    +     if (!this.hasFooter()) {
    +       return 0;
    +     }
    +
    +     var height = 0;
    +     if (this.options.showGridFooter) {
    +       height += this.options.gridFooterHeight;
    +     }
    +
    +     if (this.options.showColumnFooter) {
    +       height += this.options.columnFooterHeight;
    +     }
    +
    +     return height;
    +   };
    +
    +   Grid.prototype.getFooterStyles = function () {
    +     var style = '.grid' + this.id + ' .ui-grid-footer-aggregates-row { height: ' + this.options.columnFooterHeight + 'px; }';
    +     style += ' .grid' + this.id + ' .ui-grid-footer-info { height: ' + this.options.gridFooterHeight + 'px; }';
    +     return style;
    +   };
    +
    +  Grid.prototype.hasFooter = function () {
    +   return this.options.showGridFooter || this.options.showColumnFooter;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * - when the options watch fires, the OPTIONS callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * - OPTIONS calls OPTIONS and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +   * ALL 
    +   * @returns {function} deregister function - a function that can be called to deregister this callback
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types, _this) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types, _this:_this };
    +    
    +    var self = this;
    +    var deregisterFunction = function() {
    +      delete self.dataChangeCallbacks[uid];
    +    };
    +    return deregisterFunction;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        if (callback._this) {
    +           callback.callback.apply(callback._this,this);
    +        }
    +        else {
    +          callback.callback( this );
    +        }
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ||
    +         type === constants.OPTIONS ){
    +      this.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.refresh();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @param {object} options  An object contains options to use when building columns
    +   *
    +   * * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
    +   *
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns(opts) {
    +    var options = {
    +      orderByColumnDefs: false
    +    };
    +
    +    angular.extend(options, opts);
    +
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        // tell updateColumnDef that the column was pre-existing
    +        col.updateColumnDef(colDef, false);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    /*** Reorder columns if necessary ***/
    +    if (!!options.orderByColumnDefs) {
    +      // Create a shallow copy of the columns as a cache
    +      var columnCache = self.columns.slice(0);
    +
    +      // We need to allow for the "row headers" when mapping from the column defs array to the columns array
    +      //   If we have a row header in columns[0] and don't account for it   we'll overwrite it with the column in columnDefs[0]
    +
    +      // Go through all the column defs
    +      for (i = 0; i < self.options.columnDefs.length; i++) {
    +        // If the column at this index has a different name than the column at the same index in the column defs...
    +        if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
    +          // Replace the one in the cache with the appropriate column
    +          columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
    +        }
    +        else {
    +          // Otherwise just copy over the one from the initial columns
    +          columnCache[i + headerOffset] = self.columns[i + headerOffset];
    +        }
    +      }
    +
    +      // Empty out the columns array, non-destructively
    +      self.columns.length = 0;
    +
    +      // And splice in the updated, ordered columns from the cache
    +      Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
    +    }
    +
    +    return $q.all(builderPromises).then(function(){
    +      if (self.rows.length > 0){
    +        self.assignTypes();
    +      }
    +    });
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    var self = this;
    +
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      // See if the column name already exists:
    +      var foundName = self.getColumn(colDef.field);
    +
    +      // If a column with this name already  exists, we will add an incrementing number to the end of the new column name
    +      if (foundName) {
    +        // Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
    +        var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
    +
    +        var foundColumns = self.columns.filter(function (column) {
    +          // Test against the displayName, as that's what'll have the incremented number
    +          return nameRE.test(column.displayName);
    +        })
    +        // Sort the found columns by the end-number
    +        .sort(function (a, b) {
    +          if (a === b) {
    +            return 0;
    +          }
    +          else {
    +            var numA = a.match(nameRE)[1];
    +            var numB = b.match(nameRE)[1];
    +
    +            return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
    +          }
    +        });
    +
    +        // Not columns found, so start with number "2"
    +        if (foundColumns.length === 0) {
    +          colDef.name = colDef.field + '2';
    +        }
    +        else {
    +          // Get the number from the final column
    +          var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
    +
    +          // Make sure to parse to an int
    +          lastNum = parseInt(lastNum, 10);
    +
    +          // Add 1 to the number from the last column and tack it on to the field to be the name for this new column 
    +          colDef.name = colDef.field + (lastNum + 1);
    +        }
    +      }
    +      // ... otherwise just use the field as the column name
    +      else {
    +        colDef.name = colDef.field;
    +      }
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +//        if (wasEmpty) {
    +           self.assignTypes();
    +//        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.canvasHeightShouldUpdate = true;
    +      
    +      if ( typeof(container.visibleRowCache) === 'undefined' ){
    +        container.visibleRowCache = [];  
    +      } else {
    +        container.visibleRowCache.length = 0;  
    +      }
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +    self.api.core.raise.rowsRendered(this.api);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name updateCanvasHeight
    +   * @methodOf ui.grid.class:Grid
    +   * @description flags all render containers to update their canvas height
    +   */
    +  Grid.prototype.updateCanvasHeight = function updateCanvasHeight() {
    +    var self = this;
    +
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +        container.canvasHeightShouldUpdate = true;
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    //}
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    //gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    //gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    //}
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol && !col.colDef.suppressRemoveSort) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(null, container.prevScrolltopPercentage);
    +      container.adjustColumns(null, container.prevScrollleftPercentage);
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasLeftContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if leftContainer has columns
    +     */
    +    Grid.prototype.hasLeftContainerColumns = function () {
    +      return this.hasLeftContainer() && this.renderContainers.left.renderedColumns.length > 0;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasRightContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if rightContainer has columns
    +     */
    +    Grid.prototype.hasRightContainerColumns = function () {
    +      return this.hasRightContainer() && this.renderContainers.right.renderedColumns.length > 0;
    +    };
    +
    +
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name rowsRendered
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the cache of visible rows is changed.
    +           */
    +          this.registerEvent( 'core', 'rowsRendered' );
    +
    +
    +          /**
    +           * @ngdoc event
    +           * @name scrollEvent
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised on a scroll Event.  Called frequently so be careful what you do with it
    +           */
    +          this.registerEvent( 'core', 'scrollEvent' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name canvasHeightChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised when the canvas height has changed
    +           * <br/>
    +           * arguments: oldHeight, newHeight
    +           */
    +          this.registerEvent( 'core', 'canvasHeightChanged');
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.eventId, l.handler, self.grid, l._this);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * <br>
    +         * .raise.eventName() - takes no arguments
    +         * <br/>
    +         * <br/>
    +         * .on.eventName(scope, callBackFn, _this)
    +         * <br/>
    +         * scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +         * <br/>
    +         * callBackFn - The function to call
    +         * <br/>
    +         * _this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +         * <br/>
    +         * .on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +         * will be removed when the scope is destroyed.
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$emit.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler, _this) {
    +            var deregAngularOn = registerEventWithAngular(eventId, handler, self.grid, _this);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: deregAngularOn, eventId: eventId, scope: scope, _this:_this};
    +            self.listeners.push(listener);
    +
    +            var removeListener = function(){
    +              listener.dereg();
    +              var index = self.listeners.indexOf(listener);
    +              self.listeners.splice(index,1);
    +            };
    +
    +            //destroy tracking when scope is destroyed
    +            scope.$on('$destroy', function() {
    +              removeListener();
    +            });
    +
    +            return removeListener;
    +          };
    +        };
    +
    +        function registerEventWithAngular(eventId, handler, grid, _this) {
    +          return $rootScope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(_this ? _this : grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} _this binds callBackFn 'this' to _this.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, _this) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(_this || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} _this binds this to _this for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, _this) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, _this);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef, true);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         term: 'aa',
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...',
    +   *         flags: { caseSensitive: false }
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...',
    +   *     flags: { caseSensitive: false }
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {boolean} isNew whether the column is being newly created, if not
    +   * we're updating an existing column, and some items such as the sort shouldn't
    +   * be copied down
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef, isNew) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it, but only if this is a newly added column
    +    if ( isNew ){
    +      self.setPropertyOrDefault(colDef, 'sort');
    +    }
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * 
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * - flags: only flag currently available is `caseSensitive`, set to false if you don't want
    +     * case sensitive matching
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       term: 'xx',
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...',
    +     *       flags: { caseSensitive: false }
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    // Only set filter if this is a newly added column, if we're updating an existing
    +    // column then we don't want to put the default filter back if the user may have already
    +    // removed it.
    +    if ( isNew ) {
    +      self.setPropertyOrDefault(colDef, 'filter');
    +      self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +    }
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>
    +   * app.config(function($provide){
    +   *   $provide.decorator('GridOptions',function($delegate){
    +   *     var gridOptions;
    +   *     gridOptions = angular.copy($delegate);
    +   *     gridOptions.initialize = function(options) {
    +   *       var initOptions;
    +   *       initOptions = $delegate.initialize(options);
    +   *       initOptions.enableColumnMenus = false;
    +   *       return initOptions;
    +   *     };
    +   *     return gridOptions;
    +   *   });
    +   * });
    +   * </pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      /**
    +       * @ngdoc function
    +       * @name onRegisterApi
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description A callback that returns the gridApi once the grid is instantiated, which is 
    +       * then used to interact with the grid programatically.
    +       * 
    +       * Note that the gridApi.core.renderingComplete event is identical to this 
    +       * callback, but has the advantage that it can be called from multiple places
    +       * if needed
    +       * 
    +       * @example
    +       * <pre>
    +       *   $scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +       *     $scope.gridApi = gridApi;
    +       *     $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +       *   };
    +       * </pre>
    +       * 
    +       */
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showGridFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       * The footer display Total Rows and Visible Rows (filtered rows)
    +       */
    +      baseOptions.showGridFooter = baseOptions.showGridFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name showColumnFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the column footer, defaults to false
    +       * The column footer displays column aggregates
    +       */
    +      baseOptions.showColumnFooter = baseOptions.showColumnFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name columnFooterHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer rows (column footer and grid footer) in pixels
    +       *
    +       */
    +      baseOptions.columnFooterHeight = typeof(baseOptions.columnFooterHeight) !== "undefined" ? baseOptions.columnFooterHeight : 30;
    +      baseOptions.gridFooterHeight = typeof(baseOptions.gridFooterHeight) !== "undefined" ? baseOptions.gridFooterHeight : 30;
    +
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +
    +      /**
    +       * @ngdoc object
    +       * @name appScopeProvider
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +       * this property allows you to assign any reference you want to grid.appScope
    +       */
    +      baseOptions.appScopeProvider = baseOptions.appScopeProvider || null;
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeightShouldUpdate
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description flag to signal that container should recalculate the canvas size
    +     */
    +    self.canvasHeightShouldUpdate = true;
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeight
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description last calculated canvas height value
    +     */
    +    self.$$canvasHeight = 0;
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCanvasHeight
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false
    +   * @returns {number} total height of all the visible rows in the container
    +   */
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    if (!self.canvasHeightShouldUpdate) {
    +      return self.$$canvasHeight;
    +    }
    +
    +    var oldCanvasHeight = self.$$canvasHeight;
    +
    +    self.$$canvasHeight =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      self.$$canvasHeight += row.height;
    +    });
    +
    +
    +    self.canvasHeightShouldUpdate = false;
    +
    +    self.grid.api.core.raise.canvasHeightChanged(oldCanvasHeight, self.$$canvasHeight);
    +
    +    return self.$$canvasHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() {
    +    return this.getCanvasHeight() - this.getViewportHeight();
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    //if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +    //  ret = ret - self.verticalScrollbarWidth;
    +    //}
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getVerticalScrollLength();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
    +        // Have we hit the threshold going down?
    +        if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +        //Have we hit the threshold going up?
    +        if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      /* Commented the following lines because otherwise the moved column wasn't visible immediately on the new position
    +       * in the case of many columns with horizontal scroll, one had to scroll left or right and then return in order to see it
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }*/
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    //if (self.grid.verticalScrollbarWidth) {
    +    //  canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  GridRenderContainer.prototype.getViewPortStyle = function () {
    +    var self = this;
    +    var styles = {};
    +
    +    if (self.name === 'body') {
    +      styles['overflow-x'] = self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +      if (!self.grid.isRTL()) {
    +        if (self.grid.hasRightContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +      else {
    +        if (self.grid.hasLeftContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +    }
    +    else if (self.name === 'left') {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +    else {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = !self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +
    +    return styles;
    +
    +
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +
    +    this.$$height = grid.options.rowHeight;
    +
    +  }
    +
    +    /**
    +     *  @ngdoc object
    +     *  @name height
    +     *  @propertyOf  ui.grid.class:GridRow
    +     *  @description height of each individual row. changing the height will flag all
    +     *  row renderContainers to recalculate their canvas height
    +     */
    +    Object.defineProperty(GridRow.prototype, 'height', {
    +      get: function() {
    +        return this.$$height;
    +      },
    +      set: function(height) {
    +        if (height !== this.$$height) {
    +          this.grid.updateCanvasHeight();
    +          this.$$height = height;
    +        }
    +      }
    +    });
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +    GridRow.prototype.getQualifiedColField = function(col) {
    +      return 'row.' + this.getEntityQualifiedColField(col);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  angular.module('ui.grid')
    +    .factory('ScrollEvent', ['gridUtil', function (gridUtil) {
    +
    +      /**
    +       * @ngdoc function
    +       * @name ui.grid.class:ScrollEvent
    +       * @description Model for all scrollEvents
    +       * @param {Grid} grid that owns the scroll event
    +       * @param {GridRenderContainer} sourceRowContainer that owns the scroll event. Can be null
    +       * @param {GridRenderContainer} sourceColContainer that owns the scroll event. Can be null
    +       * @param {string} source the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName
    +       */
    +      function ScrollEvent(grid, sourceRowContainer, sourceColContainer, source) {
    +        var self = this;
    +        if (!grid) {
    +          throw new Error("grid argument is required");
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name grid
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description A reference back to the grid
    +         */
    +         self.grid = grid;
    +
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name entity
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description the source of the scroll event. limited to values from uiGridConstants.scrollEventSources
    +         */
    +        self.source = source;
    +
    +        self.sourceRowContainer = sourceRowContainer;
    +        self.sourceColContainer = sourceColContainer;
    +
    +        self.newScrollLeft = null;
    +        self.newScrollTop = null;
    +        self.x = null;
    +        self.y = null;
    +
    +
    +        /**
    +         *  @ngdoc function
    +         *  @name fireThrottledScrollingEvent
    +         *  @methodOf  ui.grid.class:ScrollEvent
    +         *  @description fires a throttled event using grid.api.core.raise.scrollEvent
    +         */
    +        self.fireThrottledScrollingEvent = gridUtil.throttle(function() {
    +          self.grid.api.core.raise.scrollEvent(self);
    +        }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      }
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name fireScrollingEvent
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description fires an event using grid.api.core.raise.scrollEvent
    +       */
    +      ScrollEvent.prototype.fireScrollingEvent = function() {
    +        this.grid.api.core.raise.scrollEvent(this);
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollLeft
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollLeft property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollLeft = function(colContainer, viewport){
    +        var self = this;
    +
    +        if (!self.newScrollLeft){
    +          var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +          var oldScrollLeft = gridUtil.normalizeScrollLeft(viewport);
    +
    +          var scrollXPercentage;
    +          if (typeof(self.x.percentage) !== 'undefined' && self.x.percentage !== undefined) {
    +            scrollXPercentage = self.x.percentage;
    +          }
    +          else if (typeof(self.x.pixels) !== 'undefined' && self.x.pixels !== undefined) {
    +            scrollXPercentage = self.x.percentage = (oldScrollLeft + self.x.pixels) / scrollWidth;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event X axis");
    +          }
    +
    +          return Math.max(0, scrollXPercentage * scrollWidth);
    +        }
    +
    +        return self.newScrollLeft;
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollTop
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollTop property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollTop = function(rowContainer, viewport){
    +        var self = this;
    +
    +
    +        if (!self.newScrollTop){
    +          var scrollLength = rowContainer.getVerticalScrollLength();
    +
    +          var oldScrollTop = viewport[0].scrollTop;
    +
    +          var scrollYPercentage;
    +          if (typeof(self.y.percentage) !== 'undefined' && self.y.percentage !== undefined) {
    +            scrollYPercentage = self.y.percentage;
    +          }
    +          else if (typeof(self.y.pixels) !== 'undefined' && self.y.pixels !== undefined) {
    +            scrollYPercentage = self.y.percentage = (oldScrollTop + self.y.pixels) / scrollLength;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +          }
    +
    +          return Math.max(0, scrollYPercentage * scrollLength);
    +        }
    +
    +        return self.newScrollTop;
    +      };
    +
    +
    +      ScrollEvent.Sources = {
    +        ViewPortScroll: 'ViewPortScroll',
    +        RenderContainerMouseWheel: 'RenderContainerMouseWheel',
    +        RenderContainerTouchMove: 'RenderContainerTouchMove',
    +        Other: 99
    +      };
    +
    +      return ScrollEvent;
    +    }]);
    +
    +
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Row builder for custom row templates
    +          grid.registerRowBuilder(service.rowTemplateAssigner);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        },
    +
    +        rowTemplateAssigner: function rowTemplateAssigner(row) {
    +          var grid = this;
    +
    +          // Row has no template assigned to it
    +          if (!row.rowTemplate) {
    +            // Use the default row template from the grid
    +            row.rowTemplate = grid.options.rowTemplate;
    +
    +            // Use the grid's function for fetching the compiled row template function
    +            row.getRowTemplateFn = grid.getRowTemplateFn;
    +          }
    +          // Row has its own template assigned
    +          else {
    +            // Create a promise for the compiled row template function
    +            var perRowTemplateFnPromise = $q.defer();
    +            row.getRowTemplateFn = perRowTemplateFnPromise.promise;
    +
    +            // Get the row template
    +            gridUtil.getTemplate(row.rowTemplate)
    +              .then(function (template) {
    +                // Compile the template
    +                var rowTemplateFn = $compile(template);
    +                
    +                // Resolve the compiled template function promise
    +                perRowTemplateFnPromise.resolve(rowTemplateFn);
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
    +              });
    +          }
    +
    +          return row.getRowTemplateFn;
    +        }
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setupFilters
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +   * do all the parsing and pre-processing and store that data into a new filters object.  The object
    +   * has the condition, the flags, the stripped term, and a parsed reg exp if there was one.
    +   * 
    +   * We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +   * for loops everywhere else in this module...
    +   * 
    +   * @param {array} filters the filters from the column (col.filters or [col.filter])
    +   * @returns {array} An array of parsed/preprocessed filters
    +   */
    +  rowSearcher.setupFilters = function setupFilters( filters ){
    +    var newFilters = [];
    +    
    +    var filtersLength = filters.length;
    +    for ( var i = 0; i < filtersLength; i++ ){
    +      var filter = filters[i];
    +      if ( filter.noTerm || filter.term ){
    +        var newFilter = {};
    +        
    +        var regexpFlags = '';
    +        if (!filter.flags || !filter.flags.caseSensitive) {
    +          regexpFlags += 'i';
    +        }
    +    
    +        if ( filter.term ){
    +          // it is possible to have noTerm.  We don't need to copy that across, it was just a flag to avoid
    +          // getting the filter ignored if the filter was a function that didn't use a term
    +          newFilter.term = rowSearcher.stripTerm(filter);
    +        }
    +        
    +        if ( filter.condition ){
    +          newFilter.condition = filter.condition;
    +        } else {
    +          newFilter.condition = rowSearcher.guessCondition(filter);
    +        }
    +
    +        newFilter.flags = angular.extend( { caseSensitive: false }, filter.flags );
    +
    +        if (newFilter.condition === uiGridConstants.filter.STARTS_WITH) {
    +          newFilter.startswithRE = new RegExp('^' + newFilter.term, regexpFlags);
    +        }
    +        
    +         if (newFilter.condition === uiGridConstants.filter.ENDS_WITH) {
    +          newFilter.endswithRE = new RegExp(newFilter.term + '$', regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.CONTAINS) {
    +          newFilter.containsRE = new RegExp(newFilter.term, regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.EXACT) {
    +          newFilter.exactRE = new RegExp('^' + newFilter.term + '$', regexpFlags);
    +        }
    +        
    +        newFilters.push(newFilter);
    +      }
    +    }
    +    return newFilters;
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name runColumnFilter
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Runs a single pre-parsed filter against a cell, returning true
    +   * if the cell matches that one filter.
    +   * 
    +   * @param {Grid} grid the grid we're working against
    +   * @param {GridRow} row the row we're matching against
    +   * @param {GridCol} column the column that we're working against
    +   * @param {object} filter the specific, preparsed, filter that we want to test
    +   * @returns {boolean} true if we match (row stays visible)
    +   */
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Term to search for.
    +    var term = filter.term;
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +    
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      return filter.condition.test(value);
    +    }
    +
    +    // If the filter's condition is a function, run it
    +    if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    
    +    if (filter.startswithRE) {
    +      return filter.startswithRE.test(value);
    +    }
    +    
    +    if (filter.endswithRE) {
    +      return filter.endswithRE.test(value);
    +    }
    +    
    +    if (filter.containsRE) {
    +      return filter.containsRE.test(value);
    +    }
    +    
    +    if (filter.exactRE) {
    +      return filter.exactRE.test(value);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      var regex = new RegExp('^' + term + '$');
    +      return !regex.exec(value);
    +    }
    +
    +    if (typeof(value) === 'number'){
    +      // if the term has a decimal in it, it comes through as '9\.4', we need to take out the \
    +      var tempFloat = parseFloat(term.replace(/\\./,'.'));
    +      if (!isNaN(tempFloat)) {
    +        term = tempFloat;
    +      }
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      return (value > term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      return (value >= term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      return (value < term);
    +    }
    +    
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      return (value <= term);
    +    }
    +    
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process provided filters on provided column against a given row. If the row meets 
    +   * the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @param {array} filters array of pre-parsed/preprocessed filters to apply
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, filters) {
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    var filtersLength = filters.length;
    +    for (var i = 0; i < filtersLength; i++) {
    +      var filter = filters[i];
    +      
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across the given rows and columns, marking any rows that don't 
    +   * match the stored col.filters or col.filter as invisible.
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    /*
    +     * Added performance optimisations into this code base, as this logic creates deeply nested
    +     * loops and is therefore very performance sensitive.  In particular, avoiding forEach as
    +     * this impacts some browser optimisers (particularly Chrome), using iterators instead
    +     */
    +    
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Build list of filters to apply
    +    var filterData = [];
    +
    +    var colsLength = columns.length;
    +    for (var i = 0; i < colsLength; i++) {
    +      var col = columns[i];
    +      
    +      if (typeof(col.filters) !== 'undefined' && ( col.filters.length > 1 || col.filters.length === 1 && col.filters[0].term ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters(col.filters) } );
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters([col.filter]) } );
    +      }
    +    }
    +    
    +    if (filterData.length > 0) {
    +      // define functions outside the loop, performance optimisation
    +      var foreachRow = function(grid, row, col, filters){
    +        if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, filters)) {
    +          row.visible = false;
    +        }
    +      };
    +      
    +      var foreachFilterCol = function(grid, filterData){
    +        var rowsLength = rows.length;
    +        for ( var i = 0; i < rowsLength; i++){
    +          foreachRow(grid, rows[i], filterData.col, filterData.filters);  
    +        }
    +      };
    +
    +      // nested loop itself - foreachFilterCol, which in turn calls foreachRow
    +      var filterDataLength = filterData.length;
    +      for ( var j = 0; j < filterDataLength; j++){
    +        foreachFilterCol( grid, filterData[j] );  
    +      }
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toString().toLowerCase(),
    +          strB = b.toString().toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +    
    +    // put a custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( rows, function ( row, idx ) {
    +      row.entity.$uiGridIndex = idx;
    +    });
    +
    +    // Now actually sort the data
    +    var newRows = rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Chrome doesn't implement a stable sort function.  If our sort returns 0 
    +      // (i.e. the items are equal), then return the previous order using our custom
    +      // index variable
    +      if (tem === 0 ) {
    +        return rowA.entity.$uiGridIndex - rowB.entity.$uiGridIndex;
    +      }
    +      
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +    
    +    // remove the custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( newRows, function ( row, idx ) {
    +      delete row.entity.$uiGridIndex;
    +    });
    +    
    +    return newRows;
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        pagination: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'всего строк: ',
    +          sum: 'итого: ',
    +          avg: 'среднее: ',
    +          min: 'мин: ',
    +          max: 'макс: '
    +        },
    +        gridMenu: {
    +          columns: 'Столбцы:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Экспортировать всё в CSV',
    +          exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
    +          exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
    +          exporterAllAsPdf: 'Экспортировать всё в PDF',
    +          exporterVisibleAsPdf: 'Экспортировать видимые данные в PDF',
    +          exporterSelectedAsPdf: 'Экспортировать выбранные данные в PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        pagination: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3, PG_UP: 4, PG_DOWN: 5},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +        this.bodyContainer = rowContainer;
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.api:GridRow
    +       *
    +       *  @description GridRow settings for cellNav feature, these are available to be
    +       *  set only internally (for example, by other features)
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name allowCellFocus
    +       *  @propertyOf  ui.grid.cellNav.api:GridRow
    +       *  @description Enable focus on a cell within this row.  If set to false then no cells
    +       *  in this row can be focused - group header rows as an example would set this to false.
    +       *  <br/>Defaults to true
    +       */
    +      /** returns focusable rows */
    +      UiGridCellNav.prototype.getFocusableRows = function () {
    +        return this.rows.filter(function(row) {
    +          return row.allowCellFocus !== false;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_UP:
    +            return this.getRowColPageUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_DOWN:
    +            return this.getRowColPageDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(focusableRows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === focusableRows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(focusableRows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === focusableRows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(focusableRows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex >= focusableRows.length - pageSize) {
    +          return new RowCol(focusableRows[focusableRows.length - 1], focusableCols[curColIndex]); //return last row
    +        }
    +        else {
    +          //down one page
    +          return new RowCol(focusableRows[curRowIndex + pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(focusableRows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex - pageSize < 0) {
    +          return new RowCol(focusableRows[0], focusableCols[curColIndex]); //return first row
    +        }
    +        else {
    +          //up one page
    +          return new RowCol(focusableRows[curRowIndex - pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory', 'ScrollEvent',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav, ScrollEvent) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +          grid.cellNav.focusedCells = [];
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function ($scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view, and sets focus
    +                 * to that cell
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus
    +                 * @param {object} colDef to make visible and set focus
    +                 */
    +                scrollToFocus: function ($scope, rowEntity, colDef) {
    +                  service.scrollToFocus(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column fully into view if it isn't already
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {GridRow} row grid row that we should make fully visible
    +                 * @param {GridCol} col grid col to make fully visible
    +                 */
    +                scrollToIfNecessary: function ($scope, row, col) {
    +                  service.scrollToIfNecessary(grid, $scope, row, col);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getCurrentSelection
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns an array containing the current selection
    +                 * <br> array is empty if no selection has occurred
    +                 */
    +                getCurrentSelection: function () {
    +                  return grid.cellNav.focusedCells;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name rowColSelectIndex
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +                 * isn't selected
    +                 * @param {object} rowCol the rowCol to evaluate
    +                 */
    +                rowColSelectIndex: function (rowCol) {
    +                  //return gridUtil.arrayContainsObjectWithProperty(grid.cellNav.focusedCells, 'col.uid', rowCol.col.uid) &&
    +                  var index = -1;
    +                  for (var i = 0; i < grid.cellNav.focusedCells.length; i++) {
    +                    if (grid.cellNav.focusedCells[i].col.uid === rowCol.col.uid &&
    +                      grid.cellNav.focusedCells[i].row.uid === rowCol.row.uid) {
    +                      index = i;
    +                      break;
    +                    }
    +                  }
    +                  return index;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:GridOptions
    +           *
    +           *  @description GridOptions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelectCells
    +           *  @propertyOf  ui.grid.cellNav.api:GridOptions
    +           *  @description Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelectCells = gridOptions.modifierKeysToMultiSelectCells === true;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_UP){
    +            return uiGridCellNavConstants.direction.PG_UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_DOWN){
    +            return uiGridCellNavConstants.direction.PG_DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell within this column.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null && typeof(rowEntity) !== 'undefined' ) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null && typeof(colDef) !== 'undefined' ) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToFocus
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view, and set focus to the cell in that row and column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus to
    +         * @param {object} colDef to make visible and set focus to
    +         */
    +        scrollToFocus: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +
    +          var rowCol = { row: gridRow, col: gridCol };
    +
    +          // Broadcast the navigation
    +          grid.cellNav.broadcastCellNav(rowCol);
    +
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         *
    +         * To get to row 9 (i.e. the last row) in the same list, we want to
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll,
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToInternal');
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            scrollEvent.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            scrollEvent.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, $scope, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToIfNecessary');
    +
    +          // Alias the visible row and column caches
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          //if (grid.horizontalScrollbarHeight) {
    +          //  bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          //}
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + grid.gridWidth;
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          //if (grid.verticalScrollbarWidth) {
    +          //  rightBound = rightBound - grid.verticalScrollbarWidth;
    +          //}
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            //if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +            //  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            //}
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;
    +            }
    +          });
    +
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var _scope = $scope;
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = grid.cellNav.broadcastCellNav = function (newRowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol, modifierDown);
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol, modifierDown);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +
    +                var row = rowCol.row,
    +                  col = rowCol.col;
    +
    +                var rowColSelectIndex = uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol);
    +
    +                if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                  if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
    +                    grid.cellNav.focusedCells.push(rowCol);
    +                  } else {
    +                    grid.cellNav.focusedCells = [rowCol];
    +                  }
    +                } else if (grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                  rowColSelectIndex >= 0) {
    +
    +                  grid.cellNav.focusedCells.splice(rowColSelectIndex, 1);
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, $scope, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                 renderContainerCtrl = controllers[1];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              var needFocus = false;
    +              
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              grid.api.core.on.scrollEvent($scope, function (args) {
    +                // Skip if not this grid that the event was broadcast for
    +                if (args.grid && args.grid.id !== uiGridCtrl.grid.id) {
    +                  return;
    +                }
    +
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +                
    +                /*
    +                 * If we have scrolled due to cellNav, we want to set the focus to the new cell after the 
    +                 * virtualisation has run, and after scroll.  If we scrolled through the browser scroll
    +                 * bar or other user action, we're going to discard the focus, because it will no longer 
    +                 * be valid (and, noting #2423, trying to keep it causes problems)
    +                 * 
    +                 * If cellNav triggers the scroll, we get a scrollToIfNecessary, then a viewport scroll. We
    +                 * want to wait for the viewport scroll to finish, then do a refocus.  
    +                 * 
    +                 * If someone manually scrolls we get just the viewport scroll, no scrollToIfNecessary.  We
    +                 * want to just clear the focus
    +                 * 
    +                 * Logic is:
    +                 *  - if cellNav scroll, set a flag that will be resolved in the native scroll
    +                 *  - if native scroll, look for the cellNav promise and resolve it
    +                 *    - if not present, then use a timeout to clear focus
    +                 *    - if it is present, then instead use a timeout to set focus
    +                 */ 
    +                
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                if ( args.source === 'uiGridCellNavService.scrollToIfNecessary'){
    +                  needFocus = true;
    +/*
    +                  focusTimeout = $timeout(function () {
    +                    if ( clearFocusTimeout ){
    +                      $timeout.cancel(clearFocusTimeout);
    +                    }
    +                    focusTimeout = $timeout(function () {
    +                      if ( clearFocusTimeout ){
    +                        $timeout.cancel(clearFocusTimeout);
    +                      }
    +                      // Get the last row+col combo
    +                      var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +  
    +                      // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                      //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                      //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                      if ($document.activeElement === $document.body) {
    +                        $elm[0].focus();
    +                      }
    +  
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                    });
    +                  });
    +                  */
    +                } else {
    +                  if ( needFocus ){
    +                    $timeout(function () {
    +                      $timeout(function () {
    +                        // Get the last row+col combo
    +                        var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +    
    +                        // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                        //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                        //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                        if ($document.activeElement === $document.body) {
    +                          $elm[0].focus();
    +                        }
    +    
    +                        // broadcast a cellNav event so we clear the focus on all cells
    +                        uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                        
    +                        needFocus = false;
    +                      });
    +                    });
    +                  } else {
    +                    $timeout(function() {
    +                      // make a dummy roCol
    +                      var rowCol = { col: { uid: null }, row: { uid: null } };
    +    
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +                    });
    +                  }
    +                }
    +              });  
    +             
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +
    +            evt.stopPropagation();
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol, modifierDown) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol) === -1) {
    +                clearFocus();
    +              } else {
    +                setFocused();
    +              }
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else if (!(uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown)) {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.api:GridRow
    +   *
    +   *  @description GridRow options for edit feature, these are available to be
    +   *  set internally only, by other features
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableCellEdit
    +   *  @propertyOf  ui.grid.edit.api:GridRow
    +   *  @description enable editing on row, grouping for example might disable editing on group header rows
    +   */
    +
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        var touchstartTimeout = 500;
    +
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit || $scope.row.enableCellEdit === false) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +            var cancelTouchstartTimeout;
    +
    +            var editCellScope;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +
    +              // Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
    +              $elm.on('touchstart', touchStart);
    +            }
    +
    +            function touchStart(event) {
    +              // jQuery masks events
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +
    +              // Bind touchend handler
    +              $elm.on('touchend', touchEnd);
    +
    +              // Start a timeout
    +              cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
    +
    +              // Timeout's done! Start the edit
    +              cancelTouchstartTimeout.then(function () {
    +                // Use setTimeout to start the edit because beginEdit expects to be outside of $digest
    +                setTimeout(beginEdit, 0);
    +
    +                // Undbind the touchend handler, we don't need it anymore
    +                $elm.off('touchend', touchEnd);
    +              });
    +            }
    +
    +            // Cancel any touchstart timeout
    +            function touchEnd(event) {
    +              $timeout.cancel(cancelTouchstartTimeout);
    +              $elm.off('touchend', touchEnd);
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +              $elm.off('touchstart', touchStart);
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving &&
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownRowEntityOptionsArrayPath
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description a path to a property on row.entity containing an
    +             *  array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which will be used to populate
    +             *  the edit dropdown.  This can be used when the dropdown values are dependent on
    +             *  the backing row entity.
    +             *  If this property is set then editDropdownOptionsArray will be ignored.
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              // if the cell isn't fully visible, and cellNav is present, scroll it to be fully visible before we start
    +              if ( $scope.grid.api.cellNav ){
    +                $scope.grid.api.cellNav.scrollToIfNecessary( $scope, $scope.row, $scope.col );
    +              }
    +              
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              var inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  inputType = 'number';
    +                  break;
    +                case 'date':
    +                  inputType = 'date';
    +                  break;
    +              }
    +              html = html.replace('INPUT_TYPE', inputType);
    +
    +              var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
    +              if (editDropdownRowEntityOptionsArrayPath) {
    +                $scope.editDropdownOptionsArray =  resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
    +              }
    +              else {
    +                $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              }
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                editCellScope = $scope.$new();
    +                $compile(cellElement)(editCellScope);
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.col.grid.api.core.on.scrollEvent($scope, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +                deregOnGridScroll();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              editCellScope.$destroy();
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +            // resolves a string path against the given object
    +            // shamelessly borrowed from
    +            // http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
    +            function resolveObjectFromPath(object, path) {
    +              path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    +              path = path.replace(/^\./, '');           // strip a leading dot
    +              var a = path.split('.');
    +              while (a.length) {
    +                  var n = a.shift();
    +                  if (n in object) {
    +                      object = object[n];
    +                  } else {
    +                      return;
    +                  }
    +              }
    +              return object;
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
    +      function (gridUtil, uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +               $scope.deepEdit = false;
    +
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('uiGridEditor', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        priority: -100, // run after default uiGridEditor directive
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.expandable.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        grid.expandable = {};
    +        grid.expandable.expandedAll = false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name 
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Width in pixels of the expandable column. Defaults to 40
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeaderWidth: 40
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name toggleAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.toggleAllRows();
    +               * </pre>
    +               */              
    +              toggleAllRows: function() {
    +                service.toggleAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +          grid.expandable.expandedAll = false;
    +        }
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = true;
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = false;
    +        grid.refresh();
    +      },
    +
    +      toggleAllRows: function(grid) {
    +        if (grid.expandable.expandedAll) {
    +          service.collapseAllRows(grid);
    +        }
    +        else {
    +          service.expandAllRows(grid);
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {
    +                  name: 'expandableButtons', 
    +                  displayName: '', 
    +                  exporterSuppressExport: true, 
    +                  enableColumnResizing: false, 
    +                  enableColumnMenu: false,
    +                  width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
    +                };
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGrid
    +   *  @description stacks on the uiGrid directive to register child grid with parent row when child is created
    +   */
    +  module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 1000,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
    +                //if a parent grid row is on the scope, then add the parentRow property to this childGrid
    +                if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
    +
    +                  /**
    +                   *  @ngdoc directive
    +                   *  @name ui.grid.expandable.class:Grid
    +                   *  @description Additional Grid properties added by expandable module
    +                   */
    +
    +                  /**
    +                   *  @ngdoc object
    +                   *  @name parentRow
    +                   *  @propertyOf ui.grid.expandable.class:Grid
    +                   *  @description reference to the expanded parent row that owns this grid
    +                   */
    +                  uiGridCtrl.grid.parentRow = $scope.row;
    +
    +                  //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
    +                 // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
    +                 //   uiGridCtrl.grid.parentRow = newHeight;
    +                 // });
    +                }
    +
    +              });
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridExpandableRow
    +   *  @description directive to render the expandable row template
    +   */
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridRow
    +   *  @description stacks on the uiGridRow directive to add support for expandable rows
    +   */
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridViewport
    +   *  @description stacks on the uiGridViewport directive to append the expandable row html elements to the
    +   *  default gridRow template
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    BUTTON_LABEL: 'BUTTON_LABEL',
    +    FILE_NAME: 'FILE_NAME'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                csvExport: function (rowTypes, colTypes) {
    +                  service.csvExport(grid, rowTypes, colTypes);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for exporter feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:ColumnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvFilename
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default filename to use when saving the downloaded csv.  
    +           * This will only work in some browsers.
    +           * <br/>Defaults to 'download.csv'
    +           */
    +          gridOptions.exporterCsvFilename = gridOptions.exporterCsvFilename ? gridOptions.exporterCsvFilename : 'download.csv';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilterUseName
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Defaults to false, which leads to `displayName` being passed into the headerFilter.
    +           * If set to true, then will pass `name` instead.
    +           * 
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilterUseName = true;
    +           * </pre>
    +           */
    +          gridOptions.exporterHeaderFilterUseName = gridOptions.exporterHeaderFilterUseName === true;          
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * 
    +           * Behaviour can be changed to pass in `name` instead of `displayName` through use of `exporterHeaderFilterUseName: true`.
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +          
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        csvExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          this.downloadFile (grid.options.exporterCsvFilename, csvContent);
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterSuppressExport
    +         * @description Suppresses export for this column.  Used by selection and expandable.
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.colDef.exporterSuppressExport !== true &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? ( grid.options.exporterHeaderFilterUseName ? grid.options.exporterHeaderFilter(gridCol.name) : grid.options.exporterHeaderFilter(gridCol.displayName) ) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.exporter.api:GridRow
    +         * @description GridRow settings for exporter
    +         */
    +        /**
    +         * @ngdoc object
    +         * @name exporterEnableExporting
    +         * @propertyOf  ui.grid.exporter.api:GridRow
    +         * @description If set to false, then don't export this row, notwithstanding visible or 
    +         * other settings
    +         * <br/>Defaults to true
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate.  Any rows marked
    +         * `exporterEnableExporting: false` will not be exported
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            if (row.exporterEnableExporting !== false) {
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.colDef.exporterSuppressExport !== true &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                  if ( gridCol.colDef.exporterPdfAlign ) {
    +                    extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                  }
    +                  extractedRow.push(extractedField);
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            }
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name downloadFile
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Triggers download of a csv file.  Logic provided
    +         * by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391
    +         * @param {string} fileName the filename we'd like our file to be
    +         * given
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * download as a file
    +         */
    +        downloadFile: function (fileName, csvContent) {
    +          var D = document;
    +          var a = D.createElement('a');
    +          var strMimeType = 'application/octet-stream;charset=utf-8';
    +          var rawFile;
    +      
    +          // IE10+
    +          if (navigator.msSaveBlob) {
    +            return navigator.msSaveBlob(new Blob(["\ufeff", csvContent], {
    +              type: strMimeType
    +            }), fileName);
    +          }
    +      
    +          //html5 A[download]
    +          if ('download' in a) {
    +            var blob = new Blob([csvContent], {
    +              type: strMimeType
    +            });
    +            rawFile = URL.createObjectURL(blob);
    +            a.setAttribute('download', fileName);
    +          } else {
    +            rawFile = 'data:' + strMimeType + ',' + encodeURIComponent(csvContent);
    +            a.setAttribute('target', '_blank');
    +          }
    +      
    +          a.href = rawFile;
    +          a.setAttribute('style', 'display:none;');
    +          D.body.appendChild(a);
    +          setTimeout(function() {
    +            if (a.click) {
    +              a.click();
    +              // Workaround for Safari 5
    +            } else if (document.createEvent) {
    +              var eventObj = document.createEvent('MouseEvents');
    +              eventObj.initEvent('click', true, true);
    +              a.dispatchEvent(eventObj);
    +            }
    +            D.body.removeChild(a);
    +    
    +          }, 100);
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.header = grid.options.exporterPdfHeader;
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.footer = grid.options.exporterPdfFooter;
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( fileObject ) {
    +                  service.importThisFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and if the rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var dataChangeDereg = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( newObjects );
    +              dataChangeDereg();
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            grid.importer.$scope.$on( '$destroy', dataChangeDereg );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            var target = event.srcElement || event.target;
    +            
    +            if (target && target.files && target.files.length === 1) {
    +              var fileObject = target.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              target.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.grid.api.core.on.scrollEvent($scope, function (args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', 'ScrollEvent', 'uiGridConstants', function ($q, $timeout, $log, ScrollEvent, uiGridConstants) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                var columns = grid.columns;
    +                if (!angular.isNumber(originalPosition) || !angular.isNumber(finalPosition)) {
    +                  console.log('Please provide valid values for originalPosition and finalPosition');
    +                  return;
    +                }
    +                var nonMovableColumns = 0;
    +                for (var i = 0; i < columns.length; i++) {
    +                  if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +                    nonMovableColumns++;
    +                  }
    +                }
    +                if (originalPosition >= (columns.length - nonMovableColumns) || finalPosition >= (columns.length - nonMovableColumns)) {
    +                  console.log('Invalid values for originalPosition, finalPosition');
    +                  return;
    +                }
    +                var findPositionForRenderIndex = function (index) {
    +                  var position = index;
    +                  for (var i = 0; i <= position; i++) {
    +                    if (angular.isDefined(columns[i]) && ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true)) {
    +                      position++;
    +                    }
    +                  }
    +                  return position;
    +                };
    +                self.redrawColumnAtPosition(grid, findPositionForRenderIndex(originalPosition), findPositionForRenderIndex(finalPosition));
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +
    +        var columns = grid.columns;
    +
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +            grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log', 'uiGridConstants', 'ScrollEvent',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log, uiGridConstants, ScrollEvent) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                $scope.$on(uiGridConstants.events.COLUMN_HEADER_CLICK, function (event, args) {
    +
    +                  if (args.columnName === $scope.col.colDef.name && !$scope.col.renderContainer) {
    +
    +                    var evt = args.event;
    +                    if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                      //Setting some variables required for calculations.
    +                      var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                      var previousMouseX = evt.pageX;
    +                      var totalMouseMovement = 0;
    +                      var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth();// - $scope.grid.verticalScrollbarWidth;
    +
    +                      //Clone element should move horizontally with mouse.
    +                      var elmCloned = false;
    +                      var movingElm;
    +                      var reducedWidth;
    +
    +                      var cloneElement = function () {
    +                        elmCloned = true;
    +
    +                        //Cloning header cell and appending to current header cell.
    +                        movingElm = $elm.clone();
    +                        $elm.parent().append(movingElm);
    +
    +                        //Left of cloned element should be aligned to original header cell.
    +                        movingElm.addClass('movingColumn');
    +                        var movingElementStyles = {};
    +                        var elmLeft = $elm[0].getBoundingClientRect().left;
    +                        movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                        var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                        var elmRight = $elm[0].getBoundingClientRect().right;
    +                        if (elmRight > gridRight) {
    +                          reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                          movingElementStyles.width = reducedWidth + 'px';
    +                        }
    +                        movingElm.css(movingElementStyles);
    +                      };
    +
    +                      var moveElement = function (changeValue) {
    +                        //Hide column menu
    +                        uiGridCtrl.fireEvent('hide-menu');
    +
    +                        //Calculate total column width
    +                        var columns = $scope.grid.columns;
    +                        var totalColumnWidth = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) {
    +                            totalColumnWidth += columns[i].drawnWidth || columns[i].width || columns[i].colDef.width;
    +                          }
    +                        }
    +
    +                        //Calculate new position of left of column
    +                        var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                        var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                        var newElementLeft;
    +                        if (gridUtil.detectBrowser() === 'ie') {
    +                          newElementLeft = currentElmLeft + changeValue;
    +                        }
    +                        else {
    +                          newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                        }
    +                        newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                        //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                        if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                          movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                        }
    +                        else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
    +                          changeValue *= 8;
    +                          var scrollEvent = new ScrollEvent($scope.col.grid, null, null, 'uiGridHeaderCell.moveElement');
    +                          scrollEvent.x = {pixels: changeValue};
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +
    +                        //Calculate total width of columns on the left of the moving column and the mouse movement
    +                        var totalColumnsLeftWidth = 0;
    +                        for (var il = 0; il < columns.length; il++) {
    +                          if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                            if (columns[il].colDef.name !== $scope.col.colDef.name) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                            }
    +                            else {
    +                              break;
    +                            }
    +                          }
    +                        }
    +                        if ($scope.newScrollLeft === undefined) {
    +                          totalMouseMovement += changeValue;
    +                        }
    +                        else {
    +                          totalMouseMovement = $scope.newScrollLeft + newElementLeft - totalColumnsLeftWidth;
    +                        }
    +
    +                        //Increase width of moving column, in case the rightmost column was moved and its width was
    +                        //decreased because of overflow
    +                        if (reducedWidth < $scope.col.drawnWidth) {
    +                          reducedWidth += Math.abs(changeValue);
    +                          movingElm.css({'width': reducedWidth + 'px'});
    +                        }
    +                      };
    +
    +                      var mouseMoveHandler = function (evt) {
    +                        //Disable text selection in Chrome during column move
    +                        document.onselectstart = function() { return false; };
    +
    +                        var changeValue = evt.pageX - previousMouseX;
    +                        if (!elmCloned && Math.abs(changeValue) > 50) {
    +                          cloneElement();
    +                        }
    +                        else if (elmCloned) {
    +                          moveElement(changeValue);
    +                          previousMouseX = evt.pageX;
    +                        }
    +                      };
    +
    +                      /*
    +                       //Commenting these lines as they are creating trouble with column moving when grid has huge scroll
    +                       // On scope destroy, remove the mouse event handlers from the document body
    +                       $scope.$on('$destroy', function () {
    +                       $document.off('mousemove', mouseMoveHandler);
    +                       $document.off('mouseup', mouseUpHandler);
    +                       });
    +                       */
    +                      $document.on('mousemove', mouseMoveHandler);
    +
    +                      var mouseUpHandler = function (evt) {
    +                        //Re-enable text selection after column move
    +                        document.onselectstart = null;
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var columns = $scope.grid.columns;
    +                        var columnIndex = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== $scope.col.colDef.name) {
    +                            columnIndex++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = columnIndex - 1; il >= 0; il--) {
    +                            if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                              if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, il + 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, 0);
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = columnIndex + 1; ir < columns.length; ir++) {
    +                            if (angular.isUndefined(columns[ir].colDef.visible) || columns[ir].colDef.visible === true) {
    +                              totalColumnsRightWidth += columns[ir].drawnWidth || columns[ir].width || columns[ir].colDef.width;
    +                              if (totalColumnsRightWidth > totalMouseMovement) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, ir - 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, columns.length - 1);
    +                          }
    +                        }
    +/*
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +*/
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      };
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    }
    +                  }
    +                });
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ng', 'ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', ['gridUtil',
    +    function (gridUtil) {
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name initializeGrid
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @description Attaches the service to a certain grid
    +         * @param {Grid} grid The grid we want to work with
    +         */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.pagination.api:PublicAPI
    +          *
    +          * @description Public API for the pagination feature
    +          */
    +          var publicApi = {
    +            events: {
    +              pagination: {
    +              /**
    +               * @ngdoc event
    +               * @name paginationChanged
    +               * @eventOf ui.grid.pagination.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {int} currentPage requested page number
    +               * @param {int} pageSize requested page size
    +               */
    +                paginationChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              pagination: {
    +                /**
    +                 * @ngdoc method
    +                 * @name getPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the number of the current page
    +                 */
    +                getPage: function () {
    +                  return grid.options.enablePagination ? grid.options.paginationCurrentPage : null;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name getTotalPages
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the total number of pages
    +                 */
    +                getTotalPages: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return null;
    +                  }
    +
    +                  return (grid.options.totalItems === 0) ? 1 : Math.ceil(grid.options.totalItems / grid.options.paginationPageSize);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name nextPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the next page, if possible
    +                 */
    +                nextPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  if (grid.options.totalItems > 0) {
    +                    grid.options.paginationCurrentPage = Math.min(
    +                      grid.options.paginationCurrentPage + 1,
    +                      publicApi.methods.pagination.getTotalPages()
    +                    );
    +                  } else {
    +                    grid.options.paginationCurrentPage++;
    +                  }
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name previousPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the previous page, if we're not on the first page
    +                 */
    +                previousPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.max(grid.options.paginationCurrentPage - 1, 1);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name seek
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the requested page
    +                 * @param {int} page The number of the page that should be displayed
    +                 */
    +                seek: function (page) {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +                  if (!angular.isNumber(page) || page < 1) {
    +                    throw 'Invalid page number: ' + page;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.min(page, publicApi.methods.pagination.getTotalPages());
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPagination || !grid.options.enablePagination) {
    +              return renderableRows;
    +            }
    +            //client side pagination
    +            var pageSize = parseInt(grid.options.paginationPageSize, 10);
    +            var currentPage = parseInt(grid.options.paginationCurrentPage, 10);
    +            
    +            var visibleRows = renderableRows.filter(function (row) { return row.visible; });
    +            grid.options.totalItems = visibleRows.length;
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            if (firstRow > visibleRows.length) {
    +              currentPage = grid.options.paginationCurrentPage = 1;
    +              firstRow = (currentPage - 1) * pageSize;
    +            }
    +            return visibleRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.pagination.api:GridOptions
    +           *
    +           * @description GridOptions for the pagination feature, these are available to be
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @name enablePagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables pagination, defaults to true
    +           */
    +          gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +          /**
    +           * @ngdoc property
    +           * @name enablePaginationControls
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +           *              own controls outside the grid.
    +           */
    +          gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Disables client side pagination. When true, handle the paginationChanged event and set data
    +           *              and totalItems, defaults to `false`
    +           */
    +          gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Total number of items, set automatically when client side pagination, needs set by user
    +           *              for server side pagination
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSizes
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Array of page sizes, defaults to `[250, 500, 1000]`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSizes)) {
    +            gridOptions.paginationPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSize
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSize)) {
    +            if (gridOptions.paginationPageSizes.length > 0) {
    +              gridOptions.paginationPageSize = gridOptions.paginationPageSizes[0];
    +            } else {              
    +              gridOptions.paginationPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationCurrentPage
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Current page number, defaults to 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationCurrentPage)) {
    +            gridOptions.paginationCurrentPage = 1;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name paginationTemplate
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description A custom template for the pager, defaults to `ui-grid/pagination`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationTemplate)) {
    +            gridOptions.paginationTemplate = 'ui-grid/pagination';
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @name uiGridPaginationService
    +         * @description  Raises paginationChanged and calls refresh for client side pagination
    +         * @param {Grid} grid the grid for which the pagination changed
    +         * @param {int} currentPage requested page number
    +         * @param {int} pageSize requested page size
    +         */
    +        onPaginationChanged: function (grid, currentPage, pageSize) {
    +            grid.api.pagination.raise.paginationChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPagination) {
    +              grid.refresh(); //client side pagination
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPagination
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds pagination features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        paginationPageSizes: [5, 10, 25],
    +        paginationPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-pagination></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPagination', ['gridUtil', 'uiGridPaginationService',
    +    function (gridUtil, uiGridPaginationService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        link: {
    +          pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +            uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +
    +            gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                $elm.append(template);
    +                uiGridCtrl.innerCompile(template);
    +              });
    +          }
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling pagination
    +   */
    +  module.directive('uiGridPager', ['uiGridPaginationService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPaginationService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +          $scope.paginationApi = uiGridCtrl.grid.api.pagination;
    +          $scope.sizesLabel = i18nService.getSafeText('pagination.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('pagination.totalItems');
    +          
    +          var options = uiGridCtrl.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          var dataChangeDereg = uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPagination) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +          
    +          $scope.$on('$destroy', dataChangeDereg);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.paginationCurrentPage - 1) * options.paginationPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.paginationCurrentPage * options.paginationPageSize, options.totalItems);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.paginationPageSize', setShowing);
    +
    +          var deregP = $scope.$watch('grid.options.paginationCurrentPage + grid.options.paginationPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.paginationCurrentPage) || options.paginationCurrentPage < 1) {
    +                options.paginationCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.paginationCurrentPage > $scope.paginationApi.getTotalPages()) {
    +                options.paginationCurrentPage = $scope.paginationApi.getTotalPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPaginationService.onPaginationChanged($scope.grid, options.paginationCurrentPage, options.paginationPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.paginationCurrentPage >= $scope.paginationApi.getTotalPages();
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.paginationCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        },
    +        
    +        // get either this column, or the column next to this column, to resize,
    +        // returns the column we're going to resize
    +        findTargetCol: function(col, position, rtlMultiplier){
    +          var renderContainer = col.getRenderContainer();
    +
    +          if (position === 'left') {
    +            // Get the column to the left of this one
    +            var colIndex = renderContainer.visibleColumnCache.indexOf(col);          
    +            return renderContainer.visibleColumnCache[colIndex - 1 * rtlMultiplier];
    +          } else {
    +            return col;
    +          }
    +        }
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', 'uiGridResizeColumnsService', 'uiGridConstants', '$timeout', function (gridUtil, $templateCache, $compile, $q, uiGridResizeColumnsService, uiGridConstants, $timeout) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var grid = uiGridCtrl.grid;
    +
    +            if (grid.options.enableColumnResizing) {
    +              var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +    
    +              var rtlMultiplier = 1;
    +              //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +              if (grid.isRTL()) {
    +                $scope.position = 'left';
    +                rtlMultiplier = -1;
    +              }
    +
    +              var displayResizers = function(){
    +                
    +                // remove any existing resizers.  
    +                var resizers = $elm[0].getElementsByClassName('ui-grid-column-resizer');
    +                for ( var i = 0; i < resizers.length; i++ ){
    +                  angular.element(resizers[i]).remove();
    +                } 
    +                
    +                // get the target column for the left resizer
    +                var otherCol = uiGridResizeColumnsService.findTargetCol($scope.col, 'left', rtlMultiplier);
    +                var renderContainer = $scope.col.getRenderContainer();
    +              
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  var resizerLeft = angular.element(columnResizerElm).clone();
    +                  resizerLeft.attr('position', 'left');
    +
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  var resizerRight = angular.element(columnResizerElm).clone();
    +                  resizerRight.attr('position', 'right');
    +
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              };
    +
    +              displayResizers();
    +              
    +              var waitDisplay = function(){
    +                $timeout(displayResizers);
    +              };
    +              
    +              var dataChangeDereg = grid.registerDataChangeCallback( waitDisplay, [uiGridConstants.dataChange.COLUMN] );
    +              
    +              $scope.$on( '$destroy', dataChangeDereg );
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var downEvent, upEvent, moveEvent;
    +
    +    if (gridUtil.isTouchEnabled()) {
    +      downEvent = 'touchstart';
    +      upEvent = 'touchend';
    +      moveEvent = 'touchmove';
    +    }
    +    else {
    +      downEvent = 'mousedown';
    +      upEvent = 'mouseup';
    +      moveEvent = 'mousemove';
    +    }
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true).then( function() {
    +                uiGridCtrl.grid.refresh();
    +              });
    +            });
    +        }
    +
    +        // Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
    +        // Returns the new recommended with, after constraints applied
    +        function constrainWidth(col, width){
    +          var newWidth = width;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          return newWidth;
    +        }
    +        
    +        
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          x = x + ( constrainWidth(col, newWidth) - newWidth ) * rtlMultiplier;
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +        
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off(upEvent, mouseup);
    +            $document.off(moveEvent, mousemove);
    +            return;
    +          }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, newWidth);
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off(upEvent, mouseup);
    +          $document.off(moveEvent, mousemove);
    +        }
    +
    +
    +        $elm.on(downEvent, function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on(upEvent, mouseup);
    +          $document.on(moveEvent, mousemove);
    +        });
    +
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, maxWidth);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off(downEvent);
    +          $elm.off('dblclick');
    +          $document.off(moveEvent, mousemove);
    +          $document.off(upEvent, mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function ( rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function () {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function () {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function () {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function ( dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty( myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.saveState
    +   * @description
    +   *
    +   *  # ui.grid.saveState
    +   * This module provides the ability to save the grid state, and restore
    +   * it when the user returns to the page.  
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate. Usually the navigate events would be used to save
    +   * the grid state and restore it.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.save-state"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.saveState', ['ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.saveState.constant:uiGridSaveStateConstants
    +   *
    +   *  @description constants available in save state module
    +   */
    +
    +  module.constant('uiGridSaveStateConstants', {
    +    featureName: 'saveState'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.saveState.service:uiGridSaveStateService
    +   *
    +   *  @description Services for saveState feature
    +   */
    +  module.service('uiGridSaveStateService', ['$q', 'uiGridSaveStateConstants', 'gridUtil', '$compile', '$interval', 'uiGridConstants',
    +    function ($q, uiGridSaveStateConstants, gridUtil, $compile, $interval, uiGridConstants ) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.saveState = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.saveState.api:PublicApi
    +           *
    +           *  @description Public Api for saveState feature
    +           */
    +          var publicApi = {
    +            events: {
    +              saveState: {
    +              }
    +            },
    +            methods: {
    +              saveState: {
    +                /**
    +                 * @ngdoc function
    +                 * @name save
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Packages the current state of the grid into 
    +                 * an object, and provides it to the user for saving
    +                 * @returns {object} the state as a javascript object that can be saved
    +                 */
    +                save: function () {
    +                  return service.save(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name restore
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Restores the provided state into the grid
    +                 * @param {scope} $scope a scope that we can broadcast on
    +                 * @param {object} state the state that should be restored into the grid
    +                 */
    +                restore: function ( $scope, state) {
    +                  service.restore(grid, $scope, state);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.saveState.api:GridOptions
    +           *
    +           * @description GridOptions for saveState feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveWidths
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column widths.  Note that unless
    +           * you've provided the user with some way to resize their columns (say
    +           * the resize columns feature), then this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveWidths = gridOptions.saveWidths !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveOrder
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column order.  Note that unless
    +           * you've provided the user with some way to reorder their columns (for
    +           * example the move columns feature), this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveOrder = gridOptions.saveOrder !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveScroll
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current scroll position.  Note that this
    +           * is saved as the percentage of the grid scrolled - so if your
    +           * user returns to a grid with a significantly different number of 
    +           * rows (perhaps some data has been deleted) then the scroll won't 
    +           * actually show the same rows as before.  If you want to scroll to
    +           * a specific row then you should instead use the saveFocus option, which
    +           * is the default.
    +           * 
    +           * Note that this element will only be saved if the cellNav feature is
    +           * enabled
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.saveScroll = gridOptions.saveScroll === true;
    +          /**
    +           * @ngdoc object
    +           * @name saveFocus
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current focused cell.  On returning
    +           * to this focused cell we'll also scroll.  This option is
    +           * preferred to the saveScroll option, so is set to true by
    +           * default.  If saveScroll is set to true then this option will 
    +           * be disabled.  
    +           * 
    +           * By default this option saves the current row number and column 
    +           * number, and returns to that row and column.  However, if you define
    +           * a saveRowIdentity function, then it will return you to the currently 
    +           * selected column within that row (in a business sense - so if some
    +           * rows have been deleted, it will still find the same data, presuming it 
    +           * still exists in the list.  If it isn't in the list then it will instead
    +           * return to the same row number - i.e. scroll percentage)
    +           * 
    +           * Note that this option will do nothing if the cellNav
    +           * feature is not enabled.
    +           * 
    +           * <br/>Defaults to true (unless saveScroll is true)
    +           */
    +          gridOptions.saveFocus = gridOptions.saveScroll !== true && gridOptions.saveFocus !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveRowIdentity
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description A function that can be called, passing in a rowEntity, 
    +           * and that will return a unique id for that row.  This might simply 
    +           * return the `id` field from that row (if you have one), or it might
    +           * concatenate some fields within the row to make a unique value.
    +           * 
    +           * This value will be used to find the same row again and set the focus 
    +           * to it, if it exists when we return.
    +           * 
    +           * <br/>Defaults to undefined
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveVisible
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save whether or not columns are visible.
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveVisible = gridOptions.saveVisible !== false;          
    +          /**
    +           * @ngdoc object
    +           * @name saveSort
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current sort state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSort = gridOptions.saveSort !== false;         
    +          /**
    +           * @ngdoc object
    +           * @name saveFilter
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current filter state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveFilter = gridOptions.saveFilter !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveSelection
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the currently selected rows.  If the `saveRowIdentity` callback
    +           * is defined, then it will save the id of the row and select that.  If not, then
    +           * it will attempt to select the rows by row number, which will give the wrong results
    +           * if the data set has changed in the mean-time.
    +           * 
    +           * Note that this option only does anything
    +           * if the selection feature is enabled.  
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSelection = gridOptions.saveSelection !== false;          
    +        },
    +
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name save
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the current grid state into an object, and
    +         * passes that object back to the caller
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the state ready to be saved
    +         */
    +        save: function (grid) {
    +          var savedState = {};
    +          
    +          savedState.columns = service.saveColumns( grid );
    +          savedState.scrollFocus = service.saveScrollFocus( grid );
    +          savedState.selection = service.saveSelection( grid );
    +          
    +          return savedState;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restore
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Applies the provided state to the grid
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} state the state we'd like to restore
    +         */
    +        restore: function( grid, $scope, state ){
    +          if ( state.columns ) {
    +            service.restoreColumns( grid, state.columns );
    +          }
    +          
    +          if ( state.scrollFocus ){
    +            service.restoreScrollFocus( grid, $scope, state.scrollFocus );
    +          }
    +          
    +          if ( state.selection ){
    +            service.restoreSelection( grid, state.selection );
    +          }
    +          
    +          grid.refresh();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name saveColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the column setup, including sort, filters, ordering
    +         * and column widths.
    +         * 
    +         * Works through the current columns, storing them in order.  Stores the
    +         * column name, then the visible flag, width, sort and filters for each column.
    +         *
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {array} the columns state ready to be saved
    +         */
    +        saveColumns: function( grid ) {
    +          var columns = [];
    +          angular.forEach( grid.columns, function( column ) {
    +            var savedColumn = {};
    +            savedColumn.name = column.name;
    +            savedColumn.visible = column.visible;
    +            savedColumn.width = column.width;
    +            
    +            // these two must be copied, not just pointed too - otherwise our saved state is pointing to the same object as current state
    +            savedColumn.sort = angular.copy( column.sort );
    +            savedColumn.filters = angular.copy ( column.filters );
    +            columns.push( savedColumn );
    +          });
    +          
    +          return columns;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently scroll or focus.
    +         * 
    +         * If cellNav isn't present then does nothing - we can't return
    +         * to the scroll position without cellNav anyway.
    +         * 
    +         * If the cellNav module is present, and saveFocus is true, then
    +         * it saves the currently focused cell.  If rowIdentity is present
    +         * then saves using rowIdentity, otherwise saves visibleRowNum.
    +         * 
    +         * If the cellNav module is not present, and saveScroll is true, then
    +         * it approximates the current scroll row and column, and saves that.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveScrollFocus: function( grid ){
    +          if ( !grid.api.cellNav ){
    +            return {};
    +          }
    +          
    +          var scrollFocus = {};
    +          if ( grid.options.saveFocus ){
    +            scrollFocus.focus = true;
    +            var rowCol = grid.api.cellNav.getFocusedCell();
    +            if ( rowCol !== null ) {
    +              scrollFocus.colName = rowCol.col.colDef.name;
    +              scrollFocus.rowVal = service.getRowVal( grid, rowCol.row );
    +            }
    +          } else if ( grid.options.saveScroll ) {
    +            scrollFocus.focus = false;
    +            if ( grid.renderContainers.body.prevRowScrollIndex ){
    +              scrollFocus.rowVal = service.getRowVal( grid, grid.renderContainers.body.visibleRowCache[ grid.renderContainers.body.prevRowScrollIndex ]);
    +            }
    +            
    +            if ( grid.renderContainers.body.prevColScrollIndex ){
    +              scrollFocus.colName = grid.renderContainers.body.visibleColumnCache[ grid.renderContainers.body.prevColScrollIndex ].name;
    +            }
    +          }        
    +          
    +          return scrollFocus;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently selected rows, if the selection feature is enabled
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveSelection: function( grid ){
    +          if ( !grid.api.selection ){
    +            return {};
    +          }
    +          
    +          var selection = grid.api.selection.getSelectedGridRows().map( function( gridRow ) {
    +            return service.getRowVal( grid, gridRow );
    +          });
    +          
    +          return selection;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getRowVal
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Helper function that gets either the rowNum or
    +         * the saveRowIdentity, given a gridRow 
    +         * @param {Grid} grid the grid the row is in
    +         * @param {GridRow} gridRow the row we want the rowNum for
    +         * @returns {object} an object containing { identity: true/false, row: rowNumber/rowIdentity }
    +         * 
    +         */
    +        getRowVal: function( grid, gridRow ){
    +          if ( !gridRow ) {
    +            return null;
    +          }
    +          
    +          var rowVal = {};
    +          if ( grid.options.saveRowIdentity ){
    +            rowVal.identity = true;
    +            rowVal.row = grid.options.saveRowIdentity( gridRow.entity );
    +          } else {
    +            rowVal.identity = false;
    +            rowVal.row = grid.renderContainers.body.visibleRowCache.indexOf( gridRow );
    +          }
    +          return rowVal;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restoreColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Restores the columns, including order, visible, width
    +         * sort and filters.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} columnsState the list of columns we had before, with their state
    +         */
    +        restoreColumns: function( grid, columnsState ){
    +          angular.forEach( columnsState, function( columnState, index ) {
    +            var currentCol = grid.columns.filter( function( column ) {
    +              return column.name === columnState.name;
    +            });
    +            
    +            if ( currentCol.length > 0 ){
    +              var currentIndex = grid.columns.indexOf( currentCol[0] );
    +              
    +              grid.columns[currentIndex].visible = columnState.visible;
    +              grid.columns[currentIndex].colDef.visible = columnState.visible;
    +              grid.columns[currentIndex].width = columnState.width;
    +              grid.columns[currentIndex].sort = angular.copy( columnState.sort );
    +              grid.columns[currentIndex].filters = angular.copy( columnState.filters );
    +
    +              if ( currentIndex !== index ){
    +                var column = grid.columns.splice( currentIndex, 1 )[0];
    +                grid.columns.splice( index, 0, column );
    +              }
    +            }
    +          });
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Scrolls to the position that was saved.  If focus is true, then
    +         * sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +         * specified row/col.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} scrollFocusState the scroll/focus state ready to be restored
    +         */
    +        restoreScrollFocus: function( grid, $scope, scrollFocusState ){
    +          if ( !grid.api.cellNav ){
    +            return;
    +          }
    +          
    +          var colDef, row;
    +          if ( scrollFocusState.colName ){
    +            var colDefs = grid.options.columnDefs.filter( function( colDef ) { return colDef.name === scrollFocusState.colName; });
    +            if ( colDefs.length > 0 ){
    +              colDef = colDefs[0];
    +            }
    +          }
    +          
    +          if ( scrollFocusState.rowVal && scrollFocusState.rowVal.row ){
    +            if ( scrollFocusState.rowVal.identity ){
    +              row = service.findRowByIdentity( grid, scrollFocusState.rowVal );
    +            } else {
    +              row = grid.renderContainers.body.visibleRowCache[ scrollFocusState.rowVal.row ];
    +            }
    +          }
    +          
    +          var entity = row && row.entity ? row.entity : null ;
    +
    +          if ( colDef || entity ) {          
    +            if (scrollFocusState.focus ){
    +              grid.api.cellNav.scrollToFocus( $scope, entity, colDef );
    +            } else {
    +              grid.api.cellNav.scrollTo( $scope, entity, colDef );
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Selects the rows that are provided in the selection
    +         * state.  If you are using `saveRowIdentity` and more than one row matches the identity
    +         * function then only the first is selected.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} selectionState the selection state ready to be restored
    +         */
    +        restoreSelection: function( grid, selectionState ){
    +          if ( !grid.api.selection ){
    +            return;
    +          }
    +          
    +          grid.api.selection.clearSelectedRows();
    +
    +          angular.forEach( selectionState, function( rowVal ) {
    +            if ( rowVal.identity ){
    +              var foundRow = service.findRowByIdentity( grid, rowVal );
    +              
    +              if ( foundRow ){
    +                grid.api.selection.selectRow( foundRow.entity );
    +              }
    +              
    +            } else {
    +              grid.api.selection.selectRowByVisibleIndex( rowVal.row );
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name findRowByIdentity
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Finds a row given it's identity value, returns the first found row
    +         * if any are found, otherwise returns null if no rows are found.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} rowVal the row we'd like to find
    +         * @returns {gridRow} the found row, or null if none found
    +         */
    +        findRowByIdentity: function( grid, rowVal ){
    +          if ( !grid.options.saveRowIdentity ){
    +            return null;
    +          }
    +          
    +          var filteredRows = grid.rows.filter( function( gridRow ) {
    +            if ( grid.options.saveRowIdentity( gridRow.entity ) === rowVal.row ){
    +              return true;
    +            } else {
    +              return false;
    +            }
    +          });
    +          
    +          if ( filteredRows.length > 0 ){
    +            return filteredRows[0];
    +          } else {
    +            return null;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.saveState.directive:uiGridSaveState
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds saveState features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-save-state></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSaveState', ['uiGridSaveStateConstants', 'uiGridSaveStateService', 'gridUtil', '$compile',
    +    function (uiGridSaveStateConstants, uiGridSaveStateService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridSaveStateService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  //add methods to GridRow
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('GridRow', ['$delegate', function($delegate) {
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.selection.api:GridRow
    +       *
    +       *  @description GridRow prototype functions added for selection
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name enableSelection
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Enable row selection for this row, only settable by internal code.
    +       *
    +       *  The grouping feature, for example, might set group header rows to not be selectable.
    +       *  <br/>Defaults to true
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name isSelected
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +       *  <br/>Defaults to false
    +       */
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name setSelected
    +         * @methodOf ui.grid.selection.api:GridRow
    +         * @description Sets the isSelected property and updates the selectedCount
    +         * Changes to isSelected state should only be made via this function
    +         * @param {bool} selelected value to set
    +         */
    +        $delegate.prototype.setSelected = function(selected) {
    +          this.isSelected = selected;
    +          if (selected) {
    +            this.grid.selection.selectedCount++;
    +          }
    +          else {
    +            this.grid.selection.selectedCount--;
    +          }
    +        };
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.grid:selection
    +           *
    +           *  @description Grid properties and functions added for selection
    +           */
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name selectedCount
    +           *  @propertyOf  ui.grid.selection.grid:selection
    +           *  @description Current count of selected rows
    +           *  @example
    +           *  var count = grid.selection.selectedCount
    +           */
    +          grid.selection.selectedCount = 0;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChanged: function (scope, row, evt) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows, evt) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                toggleRowSelection: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum, evt ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && typeof(row) !== 'undefined' && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                unSelectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected && row.enableSelection !== false ){
    +                      row.setSelected(true);
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllVisibleRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected && row.enableSelection !== false){
    +                        row.setSelected(true);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.setSelected(false);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                clearSelectedRows: function (evt) {
    +                  service.clearSelectedRows(grid, evt);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableFooterTotalSelected
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Shows the total number of selected items in footer if true.
    +           *  <br/>Defaults to true.
    +           *  <br/>GridOptions.showFooter must also be set to true.
    +           */
    +          gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name isRowSelectable
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.
    +           */
    +
    +          gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {Event} event object if resulting from event
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid, evt);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid, evt);
    +            }
    +          }
    +
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else if (row.enableSelection !== false) {
    +            row.setSelected(!selected);
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            } else {
    +              grid.selection.selectAll = false;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {Event} event object if raised from an event
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, evt, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected && rowToSelect.enableSelection !== false ){
    +                rowToSelect.setSelected(true);
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows, evt );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         * @param {Event} event object if raised from an event
    +         */
    +        clearSelectedRows: function (grid, evt) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.setSelected(false);
    +              service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +          grid.selection.selectAll = false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * @param {Event} event object if raised from an event
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows, evt ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * @param {Event} event object if raised from an event
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows, evt ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows, evt);
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  minWidth: 10,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false,
    +                  exporterSuppressExport: true 
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +              
    +              if (uiGridCtrl.grid.options.isRowSelectable !== angular.noop) {
    +                uiGridCtrl.grid.registerRowBuilder(function(row, options) {
    +                  row.enableSelection = uiGridCtrl.grid.options.isRowSelectable(row);
    +                });
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self, evt);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0, evt);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows(evt);
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            var touchStartTime = 0;
    +            var touchTimeout = 300;
    +            var selectCells = function(evt){
    +              if (evt.shiftKey) {
    +                uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect);
    +              }
    +              else if (evt.ctrlKey || evt.metaKey) {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +              }
    +              else {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +              }
    +              $scope.$apply();
    +            };
    +
    +            var touchStart = function(evt){
    +              touchStartTime = (new Date()).getTime();
    +            };
    +
    +            var touchEnd = function(evt) {
    +              var touchEndTime = (new Date()).getTime();
    +              var touchTime = touchEndTime - touchStartTime;
    +
    +              if (touchTime < touchTimeout ) {
    +                // short touch
    +                selectCells(evt);
    +              }
    +            };
    +
    +            function registerRowSelectionEvents() {
    +              if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +                $elm.addClass('ui-grid-disable-selection');
    +                $elm.on('touchstart', touchStart);
    +                $elm.on('touchend', touchEnd);
    +                $elm.on('click', selectCells);
    +
    +                $scope.registered = true;
    +              }
    +            }
    +
    +            function deregisterRowSelectionEvents() {
    +              if ($scope.registered){
    +                $elm.removeClass('ui-grid-disable-selection');
    +
    +                $elm.off('touchstart', touchStart);
    +                $elm.off('touchend', touchEnd);
    +                $elm.off('click', selectCells);
    +
    +                $scope.registered = false;
    +              }
    +            }
    +
    +            registerRowSelectionEvents();
    +            // register a dataChange callback so that we can change the selection configuration dynamically
    +            // if the user changes the options
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( function() {
    +              if ( $scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection &&
    +                !$scope.registered ){
    +                registerRowSelectionEvents();
    +              } else if ( ( !$scope.grid.options.enableRowSelection || $scope.grid.options.enableRowHeaderSelection ) &&
    +                $scope.registered ){
    +                deregisterRowSelectionEvents();
    +              }
    +            }, [uiGridConstants.dataChange.OPTIONS] );
    +
    +            $elm.on( '$destroy', dataChangeDereg);
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridGridFooter', ['$compile', 'uiGridConstants', 'gridUtil', function ($compile, uiGridConstants, gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      priority: -1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            if (!uiGridCtrl.grid.options.showGridFooter) {
    +              return;
    +            }
    +
    +
    +            gridUtil.getTemplate('ui-grid/gridFooterSelectedItems')
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +
    +                angular.element($elm[0].getElementsByClassName('ui-grid-grid-footer')[0]).append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\"><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-grid-footer',
    +    "<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{'search.totalItems' | t}} {{grid.rows.length}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    /*\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "    */\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\"></div><div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></div><!-- native scrolling --><!--<div ui-grid-native-scrollbar ng-if=\"enableVerticalScrollbar\" type=\"vertical\"></div>--><!--<div ui-grid-native-scrollbar ng-if=\"enableHorizontalScrollbar\" type=\"horizontal\"></div>--></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\" ng-style=\"containerCtrl.colContainer.getViewPortStyle()\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth()) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableTopRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !grid.expandable.expandedAll, 'ui-grid-icon-minus-squared' : grid.expandable.expandedAll }\" ng-click=\"grid.api.expandable.toggleAllRows()\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\" download=\"FILE_NAME\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/pagination',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager ng-show=\"grid.options.enablePaginationControls\"><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"paginationApi.seek(1)\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"paginationApi.previousPage()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.paginationCurrentPage\" min=\"1\" max=\"{{ paginationApi.getTotalPages() }}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"paginationApi.getTotalPages() > 0\">/ {{ paginationApi.getTotalPages() }}</span> <button type=\"button\" ng-click=\"paginationApi.nextPage()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"paginationApi.seek(paginationApi.getTotalPages())\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.paginationPageSize\" ng-options=\"o as o for o in grid.options.paginationPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/gridFooterSelectedItems',
    +    "<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"search.selectedItems\" | t}} {{grid.selection.selectedCount}})</span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.min.css b/release/3.0.0-RC.18-7774d30/ui-grid.min.css
    new file mode 100644
    index 000000000..94d5a9f7a
    --- /dev/null
    +++ b/release/3.0.0-RC.18-7774d30/ui-grid.min.css
    @@ -0,0 +1,4 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-7774d30 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;box-sizing:border-box;float:left;top:0;bottom:0;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu-button-last-col{margin-right:25px}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative;padding-top:1px}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#f0f0ee !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-grid-footer{float:left;width:100%}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid{overflow-y:scroll;max-height:300px;border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child,.ui-grid[dir=rtl] .ui-grid-header-cell:last-child{border-left:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}.ui-grid-row-selected>[ui-grid-row]>.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.min.js b/release/3.0.0-RC.18-7774d30/ui-grid.min.js
    new file mode 100644
    index 000000000..28314b580
    --- /dev/null
    +++ b/release/3.0.0-RC.18-7774d30/ui-grid.min.js
    @@ -0,0 +1,12 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-7774d30 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart",COLUMN_HEADER_CLICK:"uiGridColumnHeaderClick"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,PG_UP:33,PG_DOWN:34,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column",OPTIONS:"options"},scrollbars:{NEVER:0,ALWAYS:1}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){var c=a.col.getColClass(!1);b.addClass(c);var e,f=function(){var c=b;e&&(c.removeClass(e),e=null),e=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,c.addClass(e)};a.col.cellClass&&f();var g=a.grid.registerDataChangeCallback(f,[d.dataChange.COLUMN,d.dataChange.EDIT]),h=function(d,g){if(d!==g){(e||a.col.cellClass)&&f();var h=a.col.getColClass(!1);h!==c&&(b.removeClass(c),b.addClass(h),c=h)}},i=a.$watch("col",h),j=a.$watch("row",h),k=function(){g(),i(),j()};a.$on("$destroy",k),b.on("$destroy",k)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,e,f,g){var h=this;d.initialize(b,g),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,c,f){b.col=a;var g=d.getColumnElementPosition(b,a,c);b.menuShown?(b.colElement=c,b.colElementPosition=g,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(h.shown=b.menuShown=!0,d.repositionMenu(b,a,g,e,c),b.colElement=c,b.colElementPosition=g,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu(),b.grid.api.core.notifyDataChange(c.dataChange.COLUMN)}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",h)}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-grid-footer";return{restrict:"EA",replace:!0,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(a,c,f,g){a.grid=g.grid;var h=a.grid.options.gridFooterTemplate?a.grid.options.gridFooterTemplate:e;d.getTemplate(h).then(function(d){var e=angular.element(d),f=b(e)(a);c.append(f)})},post:function(){}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,i){function j(b){var c=!1;b.shiftKey&&(c=!0),k.grid.sortColumn(a.col,c).then(function(){k.columnMenuScope&&k.columnMenuScope.hideMenu(),k.grid.refresh()})}var k=i[0],l=i[1];a.grid=k.grid,a.renderContainer=k.grid.renderContainers[l.containerId];var m=a.col.getColClass(!1);c.addClass(m),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var n,o=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),p=function(){var b=c;n&&(b.removeClass(n),n=null),n=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(n);var d=a.grid.renderContainers.right?a.grid.renderContainers.right:a.grid.renderContainers.body;a.isLastCol=a.col===d.visibleColumnCache[d.visibleColumnCache.length-1]};a.$watch("col",function(b,d){if(b!==d){var e=a.col.getColClass(!1);e!==m&&(c.removeClass(m),c.addClass(e),m=e)}}),p();var q=a.grid.registerDataChangeCallback(p,[f.dataChange.COLUMN]);if(a.$on("$destroy",q),a.sortable=k.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=k.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var r,s=0,t=e.isTouchEnabled()?"touchstart":"mousedown";o.on(t,function(d){d.stopPropagation(),"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(s=(new Date).getTime(),r=b(function(){},h),r.then(function(){a.colMenu&&k.columnMenuScope.showMenu(a.col,c,d)}),k.fireEvent(f.events.COLUMN_HEADER_CLICK,{event:d,columnName:a.col.colDef.name}))});var u=e.isTouchEnabled()?"touchend":"mouseup";o.on(u,function(){b.cancel(r)}),a.$on("$destroy",function(){o.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),k.columnMenuScope.menuShown&&k.columnMenuScope.col===a.col?k.columnMenuScope.hideMenu():k.columnMenuScope.showMenu(a.col,c)},a.sortable){var v=e.isTouchEnabled()?"touchend":"click";o.on(v,function(a){a.stopPropagation(),b.cancel(r);var c=(new Date).getTime(),d=c-s;d>h||j(a)}),a.$on("$destroy",function(){b.cancel(r)})}if(a.filterable){var w=[];angular.forEach(a.col.filters,function(b,c){w.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(k.grid.api.core.raise.filterChanged(),k.grid.refresh().then(function(){if(k.prevScrollArgs&&k.prevScrollArgs.y&&k.prevScrollArgs.y.percentage){var a=new g(k.grid,null,null,"uiGridHeaderCell.toggleMenu");a.y.percentage=k.prevScrollArgs.y.percentage,a.fireScrollingEvent()}}))}))}),a.$on("$destroy",function(){angular.forEach(w,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth(),b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,g=a,i=!1,j=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(g/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",i=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,i=!0)});var k=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return k.indexOf(a.widthType)-k.indexOf(b.widthType)}).forEach(function(a){var b=j(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,g-=a.drawnWidth}),i&&g>0&&c>0&&a>c){var l=function(a){g>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,g--)},m=0;do m=g,b.forEach(l);while(g>0&&g!==m)}c=Math.max(c,a);var n="";return b.forEach(function(a){n+=a.getColClassDefinition()}),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),n}{var g=e[0],h=e[1];g.grid}d.disableAnimations(b),h.header=b;var i=b[0].getElementsByClassName("ui-grid-header-viewport")[0];i&&(h.headerViewport=i),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService","uiGridConstants",function(a,b,c){var d={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",d.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",d.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var c=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?c=c.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),c=c.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(c=c.concat(d.showHideColumns(b))),c},showHideColumns:function(a){var c=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(c.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};d.setMenuItemTitle(e,b,a.grid),c.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},d.setMenuItemTitle(e,b,a.grid),c.push(e)}}),c):c},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh(),a.grid.api.core.notifyDataChange(c.dataChange.COLUMN)}};return d}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d,e,g){var h=this;h.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var e="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(e=d.originalEvent.type),angular.element(document).off("click touchstart",i),b(function(){angular.element(document).on(e,i)})},h.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",i)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var i=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",i),a.$on("$destroy",function(){angular.element(document).off("click touchstart",i)}),a.$on("$destroy",function(){angular.element(c).off("resize",i)}),g&&a.$on("$destroy",g.grid.api.core.on.scrollEvent(a,i)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,i))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil","ScrollEvent",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(a,c,f,g){function h(b){if(!b.grid||b.grid.id===n.id){if(b.y&&a.bindScrollVertical){m.prevScrollArgs=b;var c=b.getNewScrollTop(o,m.viewport);(b.source!==e.Sources.ViewPortScroll||b.sourceColContainer!==p)&&(m.viewport[0].scrollTop=c)}if(b.x&&a.bindScrollHorizontal){m.prevScrollArgs=b;var f=b.getNewScrollLeft(p,m.viewport);a.newScrollLeft=f,m.headerViewport&&(m.headerViewport.scrollLeft=d.denormalizeScrollLeft(m.headerViewport,f)),m.footerViewport&&(m.footerViewport.scrollLeft=d.denormalizeScrollLeft(m.footerViewport,f)),b.source!==e.Sources.ViewPortScroll&&(m.viewport[0].scrollLeft=f),m.prevScrollLeft=f}}}function i(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,f;d=a.targetTouches[0].screenX,f=a.targetTouches[0].screenY,b=-(d-t),c=-(f-s),w=1>c?-1:1,x=1>b?-1:1,c*=2,b*=2;var g=new e(n,o,p,e.Sources.RenderContainerTouchMove);if(0!==c){var h=(u+c)/o.getVerticalScrollLength();h>1?h=1:0>h&&(h=0),g.y={percentage:h,pixels:c}}if(0!==b){var i=(v+b)/(p.getCanvasWidth()-p.getViewportWidth());i>1?i=1:0>i&&(i=0),g.x={percentage:i,pixels:b}}g.fireScrollingEvent()}function j(a){a.originalEvent&&(a=a.originalEvent),b.unbind("touchmove",i),b.unbind("touchend",j),b.unbind("touchcancel",j);{var c=m.viewport[0].scrollTop,d=m.viewport[0].scrollTop;Math.abs(c-u),Math.abs(d-v),new Date-r}}function k(){var b="",c=p.getCanvasWidth(),d=p.getViewportWidth(),e=o.getCanvasHeight();"body"!==a.containerId&&(e+=n.scrollbarHeight);var f=o.getViewportHeight(),g=p.getHeaderViewportWidth(),h=p.getHeaderViewportWidth();return b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { width: "+(c+n.scrollbarWidth)+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-canvas { width: "+c+n.scrollbarWidth+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==q.explicitHeaderHeight&&null!==q.explicitHeaderHeight&&q.explicitHeaderHeight>0?b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.explicitHeaderHeight+"px; }":void 0!==q.innerHeaderHeight&&null!==q.innerHeaderHeight&&q.innerHeaderHeight>0&&(b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.innerHeaderHeight+"px; }"),b}var l=g[0],m=g[1],n=l.grid,o=m.rowContainer,p=m.colContainer,q=n.renderContainers[a.containerId];c.addClass("ui-grid-render-container-"+a.containerId),(a.bindScrollHorizontal||a.bindScrollVertical)&&n.api.core.on.scrollEvent(a,h),c.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){var b=d.normalizeWheelEvent(a),c=new e(n,o,p,e.Sources.RenderContainerMouseWheel);if(0!==b.deltaY){var f=-120*b.deltaY,g=(m.viewport[0].scrollTop+f)/o.getVerticalScrollLength();0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:f}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(m.viewport),j=(i+h)/(p.getCanvasWidth()-p.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}(c.y&&0!==c.y.percentage&&1!==c.y.percentage&&0!==m.viewport[0].scrollTop||c.x&&0!==c.x.percentage&&1!==c.x.percentage)&&a.preventDefault(),c.fireThrottledScrollingEvent()});var r,s=0,t=0,u=0,v=0,w=1,x=1;d.isTouchEnabled()&&c.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),l.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),r=new Date,s=a.targetTouches[0].screenY,t=a.targetTouches[0].screenX,u=m.viewport[0].scrollTop,v=m.viewport[0].scrollLeft,b.on("touchmove",i),b.on("touchend touchcancel",j)}),c.bind("$destroy",function(){c.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){c.unbind(a)})}),l.grid.registerStyleComputation({priority:6,func:k})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){function e(){a.row.getRowTemplateFn.then(function(c){var d=a.$new();c(d,function(a){h&&(h.remove(),i.$destroy()),b.empty().append(a),h=a,i=d})})}{var f=d[0],g=d[1];f.grid}a.grid=f.grid,a.colContainer=g.colContainer;var h,i;e(),a.$watch("row.getRowTemplateFn",function(a,b){a!==b&&e()})},post:function(){}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil","ScrollEvent",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){var g=f[0],h=f[1];c.containerCtrl=h;var i=h.rowContainer,j=h.colContainer,k=g.grid;c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var c=d[0].scrollTop,e=a.normalizeScrollLeft(d),f=-1,g=-1;if(e!==j.prevScrollLeft){k.flagScrollingHorizontally();var h=(e-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth());f=0!==h?e/h:0,j.adjustScrollHorizontal(e,f)}if(c!==i.prevScrollTop){k.flagScrollingVertically();var l=(c-i.prevScrollTop,i.getVerticalScrollLength());g=c/l,g>1&&(g=1),0>g&&(g=0),i.adjustScrollVertical(c,g)}var m=new b(k,i,j,b.Sources.ViewPortScroll);m.newScrollLeft=e,m.newScrollTop=c,f>-1&&(m.x={percentage:f}),g>-1&&(m.y={percentage:g}),m.fireScrollingEvent()})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns({orderByColumnDefs:!0}).then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===n.grid.options.columnDefs.length&&b.length>0&&n.grid.buildColumnDefsFromData(b),(n.grid.options.columnDefs.length>0||b.length>0)&&d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()})),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),n.grid.appScope=n.grid.appScope||a.$parent,b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.refreshCanvas(!0)}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.calcFooterHeight(),m=0;
    +i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas(),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth||e.width||0}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0!==h&&h||e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.appScope=b.options.appScopeProvider,b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.calcFooterHeight(),b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),g=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.scrollbarHeight=0,b.scrollbarWidth=0,b.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarHeight=d.getScrollbarWidth()),b.options.enableVerticalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarWidth=d.getScrollbarWidth()),b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT]),b.registerStyleComputation({priority:10,func:b.getFooterStyles})};return o.prototype.calcFooterHeight=function(){if(!this.hasFooter())return 0;var a=0;return this.options.showGridFooter&&(a+=this.options.gridFooterHeight),this.options.showColumnFooter&&(a+=this.options.columnFooterHeight),a},o.prototype.getFooterStyles=function(){var a=".grid"+this.id+" .ui-grid-footer-aggregates-row { height: "+this.options.columnFooterHeight+"px; }";return a+=" .grid"+this.id+" .ui-grid-footer-info { height: "+this.options.gridFooterHeight+"px; }"},o.prototype.hasFooter=function(){return this.options.showGridFooter||this.options.showColumnFooter},o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b,c){var f=d.nextUid();b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[f]={callback:a,types:b,_this:c};var g=this,h=function(){delete g.dataChangeCallbacks[f]};return h},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&(b._this?b.callback.apply(b._this,this):b.callback(this))},this)},o.prototype.notifyDataChange=function(a){var b=e.dataChange;a===b.ALL||a===b.COLUMN||a===b.EDIT||a===b.ROW||a===b.OPTIONS?this.callDataChangeCallbacks(a):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+a)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.refresh()})})},o.prototype.buildColumns=function(b){var c={orderByColumnDefs:!1};angular.extend(c,b);var e,f=this,h=[],i=f.rowHeaderColumns.length;for(e=0;e<f.columns.length;e++)f.getColDef(f.columns[e].name)||(f.columns.splice(e,1),e--);if(f.rowHeaderColumns.forEach(function(a){f.columns.unshift(a)}),f.options.columnDefs.forEach(function(a,b){f.preprocessColDef(a);var c=f.getColumn(a.name);c?c.updateColumnDef(a,!1):(c=new g(a,d.nextUid(),f),f.columns.splice(b+i,0,c)),f.columnBuilders.forEach(function(b){h.push(b.call(f,a,c,f.options))})}),c.orderByColumnDefs){var j=f.columns.slice(0);for(e=0;e<f.options.columnDefs.length;e++)j[e+i]=f.columns[e+i].name!==f.options.columnDefs[e].name?f.getColumn(f.options.columnDefs[e].name):f.columns[e+i];f.columns.length=0,Array.prototype.splice.apply(f.columns,[0,0].concat(j))}return a.all(h).then(function(){f.rows.length>0&&f.assignTypes()})},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){var b=this;if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");if(void 0===a.name&&void 0!==a.field){var c=b.getColumn(a.field);if(c){var d=new RegExp("^"+a.field+"(\\d+)$","i"),e=b.columns.filter(function(a){return d.test(a.displayName)}).sort(function(a,b){if(a===b)return 0;var c=a.match(d)[1],e=b.match(d)[1];return parseInt(c,10)>parseInt(e,10)?1:-1});if(0===e.length)a.name=a.field+"2";else{var f=e[e.length-1].displayName.match(d)[1];f=parseInt(f,10),a.name=a.field+(f+1)}}else a.name=a.field}},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;{0===g.rows.length}for(g.rows.length=0,c=0;c<b.length;c++){var j=b[c];e=i.get(j),f=e?e.row:g.processRowBuilders(new h(j,c,g)),g.rows.push(f),d.put(j,{i:c,entity:j,row:f})}g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var k,l,m;if(g.options.enableRowHashing){k=[],m=[];var n={};for(l=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var o=!1;g.options.getRowIdentity(f)||(o=!0),e=d.get(f),e?e.row&&(n[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),o?m.push(f):k.push(f))}for(c=0;c<g.rows.length;c++){var p=g.rows[c],q=g.options.rowIdentity(p.entity);n[q]||l.push(p)}}var r=k||[],s=m||b;r=r.concat(g.newInN(g.rows,s,"entity")),g.addRows(r);var t=g.getDeletedRows(l||g.rows,b);for(c=0;c<t.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(t[c].entity),g.rows.splice(g.rows.indexOf(t[c]),1)}else g.createRowHashMap(),g.rows.length=0;var u=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),v=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([u,v])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.canvasHeightShouldUpdate=!0,"undefined"==typeof d.visibleRowCache?d.visibleRowCache=[]:d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}b.api.core.raise.rowsRendered(this.api)},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.updateCanvasHeight=function(){var a=this;for(var b in a.renderContainers)if(a.renderContainers.hasOwnProperty(b)){var c=a.renderContainers[b];c.canvasHeightShouldUpdate=!0}},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight,c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth,c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b===a||b.colDef.suppressRemoveSort||(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)&&g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(null,c.prevScrolltopPercentage),c.adjustColumns(null,c.prevScrollleftPercentage)}},o.prototype.hasLeftContainerColumns=function(){return this.hasLeftContainer()&&this.renderContainers.left.renderedColumns.length>0},o.prototype.hasRightContainerColumns=function(){return this.hasRightContainer()&&this.renderContainers.right.renderedColumns.length>0},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,c,d,e){return b.$on(a,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(e?e:d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged"),this.registerEvent("core","rowsRendered"),this.registerEvent("core","scrollEvent"),this.registerEvent("core","canvasHeightChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.eventId,a.handler,c.grid,a._this)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$emit.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b,c){var e=f(g,b,d.grid,c),h={handler:b,dereg:e,eventId:g,scope:a,_this:c};d.listeners.push(h);var i=function(){h.dereg();var a=d.listeners.indexOf(h);d.listeners.splice(a,1)};return a.$on("$destroy",function(){i()}),i}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a,!0)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b,c){var e=this;if(e.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.grid.options.columnDefs.indexOf(b));e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(e.width)||!angular.isNumber(e.width))if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(f);e.width=b.width}e.minWidth=b.minWidth?b.minWidth:30,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,"string"!=typeof e.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+e.field),e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.footerCellClass=b.footerCellClass,e.cellClass=b.cellClass,e.headerCellClass=b.headerCellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),c&&e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),c&&(e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)),d.prototype.unsort=function(){this.sort={},e.grid.api.core.raise.sortChanged(e,e.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showGridFooter=c.showGridFooter===!0,c.showColumnFooter=c.showColumnFooter===!0,c.columnFooterHeight="undefined"!=typeof c.columnFooterHeight?c.columnFooterHeight:30,c.gridFooterHeight="undefined"!=typeof c.gridFooterHeight?c.gridFooterHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c.appScopeProvider=c.appScopeProvider||null,c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],d.canvasHeightShouldUpdate=!0,d.$$canvasHeight=0,c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight,d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth,c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},c.prototype.getCanvasHeight=function(){var a=this;if(!a.canvasHeightShouldUpdate)return a.$$canvasHeight;var b=a.$$canvasHeight;return a.$$canvasHeight=0,a.visibleRowCache.forEach(function(b){a.$$canvasHeight+=b.height}),a.canvasHeightShouldUpdate=!1,a.grid.api.core.raise.canvasHeightChanged(b,a.$$canvasHeight),a.$$canvasHeight},c.prototype.getVerticalScrollLength=function(){return this.getCanvasHeight()-this.getViewportHeight()},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];
    +this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getVerticalScrollLength());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if("undefined"!=typeof a&&null!==a){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return}var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var b,c=this,d=[],e=[],f=0,g=c.getViewportWidth(),h=0,i=0,j="",k=c.visibleColumnCache;k.forEach(function(b){if(b.visible){var c=!1;angular.isNumber(b.width)||(c=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(f=parseInt(f+b.width.length,10),d.push(b)):c?e.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=g-h;if(e.length>0){for(l=0;l<e.length;l++){m=e[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1))}e.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(d.length>0){var q=parseInt(o/f,10);for(l=0;l<d.length;l++)m=d[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,f--,i+=n,m.drawnWidth=n,b=m,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,f--,i+=n,m.drawnWidth=n,d.splice(l,1));q=parseInt(o/f,10),d.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=g-parseInt(i,10);if(r>0&&i>0&&g>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}g>i&&(i=g),k.forEach(function(a){j+=a.getColClassDefinition()}),c.canvasWidth=parseInt(i,10),this.columnStyles=j},c.prototype.getViewPortStyle=function(){var a=this,c={};return"body"===a.name?(c["overflow-x"]=a.grid.options.enableHorizontalScrollbar===b.scrollbars.NEVER?"hidden":"scroll",c["overflow-y"]=a.grid.isRTL()?a.grid.hasLeftContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":a.grid.hasRightContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"):"left"===a.name?(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":"hidden"):(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"),c},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.$$height=d.options.rowHeight}return Object.defineProperty(b.prototype,"height",{get:function(){return this.$$height},set:function(a){a!==this.$$height&&(this.grid.updateCanvasHeight(),this.$$height=a)}}),b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){angular.module("ui.grid").factory("ScrollEvent",["gridUtil",function(a){function b(b,c,d,e){var f=this;if(!b)throw new Error("grid argument is required");f.grid=b,f.source=e,f.sourceRowContainer=c,f.sourceColContainer=d,f.newScrollLeft=null,f.newScrollTop=null,f.x=null,f.y=null,f.fireThrottledScrollingEvent=a.throttle(function(){f.grid.api.core.raise.scrollEvent(f)},f.grid.options.scrollThrottle,{trailing:!0})}return b.prototype.fireScrollingEvent=function(){this.grid.api.core.raise.scrollEvent(this)},b.prototype.getNewScrollLeft=function(b,c){var d=this;if(!d.newScrollLeft){var e,f=b.getCanvasWidth()-b.getViewportWidth(),g=a.normalizeScrollLeft(c);if("undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage)e=d.x.percentage;else{if("undefined"==typeof d.x.pixels||void 0===d.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");e=d.x.percentage=(g+d.x.pixels)/f}return Math.max(0,e*f)}return d.newScrollLeft},b.prototype.getNewScrollTop=function(a,b){var c=this;if(!c.newScrollTop){var d,e=a.getVerticalScrollLength(),f=b[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)d=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=c.y.percentage=(f+c.y.pixels)/e}return Math.max(0,d*e)}return c.newScrollTop},b.Sources={ViewPortScroll:"ViewPortScroll",RenderContainerMouseWheel:"RenderContainerMouseWheel",RenderContainerTouchMove:"RenderContainerTouchMove",Other:99},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowBuilder(g.rowTemplateAssigner),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)},rowTemplateAssigner:function(d){var e=this;if(d.rowTemplate){var f=b.defer();d.getRowTemplateFn=f.promise,a.getTemplate(d.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+d.rowTemplate+"'")})}else d.rowTemplate=e.options.rowTemplate,d.getRowTemplateFn=e.getRowTemplateFn;return d.getRowTemplateFn}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var b=angular.module("ui.grid");b.service("rowSearcher",["gridUtil","uiGridConstants",function(b,c){var d=c.filter.STARTS_WITH,e={};return e.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},e.stripTerm=function(b){var c=e.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},e.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return d;var b=e.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var f=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+f+"$",c)}return d},e.setupFilters=function(a){for(var b=[],d=a.length,f=0;d>f;f++){var g=a[f];if(g.noTerm||g.term){var h={},i="";g.flags&&g.flags.caseSensitive||(i+="i"),g.term&&(h.term=e.stripTerm(g)),h.condition=g.condition?g.condition:e.guessCondition(g),h.flags=angular.extend({caseSensitive:!1},g.flags),h.condition===c.filter.STARTS_WITH&&(h.startswithRE=new RegExp("^"+h.term,i)),h.condition===c.filter.ENDS_WITH&&(h.endswithRE=new RegExp(h.term+"$",i)),h.condition===c.filter.CONTAINS&&(h.containsRE=new RegExp(h.term,i)),h.condition===c.filter.EXACT&&(h.exactRE=new RegExp("^"+h.term+"$",i)),b.push(h)}}return b},e.runColumnFilter=function(a,b,d,e){var f=typeof e.condition,g=e.term,h=a.getCellValue(b,d);if(e.condition instanceof RegExp)return e.condition.test(h);if("function"===f)return e.condition(g,h,b,d);if(e.startswithRE)return e.startswithRE.test(h);if(e.endswithRE)return e.endswithRE.test(h);if(e.containsRE)return e.containsRE.test(h);if(e.exactRE)return e.exactRE.test(h);if(e.condition===c.filter.NOT_EQUAL){var i=new RegExp("^"+g+"$");return!i.exec(h)}if("number"==typeof h){var j=parseFloat(g.replace(/\\./,"."));isNaN(j)||(g=j)}return e.condition===c.filter.GREATER_THAN?h>g:e.condition===c.filter.GREATER_THAN_OR_EQUAL?h>=g:e.condition===c.filter.LESS_THAN?g>h:e.condition===c.filter.LESS_THAN_OR_EQUAL?g>=h:!0},e.searchColumn=function(a,b,c,d){if(a.options.useExternalFiltering)return!0;for(var f=d.length,g=0;f>g;g++){var h=d[g],i=e.runColumnFilter(a,b,c,h);if(!i)return!1}return!0},e.search=function(a,b,c){if(b){for(var d=[],f=c.length,g=0;f>g;g++){var h=c[g];"undefined"!=typeof h.filters&&(h.filters.length>1||1===h.filters.length&&h.filters[0].term)?d.push({col:h,filters:e.setupFilters(h.filters)}):"undefined"!=typeof h.filter&&h.filter&&("undefined"!=typeof h.filter.term&&h.filter.term||h.filter.noTerm)&&d.push({col:h,filters:e.setupFilters([h.filter])})}if(d.length>0){for(var i=function(a,b,c,d){(b.forceInvisible||!e.searchColumn(a,b,c,d))&&(b.visible=!1)},j=function(a,c){for(var d=b.length,e=0;d>e;e++)i(a,b[e],c.col,c.filters)},k=d.length,l=0;k>l;l++)j(a,d[l]);a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()}return b}},e}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toString().toLowerCase(),f=b.toString().toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);angular.forEach(c,function(a,b){a.entity.$uiGridIndex=b});var j=c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return 0===k?c.entity.$uiGridIndex-e.entity.$uiGridIndex:h===b.ASC?k:0-k});return angular.forEach(j,function(a){delete a.entity.$uiGridIndex}),j}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){p.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},pagination:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"всего строк: ",sum:"итого: ",avg:"среднее: ",min:"мин: ",max:"макс: "},gridMenu:{columns:"Столбцы:",importerTitle:"Import file",exporterAllAsCsv:"Экспортировать всё в CSV",exporterVisibleAsCsv:"Экспортировать видимые данные в CSV",exporterSelectedAsCsv:"Экспортировать выбранные данные в CSV",exporterAllAsPdf:"Экспортировать всё в PDF",exporterVisibleAsPdf:"Экспортировать видимые данные в PDF",exporterSelectedAsPdf:"Экспортировать выбранные данные в PDF"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},pagination:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3,PG_UP:4,PG_DOWN:5},EVENT_TYPE:{KEYDOWN:0,CLICK:1}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[],this.bodyContainer=a};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getFocusableRows=function(){return this.rows.filter(function(a){return a.allowCellFocus!==!1})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c);case d.direction.PG_UP:return this.getRowColPageUp(b,c);case d.direction.PG_DOWN:return this.getRowColPageDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=1);var h=0===f?d.length-1:f-1;return h>f?0===g?new a(b,d[h]):new a(e[g-1],d[h]):new a(b,d[h])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=f===d.length-1?0:f+1;return f>h?g===e.length-1?new a(b,d[h]):new a(e[g+1],d[h]):new a(b,d[h])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),g===e.length-1?new a(b,d[f]):new a(e[g+1],d[f])},e.prototype.getRowColPageDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return g>=e.length-h?new a(e[e.length-1],d[f]):new a(e[g+h],d[f])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),0===g?new a(b,d[f]):new a(e[g-1],d[f])},e.prototype.getRowColPageUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return 0>g-h?new a(e[0],d[f]):new a(e[g-h],d[f])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory","ScrollEvent",function(a,b,c,d,e,f){var g={initializeGrid:function(a){a.registerColumnBuilder(g.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null,a.cellNav.focusedCells=[],g.defaultGridOptions(a.options);var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(b,c,d){g.scrollTo(a,b,c,d)},scrollToFocus:function(b,c,d){g.scrollToFocus(a,b,c,d)},scrollToIfNecessary:function(b,c,d){g.scrollToIfNecessary(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol},getCurrentSelection:function(){return a.cellNav.focusedCells},rowColSelectIndex:function(b){for(var c=-1,d=0;d<a.cellNav.focusedCells.length;d++)if(a.cellNav.focusedCells[d].col.uid===b.col.uid&&a.cellNav.focusedCells[d].row.uid===b.row.uid){c=d;break}return c}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.modifierKeysToMultiSelectCells=a.modifierKeysToMultiSelectCells===!0},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.PG_UP?c.direction.PG_UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:a.keyCode===b.keymap.PG_DOWN?c.direction.PG_DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&"undefined"!=typeof c&&(e=a.getRow(c)),null!==d&&"undefined"!=typeof d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToFocus:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f);var g={row:e,col:f};a.cellNav.broadcastCellNav(g)},scrollToInternal:function(a,b,c,d){var e=new f(a,null,null,"uiGridCellNavService.scrollToInternal");if(null!==c){var g=a.renderContainers.body.visibleRowCache.indexOf(c),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;e.y={percentage:i}}null!==d&&(e.x={percentage:this.getLeftWidth(a,d)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(e.y||e.x)&&e.fireScrollingEvent()},scrollToIfNecessary:function(a,b,c,d){var e=new f(a,null,null,"uiGridCellNavService.scrollToIfNecessary"),g=a.renderContainers.body.visibleRowCache,h=a.renderContainers.body.visibleColumnCache,i=a.renderContainers.body.prevScrollTop+a.headerHeight;i=0>i?0:i;var j=a.renderContainers.body.prevScrollLeft,k=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight,l=a.renderContainers.body.prevScrollLeft+a.gridWidth;if(null!==c){var m=g.indexOf(c),n=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight(),o=(m+1)*a.options.rowHeight;o=0>o?0:o;var p,q;i>o?(p=a.renderContainers.body.prevScrollTop-(i-o),q=p/n,e.y={percentage:q}):o>k&&(p=o-k+a.renderContainers.body.prevScrollTop,q=p/n,e.y={percentage:q})}if(null!==d){for(var r=h.indexOf(d),s=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),t=0,u=0;r>u;u++){var v=h[u];t+=v.drawnWidth}t=0>t?0:t;var w=t+d.drawnWidth;w=0>w?0:w;var x,y;j>t?(x=a.renderContainers.body.prevScrollLeft-(j-t),y=x/s,y=y>1?1:y,e.x={percentage:y}):w>l&&(x=w-l+a.renderContainers.body.prevScrollLeft,y=x/s,y=y>1?1:y,e.x={percentage:y})}(e.y||e.x)&&e.fireScrollingEvent()},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return g}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,e,f,g){var h=b,i=g.grid;c.initializeGrid(i),g.cellNav={},g.cellNav.focusCell=function(a,b){g.cellNav.broadcastCellNav({row:a,col:b})},g.cellNav.broadcastCellNav=i.cellNav.broadcastCellNav=function(a,b){b=!(void 0===b||!b),g.cellNav.broadcastFocus(a,b),h.$broadcast(d.CELL_NAV_EVENT,a,b)},g.cellNav.broadcastFocus=function(b,c){c=!(void 0===c||!c);var d=b.row,e=b.col,f=g.grid.api.cellNav.rowColSelectIndex(b);if(null===i.cellNav.lastRowCol||-1===f){var h=new a(d,e);i.api.cellNav.raise.navigate(h,i.cellNav.lastRowCol),i.cellNav.lastRowCol=h,g.grid.options.modifierKeysToMultiSelectCells&&c?i.cellNav.focusedCells.push(b):i.cellNav.focusedCells=[b]}else i.options.modifierKeysToMultiSelectCells&&c&&f>=0&&i.cellNav.focusedCells.splice(f,1)},g.cellNav.handleKeyDown=function(a){var e=c.getDirection(a);if(null===e)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var h=g.grid.api.cellNav.getFocusedCell();if(h){var j=g.grid.renderContainers[f].cellNav.getNextRowCol(e,h.row,h.col);return j.eventType=d.EVENT_TYPE.KEYDOWN,g.cellNav.broadcastCellNav(j),c.scrollToIfNecessary(i,b,j.row,j.col),a.stopPropagation(),a.preventDefault(),!1}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,d,f,g){var h=g[0],i=g[1];if(h.grid.api.cellNav){var j=i.containerId,k=h.grid;e.decorateRenderContainers(k),d.attr("tabindex",-1),d.on("keydown",function(a){return a.uiGridTargetRenderContainerId=j,h.cellNav.handleKeyDown(a)});var l=!1;k.api.core.on.scrollEvent(c,function(c){c.grid&&c.grid.id!==h.grid.id||null!=h.grid.api.cellNav.getFocusedCell()&&("uiGridCellNavService.scrollToIfNecessary"===c.source?l=!0:a(l?function(){a(function(){var a=h.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&d[0].focus(),h.cellNav.broadcastCellNav(a),l=!1})}:function(){var a={col:{uid:null},row:{uid:null}};h.cellNav.broadcastCellNav(a)}))})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",-1)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}e.grid.api.cellNav&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey),c.stopPropagation()}),b.$on(f.CELL_NAV_EVENT,function(a,d,g){d.row===b.row&&d.col===b.col?(e.grid.options.modifierKeysToMultiSelectCells&&g&&-1===e.grid.api.cellNav.rowColSelectIndex(d)?i():h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&c.find("div")[0].focus()):e.grid.options.modifierKeysToMultiSelectCells&&g||i()}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","$timeout","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g,h){var i=500;return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(f,j,k,l){function m(){j.on("dblclick",t),j.on("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").on("focus",q),j.on("touchstart",n)}function n(a){"undefined"!=typeof a.originalEvent&&void 0!==a.originalEvent&&(a=a.originalEvent),j.on("touchend",o),A=c(function(){},i),A.then(function(){setTimeout(t,0),j.off("touchend",o)})}function o(){c.cancel(A),j.off("touchend",o)}function p(){j.off("dblclick",t),j.off("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").off("focus",q),j.off("touchstart",n)}function q(a){l&&l.cellNav&&l.cellNav.focusCell(f.row,f.col),a.stopPropagation(),t()}function r(a){h.isStartEditKey(a)&&t()}function s(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(f):a.colDef.cellEditableCondition)}function t(){if(!C&&s(f.col,f.row)){f.grid.api.cellNav&&f.grid.api.cellNav.scrollToIfNecessary(f,f.row,f.col),z=g(f.row.getQualifiedColField(f.col)),y=z(f),x=f.col.editableCellTemplate,x=x.replace(d.MODEL_COL_FIELD,f.row.getQualifiedColField(f.col));var b=f.col.colDef.editDropdownFilter?"|"+f.col.colDef.editDropdownFilter:"";x=x.replace(d.CUSTOM_FILTERS,b);var c="text";switch(f.col.colDef.type){case"boolean":c="checkbox";break;case"number":c="number";break;case"date":c="date"}x=x.replace("INPUT_TYPE",c);var h=f.col.colDef.editDropdownRowEntityOptionsArrayPath;f.editDropdownOptionsArray=h?w(f.row.entity,h):f.col.colDef.editDropdownOptionsArray,f.editDropdownIdLabel=f.col.colDef.editDropdownIdLabel?f.col.colDef.editDropdownIdLabel:"id",f.editDropdownValueLabel=f.col.colDef.editDropdownValueLabel?f.col.colDef.editDropdownValueLabel:"value";f.$apply(function(){C=!0,p();var b=angular.element(x);j.append(b),B=f.$new(),a(b)(B);var c=angular.element(j.children()[0]);D=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var i=f.col.grid.api.core.on.scrollEvent(f,function(){u(!0),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),i(),k(),l()
    +}),k=f.$on(e.events.END_CELL_EDIT,function(a,b){u(b),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),k(),i(),l()}),l=f.$on(e.events.CANCEL_CELL_EDIT,function(){v(),l(),i(),k()});f.$broadcast(e.events.BEGIN_CELL_EDIT),f.grid.api.edit.raise.beginCellEdit(f.row.entity,f.col.colDef)}}function u(a){if(C){var b=angular.element(j.children()[0]);B.$destroy(),angular.element(j.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&D&&b[0].focus(),D=!1,C=!1,m(),f.grid.api.core.notifyDataChange(d.dataChange.EDIT)}}function v(){C&&(z.assign(f,y),f.$apply(),f.grid.api.edit.raise.cancelCellEdit(f.row.entity,f.col.colDef),u(!0))}function w(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split(".");c.length;){var d=c.shift();if(!(d in a))return;a=a[d]}return a}if(f.col.colDef.enableCellEdit&&f.row.enableCellEdit!==!1){var x,y,z,A,B,C=!1,D=!1;m();try{var E=b.get("uiGridCellNavConstants");f.col.colDef.enableCellEditOnFocus&&f.$on(E.CELL_NAV_EVENT,function(a,b){b.row===f.row&&b.col===f.col?t():u()})}catch(F){}}}}}]),a.directive("uiGridEditor",["gridUtil","uiGridConstants","uiGridEditConstants",function(a,b,c){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(a,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),a.$on(c.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(b){a.stopEdit(b)})}),a.deepEdit=!1,a.stopEdit=function(b){a.inputForm&&!a.inputForm.$valid?(b.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT)):a.$emit(c.events.END_CELL_EDIT),a.deepEdit=!1},d.on("click",function(){a.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case b.keymap.ESC:d.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT);break;case b.keymap.ENTER:a.stopEdit(d);break;case b.keymap.TAB:a.stopEdit(d)}if(a.deepEdit)switch(d.keyCode){case b.keymap.LEFT:d.stopPropagation();break;case b.keymap.RIGHT:d.stopPropagation();break;case b.keymap.UP:d.stopPropagation();break;case b.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("uiGridEditor",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{priority:-100,require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.expandable={},c.expandable.expandedAll=!1,c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.expandableRowHeaderWidth=c.options.expandableRowHeaderWidth||40,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)},toggleAllRows:function(){b.toggleAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.isExpanded?b.height=b.grid.options.rowHeight+a.options.expandableRowHeight:(b.height=b.grid.options.rowHeight,a.expandable.expandedAll=!1),a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!0,a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!1,a.refresh()},toggleAllRows:function(a){a.expandable.expandedAll?b.collapseAllRows(a):b.expandAllRows(a)}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",displayName:"",exporterSuppressExport:!0,enableColumnResizing:!1,enableColumnMenu:!1,width:f.grid.options.expandableRowHeaderWidth||40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),g.headerCellTemplate=b.get("ui-grid/expandableTopRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGrid",["uiGridExpandableService","$templateCache",function(){return{replace:!0,priority:1e3,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,c,d){d.grid.api.core.on.renderingComplete(a,function(){a.row&&a.row.grid&&a.row.grid.options&&a.row.grid.options.enableExpandable&&(d.grid.parentRow=a.row)})},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",BUTTON_LABEL:"BUTTON_LABEL",FILE_NAME:"FILE_NAME"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c){h.csvExport(a,b,c)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterCsvFilename=a.exporterCsvFilename?a.exporterCsvFilename:"download.csv",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterHeaderFilterUseName=a.exporterHeaderFilterUseName===!0,a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.formatAsCsv(d,e,a.options.exporterCsvColumnSeparator);this.downloadFile(a.options.exporterCsvFilename,f)},getColumnHeaders:function(a,c){var d=[];return angular.forEach(a.columns,function(e){!e.visible&&c!==b.ALL||e.colDef.exporterSuppressExport===!0||-1!==a.options.exporterSuppressColumns.indexOf(e.name)||d.push({name:e.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(a.options.exporterHeaderFilterUseName?e.name:e.displayName):e.displayName,width:e.drawnWidth?e.drawnWidth:e.width,align:"number"===e.colDef.type?"right":"left"})}),d},getData:function(a,c,e){var f,g=[];switch(c){case b.ALL:f=a.rows;break;case b.VISIBLE:f=a.getVisibleRows();break;case b.SELECTED:a.api.selection?f=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(f,function(c){if(c.exporterEnableExporting!==!1){var d=[];angular.forEach(a.columns,function(f){if((f.visible||e===b.ALL)&&f.colDef.exporterSuppressExport!==!0&&-1===a.options.exporterSuppressColumns.indexOf(f.name)){var g={value:a.options.exporterFieldCallback(a,c,f,a.getCellValue(c,f))};f.colDef.exporterPdfAlign&&(g.alignment=f.colDef.exporterPdfAlign),d.push(g)}}),g.push(d)}}),g},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},downloadFile:function(a,b){var c,d=document,e=d.createElement("a"),f="application/octet-stream;charset=utf-8";if(navigator.msSaveBlob)return navigator.msSaveBlob(new Blob(["",b],{type:f}),a);if("download"in e){var g=new Blob([b],{type:f});c=URL.createObjectURL(g),e.setAttribute("download",a)}else c="data:"+f+","+encodeURIComponent(b),e.setAttribute("target","_blank");e.href=c,e.setAttribute("style","display:none;"),d.body.appendChild(e),setTimeout(function(){if(e.click)e.click();else if(document.createEvent){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0),e.dispatchEvent(a)}d.body.removeChild(e)},100)},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&(h.header=a.options.exporterPdfHeader),a.options.exporterPdfFooter&&(h.footer=a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a){i.importThisFile(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(c),d()},[b.dataChange.ROW]);a.importer.$scope.$on("$destroy",d)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){var c=a.srcElement||a.target;if(c&&c.files&&1===c.files.length){var d=c.files[0];b.importThisFile(i,d),c.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.grid.api.core.on.scrollEvent(a,function(b){if(b.y){var d=100-100*b.y.percentage;c.checkScroll(a.grid,d)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout","$log","ScrollEvent","uiGridConstants",function(a,b,c,d,e){var f={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){var e=a.columns;if(!angular.isNumber(c)||!angular.isNumber(d))return void console.log("Please provide valid values for originalPosition and finalPosition");for(var f=0,g=0;g<e.length;g++)(angular.isDefined(e[g].colDef.visible)&&e[g].colDef.visible===!1||e[g].isRowHeader===!0)&&f++;if(c>=e.length-f||d>=e.length-f)return void console.log("Invalid values for originalPosition, finalPosition");var h=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};b.redrawColumnAtPosition(a,h(c),h(d))}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var f=a.columns,g=f[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)f[h]=f[h-1];else if(d>c)for(var i=c;d>i;i++)f[i]=f[i+1];f[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d),a.api.core.notifyDataChange(e.dataChange.COLUMN)})}}};return f}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,h,i){a.col.colDef.enableColumnMoving&&a.$on(f.events.COLUMN_HEADER_CLICK,function(f,h){if(h.columnName===a.col.colDef.name&&!a.col.renderContainer){var j=h.event;if("ui-grid-icon-angle-down"!==j.target.className&&"I"!==j.target.tagName&&j.target.className.indexOf("ui-grid-filter-input")<0){var k,l,m=a.grid.element[0].getBoundingClientRect().left,n=j.pageX,o=0,p=m+a.grid.getViewportWidth(),q=!1,r=function(){q=!0,k=e.clone(),e.parent().append(k),k.addClass("movingColumn");var b={},c=e[0].getBoundingClientRect().left;b.left=c-m+"px";var d=a.grid.element[0].getBoundingClientRect().right,f=e[0].getBoundingClientRect().right;f>d&&(l=a.col.drawnWidth+(d-f),b.width=l+"px"),k.css(b)},s=function(c){i.fireEvent("hide-menu");for(var d=a.grid.columns,e=0,f=0;f<d.length;f++)(angular.isUndefined(d[f].colDef.visible)||d[f].colDef.visible===!0)&&(e+=d[f].drawnWidth||d[f].width||d[f].colDef.width);var h,j=k[0].getBoundingClientRect().left-1,n=k[0].getBoundingClientRect().right;if(h="ie"===b.detectBrowser()?j+c:j-m+c,h=p>h?h:p,(j>=m||c>0)&&(p>=n||0>c))k.css({visibility:"visible",left:h+"px"});else if(e>Math.ceil(i.grid.gridWidth)){c*=8;var q=new g(a.col.grid,null,null,"uiGridHeaderCell.moveElement");q.x={pixels:c},q.fireScrollingEvent()}for(var r=0,s=0;s<d.length;s++)if(angular.isUndefined(d[s].colDef.visible)||d[s].colDef.visible===!0){if(d[s].colDef.name===a.col.colDef.name)break;r+=d[s].drawnWidth||d[s].width||d[s].colDef.width}void 0===a.newScrollLeft?o+=c:o=a.newScrollLeft+h-r,l<a.col.drawnWidth&&(l+=Math.abs(c),k.css({width:l+"px"}))},t=function(a){document.onselectstart=function(){return!1};var b=a.pageX-n;!q&&Math.abs(b)>50?r():q&&(s(b),n=a.pageX)};d.on("mousemove",t);var u=function(){document.onselectstart=null,k&&k.remove();for(var b=a.grid.columns,e=0,f=0;f<b.length&&b[f].colDef.name!==a.col.colDef.name;f++)e++;if(0>o){for(var g=0,h=e-1;h>=0;h--)if((angular.isUndefined(b[h].colDef.visible)||b[h].colDef.visible===!0)&&(g+=b[h].drawnWidth||b[h].width||b[h].colDef.width,g>Math.abs(o))){c.redrawColumnAtPosition(a.grid,e,h+1);break}g<Math.abs(o)&&c.redrawColumnAtPosition(a.grid,e,0)}else if(o>0){for(var i=0,j=e+1;j<b.length;j++)if((angular.isUndefined(b[j].colDef.visible)||b[j].colDef.visible===!0)&&(i+=b[j].drawnWidth||b[j].width||b[j].colDef.width,i>o)){c.redrawColumnAtPosition(a.grid,e,j-1);break}o>i&&c.redrawColumnAtPosition(a.grid,e,b.length-1)}d.off("mousemove",t),d.off("mouseup",u)};d.on("mouseup",u)}}})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ng","ui.grid"]);a.service("uiGridPaginationService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{pagination:{paginationChanged:function(){}}},methods:{pagination:{getPage:function(){return a.options.enablePagination?a.options.paginationCurrentPage:null},getTotalPages:function(){return a.options.enablePagination?0===a.options.totalItems?1:Math.ceil(a.options.totalItems/a.options.paginationPageSize):null},nextPage:function(){a.options.enablePagination&&(a.options.totalItems>0?a.options.paginationCurrentPage=Math.min(a.options.paginationCurrentPage+1,c.methods.pagination.getTotalPages()):a.options.paginationCurrentPage++)},previousPage:function(){a.options.enablePagination&&(a.options.paginationCurrentPage=Math.max(a.options.paginationCurrentPage-1,1))},seek:function(b){if(a.options.enablePagination){if(!angular.isNumber(b)||1>b)throw"Invalid page number: "+b;a.options.paginationCurrentPage=Math.min(b,c.methods.pagination.getTotalPages())}}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPagination||!a.options.enablePagination)return b;var c=parseInt(a.options.paginationPageSize,10),d=parseInt(a.options.paginationCurrentPage,10),e=b.filter(function(a){return a.visible});a.options.totalItems=e.length;var f=(d-1)*c;return f>e.length&&(d=a.options.paginationCurrentPage=1,f=(d-1)*c),e.slice(f,f+c)})},defaultGridOptions:function(b){b.enablePagination=b.enablePagination!==!1,b.enablePaginationControls=b.enablePaginationControls!==!1,b.useExternalPagination=b.useExternalPagination===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.paginationPageSizes)&&(b.paginationPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.paginationPageSize)&&(b.paginationPageSize=b.paginationPageSizes.length>0?b.paginationPageSizes[0]:0),a.isNullOrUndefined(b.paginationCurrentPage)&&(b.paginationCurrentPage=1),a.isNullOrUndefined(b.paginationTemplate)&&(b.paginationTemplate="ui-grid/pagination")},onPaginationChanged:function(a,b,c){a.api.pagination.raise.paginationChanged(b,c),a.options.useExternalPagination||a.refresh()}};return b}]),a.directive("uiGridPagination",["gridUtil","uiGridPaginationService",function(a,b){return{priority:-200,scope:!1,require:"uiGrid",link:{pre:function(c,d,e,f){b.initializeGrid(f.grid),a.getTemplate(f.grid.options.paginationTemplate).then(function(a){var b=angular.element(a);d.append(b),f.innerCompile(b)})}}}}]),a.directive("uiGridPager",["uiGridPaginationService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.paginationApi=h.grid.api.pagination,e.sizesLabel=d.getSafeText("pagination.sizes"),e.totalItemsLabel=d.getSafeText("pagination.totalItems");var i=h.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a});var j=h.grid.registerDataChangeCallback(function(a){a.options.useExternalPagination||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);e.$on("$destroy",j);var k=function(){e.showingLow=(i.paginationCurrentPage-1)*i.paginationPageSize+1,e.showingHigh=Math.min(i.paginationCurrentPage*i.paginationPageSize,i.totalItems)},l=e.$watch("grid.options.totalItems + grid.options.paginationPageSize",k),m=e.$watch("grid.options.paginationCurrentPage + grid.options.paginationPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.paginationCurrentPage)||i.paginationCurrentPage<1)return void(i.paginationCurrentPage=1);if(i.totalItems>0&&i.paginationCurrentPage>e.paginationApi.getTotalPages())return void(i.paginationCurrentPage=e.paginationApi.getTotalPages());
    +k(),a.onPaginationChanged(e.grid,i.paginationCurrentPage,i.paginationPageSize)}});e.$on("$destroy",function(){l(),m()}),e.cantPageForward=function(){return i.totalItems>0?i.paginationCurrentPage>=e.paginationApi.getTotalPages():i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.paginationCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})},findTargetCol:function(a,b,c){var d=a.getRenderContainer();if("left"===b){var e=d.visibleColumnCache.indexOf(a);return d.visibleColumnCache[e-1*c]}return a}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q","uiGridResizeColumnsService","uiGridConstants","$timeout",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,d,h,i){var j=i.grid;if(j.options.enableColumnResizing){var k=b.get("ui-grid/columnResizer"),l=1;j.isRTL()&&(a.position="left",l=-1);var m=function(){for(var b=d[0].getElementsByClassName("ui-grid-column-resizer"),f=0;f<b.length;f++)angular.element(b[f]).remove();var g=e.findTargetCol(a.col,"left",l),h=a.col.getRenderContainer();if(g&&0!==h.visibleColumnCache.indexOf(a.col)&&g.colDef.enableColumnResizing!==!1){var i=angular.element(k).clone();i.attr("position","left"),d.prepend(i),c(i)(a)}if(a.col.colDef.enableColumnResizing!==!1){var j=angular.element(k).clone();j.attr("position","right"),d.append(j),c(j)(a)}};m();var n=function(){g(m)},o=j.registerDataChangeCallback(n,[f.dataChange.COLUMN]);a.$on("$destroy",o)}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","uiGridResizeColumnsService",function(a,b,c,d){var e,f,g,h=angular.element('<div class="ui-grid-resize-overlay"></div>');b.isTouchEnabled()?(e="touchstart",f="touchend",g="touchmove"):(e="mousedown",f="mouseup",g="mousemove");var i={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(i,j,k,l){function m(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function n(){l.grid.buildColumns().then(function(){l.grid.refreshCanvas(!0).then(function(){l.grid.refresh()})})}function o(a,b){var c=b;return a.colDef.minWidth&&c<a.colDef.minWidth?c=a.colDef.minWidth:a.colDef.maxWidth&&c>a.colDef.maxWidth&&(c=a.colDef.maxWidth),c}function p(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),s=(a.targetTouches?a.targetTouches[0]:a).clientX-t,0>s?s=0:s>l.grid.gridWidth&&(s=l.grid.gridWidth);var b=d.findTargetCol(i.col,i.position,u);if(b.colDef.enableColumnResizing!==!1){l.grid.element.hasClass("column-resizing")||l.grid.element.addClass("column-resizing");var e=s-r,f=parseInt(b.drawnWidth+e*u,10);s+=(o(b,f)-f)*u,h.css({left:s+"px"}),l.fireEvent(c.events.ITEM_DRAGGING)}}function q(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),l.grid.element.removeClass("column-resizing"),h.remove(),s=(b.changedTouches?b.changedTouches[0]:b).clientX-t;var c=s-r;if(0===c)return a.off(f,q),void a.off(g,p);var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var j=parseInt(e.drawnWidth+c*u,10);e.width=o(e,j),m(e),n(c),d.fireColumnSizeChanged(l.grid,e.colDef,c),a.off(f,q),a.off(g,p)}}var r=0,s=0,t=0,u=1;l.grid.isRTL()&&(i.position="left",u=-1),"left"===i.position?j.addClass("left"):"right"===i.position&&j.addClass("right"),j.on(e,function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),t=l.grid.element[0].getBoundingClientRect().left,r=(b.targetTouches?b.targetTouches[0]:b).clientX-t,l.grid.element.append(h),h.css({left:r}),a.on(f,q),a.on(g,p)}),j.on("dblclick",function(a){a.stopPropagation();var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var f=0,g=0,h=b.closestElm(j,".ui-grid-render-container"),k=h.querySelectorAll("."+c.COL_CLASS_PREFIX+e.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(k,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var h=b.elementWidth(c);e+=h}e>f&&(f=e,g=f-e)})}),e.width=o(e,f),m(e),n(g),d.fireColumnSizeChanged(l.grid,e.colDef,g)}}),j.on("$destroy",function(){j.off(e),j.off("dblclick"),a.off(g,p),a.off(f,q)})}};return i}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,c){f.setSavePromise(b,a,c)},getDirtyRows:function(){return b.rowEdit.dirtyRows?b.rowEdit.dirtyRows:[]},getErrorRows:function(){return b.rowEdit.errorRows?b.rowEdit.errorRows:[]},flushDirtyRows:function(){return f.flushDirtyRows(b)},setRowsDirty:function(a){f.setRowsDirty(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.saveState",["ui.grid","ui.grid.selection","ui.grid.cellNav"]);a.constant("uiGridSaveStateConstants",{featureName:"saveState"}),a.service("uiGridSaveStateService",["$q","uiGridSaveStateConstants","gridUtil","$compile","$interval","uiGridConstants",function(){var a={initializeGrid:function(b){b.saveState={},this.defaultGridOptions(b.options);var c={events:{saveState:{}},methods:{saveState:{save:function(){return a.save(b)},restore:function(c,d){a.restore(b,c,d)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.saveWidths=a.saveWidths!==!1,a.saveOrder=a.saveOrder!==!1,a.saveScroll=a.saveScroll===!0,a.saveFocus=a.saveScroll!==!0&&a.saveFocus!==!1,a.saveVisible=a.saveVisible!==!1,a.saveSort=a.saveSort!==!1,a.saveFilter=a.saveFilter!==!1,a.saveSelection=a.saveSelection!==!1},save:function(b){var c={};return c.columns=a.saveColumns(b),c.scrollFocus=a.saveScrollFocus(b),c.selection=a.saveSelection(b),c},restore:function(b,c,d){d.columns&&a.restoreColumns(b,d.columns),d.scrollFocus&&a.restoreScrollFocus(b,c,d.scrollFocus),d.selection&&a.restoreSelection(b,d.selection),b.refresh()},saveColumns:function(a){var b=[];return angular.forEach(a.columns,function(a){var c={};c.name=a.name,c.visible=a.visible,c.width=a.width,c.sort=angular.copy(a.sort),c.filters=angular.copy(a.filters),b.push(c)}),b},saveScrollFocus:function(b){if(!b.api.cellNav)return{};var c={};if(b.options.saveFocus){c.focus=!0;var d=b.api.cellNav.getFocusedCell();null!==d&&(c.colName=d.col.colDef.name,c.rowVal=a.getRowVal(b,d.row))}else b.options.saveScroll&&(c.focus=!1,b.renderContainers.body.prevRowScrollIndex&&(c.rowVal=a.getRowVal(b,b.renderContainers.body.visibleRowCache[b.renderContainers.body.prevRowScrollIndex])),b.renderContainers.body.prevColScrollIndex&&(c.colName=b.renderContainers.body.visibleColumnCache[b.renderContainers.body.prevColScrollIndex].name));return c},saveSelection:function(b){if(!b.api.selection)return{};var c=b.api.selection.getSelectedGridRows().map(function(c){return a.getRowVal(b,c)});return c},getRowVal:function(a,b){if(!b)return null;var c={};return a.options.saveRowIdentity?(c.identity=!0,c.row=a.options.saveRowIdentity(b.entity)):(c.identity=!1,c.row=a.renderContainers.body.visibleRowCache.indexOf(b)),c},restoreColumns:function(a,b){angular.forEach(b,function(b,c){var d=a.columns.filter(function(a){return a.name===b.name});if(d.length>0){var e=a.columns.indexOf(d[0]);if(a.columns[e].visible=b.visible,a.columns[e].colDef.visible=b.visible,a.columns[e].width=b.width,a.columns[e].sort=angular.copy(b.sort),a.columns[e].filters=angular.copy(b.filters),e!==c){var f=a.columns.splice(e,1)[0];a.columns.splice(c,0,f)}}})},restoreScrollFocus:function(b,c,d){if(b.api.cellNav){var e,f;if(d.colName){var g=b.options.columnDefs.filter(function(a){return a.name===d.colName});g.length>0&&(e=g[0])}d.rowVal&&d.rowVal.row&&(f=d.rowVal.identity?a.findRowByIdentity(b,d.rowVal):b.renderContainers.body.visibleRowCache[d.rowVal.row]);var h=f&&f.entity?f.entity:null;(e||h)&&(d.focus?b.api.cellNav.scrollToFocus(c,h,e):b.api.cellNav.scrollTo(c,h,e))}},restoreSelection:function(b,c){b.api.selection&&(b.api.selection.clearSelectedRows(),angular.forEach(c,function(c){if(c.identity){var d=a.findRowByIdentity(b,c);d&&b.api.selection.selectRow(d.entity)}else b.api.selection.selectRowByVisibleIndex(c.row)}))},findRowByIdentity:function(a,b){if(!a.options.saveRowIdentity)return null;var c=a.rows.filter(function(c){return a.options.saveRowIdentity(c.entity)===b.row?!0:!1});return c.length>0?c[0]:null}};return a}]),a.directive("uiGridSaveState",["uiGridSaveStateConstants","uiGridSaveStateService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),angular.module("ui.grid").config(["$provide",function(a){a.decorator("GridRow",["$delegate",function(a){return a.prototype.setSelected=function(a){this.isSelected=a,a?this.grid.selection.selectedCount++:this.grid.selection.selectedCount--},a}])}]),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,b.selection.selectedCount=0,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c,d){var e=b.getRow(c);null!==e&&e.enableSelection!==!1&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c,d){var e=b.getRow(c);null===e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c,d){var e=b.renderContainers.body.visibleRowCache[c];null===e||"undefined"==typeof e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c,d){var e=b.getRow(c);null!==e&&e.isSelected&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},selectAllVisibleRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.visible?e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c)):e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},clearSelectedRows:function(c){a.clearSelectedRows(b,c)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30,a.enableFooterTotalSelected=a.enableFooterTotalSelected!==!1,a.isRowSelectable=angular.isDefined(a.isRowSelectable)?a.isRowSelectable:angular.noop},toggleRowSelection:function(b,c,d,e,f){var g=c.isSelected;if(e||g){if(!e&&g){var h=a.getSelectedRows(b);h.length>1&&(g=!1,a.clearSelectedRows(b,d))}}else a.clearSelectedRows(b,d);g&&f||c.enableSelection!==!1&&(c.setSelected(!g),c.isSelected===!0?b.selection.lastSelectedRow=c:b.selection.selectAll=!1,b.api.selection.raise.rowSelectionChanged(c,d))},shiftSelect:function(b,c,d,e){if(e){var f=a.getSelectedRows(b),g=f.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,h=b.renderContainers.body.visibleRowCache.indexOf(c);if(g>h){var i=g;g=h,h=i}for(var j=[],k=g;h>=k;k++){var l=b.renderContainers.body.visibleRowCache[k];l&&(l.isSelected||l.enableSelection===!1||(l.setSelected(!0),b.selection.lastSelectedRow=l,a.decideRaiseSelectionEvent(b,l,j,d)))}a.decideRaiseSelectionBatchEvent(b,j,d)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b,c){var d=[];a.getSelectedRows(b).forEach(function(e){e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!1},decideRaiseSelectionEvent:function(a,b,c,d){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b,d)},decideRaiseSelectionBatchEvent:function(a,b,c){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b,c)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,minWidth:10,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1,exporterSuppressExport:!0};f.grid.addRowHeaderColumn(g)}f.grid.options.isRowSelectable!==angular.noop&&f.grid.registerRowBuilder(function(a){a.enableSelection=f.grid.options.isRowSelectable(a)})},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,c,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,c,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,c,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(a,d){c.selection.selectAll?(b.clearSelectedRows(c,d),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0,d),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(d),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,c){function d(){a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(c.addClass("ui-grid-disable-selection"),c.on("touchstart",j),c.on("touchend",k),c.on("click",i),a.registered=!0)}function e(){a.registered&&(c.removeClass("ui-grid-disable-selection"),c.off("touchstart",j),c.off("touchend",k),c.off("click",i),a.registered=!1)}var g=0,h=300,i=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,b,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()},j=function(){g=(new Date).getTime()},k=function(a){var b=(new Date).getTime(),c=b-g;h>c&&i(a)};d();var l=a.grid.registerDataChangeCallback(function(){!a.grid.options.enableRowSelection||a.grid.options.enableRowHeaderSelection||a.registered?a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection||!a.registered||e():d()},[b.dataChange.OPTIONS]);c.on("$destroy",l)}}}]),a.directive("uiGridGridFooter",["$compile","uiGridConstants","gridUtil",function(a,b,c){return{restrict:"EA",replace:!0,priority:-1e3,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(b,d,e,f){f.grid.options.showGridFooter&&c.getTemplate("ui-grid/gridFooterSelectedItems").then(function(c){var e=angular.element(c),f=a(e)(b);angular.element(d[0].getElementsByClassName("ui-grid-grid-footer")[0]).append(f)})},post:function(){}}}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel ui-grid-footer-aggregates-row"><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell ui-grid-clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-grid-footer",'<div class="ui-grid-footer-info ui-grid-grid-footer"><span>{{\'search.totalItems\' | t}} {{grid.rows.length}}</span> <span ng-if="grid.renderContainers.body.visibleRowCache.length !== grid.rows.length" class="ngLabel">({{"search.showingItems" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell ui-grid-clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    /*\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n    */\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div><div ui-grid-grid-footer ng-if="grid.options.showGridFooter"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showColumnFooter"></div><!-- native scrolling --><!--<div ui-grid-native-scrollbar ng-if="enableVerticalScrollbar" type="vertical"></div>--><!--<div ui-grid-native-scrollbar ng-if="enableHorizontalScrollbar" type="horizontal"></div>--></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport" ng-style="containerCtrl.colContainer.getViewPortStyle()"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="INPUT_TYPE" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth()) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/expandableTopRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !grid.expandable.expandedAll, \'ui-grid-icon-minus-squared\' : grid.expandable.expandedAll }" ng-click="grid.api.expandable.toggleAllRows()"></i></div></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT" download="FILE_NAME">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/pagination",'<div class="ui-grid-pager-panel" ui-grid-pager ng-show="grid.options.enablePaginationControls"><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="paginationApi.seek(1)" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="paginationApi.previousPage()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.paginationCurrentPage" min="1" max="{{ paginationApi.getTotalPages() }}" required> <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span> <button type="button" ng-click="paginationApi.nextPage()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="paginationApi.seek(paginationApi.getTotalPages())" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/gridFooterSelectedItems",'<span ng-if="grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected">({{"search.selectedItems" | t}} {{grid.selection.selectedCount}})</span>'),a.put("ui-grid/selectionHeaderCell",'<div><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.svg b/release/3.0.0-RC.18-7774d30/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-RC.18-7774d30/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.ttf b/release/3.0.0-RC.18-7774d30/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-RC.18-7774d30/ui-grid.ttf differ
    diff --git a/release/3.0.0-RC.18-7774d30/ui-grid.woff b/release/3.0.0-RC.18-7774d30/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-RC.18-7774d30/ui-grid.woff differ
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.css b/release/3.0.0-RC.18-8fe4e49/ui-grid.css
    new file mode 100644
    index 000000000..27ad4f997
    --- /dev/null
    +++ b/release/3.0.0-RC.18-8fe4e49/ui-grid.css
    @@ -0,0 +1,1313 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-8fe4e49 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top: 1px;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  overflow-y: scroll;
    +  max-height: 300px;
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child {
    +  border-left: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.eot b/release/3.0.0-RC.18-8fe4e49/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-RC.18-8fe4e49/ui-grid.eot differ
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.js b/release/3.0.0-RC.18-8fe4e49/ui-grid.js
    new file mode 100644
    index 000000000..6f131c9d5
    --- /dev/null
    +++ b/release/3.0.0-RC.18-8fe4e49/ui-grid.js
    @@ -0,0 +1,19666 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-8fe4e49 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart', // For any item being dragged
    +      COLUMN_HEADER_CLICK: 'uiGridColumnHeaderClick'
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      PG_UP: 33,
    +      PG_DOWN: 34,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column',
    +      OPTIONS: 'options'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1
    +      //WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var initColClass = $scope.col.getColClass(false);
    +          $elm.addClass(initColClass);
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          // watch the col and row to see if they change - which would indicate that we've scrolled or sorted or otherwise
    +          // changed the row/col that this cell relates to, and we need to re-evaluate cell classes and maybe other things
    +          var cellChangeFunction = function( n, o ){
    +            if ( n !== o ) {
    +              if ( classAdded || $scope.col.cellClass ){
    +                updateClass();
    +              }
    +
    +              // See if the column's internal class has changed
    +              var newColClass = $scope.col.getColClass(false);
    +              if (newColClass !== initColClass) {
    +                $elm.removeClass(initColClass);
    +                $elm.addClass(newColClass);
    +                initColClass = newColClass;
    +              }
    +            }
    +          };
    +
    +          // TODO(c0bra): Turn this into a deep array watch
    +          var colWatchDereg = $scope.$watch( 'col', cellChangeFunction );
    +          var rowWatchDereg = $scope.$watch( 'row', cellChangeFunction );
    +          
    +          
    +          var deregisterFunction = function() {
    +            dataChangeDereg();
    +            colWatchDereg();
    +            rowWatchDereg(); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +          $elm.on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +        $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            var footerTemplate = ($scope.grid.options.gridFooterTemplate) ? $scope.grid.options.gridFooterTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 'ScrollEvent',
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, ScrollEvent) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            var initColClass = $scope.col.getColClass(false);
    +            $elm.addClass(initColClass);
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +              
    +              var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
    +              $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
    +            };
    +
    +            $scope.$watch('col', function (n, o) {
    +              if (n !== o) {
    +                // See if the column's internal class has changed
    +                var newColClass = $scope.col.getColClass(false);
    +                if (newColClass !== initColClass) {
    +                  $elm.removeClass(initColClass);
    +                  $elm.addClass(newColClass);
    +                  initColClass = newColClass;
    +                }
    +              }
    +            });
    +  
    +            updateClass();
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(event) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (event.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ($scope.sortable || $scope.colMenu) {
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +
    +              var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
    +              $contentsElm.on(downEvent, function(event) {
    +                event.stopPropagation();
    +
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +
    +                uiGridCtrl.fireEvent(uiGridConstants.events.COLUMN_HEADER_CLICK, {event: event, columnName: $scope.col.colDef.name});
    +              });
    +        
    +              var upEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'mouseup';
    +              $contentsElm.on(upEvent, function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });
    +            }
    +
    +
    +            $scope.toggleMenu = function(event) {
    +              event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
    +              $contentsElm.on(clickEvent, function(event) {
    +                event.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(event);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh()
    +                      .then(function () {
    +                        if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                          var scrollEvent = new ScrollEvent(uiGridCtrl.grid,null,null,'uiGridHeaderCell.toggleMenu');
    +                          scrollEvent.y.percentage = uiGridCtrl.prevScrollArgs.y.percentage;
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +                      });
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              //if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +              //  availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              //}
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              //if (grid.verticalScrollbarWidth) {
    +              //  canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              //}
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', 'uiGridConstants', function( gridUtil, i18nService, uiGridConstants ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +      gridCol.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      if (uiGridCtrl) {
    +       $scope.$on('$destroy', uiGridCtrl.grid.api.core.on.scrollEvent($scope, applyHideMenu ));
    +      }
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil', 'ScrollEvent',
    +    function($timeout, $document, uiGridConstants, gridUtil, ScrollEvent) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              grid.api.core.on.scrollEvent($scope,scrollHandler);
    +            }
    +
    +            function scrollHandler (args) {
    +              // exit if not for this grid
    +              if (args.grid && args.grid.id !== grid.id){
    +                return;
    +              }
    +
    +              
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var newScrollTop = args.getNewScrollTop(rowContainer,containerCtrl.viewport);
    +
    +                //only set scrollTop if we coming from something other than viewPort scrollBar or
    +                //another column container
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll ||
    +                    args.sourceColContainer !== colContainer) {
    +                  containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                }
    +
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +                var newScrollLeft = args.getNewScrollLeft(colContainer,containerCtrl.viewport);
    +
    +                // Make the current horizontal scroll position available in the $scope
    +                $scope.newScrollLeft = newScrollLeft;                
    +
    +                if (containerCtrl.headerViewport) {
    +                  containerCtrl.headerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  containerCtrl.footerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                //scroll came from somewhere else, so the viewport must be positioned
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll) {
    +                  containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                }
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +
    +              var newEvent = gridUtil.normalizeWheelEvent(evt);
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerMouseWheel);
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / rowContainer.getVerticalScrollLength();
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = gridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +
    +              // todo: this isn't working when scrolling down.  it works fine for up.  tested on Chrome
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +                if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1 && containerCtrl.viewport[0].scrollTop !== 0 ) ||
    +                    (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +                  evt.preventDefault();
    +              }
    +
    +              scrollEvent.fireThrottledScrollingEvent();
    +            });
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / rowContainer.getVerticalScrollLength();
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              scrollEvent.fireScrollingEvent();
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              //function decelerate() {
    +              //  $timeout(function() {
    +              //    var args = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +              //
    +              //    if (scrollYLength !== 0) {
    +              //      var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / rowContainer.getVerticalScrollLength();
    +              //
    +              //      args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +              //    }
    +              //
    +              //    if (scrollXLength !== 0) {
    +              //      var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              //      args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +              //    }
    +              //
    +              //    uiGridCtrl.fireScrollingEvent(args);
    +              //
    +              //    decelerateCount = decelerateCount -1;
    +              //    scrollYLength = scrollYLength / 2;
    +              //    scrollXLength = scrollXLength / 2;
    +              //
    +              //    if (decelerateCount > 0) {
    +              //      decelerate();
    +              //    }
    +              //    else {
    +              //      uiGridCtrl.scrollbars.forEach(function (sbar) {
    +              //        sbar.removeClass('ui-grid-scrollbar-visible');
    +              //        sbar.removeClass('ui-grid-scrolling');
    +              //      });
    +              //    }
    +              //  }, decelerateInterval);
    +              //}
    +
    +              // decelerate();
    +            }
    +
    +            if (gridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +
    +              //add additional height for scrollbar on left and right container
    +              if ($scope.containerId !== 'body') {
    +                canvasHeight += grid.scrollbarHeight;
    +              }
    +
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + (canvasWidth + grid.scrollbarWidth) + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + grid.scrollbarWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          //gridUtil.logDebug('margin-top ' + hiddenRowWidth );
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            // Function for attaching the template to this scope
    +            var clonedElement, cloneScope;
    +            function compileTemplate() {
    +              $scope.row.getRowTemplateFn.then(function (compiledElementFn) {
    +                // var compiledElementFn = $scope.row.compiledElementFn;
    +
    +                // Create a new scope for the contents of this row, so we can destroy it later if need be
    +                var newScope = $scope.$new();
    +
    +                compiledElementFn(newScope, function (newElm, scope) {
    +                  // If we already have a cloned element, we need to remove it and destroy its scope
    +                  if (clonedElement) {
    +                    clonedElement.remove();
    +                    cloneScope.$destroy();
    +                  }
    +
    +                  // Empty the row and append the new element
    +                  $elm.empty().append(newElm);
    +
    +                  // Save the new cloned element and scope
    +                  clonedElement = newElm;
    +                  cloneScope = newScope;
    +                });
    +              });
    +            }
    +
    +            // Initially attach the compiled template to this scope
    +            compileTemplate();
    +
    +            // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
    +            $scope.$watch('row.getRowTemplateFn', function (newFunc, oldFunc) {
    +              if (newFunc !== oldFunc) {
    +                compileTemplate();
    +              }
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent',
    +    function(gridUtil, ScrollEvent) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              grid.flagScrollingHorizontally();
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              if (horizScrollLength !== 0) {
    +                horizScrollPercentage = newScrollLeft / horizScrollLength;
    +              }
    +              else {
    +                horizScrollPercentage = 0;
    +              }
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              grid.flagScrollingVertically();
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +
    +              var vertScrollLength = rowContainer.getVerticalScrollLength();
    +
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
    +              scrollEvent.newScrollLeft = newScrollLeft;
    +              scrollEvent.newScrollTop = newScrollTop;
    +              if ( horizScrollPercentage > -1 ){
    +                scrollEvent.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                scrollEvent.y = { percentage: vertScrollPercentage };
    +              }
    +              scrollEvent.fireScrollingEvent();
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +
    +      //assign $scope.$parent if appScope not already assigned
    +      self.grid.appScope = self.grid.appScope || $scope.$parent;
    +
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns({ orderByColumnDefs: true })
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '='
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.calcFooterHeight();
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.refreshCanvas(true);
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth || col.width || 0;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 || !myWidth ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +
    +    /**
    +     * @ngdoc object
    +     * @name appScope
    +     * @propertyOf ui.grid.class:Grid
    +     * @description reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +     * <br/>
    +     * use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference
    +     */
    +    self.appScope = self.options.appScopeProvider;
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +
    +
    +    self.footerHeight = self.calcFooterHeight();
    +
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +  
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +    }, 300);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +    }, 300);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +
    +    self.scrollbarHeight = 0;
    +    self.scrollbarWidth = 0;
    +    if (self.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarHeight = gridUtil.getScrollbarWidth();
    +    }
    +
    +    if (self.options.enableVerticalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarWidth = gridUtil.getScrollbarWidth();
    +    }
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +
    +    self.registerStyleComputation({
    +      priority: 10,
    +      func: self.getFooterStyles
    +    });
    +  };
    +
    +   Grid.prototype.calcFooterHeight = function () {
    +     if (!this.hasFooter()) {
    +       return 0;
    +     }
    +
    +     var height = 0;
    +     if (this.options.showGridFooter) {
    +       height += this.options.gridFooterHeight;
    +     }
    +
    +     if (this.options.showColumnFooter) {
    +       height += this.options.columnFooterHeight;
    +     }
    +
    +     return height;
    +   };
    +
    +   Grid.prototype.getFooterStyles = function () {
    +     var style = '.grid' + this.id + ' .ui-grid-footer-aggregates-row { height: ' + this.options.columnFooterHeight + 'px; }';
    +     style += ' .grid' + this.id + ' .ui-grid-footer-info { height: ' + this.options.gridFooterHeight + 'px; }';
    +     return style;
    +   };
    +
    +  Grid.prototype.hasFooter = function () {
    +   return this.options.showGridFooter || this.options.showColumnFooter;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * - when the options watch fires, the OPTIONS callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * - OPTIONS calls OPTIONS and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +   * ALL 
    +   * @returns {function} deregister function - a function that can be called to deregister this callback
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types, _this) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types, _this:_this };
    +    
    +    var self = this;
    +    var deregisterFunction = function() {
    +      delete self.dataChangeCallbacks[uid];
    +    };
    +    return deregisterFunction;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        if (callback._this) {
    +           callback.callback.apply(callback._this,this);
    +        }
    +        else {
    +          callback.callback( this );
    +        }
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ||
    +         type === constants.OPTIONS ){
    +      this.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.refresh();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @param {object} options  An object contains options to use when building columns
    +   *
    +   * * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
    +   *
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns(opts) {
    +    var options = {
    +      orderByColumnDefs: false
    +    };
    +
    +    angular.extend(options, opts);
    +
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        // tell updateColumnDef that the column was pre-existing
    +        col.updateColumnDef(colDef, false);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    /*** Reorder columns if necessary ***/
    +    if (!!options.orderByColumnDefs) {
    +      // Create a shallow copy of the columns as a cache
    +      var columnCache = self.columns.slice(0);
    +
    +      // We need to allow for the "row headers" when mapping from the column defs array to the columns array
    +      //   If we have a row header in columns[0] and don't account for it   we'll overwrite it with the column in columnDefs[0]
    +
    +      // Go through all the column defs
    +      for (i = 0; i < self.options.columnDefs.length; i++) {
    +        // If the column at this index has a different name than the column at the same index in the column defs...
    +        if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
    +          // Replace the one in the cache with the appropriate column
    +          columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
    +        }
    +        else {
    +          // Otherwise just copy over the one from the initial columns
    +          columnCache[i + headerOffset] = self.columns[i + headerOffset];
    +        }
    +      }
    +
    +      // Empty out the columns array, non-destructively
    +      self.columns.length = 0;
    +
    +      // And splice in the updated, ordered columns from the cache
    +      Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
    +    }
    +
    +    return $q.all(builderPromises).then(function(){
    +      if (self.rows.length > 0){
    +        self.assignTypes();
    +      }
    +    });
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    var self = this;
    +
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      // See if the column name already exists:
    +      var foundName = self.getColumn(colDef.field);
    +
    +      // If a column with this name already  exists, we will add an incrementing number to the end of the new column name
    +      if (foundName) {
    +        // Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
    +        var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
    +
    +        var foundColumns = self.columns.filter(function (column) {
    +          // Test against the displayName, as that's what'll have the incremented number
    +          return nameRE.test(column.displayName);
    +        })
    +        // Sort the found columns by the end-number
    +        .sort(function (a, b) {
    +          if (a === b) {
    +            return 0;
    +          }
    +          else {
    +            var numA = a.match(nameRE)[1];
    +            var numB = b.match(nameRE)[1];
    +
    +            return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
    +          }
    +        });
    +
    +        // Not columns found, so start with number "2"
    +        if (foundColumns.length === 0) {
    +          colDef.name = colDef.field + '2';
    +        }
    +        else {
    +          // Get the number from the final column
    +          var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
    +
    +          // Make sure to parse to an int
    +          lastNum = parseInt(lastNum, 10);
    +
    +          // Add 1 to the number from the last column and tack it on to the field to be the name for this new column 
    +          colDef.name = colDef.field + (lastNum + 1);
    +        }
    +      }
    +      // ... otherwise just use the field as the column name
    +      else {
    +        colDef.name = colDef.field;
    +      }
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +//        if (wasEmpty) {
    +           self.assignTypes();
    +//        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.canvasHeightShouldUpdate = true;
    +      
    +      if ( typeof(container.visibleRowCache) === 'undefined' ){
    +        container.visibleRowCache = [];  
    +      } else {
    +        container.visibleRowCache.length = 0;  
    +      }
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +    self.api.core.raise.rowsRendered(this.api);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name updateCanvasHeight
    +   * @methodOf ui.grid.class:Grid
    +   * @description flags all render containers to update their canvas height
    +   */
    +  Grid.prototype.updateCanvasHeight = function updateCanvasHeight() {
    +    var self = this;
    +
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +        container.canvasHeightShouldUpdate = true;
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    //}
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    //gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    //gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    //}
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol && !col.colDef.suppressRemoveSort) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(null, container.prevScrolltopPercentage);
    +      container.adjustColumns(null, container.prevScrollleftPercentage);
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasLeftContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if leftContainer has columns
    +     */
    +    Grid.prototype.hasLeftContainerColumns = function () {
    +      return this.hasLeftContainer() && this.renderContainers.left.renderedColumns.length > 0;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasRightContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if rightContainer has columns
    +     */
    +    Grid.prototype.hasRightContainerColumns = function () {
    +      return this.hasRightContainer() && this.renderContainers.right.renderedColumns.length > 0;
    +    };
    +
    +
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name rowsRendered
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the cache of visible rows is changed.
    +           */
    +          this.registerEvent( 'core', 'rowsRendered' );
    +
    +
    +          /**
    +           * @ngdoc event
    +           * @name scrollEvent
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised on a scroll Event.  Called frequently so be careful what you do with it
    +           */
    +          this.registerEvent( 'core', 'scrollEvent' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name canvasHeightChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised when the canvas height has changed
    +           * <br/>
    +           * arguments: oldHeight, newHeight
    +           */
    +          this.registerEvent( 'core', 'canvasHeightChanged');
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.eventId, l.handler, self.grid, l._this);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * <br>
    +         * .raise.eventName() - takes no arguments
    +         * <br/>
    +         * <br/>
    +         * .on.eventName(scope, callBackFn, _this)
    +         * <br/>
    +         * scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +         * <br/>
    +         * callBackFn - The function to call
    +         * <br/>
    +         * _this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +         * <br/>
    +         * .on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +         * will be removed when the scope is destroyed.
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$emit.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler, _this) {
    +            var deregAngularOn = registerEventWithAngular(eventId, handler, self.grid, _this);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: deregAngularOn, eventId: eventId, scope: scope, _this:_this};
    +            self.listeners.push(listener);
    +
    +            var removeListener = function(){
    +              listener.dereg();
    +              var index = self.listeners.indexOf(listener);
    +              self.listeners.splice(index,1);
    +            };
    +
    +            //destroy tracking when scope is destroyed
    +            scope.$on('$destroy', function() {
    +              removeListener();
    +            });
    +
    +            return removeListener;
    +          };
    +        };
    +
    +        function registerEventWithAngular(eventId, handler, grid, _this) {
    +          return $rootScope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(_this ? _this : grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} _this binds callBackFn 'this' to _this.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, _this) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(_this || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} _this binds this to _this for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, _this) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, _this);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef, true);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         term: 'aa',
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...',
    +   *         flags: { caseSensitive: false }
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...',
    +   *     flags: { caseSensitive: false }
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {boolean} isNew whether the column is being newly created, if not
    +   * we're updating an existing column, and some items such as the sort shouldn't
    +   * be copied down
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef, isNew) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it, but only if this is a newly added column
    +    if ( isNew ){
    +      self.setPropertyOrDefault(colDef, 'sort');
    +    }
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * 
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * - flags: only flag currently available is `caseSensitive`, set to false if you don't want
    +     * case sensitive matching
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       term: 'xx',
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...',
    +     *       flags: { caseSensitive: false }
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    // Only set filter if this is a newly added column, if we're updating an existing
    +    // column then we don't want to put the default filter back if the user may have already
    +    // removed it.
    +    if ( isNew ) {
    +      self.setPropertyOrDefault(colDef, 'filter');
    +      self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +    }
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>
    +   * app.config(function($provide){
    +   *   $provide.decorator('GridOptions',function($delegate){
    +   *     var gridOptions;
    +   *     gridOptions = angular.copy($delegate);
    +   *     gridOptions.initialize = function(options) {
    +   *       var initOptions;
    +   *       initOptions = $delegate.initialize(options);
    +   *       initOptions.enableColumnMenus = false;
    +   *       return initOptions;
    +   *     };
    +   *     return gridOptions;
    +   *   });
    +   * });
    +   * </pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      /**
    +       * @ngdoc function
    +       * @name onRegisterApi
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description A callback that returns the gridApi once the grid is instantiated, which is 
    +       * then used to interact with the grid programatically.
    +       * 
    +       * Note that the gridApi.core.renderingComplete event is identical to this 
    +       * callback, but has the advantage that it can be called from multiple places
    +       * if needed
    +       * 
    +       * @example
    +       * <pre>
    +       *   $scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +       *     $scope.gridApi = gridApi;
    +       *     $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +       *   };
    +       * </pre>
    +       * 
    +       */
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showGridFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       * The footer display Total Rows and Visible Rows (filtered rows)
    +       */
    +      baseOptions.showGridFooter = baseOptions.showGridFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name showColumnFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the column footer, defaults to false
    +       * The column footer displays column aggregates
    +       */
    +      baseOptions.showColumnFooter = baseOptions.showColumnFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name columnFooterHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer rows (column footer and grid footer) in pixels
    +       *
    +       */
    +      baseOptions.columnFooterHeight = typeof(baseOptions.columnFooterHeight) !== "undefined" ? baseOptions.columnFooterHeight : 30;
    +      baseOptions.gridFooterHeight = typeof(baseOptions.gridFooterHeight) !== "undefined" ? baseOptions.gridFooterHeight : 30;
    +
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +
    +      /**
    +       * @ngdoc object
    +       * @name appScopeProvider
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +       * this property allows you to assign any reference you want to grid.appScope
    +       */
    +      baseOptions.appScopeProvider = baseOptions.appScopeProvider || null;
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeightShouldUpdate
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description flag to signal that container should recalculate the canvas size
    +     */
    +    self.canvasHeightShouldUpdate = true;
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeight
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description last calculated canvas height value
    +     */
    +    self.$$canvasHeight = 0;
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCanvasHeight
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false
    +   * @returns {number} total height of all the visible rows in the container
    +   */
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    if (!self.canvasHeightShouldUpdate) {
    +      return self.$$canvasHeight;
    +    }
    +
    +    var oldCanvasHeight = self.$$canvasHeight;
    +
    +    self.$$canvasHeight =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      self.$$canvasHeight += row.height;
    +    });
    +
    +
    +    self.canvasHeightShouldUpdate = false;
    +
    +    self.grid.api.core.raise.canvasHeightChanged(oldCanvasHeight, self.$$canvasHeight);
    +
    +    return self.$$canvasHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() {
    +    return this.getCanvasHeight() - this.getViewportHeight();
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    //if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +    //  ret = ret - self.verticalScrollbarWidth;
    +    //}
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getVerticalScrollLength();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
    +        // Have we hit the threshold going down?
    +        if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +        //Have we hit the threshold going up?
    +        if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      /* Commented the following lines because otherwise the moved column wasn't visible immediately on the new position
    +       * in the case of many columns with horizontal scroll, one had to scroll left or right and then return in order to see it
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }*/
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    //if (self.grid.verticalScrollbarWidth) {
    +    //  canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  GridRenderContainer.prototype.getViewPortStyle = function () {
    +    var self = this;
    +    var styles = {};
    +
    +    if (self.name === 'body') {
    +      styles['overflow-x'] = self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +      if (!self.grid.isRTL()) {
    +        if (self.grid.hasRightContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +      else {
    +        if (self.grid.hasLeftContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +    }
    +    else if (self.name === 'left') {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +    else {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = !self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +
    +    return styles;
    +
    +
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +
    +    this.$$height = grid.options.rowHeight;
    +
    +  }
    +
    +    /**
    +     *  @ngdoc object
    +     *  @name height
    +     *  @propertyOf  ui.grid.class:GridRow
    +     *  @description height of each individual row. changing the height will flag all
    +     *  row renderContainers to recalculate their canvas height
    +     */
    +    Object.defineProperty(GridRow.prototype, 'height', {
    +      get: function() {
    +        return this.$$height;
    +      },
    +      set: function(height) {
    +        if (height !== this.$$height) {
    +          this.grid.updateCanvasHeight();
    +          this.$$height = height;
    +        }
    +      }
    +    });
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +    GridRow.prototype.getQualifiedColField = function(col) {
    +      return 'row.' + this.getEntityQualifiedColField(col);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  angular.module('ui.grid')
    +    .factory('ScrollEvent', ['gridUtil', function (gridUtil) {
    +
    +      /**
    +       * @ngdoc function
    +       * @name ui.grid.class:ScrollEvent
    +       * @description Model for all scrollEvents
    +       * @param {Grid} grid that owns the scroll event
    +       * @param {GridRenderContainer} sourceRowContainer that owns the scroll event. Can be null
    +       * @param {GridRenderContainer} sourceColContainer that owns the scroll event. Can be null
    +       * @param {string} source the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName
    +       */
    +      function ScrollEvent(grid, sourceRowContainer, sourceColContainer, source) {
    +        var self = this;
    +        if (!grid) {
    +          throw new Error("grid argument is required");
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name grid
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description A reference back to the grid
    +         */
    +         self.grid = grid;
    +
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name entity
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description the source of the scroll event. limited to values from uiGridConstants.scrollEventSources
    +         */
    +        self.source = source;
    +
    +        self.sourceRowContainer = sourceRowContainer;
    +        self.sourceColContainer = sourceColContainer;
    +
    +        self.newScrollLeft = null;
    +        self.newScrollTop = null;
    +        self.x = null;
    +        self.y = null;
    +
    +
    +        /**
    +         *  @ngdoc function
    +         *  @name fireThrottledScrollingEvent
    +         *  @methodOf  ui.grid.class:ScrollEvent
    +         *  @description fires a throttled event using grid.api.core.raise.scrollEvent
    +         */
    +        self.fireThrottledScrollingEvent = gridUtil.throttle(function() {
    +          self.grid.api.core.raise.scrollEvent(self);
    +        }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      }
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name fireScrollingEvent
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description fires an event using grid.api.core.raise.scrollEvent
    +       */
    +      ScrollEvent.prototype.fireScrollingEvent = function() {
    +        this.grid.api.core.raise.scrollEvent(this);
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollLeft
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollLeft property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollLeft = function(colContainer, viewport){
    +        var self = this;
    +
    +        if (!self.newScrollLeft){
    +          var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +          var oldScrollLeft = gridUtil.normalizeScrollLeft(viewport);
    +
    +          var scrollXPercentage;
    +          if (typeof(self.x.percentage) !== 'undefined' && self.x.percentage !== undefined) {
    +            scrollXPercentage = self.x.percentage;
    +          }
    +          else if (typeof(self.x.pixels) !== 'undefined' && self.x.pixels !== undefined) {
    +            scrollXPercentage = self.x.percentage = (oldScrollLeft + self.x.pixels) / scrollWidth;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event X axis");
    +          }
    +
    +          return Math.max(0, scrollXPercentage * scrollWidth);
    +        }
    +
    +        return self.newScrollLeft;
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollTop
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollTop property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollTop = function(rowContainer, viewport){
    +        var self = this;
    +
    +
    +        if (!self.newScrollTop){
    +          var scrollLength = rowContainer.getVerticalScrollLength();
    +
    +          var oldScrollTop = viewport[0].scrollTop;
    +
    +          var scrollYPercentage;
    +          if (typeof(self.y.percentage) !== 'undefined' && self.y.percentage !== undefined) {
    +            scrollYPercentage = self.y.percentage;
    +          }
    +          else if (typeof(self.y.pixels) !== 'undefined' && self.y.pixels !== undefined) {
    +            scrollYPercentage = self.y.percentage = (oldScrollTop + self.y.pixels) / scrollLength;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +          }
    +
    +          return Math.max(0, scrollYPercentage * scrollLength);
    +        }
    +
    +        return self.newScrollTop;
    +      };
    +
    +
    +      ScrollEvent.Sources = {
    +        ViewPortScroll: 'ViewPortScroll',
    +        RenderContainerMouseWheel: 'RenderContainerMouseWheel',
    +        RenderContainerTouchMove: 'RenderContainerTouchMove',
    +        Other: 99
    +      };
    +
    +      return ScrollEvent;
    +    }]);
    +
    +
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Row builder for custom row templates
    +          grid.registerRowBuilder(service.rowTemplateAssigner);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        },
    +
    +        rowTemplateAssigner: function rowTemplateAssigner(row) {
    +          var grid = this;
    +
    +          // Row has no template assigned to it
    +          if (!row.rowTemplate) {
    +            // Use the default row template from the grid
    +            row.rowTemplate = grid.options.rowTemplate;
    +
    +            // Use the grid's function for fetching the compiled row template function
    +            row.getRowTemplateFn = grid.getRowTemplateFn;
    +          }
    +          // Row has its own template assigned
    +          else {
    +            // Create a promise for the compiled row template function
    +            var perRowTemplateFnPromise = $q.defer();
    +            row.getRowTemplateFn = perRowTemplateFnPromise.promise;
    +
    +            // Get the row template
    +            gridUtil.getTemplate(row.rowTemplate)
    +              .then(function (template) {
    +                // Compile the template
    +                var rowTemplateFn = $compile(template);
    +                
    +                // Resolve the compiled template function promise
    +                perRowTemplateFnPromise.resolve(rowTemplateFn);
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
    +              });
    +          }
    +
    +          return row.getRowTemplateFn;
    +        }
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setupFilters
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +   * do all the parsing and pre-processing and store that data into a new filters object.  The object
    +   * has the condition, the flags, the stripped term, and a parsed reg exp if there was one.
    +   * 
    +   * We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +   * for loops everywhere else in this module...
    +   * 
    +   * @param {array} filters the filters from the column (col.filters or [col.filter])
    +   * @returns {array} An array of parsed/preprocessed filters
    +   */
    +  rowSearcher.setupFilters = function setupFilters( filters ){
    +    var newFilters = [];
    +    
    +    var filtersLength = filters.length;
    +    for ( var i = 0; i < filtersLength; i++ ){
    +      var filter = filters[i];
    +      if ( filter.noTerm || filter.term ){
    +        var newFilter = {};
    +        
    +        var regexpFlags = '';
    +        if (!filter.flags || !filter.flags.caseSensitive) {
    +          regexpFlags += 'i';
    +        }
    +    
    +        if ( filter.term ){
    +          // it is possible to have noTerm.  We don't need to copy that across, it was just a flag to avoid
    +          // getting the filter ignored if the filter was a function that didn't use a term
    +          newFilter.term = rowSearcher.stripTerm(filter);
    +        }
    +        
    +        if ( filter.condition ){
    +          newFilter.condition = filter.condition;
    +        } else {
    +          newFilter.condition = rowSearcher.guessCondition(filter);
    +        }
    +
    +        newFilter.flags = angular.extend( { caseSensitive: false }, filter.flags );
    +
    +        if (newFilter.condition === uiGridConstants.filter.STARTS_WITH) {
    +          newFilter.startswithRE = new RegExp('^' + newFilter.term, regexpFlags);
    +        }
    +        
    +         if (newFilter.condition === uiGridConstants.filter.ENDS_WITH) {
    +          newFilter.endswithRE = new RegExp(newFilter.term + '$', regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.CONTAINS) {
    +          newFilter.containsRE = new RegExp(newFilter.term, regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.EXACT) {
    +          newFilter.exactRE = new RegExp('^' + newFilter.term + '$', regexpFlags);
    +        }
    +        
    +        newFilters.push(newFilter);
    +      }
    +    }
    +    return newFilters;
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name runColumnFilter
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Runs a single pre-parsed filter against a cell, returning true
    +   * if the cell matches that one filter.
    +   * 
    +   * @param {Grid} grid the grid we're working against
    +   * @param {GridRow} row the row we're matching against
    +   * @param {GridCol} column the column that we're working against
    +   * @param {object} filter the specific, preparsed, filter that we want to test
    +   * @returns {boolean} true if we match (row stays visible)
    +   */
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Term to search for.
    +    var term = filter.term;
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +    
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      return filter.condition.test(value);
    +    }
    +
    +    // If the filter's condition is a function, run it
    +    if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    
    +    if (filter.startswithRE) {
    +      return filter.startswithRE.test(value);
    +    }
    +    
    +    if (filter.endswithRE) {
    +      return filter.endswithRE.test(value);
    +    }
    +    
    +    if (filter.containsRE) {
    +      return filter.containsRE.test(value);
    +    }
    +    
    +    if (filter.exactRE) {
    +      return filter.exactRE.test(value);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      var regex = new RegExp('^' + term + '$');
    +      return !regex.exec(value);
    +    }
    +
    +    if (typeof(value) === 'number'){
    +      // if the term has a decimal in it, it comes through as '9\.4', we need to take out the \
    +      var tempFloat = parseFloat(term.replace(/\\./,'.'));
    +      if (!isNaN(tempFloat)) {
    +        term = tempFloat;
    +      }
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      return (value > term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      return (value >= term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      return (value < term);
    +    }
    +    
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      return (value <= term);
    +    }
    +    
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process provided filters on provided column against a given row. If the row meets 
    +   * the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @param {array} filters array of pre-parsed/preprocessed filters to apply
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, filters) {
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    var filtersLength = filters.length;
    +    for (var i = 0; i < filtersLength; i++) {
    +      var filter = filters[i];
    +      
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across the given rows and columns, marking any rows that don't 
    +   * match the stored col.filters or col.filter as invisible.
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    /*
    +     * Added performance optimisations into this code base, as this logic creates deeply nested
    +     * loops and is therefore very performance sensitive.  In particular, avoiding forEach as
    +     * this impacts some browser optimisers (particularly Chrome), using iterators instead
    +     */
    +    
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Build list of filters to apply
    +    var filterData = [];
    +
    +    var colsLength = columns.length;
    +    for (var i = 0; i < colsLength; i++) {
    +      var col = columns[i];
    +      
    +      if (typeof(col.filters) !== 'undefined' && ( col.filters.length > 1 || col.filters.length === 1 && col.filters[0].term ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters(col.filters) } );
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters([col.filter]) } );
    +      }
    +    }
    +    
    +    if (filterData.length > 0) {
    +      // define functions outside the loop, performance optimisation
    +      var foreachRow = function(grid, row, col, filters){
    +        if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, filters)) {
    +          row.visible = false;
    +        }
    +      };
    +      
    +      var foreachFilterCol = function(grid, filterData){
    +        var rowsLength = rows.length;
    +        for ( var i = 0; i < rowsLength; i++){
    +          foreachRow(grid, rows[i], filterData.col, filterData.filters);  
    +        }
    +      };
    +
    +      // nested loop itself - foreachFilterCol, which in turn calls foreachRow
    +      var filterDataLength = filterData.length;
    +      for ( var j = 0; j < filterDataLength; j++){
    +        foreachFilterCol( grid, filterData[j] );  
    +      }
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toString().toLowerCase(),
    +          strB = b.toString().toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +    
    +    // put a custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( rows, function ( row, idx ) {
    +      row.entity.$uiGridIndex = idx;
    +    });
    +
    +    // Now actually sort the data
    +    var newRows = rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Chrome doesn't implement a stable sort function.  If our sort returns 0 
    +      // (i.e. the items are equal), then return the previous order using our custom
    +      // index variable
    +      if (tem === 0 ) {
    +        return rowA.entity.$uiGridIndex - rowB.entity.$uiGridIndex;
    +      }
    +      
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +    
    +    // remove the custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( newRows, function ( row, idx ) {
    +      delete row.entity.$uiGridIndex;
    +    });
    +    
    +    return newRows;
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        pagination: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'всего строк: ',
    +          sum: 'итого: ',
    +          avg: 'среднее: ',
    +          min: 'мин: ',
    +          max: 'макс: '
    +        },
    +        gridMenu: {
    +          columns: 'Столбцы:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Экспортировать всё в CSV',
    +          exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
    +          exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
    +          exporterAllAsPdf: 'Экспортировать всё в PDF',
    +          exporterVisibleAsPdf: 'Экспортировать видимые данные в PDF',
    +          exporterSelectedAsPdf: 'Экспортировать выбранные данные в PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        pagination: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3, PG_UP: 4, PG_DOWN: 5},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +        this.bodyContainer = rowContainer;
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.api:GridRow
    +       *
    +       *  @description GridRow settings for cellNav feature, these are available to be
    +       *  set only internally (for example, by other features)
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name allowCellFocus
    +       *  @propertyOf  ui.grid.cellNav.api:GridRow
    +       *  @description Enable focus on a cell within this row.  If set to false then no cells
    +       *  in this row can be focused - group header rows as an example would set this to false.
    +       *  <br/>Defaults to true
    +       */
    +      /** returns focusable rows */
    +      UiGridCellNav.prototype.getFocusableRows = function () {
    +        return this.rows.filter(function(row) {
    +          return row.allowCellFocus !== false;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_UP:
    +            return this.getRowColPageUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_DOWN:
    +            return this.getRowColPageDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(focusableRows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === focusableRows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(focusableRows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === focusableRows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(focusableRows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex >= focusableRows.length - pageSize) {
    +          return new RowCol(focusableRows[focusableRows.length - 1], focusableCols[curColIndex]); //return last row
    +        }
    +        else {
    +          //down one page
    +          return new RowCol(focusableRows[curRowIndex + pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(focusableRows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex - pageSize < 0) {
    +          return new RowCol(focusableRows[0], focusableCols[curColIndex]); //return first row
    +        }
    +        else {
    +          //up one page
    +          return new RowCol(focusableRows[curRowIndex - pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory', 'ScrollEvent',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav, ScrollEvent) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +          grid.cellNav.focusedCells = [];
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function ($scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view, and sets focus
    +                 * to that cell
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus
    +                 * @param {object} colDef to make visible and set focus
    +                 */
    +                scrollToFocus: function ($scope, rowEntity, colDef) {
    +                  service.scrollToFocus(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column fully into view if it isn't already
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {GridRow} row grid row that we should make fully visible
    +                 * @param {GridCol} col grid col to make fully visible
    +                 */
    +                scrollToIfNecessary: function ($scope, row, col) {
    +                  service.scrollToIfNecessary(grid, $scope, row, col);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getCurrentSelection
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns an array containing the current selection
    +                 * <br> array is empty if no selection has occurred
    +                 */
    +                getCurrentSelection: function () {
    +                  return grid.cellNav.focusedCells;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name rowColSelectIndex
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +                 * isn't selected
    +                 * @param {object} rowCol the rowCol to evaluate
    +                 */
    +                rowColSelectIndex: function (rowCol) {
    +                  //return gridUtil.arrayContainsObjectWithProperty(grid.cellNav.focusedCells, 'col.uid', rowCol.col.uid) &&
    +                  var index = -1;
    +                  for (var i = 0; i < grid.cellNav.focusedCells.length; i++) {
    +                    if (grid.cellNav.focusedCells[i].col.uid === rowCol.col.uid &&
    +                      grid.cellNav.focusedCells[i].row.uid === rowCol.row.uid) {
    +                      index = i;
    +                      break;
    +                    }
    +                  }
    +                  return index;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:GridOptions
    +           *
    +           *  @description GridOptions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelectCells
    +           *  @propertyOf  ui.grid.cellNav.api:GridOptions
    +           *  @description Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelectCells = gridOptions.modifierKeysToMultiSelectCells === true;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_UP){
    +            return uiGridCellNavConstants.direction.PG_UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_DOWN){
    +            return uiGridCellNavConstants.direction.PG_DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell within this column.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null && typeof(rowEntity) !== 'undefined' ) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null && typeof(colDef) !== 'undefined' ) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToFocus
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view, and set focus to the cell in that row and column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus to
    +         * @param {object} colDef to make visible and set focus to
    +         */
    +        scrollToFocus: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +
    +          var rowCol = { row: gridRow, col: gridCol };
    +
    +          // Broadcast the navigation
    +          grid.cellNav.broadcastCellNav(rowCol);
    +
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         *
    +         * To get to row 9 (i.e. the last row) in the same list, we want to
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll,
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToInternal');
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            scrollEvent.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            scrollEvent.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, $scope, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToIfNecessary');
    +
    +          // Alias the visible row and column caches
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          //if (grid.horizontalScrollbarHeight) {
    +          //  bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          //}
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + grid.gridWidth;
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          //if (grid.verticalScrollbarWidth) {
    +          //  rightBound = rightBound - grid.verticalScrollbarWidth;
    +          //}
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            //if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +            //  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            //}
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;
    +            }
    +          });
    +
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var _scope = $scope;
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = grid.cellNav.broadcastCellNav = function (newRowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol, modifierDown);
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol, modifierDown);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +
    +                var row = rowCol.row,
    +                  col = rowCol.col;
    +
    +                var rowColSelectIndex = uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol);
    +
    +                if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                  if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
    +                    grid.cellNav.focusedCells.push(rowCol);
    +                  } else {
    +                    grid.cellNav.focusedCells = [rowCol];
    +                  }
    +                } else if (grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                  rowColSelectIndex >= 0) {
    +
    +                  grid.cellNav.focusedCells.splice(rowColSelectIndex, 1);
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, $scope, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                 renderContainerCtrl = controllers[1];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              var needFocus = false;
    +              
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              grid.api.core.on.scrollEvent($scope, function (args) {
    +                // Skip if not this grid that the event was broadcast for
    +                if (args.grid && args.grid.id !== uiGridCtrl.grid.id) {
    +                  return;
    +                }
    +
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +                
    +                /*
    +                 * If we have scrolled due to cellNav, we want to set the focus to the new cell after the 
    +                 * virtualisation has run, and after scroll.  If we scrolled through the browser scroll
    +                 * bar or other user action, we're going to discard the focus, because it will no longer 
    +                 * be valid (and, noting #2423, trying to keep it causes problems)
    +                 * 
    +                 * If cellNav triggers the scroll, we get a scrollToIfNecessary, then a viewport scroll. We
    +                 * want to wait for the viewport scroll to finish, then do a refocus.  
    +                 * 
    +                 * If someone manually scrolls we get just the viewport scroll, no scrollToIfNecessary.  We
    +                 * want to just clear the focus
    +                 * 
    +                 * Logic is:
    +                 *  - if cellNav scroll, set a flag that will be resolved in the native scroll
    +                 *  - if native scroll, look for the cellNav promise and resolve it
    +                 *    - if not present, then use a timeout to clear focus
    +                 *    - if it is present, then instead use a timeout to set focus
    +                 */ 
    +                
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                if ( args.source === 'uiGridCellNavService.scrollToIfNecessary'){
    +                  needFocus = true;
    +/*
    +                  focusTimeout = $timeout(function () {
    +                    if ( clearFocusTimeout ){
    +                      $timeout.cancel(clearFocusTimeout);
    +                    }
    +                    focusTimeout = $timeout(function () {
    +                      if ( clearFocusTimeout ){
    +                        $timeout.cancel(clearFocusTimeout);
    +                      }
    +                      // Get the last row+col combo
    +                      var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +  
    +                      // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                      //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                      //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                      if ($document.activeElement === $document.body) {
    +                        $elm[0].focus();
    +                      }
    +  
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                    });
    +                  });
    +                  */
    +                } else {
    +                  if ( needFocus ){
    +                    $timeout(function () {
    +                      $timeout(function () {
    +                        // Get the last row+col combo
    +                        var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +    
    +                        // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                        //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                        //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                        if ($document.activeElement === $document.body) {
    +                          $elm[0].focus();
    +                        }
    +    
    +                        // broadcast a cellNav event so we clear the focus on all cells
    +                        uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                        
    +                        needFocus = false;
    +                      });
    +                    });
    +                  } else {
    +                    $timeout(function() {
    +                      // make a dummy roCol
    +                      var rowCol = { col: { uid: null }, row: { uid: null } };
    +    
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +                    });
    +                  }
    +                }
    +              });  
    +             
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +
    +            evt.stopPropagation();
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol, modifierDown) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol) === -1) {
    +                clearFocus();
    +              } else {
    +                setFocused();
    +              }
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else if (!(uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown)) {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.api:GridRow
    +   *
    +   *  @description GridRow options for edit feature, these are available to be
    +   *  set internally only, by other features
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableCellEdit
    +   *  @propertyOf  ui.grid.edit.api:GridRow
    +   *  @description enable editing on row, grouping for example might disable editing on group header rows
    +   */
    +
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        var touchstartTimeout = 500;
    +
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit || $scope.row.enableCellEdit === false) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +            var cancelTouchstartTimeout;
    +
    +            var editCellScope;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +
    +              // Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
    +              $elm.on('touchstart', touchStart);
    +            }
    +
    +            function touchStart(event) {
    +              // jQuery masks events
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +
    +              // Bind touchend handler
    +              $elm.on('touchend', touchEnd);
    +
    +              // Start a timeout
    +              cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
    +
    +              // Timeout's done! Start the edit
    +              cancelTouchstartTimeout.then(function () {
    +                // Use setTimeout to start the edit because beginEdit expects to be outside of $digest
    +                setTimeout(beginEdit, 0);
    +
    +                // Undbind the touchend handler, we don't need it anymore
    +                $elm.off('touchend', touchEnd);
    +              });
    +            }
    +
    +            // Cancel any touchstart timeout
    +            function touchEnd(event) {
    +              $timeout.cancel(cancelTouchstartTimeout);
    +              $elm.off('touchend', touchEnd);
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +              $elm.off('touchstart', touchStart);
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving &&
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownRowEntityOptionsArrayPath
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description a path to a property on row.entity containing an
    +             *  array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which will be used to populate
    +             *  the edit dropdown.  This can be used when the dropdown values are dependent on
    +             *  the backing row entity.
    +             *  If this property is set then editDropdownOptionsArray will be ignored.
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              // if the cell isn't fully visible, and cellNav is present, scroll it to be fully visible before we start
    +              if ( $scope.grid.api.cellNav ){
    +                $scope.grid.api.cellNav.scrollToIfNecessary( $scope, $scope.row, $scope.col );
    +              }
    +              
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              var inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  inputType = 'number';
    +                  break;
    +                case 'date':
    +                  inputType = 'date';
    +                  break;
    +              }
    +              html = html.replace('INPUT_TYPE', inputType);
    +
    +              var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
    +              if (editDropdownRowEntityOptionsArrayPath) {
    +                $scope.editDropdownOptionsArray =  resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
    +              }
    +              else {
    +                $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              }
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                editCellScope = $scope.$new();
    +                $compile(cellElement)(editCellScope);
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.col.grid.api.core.on.scrollEvent($scope, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +                deregOnGridScroll();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              editCellScope.$destroy();
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +            // resolves a string path against the given object
    +            // shamelessly borrowed from
    +            // http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
    +            function resolveObjectFromPath(object, path) {
    +              path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    +              path = path.replace(/^\./, '');           // strip a leading dot
    +              var a = path.split('.');
    +              while (a.length) {
    +                  var n = a.shift();
    +                  if (n in object) {
    +                      object = object[n];
    +                  } else {
    +                      return;
    +                  }
    +              }
    +              return object;
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
    +      function (gridUtil, uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +               $scope.deepEdit = false;
    +
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('uiGridEditor', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        priority: -100, // run after default uiGridEditor directive
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.expandable.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        grid.expandable = {};
    +        grid.expandable.expandedAll = false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name 
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Width in pixels of the expandable column. Defaults to 40
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeaderWidth: 40
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name toggleAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.toggleAllRows();
    +               * </pre>
    +               */              
    +              toggleAllRows: function() {
    +                service.toggleAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +          grid.expandable.expandedAll = false;
    +        }
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = true;
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = false;
    +        grid.refresh();
    +      },
    +
    +      toggleAllRows: function(grid) {
    +        if (grid.expandable.expandedAll) {
    +          service.collapseAllRows(grid);
    +        }
    +        else {
    +          service.expandAllRows(grid);
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {
    +                  name: 'expandableButtons', 
    +                  displayName: '', 
    +                  exporterSuppressExport: true, 
    +                  enableColumnResizing: false, 
    +                  enableColumnMenu: false,
    +                  width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
    +                };
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGrid
    +   *  @description stacks on the uiGrid directive to register child grid with parent row when child is created
    +   */
    +  module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 1000,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
    +                //if a parent grid row is on the scope, then add the parentRow property to this childGrid
    +                if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
    +
    +                  /**
    +                   *  @ngdoc directive
    +                   *  @name ui.grid.expandable.class:Grid
    +                   *  @description Additional Grid properties added by expandable module
    +                   */
    +
    +                  /**
    +                   *  @ngdoc object
    +                   *  @name parentRow
    +                   *  @propertyOf ui.grid.expandable.class:Grid
    +                   *  @description reference to the expanded parent row that owns this grid
    +                   */
    +                  uiGridCtrl.grid.parentRow = $scope.row;
    +
    +                  //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
    +                 // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
    +                 //   uiGridCtrl.grid.parentRow = newHeight;
    +                 // });
    +                }
    +
    +              });
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridExpandableRow
    +   *  @description directive to render the expandable row template
    +   */
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridRow
    +   *  @description stacks on the uiGridRow directive to add support for expandable rows
    +   */
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridViewport
    +   *  @description stacks on the uiGridViewport directive to append the expandable row html elements to the
    +   *  default gridRow template
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    BUTTON_LABEL: 'BUTTON_LABEL',
    +    FILE_NAME: 'FILE_NAME'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                csvExport: function (rowTypes, colTypes) {
    +                  service.csvExport(grid, rowTypes, colTypes);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for exporter feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:ColumnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvFilename
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default filename to use when saving the downloaded csv.  
    +           * This will only work in some browsers.
    +           * <br/>Defaults to 'download.csv'
    +           */
    +          gridOptions.exporterCsvFilename = gridOptions.exporterCsvFilename ? gridOptions.exporterCsvFilename : 'download.csv';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilterUseName
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Defaults to false, which leads to `displayName` being passed into the headerFilter.
    +           * If set to true, then will pass `name` instead.
    +           * 
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilterUseName = true;
    +           * </pre>
    +           */
    +          gridOptions.exporterHeaderFilterUseName = gridOptions.exporterHeaderFilterUseName === true;          
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * 
    +           * Behaviour can be changed to pass in `name` instead of `displayName` through use of `exporterHeaderFilterUseName: true`.
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +          
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        csvExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          this.downloadFile (grid.options.exporterCsvFilename, csvContent);
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterSuppressExport
    +         * @description Suppresses export for this column.  Used by selection and expandable.
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.colDef.exporterSuppressExport !== true &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? ( grid.options.exporterHeaderFilterUseName ? grid.options.exporterHeaderFilter(gridCol.name) : grid.options.exporterHeaderFilter(gridCol.displayName) ) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.exporter.api:GridRow
    +         * @description GridRow settings for exporter
    +         */
    +        /**
    +         * @ngdoc object
    +         * @name exporterEnableExporting
    +         * @propertyOf  ui.grid.exporter.api:GridRow
    +         * @description If set to false, then don't export this row, notwithstanding visible or 
    +         * other settings
    +         * <br/>Defaults to true
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate.  Any rows marked
    +         * `exporterEnableExporting: false` will not be exported
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            if (row.exporterEnableExporting !== false) {
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.colDef.exporterSuppressExport !== true &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                  if ( gridCol.colDef.exporterPdfAlign ) {
    +                    extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                  }
    +                  extractedRow.push(extractedField);
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            }
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name downloadFile
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Triggers download of a csv file.  Logic provided
    +         * by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391
    +         * @param {string} fileName the filename we'd like our file to be
    +         * given
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * download as a file
    +         */
    +        downloadFile: function (fileName, csvContent) {
    +          var D = document;
    +          var a = D.createElement('a');
    +          var strMimeType = 'application/octet-stream;charset=utf-8';
    +          var rawFile;
    +      
    +          // IE10+
    +          if (navigator.msSaveBlob) {
    +            return navigator.msSaveBlob(new Blob(["\ufeff", csvContent], {
    +              type: strMimeType
    +            }), fileName);
    +          }
    +      
    +          //html5 A[download]
    +          if ('download' in a) {
    +            var blob = new Blob([csvContent], {
    +              type: strMimeType
    +            });
    +            rawFile = URL.createObjectURL(blob);
    +            a.setAttribute('download', fileName);
    +          } else {
    +            rawFile = 'data:' + strMimeType + ',' + encodeURIComponent(csvContent);
    +            a.setAttribute('target', '_blank');
    +          }
    +      
    +          a.href = rawFile;
    +          a.setAttribute('style', 'display:none;');
    +          D.body.appendChild(a);
    +          setTimeout(function() {
    +            if (a.click) {
    +              a.click();
    +              // Workaround for Safari 5
    +            } else if (document.createEvent) {
    +              var eventObj = document.createEvent('MouseEvents');
    +              eventObj.initEvent('click', true, true);
    +              a.dispatchEvent(eventObj);
    +            }
    +            D.body.removeChild(a);
    +    
    +          }, 100);
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.header = grid.options.exporterPdfHeader;
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.footer = grid.options.exporterPdfFooter;
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( fileObject ) {
    +                  service.importThisFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and if the rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var dataChangeDereg = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( newObjects );
    +              dataChangeDereg();
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            grid.importer.$scope.$on( '$destroy', dataChangeDereg );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            var target = event.srcElement || event.target;
    +            
    +            if (target && target.files && target.files.length === 1) {
    +              var fileObject = target.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              target.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.grid.api.core.on.scrollEvent($scope, function (args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', 'ScrollEvent', 'uiGridConstants', function ($q, $timeout, $log, ScrollEvent, uiGridConstants) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                var columns = grid.columns;
    +                if (!angular.isNumber(originalPosition) || !angular.isNumber(finalPosition)) {
    +                  console.log('Please provide valid values for originalPosition and finalPosition');
    +                  return;
    +                }
    +                var nonMovableColumns = 0;
    +                for (var i = 0; i < columns.length; i++) {
    +                  if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +                    nonMovableColumns++;
    +                  }
    +                }
    +                if (originalPosition >= (columns.length - nonMovableColumns) || finalPosition >= (columns.length - nonMovableColumns)) {
    +                  console.log('Invalid values for originalPosition, finalPosition');
    +                  return;
    +                }
    +                var findPositionForRenderIndex = function (index) {
    +                  var position = index;
    +                  for (var i = 0; i <= position; i++) {
    +                    if (angular.isDefined(columns[i]) && ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true)) {
    +                      position++;
    +                    }
    +                  }
    +                  return position;
    +                };
    +                self.redrawColumnAtPosition(grid, findPositionForRenderIndex(originalPosition), findPositionForRenderIndex(finalPosition));
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +
    +        var columns = grid.columns;
    +
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +            grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log', 'uiGridConstants', 'ScrollEvent',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log, uiGridConstants, ScrollEvent) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                $scope.$on(uiGridConstants.events.COLUMN_HEADER_CLICK, function (event, args) {
    +
    +                  if (args.columnName === $scope.col.colDef.name && !$scope.col.renderContainer) {
    +
    +                    var evt = args.event;
    +                    if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                      //Setting some variables required for calculations.
    +                      var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                      var previousMouseX = evt.pageX;
    +                      var totalMouseMovement = 0;
    +                      var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth();// - $scope.grid.verticalScrollbarWidth;
    +
    +                      //Clone element should move horizontally with mouse.
    +                      var elmCloned = false;
    +                      var movingElm;
    +                      var reducedWidth;
    +
    +                      var cloneElement = function () {
    +                        elmCloned = true;
    +
    +                        //Cloning header cell and appending to current header cell.
    +                        movingElm = $elm.clone();
    +                        $elm.parent().append(movingElm);
    +
    +                        //Left of cloned element should be aligned to original header cell.
    +                        movingElm.addClass('movingColumn');
    +                        var movingElementStyles = {};
    +                        var elmLeft = $elm[0].getBoundingClientRect().left;
    +                        movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                        var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                        var elmRight = $elm[0].getBoundingClientRect().right;
    +                        if (elmRight > gridRight) {
    +                          reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                          movingElementStyles.width = reducedWidth + 'px';
    +                        }
    +                        movingElm.css(movingElementStyles);
    +                      };
    +
    +                      var moveElement = function (changeValue) {
    +                        //Hide column menu
    +                        uiGridCtrl.fireEvent('hide-menu');
    +
    +                        //Calculate total column width
    +                        var columns = $scope.grid.columns;
    +                        var totalColumnWidth = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) {
    +                            totalColumnWidth += columns[i].drawnWidth || columns[i].width || columns[i].colDef.width;
    +                          }
    +                        }
    +
    +                        //Calculate new position of left of column
    +                        var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                        var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                        var newElementLeft;
    +                        if (gridUtil.detectBrowser() === 'ie') {
    +                          newElementLeft = currentElmLeft + changeValue;
    +                        }
    +                        else {
    +                          newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                        }
    +                        newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                        //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                        if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                          movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                        }
    +                        else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
    +                          changeValue *= 8;
    +                          var scrollEvent = new ScrollEvent($scope.col.grid, null, null, 'uiGridHeaderCell.moveElement');
    +                          scrollEvent.x = {pixels: changeValue};
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +
    +                        //Calculate total width of columns on the left of the moving column and the mouse movement
    +                        var totalColumnsLeftWidth = 0;
    +                        for (var il = 0; il < columns.length; il++) {
    +                          if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                            if (columns[il].colDef.name !== $scope.col.colDef.name) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                            }
    +                            else {
    +                              break;
    +                            }
    +                          }
    +                        }
    +                        if ($scope.newScrollLeft === undefined) {
    +                          totalMouseMovement += changeValue;
    +                        }
    +                        else {
    +                          totalMouseMovement = $scope.newScrollLeft + newElementLeft - totalColumnsLeftWidth;
    +                        }
    +
    +                        //Increase width of moving column, in case the rightmost column was moved and its width was
    +                        //decreased because of overflow
    +                        if (reducedWidth < $scope.col.drawnWidth) {
    +                          reducedWidth += Math.abs(changeValue);
    +                          movingElm.css({'width': reducedWidth + 'px'});
    +                        }
    +                      };
    +
    +                      var mouseMoveHandler = function (evt) {
    +                        //Disable text selection in Chrome during column move
    +                        document.onselectstart = function() { return false; };
    +
    +                        var changeValue = evt.pageX - previousMouseX;
    +                        if (!elmCloned && Math.abs(changeValue) > 50) {
    +                          cloneElement();
    +                        }
    +                        else if (elmCloned) {
    +                          moveElement(changeValue);
    +                          previousMouseX = evt.pageX;
    +                        }
    +                      };
    +
    +                      /*
    +                       //Commenting these lines as they are creating trouble with column moving when grid has huge scroll
    +                       // On scope destroy, remove the mouse event handlers from the document body
    +                       $scope.$on('$destroy', function () {
    +                       $document.off('mousemove', mouseMoveHandler);
    +                       $document.off('mouseup', mouseUpHandler);
    +                       });
    +                       */
    +                      $document.on('mousemove', mouseMoveHandler);
    +
    +                      var mouseUpHandler = function (evt) {
    +                        //Re-enable text selection after column move
    +                        document.onselectstart = null;
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var columns = $scope.grid.columns;
    +                        var columnIndex = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== $scope.col.colDef.name) {
    +                            columnIndex++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = columnIndex - 1; il >= 0; il--) {
    +                            if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                              if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, il + 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, 0);
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = columnIndex + 1; ir < columns.length; ir++) {
    +                            if (angular.isUndefined(columns[ir].colDef.visible) || columns[ir].colDef.visible === true) {
    +                              totalColumnsRightWidth += columns[ir].drawnWidth || columns[ir].width || columns[ir].colDef.width;
    +                              if (totalColumnsRightWidth > totalMouseMovement) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, ir - 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, columns.length - 1);
    +                          }
    +                        }
    +/*
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +*/
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      };
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    }
    +                  }
    +                });
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ng', 'ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', ['gridUtil',
    +    function (gridUtil) {
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name initializeGrid
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @description Attaches the service to a certain grid
    +         * @param {Grid} grid The grid we want to work with
    +         */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.pagination.api:PublicAPI
    +          *
    +          * @description Public API for the pagination feature
    +          */
    +          var publicApi = {
    +            events: {
    +              pagination: {
    +              /**
    +               * @ngdoc event
    +               * @name paginationChanged
    +               * @eventOf ui.grid.pagination.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {int} currentPage requested page number
    +               * @param {int} pageSize requested page size
    +               */
    +                paginationChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              pagination: {
    +                /**
    +                 * @ngdoc method
    +                 * @name getPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the number of the current page
    +                 */
    +                getPage: function () {
    +                  return grid.options.enablePagination ? grid.options.paginationCurrentPage : null;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name getTotalPages
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the total number of pages
    +                 */
    +                getTotalPages: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return null;
    +                  }
    +
    +                  return (grid.options.totalItems === 0) ? 1 : Math.ceil(grid.options.totalItems / grid.options.paginationPageSize);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name nextPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the next page, if possible
    +                 */
    +                nextPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  if (grid.options.totalItems > 0) {
    +                    grid.options.paginationCurrentPage = Math.min(
    +                      grid.options.paginationCurrentPage + 1,
    +                      publicApi.methods.pagination.getTotalPages()
    +                    );
    +                  } else {
    +                    grid.options.paginationCurrentPage++;
    +                  }
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name previousPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the previous page, if we're not on the first page
    +                 */
    +                previousPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.max(grid.options.paginationCurrentPage - 1, 1);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name seek
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the requested page
    +                 * @param {int} page The number of the page that should be displayed
    +                 */
    +                seek: function (page) {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +                  if (!angular.isNumber(page) || page < 1) {
    +                    throw 'Invalid page number: ' + page;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.min(page, publicApi.methods.pagination.getTotalPages());
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPagination || !grid.options.enablePagination) {
    +              return renderableRows;
    +            }
    +            //client side pagination
    +            var pageSize = parseInt(grid.options.paginationPageSize, 10);
    +            var currentPage = parseInt(grid.options.paginationCurrentPage, 10);
    +            
    +            var visibleRows = renderableRows.filter(function (row) { return row.visible; });
    +            grid.options.totalItems = visibleRows.length;
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            if (firstRow > visibleRows.length) {
    +              currentPage = grid.options.paginationCurrentPage = 1;
    +              firstRow = (currentPage - 1) * pageSize;
    +            }
    +            return visibleRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.pagination.api:GridOptions
    +           *
    +           * @description GridOptions for the pagination feature, these are available to be
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @name enablePagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables pagination, defaults to true
    +           */
    +          gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +          /**
    +           * @ngdoc property
    +           * @name enablePaginationControls
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +           *              own controls outside the grid.
    +           */
    +          gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Disables client side pagination. When true, handle the paginationChanged event and set data
    +           *              and totalItems, defaults to `false`
    +           */
    +          gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Total number of items, set automatically when client side pagination, needs set by user
    +           *              for server side pagination
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSizes
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Array of page sizes, defaults to `[250, 500, 1000]`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSizes)) {
    +            gridOptions.paginationPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSize
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSize)) {
    +            if (gridOptions.paginationPageSizes.length > 0) {
    +              gridOptions.paginationPageSize = gridOptions.paginationPageSizes[0];
    +            } else {              
    +              gridOptions.paginationPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationCurrentPage
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Current page number, defaults to 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationCurrentPage)) {
    +            gridOptions.paginationCurrentPage = 1;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name paginationTemplate
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description A custom template for the pager, defaults to `ui-grid/pagination`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationTemplate)) {
    +            gridOptions.paginationTemplate = 'ui-grid/pagination';
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @name uiGridPaginationService
    +         * @description  Raises paginationChanged and calls refresh for client side pagination
    +         * @param {Grid} grid the grid for which the pagination changed
    +         * @param {int} currentPage requested page number
    +         * @param {int} pageSize requested page size
    +         */
    +        onPaginationChanged: function (grid, currentPage, pageSize) {
    +            grid.api.pagination.raise.paginationChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPagination) {
    +              grid.refresh(); //client side pagination
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPagination
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds pagination features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        paginationPageSizes: [5, 10, 25],
    +        paginationPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-pagination></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPagination', ['gridUtil', 'uiGridPaginationService',
    +    function (gridUtil, uiGridPaginationService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        link: {
    +          pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +            uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +
    +            gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                $elm.append(template);
    +                uiGridCtrl.innerCompile(template);
    +              });
    +          }
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling pagination
    +   */
    +  module.directive('uiGridPager', ['uiGridPaginationService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPaginationService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +          $scope.paginationApi = uiGridCtrl.grid.api.pagination;
    +          $scope.sizesLabel = i18nService.getSafeText('pagination.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('pagination.totalItems');
    +          
    +          var options = uiGridCtrl.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          var dataChangeDereg = uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPagination) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +          
    +          $scope.$on('$destroy', dataChangeDereg);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.paginationCurrentPage - 1) * options.paginationPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.paginationCurrentPage * options.paginationPageSize, options.totalItems);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.paginationPageSize', setShowing);
    +
    +          var deregP = $scope.$watch('grid.options.paginationCurrentPage + grid.options.paginationPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.paginationCurrentPage) || options.paginationCurrentPage < 1) {
    +                options.paginationCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.paginationCurrentPage > $scope.paginationApi.getTotalPages()) {
    +                options.paginationCurrentPage = $scope.paginationApi.getTotalPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPaginationService.onPaginationChanged($scope.grid, options.paginationCurrentPage, options.paginationPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.paginationCurrentPage >= $scope.paginationApi.getTotalPages();
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.paginationCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        },
    +        
    +        // get either this column, or the column next to this column, to resize,
    +        // returns the column we're going to resize
    +        findTargetCol: function(col, position, rtlMultiplier){
    +          var renderContainer = col.getRenderContainer();
    +
    +          if (position === 'left') {
    +            // Get the column to the left of this one
    +            var colIndex = renderContainer.visibleColumnCache.indexOf(col);          
    +            return renderContainer.visibleColumnCache[colIndex - 1 * rtlMultiplier];
    +          } else {
    +            return col;
    +          }
    +        }
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', 'uiGridResizeColumnsService', 'uiGridConstants', '$timeout', function (gridUtil, $templateCache, $compile, $q, uiGridResizeColumnsService, uiGridConstants, $timeout) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var grid = uiGridCtrl.grid;
    +
    +            if (grid.options.enableColumnResizing) {
    +              var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +    
    +              var rtlMultiplier = 1;
    +              //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +              if (grid.isRTL()) {
    +                $scope.position = 'left';
    +                rtlMultiplier = -1;
    +              }
    +
    +              var displayResizers = function(){
    +                
    +                // remove any existing resizers.  
    +                var resizers = $elm[0].getElementsByClassName('ui-grid-column-resizer');
    +                for ( var i = 0; i < resizers.length; i++ ){
    +                  angular.element(resizers[i]).remove();
    +                } 
    +                
    +                // get the target column for the left resizer
    +                var otherCol = uiGridResizeColumnsService.findTargetCol($scope.col, 'left', rtlMultiplier);
    +                var renderContainer = $scope.col.getRenderContainer();
    +              
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  var resizerLeft = angular.element(columnResizerElm).clone();
    +                  resizerLeft.attr('position', 'left');
    +
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  var resizerRight = angular.element(columnResizerElm).clone();
    +                  resizerRight.attr('position', 'right');
    +
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              };
    +
    +              displayResizers();
    +              
    +              var waitDisplay = function(){
    +                $timeout(displayResizers);
    +              };
    +              
    +              var dataChangeDereg = grid.registerDataChangeCallback( waitDisplay, [uiGridConstants.dataChange.COLUMN] );
    +              
    +              $scope.$on( '$destroy', dataChangeDereg );
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var downEvent, upEvent, moveEvent;
    +
    +    if (gridUtil.isTouchEnabled()) {
    +      downEvent = 'touchstart';
    +      upEvent = 'touchend';
    +      moveEvent = 'touchmove';
    +    }
    +    else {
    +      downEvent = 'mousedown';
    +      upEvent = 'mouseup';
    +      moveEvent = 'mousemove';
    +    }
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true).then( function() {
    +                uiGridCtrl.grid.refresh();
    +              });
    +            });
    +        }
    +
    +        // Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
    +        // Returns the new recommended with, after constraints applied
    +        function constrainWidth(col, width){
    +          var newWidth = width;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          return newWidth;
    +        }
    +        
    +        
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          x = x + ( constrainWidth(col, newWidth) - newWidth ) * rtlMultiplier;
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +        
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off(upEvent, mouseup);
    +            $document.off(moveEvent, mousemove);
    +            return;
    +          }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, newWidth);
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off(upEvent, mouseup);
    +          $document.off(moveEvent, mousemove);
    +        }
    +
    +
    +        $elm.on(downEvent, function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on(upEvent, mouseup);
    +          $document.on(moveEvent, mousemove);
    +        });
    +
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, maxWidth);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off(downEvent);
    +          $elm.off('dblclick');
    +          $document.off(moveEvent, mousemove);
    +          $document.off(upEvent, mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function ( rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function () {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function () {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function () {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function ( dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty( myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.saveState
    +   * @description
    +   *
    +   *  # ui.grid.saveState
    +   * This module provides the ability to save the grid state, and restore
    +   * it when the user returns to the page.  
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate. Usually the navigate events would be used to save
    +   * the grid state and restore it.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.save-state"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.saveState', ['ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.saveState.constant:uiGridSaveStateConstants
    +   *
    +   *  @description constants available in save state module
    +   */
    +
    +  module.constant('uiGridSaveStateConstants', {
    +    featureName: 'saveState'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.saveState.service:uiGridSaveStateService
    +   *
    +   *  @description Services for saveState feature
    +   */
    +  module.service('uiGridSaveStateService', ['$q', 'uiGridSaveStateConstants', 'gridUtil', '$compile', '$interval', 'uiGridConstants',
    +    function ($q, uiGridSaveStateConstants, gridUtil, $compile, $interval, uiGridConstants ) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.saveState = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.saveState.api:PublicApi
    +           *
    +           *  @description Public Api for saveState feature
    +           */
    +          var publicApi = {
    +            events: {
    +              saveState: {
    +              }
    +            },
    +            methods: {
    +              saveState: {
    +                /**
    +                 * @ngdoc function
    +                 * @name save
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Packages the current state of the grid into 
    +                 * an object, and provides it to the user for saving
    +                 * @returns {object} the state as a javascript object that can be saved
    +                 */
    +                save: function () {
    +                  return service.save(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name restore
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Restores the provided state into the grid
    +                 * @param {scope} $scope a scope that we can broadcast on
    +                 * @param {object} state the state that should be restored into the grid
    +                 */
    +                restore: function ( $scope, state) {
    +                  service.restore(grid, $scope, state);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.saveState.api:GridOptions
    +           *
    +           * @description GridOptions for saveState feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveWidths
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column widths.  Note that unless
    +           * you've provided the user with some way to resize their columns (say
    +           * the resize columns feature), then this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveWidths = gridOptions.saveWidths !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveOrder
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column order.  Note that unless
    +           * you've provided the user with some way to reorder their columns (for
    +           * example the move columns feature), this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveOrder = gridOptions.saveOrder !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveScroll
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current scroll position.  Note that this
    +           * is saved as the percentage of the grid scrolled - so if your
    +           * user returns to a grid with a significantly different number of 
    +           * rows (perhaps some data has been deleted) then the scroll won't 
    +           * actually show the same rows as before.  If you want to scroll to
    +           * a specific row then you should instead use the saveFocus option, which
    +           * is the default.
    +           * 
    +           * Note that this element will only be saved if the cellNav feature is
    +           * enabled
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.saveScroll = gridOptions.saveScroll === true;
    +          /**
    +           * @ngdoc object
    +           * @name saveFocus
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current focused cell.  On returning
    +           * to this focused cell we'll also scroll.  This option is
    +           * preferred to the saveScroll option, so is set to true by
    +           * default.  If saveScroll is set to true then this option will 
    +           * be disabled.  
    +           * 
    +           * By default this option saves the current row number and column 
    +           * number, and returns to that row and column.  However, if you define
    +           * a saveRowIdentity function, then it will return you to the currently 
    +           * selected column within that row (in a business sense - so if some
    +           * rows have been deleted, it will still find the same data, presuming it 
    +           * still exists in the list.  If it isn't in the list then it will instead
    +           * return to the same row number - i.e. scroll percentage)
    +           * 
    +           * Note that this option will do nothing if the cellNav
    +           * feature is not enabled.
    +           * 
    +           * <br/>Defaults to true (unless saveScroll is true)
    +           */
    +          gridOptions.saveFocus = gridOptions.saveScroll !== true && gridOptions.saveFocus !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveRowIdentity
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description A function that can be called, passing in a rowEntity, 
    +           * and that will return a unique id for that row.  This might simply 
    +           * return the `id` field from that row (if you have one), or it might
    +           * concatenate some fields within the row to make a unique value.
    +           * 
    +           * This value will be used to find the same row again and set the focus 
    +           * to it, if it exists when we return.
    +           * 
    +           * <br/>Defaults to undefined
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveVisible
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save whether or not columns are visible.
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveVisible = gridOptions.saveVisible !== false;          
    +          /**
    +           * @ngdoc object
    +           * @name saveSort
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current sort state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSort = gridOptions.saveSort !== false;         
    +          /**
    +           * @ngdoc object
    +           * @name saveFilter
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current filter state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveFilter = gridOptions.saveFilter !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveSelection
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the currently selected rows.  If the `saveRowIdentity` callback
    +           * is defined, then it will save the id of the row and select that.  If not, then
    +           * it will attempt to select the rows by row number, which will give the wrong results
    +           * if the data set has changed in the mean-time.
    +           * 
    +           * Note that this option only does anything
    +           * if the selection feature is enabled.  
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSelection = gridOptions.saveSelection !== false;          
    +        },
    +
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name save
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the current grid state into an object, and
    +         * passes that object back to the caller
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the state ready to be saved
    +         */
    +        save: function (grid) {
    +          var savedState = {};
    +          
    +          savedState.columns = service.saveColumns( grid );
    +          savedState.scrollFocus = service.saveScrollFocus( grid );
    +          savedState.selection = service.saveSelection( grid );
    +          
    +          return savedState;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restore
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Applies the provided state to the grid
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} state the state we'd like to restore
    +         */
    +        restore: function( grid, $scope, state ){
    +          if ( state.columns ) {
    +            service.restoreColumns( grid, state.columns );
    +          }
    +          
    +          if ( state.scrollFocus ){
    +            service.restoreScrollFocus( grid, $scope, state.scrollFocus );
    +          }
    +          
    +          if ( state.selection ){
    +            service.restoreSelection( grid, state.selection );
    +          }
    +          
    +          grid.refresh();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name saveColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the column setup, including sort, filters, ordering
    +         * and column widths.
    +         * 
    +         * Works through the current columns, storing them in order.  Stores the
    +         * column name, then the visible flag, width, sort and filters for each column.
    +         *
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {array} the columns state ready to be saved
    +         */
    +        saveColumns: function( grid ) {
    +          var columns = [];
    +          angular.forEach( grid.columns, function( column ) {
    +            var savedColumn = {};
    +            savedColumn.name = column.name;
    +            savedColumn.visible = column.visible;
    +            savedColumn.width = column.width;
    +            
    +            // these two must be copied, not just pointed too - otherwise our saved state is pointing to the same object as current state
    +            savedColumn.sort = angular.copy( column.sort );
    +            savedColumn.filters = angular.copy ( column.filters );
    +            columns.push( savedColumn );
    +          });
    +          
    +          return columns;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently scroll or focus.
    +         * 
    +         * If cellNav isn't present then does nothing - we can't return
    +         * to the scroll position without cellNav anyway.
    +         * 
    +         * If the cellNav module is present, and saveFocus is true, then
    +         * it saves the currently focused cell.  If rowIdentity is present
    +         * then saves using rowIdentity, otherwise saves visibleRowNum.
    +         * 
    +         * If the cellNav module is not present, and saveScroll is true, then
    +         * it approximates the current scroll row and column, and saves that.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveScrollFocus: function( grid ){
    +          if ( !grid.api.cellNav ){
    +            return {};
    +          }
    +          
    +          var scrollFocus = {};
    +          if ( grid.options.saveFocus ){
    +            scrollFocus.focus = true;
    +            var rowCol = grid.api.cellNav.getFocusedCell();
    +            if ( rowCol !== null ) {
    +              scrollFocus.colName = rowCol.col.colDef.name;
    +              scrollFocus.rowVal = service.getRowVal( grid, rowCol.row );
    +            }
    +          } else if ( grid.options.saveScroll ) {
    +            scrollFocus.focus = false;
    +            if ( grid.renderContainers.body.prevRowScrollIndex ){
    +              scrollFocus.rowVal = service.getRowVal( grid, grid.renderContainers.body.visibleRowCache[ grid.renderContainers.body.prevRowScrollIndex ]);
    +            }
    +            
    +            if ( grid.renderContainers.body.prevColScrollIndex ){
    +              scrollFocus.colName = grid.renderContainers.body.visibleColumnCache[ grid.renderContainers.body.prevColScrollIndex ].name;
    +            }
    +          }        
    +          
    +          return scrollFocus;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently selected rows, if the selection feature is enabled
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveSelection: function( grid ){
    +          if ( !grid.api.selection ){
    +            return {};
    +          }
    +          
    +          var selection = grid.api.selection.getSelectedGridRows().map( function( gridRow ) {
    +            return service.getRowVal( grid, gridRow );
    +          });
    +          
    +          return selection;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getRowVal
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Helper function that gets either the rowNum or
    +         * the saveRowIdentity, given a gridRow 
    +         * @param {Grid} grid the grid the row is in
    +         * @param {GridRow} gridRow the row we want the rowNum for
    +         * @returns {object} an object containing { identity: true/false, row: rowNumber/rowIdentity }
    +         * 
    +         */
    +        getRowVal: function( grid, gridRow ){
    +          if ( !gridRow ) {
    +            return null;
    +          }
    +          
    +          var rowVal = {};
    +          if ( grid.options.saveRowIdentity ){
    +            rowVal.identity = true;
    +            rowVal.row = grid.options.saveRowIdentity( gridRow.entity );
    +          } else {
    +            rowVal.identity = false;
    +            rowVal.row = grid.renderContainers.body.visibleRowCache.indexOf( gridRow );
    +          }
    +          return rowVal;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restoreColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Restores the columns, including order, visible, width
    +         * sort and filters.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} columnsState the list of columns we had before, with their state
    +         */
    +        restoreColumns: function( grid, columnsState ){
    +          angular.forEach( columnsState, function( columnState, index ) {
    +            var currentCol = grid.columns.filter( function( column ) {
    +              return column.name === columnState.name;
    +            });
    +            
    +            if ( currentCol.length > 0 ){
    +              var currentIndex = grid.columns.indexOf( currentCol[0] );
    +              
    +              grid.columns[currentIndex].visible = columnState.visible;
    +              grid.columns[currentIndex].colDef.visible = columnState.visible;
    +              grid.columns[currentIndex].width = columnState.width;
    +              grid.columns[currentIndex].sort = angular.copy( columnState.sort );
    +              grid.columns[currentIndex].filters = angular.copy( columnState.filters );
    +
    +              if ( currentIndex !== index ){
    +                var column = grid.columns.splice( currentIndex, 1 )[0];
    +                grid.columns.splice( index, 0, column );
    +              }
    +            }
    +          });
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Scrolls to the position that was saved.  If focus is true, then
    +         * sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +         * specified row/col.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} scrollFocusState the scroll/focus state ready to be restored
    +         */
    +        restoreScrollFocus: function( grid, $scope, scrollFocusState ){
    +          if ( !grid.api.cellNav ){
    +            return;
    +          }
    +          
    +          var colDef, row;
    +          if ( scrollFocusState.colName ){
    +            var colDefs = grid.options.columnDefs.filter( function( colDef ) { return colDef.name === scrollFocusState.colName; });
    +            if ( colDefs.length > 0 ){
    +              colDef = colDefs[0];
    +            }
    +          }
    +          
    +          if ( scrollFocusState.rowVal && scrollFocusState.rowVal.row ){
    +            if ( scrollFocusState.rowVal.identity ){
    +              row = service.findRowByIdentity( grid, scrollFocusState.rowVal );
    +            } else {
    +              row = grid.renderContainers.body.visibleRowCache[ scrollFocusState.rowVal.row ];
    +            }
    +          }
    +          
    +          var entity = row && row.entity ? row.entity : null ;
    +
    +          if ( colDef || entity ) {          
    +            if (scrollFocusState.focus ){
    +              grid.api.cellNav.scrollToFocus( $scope, entity, colDef );
    +            } else {
    +              grid.api.cellNav.scrollTo( $scope, entity, colDef );
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Selects the rows that are provided in the selection
    +         * state.  If you are using `saveRowIdentity` and more than one row matches the identity
    +         * function then only the first is selected.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} selectionState the selection state ready to be restored
    +         */
    +        restoreSelection: function( grid, selectionState ){
    +          if ( !grid.api.selection ){
    +            return;
    +          }
    +          
    +          grid.api.selection.clearSelectedRows();
    +
    +          angular.forEach( selectionState, function( rowVal ) {
    +            if ( rowVal.identity ){
    +              var foundRow = service.findRowByIdentity( grid, rowVal );
    +              
    +              if ( foundRow ){
    +                grid.api.selection.selectRow( foundRow.entity );
    +              }
    +              
    +            } else {
    +              grid.api.selection.selectRowByVisibleIndex( rowVal.row );
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name findRowByIdentity
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Finds a row given it's identity value, returns the first found row
    +         * if any are found, otherwise returns null if no rows are found.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} rowVal the row we'd like to find
    +         * @returns {gridRow} the found row, or null if none found
    +         */
    +        findRowByIdentity: function( grid, rowVal ){
    +          if ( !grid.options.saveRowIdentity ){
    +            return null;
    +          }
    +          
    +          var filteredRows = grid.rows.filter( function( gridRow ) {
    +            if ( grid.options.saveRowIdentity( gridRow.entity ) === rowVal.row ){
    +              return true;
    +            } else {
    +              return false;
    +            }
    +          });
    +          
    +          if ( filteredRows.length > 0 ){
    +            return filteredRows[0];
    +          } else {
    +            return null;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.saveState.directive:uiGridSaveState
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds saveState features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-save-state></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSaveState', ['uiGridSaveStateConstants', 'uiGridSaveStateService', 'gridUtil', '$compile',
    +    function (uiGridSaveStateConstants, uiGridSaveStateService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridSaveStateService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  //add methods to GridRow
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('GridRow', ['$delegate', function($delegate) {
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.selection.api:GridRow
    +       *
    +       *  @description GridRow prototype functions added for selection
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name enableSelection
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Enable row selection for this row, only settable by internal code.
    +       *
    +       *  The grouping feature, for example, might set group header rows to not be selectable.
    +       *  <br/>Defaults to true
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name isSelected
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +       *  <br/>Defaults to false
    +       */
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name setSelected
    +         * @methodOf ui.grid.selection.api:GridRow
    +         * @description Sets the isSelected property and updates the selectedCount
    +         * Changes to isSelected state should only be made via this function
    +         * @param {bool} selelected value to set
    +         */
    +        $delegate.prototype.setSelected = function(selected) {
    +          this.isSelected = selected;
    +          if (selected) {
    +            this.grid.selection.selectedCount++;
    +          }
    +          else {
    +            this.grid.selection.selectedCount--;
    +          }
    +        };
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.grid:selection
    +           *
    +           *  @description Grid properties and functions added for selection
    +           */
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name selectedCount
    +           *  @propertyOf  ui.grid.selection.grid:selection
    +           *  @description Current count of selected rows
    +           *  @example
    +           *  var count = grid.selection.selectedCount
    +           */
    +          grid.selection.selectedCount = 0;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChanged: function (scope, row, evt) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows, evt) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                toggleRowSelection: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum, evt ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && typeof(row) !== 'undefined' && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                unSelectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected && row.enableSelection !== false ){
    +                      row.setSelected(true);
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllVisibleRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected && row.enableSelection !== false){
    +                        row.setSelected(true);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.setSelected(false);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                clearSelectedRows: function (evt) {
    +                  service.clearSelectedRows(grid, evt);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableFooterTotalSelected
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Shows the total number of selected items in footer if true.
    +           *  <br/>Defaults to true.
    +           *  <br/>GridOptions.showFooter must also be set to true.
    +           */
    +          gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name isRowSelectable
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.
    +           */
    +
    +          gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {Event} event object if resulting from event
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid, evt);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid, evt);
    +            }
    +          }
    +
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else if (row.enableSelection !== false) {
    +            row.setSelected(!selected);
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            } else {
    +              grid.selection.selectAll = false;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {Event} event object if raised from an event
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, evt, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected && rowToSelect.enableSelection !== false ){
    +                rowToSelect.setSelected(true);
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows, evt );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         * @param {Event} event object if raised from an event
    +         */
    +        clearSelectedRows: function (grid, evt) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.setSelected(false);
    +              service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +          grid.selection.selectAll = false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * @param {Event} event object if raised from an event
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows, evt ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * @param {Event} event object if raised from an event
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows, evt ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows, evt);
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  minWidth: 10,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false,
    +                  exporterSuppressExport: true 
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +              
    +              if (uiGridCtrl.grid.options.isRowSelectable !== angular.noop) {
    +                uiGridCtrl.grid.registerRowBuilder(function(row, options) {
    +                  row.enableSelection = uiGridCtrl.grid.options.isRowSelectable(row);
    +                });
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self, evt);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0, evt);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows(evt);
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            var touchStartTime = 0;
    +            var touchTimeout = 300;
    +            var selectCells = function(evt){
    +              if (evt.shiftKey) {
    +                uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect);
    +              }
    +              else if (evt.ctrlKey || evt.metaKey) {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +              }
    +              else {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +              }
    +              $scope.$apply();
    +            };
    +
    +            var touchStart = function(evt){
    +              touchStartTime = (new Date()).getTime();
    +            };
    +
    +            var touchEnd = function(evt) {
    +              var touchEndTime = (new Date()).getTime();
    +              var touchTime = touchEndTime - touchStartTime;
    +
    +              if (touchTime < touchTimeout ) {
    +                // short touch
    +                selectCells(evt);
    +              }
    +            };
    +
    +            function registerRowSelectionEvents() {
    +              if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +                $elm.addClass('ui-grid-disable-selection');
    +                $elm.on('touchstart', touchStart);
    +                $elm.on('touchend', touchEnd);
    +                $elm.on('click', selectCells);
    +
    +                $scope.registered = true;
    +              }
    +            }
    +
    +            function deregisterRowSelectionEvents() {
    +              if ($scope.registered){
    +                $elm.removeClass('ui-grid-disable-selection');
    +
    +                $elm.off('touchstart', touchStart);
    +                $elm.off('touchend', touchEnd);
    +                $elm.off('click', selectCells);
    +
    +                $scope.registered = false;
    +              }
    +            }
    +
    +            registerRowSelectionEvents();
    +            // register a dataChange callback so that we can change the selection configuration dynamically
    +            // if the user changes the options
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( function() {
    +              if ( $scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection &&
    +                !$scope.registered ){
    +                registerRowSelectionEvents();
    +              } else if ( ( !$scope.grid.options.enableRowSelection || $scope.grid.options.enableRowHeaderSelection ) &&
    +                $scope.registered ){
    +                deregisterRowSelectionEvents();
    +              }
    +            }, [uiGridConstants.dataChange.OPTIONS] );
    +
    +            $elm.on( '$destroy', dataChangeDereg);
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridGridFooter', ['$compile', 'uiGridConstants', 'gridUtil', function ($compile, uiGridConstants, gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      priority: -1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            if (!uiGridCtrl.grid.options.showGridFooter) {
    +              return;
    +            }
    +
    +
    +            gridUtil.getTemplate('ui-grid/gridFooterSelectedItems')
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +
    +                angular.element($elm[0].getElementsByClassName('ui-grid-grid-footer')[0]).append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\"><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-grid-footer',
    +    "<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{'search.totalItems' | t}} {{grid.rows.length}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    /*\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "    */\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\"></div><div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></div><!-- native scrolling --><!--<div ui-grid-native-scrollbar ng-if=\"enableVerticalScrollbar\" type=\"vertical\"></div>--><!--<div ui-grid-native-scrollbar ng-if=\"enableHorizontalScrollbar\" type=\"horizontal\"></div>--></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\" ng-style=\"containerCtrl.colContainer.getViewPortStyle()\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth()) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableTopRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !grid.expandable.expandedAll, 'ui-grid-icon-minus-squared' : grid.expandable.expandedAll }\" ng-click=\"grid.api.expandable.toggleAllRows()\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\" download=\"FILE_NAME\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/pagination',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager ng-show=\"grid.options.enablePaginationControls\"><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"paginationApi.seek(1)\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"paginationApi.previousPage()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.paginationCurrentPage\" min=\"1\" max=\"{{ paginationApi.getTotalPages() }}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"paginationApi.getTotalPages() > 0\">/ {{ paginationApi.getTotalPages() }}</span> <button type=\"button\" ng-click=\"paginationApi.nextPage()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"paginationApi.seek(paginationApi.getTotalPages())\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.paginationPageSize\" ng-options=\"o as o for o in grid.options.paginationPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/gridFooterSelectedItems',
    +    "<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"search.selectedItems\" | t}} {{grid.selection.selectedCount}})</span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.min.css b/release/3.0.0-RC.18-8fe4e49/ui-grid.min.css
    new file mode 100644
    index 000000000..387267cdc
    --- /dev/null
    +++ b/release/3.0.0-RC.18-8fe4e49/ui-grid.min.css
    @@ -0,0 +1,4 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-8fe4e49 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;box-sizing:border-box;float:left;top:0;bottom:0;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu-button-last-col{margin-right:25px}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative;padding-top:1px}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#f0f0ee !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-grid-footer{float:left;width:100%}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid{overflow-y:scroll;max-height:300px;border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child,.ui-grid[dir=rtl] .ui-grid-header-cell:last-child{border-left:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}.ui-grid-row-selected>[ui-grid-row]>.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.min.js b/release/3.0.0-RC.18-8fe4e49/ui-grid.min.js
    new file mode 100644
    index 000000000..c13b71534
    --- /dev/null
    +++ b/release/3.0.0-RC.18-8fe4e49/ui-grid.min.js
    @@ -0,0 +1,12 @@
    +/*!
    + * ui-grid - v3.0.0-RC.18-8fe4e49 - 2015-02-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart",COLUMN_HEADER_CLICK:"uiGridColumnHeaderClick"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,PG_UP:33,PG_DOWN:34,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column",OPTIONS:"options"},scrollbars:{NEVER:0,ALWAYS:1}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){var c=a.col.getColClass(!1);b.addClass(c);var e,f=function(){var c=b;e&&(c.removeClass(e),e=null),e=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,c.addClass(e)};a.col.cellClass&&f();var g=a.grid.registerDataChangeCallback(f,[d.dataChange.COLUMN,d.dataChange.EDIT]),h=function(d,g){if(d!==g){(e||a.col.cellClass)&&f();var h=a.col.getColClass(!1);h!==c&&(b.removeClass(c),b.addClass(h),c=h)}},i=a.$watch("col",h),j=a.$watch("row",h),k=function(){g(),i(),j()};a.$on("$destroy",k),b.on("$destroy",k)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,e,f,g){var h=this;d.initialize(b,g),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,c,f){b.col=a;var g=d.getColumnElementPosition(b,a,c);b.menuShown?(b.colElement=c,b.colElementPosition=g,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(h.shown=b.menuShown=!0,d.repositionMenu(b,a,g,e,c),b.colElement=c,b.colElementPosition=g,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu(),b.grid.api.core.notifyDataChange(c.dataChange.COLUMN)}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",h)}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-grid-footer";return{restrict:"EA",replace:!0,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(a,c,f,g){a.grid=g.grid;var h=a.grid.options.gridFooterTemplate?a.grid.options.gridFooterTemplate:e;d.getTemplate(h).then(function(d){var e=angular.element(d),f=b(e)(a);c.append(f)})},post:function(){}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,i){function j(b){var c=!1;b.shiftKey&&(c=!0),k.grid.sortColumn(a.col,c).then(function(){k.columnMenuScope&&k.columnMenuScope.hideMenu(),k.grid.refresh()})}var k=i[0],l=i[1];a.grid=k.grid,a.renderContainer=k.grid.renderContainers[l.containerId];var m=a.col.getColClass(!1);c.addClass(m),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var n,o=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),p=function(){var b=c;n&&(b.removeClass(n),n=null),n=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(n);var d=a.grid.renderContainers.right?a.grid.renderContainers.right:a.grid.renderContainers.body;a.isLastCol=a.col===d.visibleColumnCache[d.visibleColumnCache.length-1]};a.$watch("col",function(b,d){if(b!==d){var e=a.col.getColClass(!1);e!==m&&(c.removeClass(m),c.addClass(e),m=e)}}),p();var q=a.grid.registerDataChangeCallback(p,[f.dataChange.COLUMN]);if(a.$on("$destroy",q),a.sortable=k.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=k.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var r,s=0,t=e.isTouchEnabled()?"touchstart":"mousedown";o.on(t,function(d){d.stopPropagation(),"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(s=(new Date).getTime(),r=b(function(){},h),r.then(function(){a.colMenu&&k.columnMenuScope.showMenu(a.col,c,d)}),k.fireEvent(f.events.COLUMN_HEADER_CLICK,{event:d,columnName:a.col.colDef.name}))});var u=e.isTouchEnabled()?"touchend":"mouseup";o.on(u,function(){b.cancel(r)}),a.$on("$destroy",function(){o.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),k.columnMenuScope.menuShown&&k.columnMenuScope.col===a.col?k.columnMenuScope.hideMenu():k.columnMenuScope.showMenu(a.col,c)},a.sortable){var v=e.isTouchEnabled()?"touchend":"click";o.on(v,function(a){a.stopPropagation(),b.cancel(r);var c=(new Date).getTime(),d=c-s;d>h||j(a)}),a.$on("$destroy",function(){b.cancel(r)})}if(a.filterable){var w=[];angular.forEach(a.col.filters,function(b,c){w.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(k.grid.api.core.raise.filterChanged(),k.grid.refresh().then(function(){if(k.prevScrollArgs&&k.prevScrollArgs.y&&k.prevScrollArgs.y.percentage){var a=new g(k.grid,null,null,"uiGridHeaderCell.toggleMenu");a.y.percentage=k.prevScrollArgs.y.percentage,a.fireScrollingEvent()}}))}))}),a.$on("$destroy",function(){angular.forEach(w,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth(),b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,g=a,i=!1,j=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(g/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",i=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,i=!0)});var k=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return k.indexOf(a.widthType)-k.indexOf(b.widthType)}).forEach(function(a){var b=j(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,g-=a.drawnWidth}),i&&g>0&&c>0&&a>c){var l=function(a){g>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,g--)},m=0;do m=g,b.forEach(l);while(g>0&&g!==m)}c=Math.max(c,a);var n="";return b.forEach(function(a){n+=a.getColClassDefinition()}),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),n}{var g=e[0],h=e[1];g.grid}d.disableAnimations(b),h.header=b;var i=b[0].getElementsByClassName("ui-grid-header-viewport")[0];i&&(h.headerViewport=i),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService","uiGridConstants",function(a,b,c){var d={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",d.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",d.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var c=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?c=c.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),c=c.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(c=c.concat(d.showHideColumns(b))),c},showHideColumns:function(a){var c=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(c.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};d.setMenuItemTitle(e,b,a.grid),c.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},d.setMenuItemTitle(e,b,a.grid),c.push(e)}}),c):c},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh(),a.grid.api.core.notifyDataChange(c.dataChange.COLUMN)}};return d}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d,e,g){var h=this;h.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var e="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(e=d.originalEvent.type),angular.element(document).off("click touchstart",i),b(function(){angular.element(document).on(e,i)})},h.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",i)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var i=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",i),a.$on("$destroy",function(){angular.element(document).off("click touchstart",i)}),a.$on("$destroy",function(){angular.element(c).off("resize",i)}),g&&a.$on("$destroy",g.grid.api.core.on.scrollEvent(a,i)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,i))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil","ScrollEvent",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(a,c,f,g){function h(b){if(!b.grid||b.grid.id===n.id){if(b.y&&a.bindScrollVertical){m.prevScrollArgs=b;var c=b.getNewScrollTop(o,m.viewport);(b.source!==e.Sources.ViewPortScroll||b.sourceColContainer!==p)&&(m.viewport[0].scrollTop=c)}if(b.x&&a.bindScrollHorizontal){m.prevScrollArgs=b;var f=b.getNewScrollLeft(p,m.viewport);a.newScrollLeft=f,m.headerViewport&&(m.headerViewport.scrollLeft=d.denormalizeScrollLeft(m.headerViewport,f)),m.footerViewport&&(m.footerViewport.scrollLeft=d.denormalizeScrollLeft(m.footerViewport,f)),b.source!==e.Sources.ViewPortScroll&&(m.viewport[0].scrollLeft=f),m.prevScrollLeft=f}}}function i(a){a.originalEvent&&(a=a.originalEvent);var b,c,d,f;d=a.targetTouches[0].screenX,f=a.targetTouches[0].screenY,b=-(d-t),c=-(f-s),w=1>c?-1:1,x=1>b?-1:1,c*=2,b*=2;var g=new e(n,o,p,e.Sources.RenderContainerTouchMove);if(0!==c){var h=(u+c)/o.getVerticalScrollLength();h>1?h=1:0>h&&(h=0),g.y={percentage:h,pixels:c}}if(0!==b){var i=(v+b)/(p.getCanvasWidth()-p.getViewportWidth());i>1?i=1:0>i&&(i=0),g.x={percentage:i,pixels:b}}g.fireScrollingEvent()}function j(a){a.originalEvent&&(a=a.originalEvent),b.unbind("touchmove",i),b.unbind("touchend",j),b.unbind("touchcancel",j);{var c=m.viewport[0].scrollTop,d=m.viewport[0].scrollTop;Math.abs(c-u),Math.abs(d-v),new Date-r}}function k(){var b="",c=p.getCanvasWidth(),d=p.getViewportWidth(),e=o.getCanvasHeight();"body"!==a.containerId&&(e+=n.scrollbarHeight);var f=o.getViewportHeight(),g=p.getHeaderViewportWidth(),h=p.getHeaderViewportWidth();return b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { width: "+(c+n.scrollbarWidth)+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-canvas { width: "+c+n.scrollbarWidth+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==q.explicitHeaderHeight&&null!==q.explicitHeaderHeight&&q.explicitHeaderHeight>0?b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.explicitHeaderHeight+"px; }":void 0!==q.innerHeaderHeight&&null!==q.innerHeaderHeight&&q.innerHeaderHeight>0&&(b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.innerHeaderHeight+"px; }"),b}var l=g[0],m=g[1],n=l.grid,o=m.rowContainer,p=m.colContainer,q=n.renderContainers[a.containerId];c.addClass("ui-grid-render-container-"+a.containerId),(a.bindScrollHorizontal||a.bindScrollVertical)&&n.api.core.on.scrollEvent(a,h),c.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){var b=d.normalizeWheelEvent(a),c=new e(n,o,p,e.Sources.RenderContainerMouseWheel);if(0!==b.deltaY){var f=-120*b.deltaY,g=(m.viewport[0].scrollTop+f)/o.getVerticalScrollLength();0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:f}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(m.viewport),j=(i+h)/(p.getCanvasWidth()-p.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}(c.y&&0!==c.y.percentage&&1!==c.y.percentage&&0!==m.viewport[0].scrollTop||c.x&&0!==c.x.percentage&&1!==c.x.percentage)&&a.preventDefault(),c.fireThrottledScrollingEvent()});var r,s=0,t=0,u=0,v=0,w=1,x=1;d.isTouchEnabled()&&c.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),l.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),r=new Date,s=a.targetTouches[0].screenY,t=a.targetTouches[0].screenX,u=m.viewport[0].scrollTop,v=m.viewport[0].scrollLeft,b.on("touchmove",i),b.on("touchend touchcancel",j)}),c.bind("$destroy",function(){c.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){c.unbind(a)})}),l.grid.registerStyleComputation({priority:6,func:k})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){function e(){a.row.getRowTemplateFn.then(function(c){var d=a.$new();c(d,function(a){h&&(h.remove(),i.$destroy()),b.empty().append(a),h=a,i=d})})}{var f=d[0],g=d[1];f.grid}a.grid=f.grid,a.colContainer=g.colContainer;var h,i;e(),a.$watch("row.getRowTemplateFn",function(a,b){a!==b&&e()})},post:function(){}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil","ScrollEvent",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){var g=f[0],h=f[1];c.containerCtrl=h;var i=h.rowContainer,j=h.colContainer,k=g.grid;c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var c=d[0].scrollTop,e=a.normalizeScrollLeft(d),f=-1,g=-1;if(e!==j.prevScrollLeft){k.flagScrollingHorizontally();var h=(e-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth());f=0!==h?e/h:0,j.adjustScrollHorizontal(e,f)}if(c!==i.prevScrollTop){k.flagScrollingVertically();var l=(c-i.prevScrollTop,i.getVerticalScrollLength());g=c/l,g>1&&(g=1),0>g&&(g=0),i.adjustScrollVertical(c,g)}var m=new b(k,i,j,b.Sources.ViewPortScroll);m.newScrollLeft=e,m.newScrollTop=c,f>-1&&(m.x={percentage:f}),g>-1&&(m.y={percentage:g}),m.fireScrollingEvent()})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns({orderByColumnDefs:!0}).then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===n.grid.options.columnDefs.length&&b.length>0&&n.grid.buildColumnDefsFromData(b),(n.grid.options.columnDefs.length>0||b.length>0)&&d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()})),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),n.grid.appScope=n.grid.appScope||a.$parent,b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.refreshCanvas(!0)}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.calcFooterHeight(),m=0;
    +i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas(),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth||e.width||0}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0!==h&&h||e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.appScope=b.options.appScopeProvider,b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.calcFooterHeight(),b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),g=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.scrollbarHeight=0,b.scrollbarWidth=0,b.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarHeight=d.getScrollbarWidth()),b.options.enableVerticalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarWidth=d.getScrollbarWidth()),b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT]),b.registerStyleComputation({priority:10,func:b.getFooterStyles})};return o.prototype.calcFooterHeight=function(){if(!this.hasFooter())return 0;var a=0;return this.options.showGridFooter&&(a+=this.options.gridFooterHeight),this.options.showColumnFooter&&(a+=this.options.columnFooterHeight),a},o.prototype.getFooterStyles=function(){var a=".grid"+this.id+" .ui-grid-footer-aggregates-row { height: "+this.options.columnFooterHeight+"px; }";return a+=" .grid"+this.id+" .ui-grid-footer-info { height: "+this.options.gridFooterHeight+"px; }"},o.prototype.hasFooter=function(){return this.options.showGridFooter||this.options.showColumnFooter},o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b,c){var f=d.nextUid();b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[f]={callback:a,types:b,_this:c};var g=this,h=function(){delete g.dataChangeCallbacks[f]};return h},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&(b._this?b.callback.apply(b._this,this):b.callback(this))},this)},o.prototype.notifyDataChange=function(a){var b=e.dataChange;a===b.ALL||a===b.COLUMN||a===b.EDIT||a===b.ROW||a===b.OPTIONS?this.callDataChangeCallbacks(a):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+a)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.refresh()})})},o.prototype.buildColumns=function(b){var c={orderByColumnDefs:!1};angular.extend(c,b);var e,f=this,h=[],i=f.rowHeaderColumns.length;for(e=0;e<f.columns.length;e++)f.getColDef(f.columns[e].name)||(f.columns.splice(e,1),e--);if(f.rowHeaderColumns.forEach(function(a){f.columns.unshift(a)}),f.options.columnDefs.forEach(function(a,b){f.preprocessColDef(a);var c=f.getColumn(a.name);c?c.updateColumnDef(a,!1):(c=new g(a,d.nextUid(),f),f.columns.splice(b+i,0,c)),f.columnBuilders.forEach(function(b){h.push(b.call(f,a,c,f.options))})}),c.orderByColumnDefs){var j=f.columns.slice(0);for(e=0;e<f.options.columnDefs.length;e++)j[e+i]=f.columns[e+i].name!==f.options.columnDefs[e].name?f.getColumn(f.options.columnDefs[e].name):f.columns[e+i];f.columns.length=0,Array.prototype.splice.apply(f.columns,[0,0].concat(j))}return a.all(h).then(function(){f.rows.length>0&&f.assignTypes()})},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){var b=this;if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");if(void 0===a.name&&void 0!==a.field){var c=b.getColumn(a.field);if(c){var d=new RegExp("^"+a.field+"(\\d+)$","i"),e=b.columns.filter(function(a){return d.test(a.displayName)}).sort(function(a,b){if(a===b)return 0;var c=a.match(d)[1],e=b.match(d)[1];return parseInt(c,10)>parseInt(e,10)?1:-1});if(0===e.length)a.name=a.field+"2";else{var f=e[e.length-1].displayName.match(d)[1];f=parseInt(f,10),a.name=a.field+(f+1)}}else a.name=a.field}},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;{0===g.rows.length}for(g.rows.length=0,c=0;c<b.length;c++){var j=b[c];e=i.get(j),f=e?e.row:g.processRowBuilders(new h(j,c,g)),g.rows.push(f),d.put(j,{i:c,entity:j,row:f})}g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var k,l,m;if(g.options.enableRowHashing){k=[],m=[];var n={};for(l=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var o=!1;g.options.getRowIdentity(f)||(o=!0),e=d.get(f),e?e.row&&(n[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),o?m.push(f):k.push(f))}for(c=0;c<g.rows.length;c++){var p=g.rows[c],q=g.options.rowIdentity(p.entity);n[q]||l.push(p)}}var r=k||[],s=m||b;r=r.concat(g.newInN(g.rows,s,"entity")),g.addRows(r);var t=g.getDeletedRows(l||g.rows,b);for(c=0;c<t.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(t[c].entity),g.rows.splice(g.rows.indexOf(t[c]),1)}else g.createRowHashMap(),g.rows.length=0;var u=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),v=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([u,v])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.canvasHeightShouldUpdate=!0,"undefined"==typeof d.visibleRowCache?d.visibleRowCache=[]:d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}b.api.core.raise.rowsRendered(this.api)},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.updateCanvasHeight=function(){var a=this;for(var b in a.renderContainers)if(a.renderContainers.hasOwnProperty(b)){var c=a.renderContainers[b];c.canvasHeightShouldUpdate=!0}},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight,c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth,c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b===a||b.colDef.suppressRemoveSort||(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)&&g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(null,c.prevScrolltopPercentage),c.adjustColumns(null,c.prevScrollleftPercentage)}},o.prototype.hasLeftContainerColumns=function(){return this.hasLeftContainer()&&this.renderContainers.left.renderedColumns.length>0},o.prototype.hasRightContainerColumns=function(){return this.hasRightContainer()&&this.renderContainers.right.renderedColumns.length>0},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,c,d,e){return b.$on(a,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(e?e:d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged"),this.registerEvent("core","rowsRendered"),this.registerEvent("core","scrollEvent"),this.registerEvent("core","canvasHeightChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.eventId,a.handler,c.grid,a._this)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$emit.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b,c){var e=f(g,b,d.grid,c),h={handler:b,dereg:e,eventId:g,scope:a,_this:c};d.listeners.push(h);var i=function(){h.dereg();var a=d.listeners.indexOf(h);d.listeners.splice(a,1)};return a.$on("$destroy",function(){i()}),i}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a,!0)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b,c){var e=this;if(e.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.grid.options.columnDefs.indexOf(b));e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(e.width)||!angular.isNumber(e.width))if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(f);e.width=b.width}e.minWidth=b.minWidth?b.minWidth:30,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,"string"!=typeof e.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+e.field),e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.footerCellClass=b.footerCellClass,e.cellClass=b.cellClass,e.headerCellClass=b.headerCellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),c&&e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),c&&(e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)),d.prototype.unsort=function(){this.sort={},e.grid.api.core.raise.sortChanged(e,e.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showGridFooter=c.showGridFooter===!0,c.showColumnFooter=c.showColumnFooter===!0,c.columnFooterHeight="undefined"!=typeof c.columnFooterHeight?c.columnFooterHeight:30,c.gridFooterHeight="undefined"!=typeof c.gridFooterHeight?c.gridFooterHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c.appScopeProvider=c.appScopeProvider||null,c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],d.canvasHeightShouldUpdate=!0,d.$$canvasHeight=0,c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight,d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth,c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},c.prototype.getCanvasHeight=function(){var a=this;if(!a.canvasHeightShouldUpdate)return a.$$canvasHeight;var b=a.$$canvasHeight;return a.$$canvasHeight=0,a.visibleRowCache.forEach(function(b){a.$$canvasHeight+=b.height}),a.canvasHeightShouldUpdate=!1,a.grid.api.core.raise.canvasHeightChanged(b,a.$$canvasHeight),a.$$canvasHeight},c.prototype.getVerticalScrollLength=function(){return this.getCanvasHeight()-this.getViewportHeight()},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];
    +this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getVerticalScrollLength());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if("undefined"!=typeof a&&null!==a){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return}var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var b,c=this,d=[],e=[],f=0,g=c.getViewportWidth(),h=0,i=0,j="",k=c.visibleColumnCache;k.forEach(function(b){if(b.visible){var c=!1;angular.isNumber(b.width)||(c=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(f=parseInt(f+b.width.length,10),d.push(b)):c?e.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=g-h;if(e.length>0){for(l=0;l<e.length;l++){m=e[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1))}e.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(d.length>0){var q=parseInt(o/f,10);for(l=0;l<d.length;l++)m=d[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,f--,i+=n,m.drawnWidth=n,b=m,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,f--,i+=n,m.drawnWidth=n,d.splice(l,1));q=parseInt(o/f,10),d.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=g-parseInt(i,10);if(r>0&&i>0&&g>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}g>i&&(i=g),k.forEach(function(a){j+=a.getColClassDefinition()}),c.canvasWidth=parseInt(i,10),this.columnStyles=j},c.prototype.getViewPortStyle=function(){var a=this,c={};return"body"===a.name?(c["overflow-x"]=a.grid.options.enableHorizontalScrollbar===b.scrollbars.NEVER?"hidden":"scroll",c["overflow-y"]=a.grid.isRTL()?a.grid.hasLeftContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":a.grid.hasRightContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"):"left"===a.name?(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":"hidden"):(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"),c},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.$$height=d.options.rowHeight}return Object.defineProperty(b.prototype,"height",{get:function(){return this.$$height},set:function(a){a!==this.$$height&&(this.grid.updateCanvasHeight(),this.$$height=a)}}),b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){angular.module("ui.grid").factory("ScrollEvent",["gridUtil",function(a){function b(b,c,d,e){var f=this;if(!b)throw new Error("grid argument is required");f.grid=b,f.source=e,f.sourceRowContainer=c,f.sourceColContainer=d,f.newScrollLeft=null,f.newScrollTop=null,f.x=null,f.y=null,f.fireThrottledScrollingEvent=a.throttle(function(){f.grid.api.core.raise.scrollEvent(f)},f.grid.options.scrollThrottle,{trailing:!0})}return b.prototype.fireScrollingEvent=function(){this.grid.api.core.raise.scrollEvent(this)},b.prototype.getNewScrollLeft=function(b,c){var d=this;if(!d.newScrollLeft){var e,f=b.getCanvasWidth()-b.getViewportWidth(),g=a.normalizeScrollLeft(c);if("undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage)e=d.x.percentage;else{if("undefined"==typeof d.x.pixels||void 0===d.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");e=d.x.percentage=(g+d.x.pixels)/f}return Math.max(0,e*f)}return d.newScrollLeft},b.prototype.getNewScrollTop=function(a,b){var c=this;if(!c.newScrollTop){var d,e=a.getVerticalScrollLength(),f=b[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)d=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=c.y.percentage=(f+c.y.pixels)/e}return Math.max(0,d*e)}return c.newScrollTop},b.Sources={ViewPortScroll:"ViewPortScroll",RenderContainerMouseWheel:"RenderContainerMouseWheel",RenderContainerTouchMove:"RenderContainerTouchMove",Other:99},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowBuilder(g.rowTemplateAssigner),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)},rowTemplateAssigner:function(d){var e=this;if(d.rowTemplate){var f=b.defer();d.getRowTemplateFn=f.promise,a.getTemplate(d.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+d.rowTemplate+"'")})}else d.rowTemplate=e.options.rowTemplate,d.getRowTemplateFn=e.getRowTemplateFn;return d.getRowTemplateFn}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var b=angular.module("ui.grid");b.service("rowSearcher",["gridUtil","uiGridConstants",function(b,c){var d=c.filter.STARTS_WITH,e={};return e.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},e.stripTerm=function(b){var c=e.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},e.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return d;var b=e.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var f=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+f+"$",c)}return d},e.setupFilters=function(a){for(var b=[],d=a.length,f=0;d>f;f++){var g=a[f];if(g.noTerm||g.term){var h={},i="";g.flags&&g.flags.caseSensitive||(i+="i"),g.term&&(h.term=e.stripTerm(g)),h.condition=g.condition?g.condition:e.guessCondition(g),h.flags=angular.extend({caseSensitive:!1},g.flags),h.condition===c.filter.STARTS_WITH&&(h.startswithRE=new RegExp("^"+h.term,i)),h.condition===c.filter.ENDS_WITH&&(h.endswithRE=new RegExp(h.term+"$",i)),h.condition===c.filter.CONTAINS&&(h.containsRE=new RegExp(h.term,i)),h.condition===c.filter.EXACT&&(h.exactRE=new RegExp("^"+h.term+"$",i)),b.push(h)}}return b},e.runColumnFilter=function(a,b,d,e){var f=typeof e.condition,g=e.term,h=a.getCellValue(b,d);if(e.condition instanceof RegExp)return e.condition.test(h);if("function"===f)return e.condition(g,h,b,d);if(e.startswithRE)return e.startswithRE.test(h);if(e.endswithRE)return e.endswithRE.test(h);if(e.containsRE)return e.containsRE.test(h);if(e.exactRE)return e.exactRE.test(h);if(e.condition===c.filter.NOT_EQUAL){var i=new RegExp("^"+g+"$");return!i.exec(h)}if("number"==typeof h){var j=parseFloat(g.replace(/\\./,"."));isNaN(j)||(g=j)}return e.condition===c.filter.GREATER_THAN?h>g:e.condition===c.filter.GREATER_THAN_OR_EQUAL?h>=g:e.condition===c.filter.LESS_THAN?g>h:e.condition===c.filter.LESS_THAN_OR_EQUAL?g>=h:!0},e.searchColumn=function(a,b,c,d){if(a.options.useExternalFiltering)return!0;for(var f=d.length,g=0;f>g;g++){var h=d[g],i=e.runColumnFilter(a,b,c,h);if(!i)return!1}return!0},e.search=function(a,b,c){if(b){for(var d=[],f=c.length,g=0;f>g;g++){var h=c[g];"undefined"!=typeof h.filters&&(h.filters.length>1||1===h.filters.length&&h.filters[0].term)?d.push({col:h,filters:e.setupFilters(h.filters)}):"undefined"!=typeof h.filter&&h.filter&&("undefined"!=typeof h.filter.term&&h.filter.term||h.filter.noTerm)&&d.push({col:h,filters:e.setupFilters([h.filter])})}if(d.length>0){for(var i=function(a,b,c,d){(b.forceInvisible||!e.searchColumn(a,b,c,d))&&(b.visible=!1)},j=function(a,c){for(var d=b.length,e=0;d>e;e++)i(a,b[e],c.col,c.filters)},k=d.length,l=0;k>l;l++)j(a,d[l]);a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()}return b}},e}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toString().toLowerCase(),f=b.toString().toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);angular.forEach(c,function(a,b){a.entity.$uiGridIndex=b});var j=c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return 0===k?c.entity.$uiGridIndex-e.entity.$uiGridIndex:h===b.ASC?k:0-k});return angular.forEach(j,function(a){delete a.entity.$uiGridIndex}),j}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){p.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},pagination:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"всего строк: ",sum:"итого: ",avg:"среднее: ",min:"мин: ",max:"макс: "},gridMenu:{columns:"Столбцы:",importerTitle:"Import file",exporterAllAsCsv:"Экспортировать всё в CSV",exporterVisibleAsCsv:"Экспортировать видимые данные в CSV",exporterSelectedAsCsv:"Экспортировать выбранные данные в CSV",exporterAllAsPdf:"Экспортировать всё в PDF",exporterVisibleAsPdf:"Экспортировать видимые данные в PDF",exporterSelectedAsPdf:"Экспортировать выбранные данные в PDF"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},pagination:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3,PG_UP:4,PG_DOWN:5},EVENT_TYPE:{KEYDOWN:0,CLICK:1}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[],this.bodyContainer=a};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getFocusableRows=function(){return this.rows.filter(function(a){return a.allowCellFocus!==!1})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c);case d.direction.PG_UP:return this.getRowColPageUp(b,c);case d.direction.PG_DOWN:return this.getRowColPageDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=1);var h=0===f?d.length-1:f-1;return h>f?0===g?new a(b,d[h]):new a(e[g-1],d[h]):new a(b,d[h])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=f===d.length-1?0:f+1;return f>h?g===e.length-1?new a(b,d[h]):new a(e[g+1],d[h]):new a(b,d[h])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),g===e.length-1?new a(b,d[f]):new a(e[g+1],d[f])},e.prototype.getRowColPageDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return g>=e.length-h?new a(e[e.length-1],d[f]):new a(e[g+h],d[f])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),0===g?new a(b,d[f]):new a(e[g-1],d[f])},e.prototype.getRowColPageUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return 0>g-h?new a(e[0],d[f]):new a(e[g-h],d[f])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory","ScrollEvent",function(a,b,c,d,e,f){var g={initializeGrid:function(a){a.registerColumnBuilder(g.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null,a.cellNav.focusedCells=[],g.defaultGridOptions(a.options);var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(b,c,d){g.scrollTo(a,b,c,d)},scrollToFocus:function(b,c,d){g.scrollToFocus(a,b,c,d)},scrollToIfNecessary:function(b,c,d){g.scrollToIfNecessary(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol},getCurrentSelection:function(){return a.cellNav.focusedCells},rowColSelectIndex:function(b){for(var c=-1,d=0;d<a.cellNav.focusedCells.length;d++)if(a.cellNav.focusedCells[d].col.uid===b.col.uid&&a.cellNav.focusedCells[d].row.uid===b.row.uid){c=d;break}return c}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.modifierKeysToMultiSelectCells=a.modifierKeysToMultiSelectCells===!0},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.PG_UP?c.direction.PG_UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:a.keyCode===b.keymap.PG_DOWN?c.direction.PG_DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&"undefined"!=typeof c&&(e=a.getRow(c)),null!==d&&"undefined"!=typeof d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToFocus:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f);var g={row:e,col:f};a.cellNav.broadcastCellNav(g)},scrollToInternal:function(a,b,c,d){var e=new f(a,null,null,"uiGridCellNavService.scrollToInternal");if(null!==c){var g=a.renderContainers.body.visibleRowCache.indexOf(c),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;e.y={percentage:i}}null!==d&&(e.x={percentage:this.getLeftWidth(a,d)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(e.y||e.x)&&e.fireScrollingEvent()},scrollToIfNecessary:function(a,b,c,d){var e=new f(a,null,null,"uiGridCellNavService.scrollToIfNecessary"),g=a.renderContainers.body.visibleRowCache,h=a.renderContainers.body.visibleColumnCache,i=a.renderContainers.body.prevScrollTop+a.headerHeight;i=0>i?0:i;var j=a.renderContainers.body.prevScrollLeft,k=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight,l=a.renderContainers.body.prevScrollLeft+a.gridWidth;if(null!==c){var m=g.indexOf(c),n=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight(),o=(m+1)*a.options.rowHeight;o=0>o?0:o;var p,q;i>o?(p=a.renderContainers.body.prevScrollTop-(i-o),q=p/n,e.y={percentage:q}):o>k&&(p=o-k+a.renderContainers.body.prevScrollTop,q=p/n,e.y={percentage:q})}if(null!==d){for(var r=h.indexOf(d),s=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),t=0,u=0;r>u;u++){var v=h[u];t+=v.drawnWidth}t=0>t?0:t;var w=t+d.drawnWidth;w=0>w?0:w;var x,y;j>t?(x=a.renderContainers.body.prevScrollLeft-(j-t),y=x/s,y=y>1?1:y,e.x={percentage:y}):w>l&&(x=w-l+a.renderContainers.body.prevScrollLeft,y=x/s,y=y>1?1:y,e.x={percentage:y})}(e.y||e.x)&&e.fireScrollingEvent()},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return g}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,e,f,g){var h=b,i=g.grid;c.initializeGrid(i),g.cellNav={},g.cellNav.focusCell=function(a,b){g.cellNav.broadcastCellNav({row:a,col:b})},g.cellNav.broadcastCellNav=i.cellNav.broadcastCellNav=function(a,b){b=!(void 0===b||!b),g.cellNav.broadcastFocus(a,b),h.$broadcast(d.CELL_NAV_EVENT,a,b)},g.cellNav.broadcastFocus=function(b,c){c=!(void 0===c||!c);var d=b.row,e=b.col,f=g.grid.api.cellNav.rowColSelectIndex(b);if(null===i.cellNav.lastRowCol||-1===f){var h=new a(d,e);i.api.cellNav.raise.navigate(h,i.cellNav.lastRowCol),i.cellNav.lastRowCol=h,g.grid.options.modifierKeysToMultiSelectCells&&c?i.cellNav.focusedCells.push(b):i.cellNav.focusedCells=[b]}else i.options.modifierKeysToMultiSelectCells&&c&&f>=0&&i.cellNav.focusedCells.splice(f,1)},g.cellNav.handleKeyDown=function(a){var e=c.getDirection(a);if(null===e)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var h=g.grid.api.cellNav.getFocusedCell();if(h){var j=g.grid.renderContainers[f].cellNav.getNextRowCol(e,h.row,h.col);return j.eventType=d.EVENT_TYPE.KEYDOWN,g.cellNav.broadcastCellNav(j),c.scrollToIfNecessary(i,b,j.row,j.col),a.stopPropagation(),a.preventDefault(),!1}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,d,f,g){var h=g[0],i=g[1];if(h.grid.api.cellNav){var j=i.containerId,k=h.grid;e.decorateRenderContainers(k),d.attr("tabindex",-1),d.on("keydown",function(a){return a.uiGridTargetRenderContainerId=j,h.cellNav.handleKeyDown(a)});var l=!1;k.api.core.on.scrollEvent(c,function(c){c.grid&&c.grid.id!==h.grid.id||null!=h.grid.api.cellNav.getFocusedCell()&&("uiGridCellNavService.scrollToIfNecessary"===c.source?l=!0:a(l?function(){a(function(){var a=h.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&d[0].focus(),h.cellNav.broadcastCellNav(a),l=!1})}:function(){var a={col:{uid:null},row:{uid:null}};h.cellNav.broadcastCellNav(a)}))})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",-1)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}e.grid.api.cellNav&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey),c.stopPropagation()}),b.$on(f.CELL_NAV_EVENT,function(a,d,g){d.row===b.row&&d.col===b.col?(e.grid.options.modifierKeysToMultiSelectCells&&g&&-1===e.grid.api.cellNav.rowColSelectIndex(d)?i():h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&c.find("div")[0].focus()):e.grid.options.modifierKeysToMultiSelectCells&&g||i()}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","$timeout","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g,h){var i=500;return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(f,j,k,l){function m(){j.on("dblclick",t),j.on("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").on("focus",q),j.on("touchstart",n)}function n(a){"undefined"!=typeof a.originalEvent&&void 0!==a.originalEvent&&(a=a.originalEvent),j.on("touchend",o),A=c(function(){},i),A.then(function(){setTimeout(t,0),j.off("touchend",o)})}function o(){c.cancel(A),j.off("touchend",o)}function p(){j.off("dblclick",t),j.off("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").off("focus",q),j.off("touchstart",n)}function q(a){l&&l.cellNav&&l.cellNav.focusCell(f.row,f.col),a.stopPropagation(),t()}function r(a){h.isStartEditKey(a)&&t()}function s(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(f):a.colDef.cellEditableCondition)}function t(){if(!C&&s(f.col,f.row)){f.grid.api.cellNav&&f.grid.api.cellNav.scrollToIfNecessary(f,f.row,f.col),z=g(f.row.getQualifiedColField(f.col)),y=z(f),x=f.col.editableCellTemplate,x=x.replace(d.MODEL_COL_FIELD,f.row.getQualifiedColField(f.col));var b=f.col.colDef.editDropdownFilter?"|"+f.col.colDef.editDropdownFilter:"";x=x.replace(d.CUSTOM_FILTERS,b);var c="text";switch(f.col.colDef.type){case"boolean":c="checkbox";break;case"number":c="number";break;case"date":c="date"}x=x.replace("INPUT_TYPE",c);var h=f.col.colDef.editDropdownRowEntityOptionsArrayPath;f.editDropdownOptionsArray=h?w(f.row.entity,h):f.col.colDef.editDropdownOptionsArray,f.editDropdownIdLabel=f.col.colDef.editDropdownIdLabel?f.col.colDef.editDropdownIdLabel:"id",f.editDropdownValueLabel=f.col.colDef.editDropdownValueLabel?f.col.colDef.editDropdownValueLabel:"value";f.$apply(function(){C=!0,p();var b=angular.element(x);j.append(b),B=f.$new(),a(b)(B);var c=angular.element(j.children()[0]);D=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var i=f.col.grid.api.core.on.scrollEvent(f,function(){u(!0),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),i(),k(),l()
    +}),k=f.$on(e.events.END_CELL_EDIT,function(a,b){u(b),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),k(),i(),l()}),l=f.$on(e.events.CANCEL_CELL_EDIT,function(){v(),l(),i(),k()});f.$broadcast(e.events.BEGIN_CELL_EDIT),f.grid.api.edit.raise.beginCellEdit(f.row.entity,f.col.colDef)}}function u(a){if(C){var b=angular.element(j.children()[0]);B.$destroy(),angular.element(j.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&D&&b[0].focus(),D=!1,C=!1,m(),f.grid.api.core.notifyDataChange(d.dataChange.EDIT)}}function v(){C&&(z.assign(f,y),f.$apply(),f.grid.api.edit.raise.cancelCellEdit(f.row.entity,f.col.colDef),u(!0))}function w(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split(".");c.length;){var d=c.shift();if(!(d in a))return;a=a[d]}return a}if(f.col.colDef.enableCellEdit&&f.row.enableCellEdit!==!1){var x,y,z,A,B,C=!1,D=!1;m();try{var E=b.get("uiGridCellNavConstants");f.col.colDef.enableCellEditOnFocus&&f.$on(E.CELL_NAV_EVENT,function(a,b){b.row===f.row&&b.col===f.col?t():u()})}catch(F){}}}}}]),a.directive("uiGridEditor",["gridUtil","uiGridConstants","uiGridEditConstants",function(a,b,c){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(a,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),a.$on(c.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(b){a.stopEdit(b)})}),a.deepEdit=!1,a.stopEdit=function(b){a.inputForm&&!a.inputForm.$valid?(b.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT)):a.$emit(c.events.END_CELL_EDIT),a.deepEdit=!1},d.on("click",function(){a.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case b.keymap.ESC:d.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT);break;case b.keymap.ENTER:a.stopEdit(d);break;case b.keymap.TAB:a.stopEdit(d)}if(a.deepEdit)switch(d.keyCode){case b.keymap.LEFT:d.stopPropagation();break;case b.keymap.RIGHT:d.stopPropagation();break;case b.keymap.UP:d.stopPropagation();break;case b.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("uiGridEditor",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{priority:-100,require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.expandable={},c.expandable.expandedAll=!1,c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.expandableRowHeaderWidth=c.options.expandableRowHeaderWidth||40,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)},toggleAllRows:function(){b.toggleAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.isExpanded?b.height=b.grid.options.rowHeight+a.options.expandableRowHeight:(b.height=b.grid.options.rowHeight,a.expandable.expandedAll=!1),a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!0,a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!1,a.refresh()},toggleAllRows:function(a){a.expandable.expandedAll?b.collapseAllRows(a):b.expandAllRows(a)}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",displayName:"",exporterSuppressExport:!0,enableColumnResizing:!1,enableColumnMenu:!1,width:f.grid.options.expandableRowHeaderWidth||40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),g.headerCellTemplate=b.get("ui-grid/expandableTopRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGrid",["uiGridExpandableService","$templateCache",function(){return{replace:!0,priority:1e3,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,c,d){d.grid.api.core.on.renderingComplete(a,function(){a.row&&a.row.grid&&a.row.grid.options&&a.row.grid.options.enableExpandable&&(d.grid.parentRow=a.row)})},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",BUTTON_LABEL:"BUTTON_LABEL",FILE_NAME:"FILE_NAME"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c){h.csvExport(a,b,c)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterCsvFilename=a.exporterCsvFilename?a.exporterCsvFilename:"download.csv",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterHeaderFilterUseName=a.exporterHeaderFilterUseName===!0,a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.formatAsCsv(d,e,a.options.exporterCsvColumnSeparator);this.downloadFile(a.options.exporterCsvFilename,f)},getColumnHeaders:function(a,c){var d=[];return angular.forEach(a.columns,function(e){!e.visible&&c!==b.ALL||e.colDef.exporterSuppressExport===!0||-1!==a.options.exporterSuppressColumns.indexOf(e.name)||d.push({name:e.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(a.options.exporterHeaderFilterUseName?e.name:e.displayName):e.displayName,width:e.drawnWidth?e.drawnWidth:e.width,align:"number"===e.colDef.type?"right":"left"})}),d},getData:function(a,c,e){var f,g=[];switch(c){case b.ALL:f=a.rows;break;case b.VISIBLE:f=a.getVisibleRows();break;case b.SELECTED:a.api.selection?f=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(f,function(c){if(c.exporterEnableExporting!==!1){var d=[];angular.forEach(a.columns,function(f){if((f.visible||e===b.ALL)&&f.colDef.exporterSuppressExport!==!0&&-1===a.options.exporterSuppressColumns.indexOf(f.name)){var g={value:a.options.exporterFieldCallback(a,c,f,a.getCellValue(c,f))};f.colDef.exporterPdfAlign&&(g.alignment=f.colDef.exporterPdfAlign),d.push(g)}}),g.push(d)}}),g},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},downloadFile:function(a,b){var c,d=document,e=d.createElement("a"),f="application/octet-stream;charset=utf-8";if(navigator.msSaveBlob)return navigator.msSaveBlob(new Blob(["",b],{type:f}),a);if("download"in e){var g=new Blob([b],{type:f});c=URL.createObjectURL(g),e.setAttribute("download",a)}else c="data:"+f+","+encodeURIComponent(b),e.setAttribute("target","_blank");e.href=c,e.setAttribute("style","display:none;"),d.body.appendChild(e),setTimeout(function(){if(e.click)e.click();else if(document.createEvent){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0),e.dispatchEvent(a)}d.body.removeChild(e)},100)},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&(h.header=a.options.exporterPdfHeader),a.options.exporterPdfFooter&&(h.footer=a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a){i.importThisFile(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(c),d()},[b.dataChange.ROW]);a.importer.$scope.$on("$destroy",d)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){var c=a.srcElement||a.target;if(c&&c.files&&1===c.files.length){var d=c.files[0];b.importThisFile(i,d),c.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.grid.api.core.on.scrollEvent(a,function(b){if(b.y){var d=100-100*b.y.percentage;c.checkScroll(a.grid,d)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout","$log","ScrollEvent","uiGridConstants",function(a,b,c,d,e){var f={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){var e=a.columns;if(!angular.isNumber(c)||!angular.isNumber(d))return void console.log("Please provide valid values for originalPosition and finalPosition");for(var f=0,g=0;g<e.length;g++)(angular.isDefined(e[g].colDef.visible)&&e[g].colDef.visible===!1||e[g].isRowHeader===!0)&&f++;if(c>=e.length-f||d>=e.length-f)return void console.log("Invalid values for originalPosition, finalPosition");var h=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};b.redrawColumnAtPosition(a,h(c),h(d))}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var f=a.columns,g=f[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)f[h]=f[h-1];else if(d>c)for(var i=c;d>i;i++)f[i]=f[i+1];f[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d),a.api.core.notifyDataChange(e.dataChange.COLUMN)})}}};return f}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,h,i){a.col.colDef.enableColumnMoving&&a.$on(f.events.COLUMN_HEADER_CLICK,function(f,h){if(h.columnName===a.col.colDef.name&&!a.col.renderContainer){var j=h.event;if("ui-grid-icon-angle-down"!==j.target.className&&"I"!==j.target.tagName&&j.target.className.indexOf("ui-grid-filter-input")<0){var k,l,m=a.grid.element[0].getBoundingClientRect().left,n=j.pageX,o=0,p=m+a.grid.getViewportWidth(),q=!1,r=function(){q=!0,k=e.clone(),e.parent().append(k),k.addClass("movingColumn");var b={},c=e[0].getBoundingClientRect().left;b.left=c-m+"px";var d=a.grid.element[0].getBoundingClientRect().right,f=e[0].getBoundingClientRect().right;f>d&&(l=a.col.drawnWidth+(d-f),b.width=l+"px"),k.css(b)},s=function(c){i.fireEvent("hide-menu");for(var d=a.grid.columns,e=0,f=0;f<d.length;f++)(angular.isUndefined(d[f].colDef.visible)||d[f].colDef.visible===!0)&&(e+=d[f].drawnWidth||d[f].width||d[f].colDef.width);var h,j=k[0].getBoundingClientRect().left-1,n=k[0].getBoundingClientRect().right;if(h="ie"===b.detectBrowser()?j+c:j-m+c,h=p>h?h:p,(j>=m||c>0)&&(p>=n||0>c))k.css({visibility:"visible",left:h+"px"});else if(e>Math.ceil(i.grid.gridWidth)){c*=8;var q=new g(a.col.grid,null,null,"uiGridHeaderCell.moveElement");q.x={pixels:c},q.fireScrollingEvent()}for(var r=0,s=0;s<d.length;s++)if(angular.isUndefined(d[s].colDef.visible)||d[s].colDef.visible===!0){if(d[s].colDef.name===a.col.colDef.name)break;r+=d[s].drawnWidth||d[s].width||d[s].colDef.width}void 0===a.newScrollLeft?o+=c:o=a.newScrollLeft+h-r,l<a.col.drawnWidth&&(l+=Math.abs(c),k.css({width:l+"px"}))},t=function(a){document.onselectstart=function(){return!1};var b=a.pageX-n;!q&&Math.abs(b)>50?r():q&&(s(b),n=a.pageX)};d.on("mousemove",t);var u=function(){document.onselectstart=null,k&&k.remove();for(var b=a.grid.columns,e=0,f=0;f<b.length&&b[f].colDef.name!==a.col.colDef.name;f++)e++;if(0>o){for(var g=0,h=e-1;h>=0;h--)if((angular.isUndefined(b[h].colDef.visible)||b[h].colDef.visible===!0)&&(g+=b[h].drawnWidth||b[h].width||b[h].colDef.width,g>Math.abs(o))){c.redrawColumnAtPosition(a.grid,e,h+1);break}g<Math.abs(o)&&c.redrawColumnAtPosition(a.grid,e,0)}else if(o>0){for(var i=0,j=e+1;j<b.length;j++)if((angular.isUndefined(b[j].colDef.visible)||b[j].colDef.visible===!0)&&(i+=b[j].drawnWidth||b[j].width||b[j].colDef.width,i>o)){c.redrawColumnAtPosition(a.grid,e,j-1);break}o>i&&c.redrawColumnAtPosition(a.grid,e,b.length-1)}d.off("mousemove",t),d.off("mouseup",u)};d.on("mouseup",u)}}})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ng","ui.grid"]);a.service("uiGridPaginationService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{pagination:{paginationChanged:function(){}}},methods:{pagination:{getPage:function(){return a.options.enablePagination?a.options.paginationCurrentPage:null},getTotalPages:function(){return a.options.enablePagination?0===a.options.totalItems?1:Math.ceil(a.options.totalItems/a.options.paginationPageSize):null},nextPage:function(){a.options.enablePagination&&(a.options.totalItems>0?a.options.paginationCurrentPage=Math.min(a.options.paginationCurrentPage+1,c.methods.pagination.getTotalPages()):a.options.paginationCurrentPage++)},previousPage:function(){a.options.enablePagination&&(a.options.paginationCurrentPage=Math.max(a.options.paginationCurrentPage-1,1))},seek:function(b){if(a.options.enablePagination){if(!angular.isNumber(b)||1>b)throw"Invalid page number: "+b;a.options.paginationCurrentPage=Math.min(b,c.methods.pagination.getTotalPages())}}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPagination||!a.options.enablePagination)return b;var c=parseInt(a.options.paginationPageSize,10),d=parseInt(a.options.paginationCurrentPage,10),e=b.filter(function(a){return a.visible});a.options.totalItems=e.length;var f=(d-1)*c;return f>e.length&&(d=a.options.paginationCurrentPage=1,f=(d-1)*c),e.slice(f,f+c)})},defaultGridOptions:function(b){b.enablePagination=b.enablePagination!==!1,b.enablePaginationControls=b.enablePaginationControls!==!1,b.useExternalPagination=b.useExternalPagination===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.paginationPageSizes)&&(b.paginationPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.paginationPageSize)&&(b.paginationPageSize=b.paginationPageSizes.length>0?b.paginationPageSizes[0]:0),a.isNullOrUndefined(b.paginationCurrentPage)&&(b.paginationCurrentPage=1),a.isNullOrUndefined(b.paginationTemplate)&&(b.paginationTemplate="ui-grid/pagination")},onPaginationChanged:function(a,b,c){a.api.pagination.raise.paginationChanged(b,c),a.options.useExternalPagination||a.refresh()}};return b}]),a.directive("uiGridPagination",["gridUtil","uiGridPaginationService",function(a,b){return{priority:-200,scope:!1,require:"uiGrid",link:{pre:function(c,d,e,f){b.initializeGrid(f.grid),a.getTemplate(f.grid.options.paginationTemplate).then(function(a){var b=angular.element(a);d.append(b),f.innerCompile(b)})}}}}]),a.directive("uiGridPager",["uiGridPaginationService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.paginationApi=h.grid.api.pagination,e.sizesLabel=d.getSafeText("pagination.sizes"),e.totalItemsLabel=d.getSafeText("pagination.totalItems");var i=h.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a});var j=h.grid.registerDataChangeCallback(function(a){a.options.useExternalPagination||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);e.$on("$destroy",j);var k=function(){e.showingLow=(i.paginationCurrentPage-1)*i.paginationPageSize+1,e.showingHigh=Math.min(i.paginationCurrentPage*i.paginationPageSize,i.totalItems)},l=e.$watch("grid.options.totalItems + grid.options.paginationPageSize",k),m=e.$watch("grid.options.paginationCurrentPage + grid.options.paginationPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.paginationCurrentPage)||i.paginationCurrentPage<1)return void(i.paginationCurrentPage=1);if(i.totalItems>0&&i.paginationCurrentPage>e.paginationApi.getTotalPages())return void(i.paginationCurrentPage=e.paginationApi.getTotalPages());
    +k(),a.onPaginationChanged(e.grid,i.paginationCurrentPage,i.paginationPageSize)}});e.$on("$destroy",function(){l(),m()}),e.cantPageForward=function(){return i.totalItems>0?i.paginationCurrentPage>=e.paginationApi.getTotalPages():i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.paginationCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})},findTargetCol:function(a,b,c){var d=a.getRenderContainer();if("left"===b){var e=d.visibleColumnCache.indexOf(a);return d.visibleColumnCache[e-1*c]}return a}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q","uiGridResizeColumnsService","uiGridConstants","$timeout",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,d,h,i){var j=i.grid;if(j.options.enableColumnResizing){var k=b.get("ui-grid/columnResizer"),l=1;j.isRTL()&&(a.position="left",l=-1);var m=function(){for(var b=d[0].getElementsByClassName("ui-grid-column-resizer"),f=0;f<b.length;f++)angular.element(b[f]).remove();var g=e.findTargetCol(a.col,"left",l),h=a.col.getRenderContainer();if(g&&0!==h.visibleColumnCache.indexOf(a.col)&&g.colDef.enableColumnResizing!==!1){var i=angular.element(k).clone();i.attr("position","left"),d.prepend(i),c(i)(a)}if(a.col.colDef.enableColumnResizing!==!1){var j=angular.element(k).clone();j.attr("position","right"),d.append(j),c(j)(a)}};m();var n=function(){g(m)},o=j.registerDataChangeCallback(n,[f.dataChange.COLUMN]);a.$on("$destroy",o)}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","uiGridResizeColumnsService",function(a,b,c,d){var e,f,g,h=angular.element('<div class="ui-grid-resize-overlay"></div>');b.isTouchEnabled()?(e="touchstart",f="touchend",g="touchmove"):(e="mousedown",f="mouseup",g="mousemove");var i={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(i,j,k,l){function m(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function n(){l.grid.buildColumns().then(function(){l.grid.refreshCanvas(!0).then(function(){l.grid.refresh()})})}function o(a,b){var c=b;return a.colDef.minWidth&&c<a.colDef.minWidth?c=a.colDef.minWidth:a.colDef.maxWidth&&c>a.colDef.maxWidth&&(c=a.colDef.maxWidth),c}function p(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),s=(a.targetTouches?a.targetTouches[0]:a).clientX-t,0>s?s=0:s>l.grid.gridWidth&&(s=l.grid.gridWidth);var b=d.findTargetCol(i.col,i.position,u);if(b.colDef.enableColumnResizing!==!1){l.grid.element.hasClass("column-resizing")||l.grid.element.addClass("column-resizing");var e=s-r,f=parseInt(b.drawnWidth+e*u,10);s+=(o(b,f)-f)*u,h.css({left:s+"px"}),l.fireEvent(c.events.ITEM_DRAGGING)}}function q(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),l.grid.element.removeClass("column-resizing"),h.remove(),s=(b.changedTouches?b.changedTouches[0]:b).clientX-t;var c=s-r;if(0===c)return a.off(f,q),void a.off(g,p);var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var j=parseInt(e.drawnWidth+c*u,10);e.width=o(e,j),m(e),n(c),d.fireColumnSizeChanged(l.grid,e.colDef,c),a.off(f,q),a.off(g,p)}}var r=0,s=0,t=0,u=1;l.grid.isRTL()&&(i.position="left",u=-1),"left"===i.position?j.addClass("left"):"right"===i.position&&j.addClass("right"),j.on(e,function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),t=l.grid.element[0].getBoundingClientRect().left,r=(b.targetTouches?b.targetTouches[0]:b).clientX-t,l.grid.element.append(h),h.css({left:r}),a.on(f,q),a.on(g,p)}),j.on("dblclick",function(a){a.stopPropagation();var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var f=0,g=0,h=b.closestElm(j,".ui-grid-render-container"),k=h.querySelectorAll("."+c.COL_CLASS_PREFIX+e.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(k,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var h=b.elementWidth(c);e+=h}e>f&&(f=e,g=f-e)})}),e.width=o(e,f),m(e),n(g),d.fireColumnSizeChanged(l.grid,e.colDef,g)}}),j.on("$destroy",function(){j.off(e),j.off("dblclick"),a.off(g,p),a.off(f,q)})}};return i}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,c){f.setSavePromise(b,a,c)},getDirtyRows:function(){return b.rowEdit.dirtyRows?b.rowEdit.dirtyRows:[]},getErrorRows:function(){return b.rowEdit.errorRows?b.rowEdit.errorRows:[]},flushDirtyRows:function(){return f.flushDirtyRows(b)},setRowsDirty:function(a){f.setRowsDirty(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.saveState",["ui.grid","ui.grid.selection","ui.grid.cellNav"]);a.constant("uiGridSaveStateConstants",{featureName:"saveState"}),a.service("uiGridSaveStateService",["$q","uiGridSaveStateConstants","gridUtil","$compile","$interval","uiGridConstants",function(){var a={initializeGrid:function(b){b.saveState={},this.defaultGridOptions(b.options);var c={events:{saveState:{}},methods:{saveState:{save:function(){return a.save(b)},restore:function(c,d){a.restore(b,c,d)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.saveWidths=a.saveWidths!==!1,a.saveOrder=a.saveOrder!==!1,a.saveScroll=a.saveScroll===!0,a.saveFocus=a.saveScroll!==!0&&a.saveFocus!==!1,a.saveVisible=a.saveVisible!==!1,a.saveSort=a.saveSort!==!1,a.saveFilter=a.saveFilter!==!1,a.saveSelection=a.saveSelection!==!1},save:function(b){var c={};return c.columns=a.saveColumns(b),c.scrollFocus=a.saveScrollFocus(b),c.selection=a.saveSelection(b),c},restore:function(b,c,d){d.columns&&a.restoreColumns(b,d.columns),d.scrollFocus&&a.restoreScrollFocus(b,c,d.scrollFocus),d.selection&&a.restoreSelection(b,d.selection),b.refresh()},saveColumns:function(a){var b=[];return angular.forEach(a.columns,function(a){var c={};c.name=a.name,c.visible=a.visible,c.width=a.width,c.sort=angular.copy(a.sort),c.filters=angular.copy(a.filters),b.push(c)}),b},saveScrollFocus:function(b){if(!b.api.cellNav)return{};var c={};if(b.options.saveFocus){c.focus=!0;var d=b.api.cellNav.getFocusedCell();null!==d&&(c.colName=d.col.colDef.name,c.rowVal=a.getRowVal(b,d.row))}else b.options.saveScroll&&(c.focus=!1,b.renderContainers.body.prevRowScrollIndex&&(c.rowVal=a.getRowVal(b,b.renderContainers.body.visibleRowCache[b.renderContainers.body.prevRowScrollIndex])),b.renderContainers.body.prevColScrollIndex&&(c.colName=b.renderContainers.body.visibleColumnCache[b.renderContainers.body.prevColScrollIndex].name));return c},saveSelection:function(b){if(!b.api.selection)return{};var c=b.api.selection.getSelectedGridRows().map(function(c){return a.getRowVal(b,c)});return c},getRowVal:function(a,b){if(!b)return null;var c={};return a.options.saveRowIdentity?(c.identity=!0,c.row=a.options.saveRowIdentity(b.entity)):(c.identity=!1,c.row=a.renderContainers.body.visibleRowCache.indexOf(b)),c},restoreColumns:function(a,b){angular.forEach(b,function(b,c){var d=a.columns.filter(function(a){return a.name===b.name});if(d.length>0){var e=a.columns.indexOf(d[0]);if(a.columns[e].visible=b.visible,a.columns[e].colDef.visible=b.visible,a.columns[e].width=b.width,a.columns[e].sort=angular.copy(b.sort),a.columns[e].filters=angular.copy(b.filters),e!==c){var f=a.columns.splice(e,1)[0];a.columns.splice(c,0,f)}}})},restoreScrollFocus:function(b,c,d){if(b.api.cellNav){var e,f;if(d.colName){var g=b.options.columnDefs.filter(function(a){return a.name===d.colName});g.length>0&&(e=g[0])}d.rowVal&&d.rowVal.row&&(f=d.rowVal.identity?a.findRowByIdentity(b,d.rowVal):b.renderContainers.body.visibleRowCache[d.rowVal.row]);var h=f&&f.entity?f.entity:null;(e||h)&&(d.focus?b.api.cellNav.scrollToFocus(c,h,e):b.api.cellNav.scrollTo(c,h,e))}},restoreSelection:function(b,c){b.api.selection&&(b.api.selection.clearSelectedRows(),angular.forEach(c,function(c){if(c.identity){var d=a.findRowByIdentity(b,c);d&&b.api.selection.selectRow(d.entity)}else b.api.selection.selectRowByVisibleIndex(c.row)}))},findRowByIdentity:function(a,b){if(!a.options.saveRowIdentity)return null;var c=a.rows.filter(function(c){return a.options.saveRowIdentity(c.entity)===b.row?!0:!1});return c.length>0?c[0]:null}};return a}]),a.directive("uiGridSaveState",["uiGridSaveStateConstants","uiGridSaveStateService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),angular.module("ui.grid").config(["$provide",function(a){a.decorator("GridRow",["$delegate",function(a){return a.prototype.setSelected=function(a){this.isSelected=a,a?this.grid.selection.selectedCount++:this.grid.selection.selectedCount--},a}])}]),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,b.selection.selectedCount=0,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c,d){var e=b.getRow(c);null!==e&&e.enableSelection!==!1&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c,d){var e=b.getRow(c);null===e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c,d){var e=b.renderContainers.body.visibleRowCache[c];null===e||"undefined"==typeof e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c,d){var e=b.getRow(c);null!==e&&e.isSelected&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},selectAllVisibleRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.visible?e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c)):e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},clearSelectedRows:function(c){a.clearSelectedRows(b,c)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30,a.enableFooterTotalSelected=a.enableFooterTotalSelected!==!1,a.isRowSelectable=angular.isDefined(a.isRowSelectable)?a.isRowSelectable:angular.noop},toggleRowSelection:function(b,c,d,e,f){var g=c.isSelected;if(e||g){if(!e&&g){var h=a.getSelectedRows(b);h.length>1&&(g=!1,a.clearSelectedRows(b,d))}}else a.clearSelectedRows(b,d);g&&f||c.enableSelection!==!1&&(c.setSelected(!g),c.isSelected===!0?b.selection.lastSelectedRow=c:b.selection.selectAll=!1,b.api.selection.raise.rowSelectionChanged(c,d))},shiftSelect:function(b,c,d,e){if(e){var f=a.getSelectedRows(b),g=f.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,h=b.renderContainers.body.visibleRowCache.indexOf(c);if(g>h){var i=g;g=h,h=i}for(var j=[],k=g;h>=k;k++){var l=b.renderContainers.body.visibleRowCache[k];l&&(l.isSelected||l.enableSelection===!1||(l.setSelected(!0),b.selection.lastSelectedRow=l,a.decideRaiseSelectionEvent(b,l,j,d)))}a.decideRaiseSelectionBatchEvent(b,j,d)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b,c){var d=[];a.getSelectedRows(b).forEach(function(e){e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!1},decideRaiseSelectionEvent:function(a,b,c,d){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b,d)},decideRaiseSelectionBatchEvent:function(a,b,c){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b,c)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,minWidth:10,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1,exporterSuppressExport:!0};f.grid.addRowHeaderColumn(g)}f.grid.options.isRowSelectable!==angular.noop&&f.grid.registerRowBuilder(function(a){a.enableSelection=f.grid.options.isRowSelectable(a)})},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,c,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,c,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,c,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(a,d){c.selection.selectAll?(b.clearSelectedRows(c,d),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0,d),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(d),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,c){function d(){a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(c.addClass("ui-grid-disable-selection"),c.on("touchstart",j),c.on("touchend",k),c.on("click",i),a.registered=!0)}function e(){a.registered&&(c.removeClass("ui-grid-disable-selection"),c.off("touchstart",j),c.off("touchend",k),c.off("click",i),a.registered=!1)}var g=0,h=300,i=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,b,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()},j=function(){g=(new Date).getTime()},k=function(a){var b=(new Date).getTime(),c=b-g;h>c&&i(a)};d();var l=a.grid.registerDataChangeCallback(function(){!a.grid.options.enableRowSelection||a.grid.options.enableRowHeaderSelection||a.registered?a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection||!a.registered||e():d()},[b.dataChange.OPTIONS]);c.on("$destroy",l)}}}]),a.directive("uiGridGridFooter",["$compile","uiGridConstants","gridUtil",function(a,b,c){return{restrict:"EA",replace:!0,priority:-1e3,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(b,d,e,f){f.grid.options.showGridFooter&&c.getTemplate("ui-grid/gridFooterSelectedItems").then(function(c){var e=angular.element(c),f=a(e)(b);angular.element(d[0].getElementsByClassName("ui-grid-grid-footer")[0]).append(f)})},post:function(){}}}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel ui-grid-footer-aggregates-row"><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell ui-grid-clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-grid-footer",'<div class="ui-grid-footer-info ui-grid-grid-footer"><span>{{\'search.totalItems\' | t}} {{grid.rows.length}}</span> <span ng-if="grid.renderContainers.body.visibleRowCache.length !== grid.rows.length" class="ngLabel">({{"search.showingItems" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell ui-grid-clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    /*\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n    */\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div><div ui-grid-grid-footer ng-if="grid.options.showGridFooter"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showColumnFooter"></div><!-- native scrolling --><!--<div ui-grid-native-scrollbar ng-if="enableVerticalScrollbar" type="vertical"></div>--><!--<div ui-grid-native-scrollbar ng-if="enableHorizontalScrollbar" type="horizontal"></div>--></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport" ng-style="containerCtrl.colContainer.getViewPortStyle()"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="INPUT_TYPE" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth()) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/expandableTopRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !grid.expandable.expandedAll, \'ui-grid-icon-minus-squared\' : grid.expandable.expandedAll }" ng-click="grid.api.expandable.toggleAllRows()"></i></div></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT" download="FILE_NAME">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/pagination",'<div class="ui-grid-pager-panel" ui-grid-pager ng-show="grid.options.enablePaginationControls"><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="paginationApi.seek(1)" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="paginationApi.previousPage()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.paginationCurrentPage" min="1" max="{{ paginationApi.getTotalPages() }}" required> <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span> <button type="button" ng-click="paginationApi.nextPage()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="paginationApi.seek(paginationApi.getTotalPages())" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/gridFooterSelectedItems",'<span ng-if="grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected">({{"search.selectedItems" | t}} {{grid.selection.selectedCount}})</span>'),a.put("ui-grid/selectionHeaderCell",'<div><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.svg b/release/3.0.0-RC.18-8fe4e49/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-RC.18-8fe4e49/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.ttf b/release/3.0.0-RC.18-8fe4e49/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-RC.18-8fe4e49/ui-grid.ttf differ
    diff --git a/release/3.0.0-RC.18-8fe4e49/ui-grid.woff b/release/3.0.0-RC.18-8fe4e49/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-RC.18-8fe4e49/ui-grid.woff differ
    diff --git a/release/3.0.0-RC.18/ui-grid.css b/release/3.0.0-RC.18/ui-grid.css
    new file mode 100644
    index 000000000..f6c622ab2
    --- /dev/null
    +++ b/release/3.0.0-RC.18/ui-grid.css
    @@ -0,0 +1,1357 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: fixed;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir="rtl"] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir="rtl"] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > div.ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-RC.18/ui-grid.eot b/release/3.0.0-RC.18/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-RC.18/ui-grid.eot differ
    diff --git a/release/3.0.0-RC.18/ui-grid.js b/release/3.0.0-RC.18/ui-grid.js
    new file mode 100644
    index 000000000..429c478bb
    --- /dev/null
    +++ b/release/3.0.0-RC.18/ui-grid.js
    @@ -0,0 +1,18114 @@
    +/*! ui-grid - v3.0.0-RC.18 - 2014-12-09
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1,
    +      WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          var deregisterFunction = function() {
    +           $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.headerCellClass) {
    +              updateClass();
    +            }
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            var deregisterFunction = function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            };
    +
    +            $scope.$on( '$destroy', deregisterFunction );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ( $scope.sortable || $scope.colMenu ){
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +              $contentsElm.on('mousedown touchstart', function(event) {
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +              });
    +      
    +              $contentsElm.on('mouseup touchend', function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });              
    +            }
    +
    +
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh()
    +                      .then(function () {
    +                        if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                           uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                        }
    +                        // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                      });
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', function( gridUtil, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = grid.verticalScrollbarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = grid.horizontalScrollbarHeight;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          //var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // gridUtil.logDebug('headerHeight in scrollbar', headerHeight);
    +
    +          var ondemand  = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-y:auto;" : "";
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px;' +ondemand +'}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          var bottom = gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          
    +          var adjustment = colContainer.getViewportAdjustment();
    +          bottom -= adjustment.height;
    +          
    +          var ondemand = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-x:auto" : "";
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px;' +ondemand + ' }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // gridUtil.logDebug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil',
    +    function(gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.options.showFooter ? grid.options.footerRowHeight : 0;
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +    self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +  
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +  
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +    }, 300);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +    }, 300);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {Grid} grid the grid
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN ).  Optional and defaults to
    +   * ALL 
    +   * @returns {string} uid of the callback, can be used to deregister it again
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types };
    +    return uid;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name deregisterDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description Delete the callback identified by the id.
    +   * @param {string} uid the uid of the function that is to be deregistered
    +   */
    +  Grid.prototype.deregisterDataChangeCallback = function deregisterDataChangeCallback(uid) {
    +    delete this.dataChangeCallbacks[uid];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, and COLUMN callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        callback.callback( this );
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {Grid} grid the grid
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(grid, type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ){
    +      grid.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +        if (wasEmpty) {
    +           self.assignTypes();
    +        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...'
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...'
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...'
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +    
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +      
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleRowCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleRowCount = baseOptions.maxVisibleRowCount || 200;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       *
    +       */
    +      baseOptions.showFooter = baseOptions.showFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name footerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer in pixels
    +       *
    +       */
    +      baseOptions.footerRowHeight = typeof(baseOptions.footerRowHeight) !== "undefined" ? baseOptions.footerRowHeight : 30;
    +  
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', function(gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if ( !filter.noTerm && (term === null || term === undefined || term === '')) {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        paging: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        paging: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so 
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         * 
    +         * To get to row 9 (i.e. the last row) in the same list, we want to 
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll, 
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            args.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          // Alias the visible row and column caches 
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          if (grid.horizontalScrollbarHeight) {
    +            bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          }
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + grid.gridWidth;
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          if (grid.verticalScrollbarWidth) {
    +            rightBound = rightBound - grid.verticalScrollbarWidth;
    +          }
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +            
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              args.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              args.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +            
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              args.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              args.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol) {
    +                var row = rowCol.row,
    +                    col = rowCol.col;
    +
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, $scope, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                  renderContainerCtrl = controllers[1],
    +                  cellNavController = controllers[2];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!cellNavController) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                $timeout(function () {
    +                  $timeout(function () {
    +                    // Get the last row+col combo
    +                    var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +
    +                    // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                    //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                    //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                    if ($document.activeElement === $document.body) {
    +                      $elm[0].focus();
    +                    }
    +
    +                    // Re-broadcast a cellNav event so we re-focus the right cell
    +                    uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                  });
    +                });
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: ['^uiGrid', '?^uiGridCellnav'],
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              cellNavController = controllers[1];
    +
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!cellNavController) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +          
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col));
    +
    +            evt.stopPropagation();
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                $compile(cellElement)($scope.$new());
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( $scope.grid, uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight; 
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions.columnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + displayName; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            gridUtil.logError( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? grid.options.exporterHeaderFilter(gridCol.displayName) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:GridOptions.columnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            var extractedRow = [];
    +            angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                if ( gridCol.colDef.exporterPdfAlign ) {
    +                  extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                }
    +                extractedRow.push(extractedField);
    +              }
    +            });
    +            
    +            data.push(extractedRow);
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +
    +              var template = angular.element(contents);
    +
    +              template.children("a").html(
    +                  template.children("a").html().replace(
    +                      uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel));
    +
    +              template.children("a").attr("href", 
    +                  template.children("a").attr("href").replace(
    +                      uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent)));
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.content.unshift( grid.options.exporterPdfHeader );
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.content.push( grid.options.exporterPdfFooter );
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {Grid} grid the grid we're importing into
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( grid, fileObject ) {
    +                  service.importFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and ift he rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var callbackId = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( grid, newObjects );
    +              grid.deregisterDataChangeCallback( callbackId );
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            var deregisterClosure = function() {
    +              grid.deregisterDataChangeCallback( callbackId );
    +            };
    +  
    +            grid.importer.$scope.$on( '$destroy', deregisterClosure );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            if (event.srcElement.files.length === 1) {
    +              var fileObject = event.srcElement.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              event.srcElement.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', function ($q, $timeout, $log) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.on.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                self.redrawColumnAtPosition(grid, originalPosition, finalPosition);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +        var columns = grid.columns;
    +
    +        //Function to find column position for a render index, ths is needed to take care of
    +        // invisible columns and row headers
    +        var findPositionForRenderIndex = function (index) {
    +          var position = index;
    +          for (var i = 0; i <= position; i++) {
    +            if (angular.isDefined(columns[i]) && angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) {
    +              position++;
    +            }
    +          }
    +          return position;
    +        };
    +
    +        originalPosition = findPositionForRenderIndex(originalPosition);
    +        newPosition = findPositionForRenderIndex(newPosition);
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and coned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                var mouseDownHandler = function (evt) {
    +                  if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                    //Setting some variables required for calculations.
    +                    var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                    var previousMouseX = evt.pageX;
    +                    var totalMouseMovement = 0;
    +                    var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth() - $scope.grid.verticalScrollbarWidth;
    +
    +                    //Clone element should move horizontally with mouse.
    +                    var elmCloned = false;
    +                    var movingElm;
    +                    var reducedWidth;
    +
    +                    var cloneElement = function() {
    +                      elmCloned = true;
    +
    +                      //Cloning header cell and appending to current header cell.
    +                      movingElm = $elm.clone();
    +                      $elm.append(movingElm);
    +
    +                      //Left of cloned element should be aligned to original header cell.
    +                      movingElm.addClass('movingColumn');
    +                      var movingElementStyles = {};
    +                      var elmLeft = $elm[0].getBoundingClientRect().left;
    +                      movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                      var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                      var elmRight = $elm[0].getBoundingClientRect().right;
    +                      if (elmRight > gridRight) {
    +                        reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                        movingElementStyles.width = reducedWidth + 'px';
    +                      }
    +                      movingElm.css(movingElementStyles);
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    };
    +
    +                    var moveElement = function(changeValue) {
    +                      //Hide column menu
    +                      uiGridCtrl.fireEvent('hide-menu');
    +
    +                      //Calculate new position of left of column
    +                      var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                      var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                      var newElementLeft;
    +                      if (gridUtil.detectBrowser() === 'ie') {
    +                        newElementLeft = currentElmLeft + changeValue;
    +                      }
    +                      else {
    +                        newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                      }
    +                      newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                      //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                      if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                        movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                      }
    +                      else {
    +                        changeValue *= 5;
    +                        uiGridCtrl.fireScrollingEvent({ x: { pixels: changeValue * 2.5} });
    +                      }
    +                      totalMouseMovement += changeValue;
    +
    +                      //Increase width of moving column, in case the rightmost column was moved and its width was
    +                      //decreased because of overflow
    +                      if (reducedWidth < $scope.col.drawnWidth) {
    +                        reducedWidth += Math.abs(changeValue);
    +                        movingElm.css({'width': reducedWidth + 'px'});
    +                      }
    +                    };
    +
    +                    var mouseMoveHandler = function (evt) {
    +                      var changeValue = evt.pageX - previousMouseX;
    +                      if (!elmCloned && Math.abs(changeValue) > 50) {
    +                        cloneElement();
    +                      }
    +                      else if (elmCloned) {
    +                       moveElement(changeValue);
    +                       previousMouseX = evt.pageX;
    +                      }
    +                    };
    +
    +                    // On scope destroy, remove the mouse event handlers from the document body
    +                    $scope.$on('$destroy', function () {
    +                      $document.off('mousemove', mouseMoveHandler);
    +                      $document.off('mouseup', mouseUpHandler);
    +                    });
    +                    $document.on('mousemove', mouseMoveHandler);
    +
    +                    var mouseUpHandler = function (evt) {
    +                      var renderIndexDefer = $q.defer();
    +
    +                      var renderIndex;
    +                      $attrs.$observe('renderIndex', function (n, o) {
    +                        renderIndex = $scope.$eval(n);
    +                        renderIndexDefer.resolve();
    +                      });
    +
    +                      renderIndexDefer.promise.then(function () {
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var renderedColumns = $scope.grid.renderContainers['body'].renderedColumns;
    +
    +                        //This method will calculate the number of columns hidden in lift due to scroll
    +                        //renderContainer.prevColumnScrollIndex could also have been used but this is more accurate
    +                        var scrolledColumnCount = 0;
    +                        var columns = $scope.grid.columns;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.visible && columns[i].colDef.name !== renderedColumns[0].colDef.name) {
    +                            scrolledColumnCount++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = renderIndex - 1; il >= 0; il--) {
    +                            totalColumnsLeftWidth += renderedColumns[il].drawnWidth;
    +                            if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + il + 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + 0);
    +                          }
    +                        }
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = renderIndex + 1; ir < renderedColumns.length; ir++) {
    +                            totalColumnsRightWidth += renderedColumns[ir].drawnWidth;
    +                            if (totalColumnsRightWidth > totalMouseMovement) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + ir - 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + renderedColumns.length - 1);
    +                          }
    +                        }
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      });
    +                    };
    +
    +                  }
    +                };
    +                $elm.on('mousedown', mouseDownHandler);
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', function () {
    +    var service = {
    +
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +        grid.pagination = {page: 1, totalPages: 1};
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.pagination.api:PublicAPI
    +         *
    +         * @description Public API for the pagination feature
    +         */
    +        var publicApi = {
    +          methods: {
    +            pagination: {
    +              /**
    +               * @ngdoc method
    +               * @name getPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the number of the current page
    +               */
    +              getPage: function () {
    +                return grid.pagination.page;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name getTotalPages
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the total number of pages
    +               */
    +              getTotalPages: function () {
    +                return grid.pagination.totalPages;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name nextPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the next page, if possible
    +               */
    +              nextPage: function () {
    +                grid.pagination.page++;
    +                grid.refresh();
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name previousPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the previous page, if we're not on the first page
    +               */
    +              previousPage: function () {
    +                grid.pagination.page = Math.max(1, grid.pagination.page - 1);
    +                grid.refresh();
    +              },
    +              seek: function (page) {
    +                if (!angular.isNumber(page) || page < 1) {
    +                  throw 'Invalid page number: ' + page;
    +                }
    +
    +                grid.pagination.page = page;
    +                grid.refresh();
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +        grid.registerRowsProcessor(function (renderableRows) {
    +          if (!grid.options.enablePagination) {
    +            return renderableRows;
    +          }
    +          grid.pagination.totalPages = Math.max(
    +            1,
    +            Math.ceil(renderableRows.length / grid.options.rowsPerPage)
    +          );
    +
    +          var firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          if (firstRow >= renderableRows.length) {
    +            grid.pagination.page = grid.pagination.totalPages;
    +            firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          }
    +
    +          return renderableRows.slice(
    +            firstRow,
    +            firstRow + grid.options.rowsPerPage
    +          );
    +        });
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pagination.api:GridOptions
    +         *
    +         *  @description GridOptions for the pagination feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePagination
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description Enable pagination for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name rowsPerPage
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description The number of rows that should be displayed per page
    +         *  <br/>Defaults to 10
    +         */
    +        gridOptions.rowsPerPage = angular.isNumber(gridOptions.rowsPerPage) ? gridOptions.rowsPerPage : 10;
    +      }
    +    };
    +
    +    return service;
    +  });
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.pagination.directive:uiGridPagination
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description Adds pagination support to a grid.
    +   */
    +  module.directive('uiGridPagination', ['uiGridPaginationService', function (uiGridPaginationService) {
    +    return {
    +      priority: -400,
    +      scope: false,
    +      require: '^uiGrid',
    +      link: {
    +        pre: function (scope, element, attrs, uiGridCtrl) {
    +          uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      }
    +    };
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.paging
    +   *
    +   * @description
    +   *
    +   * #ui.grid.paging
    +   * This module provides paging support to ui-grid
    +   */
    +   
    +  var module = angular.module('ui.grid.paging', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.paging.service:uiGridPagingService
    +   *
    +   * @description Service for the paging feature
    +   */
    +  module.service('uiGridPagingService', ['gridUtil', 
    +    function (gridUtil) {
    +      var service = {
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.paging.service:uiGridPagingService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.paging.api:PublicAPI
    +          *
    +          * @description Public API for the paging feature
    +          */
    +          var publicApi = {
    +            events: {
    +              paging: {
    +              /**
    +               * @ngdoc event
    +               * @name pagingChanged
    +               * @eventOf ui.grid.paging.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {currentPage} requested page number
    +               * @param {pageSize} requested page size 
    +               */
    +                pagingChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              paging: {
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPaging || !grid.options.enablePaging) {
    +              return renderableRows;
    +            }
    +            //client side paging
    +            var pageSize = parseInt(grid.options.pagingPageSize, 10);
    +            var currentPage = parseInt(grid.options.pagingCurrentPage, 10);
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            return renderableRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc property
    +           * @name enablePaging
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Enables paging, defaults to true
    +           */
    +          gridOptions.enablePaging = gridOptions.enablePaging !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPaging
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Disables client side paging. When true, handle the pagingChanged event and set data and totalItems
    +           * defaults to false
    +           */           
    +          gridOptions.useExternalPaging = gridOptions.useExternalPaging === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Total number of items, set automatically when client side paging, needs set by user for server side paging
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name pagingPageSizes
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Array of page sizes
    +           * defaults to [250, 500, 1000]
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.pagingPageSizes)) {
    +            gridOptions.pagingPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name pagingPageSize
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Page size
    +           * defaults to the first item in pagingPageSizes, or 0 if pagingPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.pagingPageSize)) {
    +            if (gridOptions.pagingPageSizes.length > 0) {
    +              gridOptions.pagingPageSize = gridOptions.pagingPageSizes[0];
    +            } else {              
    +              gridOptions.pagingPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name pagingCurrentPage
    +           * @propertyOf ui.grid.class:GridOptions
    +           * @description Current page number
    +           * default 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.pagingCurrentPage)) {
    +            gridOptions.pagingCurrentPage = 1;
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.paging.service:uiGridPagingService
    +         * @name uiGridPagingService
    +         * @description  Raises pagingChanged and calls refresh for client side paging
    +         * @param {grid} the grid for which the paging changed
    +         * @param {currentPage} requested page number
    +         * @param {pageSize} requested page size 
    +         */
    +        onPagingChanged: function (grid, currentPage, pageSize) {
    +            grid.api.paging.raise.pagingChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPaging) {
    +              grid.refresh(); //client side paging
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.paging.directive:uiGridPaging
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds paging features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.paging']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        pagingPageSizes: [5, 10, 25],
    +        pagingPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-paging></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPaging', ['gridUtil', 'uiGridPagingService', 
    +    function (gridUtil, uiGridPagingService) {
    +    /**
    +     * @ngdoc property
    +     * @name pagingTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description a custom template for the pager.  The default
    +     * is ui-grid/ui-grid-paging
    +     */
    +      var defaultTemplate = 'ui-grid/ui-grid-paging';
    +
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        compile: function ($scope, $elm, $attr, uiGridCtrl) {
    +          return {
    +            pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +
    +              uiGridPagingService.initializeGrid(uiGridCtrl.grid);
    +
    +              var pagingTemplate = uiGridCtrl.grid.options.pagingTemplate || defaultTemplate;
    +              gridUtil.getTemplate(pagingTemplate)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                  $elm.append(template);
    +                  uiGridCtrl.innerCompile(template);
    +                });
    +            },
    +            post: function ($scope, $elm, $attr, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.paging.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling paging
    +   */
    +  module.directive('uiGridPager', ['uiGridPagingService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPagingService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +
    +          $scope.sizesLabel = i18nService.getSafeText('paging.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('paging.totalItems');
    +          
    +          var options = $scope.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPaging) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.pagingCurrentPage - 1) * options.pagingPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.pagingCurrentPage * options.pagingPageSize, options.totalItems);
    +          };
    +
    +          var getMaxPages = function () {
    +            return (options.totalItems === 0) ? 1 : Math.ceil(options.totalItems / options.pagingPageSize);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.pagingPageSize', function () {
    +              $scope.currentMaxPages = getMaxPages();
    +              setShowing();
    +            }
    +          );
    +
    +          var deregP = $scope.$watch('grid.options.pagingCurrentPage + grid.options.pagingPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.pagingCurrentPage) || options.pagingCurrentPage < 1) {
    +                options.pagingCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.pagingCurrentPage > getMaxPages()) {
    +                options.pagingCurrentPage = getMaxPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPagingService.onPagingChanged($scope.grid, options.pagingCurrentPage, options.pagingPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.pageForward = function () {
    +            if (options.totalItems > 0) {
    +              options.pagingCurrentPage = Math.min(options.pagingCurrentPage + 1, $scope.currentMaxPages);
    +            } else {
    +              options.pagingCurrentPage++;
    +            }
    +          };
    +
    +          $scope.pageBackward = function () {
    +            options.pagingCurrentPage = Math.max(options.pagingCurrentPage - 1, 1);
    +          };
    +
    +          $scope.pageToFirst = function () {
    +            options.pagingCurrentPage = 1;
    +          };
    +
    +          $scope.pageToLast = function () {
    +            options.pagingCurrentPage = $scope.currentMaxPages;
    +          };
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.pagingCurrentPage >= $scope.currentMaxPages;
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.pagingCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', function (gridUtil, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth) * rtlMultiplier;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth) * rtlMultiplier;
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {object} grid the grid for which rows should be set dirty
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function (grid, dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.api:PublicApi
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing 
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected ){
    +                      row.isSelected = true;
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected){
    +                        row.isSelected = true;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.isSelected = false;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +                
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead  
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid);
    +            }
    +          }
    +          
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected ){
    +                rowToSelect.isSelected = true;
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.isSelected = false;
    +              service.decideRaiseSelectionEvent( grid, row, changedRows );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and 
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows);
    +          }
    +        }        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +          
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows();
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              var touchStartTime = 0;
    +              var touchTimeout = 300;
    +              var selectCells = function(evt){
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              };
    +
    +              $elm.on('touchstart', function(event) {
    +                touchStartTime = (new Date()).getTime();
    +              });
    +
    +              $elm.on('touchend', function (evt) {
    +                var touchEndTime = (new Date()).getTime();
    +                var touchTime = touchEndTime - touchStartTime;
    +
    +                if (touchTime < touchTimeout ) {
    +                  // short touch
    +                  selectCells(evt);
    +                }
    +              });
    +
    +              $elm.on('click', function (evt) {
    +                selectCells(evt);
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableVerticalScrollbar\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableHorizontalScrollbar\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-paging',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"pageToFirst()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"pageBackward()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.pagingCurrentPage\" min=\"1\" max=\"{{currentMaxPages}}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"currentMaxPages > 0\">/ {{currentMaxPages}}</span> <button type=\"button\" ng-click=\"pageForward()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"pageToLast()\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.pagingPageSize\" ng-options=\"o as o for o in grid.options.pagingPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons>&nbsp;</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-RC.18/ui-grid.min.css b/release/3.0.0-RC.18/ui-grid.min.css
    new file mode 100644
    index 000000000..34c5a808e
    --- /dev/null
    +++ b/release/3.0.0-RC.18/ui-grid.min.css
    @@ -0,0 +1,13 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:fixed;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir="rtl"] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir="rtl"] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +
    +.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}
    +.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected>div.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18/ui-grid.min.js b/release/3.0.0-RC.18/ui-grid.min.js
    new file mode 100644
    index 000000000..6bdb2be64
    --- /dev/null
    +++ b/release/3.0.0-RC.18/ui-grid.min.js
    @@ -0,0 +1,8 @@
    +/*! ui-grid - v3.0.0-RC.18 - 2014-12-09
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column"},scrollbars:{NEVER:0,ALWAYS:1,WHEN_NEEDED:2}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){b.addClass(a.col.getColClass(!1));var c,e=function(){var d=b;c&&(d.removeClass(c),c=null),c=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,d.addClass(c)};a.col.cellClass&&e();var f=a.grid.registerDataChangeCallback(e,[d.dataChange.COLUMN,d.dataChange.EDIT]),g=function(){a.grid.deregisterDataChangeCallback(f)};a.$on("$destroy",g)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,c,e,f){var g=this;d.initialize(b,f),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,e,f){b.col=a;var h=d.getColumnElementPosition(b,a,e);b.menuShown?(b.colElement=e,b.colElementPosition=h,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(g.shown=b.menuShown=!0,d.repositionMenu(b,a,h,c,e),b.colElement=e,b.colElementPosition=h,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,a.getExternalScopes=e.getExternalScopes,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",function(){a.grid.deregisterDataChangeCallback(h)})}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,a.getExternalScopes=h.getExternalScopes,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,e){function h(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.getExternalScopes=i.getExternalScopes,a.renderContainer=i.grid.renderContainers[j.containerId],c.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var k,l=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),m=function(){var b=c;k&&(b.removeClass(k),k=null),k=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(k)};a.col.headerCellClass&&m();var n=a.grid.registerDataChangeCallback(m,[f.dataChange.COLUMN]),o=function(){a.grid.deregisterDataChangeCallback(n)};if(a.$on("$destroy",o),a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var p,q=0;l.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(q=(new Date).getTime(),p=b(function(){},g),p.then(function(){a.colMenu&&i.columnMenuScope.showMenu(a.col,c,d)}))}),l.on("mouseup touchend",function(){b.cancel(p)}),a.$on("$destroy",function(){l.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,c)},a.sortable&&(l.on("click touchend",function(a){a.stopPropagation(),b.cancel(p);var c=(new Date).getTime(),d=c-q;d>g||h(a)}),a.$on("$destroy",function(){b.cancel(p)})),a.filterable){var r=[];angular.forEach(a.col.filters,function(b,c){r.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})}))}))}),a.$on("$destroy",function(){angular.forEach(r,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,a.getExternalScopes=i.getExternalScopes,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth();"undefined"!=typeof g.grid.verticalScrollbarWidth&&void 0!==g.grid.verticalScrollbarWidth&&g.grid.verticalScrollbarWidth>0&&(a+=g.grid.verticalScrollbarWidth);var b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,j=a,k=!1,l=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(j/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",k=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,k=!0)});var m=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return m.indexOf(a.widthType)-m.indexOf(b.widthType)}).forEach(function(a){var b=l(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,j-=a.drawnWidth}),k&&j>0&&c>0&&a>c){var n=function(a){j>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,j--)},o=0;do o=j,b.forEach(n);while(j>0&&j!==o)}c=Math.max(c,a);var p="";return b.forEach(function(a){p+=a.getColClassDefinition()}),i.verticalScrollbarWidth&&(c+=i.verticalScrollbarWidth),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),p}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(a){var d=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(d.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};c.setMenuItemTitle(e,b,a.grid),d.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},c.setMenuItemTitle(e,b,a.grid),d.push(e)}}),d):d},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a){var d=this;d.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var f="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(f=d.originalEvent.type),angular.element(document).off("click touchstart",e),b(function(){angular.element(document).on(f,e)})},d.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",e)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var e=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",e),a.$on("$destroy",function(){angular.element(document).off("click touchstart",e)}),a.$on("$destroy",function(){angular.element(c).off("resize",e)}),a.$on("$destroy",a.$on(f.events.GRID_SCROLL,e)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,e))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){var e=d.getScrollbarWidth();angular.isNumber(e)||(e=0);var f=d.detectBrowser();return"ie"===f&&(e+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,f,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),d=o.headerHeight?o.headerHeight:p.headerHeight,e=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-y:auto;":"",f=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return f+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+d+"px;"+e+"}",s=b,f}function i(){var a=o.getCanvasWidth(),b=u;p.options.showFooter&&(b-=1);var d=o.getViewportAdjustment();b-=d.height;var e=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-x:auto":"",f=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px;"+e+" }";return f+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,f}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,e=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(e-=l.grid.horizontalScrollbarHeight);var f=c/e;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=d.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,e){if(!e.target||e.target!==b&&!angular.element(e.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=e.target,"vertical"===a.type){if(e.y&&"undefined"!=typeof e.y.percentage&&void 0!==e.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,e.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&e.x&&"undefined"!=typeof e.x.percentage&&void 0!==e.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,e.x.percentage*h);b[0].scrollLeft=d.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",e+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,o.verticalScrollbarWidth=p.verticalScrollbarWidth,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",e+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,n.horizontalScrollbarHeight=p.horizontalScrollbarHeight,r=d.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=d.elementHeight(b):"horizontal"===a.type&&(s=d.elementWidth(b));var t=d.closestElm(b,".ui-grid"),u=d.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(c.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(e,f,g,h){function i(a,b){if(b.y&&e.bindScrollVertical){n.prevScrollArgs=b;var c=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(c+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)f=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,f*c);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(b.x&&e.bindScrollHorizontal){n.prevScrollArgs=b;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=d.normalizeScrollLeft(n.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=d.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=d.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=d.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-v),c=-(e-u),y=1>c?-1:1,z=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(w+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(x+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(c){function d(){a(function(){var a={target:c.target};if(0!==u){var b=(n.viewport[0].scrollTop+u)/(p.getCanvasHeight()-p.getViewportHeight());a.y={percentage:b,pixels:u}}if(0!==v){var e=(n.viewport[0].scrollLeft+v)/(q.getCanvasWidth()-q.getViewportWidth());a.x={percentage:e,pixels:v}}m.fireScrollingEvent(a),s-=1,u/=2,v/=2,s>0?d():m.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},r)}c.originalEvent&&(c=c.originalEvent),c.preventDefault(),b.unbind("touchmove",j),b.unbind("touchend",k),b.unbind("touchcancel",k);var e=n.viewport[0].scrollTop,f=n.viewport[0].scrollTop,g=Math.abs(e-w),h=Math.abs(f-x),i=new Date-t,l=g/i,o=h/i,r=63,s=8,u=120*y*l,v=120*z*o;d()}function l(){var a="",b=q.getCanvasWidth(),c=q.getViewportWidth(),d=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==r.explicitHeaderHeight&&null!==r.explicitHeaderHeight&&r.explicitHeaderHeight>0?a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.explicitHeaderHeight+"px; }":void 0!==r.innerHeaderHeight&&null!==r.innerHeaderHeight&&r.innerHeaderHeight>0&&(a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.innerHeaderHeight+"px; }"),a}var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer,r=o.renderContainers[e.containerId];f.addClass("ui-grid-render-container-"+e.containerId);var s;(e.bindScrollHorizontal||e.bindScrollVertical)&&(s=e.$on(c.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=d.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var e=-120*b.deltaY,g=(n.viewport[0].scrollTop+e)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:e}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var t,u=0,v=0,w=0,x=0,y=1,z=1;d.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),t=new Date,u=a.targetTouches[0].screenY,v=a.targetTouches[0].screenX,w=n.viewport[0].scrollTop,x=n.viewport[0].scrollLeft,b.on("touchmove",j),b.on("touchend touchcancel",k)}),f.bind("$destroy",function(){s(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil",function(a){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(b,c,d,e){var f=e[0],g=e[1];
    +b.containerCtrl=g;{var h=g.rowContainer,i=g.colContainer;f.grid}b.grid=f.grid,b.rowContainer=g.rowContainer,b.colContainer=g.colContainer,g.viewport=c,c.on("scroll",function(){var d=c[0].scrollTop,e=a.normalizeScrollLeft(c),g=-1,j=-1;if(e!==i.prevScrollLeft){var k=(e-i.prevScrollLeft,i.getCanvasWidth()-i.getViewportWidth());g=e/k,i.adjustScrollHorizontal(e,g)}if(d!==h.prevScrollTop){var l=(d-h.prevScrollTop,h.getCanvasHeight()-h.getViewportHeight());j=d/l,j>1&&(j=1),0>j&&(j=0),h.adjustScrollVertical(d,j)}if(!b.grid.isScrollingVertically&&!b.grid.isScrollingHorizontally){var m={};g>-1&&(m.x={percentage:g}),j>-1&&(m.y={percentage:j}),f.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===n.grid.options.columnDefs.length&&b.length>0&&n.grid.buildColumnDefsFromData(b),(n.grid.options.columnDefs.length>0||b.length>0)&&d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()})),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,n.getExternalScopes=a.getExternalScopes,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireScrollingEvent=d.throttle(function(b){a.$broadcast(f.events.GRID_SCROLL,b)},n.grid.options.scrollThrottle,{trailing:!0}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.queueRefresh()}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.options.showFooter?i.options.footerRowHeight:0,m=0;i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas();var q=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');b.prepend(q),g.innerCompile(q);var r=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');b.append(r),g.innerCompile(r),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0===h&&e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),g=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT])};return o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b){var c=d.nextUid();return b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[c]={callback:a,types:b},c},o.prototype.deregisterDataChangeCallback=function(a){delete this.dataChangeCallbacks[a]},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&b.callback(this)},this)},o.prototype.notifyDataChange=function(a,b){var c=e.dataChange;b===c.ALL||b===c.COLUMN||b===c.EDIT||b===c.ROW?a.callDataChangeCallbacks(b):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+b)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},o.prototype.buildColumns=function(){var b,c=this,e=[],f=c.rowHeaderColumns.length;for(b=0;b<c.columns.length;b++)c.getColDef(c.columns[b].name)||(c.columns.splice(b,1),b--);return c.rowHeaderColumns.forEach(function(a){c.columns.unshift(a)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var h=c.getColumn(a.name);h?h.updateColumnDef(a):(h=new g(a,d.nextUid(),c),c.columns.splice(b+f,0,h)),c.columnBuilders.forEach(function(b){e.push(b.call(c,a,h,c.options))})}),a.all(e)},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;var j=0===g.rows.length;for(g.rows.length=0,c=0;c<b.length;c++){var k=b[c];e=i.get(k),f=e?e.row:g.processRowBuilders(new h(k,c,g)),g.rows.push(f),d.put(k,{i:c,entity:k,row:f})}j&&g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var l,m,n;if(g.options.enableRowHashing){l=[],n=[];var o={};for(m=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var p=!1;g.options.getRowIdentity(f)||(p=!0),e=d.get(f),e?e.row&&(o[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),p?n.push(f):l.push(f))}for(c=0;c<g.rows.length;c++){var q=g.rows[c],r=g.options.rowIdentity(q.entity);o[r]||m.push(q)}}var s=l||[],t=n||b;s=s.concat(g.newInN(g.rows,t,"entity")),g.addRows(s);var u=g.getDeletedRows(m||g.rows,b);for(c=0;c<u.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(u[c].entity),g.rows.splice(g.rows.indexOf(u[c]),1)}else g.createRowHashMap(),g.rows.length=0;var v=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),w=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([v,w])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){d.logDebug("grid refresh");var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),e=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,e]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)&&g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.scope,a.eventId,a.handler,c.grid)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$broadcast.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b){var c=f(a,g,b,d.grid),e={handler:b,dereg:c,eventId:g,scope:a};d.listeners.push(e),a.$on("$destroy",function(){e.dereg=null,e.handler=null,e.eventId=null,e.scope=null})}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var e="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var f=b.width.replace(/%/g,""),g=parseInt(f,10);if(isNaN(g))throw new Error(e);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(e);c.width=b.width}c.minWidth=b.minWidth?b.minWidth:30,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.footerCellClass=b.footerCellClass,c.cellClass=b.cellClass,c.headerCellClass=b.headerCellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var h=[];b.filter?h.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&h.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",h),d.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.maxVisibleRowCount=c.maxVisibleRowCount||200,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showFooter=c.showFooter===!0,c.footerRowHeight="undefined"!=typeof c.footerRowHeight?c.footerRowHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil",function(a){function b(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return b.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},b.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;
    +return b},b.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},b.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},b.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},b.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},b.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},b.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},b.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},b.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},b.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},b.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},b.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},b.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},b.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},b.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},b.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},b.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},b.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},b.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},b.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},b.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},b.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},b.prototype.updateColumnWidths=function(){var b=this,c=[],d=[],e=0,f=b.getViewportWidth();"undefined"!=typeof b.grid.verticalScrollbarWidth&&void 0!==b.grid.verticalScrollbarWidth&&b.grid.verticalScrollbarWidth>0&&(f+=b.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=b.visibleColumnCache;k.forEach(function(b){if(b.visible){var f=!1;angular.isNumber(b.width)||(f=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(e=parseInt(e+b.width.length,10),c.push(b)):f?d.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),b.grid.verticalScrollbarWidth&&(i+=b.grid.verticalScrollbarWidth),b.canvasWidth=parseInt(i,10),this.columnStyles=j},b}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["gridUtil","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(!h.noTerm&&(null===j||void 0===j||""===j))return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&("undefined"!=typeof a.filter.term&&a.filter.term||a.filter.noTerm)&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){p.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},paging:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},paging:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3},EVENT_TYPE:{KEYDOWN:0,CLICK:1}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};if(null!==d){var g=a.renderContainers.body.visibleRowCache.indexOf(d),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;f.y={percentage:i}}null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},scrollToIfNecessary:function(a,c,d,e){var f={},g=a.renderContainers.body.visibleRowCache,h=a.renderContainers.body.visibleColumnCache,i=a.renderContainers.body.prevScrollTop+a.headerHeight;i=0>i?0:i;var j=a.renderContainers.body.prevScrollLeft,k=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight;a.horizontalScrollbarHeight&&(k-=a.horizontalScrollbarHeight);var l=a.renderContainers.body.prevScrollLeft+a.gridWidth;if(a.verticalScrollbarWidth&&(l-=a.verticalScrollbarWidth),null!==d){var m=g.indexOf(d),n=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight();a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(n+=a.horizontalScrollbarHeight);var o=(m+1)*a.options.rowHeight;o=0>o?0:o;var p,q;i>o?(p=a.renderContainers.body.prevScrollTop-(i-o),q=p/n,f.y={percentage:q}):o>k&&(p=o-k+a.renderContainers.body.prevScrollTop,q=p/n,f.y={percentage:q})}if(null!==e){for(var r=h.indexOf(e),s=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),t=0,u=0;r>u;u++){var v=h[u];t+=v.drawnWidth}t=0>t?0:t;var w=t+e.drawnWidth;w=0>w?0:w;var x,y;j>t?(x=a.renderContainers.body.prevScrollLeft-(j-t),y=x/s,y=y>1?1:y,f.x={percentage:y}):w>l&&(x=w-l+a.renderContainers.body.prevScrollLeft,y=x/s,y=y>1?1:y,f.x={percentage:y})}(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.focusCell=function(a,b){g.cellNav.broadcastCellNav({row:a,col:b})},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a)},g.cellNav.broadcastFocus=function(b){var c=b.row,d=b.col;if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==c||h.cellNav.lastRowCol.col!==d){var e=new a(c,d);h.api.cellNav.raise.navigate(e,h.cellNav.lastRowCol),h.cellNav.lastRowCol=e}},g.cellNav.handleKeyDown=function(a){var e=c.getDirection(a);if(null===e)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var i=g.grid.api.cellNav.getFocusedCell();if(i){var j=g.grid.renderContainers[f].cellNav.getNextRowCol(e,i.row,i.col);return j.eventType=d.EVENT_TYPE.KEYDOWN,g.cellNav.broadcastCellNav(j),c.scrollToIfNecessary(h,b,j.row,j.col),a.stopPropagation(),a.preventDefault(),!1}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,f,g,h){var i=h[0],j=h[1],k=h[2];if(k){var l=j.containerId,m=i.grid;e.decorateRenderContainers(m),f.attr("tabindex",-1),f.on("keydown",function(a){return a.uiGridTargetRenderContainerId=l,i.cellNav.handleKeyDown(a)}),c.$on(d.events.GRID_SCROLL,function(){null!=i.grid.api.cellNav.getFocusedCell()&&a(function(){a(function(){var a=i.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&f[0].focus(),i.cellNav.broadcastCellNav(a)})})})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:["^uiGrid","?^uiGridCellnav"],scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",-1)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}var j=e[0],k=e[1];k&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){j.cellNav.broadcastCellNav(new a(b.row,b.col)),c.stopPropagation()}),b.$on(f.CELL_NAV_EVENT,function(a,d){d.row===b.row&&d.col===b.col?(h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&c.find("div")[0].focus()):i()}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g){return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(e,h,i,j){function k(){h.on("dblclick",p),h.on("keydown",n),e.col.colDef.enableCellEditOnFocus&&h.find("div").on("focus",m)}function l(){h.off("dblclick",p),h.off("keydown",n),e.col.colDef.enableCellEditOnFocus&&h.find("div").off("focus",m)}function m(a){j&&j.cellNav&&j.cellNav.focusCell(e.row,e.col),a.stopPropagation(),p()}function n(a){g.isStartEditKey(a)&&p()}function o(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(e):a.colDef.cellEditableCondition)}function p(){if(!v&&o(e.col,e.row)){u=f(e.row.getQualifiedColField(e.col)),t=u(e),s=e.col.editableCellTemplate,s=s.replace(c.MODEL_COL_FIELD,e.row.getQualifiedColField(e.col));var b=e.col.colDef.editDropdownFilter?"|"+e.col.colDef.editDropdownFilter:"";switch(s=s.replace(c.CUSTOM_FILTERS,b),e.inputType="text",e.col.colDef.type){case"boolean":e.inputType="checkbox";break;case"number":e.inputType="number";break;case"date":e.inputType="date"}e.editDropdownOptionsArray=e.col.colDef.editDropdownOptionsArray,e.editDropdownIdLabel=e.col.colDef.editDropdownIdLabel?e.col.colDef.editDropdownIdLabel:"id",e.editDropdownValueLabel=e.col.colDef.editDropdownValueLabel?e.col.colDef.editDropdownValueLabel:"value";e.$apply(function(){v=!0,l();var b=angular.element(s);h.append(b),a(b)(e.$new());var c=angular.element(h.children()[0]);w=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var g=e.$on(c.events.GRID_SCROLL,function(){q(!0),e.grid.api.edit.raise.afterCellEdit(e.row.entity,e.col.colDef,u(e),t),g()}),i=e.$on(d.events.END_CELL_EDIT,function(a,b){q(b),e.grid.api.edit.raise.afterCellEdit(e.row.entity,e.col.colDef,u(e),t),i()}),j=e.$on(d.events.CANCEL_CELL_EDIT,function(){r(),j()});e.$broadcast(d.events.BEGIN_CELL_EDIT),e.grid.api.edit.raise.beginCellEdit(e.row.entity,e.col.colDef)}}function q(a){if(v){var b=angular.element(h.children()[0]);angular.element(h.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&w&&b[0].focus(),w=!1,v=!1,k(),e.grid.api.core.notifyDataChange(e.grid,c.dataChange.EDIT)}}function r(){v&&(u.assign(e,t),e.$apply(),e.grid.api.edit.raise.cancelCellEdit(e.row.entity,e.col.colDef),q(!0))}if(e.col.colDef.enableCellEdit){var s,t,u,v=!1,w=!1;k();try{var x=b.get("uiGridCellNavConstants");e.col.colDef.enableCellEditOnFocus&&e.$on(x.CELL_NAV_EVENT,function(a,b){b.row===e.row&&b.col===e.col?p():q()})}catch(y){}}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(c,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null
    +}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.refresh()}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",width:40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c,e){var f=this.getColumnHeaders(a,c),g=this.getData(a,b,c),h=this.formatAsCsv(f,g,a.options.exporterCsvColumnSeparator);!e&&a.options.exporterCsvLinkElement&&(e=a.options.exporterCsvLinkElement),e?this.renderCsvLink(a,h,e):d.logError("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,d){var e=[];return angular.forEach(a.columns,function(f){!f.visible&&d!==b.ALL||f.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(f.name)||e.push({name:f.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(f.displayName):f.displayName,width:f.drawnWidth?f.drawnWidth:f.width,align:"number"===f.colDef.type?"right":"left"})}),e},getData:function(a,e,f){var g,h=[];switch(e){case b.ALL:g=a.rows;break;case b.VISIBLE:g=a.getVisibleRows();break;case b.SELECTED:a.api.selection?g=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(g,function(d){var e=[];angular.forEach(a.columns,function(g){if((g.visible||f===b.ALL)&&g.name!==c.selectionRowHeaderColName&&-1===a.options.exporterSuppressColumns.indexOf(g.name)){var h={value:a.options.exporterFieldCallback(a,d,g,a.getCellValue(d,g))};g.colDef.exporterPdfAlign&&(h.alignment=g.colDef.exporterPdfAlign),e.push(h)}}),h.push(e)}),h},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},renderCsvLink:function(a,c,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){var f=angular.element(d);f.children("a").html(f.children("a").html().replace(b.LINK_LABEL,a.options.exporterLinkLabel)),f.children("a").attr("href",f.children("a").attr("href").replace(b.CSV_CONTENT,encodeURIComponent(c)));var h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&h.content.unshift(a.options.exporterPdfHeader),a.options.exporterPdfFooter&&h.content.push(a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a,b){i.importFile(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(a,c),a.deregisterDataChangeCallback(d)},[b.dataChange.ROW]),e=function(){a.deregisterDataChangeCallback(d)};a.importer.$scope.$on("$destroy",e)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){if(1===a.srcElement.files.length){var c=a.srcElement.files[0];b.importThisFile(i,c),a.srcElement.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout","$log",function(a,b){var c={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){b.redrawColumnAtPosition(a,c,d)}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var e=a.columns,f=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1&&b++;return b};c=f(c),d=f(d);var g=e[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)e[h]=e[h-1];else if(d>c)for(var i=c;d>i;i++)e[i]=e[i+1];e[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return c}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(e,f,g,h){if(e.col.colDef.enableColumnMoving){var i=function(i){if("ui-grid-icon-angle-down"!==i.target.className&&"I"!==i.target.tagName&&i.target.className.indexOf("ui-grid-filter-input")<0){var j,k,l=e.grid.element[0].getBoundingClientRect().left,m=i.pageX,n=0,o=l+e.grid.getViewportWidth()-e.grid.verticalScrollbarWidth,p=!1,q=function(){p=!0,j=f.clone(),f.append(j),j.addClass("movingColumn");var a={},b=f[0].getBoundingClientRect().left;a.left=b-l+"px";var c=e.grid.element[0].getBoundingClientRect().right,g=f[0].getBoundingClientRect().right;g>c&&(k=e.col.drawnWidth+(c-g),a.width=k+"px"),j.css(a),d.on("mouseup",t)},r=function(a){h.fireEvent("hide-menu");var c,d=j[0].getBoundingClientRect().left-1,f=j[0].getBoundingClientRect().right;c="ie"===b.detectBrowser()?d+a:d-l+a,c=o>c?c:o,(d>=l||a>0)&&(o>=f||0>a)?j.css({visibility:"visible",left:c+"px"}):(a*=5,h.fireScrollingEvent({x:{pixels:2.5*a}})),n+=a,k<e.col.drawnWidth&&(k+=Math.abs(a),j.css({width:k+"px"}))},s=function(a){var b=a.pageX-m;!p&&Math.abs(b)>50?q():p&&(r(b),m=a.pageX)};e.$on("$destroy",function(){d.off("mousemove",s),d.off("mouseup",t)}),d.on("mousemove",s);var t=function(b){var f,i=a.defer();g.$observe("renderIndex",function(a){f=e.$eval(a),i.resolve()}),i.promise.then(function(){j&&j.remove();for(var a=e.grid.renderContainers.body.renderedColumns,g=0,i=e.grid.columns,k=0;k<i.length&&(i[k].colDef.visible&&i[k].colDef.name!==a[0].colDef.name);k++)g++;if(0>n){for(var l=0,m=f-1;m>=0;m--)if(l+=a[m].drawnWidth,l>Math.abs(n)){c.redrawColumnAtPosition(e.grid,g+f,g+m+1);break}l<Math.abs(n)&&c.redrawColumnAtPosition(e.grid,g+f,g+0)}else if(n>0){for(var o=0,p=f+1;p<a.length;p++)if(o+=a[p].drawnWidth,o>n){c.redrawColumnAtPosition(e.grid,g+f,g+p-1);break}n>o&&c.redrawColumnAtPosition(e.grid,g+f,g+a.length-1)}else if(0===n&&h.grid.options.enableSorting&&e.col.enableSorting){var q=!1;b.shiftKey&&(q=!0),h.grid.sortColumn(e.col,q).then(function(){h.columnMenuScope&&h.columnMenuScope.hideMenu(),h.grid.refresh()})}d.off("mousemove",s),d.off("mouseup",t)})}}};f.on("mousedown",i)}}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ui.grid"]);a.service("uiGridPaginationService",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options),b.pagination={page:1,totalPages:1};var c={methods:{pagination:{getPage:function(){return b.pagination.page},getTotalPages:function(){return b.pagination.totalPages},nextPage:function(){b.pagination.page++,b.refresh()},previousPage:function(){b.pagination.page=Math.max(1,b.pagination.page-1),b.refresh()},seek:function(a){if(!angular.isNumber(a)||1>a)throw"Invalid page number: "+a;b.pagination.page=a,b.refresh()}}}};b.api.registerMethodsFromObject(c.methods),b.registerRowsProcessor(function(a){if(!b.options.enablePagination)return a;b.pagination.totalPages=Math.max(1,Math.ceil(a.length/b.options.rowsPerPage));var c=(b.pagination.page-1)*b.options.rowsPerPage;return c>=a.length&&(b.pagination.page=b.pagination.totalPages,c=(b.pagination.page-1)*b.options.rowsPerPage),a.slice(c,c+b.options.rowsPerPage)})},defaultGridOptions:function(a){a.enablePagination=a.enablePagination!==!1,a.rowsPerPage=angular.isNumber(a.rowsPerPage)?a.rowsPerPage:10}};return a}),a.directive("uiGridPagination",["uiGridPaginationService",function(a){return{priority:-400,scope:!1,require:"^uiGrid",link:{pre:function(b,c,d,e){a.initializeGrid(e.grid)}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.paging",["ui.grid"]);a.service("uiGridPagingService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{paging:{pagingChanged:function(){}}},methods:{paging:{}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPaging||!a.options.enablePaging)return b;var c=parseInt(a.options.pagingPageSize,10),d=parseInt(a.options.pagingCurrentPage,10),e=(d-1)*c;return b.slice(e,e+c)})},defaultGridOptions:function(b){b.enablePaging=b.enablePaging!==!1,b.useExternalPaging=b.useExternalPaging===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.pagingPageSizes)&&(b.pagingPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.pagingPageSize)&&(b.pagingPageSize=b.pagingPageSizes.length>0?b.pagingPageSizes[0]:0),a.isNullOrUndefined(b.pagingCurrentPage)&&(b.pagingCurrentPage=1)},onPagingChanged:function(a,b,c){a.api.paging.raise.pagingChanged(b,c),a.options.useExternalPaging||a.refresh()}};return b}]),a.directive("uiGridPaging",["gridUtil","uiGridPagingService",function(a,b){var c="ui-grid/ui-grid-paging";return{priority:-200,scope:!1,require:"uiGrid",compile:function(){return{pre:function(d,e,f,g){b.initializeGrid(g.grid);var h=g.grid.options.pagingTemplate||c;a.getTemplate(h).then(function(a){var b=angular.element(a);e.append(b),g.innerCompile(b)})},post:function(){}}}}}]),a.directive("uiGridPager",["uiGridPagingService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.sizesLabel=d.getSafeText("paging.sizes"),e.totalItemsLabel=d.getSafeText("paging.totalItems");var i=e.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a}),h.grid.registerDataChangeCallback(function(a){a.options.useExternalPaging||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);var j=function(){e.showingLow=(i.pagingCurrentPage-1)*i.pagingPageSize+1,e.showingHigh=Math.min(i.pagingCurrentPage*i.pagingPageSize,i.totalItems)},k=function(){return 0===i.totalItems?1:Math.ceil(i.totalItems/i.pagingPageSize)},l=e.$watch("grid.options.totalItems + grid.options.pagingPageSize",function(){e.currentMaxPages=k(),j()}),m=e.$watch("grid.options.pagingCurrentPage + grid.options.pagingPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.pagingCurrentPage)||i.pagingCurrentPage<1)return void(i.pagingCurrentPage=1);if(i.totalItems>0&&i.pagingCurrentPage>k())return void(i.pagingCurrentPage=k());j(),a.onPagingChanged(e.grid,i.pagingCurrentPage,i.pagingPageSize)}});e.$on("$destroy",function(){l(),m()}),e.pageForward=function(){i.totalItems>0?i.pagingCurrentPage=Math.min(i.pagingCurrentPage+1,e.currentMaxPages):i.pagingCurrentPage++},e.pageBackward=function(){i.pagingCurrentPage=Math.max(i.pagingCurrentPage-1,1)},e.pageToFirst=function(){i.pagingCurrentPage=1},e.pageToLast=function(){i.pagingCurrentPage=e.currentMaxPages},e.cantPageForward=function(){return i.totalItems>0?i.pagingCurrentPage>=e.currentMaxPages:i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.pagingCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)
    +})}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","columnBounds","uiGridResizeColumnsService",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(g,h,i,j){function k(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function l(){j.grid.buildColumns().then(function(){j.grid.refreshCanvas(!0)})}function m(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),p=a.clientX-q,0>p?p=0:p>j.grid.gridWidth&&(p=j.grid.gridWidth);var b,e=g.col,h=e.getRenderContainer();if("left"===g.position?(e=h.renderedColumns[g.renderIndex-1],b=g.col):"right"===g.position&&(b=h.renderedColumns[g.renderIndex+1]),e.colDef.enableColumnResizing!==!1){j.grid.element.hasClass("column-resizing")||j.grid.element.addClass("column-resizing");var i=p-o,k=parseInt(e.drawnWidth+i*r,10);e.colDef.minWidth&&k<e.colDef.minWidth?p+=(e.colDef.minWidth-k)*r:!e.colDef.minWidth&&d.minWidth&&k<d.minWidth?p+=e.colDef.minWidth-k:e.colDef.maxWidth&&k>e.colDef.maxWidth&&(p+=(e.colDef.maxWidth-k)*r),f.css({left:p+"px"}),j.fireEvent(c.events.ITEM_DRAGGING)}}function n(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),j.grid.element.removeClass("column-resizing"),f.remove(),p=b.clientX-q;var c=p-o;if(0===c)return a.off("mouseup",n),void a.off("mousemove",m);var h,i=g.col,s=i.getRenderContainer();if("left"===g.position?(i=s.renderedColumns[g.renderIndex-1],h=g.col):"right"===g.position&&(h=s.renderedColumns[g.renderIndex+1]),i.colDef.enableColumnResizing!==!1){var t=parseInt(i.drawnWidth+c*r,10);i.colDef.minWidth&&t<i.colDef.minWidth?t=i.colDef.minWidth:!i.colDef.minWidth&&d.minWidth&&t<d.minWidth&&(t=d.minWidth),i.colDef.maxWidth&&t>i.colDef.maxWidth&&(t=i.colDef.maxWidth),i.width=t,k(i),l(c),e.fireColumnSizeChanged(j.grid,i.colDef,c),a.off("mouseup",n),a.off("mousemove",m)}}var o=0,p=0,q=0,r=1;j.grid.isRTL()&&(g.position="left",r=-1),"left"===g.position?h.addClass("left"):"right"===g.position&&h.addClass("right"),h.on("mousedown",function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),q=j.grid.element[0].getBoundingClientRect().left,o=b.clientX-q,j.grid.element.append(f),f.css({left:o}),a.on("mouseup",n),a.on("mousemove",m)}),h.on("dblclick",function(a){a.stopPropagation();var f,i,m=g.col,n=m.getRenderContainer();"left"===g.position?(m=n.renderedColumns[g.renderIndex-1],f=g.col,i=1):"right"===g.position&&(f=n.renderedColumns[g.renderIndex+1],f=n.renderedColumns[g.renderIndex+1],i=-1);var o=0,p=0,q=b.closestElm(h,".ui-grid-render-container"),r=q.querySelectorAll("."+c.COL_CLASS_PREFIX+m.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(r,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var f=b.elementWidth(c);e+=f}e>o&&(o=e,p=o-e)})}),m.colDef.minWidth&&o<m.colDef.minWidth?o=m.colDef.minWidth:!m.colDef.minWidth&&d.minWidth&&o<d.minWidth&&(o=d.minWidth),m.colDef.maxWidth&&o>m.colDef.maxWidth&&(o=m.colDef.maxWidth),m.width=parseInt(o,10),k(m),l(p),e.fireColumnSizeChanged(j.grid,m.colDef,p)}),h.on("$destroy",function(){h.off("mousedown"),h.off("dblclick"),a.off("mousemove",m),a.off("mouseup",n)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){f.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEdit.dirtyRows?a.rowEdit.dirtyRows:[]},getErrorRows:function(a){return a.rowEdit.errorRows?a.rowEdit.errorRows:[]},flushDirtyRows:function(a){return f.flushDirtyRows(a)},setRowsDirty:function(a,b){f.setRowsDirty(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c){var d=b.renderContainers.body.visibleRowCache[c];null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},selectAllVisibleRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.visible?d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c)):d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;if(d||f){if(!d&&f){var g=a.getSelectedRows(b);g.length>1&&(f=!1,a.clearSelectedRows(b))}}else a.clearSelectedRows(b);f&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=[],j=f;g>=j;j++){var k=b.renderContainers.body.visibleRowCache[j];k&&(k.isSelected||(k.isSelected=!0,b.selection.lastSelectedRow=k,a.decideRaiseSelectionEvent(b,k,i)))}a.decideRaiseSelectionBatchEvent(b,i)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){var c=[];a.getSelectedRows(b).forEach(function(d){d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)},decideRaiseSelectionEvent:function(a,b,c){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b)},decideRaiseSelectionBatchEvent:function(a,b){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1};f.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(){c.selection.selectAll?(b.clearSelectedRows(c),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){var c=0,d=300,e=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()};b.on("touchstart",function(){c=(new Date).getTime()}),b.on("touchend",function(a){var b=(new Date).getTime(),f=b-c;d>f&&e(a)}),b.on("click",function(a){e(a)})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableVerticalScrollbar" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableHorizontalScrollbar" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/ui-grid-paging",'<div class="ui-grid-pager-panel" ui-grid-pager><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="pageToFirst()" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="pageBackward()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.pagingCurrentPage" min="1" max="{{currentMaxPages}}" required> <span class="ui-grid-pager-max-pages-number" ng-show="currentMaxPages > 0">/ {{currentMaxPages}}</span> <button type="button" ng-click="pageForward()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="pageToLast()" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.pagingPageSize" ng-options="o as o for o in grid.options.pagingPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons>&nbsp;</div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18/ui-grid.svg b/release/3.0.0-RC.18/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-RC.18/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-RC.18/ui-grid.ttf b/release/3.0.0-RC.18/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-RC.18/ui-grid.ttf differ
    diff --git a/release/3.0.0-RC.18/ui-grid.woff b/release/3.0.0-RC.18/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-RC.18/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.10/ui-grid.css b/release/3.0.0-rc.10/ui-grid.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/3.0.0-rc.10/ui-grid.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.10/ui-grid.eot b/release/3.0.0-rc.10/ui-grid.eot
    new file mode 100644
    index 000000000..88b133b63
    Binary files /dev/null and b/release/3.0.0-rc.10/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.10/ui-grid.js b/release/3.0.0-rc.10/ui-grid.js
    new file mode 100644
    index 000000000..2f58c19c4
    --- /dev/null
    +++ b/release/3.0.0-rc.10/ui-grid.js
    @@ -0,0 +1,13035 @@
    +/*! ui-grid - v3.0.0-rc.10 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(gridUtil.getStyles(angular.element($scope.menu)[0])['padding-right'], 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length + 1, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.gridOptions)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    //add row header columns to the grid columns array
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.push(rowHeaderColumn);
    +    });
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:',
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Kolom te verbergen'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollVerticallyTo
    +         * @description Scroll the grid vertically such that the specified
    +         * row is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var args = {};
    +          
    +          if ( rowEntity !== null ){
    +            var row = grid.getRow(rowEntity);
    +            if ( row ) { 
    +              args.y = { percentage: row.index / grid.renderContainers.body.visibleRowCache.length }; 
    +            }
    +          }
    +          
    +          if ( colDef !== null ){
    +            var col = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +            if ( col ) {
    +              args.x = { percentage: this.getLeftWidth(grid, col.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +            }
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = maxWidth;
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-selected': row.isSelected}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left;margin-top: 1px;margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell uiGridExpandableButtonsCell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{'ui-grid-icon-plus-squared':!row.isExpanded, 'ui-grid-icon-minus-squared':row.isExpanded}\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left;margin-top: 2px;margin-bottom: 2px\" ng-style=\"{width: (grid.getViewportWidth())\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight, 'margin-left': grid.options.rowHeader.rowHeaderWidth}\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5),\n" +
    +    "            'margin-left':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.10/ui-grid.min.css b/release/3.0.0-rc.10/ui-grid.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/3.0.0-rc.10/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.10/ui-grid.min.js b/release/3.0.0-rc.10/ui-grid.min.js
    new file mode 100644
    index 000000000..4d15087c7
    --- /dev/null
    +++ b/release/3.0.0-rc.10/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.10 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(f.getStyles(angular.element(i.menu)[0])["padding-right"],10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup",function(){c.cancel(j)}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,c=b.normalizeScrollLeft(d);if(c!==j.prevScrollLeft){var e=(c-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth()),f=c/e;j.adjustScrollHorizontal(c,f)}if(a!==i.prevScrollTop){var g=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight()),h=a/g;h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a
    +});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length+1,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.gridOptions).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c)})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.push(a)}),c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c
    +}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g=!0,h="width"===d?c.offsetWidth:c.offsetHeight,i=a(c),j="border-box"===i.boxSizing;if(0>=h||null==h){if(h=i[d],(0>h||null==h)&&(h=c.style[d]),e.test(h))return h;g=j&&!0,h=parseFloat(h)||0}var k=h+b(c,d,f||(j?"border":"content"),g,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Kolom te verbergen"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,d,e){var f={};if(null!==d){var g=a.getRow(d);g&&(f.y={percentage:g.index/a.renderContainers.body.visibleRowCache.length})}if(null!==e){var h=a.getColumn(e.name?e.name:e.field);h&&(f.x={percentage:this.getLeftWidth(a,h.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)})}(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0)}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};
    +g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=h.drawnWidth+d;h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=m,j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}"),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-selected': row.isSelected}"),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left;margin-top: 1px;margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n     ,height: grid.options.expandable.expandableRowHeight}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell uiGridExpandableButtonsCell"><div class="ui-grid-cell-contents"><i ng-class="{\'ui-grid-icon-plus-squared\':!row.isExpanded, \'ui-grid-icon-minus-squared\':row.isExpanded}" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller",'<div ng-if="expandableRow.shouldRenderFiller()" style="float:left;margin-top: 2px;margin-bottom: 2px" ng-style="{width: (grid.getViewportWidth())\n     ,height: grid.options.expandable.expandableRowHeight, \'margin-left\': grid.options.rowHeader.rowHeaderWidth}"><i class="ui-grid-icon-spin5 ui-grid-animate-spin" ng-style="{\'margin-top\': ( grid.options.expandable.expandableRowHeight/2 - 5),\n            \'margin-left\':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}"></i></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.10/ui-grid.svg b/release/3.0.0-rc.10/ui-grid.svg
    new file mode 100644
    index 000000000..4265b782c
    --- /dev/null
    +++ b/release/3.0.0-rc.10/ui-grid.svg
    @@ -0,0 +1,31 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xe800;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.10/ui-grid.ttf b/release/3.0.0-rc.10/ui-grid.ttf
    new file mode 100644
    index 000000000..d2dc304da
    Binary files /dev/null and b/release/3.0.0-rc.10/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.10/ui-grid.woff b/release/3.0.0-rc.10/ui-grid.woff
    new file mode 100644
    index 000000000..e11bc6564
    Binary files /dev/null and b/release/3.0.0-rc.10/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.11/ui-grid.css b/release/3.0.0-rc.11/ui-grid.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/3.0.0-rc.11/ui-grid.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.11/ui-grid.eot b/release/3.0.0-rc.11/ui-grid.eot
    new file mode 100644
    index 000000000..88b133b63
    Binary files /dev/null and b/release/3.0.0-rc.11/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.11/ui-grid.js b/release/3.0.0-rc.11/ui-grid.js
    new file mode 100644
    index 000000000..19d015542
    --- /dev/null
    +++ b/release/3.0.0-rc.11/ui-grid.js
    @@ -0,0 +1,13157 @@
    +/*! ui-grid - v3.0.0-rc.11 - 2014-09-26
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(gridUtil.getStyles(angular.element($scope.menu)[0])['padding-right'], 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.unshift(rowHeaderColumn);
    +      
    +      // renumber any columns already there, as cellNav relies on cols[index] === col.index
    +      self.columns.forEach(function(column, index){
    +        column.index = index;
    +      });
    +    });
    +
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:'
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +          
    +          if ( rowEntity !== null ){
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +          
    +          if ( colDef !== null ){
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function( grid, $scope, gridRow, gridCol ){
    +          var args = {};
    +          
    +          if ( gridRow !== null ){
    +            args.y = { percentage: gridRow.index / grid.renderContainers.body.visibleRowCache.length }; 
    +          }
    +          
    +          if ( gridCol !== null ){
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +            $scope.grid.queueRefresh();
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandable.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandable.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.11/ui-grid.min.css b/release/3.0.0-rc.11/ui-grid.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/3.0.0-rc.11/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.11/ui-grid.min.js b/release/3.0.0-rc.11/ui-grid.min.js
    new file mode 100644
    index 000000000..db0071ff4
    --- /dev/null
    +++ b/release/3.0.0-rc.11/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.11 - 2014-09-26
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(f.getStyles(angular.element(i.menu)[0])["padding-right"],10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup touchend",function(){c.cancel(j)}),a.$on("$destroy",function(){i.off("mousedown touchstart")}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,e=b.normalizeScrollLeft(d),f=-1,h=-1;if(e!==j.prevScrollLeft){var k=(e-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth());f=e/k,j.adjustScrollHorizontal(e,f)}if(a!==i.prevScrollTop){var l=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight());h=a/l,h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}if(!c.grid.isScrollingVertically&&!c.grid.isScrollingHorizontally){var m={};f>-1&&(m.x={percentage:f}),h>-1&&(m.y={percentage:h}),g.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl
    +},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.unshift(a),c.columns.forEach(function(a,b){a.index=b})}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));
    +h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,b,d,e){var f={};null!==d&&(f.y={percentage:d.index/a.renderContainers.body.visibleRowCache.length}),null!==e&&(f.x={percentage:this.getLeftWidth(a,e.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)}),(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0),b.grid.queueRefresh()}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})
    +}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=parseInt(h.drawnWidth+d,10);h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=parseInt(m,10),j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandable.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandable.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.11/ui-grid.svg b/release/3.0.0-rc.11/ui-grid.svg
    new file mode 100644
    index 000000000..4265b782c
    --- /dev/null
    +++ b/release/3.0.0-rc.11/ui-grid.svg
    @@ -0,0 +1,31 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xe800;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.11/ui-grid.ttf b/release/3.0.0-rc.11/ui-grid.ttf
    new file mode 100644
    index 000000000..d2dc304da
    Binary files /dev/null and b/release/3.0.0-rc.11/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.11/ui-grid.woff b/release/3.0.0-rc.11/ui-grid.woff
    new file mode 100644
    index 000000000..e11bc6564
    Binary files /dev/null and b/release/3.0.0-rc.11/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.12/ui-grid.css b/release/3.0.0-rc.12/ui-grid.css
    new file mode 100644
    index 000000000..dbbcfc837
    --- /dev/null
    +++ b/release/3.0.0-rc.12/ui-grid.css
    @@ -0,0 +1,1135 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: fixed;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.12/ui-grid.eot b/release/3.0.0-rc.12/ui-grid.eot
    new file mode 100644
    index 000000000..8609654ce
    Binary files /dev/null and b/release/3.0.0-rc.12/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.12/ui-grid.js b/release/3.0.0-rc.12/ui-grid.js
    new file mode 100644
    index 000000000..36ab2b30b
    --- /dev/null
    +++ b/release/3.0.0-rc.12/ui-grid.js
    @@ -0,0 +1,14558 @@
    +/*! ui-grid - v3.0.0-rc.12 - 2014-10-08
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // $log.error('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name disableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, but checking the disableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.disableHiding) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$log', '$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($log, $timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +        delete $scope.colElementPosition;
    +        delete $scope.columnElement;
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                if ($scope.col.colDef && !$scope.col.colDef.disableColumnMenu) {
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                }
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +    
    +            /** 
    +            * @ngdoc property
    +            * @name disableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, disables column menus for this specific
    +            * column
    +            *
    +            */
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ '$log', 'i18nService', function( $log, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        $scope.grid.gridMenuScope = null;
    +        $scope.grid = null;
    +        $scope.registeredMenuItems = null;
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        $log.error( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +        if ( value.id === id ){
    +          if (foundIndex > -1) {
    +            $log.error( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +          } else {
    +            
    +            foundIndex = index;
    +          }
    +        }
    +      });
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          $log.error( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs ) {
    +        $log.error( 'Something is wrong in showHideColumns, there are no columnDefs' );
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( !colDef.disableHiding ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        $log.error('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['$log', 'gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function ($log, gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +            $animate = gridUtil.enableAnimations(menuMid);
    +            if ( $animate ){
    +              $scope.shownMid = true;
    +              $animate.removeClass(menuMid, 'ng-hide', function() {
    +                $scope.$emit('menu-shown');
    +              });
    +            } else {
    +              $scope.shownMid = true;
    +              $scope.$emit('menu-shown');
    +            }
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +          if ( $animate ){
    +            $scope.shownMid = true;
    +            $animate.removeClass(menuMid, 'ng-hide', function() {
    +              $scope.$emit('menu-shown');
    +            });
    +          } else {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          }
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +
    +          if ( $animate ){
    +            $scope.shownMid = false;
    +            $animate.addClass(menuMid, 'ng-hide', function() {
    +              if ( !$scope.shownMid ){
    +                $scope.shown = false;
    +                $scope.$emit('menu-hidden');
    +              }
    +            });
    +          } else {
    +            $scope.shownMid = false;
    +            $scope.shown = false;
    +          }
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        $scope.$apply(function () {
    +          $scope.hideMenu();
    +        });
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refresh();
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === ( self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0 ) ) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name addRowHeaderColumn
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description adds a row header column to the grid
    +   * @param {object} column def
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortHandleNulls
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description A null handling method that can be used when building custom sort
    +   * functions
    +   * @example
    +   * <pre>
    +   *   mySortFn = function(a, b) {
    +   *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +   *   if ( nulls !== null ){
    +   *     return nulls;
    +   *   } else {
    +   *     // your code for sorting here
    +   *   };
    +   * </pre>
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.disableHiding = true;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description precompiles all cell templates
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow 
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', GridRow.prototype.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed, 
    +           * and that is the one that would have been useful.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', '$log', function(gridUtil, uiGridConstants, i18nService, $log) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.  A number of settings are supported:
    +    * 
    +    * - title: controls the title that is displayed in the menu
    +    * - icon: the icon shown alongside that title
    +    * - action: the method to call when the menu is clicked
    +    * - shown: a function to evaluate to determine whether or not to show the item
    +    * - active: a function to evaluate to determine whether or not the item is currently selected
    +    * - context: context to pass to the action function??
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       shown: function() { return true; },
    +    *       active: function() { return true; },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (!colDef.width.match(/^\*+$/)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      $log.error( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        return self.getAggregationText('aggregation.count', self.grid.getVisibleRowCount());
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        return self.getAggregationText('aggregation.sum', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        return self.getAggregationText('aggregation.avg', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return self.getAggregationText('aggregation.min', Math.min.apply(null, cellValues));
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return self.getAggregationText('aggregation.max', Math.max.apply(null, cellValues));
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +    
    +   /** 
    +    * @ngdoc property
    +    * @name aggregationHideLabel
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description defaults to false, if set to true hides the label text
    +    * in the aggregation footer, so only the value is displayed.
    +    *
    +    */
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationText
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description converts the aggregation value into a text string, including 
    +     * i18n and deciding whether or not to display based on colDef.aggregationHideLabel
    +     * 
    +     * @param {string} label the i18n lookup value to use for the column label
    +     * @param {number} value the calculated aggregate value for this column
    +     * 
    +     */
    +    GridColumn.prototype.getAggregationText = function ( label, value ) {
    +      var self = this;
    +      if ( self.colDef.aggregationHideLabel ){
    +        return value;
    +      } else {
    +        return i18nService.getSafeText(label) + value;
    +      }
    +    };
    +
    +    GridColumn.prototype.getCellTemplate = function () {
    +      var self = this;
    +
    +      return self.cellTemplatePromise;
    +    };
    +
    +    GridColumn.prototype.getCompiledElementFn = function () {
    +      var self = this;
    +      
    +      return self.compiledElementFnDefer.promise;
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    // Default time to throttle scroll events to.
    +    this.scrollThrottle = 70;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +            col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'gesamt reihen: ',
    +          sum: 'gesamt: ',
    +          avg: 'durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'aantal rijen: ',
    +          sum: 'som: ',
    +          avg: 'gemiddelde: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            args.y = { percentage: grid.renderContainers.body.visibleRowCache.indexOf(gridRow) / grid.renderContainers.body.visibleRowCache.length };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var grid = uiGridCtrl.grid;
    +              //needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = $scope.colContainer.cellNav.getNextRowCol(direction, $scope.row, $scope.col);
    +
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            evt.stopPropagation();
    +            evt.preventDefault();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          //this event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            console.log('setFocused: ' + div[0].parentElement.className);
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +            $scope.grid.queueRefresh();
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              console.log('begin edit');
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            $log.error( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +        grid.api.infiniteScroll.raise.needLoadMoreData();
    +        grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows ? grid.rowEditDirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows ? grid.rowEditErrorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          
    +          if (row.isSelected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: 'selectionRowHeaderCol',
    +                  displayName: '',
    +                  width: 30,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell'
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader  && !col.colDef.disableColumnMenu\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandable.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandable.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.12/ui-grid.min.css b/release/3.0.0-rc.12/ui-grid.min.css
    new file mode 100644
    index 000000000..afb2fd2fd
    --- /dev/null
    +++ b/release/3.0.0-rc.12/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:fixed;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.12/ui-grid.min.js b/release/3.0.0-rc.12/ui-grid.min.js
    new file mode 100644
    index 000000000..99ea998e7
    --- /dev/null
    +++ b/release/3.0.0-rc.12/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.12 - 2014-10-08
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){c.append(a)})});else{var i=b.col.cellTemplate.replace(e.MODEL_COL_FIELD,"row.entity."+d.preEval(b.col.field)).replace(e.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);c.append(j)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.disableHiding?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$log","$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d,e){var f={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(a,b,c,d){var f=this;e.initialize(a,d),a.defaultMenuItems=e.getDefaultMenuItems(a),a.menuItems=a.defaultMenuItems,e.setColMenuItemWatch(a),a.showMenu=function(c,d,g){a.col=c;var h=e.getColumnElementPosition(a,c,d);a.menuShown?(a.colElement=d,a.colElementPosition=h,a.hideThenShow=!0,a.$broadcast("hide-menu",{originalEvent:g})):(f.shown=a.menuShown=!0,e.repositionMenu(a,c,h,b,d),a.colElement=d,a.colElementPosition=h,a.$broadcast("show-menu",{originalEvent:g}))},a.hideMenu=function(b){delete a.col,a.menuShown=!1,b||a.$broadcast("hide-menu")},a.$on("menu-hidden",function(){a.hideThenShow?(delete a.hideThenShow,e.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),a.$broadcast("show-menu"),a.menuShown=!0):a.hideMenu(!0)}),a.$on("menu-shown",function(){e.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),delete a.colElementPosition,delete a.columnElement}),a.sortColumn=function(b,c){b.stopPropagation(),a.grid.sortColumn(a.col,c,!0).then(function(){a.grid.refresh(),a.hideMenu()})},a.unsortColumn=function(){a.col.unsort(),a.grid.refresh(),a.hideMenu()},a.hideColumn=function(){a.col.colDef.visible=!1,a.grid.refresh(),a.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return f}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.renderContainer=i.grid.renderContainers[j.containerId],b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var k=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var l,m=0;if(k.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(m=(new Date).getTime(),l=c(function(){},h),l.then(function(){a.col.colDef&&!a.col.colDef.disableColumnMenu&&i.columnMenuScope.showMenu(a.col,b,d)}))}),k.on("mouseup touchend",function(){c.cancel(l)}),a.$on("$destroy",function(){k.off("mousedown touchstart")}),a.toggleMenu=function(c){c.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,b)},a.sortable&&(k.on("click touchend",function(a){a.stopPropagation(),c.cancel(l);var b=(new Date).getTime(),d=b-m;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(l)})),a.filterable){var n=[];angular.forEach(a.col.filters,function(b,c){n.push(a.$watch("col.filters["+c+"].term",function(){i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(n,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.replaceWith(f),j.header=f,j.colContainer.header=f,b=f,j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),m.length>0&&(m[m.length-1].headerWidth=m[m.length-1].drawnWidth-30),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["$log","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.$on("$destroy",function(){a.grid.gridMenuScope=null,a.grid=null,a.registeredMenuItems=null}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c):a.error("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.error("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.error("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(d){var e=[];return d.grid.options.columnDefs?(e.push({title:b.getSafeText("gridMenu.columns")}),d.grid.options.gridMenuTitleFilter=d.grid.options.gridMenuTitleFilter?d.grid.options.gridMenuTitleFilter:function(a){return a},d.grid.options.columnDefs.forEach(function(a){if(!a.disableHiding){var b={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:d.grid.getColumn(a.name||a.field)}};c.setMenuItemTitle(b,a,d.grid),e.push(b),b={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:d.grid.getColumn(a.name||a.field)}},c.setMenuItemTitle(b,a,d.grid),e.push(b)}}),e):(a.error("Something is wrong in showHideColumns, there are no columnDefs"),e)},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.error("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["$log","gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c,d){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,c,e){var f=e[0];d.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=d.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){var e,h,i=this;i.showMenu=a.showMenu=function(d,g){a.shown?a.shownMid||(e=b[0].querySelectorAll(".ui-grid-menu-mid"),h=f.enableAnimations(e),h?(a.shownMid=!0,h.removeClass(e,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))):(a.shown=!0,c(function(){e=b[0].querySelectorAll(".ui-grid-menu-mid"),h=f.enableAnimations(e),h?(a.shownMid=!0,h.removeClass(e,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))}));var i="click";g&&g.originalEvent&&g.originalEvent.type&&"touchstart"===g.originalEvent.type&&(i=g.originalEvent.type),angular.element(document).off("click touchstart",j),c(function(){angular.element(document).on(i,j)})},i.hideMenu=a.hideMenu=function(){a.shown&&(e=b[0].querySelectorAll(".ui-grid-menu-mid"),h=f.enableAnimations(e),h?(a.shownMid=!1,h.addClass(e,"ng-hide",function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))})):(a.shownMid=!1,a.shown=!1)),angular.element(document).off("click touchstart",j)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var j=function(){a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",j),a.$on("$destroy",function(){angular.element(document).off("click touchstart",j)}),a.$on("$destroy",function(){angular.element(d).off("resize",j)}),a.$on("$destroy",a.$on(g.events.GRID_SCROLL,j)),a.$on("$destroy",a.$on(g.events.ITEM_DRAGGING,j))},controller:["$scope","$element","$attrs",function(){}]};return h}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){{var g=f[0];f[1]}("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),b.$emit("hide-menu")}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();angular.isNumber(f)||(f=0);var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(f,g,h,i){function j(a,b){if(b.y&&f.bindScrollVertical){o.prevScrollArgs=b;var c=q.getCanvasHeight()-q.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(c+=p.horizontalScrollbarHeight);var d,g=o.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)d=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,d*c);o.viewport[0].scrollTop=h,o.prevScrollArgs.y.pixels=h-g}if(b.x&&f.bindScrollHorizontal){o.prevScrollArgs=b;var i,j=r.getCanvasWidth()-r.getViewportWidth(),k=e.normalizeScrollLeft(o.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);o.viewport[0].scrollLeft=e.denormalizeScrollLeft(o.viewport,l),o.prevScrollLeft=l,o.headerViewport&&(o.headerViewport.scrollLeft=e.denormalizeScrollLeft(o.headerViewport,l)),o.footerViewport&&(o.footerViewport.scrollLeft=e.denormalizeScrollLeft(o.footerViewport,l)),o.prevScrollArgs.x.pixels=l-k}}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-w),c=-(e-v),z=1>c?-1:1,A=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(x+c)/(q.getCanvasHeight()-q.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(y+b)/(r.getCanvasWidth()-r.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}n.fireScrollingEvent(f)}function l(a){function d(){b(function(){var b={target:a.target};if(0!==t){var c=(o.viewport[0].scrollTop+t)/(q.getCanvasHeight()-q.getViewportHeight());b.y={percentage:c,pixels:t}}if(0!==v){var e=(o.viewport[0].scrollLeft+v)/(r.getCanvasWidth()-r.getViewportWidth());b.x={percentage:e,pixels:v}}n.fireScrollingEvent(b),s-=1,t/=2,v/=2,s>0?d():n.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},p)}a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",k),c.unbind("touchend",l),c.unbind("touchcancel",l);var e=o.viewport[0].scrollTop,f=o.viewport[0].scrollTop,g=Math.abs(e-x),h=Math.abs(f-y),i=new Date-u,j=g/i,m=h/i,p=63,s=8,t=120*z*j,v=120*A*m;d()}function m(){var a="",b=r.getCanvasWidth(),c=r.getViewportWidth(),d=q.getCanvasHeight(),e=q.getViewportHeight(),g=r.getHeaderViewportWidth(),h=r.getHeaderViewportWidth();return a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==s.explicitHeaderHeight&&null!==s.explicitHeaderHeight&&s.explicitHeaderHeight>0?a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-header-cell { height: "+s.explicitHeaderHeight+"px; }":void 0!==s.innerHeaderHeight&&null!==s.innerHeaderHeight&&s.innerHeaderHeight>0&&(a+="\n .grid"+n.grid.id+" .ui-grid-render-container-"+f.containerId+" .ui-grid-header-cell { height: "+s.innerHeaderHeight+"px; }"),a}a.debug("render container "+f.containerId+" post-link");var n=i[0],o=i[1],p=n.grid,q=o.rowContainer,r=o.colContainer,s=p.renderContainers[f.containerId];g.addClass("ui-grid-render-container-"+f.containerId);var t;(f.bindScrollHorizontal||f.bindScrollVertical)&&(t=f.$on(d.events.GRID_SCROLL,j)),g.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:g};if(0!==b.deltaY){var d=-120*b.deltaY,f=(o.viewport[0].scrollTop+d)/(q.getCanvasHeight()-q.getViewportHeight());0>f?f=0:f>1&&(f=1),c.y={percentage:f,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(o.viewport),j=(i+h)/(r.getCanvasWidth()-r.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}n.fireScrollingEvent(c)});var u,v=0,w=0,x=0,y=0,z=1,A=1;e.isTouchEnabled()&&g.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),n.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),u=new Date,v=a.targetTouches[0].screenY,w=a.targetTouches[0].screenX,x=o.viewport[0].scrollTop,y=o.viewport[0].scrollLeft,c.on("touchmove",k),c.on("touchend touchcancel",l)}),g.bind("$destroy",function(){t(),g.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){g.unbind(a)})}),n.grid.registerStyleComputation({priority:6,func:m})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,e=b.normalizeScrollLeft(d),f=-1,h=-1;if(e!==j.prevScrollLeft){var k=(e-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth());f=e/k,j.adjustScrollHorizontal(e,f)}if(a!==i.prevScrollTop){var l=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight());h=a/l,h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}if(!c.grid.isScrollingVertically&&!c.grid.isScrollingHorizontally){var m={};f>-1&&(m.x={percentage:f}),h>-1&&(m.y={percentage:h}),g.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")
    +})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refresh()}))}function n(b){var e=[];b&&(o.grid.columns.length===(o.grid.rowHeaderColumns?o.grid.rowHeaderColumns.length:0)&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===e.getStyles(b[0]).direction,o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=e.throttle(function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.grid.options.scrollThrottle,{trailing:!0}),o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",k.handleNulls),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.disableHiding=!0,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c,d=this,f=[],g=d.rowHeaderColumns.length;for(c=0;c<d.columns.length;c++)d.getColDef(d.columns[c].name)||(d.columns.splice(c,1),c--);return d.rowHeaderColumns.forEach(function(a){d.columns.unshift(a)}),d.options.columnDefs.forEach(function(a,b){d.preprocessColDef(a);var c=d.getColumn(a.name);c?c.updateColumnDef(a):(c=new h(a,e.nextUid(),d),d.columns.splice(b+g,0,c)),d.columnBuilders.forEach(function(b){f.push(b.call(d,a,c,d.options))})}),b.all(f)},p.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(b){var d=b.cellTemplate.replace(f.MODEL_COL_FIELD,a.getQualifiedColField(b));d=d.replace(f.COL_FIELD,"grid.getCellValue(row, col)");var e=c(d);b.compiledElementFn=e,b.compiledElementFnDefer&&b.compiledElementFnDefer.resolve(b.compiledElementFn)})},p.prototype.getQualifiedColField=function(a){return"row.entity."+e.preEval(a.field)},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?a.colDef&&a.colDef.suppressRemoveSort?f.ASC:null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){var b,g,h=!1,i=0;for(b=0;b<f.length;b++)if(g=f[b],g.header){var j=g.headerHeight,k=e.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=e.getBorderSize(g.header,"top"),m=e.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(b=0;b<f.length;b++)g=f[b],g.headerHeight<i&&(g.explicitHeaderHeight=i);a&&h&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e,f){function g(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var h=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",f.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",f.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",f.prototype.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return h.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=g(a.scope,a.eventId,a.handler,c.grid)})},h.prototype.registerEvent=function(b,d){var e=this;e[b]||(e[b]={});var f=e[b];f.on||(f.on={},f.raise={});var h=e.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),f.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),f.on[d]=function(a,b){var c=g(a,h,b,e.grid),d={handler:b,dereg:c,eventId:h,scope:a};e.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},h.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},h.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},h.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},h}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService","$log",function(a,b,c,d){function e(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return e.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},e.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);e.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())},c.minWidth=b.minWidth?b.minWidth:50,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&d.error("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.cellClass=b.cellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&i.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",i)},e.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},e.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},e.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},e.prototype.showColumn=function(){this.colDef.visible=!0},e.prototype.hideColumn=function(){this.colDef.visible=!1},e.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.getAggregationText("aggregation.count",a.grid.getVisibleRowCount()):a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),a.getAggregationText("aggregation.sum",c)):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,a.getAggregationText("aggregation.avg",c)):a.aggregationType===b.aggregationTypes.min?a.getAggregationText("aggregation.min",Math.min.apply(null,e)):a.aggregationType===b.aggregationTypes.max?a.getAggregationText("aggregation.max",Math.max.apply(null,e)):null},e.prototype.getAggregationText=function(a,b){var d=this;return d.colDef.aggregationHideLabel?b:c.getSafeText(a)+b},e.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},e.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},e}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.scrollThrottle=70,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);
    +this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)&&b.endsWith(a.width,"%")),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell",d.cellTemplatePromise=a.getTemplate(c.cellTemplate)),d.cellTemplatePromise=a.getTemplate(c.cellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=p.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=p.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"},aggregation:{count:"gesamt reihen: ",sum:"gesamt: ",avg:"durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"aantal rijen: ",sum:"som: ",avg:"gemiddelde: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();
    +return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.factory("uiGridCellNavFactory",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};null!==d&&(f.y={percentage:a.renderContainers.body.visibleRowCache.indexOf(d)/a.renderContainers.body.visibleRowCache.length}),null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$log","uiGridCellNavService","uiGridCellNavConstants",function(a,b){return{replace:!0,priority:-99999,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(){},post:function(a,c,d,e){var f=e.grid;b.decorateRenderContainers(f)}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");console.log("setFocused: "+a[0].parentElement.className),a[0].focus(),a.attr("tabindex",0),b.grid.queueRefresh()}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=b.colContainer.cellNav.getNextRowCol(d,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),c.stopPropagation(),c.preventDefault(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){console.log("begin edit"),a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.MODEL_COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(b,c,d,e){var f=this.getColumnHeaders(b,d),g=this.getData(b,c,d),h=this.formatAsCsv(f,g);!e&&b.options.exporterCsvLinkElement&&(e=b.options.exporterCsvLinkElement),e?this.renderCsvLink(b,h,e):a.error("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return h}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=parseInt(h.drawnWidth+d,10);
    +h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.width=parseInt(m,10),j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows?a.rowEditDirtyRows:[]},getErrorRows:function(a){return a.rowEditErrorRows?a.rowEditErrorRows:[]},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;d||f||a.clearSelectedRows(b),c.isSelected&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell"};e.grid.addRowHeaderColumn(f)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):b.ctrlKey||b.metaKey?c.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):c.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenu && !col.isRowHeader  && !col.colDef.disableColumnMenu" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandable.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandable.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.12/ui-grid.svg b/release/3.0.0-rc.12/ui-grid.svg
    new file mode 100644
    index 000000000..18634ed72
    --- /dev/null
    +++ b/release/3.0.0-rc.12/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m0 29v71q0 15 11 25t25 11h785q15 0 26-11t10-25v-71q0-15-10-26t-26-10h-785q-15 0-25 10t-11 26z m0 285v72q0 14 11 25t25 10h785q15 0 26-10t10-25v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25z m0 286v71q0 15 11 26t25 10h785q15 0 26-10t10-26v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.12/ui-grid.ttf b/release/3.0.0-rc.12/ui-grid.ttf
    new file mode 100644
    index 000000000..081bc1440
    Binary files /dev/null and b/release/3.0.0-rc.12/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.12/ui-grid.woff b/release/3.0.0-rc.12/ui-grid.woff
    new file mode 100644
    index 000000000..e1a95cbf5
    Binary files /dev/null and b/release/3.0.0-rc.12/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.13/ui-grid.css b/release/3.0.0-rc.13/ui-grid.css
    new file mode 100644
    index 000000000..d4db23438
    --- /dev/null
    +++ b/release/3.0.0-rc.13/ui-grid.css
    @@ -0,0 +1,1221 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: fixed;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.13/ui-grid.eot b/release/3.0.0-rc.13/ui-grid.eot
    new file mode 100644
    index 000000000..8609654ce
    Binary files /dev/null and b/release/3.0.0-rc.13/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.13/ui-grid.js b/release/3.0.0-rc.13/ui-grid.js
    new file mode 100644
    index 000000000..a97f7368e
    --- /dev/null
    +++ b/release/3.0.0-rc.13/ui-grid.js
    @@ -0,0 +1,17076 @@
    +/*! ui-grid - v3.0.0-rc.13 - 2014-11-05
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column'
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          var deregisterFunction = function() {
    +           $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +        delete $scope.colElementPosition;
    +        delete $scope.columnElement;
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.headerCellClass) {
    +              updateClass();
    +            }
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            var deregisterFunction = function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            };
    +
    +            $scope.$on( '$destroy', deregisterFunction );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false) {
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                }
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +
    +
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', function( gridUtil, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +            $animate = gridUtil.enableAnimations(menuMid);
    +            if ( $animate ){
    +              $scope.shownMid = true;
    +              $animate.removeClass(menuMid, 'ng-hide', function() {
    +                $scope.$emit('menu-shown');
    +              });
    +            } else {
    +              $scope.shownMid = true;
    +              $scope.$emit('menu-shown');
    +            }
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +          if ( $animate ){
    +            $scope.shownMid = true;
    +            $animate.removeClass(menuMid, 'ng-hide', function() {
    +              $scope.$emit('menu-shown');
    +            });
    +          } else {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          }
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +
    +          if ( $animate ){
    +            $scope.shownMid = false;
    +            $animate.addClass(menuMid, 'ng-hide', function() {
    +              if ( !$scope.shownMid ){
    +                $scope.shown = false;
    +                $scope.$emit('menu-hidden');
    +              }
    +            });
    +          } else {
    +            $scope.shownMid = false;
    +            $scope.shown = false;
    +          }
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        $scope.$apply(function () {
    +          $scope.hideMenu();
    +        });
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // gridUtil.logDebug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // gridUtil.logDebug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil',
    +    function(gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +              
    +              self.grid.refresh();
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (n) {
    +          if (self.grid.columns.length === ( self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0 ) ) {
    +            // gridUil.logDebug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = GridOptions.initialize( options );
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +  self.dataChangeCallbacks = {};
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name addRowHeaderColumn
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description adds a row header column to the grid
    +   * @param {object} column def
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortHandleNulls
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description A null handling method that can be used when building custom sort
    +   * functions
    +   * @example
    +   * <pre>
    +   *   mySortFn = function(a, b) {
    +   *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +   *   if ( nulls !== null ){
    +   *     return nulls;
    +   *   } else {
    +   *     // your code for sorting here
    +   *   };
    +   * </pre>
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +
    +  /**
    +   * @ngdoc method
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Notify the grid that a data or config change has occurred,
    +   * where that change isn't something the grid was otherwise noticing.  This 
    +   * might be particularly relevant where you've changed values within the data
    +   * and you'd like cell classes to be re-evaluated, or changed config within 
    +   * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +   * @param {Grid} grid the grid
    +   * @param {string} type one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +   * us which refreshes to fire.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN ).  Optional and defaults to
    +   * ALL 
    +   * @returns {string} uid of the callback, can be used to deregister it again
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types };
    +    return uid;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name deregisterDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description Delete the callback identified by the id.
    +   * @param {string} uid the uid of the function that is to be deregistered
    +   */
    +  Grid.prototype.deregisterDataChangeCallback = function deregisterDataChangeCallback(uid) {
    +    delete this.dataChangeCallbacks[uid];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, and COLUMN callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        callback.callback( this );
    +      }
    +    });
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {Grid} grid the grid
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(grid, type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ){
    +      grid.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow 
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', GridRow.prototype.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed, 
    +           * and that is the one that would have been useful.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.  A number of settings are supported:
    +    * 
    +    * - title: controls the title that is displayed in the menu
    +    * - icon: the icon shown alongside that title
    +    * - action: the method to call when the menu is clicked
    +    * - shown: a function to evaluate to determine whether or not to show the item
    +    * - active: a function to evaluate to determine whether or not the item is currently selected
    +    * - context: context to pass to the action function??
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       shown: function() { return true; },
    +    *       active: function() { return true; },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        return self.getAggregationText('aggregation.count', self.grid.getVisibleRowCount());
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        return self.getAggregationText('aggregation.sum', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        return self.getAggregationText('aggregation.avg', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return self.getAggregationText('aggregation.min', Math.min.apply(null, cellValues));
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return self.getAggregationText('aggregation.max', Math.max.apply(null, cellValues));
    +      }
    +      else {
    +        return '\u00A0';
    +      }
    +    };
    +    
    +   /** 
    +    * @ngdoc property
    +    * @name aggregationHideLabel
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description defaults to false, if set to true hides the label text
    +    * in the aggregation footer, so only the value is displayed.
    +    *
    +    */
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationText
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description converts the aggregation value into a text string, including 
    +     * i18n and deciding whether or not to display based on colDef.aggregationHideLabel
    +     * 
    +     * @param {string} label the i18n lookup value to use for the column label
    +     * @param {number} value the calculated aggregate value for this column
    +     * 
    +     */
    +    GridColumn.prototype.getAggregationText = function ( label, value ) {
    +      var self = this;
    +      if ( self.colDef.aggregationHideLabel ){
    +        return value;
    +      } else {
    +        return i18nService.getSafeText(label) + value;
    +      }
    +    };
    +
    +    GridColumn.prototype.getCellTemplate = function () {
    +      var self = this;
    +
    +      return self.cellTemplatePromise;
    +    };
    +
    +    GridColumn.prototype.getCompiledElementFn = function () {
    +      var self = this;
    +      
    +      return self.compiledElementFnDefer.promise;
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +  
    +      baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +      baseOptions.maxVisibleRowCount = baseOptions.maxVisibleRowCount || 200;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      baseOptions.showFooter = baseOptions.showFooter === true;
    +      baseOptions.footerRowHeight = typeof(baseOptions.footerRowHeight) !== "undefined" ? baseOptions.footerRowHeight : 30;
    +  
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      // Turn virtualization on when number of data elements goes over this number
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      // Extra rows to to render outside of the viewport
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      // Extra columns to to render outside of the viewport
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      // Default time to throttle scroll events to.
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableScrollbars
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this settings enable vertical
    +       * and horizontal scrollbar for grid.
    +       */
    +      baseOptions.enableScrollbars = baseOptions.enableScrollbars !== false;
    +  
    +      // Columns can't be smaller than 10 pixels
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', function(gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //gridUtil.logDebug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +            col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logDebug: function( logMessage ){
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug( logMessage );
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Total Artículos:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'total filas: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar nombres de columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿existe información aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'Archivo json importado debe contener un arreglo, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.refresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so 
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         * 
    +         * To get to row 9 (i.e. the last row) in the same list, we want to 
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll, 
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            args.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var grid = uiGridCtrl.grid;
    +              //needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, gridUtil, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = $scope.colContainer.cellNav.getNextRowCol(direction, $scope.row, $scope.col);
    +
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            evt.stopPropagation();
    +            evt.preventDefault();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          //this event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            // gridUtil.logDebug('setFocused: ' + div[0].parentElement.className);
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +            $scope.grid.queueRefresh();
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( $scope.grid, uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight; 
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = grid.getColumn('expandableButtons').width;
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + displayName; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCOl and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            gridUtil.logError( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? grid.options.exporterHeaderFilter(gridCol.displayName) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  extractedRow.push( grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) );
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +
    +              var template = angular.element(contents);
    +
    +              template.children("a").html(
    +                  template.children("a").html().replace(
    +                      uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel));
    +
    +              template.children("a").attr("href", 
    +                  template.children("a").attr("href").replace(
    +                      uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent)));
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.content.unshift( grid.options.exporterPdfHeader );
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.content.push( grid.options.exporterPdfFooter );
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {Grid} grid the grid we're importing into
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( grid, fileObject ) {
    +                  service.importFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and ift he rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var callbackId = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( grid, newObjects );
    +              grid.deregisterDataChangeCallback( callbackId );
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            var deregisterClosure = function() {
    +              grid.deregisterDataChangeCallback( callbackId );
    +            };
    +  
    +            grid.importer.$scope.$on( '$destroy', deregisterClosure );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            if (event.srcElement.files.length === 1) {
    +              var fileObject = event.srcElement.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              event.srcElement.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', function ($q, $timeout) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.on.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                self.redrawColumnAtPosition(grid, originalPosition, finalPosition);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +        var columns = grid.columns;
    +
    +        //Function to find column position for a render index, ths is needed to take care of
    +        // invisible columns and row headers
    +        var findPositionForRenderIndex = function (index) {
    +          var position = index;
    +          for (var i = 0; i <= position; i++) {
    +            if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +              position++;
    +            }
    +          }
    +          return position;
    +        };
    +
    +        originalPosition = findPositionForRenderIndex(originalPosition);
    +        newPosition = findPositionForRenderIndex(newPosition);
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and coned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                var mouseDownHandler = function (evt) {
    +                  if (evt.toElement.className !== 'ui-grid-icon-angle-down') {
    +
    +                    //Cloning header cell and appending to current header cell.
    +                    var movingElm = $elm.clone();
    +                    $elm.append(movingElm);
    +
    +                    //Left of cloned element should be aligned to original header cell.
    +                    movingElm.addClass('movingColumn');
    +                    var movingElementStyles = {};
    +                    var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                    var elmLeft = $elm[0].getBoundingClientRect().left;
    +                    movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                    var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                    var elmRight = $elm[0].getBoundingClientRect().right;
    +                    var reducedWidth;
    +                    if (elmRight > gridRight) {
    +                      reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                      movingElementStyles.width = reducedWidth + 'px';
    +                    }
    +                    //movingElementStyles.visibility = 'hidden';
    +                    movingElm.css(movingElementStyles);
    +
    +                    //Setting some variables required for calculations.
    +                    var previousMouseX = evt.pageX;
    +                    var totalMouseMovement = 0;
    +                    var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth() - $scope.grid.verticalScrollbarWidth;
    +
    +                    //Clone element should move horizontally with mouse.
    +                    var mouseMoveHandler = function (evt) {
    +                      uiGridCtrl.fireEvent('hide-menu');
    +                      var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                      var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                      var changeValue = evt.pageX - previousMouseX;
    +                      var newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                      newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +                      if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                        movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                      }
    +                      else {
    +                        changeValue *= 5;
    +                        uiGridCtrl.fireScrollingEvent({ x: { pixels: changeValue * 2.5} });
    +                      }
    +                      totalMouseMovement += changeValue;
    +                      previousMouseX = evt.pageX;
    +                      if (reducedWidth < $scope.col.drawnWidth) {
    +                        reducedWidth += Math.abs(changeValue);
    +                        movingElm.css({'width': reducedWidth + 'px'});
    +                      }
    +                    };
    +
    +                    // On scope destroy, remove the mouse event handlers from the document body
    +                    $scope.$on('$destroy', function () {
    +                      $document.off('mousemove', mouseMoveHandler);
    +                      $document.off('mouseup', mouseUpHandler);
    +                    });
    +
    +                    $document.on('mousemove', mouseMoveHandler);
    +                    var mouseUpHandler = function (evt) {
    +                      var renderIndexDefer = $q.defer();
    +
    +                      var renderIndex;
    +                      $attrs.$observe('renderIndex', function (n, o) {
    +                        renderIndex = $scope.$eval(n);
    +                        renderIndexDefer.resolve();
    +                      });
    +
    +                      renderIndexDefer.promise.then(function () {
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var renderedColumns = $scope.grid.renderContainers['body'].renderedColumns;
    +
    +                        //This method will calculate the number of columns hidden in lift due to scroll
    +                        //renderContainer.prevColumnScrollIndex could also have been used but this is more accurate
    +                        var scrolledColumnCount = 0;
    +                        var columns = $scope.grid.columns;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== renderedColumns[0].colDef.name) {
    +                            scrolledColumnCount++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = renderIndex - 1; il >= 0; il--) {
    +                            totalColumnsLeftWidth += renderedColumns[il].drawnWidth;
    +                            if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + il + 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + 0);
    +                          }
    +                        }
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = renderIndex + 1; ir < renderedColumns.length; ir++) {
    +                            totalColumnsRightWidth += renderedColumns[ir].drawnWidth;
    +                            if (totalColumnsRightWidth > totalMouseMovement) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + ir - 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + renderedColumns.length - 1);
    +                          }
    +                        }
    +                        else if (totalMouseMovement === 0) {
    +                          //sort the current column
    +                          var add = false;
    +                          if (evt.shiftKey) {
    +                            add = true;
    +                          }
    +
    +                          // Sort this column then rebuild the grid's rows
    +                          uiGridCtrl.grid.sortColumn($scope.col, add)
    +                            .then(function () {
    +                              if (uiGridCtrl.columnMenuScope) {
    +                                uiGridCtrl.columnMenuScope.hideMenu();
    +                              }
    +                              uiGridCtrl.grid.refresh();
    +                            });
    +                        }
    +
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      });
    +                    };
    +
    +                    $document.on('mouseup', mouseUpHandler);
    +                  }
    +                };
    +
    +                $elm.on('mousedown', mouseDownHandler);
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', function () {
    +    var service = {
    +
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +        grid.pagination = {page: 1, totalPages: 1};
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.pagination.api:PublicAPI
    +         *
    +         * @description Public API for the pagination feature
    +         */
    +        var publicApi = {
    +          methods: {
    +            pagination: {
    +              /**
    +               * @ngdoc method
    +               * @name getPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the number of the current page
    +               */
    +              getPage: function () {
    +                return grid.pagination.page;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name getTotalPages
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the total number of pages
    +               */
    +              getTotalPages: function () {
    +                return grid.pagination.totalPages;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name nextPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the next page, if possible
    +               */
    +              nextPage: function () {
    +                grid.pagination.page++;
    +                grid.refresh();
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name previousPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the previous page, if we're not on the first page
    +               */
    +              previousPage: function () {
    +                grid.pagination.page = Math.max(1, grid.pagination.page - 1);
    +                grid.refresh();
    +              },
    +              seek: function (page) {
    +                if (!angular.isNumber(page) || page < 1) {
    +                  throw 'Invalid page number: ' + page;
    +                }
    +
    +                grid.pagination.page = page;
    +                grid.refresh();
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +        grid.registerRowsProcessor(function (renderableRows) {
    +          if (!grid.options.enablePagination) {
    +            return renderableRows;
    +          }
    +          grid.pagination.totalPages = Math.max(
    +            1,
    +            Math.ceil(renderableRows.length / grid.options.rowsPerPage)
    +          );
    +
    +          var firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          if (firstRow >= renderableRows.length) {
    +            grid.pagination.page = grid.pagination.totalPages;
    +            firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          }
    +
    +          return renderableRows.slice(
    +            firstRow,
    +            firstRow + grid.options.rowsPerPage
    +          );
    +        });
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pagination.api:GridOptions
    +         *
    +         *  @description GridOptions for the pagination feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePagination
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description Enable pagination for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name rowsPerPage
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description The number of rows that should be displayed per page
    +         *  <br/>Defaults to 10
    +         */
    +        gridOptions.rowsPerPage = angular.isNumber(gridOptions.rowsPerPage) ? gridOptions.rowsPerPage : 10;
    +      }
    +    };
    +
    +    return service;
    +  });
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.pagination.directive:uiGridPagination
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description Adds pagination support to a grid.
    +   */
    +  module.directive('uiGridPagination', ['uiGridPaginationService', function (uiGridPaginationService) {
    +    return {
    +      priority: -400,
    +      scope: false,
    +      require: '^uiGrid',
    +      link: {
    +        pre: function (scope, element, attrs, uiGridCtrl) {
    +          uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      }
    +    };
    +  }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', function (gridUtil, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {object} grid the grid for which rows should be set dirty
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function (grid, dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.api:PublicApi
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing 
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected ){
    +                      row.isSelected = true;
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected){
    +                        row.isSelected = true;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.isSelected = false;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                getSelectAllState: function (grid) {
    +                  return grid.selection.selectAll;
    +                }
    +                
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead  
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid);
    +            }
    +          }
    +          
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected ){
    +                rowToSelect.isSelected = true;
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.isSelected = false;
    +              service.decideRaiseSelectionEvent( grid, row, changedRows );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and 
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows);
    +          }
    +        }        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width: 30,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +          
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows();
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              var touchStartTime = 0;
    +              var touchTimeout = 300;
    +              var selectCells = function(evt){
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              };
    +
    +              $elm.on('touchstart', function(event) {
    +                touchStartTime = (new Date()).getTime();
    +              });
    +
    +              $elm.on('touchend', function (evt) {
    +                var touchEndTime = (new Date()).getTime();
    +                var touchTime = touchEndTime - touchStartTime;
    +
    +                if (touchTime < touchTimeout ) {
    +                  // short touch
    +                  selectCells(evt);
    +                }
    +              });
    +
    +              $elm.on('click', function (evt) {
    +                selectCells(evt);
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.13/ui-grid.min.css b/release/3.0.0-rc.13/ui-grid.min.css
    new file mode 100644
    index 000000000..7554e5ec6
    --- /dev/null
    +++ b/release/3.0.0-rc.13/ui-grid.min.css
    @@ -0,0 +1,12 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:fixed;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +
    +.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.13/ui-grid.min.js b/release/3.0.0-rc.13/ui-grid.min.js
    new file mode 100644
    index 000000000..07da131f2
    --- /dev/null
    +++ b/release/3.0.0-rc.13/ui-grid.min.js
    @@ -0,0 +1,8 @@
    +/*! ui-grid - v3.0.0-rc.13 - 2014-11-05
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column"}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){b.addClass(a.col.getColClass(!1));var c,e=function(){var d=b;c&&(d.removeClass(c),c=null),c=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,d.addClass(c)};a.col.cellClass&&e();var f=a.grid.registerDataChangeCallback(e,[d.dataChange.COLUMN,d.dataChange.EDIT]),g=function(){a.grid.deregisterDataChangeCallback(f)};a.$on("$destroy",g)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(a,b,c,e){var f=this;d.initialize(a,e),a.defaultMenuItems=d.getDefaultMenuItems(a),a.menuItems=a.defaultMenuItems,d.setColMenuItemWatch(a),a.showMenu=function(c,e,g){a.col=c;var h=d.getColumnElementPosition(a,c,e);a.menuShown?(a.colElement=e,a.colElementPosition=h,a.hideThenShow=!0,a.$broadcast("hide-menu",{originalEvent:g})):(f.shown=a.menuShown=!0,d.repositionMenu(a,c,h,b,e),a.colElement=e,a.colElementPosition=h,a.$broadcast("show-menu",{originalEvent:g}))},a.hideMenu=function(b){a.menuShown=!1,b||a.$broadcast("hide-menu")},a.$on("menu-hidden",function(){a.hideThenShow?(delete a.hideThenShow,d.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),a.$broadcast("show-menu"),a.menuShown=!0):a.hideMenu(!0)}),a.$on("menu-shown",function(){d.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),delete a.colElementPosition,delete a.columnElement}),a.sortColumn=function(b,c){b.stopPropagation(),a.grid.sortColumn(a.col,c,!0).then(function(){a.grid.refresh(),a.hideMenu()})},a.unsortColumn=function(){a.col.unsort(),a.grid.refresh(),a.hideMenu()},a.hideColumn=function(){a.col.colDef.visible=!1,a.grid.refresh(),a.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,c){function e(e){b.getTemplate(e).then(function(b){var e=d(b),f=e(a);c.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,d,e){a.grid=e.grid,a.getExternalScopes=e.getExternalScopes,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",function(){a.grid.deregisterDataChangeCallback(h)})}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,a.getExternalScopes=h.getExternalScopes,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,e){function h(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.getExternalScopes=i.getExternalScopes,a.renderContainer=i.grid.renderContainers[j.containerId],c.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var k,l=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),m=function(){var b=c;k&&(b.removeClass(k),k=null),k=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(k)};a.col.headerCellClass&&m();var n=a.grid.registerDataChangeCallback(m,[f.dataChange.COLUMN]),o=function(){a.grid.deregisterDataChangeCallback(n)};a.$on("$destroy",o),a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var p,q=0;if(l.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(q=(new Date).getTime(),p=b(function(){},g),p.then(function(){a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1&&i.columnMenuScope.showMenu(a.col,c,d)}))}),l.on("mouseup touchend",function(){b.cancel(p)}),a.$on("$destroy",function(){l.off("mousedown touchstart")}),a.toggleMenu=function(b){b.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,c)},a.sortable&&(l.on("click touchend",function(a){a.stopPropagation(),b.cancel(p);var c=(new Date).getTime(),d=c-q;d>g||h(a)}),a.$on("$destroy",function(){b.cancel(p)})),a.filterable){var r=[];angular.forEach(a.col.filters,function(b,c){r.push(a.$watch("col.filters["+c+"].term",function(){i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(r,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,a.getExternalScopes=i.getExternalScopes,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.hideHeader?f:a.grid.options.headerTemplate?a.grid.options.headerTemplate:e,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth();"undefined"!=typeof g.grid.verticalScrollbarWidth&&void 0!==g.grid.verticalScrollbarWidth&&g.grid.verticalScrollbarWidth>0&&(a+=g.grid.verticalScrollbarWidth);var b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,j=a,k=!1,l=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(j/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",k=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,k=!0)});var m=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return m.indexOf(a.widthType)-m.indexOf(b.widthType)}).forEach(function(a){var b=l(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,j-=a.drawnWidth}),k&&j>0&&c>0&&a>c){var n=function(a){j>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,j--)},o=0;do o=j,b.forEach(n);while(j>0&&j!==o)}c=Math.max(c,a);var p="";return b.forEach(function(a){p+=a.getColClassDefinition()}),i.verticalScrollbarWidth&&(c+=i.verticalScrollbarWidth),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),p}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(a){var d=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(d.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};c.setMenuItemTitle(e,b,a.grid),d.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},c.setMenuItemTitle(e,b,a.grid),d.push(e)}}),d):d},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d){var g,h,i=this;i.showMenu=a.showMenu=function(c,f){a.shown?a.shownMid||(g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!0,h.removeClass(g,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))):(a.shown=!0,b(function(){g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!0,h.removeClass(g,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))}));var i="click";f&&f.originalEvent&&f.originalEvent.type&&"touchstart"===f.originalEvent.type&&(i=f.originalEvent.type),angular.element(document).off("click touchstart",j),b(function(){angular.element(document).on(i,j)})},i.hideMenu=a.hideMenu=function(){a.shown&&(g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!1,h.addClass(g,"ng-hide",function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))})):(a.shownMid=!1,a.shown=!1)),angular.element(document).off("click touchstart",j)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var j=function(){a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",j),a.$on("$destroy",function(){angular.element(document).off("click touchstart",j)}),a.$on("$destroy",function(){angular.element(c).off("resize",j)}),a.$on("$destroy",a.$on(f.events.GRID_SCROLL,j)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,j))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){var e=d.getScrollbarWidth();angular.isNumber(e)||(e=0);var f=d.detectBrowser();return"ie"===f&&(e+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,f,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*e+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,e=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(e-=l.grid.horizontalScrollbarHeight);var f=c/e;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=d.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,e){if(!e.target||e.target!==b&&!angular.element(e.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=e.target,"vertical"===a.type){if(e.y&&"undefined"!=typeof e.y.percentage&&void 0!==e.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,e.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&e.x&&"undefined"!=typeof e.x.percentage&&void 0!==e.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,e.x.percentage*h);b[0].scrollLeft=d.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",e+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=e,o.verticalScrollbarWidth=e,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",e+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=e,n.horizontalScrollbarHeight=e,r=d.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=d.elementHeight(b):"horizontal"===a.type&&(s=d.elementWidth(b));var t=d.closestElm(b,".ui-grid"),u=d.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(c.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(e,f,g,h){function i(a,b){if(b.y&&e.bindScrollVertical){n.prevScrollArgs=b;var c=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(c+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)f=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,f*c);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(b.x&&e.bindScrollHorizontal){n.prevScrollArgs=b;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=d.normalizeScrollLeft(n.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=d.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=d.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=d.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-v),c=-(e-u),y=1>c?-1:1,z=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(w+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(x+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(c){function d(){a(function(){var a={target:c.target};if(0!==u){var b=(n.viewport[0].scrollTop+u)/(p.getCanvasHeight()-p.getViewportHeight());a.y={percentage:b,pixels:u}}if(0!==v){var e=(n.viewport[0].scrollLeft+v)/(q.getCanvasWidth()-q.getViewportWidth());a.x={percentage:e,pixels:v}}m.fireScrollingEvent(a),s-=1,u/=2,v/=2,s>0?d():m.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},r)}c.originalEvent&&(c=c.originalEvent),c.preventDefault(),b.unbind("touchmove",j),b.unbind("touchend",k),b.unbind("touchcancel",k);var e=n.viewport[0].scrollTop,f=n.viewport[0].scrollTop,g=Math.abs(e-w),h=Math.abs(f-x),i=new Date-t,l=g/i,o=h/i,r=63,s=8,u=120*y*l,v=120*z*o;d()}function l(){var a="",b=q.getCanvasWidth(),c=q.getViewportWidth(),d=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==r.explicitHeaderHeight&&null!==r.explicitHeaderHeight&&r.explicitHeaderHeight>0?a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.explicitHeaderHeight+"px; }":void 0!==r.innerHeaderHeight&&null!==r.innerHeaderHeight&&r.innerHeaderHeight>0&&(a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.innerHeaderHeight+"px; }"),a}var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer,r=o.renderContainers[e.containerId];f.addClass("ui-grid-render-container-"+e.containerId);var s;(e.bindScrollHorizontal||e.bindScrollVertical)&&(s=e.$on(c.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=d.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var e=-120*b.deltaY,g=(n.viewport[0].scrollTop+e)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:e}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var t,u=0,v=0,w=0,x=0,y=1,z=1;d.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),t=new Date,u=a.targetTouches[0].screenY,v=a.targetTouches[0].screenX,w=n.viewport[0].scrollTop,x=n.viewport[0].scrollLeft,b.on("touchmove",j),b.on("touchend touchcancel",k)}),f.bind("$destroy",function(){s(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil",function(a){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(b,c,d,e){var f=e[0],g=e[1];
    +b.containerCtrl=g;{var h=g.rowContainer,i=g.colContainer;f.grid}b.grid=f.grid,b.rowContainer=g.rowContainer,b.colContainer=g.colContainer,g.viewport=c,c.on("scroll",function(){var d=c[0].scrollTop,e=a.normalizeScrollLeft(c),g=-1,j=-1;if(e!==i.prevScrollLeft){var k=(e-i.prevScrollLeft,i.getCanvasWidth()-i.getViewportWidth());g=e/k,i.adjustScrollHorizontal(e,g)}if(d!==h.prevScrollTop){var l=(d-h.prevScrollTop,h.getCanvasHeight()-h.getViewportHeight());j=d/l,j>1&&(j=1),0>j&&(j=0),h.adjustScrollVertical(d,j)}if(!b.grid.isScrollingVertically&&!b.grid.isScrollingHorizontally){var m={};g>-1&&(m.x={percentage:g}),j>-1&&(m.y={percentage:j}),f.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN),n.grid.refresh()}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&(c.uiGridColumns||0!==n.grid.options.columnDefs.length||n.grid.buildColumnDefsFromData(b),d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()}))),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,n.getExternalScopes=a.getExternalScopes,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireScrollingEvent=d.throttle(function(b){a.$broadcast(f.events.GRID_SCROLL,b)},n.grid.options.scrollThrottle,{trailing:!0}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window",function(a,b,c,d){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,e,f){function g(){h.gridWidth=a.gridWidth=c.elementWidth(b),h.gridHeight=a.gridHeight=c.elementHeight(b),h.queueRefresh()}var h=f.grid;if(f.scrollbars=[],h.renderingComplete(),h.element=b,h.gridWidth=a.gridWidth=c.elementWidth(b),h.canvasWidth=f.grid.gridWidth,h.gridHeight=a.gridHeight=c.elementHeight(b),h.gridHeight<h.options.rowHeight){var i=h.options.minRowsToShow*h.options.rowHeight;b.css("height",i+"px"),h.gridHeight=a.gridHeight=c.elementHeight(b)}h.refreshCanvas();var j=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');b.prepend(j),f.innerCompile(j);var k=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');b.append(k),f.innerCompile(k),a.$watch(function(){return h.hasLeftContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),a.$watch(function(){return h.hasRightContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),angular.element(d).on("resize",g),b.on("$destroy",function(){angular.element(d).off("resize",g)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0===h&&e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),e=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,e()},b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange)};return o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b){var c=d.nextUid();return b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[c]={callback:a,types:b},c},o.prototype.deregisterDataChangeCallback=function(a){delete this.dataChangeCallbacks[a]},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&b.callback(this)})},o.prototype.notifyDataChange=function(a,b){var c=e.dataChange;b===c.ALL||b===c.COLUMN||b===c.EDIT||b===c.ROW?a.callDataChangeCallbacks(b):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+b)},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},o.prototype.buildColumns=function(){var b,c=this,e=[],f=c.rowHeaderColumns.length;for(b=0;b<c.columns.length;b++)c.getColDef(c.columns[b].name)||(c.columns.splice(b,1),b--);return c.rowHeaderColumns.forEach(function(a){c.columns.unshift(a)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var h=c.getColumn(a.name);h?h.updateColumnDef(a):(h=new g(a,d.nextUid(),c),c.columns.splice(b+f,0,h)),c.columnBuilders.forEach(function(b){e.push(b.call(c,a,h,c.options))})}),a.all(e)},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},o.prototype.modifyRows=function(b){var c,d,e=this;if(0===e.rows.length&&b.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<b.length;c++)d=b[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(b),e.assignTypes()}else if(b.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<b.length;c++){d=b[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||b;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,b);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=a.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=a.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return a.all([r,s])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",e.prototype.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.scope,a.eventId,a.handler,c.grid)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$broadcast.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b){var c=f(a,g,b,d.grid),e={handler:b,dereg:c,eventId:g,scope:a};d.listeners.push(e),a.$on("$destroy",function(){e.dereg=null,e.handler=null,e.eventId=null,e.scope=null})}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));var e="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var f=b.width.replace(/%/g,""),g=parseInt(f,10);if(isNaN(g))throw new Error(e);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(e);c.width=b.width}d.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())},c.minWidth=b.minWidth?b.minWidth:30,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.footerCellClass=b.footerCellClass,c.cellClass=b.cellClass,c.headerCellClass=b.headerCellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var h=[];b.filter?h.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&h.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",h)},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.getAggregationText("aggregation.count",a.grid.getVisibleRowCount()):a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),a.getAggregationText("aggregation.sum",c)):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,a.getAggregationText("aggregation.avg",c)):a.aggregationType===b.aggregationTypes.min?a.getAggregationText("aggregation.min",Math.min.apply(null,e)):a.aggregationType===b.aggregationTypes.max?a.getAggregationText("aggregation.max",Math.max.apply(null,e)):" "},d.prototype.getAggregationText=function(a,b){var d=this;return d.colDef.aggregationHideLabel?b:c.getSafeText(a)+b},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){return{initialize:function(b){return b.onRegisterApi=b.onRegisterApi||angular.noop(),b.data=b.data||[],b.columnDefs=b.columnDefs||[],b.excludeProperties=b.excludeProperties||["$$hashKey"],b.enableRowHashing=b.enableRowHashing!==!1,b.rowIdentity=b.rowIdentity||function(b){return a.hashKey(b)},b.getRowIdentity=b.getRowIdentity||function(a){return a.$$hashKey},b.headerRowHeight="undefined"!=typeof b.headerRowHeight?b.headerRowHeight:30,b.rowHeight=b.rowHeight||30,b.maxVisibleRowCount=b.maxVisibleRowCount||200,b.minRowsToShow="undefined"!=typeof b.minRowsToShow?b.minRowsToShow:10,b.showFooter=b.showFooter===!0,b.footerRowHeight="undefined"!=typeof b.footerRowHeight?b.footerRowHeight:30,b.columnWidth="undefined"!=typeof b.columnWidth?b.columnWidth:50,b.maxVisibleColumnCount="undefined"!=typeof b.maxVisibleColumnCount?b.maxVisibleColumnCount:200,b.virtualizationThreshold="undefined"!=typeof b.virtualizationThreshold?b.virtualizationThreshold:20,b.columnVirtualizationThreshold="undefined"!=typeof b.columnVirtualizationThreshold?b.columnVirtualizationThreshold:10,b.excessRows="undefined"!=typeof b.excessRows?b.excessRows:4,b.scrollThreshold="undefined"!=typeof b.scrollThreshold?b.scrollThreshold:4,b.excessColumns="undefined"!=typeof b.excessColumns?b.excessColumns:4,b.horizontalScrollThreshold="undefined"!=typeof b.horizontalScrollThreshold?b.horizontalScrollThreshold:2,b.scrollThrottle="undefined"!=typeof b.scrollThrottle?b.scrollThrottle:70,b.enableSorting=b.enableSorting!==!1,b.enableFiltering=b.enableFiltering===!0,b.enableColumnMenus=b.enableColumnMenus!==!1,b.enableScrollbars=b.enableScrollbars!==!1,b.minimumColumnSize="undefined"!=typeof b.minimumColumnSize?b.minimumColumnSize:10,b.rowEquality=b.rowEquality||function(a,b){return a===b},b.headerTemplate=b.headerTemplate||null,b.footerTemplate=b.footerTemplate||null,b.rowTemplate=b.rowTemplate||"ui-grid/ui-grid-row",b}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil",function(a){function b(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return b.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},b.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},b.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},b.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},b.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},b.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},b.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},b.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},b.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},b.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},b.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b
    +},b.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},b.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},b.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},b.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},b.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},b.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},b.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},b.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},b.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},b.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},b.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},b.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},b.prototype.updateColumnWidths=function(){var b=this,c=[],d=[],e=0,f=b.getViewportWidth();"undefined"!=typeof b.grid.verticalScrollbarWidth&&void 0!==b.grid.verticalScrollbarWidth&&b.grid.verticalScrollbarWidth>0&&(f+=b.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=b.visibleColumnCache;k.forEach(function(b){if(b.visible){var f=!1;angular.isNumber(b.width)||(f=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(e=parseInt(e+b.width.length,10),c.push(b)):f?d.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),b.grid.verticalScrollbarWidth&&(i+=b.grid.verticalScrollbarWidth),b.canvasWidth=parseInt(i,10),this.columnStyles=j},b}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell",d.cellTemplatePromise=a.getTemplate(c.cellTemplate)),d.cellTemplatePromise=a.getTemplate(c.cellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["gridUtil","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){o.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){o.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(a){o.LOG_DEBUG_MESSAGES&&b.debug(a)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=p.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=p.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Total Artículos:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"total filas: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar nombres de columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿existe información aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"Archivo json importado debe contener un arreglo, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(c,d,e,f){function g(){j=b.elementHeight(d),i=b.elementWidth(d)}function h(){a.cancel(k),k=a(function(){var a=b.elementHeight(d),c=b.elementWidth(d);a!==j||c!==i?(f.grid.gridHeight=a,f.grid.gridWidth=c,f.grid.refresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),c.$on("$destroy",function(){a.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};if(null!==d){var g=a.renderContainers.body.visibleRowCache.indexOf(d),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;f.y={percentage:i}}null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(a,b){return{replace:!0,priority:-99999,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(){},post:function(a,c,d,e){var f=e.grid;b.decorateRenderContainers(f)}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","gridUtil","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0),b.grid.queueRefresh()}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=b.colContainer.cellNav.getNextRowCol(d,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),c.stopPropagation(),c.preventDefault(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.MODEL_COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var c=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),c.removeClass("ui-grid-cell-contents-hidden"),a&&t&&c.focus(),t=!1,s=!1,h(),d.grid.api.core.notifyDataChange(d.grid,b.dataChange.EDIT)}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.refresh()}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",width:40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){var e=c(d)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=b.getColumn("expandableButtons").width;return".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);
    +a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c,e){var f=this.getColumnHeaders(a,c),g=this.getData(a,b,c),h=this.formatAsCsv(f,g,a.options.exporterCsvColumnSeparator);!e&&a.options.exporterCsvLinkElement&&(e=a.options.exporterCsvLinkElement),e?this.renderCsvLink(a,h,e):d.logError("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,d){var e=[];return angular.forEach(a.columns,function(f){!f.visible&&d!==b.ALL||f.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(f.name)||e.push({name:f.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(f.displayName):f.displayName,width:f.drawnWidth?f.drawnWidth:f.width,align:"number"===f.colDef.type?"right":"left"})}),e},getData:function(a,e,f){var g,h=[];switch(e){case b.ALL:g=a.rows;break;case b.VISIBLE:g=a.getVisibleRows();break;case b.SELECTED:a.api.selection?g=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return b.ALL?(angular.forEach(g,function(d){var e=[];angular.forEach(a.columns,function(g){!g.visible&&f!==b.ALL||g.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(g.name)||e.push(a.options.exporterFieldCallback(a,d,g,a.getCellValue(d,g)))}),h.push(e)}),h):void 0},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return a.displayName}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,c,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){var f=angular.element(d);f.children("a").html(f.children("a").html().replace(b.LINK_LABEL,a.options.exporterLinkLabel)),f.children("a").attr("href",f.children("a").attr("href").replace(b.CSV_CONTENT,encodeURIComponent(c)));var h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&h.content.unshift(a.options.exporterPdfHeader),a.options.exporterPdfFooter&&h.content.push(a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a,b){i.importFile(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(a,c),a.deregisterDataChangeCallback(d)},[b.dataChange.ROW]),e=function(){a.deregisterDataChangeCallback(d)};a.importer.$scope.$on("$destroy",e)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){if(1===a.srcElement.files.length){var c=a.srcElement.files[0];b.importThisFile(i,c),a.srcElement.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout",function(a,b){var c={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){b.redrawColumnAtPosition(a,c,d)}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var e=a.columns,f=function(a){for(var b=a,c=0;b>=c;c++)(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};c=f(c),d=f(d);var g=e[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)e[h]=e[h-1];else if(d>c)for(var i=c;d>i;i++)e[i]=e[i+1];e[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return c}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(b,e,f,g){if(b.col.colDef.enableColumnMoving){var h=function(h){if("ui-grid-icon-angle-down"!==h.toElement.className){var i=e.clone();e.append(i),i.addClass("movingColumn");var j={},k=b.grid.element[0].getBoundingClientRect().left,l=e[0].getBoundingClientRect().left;j.left=l-k+"px";var m,n=b.grid.element[0].getBoundingClientRect().right,o=e[0].getBoundingClientRect().right;o>n&&(m=b.col.drawnWidth+(n-o),j.width=m+"px"),i.css(j);var p=h.pageX,q=0,r=k+b.grid.getViewportWidth()-b.grid.verticalScrollbarWidth,s=function(a){g.fireEvent("hide-menu");var c=i[0].getBoundingClientRect().left-1,d=i[0].getBoundingClientRect().right,e=a.pageX-p,f=c-k+e;f=r>f?f:r,(c>=k||e>0)&&(r>=d||0>e)?i.css({visibility:"visible",left:f+"px"}):(e*=5,g.fireScrollingEvent({x:{pixels:2.5*e}})),q+=e,p=a.pageX,m<b.col.drawnWidth&&(m+=Math.abs(e),i.css({width:m+"px"}))};b.$on("$destroy",function(){d.off("mousemove",s),d.off("mouseup",t)}),d.on("mousemove",s);var t=function(e){var h,j=a.defer();f.$observe("renderIndex",function(a){h=b.$eval(a),j.resolve()}),j.promise.then(function(){i&&i.remove();for(var a=b.grid.renderContainers.body.renderedColumns,f=0,j=b.grid.columns,k=0;k<j.length&&j[k].colDef.name!==a[0].colDef.name;k++)f++;if(0>q){for(var l=0,m=h-1;m>=0;m--)if(l+=a[m].drawnWidth,l>Math.abs(q)){c.redrawColumnAtPosition(b.grid,f+h,f+m+1);break}l<Math.abs(q)&&c.redrawColumnAtPosition(b.grid,f+h,f+0)}else if(q>0){for(var n=0,o=h+1;o<a.length;o++)if(n+=a[o].drawnWidth,n>q){c.redrawColumnAtPosition(b.grid,f+h,f+o-1);break}q>n&&c.redrawColumnAtPosition(b.grid,f+h,f+a.length-1)}else if(0===q){var p=!1;e.shiftKey&&(p=!0),g.grid.sortColumn(b.col,p).then(function(){g.columnMenuScope&&g.columnMenuScope.hideMenu(),g.grid.refresh()})}d.off("mousemove",s),d.off("mouseup",t)})};d.on("mouseup",t)}};e.on("mousedown",h)}}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ui.grid"]);a.service("uiGridPaginationService",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options),b.pagination={page:1,totalPages:1};var c={methods:{pagination:{getPage:function(){return b.pagination.page},getTotalPages:function(){return b.pagination.totalPages},nextPage:function(){b.pagination.page++,b.refresh()},previousPage:function(){b.pagination.page=Math.max(1,b.pagination.page-1),b.refresh()},seek:function(a){if(!angular.isNumber(a)||1>a)throw"Invalid page number: "+a;b.pagination.page=a,b.refresh()}}}};b.api.registerMethodsFromObject(c.methods),b.registerRowsProcessor(function(a){if(!b.options.enablePagination)return a;b.pagination.totalPages=Math.max(1,Math.ceil(a.length/b.options.rowsPerPage));var c=(b.pagination.page-1)*b.options.rowsPerPage;return c>=a.length&&(b.pagination.page=b.pagination.totalPages,c=(b.pagination.page-1)*b.options.rowsPerPage),a.slice(c,c+b.options.rowsPerPage)})},defaultGridOptions:function(a){a.enablePagination=a.enablePagination!==!1,a.rowsPerPage=angular.isNumber(a.rowsPerPage)?a.rowsPerPage:10}};return a}),a.directive("uiGridPagination",["uiGridPaginationService",function(a){return{priority:-400,scope:!1,require:"^uiGrid",link:{pre:function(b,c,d,e){a.initializeGrid(e.grid)}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?"*"===b.width?b.grid.refresh().then(function(){b.renderContainer="left",b.width=b.grid.canvasWidth/b.grid.columns.length,b.grid.createLeftContainer()}):(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&("*"===b.width?b.grid.refresh().then(function(){b.renderContainer="right",b.width=b.grid.canvasWidth/b.grid.columns.length,b.grid.createRightContainer()}):(b.renderContainer="right",b.grid.createRightContainer())),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","columnBounds","uiGridResizeColumnsService",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(g,h,i,j){function k(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function l(){j.grid.buildColumns().then(function(){j.grid.refreshCanvas(!0)})}function m(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),p=a.clientX-q,0>p?p=0:p>j.grid.gridWidth&&(p=j.grid.gridWidth);var b,e=g.col,h=e.getRenderContainer();if("left"===g.position?(e=h.renderedColumns[g.renderIndex-1],b=g.col):"right"===g.position&&(b=h.renderedColumns[g.renderIndex+1]),e.colDef.enableColumnResizing!==!1){j.grid.element.hasClass("column-resizing")||j.grid.element.addClass("column-resizing");var i=p-o,k=e.drawnWidth+i;e.colDef.minWidth&&k<e.colDef.minWidth?p+=e.colDef.minWidth-k:!e.colDef.minWidth&&d.minWidth&&k<d.minWidth?p+=e.colDef.minWidth-k:e.colDef.maxWidth&&k>e.colDef.maxWidth&&(p+=e.colDef.maxWidth-k),f.css({left:p+"px"}),j.fireEvent(c.events.ITEM_DRAGGING)}}function n(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),j.grid.element.removeClass("column-resizing"),f.remove(),p=b.clientX-q;var c=p-o;if(0===c)return a.off("mouseup",n),void a.off("mousemove",m);var h,i=g.col,r=i.getRenderContainer();if("left"===g.position?(i=r.renderedColumns[g.renderIndex-1],h=g.col):"right"===g.position&&(h=r.renderedColumns[g.renderIndex+1]),i.colDef.enableColumnResizing!==!1){var s=parseInt(i.drawnWidth+c,10);i.colDef.minWidth&&s<i.colDef.minWidth?s=i.colDef.minWidth:!i.colDef.minWidth&&d.minWidth&&s<d.minWidth&&(s=d.minWidth),i.colDef.maxWidth&&s>i.colDef.maxWidth&&(s=i.colDef.maxWidth),i.width=s,k(i),l(c),e.fireColumnSizeChanged(j.grid,i.colDef,c),a.off("mouseup",n),a.off("mousemove",m)}}var o=0,p=0,q=0;"left"===g.position?h.addClass("left"):"right"===g.position&&h.addClass("right"),h.on("mousedown",function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),q=j.grid.element[0].getBoundingClientRect().left,o=b.clientX-q,j.grid.element.append(f),f.css({left:o}),a.on("mouseup",n),a.on("mousemove",m)}),h.on("dblclick",function(a){a.stopPropagation();var f,i,m=g.col,n=m.getRenderContainer();"left"===g.position?(m=n.renderedColumns[g.renderIndex-1],f=g.col,i=1):"right"===g.position&&(f=n.renderedColumns[g.renderIndex+1],f=n.renderedColumns[g.renderIndex+1],i=-1);var o=0,p=0,q=b.closestElm(h,".ui-grid-render-container"),r=q.querySelectorAll("."+c.COL_CLASS_PREFIX+m.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(r,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var f=b.elementWidth(c);e+=f}e>o&&(o=e,p=o-e)})}),m.colDef.minWidth&&o<m.colDef.minWidth?o=m.colDef.minWidth:!m.colDef.minWidth&&d.minWidth&&o<d.minWidth&&(o=d.minWidth),m.colDef.maxWidth&&o>m.colDef.maxWidth&&(o=m.colDef.maxWidth),m.width=parseInt(o,10),k(m),l(p),e.fireColumnSizeChanged(j.grid,m.colDef,p)}),h.on("$destroy",function(){h.off("mousedown"),h.off("dblclick"),a.off("mousemove",m),a.off("mouseup",n)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){f.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEdit.dirtyRows?a.rowEdit.dirtyRows:[]},getErrorRows:function(a){return a.rowEdit.errorRows?a.rowEdit.errorRows:[]},flushDirtyRows:function(a){return f.flushDirtyRows(a)},setRowsDirty:function(a,b){f.setRowsDirty(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";
    +return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c){var d=b.renderContainers.body.visibleRowCache[c];null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},selectAllVisibleRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.visible?d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c)):d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(a){return a.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;if(d||f){if(!d&&f){var g=a.getSelectedRows(b);g.length>1&&(f=!1,a.clearSelectedRows(b))}}else a.clearSelectedRows(b);f&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=[],j=f;g>=j;j++){var k=b.renderContainers.body.visibleRowCache[j];k&&(k.isSelected||(k.isSelected=!0,b.selection.lastSelectedRow=k,a.decideRaiseSelectionEvent(b,k,i)))}a.decideRaiseSelectionBatchEvent(b,i)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){var c=[];a.getSelectedRows(b).forEach(function(d){d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)},decideRaiseSelectionEvent:function(a,b,c){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b)},decideRaiseSelectionBatchEvent:function(a,b){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:30,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1};f.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(){c.selection.selectAll?(b.clearSelectedRows(c),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){var c=0,d=300,e=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()};b.on("touchstart",function(){c=(new Date).getTime()}),b.on("touchend",function(a){var b=(new Date).getTime(),f=b-c;d>f&&e(a)}),b.on("click",function(a){e(a)})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)">&nbsp;</div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.13/ui-grid.svg b/release/3.0.0-rc.13/ui-grid.svg
    new file mode 100644
    index 000000000..18634ed72
    --- /dev/null
    +++ b/release/3.0.0-rc.13/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m0 29v71q0 15 11 25t25 11h785q15 0 26-11t10-25v-71q0-15-10-26t-26-10h-785q-15 0-25 10t-11 26z m0 285v72q0 14 11 25t25 10h785q15 0 26-10t10-25v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25z m0 286v71q0 15 11 26t25 10h785q15 0 26-10t10-26v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.13/ui-grid.ttf b/release/3.0.0-rc.13/ui-grid.ttf
    new file mode 100644
    index 000000000..081bc1440
    Binary files /dev/null and b/release/3.0.0-rc.13/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.13/ui-grid.woff b/release/3.0.0-rc.13/ui-grid.woff
    new file mode 100644
    index 000000000..e1a95cbf5
    Binary files /dev/null and b/release/3.0.0-rc.13/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.14/ui-grid.css b/release/3.0.0-rc.14/ui-grid.css
    new file mode 100644
    index 000000000..d4db23438
    --- /dev/null
    +++ b/release/3.0.0-rc.14/ui-grid.css
    @@ -0,0 +1,1221 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: fixed;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.14/ui-grid.eot b/release/3.0.0-rc.14/ui-grid.eot
    new file mode 100644
    index 000000000..8609654ce
    Binary files /dev/null and b/release/3.0.0-rc.14/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.14/ui-grid.js b/release/3.0.0-rc.14/ui-grid.js
    new file mode 100644
    index 000000000..688ef857c
    --- /dev/null
    +++ b/release/3.0.0-rc.14/ui-grid.js
    @@ -0,0 +1,17076 @@
    +/*! ui-grid - v3.0.0-rc.14 - 2014-11-05
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column'
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          var deregisterFunction = function() {
    +           $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +        delete $scope.colElementPosition;
    +        delete $scope.columnElement;
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.headerCellClass) {
    +              updateClass();
    +            }
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            var deregisterFunction = function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            };
    +
    +            $scope.$on( '$destroy', deregisterFunction );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false) {
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                }
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +
    +
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', function( gridUtil, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +            $animate = gridUtil.enableAnimations(menuMid);
    +            if ( $animate ){
    +              $scope.shownMid = true;
    +              $animate.removeClass(menuMid, 'ng-hide', function() {
    +                $scope.$emit('menu-shown');
    +              });
    +            } else {
    +              $scope.shownMid = true;
    +              $scope.$emit('menu-shown');
    +            }
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +          if ( $animate ){
    +            $scope.shownMid = true;
    +            $animate.removeClass(menuMid, 'ng-hide', function() {
    +              $scope.$emit('menu-shown');
    +            });
    +          } else {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          }
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          menuMid = $elm[0].querySelectorAll( '.ui-grid-menu-mid' );
    +          $animate = gridUtil.enableAnimations(menuMid);
    +
    +          if ( $animate ){
    +            $scope.shownMid = false;
    +            $animate.addClass(menuMid, 'ng-hide', function() {
    +              if ( !$scope.shownMid ){
    +                $scope.shown = false;
    +                $scope.$emit('menu-hidden');
    +              }
    +            });
    +          } else {
    +            $scope.shownMid = false;
    +            $scope.shown = false;
    +          }
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        $scope.$apply(function () {
    +          $scope.hideMenu();
    +        });
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // gridUtil.logDebug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // gridUtil.logDebug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil',
    +    function(gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +              
    +              self.grid.refresh();
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (n) {
    +          if (self.grid.columns.length === ( self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0 ) ) {
    +            // gridUil.logDebug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = GridOptions.initialize( options );
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +  self.dataChangeCallbacks = {};
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name addRowHeaderColumn
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description adds a row header column to the grid
    +   * @param {object} column def
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortHandleNulls
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description A null handling method that can be used when building custom sort
    +   * functions
    +   * @example
    +   * <pre>
    +   *   mySortFn = function(a, b) {
    +   *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +   *   if ( nulls !== null ){
    +   *     return nulls;
    +   *   } else {
    +   *     // your code for sorting here
    +   *   };
    +   * </pre>
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +
    +  /**
    +   * @ngdoc method
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Notify the grid that a data or config change has occurred,
    +   * where that change isn't something the grid was otherwise noticing.  This 
    +   * might be particularly relevant where you've changed values within the data
    +   * and you'd like cell classes to be re-evaluated, or changed config within 
    +   * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +   * @param {Grid} grid the grid
    +   * @param {string} type one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +   * us which refreshes to fire.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN ).  Optional and defaults to
    +   * ALL 
    +   * @returns {string} uid of the callback, can be used to deregister it again
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types };
    +    return uid;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name deregisterDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description Delete the callback identified by the id.
    +   * @param {string} uid the uid of the function that is to be deregistered
    +   */
    +  Grid.prototype.deregisterDataChangeCallback = function deregisterDataChangeCallback(uid) {
    +    delete this.dataChangeCallbacks[uid];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, and COLUMN callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        callback.callback( this );
    +      }
    +    });
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {Grid} grid the grid
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(grid, type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ){
    +      grid.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow 
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', GridRow.prototype.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed, 
    +           * and that is the one that would have been useful.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.  A number of settings are supported:
    +    * 
    +    * - title: controls the title that is displayed in the menu
    +    * - icon: the icon shown alongside that title
    +    * - action: the method to call when the menu is clicked
    +    * - shown: a function to evaluate to determine whether or not to show the item
    +    * - active: a function to evaluate to determine whether or not the item is currently selected
    +    * - context: context to pass to the action function??
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       shown: function() { return true; },
    +    *       active: function() { return true; },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        return self.getAggregationText('aggregation.count', self.grid.getVisibleRowCount());
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        return self.getAggregationText('aggregation.sum', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        return self.getAggregationText('aggregation.avg', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return self.getAggregationText('aggregation.min', Math.min.apply(null, cellValues));
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return self.getAggregationText('aggregation.max', Math.max.apply(null, cellValues));
    +      }
    +      else {
    +        return '\u00A0';
    +      }
    +    };
    +    
    +   /** 
    +    * @ngdoc property
    +    * @name aggregationHideLabel
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description defaults to false, if set to true hides the label text
    +    * in the aggregation footer, so only the value is displayed.
    +    *
    +    */
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationText
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description converts the aggregation value into a text string, including 
    +     * i18n and deciding whether or not to display based on colDef.aggregationHideLabel
    +     * 
    +     * @param {string} label the i18n lookup value to use for the column label
    +     * @param {number} value the calculated aggregate value for this column
    +     * 
    +     */
    +    GridColumn.prototype.getAggregationText = function ( label, value ) {
    +      var self = this;
    +      if ( self.colDef.aggregationHideLabel ){
    +        return value;
    +      } else {
    +        return i18nService.getSafeText(label) + value;
    +      }
    +    };
    +
    +    GridColumn.prototype.getCellTemplate = function () {
    +      var self = this;
    +
    +      return self.cellTemplatePromise;
    +    };
    +
    +    GridColumn.prototype.getCompiledElementFn = function () {
    +      var self = this;
    +      
    +      return self.compiledElementFnDefer.promise;
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +  
    +      baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +      baseOptions.maxVisibleRowCount = baseOptions.maxVisibleRowCount || 200;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      baseOptions.showFooter = baseOptions.showFooter === true;
    +      baseOptions.footerRowHeight = typeof(baseOptions.footerRowHeight) !== "undefined" ? baseOptions.footerRowHeight : 30;
    +  
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      // Turn virtualization on when number of data elements goes over this number
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      // Extra rows to to render outside of the viewport
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      // Extra columns to to render outside of the viewport
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      // Default time to throttle scroll events to.
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableScrollbars
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this settings enable vertical
    +       * and horizontal scrollbar for grid.
    +       */
    +      baseOptions.enableScrollbars = baseOptions.enableScrollbars !== false;
    +  
    +      // Columns can't be smaller than 10 pixels
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', function(gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //gridUtil.logDebug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +            col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(colDef.cellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logDebug: function( logMessage ){
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug( logMessage );
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Total Artículos:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'total filas: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar nombres de columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿existe información aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'Archivo json importado debe contener un arreglo, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.refresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so 
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         * 
    +         * To get to row 9 (i.e. the last row) in the same list, we want to 
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll, 
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            args.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var grid = uiGridCtrl.grid;
    +              //needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, gridUtil, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = $scope.colContainer.cellNav.getNextRowCol(direction, $scope.row, $scope.col);
    +
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            evt.stopPropagation();
    +            evt.preventDefault();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          //this event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            // gridUtil.logDebug('setFocused: ' + div[0].parentElement.className);
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +            $scope.grid.queueRefresh();
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( $scope.grid, uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight; 
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = grid.getColumn('expandableButtons').width;
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + displayName; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCOl and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            gridUtil.logError( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? grid.options.exporterHeaderFilter(gridCol.displayName) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  extractedRow.push( grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) );
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +
    +              var template = angular.element(contents);
    +
    +              template.children("a").html(
    +                  template.children("a").html().replace(
    +                      uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel));
    +
    +              template.children("a").attr("href", 
    +                  template.children("a").attr("href").replace(
    +                      uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent)));
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.content.unshift( grid.options.exporterPdfHeader );
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.content.push( grid.options.exporterPdfFooter );
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {Grid} grid the grid we're importing into
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( grid, fileObject ) {
    +                  service.importFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and ift he rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var callbackId = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( grid, newObjects );
    +              grid.deregisterDataChangeCallback( callbackId );
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            var deregisterClosure = function() {
    +              grid.deregisterDataChangeCallback( callbackId );
    +            };
    +  
    +            grid.importer.$scope.$on( '$destroy', deregisterClosure );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            if (event.srcElement.files.length === 1) {
    +              var fileObject = event.srcElement.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              event.srcElement.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', function ($q, $timeout) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.on.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                self.redrawColumnAtPosition(grid, originalPosition, finalPosition);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +        var columns = grid.columns;
    +
    +        //Function to find column position for a render index, ths is needed to take care of
    +        // invisible columns and row headers
    +        var findPositionForRenderIndex = function (index) {
    +          var position = index;
    +          for (var i = 0; i <= position; i++) {
    +            if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +              position++;
    +            }
    +          }
    +          return position;
    +        };
    +
    +        originalPosition = findPositionForRenderIndex(originalPosition);
    +        newPosition = findPositionForRenderIndex(newPosition);
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and coned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                var mouseDownHandler = function (evt) {
    +                  if (evt.toElement.className !== 'ui-grid-icon-angle-down') {
    +
    +                    //Cloning header cell and appending to current header cell.
    +                    var movingElm = $elm.clone();
    +                    $elm.append(movingElm);
    +
    +                    //Left of cloned element should be aligned to original header cell.
    +                    movingElm.addClass('movingColumn');
    +                    var movingElementStyles = {};
    +                    var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                    var elmLeft = $elm[0].getBoundingClientRect().left;
    +                    movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                    var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                    var elmRight = $elm[0].getBoundingClientRect().right;
    +                    var reducedWidth;
    +                    if (elmRight > gridRight) {
    +                      reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                      movingElementStyles.width = reducedWidth + 'px';
    +                    }
    +                    //movingElementStyles.visibility = 'hidden';
    +                    movingElm.css(movingElementStyles);
    +
    +                    //Setting some variables required for calculations.
    +                    var previousMouseX = evt.pageX;
    +                    var totalMouseMovement = 0;
    +                    var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth() - $scope.grid.verticalScrollbarWidth;
    +
    +                    //Clone element should move horizontally with mouse.
    +                    var mouseMoveHandler = function (evt) {
    +                      uiGridCtrl.fireEvent('hide-menu');
    +                      var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                      var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                      var changeValue = evt.pageX - previousMouseX;
    +                      var newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                      newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +                      if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                        movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                      }
    +                      else {
    +                        changeValue *= 5;
    +                        uiGridCtrl.fireScrollingEvent({ x: { pixels: changeValue * 2.5} });
    +                      }
    +                      totalMouseMovement += changeValue;
    +                      previousMouseX = evt.pageX;
    +                      if (reducedWidth < $scope.col.drawnWidth) {
    +                        reducedWidth += Math.abs(changeValue);
    +                        movingElm.css({'width': reducedWidth + 'px'});
    +                      }
    +                    };
    +
    +                    // On scope destroy, remove the mouse event handlers from the document body
    +                    $scope.$on('$destroy', function () {
    +                      $document.off('mousemove', mouseMoveHandler);
    +                      $document.off('mouseup', mouseUpHandler);
    +                    });
    +
    +                    $document.on('mousemove', mouseMoveHandler);
    +                    var mouseUpHandler = function (evt) {
    +                      var renderIndexDefer = $q.defer();
    +
    +                      var renderIndex;
    +                      $attrs.$observe('renderIndex', function (n, o) {
    +                        renderIndex = $scope.$eval(n);
    +                        renderIndexDefer.resolve();
    +                      });
    +
    +                      renderIndexDefer.promise.then(function () {
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var renderedColumns = $scope.grid.renderContainers['body'].renderedColumns;
    +
    +                        //This method will calculate the number of columns hidden in lift due to scroll
    +                        //renderContainer.prevColumnScrollIndex could also have been used but this is more accurate
    +                        var scrolledColumnCount = 0;
    +                        var columns = $scope.grid.columns;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== renderedColumns[0].colDef.name) {
    +                            scrolledColumnCount++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = renderIndex - 1; il >= 0; il--) {
    +                            totalColumnsLeftWidth += renderedColumns[il].drawnWidth;
    +                            if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + il + 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + 0);
    +                          }
    +                        }
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = renderIndex + 1; ir < renderedColumns.length; ir++) {
    +                            totalColumnsRightWidth += renderedColumns[ir].drawnWidth;
    +                            if (totalColumnsRightWidth > totalMouseMovement) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + ir - 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + renderedColumns.length - 1);
    +                          }
    +                        }
    +                        else if (totalMouseMovement === 0) {
    +                          //sort the current column
    +                          var add = false;
    +                          if (evt.shiftKey) {
    +                            add = true;
    +                          }
    +
    +                          // Sort this column then rebuild the grid's rows
    +                          uiGridCtrl.grid.sortColumn($scope.col, add)
    +                            .then(function () {
    +                              if (uiGridCtrl.columnMenuScope) {
    +                                uiGridCtrl.columnMenuScope.hideMenu();
    +                              }
    +                              uiGridCtrl.grid.refresh();
    +                            });
    +                        }
    +
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      });
    +                    };
    +
    +                    $document.on('mouseup', mouseUpHandler);
    +                  }
    +                };
    +
    +                $elm.on('mousedown', mouseDownHandler);
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', function () {
    +    var service = {
    +
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +        grid.pagination = {page: 1, totalPages: 1};
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.pagination.api:PublicAPI
    +         *
    +         * @description Public API for the pagination feature
    +         */
    +        var publicApi = {
    +          methods: {
    +            pagination: {
    +              /**
    +               * @ngdoc method
    +               * @name getPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the number of the current page
    +               */
    +              getPage: function () {
    +                return grid.pagination.page;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name getTotalPages
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the total number of pages
    +               */
    +              getTotalPages: function () {
    +                return grid.pagination.totalPages;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name nextPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the next page, if possible
    +               */
    +              nextPage: function () {
    +                grid.pagination.page++;
    +                grid.refresh();
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name previousPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the previous page, if we're not on the first page
    +               */
    +              previousPage: function () {
    +                grid.pagination.page = Math.max(1, grid.pagination.page - 1);
    +                grid.refresh();
    +              },
    +              seek: function (page) {
    +                if (!angular.isNumber(page) || page < 1) {
    +                  throw 'Invalid page number: ' + page;
    +                }
    +
    +                grid.pagination.page = page;
    +                grid.refresh();
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +        grid.registerRowsProcessor(function (renderableRows) {
    +          if (!grid.options.enablePagination) {
    +            return renderableRows;
    +          }
    +          grid.pagination.totalPages = Math.max(
    +            1,
    +            Math.ceil(renderableRows.length / grid.options.rowsPerPage)
    +          );
    +
    +          var firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          if (firstRow >= renderableRows.length) {
    +            grid.pagination.page = grid.pagination.totalPages;
    +            firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          }
    +
    +          return renderableRows.slice(
    +            firstRow,
    +            firstRow + grid.options.rowsPerPage
    +          );
    +        });
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pagination.api:GridOptions
    +         *
    +         *  @description GridOptions for the pagination feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePagination
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description Enable pagination for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name rowsPerPage
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description The number of rows that should be displayed per page
    +         *  <br/>Defaults to 10
    +         */
    +        gridOptions.rowsPerPage = angular.isNumber(gridOptions.rowsPerPage) ? gridOptions.rowsPerPage : 10;
    +      }
    +    };
    +
    +    return service;
    +  });
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.pagination.directive:uiGridPagination
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description Adds pagination support to a grid.
    +   */
    +  module.directive('uiGridPagination', ['uiGridPaginationService', function (uiGridPaginationService) {
    +    return {
    +      priority: -400,
    +      scope: false,
    +      require: '^uiGrid',
    +      link: {
    +        pre: function (scope, element, attrs, uiGridCtrl) {
    +          uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      }
    +    };
    +  }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', function (gridUtil, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {object} grid the grid for which rows should be set dirty
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function (grid, dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.api:PublicApi
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing 
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected ){
    +                      row.isSelected = true;
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected){
    +                        row.isSelected = true;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.isSelected = false;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                getSelectAllState: function (grid) {
    +                  return grid.selection.selectAll;
    +                }
    +                
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead  
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid);
    +            }
    +          }
    +          
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected ){
    +                rowToSelect.isSelected = true;
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.isSelected = false;
    +              service.decideRaiseSelectionEvent( grid, row, changedRows );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and 
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows);
    +          }
    +        }        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width: 30,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +          
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows();
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              var touchStartTime = 0;
    +              var touchTimeout = 300;
    +              var selectCells = function(evt){
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              };
    +
    +              $elm.on('touchstart', function(event) {
    +                touchStartTime = (new Date()).getTime();
    +              });
    +
    +              $elm.on('touchend', function (evt) {
    +                var touchEndTime = (new Date()).getTime();
    +                var touchTime = touchEndTime - touchStartTime;
    +
    +                if (touchTime < touchTimeout ) {
    +                  // short touch
    +                  selectCells(evt);
    +                }
    +              });
    +
    +              $elm.on('click', function (evt) {
    +                selectCells(evt);
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.14/ui-grid.min.css b/release/3.0.0-rc.14/ui-grid.min.css
    new file mode 100644
    index 000000000..7554e5ec6
    --- /dev/null
    +++ b/release/3.0.0-rc.14/ui-grid.min.css
    @@ -0,0 +1,12 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:fixed;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +
    +.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.14/ui-grid.min.js b/release/3.0.0-rc.14/ui-grid.min.js
    new file mode 100644
    index 000000000..245ee97ae
    --- /dev/null
    +++ b/release/3.0.0-rc.14/ui-grid.min.js
    @@ -0,0 +1,8 @@
    +/*! ui-grid - v3.0.0-rc.14 - 2014-11-05
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column"}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){b.addClass(a.col.getColClass(!1));var c,e=function(){var d=b;c&&(d.removeClass(c),c=null),c=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,d.addClass(c)};a.col.cellClass&&e();var f=a.grid.registerDataChangeCallback(e,[d.dataChange.COLUMN,d.dataChange.EDIT]),g=function(){a.grid.deregisterDataChangeCallback(f)};a.$on("$destroy",g)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(a,b,c,e){var f=this;d.initialize(a,e),a.defaultMenuItems=d.getDefaultMenuItems(a),a.menuItems=a.defaultMenuItems,d.setColMenuItemWatch(a),a.showMenu=function(c,e,g){a.col=c;var h=d.getColumnElementPosition(a,c,e);a.menuShown?(a.colElement=e,a.colElementPosition=h,a.hideThenShow=!0,a.$broadcast("hide-menu",{originalEvent:g})):(f.shown=a.menuShown=!0,d.repositionMenu(a,c,h,b,e),a.colElement=e,a.colElementPosition=h,a.$broadcast("show-menu",{originalEvent:g}))},a.hideMenu=function(b){a.menuShown=!1,b||a.$broadcast("hide-menu")},a.$on("menu-hidden",function(){a.hideThenShow?(delete a.hideThenShow,d.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),a.$broadcast("show-menu"),a.menuShown=!0):a.hideMenu(!0)}),a.$on("menu-shown",function(){d.repositionMenu(a,a.col,a.colElementPosition,b,a.colElement),delete a.colElementPosition,delete a.columnElement}),a.sortColumn=function(b,c){b.stopPropagation(),a.grid.sortColumn(a.col,c,!0).then(function(){a.grid.refresh(),a.hideMenu()})},a.unsortColumn=function(){a.col.unsort(),a.grid.refresh(),a.hideMenu()},a.hideColumn=function(){a.col.colDef.visible=!1,a.grid.refresh(),a.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,c){function e(e){b.getTemplate(e).then(function(b){var e=d(b),f=e(a);c.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,d,e){a.grid=e.grid,a.getExternalScopes=e.getExternalScopes,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",function(){a.grid.deregisterDataChangeCallback(h)})}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,a.getExternalScopes=h.getExternalScopes,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,e){function h(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.getExternalScopes=i.getExternalScopes,a.renderContainer=i.grid.renderContainers[j.containerId],c.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var k,l=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),m=function(){var b=c;k&&(b.removeClass(k),k=null),k=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(k)};a.col.headerCellClass&&m();var n=a.grid.registerDataChangeCallback(m,[f.dataChange.COLUMN]),o=function(){a.grid.deregisterDataChangeCallback(n)};a.$on("$destroy",o),a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var p,q=0;if(l.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(q=(new Date).getTime(),p=b(function(){},g),p.then(function(){a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1&&i.columnMenuScope.showMenu(a.col,c,d)}))}),l.on("mouseup touchend",function(){b.cancel(p)}),a.$on("$destroy",function(){l.off("mousedown touchstart")}),a.toggleMenu=function(b){b.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,c)},a.sortable&&(l.on("click touchend",function(a){a.stopPropagation(),b.cancel(p);var c=(new Date).getTime(),d=c-q;d>g||h(a)}),a.$on("$destroy",function(){b.cancel(p)})),a.filterable){var r=[];angular.forEach(a.col.filters,function(b,c){r.push(a.$watch("col.filters["+c+"].term",function(){i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(r,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,a.getExternalScopes=i.getExternalScopes,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.hideHeader?f:a.grid.options.headerTemplate?a.grid.options.headerTemplate:e,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth();"undefined"!=typeof g.grid.verticalScrollbarWidth&&void 0!==g.grid.verticalScrollbarWidth&&g.grid.verticalScrollbarWidth>0&&(a+=g.grid.verticalScrollbarWidth);var b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,j=a,k=!1,l=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(j/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",k=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,k=!0)});var m=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return m.indexOf(a.widthType)-m.indexOf(b.widthType)}).forEach(function(a){var b=l(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,j-=a.drawnWidth}),k&&j>0&&c>0&&a>c){var n=function(a){j>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,j--)},o=0;do o=j,b.forEach(n);while(j>0&&j!==o)}c=Math.max(c,a);var p="";return b.forEach(function(a){p+=a.getColClassDefinition()}),i.verticalScrollbarWidth&&(c+=i.verticalScrollbarWidth),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),p}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(a){var d=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(d.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};c.setMenuItemTitle(e,b,a.grid),d.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},c.setMenuItemTitle(e,b,a.grid),d.push(e)}}),d):d},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d){var g,h,i=this;i.showMenu=a.showMenu=function(c,f){a.shown?a.shownMid||(g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!0,h.removeClass(g,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))):(a.shown=!0,b(function(){g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!0,h.removeClass(g,"ng-hide",function(){a.$emit("menu-shown")})):(a.shownMid=!0,a.$emit("menu-shown"))}));var i="click";f&&f.originalEvent&&f.originalEvent.type&&"touchstart"===f.originalEvent.type&&(i=f.originalEvent.type),angular.element(document).off("click touchstart",j),b(function(){angular.element(document).on(i,j)})},i.hideMenu=a.hideMenu=function(){a.shown&&(g=d[0].querySelectorAll(".ui-grid-menu-mid"),h=e.enableAnimations(g),h?(a.shownMid=!1,h.addClass(g,"ng-hide",function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))})):(a.shownMid=!1,a.shown=!1)),angular.element(document).off("click touchstart",j)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var j=function(){a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",j),a.$on("$destroy",function(){angular.element(document).off("click touchstart",j)}),a.$on("$destroy",function(){angular.element(c).off("resize",j)}),a.$on("$destroy",a.$on(f.events.GRID_SCROLL,j)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,j))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){var e=d.getScrollbarWidth();angular.isNumber(e)||(e=0);var f=d.detectBrowser();return"ie"===f&&(e+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,f,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*e+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,e=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(e-=l.grid.horizontalScrollbarHeight);var f=c/e;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=d.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,e){if(!e.target||e.target!==b&&!angular.element(e.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=e.target,"vertical"===a.type){if(e.y&&"undefined"!=typeof e.y.percentage&&void 0!==e.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,e.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&e.x&&"undefined"!=typeof e.x.percentage&&void 0!==e.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,e.x.percentage*h);b[0].scrollLeft=d.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",e+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=e,o.verticalScrollbarWidth=e,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",e+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=e,n.horizontalScrollbarHeight=e,r=d.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=d.elementHeight(b):"horizontal"===a.type&&(s=d.elementWidth(b));var t=d.closestElm(b,".ui-grid"),u=d.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(c.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(e,f,g,h){function i(a,b){if(b.y&&e.bindScrollVertical){n.prevScrollArgs=b;var c=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(c+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)f=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,f*c);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(b.x&&e.bindScrollHorizontal){n.prevScrollArgs=b;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=d.normalizeScrollLeft(n.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=d.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=d.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=d.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-v),c=-(e-u),y=1>c?-1:1,z=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(w+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(x+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(c){function d(){a(function(){var a={target:c.target};if(0!==u){var b=(n.viewport[0].scrollTop+u)/(p.getCanvasHeight()-p.getViewportHeight());a.y={percentage:b,pixels:u}}if(0!==v){var e=(n.viewport[0].scrollLeft+v)/(q.getCanvasWidth()-q.getViewportWidth());a.x={percentage:e,pixels:v}}m.fireScrollingEvent(a),s-=1,u/=2,v/=2,s>0?d():m.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},r)}c.originalEvent&&(c=c.originalEvent),c.preventDefault(),b.unbind("touchmove",j),b.unbind("touchend",k),b.unbind("touchcancel",k);var e=n.viewport[0].scrollTop,f=n.viewport[0].scrollTop,g=Math.abs(e-w),h=Math.abs(f-x),i=new Date-t,l=g/i,o=h/i,r=63,s=8,u=120*y*l,v=120*z*o;d()}function l(){var a="",b=q.getCanvasWidth(),c=q.getViewportWidth(),d=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==r.explicitHeaderHeight&&null!==r.explicitHeaderHeight&&r.explicitHeaderHeight>0?a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.explicitHeaderHeight+"px; }":void 0!==r.innerHeaderHeight&&null!==r.innerHeaderHeight&&r.innerHeaderHeight>0&&(a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.innerHeaderHeight+"px; }"),a}var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer,r=o.renderContainers[e.containerId];f.addClass("ui-grid-render-container-"+e.containerId);var s;(e.bindScrollHorizontal||e.bindScrollVertical)&&(s=e.$on(c.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=d.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var e=-120*b.deltaY,g=(n.viewport[0].scrollTop+e)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:e}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var t,u=0,v=0,w=0,x=0,y=1,z=1;d.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),t=new Date,u=a.targetTouches[0].screenY,v=a.targetTouches[0].screenX,w=n.viewport[0].scrollTop,x=n.viewport[0].scrollLeft,b.on("touchmove",j),b.on("touchend touchcancel",k)}),f.bind("$destroy",function(){s(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil",function(a){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(b,c,d,e){var f=e[0],g=e[1];
    +b.containerCtrl=g;{var h=g.rowContainer,i=g.colContainer;f.grid}b.grid=f.grid,b.rowContainer=g.rowContainer,b.colContainer=g.colContainer,g.viewport=c,c.on("scroll",function(){var d=c[0].scrollTop,e=a.normalizeScrollLeft(c),g=-1,j=-1;if(e!==i.prevScrollLeft){var k=(e-i.prevScrollLeft,i.getCanvasWidth()-i.getViewportWidth());g=e/k,i.adjustScrollHorizontal(e,g)}if(d!==h.prevScrollTop){var l=(d-h.prevScrollTop,h.getCanvasHeight()-h.getViewportHeight());j=d/l,j>1&&(j=1),0>j&&(j=0),h.adjustScrollVertical(d,j)}if(!b.grid.isScrollingVertically&&!b.grid.isScrollingHorizontally){var m={};g>-1&&(m.x={percentage:g}),j>-1&&(m.y={percentage:j}),f.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN),n.grid.refresh()}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&(c.uiGridColumns||0!==n.grid.options.columnDefs.length||n.grid.buildColumnDefsFromData(b),d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()}))),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,n.getExternalScopes=a.getExternalScopes,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireScrollingEvent=d.throttle(function(b){a.$broadcast(f.events.GRID_SCROLL,b)},n.grid.options.scrollThrottle,{trailing:!0}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window",function(a,b,c,d){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,e,f){function g(){h.gridWidth=a.gridWidth=c.elementWidth(b),h.gridHeight=a.gridHeight=c.elementHeight(b),h.queueRefresh()}var h=f.grid;if(f.scrollbars=[],h.renderingComplete(),h.element=b,h.gridWidth=a.gridWidth=c.elementWidth(b),h.canvasWidth=f.grid.gridWidth,h.gridHeight=a.gridHeight=c.elementHeight(b),h.gridHeight<h.options.rowHeight){var i=h.options.minRowsToShow*h.options.rowHeight;b.css("height",i+"px"),h.gridHeight=a.gridHeight=c.elementHeight(b)}h.refreshCanvas();var j=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');b.prepend(j),f.innerCompile(j);var k=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');b.append(k),f.innerCompile(k),a.$watch(function(){return h.hasLeftContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),a.$watch(function(){return h.hasRightContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),angular.element(d).on("resize",g),b.on("$destroy",function(){angular.element(d).off("resize",g)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0===h&&e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),e=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,e()},b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange)};return o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b){var c=d.nextUid();return b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[c]={callback:a,types:b},c},o.prototype.deregisterDataChangeCallback=function(a){delete this.dataChangeCallbacks[a]},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&b.callback(this)})},o.prototype.notifyDataChange=function(a,b){var c=e.dataChange;b===c.ALL||b===c.COLUMN||b===c.EDIT||b===c.ROW?a.callDataChangeCallbacks(b):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+b)},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},o.prototype.buildColumns=function(){var b,c=this,e=[],f=c.rowHeaderColumns.length;for(b=0;b<c.columns.length;b++)c.getColDef(c.columns[b].name)||(c.columns.splice(b,1),b--);return c.rowHeaderColumns.forEach(function(a){c.columns.unshift(a)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var h=c.getColumn(a.name);h?h.updateColumnDef(a):(h=new g(a,d.nextUid(),c),c.columns.splice(b+f,0,h)),c.columnBuilders.forEach(function(b){e.push(b.call(c,a,h,c.options))})}),a.all(e)},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},o.prototype.modifyRows=function(b){var c,d,e=this;if(0===e.rows.length&&b.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<b.length;c++)d=b[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(b),e.assignTypes()}else if(b.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<b.length;c++){d=b[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||b;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,b);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=a.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=a.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return a.all([r,s])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",e.prototype.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.scope,a.eventId,a.handler,c.grid)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$broadcast.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b){var c=f(a,g,b,d.grid),e={handler:b,dereg:c,eventId:g,scope:a};d.listeners.push(e),a.$on("$destroy",function(){e.dereg=null,e.handler=null,e.eventId=null,e.scope=null})}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));var e="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var f=b.width.replace(/%/g,""),g=parseInt(f,10);if(isNaN(g))throw new Error(e);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(e);c.width=b.width}d.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())},c.minWidth=b.minWidth?b.minWidth:30,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.footerCellClass=b.footerCellClass,c.cellClass=b.cellClass,c.headerCellClass=b.headerCellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var h=[];b.filter?h.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&h.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",h)},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.getAggregationText("aggregation.count",a.grid.getVisibleRowCount()):a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),a.getAggregationText("aggregation.sum",c)):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,a.getAggregationText("aggregation.avg",c)):a.aggregationType===b.aggregationTypes.min?a.getAggregationText("aggregation.min",Math.min.apply(null,e)):a.aggregationType===b.aggregationTypes.max?a.getAggregationText("aggregation.max",Math.max.apply(null,e)):" "},d.prototype.getAggregationText=function(a,b){var d=this;return d.colDef.aggregationHideLabel?b:c.getSafeText(a)+b},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){return{initialize:function(b){return b.onRegisterApi=b.onRegisterApi||angular.noop(),b.data=b.data||[],b.columnDefs=b.columnDefs||[],b.excludeProperties=b.excludeProperties||["$$hashKey"],b.enableRowHashing=b.enableRowHashing!==!1,b.rowIdentity=b.rowIdentity||function(b){return a.hashKey(b)},b.getRowIdentity=b.getRowIdentity||function(a){return a.$$hashKey},b.headerRowHeight="undefined"!=typeof b.headerRowHeight?b.headerRowHeight:30,b.rowHeight=b.rowHeight||30,b.maxVisibleRowCount=b.maxVisibleRowCount||200,b.minRowsToShow="undefined"!=typeof b.minRowsToShow?b.minRowsToShow:10,b.showFooter=b.showFooter===!0,b.footerRowHeight="undefined"!=typeof b.footerRowHeight?b.footerRowHeight:30,b.columnWidth="undefined"!=typeof b.columnWidth?b.columnWidth:50,b.maxVisibleColumnCount="undefined"!=typeof b.maxVisibleColumnCount?b.maxVisibleColumnCount:200,b.virtualizationThreshold="undefined"!=typeof b.virtualizationThreshold?b.virtualizationThreshold:20,b.columnVirtualizationThreshold="undefined"!=typeof b.columnVirtualizationThreshold?b.columnVirtualizationThreshold:10,b.excessRows="undefined"!=typeof b.excessRows?b.excessRows:4,b.scrollThreshold="undefined"!=typeof b.scrollThreshold?b.scrollThreshold:4,b.excessColumns="undefined"!=typeof b.excessColumns?b.excessColumns:4,b.horizontalScrollThreshold="undefined"!=typeof b.horizontalScrollThreshold?b.horizontalScrollThreshold:2,b.scrollThrottle="undefined"!=typeof b.scrollThrottle?b.scrollThrottle:70,b.enableSorting=b.enableSorting!==!1,b.enableFiltering=b.enableFiltering===!0,b.enableColumnMenus=b.enableColumnMenus!==!1,b.enableScrollbars=b.enableScrollbars!==!1,b.minimumColumnSize="undefined"!=typeof b.minimumColumnSize?b.minimumColumnSize:10,b.rowEquality=b.rowEquality||function(a,b){return a===b},b.headerTemplate=b.headerTemplate||null,b.footerTemplate=b.footerTemplate||null,b.rowTemplate=b.rowTemplate||"ui-grid/ui-grid-row",b}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil",function(a){function b(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return b.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},b.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},b.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},b.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},b.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},b.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},b.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},b.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},b.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},b.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},b.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b
    +},b.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},b.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},b.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},b.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},b.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},b.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},b.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},b.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},b.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},b.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},b.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},b.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},b.prototype.updateColumnWidths=function(){var b=this,c=[],d=[],e=0,f=b.getViewportWidth();"undefined"!=typeof b.grid.verticalScrollbarWidth&&void 0!==b.grid.verticalScrollbarWidth&&b.grid.verticalScrollbarWidth>0&&(f+=b.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=b.visibleColumnCache;k.forEach(function(b){if(b.visible){var f=!1;angular.isNumber(b.width)||(f=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(e=parseInt(e+b.width.length,10),c.push(b)):f?d.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),b.grid.verticalScrollbarWidth&&(i+=b.grid.verticalScrollbarWidth),b.canvasWidth=parseInt(i,10),this.columnStyles=j},b}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell",d.cellTemplatePromise=a.getTemplate(c.cellTemplate)),d.cellTemplatePromise=a.getTemplate(c.cellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["gridUtil","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){o.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){o.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(a){o.LOG_DEBUG_MESSAGES&&b.debug(a)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=p.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=p.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Total Artículos:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"total filas: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar nombres de columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿existe información aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"Archivo json importado debe contener un arreglo, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(c,d,e,f){function g(){j=b.elementHeight(d),i=b.elementWidth(d)}function h(){a.cancel(k),k=a(function(){var a=b.elementHeight(d),c=b.elementWidth(d);a!==j||c!==i?(f.grid.gridHeight=a,f.grid.gridWidth=c,f.grid.refresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),c.$on("$destroy",function(){a.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};if(null!==d){var g=a.renderContainers.body.visibleRowCache.indexOf(d),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;f.y={percentage:i}}null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(a,b){return{replace:!0,priority:-99999,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(){},post:function(a,c,d,e){var f=e.grid;b.decorateRenderContainers(f)}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","gridUtil","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0),b.grid.queueRefresh()}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=b.colContainer.cellNav.getNextRowCol(d,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),c.stopPropagation(),c.preventDefault(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.MODEL_COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var c=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),c.removeClass("ui-grid-cell-contents-hidden"),a&&t&&c.focus(),t=!1,s=!1,h(),d.grid.api.core.notifyDataChange(d.grid,b.dataChange.EDIT)}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.refresh()}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",width:40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){var e=c(d)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=b.getColumn("expandableButtons").width;return".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);
    +a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c,e){var f=this.getColumnHeaders(a,c),g=this.getData(a,b,c),h=this.formatAsCsv(f,g,a.options.exporterCsvColumnSeparator);!e&&a.options.exporterCsvLinkElement&&(e=a.options.exporterCsvLinkElement),e?this.renderCsvLink(a,h,e):d.logError("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,d){var e=[];return angular.forEach(a.columns,function(f){!f.visible&&d!==b.ALL||f.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(f.name)||e.push({name:f.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(f.displayName):f.displayName,width:f.drawnWidth?f.drawnWidth:f.width,align:"number"===f.colDef.type?"right":"left"})}),e},getData:function(a,e,f){var g,h=[];switch(e){case b.ALL:g=a.rows;break;case b.VISIBLE:g=a.getVisibleRows();break;case b.SELECTED:a.api.selection?g=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return b.ALL?(angular.forEach(g,function(d){var e=[];angular.forEach(a.columns,function(g){!g.visible&&f!==b.ALL||g.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(g.name)||e.push(a.options.exporterFieldCallback(a,d,g,a.getCellValue(d,g)))}),h.push(e)}),h):void 0},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return a.displayName}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,c,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){var f=angular.element(d);f.children("a").html(f.children("a").html().replace(b.LINK_LABEL,a.options.exporterLinkLabel)),f.children("a").attr("href",f.children("a").attr("href").replace(b.CSV_CONTENT,encodeURIComponent(c)));var h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&h.content.unshift(a.options.exporterPdfHeader),a.options.exporterPdfFooter&&h.content.push(a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a,b){i.importFile(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(a,c),a.deregisterDataChangeCallback(d)},[b.dataChange.ROW]),e=function(){a.deregisterDataChangeCallback(d)};a.importer.$scope.$on("$destroy",e)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){if(1===a.srcElement.files.length){var c=a.srcElement.files[0];b.importThisFile(i,c),a.srcElement.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout",function(a,b){var c={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){b.redrawColumnAtPosition(a,c,d)}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var e=a.columns,f=function(a){for(var b=a,c=0;b>=c;c++)(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};c=f(c),d=f(d);var g=e[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)e[h]=e[h-1];else if(d>c)for(var i=c;d>i;i++)e[i]=e[i+1];e[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return c}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(b,e,f,g){if(b.col.colDef.enableColumnMoving){var h=function(h){if("ui-grid-icon-angle-down"!==h.toElement.className){var i=e.clone();e.append(i),i.addClass("movingColumn");var j={},k=b.grid.element[0].getBoundingClientRect().left,l=e[0].getBoundingClientRect().left;j.left=l-k+"px";var m,n=b.grid.element[0].getBoundingClientRect().right,o=e[0].getBoundingClientRect().right;o>n&&(m=b.col.drawnWidth+(n-o),j.width=m+"px"),i.css(j);var p=h.pageX,q=0,r=k+b.grid.getViewportWidth()-b.grid.verticalScrollbarWidth,s=function(a){g.fireEvent("hide-menu");var c=i[0].getBoundingClientRect().left-1,d=i[0].getBoundingClientRect().right,e=a.pageX-p,f=c-k+e;f=r>f?f:r,(c>=k||e>0)&&(r>=d||0>e)?i.css({visibility:"visible",left:f+"px"}):(e*=5,g.fireScrollingEvent({x:{pixels:2.5*e}})),q+=e,p=a.pageX,m<b.col.drawnWidth&&(m+=Math.abs(e),i.css({width:m+"px"}))};b.$on("$destroy",function(){d.off("mousemove",s),d.off("mouseup",t)}),d.on("mousemove",s);var t=function(e){var h,j=a.defer();f.$observe("renderIndex",function(a){h=b.$eval(a),j.resolve()}),j.promise.then(function(){i&&i.remove();for(var a=b.grid.renderContainers.body.renderedColumns,f=0,j=b.grid.columns,k=0;k<j.length&&j[k].colDef.name!==a[0].colDef.name;k++)f++;if(0>q){for(var l=0,m=h-1;m>=0;m--)if(l+=a[m].drawnWidth,l>Math.abs(q)){c.redrawColumnAtPosition(b.grid,f+h,f+m+1);break}l<Math.abs(q)&&c.redrawColumnAtPosition(b.grid,f+h,f+0)}else if(q>0){for(var n=0,o=h+1;o<a.length;o++)if(n+=a[o].drawnWidth,n>q){c.redrawColumnAtPosition(b.grid,f+h,f+o-1);break}q>n&&c.redrawColumnAtPosition(b.grid,f+h,f+a.length-1)}else if(0===q){var p=!1;e.shiftKey&&(p=!0),g.grid.sortColumn(b.col,p).then(function(){g.columnMenuScope&&g.columnMenuScope.hideMenu(),g.grid.refresh()})}d.off("mousemove",s),d.off("mouseup",t)})};d.on("mouseup",t)}};e.on("mousedown",h)}}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ui.grid"]);a.service("uiGridPaginationService",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options),b.pagination={page:1,totalPages:1};var c={methods:{pagination:{getPage:function(){return b.pagination.page},getTotalPages:function(){return b.pagination.totalPages},nextPage:function(){b.pagination.page++,b.refresh()},previousPage:function(){b.pagination.page=Math.max(1,b.pagination.page-1),b.refresh()},seek:function(a){if(!angular.isNumber(a)||1>a)throw"Invalid page number: "+a;b.pagination.page=a,b.refresh()}}}};b.api.registerMethodsFromObject(c.methods),b.registerRowsProcessor(function(a){if(!b.options.enablePagination)return a;b.pagination.totalPages=Math.max(1,Math.ceil(a.length/b.options.rowsPerPage));var c=(b.pagination.page-1)*b.options.rowsPerPage;return c>=a.length&&(b.pagination.page=b.pagination.totalPages,c=(b.pagination.page-1)*b.options.rowsPerPage),a.slice(c,c+b.options.rowsPerPage)})},defaultGridOptions:function(a){a.enablePagination=a.enablePagination!==!1,a.rowsPerPage=angular.isNumber(a.rowsPerPage)?a.rowsPerPage:10}};return a}),a.directive("uiGridPagination",["uiGridPaginationService",function(a){return{priority:-400,scope:!1,require:"^uiGrid",link:{pre:function(b,c,d,e){a.initializeGrid(e.grid)}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?"*"===b.width?b.grid.refresh().then(function(){b.renderContainer="left",b.width=b.grid.canvasWidth/b.grid.columns.length,b.grid.createLeftContainer()}):(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&("*"===b.width?b.grid.refresh().then(function(){b.renderContainer="right",b.width=b.grid.canvasWidth/b.grid.columns.length,b.grid.createRightContainer()}):(b.renderContainer="right",b.grid.createRightContainer())),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","columnBounds","uiGridResizeColumnsService",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(g,h,i,j){function k(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function l(){j.grid.buildColumns().then(function(){j.grid.refreshCanvas(!0)})}function m(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),p=a.clientX-q,0>p?p=0:p>j.grid.gridWidth&&(p=j.grid.gridWidth);var b,e=g.col,h=e.getRenderContainer();if("left"===g.position?(e=h.renderedColumns[g.renderIndex-1],b=g.col):"right"===g.position&&(b=h.renderedColumns[g.renderIndex+1]),e.colDef.enableColumnResizing!==!1){j.grid.element.hasClass("column-resizing")||j.grid.element.addClass("column-resizing");var i=p-o,k=e.drawnWidth+i;e.colDef.minWidth&&k<e.colDef.minWidth?p+=e.colDef.minWidth-k:!e.colDef.minWidth&&d.minWidth&&k<d.minWidth?p+=e.colDef.minWidth-k:e.colDef.maxWidth&&k>e.colDef.maxWidth&&(p+=e.colDef.maxWidth-k),f.css({left:p+"px"}),j.fireEvent(c.events.ITEM_DRAGGING)}}function n(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),j.grid.element.removeClass("column-resizing"),f.remove(),p=b.clientX-q;var c=p-o;if(0===c)return a.off("mouseup",n),void a.off("mousemove",m);var h,i=g.col,r=i.getRenderContainer();if("left"===g.position?(i=r.renderedColumns[g.renderIndex-1],h=g.col):"right"===g.position&&(h=r.renderedColumns[g.renderIndex+1]),i.colDef.enableColumnResizing!==!1){var s=parseInt(i.drawnWidth+c,10);i.colDef.minWidth&&s<i.colDef.minWidth?s=i.colDef.minWidth:!i.colDef.minWidth&&d.minWidth&&s<d.minWidth&&(s=d.minWidth),i.colDef.maxWidth&&s>i.colDef.maxWidth&&(s=i.colDef.maxWidth),i.width=s,k(i),l(c),e.fireColumnSizeChanged(j.grid,i.colDef,c),a.off("mouseup",n),a.off("mousemove",m)}}var o=0,p=0,q=0;"left"===g.position?h.addClass("left"):"right"===g.position&&h.addClass("right"),h.on("mousedown",function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),q=j.grid.element[0].getBoundingClientRect().left,o=b.clientX-q,j.grid.element.append(f),f.css({left:o}),a.on("mouseup",n),a.on("mousemove",m)}),h.on("dblclick",function(a){a.stopPropagation();var f,i,m=g.col,n=m.getRenderContainer();"left"===g.position?(m=n.renderedColumns[g.renderIndex-1],f=g.col,i=1):"right"===g.position&&(f=n.renderedColumns[g.renderIndex+1],f=n.renderedColumns[g.renderIndex+1],i=-1);var o=0,p=0,q=b.closestElm(h,".ui-grid-render-container"),r=q.querySelectorAll("."+c.COL_CLASS_PREFIX+m.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(r,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var f=b.elementWidth(c);e+=f}e>o&&(o=e,p=o-e)})}),m.colDef.minWidth&&o<m.colDef.minWidth?o=m.colDef.minWidth:!m.colDef.minWidth&&d.minWidth&&o<d.minWidth&&(o=d.minWidth),m.colDef.maxWidth&&o>m.colDef.maxWidth&&(o=m.colDef.maxWidth),m.width=parseInt(o,10),k(m),l(p),e.fireColumnSizeChanged(j.grid,m.colDef,p)}),h.on("$destroy",function(){h.off("mousedown"),h.off("dblclick"),a.off("mousemove",m),a.off("mouseup",n)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){f.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEdit.dirtyRows?a.rowEdit.dirtyRows:[]},getErrorRows:function(a){return a.rowEdit.errorRows?a.rowEdit.errorRows:[]},flushDirtyRows:function(a){return f.flushDirtyRows(a)},setRowsDirty:function(a,b){f.setRowsDirty(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";
    +return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c){var d=b.renderContainers.body.visibleRowCache[c];null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},selectAllVisibleRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.visible?d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c)):d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(a){return a.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;if(d||f){if(!d&&f){var g=a.getSelectedRows(b);g.length>1&&(f=!1,a.clearSelectedRows(b))}}else a.clearSelectedRows(b);f&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=[],j=f;g>=j;j++){var k=b.renderContainers.body.visibleRowCache[j];k&&(k.isSelected||(k.isSelected=!0,b.selection.lastSelectedRow=k,a.decideRaiseSelectionEvent(b,k,i)))}a.decideRaiseSelectionBatchEvent(b,i)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){var c=[];a.getSelectedRows(b).forEach(function(d){d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)},decideRaiseSelectionEvent:function(a,b,c){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b)},decideRaiseSelectionBatchEvent:function(a,b){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:30,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1};f.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(){c.selection.selectAll?(b.clearSelectedRows(c),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){var c=0,d=300,e=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()};b.on("touchstart",function(){c=(new Date).getTime()}),b.on("touchend",function(a){var b=(new Date).getTime(),f=b-c;d>f&&e(a)}),b.on("click",function(a){e(a)})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)">&nbsp;</div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.14/ui-grid.svg b/release/3.0.0-rc.14/ui-grid.svg
    new file mode 100644
    index 000000000..18634ed72
    --- /dev/null
    +++ b/release/3.0.0-rc.14/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m0 29v71q0 15 11 25t25 11h785q15 0 26-11t10-25v-71q0-15-10-26t-26-10h-785q-15 0-25 10t-11 26z m0 285v72q0 14 11 25t25 10h785q15 0 26-10t10-25v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25z m0 286v71q0 15 11 26t25 10h785q15 0 26-10t10-26v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.14/ui-grid.ttf b/release/3.0.0-rc.14/ui-grid.ttf
    new file mode 100644
    index 000000000..081bc1440
    Binary files /dev/null and b/release/3.0.0-rc.14/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.14/ui-grid.woff b/release/3.0.0-rc.14/ui-grid.woff
    new file mode 100644
    index 000000000..e1a95cbf5
    Binary files /dev/null and b/release/3.0.0-rc.14/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.15/ui-grid.css b/release/3.0.0-rc.15/ui-grid.css
    new file mode 100644
    index 000000000..faace9d30
    --- /dev/null
    +++ b/release/3.0.0-rc.15/ui-grid.css
    @@ -0,0 +1,1236 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: fixed;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.15/ui-grid.eot b/release/3.0.0-rc.15/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-rc.15/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.15/ui-grid.js b/release/3.0.0-rc.15/ui-grid.js
    new file mode 100644
    index 000000000..5e81bb4c9
    --- /dev/null
    +++ b/release/3.0.0-rc.15/ui-grid.js
    @@ -0,0 +1,17181 @@
    +/*! ui-grid - v3.0.0-rc.15 - 2014-11-11
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1,
    +      WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          var deregisterFunction = function() {
    +           $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.headerCellClass) {
    +              updateClass();
    +            }
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            var deregisterFunction = function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            };
    +
    +            $scope.$on( '$destroy', deregisterFunction );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false) {
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                }
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +
    +
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', function( gridUtil, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        $scope.$apply(function () {
    +          $scope.hideMenu();
    +        });
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = grid.verticalScrollbarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = grid.horizontalScrollbarHeight;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // gridUtil.logDebug('headerHeight in scrollbar', headerHeight);
    +
    +          var ondemand  = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-y:auto;" : "";
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px;' +ondemand +'}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          var bottom = gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ondemand = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-x:auto" : "";
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px;' +ondemand + ' }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // gridUtil.logDebug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil',
    +    function(gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (n) {
    +          if (self.grid.columns.length === ( self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0 ) ) {
    +            // gridUil.logDebug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.hideHeader ? 0 : grid.options.headerRowHeight;
    +                var footerHeight = grid.options.showFooter ? grid.options.footerRowHeight : 0;
    +                var scrollbarHeight = grid.options.enableScrollbars ? gridUtil.getScrollbarWidth() : 0;
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = GridOptions.initialize( options );
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +  self.dataChangeCallbacks = {};
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name addRowHeaderColumn
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description adds a row header column to the grid
    +   * @param {object} column def
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortHandleNulls
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description A null handling method that can be used when building custom sort
    +   * functions
    +   * @example
    +   * <pre>
    +   *   mySortFn = function(a, b) {
    +   *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +   *   if ( nulls !== null ){
    +   *     return nulls;
    +   *   } else {
    +   *     // your code for sorting here
    +   *   };
    +   * </pre>
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +
    +  /**
    +   * @ngdoc method
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Notify the grid that a data or config change has occurred,
    +   * where that change isn't something the grid was otherwise noticing.  This 
    +   * might be particularly relevant where you've changed values within the data
    +   * and you'd like cell classes to be re-evaluated, or changed config within 
    +   * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +   * @param {Grid} grid the grid
    +   * @param {string} type one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +   * us which refreshes to fire.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +  
    +  self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN ).  Optional and defaults to
    +   * ALL 
    +   * @returns {string} uid of the callback, can be used to deregister it again
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types };
    +    return uid;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name deregisterDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description Delete the callback identified by the id.
    +   * @param {string} uid the uid of the function that is to be deregistered
    +   */
    +  Grid.prototype.deregisterDataChangeCallback = function deregisterDataChangeCallback(uid) {
    +    delete this.dataChangeCallbacks[uid];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, and COLUMN callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        callback.callback( this );
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {Grid} grid the grid
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(grid, type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ){
    +      grid.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag 
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.refresh();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +        if (wasEmpty) {
    +           self.assignTypes();
    +        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow 
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', GridRow.prototype.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed, 
    +           * and that is the one that would have been useful.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.  A number of settings are supported:
    +    * 
    +    * - title: controls the title that is displayed in the menu
    +    * - icon: the icon shown alongside that title
    +    * - action: the method to call when the menu is clicked
    +    * - shown: a function to evaluate to determine whether or not to show the item
    +    * - active: a function to evaluate to determine whether or not the item is currently selected
    +    * - context: context to pass to the action function??
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       shown: function() { return true; },
    +    *       active: function() { return true; },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        return self.getAggregationText('aggregation.count', self.grid.getVisibleRowCount());
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        return self.getAggregationText('aggregation.sum', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        return self.getAggregationText('aggregation.avg', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return self.getAggregationText('aggregation.min', Math.min.apply(null, cellValues));
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return self.getAggregationText('aggregation.max', Math.max.apply(null, cellValues));
    +      }
    +      else {
    +        return '\u00A0';
    +      }
    +    };
    +    
    +   /** 
    +    * @ngdoc property
    +    * @name aggregationHideLabel
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description defaults to false, if set to true hides the label text
    +    * in the aggregation footer, so only the value is displayed.
    +    *
    +    */
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationText
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description converts the aggregation value into a text string, including 
    +     * i18n and deciding whether or not to display based on colDef.aggregationHideLabel
    +     * 
    +     * @param {string} label the i18n lookup value to use for the column label
    +     * @param {number} value the calculated aggregate value for this column
    +     * 
    +     */
    +    GridColumn.prototype.getAggregationText = function ( label, value ) {
    +      var self = this;
    +      if ( self.colDef.aggregationHideLabel ){
    +        return value;
    +      } else {
    +        return i18nService.getSafeText(label) + value;
    +      }
    +    };
    +
    +    GridColumn.prototype.getCellTemplate = function () {
    +      var self = this;
    +
    +      return self.cellTemplatePromise;
    +    };
    +
    +    GridColumn.prototype.getCompiledElementFn = function () {
    +      var self = this;
    +      
    +      return self.compiledElementFnDefer.promise;
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +  
    +      baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +      baseOptions.maxVisibleRowCount = baseOptions.maxVisibleRowCount || 200;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      baseOptions.showFooter = baseOptions.showFooter === true;
    +      baseOptions.footerRowHeight = typeof(baseOptions.footerRowHeight) !== "undefined" ? baseOptions.footerRowHeight : 30;
    +  
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      // Turn virtualization on when number of data elements goes over this number
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      // Extra rows to to render outside of the viewport
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      // Extra columns to to render outside of the viewport
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      // Default time to throttle scroll events to.
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      // Columns can't be smaller than 10 pixels
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', function(gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //gridUtil.logDebug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.headerCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.cellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.cellTemplate = colDef.cellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.cellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logDebug: function( logMessage ){
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug( logMessage );
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.refresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so 
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         * 
    +         * To get to row 9 (i.e. the last row) in the same list, we want to 
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll, 
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            args.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var grid = uiGridCtrl.grid;
    +              //needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, gridUtil, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = $scope.colContainer.cellNav.getNextRowCol(direction, $scope.row, $scope.col);
    +
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            evt.stopPropagation();
    +            evt.preventDefault();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          //this event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            // gridUtil.logDebug('setFocused: ' + div[0].parentElement.className);
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +            $scope.grid.queueRefresh();
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( $scope.grid, uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight; 
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + displayName; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCOl and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            gridUtil.logError( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? grid.options.exporterHeaderFilter(gridCol.displayName) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  extractedRow.push( grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) );
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +
    +              var template = angular.element(contents);
    +
    +              template.children("a").html(
    +                  template.children("a").html().replace(
    +                      uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel));
    +
    +              template.children("a").attr("href", 
    +                  template.children("a").attr("href").replace(
    +                      uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent)));
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.content.unshift( grid.options.exporterPdfHeader );
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.content.push( grid.options.exporterPdfFooter );
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {Grid} grid the grid we're importing into
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( grid, fileObject ) {
    +                  service.importFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and ift he rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var callbackId = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( grid, newObjects );
    +              grid.deregisterDataChangeCallback( callbackId );
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            var deregisterClosure = function() {
    +              grid.deregisterDataChangeCallback( callbackId );
    +            };
    +  
    +            grid.importer.$scope.$on( '$destroy', deregisterClosure );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            if (event.srcElement.files.length === 1) {
    +              var fileObject = event.srcElement.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              event.srcElement.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', function ($q, $timeout) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.on.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                self.redrawColumnAtPosition(grid, originalPosition, finalPosition);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +        var columns = grid.columns;
    +
    +        //Function to find column position for a render index, ths is needed to take care of
    +        // invisible columns and row headers
    +        var findPositionForRenderIndex = function (index) {
    +          var position = index;
    +          for (var i = 0; i <= position; i++) {
    +            if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +              position++;
    +            }
    +          }
    +          return position;
    +        };
    +
    +        originalPosition = findPositionForRenderIndex(originalPosition);
    +        newPosition = findPositionForRenderIndex(newPosition);
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and coned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                var mouseDownHandler = function (evt) {
    +                  if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I') {
    +
    +                    //Cloning header cell and appending to current header cell.
    +                    var movingElm = $elm.clone();
    +                    $elm.append(movingElm);
    +
    +                    //Left of cloned element should be aligned to original header cell.
    +                    movingElm.addClass('movingColumn');
    +                    var movingElementStyles = {};
    +                    var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                    var elmLeft = $elm[0].getBoundingClientRect().left;
    +                    movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                    var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                    var elmRight = $elm[0].getBoundingClientRect().right;
    +                    var reducedWidth;
    +                    if (elmRight > gridRight) {
    +                      reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                      movingElementStyles.width = reducedWidth + 'px';
    +                    }
    +                    //movingElementStyles.visibility = 'hidden';
    +                    movingElm.css(movingElementStyles);
    +
    +                    //Setting some variables required for calculations.
    +                    var previousMouseX = evt.pageX;
    +                    var totalMouseMovement = 0;
    +                    var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth() - $scope.grid.verticalScrollbarWidth;
    +
    +                    //Clone element should move horizontally with mouse.
    +                    var mouseMoveHandler = function (evt) {
    +                      uiGridCtrl.fireEvent('hide-menu');
    +                      var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                      var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                      var changeValue = evt.pageX - previousMouseX;
    +                      var newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                      newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +                      if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                        movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                      }
    +                      else {
    +                        changeValue *= 5;
    +                        uiGridCtrl.fireScrollingEvent({ x: { pixels: changeValue * 2.5} });
    +                      }
    +                      totalMouseMovement += changeValue;
    +                      previousMouseX = evt.pageX;
    +                      if (reducedWidth < $scope.col.drawnWidth) {
    +                        reducedWidth += Math.abs(changeValue);
    +                        movingElm.css({'width': reducedWidth + 'px'});
    +                      }
    +                    };
    +
    +                    // On scope destroy, remove the mouse event handlers from the document body
    +                    $scope.$on('$destroy', function () {
    +                      $document.off('mousemove', mouseMoveHandler);
    +                      $document.off('mouseup', mouseUpHandler);
    +                    });
    +
    +                    $document.on('mousemove', mouseMoveHandler);
    +                    var mouseUpHandler = function (evt) {
    +                      var renderIndexDefer = $q.defer();
    +
    +                      var renderIndex;
    +                      $attrs.$observe('renderIndex', function (n, o) {
    +                        renderIndex = $scope.$eval(n);
    +                        renderIndexDefer.resolve();
    +                      });
    +
    +                      renderIndexDefer.promise.then(function () {
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var renderedColumns = $scope.grid.renderContainers['body'].renderedColumns;
    +
    +                        //This method will calculate the number of columns hidden in lift due to scroll
    +                        //renderContainer.prevColumnScrollIndex could also have been used but this is more accurate
    +                        var scrolledColumnCount = 0;
    +                        var columns = $scope.grid.columns;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== renderedColumns[0].colDef.name) {
    +                            scrolledColumnCount++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = renderIndex - 1; il >= 0; il--) {
    +                            totalColumnsLeftWidth += renderedColumns[il].drawnWidth;
    +                            if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + il + 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + 0);
    +                          }
    +                        }
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = renderIndex + 1; ir < renderedColumns.length; ir++) {
    +                            totalColumnsRightWidth += renderedColumns[ir].drawnWidth;
    +                            if (totalColumnsRightWidth > totalMouseMovement) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + ir - 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + renderedColumns.length - 1);
    +                          }
    +                        }
    +                        else if (totalMouseMovement === 0) {
    +                          //sort the current column
    +                          var add = false;
    +                          if (evt.shiftKey) {
    +                            add = true;
    +                          }
    +
    +                          // Sort this column then rebuild the grid's rows
    +                          uiGridCtrl.grid.sortColumn($scope.col, add)
    +                            .then(function () {
    +                              if (uiGridCtrl.columnMenuScope) {
    +                                uiGridCtrl.columnMenuScope.hideMenu();
    +                              }
    +                              uiGridCtrl.grid.refresh();
    +                            });
    +                        }
    +
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      });
    +                    };
    +
    +                    $document.on('mouseup', mouseUpHandler);
    +                  }
    +                };
    +
    +                $elm.on('mousedown', mouseDownHandler);
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', function () {
    +    var service = {
    +
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +        grid.pagination = {page: 1, totalPages: 1};
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.pagination.api:PublicAPI
    +         *
    +         * @description Public API for the pagination feature
    +         */
    +        var publicApi = {
    +          methods: {
    +            pagination: {
    +              /**
    +               * @ngdoc method
    +               * @name getPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the number of the current page
    +               */
    +              getPage: function () {
    +                return grid.pagination.page;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name getTotalPages
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the total number of pages
    +               */
    +              getTotalPages: function () {
    +                return grid.pagination.totalPages;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name nextPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the next page, if possible
    +               */
    +              nextPage: function () {
    +                grid.pagination.page++;
    +                grid.refresh();
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name previousPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the previous page, if we're not on the first page
    +               */
    +              previousPage: function () {
    +                grid.pagination.page = Math.max(1, grid.pagination.page - 1);
    +                grid.refresh();
    +              },
    +              seek: function (page) {
    +                if (!angular.isNumber(page) || page < 1) {
    +                  throw 'Invalid page number: ' + page;
    +                }
    +
    +                grid.pagination.page = page;
    +                grid.refresh();
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +        grid.registerRowsProcessor(function (renderableRows) {
    +          if (!grid.options.enablePagination) {
    +            return renderableRows;
    +          }
    +          grid.pagination.totalPages = Math.max(
    +            1,
    +            Math.ceil(renderableRows.length / grid.options.rowsPerPage)
    +          );
    +
    +          var firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          if (firstRow >= renderableRows.length) {
    +            grid.pagination.page = grid.pagination.totalPages;
    +            firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          }
    +
    +          return renderableRows.slice(
    +            firstRow,
    +            firstRow + grid.options.rowsPerPage
    +          );
    +        });
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pagination.api:GridOptions
    +         *
    +         *  @description GridOptions for the pagination feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePagination
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description Enable pagination for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name rowsPerPage
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description The number of rows that should be displayed per page
    +         *  <br/>Defaults to 10
    +         */
    +        gridOptions.rowsPerPage = angular.isNumber(gridOptions.rowsPerPage) ? gridOptions.rowsPerPage : 10;
    +      }
    +    };
    +
    +    return service;
    +  });
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.pagination.directive:uiGridPagination
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description Adds pagination support to a grid.
    +   */
    +  module.directive('uiGridPagination', ['uiGridPaginationService', function (uiGridPaginationService) {
    +    return {
    +      priority: -400,
    +      scope: false,
    +      require: '^uiGrid',
    +      link: {
    +        pre: function (scope, element, attrs, uiGridCtrl) {
    +          uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      }
    +    };
    +  }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'title', 'Pin Left')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'title', 'Pin Right')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'title', 'Unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', function (gridUtil, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth) * rtlMultiplier;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth) * rtlMultiplier;
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {object} grid the grid for which rows should be set dirty
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function (grid, dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.api:PublicApi
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing 
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected ){
    +                      row.isSelected = true;
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected){
    +                        row.isSelected = true;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.isSelected = false;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                getSelectAllState: function (grid) {
    +                  return grid.selection.selectAll;
    +                }
    +                
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead  
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid);
    +            }
    +          }
    +          
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected ){
    +                rowToSelect.isSelected = true;
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.isSelected = false;
    +              service.decideRaiseSelectionEvent( grid, row, changedRows );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and 
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows);
    +          }
    +        }        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width: 40,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +          
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows();
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              var touchStartTime = 0;
    +              var touchTimeout = 300;
    +              var selectCells = function(evt){
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              };
    +
    +              $elm.on('touchstart', function(event) {
    +                touchStartTime = (new Date()).getTime();
    +              });
    +
    +              $elm.on('touchend', function (evt) {
    +                var touchEndTime = (new Date()).getTime();
    +                var touchTime = touchEndTime - touchStartTime;
    +
    +                if (touchTime < touchTimeout ) {
    +                  // short touch
    +                  selectCells(evt);
    +                }
    +              });
    +
    +              $elm.on('click', function (evt) {
    +                selectCells(evt);
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableVerticalScrollbar\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableHorizontalScrollbar\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.15/ui-grid.min.css b/release/3.0.0-rc.15/ui-grid.min.css
    new file mode 100644
    index 000000000..64a51dc41
    --- /dev/null
    +++ b/release/3.0.0-rc.15/ui-grid.min.css
    @@ -0,0 +1,12 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:fixed;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +
    +.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.15/ui-grid.min.js b/release/3.0.0-rc.15/ui-grid.min.js
    new file mode 100644
    index 000000000..9624a2e7c
    --- /dev/null
    +++ b/release/3.0.0-rc.15/ui-grid.min.js
    @@ -0,0 +1,8 @@
    +/*! ui-grid - v3.0.0-rc.15 - 2014-11-11
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column"},scrollbars:{NEVER:0,ALWAYS:1,WHEN_NEEDED:2}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){b.addClass(a.col.getColClass(!1));var c,e=function(){var d=b;c&&(d.removeClass(c),c=null),c=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,d.addClass(c)};a.col.cellClass&&e();var f=a.grid.registerDataChangeCallback(e,[d.dataChange.COLUMN,d.dataChange.EDIT]),g=function(){a.grid.deregisterDataChangeCallback(f)};a.$on("$destroy",g)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,c,e,f){var g=this;d.initialize(b,f),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,e,f){b.col=a;var h=d.getColumnElementPosition(b,a,e);b.menuShown?(b.colElement=e,b.colElementPosition=h,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(g.shown=b.menuShown=!0,d.repositionMenu(b,a,h,c,e),b.colElement=e,b.colElementPosition=h,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,c){function e(e){b.getTemplate(e).then(function(b){var e=d(b),f=e(a);c.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,d,e){a.grid=e.grid,a.getExternalScopes=e.getExternalScopes,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",function(){a.grid.deregisterDataChangeCallback(h)})}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,a.getExternalScopes=h.getExternalScopes,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,e){function h(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.getExternalScopes=i.getExternalScopes,a.renderContainer=i.grid.renderContainers[j.containerId],c.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var k,l=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),m=function(){var b=c;k&&(b.removeClass(k),k=null),k=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(k)};a.col.headerCellClass&&m();var n=a.grid.registerDataChangeCallback(m,[f.dataChange.COLUMN]),o=function(){a.grid.deregisterDataChangeCallback(n)};a.$on("$destroy",o),a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var p,q=0;if(l.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(q=(new Date).getTime(),p=b(function(){},g),p.then(function(){a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1&&i.columnMenuScope.showMenu(a.col,c,d)}))}),l.on("mouseup touchend",function(){b.cancel(p)}),a.$on("$destroy",function(){l.off("mousedown touchstart")}),a.toggleMenu=function(b){b.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,c)},a.sortable&&(l.on("click touchend",function(a){a.stopPropagation(),b.cancel(p);var c=(new Date).getTime(),d=c-q;d>g||h(a)}),a.$on("$destroy",function(){b.cancel(p)})),a.filterable){var r=[];angular.forEach(a.col.filters,function(b,c){r.push(a.$watch("col.filters["+c+"].term",function(){i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(r,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,a.getExternalScopes=i.getExternalScopes,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.hideHeader?f:a.grid.options.headerTemplate?a.grid.options.headerTemplate:e,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth();"undefined"!=typeof g.grid.verticalScrollbarWidth&&void 0!==g.grid.verticalScrollbarWidth&&g.grid.verticalScrollbarWidth>0&&(a+=g.grid.verticalScrollbarWidth);var b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,j=a,k=!1,l=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(j/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",k=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,k=!0)});var m=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return m.indexOf(a.widthType)-m.indexOf(b.widthType)}).forEach(function(a){var b=l(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,j-=a.drawnWidth}),k&&j>0&&c>0&&a>c){var n=function(a){j>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,j--)},o=0;do o=j,b.forEach(n);while(j>0&&j!==o)}c=Math.max(c,a);var p="";return b.forEach(function(a){p+=a.getColClassDefinition()}),i.verticalScrollbarWidth&&(c+=i.verticalScrollbarWidth),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),p}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(a){var d=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(d.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};c.setMenuItemTitle(e,b,a.grid),d.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},c.setMenuItemTitle(e,b,a.grid),d.push(e)}}),d):d},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a){var d=this;d.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var f="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(f=d.originalEvent.type),angular.element(document).off("click touchstart",e),b(function(){angular.element(document).on(f,e)})},d.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",e)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var e=function(){a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",e),a.$on("$destroy",function(){angular.element(document).off("click touchstart",e)}),a.$on("$destroy",function(){angular.element(c).off("resize",e)}),a.$on("$destroy",a.$on(f.events.GRID_SCROLL,e)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,e))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){var e=d.getScrollbarWidth();angular.isNumber(e)||(e=0);var f=d.detectBrowser();return"ie"===f&&(e+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,f,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),d=o.headerHeight?o.headerHeight:p.headerHeight,e=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-y:auto;":"",f=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return f+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+d+"px;"+e+"}",s=b,f}function i(){var a=o.getCanvasWidth(),b=u;p.options.showFooter&&(b-=1);var d=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-x:auto":"",e=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px;"+d+" }";return e+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,e}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,e=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(e-=l.grid.horizontalScrollbarHeight);var f=c/e;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=d.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,e){if(!e.target||e.target!==b&&!angular.element(e.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=e.target,"vertical"===a.type){if(e.y&&"undefined"!=typeof e.y.percentage&&void 0!==e.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,e.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&e.x&&"undefined"!=typeof e.x.percentage&&void 0!==e.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,e.x.percentage*h);b[0].scrollLeft=d.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",e+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,o.verticalScrollbarWidth=p.verticalScrollbarWidth,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",e+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,n.horizontalScrollbarHeight=p.horizontalScrollbarHeight,r=d.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=d.elementHeight(b):"horizontal"===a.type&&(s=d.elementWidth(b));var t=d.closestElm(b,".ui-grid"),u=d.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(c.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(e,f,g,h){function i(a,b){if(b.y&&e.bindScrollVertical){n.prevScrollArgs=b;var c=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(c+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)f=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,f*c);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(b.x&&e.bindScrollHorizontal){n.prevScrollArgs=b;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=d.normalizeScrollLeft(n.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=d.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=d.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=d.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-v),c=-(e-u),y=1>c?-1:1,z=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(w+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(x+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(c){function d(){a(function(){var a={target:c.target};if(0!==u){var b=(n.viewport[0].scrollTop+u)/(p.getCanvasHeight()-p.getViewportHeight());a.y={percentage:b,pixels:u}}if(0!==v){var e=(n.viewport[0].scrollLeft+v)/(q.getCanvasWidth()-q.getViewportWidth());a.x={percentage:e,pixels:v}}m.fireScrollingEvent(a),s-=1,u/=2,v/=2,s>0?d():m.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},r)}c.originalEvent&&(c=c.originalEvent),c.preventDefault(),b.unbind("touchmove",j),b.unbind("touchend",k),b.unbind("touchcancel",k);var e=n.viewport[0].scrollTop,f=n.viewport[0].scrollTop,g=Math.abs(e-w),h=Math.abs(f-x),i=new Date-t,l=g/i,o=h/i,r=63,s=8,u=120*y*l,v=120*z*o;d()}function l(){var a="",b=q.getCanvasWidth(),c=q.getViewportWidth(),d=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==r.explicitHeaderHeight&&null!==r.explicitHeaderHeight&&r.explicitHeaderHeight>0?a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.explicitHeaderHeight+"px; }":void 0!==r.innerHeaderHeight&&null!==r.innerHeaderHeight&&r.innerHeaderHeight>0&&(a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.innerHeaderHeight+"px; }"),a}var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer,r=o.renderContainers[e.containerId];f.addClass("ui-grid-render-container-"+e.containerId);var s;(e.bindScrollHorizontal||e.bindScrollVertical)&&(s=e.$on(c.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=d.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var e=-120*b.deltaY,g=(n.viewport[0].scrollTop+e)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:e}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var t,u=0,v=0,w=0,x=0,y=1,z=1;d.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),t=new Date,u=a.targetTouches[0].screenY,v=a.targetTouches[0].screenX,w=n.viewport[0].scrollTop,x=n.viewport[0].scrollLeft,b.on("touchmove",j),b.on("touchend touchcancel",k)}),f.bind("$destroy",function(){s(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil",function(a){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(b,c,d,e){var f=e[0],g=e[1];
    +b.containerCtrl=g;{var h=g.rowContainer,i=g.colContainer;f.grid}b.grid=f.grid,b.rowContainer=g.rowContainer,b.colContainer=g.colContainer,g.viewport=c,c.on("scroll",function(){var d=c[0].scrollTop,e=a.normalizeScrollLeft(c),g=-1,j=-1;if(e!==i.prevScrollLeft){var k=(e-i.prevScrollLeft,i.getCanvasWidth()-i.getViewportWidth());g=e/k,i.adjustScrollHorizontal(e,g)}if(d!==h.prevScrollTop){var l=(d-h.prevScrollTop,h.getCanvasHeight()-h.getViewportHeight());j=d/l,j>1&&(j=1),0>j&&(j=0),h.adjustScrollVertical(d,j)}if(!b.grid.isScrollingVertically&&!b.grid.isScrollingHorizontally){var m={};g>-1&&(m.x={percentage:g}),j>-1&&(m.y={percentage:j}),f.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&(c.uiGridColumns||0!==n.grid.options.columnDefs.length||n.grid.buildColumnDefsFromData(b),d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()}))),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,n.getExternalScopes=a.getExternalScopes,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireScrollingEvent=d.throttle(function(b){a.$broadcast(f.events.GRID_SCROLL,b)},n.grid.options.scrollThrottle,{trailing:!0}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window",function(a,b,c,d){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,e,f){function g(){h.gridWidth=a.gridWidth=c.elementWidth(b),h.gridHeight=a.gridHeight=c.elementHeight(b),h.queueRefresh()}var h=f.grid;if(f.scrollbars=[],h.renderingComplete(),h.element=b,h.gridWidth=a.gridWidth=c.elementWidth(b),h.canvasWidth=f.grid.gridWidth,h.gridHeight=a.gridHeight=c.elementHeight(b),h.gridHeight<h.options.rowHeight){var i=h.options.minRowsToShow*h.options.rowHeight,j=h.options.hideHeader?0:h.options.headerRowHeight,k=h.options.showFooter?h.options.footerRowHeight:0,l=h.options.enableScrollbars?c.getScrollbarWidth():0,m=0;angular.forEach(h.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>m&&(m=1):a.hasOwnProperty("filters")&&m<a.filters.length&&(m=a.filters.length)});var n=m*j,o=j+i+k+l+n;b.css("height",o+"px"),h.gridHeight=a.gridHeight=c.elementHeight(b)}h.refreshCanvas();var p=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');b.prepend(p),f.innerCompile(p);var q=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');b.append(q),f.innerCompile(q),a.$watch(function(){return h.hasLeftContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),a.$watch(function(){return h.hasRightContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),angular.element(d).on("resize",g),b.on("$destroy",function(){angular.element(d).off("resize",g)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0===h&&e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),g=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN])};return o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b){var c=d.nextUid();return b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[c]={callback:a,types:b},c},o.prototype.deregisterDataChangeCallback=function(a){delete this.dataChangeCallbacks[a]},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&b.callback(this)},this)},o.prototype.notifyDataChange=function(a,b){var c=e.dataChange;b===c.ALL||b===c.COLUMN||b===c.EDIT||b===c.ROW?a.callDataChangeCallbacks(b):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+b)},o.prototype.columnRefreshCallback=function(a){a.refresh()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},o.prototype.buildColumns=function(){var b,c=this,e=[],f=c.rowHeaderColumns.length;for(b=0;b<c.columns.length;b++)c.getColDef(c.columns[b].name)||(c.columns.splice(b,1),b--);return c.rowHeaderColumns.forEach(function(a){c.columns.unshift(a)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var h=c.getColumn(a.name);h?h.updateColumnDef(a):(h=new g(a,d.nextUid(),c),c.columns.splice(b+f,0,h)),c.columnBuilders.forEach(function(b){e.push(b.call(c,a,h,c.options))})}),a.all(e)},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;var j=0===g.rows.length;for(g.rows.length=0,c=0;c<b.length;c++){var k=b[c];e=i.get(k),f=e?e.row:g.processRowBuilders(new h(k,c,g)),g.rows.push(f),d.put(k,{i:c,entity:k,row:f})}j&&g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var l,m,n;if(g.options.enableRowHashing){l=[],n=[];var o={};for(m=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var p=!1;g.options.getRowIdentity(f)||(p=!0),e=d.get(f),e?e.row&&(o[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),p?n.push(f):l.push(f))}for(c=0;c<g.rows.length;c++){var q=g.rows[c],r=g.options.rowIdentity(q.entity);o[r]||m.push(q)}}var s=l||[],t=n||b;s=s.concat(g.newInN(g.rows,t,"entity")),g.addRows(s);var u=g.getDeletedRows(m||g.rows,b);for(c=0;c<u.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(u[c].entity),g.rows.splice(g.rows.indexOf(u[c]),1)}else g.createRowHashMap(),g.rows.length=0;var v=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),w=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([v,w])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",e.prototype.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.scope,a.eventId,a.handler,c.grid)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$broadcast.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b){var c=f(a,g,b,d.grid),e={handler:b,dereg:c,eventId:g,scope:a};d.listeners.push(e),a.$on("$destroy",function(){e.dereg=null,e.handler=null,e.eventId=null,e.scope=null})}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));var e="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var f=b.width.replace(/%/g,""),g=parseInt(f,10);if(isNaN(g))throw new Error(e);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(e);c.width=b.width}d.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())},c.minWidth=b.minWidth?b.minWidth:30,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.footerCellClass=b.footerCellClass,c.cellClass=b.cellClass,c.headerCellClass=b.headerCellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var h=[];b.filter?h.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&h.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",h)},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.getAggregationText("aggregation.count",a.grid.getVisibleRowCount()):a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),a.getAggregationText("aggregation.sum",c)):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,a.getAggregationText("aggregation.avg",c)):a.aggregationType===b.aggregationTypes.min?a.getAggregationText("aggregation.min",Math.min.apply(null,e)):a.aggregationType===b.aggregationTypes.max?a.getAggregationText("aggregation.max",Math.max.apply(null,e)):" "},d.prototype.getAggregationText=function(a,b){var d=this;return d.colDef.aggregationHideLabel?b:c.getSafeText(a)+b},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.headerRowHeight="undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30,c.rowHeight=c.rowHeight||30,c.maxVisibleRowCount=c.maxVisibleRowCount||200,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showFooter=c.showFooter===!0,c.footerRowHeight="undefined"!=typeof c.footerRowHeight?c.footerRowHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil",function(a){function b(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return b.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},b.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},b.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},b.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},b.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},b.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},b.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},b.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;
    +"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},b.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},b.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},b.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},b.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},b.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},b.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},b.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},b.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},b.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},b.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},b.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},b.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},b.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},b.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},b.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},b.prototype.updateColumnWidths=function(){var b=this,c=[],d=[],e=0,f=b.getViewportWidth();"undefined"!=typeof b.grid.verticalScrollbarWidth&&void 0!==b.grid.verticalScrollbarWidth&&b.grid.verticalScrollbarWidth>0&&(f+=b.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=b.visibleColumnCache;k.forEach(function(b){if(b.visible){var f=!1;angular.isNumber(b.width)||(f=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(e=parseInt(e+b.width.length,10),c.push(b)):f?d.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),b.grid.verticalScrollbarWidth&&(i+=b.grid.verticalScrollbarWidth),b.canvasWidth=parseInt(i,10),this.columnStyles=j},b}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.headerCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.cellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.cellTemplatePromise=a.getTemplate(d.cellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["gridUtil","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(a){p.LOG_DEBUG_MESSAGES&&b.debug(a)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(c,d,e,f){function g(){j=b.elementHeight(d),i=b.elementWidth(d)}function h(){a.cancel(k),k=a(function(){var a=b.elementHeight(d),c=b.elementWidth(d);a!==j||c!==i?(f.grid.gridHeight=a,f.grid.gridWidth=c,f.grid.refresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),c.$on("$destroy",function(){a.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};if(null!==d){var g=a.renderContainers.body.visibleRowCache.indexOf(d),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;f.y={percentage:i}}null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(a,b){return{replace:!0,priority:-99999,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(){},post:function(a,c,d,e){var f=e.grid;b.decorateRenderContainers(f)}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","gridUtil","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0),b.grid.queueRefresh()}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=b.colContainer.cellNav.getNextRowCol(d,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),c.stopPropagation(),c.preventDefault(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.MODEL_COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var c=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),c.removeClass("ui-grid-cell-contents-hidden"),a&&t&&c.focus(),t=!1,s=!1,h(),d.grid.api.core.notifyDataChange(d.grid,b.dataChange.EDIT)}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.refresh()}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",width:40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){var e=c(d)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}
    +}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c,e){var f=this.getColumnHeaders(a,c),g=this.getData(a,b,c),h=this.formatAsCsv(f,g,a.options.exporterCsvColumnSeparator);!e&&a.options.exporterCsvLinkElement&&(e=a.options.exporterCsvLinkElement),e?this.renderCsvLink(a,h,e):d.logError("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,d){var e=[];return angular.forEach(a.columns,function(f){!f.visible&&d!==b.ALL||f.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(f.name)||e.push({name:f.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(f.displayName):f.displayName,width:f.drawnWidth?f.drawnWidth:f.width,align:"number"===f.colDef.type?"right":"left"})}),e},getData:function(a,e,f){var g,h=[];switch(e){case b.ALL:g=a.rows;break;case b.VISIBLE:g=a.getVisibleRows();break;case b.SELECTED:a.api.selection?g=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return b.ALL?(angular.forEach(g,function(d){var e=[];angular.forEach(a.columns,function(g){!g.visible&&f!==b.ALL||g.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(g.name)||e.push(a.options.exporterFieldCallback(a,d,g,a.getCellValue(d,g)))}),h.push(e)}),h):void 0},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return a.displayName}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,c,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){var f=angular.element(d);f.children("a").html(f.children("a").html().replace(b.LINK_LABEL,a.options.exporterLinkLabel)),f.children("a").attr("href",f.children("a").attr("href").replace(b.CSV_CONTENT,encodeURIComponent(c)));var h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&h.content.unshift(a.options.exporterPdfHeader),a.options.exporterPdfFooter&&h.content.push(a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a,b){i.importFile(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(a,c),a.deregisterDataChangeCallback(d)},[b.dataChange.ROW]),e=function(){a.deregisterDataChangeCallback(d)};a.importer.$scope.$on("$destroy",e)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){if(1===a.srcElement.files.length){var c=a.srcElement.files[0];b.importThisFile(i,c),a.srcElement.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout",function(a,b){var c={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){b.redrawColumnAtPosition(a,c,d)}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var e=a.columns,f=function(a){for(var b=a,c=0;b>=c;c++)(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};c=f(c),d=f(d);var g=e[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)e[h]=e[h-1];else if(d>c)for(var i=c;d>i;i++)e[i]=e[i+1];e[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return c}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(b,e,f,g){if(b.col.colDef.enableColumnMoving){var h=function(h){if("ui-grid-icon-angle-down"!==h.target.className&&"I"!==h.target.tagName){var i=e.clone();e.append(i),i.addClass("movingColumn");var j={},k=b.grid.element[0].getBoundingClientRect().left,l=e[0].getBoundingClientRect().left;j.left=l-k+"px";var m,n=b.grid.element[0].getBoundingClientRect().right,o=e[0].getBoundingClientRect().right;o>n&&(m=b.col.drawnWidth+(n-o),j.width=m+"px"),i.css(j);var p=h.pageX,q=0,r=k+b.grid.getViewportWidth()-b.grid.verticalScrollbarWidth,s=function(a){g.fireEvent("hide-menu");var c=i[0].getBoundingClientRect().left-1,d=i[0].getBoundingClientRect().right,e=a.pageX-p,f=c-k+e;f=r>f?f:r,(c>=k||e>0)&&(r>=d||0>e)?i.css({visibility:"visible",left:f+"px"}):(e*=5,g.fireScrollingEvent({x:{pixels:2.5*e}})),q+=e,p=a.pageX,m<b.col.drawnWidth&&(m+=Math.abs(e),i.css({width:m+"px"}))};b.$on("$destroy",function(){d.off("mousemove",s),d.off("mouseup",t)}),d.on("mousemove",s);var t=function(e){var h,j=a.defer();f.$observe("renderIndex",function(a){h=b.$eval(a),j.resolve()}),j.promise.then(function(){i&&i.remove();for(var a=b.grid.renderContainers.body.renderedColumns,f=0,j=b.grid.columns,k=0;k<j.length&&j[k].colDef.name!==a[0].colDef.name;k++)f++;if(0>q){for(var l=0,m=h-1;m>=0;m--)if(l+=a[m].drawnWidth,l>Math.abs(q)){c.redrawColumnAtPosition(b.grid,f+h,f+m+1);break}l<Math.abs(q)&&c.redrawColumnAtPosition(b.grid,f+h,f+0)}else if(q>0){for(var n=0,o=h+1;o<a.length;o++)if(n+=a[o].drawnWidth,n>q){c.redrawColumnAtPosition(b.grid,f+h,f+o-1);break}q>n&&c.redrawColumnAtPosition(b.grid,f+h,f+a.length-1)}else if(0===q){var p=!1;e.shiftKey&&(p=!0),g.grid.sortColumn(b.col,p).then(function(){g.columnMenuScope&&g.columnMenuScope.hideMenu(),g.grid.refresh()})}d.off("mousemove",s),d.off("mouseup",t)})};d.on("mouseup",t)}};e.on("mousedown",h)}}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ui.grid"]);a.service("uiGridPaginationService",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options),b.pagination={page:1,totalPages:1};var c={methods:{pagination:{getPage:function(){return b.pagination.page},getTotalPages:function(){return b.pagination.totalPages},nextPage:function(){b.pagination.page++,b.refresh()},previousPage:function(){b.pagination.page=Math.max(1,b.pagination.page-1),b.refresh()},seek:function(a){if(!angular.isNumber(a)||1>a)throw"Invalid page number: "+a;b.pagination.page=a,b.refresh()}}}};b.api.registerMethodsFromObject(c.methods),b.registerRowsProcessor(function(a){if(!b.options.enablePagination)return a;b.pagination.totalPages=Math.max(1,Math.ceil(a.length/b.options.rowsPerPage));var c=(b.pagination.page-1)*b.options.rowsPerPage;return c>=a.length&&(b.pagination.page=b.pagination.totalPages,c=(b.pagination.page-1)*b.options.rowsPerPage),a.slice(c,c+b.options.rowsPerPage)})},defaultGridOptions:function(a){a.enablePagination=a.enablePagination!==!1,a.rowsPerPage=angular.isNumber(a.rowsPerPage)?a.rowsPerPage:10}};return a}),a.directive("uiGridPagination",["uiGridPaginationService",function(a){return{priority:-400,scope:!1,require:"^uiGrid",link:{pre:function(b,c,d,e){a.initializeGrid(e.grid)}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"title","Pin Left")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"title","Pin Right")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"title","Unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","columnBounds","uiGridResizeColumnsService",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(g,h,i,j){function k(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function l(){j.grid.buildColumns().then(function(){j.grid.refreshCanvas(!0)})}function m(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),p=a.clientX-q,0>p?p=0:p>j.grid.gridWidth&&(p=j.grid.gridWidth);var b,e=g.col,h=e.getRenderContainer();if("left"===g.position?(e=h.renderedColumns[g.renderIndex-1],b=g.col):"right"===g.position&&(b=h.renderedColumns[g.renderIndex+1]),e.colDef.enableColumnResizing!==!1){j.grid.element.hasClass("column-resizing")||j.grid.element.addClass("column-resizing");var i=p-o,k=parseInt(e.drawnWidth+i*r,10);e.colDef.minWidth&&k<e.colDef.minWidth?p+=(e.colDef.minWidth-k)*r:!e.colDef.minWidth&&d.minWidth&&k<d.minWidth?p+=e.colDef.minWidth-k:e.colDef.maxWidth&&k>e.colDef.maxWidth&&(p+=(e.colDef.maxWidth-k)*r),f.css({left:p+"px"}),j.fireEvent(c.events.ITEM_DRAGGING)}}function n(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),j.grid.element.removeClass("column-resizing"),f.remove(),p=b.clientX-q;var c=p-o;if(0===c)return a.off("mouseup",n),void a.off("mousemove",m);var h,i=g.col,s=i.getRenderContainer();if("left"===g.position?(i=s.renderedColumns[g.renderIndex-1],h=g.col):"right"===g.position&&(h=s.renderedColumns[g.renderIndex+1]),i.colDef.enableColumnResizing!==!1){var t=parseInt(i.drawnWidth+c*r,10);i.colDef.minWidth&&t<i.colDef.minWidth?t=i.colDef.minWidth:!i.colDef.minWidth&&d.minWidth&&t<d.minWidth&&(t=d.minWidth),i.colDef.maxWidth&&t>i.colDef.maxWidth&&(t=i.colDef.maxWidth),i.width=t,k(i),l(c),e.fireColumnSizeChanged(j.grid,i.colDef,c),a.off("mouseup",n),a.off("mousemove",m)}}var o=0,p=0,q=0,r=1;j.grid.isRTL()&&(g.position="left",r=-1),"left"===g.position?h.addClass("left"):"right"===g.position&&h.addClass("right"),h.on("mousedown",function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),q=j.grid.element[0].getBoundingClientRect().left,o=b.clientX-q,j.grid.element.append(f),f.css({left:o}),a.on("mouseup",n),a.on("mousemove",m)}),h.on("dblclick",function(a){a.stopPropagation();var f,i,m=g.col,n=m.getRenderContainer();"left"===g.position?(m=n.renderedColumns[g.renderIndex-1],f=g.col,i=1):"right"===g.position&&(f=n.renderedColumns[g.renderIndex+1],f=n.renderedColumns[g.renderIndex+1],i=-1);var o=0,p=0,q=b.closestElm(h,".ui-grid-render-container"),r=q.querySelectorAll("."+c.COL_CLASS_PREFIX+m.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(r,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var f=b.elementWidth(c);e+=f}e>o&&(o=e,p=o-e)})}),m.colDef.minWidth&&o<m.colDef.minWidth?o=m.colDef.minWidth:!m.colDef.minWidth&&d.minWidth&&o<d.minWidth&&(o=d.minWidth),m.colDef.maxWidth&&o>m.colDef.maxWidth&&(o=m.colDef.maxWidth),m.width=parseInt(o,10),k(m),l(p),e.fireColumnSizeChanged(j.grid,m.colDef,p)}),h.on("$destroy",function(){h.off("mousedown"),h.off("dblclick"),a.off("mousemove",m),a.off("mouseup",n)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){f.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEdit.dirtyRows?a.rowEdit.dirtyRows:[]},getErrorRows:function(a){return a.rowEdit.errorRows?a.rowEdit.errorRows:[]},flushDirtyRows:function(a){return f.flushDirtyRows(a)},setRowsDirty:function(a,b){f.setRowsDirty(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)
    +})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c){var d=b.renderContainers.body.visibleRowCache[c];null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},selectAllVisibleRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.visible?d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c)):d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(a){return a.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;if(d||f){if(!d&&f){var g=a.getSelectedRows(b);g.length>1&&(f=!1,a.clearSelectedRows(b))}}else a.clearSelectedRows(b);f&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=[],j=f;g>=j;j++){var k=b.renderContainers.body.visibleRowCache[j];k&&(k.isSelected||(k.isSelected=!0,b.selection.lastSelectedRow=k,a.decideRaiseSelectionEvent(b,k,i)))}a.decideRaiseSelectionBatchEvent(b,i)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){var c=[];a.getSelectedRows(b).forEach(function(d){d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)},decideRaiseSelectionEvent:function(a,b,c){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b)},decideRaiseSelectionBatchEvent:function(a,b){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:40,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1};f.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(){c.selection.selectAll?(b.clearSelectedRows(c),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){var c=0,d=300,e=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()};b.on("touchstart",function(){c=(new Date).getTime()}),b.on("touchend",function(a){var b=(new Date).getTime(),f=b-c;d>f&&e(a)}),b.on("click",function(a){e(a)})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableVerticalScrollbar" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableHorizontalScrollbar" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)">&nbsp;</div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.15/ui-grid.svg b/release/3.0.0-rc.15/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-rc.15/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.15/ui-grid.ttf b/release/3.0.0-rc.15/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-rc.15/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.15/ui-grid.woff b/release/3.0.0-rc.15/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-rc.15/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.16/ui-grid.css b/release/3.0.0-rc.16/ui-grid.css
    new file mode 100644
    index 000000000..f020a9ee6
    --- /dev/null
    +++ b/release/3.0.0-rc.16/ui-grid.css
    @@ -0,0 +1,1239 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: fixed;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.16/ui-grid.eot b/release/3.0.0-rc.16/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-rc.16/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.16/ui-grid.js b/release/3.0.0-rc.16/ui-grid.js
    new file mode 100644
    index 000000000..89881e7f3
    --- /dev/null
    +++ b/release/3.0.0-rc.16/ui-grid.js
    @@ -0,0 +1,17512 @@
    +/*! ui-grid - v3.0.0-rc.16 - 2014-11-14
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +    
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1,
    +      WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          var deregisterFunction = function() {
    +           $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            $elm.addClass($scope.col.getColClass(false));
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.headerCellClass) {
    +              updateClass();
    +            }
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var watchUid = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            var deregisterFunction = function() {
    +              $scope.grid.deregisterDataChangeCallback( watchUid ); 
    +            };
    +
    +            $scope.$on( '$destroy', deregisterFunction );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown touchstart', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false) {
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                }
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup touchend', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +
    +            $scope.$on('$destroy', function () {
    +              $contentsElm.off('mousedown touchstart');
    +            });
    +
    +
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click touchend', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh()
    +                      .then(function () {
    +                        if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                           uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                        }
    +                        // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                      });
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', function( gridUtil, i18nService ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, applyHideMenu ));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +
    +    // scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +    if (!angular.isNumber(scrollBarWidth)) {
    +      scrollBarWidth = 0;
    +    }
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = grid.verticalScrollbarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? 0 : scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = grid.horizontalScrollbarHeight;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // gridUtil.logDebug('headerHeight in scrollbar', headerHeight);
    +
    +          var ondemand  = grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-y:auto;" : "";
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px;' +ondemand +'}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          var bottom = gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ondemand = grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.WHEN_NEEDED ? "overflow-x:auto" : "";
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px;' +ondemand + ' }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // gridUtil.logDebug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil',
    +    function(gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +            
    +            if ( !$scope.grid.isScrollingVertically && !$scope.grid.isScrollingHorizontally ){
    +              // viewport scroll that didn't come from fireScrollEvent, so fire a scroll to keep 
    +              // the header in sync
    +              var args = {};
    +              if ( horizScrollPercentage > -1 ){
    +                args.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                args.y = { percentage: vertScrollPercentage };
    +              }
    +              uiGridCtrl.fireScrollingEvent(args); 
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      self.fireScrollingEvent = gridUtil.throttle(function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.hideHeader ? 0 : grid.options.headerRowHeight;
    +                var footerHeight = grid.options.showFooter ? grid.options.footerRowHeight : 0;
    +                var scrollbarHeight = grid.options.enableScrollbars ? gridUtil.getScrollbarWidth() : 0;
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = GridOptions.initialize( options );
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +  self.dataChangeCallbacks = {};
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Trigger a grid resize, normally this would be picked
    +   * up by a watch on window size, but in some circumstances it is necessary
    +   * to call this manually
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name addRowHeaderColumn
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description adds a row header column to the grid
    +   * @param {object} column def
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortHandleNulls
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description A null handling method that can be used when building custom sort
    +   * functions
    +   * @example
    +   * <pre>
    +   *   mySortFn = function(a, b) {
    +   *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +   *   if ( nulls !== null ){
    +   *     return nulls;
    +   *   } else {
    +   *     // your code for sorting here
    +   *   };
    +   * </pre>
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +
    +  /**
    +   * @ngdoc method
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Notify the grid that a data or config change has occurred,
    +   * where that change isn't something the grid was otherwise noticing.  This 
    +   * might be particularly relevant where you've changed values within the data
    +   * and you'd like cell classes to be re-evaluated, or changed config within 
    +   * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +   * @param {Grid} grid the grid
    +   * @param {string} type one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +   * us which refreshes to fire.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +  
    +  self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN ).  Optional and defaults to
    +   * ALL 
    +   * @returns {string} uid of the callback, can be used to deregister it again
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types };
    +    return uid;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name deregisterDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description Delete the callback identified by the id.
    +   * @param {string} uid the uid of the function that is to be deregistered
    +   */
    +  Grid.prototype.deregisterDataChangeCallback = function deregisterDataChangeCallback(uid) {
    +    delete this.dataChangeCallbacks[uid];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, and COLUMN callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        callback.callback( this );
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {Grid} grid the grid
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(grid, type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ){
    +      grid.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag 
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.refresh();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.handleWindowResize();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +    
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +        if (wasEmpty) {
    +           self.assignTypes();
    +        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow 
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', GridRow.prototype.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed, 
    +           * and that is the one that would have been useful.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.  A number of settings are supported:
    +    * 
    +    * - title: controls the title that is displayed in the menu
    +    * - icon: the icon shown alongside that title
    +    * - action: the method to call when the menu is clicked
    +    * - shown: a function to evaluate to determine whether or not to show the item
    +    * - active: a function to evaluate to determine whether or not the item is currently selected
    +    * - context: context to pass to the action function??
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       shown: function() { return true; },
    +    *       active: function() { return true; },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        return self.getAggregationText('aggregation.count', self.grid.getVisibleRowCount());
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        return self.getAggregationText('aggregation.sum', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        return self.getAggregationText('aggregation.avg', result);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return self.getAggregationText('aggregation.min', Math.min.apply(null, cellValues));
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return self.getAggregationText('aggregation.max', Math.max.apply(null, cellValues));
    +      }
    +      else {
    +        return '\u00A0';
    +      }
    +    };
    +    
    +   /** 
    +    * @ngdoc property
    +    * @name aggregationHideLabel
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description defaults to false, if set to true hides the label text
    +    * in the aggregation footer, so only the value is displayed.
    +    *
    +    */
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationText
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description converts the aggregation value into a text string, including 
    +     * i18n and deciding whether or not to display based on colDef.aggregationHideLabel
    +     * 
    +     * @param {string} label the i18n lookup value to use for the column label
    +     * @param {number} value the calculated aggregate value for this column
    +     * 
    +     */
    +    GridColumn.prototype.getAggregationText = function ( label, value ) {
    +      var self = this;
    +      if ( self.colDef.aggregationHideLabel ){
    +        return value;
    +      } else {
    +        return i18nService.getSafeText(label) + value;
    +      }
    +    };
    +
    +    GridColumn.prototype.getCellTemplate = function () {
    +      var self = this;
    +
    +      return self.cellTemplatePromise;
    +    };
    +
    +    GridColumn.prototype.getCompiledElementFn = function () {
    +      var self = this;
    +      
    +      return self.compiledElementFnDefer.promise;
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +  
    +      baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +      baseOptions.maxVisibleRowCount = baseOptions.maxVisibleRowCount || 200;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      baseOptions.showFooter = baseOptions.showFooter === true;
    +      baseOptions.footerRowHeight = typeof(baseOptions.footerRowHeight) !== "undefined" ? baseOptions.footerRowHeight : 30;
    +  
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      // Turn virtualization on when number of data elements goes over this number
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      // Extra rows to to render outside of the viewport
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      // Extra columns to to render outside of the viewport
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      // Default time to throttle scroll events to.
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER, uiGridConstants.scrollbars.WHEN_NEEDED.
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      // Columns can't be smaller than 10 pixels
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', function(gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.headerCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.cellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.cellTemplate = colDef.cellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.cellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toLowerCase(),
    +          strB = b.toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.refresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(this.rows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === this.rows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(this.rows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === this.rows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(this.rows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = this.rows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(this.rows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, $scope, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so 
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         * 
    +         * To get to row 9 (i.e. the last row) in the same list, we want to 
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll, 
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            args.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            args.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, $scope, gridRow, gridCol) {
    +          var args = {};
    +
    +          // Alias the visible row and column caches 
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          if (grid.horizontalScrollbarHeight) {
    +            bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          }
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + grid.gridWidth;
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          if (grid.verticalScrollbarWidth) {
    +            rightBound = rightBound - grid.verticalScrollbarWidth;
    +          }
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +            
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              args.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              args.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +            
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              args.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              args.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (args.y || args.x) {
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +          
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +          
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;  
    +            }
    +          });
    +          
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +           
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol) {
    +                var row = rowCol.row,
    +                    col = rowCol.col;
    +
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, $scope, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            },
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                  renderContainerCtrl = controllers[1];
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                $timeout(function () {
    +                  $timeout(function () {
    +                    // Get the last row+col combo
    +                    var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +
    +                    // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                    //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                    //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                    if ($document.activeElement === $document.body) {
    +                      $elm[0].focus();
    +                    }
    +
    +                    // Re-broadcast a cellNav event so we re-focus the right cell
    +                    uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                  });
    +                });
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +          
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col));
    +
    +            evt.stopPropagation();
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              setFocused();
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                $compile(cellElement)($scope.$new());
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( $scope.grid, uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    console.log('stop edit!');
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight; 
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + displayName; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCOl and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc object
    +         * @name exporterCsvLinkElement
    +         * @propertyOf  ui.grid.exporter.api:GridOptions
    +         * @description The element that the csv link should be placed into.
    +         * Mandatory if using the native UI.
    +         */
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          if ( !$elm && grid.options.exporterCsvLinkElement ){
    +            $elm = grid.options.exporterCsvLinkElement;
    +          }
    +          
    +          if ( $elm ){
    +            this.renderCsvLink(grid, csvContent, $elm);
    +          } else {
    +            gridUtil.logError( 'Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?')
    +;          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? grid.options.exporterHeaderFilter(gridCol.displayName) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.name !== uiGridSelectionConstants.selectionRowHeaderColName &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  extractedRow.push( grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) );
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +
    +              var template = angular.element(contents);
    +
    +              template.children("a").html(
    +                  template.children("a").html().replace(
    +                      uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel));
    +
    +              template.children("a").attr("href", 
    +                  template.children("a").attr("href").replace(
    +                      uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent)));
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.content.unshift( grid.options.exporterPdfHeader );
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.content.push( grid.options.exporterPdfFooter );
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {Grid} grid the grid we're importing into
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( grid, fileObject ) {
    +                  service.importFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and ift he rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var callbackId = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( grid, newObjects );
    +              grid.deregisterDataChangeCallback( callbackId );
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            var deregisterClosure = function() {
    +              grid.deregisterDataChangeCallback( callbackId );
    +            };
    +  
    +            grid.importer.$scope.$on( '$destroy', deregisterClosure );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            if (event.srcElement.files.length === 1) {
    +              var fileObject = event.srcElement.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              event.srcElement.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +		grid.options.loadTimout = true;
    +        grid.api.infiniteScroll.raise.needLoadMoreData();        
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.$on(uiGridConstants.events.GRID_SCROLL, function (evt, args) {
    +                if (args.y) {
    +                  var percentage = 100 - (args.y.percentage * 100);
    +                  uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', function ($q, $timeout) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.on.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                self.redrawColumnAtPosition(grid, originalPosition, finalPosition);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +        var columns = grid.columns;
    +
    +        //Function to find column position for a render index, ths is needed to take care of
    +        // invisible columns and row headers
    +        var findPositionForRenderIndex = function (index) {
    +          var position = index;
    +          for (var i = 0; i <= position; i++) {
    +            if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +              position++;
    +            }
    +          }
    +          return position;
    +        };
    +
    +        originalPosition = findPositionForRenderIndex(originalPosition);
    +        newPosition = findPositionForRenderIndex(newPosition);
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and coned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                var mouseDownHandler = function (evt) {
    +                  if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I') {
    +
    +                    //Cloning header cell and appending to current header cell.
    +                    var movingElm = $elm.clone();
    +                    $elm.append(movingElm);
    +
    +                    //Left of cloned element should be aligned to original header cell.
    +                    movingElm.addClass('movingColumn');
    +                    var movingElementStyles = {};
    +                    var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                    var elmLeft = $elm[0].getBoundingClientRect().left;
    +                    movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                    var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                    var elmRight = $elm[0].getBoundingClientRect().right;
    +                    var reducedWidth;
    +                    if (elmRight > gridRight) {
    +                      reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                      movingElementStyles.width = reducedWidth + 'px';
    +                    }
    +                    //movingElementStyles.visibility = 'hidden';
    +                    movingElm.css(movingElementStyles);
    +
    +                    //Setting some variables required for calculations.
    +                    var previousMouseX = evt.pageX;
    +                    var totalMouseMovement = 0;
    +                    var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth() - $scope.grid.verticalScrollbarWidth;
    +
    +                    //Clone element should move horizontally with mouse.
    +                    var mouseMoveHandler = function (evt) {
    +                      uiGridCtrl.fireEvent('hide-menu');
    +                      var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                      var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                      var changeValue = evt.pageX - previousMouseX;
    +                      var newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                      newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +                      if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                        movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                      }
    +                      else {
    +                        changeValue *= 5;
    +                        uiGridCtrl.fireScrollingEvent({ x: { pixels: changeValue * 2.5} });
    +                      }
    +                      totalMouseMovement += changeValue;
    +                      previousMouseX = evt.pageX;
    +                      if (reducedWidth < $scope.col.drawnWidth) {
    +                        reducedWidth += Math.abs(changeValue);
    +                        movingElm.css({'width': reducedWidth + 'px'});
    +                      }
    +                    };
    +
    +                    // On scope destroy, remove the mouse event handlers from the document body
    +                    $scope.$on('$destroy', function () {
    +                      $document.off('mousemove', mouseMoveHandler);
    +                      $document.off('mouseup', mouseUpHandler);
    +                    });
    +
    +                    $document.on('mousemove', mouseMoveHandler);
    +                    var mouseUpHandler = function (evt) {
    +                      var renderIndexDefer = $q.defer();
    +
    +                      var renderIndex;
    +                      $attrs.$observe('renderIndex', function (n, o) {
    +                        renderIndex = $scope.$eval(n);
    +                        renderIndexDefer.resolve();
    +                      });
    +
    +                      renderIndexDefer.promise.then(function () {
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var renderedColumns = $scope.grid.renderContainers['body'].renderedColumns;
    +
    +                        //This method will calculate the number of columns hidden in lift due to scroll
    +                        //renderContainer.prevColumnScrollIndex could also have been used but this is more accurate
    +                        var scrolledColumnCount = 0;
    +                        var columns = $scope.grid.columns;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== renderedColumns[0].colDef.name) {
    +                            scrolledColumnCount++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = renderIndex - 1; il >= 0; il--) {
    +                            totalColumnsLeftWidth += renderedColumns[il].drawnWidth;
    +                            if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + il + 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + 0);
    +                          }
    +                        }
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = renderIndex + 1; ir < renderedColumns.length; ir++) {
    +                            totalColumnsRightWidth += renderedColumns[ir].drawnWidth;
    +                            if (totalColumnsRightWidth > totalMouseMovement) {
    +                              uiGridMoveColumnService.redrawColumnAtPosition
    +                              ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + ir - 1);
    +                              break;
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, scrolledColumnCount + renderIndex, scrolledColumnCount + renderedColumns.length - 1);
    +                          }
    +                        }
    +                        else if (totalMouseMovement === 0) {
    +                          //sort the current column
    +                          var add = false;
    +                          if (evt.shiftKey) {
    +                            add = true;
    +                          }
    +
    +                          // Sort this column then rebuild the grid's rows
    +                          uiGridCtrl.grid.sortColumn($scope.col, add)
    +                            .then(function () {
    +                              if (uiGridCtrl.columnMenuScope) {
    +                                uiGridCtrl.columnMenuScope.hideMenu();
    +                              }
    +                              uiGridCtrl.grid.refresh();
    +                            });
    +                        }
    +
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      });
    +                    };
    +
    +                    $document.on('mouseup', mouseUpHandler);
    +                  }
    +                };
    +
    +                $elm.on('mousedown', mouseDownHandler);
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', function () {
    +    var service = {
    +
    +      /**
    +       * @ngdoc method
    +       * @name initializeGrid
    +       * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +       * @description Attaches the service to a certain grid
    +       * @param {Grid} grid The grid we want to work with
    +       */
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +        grid.pagination = {page: 1, totalPages: 1};
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.pagination.api:PublicAPI
    +         *
    +         * @description Public API for the pagination feature
    +         */
    +        var publicApi = {
    +          methods: {
    +            pagination: {
    +              /**
    +               * @ngdoc method
    +               * @name getPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the number of the current page
    +               */
    +              getPage: function () {
    +                return grid.pagination.page;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name getTotalPages
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Returns the total number of pages
    +               */
    +              getTotalPages: function () {
    +                return grid.pagination.totalPages;
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name nextPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the next page, if possible
    +               */
    +              nextPage: function () {
    +                grid.pagination.page++;
    +                grid.refresh();
    +              },
    +              /**
    +               * @ngdoc method
    +               * @name previousPage
    +               * @methodOf ui.grid.pagination.api:PublicAPI
    +               * @description Moves to the previous page, if we're not on the first page
    +               */
    +              previousPage: function () {
    +                grid.pagination.page = Math.max(1, grid.pagination.page - 1);
    +                grid.refresh();
    +              },
    +              seek: function (page) {
    +                if (!angular.isNumber(page) || page < 1) {
    +                  throw 'Invalid page number: ' + page;
    +                }
    +
    +                grid.pagination.page = page;
    +                grid.refresh();
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +        grid.registerRowsProcessor(function (renderableRows) {
    +          if (!grid.options.enablePagination) {
    +            return renderableRows;
    +          }
    +          grid.pagination.totalPages = Math.max(
    +            1,
    +            Math.ceil(renderableRows.length / grid.options.rowsPerPage)
    +          );
    +
    +          var firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          if (firstRow >= renderableRows.length) {
    +            grid.pagination.page = grid.pagination.totalPages;
    +            firstRow = (grid.pagination.page - 1) * grid.options.rowsPerPage;
    +          }
    +
    +          return renderableRows.slice(
    +            firstRow,
    +            firstRow + grid.options.rowsPerPage
    +          );
    +        });
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pagination.api:GridOptions
    +         *
    +         *  @description GridOptions for the pagination feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePagination
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description Enable pagination for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name rowsPerPage
    +         *  @propertyOf  ui.grid.pagination.api:GridOptions
    +         *  @description The number of rows that should be displayed per page
    +         *  <br/>Defaults to 10
    +         */
    +        gridOptions.rowsPerPage = angular.isNumber(gridOptions.rowsPerPage) ? gridOptions.rowsPerPage : 10;
    +      }
    +    };
    +
    +    return service;
    +  });
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.pagination.directive:uiGridPagination
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description Adds pagination support to a grid.
    +   */
    +  module.directive('uiGridPagination', ['uiGridPaginationService', function (uiGridPaginationService) {
    +    return {
    +      priority: -400,
    +      scope: false,
    +      require: '^uiGrid',
    +      link: {
    +        pre: function (scope, element, attrs, uiGridCtrl) {
    +          uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      }
    +    };
    +  }]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', function (gridUtil, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth) * rtlMultiplier;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth) * rtlMultiplier;
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.width = parseInt(maxWidth, 10);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {object} grid the grid for which rows should be set dirty
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function (grid, dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.api:PublicApi
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing 
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected ){
    +                      row.isSelected = true;
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected){
    +                        row.isSelected = true;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.isSelected = false;
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +                
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead  
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid);
    +            }
    +          }
    +          
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else {
    +            row.isSelected = !selected;
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected ){
    +                rowToSelect.isSelected = true;
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.isSelected = false;
    +              service.decideRaiseSelectionEvent( grid, row, changedRows );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows );
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and 
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows);
    +          }
    +        }        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect, self.options.noUnselect); 
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +          
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows();
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              var touchStartTime = 0;
    +              var touchTimeout = 300;
    +              var selectCells = function(evt){
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                else if (evt.ctrlKey || evt.metaKey) {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +                }
    +                $scope.$apply();
    +              };
    +
    +              $elm.on('touchstart', function(event) {
    +                touchStartTime = (new Date()).getTime();
    +              });
    +
    +              $elm.on('touchend', function (evt) {
    +                var touchEndTime = (new Date()).getTime();
    +                var touchTime = touchEndTime - touchStartTime;
    +
    +                if (touchTime < touchTimeout ) {
    +                  // short touch
    +                  selectCells(evt);
    +                }
    +              });
    +
    +              $elm.on('click', function (evt) {
    +                selectCells(evt);
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableVerticalScrollbar\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableHorizontalScrollbar\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.16/ui-grid.min.css b/release/3.0.0-rc.16/ui-grid.min.css
    new file mode 100644
    index 000000000..2f1b317f2
    --- /dev/null
    +++ b/release/3.0.0-rc.16/ui-grid.min.css
    @@ -0,0 +1,12 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu{z-index:2;position:fixed;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +
    +.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.16/ui-grid.min.js b/release/3.0.0-rc.16/ui-grid.min.js
    new file mode 100644
    index 000000000..3edaaba90
    --- /dev/null
    +++ b/release/3.0.0-rc.16/ui-grid.min.js
    @@ -0,0 +1,8 @@
    +/*! ui-grid - v3.0.0-rc.16 - 2014-11-14
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column"},scrollbars:{NEVER:0,ALWAYS:1,WHEN_NEEDED:2}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){b.addClass(a.col.getColClass(!1));var c,e=function(){var d=b;c&&(d.removeClass(c),c=null),c=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,d.addClass(c)};a.col.cellClass&&e();var f=a.grid.registerDataChangeCallback(e,[d.dataChange.COLUMN,d.dataChange.EDIT]),g=function(){a.grid.deregisterDataChangeCallback(f)};a.$on("$destroy",g)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,c,e,f){var g=this;d.initialize(b,f),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,e,f){b.col=a;var h=d.getColumnElementPosition(b,a,e);b.menuShown?(b.colElement=e,b.colElementPosition=h,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(g.shown=b.menuShown=!0,d.repositionMenu(b,a,h,c,e),b.colElement=e,b.colElementPosition=h,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,c,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,c){function e(e){b.getTemplate(e).then(function(b){var e=d(b),f=e(a);c.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,d,e){a.grid=e.grid,a.getExternalScopes=e.getExternalScopes,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",function(){a.grid.deregisterDataChangeCallback(h)})}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,a.getExternalScopes=h.getExternalScopes,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,e){function h(b){var c=!1;b.shiftKey&&(c=!0),i.grid.sortColumn(a.col,c).then(function(){i.columnMenuScope&&i.columnMenuScope.hideMenu(),i.grid.refresh()})}var i=e[0],j=e[1];a.grid=i.grid,a.getExternalScopes=i.getExternalScopes,a.renderContainer=i.grid.renderContainers[j.containerId],c.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var k,l=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),m=function(){var b=c;k&&(b.removeClass(k),k=null),k=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(k)};a.col.headerCellClass&&m();var n=a.grid.registerDataChangeCallback(m,[f.dataChange.COLUMN]),o=function(){a.grid.deregisterDataChangeCallback(n)};a.$on("$destroy",o),a.sortable=i.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=i.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var p,q=0;if(l.on("mousedown touchstart",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(q=(new Date).getTime(),p=b(function(){},g),p.then(function(){a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1&&i.columnMenuScope.showMenu(a.col,c,d)}))}),l.on("mouseup touchend",function(){b.cancel(p)}),a.$on("$destroy",function(){l.off("mousedown touchstart")}),a.toggleMenu=function(b){b.stopPropagation(),i.columnMenuScope.menuShown&&i.columnMenuScope.col===a.col?i.columnMenuScope.hideMenu():i.columnMenuScope.showMenu(a.col,c)},a.sortable&&(l.on("click touchend",function(a){a.stopPropagation(),b.cancel(p);var c=(new Date).getTime(),d=c-q;d>g||h(a)}),a.$on("$destroy",function(){b.cancel(p)})),a.filterable){var r=[];angular.forEach(a.col.filters,function(b,c){r.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(i.grid.api.core.raise.filterChanged(),i.grid.refresh().then(function(){i.prevScrollArgs&&i.prevScrollArgs.y&&i.prevScrollArgs.y.percentage&&i.fireScrollingEvent({y:{percentage:i.prevScrollArgs.y.percentage}})}))}))}),a.$on("$destroy",function(){angular.forEach(r,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,a.getExternalScopes=i.getExternalScopes,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.hideHeader?f:a.grid.options.headerTemplate?a.grid.options.headerTemplate:e,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth();"undefined"!=typeof g.grid.verticalScrollbarWidth&&void 0!==g.grid.verticalScrollbarWidth&&g.grid.verticalScrollbarWidth>0&&(a+=g.grid.verticalScrollbarWidth);var b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,j=a,k=!1,l=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(j/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",k=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,k=!0)});var m=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return m.indexOf(a.widthType)-m.indexOf(b.widthType)}).forEach(function(a){var b=l(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,j-=a.drawnWidth}),k&&j>0&&c>0&&a>c){var n=function(a){j>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,j--)},o=0;do o=j,b.forEach(n);while(j>0&&j!==o)}c=Math.max(c,a);var p="";return b.forEach(function(a){p+=a.getColClassDefinition()}),i.verticalScrollbarWidth&&(c+=i.verticalScrollbarWidth),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),p}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService",function(a,b){var c={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",c.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",c.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var d=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?d=d.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),d=d.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(d=d.concat(c.showHideColumns(b))),d},showHideColumns:function(a){var d=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(d.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};c.setMenuItemTitle(e,b,a.grid),d.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},c.setMenuItemTitle(e,b,a.grid),d.push(e)}}),d):d},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh()}};return c}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a){var d=this;d.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var f="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(f=d.originalEvent.type),angular.element(document).off("click touchstart",e),b(function(){angular.element(document).on(f,e)})},d.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",e)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var e=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",e),a.$on("$destroy",function(){angular.element(document).off("click touchstart",e)}),a.$on("$destroy",function(){angular.element(c).off("resize",e)}),a.$on("$destroy",a.$on(f.events.GRID_SCROLL,e)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,e))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){var e=d.getScrollbarWidth();angular.isNumber(e)||(e=0);var f=d.detectBrowser();return"ie"===f&&(e+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,f,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),d=o.headerHeight?o.headerHeight:p.headerHeight,e=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-y:auto;":"",f=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return f+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+d+"px;"+e+"}",s=b,f}function i(){var a=o.getCanvasWidth(),b=u;p.options.showFooter&&(b-=1);var d=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?"overflow-x:auto":"",e=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px;"+d+" }";return e+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,e}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,e=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(e-=l.grid.horizontalScrollbarHeight);var f=c/e;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=d.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,e){if(!e.target||e.target!==b&&!angular.element(e.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=e.target,"vertical"===a.type){if(e.y&&"undefined"!=typeof e.y.percentage&&void 0!==e.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,e.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&e.x&&"undefined"!=typeof e.x.percentage&&void 0!==e.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,e.x.percentage*h);b[0].scrollLeft=d.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",e+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=p.options.enableVerticalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,o.verticalScrollbarWidth=p.verticalScrollbarWidth,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",e+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=p.options.enableHorizontalScrollbar===c.scrollbars.WHEN_NEEDED?0:e,n.horizontalScrollbarHeight=p.horizontalScrollbarHeight,r=d.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=d.elementHeight(b):"horizontal"===a.type&&(s=d.elementWidth(b));var t=d.closestElm(b,".ui-grid"),u=d.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(c.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(e,f,g,h){function i(a,b){if(b.y&&e.bindScrollVertical){n.prevScrollArgs=b;var c=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(c+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof b.y.percentage&&void 0!==b.y.percentage)f=b.y.percentage;else{if("undefined"==typeof b.y.pixels||void 0===b.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=b.y.percentage=(g+b.y.pixels)/c}var h=Math.max(0,f*c);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(b.x&&e.bindScrollHorizontal){n.prevScrollArgs=b;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=d.normalizeScrollLeft(n.viewport);if("undefined"!=typeof b.x.percentage&&void 0!==b.x.percentage)i=b.x.percentage;else{if("undefined"==typeof b.x.pixels||void 0===b.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=b.x.percentage=(k+b.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=d.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=d.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=d.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-v),c=-(e-u),y=1>c?-1:1,z=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(w+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(x+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(c){function d(){a(function(){var a={target:c.target};if(0!==u){var b=(n.viewport[0].scrollTop+u)/(p.getCanvasHeight()-p.getViewportHeight());a.y={percentage:b,pixels:u}}if(0!==v){var e=(n.viewport[0].scrollLeft+v)/(q.getCanvasWidth()-q.getViewportWidth());a.x={percentage:e,pixels:v}}m.fireScrollingEvent(a),s-=1,u/=2,v/=2,s>0?d():m.scrollbars.forEach(function(a){a.removeClass("ui-grid-scrollbar-visible"),a.removeClass("ui-grid-scrolling")})},r)}c.originalEvent&&(c=c.originalEvent),c.preventDefault(),b.unbind("touchmove",j),b.unbind("touchend",k),b.unbind("touchcancel",k);var e=n.viewport[0].scrollTop,f=n.viewport[0].scrollTop,g=Math.abs(e-w),h=Math.abs(f-x),i=new Date-t,l=g/i,o=h/i,r=63,s=8,u=120*y*l,v=120*z*o;d()}function l(){var a="",b=q.getCanvasWidth(),c=q.getViewportWidth(),d=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-canvas { width: "+b+"px; height: "+d+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-viewport { width: "+c+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-canvas { width: "+b+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==r.explicitHeaderHeight&&null!==r.explicitHeaderHeight&&r.explicitHeaderHeight>0?a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.explicitHeaderHeight+"px; }":void 0!==r.innerHeaderHeight&&null!==r.innerHeaderHeight&&r.innerHeaderHeight>0&&(a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+e.containerId+" .ui-grid-header-cell { height: "+r.innerHeaderHeight+"px; }"),a}var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer,r=o.renderContainers[e.containerId];f.addClass("ui-grid-render-container-"+e.containerId);var s;(e.bindScrollHorizontal||e.bindScrollVertical)&&(s=e.$on(c.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=d.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var e=-120*b.deltaY,g=(n.viewport[0].scrollTop+e)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:e}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var t,u=0,v=0,w=0,x=0,y=1,z=1;d.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),t=new Date,u=a.targetTouches[0].screenY,v=a.targetTouches[0].screenX,w=n.viewport[0].scrollTop,x=n.viewport[0].scrollLeft,b.on("touchmove",j),b.on("touchend touchcancel",k)}),f.bind("$destroy",function(){s(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil",function(a){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(b,c,d,e){var f=e[0],g=e[1];
    +b.containerCtrl=g;{var h=g.rowContainer,i=g.colContainer;f.grid}b.grid=f.grid,b.rowContainer=g.rowContainer,b.colContainer=g.colContainer,g.viewport=c,c.on("scroll",function(){var d=c[0].scrollTop,e=a.normalizeScrollLeft(c),g=-1,j=-1;if(e!==i.prevScrollLeft){var k=(e-i.prevScrollLeft,i.getCanvasWidth()-i.getViewportWidth());g=e/k,i.adjustScrollHorizontal(e,g)}if(d!==h.prevScrollTop){var l=(d-h.prevScrollTop,h.getCanvasHeight()-h.getViewportHeight());j=d/l,j>1&&(j=1),0>j&&(j=0),h.adjustScrollVertical(d,j)}if(!b.grid.isScrollingVertically&&!b.grid.isScrollingHorizontally){var m={};g>-1&&(m.x={percentage:g}),j>-1&&(m.y={percentage:j}),f.fireScrollingEvent(m)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){a&&a!==b&&(n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function m(b){var d=[];b&&(n.grid.columns.length===(n.grid.rowHeaderColumns?n.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===n.grid.options.columnDefs.length&&b.length>0&&n.grid.buildColumnDefsFromData(b),(n.grid.options.columnDefs.length>0||b.length>0)&&d.push(n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates()})),e.all(d).then(function(){n.grid.modifyRows(b).then(function(){n.grid.redrawInPlace(),a.$evalAsync(function(){n.grid.refreshCanvas(!0),n.grid.callDataChangeCallbacks(f.dataChange.ROW)})})}))}var n=this;n.grid=h.createGrid(a.uiGrid),b.addClass("grid"+n.grid.id),n.grid.rtl="rtl"===d.getStyles(b[0]).direction,n.getExternalScopes=a.getExternalScopes,a.grid=n.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){n.grid.options.columnDefs=a,n.grid.buildColumns().then(function(){n.grid.preCompileCellTemplates(),n.grid.refreshCanvas(!0)})});var o;o=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,m):a.$parent.$watchCollection(function(){return a.uiGrid.data},m);var p=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},l);a.$on("$destroy",function(){o(),p()}),a.$watch(function(){return n.grid.styleComputations},function(){n.grid.refreshCanvas(!0)}),n.fireScrollingEvent=d.throttle(function(b){a.$broadcast(f.events.GRID_SCROLL,b)},n.grid.options.scrollThrottle,{trailing:!0}),n.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=n.grid),a.$broadcast(b,c)},n.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window",function(a,b,c,d){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,e,f){function g(){h.gridWidth=a.gridWidth=c.elementWidth(b),h.gridHeight=a.gridHeight=c.elementHeight(b),h.queueRefresh()}var h=f.grid;if(f.scrollbars=[],h.renderingComplete(),h.element=b,h.gridWidth=a.gridWidth=c.elementWidth(b),h.canvasWidth=f.grid.gridWidth,h.gridHeight=a.gridHeight=c.elementHeight(b),h.gridHeight<h.options.rowHeight){var i=h.options.minRowsToShow*h.options.rowHeight,j=h.options.hideHeader?0:h.options.headerRowHeight,k=h.options.showFooter?h.options.footerRowHeight:0,l=h.options.enableScrollbars?c.getScrollbarWidth():0,m=0;angular.forEach(h.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>m&&(m=1):a.hasOwnProperty("filters")&&m<a.filters.length&&(m=a.filters.length)});var n=m*j,o=j+i+k+l+n;b.css("height",o+"px"),h.gridHeight=a.gridHeight=c.elementHeight(b)}h.refreshCanvas();var p=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');b.prepend(p),f.innerCompile(p);var q=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');b.append(q),f.innerCompile(q),a.$watch(function(){return h.hasLeftContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),a.$watch(function(){return h.hasRightContainer()},function(a,b){a!==b&&h.refreshCanvas(!0)}),angular.element(d).on("resize",g),b.on("$destroy",function(){angular.element(d).off("resize",g)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0===h&&e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=d.debounce(function(){b.isScrollingVertically=!1},300),g=d.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN])};return o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b){var c=d.nextUid();return b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[c]={callback:a,types:b},c},o.prototype.deregisterDataChangeCallback=function(a){delete this.dataChangeCallbacks[a]},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&b.callback(this)},this)},o.prototype.notifyDataChange=function(a,b){var c=e.dataChange;b===c.ALL||b===c.COLUMN||b===c.EDIT||b===c.ROW?a.callDataChangeCallbacks(b):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+b)},o.prototype.columnRefreshCallback=function(a){a.refresh()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.handleWindowResize()})})},o.prototype.buildColumns=function(){var b,c=this,e=[],f=c.rowHeaderColumns.length;for(b=0;b<c.columns.length;b++)c.getColDef(c.columns[b].name)||(c.columns.splice(b,1),b--);return c.rowHeaderColumns.forEach(function(a){c.columns.unshift(a)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var h=c.getColumn(a.name);h?h.updateColumnDef(a):(h=new g(a,d.nextUid(),c),c.columns.splice(b+f,0,h)),c.columnBuilders.forEach(function(b){e.push(b.call(c,a,h,c.options))})}),a.all(e)},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;var j=0===g.rows.length;for(g.rows.length=0,c=0;c<b.length;c++){var k=b[c];e=i.get(k),f=e?e.row:g.processRowBuilders(new h(k,c,g)),g.rows.push(f),d.put(k,{i:c,entity:k,row:f})}j&&g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var l,m,n;if(g.options.enableRowHashing){l=[],n=[];var o={};for(m=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var p=!1;g.options.getRowIdentity(f)||(p=!0),e=d.get(f),e?e.row&&(o[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),p?n.push(f):l.push(f))}for(c=0;c<g.rows.length;c++){var q=g.rows[c],r=g.options.rowIdentity(q.entity);o[r]||m.push(q)}}var s=l||[],t=n||b;s=s.concat(g.newInN(g.rows,t,"entity")),g.addRows(s);var u=g.getDeletedRows(m||g.rows,b);for(c=0;c<u.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(u[c].entity),g.rows.splice(g.rows.indexOf(u[c]),1)}else g.createRowHashMap(),g.rows.length=0;var v=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),w=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([v,w])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){d.logDebug("grid refresh");var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),e=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,e]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)&&g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",e.prototype.getVisibleRows),this.registerEvent("core","rowsVisibleChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.scope,a.eventId,a.handler,c.grid)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$broadcast.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b){var c=f(a,g,b,d.grid),e={handler:b,dereg:c,eventId:g,scope:a};d.listeners.push(e),a.$on("$destroy",function(){e.dereg=null,e.handler=null,e.eventId=null,e.scope=null})}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b){var c=this;if(c.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+c.grid.options.columnDefs.indexOf(b));var e="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(c.width)||!angular.isNumber(c.width))if(a.isNullOrUndefined(b.width))c.width="*";else if(angular.isNumber(b.width))c.width=b.width;else if(a.endsWith(b.width,"%")){var f=b.width.replace(/%/g,""),g=parseInt(f,10);if(isNaN(g))throw new Error(e);c.width=b.width}else if(b.width.match(/^(\d+)$/))c.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(e);c.width=b.width}d.prototype.unsort=function(){this.sort={},c.grid.api.core.raise.sortChanged(c,c.grid.getColumnSorting())},c.minWidth=b.minWidth?b.minWidth:30,c.maxWidth=b.maxWidth?b.maxWidth:9e3,c.field=void 0===b.field?b.name:b.field,"string"!=typeof c.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+c.field),c.name=b.name,c.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,c.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,c.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,c.footerCellClass=b.footerCellClass,c.cellClass=b.cellClass,c.headerCellClass=b.headerCellClass,c.cellFilter=b.cellFilter?b.cellFilter:"",c.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",c.visible=a.isNullOrUndefined(b.visible)||b.visible,c.headerClass=b.headerClass,c.visible=!0,c.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,c.sortingAlgorithm=b.sortingAlgorithm,c.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,c.setPropertyOrDefault(b,"menuItems",[]),c.setPropertyOrDefault(b,"sort");var h=[];b.filter?h.push(b.filter):c.enableFiltering&&c.grid.options.enableFiltering&&h.push({}),c.setPropertyOrDefault(b,"filter"),c.setPropertyOrDefault(b,"filters",h)},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.getAggregationText("aggregation.count",a.grid.getVisibleRowCount()):a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),a.getAggregationText("aggregation.sum",c)):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,a.getAggregationText("aggregation.avg",c)):a.aggregationType===b.aggregationTypes.min?a.getAggregationText("aggregation.min",Math.min.apply(null,e)):a.aggregationType===b.aggregationTypes.max?a.getAggregationText("aggregation.max",Math.max.apply(null,e)):" "},d.prototype.getAggregationText=function(a,b){var d=this;return d.colDef.aggregationHideLabel?b:c.getSafeText(a)+b},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.headerRowHeight="undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30,c.rowHeight=c.rowHeight||30,c.maxVisibleRowCount=c.maxVisibleRowCount||200,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showFooter=c.showFooter===!0,c.footerRowHeight="undefined"!=typeof c.footerRowHeight?c.footerRowHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil",function(a){function b(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return b.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},b.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},b.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},b.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},b.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},b.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},b.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};
    +return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},b.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},b.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},b.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},b.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},b.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},b.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},b.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},b.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},b.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},b.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},b.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},b.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},b.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},b.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},b.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},b.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},b.prototype.updateColumnWidths=function(){var b=this,c=[],d=[],e=0,f=b.getViewportWidth();"undefined"!=typeof b.grid.verticalScrollbarWidth&&void 0!==b.grid.verticalScrollbarWidth&&b.grid.verticalScrollbarWidth>0&&(f+=b.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=b.visibleColumnCache;k.forEach(function(b){if(b.visible){var f=!1;angular.isNumber(b.width)||(f=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(e=parseInt(e+b.width.length,10),c.push(b)):f?d.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),b.grid.verticalScrollbarWidth&&(i+=b.grid.verticalScrollbarWidth),b.canvasWidth=parseInt(i,10),this.columnStyles=j},b}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.headerCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.cellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.cellTemplatePromise=a.getTemplate(d.cellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["gridUtil","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()),e.clear(),c}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toLowerCase(),f=b.toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){p.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(c,d,e,f){function g(){j=b.elementHeight(d),i=b.elementWidth(d)}function h(){a.cancel(k),k=a(function(){var a=b.elementHeight(d),c=b.elementWidth(d);a!==j||c!==i?(f.grid.gridHeight=a,f.grid.gridWidth=c,f.grid.refresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),c.$on("$destroy",function(){a.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3},EVENT_TYPE:{KEYDOWN:0,CLICK:1}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[]};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=1);var g=0===e?d.length-1:e-1;return g>e?0===f?new a(b,d[g]):new a(this.rows[f-1],d[g]):new a(b,d[g])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);-1===e&&(e=0);var g=e===d.length-1?0:e+1;return e>g?f===this.rows.length-1?new a(b,d[g]):new a(this.rows[f+1],d[g]):new a(b,d[g])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),f===this.rows.length-1?new a(b,d[e]):new a(this.rows[f+1],d[e])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=d.indexOf(c),f=this.rows.indexOf(b);return-1===e&&(e=0),0===f?new a(b,d[e]):new a(this.rows[f-1],d[e])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory",function(a,b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c,d){var e=null,f=null;null!==c&&(e=a.getRow(c)),null!==d&&(f=a.getColumn(d.name?d.name:d.field)),this.scrollToInternal(a,b,e,f)},scrollToInternal:function(a,c,d,e){var f={};if(null!==d){var g=a.renderContainers.body.visibleRowCache.indexOf(d),h=a.renderContainers.body.visibleRowCache.length,i=(g+g/(h-1))/h;f.y={percentage:i}}null!==e&&(f.x={percentage:this.getLeftWidth(a,e)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},scrollToIfNecessary:function(a,c,d,e){var f={},g=a.renderContainers.body.visibleRowCache,h=a.renderContainers.body.visibleColumnCache,i=a.renderContainers.body.prevScrollTop+a.headerHeight;i=0>i?0:i;var j=a.renderContainers.body.prevScrollLeft,k=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight;a.horizontalScrollbarHeight&&(k-=a.horizontalScrollbarHeight);var l=a.renderContainers.body.prevScrollLeft+a.gridWidth;if(a.verticalScrollbarWidth&&(l-=a.verticalScrollbarWidth),null!==d){var m=g.indexOf(d),n=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight();a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(n+=a.horizontalScrollbarHeight);var o=(m+1)*a.options.rowHeight;o=0>o?0:o;var p,q;i>o?(p=a.renderContainers.body.prevScrollTop-(i-o),q=p/n,f.y={percentage:q}):o>k&&(p=o-k+a.renderContainers.body.prevScrollTop,q=p/n,f.y={percentage:q})}if(null!==e){for(var r=h.indexOf(e),s=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),t=0,u=0;r>u;u++){var v=h[u];t+=v.drawnWidth}t=0>t?0:t;var w=t+e.drawnWidth;w=0>w?0:w;var x,y;j>t?(x=a.renderContainers.body.prevScrollLeft-(j-t),y=x/s,y=y>1?1:y,f.x={percentage:y}):w>l&&(x=w-l+a.renderContainers.body.prevScrollLeft,y=x/s,y=y>1?1:y,f.x={percentage:y})}(f.y||f.x)&&c.$broadcast(b.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return f}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.focusCell=function(a,b){g.cellNav.broadcastCellNav({row:a,col:b})},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a)},g.cellNav.broadcastFocus=function(b){var c=b.row,d=b.col;if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==c||h.cellNav.lastRowCol.col!==d){var e=new a(c,d);h.api.cellNav.raise.navigate(e,h.cellNav.lastRowCol),h.cellNav.lastRowCol=e}},g.cellNav.handleKeyDown=function(a){var e=c.getDirection(a);if(null===e)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var i=g.grid.api.cellNav.getFocusedCell();if(i){var j=g.grid.renderContainers[f].cellNav.getNextRowCol(e,i.row,i.col);return j.eventType=d.EVENT_TYPE.KEYDOWN,g.cellNav.broadcastCellNav(j),c.scrollToIfNecessary(h,b,j.row,j.col),a.stopPropagation(),a.preventDefault(),!1}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer"],scope:!1,compile:function(){return{pre:function(){},post:function(c,f,g,h){var i=h[0],j=h[1],k=j.containerId,l=i.grid;e.decorateRenderContainers(l),f.attr("tabindex",-1),f.on("keydown",function(a){return a.uiGridTargetRenderContainerId=k,i.cellNav.handleKeyDown(a)}),c.$on(d.events.GRID_SCROLL,function(){null!=i.grid.api.cellNav.getFocusedCell()&&a(function(){a(function(){var a=i.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&f[0].focus(),i.cellNav.broadcastCellNav(a)})})})}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",-1)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col)),c.stopPropagation()}),b.$on(f.CELL_NAV_EVENT,function(a,d){d.row===b.row&&d.col===b.col?(h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&c.find("div")[0].focus()):i()}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g){return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(e,h,i,j){function k(){h.on("dblclick",p),h.on("keydown",n),e.col.colDef.enableCellEditOnFocus&&h.find("div").on("focus",m)}function l(){h.off("dblclick",p),h.off("keydown",n),e.col.colDef.enableCellEditOnFocus&&h.find("div").off("focus",m)}function m(a){j&&j.cellNav&&j.cellNav.focusCell(e.row,e.col),a.stopPropagation(),p()}function n(a){g.isStartEditKey(a)&&p()}function o(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(e):a.colDef.cellEditableCondition)}function p(){if(!v&&o(e.col,e.row)){u=f(e.row.getQualifiedColField(e.col)),t=u(e),s=e.col.editableCellTemplate,s=s.replace(c.MODEL_COL_FIELD,e.row.getQualifiedColField(e.col));var b=e.col.colDef.editDropdownFilter?"|"+e.col.colDef.editDropdownFilter:"";switch(s=s.replace(c.CUSTOM_FILTERS,b),e.inputType="text",e.col.colDef.type){case"boolean":e.inputType="checkbox";break;case"number":e.inputType="number";break;case"date":e.inputType="date"}e.editDropdownOptionsArray=e.col.colDef.editDropdownOptionsArray,e.editDropdownIdLabel=e.col.colDef.editDropdownIdLabel?e.col.colDef.editDropdownIdLabel:"id",e.editDropdownValueLabel=e.col.colDef.editDropdownValueLabel?e.col.colDef.editDropdownValueLabel:"value";e.$apply(function(){v=!0,l();var b=angular.element(s);h.append(b),a(b)(e.$new());var c=angular.element(h.children()[0]);w=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var g=e.$on(c.events.GRID_SCROLL,function(){q(!0),e.grid.api.edit.raise.afterCellEdit(e.row.entity,e.col.colDef,u(e),t),g()}),i=e.$on(d.events.END_CELL_EDIT,function(a,b){q(b),e.grid.api.edit.raise.afterCellEdit(e.row.entity,e.col.colDef,u(e),t),i()}),j=e.$on(d.events.CANCEL_CELL_EDIT,function(){r(),j()});e.$broadcast(d.events.BEGIN_CELL_EDIT),e.grid.api.edit.raise.beginCellEdit(e.row.entity,e.col.colDef)}}function q(a){if(v){var b=angular.element(h.children()[0]);angular.element(h.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&w&&b[0].focus(),w=!1,v=!1,k(),e.grid.api.core.notifyDataChange(e.grid,c.dataChange.EDIT)}}function r(){v&&(u.assign(e,t),e.$apply(),e.grid.api.edit.raise.cancelCellEdit(e.row.entity,e.col.colDef),q(!0))}if(e.col.colDef.enableCellEdit){var s,t,u,v=!1,w=!1;k();try{var x=b.get("uiGridCellNavConstants");e.col.colDef.enableCellEditOnFocus&&e.$on(x.CELL_NAV_EVENT,function(a,b){b.row===e.row&&b.col===e.col?p():q()})}catch(y){}}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(c,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){console.log("stop edit!"),c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)
    +})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.refresh()}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",width:40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){var e=c(d)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){h.csvExport(a,b,c,d)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c,e){var f=this.getColumnHeaders(a,c),g=this.getData(a,b,c),h=this.formatAsCsv(f,g,a.options.exporterCsvColumnSeparator);!e&&a.options.exporterCsvLinkElement&&(e=a.options.exporterCsvLinkElement),e?this.renderCsvLink(a,h,e):d.logError("Exporter asked to export as csv, but no element provided.  Perhaps you should set gridOptions.exporterCsvLinkElement?")},getColumnHeaders:function(a,d){var e=[];return angular.forEach(a.columns,function(f){!f.visible&&d!==b.ALL||f.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(f.name)||e.push({name:f.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(f.displayName):f.displayName,width:f.drawnWidth?f.drawnWidth:f.width,align:"number"===f.colDef.type?"right":"left"})}),e},getData:function(a,e,f){var g,h=[];switch(e){case b.ALL:g=a.rows;break;case b.VISIBLE:g=a.getVisibleRows();break;case b.SELECTED:a.api.selection?g=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return b.ALL?(angular.forEach(g,function(d){var e=[];angular.forEach(a.columns,function(g){!g.visible&&f!==b.ALL||g.name===c.selectionRowHeaderColName||-1!==a.options.exporterSuppressColumns.indexOf(g.name)||e.push(a.options.exporterFieldCallback(a,d,g,a.getCellValue(d,g)))}),h.push(e)}),h):void 0},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return a.displayName}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,c,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){var f=angular.element(d);f.children("a").html(f.children("a").html().replace(b.LINK_LABEL,a.options.exporterLinkLabel)),f.children("a").attr("href",f.children("a").attr("href").replace(b.CSV_CONTENT,encodeURIComponent(c)));var h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&h.content.unshift(a.options.exporterPdfHeader),a.options.exporterPdfFooter&&h.content.push(a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a,b){i.importFile(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(a,c),a.deregisterDataChangeCallback(d)},[b.dataChange.ROW]),e=function(){a.deregisterDataChangeCallback(d)};a.importer.$scope.$on("$destroy",e)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){if(1===a.srcElement.files.length){var c=a.srcElement.files[0];b.importThisFile(i,c),a.srcElement.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options);var c={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){b.options.loadTimout=!1}}}};b.options.loadTimout=!1,b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){a.options.loadTimout=!0,a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.$on(d.events.GRID_SCROLL,function(b,d){if(d.y){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout",function(a,b){var c={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){b.redrawColumnAtPosition(a,c,d)}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var e=a.columns,f=function(a){for(var b=a,c=0;b>=c;c++)(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};c=f(c),d=f(d);var g=e[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)e[h]=e[h-1];else if(d>c)for(var i=c;d>i;i++)e[i]=e[i+1];e[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return c}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(b,e,f,g){if(b.col.colDef.enableColumnMoving){var h=function(h){if("ui-grid-icon-angle-down"!==h.target.className&&"I"!==h.target.tagName){var i=e.clone();e.append(i),i.addClass("movingColumn");var j={},k=b.grid.element[0].getBoundingClientRect().left,l=e[0].getBoundingClientRect().left;j.left=l-k+"px";var m,n=b.grid.element[0].getBoundingClientRect().right,o=e[0].getBoundingClientRect().right;o>n&&(m=b.col.drawnWidth+(n-o),j.width=m+"px"),i.css(j);var p=h.pageX,q=0,r=k+b.grid.getViewportWidth()-b.grid.verticalScrollbarWidth,s=function(a){g.fireEvent("hide-menu");var c=i[0].getBoundingClientRect().left-1,d=i[0].getBoundingClientRect().right,e=a.pageX-p,f=c-k+e;f=r>f?f:r,(c>=k||e>0)&&(r>=d||0>e)?i.css({visibility:"visible",left:f+"px"}):(e*=5,g.fireScrollingEvent({x:{pixels:2.5*e}})),q+=e,p=a.pageX,m<b.col.drawnWidth&&(m+=Math.abs(e),i.css({width:m+"px"}))};b.$on("$destroy",function(){d.off("mousemove",s),d.off("mouseup",t)}),d.on("mousemove",s);var t=function(e){var h,j=a.defer();f.$observe("renderIndex",function(a){h=b.$eval(a),j.resolve()}),j.promise.then(function(){i&&i.remove();for(var a=b.grid.renderContainers.body.renderedColumns,f=0,j=b.grid.columns,k=0;k<j.length&&j[k].colDef.name!==a[0].colDef.name;k++)f++;if(0>q){for(var l=0,m=h-1;m>=0;m--)if(l+=a[m].drawnWidth,l>Math.abs(q)){c.redrawColumnAtPosition(b.grid,f+h,f+m+1);break}l<Math.abs(q)&&c.redrawColumnAtPosition(b.grid,f+h,f+0)}else if(q>0){for(var n=0,o=h+1;o<a.length;o++)if(n+=a[o].drawnWidth,n>q){c.redrawColumnAtPosition(b.grid,f+h,f+o-1);break}q>n&&c.redrawColumnAtPosition(b.grid,f+h,f+a.length-1)}else if(0===q){var p=!1;e.shiftKey&&(p=!0),g.grid.sortColumn(b.col,p).then(function(){g.columnMenuScope&&g.columnMenuScope.hideMenu(),g.grid.refresh()})}d.off("mousemove",s),d.off("mouseup",t)})};d.on("mouseup",t)}};e.on("mousedown",h)}}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ui.grid"]);a.service("uiGridPaginationService",function(){var a={initializeGrid:function(b){a.defaultGridOptions(b.options),b.pagination={page:1,totalPages:1};var c={methods:{pagination:{getPage:function(){return b.pagination.page},getTotalPages:function(){return b.pagination.totalPages},nextPage:function(){b.pagination.page++,b.refresh()},previousPage:function(){b.pagination.page=Math.max(1,b.pagination.page-1),b.refresh()},seek:function(a){if(!angular.isNumber(a)||1>a)throw"Invalid page number: "+a;b.pagination.page=a,b.refresh()}}}};b.api.registerMethodsFromObject(c.methods),b.registerRowsProcessor(function(a){if(!b.options.enablePagination)return a;b.pagination.totalPages=Math.max(1,Math.ceil(a.length/b.options.rowsPerPage));var c=(b.pagination.page-1)*b.options.rowsPerPage;return c>=a.length&&(b.pagination.page=b.pagination.totalPages,c=(b.pagination.page-1)*b.options.rowsPerPage),a.slice(c,c+b.options.rowsPerPage)})},defaultGridOptions:function(a){a.enablePagination=a.enablePagination!==!1,a.rowsPerPage=angular.isNumber(a.rowsPerPage)?a.rowsPerPage:10}};return a}),a.directive("uiGridPagination",["uiGridPaginationService",function(a){return{priority:-400,scope:!1,require:"^uiGrid",link:{pre:function(b,c,d,e){a.initializeGrid(e.grid)}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==i.visibleColumnCache.indexOf(a.col)&&j.colDef.enableColumnResizing!==!1&&(e.prepend(f),c(f)(a)),a.col.colDef.enableColumnResizing!==!1&&(e.append(g),c(g)(a))})}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","columnBounds","uiGridResizeColumnsService",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(g,h,i,j){function k(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function l(){j.grid.buildColumns().then(function(){j.grid.refreshCanvas(!0)})}function m(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),p=a.clientX-q,0>p?p=0:p>j.grid.gridWidth&&(p=j.grid.gridWidth);var b,e=g.col,h=e.getRenderContainer();if("left"===g.position?(e=h.renderedColumns[g.renderIndex-1],b=g.col):"right"===g.position&&(b=h.renderedColumns[g.renderIndex+1]),e.colDef.enableColumnResizing!==!1){j.grid.element.hasClass("column-resizing")||j.grid.element.addClass("column-resizing");var i=p-o,k=parseInt(e.drawnWidth+i*r,10);e.colDef.minWidth&&k<e.colDef.minWidth?p+=(e.colDef.minWidth-k)*r:!e.colDef.minWidth&&d.minWidth&&k<d.minWidth?p+=e.colDef.minWidth-k:e.colDef.maxWidth&&k>e.colDef.maxWidth&&(p+=(e.colDef.maxWidth-k)*r),f.css({left:p+"px"}),j.fireEvent(c.events.ITEM_DRAGGING)}}function n(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),j.grid.element.removeClass("column-resizing"),f.remove(),p=b.clientX-q;var c=p-o;if(0===c)return a.off("mouseup",n),void a.off("mousemove",m);var h,i=g.col,s=i.getRenderContainer();if("left"===g.position?(i=s.renderedColumns[g.renderIndex-1],h=g.col):"right"===g.position&&(h=s.renderedColumns[g.renderIndex+1]),i.colDef.enableColumnResizing!==!1){var t=parseInt(i.drawnWidth+c*r,10);i.colDef.minWidth&&t<i.colDef.minWidth?t=i.colDef.minWidth:!i.colDef.minWidth&&d.minWidth&&t<d.minWidth&&(t=d.minWidth),i.colDef.maxWidth&&t>i.colDef.maxWidth&&(t=i.colDef.maxWidth),i.width=t,k(i),l(c),e.fireColumnSizeChanged(j.grid,i.colDef,c),a.off("mouseup",n),a.off("mousemove",m)}}var o=0,p=0,q=0,r=1;j.grid.isRTL()&&(g.position="left",r=-1),"left"===g.position?h.addClass("left"):"right"===g.position&&h.addClass("right"),h.on("mousedown",function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),q=j.grid.element[0].getBoundingClientRect().left,o=b.clientX-q,j.grid.element.append(f),f.css({left:o}),a.on("mouseup",n),a.on("mousemove",m)}),h.on("dblclick",function(a){a.stopPropagation();var f,i,m=g.col,n=m.getRenderContainer();"left"===g.position?(m=n.renderedColumns[g.renderIndex-1],f=g.col,i=1):"right"===g.position&&(f=n.renderedColumns[g.renderIndex+1],f=n.renderedColumns[g.renderIndex+1],i=-1);var o=0,p=0,q=b.closestElm(h,".ui-grid-render-container"),r=q.querySelectorAll("."+c.COL_CLASS_PREFIX+m.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(r,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var f=b.elementWidth(c);
    +e+=f}e>o&&(o=e,p=o-e)})}),m.colDef.minWidth&&o<m.colDef.minWidth?o=m.colDef.minWidth:!m.colDef.minWidth&&d.minWidth&&o<d.minWidth&&(o=d.minWidth),m.colDef.maxWidth&&o>m.colDef.maxWidth&&(o=m.colDef.maxWidth),m.width=parseInt(o,10),k(m),l(p),e.fireColumnSizeChanged(j.grid,m.colDef,p)}),h.on("$destroy",function(){h.off("mousedown"),h.off("dblclick"),a.off("mousemove",m),a.off("mouseup",n)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){f.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEdit.dirtyRows?a.rowEdit.dirtyRows:[]},getErrorRows:function(a){return a.rowEdit.errorRows?a.rowEdit.errorRows:[]},flushDirtyRows:function(a){return f.flushDirtyRows(a)},setRowsDirty:function(a,b){f.setRowsDirty(a,b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c){var d=b.renderContainers.body.visibleRowCache[c];null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},selectAllVisibleRows:function(){if(b.options.multiSelect!==!1){var c=[];b.rows.forEach(function(d){d.visible?d.isSelected||(d.isSelected=!0,a.decideRaiseSelectionEvent(b,d,c)):d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)}},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30},toggleRowSelection:function(b,c,d,e){var f=c.isSelected;if(d||f){if(!d&&f){var g=a.getSelectedRows(b);g.length>1&&(f=!1,a.clearSelectedRows(b))}}else a.clearSelectedRows(b);f&&e||(c.isSelected=!f,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c))},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=[],j=f;g>=j;j++){var k=b.renderContainers.body.visibleRowCache[j];k&&(k.isSelected||(k.isSelected=!0,b.selection.lastSelectedRow=k,a.decideRaiseSelectionEvent(b,k,i)))}a.decideRaiseSelectionBatchEvent(b,i)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){var c=[];a.getSelectedRows(b).forEach(function(d){d.isSelected&&(d.isSelected=!1,a.decideRaiseSelectionEvent(b,d,c))}),a.decideRaiseSelectionBatchEvent(b,c)},decideRaiseSelectionEvent:function(a,b,c){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b)},decideRaiseSelectionBatchEvent:function(a,b){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1};f.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(){c.selection.selectAll?(b.clearSelectedRows(c),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){var c=0,d=300,e=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()};b.on("touchstart",function(){c=(new Date).getTime()}),b.on("touchend",function(a){var b=(new Date).getTime(),f=b-c;d>f&&e(a)}),b.on("click",function(a){e(a)})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableVerticalScrollbar" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableHorizontalScrollbar" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionHeaderCell",'<div><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)">&nbsp;</div>')}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.16/ui-grid.svg b/release/3.0.0-rc.16/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-rc.16/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.16/ui-grid.ttf b/release/3.0.0-rc.16/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-rc.16/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.16/ui-grid.woff b/release/3.0.0-rc.16/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-rc.16/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.19/ui-grid.css b/release/3.0.0-rc.19/ui-grid.css
    new file mode 100644
    index 000000000..ce374c369
    --- /dev/null
    +++ b/release/3.0.0-rc.19/ui-grid.css
    @@ -0,0 +1,1289 @@
    +/*!
    + * ui-grid - v3.0.0-rc.19 - 2015-02-11
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow-y: scroll;
    +  -webkit-overflow-scrolling: touch;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top: 1px;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  overflow-y: scroll;
    +  max-height: 300px;
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child {
    +  border-left: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.19/ui-grid.eot b/release/3.0.0-rc.19/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-rc.19/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.19/ui-grid.js b/release/3.0.0-rc.19/ui-grid.js
    new file mode 100644
    index 000000000..00e16ffac
    --- /dev/null
    +++ b/release/3.0.0-rc.19/ui-grid.js
    @@ -0,0 +1,19879 @@
    +/*!
    + * ui-grid - v3.0.0-rc.19 - 2015-02-11
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart', // For any item being dragged
    +      COLUMN_HEADER_CLICK: 'uiGridColumnHeaderClick'
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      PG_UP: 33,
    +      PG_DOWN: 34,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +
    +    scrollDirection: {
    +      UP: 'up',
    +      DOWN: 'down',
    +      LEFT: 'left',
    +      RIGHT: 'right',
    +      NONE: 'none'
    +
    +    },
    +
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column',
    +      OPTIONS: 'options'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1
    +      //WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var initColClass = $scope.col.getColClass(false);
    +          $elm.addClass(initColClass);
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          // watch the col and row to see if they change - which would indicate that we've scrolled or sorted or otherwise
    +          // changed the row/col that this cell relates to, and we need to re-evaluate cell classes and maybe other things
    +          var cellChangeFunction = function( n, o ){
    +            if ( n !== o ) {
    +              if ( classAdded || $scope.col.cellClass ){
    +                updateClass();
    +              }
    +
    +              // See if the column's internal class has changed
    +              var newColClass = $scope.col.getColClass(false);
    +              if (newColClass !== initColClass) {
    +                $elm.removeClass(initColClass);
    +                $elm.addClass(newColClass);
    +                initColClass = newColClass;
    +              }
    +            }
    +          };
    +
    +          // TODO(c0bra): Turn this into a deep array watch
    +          var colWatchDereg = $scope.$watch( 'col', cellChangeFunction );
    +          var rowWatchDereg = $scope.$watch( 'row', cellChangeFunction );
    +          
    +          
    +          var deregisterFunction = function() {
    +            dataChangeDereg();
    +            colWatchDereg();
    +            rowWatchDereg(); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +          $elm.on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +        $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +        $scope.grid.api.core.raise.columnVisibilityChanged( $scope.col );        
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            var footerTemplate = ($scope.grid.options.gridFooterTemplate) ? $scope.grid.options.gridFooterTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 'ScrollEvent',
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, ScrollEvent) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            var initColClass = $scope.col.getColClass(false);
    +            $elm.addClass(initColClass);
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +              
    +              var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
    +              $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
    +            };
    +
    +            $scope.$watch('col', function (n, o) {
    +              if (n !== o) {
    +                // See if the column's internal class has changed
    +                var newColClass = $scope.col.getColClass(false);
    +                if (newColClass !== initColClass) {
    +                  $elm.removeClass(initColClass);
    +                  $elm.addClass(newColClass);
    +                  initColClass = newColClass;
    +                }
    +              }
    +            });
    +  
    +            updateClass();
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(event) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (event.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ($scope.sortable || $scope.colMenu) {
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +
    +              var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
    +              $contentsElm.on(downEvent, function(event) {
    +                event.stopPropagation();
    +
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +
    +                uiGridCtrl.fireEvent(uiGridConstants.events.COLUMN_HEADER_CLICK, {event: event, columnName: $scope.col.colDef.name});
    +              });
    +        
    +              var upEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'mouseup';
    +              $contentsElm.on(upEvent, function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });
    +            }
    +
    +
    +            $scope.toggleMenu = function(event) {
    +              event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
    +              $contentsElm.on(clickEvent, function(event) {
    +                event.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(event);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh()
    +                      .then(function () {
    +                        if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                          var scrollEvent = new ScrollEvent(uiGridCtrl.grid,null,null,'uiGridHeaderCell.toggleMenu');
    +                          scrollEvent.y.percentage = uiGridCtrl.prevScrollArgs.y.percentage;
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +                      });
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // Replace the reference to the container's header element with this new element
    +                containerCtrl.header = newElm;
    +                containerCtrl.colContainer.header = newElm;
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              //if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +              //  availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              //}
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              //if (grid.verticalScrollbarWidth) {
    +              //  canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              //}
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', 'uiGridConstants', function( gridUtil, i18nService, uiGridConstants ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +      gridCol.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +      gridCol.grid.api.core.raise.columnVisibilityChanged( gridCol );
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      if (uiGridCtrl) {
    +       $scope.$on('$destroy', uiGridCtrl.grid.api.core.on.scrollEvent($scope, applyHideMenu ));
    +      }
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil', 'ScrollEvent',
    +    function($timeout, $document, uiGridConstants, gridUtil, ScrollEvent) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              grid.api.core.on.scrollEvent($scope,scrollHandler);
    +            }
    +
    +            function scrollHandler (args) {
    +              // exit if not for this grid
    +              if (args.grid && args.grid.id !== grid.id){
    +                return;
    +              }
    +
    +              
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var newScrollTop = args.getNewScrollTop(rowContainer,containerCtrl.viewport);
    +
    +                //only set scrollTop if we coming from something other than viewPort scrollBar or
    +                //another column container
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll ||
    +                    args.sourceColContainer !== colContainer) {
    +                  containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                }
    +
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +                var newScrollLeft = args.getNewScrollLeft(colContainer,containerCtrl.viewport);
    +
    +                // Make the current horizontal scroll position available in the $scope
    +                $scope.newScrollLeft = newScrollLeft;                
    +
    +                if (containerCtrl.headerViewport) {
    +                  containerCtrl.headerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  containerCtrl.footerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                //scroll came from somewhere else, so the viewport must be positioned
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll) {
    +                  containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                }
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +
    +              var newEvent = gridUtil.normalizeWheelEvent(evt);
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerMouseWheel);
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / rowContainer.getVerticalScrollLength();
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = gridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +
    +              // todo: this isn't working when scrolling down.  it works fine for up.  tested on Chrome
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +                if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1 && containerCtrl.viewport[0].scrollTop !== 0 ) ||
    +                    (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +                  evt.preventDefault();
    +              }
    +
    +              scrollEvent.fireThrottledScrollingEvent();
    +            });
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / rowContainer.getVerticalScrollLength();
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +              if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1) ||
    +                  (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +                event.preventDefault();
    +              }
    +              scrollEvent.fireScrollingEvent();
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              //function decelerate() {
    +              //  $timeout(function() {
    +              //    var args = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerTouchMove);
    +              //
    +              //    if (scrollYLength !== 0) {
    +              //      var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / rowContainer.getVerticalScrollLength();
    +              //
    +              //      args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +              //    }
    +              //
    +              //    if (scrollXLength !== 0) {
    +              //      var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              //      args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +              //    }
    +              //
    +              //    uiGridCtrl.fireScrollingEvent(args);
    +              //
    +              //    decelerateCount = decelerateCount -1;
    +              //    scrollYLength = scrollYLength / 2;
    +              //    scrollXLength = scrollXLength / 2;
    +              //
    +              //    if (decelerateCount > 0) {
    +              //      decelerate();
    +              //    }
    +              //    else {
    +              //      uiGridCtrl.scrollbars.forEach(function (sbar) {
    +              //        sbar.removeClass('ui-grid-scrollbar-visible');
    +              //        sbar.removeClass('ui-grid-scrolling');
    +              //      });
    +              //    }
    +              //  }, decelerateInterval);
    +              //}
    +
    +              // decelerate();
    +            }
    +
    +            if (gridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                //uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                //  sbar.addClass('ui-grid-scrollbar-visible');
    +                //  sbar.addClass('ui-grid-scrolling');
    +                //});
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +
    +              //add additional height for scrollbar on left and right container
    +              if ($scope.containerId !== 'body') {
    +                canvasHeight += grid.scrollbarHeight;
    +              }
    +
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + (canvasWidth + grid.scrollbarWidth) + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + grid.scrollbarWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              // If the render container has an "explicit" header height (such as in the case that its header is smaller than the other headers and needs to be explicitly set to be the same, ue thae)
    +              if (renderContainer.explicitHeaderHeight !== undefined && renderContainer.explicitHeaderHeight !== null && renderContainer.explicitHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.explicitHeaderHeight + 'px; }';
    +              }
    +              // Otherwise if the render container has an INNER header height, use that on the header cells (so that all the header cells are the same height and those that have less elements don't have undersized borders)
    +              else if (renderContainer.innerHeaderHeight !== undefined && renderContainer.innerHeaderHeight !== null && renderContainer.innerHeaderHeight > 0) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-cell { height: ' + renderContainer.innerHeaderHeight + 'px; }';
    +              }
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          //gridUtil.logDebug('margin-top ' + hiddenRowWidth );
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            // Function for attaching the template to this scope
    +            var clonedElement, cloneScope;
    +            function compileTemplate() {
    +              $scope.row.getRowTemplateFn.then(function (compiledElementFn) {
    +                // var compiledElementFn = $scope.row.compiledElementFn;
    +
    +                // Create a new scope for the contents of this row, so we can destroy it later if need be
    +                var newScope = $scope.$new();
    +
    +                compiledElementFn(newScope, function (newElm, scope) {
    +                  // If we already have a cloned element, we need to remove it and destroy its scope
    +                  if (clonedElement) {
    +                    clonedElement.remove();
    +                    cloneScope.$destroy();
    +                  }
    +
    +                  // Empty the row and append the new element
    +                  $elm.empty().append(newElm);
    +
    +                  // Save the new cloned element and scope
    +                  clonedElement = newElm;
    +                  cloneScope = newScope;
    +                });
    +              });
    +            }
    +
    +            // Initially attach the compiled template to this scope
    +            compileTemplate();
    +
    +            // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
    +            $scope.$watch('row.getRowTemplateFn', function (newFunc, oldFunc) {
    +              if (newFunc !== oldFunc) {
    +                compileTemplate();
    +              }
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants',
    +    function(gridUtil, ScrollEvent, uiGridConstants) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              grid.flagScrollingHorizontally();
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              if (xDiff > 0) { grid.scrollDirection = uiGridConstants.scrollDirection.RIGHT; }
    +              if (xDiff < 0) { grid.scrollDirection = uiGridConstants.scrollDirection.LEFT; }
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              if (horizScrollLength !== 0) {
    +                horizScrollPercentage = newScrollLeft / horizScrollLength;
    +              }
    +              else {
    +                horizScrollPercentage = 0;
    +              }
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              grid.flagScrollingVertically();
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              if (yDiff > 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.DOWN; }
    +              if (yDiff < 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.UP; }
    +
    +              var vertScrollLength = rowContainer.getVerticalScrollLength();
    +
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
    +              scrollEvent.newScrollLeft = newScrollLeft;
    +              scrollEvent.newScrollTop = newScrollTop;
    +              if ( horizScrollPercentage > -1 ){
    +                scrollEvent.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                scrollEvent.y = { percentage: vertScrollPercentage };
    +              }
    +              scrollEvent.fireScrollingEvent();
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile', 'ScrollEvent',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile, ScrollEvent) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +
    +      //assign $scope.$parent if appScope not already assigned
    +      self.grid.appScope = self.grid.appScope || $scope.$parent;
    +
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns({ orderByColumnDefs: true })
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function adjustInfiniteScrollPosition (scrollToRow) {
    +
    +        var scrollEvent = new ScrollEvent(self.grid, null, null, 'ui.grid.adjustInfiniteScrollPosition');
    +        var totalRows = self.grid.renderContainers.body.visibleRowCache.length;
    +        var percentage = ( scrollToRow + ( scrollToRow / ( totalRows - 1 ) ) ) / totalRows;
    +
    +        //for infinite scroll, never allow it to be at the zero position so the up button can be active
    +        if ( percentage === 0 ) {
    +          scrollEvent.y = {pixels: 1};
    +        }
    +        else {
    +          scrollEvent.y = {percentage: percentage};
    +        }
    +        scrollEvent.fireScrollingEvent();
    +
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +
    +                  $timeout(function () {
    +                    //Process post load scroll events if using infinite scroll
    +                    if ( self.grid.options.enableInfiniteScroll ) {
    +                      //If first load, seed the scrollbar down a little to activate the button
    +                      if ( self.grid.renderContainers.body.prevRowScrollIndex === 0 ) {
    +                        adjustInfiniteScrollPosition(0);
    +                      }
    +                      //If we are scrolling up, we need to reseed the grid.
    +                      if (self.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                        adjustInfiniteScrollPosition(self.grid.renderContainers.body.prevRowScrollIndex + 1 + self.grid.options.excessRows);
    +                      }
    +                    }
    +                    }, 0);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '='
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.calcFooterHeight();
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.refreshCanvas(true);
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth || col.width || 0;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 || !myWidth ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +
    +    /**
    +     * @ngdoc object
    +     * @name appScope
    +     * @propertyOf ui.grid.class:Grid
    +     * @description reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +     * <br/>
    +     * use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference
    +     */
    +    self.appScope = self.options.appScopeProvider;
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +
    +
    +    self.footerHeight = self.calcFooterHeight();
    +
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +
    +    /**
    +     * @ngdoc property
    +     * @name scrollDirection
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set one of the uiGridConstants.scrollDirection values (UP, DOWN, LEFT, RIGHT, NONE), which tells
    +     * us which direction we are scrolling. Set to NONE via debounced method
    +     */
    +    self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +
    +    self.scrollbarHeight = 0;
    +    self.scrollbarWidth = 0;
    +    if (self.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarHeight = gridUtil.getScrollbarWidth();
    +    }
    +
    +    if (self.options.enableVerticalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarWidth = gridUtil.getScrollbarWidth();
    +    }
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +      /**
    +     * @ngdoc function
    +     * @name columnVisibilityChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The visibility of a column has changed,
    +     * the column itself is passed out as a parameter of the event. 
    +     * 
    +     * @param {GridCol} column the column that changed
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.columnVisibilityChanged( $scope, function (column) {
    +     *        // do something
    +     *      } );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'columnVisibilityChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +
    +    self.registerStyleComputation({
    +      priority: 10,
    +      func: self.getFooterStyles
    +    });
    +  };
    +
    +   Grid.prototype.calcFooterHeight = function () {
    +     if (!this.hasFooter()) {
    +       return 0;
    +     }
    +
    +     var height = 0;
    +     if (this.options.showGridFooter) {
    +       height += this.options.gridFooterHeight;
    +     }
    +
    +     if (this.options.showColumnFooter) {
    +       height += this.options.columnFooterHeight;
    +     }
    +
    +     return height;
    +   };
    +
    +   Grid.prototype.getFooterStyles = function () {
    +     var style = '.grid' + this.id + ' .ui-grid-footer-aggregates-row { height: ' + this.options.columnFooterHeight + 'px; }';
    +     style += ' .grid' + this.id + ' .ui-grid-footer-info { height: ' + this.options.gridFooterHeight + 'px; }';
    +     return style;
    +   };
    +
    +  Grid.prototype.hasFooter = function () {
    +   return this.options.showGridFooter || this.options.showColumnFooter;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * - when the options watch fires, the OPTIONS callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * - OPTIONS calls OPTIONS and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +   * ALL 
    +   * @returns {function} deregister function - a function that can be called to deregister this callback
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types, _this) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types, _this:_this };
    +    
    +    var self = this;
    +    var deregisterFunction = function() {
    +      delete self.dataChangeCallbacks[uid];
    +    };
    +    return deregisterFunction;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        if (callback._this) {
    +           callback.callback.apply(callback._this,this);
    +        }
    +        else {
    +          callback.callback( this );
    +        }
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ||
    +         type === constants.OPTIONS ){
    +      this.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.refresh();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @param {object} options  An object contains options to use when building columns
    +   *
    +   * * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
    +   *
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns(opts) {
    +    var options = {
    +      orderByColumnDefs: false
    +    };
    +
    +    angular.extend(options, opts);
    +
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        // tell updateColumnDef that the column was pre-existing
    +        col.updateColumnDef(colDef, false);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    /*** Reorder columns if necessary ***/
    +    if (!!options.orderByColumnDefs) {
    +      // Create a shallow copy of the columns as a cache
    +      var columnCache = self.columns.slice(0);
    +
    +      // We need to allow for the "row headers" when mapping from the column defs array to the columns array
    +      //   If we have a row header in columns[0] and don't account for it   we'll overwrite it with the column in columnDefs[0]
    +
    +      // Go through all the column defs
    +      for (i = 0; i < self.options.columnDefs.length; i++) {
    +        // If the column at this index has a different name than the column at the same index in the column defs...
    +        if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
    +          // Replace the one in the cache with the appropriate column
    +          columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
    +        }
    +        else {
    +          // Otherwise just copy over the one from the initial columns
    +          columnCache[i + headerOffset] = self.columns[i + headerOffset];
    +        }
    +      }
    +
    +      // Empty out the columns array, non-destructively
    +      self.columns.length = 0;
    +
    +      // And splice in the updated, ordered columns from the cache
    +      Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
    +    }
    +
    +    return $q.all(builderPromises).then(function(){
    +      if (self.rows.length > 0){
    +        self.assignTypes();
    +      }
    +    });
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    var self = this;
    +
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      // See if the column name already exists:
    +      var foundName = self.getColumn(colDef.field);
    +
    +      // If a column with this name already  exists, we will add an incrementing number to the end of the new column name
    +      if (foundName) {
    +        // Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
    +        var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
    +
    +        var foundColumns = self.columns.filter(function (column) {
    +          // Test against the displayName, as that's what'll have the incremented number
    +          return nameRE.test(column.displayName);
    +        })
    +        // Sort the found columns by the end-number
    +        .sort(function (a, b) {
    +          if (a === b) {
    +            return 0;
    +          }
    +          else {
    +            var numA = a.match(nameRE)[1];
    +            var numB = b.match(nameRE)[1];
    +
    +            return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
    +          }
    +        });
    +
    +        // Not columns found, so start with number "2"
    +        if (foundColumns.length === 0) {
    +          colDef.name = colDef.field + '2';
    +        }
    +        else {
    +          // Get the number from the final column
    +          var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
    +
    +          // Make sure to parse to an int
    +          lastNum = parseInt(lastNum, 10);
    +
    +          // Add 1 to the number from the last column and tack it on to the field to be the name for this new column 
    +          colDef.name = colDef.field + (lastNum + 1);
    +        }
    +      }
    +      // ... otherwise just use the field as the column name
    +      else {
    +        colDef.name = colDef.field;
    +      }
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +//        if (wasEmpty) {
    +           self.assignTypes();
    +//        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.canvasHeightShouldUpdate = true;
    +      
    +      if ( typeof(container.visibleRowCache) === 'undefined' ){
    +        container.visibleRowCache = [];  
    +      } else {
    +        container.visibleRowCache.length = 0;  
    +      }
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +    self.api.core.raise.rowsRendered(this.api);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name updateCanvasHeight
    +   * @methodOf ui.grid.class:Grid
    +   * @description flags all render containers to update their canvas height
    +   */
    +  Grid.prototype.updateCanvasHeight = function updateCanvasHeight() {
    +    var self = this;
    +
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +        container.canvasHeightShouldUpdate = true;
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    //}
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    //gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    //gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    //}
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol && !col.colDef.suppressRemoveSort) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    // gridUtil.logDebug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeight) {
    +              maxHeight = innerHeaderHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (container.headerHeight < maxHeight) {
    +            container.explicitHeaderHeight = maxHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +
    +      container.adjustRows(null, container.prevScrolltopPercentage, true);
    +      container.adjustColumns(null, container.prevScrollleftPercentage);
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasLeftContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if leftContainer has columns
    +     */
    +    Grid.prototype.hasLeftContainerColumns = function () {
    +      return this.hasLeftContainer() && this.renderContainers.left.renderedColumns.length > 0;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasRightContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if rightContainer has columns
    +     */
    +    Grid.prototype.hasRightContainerColumns = function () {
    +      return this.hasRightContainer() && this.renderContainers.right.renderedColumns.length > 0;
    +    };
    +
    +
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name rowsRendered
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the cache of visible rows is changed.
    +           */
    +          this.registerEvent( 'core', 'rowsRendered' );
    +
    +
    +          /**
    +           * @ngdoc event
    +           * @name scrollEvent
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised on a scroll Event.  Called frequently so be careful what you do with it
    +           */
    +          this.registerEvent( 'core', 'scrollEvent' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name canvasHeightChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised when the canvas height has changed
    +           * <br/>
    +           * arguments: oldHeight, newHeight
    +           */
    +          this.registerEvent( 'core', 'canvasHeightChanged');
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.eventId, l.handler, self.grid, l._this);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * <br>
    +         * .raise.eventName() - takes no arguments
    +         * <br/>
    +         * <br/>
    +         * .on.eventName(scope, callBackFn, _this)
    +         * <br/>
    +         * scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +         * <br/>
    +         * callBackFn - The function to call
    +         * <br/>
    +         * _this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +         * <br/>
    +         * .on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +         * will be removed when the scope is destroyed.
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$emit.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler, _this) {
    +            var deregAngularOn = registerEventWithAngular(eventId, handler, self.grid, _this);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: deregAngularOn, eventId: eventId, scope: scope, _this:_this};
    +            self.listeners.push(listener);
    +
    +            var removeListener = function(){
    +              listener.dereg();
    +              var index = self.listeners.indexOf(listener);
    +              self.listeners.splice(index,1);
    +            };
    +
    +            //destroy tracking when scope is destroyed
    +            scope.$on('$destroy', function() {
    +              removeListener();
    +            });
    +
    +            return removeListener;
    +          };
    +        };
    +
    +        function registerEventWithAngular(eventId, handler, grid, _this) {
    +          return $rootScope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(_this ? _this : grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} _this binds callBackFn 'this' to _this.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, _this) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(_this || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} _this binds this to _this for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, _this) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, _this);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef, true);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         term: 'aa',
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...',
    +   *         flags: { caseSensitive: false }
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...',
    +   *     flags: { caseSensitive: false }
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {boolean} isNew whether the column is being newly created, if not
    +   * we're updating an existing column, and some items such as the sort shouldn't
    +   * be copied down
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef, isNew) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it, but only if this is a newly added column
    +    if ( isNew ){
    +      self.setPropertyOrDefault(colDef, 'sort');
    +    }
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * 
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * - flags: only flag currently available is `caseSensitive`, set to false if you don't want
    +     * case sensitive matching
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       term: 'xx',
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...',
    +     *       flags: { caseSensitive: false }
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    // Only set filter if this is a newly added column, if we're updating an existing
    +    // column then we don't want to put the default filter back if the user may have already
    +    // removed it.
    +    if ( isNew ) {
    +      self.setPropertyOrDefault(colDef, 'filter');
    +      self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +    }
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>
    +   * app.config(function($provide){
    +   *   $provide.decorator('GridOptions',function($delegate){
    +   *     var gridOptions;
    +   *     gridOptions = angular.copy($delegate);
    +   *     gridOptions.initialize = function(options) {
    +   *       var initOptions;
    +   *       initOptions = $delegate.initialize(options);
    +   *       initOptions.enableColumnMenus = false;
    +   *       return initOptions;
    +   *     };
    +   *     return gridOptions;
    +   *   });
    +   * });
    +   * </pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      /**
    +       * @ngdoc function
    +       * @name onRegisterApi
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description A callback that returns the gridApi once the grid is instantiated, which is 
    +       * then used to interact with the grid programatically.
    +       * 
    +       * Note that the gridApi.core.renderingComplete event is identical to this 
    +       * callback, but has the advantage that it can be called from multiple places
    +       * if needed
    +       * 
    +       * @example
    +       * <pre>
    +       *   $scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +       *     $scope.gridApi = gridApi;
    +       *     $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +       *   };
    +       * </pre>
    +       * 
    +       */
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showGridFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       * The footer display Total Rows and Visible Rows (filtered rows)
    +       */
    +      baseOptions.showGridFooter = baseOptions.showGridFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name showColumnFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the column footer, defaults to false
    +       * The column footer displays column aggregates
    +       */
    +      baseOptions.showColumnFooter = baseOptions.showColumnFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name columnFooterHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer rows (column footer and grid footer) in pixels
    +       *
    +       */
    +      baseOptions.columnFooterHeight = typeof(baseOptions.columnFooterHeight) !== "undefined" ? baseOptions.columnFooterHeight : 30;
    +      baseOptions.gridFooterHeight = typeof(baseOptions.gridFooterHeight) !== "undefined" ? baseOptions.gridFooterHeight : 30;
    +
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +
    +      /**
    +       * @ngdoc object
    +       * @name appScopeProvider
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +       * this property allows you to assign any reference you want to grid.appScope
    +       */
    +      baseOptions.appScopeProvider = baseOptions.appScopeProvider || null;
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeightShouldUpdate
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description flag to signal that container should recalculate the canvas size
    +     */
    +    self.canvasHeightShouldUpdate = true;
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeight
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description last calculated canvas height value
    +     */
    +    self.$$canvasHeight = 0;
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCanvasHeight
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false
    +   * @returns {number} total height of all the visible rows in the container
    +   */
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    if (!self.canvasHeightShouldUpdate) {
    +      return self.$$canvasHeight;
    +    }
    +
    +    var oldCanvasHeight = self.$$canvasHeight;
    +
    +    self.$$canvasHeight =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      self.$$canvasHeight += row.height;
    +    });
    +
    +
    +    self.canvasHeightShouldUpdate = false;
    +
    +    self.grid.api.core.raise.canvasHeightChanged(oldCanvasHeight, self.$$canvasHeight);
    +
    +    return self.$$canvasHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() {
    +    return this.getCanvasHeight() - this.getViewportHeight();
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    //if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +    //  ret = ret - self.verticalScrollbarWidth;
    +    //}
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage, false);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage, postDataLoaded) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getVerticalScrollLength();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
    +        // Have we hit the threshold going down?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +        //Have we hit the threshold going up?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +      }
    +      var rangeStart = {};
    +      var rangeEnd = {};
    +
    +      //If infinite scroll is enabled, and we loaded more data coming from redrawInPlace, then recalculate the range and set rowIndex to proper place to scroll to
    +      if ( self.grid.options.enableInfiniteScroll && self.grid.scrollDirection !== uiGridConstants.scrollDirection.NONE && postDataLoaded ) {
    +        var findIndex = null;
    +        var i = null;
    +        if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.UP ) {
    +          findIndex = rowIndex > 0 ? self.grid.options.excessRows : 0;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex);
    +          rangeEnd = Math.min(rowCache.length, rangeStart + self.grid.options.excessRows + minRows);
    +        }
    +        else if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.DOWN ) {
    +          findIndex = minRows;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows - minRows);
    +          rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +        }
    +      }
    +      else {
    +        rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +        rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +      }
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      /* Commented the following lines because otherwise the moved column wasn't visible immediately on the new position
    +       * in the case of many columns with horizontal scroll, one had to scroll left or right and then return in order to see it
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }*/
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    //if (self.grid.verticalScrollbarWidth) {
    +    //  canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  GridRenderContainer.prototype.getViewPortStyle = function () {
    +    var self = this;
    +    var styles = {};
    +
    +    if (self.name === 'body') {
    +      styles['overflow-x'] = self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +      if (!self.grid.isRTL()) {
    +        if (self.grid.hasRightContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +      else {
    +        if (self.grid.hasLeftContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +    }
    +    else if (self.name === 'left') {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +    else {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = !self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +
    +    return styles;
    +
    +
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +
    +    this.$$height = grid.options.rowHeight;
    +
    +  }
    +
    +    /**
    +     *  @ngdoc object
    +     *  @name height
    +     *  @propertyOf  ui.grid.class:GridRow
    +     *  @description height of each individual row. changing the height will flag all
    +     *  row renderContainers to recalculate their canvas height
    +     */
    +    Object.defineProperty(GridRow.prototype, 'height', {
    +      get: function() {
    +        return this.$$height;
    +      },
    +      set: function(height) {
    +        if (height !== this.$$height) {
    +          this.grid.updateCanvasHeight();
    +          this.$$height = height;
    +        }
    +      }
    +    });
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +    GridRow.prototype.getQualifiedColField = function(col) {
    +      return 'row.' + this.getEntityQualifiedColField(col);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  angular.module('ui.grid')
    +    .factory('ScrollEvent', ['gridUtil', function (gridUtil) {
    +
    +      /**
    +       * @ngdoc function
    +       * @name ui.grid.class:ScrollEvent
    +       * @description Model for all scrollEvents
    +       * @param {Grid} grid that owns the scroll event
    +       * @param {GridRenderContainer} sourceRowContainer that owns the scroll event. Can be null
    +       * @param {GridRenderContainer} sourceColContainer that owns the scroll event. Can be null
    +       * @param {string} source the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName
    +       */
    +      function ScrollEvent(grid, sourceRowContainer, sourceColContainer, source) {
    +        var self = this;
    +        if (!grid) {
    +          throw new Error("grid argument is required");
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name grid
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description A reference back to the grid
    +         */
    +         self.grid = grid;
    +
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name entity
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description the source of the scroll event. limited to values from uiGridConstants.scrollEventSources
    +         */
    +        self.source = source;
    +
    +        self.sourceRowContainer = sourceRowContainer;
    +        self.sourceColContainer = sourceColContainer;
    +
    +        self.newScrollLeft = null;
    +        self.newScrollTop = null;
    +        self.x = null;
    +        self.y = null;
    +
    +
    +        /**
    +         *  @ngdoc function
    +         *  @name fireThrottledScrollingEvent
    +         *  @methodOf  ui.grid.class:ScrollEvent
    +         *  @description fires a throttled event using grid.api.core.raise.scrollEvent
    +         */
    +        self.fireThrottledScrollingEvent = gridUtil.throttle(function() {
    +          self.grid.api.core.raise.scrollEvent(self);
    +        }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      }
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name fireScrollingEvent
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description fires an event using grid.api.core.raise.scrollEvent
    +       */
    +      ScrollEvent.prototype.fireScrollingEvent = function() {
    +        this.grid.api.core.raise.scrollEvent(this);
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollLeft
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollLeft property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollLeft = function(colContainer, viewport){
    +        var self = this;
    +
    +        if (!self.newScrollLeft){
    +          var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +          var oldScrollLeft = gridUtil.normalizeScrollLeft(viewport);
    +
    +          var scrollXPercentage;
    +          if (typeof(self.x.percentage) !== 'undefined' && self.x.percentage !== undefined) {
    +            scrollXPercentage = self.x.percentage;
    +          }
    +          else if (typeof(self.x.pixels) !== 'undefined' && self.x.pixels !== undefined) {
    +            scrollXPercentage = self.x.percentage = (oldScrollLeft + self.x.pixels) / scrollWidth;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event X axis");
    +          }
    +
    +          return Math.max(0, scrollXPercentage * scrollWidth);
    +        }
    +
    +        return self.newScrollLeft;
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollTop
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollTop property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollTop = function(rowContainer, viewport){
    +        var self = this;
    +
    +
    +        if (!self.newScrollTop){
    +          var scrollLength = rowContainer.getVerticalScrollLength();
    +
    +          var oldScrollTop = viewport[0].scrollTop;
    +
    +          var scrollYPercentage;
    +          if (typeof(self.y.percentage) !== 'undefined' && self.y.percentage !== undefined) {
    +            scrollYPercentage = self.y.percentage;
    +          }
    +          else if (typeof(self.y.pixels) !== 'undefined' && self.y.pixels !== undefined) {
    +            scrollYPercentage = self.y.percentage = (oldScrollTop + self.y.pixels) / scrollLength;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +          }
    +
    +          return Math.max(0, scrollYPercentage * scrollLength);
    +        }
    +
    +        return self.newScrollTop;
    +      };
    +
    +
    +      ScrollEvent.Sources = {
    +        ViewPortScroll: 'ViewPortScroll',
    +        RenderContainerMouseWheel: 'RenderContainerMouseWheel',
    +        RenderContainerTouchMove: 'RenderContainerTouchMove',
    +        Other: 99
    +      };
    +
    +      return ScrollEvent;
    +    }]);
    +
    +
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Row builder for custom row templates
    +          grid.registerRowBuilder(service.rowTemplateAssigner);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        },
    +
    +        rowTemplateAssigner: function rowTemplateAssigner(row) {
    +          var grid = this;
    +
    +          // Row has no template assigned to it
    +          if (!row.rowTemplate) {
    +            // Use the default row template from the grid
    +            row.rowTemplate = grid.options.rowTemplate;
    +
    +            // Use the grid's function for fetching the compiled row template function
    +            row.getRowTemplateFn = grid.getRowTemplateFn;
    +          }
    +          // Row has its own template assigned
    +          else {
    +            // Create a promise for the compiled row template function
    +            var perRowTemplateFnPromise = $q.defer();
    +            row.getRowTemplateFn = perRowTemplateFnPromise.promise;
    +
    +            // Get the row template
    +            gridUtil.getTemplate(row.rowTemplate)
    +              .then(function (template) {
    +                // Compile the template
    +                var rowTemplateFn = $compile(template);
    +                
    +                // Resolve the compiled template function promise
    +                perRowTemplateFnPromise.resolve(rowTemplateFn);
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
    +              });
    +          }
    +
    +          return row.getRowTemplateFn;
    +        }
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setupFilters
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +   * do all the parsing and pre-processing and store that data into a new filters object.  The object
    +   * has the condition, the flags, the stripped term, and a parsed reg exp if there was one.
    +   * 
    +   * We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +   * for loops everywhere else in this module...
    +   * 
    +   * @param {array} filters the filters from the column (col.filters or [col.filter])
    +   * @returns {array} An array of parsed/preprocessed filters
    +   */
    +  rowSearcher.setupFilters = function setupFilters( filters ){
    +    var newFilters = [];
    +    
    +    var filtersLength = filters.length;
    +    for ( var i = 0; i < filtersLength; i++ ){
    +      var filter = filters[i];
    +      if ( filter.noTerm || filter.term ){
    +        var newFilter = {};
    +        
    +        var regexpFlags = '';
    +        if (!filter.flags || !filter.flags.caseSensitive) {
    +          regexpFlags += 'i';
    +        }
    +    
    +        if ( filter.term ){
    +          // it is possible to have noTerm.  We don't need to copy that across, it was just a flag to avoid
    +          // getting the filter ignored if the filter was a function that didn't use a term
    +          newFilter.term = rowSearcher.stripTerm(filter);
    +        }
    +        
    +        if ( filter.condition ){
    +          newFilter.condition = filter.condition;
    +        } else {
    +          newFilter.condition = rowSearcher.guessCondition(filter);
    +        }
    +
    +        newFilter.flags = angular.extend( { caseSensitive: false }, filter.flags );
    +
    +        if (newFilter.condition === uiGridConstants.filter.STARTS_WITH) {
    +          newFilter.startswithRE = new RegExp('^' + newFilter.term, regexpFlags);
    +        }
    +        
    +         if (newFilter.condition === uiGridConstants.filter.ENDS_WITH) {
    +          newFilter.endswithRE = new RegExp(newFilter.term + '$', regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.CONTAINS) {
    +          newFilter.containsRE = new RegExp(newFilter.term, regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.EXACT) {
    +          newFilter.exactRE = new RegExp('^' + newFilter.term + '$', regexpFlags);
    +        }
    +        
    +        newFilters.push(newFilter);
    +      }
    +    }
    +    return newFilters;
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name runColumnFilter
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Runs a single pre-parsed filter against a cell, returning true
    +   * if the cell matches that one filter.
    +   * 
    +   * @param {Grid} grid the grid we're working against
    +   * @param {GridRow} row the row we're matching against
    +   * @param {GridCol} column the column that we're working against
    +   * @param {object} filter the specific, preparsed, filter that we want to test
    +   * @returns {boolean} true if we match (row stays visible)
    +   */
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Term to search for.
    +    var term = filter.term;
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +    
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      return filter.condition.test(value);
    +    }
    +
    +    // If the filter's condition is a function, run it
    +    if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    
    +    if (filter.startswithRE) {
    +      return filter.startswithRE.test(value);
    +    }
    +    
    +    if (filter.endswithRE) {
    +      return filter.endswithRE.test(value);
    +    }
    +    
    +    if (filter.containsRE) {
    +      return filter.containsRE.test(value);
    +    }
    +    
    +    if (filter.exactRE) {
    +      return filter.exactRE.test(value);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      var regex = new RegExp('^' + term + '$');
    +      return !regex.exec(value);
    +    }
    +
    +    if (typeof(value) === 'number'){
    +      // if the term has a decimal in it, it comes through as '9\.4', we need to take out the \
    +      var tempFloat = parseFloat(term.replace(/\\./,'.'));
    +      if (!isNaN(tempFloat)) {
    +        term = tempFloat;
    +      }
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      return (value > term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      return (value >= term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      return (value < term);
    +    }
    +    
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      return (value <= term);
    +    }
    +    
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process provided filters on provided column against a given row. If the row meets 
    +   * the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @param {array} filters array of pre-parsed/preprocessed filters to apply
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, filters) {
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    var filtersLength = filters.length;
    +    for (var i = 0; i < filtersLength; i++) {
    +      var filter = filters[i];
    +      
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across the given rows and columns, marking any rows that don't 
    +   * match the stored col.filters or col.filter as invisible.
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    /*
    +     * Added performance optimisations into this code base, as this logic creates deeply nested
    +     * loops and is therefore very performance sensitive.  In particular, avoiding forEach as
    +     * this impacts some browser optimisers (particularly Chrome), using iterators instead
    +     */
    +    
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Build list of filters to apply
    +    var filterData = [];
    +
    +    var colsLength = columns.length;
    +    for (var i = 0; i < colsLength; i++) {
    +      var col = columns[i];
    +      
    +      if (typeof(col.filters) !== 'undefined' && ( col.filters.length > 1 || col.filters.length === 1 && ( typeof(col.filters[0].term) !== 'undefined' && col.filters[0].term || col.filters[0].noTerm ) ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters(col.filters) } );
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters([col.filter]) } );
    +      }
    +    }
    +    
    +    if (filterData.length > 0) {
    +      // define functions outside the loop, performance optimisation
    +      var foreachRow = function(grid, row, col, filters){
    +        if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, filters)) {
    +          row.visible = false;
    +        }
    +      };
    +      
    +      var foreachFilterCol = function(grid, filterData){
    +        var rowsLength = rows.length;
    +        for ( var i = 0; i < rowsLength; i++){
    +          foreachRow(grid, rows[i], filterData.col, filterData.filters);  
    +        }
    +      };
    +
    +      // nested loop itself - foreachFilterCol, which in turn calls foreachRow
    +      var filterDataLength = filterData.length;
    +      for ( var j = 0; j < filterDataLength; j++){
    +        foreachFilterCol( grid, filterData[j] );  
    +      }
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toString().toLowerCase(),
    +          strB = b.toString().toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +    
    +    // put a custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( rows, function ( row, idx ) {
    +      row.entity.$uiGridIndex = idx;
    +    });
    +
    +    // Now actually sort the data
    +    var newRows = rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Chrome doesn't implement a stable sort function.  If our sort returns 0 
    +      // (i.e. the items are equal), then return the previous order using our custom
    +      // index variable
    +      if (tem === 0 ) {
    +        return rowA.entity.$uiGridIndex - rowB.entity.$uiGridIndex;
    +      }
    +      
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +    
    +    // remove the custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( newRows, function ( row, idx ) {
    +      delete row.entity.$uiGridIndex;
    +    });
    +    
    +    return newRows;
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        pagination: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        },
    +        pagination: {
    +          sizes: 'articles par page',
    +          totalItems: 'articles'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ja', {
    +        aggregate: {
    +          label: '件'
    +        },
    +        groupPanel: {
    +          description: '列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。'
    +        },
    +        search: {
    +          placeholder: '検索...',
    +          showingItems: '絞込み件数:',
    +          selectedItems: '選択件数:',
    +          totalItems: '全件数:',
    +          size: 'ページサイズ: ',
    +          first: '最初のページ',
    +          next: '次のページ',
    +          previous: '前のページ',
    +          last: '最後のページ'
    +        },
    +        menu: {
    +          text: '列選択:'
    +        },
    +        sort: {
    +          ascending: '昇順ソート',
    +          descending: '降順ソート',
    +          remove: 'ソート取消'
    +        },
    +        column: {
    +          hide: '列を隠す'
    +        },
    +        aggregation: {
    +          count: '合計件数: ',
    +          sum: '合計: ',
    +          avg: '平均: ',
    +          min: '最小値: ',
    +          max: '最大値: '
    +        },
    +        pinning: {
    +          pinLeft: '左にピン留め',
    +          pinRight: '右にピン留め',
    +          unpin: 'ピン留め取消'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: 'インポートファイル',
    +          exporterAllAsCsv: '全てのデータをCSV形式でエクスポート',
    +          exporterVisibleAsCsv: '絞込み済みデータをCSV形式でエクスポート',
    +          exporterSelectedAsCsv: '選択しているデータをCSV形式でエクスポート',
    +          exporterAllAsPdf: '全てのデータをPDFでエクスポート',
    +          exporterVisibleAsPdf: '絞込み済みデータをPDFでエクスポート',
    +          exporterSelectedAsPdf: '選択しているデータをPDFでエクスポート'
    +        },
    +        importer: {
    +          noHeaders: '列名が抽出できません。ヘッダーは設定されていますか?',
    +          noObjects: 'データが抽出できません。ファイルにデータは含まれていますか?',
    +          invalidCsv: '処理を行うことができません。ファイルは有効なCSVファイルですか?',
    +          invalidJson: '処理を行うことができません。ファイルは有効なJSONファイルですか?',
    +          jsonNotArray: 'JSONファイルは配列を含んでいる必要があります。処理を中断します。'
    +        },
    +        pagination: {
    +          sizes: '件 / ページ',
    +          totalItems: '件'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'всего строк: ',
    +          sum: 'итого: ',
    +          avg: 'среднее: ',
    +          min: 'мин: ',
    +          max: 'макс: '
    +        },
    +        gridMenu: {
    +          columns: 'Столбцы:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Экспортировать всё в CSV',
    +          exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
    +          exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
    +          exporterAllAsPdf: 'Экспортировать всё в PDF',
    +          exporterVisibleAsPdf: 'Экспортировать видимые данные в PDF',
    +          exporterSelectedAsPdf: 'Экспортировать выбранные данные в PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        pagination: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        },
    +        pagination: {
    +          sizes: '行每页',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        },
    +        pagination: {
    +          sizes: '行每頁',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3, PG_UP: 4, PG_DOWN: 5},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +        this.bodyContainer = rowContainer;
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.api:GridRow
    +       *
    +       *  @description GridRow settings for cellNav feature, these are available to be
    +       *  set only internally (for example, by other features)
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name allowCellFocus
    +       *  @propertyOf  ui.grid.cellNav.api:GridRow
    +       *  @description Enable focus on a cell within this row.  If set to false then no cells
    +       *  in this row can be focused - group header rows as an example would set this to false.
    +       *  <br/>Defaults to true
    +       */
    +      /** returns focusable rows */
    +      UiGridCellNav.prototype.getFocusableRows = function () {
    +        return this.rows.filter(function(row) {
    +          return row.allowCellFocus !== false;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_UP:
    +            return this.getRowColPageUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_DOWN:
    +            return this.getRowColPageDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(focusableRows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === focusableRows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(focusableRows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === focusableRows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(focusableRows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex >= focusableRows.length - pageSize) {
    +          return new RowCol(focusableRows[focusableRows.length - 1], focusableCols[curColIndex]); //return last row
    +        }
    +        else {
    +          //down one page
    +          return new RowCol(focusableRows[curRowIndex + pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(focusableRows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex - pageSize < 0) {
    +          return new RowCol(focusableRows[0], focusableCols[curColIndex]); //return first row
    +        }
    +        else {
    +          //up one page
    +          return new RowCol(focusableRows[curRowIndex - pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory', 'ScrollEvent',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav, ScrollEvent) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +          grid.cellNav.focusedCells = [];
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (rowEntity, colDef) {
    +                  service.scrollTo(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view, and sets focus
    +                 * to that cell
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus
    +                 * @param {object} colDef to make visible and set focus
    +                 */
    +                scrollToFocus: function (rowEntity, colDef) {
    +                  service.scrollToFocus(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column fully into view if it isn't already
    +                 * @param {GridRow} row grid row that we should make fully visible
    +                 * @param {GridCol} col grid col to make fully visible
    +                 */
    +                scrollToIfNecessary: function (row, col) {
    +                  service.scrollToIfNecessary(grid, row, col);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getCurrentSelection
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns an array containing the current selection
    +                 * <br> array is empty if no selection has occurred
    +                 */
    +                getCurrentSelection: function () {
    +                  return grid.cellNav.focusedCells;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name rowColSelectIndex
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +                 * isn't selected
    +                 * @param {object} rowCol the rowCol to evaluate
    +                 */
    +                rowColSelectIndex: function (rowCol) {
    +                  //return gridUtil.arrayContainsObjectWithProperty(grid.cellNav.focusedCells, 'col.uid', rowCol.col.uid) &&
    +                  var index = -1;
    +                  for (var i = 0; i < grid.cellNav.focusedCells.length; i++) {
    +                    if (grid.cellNav.focusedCells[i].col.uid === rowCol.col.uid &&
    +                      grid.cellNav.focusedCells[i].row.uid === rowCol.row.uid) {
    +                      index = i;
    +                      break;
    +                    }
    +                  }
    +                  return index;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:GridOptions
    +           *
    +           *  @description GridOptions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelectCells
    +           *  @propertyOf  ui.grid.cellNav.api:GridOptions
    +           *  @description Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelectCells = gridOptions.modifierKeysToMultiSelectCells === true;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_UP){
    +            return uiGridCellNavConstants.direction.PG_UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_DOWN){
    +            return uiGridCellNavConstants.direction.PG_DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell within this column.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null && typeof(rowEntity) !== 'undefined' ) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null && typeof(colDef) !== 'undefined' ) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToFocus
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view, and set focus to the cell in that row and column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus to
    +         * @param {object} colDef to make visible and set focus to
    +         */
    +        scrollToFocus: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +
    +          var rowCol = { row: gridRow, col: gridCol };
    +
    +          // Broadcast the navigation
    +          grid.cellNav.broadcastCellNav(rowCol);
    +
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         *
    +         * To get to row 9 (i.e. the last row) in the same list, we want to
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll,
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToInternal');
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            scrollEvent.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            scrollEvent.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid, 'uiGridCellNavService.scrollToIfNecessary');
    +
    +          // Alias the visible row and column caches
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          //if (grid.horizontalScrollbarHeight) {
    +          //  bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          //}
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + Math.ceil(grid.gridWidth);
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          //if (grid.verticalScrollbarWidth) {
    +          //  rightBound = rightBound - grid.verticalScrollbarWidth;
    +          //}
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            //if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +            //  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            //}
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;
    +            }
    +          });
    +
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var _scope = $scope;
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = grid.cellNav.broadcastCellNav = function (newRowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol, modifierDown);
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol, modifierDown);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +
    +                var row = rowCol.row,
    +                  col = rowCol.col;
    +
    +                var rowColSelectIndex = uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol);
    +
    +                if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                  if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
    +                    grid.cellNav.focusedCells.push(rowCol);
    +                  } else {
    +                    grid.cellNav.focusedCells = [rowCol];
    +                  }
    +                } else if (grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                  rowColSelectIndex >= 0) {
    +
    +                  grid.cellNav.focusedCells.splice(rowColSelectIndex, 1);
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                 renderContainerCtrl = controllers[1];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              var needFocus = false;
    +              
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              grid.api.core.on.scrollEvent($scope, function (args) {
    +                // Skip if not this grid that the event was broadcast for
    +                if (args.grid && args.grid.id !== uiGridCtrl.grid.id) {
    +                  return;
    +                }
    +
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +                
    +                /*
    +                 * If we have scrolled due to cellNav, we want to set the focus to the new cell after the 
    +                 * virtualisation has run, and after scroll.  If we scrolled through the browser scroll
    +                 * bar or other user action, we're going to discard the focus, because it will no longer 
    +                 * be valid (and, noting #2423, trying to keep it causes problems)
    +                 * 
    +                 * If cellNav triggers the scroll, we get a scrollToIfNecessary, then a viewport scroll. We
    +                 * want to wait for the viewport scroll to finish, then do a refocus.  
    +                 * 
    +                 * If someone manually scrolls we get just the viewport scroll, no scrollToIfNecessary.  We
    +                 * want to just clear the focus
    +                 * 
    +                 * Logic is:
    +                 *  - if cellNav scroll, set a flag that will be resolved in the native scroll
    +                 *  - if native scroll, look for the cellNav promise and resolve it
    +                 *    - if not present, then use a timeout to clear focus
    +                 *    - if it is present, then instead use a timeout to set focus
    +                 */ 
    +                
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                if ( args.source === 'uiGridCellNavService.scrollToIfNecessary'){
    +                  needFocus = true;
    +/*
    +                  focusTimeout = $timeout(function () {
    +                    if ( clearFocusTimeout ){
    +                      $timeout.cancel(clearFocusTimeout);
    +                    }
    +                    focusTimeout = $timeout(function () {
    +                      if ( clearFocusTimeout ){
    +                        $timeout.cancel(clearFocusTimeout);
    +                      }
    +                      // Get the last row+col combo
    +                      var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +  
    +                      // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                      //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                      //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                      if ($document.activeElement === $document.body) {
    +                        $elm[0].focus();
    +                      }
    +  
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                    });
    +                  });
    +                  */
    +                } else {
    +                  if ( needFocus ){
    +                    $timeout(function () {
    +                      $timeout(function () {
    +                        // Get the last row+col combo
    +                        var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +    
    +                        // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                        //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                        //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                        if ($document.activeElement === $document.body) {
    +                          $elm[0].focus();
    +                        }
    +    
    +                        // broadcast a cellNav event so we clear the focus on all cells
    +                        uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                        
    +                        needFocus = false;
    +                      });
    +                    });
    +                  }
    +                }
    +              });  
    +             
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +
    +            evt.stopPropagation();
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol, modifierDown) {
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol) === -1) {
    +                clearFocus();
    +              } else {
    +                setFocused();
    +              }
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else if (!(uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown)) {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.api:GridRow
    +   *
    +   *  @description GridRow options for edit feature, these are available to be
    +   *  set internally only, by other features
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableCellEdit
    +   *  @propertyOf  ui.grid.edit.api:GridRow
    +   *  @description enable editing on row, grouping for example might disable editing on group header rows
    +   */
    +
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        var touchstartTimeout = 500;
    +
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit || $scope.row.enableCellEdit === false) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +            var cancelTouchstartTimeout;
    +
    +            var editCellScope;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +
    +              // Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
    +              $elm.on('touchstart', touchStart);
    +            }
    +
    +            function touchStart(event) {
    +              // jQuery masks events
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +
    +              // Bind touchend handler
    +              $elm.on('touchend', touchEnd);
    +
    +              // Start a timeout
    +              cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
    +
    +              // Timeout's done! Start the edit
    +              cancelTouchstartTimeout.then(function () {
    +                // Use setTimeout to start the edit because beginEdit expects to be outside of $digest
    +                setTimeout(beginEdit, 0);
    +
    +                // Undbind the touchend handler, we don't need it anymore
    +                $elm.off('touchend', touchEnd);
    +              });
    +            }
    +
    +            // Cancel any touchstart timeout
    +            function touchEnd(event) {
    +              $timeout.cancel(cancelTouchstartTimeout);
    +              $elm.off('touchend', touchEnd);
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +              $elm.off('touchstart', touchStart);
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving &&
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownRowEntityOptionsArrayPath
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description a path to a property on row.entity containing an
    +             *  array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which will be used to populate
    +             *  the edit dropdown.  This can be used when the dropdown values are dependent on
    +             *  the backing row entity.
    +             *  If this property is set then editDropdownOptionsArray will be ignored.
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              // if the cell isn't fully visible, and cellNav is present, scroll it to be fully visible before we start
    +              if ( $scope.grid.api.cellNav ){
    +                $scope.grid.api.cellNav.scrollToIfNecessary( $scope, $scope.row, $scope.col );
    +              }
    +              
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              var inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  inputType = 'number';
    +                  break;
    +                case 'date':
    +                  inputType = 'date';
    +                  break;
    +              }
    +              html = html.replace('INPUT_TYPE', inputType);
    +
    +              var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
    +              if (editDropdownRowEntityOptionsArrayPath) {
    +                $scope.editDropdownOptionsArray =  resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
    +              }
    +              else {
    +                $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              }
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                editCellScope = $scope.$new();
    +                $compile(cellElement)(editCellScope);
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.col.grid.api.core.on.scrollEvent($scope, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +                deregOnGridScroll();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              editCellScope.$destroy();
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +            // resolves a string path against the given object
    +            // shamelessly borrowed from
    +            // http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
    +            function resolveObjectFromPath(object, path) {
    +              path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    +              path = path.replace(/^\./, '');           // strip a leading dot
    +              var a = path.split('.');
    +              while (a.length) {
    +                  var n = a.shift();
    +                  if (n in object) {
    +                      object = object[n];
    +                  } else {
    +                      return;
    +                  }
    +              }
    +              return object;
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
    +      function (gridUtil, uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +               $scope.deepEdit = false;
    +
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('uiGridEditor', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        priority: -100, // run after default uiGridEditor directive
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.expandable.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        grid.expandable = {};
    +        grid.expandable.expandedAll = false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name 
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Width in pixels of the expandable column. Defaults to 40
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeaderWidth: 40
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name toggleAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.toggleAllRows();
    +               * </pre>
    +               */              
    +              toggleAllRows: function() {
    +                service.toggleAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +          grid.expandable.expandedAll = false;
    +        }
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = true;
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = false;
    +        grid.refresh();
    +      },
    +
    +      toggleAllRows: function(grid) {
    +        if (grid.expandable.expandedAll) {
    +          service.collapseAllRows(grid);
    +        }
    +        else {
    +          service.expandAllRows(grid);
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {
    +                  name: 'expandableButtons', 
    +                  displayName: '', 
    +                  exporterSuppressExport: true, 
    +                  enableColumnResizing: false, 
    +                  enableColumnMenu: false,
    +                  width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
    +                };
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGrid
    +   *  @description stacks on the uiGrid directive to register child grid with parent row when child is created
    +   */
    +  module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 1000,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
    +                //if a parent grid row is on the scope, then add the parentRow property to this childGrid
    +                if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
    +
    +                  /**
    +                   *  @ngdoc directive
    +                   *  @name ui.grid.expandable.class:Grid
    +                   *  @description Additional Grid properties added by expandable module
    +                   */
    +
    +                  /**
    +                   *  @ngdoc object
    +                   *  @name parentRow
    +                   *  @propertyOf ui.grid.expandable.class:Grid
    +                   *  @description reference to the expanded parent row that owns this grid
    +                   */
    +                  uiGridCtrl.grid.parentRow = $scope.row;
    +
    +                  //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
    +                 // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
    +                 //   uiGridCtrl.grid.parentRow = newHeight;
    +                 // });
    +                }
    +
    +              });
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridExpandableRow
    +   *  @description directive to render the expandable row template
    +   */
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridRow
    +   *  @description stacks on the uiGridRow directive to add support for expandable rows
    +   */
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridViewport
    +   *  @description stacks on the uiGridViewport directive to append the expandable row html elements to the
    +   *  default gridRow template
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    BUTTON_LABEL: 'BUTTON_LABEL',
    +    FILE_NAME: 'FILE_NAME'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                csvExport: function (rowTypes, colTypes) {
    +                  service.csvExport(grid, rowTypes, colTypes);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for exporter feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:ColumnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvFilename
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default filename to use when saving the downloaded csv.  
    +           * This will only work in some browsers.
    +           * <br/>Defaults to 'download.csv'
    +           */
    +          gridOptions.exporterCsvFilename = gridOptions.exporterCsvFilename ? gridOptions.exporterCsvFilename : 'download.csv';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilterUseName
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Defaults to false, which leads to `displayName` being passed into the headerFilter.
    +           * If set to true, then will pass `name` instead.
    +           * 
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilterUseName = true;
    +           * </pre>
    +           */
    +          gridOptions.exporterHeaderFilterUseName = gridOptions.exporterHeaderFilterUseName === true;          
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * 
    +           * Behaviour can be changed to pass in `name` instead of `displayName` through use of `exporterHeaderFilterUseName: true`.
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +          
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        csvExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          this.downloadFile (grid.options.exporterCsvFilename, csvContent);
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterSuppressExport
    +         * @description Suppresses export for this column.  Used by selection and expandable.
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.colDef.exporterSuppressExport !== true &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? ( grid.options.exporterHeaderFilterUseName ? grid.options.exporterHeaderFilter(gridCol.name) : grid.options.exporterHeaderFilter(gridCol.displayName) ) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.exporter.api:GridRow
    +         * @description GridRow settings for exporter
    +         */
    +        /**
    +         * @ngdoc object
    +         * @name exporterEnableExporting
    +         * @propertyOf  ui.grid.exporter.api:GridRow
    +         * @description If set to false, then don't export this row, notwithstanding visible or 
    +         * other settings
    +         * <br/>Defaults to true
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate.  Any rows marked
    +         * `exporterEnableExporting: false` will not be exported
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            if (row.exporterEnableExporting !== false) {
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.colDef.exporterSuppressExport !== true &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                  if ( gridCol.colDef.exporterPdfAlign ) {
    +                    extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                  }
    +                  extractedRow.push(extractedField);
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            }
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name downloadFile
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Triggers download of a csv file.  Logic provided
    +         * by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391
    +         * @param {string} fileName the filename we'd like our file to be
    +         * given
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * download as a file
    +         */
    +        downloadFile: function (fileName, csvContent) {
    +          var D = document;
    +          var a = D.createElement('a');
    +          var strMimeType = 'application/octet-stream;charset=utf-8';
    +          var rawFile;
    +      
    +          // IE10+
    +          if (navigator.msSaveBlob) {
    +            return navigator.msSaveBlob(new Blob(["\ufeff", csvContent], {
    +              type: strMimeType
    +            }), fileName);
    +          }
    +      
    +          //html5 A[download]
    +          if ('download' in a) {
    +            var blob = new Blob([csvContent], {
    +              type: strMimeType
    +            });
    +            rawFile = URL.createObjectURL(blob);
    +            a.setAttribute('download', fileName);
    +          } else {
    +            rawFile = 'data:' + strMimeType + ',' + encodeURIComponent(csvContent);
    +            a.setAttribute('target', '_blank');
    +          }
    +      
    +          a.href = rawFile;
    +          a.setAttribute('style', 'display:none;');
    +          D.body.appendChild(a);
    +          setTimeout(function() {
    +            if (a.click) {
    +              a.click();
    +              // Workaround for Safari 5
    +            } else if (document.createEvent) {
    +              var eventObj = document.createEvent('MouseEvents');
    +              eventObj.initEvent('click', true, true);
    +              a.dispatchEvent(eventObj);
    +            }
    +            D.body.removeChild(a);
    +    
    +          }, 100);
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.header = grid.options.exporterPdfHeader;
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.footer = grid.options.exporterPdfFooter;
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( fileObject ) {
    +                  service.importThisFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and if the rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var dataChangeDereg = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( newObjects );
    +              dataChangeDereg();
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            grid.importer.$scope.$on( '$destroy', dataChangeDereg );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            var target = event.srcElement || event.target;
    +            
    +            if (target && target.files && target.files.length === 1) {
    +              var fileObject = target.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              target.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', function (gridUtil, $compile, $timeout, uiGridConstants) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              },
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreDataTop
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached top percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreDataTop: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
    +       */
    +
    +      loadData: function (grid) {
    +        grid.options.loadTimout = true;
    +        if (grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +          grid.api.infiniteScroll.raise.needLoadMoreDataTop();
    +          return;
    +        }
    +        grid.api.infiniteScroll.raise.needLoadMoreData();
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.grid.api.core.on.scrollEvent($scope, function (args) {
    +                  //Prevent circular scroll references, if source is coming from ui.grid.adjustInfiniteScrollPosition() function
    +                  if (args.y && (args.source !== 'ui.grid.adjustInfiniteScrollPosition')) {
    +                    var percentage = 100 - (args.y.percentage * 100);
    +                    if ($scope.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                      percentage = (args.y.percentage * 100);
    +                    }
    +                    uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                  }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', 'ScrollEvent', 'uiGridConstants', function ($q, $timeout, $log, ScrollEvent, uiGridConstants) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                var columns = grid.columns;
    +                if (!angular.isNumber(originalPosition) || !angular.isNumber(finalPosition)) {
    +                  console.log('Please provide valid values for originalPosition and finalPosition');
    +                  return;
    +                }
    +                var nonMovableColumns = 0;
    +                for (var i = 0; i < columns.length; i++) {
    +                  if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +                    nonMovableColumns++;
    +                  }
    +                }
    +                if (originalPosition >= (columns.length - nonMovableColumns) || finalPosition >= (columns.length - nonMovableColumns)) {
    +                  console.log('Invalid values for originalPosition, finalPosition');
    +                  return;
    +                }
    +                var findPositionForRenderIndex = function (index) {
    +                  var position = index;
    +                  for (var i = 0; i <= position; i++) {
    +                    if (angular.isDefined(columns[i]) && ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true)) {
    +                      position++;
    +                    }
    +                  }
    +                  return position;
    +                };
    +                self.redrawColumnAtPosition(grid, findPositionForRenderIndex(originalPosition), findPositionForRenderIndex(finalPosition));
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +
    +        var columns = grid.columns;
    +
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +            grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log', 'uiGridConstants', 'ScrollEvent',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log, uiGridConstants, ScrollEvent) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                $scope.$on(uiGridConstants.events.COLUMN_HEADER_CLICK, function (event, args) {
    +
    +                  if (args.columnName === $scope.col.colDef.name && !$scope.col.renderContainer) {
    +
    +                    var evt = args.event;
    +                    if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                      //Setting some variables required for calculations.
    +                      var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                      var previousMouseX = evt.pageX;
    +                      var totalMouseMovement = 0;
    +                      var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth();// - $scope.grid.verticalScrollbarWidth;
    +
    +                      //Clone element should move horizontally with mouse.
    +                      var elmCloned = false;
    +                      var movingElm;
    +                      var reducedWidth;
    +
    +                      var cloneElement = function () {
    +                        elmCloned = true;
    +
    +                        //Cloning header cell and appending to current header cell.
    +                        movingElm = $elm.clone();
    +                        $elm.parent().append(movingElm);
    +
    +                        //Left of cloned element should be aligned to original header cell.
    +                        movingElm.addClass('movingColumn');
    +                        var movingElementStyles = {};
    +                        var elmLeft = $elm[0].getBoundingClientRect().left;
    +                        movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                        var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                        var elmRight = $elm[0].getBoundingClientRect().right;
    +                        if (elmRight > gridRight) {
    +                          reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                          movingElementStyles.width = reducedWidth + 'px';
    +                        }
    +                        movingElm.css(movingElementStyles);
    +                      };
    +
    +                      var moveElement = function (changeValue) {
    +                        //Hide column menu
    +                        uiGridCtrl.fireEvent('hide-menu');
    +
    +                        //Calculate total column width
    +                        var columns = $scope.grid.columns;
    +                        var totalColumnWidth = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) {
    +                            totalColumnWidth += columns[i].drawnWidth || columns[i].width || columns[i].colDef.width;
    +                          }
    +                        }
    +
    +                        //Calculate new position of left of column
    +                        var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                        var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                        var newElementLeft;
    +                        if (gridUtil.detectBrowser() === 'ie') {
    +                          newElementLeft = currentElmLeft + changeValue;
    +                        }
    +                        else {
    +                          newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                        }
    +                        newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                        //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                        if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                          movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                        }
    +                        else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
    +                          changeValue *= 8;
    +                          var scrollEvent = new ScrollEvent($scope.col.grid, null, null, 'uiGridHeaderCell.moveElement');
    +                          scrollEvent.x = {pixels: changeValue};
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +
    +                        //Calculate total width of columns on the left of the moving column and the mouse movement
    +                        var totalColumnsLeftWidth = 0;
    +                        for (var il = 0; il < columns.length; il++) {
    +                          if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                            if (columns[il].colDef.name !== $scope.col.colDef.name) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                            }
    +                            else {
    +                              break;
    +                            }
    +                          }
    +                        }
    +                        if ($scope.newScrollLeft === undefined) {
    +                          totalMouseMovement += changeValue;
    +                        }
    +                        else {
    +                          totalMouseMovement = $scope.newScrollLeft + newElementLeft - totalColumnsLeftWidth;
    +                        }
    +
    +                        //Increase width of moving column, in case the rightmost column was moved and its width was
    +                        //decreased because of overflow
    +                        if (reducedWidth < $scope.col.drawnWidth) {
    +                          reducedWidth += Math.abs(changeValue);
    +                          movingElm.css({'width': reducedWidth + 'px'});
    +                        }
    +                      };
    +
    +                      var mouseMoveHandler = function (evt) {
    +                        //Disable text selection in Chrome during column move
    +                        document.onselectstart = function() { return false; };
    +
    +                        var changeValue = evt.pageX - previousMouseX;
    +                        if (!elmCloned && Math.abs(changeValue) > 50) {
    +                          cloneElement();
    +                        }
    +                        else if (elmCloned) {
    +                          moveElement(changeValue);
    +                          previousMouseX = evt.pageX;
    +                        }
    +                      };
    +
    +                      /*
    +                       //Commenting these lines as they are creating trouble with column moving when grid has huge scroll
    +                       // On scope destroy, remove the mouse event handlers from the document body
    +                       $scope.$on('$destroy', function () {
    +                       $document.off('mousemove', mouseMoveHandler);
    +                       $document.off('mouseup', mouseUpHandler);
    +                       });
    +                       */
    +                      $document.on('mousemove', mouseMoveHandler);
    +
    +                      var mouseUpHandler = function (evt) {
    +                        //Re-enable text selection after column move
    +                        document.onselectstart = null;
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var columns = $scope.grid.columns;
    +                        var columnIndex = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== $scope.col.colDef.name) {
    +                            columnIndex++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = columnIndex - 1; il >= 0; il--) {
    +                            if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                              if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, il + 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, 0);
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = columnIndex + 1; ir < columns.length; ir++) {
    +                            if (angular.isUndefined(columns[ir].colDef.visible) || columns[ir].colDef.visible === true) {
    +                              totalColumnsRightWidth += columns[ir].drawnWidth || columns[ir].width || columns[ir].colDef.width;
    +                              if (totalColumnsRightWidth > totalMouseMovement) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, ir - 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, columns.length - 1);
    +                          }
    +                        }
    +/*
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +*/
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      };
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    }
    +                  }
    +                });
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ng', 'ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', ['gridUtil',
    +    function (gridUtil) {
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name initializeGrid
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @description Attaches the service to a certain grid
    +         * @param {Grid} grid The grid we want to work with
    +         */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.pagination.api:PublicAPI
    +          *
    +          * @description Public API for the pagination feature
    +          */
    +          var publicApi = {
    +            events: {
    +              pagination: {
    +              /**
    +               * @ngdoc event
    +               * @name paginationChanged
    +               * @eventOf ui.grid.pagination.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {int} currentPage requested page number
    +               * @param {int} pageSize requested page size
    +               */
    +                paginationChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              pagination: {
    +                /**
    +                 * @ngdoc method
    +                 * @name getPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the number of the current page
    +                 */
    +                getPage: function () {
    +                  return grid.options.enablePagination ? grid.options.paginationCurrentPage : null;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name getTotalPages
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the total number of pages
    +                 */
    +                getTotalPages: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return null;
    +                  }
    +
    +                  return (grid.options.totalItems === 0) ? 1 : Math.ceil(grid.options.totalItems / grid.options.paginationPageSize);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name nextPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the next page, if possible
    +                 */
    +                nextPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  if (grid.options.totalItems > 0) {
    +                    grid.options.paginationCurrentPage = Math.min(
    +                      grid.options.paginationCurrentPage + 1,
    +                      publicApi.methods.pagination.getTotalPages()
    +                    );
    +                  } else {
    +                    grid.options.paginationCurrentPage++;
    +                  }
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name previousPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the previous page, if we're not on the first page
    +                 */
    +                previousPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.max(grid.options.paginationCurrentPage - 1, 1);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name seek
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the requested page
    +                 * @param {int} page The number of the page that should be displayed
    +                 */
    +                seek: function (page) {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +                  if (!angular.isNumber(page) || page < 1) {
    +                    throw 'Invalid page number: ' + page;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.min(page, publicApi.methods.pagination.getTotalPages());
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPagination || !grid.options.enablePagination) {
    +              return renderableRows;
    +            }
    +            //client side pagination
    +            var pageSize = parseInt(grid.options.paginationPageSize, 10);
    +            var currentPage = parseInt(grid.options.paginationCurrentPage, 10);
    +            
    +            var visibleRows = renderableRows.filter(function (row) { return row.visible; });
    +            grid.options.totalItems = visibleRows.length;
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            if (firstRow > visibleRows.length) {
    +              currentPage = grid.options.paginationCurrentPage = 1;
    +              firstRow = (currentPage - 1) * pageSize;
    +            }
    +            return visibleRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.pagination.api:GridOptions
    +           *
    +           * @description GridOptions for the pagination feature, these are available to be
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @name enablePagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables pagination, defaults to true
    +           */
    +          gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +          /**
    +           * @ngdoc property
    +           * @name enablePaginationControls
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +           *              own controls outside the grid.
    +           */
    +          gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Disables client side pagination. When true, handle the paginationChanged event and set data
    +           *              and totalItems, defaults to `false`
    +           */
    +          gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Total number of items, set automatically when client side pagination, needs set by user
    +           *              for server side pagination
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSizes
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Array of page sizes, defaults to `[250, 500, 1000]`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSizes)) {
    +            gridOptions.paginationPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSize
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSize)) {
    +            if (gridOptions.paginationPageSizes.length > 0) {
    +              gridOptions.paginationPageSize = gridOptions.paginationPageSizes[0];
    +            } else {              
    +              gridOptions.paginationPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationCurrentPage
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Current page number, defaults to 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationCurrentPage)) {
    +            gridOptions.paginationCurrentPage = 1;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name paginationTemplate
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description A custom template for the pager, defaults to `ui-grid/pagination`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationTemplate)) {
    +            gridOptions.paginationTemplate = 'ui-grid/pagination';
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @name uiGridPaginationService
    +         * @description  Raises paginationChanged and calls refresh for client side pagination
    +         * @param {Grid} grid the grid for which the pagination changed
    +         * @param {int} currentPage requested page number
    +         * @param {int} pageSize requested page size
    +         */
    +        onPaginationChanged: function (grid, currentPage, pageSize) {
    +            grid.api.pagination.raise.paginationChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPagination) {
    +              grid.refresh(); //client side pagination
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPagination
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds pagination features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        paginationPageSizes: [5, 10, 25],
    +        paginationPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-pagination></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPagination', ['gridUtil', 'uiGridPaginationService',
    +    function (gridUtil, uiGridPaginationService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        link: {
    +          pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +            uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +
    +            gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                $elm.append(template);
    +                uiGridCtrl.innerCompile(template);
    +              });
    +          }
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling pagination
    +   */
    +  module.directive('uiGridPager', ['uiGridPaginationService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPaginationService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +          $scope.paginationApi = uiGridCtrl.grid.api.pagination;
    +          $scope.sizesLabel = i18nService.getSafeText('pagination.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('pagination.totalItems');
    +          
    +          var options = uiGridCtrl.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          var dataChangeDereg = uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPagination) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +          
    +          $scope.$on('$destroy', dataChangeDereg);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.paginationCurrentPage - 1) * options.paginationPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.paginationCurrentPage * options.paginationPageSize, options.totalItems);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.paginationPageSize', setShowing);
    +
    +          var deregP = $scope.$watch('grid.options.paginationCurrentPage + grid.options.paginationPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.paginationCurrentPage) || options.paginationCurrentPage < 1) {
    +                options.paginationCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.paginationCurrentPage > $scope.paginationApi.getTotalPages()) {
    +                options.paginationCurrentPage = $scope.paginationApi.getTotalPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPaginationService.onPaginationChanged($scope.grid, options.paginationCurrentPage, options.paginationPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.paginationCurrentPage >= $scope.paginationApi.getTotalPages();
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.paginationCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        },
    +        
    +        // get either this column, or the column next to this column, to resize,
    +        // returns the column we're going to resize
    +        findTargetCol: function(col, position, rtlMultiplier){
    +          var renderContainer = col.getRenderContainer();
    +
    +          if (position === 'left') {
    +            // Get the column to the left of this one
    +            var colIndex = renderContainer.visibleColumnCache.indexOf(col);          
    +            return renderContainer.visibleColumnCache[colIndex - 1 * rtlMultiplier];
    +          } else {
    +            return col;
    +          }
    +        }
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', 'uiGridResizeColumnsService', 'uiGridConstants', '$timeout', function (gridUtil, $templateCache, $compile, $q, uiGridResizeColumnsService, uiGridConstants, $timeout) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var grid = uiGridCtrl.grid;
    +
    +            if (grid.options.enableColumnResizing) {
    +              var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +    
    +              var rtlMultiplier = 1;
    +              //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +              if (grid.isRTL()) {
    +                $scope.position = 'left';
    +                rtlMultiplier = -1;
    +              }
    +
    +              var displayResizers = function(){
    +                
    +                // remove any existing resizers.  
    +                var resizers = $elm[0].getElementsByClassName('ui-grid-column-resizer');
    +                for ( var i = 0; i < resizers.length; i++ ){
    +                  angular.element(resizers[i]).remove();
    +                } 
    +                
    +                // get the target column for the left resizer
    +                var otherCol = uiGridResizeColumnsService.findTargetCol($scope.col, 'left', rtlMultiplier);
    +                var renderContainer = $scope.col.getRenderContainer();
    +              
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  var resizerLeft = angular.element(columnResizerElm).clone();
    +                  resizerLeft.attr('position', 'left');
    +
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  var resizerRight = angular.element(columnResizerElm).clone();
    +                  resizerRight.attr('position', 'right');
    +
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              };
    +
    +              displayResizers();
    +              
    +              var waitDisplay = function(){
    +                $timeout(displayResizers);
    +              };
    +              
    +              var dataChangeDereg = grid.registerDataChangeCallback( waitDisplay, [uiGridConstants.dataChange.COLUMN] );
    +              
    +              $scope.$on( '$destroy', dataChangeDereg );
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var downEvent, upEvent, moveEvent;
    +
    +    if (gridUtil.isTouchEnabled()) {
    +      downEvent = 'touchstart';
    +      upEvent = 'touchend';
    +      moveEvent = 'touchmove';
    +    }
    +    else {
    +      downEvent = 'mousedown';
    +      upEvent = 'mouseup';
    +      moveEvent = 'mousemove';
    +    }
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true).then( function() {
    +                uiGridCtrl.grid.refresh();
    +              });
    +            });
    +        }
    +
    +        // Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
    +        // Returns the new recommended with, after constraints applied
    +        function constrainWidth(col, width){
    +          var newWidth = width;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          return newWidth;
    +        }
    +        
    +        
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          x = x + ( constrainWidth(col, newWidth) - newWidth ) * rtlMultiplier;
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +        
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off(upEvent, mouseup);
    +            $document.off(moveEvent, mousemove);
    +            return;
    +          }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, newWidth);
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off(upEvent, mouseup);
    +          $document.off(moveEvent, mousemove);
    +        }
    +
    +
    +        $elm.on(downEvent, function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on(upEvent, mouseup);
    +          $document.on(moveEvent, mousemove);
    +        });
    +
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, maxWidth);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off(downEvent);
    +          $elm.off('dblclick');
    +          $document.off(moveEvent, mousemove);
    +          $document.off(upEvent, mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function ( rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function () {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function () {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function () {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function ( dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty( myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.saveState
    +   * @description
    +   *
    +   *  # ui.grid.saveState
    +   * This module provides the ability to save the grid state, and restore
    +   * it when the user returns to the page.  
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate. Usually the navigate events would be used to save
    +   * the grid state and restore it.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.save-state"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.saveState', ['ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.saveState.constant:uiGridSaveStateConstants
    +   *
    +   *  @description constants available in save state module
    +   */
    +
    +  module.constant('uiGridSaveStateConstants', {
    +    featureName: 'saveState'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.saveState.service:uiGridSaveStateService
    +   *
    +   *  @description Services for saveState feature
    +   */
    +  module.service('uiGridSaveStateService', ['$q', 'uiGridSaveStateConstants', 'gridUtil', '$compile', '$interval', 'uiGridConstants',
    +    function ($q, uiGridSaveStateConstants, gridUtil, $compile, $interval, uiGridConstants ) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.saveState = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.saveState.api:PublicApi
    +           *
    +           *  @description Public Api for saveState feature
    +           */
    +          var publicApi = {
    +            events: {
    +              saveState: {
    +              }
    +            },
    +            methods: {
    +              saveState: {
    +                /**
    +                 * @ngdoc function
    +                 * @name save
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Packages the current state of the grid into 
    +                 * an object, and provides it to the user for saving
    +                 * @returns {object} the state as a javascript object that can be saved
    +                 */
    +                save: function () {
    +                  return service.save(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name restore
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Restores the provided state into the grid
    +                 * @param {scope} $scope a scope that we can broadcast on
    +                 * @param {object} state the state that should be restored into the grid
    +                 */
    +                restore: function ( $scope, state) {
    +                  service.restore(grid, $scope, state);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.saveState.api:GridOptions
    +           *
    +           * @description GridOptions for saveState feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveWidths
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column widths.  Note that unless
    +           * you've provided the user with some way to resize their columns (say
    +           * the resize columns feature), then this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveWidths = gridOptions.saveWidths !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveOrder
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column order.  Note that unless
    +           * you've provided the user with some way to reorder their columns (for
    +           * example the move columns feature), this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveOrder = gridOptions.saveOrder !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveScroll
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current scroll position.  Note that this
    +           * is saved as the percentage of the grid scrolled - so if your
    +           * user returns to a grid with a significantly different number of 
    +           * rows (perhaps some data has been deleted) then the scroll won't 
    +           * actually show the same rows as before.  If you want to scroll to
    +           * a specific row then you should instead use the saveFocus option, which
    +           * is the default.
    +           * 
    +           * Note that this element will only be saved if the cellNav feature is
    +           * enabled
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.saveScroll = gridOptions.saveScroll === true;
    +          /**
    +           * @ngdoc object
    +           * @name saveFocus
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current focused cell.  On returning
    +           * to this focused cell we'll also scroll.  This option is
    +           * preferred to the saveScroll option, so is set to true by
    +           * default.  If saveScroll is set to true then this option will 
    +           * be disabled.  
    +           * 
    +           * By default this option saves the current row number and column 
    +           * number, and returns to that row and column.  However, if you define
    +           * a saveRowIdentity function, then it will return you to the currently 
    +           * selected column within that row (in a business sense - so if some
    +           * rows have been deleted, it will still find the same data, presuming it 
    +           * still exists in the list.  If it isn't in the list then it will instead
    +           * return to the same row number - i.e. scroll percentage)
    +           * 
    +           * Note that this option will do nothing if the cellNav
    +           * feature is not enabled.
    +           * 
    +           * <br/>Defaults to true (unless saveScroll is true)
    +           */
    +          gridOptions.saveFocus = gridOptions.saveScroll !== true && gridOptions.saveFocus !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveRowIdentity
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description A function that can be called, passing in a rowEntity, 
    +           * and that will return a unique id for that row.  This might simply 
    +           * return the `id` field from that row (if you have one), or it might
    +           * concatenate some fields within the row to make a unique value.
    +           * 
    +           * This value will be used to find the same row again and set the focus 
    +           * to it, if it exists when we return.
    +           * 
    +           * <br/>Defaults to undefined
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveVisible
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save whether or not columns are visible.
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveVisible = gridOptions.saveVisible !== false;          
    +          /**
    +           * @ngdoc object
    +           * @name saveSort
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current sort state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSort = gridOptions.saveSort !== false;         
    +          /**
    +           * @ngdoc object
    +           * @name saveFilter
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current filter state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveFilter = gridOptions.saveFilter !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveSelection
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the currently selected rows.  If the `saveRowIdentity` callback
    +           * is defined, then it will save the id of the row and select that.  If not, then
    +           * it will attempt to select the rows by row number, which will give the wrong results
    +           * if the data set has changed in the mean-time.
    +           * 
    +           * Note that this option only does anything
    +           * if the selection feature is enabled.  
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSelection = gridOptions.saveSelection !== false;          
    +        },
    +
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name save
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the current grid state into an object, and
    +         * passes that object back to the caller
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the state ready to be saved
    +         */
    +        save: function (grid) {
    +          var savedState = {};
    +          
    +          savedState.columns = service.saveColumns( grid );
    +          savedState.scrollFocus = service.saveScrollFocus( grid );
    +          savedState.selection = service.saveSelection( grid );
    +          
    +          return savedState;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restore
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Applies the provided state to the grid
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} state the state we'd like to restore
    +         */
    +        restore: function( grid, $scope, state ){
    +          if ( state.columns ) {
    +            service.restoreColumns( grid, state.columns );
    +          }
    +          
    +          if ( state.scrollFocus ){
    +            service.restoreScrollFocus( grid, $scope, state.scrollFocus );
    +          }
    +          
    +          if ( state.selection ){
    +            service.restoreSelection( grid, state.selection );
    +          }
    +          
    +          grid.refresh();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name saveColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the column setup, including sort, filters, ordering
    +         * and column widths.
    +         * 
    +         * Works through the current columns, storing them in order.  Stores the
    +         * column name, then the visible flag, width, sort and filters for each column.
    +         *
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {array} the columns state ready to be saved
    +         */
    +        saveColumns: function( grid ) {
    +          var columns = [];
    +          angular.forEach( grid.columns, function( column ) {
    +            var savedColumn = {};
    +            savedColumn.name = column.name;
    +            savedColumn.visible = column.visible;
    +            savedColumn.width = column.width;
    +            
    +            // these two must be copied, not just pointed too - otherwise our saved state is pointing to the same object as current state
    +            savedColumn.sort = angular.copy( column.sort );
    +            savedColumn.filters = angular.copy ( column.filters );
    +            columns.push( savedColumn );
    +          });
    +          
    +          return columns;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently scroll or focus.
    +         * 
    +         * If cellNav isn't present then does nothing - we can't return
    +         * to the scroll position without cellNav anyway.
    +         * 
    +         * If the cellNav module is present, and saveFocus is true, then
    +         * it saves the currently focused cell.  If rowIdentity is present
    +         * then saves using rowIdentity, otherwise saves visibleRowNum.
    +         * 
    +         * If the cellNav module is not present, and saveScroll is true, then
    +         * it approximates the current scroll row and column, and saves that.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveScrollFocus: function( grid ){
    +          if ( !grid.api.cellNav ){
    +            return {};
    +          }
    +          
    +          var scrollFocus = {};
    +          if ( grid.options.saveFocus ){
    +            scrollFocus.focus = true;
    +            var rowCol = grid.api.cellNav.getFocusedCell();
    +            if ( rowCol !== null ) {
    +              scrollFocus.colName = rowCol.col.colDef.name;
    +              scrollFocus.rowVal = service.getRowVal( grid, rowCol.row );
    +            }
    +          } else if ( grid.options.saveScroll ) {
    +            scrollFocus.focus = false;
    +            if ( grid.renderContainers.body.prevRowScrollIndex ){
    +              scrollFocus.rowVal = service.getRowVal( grid, grid.renderContainers.body.visibleRowCache[ grid.renderContainers.body.prevRowScrollIndex ]);
    +            }
    +            
    +            if ( grid.renderContainers.body.prevColScrollIndex ){
    +              scrollFocus.colName = grid.renderContainers.body.visibleColumnCache[ grid.renderContainers.body.prevColScrollIndex ].name;
    +            }
    +          }        
    +          
    +          return scrollFocus;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently selected rows, if the selection feature is enabled
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveSelection: function( grid ){
    +          if ( !grid.api.selection ){
    +            return {};
    +          }
    +          
    +          var selection = grid.api.selection.getSelectedGridRows().map( function( gridRow ) {
    +            return service.getRowVal( grid, gridRow );
    +          });
    +          
    +          return selection;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getRowVal
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Helper function that gets either the rowNum or
    +         * the saveRowIdentity, given a gridRow 
    +         * @param {Grid} grid the grid the row is in
    +         * @param {GridRow} gridRow the row we want the rowNum for
    +         * @returns {object} an object containing { identity: true/false, row: rowNumber/rowIdentity }
    +         * 
    +         */
    +        getRowVal: function( grid, gridRow ){
    +          if ( !gridRow ) {
    +            return null;
    +          }
    +          
    +          var rowVal = {};
    +          if ( grid.options.saveRowIdentity ){
    +            rowVal.identity = true;
    +            rowVal.row = grid.options.saveRowIdentity( gridRow.entity );
    +          } else {
    +            rowVal.identity = false;
    +            rowVal.row = grid.renderContainers.body.visibleRowCache.indexOf( gridRow );
    +          }
    +          return rowVal;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restoreColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Restores the columns, including order, visible, width
    +         * sort and filters.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} columnsState the list of columns we had before, with their state
    +         */
    +        restoreColumns: function( grid, columnsState ){
    +          angular.forEach( columnsState, function( columnState, index ) {
    +            var currentCol = grid.columns.filter( function( column ) {
    +              return column.name === columnState.name;
    +            });
    +            
    +            if ( currentCol.length > 0 ){
    +              var currentIndex = grid.columns.indexOf( currentCol[0] );
    +              
    +              if ( grid.columns[currentIndex].visible !== columnState.visible ||
    +                   grid.columns[currentIndex].colDef.visible !== columnState.visible ){
    +                grid.columns[currentIndex].visible = columnState.visible;
    +                grid.columns[currentIndex].colDef.visible = columnState.visible;
    +                grid.api.core.raise.columnVisibilityChanged( grid.columns[currentIndex]);
    +              }
    +              
    +              grid.columns[currentIndex].width = columnState.width;
    +
    +              if ( !angular.equals(grid.columns[currentIndex].sort, columnState.sort && 
    +                   !( grid.columns[currentIndex].sort === undefined && angular.isEmpty(columnState.sort) ) ) ){
    +                grid.columns[currentIndex].sort = angular.copy( columnState.sort );
    +                grid.api.core.raise.sortChanged();
    +              }
    +
    +              if ( !angular.equals(grid.columns[currentIndex].filters, columnState.filters ) ){
    +                grid.columns[currentIndex].filters = angular.copy( columnState.filters );
    +                grid.api.core.raise.filterChanged();
    +              }
    +              
    +              if ( currentIndex !== index ){
    +                var column = grid.columns.splice( currentIndex, 1 )[0];
    +                grid.columns.splice( index, 0, column );
    +              }
    +            }
    +          });
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Scrolls to the position that was saved.  If focus is true, then
    +         * sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +         * specified row/col.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} scrollFocusState the scroll/focus state ready to be restored
    +         */
    +        restoreScrollFocus: function( grid, $scope, scrollFocusState ){
    +          if ( !grid.api.cellNav ){
    +            return;
    +          }
    +          
    +          var colDef, row;
    +          if ( scrollFocusState.colName ){
    +            var colDefs = grid.options.columnDefs.filter( function( colDef ) { return colDef.name === scrollFocusState.colName; });
    +            if ( colDefs.length > 0 ){
    +              colDef = colDefs[0];
    +            }
    +          }
    +          
    +          if ( scrollFocusState.rowVal && scrollFocusState.rowVal.row ){
    +            if ( scrollFocusState.rowVal.identity ){
    +              row = service.findRowByIdentity( grid, scrollFocusState.rowVal );
    +            } else {
    +              row = grid.renderContainers.body.visibleRowCache[ scrollFocusState.rowVal.row ];
    +            }
    +          }
    +          
    +          var entity = row && row.entity ? row.entity : null ;
    +
    +          if ( colDef || entity ) {          
    +            if (scrollFocusState.focus ){
    +              grid.api.cellNav.scrollToFocus( $scope, entity, colDef );
    +            } else {
    +              grid.api.cellNav.scrollTo( $scope, entity, colDef );
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Selects the rows that are provided in the selection
    +         * state.  If you are using `saveRowIdentity` and more than one row matches the identity
    +         * function then only the first is selected.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} selectionState the selection state ready to be restored
    +         */
    +        restoreSelection: function( grid, selectionState ){
    +          if ( !grid.api.selection ){
    +            return;
    +          }
    +          
    +          grid.api.selection.clearSelectedRows();
    +
    +          angular.forEach( selectionState, function( rowVal ) {
    +            if ( rowVal.identity ){
    +              var foundRow = service.findRowByIdentity( grid, rowVal );
    +              
    +              if ( foundRow ){
    +                grid.api.selection.selectRow( foundRow.entity );
    +              }
    +              
    +            } else {
    +              grid.api.selection.selectRowByVisibleIndex( rowVal.row );
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name findRowByIdentity
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Finds a row given it's identity value, returns the first found row
    +         * if any are found, otherwise returns null if no rows are found.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} rowVal the row we'd like to find
    +         * @returns {gridRow} the found row, or null if none found
    +         */
    +        findRowByIdentity: function( grid, rowVal ){
    +          if ( !grid.options.saveRowIdentity ){
    +            return null;
    +          }
    +          
    +          var filteredRows = grid.rows.filter( function( gridRow ) {
    +            if ( grid.options.saveRowIdentity( gridRow.entity ) === rowVal.row ){
    +              return true;
    +            } else {
    +              return false;
    +            }
    +          });
    +          
    +          if ( filteredRows.length > 0 ){
    +            return filteredRows[0];
    +          } else {
    +            return null;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.saveState.directive:uiGridSaveState
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds saveState features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-save-state></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSaveState', ['uiGridSaveStateConstants', 'uiGridSaveStateService', 'gridUtil', '$compile',
    +    function (uiGridSaveStateConstants, uiGridSaveStateService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridSaveStateService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  //add methods to GridRow
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('GridRow', ['$delegate', function($delegate) {
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.selection.api:GridRow
    +       *
    +       *  @description GridRow prototype functions added for selection
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name enableSelection
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Enable row selection for this row, only settable by internal code.
    +       *
    +       *  The grouping feature, for example, might set group header rows to not be selectable.
    +       *  <br/>Defaults to true
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name isSelected
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +       *  <br/>Defaults to false
    +       */
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name setSelected
    +         * @methodOf ui.grid.selection.api:GridRow
    +         * @description Sets the isSelected property and updates the selectedCount
    +         * Changes to isSelected state should only be made via this function
    +         * @param {bool} selelected value to set
    +         */
    +        $delegate.prototype.setSelected = function(selected) {
    +          this.isSelected = selected;
    +          if (selected) {
    +            this.grid.selection.selectedCount++;
    +          }
    +          else {
    +            this.grid.selection.selectedCount--;
    +          }
    +        };
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.grid:selection
    +           *
    +           *  @description Grid properties and functions added for selection
    +           */
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name selectedCount
    +           *  @propertyOf  ui.grid.selection.grid:selection
    +           *  @description Current count of selected rows
    +           *  @example
    +           *  var count = grid.selection.selectedCount
    +           */
    +          grid.selection.selectedCount = 0;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChanged: function (scope, row, evt) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows, evt) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                toggleRowSelection: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum, evt ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && typeof(row) !== 'undefined' && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                unSelectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected && row.enableSelection !== false ){
    +                      row.setSelected(true);
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllVisibleRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected && row.enableSelection !== false){
    +                        row.setSelected(true);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.setSelected(false);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                clearSelectedRows: function (evt) {
    +                  service.clearSelectedRows(grid, evt);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableFooterTotalSelected
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Shows the total number of selected items in footer if true.
    +           *  <br/>Defaults to true.
    +           *  <br/>GridOptions.showFooter must also be set to true.
    +           */
    +          gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name isRowSelectable
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.
    +           */
    +
    +          gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {Event} event object if resulting from event
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid, evt);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid, evt);
    +            }
    +          }
    +
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else if (row.enableSelection !== false) {
    +            row.setSelected(!selected);
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            } else {
    +              grid.selection.selectAll = false;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {Event} event object if raised from an event
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, evt, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected && rowToSelect.enableSelection !== false ){
    +                rowToSelect.setSelected(true);
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows, evt );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         * @param {Event} event object if raised from an event
    +         */
    +        clearSelectedRows: function (grid, evt) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.setSelected(false);
    +              service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +          grid.selection.selectAll = false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * @param {Event} event object if raised from an event
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows, evt ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * @param {Event} event object if raised from an event
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows, evt ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows, evt);
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  minWidth: 10,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false,
    +                  exporterSuppressExport: true 
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +              
    +              if (uiGridCtrl.grid.options.isRowSelectable !== angular.noop) {
    +                uiGridCtrl.grid.registerRowBuilder(function(row, options) {
    +                  row.enableSelection = uiGridCtrl.grid.options.isRowSelectable(row);
    +                });
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self, evt);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0, evt);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows(evt);
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            var touchStartTime = 0;
    +            var touchTimeout = 300;
    +            var selectCells = function(evt){
    +              if (evt.shiftKey) {
    +                uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect);
    +              }
    +              else if (evt.ctrlKey || evt.metaKey) {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +              }
    +              else {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +              }
    +              $scope.$apply();
    +            };
    +
    +            var touchStart = function(evt){
    +              touchStartTime = (new Date()).getTime();
    +            };
    +
    +            var touchEnd = function(evt) {
    +              var touchEndTime = (new Date()).getTime();
    +              var touchTime = touchEndTime - touchStartTime;
    +
    +              if (touchTime < touchTimeout ) {
    +                // short touch
    +                selectCells(evt);
    +              }
    +            };
    +
    +            function registerRowSelectionEvents() {
    +              if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +                $elm.addClass('ui-grid-disable-selection');
    +                $elm.on('touchstart', touchStart);
    +                $elm.on('touchend', touchEnd);
    +                $elm.on('click', selectCells);
    +
    +                $scope.registered = true;
    +              }
    +            }
    +
    +            function deregisterRowSelectionEvents() {
    +              if ($scope.registered){
    +                $elm.removeClass('ui-grid-disable-selection');
    +
    +                $elm.off('touchstart', touchStart);
    +                $elm.off('touchend', touchEnd);
    +                $elm.off('click', selectCells);
    +
    +                $scope.registered = false;
    +              }
    +            }
    +
    +            registerRowSelectionEvents();
    +            // register a dataChange callback so that we can change the selection configuration dynamically
    +            // if the user changes the options
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( function() {
    +              if ( $scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection &&
    +                !$scope.registered ){
    +                registerRowSelectionEvents();
    +              } else if ( ( !$scope.grid.options.enableRowSelection || $scope.grid.options.enableRowHeaderSelection ) &&
    +                $scope.registered ){
    +                deregisterRowSelectionEvents();
    +              }
    +            }, [uiGridConstants.dataChange.OPTIONS] );
    +
    +            $elm.on( '$destroy', dataChangeDereg);
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridGridFooter', ['$compile', 'uiGridConstants', 'gridUtil', function ($compile, uiGridConstants, gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      priority: -1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            if (!uiGridCtrl.grid.options.showGridFooter) {
    +              return;
    +            }
    +
    +
    +            gridUtil.getTemplate('ui-grid/gridFooterSelectedItems')
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +
    +                angular.element($elm[0].getElementsByClassName('ui-grid-grid-footer')[0]).append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\"><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-grid-footer',
    +    "<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{'search.totalItems' | t}} {{grid.rows.length}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    /*\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "    */\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\"></div><div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\" ng-style=\"containerCtrl.colContainer.getViewPortStyle()\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth()) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableTopRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !grid.expandable.expandedAll, 'ui-grid-icon-minus-squared' : grid.expandable.expandedAll }\" ng-click=\"grid.api.expandable.toggleAllRows()\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\" download=\"FILE_NAME\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/pagination',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager ng-show=\"grid.options.enablePaginationControls\"><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"paginationApi.seek(1)\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"paginationApi.previousPage()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.paginationCurrentPage\" min=\"1\" max=\"{{ paginationApi.getTotalPages() }}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"paginationApi.getTotalPages() > 0\">/ {{ paginationApi.getTotalPages() }}</span> <button type=\"button\" ng-click=\"paginationApi.nextPage()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"paginationApi.seek(paginationApi.getTotalPages())\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.paginationPageSize\" ng-options=\"o as o for o in grid.options.paginationPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/gridFooterSelectedItems',
    +    "<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"search.selectedItems\" | t}} {{grid.selection.selectedCount}})</span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.19/ui-grid.min.css b/release/3.0.0-rc.19/ui-grid.min.css
    new file mode 100644
    index 000000000..1560212e1
    --- /dev/null
    +++ b/release/3.0.0-rc.19/ui-grid.min.css
    @@ -0,0 +1,4 @@
    +/*!
    + * ui-grid - v3.0.0-rc.19 - 2015-02-11
    + * Copyright (c) 2015 ; License: MIT 
    + */.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;box-sizing:border-box;float:left;top:0;bottom:0;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu-button-last-col{margin-right:25px}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative;overflow-y:scroll;-webkit-overflow-scrolling:touch}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative;padding-top:1px}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#f0f0ee !important;border-bottom:solid 1px #d4d4d4}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-grid-footer{float:left;width:100%}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid{overflow-y:scroll;max-height:300px;border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child,.ui-grid[dir=rtl] .ui-grid-header-cell:last-child{border-left:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}.ui-grid-row-selected>[ui-grid-row]>.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.19/ui-grid.min.js b/release/3.0.0-rc.19/ui-grid.min.js
    new file mode 100644
    index 000000000..89ce3718e
    --- /dev/null
    +++ b/release/3.0.0-rc.19/ui-grid.min.js
    @@ -0,0 +1,12 @@
    +/*!
    + * ui-grid - v3.0.0-rc.19 - 2015-02-11
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart",COLUMN_HEADER_CLICK:"uiGridColumnHeaderClick"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,PG_UP:33,PG_DOWN:34,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],scrollDirection:{UP:"up",DOWN:"down",LEFT:"left",RIGHT:"right",NONE:"none"},dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column",OPTIONS:"options"},scrollbars:{NEVER:0,ALWAYS:1}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){var c=a.col.getColClass(!1);b.addClass(c);var e,f=function(){var c=b;e&&(c.removeClass(e),e=null),e=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,c.addClass(e)};a.col.cellClass&&f();var g=a.grid.registerDataChangeCallback(f,[d.dataChange.COLUMN,d.dataChange.EDIT]),h=function(d,g){if(d!==g){(e||a.col.cellClass)&&f();var h=a.col.getColClass(!1);h!==c&&(b.removeClass(c),b.addClass(h),c=h)}},i=a.$watch("col",h),j=a.$watch("row",h),k=function(){g(),i(),j()};a.$on("$destroy",k),b.on("$destroy",k)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,e,f,g){var h=this;d.initialize(b,g),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,c,f){b.col=a;var g=d.getColumnElementPosition(b,a,c);b.menuShown?(b.colElement=c,b.colElementPosition=g,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(h.shown=b.menuShown=!0,d.repositionMenu(b,a,g,e,c),b.colElement=c,b.colElementPosition=g,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu(),b.grid.api.core.notifyDataChange(c.dataChange.COLUMN),b.grid.api.core.raise.columnVisibilityChanged(b.col)}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",h)}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-grid-footer";return{restrict:"EA",replace:!0,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(a,c,f,g){a.grid=g.grid;var h=a.grid.options.gridFooterTemplate?a.grid.options.gridFooterTemplate:e;d.getTemplate(h).then(function(d){var e=angular.element(d),f=b(e)(a);c.append(f)})},post:function(){}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,i){function j(b){var c=!1;b.shiftKey&&(c=!0),k.grid.sortColumn(a.col,c).then(function(){k.columnMenuScope&&k.columnMenuScope.hideMenu(),k.grid.refresh()})}var k=i[0],l=i[1];a.grid=k.grid,a.renderContainer=k.grid.renderContainers[l.containerId];var m=a.col.getColClass(!1);c.addClass(m),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var n,o=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),p=function(){var b=c;n&&(b.removeClass(n),n=null),n=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(n);var d=a.grid.renderContainers.right?a.grid.renderContainers.right:a.grid.renderContainers.body;a.isLastCol=a.col===d.visibleColumnCache[d.visibleColumnCache.length-1]};a.$watch("col",function(b,d){if(b!==d){var e=a.col.getColClass(!1);e!==m&&(c.removeClass(m),c.addClass(e),m=e)}}),p();var q=a.grid.registerDataChangeCallback(p,[f.dataChange.COLUMN]);if(a.$on("$destroy",q),a.sortable=k.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=k.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var r,s=0,t=e.isTouchEnabled()?"touchstart":"mousedown";o.on(t,function(d){d.stopPropagation(),"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(s=(new Date).getTime(),r=b(function(){},h),r.then(function(){a.colMenu&&k.columnMenuScope.showMenu(a.col,c,d)}),k.fireEvent(f.events.COLUMN_HEADER_CLICK,{event:d,columnName:a.col.colDef.name}))});var u=e.isTouchEnabled()?"touchend":"mouseup";o.on(u,function(){b.cancel(r)}),a.$on("$destroy",function(){o.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),k.columnMenuScope.menuShown&&k.columnMenuScope.col===a.col?k.columnMenuScope.hideMenu():k.columnMenuScope.showMenu(a.col,c)},a.sortable){var v=e.isTouchEnabled()?"touchend":"click";o.on(v,function(a){a.stopPropagation(),b.cancel(r);var c=(new Date).getTime(),d=c-s;d>h||j(a)}),a.$on("$destroy",function(){b.cancel(r)})}if(a.filterable){var w=[];angular.forEach(a.col.filters,function(b,c){w.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(k.grid.api.core.raise.filterChanged(),k.grid.refresh().then(function(){if(k.prevScrollArgs&&k.prevScrollArgs.y&&k.prevScrollArgs.y.percentage){var a=new g(k.grid,null,null,"uiGridHeaderCell.toggleMenu");a.y.percentage=k.prevScrollArgs.y.percentage,a.fireScrollingEvent()}}))}))}),a.$on("$destroy",function(){angular.forEach(w,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=c,j.colContainer.header=c;var k;k=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(k).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),j.header=f,j.colContainer.header=f,c=f,j){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth(),b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,g=a,i=!1,j=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(g/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",i=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,i=!0)});var k=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return k.indexOf(a.widthType)-k.indexOf(b.widthType)}).forEach(function(a){var b=j(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,g-=a.drawnWidth}),i&&g>0&&c>0&&a>c){var l=function(a){g>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,g--)},m=0;do m=g,b.forEach(l);while(g>0&&g!==m)}c=Math.max(c,a);var n="";return b.forEach(function(a){n+=a.getColClassDefinition()}),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),n}{var g=e[0],h=e[1];g.grid}d.disableAnimations(b),h.header=b;var i=b[0].getElementsByClassName("ui-grid-header-viewport")[0];i&&(h.headerViewport=i),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService","uiGridConstants",function(a,b,c){var d={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",d.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",d.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var c=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?c=c.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),c=c.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(c=c.concat(d.showHideColumns(b))),c},showHideColumns:function(a){var c=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(c.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};d.setMenuItemTitle(e,b,a.grid),c.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},d.setMenuItemTitle(e,b,a.grid),c.push(e)}}),c):c},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh(),a.grid.api.core.notifyDataChange(c.dataChange.COLUMN),a.grid.api.core.raise.columnVisibilityChanged(a)}};return d}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d,e,g){var h=this;h.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var e="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(e=d.originalEvent.type),angular.element(document).off("click touchstart",i),b(function(){angular.element(document).on(e,i)})},h.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",i)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var i=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",i),a.$on("$destroy",function(){angular.element(document).off("click touchstart",i)}),a.$on("$destroy",function(){angular.element(c).off("resize",i)}),g&&a.$on("$destroy",g.grid.api.core.on.scrollEvent(a,i)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,i))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil","ScrollEvent",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(a,c,f,g){function h(b){if(!b.grid||b.grid.id===n.id){if(b.y&&a.bindScrollVertical){m.prevScrollArgs=b;var c=b.getNewScrollTop(o,m.viewport);(b.source!==e.Sources.ViewPortScroll||b.sourceColContainer!==p)&&(m.viewport[0].scrollTop=c)}if(b.x&&a.bindScrollHorizontal){m.prevScrollArgs=b;var f=b.getNewScrollLeft(p,m.viewport);a.newScrollLeft=f,m.headerViewport&&(m.headerViewport.scrollLeft=d.denormalizeScrollLeft(m.headerViewport,f)),m.footerViewport&&(m.footerViewport.scrollLeft=d.denormalizeScrollLeft(m.footerViewport,f)),b.source!==e.Sources.ViewPortScroll&&(m.viewport[0].scrollLeft=f),m.prevScrollLeft=f}}}function i(a){a.originalEvent&&(a=a.originalEvent);var b,c,d,f;d=a.targetTouches[0].screenX,f=a.targetTouches[0].screenY,b=-(d-t),c=-(f-s),w=1>c?-1:1,x=1>b?-1:1,c*=2,b*=2;var g=new e(n,o,p,e.Sources.RenderContainerTouchMove);if(0!==c){var h=(u+c)/o.getVerticalScrollLength();h>1?h=1:0>h&&(h=0),g.y={percentage:h,pixels:c}}if(0!==b){var i=(v+b)/(p.getCanvasWidth()-p.getViewportWidth());i>1?i=1:0>i&&(i=0),g.x={percentage:i,pixels:b}}(g.y&&0!==g.y.percentage&&1!==g.y.percentage||g.x&&0!==g.x.percentage&&1!==g.x.percentage)&&a.preventDefault(),g.fireScrollingEvent()}function j(a){a.originalEvent&&(a=a.originalEvent),b.unbind("touchmove",i),b.unbind("touchend",j),b.unbind("touchcancel",j);{var c=m.viewport[0].scrollTop,d=m.viewport[0].scrollTop;Math.abs(c-u),Math.abs(d-v),new Date-r}}function k(){var b="",c=p.getCanvasWidth(),d=p.getViewportWidth(),e=o.getCanvasHeight();"body"!==a.containerId&&(e+=n.scrollbarHeight);var f=o.getViewportHeight(),g=p.getHeaderViewportWidth(),h=p.getHeaderViewportWidth();return b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { width: "+(c+n.scrollbarWidth)+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-canvas { width: "+c+n.scrollbarWidth+"px; }",b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }",void 0!==q.explicitHeaderHeight&&null!==q.explicitHeaderHeight&&q.explicitHeaderHeight>0?b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.explicitHeaderHeight+"px; }":void 0!==q.innerHeaderHeight&&null!==q.innerHeaderHeight&&q.innerHeaderHeight>0&&(b+="\n .grid"+l.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-cell { height: "+q.innerHeaderHeight+"px; }"),b}var l=g[0],m=g[1],n=l.grid,o=m.rowContainer,p=m.colContainer,q=n.renderContainers[a.containerId];c.addClass("ui-grid-render-container-"+a.containerId),(a.bindScrollHorizontal||a.bindScrollVertical)&&n.api.core.on.scrollEvent(a,h),c.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){var b=d.normalizeWheelEvent(a),c=new e(n,o,p,e.Sources.RenderContainerMouseWheel);if(0!==b.deltaY){var f=-120*b.deltaY,g=(m.viewport[0].scrollTop+f)/o.getVerticalScrollLength();0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:f}}if(0!==b.deltaX){var h=-120*b.deltaX,i=d.normalizeScrollLeft(m.viewport),j=(i+h)/(p.getCanvasWidth()-p.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}(c.y&&0!==c.y.percentage&&1!==c.y.percentage&&0!==m.viewport[0].scrollTop||c.x&&0!==c.x.percentage&&1!==c.x.percentage)&&a.preventDefault(),c.fireThrottledScrollingEvent()});var r,s=0,t=0,u=0,v=0,w=1,x=1;d.isTouchEnabled()&&c.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),r=new Date,s=a.targetTouches[0].screenY,t=a.targetTouches[0].screenX,u=m.viewport[0].scrollTop,v=m.viewport[0].scrollLeft,b.on("touchmove",i),b.on("touchend touchcancel",j)}),c.bind("$destroy",function(){c.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){c.unbind(a)})}),l.grid.registerStyleComputation({priority:6,func:k})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){function e(){a.row.getRowTemplateFn.then(function(c){var d=a.$new();c(d,function(a){h&&(h.remove(),i.$destroy()),b.empty().append(a),h=a,i=d})})}{var f=d[0],g=d[1];f.grid}a.grid=f.grid,a.colContainer=g.colContainer;var h,i;e(),a.$watch("row.getRowTemplateFn",function(a,b){a!==b&&e()})},post:function(){}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil","ScrollEvent","uiGridConstants",function(a,b,c){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(d,e,f,g){var h=g[0],i=g[1];d.containerCtrl=i;var j=i.rowContainer,k=i.colContainer,l=h.grid;d.grid=h.grid,d.rowContainer=i.rowContainer,d.colContainer=i.colContainer,i.viewport=e,e.on("scroll",function(){var d=e[0].scrollTop,f=a.normalizeScrollLeft(e),g=-1,h=-1;if(f!==k.prevScrollLeft){l.flagScrollingHorizontally();var i=f-k.prevScrollLeft;i>0&&(l.scrollDirection=c.scrollDirection.RIGHT),0>i&&(l.scrollDirection=c.scrollDirection.LEFT);var m=k.getCanvasWidth()-k.getViewportWidth();g=0!==m?f/m:0,k.adjustScrollHorizontal(f,g)}if(d!==j.prevScrollTop){l.flagScrollingVertically();var n=d-j.prevScrollTop;n>0&&(l.scrollDirection=c.scrollDirection.DOWN),0>n&&(l.scrollDirection=c.scrollDirection.UP);var o=j.getVerticalScrollLength();h=d/o,h>1&&(h=1),0>h&&(h=0),j.adjustScrollVertical(d,h)}var p=new b(l,j,k,b.Sources.ViewPortScroll);p.newScrollLeft=f,p.newScrollTop=d,g>-1&&(p.x={percentage:g}),h>-1&&(p.y={percentage:h}),p.fireScrollingEvent()})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile","ScrollEvent",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(p.grid.options.columnDefs=a,p.grid.buildColumns({orderByColumnDefs:!0}).then(function(){p.grid.preCompileCellTemplates(),p.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function n(a){var b=new l(p.grid,null,null,"ui.grid.adjustInfiniteScrollPosition"),c=p.grid.renderContainers.body.visibleRowCache.length,d=(a+a/(c-1))/c;b.y=0===d?{pixels:1}:{percentage:d},b.fireScrollingEvent()}function o(b){var d=[];b&&(p.grid.columns.length===(p.grid.rowHeaderColumns?p.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===p.grid.options.columnDefs.length&&b.length>0&&p.grid.buildColumnDefsFromData(b),(p.grid.options.columnDefs.length>0||b.length>0)&&d.push(p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates()})),e.all(d).then(function(){p.grid.modifyRows(b).then(function(){p.grid.redrawInPlace(),a.$evalAsync(function(){p.grid.refreshCanvas(!0),p.grid.callDataChangeCallbacks(f.dataChange.ROW),i(function(){p.grid.options.enableInfiniteScroll&&(0===p.grid.renderContainers.body.prevRowScrollIndex&&n(0),p.grid.scrollDirection===f.scrollDirection.UP&&n(p.grid.renderContainers.body.prevRowScrollIndex+1+p.grid.options.excessRows))},0)})})}))}var p=this;p.grid=h.createGrid(a.uiGrid),p.grid.appScope=p.grid.appScope||a.$parent,b.addClass("grid"+p.grid.id),p.grid.rtl="rtl"===d.getStyles(b[0]).direction,a.grid=p.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){p.grid.options.columnDefs=a,p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates(),p.grid.refreshCanvas(!0)})});var q;q=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,o):a.$parent.$watchCollection(function(){return a.uiGrid.data},o);var r=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs
    +},m);a.$on("$destroy",function(){q(),r()}),a.$watch(function(){return p.grid.styleComputations},function(){p.grid.refreshCanvas(!0)}),p.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=p.grid),a.$broadcast(b,c)},p.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.refreshCanvas(!0)}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.calcFooterHeight(),m=0;i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas(),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];c+=e.drawnWidth||e.width||0}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0!==h&&h||e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.appScope=b.options.appScopeProvider,b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.calcFooterHeight(),b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE;var c=d.debounce(function(){b.isScrollingVertically=!1,b.scrollDirection=e.scrollDirection.NONE},1e3),g=d.debounce(function(){b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE},1e3);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.scrollbarHeight=0,b.scrollbarWidth=0,b.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarHeight=d.getScrollbarWidth()),b.options.enableVerticalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarWidth=d.getScrollbarWidth()),b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerEvent("core","columnVisibilityChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT]),b.registerStyleComputation({priority:10,func:b.getFooterStyles})};return o.prototype.calcFooterHeight=function(){if(!this.hasFooter())return 0;var a=0;return this.options.showGridFooter&&(a+=this.options.gridFooterHeight),this.options.showColumnFooter&&(a+=this.options.columnFooterHeight),a},o.prototype.getFooterStyles=function(){var a=".grid"+this.id+" .ui-grid-footer-aggregates-row { height: "+this.options.columnFooterHeight+"px; }";return a+=" .grid"+this.id+" .ui-grid-footer-info { height: "+this.options.gridFooterHeight+"px; }"},o.prototype.hasFooter=function(){return this.options.showGridFooter||this.options.showColumnFooter},o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b,c){var f=d.nextUid();b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[f]={callback:a,types:b,_this:c};var g=this,h=function(){delete g.dataChangeCallbacks[f]};return h},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&(b._this?b.callback.apply(b._this,this):b.callback(this))},this)},o.prototype.notifyDataChange=function(a){var b=e.dataChange;a===b.ALL||a===b.COLUMN||a===b.EDIT||a===b.ROW||a===b.OPTIONS?this.callDataChangeCallbacks(a):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+a)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.refresh()})})},o.prototype.buildColumns=function(b){var c={orderByColumnDefs:!1};angular.extend(c,b);var e,f=this,h=[],i=f.rowHeaderColumns.length;for(e=0;e<f.columns.length;e++)f.getColDef(f.columns[e].name)||(f.columns.splice(e,1),e--);if(f.rowHeaderColumns.forEach(function(a){f.columns.unshift(a)}),f.options.columnDefs.forEach(function(a,b){f.preprocessColDef(a);var c=f.getColumn(a.name);c?c.updateColumnDef(a,!1):(c=new g(a,d.nextUid(),f),f.columns.splice(b+i,0,c)),f.columnBuilders.forEach(function(b){h.push(b.call(f,a,c,f.options))})}),c.orderByColumnDefs){var j=f.columns.slice(0);for(e=0;e<f.options.columnDefs.length;e++)j[e+i]=f.columns[e+i].name!==f.options.columnDefs[e].name?f.getColumn(f.options.columnDefs[e].name):f.columns[e+i];f.columns.length=0,Array.prototype.splice.apply(f.columns,[0,0].concat(j))}return a.all(h).then(function(){f.rows.length>0&&f.assignTypes()})},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){var b=this;if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");if(void 0===a.name&&void 0!==a.field){var c=b.getColumn(a.field);if(c){var d=new RegExp("^"+a.field+"(\\d+)$","i"),e=b.columns.filter(function(a){return d.test(a.displayName)}).sort(function(a,b){if(a===b)return 0;var c=a.match(d)[1],e=b.match(d)[1];return parseInt(c,10)>parseInt(e,10)?1:-1});if(0===e.length)a.name=a.field+"2";else{var f=e[e.length-1].displayName.match(d)[1];f=parseInt(f,10),a.name=a.field+(f+1)}}else a.name=a.field}},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;{0===g.rows.length}for(g.rows.length=0,c=0;c<b.length;c++){var j=b[c];e=i.get(j),f=e?e.row:g.processRowBuilders(new h(j,c,g)),g.rows.push(f),d.put(j,{i:c,entity:j,row:f})}g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var k,l,m;if(g.options.enableRowHashing){k=[],m=[];var n={};for(l=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var o=!1;g.options.getRowIdentity(f)||(o=!0),e=d.get(f),e?e.row&&(n[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),o?m.push(f):k.push(f))}for(c=0;c<g.rows.length;c++){var p=g.rows[c],q=g.options.rowIdentity(p.entity);n[q]||l.push(p)}}var r=k||[],s=m||b;r=r.concat(g.newInN(g.rows,s,"entity")),g.addRows(r);var t=g.getDeletedRows(l||g.rows,b);for(c=0;c<t.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(t[c].entity),g.rows.splice(g.rows.indexOf(t[c]),1)}else g.createRowHashMap(),g.rows.length=0;var u=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),v=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([u,v])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.canvasHeightShouldUpdate=!0,"undefined"==typeof d.visibleRowCache?d.visibleRowCache=[]:d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}b.api.core.raise.rowsRendered(this.api)},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.updateCanvasHeight=function(){var a=this;for(var b in a.renderContainers)if(a.renderContainers.hasOwnProperty(b)){var c=a.renderContainers[b];c.canvasHeightShouldUpdate=!0}},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight,c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth,c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b===a||b.colDef.suppressRemoveSort||(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(){var b=this,c=b.processRowsProcessors(b.rows).then(function(a){b.setVisibleRows(a)}),d=b.processColumnsProcessors(b.columns).then(function(a){b.setVisibleColumns(a)});return a.all([c,d]).then(function(){b.redrawInPlace(),b.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;h.header&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)&&g.header){var j=g.headerHeight,k=d.outerElementHeight(g.header);g.headerHeight=parseInt(k,10),j!==k&&(h=!0);var l=d.getBorderSize(g.header,"top"),m=d.getBorderSize(g.header,"bottom"),n=parseInt(k-l-m,10);n=0>n?0:n,g.innerHeaderHeight=n,n>i&&(i=n)}for(a=0;a<f.length;a++)g=f[a],g.headerHeight<i&&(g.explicitHeaderHeight=i);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(null,c.prevScrolltopPercentage,!0),c.adjustColumns(null,c.prevScrollleftPercentage)}},o.prototype.hasLeftContainerColumns=function(){return this.hasLeftContainer()&&this.renderContainers.left.renderedColumns.length>0},o.prototype.hasRightContainerColumns=function(){return this.hasRightContainer()&&this.renderContainers.right.renderedColumns.length>0},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,c,d,e){return b.$on(a,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(e?e:d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged"),this.registerEvent("core","rowsRendered"),this.registerEvent("core","scrollEvent"),this.registerEvent("core","canvasHeightChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.eventId,a.handler,c.grid,a._this)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$emit.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b,c){var e=f(g,b,d.grid,c),h={handler:b,dereg:e,eventId:g,scope:a,_this:c};d.listeners.push(h);var i=function(){h.dereg();var a=d.listeners.indexOf(h);d.listeners.splice(a,1)};return a.$on("$destroy",function(){i()}),i}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a,!0)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b,c){var e=this;if(e.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.grid.options.columnDefs.indexOf(b));e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(e.width)||!angular.isNumber(e.width))if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(f);e.width=b.width}e.minWidth=b.minWidth?b.minWidth:30,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,"string"!=typeof e.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+e.field),e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.footerCellClass=b.footerCellClass,e.cellClass=b.cellClass,e.headerCellClass=b.headerCellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),c&&e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),c&&(e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)),d.prototype.unsort=function(){this.sort={},e.grid.api.core.raise.sortChanged(e,e.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showGridFooter=c.showGridFooter===!0,c.showColumnFooter=c.showColumnFooter===!0,c.columnFooterHeight="undefined"!=typeof c.columnFooterHeight?c.columnFooterHeight:30,c.gridFooterHeight="undefined"!=typeof c.gridFooterHeight?c.gridFooterHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c.appScopeProvider=c.appScopeProvider||null,c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],d.canvasHeightShouldUpdate=!0,d.$$canvasHeight=0,c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};
    +return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight,d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth,c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},c.prototype.getCanvasHeight=function(){var a=this;if(!a.canvasHeightShouldUpdate)return a.$$canvasHeight;var b=a.$$canvasHeight;return a.$$canvasHeight=0,a.visibleRowCache.forEach(function(b){a.$$canvasHeight+=b.height}),a.canvasHeightShouldUpdate=!1,a.grid.api.core.raise.canvasHeightChanged(b,a.$$canvasHeight),a.$$canvasHeight},c.prototype.getVerticalScrollLength=function(){return this.getCanvasHeight()-this.getViewportHeight()},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b,!1),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,c,d){var e=this,f=e.minRowsToRender(),g=e.visibleRowCache,h=g.length-f;"undefined"!=typeof c&&null!==c||!a||(c=a/e.getVerticalScrollLength());var i=Math.ceil(Math.min(h,h*c));i>h&&(i=h);var j=[];if(g.length>e.grid.options.virtualizationThreshold){if("undefined"!=typeof a&&null!==a){if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop<a&&i<e.prevRowScrollIndex+e.grid.options.scrollThreshold&&h>i)return;if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop>a&&i>e.prevRowScrollIndex-e.grid.options.scrollThreshold&&h>i)return}var k={},l={};if(e.grid.options.enableInfiniteScroll&&e.grid.scrollDirection!==b.scrollDirection.NONE&&d){var m=null,n=null;if(e.grid.scrollDirection===b.scrollDirection.UP){for(m=i>0?e.grid.options.excessRows:0,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i),l=Math.min(g.length,k+e.grid.options.excessRows+f)}else if(e.grid.scrollDirection===b.scrollDirection.DOWN){for(m=f,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i-e.grid.options.excessRows-f),l=Math.min(g.length,i+f+e.grid.options.excessRows)}}else k=Math.max(0,i-e.grid.options.excessRows),l=Math.min(g.length,i+f+e.grid.options.excessRows);j=[k,l]}else{var o=e.visibleRowCache.length;j=[0,Math.max(o,f+e.grid.options.excessRows)]}e.updateViewableRowRange(j),e.prevRowScrollIndex=i},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var b,c=this,d=[],e=[],f=0,g=c.getViewportWidth(),h=0,i=0,j="",k=c.visibleColumnCache;k.forEach(function(b){if(b.visible){var c=!1;angular.isNumber(b.width)||(c=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(f=parseInt(f+b.width.length,10),d.push(b)):c?e.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=g-h;if(e.length>0){for(l=0;l<e.length;l++){m=e[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1))}e.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(d.length>0){var q=parseInt(o/f,10);for(l=0;l<d.length;l++)m=d[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,f--,i+=n,m.drawnWidth=n,b=m,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,f--,i+=n,m.drawnWidth=n,d.splice(l,1));q=parseInt(o/f,10),d.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=g-parseInt(i,10);if(r>0&&i>0&&g>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}g>i&&(i=g),k.forEach(function(a){j+=a.getColClassDefinition()}),c.canvasWidth=parseInt(i,10),this.columnStyles=j},c.prototype.getViewPortStyle=function(){var a=this,c={};return"body"===a.name?(c["overflow-x"]=a.grid.options.enableHorizontalScrollbar===b.scrollbars.NEVER?"hidden":"scroll",c["overflow-y"]=a.grid.isRTL()?a.grid.hasLeftContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":a.grid.hasRightContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"):"left"===a.name?(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":"hidden"):(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"),c},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.$$height=d.options.rowHeight}return Object.defineProperty(b.prototype,"height",{get:function(){return this.$$height},set:function(a){a!==this.$$height&&(this.grid.updateCanvasHeight(),this.$$height=a)}}),b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){angular.module("ui.grid").factory("ScrollEvent",["gridUtil",function(a){function b(b,c,d,e){var f=this;if(!b)throw new Error("grid argument is required");f.grid=b,f.source=e,f.sourceRowContainer=c,f.sourceColContainer=d,f.newScrollLeft=null,f.newScrollTop=null,f.x=null,f.y=null,f.fireThrottledScrollingEvent=a.throttle(function(){f.grid.api.core.raise.scrollEvent(f)},f.grid.options.scrollThrottle,{trailing:!0})}return b.prototype.fireScrollingEvent=function(){this.grid.api.core.raise.scrollEvent(this)},b.prototype.getNewScrollLeft=function(b,c){var d=this;if(!d.newScrollLeft){var e,f=b.getCanvasWidth()-b.getViewportWidth(),g=a.normalizeScrollLeft(c);if("undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage)e=d.x.percentage;else{if("undefined"==typeof d.x.pixels||void 0===d.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");e=d.x.percentage=(g+d.x.pixels)/f}return Math.max(0,e*f)}return d.newScrollLeft},b.prototype.getNewScrollTop=function(a,b){var c=this;if(!c.newScrollTop){var d,e=a.getVerticalScrollLength(),f=b[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)d=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=c.y.percentage=(f+c.y.pixels)/e}return Math.max(0,d*e)}return c.newScrollTop},b.Sources={ViewPortScroll:"ViewPortScroll",RenderContainerMouseWheel:"RenderContainerMouseWheel",RenderContainerTouchMove:"RenderContainerTouchMove",Other:99},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowBuilder(g.rowTemplateAssigner),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)},rowTemplateAssigner:function(d){var e=this;if(d.rowTemplate){var f=b.defer();d.getRowTemplateFn=f.promise,a.getTemplate(d.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+d.rowTemplate+"'")})}else d.rowTemplate=e.options.rowTemplate,d.getRowTemplateFn=e.getRowTemplateFn;return d.getRowTemplateFn}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var b=angular.module("ui.grid");b.service("rowSearcher",["gridUtil","uiGridConstants",function(b,c){var d=c.filter.STARTS_WITH,e={};return e.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},e.stripTerm=function(b){var c=e.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},e.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return d;var b=e.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var f=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+f+"$",c)}return d},e.setupFilters=function(a){for(var b=[],d=a.length,f=0;d>f;f++){var g=a[f];if(g.noTerm||g.term){var h={},i="";g.flags&&g.flags.caseSensitive||(i+="i"),g.term&&(h.term=e.stripTerm(g)),h.condition=g.condition?g.condition:e.guessCondition(g),h.flags=angular.extend({caseSensitive:!1},g.flags),h.condition===c.filter.STARTS_WITH&&(h.startswithRE=new RegExp("^"+h.term,i)),h.condition===c.filter.ENDS_WITH&&(h.endswithRE=new RegExp(h.term+"$",i)),h.condition===c.filter.CONTAINS&&(h.containsRE=new RegExp(h.term,i)),h.condition===c.filter.EXACT&&(h.exactRE=new RegExp("^"+h.term+"$",i)),b.push(h)}}return b},e.runColumnFilter=function(a,b,d,e){var f=typeof e.condition,g=e.term,h=a.getCellValue(b,d);if(e.condition instanceof RegExp)return e.condition.test(h);if("function"===f)return e.condition(g,h,b,d);if(e.startswithRE)return e.startswithRE.test(h);if(e.endswithRE)return e.endswithRE.test(h);if(e.containsRE)return e.containsRE.test(h);if(e.exactRE)return e.exactRE.test(h);if(e.condition===c.filter.NOT_EQUAL){var i=new RegExp("^"+g+"$");return!i.exec(h)}if("number"==typeof h){var j=parseFloat(g.replace(/\\./,"."));isNaN(j)||(g=j)}return e.condition===c.filter.GREATER_THAN?h>g:e.condition===c.filter.GREATER_THAN_OR_EQUAL?h>=g:e.condition===c.filter.LESS_THAN?g>h:e.condition===c.filter.LESS_THAN_OR_EQUAL?g>=h:!0},e.searchColumn=function(a,b,c,d){if(a.options.useExternalFiltering)return!0;for(var f=d.length,g=0;f>g;g++){var h=d[g],i=e.runColumnFilter(a,b,c,h);if(!i)return!1}return!0},e.search=function(a,b,c){if(b){for(var d=[],f=c.length,g=0;f>g;g++){var h=c[g];"undefined"!=typeof h.filters&&(h.filters.length>1||1===h.filters.length&&("undefined"!=typeof h.filters[0].term&&h.filters[0].term||h.filters[0].noTerm))?d.push({col:h,filters:e.setupFilters(h.filters)}):"undefined"!=typeof h.filter&&h.filter&&("undefined"!=typeof h.filter.term&&h.filter.term||h.filter.noTerm)&&d.push({col:h,filters:e.setupFilters([h.filter])})}if(d.length>0){for(var i=function(a,b,c,d){(b.forceInvisible||!e.searchColumn(a,b,c,d))&&(b.visible=!1)},j=function(a,c){for(var d=b.length,e=0;d>e;e++)i(a,b[e],c.col,c.filters)},k=d.length,l=0;k>l;l++)j(a,d[l]);a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()}return b}},e}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toString().toLowerCase(),f=b.toString().toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);angular.forEach(c,function(a,b){a.entity.$uiGridIndex=b});var j=c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return 0===k?c.entity.$uiGridIndex-e.entity.$uiGridIndex:h===b.ASC?k:0-k});return angular.forEach(j,function(a){delete a.entity.$uiGridIndex}),j}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=g||null==g){if(g=i[d],(0>g||null==g)&&(g=c.style[d]),e.test(g))return g;h=j&&!0,g=parseFloat(g)||0}var k=g+b(c,d,f||(j?"border":"content"),h,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,d,e,j,k,l,m,n,o,p){var q={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return q.postProcessTemplate(k.get(a));if(a.hasOwnProperty("then"))return a.then(q.postProcessTemplate);try{if(angular.element(a).length>0)return n.when(a).then(q.postProcessTemplate)}catch(b){}return q.logDebug("fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(q.postProcessTemplate)},postProcessTemplate:function(a){var b=o.startSymbol(),c=o.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),n.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=m.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=q.nextUid()):b=a,c+":"+b},resetUids:function(){h=["0","0","0"]},logError:function(a){p.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){p.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){p.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);q["element"+d]=function(d,e){var h=d;if(h&&"undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?q.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},q["outerElement"+d]=function(a,b){return a?q["element"+d].call(this,a,b?"margin":"border"):null}}),q.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},q.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},q.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},q.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},q.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=q.detectBrowser(),c=a.scrollLeft,d=q.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},q.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=q.detectBrowser(),d=q.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},q.preEval=function(a){var b=p.BRACKET_REGEXP.exec(a);if(b)return(b[1]?q.preEval(b[1]):b[1])+b[2]+(b[3]?q.preEval(b[3]):b[3]);a=a.replace(p.APOS_REGEXP,"\\'");var c=a.split(p.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(p.FUNC_REGEXP,"']$1"))}),d.join("['")},q.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},q.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),l(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=l(d,b-a))}}},q}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},pagination:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."},pagination:{sizes:"articles par page",totalItems:"articles"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ja",{aggregate:{label:"件"},groupPanel:{description:"列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。"},search:{placeholder:"検索...",showingItems:"絞込み件数:",selectedItems:"選択件数:",totalItems:"全件数:",size:"ページサイズ: ",first:"最初のページ",next:"次のページ",previous:"前のページ",last:"最後のページ"},menu:{text:"列選択:"},sort:{ascending:"昇順ソート",descending:"降順ソート",remove:"ソート取消"},column:{hide:"列を隠す"},aggregation:{count:"合計件数: ",sum:"合計: ",avg:"平均: ",min:"最小値: ",max:"最大値: "},pinning:{pinLeft:"左にピン留め",pinRight:"右にピン留め",unpin:"ピン留め取消"},gridMenu:{columns:"列:",importerTitle:"インポートファイル",exporterAllAsCsv:"全てのデータをCSV形式でエクスポート",exporterVisibleAsCsv:"絞込み済みデータをCSV形式でエクスポート",exporterSelectedAsCsv:"選択しているデータをCSV形式でエクスポート",exporterAllAsPdf:"全てのデータをPDFでエクスポート",exporterVisibleAsPdf:"絞込み済みデータをPDFでエクスポート",exporterSelectedAsPdf:"選択しているデータをPDFでエクスポート"},importer:{noHeaders:"列名が抽出できません。ヘッダーは設定されていますか?",noObjects:"データが抽出できません。ファイルにデータは含まれていますか?",invalidCsv:"処理を行うことができません。ファイルは有効なCSVファイルですか?",invalidJson:"処理を行うことができません。ファイルは有効なJSONファイルですか?",jsonNotArray:"JSONファイルは配列を含んでいる必要があります。処理を中断します。"},pagination:{sizes:"件 / ページ",totalItems:"件"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"всего строк: ",sum:"итого: ",avg:"среднее: ",min:"мин: ",max:"макс: "},gridMenu:{columns:"Столбцы:",importerTitle:"Import file",exporterAllAsCsv:"Экспортировать всё в CSV",exporterVisibleAsCsv:"Экспортировать видимые данные в CSV",exporterSelectedAsCsv:"Экспортировать выбранные данные в CSV",exporterAllAsPdf:"Экспортировать всё в PDF",exporterVisibleAsPdf:"Экспортировать видимые данные в PDF",exporterSelectedAsPdf:"Экспортировать выбранные данные в PDF"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},pagination:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"},pagination:{sizes:"行每页",totalItems:"行"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"},pagination:{sizes:"行每頁",totalItems:"行"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3,PG_UP:4,PG_DOWN:5},EVENT_TYPE:{KEYDOWN:0,CLICK:1}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[],this.bodyContainer=a};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getFocusableRows=function(){return this.rows.filter(function(a){return a.allowCellFocus!==!1})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c);case d.direction.PG_UP:return this.getRowColPageUp(b,c);case d.direction.PG_DOWN:return this.getRowColPageDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=1);var h=0===f?d.length-1:f-1;return h>f?0===g?new a(b,d[h]):new a(e[g-1],d[h]):new a(b,d[h])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=f===d.length-1?0:f+1;return f>h?g===e.length-1?new a(b,d[h]):new a(e[g+1],d[h]):new a(b,d[h])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),g===e.length-1?new a(b,d[f]):new a(e[g+1],d[f])},e.prototype.getRowColPageDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return g>=e.length-h?new a(e[e.length-1],d[f]):new a(e[g+h],d[f])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),0===g?new a(b,d[f]):new a(e[g-1],d[f])},e.prototype.getRowColPageUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return 0>g-h?new a(e[0],d[f]):new a(e[g-h],d[f])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory","ScrollEvent",function(a,b,c,d,e,f){var g={initializeGrid:function(a){a.registerColumnBuilder(g.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null,a.cellNav.focusedCells=[],g.defaultGridOptions(a.options);var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(b,c){g.scrollTo(a,b,c)},scrollToFocus:function(b,c){g.scrollToFocus(a,b,c)},scrollToIfNecessary:function(b,c){g.scrollToIfNecessary(a,b,c)},getFocusedCell:function(){return a.cellNav.lastRowCol},getCurrentSelection:function(){return a.cellNav.focusedCells},rowColSelectIndex:function(b){for(var c=-1,d=0;d<a.cellNav.focusedCells.length;d++)if(a.cellNav.focusedCells[d].col.uid===b.col.uid&&a.cellNav.focusedCells[d].row.uid===b.row.uid){c=d;break}return c}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.modifierKeysToMultiSelectCells=a.modifierKeysToMultiSelectCells===!0},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.PG_UP?c.direction.PG_UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:a.keyCode===b.keymap.PG_DOWN?c.direction.PG_DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c){var d=null,e=null;null!==b&&"undefined"!=typeof b&&(d=a.getRow(b)),null!==c&&"undefined"!=typeof c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e)},scrollToFocus:function(a,b,c){var d=null,e=null;null!==b&&(d=a.getRow(b)),null!==c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e);var f={row:d,col:e};a.cellNav.broadcastCellNav(f)},scrollToInternal:function(a,b,c){var d=new f(a,null,null,"uiGridCellNavService.scrollToInternal");if(null!==b){var e=a.renderContainers.body.visibleRowCache.indexOf(b),g=a.renderContainers.body.visibleRowCache.length,h=(e+e/(g-1))/g;d.y={percentage:h}}null!==c&&(d.x={percentage:this.getLeftWidth(a,c)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(d.y||d.x)&&d.fireScrollingEvent()},scrollToIfNecessary:function(a,b,c){var d=new f(a,"uiGridCellNavService.scrollToIfNecessary"),e=a.renderContainers.body.visibleRowCache,g=a.renderContainers.body.visibleColumnCache,h=a.renderContainers.body.prevScrollTop+a.headerHeight;h=0>h?0:h;var i=a.renderContainers.body.prevScrollLeft,j=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight,k=a.renderContainers.body.prevScrollLeft+Math.ceil(a.gridWidth);if(null!==b){var l=e.indexOf(b),m=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight(),n=(l+1)*a.options.rowHeight;n=0>n?0:n;var o,p;h>n?(o=a.renderContainers.body.prevScrollTop-(h-n),p=o/m,d.y={percentage:p}):n>j&&(o=n-j+a.renderContainers.body.prevScrollTop,p=o/m,d.y={percentage:p})}if(null!==c){for(var q=g.indexOf(c),r=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),s=0,t=0;q>t;t++){var u=g[t];s+=u.drawnWidth}s=0>s?0:s;var v=s+c.drawnWidth;v=0>v?0:v;var w,x;i>s?(w=a.renderContainers.body.prevScrollLeft-(i-s),x=w/r,x=x>1?1:x,d.x={percentage:x}):v>k&&(w=v-k+a.renderContainers.body.prevScrollLeft,x=w/r,x=x>1?1:x,d.x={percentage:x})}(d.y||d.x)&&d.fireScrollingEvent()},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return g}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,e,f,g){var h=b,i=g.grid;c.initializeGrid(i),g.cellNav={},g.cellNav.focusCell=function(a,b){g.cellNav.broadcastCellNav({row:a,col:b})},g.cellNav.broadcastCellNav=i.cellNav.broadcastCellNav=function(a,b){b=!(void 0===b||!b),g.cellNav.broadcastFocus(a,b),h.$broadcast(d.CELL_NAV_EVENT,a,b)},g.cellNav.broadcastFocus=function(b,c){c=!(void 0===c||!c);var d=b.row,e=b.col,f=g.grid.api.cellNav.rowColSelectIndex(b);if(null===i.cellNav.lastRowCol||-1===f){var h=new a(d,e);i.api.cellNav.raise.navigate(h,i.cellNav.lastRowCol),i.cellNav.lastRowCol=h,g.grid.options.modifierKeysToMultiSelectCells&&c?i.cellNav.focusedCells.push(b):i.cellNav.focusedCells=[b]}else i.options.modifierKeysToMultiSelectCells&&c&&f>=0&&i.cellNav.focusedCells.splice(f,1)},g.cellNav.handleKeyDown=function(a){var b=c.getDirection(a);if(null===b)return!0;var e="body";a.uiGridTargetRenderContainerId&&(e=a.uiGridTargetRenderContainerId);var f=g.grid.api.cellNav.getFocusedCell();if(f){var h=g.grid.renderContainers[e].cellNav.getNextRowCol(b,f.row,f.col);return h.eventType=d.EVENT_TYPE.KEYDOWN,g.cellNav.broadcastCellNav(h),c.scrollToIfNecessary(i,h.row,h.col),a.stopPropagation(),a.preventDefault(),!1}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,d,f,g){var h=g[0],i=g[1];if(h.grid.api.cellNav){var j=i.containerId,k=h.grid;e.decorateRenderContainers(k),d.attr("tabindex",-1),d.on("keydown",function(a){return a.uiGridTargetRenderContainerId=j,h.cellNav.handleKeyDown(a)});var l=!1;k.api.core.on.scrollEvent(c,function(c){c.grid&&c.grid.id!==h.grid.id||null!=h.grid.api.cellNav.getFocusedCell()&&("uiGridCellNavService.scrollToIfNecessary"===c.source?l=!0:l&&a(function(){a(function(){var a=h.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&d[0].focus(),h.cellNav.broadcastCellNav(a),l=!1})}))})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",-1)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}e.grid.api.cellNav&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey),c.stopPropagation()}),b.$on(f.CELL_NAV_EVENT,function(a,d,g){d.row===b.row&&d.col===b.col?(e.grid.options.modifierKeysToMultiSelectCells&&g&&-1===e.grid.api.cellNav.rowColSelectIndex(d)?i():h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&c.find("div")[0].focus()):e.grid.options.modifierKeysToMultiSelectCells&&g||i()}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);
    +var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","$timeout","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g,h){var i=500;return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(f,j,k,l){function m(){j.on("dblclick",t),j.on("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").on("focus",q),j.on("touchstart",n)}function n(a){"undefined"!=typeof a.originalEvent&&void 0!==a.originalEvent&&(a=a.originalEvent),j.on("touchend",o),A=c(function(){},i),A.then(function(){setTimeout(t,0),j.off("touchend",o)})}function o(){c.cancel(A),j.off("touchend",o)}function p(){j.off("dblclick",t),j.off("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").off("focus",q),j.off("touchstart",n)}function q(a){l&&l.cellNav&&l.cellNav.focusCell(f.row,f.col),a.stopPropagation(),t()}function r(a){h.isStartEditKey(a)&&t()}function s(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(f):a.colDef.cellEditableCondition)}function t(){if(!C&&s(f.col,f.row)){f.grid.api.cellNav&&f.grid.api.cellNav.scrollToIfNecessary(f,f.row,f.col),z=g(f.row.getQualifiedColField(f.col)),y=z(f),x=f.col.editableCellTemplate,x=x.replace(d.MODEL_COL_FIELD,f.row.getQualifiedColField(f.col));var b=f.col.colDef.editDropdownFilter?"|"+f.col.colDef.editDropdownFilter:"";x=x.replace(d.CUSTOM_FILTERS,b);var c="text";switch(f.col.colDef.type){case"boolean":c="checkbox";break;case"number":c="number";break;case"date":c="date"}x=x.replace("INPUT_TYPE",c);var h=f.col.colDef.editDropdownRowEntityOptionsArrayPath;f.editDropdownOptionsArray=h?w(f.row.entity,h):f.col.colDef.editDropdownOptionsArray,f.editDropdownIdLabel=f.col.colDef.editDropdownIdLabel?f.col.colDef.editDropdownIdLabel:"id",f.editDropdownValueLabel=f.col.colDef.editDropdownValueLabel?f.col.colDef.editDropdownValueLabel:"value";f.$apply(function(){C=!0,p();var b=angular.element(x);j.append(b),B=f.$new(),a(b)(B);var c=angular.element(j.children()[0]);D=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var i=f.col.grid.api.core.on.scrollEvent(f,function(){u(!0),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),i(),k(),l()}),k=f.$on(e.events.END_CELL_EDIT,function(a,b){u(b),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),k(),i(),l()}),l=f.$on(e.events.CANCEL_CELL_EDIT,function(){v(),l(),i(),k()});f.$broadcast(e.events.BEGIN_CELL_EDIT),f.grid.api.edit.raise.beginCellEdit(f.row.entity,f.col.colDef)}}function u(a){if(C){var b=angular.element(j.children()[0]);B.$destroy(),angular.element(j.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&D&&b[0].focus(),D=!1,C=!1,m(),f.grid.api.core.notifyDataChange(d.dataChange.EDIT)}}function v(){C&&(z.assign(f,y),f.$apply(),f.grid.api.edit.raise.cancelCellEdit(f.row.entity,f.col.colDef),u(!0))}function w(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split(".");c.length;){var d=c.shift();if(!(d in a))return;a=a[d]}return a}if(f.col.colDef.enableCellEdit&&f.row.enableCellEdit!==!1){var x,y,z,A,B,C=!1,D=!1;m();try{var E=b.get("uiGridCellNavConstants");f.col.colDef.enableCellEditOnFocus&&f.$on(E.CELL_NAV_EVENT,function(a,b){b.row===f.row&&b.col===f.col?t():u()})}catch(F){}}}}}]),a.directive("uiGridEditor",["gridUtil","uiGridConstants","uiGridEditConstants",function(a,b,c){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(a,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),a.$on(c.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(b){a.stopEdit(b)})}),a.deepEdit=!1,a.stopEdit=function(b){a.inputForm&&!a.inputForm.$valid?(b.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT)):a.$emit(c.events.END_CELL_EDIT),a.deepEdit=!1},d.on("click",function(){a.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case b.keymap.ESC:d.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT);break;case b.keymap.ENTER:a.stopEdit(d);break;case b.keymap.TAB:a.stopEdit(d)}if(a.deepEdit)switch(d.keyCode){case b.keymap.LEFT:d.stopPropagation();break;case b.keymap.RIGHT:d.stopPropagation();break;case b.keymap.UP:d.stopPropagation();break;case b.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("uiGridEditor",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{priority:-100,require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.expandable={},c.expandable.expandedAll=!1,c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.expandableRowHeaderWidth=c.options.expandableRowHeaderWidth||40,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)},toggleAllRows:function(){b.toggleAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.isExpanded?b.height=b.grid.options.rowHeight+a.options.expandableRowHeight:(b.height=b.grid.options.rowHeight,a.expandable.expandedAll=!1),a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!0,a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!1,a.refresh()},toggleAllRows:function(a){a.expandable.expandedAll?b.collapseAllRows(a):b.expandAllRows(a)}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",displayName:"",exporterSuppressExport:!0,enableColumnResizing:!1,enableColumnMenu:!1,width:f.grid.options.expandableRowHeaderWidth||40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),g.headerCellTemplate=b.get("ui-grid/expandableTopRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGrid",["uiGridExpandableService","$templateCache",function(){return{replace:!0,priority:1e3,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,c,d){d.grid.api.core.on.renderingComplete(a,function(){a.row&&a.row.grid&&a.row.grid.options&&a.row.grid.options.enableExpandable&&(d.grid.parentRow=a.row)})},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",BUTTON_LABEL:"BUTTON_LABEL",FILE_NAME:"FILE_NAME"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c){h.csvExport(a,b,c)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterCsvFilename=a.exporterCsvFilename?a.exporterCsvFilename:"download.csv",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterHeaderFilterUseName=a.exporterHeaderFilterUseName===!0,a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.formatAsCsv(d,e,a.options.exporterCsvColumnSeparator);this.downloadFile(a.options.exporterCsvFilename,f)},getColumnHeaders:function(a,c){var d=[];return angular.forEach(a.columns,function(e){!e.visible&&c!==b.ALL||e.colDef.exporterSuppressExport===!0||-1!==a.options.exporterSuppressColumns.indexOf(e.name)||d.push({name:e.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(a.options.exporterHeaderFilterUseName?e.name:e.displayName):e.displayName,width:e.drawnWidth?e.drawnWidth:e.width,align:"number"===e.colDef.type?"right":"left"})}),d},getData:function(a,c,e){var f,g=[];switch(c){case b.ALL:f=a.rows;break;case b.VISIBLE:f=a.getVisibleRows();break;case b.SELECTED:a.api.selection?f=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(f,function(c){if(c.exporterEnableExporting!==!1){var d=[];angular.forEach(a.columns,function(f){if((f.visible||e===b.ALL)&&f.colDef.exporterSuppressExport!==!0&&-1===a.options.exporterSuppressColumns.indexOf(f.name)){var g={value:a.options.exporterFieldCallback(a,c,f,a.getCellValue(c,f))};f.colDef.exporterPdfAlign&&(g.alignment=f.colDef.exporterPdfAlign),d.push(g)}}),g.push(d)}}),g},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},downloadFile:function(a,b){var c,d=document,e=d.createElement("a"),f="application/octet-stream;charset=utf-8";if(navigator.msSaveBlob)return navigator.msSaveBlob(new Blob(["",b],{type:f}),a);if("download"in e){var g=new Blob([b],{type:f});c=URL.createObjectURL(g),e.setAttribute("download",a)}else c="data:"+f+","+encodeURIComponent(b),e.setAttribute("target","_blank");e.href=c,e.setAttribute("style","display:none;"),d.body.appendChild(e),setTimeout(function(){if(e.click)e.click();else if(document.createEvent){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0),e.dispatchEvent(a)}d.body.removeChild(e)},100)},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&(h.header=a.options.exporterPdfHeader),a.options.exporterPdfFooter&&(h.footer=a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a){i.importThisFile(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(c),d()},[b.dataChange.ROW]);a.importer.$scope.$on("$destroy",d)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){var c=a.srcElement||a.target;if(c&&c.files&&1===c.files.length){var d=c.files[0];b.importThisFile(i,d),c.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout","uiGridConstants",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options);var b={events:{infiniteScroll:{needLoadMoreData:function(){},needLoadMoreDataTop:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){return a.options.loadTimout=!0,a.scrollDirection===d.scrollDirection.UP?void a.api.infiniteScroll.raise.needLoadMoreDataTop():void a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return e}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.grid.api.core.on.scrollEvent(a,function(b){if(b.y&&"ui.grid.adjustInfiniteScrollPosition"!==b.source){var e=100-100*b.y.percentage;a.grid.scrollDirection===d.scrollDirection.UP&&(e=100*b.y.percentage),c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout","$log","ScrollEvent","uiGridConstants",function(a,b,c,d,e){var f={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){var e=a.columns;if(!angular.isNumber(c)||!angular.isNumber(d))return void console.log("Please provide valid values for originalPosition and finalPosition");for(var f=0,g=0;g<e.length;g++)(angular.isDefined(e[g].colDef.visible)&&e[g].colDef.visible===!1||e[g].isRowHeader===!0)&&f++;if(c>=e.length-f||d>=e.length-f)return void console.log("Invalid values for originalPosition, finalPosition");var h=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};b.redrawColumnAtPosition(a,h(c),h(d))}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var f=a.columns,g=f[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)f[h]=f[h-1];else if(d>c)for(var i=c;d>i;i++)f[i]=f[i+1];f[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d),a.api.core.notifyDataChange(e.dataChange.COLUMN)})}}};return f}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,h,i){a.col.colDef.enableColumnMoving&&a.$on(f.events.COLUMN_HEADER_CLICK,function(f,h){if(h.columnName===a.col.colDef.name&&!a.col.renderContainer){var j=h.event;if("ui-grid-icon-angle-down"!==j.target.className&&"I"!==j.target.tagName&&j.target.className.indexOf("ui-grid-filter-input")<0){var k,l,m=a.grid.element[0].getBoundingClientRect().left,n=j.pageX,o=0,p=m+a.grid.getViewportWidth(),q=!1,r=function(){q=!0,k=e.clone(),e.parent().append(k),k.addClass("movingColumn");var b={},c=e[0].getBoundingClientRect().left;b.left=c-m+"px";var d=a.grid.element[0].getBoundingClientRect().right,f=e[0].getBoundingClientRect().right;f>d&&(l=a.col.drawnWidth+(d-f),b.width=l+"px"),k.css(b)},s=function(c){i.fireEvent("hide-menu");for(var d=a.grid.columns,e=0,f=0;f<d.length;f++)(angular.isUndefined(d[f].colDef.visible)||d[f].colDef.visible===!0)&&(e+=d[f].drawnWidth||d[f].width||d[f].colDef.width);var h,j=k[0].getBoundingClientRect().left-1,n=k[0].getBoundingClientRect().right;if(h="ie"===b.detectBrowser()?j+c:j-m+c,h=p>h?h:p,(j>=m||c>0)&&(p>=n||0>c))k.css({visibility:"visible",left:h+"px"});else if(e>Math.ceil(i.grid.gridWidth)){c*=8;var q=new g(a.col.grid,null,null,"uiGridHeaderCell.moveElement");q.x={pixels:c},q.fireScrollingEvent()}for(var r=0,s=0;s<d.length;s++)if(angular.isUndefined(d[s].colDef.visible)||d[s].colDef.visible===!0){if(d[s].colDef.name===a.col.colDef.name)break;r+=d[s].drawnWidth||d[s].width||d[s].colDef.width}void 0===a.newScrollLeft?o+=c:o=a.newScrollLeft+h-r,l<a.col.drawnWidth&&(l+=Math.abs(c),k.css({width:l+"px"}))},t=function(a){document.onselectstart=function(){return!1};var b=a.pageX-n;!q&&Math.abs(b)>50?r():q&&(s(b),n=a.pageX)};d.on("mousemove",t);var u=function(){document.onselectstart=null,k&&k.remove();for(var b=a.grid.columns,e=0,f=0;f<b.length&&b[f].colDef.name!==a.col.colDef.name;f++)e++;if(0>o){for(var g=0,h=e-1;h>=0;h--)if((angular.isUndefined(b[h].colDef.visible)||b[h].colDef.visible===!0)&&(g+=b[h].drawnWidth||b[h].width||b[h].colDef.width,g>Math.abs(o))){c.redrawColumnAtPosition(a.grid,e,h+1);break}g<Math.abs(o)&&c.redrawColumnAtPosition(a.grid,e,0)}else if(o>0){for(var i=0,j=e+1;j<b.length;j++)if((angular.isUndefined(b[j].colDef.visible)||b[j].colDef.visible===!0)&&(i+=b[j].drawnWidth||b[j].width||b[j].colDef.width,i>o)){c.redrawColumnAtPosition(a.grid,e,j-1);
    +break}o>i&&c.redrawColumnAtPosition(a.grid,e,b.length-1)}d.off("mousemove",t),d.off("mouseup",u)};d.on("mouseup",u)}}})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ng","ui.grid"]);a.service("uiGridPaginationService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{pagination:{paginationChanged:function(){}}},methods:{pagination:{getPage:function(){return a.options.enablePagination?a.options.paginationCurrentPage:null},getTotalPages:function(){return a.options.enablePagination?0===a.options.totalItems?1:Math.ceil(a.options.totalItems/a.options.paginationPageSize):null},nextPage:function(){a.options.enablePagination&&(a.options.totalItems>0?a.options.paginationCurrentPage=Math.min(a.options.paginationCurrentPage+1,c.methods.pagination.getTotalPages()):a.options.paginationCurrentPage++)},previousPage:function(){a.options.enablePagination&&(a.options.paginationCurrentPage=Math.max(a.options.paginationCurrentPage-1,1))},seek:function(b){if(a.options.enablePagination){if(!angular.isNumber(b)||1>b)throw"Invalid page number: "+b;a.options.paginationCurrentPage=Math.min(b,c.methods.pagination.getTotalPages())}}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPagination||!a.options.enablePagination)return b;var c=parseInt(a.options.paginationPageSize,10),d=parseInt(a.options.paginationCurrentPage,10),e=b.filter(function(a){return a.visible});a.options.totalItems=e.length;var f=(d-1)*c;return f>e.length&&(d=a.options.paginationCurrentPage=1,f=(d-1)*c),e.slice(f,f+c)})},defaultGridOptions:function(b){b.enablePagination=b.enablePagination!==!1,b.enablePaginationControls=b.enablePaginationControls!==!1,b.useExternalPagination=b.useExternalPagination===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.paginationPageSizes)&&(b.paginationPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.paginationPageSize)&&(b.paginationPageSize=b.paginationPageSizes.length>0?b.paginationPageSizes[0]:0),a.isNullOrUndefined(b.paginationCurrentPage)&&(b.paginationCurrentPage=1),a.isNullOrUndefined(b.paginationTemplate)&&(b.paginationTemplate="ui-grid/pagination")},onPaginationChanged:function(a,b,c){a.api.pagination.raise.paginationChanged(b,c),a.options.useExternalPagination||a.refresh()}};return b}]),a.directive("uiGridPagination",["gridUtil","uiGridPaginationService",function(a,b){return{priority:-200,scope:!1,require:"uiGrid",link:{pre:function(c,d,e,f){b.initializeGrid(f.grid),a.getTemplate(f.grid.options.paginationTemplate).then(function(a){var b=angular.element(a);d.append(b),f.innerCompile(b)})}}}}]),a.directive("uiGridPager",["uiGridPaginationService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.paginationApi=h.grid.api.pagination,e.sizesLabel=d.getSafeText("pagination.sizes"),e.totalItemsLabel=d.getSafeText("pagination.totalItems");var i=h.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a});var j=h.grid.registerDataChangeCallback(function(a){a.options.useExternalPagination||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);e.$on("$destroy",j);var k=function(){e.showingLow=(i.paginationCurrentPage-1)*i.paginationPageSize+1,e.showingHigh=Math.min(i.paginationCurrentPage*i.paginationPageSize,i.totalItems)},l=e.$watch("grid.options.totalItems + grid.options.paginationPageSize",k),m=e.$watch("grid.options.paginationCurrentPage + grid.options.paginationPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.paginationCurrentPage)||i.paginationCurrentPage<1)return void(i.paginationCurrentPage=1);if(i.totalItems>0&&i.paginationCurrentPage>e.paginationApi.getTotalPages())return void(i.paginationCurrentPage=e.paginationApi.getTotalPages());k(),a.onPaginationChanged(e.grid,i.paginationCurrentPage,i.paginationPageSize)}});e.$on("$destroy",function(){l(),m()}),e.cantPageForward=function(){return i.totalItems>0?i.paginationCurrentPage>=e.paginationApi.getTotalPages():i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.paginationCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})},findTargetCol:function(a,b,c){var d=a.getRenderContainer();if("left"===b){var e=d.visibleColumnCache.indexOf(a);return d.visibleColumnCache[e-1*c]}return a}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q","uiGridResizeColumnsService","uiGridConstants","$timeout",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,d,h,i){var j=i.grid;if(j.options.enableColumnResizing){var k=b.get("ui-grid/columnResizer"),l=1;j.isRTL()&&(a.position="left",l=-1);var m=function(){for(var b=d[0].getElementsByClassName("ui-grid-column-resizer"),f=0;f<b.length;f++)angular.element(b[f]).remove();var g=e.findTargetCol(a.col,"left",l),h=a.col.getRenderContainer();if(g&&0!==h.visibleColumnCache.indexOf(a.col)&&g.colDef.enableColumnResizing!==!1){var i=angular.element(k).clone();i.attr("position","left"),d.prepend(i),c(i)(a)}if(a.col.colDef.enableColumnResizing!==!1){var j=angular.element(k).clone();j.attr("position","right"),d.append(j),c(j)(a)}};m();var n=function(){g(m)},o=j.registerDataChangeCallback(n,[f.dataChange.COLUMN]);a.$on("$destroy",o)}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","uiGridResizeColumnsService",function(a,b,c,d){var e,f,g,h=angular.element('<div class="ui-grid-resize-overlay"></div>');b.isTouchEnabled()?(e="touchstart",f="touchend",g="touchmove"):(e="mousedown",f="mouseup",g="mousemove");var i={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(i,j,k,l){function m(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function n(){l.grid.buildColumns().then(function(){l.grid.refreshCanvas(!0).then(function(){l.grid.refresh()})})}function o(a,b){var c=b;return a.colDef.minWidth&&c<a.colDef.minWidth?c=a.colDef.minWidth:a.colDef.maxWidth&&c>a.colDef.maxWidth&&(c=a.colDef.maxWidth),c}function p(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),s=(a.targetTouches?a.targetTouches[0]:a).clientX-t,0>s?s=0:s>l.grid.gridWidth&&(s=l.grid.gridWidth);var b=d.findTargetCol(i.col,i.position,u);if(b.colDef.enableColumnResizing!==!1){l.grid.element.hasClass("column-resizing")||l.grid.element.addClass("column-resizing");var e=s-r,f=parseInt(b.drawnWidth+e*u,10);s+=(o(b,f)-f)*u,h.css({left:s+"px"}),l.fireEvent(c.events.ITEM_DRAGGING)}}function q(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),l.grid.element.removeClass("column-resizing"),h.remove(),s=(b.changedTouches?b.changedTouches[0]:b).clientX-t;var c=s-r;if(0===c)return a.off(f,q),void a.off(g,p);var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var j=parseInt(e.drawnWidth+c*u,10);e.width=o(e,j),m(e),n(c),d.fireColumnSizeChanged(l.grid,e.colDef,c),a.off(f,q),a.off(g,p)}}var r=0,s=0,t=0,u=1;l.grid.isRTL()&&(i.position="left",u=-1),"left"===i.position?j.addClass("left"):"right"===i.position&&j.addClass("right"),j.on(e,function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),t=l.grid.element[0].getBoundingClientRect().left,r=(b.targetTouches?b.targetTouches[0]:b).clientX-t,l.grid.element.append(h),h.css({left:r}),a.on(f,q),a.on(g,p)}),j.on("dblclick",function(a){a.stopPropagation();var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var f=0,g=0,h=b.closestElm(j,".ui-grid-render-container"),k=h.querySelectorAll("."+c.COL_CLASS_PREFIX+e.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(k,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var h=b.elementWidth(c);e+=h}e>f&&(f=e,g=f-e)})}),e.width=o(e,f),m(e),n(g),d.fireColumnSizeChanged(l.grid,e.colDef,g)}}),j.on("$destroy",function(){j.off(e),j.off("dblclick"),a.off(g,p),a.off(f,q)})}};return i}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,c){f.setSavePromise(b,a,c)},getDirtyRows:function(){return b.rowEdit.dirtyRows?b.rowEdit.dirtyRows:[]},getErrorRows:function(){return b.rowEdit.errorRows?b.rowEdit.errorRows:[]},flushDirtyRows:function(){return f.flushDirtyRows(b)},setRowsDirty:function(a){f.setRowsDirty(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.saveState",["ui.grid","ui.grid.selection","ui.grid.cellNav"]);a.constant("uiGridSaveStateConstants",{featureName:"saveState"}),a.service("uiGridSaveStateService",["$q","uiGridSaveStateConstants","gridUtil","$compile","$interval","uiGridConstants",function(){var a={initializeGrid:function(b){b.saveState={},this.defaultGridOptions(b.options);var c={events:{saveState:{}},methods:{saveState:{save:function(){return a.save(b)},restore:function(c,d){a.restore(b,c,d)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.saveWidths=a.saveWidths!==!1,a.saveOrder=a.saveOrder!==!1,a.saveScroll=a.saveScroll===!0,a.saveFocus=a.saveScroll!==!0&&a.saveFocus!==!1,a.saveVisible=a.saveVisible!==!1,a.saveSort=a.saveSort!==!1,a.saveFilter=a.saveFilter!==!1,a.saveSelection=a.saveSelection!==!1},save:function(b){var c={};return c.columns=a.saveColumns(b),c.scrollFocus=a.saveScrollFocus(b),c.selection=a.saveSelection(b),c},restore:function(b,c,d){d.columns&&a.restoreColumns(b,d.columns),d.scrollFocus&&a.restoreScrollFocus(b,c,d.scrollFocus),d.selection&&a.restoreSelection(b,d.selection),b.refresh()},saveColumns:function(a){var b=[];return angular.forEach(a.columns,function(a){var c={};c.name=a.name,c.visible=a.visible,c.width=a.width,c.sort=angular.copy(a.sort),c.filters=angular.copy(a.filters),b.push(c)}),b},saveScrollFocus:function(b){if(!b.api.cellNav)return{};var c={};if(b.options.saveFocus){c.focus=!0;var d=b.api.cellNav.getFocusedCell();null!==d&&(c.colName=d.col.colDef.name,c.rowVal=a.getRowVal(b,d.row))}else b.options.saveScroll&&(c.focus=!1,b.renderContainers.body.prevRowScrollIndex&&(c.rowVal=a.getRowVal(b,b.renderContainers.body.visibleRowCache[b.renderContainers.body.prevRowScrollIndex])),b.renderContainers.body.prevColScrollIndex&&(c.colName=b.renderContainers.body.visibleColumnCache[b.renderContainers.body.prevColScrollIndex].name));return c},saveSelection:function(b){if(!b.api.selection)return{};var c=b.api.selection.getSelectedGridRows().map(function(c){return a.getRowVal(b,c)});return c},getRowVal:function(a,b){if(!b)return null;var c={};return a.options.saveRowIdentity?(c.identity=!0,c.row=a.options.saveRowIdentity(b.entity)):(c.identity=!1,c.row=a.renderContainers.body.visibleRowCache.indexOf(b)),c},restoreColumns:function(a,b){angular.forEach(b,function(b,c){var d=a.columns.filter(function(a){return a.name===b.name});if(d.length>0){var e=a.columns.indexOf(d[0]);if((a.columns[e].visible!==b.visible||a.columns[e].colDef.visible!==b.visible)&&(a.columns[e].visible=b.visible,a.columns[e].colDef.visible=b.visible,a.api.core.raise.columnVisibilityChanged(a.columns[e])),a.columns[e].width=b.width,angular.equals(a.columns[e].sort,b.sort&&!(void 0===a.columns[e].sort&&angular.isEmpty(b.sort)))||(a.columns[e].sort=angular.copy(b.sort),a.api.core.raise.sortChanged()),angular.equals(a.columns[e].filters,b.filters)||(a.columns[e].filters=angular.copy(b.filters),a.api.core.raise.filterChanged()),e!==c){var f=a.columns.splice(e,1)[0];a.columns.splice(c,0,f)}}})},restoreScrollFocus:function(b,c,d){if(b.api.cellNav){var e,f;if(d.colName){var g=b.options.columnDefs.filter(function(a){return a.name===d.colName});g.length>0&&(e=g[0])}d.rowVal&&d.rowVal.row&&(f=d.rowVal.identity?a.findRowByIdentity(b,d.rowVal):b.renderContainers.body.visibleRowCache[d.rowVal.row]);var h=f&&f.entity?f.entity:null;(e||h)&&(d.focus?b.api.cellNav.scrollToFocus(c,h,e):b.api.cellNav.scrollTo(c,h,e))}},restoreSelection:function(b,c){b.api.selection&&(b.api.selection.clearSelectedRows(),angular.forEach(c,function(c){if(c.identity){var d=a.findRowByIdentity(b,c);d&&b.api.selection.selectRow(d.entity)}else b.api.selection.selectRowByVisibleIndex(c.row)}))},findRowByIdentity:function(a,b){if(!a.options.saveRowIdentity)return null;var c=a.rows.filter(function(c){return a.options.saveRowIdentity(c.entity)===b.row?!0:!1});return c.length>0?c[0]:null}};return a}]),a.directive("uiGridSaveState",["uiGridSaveStateConstants","uiGridSaveStateService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),angular.module("ui.grid").config(["$provide",function(a){a.decorator("GridRow",["$delegate",function(a){return a.prototype.setSelected=function(a){this.isSelected=a,a?this.grid.selection.selectedCount++:this.grid.selection.selectedCount--},a}])}]),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,b.selection.selectedCount=0,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c,d){var e=b.getRow(c);null!==e&&e.enableSelection!==!1&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c,d){var e=b.getRow(c);null===e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c,d){var e=b.renderContainers.body.visibleRowCache[c];null===e||"undefined"==typeof e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c,d){var e=b.getRow(c);null!==e&&e.isSelected&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},selectAllVisibleRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.visible?e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c)):e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},clearSelectedRows:function(c){a.clearSelectedRows(b,c)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30,a.enableFooterTotalSelected=a.enableFooterTotalSelected!==!1,a.isRowSelectable=angular.isDefined(a.isRowSelectable)?a.isRowSelectable:angular.noop},toggleRowSelection:function(b,c,d,e,f){var g=c.isSelected;if(e||g){if(!e&&g){var h=a.getSelectedRows(b);h.length>1&&(g=!1,a.clearSelectedRows(b,d))}}else a.clearSelectedRows(b,d);g&&f||c.enableSelection!==!1&&(c.setSelected(!g),c.isSelected===!0?b.selection.lastSelectedRow=c:b.selection.selectAll=!1,b.api.selection.raise.rowSelectionChanged(c,d))},shiftSelect:function(b,c,d,e){if(e){var f=a.getSelectedRows(b),g=f.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,h=b.renderContainers.body.visibleRowCache.indexOf(c);if(g>h){var i=g;g=h,h=i}for(var j=[],k=g;h>=k;k++){var l=b.renderContainers.body.visibleRowCache[k];l&&(l.isSelected||l.enableSelection===!1||(l.setSelected(!0),b.selection.lastSelectedRow=l,a.decideRaiseSelectionEvent(b,l,j,d)))}a.decideRaiseSelectionBatchEvent(b,j,d)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b,c){var d=[];a.getSelectedRows(b).forEach(function(e){e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!1},decideRaiseSelectionEvent:function(a,b,c,d){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b,d)},decideRaiseSelectionBatchEvent:function(a,b,c){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b,c)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,minWidth:10,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1,exporterSuppressExport:!0};f.grid.addRowHeaderColumn(g)}f.grid.options.isRowSelectable!==angular.noop&&f.grid.registerRowBuilder(function(a){a.enableSelection=f.grid.options.isRowSelectable(a)})},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,c,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,c,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,c,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(a,d){c.selection.selectAll?(b.clearSelectedRows(c,d),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0,d),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(d),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,c){function d(){a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(c.addClass("ui-grid-disable-selection"),c.on("touchstart",j),c.on("touchend",k),c.on("click",i),a.registered=!0)}function e(){a.registered&&(c.removeClass("ui-grid-disable-selection"),c.off("touchstart",j),c.off("touchend",k),c.off("click",i),a.registered=!1)}var g=0,h=300,i=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,b,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()},j=function(){g=(new Date).getTime()},k=function(a){var b=(new Date).getTime(),c=b-g;h>c&&i(a)};d();var l=a.grid.registerDataChangeCallback(function(){!a.grid.options.enableRowSelection||a.grid.options.enableRowHeaderSelection||a.registered?a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection||!a.registered||e():d()},[b.dataChange.OPTIONS]);c.on("$destroy",l)}}}]),a.directive("uiGridGridFooter",["$compile","uiGridConstants","gridUtil",function(a,b,c){return{restrict:"EA",replace:!0,priority:-1e3,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(b,d,e,f){f.grid.options.showGridFooter&&c.getTemplate("ui-grid/gridFooterSelectedItems").then(function(c){var e=angular.element(c),f=a(e)(b);angular.element(d[0].getElementsByClassName("ui-grid-grid-footer")[0]).append(f)})},post:function(){}}}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel ui-grid-footer-aggregates-row"><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell ui-grid-clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-grid-footer",'<div class="ui-grid-footer-info ui-grid-grid-footer"><span>{{\'search.totalItems\' | t}} {{grid.rows.length}}</span> <span ng-if="grid.renderContainers.body.visibleRowCache.length !== grid.rows.length" class="ngLabel">({{"search.showingItems" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell ui-grid-clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    /*\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n    */\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div><div ui-grid-grid-footer ng-if="grid.options.showGridFooter"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showColumnFooter"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport" ng-style="containerCtrl.colContainer.getViewPortStyle()"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="INPUT_TYPE" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth()) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/expandableTopRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !grid.expandable.expandedAll, \'ui-grid-icon-minus-squared\' : grid.expandable.expandedAll }" ng-click="grid.api.expandable.toggleAllRows()"></i></div></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT" download="FILE_NAME">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/pagination",'<div class="ui-grid-pager-panel" ui-grid-pager ng-show="grid.options.enablePaginationControls"><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="paginationApi.seek(1)" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="paginationApi.previousPage()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.paginationCurrentPage" min="1" max="{{ paginationApi.getTotalPages() }}" required> <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span> <button type="button" ng-click="paginationApi.nextPage()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="paginationApi.seek(paginationApi.getTotalPages())" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/gridFooterSelectedItems",'<span ng-if="grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected">({{"search.selectedItems" | t}} {{grid.selection.selectedCount}})</span>'),a.put("ui-grid/selectionHeaderCell",'<div><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.19/ui-grid.svg b/release/3.0.0-rc.19/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-rc.19/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.19/ui-grid.ttf b/release/3.0.0-rc.19/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-rc.19/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.19/ui-grid.woff b/release/3.0.0-rc.19/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-rc.19/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.20/ui-grid.css b/release/3.0.0-rc.20/ui-grid.css
    new file mode 100644
    index 000000000..69dafb97f
    --- /dev/null
    +++ b/release/3.0.0-rc.20/ui-grid.css
    @@ -0,0 +1,1317 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20 - 2015-02-24
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +.ui-grid-header-cell-row {
    +  display: table-row;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  display: table-cell;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow-y: scroll;
    +  -webkit-overflow-scrolling: touch;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top: 1px;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +.ui-grid-footer-cell-row {
    +  display: table-row;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +  display: table-cell;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  overflow-y: scroll;
    +  max-height: 300px;
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child {
    +  border-right: 1px solid #d4d4d4;
    +  border-left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-column-resizer.right {
    +  border-right: 1px solid #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.right {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.left {
    +  border-left: 1px solid #d4d4d4;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.20/ui-grid.eot b/release/3.0.0-rc.20/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/3.0.0-rc.20/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.20/ui-grid.js b/release/3.0.0-rc.20/ui-grid.js
    new file mode 100644
    index 000000000..04ee0eaa4
    --- /dev/null
    +++ b/release/3.0.0-rc.20/ui-grid.js
    @@ -0,0 +1,19995 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20 - 2015-02-24
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart', // For any item being dragged
    +      COLUMN_HEADER_CLICK: 'uiGridColumnHeaderClick'
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      PG_UP: 33,
    +      PG_DOWN: 34,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +
    +    scrollDirection: {
    +      UP: 'up',
    +      DOWN: 'down',
    +      LEFT: 'left',
    +      RIGHT: 'right',
    +      NONE: 'none'
    +
    +    },
    +
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column',
    +      OPTIONS: 'options'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1
    +      //WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var initColClass = $scope.col.getColClass(false);
    +          $elm.addClass(initColClass);
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          // watch the col and row to see if they change - which would indicate that we've scrolled or sorted or otherwise
    +          // changed the row/col that this cell relates to, and we need to re-evaluate cell classes and maybe other things
    +          var cellChangeFunction = function( n, o ){
    +            if ( n !== o ) {
    +              if ( classAdded || $scope.col.cellClass ){
    +                updateClass();
    +              }
    +
    +              // See if the column's internal class has changed
    +              var newColClass = $scope.col.getColClass(false);
    +              if (newColClass !== initColClass) {
    +                $elm.removeClass(initColClass);
    +                $elm.addClass(newColClass);
    +                initColClass = newColClass;
    +              }
    +            }
    +          };
    +
    +          // TODO(c0bra): Turn this into a deep array watch
    +          var colWatchDereg = $scope.$watch( 'col', cellChangeFunction );
    +          var rowWatchDereg = $scope.$watch( 'row', cellChangeFunction );
    +          
    +          
    +          var deregisterFunction = function() {
    +            dataChangeDereg();
    +            colWatchDereg();
    +            rowWatchDereg(); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +          $elm.on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +        $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +        $scope.grid.api.core.raise.columnVisibilityChanged( $scope.col );        
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            var footerTemplate = ($scope.grid.options.gridFooterTemplate) ? $scope.grid.options.gridFooterTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 'ScrollEvent',
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, ScrollEvent) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            var initColClass = $scope.col.getColClass(false);
    +            $elm.addClass(initColClass);
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +              
    +              var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
    +              $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
    +            };
    +
    +            $scope.$watch('col', function (n, o) {
    +              if (n !== o) {
    +                // See if the column's internal class has changed
    +                var newColClass = $scope.col.getColClass(false);
    +                if (newColClass !== initColClass) {
    +                  $elm.removeClass(initColClass);
    +                  $elm.addClass(newColClass);
    +                  initColClass = newColClass;
    +                }
    +              }
    +            });
    +  
    +            updateClass();
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(event) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (event.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ($scope.sortable || $scope.colMenu) {
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +
    +              var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
    +              $contentsElm.on(downEvent, function(event) {
    +                event.stopPropagation();
    +
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +
    +                uiGridCtrl.fireEvent(uiGridConstants.events.COLUMN_HEADER_CLICK, {event: event, columnName: $scope.col.colDef.name});
    +              });
    +        
    +              var upEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'mouseup';
    +              $contentsElm.on(upEvent, function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });
    +            }
    +
    +
    +            $scope.toggleMenu = function(event) {
    +              event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
    +              $contentsElm.on(clickEvent, function(event) {
    +                event.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(event);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh(true);
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            updateHeaderReferences();
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +            gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                updateHeaderReferences();
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +
    +                $scope.grid.queueRefresh();
    +              });
    +
    +            function updateHeaderReferences() {
    +              containerCtrl.header = containerCtrl.colContainer.header = $elm;
    +
    +              var headerCanvases = $elm[0].getElementsByClassName('ui-grid-header-canvas');
    +
    +              if (headerCanvases.length > 0) {
    +                containerCtrl.headerCanvas = containerCtrl.colContainer.headerCanvas = headerCanvases[0];
    +              }
    +              else {
    +                containerCtrl.headerCanvas = null;
    +              }
    +            }
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth() - grid.scrollbarWidth;
    +
    +              //if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +              //  availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              //}
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              //if (grid.verticalScrollbarWidth) {
    +              //  canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              //}
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', 'uiGridConstants', function( gridUtil, i18nService, uiGridConstants ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +      gridCol.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +      gridCol.grid.api.core.raise.columnVisibilityChanged( gridCol );
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      if (uiGridCtrl) {
    +       $scope.$on('$destroy', uiGridCtrl.grid.api.core.on.scrollEvent($scope, applyHideMenu ));
    +      }
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil', 'ScrollEvent',
    +    function($timeout, $document, uiGridConstants, gridUtil, ScrollEvent) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              grid.api.core.on.scrollEvent($scope,scrollHandler);
    +            }
    +
    +            function scrollHandler (args) {
    +              // exit if not for this grid
    +              if (args.grid && args.grid.id !== grid.id){
    +                return;
    +              }
    +
    +              
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var newScrollTop = args.getNewScrollTop(rowContainer,containerCtrl.viewport);
    +
    +                //only set scrollTop if we coming from something other than viewPort scrollBar or
    +                //another column container
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll ||
    +                    args.sourceColContainer !== colContainer) {
    +                  containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                }
    +
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +                var newScrollLeft = args.getNewScrollLeft(colContainer,containerCtrl.viewport);
    +
    +                // Make the current horizontal scroll position available in the $scope
    +                $scope.newScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  containerCtrl.headerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  containerCtrl.footerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // Scroll came from somewhere else, so the viewport must be positioned
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll) {
    +                  containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                }
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            gridUtil.on.mousewheel($elm, function (event) {
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerMouseWheel);
    +              if (event.deltaY !== 0) {
    +                var scrollYAmount = event.deltaY * -1 * event.deltaFactor;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / rowContainer.getVerticalScrollLength();
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (event.deltaX !== 0) {
    +                var scrollXAmount = event.deltaX * event.deltaFactor;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = gridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +
    +              // todo: this isn't working when scrolling down.  it works fine for up.  tested on Chrome
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +              if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1) ||
    +                 (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +
    +                  event.preventDefault();
    +                  scrollEvent.fireThrottledScrollingEvent();
    +              }
    +            });
    +
    +            $elm.bind('$destroy', function() {
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +
    +              //add additional height for scrollbar on left and right container
    +              if ($scope.containerId !== 'body') {
    +                canvasHeight += grid.scrollbarHeight;
    +              }
    +
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + (canvasWidth + grid.scrollbarWidth) + 'px; }';
    +
    +              if (renderContainer.explicitHeaderCanvasHeight) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { height: ' + renderContainer.explicitHeaderCanvasHeight + 'px; }';
    +              }
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + grid.scrollbarWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            // Function for attaching the template to this scope
    +            var clonedElement, cloneScope;
    +            function compileTemplate() {
    +              $scope.row.getRowTemplateFn.then(function (compiledElementFn) {
    +                // var compiledElementFn = $scope.row.compiledElementFn;
    +
    +                // Create a new scope for the contents of this row, so we can destroy it later if need be
    +                var newScope = $scope.$new();
    +
    +                compiledElementFn(newScope, function (newElm, scope) {
    +                  // If we already have a cloned element, we need to remove it and destroy its scope
    +                  if (clonedElement) {
    +                    clonedElement.remove();
    +                    cloneScope.$destroy();
    +                  }
    +
    +                  // Empty the row and append the new element
    +                  $elm.empty().append(newElm);
    +
    +                  // Save the new cloned element and scope
    +                  clonedElement = newElm;
    +                  cloneScope = newScope;
    +                });
    +              });
    +            }
    +
    +            // Initially attach the compiled template to this scope
    +            compileTemplate();
    +
    +            // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
    +            $scope.$watch('row.getRowTemplateFn', function (newFunc, oldFunc) {
    +              if (newFunc !== oldFunc) {
    +                compileTemplate();
    +              }
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants',
    +    function(gridUtil, ScrollEvent, uiGridConstants) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        controllerAs: 'Viewport',
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              grid.flagScrollingHorizontally();
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              if (xDiff > 0) { grid.scrollDirection = uiGridConstants.scrollDirection.RIGHT; }
    +              if (xDiff < 0) { grid.scrollDirection = uiGridConstants.scrollDirection.LEFT; }
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              if (horizScrollLength !== 0) {
    +                horizScrollPercentage = newScrollLeft / horizScrollLength;
    +              }
    +              else {
    +                horizScrollPercentage = 0;
    +              }
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              grid.flagScrollingVertically();
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              if (yDiff > 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.DOWN; }
    +              if (yDiff < 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.UP; }
    +
    +              var vertScrollLength = rowContainer.getVerticalScrollLength();
    +
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
    +              scrollEvent.newScrollLeft = newScrollLeft;
    +              scrollEvent.newScrollTop = newScrollTop;
    +              if ( horizScrollPercentage > -1 ){
    +                scrollEvent.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                scrollEvent.y = { percentage: vertScrollPercentage };
    +              }
    +              scrollEvent.fireScrollingEvent();
    +          });
    +        },
    +        controller: ['$scope', function ($scope) {
    +          this.rowStyle = function (index) {
    +            var rowContainer = $scope.rowContainer;
    +            var colContainer = $scope.colContainer;
    +
    +            var styles = {};
    +
    +            if (index === 0 && rowContainer.currentTopRow !== 0) {
    +              // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +              var hiddenRowWidth = (rowContainer.currentTopRow) * rowContainer.grid.options.rowHeight;
    +
    +              // return { 'margin-top': hiddenRowWidth + 'px' };
    +              styles['margin-top'] = hiddenRowWidth + 'px';
    +            }
    +
    +            if (colContainer.currentFirstColumn !== 0) {
    +              if (colContainer.grid.isRTL()) {
    +                styles['margin-right'] = colContainer.columnOffset + 'px';
    +              }
    +              else {
    +                styles['margin-left'] = colContainer.columnOffset + 'px';
    +              }
    +            }
    +
    +            return styles;
    +          };
    +        }]
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile', 'ScrollEvent',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile, ScrollEvent) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +
    +      //assign $scope.$parent if appScope not already assigned
    +      self.grid.appScope = self.grid.appScope || $scope.$parent;
    +
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns({ orderByColumnDefs: true })
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function adjustInfiniteScrollPosition (scrollToRow) {
    +
    +        var scrollEvent = new ScrollEvent(self.grid, null, null, 'ui.grid.adjustInfiniteScrollPosition');
    +        var totalRows = self.grid.renderContainers.body.visibleRowCache.length;
    +        var percentage = ( scrollToRow + ( scrollToRow / ( totalRows - 1 ) ) ) / totalRows;
    +
    +        //for infinite scroll, never allow it to be at the zero position so the up button can be active
    +        if ( percentage === 0 ) {
    +          scrollEvent.y = {pixels: 1};
    +        }
    +        else {
    +          scrollEvent.y = {percentage: percentage};
    +        }
    +        scrollEvent.fireScrollingEvent();
    +
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace(true);
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +
    +                  $timeout(function () {
    +                    //Process post load scroll events if using infinite scroll
    +                    if ( self.grid.options.enableInfiniteScroll ) {
    +                      //If first load, seed the scrollbar down a little to activate the button
    +                      if ( self.grid.renderContainers.body.prevRowScrollIndex === 0 ) {
    +                        adjustInfiniteScrollPosition(0);
    +                      }
    +                      //If we are scrolling up, we need to reseed the grid.
    +                      if (self.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                        adjustInfiniteScrollPosition(self.grid.renderContainers.body.prevRowScrollIndex + 1 + self.grid.options.excessRows);
    +                      }
    +                    }
    +                    }, 0);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +      var styleWatchDereg = $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +        styleWatchDereg();
    +      });
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '='
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.calcFooterHeight();
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.refreshCanvas(true);
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  // TODO: rename this file to ui-grid-pinned-container.js
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth || col.width || 0;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 || !myWidth ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +
    +    /**
    +     * @ngdoc object
    +     * @name appScope
    +     * @propertyOf ui.grid.class:Grid
    +     * @description reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +     * <br/>
    +     * use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference
    +     */
    +    self.appScope = self.options.appScopeProvider;
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +
    +
    +    self.footerHeight = self.calcFooterHeight();
    +
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +
    +    /**
    +     * @ngdoc property
    +     * @name scrollDirection
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set one of the uiGridConstants.scrollDirection values (UP, DOWN, LEFT, RIGHT, NONE), which tells
    +     * us which direction we are scrolling. Set to NONE via debounced method
    +     */
    +    self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +
    +    self.scrollbarHeight = 0;
    +    self.scrollbarWidth = 0;
    +    if (self.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarHeight = gridUtil.getScrollbarWidth();
    +    }
    +
    +    if (self.options.enableVerticalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarWidth = gridUtil.getScrollbarWidth();
    +    }
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +      /**
    +     * @ngdoc function
    +     * @name columnVisibilityChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The visibility of a column has changed,
    +     * the column itself is passed out as a parameter of the event. 
    +     * 
    +     * @param {GridCol} column the column that changed
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.columnVisibilityChanged( $scope, function (column) {
    +     *        // do something
    +     *      } );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'columnVisibilityChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +
    +    self.registerStyleComputation({
    +      priority: 10,
    +      func: self.getFooterStyles
    +    });
    +  };
    +
    +   Grid.prototype.calcFooterHeight = function () {
    +     if (!this.hasFooter()) {
    +       return 0;
    +     }
    +
    +     var height = 0;
    +     if (this.options.showGridFooter) {
    +       height += this.options.gridFooterHeight;
    +     }
    +
    +     if (this.options.showColumnFooter) {
    +       height += this.options.columnFooterHeight;
    +     }
    +
    +     return height;
    +   };
    +
    +   Grid.prototype.getFooterStyles = function () {
    +     var style = '.grid' + this.id + ' .ui-grid-footer-aggregates-row { height: ' + this.options.columnFooterHeight + 'px; }';
    +     style += ' .grid' + this.id + ' .ui-grid-footer-info { height: ' + this.options.gridFooterHeight + 'px; }';
    +     return style;
    +   };
    +
    +  Grid.prototype.hasFooter = function () {
    +   return this.options.showGridFooter || this.options.showColumnFooter;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * - when the options watch fires, the OPTIONS callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * - OPTIONS calls OPTIONS and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +   * ALL 
    +   * @returns {function} deregister function - a function that can be called to deregister this callback
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types, _this) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types, _this:_this };
    +    
    +    var self = this;
    +    var deregisterFunction = function() {
    +      delete self.dataChangeCallbacks[uid];
    +    };
    +    return deregisterFunction;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        if (callback._this) {
    +           callback.callback.apply(callback._this,this);
    +        }
    +        else {
    +          callback.callback( this );
    +        }
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ||
    +         type === constants.OPTIONS ){
    +      this.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.refresh();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @param {object} options  An object contains options to use when building columns
    +   *
    +   * * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
    +   *
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns(opts) {
    +    var options = {
    +      orderByColumnDefs: false
    +    };
    +
    +    angular.extend(options, opts);
    +
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        // tell updateColumnDef that the column was pre-existing
    +        col.updateColumnDef(colDef, false);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    /*** Reorder columns if necessary ***/
    +    if (!!options.orderByColumnDefs) {
    +      // Create a shallow copy of the columns as a cache
    +      var columnCache = self.columns.slice(0);
    +
    +      // We need to allow for the "row headers" when mapping from the column defs array to the columns array
    +      //   If we have a row header in columns[0] and don't account for it   we'll overwrite it with the column in columnDefs[0]
    +
    +      // Go through all the column defs
    +      for (i = 0; i < self.options.columnDefs.length; i++) {
    +        // If the column at this index has a different name than the column at the same index in the column defs...
    +        if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
    +          // Replace the one in the cache with the appropriate column
    +          columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
    +        }
    +        else {
    +          // Otherwise just copy over the one from the initial columns
    +          columnCache[i + headerOffset] = self.columns[i + headerOffset];
    +        }
    +      }
    +
    +      // Empty out the columns array, non-destructively
    +      self.columns.length = 0;
    +
    +      // And splice in the updated, ordered columns from the cache
    +      Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
    +    }
    +
    +    return $q.all(builderPromises).then(function(){
    +      if (self.rows.length > 0){
    +        self.assignTypes();
    +      }
    +    });
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    var self = this;
    +
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      // See if the column name already exists:
    +      var foundName = self.getColumn(colDef.field);
    +
    +      // If a column with this name already  exists, we will add an incrementing number to the end of the new column name
    +      if (foundName) {
    +        // Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
    +        var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
    +
    +        var foundColumns = self.columns.filter(function (column) {
    +          // Test against the displayName, as that's what'll have the incremented number
    +          return nameRE.test(column.displayName);
    +        })
    +        // Sort the found columns by the end-number
    +        .sort(function (a, b) {
    +          if (a === b) {
    +            return 0;
    +          }
    +          else {
    +            var numA = a.displayName.match(nameRE)[1];
    +            var numB = b.displayName.match(nameRE)[1];
    +
    +            return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
    +          }
    +        });
    +
    +        // Not columns found, so start with number "2"
    +        if (foundColumns.length === 0) {
    +          colDef.name = colDef.field + '2';
    +        }
    +        else {
    +          // Get the number from the final column
    +          var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
    +
    +          // Make sure to parse to an int
    +          lastNum = parseInt(lastNum, 10);
    +
    +          // Add 1 to the number from the last column and tack it on to the field to be the name for this new column 
    +          colDef.name = colDef.field + (lastNum + 1);
    +        }
    +      }
    +      // ... otherwise just use the field as the column name
    +      else {
    +        colDef.name = colDef.field;
    +      }
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +//        if (wasEmpty) {
    +           self.assignTypes();
    +//        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.canvasHeightShouldUpdate = true;
    +      
    +      if ( typeof(container.visibleRowCache) === 'undefined' ){
    +        container.visibleRowCache = [];  
    +      } else {
    +        container.visibleRowCache.length = 0;  
    +      }
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +    self.api.core.raise.rowsRendered(this.api);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name updateCanvasHeight
    +   * @methodOf ui.grid.class:Grid
    +   * @description flags all render containers to update their canvas height
    +   */
    +  Grid.prototype.updateCanvasHeight = function updateCanvasHeight() {
    +    var self = this;
    +
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +        container.canvasHeightShouldUpdate = true;
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    //}
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    //gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    //gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    //}
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol && !col.colDef.suppressRemoveSort) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * @params {boolean} [rowsAltered] Optional flag for refreshing when the number of rows has changed.
    +   */
    +  Grid.prototype.refresh = function refresh(rowsAltered) {
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace(rowsAltered);
    +
    +      self.refreshCanvas(true);
    +    });
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header || container.headerCanvas) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    /*
    +     *
    +     * Here we loop through the headers, measuring each element as well as any header "canvas" it has within it.
    +     *
    +     * If any header is less than the largest header height, it will be resized to that so that we don't have headers
    +     * with different heights, which looks like a rendering problem
    +     *
    +     * We'll do the same thing with the header canvases, and give the header CELLS an explicit height if their canvas
    +     * is smaller than the largest canvas height. That was header cells without extra controls like filtering don't
    +     * appear shorter than other cells.
    +     *
    +     */
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeaderHeight = 0;
    +        var maxHeaderCanvasHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeaderHeight) {
    +              maxHeaderHeight = innerHeaderHeight;
    +            }
    +          }
    +
    +          if (container.headerCanvas) {
    +            var oldHeaderCanvasHeight = container.headerCanvasHeight;
    +            var headerCanvasHeight = gridUtil.outerElementHeight(container.headerCanvas);
    +
    +            container.headerCanvasHeight = parseInt(headerCanvasHeight, 10);
    +
    +            if (oldHeaderCanvasHeight !== headerCanvasHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Save the largest header canvas height for use later
    +            if (headerCanvasHeight > maxHeaderCanvasHeight) {
    +              maxHeaderCanvasHeight = headerCanvasHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (maxHeaderHeight > 0 && typeof(container.headerHeight) !== 'undefined' && container.headerHeight !== null && container.headerHeight < maxHeaderHeight) {
    +            container.explicitHeaderHeight = maxHeaderHeight;
    +          }
    +
    +          if (typeof(container.headerCanvasHeight) !== 'undefined' && container.headerCanvasHeight !== null && maxHeaderCanvasHeight > 0 && container.headerCanvasHeight < maxHeaderCanvasHeight) {
    +            container.explicitHeaderCanvasHeight = maxHeaderCanvasHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * @param {boolean} [rowsAdded] Optional to indicate rows are added and the scroll percentage must be recalculated
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace(rowsAdded) {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +      
    +      if (rowsAdded) {
    +        container.adjustRows(container.prevScrollTop, null);
    +        container.adjustColumns(container.prevScrollTop, null);
    +      }
    +      else {
    +        container.adjustRows(null, container.prevScrolltopPercentage);
    +        container.adjustColumns(null, container.prevScrollleftPercentage);
    +      }
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasLeftContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if leftContainer has columns
    +     */
    +    Grid.prototype.hasLeftContainerColumns = function () {
    +      return this.hasLeftContainer() && this.renderContainers.left.renderedColumns.length > 0;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasRightContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if rightContainer has columns
    +     */
    +    Grid.prototype.hasRightContainerColumns = function () {
    +      return this.hasRightContainer() && this.renderContainers.right.renderedColumns.length > 0;
    +    };
    +
    +
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name rowsRendered
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the cache of visible rows is changed.
    +           */
    +          this.registerEvent( 'core', 'rowsRendered' );
    +
    +
    +          /**
    +           * @ngdoc event
    +           * @name scrollEvent
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised on a scroll Event.  Called frequently so be careful what you do with it
    +           */
    +          this.registerEvent( 'core', 'scrollEvent' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name canvasHeightChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised when the canvas height has changed
    +           * <br/>
    +           * arguments: oldHeight, newHeight
    +           */
    +          this.registerEvent( 'core', 'canvasHeightChanged');
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.eventId, l.handler, self.grid, l._this);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * <br>
    +         * .raise.eventName() - takes no arguments
    +         * <br/>
    +         * <br/>
    +         * .on.eventName(scope, callBackFn, _this)
    +         * <br/>
    +         * scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +         * <br/>
    +         * callBackFn - The function to call
    +         * <br/>
    +         * _this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +         * <br/>
    +         * .on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +         * will be removed when the scope is destroyed.
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$emit.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler, _this) {
    +            var deregAngularOn = registerEventWithAngular(eventId, handler, self.grid, _this);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: deregAngularOn, eventId: eventId, scope: scope, _this:_this};
    +            self.listeners.push(listener);
    +
    +            var removeListener = function(){
    +              listener.dereg();
    +              var index = self.listeners.indexOf(listener);
    +              self.listeners.splice(index,1);
    +            };
    +
    +            //destroy tracking when scope is destroyed
    +            scope.$on('$destroy', function() {
    +              removeListener();
    +            });
    +
    +            return removeListener;
    +          };
    +        };
    +
    +        function registerEventWithAngular(eventId, handler, grid, _this) {
    +          return $rootScope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(_this ? _this : grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} _this binds callBackFn 'this' to _this.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, _this) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(_this || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} _this binds this to _this for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, _this) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, _this);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef, true);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         term: 'aa',
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...',
    +   *         flags: { caseSensitive: false }
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...',
    +   *     flags: { caseSensitive: false }
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {boolean} isNew whether the column is being newly created, if not
    +   * we're updating an existing column, and some items such as the sort shouldn't
    +   * be copied down
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef, isNew) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it, but only if this is a newly added column
    +    if ( isNew ){
    +      self.setPropertyOrDefault(colDef, 'sort');
    +    }
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * 
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * - flags: only flag currently available is `caseSensitive`, set to false if you don't want
    +     * case sensitive matching
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       term: 'xx',
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...',
    +     *       flags: { caseSensitive: false }
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    // Only set filter if this is a newly added column, if we're updating an existing
    +    // column then we don't want to put the default filter back if the user may have already
    +    // removed it.
    +    if ( isNew ) {
    +      self.setPropertyOrDefault(colDef, 'filter');
    +      self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +    }
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { min-width: ' + this.drawnWidth + 'px; max-width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>
    +   * app.config(function($provide){
    +   *   $provide.decorator('GridOptions',function($delegate){
    +   *     var gridOptions;
    +   *     gridOptions = angular.copy($delegate);
    +   *     gridOptions.initialize = function(options) {
    +   *       var initOptions;
    +   *       initOptions = $delegate.initialize(options);
    +   *       initOptions.enableColumnMenus = false;
    +   *       return initOptions;
    +   *     };
    +   *     return gridOptions;
    +   *   });
    +   * });
    +   * </pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      /**
    +       * @ngdoc function
    +       * @name onRegisterApi
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description A callback that returns the gridApi once the grid is instantiated, which is 
    +       * then used to interact with the grid programatically.
    +       * 
    +       * Note that the gridApi.core.renderingComplete event is identical to this 
    +       * callback, but has the advantage that it can be called from multiple places
    +       * if needed
    +       * 
    +       * @example
    +       * <pre>
    +       *   $scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +       *     $scope.gridApi = gridApi;
    +       *     $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +       *   };
    +       * </pre>
    +       * 
    +       */
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showGridFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       * The footer display Total Rows and Visible Rows (filtered rows)
    +       */
    +      baseOptions.showGridFooter = baseOptions.showGridFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name showColumnFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the column footer, defaults to false
    +       * The column footer displays column aggregates
    +       */
    +      baseOptions.showColumnFooter = baseOptions.showColumnFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name columnFooterHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer rows (column footer and grid footer) in pixels
    +       *
    +       */
    +      baseOptions.columnFooterHeight = typeof(baseOptions.columnFooterHeight) !== "undefined" ? baseOptions.columnFooterHeight : 30;
    +      baseOptions.gridFooterHeight = typeof(baseOptions.gridFooterHeight) !== "undefined" ? baseOptions.gridFooterHeight : 30;
    +
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +
    +      /**
    +       * @ngdoc object
    +       * @name appScopeProvider
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +       * this property allows you to assign any reference you want to grid.appScope
    +       */
    +      baseOptions.appScopeProvider = baseOptions.appScopeProvider || null;
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeightShouldUpdate
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description flag to signal that container should recalculate the canvas size
    +     */
    +    self.canvasHeightShouldUpdate = true;
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeight
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description last calculated canvas height value
    +     */
    +    self.$$canvasHeight = 0;
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCanvasHeight
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false
    +   * @returns {number} total height of all the visible rows in the container
    +   */
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    if (!self.canvasHeightShouldUpdate) {
    +      return self.$$canvasHeight;
    +    }
    +
    +    var oldCanvasHeight = self.$$canvasHeight;
    +
    +    self.$$canvasHeight =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      self.$$canvasHeight += row.height;
    +    });
    +
    +
    +    self.canvasHeightShouldUpdate = false;
    +
    +    self.grid.api.core.raise.canvasHeightChanged(oldCanvasHeight, self.$$canvasHeight);
    +
    +    return self.$$canvasHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() {
    +    return this.getCanvasHeight() - this.getViewportHeight();
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    //if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +    //  ret = ret - self.verticalScrollbarWidth;
    +    //}
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage, false);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage, postDataLoaded) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getVerticalScrollLength();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
    +        // Have we hit the threshold going down?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +        //Have we hit the threshold going up?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +      }
    +      var rangeStart = {};
    +      var rangeEnd = {};
    +
    +      //If infinite scroll is enabled, and we loaded more data coming from redrawInPlace, then recalculate the range and set rowIndex to proper place to scroll to
    +      if ( self.grid.options.enableInfiniteScroll && self.grid.scrollDirection !== uiGridConstants.scrollDirection.NONE && postDataLoaded ) {
    +        var findIndex = null;
    +        var i = null;
    +        if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.UP ) {
    +          findIndex = rowIndex > 0 ? self.grid.options.excessRows : 0;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex);
    +          rangeEnd = Math.min(rowCache.length, rangeStart + self.grid.options.excessRows + minRows);
    +        }
    +        else if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.DOWN ) {
    +          findIndex = minRows;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows - minRows);
    +          rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +        }
    +      }
    +      else {
    +        rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +        rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +      }
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      /* Commented the following lines because otherwise the moved column wasn't visible immediately on the new position
    +       * in the case of many columns with horizontal scroll, one had to scroll left or right and then return in order to see it
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }*/
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.headerCellWrapperStyle = function () {
    +    var self = this;
    +    
    +    if (self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth() - self.grid.scrollbarWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    //if (self.grid.verticalScrollbarWidth) {
    +    //  canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  GridRenderContainer.prototype.getViewPortStyle = function () {
    +    var self = this;
    +    var styles = {};
    +
    +    if (self.name === 'body') {
    +      styles['overflow-x'] = self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +      if (!self.grid.isRTL()) {
    +        if (self.grid.hasRightContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +      else {
    +        if (self.grid.hasLeftContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +    }
    +    else if (self.name === 'left') {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +    else {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = !self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +
    +    return styles;
    +
    +
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +
    +    this.$$height = grid.options.rowHeight;
    +
    +  }
    +
    +    /**
    +     *  @ngdoc object
    +     *  @name height
    +     *  @propertyOf  ui.grid.class:GridRow
    +     *  @description height of each individual row. changing the height will flag all
    +     *  row renderContainers to recalculate their canvas height
    +     */
    +    Object.defineProperty(GridRow.prototype, 'height', {
    +      get: function() {
    +        return this.$$height;
    +      },
    +      set: function(height) {
    +        if (height !== this.$$height) {
    +          this.grid.updateCanvasHeight();
    +          this.$$height = height;
    +        }
    +      }
    +    });
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +    GridRow.prototype.getQualifiedColField = function(col) {
    +      return 'row.' + this.getEntityQualifiedColField(col);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  angular.module('ui.grid')
    +    .factory('ScrollEvent', ['gridUtil', function (gridUtil) {
    +
    +      /**
    +       * @ngdoc function
    +       * @name ui.grid.class:ScrollEvent
    +       * @description Model for all scrollEvents
    +       * @param {Grid} grid that owns the scroll event
    +       * @param {GridRenderContainer} sourceRowContainer that owns the scroll event. Can be null
    +       * @param {GridRenderContainer} sourceColContainer that owns the scroll event. Can be null
    +       * @param {string} source the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName
    +       */
    +      function ScrollEvent(grid, sourceRowContainer, sourceColContainer, source) {
    +        var self = this;
    +        if (!grid) {
    +          throw new Error("grid argument is required");
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name grid
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description A reference back to the grid
    +         */
    +         self.grid = grid;
    +
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name entity
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description the source of the scroll event. limited to values from uiGridConstants.scrollEventSources
    +         */
    +        self.source = source;
    +
    +        self.sourceRowContainer = sourceRowContainer;
    +        self.sourceColContainer = sourceColContainer;
    +
    +        self.newScrollLeft = null;
    +        self.newScrollTop = null;
    +        self.x = null;
    +        self.y = null;
    +
    +
    +        /**
    +         *  @ngdoc function
    +         *  @name fireThrottledScrollingEvent
    +         *  @methodOf  ui.grid.class:ScrollEvent
    +         *  @description fires a throttled event using grid.api.core.raise.scrollEvent
    +         */
    +        self.fireThrottledScrollingEvent = gridUtil.throttle(function() {
    +          self.grid.api.core.raise.scrollEvent(self);
    +        }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      }
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name fireScrollingEvent
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description fires an event using grid.api.core.raise.scrollEvent
    +       */
    +      ScrollEvent.prototype.fireScrollingEvent = function() {
    +        this.grid.api.core.raise.scrollEvent(this);
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollLeft
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollLeft property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollLeft = function(colContainer, viewport){
    +        var self = this;
    +
    +        if (!self.newScrollLeft){
    +          var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +          var oldScrollLeft = gridUtil.normalizeScrollLeft(viewport);
    +
    +          var scrollXPercentage;
    +          if (typeof(self.x.percentage) !== 'undefined' && self.x.percentage !== undefined) {
    +            scrollXPercentage = self.x.percentage;
    +          }
    +          else if (typeof(self.x.pixels) !== 'undefined' && self.x.pixels !== undefined) {
    +            scrollXPercentage = self.x.percentage = (oldScrollLeft + self.x.pixels) / scrollWidth;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event X axis");
    +          }
    +
    +          return Math.max(0, scrollXPercentage * scrollWidth);
    +        }
    +
    +        return self.newScrollLeft;
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollTop
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollTop property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollTop = function(rowContainer, viewport){
    +        var self = this;
    +
    +
    +        if (!self.newScrollTop){
    +          var scrollLength = rowContainer.getVerticalScrollLength();
    +
    +          var oldScrollTop = viewport[0].scrollTop;
    +
    +          var scrollYPercentage;
    +          if (typeof(self.y.percentage) !== 'undefined' && self.y.percentage !== undefined) {
    +            scrollYPercentage = self.y.percentage;
    +          }
    +          else if (typeof(self.y.pixels) !== 'undefined' && self.y.pixels !== undefined) {
    +            scrollYPercentage = self.y.percentage = (oldScrollTop + self.y.pixels) / scrollLength;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +          }
    +
    +          return Math.max(0, scrollYPercentage * scrollLength);
    +        }
    +
    +        return self.newScrollTop;
    +      };
    +
    +
    +      ScrollEvent.Sources = {
    +        ViewPortScroll: 'ViewPortScroll',
    +        RenderContainerMouseWheel: 'RenderContainerMouseWheel',
    +        RenderContainerTouchMove: 'RenderContainerTouchMove',
    +        Other: 99
    +      };
    +
    +      return ScrollEvent;
    +    }]);
    +
    +
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Row builder for custom row templates
    +          grid.registerRowBuilder(service.rowTemplateAssigner);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        },
    +
    +        rowTemplateAssigner: function rowTemplateAssigner(row) {
    +          var grid = this;
    +
    +          // Row has no template assigned to it
    +          if (!row.rowTemplate) {
    +            // Use the default row template from the grid
    +            row.rowTemplate = grid.options.rowTemplate;
    +
    +            // Use the grid's function for fetching the compiled row template function
    +            row.getRowTemplateFn = grid.getRowTemplateFn;
    +          }
    +          // Row has its own template assigned
    +          else {
    +            // Create a promise for the compiled row template function
    +            var perRowTemplateFnPromise = $q.defer();
    +            row.getRowTemplateFn = perRowTemplateFnPromise.promise;
    +
    +            // Get the row template
    +            gridUtil.getTemplate(row.rowTemplate)
    +              .then(function (template) {
    +                // Compile the template
    +                var rowTemplateFn = $compile(template);
    +                
    +                // Resolve the compiled template function promise
    +                perRowTemplateFnPromise.resolve(rowTemplateFn);
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
    +              });
    +          }
    +
    +          return row.getRowTemplateFn;
    +        }
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setupFilters
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +   * do all the parsing and pre-processing and store that data into a new filters object.  The object
    +   * has the condition, the flags, the stripped term, and a parsed reg exp if there was one.
    +   * 
    +   * We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +   * for loops everywhere else in this module...
    +   * 
    +   * @param {array} filters the filters from the column (col.filters or [col.filter])
    +   * @returns {array} An array of parsed/preprocessed filters
    +   */
    +  rowSearcher.setupFilters = function setupFilters( filters ){
    +    var newFilters = [];
    +    
    +    var filtersLength = filters.length;
    +    for ( var i = 0; i < filtersLength; i++ ){
    +      var filter = filters[i];
    +      if ( filter.noTerm || filter.term ){
    +        var newFilter = {};
    +        
    +        var regexpFlags = '';
    +        if (!filter.flags || !filter.flags.caseSensitive) {
    +          regexpFlags += 'i';
    +        }
    +    
    +        if ( filter.term ){
    +          // it is possible to have noTerm.  We don't need to copy that across, it was just a flag to avoid
    +          // getting the filter ignored if the filter was a function that didn't use a term
    +          newFilter.term = rowSearcher.stripTerm(filter);
    +        }
    +        
    +        if ( filter.condition ){
    +          newFilter.condition = filter.condition;
    +        } else {
    +          newFilter.condition = rowSearcher.guessCondition(filter);
    +        }
    +
    +        newFilter.flags = angular.extend( { caseSensitive: false, date: false }, filter.flags );
    +
    +        if (newFilter.condition === uiGridConstants.filter.STARTS_WITH) {
    +          newFilter.startswithRE = new RegExp('^' + newFilter.term, regexpFlags);
    +        }
    +        
    +         if (newFilter.condition === uiGridConstants.filter.ENDS_WITH) {
    +          newFilter.endswithRE = new RegExp(newFilter.term + '$', regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.CONTAINS) {
    +          newFilter.containsRE = new RegExp(newFilter.term, regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.EXACT) {
    +          newFilter.exactRE = new RegExp('^' + newFilter.term + '$', regexpFlags);
    +        }
    +        
    +        newFilters.push(newFilter);
    +      }
    +    }
    +    return newFilters;
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name runColumnFilter
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Runs a single pre-parsed filter against a cell, returning true
    +   * if the cell matches that one filter.
    +   * 
    +   * @param {Grid} grid the grid we're working against
    +   * @param {GridRow} row the row we're matching against
    +   * @param {GridCol} column the column that we're working against
    +   * @param {object} filter the specific, preparsed, filter that we want to test
    +   * @returns {boolean} true if we match (row stays visible)
    +   */
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Term to search for.
    +    var term = filter.term;
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +    
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      return filter.condition.test(value);
    +    }
    +
    +    // If the filter's condition is a function, run it
    +    if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    
    +    if (filter.startswithRE) {
    +      return filter.startswithRE.test(value);
    +    }
    +    
    +    if (filter.endswithRE) {
    +      return filter.endswithRE.test(value);
    +    }
    +    
    +    if (filter.containsRE) {
    +      return filter.containsRE.test(value);
    +    }
    +    
    +    if (filter.exactRE) {
    +      return filter.exactRE.test(value);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      var regex = new RegExp('^' + term + '$');
    +      return !regex.exec(value);
    +    }
    +
    +    if (typeof(value) === 'number'){
    +      // if the term has a decimal in it, it comes through as '9\.4', we need to take out the \
    +      var tempFloat = parseFloat(term.replace(/\\./,'.'));
    +      if (!isNaN(tempFloat)) {
    +        term = tempFloat;
    +      }
    +    }
    +
    +    if (filter.flags.date === true) {
    +      value = new Date(value);
    +      // If the term has a dash in it, it comes through as '\-' -- we need to take out the '\'.
    +      term = new Date(term.replace(/\\/g, ''));
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      return (value > term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      return (value >= term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      return (value < term);
    +    }
    +    
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      return (value <= term);
    +    }
    +    
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process provided filters on provided column against a given row. If the row meets 
    +   * the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @param {array} filters array of pre-parsed/preprocessed filters to apply
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, filters) {
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    var filtersLength = filters.length;
    +    for (var i = 0; i < filtersLength; i++) {
    +      var filter = filters[i];
    +      
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across the given rows and columns, marking any rows that don't 
    +   * match the stored col.filters or col.filter as invisible.
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    /*
    +     * Added performance optimisations into this code base, as this logic creates deeply nested
    +     * loops and is therefore very performance sensitive.  In particular, avoiding forEach as
    +     * this impacts some browser optimisers (particularly Chrome), using iterators instead
    +     */
    +    
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Build list of filters to apply
    +    var filterData = [];
    +
    +    var colsLength = columns.length;
    +    for (var i = 0; i < colsLength; i++) {
    +      var col = columns[i];
    +      
    +      if (typeof(col.filters) !== 'undefined' && ( col.filters.length > 1 || col.filters.length === 1 && ( typeof(col.filters[0].term) !== 'undefined' && col.filters[0].term || col.filters[0].noTerm ) ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters(col.filters) } );
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters([col.filter]) } );
    +      }
    +    }
    +    
    +    if (filterData.length > 0) {
    +      // define functions outside the loop, performance optimisation
    +      var foreachRow = function(grid, row, col, filters){
    +        if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, filters)) {
    +          row.visible = false;
    +        }
    +      };
    +      
    +      var foreachFilterCol = function(grid, filterData){
    +        var rowsLength = rows.length;
    +        for ( var i = 0; i < rowsLength; i++){
    +          foreachRow(grid, rows[i], filterData.col, filterData.filters);  
    +        }
    +      };
    +
    +      // nested loop itself - foreachFilterCol, which in turn calls foreachRow
    +      var filterDataLength = filterData.length;
    +      for ( var j = 0; j < filterDataLength; j++){
    +        foreachFilterCol( grid, filterData[j] );  
    +      }
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toString().toLowerCase(),
    +          strB = b.toString().toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +    
    +    // put a custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( rows, function ( row, idx ) {
    +      row.entity.$uiGridIndex = idx;
    +    });
    +
    +    // Now actually sort the data
    +    var newRows = rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Chrome doesn't implement a stable sort function.  If our sort returns 0 
    +      // (i.e. the items are equal), then return the previous order using our custom
    +      // index variable
    +      if (tem === 0 ) {
    +        return rowA.entity.$uiGridIndex - rowB.entity.$uiGridIndex;
    +      }
    +      
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +    
    +    // remove the custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( newRows, function ( row, idx ) {
    +      delete row.entity.$uiGridIndex;
    +    });
    +    
    +    return newRows;
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +var bindPolyfill;
    +if (typeof Function.prototype.bind !== "function") {
    +  bindPolyfill = function() {
    +    var slice = Array.prototype.slice;
    +    return function(context) {
    +      var fn = this,
    +        args = slice.call(arguments, 1);
    +      if (args.length) {
    +        return function() {
    +          return arguments.length ? fn.apply(context, args.concat(slice.call(arguments))) : fn.apply(context, args);
    +        };
    +      }
    +      return function() {
    +        return arguments.length ? fn.apply(context, arguments) : fn.call(context);
    +      };
    +    };
    +  };
    +}
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +function getLineHeight(elm) {
    +  elm = angular.element(elm)[0];
    +  var parent = elm.offsetParent;
    +
    +  if (!parent) {
    +    parent = document.getElementsByTagName('body')[0];
    +  }
    +
    +  return parseInt( getStyles(parent).fontSize ) || parseInt( getStyles(elm).fontSize ) || 16;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  s.on = {};
    +  s.off = {};
    +  s._events = {};
    +
    +  s.addOff = function (eventName) {
    +    s.off[eventName] = function (elm, fn) {
    +      var idx = s._events[eventName].indexOf(fn);
    +      if (idx > 0) {
    +        s._events[eventName].removeAt(idx);
    +      }
    +    };
    +  };
    +
    +  var mouseWheeltoBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
    +      nullLowestDeltaTimeout,
    +      lowestDelta;
    +
    +  s.on.mousewheel = function (elm, fn) {
    +    if (!elm || !fn) { return; }
    +
    +    var $elm = angular.element(elm);
    +
    +    // Store the line height and page height for this particular element
    +    $elm.data('mousewheel-line-height', getLineHeight($elm));
    +    $elm.data('mousewheel-page-height', s.elementHeight($elm));
    +    if (!$elm.data('mousewheel-callbacks')) { $elm.data('mousewheel-callbacks', {}); }
    +
    +    var cbs = $elm.data('mousewheel-callbacks');
    +    cbs[fn] = (Function.prototype.bind || bindPolyfill).call(mousewheelHandler, $elm[0], fn);
    +
    +    // Bind all the mousew heel events
    +    for ( var i = mouseWheeltoBind.length; i; ) {
    +      $elm.on(mouseWheeltoBind[--i], cbs[fn]);
    +    }
    +  };
    +  s.off.mousewheel = function (elm, fn) {
    +    var $elm = angular.element(this);
    +
    +    var cbs = $elm.data('mousewheel-callbacks');
    +    var handler = cbs[fn];
    +
    +    if (handler) {
    +      for ( var i = mouseWheeltoBind.length; i; ) {
    +        $elm.off(mouseWheeltoBind[--i], handler);
    +      }
    +    }
    +
    +    delete cbs[fn];
    +
    +    if (Object.keys(cbs).length === 0) {
    +      $elm.removeData('mousewheel-line-height');
    +      $elm.removeData('mousewheel-page-height');
    +      $elm.removeData('mousewheel-callbacks');
    +    }
    +  };
    +
    +  function mousewheelHandler(fn, event) {
    +    var $elm = angular.element(this);
    +
    +    var delta      = 0,
    +        deltaX     = 0,
    +        deltaY     = 0,
    +        absDelta   = 0,
    +        offsetX    = 0,
    +        offsetY    = 0;
    +
    +    // jQuery masks events
    +    if (event.originalEvent) { event = event.originalEvent; }
    +
    +    if ( 'detail'      in event ) { deltaY = event.detail * -1;      }
    +    if ( 'wheelDelta'  in event ) { deltaY = event.wheelDelta;       }
    +    if ( 'wheelDeltaY' in event ) { deltaY = event.wheelDeltaY;      }
    +    if ( 'wheelDeltaX' in event ) { deltaX = event.wheelDeltaX * -1; }
    +
    +    // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
    +    if ( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
    +      deltaX = deltaY * -1;
    +      deltaY = 0;
    +    }
    +
    +    // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
    +    delta = deltaY === 0 ? deltaX : deltaY;
    +
    +    // New school wheel delta (wheel event)
    +    if ( 'deltaY' in event ) {
    +      deltaY = event.deltaY * -1;
    +      delta  = deltaY;
    +    }
    +    if ( 'deltaX' in event ) {
    +      deltaX = event.deltaX;
    +      if ( deltaY === 0 ) { delta  = deltaX * -1; }
    +    }
    +
    +    // No change actually happened, no reason to go any further
    +    if ( deltaY === 0 && deltaX === 0 ) { return; }
    +
    +    // Need to convert lines and pages to pixels if we aren't already in pixels
    +    // There are three delta modes:
    +    //   * deltaMode 0 is by pixels, nothing to do
    +    //   * deltaMode 1 is by lines
    +    //   * deltaMode 2 is by pages
    +    if ( event.deltaMode === 1 ) {
    +        var lineHeight = $elm.data('mousewheel-line-height');
    +        delta  *= lineHeight;
    +        deltaY *= lineHeight;
    +        deltaX *= lineHeight;
    +    }
    +    else if ( event.deltaMode === 2 ) {
    +        var pageHeight = $elm.data('mousewheel-page-height');
    +        delta  *= pageHeight;
    +        deltaY *= pageHeight;
    +        deltaX *= pageHeight;
    +    }
    +
    +    // Store lowest absolute delta to normalize the delta values
    +    absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
    +
    +    if ( !lowestDelta || absDelta < lowestDelta ) {
    +      lowestDelta = absDelta;
    +
    +      // Adjust older deltas if necessary
    +      if ( shouldAdjustOldDeltas(event, absDelta) ) {
    +        lowestDelta /= 40;
    +      }
    +    }
    +
    +    // Get a whole, normalized value for the deltas
    +    delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
    +    deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
    +    deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
    +
    +    event.deltaMode = 0;
    +
    +    // Normalise offsetX and offsetY properties
    +    // if ($elm[0].getBoundingClientRect ) {
    +    //   var boundingRect = $(elm)[0].getBoundingClientRect();
    +    //   offsetX = event.clientX - boundingRect.left;
    +    //   offsetY = event.clientY - boundingRect.top;
    +    // }
    +    
    +    // event.deltaX = deltaX;
    +    // event.deltaY = deltaY;
    +    // event.deltaFactor = lowestDelta;
    +
    +    var newEvent = {
    +      originalEvent: event,
    +      deltaX: deltaX,
    +      deltaY: deltaY,
    +      deltaFactor: lowestDelta,
    +      preventDefault: function () { event.preventDefault(); }
    +    };
    +
    +    // Clearout lowestDelta after sometime to better
    +    // handle multiple device types that give
    +    // a different lowestDelta
    +    // Ex: trackpad = 3 and mouse wheel = 120
    +    if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
    +    nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
    +
    +    fn.call($elm[0], newEvent);
    +  }
    +
    +  function nullLowestDelta() {
    +    lowestDelta = null;
    +  }
    +
    +  function shouldAdjustOldDeltas(orgEvent, absDelta) {
    +    // If this is an older event and the delta is divisable by 120,
    +    // then we are assuming that the browser is treating this as an
    +    // older mouse wheel event and that we should divide the deltas
    +    // by 40 to try and get a more usable deltaFactor.
    +    // Side note, this actually impacts the reported scroll distance
    +    // in older browsers and can cause scrolling to be slower than native.
    +    // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
    +    return orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
    +  }
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'Eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +            pinLeft: 'Links anheften',
    +            pinRight: 'Rechts anheften',
    +            unpin: 'Lösen'
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        },
    +        pagination: {
    +            sizes: 'Einträge pro Seite',
    +            totalItems: 'Einträge'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        pagination: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        },
    +        pagination: {
    +          sizes: 'articles par page',
    +          totalItems: 'articles'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ja', {
    +        aggregate: {
    +          label: '件'
    +        },
    +        groupPanel: {
    +          description: '列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。'
    +        },
    +        search: {
    +          placeholder: '検索...',
    +          showingItems: '絞込み件数:',
    +          selectedItems: '選択件数:',
    +          totalItems: '全件数:',
    +          size: 'ページサイズ: ',
    +          first: '最初のページ',
    +          next: '次のページ',
    +          previous: '前のページ',
    +          last: '最後のページ'
    +        },
    +        menu: {
    +          text: '列選択:'
    +        },
    +        sort: {
    +          ascending: '昇順ソート',
    +          descending: '降順ソート',
    +          remove: 'ソート取消'
    +        },
    +        column: {
    +          hide: '列を隠す'
    +        },
    +        aggregation: {
    +          count: '合計件数: ',
    +          sum: '合計: ',
    +          avg: '平均: ',
    +          min: '最小値: ',
    +          max: '最大値: '
    +        },
    +        pinning: {
    +          pinLeft: '左にピン留め',
    +          pinRight: '右にピン留め',
    +          unpin: 'ピン留め取消'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: 'インポートファイル',
    +          exporterAllAsCsv: '全てのデータをCSV形式でエクスポート',
    +          exporterVisibleAsCsv: '絞込み済みデータをCSV形式でエクスポート',
    +          exporterSelectedAsCsv: '選択しているデータをCSV形式でエクスポート',
    +          exporterAllAsPdf: '全てのデータをPDFでエクスポート',
    +          exporterVisibleAsPdf: '絞込み済みデータをPDFでエクスポート',
    +          exporterSelectedAsPdf: '選択しているデータをPDFでエクスポート'
    +        },
    +        importer: {
    +          noHeaders: '列名が抽出できません。ヘッダーは設定されていますか?',
    +          noObjects: 'データが抽出できません。ファイルにデータは含まれていますか?',
    +          invalidCsv: '処理を行うことができません。ファイルは有効なCSVファイルですか?',
    +          invalidJson: '処理を行うことができません。ファイルは有効なJSONファイルですか?',
    +          jsonNotArray: 'JSONファイルは配列を含んでいる必要があります。処理を中断します。'
    +        },
    +        pagination: {
    +          sizes: '件 / ページ',
    +          totalItems: '件'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'всего строк: ',
    +          sum: 'итого: ',
    +          avg: 'среднее: ',
    +          min: 'мин: ',
    +          max: 'макс: '
    +        },
    +        gridMenu: {
    +          columns: 'Столбцы:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Экспортировать всё в CSV',
    +          exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
    +          exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
    +          exporterAllAsPdf: 'Экспортировать всё в PDF',
    +          exporterVisibleAsPdf: 'Экспортировать видимые данные в PDF',
    +          exporterSelectedAsPdf: 'Экспортировать выбранные данные в PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        pagination: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        },
    +        pagination: {
    +          sizes: '行每页',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        },
    +        pagination: {
    +          sizes: '行每頁',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3, PG_UP: 4, PG_DOWN: 5},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1,
    +      CLEAR: 2
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +        this.bodyContainer = rowContainer;
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.api:GridRow
    +       *
    +       *  @description GridRow settings for cellNav feature, these are available to be
    +       *  set only internally (for example, by other features)
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name allowCellFocus
    +       *  @propertyOf  ui.grid.cellNav.api:GridRow
    +       *  @description Enable focus on a cell within this row.  If set to false then no cells
    +       *  in this row can be focused - group header rows as an example would set this to false.
    +       *  <br/>Defaults to true
    +       */
    +      /** returns focusable rows */
    +      UiGridCellNav.prototype.getFocusableRows = function () {
    +        return this.rows.filter(function(row) {
    +          return row.allowCellFocus !== false;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_UP:
    +            return this.getRowColPageUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_DOWN:
    +            return this.getRowColPageDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          // On the first row
    +          // if (curRowIndex === 0 && curColIndex === 0) {
    +          //   return null;
    +          // }
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(focusableRows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === focusableRows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(focusableRows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === focusableRows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(focusableRows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex >= focusableRows.length - pageSize) {
    +          return new RowCol(focusableRows[focusableRows.length - 1], focusableCols[curColIndex]); //return last row
    +        }
    +        else {
    +          //down one page
    +          return new RowCol(focusableRows[curRowIndex + pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(focusableRows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex - pageSize < 0) {
    +          return new RowCol(focusableRows[0], focusableCols[curColIndex]); //return first row
    +        }
    +        else {
    +          //up one page
    +          return new RowCol(focusableRows[curRowIndex - pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory', 'ScrollEvent',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav, ScrollEvent) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +          grid.cellNav.focusedCells = [];
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (rowEntity, colDef) {
    +                  service.scrollTo(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view, and sets focus
    +                 * to that cell
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus
    +                 * @param {object} colDef to make visible and set focus
    +                 */
    +                scrollToFocus: function (rowEntity, colDef) {
    +                  service.scrollToFocus(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column fully into view if it isn't already
    +                 * @param {GridRow} row grid row that we should make fully visible
    +                 * @param {GridCol} col grid col to make fully visible
    +                 */
    +                scrollToIfNecessary: function (row, col) {
    +                  service.scrollToIfNecessary(grid, row, col);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getCurrentSelection
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns an array containing the current selection
    +                 * <br> array is empty if no selection has occurred
    +                 */
    +                getCurrentSelection: function () {
    +                  return grid.cellNav.focusedCells;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name rowColSelectIndex
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +                 * isn't selected
    +                 * @param {object} rowCol the rowCol to evaluate
    +                 */
    +                rowColSelectIndex: function (rowCol) {
    +                  //return gridUtil.arrayContainsObjectWithProperty(grid.cellNav.focusedCells, 'col.uid', rowCol.col.uid) &&
    +                  var index = -1;
    +                  for (var i = 0; i < grid.cellNav.focusedCells.length; i++) {
    +                    if (grid.cellNav.focusedCells[i].col.uid === rowCol.col.uid &&
    +                      grid.cellNav.focusedCells[i].row.uid === rowCol.row.uid) {
    +                      index = i;
    +                      break;
    +                    }
    +                  }
    +                  return index;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:GridOptions
    +           *
    +           *  @description GridOptions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelectCells
    +           *  @propertyOf  ui.grid.cellNav.api:GridOptions
    +           *  @description Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelectCells = gridOptions.modifierKeysToMultiSelectCells === true;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_UP){
    +            return uiGridCellNavConstants.direction.PG_UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_DOWN){
    +            return uiGridCellNavConstants.direction.PG_DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell within this column.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null && typeof(rowEntity) !== 'undefined' ) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null && typeof(colDef) !== 'undefined' ) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToFocus
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view, and set focus to the cell in that row and column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus to
    +         * @param {object} colDef to make visible and set focus to
    +         */
    +        scrollToFocus: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +
    +          var rowCol = { row: gridRow, col: gridCol };
    +
    +          // Broadcast the navigation
    +          grid.cellNav.broadcastCellNav(rowCol);
    +
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         *
    +         * To get to row 9 (i.e. the last row) in the same list, we want to
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll,
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToInternal');
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            scrollEvent.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            scrollEvent.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid, 'uiGridCellNavService.scrollToIfNecessary');
    +
    +          // Alias the visible row and column caches
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          //if (grid.horizontalScrollbarHeight) {
    +          //  bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          //}
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + Math.ceil(grid.gridWidth);
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          //if (grid.verticalScrollbarWidth) {
    +          //  rightBound = rightBound - grid.verticalScrollbarWidth;
    +          //}
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            //if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +            //  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            //}
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;
    +            }
    +          });
    +
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var _scope = $scope;
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = grid.cellNav.broadcastCellNav = function (newRowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol, modifierDown);
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol, modifierDown);
    +              };
    +
    +              uiGridCtrl.cellNav.clearFocus = grid.cellNav.clearFocus = function () {
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, { eventType: uiGridCellNavConstants.EVENT_TYPE.CLEAR });
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +
    +                var row = rowCol.row,
    +                  col = rowCol.col;
    +
    +                var rowColSelectIndex = uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol);
    +
    +                if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                  if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
    +                    grid.cellNav.focusedCells.push(rowCol);
    +                  } else {
    +                    grid.cellNav.focusedCells = [rowCol];
    +                  }
    +                } else if (grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                  rowColSelectIndex >= 0) {
    +
    +                  grid.cellNav.focusedCells.splice(rowColSelectIndex, 1);
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  // Shift+tab on top-left cell should exit cellnav on render container
    +                  if (
    +                    // Navigating left
    +                    direction === uiGridCellNavConstants.direction.LEFT &&
    +                    // Trying to stay on same row
    +                    rowCol.row === lastRowCol.row &&
    +                    evt.keyCode === uiGridConstants.keymap.TAB &&
    +                    evt.shiftKey
    +                  ) {
    +                    uiGridCtrl.cellNav.clearFocus();
    +                    return true;
    +                  }
    +                  // Tab on bottom-right cell should exit cellnav on render container
    +                  else if (
    +                    direction === uiGridCellNavConstants.direction.RIGHT &&
    +                    rowCol.row === lastRowCol.row &&
    +                    evt.keyCode === uiGridConstants.keymap.TAB &&
    +                    !evt.shiftKey
    +                  ) {
    +                    uiGridCtrl.cellNav.clearFocus();
    +                    return true;
    +                  }
    +
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                 renderContainerCtrl = controllers[1];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              var needFocus = false;
    +              
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              grid.api.core.on.scrollEvent($scope, function (args) {
    +                // Skip if not this grid that the event was broadcast for
    +                if (args.grid && args.grid.id !== uiGridCtrl.grid.id) {
    +                  return;
    +                }
    +
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +                
    +                /*
    +                 * If we have scrolled due to cellNav, we want to set the focus to the new cell after the 
    +                 * virtualisation has run, and after scroll.  If we scrolled through the browser scroll
    +                 * bar or other user action, we're going to discard the focus, because it will no longer 
    +                 * be valid (and, noting #2423, trying to keep it causes problems)
    +                 * 
    +                 * If cellNav triggers the scroll, we get a scrollToIfNecessary, then a viewport scroll. We
    +                 * want to wait for the viewport scroll to finish, then do a refocus.  
    +                 * 
    +                 * If someone manually scrolls we get just the viewport scroll, no scrollToIfNecessary.  We
    +                 * want to just clear the focus
    +                 * 
    +                 * Logic is:
    +                 *  - if cellNav scroll, set a flag that will be resolved in the native scroll
    +                 *  - if native scroll, look for the cellNav promise and resolve it
    +                 *    - if not present, then use a timeout to clear focus
    +                 *    - if it is present, then instead use a timeout to set focus
    +                 */ 
    +                
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                if ( args.source === 'uiGridCellNavService.scrollToIfNecessary'){
    +                  needFocus = true;
    +/*
    +                  focusTimeout = $timeout(function () {
    +                    if ( clearFocusTimeout ){
    +                      $timeout.cancel(clearFocusTimeout);
    +                    }
    +                    focusTimeout = $timeout(function () {
    +                      if ( clearFocusTimeout ){
    +                        $timeout.cancel(clearFocusTimeout);
    +                      }
    +                      // Get the last row+col combo
    +                      var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +  
    +                      // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                      //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                      //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                      if ($document.activeElement === $document.body) {
    +                        $elm[0].focus();
    +                      }
    +  
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                    });
    +                  });
    +                  */
    +                } else {
    +                  if ( needFocus ){
    +                    $timeout(function () {
    +                      $timeout(function () {
    +                        // Get the last row+col combo
    +                        var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +    
    +                        // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                        //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                        //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                        if ($document.activeElement === $document.body) {
    +                          $elm[0].focus();
    +                        }
    +    
    +                        // broadcast a cellNav event so we clear the focus on all cells
    +                        uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                        
    +                        needFocus = false;
    +                      });
    +                    });
    +                  }
    +                }
    +              });  
    +             
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +
    +            evt.stopPropagation();
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            console.log('cellNav focus');
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol, modifierDown) {
    +            if (evt.eventType === uiGridCellNavConstants.EVENT_TYPE.CLEAR) {
    +              clearFocus();
    +              return;
    +            }
    +
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol) === -1) {
    +                clearFocus();
    +              } else {
    +                setFocused();
    +              }
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                console.log('focus from navEvent');
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else if (!(uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown)) {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", 0);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.api:GridRow
    +   *
    +   *  @description GridRow options for edit feature, these are available to be
    +   *  set internally only, by other features
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableCellEdit
    +   *  @propertyOf  ui.grid.edit.api:GridRow
    +   *  @description enable editing on row, grouping for example might disable editing on group header rows
    +   */
    +
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        var touchstartTimeout = 500;
    +
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit || $scope.row.enableCellEdit === false) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +            var cancelTouchstartTimeout;
    +
    +            var editCellScope;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +
    +              // Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
    +              $elm.on('touchstart', touchStart);
    +            }
    +
    +            function touchStart(event) {
    +              // jQuery masks events
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +
    +              // Bind touchend handler
    +              $elm.on('touchend', touchEnd);
    +
    +              // Start a timeout
    +              cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
    +
    +              // Timeout's done! Start the edit
    +              cancelTouchstartTimeout.then(function () {
    +                // Use setTimeout to start the edit because beginEdit expects to be outside of $digest
    +                setTimeout(beginEdit, 0);
    +
    +                // Undbind the touchend handler, we don't need it anymore
    +                $elm.off('touchend', touchEnd);
    +              });
    +            }
    +
    +            // Cancel any touchstart timeout
    +            function touchEnd(event) {
    +              $timeout.cancel(cancelTouchstartTimeout);
    +              $elm.off('touchend', touchEnd);
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +              $elm.off('touchstart', touchStart);
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving &&
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownRowEntityOptionsArrayPath
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description a path to a property on row.entity containing an
    +             *  array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which will be used to populate
    +             *  the edit dropdown.  This can be used when the dropdown values are dependent on
    +             *  the backing row entity.
    +             *  If this property is set then editDropdownOptionsArray will be ignored.
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              // if the cell isn't fully visible, and cellNav is present, scroll it to be fully visible before we start
    +              if ( $scope.grid.api.cellNav ){
    +                $scope.grid.api.cellNav.scrollToIfNecessary( $scope.row, $scope.col );
    +              }
    +              
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              var inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  inputType = 'number';
    +                  break;
    +                case 'date':
    +                  inputType = 'date';
    +                  break;
    +              }
    +              html = html.replace('INPUT_TYPE', inputType);
    +
    +              var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
    +              if (editDropdownRowEntityOptionsArrayPath) {
    +                $scope.editDropdownOptionsArray =  resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
    +              }
    +              else {
    +                $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              }
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                editCellScope = $scope.$new();
    +                $compile(cellElement)(editCellScope);
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.col.grid.api.core.on.scrollEvent($scope, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +                deregOnGridScroll();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              editCellScope.$destroy();
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +            // resolves a string path against the given object
    +            // shamelessly borrowed from
    +            // http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
    +            function resolveObjectFromPath(object, path) {
    +              path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    +              path = path.replace(/^\./, '');           // strip a leading dot
    +              var a = path.split('.');
    +              while (a.length) {
    +                  var n = a.shift();
    +                  if (n in object) {
    +                      object = object[n];
    +                  } else {
    +                      return;
    +                  }
    +              }
    +              return object;
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
    +      function (gridUtil, uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +               $scope.deepEdit = false;
    +
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('uiGridEditor', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        priority: -100, // run after default uiGridEditor directive
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.expandable.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        grid.expandable = {};
    +        grid.expandable.expandedAll = false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name 
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Width in pixels of the expandable column. Defaults to 40
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeaderWidth: 40
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name toggleAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.toggleAllRows();
    +               * </pre>
    +               */              
    +              toggleAllRows: function() {
    +                service.toggleAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +          grid.expandable.expandedAll = false;
    +        }
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = true;
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = false;
    +        grid.refresh();
    +      },
    +
    +      toggleAllRows: function(grid) {
    +        if (grid.expandable.expandedAll) {
    +          service.collapseAllRows(grid);
    +        }
    +        else {
    +          service.expandAllRows(grid);
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {
    +                  name: 'expandableButtons', 
    +                  displayName: '', 
    +                  exporterSuppressExport: true, 
    +                  enableColumnResizing: false, 
    +                  enableColumnMenu: false,
    +                  width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
    +                };
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGrid
    +   *  @description stacks on the uiGrid directive to register child grid with parent row when child is created
    +   */
    +  module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 1000,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
    +                //if a parent grid row is on the scope, then add the parentRow property to this childGrid
    +                if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
    +
    +                  /**
    +                   *  @ngdoc directive
    +                   *  @name ui.grid.expandable.class:Grid
    +                   *  @description Additional Grid properties added by expandable module
    +                   */
    +
    +                  /**
    +                   *  @ngdoc object
    +                   *  @name parentRow
    +                   *  @propertyOf ui.grid.expandable.class:Grid
    +                   *  @description reference to the expanded parent row that owns this grid
    +                   */
    +                  uiGridCtrl.grid.parentRow = $scope.row;
    +
    +                  //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
    +                 // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
    +                 //   uiGridCtrl.grid.parentRow = newHeight;
    +                 // });
    +                }
    +
    +              });
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridExpandableRow
    +   *  @description directive to render the expandable row template
    +   */
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridRow
    +   *  @description stacks on the uiGridRow directive to add support for expandable rows
    +   */
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridViewport
    +   *  @description stacks on the uiGridViewport directive to append the expandable row html elements to the
    +   *  default gridRow template
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    BUTTON_LABEL: 'BUTTON_LABEL',
    +    FILE_NAME: 'FILE_NAME'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                csvExport: function (rowTypes, colTypes) {
    +                  service.csvExport(grid, rowTypes, colTypes);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for exporter feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:ColumnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvFilename
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default filename to use when saving the downloaded csv.  
    +           * This will only work in some browsers.
    +           * <br/>Defaults to 'download.csv'
    +           */
    +          gridOptions.exporterCsvFilename = gridOptions.exporterCsvFilename ? gridOptions.exporterCsvFilename : 'download.csv';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilterUseName
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Defaults to false, which leads to `displayName` being passed into the headerFilter.
    +           * If set to true, then will pass `name` instead.
    +           * 
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilterUseName = true;
    +           * </pre>
    +           */
    +          gridOptions.exporterHeaderFilterUseName = gridOptions.exporterHeaderFilterUseName === true;          
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * 
    +           * Behaviour can be changed to pass in `name` instead of `displayName` through use of `exporterHeaderFilterUseName: true`.
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +          
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        csvExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          this.downloadFile (grid.options.exporterCsvFilename, csvContent);
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterSuppressExport
    +         * @description Suppresses export for this column.  Used by selection and expandable.
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.colDef.exporterSuppressExport !== true &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? ( grid.options.exporterHeaderFilterUseName ? grid.options.exporterHeaderFilter(gridCol.name) : grid.options.exporterHeaderFilter(gridCol.displayName) ) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.exporter.api:GridRow
    +         * @description GridRow settings for exporter
    +         */
    +        /**
    +         * @ngdoc object
    +         * @name exporterEnableExporting
    +         * @propertyOf  ui.grid.exporter.api:GridRow
    +         * @description If set to false, then don't export this row, notwithstanding visible or 
    +         * other settings
    +         * <br/>Defaults to true
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate.  Any rows marked
    +         * `exporterEnableExporting: false` will not be exported
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            if (row.exporterEnableExporting !== false) {
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.colDef.exporterSuppressExport !== true &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                  if ( gridCol.colDef.exporterPdfAlign ) {
    +                    extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                  }
    +                  extractedRow.push(extractedField);
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            }
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name downloadFile
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Triggers download of a csv file.  Logic provided
    +         * by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391
    +         * @param {string} fileName the filename we'd like our file to be
    +         * given
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * download as a file
    +         */
    +        downloadFile: function (fileName, csvContent) {
    +          var D = document;
    +          var a = D.createElement('a');
    +          var strMimeType = 'application/octet-stream;charset=utf-8';
    +          var rawFile;
    +      
    +          // IE10+
    +          if (navigator.msSaveBlob) {
    +            return navigator.msSaveBlob(new Blob(["\ufeff", csvContent], {
    +              type: strMimeType
    +            }), fileName);
    +          }
    +      
    +          //html5 A[download]
    +          if ('download' in a) {
    +            var blob = new Blob([csvContent], {
    +              type: strMimeType
    +            });
    +            rawFile = URL.createObjectURL(blob);
    +            a.setAttribute('download', fileName);
    +          } else {
    +            rawFile = 'data:' + strMimeType + ',' + encodeURIComponent(csvContent);
    +            a.setAttribute('target', '_blank');
    +          }
    +      
    +          a.href = rawFile;
    +          a.setAttribute('style', 'display:none;');
    +          D.body.appendChild(a);
    +          setTimeout(function() {
    +            if (a.click) {
    +              a.click();
    +              // Workaround for Safari 5
    +            } else if (document.createEvent) {
    +              var eventObj = document.createEvent('MouseEvents');
    +              eventObj.initEvent('click', true, true);
    +              a.dispatchEvent(eventObj);
    +            }
    +            D.body.removeChild(a);
    +    
    +          }, 100);
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.header = grid.options.exporterPdfHeader;
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.footer = grid.options.exporterPdfFooter;
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( fileObject ) {
    +                  service.importThisFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and if the rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var dataChangeDereg = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( newObjects );
    +              dataChangeDereg();
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            grid.importer.$scope.$on( '$destroy', dataChangeDereg );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            var target = event.srcElement || event.target;
    +            
    +            if (target && target.files && target.files.length === 1) {
    +              var fileObject = target.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              target.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', function (gridUtil, $compile, $timeout, uiGridConstants) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              },
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreDataTop
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached top percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreDataTop: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
    +       */
    +
    +      loadData: function (grid) {
    +        grid.options.loadTimout = true;
    +        if (grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +          grid.api.infiniteScroll.raise.needLoadMoreDataTop();
    +          return;
    +        }
    +        grid.api.infiniteScroll.raise.needLoadMoreData();
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.grid.api.core.on.scrollEvent($scope, function (args) {
    +                  //Prevent circular scroll references, if source is coming from ui.grid.adjustInfiniteScrollPosition() function
    +                  if (args.y && (args.source !== 'ui.grid.adjustInfiniteScrollPosition')) {
    +                    var percentage = 100 - (args.y.percentage * 100);
    +                    if ($scope.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                      percentage = (args.y.percentage * 100);
    +                    }
    +                    uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                  }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', 'ScrollEvent', 'uiGridConstants', function ($q, $timeout, $log, ScrollEvent, uiGridConstants) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                var columns = grid.columns;
    +                if (!angular.isNumber(originalPosition) || !angular.isNumber(finalPosition)) {
    +                  console.log('Please provide valid values for originalPosition and finalPosition');
    +                  return;
    +                }
    +                var nonMovableColumns = 0;
    +                for (var i = 0; i < columns.length; i++) {
    +                  if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +                    nonMovableColumns++;
    +                  }
    +                }
    +                if (originalPosition >= (columns.length - nonMovableColumns) || finalPosition >= (columns.length - nonMovableColumns)) {
    +                  console.log('Invalid values for originalPosition, finalPosition');
    +                  return;
    +                }
    +                var findPositionForRenderIndex = function (index) {
    +                  var position = index;
    +                  for (var i = 0; i <= position; i++) {
    +                    if (angular.isDefined(columns[i]) && ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true)) {
    +                      position++;
    +                    }
    +                  }
    +                  return position;
    +                };
    +                self.redrawColumnAtPosition(grid, findPositionForRenderIndex(originalPosition), findPositionForRenderIndex(finalPosition));
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +
    +        var columns = grid.columns;
    +
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +            grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log', 'uiGridConstants', 'ScrollEvent',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log, uiGridConstants, ScrollEvent) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                $scope.$on(uiGridConstants.events.COLUMN_HEADER_CLICK, function (event, args) {
    +
    +                  if (args.columnName === $scope.col.colDef.name && !$scope.col.renderContainer) {
    +
    +                    var evt = args.event;
    +                    if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                      //Setting some variables required for calculations.
    +                      var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                      var previousMouseX = evt.pageX;
    +                      var totalMouseMovement = 0;
    +                      var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth();// - $scope.grid.verticalScrollbarWidth;
    +
    +                      //Clone element should move horizontally with mouse.
    +                      var elmCloned = false;
    +                      var movingElm;
    +                      var reducedWidth;
    +
    +                      var cloneElement = function () {
    +                        elmCloned = true;
    +
    +                        //Cloning header cell and appending to current header cell.
    +                        movingElm = $elm.clone();
    +                        $elm.parent().append(movingElm);
    +
    +                        //Left of cloned element should be aligned to original header cell.
    +                        movingElm.addClass('movingColumn');
    +                        var movingElementStyles = {};
    +                        var elmLeft = $elm[0].getBoundingClientRect().left;
    +                        movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                        var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                        var elmRight = $elm[0].getBoundingClientRect().right;
    +                        if (elmRight > gridRight) {
    +                          reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                          movingElementStyles.width = reducedWidth + 'px';
    +                        }
    +                        movingElm.css(movingElementStyles);
    +                      };
    +
    +                      var moveElement = function (changeValue) {
    +                        //Hide column menu
    +                        uiGridCtrl.fireEvent('hide-menu');
    +
    +                        //Calculate total column width
    +                        var columns = $scope.grid.columns;
    +                        var totalColumnWidth = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) {
    +                            totalColumnWidth += columns[i].drawnWidth || columns[i].width || columns[i].colDef.width;
    +                          }
    +                        }
    +
    +                        //Calculate new position of left of column
    +                        var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                        var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                        var newElementLeft;
    +                        if (gridUtil.detectBrowser() === 'ie') {
    +                          newElementLeft = currentElmLeft + changeValue;
    +                        }
    +                        else {
    +                          newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                        }
    +                        newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                        //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                        if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                          movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                        }
    +                        else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
    +                          changeValue *= 8;
    +                          var scrollEvent = new ScrollEvent($scope.col.grid, null, null, 'uiGridHeaderCell.moveElement');
    +                          scrollEvent.x = {pixels: changeValue};
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +
    +                        //Calculate total width of columns on the left of the moving column and the mouse movement
    +                        var totalColumnsLeftWidth = 0;
    +                        for (var il = 0; il < columns.length; il++) {
    +                          if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                            if (columns[il].colDef.name !== $scope.col.colDef.name) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                            }
    +                            else {
    +                              break;
    +                            }
    +                          }
    +                        }
    +                        if ($scope.newScrollLeft === undefined) {
    +                          totalMouseMovement += changeValue;
    +                        }
    +                        else {
    +                          totalMouseMovement = $scope.newScrollLeft + newElementLeft - totalColumnsLeftWidth;
    +                        }
    +
    +                        //Increase width of moving column, in case the rightmost column was moved and its width was
    +                        //decreased because of overflow
    +                        if (reducedWidth < $scope.col.drawnWidth) {
    +                          reducedWidth += Math.abs(changeValue);
    +                          movingElm.css({'width': reducedWidth + 'px'});
    +                        }
    +                      };
    +
    +                      var mouseMoveHandler = function (evt) {
    +                        //Disable text selection in Chrome during column move
    +                        document.onselectstart = function() { return false; };
    +
    +                        var changeValue = evt.pageX - previousMouseX;
    +                        if (!elmCloned && Math.abs(changeValue) > 50) {
    +                          cloneElement();
    +                        }
    +                        else if (elmCloned) {
    +                          moveElement(changeValue);
    +                          previousMouseX = evt.pageX;
    +                        }
    +                      };
    +
    +                      /*
    +                       //Commenting these lines as they are creating trouble with column moving when grid has huge scroll
    +                       // On scope destroy, remove the mouse event handlers from the document body
    +                       $scope.$on('$destroy', function () {
    +                       $document.off('mousemove', mouseMoveHandler);
    +                       $document.off('mouseup', mouseUpHandler);
    +                       });
    +                       */
    +                      $document.on('mousemove', mouseMoveHandler);
    +
    +                      var mouseUpHandler = function (evt) {
    +                        //Re-enable text selection after column move
    +                        document.onselectstart = null;
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var columns = $scope.grid.columns;
    +                        var columnIndex = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== $scope.col.colDef.name) {
    +                            columnIndex++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = columnIndex - 1; il >= 0; il--) {
    +                            if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                              if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, il + 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, 0);
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = columnIndex + 1; ir < columns.length; ir++) {
    +                            if (angular.isUndefined(columns[ir].colDef.visible) || columns[ir].colDef.visible === true) {
    +                              totalColumnsRightWidth += columns[ir].drawnWidth || columns[ir].width || columns[ir].colDef.width;
    +                              if (totalColumnsRightWidth > totalMouseMovement) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, ir - 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, columns.length - 1);
    +                          }
    +                        }
    +/*
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +*/
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      };
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    }
    +                  }
    +                });
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ng', 'ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', ['gridUtil',
    +    function (gridUtil) {
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name initializeGrid
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @description Attaches the service to a certain grid
    +         * @param {Grid} grid The grid we want to work with
    +         */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.pagination.api:PublicAPI
    +          *
    +          * @description Public API for the pagination feature
    +          */
    +          var publicApi = {
    +            events: {
    +              pagination: {
    +              /**
    +               * @ngdoc event
    +               * @name paginationChanged
    +               * @eventOf ui.grid.pagination.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {int} currentPage requested page number
    +               * @param {int} pageSize requested page size
    +               */
    +                paginationChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              pagination: {
    +                /**
    +                 * @ngdoc method
    +                 * @name getPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the number of the current page
    +                 */
    +                getPage: function () {
    +                  return grid.options.enablePagination ? grid.options.paginationCurrentPage : null;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name getTotalPages
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the total number of pages
    +                 */
    +                getTotalPages: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return null;
    +                  }
    +
    +                  return (grid.options.totalItems === 0) ? 1 : Math.ceil(grid.options.totalItems / grid.options.paginationPageSize);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name nextPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the next page, if possible
    +                 */
    +                nextPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  if (grid.options.totalItems > 0) {
    +                    grid.options.paginationCurrentPage = Math.min(
    +                      grid.options.paginationCurrentPage + 1,
    +                      publicApi.methods.pagination.getTotalPages()
    +                    );
    +                  } else {
    +                    grid.options.paginationCurrentPage++;
    +                  }
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name previousPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the previous page, if we're not on the first page
    +                 */
    +                previousPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.max(grid.options.paginationCurrentPage - 1, 1);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name seek
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the requested page
    +                 * @param {int} page The number of the page that should be displayed
    +                 */
    +                seek: function (page) {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +                  if (!angular.isNumber(page) || page < 1) {
    +                    throw 'Invalid page number: ' + page;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.min(page, publicApi.methods.pagination.getTotalPages());
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPagination || !grid.options.enablePagination) {
    +              return renderableRows;
    +            }
    +            //client side pagination
    +            var pageSize = parseInt(grid.options.paginationPageSize, 10);
    +            var currentPage = parseInt(grid.options.paginationCurrentPage, 10);
    +            
    +            var visibleRows = renderableRows.filter(function (row) { return row.visible; });
    +            grid.options.totalItems = visibleRows.length;
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            if (firstRow > visibleRows.length) {
    +              currentPage = grid.options.paginationCurrentPage = 1;
    +              firstRow = (currentPage - 1) * pageSize;
    +            }
    +            return visibleRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.pagination.api:GridOptions
    +           *
    +           * @description GridOptions for the pagination feature, these are available to be
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @name enablePagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables pagination, defaults to true
    +           */
    +          gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +          /**
    +           * @ngdoc property
    +           * @name enablePaginationControls
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +           *              own controls outside the grid.
    +           */
    +          gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Disables client side pagination. When true, handle the paginationChanged event and set data
    +           *              and totalItems, defaults to `false`
    +           */
    +          gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Total number of items, set automatically when client side pagination, needs set by user
    +           *              for server side pagination
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSizes
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Array of page sizes, defaults to `[250, 500, 1000]`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSizes)) {
    +            gridOptions.paginationPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSize
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSize)) {
    +            if (gridOptions.paginationPageSizes.length > 0) {
    +              gridOptions.paginationPageSize = gridOptions.paginationPageSizes[0];
    +            } else {              
    +              gridOptions.paginationPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationCurrentPage
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Current page number, defaults to 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationCurrentPage)) {
    +            gridOptions.paginationCurrentPage = 1;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name paginationTemplate
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description A custom template for the pager, defaults to `ui-grid/pagination`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationTemplate)) {
    +            gridOptions.paginationTemplate = 'ui-grid/pagination';
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @name uiGridPaginationService
    +         * @description  Raises paginationChanged and calls refresh for client side pagination
    +         * @param {Grid} grid the grid for which the pagination changed
    +         * @param {int} currentPage requested page number
    +         * @param {int} pageSize requested page size
    +         */
    +        onPaginationChanged: function (grid, currentPage, pageSize) {
    +            grid.api.pagination.raise.paginationChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPagination) {
    +              grid.refresh(); //client side pagination
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPagination
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds pagination features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        paginationPageSizes: [5, 10, 25],
    +        paginationPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-pagination></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPagination', ['gridUtil', 'uiGridPaginationService',
    +    function (gridUtil, uiGridPaginationService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        link: {
    +          pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +            uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +
    +            gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                $elm.append(template);
    +                uiGridCtrl.innerCompile(template);
    +              });
    +          }
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling pagination
    +   */
    +  module.directive('uiGridPager', ['uiGridPaginationService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPaginationService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +          $scope.paginationApi = uiGridCtrl.grid.api.pagination;
    +          $scope.sizesLabel = i18nService.getSafeText('pagination.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('pagination.totalItems');
    +          
    +          var options = uiGridCtrl.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          var dataChangeDereg = uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPagination) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +          
    +          $scope.$on('$destroy', dataChangeDereg);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.paginationCurrentPage - 1) * options.paginationPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.paginationCurrentPage * options.paginationPageSize, options.totalItems);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.paginationPageSize', setShowing);
    +
    +          var deregP = $scope.$watch('grid.options.paginationCurrentPage + grid.options.paginationPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.paginationCurrentPage) || options.paginationCurrentPage < 1) {
    +                options.paginationCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.paginationCurrentPage > $scope.paginationApi.getTotalPages()) {
    +                options.paginationCurrentPage = $scope.paginationApi.getTotalPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPaginationService.onPaginationChanged($scope.grid, options.paginationCurrentPage, options.paginationPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.paginationCurrentPage >= $scope.paginationApi.getTotalPages();
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.paginationCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        },
    +        
    +        // get either this column, or the column next to this column, to resize,
    +        // returns the column we're going to resize
    +        findTargetCol: function(col, position, rtlMultiplier){
    +          var renderContainer = col.getRenderContainer();
    +
    +          if (position === 'left') {
    +            // Get the column to the left of this one
    +            var colIndex = renderContainer.visibleColumnCache.indexOf(col);          
    +            return renderContainer.visibleColumnCache[colIndex - 1 * rtlMultiplier];
    +          } else {
    +            return col;
    +          }
    +        }
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', 'uiGridResizeColumnsService', 'uiGridConstants', '$timeout', function (gridUtil, $templateCache, $compile, $q, uiGridResizeColumnsService, uiGridConstants, $timeout) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var grid = uiGridCtrl.grid;
    +
    +            if (grid.options.enableColumnResizing) {
    +              var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +    
    +              var rtlMultiplier = 1;
    +              //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +              if (grid.isRTL()) {
    +                $scope.position = 'left';
    +                rtlMultiplier = -1;
    +              }
    +
    +              var displayResizers = function(){
    +                
    +                // remove any existing resizers.  
    +                var resizers = $elm[0].getElementsByClassName('ui-grid-column-resizer');
    +                for ( var i = 0; i < resizers.length; i++ ){
    +                  angular.element(resizers[i]).remove();
    +                } 
    +                
    +                // get the target column for the left resizer
    +                var otherCol = uiGridResizeColumnsService.findTargetCol($scope.col, 'left', rtlMultiplier);
    +                var renderContainer = $scope.col.getRenderContainer();
    +              
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  var resizerLeft = angular.element(columnResizerElm).clone();
    +                  resizerLeft.attr('position', 'left');
    +
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  var resizerRight = angular.element(columnResizerElm).clone();
    +                  resizerRight.attr('position', 'right');
    +
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              };
    +
    +              displayResizers();
    +              
    +              var waitDisplay = function(){
    +                $timeout(displayResizers);
    +              };
    +              
    +              var dataChangeDereg = grid.registerDataChangeCallback( waitDisplay, [uiGridConstants.dataChange.COLUMN] );
    +              
    +              $scope.$on( '$destroy', dataChangeDereg );
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var downEvent, upEvent, moveEvent;
    +
    +    if (gridUtil.isTouchEnabled()) {
    +      downEvent = 'touchstart';
    +      upEvent = 'touchend';
    +      moveEvent = 'touchmove';
    +    }
    +    else {
    +      downEvent = 'mousedown';
    +      upEvent = 'mouseup';
    +      moveEvent = 'mousemove';
    +    }
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true).then( function() {
    +                uiGridCtrl.grid.refresh();
    +              });
    +            });
    +        }
    +
    +        // Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
    +        // Returns the new recommended with, after constraints applied
    +        function constrainWidth(col, width){
    +          var newWidth = width;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          return newWidth;
    +        }
    +        
    +        
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          x = x + ( constrainWidth(col, newWidth) - newWidth ) * rtlMultiplier;
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +        
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off(upEvent, mouseup);
    +            $document.off(moveEvent, mousemove);
    +            return;
    +          }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, newWidth);
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off(upEvent, mouseup);
    +          $document.off(moveEvent, mousemove);
    +        }
    +
    +
    +        $elm.on(downEvent, function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on(upEvent, mouseup);
    +          $document.on(moveEvent, mousemove);
    +        });
    +
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, maxWidth);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off(downEvent);
    +          $elm.off('dblclick');
    +          $document.off(moveEvent, mousemove);
    +          $document.off(upEvent, mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function ( rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function () {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function () {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function () {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function ( dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty( myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.saveState
    +   * @description
    +   *
    +   *  # ui.grid.saveState
    +   * This module provides the ability to save the grid state, and restore
    +   * it when the user returns to the page.  
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate. Usually the navigate events would be used to save
    +   * the grid state and restore it.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.save-state"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.saveState', ['ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.saveState.constant:uiGridSaveStateConstants
    +   *
    +   *  @description constants available in save state module
    +   */
    +
    +  module.constant('uiGridSaveStateConstants', {
    +    featureName: 'saveState'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.saveState.service:uiGridSaveStateService
    +   *
    +   *  @description Services for saveState feature
    +   */
    +  module.service('uiGridSaveStateService', ['$q', 'uiGridSaveStateConstants', 'gridUtil', '$compile', '$interval', 'uiGridConstants',
    +    function ($q, uiGridSaveStateConstants, gridUtil, $compile, $interval, uiGridConstants ) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.saveState = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.saveState.api:PublicApi
    +           *
    +           *  @description Public Api for saveState feature
    +           */
    +          var publicApi = {
    +            events: {
    +              saveState: {
    +              }
    +            },
    +            methods: {
    +              saveState: {
    +                /**
    +                 * @ngdoc function
    +                 * @name save
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Packages the current state of the grid into 
    +                 * an object, and provides it to the user for saving
    +                 * @returns {object} the state as a javascript object that can be saved
    +                 */
    +                save: function () {
    +                  return service.save(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name restore
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Restores the provided state into the grid
    +                 * @param {scope} $scope a scope that we can broadcast on
    +                 * @param {object} state the state that should be restored into the grid
    +                 */
    +                restore: function ( $scope, state) {
    +                  service.restore(grid, $scope, state);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.saveState.api:GridOptions
    +           *
    +           * @description GridOptions for saveState feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveWidths
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column widths.  Note that unless
    +           * you've provided the user with some way to resize their columns (say
    +           * the resize columns feature), then this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveWidths = gridOptions.saveWidths !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveOrder
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column order.  Note that unless
    +           * you've provided the user with some way to reorder their columns (for
    +           * example the move columns feature), this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveOrder = gridOptions.saveOrder !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveScroll
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current scroll position.  Note that this
    +           * is saved as the percentage of the grid scrolled - so if your
    +           * user returns to a grid with a significantly different number of 
    +           * rows (perhaps some data has been deleted) then the scroll won't 
    +           * actually show the same rows as before.  If you want to scroll to
    +           * a specific row then you should instead use the saveFocus option, which
    +           * is the default.
    +           * 
    +           * Note that this element will only be saved if the cellNav feature is
    +           * enabled
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.saveScroll = gridOptions.saveScroll === true;
    +          /**
    +           * @ngdoc object
    +           * @name saveFocus
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current focused cell.  On returning
    +           * to this focused cell we'll also scroll.  This option is
    +           * preferred to the saveScroll option, so is set to true by
    +           * default.  If saveScroll is set to true then this option will 
    +           * be disabled.  
    +           * 
    +           * By default this option saves the current row number and column 
    +           * number, and returns to that row and column.  However, if you define
    +           * a saveRowIdentity function, then it will return you to the currently 
    +           * selected column within that row (in a business sense - so if some
    +           * rows have been deleted, it will still find the same data, presuming it 
    +           * still exists in the list.  If it isn't in the list then it will instead
    +           * return to the same row number - i.e. scroll percentage)
    +           * 
    +           * Note that this option will do nothing if the cellNav
    +           * feature is not enabled.
    +           * 
    +           * <br/>Defaults to true (unless saveScroll is true)
    +           */
    +          gridOptions.saveFocus = gridOptions.saveScroll !== true && gridOptions.saveFocus !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveRowIdentity
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description A function that can be called, passing in a rowEntity, 
    +           * and that will return a unique id for that row.  This might simply 
    +           * return the `id` field from that row (if you have one), or it might
    +           * concatenate some fields within the row to make a unique value.
    +           * 
    +           * This value will be used to find the same row again and set the focus 
    +           * to it, if it exists when we return.
    +           * 
    +           * <br/>Defaults to undefined
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveVisible
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save whether or not columns are visible.
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveVisible = gridOptions.saveVisible !== false;          
    +          /**
    +           * @ngdoc object
    +           * @name saveSort
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current sort state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSort = gridOptions.saveSort !== false;         
    +          /**
    +           * @ngdoc object
    +           * @name saveFilter
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current filter state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveFilter = gridOptions.saveFilter !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveSelection
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the currently selected rows.  If the `saveRowIdentity` callback
    +           * is defined, then it will save the id of the row and select that.  If not, then
    +           * it will attempt to select the rows by row number, which will give the wrong results
    +           * if the data set has changed in the mean-time.
    +           * 
    +           * Note that this option only does anything
    +           * if the selection feature is enabled.  
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSelection = gridOptions.saveSelection !== false;          
    +        },
    +
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name save
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the current grid state into an object, and
    +         * passes that object back to the caller
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the state ready to be saved
    +         */
    +        save: function (grid) {
    +          var savedState = {};
    +          
    +          savedState.columns = service.saveColumns( grid );
    +          savedState.scrollFocus = service.saveScrollFocus( grid );
    +          savedState.selection = service.saveSelection( grid );
    +          
    +          return savedState;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restore
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Applies the provided state to the grid
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} state the state we'd like to restore
    +         */
    +        restore: function( grid, $scope, state ){
    +          if ( state.columns ) {
    +            service.restoreColumns( grid, state.columns );
    +          }
    +          
    +          if ( state.scrollFocus ){
    +            service.restoreScrollFocus( grid, $scope, state.scrollFocus );
    +          }
    +          
    +          if ( state.selection ){
    +            service.restoreSelection( grid, state.selection );
    +          }
    +          
    +          grid.refresh();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name saveColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the column setup, including sort, filters, ordering
    +         * and column widths.
    +         * 
    +         * Works through the current columns, storing them in order.  Stores the
    +         * column name, then the visible flag, width, sort and filters for each column.
    +         *
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {array} the columns state ready to be saved
    +         */
    +        saveColumns: function( grid ) {
    +          var columns = [];
    +          angular.forEach( grid.columns, function( column ) {
    +            var savedColumn = {};
    +            savedColumn.name = column.name;
    +            savedColumn.visible = column.visible;
    +            savedColumn.width = column.width;
    +            
    +            // these two must be copied, not just pointed too - otherwise our saved state is pointing to the same object as current state
    +            savedColumn.sort = angular.copy( column.sort );
    +            savedColumn.filters = angular.copy ( column.filters );
    +            columns.push( savedColumn );
    +          });
    +          
    +          return columns;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently scroll or focus.
    +         * 
    +         * If cellNav isn't present then does nothing - we can't return
    +         * to the scroll position without cellNav anyway.
    +         * 
    +         * If the cellNav module is present, and saveFocus is true, then
    +         * it saves the currently focused cell.  If rowIdentity is present
    +         * then saves using rowIdentity, otherwise saves visibleRowNum.
    +         * 
    +         * If the cellNav module is not present, and saveScroll is true, then
    +         * it approximates the current scroll row and column, and saves that.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveScrollFocus: function( grid ){
    +          if ( !grid.api.cellNav ){
    +            return {};
    +          }
    +          
    +          var scrollFocus = {};
    +          if ( grid.options.saveFocus ){
    +            scrollFocus.focus = true;
    +            var rowCol = grid.api.cellNav.getFocusedCell();
    +            if ( rowCol !== null ) {
    +              scrollFocus.colName = rowCol.col.colDef.name;
    +              scrollFocus.rowVal = service.getRowVal( grid, rowCol.row );
    +            }
    +          } else if ( grid.options.saveScroll ) {
    +            scrollFocus.focus = false;
    +            if ( grid.renderContainers.body.prevRowScrollIndex ){
    +              scrollFocus.rowVal = service.getRowVal( grid, grid.renderContainers.body.visibleRowCache[ grid.renderContainers.body.prevRowScrollIndex ]);
    +            }
    +            
    +            if ( grid.renderContainers.body.prevColScrollIndex ){
    +              scrollFocus.colName = grid.renderContainers.body.visibleColumnCache[ grid.renderContainers.body.prevColScrollIndex ].name;
    +            }
    +          }        
    +          
    +          return scrollFocus;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently selected rows, if the selection feature is enabled
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveSelection: function( grid ){
    +          if ( !grid.api.selection || !grid.options.saveSelection ){
    +            return {};
    +          }
    +
    +          var selection = grid.api.selection.getSelectedGridRows().map( function( gridRow ) {
    +            return service.getRowVal( grid, gridRow );
    +          });
    +
    +          return selection;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getRowVal
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Helper function that gets either the rowNum or
    +         * the saveRowIdentity, given a gridRow 
    +         * @param {Grid} grid the grid the row is in
    +         * @param {GridRow} gridRow the row we want the rowNum for
    +         * @returns {object} an object containing { identity: true/false, row: rowNumber/rowIdentity }
    +         * 
    +         */
    +        getRowVal: function( grid, gridRow ){
    +          if ( !gridRow ) {
    +            return null;
    +          }
    +          
    +          var rowVal = {};
    +          if ( grid.options.saveRowIdentity ){
    +            rowVal.identity = true;
    +            rowVal.row = grid.options.saveRowIdentity( gridRow.entity );
    +          } else {
    +            rowVal.identity = false;
    +            rowVal.row = grid.renderContainers.body.visibleRowCache.indexOf( gridRow );
    +          }
    +          return rowVal;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restoreColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Restores the columns, including order, visible, width
    +         * sort and filters.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} columnsState the list of columns we had before, with their state
    +         */
    +        restoreColumns: function( grid, columnsState ){
    +          angular.forEach( columnsState, function( columnState, index ) {
    +            var currentCol = grid.columns.filter( function( column ) {
    +              return column.name === columnState.name;
    +            });
    +            
    +            if ( currentCol.length > 0 ){
    +              var currentIndex = grid.columns.indexOf( currentCol[0] );
    +              
    +              if ( grid.columns[currentIndex].visible !== columnState.visible ||
    +                   grid.columns[currentIndex].colDef.visible !== columnState.visible ){
    +                grid.columns[currentIndex].visible = columnState.visible;
    +                grid.columns[currentIndex].colDef.visible = columnState.visible;
    +                grid.api.core.raise.columnVisibilityChanged( grid.columns[currentIndex]);
    +              }
    +              
    +              grid.columns[currentIndex].width = columnState.width;
    +
    +              if ( !angular.equals(grid.columns[currentIndex].sort, columnState.sort && 
    +                   !( grid.columns[currentIndex].sort === undefined && angular.isEmpty(columnState.sort) ) ) ){
    +                grid.columns[currentIndex].sort = angular.copy( columnState.sort );
    +                grid.api.core.raise.sortChanged();
    +              }
    +
    +              if ( !angular.equals(grid.columns[currentIndex].filters, columnState.filters ) ){
    +                grid.columns[currentIndex].filters = angular.copy( columnState.filters );
    +                grid.api.core.raise.filterChanged();
    +              }
    +              
    +              if ( currentIndex !== index ){
    +                var column = grid.columns.splice( currentIndex, 1 )[0];
    +                grid.columns.splice( index, 0, column );
    +              }
    +            }
    +          });
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Scrolls to the position that was saved.  If focus is true, then
    +         * sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +         * specified row/col.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} scrollFocusState the scroll/focus state ready to be restored
    +         */
    +        restoreScrollFocus: function( grid, $scope, scrollFocusState ){
    +          if ( !grid.api.cellNav ){
    +            return;
    +          }
    +          
    +          var colDef, row;
    +          if ( scrollFocusState.colName ){
    +            var colDefs = grid.options.columnDefs.filter( function( colDef ) { return colDef.name === scrollFocusState.colName; });
    +            if ( colDefs.length > 0 ){
    +              colDef = colDefs[0];
    +            }
    +          }
    +          
    +          if ( scrollFocusState.rowVal && scrollFocusState.rowVal.row ){
    +            if ( scrollFocusState.rowVal.identity ){
    +              row = service.findRowByIdentity( grid, scrollFocusState.rowVal );
    +            } else {
    +              row = grid.renderContainers.body.visibleRowCache[ scrollFocusState.rowVal.row ];
    +            }
    +          }
    +          
    +          var entity = row && row.entity ? row.entity : null ;
    +
    +          if ( colDef || entity ) {          
    +            if (scrollFocusState.focus ){
    +              grid.api.cellNav.scrollToFocus( entity, colDef );
    +            } else {
    +              grid.api.cellNav.scrollTo( entity, colDef );
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Selects the rows that are provided in the selection
    +         * state.  If you are using `saveRowIdentity` and more than one row matches the identity
    +         * function then only the first is selected.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} selectionState the selection state ready to be restored
    +         */
    +        restoreSelection: function( grid, selectionState ){
    +          if ( !grid.api.selection ){
    +            return;
    +          }
    +          
    +          grid.api.selection.clearSelectedRows();
    +
    +          angular.forEach( selectionState, function( rowVal ) {
    +            if ( rowVal.identity ){
    +              var foundRow = service.findRowByIdentity( grid, rowVal );
    +              
    +              if ( foundRow ){
    +                grid.api.selection.selectRow( foundRow.entity );
    +              }
    +              
    +            } else {
    +              grid.api.selection.selectRowByVisibleIndex( rowVal.row );
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name findRowByIdentity
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Finds a row given it's identity value, returns the first found row
    +         * if any are found, otherwise returns null if no rows are found.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} rowVal the row we'd like to find
    +         * @returns {gridRow} the found row, or null if none found
    +         */
    +        findRowByIdentity: function( grid, rowVal ){
    +          if ( !grid.options.saveRowIdentity ){
    +            return null;
    +          }
    +          
    +          var filteredRows = grid.rows.filter( function( gridRow ) {
    +            if ( grid.options.saveRowIdentity( gridRow.entity ) === rowVal.row ){
    +              return true;
    +            } else {
    +              return false;
    +            }
    +          });
    +          
    +          if ( filteredRows.length > 0 ){
    +            return filteredRows[0];
    +          } else {
    +            return null;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.saveState.directive:uiGridSaveState
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds saveState features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-save-state></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSaveState', ['uiGridSaveStateConstants', 'uiGridSaveStateService', 'gridUtil', '$compile',
    +    function (uiGridSaveStateConstants, uiGridSaveStateService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridSaveStateService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  //add methods to GridRow
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('GridRow', ['$delegate', function($delegate) {
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.selection.api:GridRow
    +       *
    +       *  @description GridRow prototype functions added for selection
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name enableSelection
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Enable row selection for this row, only settable by internal code.
    +       *
    +       *  The grouping feature, for example, might set group header rows to not be selectable.
    +       *  <br/>Defaults to true
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name isSelected
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +       *  <br/>Defaults to false
    +       */
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name setSelected
    +         * @methodOf ui.grid.selection.api:GridRow
    +         * @description Sets the isSelected property and updates the selectedCount
    +         * Changes to isSelected state should only be made via this function
    +         * @param {bool} selelected value to set
    +         */
    +        $delegate.prototype.setSelected = function(selected) {
    +          this.isSelected = selected;
    +          if (selected) {
    +            this.grid.selection.selectedCount++;
    +          }
    +          else {
    +            this.grid.selection.selectedCount--;
    +          }
    +        };
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.grid:selection
    +           *
    +           *  @description Grid properties and functions added for selection
    +           */
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name selectedCount
    +           *  @propertyOf  ui.grid.selection.grid:selection
    +           *  @description Current count of selected rows
    +           *  @example
    +           *  var count = grid.selection.selectedCount
    +           */
    +          grid.selection.selectedCount = 0;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChanged: function (scope, row, evt) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows, evt) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                toggleRowSelection: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum, evt ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && typeof(row) !== 'undefined' && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                unSelectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected && row.enableSelection !== false ){
    +                      row.setSelected(true);
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllVisibleRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected && row.enableSelection !== false){
    +                        row.setSelected(true);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.setSelected(false);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                clearSelectedRows: function (evt) {
    +                  service.clearSelectedRows(grid, evt);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableFooterTotalSelected
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Shows the total number of selected items in footer if true.
    +           *  <br/>Defaults to true.
    +           *  <br/>GridOptions.showFooter must also be set to true.
    +           */
    +          gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name isRowSelectable
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.
    +           */
    +
    +          gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {Event} event object if resulting from event
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid, evt);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid, evt);
    +            }
    +          }
    +
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else if (row.enableSelection !== false) {
    +            row.setSelected(!selected);
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            } else {
    +              grid.selection.selectAll = false;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {Event} event object if raised from an event
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, evt, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected && rowToSelect.enableSelection !== false ){
    +                rowToSelect.setSelected(true);
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows, evt );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         * @param {Event} event object if raised from an event
    +         */
    +        clearSelectedRows: function (grid, evt) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.setSelected(false);
    +              service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +          grid.selection.selectAll = false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * @param {Event} event object if raised from an event
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows, evt ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * @param {Event} event object if raised from an event
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows, evt ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows, evt);
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  minWidth: 10,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false,
    +                  exporterSuppressExport: true 
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +              
    +              if (uiGridCtrl.grid.options.isRowSelectable !== angular.noop) {
    +                uiGridCtrl.grid.registerRowBuilder(function(row, options) {
    +                  row.enableSelection = uiGridCtrl.grid.options.isRowSelectable(row);
    +                });
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self, evt);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0, evt);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows(evt);
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            var touchStartTime = 0;
    +            var touchTimeout = 300;
    +            var selectCells = function(evt){
    +              if (evt.shiftKey) {
    +                uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect);
    +              }
    +              else if (evt.ctrlKey || evt.metaKey) {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +              }
    +              else {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +              }
    +              $scope.$apply();
    +            };
    +
    +            var touchStart = function(evt){
    +              touchStartTime = (new Date()).getTime();
    +            };
    +
    +            var touchEnd = function(evt) {
    +              var touchEndTime = (new Date()).getTime();
    +              var touchTime = touchEndTime - touchStartTime;
    +
    +              if (touchTime < touchTimeout ) {
    +                // short touch
    +                selectCells(evt);
    +              }
    +            };
    +
    +            function registerRowSelectionEvents() {
    +              if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +                $elm.addClass('ui-grid-disable-selection');
    +                $elm.on('touchstart', touchStart);
    +                $elm.on('touchend', touchEnd);
    +                $elm.on('click', selectCells);
    +
    +                $scope.registered = true;
    +              }
    +            }
    +
    +            function deregisterRowSelectionEvents() {
    +              if ($scope.registered){
    +                $elm.removeClass('ui-grid-disable-selection');
    +
    +                $elm.off('touchstart', touchStart);
    +                $elm.off('touchend', touchEnd);
    +                $elm.off('click', selectCells);
    +
    +                $scope.registered = false;
    +              }
    +            }
    +
    +            registerRowSelectionEvents();
    +            // register a dataChange callback so that we can change the selection configuration dynamically
    +            // if the user changes the options
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( function() {
    +              if ( $scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection &&
    +                !$scope.registered ){
    +                registerRowSelectionEvents();
    +              } else if ( ( !$scope.grid.options.enableRowSelection || $scope.grid.options.enableRowHeaderSelection ) &&
    +                $scope.registered ){
    +                deregisterRowSelectionEvents();
    +              }
    +            }, [uiGridConstants.dataChange.OPTIONS] );
    +
    +            $elm.on( '$destroy', dataChangeDereg);
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridGridFooter', ['$compile', 'uiGridConstants', 'gridUtil', function ($compile, uiGridConstants, gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      priority: -1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            if (!uiGridCtrl.grid.options.showGridFooter) {
    +              return;
    +            }
    +
    +
    +            gridUtil.getTemplate('ui-grid/gridFooterSelectedItems')
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +
    +                angular.element($elm[0].getElementsByClassName('ui-grid-grid-footer')[0]).append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\"><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div class=\"ui-grid-footer-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\"><div class=\"ui-grid-footer-cell-row\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\"></div></div></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-grid-footer',
    +    "<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{'search.totalItems' | t}} {{grid.rows.length}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\"><div class=\"ui-grid-header-cell-row\"><div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\"></div></div></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    /*\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "    */\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\"></div><div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\" ng-style=\"colContainer.getViewPortStyle()\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"Viewport.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth()) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableTopRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !grid.expandable.expandedAll, 'ui-grid-icon-minus-squared' : grid.expandable.expandedAll }\" ng-click=\"grid.api.expandable.toggleAllRows()\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\" download=\"FILE_NAME\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/pagination',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager ng-show=\"grid.options.enablePaginationControls\"><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"paginationApi.seek(1)\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"paginationApi.previousPage()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.paginationCurrentPage\" min=\"1\" max=\"{{ paginationApi.getTotalPages() }}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"paginationApi.getTotalPages() > 0\">/ {{ paginationApi.getTotalPages() }}</span> <button type=\"button\" ng-click=\"paginationApi.nextPage()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"paginationApi.seek(paginationApi.getTotalPages())\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.paginationPageSize\" ng-options=\"o as o for o in grid.options.paginationPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/gridFooterSelectedItems',
    +    "<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"search.selectedItems\" | t}} {{grid.selection.selectedCount}})</span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.20/ui-grid.min.css b/release/3.0.0-rc.20/ui-grid.min.css
    new file mode 100644
    index 000000000..69fa19adc
    --- /dev/null
    +++ b/release/3.0.0-rc.20/ui-grid.min.css
    @@ -0,0 +1,4 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20 - 2015-02-24
    + * Copyright (c) 2015 ; License: MIT 
    + */.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell-wrapper{position:relative;display:table;box-sizing:border-box;height:100%}.ui-grid-header-cell-row{display:table-row}.ui-grid-header-cell{position:relative;box-sizing:border-box;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;display:table-cell;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell:last-child{border-right:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu-button-last-col{margin-right:25px}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative;overflow-y:scroll;-webkit-overflow-scrolling:touch}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative;padding-top:1px}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#f0f0ee !important;border-bottom:solid 1px #d4d4d4}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-grid-footer{float:left;width:100%}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell-wrapper{position:relative;display:table;box-sizing:border-box;height:100%}.ui-grid-footer-cell-row{display:table-row}.ui-grid-footer-cell{overflow:hidden;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box;display:table-cell}.ui-grid-footer-cell:last-child{border-right:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid{overflow-y:scroll;max-height:300px;border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child,.ui-grid[dir=rtl] .ui-grid-header-cell:last-child{border-right:1px solid #d4d4d4;border-left:0}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid-header-cell:last-child .ui-grid-column-resizer.right{border-right:1px solid #d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.right{border-right:0}.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.left{border-left:1px solid #d4d4d4}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}.ui-grid-row-selected>[ui-grid-row]>.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.20/ui-grid.min.js b/release/3.0.0-rc.20/ui-grid.min.js
    new file mode 100644
    index 000000000..72166a9ee
    --- /dev/null
    +++ b/release/3.0.0-rc.20/ui-grid.min.js
    @@ -0,0 +1,12 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20 - 2015-02-24
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart",COLUMN_HEADER_CLICK:"uiGridColumnHeaderClick"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,PG_UP:33,PG_DOWN:34,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],scrollDirection:{UP:"up",DOWN:"down",LEFT:"left",RIGHT:"right",NONE:"none"},dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column",OPTIONS:"options"},scrollbars:{NEVER:0,ALWAYS:1}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){var c=a.col.getColClass(!1);b.addClass(c);var e,f=function(){var c=b;e&&(c.removeClass(e),e=null),e=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,c.addClass(e)};a.col.cellClass&&f();var g=a.grid.registerDataChangeCallback(f,[d.dataChange.COLUMN,d.dataChange.EDIT]),h=function(d,g){if(d!==g){(e||a.col.cellClass)&&f();var h=a.col.getColClass(!1);h!==c&&(b.removeClass(c),b.addClass(h),c=h)}},i=a.$watch("col",h),j=a.$watch("row",h),k=function(){g(),i(),j()};a.$on("$destroy",k),b.on("$destroy",k)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,e,f,g){var h=this;d.initialize(b,g),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,c,f){b.col=a;var g=d.getColumnElementPosition(b,a,c);b.menuShown?(b.colElement=c,b.colElementPosition=g,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(h.shown=b.menuShown=!0,d.repositionMenu(b,a,g,e,c),b.colElement=c,b.colElementPosition=g,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu(),b.grid.api.core.notifyDataChange(c.dataChange.COLUMN),b.grid.api.core.raise.columnVisibilityChanged(b.col)}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",h)}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-grid-footer";return{restrict:"EA",replace:!0,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(a,c,f,g){a.grid=g.grid;var h=a.grid.options.gridFooterTemplate?a.grid.options.gridFooterTemplate:e;d.getTemplate(h).then(function(d){var e=angular.element(d),f=b(e)(a);c.append(f)})},post:function(){}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,h){function i(b){var c=!1;b.shiftKey&&(c=!0),j.grid.sortColumn(a.col,c).then(function(){j.columnMenuScope&&j.columnMenuScope.hideMenu(),j.grid.refresh()})}var j=h[0],k=h[1];a.grid=j.grid,a.renderContainer=j.grid.renderContainers[k.containerId];var l=a.col.getColClass(!1);c.addClass(l),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var m,n=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),o=function(){var b=c;m&&(b.removeClass(m),m=null),m=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(m);var d=a.grid.renderContainers.right?a.grid.renderContainers.right:a.grid.renderContainers.body;a.isLastCol=a.col===d.visibleColumnCache[d.visibleColumnCache.length-1]};a.$watch("col",function(b,d){if(b!==d){var e=a.col.getColClass(!1);e!==l&&(c.removeClass(l),c.addClass(e),l=e)}}),o();var p=a.grid.registerDataChangeCallback(o,[f.dataChange.COLUMN]);if(a.$on("$destroy",p),a.sortable=j.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=j.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var q,r=0,s=e.isTouchEnabled()?"touchstart":"mousedown";n.on(s,function(d){d.stopPropagation(),"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(r=(new Date).getTime(),q=b(function(){},g),q.then(function(){a.colMenu&&j.columnMenuScope.showMenu(a.col,c,d)}),j.fireEvent(f.events.COLUMN_HEADER_CLICK,{event:d,columnName:a.col.colDef.name}))});var t=e.isTouchEnabled()?"touchend":"mouseup";n.on(t,function(){b.cancel(q)}),a.$on("$destroy",function(){n.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),j.columnMenuScope.menuShown&&j.columnMenuScope.col===a.col?j.columnMenuScope.hideMenu():j.columnMenuScope.showMenu(a.col,c)},a.sortable){var u=e.isTouchEnabled()?"touchend":"click";n.on(u,function(a){a.stopPropagation(),b.cancel(q);var c=(new Date).getTime(),d=c-r;d>g||i(a)}),a.$on("$destroy",function(){b.cancel(q)})}if(a.filterable){var v=[];angular.forEach(a.col.filters,function(b,c){v.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(j.grid.api.core.raise.filterChanged(),j.grid.refresh(!0))}))}),a.$on("$destroy",function(){angular.forEach(v,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){function i(){k.header=k.colContainer.header=c;var a=c[0].getElementsByClassName("ui-grid-header-canvas");k.headerCanvas=a.length>0?k.colContainer.headerCanvas=a[0]:null}var j=h[0],k=h[1];a.grid=j.grid,a.colContainer=k.colContainer,i();var l;l=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(l).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),c=f,i(),k){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(k.headerViewport=g)}a.grid.queueRefresh()})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth()-i.scrollbarWidth,b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,g=a,j=!1,k=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(g/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",j=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,j=!0)});var l=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return l.indexOf(a.widthType)-l.indexOf(b.widthType)}).forEach(function(a){var b=k(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,g-=a.drawnWidth}),j&&g>0&&c>0&&a>c){var m=function(a){g>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,g--)},n=0;do n=g,b.forEach(m);while(g>0&&g!==n)}c=Math.max(c,a);var o="";return b.forEach(function(a){o+=a.getColClassDefinition()}),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),o}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService","uiGridConstants",function(a,b,c){var d={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",d.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",d.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var c=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?c=c.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),c=c.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(c=c.concat(d.showHideColumns(b))),c},showHideColumns:function(a){var c=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(c.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};d.setMenuItemTitle(e,b,a.grid),c.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},d.setMenuItemTitle(e,b,a.grid),c.push(e)}}),c):c},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh(),a.grid.api.core.notifyDataChange(c.dataChange.COLUMN),a.grid.api.core.raise.columnVisibilityChanged(a)}};return d}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d,e,g){var h=this;h.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var e="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(e=d.originalEvent.type),angular.element(document).off("click touchstart",i),b(function(){angular.element(document).on(e,i)})},h.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",i)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var i=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",i),a.$on("$destroy",function(){angular.element(document).off("click touchstart",i)}),a.$on("$destroy",function(){angular.element(c).off("resize",i)}),g&&a.$on("$destroy",g.grid.api.core.on.scrollEvent(a,i)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,i))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil","ScrollEvent",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(a,b,c,f){function g(b){if(!b.grid||b.grid.id===k.id){if(b.y&&a.bindScrollVertical){j.prevScrollArgs=b;var c=b.getNewScrollTop(l,j.viewport);(b.source!==e.Sources.ViewPortScroll||b.sourceColContainer!==m)&&(j.viewport[0].scrollTop=c)}if(b.x&&a.bindScrollHorizontal){j.prevScrollArgs=b;var f=b.getNewScrollLeft(m,j.viewport);a.newScrollLeft=f,j.headerViewport&&(j.headerViewport.scrollLeft=d.denormalizeScrollLeft(j.headerViewport,f)),j.footerViewport&&(j.footerViewport.scrollLeft=d.denormalizeScrollLeft(j.footerViewport,f)),b.source!==e.Sources.ViewPortScroll&&(j.viewport[0].scrollLeft=f),j.prevScrollLeft=f}}}function h(){var b="",c=m.getCanvasWidth(),d=m.getViewportWidth(),e=l.getCanvasHeight();"body"!==a.containerId&&(e+=k.scrollbarHeight);var f=l.getViewportHeight(),g=m.getHeaderViewportWidth(),h=m.getHeaderViewportWidth();return b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { width: "+(c+k.scrollbarWidth)+"px; }",n.explicitHeaderCanvasHeight&&(b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { height: "+n.explicitHeaderCanvasHeight+"px; }"),b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-canvas { width: "+c+k.scrollbarWidth+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}var i=f[0],j=f[1],k=i.grid,l=j.rowContainer,m=j.colContainer,n=k.renderContainers[a.containerId];b.addClass("ui-grid-render-container-"+a.containerId),(a.bindScrollHorizontal||a.bindScrollVertical)&&k.api.core.on.scrollEvent(a,g),d.on.mousewheel(b,function(a){var b=new e(k,l,m,e.Sources.RenderContainerMouseWheel);if(0!==a.deltaY){var c=-1*a.deltaY*a.deltaFactor,f=(j.viewport[0].scrollTop+c)/l.getVerticalScrollLength();0>f?f=0:f>1&&(f=1),b.y={percentage:f,pixels:c}}if(0!==a.deltaX){var g=a.deltaX*a.deltaFactor,h=d.normalizeScrollLeft(j.viewport),i=(h+g)/(m.getCanvasWidth()-m.getViewportWidth());0>i?i=0:i>1&&(i=1),b.x={percentage:i,pixels:g}}(b.y&&0!==b.y.percentage&&1!==b.y.percentage||b.x&&0!==b.x.percentage&&1!==b.x.percentage)&&(a.preventDefault(),b.fireThrottledScrollingEvent())}),b.bind("$destroy",function(){b.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){b.unbind(a)})}),i.grid.registerStyleComputation({priority:6,func:h})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(){}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){function e(){a.row.getRowTemplateFn.then(function(c){var d=a.$new();c(d,function(a){h&&(h.remove(),i.$destroy()),b.empty().append(a),h=a,i=d})})}{var f=d[0],g=d[1];f.grid}a.grid=f.grid,a.colContainer=g.colContainer;var h,i;e(),a.$watch("row.getRowTemplateFn",function(a,b){a!==b&&e()})},post:function(){}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil","ScrollEvent","uiGridConstants",function(a,b,c){return{replace:!0,scope:{},controllerAs:"Viewport",templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(d,e,f,g){var h=g[0],i=g[1];d.containerCtrl=i;var j=i.rowContainer,k=i.colContainer,l=h.grid;d.grid=h.grid,d.rowContainer=i.rowContainer,d.colContainer=i.colContainer,i.viewport=e,e.on("scroll",function(){var d=e[0].scrollTop,f=a.normalizeScrollLeft(e),g=-1,h=-1;if(f!==k.prevScrollLeft){l.flagScrollingHorizontally();var i=f-k.prevScrollLeft;i>0&&(l.scrollDirection=c.scrollDirection.RIGHT),0>i&&(l.scrollDirection=c.scrollDirection.LEFT);var m=k.getCanvasWidth()-k.getViewportWidth();g=0!==m?f/m:0,k.adjustScrollHorizontal(f,g)}if(d!==j.prevScrollTop){l.flagScrollingVertically();var n=d-j.prevScrollTop;n>0&&(l.scrollDirection=c.scrollDirection.DOWN),0>n&&(l.scrollDirection=c.scrollDirection.UP);var o=j.getVerticalScrollLength();h=d/o,h>1&&(h=1),0>h&&(h=0),j.adjustScrollVertical(d,h)}var p=new b(l,j,k,b.Sources.ViewPortScroll);p.newScrollLeft=f,p.newScrollTop=d,g>-1&&(p.x={percentage:g}),h>-1&&(p.y={percentage:h}),p.fireScrollingEvent()})},controller:["$scope",function(a){this.rowStyle=function(b){var c=a.rowContainer,d=a.colContainer,e={};if(0===b&&0!==c.currentTopRow){var f=c.currentTopRow*c.grid.options.rowHeight;e["margin-top"]=f+"px"}return 0!==d.currentFirstColumn&&(d.grid.isRTL()?e["margin-right"]=d.columnOffset+"px":e["margin-left"]=d.columnOffset+"px"),e}}]}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile","ScrollEvent",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(p.grid.options.columnDefs=a,p.grid.buildColumns({orderByColumnDefs:!0}).then(function(){p.grid.preCompileCellTemplates(),p.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function n(a){var b=new l(p.grid,null,null,"ui.grid.adjustInfiniteScrollPosition"),c=p.grid.renderContainers.body.visibleRowCache.length,d=(a+a/(c-1))/c;b.y=0===d?{pixels:1}:{percentage:d},b.fireScrollingEvent()}function o(b){var d=[];b&&(p.grid.columns.length===(p.grid.rowHeaderColumns?p.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===p.grid.options.columnDefs.length&&b.length>0&&p.grid.buildColumnDefsFromData(b),(p.grid.options.columnDefs.length>0||b.length>0)&&d.push(p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates()})),e.all(d).then(function(){p.grid.modifyRows(b).then(function(){p.grid.redrawInPlace(!0),a.$evalAsync(function(){p.grid.refreshCanvas(!0),p.grid.callDataChangeCallbacks(f.dataChange.ROW),i(function(){p.grid.options.enableInfiniteScroll&&(0===p.grid.renderContainers.body.prevRowScrollIndex&&n(0),p.grid.scrollDirection===f.scrollDirection.UP&&n(p.grid.renderContainers.body.prevRowScrollIndex+1+p.grid.options.excessRows))},0)})})}))}var p=this;p.grid=h.createGrid(a.uiGrid),p.grid.appScope=p.grid.appScope||a.$parent,b.addClass("grid"+p.grid.id),p.grid.rtl="rtl"===d.getStyles(b[0]).direction,a.grid=p.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){p.grid.options.columnDefs=a,p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates(),p.grid.refreshCanvas(!0)})});var q;q=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,o):a.$parent.$watchCollection(function(){return a.uiGrid.data},o);var r=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m),s=a.$watch(function(){return p.grid.styleComputations},function(){p.grid.refreshCanvas(!0)});a.$on("$destroy",function(){q(),r(),s()}),p.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=p.grid),a.$broadcast(b,c)},p.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.refreshCanvas(!0)}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.calcFooterHeight(),m=0;i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas(),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];
    +c+=e.drawnWidth||e.width||0}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0!==h&&h||e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.appScope=b.options.appScopeProvider,b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.calcFooterHeight(),b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE;var c=d.debounce(function(){b.isScrollingVertically=!1,b.scrollDirection=e.scrollDirection.NONE},1e3),g=d.debounce(function(){b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE},1e3);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.scrollbarHeight=0,b.scrollbarWidth=0,b.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarHeight=d.getScrollbarWidth()),b.options.enableVerticalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarWidth=d.getScrollbarWidth()),b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerEvent("core","columnVisibilityChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT]),b.registerStyleComputation({priority:10,func:b.getFooterStyles})};return o.prototype.calcFooterHeight=function(){if(!this.hasFooter())return 0;var a=0;return this.options.showGridFooter&&(a+=this.options.gridFooterHeight),this.options.showColumnFooter&&(a+=this.options.columnFooterHeight),a},o.prototype.getFooterStyles=function(){var a=".grid"+this.id+" .ui-grid-footer-aggregates-row { height: "+this.options.columnFooterHeight+"px; }";return a+=" .grid"+this.id+" .ui-grid-footer-info { height: "+this.options.gridFooterHeight+"px; }"},o.prototype.hasFooter=function(){return this.options.showGridFooter||this.options.showColumnFooter},o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b,c){var f=d.nextUid();b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[f]={callback:a,types:b,_this:c};var g=this,h=function(){delete g.dataChangeCallbacks[f]};return h},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&(b._this?b.callback.apply(b._this,this):b.callback(this))},this)},o.prototype.notifyDataChange=function(a){var b=e.dataChange;a===b.ALL||a===b.COLUMN||a===b.EDIT||a===b.ROW||a===b.OPTIONS?this.callDataChangeCallbacks(a):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+a)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,b.rowHeaderColumns.length,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.refresh()})})},o.prototype.buildColumns=function(b){var c={orderByColumnDefs:!1};angular.extend(c,b);var e,f=this,h=[],i=f.rowHeaderColumns.length;for(e=0;e<f.columns.length;e++)f.getColDef(f.columns[e].name)||(f.columns.splice(e,1),e--);if(f.rowHeaderColumns.forEach(function(a){f.columns.unshift(a)}),f.options.columnDefs.forEach(function(a,b){f.preprocessColDef(a);var c=f.getColumn(a.name);c?c.updateColumnDef(a,!1):(c=new g(a,d.nextUid(),f),f.columns.splice(b+i,0,c)),f.columnBuilders.forEach(function(b){h.push(b.call(f,a,c,f.options))})}),c.orderByColumnDefs){var j=f.columns.slice(0);for(e=0;e<f.options.columnDefs.length;e++)j[e+i]=f.columns[e+i].name!==f.options.columnDefs[e].name?f.getColumn(f.options.columnDefs[e].name):f.columns[e+i];f.columns.length=0,Array.prototype.splice.apply(f.columns,[0,0].concat(j))}return a.all(h).then(function(){f.rows.length>0&&f.assignTypes()})},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){var b=this;if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");if(void 0===a.name&&void 0!==a.field){var c=b.getColumn(a.field);if(c){var d=new RegExp("^"+a.field+"(\\d+)$","i"),e=b.columns.filter(function(a){return d.test(a.displayName)}).sort(function(a,b){if(a===b)return 0;var c=a.displayName.match(d)[1],e=b.displayName.match(d)[1];return parseInt(c,10)>parseInt(e,10)?1:-1});if(0===e.length)a.name=a.field+"2";else{var f=e[e.length-1].displayName.match(d)[1];f=parseInt(f,10),a.name=a.field+(f+1)}}else a.name=a.field}},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;{0===g.rows.length}for(g.rows.length=0,c=0;c<b.length;c++){var j=b[c];e=i.get(j),f=e?e.row:g.processRowBuilders(new h(j,c,g)),g.rows.push(f),d.put(j,{i:c,entity:j,row:f})}g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var k,l,m;if(g.options.enableRowHashing){k=[],m=[];var n={};for(l=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var o=!1;g.options.getRowIdentity(f)||(o=!0),e=d.get(f),e?e.row&&(n[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),o?m.push(f):k.push(f))}for(c=0;c<g.rows.length;c++){var p=g.rows[c],q=g.options.rowIdentity(p.entity);n[q]||l.push(p)}}var r=k||[],s=m||b;r=r.concat(g.newInN(g.rows,s,"entity")),g.addRows(r);var t=g.getDeletedRows(l||g.rows,b);for(c=0;c<t.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(t[c].entity),g.rows.splice(g.rows.indexOf(t[c]),1)}else g.createRowHashMap(),g.rows.length=0;var u=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),v=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([u,v])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.canvasHeightShouldUpdate=!0,"undefined"==typeof d.visibleRowCache?d.visibleRowCache=[]:d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}b.api.core.raise.rowsRendered(this.api)},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.updateCanvasHeight=function(){var a=this;for(var b in a.renderContainers)if(a.renderContainers.hasOwnProperty(b)){var c=a.renderContainers[b];c.canvasHeightShouldUpdate=!0}},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight,c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth,c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b===a||b.colDef.suppressRemoveSort||(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(b){var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return a.all([d,e]).then(function(){c.redrawInPlace(b),c.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;(h.header||h.headerCanvas)&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0,j=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)){if(g.header){var k=g.headerHeight,l=d.outerElementHeight(g.header);g.headerHeight=parseInt(l,10),k!==l&&(h=!0);var m=d.getBorderSize(g.header,"top"),n=d.getBorderSize(g.header,"bottom"),o=parseInt(l-m-n,10);o=0>o?0:o,g.innerHeaderHeight=o,o>i&&(i=o)}if(g.headerCanvas){var p=g.headerCanvasHeight,q=d.outerElementHeight(g.headerCanvas);g.headerCanvasHeight=parseInt(q,10),p!==q&&(h=!0),q>j&&(j=q)}}for(a=0;a<f.length;a++)g=f[a],i>0&&"undefined"!=typeof g.headerHeight&&null!==g.headerHeight&&g.headerHeight<i&&(g.explicitHeaderHeight=i),"undefined"!=typeof g.headerCanvasHeight&&null!==g.headerCanvasHeight&&j>0&&g.headerCanvasHeight<j&&(g.explicitHeaderCanvasHeight=j);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];a?(d.adjustRows(d.prevScrollTop,null),d.adjustColumns(d.prevScrollTop,null)):(d.adjustRows(null,d.prevScrolltopPercentage),d.adjustColumns(null,d.prevScrollleftPercentage))}},o.prototype.hasLeftContainerColumns=function(){return this.hasLeftContainer()&&this.renderContainers.left.renderedColumns.length>0},o.prototype.hasRightContainerColumns=function(){return this.hasRightContainer()&&this.renderContainers.right.renderedColumns.length>0},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,c,d,e){return b.$on(a,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(e?e:d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged"),this.registerEvent("core","rowsRendered"),this.registerEvent("core","scrollEvent"),this.registerEvent("core","canvasHeightChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.eventId,a.handler,c.grid,a._this)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$emit.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b,c){var e=f(g,b,d.grid,c),h={handler:b,dereg:e,eventId:g,scope:a,_this:c};d.listeners.push(h);var i=function(){h.dereg();var a=d.listeners.indexOf(h);d.listeners.splice(a,1)};return a.$on("$destroy",function(){i()}),i}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a,!0)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b,c){var e=this;if(e.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.grid.options.columnDefs.indexOf(b));e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(e.width)||!angular.isNumber(e.width))if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(f);e.width=b.width}e.minWidth=b.minWidth?b.minWidth:30,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,"string"!=typeof e.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+e.field),e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.footerCellClass=b.footerCellClass,e.cellClass=b.cellClass,e.headerCellClass=b.headerCellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),c&&e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),c&&(e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)),d.prototype.unsort=function(){this.sort={},e.grid.api.core.raise.sortChanged(e,e.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { min-width: "+this.drawnWidth+"px; max-width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showGridFooter=c.showGridFooter===!0,c.showColumnFooter=c.showColumnFooter===!0,c.columnFooterHeight="undefined"!=typeof c.columnFooterHeight?c.columnFooterHeight:30,c.gridFooterHeight="undefined"!=typeof c.gridFooterHeight?c.gridFooterHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c.appScopeProvider=c.appScopeProvider||null,c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],d.canvasHeightShouldUpdate=!0,d.$$canvasHeight=0,c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight,d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth,c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},c.prototype.getCanvasHeight=function(){var a=this;if(!a.canvasHeightShouldUpdate)return a.$$canvasHeight;var b=a.$$canvasHeight;return a.$$canvasHeight=0,a.visibleRowCache.forEach(function(b){a.$$canvasHeight+=b.height}),a.canvasHeightShouldUpdate=!1,a.grid.api.core.raise.canvasHeightChanged(b,a.$$canvasHeight),a.$$canvasHeight},c.prototype.getVerticalScrollLength=function(){return this.getCanvasHeight()-this.getViewportHeight()},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b,!1),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())
    +},c.prototype.adjustRows=function(a,c,d){var e=this,f=e.minRowsToRender(),g=e.visibleRowCache,h=g.length-f;"undefined"!=typeof c&&null!==c||!a||(c=a/e.getVerticalScrollLength());var i=Math.ceil(Math.min(h,h*c));i>h&&(i=h);var j=[];if(g.length>e.grid.options.virtualizationThreshold){if("undefined"!=typeof a&&null!==a){if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop<a&&i<e.prevRowScrollIndex+e.grid.options.scrollThreshold&&h>i)return;if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop>a&&i>e.prevRowScrollIndex-e.grid.options.scrollThreshold&&h>i)return}var k={},l={};if(e.grid.options.enableInfiniteScroll&&e.grid.scrollDirection!==b.scrollDirection.NONE&&d){var m=null,n=null;if(e.grid.scrollDirection===b.scrollDirection.UP){for(m=i>0?e.grid.options.excessRows:0,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i),l=Math.min(g.length,k+e.grid.options.excessRows+f)}else if(e.grid.scrollDirection===b.scrollDirection.DOWN){for(m=f,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i-e.grid.options.excessRows-f),l=Math.min(g.length,i+f+e.grid.options.excessRows)}}else k=Math.max(0,i-e.grid.options.excessRows),l=Math.min(g.length,i+f+e.grid.options.excessRows);j=[k,l]}else{var o=e.visibleRowCache.length;j=[0,Math.max(o,f+e.grid.options.excessRows)]}e.updateViewableRowRange(j),e.prevRowScrollIndex=i},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.headerCellWrapperStyle=function(){var a=this;if(0!==a.currentFirstColumn){var b=a.columnOffset;return a.grid.isRTL()?{"margin-right":b+"px"}:{"margin-left":b+"px"}}return null},c.prototype.updateColumnWidths=function(){var b,c=this,d=[],e=[],f=0,g=c.getViewportWidth()-c.grid.scrollbarWidth,h=0,i=0,j="",k=c.visibleColumnCache;k.forEach(function(b){if(b.visible){var c=!1;angular.isNumber(b.width)||(c=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(f=parseInt(f+b.width.length,10),d.push(b)):c?e.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=g-h;if(e.length>0){for(l=0;l<e.length;l++){m=e[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1))}e.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(d.length>0){var q=parseInt(o/f,10);for(l=0;l<d.length;l++)m=d[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,f--,i+=n,m.drawnWidth=n,b=m,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,f--,i+=n,m.drawnWidth=n,d.splice(l,1));q=parseInt(o/f,10),d.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=g-parseInt(i,10);if(r>0&&i>0&&g>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}g>i&&(i=g),k.forEach(function(a){j+=a.getColClassDefinition()}),c.canvasWidth=parseInt(i,10),this.columnStyles=j},c.prototype.getViewPortStyle=function(){var a=this,c={};return"body"===a.name?(c["overflow-x"]=a.grid.options.enableHorizontalScrollbar===b.scrollbars.NEVER?"hidden":"scroll",c["overflow-y"]=a.grid.isRTL()?a.grid.hasLeftContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":a.grid.hasRightContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"):"left"===a.name?(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":"hidden"):(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"),c},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.$$height=d.options.rowHeight}return Object.defineProperty(b.prototype,"height",{get:function(){return this.$$height},set:function(a){a!==this.$$height&&(this.grid.updateCanvasHeight(),this.$$height=a)}}),b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){angular.module("ui.grid").factory("ScrollEvent",["gridUtil",function(a){function b(b,c,d,e){var f=this;if(!b)throw new Error("grid argument is required");f.grid=b,f.source=e,f.sourceRowContainer=c,f.sourceColContainer=d,f.newScrollLeft=null,f.newScrollTop=null,f.x=null,f.y=null,f.fireThrottledScrollingEvent=a.throttle(function(){f.grid.api.core.raise.scrollEvent(f)},f.grid.options.scrollThrottle,{trailing:!0})}return b.prototype.fireScrollingEvent=function(){this.grid.api.core.raise.scrollEvent(this)},b.prototype.getNewScrollLeft=function(b,c){var d=this;if(!d.newScrollLeft){var e,f=b.getCanvasWidth()-b.getViewportWidth(),g=a.normalizeScrollLeft(c);if("undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage)e=d.x.percentage;else{if("undefined"==typeof d.x.pixels||void 0===d.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");e=d.x.percentage=(g+d.x.pixels)/f}return Math.max(0,e*f)}return d.newScrollLeft},b.prototype.getNewScrollTop=function(a,b){var c=this;if(!c.newScrollTop){var d,e=a.getVerticalScrollLength(),f=b[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)d=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=c.y.percentage=(f+c.y.pixels)/e}return Math.max(0,d*e)}return c.newScrollTop},b.Sources={ViewPortScroll:"ViewPortScroll",RenderContainerMouseWheel:"RenderContainerMouseWheel",RenderContainerTouchMove:"RenderContainerTouchMove",Other:99},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowBuilder(g.rowTemplateAssigner),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)},rowTemplateAssigner:function(d){var e=this;if(d.rowTemplate){var f=b.defer();d.getRowTemplateFn=f.promise,a.getTemplate(d.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+d.rowTemplate+"'")})}else d.rowTemplate=e.options.rowTemplate,d.getRowTemplateFn=e.getRowTemplateFn;return d.getRowTemplateFn}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var b=angular.module("ui.grid");b.service("rowSearcher",["gridUtil","uiGridConstants",function(b,c){var d=c.filter.STARTS_WITH,e={};return e.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},e.stripTerm=function(b){var c=e.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},e.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return d;var b=e.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var f=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+f+"$",c)}return d},e.setupFilters=function(a){for(var b=[],d=a.length,f=0;d>f;f++){var g=a[f];if(g.noTerm||g.term){var h={},i="";g.flags&&g.flags.caseSensitive||(i+="i"),g.term&&(h.term=e.stripTerm(g)),h.condition=g.condition?g.condition:e.guessCondition(g),h.flags=angular.extend({caseSensitive:!1,date:!1},g.flags),h.condition===c.filter.STARTS_WITH&&(h.startswithRE=new RegExp("^"+h.term,i)),h.condition===c.filter.ENDS_WITH&&(h.endswithRE=new RegExp(h.term+"$",i)),h.condition===c.filter.CONTAINS&&(h.containsRE=new RegExp(h.term,i)),h.condition===c.filter.EXACT&&(h.exactRE=new RegExp("^"+h.term+"$",i)),b.push(h)}}return b},e.runColumnFilter=function(a,b,d,e){var f=typeof e.condition,g=e.term,h=a.getCellValue(b,d);if(e.condition instanceof RegExp)return e.condition.test(h);if("function"===f)return e.condition(g,h,b,d);if(e.startswithRE)return e.startswithRE.test(h);if(e.endswithRE)return e.endswithRE.test(h);if(e.containsRE)return e.containsRE.test(h);if(e.exactRE)return e.exactRE.test(h);if(e.condition===c.filter.NOT_EQUAL){var i=new RegExp("^"+g+"$");return!i.exec(h)}if("number"==typeof h){var j=parseFloat(g.replace(/\\./,"."));isNaN(j)||(g=j)}return e.flags.date===!0&&(h=new Date(h),g=new Date(g.replace(/\\/g,""))),e.condition===c.filter.GREATER_THAN?h>g:e.condition===c.filter.GREATER_THAN_OR_EQUAL?h>=g:e.condition===c.filter.LESS_THAN?g>h:e.condition===c.filter.LESS_THAN_OR_EQUAL?g>=h:!0},e.searchColumn=function(a,b,c,d){if(a.options.useExternalFiltering)return!0;for(var f=d.length,g=0;f>g;g++){var h=d[g],i=e.runColumnFilter(a,b,c,h);if(!i)return!1}return!0},e.search=function(a,b,c){if(b){for(var d=[],f=c.length,g=0;f>g;g++){var h=c[g];"undefined"!=typeof h.filters&&(h.filters.length>1||1===h.filters.length&&("undefined"!=typeof h.filters[0].term&&h.filters[0].term||h.filters[0].noTerm))?d.push({col:h,filters:e.setupFilters(h.filters)}):"undefined"!=typeof h.filter&&h.filter&&("undefined"!=typeof h.filter.term&&h.filter.term||h.filter.noTerm)&&d.push({col:h,filters:e.setupFilters([h.filter])})}if(d.length>0){for(var i=function(a,b,c,d){(b.forceInvisible||!e.searchColumn(a,b,c,d))&&(b.visible=!1)},j=function(a,c){for(var d=b.length,e=0;d>e;e++)i(a,b[e],c.col,c.filters)},k=d.length,l=0;k>l;l++)j(a,d[l]);a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()}return b}},e}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toString().toLowerCase(),f=b.toString().toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);angular.forEach(c,function(a,b){a.entity.$uiGridIndex=b});var j=c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return 0===k?c.entity.$uiGridIndex-e.entity.$uiGridIndex:h===b.ASC?k:0-k});return angular.forEach(j,function(a){delete a.entity.$uiGridIndex}),j}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,e){var f,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=f||null==f){if(f=i[d],(0>f||null==f)&&(f=c.style[d]),g.test(f))return f;h=j&&!0,f=parseFloat(f)||0}var k=f+b(c,d,e||(j?"border":"content"),h,i);return k}function d(b){b=angular.element(b)[0];var c=b.offsetParent;return c||(c=document.getElementsByTagName("body")[0]),parseInt(a(c).fontSize)||parseInt(a(b).fontSize)||16}var e,f=angular.module("ui.grid");"function"!=typeof Function.prototype.bind&&(e=function(){var a=Array.prototype.slice;return function(b){var c=this,d=a.call(arguments,1);return d.length?function(){return arguments.length?c.apply(b,d.concat(a.call(arguments))):c.apply(b,d)}:function(){return arguments.length?c.apply(b,arguments):c.call(b)}}});var g=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),h=/^(block|none|table(?!-c[ea]).+)/,i={position:"absolute",visibility:"hidden",display:"block"},j=["0","0","0"],k="uiGrid-";f.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,f,g,l,m,n,o,p,q,r){function s(a,b){var c=angular.element(this),d=0,e=0,f=0,g=0;if(b.originalEvent&&(b=b.originalEvent),"detail"in b&&(f=-1*b.detail),"wheelDelta"in b&&(f=b.wheelDelta),"wheelDeltaY"in b&&(f=b.wheelDeltaY),"wheelDeltaX"in b&&(e=-1*b.wheelDeltaX),"axis"in b&&b.axis===b.HORIZONTAL_AXIS&&(e=-1*f,f=0),d=0===f?e:f,"deltaY"in b&&(f=-1*b.deltaY,d=f),"deltaX"in b&&(e=b.deltaX,0===f&&(d=-1*e)),0!==f||0!==e){if(1===b.deltaMode){var h=c.data("mousewheel-line-height");d*=h,f*=h,e*=h}else if(2===b.deltaMode){var i=c.data("mousewheel-page-height");d*=i,f*=i,e*=i}g=Math.max(Math.abs(f),Math.abs(e)),(!x||x>g)&&(x=g,u(b,g)&&(x/=40)),d=Math[d>=1?"floor":"ceil"](d/x),e=Math[e>=1?"floor":"ceil"](e/x),f=Math[f>=1?"floor":"ceil"](f/x),b.deltaMode=0;var j={originalEvent:b,deltaX:e,deltaY:f,deltaFactor:x,preventDefault:function(){b.preventDefault()}};w&&clearTimeout(w),w=setTimeout(t,200),a.call(c[0],j)}}function t(){x=null}function u(a,b){return"mousewheel"===a.type&&b%120===0}var v={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(m.get(a))return v.postProcessTemplate(m.get(a));if(a.hasOwnProperty("then"))return a.then(v.postProcessTemplate);try{if(angular.element(a).length>0)return p.when(a).then(v.postProcessTemplate)}catch(b){}return v.logDebug("fetching url",a),l({method:"GET",url:a}).then(function(b){var c=b.data.trim();return m.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(v.postProcessTemplate)},postProcessTemplate:function(a){var b=q.startSymbol(),c=q.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),p.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in f||f.DocumentTouch&&g instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:f.requestAnimationFrame&&f.requestAnimationFrame.bind(f)||f.webkitRequestAnimationFrame&&f.webkitRequestAnimationFrame.bind(f)||function(a){return n(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=o.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=o.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=j.length;b;){if(b--,a=j[b].charCodeAt(0),57===a)return j[b]="A",k+j.join("");if(90!==a)return j[b]=String.fromCharCode(a+1),k+j.join("");j[b]="0"}return j.unshift("0"),k+j.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=v.nextUid()):b=a,c+":"+b},resetUids:function(){j=["0","0","0"]},logError:function(a){r.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){r.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){r.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);v["element"+d]=function(d,e){var f=d;if(f&&"undefined"!=typeof f.length&&f.length&&(f=d[0]),f){var g=a(f);return 0===f.offsetWidth&&h.test(g.display)?v.fakeElement(f,i,function(a){return c(a,b,e)}):c(f,b,e)}return null},v["outerElement"+d]=function(a,b){return a?v["element"+d].call(this,a,b?"margin":"border"):null}}),v.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},v.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},v.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},v.detectBrowser=function(){var a=f.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},v.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=v.detectBrowser(),c=a.scrollLeft,d=v.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},v.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=v.detectBrowser(),d=v.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},v.preEval=function(a){var b=r.BRACKET_REGEXP.exec(a);if(b)return(b[1]?v.preEval(b[1]):b[1])+b[2]+(b[3]?v.preEval(b[3]):b[3]);a=a.replace(r.APOS_REGEXP,"\\'");var c=a.split(r.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(r.FUNC_REGEXP,"']$1"))}),d.join("['")},v.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&n.cancel(e),e=n(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){n.cancel(e),e=null},d},v.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),n(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=n(d,b-a))}}},v.on={},v.off={},v._events={},v.addOff=function(a){v.off[a]=function(b,c){var d=v._events[a].indexOf(c);d>0&&v._events[a].removeAt(d)}};var w,x,y="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"];return v.on.mousewheel=function(a,b){if(a&&b){var c=angular.element(a);c.data("mousewheel-line-height",d(c)),c.data("mousewheel-page-height",v.elementHeight(c)),c.data("mousewheel-callbacks")||c.data("mousewheel-callbacks",{});var f=c.data("mousewheel-callbacks");f[b]=(Function.prototype.bind||e).call(s,c[0],b);for(var g=y.length;g;)c.on(y[--g],f[b])}},v.off.mousewheel=function(a,b){var c=angular.element(this),d=c.data("mousewheel-callbacks"),e=d[b];if(e)for(var f=y.length;f;)c.off(y[--f],e);delete d[b],0===Object.keys(d).length&&(c.removeData("mousewheel-line-height"),c.removeData("mousewheel-page-height"),c.removeData("mousewheel-callbacks"))},v}]),f.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"Eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Links anheften",pinRight:"Rechts anheften",unpin:"Lösen"},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."},pagination:{sizes:"Einträge pro Seite",totalItems:"Einträge"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},pagination:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."},pagination:{sizes:"articles par page",totalItems:"articles"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ja",{aggregate:{label:"件"},groupPanel:{description:"列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。"},search:{placeholder:"検索...",showingItems:"絞込み件数:",selectedItems:"選択件数:",totalItems:"全件数:",size:"ページサイズ: ",first:"最初のページ",next:"次のページ",previous:"前のページ",last:"最後のページ"},menu:{text:"列選択:"},sort:{ascending:"昇順ソート",descending:"降順ソート",remove:"ソート取消"},column:{hide:"列を隠す"},aggregation:{count:"合計件数: ",sum:"合計: ",avg:"平均: ",min:"最小値: ",max:"最大値: "},pinning:{pinLeft:"左にピン留め",pinRight:"右にピン留め",unpin:"ピン留め取消"},gridMenu:{columns:"列:",importerTitle:"インポートファイル",exporterAllAsCsv:"全てのデータをCSV形式でエクスポート",exporterVisibleAsCsv:"絞込み済みデータをCSV形式でエクスポート",exporterSelectedAsCsv:"選択しているデータをCSV形式でエクスポート",exporterAllAsPdf:"全てのデータをPDFでエクスポート",exporterVisibleAsPdf:"絞込み済みデータをPDFでエクスポート",exporterSelectedAsPdf:"選択しているデータをPDFでエクスポート"},importer:{noHeaders:"列名が抽出できません。ヘッダーは設定されていますか?",noObjects:"データが抽出できません。ファイルにデータは含まれていますか?",invalidCsv:"処理を行うことができません。ファイルは有効なCSVファイルですか?",invalidJson:"処理を行うことができません。ファイルは有効なJSONファイルですか?",jsonNotArray:"JSONファイルは配列を含んでいる必要があります。処理を中断します。"},pagination:{sizes:"件 / ページ",totalItems:"件"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"всего строк: ",sum:"итого: ",avg:"среднее: ",min:"мин: ",max:"макс: "},gridMenu:{columns:"Столбцы:",importerTitle:"Import file",exporterAllAsCsv:"Экспортировать всё в CSV",exporterVisibleAsCsv:"Экспортировать видимые данные в CSV",exporterSelectedAsCsv:"Экспортировать выбранные данные в CSV",exporterAllAsPdf:"Экспортировать всё в PDF",exporterVisibleAsPdf:"Экспортировать видимые данные в PDF",exporterSelectedAsPdf:"Экспортировать выбранные данные в PDF"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},pagination:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"},pagination:{sizes:"行每页",totalItems:"行"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"},pagination:{sizes:"行每頁",totalItems:"行"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3,PG_UP:4,PG_DOWN:5},EVENT_TYPE:{KEYDOWN:0,CLICK:1,CLEAR:2}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[],this.bodyContainer=a};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getFocusableRows=function(){return this.rows.filter(function(a){return a.allowCellFocus!==!1})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c);case d.direction.PG_UP:return this.getRowColPageUp(b,c);case d.direction.PG_DOWN:return this.getRowColPageDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=1);var h=0===f?d.length-1:f-1;return h>f?0===g?new a(b,d[h]):new a(e[g-1],d[h]):new a(b,d[h])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=f===d.length-1?0:f+1;return f>h?g===e.length-1?new a(b,d[h]):new a(e[g+1],d[h]):new a(b,d[h])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),g===e.length-1?new a(b,d[f]):new a(e[g+1],d[f])},e.prototype.getRowColPageDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return g>=e.length-h?new a(e[e.length-1],d[f]):new a(e[g+h],d[f])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),0===g?new a(b,d[f]):new a(e[g-1],d[f])},e.prototype.getRowColPageUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return 0>g-h?new a(e[0],d[f]):new a(e[g-h],d[f])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory","ScrollEvent",function(a,b,c,d,e,f){var g={initializeGrid:function(a){a.registerColumnBuilder(g.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null,a.cellNav.focusedCells=[],g.defaultGridOptions(a.options);var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(b,c){g.scrollTo(a,b,c)},scrollToFocus:function(b,c){g.scrollToFocus(a,b,c)},scrollToIfNecessary:function(b,c){g.scrollToIfNecessary(a,b,c)},getFocusedCell:function(){return a.cellNav.lastRowCol},getCurrentSelection:function(){return a.cellNav.focusedCells},rowColSelectIndex:function(b){for(var c=-1,d=0;d<a.cellNav.focusedCells.length;d++)if(a.cellNav.focusedCells[d].col.uid===b.col.uid&&a.cellNav.focusedCells[d].row.uid===b.row.uid){c=d;break}return c}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.modifierKeysToMultiSelectCells=a.modifierKeysToMultiSelectCells===!0},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.PG_UP?c.direction.PG_UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:a.keyCode===b.keymap.PG_DOWN?c.direction.PG_DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c){var d=null,e=null;null!==b&&"undefined"!=typeof b&&(d=a.getRow(b)),null!==c&&"undefined"!=typeof c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e)},scrollToFocus:function(a,b,c){var d=null,e=null;null!==b&&(d=a.getRow(b)),null!==c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e);var f={row:d,col:e};a.cellNav.broadcastCellNav(f)},scrollToInternal:function(a,b,c){var d=new f(a,null,null,"uiGridCellNavService.scrollToInternal");if(null!==b){var e=a.renderContainers.body.visibleRowCache.indexOf(b),g=a.renderContainers.body.visibleRowCache.length,h=(e+e/(g-1))/g;d.y={percentage:h}}null!==c&&(d.x={percentage:this.getLeftWidth(a,c)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(d.y||d.x)&&d.fireScrollingEvent()},scrollToIfNecessary:function(a,b,c){var d=new f(a,"uiGridCellNavService.scrollToIfNecessary"),e=a.renderContainers.body.visibleRowCache,g=a.renderContainers.body.visibleColumnCache,h=a.renderContainers.body.prevScrollTop+a.headerHeight;h=0>h?0:h;var i=a.renderContainers.body.prevScrollLeft,j=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight,k=a.renderContainers.body.prevScrollLeft+Math.ceil(a.gridWidth);if(null!==b){var l=e.indexOf(b),m=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight(),n=(l+1)*a.options.rowHeight;n=0>n?0:n;var o,p;h>n?(o=a.renderContainers.body.prevScrollTop-(h-n),p=o/m,d.y={percentage:p}):n>j&&(o=n-j+a.renderContainers.body.prevScrollTop,p=o/m,d.y={percentage:p})}if(null!==c){for(var q=g.indexOf(c),r=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),s=0,t=0;q>t;t++){var u=g[t];s+=u.drawnWidth}s=0>s?0:s;var v=s+c.drawnWidth;v=0>v?0:v;var w,x;i>s?(w=a.renderContainers.body.prevScrollLeft-(i-s),x=w/r,x=x>1?1:x,d.x={percentage:x}):v>k&&(w=v-k+a.renderContainers.body.prevScrollLeft,x=w/r,x=x>1?1:x,d.x={percentage:x})}(d.y||d.x)&&d.fireScrollingEvent()},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return g}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,f,g,h){var i=b,j=h.grid;c.initializeGrid(j),h.cellNav={},h.cellNav.focusCell=function(a,b){h.cellNav.broadcastCellNav({row:a,col:b})},h.cellNav.broadcastCellNav=j.cellNav.broadcastCellNav=function(a,b){b=!(void 0===b||!b),h.cellNav.broadcastFocus(a,b),i.$broadcast(d.CELL_NAV_EVENT,a,b)},h.cellNav.clearFocus=j.cellNav.clearFocus=function(){i.$broadcast(d.CELL_NAV_EVENT,{eventType:d.EVENT_TYPE.CLEAR})},h.cellNav.broadcastFocus=function(b,c){c=!(void 0===c||!c);var d=b.row,e=b.col,f=h.grid.api.cellNav.rowColSelectIndex(b);if(null===j.cellNav.lastRowCol||-1===f){var g=new a(d,e);j.api.cellNav.raise.navigate(g,j.cellNav.lastRowCol),j.cellNav.lastRowCol=g,h.grid.options.modifierKeysToMultiSelectCells&&c?j.cellNav.focusedCells.push(b):j.cellNav.focusedCells=[b]}else j.options.modifierKeysToMultiSelectCells&&c&&f>=0&&j.cellNav.focusedCells.splice(f,1)},h.cellNav.handleKeyDown=function(a){var b=c.getDirection(a);if(null===b)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var g=h.grid.api.cellNav.getFocusedCell();if(g){var i=h.grid.renderContainers[f].cellNav.getNextRowCol(b,g.row,g.col);return b===d.direction.LEFT&&i.row===g.row&&a.keyCode===e.keymap.TAB&&a.shiftKey?(h.cellNav.clearFocus(),!0):b!==d.direction.RIGHT||i.row!==g.row||a.keyCode!==e.keymap.TAB||a.shiftKey?(i.eventType=d.EVENT_TYPE.KEYDOWN,h.cellNav.broadcastCellNav(i),c.scrollToIfNecessary(j,i.row,i.col),a.stopPropagation(),a.preventDefault(),!1):(h.cellNav.clearFocus(),!0)}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,d,f,g){var h=g[0],i=g[1];if(h.grid.api.cellNav){var j=i.containerId,k=h.grid;e.decorateRenderContainers(k),d.attr("tabindex",-1),d.on("keydown",function(a){return a.uiGridTargetRenderContainerId=j,h.cellNav.handleKeyDown(a)});var l=!1;k.api.core.on.scrollEvent(c,function(c){c.grid&&c.grid.id!==h.grid.id||null!=h.grid.api.cellNav.getFocusedCell()&&("uiGridCellNavService.scrollToIfNecessary"===c.source?l=!0:l&&a(function(){a(function(){var a=h.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&d[0].focus(),h.cellNav.broadcastCellNav(a),l=!1})}))})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",0)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}e.grid.api.cellNav&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey),c.stopPropagation()}),c.find("div").on("focus",function(c){console.log("cellNav focus"),e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey)}),b.$on(f.CELL_NAV_EVENT,function(a,d,g){return a.eventType===f.EVENT_TYPE.CLEAR?void i():void(d.row===b.row&&d.col===b.col?(e.grid.options.modifierKeysToMultiSelectCells&&g&&-1===e.grid.api.cellNav.rowColSelectIndex(d)?i():h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&(console.log("focus from navEvent"),c.find("div")[0].focus())):e.grid.options.modifierKeysToMultiSelectCells&&g||i())
    +}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","$timeout","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g,h){var i=500;return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(f,j,k,l){function m(){j.on("dblclick",t),j.on("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").on("focus",q),j.on("touchstart",n)}function n(a){"undefined"!=typeof a.originalEvent&&void 0!==a.originalEvent&&(a=a.originalEvent),j.on("touchend",o),A=c(function(){},i),A.then(function(){setTimeout(t,0),j.off("touchend",o)})}function o(){c.cancel(A),j.off("touchend",o)}function p(){j.off("dblclick",t),j.off("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").off("focus",q),j.off("touchstart",n)}function q(a){l&&l.cellNav&&l.cellNav.focusCell(f.row,f.col),a.stopPropagation(),t()}function r(a){h.isStartEditKey(a)&&t()}function s(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(f):a.colDef.cellEditableCondition)}function t(){if(!C&&s(f.col,f.row)){f.grid.api.cellNav&&f.grid.api.cellNav.scrollToIfNecessary(f.row,f.col),z=g(f.row.getQualifiedColField(f.col)),y=z(f),x=f.col.editableCellTemplate,x=x.replace(d.MODEL_COL_FIELD,f.row.getQualifiedColField(f.col));var b=f.col.colDef.editDropdownFilter?"|"+f.col.colDef.editDropdownFilter:"";x=x.replace(d.CUSTOM_FILTERS,b);var c="text";switch(f.col.colDef.type){case"boolean":c="checkbox";break;case"number":c="number";break;case"date":c="date"}x=x.replace("INPUT_TYPE",c);var h=f.col.colDef.editDropdownRowEntityOptionsArrayPath;f.editDropdownOptionsArray=h?w(f.row.entity,h):f.col.colDef.editDropdownOptionsArray,f.editDropdownIdLabel=f.col.colDef.editDropdownIdLabel?f.col.colDef.editDropdownIdLabel:"id",f.editDropdownValueLabel=f.col.colDef.editDropdownValueLabel?f.col.colDef.editDropdownValueLabel:"value";f.$apply(function(){C=!0,p();var b=angular.element(x);j.append(b),B=f.$new(),a(b)(B);var c=angular.element(j.children()[0]);D=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var i=f.col.grid.api.core.on.scrollEvent(f,function(){u(!0),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),i(),k(),l()}),k=f.$on(e.events.END_CELL_EDIT,function(a,b){u(b),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),k(),i(),l()}),l=f.$on(e.events.CANCEL_CELL_EDIT,function(){v(),l(),i(),k()});f.$broadcast(e.events.BEGIN_CELL_EDIT),f.grid.api.edit.raise.beginCellEdit(f.row.entity,f.col.colDef)}}function u(a){if(C){var b=angular.element(j.children()[0]);B.$destroy(),angular.element(j.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&D&&b[0].focus(),D=!1,C=!1,m(),f.grid.api.core.notifyDataChange(d.dataChange.EDIT)}}function v(){C&&(z.assign(f,y),f.$apply(),f.grid.api.edit.raise.cancelCellEdit(f.row.entity,f.col.colDef),u(!0))}function w(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split(".");c.length;){var d=c.shift();if(!(d in a))return;a=a[d]}return a}if(f.col.colDef.enableCellEdit&&f.row.enableCellEdit!==!1){var x,y,z,A,B,C=!1,D=!1;m();try{var E=b.get("uiGridCellNavConstants");f.col.colDef.enableCellEditOnFocus&&f.$on(E.CELL_NAV_EVENT,function(a,b){b.row===f.row&&b.col===f.col?t():u()})}catch(F){}}}}}]),a.directive("uiGridEditor",["gridUtil","uiGridConstants","uiGridEditConstants",function(a,b,c){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(a,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),a.$on(c.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(b){a.stopEdit(b)})}),a.deepEdit=!1,a.stopEdit=function(b){a.inputForm&&!a.inputForm.$valid?(b.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT)):a.$emit(c.events.END_CELL_EDIT),a.deepEdit=!1},d.on("click",function(){a.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case b.keymap.ESC:d.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT);break;case b.keymap.ENTER:a.stopEdit(d);break;case b.keymap.TAB:a.stopEdit(d)}if(a.deepEdit)switch(d.keyCode){case b.keymap.LEFT:d.stopPropagation();break;case b.keymap.RIGHT:d.stopPropagation();break;case b.keymap.UP:d.stopPropagation();break;case b.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("uiGridEditor",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{priority:-100,require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.expandable={},c.expandable.expandedAll=!1,c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.expandableRowHeaderWidth=c.options.expandableRowHeaderWidth||40,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)},toggleAllRows:function(){b.toggleAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.isExpanded?b.height=b.grid.options.rowHeight+a.options.expandableRowHeight:(b.height=b.grid.options.rowHeight,a.expandable.expandedAll=!1),a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!0,a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!1,a.refresh()},toggleAllRows:function(a){a.expandable.expandedAll?b.collapseAllRows(a):b.expandAllRows(a)}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",displayName:"",exporterSuppressExport:!0,enableColumnResizing:!1,enableColumnMenu:!1,width:f.grid.options.expandableRowHeaderWidth||40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),g.headerCellTemplate=b.get("ui-grid/expandableTopRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGrid",["uiGridExpandableService","$templateCache",function(){return{replace:!0,priority:1e3,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,c,d){d.grid.api.core.on.renderingComplete(a,function(){a.row&&a.row.grid&&a.row.grid.options&&a.row.grid.options.enableExpandable&&(d.grid.parentRow=a.row)})},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",BUTTON_LABEL:"BUTTON_LABEL",FILE_NAME:"FILE_NAME"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c){h.csvExport(a,b,c)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterCsvFilename=a.exporterCsvFilename?a.exporterCsvFilename:"download.csv",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterHeaderFilterUseName=a.exporterHeaderFilterUseName===!0,a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.formatAsCsv(d,e,a.options.exporterCsvColumnSeparator);this.downloadFile(a.options.exporterCsvFilename,f)},getColumnHeaders:function(a,c){var d=[];return angular.forEach(a.columns,function(e){!e.visible&&c!==b.ALL||e.colDef.exporterSuppressExport===!0||-1!==a.options.exporterSuppressColumns.indexOf(e.name)||d.push({name:e.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(a.options.exporterHeaderFilterUseName?e.name:e.displayName):e.displayName,width:e.drawnWidth?e.drawnWidth:e.width,align:"number"===e.colDef.type?"right":"left"})}),d},getData:function(a,c,e){var f,g=[];switch(c){case b.ALL:f=a.rows;break;case b.VISIBLE:f=a.getVisibleRows();break;case b.SELECTED:a.api.selection?f=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(f,function(c){if(c.exporterEnableExporting!==!1){var d=[];angular.forEach(a.columns,function(f){if((f.visible||e===b.ALL)&&f.colDef.exporterSuppressExport!==!0&&-1===a.options.exporterSuppressColumns.indexOf(f.name)){var g={value:a.options.exporterFieldCallback(a,c,f,a.getCellValue(c,f))};f.colDef.exporterPdfAlign&&(g.alignment=f.colDef.exporterPdfAlign),d.push(g)}}),g.push(d)}}),g},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},downloadFile:function(a,b){var c,d=document,e=d.createElement("a"),f="application/octet-stream;charset=utf-8";if(navigator.msSaveBlob)return navigator.msSaveBlob(new Blob(["",b],{type:f}),a);if("download"in e){var g=new Blob([b],{type:f});c=URL.createObjectURL(g),e.setAttribute("download",a)}else c="data:"+f+","+encodeURIComponent(b),e.setAttribute("target","_blank");e.href=c,e.setAttribute("style","display:none;"),d.body.appendChild(e),setTimeout(function(){if(e.click)e.click();else if(document.createEvent){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0),e.dispatchEvent(a)}d.body.removeChild(e)},100)},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&(h.header=a.options.exporterPdfHeader),a.options.exporterPdfFooter&&(h.footer=a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a){i.importThisFile(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(c),d()},[b.dataChange.ROW]);a.importer.$scope.$on("$destroy",d)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){var c=a.srcElement||a.target;if(c&&c.files&&1===c.files.length){var d=c.files[0];b.importThisFile(i,d),c.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout","uiGridConstants",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options);var b={events:{infiniteScroll:{needLoadMoreData:function(){},needLoadMoreDataTop:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){return a.options.loadTimout=!0,a.scrollDirection===d.scrollDirection.UP?void a.api.infiniteScroll.raise.needLoadMoreDataTop():void a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return e}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.grid.api.core.on.scrollEvent(a,function(b){if(b.y&&"ui.grid.adjustInfiniteScrollPosition"!==b.source){var e=100-100*b.y.percentage;a.grid.scrollDirection===d.scrollDirection.UP&&(e=100*b.y.percentage),c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);a.service("uiGridMoveColumnService",["$q","$timeout","$log","ScrollEvent","uiGridConstants",function(a,b,c,d,e){var f={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){var e=a.columns;if(!angular.isNumber(c)||!angular.isNumber(d))return void console.log("Please provide valid values for originalPosition and finalPosition");for(var f=0,g=0;g<e.length;g++)(angular.isDefined(e[g].colDef.visible)&&e[g].colDef.visible===!1||e[g].isRowHeader===!0)&&f++;if(c>=e.length-f||d>=e.length-f)return void console.log("Invalid values for originalPosition, finalPosition");var h=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};b.redrawColumnAtPosition(a,h(c),h(d))}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var f=a.columns,g=f[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)f[h]=f[h-1];else if(d>c)for(var i=c;d>i;i++)f[i]=f[i+1];f[d]=g,b(function(){a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d),a.api.core.notifyDataChange(e.dataChange.COLUMN)})}}};return f}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,h,i){a.col.colDef.enableColumnMoving&&a.$on(f.events.COLUMN_HEADER_CLICK,function(f,h){if(h.columnName===a.col.colDef.name&&!a.col.renderContainer){var j=h.event;if("ui-grid-icon-angle-down"!==j.target.className&&"I"!==j.target.tagName&&j.target.className.indexOf("ui-grid-filter-input")<0){var k,l,m=a.grid.element[0].getBoundingClientRect().left,n=j.pageX,o=0,p=m+a.grid.getViewportWidth(),q=!1,r=function(){q=!0,k=e.clone(),e.parent().append(k),k.addClass("movingColumn");var b={},c=e[0].getBoundingClientRect().left;b.left=c-m+"px";var d=a.grid.element[0].getBoundingClientRect().right,f=e[0].getBoundingClientRect().right;f>d&&(l=a.col.drawnWidth+(d-f),b.width=l+"px"),k.css(b)},s=function(c){i.fireEvent("hide-menu");for(var d=a.grid.columns,e=0,f=0;f<d.length;f++)(angular.isUndefined(d[f].colDef.visible)||d[f].colDef.visible===!0)&&(e+=d[f].drawnWidth||d[f].width||d[f].colDef.width);var h,j=k[0].getBoundingClientRect().left-1,n=k[0].getBoundingClientRect().right;if(h="ie"===b.detectBrowser()?j+c:j-m+c,h=p>h?h:p,(j>=m||c>0)&&(p>=n||0>c))k.css({visibility:"visible",left:h+"px"});else if(e>Math.ceil(i.grid.gridWidth)){c*=8;var q=new g(a.col.grid,null,null,"uiGridHeaderCell.moveElement");q.x={pixels:c},q.fireScrollingEvent()}for(var r=0,s=0;s<d.length;s++)if(angular.isUndefined(d[s].colDef.visible)||d[s].colDef.visible===!0){if(d[s].colDef.name===a.col.colDef.name)break;r+=d[s].drawnWidth||d[s].width||d[s].colDef.width}void 0===a.newScrollLeft?o+=c:o=a.newScrollLeft+h-r,l<a.col.drawnWidth&&(l+=Math.abs(c),k.css({width:l+"px"}))
    +},t=function(a){document.onselectstart=function(){return!1};var b=a.pageX-n;!q&&Math.abs(b)>50?r():q&&(s(b),n=a.pageX)};d.on("mousemove",t);var u=function(){document.onselectstart=null,k&&k.remove();for(var b=a.grid.columns,e=0,f=0;f<b.length&&b[f].colDef.name!==a.col.colDef.name;f++)e++;if(0>o){for(var g=0,h=e-1;h>=0;h--)if((angular.isUndefined(b[h].colDef.visible)||b[h].colDef.visible===!0)&&(g+=b[h].drawnWidth||b[h].width||b[h].colDef.width,g>Math.abs(o))){c.redrawColumnAtPosition(a.grid,e,h+1);break}g<Math.abs(o)&&c.redrawColumnAtPosition(a.grid,e,0)}else if(o>0){for(var i=0,j=e+1;j<b.length;j++)if((angular.isUndefined(b[j].colDef.visible)||b[j].colDef.visible===!0)&&(i+=b[j].drawnWidth||b[j].width||b[j].colDef.width,i>o)){c.redrawColumnAtPosition(a.grid,e,j-1);break}o>i&&c.redrawColumnAtPosition(a.grid,e,b.length-1)}d.off("mousemove",t),d.off("mouseup",u)};d.on("mouseup",u)}}})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ng","ui.grid"]);a.service("uiGridPaginationService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{pagination:{paginationChanged:function(){}}},methods:{pagination:{getPage:function(){return a.options.enablePagination?a.options.paginationCurrentPage:null},getTotalPages:function(){return a.options.enablePagination?0===a.options.totalItems?1:Math.ceil(a.options.totalItems/a.options.paginationPageSize):null},nextPage:function(){a.options.enablePagination&&(a.options.totalItems>0?a.options.paginationCurrentPage=Math.min(a.options.paginationCurrentPage+1,c.methods.pagination.getTotalPages()):a.options.paginationCurrentPage++)},previousPage:function(){a.options.enablePagination&&(a.options.paginationCurrentPage=Math.max(a.options.paginationCurrentPage-1,1))},seek:function(b){if(a.options.enablePagination){if(!angular.isNumber(b)||1>b)throw"Invalid page number: "+b;a.options.paginationCurrentPage=Math.min(b,c.methods.pagination.getTotalPages())}}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPagination||!a.options.enablePagination)return b;var c=parseInt(a.options.paginationPageSize,10),d=parseInt(a.options.paginationCurrentPage,10),e=b.filter(function(a){return a.visible});a.options.totalItems=e.length;var f=(d-1)*c;return f>e.length&&(d=a.options.paginationCurrentPage=1,f=(d-1)*c),e.slice(f,f+c)})},defaultGridOptions:function(b){b.enablePagination=b.enablePagination!==!1,b.enablePaginationControls=b.enablePaginationControls!==!1,b.useExternalPagination=b.useExternalPagination===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.paginationPageSizes)&&(b.paginationPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.paginationPageSize)&&(b.paginationPageSize=b.paginationPageSizes.length>0?b.paginationPageSizes[0]:0),a.isNullOrUndefined(b.paginationCurrentPage)&&(b.paginationCurrentPage=1),a.isNullOrUndefined(b.paginationTemplate)&&(b.paginationTemplate="ui-grid/pagination")},onPaginationChanged:function(a,b,c){a.api.pagination.raise.paginationChanged(b,c),a.options.useExternalPagination||a.refresh()}};return b}]),a.directive("uiGridPagination",["gridUtil","uiGridPaginationService",function(a,b){return{priority:-200,scope:!1,require:"uiGrid",link:{pre:function(c,d,e,f){b.initializeGrid(f.grid),a.getTemplate(f.grid.options.paginationTemplate).then(function(a){var b=angular.element(a);d.append(b),f.innerCompile(b)})}}}}]),a.directive("uiGridPager",["uiGridPaginationService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.paginationApi=h.grid.api.pagination,e.sizesLabel=d.getSafeText("pagination.sizes"),e.totalItemsLabel=d.getSafeText("pagination.totalItems");var i=h.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a});var j=h.grid.registerDataChangeCallback(function(a){a.options.useExternalPagination||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);e.$on("$destroy",j);var k=function(){e.showingLow=(i.paginationCurrentPage-1)*i.paginationPageSize+1,e.showingHigh=Math.min(i.paginationCurrentPage*i.paginationPageSize,i.totalItems)},l=e.$watch("grid.options.totalItems + grid.options.paginationPageSize",k),m=e.$watch("grid.options.paginationCurrentPage + grid.options.paginationPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.paginationCurrentPage)||i.paginationCurrentPage<1)return void(i.paginationCurrentPage=1);if(i.totalItems>0&&i.paginationCurrentPage>e.paginationApi.getTotalPages())return void(i.paginationCurrentPage=e.paginationApi.getTotalPages());k(),a.onPaginationChanged(e.grid,i.paginationCurrentPage,i.paginationPageSize)}});e.$on("$destroy",function(){l(),m()}),e.cantPageForward=function(){return i.totalItems>0?i.paginationCurrentPage>=e.paginationApi.getTotalPages():i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.paginationCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})},findTargetCol:function(a,b,c){var d=a.getRenderContainer();if("left"===b){var e=d.visibleColumnCache.indexOf(a);return d.visibleColumnCache[e-1*c]}return a}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q","uiGridResizeColumnsService","uiGridConstants","$timeout",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,d,h,i){var j=i.grid;if(j.options.enableColumnResizing){var k=b.get("ui-grid/columnResizer"),l=1;j.isRTL()&&(a.position="left",l=-1);var m=function(){for(var b=d[0].getElementsByClassName("ui-grid-column-resizer"),f=0;f<b.length;f++)angular.element(b[f]).remove();var g=e.findTargetCol(a.col,"left",l),h=a.col.getRenderContainer();if(g&&0!==h.visibleColumnCache.indexOf(a.col)&&g.colDef.enableColumnResizing!==!1){var i=angular.element(k).clone();i.attr("position","left"),d.prepend(i),c(i)(a)}if(a.col.colDef.enableColumnResizing!==!1){var j=angular.element(k).clone();j.attr("position","right"),d.append(j),c(j)(a)}};m();var n=function(){g(m)},o=j.registerDataChangeCallback(n,[f.dataChange.COLUMN]);a.$on("$destroy",o)}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","uiGridResizeColumnsService",function(a,b,c,d){var e,f,g,h=angular.element('<div class="ui-grid-resize-overlay"></div>');b.isTouchEnabled()?(e="touchstart",f="touchend",g="touchmove"):(e="mousedown",f="mouseup",g="mousemove");var i={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(i,j,k,l){function m(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function n(){l.grid.buildColumns().then(function(){l.grid.refreshCanvas(!0).then(function(){l.grid.refresh()})})}function o(a,b){var c=b;return a.colDef.minWidth&&c<a.colDef.minWidth?c=a.colDef.minWidth:a.colDef.maxWidth&&c>a.colDef.maxWidth&&(c=a.colDef.maxWidth),c}function p(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),s=(a.targetTouches?a.targetTouches[0]:a).clientX-t,0>s?s=0:s>l.grid.gridWidth&&(s=l.grid.gridWidth);var b=d.findTargetCol(i.col,i.position,u);if(b.colDef.enableColumnResizing!==!1){l.grid.element.hasClass("column-resizing")||l.grid.element.addClass("column-resizing");var e=s-r,f=parseInt(b.drawnWidth+e*u,10);s+=(o(b,f)-f)*u,h.css({left:s+"px"}),l.fireEvent(c.events.ITEM_DRAGGING)}}function q(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),l.grid.element.removeClass("column-resizing"),h.remove(),s=(b.changedTouches?b.changedTouches[0]:b).clientX-t;var c=s-r;if(0===c)return a.off(f,q),void a.off(g,p);var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var j=parseInt(e.drawnWidth+c*u,10);e.width=o(e,j),m(e),n(c),d.fireColumnSizeChanged(l.grid,e.colDef,c),a.off(f,q),a.off(g,p)}}var r=0,s=0,t=0,u=1;l.grid.isRTL()&&(i.position="left",u=-1),"left"===i.position?j.addClass("left"):"right"===i.position&&j.addClass("right"),j.on(e,function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),t=l.grid.element[0].getBoundingClientRect().left,r=(b.targetTouches?b.targetTouches[0]:b).clientX-t,l.grid.element.append(h),h.css({left:r}),a.on(f,q),a.on(g,p)}),j.on("dblclick",function(a){a.stopPropagation();var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var f=0,g=0,h=b.closestElm(j,".ui-grid-render-container"),k=h.querySelectorAll("."+c.COL_CLASS_PREFIX+e.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(k,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var h=b.elementWidth(c);e+=h}e>f&&(f=e,g=f-e)})}),e.width=o(e,f),m(e),n(g),d.fireColumnSizeChanged(l.grid,e.colDef,g)}}),j.on("$destroy",function(){j.off(e),j.off("dblclick"),a.off(g,p),a.off(f,q)})}};return i}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,c){f.setSavePromise(b,a,c)},getDirtyRows:function(){return b.rowEdit.dirtyRows?b.rowEdit.dirtyRows:[]},getErrorRows:function(){return b.rowEdit.errorRows?b.rowEdit.errorRows:[]},flushDirtyRows:function(){return f.flushDirtyRows(b)},setRowsDirty:function(a){f.setRowsDirty(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.saveState",["ui.grid","ui.grid.selection","ui.grid.cellNav"]);a.constant("uiGridSaveStateConstants",{featureName:"saveState"}),a.service("uiGridSaveStateService",["$q","uiGridSaveStateConstants","gridUtil","$compile","$interval","uiGridConstants",function(){var a={initializeGrid:function(b){b.saveState={},this.defaultGridOptions(b.options);var c={events:{saveState:{}},methods:{saveState:{save:function(){return a.save(b)},restore:function(c,d){a.restore(b,c,d)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.saveWidths=a.saveWidths!==!1,a.saveOrder=a.saveOrder!==!1,a.saveScroll=a.saveScroll===!0,a.saveFocus=a.saveScroll!==!0&&a.saveFocus!==!1,a.saveVisible=a.saveVisible!==!1,a.saveSort=a.saveSort!==!1,a.saveFilter=a.saveFilter!==!1,a.saveSelection=a.saveSelection!==!1},save:function(b){var c={};return c.columns=a.saveColumns(b),c.scrollFocus=a.saveScrollFocus(b),c.selection=a.saveSelection(b),c},restore:function(b,c,d){d.columns&&a.restoreColumns(b,d.columns),d.scrollFocus&&a.restoreScrollFocus(b,c,d.scrollFocus),d.selection&&a.restoreSelection(b,d.selection),b.refresh()},saveColumns:function(a){var b=[];return angular.forEach(a.columns,function(a){var c={};c.name=a.name,c.visible=a.visible,c.width=a.width,c.sort=angular.copy(a.sort),c.filters=angular.copy(a.filters),b.push(c)}),b},saveScrollFocus:function(b){if(!b.api.cellNav)return{};var c={};if(b.options.saveFocus){c.focus=!0;var d=b.api.cellNav.getFocusedCell();null!==d&&(c.colName=d.col.colDef.name,c.rowVal=a.getRowVal(b,d.row))}else b.options.saveScroll&&(c.focus=!1,b.renderContainers.body.prevRowScrollIndex&&(c.rowVal=a.getRowVal(b,b.renderContainers.body.visibleRowCache[b.renderContainers.body.prevRowScrollIndex])),b.renderContainers.body.prevColScrollIndex&&(c.colName=b.renderContainers.body.visibleColumnCache[b.renderContainers.body.prevColScrollIndex].name));return c},saveSelection:function(b){if(!b.api.selection||!b.options.saveSelection)return{};var c=b.api.selection.getSelectedGridRows().map(function(c){return a.getRowVal(b,c)});return c},getRowVal:function(a,b){if(!b)return null;var c={};return a.options.saveRowIdentity?(c.identity=!0,c.row=a.options.saveRowIdentity(b.entity)):(c.identity=!1,c.row=a.renderContainers.body.visibleRowCache.indexOf(b)),c},restoreColumns:function(a,b){angular.forEach(b,function(b,c){var d=a.columns.filter(function(a){return a.name===b.name});if(d.length>0){var e=a.columns.indexOf(d[0]);if((a.columns[e].visible!==b.visible||a.columns[e].colDef.visible!==b.visible)&&(a.columns[e].visible=b.visible,a.columns[e].colDef.visible=b.visible,a.api.core.raise.columnVisibilityChanged(a.columns[e])),a.columns[e].width=b.width,angular.equals(a.columns[e].sort,b.sort&&!(void 0===a.columns[e].sort&&angular.isEmpty(b.sort)))||(a.columns[e].sort=angular.copy(b.sort),a.api.core.raise.sortChanged()),angular.equals(a.columns[e].filters,b.filters)||(a.columns[e].filters=angular.copy(b.filters),a.api.core.raise.filterChanged()),e!==c){var f=a.columns.splice(e,1)[0];a.columns.splice(c,0,f)}}})},restoreScrollFocus:function(b,c,d){if(b.api.cellNav){var e,f;if(d.colName){var g=b.options.columnDefs.filter(function(a){return a.name===d.colName});g.length>0&&(e=g[0])}d.rowVal&&d.rowVal.row&&(f=d.rowVal.identity?a.findRowByIdentity(b,d.rowVal):b.renderContainers.body.visibleRowCache[d.rowVal.row]);var h=f&&f.entity?f.entity:null;(e||h)&&(d.focus?b.api.cellNav.scrollToFocus(h,e):b.api.cellNav.scrollTo(h,e))}},restoreSelection:function(b,c){b.api.selection&&(b.api.selection.clearSelectedRows(),angular.forEach(c,function(c){if(c.identity){var d=a.findRowByIdentity(b,c);d&&b.api.selection.selectRow(d.entity)}else b.api.selection.selectRowByVisibleIndex(c.row)}))},findRowByIdentity:function(a,b){if(!a.options.saveRowIdentity)return null;var c=a.rows.filter(function(c){return a.options.saveRowIdentity(c.entity)===b.row?!0:!1});return c.length>0?c[0]:null}};return a}]),a.directive("uiGridSaveState",["uiGridSaveStateConstants","uiGridSaveStateService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),angular.module("ui.grid").config(["$provide",function(a){a.decorator("GridRow",["$delegate",function(a){return a.prototype.setSelected=function(a){this.isSelected=a,a?this.grid.selection.selectedCount++:this.grid.selection.selectedCount--},a}])}]),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,b.selection.selectedCount=0,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c,d){var e=b.getRow(c);null!==e&&e.enableSelection!==!1&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c,d){var e=b.getRow(c);null===e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c,d){var e=b.renderContainers.body.visibleRowCache[c];null===e||"undefined"==typeof e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c,d){var e=b.getRow(c);null!==e&&e.isSelected&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},selectAllVisibleRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.visible?e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c)):e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},clearSelectedRows:function(c){a.clearSelectedRows(b,c)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30,a.enableFooterTotalSelected=a.enableFooterTotalSelected!==!1,a.isRowSelectable=angular.isDefined(a.isRowSelectable)?a.isRowSelectable:angular.noop},toggleRowSelection:function(b,c,d,e,f){var g=c.isSelected;if(e||g){if(!e&&g){var h=a.getSelectedRows(b);h.length>1&&(g=!1,a.clearSelectedRows(b,d))}}else a.clearSelectedRows(b,d);g&&f||c.enableSelection!==!1&&(c.setSelected(!g),c.isSelected===!0?b.selection.lastSelectedRow=c:b.selection.selectAll=!1,b.api.selection.raise.rowSelectionChanged(c,d))},shiftSelect:function(b,c,d,e){if(e){var f=a.getSelectedRows(b),g=f.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,h=b.renderContainers.body.visibleRowCache.indexOf(c);if(g>h){var i=g;g=h,h=i}for(var j=[],k=g;h>=k;k++){var l=b.renderContainers.body.visibleRowCache[k];l&&(l.isSelected||l.enableSelection===!1||(l.setSelected(!0),b.selection.lastSelectedRow=l,a.decideRaiseSelectionEvent(b,l,j,d)))}a.decideRaiseSelectionBatchEvent(b,j,d)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b,c){var d=[];a.getSelectedRows(b).forEach(function(e){e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!1},decideRaiseSelectionEvent:function(a,b,c,d){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b,d)},decideRaiseSelectionBatchEvent:function(a,b,c){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b,c)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,minWidth:10,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1,exporterSuppressExport:!0};f.grid.addRowHeaderColumn(g)}f.grid.options.isRowSelectable!==angular.noop&&f.grid.registerRowBuilder(function(a){a.enableSelection=f.grid.options.isRowSelectable(a)})},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,c,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,c,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,c,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(a,d){c.selection.selectAll?(b.clearSelectedRows(c,d),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0,d),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(d),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,c){function d(){a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(c.addClass("ui-grid-disable-selection"),c.on("touchstart",j),c.on("touchend",k),c.on("click",i),a.registered=!0)}function e(){a.registered&&(c.removeClass("ui-grid-disable-selection"),c.off("touchstart",j),c.off("touchend",k),c.off("click",i),a.registered=!1)}var g=0,h=300,i=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,b,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()},j=function(){g=(new Date).getTime()},k=function(a){var b=(new Date).getTime(),c=b-g;h>c&&i(a)};d();var l=a.grid.registerDataChangeCallback(function(){!a.grid.options.enableRowSelection||a.grid.options.enableRowHeaderSelection||a.registered?a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection||!a.registered||e():d()},[b.dataChange.OPTIONS]);c.on("$destroy",l)}}}]),a.directive("uiGridGridFooter",["$compile","uiGridConstants","gridUtil",function(a,b,c){return{restrict:"EA",replace:!0,priority:-1e3,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(b,d,e,f){f.grid.options.showGridFooter&&c.getTemplate("ui-grid/gridFooterSelectedItems").then(function(c){var e=angular.element(c),f=a(e)(b);angular.element(d[0].getElementsByClassName("ui-grid-grid-footer")[0]).append(f)})},post:function(){}}}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel ui-grid-footer-aggregates-row"><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div class="ui-grid-footer-cell-wrapper" ng-style="colContainer.headerCellWrapperStyle()"><div class="ui-grid-footer-cell-row"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell ui-grid-clearfix"></div></div></div></div></div></div>'),a.put("ui-grid/ui-grid-grid-footer",'<div class="ui-grid-footer-info ui-grid-grid-footer"><span>{{\'search.totalItems\' | t}} {{grid.rows.length}}</span> <span ng-if="grid.renderContainers.body.visibleRowCache.length !== grid.rows.length" class="ngLabel">({{"search.showingItems" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell-wrapper" ng-style="colContainer.headerCellWrapperStyle()"><div class="ui-grid-header-cell-row"><div class="ui-grid-header-cell ui-grid-clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index"></div></div></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    /*\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n    */\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div><div ui-grid-grid-footer ng-if="grid.options.showGridFooter"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showColumnFooter"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport" ng-style="colContainer.getViewPortStyle()"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="Viewport.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="INPUT_TYPE" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth()) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/expandableTopRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !grid.expandable.expandedAll, \'ui-grid-icon-minus-squared\' : grid.expandable.expandedAll }" ng-click="grid.api.expandable.toggleAllRows()"></i></div></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT" download="FILE_NAME">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/pagination",'<div class="ui-grid-pager-panel" ui-grid-pager ng-show="grid.options.enablePaginationControls"><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="paginationApi.seek(1)" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="paginationApi.previousPage()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.paginationCurrentPage" min="1" max="{{ paginationApi.getTotalPages() }}" required> <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span> <button type="button" ng-click="paginationApi.nextPage()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="paginationApi.seek(paginationApi.getTotalPages())" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/gridFooterSelectedItems",'<span ng-if="grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected">({{"search.selectedItems" | t}} {{grid.selection.selectedCount}})</span>'),a.put("ui-grid/selectionHeaderCell",'<div><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.20/ui-grid.svg b/release/3.0.0-rc.20/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/3.0.0-rc.20/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.20/ui-grid.ttf b/release/3.0.0-rc.20/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/3.0.0-rc.20/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.20/ui-grid.woff b/release/3.0.0-rc.20/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/3.0.0-rc.20/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.3/ui-grid.css b/release/3.0.0-rc.3/ui-grid.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/3.0.0-rc.3/ui-grid.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.3/ui-grid.js b/release/3.0.0-rc.3/ui-grid.js
    new file mode 100644
    index 000000000..c3c3dcd78
    --- /dev/null
    +++ b/release/3.0.0-rc.3/ui-grid.js
    @@ -0,0 +1,13034 @@
    +/*! ui-grid - v3.0.0-rc.3 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(angular.element($scope.menu).css('padding-right'), 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length + 1, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.gridOptions)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    //add row header columns to the grid columns array
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.push(rowHeaderColumn);
    +    });
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:',
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Kolom te verbergen'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollVerticallyTo
    +         * @description Scroll the grid vertically such that the specified
    +         * row is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var args = {};
    +          
    +          if ( rowEntity !== null ){
    +            var row = grid.getRow(rowEntity);
    +            if ( row ) { 
    +              args.y = { percentage: row.index / grid.renderContainers.body.visibleRowCache.length }; 
    +            }
    +          }
    +          
    +          if ( colDef !== null ){
    +            var col = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +            if ( col ) {
    +              args.x = { percentage: this.getLeftWidth(grid, col.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +            }
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = maxWidth;
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-selected': row.isSelected}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left;margin-top: 1px;margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell uiGridExpandableButtonsCell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{'ui-grid-icon-plus-squared':!row.isExpanded, 'ui-grid-icon-minus-squared':row.isExpanded}\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left;margin-top: 2px;margin-bottom: 2px\" ng-style=\"{width: (grid.getViewportWidth())\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight, 'margin-left': grid.options.rowHeader.rowHeaderWidth}\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5),\n" +
    +    "            'margin-left':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.3/ui-grid.min.css b/release/3.0.0-rc.3/ui-grid.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/3.0.0-rc.3/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.3/ui-grid.min.js b/release/3.0.0-rc.3/ui-grid.min.js
    new file mode 100644
    index 000000000..84b4ab8d0
    --- /dev/null
    +++ b/release/3.0.0-rc.3/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.3 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(angular.element(i.menu).css("padding-right"),10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup",function(){c.cancel(j)}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,c=b.normalizeScrollLeft(d);if(c!==j.prevScrollLeft){var e=(c-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth()),f=c/e;j.adjustScrollHorizontal(c,f)}if(a!==i.prevScrollTop){var g=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight()),h=a/g;h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a
    +});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length+1,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.gridOptions).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c)})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.push(a)}),c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c
    +}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g=!0,h="width"===d?c.offsetWidth:c.offsetHeight,i=a(c),j="border-box"===i.boxSizing;if(0>=h||null==h){if(h=i[d],(0>h||null==h)&&(h=c.style[d]),e.test(h))return h;g=j&&!0,h=parseFloat(h)||0}var k=h+b(c,d,f||(j?"border":"content"),g,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Kolom te verbergen"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,d,e){var f={};if(null!==d){var g=a.getRow(d);g&&(f.y={percentage:g.index/a.renderContainers.body.visibleRowCache.length})}if(null!==e){var h=a.getColumn(e.name?e.name:e.field);h&&(f.x={percentage:this.getLeftWidth(a,h.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)})}(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0)}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};
    +g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=h.drawnWidth+d;h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=m,j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}"),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-selected': row.isSelected}"),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left;margin-top: 1px;margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n     ,height: grid.options.expandable.expandableRowHeight}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell uiGridExpandableButtonsCell"><div class="ui-grid-cell-contents"><i ng-class="{\'ui-grid-icon-plus-squared\':!row.isExpanded, \'ui-grid-icon-minus-squared\':row.isExpanded}" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller",'<div ng-if="expandableRow.shouldRenderFiller()" style="float:left;margin-top: 2px;margin-bottom: 2px" ng-style="{width: (grid.getViewportWidth())\n     ,height: grid.options.expandable.expandableRowHeight, \'margin-left\': grid.options.rowHeader.rowHeaderWidth}"><i class="ui-grid-icon-spin5 ui-grid-animate-spin" ng-style="{\'margin-top\': ( grid.options.expandable.expandableRowHeight/2 - 5),\n            \'margin-left\':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}"></i></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.7/ui-grid.css b/release/3.0.0-rc.7/ui-grid.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/3.0.0-rc.7/ui-grid.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.7/ui-grid.eot b/release/3.0.0-rc.7/ui-grid.eot
    new file mode 100644
    index 000000000..88b133b63
    Binary files /dev/null and b/release/3.0.0-rc.7/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.7/ui-grid.js b/release/3.0.0-rc.7/ui-grid.js
    new file mode 100644
    index 000000000..f34a1d550
    --- /dev/null
    +++ b/release/3.0.0-rc.7/ui-grid.js
    @@ -0,0 +1,13034 @@
    +/*! ui-grid - v3.0.0-rc.7 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(angular.element($scope.menu).css('padding-right'), 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length + 1, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.gridOptions)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    //add row header columns to the grid columns array
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.push(rowHeaderColumn);
    +    });
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:',
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Kolom te verbergen'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollVerticallyTo
    +         * @description Scroll the grid vertically such that the specified
    +         * row is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var args = {};
    +          
    +          if ( rowEntity !== null ){
    +            var row = grid.getRow(rowEntity);
    +            if ( row ) { 
    +              args.y = { percentage: row.index / grid.renderContainers.body.visibleRowCache.length }; 
    +            }
    +          }
    +          
    +          if ( colDef !== null ){
    +            var col = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +            if ( col ) {
    +              args.x = { percentage: this.getLeftWidth(grid, col.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +            }
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = maxWidth;
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-selected': row.isSelected}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left;margin-top: 1px;margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell uiGridExpandableButtonsCell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{'ui-grid-icon-plus-squared':!row.isExpanded, 'ui-grid-icon-minus-squared':row.isExpanded}\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left;margin-top: 2px;margin-bottom: 2px\" ng-style=\"{width: (grid.getViewportWidth())\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight, 'margin-left': grid.options.rowHeader.rowHeaderWidth}\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5),\n" +
    +    "            'margin-left':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.7/ui-grid.min.css b/release/3.0.0-rc.7/ui-grid.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/3.0.0-rc.7/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.7/ui-grid.min.js b/release/3.0.0-rc.7/ui-grid.min.js
    new file mode 100644
    index 000000000..1f0c62888
    --- /dev/null
    +++ b/release/3.0.0-rc.7/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.7 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(angular.element(i.menu).css("padding-right"),10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup",function(){c.cancel(j)}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,c=b.normalizeScrollLeft(d);if(c!==j.prevScrollLeft){var e=(c-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth()),f=c/e;j.adjustScrollHorizontal(c,f)}if(a!==i.prevScrollTop){var g=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight()),h=a/g;h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a
    +});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length+1,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.gridOptions).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c)})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.push(a)}),c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c
    +}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g=!0,h="width"===d?c.offsetWidth:c.offsetHeight,i=a(c),j="border-box"===i.boxSizing;if(0>=h||null==h){if(h=i[d],(0>h||null==h)&&(h=c.style[d]),e.test(h))return h;g=j&&!0,h=parseFloat(h)||0}var k=h+b(c,d,f||(j?"border":"content"),g,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Kolom te verbergen"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,d,e){var f={};if(null!==d){var g=a.getRow(d);g&&(f.y={percentage:g.index/a.renderContainers.body.visibleRowCache.length})}if(null!==e){var h=a.getColumn(e.name?e.name:e.field);h&&(f.x={percentage:this.getLeftWidth(a,h.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)})}(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0)}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};
    +g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=h.drawnWidth+d;h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=m,j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}"),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-selected': row.isSelected}"),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left;margin-top: 1px;margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n     ,height: grid.options.expandable.expandableRowHeight}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell uiGridExpandableButtonsCell"><div class="ui-grid-cell-contents"><i ng-class="{\'ui-grid-icon-plus-squared\':!row.isExpanded, \'ui-grid-icon-minus-squared\':row.isExpanded}" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller",'<div ng-if="expandableRow.shouldRenderFiller()" style="float:left;margin-top: 2px;margin-bottom: 2px" ng-style="{width: (grid.getViewportWidth())\n     ,height: grid.options.expandable.expandableRowHeight, \'margin-left\': grid.options.rowHeader.rowHeaderWidth}"><i class="ui-grid-icon-spin5 ui-grid-animate-spin" ng-style="{\'margin-top\': ( grid.options.expandable.expandableRowHeight/2 - 5),\n            \'margin-left\':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}"></i></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.7/ui-grid.svg b/release/3.0.0-rc.7/ui-grid.svg
    new file mode 100644
    index 000000000..4265b782c
    --- /dev/null
    +++ b/release/3.0.0-rc.7/ui-grid.svg
    @@ -0,0 +1,31 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xe800;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.7/ui-grid.ttf b/release/3.0.0-rc.7/ui-grid.ttf
    new file mode 100644
    index 000000000..d2dc304da
    Binary files /dev/null and b/release/3.0.0-rc.7/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.7/ui-grid.woff b/release/3.0.0-rc.7/ui-grid.woff
    new file mode 100644
    index 000000000..e11bc6564
    Binary files /dev/null and b/release/3.0.0-rc.7/ui-grid.woff differ
    diff --git a/release/3.0.0-rc.8/ui-grid.css b/release/3.0.0-rc.8/ui-grid.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/3.0.0-rc.8/ui-grid.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/3.0.0-rc.8/ui-grid.eot b/release/3.0.0-rc.8/ui-grid.eot
    new file mode 100644
    index 000000000..88b133b63
    Binary files /dev/null and b/release/3.0.0-rc.8/ui-grid.eot differ
    diff --git a/release/3.0.0-rc.8/ui-grid.js b/release/3.0.0-rc.8/ui-grid.js
    new file mode 100644
    index 000000000..9e64158b0
    --- /dev/null
    +++ b/release/3.0.0-rc.8/ui-grid.js
    @@ -0,0 +1,13034 @@
    +/*! ui-grid - v3.0.0-rc.8 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(angular.element($scope.menu).css('padding-right'), 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length + 1, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.gridOptions)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    //add row header columns to the grid columns array
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.push(rowHeaderColumn);
    +    });
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:',
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Kolom te verbergen'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollVerticallyTo
    +         * @description Scroll the grid vertically such that the specified
    +         * row is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var args = {};
    +          
    +          if ( rowEntity !== null ){
    +            var row = grid.getRow(rowEntity);
    +            if ( row ) { 
    +              args.y = { percentage: row.index / grid.renderContainers.body.visibleRowCache.length }; 
    +            }
    +          }
    +          
    +          if ( colDef !== null ){
    +            var col = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +            if ( col ) {
    +              args.x = { percentage: this.getLeftWidth(grid, col.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +            }
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = maxWidth;
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-selected': row.isSelected}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left;margin-top: 1px;margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell uiGridExpandableButtonsCell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{'ui-grid-icon-plus-squared':!row.isExpanded, 'ui-grid-icon-minus-squared':row.isExpanded}\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left;margin-top: 2px;margin-bottom: 2px\" ng-style=\"{width: (grid.getViewportWidth())\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight, 'margin-left': grid.options.rowHeader.rowHeaderWidth}\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5),\n" +
    +    "            'margin-left':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/3.0.0-rc.8/ui-grid.min.css b/release/3.0.0-rc.8/ui-grid.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/3.0.0-rc.8/ui-grid.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.8/ui-grid.min.js b/release/3.0.0-rc.8/ui-grid.min.js
    new file mode 100644
    index 000000000..cfef3171c
    --- /dev/null
    +++ b/release/3.0.0-rc.8/ui-grid.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.8 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(angular.element(i.menu).css("padding-right"),10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup",function(){c.cancel(j)}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,c=b.normalizeScrollLeft(d);if(c!==j.prevScrollLeft){var e=(c-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth()),f=c/e;j.adjustScrollHorizontal(c,f)}if(a!==i.prevScrollTop){var g=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight()),h=a/g;h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a
    +});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length+1,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.gridOptions).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c)})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.push(a)}),c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c
    +}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g=!0,h="width"===d?c.offsetWidth:c.offsetHeight,i=a(c),j="border-box"===i.boxSizing;if(0>=h||null==h){if(h=i[d],(0>h||null==h)&&(h=c.style[d]),e.test(h))return h;g=j&&!0,h=parseFloat(h)||0}var k=h+b(c,d,f||(j?"border":"content"),g,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Kolom te verbergen"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,d,e){var f={};if(null!==d){var g=a.getRow(d);g&&(f.y={percentage:g.index/a.renderContainers.body.visibleRowCache.length})}if(null!==e){var h=a.getColumn(e.name?e.name:e.field);h&&(f.x={percentage:this.getLeftWidth(a,h.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)})}(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0)}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};
    +g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=h.drawnWidth+d;h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=m,j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}"),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-selected': row.isSelected}"),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left;margin-top: 1px;margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n     ,height: grid.options.expandable.expandableRowHeight}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell uiGridExpandableButtonsCell"><div class="ui-grid-cell-contents"><i ng-class="{\'ui-grid-icon-plus-squared\':!row.isExpanded, \'ui-grid-icon-minus-squared\':row.isExpanded}" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller",'<div ng-if="expandableRow.shouldRenderFiller()" style="float:left;margin-top: 2px;margin-bottom: 2px" ng-style="{width: (grid.getViewportWidth())\n     ,height: grid.options.expandable.expandableRowHeight, \'margin-left\': grid.options.rowHeader.rowHeaderWidth}"><i class="ui-grid-icon-spin5 ui-grid-animate-spin" ng-style="{\'margin-top\': ( grid.options.expandable.expandableRowHeight/2 - 5),\n            \'margin-left\':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}"></i></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.8/ui-grid.svg b/release/3.0.0-rc.8/ui-grid.svg
    new file mode 100644
    index 000000000..4265b782c
    --- /dev/null
    +++ b/release/3.0.0-rc.8/ui-grid.svg
    @@ -0,0 +1,31 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xe800;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/3.0.0-rc.8/ui-grid.ttf b/release/3.0.0-rc.8/ui-grid.ttf
    new file mode 100644
    index 000000000..d2dc304da
    Binary files /dev/null and b/release/3.0.0-rc.8/ui-grid.ttf differ
    diff --git a/release/3.0.0-rc.8/ui-grid.woff b/release/3.0.0-rc.8/ui-grid.woff
    new file mode 100644
    index 000000000..e11bc6564
    Binary files /dev/null and b/release/3.0.0-rc.8/ui-grid.woff differ
    diff --git a/release/ui-grid-stable.css b/release/ui-grid-stable.css
    new file mode 100644
    index 000000000..409817bc6
    --- /dev/null
    +++ b/release/ui-grid-stable.css
    @@ -0,0 +1,1086 @@
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-header-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas {
    +  position: relative;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  float: left;
    +  top: 0;
    +  bottom: 0;
    +  background-color: inherit;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: relative;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow: hidden;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-native-scrollbar {
    +  position: absolute;
    +  overflow: scroll;
    +}
    +.ui-grid-native-scrollbar.vertical {
    +  top: 0;
    +  right: 0;
    +  height: 100%;
    +  overflow-x: hidden;
    +  width: 17px;
    +}
    +.ui-grid-native-scrollbar.horizontal {
    +  bottom: 0;
    +  left: 0;
    +  width: 100%;
    +  overflow-y: hidden;
    +  height: 17px;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-group-panel {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  min-height: 30px;
    +}
    +.ui-grid-footer-group-panel .hidden {
    +  display: none;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-footer .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: default;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal {
    +  left: inherit;
    +  right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical {
    +  left: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child {
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-contents:focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-cell {
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\e800';
    +}
    +/* '' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/ui-grid-stable.js b/release/ui-grid-stable.js
    new file mode 100644
    index 000000000..c3c3dcd78
    --- /dev/null
    +++ b/release/ui-grid-stable.js
    @@ -0,0 +1,13034 @@
    +/*! ui-grid - v3.0.0-rc.3 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart' // For any item being dragged
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫']
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$log', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $log, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            var html = $scope.col.cellTemplate
    +              .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +            var cellElement = $compile(html)($scope);
    +            $elm.append(cellElement);
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          $elm.addClass($scope.col.getColClass(false));
    +          if ($scope.col.cellClass) {
    +            //var contents = angular.element($elm[0].getElementsByClassName('ui-grid-cell-contents'));
    +            var contents = $elm;
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              contents.addClass($scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex));
    +            }
    +            else {
    +              contents.addClass($scope.col.cellClass);
    +            }
    +          }
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid').directive('uiGridColumnMenu', ['$log', '$timeout', '$window', '$document', '$injector', 'gridUtil', 'uiGridConstants', 'i18nService', function ($log, $timeout, $window, $document, $injector, gridUtil, uiGridConstants, i18nService) {
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      var self = this;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +
    +      // Save whether we're shown or not so the columns can check
    +      self.shown = $scope.menuShown = false;
    +
    +      // Put asc and desc sort directions in scope
    +      $scope.asc = uiGridConstants.ASC;
    +      $scope.desc = uiGridConstants.DESC;
    +
    +      // $scope.i18n = i18nService;
    +
    +      // Get the grid menu element. We'll use it to calculate positioning
    +      $scope.menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +
    +      // Get the inner menu part. It's what slides up/down
    +      $scope.inner = $elm[0].querySelectorAll('.ui-grid-menu-inner');
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds sort
    +       * widgets to the column header, allowing sorting of the data in the individual column.
    +       */
    +      $scope.sortable = function() {
    +        if (uiGridCtrl.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions.columnDef
    +       * @description (optional) True by default. When enabled, this setting adds filter
    +       * widgets to the column header, allowing filtering of the data in the individual column.
    +       */
    +      $scope.filterable = function() {
    +        if (uiGridCtrl.grid.options.enableFiltering && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableFiltering) {
    +          return true;
    +        }
    +        else {
    +          return false;
    +        }
    +      };
    +      
    +      var defaultMenuItems = [
    +        // NOTE: disabling this in favor of a little filter text box
    +        // Column filter input
    +        // {
    +        //   templateUrl: 'ui-grid/uiGridColumnFilter',
    +        //   action: function($event) {
    +        //     $event.stopPropagation();
    +        //     $scope.filterColumn($event);
    +        //   },
    +        //   cancel: function ($event) {
    +        //     $event.stopPropagation();
    +
    +        //     $scope.col.filter = {};
    +        //   },
    +        //   shown: function () {
    +        //     return filterable();
    +        //   }
    +        // },
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return $scope.sortable();
    +          },
    +          active: function() {
    +            return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return ($scope.sortable() && typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +
    +      // Set the menu items for use with the column menu. Let's the user specify extra menu items per column if they want.
    +      $scope.menuItems = defaultMenuItems;
    +      $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = defaultMenuItems;
    +        }
    +      });
    +
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +      }
    +      catch (e) {
    +        $log.info('$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur');
    +      }
    +
    +      // Show the menu
    +      $scope.showMenu = function(column, $columnElement) {
    +        // Swap to this column
    +        //   note - store a reference to this column in 'self' so the columns can check whether they're the shown column or not
    +        self.col = $scope.col = column;
    +
    +        // Remove an existing document click handler
    +        $document.off('click', documentClick);
    +
    +        /* Reposition the menu below this column's element */
    +        var left = $columnElement[0].offsetLeft;
    +        var top = $columnElement[0].offsetTop;
    +
    +        // Get the grid scrollLeft
    +        var offset = 0;
    +        if (column.grid.options.offsetLeft) {
    +          offset = column.grid.options.offsetLeft;
    +        }
    +
    +        var height = gridUtil.elementHeight($columnElement, true);
    +        var width = gridUtil.elementWidth($columnElement, true);
    +
    +        // Flag for whether we're hidden for showing via $animate
    +        var hidden = false;
    +
    +        // Re-position the menu AFTER it's been shown, so we can calculate the width correctly.
    +        function reposition() {
    +          $timeout(function() {
    +            if (hidden && $animate) {
    +              $animate.removeClass($scope.inner, 'ng-hide');
    +              self.shown = $scope.menuShown = true;
    +              $scope.$broadcast('show-menu');
    +            }
    +            else if (angular.element($scope.inner).hasClass('ng-hide')) {
    +              angular.element($scope.inner).removeClass('ng-hide');
    +            }
    +
    +            // var containerScrollLeft = $columnelement
    +            var containerId = column.renderContainer ? column.renderContainer : 'body';
    +            var renderContainer = column.grid.renderContainers[containerId];
    +            // var containerScrolLeft = renderContainer.prevScrollLeft;
    +
    +            // It's possible that the render container of the column we're attaching to is offset from the grid (i.e. pinned containers), we
    +            //   need to get the different in the offsetLeft between the render container and the grid
    +            var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +            var renderContainerOffset = renderContainerElm.offsetLeft - $scope.grid.element[0].offsetLeft;
    +
    +            var containerScrolLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +            var myWidth = gridUtil.elementWidth($scope.menu, true);
    +
    +            // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +            // Get the column menu right padding
    +            var paddingRight = parseInt(angular.element($scope.menu).css('padding-right'), 10);
    +
    +            // $log.debug('position', left + ' + ' + width + ' - ' + myWidth + ' + ' + paddingRight);
    +
    +            $elm.css('left', (left + renderContainerOffset - containerScrolLeft + width - myWidth + paddingRight) + 'px');
    +            $elm.css('top', (top + height) + 'px');
    +
    +            // Hide the menu on a click on the document
    +            $document.on('click', documentClick);
    +          });
    +        }
    +
    +        if ($scope.menuShown && $animate) {
    +          // Animate closing the menu on the current column, then animate it opening on the other column
    +          $animate.addClass($scope.inner, 'ng-hide', reposition);
    +          hidden = true;
    +        }
    +        else {
    +          self.shown = $scope.menuShown = true;
    +          $scope.$broadcast('show-menu');
    +          reposition();
    +        }
    +      };
    +
    +      // Hide the menu
    +      $scope.hideMenu = function() {
    +        delete self.col;
    +        delete $scope.col;
    +        self.shown = $scope.menuShown = false;
    +        $scope.$broadcast('hide-menu');
    +      };
    +
    +      // Prevent clicks on the menu from bubbling up to the document and making it hide prematurely
    +      // $elm.on('click', function (event) {
    +      //   event.stopPropagation();
    +      // });
    +
    +      function documentClick() {
    +        $scope.$apply($scope.hideMenu);
    +        $document.off('click', documentClick);
    +      }
    +      
    +      function resizeHandler() {
    +        $scope.$apply($scope.hideMenu);
    +      }
    +      angular.element($window).bind('resize', resizeHandler);
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, function(evt, args) {
    +        $scope.hideMenu();
    +        // if (!$scope.$$phase) { $scope.$apply(); }
    +      }));
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', resizeHandler);
    +        $document.off('click', documentClick);
    +      });
    +
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        uiGridCtrl.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            uiGridCtrl.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        uiGridCtrl.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +    },
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$log', '$timeout', 'gridUtil', '$compile', function ($log, $timeout, gridUtil, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            function compileTemplate(template) {
    +              gridUtil.getTemplate(template).then(function (contents) {
    +                var linkFunction = $compile(contents);
    +                var html = linkFunction($scope);
    +                $elm.append(html);
    +              });
    +            }
    +
    +            //compile the footer template
    +            if ($scope.col.footerCellTemplate) {
    +              //compile the custom template
    +              compileTemplate($scope.col.footerCellTemplate);
    +            }
    +            else {
    +              //use default template
    +              compileTemplate('ui-grid/uiGridFooterCell');
    +            }
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +  function ($log, $compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $scope.grid = uiGridCtrl.grid;
    +            
    +            /**
    +             * @ngdoc event
    +             * @name filterChanged
    +             * @eventOf  ui.grid.core.api:PublicApi
    +             * @description  is raised after the filter is changed.  The nature
    +             * of the watch expression doesn't allow notification of what changed,
    +             * so the receiver of this event will need to re-extract the filter 
    +             * conditions from the columns.
    +             * 
    +             */
    +            if (!$scope.grid.api.core.raise.filterChanged){
    +              $scope.grid.api.registerEvent( 'core', 'filterChanged' );
    +            }
    +                        
    +    
    +            $elm.addClass($scope.col.getColClass(false));
    +    // shane - No need for watch now that we trackby col name
    +    //        $scope.$watch('col.index', function (newValue, oldValue) {
    +    //          if (newValue === oldValue) { return; }
    +    //          var className = $elm.attr('class');
    +    //          className = className.replace(uiGridConstants.COL_CLASS_PREFIX + oldValue, uiGridConstants.COL_CLASS_PREFIX + newValue);
    +    //          $elm.attr('class', className);
    +    //        });
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +    
    +            function handleClick(evt) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (evt.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            // Long-click (for mobile)
    +            var cancelMousedownTimeout;
    +            var mousedownStartTime = 0;
    +            $contentsElm.on('mousedown', function(event) {
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +    
    +              // Don't show the menu if it's not the left button
    +              if (event.button && event.button !== 0) {
    +                return;
    +              }
    +    
    +              mousedownStartTime = (new Date()).getTime();
    +    
    +              cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +    
    +              cancelMousedownTimeout.then(function () {
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              });
    +            });
    +    
    +            $contentsElm.on('mouseup', function () {
    +              $timeout.cancel(cancelMousedownTimeout);
    +            });
    +    
    +            $scope.toggleMenu = function($event) {
    +              $event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              $contentsElm.on('click', function(evt) {
    +                evt.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(evt);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  uiGridCtrl.grid.api.core.raise.filterChanged();
    +                  uiGridCtrl.grid.refresh()
    +                    .then(function () {
    +                      if (uiGridCtrl.prevScrollArgs && uiGridCtrl.prevScrollArgs.y && uiGridCtrl.prevScrollArgs.y.percentage) {
    +                         uiGridCtrl.fireScrollingEvent({ y: { percentage: uiGridCtrl.prevScrollArgs.y.percentage } });
    +                      }
    +                      // uiGridCtrl.fireEvent('force-vertical-scroll');
    +                    });
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.header = $elm;
    +            containerCtrl.colContainer.header = $elm;
    +
    +            /**
    +             * @ngdoc property
    +             * @name hideHeader
    +             * @propertyOf ui.grid.class:GridOptions
    +             * @description Null by default. When set to true, this setting will replace the
    +             * standard header template with '<div></div>', resulting in no header being shown.
    +             */
    +            
    +            var headerTemplate;
    +            if ($scope.grid.options.hideHeader){
    +              headerTemplate = emptyTemplate;
    +            } else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +             gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $log.debug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              var asterisksArray = [],
    +                  percentArray = [],
    +                  manualArray = [],
    +                  asteriskNum = 0,
    +                  totalWidth = 0;
    +
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth();
    +
    +              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              }
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              // The last column we processed
    +              var lastColumn;
    +
    +              var manualWidthSum = 0;
    +
    +              var canvasWidth = 0;
    +
    +              var ret = '';
    +
    +
    +              // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache;
    +
    +              columnCache.forEach(function(column, i) {
    +                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +                // Skip hidden columns
    +                if (!column.visible) { return; }
    +
    +                var colWidth,
    +                    isPercent = false;
    +
    +                if (!angular.isNumber(column.width)) {
    +                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +                }
    +
    +                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +                  
    +                  asterisksArray.push(column);
    +                }
    +                else if (isPercent) { // If the width is a percentage, save it until the very last.
    +                  percentArray.push(column);
    +                }
    +                else if (angular.isNumber(column.width)) {
    +                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +                  
    +                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +                  column.drawnWidth = column.width;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +                }
    +              });
    +
    +              // Get the remaining width (available width subtracted by the manual widths sum)
    +              var remainingWidth = availableWidth - manualWidthSum;
    +
    +              var i, column, colWidth;
    +
    +              if (percentArray.length > 0) {
    +                // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < percentArray.length; i++) {
    +                  column = percentArray[i];
    +
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +                  colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    percentArray.splice(i, 1);
    +                  }
    +                }
    +
    +                percentArray.forEach(function(column) {
    +                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +                  var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              if (asterisksArray.length > 0) {
    +                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                 // Pre-process to make sure they're all within any min/max values
    +                for (i = 0; i < asterisksArray.length; i++) {
    +                  column = asterisksArray[i];
    +
    +                  colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +                    colWidth = column.colDef.minWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    lastColumn = column;
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +                    colWidth = column.colDef.maxWidth;
    +
    +                    remainingWidth = remainingWidth - colWidth;
    +                    asteriskNum--;
    +
    +                    canvasWidth += colWidth;
    +                    column.drawnWidth = colWidth;
    +
    +                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +                    // Remove this element from the percent array so it's not processed below
    +                    asterisksArray.splice(i, 1);
    +                  }
    +                }
    +
    +                // Redo the asterisk value, as we may have removed columns due to width constraints
    +                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +                asterisksArray.forEach(function(column) {
    +                  var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +                  canvasWidth += colWidth;
    +
    +                  column.drawnWidth = colWidth;
    +
    +                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +                });
    +              }
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var variableColumn = false;
    +                // uiGridCtrl.grid.columns.forEach(function(col) {
    +                columnCache.forEach(function(col) {
    +                  if (col.width && !angular.isNumber(col.width)) {
    +                    variableColumn = true;
    +                  }
    +                });
    +
    +                if (variableColumn) {
    +                  var remFn = function (column) {
    +                    if (leftoverWidth > 0) {
    +                      column.drawnWidth = column.drawnWidth + 1;
    +                      canvasWidth = canvasWidth + 1;
    +                      leftoverWidth--;
    +                    }
    +                  };
    +                  while (leftoverWidth > 0) {
    +                    columnCache.forEach(remFn);
    +                  }
    +                }
    +              }
    +
    +              if (canvasWidth < availableWidth) {
    +                canvasWidth = availableWidth;
    +              }
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +              if (grid.verticalScrollbarWidth) {
    +                canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              }
    +              // canvasWidth = canvasWidth + 1;
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$log', '$compile', '$timeout', '$window', '$document', 'gridUtil', function ($log, $compile, $timeout, $window, $document, gridUtil) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      gridUtil.enableAnimations($elm);
    +
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', $scope.hideMenu);
    +      }
    +
    +      $scope.$on('hide-menu', function () {
    +        $scope.shown = false;
    +      });
    +
    +      $scope.$on('show-menu', function () {
    +        $scope.shown = true;
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', $scope.hideMenu);
    +      });
    +    },
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +
    +      self.hideMenu = $scope.hideMenu = function() {
    +        $scope.shown = false;
    +      };
    +
    +      function documentClick() {
    +        $scope.$apply(function () {
    +          self.hideMenu();
    +          angular.element(document).off('click', documentClick);
    +        });
    +      }
    +
    +      self.showMenu = $scope.showMenu = function() {
    +        $scope.shown = true;
    +
    +        // Turn off an existing dpcument click handler
    +        angular.element(document).off('click', documentClick);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on('click', documentClick);
    +        });
    +      };
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click', documentClick);
    +      });
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['$log', 'gridUtil', '$compile', 'i18nService', function ($log, gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      title: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            $log.debug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              uiGridMenuCtrl.hideMenu();
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +// 'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridNativeScrollbar', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function ($log, $timeout, $document, uiGridConstants, gridUtil) {
    +    var scrollBarWidth = gridUtil.getScrollbarWidth();
    +    scrollBarWidth = scrollBarWidth > 0 ? scrollBarWidth : 17;
    +
    +    // If the browser is IE, add 1px to the scrollbar container, otherwise scroll events won't work right (in IE11 at least)
    +    var browser = gridUtil.detectBrowser();
    +    if (browser === 'ie') {
    +      scrollBarWidth = scrollBarWidth + 1;
    +    }
    +
    +    return {
    +      scope: {
    +        type: '@'
    +      },
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      link: function ($scope, $elm, $attrs, controllers) {
    +        var uiGridCtrl = controllers[0];
    +        var containerCtrl = controllers[1];
    +        var rowContainer = containerCtrl.rowContainer;
    +        var colContainer = containerCtrl.colContainer;
    +        var grid = uiGridCtrl.grid;
    +
    +        var contents = angular.element('<div class="contents">&nbsp;</div>');
    +
    +        $elm.addClass('ui-grid-native-scrollbar');
    +
    +        var previousScrollPosition;
    +
    +        var elmMaxScroll = 0;
    +
    +        if ($scope.type === 'vertical') {
    +          // Update the width based on native scrollbar width
    +          $elm.css('width', scrollBarWidth + 'px');
    +
    +          $elm.addClass('vertical');
    +
    +          grid.verticalScrollbarWidth = scrollBarWidth;
    +          colContainer.verticalScrollbarWidth = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = $elm[0].scrollTop;
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          // Update the height based on native scrollbar height
    +          $elm.css('height', scrollBarWidth + 'px');
    +
    +          $elm.addClass('horizontal');
    +
    +          // Save this scrollbar's dimension in the grid properties
    +          grid.horizontalScrollbarHeight = scrollBarWidth;
    +          rowContainer.horizontalScrollbarHeight = scrollBarWidth;
    +
    +          // Save the initial scroll position for use in scroll events
    +          previousScrollPosition = gridUtil.normalizeScrollLeft($elm);
    +        }
    +
    +        // Save the contents elm inside the scrollbar elm so it sizes correctly
    +        $elm.append(contents);
    +
    +        // Get the relevant element dimension now that the contents are in it
    +        if ($scope.type === 'vertical') {
    +          elmMaxScroll = gridUtil.elementHeight($elm);
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          elmMaxScroll = gridUtil.elementWidth($elm);
    +        }
    +
    +        function updateNativeVerticalScrollbar() {
    +          // Get the height that the scrollbar should have
    +          var height = rowContainer.getViewportHeight();
    +
    +          // Update the vertical scrollbar's content height so it's the same as the canvas
    +          var contentHeight = rowContainer.getCanvasHeight();
    +
    +          // TODO(c0bra): set scrollbar `top` by height of header row
    +          // var headerHeight = gridUtil.outerElementHeight(containerCtrl.header);
    +          var headerHeight = colContainer.headerHeight ? colContainer.headerHeight : grid.headerHeight;
    +
    +          // $log.debug('headerHeight in scrollbar', headerHeight);
    +
    +          // var ret = '.grid' + uiGridCtrl.grid.id + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + h + 'px; }';
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical .contents { height: ' + contentHeight + 'px; }';
    +          ret += '\n .grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.vertical { height: ' + height + 'px; top: ' + headerHeight + 'px}';
    +
    +          elmMaxScroll = contentHeight;
    +
    +          return ret;
    +        }
    +
    +        // Get the grid's bottom border height (TODO(c0bra): need to account for footer here!)
    +        var gridElm = gridUtil.closestElm($elm, '.ui-grid');
    +        var gridBottomBorder = gridUtil.getBorderSize(gridElm, 'bottom');
    +
    +        function updateNativeHorizontalScrollbar() {
    +          var w = colContainer.getCanvasWidth();
    +
    +          // Scrollbar needs to be negatively positioned beyond the bottom of the relatively-positioned render container
    +          var bottom = (scrollBarWidth * -1) + gridBottomBorder;
    +          if (grid.options.showFooter) {
    +            bottom -= 1;
    +          }
    +          var ret = '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal { bottom: ' + bottom + 'px; }';
    +          ret += '.grid' + grid.id + ' .ui-grid-render-container-' + containerCtrl.containerId + ' .ui-grid-native-scrollbar.horizontal .contents { width: ' + w + 'px; }';
    +
    +          elmMaxScroll = w;
    +
    +          return ret;
    +        }
    +
    +        // NOTE: priority 6 so they run after the column widths update, which in turn update the canvas width
    +        if ($scope.type === 'vertical') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeVerticalScrollbar
    +          });
    +        }
    +        else if ($scope.type === 'horizontal') {
    +          grid.registerStyleComputation({
    +            priority: 6,
    +            func: updateNativeHorizontalScrollbar
    +          });
    +        }
    +
    +
    +        $scope.scrollSource = null;
    +
    +        function scrollEvent(evt) {
    +          if ($scope.type === 'vertical') {
    +            grid.flagScrollingVertically();
    +            var newScrollTop = $elm[0].scrollTop;
    +
    +            var yDiff = previousScrollPosition - newScrollTop;
    +
    +            var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +            // Subtract the h. scrollbar height from the vertical length if it's present
    +            if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +              vertScrollLength = vertScrollLength - uiGridCtrl.grid.horizontalScrollbarHeight;
    +            }
    +
    +            var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +            if (vertScrollPercentage > 1) {
    +              vertScrollPercentage = 1;
    +            }
    +            if (vertScrollPercentage < 0) {
    +              vertScrollPercentage = 0;
    +            }
    +
    +            var yArgs = {
    +              target: $elm,
    +              y: {
    +                percentage: vertScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(yArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollTop;
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            grid.flagScrollingHorizontally();
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            var xDiff = previousScrollPosition - newScrollLeft;
    +
    +            var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +            var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +            var xArgs = {
    +              target: $elm,
    +              x: {
    +                percentage: horizScrollPercentage
    +              }
    +            };
    +
    +            // If the source of this scroll is defined (i.e., not us, then don't fire the scroll event because we'll be re-triggering)
    +            if (!$scope.scrollSource) {
    +              uiGridCtrl.fireScrollingEvent(xArgs);
    +            }
    +            else {
    +              // Reset the scroll source for the next scroll event
    +              $scope.scrollSource = null;
    +            }
    +
    +            previousScrollPosition = newScrollLeft;
    +          }
    +        }
    +
    +        $elm.on('scroll', scrollEvent);
    +
    +        $elm.on('$destroy', function () {
    +          $elm.off('scroll');
    +        });
    +
    +        function gridScroll(evt, args) {
    +          // Don't listen to our own scroll event!
    +          if (args.target && (args.target === $elm || angular.element(args.target).hasClass('ui-grid-native-scrollbar'))) {
    +            return;
    +          }
    +
    +          // Set the source of the scroll event in our scope so it's available in our 'scroll' event handler
    +          $scope.scrollSource = args.target;
    +
    +          if ($scope.type === 'vertical') {
    +            if (args.y && typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +              grid.flagScrollingVertically();
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +              var newScrollTop = Math.max(0, args.y.percentage * vertScrollLength);
    +
    +              $elm[0].scrollTop = newScrollTop;
    +
    +
    +            }
    +          }
    +          else if ($scope.type === 'horizontal') {
    +            if (args.x && typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +              grid.flagScrollingHorizontally();
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +              var newScrollLeft = Math.max(0, args.x.percentage * horizScrollLength);
    +
    +              // $elm[0].scrollLeft = newScrollLeft;
    +              $elm[0].scrollLeft = gridUtil.denormalizeScrollLeft($elm, newScrollLeft);
    +            }
    +          }
    +        }
    +
    +        var gridScrollDereg = $scope.$on(uiGridConstants.events.GRID_SCROLL, gridScroll);
    +        $scope.$on('$destroy', gridScrollDereg);
    +
    +
    +
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$log', '$timeout', '$document', 'uiGridConstants', 'gridUtil',
    +    function($log, $timeout, $document, uiGridConstants, GridUtil) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableScrollbars: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            $log.debug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            var scrollUnbinder;
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              scrollUnbinder = $scope.$on(uiGridConstants.events.GRID_SCROLL, scrollHandler);
    +            }
    +
    +            function scrollHandler (evt, args) {
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Add the height of the native horizontal scrollbar, if it's there. Otherwise it will mask over the final row
    +                if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +                  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +                }
    +
    +                var oldScrollTop = containerCtrl.viewport[0].scrollTop;
    +                
    +                var scrollYPercentage;
    +                if (typeof(args.y.percentage) !== 'undefined' && args.y.percentage !== undefined) {
    +                  scrollYPercentage = args.y.percentage;
    +                }
    +                else if (typeof(args.y.pixels) !== 'undefined' && args.y.pixels !== undefined) {
    +                  scrollYPercentage = args.y.percentage = (oldScrollTop + args.y.pixels) / scrollLength;
    +                  // $log.debug('y.percentage', args.y.percentage);
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +                }
    +
    +                var newScrollTop = Math.max(0, scrollYPercentage * scrollLength);
    +
    +                containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                
    +                // TOOD(c0bra): what's this for?
    +                // grid.options.offsetTop = newScrollTop;
    +
    +                containerCtrl.prevScrollArgs.y.pixels = newScrollTop - oldScrollTop;
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // var oldScrollLeft = containerCtrl.viewport[0].scrollLeft;
    +                var oldScrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +
    +                var scrollXPercentage;
    +                if (typeof(args.x.percentage) !== 'undefined' && args.x.percentage !== undefined) {
    +                  scrollXPercentage = args.x.percentage;
    +                }
    +                else if (typeof(args.x.pixels) !== 'undefined' && args.x.pixels !== undefined) {
    +                  scrollXPercentage = args.x.percentage = (oldScrollLeft + args.x.pixels) / scrollWidth;
    +                }
    +                else {
    +                  throw new Error("No percentage or pixel value provided for scroll event X axis");
    +                }
    +
    +                var newScrollLeft = Math.max(0, scrollXPercentage * scrollWidth);
    +                
    +                // uiGridCtrl.adjustScrollHorizontal(newScrollLeft, scrollXPercentage);
    +
    +                // containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                containerCtrl.viewport[0].scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.viewport, newScrollLeft);
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  // containerCtrl.headerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.headerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  // containerCtrl.footerViewport.scrollLeft = newScrollLeft;
    +                  containerCtrl.footerViewport.scrollLeft = GridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // uiGridCtrl.grid.options.offsetLeft = newScrollLeft;
    +
    +                containerCtrl.prevScrollArgs.x.pixels = newScrollLeft - oldScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            $elm.bind('wheel mousewheel DomMouseScroll MozMousePixelScroll', function(evt) {
    +              // use wheelDeltaY
    +              evt.preventDefault();
    +
    +              var newEvent = GridUtil.normalizeWheelEvent(evt);
    +
    +              var args = { target: $elm };
    +              if (newEvent.deltaY !== 0) {
    +                var scrollYAmount = newEvent.deltaY * -120;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (newEvent.deltaX !== 0) {
    +                var scrollXAmount = newEvent.deltaX * -120;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = GridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +              
    +              uiGridCtrl.fireScrollingEvent(args);
    +            });
    +            
    +
    +            var startY = 0,
    +            startX = 0,
    +            scrollTopStart = 0,
    +            scrollLeftStart = 0,
    +            directionY = 1,
    +            directionX = 1,
    +            moveStart;
    +
    +            function touchmove(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              var deltaX, deltaY, newX, newY;
    +              newX = event.targetTouches[0].screenX;
    +              newY = event.targetTouches[0].screenY;
    +              deltaX = -(newX - startX);
    +              deltaY = -(newY - startY);
    +
    +              directionY = (deltaY < 1) ? -1 : 1;
    +              directionX = (deltaX < 1) ? -1 : 1;
    +
    +              deltaY *= 2;
    +              deltaX *= 2;
    +
    +              var args = { target: event.target };
    +
    +              if (deltaY !== 0) {
    +                var scrollYPercentage = (scrollTopStart + deltaY) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +                else if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +
    +                args.y = { percentage: scrollYPercentage, pixels: deltaY };
    +              }
    +              if (deltaX !== 0) {
    +                var scrollXPercentage = (scrollLeftStart + deltaX) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +                else if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +
    +                args.x = { percentage: scrollXPercentage, pixels: deltaX };
    +              }
    +
    +              uiGridCtrl.fireScrollingEvent(args);
    +            }
    +            
    +            function touchend(event) {
    +              if (event.originalEvent) {
    +                event = event.originalEvent;
    +              }
    +
    +              event.preventDefault();
    +
    +              $document.unbind('touchmove', touchmove);
    +              $document.unbind('touchend', touchend);
    +              $document.unbind('touchcancel', touchend);
    +
    +              // Get the distance we moved on the Y axis
    +              var scrollTopEnd = containerCtrl.viewport[0].scrollTop;
    +              var scrollLeftEnd = containerCtrl.viewport[0].scrollTop;
    +              var deltaY = Math.abs(scrollTopEnd - scrollTopStart);
    +              var deltaX = Math.abs(scrollLeftEnd - scrollLeftStart);
    +
    +              // Get the duration it took to move this far
    +              var moveDuration = (new Date()) - moveStart;
    +
    +              // Scale the amount moved by the time it took to move it (i.e. quicker, longer moves == more scrolling after the move is over)
    +              var moveYScale = deltaY / moveDuration;
    +              var moveXScale = deltaX / moveDuration;
    +
    +              var decelerateInterval = 63; // 1/16th second
    +              var decelerateCount = 8; // == 1/2 second
    +              var scrollYLength = 120 * directionY * moveYScale;
    +              var scrollXLength = 120 * directionX * moveXScale;
    +
    +              function decelerate() {
    +                $timeout(function() {
    +                  var args = { target: event.target };
    +
    +                  if (scrollYLength !== 0) {
    +                    var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYLength) / (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +
    +                    args.y = { percentage: scrollYPercentage, pixels: scrollYLength };
    +                  }
    +
    +                  if (scrollXLength !== 0) {
    +                    var scrollXPercentage = (containerCtrl.viewport[0].scrollLeft + scrollXLength) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +                    args.x = { percentage: scrollXPercentage, pixels: scrollXLength };
    +                  }
    +
    +                  uiGridCtrl.fireScrollingEvent(args);
    +
    +                  decelerateCount = decelerateCount -1;
    +                  scrollYLength = scrollYLength / 2;
    +                  scrollXLength = scrollXLength / 2;
    +
    +                  if (decelerateCount > 0) {
    +                    decelerate();
    +                  }
    +                  else {
    +                    uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                      sbar.removeClass('ui-grid-scrollbar-visible');
    +                      sbar.removeClass('ui-grid-scrolling');
    +                    });
    +                  }
    +                }, decelerateInterval);
    +              }
    +
    +              // decelerate();
    +            }
    +
    +            if (GridUtil.isTouchEnabled()) {
    +              $elm.bind('touchstart', function (event) {
    +                if (event.originalEvent) {
    +                  event = event.originalEvent;
    +                }
    +
    +                event.preventDefault();
    +
    +                uiGridCtrl.scrollbars.forEach(function (sbar) {
    +                  sbar.addClass('ui-grid-scrollbar-visible');
    +                  sbar.addClass('ui-grid-scrolling');
    +                });
    +
    +                moveStart = new Date();
    +                startY = event.targetTouches[0].screenY;
    +                startX = event.targetTouches[0].screenX;
    +                scrollTopStart = containerCtrl.viewport[0].scrollTop;
    +                scrollLeftStart = containerCtrl.viewport[0].scrollLeft;
    +                
    +                $document.on('touchmove', touchmove);
    +                $document.on('touchend touchcancel', touchend);
    +              });
    +            }
    +
    +            $elm.bind('$destroy', function() {
    +              scrollUnbinder();
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + canvasWidth + 'px; }';
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +              // Update
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', '$log', function ($scope, $log) {
    +    var self = this;
    +
    +    self.rowStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var styles = {};
    +      
    +      if (!renderContainer.disableRowOffset) {
    +        if (index === 0 && self.currentTopRow !== 0) {
    +          // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +          var hiddenRowWidth = ($scope.rowContainer.currentTopRow) *
    +            $scope.rowContainer.visibleRowCache[$scope.rowContainer.currentTopRow].height;
    +
    +          // return { 'margin-top': hiddenRowWidth + 'px' };
    +          styles['margin-top'] = hiddenRowWidth + 'px';
    +        }
    +      }
    +      
    +      if (!renderContainer.disableColumnOffset && $scope.colContainer.currentFirstColumn !== 0) {
    +        if ($scope.grid.isRTL()) {
    +          styles['margin-right'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +        else {
    +          styles['margin-left'] = $scope.colContainer.columnOffset + 'px';
    +        }
    +      }
    +
    +      return styles;
    +    };
    +
    +    self.columnStyle = function (index) {
    +      var renderContainer = $scope.grid.renderContainers[$scope.containerId];
    +
    +      var self = this;
    +
    +      if (!renderContainer.disableColumnOffset) {
    +        if (index === 0 && $scope.colContainer.currentFirstColumn !== 0) {
    +          var offset = $scope.colContainer.columnOffset;
    +
    +          if ($scope.grid.isRTL()) {
    +            return { 'margin-right': offset + 'px' };
    +          }
    +          else {
    +            return { 'margin-left': offset + 'px' }; 
    +          }
    +        }
    +      }
    +
    +      return null;
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['$log', function($log) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            grid.getRowTemplateFn.then(function (templateFn) {
    +              templateFn($scope, function(clonedElement, scope) {
    +                $elm.replaceWith(clonedElement);
    +              });
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            //add optional reference to externalScopes function to scope
    +            //so it can be retrieved in lower elements
    +            $scope.getExternalScopes = uiGridCtrl.getExternalScopes;
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['$log', '$interpolate', function($log, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        $log.debug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    $log.warn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['$log', 'gridUtil',
    +    function($log, gridUtil) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          $log.debug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              var horizScrollPercentage = newScrollLeft / horizScrollLength;
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              // uiGridCtrl.fireScrollingEvent({ y: { pixels: diff } });
    +              var vertScrollLength = (rowContainer.getCanvasHeight() - rowContainer.getViewportHeight());
    +              // var vertScrollPercentage = (uiGridCtrl.prevScrollTop + yDiff) / vertScrollLength;
    +              var vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +          });
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', '$log', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
    +    function ($scope, $elm, $attrs, $log, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile) {
    +      $log.debug('ui-grid controller');
    +
    +      var self = this;
    +
    +      // Extend options with ui-grid attribute reference
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = $elm.css('direction') === 'rtl';
    +
    +
    +      //add optional reference to externalScopes function to controller
    +      //so it can be retrieved in lower elements that have isolate scope
    +      self.getExternalScopes = $scope.getExternalScopes;
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns()
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        }
    +      }
    +
    +      function dataWatchFunction(n) {
    +        // $log.debug('dataWatch fired');
    +        var promises = [];
    +
    +        if (n) {
    +          if (self.grid.columns.length === 0) {
    +            $log.debug('loading cols in dataWatchFunction');
    +            if (!$attrs.uiGridColumns && self.grid.options.columnDefs.length === 0) {
    +              self.grid.buildColumnDefsFromData(n);
    +            }
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();}
    +            ));
    +          }
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(n)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace();
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +      });
    +
    +      $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +
    +      /* Event Methods */
    +
    +      //todo: throttle this event?
    +      self.fireScrollingEvent = function(args) {
    +        $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +      };
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *  @param {Object=} external-scopes Add external-scopes='someScopeObjectYouNeed' attribute so you can access
    + *            your scopes from within any custom templatedirective.  You access by $scope.getExternalScopes() function
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$log',
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    function(
    +      $log,
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '=',
    +          getExternalScopes: '&?externalScopes' //optional functionwrapper around any needed external scope instances
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $log.debug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var newHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //add pinned containers for row headers support
    +              //moved from pinning feature
    +              var left = angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');
    +              $elm.prepend(left);
    +              uiGridCtrl.innerCompile(left);
    +
    +              var right = angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');
    +              $elm.append(right);
    +              uiGridCtrl.innerCompile(right);
    +
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +
    +                //todo: remove this code.  it was commented out after moving from pinning because body is already float:left
    +//                var bodyContainer = angular.element($elm[0].querySelectorAll('[container-id="body"]'));
    +//                if (newValue){
    +//                  bodyContainer.attr('style', 'float: left; position: inherit');
    +//                }
    +//                else {
    +//                  bodyContainer.attr('style', 'float: left; position: relative');
    +//                }
    +
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.queueRefresh();
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['$log', function ($log) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $log.debug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerDimensions() {
    +              // $log.debug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth;
    +                }
    +
    +                myWidth = width;
    +
    +                // $log.debug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$log', '$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($log, $q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.core.api:PublicApi
    + * @description Public Api for the core grid features
    + *
    + */
    +
    +
    +/**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    + * * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +  // Get the id out of the options, then remove it
    +  if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +    if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +      throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +    }
    +  }
    +  else {
    +    throw new Error('No ID provided. An ID must be given when creating a grid.');
    +  }
    +
    +  self.id = options.id;
    +  delete options.id;
    +
    +  // Get default options
    +  self.options = new GridOptions();
    +
    +  // Extend the default options with what we were passed in
    +  angular.extend(self.options, options);
    +
    +  self.headerHeight = self.options.headerRowHeight;
    +  self.footerHeight = self.options.showFooter === true ? self.options.footerRowHeight : 0;
    +
    +  self.rtl = false;
    +  self.gridHeight = 0;
    +  self.gridWidth = 0;
    +  self.columnBuilders = [];
    +  self.rowBuilders = [];
    +  self.rowsProcessors = [];
    +  self.columnsProcessors = [];
    +  self.styleComputations = [];
    +  self.viewportAdjusters = [];
    +  self.rowHeaderColumns = [];
    +
    +  // self.visibleRowCache = [];
    +
    +  // Set of 'render' containers for self grid, which can render sets of rows
    +  self.renderContainers = {};
    +
    +  // Create a
    +  self.renderContainers.body = new GridRenderContainer('body', self);
    +
    +  self.cellValueGetterCache = {};
    +
    +  // Cached function to use with custom row templates
    +  self.getRowTemplateFn = null;
    +
    +
    +  //representation of the rows on the grid.
    +  //these are wrapped references to the actual data rows (options.data)
    +  self.rows = [];
    +
    +  //represents the columns on the grid
    +  self.columns = [];
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingVertically
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +   */
    +  self.isScrollingVertically = false;
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name isScrollingHorizontally
    +   * @propertyOf ui.grid.class:Grid
    +   * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +   */
    +  self.isScrollingHorizontally = false;
    +
    +  var debouncedVertical = gridUtil.debounce(function () {
    +    self.isScrollingVertically = false;
    +  }, 300);
    +
    +  var debouncedHorizontal = gridUtil.debounce(function () {
    +    self.isScrollingHorizontally = false;
    +  }, 300);
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingVertically
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingVertically = function() {
    +    self.isScrollingVertically = true;
    +    debouncedVertical();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name flagScrollingHorizontally
    +   * @methodOf ui.grid.class:Grid
    +   * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +   */
    +  self.flagScrollingHorizontally = function() {
    +    self.isScrollingHorizontally = true;
    +    debouncedHorizontal();
    +  };
    +
    +
    +
    +  self.api = new GridApi(self);
    +
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refresh', this.refresh );
    +
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.core.api:PublicApi
    +   * @description Refresh the rendered grid on screen?  Note: not functional at present
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortChanged
    +   * @methodOf  ui.grid.core.api:PublicApi
    +   * @description The sort criteria on one or more columns has
    +   * changed.  Provides as parameters the grid and the output of
    +   * getColumnSorting, which is an array of gridColumns
    +   * that have sorting on them, sorted in priority order. 
    +   * 
    +   * @param {Grid} grid the grid
    +   * @param {array} sortColumns an array of columns with 
    +   * sorts on them, in priority order
    +   * 
    +   * @example
    +   * <pre>
    +   *      gridApi.core.on.sortChanged( grid, sortColumns );
    +   * </pre>
    +   */
    +  self.api.registerEvent( 'core', 'sortChanged' );
    +};
    +
    +    /**
    +     * @ngdoc function
    +     * @name isRTL
    +     * @methodOf ui.grid.class:Grid
    +     * @description Returns true if grid is RightToLeft
    +     */
    +    Grid.prototype.isRTL = function () {
    +      return this.rtl;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows,  this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          $log.log('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, self.rowHeaderColumns.length + 1, self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.gridOptions)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns() {
    +    $log.debug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var offset = self.rowHeaderColumns.length;
    +
    +    //add row header columns to the grid columns array
    +    angular.forEach(self.rowHeaderColumns, function (rowHeaderColumn) {
    +      offset++;
    +      self.columns.push(rowHeaderColumn);
    +    });
    +
    +    // Synchronize self.columns with self.options.columnDefs so that columns can also be removed.
    +    if (self.columns.length > self.options.columnDefs.length) {
    +      self.columns.forEach(function (column, index) {
    +        if (!self.getColDef(column.name)) {
    +          self.columns.splice(index, 1);
    +        }
    +      });
    +    }
    +
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, index + offset, self);
    +        self.columns.push(col);
    +      }
    +      else {
    +        col.updateColumnDef(colDef, col.index);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    return $q.all(builderPromises);
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +        this.columns.forEach(function (col) {
    +          var html = col.cellTemplate.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +          var compiledElementFn = $compile(html);
    +          col.compiledElementFn = compiledElementFn;
    +        });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      colDef.name = colDef.field;
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i=0; i<n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j=0; j<o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var rows = this.rows.filter(function (row) {
    +        return row.entity === rowEntity;
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        newRow;
    +
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i=0; i<newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        var rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          var found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i=0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.gridOptions);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // $log.debug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleRowCache.length = 0;
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // $log.debug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // $log.debug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    }
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    // $log.debug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    // $log.debug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    }
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        column.sort.direction = null;
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * 
    +   */
    +  Grid.prototype.refresh = function refresh() {
    +    $log.debug('grid refresh');
    +    
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace();
    +
    +      self.refreshCanvas(true);
    +    });
    +  };  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        // TODO: this method doesn't exist, so clearly refreshRows doesn't work.
    +        self.redrawRows();
    +
    +        self.refreshCanvas();
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +    
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        if (container.header) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        for (var i = 0; i < containerHeadersToRecalc.length; i++) {
    +          var container = containerHeadersToRecalc[i];
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +            container.headerHeight = headerHeight;
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace() {
    +    // $log.debug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // $log.debug('redrawing container', i);
    +
    +      container.adjustRows(container.prevScrollTop, null);
    +      container.adjustColumns(container.prevScrollLeft, null);
    +    }
    +  };
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$log', '$q', '$rootScope', 'gridUtil', 'uiGridConstants',
    +      function ($log, $q, $rootScope, gridUtil, uiGridConstants) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.methodName and featureName.on.eventName(function(args){}
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.scope, l.eventId, l.handler, self.grid);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          $log.log('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$broadcast.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          $log.log('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler) {
    +            var dereg = registerEventWithAngular(scope, eventId, handler, self.grid);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: dereg, eventId: eventId, scope: scope};
    +            self.listeners.push(listener);
    +
    +            //destroy tracking when scope is destroyed
    +            //wanted to remove the listener from the array but angular does
    +            //strange things in scope.$destroy so I could not access the listener array
    +            scope.$on('$destroy', function() {
    +              listener.dereg = null;
    +              listener.handler = null;
    +              listener.eventId = null;
    +              listener.scope = null;
    +            });
    +          };
    +        };
    +
    +        function registerEventWithAngular(scope, eventId, handler, grid) {
    +          return scope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} thisArg binds callBackFn 'this' to thisArg.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, thisArg) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(thisArg || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} thisArg binds this to thisArg for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, thisArg) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, thisArg);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +   /**
    +    * ******************************************************************************************
    +    * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +    * and need to be noted as such for those extending and building ui-grid itself.
    +    * However, from an end-developer perspective, they interact with all these through columnDefs,
    +    * and they really need to be documented there.  I feel like they're relatively static, and
    +    * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +    * comment block.  Ugh.
    +    * 
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name name
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description (mandatory) each column should have a name, although for backward
    +    * compatibility with 2.x name can be omitted if field is present
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name displayName
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Column name that will be shown in the header.  If displayName is not
    +    * provided then one is generated using the name.
    +    *
    +    */
    +       
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name field
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description field must be provided if you wish to bind to a 
    +    * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +    * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +    * See the angular docs on binding expressions.
    +    *
    +    */
    +    
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filter on this column.  
    +    * @example
    +    * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...' }</pre>
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name filter
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify a single filter field on this column.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1',
    +    *     filter: {
    +    *       condition: uiGridConstants.filter.STARTS_WITH,
    +    *       placeholder: 'starts with...'
    +    *     }
    +    *   }
    +    * ]; </pre>
    +    *
    +    */
    +    
    +   
    +  function GridColumn(colDef, index, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    colDef.index = index;
    +
    +    self.updateColumnDef(colDef);
    +  }
    +
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +   /** 
    +    * @ngdoc property
    +    * @name width
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the column width.  Can be either 
    +    * a number or a percentage, or an * for auto.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +    *                                          { field: 'field2', width: '20%'},
    +    *                                          { field: 'field3', width: '*' }]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name minWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the minimum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name maxWidth
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets the maximum column width.  Should be a number.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +    *
    +    */
    +
    +   /** 
    +    * @ngdoc property
    +    * @name visible
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description sets whether or not the column is visible
    +    * </br>Default is true
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *     { field: 'field1', visible: true},
    +    *     { field: 'field2', visible: false }
    +    *   ]; </pre>
    +    *
    +    */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +
    +    /** 
    +    * @ngdoc property
    +    * @name sortingAlgorithm
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +    * like any normal sorting function.
    +    *
    +    */
    +      
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description Specify multiple filter fields.
    +    * @example
    +    * <pre>$scope.gridOptions.columnDefs = [ 
    +    *   {
    +    *     field: 'field1', filters: [
    +    *       {
    +    *         condition: uiGridConstants.filter.STARTS_WITH,
    +    *         placeholder: 'starts with...'
    +    *       },
    +    *       {
    +    *         condition: uiGridConstants.filter.ENDS_WITH,
    +    *         placeholder: 'ends with...'
    +    *       }
    +    *     ]
    +    *   }
    +    * ]; </pre>
    +    *
    +    * 
    +    */ 
    +   
    +   /** 
    +    * @ngdoc array
    +    * @name filters
    +    * @propertyOf ui.grid.class:GridColumn
    +    * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +    * @example
    +    * <pre>[
    +    *   {
    +    *     term: 'foo', // ngModel for <input>
    +    *     condition: uiGridConstants.filter.STARTS_WITH,
    +    *     placeholder: 'starts with...'
    +    *   },
    +    *   {
    +    *     term: 'baz',
    +    *     condition: uiGridConstants.filter.ENDS_WITH,
    +    *     placeholder: 'ends with...'
    +    *   }
    +    * ] </pre>
    +    *
    +    * 
    +    */   
    +
    +   /** 
    +    * @ngdoc array
    +    * @name menuItems
    +    * @propertyOf ui.grid.class:GridOptions.columnDef
    +    * @description used to add menu items to a column.  Refer to the tutorial on this 
    +    * functionality.
    +    * @example
    +    * <pre>  $scope.gridOptions.columnDefs = [ 
    +    *   { field: 'field1', menuItems: [
    +    *     {
    +    *       title: 'Outer Scope Alert',
    +    *       icon: 'ui-grid-icon-info-circled',
    +    *       action: function($event) {
    +    *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +    *       },
    +    *       context: $scope
    +    *     },
    +    *     {
    +    *       title: 'Grid ID',
    +    *       action: function() {
    +    *         alert('Grid ID: ' + this.grid.id);
    +    *       }
    +    *     }
    +    *   ] }]; </pre>
    +    *
    +    */   
    +  GridColumn.prototype.updateColumnDef = function(colDef, index) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    //position of column
    +    self.index = (typeof(index) === 'undefined') ? colDef.index : index;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.index);
    +    }
    +
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(colDef.width)) {
    +      self.width = '*';
    +    }
    +    else {
    +      // If the width is not a number
    +      if (!angular.isNumber(colDef.width)) {
    +        // See if it ends with a percent
    +        if (gridUtil.endsWith(colDef.width, '%')) {
    +          // If so we should be able to parse the non-percent-sign part to a number
    +          var percentStr = colDef.width.replace(/%/g, '');
    +          var percent = parseInt(percentStr, 10);
    +          if (isNaN(percent)) {
    +            throw new Error(parseErrorMsg);
    +          }
    +          self.width = colDef.width;
    +        }
    +        // And see if it's a number string
    +        else if (colDef.width.match(/^(\d+)$/)) {
    +          self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +        }
    +        // Otherwise it should be a string of asterisks
    +        else if (!colDef.width.match(/^\*+$/)) {
    +          throw new Error(parseErrorMsg);
    +        }
    +      }
    +      // Is a number, use it as the width
    +      else {
    +        self.width = colDef.width;
    +      }
    +    }
    +
    +    // Remove this column from the grid sorting
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +    };
    +
    +    self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    self.visible = true;
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it
    +    self.setPropertyOrDefault(colDef, 'sort');
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef.filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description An object defining filtering for a column.
    +     */    
    +
    +    /**
    +     * @ngdoc property
    +     * @name condition
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description Defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     */
    +    
    +    /**
    +     * @ngdoc property
    +     * @name term
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description If set, the filter field will be pre-populated
    +     * with this value.
    +     */
    +
    +    /**
    +     * @ngdoc property
    +     * @name placeholder
    +     * @propertyOf ui.grid.class:GridOptions.columnDef.filter
    +     * @description String that will be set to the <input>.placeholder attribute.
    +     */
    +
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    self.setPropertyOrDefault(colDef, 'filter');
    +    self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +  };
    +
    +
    +
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClass
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class name for the column
    +     * @param {bool} prefixDot  if true, will return .className instead of className
    +     */
    +    GridColumn.prototype.getColClass = function (prefixDot) {
    +      var cls = uiGridConstants.COL_CLASS_PREFIX + this.index;
    +
    +      return prefixDot ? '.' + cls : cls;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getColClassDefinition
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the class definition for th column
    +     */
    +    GridColumn.prototype.getColClassDefinition = function () {
    +      return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { width: ' + this.drawnWidth + 'px; }';
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRenderContainer
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Returns the render container object that this column belongs to.
    +     *
    +     * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +     */
    +    GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +      var self = this;
    +
    +      var containerId = self.renderContainer;
    +
    +      if (containerId === null || containerId === '' || containerId === undefined) {
    +        containerId = 'body';
    +      }
    +
    +      return self.grid.renderContainers[containerId];
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name showColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Makes the column visible by setting colDef.visible = true
    +     */
    +    GridColumn.prototype.showColumn = function() {
    +        this.colDef.visible = true;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hideColumn
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description Hides the column by setting colDef.visible = false
    +     */
    +    GridColumn.prototype.hideColumn = function() {
    +        this.colDef.visible = false;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getAggregationValue
    +     * @methodOf ui.grid.class:GridColumn
    +     * @description gets the aggregation value based on the aggregation type for this column
    +     */
    +    GridColumn.prototype.getAggregationValue = function () {
    +      var self = this;
    +      var result = 0;
    +      var visibleRows = self.grid.getVisibleRows();
    +      var cellValues = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          cellValues.push(cellValue);
    +        }
    +      });
    +      if (angular.isFunction(self.aggregationType)) {
    +        return self.aggregationType(visibleRows, self);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +        //TODO: change to i18n
    +        return 'total rows: ' + self.grid.getVisibleRowCount();
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        //TODO: change to i18n
    +        return 'total: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +        angular.forEach(cellValues, function (value) {
    +          result += value;
    +        });
    +        result = result / cellValues.length;
    +        //TODO: change to i18n
    +        return 'avg: ' + result;
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +        return 'min: ' + Math.min.apply(null, cellValues);
    +      }
    +      else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +        return 'max: ' + Math.max.apply(null, cellValues);
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    return GridColumn;
    +  }]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil', function(gridUtil) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>app.config(function($provide){
    +   *    $provide.decorator('GridOptions',function($delegate){
    +   *      return function(){
    +   *        var defaultOptions = new $delegate();
    +   *        defaultOptions.excludeProperties = ['id' ,'$$hashKey'];
    +   *        return defaultOptions;
    +   *      };
    +   *    })
    +   *  })</pre>
    +   */
    +  function GridOptions() {
    +
    +    this.onRegisterApi = angular.noop();
    +
    +    /**
    +     * @ngdoc object
    +     * @name data
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +     * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +     * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +     * an angularJS $resource query request.  The array can also contain complex objects.
    +     * 
    +     */
    +    this.data = [];
    +
    +    /**
    +     * @ngdoc array
    +     * @name columnDefs
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of columnDef objects.  Only required property is name.
    +     * The individual options available in columnDefs are documented in the
    +     * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +     * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +     *  @example
    +     *
    +     * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +     *
    +     */
    +    this.columnDefs = [];
    +
    +    /**
    +     * @ngdoc object
    +     * @name ui.grid.class:GridOptions.columnDef
    +     * @description Definition / configuration of an individual column, which would typically be
    +     * one of many column definitions within the gridOptions.columnDefs array
    +     * @example
    +     * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +     *
    +     */
    +
    +        
    +    /**
    +     * @ngdoc array
    +     * @name excludeProperties
    +     * @propertyOf  ui.grid.class:GridOptions
    +     * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +     * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +     * to exclude. 
    +     * 
    +     * If columnDefs is defined, this will be ignored.
    +     * 
    +     * Defaults to ['$$hashKey']
    +     */
    +    
    +    this.excludeProperties = ['$$hashKey'];
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableRowHashing
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting allows uiGrid to add
    +     * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +     * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +     * 
    +     * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +     * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +     * and are altering the data set often.
    +     */
    +    this.enableRowHashing = true;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function is used to get and, if necessary, set the value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +     */
    +    this.rowIdentity = function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRowIdentity
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description This function returns the identity value uniquely identifying this row.
    +     * 
    +     * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +     */
    +    this.getRowIdentity = function getRowIdentity(row) {
    +        return row.$$hashKey;
    +    };
    +
    +    this.headerRowHeight = 30;
    +    this.rowHeight = 30;
    +    this.maxVisibleRowCount = 200;
    +
    +    /**
    +     * @ngdoc integer
    +     * @name minRowsToShow
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +     */
    +    this.minRowsToShow = 10;
    +
    +    this.showFooter = false;
    +    this.footerRowHeight = 30;
    +
    +    this.columnWidth = 50;
    +    this.maxVisibleColumnCount = 200;
    +
    +    // Turn virtualization on when number of data elements goes over this number
    +    this.virtualizationThreshold = 20;
    +
    +    this.columnVirtualizationThreshold = 10;
    +
    +    // Extra rows to to render outside of the viewport
    +    this.excessRows = 4;
    +    this.scrollThreshold = 4;
    +
    +    // Extra columns to to render outside of the viewport
    +    this.excessColumns = 4;
    +    this.horizontalScrollThreshold = 2;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting adds sort
    +     * widgets to the column headers, allowing sorting of the data for the entire grid.
    +     * Sorting can then be disabled on individual columns using the columnDefs.
    +     */
    +    this.enableSorting = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description False by default. When enabled, this setting adds filter 
    +     * boxes to each column header, allowing filtering within the column for the entire grid.
    +     * Filtering can then be disabled on individual columns using the columnDefs. 
    +     */
    +    this.enableFiltering = false;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableColumnMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this setting displays a column
    +     * menu within each column.
    +     */
    +    this.enableColumnMenu = true;
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableScrollbars
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description True by default. When enabled, this settings enable vertical
    +     * and horizontal scrollbar for grid.
    +     */
    +    this.enableScrollbars = true;
    +
    +    // Columns can't be smaller than 10 pixels
    +    this.minimumColumnSize = 10;
    +
    +    /**
    +     * @ngdoc function
    +     * @name rowEquality
    +     * @methodOf ui.grid.class:GridOptions
    +     * @description By default, rows are compared using object equality.  This option can be overridden
    +     * to compare on any data item property or function
    +     * @param {object} entityA First Data Item to compare
    +     * @param {object} entityB Second Data Item to compare
    +     */
    +    this.rowEquality = function(entityA, entityB) {
    +      return entityA === entityB;
    +    };
    +
    +    /**
    +     * @ngdoc string
    +     * @name headerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description Null by default. When provided, this setting uses a custom header
    +     * template, rather than the default template. Can be set to either the name of a template file:
    +     * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +     * or the id of a precompiled template (TBD how to use this).  
    +     * </br>Refer to the custom header tutorial for more information.
    +     * If you want no header at all, you can set to an empty div:
    +     * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +     * 
    +     * If you want to only have a static header, then you can set to static content.  If
    +     * you want to tailor the existing column headers, then you should look at the
    +     * current 'ui-grid-header.html' template in github as your starting point.
    +     * 
    +     */
    +    this.headerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name footerTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) Null by default. When provided, this setting uses a custom footer
    +     * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +     * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +     * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +     */
    +    this.footerTemplate = null;
    +
    +    /**
    +     * @ngdoc string
    +     * @name rowTemplate
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +     * custom row template.  Can be set to either the name of a template file:
    +     * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +     * inline html 
    +     * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="getExternalScopes().fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +     * or the id of a precompiled template (TBD how to use this) can be provided.  
    +     * </br>Refer to the custom row template tutorial for more information.
    +     */
    +    this.rowTemplate = 'ui-grid/ui-grid-row';
    +  }
    +
    +  return GridOptions;
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRenderContainer', ['$log', 'gridUtil', function($log, gridUtil) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    if (typeof(self.horizontalScrollbarHeight) !== 'undefined' && self.horizontalScrollbarHeight !== undefined && self.horizontalScrollbarHeight > 0) {
    +      viewPortHeight = viewPortHeight - self.horizontalScrollbarHeight;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    }
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    var ret =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      ret += row.height;
    +    });
    +
    +    if (typeof(self.grid.horizontalScrollbarHeight) !== 'undefined' && self.grid.horizontalScrollbarHeight !== undefined && self.grid.horizontalScrollbarHeight > 0) {
    +      ret = ret - self.grid.horizontalScrollbarHeight;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +      ret = ret - self.verticalScrollbarWidth;
    +    }
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    scrollTop = this.getCanvasHeight() * scrollPercentage;
    +
    +    this.adjustRows(scrollTop, scrollPercentage);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    // scrollLeft = uiGridCtrl.canvas[0].scrollWidth * scrollPercentage;
    +    scrollLeft = this.getCanvasWidth() * scrollPercentage;
    +
    +    //$log.debug('scrollPercentage', scrollPercentage);
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +    self.maxRowIndex = maxRowIndex;
    +
    +    var curRowIndex = self.prevRowScrollIndex;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getCanvasHeight();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +      var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.rowStyle = function (index) {
    +    var self = this;
    +
    +    var styles = {};
    +    
    +    if (index === 0 && self.currentTopRow !== 0) {
    +      // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +      var hiddenRowWidth = (self.currentTopRow) * self.grid.options.rowHeight;
    +
    +      // return { 'margin-top': hiddenRowWidth + 'px' };
    +      styles['margin-top'] = hiddenRowWidth + 'px';
    +    }
    +
    +    if (self.currentFirstColumn !== 0) {
    +      if (self.grid.isRTL()) {
    +        styles['margin-right'] = self.columnOffset + 'px';
    +      }
    +      else {
    +        styles['margin-left'] = self.columnOffset + 'px';
    +      }
    +    }
    +
    +    return styles;
    +  };
    +
    +  GridRenderContainer.prototype.columnStyle = function (index) {
    +    var self = this;
    +    
    +    if (index === 0 && self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth();
    +
    +    if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +      availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    }
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +
    +        // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    if (self.grid.verticalScrollbarWidth) {
    +      canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    }
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name index
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description the index of the GridRow. It should always be unique and immutable
    +      */
    +    this.index = index;
    +
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +  /**
    +    *  @ngdoc object
    +    *  @name height
    +    *  @propertyOf  ui.grid.class:GridRow
    +    *  @description height of each individual row
    +    */
    +    this.height = grid.options.rowHeight;
    +
    +    /**
    +     * @ngdoc function
    +     * @name setRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Sets an override on the row to make it always invisible,
    +     * which will override any filtering or other visibility calculations.  
    +     * If the row is currently visible then sets it to invisible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.setRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'setRowInvisible', this.setRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name clearRowInvisible
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Clears any override on visibility for the row so that it returns to 
    +     * using normal filtering and other visibility calculations.  
    +     * If the row is currently invisible then sets it to visible and calls
    +     * both grid refresh and emits the rowsVisibleChanged event
    +     * TODO: if a filter is active then we can't just set it to visible?
    +     * @param {object} rowEntity gridOptions.data[] array instance
    +     */
    +    if (!this.grid.api.core.clearRowInvisible){
    +      this.grid.api.registerMethod( 'core', 'clearRowInvisible', this.clearRowInvisible );
    +    }
    +
    +    /**
    +     * @ngdoc function
    +     * @name getVisibleRows
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description Returns all visible rows
    +     * @param {Grid} grid the grid you want to get visible rows from
    +     * @returns {array} an array of gridRow 
    +     */
    +    if (!this.grid.api.core.getVisibleRows){
    +      this.grid.api.registerMethod( 'core', 'getVisibleRows', this.getVisibleRows );
    +    }
    +    
    +    /**
    +     * @ngdoc event
    +     * @name rowsVisibleChanged
    +     * @eventOf  ui.grid.core.api:PublicApi
    +     * @description  is raised after the rows that are visible
    +     * change.  The filtering is zero-based, so it isn't possible
    +     * to say which rows changed (unlike in the selection feature).
    +     * We can plausibly know which row was changed when setRowInvisible
    +     * is called, but in that situation the user already knows which row
    +     * they changed.  When a filter runs we don't know what changed, 
    +     * and that is the one that would have been useful.
    +     * 
    +     */
    +    if (!this.grid.api.core.raise.rowsVisibleChanged){
    +      this.grid.api.registerEvent( 'core', 'rowsVisibleChanged' );
    +    }
    +    
    +  }
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +  GridRow.prototype.getQualifiedColField = function(col) {
    +    return 'row.' + this.getEntityQualifiedColField(col);
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getVisibleRows
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Returns all the visible rows
    +   * @param {Grid} grid the grid to return rows from
    +   * @returns {array} rows that are currently visible, returns the
    +   * GridRows rather than gridRow.entity
    +   * TODO: should this come from visible row cache instead?
    +   */
    +  GridRow.prototype.getVisibleRows = function ( grid ) {
    +    return grid.rows.filter(function (row) {
    +      return row.visible;
    +    });
    +  };  
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', '$log', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, $log, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options: {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            colDef.headerCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            colDef.cellTemplate = 'ui-grid/uiGridCell';
    +          }
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.cellTemplate)
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +
    +          templateGetPromises.push(gridUtil.getTemplate(colDef.headerCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          return $q.all(templateGetPromises);
    +        }
    +
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +function QuickCache() {
    +  var c = function(get, set) {
    +    // Return the cached value of 'get' if it's stored
    +    if (get && c.cache[get]) {
    +      return c.cache[get];
    +    }
    +    // Otherwise set it and return it
    +    else if (get && set) {
    +      c.cache[get] = set;
    +      return c.cache[get];
    +    }
    +    else {
    +      return undefined;
    +    }
    +  };
    +
    +  c.cache = {};
    +
    +  c.clear = function () {
    +    c.cache = {};
    +  };
    +
    +  return c;
    +}
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['$log', 'uiGridConstants', function ($log, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  // rowSearcher.searchColumn = function searchColumn(condition, item) {
    +  //   var result;
    +
    +  //   var col = self.fieldMap[condition.columnDisplay];
    +
    +  //   if (!col) {
    +  //       return false;
    +  //   }
    +  //   var sp = col.cellFilter.split(':');
    +  //   var filter = col.cellFilter ? $filter(sp[0]) : null;
    +  //   var value = item[condition.column] || item[col.field.split('.')[0]];
    +  //   if (value === null || value === undefined) {
    +  //       return false;
    +  //   }
    +  //   if (typeof filter === "function") {
    +  //       var filterResults = filter(typeof value === "object" ? evalObject(value, col.field) : value, sp[1]).toString();
    +  //       result = condition.regex.test(filterResults);
    +  //   }
    +  //   else {
    +  //       result = condition.regex.test(typeof value === "object" ? evalObject(value, col.field).toString() : value.toString());
    +  //   }
    +  //   if (result) {
    +  //       return true;
    +  //   }
    +  //   return false;
    +  // };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    // Term starts with and ends with a *, use 'contains' condition
    +    // if (/^\*[\s\S]+?\*$/.test(term)) {
    +    //   return uiGridConstants.filter.CONTAINS;
    +    // }
    +    // // Term starts with a *, use 'ends with' condition
    +    // else if (/^\*/.test(term)) {
    +    //   return uiGridConstants.filter.ENDS_WITH;
    +    // }
    +    // // Term ends with a *, use 'starts with' condition
    +    // else if (/\*$/.test(term)) {
    +    //   return uiGridConstants.filter.STARTS_WITH;
    +    // }
    +    // // Default to default condition
    +    // else {
    +    //   return defaultCondition;
    +    // }
    +
    +    // If the term has *s then turn it into a regex
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, termCache, i, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Default to CONTAINS condition
    +    if (conditionType === 'undefined' || !filter.condition) {
    +      filter.condition = uiGridConstants.filter.CONTAINS;
    +    }
    +
    +    // Term to search for.
    +    var term = rowSearcher.stripTerm(filter);
    +
    +    if (term === null || term === undefined || term === '') {
    +      return true;
    +    }
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +
    +    var regexpFlags = '';
    +    if (!filter.flags || !filter.flags.caseSensitive) {
    +      regexpFlags += 'i';
    +    }
    +
    +    var cacheId = column.field + i;
    +
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      if (!filter.condition.test(value)) {
    +        return false;
    +      }
    +    }
    +    // If the filter's condition is a function, run it
    +    else if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    else if (filter.condition === uiGridConstants.filter.STARTS_WITH) {
    +      var startswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp('^' + term, regexpFlags));
    +
    +      if (!startswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.ENDS_WITH) {
    +      var endswithRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term + '$', regexpFlags));
    +
    +      if (!endswithRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.CONTAINS) {
    +      var containsRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId, new RegExp(term, regexpFlags));
    +
    +      if (!containsRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.EXACT) {
    +      var exactRE = termCache(cacheId) ? termCache(cacheId) : termCache(cacheId,  new RegExp('^' + term + '$', regexpFlags));
    +
    +      if (!exactRE.test(value)) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      if (value <= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      if (value < term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      if (value >= term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      if (value > term) {
    +        return false;
    +      }
    +    }
    +    else if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      if (!angular.equals(value, term)) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process filters on a given column against a given row. If the row meets the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, termCache) {
    +    var filters = [];
    +
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    if (typeof(column.filters) !== 'undefined' && column.filters && column.filters.length > 0) {
    +      filters = column.filters;
    +    } else {
    +      // If filters array is not there, assume no filters for this column. 
    +      // This array should have been built in GridColumn::updateColumnDef.
    +      return true;
    +    }
    +    
    +    for (var i in filters) {
    +      var filter = filters[i];
    +
    +      /*
    +        filter: {
    +          term: 'blah', // Search term to search for, could be a string, integer, etc.
    +          condition: uiGridConstants.filter.CONTAINS // Type of match to do. Defaults to CONTAINS (i.e. looking in a string), but could be EXACT, GREATER_THAN, etc.
    +          flags: { // Flags for the conditions
    +            caseSensitive: false // Case-sensitivity defaults to false
    +          }
    +        }
    +      */
    +     
    +      // Check for when no condition is supplied. In this case, guess the condition
    +      // to use based on the filter's term. Cache this result.
    +      if (!filter.condition) {
    +        // Cache custom conditions, building the RegExp takes time
    +        var conditionCacheId = 'cond-' + column.field + '-' + filter.term;
    +        var condition = termCache(conditionCacheId) ? termCache(conditionCacheId) : termCache(conditionCacheId, rowSearcher.guessCondition(filter));
    +
    +        // Create a surrogate filter so as not to change
    +        // the actual columnDef.filters.
    +        filter = {
    +          // Copy over the search term
    +          term: filter.term,
    +          // Use the guessed condition
    +          condition: condition,
    +          // Set flags, using passed flags if present
    +          flags: angular.extend({
    +            caseSensitive: false
    +          }, filter.flags)
    +        };
    +      }
    +
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, termCache, i, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +    // }
    +    // else {
    +    //   // No filter conditions, default to true
    +    //   return true;
    +    // }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Create a term cache
    +    var termCache = new QuickCache();
    +
    +    // Build filtered column list
    +    var filterCols = [];
    +    columns.forEach(function (col) {
    +      if (typeof(col.filters) !== 'undefined' && col.filters.length > 0) {
    +        filterCols.push(col);
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && typeof(col.filter.term) !== 'undefined' && col.filter.term) {
    +        filterCols.push(col);
    +      }
    +    });
    +    
    +    if (filterCols.length > 0) {
    +      filterCols.forEach(function foreachFilterCol(col) {
    +        rows.forEach(function foreachRow(row) {
    +          if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, termCache)) {
    +            row.visible = false;
    +          }
    +        });
    +      });
    +      
    +      grid.api.core.raise.rowsVisibleChanged();
    +
    +      // rows.forEach(function (row) {
    +      //   var matchesAllColumns = true;
    +
    +      //   for (var i in filterCols) {
    +      //     var col = filterCols[i];
    +
    +      //     if (!rowSearcher.searchColumn(grid, row, col, termCache)) {
    +      //       matchesAllColumns = false;
    +
    +      //       // Stop processing other terms
    +      //       break;
    +      //     }
    +      //   }
    +
    +      //   // Row doesn't match all the terms, don't display it
    +      //   if (!matchesAllColumns) {
    +      //     row.visible = false;
    +      //   }
    +      //   else {
    +      //     row.visible = true;
    +      //   }
    +      // });
    +    }
    +
    +    // Reset the term cache
    +    termCache.clear();
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +  // Guess which sort function to use on this item
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +
    +    // Check for numbers and booleans
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +  // Basic sorting function
    +  rowSorter.basicSort = function basicSort(a, b) {
    +      if (a === b) {
    +          return 0;
    +      }
    +      if (a < b) {
    +          return -1;
    +      }
    +      return 1;
    +  };
    +
    +  // Number sorting function
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +      return a - b;
    +  };
    +
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var numA, // The parsed number form of 'a'
    +        numB, // The parsed number form of 'b'
    +        badA = false,
    +        badB = false;
    +
    +    // Try to parse 'a' to a float
    +    numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'a' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numA)) {
    +        badA = true;
    +    }
    +
    +    // Try to parse 'b' to a float
    +    numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +
    +    // If 'b' couldn't be parsed to float, flag it as bad
    +    if (isNaN(numB)) {
    +        badB = true;
    +    }
    +
    +    // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +    if (badA && badB) {
    +        return 0;
    +    }
    +
    +    if (badA) {
    +        return 1;
    +    }
    +
    +    if (badB) {
    +        return -1;
    +    }
    +
    +    return numA - numB;
    +  };
    +
    +  // String sorting function
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var strA = a.toLowerCase(),
    +        strB = b.toLowerCase();
    +
    +    return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +  };
    +
    +  // Date sorting function
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var timeA = a.getTime(),
    +        timeB = b.getTime();
    +
    +    return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +  };
    +
    +  // Boolean sorting function
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    if (a && b) {
    +      return 0;
    +    }
    +
    +    if (!a && !b) {
    +      return 0;
    +    }
    +    else {
    +      return a ? 1 : -1;
    +    }
    +  };
    +
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +
    +    // Now actually sort the data
    +    return rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        // We want to allow zero values to be evaluated in the sort function
    +        if ((!propA && propA !== 0) || (!propB && propB !== 0)) {
    +          // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +          if (!propB && !propA) {
    +            tem = 0;
    +          }
    +          else if (!propA) {
    +            tem = 1;
    +          }
    +          else if (!propB) {
    +            tem = -1;
    +          }
    +        }
    +        else {
    +          tem = sortFn(propA, propB);
    +        }
    +
    +        idx++;
    +      }
    +
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +
    +function getStyles (elem) {
    +  return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, uiGridConstants) {
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return $q.when($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template;
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      $log.debug('Fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        );
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    }
    +
    +    // setHashKey: function setHashKey(obj, h) {
    +    //   if (h) {
    +    //     obj.$$hashKey = h;
    +    //   }
    +    //   else {
    +    //     delete obj.$$hashKey;
    +    //   }
    +    // }
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    if (borderType) {
    +      borderType = 'border-' + borderType;
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = angular.element(element).css('direction');
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +          aggregate:{
    +            label: 'artikler'
    +          },
    +          groupPanel:{
    +            description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +          },
    +          search:{
    +            placeholder: 'Søg...',
    +            showingItems: 'Viste rækker:',
    +            selectedItems: 'Valgte rækker:',
    +            totalItems: 'Rækker totalt:',
    +            size: 'Side størrelse:',
    +            first: 'Første side',
    +            next: 'Næste side',
    +            previous: 'Forrige side',
    +            last: 'Sidste side'
    +          },
    +          menu:{
    +            text: 'Vælg kolonner:',
    +          },
    +          column: {
    +            hide: 'Skjul kolonne'
    +          }
    +        });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrando:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        column: {
    +          hide: 'Colonne de peau'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +    angular.module('ui.grid').config(['$provide', function ($provide) {
    +        $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +            $delegate.add('he', {
    +                aggregate: {
    +                    label: 'items'
    +                },
    +                groupPanel: {
    +                    description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +                },
    +                search: {
    +                    placeholder: 'חפש...',
    +                    showingItems: 'מציג:',
    +                    selectedItems: 'סה"כ נבחרו:',
    +                    totalItems: 'סה"כ רשומות:',
    +                    size: 'תוצאות בדף:',
    +                    first: 'דף ראשון',
    +                    next: 'דף הבא',
    +                    previous: 'דף קודם',
    +                    last: 'דף אחרון'
    +                },
    +                menu: {
    +                    text: 'בחר עמודות:'
    +                },
    +                sort: {
    +                    ascending: 'סדר עולה',
    +                    descending: 'סדר יורד',
    +                    remove: 'בטל'
    +                },
    +                column: {
    +                  hide: 'טור הסתר'
    +                }
    +            });
    +            return $delegate;
    +        }]);
    +    }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Kolom te verbergen'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +angular.module('ui.grid').config(['$provide', function($provide) {
    +$provide.decorator('i18nService', ['$delegate', function($delegate) {
    +$delegate.add('sk', {
    +aggregate: {
    +label: 'items'
    +},
    +groupPanel: {
    +description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +},
    +search: {
    +placeholder: 'Hľadaj...',
    +showingItems: 'Zobrazujem položky:',
    +selectedItems: 'Vybraté položky:',
    +totalItems: 'Počet položiek:',
    +size: 'Počet:',
    +first: 'Prvá strana',
    +next: 'Ďalšia strana',
    +previous: 'Predchádzajúca strana',
    +last: 'Posledná strana'
    +},
    +menu: {
    +text: 'Vyberte stĺpce:'
    +},
    +sort: {
    +ascending: 'Zotriediť vzostupne',
    +descending: 'Zotriediť zostupne',
    +remove: 'Vymazať triedenie'
    +}
    +});
    +return $delegate;
    +}]);
    +}]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  DIRECTIVE_ALIASES.forEach(function (alias) {
    +    module.directive(alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective]);
    +  });
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  FILTER_ALIASES.forEach(function (alias) {
    +    module.filter(alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter]);
    +  });
    +
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '条目'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处以进行分组'
    +        },
    +        search: {
    +          placeholder: '搜索...',
    +          showingItems: '当前显示条目:',
    +          selectedItems: '选中条目:',
    +          totalItems: '条目总数:',
    +          size: '每页显示数:',
    +          first: '回到首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '前往尾页'
    +        },
    +        menu: {
    +          text: '数据分组与选择列:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '筆'
    +        },
    +        groupPanel: {
    +          description: '拖拉表頭到此處以進行分組'
    +        },
    +        search: {
    +          placeholder: '搜尋...',
    +          showingItems: '目前顯示筆數:',
    +          selectedItems: '選取筆數:',
    +          totalItems: '總筆數:',
    +          size: '每頁顯示:',
    +          first: '第一頁',
    +          next: '下一頁',
    +          previous: '上一頁',
    +          last: '最後頁'
    +        },
    +        menu: {
    +          text: '選擇欄位:'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$log', '$timeout', 'gridUtil', function ($log, $timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var canceler;
    +        function startTimeout() {
    +          $timeout.cancel(canceler);
    +
    +          canceler = $timeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              uiGridCtrl.grid.queueRefresh()
    +                .then(function () {
    +                  getDimensions();
    +
    +                  startTimeout();
    +                });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          $timeout.cancel(canceler);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME : 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3}
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['$log', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function ($log, uiGridConstants, uiGridCellNavConstants, $q) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav : {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate : function(newRowCol, oldRowCol){}
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {Grid} grid the grid you'd like to act upon, usually available
    +                 * from gridApi.grid
    +                 * @param {object} $scope a scope we can broadcast events from
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (grid, $scope, rowEntity, colDef) {
    +                  service.scrollTo(grid, $scope, rowEntity, colDef);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getNextRowCol
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  returns the next row and column for a given direction
    +         * columns that are not focusable are skipped
    +         * @param {object} direction navigation direction
    +         * @param {Grid} grid current grid
    +         * @param {GridRow} curRow Gridrow
    +         * @param {GridCol} curCol Gridcol
    +         * @returns {uiGridCellNavConstants.direction} rowCol object
    +         */
    +        getNextRowCol: function (direction, grid, curRow, curCol) {
    +          switch (direction) {
    +            case uiGridCellNavConstants.direction.LEFT:
    +              return service.getRowColLeft(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.RIGHT:
    +              return service.getRowColRight(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.UP:
    +              return service.getRowColUp(grid.rows, grid.columns, curRow, curCol);
    +            case uiGridCellNavConstants.direction.DOWN:
    +              return service.getRowColDown(grid.rows, grid.columns, curRow, curCol);
    +          }
    +        },
    +
    +        getRowColLeft: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexLeft(cols, curCol);
    +
    +          if (colIndex > curCol.index) {
    +            if (curRow.index === 0) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //up one row and far right column
    +              return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColRight: function (rows, cols, curRow, curCol) {
    +          var colIndex = service.getNextColIndexRight(cols, curCol);
    +
    +          if (colIndex < curCol.index) {
    +            if (curRow.index === rows.length - 1) {
    +              return new RowCol(curRow, cols[colIndex]); //return same row
    +            }
    +            else {
    +              //down one row and far left column
    +              return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +            }
    +          }
    +          else {
    +            return new RowCol(curRow, cols[colIndex]);
    +          }
    +        },
    +
    +        getNextColIndexLeft: function (cols, curCol) {
    +          //start with next col to the left or the end of the array if curCol is the first col
    +          var i = curCol.index === 0 ? cols.length - 1 : curCol.index - 1;
    +
    +          //find first focusable column to the left
    +          //circle around to the end of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i--;
    +            //go to end of array if at the beginning
    +            if (i === -1) {
    +              i = cols.length - 1;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getNextColIndexRight: function (cols, curCol) {
    +          //start with next col to the right or the beginning of the array if curCol is the last col
    +          var i = curCol.index === cols.length - 1 ? 0 : curCol.index + 1;
    +
    +          //find first focusable column to the right
    +          //circle around to the beginning of the array if no col is found
    +          while (i !== curCol.index) {
    +            if (cols[i].colDef.allowCellFocus) {
    +              break;
    +            }
    +            i++;
    +            //go to end of array if at the beginning
    +            if (i > cols.length - 1) {
    +              i = 0;
    +            }
    +          }
    +
    +          return i;
    +        },
    +
    +        getRowColUp: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === 0) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //up one row
    +            return new RowCol(rows[curRow.index - 1], cols[colIndex]);
    +          }
    +        },
    +
    +        getRowColDown: function (rows, cols, curRow, curCol) {
    +          //if curCol is not focusable, then we need to find a focusable column to the right
    +          //this shouldn't ever happen in the grid, but we handle it anyway
    +          var colIndex = curCol.colDef.allowCellFocus ? curCol.index : service.getNextColIndexRight(cols, curCol);
    +
    +
    +          if (curRow.index === rows.length - 1) {
    +            return new RowCol(curRow, cols[colIndex]); //return same row
    +          }
    +          else {
    +            //down one row
    +            return new RowCol(rows[curRow.index + 1], cols[colIndex]);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell.  
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus ;
    +
    +          return $q.all(promises);
    +        },
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollVerticallyTo
    +         * @description Scroll the grid vertically such that the specified
    +         * row is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} $scope a scope we can broadcast events from
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, $scope, rowEntity, colDef) {
    +          var args = {};
    +          
    +          if ( rowEntity !== null ){
    +            var row = grid.getRow(rowEntity);
    +            if ( row ) { 
    +              args.y = { percentage: row.index / grid.renderContainers.body.visibleRowCache.length }; 
    +            }
    +          }
    +          
    +          if ( colDef !== null ){
    +            var col = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +            if ( col ) {
    +              args.x = { percentage: this.getLeftWidth(grid, col.index) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache.length - 1) };              
    +            }
    +          }
    +          
    +          if ( args.y || args.x ){
    +            $scope.$broadcast(uiGridConstants.events.GRID_SCROLL, args);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the 
    +         * grid up to and including the numbered column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} colIndex the column to total up to and including
    +         */
    +        getLeftWidth: function( grid, colIndex ){
    +          var width = 0;
    +          
    +          if ( !colIndex ){ return; }
    +          
    +          for ( var i=0; i <= colIndex; i++ ){
    +            if ( grid.renderContainers.body.visibleColumnCache[i].drawnWidth ){
    +              width += grid.renderContainers.body.visibleColumnCache[i].drawnWidth;
    +            } 
    +          }
    +          return width;
    +        }
    +
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['$log', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($log, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              //  $log.debug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = function (newRowCol) {
    +                $scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol.row, newRowCol.col);
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (row, col) {
    +                if (grid.cellNav.lastRowCol === null || (grid.cellNav.lastRowCol.row !== row || grid.cellNav.lastRowCol.col !== col)) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                }
    +              };
    +
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['uiGridCellNavService', '$log', 'uiGridCellNavConstants',
    +    function (uiGridCellNavService, $log, uiGridCellNavConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          if (!$scope.col.colDef.allowCellFocus) {
    +             return;
    +          }
    +
    +          setTabEnabled();
    +
    +          $elm.on('keydown', function (evt) {
    +            var direction = uiGridCellNavService.getDirection(evt);
    +            if (direction === null) {
    +              return true;
    +            }
    +
    +            var rowCol = uiGridCellNavService.getNextRowCol(direction, $scope.grid, $scope.row, $scope.col);
    +
    +            //$log.debug('next row ' + rowCol.row.index + ' next Col ' + rowCol.col.colDef.name);
    +            uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +            setTabEnabled();
    +
    +            return false;
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            uiGridCtrl.cellNav.broadcastFocus($scope.row, $scope.col);
    +          });
    +
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function(evt,rowCol){
    +             if (rowCol.row === $scope.row &&
    +               rowCol.col === $scope.col){
    +               // $log.debug('Setting focus on Row ' + rowCol.row.index + ' Col ' + rowCol.col.colDef.name);
    +                setFocused();
    +             }
    +          });
    +
    +          function setTabEnabled(){
    +            $elm.find('div').attr("tabindex", -1);
    +          }
    +
    +          function setFocused(){
    +            var div = $elm.find('div');
    +            div[0].focus();
    +            div.attr("tabindex", 0);
    +          }
    +
    +        }
    +      };
    +    }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$log', '$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }                
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs 
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.  
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.  
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.  
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ?
    +            false: gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object'):gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example 
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['$log', 'uiGridEditService', function ($log, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridEditConstants', '$log', '$parse', 'uiGridEditService',
    +      function ($compile, uiGridConstants, uiGridEditConstants, $log, $parse, uiGridEditService) {
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +            if (!$scope.col.colDef.enableCellEdit) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +            }
    +
    +            function beginEditFocus(evt) {
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving && 
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = { 
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor', 
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             * 
    +             */
    +            function beginEdit() {
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +              
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : ''; 
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              $scope.inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  $scope.inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  $scope.inputType = 'number';
    +                  break;
    +                case 'date':
    +                  $scope.inputType = 'date';
    +                  break;
    +              }
    +              
    +              $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';  
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';  
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                  inEdit = true;
    +                  cancelBeginEditEvents();
    +                  cellElement = $compile(html)($scope.$new());
    +                  var gridCellContentsEl = angular.element($elm.children()[0]);
    +                  isFocusedBeforeEdit = gridCellContentsEl.hasClass(':focus');
    +                  gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +                  $elm.append(cellElement);
    +                }
    +              );
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.$on(uiGridConstants.events.GRID_SCROLL, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl.focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +               $scope.deepEdit = false;
    +               
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('input', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if ('undefined' === typeof dateString || '' === dateString) {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (3 !== parts.length) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        restrict: 'E',
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && 'date' === attrs.type && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +    
    +    
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +               
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);    
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  module.service('uiGridExpandableService', ['gridUtil', '$log', '$compile', function (gridUtil, $log, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          methods: {
    +            expandable: {
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandable.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +        }
    +
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      },
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.refresh();
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridExpandable', ['$log', 'uiGridExpandableService', '$templateCache',
    +    function ($log, uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var expandableRowHeaderColDef = {name: 'expandableButtons', width: 40};
    +              expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +              uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$log', '$compile', 'uiGridConstants','gridUtil','$interval',
    +    function (uiGridExpandableService, $timeout, $log, $compile, uiGridConstants, gridUtil, $interval) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandable.rowExpandableTemplate).then(
    +                function (template) {
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRow',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', '$templateCache',
    +      function ($compile, $log, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    LINK_LABEL: 'LINK_LABEL',
    +    BUTTON_LABEL: 'BUTTON_LABEL'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$log', '$q', 'uiGridExporterConstants', 'gridUtil', '$compile',
    +    function ($log, $q, uiGridExporterConstants, gridUtil, $compile) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 * @param {element} $elm (Optional) A UI element into which the
    +                 * resulting download link will be placed. 
    +                 */
    +                csvExport: function (rowTypes, colTypes, $elm) {
    +                  service.csvExport(grid, rowTypes, colTypes, $elm);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for selection feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressButton
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressButton = gridOptions.exporterSuppressButton === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the resulting
    +           * link (for csv export)
    +           * <br/>Defaults to ui-grid/csvLink
    +           */
    +          gridOptions.exporterLinkTemplate = gridOptions.exporterLinkTemplate ? gridOptions.exporterLinkTemplate : 'ui-grid/csvLink';
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderTemplate
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom template to use for the header
    +           * section, containing the button and csv download link.  Not
    +           * needed if you've set suppressButton and are providing a custom
    +           * $elm into which the download link will go.
    +           * <br/>Defaults to ui-grid/exporterHeader
    +           */
    +          gridOptions.exporterHeaderTemplate = gridOptions.exporterHeaderTemplate ? gridOptions.exporterHeaderTemplate : 'ui-grid/exporterHeader';
    +          /**
    +           * @ngdoc object
    +           * @name exporterLinkLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the CSV download
    +           * link
    +           * <br/>Defaults to 'Download CSV'
    +           */
    +          gridOptions.exporterLinkLabel = gridOptions.exporterLinkLabel ? gridOptions.exporterLinkLabel : 'Download CSV';
    +          /**
    +           * @ngdoc object
    +           * @name exporterButtonLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterButtonLabel = gridOptions.exporterButtonLabel ? gridOptions.exporterButtonLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name showMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Shows the grid menu with exporter content,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        showMenu: function ( grid ) {
    +          grid.exporter.$scope.menuItems = [
    +            {
    +              title: 'Export all data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as csv',
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export all data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              }
    +            },
    +            {
    +              title: 'Export visible data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              }
    +            },
    +            {
    +              title: 'Export selected data as pdf',
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              }
    +            }
    +          ];
    +          
    +          grid.exporter.$scope.$broadcast('toggleExporterMenu');          
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed. 
    +         */
    +        csvExport: function (grid, rowTypes, colTypes, $elm) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData);
    +          this.renderCsvLink(grid, csvContent, $elm);
    +          
    +          // this.grid.exporter.$scope.$broadcast('clearExporterMenu');
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * TODO: filters
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: gridCol.displayName,
    +                // TODO: should we do something to normalise here if too wide?
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                // TODO: if/when we have an alignment attribute, use it here
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                $log.error('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          if ( uiGridExporterConstants.ALL ) {
    +            angular.forEach(rows, function( row, index ) {
    +
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +                if (gridCol.visible || colTypes === uiGridExporterConstants.ALL){
    +                  extractedRow.push(grid.getCellValue(row, gridCol));
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            });
    +            
    +            return data;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return header.displayName;});
    +          
    +          var csv = self.formatRowAsCsv(this)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsCsv).join(',');
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field;
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return '"' + field.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field);        
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name renderCsvLink
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Creates a download link with the csv content, 
    +         * putting it into the default exporter element, or into the element
    +         * passed in if provided
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * make available as a download link
    +         * @param {element} $elm (Optional) A UI element into which the
    +         * resulting download link will be placed.  If not provided, the
    +         * link is put into the default exporter element. 
    +         */
    +        renderCsvLink: function (grid, csvContent, $elm) {
    +          var targetElm = $elm ? $elm : angular.element( grid.exporter.gridElm[0].querySelectorAll('.ui-grid-exporter-csv-link') );
    +          if ( angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')) ) {
    +            angular.element( targetElm[0].querySelectorAll('.ui-grid-exporter-csv-link-span')).remove();
    +          }
    +          
    +          var linkTemplate = gridUtil.getTemplate(grid.options.exporterLinkTemplate)
    +          .then(function (contents) {
    +            contents = contents.replace(uiGridExporterConstants.LINK_LABEL, grid.options.exporterLinkLabel);
    +            contents = contents.replace(uiGridExporterConstants.CSV_CONTENT, encodeURIComponent(csvContent));
    +          
    +            var template = angular.element(contents);
    +            
    +            var newElm = $compile(template)(grid.exporter.$scope);
    +            targetElm.append(newElm);
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on jsPDF, which must
    +         * be either included as a script on your page, or downloaded and
    +         * served as part of your site.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle,
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          if (field == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field) === 'number') {
    +            return field.toString();
    +          }
    +          if (typeof(field) === 'boolean') {
    +            return (field ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field) === 'string') {
    +            return field.replace(/"/g,'""');
    +          }
    +
    +          return JSON.stringify(field).replace(/^"/,'').replace(/"$/,'');        
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['$log', 'uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function ($log, uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +              uiGridCtrl.grid.exporter.$scope = $scope;
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description 
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$log', '$compile', '$timeout', function (gridUtil, $log, $compile, $timeout) {
    +    
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' event
    +       */
    +
    +      loadData: function (grid) {
    +          grid.api.infiniteScroll.raise.needLoadMoreData();
    +          grid.options.loadTimout = true;
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and 
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20; 
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +      * @ngdoc property
    +      * @name infiniteScrollPercentage
    +      * @propertyOf ui.grid.class:GridOptions
    +      * @description This setting controls at what percentage of the scroll more data
    +      * is requested by the infinite scroll
    +      */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  
    +  module.directive('uiGridInfiniteScroll', ['$log', 'uiGridInfiniteScrollService',
    +    function ($log, uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return { 
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', '$log', 'uiGridInfiniteScrollService', 'uiGridConstants', 
    +      function ($compile, $log, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            $scope.$on(uiGridConstants.events.GRID_SCROLL, function(evt, args) {
    +
    +              var percentage = 100 - (args.y.percentage * 100);
    +              uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +            });
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('en',
    +        { pinning: {
    +            pinLeft: 'Pin Left',
    +            pinRight: 'Pin Right',
    +            unpin: 'Unpin'
    +          }
    +        }
    +      );
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  module.service('uiGridPinningService', ['$log', 'GridRenderContainer', 'i18nService', function ($log, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableRowSelection
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          col.renderContainer = 'left';
    +          col.grid.createLeftContainer();
    +        }
    +        else if (colDef.pinnedRight) {
    +          col.renderContainer = 'right';
    +          col.grid.createRightContainer();
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        col.menuItems.push(pinColumnLeftAction);
    +        col.menuItems.push(pinColumnRightAction);
    +        col.menuItems.push(removePinAction);
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['$log', 'uiGridPinningService',
    +    function ($log, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.constant('columnBounds', {
    +    minWidth: 35
    +  });
    +
    +
    +  module.service('uiGridResizeColumnsService', ['$log','$q',
    +    function ($log,$q) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['$log', 'uiGridResizeColumnsService', function ($log, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['$log', '$templateCache', '$compile', '$q', function ($log, $templateCache, $compile, $q) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +           if (uiGridCtrl.grid.options.enableColumnResizing) {
    +              var renderIndexDefer = $q.defer();
    +
    +              $attrs.$observe('renderIndex', function (n, o) {
    +                $scope.renderIndex = $scope.$eval(n);
    +
    +                renderIndexDefer.resolve();
    +              });
    +
    +              renderIndexDefer.promise.then(function() {
    +                var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +
    +                var resizerLeft = angular.element(columnResizerElm).clone();
    +                var resizerRight = angular.element(columnResizerElm).clone();
    +
    +                resizerLeft.attr('position', 'left');
    +                resizerRight.attr('position', 'right');
    +
    +                var col = $scope.col;
    +                var renderContainer = col.getRenderContainer();
    +
    +
    +                // Get the column to the left of this one
    +                var otherCol = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && $scope.col.index !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  $elm.prepend(resizerLeft);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                //if ($scope.col.index !== $scope.grid.renderedColumns.length - 1 && $scope.col.colDef.enableColumnResizing !== false) {
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  $elm.append(resizerRight);
    +                }
    +
    +                $compile(resizerLeft)($scope);
    +                $compile(resizerRight)($scope);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$log', '$document', 'gridUtil', 'uiGridConstants', 'columnBounds', function ($log, $document, gridUtil, uiGridConstants, columnBounds) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0;
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column.index === col.index) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              colDef.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true);
    +            });
    +        }
    +
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = event.clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            x = x + (col.colDef.minWidth - newWidth);
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            x = x + (col.colDef.maxWidth - newWidth);
    +          }
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = event.clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off('mouseup', mouseup);
    +            $document.off('mousemove', mousemove);
    +            return;
    +          }
    +
    +          // The other column to resize (the one next to this one)
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol;
    +          if ($scope.position === 'left') {
    +            // Get the column to the left of this one
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +          }
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = col.drawnWidth + xDiff;
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && newWidth < columnBounds.minWidth) {
    +            newWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          col.colDef.width = newWidth;
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          $document.off('mouseup', mouseup);
    +          $document.off('mousemove', mousemove);
    +        }
    +
    +        $elm.on('mousedown', function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = event.clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on('mouseup', mouseup);
    +          $document.on('mousemove', mousemove);
    +        });
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = $scope.col;
    +          var renderContainer = col.getRenderContainer();
    +
    +          var otherCol, multiplier;
    +
    +          // If we're the left-positioned resizer then we need to resize the column to the left of our column, and not our column itself
    +          if ($scope.position === 'left') {
    +            col = renderContainer.renderedColumns[$scope.renderIndex - 1];
    +            otherCol = $scope.col;
    +            multiplier = 1;
    +          }
    +          else if ($scope.position === 'right') {
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            otherCol = renderContainer.renderedColumns[$scope.renderIndex + 1];
    +            multiplier = -1;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.index + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // $log.debug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // If the new width is less than the minimum width, make it the minimum width
    +          if (col.colDef.minWidth && maxWidth < col.colDef.minWidth) {
    +            maxWidth = col.colDef.minWidth;
    +          }
    +          else if (!col.colDef.minWidth && columnBounds.minWidth && maxWidth < columnBounds.minWidth) {
    +            maxWidth = columnBounds.minWidth;
    +          }
    +          // 
    +          if (col.colDef.maxWidth && maxWidth > col.colDef.maxWidth) {
    +            maxWidth = col.colDef.maxWidth;
    +          }
    +
    +          col.colDef.width = maxWidth;
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off('mousedown');
    +          $elm.off('dblclick');
    +          $document.off('mousemove', mousemove);
    +          $document.off('mouseup', mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$log', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $log, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function (grid, rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be returned
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function (grid) {
    +                  return grid.rowEditDirtyRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which errored rows should be returned
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function (grid) {
    +                  return grid.rowEditErrorRows;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @param {object} grid the grid for which dirty rows should be flushed
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function (grid) {
    +                  return service.flushDirtyRows(grid);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              $log.log( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEditErrorRows, gridRow );
    +            self.removeRow( grid.rowEditDirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEditErrorRows){
    +              grid.rowEditErrorRows = [];
    +            }
    +            grid.rowEditErrorRows.push( gridRow );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEditErrorRows or grid.rowEditDirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEditDirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEditDirtyRows ){
    +              grid.rowEditDirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEditDirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ $log.log( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +            gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['$log', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function ($log, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', '$log', '$parse',
    +      function ($compile, uiGridConstants, $log, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection"
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$log', '$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($log, $q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 */
    +                rowSelectionChanged: function (scope, row) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                toggleRowSelection: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                selectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 */
    +                unSelectRow: function (rowEntity) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, grid.options.multiSelect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    row.isSelected = true;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 */
    +                selectAllVisibleRows: function () {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      row.isSelected = true;
    +                    } else {
    +                      row.isSelected = false;
    +                    }
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 */
    +                clearSelectedRows: function () {
    +                  service.clearSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         */
    +        toggleRowSelection: function (grid, row, multiSelect) {
    +          var selected = row.isSelected;
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid);
    +          }
    +          row.isSelected = !selected;
    +          if (row.isSelected === true) {
    +            grid.selection.lastSelectedRow = row;
    +          }
    +          grid.api.selection.raise.rowSelectionChanged(row);
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              rowToSelect.isSelected = true;
    +              grid.selection.lastSelectedRow = rowToSelect;
    +              grid.api.selection.raise.rowSelectionChanged(rowToSelect);
    +            }
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        clearSelectedRows: function (grid) {
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            row.isSelected = false;
    +            grid.api.selection.raise.rowSelectionChanged(row);
    +          });
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['$log', 'uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function ($log, uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var cellTemplate = 'ui-grid/selectionRowHeader';
    +                var selectionRowHeaderDef = { name: 'selectionRowHeaderCol', displayName: '', width: 30, cellTemplate: cellTemplate};
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$log', '$templateCache', 'uiGridSelectionService',
    +    function ($log, $templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, self.options.multiSelect);
    +
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, self.options.multiSelect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            rowRepeatDiv.attr("ng-class", "{'ui-grid-row-selected': row.isSelected}");
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', '$log', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, $log, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +              $elm.addClass('ui-grid-disable-selection');
    +              registerRowSelectionEvents();
    +            }
    +
    +            function registerRowSelectionEvents() {
    +              $elm.on('click', function (evt) {
    +                if (evt.shiftKey) {
    +                  uiGridSelectionService.shiftSelect($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +
    +                }
    +                else {
    +                  uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, $scope.grid.options.multiSelect);
    +                }
    +                $scope.$apply();
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +
    +})();
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell clearfix\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-top-panel\"><div ui-grid-group-panel ng-show=\"grid.options.showGroupPanel\"></div><div class=\"ui-grid-header ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\" ng-style=\"$index === 0 && colContainer.columnStyle($index)\"></div></div></div><div ui-grid-menu></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-scrollbars=\"grid.options.enableScrollbars\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenu\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationValue() }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-vertical-bar\">&nbsp;</div><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div ng-if=\"grid.options.enableColumnMenu && !col.isRowHeader\" class=\"ui-grid-column-menu-button\" ng-click=\"toggleMenu($event)\"><i class=\"ui-grid-icon-angle-down\">&nbsp;<i></i></i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-click=\"$event.stopPropagation()\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel right\" ng-show=\"!!colFilter.term\">&nbsp;</i> <!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\"><div class=\"ui-grid-menu-inner\" ng-show=\"shown\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" title=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ title }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showFooter\"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"vertical\"></div><div ui-grid-native-scrollbar ng-if=\"enableScrollbars\" type=\"horizontal\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid\" class=\"ui-grid-row\" ng-style=\"containerCtrl.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"{{inputType}}\" ng-class=\"'colt' + col.index\" ui-grid-editor ng-model=\"COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.index\" ui-grid-edit-dropdown ng-model=\"COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left;margin-top: 1px;margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell uiGridExpandableButtonsCell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{'ui-grid-icon-plus-squared':!row.isExpanded, 'ui-grid-icon-minus-squared':row.isExpanded}\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left;margin-top: 2px;margin-bottom: 2px\" ng-style=\"{width: (grid.getViewportWidth())\n" +
    +    "     ,height: grid.options.expandable.expandableRowHeight, 'margin-left': grid.options.rowHeader.rowHeaderWidth}\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{'margin-top': ( grid.options.expandable.expandableRowHeight/2 - 5),\n" +
    +    "            'margin-left':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +}]);
    diff --git a/release/ui-grid-stable.min.css b/release/ui-grid-stable.min.css
    new file mode 100644
    index 000000000..1adf522cf
    --- /dev/null
    +++ b/release/ui-grid-stable.min.css
    @@ -0,0 +1,10 @@
    +.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-top-panel{position:relative;border-bottom:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-header-group-panel .hidden{display:none}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas{position:relative}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell{position:relative;float:left;top:0;bottom:0;background-color:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-inner.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:0.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"].right:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:relative;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-viewport{min-height:20px;position:relative;overflow:hidden}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:0.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#F0F0EE !important;border-bottom:solid 1px #d4d4d4}.ui-grid-native-scrollbar{position:absolute;overflow:scroll}.ui-grid-native-scrollbar.vertical{top:0;right:0;height:100%;overflow-x:hidden;width:17px}.ui-grid-native-scrollbar.horizontal{bottom:0;left:0;width:100%;overflow-y:hidden;height:17px}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-group-panel{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;min-height:30px}.ui-grid-footer-group-panel .hidden{display:none}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-footer-cell:last-child{border-right:0}.ui-grid-footer .ui-grid-vertical-bar{top:0;bottom:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:default}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-scrollbar-horizontal{left:inherit;right:0}.ui-grid[dir=rtl] .ui-grid-native-scrollbar.vertical{left:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child{border-right:1px solid;border-color:#d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
    +.ui-grid-cell-contents:focus{outline:0;background-color:#b3c4c7}
    +div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}
    +
    +.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}
    +.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}
    +.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}
    +.ui-grid-row-selected .ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:0.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-cell{border-bottom:solid 1px #d4d4d4}
    +.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\e800'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/ui-grid-stable.min.js b/release/ui-grid-stable.min.js
    new file mode 100644
    index 000000000..84b4ab8d0
    --- /dev/null
    +++ b/release/ui-grid-stable.min.js
    @@ -0,0 +1,7 @@
    +/*! ui-grid - v3.0.0-rc.3 - 2014-09-25
    +* Copyright (c) 2014 ; License: MIT */
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"]})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$log","$parse","gridUtil","uiGridConstants",function(a,b,c,d,e){var f={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,c,d,f){function g(){var a=b.col.compiledElementFn;a(b,function(a){c.append(a)})}if(f)g();else{var h=b.col.cellTemplate.replace(e.COL_FIELD,"grid.getCellValue(row, col)"),i=a(h)(b);c.append(i)}},post:function(a,b){if(b.addClass(a.col.getColClass(!1)),a.col.cellClass){var c=b;c.addClass(angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass)}}}}};return f}]),function(){angular.module("ui.grid").directive("uiGridColumnMenu",["$log","$timeout","$window","$document","$injector","gridUtil","uiGridConstants","i18nService",function(a,b,c,d,e,f,g,h){var i={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(i,j,k,l){function m(){i.$apply(i.hideMenu),d.off("click",m)}function n(){i.$apply(i.hideMenu)}f.enableAnimations(j),i.grid=l.grid;var o=this;l.columnMenuScope=i,o.shown=i.menuShown=!1,i.asc=g.ASC,i.desc=g.DESC,i.menu=j[0].querySelectorAll(".ui-grid-menu"),i.inner=j[0].querySelectorAll(".ui-grid-menu-inner"),i.sortable=function(){return l.grid.options.enableSorting&&"undefined"!=typeof i.col&&i.col&&i.col.enableSorting?!0:!1},i.filterable=function(){return l.grid.options.enableFiltering&&"undefined"!=typeof i.col&&i.col&&i.col.enableFiltering?!0:!1};var p=[{title:h.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),i.sortColumn(a,g.ASC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.ASC}},{title:h.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),i.sortColumn(a,g.DESC)},shown:function(){return i.sortable()},active:function(){return"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&i.col.sort.direction===g.DESC}},{title:h.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.unsortColumn()},shown:function(){return i.sortable()&&"undefined"!=typeof i.col&&"undefined"!=typeof i.col.sort&&"undefined"!=typeof i.col.sort.direction&&null!==i.col.sort.direction}},{title:h.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),i.hideColumn()}}];i.menuItems=p,i.$watch("col.menuItems",function(a){"undefined"!=typeof a&&a&&angular.isArray(a)?(a.forEach(function(a){"undefined"!=typeof a.context&&a.context||(a.context={}),a.context.col=i.col}),i.menuItems=p.concat(a)):i.menuItems=p});var q;try{q=e.get("$animate")}catch(r){a.info("$animate service not found (ngAnimate not add as a dependency?), menu animations will not occur")}i.showMenu=function(a,c){function e(){b(function(){p&&q?(q.removeClass(i.inner,"ng-hide"),o.shown=i.menuShown=!0,i.$broadcast("show-menu")):angular.element(i.inner).hasClass("ng-hide")&&angular.element(i.inner).removeClass("ng-hide");var b=a.renderContainer?a.renderContainer:"body",e=(a.grid.renderContainers[b],f.closestElm(c,".ui-grid-render-container")),k=e.offsetLeft-i.grid.element[0].offsetLeft,r=e.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,s=f.elementWidth(i.menu,!0),t=parseInt(angular.element(i.menu).css("padding-right"),10);j.css("left",g+k-r+n-s+t+"px"),j.css("top",h+l+"px"),d.on("click",m)})}o.col=i.col=a,d.off("click",m);var g=c[0].offsetLeft,h=c[0].offsetTop,k=0;a.grid.options.offsetLeft&&(k=a.grid.options.offsetLeft);var l=f.elementHeight(c,!0),n=f.elementWidth(c,!0),p=!1;i.menuShown&&q?(q.addClass(i.inner,"ng-hide",e),p=!0):(o.shown=i.menuShown=!0,i.$broadcast("show-menu"),e())},i.hideMenu=function(){delete o.col,delete i.col,o.shown=i.menuShown=!1,i.$broadcast("hide-menu")},angular.element(c).bind("resize",n),i.$on("$destroy",i.$on(g.events.GRID_SCROLL,function(){i.hideMenu()})),i.$on("$destroy",i.$on(g.events.ITEM_DRAGGING,function(){i.hideMenu()})),i.$on("$destroy",function(){angular.element(c).off("resize",n),d.off("click",m)}),i.sortColumn=function(a,b){a.stopPropagation(),l.grid.sortColumn(i.col,b,!0).then(function(){l.grid.refresh(),i.hideMenu()})},i.unsortColumn=function(){i.col.unsort(),l.grid.refresh(),i.hideMenu()},i.hideColumn=function(){i.col.colDef.visible=!1,l.grid.refresh(),i.hideMenu()}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$log","$timeout","gridUtil","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){function e(e){c.getTemplate(e).then(function(c){var e=d(c),f=e(a);b.append(f)})}e(a.col.footerCellTemplate?a.col.footerCellTemplate:"ui-grid/uiGridFooterCell")},post:function(a,b,c,d){a.grid=d.grid,b.addClass(a.col.getColClass(!1))}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=b;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:f;e.getTemplate(j).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),i){var g=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(b,c,d,f){var g=f[0],h=f[1];a.debug("ui-grid-footer link");g.grid;e.disableAnimations(c),h.footer=c;var i=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];i&&(h.footerViewport=i)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$log","$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f,g){var h=500,i={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:"?^uiGrid",replace:!0,compile:function(){return{pre:function(a,c){var d=b(a.col.headerCellTemplate)(a);c.append(d)},post:function(a,b,d,e){function f(b){var c=!1;b.shiftKey&&(c=!0),e.grid.sortColumn(a.col,c).then(function(){e.columnMenuScope&&e.columnMenuScope.hideMenu(),e.grid.refresh()})}a.grid=e.grid,a.grid.api.core.raise.filterChanged||a.grid.api.registerEvent("core","filterChanged"),b.addClass(a.col.getColClass(!1)),a.menuShown=!1,a.asc=g.ASC,a.desc=g.DESC;var i=(angular.element(b[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(b[0].querySelectorAll(".ui-grid-cell-contents")));a.sortable=e.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=e.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1;var j,k=0;if(i.on("mousedown",function(d){"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(k=(new Date).getTime(),j=c(function(){},h),j.then(function(){e.columnMenuScope.showMenu(a.col,b)}))}),i.on("mouseup",function(){c.cancel(j)}),a.toggleMenu=function(c){c.stopPropagation(),e.columnMenuScope.menuShown&&e.columnMenuScope.col===a.col?e.columnMenuScope.hideMenu():e.columnMenuScope.showMenu(a.col,b)},a.sortable&&(i.on("click",function(a){a.stopPropagation(),c.cancel(j);var b=(new Date).getTime(),d=b-k;d>h||f(a)}),a.$on("$destroy",function(){c.cancel(j)})),a.filterable){var l=[];angular.forEach(a.col.filters,function(b,c){l.push(a.$watch("col.filters["+c+"].term",function(){e.grid.api.core.raise.filterChanged(),e.grid.refresh().then(function(){e.prevScrollArgs&&e.prevScrollArgs.y&&e.prevScrollArgs.y.percentage&&e.fireScrollingEvent({y:{percentage:e.prevScrollArgs.y.percentage}})})}))}),a.$on("$destroy",function(){angular.forEach(l,function(a){a()})})}}}}};return i}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$log","$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d,e){var f="ui-grid/ui-grid-header",g="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,b,d,h){var i=h[0],j=h[1];a.grid=i.grid,a.colContainer=j.colContainer,j.header=b,j.colContainer.header=b;var k;k=a.grid.options.hideHeader?g:a.grid.options.headerTemplate?a.grid.options.headerTemplate:f,e.getTemplate(k).then(function(d){var e=angular.element(d),f=c(e)(a);if(b.append(f),j){var g=b[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(j.headerViewport=g)}})},post:function(b,c,d,f){function g(){var a=[],b=[],c=0,d=i.colContainer.getViewportWidth();"undefined"!=typeof h.grid.verticalScrollbarWidth&&void 0!==h.grid.verticalScrollbarWidth&&h.grid.verticalScrollbarWidth>0&&(d+=h.grid.verticalScrollbarWidth);var f,g=0,k=0,l="",m=i.colContainer.visibleColumnCache;m.forEach(function(d){if(d.visible){var f=!1;angular.isNumber(d.width)||(f=isNaN(d.width)?e.endsWith(d.width,"%"):!1),angular.isString(d.width)&&-1!==d.width.indexOf("*")?(c=parseInt(c+d.width.length,10),a.push(d)):f?b.push(d):angular.isNumber(d.width)&&(g=parseInt(g+d.width,10),k=parseInt(k,10)+parseInt(d.width,10),d.drawnWidth=d.width)}});var n,o,p,q=d-g;if(b.length>0){for(n=0;n<b.length;n++){o=b[n];var r=parseInt(o.width.replace(/%/g,""),10)/100;p=parseInt(r*q,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,k+=p,o.drawnWidth=p,b.splice(n,1))}b.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*q,10);k+=c,a.drawnWidth=c})}if(a.length>0){var s=parseInt(q/c,10);for(n=0;n<a.length;n++)o=a[n],p=parseInt(s*o.width.length,10),o.colDef.minWidth&&p<o.colDef.minWidth?(p=o.colDef.minWidth,q-=p,c--,k+=p,o.drawnWidth=p,f=o,a.splice(n,1)):o.colDef.maxWidth&&p>o.colDef.maxWidth&&(p=o.colDef.maxWidth,q-=p,c--,k+=p,o.drawnWidth=p,a.splice(n,1));s=parseInt(q/c,10),a.forEach(function(a){var b=parseInt(s*a.width.length,10);k+=b,a.drawnWidth=b})}var t=d-parseInt(k,10);if(t>0&&k>0&&d>k){var u=!1;if(m.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(u=!0)}),u)for(var v=function(a){t>0&&(a.drawnWidth=a.drawnWidth+1,k+=1,t--)};t>0;)m.forEach(v)}return d>k&&(k=d),m.forEach(function(a){l+=a.getColClassDefinition()}),j.verticalScrollbarWidth&&(k+=j.verticalScrollbarWidth),i.colContainer.canvasWidth=parseInt(k,10),l}var h=f[0],i=f[1];a.debug("ui-grid-header link");var j=h.grid;e.disableAnimations(c),i.header=c;var k=c[0].getElementsByClassName("ui-grid-header-viewport")[0];k&&(i.headerViewport=k),h&&h.grid.registerStyleComputation({priority:5,func:g})}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$log","$compile","$timeout","$window","$document","gridUtil",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,b){f.enableAnimations(b),("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(d).on("resize",a.hideMenu),a.$on("hide-menu",function(){a.shown=!1}),a.$on("show-menu",function(){a.shown=!0}),a.$on("$destroy",function(){angular.element(d).off("resize",a.hideMenu)})},controller:["$scope","$element","$attrs",function(a){function b(){a.$apply(function(){d.hideMenu(),angular.element(document).off("click",b)})}var d=this;d.hideMenu=a.hideMenu=function(){a.shown=!1},d.showMenu=a.showMenu=function(){a.shown=!0,angular.element(document).off("click",b),c(function(){angular.element(document).on("click",b)})},a.$on("$destroy",function(){angular.element(document).off("click",b)})}]};return g}]).directive("uiGridMenuItem",["$log","gridUtil","$compile","i18nService",function(a,b,c,d){var e={priority:0,scope:{title:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(a,d,e,f){f[0],f[1];a.templateUrl&&b.getTemplate(a.templateUrl).then(function(b){var e=angular.element(b),f=c(e)(a);d.replaceWith(f)})},post:function(b,c,e,f){var g=f[0],h=f[1];("undefined"==typeof b.shown||null===b.shown)&&(b.shown=function(){return!0}),b.itemShown=function(){var a={};return b.context&&(a.context=b.context),"undefined"!=typeof g&&g&&(a.grid=g.grid),b.shown.call(a)},b.itemAction=function(c,d){if(a.debug("itemAction"),c.stopPropagation(),"function"==typeof b.action){var e={};b.context&&(e.context=b.context),"undefined"!=typeof g&&g&&(e.grid=g.grid),b.action.call(e,c,d),h.hideMenu()}},b.i18n=d.get()}}}};return e}])}(),function(){angular.module("ui.grid").directive("uiGridNativeScrollbar",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){var f=e.getScrollbarWidth();f=f>0?f:17;var g=e.detectBrowser();return"ie"===g&&(f+=1),{scope:{type:"@"},require:["^uiGrid","^uiGridRenderContainer"],link:function(a,b,c,g){function h(){var a=n.getViewportHeight(),b=n.getCanvasHeight(),c=o.headerHeight?o.headerHeight:p.headerHeight,d=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical .contents { height: "+b+"px; }";return d+="\n .grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.vertical { height: "+a+"px; top: "+c+"px}",s=b,d}function i(){var a=o.getCanvasWidth(),b=-1*f+u;p.options.showFooter&&(b-=1);var c=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal { bottom: "+b+"px; }";return c+=".grid"+p.id+" .ui-grid-render-container-"+m.containerId+" .ui-grid-native-scrollbar.horizontal .contents { width: "+a+"px; }",s=a,c}function j(){if("vertical"===a.type){p.flagScrollingVertically();var c=b[0].scrollTop,d=n.getCanvasHeight()-n.getViewportHeight();p.horizontalScrollbarHeight&&p.horizontalScrollbarHeight>0&&(d-=l.grid.horizontalScrollbarHeight);var f=c/d;f>1&&(f=1),0>f&&(f=0);var g={target:b,y:{percentage:f}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(g),r=c}else if("horizontal"===a.type){p.flagScrollingHorizontally();var h=e.normalizeScrollLeft(b),i=o.getCanvasWidth()-o.getViewportWidth(),j=h/i,k={target:b,x:{percentage:j}};a.scrollSource?a.scrollSource=null:l.fireScrollingEvent(k),r=h}}function k(c,d){if(!d.target||d.target!==b&&!angular.element(d.target).hasClass("ui-grid-native-scrollbar"))if(a.scrollSource=d.target,"vertical"===a.type){if(d.y&&"undefined"!=typeof d.y.percentage&&void 0!==d.y.percentage){p.flagScrollingVertically();var f=n.getCanvasHeight()-n.getViewportHeight(),g=Math.max(0,d.y.percentage*f);b[0].scrollTop=g}}else if("horizontal"===a.type&&d.x&&"undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage){p.flagScrollingHorizontally();var h=o.getCanvasWidth()-o.getViewportWidth(),i=Math.max(0,d.x.percentage*h);b[0].scrollLeft=e.denormalizeScrollLeft(b,i)}}var l=g[0],m=g[1],n=m.rowContainer,o=m.colContainer,p=l.grid,q=angular.element('<div class="contents">&nbsp;</div>');b.addClass("ui-grid-native-scrollbar");var r,s=0;"vertical"===a.type?(b.css("width",f+"px"),b.addClass("vertical"),p.verticalScrollbarWidth=f,o.verticalScrollbarWidth=f,r=b[0].scrollTop):"horizontal"===a.type&&(b.css("height",f+"px"),b.addClass("horizontal"),p.horizontalScrollbarHeight=f,n.horizontalScrollbarHeight=f,r=e.normalizeScrollLeft(b)),b.append(q),"vertical"===a.type?s=e.elementHeight(b):"horizontal"===a.type&&(s=e.elementWidth(b));var t=e.closestElm(b,".ui-grid"),u=e.getBorderSize(t,"bottom");"vertical"===a.type?p.registerStyleComputation({priority:6,func:h}):"horizontal"===a.type&&p.registerStyleComputation({priority:6,func:i}),a.scrollSource=null,b.on("scroll",j),b.on("$destroy",function(){b.off("scroll")});var v=a.$on(d.events.GRID_SCROLL,k);a.$on("$destroy",v)}}}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$log","$timeout","$document","uiGridConstants","gridUtil",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableScrollbars:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(b,c,d,e){a.debug("render container "+b.containerId+" pre-link");var f=e[0],g=e[1],h=b.grid=f.grid;if(!b.rowContainerName)throw"No row render container name specified";if(!b.colContainerName)throw"No column render container name specified";if(!h.renderContainers[b.rowContainerName])throw"Row render container '"+b.rowContainerName+"' is not registered.";if(!h.renderContainers[b.colContainerName])throw"Column render container '"+b.colContainerName+"' is not registered.";var i=b.rowContainer=h.renderContainers[b.rowContainerName],j=b.colContainer=h.renderContainers[b.colContainerName];g.containerId=b.containerId,g.rowContainer=i,g.colContainer=j},post:function(b,f,g,h){function i(a,c){if(c.y&&b.bindScrollVertical){n.prevScrollArgs=c;var d=p.getCanvasHeight()-p.getViewportHeight();o.horizontalScrollbarHeight&&o.horizontalScrollbarHeight>0&&(d+=o.horizontalScrollbarHeight);var f,g=n.viewport[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)f=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");f=c.y.percentage=(g+c.y.pixels)/d}var h=Math.max(0,f*d);n.viewport[0].scrollTop=h,n.prevScrollArgs.y.pixels=h-g}if(c.x&&b.bindScrollHorizontal){n.prevScrollArgs=c;var i,j=q.getCanvasWidth()-q.getViewportWidth(),k=e.normalizeScrollLeft(n.viewport);if("undefined"!=typeof c.x.percentage&&void 0!==c.x.percentage)i=c.x.percentage;else{if("undefined"==typeof c.x.pixels||void 0===c.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");i=c.x.percentage=(k+c.x.pixels)/j}var l=Math.max(0,i*j);n.viewport[0].scrollLeft=e.denormalizeScrollLeft(n.viewport,l),n.prevScrollLeft=l,n.headerViewport&&(n.headerViewport.scrollLeft=e.denormalizeScrollLeft(n.headerViewport,l)),n.footerViewport&&(n.footerViewport.scrollLeft=e.denormalizeScrollLeft(n.footerViewport,l)),n.prevScrollArgs.x.pixels=l-k}}function j(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault();var b,c,d,e;d=a.targetTouches[0].screenX,e=a.targetTouches[0].screenY,b=-(d-u),c=-(e-t),x=1>c?-1:1,y=1>b?-1:1,c*=2,b*=2;var f={target:a.target};if(0!==c){var g=(v+c)/(p.getCanvasHeight()-p.getViewportHeight());g>1?g=1:0>g&&(g=0),f.y={percentage:g,pixels:c}}if(0!==b){var h=(w+b)/(q.getCanvasWidth()-q.getViewportWidth());h>1?h=1:0>h&&(h=0),f.x={percentage:h,pixels:b}}m.fireScrollingEvent(f)}function k(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),c.unbind("touchmove",j),c.unbind("touchend",k),c.unbind("touchcancel",k);{var b=n.viewport[0].scrollTop,d=n.viewport[0].scrollTop;Math.abs(b-v),Math.abs(d-w),new Date-s}}function l(){var a="",c=q.getCanvasWidth(),d=q.getViewportWidth(),e=p.getCanvasHeight(),f=p.getViewportHeight(),g=q.getHeaderViewportWidth(),h=q.getHeaderViewportWidth();return a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-canvas { width: "+c+"px; }",a+="\n .grid"+m.grid.id+" .ui-grid-render-container-"+b.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}a.debug("render container "+b.containerId+" post-link");var m=h[0],n=h[1],o=m.grid,p=n.rowContainer,q=n.colContainer;f.addClass("ui-grid-render-container-"+b.containerId);var r;(b.bindScrollHorizontal||b.bindScrollVertical)&&(r=b.$on(d.events.GRID_SCROLL,i)),f.bind("wheel mousewheel DomMouseScroll MozMousePixelScroll",function(a){a.preventDefault();var b=e.normalizeWheelEvent(a),c={target:f};if(0!==b.deltaY){var d=-120*b.deltaY,g=(n.viewport[0].scrollTop+d)/(p.getCanvasHeight()-p.getViewportHeight());0>g?g=0:g>1&&(g=1),c.y={percentage:g,pixels:d}}if(0!==b.deltaX){var h=-120*b.deltaX,i=e.normalizeScrollLeft(n.viewport),j=(i+h)/(q.getCanvasWidth()-q.getViewportWidth());0>j?j=0:j>1&&(j=1),c.x={percentage:j,pixels:h}}m.fireScrollingEvent(c)});var s,t=0,u=0,v=0,w=0,x=1,y=1;e.isTouchEnabled()&&f.bind("touchstart",function(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),m.scrollbars.forEach(function(a){a.addClass("ui-grid-scrollbar-visible"),a.addClass("ui-grid-scrolling")}),s=new Date,t=a.targetTouches[0].screenY,u=a.targetTouches[0].screenX,v=n.viewport[0].scrollTop,w=n.viewport[0].scrollLeft,c.on("touchmove",j),c.on("touchend touchcancel",k)}),f.bind("$destroy",function(){r(),f.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){f.unbind(a)})}),m.grid.registerStyleComputation({priority:6,func:l})}}}}}]),a.controller("uiGridRenderContainer",["$scope","$log",function(a){var b=this;b.rowStyle=function(c){var d=a.grid.renderContainers[a.containerId],e={};if(!d.disableRowOffset&&0===c&&0!==b.currentTopRow){var f=a.rowContainer.currentTopRow*a.rowContainer.visibleRowCache[a.rowContainer.currentTopRow].height;e["margin-top"]=f+"px"}return d.disableColumnOffset||0===a.colContainer.currentFirstColumn||(a.grid.isRTL()?e["margin-right"]=a.colContainer.columnOffset+"px":e["margin-left"]=a.colContainer.columnOffset+"px"),e},b.columnStyle=function(b){var c=a.grid.renderContainers[a.containerId];if(!c.disableColumnOffset&&0===b&&0!==a.colContainer.currentFirstColumn){var d=a.colContainer.columnOffset;return a.grid.isRTL()?{"margin-right":d+"px"}:{"margin-left":d+"px"}}return null}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["$log",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=e.grid;a.grid=e.grid,a.colContainer=f.colContainer,g.getRowTemplateFn.then(function(c){c(a,function(a){b.replaceWith(a)})})},post:function(a,b,c,d){{var e=d[0];d[1]}a.getExternalScopes=e.getExternalScopes}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["$log","$interpolate",function(a,b){return{link:function(c,d){a.debug("ui-grid-style link");var e=b(d.text(),!0);e&&c.$watch(e,function(a){d.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["$log","gridUtil",function(a,b){return{replace:!0,scope:{},templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(c,d,e,f){a.debug("viewport post-link");var g=f[0],h=f[1];c.containerCtrl=h;{var i=h.rowContainer,j=h.colContainer;g.grid}c.grid=g.grid,c.rowContainer=h.rowContainer,c.colContainer=h.colContainer,h.viewport=d,d.on("scroll",function(){var a=d[0].scrollTop,c=b.normalizeScrollLeft(d);if(c!==j.prevScrollLeft){var e=(c-j.prevScrollLeft,j.getCanvasWidth()-j.getViewportWidth()),f=c/e;j.adjustScrollHorizontal(c,f)}if(a!==i.prevScrollTop){var g=(a-i.prevScrollTop,i.getCanvasHeight()-i.getViewportHeight()),h=a/g;h>1&&(h=1),0>h&&(h=0),i.adjustScrollVertical(a,h)}})}}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","$log","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)}))}function n(b){var e=[];b&&(0===o.grid.columns.length&&(d.debug("loading cols in dataWatchFunction"),c.uiGridColumns||0!==o.grid.options.columnDefs.length||o.grid.buildColumnDefsFromData(b),e.push(o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates()}))),f.all(e).then(function(){o.grid.modifyRows(b).then(function(){o.grid.redrawInPlace(),a.$evalAsync(function(){o.grid.refreshCanvas(!0)})})}))}d.debug("ui-grid controller");var o=this;o.grid=i.createGrid(a.uiGrid),b.addClass("grid"+o.grid.id),o.grid.rtl="rtl"===b.css("direction"),o.getExternalScopes=a.getExternalScopes,a.grid=o.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){o.grid.options.columnDefs=a,o.grid.buildColumns().then(function(){o.grid.preCompileCellTemplates(),o.grid.refreshCanvas(!0)})});var p;p=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,n):a.$parent.$watchCollection(function(){return a.uiGrid.data},n);var q=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m);a.$on("$destroy",function(){p(),q()}),a.$watch(function(){return o.grid.styleComputations},function(){o.grid.refreshCanvas(!0)}),o.fireScrollingEvent=function(b){a.$broadcast(g.events.GRID_SCROLL,b)},o.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=o.grid),a.$broadcast(b,c)},o.innerCompile=function(b){l(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$log","$compile","$templateCache","gridUtil","$window",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"=",getExternalScopes:"&?externalScopes"},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(b,c,f,g){function h(){i.gridWidth=b.gridWidth=d.elementWidth(c),i.gridHeight=b.gridHeight=d.elementHeight(c),i.queueRefresh()}a.debug("ui-grid postlink");var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=c,i.gridWidth=b.gridWidth=d.elementWidth(c),i.canvasWidth=g.grid.gridWidth,i.gridHeight=b.gridHeight=d.elementHeight(c),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight;c.css("height",j+"px"),i.gridHeight=b.gridHeight=d.elementHeight(c)}i.refreshCanvas();var k=angular.element('<div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div>');c.prepend(k),g.innerCompile(k);var l=angular.element('<div  ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div>');c.append(l),g.innerCompile(l),b.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),b.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(e).on("resize",h),c.on("$destroy",function(){angular.element(e).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["$log",function(a){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(b,c,d,e){function f(){var a="";if("left"===b.side||"right"===b.side){for(var d=g.renderContainers[b.side].visibleColumnCache,e=0,f=0;f<d.length;f++){var i=d[f];e+=i.drawnWidth}h=e,c.attr("style",null);var j=g.renderContainers.body.getViewportHeight();a+=".grid"+g.id+" .ui-grid-pinned-container-"+b.side+", .grid"+g.id+" .ui-grid-pinned-container-"+b.side+" .ui-grid-render-container-"+b.side+" .ui-grid-viewport { width: "+h+"px; height: "+j+"px; } "}return a}a.debug("ui-grid-pinned-container "+b.side+" link");var g=e.grid,h=0;c.addClass("ui-grid-pinned-container-"+b.side),g.renderContainers.body.registerViewportAdjuster(function(a){return a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$log","$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(){}var p=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=new g,angular.extend(b.options,a),b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.options.showFooter===!0?b.options.footerRowHeight:0,b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.renderContainers={},b.renderContainers.body=new m("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1;var c=e.debounce(function(){b.isScrollingVertically=!1},300),d=e.debounce(function(){b.isScrollingHorizontally=!1},300);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,d()},b.api=new j(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerEvent("core","sortChanged")};return p.prototype.isRTL=function(){return this.rtl},p.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},p.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=e.getColumnsFromData(a,this.options.excludeProperties)},p.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},p.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a
    +});return b.length>0?b[0]:null},p.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},p.prototype.assignTypes=function(){var b=this;b.options.columnDefs.forEach(function(c,d){if(!c.type){var f=new h(c,d,b),g=b.rows.length>0?b.rows[0]:null;g?c.type=e.guessType(b.getCellValue(g,f)):(a.log("Unable to assign type from data, so defaulting to string"),c.type="string")}})},p.prototype.addRowHeaderColumn=function(a){var b=this,c=new h(a,b.rowHeaderColumns.length+1,b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.gridOptions).then(function(){c.enableFiltering=!1,c.enableSorting=!1,b.rowHeaderColumns.push(c)})},p.prototype.buildColumns=function(){a.debug("buildColumns");var c=this,d=[],e=c.rowHeaderColumns.length;return angular.forEach(c.rowHeaderColumns,function(a){e++,c.columns.push(a)}),c.columns.length>c.options.columnDefs.length&&c.columns.forEach(function(a,b){c.getColDef(a.name)||c.columns.splice(b,1)}),c.options.columnDefs.forEach(function(a,b){c.preprocessColDef(a);var f=c.getColumn(a.name);f?f.updateColumnDef(a,f.index):(f=new h(a,b+e,c),c.columns.push(f)),c.columnBuilders.forEach(function(b){d.push(b.call(c,a,f,c.options))})}),b.all(d)},p.prototype.preCompileCellTemplates=function(){this.columns.forEach(function(a){var b=a.cellTemplate.replace(f.COL_FIELD,"grid.getCellValue(row, col)"),d=c(b);a.compiledElementFn=d})},p.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new m("left",this,{disableColumnOffset:!0}))},p.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new m("right",this,{disableColumnOffset:!0}))},p.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},p.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},p.prototype.preprocessColDef=function(a){if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");void 0===a.name&&void 0!==a.field&&(a.name=a.field)},p.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},p.prototype.getRow=function(a){var b=this.rows.filter(function(b){return b.entity===a});return b.length>0?b[0]:null},p.prototype.modifyRows=function(a){var c,d,e=this;if(0===e.rows.length&&a.length>0){if(e.options.enableRowHashing)for(e.rowHashMap||e.createRowHashMap(),c=0;c<a.length;c++)d=a[c],e.rowHashMap.put(d,{i:c,entity:d});e.addRows(a),e.assignTypes()}else if(a.length>0){var f,g,h;if(e.options.enableRowHashing){f=[],h=[];var i={};g=[],e.rowHashMap||e.createRowHashMap();var j=e.rowHashMap;for(c=0;c<a.length;c++){d=a[c];var k=!1;e.options.getRowIdentity(d)||(k=!0);var l=j.get(d);l?l.row&&(i[e.options.rowIdentity(d)]=!0):(j.put(d,{i:c,entity:d}),k?h.push(d):f.push(d))}for(c=0;c<e.rows.length;c++){var m=e.rows[c],n=e.options.rowIdentity(m.entity);i[n]||g.push(m)}}var o=f||[],p=h||a;o=o.concat(e.newInN(e.rows,p,"entity")),e.addRows(o);var q=e.getDeletedRows(g||e.rows,a);for(c=0;c<q.length;c++)e.options.enableRowHashing&&e.rowHashMap.remove(q[c].entity),e.rows.splice(e.rows.indexOf(q[c]),1)}else e.createRowHashMap(),e.rows.length=0;var r=b.when(e.processRowsProcessors(e.rows)).then(function(a){return e.setVisibleRows(a)}),s=b.when(e.processColumnsProcessors(e.columns)).then(function(a){return e.setVisibleColumns(a)});return b.all([r,s])},p.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},p.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new i(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},p.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.gridOptions)}),a},p.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},p.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},p.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},p.prototype.processRowsProcessors=function(a){function c(a,e){var g=d.rowsProcessors[a];return b.when(g.call(d,e,d.columns)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.rowsProcessors.length-1?c(a,b):void f.resolve(b)})}var d=this,e=a.slice(0);if(0===d.rowsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}},p.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},p.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},p.prototype.processColumnsProcessors=function(a){function c(a,g){var h=d.columnsProcessors[a];return b.when(h.call(d,g,d.rows)).then(function(b){if(!b)throw"Processor at index "+a+" did not return a set of renderable rows";if(!angular.isArray(b))throw"Processor at index "+a+" did not return an array";return a++,a<=d.columnsProcessors.length-1?c(a,e):void f.resolve(e)})}var d=this,e=a.slice(0);if(0===d.columnsProcessors.length)return b.when(e);var f=b.defer();return c(0,e),f.promise},p.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},p.prototype.handleWindowResize=function(){var a=this;a.gridWidth=e.elementWidth(a.element),a.gridHeight=e.elementHeight(a.element),a.queueRefresh()},p.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&n.cancel(a.refreshCanceller),a.refreshCanceller=n(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},p.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},p.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},p.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(a+=this.horizontalScrollbarHeight),a},p.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight;"undefined"!=typeof this.horizontalScrollbarHeight&&void 0!==this.horizontalScrollbarHeight&&this.horizontalScrollbarHeight>0&&(b-=this.horizontalScrollbarHeight);var c=a.getViewportAdjustment();return b+=c.height},p.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth;"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(b-=this.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},p.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return"undefined"!=typeof this.verticalScrollbarWidth&&void 0!==this.verticalScrollbarWidth&&this.verticalScrollbarWidth>0&&(a+=this.verticalScrollbarWidth),a},p.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},p.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},p.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},p.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},p.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},p.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},p.prototype.searchRows=function(a){return l.search(this,a,this.columns)},p.prototype.sortByColumn=function(a){return k.sort(this,a,this.columns)},p.prototype.getCellValue=function(a,b){var c=this;return c.cellValueGetterCache[b.colDef.name]||(c.cellValueGetterCache[b.colDef.name]=d(a.getEntityQualifiedColField(b))),c.cellValueGetterCache[b.colDef.name](a)},p.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},p.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b!==a&&(b.sort={})})},p.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(k.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===f.ASC||a.sort.direction===f.DESC)&&c.push(a)}),c},p.prototype.sortColumn=function(a,c,d){var e=this,g=null;if("undefined"==typeof a||!a)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?a.sort.priority=e.getNextColumnSortPriority():(e.resetColumnSorting(a),a.sort.priority=0),a.sort.direction=g?g:a.sort.direction&&a.sort.direction===f.ASC?f.DESC:a.sort.direction&&a.sort.direction===f.DESC?null:f.ASC,e.api.core.raise.sortChanged(e,e.getColumnSorting()),b.when(a)},p.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},p.prototype.createRowHashMap=function(){var a=this,b=new o;b.grid=a,a.rowHashMap=b},p.prototype.refresh=function(){a.debug("grid refresh");var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return b.all([d,e]).then(function(){c.redrawInPlace(),c.refreshCanvas(!0)})},p.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawRows(),a.refreshCanvas()})},p.prototype.refreshCanvas=function(a){var c=this;a&&c.buildStyles();var d=b.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];h.header&&f.push(h)}return n(f.length>0?function(){for(var b=!1,g=0;g<f.length;g++){var h=f[g];if(h.header){var i=h.headerHeight,j=e.outerElementHeight(h.header);h.headerHeight=j,i!==j&&(b=!0)}}a&&b&&c.buildStyles(),d.resolve()}:function(){d.resolve()}),d.promise},p.prototype.redrawInPlace=function(){var a=this;for(var b in a.renderContainers){var c=a.renderContainers[b];c.adjustRows(c.prevScrollTop,null),c.adjustColumns(c.prevScrollLeft,null)}},o.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},p}])}(),function(){angular.module("ui.grid").factory("GridApi",["$log","$q","$rootScope","gridUtil","uiGridConstants",function(a,b,c,d){function e(a,b,c,d){return a.$on(b,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(d.api,a)})}var f=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete")};return f.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],f=[];d.forEach(function(a){f=c.listeners.filter(function(b){return a===b.handler})}),f.forEach(function(a){a.dereg()}),b(),f.forEach(function(a){a.dereg=e(a.scope,a.eventId,a.handler,c.grid)})},f.prototype.registerEvent=function(b,d){var f=this;f[b]||(f[b]={});var g=f[b];g.on||(g.on={},g.raise={});var h=f.grid.id+b+d;a.log("Creating raise event method "+b+".raise."+d),g.raise[d]=function(){c.$broadcast.apply(c,[h].concat(Array.prototype.slice.call(arguments)))},a.log("Creating on event method "+b+".on."+d),g.on[d]=function(a,b){var c=e(a,h,b,f.grid),d={handler:b,dereg:c,eventId:h,scope:a};f.listeners.push(d),a.$on("$destroy",function(){d.dereg=null,d.handler=null,d.eventId=null,d.scope=null})}},f.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},f.prototype.registerMethod=function(a,b,c,e){this[a]||(this[a]={});var f=this[a];f[b]=d.createBoundedWrapper(e||this.grid,c)},f.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},f}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.grid=c,a.index=b,d.updateColumnDef(a)}return c.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},c.prototype.updateColumnDef=function(b,d){var e=this;if(e.colDef=b,e.index="undefined"==typeof d?b.index:d,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.index);var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else if(!b.width.match(/^\*+$/))throw new Error(f);c.prototype.unsort=function(){this.sort={}},e.minWidth=b.minWidth?b.minWidth:50,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.cellClass=b.cellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.visible=!0,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)},c.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.index;return a?"."+c:c},c.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { width: "+this.drawnWidth+"px; }"},c.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},c.prototype.showColumn=function(){this.colDef.visible=!0},c.prototype.hideColumn=function(){this.colDef.visible=!1},c.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=[];return angular.forEach(d,function(b){var c=a.grid.getCellValue(b,a);angular.isNumber(c)&&e.push(c)}),angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?"total rows: "+a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e,function(a){c+=a}),"total: "+c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e,function(a){c+=a}),c/=e.length,"avg: "+c):a.aggregationType===b.aggregationTypes.min?"min: "+Math.min.apply(null,e):a.aggregationType===b.aggregationTypes.max?"max: "+Math.max.apply(null,e):null},c}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil",function(a){function b(){this.onRegisterApi=angular.noop(),this.data=[],this.columnDefs=[],this.excludeProperties=["$$hashKey"],this.enableRowHashing=!0,this.rowIdentity=function(b){return a.hashKey(b)},this.getRowIdentity=function(a){return a.$$hashKey},this.headerRowHeight=30,this.rowHeight=30,this.maxVisibleRowCount=200,this.minRowsToShow=10,this.showFooter=!1,this.footerRowHeight=30,this.columnWidth=50,this.maxVisibleColumnCount=200,this.virtualizationThreshold=20,this.columnVirtualizationThreshold=10,this.excessRows=4,this.scrollThreshold=4,this.excessColumns=4,this.horizontalScrollThreshold=2,this.enableSorting=!0,this.enableFiltering=!1,this.enableColumnMenu=!0,this.enableScrollbars=!0,this.minimumColumnSize=10,this.rowEquality=function(a,b){return a===b},this.headerTemplate=null,this.footerTemplate=null,this.rowTemplate="ui-grid/ui-grid-row"}return b}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["$log","gridUtil",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight;"undefined"!=typeof a.horizontalScrollbarHeight&&void 0!==a.horizontalScrollbarHeight&&a.horizontalScrollbarHeight>0&&(c-=a.horizontalScrollbarHeight);var d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth;"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b-=a.grid.verticalScrollbarWidth);var c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this,b=this.getViewportWidth();return"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(b+=a.grid.verticalScrollbarWidth),b},c.prototype.getCanvasHeight=function(){var a=this,b=0;return a.visibleRowCache.forEach(function(a){b+=a.height}),"undefined"!=typeof a.grid.horizontalScrollbarHeight&&void 0!==a.grid.horizontalScrollbarHeight&&a.grid.horizontalScrollbarHeight>0&&(b-=a.grid.horizontalScrollbarHeight),b},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return"undefined"!=typeof a.verticalScrollbarWidth&&void 0!==a.verticalScrollbarWidth&&a.verticalScrollbarWidth>0&&(b-=a.verticalScrollbarWidth),b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(a=this.getCanvasHeight()*b,this.adjustRows(a,b),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(a=this.getCanvasWidth()*b,this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())},c.prototype.adjustRows=function(a,b){var c=this,d=c.minRowsToRender(),e=c.visibleRowCache,f=e.length-d;c.maxRowIndex=f;c.prevRowScrollIndex;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasHeight());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.virtualizationThreshold){if(c.prevScrollTop<a&&g<c.prevRowScrollIndex+c.grid.options.scrollThreshold&&f>g)return;if(c.prevScrollTop>a&&g>c.prevRowScrollIndex-c.grid.options.scrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessRows),j=Math.min(e.length,g+d+c.grid.options.excessRows);h=[i,j]}else{var k=c.visibleRowCache.length;h=[0,Math.max(k,d+c.grid.options.excessRows)]}c.updateViewableRowRange(h),c.prevRowScrollIndex=g},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){if(c.prevScrollLeft<a&&g<c.prevColumnScrollIndex+c.grid.options.horizontalScrollThreshold&&f>g)return;if(c.prevScrollLeft>a&&g>c.prevColumnScrollIndex-c.grid.options.horizontalScrollThreshold&&f>g)return;var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.rowStyle=function(a){var b=this,c={};if(0===a&&0!==b.currentTopRow){var d=b.currentTopRow*b.grid.options.rowHeight;c["margin-top"]=d+"px"}return 0!==b.currentFirstColumn&&(b.grid.isRTL()?c["margin-right"]=b.columnOffset+"px":c["margin-left"]=b.columnOffset+"px"),c},c.prototype.columnStyle=function(a){var b=this;if(0===a&&0!==b.currentFirstColumn){var c=b.columnOffset;return b.grid.isRTL()?{"margin-right":c+"px"}:{"margin-left":c+"px"}}return null},c.prototype.updateColumnWidths=function(){var a=this,c=[],d=[],e=0,f=a.getViewportWidth();"undefined"!=typeof a.grid.verticalScrollbarWidth&&void 0!==a.grid.verticalScrollbarWidth&&a.grid.verticalScrollbarWidth>0&&(f+=a.grid.verticalScrollbarWidth);var g,h=0,i=0,j="",k=a.visibleColumnCache;k.forEach(function(a){if(a.visible){var f=!1;angular.isNumber(a.width)||(f=isNaN(a.width)?b.endsWith(a.width,"%"):!1),angular.isString(a.width)&&-1!==a.width.indexOf("*")?(e=parseInt(e+a.width.length,10),c.push(a)):f?d.push(a):angular.isNumber(a.width)&&(h=parseInt(h+a.width,10),i=parseInt(i,10)+parseInt(a.width,10),a.drawnWidth=a.width)}});var l,m,n,o=f-h;if(d.length>0){for(l=0;l<d.length;l++){m=d[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,d.splice(l,1))}d.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(c.length>0){var q=parseInt(o/e,10);for(l=0;l<c.length;l++)m=c[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,e--,i+=n,m.drawnWidth=n,g=m,c.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,e--,i+=n,m.drawnWidth=n,c.splice(l,1));q=parseInt(o/e,10),c.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=f-parseInt(i,10);if(r>0&&i>0&&f>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}f>i&&(i=f),k.forEach(function(a){j+=a.getColClassDefinition()}),a.grid.verticalScrollbarWidth&&(i+=a.grid.verticalScrollbarWidth),a.canvasWidth=parseInt(i,10),this.columnStyles=j},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.index=c,this.uid=a.nextUid(),this.visible=!0,this.height=d.options.rowHeight,this.grid.api.core.setRowInvisible||this.grid.api.registerMethod("core","setRowInvisible",this.setRowInvisible),this.grid.api.core.clearRowInvisible||this.grid.api.registerMethod("core","clearRowInvisible",this.clearRowInvisible),this.grid.api.core.getVisibleRows||this.grid.api.registerMethod("core","getVisibleRows",this.getVisibleRows),this.grid.api.core.raise.rowsVisibleChanged||this.grid.api.registerEvent("core","rowsVisibleChanged")}return b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.getVisibleRows=function(a){return a.rows.filter(function(a){return a.visible})},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","$log","Grid","GridColumn","GridRow",function(a,b,c,d,e,f,g){var h={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new g(d);if(e.options.rowTemplate){var f=b.defer();e.getRowTemplateFn=f.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(h.defaultColumnBuilder),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return c.headerCellTemplate||(c.headerCellTemplate="ui-grid/uiGridHeaderCell"),c.cellTemplate||(c.cellTemplate="ui-grid/uiGridCell"),f.push(a.getTemplate(c.cellTemplate).then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(c.headerCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),b.all(f)}};return h}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function b(){var a=function(b,c){return b&&a.cache[b]?a.cache[b]:b&&c?(a.cache[b]=c,a.cache[b]):void 0};return a.cache={},a.clear=function(){a.cache={}},a}var c=angular.module("ui.grid");c.service("rowSearcher",["$log","uiGridConstants",function(c,d){var e=d.filter.STARTS_WITH,f={};return f.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},f.stripTerm=function(b){var c=f.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},f.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return e;var b=f.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var d=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+d+"$",c)}return e},f.runColumnFilter=function(a,b,c,e,g,h){var i=typeof h.condition;"undefined"!==i&&h.condition||(h.condition=d.filter.CONTAINS);var j=f.stripTerm(h);if(null===j||void 0===j||""===j)return!0;var k=a.getCellValue(b,c),l="";h.flags&&h.flags.caseSensitive||(l+="i");var m=c.field+g;if(h.condition instanceof RegExp){if(!h.condition.test(k))return!1}else{if("function"===i)return h.condition(j,k,b,c);if(h.condition===d.filter.STARTS_WITH){var n=e(m)?e(m):e(m,new RegExp("^"+j,l));if(!n.test(k))return!1}else if(h.condition===d.filter.ENDS_WITH){var o=e(m)?e(m):e(m,new RegExp(j+"$",l));if(!o.test(k))return!1}else if(h.condition===d.filter.CONTAINS){var p=e(m)?e(m):e(m,new RegExp(j,l));if(!p.test(k))return!1}else if(h.condition===d.filter.EXACT){var q=e(m)?e(m):e(m,new RegExp("^"+j+"$",l));if(!q.test(k))return!1}else if(h.condition===d.filter.GREATER_THAN){if(j>=k)return!1}else if(h.condition===d.filter.GREATER_THAN_OR_EQUAL){if(j>k)return!1}else if(h.condition===d.filter.LESS_THAN){if(k>=j)return!1}else if(h.condition===d.filter.LESS_THAN_OR_EQUAL){if(k>j)return!1}else if(h.condition===d.filter.NOT_EQUAL&&!angular.equals(k,j))return!1}return!0},f.searchColumn=function(a,b,c,d){var e=[];if(a.options.useExternalFiltering)return!0;if(!("undefined"!=typeof c.filters&&c.filters&&c.filters.length>0))return!0;e=c.filters;for(var g in e){var h=e[g];if(!h.condition){var i="cond-"+c.field+"-"+h.term,j=d(i)?d(i):d(i,f.guessCondition(h));h={term:h.term,condition:j,flags:angular.extend({caseSensitive:!1},h.flags)}}var k=f.runColumnFilter(a,b,c,d,g,h);if(!k)return!1}return!0},f.search=function(a,c,d){if(c){var e=new b,g=[];return d.forEach(function(a){"undefined"!=typeof a.filters&&a.filters.length>0?g.push(a):"undefined"!=typeof a.filter&&a.filter&&"undefined"!=typeof a.filter.term&&a.filter.term&&g.push(a)}),g.length>0&&(g.forEach(function(b){c.forEach(function(c){(c.forceInvisible||!f.searchColumn(a,c,b,e))&&(c.visible=!1)})}),a.api.core.raise.rowsVisibleChanged()),e.clear(),c
    +}},f}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.basicSort=function(a,b){return a===b?0:b>a?-1:1},d.sortNumber=function(a,b){return a-b},d.sortNumberStr=function(a,b){var c,d,e=!1,f=!1;return c=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(c)&&(e=!0),d=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(d)&&(f=!0),e&&f?0:e?1:f?-1:c-d},d.sortAlpha=function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c===d?0:d>c?-1:1},d.sortDate=function(a,b){var c=a.getTime(),d=b.getTime();return c===d?0:d>c?-1:1},d.sortBool=function(a,b){return a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority?-1:b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);return c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);!m&&0!==m||!n&&0!==n?n||m?m?n||(k=-1):k=1:k=0:k=j(m,n),l++}return h===b.ASC?k:0-k})}},d}])}(),function(){function a(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,f){var g=!0,h="width"===d?c.offsetWidth:c.offsetHeight,i=a(c),j="border-box"===i.boxSizing;if(0>=h||null==h){if(h=i[d],(0>h||null==h)&&(h=c.style[d]),e.test(h))return h;g=j&&!0,h=parseFloat(h)||0}var k=h+b(c,d,f||(j?"border":"content"),g,i);return k}var d=angular.module("ui.grid"),e=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),f=/^(block|none|table(?!-c[ea]).+)/,g={position:"absolute",visibility:"hidden",display:"block"},h=["0","0","0"],i="uiGrid-";d.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","uiGridConstants",function(b,d,e,j,k,l,m,n,o){var p={createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(k.get(a))return n.when(k.get(a));if(a.hasOwnProperty("then"))return a;try{if(angular.element(a).length>0)return n.when(a)}catch(c){}return b.debug("Fetching url",a),j({method:"GET",url:a}).then(function(b){var c=b.data.trim();return k.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)})},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in d||d.DocumentTouch&&e instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},requestAnimationFrame:d.requestAnimationFrame&&d.requestAnimationFrame.bind(d)||d.webkitRequestAnimationFrame&&d.webkitRequestAnimationFrame.bind(d)||function(a){return l(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{b=m.get("$animate"),b.enabled(!0,a)}catch(c){}},nextUid:function(){for(var a,b=h.length;b;){if(b--,a=h[b].charCodeAt(0),57===a)return h[b]="A",i+h.join("");if(90!==a)return h[b]=String.fromCharCode(a+1),i+h.join("");h[b]="0"}return h.unshift("0"),i+h.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=p.nextUid()):b=a,c+":"+b}};return["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);p["element"+d]=function(d,e){var h=d;if("undefined"!=typeof h.length&&h.length&&(h=d[0]),h){var i=a(h);return 0===h.offsetWidth&&f.test(i.display)?p.fakeElement(h,g,function(a){return c(a,b,e)}):c(h,b,e)}return null},p["outerElement"+d]=function(a,b){return a?p["element"+d].call(this,a,b?"margin":"border"):null}}),p.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},p.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},p.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border-"+c:"border";var e=parseInt(d[c],10);return isNaN(e)?0:e},p.detectBrowser=function(){var a=d.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},p.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=p.detectBrowser(),c=a.scrollLeft,d=angular.element(a).css("direction");if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},p.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=p.detectBrowser(),d=angular.element(a).css("direction");if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},p.preEval=function(a){var b=o.BRACKET_REGEXP.exec(a);if(b)return(b[1]?p.preEval(b[1]):b[1])+b[2]+(b[3]?p.preEval(b[3]):b[3]);a=a.replace(o.APOS_REGEXP,"\\'");var c=a.split(o.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(o.FUNC_REGEXP,"']$1"))}),d.join("['")},p.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&l.cancel(e),e=l(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){l.cancel(e),e=null},d},p}]),d.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},column:{hide:"Spalte ausblenden"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y soltarlo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrando:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},column:{hide:"Ocultar la columna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},column:{hide:"Colonne de peau"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Kolom te verbergen"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},column:{hide:"Esconder coluna"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};a.forEach(function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};b.forEach(function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"条目"},groupPanel:{description:"拖曳表头到此处以进行分组"},search:{placeholder:"搜索...",showingItems:"当前显示条目:",selectedItems:"选中条目:",totalItems:"条目总数:",size:"每页显示数:",first:"回到首页",next:"下一页",previous:"上一页",last:"前往尾页"},menu:{text:"数据分组与选择列:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"筆"},groupPanel:{description:"拖拉表頭到此處以進行分組"},search:{placeholder:"搜尋...",showingItems:"目前顯示筆數:",selectedItems:"選取筆數:",totalItems:"總筆數:",size:"每頁顯示:",first:"第一頁",next:"下一頁",previous:"上一頁",last:"最後頁"},menu:{text:"選擇欄位:"},column:{hide:"隐藏列"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$log","$timeout","gridUtil",function(a,b,c){return{require:"uiGrid",scope:!1,link:function(a,d,e,f){function g(){j=c.elementHeight(d),i=c.elementWidth(d)}function h(){b.cancel(k),k=b(function(){var a=c.elementHeight(d),b=c.elementWidth(d);a!==j||b!==i?(f.grid.gridHeight=a,f.grid.gridWidth=b,f.grid.queueRefresh().then(function(){g(),h()})):h()},250)}var i,j;g();var k;h(),a.$on("$destroy",function(){b.cancel(k)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3}}),b.service("uiGridCellNavService",["$log","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d,e){var f={initializeGrid:function(a){a.registerColumnBuilder(f.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null;var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(a,b,c,d){f.scrollTo(a,b,c,d)},getFocusedCell:function(){return a.cellNav.lastRowCol}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},getDirection:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey?d.direction.LEFT:a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB?d.direction.RIGHT:a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey?d.direction.UP:a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?d.direction.DOWN:null},getNextRowCol:function(a,b,c,e){switch(a){case d.direction.LEFT:return f.getRowColLeft(b.rows,b.columns,c,e);case d.direction.RIGHT:return f.getRowColRight(b.rows,b.columns,c,e);case d.direction.UP:return f.getRowColUp(b.rows,b.columns,c,e);case d.direction.DOWN:return f.getRowColDown(b.rows,b.columns,c,e)}},getRowColLeft:function(b,c,d,e){var g=f.getNextColIndexLeft(c,e);return g>e.index?0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g]):new a(d,c[g])},getRowColRight:function(b,c,d,e){var g=f.getNextColIndexRight(c,e);return g<e.index?d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g]):new a(d,c[g])},getNextColIndexLeft:function(a,b){for(var c=0===b.index?a.length-1:b.index-1;c!==b.index&&!a[c].colDef.allowCellFocus;)c--,-1===c&&(c=a.length-1);return c},getNextColIndexRight:function(a,b){for(var c=b.index===a.length-1?0:b.index+1;c!==b.index&&!a[c].colDef.allowCellFocus;)c++,c>a.length-1&&(c=0);return c},getRowColUp:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return 0===d.index?new a(d,c[g]):new a(b[d.index-1],c[g])},getRowColDown:function(b,c,d,e){var g=e.colDef.allowCellFocus?e.index:f.getNextColIndexRight(c,e);return d.index===b.length-1?new a(d,c[g]):new a(b[d.index+1],c[g])},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,e.all(b)},scrollTo:function(a,b,d,e){var f={};if(null!==d){var g=a.getRow(d);g&&(f.y={percentage:g.index/a.renderContainers.body.visibleRowCache.length})}if(null!==e){var h=a.getColumn(e.name?e.name:e.field);h&&(f.x={percentage:this.getLeftWidth(a,h.index)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache.length-1)})}(f.y||f.x)&&b.$broadcast(c.events.GRID_SCROLL,f)},getLeftWidth:function(a,b){var c=0;if(b){for(var d=0;b>=d;d++)a.renderContainers.body.visibleColumnCache[d].drawnWidth&&(c+=a.renderContainers.body.visibleColumnCache[d].drawnWidth);return c}}};return f}]),b.directive("uiGridCellnav",["$log","uiGridCellNavService","uiGridCellNavConstants",function(b,c,d){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,e,f,g){var h=g.grid;c.initializeGrid(h),g.cellNav={},g.cellNav.broadcastCellNav=function(a){b.$broadcast(d.CELL_NAV_EVENT,a),g.cellNav.broadcastFocus(a.row,a.col)},g.cellNav.broadcastFocus=function(b,c){if(null===h.cellNav.lastRowCol||h.cellNav.lastRowCol.row!==b||h.cellNav.lastRowCol.col!==c){var d=new a(b,c);h.api.cellNav.raise.navigate(d,h.cellNav.lastRowCol),h.cellNav.lastRowCol=d}}},post:function(){}}}}}]),b.directive("uiGridCell",["uiGridCellNavService","$log","uiGridCellNavConstants",function(a,b,c){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,d,e,f){function g(){d.find("div").attr("tabindex",-1)}function h(){var a=d.find("div");a[0].focus(),a.attr("tabindex",0)}b.col.colDef.allowCellFocus&&(g(),d.on("keydown",function(c){var d=a.getDirection(c);if(null===d)return!0;var e=a.getNextRowCol(d,b.grid,b.row,b.col);return f.cellNav.broadcastCellNav(e),g(),!1}),d.find("div").on("focus",function(){f.cellNav.broadcastFocus(b.row,b.col)}),b.$on(c.CELL_NAV_EVENT,function(a,c){c.row===b.row&&c.col===b.col&&h()}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$log","$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a){f.defaultGridOptions(a.options),a.registerColumnBuilder(f.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(a,c,d){var f=[];return a.enableCellEdit=void 0===a.enableCellEdit?void 0===d.enableCellEdit?"object"!==a.type:d.enableCellEdit:a.enableCellEdit,a.cellEditableCondition=void 0===a.cellEditableCondition?d.cellEditableCondition:a.cellEditableCondition,a.enableCellEdit&&(a.editableCellTemplate=a.editableCellTemplate||d.editableCellTemplate||"ui-grid/cellEditor",f.push(e.getTemplate(a.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+a.editableCellTemplate+"'")}))),a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?d.enableCellEditOnFocus:a.enableCellEditOnFocus,b.all(f)},isStartEditKey:function(a){return a.keyCode===d.keymap.LEFT||a.keyCode===d.keymap.TAB&&a.shiftKey||a.keyCode===d.keymap.RIGHT||a.keyCode===d.keymap.TAB||a.keyCode===d.keymap.UP||a.keyCode===d.keymap.ENTER&&a.shiftKey||a.keyCode===d.keymap.DOWN||a.keyCode===d.keymap.ENTER?!1:!0}};return f}]),a.directive("uiGridEdit",["$log","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridEditConstants","$log","$parse","uiGridEditService",function(a,b,c,d,e,f){return{priority:-100,restrict:"A",scope:!1,link:function(d,g){function h(){g.on("dblclick",m),g.on("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").on("focus",j)}function i(){g.off("dblclick",m),g.off("keydown",k),d.col.colDef.enableCellEditOnFocus&&g.find("div").off("focus",j)}function j(a){a.stopPropagation(),m()}function k(a){f.isStartEditKey(a)&&m()}function l(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(d):a.colDef.cellEditableCondition)}function m(){if(l(d.col,d.row)){r=e(d.row.getQualifiedColField(d.col)),q=r(d),p=d.col.editableCellTemplate,p=p.replace(b.COL_FIELD,d.row.getQualifiedColField(d.col));var f=d.col.colDef.editDropdownFilter?"|"+d.col.colDef.editDropdownFilter:"";switch(p=p.replace(b.CUSTOM_FILTERS,f),d.inputType="text",d.col.colDef.type){case"boolean":d.inputType="checkbox";break;case"number":d.inputType="number";break;case"date":d.inputType="date"}d.editDropdownOptionsArray=d.col.colDef.editDropdownOptionsArray,d.editDropdownIdLabel=d.col.colDef.editDropdownIdLabel?d.col.colDef.editDropdownIdLabel:"id",d.editDropdownValueLabel=d.col.colDef.editDropdownValueLabel?d.col.colDef.editDropdownValueLabel:"value";var h;d.$apply(function(){s=!0,i(),h=a(p)(d.$new());var b=angular.element(g.children()[0]);t=b.hasClass(":focus"),b.addClass("ui-grid-cell-contents-hidden"),g.append(h)});var j=d.$on(b.events.GRID_SCROLL,function(){n(!0),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),j()}),k=d.$on(c.events.END_CELL_EDIT,function(a,b){n(b),d.grid.api.edit.raise.afterCellEdit(d.row.entity,d.col.colDef,r(d),q),k()}),m=d.$on(c.events.CANCEL_CELL_EDIT,function(){o(),m()});d.$broadcast(c.events.BEGIN_CELL_EDIT),d.grid.api.edit.raise.beginCellEdit(d.row.entity,d.col.colDef)}}function n(a){if(s){var b=angular.element(g.children()[0]);angular.element(g.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&t&&b.focus(),t=!1,s=!1,h()}}function o(){s&&(r.assign(d,q),d.$apply(),d.grid.api.edit.raise.cancelCellEdit(d.row.entity,d.col.colDef),n(!0))}if(d.col.colDef.enableCellEdit){var p,q,r,s=!1,t=!1;h()}}}}]),a.directive("uiGridEditor",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(a){c.stopEdit(a)})}),c.deepEdit=!1,c.stopEdit=function(a){c.inputForm&&!c.inputForm.$valid?(a.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT)):c.$emit(b.events.END_CELL_EDIT),c.deepEdit=!1},d.on("click",function(){c.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.TAB:c.stopEdit(d)}if(c.deepEdit)switch(d.keyCode){case a.keymap.LEFT:d.stopPropagation();break;case a.keymap.RIGHT:d.stopPropagation();break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation()}return!0})}}}}}]),a.directive("input",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{restrict:"E",require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$log","$compile",function(){var a={initializeGrid:function(b){var c={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(c){var d=b.getRow(c);null!==d&&a.toggleRowExpansion(b,d)},expandAllRows:function(){a.expandAllRows(b)},collapseAllRows:function(){a.collapseAllRows(b)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.height=b.isExpanded?b.grid.options.rowHeight+a.options.expandable.expandableRowHeight:b.grid.options.rowHeight,a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded||a.toggleRowExpansion(b,c)}),b.refresh()},collapseAllRows:function(b){angular.forEach(b.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&a.toggleRowExpansion(b,c)}),b.refresh()}};return a}]),a.directive("uiGridExpandable",["$log","uiGridExpandableService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,d,e,f){var g={name:"expandableButtons",width:40};
    +g.cellTemplate=c.get("ui-grid/expandableRowHeader"),f.grid.addRowHeaderColumn(g),b.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$log","$compile","uiGridConstants","gridUtil","$interval",function(a,b,c,d,e,f){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){f.getTemplate(a.grid.options.expandable.rowExpandableTemplate).then(function(c){var e=d(c)(a);b.append(e),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","$log","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b}},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",LINK_LABEL:"LINK_LABEL",BUTTON_LABEL:"BUTTON_LABEL"}),a.service("uiGridExporterService",["$log","$q","uiGridExporterConstants","gridUtil","$compile",function(a,b,c,d,e){var f={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c,d){f.csvExport(a,b,c,d)},pdfExport:function(b,c){f.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.exporterSuppressButton=a.exporterSuppressButton===!0,a.exporterLinkTemplate=a.exporterLinkTemplate?a.exporterLinkTemplate:"ui-grid/csvLink",a.exporterHeaderTemplate=a.exporterHeaderTemplate?a.exporterHeaderTemplate:"ui-grid/exporterHeader",a.exporterLinkLabel=a.exporterLinkLabel?a.exporterLinkLabel:"Download CSV",a.exporterButtonLabel=a.exporterButtonLabel?a.exporterButtonLabel:"Export",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720},showMenu:function(a){a.exporter.$scope.menuItems=[{title:"Export all data as csv",action:function(){this.grid.api.exporter.csvExport(c.ALL,c.ALL)}},{title:"Export visible data as csv",action:function(){this.grid.api.exporter.csvExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as csv",action:function(){this.grid.api.exporter.csvExport(c.SELECTED,c.VISIBLE)}},{title:"Export all data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.ALL,c.ALL)}},{title:"Export visible data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.VISIBLE,c.VISIBLE)}},{title:"Export selected data as pdf",action:function(){this.grid.api.exporter.pdfExport(c.SELECTED,c.VISIBLE)}}],a.exporter.$scope.$broadcast("toggleExporterMenu")},csvExport:function(a,b,c,d){var e=this.getColumnHeaders(a,c),f=this.getData(a,b,c),g=this.formatAsCsv(e,f);this.renderCsvLink(a,g,d)},getColumnHeaders:function(a,b){var d=[];return angular.forEach(a.columns,function(a){(a.visible||b===c.ALL)&&d.push({name:a.field,displayName:a.displayName,width:a.drawnWidth?a.drawnWidth:a.width,align:"number"===a.colDef.type?"right":"left"})}),d},getData:function(b,d,e){var f,g=[];switch(d){case c.ALL:f=b.rows;break;case c.VISIBLE:f=b.getVisibleRows();break;case c.SELECTED:b.api.selection?f=b.api.selection.getSelectedGridRows():a.error("selection feature must be enabled to allow selected rows to be exported")}return c.ALL?(angular.forEach(f,function(a){var d=[];angular.forEach(b.columns,function(f){(f.visible||e===c.ALL)&&d.push(b.getCellValue(a,f))}),g.push(d)}),g):void 0},formatAsCsv:function(a,b){var c=this,d=a.map(function(a){return a.displayName}),e=c.formatRowAsCsv(this)(d)+"\n";return e+=b.map(this.formatRowAsCsv(this)).join("\n")},formatRowAsCsv:function(a){return function(b){return b.map(a.formatFieldAsCsv).join(",")}},formatFieldAsCsv:function(a){return null==a?"":"number"==typeof a?a:"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?'"'+a.replace(/"/g,'""')+'"':JSON.stringify(a)},renderCsvLink:function(a,b,f){var g=f?f:angular.element(a.exporter.gridElm[0].querySelectorAll(".ui-grid-exporter-csv-link"));angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span"))&&angular.element(g[0].querySelectorAll(".ui-grid-exporter-csv-link-span")).remove();d.getTemplate(a.options.exporterLinkTemplate).then(function(d){d=d.replace(c.LINK_LABEL,a.options.exporterLinkLabel),d=d.replace(c.CSV_CONTENT,encodeURIComponent(b));var f=angular.element(d),h=e(f)(a.exporter.$scope);g.append(h)})},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){return null==a?"":"number"==typeof a?a.toString():"boolean"==typeof a?a?"TRUE":"FALSE":"string"==typeof a?a.replace(/"/g,'""'):JSON.stringify(a).replace(/^"/,"").replace(/"$/,"")}};return f}]),a.directive("uiGridExporter",["$log","uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){c.initializeGrid(e.grid),e.grid.exporter.$scope=a},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$log","$compile","$timeout",function(){var a={initializeGrid:function(a){var b={events:{infiniteScroll:{needLoadMoreData:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},loadData:function(a){a.api.infiniteScroll.raise.needLoadMoreData(),a.options.loadTimout=!0},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return a}]),a.directive("uiGridInfiniteScroll",["$log","uiGridInfiniteScrollService",function(a,b){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","$log","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.$on(d.events.GRID_SCROLL,function(b,d){var e=100-100*d.y.percentage;c.checkScroll(a.grid,e)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"}}),a}])}]),a.service("uiGridPinningService",["$log","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(a,b,d){if(a.enablePinning=void 0===a.enablePinning?d.enablePinning:a.enablePinning,a.pinnedLeft?(b.renderContainer="left",b.grid.createLeftContainer()):a.pinnedRight&&(b.renderContainer="right",b.grid.createRightContainer()),a.enablePinning){var e={title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.grid.createLeftContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},f={title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.grid.createRightContainer(),b.grid.refresh().then(function(){b.grid.refresh()})}},g={title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,b.grid.refresh().then(function(){b.grid.refresh()})}};b.menuItems.push(e),b.menuItems.push(f),b.menuItems.push(g)}}};return d}]),a.directive("uiGridPinning",["$log","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.constant("columnBounds",{minWidth:35}),a.service("uiGridResizeColumnsService",["$log","$q",function(a,b){var c={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)}};return c}]),a.directive("uiGridResizeColumns",["$log","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$log","$templateCache","$compile","$q",function(a,b,c,d){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,f,g){if(g.grid.options.enableColumnResizing){var h=d.defer();f.$observe("renderIndex",function(b){a.renderIndex=a.$eval(b),h.resolve()}),h.promise.then(function(){var d=b.get("ui-grid/columnResizer"),f=angular.element(d).clone(),g=angular.element(d).clone();f.attr("position","left"),g.attr("position","right");var h=a.col,i=h.getRenderContainer(),j=i.renderedColumns[a.renderIndex-1];j&&0!==a.col.index&&j.colDef.enableColumnResizing!==!1&&e.prepend(f),a.col.colDef.enableColumnResizing!==!1&&e.append(g),c(f)(a),c(g)(a)})}}}}}}]),a.directive("uiGridColumnResizer",["$log","$document","gridUtil","uiGridConstants","columnBounds",function(a,b,c,d,e){var f=angular.element('<div class="ui-grid-resize-overlay"></div>'),g={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(a,g,h,i){function j(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b.index!==a.index){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(c.width=b.drawnWidth)}})}function k(){i.grid.buildColumns().then(function(){i.grid.refreshCanvas(!0)})}function l(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),o=b.clientX-p,0>o?o=0:o>i.grid.gridWidth&&(o=i.grid.gridWidth);var c,g=a.col,h=g.getRenderContainer();if("left"===a.position?(g=h.renderedColumns[a.renderIndex-1],c=a.col):"right"===a.position&&(c=h.renderedColumns[a.renderIndex+1]),g.colDef.enableColumnResizing!==!1){i.grid.element.hasClass("column-resizing")||i.grid.element.addClass("column-resizing");var j=o-n,k=g.drawnWidth+j;g.colDef.minWidth&&k<g.colDef.minWidth?o+=g.colDef.minWidth-k:!g.colDef.minWidth&&e.minWidth&&k<e.minWidth?o+=g.colDef.minWidth-k:g.colDef.maxWidth&&k>g.colDef.maxWidth&&(o+=g.colDef.maxWidth-k),f.css({left:o+"px"}),i.fireEvent(d.events.ITEM_DRAGGING)}}function m(c){c.originalEvent&&(c=c.originalEvent),c.preventDefault(),i.grid.element.removeClass("column-resizing"),f.remove(),o=c.clientX-p;var d=o-n;if(0===d)return b.off("mouseup",m),void b.off("mousemove",l);var g,h=a.col,q=h.getRenderContainer();if("left"===a.position?(h=q.renderedColumns[a.renderIndex-1],g=a.col):"right"===a.position&&(g=q.renderedColumns[a.renderIndex+1]),h.colDef.enableColumnResizing!==!1){var r=h.drawnWidth+d;h.colDef.minWidth&&r<h.colDef.minWidth?r=h.colDef.minWidth:!h.colDef.minWidth&&e.minWidth&&r<e.minWidth&&(r=e.minWidth),h.colDef.maxWidth&&r>h.colDef.maxWidth&&(r=h.colDef.maxWidth),h.colDef.width=r,j(h),k(d),b.off("mouseup",m),b.off("mousemove",l)}}var n=0,o=0,p=0;"left"===a.position?g.addClass("left"):"right"===a.position&&g.addClass("right"),g.on("mousedown",function(a){a.originalEvent&&(a=a.originalEvent),a.stopPropagation(),p=i.grid.element[0].getBoundingClientRect().left,n=a.clientX-p,i.grid.element.append(f),f.css({left:n}),b.on("mouseup",m),b.on("mousemove",l)}),g.on("dblclick",function(b){b.stopPropagation();var f,h,i=a.col,l=i.getRenderContainer();"left"===a.position?(i=l.renderedColumns[a.renderIndex-1],f=a.col,h=1):"right"===a.position&&(f=l.renderedColumns[a.renderIndex+1],f=l.renderedColumns[a.renderIndex+1],h=-1);var m=0,n=0,o=c.closestElm(g,".ui-grid-render-container"),p=o.querySelectorAll("."+d.COL_CLASS_PREFIX+i.index+" .ui-grid-cell-contents");Array.prototype.forEach.call(p,function(a){var b;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(b=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),c.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=c.elementWidth(d);if(b){var f=c.elementWidth(b);e+=f}e>m&&(m=e,n=m-e)})}),i.colDef.minWidth&&m<i.colDef.minWidth?m=i.colDef.minWidth:!i.colDef.minWidth&&e.minWidth&&m<e.minWidth&&(m=e.minWidth),i.colDef.maxWidth&&m>i.colDef.maxWidth&&(m=i.colDef.maxWidth),i.colDef.width=m,j(i),k(n)}),g.on("$destroy",function(){g.off("mousedown"),g.off("dblclick"),b.off("mousemove",l),b.off("mouseup",m)})}};return g}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$log","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c){var d={initializeGrid:function(a,b){var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,b,c){d.setSavePromise(a,b,c)},getDirtyRows:function(a){return a.rowEditDirtyRows},getErrorRows:function(a){return a.rowEditErrorRows},flushDirtyRows:function(a){return d.flushDirtyRows(a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,d.endEditCell),b.api.edit.on.beginCellEdit(a,d.beginEditCell),b.api.edit.on.cancelCellEdit(a,d.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,d.navigate)})},defaultGridOptions:function(){},saveRow:function(a,c){var d=this;return function(){c.isSaving=!0;var e=a.api.rowEdit.raise.saveRow(c.entity);return c.rowEditSavePromise?c.rowEditSavePromise.then(d.processSuccessPromise(a,c),d.processErrorPromise(a,c)):b.log("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),e}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEditErrorRows,b),c.removeRow(a.rowEditDirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEditErrorRows||(a.rowEditErrorRows=[]),a.rowEditErrorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},flushDirtyRows:function(a){var b=[];return angular.forEach(a.rowEditDirtyRows,function(c){d.saveRow(a,c)(),b.push(c.rowEditSavePromise)}),c.all(b)},endEditCell:function(a,c,e,f){var g=this.grid,h=g.getRow(a);return h?void((e!==f||h.isDirty)&&(g.rowEditDirtyRows||(g.rowEditDirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEditDirtyRows.push(h)),delete h.isError,d.considerSetTimer(g,h))):void b.log("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.cancelTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var c=this.grid,e=c.getRow(a);return e?void d.considerSetTimer(c,e):void b.log("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&d.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&d.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(d.cancelTimer(b,c),c.isDirty&&!c.isSaving){var e=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(d.saveRow(b,c),e,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)}};return d}]),a.directive("uiGridRowEdit",["$log","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","$log","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}"),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection"}),a.service("uiGridSelectionService",["$log","$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){}}},methods:{selection:{toggleRowSelection:function(c){var d=b.getRow(c);null!==d&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectRow:function(c){var d=b.getRow(c);null===d||d.isSelected||a.toggleRowSelection(b,d,b.options.multiSelect)},unSelectRow:function(c){var d=b.getRow(c);null!==d&&d.isSelected&&a.toggleRowSelection(b,d,b.options.multiSelect)},selectAllRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=!0})},selectAllVisibleRows:function(){b.options.multiSelect!==!1&&b.rows.forEach(function(a){a.isSelected=a.visible?!0:!1})},clearSelectedRows:function(){a.clearSelectedRows(b)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1},toggleRowSelection:function(b,c,d){var e=c.isSelected;d||e||a.clearSelectedRows(b),c.isSelected=!e,c.isSelected===!0&&(b.selection.lastSelectedRow=c),b.api.selection.raise.rowSelectionChanged(c)},shiftSelect:function(b,c,d){if(d){var e=a.getSelectedRows(b),f=e.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,g=b.renderContainers.body.visibleRowCache.indexOf(c);if(f>g){var h=f;f=g,g=h}for(var i=f;g>=i;i++){var j=b.renderContainers.body.visibleRowCache[i];j&&(j.isSelected=!0,b.selection.lastSelectedRow=j,b.api.selection.raise.rowSelectionChanged(j))}}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b){a.getSelectedRows(b).forEach(function(a){a.isSelected=!1,b.api.selection.raise.rowSelectionChanged(a)})}};return a}]),a.directive("uiGridSelection",["$log","uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,d,e){if(c.initializeGrid(e.grid),e.grid.options.enableRowHeaderSelection){var f="ui-grid/selectionRowHeader",g={name:"selectionRowHeaderCol",displayName:"",width:30,cellTemplate:f};e.grid.addRowHeaderColumn(g)}},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$log","$templateCache","uiGridSelectionService",function(a,b,c){return{replace:!0,restrict:"E",template:b.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,b,d,e){var f=e.grid;a.selectButtonClick=function(a,b){b.shiftKey?c.shiftSelect(f,a,f.options.multiSelect):c.toggleRowSelection(f,a,f.options.multiSelect)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]);return b.attr("ng-class","{'ui-grid-row-selected': row.isSelected}"),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","$log","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,b){function c(){b.on("click",function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,a.grid.options.multiSelect):f.toggleRowSelection(a.grid,a.row,a.grid.options.multiSelect),a.$apply()})}a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(b.addClass("ui-grid-disable-selection"),c())}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell clearfix" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-top-panel"><div ui-grid-group-panel ng-show="grid.options.showGroupPanel"></div><div class="ui-grid-header ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index" ng-style="$index === 0 && colContainer.columnStyle($index)"></div></div></div><div ui-grid-menu></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n\n    {{ grid.customStyles }}</style><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-scrollbars="grid.options.enableScrollbars"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenu"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationValue() }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><div class="ui-grid-vertical-bar">&nbsp;</div><div class="ui-grid-cell-contents" col-index="renderIndex">{{ col.displayName CUSTOM_FILTERS }} <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div ng-if="grid.options.enableColumnMenu && !col.isRowHeader" class="ui-grid-column-menu-button" ng-click="toggleMenu($event)"><i class="ui-grid-icon-angle-down">&nbsp;<i></i></i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-click="$event.stopPropagation()" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel right" ng-show="!!colFilter.term">&nbsp;</i> <!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu"><div class="ui-grid-menu-inner" ng-show="shown"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" title="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ title }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showFooter"></div><!-- native scrolling --><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="vertical"></div><div ui-grid-native-scrollbar ng-if="enableScrollbars" type="horizontal"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by row.uid" class="ui-grid-row" ng-style="containerCtrl.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="{{inputType}}" ng-class="\'colt\' + col.index" ui-grid-editor ng-model="COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.index" ui-grid-edit-dropdown ng-model="COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left;margin-top: 1px;margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth() - grid.verticalScrollbarWidth)\n     ,height: grid.options.expandable.expandableRowHeight}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell uiGridExpandableButtonsCell"><div class="ui-grid-cell-contents"><i ng-class="{\'ui-grid-icon-plus-squared\':!row.isExpanded, \'ui-grid-icon-minus-squared\':row.isExpanded}" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller",'<div ng-if="expandableRow.shouldRenderFiller()" style="float:left;margin-top: 2px;margin-bottom: 2px" ng-style="{width: (grid.getViewportWidth())\n     ,height: grid.options.expandable.expandableRowHeight, \'margin-left\': grid.options.rowHeader.rowHeaderWidth}"><i class="ui-grid-icon-spin5 ui-grid-animate-spin" ng-style="{\'margin-top\': ( grid.options.expandable.expandableRowHeight/2 - 5),\n            \'margin-left\':((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5)}"></i></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT">LINK_LABEL</a></span>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-row-header-cell ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>')
    +}]);
    \ No newline at end of file
    diff --git a/release/ui-grid-unstable.css b/release/ui-grid-unstable.css
    new file mode 100644
    index 000000000..bc9460344
    --- /dev/null
    +++ b/release/ui-grid-unstable.css
    @@ -0,0 +1,1317 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20-5f155b2 - 2015-03-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +.ui-grid {
    +  border: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-transform: translateZ(0);
    +  -moz-transform: translateZ(0);
    +  -o-transform: translateZ(0);
    +  -ms-transform: translateZ(0);
    +  transform: translateZ(0);
    +}
    +.ui-grid-vertical-bar {
    +  position: absolute;
    +  right: 0;
    +  width: 0;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-clearfix:before,
    +.ui-grid-clearfix:after {
    +  content: "";
    +  display: table;
    +}
    +.ui-grid-clearfix:after {
    +  clear: both;
    +}
    +.ui-grid-invisible {
    +  visibility: hidden;
    +}
    +.ui-grid-top-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-header {
    +  border-bottom: 1px solid #d4d4d4;
    +  box-sizing: content-box;
    +}
    +.ui-grid-top-panel {
    +  position: relative;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-header-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-header-canvas:before,
    +.ui-grid-header-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-header-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-header-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +.ui-grid-header-cell-row {
    +  display: table-row;
    +}
    +.ui-grid-header-cell {
    +  position: relative;
    +  box-sizing: border-box;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  display: table-cell;
    +  -webkit-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  width: 0;
    +}
    +.ui-grid-header-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-header-cell .sortable {
    +  cursor: pointer;
    +}
    +.ui-grid-header .ui-grid-vertical-bar {
    +  top: 0;
    +  bottom: 0;
    +}
    +.ui-grid-column-menu-button {
    +  position: absolute;
    +  right: 1px;
    +  top: 0;
    +}
    +.ui-grid-column-menu-button .ui-grid-icon-angle-down {
    +  vertical-align: sub;
    +}
    +.ui-grid-column-menu-button-last-col {
    +  margin-right: 25px;
    +}
    +.ui-grid-column-menu {
    +  position: absolute;
    +}
    +/* Slide up/down animations */
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +/* Slide up/down animations */
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transition: all 0.05s linear;
    +  -moz-transition: all 0.05s linear;
    +  -o-transition: all 0.05s linear;
    +  transition: all 0.05s linear;
    +  display: block !important;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove {
    +  -webkit-transform: translateY(-100%);
    +  -moz-transform: translateY(-100%);
    +  -o-transform: translateY(-100%);
    +  -ms-transform: translateY(-100%);
    +  transform: translateY(-100%);
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active {
    +  -webkit-transform: translateY(0);
    +  -moz-transform: translateY(0);
    +  -o-transform: translateY(0);
    +  -ms-transform: translateY(0);
    +  transform: translateY(0);
    +}
    +.ui-grid-filter-container {
    +  padding: 4px 10px;
    +  position: relative;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  right: 0;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  position: absolute;
    +  top: 50%;
    +  line-height: 32px;
    +  margin-top: -16px;
    +  right: 10px;
    +  opacity: 0.66;
    +}
    +.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover {
    +  opacity: 1;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-render-container {
    +  position: inherit;
    +  -webkit-border-top-right-radius: 0;
    +  -webkit-border-bottom-right-radius: 0px;
    +  -webkit-border-bottom-left-radius: 0px;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0;
    +  -moz-border-radius-bottomright: 0px;
    +  -moz-border-radius-bottomleft: 0px;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0;
    +  border-bottom-right-radius: 0px;
    +  border-bottom-left-radius: 0px;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-render-container:focus {
    +  outline: none;
    +}
    +.ui-grid-viewport {
    +  min-height: 20px;
    +  position: relative;
    +  overflow-y: scroll;
    +  -webkit-overflow-scrolling: touch;
    +}
    +.ui-grid-viewport :focus {
    +  outline: none;
    +}
    +.ui-grid-canvas {
    +  position: relative;
    +  padding-top: 1px;
    +}
    +.ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +.ui-grid-row:last-child .ui-grid-cell {
    +  border-bottom-color: #d4d4d4;
    +  border-bottom-style: solid;
    +}
    +.ui-grid-no-row-overlay {
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  margin: 10%;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +  border: 1px solid #d4d4d4;
    +  font-size: 2em;
    +  text-align: center;
    +}
    +.ui-grid-no-row-overlay > * {
    +  position: absolute;
    +  display: table;
    +  margin: auto 0;
    +  width: 100%;
    +  top: 0;
    +  bottom: 0;
    +  left: 0;
    +  right: 0;
    +  opacity: 0.66;
    +}
    +.ui-grid-cell {
    +  overflow: hidden;
    +  float: left;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +}
    +.ui-grid-cell:last-child {
    +  border-right: 0;
    +}
    +.ui-grid-cell-contents {
    +  padding: 5px;
    +  -moz-box-sizing: border-box;
    +  -webkit-box-sizing: border-box;
    +  box-sizing: border-box;
    +  white-space: nowrap;
    +  -ms-text-overflow: ellipsis;
    +  -o-text-overflow: ellipsis;
    +  text-overflow: ellipsis;
    +  overflow: hidden;
    +  height: 100%;
    +}
    +.ui-grid-cell-contents-hidden {
    +  visibility: hidden;
    +  width: 0;
    +  height: 0;
    +  display: none;
    +}
    +.ui-grid-row-header-cell {
    +  background-color: #F0F0EE !important;
    +  border-bottom: solid 1px #d4d4d4;
    +}
    +.ui-grid-footer-panel-background {
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +}
    +.ui-grid-footer-panel {
    +  position: relative;
    +  border-bottom: 1px solid #d4d4d4;
    +  border-top: 1px solid #d4d4d4;
    +  overflow: hidden;
    +  font-weight: bold;
    +  background: #f3f3f3;
    +  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff));
    +  background: -ms-linear-gradient(bottom, #eeeeee, #ffffff);
    +  background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%);
    +  background: -o-linear-gradient(#ffffff, #eeeeee);
    +  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
    +  -webkit-border-top-right-radius: -1px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: -1px;
    +  -moz-border-radius-topright: -1px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: -1px;
    +  border-top-right-radius: -1px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: -1px;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +.ui-grid-grid-footer {
    +  float: left;
    +  width: 100%;
    +}
    +.ui-grid-footer-viewport {
    +  overflow: hidden;
    +}
    +.ui-grid-footer-canvas {
    +  position: relative;
    +}
    +.ui-grid-footer-canvas:before,
    +.ui-grid-footer-canvas:after {
    +  content: "";
    +  display: table;
    +  line-height: 0;
    +}
    +.ui-grid-footer-canvas:after {
    +  clear: both;
    +}
    +.ui-grid-footer-cell-wrapper {
    +  position: relative;
    +  display: table;
    +  box-sizing: border-box;
    +  height: 100%;
    +}
    +.ui-grid-footer-cell-row {
    +  display: table-row;
    +}
    +.ui-grid-footer-cell {
    +  overflow: hidden;
    +  background-color: inherit;
    +  border-right: 1px solid;
    +  border-color: #d4d4d4;
    +  box-sizing: border-box;
    +  display: table-cell;
    +}
    +.ui-grid-footer-cell:last-child {
    +  border-right: 0;
    +}
    +input[type="text"].ui-grid-filter-input {
    +  padding: 0;
    +  margin: 0;
    +  border: 0;
    +  width: 100%;
    +  border: 1px solid #d4d4d4;
    +  -webkit-border-top-right-radius: 0px;
    +  -webkit-border-bottom-right-radius: 0;
    +  -webkit-border-bottom-left-radius: 0;
    +  -webkit-border-top-left-radius: 0;
    +  -moz-border-radius-topright: 0px;
    +  -moz-border-radius-bottomright: 0;
    +  -moz-border-radius-bottomleft: 0;
    +  -moz-border-radius-topleft: 0;
    +  border-top-right-radius: 0px;
    +  border-bottom-right-radius: 0;
    +  border-bottom-left-radius: 0;
    +  border-top-left-radius: 0;
    +  -moz-background-clip: padding-box;
    +  -webkit-background-clip: padding-box;
    +  background-clip: padding-box;
    +}
    +input[type="text"].ui-grid-filter-input:hover {
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  right: 0;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid-menu-button .ui-grid-icon-container {
    +  margin-top: 3px;
    +}
    +.ui-grid-menu-button .ui-grid-menu {
    +  right: 0;
    +}
    +.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid {
    +  overflow-y: scroll;
    +  max-height: 300px;
    +  border: 1px solid #d4d4d4;
    +}
    +.ui-grid-menu {
    +  z-index: 2;
    +  position: absolute;
    +  overflow: hidden;
    +  padding: 0 10px 20px 10px;
    +  cursor: pointer;
    +  box-sizing: content-box;
    +}
    +.ui-grid-menu .ui-grid-menu-inner {
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  position: relative;
    +  white-space: nowrap;
    +  -webkit-border-radius: 0px;
    +  -moz-border-radius: 0px;
    +  border-radius: 0px;
    +  -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul {
    +  margin: 0;
    +  padding: 0;
    +  list-style-type: none;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li {
    +  padding: 8px;
    +  cursor: pointer;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:hover {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active {
    +  -webkit-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  -moz-box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +  background-color: #cecece;
    +}
    +.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child) {
    +  border-bottom: 1px solid #d4d4d4;
    +}
    +.ui-grid-sortarrow {
    +  right: 5px;
    +  position: absolute;
    +  width: 20px;
    +  top: 0;
    +  bottom: 0;
    +  background-position: center;
    +}
    +.ui-grid-sortarrow.down {
    +  -webkit-transform: rotate(180deg);
    +  -moz-transform: rotate(180deg);
    +  -o-transform: rotate(180deg);
    +  -ms-transform: rotate(180deg);
    +  transform: rotate(180deg);
    +}
    +@font-face {
    +  font-family: 'ui-grid';
    +  src: url('ui-grid.eot');
    +  src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg');
    +  font-weight: normal;
    +  font-style: normal;
    +}
    +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
    +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
    +/*
    +@media screen and (-webkit-min-device-pixel-ratio:0) {
    +  @font-face {
    +    font-family: 'ui-grid';
    +    src: url('../font/ui-grid.svg?12312827#ui-grid') format('svg');
    +  }
    +}
    +*/
    +[class^="ui-grid-icon"]:before,
    +[class*=" ui-grid-icon"]:before {
    +  font-family: "ui-grid";
    +  font-style: normal;
    +  font-weight: normal;
    +  speak: none;
    +  display: inline-block;
    +  text-decoration: inherit;
    +  width: 1em;
    +  margin-right: .2em;
    +  text-align: center;
    +  /* opacity: .8; */
    +  /* For safety - reset parent styles, that can break glyph codes*/
    +  font-variant: normal;
    +  text-transform: none;
    +  /* fix buttons height, for twitter bootstrap */
    +  line-height: 1em;
    +  /* Animation center compensation - margins should be symmetric */
    +  /* remove if not needed */
    +  margin-left: .2em;
    +  /* you can be more comfortable with increased icons size */
    +  /* font-size: 120%; */
    +  /* Uncomment for 3D effect */
    +  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
    +}
    +.ui-grid-icon-blank::before {
    +  width: 1em;
    +  content: ' ';
    +}
    +/*
    +* RTL Styles
    +*/
    +.ui-grid[dir=rtl] .ui-grid-header-cell,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell,
    +.ui-grid[dir=rtl] .ui-grid-cell {
    +  float: right !important;
    +}
    +.ui-grid[dir=rtl] .ui-grid-column-menu-button {
    +  position: absolute;
    +  left: 1px;
    +  top: 0;
    +  right: inherit;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-cell:last-child,
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child {
    +  border-right: 1px solid #d4d4d4;
    +  border-left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,
    +.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar {
    +  width: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button {
    +  z-index: 2;
    +  position: absolute;
    +  left: 0;
    +  right: auto;
    +  background: #f3f3f3;
    +  border: 1px solid #d4d4d4;
    +  cursor: pointer;
    +  min-height: 27px;
    +  font-weight: normal;
    +}
    +.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu {
    +  left: 0;
    +  right: auto;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button {
    +  right: initial;
    +  left: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"] {
    +  right: initial;
    +  left: 10px;
    +}
    +/*
    +   Animation example, for spinners
    +*/
    +.ui-grid-animate-spin {
    +  -moz-animation: ui-grid-spin 2s infinite linear;
    +  -o-animation: ui-grid-spin 2s infinite linear;
    +  -webkit-animation: ui-grid-spin 2s infinite linear;
    +  animation: ui-grid-spin 2s infinite linear;
    +  display: inline-block;
    +}
    +@-moz-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-webkit-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-o-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@-ms-keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +@keyframes ui-grid-spin {
    +  0% {
    +    -moz-transform: rotate(0deg);
    +    -o-transform: rotate(0deg);
    +    -webkit-transform: rotate(0deg);
    +    transform: rotate(0deg);
    +  }
    +  100% {
    +    -moz-transform: rotate(359deg);
    +    -o-transform: rotate(359deg);
    +    -webkit-transform: rotate(359deg);
    +    transform: rotate(359deg);
    +  }
    +}
    +/*---------------------------------------------------
    +    LESS Elements 0.9
    +  ---------------------------------------------------
    +    A set of useful LESS mixins
    +    More info at: http://lesselements.com
    +  ---------------------------------------------------*/
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-cell-focus {
    +  outline: 0;
    +  background-color: #b3c4c7;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +div.ui-grid-cell input {
    +  border-radius: inherit;
    +  padding: 0;
    +  width: 100%;
    +  color: inherit;
    +  height: auto;
    +  font: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input:focus {
    +  color: inherit;
    +  outline: none;
    +}
    +div.ui-grid-cell input[type="checkbox"] {
    +  margin: 9px 0 0 6px;
    +  width: auto;
    +}
    +div.ui-grid-cell input.ng-invalid {
    +  border: 1px solid #fc8f8f;
    +}
    +div.ui-grid-cell input.ng-valid {
    +  border: 1px solid #d4d4d4;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell {
    +  background-color: #fdfdfd;
    +}
    +.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell {
    +  background-color: #f3f3f3;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.movingColumn {
    +  position: fixed;
    +  border: 1px solid #d4d4d4;
    +  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
    +}
    +.movingColumn .ui-grid-icon-angle-down {
    +  display: none;
    +}
    +
    +.ui-grid-pager-panel {
    +  position: absolute;
    +  left: 0;
    +  bottom: 0;
    +  width: 100%;
    +  padding-top: 3px;
    +  padding-bottom: 3px;
    +}
    +.ui-grid-pager-container {
    +  float: left;
    +}
    +.ui-grid-pager-control {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  min-width: 135px;
    +  float: left;
    +}
    +.ui-grid-pager-control button {
    +  height: 25px;
    +  min-width: 26px;
    +}
    +.ui-grid-pager-control input {
    +  height: 26px;
    +  width: 50px;
    +  vertical-align: top;
    +}
    +.ui-grid-pager-control .first-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: -3px;
    +}
    +.ui-grid-pager-control .first-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 8.7px 5px 0;
    +  border-color: transparent #4d4d4d transparent transparent;
    +  margin-left: 2px;
    +}
    +.ui-grid-pager-control .next-triangle {
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-control .prev-triangle {
    +  margin-left: 0;
    +}
    +.ui-grid-pager-control .last-triangle {
    +  width: 0;
    +  height: 0;
    +  border-style: solid;
    +  border-width: 5px 0 5px 8.7px;
    +  border-color: transparent transparent transparent #4d4d4d;
    +  margin-left: -1px;
    +}
    +.ui-grid-pager-control .last-bar {
    +  width: 10px;
    +  border-left: 2px solid #4d4d4d;
    +  margin-top: -6px;
    +  height: 12px;
    +  margin-left: 1px;
    +}
    +.ui-grid-pager-row-count-picker {
    +  float: left;
    +}
    +.ui-grid-pager-row-count-picker select {
    +  height: 26px;
    +  width: 60px;
    +}
    +.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label {
    +  margin-top: 3px;
    +}
    +.ui-grid-pager-count-container {
    +  float: right;
    +  margin-top: 4px;
    +  min-width: 50px;
    +}
    +.ui-grid-pager-count-container .ui-grid-pager-count {
    +  margin-right: 10px;
    +  margin-left: 10px;
    +  float: right;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-pinned-container {
    +  float: left;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child {
    +  box-sizing: border-box;
    +  border-right: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar {
    +  right: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child {
    +  box-sizing: border-box;
    +  border-left: 1px solid;
    +  border-width: 1px;
    +  border-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,
    +.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar {
    +  width: 1px;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar {
    +  background-color: #d4d4d4;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar {
    +  background-color: #aeaeae;
    +}
    +.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar {
    +  left: -1px;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +.ui-grid-render-container-body {
    +  float: left;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-column-resizer {
    +  top: 0;
    +  bottom: 0;
    +  width: 5px;
    +  position: absolute;
    +  cursor: col-resize;
    +}
    +.ui-grid-column-resizer.left {
    +  left: 0;
    +}
    +.ui-grid-column-resizer.right {
    +  right: 0;
    +}
    +.ui-grid-header-cell:last-child .ui-grid-column-resizer.right {
    +  border-right: 1px solid #d4d4d4;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.right {
    +  border-right: 0;
    +}
    +.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.left {
    +  border-left: 1px solid #d4d4d4;
    +}
    +.ui-grid.column-resizing {
    +  cursor: col-resize;
    +}
    +.ui-grid.column-resizing .ui-grid-resize-overlay {
    +  position: absolute;
    +  top: 0;
    +  height: 100%;
    +  width: 1px;
    +  background-color: #aeaeae;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-saving .ui-grid-cell {
    +  color: #848484 !important;
    +}
    +.ui-grid-row-dirty .ui-grid-cell {
    +  color: #610b38;
    +}
    +.ui-grid-row-error .ui-grid-cell {
    +  color: #ff0000 !important;
    +}
    +
    +/* This file contains variable declarations (do not remove this line) */
    +/*-- VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +/**
    +* @section Grid styles
    +*/
    +/**
    +* @section Header styles
    +*/
    +/** @description Colors for header gradient */
    +/**
    +* @section Grid body styles
    +*/
    +/** @description Colors used for row alternation */
    +/**
    +* @section Sort arrow colors
    +*/
    +/**
    +* @section Scrollbar styles
    +*/
    +/**
    +* @section font library path
    +*/
    +/*-- END VARIABLES (DO NOT REMOVE THESE COMMENTS) --*/
    +.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
    +  background-color: #c9dde1 !important;
    +}
    +.ui-grid-disable-selection {
    +  -webkit-touch-callout: none;
    +  -webkit-user-select: none;
    +  -khtml-user-select: none;
    +  -moz-user-select: none;
    +  -ms-user-select: none;
    +  user-select: none;
    +  cursor: default;
    +}
    +.ui-grid-selection-row-header-buttons {
    +  cursor: pointer;
    +  opacity: 0.1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-row-selected {
    +  opacity: 1;
    +}
    +.ui-grid-selection-row-header-buttons.ui-grid-all-selected {
    +  opacity: 1;
    +}
    +
    +.ui-grid-icon-plus-squared:before {
    +  content: '\c350';
    +}
    +/* '썐' */
    +.ui-grid-icon-minus-squared:before {
    +  content: '\c351';
    +}
    +/* '썑' */
    +.ui-grid-icon-search:before {
    +  content: '\c352';
    +}
    +/* '썒' */
    +.ui-grid-icon-cancel:before {
    +  content: '\c353';
    +}
    +/* '썓' */
    +.ui-grid-icon-info-circled:before {
    +  content: '\c354';
    +}
    +/* '썔' */
    +.ui-grid-icon-lock:before {
    +  content: '\c355';
    +}
    +/* '썕' */
    +.ui-grid-icon-lock-open:before {
    +  content: '\c356';
    +}
    +/* '썖' */
    +.ui-grid-icon-pencil:before {
    +  content: '\c357';
    +}
    +/* '썗' */
    +.ui-grid-icon-down-dir:before {
    +  content: '\c358';
    +}
    +/* '썘' */
    +.ui-grid-icon-up-dir:before {
    +  content: '\c359';
    +}
    +/* '썙' */
    +.ui-grid-icon-left-dir:before {
    +  content: '\c35a';
    +}
    +/* '썚' */
    +.ui-grid-icon-right-dir:before {
    +  content: '\c35b';
    +}
    +/* '썛' */
    +.ui-grid-icon-left-open:before {
    +  content: '\c35c';
    +}
    +/* '썜' */
    +.ui-grid-icon-right-open:before {
    +  content: '\c35d';
    +}
    +/* '썝' */
    +.ui-grid-icon-angle-down:before {
    +  content: '\c35e';
    +}
    +/* '썞' */
    +.ui-grid-icon-filter:before {
    +  content: '\c35f';
    +}
    +/* '썟' */
    +.ui-grid-icon-sort-alt-up:before {
    +  content: '\c360';
    +}
    +/* '썠' */
    +.ui-grid-icon-sort-alt-down:before {
    +  content: '\c361';
    +}
    +/* '썡' */
    +.ui-grid-icon-ok:before {
    +  content: '\c362';
    +}
    +/* '썢' */
    +.ui-grid-icon-menu:before {
    +  content: '\c363';
    +}
    +/* '썣' */
    +.ui-grid-icon-spin5:before {
    +  content: '\ea61';
    +}
    +/* '' */
    diff --git a/release/ui-grid-unstable.eot b/release/ui-grid-unstable.eot
    new file mode 100644
    index 000000000..88b133b63
    Binary files /dev/null and b/release/ui-grid-unstable.eot differ
    diff --git a/release/ui-grid-unstable.js b/release/ui-grid-unstable.js
    new file mode 100644
    index 000000000..27ce7aac7
    --- /dev/null
    +++ b/release/ui-grid-unstable.js
    @@ -0,0 +1,20169 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20-5f155b2 - 2015-03-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid.i18n', []);
    +  angular.module('ui.grid', ['ui.grid.i18n']);
    +})();
    +(function () {
    +  'use strict';
    +  angular.module('ui.grid').constant('uiGridConstants', {
    +    LOG_DEBUG_MESSAGES: true,
    +    LOG_WARN_MESSAGES: true,
    +    LOG_ERROR_MESSAGES: true,
    +    CUSTOM_FILTERS: /CUSTOM_FILTERS/g,
    +    COL_FIELD: /COL_FIELD/g,
    +    MODEL_COL_FIELD: /MODEL_COL_FIELD/g,
    +    DISPLAY_CELL_TEMPLATE: /DISPLAY_CELL_TEMPLATE/g,
    +    TEMPLATE_REGEXP: /<.+>/,
    +    FUNC_REGEXP: /(\([^)]*\))?$/,
    +    DOT_REGEXP: /\./g,
    +    APOS_REGEXP: /'/g,
    +    BRACKET_REGEXP: /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,
    +    COL_CLASS_PREFIX: 'ui-grid-col',
    +    events: {
    +      GRID_SCROLL: 'uiGridScroll',
    +      COLUMN_MENU_SHOWN: 'uiGridColMenuShown',
    +      ITEM_DRAGGING: 'uiGridItemDragStart', // For any item being dragged
    +      COLUMN_HEADER_CLICK: 'uiGridColumnHeaderClick'
    +    },
    +    // copied from http://www.lsauer.com/2011/08/javascript-keymap-keycodes-in-json.html
    +    keymap: {
    +      TAB: 9,
    +      STRG: 17,
    +      CTRL: 17,
    +      CTRLRIGHT: 18,
    +      CTRLR: 18,
    +      SHIFT: 16,
    +      RETURN: 13,
    +      ENTER: 13,
    +      BACKSPACE: 8,
    +      BCKSP: 8,
    +      ALT: 18,
    +      ALTR: 17,
    +      ALTRIGHT: 17,
    +      SPACE: 32,
    +      WIN: 91,
    +      MAC: 91,
    +      FN: null,
    +      PG_UP: 33,
    +      PG_DOWN: 34,
    +      UP: 38,
    +      DOWN: 40,
    +      LEFT: 37,
    +      RIGHT: 39,
    +      ESC: 27,
    +      DEL: 46,
    +      F1: 112,
    +      F2: 113,
    +      F3: 114,
    +      F4: 115,
    +      F5: 116,
    +      F6: 117,
    +      F7: 118,
    +      F8: 119,
    +      F9: 120,
    +      F10: 121,
    +      F11: 122,
    +      F12: 123
    +    },
    +    ASC: 'asc',
    +    DESC: 'desc',
    +    filter: {
    +      STARTS_WITH: 2,
    +      ENDS_WITH: 4,
    +      EXACT: 8,
    +      CONTAINS: 16,
    +      GREATER_THAN: 32,
    +      GREATER_THAN_OR_EQUAL: 64,
    +      LESS_THAN: 128,
    +      LESS_THAN_OR_EQUAL: 256,
    +      NOT_EQUAL: 512
    +    },
    +
    +    aggregationTypes: {
    +      sum: 2,
    +      count: 4,
    +      avg: 8,
    +      min: 16,
    +      max: 32
    +    },
    +
    +    // TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
    +    CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],
    +
    +    scrollDirection: {
    +      UP: 'up',
    +      DOWN: 'down',
    +      LEFT: 'left',
    +      RIGHT: 'right',
    +      NONE: 'none'
    +
    +    },
    +
    +    dataChange: {
    +      ALL: 'all',
    +      EDIT: 'edit',
    +      ROW: 'row',
    +      COLUMN: 'column',
    +      OPTIONS: 'options'
    +    },
    +    scrollbars: {
    +      NEVER: 0,
    +      ALWAYS: 1
    +      //WHEN_NEEDED: 2
    +    }
    +  });
    +
    +})();
    +angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUtil', 'uiGridConstants', function ($compile, $parse, gridUtil, uiGridConstants) {
    +  var uiGridCell = {
    +    priority: 0,
    +    scope: false,
    +    require: '?^uiGrid',
    +    compile: function() {
    +      return {
    +        pre: function($scope, $elm, $attrs, uiGridCtrl) {
    +          function compileTemplate() {
    +            var compiledElementFn = $scope.col.compiledElementFn;
    +
    +            compiledElementFn($scope, function(clonedElement, scope) {
    +              $elm.append(clonedElement);
    +            });
    +          }
    +
    +          // If the grid controller is present, use it to get the compiled cell template function
    +          if (uiGridCtrl && $scope.col.compiledElementFn) {
    +             compileTemplate();
    +          }
    +          // No controller, compile the element manually (for unit tests)
    +          else {
    +            if ( uiGridCtrl && !$scope.col.compiledElementFn ){
    +              // gridUtil.logError('Render has been called before precompile.  Please log a ui-grid issue');  
    +
    +              $scope.col.getCompiledElementFn()
    +                .then(function (compiledElementFn) {
    +                  compiledElementFn($scope, function(clonedElement, scope) {
    +                    $elm.append(clonedElement);
    +                  });
    +                });
    +            }
    +            else {
    +              var html = $scope.col.cellTemplate
    +                .replace(uiGridConstants.MODEL_COL_FIELD, 'row.entity.' + gridUtil.preEval($scope.col.field))
    +                .replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +              var cellElement = $compile(html)($scope);
    +              $elm.append(cellElement);
    +            }
    +          }
    +        },
    +        post: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var initColClass = $scope.col.getColClass(false);
    +          $elm.addClass(initColClass);
    +
    +          var classAdded;
    +          var updateClass = function( grid ){
    +            var contents = $elm;
    +            if ( classAdded ){
    +              contents.removeClass( classAdded );
    +              classAdded = null;
    +            }
    +
    +            if (angular.isFunction($scope.col.cellClass)) {
    +              classAdded = $scope.col.cellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +            }
    +            else {
    +              classAdded = $scope.col.cellClass;
    +            }
    +            contents.addClass(classAdded);
    +          };
    +
    +          if ($scope.col.cellClass) {
    +            updateClass();
    +          }
    +          
    +          // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +          var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN, uiGridConstants.dataChange.EDIT]);
    +          
    +          // watch the col and row to see if they change - which would indicate that we've scrolled or sorted or otherwise
    +          // changed the row/col that this cell relates to, and we need to re-evaluate cell classes and maybe other things
    +          var cellChangeFunction = function( n, o ){
    +            if ( n !== o ) {
    +              if ( classAdded || $scope.col.cellClass ){
    +                updateClass();
    +              }
    +
    +              // See if the column's internal class has changed
    +              var newColClass = $scope.col.getColClass(false);
    +              if (newColClass !== initColClass) {
    +                $elm.removeClass(initColClass);
    +                $elm.addClass(newColClass);
    +                initColClass = newColClass;
    +              }
    +            }
    +          };
    +
    +          // TODO(c0bra): Turn this into a deep array watch
    +          var colWatchDereg = $scope.$watch( 'col', cellChangeFunction );
    +          var rowWatchDereg = $scope.$watch( 'row', cellChangeFunction );
    +          
    +          
    +          var deregisterFunction = function() {
    +            dataChangeDereg();
    +            colWatchDereg();
    +            rowWatchDereg(); 
    +          };
    +          
    +          $scope.$on( '$destroy', deregisterFunction );
    +          $elm.on( '$destroy', deregisterFunction );
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridCell;
    +}]);
    +
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridColumnMenuService', [ 'i18nService', 'uiGridConstants', 'gridUtil', 
    +function ( i18nService, uiGridConstants, gridUtil ) {
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:uiGridColumnMenuService
    + *
    + *  @description Services for working with column menus, factored out
    + *  to make the code easier to understand
    + */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name initialize
    +     * @description  Sets defaults, puts a reference to the $scope on 
    +     * the uiGridController
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */
    +    initialize: function( $scope, uiGridCtrl ){
    +      $scope.grid = uiGridCtrl.grid;
    +
    +      // Store a reference to this link/controller in the main uiGrid controller
    +      // to allow showMenu later
    +      uiGridCtrl.columnMenuScope = $scope;
    +      
    +      // Save whether we're shown or not so the columns can check
    +      $scope.menuShown = false;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name setColMenuItemWatch
    +     * @description  Setup a watch on $scope.col.menuItems, and update
    +     * menuItems based on this.  $scope.col needs to be set by the column
    +     * before calling the menu.
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {controller} uiGridCtrl the uiGridController for the grid
    +     * we're on
    +     * 
    +     */    
    +    setColMenuItemWatch: function ( $scope ){
    +      var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
    +        if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
    +          n.forEach(function (item) {
    +            if (typeof(item.context) === 'undefined' || !item.context) {
    +              item.context = {};
    +            }
    +            item.context.col = $scope.col;
    +          });
    +
    +          $scope.menuItems = $scope.defaultMenuItems.concat(n);
    +        }
    +        else {
    +          $scope.menuItems = $scope.defaultMenuItems;
    +        }
    +      }); 
    +      
    +      $scope.$on( '$destroy', deregFunction );     
    +    },
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableSorting
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When enabled, this setting adds sort
    +     * widgets to the column header, allowing sorting of the data in the individual column.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name sortable
    +     * @description  determines whether this column is sortable
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */    
    +    sortable: function( $scope ) {
    +      if ( $scope.grid.options.enableSorting && typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.enableSorting) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name isActiveSort
    +     * @description  determines whether the requested sort direction is current active, to 
    +     * allow highlighting in the menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {string} direction the direction that we'd have selected for us to be active
    +     * 
    +     */  
    +    isActiveSort: function( $scope, direction ){
    +      return (typeof($scope.col) !== 'undefined' && typeof($scope.col.sort) !== 'undefined' && 
    +              typeof($scope.col.sort.direction) !== 'undefined' && $scope.col.sort.direction === direction);
    +      
    +    },
    +    
    +    /**
    +     * @ngdoc boolean
    +     * @name suppressRemoveSort
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) False by default. When enabled, this setting hides the removeSort option
    +     * in the menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name suppressRemoveSort
    +     * @description  determines whether we should suppress the removeSort option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    suppressRemoveSort: function( $scope ) {
    +      if ($scope.col && $scope.col.colDef && $scope.col.colDef.suppressRemoveSort) {
    +        return true;
    +      }
    +      else {
    +        return false;
    +      }
    +    },       
    +
    +
    +    /**
    +     * @ngdoc boolean
    +     * @name enableHiding
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description (optional) True by default. When set to false, this setting prevents a user from hiding the column
    +     * using the column menu or the grid menu.
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name hideable
    +     * @description  determines whether a column can be hidden, by checking the enableHiding columnDef option
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */  
    +    hideable: function( $scope ) {
    +      if (typeof($scope.col) !== 'undefined' && $scope.col && $scope.col.colDef && $scope.col.colDef.enableHiding === false ) {
    +        return false;
    +      }
    +      else {
    +        return true;
    +      }
    +    },     
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getDefaultMenuItems
    +     * @description  returns the default menu items for a column menu
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * 
    +     */     
    +    getDefaultMenuItems: function( $scope ){
    +      return [
    +        {
    +          title: i18nService.getSafeText('sort.ascending'),
    +          icon: 'ui-grid-icon-sort-alt-up',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.ASC);
    +          },
    +          shown: function () {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.ASC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.descending'),
    +          icon: 'ui-grid-icon-sort-alt-down',
    +          action: function($event) {
    +            $event.stopPropagation();
    +            $scope.sortColumn($event, uiGridConstants.DESC);
    +          },
    +          shown: function() {
    +            return service.sortable( $scope );
    +          },
    +          active: function() {
    +            return service.isActiveSort( $scope, uiGridConstants.DESC);
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('sort.remove'),
    +          icon: 'ui-grid-icon-cancel',
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.unsortColumn();
    +          },
    +          shown: function() {
    +            return service.sortable( $scope ) && 
    +                   typeof($scope.col) !== 'undefined' && (typeof($scope.col.sort) !== 'undefined' && 
    +                   typeof($scope.col.sort.direction) !== 'undefined') && $scope.col.sort.direction !== null &&
    +                  !service.suppressRemoveSort( $scope );
    +          }
    +        },
    +        {
    +          title: i18nService.getSafeText('column.hide'),
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function() {
    +            return service.hideable( $scope );
    +          },
    +          action: function ($event) {
    +            $event.stopPropagation();
    +            $scope.hideColumn();
    +          }
    +        }
    +      ];
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name getColumnElementPosition
    +     * @description  gets the position information needed to place the column
    +     * menu below the column header
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {element} $columnElement the column element we want to position below
    +     * @returns {hash} containing left, top, offset, height, width
    +     * 
    +     */  
    +    getColumnElementPosition: function( $scope, column, $columnElement ){
    +      var positionData = {};
    +      positionData.left = $columnElement[0].offsetLeft;
    +      positionData.top = $columnElement[0].offsetTop;
    +      positionData.parentLeft = $columnElement[0].offsetParent.offsetLeft;
    +
    +      // Get the grid scrollLeft
    +      positionData.offset = 0;
    +      if (column.grid.options.offsetLeft) {
    +        positionData.offset = column.grid.options.offsetLeft;
    +      }
    +
    +      positionData.height = gridUtil.elementHeight($columnElement, true);
    +      positionData.width = gridUtil.elementWidth($columnElement, true);
    +      
    +      return positionData;
    +    },
    +    
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:uiGridColumnMenuService
    +     * @name repositionMenu
    +     * @description  Reposition the menu below the new column.  If the menu has no child nodes 
    +     * (i.e. it's not currently visible) then we guess it's width at 100, we'll be called again
    +     * later to fix it
    +     * @param {$scope} $scope the $scope from the uiGridColumnMenu
    +     * @param {GridCol} column the column we want to position below
    +     * @param {hash} positionData a hash containing left, top, offset, height, width
    +     * @param {element} $elm the column menu element that we want to reposition
    +     * @param {element} $columnElement the column element that we want to reposition underneath
    +     * 
    +     */  
    +    repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
    +      var menu = $elm[0].querySelectorAll('.ui-grid-menu');
    +      var containerId = column.renderContainer ? column.renderContainer : 'body';
    +      var renderContainer = column.grid.renderContainers[containerId];
    +
    +      // It's possible that the render container of the column we're attaching to is 
    +      // offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft 
    +      // between the render container and the grid
    +      var renderContainerElm = gridUtil.closestElm($columnElement, '.ui-grid-render-container');
    +      var renderContainerOffset = renderContainerElm.getBoundingClientRect().left - $scope.grid.element[0].getBoundingClientRect().left;
    +
    +      var containerScrollLeft = renderContainerElm.querySelectorAll('.ui-grid-viewport')[0].scrollLeft;
    +
    +      // default value the last width for _this_ column, otherwise last width for _any_ column, otherwise default to 170
    +      var myWidth = column.lastMenuWidth ? column.lastMenuWidth : ( $scope.lastMenuWidth ? $scope.lastMenuWidth : 170);
    +      var paddingRight = column.lastMenuPaddingRight ? column.lastMenuPaddingRight : ( $scope.lastMenuPaddingRight ? $scope.lastMenuPaddingRight : 10);
    +      
    +      if ( menu.length !== 0 ){
    +        var mid = menu[0].querySelectorAll('.ui-grid-menu-mid'); 
    +        if ( mid.length !== 0 && !angular.element(mid).hasClass('ng-hide') ) {
    +          myWidth = gridUtil.elementWidth(menu, true);
    +          $scope.lastMenuWidth = myWidth;
    +          column.lastMenuWidth = myWidth;
    +  
    +          // TODO(c0bra): use padding-left/padding-right based on document direction (ltr/rtl), place menu on proper side
    +          // Get the column menu right padding
    +          paddingRight = parseInt(gridUtil.getStyles(angular.element(menu)[0])['paddingRight'], 10);
    +          $scope.lastMenuPaddingRight = paddingRight;
    +          column.lastMenuPaddingRight = paddingRight;
    +        }
    +      }
    +      
    +      var left = positionData.left + renderContainerOffset - containerScrollLeft + positionData.parentLeft + positionData.width - myWidth + paddingRight;
    +      if (left < positionData.offset){
    +        left = positionData.offset;
    +      }
    +
    +      $elm.css('left', left + 'px');
    +      $elm.css('top', (positionData.top + positionData.height) + 'px');
    +    }    
    +
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +.directive('uiGridColumnMenu', ['$timeout', 'gridUtil', 'uiGridConstants', 'uiGridColumnMenuService', 
    +function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService) {
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @description  Provides the column menu framework, leverages uiGridMenu underneath
    + * 
    + */
    +
    +  var uiGridColumnMenu = {
    +    priority: 0,
    +    scope: true,
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridColumnMenu',
    +    replace: true,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      
    +      uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
    +
    +      $scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
    +
    +      // Set the menu items for use with the column menu. The user can later add additional items via the watch
    +      $scope.menuItems = $scope.defaultMenuItems;
    +      uiGridColumnMenuService.setColMenuItemWatch( $scope );
    +
    +  
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name showMenu
    +       * @description Shows the column menu.  If the menu is already displayed it
    +       * calls the menu to ask it to hide (it will animate), then it repositions the menu
    +       * to the right place whilst hidden (it will make an assumption on menu width), 
    +       * then it asks the menu to show (it will animate), then it repositions the menu again 
    +       * once we can calculate it's size.
    +       * @param {GridCol} column the column we want to position below
    +       * @param {element} $columnElement the column element we want to position below
    +       */
    +      $scope.showMenu = function(column, $columnElement, event) {
    +        // Swap to this column
    +        $scope.col = column;
    +
    +        // Get the position information for the column element
    +        var colElementPosition = uiGridColumnMenuService.getColumnElementPosition( $scope, column, $columnElement );
    +
    +        if ($scope.menuShown) {
    +          // we want to hide, then reposition, then show, but we want to wait for animations
    +          // we set a variable, and then rely on the menu-hidden event to call the reposition and show
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.hideThenShow = true;
    +
    +          $scope.$broadcast('hide-menu', { originalEvent: event });
    +        } else {
    +          self.shown = $scope.menuShown = true;
    +          uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
    +
    +          $scope.colElement = $columnElement;
    +          $scope.colElementPosition = colElementPosition;
    +          $scope.$broadcast('show-menu', { originalEvent: event });
    +        } 
    +
    +      };
    +
    +
    +      /**
    +       * @ngdoc method
    +       * @methodOf ui.grid.directive:uiGridColumnMenu
    +       * @name hideMenu
    +       * @description Hides the column menu.
    +       * @param {boolean} broadcastTrigger true if we were triggered by a broadcast
    +       * from the menu itself - in which case don't broadcast again as we'll get
    +       * an infinite loop
    +       */
    +      $scope.hideMenu = function( broadcastTrigger ) {
    +        // delete $scope.col;
    +        $scope.menuShown = false;
    +        
    +        if ( !broadcastTrigger ){
    +          $scope.$broadcast('hide-menu');
    +        }
    +      };
    +
    +      
    +      $scope.$on('menu-hidden', function() {
    +        if ( $scope.hideThenShow ){
    +          delete $scope.hideThenShow;
    +
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          $scope.$broadcast('show-menu');
    +
    +          $scope.menuShown = true;
    +        } else {
    +          $scope.hideMenu( true );
    +        }
    +      });
    +      
    +      $scope.$on('menu-shown', function() {
    +        $timeout( function() {
    +          uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
    +          delete $scope.colElementPosition;
    +          delete $scope.columnElement;
    +        }, 200);
    +      });
    +
    + 
    +      /* Column methods */
    +      $scope.sortColumn = function (event, dir) {
    +        event.stopPropagation();
    +
    +        $scope.grid.sortColumn($scope.col, dir, true)
    +          .then(function () {
    +            $scope.grid.refresh();
    +            $scope.hideMenu();
    +          });
    +      };
    +
    +      $scope.unsortColumn = function () {
    +        $scope.col.unsort();
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +      };
    +
    +      $scope.hideColumn = function () {
    +        $scope.col.colDef.visible = false;
    +
    +        $scope.grid.refresh();
    +        $scope.hideMenu();
    +        $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +        $scope.grid.api.core.raise.columnVisibilityChanged( $scope.col );        
    +      };
    +    },
    +    
    +    
    +    
    +    controller: ['$scope', function ($scope) {
    +      var self = this;
    +      
    +      $scope.$watch('menuItems', function (n, o) {
    +        self.menuItems = n;
    +      });
    +    }]
    +  };
    +
    +  return uiGridColumnMenu;
    +
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooterCell', ['$timeout', 'gridUtil', 'uiGridConstants', '$compile',
    +  function ($timeout, gridUtil, uiGridConstants, $compile) {
    +    var uiGridFooterCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      replace: true,
    +      require: '^uiGrid',
    +      compile: function compile(tElement, tAttrs, transclude) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
    +            $elm.append(cellFooter);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            //$elm.addClass($scope.col.getColClass(false));
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $elm.addClass($scope.col.getColClass(false));
    +
    +            // apply any footerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.footerCellClass)) {
    +                classAdded = $scope.col.footerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.footerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +            };
    +  
    +            if ($scope.col.footerCellClass) {
    +              updateClass();
    +            }
    +
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridFooterCell;
    +  }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerTemplate = ($scope.grid.options.footerTemplate) ? $scope.grid.options.footerTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the footer viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +
    +                  if (footerViewport) {
    +                    containerCtrl.footerViewport = footerViewport;
    +                  }
    +                }
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-footer link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate footer cells
    +            gridUtil.disableAnimations($elm);
    +
    +            containerCtrl.footer = $elm;
    +
    +            var footerViewport = $elm[0].getElementsByClassName('ui-grid-footer-viewport')[0];
    +            if (footerViewport) {
    +              containerCtrl.footerViewport = footerViewport;
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGridFooter', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function ($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-grid-footer';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      // priority: 1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            var footerTemplate = ($scope.grid.options.gridFooterTemplate) ? $scope.grid.options.gridFooterTemplate : defaultTemplate;
    +            gridUtil.getTemplate(footerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridGroupPanel', ["$compile", "uiGridConstants", "gridUtil", function($compile, uiGridConstants, gridUtil) {
    +    var defaultTemplate = 'ui-grid/ui-grid-group-panel';
    +
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      require: '?^uiGrid',
    +      scope: false,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var groupPanelTemplate = $scope.grid.options.groupPanelTemplate  || defaultTemplate;
    +
    +             gridUtil.getTemplate(groupPanelTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            $elm.bind('$destroy', function() {
    +              // scrollUnbinder();
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeaderCell', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 'ScrollEvent',
    +  function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, ScrollEvent) {
    +    // Do stuff after mouse has been down this many ms on the header cell
    +    var mousedownTimeout = 500;
    +
    +    var uiGridHeaderCell = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        row: '=',
    +        renderIndex: '='
    +      },
    +      require: ['?^uiGrid', '^uiGridRenderContainer'],
    +      replace: true,
    +      compile: function() {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
    +            $elm.append(cellHeader);
    +          },
    +          
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var renderContainerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +
    +            $scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];
    +            
    +            var initColClass = $scope.col.getColClass(false);
    +            $elm.addClass(initColClass);
    +    
    +            // Hide the menu by default
    +            $scope.menuShown = false;
    +    
    +            // Put asc and desc sort directions in scope
    +            $scope.asc = uiGridConstants.ASC;
    +            $scope.desc = uiGridConstants.DESC;
    +    
    +            // Store a reference to menu element
    +            var $colMenu = angular.element( $elm[0].querySelectorAll('.ui-grid-header-cell-menu') );
    +    
    +            var $contentsElm = angular.element( $elm[0].querySelectorAll('.ui-grid-cell-contents') );
    +    
    +
    +            // apply any headerCellClass
    +            var classAdded;
    +            var updateClass = function( grid ){
    +              var contents = $elm;
    +              if ( classAdded ){
    +                contents.removeClass( classAdded );
    +                classAdded = null;
    +              }
    +  
    +              if (angular.isFunction($scope.col.headerCellClass)) {
    +                classAdded = $scope.col.headerCellClass($scope.grid, $scope.row, $scope.col, $scope.rowRenderIndex, $scope.colRenderIndex);
    +              }
    +              else {
    +                classAdded = $scope.col.headerCellClass;
    +              }
    +              contents.addClass(classAdded);
    +              
    +              var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
    +              $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
    +            };
    +
    +            $scope.$watch('col', function (n, o) {
    +              if (n !== o) {
    +                // See if the column's internal class has changed
    +                var newColClass = $scope.col.getColClass(false);
    +                if (newColClass !== initColClass) {
    +                  $elm.removeClass(initColClass);
    +                  $elm.addClass(newColClass);
    +                  initColClass = newColClass;
    +                }
    +              }
    +            });
    +  
    +            updateClass();
    +            
    +            // Register a data change watch that would get triggered whenever someone edits a cell or modifies column defs
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( updateClass, [uiGridConstants.dataChange.COLUMN]);
    +
    +            $scope.$on( '$destroy', dataChangeDereg );            
    +
    +
    +            // Figure out whether this column is sortable or not
    +            if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +              $scope.sortable = true;
    +            }
    +            else {
    +              $scope.sortable = false;
    +            }
    +    
    +            // Figure out whether this column is filterable or not
    +            if (uiGridCtrl.grid.options.enableFiltering && $scope.col.enableFiltering) {
    +              $scope.filterable = true;
    +            }
    +            else {
    +              $scope.filterable = false;
    +            }
    +            
    +            // figure out whether we support column menus
    +            if ($scope.col.grid.options && $scope.col.grid.options.enableColumnMenus !== false && 
    +                    $scope.col.colDef && $scope.col.colDef.enableColumnMenu !== false){
    +              $scope.colMenu = true;
    +            } else {
    +              $scope.colMenu = false;
    +            }
    +    
    +            function handleClick(event) {
    +              // If the shift key is being held down, add this column to the sort
    +              var add = false;
    +              if (event.shiftKey) {
    +                add = true;
    +              }
    +    
    +              // Sort this column then rebuild the grid's rows
    +              uiGridCtrl.grid.sortColumn($scope.col, add)
    +                .then(function () {
    +                  if (uiGridCtrl.columnMenuScope) { uiGridCtrl.columnMenuScope.hideMenu(); }
    +                  uiGridCtrl.grid.refresh();
    +                });
    +            }
    +    
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenu
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description if column menus are enabled, controls the column menus for this specific
    +            * column (i.e. if gridOptions.enableColumnMenus, then you can control column menus
    +            * using this option. If gridOptions.enableColumnMenus === false then you get no column
    +            * menus irrespective of the value of this option ).  Defaults to true.
    +            *
    +            */
    +            /**
    +            * @ngdoc property
    +            * @name enableColumnMenus
    +            * @propertyOf ui.grid.class:GridOptions.columnDef
    +            * @description Override for column menus everywhere - if set to false then you get no
    +            * column menus.  Defaults to true.
    +            *
    +            */
    +
    +            if ($scope.sortable || $scope.colMenu) {
    +              // Long-click (for mobile)
    +              var cancelMousedownTimeout;
    +              var mousedownStartTime = 0;
    +
    +              var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
    +              $contentsElm.on(downEvent, function(event) {
    +                event.stopPropagation();
    +
    +                if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                  event = event.originalEvent;
    +                }
    +      
    +                // Don't show the menu if it's not the left button
    +                if (event.button && event.button !== 0) {
    +                  return;
    +                }
    +      
    +                mousedownStartTime = (new Date()).getTime();
    +      
    +                cancelMousedownTimeout = $timeout(function() { }, mousedownTimeout);
    +      
    +                cancelMousedownTimeout.then(function () {
    +                  if ( $scope.colMenu ) {
    +                    uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm, event);
    +                  }
    +                });
    +
    +                uiGridCtrl.fireEvent(uiGridConstants.events.COLUMN_HEADER_CLICK, {event: event, columnName: $scope.col.colDef.name});
    +              });
    +        
    +              var upEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'mouseup';
    +              $contentsElm.on(upEvent, function () {
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +  
    +              $scope.$on('$destroy', function () {
    +                $contentsElm.off('mousedown touchstart');
    +              });
    +            }
    +
    +
    +            $scope.toggleMenu = function(event) {
    +              event.stopPropagation();
    +    
    +              // If the menu is already showing...
    +              if (uiGridCtrl.columnMenuScope.menuShown) {
    +                // ... and we're the column the menu is on...
    +                if (uiGridCtrl.columnMenuScope.col === $scope.col) {
    +                  // ... hide it
    +                  uiGridCtrl.columnMenuScope.hideMenu();
    +                }
    +                // ... and we're NOT the column the menu is on
    +                else {
    +                  // ... move the menu to our column
    +                  uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +                }
    +              }
    +              // If the menu is NOT showing
    +              else {
    +                // ... show it on our column
    +                uiGridCtrl.columnMenuScope.showMenu($scope.col, $elm);
    +              }
    +            };
    +    
    +            // If this column is sortable, add a click event handler
    +            if ($scope.sortable) {
    +              var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
    +              $contentsElm.on(clickEvent, function(event) {
    +                event.stopPropagation();
    +    
    +                $timeout.cancel(cancelMousedownTimeout);
    +    
    +                var mousedownEndTime = (new Date()).getTime();
    +                var mousedownTime = mousedownEndTime - mousedownStartTime;
    +    
    +                if (mousedownTime > mousedownTimeout) {
    +                  // long click, handled above with mousedown
    +                }
    +                else {
    +                  // short click
    +                  handleClick(event);
    +                }
    +              });
    +    
    +              $scope.$on('$destroy', function () {
    +                // Cancel any pending long-click timeout
    +                $timeout.cancel(cancelMousedownTimeout);
    +              });
    +            }
    +    
    +            if ($scope.filterable) {
    +              var filterDeregisters = [];
    +              angular.forEach($scope.col.filters, function(filter, i) {
    +                filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
    +                  if (n !== o) {
    +                    uiGridCtrl.grid.api.core.raise.filterChanged();
    +                    uiGridCtrl.grid.refresh(true);
    +                  }
    +                }));  
    +              });
    +              $scope.$on('$destroy', function() {
    +                angular.forEach(filterDeregisters, function(filterDeregister) {
    +                  filterDeregister();
    +                });
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +
    +    return uiGridHeaderCell;
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridHeader', ['$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    +    var defaultTemplate = 'ui-grid/ui-grid-header';
    +    var emptyTemplate = 'ui-grid/ui-grid-no-header';
    +
    +    return {
    +      restrict: 'EA',
    +      // templateUrl: 'ui-grid/ui-grid-header',
    +      replace: true,
    +      // priority: 1000,
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: true,
    +      compile: function($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            updateHeaderReferences();
    +            
    +            var headerTemplate;
    +            if (!$scope.grid.options.showHeader) {
    +              headerTemplate = emptyTemplate;
    +            }
    +            else {
    +              headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;            
    +            }
    +
    +            gridUtil.getTemplate(headerTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                
    +                var newElm = $compile(template)($scope);
    +                $elm.replaceWith(newElm);
    +
    +                // And update $elm to be the new element
    +                $elm = newElm;
    +
    +                updateHeaderReferences();
    +
    +                if (containerCtrl) {
    +                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
    +                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +
    +                  if (headerViewport) {
    +                    containerCtrl.headerViewport = headerViewport;
    +                  }
    +                }
    +
    +                $scope.grid.queueRefresh();
    +              });
    +
    +            function updateHeaderReferences() {
    +              containerCtrl.header = containerCtrl.colContainer.header = $elm;
    +
    +              var headerCanvases = $elm[0].getElementsByClassName('ui-grid-header-canvas');
    +
    +              if (headerCanvases.length > 0) {
    +                containerCtrl.headerCanvas = containerCtrl.colContainer.headerCanvas = headerCanvases[0];
    +              }
    +              else {
    +                containerCtrl.headerCanvas = null;
    +              }
    +            }
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            // gridUtil.logDebug('ui-grid-header link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            // Don't animate header cells
    +            gridUtil.disableAnimations($elm);
    +
    +            function updateColumnWidths() {
    +              // Get the width of the viewport
    +              var availableWidth = containerCtrl.colContainer.getViewportWidth() - grid.scrollbarWidth;
    +
    +              //if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
    +              //  availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
    +              //}
    +
    +              // The total number of columns
    +              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +              // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +              var columnCache = containerCtrl.colContainer.visibleColumnCache,
    +                  canvasWidth = 0,
    +                  asteriskNum = 0,
    +                  oneAsterisk = 0,
    +                  leftoverWidth = availableWidth,
    +                  hasVariableWidth = false;
    +              
    +              var getColWidth = function(column){
    +                if (column.widthType === "manual"){ 
    +                  return +column.width; 
    +                }
    +                else if (column.widthType === "percent"){ 
    +                  return parseInt(column.width.replace(/%/g, ''), 10) * availableWidth / 100;
    +                }
    +                else if (column.widthType === "auto"){
    +                  // leftOverWidth is subtracted from after each call to this
    +                  // function so we need to calculate oneAsterisk size only once
    +                  if (oneAsterisk === 0) {
    +                    oneAsterisk = parseInt(leftoverWidth / asteriskNum, 10);
    +                  }
    +                  return column.width.length * oneAsterisk; 
    +                }
    +              };
    +              
    +              // Populate / determine column width types:
    +              columnCache.forEach(function(column){
    +                column.widthType = null;
    +                if (isFinite(+column.width)){
    +                  column.widthType = "manual";
    +                }
    +                else if (gridUtil.endsWith(column.width, "%")){
    +                  column.widthType = "percent";
    +                  hasVariableWidth = true;
    +                }
    +                else if (angular.isString(column.width) && column.width.indexOf('*') !== -1){
    +                  column.widthType = "auto";
    +                  asteriskNum += column.width.length;
    +                  hasVariableWidth = true;
    +                }
    +              });
    +              
    +              // For sorting, calculate width from first to last:
    +              var colWidthPriority = ["manual", "percent", "auto"];
    +              columnCache.filter(function(column){
    +                // Only draw visible items with a widthType
    +                return (column.visible && column.widthType); 
    +              }).sort(function(a,b){
    +                // Calculate widths in order, so that manual comes first, etc.
    +                return colWidthPriority.indexOf(a.widthType) - colWidthPriority.indexOf(b.widthType);
    +              }).forEach(function(column){
    +                // Calculate widths:
    +                var colWidth = getColWidth(column);
    +                if (column.minWidth){
    +                  colWidth = Math.max(colWidth, column.minWidth);
    +                }
    +                if (column.maxWidth){
    +                  colWidth = Math.min(colWidth, column.maxWidth);
    +                }
    +                column.drawnWidth = Math.floor(colWidth);
    +                canvasWidth += column.drawnWidth;
    +                leftoverWidth -= column.drawnWidth;
    +              });
    +
    +              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +              if (hasVariableWidth && leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +                var remFn = function (column) {
    +                  if (leftoverWidth > 0 && (column.widthType === "auto" || column.widthType === "percent")) {
    +                    column.drawnWidth = column.drawnWidth + 1;
    +                    canvasWidth = canvasWidth + 1;
    +                    leftoverWidth--;
    +                  }
    +                };
    +                var prevLeftover = 0;
    +                do {
    +                  prevLeftover = leftoverWidth;
    +                  columnCache.forEach(remFn);
    +                } while (leftoverWidth > 0 && leftoverWidth !== prevLeftover );
    +              }
    +              canvasWidth = Math.max(canvasWidth, availableWidth);
    +
    +              // Build the CSS
    +              // uiGridCtrl.grid.columns.forEach(function (column) {
    +              var ret = '';
    +              columnCache.forEach(function (column) {
    +                ret = ret + column.getColClassDefinition();
    +              });
    +
    +              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getViewportWidth
    +              //if (grid.verticalScrollbarWidth) {
    +              //  canvasWidth = canvasWidth + grid.verticalScrollbarWidth;
    +              //}
    +              // canvasWidth = canvasWidth + 1;
    +
    +              // if we have a grid menu, then we prune the width of the last column header
    +              // to allow room for the button whilst still getting to the column menu
    +              if (columnCache.length > 0) { // && grid.options.enableGridMenu) {
    +                columnCache[columnCache.length - 1].headerWidth = columnCache[columnCache.length - 1].drawnWidth - 30;
    +              }
    +
    +              containerCtrl.colContainer.canvasWidth = parseInt(canvasWidth, 10);
    +
    +              // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +              return ret;
    +            }
    +            
    +            containerCtrl.header = $elm;
    +            
    +            var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
    +            if (headerViewport) {
    +              containerCtrl.headerViewport = headerViewport;
    +            }
    +
    +            //todo: remove this if by injecting gridCtrl into unit tests
    +            if (uiGridCtrl) {
    +              uiGridCtrl.grid.registerStyleComputation({
    +                priority: 5,
    +                func: updateColumnWidths
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.service('uiGridGridMenuService', [ 'gridUtil', 'i18nService', 'uiGridConstants', function( gridUtil, i18nService, uiGridConstants ) {
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.gridMenuService
    +   *
    +   *  @description Methods for working with the grid menu
    +   */
    +
    +  var service = {
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name initialize
    +     * @description Sets up the gridMenu. Most importantly, sets our
    +     * scope onto the grid object as grid.gridMenuScope, allowing us
    +     * to operate when passed only the grid.  Second most importantly, 
    +     * we register the 'addToGridMenu' and 'removeFromGridMenu' methods
    +     * on the core api.
    +     * @param {$scope} $scope the scope of this gridMenu
    +     * @param {Grid} grid the grid to which this gridMenu is associated
    +     */
    +    initialize: function( $scope, grid ){
    +      grid.gridMenuScope = $scope;
    +      $scope.grid = grid;
    +      $scope.registeredMenuItems = [];
    +      
    +      // not certain this is needed, but would be bad to create a memory leak
    +      $scope.$on('$destroy', function() {
    +        if ( $scope.grid && $scope.grid.gridMenuScope ){
    +          $scope.grid.gridMenuScope = null;
    +        }
    +        if ( $scope.grid ){
    +          $scope.grid = null;
    +        }
    +        if ( $scope.registeredMenuItems ){
    +          $scope.registeredMenuItems = null;
    +        }
    +      });
    +      
    +      $scope.registeredMenuItems = [];
    +
    +      /**
    +       * @ngdoc function
    +       * @name addToGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description add items to the grid menu.  Used by features
    +       * to add their menu items if they are enabled, can also be used by
    +       * end users to add menu items.  This method has the advantage of allowing
    +       * remove again, which can simplify management of which items are included
    +       * in the menu when.  (Noting that in most cases the shown and active functions
    +       * provide a better way to handle visibility of menu items)
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {array} items menu items in the format as described in the tutorial, with 
    +       * the added note that if you want to use remove you must also specify an `id` field,
    +       * which is provided when you want to remove an item.  The id should be unique.
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'addToGridMenu', service.addToGridMenu );
    +  
    +      /**
    +       * @ngdoc function
    +       * @name removeFromGridMenu
    +       * @methodOf ui.grid.core.api:PublicApi
    +       * @description Remove an item from the grid menu based on a provided id. Assumes
    +       * that the id is unique, removes only the last instance of that id. Does nothing if
    +       * the specified id is not found
    +       * @param {Grid} grid the grid on which we are acting
    +       * @param {string} id the id we'd like to remove from the menu
    +       * 
    +       */
    +      grid.api.registerMethod( 'core', 'removeFromGridMenu', service.removeFromGridMenu );
    +    },
    + 
    +    
    +    /**
    +     * @ngdoc function
    +     * @name addToGridMenu
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description add items to the grid menu.  Used by features
    +     * to add their menu items if they are enabled, can also be used by
    +     * end users to add menu items.  This method has the advantage of allowing
    +     * remove again, which can simplify management of which items are included
    +     * in the menu when.  (Noting that in most cases the shown and active functions
    +     * provide a better way to handle visibility of menu items)
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {array} items menu items in the format as described in the tutorial, with 
    +     * the added note that if you want to use remove you must also specify an `id` field,
    +     * which is provided when you want to remove an item.  The id should be unique.
    +     * 
    +     */
    +    addToGridMenu: function( grid, menuItems ) {
    +      if ( !angular.isArray( menuItems ) ) {
    +        gridUtil.logError( 'addToGridMenu: menuItems must be an array, and is not, not adding any items');
    +      } else {
    +        if ( grid.gridMenuScope ){
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems ? grid.gridMenuScope.registeredMenuItems : [];
    +          grid.gridMenuScope.registeredMenuItems = grid.gridMenuScope.registeredMenuItems.concat( menuItems );
    +        } else {
    +          gridUtil.logError( 'Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid');
    +        }
    +      }  
    +    },
    +    
    +
    +    /**
    +     * @ngdoc function
    +     * @name removeFromGridMenu
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Remove an item from the grid menu based on a provided id.  Assumes
    +     * that the id is unique, removes only the last instance of that id.  Does nothing if
    +     * the specified id is not found.  If there is no gridMenuScope or registeredMenuItems
    +     * then do nothing silently - the desired result is those menu items not be present and they
    +     * aren't.
    +     * @param {Grid} grid the grid on which we are acting
    +     * @param {string} id the id we'd like to remove from the menu
    +     * 
    +     */    
    +    removeFromGridMenu: function( grid, id ){
    +      var foundIndex = -1;
    +      
    +      if ( grid && grid.gridMenuScope ){
    +        grid.gridMenuScope.registeredMenuItems.forEach( function( value, index ) {
    +          if ( value.id === id ){
    +            if (foundIndex > -1) {
    +              gridUtil.logError( 'removeFromGridMenu: found multiple items with the same id, removing only the last' );
    +            } else {
    +              
    +              foundIndex = index;
    +            }
    +          }
    +        });
    +      }
    +
    +      if ( foundIndex > -1 ){
    +        grid.gridMenuScope.registeredMenuItems.splice( foundIndex, 1 );
    +      }
    +    },
    +    
    +        
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuCustomItems
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) An array of menu items that should be added to
    +     * the gridMenu.  Follow the format documented in the tutorial for column
    +     * menu customisation.  The context provided to the action function will 
    +     * include context.grid.  An alternative if working with dynamic menus is to use the 
    +     * provided api - core.addToGridMenu and core.removeFromGridMenu, which handles
    +     * some of the management of items for you.
    +     * 
    +     */
    +    /**
    +     * @ngdoc boolean
    +     * @name gridMenuShowHideColumns
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description true by default, whether the grid menu should allow hide/show
    +     * of columns
    +     * 
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name getMenuItems
    +     * @description Decides the menu items to show in the menu.  This is a
    +     * combination of:
    +     * 
    +     * - the default menu items that are always included, 
    +     * - any menu items that have been provided through the addMenuItem api. These
    +     *   are typically added by features within the grid
    +     * - any menu items included in grid.options.gridMenuCustomItems.  These can be
    +     *   changed dynamically, as they're always recalculated whenever we show the
    +     *   menu
    +     * @param {$scope} $scope the scope of this gridMenu, from which we can find all 
    +     * the information that we need
    +     * @returns {array} an array of menu items that can be shown 
    +     */
    +    getMenuItems: function( $scope ) {
    +      var menuItems = [
    +        // this is where we add any menu items we want to always include
    +      ];
    +      
    +      if ( $scope.grid.options.gridMenuCustomItems ){
    +        if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){ 
    +          gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not'); 
    +        } else {
    +          menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    +        }
    +      }
    +  
    +      menuItems = menuItems.concat( $scope.registeredMenuItems );
    +      
    +      if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    +        menuItems = menuItems.concat( service.showHideColumns( $scope ) );
    +      }
    +      
    +      return menuItems;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc array
    +     * @name gridMenuTitleFilter
    +     * @propertyOf ui.grid.class:GridOptions
    +     * @description (optional) A function that takes a title string 
    +     * (usually the col.displayName), and converts it into a display value.  The function
    +     * must return either a string or a promise.
    +     * 
    +     * Used for internationalization of the grid menu column names - for angular-translate
    +     * you can pass $translate as the function, for i18nService you can pass getSafeText as the 
    +     * function
    +     * @example
    +     * <pre>
    +     *   gridOptions = {
    +     *     gridMenuTitleFilter: $translate
    +     *   }
    +     * </pre>
    +     */
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name showHideColumns
    +     * @description Adds two menu items for each of the columns in columnDefs.  One
    +     * menu item for hide, one menu item for show.  Each is visible when appropriate
    +     * (show when column is not visible, hide when column is visible).  Each toggles
    +     * the visible property on the columnDef using toggleColumnVisibility
    +     * @param {$scope} $scope of a gridMenu, which contains a reference to the grid
    +     */
    +    showHideColumns: function( $scope ){
    +      var showHideColumns = [];
    +      if ( !$scope.grid.options.columnDefs || $scope.grid.options.columnDefs.length === 0 || $scope.grid.columns.length === 0 ) {
    +        return showHideColumns;
    +      }
    +      
    +      // add header for columns
    +      showHideColumns.push({
    +        title: i18nService.getSafeText('gridMenu.columns')
    +      });
    +      
    +      $scope.grid.options.gridMenuTitleFilter = $scope.grid.options.gridMenuTitleFilter ? $scope.grid.options.gridMenuTitleFilter : function( title ) { return title; };  
    +      
    +      $scope.grid.options.columnDefs.forEach( function( colDef, index ){
    +        if ( colDef.enableHiding !== false ){
    +          // add hide menu item - shows an OK icon as we only show when column is already visible
    +          var menuItem = {
    +            icon: 'ui-grid-icon-ok',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined;
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +
    +          // add show menu item - shows no icon as we only show when column is invisible
    +          menuItem = {
    +            icon: 'ui-grid-icon-cancel',
    +            action: function($event) {
    +              $event.stopPropagation();
    +              service.toggleColumnVisibility( this.context.gridCol );
    +            },
    +            shown: function() {
    +              return !(this.context.gridCol.colDef.visible === true || this.context.gridCol.colDef.visible === undefined);
    +            },
    +            context: { gridCol: $scope.grid.getColumn(colDef.name || colDef.field) }
    +          };
    +          service.setMenuItemTitle( menuItem, colDef, $scope.grid );
    +          showHideColumns.push( menuItem );
    +        }
    +      });
    +      return showHideColumns;
    +    },
    +    
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name setMenuItemTitle
    +     * @description Handles the response from gridMenuTitleFilter, adding it directly to the menu
    +     * item if it returns a string, otherwise waiting for the promise to resolve or reject then
    +     * putting the result into the title 
    +     * @param {object} menuItem the menuItem we want to put the title on
    +     * @param {object} colDef the colDef from which we can get displayName, name or field
    +     * @param {Grid} grid the grid, from which we can get the options.gridMenuTitleFilter
    +     * 
    +     */
    +    setMenuItemTitle: function( menuItem, colDef, grid ){
    +      var title = grid.options.gridMenuTitleFilter( colDef.displayName || colDef.name || colDef.field );
    +      
    +      if ( typeof(title) === 'string' ){
    +        menuItem.title = title;
    +      } else if ( title.then ){
    +        // must be a promise
    +        menuItem.title = "";
    +        title.then( function( successValue ) {
    +          menuItem.title = successValue;
    +        }, function( errorValue ) {
    +          menuItem.title = errorValue;
    +        });
    +      } else {
    +        gridUtil.logError('Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config');
    +        menuItem.title = 'badconfig';
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.gridMenuService
    +     * @name toggleColumnVisibility
    +     * @description Toggles the visibility of an individual column.  Expects to be
    +     * provided a context that has on it a gridColumn, which is the column that
    +     * we'll operate upon.  We change the visibility, and refresh the grid as appropriate
    +     * @param {GridCol} gridCol the column that we want to toggle
    +     * 
    +     */
    +    toggleColumnVisibility: function( gridCol ) {
    +      gridCol.colDef.visible = !( gridCol.colDef.visible === true || gridCol.colDef.visible === undefined ); 
    +      
    +      gridCol.grid.refresh();
    +      gridCol.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +      gridCol.grid.api.core.raise.columnVisibilityChanged( gridCol );
    +    }
    +  };
    +  
    +  return service;
    +}])
    +
    +
    +
    +.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 
    +function (gridUtil, uiGridConstants, uiGridGridMenuService) {
    +
    +  return {
    +    priority: 0,
    +    scope: true,
    +    require: ['?^uiGrid'],
    +    templateUrl: 'ui-grid/ui-grid-menu-button',
    +    replace: true,
    +
    +
    +    link: function ($scope, $elm, $attrs, controllers) {
    +      var uiGridCtrl = controllers[0];
    +
    +      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
    +      
    +      $scope.shown = false;
    +
    +      $scope.toggleMenu = function () {
    +        if ( $scope.shown ){
    +          $scope.$broadcast('hide-menu');
    +          $scope.shown = false;
    +        } else {
    +          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
    +          $scope.$broadcast('show-menu');
    +          $scope.shown = true;
    +        }
    +      };
    +      
    +      $scope.$on('menu-hidden', function() {
    +        $scope.shown = false;
    +      });
    +    }
    +  };
    +
    +}]);
    +
    +})();
    +(function(){
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.directive:uiGridColumnMenu
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    + <doc:example module="app">
    + <doc:source>
    + <script>
    + var app = angular.module('app', ['ui.grid']);
    +
    + app.controller('MainCtrl', ['$scope', function ($scope) {
    +   
    + }]);
    + </script>
    +
    + <div ng-controller="MainCtrl">
    +   <div ui-grid-menu shown="true"  ></div>
    + </div>
    + </doc:source>
    + <doc:scenario>
    + </doc:scenario>
    + </doc:example>
    + */
    +angular.module('ui.grid')
    +
    +.directive('uiGridMenu', ['$compile', '$timeout', '$window', '$document', 'gridUtil', 'uiGridConstants', 
    +function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants) {
    +  var uiGridMenu = {
    +    priority: 0,
    +    scope: {
    +      // shown: '&',
    +      menuItems: '=',
    +      autoHide: '=?'
    +    },
    +    require: '?^uiGrid',
    +    templateUrl: 'ui-grid/uiGridMenu',
    +    replace: false,
    +    link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +      var self = this;
    +      var menuMid;
    +      var $animate;
    +     
    +    // *** Show/Hide functions ******
    +      self.showMenu = $scope.showMenu = function(event, args) {
    +        if ( !$scope.shown ){
    +
    +          /*
    +           * In order to animate cleanly we remove the ng-if, wait a digest cycle, then
    +           * animate the removal of the ng-hide.  We can't successfully (so far as I can tell)
    +           * animate removal of the ng-if, as the menu items aren't there yet.  And we don't want
    +           * to rely on ng-show only, as that leaves elements in the DOM that are needlessly evaluated
    +           * on scroll events.
    +           * 
    +           * Note when testing animation that animations don't run on the tutorials.  When debugging it looks
    +           * like they do, but angular has a default $animate provider that is just a stub, and that's what's
    +           * being called.  ALso don't be fooled by the fact that your browser has actually loaded the 
    +           * angular-translate.js, it's not using it.  You need to test animations in an external application. 
    +           */
    +          $scope.shown = true;
    +
    +          $timeout( function() {
    +            $scope.shownMid = true;
    +            $scope.$emit('menu-shown');
    +          });
    +        } else if ( !$scope.shownMid ) {
    +          // we're probably doing a hide then show, so we don't need to wait for ng-if
    +          $scope.shownMid = true;
    +          $scope.$emit('menu-shown');
    +        }
    +
    +        var docEventType = 'click';
    +        if (args && args.originalEvent && args.originalEvent.type && args.originalEvent.type === 'touchstart') {
    +          docEventType = args.originalEvent.type;
    +        }
    +
    +        // Turn off an existing document click handler
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +
    +        // Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
    +        $timeout(function() {
    +          angular.element(document).on(docEventType, applyHideMenu);
    +        });
    +      };
    +
    +
    +      self.hideMenu = $scope.hideMenu = function(event, args) {
    +        if ( $scope.shown ){
    +          /*
    +           * In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
    +           * set the ng-if (shown = false) after the animation runs.  In theory we can cascade off the
    +           * callback on the addClass method, but it is very unreliable with unit tests for no discernable reason.
    +           *   
    +           * The user may have clicked on the menu again whilst
    +           * we're waiting, so we check that the mid isn't shown before applying the ng-if.
    +           */
    +          $scope.shownMid = false;
    +          $timeout( function() {
    +            if ( !$scope.shownMid ){
    +              $scope.shown = false;
    +              $scope.$emit('menu-hidden');
    +            }
    +          }, 200);
    +        }
    +
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      };
    +
    +      $scope.$on('hide-menu', function (event, args) {
    +        $scope.hideMenu(event, args);
    +      });
    +
    +      $scope.$on('show-menu', function (event, args) {
    +        $scope.showMenu(event, args);
    +      });
    +
    +      
    +    // *** Auto hide when click elsewhere ******
    +      var applyHideMenu = function(){
    +        if ($scope.shown) {
    +          $scope.$apply(function () {
    +            $scope.hideMenu();
    +          });
    +        }
    +      };
    +    
    +      if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
    +        $scope.autoHide = true;
    +      }
    +
    +      if ($scope.autoHide) {
    +        angular.element($window).on('resize', applyHideMenu);
    +      }
    +
    +      $scope.$on('$destroy', function () {
    +        angular.element(document).off('click touchstart', applyHideMenu);
    +      });
    +      
    +
    +      $scope.$on('$destroy', function() {
    +        angular.element($window).off('resize', applyHideMenu);
    +      });
    +
    +      if (uiGridCtrl) {
    +       $scope.$on('$destroy', uiGridCtrl.grid.api.core.on.scrollEvent($scope, applyHideMenu ));
    +      }
    +
    +      $scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
    +    },
    +    
    +    
    +    controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
    +      var self = this;
    +    }]
    +  };
    +
    +  return uiGridMenu;
    +}])
    +
    +.directive('uiGridMenuItem', ['gridUtil', '$compile', 'i18nService', function (gridUtil, $compile, i18nService) {
    +  var uiGridMenuItem = {
    +    priority: 0,
    +    scope: {
    +      name: '=',
    +      active: '=',
    +      action: '=',
    +      icon: '=',
    +      shown: '=',
    +      context: '=',
    +      templateUrl: '='
    +    },
    +    require: ['?^uiGrid', '^uiGridMenu'],
    +    templateUrl: 'ui-grid/uiGridMenuItem',
    +    replace: true,
    +    compile: function($elm, $attrs) {
    +      return {
    +        pre: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +          
    +          if ($scope.templateUrl) {
    +            gridUtil.getTemplate($scope.templateUrl)
    +                .then(function (contents) {
    +                  var template = angular.element(contents);
    +                    
    +                  var newElm = $compile(template)($scope);
    +                  $elm.replaceWith(newElm);
    +                });
    +          }
    +        },
    +        post: function ($scope, $elm, $attrs, controllers) {
    +          var uiGridCtrl = controllers[0],
    +              uiGridMenuCtrl = controllers[1];
    +
    +          // TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
    +          // if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
    +          //   throw new TypeError("$scope.shown is defined but not a function");
    +          // }
    +          if (typeof($scope.shown) === 'undefined' || $scope.shown === null) {
    +            $scope.shown = function() { return true; };
    +          }
    +
    +          $scope.itemShown = function () {
    +            var context = {};
    +            if ($scope.context) {
    +              context.context = $scope.context;
    +            }
    +
    +            if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +              context.grid = uiGridCtrl.grid;
    +            }
    +
    +            return $scope.shown.call(context);
    +          };
    +
    +          $scope.itemAction = function($event,title) {
    +            // gridUtil.logDebug('itemAction');
    +            $event.stopPropagation();
    +
    +            if (typeof($scope.action) === 'function') {
    +              var context = {};
    +
    +              if ($scope.context) {
    +                context.context = $scope.context;
    +              }
    +
    +              // Add the grid to the function call context if the uiGrid controller is present
    +              if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
    +                context.grid = uiGridCtrl.grid;
    +              }
    +
    +              $scope.action.call(context, $event, title);
    +
    +              $scope.$emit('hide-menu');
    +            }
    +          };
    +
    +          $scope.i18n = i18nService.get();
    +        }
    +      };
    +    }
    +  };
    +
    +  return uiGridMenuItem;
    +}]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  var module = angular.module('ui.grid');
    +  
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'uiGridConstants', 'gridUtil', 'ScrollEvent',
    +    function($timeout, $document, uiGridConstants, gridUtil, ScrollEvent) {
    +    return {
    +      replace: true,
    +      transclude: true,
    +      templateUrl: 'ui-grid/uiGridRenderContainer',
    +      require: ['^uiGrid', 'uiGridRenderContainer'],
    +      scope: {
    +        containerId: '=',
    +        rowContainerName: '=',
    +        colContainerName: '=',
    +        bindScrollHorizontal: '=',
    +        bindScrollVertical: '=',
    +        enableVerticalScrollbar: '=',
    +        enableHorizontalScrollbar: '='
    +      },
    +      controller: 'uiGridRenderContainer as RenderContainer',
    +      compile: function () {
    +        return {
    +          pre: function prelink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' pre-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = $scope.grid = uiGridCtrl.grid;
    +
    +            // Verify that the render container for this element exists
    +            if (!$scope.rowContainerName) {
    +              throw "No row render container name specified";
    +            }
    +            if (!$scope.colContainerName) {
    +              throw "No column render container name specified";
    +            }
    +
    +            if (!grid.renderContainers[$scope.rowContainerName]) {
    +              throw "Row render container '" + $scope.rowContainerName + "' is not registered.";
    +            }
    +            if (!grid.renderContainers[$scope.colContainerName]) {
    +              throw "Column render container '" + $scope.colContainerName + "' is not registered.";
    +            }
    +
    +            var rowContainer = $scope.rowContainer = grid.renderContainers[$scope.rowContainerName];
    +            var colContainer = $scope.colContainer = grid.renderContainers[$scope.colContainerName];
    +            
    +            containerCtrl.containerId = $scope.containerId;
    +            containerCtrl.rowContainer = rowContainer;
    +            containerCtrl.colContainer = colContainer;
    +          },
    +          post: function postlink($scope, $elm, $attrs, controllers) {
    +            // gridUtil.logDebug('render container ' + $scope.containerId + ' post-link');
    +
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +            var rowContainer = containerCtrl.rowContainer;
    +            var colContainer = containerCtrl.colContainer;
    +
    +            var renderContainer = grid.renderContainers[$scope.containerId];
    +
    +            // Put the container name on this element as a class
    +            $elm.addClass('ui-grid-render-container-' + $scope.containerId);
    +
    +            // Bind to left/right-scroll events
    +            if ($scope.bindScrollHorizontal || $scope.bindScrollVertical) {
    +              grid.api.core.on.scrollEvent($scope,scrollHandler);
    +            }
    +
    +            function scrollHandler (args) {
    +              // exit if not for this grid
    +              if (args.grid && args.grid.id !== grid.id){
    +                return;
    +              }
    +
    +              
    +              // Vertical scroll
    +              if (args.y && $scope.bindScrollVertical) {
    +                containerCtrl.prevScrollArgs = args;
    +
    +                var newScrollTop = args.getNewScrollTop(rowContainer,containerCtrl.viewport);
    +
    +                //only set scrollTop if we coming from something other than viewPort scrollBar or
    +                //another column container
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll ||
    +                    args.sourceColContainer !== colContainer) {
    +                  containerCtrl.viewport[0].scrollTop = newScrollTop;
    +                }
    +
    +              }
    +
    +              // Horizontal scroll
    +              if (args.x && $scope.bindScrollHorizontal) {
    +                containerCtrl.prevScrollArgs = args;
    +                var newScrollLeft = args.getNewScrollLeft(colContainer,containerCtrl.viewport);
    +
    +                // Make the current horizontal scroll position available in the $scope
    +                $scope.newScrollLeft = newScrollLeft;
    +
    +                if (containerCtrl.headerViewport) {
    +                  containerCtrl.headerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.headerViewport, newScrollLeft);
    +                }
    +
    +                if (containerCtrl.footerViewport) {
    +                  containerCtrl.footerViewport.scrollLeft = gridUtil.denormalizeScrollLeft(containerCtrl.footerViewport, newScrollLeft);
    +                }
    +
    +                // Scroll came from somewhere else, so the viewport must be positioned
    +                if (args.source !== ScrollEvent.Sources.ViewPortScroll) {
    +                  containerCtrl.viewport[0].scrollLeft = newScrollLeft;
    +                }
    +
    +                containerCtrl.prevScrollLeft = newScrollLeft;
    +              }
    +            }
    +
    +            // Scroll the render container viewport when the mousewheel is used
    +            gridUtil.on.mousewheel($elm, function (event) {
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.RenderContainerMouseWheel);
    +              if (event.deltaY !== 0) {
    +                var scrollYAmount = event.deltaY * -1 * event.deltaFactor;
    +
    +                // Get the scroll percentage
    +                var scrollYPercentage = (containerCtrl.viewport[0].scrollTop + scrollYAmount) / rowContainer.getVerticalScrollLength();
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollYPercentage < 0) { scrollYPercentage = 0; }
    +                else if (scrollYPercentage > 1) { scrollYPercentage = 1; }
    +
    +                scrollEvent.y = { percentage: scrollYPercentage, pixels: scrollYAmount };
    +              }
    +              if (event.deltaX !== 0) {
    +                var scrollXAmount = event.deltaX * event.deltaFactor;
    +
    +                // Get the scroll percentage
    +                var scrollLeft = gridUtil.normalizeScrollLeft(containerCtrl.viewport);
    +                var scrollXPercentage = (scrollLeft + scrollXAmount) / (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +                // Keep scrollPercentage within the range 0-1.
    +                if (scrollXPercentage < 0) { scrollXPercentage = 0; }
    +                else if (scrollXPercentage > 1) { scrollXPercentage = 1; }
    +
    +                scrollEvent.x = { percentage: scrollXPercentage, pixels: scrollXAmount };
    +              }
    +
    +              // todo: this isn't working when scrolling down.  it works fine for up.  tested on Chrome
    +              // Let the parent container scroll if the grid is already at the top/bottom
    +              if ((scrollEvent.y && scrollEvent.y.percentage !== 0 && scrollEvent.y.percentage !== 1) ||
    +                 (scrollEvent.x && scrollEvent.x.percentage !== 0 && scrollEvent.x.percentage !== 1)) {
    +
    +                  event.preventDefault();
    +                  scrollEvent.fireThrottledScrollingEvent();
    +              }
    +            });
    +
    +            $elm.bind('$destroy', function() {
    +              $elm.unbind('keydown');
    +
    +              ['touchstart', 'touchmove', 'touchend','keydown', 'wheel', 'mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'].forEach(function (eventName) {
    +                $elm.unbind(eventName);
    +              });
    +            });
    +            
    +            // TODO(c0bra): Handle resizing the inner canvas based on the number of elements
    +            function update() {
    +              var ret = '';
    +
    +              var canvasWidth = colContainer.getCanvasWidth();
    +              var viewportWidth = colContainer.getViewportWidth();
    +
    +              var canvasHeight = rowContainer.getCanvasHeight();
    +
    +              //add additional height for scrollbar on left and right container
    +              if ($scope.containerId !== 'body') {
    +                canvasHeight += grid.scrollbarHeight;
    +              }
    +
    +              var viewportHeight = rowContainer.getViewportHeight();
    +
    +              var headerViewportWidth = colContainer.getHeaderViewportWidth();
    +              var footerViewportWidth = colContainer.getHeaderViewportWidth();
    +              
    +              // Set canvas dimensions
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-canvas { width: ' + canvasWidth + 'px; height: ' + canvasHeight + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { width: ' + (canvasWidth + grid.scrollbarWidth) + 'px; }';
    +
    +              if (renderContainer.explicitHeaderCanvasHeight) {
    +                ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-canvas { height: ' + renderContainer.explicitHeaderCanvasHeight + 'px; }';
    +              }
    +              
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-viewport { width: ' + viewportWidth + 'px; height: ' + viewportHeight + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-header-viewport { width: ' + headerViewportWidth + 'px; }';
    +
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-canvas { width: ' + canvasWidth + grid.scrollbarWidth + 'px; }';
    +              ret += '\n .grid' + uiGridCtrl.grid.id + ' .ui-grid-render-container-' + $scope.containerId + ' .ui-grid-footer-viewport { width: ' + footerViewportWidth + 'px; }';
    +
    +              return ret;
    +            }
    +            
    +            uiGridCtrl.grid.registerStyleComputation({
    +              priority: 6,
    +              func: update
    +            });
    +          }
    +        };
    +      }
    +    };
    +
    +  }]);
    +
    +  module.controller('uiGridRenderContainer', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +    
    +  }]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridRow', ['gridUtil', function(gridUtil) {
    +    return {
    +      replace: true,
    +      // priority: 2001,
    +      // templateUrl: 'ui-grid/ui-grid-row',
    +      require: ['^uiGrid', '^uiGridRenderContainer'],
    +      scope: {
    +         row: '=uiGridRow',
    +         //rowRenderIndex is added to scope to give the true visual index of the row to any directives that need it
    +         rowRenderIndex: '='
    +      },
    +      compile: function() {
    +        return {
    +          pre: function($scope, $elm, $attrs, controllers) {
    +            var uiGridCtrl = controllers[0];
    +            var containerCtrl = controllers[1];
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            $scope.grid = uiGridCtrl.grid;
    +            $scope.colContainer = containerCtrl.colContainer;
    +
    +            // Function for attaching the template to this scope
    +            var clonedElement, cloneScope;
    +            function compileTemplate() {
    +              $scope.row.getRowTemplateFn.then(function (compiledElementFn) {
    +                // var compiledElementFn = $scope.row.compiledElementFn;
    +
    +                // Create a new scope for the contents of this row, so we can destroy it later if need be
    +                var newScope = $scope.$new();
    +
    +                compiledElementFn(newScope, function (newElm, scope) {
    +                  // If we already have a cloned element, we need to remove it and destroy its scope
    +                  if (clonedElement) {
    +                    clonedElement.remove();
    +                    cloneScope.$destroy();
    +                  }
    +
    +                  // Empty the row and append the new element
    +                  $elm.empty().append(newElm);
    +
    +                  // Save the new cloned element and scope
    +                  clonedElement = newElm;
    +                  cloneScope = newScope;
    +                });
    +              });
    +            }
    +
    +            // Initially attach the compiled template to this scope
    +            compileTemplate();
    +
    +            // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
    +            $scope.$watch('row.getRowTemplateFn', function (newFunc, oldFunc) {
    +              if (newFunc !== oldFunc) {
    +                compileTemplate();
    +              }
    +            });
    +          },
    +          post: function($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.directive:uiGridStyle
    +   * @element style
    +   * @restrict A
    +   *
    +   * @description
    +   * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.myStyle = '.blah { border: 1px solid }';
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <style ui-grid-style>{{ myStyle }}</style>
    +   <span class="blah">I am in a box.</span>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +   it('should apply the right class to the element', function () {
    +        element(by.css('.blah')).getCssValue('border')
    +          .then(function(c) {
    +            expect(c).toContain('1px solid');
    +          });
    +      });
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +
    +
    +  angular.module('ui.grid').directive('uiGridStyle', ['gridUtil', '$interpolate', function(gridUtil, $interpolate) {
    +    return {
    +      // restrict: 'A',
    +      // priority: 1000,
    +      // require: '?^uiGrid',
    +      link: function($scope, $elm, $attrs, uiGridCtrl) {
    +        // gridUtil.logDebug('ui-grid-style link');
    +        // if (uiGridCtrl === undefined) {
    +        //    gridUtil.logWarn('[ui-grid-style link] uiGridCtrl is undefined!');
    +        // }
    +
    +        var interpolateFn = $interpolate($elm.text(), true);
    +
    +        if (interpolateFn) {
    +          $scope.$watch(interpolateFn, function(value) {
    +            $elm.text(value);
    +          });
    +        }
    +
    +          // uiGridCtrl.recalcRowStyles = function() {
    +          //   var offset = (scope.options.offsetTop || 0) - (scope.options.excessRows * scope.options.rowHeight);
    +          //   var rowHeight = scope.options.rowHeight;
    +
    +          //   var ret = '';
    +          //   var rowStyleCount = uiGridCtrl.minRowsToRender() + (scope.options.excessRows * 2);
    +          //   for (var i = 1; i <= rowStyleCount; i++) {
    +          //     ret = ret + ' .grid' + scope.gridId + ' .ui-grid-row:nth-child(' + i + ') { top: ' + offset + 'px; }';
    +          //     offset = offset + rowHeight;
    +          //   }
    +
    +          //   scope.rowStyles = ret;
    +          // };
    +
    +          // uiGridCtrl.styleComputions.push(uiGridCtrl.recalcRowStyles);
    +
    +      }
    +    };
    +  }]);
    +
    +})();
    +(function(){
    +  'use strict';
    +
    +  angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants',
    +    function(gridUtil, ScrollEvent, uiGridConstants) {
    +      return {
    +        replace: true,
    +        scope: {},
    +        controllerAs: 'Viewport',
    +        templateUrl: 'ui-grid/uiGridViewport',
    +        require: ['^uiGrid', '^uiGridRenderContainer'],
    +        link: function($scope, $elm, $attrs, controllers) {
    +          // gridUtil.logDebug('viewport post-link');
    +
    +          var uiGridCtrl = controllers[0];
    +          var containerCtrl = controllers[1];
    +
    +          $scope.containerCtrl = containerCtrl;
    +
    +          var rowContainer = containerCtrl.rowContainer;
    +          var colContainer = containerCtrl.colContainer;
    +
    +          var grid = uiGridCtrl.grid;
    +
    +          $scope.grid = uiGridCtrl.grid;
    +
    +          // Put the containers in scope so we can get rows and columns from them
    +          $scope.rowContainer = containerCtrl.rowContainer;
    +          $scope.colContainer = containerCtrl.colContainer;
    +
    +          // Register this viewport with its container 
    +          containerCtrl.viewport = $elm;
    +
    +          $elm.on('scroll', function (evt) {
    +            var newScrollTop = $elm[0].scrollTop;
    +            // var newScrollLeft = $elm[0].scrollLeft;
    +            var newScrollLeft = gridUtil.normalizeScrollLeft($elm);
    +            var horizScrollPercentage = -1;
    +            var vertScrollPercentage = -1;
    +
    +            // Handle RTL here
    +
    +            if (newScrollLeft !== colContainer.prevScrollLeft) {
    +              grid.flagScrollingHorizontally();
    +              var xDiff = newScrollLeft - colContainer.prevScrollLeft;
    +
    +              if (xDiff > 0) { grid.scrollDirection = uiGridConstants.scrollDirection.RIGHT; }
    +              if (xDiff < 0) { grid.scrollDirection = uiGridConstants.scrollDirection.LEFT; }
    +
    +              var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +              if (horizScrollLength !== 0) {
    +                horizScrollPercentage = newScrollLeft / horizScrollLength;
    +              }
    +              else {
    +                horizScrollPercentage = 0;
    +              }
    +
    +              colContainer.adjustScrollHorizontal(newScrollLeft, horizScrollPercentage);
    +            }
    +
    +            if (newScrollTop !== rowContainer.prevScrollTop) {
    +              grid.flagScrollingVertically();
    +              var yDiff = newScrollTop - rowContainer.prevScrollTop;
    +
    +              if (yDiff > 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.DOWN; }
    +              if (yDiff < 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.UP; }
    +
    +              var vertScrollLength = rowContainer.getVerticalScrollLength();
    +
    +              vertScrollPercentage = newScrollTop / vertScrollLength;
    +
    +              if (vertScrollPercentage > 1) { vertScrollPercentage = 1; }
    +              if (vertScrollPercentage < 0) { vertScrollPercentage = 0; }
    +              
    +              rowContainer.adjustScrollVertical(newScrollTop, vertScrollPercentage);
    +            }
    +
    +              var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
    +              scrollEvent.newScrollLeft = newScrollLeft;
    +              scrollEvent.newScrollTop = newScrollTop;
    +              if ( horizScrollPercentage > -1 ){
    +                scrollEvent.x = { percentage: horizScrollPercentage };
    +              }
    +
    +              if ( vertScrollPercentage > -1 ){
    +                scrollEvent.y = { percentage: vertScrollPercentage };
    +              }
    +              scrollEvent.fireScrollingEvent();
    +          });
    +        },
    +        controller: ['$scope', function ($scope) {
    +          this.rowStyle = function (index) {
    +            var rowContainer = $scope.rowContainer;
    +            var colContainer = $scope.colContainer;
    +
    +            var styles = {};
    +
    +            if (index === 0 && rowContainer.currentTopRow !== 0) {
    +              // The row offset-top is just the height of the rows above the current top-most row, which are no longer rendered
    +              var hiddenRowWidth = (rowContainer.currentTopRow) * rowContainer.grid.options.rowHeight;
    +
    +              // return { 'margin-top': hiddenRowWidth + 'px' };
    +              styles['margin-top'] = hiddenRowWidth + 'px';
    +            }
    +
    +            if (colContainer.currentFirstColumn !== 0) {
    +              if (colContainer.grid.isRTL()) {
    +                styles['margin-right'] = colContainer.columnOffset + 'px';
    +              }
    +              else {
    +                styles['margin-left'] = colContainer.columnOffset + 'px';
    +              }
    +            }
    +
    +            return styles;
    +          };
    +        }]
    +      };
    +    }
    +  ]);
    +
    +})();
    +(function() {
    +
    +angular.module('ui.grid')
    +.directive('uiGridVisible', function uiGridVisibleAction() {
    +  return function ($scope, $elm, $attr) {
    +    $scope.$watch($attr.uiGridVisible, function (visible) {
    +        // $elm.css('visibility', visible ? 'visible' : 'hidden');
    +        $elm[visible ? 'removeClass' : 'addClass']('ui-grid-invisible');
    +    });
    +  };
    +});
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
    +                    '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile', 'ScrollEvent',
    +    function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
    +              $templateCache, gridClassFactory, $timeout, $parse, $compile, ScrollEvent) {
    +      // gridUtil.logDebug('ui-grid controller');
    +
    +      var self = this;
    +
    +      self.grid = gridClassFactory.createGrid($scope.uiGrid);
    +
    +      //assign $scope.$parent if appScope not already assigned
    +      self.grid.appScope = self.grid.appScope || $scope.$parent;
    +
    +      $elm.addClass('grid' + self.grid.id);
    +      self.grid.rtl = gridUtil.getStyles($elm[0])['direction'] === 'rtl';
    +
    +
    +      // angular.extend(self.grid.options, );
    +
    +      //all properties of grid are available on scope
    +      $scope.grid = self.grid;
    +
    +      if ($attrs.uiGridColumns) {
    +        $attrs.$observe('uiGridColumns', function(value) {
    +          self.grid.options.columnDefs = value;
    +          self.grid.buildColumns()
    +            .then(function(){
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.refreshCanvas(true);
    +            });
    +        });
    +      }
    +
    +
    +      var dataWatchCollectionDereg;
    +      if (angular.isString($scope.uiGrid.data)) {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
    +      }
    +      else {
    +        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
    +      }
    +
    +      var columnDefWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction);
    +
    +      function columnDefsWatchFunction(n, o) {
    +        if (n && n !== o) {
    +          self.grid.options.columnDefs = n;
    +          self.grid.buildColumns({ orderByColumnDefs: true })
    +            .then(function(){
    +
    +              self.grid.preCompileCellTemplates();
    +
    +              self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
    +            });
    +        }
    +      }
    +
    +      function adjustInfiniteScrollPosition (scrollToRow) {
    +
    +        var scrollEvent = new ScrollEvent(self.grid, null, null, 'ui.grid.adjustInfiniteScrollPosition');
    +        var totalRows = self.grid.renderContainers.body.visibleRowCache.length;
    +        var percentage = ( scrollToRow + ( scrollToRow / ( totalRows - 1 ) ) ) / totalRows;
    +
    +        //for infinite scroll, never allow it to be at the zero position so the up button can be active
    +        if ( percentage === 0 ) {
    +          scrollEvent.y = {pixels: 1};
    +        }
    +        else {
    +          scrollEvent.y = {percentage: percentage};
    +        }
    +        scrollEvent.fireScrollingEvent();
    +
    +      }
    +
    +      function dataWatchFunction(newData) {
    +        // gridUtil.logDebug('dataWatch fired');
    +        var promises = [];
    +        
    +        if (newData) {
    +          if (
    +            // If we have no columns (i.e. columns length is either 0 or equal to the number of row header columns, which don't count because they're created automatically)
    +            self.grid.columns.length === (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0) &&
    +            // ... and we don't have a ui-grid-columns attribute, which would define columns for us
    +            !$attrs.uiGridColumns &&
    +            // ... and we have no pre-defined columns
    +            self.grid.options.columnDefs.length === 0 &&
    +            // ... but we DO have data
    +            newData.length > 0
    +          ) {
    +            // ... then build the column definitions from the data that we have
    +            self.grid.buildColumnDefsFromData(newData);
    +          }
    +
    +          // If we either have some columns defined, or some data defined
    +          if (self.grid.options.columnDefs.length > 0 || newData.length > 0) {
    +            // Build the column set, then pre-compile the column cell templates
    +            promises.push(self.grid.buildColumns()
    +              .then(function() {
    +                self.grid.preCompileCellTemplates();
    +              }));
    +          }
    +
    +          $q.all(promises).then(function() {
    +            self.grid.modifyRows(newData)
    +              .then(function () {
    +                // if (self.viewport) {
    +                  self.grid.redrawInPlace(true);
    +                // }
    +
    +                $scope.$evalAsync(function() {
    +                  self.grid.refreshCanvas(true);
    +                  self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
    +
    +                  $timeout(function () {
    +                    //Process post load scroll events if using infinite scroll
    +                    if ( self.grid.options.enableInfiniteScroll ) {
    +                      //If first load, seed the scrollbar down a little to activate the button
    +                      if ( self.grid.renderContainers.body.prevRowScrollIndex === 0 ) {
    +                        adjustInfiniteScrollPosition(0);
    +                      }
    +                      //If we are scrolling up, we need to reseed the grid.
    +                      if (self.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                        adjustInfiniteScrollPosition(self.grid.renderContainers.body.prevRowScrollIndex + 1 + self.grid.options.excessRows);
    +                      }
    +                    }
    +                    }, 0);
    +                });
    +              });
    +          });
    +        }
    +      }
    +
    +      var styleWatchDereg = $scope.$watch(function () { return self.grid.styleComputations; }, function() {
    +        self.grid.refreshCanvas(true);
    +      });
    +
    +      $scope.$on('$destroy', function() {
    +        dataWatchCollectionDereg();
    +        columnDefWatchCollectionDereg();
    +        styleWatchDereg();
    +      });
    +
    +      self.fireEvent = function(eventName, args) {
    +        // Add the grid to the event arguments if it's not there
    +        if (typeof(args) === 'undefined' || args === undefined) {
    +          args = {};
    +        }
    +
    +        if (typeof(args.grid) === 'undefined' || args.grid === undefined) {
    +          args.grid = self.grid;
    +        }
    +
    +        $scope.$broadcast(eventName, args);
    +      };
    +
    +      self.innerCompile = function innerCompile(elm) {
    +        $compile(elm)($scope);
    +      };
    +
    +    }]);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {Object} uiGrid Options for the grid to use
    + *
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="{ data: data }"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +angular.module('ui.grid').directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    'gridUtil',
    +    '$window',
    +    'uiGridConstants',
    +    function(
    +      $compile,
    +      $templateCache,
    +      gridUtil,
    +      $window,
    +      uiGridConstants
    +      ) {
    +      return {
    +        templateUrl: 'ui-grid/ui-grid',
    +        scope: {
    +          uiGrid: '='
    +        },
    +        replace: true,
    +        transclude: true,
    +        controller: 'uiGridController',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              // gridUtil.logDebug('ui-grid postlink');
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Initialize scrollbars (TODO: move to controller??)
    +              uiGridCtrl.scrollbars = [];
    +
    +              //todo: assume it is ok to communicate that rendering is complete??
    +              grid.renderingComplete();
    +
    +              grid.element = $elm;
    +
    +              grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +
    +              // Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
    +              grid.canvasWidth = uiGridCtrl.grid.gridWidth;
    +
    +              grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +              // If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
    +              if (grid.gridHeight < grid.options.rowHeight) {
    +                // Figure out the new height
    +                var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
    +                var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
    +                var footerHeight = grid.calcFooterHeight();
    +                
    +                var scrollbarHeight = 0;
    +                if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +                  scrollbarHeight = gridUtil.getScrollbarWidth();
    +                }
    +
    +                var maxNumberOfFilters = 0;
    +                // Calculates the maximum number of filters in the columns
    +                angular.forEach(grid.options.columnDefs, function(col) {
    +                  if (col.hasOwnProperty('filter')) {
    +                    if (maxNumberOfFilters < 1) {
    +                        maxNumberOfFilters = 1;
    +                    }
    +                  }
    +                  else if (col.hasOwnProperty('filters')) {
    +                    if (maxNumberOfFilters < col.filters.length) {
    +                        maxNumberOfFilters = col.filters.length;
    +                    }
    +                  }
    +                });
    +                var filterHeight = maxNumberOfFilters * headerHeight;
    +
    +                var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
    +
    +                $elm.css('height', newHeight + 'px');
    +
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +              }
    +
    +              // Run initial canvas refresh
    +              grid.refreshCanvas();
    +
    +              //if we add a left container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +              //if we add a right container after render, we need to watch and react
    +              $scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
    +                if (newValue === oldValue) {
    +                  return;
    +                }
    +                grid.refreshCanvas(true);
    +              });
    +
    +
    +              // Resize the grid on window resize events
    +              function gridResize($event) {
    +                grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
    +                grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
    +
    +                grid.refreshCanvas(true);
    +              }
    +
    +              angular.element($window).on('resize', gridResize);
    +
    +              // Unbind from window resize events when the grid is destroyed
    +              $elm.on('$destroy', function () {
    +                angular.element($window).off('resize', gridResize);
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  // TODO: rename this file to ui-grid-pinned-container.js
    +
    +  angular.module('ui.grid').directive('uiGridPinnedContainer', ['gridUtil', function (gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      template: '<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',
    +      scope: {
    +        side: '=uiGridPinnedContainer'
    +      },
    +      require: '^uiGrid',
    +      compile: function compile() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            // gridUtil.logDebug('ui-grid-pinned-container ' + $scope.side + ' link');
    +
    +            var grid = uiGridCtrl.grid;
    +
    +            var myWidth = 0;
    +
    +            $elm.addClass('ui-grid-pinned-container-' + $scope.side);
    +
    +            function updateContainerWidth() {
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                var cols = grid.renderContainers[$scope.side].visibleColumnCache;
    +                var width = 0;
    +                for (var i = 0; i < cols.length; i++) {
    +                  var col = cols[i];
    +                  width += col.drawnWidth || col.width || 0;
    +                }
    +
    +                myWidth = width;
    +              }              
    +            }
    +            
    +            function updateContainerDimensions() {
    +              // gridUtil.logDebug('update ' + $scope.side + ' dimensions');
    +
    +              var ret = '';
    +              
    +              // Column containers
    +              if ($scope.side === 'left' || $scope.side === 'right') {
    +                updateContainerWidth();
    +
    +                // gridUtil.logDebug('myWidth', myWidth);
    +
    +                // TODO(c0bra): Subtract sum of col widths from grid viewport width and update it
    +                $elm.attr('style', null);
    +
    +                var myHeight = grid.renderContainers.body.getViewportHeight(); // + grid.horizontalScrollbarHeight;
    +
    +                ret += '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ', .grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.side + ' .ui-grid-render-container-' + $scope.side + ' .ui-grid-viewport { width: ' + myWidth + 'px; height: ' + myHeight + 'px; } ';
    +              }
    +
    +              return ret;
    +            }
    +
    +            grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +              if ( myWidth === 0 || !myWidth ){
    +                updateContainerWidth();
    +              }
    +              // Subtract our own width
    +              adjustment.width -= myWidth;
    +
    +              return adjustment;
    +            });
    +
    +            // Register style computation to adjust for columns in `side`'s render container
    +            grid.registerStyleComputation({
    +              priority: 15,
    +              func: updateContainerDimensions
    +            });
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +})();
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('Grid', ['$q', '$compile', '$parse', 'gridUtil', 'uiGridConstants', 'GridOptions', 'GridColumn', 'GridRow', 'GridApi', 'rowSorter', 'rowSearcher', 'GridRenderContainer', '$timeout',
    +    function($q, $compile, $parse, gridUtil, uiGridConstants, GridOptions, GridColumn, GridRow, GridApi, rowSorter, rowSearcher, GridRenderContainer, $timeout) {
    +
    +  /**
    +   * @ngdoc object
    +   * @name ui.grid.core.api:PublicApi
    +   * @description Public Api for the core grid features
    +   *
    +   */
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:Grid
    +   * @description Grid is the main viewModel.  Any properties or methods needed to maintain state are defined in
    +   * this prototype.  One instance of Grid is created per Grid directive instance.
    +   * @param {object} options Object map of options to pass into the grid. An 'id' property is expected.
    +   */
    +  var Grid = function Grid(options) {
    +    var self = this;
    +    // Get the id out of the options, then remove it
    +    if (options !== undefined && typeof(options.id) !== 'undefined' && options.id) {
    +      if (!/^[_a-zA-Z0-9-]+$/.test(options.id)) {
    +        throw new Error("Grid id '" + options.id + '" is invalid. It must follow CSS selector syntax rules.');
    +      }
    +    }
    +    else {
    +      throw new Error('No ID provided. An ID must be given when creating a grid.');
    +    }
    +  
    +    self.id = options.id;
    +    delete options.id;
    +  
    +    // Get default options
    +    self.options = GridOptions.initialize( options );
    +
    +    /**
    +     * @ngdoc object
    +     * @name appScope
    +     * @propertyOf ui.grid.class:Grid
    +     * @description reference to the application scope (the parent scope of the ui-grid element).  Assigned in ui-grid controller
    +     * <br/>
    +     * use gridOptions.appScopeProvider to override the default assignment of $scope.$parent with any reference
    +     */
    +    self.appScope = self.options.appScopeProvider;
    +  
    +    self.headerHeight = self.options.headerRowHeight;
    +
    +
    +    self.footerHeight = self.calcFooterHeight();
    +
    +    self.rtl = false;
    +    self.gridHeight = 0;
    +    self.gridWidth = 0;
    +    self.columnBuilders = [];
    +    self.rowBuilders = [];
    +    self.rowsProcessors = [];
    +    self.columnsProcessors = [];
    +    self.styleComputations = [];
    +    self.viewportAdjusters = [];
    +    self.rowHeaderColumns = [];
    +    self.dataChangeCallbacks = {};
    +  
    +    // self.visibleRowCache = [];
    +  
    +    // Set of 'render' containers for self grid, which can render sets of rows
    +    self.renderContainers = {};
    +  
    +    // Create a
    +    self.renderContainers.body = new GridRenderContainer('body', self);
    +  
    +    self.cellValueGetterCache = {};
    +  
    +    // Cached function to use with custom row templates
    +    self.getRowTemplateFn = null;
    +  
    +  
    +    //representation of the rows on the grid.
    +    //these are wrapped references to the actual data rows (options.data)
    +    self.rows = [];
    +  
    +    //represents the columns on the grid
    +    self.columns = [];
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingVertically
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling vertically. Set to false via debounced method
    +     */
    +    self.isScrollingVertically = false;
    +  
    +    /**
    +     * @ngdoc boolean
    +     * @name isScrollingHorizontally
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set to true when Grid is scrolling horizontally. Set to false via debounced method
    +     */
    +    self.isScrollingHorizontally = false;
    +
    +    /**
    +     * @ngdoc property
    +     * @name scrollDirection
    +     * @propertyOf ui.grid.class:Grid
    +     * @description set one of the uiGridConstants.scrollDirection values (UP, DOWN, LEFT, RIGHT, NONE), which tells
    +     * us which direction we are scrolling. Set to NONE via debounced method
    +     */
    +    self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +
    +    var debouncedVertical = gridUtil.debounce(function () {
    +      self.isScrollingVertically = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +    var debouncedHorizontal = gridUtil.debounce(function () {
    +      self.isScrollingHorizontally = false;
    +      self.scrollDirection = uiGridConstants.scrollDirection.NONE;
    +    }, 1000);
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingVertically
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingVertically to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingVertically = function() {
    +      self.isScrollingVertically = true;
    +      debouncedVertical();
    +    };
    +  
    +    /**
    +     * @ngdoc function
    +     * @name flagScrollingHorizontally
    +     * @methodOf ui.grid.class:Grid
    +     * @description sets isScrollingHorizontally to true and sets it to false in a debounced function
    +     */
    +    self.flagScrollingHorizontally = function() {
    +      self.isScrollingHorizontally = true;
    +      debouncedHorizontal();
    +    };
    +
    +    self.scrollbarHeight = 0;
    +    self.scrollbarWidth = 0;
    +    if (self.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarHeight = gridUtil.getScrollbarWidth();
    +    }
    +
    +    if (self.options.enableVerticalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
    +      self.scrollbarWidth = gridUtil.getScrollbarWidth();
    +    }
    +  
    +  
    +  
    +    self.api = new GridApi(self);
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refresh
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refresh', this.refresh );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name refreshRows
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Refresh the rendered grid on screen?  Note: not functional at present
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'refreshRows', this.refreshRows );
    +  
    +    /**
    +     * @ngdoc function
    +     * @name handleWindowResize
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Trigger a grid resize, normally this would be picked
    +     * up by a watch on window size, but in some circumstances it is necessary
    +     * to call this manually
    +     * @returns {promise} promise that is resolved when render completes?
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'handleWindowResize', this.handleWindowResize );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name addRowHeaderColumn
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description adds a row header column to the grid
    +     * @param {object} column def
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'addRowHeaderColumn', this.addRowHeaderColumn );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortHandleNulls
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description A null handling method that can be used when building custom sort
    +     * functions
    +     * @example
    +     * <pre>
    +     *   mySortFn = function(a, b) {
    +     *   var nulls = $scope.gridApi.core.sortHandleNulls(a, b);
    +     *   if ( nulls !== null ){
    +     *     return nulls;
    +     *   } else {
    +     *     // your code for sorting here
    +     *   };
    +     * </pre>
    +     * @param {object} a sort value a
    +     * @param {object} b sort value b
    +     * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +     * a sort value that should be passed back from the sort function
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'sortHandleNulls', rowSorter.handleNulls );
    +  
    +  
    +    /**
    +     * @ngdoc function
    +     * @name sortChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The sort criteria on one or more columns has
    +     * changed.  Provides as parameters the grid and the output of
    +     * getColumnSorting, which is an array of gridColumns
    +     * that have sorting on them, sorted in priority order. 
    +     * 
    +     * @param {Grid} grid the grid
    +     * @param {array} sortColumns an array of columns with 
    +     * sorts on them, in priority order
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.sortChanged( grid, sortColumns );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'sortChanged' );
    +  
    +      /**
    +     * @ngdoc function
    +     * @name columnVisibilityChanged
    +     * @methodOf  ui.grid.core.api:PublicApi
    +     * @description The visibility of a column has changed,
    +     * the column itself is passed out as a parameter of the event. 
    +     * 
    +     * @param {GridCol} column the column that changed
    +     * 
    +     * @example
    +     * <pre>
    +     *      gridApi.core.on.columnVisibilityChanged( $scope, function (column) {
    +     *        // do something
    +     *      } );
    +     * </pre>
    +     */
    +    self.api.registerEvent( 'core', 'columnVisibilityChanged' );
    +  
    +    /**
    +     * @ngdoc method
    +     * @name notifyDataChange
    +     * @methodOf ui.grid.core.api:PublicApi
    +     * @description Notify the grid that a data or config change has occurred,
    +     * where that change isn't something the grid was otherwise noticing.  This 
    +     * might be particularly relevant where you've changed values within the data
    +     * and you'd like cell classes to be re-evaluated, or changed config within 
    +     * the columnDef and you'd like headerCellClasses to be re-evaluated.
    +     * @param {string} type one of the 
    +     * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN), which tells
    +     * us which refreshes to fire.
    +     * 
    +     */
    +    self.api.registerMethod( 'core', 'notifyDataChange', this.notifyDataChange );
    +    
    +    self.registerDataChangeCallback( self.columnRefreshCallback, [uiGridConstants.dataChange.COLUMN]);
    +    self.registerDataChangeCallback( self.processRowsCallback, [uiGridConstants.dataChange.EDIT]);
    +
    +    self.registerStyleComputation({
    +      priority: 10,
    +      func: self.getFooterStyles
    +    });
    +  };
    +
    +   Grid.prototype.calcFooterHeight = function () {
    +     if (!this.hasFooter()) {
    +       return 0;
    +     }
    +
    +     var height = 0;
    +     if (this.options.showGridFooter) {
    +       height += this.options.gridFooterHeight;
    +     }
    +
    +     if (this.options.showColumnFooter) {
    +       height += this.options.columnFooterHeight;
    +     }
    +
    +     return height;
    +   };
    +
    +   Grid.prototype.getFooterStyles = function () {
    +     var style = '.grid' + this.id + ' .ui-grid-footer-aggregates-row { height: ' + this.options.columnFooterHeight + 'px; }';
    +     style += ' .grid' + this.id + ' .ui-grid-footer-info { height: ' + this.options.gridFooterHeight + 'px; }';
    +     return style;
    +   };
    +
    +  Grid.prototype.hasFooter = function () {
    +   return this.options.showGridFooter || this.options.showColumnFooter;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name isRTL
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns true if grid is RightToLeft
    +   */
    +  Grid.prototype.isRTL = function () {
    +    return this.rtl;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates columns from column definitions, the columnbuilders will be called to add
    +   * additional properties to the column.
    +   * @param {function(colDef, col, gridOptions)} columnsProcessor function to be called
    +   */
    +  Grid.prototype.registerColumnBuilder = function registerColumnBuilder(columnBuilder) {
    +    this.columnBuilders.push(columnBuilder);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumnDefsFromData
    +   * @methodOf ui.grid.class:Grid
    +   * @description Populates columnDefs from the provided data
    +   * @param {function(colDef, col, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.buildColumnDefsFromData = function (dataRows){
    +    this.options.columnDefs =  gridUtil.getColumnsFromData(dataRows, this.options.excludeProperties);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowBuilder
    +   * @methodOf ui.grid.class:Grid
    +   * @description When the build creates rows from gridOptions.data, the rowBuilders will be called to add
    +   * additional properties to the row.
    +   * @param {function(row, gridOptions)} rowBuilder function to be called
    +   */
    +  Grid.prototype.registerRowBuilder = function registerRowBuilder(rowBuilder) {
    +    this.rowBuilders.push(rowBuilder);
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerDataChangeCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description When a data change occurs, the data change callbacks of the specified type
    +   * will be called.  The rules are:
    +   * 
    +   * - when the data watch fires, that is considered a ROW change (the data watch only notices
    +   *   added or removed rows)
    +   * - when the api is called to inform us of a change, the declared type of that change is used
    +   * - when a cell edit completes, the EDIT callbacks are triggered
    +   * - when the columnDef watch fires, the COLUMN callbacks are triggered
    +   * - when the options watch fires, the OPTIONS callbacks are triggered
    +   * 
    +   * For a given event:
    +   * - ALL calls ROW, EDIT, COLUMN, OPTIONS and ALL callbacks
    +   * - ROW calls ROW and ALL callbacks
    +   * - EDIT calls EDIT and ALL callbacks
    +   * - COLUMN calls COLUMN and ALL callbacks
    +   * - OPTIONS calls OPTIONS and ALL callbacks
    +   * 
    +   * @param {function(grid)} callback function to be called
    +   * @param {array} types the types of data change you want to be informed of.  Values from 
    +   * the uiGridConstants.dataChange values ( ALL, EDIT, ROW, COLUMN, OPTIONS ).  Optional and defaults to
    +   * ALL 
    +   * @returns {function} deregister function - a function that can be called to deregister this callback
    +   */
    +  Grid.prototype.registerDataChangeCallback = function registerDataChangeCallback(callback, types, _this) {
    +    var uid = gridUtil.nextUid();
    +    if ( !types ){
    +      types = [uiGridConstants.dataChange.ALL];
    +    }
    +    if ( !Array.isArray(types)){
    +      gridUtil.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: " + types );
    +    }
    +    this.dataChangeCallbacks[uid] = { callback: callback, types: types, _this:_this };
    +    
    +    var self = this;
    +    var deregisterFunction = function() {
    +      delete self.dataChangeCallbacks[uid];
    +    };
    +    return deregisterFunction;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name callDataChangeCallbacks
    +   * @methodOf ui.grid.class:Grid
    +   * @description Calls the callbacks based on the type of data change that
    +   * has occurred. Always calls the ALL callbacks, calls the ROW, EDIT, COLUMN and OPTIONS callbacks if the 
    +   * event type is matching, or if the type is ALL.
    +   * @param {number} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN, OPTIONS)
    +   */
    +  Grid.prototype.callDataChangeCallbacks = function callDataChangeCallbacks(type, options) {
    +    angular.forEach( this.dataChangeCallbacks, function( callback, uid ){
    +      if ( callback.types.indexOf( uiGridConstants.dataChange.ALL ) !== -1 ||
    +           callback.types.indexOf( type ) !== -1 ||
    +           type === uiGridConstants.dataChange.ALL ) {
    +        if (callback._this) {
    +           callback.callback.apply(callback._this,this);
    +        }
    +        else {
    +          callback.callback( this );
    +        }
    +      }
    +    }, this);
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name notifyDataChange
    +   * @methodOf ui.grid.class:Grid
    +   * @description Notifies us that a data change has occurred, used in the public
    +   * api for users to tell us when they've changed data or some other event that 
    +   * our watches cannot pick up
    +   * @param {string} type the type of event that occurred - one of the 
    +   * uiGridConstants.dataChange values (ALL, ROW, EDIT, COLUMN)
    +   */
    +  Grid.prototype.notifyDataChange = function notifyDataChange(type) {
    +    var constants = uiGridConstants.dataChange;
    +    if ( type === constants.ALL || 
    +         type === constants.COLUMN ||
    +         type === constants.EDIT ||
    +         type === constants.ROW ||
    +         type === constants.OPTIONS ){
    +      this.callDataChangeCallbacks( type );
    +    } else {
    +      gridUtil.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: " + type);
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name columnRefreshCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description refreshes the grid when a column refresh
    +   * is notified, which triggers handling of the visible flag. 
    +   * This is called on uiGridConstants.dataChange.COLUMN, and is 
    +   * registered as a dataChangeCallback in grid.js
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.columnRefreshCallback = function columnRefreshCallback( grid ){
    +    grid.buildColumns();
    +    grid.refresh();
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowsCallback
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls the row processors, specifically
    +   * intended to reset the sorting when an edit is called,
    +   * registered as a dataChangeCallback on uiGridConstants.dataChange.EDIT
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.processRowsCallback = function processRowsCallback( grid ){
    +    grid.refreshRows();
    +  };
    +    
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid column for the column name
    +   * @param {string} name column name
    +   */
    +  Grid.prototype.getColumn = function getColumn(name) {
    +    var columns = this.columns.filter(function (column) {
    +      return column.colDef.name === name;
    +    });
    +    return columns.length > 0 ? columns[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns a grid colDef for the column name
    +   * @param {string} name column.field
    +   */
    +  Grid.prototype.getColDef = function getColDef(name) {
    +    var colDefs = this.options.columnDefs.filter(function (colDef) {
    +      return colDef.name === name;
    +    });
    +    return colDefs.length > 0 ? colDefs[0] : null;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name assignTypes
    +   * @methodOf ui.grid.class:Grid
    +   * @description uses the first row of data to assign colDef.type for any types not defined.
    +   */
    +  /**
    +   * @ngdoc property
    +   * @name type
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description the type of the column, used in sorting.  If not provided then the 
    +   * grid will guess the type.  Add this only if the grid guessing is not to your
    +   * satisfaction.  Refer to {@link ui.grid.service:GridUtil.guessType gridUtil.guessType} for
    +   * a list of values the grid knows about.
    +   *
    +   */
    +  Grid.prototype.assignTypes = function(){
    +    var self = this;
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +
    +      //Assign colDef type if not specified
    +      if (!colDef.type) {
    +        var col = new GridColumn(colDef, index, self);
    +        var firstRow = self.rows.length > 0 ? self.rows[0] : null;
    +        if (firstRow) {
    +          colDef.type = gridUtil.guessType(self.getCellValue(firstRow, col));
    +        }
    +        else {
    +          gridUtil.logWarn('Unable to assign type from data, so defaulting to string');
    +          colDef.type = 'string';
    +        }
    +      }
    +    });
    +  };
    +
    +  /**
    +  * @ngdoc function
    +  * @name addRowHeaderColumn
    +  * @methodOf ui.grid.class:Grid
    +  * @description adds a row header column to the grid
    +  * @param {object} column def
    +  */
    +  Grid.prototype.addRowHeaderColumn = function addRowHeaderColumn(colDef) {
    +    var self = this;
    +    //self.createLeftContainer();
    +    var rowHeaderCol = new GridColumn(colDef, gridUtil.nextUid(), self);
    +    rowHeaderCol.isRowHeader = true;
    +    if (self.isRTL()) {
    +      self.createRightContainer();
    +      rowHeaderCol.renderContainer = 'right';
    +    }
    +    else {
    +      self.createLeftContainer();
    +      rowHeaderCol.renderContainer = 'left';
    +    }
    +
    +    // relies on the default column builder being first in array, as it is instantiated
    +    // as part of grid creation
    +    self.columnBuilders[0](colDef,rowHeaderCol,self.options)
    +      .then(function(){
    +        rowHeaderCol.enableFiltering = false;
    +        rowHeaderCol.enableSorting = false;
    +        rowHeaderCol.enableHiding = false;
    +        self.rowHeaderColumns.push(rowHeaderCol);
    +        self.buildColumns()
    +          .then( function() {
    +            self.preCompileCellTemplates();
    +            self.refresh();
    +          });
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildColumns
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates GridColumn objects from the columnDefinition.  Calls each registered
    +   * columnBuilder to further process the column
    +   * @param {object} options  An object contains options to use when building columns
    +   *
    +   * * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
    +   *
    +   * @returns {Promise} a promise to load any needed column resources
    +   */
    +  Grid.prototype.buildColumns = function buildColumns(opts) {
    +    var options = {
    +      orderByColumnDefs: false
    +    };
    +
    +    angular.extend(options, opts);
    +
    +    // gridUtil.logDebug('buildColumns');
    +    var self = this;
    +    var builderPromises = [];
    +    var headerOffset = self.rowHeaderColumns.length;
    +    var i;
    +
    +    // Remove any columns for which a columnDef cannot be found
    +    // Deliberately don't use forEach, as it doesn't like splice being called in the middle
    +    // Also don't cache columns.length, as it will change during this operation
    +    for (i = 0; i < self.columns.length; i++){
    +      if (!self.getColDef(self.columns[i].name)) {
    +        self.columns.splice(i, 1);
    +        i--;
    +      }
    +    }
    +
    +    //add row header columns to the grid columns array _after_ columns without columnDefs have been removed
    +    self.rowHeaderColumns.forEach(function (rowHeaderColumn) {
    +      self.columns.unshift(rowHeaderColumn);
    +    });
    +
    +
    +    // look at each column def, and update column properties to match.  If the column def
    +    // doesn't have a column, then splice in a new gridCol
    +    self.options.columnDefs.forEach(function (colDef, index) {
    +      self.preprocessColDef(colDef);
    +      var col = self.getColumn(colDef.name);
    +
    +      if (!col) {
    +        col = new GridColumn(colDef, gridUtil.nextUid(), self);
    +        self.columns.splice(index + headerOffset, 0, col);
    +      }
    +      else {
    +        // tell updateColumnDef that the column was pre-existing
    +        col.updateColumnDef(colDef, false);
    +      }
    +
    +      self.columnBuilders.forEach(function (builder) {
    +        builderPromises.push(builder.call(self, colDef, col, self.options));
    +      });
    +    });
    +
    +    /*** Reorder columns if necessary ***/
    +    if (!!options.orderByColumnDefs) {
    +      // Create a shallow copy of the columns as a cache
    +      var columnCache = self.columns.slice(0);
    +
    +      // We need to allow for the "row headers" when mapping from the column defs array to the columns array
    +      //   If we have a row header in columns[0] and don't account for it   we'll overwrite it with the column in columnDefs[0]
    +
    +      // Go through all the column defs
    +      for (i = 0; i < self.options.columnDefs.length; i++) {
    +        // If the column at this index has a different name than the column at the same index in the column defs...
    +        if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
    +          // Replace the one in the cache with the appropriate column
    +          columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
    +        }
    +        else {
    +          // Otherwise just copy over the one from the initial columns
    +          columnCache[i + headerOffset] = self.columns[i + headerOffset];
    +        }
    +      }
    +
    +      // Empty out the columns array, non-destructively
    +      self.columns.length = 0;
    +
    +      // And splice in the updated, ordered columns from the cache
    +      Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
    +    }
    +
    +    return $q.all(builderPromises).then(function(){
    +      if (self.rows.length > 0){
    +        self.assignTypes();
    +      }
    +    });
    +  };
    +
    +/**
    + * @ngdoc function
    + * @name preCompileCellTemplates
    + * @methodOf ui.grid.class:Grid
    + * @description precompiles all cell templates
    + */
    +  Grid.prototype.preCompileCellTemplates = function() {
    +    var self = this;
    +    this.columns.forEach(function (col) {
    +      var html = col.cellTemplate.replace(uiGridConstants.MODEL_COL_FIELD, self.getQualifiedColField(col));
    +      html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
    +
    +
    +      var compiledElementFn = $compile(html);
    +      col.compiledElementFn = compiledElementFn;
    +
    +      if (col.compiledElementFnDefer) {
    +        col.compiledElementFnDefer.resolve(col.compiledElementFn);
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getGridQualifiedColField
    +   * @methodOf ui.grid.class:Grid
    +   * @description Returns the $parse-able accessor for a column within its $scope
    +   * @param {GridColumn} col col object
    +   */
    +  Grid.prototype.getQualifiedColField = function (col) {
    +    return 'row.entity.' + gridUtil.preEval(col.field);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the left render container if it doesn't already exist
    +   */
    +  Grid.prototype.createLeftContainer = function() {
    +    if (!this.hasLeftContainer()) {
    +      this.renderContainers.left = new GridRenderContainer('left', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name createRightContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates the right render container if it doesn't already exist
    +   */
    +  Grid.prototype.createRightContainer = function() {
    +    if (!this.hasRightContainer()) {
    +      this.renderContainers.right = new GridRenderContainer('right', this, { disableColumnOffset: true });
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if leftContainer exists
    +   */
    +  Grid.prototype.hasLeftContainer = function() {
    +    return this.renderContainers.left !== undefined;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hasLeftContainer
    +   * @methodOf ui.grid.class:Grid
    +   * @description returns true if rightContainer exists
    +   */
    +  Grid.prototype.hasRightContainer = function() {
    +    return this.renderContainers.right !== undefined;
    +  };
    +
    +
    +      /**
    +   * undocumented function
    +   * @name preprocessColDef
    +   * @methodOf ui.grid.class:Grid
    +   * @description defaults the name property from field to maintain backwards compatibility with 2.x
    +   * validates that name or field is present
    +   */
    +  Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
    +    var self = this;
    +
    +    if (!colDef.field && !colDef.name) {
    +      throw new Error('colDef.name or colDef.field property is required');
    +    }
    +
    +    //maintain backwards compatibility with 2.x
    +    //field was required in 2.x.  now name is required
    +    if (colDef.name === undefined && colDef.field !== undefined) {
    +      // See if the column name already exists:
    +      var foundName = self.getColumn(colDef.field);
    +
    +      // If a column with this name already  exists, we will add an incrementing number to the end of the new column name
    +      if (foundName) {
    +        // Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
    +        var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
    +
    +        var foundColumns = self.columns.filter(function (column) {
    +          // Test against the displayName, as that's what'll have the incremented number
    +          return nameRE.test(column.displayName);
    +        })
    +        // Sort the found columns by the end-number
    +        .sort(function (a, b) {
    +          if (a === b) {
    +            return 0;
    +          }
    +          else {
    +            var numA = a.displayName.match(nameRE)[1];
    +            var numB = b.displayName.match(nameRE)[1];
    +
    +            return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
    +          }
    +        });
    +
    +        // Not columns found, so start with number "2"
    +        if (foundColumns.length === 0) {
    +          colDef.name = colDef.field + '2';
    +        }
    +        else {
    +          // Get the number from the final column
    +          var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
    +
    +          // Make sure to parse to an int
    +          lastNum = parseInt(lastNum, 10);
    +
    +          // Add 1 to the number from the last column and tack it on to the field to be the name for this new column 
    +          colDef.name = colDef.field + (lastNum + 1);
    +        }
    +      }
    +      // ... otherwise just use the field as the column name
    +      else {
    +        colDef.name = colDef.field;
    +      }
    +    }
    +
    +  };
    +
    +  // Return a list of items that exist in the `n` array but not the `o` array. Uses optional property accessors passed as third & fourth parameters
    +  Grid.prototype.newInN = function newInN(o, n, oAccessor, nAccessor) {
    +    var self = this;
    +
    +    var t = [];
    +    for (var i = 0; i < n.length; i++) {
    +      var nV = nAccessor ? n[i][nAccessor] : n[i];
    +      
    +      var found = false;
    +      for (var j = 0; j < o.length; j++) {
    +        var oV = oAccessor ? o[j][oAccessor] : o[j];
    +        if (self.options.rowEquality(nV, oV)) {
    +          found = true;
    +          break;
    +        }
    +      }
    +      if (!found) {
    +        t.push(nV);
    +      }
    +    }
    +    
    +    return t;
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getRow
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns the GridRow that contains the rowEntity
    +     * @param {object} rowEntity the gridOptions.data array element instance
    +     */
    +    Grid.prototype.getRow = function getRow(rowEntity) {
    +      var self = this;
    +      var rows = this.rows.filter(function (row) {
    +        return self.options.rowEquality(row.entity, rowEntity);
    +      });
    +      return rows.length > 0 ? rows[0] : null;
    +    };
    +
    +
    +      /**
    +   * @ngdoc function
    +   * @name modifyRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description creates or removes GridRow objects from the newRawData array.  Calls each registered
    +   * rowBuilder to further process the row
    +   *
    +   * Rows are identified using the gridOptions.rowEquality function
    +   */
    +  Grid.prototype.modifyRows = function modifyRows(newRawData) {
    +    var self = this,
    +        i,
    +        rowhash,
    +        found,
    +        newRow;
    +    if ((self.options.useExternalSorting || self.getColumnSorting().length === 0) && newRawData.length > 0) {
    +        var oldRowHash = self.rowHashMap;
    +        if (!oldRowHash) {
    +           oldRowHash = {get: function(){return null;}};
    +        }
    +        self.createRowHashMap();
    +        rowhash = self.rowHashMap;
    +        var wasEmpty = self.rows.length === 0;
    +        self.rows.length = 0;
    +        for (i = 0; i < newRawData.length; i++) {
    +            var newRawRow = newRawData[i];
    +            found = oldRowHash.get(newRawRow);
    +            if (found) {
    +              newRow = found.row; 
    +            }
    +            else {
    +              newRow = self.processRowBuilders(new GridRow(newRawRow, i, self));
    +            }
    +            self.rows.push(newRow);
    +            rowhash.put(newRawRow, {
    +                i: i,
    +                entity: newRawRow,
    +                row:newRow
    +            });
    +        }
    +        //now that we have data, it is save to assign types to colDefs
    +//        if (wasEmpty) {
    +           self.assignTypes();
    +//        }
    +    } else {
    +    if (self.rows.length === 0 && newRawData.length > 0) {
    +      if (self.options.enableRowHashing) {
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          self.rowHashMap.put(newRow, {
    +            i: i,
    +            entity: newRow
    +          });
    +        }
    +      }
    +
    +      self.addRows(newRawData);
    +      //now that we have data, it is save to assign types to colDefs
    +      self.assignTypes();
    +    }
    +    else if (newRawData.length > 0) {
    +      var unfoundNewRows, unfoundOldRows, unfoundNewRowsToFind;
    +
    +      // If row hashing is turned on
    +      if (self.options.enableRowHashing) {
    +        // Array of new rows that haven't been found in the old rowset
    +        unfoundNewRows = [];
    +        // Array of new rows that we explicitly HAVE to search for manually in the old row set. They cannot be looked up by their identity (because it doesn't exist).
    +        unfoundNewRowsToFind = [];
    +        // Map of rows that have been found in the new rowset
    +        var foundOldRows = {};
    +        // Array of old rows that have NOT been found in the new rowset
    +        unfoundOldRows = [];
    +
    +        // Create the row HashMap if it doesn't exist already
    +        if (!self.rowHashMap) {
    +          self.createRowHashMap();
    +        }
    +        rowhash = self.rowHashMap;
    +        
    +        // Make sure every new row has a hash
    +        for (i = 0; i < newRawData.length; i++) {
    +          newRow = newRawData[i];
    +
    +          // Flag this row as needing to be manually found if it didn't come in with a $$hashKey
    +          var mustFind = false;
    +          if (!self.options.getRowIdentity(newRow)) {
    +            mustFind = true;
    +          }
    +
    +          // See if the new row is already in the rowhash
    +          found = rowhash.get(newRow);
    +          // If so...
    +          if (found) {
    +            // See if it's already being used by as GridRow
    +            if (found.row) {
    +              // If so, mark this new row as being found
    +              foundOldRows[self.options.rowIdentity(newRow)] = true;
    +            }
    +          }
    +          else {
    +            // Put the row in the hashmap with the index it corresponds to
    +            rowhash.put(newRow, {
    +              i: i,
    +              entity: newRow
    +            });
    +            
    +            // This row has to be searched for manually in the old row set
    +            if (mustFind) {
    +              unfoundNewRowsToFind.push(newRow);
    +            }
    +            else {
    +              unfoundNewRows.push(newRow);
    +            }
    +          }
    +        }
    +
    +        // Build the list of unfound old rows
    +        for (i = 0; i < self.rows.length; i++) {
    +          var row = self.rows[i];
    +          var hash = self.options.rowIdentity(row.entity);
    +          if (!foundOldRows[hash]) {
    +            unfoundOldRows.push(row);
    +          }
    +        }
    +      }
    +
    +      // Look for new rows
    +      var newRows = unfoundNewRows || [];
    +
    +      // The unfound new rows is either `unfoundNewRowsToFind`, if row hashing is turned on, or straight `newRawData` if it isn't
    +      var unfoundNew = (unfoundNewRowsToFind || newRawData);
    +
    +      // Search for real new rows in `unfoundNew` and concat them onto `newRows`
    +      newRows = newRows.concat(self.newInN(self.rows, unfoundNew, 'entity'));
    +      
    +      self.addRows(newRows); 
    +      
    +      var deletedRows = self.getDeletedRows((unfoundOldRows || self.rows), newRawData);
    +
    +      for (i = 0; i < deletedRows.length; i++) {
    +        if (self.options.enableRowHashing) {
    +          self.rowHashMap.remove(deletedRows[i].entity);
    +        }
    +
    +        self.rows.splice( self.rows.indexOf(deletedRows[i]), 1 );
    +      }
    +    }
    +    // Empty data set
    +    else {
    +      // Reset the row HashMap
    +      self.createRowHashMap();
    +
    +      // Reset the rows length!
    +      self.rows.length = 0;
    +    }
    +    }
    +    
    +    var p1 = $q.when(self.processRowsProcessors(self.rows))
    +      .then(function (renderableRows) {
    +        return self.setVisibleRows(renderableRows);
    +      });
    +
    +    var p2 = $q.when(self.processColumnsProcessors(self.columns))
    +      .then(function (renderableColumns) {
    +        return self.setVisibleColumns(renderableColumns);
    +      });
    +
    +    return $q.all([p1, p2]);
    +  };
    +
    +  Grid.prototype.getDeletedRows = function(oldRows, newRows) {
    +    var self = this;
    +
    +    var olds = oldRows.filter(function (oldRow) {
    +      return !newRows.some(function (newItem) {
    +        return self.options.rowEquality(newItem, oldRow.entity);
    +      });
    +    });
    +    // var olds = self.newInN(newRows, oldRows, null, 'entity');
    +    // dump('olds', olds);
    +    return olds;
    +  };
    +
    +  /**
    +   * Private Undocumented Method
    +   * @name addRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description adds the newRawData array of rows to the grid and calls all registered
    +   * rowBuilders. this keyword will reference the grid
    +   */
    +  Grid.prototype.addRows = function addRows(newRawData) {
    +    var self = this;
    +
    +    var existingRowCount = self.rows.length;
    +    for (var i = 0; i < newRawData.length; i++) {
    +      var newRow = self.processRowBuilders(new GridRow(newRawData[i], i + existingRowCount, self));
    +
    +      if (self.options.enableRowHashing) {
    +        var found = self.rowHashMap.get(newRow.entity);
    +        if (found) {
    +          found.row = newRow;
    +        }
    +      }
    +
    +      self.rows.push(newRow);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name processRowBuilders
    +   * @methodOf ui.grid.class:Grid
    +   * @description processes all RowBuilders for the gridRow
    +   * @param {GridRow} gridRow reference to gridRow
    +   * @returns {GridRow} the gridRow with all additional behavior added
    +   */
    +  Grid.prototype.processRowBuilders = function processRowBuilders(gridRow) {
    +    var self = this;
    +
    +    self.rowBuilders.forEach(function (builder) {
    +      builder.call(self, gridRow, self.options);
    +    });
    +
    +    return gridRow;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerStyleComputation
    +   * @methodOf ui.grid.class:Grid
    +   * @description registered a styleComputation function
    +   * 
    +   * If the function returns a value it will be appended into the grid's `<style>` block
    +   * @param {function($scope)} styleComputation function
    +   */
    +  Grid.prototype.registerStyleComputation = function registerStyleComputation(styleComputationInfo) {
    +    this.styleComputations.push(styleComputationInfo);
    +  };
    +
    +
    +  // NOTE (c0bra): We already have rowBuilders. I think these do exactly the same thing...
    +  // Grid.prototype.registerRowFilter = function(filter) {
    +  //   // TODO(c0bra): validate filter?
    +
    +  //   this.rowFilters.push(filter);
    +  // };
    +
    +  // Grid.prototype.removeRowFilter = function(filter) {
    +  //   var idx = this.rowFilters.indexOf(filter);
    +
    +  //   if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +  //     this.rowFilters.slice(idx, 1);
    +  //   }
    +  // };
    +  
    +  // Grid.prototype.processRowFilters = function(rows) {
    +  //   var self = this;
    +  //   self.rowFilters.forEach(function (filter) {
    +  //     filter.call(self, rows);
    +  //   });
    +  // };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @returns {Array[GridRow]} Updated renderable rows
    +   * @description
    +
    +     Register a "rows processor" function. When the rows are updated,
    +     the grid calls each registered "rows processor", which has a chance
    +     to alter the set of rows (sorting, etc) as long as the count is not
    +     modified.
    +   */
    +  Grid.prototype.registerRowsProcessor = function registerRowsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.rowsProcessors.push(processor);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeRowsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableRows)} rows processor function
    +   * @description Remove a registered rows processor
    +   */
    +  Grid.prototype.removeRowsProcessor = function removeRowsProcessor(processor) {
    +    var idx = this.rowsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.rowsProcessors.splice(idx, 1);
    +    }
    +  };
    +  
    +  /**
    +   * Private Undocumented Method
    +   * @name processRowsProcessors
    +   * @methodOf ui.grid.class:Grid
    +   * @param {Array[GridRow]} The array of "renderable" rows
    +   * @param {Array[GridColumn]} The array of columns
    +   * @description Run all the registered rows processors on the array of renderable rows
    +   */
    +  Grid.prototype.processRowsProcessors = function processRowsProcessors(renderableRows) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableRows = renderableRows.slice(0);
    +    
    +    // self.rowsProcessors.forEach(function (processor) {
    +    //   myRenderableRows = processor.call(self, myRenderableRows, self.columns);
    +
    +    //   if (!renderableRows) {
    +    //     throw "Processor at index " + i + " did not return a set of renderable rows";
    +    //   }
    +
    +    //   if (!angular.isArray(renderableRows)) {
    +    //     throw "Processor at index " + i + " did not return an array";
    +    //   }
    +
    +    //   i++;
    +    // });
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.rowsProcessors.length === 0) {
    +      return $q.when(myRenderableRows);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedRowsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.rowsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedRowsToProcess, self.columns) )
    +        .then(function handleProcessedRows(processedRows) {
    +          // Check for errors
    +          if (!processedRows) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedRows)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.rowsProcessors.length - 1) {
    +            return startProcessor(i, processedRows);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(processedRows);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableRows);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleRows = function setVisibleRows(rows) {
    +    // gridUtil.logDebug('setVisibleRows');
    +
    +    var self = this;
    +
    +    //var newVisibleRowCache = [];
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.canvasHeightShouldUpdate = true;
    +      
    +      if ( typeof(container.visibleRowCache) === 'undefined' ){
    +        container.visibleRowCache = [];  
    +      } else {
    +        container.visibleRowCache.length = 0;  
    +      }
    +    }
    +    
    +    // rows.forEach(function (row) {
    +    for (var ri = 0; ri < rows.length; ri++) {
    +      var row = rows[ri];
    +
    +      // If the row is visible
    +      if (row.visible) {
    +        // newVisibleRowCache.push(row);
    +
    +        // If the row has a container specified
    +        if (typeof(row.renderContainer) !== 'undefined' && row.renderContainer) {
    +          self.renderContainers[row.renderContainer].visibleRowCache.push(row);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleRowCache.push(row);
    +        }
    +      }
    +    }
    +    self.api.core.raise.rowsRendered(this.api);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerColumnsProcessor
    +   * @methodOf ui.grid.class:Grid
    +   * @param {function(renderableColumns)} rows processor function
    +   * @returns {Array[GridColumn]} Updated renderable columns
    +   * @description
    +
    +     Register a "columns processor" function. When the columns are updated,
    +     the grid calls each registered "columns processor", which has a chance
    +     to alter the set of columns, as long as the count is not modified.
    +   */
    +  Grid.prototype.registerColumnsProcessor = function registerColumnsProcessor(processor) {
    +    if (!angular.isFunction(processor)) {
    +      throw 'Attempt to register non-function rows processor: ' + processor;
    +    }
    +
    +    this.columnsProcessors.push(processor);
    +  };
    +
    +  Grid.prototype.removeColumnsProcessor = function removeColumnsProcessor(processor) {
    +    var idx = this.columnsProcessors.indexOf(processor);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.columnsProcessors.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.processColumnsProcessors = function processColumnsProcessors(renderableColumns) {
    +    var self = this;
    +
    +    // Create a shallow copy of the rows so that we can safely sort them without altering the original grid.rows sort order
    +    var myRenderableColumns = renderableColumns.slice(0);
    +
    +    // Return myRenderableRows with no processing if we have no rows processors 
    +    if (self.columnsProcessors.length === 0) {
    +      return $q.when(myRenderableColumns);
    +    }
    +  
    +    // Counter for iterating through rows processors
    +    var i = 0;
    +    
    +    // Promise for when we're done with all the processors
    +    var finished = $q.defer();
    +
    +    // This function will call the processor in self.rowsProcessors at index 'i', and then
    +    //   when done will call the next processor in the list, using the output from the processor
    +    //   at i as the argument for 'renderedRowsToProcess' on the next iteration.
    +    //  
    +    //   If we're at the end of the list of processors, we resolve our 'finished' callback with
    +    //   the result.
    +    function startProcessor(i, renderedColumnsToProcess) {
    +      // Get the processor at 'i'
    +      var processor = self.columnsProcessors[i];
    +
    +      // Call the processor, passing in the rows to process and the current columns
    +      //   (note: it's wrapped in $q.when() in case the processor does not return a promise)
    +      return $q.when( processor.call(self, renderedColumnsToProcess, self.rows) )
    +        .then(function handleProcessedRows(processedColumns) {
    +          // Check for errors
    +          if (!processedColumns) {
    +            throw "Processor at index " + i + " did not return a set of renderable rows";
    +          }
    +
    +          if (!angular.isArray(processedColumns)) {
    +            throw "Processor at index " + i + " did not return an array";
    +          }
    +
    +          // Processor is done, increment the counter
    +          i++;
    +
    +          // If we're not done with the processors, call the next one
    +          if (i <= self.columnsProcessors.length - 1) {
    +            return startProcessor(i, myRenderableColumns);
    +          }
    +          // We're done! Resolve the 'finished' promise
    +          else {
    +            finished.resolve(myRenderableColumns);
    +          }
    +        });
    +    }
    +
    +    // Start on the first processor
    +    startProcessor(0, myRenderableColumns);
    +    
    +    return finished.promise;
    +  };
    +
    +  Grid.prototype.setVisibleColumns = function setVisibleColumns(columns) {
    +    // gridUtil.logDebug('setVisibleColumns');
    +
    +    var self = this;
    +
    +    // Reset all the render container row caches
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      container.visibleColumnCache.length = 0;
    +    }
    +
    +    for (var ci = 0; ci < columns.length; ci++) {
    +      var column = columns[ci];
    +
    +      // If the column is visible
    +      if (column.visible) {
    +        // If the column has a container specified
    +        if (typeof(column.renderContainer) !== 'undefined' && column.renderContainer) {
    +          self.renderContainers[column.renderContainer].visibleColumnCache.push(column);
    +        }
    +        // If not, put it into the body container
    +        else {
    +          self.renderContainers.body.visibleColumnCache.push(column);
    +        }
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name handleWindowResize
    +   * @methodOf ui.grid.class:Grid
    +   * @description Triggered when the browser window resizes; automatically resizes the grid
    +   */
    +  Grid.prototype.handleWindowResize = function handleWindowResize($event) {
    +    var self = this;
    +
    +    self.gridWidth = gridUtil.elementWidth(self.element);
    +    self.gridHeight = gridUtil.elementHeight(self.element);
    +
    +    self.queueRefresh();
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name queueRefresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description todo: @c0bra can you document this method?
    +   */
    +  Grid.prototype.queueRefresh = function queueRefresh() {
    +    var self = this;
    +
    +    if (self.refreshCanceller) {
    +      $timeout.cancel(self.refreshCanceller);
    +    }
    +
    +    self.refreshCanceller = $timeout(function () {
    +      self.refreshCanvas(true);
    +    });
    +
    +    self.refreshCanceller.then(function () {
    +      self.refreshCanceller = null;
    +    });
    +
    +    return self.refreshCanceller;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name updateCanvasHeight
    +   * @methodOf ui.grid.class:Grid
    +   * @description flags all render containers to update their canvas height
    +   */
    +  Grid.prototype.updateCanvasHeight = function updateCanvasHeight() {
    +    var self = this;
    +
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +        container.canvasHeightShouldUpdate = true;
    +      }
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name buildStyles
    +   * @methodOf ui.grid.class:Grid
    +   * @description calls each styleComputation function
    +   */
    +  // TODO: this used to take $scope, but couldn't see that it was used
    +  Grid.prototype.buildStyles = function buildStyles() {
    +    // gridUtil.logDebug('buildStyles');
    +
    +    var self = this;
    +    
    +    self.customStyles = '';
    +
    +    self.styleComputations
    +      .sort(function(a, b) {
    +        if (a.priority === null) { return 1; }
    +        if (b.priority === null) { return -1; }
    +        if (a.priority === null && b.priority === null) { return 0; }
    +        return a.priority - b.priority;
    +      })
    +      .forEach(function (compInfo) {
    +        // this used to provide $scope as a second parameter, but I couldn't find any 
    +        // style builders that used it, so removed it as part of moving to grid from controller
    +        var ret = compInfo.func.call(self);
    +
    +        if (angular.isString(ret)) {
    +          self.customStyles += '\n' + ret;
    +        }
    +      });
    +  };
    +
    +
    +  Grid.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewport = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    self.columns.forEach(function(col, i) {
    +      if (totalWidth < viewport) {
    +        totalWidth += col.drawnWidth;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.columns[j].drawnWidth;
    +        }
    +        if (currWidth < viewport) {
    +          min++;
    +        }
    +      }
    +    });
    +
    +    return min;
    +  };
    +
    +  Grid.prototype.getBodyHeight = function getBodyHeight() {
    +    // Start with the viewportHeight
    +    var bodyHeight = this.getViewportHeight();
    +
    +    // Add the horizontal scrollbar height if there is one
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  bodyHeight = bodyHeight + this.horizontalScrollbarHeight;
    +    //}
    +
    +    return bodyHeight;
    +  };
    +
    +  // NOTE: viewport drawable height is the height of the grid minus the header row height (including any border)
    +  // TODO(c0bra): account for footer height
    +  Grid.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var viewPortHeight = this.gridHeight - this.headerHeight - this.footerHeight;
    +
    +    // Account for native horizontal scrollbar, if present
    +    //if (typeof(this.horizontalScrollbarHeight) !== 'undefined' && this.horizontalScrollbarHeight !== undefined && this.horizontalScrollbarHeight > 0) {
    +    //  viewPortHeight = viewPortHeight - this.horizontalScrollbarHeight;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    //gridUtil.logDebug('viewPortHeight', viewPortHeight);
    +
    +    return viewPortHeight;
    +  };
    +
    +  Grid.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.gridWidth;
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - this.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    //gridUtil.logDebug('getviewPortWidth', viewPortWidth);
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(this.verticalScrollbarWidth) !== 'undefined' && this.verticalScrollbarWidth !== undefined && this.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + this.verticalScrollbarWidth;
    +    //}
    +
    +    return viewPortWidth;
    +  };
    +
    +  Grid.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  Grid.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  Grid.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  Grid.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleRowCache.length;
    +  };
    +
    +   Grid.prototype.getVisibleRows = function getVisibleRows() {
    +    return this.renderContainers.body.visibleRowCache;
    +   };
    +
    +  Grid.prototype.getVisibleColumnCount = function getVisibleColumnCount() {
    +    // var count = 0;
    +
    +    // this.rows.forEach(function (row) {
    +    //   if (row.visible) {
    +    //     count++;
    +    //   }
    +    // });
    +
    +    // return this.visibleRowCache.length;
    +    return this.renderContainers.body.visibleColumnCache.length;
    +  };
    +
    +
    +  Grid.prototype.searchRows = function searchRows(renderableRows) {
    +    return rowSearcher.search(this, renderableRows, this.columns);
    +  };
    +
    +  Grid.prototype.sortByColumn = function sortByColumn(renderableRows) {
    +    return rowSorter.sort(this, renderableRows, this.columns);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCellValue
    +   * @methodOf ui.grid.class:Grid
    +   * @description Gets the value of a cell for a particular row and column
    +   * @param {GridRow} row Row to access
    +   * @param {GridColumn} col Column to access
    +   */
    +  Grid.prototype.getCellValue = function getCellValue(row, col){
    +    var self = this;
    +
    +    if (!self.cellValueGetterCache[col.colDef.name]) {
    +      self.cellValueGetterCache[col.colDef.name] = $parse(row.getEntityQualifiedColField(col));
    +    }
    +
    +    return self.cellValueGetterCache[col.colDef.name](row);
    +  };
    +
    +  
    +  Grid.prototype.getNextColumnSortPriority = function getNextColumnSortPriority() {
    +    var self = this,
    +        p = 0;
    +
    +    self.columns.forEach(function (col) {
    +      if (col.sort && col.sort.priority && col.sort.priority > p) {
    +        p = col.sort.priority;
    +      }
    +    });
    +
    +    return p + 1;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name resetColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @param {GridColumn} [excludedColumn] Optional GridColumn to exclude from having its sorting reset
    +   */
    +  Grid.prototype.resetColumnSorting = function resetColumnSorting(excludeCol) {
    +    var self = this;
    +
    +    self.columns.forEach(function (col) {
    +      if (col !== excludeCol && !col.colDef.suppressRemoveSort) {
    +        col.sort = {};
    +      }
    +    });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColumnSorting
    +   * @methodOf ui.grid.class:Grid
    +   * @description Return the columns that the grid is currently being sorted by
    +   * @returns {Array[GridColumn]} An array of GridColumn objects
    +   */
    +  Grid.prototype.getColumnSorting = function getColumnSorting() {
    +    var self = this;
    +
    +    var sortedCols = [], myCols;
    +
    +    // Iterate through all the columns, sorted by priority
    +    // Make local copy of column list, because sorting is in-place and we do not want to
    +    // change the original sequence of columns
    +    myCols = self.columns.slice(0);
    +    myCols.sort(rowSorter.prioritySort).forEach(function (col) {
    +      if (col.sort && typeof(col.sort.direction) !== 'undefined' && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortedCols.push(col);
    +      }
    +    });
    +
    +    return sortedCols;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name sortColumn
    +   * @methodOf ui.grid.class:Grid
    +   * @description Set the sorting on a given column, optionally resetting any existing sorting on the Grid.
    +   * Emits the sortChanged event whenever the sort criteria are changed.
    +   * @param {GridColumn} column Column to set the sorting on
    +   * @param {uiGridConstants.ASC|uiGridConstants.DESC} [direction] Direction to sort by, either descending or ascending.
    +   *   If not provided, the column will iterate through the sort directions: ascending, descending, unsorted.
    +   * @param {boolean} [add] Add this column to the sorting. If not provided or set to `false`, the Grid will reset any existing sorting and sort
    +   *   by this column only
    +   * @returns {Promise} A resolved promise that supplies the column.
    +   */
    +  
    +  Grid.prototype.sortColumn = function sortColumn(column, directionOrAdd, add) {
    +    var self = this,
    +        direction = null;
    +
    +    if (typeof(column) === 'undefined' || !column) {
    +      throw new Error('No column parameter provided');
    +    }
    +
    +    // Second argument can either be a direction or whether to add this column to the existing sort.
    +    //   If it's a boolean, it's an add, otherwise, it's a direction
    +    if (typeof(directionOrAdd) === 'boolean') {
    +      add = directionOrAdd;
    +    }
    +    else {
    +      direction = directionOrAdd;
    +    }
    +    
    +    if (!add) {
    +      self.resetColumnSorting(column);
    +      column.sort.priority = 0;
    +    }
    +    else {
    +      column.sort.priority = self.getNextColumnSortPriority();
    +    }
    +
    +    if (!direction) {
    +      // Figure out the sort direction
    +      if (column.sort.direction && column.sort.direction === uiGridConstants.ASC) {
    +        column.sort.direction = uiGridConstants.DESC;
    +      }
    +      else if (column.sort.direction && column.sort.direction === uiGridConstants.DESC) {
    +        if ( column.colDef && column.colDef.suppressRemoveSort ){
    +          column.sort.direction = uiGridConstants.ASC;
    +        } else {
    +          column.sort.direction = null;
    +        }
    +      }
    +      else {
    +        column.sort.direction = uiGridConstants.ASC;
    +      }
    +    }
    +    else {
    +      column.sort.direction = direction;
    +    }
    +    
    +    self.api.core.raise.sortChanged( self, self.getColumnSorting() );
    +
    +    return $q.when(column);
    +  };
    +  
    +  /**
    +   * communicate to outside world that we are done with initial rendering
    +   */
    +  Grid.prototype.renderingComplete = function(){
    +    if (angular.isFunction(this.options.onRegisterApi)) {
    +      this.options.onRegisterApi(this.api);
    +    }
    +    this.api.core.raise.renderingComplete( this.api );
    +  };
    +
    +  Grid.prototype.createRowHashMap = function createRowHashMap() {
    +    var self = this;
    +
    +    var hashMap = new RowHashMap();
    +    hashMap.grid = self;
    +
    +    self.rowHashMap = hashMap;
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refresh
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered grid on screen.
    +   * @params {boolean} [rowsAltered] Optional flag for refreshing when the number of rows has changed.
    +   */
    +  Grid.prototype.refresh = function refresh(rowsAltered) {
    +    var self = this;
    +    
    +    var p1 = self.processRowsProcessors(self.rows).then(function (renderableRows) {
    +      self.setVisibleRows(renderableRows);
    +    });
    +
    +    var p2 = self.processColumnsProcessors(self.columns).then(function (renderableColumns) {
    +      self.setVisibleColumns(renderableColumns);
    +    });
    +
    +    return $q.all([p1, p2]).then(function () {
    +      self.redrawInPlace(rowsAltered);
    +
    +      self.refreshCanvas(true);
    +    });
    +  };
    +  
    +  /**
    +   * @ngdoc function
    +   * @name refreshRows
    +   * @methodOf ui.grid.class:Grid
    +   * @description Refresh the rendered rows on screen?  Note: not functional at present 
    +   * @returns {promise} promise that is resolved when render completes?
    +   * 
    +   */
    +  Grid.prototype.refreshRows = function refreshRows() {
    +    var self = this;
    +    
    +    return self.processRowsProcessors(self.rows)
    +      .then(function (renderableRows) {
    +        self.setVisibleRows(renderableRows);
    +
    +        self.redrawInPlace();
    +
    +        self.refreshCanvas( true );
    +      });
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description TBD
    +   * @params {object} buildStyles optional parameter.  Use TBD
    +   * @returns {promise} promise that is resolved when the canvas
    +   * has been refreshed
    +   * 
    +   */
    +  Grid.prototype.refreshCanvas = function(buildStyles) {
    +    var self = this;
    +
    +    if (buildStyles) {
    +      self.buildStyles();
    +    }
    +
    +    var p = $q.defer();
    +
    +    // Get all the header heights
    +    var containerHeadersToRecalc = [];
    +    for (var containerId in self.renderContainers) {
    +      if (self.renderContainers.hasOwnProperty(containerId)) {
    +        var container = self.renderContainers[containerId];
    +
    +        // Skip containers that have no canvasWidth set yet
    +        if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +          continue;
    +        }
    +
    +        if (container.header || container.headerCanvas) {
    +          containerHeadersToRecalc.push(container);
    +        }
    +      }
    +    }
    +
    +    /*
    +     *
    +     * Here we loop through the headers, measuring each element as well as any header "canvas" it has within it.
    +     *
    +     * If any header is less than the largest header height, it will be resized to that so that we don't have headers
    +     * with different heights, which looks like a rendering problem
    +     *
    +     * We'll do the same thing with the header canvases, and give the header CELLS an explicit height if their canvas
    +     * is smaller than the largest canvas height. That was header cells without extra controls like filtering don't
    +     * appear shorter than other cells.
    +     *
    +     */
    +    if (containerHeadersToRecalc.length > 0) {
    +      // Putting in a timeout as it's not calculating after the grid element is rendered and filled out
    +      $timeout(function() {
    +        // var oldHeaderHeight = self.grid.headerHeight;
    +        // self.grid.headerHeight = gridUtil.outerElementHeight(self.header);
    +
    +        var rebuildStyles = false;
    +
    +        // Get all the header heights
    +        var maxHeaderHeight = 0;
    +        var maxHeaderCanvasHeight = 0;
    +        var i, container;
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // Skip containers that have no canvasWidth set yet
    +          if (container.canvasWidth === null || isNaN(container.canvasWidth)) {
    +            continue;
    +          }
    +
    +          if (container.header) {
    +            var oldHeaderHeight = container.headerHeight;
    +            var headerHeight = gridUtil.outerElementHeight(container.header);
    +
    +            container.headerHeight = parseInt(headerHeight, 10);
    +
    +            if (oldHeaderHeight !== headerHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Get the "inner" header height, that is the height minus the top and bottom borders, if present. We'll use it to make sure all the headers have a consistent height
    +            var topBorder = gridUtil.getBorderSize(container.header, 'top');
    +            var bottomBorder = gridUtil.getBorderSize(container.header, 'bottom');
    +            var innerHeaderHeight = parseInt(headerHeight - topBorder - bottomBorder, 10);
    +
    +            innerHeaderHeight  = innerHeaderHeight < 0 ? 0 : innerHeaderHeight;
    +
    +            container.innerHeaderHeight = innerHeaderHeight;
    +
    +            // Save the largest header height for use later
    +            if (innerHeaderHeight > maxHeaderHeight) {
    +              maxHeaderHeight = innerHeaderHeight;
    +            }
    +          }
    +
    +          if (container.headerCanvas) {
    +            var oldHeaderCanvasHeight = container.headerCanvasHeight;
    +            var headerCanvasHeight = gridUtil.outerElementHeight(container.headerCanvas);
    +
    +            container.headerCanvasHeight = parseInt(headerCanvasHeight, 10);
    +
    +            if (oldHeaderCanvasHeight !== headerCanvasHeight) {
    +              rebuildStyles = true;
    +            }
    +
    +            // Save the largest header canvas height for use later
    +            if (headerCanvasHeight > maxHeaderCanvasHeight) {
    +              maxHeaderCanvasHeight = headerCanvasHeight;
    +            }
    +          }
    +        }
    +
    +        // Go through all the headers
    +        for (i = 0; i < containerHeadersToRecalc.length; i++) {
    +          container = containerHeadersToRecalc[i];
    +
    +          // If this header's height is less than another header's height, then explicitly set it so they're the same and one isn't all offset and weird looking
    +          if (maxHeaderHeight > 0 && typeof(container.headerHeight) !== 'undefined' && container.headerHeight !== null && container.headerHeight < maxHeaderHeight) {
    +            container.explicitHeaderHeight = maxHeaderHeight;
    +          }
    +
    +          if (typeof(container.headerCanvasHeight) !== 'undefined' && container.headerCanvasHeight !== null && maxHeaderCanvasHeight > 0 && container.headerCanvasHeight < maxHeaderCanvasHeight) {
    +            container.explicitHeaderCanvasHeight = maxHeaderCanvasHeight;
    +          }
    +        }
    +
    +        // Rebuild styles if the header height has changed
    +        //   The header height is used in body/viewport calculations and those are then used in other styles so we need it to be available
    +        if (buildStyles && rebuildStyles) {
    +          self.buildStyles();
    +        }
    +
    +        p.resolve();
    +      });
    +    }
    +    else {
    +      // Timeout still needs to be here to trigger digest after styles have been rebuilt
    +      $timeout(function() {
    +        p.resolve();
    +      });
    +    }
    +
    +    return p.promise;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name redrawCanvas
    +   * @methodOf ui.grid.class:Grid
    +   * @description Redraw the rows and columns based on our current scroll position
    +   * @param {boolean} [rowsAdded] Optional to indicate rows are added and the scroll percentage must be recalculated
    +   * 
    +   */
    +  Grid.prototype.redrawInPlace = function redrawInPlace(rowsAdded) {
    +    // gridUtil.logDebug('redrawInPlace');
    +    
    +    var self = this;
    +
    +    for (var i in self.renderContainers) {
    +      var container = self.renderContainers[i];
    +
    +      // gridUtil.logDebug('redrawing container', i);
    +      
    +      if (rowsAdded) {
    +        container.adjustRows(container.prevScrollTop, null);
    +        container.adjustColumns(container.prevScrollTop, null);
    +      }
    +      else {
    +        container.adjustRows(null, container.prevScrolltopPercentage);
    +        container.adjustColumns(null, container.prevScrollleftPercentage);
    +      }
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasLeftContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if leftContainer has columns
    +     */
    +    Grid.prototype.hasLeftContainerColumns = function () {
    +      return this.hasLeftContainer() && this.renderContainers.left.renderedColumns.length > 0;
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name hasRightContainerColumns
    +     * @methodOf ui.grid.class:Grid
    +     * @description returns true if rightContainer has columns
    +     */
    +    Grid.prototype.hasRightContainerColumns = function () {
    +      return this.hasRightContainer() && this.renderContainers.right.renderedColumns.length > 0;
    +    };
    +
    +
    +
    +
    +  // Blatantly stolen from Angular as it isn't exposed (yet? 2.0?)
    +  function RowHashMap() {}
    +
    +  RowHashMap.prototype = {
    +    /**
    +     * Store key value pair
    +     * @param key key to store can be any type
    +     * @param value value to store can be any type
    +     */
    +    put: function(key, value) {
    +      this[this.grid.options.rowIdentity(key)] = value;
    +    },
    +
    +    /**
    +     * @param key
    +     * @returns {Object} the value for the key
    +     */
    +    get: function(key) {
    +      return this[this.grid.options.rowIdentity(key)];
    +    },
    +
    +    /**
    +     * Remove the key/value pair
    +     * @param key
    +     */
    +    remove: function(key) {
    +      var value = this[key = this.grid.options.rowIdentity(key)];
    +      delete this[key];
    +      return value;
    +    }
    +  };
    +
    +
    +
    +  return Grid;
    +
    +}]);
    +
    +})();
    +
    +(function () {
    +
    +  angular.module('ui.grid')
    +    .factory('GridApi', ['$q', '$rootScope', 'gridUtil', 'uiGridConstants', 'GridRow', 'uiGridGridMenuService',
    +      function ($q, $rootScope, gridUtil, uiGridConstants, GridRow, uiGridGridMenuService) {
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:GridApi
    +         * @description GridApi provides the ability to register public methods events inside the grid and allow
    +         * for other components to use the api via featureName.raise.methodName and featureName.on.eventName(function(args){}.
    +         * <br/>
    +         * To listen to events, you must add a callback to gridOptions.onRegisterApi
    +         * <pre>
    +         *   $scope.gridOptions.onRegisterApi = function(gridApi){
    +         *      gridApi.cellNav.on.navigate($scope,function(newRowCol, oldRowCol){
    +         *          $log.log('navigation event');
    +         *      });
    +         *   };
    +         * </pre>
    +         * @param {object} grid grid that owns api
    +         */
    +        var GridApi = function GridApi(grid) {
    +          this.grid = grid;
    +          this.listeners = [];
    +          
    +          /**
    +           * @ngdoc function
    +           * @name renderingComplete
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Rendering is complete, called at the same
    +           * time as `onRegisterApi`, but provides a way to obtain
    +           * that same event within features without stopping end
    +           * users from getting at the onRegisterApi method.
    +           * 
    +           * Included in gridApi so that it's always there - otherwise
    +           * there is still a timing problem with when a feature can
    +           * call this. 
    +           * 
    +           * @param {GridApi} gridApi the grid api, as normally 
    +           * returned in the onRegisterApi method
    +           * 
    +           * @example
    +           * <pre>
    +           *      gridApi.core.on.renderingComplete( grid );
    +           * </pre>
    +           */
    +          this.registerEvent( 'core', 'renderingComplete' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name filterChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the filter is changed.  The nature
    +           * of the watch expression doesn't allow notification of what changed,
    +           * so the receiver of this event will need to re-extract the filter 
    +           * conditions from the columns.
    +           * 
    +           */
    +          this.registerEvent( 'core', 'filterChanged' );
    +
    +          /**
    +           * @ngdoc function
    +           * @name setRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Sets an override on the row to make it always invisible,
    +           * which will override any filtering or other visibility calculations.  
    +           * If the row is currently visible then sets it to invisible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name clearRowInvisible
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Clears any override on visibility for the row so that it returns to 
    +           * using normal filtering and other visibility calculations.  
    +           * If the row is currently invisible then sets it to visible and calls
    +           * both grid refresh and emits the rowsVisibleChanged event
    +           * TODO: if a filter is active then we can't just set it to visible?
    +           * @param {object} rowEntity gridOptions.data[] array instance
    +           */
    +          this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible );
    +      
    +          /**
    +           * @ngdoc function
    +           * @name getVisibleRows
    +           * @methodOf  ui.grid.core.api:PublicApi
    +           * @description Returns all visible rows
    +           * @param {Grid} grid the grid you want to get visible rows from
    +           * @returns {array} an array of gridRow
    +           */
    +          this.registerMethod( 'core', 'getVisibleRows', this.grid.getVisibleRows );
    +          
    +          /**
    +           * @ngdoc event
    +           * @name rowsVisibleChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the rows that are visible
    +           * change.  The filtering is zero-based, so it isn't possible
    +           * to say which rows changed (unlike in the selection feature).
    +           * We can plausibly know which row was changed when setRowInvisible
    +           * is called, but in that situation the user already knows which row
    +           * they changed.  When a filter runs we don't know what changed,
    +           * and that is the one that would have been useful.
    +           *
    +           */
    +          this.registerEvent( 'core', 'rowsVisibleChanged' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name rowsRendered
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised after the cache of visible rows is changed.
    +           */
    +          this.registerEvent( 'core', 'rowsRendered' );
    +
    +
    +          /**
    +           * @ngdoc event
    +           * @name scrollEvent
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised on a scroll Event.  Called frequently so be careful what you do with it
    +           */
    +          this.registerEvent( 'core', 'scrollEvent' );
    +
    +          /**
    +           * @ngdoc event
    +           * @name canvasHeightChanged
    +           * @eventOf  ui.grid.core.api:PublicApi
    +           * @description  is raised when the canvas height has changed
    +           * <br/>
    +           * arguments: oldHeight, newHeight
    +           */
    +          this.registerEvent( 'core', 'canvasHeightChanged');
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name ui.grid.class:suppressEvents
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Used to execute a function while disabling the specified event listeners.
    +         * Disables the listenerFunctions, executes the callbackFn, and then enables
    +         * the listenerFunctions again
    +         * @param {object} listenerFuncs listenerFunc or array of listenerFuncs to suppress. These must be the same
    +         * functions that were used in the .on.eventName method
    +         * @param {object} callBackFn function to execute
    +         * @example
    +         * <pre>
    +         *    var navigate = function (newRowCol, oldRowCol){
    +         *       //do something on navigate
    +         *    }
    +         *
    +         *    gridApi.cellNav.on.navigate(scope,navigate);
    +         *
    +         *
    +         *    //call the scrollTo event and suppress our navigate listener
    +         *    //scrollTo will still raise the event for other listeners
    +         *    gridApi.suppressEvents(navigate, function(){
    +         *       gridApi.cellNav.scrollTo(aRow, aCol);
    +         *    });
    +         *
    +         * </pre>
    +         */
    +        GridApi.prototype.suppressEvents = function (listenerFuncs, callBackFn) {
    +          var self = this;
    +          var listeners = angular.isArray(listenerFuncs) ? listenerFuncs : [listenerFuncs];
    +
    +          //find all registered listeners
    +          var foundListeners = [];
    +          listeners.forEach(function (l) {
    +            foundListeners = self.listeners.filter(function (lstnr) {
    +              return l === lstnr.handler;
    +            });
    +          });
    +
    +          //deregister all the listeners
    +          foundListeners.forEach(function(l){
    +            l.dereg();
    +          });
    +
    +          callBackFn();
    +
    +          //reregister all the listeners
    +          foundListeners.forEach(function(l){
    +              l.dereg = registerEventWithAngular(l.eventId, l.handler, self.grid, l._this);
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEvent
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature.  The event will get a
    +         * .raise and .on prepended to it
    +         * <br>
    +         * .raise.eventName() - takes no arguments
    +         * <br/>
    +         * <br/>
    +         * .on.eventName(scope, callBackFn, _this)
    +         * <br/>
    +         * scope - a scope reference to add a deregister call to the scopes .$on('destroy')
    +         * <br/>
    +         * callBackFn - The function to call
    +         * <br/>
    +         * _this - optional this context variable for callbackFn. If omitted, grid.api will be used for the context
    +         * <br/>
    +         * .on.eventName returns a dereg funtion that will remove the listener.  It's not necessary to use it as the listener
    +         * will be removed when the scope is destroyed.
    +         * @param {string} featureName name of the feature that raises the event
    +         * @param {string} eventName  name of the event
    +         */
    +        GridApi.prototype.registerEvent = function (featureName, eventName) {
    +          var self = this;
    +          if (!self[featureName]) {
    +            self[featureName] = {};
    +          }
    +
    +          var feature = self[featureName];
    +          if (!feature.on) {
    +            feature.on = {};
    +            feature.raise = {};
    +          }
    +
    +          var eventId = self.grid.id + featureName + eventName;
    +
    +          // gridUtil.logDebug('Creating raise event method ' + featureName + '.raise.' + eventName);
    +          feature.raise[eventName] = function () {
    +            $rootScope.$emit.apply($rootScope, [eventId].concat(Array.prototype.slice.call(arguments)));
    +          };
    +
    +          // gridUtil.logDebug('Creating on event method ' + featureName + '.on.' + eventName);
    +          feature.on[eventName] = function (scope, handler, _this) {
    +            var deregAngularOn = registerEventWithAngular(eventId, handler, self.grid, _this);
    +
    +            //track our listener so we can turn off and on
    +            var listener = {handler: handler, dereg: deregAngularOn, eventId: eventId, scope: scope, _this:_this};
    +            self.listeners.push(listener);
    +
    +            var removeListener = function(){
    +              listener.dereg();
    +              var index = self.listeners.indexOf(listener);
    +              self.listeners.splice(index,1);
    +            };
    +
    +            //destroy tracking when scope is destroyed
    +            scope.$on('$destroy', function() {
    +              removeListener();
    +            });
    +
    +            return removeListener;
    +          };
    +        };
    +
    +        function registerEventWithAngular(eventId, handler, grid, _this) {
    +          return $rootScope.$on(eventId, function (event) {
    +            var args = Array.prototype.slice.call(arguments);
    +            args.splice(0, 1); //remove evt argument
    +            handler.apply(_this ? _this : grid.api, args);
    +          });
    +        }
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerEventsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and events from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <pre>
    +         * {featureName:
    +         *        {
    +         *          eventNameOne:function(args){},
    +         *          eventNameTwo:function(args){}
    +         *        }
    +         *  }
    +         * </pre>
    +         * @param {object} eventObjectMap map of feature/event names
    +         */
    +        GridApi.prototype.registerEventsFromObject = function (eventObjectMap) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(eventObjectMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, events: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.events.push(propName);
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.events.forEach(function (event) {
    +              self.registerEvent(feature.name, event);
    +            });
    +          });
    +
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethod
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers a new event for the given feature
    +         * @param {string} featureName name of the feature
    +         * @param {string} methodName  name of the method
    +         * @param {object} callBackFn function to execute
    +         * @param {object} _this binds callBackFn 'this' to _this.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethod = function (featureName, methodName, callBackFn, _this) {
    +          if (!this[featureName]) {
    +            this[featureName] = {};
    +          }
    +
    +          var feature = this[featureName];
    +
    +          feature[methodName] = gridUtil.createBoundedWrapper(_this || this.grid, callBackFn);
    +        };
    +
    +        /**
    +         * @ngdoc function
    +         * @name registerMethodsFromObject
    +         * @methodOf ui.grid.class:GridApi
    +         * @description Registers features and methods from a simple objectMap.
    +         * eventObjectMap must be in this format (multiple features allowed)
    +         * <br>
    +         * {featureName:
    +         *        {
    +         *          methodNameOne:function(args){},
    +         *          methodNameTwo:function(args){}
    +         *        }
    +         * @param {object} eventObjectMap map of feature/event names
    +         * @param {object} _this binds this to _this for all functions.  Defaults to gridApi.grid
    +         */
    +        GridApi.prototype.registerMethodsFromObject = function (methodMap, _this) {
    +          var self = this;
    +          var features = [];
    +          angular.forEach(methodMap, function (featProp, featPropName) {
    +            var feature = {name: featPropName, methods: []};
    +            angular.forEach(featProp, function (prop, propName) {
    +              feature.methods.push({name: propName, fn: prop});
    +            });
    +            features.push(feature);
    +          });
    +
    +          features.forEach(function (feature) {
    +            feature.methods.forEach(function (method) {
    +              self.registerMethod(feature.name, method.name, method.fn, _this);
    +            });
    +          });
    +
    +        };
    +        
    +        return GridApi;
    +
    +      }]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridColumn', ['gridUtil', 'uiGridConstants', 'i18nService', function(gridUtil, uiGridConstants, i18nService) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridColumn
    +   * @description Represents the viewModel for each column.  Any state or methods needed for a Grid Column
    +   * are defined on this prototype
    +   * @param {ColDef} colDef Column definition.
    +   * @param {number} index the current position of the column in the array
    +   * @param {Grid} grid reference to the grid
    +   */
    +   
    +  /**
    +   * ******************************************************************************************
    +   * PaulL1: Ugly hack here in documentation.  These properties are clearly properties of GridColumn, 
    +   * and need to be noted as such for those extending and building ui-grid itself.
    +   * However, from an end-developer perspective, they interact with all these through columnDefs,
    +   * and they really need to be documented there.  I feel like they're relatively static, and
    +   * I can't find an elegant way for ngDoc to reference to both....so I've duplicated each
    +   * comment block.  Ugh.
    +   * 
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name name
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description (mandatory) each column should have a name, although for backward
    +   * compatibility with 2.x name can be omitted if field is present
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name displayName
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Column name that will be shown in the header.  If displayName is not
    +   * provided then one is generated using the name.
    +   *
    +   */
    +       
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.
    +   * See the angular docs on binding expressions.
    +   *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name field
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description field must be provided if you wish to bind to a 
    +   * property in the data source.  Should be an angular expression that evaluates against grid.options.data 
    +   * array element.  Can be a complex expression: <code>employee.address.city</code>, or can be a function: <code>employee.getFullAddress()</code>.    * See the angular docs on binding expressions.    *
    +   */
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name filter
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filter on this column.  
    +   * @example
    +   * <pre>{ term: 'text', condition: uiGridConstants.filter.STARTS_WITH, placeholder: 'type to filter...', flags: { caseSensitive: false } }</pre>
    +   *
    +   */
    +    
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name GridColumn
    +   * @description Initializes a gridColumn
    +   * @param {ColumnDef} colDef the column def to associate with this column
    +   * @param {number} uid the unique and immutable uid we'd like to allocate to this column
    +   * @param {Grid} grid the grid we'd like to create this column in
    +   */ 
    +  function GridColumn(colDef, uid, grid) {
    +    var self = this;
    +
    +    self.grid = grid;
    +    self.uid = uid;
    +
    +    self.updateColumnDef(colDef, true);
    +  }
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name setPropertyOrDefault
    +   * @description Sets a property on the column using the passed in columnDef, and
    +   * setting the defaultValue if the value cannot be found on the colDef
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {string} propName the property name we'd like to set
    +   * @param {object} defaultValue the value to use if the colDef doesn't provide the setting
    +   */ 
    +  GridColumn.prototype.setPropertyOrDefault = function (colDef, propName, defaultValue) {
    +    var self = this;
    +
    +    // Use the column definition filter if we were passed it
    +    if (typeof(colDef[propName]) !== 'undefined' && colDef[propName]) {
    +      self[propName] = colDef[propName];
    +    }
    +    // Otherwise use our own if it's set
    +    else if (typeof(self[propName]) !== 'undefined') {
    +      self[propName] = self[propName];
    +    }
    +    // Default to empty object for the filter
    +    else {
    +      self[propName] = defaultValue ? defaultValue : {};
    +    }
    +  };
    +
    +  
    +  
    +  /** 
    +   * @ngdoc property
    +   * @name width
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the column width.  Can be either 
    +   * a number or a percentage, or an * for auto.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', width: 100},
    +   *                                          { field: 'field2', width: '20%'},
    +   *                                          { field: 'field3', width: '*' }]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name minWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the minimum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', minWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name maxWidth
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets the maximum column width.  Should be a number.
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', maxWidth: 100}]; </pre>
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name visible
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description sets whether or not the column is visible
    +   * </br>Default is true
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *     { field: 'field1', visible: true},
    +   *     { field: 'field2', visible: false }
    +   *   ]; </pre>
    +   *
    +   */
    +   
    +  /**
    +   * @ngdoc property
    +   * @name sort
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Can be used to set the sort direction for the column, values are
    +   * uiGridConstants.ASC or uiGridConstants.DESC
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ { field: 'field1', sort: { direction: uiGridConstants.ASC }}] </pre>
    +   */
    +  
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +
    +  /** 
    +   * @ngdoc property
    +   * @name sortingAlgorithm
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Algorithm to use for sorting this column. Takes 'a' and 'b' parameters 
    +   * like any normal sorting function.
    +   *
    +   */
    +      
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description Specify multiple filter fields.
    +   * @example
    +   * <pre>$scope.gridOptions.columnDefs = [ 
    +   *   {
    +   *     field: 'field1', filters: [
    +   *       {
    +   *         term: 'aa',
    +   *         condition: uiGridConstants.filter.STARTS_WITH,
    +   *         placeholder: 'starts with...',
    +   *         flags: { caseSensitive: false }
    +   *       },
    +   *       {
    +   *         condition: uiGridConstants.filter.ENDS_WITH,
    +   *         placeholder: 'ends with...'
    +   *       }
    +   *     ]
    +   *   }
    +   * ]; </pre>
    +   *
    +   * 
    +   */ 
    +   
    +  /** 
    +   * @ngdoc array
    +   * @name filters
    +   * @propertyOf ui.grid.class:GridColumn
    +   * @description Filters for this column. Includes 'term' property bound to filter input elements.
    +   * @example
    +   * <pre>[
    +   *   {
    +   *     term: 'foo', // ngModel for <input>
    +   *     condition: uiGridConstants.filter.STARTS_WITH,
    +   *     placeholder: 'starts with...',
    +   *     flags: { caseSensitive: false }
    +   *   },
    +   *   {
    +   *     term: 'baz',
    +   *     condition: uiGridConstants.filter.ENDS_WITH,
    +   *     placeholder: 'ends with...'
    +   *   }
    +   * ] </pre>
    +   *
    +   * 
    +   */   
    +
    +  /** 
    +   * @ngdoc array
    +   * @name menuItems
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description used to add menu items to a column.  Refer to the tutorial on this 
    +   * functionality.  A number of settings are supported:
    +   * 
    +   * - title: controls the title that is displayed in the menu
    +   * - icon: the icon shown alongside that title
    +   * - action: the method to call when the menu is clicked
    +   * - shown: a function to evaluate to determine whether or not to show the item
    +   * - active: a function to evaluate to determine whether or not the item is currently selected
    +   * - context: context to pass to the action function??
    +   * @example
    +   * <pre>  $scope.gridOptions.columnDefs = [ 
    +   *   { field: 'field1', menuItems: [
    +   *     {
    +   *       title: 'Outer Scope Alert',
    +   *       icon: 'ui-grid-icon-info-circled',
    +   *       action: function($event) {
    +   *         this.context.blargh(); // $scope.blargh() would work too, this is just an example
    +   *       },
    +   *       shown: function() { return true; },
    +   *       active: function() { return true; },
    +   *       context: $scope
    +   *     },
    +   *     {
    +   *       title: 'Grid ID',
    +   *       action: function() {
    +   *         alert('Grid ID: ' + this.grid.id);
    +   *       }
    +   *     }
    +   *   ] }]; </pre>
    +   *
    +   */   
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:GridColumn
    +   * @name updateColumnDef
    +   * @description Moves settings from the columnDef down onto the column,
    +   * and sets properties as appropriate
    +   * @param {ColumnDef} colDef the column def to look in for the property value
    +   * @param {boolean} isNew whether the column is being newly created, if not
    +   * we're updating an existing column, and some items such as the sort shouldn't
    +   * be copied down
    +   */ 
    +  GridColumn.prototype.updateColumnDef = function(colDef, isNew) {
    +    var self = this;
    +
    +    self.colDef = colDef;
    +
    +    if (colDef.name === undefined) {
    +      throw new Error('colDef.name is required for column at index ' + self.grid.options.columnDefs.indexOf(colDef));
    +    }
    +
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +    
    +    var parseErrorMsg = "Cannot parse column width '" + colDef.width + "' for column named '" + colDef.name + "'";
    +
    +    // If width is not defined, set it to a single star
    +    if (gridUtil.isNullOrUndefined(self.width) || !angular.isNumber(self.width)) {
    +      if (gridUtil.isNullOrUndefined(colDef.width)) {
    +        self.width = '*';
    +      }
    +      else {
    +        // If the width is not a number
    +        if (!angular.isNumber(colDef.width)) {
    +          // See if it ends with a percent
    +          if (gridUtil.endsWith(colDef.width, '%')) {
    +            // If so we should be able to parse the non-percent-sign part to a number
    +            var percentStr = colDef.width.replace(/%/g, '');
    +            var percent = parseInt(percentStr, 10);
    +            if (isNaN(percent)) {
    +              throw new Error(parseErrorMsg);
    +            }
    +            self.width = colDef.width;
    +          }
    +          // And see if it's a number string
    +          else if (colDef.width.match(/^(\d+)$/)) {
    +            self.width = parseInt(colDef.width.match(/^(\d+)$/)[1], 10);
    +          }
    +          // Otherwise it should be a string of asterisks
    +          else if (colDef.width.match(/^\*+$/)) {
    +            self.width = colDef.width;
    +          }
    +          // No idea, throw an Error
    +          else {
    +            throw new Error(parseErrorMsg);
    +          }
    +        }
    +        // Is a number, use it as the width
    +        else {
    +          self.width = colDef.width;
    +        }
    +      }
    +    }
    +
    +    self.minWidth = !colDef.minWidth ? 30 : colDef.minWidth;
    +    self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
    +
    +    //use field if it is defined; name if it is not
    +    self.field = (colDef.field === undefined) ? colDef.name : colDef.field;
    +    
    +    if ( typeof( self.field ) !== 'string' ){
    +      gridUtil.logError( 'Field is not a string, this is likely to break the code, Field is: ' + self.field );
    +    }
    +    
    +    self.name = colDef.name;
    +
    +    // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
    +    self.displayName = (colDef.displayName === undefined) ? gridUtil.readableColumnName(colDef.name) : colDef.displayName;
    +
    +    //self.originalIndex = index;
    +
    +    self.aggregationType = angular.isDefined(colDef.aggregationType) ? colDef.aggregationType : null;
    +    self.footerCellTemplate = angular.isDefined(colDef.footerCellTemplate) ? colDef.footerCellTemplate : null;
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.footerCellClass = colDef.footerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.cellClass = colDef.cellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellClass
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellClass can be a string specifying the class to append to a cell
    +     * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
    +     *
    +     */
    +    self.headerCellClass = colDef.headerCellClass;
    +
    +    /**
    +     * @ngdoc property
    +     * @name cellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description cellFilter is a filter to apply to the content of each cell
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].cellFilter = 'date'
    +     *
    +     */
    +    self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name headerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description headerCellFilter is a filter to apply to the content of the column header
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].headerCellFilter = 'translate'
    +     *
    +     */
    +    self.headerCellFilter = colDef.headerCellFilter ? colDef.headerCellFilter : "";
    +
    +    /**
    +     * @ngdoc property
    +     * @name footerCellFilter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description footerCellFilter is a filter to apply to the content of the column footer
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].footerCellFilter = 'date'
    +     *
    +     */
    +    self.footerCellFilter = colDef.footerCellFilter ? colDef.footerCellFilter : "";
    +
    +    self.visible = gridUtil.isNullOrUndefined(colDef.visible) || colDef.visible;
    +
    +    self.headerClass = colDef.headerClass;
    +    //self.cursor = self.sortable ? 'pointer' : 'default';
    +
    +    // Turn on sorting by default
    +    self.enableSorting = typeof(colDef.enableSorting) !== 'undefined' ? colDef.enableSorting : true;
    +    self.sortingAlgorithm = colDef.sortingAlgorithm;
    +
    +    /**
    +     * @ngdoc property
    +     * @name enableFiltering
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description turn off filtering for an individual column, where
    +     * you've turned on filtering for the overall grid
    +     * @example
    +     * <pre>
    +     *   gridOptions.columnDefs[0].enableFiltering = false;
    +     *
    +     */
    +    // Turn on filtering by default (it's disabled by default at the Grid level)
    +    self.enableFiltering = typeof(colDef.enableFiltering) !== 'undefined' ? colDef.enableFiltering : true;
    +
    +    // self.menuItems = colDef.menuItems;
    +    self.setPropertyOrDefault(colDef, 'menuItems', []);
    +
    +    // Use the column definition sort if we were passed it, but only if this is a newly added column
    +    if ( isNew ){
    +      self.setPropertyOrDefault(colDef, 'sort');
    +    }
    +
    +    // Set up default filters array for when one is not provided.
    +    //   In other words, this (in column def):
    +    //   
    +    //       filter: { term: 'something', flags: {}, condition: [CONDITION] }
    +    //       
    +    //   is just shorthand for this:
    +    //   
    +    //       filters: [{ term: 'something', flags: {}, condition: [CONDITION] }]
    +    //       
    +    var defaultFilters = [];
    +    if (colDef.filter) {
    +      defaultFilters.push(colDef.filter);
    +    }
    +    else if (self.enableFiltering && self.grid.options.enableFiltering) {
    +      // Add an empty filter definition object, which will
    +      // translate to a guessed condition and no pre-populated
    +      // value for the filter <input>.
    +      defaultFilters.push({});
    +    }
    +
    +    /** 
    +     * @ngdoc property
    +     * @name filter
    +     * @propertyOf ui.grid.class:GridOptions.columnDef
    +     * @description Specify a single filter field on this column.
    +     * 
    +     * A filter consists of a condition, a term, and a placeholder:
    +     * 
    +     * - condition defines how rows are chosen as matching the filter term. This can be set to
    +     * one of the constants in uiGridConstants.filter, or you can supply a custom filter function
    +     * that gets passed the following arguments: [searchTerm, cellValue, row, column].
    +     * - term: If set, the filter field will be pre-populated
    +     * with this value.
    +     * - placeholder: String that will be set to the `<input>.placeholder` attribute.
    +     * - noTerm: set this to true if you have defined a custom function in condition, and
    +     * your custom function doesn't require a term (so it can run even when the term is null)
    +     * - flags: only flag currently available is `caseSensitive`, set to false if you don't want
    +     * case sensitive matching
    +     * @example
    +     * <pre>$scope.gridOptions.columnDefs = [ 
    +     *   {
    +     *     field: 'field1',
    +     *     filter: {
    +     *       term: 'xx',
    +     *       condition: uiGridConstants.filter.STARTS_WITH,
    +     *       placeholder: 'starts with...',
    +     *       flags: { caseSensitive: false }
    +     *     }
    +     *   }
    +     * ]; </pre>
    +     *
    +     */
    +  
    +    /*
    +
    +      self.filters = [
    +        {
    +          term: 'search term'
    +          condition: uiGridConstants.filter.CONTAINS,
    +          placeholder: 'my placeholder',
    +          flags: {
    +            caseSensitive: true
    +          }
    +        }
    +      ]
    +
    +    */
    +
    +    // Only set filter if this is a newly added column, if we're updating an existing
    +    // column then we don't want to put the default filter back if the user may have already
    +    // removed it.
    +    if ( isNew ) {
    +      self.setPropertyOrDefault(colDef, 'filter');
    +      self.setPropertyOrDefault(colDef, 'filters', defaultFilters);
    +    }
    +
    +    // Remove this column from the grid sorting, include inside build columns so has
    +    // access to self - all seems a bit dodgy but doesn't work otherwise so have left
    +    // as is
    +    GridColumn.prototype.unsort = function () {
    +      this.sort = {};
    +      self.grid.api.core.raise.sortChanged( self, self.grid.getColumnSorting() );
    +    };
    +  
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClass
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class name for the column
    +   * @param {bool} prefixDot  if true, will return .className instead of className
    +   */
    +  GridColumn.prototype.getColClass = function (prefixDot) {
    +    var cls = uiGridConstants.COL_CLASS_PREFIX + this.uid;
    +
    +    return prefixDot ? '.' + cls : cls;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getColClassDefinition
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the class definition for th column
    +   */
    +  GridColumn.prototype.getColClassDefinition = function () {
    +    return ' .grid' + this.grid.id + ' ' + this.getColClass(true) + ' { min-width: ' + this.drawnWidth + 'px; max-width: ' + this.drawnWidth + 'px; }';
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getRenderContainer
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Returns the render container object that this column belongs to.
    +   *
    +   * Columns will be default be in the `body` render container if they aren't allocated to one specifically.
    +   */
    +  GridColumn.prototype.getRenderContainer = function getRenderContainer() {
    +    var self = this;
    +
    +    var containerId = self.renderContainer;
    +
    +    if (containerId === null || containerId === '' || containerId === undefined) {
    +      containerId = 'body';
    +    }
    +
    +    return self.grid.renderContainers[containerId];
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name showColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Makes the column visible by setting colDef.visible = true
    +   */
    +  GridColumn.prototype.showColumn = function() {
    +      this.colDef.visible = true;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name hideColumn
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Hides the column by setting colDef.visible = false
    +   */
    +  GridColumn.prototype.hideColumn = function() {
    +      this.colDef.visible = false;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationValue
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description gets the aggregation value based on the aggregation type for this column
    +   */
    +  GridColumn.prototype.getAggregationValue = function () {
    +    var self = this;
    +    var result = 0;
    +    var visibleRows = self.grid.getVisibleRows();
    +
    +    var cellValues = function(){
    +      var values = [];
    +      angular.forEach(visibleRows, function (row) {
    +        var cellValue = self.grid.getCellValue(row, self);
    +        if (angular.isNumber(cellValue)) {
    +          values.push(cellValue);
    +        }
    +      });
    +      return values;
    +    };
    +
    +    if (angular.isFunction(self.aggregationType)) {
    +      return self.aggregationType(visibleRows, self);
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.count) {
    +      return self.grid.getVisibleRowCount();
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.sum) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.avg) {
    +      angular.forEach(cellValues(), function (value) {
    +        result += value;
    +      });
    +      result = result / cellValues().length;
    +      return result;
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.min) {
    +      return Math.min.apply(null, cellValues());
    +    }
    +    else if (self.aggregationType === uiGridConstants.aggregationTypes.max) {
    +      return Math.max.apply(null, cellValues());
    +    }
    +    else {
    +      return '\u00A0';
    +    }
    +  };
    +    
    +  /** 
    +   * @ngdoc property
    +   * @name aggregationHideLabel
    +   * @propertyOf ui.grid.class:GridOptions.columnDef
    +   * @description defaults to false, if set to true hides the label text
    +   * in the aggregation footer, so only the value is displayed.
    +   *
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name getAggregationText
    +   * @methodOf ui.grid.class:GridColumn
    +   * @description Gets the aggregation label from colDef.aggregationLabel if
    +   * specified or by using i18n, including deciding whether or not to display
    +   * based on colDef.aggregationHideLabel.
    +   *
    +   * @param {string} label the i18n lookup value to use for the column label
    +   * 
    +   */
    +  GridColumn.prototype.getAggregationText = function () {
    +    var self = this;
    +    if ( self.colDef.aggregationHideLabel ){
    +      return '';
    +    }
    +    else if ( self.colDef.aggregationLabel ) {
    +      return self.colDef.aggregationLabel;
    +    }
    +    else {
    +      switch ( self.colDef.aggregationType ){
    +        case uiGridConstants.aggregationTypes.count:
    +          return i18nService.getSafeText('aggregation.count');
    +        case uiGridConstants.aggregationTypes.sum:
    +          return i18nService.getSafeText('aggregation.sum');
    +        case uiGridConstants.aggregationTypes.avg:
    +          return i18nService.getSafeText('aggregation.avg');
    +        case uiGridConstants.aggregationTypes.min:
    +          return i18nService.getSafeText('aggregation.min');
    +        case uiGridConstants.aggregationTypes.max:
    +          return i18nService.getSafeText('aggregation.max');
    +        default:
    +          return '';
    +      }
    +    }
    +  };
    +
    +  GridColumn.prototype.getCellTemplate = function () {
    +    var self = this;
    +
    +    return self.cellTemplatePromise;
    +  };
    +
    +  GridColumn.prototype.getCompiledElementFn = function () {
    +    var self = this;
    +
    +    return self.compiledElementFnDefer.promise;
    +  };
    +
    +  return GridColumn;
    +}]);
    +
    +})();
    +
    +  (function(){
    +
    +angular.module('ui.grid')
    +.factory('GridOptions', ['gridUtil','uiGridConstants', function(gridUtil,uiGridConstants) {
    +
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridOptions
    +   * @description Default GridOptions class.  GridOptions are defined by the application developer and overlaid
    +   * over this object.  Setting gridOptions within your controller is the most common method for an application 
    +   * developer to configure the behaviour of their ui-grid
    +   * 
    +   * @example To define your gridOptions within your controller:
    +   * <pre>$scope.gridOptions = {
    +   *   data: $scope.myData,
    +   *   columnDefs: [ 
    +   *     { name: 'field1', displayName: 'pretty display name' },
    +   *     { name: 'field2', visible: false }
    +   *  ]
    +   * };</pre>
    +   * 
    +   * You can then use this within your html template, when you define your grid:
    +   * <pre>&lt;div ui-grid="gridOptions"&gt;&lt;/div&gt;</pre>
    +   *
    +   * To provide default options for all of the grids within your application, use an angular
    +   * decorator to modify the GridOptions factory.
    +   * <pre>
    +   * app.config(function($provide){
    +   *   $provide.decorator('GridOptions',function($delegate){
    +   *     var gridOptions;
    +   *     gridOptions = angular.copy($delegate);
    +   *     gridOptions.initialize = function(options) {
    +   *       var initOptions;
    +   *       initOptions = $delegate.initialize(options);
    +   *       initOptions.enableColumnMenus = false;
    +   *       return initOptions;
    +   *     };
    +   *     return gridOptions;
    +   *   });
    +   * });
    +   * </pre>
    +   */
    +  return {
    +    initialize: function( baseOptions ){
    +      /**
    +       * @ngdoc function
    +       * @name onRegisterApi
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description A callback that returns the gridApi once the grid is instantiated, which is 
    +       * then used to interact with the grid programatically.
    +       * 
    +       * Note that the gridApi.core.renderingComplete event is identical to this 
    +       * callback, but has the advantage that it can be called from multiple places
    +       * if needed
    +       * 
    +       * @example
    +       * <pre>
    +       *   $scope.gridOptions.onRegisterApi = function ( gridApi ) {
    +       *     $scope.gridApi = gridApi;
    +       *     $scope.gridApi.selection.selectAllRows( $scope.gridApi.grid );
    +       *   };
    +       * </pre>
    +       * 
    +       */
    +      baseOptions.onRegisterApi = baseOptions.onRegisterApi || angular.noop();
    +  
    +      /**
    +       * @ngdoc object
    +       * @name data
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (mandatory) Array of data to be rendered into the grid, providing the data source or data binding for 
    +       * the grid.  The most common case is an array of objects, where each object has a number of attributes.
    +       * Each attribute automatically becomes a column in your grid.  This array could, for example, be sourced from
    +       * an angularJS $resource query request.  The array can also contain complex objects.
    +       * 
    +       */
    +      baseOptions.data = baseOptions.data || [];
    +  
    +      /**
    +       * @ngdoc array
    +       * @name columnDefs
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of columnDef objects.  Only required property is name.
    +       * The individual options available in columnDefs are documented in the
    +       * {@link ui.grid.class:GridOptions.columnDef columnDef} section
    +       * </br>_field property can be used in place of name for backwards compatibility with 2.x_
    +       *  @example
    +       *
    +       * <pre>var columnDefs = [{name:'field1'}, {name:'field2'}];</pre>
    +       *
    +       */
    +      baseOptions.columnDefs = baseOptions.columnDefs || [];
    +  
    +      /**
    +       * @ngdoc object
    +       * @name ui.grid.class:GridOptions.columnDef
    +       * @description Definition / configuration of an individual column, which would typically be
    +       * one of many column definitions within the gridOptions.columnDefs array
    +       * @example
    +       * <pre>{name:'field1', field: 'field1', filter: { term: 'xxx' }}</pre>
    +       *
    +       */
    +  
    +          
    +      /**
    +       * @ngdoc array
    +       * @name excludeProperties
    +       * @propertyOf  ui.grid.class:GridOptions
    +       * @description Array of property names in data to ignore when auto-generating column names.  Provides the
    +       * inverse of columnDefs - columnDefs is a list of columns to include, excludeProperties is a list of columns
    +       * to exclude. 
    +       * 
    +       * If columnDefs is defined, this will be ignored.
    +       * 
    +       * Defaults to ['$$hashKey']
    +       */
    +      
    +      baseOptions.excludeProperties = baseOptions.excludeProperties || ['$$hashKey'];
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableRowHashing
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting allows uiGrid to add
    +       * `$$hashKey`-type properties (similar to Angular) to elements in the `data` array. This allows
    +       * the grid to maintain state while vastly speeding up the process of altering `data` by adding/moving/removing rows.
    +       * 
    +       * Note that this DOES add properties to your data that you may not want, but they are stripped out when using `angular.toJson()`. IF
    +       * you do not want this at all you can disable this setting but you will take a performance hit if you are using large numbers of rows
    +       * and are altering the data set often.
    +       */
    +      baseOptions.enableRowHashing = baseOptions.enableRowHashing !== false;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function is used to get and, if necessary, set the value uniquely identifying this row (i.e. if an identity is not present it will set one).
    +       * 
    +       * By default it returns the `$$hashKey` property if it exists. If it doesn't it uses gridUtil.nextUid() to generate one
    +       */
    +      baseOptions.rowIdentity = baseOptions.rowIdentity || function rowIdentity(row) {
    +        return gridUtil.hashKey(row);
    +      };
    +  
    +      /**
    +       * @ngdoc function
    +       * @name getRowIdentity
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description This function returns the identity value uniquely identifying this row, if one is not present it does not set it.
    +       * 
    +       * By default it returns the `$$hashKey` property but can be overridden to use any property or set of properties you want.
    +       */
    +      baseOptions.getRowIdentity = baseOptions.getRowIdentity || function getRowIdentity(row) {
    +        return row.$$hashKey;
    +      };
    +
    +      /**
    +       * @ngdoc property
    +       * @name showHeader
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When set to false, this setting will replace the
    +       * standard header template with '<div></div>', resulting in no header being shown.
    +       *
    +       * It will also set the `headerRowHeight` option to 0.
    +       */
    +      baseOptions.showHeader = typeof(baseOptions.showHeader) !== "undefined" ? baseOptions.showHeader : true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name headerRowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the header in pixels, defaults to 30
    +       *
    +       */
    +      if (!baseOptions.showHeader) {
    +        baseOptions.headerRowHeight = 0;
    +      }
    +      else {
    +        baseOptions.headerRowHeight = typeof(baseOptions.headerRowHeight) !== "undefined" ? baseOptions.headerRowHeight : 30;
    +      }
    +
    +      /**
    +       * @ngdoc property
    +       * @name rowHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the row in pixels, defaults to 30
    +       *
    +       */
    +      baseOptions.rowHeight = baseOptions.rowHeight || 30;
    +  
    +      /**
    +       * @ngdoc integer
    +       * @name minRowsToShow
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Minimum number of rows to show when the grid doesn't have a defined height. Defaults to "10".
    +       */
    +      baseOptions.minRowsToShow = typeof(baseOptions.minRowsToShow) !== "undefined" ? baseOptions.minRowsToShow : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name showGridFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the footer, defaults to false
    +       * The footer display Total Rows and Visible Rows (filtered rows)
    +       */
    +      baseOptions.showGridFooter = baseOptions.showGridFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name showColumnFooter
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Whether or not to show the column footer, defaults to false
    +       * The column footer displays column aggregates
    +       */
    +      baseOptions.showColumnFooter = baseOptions.showColumnFooter === true;
    +
    +      /**
    +       * @ngdoc property
    +       * @name columnFooterHeight
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description The height of the footer rows (column footer and grid footer) in pixels
    +       *
    +       */
    +      baseOptions.columnFooterHeight = typeof(baseOptions.columnFooterHeight) !== "undefined" ? baseOptions.columnFooterHeight : 30;
    +      baseOptions.gridFooterHeight = typeof(baseOptions.gridFooterHeight) !== "undefined" ? baseOptions.gridFooterHeight : 30;
    +
    +      baseOptions.columnWidth = typeof(baseOptions.columnWidth) !== "undefined" ? baseOptions.columnWidth : 50;
    +
    +      /**
    +       * @ngdoc property
    +       * @name maxVisibleColumnCount
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 200
    +       *
    +       */
    +      baseOptions.maxVisibleColumnCount = typeof(baseOptions.maxVisibleColumnCount) !== "undefined" ? baseOptions.maxVisibleColumnCount : 200;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name virtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of data elements goes over this number, defaults to 20
    +       */
    +      baseOptions.virtualizationThreshold = typeof(baseOptions.virtualizationThreshold) !== "undefined" ? baseOptions.virtualizationThreshold : 20;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name columnVirtualizationThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Turn virtualization on when number of columns goes over this number, defaults to 10
    +       */
    +      baseOptions.columnVirtualizationThreshold = typeof(baseOptions.columnVirtualizationThreshold) !== "undefined" ? baseOptions.columnVirtualizationThreshold : 10;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessRows
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra rows to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessRows = typeof(baseOptions.excessRows) !== "undefined" ? baseOptions.excessRows : 4;
    +      /**
    +       * @ngdoc property
    +       * @name scrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.scrollThreshold = typeof(baseOptions.scrollThreshold) !== "undefined" ? baseOptions.scrollThreshold : 4;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name excessColumns
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Extra columns to to render outside of the viewport, which helps with smoothness of scrolling.
    +       * Defaults to 4
    +       */
    +      baseOptions.excessColumns = typeof(baseOptions.excessColumns) !== "undefined" ? baseOptions.excessColumns : 4;
    +      /**
    +       * @ngdoc property
    +       * @name horizontalScrollThreshold
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Defaults to 4
    +       */
    +      baseOptions.horizontalScrollThreshold = typeof(baseOptions.horizontalScrollThreshold) !== "undefined" ? baseOptions.horizontalScrollThreshold : 2;
    +  
    +      /**
    +       * @ngdoc property
    +       * @name scrollThrottle
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Default time to throttle scroll events to, defaults to 70ms
    +       */
    +      baseOptions.scrollThrottle = typeof(baseOptions.scrollThrottle) !== "undefined" ? baseOptions.scrollThrottle : 70;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableSorting
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting adds sort
    +       * widgets to the column headers, allowing sorting of the data for the entire grid.
    +       * Sorting can then be disabled on individual columns using the columnDefs.
    +       */
    +      baseOptions.enableSorting = baseOptions.enableSorting !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableFiltering
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description False by default. When enabled, this setting adds filter 
    +       * boxes to each column header, allowing filtering within the column for the entire grid.
    +       * Filtering can then be disabled on individual columns using the columnDefs. 
    +       */
    +      baseOptions.enableFiltering = baseOptions.enableFiltering === true;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableColumnMenus
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description True by default. When enabled, this setting displays a column
    +       * menu within each column.
    +       */
    +      baseOptions.enableColumnMenus = baseOptions.enableColumnMenus !== false;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name enableVerticalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the vertical scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableVerticalScrollbar = typeof(baseOptions.enableVerticalScrollbar) !== "undefined" ? baseOptions.enableVerticalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +      
    +      /**
    +       * @ngdoc boolean
    +       * @name enableHorizontalScrollbar
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description uiGridConstants.scrollbars.ALWAYS by default. This settings controls the horizontal scrollbar for the grid.
    +       * Supported values: uiGridConstants.scrollbars.ALWAYS, uiGridConstants.scrollbars.NEVER
    +       */
    +      baseOptions.enableHorizontalScrollbar = typeof(baseOptions.enableHorizontalScrollbar) !== "undefined" ? baseOptions.enableHorizontalScrollbar : uiGridConstants.scrollbars.ALWAYS;
    +  
    +      /**
    +       * @ngdoc boolean
    +       * @name minimumColumnSize
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Columns can't be smaller than this, defaults to 10 pixels
    +       */
    +      baseOptions.minimumColumnSize = typeof(baseOptions.minimumColumnSize) !== "undefined" ? baseOptions.minimumColumnSize : 10;
    +  
    +      /**
    +       * @ngdoc function
    +       * @name rowEquality
    +       * @methodOf ui.grid.class:GridOptions
    +       * @description By default, rows are compared using object equality.  This option can be overridden
    +       * to compare on any data item property or function
    +       * @param {object} entityA First Data Item to compare
    +       * @param {object} entityB Second Data Item to compare
    +       */
    +      baseOptions.rowEquality = baseOptions.rowEquality || function(entityA, entityB) {
    +        return entityA === entityB;
    +      };
    +  
    +      /**
    +       * @ngdoc string
    +       * @name headerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description Null by default. When provided, this setting uses a custom header
    +       * template, rather than the default template. Can be set to either the name of a template file:
    +       * <pre>  $scope.gridOptions.headerTemplate = 'header_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div class="ui-grid-top-panel" style="text-align: center">I am a Custom Grid Header</div>'</pre>
    +       * or the id of a precompiled template (TBD how to use this).  
    +       * </br>Refer to the custom header tutorial for more information.
    +       * If you want no header at all, you can set to an empty div:
    +       * <pre>  $scope.gridOptions.headerTemplate = '<div></div>';</pre>
    +       * 
    +       * If you want to only have a static header, then you can set to static content.  If
    +       * you want to tailor the existing column headers, then you should look at the
    +       * current 'ui-grid-header.html' template in github as your starting point.
    +       * 
    +       */
    +      baseOptions.headerTemplate = baseOptions.headerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name footerTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description (optional) Null by default. When provided, this setting uses a custom footer
    +       * template. Can be set to either the name of a template file 'footer_template.html', inline html
    +       * <pre>'<div class="ui-grid-bottom-panel" style="text-align: center">I am a Custom Grid Footer</div>'</pre>, or the id
    +       * of a precompiled template (TBD how to use this).  Refer to the custom footer tutorial for more information.
    +       */
    +      baseOptions.footerTemplate = baseOptions.footerTemplate || null;
    +  
    +      /**
    +       * @ngdoc string
    +       * @name rowTemplate
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description 'ui-grid/ui-grid-row' by default. When provided, this setting uses a 
    +       * custom row template.  Can be set to either the name of a template file:
    +       * <pre> $scope.gridOptions.rowTemplate = 'row_template.html';</pre>
    +       * inline html 
    +       * <pre>  $scope.gridOptions.rowTemplate = '<div style="background-color: aquamarine" ng-click="grid.appScope.fnOne(row)" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ui-grid-cell></div>';</pre>
    +       * or the id of a precompiled template (TBD how to use this) can be provided.  
    +       * </br>Refer to the custom row template tutorial for more information.
    +       */
    +      baseOptions.rowTemplate = baseOptions.rowTemplate || 'ui-grid/ui-grid-row';
    +
    +      /**
    +       * @ngdoc object
    +       * @name appScopeProvider
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description by default, the parent scope of the ui-grid element will be assigned to grid.appScope
    +       * this property allows you to assign any reference you want to grid.appScope
    +       */
    +      baseOptions.appScopeProvider = baseOptions.appScopeProvider || null;
    +      
    +      return baseOptions;
    +    }     
    +  };
    +
    +
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +  
    +  /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRenderContainer
    +   * @description The grid has render containers, allowing the ability to have pinned columns.  If the grid
    +   * is right-to-left then there may be a right render container, if left-to-right then there may 
    +   * be a left render container.  There is always a body render container.
    +   * @param {string} name The name of the render container ('body', 'left', or 'right')
    +   * @param {Grid} grid the grid the render container is in
    +   * @param {object} options the render container options
    +   */
    +.factory('GridRenderContainer', ['gridUtil', 'uiGridConstants', function(gridUtil, uiGridConstants) {
    +  function GridRenderContainer(name, grid, options) {
    +    var self = this;
    +
    +    // if (gridUtil.type(grid) !== 'Grid') {
    +    //   throw new Error('Grid argument is not a Grid object');
    +    // }
    +
    +    self.name = name;
    +
    +    self.grid = grid;
    +    
    +    // self.rowCache = [];
    +    // self.columnCache = [];
    +
    +    self.visibleRowCache = [];
    +    self.visibleColumnCache = [];
    +
    +    self.renderedRows = [];
    +    self.renderedColumns = [];
    +
    +    self.prevScrollTop = 0;
    +    self.prevScrolltopPercentage = 0;
    +    self.prevRowScrollIndex = 0;
    +
    +    self.prevScrollLeft = 0;
    +    self.prevScrollleftPercentage = 0;
    +    self.prevColumnScrollIndex = 0;
    +
    +    self.columnStyles = "";
    +
    +    self.viewportAdjusters = [];
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeightShouldUpdate
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description flag to signal that container should recalculate the canvas size
    +     */
    +    self.canvasHeightShouldUpdate = true;
    +
    +    /**
    +     *  @ngdoc boolean
    +     *  @name canvasHeight
    +     *  @propertyOf  ui.grid.class:GridRenderContainer
    +     *  @description last calculated canvas height value
    +     */
    +    self.$$canvasHeight = 0;
    +
    +    if (options && angular.isObject(options)) {
    +      angular.extend(self, options);
    +    }
    +
    +    grid.registerStyleComputation({
    +      priority: 5,
    +      func: function () {
    +        return self.columnStyles;
    +      }
    +    });
    +  }
    +
    +  // GridRenderContainer.prototype.addRenderable = function addRenderable(renderable) {
    +  //   this.renderables.push(renderable);
    +  // };
    +
    +  GridRenderContainer.prototype.reset = function reset() {
    +    // this.rowCache.length = 0;
    +    // this.columnCache.length = 0;
    +
    +    this.visibleColumnCache.length = 0;
    +    this.visibleRowCache.length = 0;
    +
    +    this.renderedRows.length = 0;
    +    this.renderedColumns.length = 0;
    +  };
    +
    +  // TODO(c0bra): calculate size?? Should this be in a stackable directive?
    +
    +  GridRenderContainer.prototype.minRowsToRender = function minRowsToRender() {
    +    var self = this;
    +    var minRows = 0;
    +    var rowAddedHeight = 0;
    +    var viewPortHeight = self.getViewportHeight();
    +    for (var i = self.visibleRowCache.length - 1; rowAddedHeight < viewPortHeight && i >= 0; i--) {
    +      rowAddedHeight += self.visibleRowCache[i].height;
    +      minRows++;
    +    }
    +    return minRows;
    +  };
    +
    +  GridRenderContainer.prototype.minColumnsToRender = function minColumnsToRender() {
    +    var self = this;
    +    var viewportWidth = this.getViewportWidth();
    +
    +    var min = 0;
    +    var totalWidth = 0;
    +    // self.columns.forEach(function(col, i) {
    +    for (var i = 0; i < self.visibleColumnCache.length; i++) {
    +      var col = self.visibleColumnCache[i];
    +
    +      if (totalWidth < viewportWidth) {
    +        totalWidth += col.drawnWidth ? col.drawnWidth : 0;
    +        min++;
    +      }
    +      else {
    +        var currWidth = 0;
    +        for (var j = i; j >= i - min; j--) {
    +          currWidth += self.visibleColumnCache[j].drawnWidth ? self.visibleColumnCache[j].drawnWidth : 0;
    +        }
    +        if (currWidth < viewportWidth) {
    +          min++;
    +        }
    +      }
    +    }
    +
    +    return min;
    +  };
    +
    +  GridRenderContainer.prototype.getVisibleRowCount = function getVisibleRowCount() {
    +    return this.visibleRowCache.length;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name registerViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Registers an adjuster to the render container's available width or height.  Adjusters are used
    +   * to tell the render container that there is something else consuming space, and to adjust it's size
    +   * appropriately.  
    +   * @param {function} func the adjuster function we want to register
    +   */
    +
    +  GridRenderContainer.prototype.registerViewportAdjuster = function registerViewportAdjuster(func) {
    +    this.viewportAdjusters.push(func);
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name removeViewportAdjuster
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Removes an adjuster, should be used when your element is destroyed
    +   * @param {function} func the adjuster function we want to remove
    +   */
    +  GridRenderContainer.prototype.removeViewportAdjuster = function registerViewportAdjuster(func) {
    +    var idx = this.viewportAdjusters.indexOf(func);
    +
    +    if (typeof(idx) !== 'undefined' && idx !== undefined) {
    +      this.viewportAdjusters.splice(idx, 1);
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name getViewportAdjustment
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Gets the adjustment based on the viewportAdjusters.  
    +   * @returns {object} a hash of { height: x, width: y }.  Usually the values will be negative
    +   */
    +  GridRenderContainer.prototype.getViewportAdjustment = function getViewportAdjustment() {
    +    var self = this;
    +
    +    var adjustment = { height: 0, width: 0 };
    +
    +    self.viewportAdjusters.forEach(function (func) {
    +      adjustment = func.call(this, adjustment);
    +    });
    +
    +    return adjustment;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportHeight = function getViewportHeight() {
    +    var self = this;
    +
    +    var headerHeight = (self.headerHeight) ? self.headerHeight : self.grid.headerHeight;
    +
    +    var viewPortHeight = self.grid.gridHeight - headerHeight - self.grid.footerHeight;
    +
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortHeight = viewPortHeight + adjustment.height;
    +
    +    return viewPortHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getViewportWidth = function getViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = self.grid.gridWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth - self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    var adjustment = self.getViewportAdjustment();
    +    
    +    viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +  GridRenderContainer.prototype.getHeaderViewportWidth = function getHeaderViewportWidth() {
    +    var self = this;
    +
    +    var viewPortWidth = this.getViewportWidth();
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  viewPortWidth = viewPortWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // var adjustment = self.getViewportAdjustment();
    +    // viewPortWidth = viewPortWidth + adjustment.width;
    +
    +    return viewPortWidth;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name getCanvasHeight
    +   * @methodOf ui.grid.class:GridRenderContainer
    +   * @description Returns the total canvas height.   Only recalculates if canvasHeightShouldUpdate = false
    +   * @returns {number} total height of all the visible rows in the container
    +   */
    +  GridRenderContainer.prototype.getCanvasHeight = function getCanvasHeight() {
    +    var self = this;
    +
    +    if (!self.canvasHeightShouldUpdate) {
    +      return self.$$canvasHeight;
    +    }
    +
    +    var oldCanvasHeight = self.$$canvasHeight;
    +
    +    self.$$canvasHeight =  0;
    +
    +    self.visibleRowCache.forEach(function(row){
    +      self.$$canvasHeight += row.height;
    +    });
    +
    +
    +    self.canvasHeightShouldUpdate = false;
    +
    +    self.grid.api.core.raise.canvasHeightChanged(oldCanvasHeight, self.$$canvasHeight);
    +
    +    return self.$$canvasHeight;
    +  };
    +
    +  GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() {
    +    return this.getCanvasHeight() - this.getViewportHeight();
    +  };
    +
    +  GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() {
    +    var self = this;
    +
    +    var ret = self.canvasWidth;
    +
    +    //if (typeof(self.verticalScrollbarWidth) !== 'undefined' && self.verticalScrollbarWidth !== undefined && self.verticalScrollbarWidth > 0) {
    +    //  ret = ret - self.verticalScrollbarWidth;
    +    //}
    +
    +    return ret;
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedRows = function setRenderedRows(newRows) {
    +    this.renderedRows.length = newRows.length;
    +    for (var i = 0; i < newRows.length; i++) {
    +      this.renderedRows[i] = newRows[i];
    +    }
    +  };
    +
    +  GridRenderContainer.prototype.setRenderedColumns = function setRenderedColumns(newColumns) {
    +    var self = this;
    +
    +    // OLD:
    +    this.renderedColumns.length = newColumns.length;
    +    for (var i = 0; i < newColumns.length; i++) {
    +      this.renderedColumns[i] = newColumns[i];
    +    }
    +    
    +    this.updateColumnOffset();
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnOffset = function updateColumnOffset() {
    +    // Calculate the width of the columns on the left side that are no longer rendered.
    +    //  That will be the offset for the columns as we scroll horizontally.
    +    var hiddenColumnsWidth = 0;
    +    for (var i = 0; i < this.currentFirstColumn; i++) {
    +      hiddenColumnsWidth += this.visibleColumnCache[i].drawnWidth;
    +    }
    +
    +    this.columnOffset = hiddenColumnsWidth;
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollVertical = function adjustScrollVertical(scrollTop, scrollPercentage, force) {
    +    if (this.prevScrollTop === scrollTop && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollTop) === 'undefined' || scrollTop === undefined || scrollTop === null) {
    +      scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustRows(scrollTop, scrollPercentage, false);
    +
    +    this.prevScrollTop = scrollTop;
    +    this.prevScrolltopPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustScrollHorizontal = function adjustScrollHorizontal(scrollLeft, scrollPercentage, force) {
    +    if (this.prevScrollLeft === scrollLeft && !force) {
    +      return;
    +    }
    +
    +    if (typeof(scrollLeft) === 'undefined' || scrollLeft === undefined || scrollLeft === null) {
    +      scrollLeft = (this.getCanvasWidth() - this.getViewportWidth()) * scrollPercentage;
    +    }
    +
    +    this.adjustColumns(scrollLeft, scrollPercentage);
    +
    +    this.prevScrollLeft = scrollLeft;
    +    this.prevScrollleftPercentage = scrollPercentage;
    +
    +    this.grid.queueRefresh();
    +  };
    +
    +  GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage, postDataLoaded) {
    +    var self = this;
    +
    +    var minRows = self.minRowsToRender();
    +
    +    var rowCache = self.visibleRowCache;
    +
    +    var maxRowIndex = rowCache.length - minRows;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollTop) {
    +      scrollPercentage = scrollTop / self.getVerticalScrollLength();
    +    }
    +    
    +    var rowIndex = Math.ceil(Math.min(maxRowIndex, maxRowIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (rowIndex > maxRowIndex) {
    +      rowIndex = maxRowIndex;
    +    }
    +
    +    var newRange = [];
    +    if (rowCache.length > self.grid.options.virtualizationThreshold) {
    +      if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
    +        // Have we hit the threshold going down?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +        //Have we hit the threshold going up?
    +        if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
    +          return;
    +        }
    +      }
    +      var rangeStart = {};
    +      var rangeEnd = {};
    +
    +      //If infinite scroll is enabled, and we loaded more data coming from redrawInPlace, then recalculate the range and set rowIndex to proper place to scroll to
    +      if ( self.grid.options.enableInfiniteScroll && self.grid.scrollDirection !== uiGridConstants.scrollDirection.NONE && postDataLoaded ) {
    +        var findIndex = null;
    +        var i = null;
    +        if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.UP ) {
    +          findIndex = rowIndex > 0 ? self.grid.options.excessRows : 0;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex);
    +          rangeEnd = Math.min(rowCache.length, rangeStart + self.grid.options.excessRows + minRows);
    +        }
    +        else if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.DOWN ) {
    +          findIndex = minRows;
    +          for ( i = 0; i < rowCache.length; i++) {
    +            if (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
    +              rowIndex = i;
    +              break;
    +            }
    +          }
    +          rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows - minRows);
    +          rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +        }
    +      }
    +      else {
    +        rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
    +        rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
    +      }
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleRowCache.length;
    +      newRange = [0, Math.max(maxLen, minRows + self.grid.options.excessRows)];
    +    }
    +
    +    self.updateViewableRowRange(newRange);
    +
    +    self.prevRowScrollIndex = rowIndex;
    +  };
    +
    +  GridRenderContainer.prototype.adjustColumns = function adjustColumns(scrollLeft, scrollPercentage) {
    +    var self = this;
    +
    +    var minCols = self.minColumnsToRender();
    +
    +    var columnCache = self.visibleColumnCache;
    +    var maxColumnIndex = columnCache.length - minCols;
    +
    +    // Calculate the scroll percentage according to the scrollTop location, if no percentage was provided
    +    if ((typeof(scrollPercentage) === 'undefined' || scrollPercentage === null) && scrollLeft) {
    +      scrollPercentage = scrollLeft / self.getCanvasWidth();
    +    }
    +
    +    var colIndex = Math.ceil(Math.min(maxColumnIndex, maxColumnIndex * scrollPercentage));
    +
    +    // Define a max row index that we can't scroll past
    +    if (colIndex > maxColumnIndex) {
    +      colIndex = maxColumnIndex;
    +    }
    +    
    +    var newRange = [];
    +    if (columnCache.length > self.grid.options.columnVirtualizationThreshold && self.getCanvasWidth() > self.getViewportWidth()) {
    +      /* Commented the following lines because otherwise the moved column wasn't visible immediately on the new position
    +       * in the case of many columns with horizontal scroll, one had to scroll left or right and then return in order to see it
    +      // Have we hit the threshold going down?
    +      if (self.prevScrollLeft < scrollLeft && colIndex < self.prevColumnScrollIndex + self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }
    +      //Have we hit the threshold going up?
    +      if (self.prevScrollLeft > scrollLeft && colIndex > self.prevColumnScrollIndex - self.grid.options.horizontalScrollThreshold && colIndex < maxColumnIndex) {
    +        return;
    +      }*/
    +
    +      var rangeStart = Math.max(0, colIndex - self.grid.options.excessColumns);
    +      var rangeEnd = Math.min(columnCache.length, colIndex + minCols + self.grid.options.excessColumns);
    +
    +      newRange = [rangeStart, rangeEnd];
    +    }
    +    else {
    +      var maxLen = self.visibleColumnCache.length;
    +
    +      newRange = [0, Math.max(maxLen, minCols + self.grid.options.excessColumns)];
    +    }
    +    
    +    self.updateViewableColumnRange(newRange);
    +
    +    self.prevColumnScrollIndex = colIndex;
    +  };
    +
    +  // Method for updating the visible rows
    +  GridRenderContainer.prototype.updateViewableRowRange = function updateViewableRowRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var rowArr = uiGridCtrl.grid.rows.slice(renderedRange[0], renderedRange[1]);
    +    var rowArr = this.visibleRowCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the top-most rendered row
    +    this.currentTopRow = renderedRange[0];
    +
    +    // TODO(c0bra): make this method!
    +    this.setRenderedRows(rowArr);
    +  };
    +
    +  // Method for updating the visible columns
    +  GridRenderContainer.prototype.updateViewableColumnRange = function updateViewableColumnRange(renderedRange) {
    +    // Slice out the range of rows from the data
    +    // var columnArr = uiGridCtrl.grid.columns.slice(renderedRange[0], renderedRange[1]);
    +    var columnArr = this.visibleColumnCache.slice(renderedRange[0], renderedRange[1]);
    +
    +    // Define the left-most rendered columns
    +    this.currentFirstColumn = renderedRange[0];
    +
    +    this.setRenderedColumns(columnArr);
    +  };
    +
    +  GridRenderContainer.prototype.headerCellWrapperStyle = function () {
    +    var self = this;
    +    
    +    if (self.currentFirstColumn !== 0) {
    +      var offset = self.columnOffset;
    +
    +      if (self.grid.isRTL()) {
    +        return { 'margin-right': offset + 'px' };
    +      }
    +      else {
    +        return { 'margin-left': offset + 'px' };
    +      }
    +    }
    +
    +    return null;
    +  };
    +
    +  GridRenderContainer.prototype.updateColumnWidths = function () {
    +    var self = this;
    +
    +    var asterisksArray = [],
    +        percentArray = [],
    +        manualArray = [],
    +        asteriskNum = 0,
    +        totalWidth = 0;
    +
    +    // Get the width of the viewport
    +    var availableWidth = self.getViewportWidth() - self.grid.scrollbarWidth;
    +
    +    //if (typeof(self.grid.verticalScrollbarWidth) !== 'undefined' && self.grid.verticalScrollbarWidth !== undefined && self.grid.verticalScrollbarWidth > 0) {
    +    //  availableWidth = availableWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +
    +    // The total number of columns
    +    // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
    +    // var equalWidth = availableWidth / equalWidthColumnCount;
    +
    +    // The last column we processed
    +    var lastColumn;
    +
    +    var manualWidthSum = 0;
    +
    +    var canvasWidth = 0;
    +
    +    var ret = '';
    +
    +
    +    // uiGridCtrl.grid.columns.forEach(function(column, i) {
    +
    +    var columnCache = self.visibleColumnCache;
    +
    +    columnCache.forEach(function(column, i) {
    +      // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
    +      //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;
    +
    +      // Skip hidden columns
    +      if (!column.visible) { return; }
    +
    +      var colWidth,
    +          isPercent = false;
    +
    +      if (!angular.isNumber(column.width)) {
    +        isPercent = isNaN(column.width) && gridUtil.endsWith(column.width, "%");
    +      }
    +
    +      if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
    +        asteriskNum = parseInt(asteriskNum + column.width.length, 10);
    +        
    +        asterisksArray.push(column);
    +      }
    +      else if (isPercent) { // If the width is a percentage, save it until the very last.
    +        percentArray.push(column);
    +      }
    +      else if (angular.isNumber(column.width)) {
    +        manualWidthSum = parseInt(manualWidthSum + column.width, 10);
    +        
    +        canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);
    +
    +        column.drawnWidth = column.width;
    +      }
    +    });
    +
    +    // Get the remaining width (available width subtracted by the manual widths sum)
    +    var remainingWidth = availableWidth - manualWidthSum;
    +
    +    var i, column, colWidth;
    +
    +    if (percentArray.length > 0) {
    +      // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < percentArray.length; i++) {
    +        column = percentArray[i];
    +
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +
    +        colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          percentArray.splice(i, 1);
    +        }
    +      }
    +
    +      percentArray.forEach(function(column) {
    +        var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
    +        var colWidth = parseInt(percent * remainingWidth, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    if (asterisksArray.length > 0) {
    +      var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +       // Pre-process to make sure they're all within any min/max values
    +      for (i = 0; i < asterisksArray.length; i++) {
    +        column = asterisksArray[i];
    +
    +        colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
    +          colWidth = column.colDef.minWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          lastColumn = column;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +        else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
    +          colWidth = column.colDef.maxWidth;
    +
    +          remainingWidth = remainingWidth - colWidth;
    +          asteriskNum--;
    +
    +          canvasWidth += colWidth;
    +          column.drawnWidth = colWidth;
    +
    +          // Remove this element from the percent array so it's not processed below
    +          asterisksArray.splice(i, 1);
    +        }
    +      }
    +
    +      // Redo the asterisk value, as we may have removed columns due to width constraints
    +      asteriskVal = parseInt(remainingWidth / asteriskNum, 10);
    +
    +      asterisksArray.forEach(function(column) {
    +        var colWidth = parseInt(asteriskVal * column.width.length, 10);
    +
    +        canvasWidth += colWidth;
    +
    +        column.drawnWidth = colWidth;
    +      });
    +    }
    +
    +    // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
    +    var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);
    +
    +    if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
    +      var variableColumn = false;
    +      // uiGridCtrl.grid.columns.forEach(function(col) {
    +      columnCache.forEach(function(col) {
    +        if (col.width && !angular.isNumber(col.width)) {
    +          variableColumn = true;
    +        }
    +      });
    +
    +      if (variableColumn) {
    +        var remFn = function (column) {
    +          if (leftoverWidth > 0) {
    +            column.drawnWidth = column.drawnWidth + 1;
    +            canvasWidth = canvasWidth + 1;
    +            leftoverWidth--;
    +          }
    +        };
    +        while (leftoverWidth > 0) {
    +          columnCache.forEach(remFn);
    +        }
    +      }
    +    }
    +
    +    if (canvasWidth < availableWidth) {
    +      canvasWidth = availableWidth;
    +    }
    +
    +    // Build the CSS
    +    columnCache.forEach(function (column) {
    +      ret = ret + column.getColClassDefinition();
    +    });
    +
    +    // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
    +    //if (self.grid.verticalScrollbarWidth) {
    +    //  canvasWidth = canvasWidth + self.grid.verticalScrollbarWidth;
    +    //}
    +    // canvasWidth = canvasWidth + 1;
    +
    +    self.canvasWidth = parseInt(canvasWidth, 10);
    +
    +    // Return the styles back to buildStyles which pops them into the `customStyles` scope variable
    +    // return ret;
    +
    +    // Set this render container's column styles so they can be used in style computation
    +    this.columnStyles = ret;
    +  };
    +
    +  GridRenderContainer.prototype.getViewPortStyle = function () {
    +    var self = this;
    +    var styles = {};
    +
    +    if (self.name === 'body') {
    +      styles['overflow-x'] = self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +      if (!self.grid.isRTL()) {
    +        if (self.grid.hasRightContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +      else {
    +        if (self.grid.hasLeftContainerColumns()) {
    +          styles['overflow-y'] = 'hidden';
    +        }
    +        else {
    +          styles['overflow-y'] = self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll';
    +        }
    +      }
    +    }
    +    else if (self.name === 'left') {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +    else {
    +      styles['overflow-x'] = 'hidden';
    +      styles['overflow-y'] = !self.grid.isRTL() ? (self.grid.options.enableVerticalScrollbar === uiGridConstants.scrollbars.NEVER ? 'hidden' : 'scroll') : 'hidden';
    +    }
    +
    +    return styles;
    +
    +
    +  };
    +
    +  return GridRenderContainer;
    +}]);
    +
    +})();
    +
    +(function(){
    +
    +angular.module('ui.grid')
    +.factory('GridRow', ['gridUtil', function(gridUtil) {
    +
    +   /**
    +   * @ngdoc function
    +   * @name ui.grid.class:GridRow
    +   * @description GridRow is the viewModel for one logical row on the grid.  A grid Row is not necessarily a one-to-one
    +   * relation to gridOptions.data.
    +   * @param {object} entity the array item from GridOptions.data
    +   * @param {number} index the current position of the row in the array
    +   * @param {Grid} reference to the parent grid
    +   */
    +  function GridRow(entity, index, grid) {
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name grid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference back to the grid
    +      */
    +     this.grid = grid;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name entity
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description A reference to an item in gridOptions.data[]
    +      */
    +    this.entity = entity;
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name uid
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description  UniqueId of row
    +      */
    +     this.uid = gridUtil.nextUid();
    +
    +     /**
    +      *  @ngdoc object
    +      *  @name visible
    +      *  @propertyOf  ui.grid.class:GridRow
    +      *  @description If true, the row will be rendered
    +      */
    +    // Default to true
    +    this.visible = true;
    +
    +
    +    this.$$height = grid.options.rowHeight;
    +
    +  }
    +
    +    /**
    +     *  @ngdoc object
    +     *  @name height
    +     *  @propertyOf  ui.grid.class:GridRow
    +     *  @description height of each individual row. changing the height will flag all
    +     *  row renderContainers to recalculate their canvas height
    +     */
    +    Object.defineProperty(GridRow.prototype, 'height', {
    +      get: function() {
    +        return this.$$height;
    +      },
    +      set: function(height) {
    +        if (height !== this.$$height) {
    +          this.grid.updateCanvasHeight();
    +          this.$$height = height;
    +        }
    +      }
    +    });
    +
    +  /**
    +   * @ngdoc function
    +   * @name getQualifiedColField
    +   * @methodOf ui.grid.class:GridRow
    +   * @description returns the qualified field name as it exists on scope
    +   * ie: row.entity.fieldA
    +   * @param {GridCol} col column instance
    +   * @returns {string} resulting name that can be evaluated on scope
    +   */
    +    GridRow.prototype.getQualifiedColField = function(col) {
    +      return 'row.' + this.getEntityQualifiedColField(col);
    +    };
    +
    +    /**
    +     * @ngdoc function
    +     * @name getEntityQualifiedColField
    +     * @methodOf ui.grid.class:GridRow
    +     * @description returns the qualified field name minus the row path
    +     * ie: entity.fieldA
    +     * @param {GridCol} col column instance
    +     * @returns {string} resulting name that can be evaluated against a row
    +     */
    +  GridRow.prototype.getEntityQualifiedColField = function(col) {
    +    return gridUtil.preEval('entity.' + col.field);
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setRowInvisible
    +   * @methodOf  ui.grid.class:GridRow
    +   * @description Sets an override on the row that forces it to always
    +   * be invisible, and if the row is currently visible then marks it
    +   * as invisible and refreshes the grid.  Emits the rowsVisibleChanged
    +   * event if it changed the row visibility
    +   * @param {GridRow} row row to force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.setRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = true;
    +      
    +      if ( row.visible ){
    +        row.visible = false;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name clearRowInvisible
    +   * @methodOf ui.grid.class:GridRow
    +   * @description Clears any override on the row visibility, returning it 
    +   * to normal visibility calculations.  If the row is currently invisible
    +   * then sets it to visible and calls refresh and emits the rowsVisibleChanged
    +   * event
    +   * TODO: if filter in action, then is this right?
    +   * @param {GridRow} row row clear force invisible, needs to be a GridRow,
    +   * which can be found from your data entity using grid.findRow
    +   */
    +  GridRow.prototype.clearRowInvisible = function (row) {
    +    if (row !== null) {
    +      row.forceInvisible = false;
    +      
    +      if ( !row.visible ){
    +        row.visible = true;
    +        row.grid.refresh();
    +        row.grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }        
    +  };
    +
    +  return GridRow;
    +}]);
    +
    +})();
    +(function () {
    +  angular.module('ui.grid')
    +    .factory('ScrollEvent', ['gridUtil', function (gridUtil) {
    +
    +      /**
    +       * @ngdoc function
    +       * @name ui.grid.class:ScrollEvent
    +       * @description Model for all scrollEvents
    +       * @param {Grid} grid that owns the scroll event
    +       * @param {GridRenderContainer} sourceRowContainer that owns the scroll event. Can be null
    +       * @param {GridRenderContainer} sourceColContainer that owns the scroll event. Can be null
    +       * @param {string} source the source of the event - from uiGridConstants.scrollEventSources or a string value of directive/service/factory.functionName
    +       */
    +      function ScrollEvent(grid, sourceRowContainer, sourceColContainer, source) {
    +        var self = this;
    +        if (!grid) {
    +          throw new Error("grid argument is required");
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name grid
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description A reference back to the grid
    +         */
    +         self.grid = grid;
    +
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name entity
    +         *  @propertyOf  ui.grid.class:ScrollEvent
    +         *  @description the source of the scroll event. limited to values from uiGridConstants.scrollEventSources
    +         */
    +        self.source = source;
    +
    +        self.sourceRowContainer = sourceRowContainer;
    +        self.sourceColContainer = sourceColContainer;
    +
    +        self.newScrollLeft = null;
    +        self.newScrollTop = null;
    +        self.x = null;
    +        self.y = null;
    +
    +
    +        /**
    +         *  @ngdoc function
    +         *  @name fireThrottledScrollingEvent
    +         *  @methodOf  ui.grid.class:ScrollEvent
    +         *  @description fires a throttled event using grid.api.core.raise.scrollEvent
    +         */
    +        self.fireThrottledScrollingEvent = gridUtil.throttle(function() {
    +          self.grid.api.core.raise.scrollEvent(self);
    +        }, self.grid.options.scrollThrottle, {trailing: true});
    +
    +      }
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name fireScrollingEvent
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description fires an event using grid.api.core.raise.scrollEvent
    +       */
    +      ScrollEvent.prototype.fireScrollingEvent = function() {
    +        this.grid.api.core.raise.scrollEvent(this);
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollLeft
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollLeft property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollLeft = function(colContainer, viewport){
    +        var self = this;
    +
    +        if (!self.newScrollLeft){
    +          var scrollWidth = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
    +
    +          var oldScrollLeft = gridUtil.normalizeScrollLeft(viewport);
    +
    +          var scrollXPercentage;
    +          if (typeof(self.x.percentage) !== 'undefined' && self.x.percentage !== undefined) {
    +            scrollXPercentage = self.x.percentage;
    +          }
    +          else if (typeof(self.x.pixels) !== 'undefined' && self.x.pixels !== undefined) {
    +            scrollXPercentage = self.x.percentage = (oldScrollLeft + self.x.pixels) / scrollWidth;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event X axis");
    +          }
    +
    +          return Math.max(0, scrollXPercentage * scrollWidth);
    +        }
    +
    +        return self.newScrollLeft;
    +      };
    +
    +
    +      /**
    +       *  @ngdoc function
    +       *  @name getNewScrollTop
    +       *  @methodOf  ui.grid.class:ScrollEvent
    +       *  @description returns newScrollTop property if available; calculates a new value if it isn't
    +       */
    +      ScrollEvent.prototype.getNewScrollTop = function(rowContainer, viewport){
    +        var self = this;
    +
    +
    +        if (!self.newScrollTop){
    +          var scrollLength = rowContainer.getVerticalScrollLength();
    +
    +          var oldScrollTop = viewport[0].scrollTop;
    +
    +          var scrollYPercentage;
    +          if (typeof(self.y.percentage) !== 'undefined' && self.y.percentage !== undefined) {
    +            scrollYPercentage = self.y.percentage;
    +          }
    +          else if (typeof(self.y.pixels) !== 'undefined' && self.y.pixels !== undefined) {
    +            scrollYPercentage = self.y.percentage = (oldScrollTop + self.y.pixels) / scrollLength;
    +          }
    +          else {
    +            throw new Error("No percentage or pixel value provided for scroll event Y axis");
    +          }
    +
    +          return Math.max(0, scrollYPercentage * scrollLength);
    +        }
    +
    +        return self.newScrollTop;
    +      };
    +
    +
    +      ScrollEvent.Sources = {
    +        ViewPortScroll: 'ViewPortScroll',
    +        RenderContainerMouseWheel: 'RenderContainerMouseWheel',
    +        RenderContainerTouchMove: 'RenderContainerTouchMove',
    +        Other: 99
    +      };
    +
    +      return ScrollEvent;
    +    }]);
    +
    +
    +
    +})();
    +(function () {
    +  'use strict';
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.service:gridClassFactory
    +   *
    +   *  @description factory to return dom specific instances of a grid
    +   *
    +   */
    +  angular.module('ui.grid').service('gridClassFactory', ['gridUtil', '$q', '$compile', '$templateCache', 'uiGridConstants', 'Grid', 'GridColumn', 'GridRow',
    +    function (gridUtil, $q, $compile, $templateCache, uiGridConstants, Grid, GridColumn, GridRow) {
    +
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name createGrid
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Creates a new grid instance. Each instance will have a unique id
    +         * @param {object} options An object map of options to pass into the created grid instance.
    +         * @returns {Grid} grid
    +         */
    +        createGrid : function(options) {
    +          options = (typeof(options) !== 'undefined') ? options : {};
    +          options.id = gridUtil.newId();
    +          var grid = new Grid(options);
    +
    +          // NOTE/TODO: rowTemplate should always be defined...
    +          if (grid.options.rowTemplate) {
    +            var rowTemplateFnPromise = $q.defer();
    +            grid.getRowTemplateFn = rowTemplateFnPromise.promise;
    +            
    +            gridUtil.getTemplate(grid.options.rowTemplate)
    +              .then(
    +                function (template) {
    +                  var rowTemplateFn = $compile(template);
    +                  rowTemplateFnPromise.resolve(rowTemplateFn);
    +                },
    +                function (res) {
    +                  // Todo handle response error here?
    +                  throw new Error("Couldn't fetch/use row template '" + grid.options.rowTemplate + "'");
    +                });
    +          }
    +
    +          grid.registerColumnBuilder(service.defaultColumnBuilder);
    +
    +          // Row builder for custom row templates
    +          grid.registerRowBuilder(service.rowTemplateAssigner);
    +
    +          // Reset all rows to visible initially
    +          grid.registerRowsProcessor(function allRowsVisible(rows) {
    +            rows.forEach(function (row) {
    +              row.visible = !row.forceInvisible;
    +            });
    +
    +            return rows;
    +          });
    +
    +          grid.registerColumnsProcessor(function allColumnsVisible(columns) {
    +            columns.forEach(function (column) {
    +              column.visible = true;
    +            });
    +
    +            return columns;
    +          });
    +
    +          grid.registerColumnsProcessor(function(renderableColumns) {
    +              renderableColumns.forEach(function (column) {
    +                  if (column.colDef.visible === false) {
    +                      column.visible = false;
    +                  }
    +              });
    +
    +              return renderableColumns;
    +          });
    +
    +
    +
    +          if (grid.options.enableFiltering) {
    +            grid.registerRowsProcessor(grid.searchRows);
    +          }
    +
    +          // Register the default row processor, it sorts rows by selected columns
    +          if (grid.options.externalSort && angular.isFunction(grid.options.externalSort)) {
    +            grid.registerRowsProcessor(grid.options.externalSort);
    +          }
    +          else {
    +            grid.registerRowsProcessor(grid.sortByColumn);
    +          }
    +
    +          return grid;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name defaultColumnBuilder
    +         * @methodOf ui.grid.service:gridClassFactory
    +         * @description Processes designTime column definitions and applies them to col for the
    +         *              core grid features
    +         * @param {object} colDef reference to column definition
    +         * @param {GridColumn} col reference to gridCol
    +         * @param {object} gridOptions reference to grid options
    +         */
    +        defaultColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var templateGetPromises = [];
    +
    +          /**
    +           * @ngdoc property
    +           * @name headerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the header for this column.  The default
    +           * is ui-grid/uiGridHeaderCell
    +           *
    +           */
    +          if (!colDef.headerCellTemplate) {
    +            col.providedHeaderCellTemplate = 'ui-grid/uiGridHeaderCell';
    +          } else {
    +            col.providedHeaderCellTemplate = colDef.headerCellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name cellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for each cell in this column.  The default
    +           * is ui-grid/uiGridCell.  If you are using the cellNav feature, this template
    +           * must contain a div that can receive focus.
    +           *
    +           */
    +          if (!colDef.cellTemplate) {
    +            col.providedCellTemplate = 'ui-grid/uiGridCell';
    +          } else {
    +            col.providedCellTemplate = colDef.cellTemplate;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name footerCellTemplate
    +           * @propertyOf ui.grid.class:GridOptions.columnDef
    +           * @description a custom template for the footer for this column.  The default
    +           * is ui-grid/uiGridFooterCell
    +           *
    +           */
    +          if (!colDef.footerCellTemplate) {
    +            col.providedFooterCellTemplate = 'ui-grid/uiGridFooterCell';
    +          } else {
    +            col.providedFooterCellTemplate = colDef.footerCellTemplate;
    +          }
    +
    +          col.cellTemplatePromise = gridUtil.getTemplate(col.providedCellTemplate);
    +          templateGetPromises.push(col.cellTemplatePromise
    +            .then(
    +              function (template) {
    +                col.cellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.cellFilter ? "|" + col.cellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.cellTemplate '" + colDef.cellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedHeaderCellTemplate)
    +              .then(
    +              function (template) {
    +                col.headerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.headerCellFilter ? "|" + col.headerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.headerCellTemplate '" + colDef.headerCellTemplate + "'");
    +              })
    +          );
    +
    +          templateGetPromises.push(gridUtil.getTemplate(col.providedFooterCellTemplate)
    +              .then(
    +              function (template) {
    +                col.footerCellTemplate = template.replace(uiGridConstants.CUSTOM_FILTERS, col.footerCellFilter ? "|" + col.footerCellFilter : "");
    +              },
    +              function (res) {
    +                throw new Error("Couldn't fetch/use colDef.footerCellTemplate '" + colDef.footerCellTemplate + "'");
    +              })
    +          );
    +
    +          // Create a promise for the compiled element function
    +          col.compiledElementFnDefer = $q.defer();
    +
    +          return $q.all(templateGetPromises);
    +        },
    +
    +        rowTemplateAssigner: function rowTemplateAssigner(row) {
    +          var grid = this;
    +
    +          // Row has no template assigned to it
    +          if (!row.rowTemplate) {
    +            // Use the default row template from the grid
    +            row.rowTemplate = grid.options.rowTemplate;
    +
    +            // Use the grid's function for fetching the compiled row template function
    +            row.getRowTemplateFn = grid.getRowTemplateFn;
    +          }
    +          // Row has its own template assigned
    +          else {
    +            // Create a promise for the compiled row template function
    +            var perRowTemplateFnPromise = $q.defer();
    +            row.getRowTemplateFn = perRowTemplateFnPromise.promise;
    +
    +            // Get the row template
    +            gridUtil.getTemplate(row.rowTemplate)
    +              .then(function (template) {
    +                // Compile the template
    +                var rowTemplateFn = $compile(template);
    +                
    +                // Resolve the compiled template function promise
    +                perRowTemplateFnPromise.resolve(rowTemplateFn);
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
    +              });
    +          }
    +
    +          return row.getRowTemplateFn;
    +        }
    +      };
    +
    +      //class definitions (moved to separate factories)
    +
    +      return service;
    +    }]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +function escapeRegExp(str) {
    +  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    +}
    +
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:rowSearcher
    + *
    + *  @description Service for searching/filtering rows based on column value conditions.
    + */
    +module.service('rowSearcher', ['gridUtil', 'uiGridConstants', function (gridUtil, uiGridConstants) {
    +  var defaultCondition = uiGridConstants.filter.STARTS_WITH;
    +
    +  var rowSearcher = {};
    +
    +  /**
    +   * @ngdoc function
    +   * @name getTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Get the term from a filter
    +   * Trims leading and trailing whitespace
    +   * @param {object} filter object to use
    +   * @returns {object} Parsed term
    +   */
    +  rowSearcher.getTerm = function getTerm(filter) {
    +    if (typeof(filter.term) === 'undefined') { return filter.term; }
    +    
    +    var term = filter.term;
    +
    +    // Strip leading and trailing whitespace if the term is a string
    +    if (typeof(term) === 'string') {
    +      term = term.trim();
    +    }
    +
    +    return term;
    +  };
    +
    +  /**
    +   * @ngdoc function
    +   * @name stripTerm
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Remove leading and trailing asterisk (*) from the filter's term
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.stripTerm = function stripTerm(filter) {
    +    var term = rowSearcher.getTerm(filter);
    +
    +    if (typeof(term) === 'string') {
    +      return escapeRegExp(term.replace(/(^\*|\*$)/g, ''));
    +    }
    +    else {
    +      return term;
    +    }
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name guessCondition
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Guess the condition for a filter based on its term
    +   * <br>
    +   * Defaults to STARTS_WITH. Uses CONTAINS for strings beginning and ending with *s (*bob*).
    +   * Uses STARTS_WITH for strings ending with * (bo*). Uses ENDS_WITH for strings starting with * (*ob).
    +   * @param {object} filter object to use
    +   * @returns {uiGridConstants.filter<int>} Value representing the condition constant value
    +   */
    +  rowSearcher.guessCondition = function guessCondition(filter) {
    +    if (typeof(filter.term) === 'undefined' || !filter.term) {
    +      return defaultCondition;
    +    }
    +
    +    var term = rowSearcher.getTerm(filter);
    +    
    +    if (/\*/.test(term)) {
    +      var regexpFlags = '';
    +      if (!filter.flags || !filter.flags.caseSensitive) {
    +        regexpFlags += 'i';
    +      }
    +
    +      var reText = term.replace(/(\\)?\*/g, function ($0, $1) { return $1 ? $0 : '[\\s\\S]*?'; });
    +      return new RegExp('^' + reText + '$', regexpFlags);
    +    }
    +    // Otherwise default to default condition
    +    else {
    +      return defaultCondition;
    +    }
    +  };
    +  
    +  
    +  /**
    +   * @ngdoc function
    +   * @name setupFilters
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description For a given columns filters (either col.filters, or [col.filter] can be passed in),
    +   * do all the parsing and pre-processing and store that data into a new filters object.  The object
    +   * has the condition, the flags, the stripped term, and a parsed reg exp if there was one.
    +   * 
    +   * We could use a forEach in here, since it's much less performance sensitive, but since we're using 
    +   * for loops everywhere else in this module...
    +   * 
    +   * @param {array} filters the filters from the column (col.filters or [col.filter])
    +   * @returns {array} An array of parsed/preprocessed filters
    +   */
    +  rowSearcher.setupFilters = function setupFilters( filters ){
    +    var newFilters = [];
    +    
    +    var filtersLength = filters.length;
    +    for ( var i = 0; i < filtersLength; i++ ){
    +      var filter = filters[i];
    +      if ( filter.noTerm || filter.term ){
    +        var newFilter = {};
    +        
    +        var regexpFlags = '';
    +        if (!filter.flags || !filter.flags.caseSensitive) {
    +          regexpFlags += 'i';
    +        }
    +    
    +        if ( filter.term ){
    +          // it is possible to have noTerm.  We don't need to copy that across, it was just a flag to avoid
    +          // getting the filter ignored if the filter was a function that didn't use a term
    +          newFilter.term = rowSearcher.stripTerm(filter);
    +        }
    +        
    +        if ( filter.condition ){
    +          newFilter.condition = filter.condition;
    +        } else {
    +          newFilter.condition = rowSearcher.guessCondition(filter);
    +        }
    +
    +        newFilter.flags = angular.extend( { caseSensitive: false, date: false }, filter.flags );
    +
    +        if (newFilter.condition === uiGridConstants.filter.STARTS_WITH) {
    +          newFilter.startswithRE = new RegExp('^' + newFilter.term, regexpFlags);
    +        }
    +        
    +         if (newFilter.condition === uiGridConstants.filter.ENDS_WITH) {
    +          newFilter.endswithRE = new RegExp(newFilter.term + '$', regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.CONTAINS) {
    +          newFilter.containsRE = new RegExp(newFilter.term, regexpFlags);
    +        }
    +
    +        if (newFilter.condition === uiGridConstants.filter.EXACT) {
    +          newFilter.exactRE = new RegExp('^' + newFilter.term + '$', regexpFlags);
    +        }
    +        
    +        newFilters.push(newFilter);
    +      }
    +    }
    +    return newFilters;
    +  };
    +  
    +
    +  /**
    +   * @ngdoc function
    +   * @name runColumnFilter
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Runs a single pre-parsed filter against a cell, returning true
    +   * if the cell matches that one filter.
    +   * 
    +   * @param {Grid} grid the grid we're working against
    +   * @param {GridRow} row the row we're matching against
    +   * @param {GridCol} column the column that we're working against
    +   * @param {object} filter the specific, preparsed, filter that we want to test
    +   * @returns {boolean} true if we match (row stays visible)
    +   */
    +  rowSearcher.runColumnFilter = function runColumnFilter(grid, row, column, filter) {
    +    // Cache typeof condition
    +    var conditionType = typeof(filter.condition);
    +
    +    // Term to search for.
    +    var term = filter.term;
    +
    +    // Get the column value for this row
    +    var value = grid.getCellValue(row, column);
    +    
    +    // If the filter's condition is a RegExp, then use it
    +    if (filter.condition instanceof RegExp) {
    +      return filter.condition.test(value);
    +    }
    +
    +    // If the filter's condition is a function, run it
    +    if (conditionType === 'function') {
    +      return filter.condition(term, value, row, column);
    +    }
    +    
    +    if (filter.startswithRE) {
    +      return filter.startswithRE.test(value);
    +    }
    +    
    +    if (filter.endswithRE) {
    +      return filter.endswithRE.test(value);
    +    }
    +    
    +    if (filter.containsRE) {
    +      return filter.containsRE.test(value);
    +    }
    +    
    +    if (filter.exactRE) {
    +      return filter.exactRE.test(value);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.NOT_EQUAL) {
    +      var regex = new RegExp('^' + term + '$');
    +      return !regex.exec(value);
    +    }
    +
    +    if (typeof(value) === 'number'){
    +      // if the term has a decimal in it, it comes through as '9\.4', we need to take out the \
    +      var tempFloat = parseFloat(term.replace(/\\./,'.'));
    +      if (!isNaN(tempFloat)) {
    +        term = tempFloat;
    +      }
    +    }
    +
    +    if (filter.flags.date === true) {
    +      value = new Date(value);
    +      // If the term has a dash in it, it comes through as '\-' -- we need to take out the '\'.
    +      term = new Date(term.replace(/\\/g, ''));
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN) {
    +      return (value > term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.GREATER_THAN_OR_EQUAL) {
    +      return (value >= term);
    +    }
    +
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN) {
    +      return (value < term);
    +    }
    +    
    +    if (filter.condition === uiGridConstants.filter.LESS_THAN_OR_EQUAL) {
    +      return (value <= term);
    +    }
    +    
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc boolean
    +   * @name useExternalFiltering
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description False by default. When enabled, this setting suppresses the internal filtering.
    +   * All UI logic will still operate, allowing filter conditions to be set and modified.
    +   * 
    +   * The external filter logic can listen for the `filterChange` event, which fires whenever
    +   * a filter has been adjusted.
    +   */
    +  /**
    +   * @ngdoc function
    +   * @name searchColumn
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Process provided filters on provided column against a given row. If the row meets 
    +   * the conditions on all the filters, return true.
    +   * @param {Grid} grid Grid to search in
    +   * @param {GridRow} row Row to search on
    +   * @param {GridCol} column Column with the filters to use
    +   * @param {array} filters array of pre-parsed/preprocessed filters to apply
    +   * @returns {boolean} Whether the column matches or not.
    +   */
    +  rowSearcher.searchColumn = function searchColumn(grid, row, column, filters) {
    +    if (grid.options.useExternalFiltering) {
    +      return true;
    +    }
    +    
    +    var filtersLength = filters.length;
    +    for (var i = 0; i < filtersLength; i++) {
    +      var filter = filters[i];
    +      
    +      var ret = rowSearcher.runColumnFilter(grid, row, column, filter);
    +      if (!ret) {
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  };
    +
    +
    +  /**
    +   * @ngdoc function
    +   * @name search
    +   * @methodOf ui.grid.service:rowSearcher
    +   * @description Run a search across the given rows and columns, marking any rows that don't 
    +   * match the stored col.filters or col.filter as invisible.
    +   * @param {Grid} grid Grid instance to search inside
    +   * @param {Array[GridRow]} rows GridRows to filter
    +   * @param {Array[GridColumn]} columns GridColumns with filters to process
    +   */
    +  rowSearcher.search = function search(grid, rows, columns) {
    +    /*
    +     * Added performance optimisations into this code base, as this logic creates deeply nested
    +     * loops and is therefore very performance sensitive.  In particular, avoiding forEach as
    +     * this impacts some browser optimisers (particularly Chrome), using iterators instead
    +     */
    +    
    +    // Don't do anything if we weren't passed any rows
    +    if (!rows) {
    +      return;
    +    }
    +
    +    // Build list of filters to apply
    +    var filterData = [];
    +
    +    var colsLength = columns.length;
    +    for (var i = 0; i < colsLength; i++) {
    +      var col = columns[i];
    +      
    +      if (typeof(col.filters) !== 'undefined' && ( col.filters.length > 1 || col.filters.length === 1 && ( typeof(col.filters[0].term) !== 'undefined' && col.filters[0].term || col.filters[0].noTerm ) ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters(col.filters) } );
    +      }
    +      else if (typeof(col.filter) !== 'undefined' && col.filter && ( typeof(col.filter.term) !== 'undefined' && col.filter.term || col.filter.noTerm ) ) {
    +        filterData.push( { col: col, filters: rowSearcher.setupFilters([col.filter]) } );
    +      }
    +    }
    +    
    +    if (filterData.length > 0) {
    +      // define functions outside the loop, performance optimisation
    +      var foreachRow = function(grid, row, col, filters){
    +        if (row.forceInvisible || !rowSearcher.searchColumn(grid, row, col, filters)) {
    +          row.visible = false;
    +        }
    +      };
    +      
    +      var foreachFilterCol = function(grid, filterData){
    +        var rowsLength = rows.length;
    +        for ( var i = 0; i < rowsLength; i++){
    +          foreachRow(grid, rows[i], filterData.col, filterData.filters);  
    +        }
    +      };
    +
    +      // nested loop itself - foreachFilterCol, which in turn calls foreachRow
    +      var filterDataLength = filterData.length;
    +      for ( var j = 0; j < filterDataLength; j++){
    +        foreachFilterCol( grid, filterData[j] );  
    +      }
    +
    +      if (grid.api.core.raise.rowsVisibleChanged) {
    +        grid.api.core.raise.rowsVisibleChanged();
    +      }
    +    }
    +
    +    return rows;
    +  };
    +
    +  return rowSearcher;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +/**
    + * @ngdoc object
    + * @name ui.grid.class:RowSorter
    + * @description RowSorter provides the default sorting mechanisms, 
    + * including guessing column types and applying appropriate sort 
    + * algorithms
    + * 
    + */ 
    +
    +module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGridConstants) {
    +  var currencyRegexStr = 
    +    '(' +
    +    uiGridConstants.CURRENCY_SYMBOLS
    +      .map(function (a) { return '\\' + a; }) // Escape all the currency symbols ($ at least will jack up this regex)
    +      .join('|') + // Join all the symbols together with |s
    +    ')?';
    +
    +  // /^[-+]?[£$¤¥]?[\d,.]+%?$/
    +  var numberStrRegex = new RegExp('^[-+]?' + currencyRegexStr + '[\\d,.]+' + currencyRegexStr + '%?$');
    +
    +  var rowSorter = {
    +    // Cache of sorting functions. Once we create them, we don't want to keep re-doing it
    +    //   this takes a piece of data from the cell and tries to determine its type and what sorting
    +    //   function to use for it
    +    colSortFnCache: []
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name guessSortFn
    +   * @description Assigns a sort function to use based on the itemType in the column
    +   * @param {string} itemType one of 'number', 'boolean', 'string', 'date', 'object'.  And
    +   * error will be thrown for any other type.
    +   * @returns {function} a sort function that will sort that type
    +   */
    +  rowSorter.guessSortFn = function guessSortFn(itemType) {
    +    switch (itemType) {
    +      case "number":
    +        return rowSorter.sortNumber;
    +      case "boolean":
    +        return rowSorter.sortBool;
    +      case "string":
    +        return rowSorter.sortAlpha;
    +      case "date":
    +        return rowSorter.sortDate;
    +      case "object":
    +        return rowSorter.basicSort;
    +      default:
    +        throw new Error('No sorting function found for type:' + itemType);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name handleNulls
    +   * @description Sorts nulls and undefined to the bottom (top when
    +   * descending).  Called by each of the internal sorters before
    +   * attempting to sort.  Note that this method is available on the core api
    +   * via gridApi.core.sortHandleNulls
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} null if there were no nulls/undefineds, otherwise returns
    +   * a sort value that should be passed back from the sort function
    +   */
    +  rowSorter.handleNulls = function handleNulls(a, b) {
    +    // We want to allow zero values and false values to be evaluated in the sort function
    +    if ((!a && a !== 0 && a !== false) || (!b && b !== 0 && b !== false)) {
    +      // We want to force nulls and such to the bottom when we sort... which effectively is "greater than"
    +      if ((!a && a !== 0 && a !== false) && (!b && b !== 0 && b !== false)) {
    +        return 0;
    +      }
    +      else if (!a && a !== 0 && a !== false) {
    +        return 1;
    +      }
    +      else if (!b && b !== 0 && b !== false) {
    +        return -1;
    +      }
    +    }
    +    return null;
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name basicSort
    +   * @description Sorts any values that provide the < method, including strings
    +   * or numbers.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.basicSort = function basicSort(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a === b) {
    +        return 0;
    +      }
    +      if (a < b) {
    +        return -1;
    +      }
    +      return 1;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumber
    +   * @description Sorts numerical values.  Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumber = function sortNumber(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      return a - b;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortNumberStr
    +   * @description Sorts numerical values that are stored in a string (i.e. parses them to numbers first).  
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortNumberStr = function sortNumberStr(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var numA, // The parsed number form of 'a'
    +          numB, // The parsed number form of 'b'
    +          badA = false,
    +          badB = false;
    +  
    +      // Try to parse 'a' to a float
    +      numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'a' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numA)) {
    +          badA = true;
    +      }
    +  
    +      // Try to parse 'b' to a float
    +      numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
    +  
    +      // If 'b' couldn't be parsed to float, flag it as bad
    +      if (isNaN(numB)) {
    +          badB = true;
    +      }
    +  
    +      // We want bad ones to get pushed to the bottom... which effectively is "greater than"
    +      if (badA && badB) {
    +          return 0;
    +      }
    +  
    +      if (badA) {
    +          return 1;
    +      }
    +  
    +      if (badB) {
    +          return -1;
    +      }
    +  
    +      return numA - numB;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortAlpha
    +   * @description Sorts string values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortAlpha = function sortAlpha(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var strA = a.toString().toLowerCase(),
    +          strB = b.toString().toLowerCase();
    +  
    +      return strA === strB ? 0 : (strA < strB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortDate
    +   * @description Sorts date values. Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortDate = function sortDate(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      var timeA = a.getTime(),
    +          timeB = b.getTime();
    +  
    +      return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sortBool
    +   * @description Sorts boolean values, true is considered larger than false. 
    +   * Handles nulls and undefined through calling handleNulls 
    +   * @param {object} a sort value a
    +   * @param {object} b sort value b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.sortBool = function sortBool(a, b) {
    +    var nulls = rowSorter.handleNulls(a, b);
    +    if ( nulls !== null ){
    +      return nulls;
    +    } else {
    +      if (a && b) {
    +        return 0;
    +      }
    +  
    +      if (!a && !b) {
    +        return 0;
    +      }
    +      else {
    +        return a ? 1 : -1;
    +      }
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name getSortFn
    +   * @description Get the sort function for the column.  Looks first in 
    +   * rowSorter.colSortFnCache using the column name, failing that it
    +   * looks at col.sortingAlgorithm (and puts it in the cache), failing that
    +   * it guesses the sort algorithm based on the data type.
    +   * 
    +   * The cache currently seems a bit pointless, as none of the work we do is
    +   * processor intensive enough to need caching.  Presumably in future we might
    +   * inspect the row data itself to guess the sort function, and in that case
    +   * it would make sense to have a cache, the infrastructure is in place to allow
    +   * that.
    +   * 
    +   * @param {Grid} grid the grid to consider
    +   * @param {GridCol} col the column to find a function for
    +   * @param {array} rows an array of grid rows.  Currently unused, but presumably in future
    +   * we might inspect the rows themselves to decide what sort of data might be there
    +   * @returns {function} the sort function chosen for the column
    +   */
    +  rowSorter.getSortFn = function getSortFn(grid, col, rows) {
    +    var sortFn, item;
    +
    +    // See if we already figured out what to use to sort the column and have it in the cache
    +    if (rowSorter.colSortFnCache[col.colDef.name]) {
    +      sortFn = rowSorter.colSortFnCache[col.colDef.name];
    +    }
    +    // If the column has its OWN sorting algorithm, use that
    +    else if (col.sortingAlgorithm !== undefined) {
    +      sortFn = col.sortingAlgorithm;
    +      rowSorter.colSortFnCache[col.colDef.name] = col.sortingAlgorithm;
    +    }
    +    // Try and guess what sort function to use
    +    else {
    +      // Guess the sort function
    +      sortFn = rowSorter.guessSortFn(col.colDef.type);
    +
    +      // If we found a sort function, cache it
    +      if (sortFn) {
    +        rowSorter.colSortFnCache[col.colDef.name] = sortFn;
    +      }
    +      else {
    +        // We assign the alpha sort because anything that is null/undefined will never get passed to
    +        // the actual sorting function. It will get caught in our null check and returned to be sorted
    +        // down to the bottom
    +        sortFn = rowSorter.sortAlpha;
    +      }
    +    }
    +
    +    return sortFn;
    +  };
    +
    +
    +
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name prioritySort
    +   * @description Used where multiple columns are present in the sort criteria,
    +   * we determine which column should take precedence in the sort by sorting
    +   * the columns based on their sort.priority
    +   * 
    +   * @param {gridColumn} a column a
    +   * @param {gridColumn} b column b
    +   * @returns {number} normal sort function, returns -ve, 0, +ve
    +   */
    +  rowSorter.prioritySort = function (a, b) {
    +    // Both columns have a sort priority
    +    if (a.sort.priority !== undefined && b.sort.priority !== undefined) {
    +      // A is higher priority
    +      if (a.sort.priority < b.sort.priority) {
    +        return -1;
    +      }
    +      // Equal
    +      else if (a.sort.priority === b.sort.priority) {
    +        return 0;
    +      }
    +      // B is higher
    +      else {
    +        return 1;
    +      }
    +    }
    +    // Only A has a priority
    +    else if (a.sort.priority || a.sort.priority === 0) {
    +      return -1;
    +    }
    +    // Only B has a priority
    +    else if (b.sort.priority || b.sort.priority === 0) {
    +      return 1;
    +    }
    +    // Neither has a priority
    +    else {
    +      return 0;
    +    }
    +  };
    +
    +
    +  /**
    +   * @ngdoc object
    +   * @name useExternalSorting
    +   * @propertyOf ui.grid.class:GridOptions
    +   * @description Prevents the internal sorting from executing.  Events will
    +   * still be fired when the sort changes, and the sort information on
    +   * the columns will be updated, allowing an external sorter (for example,
    +   * server sorting) to be implemented.  Defaults to false. 
    +   * 
    +   */
    +  /**
    +   * @ngdoc method
    +   * @methodOf ui.grid.class:RowSorter
    +   * @name sort
    +   * @description sorts the grid 
    +   * @param {Object} grid the grid itself
    +   * @param {Object} rows the rows to be sorted
    +   * @param {Object} columns the columns in which to look
    +   * for sort criteria
    +   */
    +  rowSorter.sort = function rowSorterSort(grid, rows, columns) {
    +    // first make sure we are even supposed to do work
    +    if (!rows) {
    +      return;
    +    }
    +    
    +    if (grid.options.useExternalSorting){
    +      return rows;
    +    }
    +
    +    // Build the list of columns to sort by
    +    var sortCols = [];
    +    columns.forEach(function (col) {
    +      if (col.sort && col.sort.direction && (col.sort.direction === uiGridConstants.ASC || col.sort.direction === uiGridConstants.DESC)) {
    +        sortCols.push(col);
    +      }
    +    });
    +
    +    // Sort the "sort columns" by their sort priority
    +    sortCols = sortCols.sort(rowSorter.prioritySort);
    +
    +    // Now rows to sort by, maintain original order
    +    if (sortCols.length === 0) {
    +      return rows;
    +    }
    +    
    +    // Re-usable variables
    +    var col, direction;
    +
    +    // IE9-11 HACK.... the 'rows' variable would be empty where we call rowSorter.getSortFn(...) below. We have to use a separate reference
    +    // var d = data.slice(0);
    +    var r = rows.slice(0);
    +    
    +    // put a custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( rows, function ( row, idx ) {
    +      row.entity.$uiGridIndex = idx;
    +    });
    +
    +    // Now actually sort the data
    +    var newRows = rows.sort(function rowSortFn(rowA, rowB) {
    +      var tem = 0,
    +          idx = 0,
    +          sortFn;
    +
    +      while (tem === 0 && idx < sortCols.length) {
    +        // grab the metadata for the rest of the logic
    +        col = sortCols[idx];
    +        direction = sortCols[idx].sort.direction;
    +
    +        sortFn = rowSorter.getSortFn(grid, col, r);
    +        
    +        var propA = grid.getCellValue(rowA, col);
    +        var propB = grid.getCellValue(rowB, col);
    +
    +        tem = sortFn(propA, propB);
    +
    +        idx++;
    +      }
    +
    +      // Chrome doesn't implement a stable sort function.  If our sort returns 0 
    +      // (i.e. the items are equal), then return the previous order using our custom
    +      // index variable
    +      if (tem === 0 ) {
    +        return rowA.entity.$uiGridIndex - rowB.entity.$uiGridIndex;
    +      }
    +      
    +      // Made it this far, we don't have to worry about null & undefined
    +      if (direction === uiGridConstants.ASC) {
    +        return tem;
    +      } else {
    +        return 0 - tem;
    +      }
    +    });
    +    
    +    // remove the custom index field on each row, used to make a stable sort out of unstable sorts (e.g. Chrome)
    +    angular.forEach( newRows, function ( row, idx ) {
    +      delete row.entity.$uiGridIndex;
    +    });
    +    
    +    return newRows;
    +  };
    +
    +  return rowSorter;
    +}]);
    +
    +})();
    +(function() {
    +
    +var module = angular.module('ui.grid');
    +
    +var bindPolyfill;
    +if (typeof Function.prototype.bind !== "function") {
    +  bindPolyfill = function() {
    +    var slice = Array.prototype.slice;
    +    return function(context) {
    +      var fn = this,
    +        args = slice.call(arguments, 1);
    +      if (args.length) {
    +        return function() {
    +          return arguments.length ? fn.apply(context, args.concat(slice.call(arguments))) : fn.apply(context, args);
    +        };
    +      }
    +      return function() {
    +        return arguments.length ? fn.apply(context, arguments) : fn.call(context);
    +      };
    +    };
    +  };
    +}
    +
    +function getStyles (elem) {
    +  var e = elem;
    +  if (typeof(e.length) !== 'undefined' && e.length) {
    +    e = elem[0];
    +  }
    +
    +  return e.ownerDocument.defaultView.getComputedStyle(e, null);
    +}
    +
    +var rnumnonpx = new RegExp( "^(" + (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source + ")(?!px)[a-z%]+$", "i" ),
    +    // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
    +    // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    +    rdisplayswap = /^(block|none|table(?!-c[ea]).+)/,
    +    cssShow = { position: "absolute", visibility: "hidden", display: "block" };
    +
    +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
    +  var i = extra === ( isBorderBox ? 'border' : 'content' ) ?
    +          // If we already have the right measurement, avoid augmentation
    +          4 :
    +          // Otherwise initialize for horizontal or vertical properties
    +          name === 'width' ? 1 : 0,
    +
    +          val = 0;
    +
    +  var sides = ['Top', 'Right', 'Bottom', 'Left'];
    +  
    +  for ( ; i < 4; i += 2 ) {
    +    var side = sides[i];
    +    // dump('side', side);
    +
    +    // both box models exclude margin, so add it if we want it
    +    if ( extra === 'margin' ) {
    +      var marg = parseFloat(styles[extra + side]);
    +      if (!isNaN(marg)) {
    +        val += marg;
    +      }
    +    }
    +    // dump('val1', val);
    +
    +    if ( isBorderBox ) {
    +      // border-box includes padding, so remove it if we want content
    +      if ( extra === 'content' ) {
    +        var padd = parseFloat(styles['padding' + side]);
    +        if (!isNaN(padd)) {
    +          val -= padd;
    +          // dump('val2', val);
    +        }
    +      }
    +
    +      // at this point, extra isn't border nor margin, so remove border
    +      if ( extra !== 'margin' ) {
    +        var bordermarg = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(bordermarg)) {
    +          val -= bordermarg;
    +          // dump('val3', val);
    +        }
    +      }
    +    }
    +    else {
    +      // at this point, extra isn't content, so add padding
    +      var nocontentPad = parseFloat(styles['padding' + side]);
    +      if (!isNaN(nocontentPad)) {
    +        val += nocontentPad;
    +        // dump('val4', val);
    +      }
    +
    +      // at this point, extra isn't content nor padding, so add border
    +      if ( extra !== 'padding') {
    +        var nocontentnopad = parseFloat(styles['border' + side + 'Width']);
    +        if (!isNaN(nocontentnopad)) {
    +          val += nocontentnopad;
    +          // dump('val5', val);
    +        }
    +      }
    +    }
    +  }
    +
    +  // dump('augVal', val);
    +
    +  return val;
    +}
    +
    +function getWidthOrHeight( elem, name, extra ) {
    +  // Start with offset property, which is equivalent to the border-box value
    +  var valueIsBorderBox = true,
    +          val,
    +          styles = getStyles(elem),
    +          isBorderBox = styles['boxSizing'] === 'border-box';
    +
    +  // some non-html elements return undefined for offsetWidth, so check for null/undefined
    +  // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
    +  // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
    +  if ( val <= 0 || val == null ) {
    +    // Fall back to computed then uncomputed css if necessary
    +    val = styles[name];
    +    if ( val < 0 || val == null ) {
    +      val = elem.style[ name ];
    +    }
    +
    +    // Computed unit is not pixels. Stop here and return.
    +    if ( rnumnonpx.test(val) ) {
    +      return val;
    +    }
    +
    +    // we need the check for style in case a browser which returns unreliable values
    +    // for getComputedStyle silently falls back to the reliable elem.style
    +    valueIsBorderBox = isBorderBox &&
    +            ( true || val === elem.style[ name ] ); // use 'true' instead of 'support.boxSizingReliable()'
    +
    +    // Normalize "", auto, and prepare for extra
    +    val = parseFloat( val ) || 0;
    +  }
    +
    +  // use the active box-sizing model to add/subtract irrelevant styles
    +  var ret = ( val +
    +    augmentWidthOrHeight(
    +      elem,
    +      name,
    +      extra || ( isBorderBox ? "border" : "content" ),
    +      valueIsBorderBox,
    +      styles
    +    )
    +  );
    +
    +  // dump('ret', ret, val);
    +  return ret;
    +}
    +
    +function getLineHeight(elm) {
    +  elm = angular.element(elm)[0];
    +  var parent = elm.offsetParent;
    +
    +  if (!parent) {
    +    parent = document.getElementsByTagName('body')[0];
    +  }
    +
    +  return parseInt( getStyles(parent).fontSize ) || parseInt( getStyles(elm).fontSize ) || 16;
    +}
    +
    +var uid = ['0', '0', '0'];
    +var uidPrefix = 'uiGrid-';
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateCache', '$timeout', '$injector', '$q', '$interpolate', 'uiGridConstants',
    +  function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
    +  var s = {
    +
    +    getStyles: getStyles,
    +
    +    /**
    +     * @ngdoc method
    +     * @name createBoundedWrapper
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {object} Object to bind 'this' to
    +     * @param {method} Method to bind
    +     * @returns {Function} The wrapper that performs the binding
    +     *
    +     * @description
    +     * Binds given method to given object.
    +     *
    +     * By means of a wrapper, ensures that ``method`` is always bound to
    +     * ``object`` regardless of its calling environment.
    +     * Iow, inside ``method``, ``this`` always points to ``object``.
    +     *
    +     * See http://alistapart.com/article/getoutbindingsituations
    +     *
    +     */
    +    createBoundedWrapper: function(object, method) {
    +        return function() {
    +            return method.apply(object, arguments);
    +        };
    +    },
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid']);
    +
    +          app.controller('MainCtrl', ['$scope', 'gridUtil', function ($scope, gridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return gridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data, excludeProperties);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data, excludeProperties) {
    +      var columnDefs = [];
    +
    +      if (!data || typeof(data[0]) === 'undefined' || data[0] === undefined) { return []; }
    +      if (angular.isUndefined(excludeProperties)) { excludeProperties = []; }
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item,function (prop, propName) {
    +        if ( excludeProperties.indexOf(propName) === -1){
    +          columnDefs.push({
    +            name: propName
    +          });
    +        }
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +
    +
    +    /**
    +     * @ngdoc method
    +     * @name getTemplate
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description Get's template from cache / element / url
    +     *
    +     * @param {string|element|promise} Either a string representing the template id, a string representing the template url,
    +     *   an jQuery/Angualr element, or a promise that returns the template contents to use.
    +     * @returns {object} a promise resolving to template contents
    +     *
    +     * @example
    +     <pre>
    +     GridUtil.getTemplate(url).then(function (contents) {
    +          alert(contents);
    +        })
    +     </pre>
    +     */
    +    getTemplate: function (template) {
    +      // Try to fetch the template out of the templateCache
    +      if ($templateCache.get(template)) {
    +        return s.postProcessTemplate($templateCache.get(template));
    +      }
    +
    +      // See if the template is itself a promise
    +      if (template.hasOwnProperty('then')) {
    +        return template.then(s.postProcessTemplate);
    +      }
    +
    +      // If the template is an element, return the element
    +      try {
    +        if (angular.element(template).length > 0) {
    +          return $q.when(template).then(s.postProcessTemplate);
    +        }
    +      }
    +      catch (err){
    +        //do nothing; not valid html
    +      }
    +
    +      s.logDebug('fetching url', template);
    +
    +      // Default to trying to fetch the template as a url with $http
    +      return $http({ method: 'GET', url: template})
    +        .then(
    +          function (result) {
    +            var templateHtml = result.data.trim();
    +            //put in templateCache for next call
    +            $templateCache.put(template, templateHtml);
    +            return templateHtml;
    +          },
    +          function (err) {
    +            throw new Error("Could not get template " + template + ": " + err);
    +          }
    +        )
    +        .then(s.postProcessTemplate);
    +    },
    +
    +    // 
    +    postProcessTemplate: function (template) {
    +      var startSym = $interpolate.startSymbol(),
    +          endSym = $interpolate.endSymbol();
    +
    +      // If either of the interpolation symbols have been changed, we need to alter this template
    +      if (startSym !== '{{' || endSym !== '}}') {
    +        template = template.replace(/\{\{/g, startSym);
    +        template = template.replace(/\}\}/g, endSym);
    +      }
    +
    +      return $q.when(template);
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name guessType
    +     * @methodOf ui.grid.service:GridUtil
    +     * @description guesses the type of an argument
    +     *
    +     * @param {string/number/bool/object} item variable to examine
    +     * @returns {string} one of the following
    +     * 'string'
    +     * 'boolean'
    +     * 'number'
    +     * 'date'
    +     * 'object'
    +     */
    +    guessType : function (item) {
    +      var itemType = typeof(item);
    +
    +      // Check for numbers and booleans
    +      switch (itemType) {
    +        case "number":
    +        case "boolean":
    +        case "string":
    +          return itemType;
    +        default:
    +          if (angular.isDate(item)) {
    +            return "date";
    +          }
    +          return "object";
    +      }
    +    },
    +
    +
    +  /**
    +    * @ngdoc method
    +    * @name elementWidth
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element width in pixels, accounting for any borders, etc.
    +    */
    +    elementWidth: function (elem) {
    +      
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name elementHeight
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element DOM element
    +    * @param {string} [extra] Optional modifier for calculation. Use 'margin' to account for margins on element
    +    *
    +    * @returns {number} Element height in pixels, accounting for any borders, etc.
    +    */
    +    elementHeight: function (elem) {
    +      
    +    },
    +
    +    // Thanks to http://stackoverflow.com/a/13382873/888165
    +    getScrollbarWidth: function() {
    +        var outer = document.createElement("div");
    +        outer.style.visibility = "hidden";
    +        outer.style.width = "100px";
    +        outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    +
    +        document.body.appendChild(outer);
    +
    +        var widthNoScroll = outer.offsetWidth;
    +        // force scrollbars
    +        outer.style.overflow = "scroll";
    +
    +        // add innerdiv
    +        var inner = document.createElement("div");
    +        inner.style.width = "100%";
    +        outer.appendChild(inner);        
    +
    +        var widthWithScroll = inner.offsetWidth;
    +
    +        // remove divs
    +        outer.parentNode.removeChild(outer);
    +
    +        return widthNoScroll - widthWithScroll;
    +    },
    +
    +    swap: function( elem, options, callback, args ) {
    +      var ret, name,
    +              old = {};
    +
    +      // Remember the old values, and insert the new ones
    +      for ( name in options ) {
    +        old[ name ] = elem.style[ name ];
    +        elem.style[ name ] = options[ name ];
    +      }
    +
    +      ret = callback.apply( elem, args || [] );
    +
    +      // Revert the old values
    +      for ( name in options ) {
    +        elem.style[ name ] = old[ name ];
    +      }
    +
    +      return ret;
    +    },
    +
    +    fakeElement: function( elem, options, callback, args ) {
    +      var ret, name,
    +          newElement = angular.element(elem).clone()[0];
    +
    +      for ( name in options ) {
    +        newElement.style[ name ] = options[ name ];
    +      }
    +
    +      angular.element(document.body).append(newElement);
    +
    +      ret = callback.call( newElement, newElement );
    +
    +      angular.element(newElement).remove();
    +
    +      return ret;
    +    },
    +
    +    /**
    +    * @ngdoc method
    +    * @name normalizeWheelEvent
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {event} event A mouse wheel event
    +    *
    +    * @returns {event} A normalized event
    +    *
    +    * @description
    +    * Given an event from this list:
    +    *
    +    * `wheel, mousewheel, DomMouseScroll, MozMousePixelScroll`
    +    *
    +    * "normalize" it
    +    * so that it stays consistent no matter what browser it comes from (i.e. scale it correctly and make sure the direction is right.)
    +    */
    +    normalizeWheelEvent: function (event) {
    +      // var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
    +      // var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
    +      var lowestDelta, lowestDeltaXY;
    +      
    +      var orgEvent   = event || window.event,
    +          args       = [].slice.call(arguments, 1),
    +          delta      = 0,
    +          deltaX     = 0,
    +          deltaY     = 0,
    +          absDelta   = 0,
    +          absDeltaXY = 0,
    +          fn;
    +
    +      // event = $.event.fix(orgEvent);
    +      // event.type = 'mousewheel';
    +
    +      // NOTE: jQuery masks the event and stores it in the event as originalEvent
    +      if (orgEvent.originalEvent) {
    +        orgEvent = orgEvent.originalEvent;
    +      }
    +
    +      // Old school scrollwheel delta
    +      if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
    +      if ( orgEvent.detail )     { delta = orgEvent.detail * -1; }
    +
    +      // At a minimum, setup the deltaY to be delta
    +      deltaY = delta;
    +
    +      // Firefox < 17 related to DOMMouseScroll event
    +      if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
    +          deltaY = 0;
    +          deltaX = delta * -1;
    +      }
    +
    +      // New school wheel delta (wheel event)
    +      if ( orgEvent.deltaY ) {
    +          deltaY = orgEvent.deltaY * -1;
    +          delta  = deltaY;
    +      }
    +      if ( orgEvent.deltaX ) {
    +          deltaX = orgEvent.deltaX;
    +          delta  = deltaX * -1;
    +      }
    +
    +      // Webkit
    +      if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
    +      if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX; }
    +
    +      // Look for lowest delta to normalize the delta values
    +      absDelta = Math.abs(delta);
    +      if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
    +      absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
    +      if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
    +
    +      // Get a whole value for the deltas
    +      fn     = delta > 0 ? 'floor' : 'ceil';
    +      delta  = Math[fn](delta  / lowestDelta);
    +      deltaX = Math[fn](deltaX / lowestDeltaXY);
    +      deltaY = Math[fn](deltaY / lowestDeltaXY);
    +
    +      return {
    +        delta: delta,
    +        deltaX: deltaX,
    +        deltaY: deltaY
    +      };
    +    },
    +
    +    // Stolen from Modernizr
    +    // TODO: make this, and everythign that flows from it, robust
    +    //http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
    +    isTouchEnabled: function() {
    +      var bool;
    +
    +      if (('ontouchstart' in $window) || $window.DocumentTouch && $document instanceof DocumentTouch) {
    +        bool = true;
    +      }
    +
    +      return bool;
    +    },
    +
    +    isNullOrUndefined: function(obj) {
    +      if (obj === undefined || obj === null) {
    +        return true;
    +      }
    +      return false;
    +    },
    +
    +    endsWith: function(str, suffix) {
    +      if (!str || !suffix || typeof str !== "string") {
    +        return false;
    +      }
    +      return str.indexOf(suffix, str.length - suffix.length) !== -1;
    +    },
    +
    +    arrayContainsObjectWithProperty: function(array, propertyName, propertyValue) {
    +        var found = false;
    +        angular.forEach(array, function (object) {
    +            if (object[propertyName] === propertyValue) {
    +                found = true;
    +            }
    +        });
    +        return found;
    +    },
    +
    +    // Shim requestAnimationFrame
    +    requestAnimationFrame: $window.requestAnimationFrame && $window.requestAnimationFrame.bind($window) ||
    +                           $window.webkitRequestAnimationFrame && $window.webkitRequestAnimationFrame.bind($window) ||
    +                           function(fn) {
    +                             return $timeout(fn, 10, false);
    +                           },
    +
    +    numericAndNullSort: function (a, b) {
    +      if (a === null) { return 1; }
    +      if (b === null) { return -1; }
    +      if (a === null && b === null) { return 0; }
    +      return a - b;
    +    },
    +
    +    // Disable ngAnimate animations on an element
    +    disableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(false, element);
    +      }
    +      catch (e) {}
    +    },
    +
    +    enableAnimations: function (element) {
    +      var $animate;
    +      try {
    +        $animate = $injector.get('$animate');
    +        $animate.enabled(true, element);
    +        return $animate;
    +      }
    +      catch (e) {}
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    nextUid: function nextUid() {
    +      var index = uid.length;
    +      var digit;
    +
    +      while (index) {
    +        index--;
    +        digit = uid[index].charCodeAt(0);
    +        if (digit === 57 /*'9'*/) {
    +          uid[index] = 'A';
    +          return uidPrefix + uid.join('');
    +        }
    +        if (digit === 90  /*'Z'*/) {
    +          uid[index] = '0';
    +        } else {
    +          uid[index] = String.fromCharCode(digit + 1);
    +          return uidPrefix + uid.join('');
    +        }
    +      }
    +      uid.unshift('0');
    +
    +      return uidPrefix + uid.join('');
    +    },
    +
    +    // Blatantly stolen from Angular as it isn't exposed (yet. 2.0 maybe?)
    +    hashKey: function hashKey(obj) {
    +      var objType = typeof obj,
    +          key;
    +
    +      if (objType === 'object' && obj !== null) {
    +        if (typeof (key = obj.$$hashKey) === 'function') {
    +          // must invoke on object to keep the right this
    +          key = obj.$$hashKey();
    +        }
    +        else if (typeof(obj.$$hashKey) !== 'undefined' && obj.$$hashKey) {
    +          key = obj.$$hashKey;
    +        }
    +        else if (key === undefined) {
    +          key = obj.$$hashKey = s.nextUid();
    +        }
    +      }
    +      else {
    +        key = obj;
    +      }
    +
    +      return objType + ':' + key;
    +    },
    +
    +    resetUids: function () {
    +      uid = ['0', '0', '0'];
    +    },
    +    
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logError
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * error messages if uiGridConstants.LOG_ERROR_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logError: function( logMessage ){
    +      if ( uiGridConstants.LOG_ERROR_MESSAGES ){
    +        $log.error( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logWarn
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * warning messages if uiGridConstants.LOG_WARN_MESSAGES is set to true
    +     * @param {string} logMessage message to be logged to the console
    +     * 
    +     */
    +    logWarn: function( logMessage ){
    +      if ( uiGridConstants.LOG_WARN_MESSAGES ){
    +        $log.warn( logMessage );
    +      }
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @methodOf ui.grid.service:GridUtil
    +     * @name logDebug
    +     * @description wraps the $log method, allowing us to choose different
    +     * treatment within ui-grid if we so desired.  At present we only log
    +     * debug messages if uiGridConstants.LOG_DEBUG_MESSAGES is set to true
    +     * 
    +     */
    +    logDebug: function() {
    +      if ( uiGridConstants.LOG_DEBUG_MESSAGES ){
    +        $log.debug.apply($log, arguments);
    +      }
    +    }
    +
    +  };
    +
    +  ['width', 'height'].forEach(function (name) {
    +    var capsName = angular.uppercase(name.charAt(0)) + name.substr(1);
    +    s['element' + capsName] = function (elem, extra) {
    +      var e = elem;
    +      if (e && typeof(e.length) !== 'undefined' && e.length) {
    +        e = elem[0];
    +      }
    +
    +      if (e) {
    +        var styles = getStyles(e);
    +        return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
    +                  s.fakeElement(e, cssShow, function(newElm) {
    +                    return getWidthOrHeight( newElm, name, extra );
    +                  }) :
    +                  getWidthOrHeight( e, name, extra );
    +      }
    +      else {
    +        return null;
    +      }
    +    };
    +
    +    s['outerElement' + capsName] = function (elem, margin) {
    +      return elem ? s['element' + capsName].call(this, elem, margin ? 'margin' : 'border') : null;
    +    };
    +  });
    +
    +  // http://stackoverflow.com/a/24107550/888165
    +  s.closestElm = function closestElm(el, selector) {
    +    if (typeof(el.length) !== 'undefined' && el.length) {
    +      el = el[0];
    +    }
    +
    +    var matchesFn;
    +
    +    // find vendor prefix
    +    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    +        if (typeof document.body[fn] === 'function') {
    +            matchesFn = fn;
    +            return true;
    +        }
    +        return false;
    +    });
    +
    +    // traverse parents
    +    var parent;
    +    while (el !== null) {
    +      parent = el.parentElement;
    +      if (parent !== null && parent[matchesFn](selector)) {
    +          return parent;
    +      }
    +      el = parent;
    +    }
    +
    +    return null;
    +  };
    +
    +  s.type = function (obj) {
    +    var text = Function.prototype.toString.call(obj.constructor);
    +    return text.match(/function (.*?)\(/)[1];
    +  };
    +
    +  s.getBorderSize = function getBorderSize(elem, borderType) {
    +    if (typeof(elem.length) !== 'undefined' && elem.length) {
    +      elem = elem[0];
    +    }
    +
    +    var styles = getStyles(elem);
    +
    +    // If a specific border is supplied, like 'top', read the 'borderTop' style property
    +    if (borderType) {
    +      borderType = 'border' + borderType.charAt(0).toUpperCase() + borderType.slice(1);
    +    }
    +    else {
    +      borderType = 'border';
    +    }
    +
    +    borderType += 'Width';
    +
    +    var val = parseInt(styles[borderType], 10);
    +
    +    if (isNaN(val)) {
    +      return 0;
    +    }
    +    else {
    +      return val;
    +    }
    +  };
    +
    +  // http://stackoverflow.com/a/22948274/888165
    +  // TODO: Opera? Mobile?
    +  s.detectBrowser = function detectBrowser() {
    +    var userAgent = $window.navigator.userAgent;
    +
    +    var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer|trident\//i};
    +
    +    for (var key in browsers) {
    +      if (browsers[key].test(userAgent)) {
    +        return key;
    +      }
    +    }
    +
    +    return 'unknown';
    +  };
    +
    +  /**
    +    * @ngdoc method
    +    * @name normalizeScrollLeft
    +    * @methodOf ui.grid.service:GridUtil
    +    *
    +    * @param {element} element The element to get the `scrollLeft` from.
    +    *
    +    * @returns {int} A normalized scrollLeft value for the current browser.
    +    *
    +    * @description
    +    * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method normalizes them
    +    */
    +  s.normalizeScrollLeft = function normalizeScrollLeft(element) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var scrollLeft = element.scrollLeft;
    +    
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      return Math.abs(scrollLeft);
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +  /**
    +  * @ngdoc method
    +  * @name normalizeScrollLeft
    +  * @methodOf ui.grid.service:GridUtil
    +  *
    +  * @param {element} element The element to normalize the `scrollLeft` value for
    +  * @param {int} scrollLeft The `scrollLeft` value to denormalize.
    +  *
    +  * @returns {int} A normalized scrollLeft value for the current browser.
    +  *
    +  * @description
    +  * Browsers currently handle RTL in different ways, resulting in inconsistent scrollLeft values. This method denormalizes a value for the current browser.
    +  */
    +  s.denormalizeScrollLeft = function denormalizeScrollLeft(element, scrollLeft) {
    +    if (typeof(element.length) !== 'undefined' && element.length) {
    +      element = element[0];
    +    }
    +
    +    var browser = s.detectBrowser();
    +
    +    var dir = s.getStyles(element)['direction'];
    +
    +    // IE stays normal in RTL
    +    if (browser === 'ie') {
    +      return scrollLeft;
    +    }
    +    // Chrome doesn't alter the scrollLeft value. So with RTL on a 400px-wide grid, the right-most position will still be 400 and the left-most will still be 0;
    +    else if (browser === 'chrome') {
    +      if (dir === 'rtl') {
    +        // Get the max scroll for the element
    +        var maxScrollLeft = element.scrollWidth - element.clientWidth;
    +
    +        // Subtract the current scroll amount from the max scroll
    +        return maxScrollLeft - scrollLeft;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    // Firefox goes negative!
    +    else if (browser === 'firefox') {
    +      if (dir === 'rtl') {
    +        return scrollLeft * -1;
    +      }
    +      else {
    +        return scrollLeft;
    +      }
    +    }
    +    else {
    +      // TODO(c0bra): Handle other browsers? Android? iOS? Opera?
    +      return scrollLeft;
    +    }
    +  };
    +
    +    /**
    +     * @ngdoc method
    +     * @name preEval
    +     * @methodOf ui.grid.service:GridUtil
    +     *
    +     * @param {string} path Path to evaluate
    +     *
    +     * @returns {string} A path that is normalized.
    +     *
    +     * @description
    +     * Takes a field path and converts it to bracket notation to allow for special characters in path
    +     * @example
    +     * <pre>
    +     * gridUtil.preEval('property') == 'property'
    +     * gridUtil.preEval('nested.deep.prop-erty') = "nested['deep']['prop-erty']"
    +     * </pre>
    +     */
    +  s.preEval = function (path) {
    +    var m = uiGridConstants.BRACKET_REGEXP.exec(path);
    +    if (m) {
    +      return (m[1] ? s.preEval(m[1]) : m[1]) + m[2] + (m[3] ? s.preEval(m[3]) : m[3]);
    +    } else {
    +      path = path.replace(uiGridConstants.APOS_REGEXP, '\\\'');
    +      var parts = path.split(uiGridConstants.DOT_REGEXP);
    +      var preparsed = [parts.shift()];    // first item must be var notation, thus skip
    +      angular.forEach(parts, function (part) {
    +        preparsed.push(part.replace(uiGridConstants.FUNC_REGEXP, '\']$1'));
    +      });
    +      return preparsed.join('[\'');
    +    }
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name debounce
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to debounce
    +   * @param {number} wait milliseconds to delay
    +   * @param {bool} immediate execute before delay
    +   *
    +   * @returns {function} A function that can be executed as debounced function
    +   *
    +   * @description
    +   * Copied from https://github.com/shahata/angular-debounce
    +   * Takes a function, decorates it to execute only 1 time after multiple calls, and returns the decorated function
    +   * @example
    +   * <pre>
    +   * var debouncedFunc =  gridUtil.debounce(function(){alert('debounced');}, 500);
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * debouncedFunc();
    +   * </pre>
    +   */
    +  s.debounce =  function (func, wait, immediate) {
    +    var timeout, args, context, result;
    +    function debounce() {
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      var later = function () {
    +        timeout = null;
    +        if (!immediate) {
    +          result = func.apply(context, args);
    +        }
    +      };
    +      var callNow = immediate && !timeout;
    +      if (timeout) {
    +        $timeout.cancel(timeout);
    +      }
    +      timeout = $timeout(later, wait);
    +      if (callNow) {
    +        result = func.apply(context, args);
    +      }
    +      return result;
    +    }
    +    debounce.cancel = function () {
    +      $timeout.cancel(timeout);
    +      timeout = null;
    +    };
    +    return debounce;
    +  };
    +
    +  /**
    +   * @ngdoc method
    +   * @name throttle
    +   * @methodOf ui.grid.service:GridUtil
    +   *
    +   * @param {function} func function to throttle
    +   * @param {number} wait milliseconds to delay after first trigger
    +   * @param {Object} params to use in throttle.
    +   *
    +   * @returns {function} A function that can be executed as throttled function
    +   *
    +   * @description
    +   * Adapted from debounce function (above)
    +   * Potential keys for Params Object are:
    +   *    trailing (bool) - whether to trigger after throttle time ends if called multiple times
    +   * @example
    +   * <pre>
    +   * var throttledFunc =  gridUtil.throttle(function(){console.log('throttled');}, 500, {trailing: true});
    +   * throttledFunc(); //=> logs throttled
    +   * throttledFunc(); //=> queues attempt to log throttled for ~500ms (since trailing param is truthy)
    +   * throttledFunc(); //=> updates arguments to keep most-recent request, but does not do anything else.
    +   * </pre>
    +   */
    +  s.throttle = function(func, wait, options){
    +    options = options || {};
    +    var lastCall = 0, queued = null, context, args;
    +
    +    function runFunc(endDate){
    +      lastCall = +new Date();
    +      func.apply(context, args);
    +      $timeout(function(){ queued = null; }, 0);
    +    }
    +
    +    return function(){
    +      /* jshint validthis:true */
    +      context = this;
    +      args = arguments;
    +      if (queued === null){
    +        var sinceLast = +new Date() - lastCall;
    +        if (sinceLast > wait){
    +          runFunc();
    +        }
    +        else if (options.trailing){
    +          queued = $timeout(runFunc, wait - sinceLast);
    +        }
    +      }
    +    };
    +  };
    +
    +  s.on = {};
    +  s.off = {};
    +  s._events = {};
    +
    +  s.addOff = function (eventName) {
    +    s.off[eventName] = function (elm, fn) {
    +      var idx = s._events[eventName].indexOf(fn);
    +      if (idx > 0) {
    +        s._events[eventName].removeAt(idx);
    +      }
    +    };
    +  };
    +
    +  var mouseWheeltoBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
    +      nullLowestDeltaTimeout,
    +      lowestDelta;
    +
    +  s.on.mousewheel = function (elm, fn) {
    +    if (!elm || !fn) { return; }
    +
    +    var $elm = angular.element(elm);
    +
    +    // Store the line height and page height for this particular element
    +    $elm.data('mousewheel-line-height', getLineHeight($elm));
    +    $elm.data('mousewheel-page-height', s.elementHeight($elm));
    +    if (!$elm.data('mousewheel-callbacks')) { $elm.data('mousewheel-callbacks', {}); }
    +
    +    var cbs = $elm.data('mousewheel-callbacks');
    +    cbs[fn] = (Function.prototype.bind || bindPolyfill).call(mousewheelHandler, $elm[0], fn);
    +
    +    // Bind all the mousew heel events
    +    for ( var i = mouseWheeltoBind.length; i; ) {
    +      $elm.on(mouseWheeltoBind[--i], cbs[fn]);
    +    }
    +  };
    +  s.off.mousewheel = function (elm, fn) {
    +    var $elm = angular.element(this);
    +
    +    var cbs = $elm.data('mousewheel-callbacks');
    +    var handler = cbs[fn];
    +
    +    if (handler) {
    +      for ( var i = mouseWheeltoBind.length; i; ) {
    +        $elm.off(mouseWheeltoBind[--i], handler);
    +      }
    +    }
    +
    +    delete cbs[fn];
    +
    +    if (Object.keys(cbs).length === 0) {
    +      $elm.removeData('mousewheel-line-height');
    +      $elm.removeData('mousewheel-page-height');
    +      $elm.removeData('mousewheel-callbacks');
    +    }
    +  };
    +
    +  function mousewheelHandler(fn, event) {
    +    var $elm = angular.element(this);
    +
    +    var delta      = 0,
    +        deltaX     = 0,
    +        deltaY     = 0,
    +        absDelta   = 0,
    +        offsetX    = 0,
    +        offsetY    = 0;
    +
    +    // jQuery masks events
    +    if (event.originalEvent) { event = event.originalEvent; }
    +
    +    if ( 'detail'      in event ) { deltaY = event.detail * -1;      }
    +    if ( 'wheelDelta'  in event ) { deltaY = event.wheelDelta;       }
    +    if ( 'wheelDeltaY' in event ) { deltaY = event.wheelDeltaY;      }
    +    if ( 'wheelDeltaX' in event ) { deltaX = event.wheelDeltaX * -1; }
    +
    +    // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
    +    if ( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
    +      deltaX = deltaY * -1;
    +      deltaY = 0;
    +    }
    +
    +    // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
    +    delta = deltaY === 0 ? deltaX : deltaY;
    +
    +    // New school wheel delta (wheel event)
    +    if ( 'deltaY' in event ) {
    +      deltaY = event.deltaY * -1;
    +      delta  = deltaY;
    +    }
    +    if ( 'deltaX' in event ) {
    +      deltaX = event.deltaX;
    +      if ( deltaY === 0 ) { delta  = deltaX * -1; }
    +    }
    +
    +    // No change actually happened, no reason to go any further
    +    if ( deltaY === 0 && deltaX === 0 ) { return; }
    +
    +    // Need to convert lines and pages to pixels if we aren't already in pixels
    +    // There are three delta modes:
    +    //   * deltaMode 0 is by pixels, nothing to do
    +    //   * deltaMode 1 is by lines
    +    //   * deltaMode 2 is by pages
    +    if ( event.deltaMode === 1 ) {
    +        var lineHeight = $elm.data('mousewheel-line-height');
    +        delta  *= lineHeight;
    +        deltaY *= lineHeight;
    +        deltaX *= lineHeight;
    +    }
    +    else if ( event.deltaMode === 2 ) {
    +        var pageHeight = $elm.data('mousewheel-page-height');
    +        delta  *= pageHeight;
    +        deltaY *= pageHeight;
    +        deltaX *= pageHeight;
    +    }
    +
    +    // Store lowest absolute delta to normalize the delta values
    +    absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
    +
    +    if ( !lowestDelta || absDelta < lowestDelta ) {
    +      lowestDelta = absDelta;
    +
    +      // Adjust older deltas if necessary
    +      if ( shouldAdjustOldDeltas(event, absDelta) ) {
    +        lowestDelta /= 40;
    +      }
    +    }
    +
    +    // Get a whole, normalized value for the deltas
    +    delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
    +    deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
    +    deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
    +
    +    event.deltaMode = 0;
    +
    +    // Normalise offsetX and offsetY properties
    +    // if ($elm[0].getBoundingClientRect ) {
    +    //   var boundingRect = $(elm)[0].getBoundingClientRect();
    +    //   offsetX = event.clientX - boundingRect.left;
    +    //   offsetY = event.clientY - boundingRect.top;
    +    // }
    +    
    +    // event.deltaX = deltaX;
    +    // event.deltaY = deltaY;
    +    // event.deltaFactor = lowestDelta;
    +
    +    var newEvent = {
    +      originalEvent: event,
    +      deltaX: deltaX,
    +      deltaY: deltaY,
    +      deltaFactor: lowestDelta,
    +      preventDefault: function () { event.preventDefault(); }
    +    };
    +
    +    // Clearout lowestDelta after sometime to better
    +    // handle multiple device types that give
    +    // a different lowestDelta
    +    // Ex: trackpad = 3 and mouse wheel = 120
    +    if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
    +    nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
    +
    +    fn.call($elm[0], newEvent);
    +  }
    +
    +  function nullLowestDelta() {
    +    lowestDelta = null;
    +  }
    +
    +  function shouldAdjustOldDeltas(orgEvent, absDelta) {
    +    // If this is an older event and the delta is divisable by 120,
    +    // then we are assuming that the browser is treating this as an
    +    // older mouse wheel event and that we should divide the deltas
    +    // by 40 to try and get a more usable deltaFactor.
    +    // Side note, this actually impacts the reported scroll distance
    +    // in older browsers and can cause scrolling to be slower than native.
    +    // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
    +    return orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
    +  }
    +
    +  return s;
    +}]);
    +
    +// Add 'px' to the end of a number string if it doesn't have it already
    +module.filter('px', function() {
    +  return function(str) {
    +    if (str.match(/^[\d\.]+$/)) {
    +      return str + 'px';
    +    }
    +    else {
    +      return str;
    +    }
    +  };
    +});
    +
    +})();
    +
    +(function(){
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('da', {
    +        aggregate:{
    +          label: 'artikler'
    +        },
    +        groupPanel:{
    +          description: 'Grupér rækker udfra en kolonne ved at trække dens overskift hertil.'
    +        },
    +        search:{
    +          placeholder: 'Søg...',
    +          showingItems: 'Viste rækker:',
    +          selectedItems: 'Valgte rækker:',
    +          totalItems: 'Rækker totalt:',
    +          size: 'Side størrelse:',
    +          first: 'Første side',
    +          next: 'Næste side',
    +          previous: 'Forrige side',
    +          last: 'Sidste side'
    +        },
    +        menu:{
    +          text: 'Vælg kolonner:'
    +        },
    +        column: {
    +          hide: 'Skjul kolonne'
    +        },
    +        aggregation: {
    +          count: 'samlede rækker: ',
    +          sum: 'smalede: ',
    +          avg: 'gns: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('de', {
    +        aggregate: {
    +          label: 'Eintrag'
    +        },
    +        groupPanel: {
    +          description: 'Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren.'
    +        },
    +        search: {
    +          placeholder: 'Suche...',
    +          showingItems: 'Zeige Einträge:',
    +          selectedItems: 'Ausgewählte Einträge:',
    +          totalItems: 'Einträge gesamt:',
    +          size: 'Einträge pro Seite:',
    +          first: 'Erste Seite',
    +          next: 'Nächste Seite',
    +          previous: 'Vorherige Seite',
    +          last: 'Letzte Seite'
    +        },
    +        menu: {
    +          text: 'Spalten auswählen:'
    +        },
    +        sort: {
    +          ascending: 'aufsteigend sortieren',
    +          descending: 'absteigend sortieren',
    +          remove: 'Sortierung zurücksetzen'
    +        },
    +        column: {
    +          hide: 'Spalte ausblenden'
    +        },
    +        aggregation: {
    +          count: 'Zeilen insgesamt: ',
    +          sum: 'gesamt: ',
    +          avg: 'Durchschnitt: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +            pinLeft: 'Links anheften',
    +            pinRight: 'Rechts anheften',
    +            unpin: 'Lösen'
    +        },
    +        gridMenu: {
    +          columns: 'Spalten:',
    +          importerTitle: 'Datei importieren',
    +          exporterAllAsCsv: 'Alle Daten als CSV exportieren',
    +          exporterVisibleAsCsv: 'sichtbare Daten als CSV exportieren',
    +          exporterSelectedAsCsv: 'markierte Daten als CSV exportieren',
    +          exporterAllAsPdf: 'Alle Daten als PDF exportieren',
    +          exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
    +          exporterSelectedAsPdf: 'markierte Daten als CSV exportieren'
    +        },
    +        importer: {
    +          noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
    +          noObjects: 'Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?',
    +          invalidCsv: 'Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?',
    +          invalidJson: 'Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?',
    +          jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
    +        },
    +        pagination: {
    +            sizes: 'Einträge pro Seite',
    +            totalItems: 'Einträge'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('en', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Drag a column header here and drop it to group by that column.'
    +        },
    +        search: {
    +          placeholder: 'Search...',
    +          showingItems: 'Showing Items:',
    +          selectedItems: 'Selected Items:',
    +          totalItems: 'Total Items:',
    +          size: 'Page Size:',
    +          first: 'First Page',
    +          next: 'Next Page',
    +          previous: 'Previous Page',
    +          last: 'Last Page'
    +        },
    +        menu: {
    +          text: 'Choose Columns:'
    +        },
    +        sort: {
    +          ascending: 'Sort Ascending',
    +          descending: 'Sort Descending',
    +          remove: 'Remove Sort'
    +        },
    +        column: {
    +          hide: 'Hide Column'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Pin Left',
    +          pinRight: 'Pin Right',
    +          unpin: 'Unpin'
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        },
    +        pagination: {
    +          sizes: 'items per page',
    +          totalItems: 'items'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('es', {
    +        aggregate: {
    +          label: 'Artículos'
    +        },
    +        groupPanel: {
    +          description: 'Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna.'
    +        },
    +        search: {
    +          placeholder: 'Buscar...',
    +          showingItems: 'Artículos Mostrados:',
    +          selectedItems: 'Artículos Seleccionados:',
    +          totalItems: 'Artículos Totales:',
    +          size: 'Tamaño de Página:',
    +          first: 'Primera Página',
    +          next: 'Página Siguiente',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Elegir columnas:'
    +        },
    +        sort: {
    +          ascending: 'Orden Ascendente',
    +          descending: 'Orden Descendente',
    +          remove: 'Sin Ordenar'
    +        },
    +        column: {
    +          hide: 'Ocultar la columna'
    +        },
    +        aggregation: {
    +          count: 'filas totales: ',
    +          sum: 'total: ',
    +          avg: 'media: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fijar a la Izquierda',
    +          pinRight: 'Fijar a la Derecha',
    +          unpin: 'Quitar Fijación'
    +        },
    +        gridMenu: {
    +          columns: 'Columnas:',
    +          importerTitle: 'Importar archivo',
    +          exporterAllAsCsv: 'Exportar todo como csv',
    +          exporterVisibleAsCsv: 'Exportar vista como csv',
    +          exporterSelectedAsCsv: 'Exportar selección como csv',
    +          exporterAllAsPdf: 'Exportar todo como pdf',
    +          exporterVisibleAsPdf: 'Exportar vista como pdf',
    +          exporterSelectedAsPdf: 'Exportar selección como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?',
    +          noObjects: 'No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?',
    +          invalidCsv: 'No fue posible procesar el archivo, ¿es un CSV válido?',
    +          invalidJson: 'No fue posible procesar el archivo, ¿es un Json válido?',
    +          jsonNotArray: 'El archivo json importado debe contener un array, abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fa', {
    +        aggregate: {
    +          label: 'موردها'
    +        },
    +        groupPanel: {
    +          description: 'یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز.'
    +        },
    +        search: {
    +          placeholder: 'جستجو...',
    +          showingItems: 'نمایش موردها:',
    +          selectedItems: 'موردهای انتخاب\u200cشده:',
    +          totalItems: 'همهٔ موردها:',
    +          size: 'اندازهٔ صفحه:',
    +          first: 'صفحهٔ اول',
    +          next: 'صفحهٔ بعد',
    +          previous: 'صفحهٔ قبل',
    +          last: 'آخرین صفحه'
    +        },
    +        menu: {
    +          text: 'انتخاب ستون\u200cها:'
    +        },
    +        column: {
    +          hide: 'ستون پنهان کن'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fi', {
    +        aggregate: {
    +          label: 'rivit'
    +        },
    +        groupPanel: {
    +          description: 'Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan.'
    +        },
    +        search: {
    +          placeholder: 'Hae...',
    +          showingItems: 'Näytetään rivejä:',
    +          selectedItems: 'Valitut rivit:',
    +          totalItems: 'Rivejä yht.:',
    +          size: 'Näytä:',
    +          first: 'Ensimmäinen sivu',
    +          next: 'Seuraava sivu',
    +          previous: 'Edellinen sivu',
    +          last: 'Viimeinen sivu'
    +        },
    +        menu: {
    +          text: 'Valitse sarakkeet:'
    +        },
    +        sort: {
    +          ascending: 'Järjestä nouseva',
    +          descending: 'Järjestä laskeva',
    +          remove: 'Poista järjestys'
    +        },
    +        column: {
    +          hide: 'Piilota sarake'
    +        },
    +        aggregation: {
    +          count: 'Rivejä yht.: ',
    +          sum: 'Summa: ',
    +          avg: 'K.a.: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +         pinLeft: 'Lukitse vasemmalle',
    +          pinRight: 'Lukitse oikealle',
    +          unpin: 'Poista lukitus'
    +        },
    +        gridMenu: {
    +          columns: 'Sarakkeet:',
    +          importerTitle: 'Tuo tiedosto',
    +          exporterAllAsCsv: 'Vie tiedot csv-muodossa',
    +          exporterVisibleAsCsv: 'Vie näkyvä tieto csv-muodossa',
    +          exporterSelectedAsCsv: 'Vie valittu tieto csv-muodossa',
    +          exporterAllAsPdf: 'Vie tiedot pdf-muodossa',
    +          exporterVisibleAsPdf: 'Vie näkyvä tieto pdf-muodossa',
    +          exporterSelectedAsPdf: 'Vie valittu tieto pdf-muodossa'
    +        },
    +        importer: {
    +          noHeaders: 'Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?',
    +          noObjects: 'Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?',
    +          invalidCsv: 'Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?',
    +          invalidJson: 'Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?',
    +          jsonNotArray: 'Tiedosto ei sisältänyt taulukkoa, lopetetaan.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('fr', {
    +        aggregate: {
    +          label: 'articles'
    +        },
    +        groupPanel: {
    +          description: 'Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne.'
    +        },
    +        search: {
    +          placeholder: 'Recherche...',
    +          showingItems: 'Articles Affichage des:',
    +          selectedItems: 'Éléments Articles:',
    +          totalItems: 'Nombre total d\'articles:',
    +          size: 'Taille de page:',
    +          first: 'Première page',
    +          next: 'Page Suivante',
    +          previous: 'Page précédente',
    +          last: 'Dernière page'
    +        },
    +        menu: {
    +          text: 'Choisir des colonnes:'
    +        },
    +        sort: {
    +          ascending: 'Trier par ordre croissant',
    +          descending: 'Trier par ordre décroissant',
    +          remove: 'Enlever le tri'
    +        },
    +        column: {
    +          hide: 'Cacher la colonne'
    +        },
    +        aggregation: {
    +          count: 'total lignes: ',
    +          sum: 'total: ',
    +          avg: 'moy: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Épingler à gauche',
    +          pinRight: 'Épingler à droite',
    +          unpin: 'Détacher'
    +        },
    +        gridMenu: {
    +          columns: 'Colonnes:',
    +          importerTitle: 'Importer un fichier',
    +          exporterAllAsCsv: 'Exporter toutes les données en CSV',
    +          exporterVisibleAsCsv: 'Exporter les données visibles en CSV',
    +          exporterSelectedAsCsv: 'Exporter les données sélectionnées en CSV',
    +          exporterAllAsPdf: 'Exporter toutes les données en PDF',
    +          exporterVisibleAsPdf: 'Exporter les données visibles en PDF',
    +          exporterSelectedAsPdf: 'Exporter les données sélectionnées en PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?',
    +          noObjects: 'Aucun objet trouvé, le fichier possède-t-il des données autres que l\'en-tête ?',
    +          invalidCsv: 'Le fichier n\'a pas pu être traité, le CSV est-il valide ?',
    +          invalidJson: 'Le fichier n\'a pas pu être traité, le JSON est-il valide ?',
    +          jsonNotArray: 'Le fichier JSON importé doit contenir un tableau. Abandon.'
    +        },
    +        pagination: {
    +          sizes: 'articles par page',
    +          totalItems: 'articles'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function ($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function ($delegate) {
    +      $delegate.add('he', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו.'
    +        },
    +        search: {
    +          placeholder: 'חפש...',
    +          showingItems: 'מציג:',
    +          selectedItems: 'סה"כ נבחרו:',
    +          totalItems: 'סה"כ רשומות:',
    +          size: 'תוצאות בדף:',
    +          first: 'דף ראשון',
    +          next: 'דף הבא',
    +          previous: 'דף קודם',
    +          last: 'דף אחרון'
    +        },
    +        menu: {
    +          text: 'בחר עמודות:'
    +        },
    +        sort: {
    +          ascending: 'סדר עולה',
    +          descending: 'סדר יורד',
    +          remove: 'בטל'
    +        },
    +        column: {
    +          hide: 'טור הסתר'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('hy', {
    +        aggregate: {
    +          label: 'տվյալներ'
    +        },
    +        groupPanel: {
    +          description: 'Ըստ սյան խմբավորելու համար քաշեք և գցեք վերնագիրն այստեղ։'
    +        },
    +        search: {
    +          placeholder: 'Փնտրում...',
    +          showingItems: 'Ցուցադրված տվյալներ՝',
    +          selectedItems: 'Ընտրված:',
    +          totalItems: 'Ընդամենը՝',
    +          size: 'Տողերի քանակը էջում՝',
    +          first: 'Առաջին էջ',
    +          next: 'Հաջորդ էջ',
    +          previous: 'Նախորդ էջ',
    +          last: 'Վերջին էջ'
    +        },
    +        menu: {
    +          text: 'Ընտրել սյուները:'
    +        },
    +        sort: {
    +          ascending: 'Աճման կարգով',
    +          descending: 'Նվազման կարգով',
    +          remove: 'Հանել '
    +        },
    +        column: {
    +          hide: 'Թաքցնել սյունը'
    +        },
    +        aggregation: {
    +          count: 'ընդամենը տող՝ ',
    +          sum: 'ընդամենը՝ ',
    +          avg: 'միջին՝ ',
    +          min: 'մին՝ ',
    +          max: 'մաքս՝ '
    +        },
    +        pinning: {
    +          pinLeft: 'Կպցնել ձախ կողմում',
    +          pinRight: 'Կպցնել աջ կողմում',
    +          unpin: 'Արձակել'
    +        },
    +        gridMenu: {
    +          columns: 'Սյուներ:',
    +          importerTitle: 'Ներմուծել ֆայլ',
    +          exporterAllAsCsv: 'Արտահանել ամբողջը CSV',
    +          exporterVisibleAsCsv: 'Արտահանել երևացող տվյալները CSV',
    +          exporterSelectedAsCsv: 'Արտահանել ընտրված տվյալները CSV',
    +          exporterAllAsPdf: 'Արտահանել PDF',
    +          exporterVisibleAsPdf: 'Արտահանել երևացող տվյալները PDF',
    +          exporterSelectedAsPdf: 'Արտահանել ընտրված տվյալները PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Հնարավոր չեղավ որոշել սյան վերնագրերը։ Արդյո՞ք ֆայլը ունի վերնագրեր։',
    +          noObjects: 'Հնարավոր չեղավ կարդալ տվյալները։ Արդյո՞ք ֆայլում կան տվյալներ։',
    +          invalidCsv: 'Հնարավոր չեղավ մշակել ֆայլը։ Արդյո՞ք այն վավեր CSV է։',
    +          invalidJson: 'Հնարավոր չեղավ մշակել ֆայլը։ Արդյո՞ք այն վավեր Json է։',
    +          jsonNotArray: 'Ներմուծված json ֆայլը պետք է պարունակի զանգված, կասեցվում է։'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('it', {
    +        aggregate: {
    +          label: 'elementi'
    +        },
    +        groupPanel: {
    +          description: 'Trascina un\'intestazione all\'interno del gruppo della colonna.'
    +        },
    +        search: {
    +          placeholder: 'Ricerca...',
    +          showingItems: 'Mostra:',
    +          selectedItems: 'Selezionati:',
    +          totalItems: 'Totali:',
    +          size: 'Tot Pagine:',
    +          first: 'Prima',
    +          next: 'Prossima',
    +          previous: 'Precedente',
    +          last: 'Ultima'
    +        },
    +        menu: {
    +          text: 'Scegli le colonne:'
    +        },
    +        sort: {
    +          ascending: 'Asc.',
    +          descending: 'Desc.',
    +          remove: 'Annulla ordinamento'
    +        },
    +        column: {
    +          hide: 'Nascondi'
    +        },
    +        aggregation: {
    +          count: 'righe totali: ',
    +          sum: 'tot: ',
    +          avg: 'media: ',
    +          min: 'minimo: ',
    +          max: 'massimo: '
    +        },
    +        pinning: {
    +         pinLeft: 'Blocca a sx',
    +          pinRight: 'Blocca a dx',
    +          unpin: 'Blocca in alto'
    +        },
    +        gridMenu: {
    +          columns: 'Colonne:',
    +          importerTitle: 'Importa',
    +          exporterAllAsCsv: 'Esporta tutti i dati in CSV',
    +          exporterVisibleAsCsv: 'Esporta i dati visibili in CSV',
    +          exporterSelectedAsCsv: 'Esporta i dati selezionati in CSV',
    +          exporterAllAsPdf: 'Esporta tutti i dati in PDF',
    +          exporterVisibleAsPdf: 'Esporta i dati visibili in PDF',
    +          exporterSelectedAsPdf: 'Esporta i dati selezionati in PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Impossibile reperire i nomi delle colonne, sicuro che siano indicati all\'interno del file?',
    +          noObjects: 'Impossibile reperire gli oggetti, sicuro che siano indicati all\'interno del file?',
    +          invalidCsv: 'Impossibile elaborare il file, sicuro che sia un CSV?',
    +          invalidJson: 'Impossibile elaborare il file, sicuro che sia un JSON valido?',
    +          jsonNotArray: 'Errore! Il file JSON da importare deve contenere un array.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ja', {
    +        aggregate: {
    +          label: '件'
    +        },
    +        groupPanel: {
    +          description: '列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。'
    +        },
    +        search: {
    +          placeholder: '検索...',
    +          showingItems: '絞込み件数:',
    +          selectedItems: '選択件数:',
    +          totalItems: '全件数:',
    +          size: 'ページサイズ: ',
    +          first: '最初のページ',
    +          next: '次のページ',
    +          previous: '前のページ',
    +          last: '最後のページ'
    +        },
    +        menu: {
    +          text: '列選択:'
    +        },
    +        sort: {
    +          ascending: '昇順ソート',
    +          descending: '降順ソート',
    +          remove: 'ソート取消'
    +        },
    +        column: {
    +          hide: '列を隠す'
    +        },
    +        aggregation: {
    +          count: '合計件数: ',
    +          sum: '合計: ',
    +          avg: '平均: ',
    +          min: '最小値: ',
    +          max: '最大値: '
    +        },
    +        pinning: {
    +          pinLeft: '左にピン留め',
    +          pinRight: '右にピン留め',
    +          unpin: 'ピン留め取消'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: 'インポートファイル',
    +          exporterAllAsCsv: '全てのデータをCSV形式でエクスポート',
    +          exporterVisibleAsCsv: '絞込み済みデータをCSV形式でエクスポート',
    +          exporterSelectedAsCsv: '選択しているデータをCSV形式でエクスポート',
    +          exporterAllAsPdf: '全てのデータをPDFでエクスポート',
    +          exporterVisibleAsPdf: '絞込み済みデータをPDFでエクスポート',
    +          exporterSelectedAsPdf: '選択しているデータをPDFでエクスポート'
    +        },
    +        importer: {
    +          noHeaders: '列名が抽出できません。ヘッダーは設定されていますか?',
    +          noObjects: 'データが抽出できません。ファイルにデータは含まれていますか?',
    +          invalidCsv: '処理を行うことができません。ファイルは有効なCSVファイルですか?',
    +          invalidJson: '処理を行うことができません。ファイルは有効なJSONファイルですか?',
    +          jsonNotArray: 'JSONファイルは配列を含んでいる必要があります。処理を中断します。'
    +        },
    +        pagination: {
    +          sizes: '件 / ページ',
    +          totalItems: '件'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ko', {
    +        aggregate: {
    +          label: '아이템'
    +        },
    +        groupPanel: {
    +          description: '컬럼으로 그룹핑하기 위해서는 컬럼 헤더를 끌어 떨어뜨려 주세요.'
    +        },
    +        search: {
    +          placeholder: '검색...',
    +          showingItems: '항목 보여주기:',
    +          selectedItems: '선택 항목:',
    +          totalItems: '전체 항목:',
    +          size: '페이지 크기:',
    +          first: '첫번째 페이지',
    +          next: '다음 페이지',
    +          previous: '이전 페이지',
    +          last: '마지막 페이지'
    +        },
    +        menu: {
    +          text: '컬럼을 선택하세요:'
    +        },
    +        sort: {
    +          ascending: '오름차순 정렬',
    +          descending: '내림차순 정렬',
    +          remove: '소팅 제거'
    +        },
    +        column: {
    +          hide: '컬럼 제거'
    +        },
    +        aggregation: {
    +          count: '전체 갯수: ',
    +          sum: '전체: ',
    +          avg: '평균: ',
    +          min: '최소: ',
    +          max: '최대: '
    +        },
    +        pinning: {
    +         pinLeft: '왼쪽 핀',
    +          pinRight: '오른쪽 핀',
    +          unpin: '핀 제거'
    +        },
    +        gridMenu: {
    +          columns: '컬럼:',
    +          importerTitle: '파일 가져오기',
    +          exporterAllAsCsv: 'csv로 모든 데이터 내보내기',
    +          exporterVisibleAsCsv: 'csv로 보이는 데이터 내보내기',
    +          exporterSelectedAsCsv: 'csv로 선택된 데이터 내보내기',
    +          exporterAllAsPdf: 'pdf로 모든 데이터 내보내기',
    +          exporterVisibleAsPdf: 'pdf로 보이는 데이터 내보내기',
    +          exporterSelectedAsPdf: 'pdf로 선택 데이터 내보내기'
    +        },
    +        importer: {
    +          noHeaders: '컬럼명이 지정되어 있지 않습니다. 파일에 헤더가 명시되어 있는지 확인해 주세요.',
    +          noObjects: '데이터가 지정되어 있지 않습니다. 데이터가 파일에 있는지 확인해 주세요.',
    +          invalidCsv: '파일을 처리할 수 없습니다. 올바른 csv인지 확인해 주세요.',
    +          invalidJson: '파일을 처리할 수 없습니다. 올바른 json인지 확인해 주세요.',
    +          jsonNotArray: 'json 파일은 배열을 포함해야 합니다.'
    +        },
    +        pagination: {
    +          sizes: '페이지당 항목',
    +          totalItems: '전체 항목'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('nl', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
    +        },
    +        search: {
    +          placeholder: 'Zoeken...',
    +          showingItems: 'Getoonde items:',
    +          selectedItems: 'Geselecteerde items:',
    +          totalItems: 'Totaal aantal items:',
    +          size: 'Items per pagina:',
    +          first: 'Eerste pagina',
    +          next: 'Volgende pagina',
    +          previous: 'Vorige pagina',
    +          last: 'Laatste pagina'
    +        },
    +        menu: {
    +          text: 'Kies kolommen:'
    +        },
    +        sort: {
    +          ascending: 'Sorteer oplopend',
    +          descending: 'Sorteer aflopend',
    +          remove: 'Verwijder sortering'
    +        },
    +        column: {
    +          hide: 'Verberg kolom'
    +        },
    +        aggregation: {
    +          count: 'Aantal rijen: ',
    +          sum: 'Som: ',
    +          avg: 'Gemiddelde: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Zet links vast',
    +          pinRight: 'Zet rechts vast',
    +          unpin: 'Maak los'
    +        },
    +        gridMenu: {
    +          columns: 'Kolommen:',
    +          importerTitle: 'Importeer bestand',
    +          exporterAllAsCsv: 'Exporteer alle data als csv',
    +          exporterVisibleAsCsv: 'Exporteer zichtbare data als csv',
    +          exporterSelectedAsCsv: 'Exporteer geselecteerde data als csv',
    +          exporterAllAsPdf: 'Exporteer alle data als pdf',
    +          exporterVisibleAsPdf: 'Exporteer zichtbare data als pdf',
    +          exporterSelectedAsPdf: 'Exporteer geselecteerde data als pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?',
    +          noObjects: 'Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?',
    +          invalidCsv: 'Het bestand kan niet verwerkt worden. Is het een valide csv bestand?',
    +          invalidJson: 'Het bestand kan niet verwerkt worden. Is het valide json?',
    +          jsonNotArray: 'Het json bestand moet een array bevatten. De actie wordt geannuleerd.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('pt-br', {
    +        aggregate: {
    +          label: 'itens'
    +        },
    +        groupPanel: {
    +          description: 'Arraste e solte uma coluna aqui para agrupar por essa coluna'
    +        },
    +        search: {
    +          placeholder: 'Procurar...',
    +          showingItems: 'Mostrando os Itens:',
    +          selectedItems: 'Items Selecionados:',
    +          totalItems: 'Total de Itens:',
    +          size: 'Tamanho da Página:',
    +          first: 'Primeira Página',
    +          next: 'Próxima Página',
    +          previous: 'Página Anterior',
    +          last: 'Última Página'
    +        },
    +        menu: {
    +          text: 'Selecione as colunas:'
    +        },
    +        sort: {
    +          ascending: 'Ordenar Ascendente',
    +          descending: 'Ordenar Descendente',
    +          remove: 'Remover Ordenação'
    +        },
    +        column: {
    +          hide: 'Esconder coluna'
    +        },
    +        aggregation: {
    +          count: 'total de linhas: ',
    +          sum: 'total: ',
    +          avg: 'med: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fixar Esquerda',
    +          pinRight: 'Fixar Direita',
    +          unpin: 'Desprender'
    +        },
    +        gridMenu: {
    +          columns: 'Colunas:',
    +          exporterAllAsCsv: 'Exportar todos os dados como csv',
    +          exporterVisibleAsCsv: 'Exportar dados visíveis como csv',
    +          exporterSelectedAsCsv: 'Exportar dados selecionados como csv',
    +          exporterAllAsPdf: 'Exportar todos os dados como pdf',
    +          exporterVisibleAsPdf: 'Exportar dados visíveis como pdf',
    +          exporterSelectedAsPdf: 'Exportar dados selecionados como pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?',
    +          noObjects: 'Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?',
    +          invalidCsv: 'Arquivo não pode ser processado. É um CSV válido?',
    +          invalidJson: 'Arquivo não pode ser processado. É um Json válido?',
    +          jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +}]);
    +})();
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('ru', {
    +        aggregate: {
    +          label: 'элементы'
    +        },
    +        groupPanel: {
    +          description: 'Для группировки по столбцу перетащите сюда его название.'
    +        },
    +        search: {
    +          placeholder: 'Поиск...',
    +          showingItems: 'Показать элементы:',
    +          selectedItems: 'Выбранные элементы:',
    +          totalItems: 'Всего элементов:',
    +          size: 'Размер страницы:',
    +          first: 'Первая страница',
    +          next: 'Следующая страница',
    +          previous: 'Предыдущая страница',
    +          last: 'Последняя страница'
    +        },
    +        menu: {
    +          text: 'Выбрать столбцы:'
    +        },
    +        sort: {
    +          ascending: 'По возрастанию',
    +          descending: 'По убыванию',
    +          remove: 'Убрать сортировку'
    +        },
    +        column: {
    +          hide: 'спрятать столбец'
    +        },
    +        aggregation: {
    +          count: 'всего строк: ',
    +          sum: 'итого: ',
    +          avg: 'среднее: ',
    +          min: 'мин: ',
    +          max: 'макс: '
    +        },
    +        gridMenu: {
    +          columns: 'Столбцы:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Экспортировать всё в CSV',
    +          exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
    +          exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
    +          exporterAllAsPdf: 'Экспортировать всё в PDF',
    +          exporterVisibleAsPdf: 'Экспортировать видимые данные в PDF',
    +          exporterSelectedAsPdf: 'Экспортировать выбранные данные в PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sk', {
    +        aggregate: {
    +          label: 'items'
    +        },
    +        groupPanel: {
    +          description: 'Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca.'
    +        },
    +        search: {
    +          placeholder: 'Hľadaj...',
    +          showingItems: 'Zobrazujem položky:',
    +          selectedItems: 'Vybraté položky:',
    +          totalItems: 'Počet položiek:',
    +          size: 'Počet:',
    +          first: 'Prvá strana',
    +          next: 'Ďalšia strana',
    +          previous: 'Predchádzajúca strana',
    +          last: 'Posledná strana'
    +        },
    +        menu: {
    +          text: 'Vyberte stĺpce:'
    +        },
    +        sort: {
    +          ascending: 'Zotriediť vzostupne',
    +          descending: 'Zotriediť zostupne',
    +          remove: 'Vymazať triedenie'
    +        },
    +        aggregation: {
    +          count: 'total rows: ',
    +          sum: 'total: ',
    +          avg: 'avg: ',
    +          min: 'min: ',
    +          max: 'max: '
    +        },
    +        gridMenu: {
    +          columns: 'Columns:',
    +          importerTitle: 'Import file',
    +          exporterAllAsCsv: 'Export all data as csv',
    +          exporterVisibleAsCsv: 'Export visible data as csv',
    +          exporterSelectedAsCsv: 'Export selected data as csv',
    +          exporterAllAsPdf: 'Export all data as pdf',
    +          exporterVisibleAsPdf: 'Export visible data as pdf',
    +          exporterSelectedAsPdf: 'Export selected data as pdf'
    +        },
    +        importer: {
    +          noHeaders: 'Column names were unable to be derived, does the file have a header?',
    +          noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
    +          invalidCsv: 'File was unable to be processed, is it valid CSV?',
    +          invalidJson: 'File was unable to be processed, is it valid Json?',
    +          jsonNotArray: 'Imported json file must contain an array, aborting.'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function () {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('sv', {
    +        aggregate: {
    +          label: 'Artiklar'
    +        },
    +        groupPanel: {
    +          description: 'Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen.'
    +        },
    +        search: {
    +          placeholder: 'Sök...',
    +          showingItems: 'Visar artiklar:',
    +          selectedItems: 'Valda artiklar:',
    +          totalItems: 'Antal artiklar:',
    +          size: 'Sidstorlek:',
    +          first: 'Första sidan',
    +          next: 'Nästa sida',
    +          previous: 'Föregående sida',
    +          last: 'Sista sidan'
    +        },
    +        menu: {
    +          text: 'Välj kolumner:'
    +        },
    +        sort: {
    +          ascending: 'Sortera stigande',
    +          descending: 'Sortera fallande',
    +          remove: 'Inaktivera sortering'
    +        },
    +        column: {
    +          hide: 'Göm kolumn'
    +        },
    +        aggregation: {
    +          count: 'Antal rader: ',
    +          sum: 'Summa: ',
    +          avg: 'Genomsnitt: ',
    +          min: 'Min: ',
    +          max: 'Max: '
    +        },
    +        pinning: {
    +          pinLeft: 'Fäst vänster',
    +          pinRight: 'Fäst höger',
    +          unpin: 'Lösgör'
    +        },
    +        gridMenu: {
    +          columns: 'Kolumner:',
    +          importerTitle: 'Importera fil',
    +          exporterAllAsCsv: 'Exportera all data som CSV',
    +          exporterVisibleAsCsv: 'Exportera synlig data som CSV',
    +          exporterSelectedAsCsv: 'Exportera markerad data som CSV',
    +          exporterAllAsPdf: 'Exportera all data som PDF',
    +          exporterVisibleAsPdf: 'Exportera synlig data som PDF',
    +          exporterSelectedAsPdf: 'Exportera markerad data som PDF'
    +        },
    +        importer: {
    +          noHeaders: 'Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?',
    +          noObjects: 'Objekt kunde inte härledas. Har filen data undantaget sidhuvud?',
    +          invalidCsv: 'Filen kunde inte behandlas, är den en giltig CSV?',
    +          invalidJson: 'Filen kunde inte behandlas, är den en giltig JSON?',
    +          jsonNotArray: 'Importerad JSON-fil måste innehålla ett fält. Import avbruten.'
    +        },
    +        pagination: {
    +          sizes: 'Artiklar per sida',
    +          totalItems: 'Artiklar'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +/**
    + * @ngdoc overview
    + * @name ui.grid.i18n
    + * @description
    + *
    + *  # ui.grid.i18n
    + * This module provides i18n functions to ui.grid and any application that wants to use it
    +
    + *
    + * <div doc-module-components="ui.grid.i18n"></div>
    + */
    +
    +(function () {
    +  var DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'];
    +  var FILTER_ALIASES = ['t', 'uiTranslate'];
    +
    +  var module = angular.module('ui.grid.i18n');
    +
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.i18n.constant:i18nConstants
    +   *
    +   *  @description constants available in i18n module
    +   */
    +  module.constant('i18nConstants', {
    +    MISSING: '[MISSING]',
    +    UPDATE_EVENT: '$uiI18n',
    +
    +    LOCALE_DIRECTIVE_ALIAS: 'uiI18n',
    +    // default to english
    +    DEFAULT_LANG: 'en'
    +  });
    +
    +//    module.config(['$provide', function($provide) {
    +//        $provide.decorator('i18nService', ['$delegate', function($delegate) {}])}]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.i18n.service:i18nService
    +   *
    +   *  @description Services for i18n
    +   */
    +  module.service('i18nService', ['$log', 'i18nConstants', '$rootScope',
    +    function ($log, i18nConstants, $rootScope) {
    +
    +      var langCache = {
    +        _langs: {},
    +        current: null,
    +        get: function (lang) {
    +          return this._langs[lang.toLowerCase()];
    +        },
    +        add: function (lang, strings) {
    +          var lower = lang.toLowerCase();
    +          if (!this._langs[lower]) {
    +            this._langs[lower] = {};
    +          }
    +          angular.extend(this._langs[lower], strings);
    +        },
    +        getAllLangs: function () {
    +          var langs = [];
    +          if (!this._langs) {
    +            return langs;
    +          }
    +
    +          for (var key in this._langs) {
    +            langs.push(key);
    +          }
    +
    +          return langs;
    +        },
    +        setCurrent: function (lang) {
    +          this.current = lang.toLowerCase();
    +        },
    +        getCurrentLang: function () {
    +          return this.current;
    +        }
    +      };
    +
    +      var service = {
    +
    +        /**
    +         * @ngdoc service
    +         * @name add
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  Adds the languages and strings to the cache. Decorate this service to
    +         * add more translation strings
    +         * @param {string} lang language to add
    +         * @param {object} stringMaps of strings to add grouped by property names
    +         * @example
    +         * <pre>
    +         *      i18nService.add('en', {
    +         *         aggregate: {
    +         *                 label1: 'items',
    +         *                 label2: 'some more items'
    +         *                 }
    +         *         },
    +         *         groupPanel: {
    +         *              description: 'Drag a column header here and drop it to group by that column.'
    +         *           }
    +         *      }
    +         * </pre>
    +         */
    +        add: function (langs, stringMaps) {
    +          if (typeof(langs) === 'object') {
    +            angular.forEach(langs, function (lang) {
    +              if (lang) {
    +                langCache.add(lang, stringMaps);
    +              }
    +            });
    +          } else {
    +            langCache.add(langs, stringMaps);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getAllLangs
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @returns {array} string
    +         */
    +        getAllLangs: function () {
    +          return langCache.getAllLangs();
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name get
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  return all currently loaded languages
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation string maps for the language
    +         */
    +        get: function (lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          return langCache.get(language);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getSafeText
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description  returns the text specified in the path or a Missing text if text is not found
    +         * @param {string} path property path to use for retrieving text from string map
    +         * @param {string} lang to return.  If not specified, returns current language
    +         * @returns {object} the translation for the path
    +         * @example
    +         * <pre>
    +         * i18nService.getSafeText('sort.ascending')
    +         * </pre>
    +         */
    +        getSafeText: function (path, lang) {
    +          var language = lang ? lang : service.getCurrentLang();
    +          var trans = langCache.get(language);
    +
    +          if (!trans) {
    +            return i18nConstants.MISSING;
    +          }
    +
    +          var paths = path.split('.');
    +          var current = trans;
    +
    +          for (var i = 0; i < paths.length; ++i) {
    +            if (current[paths[i]] === undefined || current[paths[i]] === null) {
    +              return i18nConstants.MISSING;
    +            } else {
    +              current = current[paths[i]];
    +            }
    +          }
    +
    +          return current;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name setCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description sets the current language to use in the application
    +         * $broadcasts the Update_Event on the $rootScope
    +         * @param {string} lang to set
    +         * @example
    +         * <pre>
    +         * i18nService.setCurrentLang('fr');
    +         * </pre>
    +         */
    +
    +        setCurrentLang: function (lang) {
    +          if (lang) {
    +            langCache.setCurrent(lang);
    +            $rootScope.$broadcast(i18nConstants.UPDATE_EVENT);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getCurrentLang
    +         * @methodOf ui.grid.i18n.service:i18nService
    +         * @description returns the current language used in the application
    +         */
    +        getCurrentLang: function () {
    +          var lang = langCache.getCurrentLang();
    +          if (!lang) {
    +            lang = i18nConstants.DEFAULT_LANG;
    +            langCache.setCurrent(lang);
    +          }
    +          return lang;
    +        }
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  var localeDirective = function (i18nService, i18nConstants) {
    +    return {
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias = i18nConstants.LOCALE_DIRECTIVE_ALIAS;
    +            // check for watchable property
    +            var lang = $scope.$eval($attrs[alias]);
    +            if (lang) {
    +              $scope.$watch($attrs[alias], function () {
    +                i18nService.setCurrentLang(lang);
    +              });
    +            } else if ($attrs.$$observers) {
    +              $attrs.$observe(alias, function () {
    +                i18nService.setCurrentLang($attrs[alias] || i18nConstants.DEFAULT_LANG);
    +              });
    +            }
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  module.directive('uiI18n', ['i18nService', 'i18nConstants', localeDirective]);
    +
    +  // directive syntax
    +  var uitDirective = function ($parse, i18nService, i18nConstants) {
    +    return {
    +      restrict: 'EA',
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs) {
    +            var alias1 = DIRECTIVE_ALIASES[0],
    +              alias2 = DIRECTIVE_ALIASES[1];
    +            var token = $attrs[alias1] || $attrs[alias2] || $elm.html();
    +            var missing = i18nConstants.MISSING + token;
    +            var observer;
    +            if ($attrs.$$observers) {
    +              var prop = $attrs[alias1] ? alias1 : alias2;
    +              observer = $attrs.$observe(prop, function (result) {
    +                if (result) {
    +                  $elm.html($parse(result)(i18nService.getCurrentLang()) || missing);
    +                }
    +              });
    +            }
    +            var getter = $parse(token);
    +            var listener = $scope.$on(i18nConstants.UPDATE_EVENT, function (evt) {
    +              if (observer) {
    +                observer($attrs[alias1] || $attrs[alias2]);
    +              } else {
    +                // set text based on i18n current language
    +                $elm.html(getter(i18nService.get()) || missing);
    +              }
    +            });
    +            $scope.$on('$destroy', listener);
    +
    +            $elm.html(getter(i18nService.get()) || missing);
    +          }
    +        };
    +      }
    +    };
    +  };
    +
    +  angular.forEach( DIRECTIVE_ALIASES, function ( alias ) {
    +    module.directive( alias, ['$parse', 'i18nService', 'i18nConstants', uitDirective] );
    +  } );
    +
    +  // optional filter syntax
    +  var uitFilter = function ($parse, i18nService, i18nConstants) {
    +    return function (data) {
    +      var getter = $parse(data);
    +      // set text based on i18n current language
    +      return getter(i18nService.get()) || i18nConstants.MISSING + data;
    +    };
    +  };
    +
    +  angular.forEach( FILTER_ALIASES, function ( alias ) {
    +    module.filter( alias, ['$parse', 'i18nService', 'i18nConstants', uitFilter] );
    +  } );
    +
    +
    +})();
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-cn', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表头到此处进行分组'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已显示行数:',
    +          selectedItems: '已选择行数:',
    +          totalItems: '总行数:',
    +          size: '每页显示行数:',
    +          first: '首页',
    +          next: '下一页',
    +          previous: '上一页',
    +          last: '末页'
    +        },
    +        menu: {
    +          text: '选择列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隐藏列'
    +        },
    +        aggregation: {
    +          count: '计数:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左侧固定',
    +          pinRight: '右侧固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '导入文件',
    +          exporterAllAsCsv: '导出全部数据到CSV',
    +          exporterVisibleAsCsv: '导出可见数据到CSV',
    +          exporterSelectedAsCsv: '导出已选数据到CSV',
    +          exporterAllAsPdf: '导出全部数据到PDF',
    +          exporterVisibleAsPdf: '导出可见数据到PDF',
    +          exporterSelectedAsPdf: '导出已选数据到PDF'
    +        },
    +        importer: {
    +          noHeaders: '无法获取列名,确定文件包含表头?',
    +          noObjects: '无法获取数据,确定文件包含数据?',
    +          invalidCsv: '无法处理文件,确定是合法的CSV文件?',
    +          invalidJson: '无法处理文件,确定是合法的JSON文件?',
    +          jsonNotArray: '导入的文件不是JSON数组!'
    +        },
    +        pagination: {
    +          sizes: '行每页',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('i18nService', ['$delegate', function($delegate) {
    +      $delegate.add('zh-tw', {
    +        aggregate: {
    +          label: '行'
    +        },
    +        groupPanel: {
    +          description: '拖曳表頭到此處進行分組'
    +        },
    +        search: {
    +          placeholder: '查找',
    +          showingItems: '已顯示行數:',
    +          selectedItems: '已選擇行數:',
    +          totalItems: '總行數:',
    +          size: '每頁顯示行數:',
    +          first: '首頁',
    +          next: '下壹頁',
    +          previous: '上壹頁',
    +          last: '末頁'
    +        },
    +        menu: {
    +          text: '選擇列:'
    +        },
    +        sort: {
    +          ascending: '升序',
    +          descending: '降序',
    +          remove: '取消排序'
    +        },
    +        column: {
    +          hide: '隱藏列'
    +        },
    +        aggregation: {
    +          count: '計數:',
    +          sum: '求和:',
    +          avg: '均值:',
    +          min: '最小值:',
    +          max: '最大值:'
    +        },
    +        pinning: {
    +          pinLeft: '左側固定',
    +          pinRight: '右側固定',
    +          unpin: '取消固定'
    +        },
    +        gridMenu: {
    +          columns: '列:',
    +          importerTitle: '導入文件',
    +          exporterAllAsCsv: '導出全部數據到CSV',
    +          exporterVisibleAsCsv: '導出可見數據到CSV',
    +          exporterSelectedAsCsv: '導出已選數據到CSV',
    +          exporterAllAsPdf: '導出全部數據到PDF',
    +          exporterVisibleAsPdf: '導出可見數據到PDF',
    +          exporterSelectedAsPdf: '導出已選數據到PDF'
    +        },
    +        importer: {
    +          noHeaders: '無法獲取列名,確定文件包含表頭?',
    +          noObjects: '無法獲取數據,確定文件包含數據?',
    +          invalidCsv: '無法處理文件,確定是合法的CSV文件?',
    +          invalidJson: '無法處理文件,確定是合法的JSON文件?',
    +          jsonNotArray: '導入的文件不是JSON數組!'
    +        },
    +        pagination: {
    +          sizes: '行每頁',
    +          totalItems: '行'
    +        }
    +      });
    +      return $delegate;
    +    }]);
    +  }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.autoResize
    +   *
    +   *  @description 
    +   *
    +   *  #ui.grid.autoResize
    +   *  This module provides auto-resizing functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.autoResize', ['ui.grid']);
    +  
    +
    +  module.directive('uiGridAutoResize', ['$timeout', 'gridUtil', function ($timeout, gridUtil) {
    +    return {
    +      require: 'uiGrid',
    +      scope: false,
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var prevGridWidth, prevGridHeight;
    +
    +        function getDimensions() {
    +          prevGridHeight = gridUtil.elementHeight($elm);
    +          prevGridWidth = gridUtil.elementWidth($elm);
    +        }
    +
    +        // Initialize the dimensions
    +        getDimensions();
    +
    +        var resizeTimeoutId;
    +        function startTimeout() {
    +          clearTimeout(resizeTimeoutId);
    +
    +          resizeTimeoutId = setTimeout(function () {
    +            var newGridHeight = gridUtil.elementHeight($elm);
    +            var newGridWidth = gridUtil.elementWidth($elm);
    +
    +            if (newGridHeight !== prevGridHeight || newGridWidth !== prevGridWidth) {
    +              uiGridCtrl.grid.gridHeight = newGridHeight;
    +              uiGridCtrl.grid.gridWidth = newGridWidth;
    +
    +              $scope.$apply(function () {
    +                uiGridCtrl.grid.refresh()
    +                  .then(function () {
    +                    getDimensions();
    +
    +                    startTimeout();
    +                  });
    +              });
    +            }
    +            else {
    +              startTimeout();
    +            }
    +          }, 250);
    +        }
    +
    +        startTimeout();
    +
    +        $scope.$on('$destroy', function() {
    +          clearTimeout(resizeTimeoutId);
    +        });
    +      }
    +    };
    +  }]);
    +})();
    +(function () {
    +  'use strict';
    +  var module = angular.module('ui.grid.cellNav', ['ui.grid']);
    +
    +  function RowCol(row, col) {
    +    this.row = row;
    +    this.col = col;
    +  }
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.cellNav.constant:uiGridCellNavConstants
    +   *
    +   *  @description constants available in cellNav
    +   */
    +  module.constant('uiGridCellNavConstants', {
    +    FEATURE_NAME: 'gridCellNav',
    +    CELL_NAV_EVENT: 'cellNav',
    +    direction: {LEFT: 0, RIGHT: 1, UP: 2, DOWN: 3, PG_UP: 4, PG_DOWN: 5},
    +    EVENT_TYPE: {
    +      KEYDOWN: 0,
    +      CLICK: 1,
    +      CLEAR: 2
    +    }
    +  });
    +
    +
    +  module.factory('uiGridCellNavFactory', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q) {
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.object:CellNav
    +       *  @description returns a CellNav prototype function
    +       *  @param {object} rowContainer container for rows
    +       *  @param {object} colContainer parent column container
    +       *  @param {object} leftColContainer column container to the left of parent
    +       *  @param {object} rightColContainer column container to the right of parent
    +       */
    +      var UiGridCellNav = function UiGridCellNav(rowContainer, colContainer, leftColContainer, rightColContainer) {
    +        this.rows = rowContainer.visibleRowCache;
    +        this.columns = colContainer.visibleColumnCache;
    +        this.leftColumns = leftColContainer ? leftColContainer.visibleColumnCache : [];
    +        this.rightColumns = rightColContainer ? rightColContainer.visibleColumnCache : [];
    +        this.bodyContainer = rowContainer;
    +      };
    +
    +      /** returns focusable columns of all containers */
    +      UiGridCellNav.prototype.getFocusableCols = function () {
    +        var allColumns = this.leftColumns.concat(this.columns, this.rightColumns);
    +
    +        return allColumns.filter(function (col) {
    +          return col.colDef.allowCellFocus;
    +        });
    +      };
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.cellNav.api:GridRow
    +       *
    +       *  @description GridRow settings for cellNav feature, these are available to be
    +       *  set only internally (for example, by other features)
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name allowCellFocus
    +       *  @propertyOf  ui.grid.cellNav.api:GridRow
    +       *  @description Enable focus on a cell within this row.  If set to false then no cells
    +       *  in this row can be focused - group header rows as an example would set this to false.
    +       *  <br/>Defaults to true
    +       */
    +      /** returns focusable rows */
    +      UiGridCellNav.prototype.getFocusableRows = function () {
    +        return this.rows.filter(function(row) {
    +          return row.allowCellFocus !== false;
    +        });
    +      };
    +
    +      UiGridCellNav.prototype.getNextRowCol = function (direction, curRow, curCol) {
    +        switch (direction) {
    +          case uiGridCellNavConstants.direction.LEFT:
    +            return this.getRowColLeft(curRow, curCol);
    +          case uiGridCellNavConstants.direction.RIGHT:
    +            return this.getRowColRight(curRow, curCol);
    +          case uiGridCellNavConstants.direction.UP:
    +            return this.getRowColUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.DOWN:
    +            return this.getRowColDown(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_UP:
    +            return this.getRowColPageUp(curRow, curCol);
    +          case uiGridCellNavConstants.direction.PG_DOWN:
    +            return this.getRowColPageDown(curRow, curCol);
    +        }
    +
    +      };
    +
    +      UiGridCellNav.prototype.getRowColLeft = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 1
    +        if (curColIndex === -1) {
    +          curColIndex = 1;
    +        }
    +
    +        var nextColIndex = curColIndex === 0 ? focusableCols.length - 1 : curColIndex - 1;
    +
    +        //get column to left
    +        if (nextColIndex > curColIndex) {
    +          // On the first row
    +          // if (curRowIndex === 0 && curColIndex === 0) {
    +          //   return null;
    +          // }
    +          if (curRowIndex === 0) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //up one row and far right column
    +            return new RowCol(focusableRows[curRowIndex - 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColRight = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +        var nextColIndex = curColIndex === focusableCols.length - 1 ? 0 : curColIndex + 1;
    +
    +        if (nextColIndex < curColIndex) {
    +          if (curRowIndex === focusableRows.length - 1) {
    +            return new RowCol(curRow, focusableCols[nextColIndex]); //return same row
    +          }
    +          else {
    +            //down one row and far left column
    +            return new RowCol(focusableRows[curRowIndex + 1], focusableCols[nextColIndex]);
    +          }
    +        }
    +        else {
    +          return new RowCol(curRow, focusableCols[nextColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === focusableRows.length - 1) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //down one row
    +          return new RowCol(focusableRows[curRowIndex + 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageDown = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex >= focusableRows.length - pageSize) {
    +          return new RowCol(focusableRows[focusableRows.length - 1], focusableCols[curColIndex]); //return last row
    +        }
    +        else {
    +          //down one page
    +          return new RowCol(focusableRows[curRowIndex + pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        if (curRowIndex === 0) {
    +          return new RowCol(curRow, focusableCols[curColIndex]); //return same row
    +        }
    +        else {
    +          //up one row
    +          return new RowCol(focusableRows[curRowIndex - 1], focusableCols[curColIndex]);
    +        }
    +      };
    +
    +      UiGridCellNav.prototype.getRowColPageUp = function (curRow, curCol) {
    +        var focusableCols = this.getFocusableCols();
    +        var focusableRows = this.getFocusableRows();
    +        var curColIndex = focusableCols.indexOf(curCol);
    +        var curRowIndex = focusableRows.indexOf(curRow);
    +
    +        //could not find column in focusable Columns so set it to 0
    +        if (curColIndex === -1) {
    +          curColIndex = 0;
    +        }
    +
    +        var pageSize = this.bodyContainer.minRowsToRender();
    +        if (curRowIndex - pageSize < 0) {
    +          return new RowCol(focusableRows[0], focusableCols[curColIndex]); //return first row
    +        }
    +        else {
    +          //up one page
    +          return new RowCol(focusableRows[curRowIndex - pageSize], focusableCols[curColIndex]);
    +        }
    +      };
    +      return UiGridCellNav;
    +    }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.cellNav.service:uiGridCellNavService
    +   *
    +   *  @description Services for cell navigation features. If you don't like the key maps we use,
    +   *  or the direction cells navigation, override with a service decorator (see angular docs)
    +   */
    +  module.service('uiGridCellNavService', ['gridUtil', 'uiGridConstants', 'uiGridCellNavConstants', '$q', 'uiGridCellNavFactory', 'ScrollEvent',
    +    function (gridUtil, uiGridConstants, uiGridCellNavConstants, $q, UiGridCellNav, ScrollEvent) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +          grid.registerColumnBuilder(service.cellNavColumnBuilder);
    +
    +          //create variables for state
    +          grid.cellNav = {};
    +          grid.cellNav.lastRowCol = null;
    +          grid.cellNav.focusedCells = [];
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:PublicApi
    +           *
    +           *  @description Public Api for cellNav feature
    +           */
    +          var publicApi = {
    +            events: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc event
    +                 * @name navigate
    +                 * @eventOf  ui.grid.cellNav.api:PublicApi
    +                 * @description raised when the active cell is changed
    +                 * <pre>
    +                 *      gridApi.cellNav.on.navigate(scope,function(newRowcol, oldRowCol){})
    +                 * </pre>
    +                 * @param {object} newRowCol new position
    +                 * @param {object} oldRowCol old position
    +                 */
    +                navigate: function (newRowCol, oldRowCol) {
    +                }
    +              }
    +            },
    +            methods: {
    +              cellNav: {
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollTo
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +                 * @param {object} colDef to make visible
    +                 */
    +                scrollTo: function (rowEntity, colDef) {
    +                  service.scrollTo(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column into view, and sets focus
    +                 * to that cell
    +                 * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus
    +                 * @param {object} colDef to make visible and set focus
    +                 */
    +                scrollToFocus: function (rowEntity, colDef) {
    +                  service.scrollToFocus(grid, rowEntity, colDef);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name scrollToFocus
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description brings the specified row and column fully into view if it isn't already
    +                 * @param {GridRow} row grid row that we should make fully visible
    +                 * @param {GridCol} col grid col to make fully visible
    +                 */
    +                scrollToIfNecessary: function (row, col) {
    +                  service.scrollToIfNecessary(grid, row, col);
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getFocusedCell
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the current (or last if Grid does not have focus) focused row and column
    +                 * <br> value is null if no selection has occurred
    +                 */
    +                getFocusedCell: function () {
    +                  return grid.cellNav.lastRowCol;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name getCurrentSelection
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns an array containing the current selection
    +                 * <br> array is empty if no selection has occurred
    +                 */
    +                getCurrentSelection: function () {
    +                  return grid.cellNav.focusedCells;
    +                },
    +
    +                /**
    +                 * @ngdoc function
    +                 * @name rowColSelectIndex
    +                 * @methodOf  ui.grid.cellNav.api:PublicApi
    +                 * @description returns the index in the order in which the RowCol was selected, returns -1 if the RowCol
    +                 * isn't selected
    +                 * @param {object} rowCol the rowCol to evaluate
    +                 */
    +                rowColSelectIndex: function (rowCol) {
    +                  //return gridUtil.arrayContainsObjectWithProperty(grid.cellNav.focusedCells, 'col.uid', rowCol.col.uid) &&
    +                  var index = -1;
    +                  for (var i = 0; i < grid.cellNav.focusedCells.length; i++) {
    +                    if (grid.cellNav.focusedCells[i].col.uid === rowCol.col.uid &&
    +                      grid.cellNav.focusedCells[i].row.uid === rowCol.row.uid) {
    +                      index = i;
    +                      break;
    +                    }
    +                  }
    +                  return index;
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:GridOptions
    +           *
    +           *  @description GridOptions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelectCells
    +           *  @propertyOf  ui.grid.cellNav.api:GridOptions
    +           *  @description Enable multiple cell selection only when using the ctrlKey or shiftKey.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelectCells = gridOptions.modifierKeysToMultiSelectCells === true;
    +
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name decorateRenderContainers
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  decorates grid renderContainers with cellNav functions
    +         */
    +        decorateRenderContainers: function (grid) {
    +
    +          var rightContainer = grid.hasRightContainer() ? grid.renderContainers.right : null;
    +          var leftContainer = grid.hasLeftContainer() ? grid.renderContainers.left : null;
    +
    +          if (leftContainer !== null) {
    +            grid.renderContainers.left.cellNav = new UiGridCellNav(grid.renderContainers.body, leftContainer, rightContainer, grid.renderContainers.body);
    +          }
    +          if (rightContainer !== null) {
    +            grid.renderContainers.right.cellNav = new UiGridCellNav(grid.renderContainers.body, rightContainer, grid.renderContainers.body, leftContainer);
    +          }
    +
    +          grid.renderContainers.body.cellNav = new UiGridCellNav(grid.renderContainers.body, grid.renderContainers.body, leftContainer, rightContainer);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name getDirection
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description  determines which direction to for a given keyDown event
    +         * @returns {uiGridCellNavConstants.direction} direction
    +         */
    +        getDirection: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey)) {
    +            return uiGridCellNavConstants.direction.LEFT;
    +          }
    +          if (evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB) {
    +            return uiGridCellNavConstants.direction.RIGHT;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ) {
    +            return uiGridCellNavConstants.direction.UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_UP){
    +            return uiGridCellNavConstants.direction.PG_UP;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return uiGridCellNavConstants.direction.DOWN;
    +          }
    +
    +          if (evt.keyCode === uiGridConstants.keymap.PG_DOWN){
    +            return uiGridCellNavConstants.direction.PG_DOWN;
    +          }
    +
    +          return null;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name cellNavColumnBuilder
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @description columnBuilder function that adds cell navigation properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        cellNavColumnBuilder: function (colDef, col, gridOptions) {
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.cellNav.api:ColumnDef
    +           *
    +           *  @description Column Definitions for cellNav feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name allowCellFocus
    +           *  @propertyOf  ui.grid.cellNav.api:ColumnDef
    +           *  @description Enable focus on a cell within this column.
    +           *  <br/>Defaults to true
    +           */
    +          colDef.allowCellFocus = colDef.allowCellFocus === undefined ? true : colDef.allowCellFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollTo
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible
    +         * @param {object} colDef to make visible
    +         */
    +        scrollTo: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null && typeof(rowEntity) !== 'undefined' ) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null && typeof(colDef) !== 'undefined' ) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToFocus
    +         * @description Scroll the grid such that the specified
    +         * row and column is in view, and set focus to the cell in that row and column
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {object} rowEntity gridOptions.data[] array instance to make visible and set focus to
    +         * @param {object} colDef to make visible and set focus to
    +         */
    +        scrollToFocus: function (grid, rowEntity, colDef) {
    +          var gridRow = null, gridCol = null;
    +
    +          if (rowEntity !== null) {
    +            gridRow = grid.getRow(rowEntity);
    +          }
    +
    +          if (colDef !== null) {
    +            gridCol = grid.getColumn(colDef.name ? colDef.name : colDef.field);
    +          }
    +          this.scrollToInternal(grid, gridRow, gridCol);
    +
    +          var rowCol = { row: gridRow, col: gridCol };
    +
    +          // Broadcast the navigation
    +          grid.cellNav.broadcastCellNav(rowCol);
    +
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToInternal
    +         * @description Like scrollTo, but takes gridRow and gridCol.
    +         * In calculating the scroll height we have to deal with wanting
    +         * 0% for the first row, and 100% for the last row.  Normal maths
    +         * for a 10 row list would return 1/10 = 10% for the first row, so
    +         * we need to tweak the numbers to add an extra 10% somewhere.  The
    +         * formula if we're trying to get to row 0 in a 10 row list (assuming our
    +         * index is zero based, so the last row is row 9) is:
    +         * <pre>
    +         *   0 + 0 / 10 = 0%
    +         * </pre>
    +         *
    +         * To get to row 9 (i.e. the last row) in the same list, we want to
    +         * go to:
    +         * <pre>
    +         *  ( 9 + 1 ) / 10 = 100%
    +         * </pre>
    +         * So we need to apportion one whole row within the overall grid scroll,
    +         * the formula is:
    +         * <pre>
    +         *   ( index + ( index / (total rows - 1) ) / total rows
    +         * </pre>
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToInternal: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid,null,null,'uiGridCellNavService.scrollToInternal');
    +
    +          if (gridRow !== null) {
    +            var seekRowIndex = grid.renderContainers.body.visibleRowCache.indexOf(gridRow);
    +            var totalRows = grid.renderContainers.body.visibleRowCache.length;
    +            var percentage = ( seekRowIndex + ( seekRowIndex / ( totalRows - 1 ) ) ) / totalRows;
    +            scrollEvent.y = { percentage:  percentage  };
    +          }
    +
    +          if (gridCol !== null) {
    +            scrollEvent.x = { percentage: this.getLeftWidth(grid, gridCol) / this.getLeftWidth(grid, grid.renderContainers.body.visibleColumnCache[grid.renderContainers.body.visibleColumnCache.length - 1] ) };
    +          }
    +
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name scrollToIfNecessary
    +         * @description Scrolls the grid to make a certain row and column combo visible,
    +         *   in the case that it is not completely visible on the screen already.
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {GridRow} gridRow row to make visible
    +         * @param {GridCol} gridCol column to make visible
    +         */
    +        scrollToIfNecessary: function (grid, gridRow, gridCol) {
    +          var scrollEvent = new ScrollEvent(grid, 'uiGridCellNavService.scrollToIfNecessary');
    +
    +          // Alias the visible row and column caches
    +          var visRowCache = grid.renderContainers.body.visibleRowCache;
    +          var visColCache = grid.renderContainers.body.visibleColumnCache;
    +
    +          /*-- Get the top, left, right, and bottom "scrolled" edges of the grid --*/
    +
    +          // The top boundary is the current Y scroll position PLUS the header height, because the header can obscure rows when the grid is scrolled downwards
    +          var topBound = grid.renderContainers.body.prevScrollTop + grid.headerHeight;
    +
    +          // Don't the let top boundary be less than 0
    +          topBound = (topBound < 0) ? 0 : topBound;
    +
    +          // The left boundary is the current X scroll position
    +          var leftBound = grid.renderContainers.body.prevScrollLeft;
    +
    +          // The bottom boundary is the current Y scroll position, plus the height of the grid, but minus the header height.
    +          //   Basically this is the viewport height added on to the scroll position
    +          var bottomBound = grid.renderContainers.body.prevScrollTop + grid.gridHeight - grid.headerHeight;
    +
    +          // If there's a horizontal scrollbar, remove its height from the bottom boundary, otherwise we'll be letting it obscure rows
    +          //if (grid.horizontalScrollbarHeight) {
    +          //  bottomBound = bottomBound - grid.horizontalScrollbarHeight;
    +          //}
    +
    +          // The right position is the current X scroll position minus the grid width
    +          var rightBound = grid.renderContainers.body.prevScrollLeft + Math.ceil(grid.gridWidth);
    +
    +          // If there's a vertical scrollbar, subtract it from the right boundary or we'll allow it to obscure cells
    +          //if (grid.verticalScrollbarWidth) {
    +          //  rightBound = rightBound - grid.verticalScrollbarWidth;
    +          //}
    +
    +          // We were given a row to scroll to
    +          if (gridRow !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekRowIndex = visRowCache.indexOf(gridRow);
    +
    +            // Total vertical scroll length of the grid
    +            var scrollLength = (grid.renderContainers.body.getCanvasHeight() - grid.renderContainers.body.getViewportHeight());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            //if (grid.horizontalScrollbarHeight && grid.horizontalScrollbarHeight > 0) {
    +            //  scrollLength = scrollLength + grid.horizontalScrollbarHeight;
    +            //}
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this row.
    +            var pixelsToSeeRow = ((seekRowIndex + 1) * grid.options.rowHeight);
    +
    +            // Don't let the pixels required to see the row be less than zero
    +            pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
    +
    +            var scrollPixels, percentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (pixelsToSeeRow < topBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              scrollPixels = grid.renderContainers.body.prevScrollTop - (topBound - pixelsToSeeRow);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (pixelsToSeeRow > bottomBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              scrollPixels = pixelsToSeeRow - bottomBound + grid.renderContainers.body.prevScrollTop;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              percentage = scrollPixels / scrollLength;
    +              scrollEvent.y = { percentage: percentage  };
    +            }
    +          }
    +
    +          // We were given a column to scroll to
    +          if (gridCol !== null) {
    +            // This is the index of the row we want to scroll to, within the list of rows that can be visible
    +            var seekColumnIndex = visColCache.indexOf(gridCol);
    +
    +            // Total vertical scroll length of the grid
    +            var horizScrollLength = (grid.renderContainers.body.getCanvasWidth() - grid.renderContainers.body.getViewportWidth());
    +
    +            // Add the height of the native horizontal scrollbar to the scroll length, if it's there. Otherwise it will mask over the final row
    +            // if (grid.verticalScrollbarWidth && grid.verticalScrollbarWidth > 0) {
    +            //   horizScrollLength = horizScrollLength + grid.verticalScrollbarWidth;
    +            // }
    +
    +            // This is the minimum amount of pixels we need to scroll vertical in order to see this column
    +            var columnLeftEdge = 0;
    +            for (var i = 0; i < seekColumnIndex; i++) {
    +              var col = visColCache[i];
    +              columnLeftEdge += col.drawnWidth;
    +            }
    +            columnLeftEdge = (columnLeftEdge < 0) ? 0 : columnLeftEdge;
    +
    +            var columnRightEdge = columnLeftEdge + gridCol.drawnWidth;
    +
    +            // Don't let the pixels required to see the column be less than zero
    +            columnRightEdge = (columnRightEdge < 0) ? 0 : columnRightEdge;
    +
    +            var horizScrollPixels, horizPercentage;
    +
    +            // If the scroll position we need to see the row is LESS than the top boundary, i.e. obscured above the top of the grid...
    +            if (columnLeftEdge < leftBound) {
    +              // Get the different between the top boundary and the required scroll position and subtract it from the current scroll position\
    +              //   to get the full position we need
    +              horizScrollPixels = grid.renderContainers.body.prevScrollLeft - (leftBound - columnLeftEdge);
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +            // Otherwise if the scroll position we need to see the row is MORE than the bottom boundary, i.e. obscured below the bottom of the grid...
    +            else if (columnRightEdge > rightBound) {
    +              // Get the different between the bottom boundary and the required scroll position and add it to the current scroll position
    +              //   to get the full position we need
    +              horizScrollPixels = columnRightEdge - rightBound + grid.renderContainers.body.prevScrollLeft;
    +
    +              // Turn the scroll position into a percentage and make it an argument for a scroll event
    +              horizPercentage = horizScrollPixels / horizScrollLength;
    +              horizPercentage = (horizPercentage > 1) ? 1 : horizPercentage;
    +              scrollEvent.x = { percentage: horizPercentage  };
    +            }
    +          }
    +
    +          // If we need to scroll on either the x or y axes, fire a scroll event
    +          if (scrollEvent.y || scrollEvent.x) {
    +            scrollEvent.fireScrollingEvent();
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.cellNav.service:uiGridCellNavService
    +         * @name getLeftWidth
    +         * @description Get the current drawn width of the columns in the
    +         * grid up to the numbered column, and add an apportionment for the
    +         * column that we're on.  So if we are on column 0, we want to scroll
    +         * 0% (i.e. exclude this column from calc).  If we're on the last column
    +         * we want to scroll to 100% (i.e. include this column in the calc). So
    +         * we include (thisColIndex / totalNumberCols) % of this column width
    +         * @param {Grid} grid the grid you'd like to act upon, usually available
    +         * from gridApi.grid
    +         * @param {gridCol} upToCol the column to total up to and including
    +         */
    +        getLeftWidth: function (grid, upToCol) {
    +          var width = 0;
    +
    +          if (!upToCol) {
    +            return width;
    +          }
    +
    +          var lastIndex = grid.renderContainers.body.visibleColumnCache.indexOf( upToCol );
    +
    +          // total column widths up-to but not including the passed in column
    +          grid.renderContainers.body.visibleColumnCache.forEach( function( col, index ) {
    +            if ( index < lastIndex ){
    +              width += col.drawnWidth;
    +            }
    +          });
    +
    +          // pro-rata the final column based on % of total columns.
    +          var percentage = lastIndex === 0 ? 0 : (lastIndex + 1) / grid.renderContainers.body.visibleColumnCache.length;
    +          width += upToCol.drawnWidth * percentage;
    +
    +          return width;
    +        }
    +      };
    +
    +      return service;
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiCellNav
    +   *  @element div
    +   *  @restrict EA
    +   *
    +   *  @description Adds cell navigation features to the grid columns
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.cellNav']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'title'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-cellnav></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridCellnav', ['gridUtil', 'uiGridCellNavService', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function (gridUtil, uiGridCellNavService, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        replace: true,
    +        priority: -150,
    +        require: '^uiGrid',
    +        scope: false,
    +        controller: function () {},
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              var _scope = $scope;
    +
    +              var grid = uiGridCtrl.grid;
    +              uiGridCellNavService.initializeGrid(grid);
    +
    +              uiGridCtrl.cellNav = {};
    +
    +              uiGridCtrl.cellNav.focusCell = function (row, col) {
    +                uiGridCtrl.cellNav.broadcastCellNav({ row: row, col: col });
    +              };
    +
    +              //  gridUtil.logDebug('uiGridEdit preLink');
    +              uiGridCtrl.cellNav.broadcastCellNav = grid.cellNav.broadcastCellNav = function (newRowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +                uiGridCtrl.cellNav.broadcastFocus(newRowCol, modifierDown);
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, newRowCol, modifierDown);
    +              };
    +
    +              uiGridCtrl.cellNav.clearFocus = grid.cellNav.clearFocus = function () {
    +                _scope.$broadcast(uiGridCellNavConstants.CELL_NAV_EVENT, { eventType: uiGridCellNavConstants.EVENT_TYPE.CLEAR });
    +              };
    +
    +              uiGridCtrl.cellNav.broadcastFocus = function (rowCol, modifierDown) {
    +                modifierDown = !(modifierDown === undefined || !modifierDown);
    +
    +                var row = rowCol.row,
    +                  col = rowCol.col;
    +
    +                var rowColSelectIndex = uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol);
    +
    +                if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
    +                  var newRowCol = new RowCol(row, col);
    +                  grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
    +                  grid.cellNav.lastRowCol = newRowCol;
    +                  if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
    +                    grid.cellNav.focusedCells.push(rowCol);
    +                  } else {
    +                    grid.cellNav.focusedCells = [rowCol];
    +                  }
    +                } else if (grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                  rowColSelectIndex >= 0) {
    +
    +                  grid.cellNav.focusedCells.splice(rowColSelectIndex, 1);
    +                }
    +              };
    +
    +              uiGridCtrl.cellNav.handleKeyDown = function (evt) {
    +                var direction = uiGridCellNavService.getDirection(evt);
    +                if (direction === null) {
    +                  return true;
    +                }
    +
    +                var containerId = 'body';
    +                if (evt.uiGridTargetRenderContainerId) {
    +                  containerId = evt.uiGridTargetRenderContainerId;
    +                }
    +
    +                // Get the last-focused row+col combo
    +                var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +                if (lastRowCol) {
    +                  // Figure out which new row+combo we're navigating to
    +                  var rowCol = uiGridCtrl.grid.renderContainers[containerId].cellNav.getNextRowCol(direction, lastRowCol.row, lastRowCol.col);
    +
    +                  // Shift+tab on top-left cell should exit cellnav on render container
    +                  if (
    +                    // Navigating left
    +                    direction === uiGridCellNavConstants.direction.LEFT &&
    +                    // Trying to stay on same row
    +                    rowCol.row === lastRowCol.row &&
    +                    evt.keyCode === uiGridConstants.keymap.TAB &&
    +                    evt.shiftKey
    +                  ) {
    +                    uiGridCtrl.cellNav.clearFocus();
    +                    return true;
    +                  }
    +                  // Tab on bottom-right cell should exit cellnav on render container
    +                  else if (
    +                    direction === uiGridCellNavConstants.direction.RIGHT &&
    +                    rowCol.row === lastRowCol.row &&
    +                    evt.keyCode === uiGridConstants.keymap.TAB &&
    +                    !evt.shiftKey
    +                  ) {
    +                    uiGridCtrl.cellNav.clearFocus();
    +                    return true;
    +                  }
    +
    +
    +                  rowCol.eventType = uiGridCellNavConstants.EVENT_TYPE.KEYDOWN;
    +
    +                  // Broadcast the navigation
    +                  uiGridCtrl.cellNav.broadcastCellNav(rowCol);
    +
    +                  // Scroll to the new cell, if it's not completely visible within the render container's viewport
    +                  uiGridCellNavService.scrollToIfNecessary(grid, rowCol.row, rowCol.col);
    +
    +                  evt.stopPropagation();
    +                  evt.preventDefault();
    +
    +                  return false;
    +                }
    +              };
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridRenderContainer', ['$timeout', '$document', 'gridUtil', 'uiGridConstants', 'uiGridCellNavService', 'uiGridCellNavConstants',
    +    function ($timeout, $document, gridUtil, uiGridConstants, uiGridCellNavService, uiGridCellNavConstants) {
    +      return {
    +        replace: true,
    +        priority: -99999, //this needs to run very last
    +        require: ['^uiGrid', 'uiGridRenderContainer', '?^uiGridCellnav'],
    +        scope: false,
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, controllers) {
    +              var uiGridCtrl = controllers[0],
    +                 renderContainerCtrl = controllers[1];
    +
    +              // Skip attaching cell-nav specific logic if the directive is not attached above us
    +              if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +              var containerId = renderContainerCtrl.containerId;
    +
    +              var grid = uiGridCtrl.grid;
    +
    +              // Needs to run last after all renderContainers are built
    +              uiGridCellNavService.decorateRenderContainers(grid);
    +
    +              // Let the render container be focus-able
    +              $elm.attr("tabindex", -1);
    +
    +              // Bind to keydown events in the render container
    +              $elm.on('keydown', function (evt) {
    +                evt.uiGridTargetRenderContainerId = containerId;
    +                return uiGridCtrl.cellNav.handleKeyDown(evt);
    +              });
    +
    +              var needFocus = false;
    +              
    +              // When there's a scroll event we need to make sure to re-focus the right row, because the cell contents may have changed
    +              grid.api.core.on.scrollEvent($scope, function (args) {
    +                // Skip if not this grid that the event was broadcast for
    +                if (args.grid && args.grid.id !== uiGridCtrl.grid.id) {
    +                  return;
    +                }
    +
    +                // Skip if there's no currently-focused cell
    +                if (uiGridCtrl.grid.api.cellNav.getFocusedCell() == null) {
    +                  return;
    +                }
    +                
    +                /*
    +                 * If we have scrolled due to cellNav, we want to set the focus to the new cell after the 
    +                 * virtualisation has run, and after scroll.  If we scrolled through the browser scroll
    +                 * bar or other user action, we're going to discard the focus, because it will no longer 
    +                 * be valid (and, noting #2423, trying to keep it causes problems)
    +                 * 
    +                 * If cellNav triggers the scroll, we get a scrollToIfNecessary, then a viewport scroll. We
    +                 * want to wait for the viewport scroll to finish, then do a refocus.  
    +                 * 
    +                 * If someone manually scrolls we get just the viewport scroll, no scrollToIfNecessary.  We
    +                 * want to just clear the focus
    +                 * 
    +                 * Logic is:
    +                 *  - if cellNav scroll, set a flag that will be resolved in the native scroll
    +                 *  - if native scroll, look for the cellNav promise and resolve it
    +                 *    - if not present, then use a timeout to clear focus
    +                 *    - if it is present, then instead use a timeout to set focus
    +                 */ 
    +                
    +                // We have to wrap in TWO timeouts so that we run AFTER the scroll event is resolved.
    +                if ( args.source === 'uiGridCellNavService.scrollToIfNecessary'){
    +                  needFocus = true;
    +/*
    +                  focusTimeout = $timeout(function () {
    +                    if ( clearFocusTimeout ){
    +                      $timeout.cancel(clearFocusTimeout);
    +                    }
    +                    focusTimeout = $timeout(function () {
    +                      if ( clearFocusTimeout ){
    +                        $timeout.cancel(clearFocusTimeout);
    +                      }
    +                      // Get the last row+col combo
    +                      var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +  
    +                      // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                      //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                      //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                      if ($document.activeElement === $document.body) {
    +                        $elm[0].focus();
    +                      }
    +  
    +                      // broadcast a cellNav event so we clear the focus on all cells
    +                      uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                    });
    +                  });
    +                  */
    +                } else {
    +                  if ( needFocus ){
    +                    $timeout(function () {
    +                      $timeout(function () {
    +                        // Get the last row+col combo
    +                        var lastRowCol = uiGridCtrl.grid.api.cellNav.getFocusedCell();
    +    
    +                        // If the body element becomes active, re-focus on the render container so we can capture cellNav events again.
    +                        //   NOTE: this happens when we navigate LET from the left-most cell (RIGHT from the right-most) and have to re-render a new
    +                        //   set of cells. The cell element we are navigating to doesn't exist and focus gets lost. This will re-capture it, imperfectly...
    +                        if ($document.activeElement === $document.body) {
    +                          $elm[0].focus();
    +                        }
    +    
    +                        // broadcast a cellNav event so we clear the focus on all cells
    +                        uiGridCtrl.cellNav.broadcastCellNav(lastRowCol);
    +                        
    +                        needFocus = false;
    +                      });
    +                    });
    +                  }
    +                }
    +              });  
    +             
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.cellNav.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide cell navigation
    +   */
    +  module.directive('uiGridCell', ['$timeout', '$document', 'uiGridCellNavService', 'gridUtil', 'uiGridCellNavConstants', 'uiGridConstants',
    +    function ($timeout, $document, uiGridCellNavService, gridUtil, uiGridCellNavConstants, uiGridConstants) {
    +      return {
    +        priority: -150, // run after default uiGridCell directive and ui.grid.edit uiGridCell
    +        restrict: 'A',
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          // Skip attaching cell-nav specific logic if the directive is not attached above us
    +          if (!uiGridCtrl.grid.api.cellNav) { return; }
    +
    +          if (!$scope.col.colDef.allowCellFocus) {
    +            return;
    +          }
    +
    +          setTabEnabled();
    +
    +          // When a cell is clicked, broadcast a cellNav event saying that this row+col combo is now focused
    +          $elm.find('div').on('click', function (evt) {
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +
    +            evt.stopPropagation();
    +          });
    +
    +          $elm.find('div').on('focus', function (evt) {
    +            console.log('cellNav focus');
    +            uiGridCtrl.cellNav.broadcastCellNav(new RowCol($scope.row, $scope.col), evt.ctrlKey || evt.metaKey);
    +          });
    +
    +          // This event is fired for all cells.  If the cell matches, then focus is set
    +          $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol, modifierDown) {
    +            if (evt.eventType === uiGridCellNavConstants.EVENT_TYPE.CLEAR) {
    +              clearFocus();
    +              return;
    +            }
    +
    +            if (rowCol.row === $scope.row &&
    +              rowCol.col === $scope.col) {
    +              if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown &&
    +                uiGridCtrl.grid.api.cellNav.rowColSelectIndex(rowCol) === -1) {
    +                clearFocus();
    +              } else {
    +                setFocused();
    +              }
    +
    +              // This cellNav event came from a keydown event so we can safely refocus
    +              if (rowCol.hasOwnProperty('eventType') && rowCol.eventType === uiGridCellNavConstants.EVENT_TYPE.KEYDOWN) {
    +                console.log('focus from navEvent');
    +                $elm.find('div')[0].focus();
    +              }
    +            }
    +            else if (!(uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown)) {
    +              clearFocus();
    +            }
    +          });
    +
    +          function setTabEnabled() {
    +            $elm.find('div').attr("tabindex", 0);
    +          }
    +
    +          function setFocused() {
    +            var div = $elm.find('div');
    +            div.addClass('ui-grid-cell-focus');
    +          }
    +
    +          function clearFocus() {
    +            var div = $elm.find('div');
    +            div.removeClass('ui-grid-cell-focus');
    +          }
    +
    +          $scope.$on('$destroy', function () {
    +            $elm.find('div').off('click');
    +          });
    +        }
    +      };
    +    }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.edit
    +   * @description
    +   *
    +   *  # ui.grid.edit
    +   * This module provides cell editing capability to ui.grid. The goal was to emulate keying data in a spreadsheet via
    +   * a keyboard.
    +   * <br/>
    +   * <br/>
    +   * To really get the full spreadsheet-like data entry, the ui.grid.cellNav module should be used. This will allow the
    +   * user to key data and then tab, arrow, or enter to the cells beside or below.
    +   *
    +   * <div doc-module-components="ui.grid.edit"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.edit', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.constant:uiGridEditConstants
    +   *
    +   *  @description constants available in edit module
    +   */
    +  module.constant('uiGridEditConstants', {
    +    EDITABLE_CELL_TEMPLATE: /EDITABLE_CELL_TEMPLATE/g,
    +    //must be lowercase because template bulder converts to lower
    +    EDITABLE_CELL_DIRECTIVE: /editable_cell_directive/g,
    +    events: {
    +      BEGIN_CELL_EDIT: 'uiGridEventBeginCellEdit',
    +      END_CELL_EDIT: 'uiGridEventEndCellEdit',
    +      CANCEL_CELL_EDIT: 'uiGridEventCancelCellEdit'
    +    }
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.edit.service:uiGridEditService
    +   *
    +   *  @description Services for editing features
    +   */
    +  module.service('uiGridEditService', ['$q', '$templateCache', 'uiGridConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          grid.registerColumnBuilder(service.editColumnBuilder);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:PublicApi
    +           *
    +           *  @description Public Api for edit feature
    +           */
    +          var publicApi = {
    +            events: {
    +              edit: {
    +                /**
    +                 * @ngdoc event
    +                 * @name afterCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is complete
    +                 * <pre>
    +                 *      gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 * @param {object} newValue new value
    +                 * @param {object} oldValue old value
    +                 */
    +                afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name beginCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing starts on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                beginCellEdit: function (rowEntity, colDef) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name cancelCellEdit
    +                 * @eventOf  ui.grid.edit.api:PublicApi
    +                 * @description raised when cell editing is cancelled on a cell
    +                 * <pre>
    +                 *      gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @param {object} colDef the column that was edited
    +                 */
    +                cancelCellEdit: function (rowEntity, colDef) {
    +                }
    +              }
    +            },
    +            methods: {
    +              edit: { }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          //grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:GridOptions
    +           *
    +           *  @description Options for configuring the edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If defined, sets the default value for the editable flag on each individual colDefs
    +           *  if their individual enableCellEdit configuration is not defined. Defaults to undefined.
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, either a value or function to be used by all columns before editing.
    +           *  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If specified, cellTemplate to use as the editor for all columns.
    +           *  <br/> defaults to 'ui-grid/cellTextEditor'
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:GridOptions
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br/>_requires cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          gridOptions.enableCellEditOnFocus = gridOptions.enableCellEditOnFocus === undefined ? false : gridOptions.enableCellEditOnFocus;
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name editColumnBuilder
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description columnBuilder function that adds edit properties to grid column
    +         * @returns {promise} promise that will load any needed templates when resolved
    +         */
    +        editColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.edit.api:ColumnDef
    +           *
    +           *  @description Column Definition for edit feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEdit
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description enable editing on column
    +           */
    +          colDef.enableCellEdit = colDef.enableCellEdit === undefined ? (gridOptions.enableCellEdit === undefined ?
    +            (colDef.type !== 'object') : gridOptions.enableCellEdit) : colDef.enableCellEdit;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name cellEditableCondition
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description If specified, either a value or function evaluated before editing cell.  If falsy, then editing of cell is not allowed.
    +           *  @example
    +           *  <pre>
    +           *  function($scope){
    +           *    //use $scope.row.entity and $scope.col.colDef to determine if editing is allowed
    +           *    return true;
    +           *  }
    +           *  </pre>
    +           */
    +          colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition :  colDef.cellEditableCondition;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name editableCellTemplate
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @description cell template to be used when editing this column. Can be Url or text template
    +           *  <br/>Defaults to gridOptions.editableCellTemplate
    +           */
    +          if (colDef.enableCellEdit) {
    +            colDef.editableCellTemplate = colDef.editableCellTemplate || gridOptions.editableCellTemplate || 'ui-grid/cellEditor';
    +
    +            promises.push(gridUtil.getTemplate(colDef.editableCellTemplate)
    +              .then(
    +              function (template) {
    +                col.editableCellTemplate = template;
    +              },
    +              function (res) {
    +                // Todo handle response error here?
    +                throw new Error("Couldn't fetch/use colDef.editableCellTemplate '" + colDef.editableCellTemplate + "'");
    +              }));
    +          }
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableCellEditOnFocus
    +           *  @propertyOf  ui.grid.edit.api:ColumnDef
    +           *  @requires ui.grid.cellNav
    +           *  @description If true, then editor is invoked as soon as cell receives focus. Default false.
    +           *  <br>_requires both the cellNav feature and the edit feature to be enabled_
    +           */
    +            //enableCellEditOnFocus can only be used if cellnav module is used
    +          colDef.enableCellEditOnFocus = colDef.enableCellEditOnFocus === undefined ? gridOptions.enableCellEditOnFocus : colDef.enableCellEditOnFocus;
    +
    +          return $q.all(promises);
    +        },
    +
    +        /**
    +         * @ngdoc service
    +         * @name isStartEditKey
    +         * @methodOf ui.grid.edit.service:uiGridEditService
    +         * @description  Determines if a keypress should start editing.  Decorate this service to override with your
    +         * own key events.  See service decorator in angular docs.
    +         * @param {Event} evt keydown event
    +         * @returns {boolean} true if an edit should start
    +         */
    +        isStartEditKey: function (evt) {
    +          if (evt.keyCode === uiGridConstants.keymap.LEFT ||
    +            (evt.keyCode === uiGridConstants.keymap.TAB && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.RIGHT ||
    +            evt.keyCode === uiGridConstants.keymap.TAB ||
    +
    +            evt.keyCode === uiGridConstants.keymap.UP ||
    +            (evt.keyCode === uiGridConstants.keymap.ENTER && evt.shiftKey) ||
    +
    +            evt.keyCode === uiGridConstants.keymap.DOWN ||
    +            evt.keyCode === uiGridConstants.keymap.ENTER) {
    +            return false;
    +
    +          }
    +          return true;
    +        }
    +
    +
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds editing features to the ui-grid directive.
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridEdit', ['gridUtil', 'uiGridEditService', function (gridUtil, uiGridEditService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridEditService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide in-line editing capabilities to the cell
    +   *  Editing Actions.
    +   *
    +   *  Binds edit start events to the uiGridCell element.  When the events fire, the gridCell element is appended
    +   *  with the columnDef.editableCellTemplate element ('cellEditor.html' by default).
    +   *
    +   *  The editableCellTemplate should respond to uiGridEditConstants.events.BEGIN\_CELL\_EDIT angular event
    +   *  and do the initial steps needed to edit the cell (setfocus on input element, etc).
    +   *
    +   *  When the editableCellTemplate recognizes that the editing is ended (blur event, Enter key, etc.)
    +   *  it should emit the uiGridEditConstants.events.END\_CELL\_EDIT event.
    +   *
    +   *  If editableCellTemplate recognizes that the editing has been cancelled (esc key)
    +   *  it should emit the uiGridEditConstants.events.CANCEL\_CELL\_EDIT event.  The original value
    +   *  will be set back on the model by the uiGridCell directive.
    +   *
    +   *  Events that invoke editing:
    +   *    - dblclick
    +   *    - F2 keydown (when using cell selection)
    +   *
    +   *  Events that end editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Dependent on the specific editableCellTemplate
    +   *    - Standards should be Esc keydown
    +   *
    +   *  Grid Events that end editing:
    +   *    - uiGridConstants.events.GRID_SCROLL
    +   *
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.edit.api:GridRow
    +   *
    +   *  @description GridRow options for edit feature, these are available to be
    +   *  set internally only, by other features
    +   */
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableCellEdit
    +   *  @propertyOf  ui.grid.edit.api:GridRow
    +   *  @description enable editing on row, grouping for example might disable editing on group header rows
    +   */
    +
    +  module.directive('uiGridCell',
    +    ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
    +      function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
    +        var touchstartTimeout = 500;
    +
    +        return {
    +          priority: -100, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          require: '?^uiGrid',
    +          link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            if (!$scope.col.colDef.enableCellEdit || $scope.row.enableCellEdit === false) {
    +              return;
    +            }
    +
    +            var html;
    +            var origCellValue;
    +            var inEdit = false;
    +            var isFocusedBeforeEdit = false;
    +            var cellModel;
    +            var cancelTouchstartTimeout;
    +
    +            var editCellScope;
    +
    +            registerBeginEditEvents();
    +
    +            function registerBeginEditEvents() {
    +              $elm.on('dblclick', beginEdit);
    +              $elm.on('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').on('focus', beginEditFocus);
    +              }
    +
    +              // Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
    +              $elm.on('touchstart', touchStart);
    +            }
    +
    +            function touchStart(event) {
    +              // jQuery masks events
    +              if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
    +                event = event.originalEvent;
    +              }
    +
    +              // Bind touchend handler
    +              $elm.on('touchend', touchEnd);
    +
    +              // Start a timeout
    +              cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
    +
    +              // Timeout's done! Start the edit
    +              cancelTouchstartTimeout.then(function () {
    +                // Use setTimeout to start the edit because beginEdit expects to be outside of $digest
    +                setTimeout(beginEdit, 0);
    +
    +                // Undbind the touchend handler, we don't need it anymore
    +                $elm.off('touchend', touchEnd);
    +              });
    +            }
    +
    +            // Cancel any touchstart timeout
    +            function touchEnd(event) {
    +              $timeout.cancel(cancelTouchstartTimeout);
    +              $elm.off('touchend', touchEnd);
    +            }
    +
    +            function cancelBeginEditEvents() {
    +              $elm.off('dblclick', beginEdit);
    +              $elm.off('keydown', beginEditKeyDown);
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $elm.find('div').off('focus', beginEditFocus);
    +              }
    +              $elm.off('touchstart', touchStart);
    +            }
    +
    +            function beginEditFocus(evt) {
    +              // gridUtil.logDebug('begin edit');
    +              if (uiGridCtrl && uiGridCtrl.cellNav) {
    +                // NOTE(c0bra): This is causing a loop where focusCell causes beginEditFocus to be called....
    +                uiGridCtrl.cellNav.focusCell($scope.row, $scope.col);
    +              }
    +
    +              evt.stopPropagation();
    +              beginEdit();
    +            }
    +
    +            // If the cellNagv module is installed and we can get the uiGridCellNavConstants value injected,
    +            //   then if the column has enableCellEditOnFocus set to true, we need to listen for cellNav events
    +            //   to this cell and start editing when the "focus" reaches us
    +            try {
    +              var uiGridCellNavConstants = $injector.get('uiGridCellNavConstants');
    +
    +              if ($scope.col.colDef.enableCellEditOnFocus) {
    +                $scope.$on(uiGridCellNavConstants.CELL_NAV_EVENT, function (evt, rowCol) {
    +                  if (rowCol.row === $scope.row && rowCol.col === $scope.col) {
    +                    beginEdit();
    +                  }
    +                  else {
    +                    endEdit();
    +                  }
    +                });
    +              }
    +            }
    +            catch (e) {}
    +
    +            function beginEditKeyDown(evt) {
    +              if (uiGridEditService.isStartEditKey(evt)) {
    +                beginEdit();
    +              }
    +            }
    +
    +            function shouldEdit(col, row) {
    +              return !row.isSaving &&
    +                ( angular.isFunction(col.colDef.cellEditableCondition) ?
    +                    col.colDef.cellEditableCondition($scope) :
    +                    col.colDef.cellEditableCondition );
    +            }
    +
    +
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownOptionsArray
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description an array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which is populated
    +             *  into the edit dropdown
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownIdLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "id" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'id'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownRowEntityOptionsArrayPath
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description a path to a property on row.entity containing an
    +             *  array of values in the format
    +             *  [ {id: xxx, value: xxx} ], which will be used to populate
    +             *  the edit dropdown.  This can be used when the dropdown values are dependent on
    +             *  the backing row entity.
    +             *  If this property is set then editDropdownOptionsArray will be ignored.
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownValueLabel
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description the label for the "value" field
    +             *  in the editDropdownOptionsArray.  Defaults
    +             *  to 'value'
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            /**
    +             *  @ngdoc property
    +             *  @name editDropdownFilter
    +             *  @propertyOf ui.grid.edit.api:ColumnDef
    +             *  @description A filter that you would like to apply to the values in the options list
    +             *  of the dropdown.  For example if you were using angular-translate you might set this
    +             *  to `'translate'`
    +             *  @example
    +             *  <pre>
    +             *    $scope.gridOptions = {
    +             *      columnDefs: [
    +             *        {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
    +             *          editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
    +             *          editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
    +             *      ],
    +             *  </pre>
    +             *
    +             */
    +            function beginEdit() {
    +              // If we are already editing, then just skip this so we don't try editing twice...
    +              if (inEdit) {
    +                return;
    +              }
    +
    +              if (!shouldEdit($scope.col, $scope.row)) {
    +                return;
    +              }
    +
    +              // if the cell isn't fully visible, and cellNav is present, scroll it to be fully visible before we start
    +              if ( $scope.grid.api.cellNav ){
    +                $scope.grid.api.cellNav.scrollToIfNecessary( $scope.row, $scope.col );
    +              }
    +              
    +              cellModel = $parse($scope.row.getQualifiedColField($scope.col));
    +              //get original value from the cell
    +              origCellValue = cellModel($scope);
    +
    +              html = $scope.col.editableCellTemplate;
    +              html = html.replace(uiGridConstants.MODEL_COL_FIELD, $scope.row.getQualifiedColField($scope.col));
    +
    +              var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
    +              html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
    +
    +              var inputType = 'text';
    +              switch ($scope.col.colDef.type){
    +                case 'boolean':
    +                  inputType = 'checkbox';
    +                  break;
    +                case 'number':
    +                  inputType = 'number';
    +                  break;
    +                case 'date':
    +                  inputType = 'date';
    +                  break;
    +              }
    +              html = html.replace('INPUT_TYPE', inputType);
    +
    +              var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
    +              if (editDropdownRowEntityOptionsArrayPath) {
    +                $scope.editDropdownOptionsArray =  resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
    +              }
    +              else {
    +                $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
    +              }
    +              $scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
    +              $scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
    +
    +              var cellElement;
    +              $scope.$apply(function () {
    +                inEdit = true;
    +                cancelBeginEditEvents();
    +                var cellElement = angular.element(html);
    +                $elm.append(cellElement);
    +                editCellScope = $scope.$new();
    +                $compile(cellElement)(editCellScope);
    +                var gridCellContentsEl = angular.element($elm.children()[0]);
    +                isFocusedBeforeEdit = gridCellContentsEl.hasClass('ui-grid-cell-focus');
    +                gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
    +              });
    +
    +              //stop editing when grid is scrolled
    +              var deregOnGridScroll = $scope.col.grid.api.core.on.scrollEvent($scope, function () {
    +                endEdit(true);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //end editing
    +              var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function (evt, retainFocus) {
    +                endEdit(retainFocus);
    +                $scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
    +                deregOnEndCellEdit();
    +                deregOnGridScroll();
    +                deregOnCancelCellEdit();
    +              });
    +
    +              //cancel editing
    +              var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
    +                cancelEdit();
    +                deregOnCancelCellEdit();
    +                deregOnGridScroll();
    +                deregOnEndCellEdit();
    +              });
    +
    +              $scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT);
    +              $scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef);
    +            }
    +
    +            function endEdit(retainFocus) {
    +              if (!inEdit) {
    +                return;
    +              }
    +              var gridCellContentsEl = angular.element($elm.children()[0]);
    +              //remove edit element
    +              editCellScope.$destroy();
    +              angular.element($elm.children()[1]).remove();
    +              gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
    +              if (retainFocus && isFocusedBeforeEdit) {
    +                gridCellContentsEl[0].focus();
    +              }
    +              isFocusedBeforeEdit = false;
    +              inEdit = false;
    +              registerBeginEditEvents();
    +              $scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
    +            }
    +
    +            function cancelEdit() {
    +              if (!inEdit) {
    +                return;
    +              }
    +              cellModel.assign($scope, origCellValue);
    +              $scope.$apply();
    +
    +              $scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
    +              endEdit(true);
    +            }
    +
    +            // resolves a string path against the given object
    +            // shamelessly borrowed from
    +            // http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
    +            function resolveObjectFromPath(object, path) {
    +              path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    +              path = path.replace(/^\./, '');           // strip a leading dot
    +              var a = path.split('.');
    +              while (a.length) {
    +                  var n = a.shift();
    +                  if (n in object) {
    +                      object = object[n];
    +                  } else {
    +                      return;
    +                  }
    +              }
    +              return object;
    +            }
    +
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditor
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description input editor directive for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditor',
    +    ['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
    +      function (gridUtil, uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          require: ['?^uiGrid', '?^uiGridRenderContainer'],
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +                var uiGridCtrl, renderContainerCtrl;
    +                if (controllers[0]) { uiGridCtrl = controllers[0]; }
    +                if (controllers[1]) { renderContainerCtrl = controllers[1]; }
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].select();
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +               $scope.deepEdit = false;
    +
    +               $scope.stopEdit = function (evt) {
    +                  if ($scope.inputForm && !$scope.inputForm.$valid) {
    +                    evt.stopPropagation();
    +                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                  }
    +                  else {
    +                    $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                  }
    +                  $scope.deepEdit = false;
    +                };
    +
    +                $elm.on('click', function (evt) {
    +                  $scope.deepEdit = true;
    +                });
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +
    +                  if ($scope.deepEdit) {
    +                    switch (evt.keyCode) {
    +                      case uiGridConstants.keymap.LEFT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.RIGHT:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.UP:
    +                        evt.stopPropagation();
    +                        break;
    +                      case uiGridConstants.keymap.DOWN:
    +                        evt.stopPropagation();
    +                        break;
    +                    }
    +                  }
    +                  // Pass the keydown event off to the cellNav service, if it exists
    +                  else if (uiGridCtrl && uiGridCtrl.hasOwnProperty('cellNav') && renderContainerCtrl) {
    +                    evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
    +                    uiGridCtrl.cellNav.handleKeyDown(evt);
    +                  }
    +
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:input
    +   *  @element input
    +   *  @restrict E
    +   *
    +   *  @description directive to provide binding between input[date] value and ng-model for angular 1.2
    +   *  It is similar to input[date] directive of angular 1.3
    +   *
    +   *  Supported date format for input is 'yyyy-MM-dd'
    +   *  The directive will set the $valid property of input element and the enclosing form to false if
    +   *  model is invalid date or value of input is entered wrong.
    +   *
    +   */
    +    module.directive('uiGridEditor', ['$filter', function ($filter) {
    +      function parseDateString(dateString) {
    +        if (typeof(dateString) === 'undefined' || dateString === '') {
    +          return null;
    +        }
    +        var parts = dateString.split('-');
    +        if (parts.length !== 3) {
    +          return null;
    +        }
    +        var year = parseInt(parts[0], 10);
    +        var month = parseInt(parts[1], 10);
    +        var day = parseInt(parts[2], 10);
    +
    +        if (month < 1 || year < 1 || day < 1) {
    +          return null;
    +        }
    +        return new Date(year, (month - 1), day);
    +      }
    +      return {
    +        priority: -100, // run after default uiGridEditor directive
    +        require: '?ngModel',
    +        link: function (scope, element, attrs, ngModel) {
    +
    +          if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
    +
    +            ngModel.$formatters.push(function (modelValue) {
    +              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
    +              return $filter('date')(modelValue, 'yyyy-MM-dd');
    +            });
    +
    +            ngModel.$parsers.push(function (viewValue) {
    +              if (viewValue && viewValue.length > 0) {
    +                var dateValue = parseDateString(viewValue);
    +                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
    +                return dateValue;
    +              }
    +              else {
    +                ngModel.$setValidity(null, true);
    +                return null;
    +              }
    +            });
    +          }
    +        }
    +      };
    +    }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.edit.directive:uiGridEditDropdown
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description dropdown editor for editable fields.
    +   *  Provides EndEdit and CancelEdit events
    +   *
    +   *  Events that end editing:
    +   *     blur and enter keydown, and any left/right nav
    +   *
    +   *  Events that cancel editing:
    +   *    - Esc keydown
    +   *
    +   */
    +  module.directive('uiGridEditDropdown',
    +    ['uiGridConstants', 'uiGridEditConstants',
    +      function (uiGridConstants, uiGridEditConstants) {
    +        return {
    +          scope: true,
    +          compile: function () {
    +            return {
    +              pre: function ($scope, $elm, $attrs) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs) {
    +
    +                //set focus at start of edit
    +                $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
    +                  $elm[0].focus();
    +                  $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
    +                  $elm.on('blur', function (evt) {
    +                    $scope.stopEdit(evt);
    +                  });
    +                });
    +
    +
    +                $scope.stopEdit = function (evt) {
    +                  // no need to validate a dropdown - invalid values shouldn't be
    +                  // available in the list
    +                  $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
    +                };
    +
    +                $elm.on('keydown', function (evt) {
    +                  switch (evt.keyCode) {
    +                    case uiGridConstants.keymap.ESC:
    +                      evt.stopPropagation();
    +                      $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
    +                      break;
    +                    case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.LEFT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.RIGHT:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                    case uiGridConstants.keymap.UP:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.DOWN:
    +                      evt.stopPropagation();
    +                      break;
    +                    case uiGridConstants.keymap.TAB:
    +                      $scope.stopEdit(evt);
    +                      break;
    +                  }
    +                  return true;
    +                });
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.expandable
    +   * @description
    +   *
    +   *  # ui.grid.expandable
    +   * This module provides the ability to create subgrids with the ability to expand a row
    +   * to show the subgrid.
    +   *
    +   * <div doc-module-components="ui.grid.expandable"></div>
    +   */
    +  var module = angular.module('ui.grid.expandable', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.expandable.service:uiGridExpandableService
    +   *
    +   *  @description Services for the expandable grid
    +   */
    +  module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
    +    var service = {
    +      initializeGrid: function (grid) {
    +        
    +        grid.expandable = {};
    +        grid.expandable.expandedAll = false;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableExpandable
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
    +         *  within your application, or in specific modes on _this_ grid. Defaults to true.  
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      enableExpandable: false
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.enableExpandable = grid.options.enableExpandable !== false;
    +        
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowHeight
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Height in pixels of the expanded subgrid.  Defaults to
    +         *  150
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeight: 150
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name 
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Width in pixels of the expandable column. Defaults to 40
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowHeaderWidth: 40
    +         *    }
    +         *  </pre>  
    +         */
    +        grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name expandableRowTemplate
    +         *  @propertyOf  ui.grid.expandable.api:GridOptions
    +         *  @description Mandatory. The template for your expanded row
    +         *  @example
    +         *  <pre>
    +         *    $scope.gridOptions = {
    +         *      expandableRowTemplate: 'expandableRowTemplate.html'
    +         *    }
    +         *  </pre>  
    +         */
    +        if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
    +          gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
    +          grid.options.enableExpandable = false;
    +        }
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:PublicApi
    +         *
    +         *  @description Public Api for expandable feature
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.expandable.api:GridOptions
    +         *
    +         *  @description Options for configuring the expandable feature, these are available to be  
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        var publicApi = {
    +          events: {
    +            expandable: {
    +              /**
    +               * @ngdoc event
    +               * @name rowExpandedStateChanged
    +               * @eventOf  ui.grid.expandable.api:PublicApi
    +               * @description raised when cell editing is complete
    +               * <pre>
    +               *      gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
    +               * </pre>
    +               * @param {GridRow} row the row that was expanded
    +               */
    +              rowExpandedStateChanged: function (scope, row) {
    +              }
    +            }
    +          },
    +          
    +          methods: {
    +            expandable: {
    +              /**
    +               * @ngdoc method
    +               * @name toggleRowExpansion
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle a specific row
    +               * <pre>
    +               *      gridApi.expandable.toggleRowExpansion(rowEntity);
    +               * </pre>
    +               * @param {object} rowEntity the data entity for the row you want to expand
    +               */              
    +              toggleRowExpansion: function (rowEntity) {
    +                var row = grid.getRow(rowEntity);
    +                if (row !== null) {
    +                  service.toggleRowExpansion(grid, row);
    +                }
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name expandAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Expand all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.expandAllRows();
    +               * </pre>
    +               */              
    +              expandAllRows: function() {
    +                service.expandAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name collapseAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Collapse all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.collapseAllRows();
    +               * </pre>
    +               */              
    +              collapseAllRows: function() {
    +                service.collapseAllRows(grid);
    +              },
    +
    +              /**
    +               * @ngdoc method
    +               * @name toggleAllRows
    +               * @methodOf  ui.grid.expandable.api:PublicApi
    +               * @description Toggle all subgrids.
    +               * <pre>
    +               *      gridApi.expandable.toggleAllRows();
    +               * </pre>
    +               */              
    +              toggleAllRows: function() {
    +                service.toggleAllRows(grid);
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      
    +      toggleRowExpansion: function (grid, row) {
    +        row.isExpanded = !row.isExpanded;
    +        if (row.isExpanded) {
    +          row.height = row.grid.options.rowHeight + grid.options.expandableRowHeight;
    +        }
    +        else {
    +          row.height = row.grid.options.rowHeight;
    +          grid.expandable.expandedAll = false;
    +        }
    +        grid.api.expandable.raise.rowExpandedStateChanged(row);
    +      },
    +      
    +      expandAllRows: function(grid, $scope) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (!row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = true;
    +        grid.refresh();
    +      },
    +      
    +      collapseAllRows: function(grid) {
    +        angular.forEach(grid.renderContainers.body.visibleRowCache, function(row) {
    +          if (row.isExpanded) {
    +            service.toggleRowExpansion(grid, row);
    +          }
    +        });
    +        grid.expandable.expandedAll = false;
    +        grid.refresh();
    +      },
    +
    +      toggleAllRows: function(grid) {
    +        if (grid.expandable.expandedAll) {
    +          service.collapseAllRows(grid);
    +        }
    +        else {
    +          service.expandAllRows(grid);
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name enableExpandableRowHeader
    +   *  @propertyOf  ui.grid.expandable.api:GridOptions
    +   *  @description Show a rowHeader to provide the expandable buttons.  If set to false then implies
    +   *  you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
    +   *  @example
    +   *  <pre>
    +   *    $scope.gridOptions = {
    +   *      enableExpandableRowHeader: false
    +   *    }
    +   *  </pre>  
    +   */
    +  module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              if ( uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
    +                var expandableRowHeaderColDef = {
    +                  name: 'expandableButtons', 
    +                  displayName: '', 
    +                  exporterSuppressExport: true, 
    +                  enableColumnResizing: false, 
    +                  enableColumnMenu: false,
    +                  width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
    +                };
    +                expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
    +                expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
    +                uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef);
    +              }
    +              uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGrid
    +   *  @description stacks on the uiGrid directive to register child grid with parent row when child is created
    +   */
    +  module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
    +    function (uiGridExpandableService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 1000,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
    +                //if a parent grid row is on the scope, then add the parentRow property to this childGrid
    +                if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
    +
    +                  /**
    +                   *  @ngdoc directive
    +                   *  @name ui.grid.expandable.class:Grid
    +                   *  @description Additional Grid properties added by expandable module
    +                   */
    +
    +                  /**
    +                   *  @ngdoc object
    +                   *  @name parentRow
    +                   *  @propertyOf ui.grid.expandable.class:Grid
    +                   *  @description reference to the expanded parent row that owns this grid
    +                   */
    +                  uiGridCtrl.grid.parentRow = $scope.row;
    +
    +                  //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
    +                 // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
    +                 //   uiGridCtrl.grid.parentRow = newHeight;
    +                 // });
    +                }
    +
    +              });
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridExpandableRow
    +   *  @description directive to render the expandable row template
    +   */
    +  module.directive('uiGridExpandableRow',
    +  ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
    +    function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
    +
    +      return {
    +        replace: false,
    +        priority: 0,
    +        scope: false,
    +
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
    +                function (template) {
    +                  if ($scope.grid.options.expandableRowScope) {
    +                    var expandableRowScope = $scope.grid.options.expandableRowScope;
    +                    for (var property in expandableRowScope) {
    +                      if (expandableRowScope.hasOwnProperty(property)) {
    +                        $scope[property] = expandableRowScope[property];
    +                      }
    +                    }
    +                  }
    +                  var expandedRowElement = $compile(template)($scope);
    +                  $elm.append(expandedRowElement);
    +                  $scope.row.expandedRendered = true;
    +              });
    +            },
    +
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              $scope.$on('$destroy', function() {
    +                $scope.row.expandedRendered = false;
    +              });
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridRow
    +   *  @description stacks on the uiGridRow directive to add support for expandable rows
    +   */
    +  module.directive('uiGridRow',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +                $scope.expandableRow = {};
    +
    +                $scope.expandableRow.shouldRenderExpand = function () {
    +                  var ret = $scope.colContainer.name === 'body' &&  $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
    +                  return ret;
    +                };
    +
    +                $scope.expandableRow.shouldRenderFiller = function () {
    +                  var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
    +                  return ret;
    +                };
    +
    +                  function updateRowContainerWidth() {
    +                      var grid = $scope.grid;
    +                      var colWidth = 0;
    +                      angular.forEach(grid.columns, function (column) {
    +                          if (column.renderContainer === 'left') {
    +                            colWidth += column.width;
    +                          }
    +                      });
    +                      colWidth = Math.floor(colWidth);
    +                      return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
    +                          ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
    +                          ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
    +                  }
    +
    +                  if ($scope.colContainer.name === 'left') {
    +                      $scope.grid.registerStyleComputation({
    +                          priority: 15,
    +                          func: updateRowContainerWidth
    +                      });
    +                  }
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.expandable.directive:uiGridViewport
    +   *  @description stacks on the uiGridViewport directive to append the expandable row html elements to the
    +   *  default gridRow template
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', '$templateCache',
    +      function ($compile, gridUtil, $templateCache) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
    +            var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
    +            rowRepeatDiv.append(expandedRowElement);
    +            rowRepeatDiv.append(expandedRowFillerElement);
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +/* global console */
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.exporter
    +   * @description
    +   *
    +   *  # ui.grid.exporter
    +   * This module provides the ability to exporter data from the grid.  
    +   * 
    +   * Data can be exported in a range of formats, and all data, visible 
    +   * data, or selected rows can be exported, with all columns or visible
    +   * columns.
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate, or enable the gridMenu
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.exporter"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.exporter', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.exporter.constant:uiGridExporterConstants
    +   *
    +   *  @description constants available in exporter module
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name ALL
    +   * @description export all data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name VISIBLE
    +   * @description export only visible data, including data not visible.  Can
    +   * be set for either rowTypes or colTypes
    +   */
    +  /**
    +   * @ngdoc property
    +   * @propertyOf ui.grid.exporter.constant:uiGridExporterConstants
    +   * @name SELECTED
    +   * @description export all data, including data not visible.  Can
    +   * be set only for rowTypes, selection of only some columns is 
    +   * not supported
    +   */
    +  module.constant('uiGridExporterConstants', {
    +    featureName: 'exporter',
    +    ALL: 'all',
    +    VISIBLE: 'visible',
    +    SELECTED: 'selected',
    +    CSV_CONTENT: 'CSV_CONTENT',
    +    BUTTON_LABEL: 'BUTTON_LABEL',
    +    FILE_NAME: 'FILE_NAME'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.exporter.service:uiGridExporterService
    +   *
    +   *  @description Services for exporter feature
    +   */
    +  module.service('uiGridExporterService', ['$q', 'uiGridExporterConstants', 'uiGridSelectionConstants', 'gridUtil', '$compile', '$interval', 'i18nService',
    +    function ($q, uiGridExporterConstants, uiGridSelectionConstants, gridUtil, $compile, $interval, i18nService) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.exporter = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.exporter.api:PublicApi
    +           *
    +           *  @description Public Api for exporter feature
    +           */
    +          var publicApi = {
    +            events: {
    +              exporter: {
    +              }
    +            },
    +            methods: {
    +              exporter: {
    +                /**
    +                 * @ngdoc function
    +                 * @name csvExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in csv format, 
    +                 * the data exported is selected based on the provided options
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                csvExport: function (rowTypes, colTypes) {
    +                  service.csvExport(grid, rowTypes, colTypes);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name pdfExport
    +                 * @methodOf  ui.grid.exporter.api:PublicApi
    +                 * @description Exports rows from the grid in pdf format, 
    +                 * the data exported is selected based on the provided options
    +                 * Note that this function has a dependency on pdfMake, all
    +                 * going well this has been installed for you.
    +                 * The resulting pdf opens in a new browser window.
    +                 * @param {string} rowTypes which rows to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +                 * uiGridExporterConstants.SELECTED
    +                 * @param {string} colTypes which columns to export, valid values are
    +                 * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE
    +                 */
    +                pdfExport: function (rowTypes, colTypes) {
    +                  service.pdfExport(grid, rowTypes, colTypes);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          if (grid.api.core.addToGridMenu){
    +            service.addToMenu( grid );
    +          } else {
    +            // order of registration is not guaranteed, register in a little while
    +            $interval( function() {
    +              if (grid.api.core.addToGridMenu){
    +                service.addToMenu( grid );
    +              }              
    +            }, 100, 1);
    +          }
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:GridOptions
    +           *
    +           * @description GridOptions for exporter feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.exporter.api:ColumnDef
    +           * @description ColumnDef settings for exporter
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressMenu
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Don't show the export menu button, implying the user
    +           * will roll their own UI for calling the exporter
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.exporterSuppressMenu = gridOptions.exporterSuppressMenu === true;
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuLabel
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The text to show on the exporter menu button
    +           * link
    +           * <br/>Defaults to 'Export'
    +           */
    +          gridOptions.exporterMenuLabel = gridOptions.exporterMenuLabel ? gridOptions.exporterMenuLabel : 'Export';
    +          /**
    +           * @ngdoc object
    +           * @name exporterSuppressColumns
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Columns that should not be exported.  The selectionRowHeader is already automatically
    +           * suppressed, but if you had a button column or some other "system" column that shouldn't be shown in the
    +           * output then add it in this list.  You should provide an array of column names.
    +           * <br/>Defaults to: []
    +           * <pre>
    +           *   gridOptions.exporterSuppressColumns = [ 'buttons' ];
    +           * </pre>
    +           */
    +          gridOptions.exporterSuppressColumns = gridOptions.exporterSuppressColumns ? gridOptions.exporterSuppressColumns : [];
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvColumnSeparator
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The character to use as column separator
    +           * link
    +           * <br/>Defaults to ','
    +           */
    +          gridOptions.exporterCsvColumnSeparator = gridOptions.exporterCsvColumnSeparator ? gridOptions.exporterCsvColumnSeparator : ',';
    +          /**
    +           * @ngdoc object
    +           * @name exporterCsvFilename
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default filename to use when saving the downloaded csv.  
    +           * This will only work in some browsers.
    +           * <br/>Defaults to 'download.csv'
    +           */
    +          gridOptions.exporterCsvFilename = gridOptions.exporterCsvFilename ? gridOptions.exporterCsvFilename : 'download.csv';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfDefaultStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The default style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     fontSize: 11
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfDefaultStyle = gridOptions.exporterPdfDefaultStyle ? gridOptions.exporterPdfDefaultStyle : { fontSize: 11 };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The table style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     margin: [0, 5, 0, 15]
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableStyle = gridOptions.exporterPdfTableStyle ? gridOptions.exporterPdfTableStyle : { margin: [0, 5, 0, 15] };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableHeaderStyle
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The tableHeader style in pdfMake format
    +           * <br/>Defaults to:
    +           * <pre>
    +           *   {
    +           *     bold: true,
    +           *     fontSize: 12,
    +           *     color: 'black'
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfTableHeaderStyle = gridOptions.exporterPdfTableHeaderStyle ? gridOptions.exporterPdfTableHeaderStyle : { bold: true, fontSize: 12, color: 'black' };
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfHeader
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = 'My Header';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfHeader: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfHeader = gridOptions.exporterPdfHeader ? gridOptions.exporterPdfHeader : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfFooter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The header section for pdf exports.  Can be
    +           * simple text:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = 'My Footer';
    +           * </pre>
    +           * Can be a more complex object in pdfMake format:
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter = {
    +           *     columns: [
    +           *       'Left part',
    +           *       { text: 'Right part', alignment: 'right' }
    +           *     ]
    +           *   };
    +           * </pre>
    +           * Or can be a function, allowing page numbers and the like
    +           * <pre>
    +           *   gridOptions.exporterPdfFooter: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; };
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfFooter = gridOptions.exporterPdfFooter ? gridOptions.exporterPdfFooter : null;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfOrientation
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake value,
    +           * 'landscape' or 'portrait'
    +           * <br/>Defaults to landscape
    +           */
    +          gridOptions.exporterPdfOrientation = gridOptions.exporterPdfOrientation ? gridOptions.exporterPdfOrientation : 'landscape';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfPageSize
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The orientation, should be a valid pdfMake
    +           * paper size, usually 'A4' or 'LETTER'
    +           * {@link https://github.com/bpampuch/pdfmake/blob/master/src/standardPageSizes.js pdfMake page sizes}
    +           * <br/>Defaults to A4
    +           */
    +          gridOptions.exporterPdfPageSize = gridOptions.exporterPdfPageSize ? gridOptions.exporterPdfPageSize : 'A4';
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfMaxGridWidth
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description The maxium grid width - the current grid width 
    +           * will be scaled to match this, with any fixed width columns
    +           * being adjusted accordingly.
    +           * <br/>Defaults to 720 (for A4 landscape), use 670 for LETTER 
    +           */
    +          gridOptions.exporterPdfMaxGridWidth = gridOptions.exporterPdfMaxGridWidth ? gridOptions.exporterPdfMaxGridWidth : 720;
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfTableLayout
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A tableLayout in pdfMake format, 
    +           * controls gridlines and the like.  We use the default
    +           * layout usually.
    +           * <br/>Defaults to null, which means no layout 
    +           */
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuCsv
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add csv export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuCsv = gridOptions.exporterMenuCsv !== undefined ? gridOptions.exporterMenuCsv : true;
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterMenuPdf
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Add pdf export menu items to the ui-grid grid menu, if it's present.  Defaults to true.
    +           */
    +          gridOptions.exporterMenuPdf = gridOptions.exporterMenuPdf !== undefined ? gridOptions.exporterMenuPdf : true;
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterPdfCustomFormatter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A custom callback routine that changes the pdf document, adding any
    +           * custom styling or content that is supported by pdfMake.  Takes in the complete docDefinition, and
    +           * must return an updated docDefinition ready for pdfMake.
    +           * @example
    +           * In this example we add a style to the style array, so that we can use it in our
    +           * footer definition.
    +           * <pre>
    +           *   gridOptions.exporterPdfCustomFormatter = function ( docDefinition ) {
    +           *     docDefinition.styles.footerStyle = { bold: true, fontSize: 10 };
    +           *     return docDefinition;
    +           *   }
    +           * 
    +           *   gridOptions.exporterPdfFooter = { text: 'My footer', style: 'footerStyle' }
    +           * </pre>
    +           */
    +          gridOptions.exporterPdfCustomFormatter = ( gridOptions.exporterPdfCustomFormatter && typeof( gridOptions.exporterPdfCustomFormatter ) === 'function' ) ? gridOptions.exporterPdfCustomFormatter : function ( docDef ) { return docDef; };
    +          
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilterUseName
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description Defaults to false, which leads to `displayName` being passed into the headerFilter.
    +           * If set to true, then will pass `name` instead.
    +           * 
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilterUseName = true;
    +           * </pre>
    +           */
    +          gridOptions.exporterHeaderFilterUseName = gridOptions.exporterHeaderFilterUseName === true;          
    +
    +          /**
    +           * @ngdoc object
    +           * @name exporterHeaderFilter
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to apply to the header displayNames before exporting.  Useful for internationalisation,
    +           * for example if you were using angular-translate you'd set this to `$translate.instant`.  Note that this
    +           * call must be synchronous, it cannot be a call that returns a promise.
    +           * 
    +           * Behaviour can be changed to pass in `name` instead of `displayName` through use of `exporterHeaderFilterUseName: true`.
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = function( displayName ){ return 'col: ' + name; };
    +           * </pre>
    +           * OR
    +           * <pre>
    +           *   gridOptions.exporterHeaderFilter = $translate.instant;
    +           * </pre>
    +           */
    +          
    +          /**
    +           * @ngdoc function
    +           * @name exporterFieldCallback
    +           * @propertyOf  ui.grid.exporter.api:GridOptions
    +           * @description A function to call for each field before exporting it.  Allows 
    +           * massaging of raw data into a display format, for example if you have applied 
    +           * filters to convert codes into decodes, or you require
    +           * a specific date format in the exported content.
    +           * 
    +           * The method is called once for each field exported, and provides the grid, the
    +           * gridCol and the GridRow for you to use as context in massaging the data.
    +           * 
    +           * @param {Grid} grid provides the grid in case you have need of it
    +           * @param {GridRow} row the row from which the data comes
    +           * @param {GridCol} col the column from which the data comes
    +           * @param {object} value the value for your massaging
    +           * @returns {object} you must return the massaged value ready for exporting
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.exporterFieldCallback = function ( grid, row, col, value ){
    +           *     if ( col.name === 'status' ){
    +           *       value = decodeStatus( value );
    +           *     }
    +           *     return value;
    +           *   }
    +           * </pre>
    +           */
    +          gridOptions.exporterFieldCallback = gridOptions.exporterFieldCallback ? gridOptions.exporterFieldCallback : function( grid, row, col, value ) { return value; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Adds export items to the grid menu,
    +         * allowing the user to select export options 
    +         * @param {Grid} grid the grid from which data should be exported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'),
    +              action: function ($event) {
    +                this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuCsv &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.ALL, uiGridExporterConstants.ALL );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf; 
    +              }
    +            },
    +            {
    +              title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'),
    +              action: function ($event) {
    +                this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
    +              },
    +              shown: function() {
    +                return this.grid.options.exporterMenuPdf &&
    +                       ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); 
    +              }
    +            }
    +          ]);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name csvExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in csv format, 
    +         * the data exported is selected based on the provided options
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        csvExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var csvContent = this.formatAsCsv(exportColumnHeaders, exportData, grid.options.exporterCsvColumnSeparator);
    +          
    +          this.downloadFile (grid.options.exporterCsvFilename, csvContent);
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterSuppressExport
    +         * @description Suppresses export for this column.  Used by selection and expandable.
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getColumnHeaders
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets the column headers from the grid to use
    +         * as a title row for the exported file, all headers have 
    +         * headerCellFilters applied as appropriate.
    +         * 
    +         * Column headers are an array of objects, each object has
    +         * name, displayName, width and align attributes.  Only name is
    +         * used for csv, all attributes are used for pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getColumnHeaders: function (grid, colTypes) {
    +          var headers = [];
    +          angular.forEach(grid.columns, function( gridCol, index ) {
    +            if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                 gridCol.colDef.exporterSuppressExport !== true &&
    +                 grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +              headers.push({
    +                name: gridCol.field,
    +                displayName: grid.options.exporterHeaderFilter ? ( grid.options.exporterHeaderFilterUseName ? grid.options.exporterHeaderFilter(gridCol.name) : grid.options.exporterHeaderFilter(gridCol.displayName) ) : gridCol.displayName,
    +                width: gridCol.drawnWidth ? gridCol.drawnWidth : gridCol.width,
    +                align: gridCol.colDef.type === 'number' ? 'right' : 'left'
    +              });
    +            }
    +          });
    +          
    +          return headers;
    +        },
    +        
    +        
    +        /** 
    +         * @ngdoc property
    +         * @propertyOf ui.grid.exporter.api:ColumnDef
    +         * @name exporterPdfAlign
    +         * @description the alignment you'd like for this specific column when
    +         * exported into a pdf.  Can be 'left', 'right', 'center' or any other
    +         * valid pdfMake alignment option.
    +         */
    +
    +
    +        /**
    +         * @ngdoc object
    +         * @name ui.grid.exporter.api:GridRow
    +         * @description GridRow settings for exporter
    +         */
    +        /**
    +         * @ngdoc object
    +         * @name exporterEnableExporting
    +         * @propertyOf  ui.grid.exporter.api:GridRow
    +         * @description If set to false, then don't export this row, notwithstanding visible or 
    +         * other settings
    +         * <br/>Defaults to true
    +         */
    +
    +        /**
    +         * @ngdoc function
    +         * @name getData
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Gets data from the grid based on the provided options,
    +         * all cells have cellFilters applied as appropriate.  Any rows marked
    +         * `exporterEnableExporting: false` will not be exported
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        getData: function (grid, rowTypes, colTypes) {
    +          var data = [];
    +          
    +          var rows;
    +          
    +          switch ( rowTypes ) {
    +            case uiGridExporterConstants.ALL:
    +              rows = grid.rows; 
    +              break;
    +            case uiGridExporterConstants.VISIBLE:
    +              rows = grid.getVisibleRows();
    +              break;
    +            case uiGridExporterConstants.SELECTED:
    +              if ( grid.api.selection ){
    +                rows = grid.api.selection.getSelectedGridRows();
    +              } else {
    +                gridUtil.logError('selection feature must be enabled to allow selected rows to be exported');
    +              }
    +              break;
    +          }
    +          
    +          angular.forEach(rows, function( row, index ) {
    +
    +            if (row.exporterEnableExporting !== false) {
    +              var extractedRow = [];
    +              angular.forEach(grid.columns, function( gridCol, index ) {
    +              if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) && 
    +                   gridCol.colDef.exporterSuppressExport !== true &&
    +                   grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
    +                  var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
    +                  if ( gridCol.colDef.exporterPdfAlign ) {
    +                    extractedField.alignment = gridCol.colDef.exporterPdfAlign;                 
    +                  }
    +                  extractedRow.push(extractedField);
    +                }
    +              });
    +              
    +              data.push(extractedRow);
    +            }
    +          });
    +          
    +          return data;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatAsCSV
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Formats the column headers and data as a CSV, 
    +         * and sends that data to the user
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {string} csv the formatted csv as a string
    +         */
    +        formatAsCsv: function (exportColumnHeaders, exportData, separator) {
    +          var self = this;
    +          
    +          var bareHeaders = exportColumnHeaders.map(function(header){return { value: header.displayName };});
    +          
    +          var csv = self.formatRowAsCsv(this, separator)(bareHeaders) + '\n';
    +          
    +          csv += exportData.map(this.formatRowAsCsv(this, separator)).join('\n');
    +          
    +          return csv;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsCsv: function (exporter, separator) {
    +          return function (row) {
    +            return row.map(exporter.formatFieldAsCsv).join(separator);
    +          };
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a csv field, including
    +         * quotes around the value
    +         * @param {field} field the field to be turned into a csv string,
    +         * may be of any type
    +         * @returns {string} a csv-ified version of the field
    +         */
    +        formatFieldAsCsv: function (field) {
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            return '';
    +          }
    +          if (typeof(field.value) === 'number') {
    +            return field.value;
    +          }
    +          if (typeof(field.value) === 'boolean') {
    +            return (field.value ? 'TRUE' : 'FALSE') ;
    +          }
    +          if (typeof(field.value) === 'string') {
    +            return '"' + field.value.replace(/"/g,'""') + '"';
    +          }
    +
    +          return JSON.stringify(field.value);        
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name isIE
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Checks whether current browser is IE and returns it's version if it is
    +        */
    +        isIE: function () {
    +            var myNav = navigator.userAgent.toLowerCase();
    +            return (myNav.indexOf('msie') !== -1) ? parseInt(myNav.split('msie')[1]) : false;
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name downloadFile
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Triggers download of a csv file.  Logic provided
    +         * by @cssensei (from his colleagues at https://github.com/ifeelgoods) in issue #2391
    +         * @param {string} fileName the filename we'd like our file to be
    +         * given
    +         * @param {string} csvContent the csv content that we'd like to 
    +         * download as a file
    +         */
    +        downloadFile: function (fileName, csvContent) {
    +          var D = document;
    +          var a = D.createElement('a');
    +          var strMimeType = 'application/octet-stream;charset=utf-8';
    +          var rawFile;
    +          var ieVersion;
    +      
    +          if (!fileName) {
    +            var currentDate = new Date();
    +            fileName = "CWS Export - " + currentDate.getFullYear() + (currentDate.getMonth() + 1) +
    +                       currentDate.getDate() + currentDate.getHours() +
    +                       currentDate.getMinutes() + currentDate.getSeconds() + ".csv";
    +          }
    +
    +          ieVersion = this.isIE();
    +          if (ieVersion && ieVersion < 10) {
    +            var frame = D.createElement('iframe');
    +            document.body.appendChild(frame);
    +        
    +            frame.contentWindow.document.open("text/html", "replace");
    +            frame.contentWindow.document.write('sep=,\r\n' + csvContent);
    +            frame.contentWindow.document.close();
    +            frame.contentWindow.focus();
    +            frame.contentWindow.document.execCommand('SaveAs', true, fileName);
    +        
    +            document.body.removeChild(frame);
    +            return true;
    +          }
    +        
    +          // IE10+
    +          if (navigator.msSaveBlob) {
    +            return navigator.msSaveBlob(new Blob(["\ufeff", csvContent], {
    +              type: strMimeType
    +            }), fileName);
    +          }
    +      
    +          //html5 A[download]
    +          if ('download' in a) {
    +            var blob = new Blob([csvContent], {
    +              type: strMimeType
    +            });
    +            rawFile = URL.createObjectURL(blob);
    +            a.setAttribute('download', fileName);
    +          } else {
    +            rawFile = 'data:' + strMimeType + ',' + encodeURIComponent(csvContent);
    +            a.setAttribute('target', '_blank');
    +          }
    +      
    +          a.href = rawFile;
    +          a.setAttribute('style', 'display:none;');
    +          D.body.appendChild(a);
    +          setTimeout(function() {
    +            if (a.click) {
    +              a.click();
    +              // Workaround for Safari 5
    +            } else if (document.createEvent) {
    +              var eventObj = document.createEvent('MouseEvents');
    +              eventObj.initEvent('click', true, true);
    +              a.dispatchEvent(eventObj);
    +            }
    +            D.body.removeChild(a);
    +    
    +          }, 100);
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name pdfExport
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Exports rows from the grid in pdf format, 
    +         * the data exported is selected based on the provided options.
    +         * Note that this function has a dependency on pdfMake, which must
    +         * be installed.  The resulting pdf opens in a new
    +         * browser window.
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {string} rowTypes which rows to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         * @param {string} colTypes which columns to export, valid values are
    +         * uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
    +         * uiGridExporterConstants.SELECTED
    +         */
    +        pdfExport: function (grid, rowTypes, colTypes) {
    +          var exportColumnHeaders = this.getColumnHeaders(grid, colTypes);
    +          var exportData = this.getData(grid, rowTypes, colTypes);
    +          var docDefinition = this.prepareAsPdf(grid, exportColumnHeaders, exportData);
    +          
    +          pdfMake.createPdf(docDefinition).open();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name renderAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders the data into a pdf, and opens that pdf.
    +         * 
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {array} exportColumnHeaders an array of column headers, 
    +         * where each header is an object with name, width and maybe alignment
    +         * @param {array} exportData an array of rows, where each row is
    +         * an array of column data
    +         * @returns {object} a pdfMake format document definition, ready 
    +         * for generation
    +         */        
    +        prepareAsPdf: function(grid, exportColumnHeaders, exportData) {
    +          var headerWidths = this.calculatePdfHeaderWidths( grid, exportColumnHeaders );
    +          
    +          var headerColumns = exportColumnHeaders.map( function( header ) {
    +            return { text: header.displayName, style: 'tableHeader' }; 
    +          });
    +          
    +          var stringData = exportData.map(this.formatRowAsPdf(this));
    +          
    +          var allData = [headerColumns].concat(stringData);
    +          
    +          var docDefinition = {
    +            pageOrientation: grid.options.exporterPdfOrientation,
    +            pageSize: grid.options.exporterPdfPageSize,
    +            content: [{
    +              style: 'tableStyle',
    +              table: {
    +                headerRows: 1,
    +                widths: headerWidths,
    +                body: allData 
    +              }
    +            }],
    +            styles: {
    +              tableStyle: grid.options.exporterPdfTableStyle,
    +              tableHeader: grid.options.exporterPdfTableHeaderStyle
    +            },
    +            defaultStyle: grid.options.exporterPdfDefaultStyle
    +          };
    +          
    +          if ( grid.options.exporterPdfLayout ){
    +            docDefinition.layout = grid.options.exporterPdfLayout;
    +          }
    +          
    +          if ( grid.options.exporterPdfHeader ){
    +            docDefinition.header = grid.options.exporterPdfHeader;
    +          }
    +          
    +          if ( grid.options.exporterPdfFooter ){
    +            docDefinition.footer = grid.options.exporterPdfFooter;
    +          }
    +          
    +          if ( grid.options.exporterPdfCustomFormatter ){
    +            docDefinition = grid.options.exporterPdfCustomFormatter( docDefinition );
    +          }
    +          return docDefinition;
    +          
    +        },
    +        
    +                
    +        /**
    +         * @ngdoc function
    +         * @name calculatePdfHeaderWidths
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Determines the column widths base on the 
    +         * widths we got from the grid.  If the column is drawn
    +         * then we have a drawnWidth.  If the column is not visible
    +         * then we have '*', 'x%' or a width.  When columns are
    +         * not visible they don't contribute to the overall gridWidth,
    +         * so we need to adjust to allow for extra columns
    +         * 
    +         * Our basic heuristic is to take the current gridWidth, plus 
    +         * numeric columns and call this the base gridwidth.
    +         * 
    +         * To that we add 100 for any '*' column, and x% of the base gridWidth
    +         * for any column that is a %
    +         *  
    +         * @param {Grid} grid the grid from which data should be exported
    +         * @param {object} exportHeaders array of header information 
    +         * @returns {object} an array of header widths
    +         */
    +        calculatePdfHeaderWidths: function ( grid, exportHeaders ) {
    +          var baseGridWidth = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (typeof(value.width) === 'number'){
    +              baseGridWidth += value.width;
    +            }
    +          });
    +          
    +          var extraColumns = 0;
    +          angular.forEach(exportHeaders, function(value){
    +            if (value.width === '*'){
    +              extraColumns += 100;
    +            }
    +            if (typeof(value.width) === 'string' && value.width.match(/(\d)*%/)) {
    +              var percent = parseInt(value.width.match(/(\d)*%/)[0]);
    +              
    +              value.width = baseGridWidth * percent / 100;
    +              extraColumns += value.width;
    +            }
    +          });
    +          
    +          var gridWidth = baseGridWidth + extraColumns;
    +          
    +          return exportHeaders.map(function( header ) {
    +            return header.width === '*' ? header.width : header.width * grid.options.exporterPdfMaxGridWidth / gridWidth;
    +          });
    +          
    +        },
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatRowAsPdf
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a row in a format consumable by PDF,
    +         * mainly meaning casting everything to a string
    +         * @param {exporterService} exporter pass in exporter 
    +         * @param {array} row the row to be turned into a csv string
    +         * @returns {string} a csv-ified version of the row
    +         */
    +        formatRowAsPdf: function ( exporter ) {
    +          return function( row ) {
    +            return row.map(exporter.formatFieldAsPdfString);
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name formatFieldAsCsv
    +         * @methodOf  ui.grid.exporter.service:uiGridExporterService
    +         * @description Renders a single field as a pdf-able field, which
    +         * is different from a csv field only in that strings don't have quotes
    +         * around them
    +         * @param {field} field the field to be turned into a pdf string,
    +         * may be of any type
    +         * @returns {string} a string-ified version of the field
    +         */
    +        formatFieldAsPdfString: function (field) {
    +          var returnVal;
    +          if (field.value == null) { // we want to catch anything null-ish, hence just == not ===
    +            returnVal = '';
    +          } else if (typeof(field.value) === 'number') {
    +            returnVal = field.value.toString();
    +          } else if (typeof(field.value) === 'boolean') {
    +            returnVal = (field.value ? 'TRUE' : 'FALSE') ;
    +          } else if (typeof(field.value) === 'string') {
    +            returnVal = field.value.replace(/"/g,'""');
    +          } else {
    +            returnVal = JSON.stringify(field.value).replace(/^"/,'').replace(/"$/,'');        
    +          }
    +          
    +          if (field.alignment && typeof(field.alignment) === 'string' ){
    +            returnVal = { text: returnVal, alignment: field.alignment };
    +          }
    +          
    +          return returnVal;
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.exporter.directive:uiGridExporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds exporter features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.exporter']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        enableGridMenu: true,
    +        exporterMenuCsv: false,
    +        columnDefs: [
    +          {name: 'name', enableCellEdit: true},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-exporter></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridExporter', ['uiGridExporterConstants', 'uiGridExporterService', 'gridUtil', '$compile',
    +    function (uiGridExporterConstants, uiGridExporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridExporterService.initializeGrid(uiGridCtrl.grid);
    +          uiGridCtrl.grid.exporter.$scope = $scope;
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.importer
    +   * @description
    +   *
    +   *  # ui.grid.importer
    +   * This module provides the ability to import data into the grid. It
    +   * uses the column defs to work out which data belongs in which column, 
    +   * and creates entities from a configured class (typically a $resource).
    +   * 
    +   * If the rowEdit feature is enabled, it also calls save on those newly 
    +   * created objects, and then displays any errors in the imported data.  
    +   * 
    +   * Currently the importer imports only CSV and json files, although provision has been
    +   * made to process other file formats, and these can be added over time.  
    +   * 
    +   * For json files, the properties within each object in the json must match the column names
    +   * (to put it another way, the importer doesn't process the json, it just copies the objects
    +   * within the json into a new instance of the specified object type)
    +   * 
    +   * For CSV import, the default column identification relies on each column in the
    +   * header row matching a column.name or column.displayName. Optionally, a column identification 
    +   * callback can be used.  This allows matching using other attributes, which is particularly
    +   * useful if your application has internationalised column headings (i.e. the headings that 
    +   * the user sees don't match the column names).
    +   * 
    +   * The importer makes use of the grid menu as the UI for requesting an
    +   * import. 
    +   *
    +   * <div ui-grid-importer></div>
    +   */
    +
    +  var module = angular.module('ui.grid.importer', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.importer.constant:uiGridImporterConstants
    +   *
    +   *  @description constants available in importer module
    +   */
    +
    +  module.constant('uiGridImporterConstants', {
    +    featureName: 'importer'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.importer.service:uiGridImporterService
    +   *
    +   *  @description Services for importer feature
    +   */
    +  module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
    +    function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
    +
    +      var service = {
    +
    +        initializeGrid: function ($scope, grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.importer = {
    +            $scope: $scope 
    +          };
    +          
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.importer.api:PublicApi
    +           *
    +           *  @description Public Api for importer feature
    +           */
    +          var publicApi = {
    +            events: {
    +              importer: {
    +              }
    +            },
    +            methods: {
    +              importer: {
    +                /**
    +                 * @ngdoc function
    +                 * @name importFile
    +                 * @methodOf  ui.grid.importer.api:PublicApi
    +                 * @description Imports a file into the grid using the file object 
    +                 * provided.  Bypasses the grid menu
    +                 * @param {File} fileObject the file we want to import, as a javascript
    +                 * File object
    +                 */
    +                importFile: function ( fileObject ) {
    +                  service.importThisFile( grid, fileObject );
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +          if ( grid.options.enableImporter && grid.options.importerShowMenu ){
    +            if ( grid.api.core.addToGridMenu ){
    +              service.addToMenu( grid );
    +            } else {
    +              // order of registration is not guaranteed, register in a little while
    +              $interval( function() {
    +                if (grid.api.core.addToGridMenu){
    +                  service.addToMenu( grid );
    +                }             
    +              }, 100, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.importer.api:GridOptions
    +           *
    +           * @description GridOptions for importer feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name enableImporter
    +           * @description Whether or not importer is enabled.  Automatically set
    +           * to false if the user's browser does not support the required fileApi.
    +           * Otherwise defaults to true.
    +           * 
    +           */
    +          if (gridOptions.enableImporter  || gridOptions.enableImporter === undefined) {
    +            if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
    +              gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
    +              gridOptions.enableImporter = false;
    +            } else {
    +              gridOptions.enableImporter = true;
    +            }
    +          } else {
    +            gridOptions.enableImporter = false;
    +          }
    +          
    +          /**
    +           * @ngdoc method
    +           * @name importerProcessHeaders
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will process headers using custom
    +           * logic.  Set this callback function if the headers that your user will provide in their 
    +           * import file don't necessarily match the grid header or field names.  This might commonly
    +           * occur where your application is internationalised, and therefore the field names
    +           * that the user recognises are in a different language than the field names that
    +           * ui-grid knows about.
    +           * 
    +           * Defaults to the internal `processHeaders` method, which seeks to match using both
    +           * displayName and column.name.  Any non-matching columns are discarded.
    +           * 
    +           * Your callback routine should respond by processing the header array, and returning an array
    +           * of matching column names.  A null value in any given position means "don't import this column"
    +           * 
    +           * <pre>
    +           *      gridOptions.importerProcessHeaders: function( headerArray ) {
    +           *        var myHeaderColumns = [];
    +           *        var thisCol;
    +           *        headerArray.forEach( function( value, index ) {
    +           *          thisCol = mySpecialLookupFunction( value );
    +           *          myHeaderColumns.push( thisCol.name ); 
    +           *        });
    +           *        
    +           *        return myHeaderCols;
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into
    +           * @param {array} headerArray an array of the text from the first row of the csv file,
    +           * which you need to match to column.names
    +           * @returns {array} array of matching column names, in the same order as the headerArray
    +           * 
    +           */
    +          gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerHeaderFilter
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that will filter (usually translate) a single
    +           * header.  Used when you want to match the passed in column names to the column
    +           * displayName after the header filter.
    +           * 
    +           * Your callback routine needs to return the filtered header value. 
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: function( displayName ) {
    +           *        return $translate.instant( displayName );
    +           *      })
    +           * </pre>
    +           * 
    +           * or:
    +           * <pre>
    +           *      gridOptions.importerHeaderFilter: $translate.instant
    +           * </pre>
    +           * @param {string} displayName the displayName that we'd like to translate
    +           * @returns {string} the translated name
    +           * 
    +           */
    +          gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerErrorCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A callback function that provides custom error handling, rather
    +           * than the standard grid behaviour of an alert box and a console message.  You 
    +           * might use this to internationalise the console log messages, or to write to a 
    +           * custom logging routine that returned errors to the server.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
    +           *        myUserDisplayRoutine( errorKey );
    +           *        myLoggingRoutine( consoleMessage, context );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
    +           * in some way
    +           * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders, 
    +           * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
    +           * @param {string} consoleMessage the English console message that importer would have written
    +           * @param {object} context the context data that importer would have appended to that console message,
    +           * often the file content itself or the element that is in error
    +           * 
    +           */
    +          if ( !gridOptions.importerErrorCallback ||  typeof(gridOptions.importerErrorCallback) !== 'function' ){
    +            delete gridOptions.importerErrorCallback;  
    +          }
    +
    +          /**
    +           * @ngdoc method
    +           * @name importerDataAddCallback
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @description A mandatory callback function that adds data to the source data array.  The grid
    +           * generally doesn't add rows to the source data array, it is tidier to handle this through a user
    +           * callback.
    +           * 
    +           * <pre>
    +           *      gridOptions.importerDataAddCallback: function( grid, newObjects ) {
    +           *        $scope.myData = $scope.myData.concat( newObjects );
    +           *      })
    +           * </pre>
    +           * @param {Grid} grid the grid we're importing into, may be useful in some way
    +           * @param {array} newObjects an array of new objects that you should add to your data
    +           * 
    +           */
    +          if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
    +            gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
    +            gridOptions.enableImporter = false;
    +          }
    +                    
    +          /**
    +           * @ngdoc object
    +           * @name importerNewObject
    +           * @propertyOf  ui.grid.importer.api:GridOptions
    +           * @description An object on which we call `new` to create each new row before inserting it into
    +           * the data array.  Typically this would be a $resource entity, which means that if you're using 
    +           * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
    +           * 
    +           * Defaults to a vanilla javascript object
    +           * 
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerNewObject = MyRes;
    +           * </pre>
    +           * 
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @propertyOf ui.grid.importer.api:GridOptions
    +           * @name importerShowMenu
    +           * @description Whether or not to show an item in the grid menu.  Defaults to true.
    +           * 
    +           */
    +          gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
    +          
    +          /**
    +           * @ngdoc method
    +           * @methodOf ui.grid.importer.api:GridOptions
    +           * @name importerObjectCallback
    +           * @description A callback that massages the data for each object.  For example,
    +           * you might have data stored as a code value, but display the decode.  This callback
    +           * can be used to change the decoded value back into a code.  Defaults to doing nothing.
    +           * @param {Grid} grid in case you need it
    +           * @param {object} newObject the new object as importer has created it, modify it
    +           * then return the modified version
    +           * @returns {object} the modified object
    +           * @example
    +           * <pre>
    +           *   gridOptions.importerObjectCallback = function ( grid, newObject ) {
    +           *     switch newObject.status {
    +           *       case 'Active':
    +           *         newObject.status = 1;
    +           *         break;
    +           *       case 'Inactive':
    +           *         newObject.status = 2;
    +           *         break;
    +           *     }
    +           *     return newObject;
    +           *   };
    +           * </pre>
    +           */
    +          gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name addToMenu
    +         * @methodOf  ui.grid.importer.service:uiGridImporterService
    +         * @description Adds import menu item to the grid menu,
    +         * allowing the user to request import of a file 
    +         * @param {Grid} grid the grid into which data should be imported
    +         */
    +        addToMenu: function ( grid ) {
    +          grid.api.core.addToGridMenu( grid, [
    +            {
    +              title: i18nService.getSafeText('gridMenu.importerTitle')
    +            },
    +            {
    +              templateUrl: 'ui-grid/importerMenuItemContainer',
    +              action: function ($event) {
    +                this.grid.api.importer.importAFile( grid );
    +              }
    +            }
    +          ]);
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importThisFile
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Imports the provided file into the grid using the file object 
    +         * provided.  Bypasses the grid menu
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {File} fileObject the file we want to import, as returned from the File
    +         * javascript object
    +         */
    +        importThisFile: function ( grid, fileObject ) {
    +          if (!fileObject){
    +            gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
    +            return;
    +          }
    +          
    +          var reader = new FileReader();
    +          
    +          switch ( fileObject.type ){
    +            case 'application/json':
    +              reader.onload = service.importJsonClosure( grid );
    +              break;
    +            default:
    +              reader.onload = service.importCsvClosure( grid );
    +              break;
    +          }
    +          
    +          reader.readAsText( fileObject );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a json file into the grid.
    +         * The json data is imported into new objects of type `gridOptions.importerNewObject`,
    +         * and if the rowEdit feature is enabled the rows are marked as dirty
    +         * @param {Grid} grid the grid we want to import into
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         */
    +        importJsonClosure: function( grid ) {
    +          return function( importFile ){
    +            var newObjects = [];
    +            var newObject;
    +            
    +            angular.forEach( service.parseJson( grid, importFile ), function( value, index ) {
    +              newObject = service.newObject( grid );
    +              angular.extend( newObject, value );
    +              newObject = grid.options.importerObjectCallback( grid, newObject );
    +              newObjects.push( newObject );
    +            });
    +            
    +            service.addObjects( grid, newObjects );
    +            
    +          };
    +        },
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name parseJson
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a json file, returns the parsed data.
    +         * Displays an error if file doesn't parse
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a FileObject
    +         * @returns {array} array of objects from the imported json
    +         */
    +        parseJson: function( grid, importFile ){
    +          var loadedObjects;
    +          try {
    +            loadedObjects = JSON.parse( importFile.target.result );
    +          } catch (e) {
    +            service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
    +            return;
    +          }
    +          
    +          if ( !Array.isArray( loadedObjects ) ){
    +            service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
    +            return [];
    +          } else {
    +            return loadedObjects;
    +          }
    +        },
    +        
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name importCsvClosure
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Creates a function that imports a csv file into the grid
    +         * (allowing it to be used in the reader.onload event)
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as 
    +         * a file object
    +         */
    +        importCsvClosure: function( grid ) {
    +          return function( importFile ){
    +            var importArray = service.parseCsv( importFile );
    +            if ( !importArray || importArray.length < 1 ){ 
    +              service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
    +              return; 
    +            }
    +            
    +            var newObjects = service.createCsvObjects( grid, importArray );
    +            if ( !newObjects || newObjects.length === 0 ){
    +              service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
    +              return;
    +            }
    +            
    +            service.addObjects( grid, newObjects );
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name parseCsv
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Parses a csv file into an array of arrays, with the first
    +         * array being the headers, and the remaining arrays being the data.
    +         * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js, 
    +         * which is noted as being under the MIT license.  The code is modified to pass the jscs yoda condition
    +         * checker
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        parseCsv: function( importFile ) {
    +          var csv = importFile.target.result;
    +          
    +          // use the CSV-JS library to parse
    +          return CSV.parse(csv);
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name createCsvObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Converts an array of arrays (representing the csv file)
    +         * into a set of objects.  Uses the provided `gridOptions.importerNewObject`
    +         * to create the objects, and maps the header row into the individual columns 
    +         * using either `gridOptions.importerProcessHeaders`, or by using a native method
    +         * of matching to either the displayName, column name or column field of
    +         * the columns in the column defs.  The resulting objects will have attributes
    +         * that are named based on the column.field or column.name, in that order.
    +         * @param {Grid} grid the grid that we want to import into 
    +         * @param {FileObject} importFile the file that we want to import, as a 
    +         * file object
    +         */
    +        createCsvObjects: function( grid, importArray ){
    +          // pull off header row and turn into headers
    +          var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
    +          if ( !headerMapping || headerMapping.length === 0 ){
    +            service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
    +            return [];
    +          }
    +          
    +          var newObjects = [];
    +          var newObject;
    +          angular.forEach( importArray, function( row, index ) {
    +            newObject = service.newObject( grid );
    +            angular.forEach( row, function( field, index ){
    +              if ( headerMapping[index] !== null ){
    +                newObject[ headerMapping[index] ] = field;
    +              }
    +            });
    +            newObject = grid.options.importerObjectCallback( grid, newObject );
    +            newObjects.push( newObject );
    +          });
    +          
    +          return newObjects;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name processHeaders
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Determines the columns that the header row from
    +         * a csv (or other) file represents.
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         * @returns {array} an array of the attribute names that should be used
    +         * for that column, based on matching the headers or creating the headers
    +         * 
    +         */
    +        processHeaders: function( grid, headerRow ) {
    +          var headers = [];
    +          if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
    +            // we are going to create new columnDefs for all these columns, so just remove
    +            // spaces from the names to create fields
    +            angular.forEach( headerRow, function( value, index ) {
    +              headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
    +            });
    +            return headers;
    +          } else {
    +            var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
    +            angular.forEach( headerRow, function( value, index ) {
    +              if ( lookupHash[value] ) {
    +                headers.push( lookupHash[value] );
    +              } else if ( lookupHash[ value.toLowerCase() ] ) {
    +                headers.push( lookupHash[ value.toLowerCase() ] );
    +              } else {
    +                headers.push( null );
    +              }
    +            });
    +            return headers;
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @name flattenColumnDefs
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Runs through the column defs and creates a hash of
    +         * the displayName, name and field, and of each of those values forced to lower case,
    +         * with each pointing to the field or name
    +         * (whichever is present).  Used to lookup column headers and decide what 
    +         * attribute name to give to the resulting field. 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} columnDefs the columnDefs that we should flatten
    +         * @returns {hash} the flattened version of the column def information, allowing
    +         * us to look up a value by `flattenedHash[ headerValue ]`
    +         */
    +        flattenColumnDefs: function( grid, columnDefs ){
    +          var flattenedHash = {};
    +          angular.forEach( columnDefs, function( columnDef, index) {
    +            if ( columnDef.name ){
    +              flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.field ){
    +              flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName ){
    +              flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
    +              flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +            
    +            if ( columnDef.displayName && grid.options.importerHeaderFilter ){
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
    +              flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
    +            }
    +          });
    +          
    +          return flattenedHash;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name addObjects
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Inserts our new objects into the grid data, and
    +         * sets the rows to dirty if the rowEdit feature is being used
    +         * 
    +         * Does this by registering a watch on dataChanges, which essentially
    +         * is waiting on the result of the grid data watch, and downstream processing.
    +         * 
    +         * When the callback is called, it deregisters itself - we don't want to run
    +         * again next time data is added.
    +         * 
    +         * If we never get called, we deregister on destroy.
    +         * 
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} newObjects the objects we want to insert into the grid data
    +         * @returns {object} the new object
    +         */
    +        addObjects: function( grid, newObjects, $scope ){
    +          if ( grid.api.rowEdit ){
    +            var dataChangeDereg = grid.registerDataChangeCallback( function() {
    +              grid.api.rowEdit.setRowsDirty( newObjects );
    +              dataChangeDereg();
    +            }, [uiGridConstants.dataChange.ROW] );
    +            
    +            grid.importer.$scope.$on( '$destroy', dataChangeDereg );
    +          }
    +
    +          grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
    +          
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name newObject
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Makes a new object based on `gridOptions.importerNewObject`,
    +         * or based on an empty object if not present
    +         * @param {Grid} grid the grid we're importing into
    +         * @returns {object} the new object
    +         */
    +        newObject: function( grid ){
    +          if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
    +            return new grid.options.importerNewObject();
    +          } else {
    +            return {};
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name alertError
    +         * @methodOf ui.grid.importer.service:uiGridImporterService
    +         * @description Provides an internationalised user alert for the failure,
    +         * and logs a console message including diagnostic content.
    +         * Optionally, if the the `gridOptions.importerErrorCallback` routine
    +         * is defined, then calls that instead, allowing user specified error routines
    +         * @param {Grid} grid the grid we're importing into
    +         * @param {array} headerRow the header row that we wish to match against
    +         * the column definitions
    +         */
    +        alertError: function( grid, alertI18nToken, consoleMessage, context ){
    +          if ( grid.options.importerErrorCallback ){
    +            grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
    +          } else {
    +            $window.alert(i18nService.getSafeText( alertI18nToken )); 
    +            gridUtil.logError(consoleMessage + context ); 
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporter
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds importer features to grid
    +   *
    +   */
    +  module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +  
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.importer.directive:uiGridImporterMenuItem
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Handles the processing from the importer menu item - once a file is
    +   *  selected
    +   *
    +   */
    +  module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
    +    function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        templateUrl: 'ui-grid/importerMenuItem',
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          var handleFileSelect = function( event ){
    +            var target = event.srcElement || event.target;
    +            
    +            if (target && target.files && target.files.length === 1) {
    +              var fileObject = target.files[0];
    +              uiGridImporterService.importThisFile( grid, fileObject );
    +              target.form.reset();
    +            }
    +          };
    +
    +          var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
    +          var grid = uiGridCtrl.grid;
    +          
    +          if ( fileChooser.length !== 1 ){
    +            gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
    +          } else {
    +            fileChooser[0].addEventListener('change', handleFileSelect, false);  // TODO: why the false on the end?  Google  
    +          }
    +        }
    +      };
    +    }
    +  ]);  
    +})();
    +(function() {
    +  'use strict';
    +  /**
    +   *  @ngdoc overview
    +   *  @name ui.grid.infiniteScroll
    +   *
    +   *  @description
    +   *
    +   *   #ui.grid.infiniteScroll
    +   * This module provides infinite scroll functionality to ui-grid
    +   *
    +   */
    +  var module = angular.module('ui.grid.infiniteScroll', ['ui.grid']);
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +   *
    +   *  @description Service for infinite scroll features
    +   */
    +  module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', function (gridUtil, $compile, $timeout, uiGridConstants) {
    +
    +    var service = {
    +
    +      /**
    +       * @ngdoc function
    +       * @name initializeGrid
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This method register events and methods into grid public API
    +       */
    +
    +      initializeGrid: function(grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:PublicAPI
    +         *
    +         *  @description Public API for infinite scroll feature
    +         */
    +        var publicApi = {
    +          events: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreData
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached bottom percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreData: function ($scope, fn) {
    +              },
    +
    +              /**
    +               * @ngdoc event
    +               * @name needLoadMoreDataTop
    +               * @eventOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This event fires when scroll reached top percentage of grid
    +               * and needs to load data
    +               */
    +
    +              needLoadMoreDataTop: function ($scope, fn) {
    +              }
    +            }
    +          },
    +          methods: {
    +            infiniteScroll: {
    +
    +              /**
    +               * @ngdoc function
    +               * @name dataLoaded
    +               * @methodOf ui.grid.infiniteScroll.api:PublicAPI
    +               * @description This function is used as a promise when data finished loading.
    +               * See infinite_scroll ngdoc for example of usage
    +               */
    +
    +              dataLoaded: function() {
    +                grid.options.loadTimout = false;
    +              }
    +            }
    +          }
    +        };
    +        grid.options.loadTimout = false;
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.infiniteScroll.api:GridOptions
    +         *
    +         *  @description GridOptions for infinite scroll feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enableInfiniteScroll
    +         *  @propertyOf  ui.grid.infiniteScroll.api:GridOptions
    +         *  @description Enable infinite scrolling for this grid
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
    +      },
    +
    +
    +      /**
    +       * @ngdoc function
    +       * @name loadData
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
    +       */
    +
    +      loadData: function (grid) {
    +        grid.options.loadTimout = true;
    +        if (grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +          grid.api.infiniteScroll.raise.needLoadMoreDataTop();
    +          return;
    +        }
    +        grid.api.infiniteScroll.raise.needLoadMoreData();
    +      },
    +
    +      /**
    +       * @ngdoc function
    +       * @name checkScroll
    +       * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
    +       * @description This function checks scroll position inside grid and
    +       * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
    +       */
    +
    +      checkScroll: function(grid, scrollTop) {
    +
    +        /* Take infiniteScrollPercentage value or use 20% as default */
    +        var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
    +
    +        if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
    +          this.loadData(grid);
    +          return true;
    +        }
    +        return false;
    +      }
    +      /**
    +       * @ngdoc property
    +       * @name infiniteScrollPercentage
    +       * @propertyOf ui.grid.class:GridOptions
    +       * @description This setting controls at what percentage of the scroll more data
    +       * is requested by the infinite scroll
    +       */
    +    };
    +    return service;
    +  }]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.infiniteScroll.directive:uiGridInfiniteScroll
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds infinite scroll features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.infiniteScroll']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +            { name: 'Sam', car: 'Lexus' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name'},
    +        {name: 'car'}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-infinite-scroll="20"></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +
    +  module.directive('uiGridInfiniteScroll', ['uiGridInfiniteScrollService',
    +    function (uiGridInfiniteScrollService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: '^uiGrid',
    +        compile: function($scope, $elm, $attr){
    +          return {
    +            pre: function($scope, $elm, $attr, uiGridCtrl) {
    +              uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function($scope, $elm, $attr) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridViewport',
    +    ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
    +      function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
    +        return {
    +          priority: -200,
    +          scope: false,
    +          link: function ($scope, $elm, $attr){
    +            if ($scope.grid.options.enableInfiniteScroll) {
    +              $scope.grid.api.core.on.scrollEvent($scope, function (args) {
    +                  //Prevent circular scroll references, if source is coming from ui.grid.adjustInfiniteScrollPosition() function
    +                  if (args.y && (args.source !== 'ui.grid.adjustInfiniteScrollPosition')) {
    +                    var percentage = 100 - (args.y.percentage * 100);
    +                    if ($scope.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
    +                      percentage = (args.y.percentage * 100);
    +                    }
    +                    uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
    +                  }
    +              });
    +            }
    +          }
    +        };
    +      }]);
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.moveColumns
    +   * @description
    +   * # ui.grid.moveColumns
    +   * This module provides column moving capability to ui.grid. It enables to change the position of columns.
    +   * <div doc-module-components="ui.grid.moveColumns"></div>
    +   */
    +  var module = angular.module('ui.grid.moveColumns', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.moveColumns.service:uiGridMoveColumnService
    +   *  @description Service for column moving feature.
    +   */
    +  module.service('uiGridMoveColumnService', ['$q', '$timeout', '$log', 'ScrollEvent', 'uiGridConstants', function ($q, $timeout, $log, ScrollEvent, uiGridConstants) {
    +
    +    var service = {
    +      initializeGrid: function (grid) {
    +        var self = this;
    +        this.registerPublicApi(grid);
    +        this.defaultGridOptions(grid.options);
    +        grid.registerColumnBuilder(self.movableColumnBuilder);
    +      },
    +      registerPublicApi: function (grid) {
    +        var self = this;
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:PublicApi
    +         *  @description Public Api for column moving feature.
    +         */
    +        var publicApi = {
    +          events: {
    +            /**
    +             * @ngdoc event
    +             * @name columnPositionChanged
    +             * @eventOf  ui.grid.moveColumns.api:PublicApi
    +             * @description raised when column is moved
    +             * <pre>
    +             *      gridApi.colMovable.on.columnPositionChanged(scope,function(colDef, originalPosition, newPosition){})
    +             * </pre>
    +             * @param {object} colDef the column that was moved
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              columnPositionChanged: function (colDef, originalPosition, newPosition) {
    +              }
    +            }
    +          },
    +          methods: {
    +            /**
    +             * @ngdoc method
    +             * @name moveColumn
    +             * @methodOf  ui.grid.moveColumns.api:PublicApi
    +             * @description Method can be used to change column position.
    +             * <pre>
    +             *      gridApi.colMovable.moveColumn(oldPosition, newPosition)
    +             * </pre>
    +             * @param {integer} originalPosition of the column
    +             * @param {integer} finalPosition of the column
    +             */
    +            colMovable: {
    +              moveColumn: function (originalPosition, finalPosition) {
    +                var columns = grid.columns;
    +                if (!angular.isNumber(originalPosition) || !angular.isNumber(finalPosition)) {
    +                  console.log('Please provide valid values for originalPosition and finalPosition');
    +                  return;
    +                }
    +                var nonMovableColumns = 0;
    +                for (var i = 0; i < columns.length; i++) {
    +                  if ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true) {
    +                    nonMovableColumns++;
    +                  }
    +                }
    +                if (originalPosition >= (columns.length - nonMovableColumns) || finalPosition >= (columns.length - nonMovableColumns)) {
    +                  console.log('Invalid values for originalPosition, finalPosition');
    +                  return;
    +                }
    +                var findPositionForRenderIndex = function (index) {
    +                  var position = index;
    +                  for (var i = 0; i <= position; i++) {
    +                    if (angular.isDefined(columns[i]) && ((angular.isDefined(columns[i].colDef.visible) && columns[i].colDef.visible === false) || columns[i].isRowHeader === true)) {
    +                      position++;
    +                    }
    +                  }
    +                  return position;
    +                };
    +                self.redrawColumnAtPosition(grid, findPositionForRenderIndex(originalPosition), findPositionForRenderIndex(finalPosition));
    +              }
    +            }
    +          }
    +        };
    +        grid.api.registerEventsFromObject(publicApi.events);
    +        grid.api.registerMethodsFromObject(publicApi.methods);
    +      },
    +      defaultGridOptions: function (gridOptions) {
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:GridOptions
    +         *
    +         *  @description Options for configuring the move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:GridOptions
    +         *  @description If defined, sets the default value for the colMovable flag on each individual colDefs
    +         *  if their individual enableColumnMoving configuration is not defined. Defaults to true.
    +         */
    +        gridOptions.enableColumnMoving = gridOptions.enableColumnMoving !== false;
    +      },
    +      movableColumnBuilder: function (colDef, col, gridOptions) {
    +        var promises = [];
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.moveColumns.api:ColumnDef
    +         *
    +         *  @description Column Definition for move column feature, these are available to be
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +        /**
    +         *  @ngdoc object
    +         *  @name enableColumnMoving
    +         *  @propertyOf  ui.grid.moveColumns.api:ColumnDef
    +         *  @description Enable column moving for the column.
    +         */
    +        colDef.enableColumnMoving = colDef.enableColumnMoving === undefined ? gridOptions.enableColumnMoving
    +          : colDef.enableColumnMoving;
    +        return $q.all(promises);
    +      },
    +      redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
    +
    +        var columns = grid.columns;
    +
    +        var originalColumn = columns[originalPosition];
    +        if (originalColumn.colDef.enableColumnMoving) {
    +          if (originalPosition > newPosition) {
    +            for (var i1 = originalPosition; i1 > newPosition; i1--) {
    +              columns[i1] = columns[i1 - 1];
    +            }
    +          }
    +          else if (newPosition > originalPosition) {
    +            for (var i2 = originalPosition; i2 < newPosition; i2++) {
    +              columns[i2] = columns[i2 + 1];
    +            }
    +          }
    +          columns[newPosition] = originalColumn;
    +          $timeout(function () {
    +            grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
    +            grid.refresh();
    +            grid.api.colMovable.raise.columnPositionChanged(originalColumn.colDef, originalPosition, newPosition);
    +          });
    +        }
    +      }
    +    };
    +    return service;
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridMoveColumns
    +   *  @element div
    +   *  @restrict A
    +   *  @description Adds column moving features to the ui-grid directive.
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.moveColumns']);
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +        $scope.data = [
    +          { name: 'Bob', title: 'CEO', age: 45 },
    +          { name: 'Frank', title: 'Lowly Developer', age: 25 },
    +          { name: 'Jenny', title: 'Highly Developer', age: 35 }
    +        ];
    +        $scope.columnDefs = [
    +          {name: 'name'},
    +          {name: 'title'},
    +          {name: 'age'}
    +        ];
    +      }]);
    +   </file>
    +   <file name="main.css">
    +   .grid {
    +      width: 100%;
    +      height: 150px;
    +    }
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div class="grid" ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-move-columns></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridMoveColumns', ['uiGridMoveColumnService', function (uiGridMoveColumnService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridMoveColumnService.initializeGrid(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.moveColumns.directive:uiGridHeaderCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridHeaderCell to provide capability to be able to move it to reposition column.
    +   *
    +   *  On receiving mouseDown event headerCell is cloned, now as the mouse moves the cloned header cell also moved in the grid.
    +   *  In case the moving cloned header cell reaches the left or right extreme of grid, grid scrolling is triggered (if horizontal scroll exists).
    +   *  On mouseUp event column is repositioned at position where mouse is released and cloned header cell is removed.
    +   *
    +   *  Events that invoke cloning of header cell:
    +   *    - mousedown
    +   *
    +   *  Events that invoke movement of cloned header cell:
    +   *    - mousemove
    +   *
    +   *  Events that invoke repositioning of column:
    +   *    - mouseup
    +   */
    +  module.directive('uiGridHeaderCell', ['$q', 'gridUtil', 'uiGridMoveColumnService', '$document', '$log', 'uiGridConstants', 'ScrollEvent',
    +    function ($q, gridUtil, uiGridMoveColumnService, $document, $log, uiGridConstants, ScrollEvent) {
    +      return {
    +        priority: -10,
    +        require: '^uiGrid',
    +        compile: function () {
    +          return {
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +              if ($scope.col.colDef.enableColumnMoving) {
    +
    +                $scope.$on(uiGridConstants.events.COLUMN_HEADER_CLICK, function (event, args) {
    +
    +                  if (args.columnName === $scope.col.colDef.name && !$scope.col.renderContainer) {
    +
    +                    var evt = args.event;
    +                    if (evt.target.className !== 'ui-grid-icon-angle-down' && evt.target.tagName !== 'I' &&
    +                      evt.target.className.indexOf('ui-grid-filter-input') < 0) {
    +
    +                      //Setting some variables required for calculations.
    +                      var gridLeft = $scope.grid.element[0].getBoundingClientRect().left;
    +                      var previousMouseX = evt.pageX;
    +                      var totalMouseMovement = 0;
    +                      var rightMoveLimit = gridLeft + $scope.grid.getViewportWidth();// - $scope.grid.verticalScrollbarWidth;
    +
    +                      //Clone element should move horizontally with mouse.
    +                      var elmCloned = false;
    +                      var movingElm;
    +                      var reducedWidth;
    +
    +                      var cloneElement = function () {
    +                        elmCloned = true;
    +
    +                        //Cloning header cell and appending to current header cell.
    +                        movingElm = $elm.clone();
    +                        $elm.parent().append(movingElm);
    +
    +                        //Left of cloned element should be aligned to original header cell.
    +                        movingElm.addClass('movingColumn');
    +                        var movingElementStyles = {};
    +                        var elmLeft = $elm[0].getBoundingClientRect().left;
    +                        movingElementStyles.left = (elmLeft - gridLeft) + 'px';
    +                        var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
    +                        var elmRight = $elm[0].getBoundingClientRect().right;
    +                        if (elmRight > gridRight) {
    +                          reducedWidth = $scope.col.drawnWidth + (gridRight - elmRight);
    +                          movingElementStyles.width = reducedWidth + 'px';
    +                        }
    +                        movingElm.css(movingElementStyles);
    +                      };
    +
    +                      var moveElement = function (changeValue) {
    +                        //Hide column menu
    +                        uiGridCtrl.fireEvent('hide-menu');
    +
    +                        //Calculate total column width
    +                        var columns = $scope.grid.columns;
    +                        var totalColumnWidth = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) {
    +                            totalColumnWidth += columns[i].drawnWidth || columns[i].width || columns[i].colDef.width;
    +                          }
    +                        }
    +
    +                        //Calculate new position of left of column
    +                        var currentElmLeft = movingElm[0].getBoundingClientRect().left - 1;
    +                        var currentElmRight = movingElm[0].getBoundingClientRect().right;
    +                        var newElementLeft;
    +                        if (gridUtil.detectBrowser() === 'ie') {
    +                          newElementLeft = currentElmLeft + changeValue;
    +                        }
    +                        else {
    +                          newElementLeft = currentElmLeft - gridLeft + changeValue;
    +                        }
    +                        newElementLeft = newElementLeft < rightMoveLimit ? newElementLeft : rightMoveLimit;
    +
    +                        //Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
    +                        if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
    +                          movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
    +                        }
    +                        else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
    +                          changeValue *= 8;
    +                          var scrollEvent = new ScrollEvent($scope.col.grid, null, null, 'uiGridHeaderCell.moveElement');
    +                          scrollEvent.x = {pixels: changeValue};
    +                          scrollEvent.fireScrollingEvent();
    +                        }
    +
    +                        //Calculate total width of columns on the left of the moving column and the mouse movement
    +                        var totalColumnsLeftWidth = 0;
    +                        for (var il = 0; il < columns.length; il++) {
    +                          if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                            if (columns[il].colDef.name !== $scope.col.colDef.name) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                            }
    +                            else {
    +                              break;
    +                            }
    +                          }
    +                        }
    +                        if ($scope.newScrollLeft === undefined) {
    +                          totalMouseMovement += changeValue;
    +                        }
    +                        else {
    +                          totalMouseMovement = $scope.newScrollLeft + newElementLeft - totalColumnsLeftWidth;
    +                        }
    +
    +                        //Increase width of moving column, in case the rightmost column was moved and its width was
    +                        //decreased because of overflow
    +                        if (reducedWidth < $scope.col.drawnWidth) {
    +                          reducedWidth += Math.abs(changeValue);
    +                          movingElm.css({'width': reducedWidth + 'px'});
    +                        }
    +                      };
    +
    +                      var mouseMoveHandler = function (evt) {
    +                        //Disable text selection in Chrome during column move
    +                        document.onselectstart = function() { return false; };
    +
    +                        var changeValue = evt.pageX - previousMouseX;
    +                        if (!elmCloned && Math.abs(changeValue) > 50) {
    +                          cloneElement();
    +                        }
    +                        else if (elmCloned) {
    +                          moveElement(changeValue);
    +                          previousMouseX = evt.pageX;
    +                        }
    +                      };
    +
    +                      /*
    +                       //Commenting these lines as they are creating trouble with column moving when grid has huge scroll
    +                       // On scope destroy, remove the mouse event handlers from the document body
    +                       $scope.$on('$destroy', function () {
    +                       $document.off('mousemove', mouseMoveHandler);
    +                       $document.off('mouseup', mouseUpHandler);
    +                       });
    +                       */
    +                      $document.on('mousemove', mouseMoveHandler);
    +
    +                      var mouseUpHandler = function (evt) {
    +                        //Re-enable text selection after column move
    +                        document.onselectstart = null;
    +
    +                        //Remove the cloned element on mouse up.
    +                        if (movingElm) {
    +                          movingElm.remove();
    +                        }
    +
    +                        var columns = $scope.grid.columns;
    +                        var columnIndex = 0;
    +                        for (var i = 0; i < columns.length; i++) {
    +                          if (columns[i].colDef.name !== $scope.col.colDef.name) {
    +                            columnIndex++;
    +                          }
    +                          else {
    +                            break;
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its left
    +                        if (totalMouseMovement < 0) {
    +                          var totalColumnsLeftWidth = 0;
    +                          for (var il = columnIndex - 1; il >= 0; il--) {
    +                            if (angular.isUndefined(columns[il].colDef.visible) || columns[il].colDef.visible === true) {
    +                              totalColumnsLeftWidth += columns[il].drawnWidth || columns[il].width || columns[il].colDef.width;
    +                              if (totalColumnsLeftWidth > Math.abs(totalMouseMovement)) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, il + 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to beginning of the grid.
    +                          if (totalColumnsLeftWidth < Math.abs(totalMouseMovement)) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, 0);
    +                          }
    +                        }
    +
    +                        //Case where column should be moved to a position on its right
    +                        else if (totalMouseMovement > 0) {
    +                          var totalColumnsRightWidth = 0;
    +                          for (var ir = columnIndex + 1; ir < columns.length; ir++) {
    +                            if (angular.isUndefined(columns[ir].colDef.visible) || columns[ir].colDef.visible === true) {
    +                              totalColumnsRightWidth += columns[ir].drawnWidth || columns[ir].width || columns[ir].colDef.width;
    +                              if (totalColumnsRightWidth > totalMouseMovement) {
    +                                uiGridMoveColumnService.redrawColumnAtPosition
    +                                ($scope.grid, columnIndex, ir - 1);
    +                                break;
    +                              }
    +                            }
    +                          }
    +                          //Case where column should be moved to end of the grid.
    +                          if (totalColumnsRightWidth < totalMouseMovement) {
    +                            uiGridMoveColumnService.redrawColumnAtPosition
    +                            ($scope.grid, columnIndex, columns.length - 1);
    +                          }
    +                        }
    +/*
    +                        else if (totalMouseMovement === 0) {
    +                          if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
    +                            //sort the current column
    +                            var add = false;
    +                            if (evt.shiftKey) {
    +                              add = true;
    +                            }
    +                            // Sort this column then rebuild the grid's rows
    +                            uiGridCtrl.grid.sortColumn($scope.col, add)
    +                              .then(function () {
    +                                if (uiGridCtrl.columnMenuScope) {
    +                                  uiGridCtrl.columnMenuScope.hideMenu();
    +                                }
    +                                uiGridCtrl.grid.refresh();
    +                              });
    +                          }
    +                        }
    +*/
    +                        $document.off('mousemove', mouseMoveHandler);
    +                        $document.off('mouseup', mouseUpHandler);
    +                      };
    +
    +                      //Binding the mouseup event handler
    +                      $document.on('mouseup', mouseUpHandler);
    +                    }
    +                  }
    +                });
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +})();
    +
    +(function() {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pagination
    +   *
    +   * @description
    +   *
    +   * #ui.grid.pagination
    +   * This module provides pagination support to ui-grid
    +   */
    +  var module = angular.module('ui.grid.pagination', ['ng', 'ui.grid']);
    +
    +  /**
    +   * @ngdoc service
    +   * @name ui.grid.pagination.service:uiGridPaginationService
    +   *
    +   * @description Service for the pagination feature
    +   */
    +  module.service('uiGridPaginationService', ['gridUtil',
    +    function (gridUtil) {
    +      var service = {
    +        /**
    +         * @ngdoc method
    +         * @name initializeGrid
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @description Attaches the service to a certain grid
    +         * @param {Grid} grid The grid we want to work with
    +         */
    +        initializeGrid: function (grid) {
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +          * @ngdoc object
    +          * @name ui.grid.pagination.api:PublicAPI
    +          *
    +          * @description Public API for the pagination feature
    +          */
    +          var publicApi = {
    +            events: {
    +              pagination: {
    +              /**
    +               * @ngdoc event
    +               * @name paginationChanged
    +               * @eventOf ui.grid.pagination.api:PublicAPI
    +               * @description This event fires when the pageSize or currentPage changes
    +               * @param {int} currentPage requested page number
    +               * @param {int} pageSize requested page size
    +               */
    +                paginationChanged: function (currentPage, pageSize) { }
    +              }
    +            },
    +            methods: {
    +              pagination: {
    +                /**
    +                 * @ngdoc method
    +                 * @name getPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the number of the current page
    +                 */
    +                getPage: function () {
    +                  return grid.options.enablePagination ? grid.options.paginationCurrentPage : null;
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name getTotalPages
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Returns the total number of pages
    +                 */
    +                getTotalPages: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return null;
    +                  }
    +
    +                  return (grid.options.totalItems === 0) ? 1 : Math.ceil(grid.options.totalItems / grid.options.paginationPageSize);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name nextPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the next page, if possible
    +                 */
    +                nextPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  if (grid.options.totalItems > 0) {
    +                    grid.options.paginationCurrentPage = Math.min(
    +                      grid.options.paginationCurrentPage + 1,
    +                      publicApi.methods.pagination.getTotalPages()
    +                    );
    +                  } else {
    +                    grid.options.paginationCurrentPage++;
    +                  }
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name previousPage
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the previous page, if we're not on the first page
    +                 */
    +                previousPage: function () {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.max(grid.options.paginationCurrentPage - 1, 1);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @name seek
    +                 * @methodOf ui.grid.pagination.api:PublicAPI
    +                 * @description Moves to the requested page
    +                 * @param {int} page The number of the page that should be displayed
    +                 */
    +                seek: function (page) {
    +                  if (!grid.options.enablePagination) {
    +                    return;
    +                  }
    +                  if (!angular.isNumber(page) || page < 1) {
    +                    throw 'Invalid page number: ' + page;
    +                  }
    +
    +                  grid.options.paginationCurrentPage = Math.min(page, publicApi.methods.pagination.getTotalPages());
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          grid.registerRowsProcessor(function (renderableRows) {
    +            if (grid.options.useExternalPagination || !grid.options.enablePagination) {
    +              return renderableRows;
    +            }
    +            //client side pagination
    +            var pageSize = parseInt(grid.options.paginationPageSize, 10);
    +            var currentPage = parseInt(grid.options.paginationCurrentPage, 10);
    +            
    +            var visibleRows = renderableRows.filter(function (row) { return row.visible; });
    +            grid.options.totalItems = visibleRows.length;
    +
    +            var firstRow = (currentPage - 1) * pageSize;
    +            if (firstRow > visibleRows.length) {
    +              currentPage = grid.options.paginationCurrentPage = 1;
    +              firstRow = (currentPage - 1) * pageSize;
    +            }
    +            return visibleRows.slice(firstRow, firstRow + pageSize);
    +          });
    +
    +        },
    +        defaultGridOptions: function (gridOptions) {
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.pagination.api:GridOptions
    +           *
    +           * @description GridOptions for the pagination feature, these are available to be
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           * @ngdoc property
    +           * @name enablePagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables pagination, defaults to true
    +           */
    +          gridOptions.enablePagination = gridOptions.enablePagination !== false;
    +          /**
    +           * @ngdoc property
    +           * @name enablePaginationControls
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
    +           *              own controls outside the grid.
    +           */
    +          gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
    +          /**
    +           * @ngdoc property
    +           * @name useExternalPagination
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Disables client side pagination. When true, handle the paginationChanged event and set data
    +           *              and totalItems, defaults to `false`
    +           */
    +          gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
    +          /**
    +           * @ngdoc property
    +           * @name totalItems
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Total number of items, set automatically when client side pagination, needs set by user
    +           *              for server side pagination
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
    +            gridOptions.totalItems = 0;
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSizes
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Array of page sizes, defaults to `[250, 500, 1000]`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSizes)) {
    +            gridOptions.paginationPageSizes = [250, 500, 1000];
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationPageSize
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Page size, defaults to the first item in paginationPageSizes, or 0 if paginationPageSizes is empty
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationPageSize)) {
    +            if (gridOptions.paginationPageSizes.length > 0) {
    +              gridOptions.paginationPageSize = gridOptions.paginationPageSizes[0];
    +            } else {              
    +              gridOptions.paginationPageSize = 0;
    +            }
    +          }
    +          /**
    +           * @ngdoc property
    +           * @name paginationCurrentPage
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description Current page number, defaults to 1
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationCurrentPage)) {
    +            gridOptions.paginationCurrentPage = 1;
    +          }
    +
    +          /**
    +           * @ngdoc property
    +           * @name paginationTemplate
    +           * @propertyOf ui.grid.pagination.api:GridOptions
    +           * @description A custom template for the pager, defaults to `ui-grid/pagination`
    +           */
    +          if (gridUtil.isNullOrUndefined(gridOptions.paginationTemplate)) {
    +            gridOptions.paginationTemplate = 'ui-grid/pagination';
    +          }
    +        },
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.pagination.service:uiGridPaginationService
    +         * @name uiGridPaginationService
    +         * @description  Raises paginationChanged and calls refresh for client side pagination
    +         * @param {Grid} grid the grid for which the pagination changed
    +         * @param {int} currentPage requested page number
    +         * @param {int} pageSize requested page size
    +         */
    +        onPaginationChanged: function (grid, currentPage, pageSize) {
    +            grid.api.pagination.raise.paginationChanged(currentPage, pageSize);
    +            if (!grid.options.useExternalPagination) {
    +              grid.refresh(); //client side pagination
    +            }
    +        }
    +      };
    +      
    +      return service;
    +    }
    +  ]);
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPagination
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds pagination features to grid
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.pagination']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Alex', car: 'Toyota' },
    +        { name: 'Sam', car: 'Lexus' },
    +        { name: 'Joe', car: 'Dodge' },
    +        { name: 'Bob', car: 'Buick' },
    +        { name: 'Cindy', car: 'Ford' },
    +        { name: 'Brian', car: 'Audi' },
    +        { name: 'Malcom', car: 'Mercedes Benz' },
    +        { name: 'Dave', car: 'Ford' },
    +        { name: 'Stacey', car: 'Audi' },
    +        { name: 'Amy', car: 'Acura' },
    +        { name: 'Scott', car: 'Toyota' },
    +        { name: 'Ryan', car: 'BMW' },
    +      ];
    +
    +      $scope.gridOptions = {
    +        data: 'data',
    +        paginationPageSizes: [5, 10, 25],
    +        paginationPageSize: 5,
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'car'}
    +        ];
    +       }
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-pagination></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridPagination', ['gridUtil', 'uiGridPaginationService',
    +    function (gridUtil, uiGridPaginationService) {
    +      return {
    +        priority: -200,
    +        scope: false,
    +        require: 'uiGrid',
    +        link: {
    +          pre: function ($scope, $elm, $attr, uiGridCtrl) {
    +            uiGridPaginationService.initializeGrid(uiGridCtrl.grid);
    +
    +            gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +                $elm.append(template);
    +                uiGridCtrl.innerCompile(template);
    +              });
    +          }
    +        }
    +      };
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.pagination.directive:uiGridPager
    +   *  @element div
    +   *
    +   *  @description Panel for handling pagination
    +   */
    +  module.directive('uiGridPager', ['uiGridPaginationService', 'uiGridConstants', 'gridUtil', 'i18nService',
    +    function (uiGridPaginationService, uiGridConstants, gridUtil, i18nService) {
    +      return {
    +        priority: -200,
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function ($scope, $elm, $attr, uiGridCtrl) {
    +          $scope.paginationApi = uiGridCtrl.grid.api.pagination;
    +          $scope.sizesLabel = i18nService.getSafeText('pagination.sizes');
    +          $scope.totalItemsLabel = i18nService.getSafeText('pagination.totalItems');
    +          
    +          var options = uiGridCtrl.grid.options;
    +          
    +          uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
    +            adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
    +            return adjustment;
    +          });
    +          
    +          var dataChangeDereg = uiGridCtrl.grid.registerDataChangeCallback(function (grid) {
    +            if (!grid.options.useExternalPagination) {
    +              grid.options.totalItems = grid.rows.length;
    +            }
    +          }, [uiGridConstants.dataChange.ROW]);
    +          
    +          $scope.$on('$destroy', dataChangeDereg);
    +
    +          var setShowing = function () {
    +            $scope.showingLow = ((options.paginationCurrentPage - 1) * options.paginationPageSize) + 1;
    +            $scope.showingHigh = Math.min(options.paginationCurrentPage * options.paginationPageSize, options.totalItems);
    +          };
    +
    +          var deregT = $scope.$watch('grid.options.totalItems + grid.options.paginationPageSize', setShowing);
    +
    +          var deregP = $scope.$watch('grid.options.paginationCurrentPage + grid.options.paginationPageSize', function (newValues, oldValues) {
    +              if (newValues === oldValues) { 
    +                return; 
    +              }
    +
    +              if (!angular.isNumber(options.paginationCurrentPage) || options.paginationCurrentPage < 1) {
    +                options.paginationCurrentPage = 1;
    +                return;
    +              }
    +
    +              if (options.totalItems > 0 && options.paginationCurrentPage > $scope.paginationApi.getTotalPages()) {
    +                options.paginationCurrentPage = $scope.paginationApi.getTotalPages();
    +                return;
    +              }
    +
    +              setShowing();
    +              uiGridPaginationService.onPaginationChanged($scope.grid, options.paginationCurrentPage, options.paginationPageSize);
    +            }
    +          );
    +
    +          $scope.$on('$destroy', function() {
    +            deregT();
    +            deregP();
    +          });
    +
    +          $scope.cantPageForward = function () {
    +            if (options.totalItems > 0) {
    +              return options.paginationCurrentPage >= $scope.paginationApi.getTotalPages();
    +            } else {
    +              return options.data.length < 1;
    +            }
    +          };
    +          
    +          $scope.cantPageToLast = function () {
    +            if (options.totalItems > 0) {
    +              return $scope.cantPageForward();
    +            } else {
    +              return true;
    +            }
    +          };
    +          
    +          $scope.cantPageBackward = function () {
    +            return options.paginationCurrentPage <= 1;
    +          };
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.pinning
    +   * @description
    +   *
    +   *  # ui.grid.pinning
    +   * This module provides column pinning to the end user via menu options in the column header
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.pinning"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.pinning', ['ui.grid']);
    +
    +  module.service('uiGridPinningService', ['gridUtil', 'GridRenderContainer', 'i18nService', function (gridUtil, GridRenderContainer, i18nService) {
    +    var service = {
    +
    +      initializeGrid: function (grid) {
    +        service.defaultGridOptions(grid.options);
    +
    +        // Register a column builder to add new menu items for pinning left and right
    +        grid.registerColumnBuilder(service.pinningColumnBuilder);
    +      },
    +
    +      defaultGridOptions: function (gridOptions) {
    +        //default option to true unless it was explicitly set to false
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:GridOptions
    +         *
    +         *  @description GridOptions for pinning feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:GridOptions
    +         *  @description Enable pinning for the entire grid.  
    +         *  <br/>Defaults to true
    +         */
    +        gridOptions.enablePinning = gridOptions.enablePinning !== false;
    +
    +      },
    +
    +      pinningColumnBuilder: function (colDef, col, gridOptions) {
    +        //default to true unless gridOptions or colDef is explicitly false
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name ui.grid.pinning.api:ColumnDef
    +         *
    +         *  @description ColumnDef for pinning feature, these are available to be 
    +         *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name enablePinning
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Enable pinning for the individual column.  
    +         *  <br/>Defaults to true
    +         */
    +        colDef.enablePinning = colDef.enablePinning === undefined ? gridOptions.enablePinning : colDef.enablePinning;
    +
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedLeft
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned left when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +
    +        /**
    +         *  @ngdoc object
    +         *  @name pinnedRight
    +         *  @propertyOf  ui.grid.pinning.api:ColumnDef
    +         *  @description Column is pinned right when grid is rendered
    +         *  <br/>Defaults to false
    +         */
    +        if (colDef.pinnedLeft) {
    +          if (col.width === '*') {
    +            // Need to refresh so the width can be calculated.
    +            col.grid.refresh()
    +                .then(function () {
    +                    col.renderContainer = 'left';
    +                    // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                    // will be 100% if it's the first column, 50% if it's the second etc.
    +                    col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                    col.grid.createLeftContainer();
    +            });
    +          }
    +          else {
    +            col.renderContainer = 'left';
    +            col.grid.createLeftContainer();
    +          }
    +        }
    +        else if (colDef.pinnedRight) {
    +            if (col.width === '*') {
    +                // Need to refresh so the width can be calculated.
    +                col.grid.refresh()
    +                    .then(function () {
    +                        col.renderContainer = 'right';
    +                        // Need to calculate the width. If col.drawnWidth is used instead then the width
    +                        // will be 100% if it's the first column, 50% if it's the second etc.
    +                        col.width = col.grid.canvasWidth / col.grid.columns.length;
    +                        col.grid.createRightContainer();
    +                    });
    +            }
    +            else {
    +                col.renderContainer = 'right';
    +                col.grid.createRightContainer();
    +            }
    +        }
    +
    +        if (!colDef.enablePinning) {
    +          return;
    +        }
    +
    +        var pinColumnLeftAction = {
    +          name: 'ui.grid.pinning.pinLeft',
    +          title: i18nService.get().pinning.pinLeft,
    +          icon: 'ui-grid-icon-left-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'left';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'left';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createLeftContainer();
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var pinColumnRightAction = {
    +          name: 'ui.grid.pinning.pinRight',
    +          title: i18nService.get().pinning.pinRight,
    +          icon: 'ui-grid-icon-right-open',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) === 'undefined' || !this.context.col.renderContainer || this.context.col.renderContainer !== 'right';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = 'right';
    +            this.context.col.width = this.context.col.drawnWidth;
    +            this.context.col.grid.createRightContainer();
    +
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        var removePinAction = {
    +          name: 'ui.grid.pinning.unpin',
    +          title: i18nService.get().pinning.unpin,
    +          icon: 'ui-grid-icon-cancel',
    +          shown: function () {
    +            return typeof(this.context.col.renderContainer) !== 'undefined' && this.context.col.renderContainer !== null && this.context.col.renderContainer !== 'body';
    +          },
    +          action: function () {
    +            this.context.col.renderContainer = null;
    +
    +            // Need to call refresh twice; once to move our column over to the new render container and then
    +            //   a second time to update the grid viewport dimensions with our adjustments
    +            col.grid.refresh()
    +              .then(function () {
    +                col.grid.refresh();
    +              });
    +          }
    +        };
    +
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinLeft')) {
    +          col.menuItems.push(pinColumnLeftAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.pinRight')) {
    +          col.menuItems.push(pinColumnRightAction);
    +        }
    +        if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.pinning.unpin')) {
    +          col.menuItems.push(removePinAction);
    +        }
    +      }
    +    };
    +
    +    return service;
    +  }]);
    +
    +  module.directive('uiGridPinning', ['gridUtil', 'uiGridPinningService',
    +    function (gridUtil, uiGridPinningService) {
    +      return {
    +        require: 'uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridPinningService.initializeGrid(uiGridCtrl.grid);
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +
    +})();
    +
    +(function(){
    +  'use strict';
    +
    +  var module = angular.module('ui.grid.resizeColumns', ['ui.grid']);
    +
    +  module.service('uiGridResizeColumnsService', ['gridUtil', '$q', '$timeout',
    +    function (gridUtil, $q, $timeout) {
    +
    +      var service = {
    +        defaultGridOptions: function(gridOptions){
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:GridOptions
    +           *
    +           *  @description GridOptions for resizeColumns feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:GridOptions
    +           *  @description Enable column resizing on the entire grid 
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableColumnResizing = gridOptions.enableColumnResizing !== false;
    +
    +          //legacy support
    +          //use old name if it is explicitly false
    +          if (gridOptions.enableColumnResize === false){
    +            gridOptions.enableColumnResizing = false;
    +          }
    +        },
    +
    +        colResizerColumnBuilder: function (colDef, col, gridOptions) {
    +
    +          var promises = [];
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.resizeColumns.api:ColumnDef
    +           *
    +           *  @description ColumnDef for resizeColumns feature, these are available to be 
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableColumnResizing
    +           *  @propertyOf  ui.grid.resizeColumns.api:ColumnDef
    +           *  @description Enable column resizing on an individual column
    +           *  <br/>Defaults to GridOptions.enableColumnResizing
    +           */
    +          //default to true unless gridOptions or colDef is explicitly false
    +          colDef.enableColumnResizing = colDef.enableColumnResizing === undefined ? gridOptions.enableColumnResizing : colDef.enableColumnResizing;
    +
    +
    +          //legacy support of old option name
    +          if (colDef.enableColumnResize === false){
    +            colDef.enableColumnResizing = false;
    +          }
    +
    +          return $q.all(promises);
    +        },
    +        
    +        registerPublicApi: function (grid) {
    +            /**
    +             *  @ngdoc object
    +             *  @name ui.grid.resizeColumns.api:PublicApi
    +             *  @description Public Api for column resize feature.
    +             */
    +            var publicApi = {
    +              events: {
    +                /**
    +                 * @ngdoc event
    +                 * @name columnSizeChanged
    +                 * @eventOf  ui.grid.resizeColumns.api:PublicApi
    +                 * @description raised when column is resized
    +                 * <pre>
    +                 *      gridApi.colResizable.on.columnSizeChanged(scope,function(colDef, deltaChange){})
    +                 * </pre>
    +                 * @param {object} colDef the column that was resized
    +                 * @param {integer} delta of the column size change
    +                 */
    +                colResizable: {
    +                  columnSizeChanged: function (colDef, deltaChange) {
    +                  }
    +                }
    +              }
    +            };
    +            grid.api.registerEventsFromObject(publicApi.events);
    +        },
    +        
    +        fireColumnSizeChanged: function (grid, colDef, deltaChange) {
    +          $timeout(function () {
    +            grid.api.colResizable.raise.columnSizeChanged(colDef, deltaChange);
    +          });
    +        },
    +        
    +        // get either this column, or the column next to this column, to resize,
    +        // returns the column we're going to resize
    +        findTargetCol: function(col, position, rtlMultiplier){
    +          var renderContainer = col.getRenderContainer();
    +
    +          if (position === 'left') {
    +            // Get the column to the left of this one
    +            var colIndex = renderContainer.visibleColumnCache.indexOf(col);          
    +            return renderContainer.visibleColumnCache[colIndex - 1 * rtlMultiplier];
    +          } else {
    +            return col;
    +          }
    +        }
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridResizeColumns
    +   * @element div
    +   * @restrict A
    +   * @description
    +   * Enables resizing for all columns on the grid. If, for some reason, you want to use the ui-grid-resize-columns directive, but not allow column resizing, you can explicitly set the
    +   * option to false. This prevents resizing for the entire grid, regardless of individual columnDef options.
    +   *
    +   * @example
    +   <doc:example module="app">
    +   <doc:source>
    +   <script>
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +   </script>
    +
    +   <div ng-controller="MainCtrl">
    +   <div class="testGrid" ui-grid="gridOpts" ui-grid-resize-columns ></div>
    +   </div>
    +   </doc:source>
    +   <doc:scenario>
    +
    +   </doc:scenario>
    +   </doc:example>
    +   */
    +  module.directive('uiGridResizeColumns', ['gridUtil', 'uiGridResizeColumnsService', function (gridUtil, uiGridResizeColumnsService) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +            uiGridResizeColumnsService.defaultGridOptions(uiGridCtrl.grid.options);
    +            uiGridCtrl.grid.registerColumnBuilder( uiGridResizeColumnsService.colResizerColumnBuilder);
    +            uiGridResizeColumnsService.registerPublicApi(uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +  // Extend the uiGridHeaderCell directive
    +  module.directive('uiGridHeaderCell', ['gridUtil', '$templateCache', '$compile', '$q', 'uiGridResizeColumnsService', 'uiGridConstants', '$timeout', function (gridUtil, $templateCache, $compile, $q, uiGridResizeColumnsService, uiGridConstants, $timeout) {
    +    return {
    +      // Run after the original uiGridHeaderCell
    +      priority: -10,
    +      require: '^uiGrid',
    +      // scope: false,
    +      compile: function() {
    +        return {
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            var grid = uiGridCtrl.grid;
    +
    +            if (grid.options.enableColumnResizing) {
    +              var columnResizerElm = $templateCache.get('ui-grid/columnResizer');
    +    
    +              var rtlMultiplier = 1;
    +              //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +              if (grid.isRTL()) {
    +                $scope.position = 'left';
    +                rtlMultiplier = -1;
    +              }
    +
    +              var displayResizers = function(){
    +                
    +                // remove any existing resizers.  
    +                var resizers = $elm[0].getElementsByClassName('ui-grid-column-resizer');
    +                for ( var i = 0; i < resizers.length; i++ ){
    +                  angular.element(resizers[i]).remove();
    +                } 
    +                
    +                // get the target column for the left resizer
    +                var otherCol = uiGridResizeColumnsService.findTargetCol($scope.col, 'left', rtlMultiplier);
    +                var renderContainer = $scope.col.getRenderContainer();
    +              
    +                // Don't append the left resizer if this is the first column or the column to the left of this one has resizing disabled
    +                if (otherCol && renderContainer.visibleColumnCache.indexOf($scope.col) !== 0 && otherCol.colDef.enableColumnResizing !== false) {
    +                  var resizerLeft = angular.element(columnResizerElm).clone();
    +                  resizerLeft.attr('position', 'left');
    +
    +                  $elm.prepend(resizerLeft);
    +                  $compile(resizerLeft)($scope);
    +                }
    +                
    +                // Don't append the right resizer if this column has resizing disabled
    +                if ($scope.col.colDef.enableColumnResizing !== false) {
    +                  var resizerRight = angular.element(columnResizerElm).clone();
    +                  resizerRight.attr('position', 'right');
    +
    +                  $elm.append(resizerRight);
    +                  $compile(resizerRight)($scope);
    +                }
    +              };
    +
    +              displayResizers();
    +              
    +              var waitDisplay = function(){
    +                $timeout(displayResizers);
    +              };
    +              
    +              var dataChangeDereg = grid.registerDataChangeCallback( waitDisplay, [uiGridConstants.dataChange.COLUMN] );
    +              
    +              $scope.$on( '$destroy', dataChangeDereg );
    +            }
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  
    +  /**
    +   * @ngdoc directive
    +   * @name ui.grid.resizeColumns.directive:uiGridColumnResizer
    +   * @element div
    +   * @restrict A
    +   *
    +   * @description
    +   * Draggable handle that controls column resizing.
    +   * 
    +   * @example
    +   <doc:example module="app">
    +     <doc:source>
    +       <script>
    +        var app = angular.module('app', ['ui.grid', 'ui.grid.resizeColumns']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.gridOpts = {
    +            enableColumnResizing: true,
    +            data: [
    +              { "name": "Ethel Price", "gender": "female", "company": "Enersol" },
    +              { "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
    +              { "name": "Beryl Rice", "gender": "female", "company": "Velity" },
    +              { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko" }
    +            ]
    +          };
    +        }]);
    +       </script>
    +
    +       <div ng-controller="MainCtrl">
    +        <div class="testGrid" ui-grid="gridOpts"></div>
    +       </div>
    +     </doc:source>
    +     <doc:scenario>
    +      // TODO: e2e specs?
    +        // TODO: Obey minWidth and maxWIdth;
    +
    +      // TODO: post-resize a horizontal scroll event should be fired
    +     </doc:scenario>
    +   </doc:example>
    +   */  
    +  module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, uiGridResizeColumnsService) {
    +    var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
    +
    +    var downEvent, upEvent, moveEvent;
    +
    +    if (gridUtil.isTouchEnabled()) {
    +      downEvent = 'touchstart';
    +      upEvent = 'touchend';
    +      moveEvent = 'touchmove';
    +    }
    +    else {
    +      downEvent = 'mousedown';
    +      upEvent = 'mouseup';
    +      moveEvent = 'mousemove';
    +    }
    +
    +    var resizer = {
    +      priority: 0,
    +      scope: {
    +        col: '=',
    +        position: '@',
    +        renderIndex: '='
    +      },
    +      require: '?^uiGrid',
    +      link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +        var startX = 0,
    +            x = 0,
    +            gridLeft = 0,
    +            rtlMultiplier = 1;
    +
    +        //when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
    +        if (uiGridCtrl.grid.isRTL()) {
    +          $scope.position = 'left';
    +          rtlMultiplier = -1;
    +        }
    +
    +        if ($scope.position === 'left') {
    +          $elm.addClass('left');
    +        }
    +        else if ($scope.position === 'right') {
    +          $elm.addClass('right');
    +        }
    +
    +        // Resize all the other columns around col
    +        function resizeAroundColumn(col) {
    +          // Get this column's render container
    +          var renderContainer = col.getRenderContainer();
    +
    +          renderContainer.visibleColumnCache.forEach(function (column) {
    +            // Skip the column we just resized
    +            if (column === col) { return; }
    +            
    +            var colDef = column.colDef;
    +            if (!colDef.width || (angular.isString(colDef.width) && (colDef.width.indexOf('*') !== -1 || colDef.width.indexOf('%') !== -1))) {
    +              column.width = column.drawnWidth;
    +            }
    +          });
    +        }
    +
    +        // Build the columns then refresh the grid canvas
    +        //   takes an argument representing the diff along the X-axis that the resize had
    +        function buildColumnsAndRefresh(xDiff) {
    +          // Build the columns
    +          uiGridCtrl.grid.buildColumns()
    +            .then(function() {
    +              // Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
    +              uiGridCtrl.grid.refreshCanvas(true).then( function() {
    +                uiGridCtrl.grid.refresh();
    +              });
    +            });
    +        }
    +
    +        // Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
    +        // Returns the new recommended with, after constraints applied
    +        function constrainWidth(col, width){
    +          var newWidth = width;
    +
    +          // If the new width would be less than the column's allowably minimum width, don't allow it
    +          if (col.colDef.minWidth && newWidth < col.colDef.minWidth) {
    +            newWidth = col.colDef.minWidth;
    +          }
    +          else if (col.colDef.maxWidth && newWidth > col.colDef.maxWidth) {
    +            newWidth = col.colDef.maxWidth;
    +          }
    +          
    +          return newWidth;
    +        }
    +        
    +        
    +        function mousemove(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          if (x < 0) { x = 0; }
    +          else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
    +            uiGridCtrl.grid.element.addClass('column-resizing');
    +          }
    +
    +          // Get the diff along the X axis
    +          var xDiff = x - startX;
    +
    +          // Get the width that this mouse would give the column
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          x = x + ( constrainWidth(col, newWidth) - newWidth ) * rtlMultiplier;
    +          
    +          resizeOverlay.css({ left: x + 'px' });
    +
    +          uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
    +        }
    +        
    +
    +        function mouseup(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.preventDefault();
    +
    +          uiGridCtrl.grid.element.removeClass('column-resizing');
    +
    +          resizeOverlay.remove();
    +
    +          // Resize the column
    +          x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
    +          var xDiff = x - startX;
    +
    +          if (xDiff === 0) {
    +            $document.off(upEvent, mouseup);
    +            $document.off(moveEvent, mousemove);
    +            return;
    +          }
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Get the new width
    +          var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, newWidth);
    +
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +
    +          $document.off(upEvent, mouseup);
    +          $document.off(moveEvent, mousemove);
    +        }
    +
    +
    +        $elm.on(downEvent, function(event, args) {
    +          if (event.originalEvent) { event = event.originalEvent; }
    +          event.stopPropagation();
    +
    +          // Get the left offset of the grid
    +          // gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
    +          gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;
    +
    +          // Get the starting X position, which is the X coordinate of the click minus the grid's offset
    +          startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;
    +
    +          // Append the resizer overlay
    +          uiGridCtrl.grid.element.append(resizeOverlay);
    +
    +          // Place the resizer overlay at the start position
    +          resizeOverlay.css({ left: startX });
    +
    +          // Add handlers for mouse move and up events
    +          $document.on(upEvent, mouseup);
    +          $document.on(moveEvent, mousemove);
    +        });
    +
    +
    +        // On doubleclick, resize to fit all rendered cells
    +        $elm.on('dblclick', function(event, args) {
    +          event.stopPropagation();
    +
    +          var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);
    +
    +          // Don't resize if it's disabled on this column
    +          if (col.colDef.enableColumnResizing === false) {
    +            return;
    +          }
    +
    +          // Go through the rendered rows and find out the max size for the data in this column
    +          var maxWidth = 0;
    +          var xDiff = 0;
    +
    +          // Get the parent render container element
    +          var renderContainerElm = gridUtil.closestElm($elm, '.ui-grid-render-container');
    +
    +          // Get the cell contents so we measure correctly. For the header cell we have to account for the sort icon and the menu buttons, if present
    +          var cells = renderContainerElm.querySelectorAll('.' + uiGridConstants.COL_CLASS_PREFIX + col.uid + ' .ui-grid-cell-contents');
    +          Array.prototype.forEach.call(cells, function (cell) {
    +              // Get the cell width
    +              // gridUtil.logDebug('width', gridUtil.elementWidth(cell));
    +
    +              // Account for the menu button if it exists
    +              var menuButton;
    +              if (angular.element(cell).parent().hasClass('ui-grid-header-cell')) {
    +                menuButton = angular.element(cell).parent()[0].querySelectorAll('.ui-grid-column-menu-button');
    +              }
    +
    +              gridUtil.fakeElement(cell, {}, function(newElm) {
    +                // Make the element float since it's a div and can expand to fill its container
    +                var e = angular.element(newElm);
    +                e.attr('style', 'float: left');
    +
    +                var width = gridUtil.elementWidth(e);
    +
    +                if (menuButton) {
    +                  var menuButtonWidth = gridUtil.elementWidth(menuButton);
    +                  width = width + menuButtonWidth;
    +                }
    +
    +                if (width > maxWidth) {
    +                  maxWidth = width;
    +                  xDiff = maxWidth - width;
    +                }
    +              });
    +            });
    +
    +          // check we're not outside the allowable bounds for this column
    +          col.width = constrainWidth(col, maxWidth);
    +          
    +          // All other columns because fixed to their drawn width, if they aren't already
    +          resizeAroundColumn(col);
    +
    +          buildColumnsAndRefresh(xDiff);
    +          
    +          uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
    +        });
    +
    +        $elm.on('$destroy', function() {
    +          $elm.off(downEvent);
    +          $elm.off('dblclick');
    +          $document.off(moveEvent, mousemove);
    +          $document.off(upEvent, mouseup);
    +        });
    +      }
    +    };
    +
    +    return resizer;
    +  }]);
    +
    +})();
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.rowEdit
    +   * @description
    +   *
    +   *  # ui.grid.rowEdit
    +   * This module extends the edit feature to provide tracking and saving of rows
    +   * of data.  The tutorial provides more information on how this feature is best
    +   * used {@link tutorial/205_row_editable here}.
    +   * <br/>
    +   * This feature depends on usage of the ui-grid-edit feature, and also benefits
    +   * from use of ui-grid-cellNav to provide the full spreadsheet-like editing 
    +   * experience
    +   * 
    +   */
    +
    +  var module = angular.module('ui.grid.rowEdit', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.rowEdit.constant:uiGridRowEditConstants
    +   *
    +   *  @description constants available in row edit module
    +   */
    +  module.constant('uiGridRowEditConstants', {
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.rowEdit.service:uiGridRowEditService
    +   *
    +   *  @description Services for row editing features
    +   */
    +  module.service('uiGridRowEditService', ['$interval', '$q', 'uiGridConstants', 'uiGridRowEditConstants', 'gridUtil', 
    +    function ($interval, $q, uiGridConstants, uiGridRowEditConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (scope, grid) {
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:PublicApi
    +           *
    +           *  @description Public Api for rowEdit feature
    +           */
    +          
    +          grid.rowEdit = {};
    +          
    +          var publicApi = {
    +            events: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc event
    +                 * @eventOf ui.grid.rowEdit.api:PublicApi
    +                 * @name saveRow
    +                 * @description raised when a row is ready for saving.  Once your
    +                 * row has saved you may need to use angular.extend to update the
    +                 * data entity with any changed data from your save (for example, 
    +                 * lock version information if you're using optimistic locking,
    +                 * or last update time/user information).
    +                 * 
    +                 * Your method should call setSavePromise somewhere in the body before
    +                 * returning control.  The feature will then wait, with the gridRow greyed out 
    +                 * whilst this promise is being resolved.
    +                 * 
    +                 * <pre>
    +                 *      gridApi.rowEdit.on.saveRow(scope,function(rowEntity){})
    +                 * </pre>
    +                 * and somewhere within the event handler:
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise( grid, rowEntity, savePromise)
    +                 * </pre>
    +                 * @param {object} rowEntity the options.data element that was edited
    +                 * @returns {promise} Your saveRow method should return a promise, the
    +                 * promise should either be resolved (implying successful save), or 
    +                 * rejected (implying an error).
    +                 */
    +                saveRow: function (rowEntity) {
    +                }
    +              }
    +            },
    +            methods: {
    +              rowEdit: {
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setSavePromise
    +                 * @description Sets the promise associated with the row save, mandatory that
    +                 * the saveRow event handler calls this method somewhere before returning.
    +                 * <pre>
    +                 *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +                 * </pre>
    +                 * @param {object} rowEntity a data row from the grid for which a save has
    +                 * been initiated
    +                 * @param {promise} savePromise the promise that will be resolved when the
    +                 * save is successful, or rejected if the save fails
    +                 * 
    +                 */
    +                setSavePromise: function ( rowEntity, savePromise) {
    +                  service.setSavePromise(grid, rowEntity, savePromise);
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getDirtyRows
    +                 * @description Returns all currently dirty rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently dirty
    +                 * 
    +                 */
    +                getDirtyRows: function () {
    +                  return grid.rowEdit.dirtyRows ? grid.rowEdit.dirtyRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name getErrorRows
    +                 * @description Returns all currently errored rows
    +                 * <pre>
    +                 *      gridApi.rowEdit.getErrorRows(grid)
    +                 * </pre>
    +                 * @returns {array} An array of gridRows that are currently in error
    +                 * 
    +                 */
    +                getErrorRows: function () {
    +                  return grid.rowEdit.errorRows ? grid.rowEdit.errorRows : [];
    +                },
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name flushDirtyRows
    +                 * @description Triggers a save event for all currently dirty rows, could
    +                 * be used where user presses a save button or navigates away from the page
    +                 * <pre>
    +                 *      gridApi.rowEdit.flushDirtyRows(grid)
    +                 * </pre>
    +                 * @returns {promise} a promise that represents the aggregate of all
    +                 * of the individual save promises - i.e. it will be resolved when all
    +                 * the individual save promises have been resolved.
    +                 * 
    +                 */
    +                flushDirtyRows: function () {
    +                  return service.flushDirtyRows(grid);
    +                },
    +                
    +                /**
    +                 * @ngdoc method
    +                 * @methodOf ui.grid.rowEdit.api:PublicApi
    +                 * @name setRowsDirty
    +                 * @description Sets each of the rows passed in dataRows
    +                 * to be dirty.  note that if you have only just inserted the
    +                 * rows into your data you will need to wait for a $digest cycle
    +                 * before the gridRows are present - so often you would wrap this
    +                 * call in a $interval or $timeout
    +                 * <pre>
    +                 *      $interval( function() {
    +                 *        gridApi.rowEdit.setRowsDirty(grid, myDataRows);
    +                 *      }, 0, 1);
    +                 * </pre>
    +                 * @param {array} dataRows the data entities for which the gridRows
    +                 * should be set dirty.  
    +                 * 
    +                 */
    +                setRowsDirty: function ( dataRows) {
    +                  service.setRowsDirty(grid, dataRows);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +          grid.api.core.on.renderingComplete( scope, function ( gridApi ) {
    +            grid.api.edit.on.afterCellEdit( scope, service.endEditCell );
    +            grid.api.edit.on.beginCellEdit( scope, service.beginEditCell );
    +            grid.api.edit.on.cancelCellEdit( scope, service.cancelEditCell );
    +            
    +            if ( grid.api.cellNav ) {
    +              grid.api.cellNav.on.navigate( scope, service.navigate );
    +            }              
    +          });
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.rowEdit.api:GridOptions
    +           *
    +           *  @description Options for configuring the rowEdit feature, these are available to be  
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name saveRow
    +         * @description  Returns a function that saves the specified row from the grid,
    +         * and returns a promise
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @param {GridRow} gridRow the row that should be saved
    +         * @returns {function} the saveRow function returns a function.  That function
    +         * in turn, when called, returns a promise relating to the save callback
    +         */
    +        saveRow: function ( grid, gridRow ) {
    +          var self = this;
    +
    +          return function() {
    +            gridRow.isSaving = true;
    +
    +            var promise = grid.api.rowEdit.raise.saveRow( gridRow.entity );
    +            
    +            if ( gridRow.rowEditSavePromise ){
    +              gridRow.rowEditSavePromise.then( self.processSuccessPromise( grid, gridRow ), self.processErrorPromise( grid, gridRow ));
    +            } else {
    +              gridUtil.logError( 'A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise' );
    +            }
    +            return promise;
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf  ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setSavePromise
    +         * @description Sets the promise associated with the row save, mandatory that
    +         * the saveRow event handler calls this method somewhere before returning.
    +         * <pre>
    +         *      gridApi.rowEdit.setSavePromise(grid, rowEntity)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be returned
    +         * @param {object} rowEntity a data row from the grid for which a save has
    +         * been initiated
    +         * @param {promise} savePromise the promise that will be resolved when the
    +         * save is successful, or rejected if the save fails
    +         * 
    +         */
    +        setSavePromise: function (grid, rowEntity, savePromise) {
    +          var gridRow = grid.getRow( rowEntity );
    +          gridRow.rowEditSavePromise = savePromise;
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processSuccessPromise
    +         * @description  Returns a function that processes the successful
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that has been saved
    +         * @returns {function} the success handling function
    +         */
    +        processSuccessPromise: function ( grid, gridRow ) {
    +          var self = this;
    +          
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.isDirty;
    +            delete gridRow.isError;
    +            delete gridRow.rowEditSaveTimer;
    +            self.removeRow( grid.rowEdit.errorRows, gridRow );
    +            self.removeRow( grid.rowEdit.dirtyRows, gridRow );
    +          };
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name processErrorPromise
    +         * @description  Returns a function that processes the failed
    +         * resolution of a save promise  
    +         * @param {object} grid the grid for which the promise should be processed
    +         * @param {GridRow} gridRow the row that is now in error
    +         * @returns {function} the error handling function
    +         */
    +        processErrorPromise: function ( grid, gridRow ) {
    +          return function() {
    +            delete gridRow.isSaving;
    +            delete gridRow.rowEditSaveTimer;
    +
    +            gridRow.isError = true;
    +            
    +            if (!grid.rowEdit.errorRows){
    +              grid.rowEdit.errorRows = [];
    +            }
    +            if (!service.isRowPresent( grid.rowEdit.errorRows, gridRow ) ){
    +              grid.rowEdit.errorRows.push( gridRow );
    +            }
    +          };
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name removeRow
    +         * @description  Removes a row from a cache of rows - either
    +         * grid.rowEdit.errorRows or grid.rowEdit.dirtyRows.  If the row
    +         * is not present silently does nothing. 
    +         * @param {array} rowArray the array from which to remove the row
    +         * @param {GridRow} gridRow the row that should be removed
    +         */
    +        removeRow: function( rowArray, removeGridRow ){
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              rowArray.splice( index, 1);
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name isRowPresent
    +         * @description  Checks whether a row is already present
    +         * in the given array 
    +         * @param {array} rowArray the array in which to look for the row
    +         * @param {GridRow} gridRow the row that should be looked for
    +         */
    +        isRowPresent: function( rowArray, removeGridRow ){
    +          var present = false;
    +          angular.forEach( rowArray, function( gridRow, index ){
    +            if ( gridRow.uid === removeGridRow.uid ){
    +              present = true;
    +            }
    +          });
    +          return present;
    +        },
    +
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name flushDirtyRows
    +         * @description Triggers a save event for all currently dirty rows, could
    +         * be used where user presses a save button or navigates away from the page
    +         * <pre>
    +         *      gridApi.rowEdit.flushDirtyRows(grid)
    +         * </pre>
    +         * @param {object} grid the grid for which dirty rows should be flushed
    +         * @returns {promise} a promise that represents the aggregate of all
    +         * of the individual save promises - i.e. it will be resolved when all
    +         * the individual save promises have been resolved.
    +         * 
    +         */
    +        flushDirtyRows: function(grid){
    +          var promises = [];
    +          angular.forEach(grid.rowEdit.dirtyRows, function( gridRow ){
    +            service.saveRow( grid, gridRow )();
    +            promises.push( gridRow.rowEditSavePromise );
    +          });
    +          
    +          return $q.all( promises );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name endEditCell
    +         * @description Receives an afterCellEdit event from the edit function,
    +         * and sets flags as appropriate.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * was edited
    +         */        
    +        endEditCell: function( rowEntity, colDef, newValue, previousValue ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, dirty flag cannot be set' ); return; }
    +
    +          if ( newValue !== previousValue || gridRow.isDirty ){
    +            if ( !grid.rowEdit.dirtyRows ){
    +              grid.rowEdit.dirtyRows = [];
    +            }
    +            
    +            if ( !gridRow.isDirty ){
    +              gridRow.isDirty = true;
    +              grid.rowEdit.dirtyRows.push( gridRow );
    +            }
    +            
    +            delete gridRow.isError;
    +            
    +            service.considerSetTimer( grid, gridRow );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name beginEditCell
    +         * @description Receives a beginCellEdit event from the edit function,
    +         * and cancels any rowEditSaveTimers if present, as the user is still editing
    +         * this row.  Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi. 
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing has commenced
    +         */
    +        beginEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be cancelled' ); return; }
    +          
    +          service.cancelTimer( grid, gridRow );
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelEditCell
    +         * @description Receives a cancelCellEdit event from the edit function,
    +         * and if the row was already dirty, restarts the save timer.  If the row
    +         * was not already dirty, then it's not dirty now either and does nothing.
    +         * 
    +         * Only the rowEntity parameter
    +         * is processed, although other params are available.  Grid
    +         * is automatically provided by the gridApi.
    +         *  
    +         * @param {object} rowEntity the data entity for which the cell
    +         * editing was cancelled
    +         */        
    +        cancelEditCell: function( rowEntity, colDef ){
    +          var grid = this.grid;
    +          var gridRow = grid.getRow( rowEntity );
    +          if ( !gridRow ){ gridUtil.logError( 'Unable to find rowEntity in grid data, timer cannot be set' ); return; }
    +          
    +          service.considerSetTimer( grid, gridRow );
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name navigate
    +         * @description cellNav tells us that the selected cell has changed.  If
    +         * the new row had a timer running, then stop it similar to in a beginCellEdit
    +         * call.  If the old row is dirty and not the same as the new row, then 
    +         * start a timer on it.
    +         * @param {object} newRowCol the row and column that were selected
    +         * @param {object} oldRowCol the row and column that was left
    +         * 
    +         */
    +        navigate: function( newRowCol, oldRowCol ){
    +          var grid = this.grid;
    +          if ( newRowCol.row.rowEditSaveTimer ){
    +            service.cancelTimer( grid, newRowCol.row );
    +          }
    +
    +          if ( oldRowCol && oldRowCol.row && oldRowCol.row !== newRowCol.row ){
    +            service.considerSetTimer( grid, oldRowCol.row );
    +          }
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc property
    +         * @propertyOf ui.grid.rowEdit.api:GridOptions
    +         * @name rowEditWaitInterval
    +         * @description How long the grid should wait for another change on this row
    +         * before triggering a save (in milliseconds).  If set to -1, then saves are 
    +         * never triggered by timer (implying that the user will call flushDirtyRows() 
    +         * manually)
    +         * 
    +         * @example
    +         * Setting the wait interval to 4 seconds
    +         * <pre>
    +         *   $scope.gridOptions = { rowEditWaitInterval: 4000 }
    +         * </pre>
    +         * 
    +         */
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name considerSetTimer
    +         * @description Consider setting a timer on this row (if it is dirty).  if there is a timer running 
    +         * on the row and the row isn't currently saving, cancel it, using cancelTimer, then if the row is 
    +         * dirty and not currently saving then set a new timer
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        considerSetTimer: function( grid, gridRow ){
    +          service.cancelTimer( grid, gridRow );
    +          
    +          if ( gridRow.isDirty && !gridRow.isSaving ){
    +            if ( grid.options.rowEditWaitInterval !== -1 ){
    +              var waitTime = grid.options.rowEditWaitInterval ? grid.options.rowEditWaitInterval : 2000;
    +              gridRow.rowEditSaveTimer = $interval( service.saveRow( grid, gridRow ), waitTime, 1);
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name cancelTimer
    +         * @description cancel the $interval for any timer running on this row
    +         * then delete the timer itself
    +         * @param {object} grid the grid for which we are processing
    +         * @param {GridRow} gridRow the row for which the timer should be adjusted
    +         * 
    +         */
    +        cancelTimer: function( grid, gridRow ){
    +          if ( gridRow.rowEditSaveTimer && !gridRow.isSaving ){
    +            $interval.cancel(gridRow.rowEditSaveTimer);
    +            delete gridRow.rowEditSaveTimer;
    +          }
    +        },
    +
    +
    +        /**
    +         * @ngdoc method
    +         * @methodOf ui.grid.rowEdit.service:uiGridRowEditService
    +         * @name setRowsDirty
    +         * @description Sets each of the rows passed in dataRows
    +         * to be dirty.  note that if you have only just inserted the
    +         * rows into your data you will need to wait for a $digest cycle
    +         * before the gridRows are present - so often you would wrap this
    +         * call in a $interval or $timeout
    +         * <pre>
    +         *      $interval( function() {
    +         *        gridApi.rowEdit.setRowsDirty( myDataRows);
    +         *      }, 0, 1);
    +         * </pre>
    +         * @param {object} grid the grid for which rows should be set dirty
    +         * @param {array} dataRows the data entities for which the gridRows
    +         * should be set dirty.  
    +         * 
    +         */
    +        setRowsDirty: function( grid, myDataRows ) {
    +          var gridRow;
    +          myDataRows.forEach( function( value, index ){
    +            gridRow = grid.getRow( value );
    +            if ( gridRow ){
    +              if ( !grid.rowEdit.dirtyRows ){
    +                grid.rowEdit.dirtyRows = [];
    +              }
    +              
    +              if ( !gridRow.isDirty ){
    +                gridRow.isDirty = true;
    +                grid.rowEdit.dirtyRows.push( gridRow );
    +              }
    +              
    +              delete gridRow.isError;
    +              
    +              service.considerSetTimer( grid, gridRow );
    +            } else {
    +              gridUtil.logError( "requested row not found in rowEdit.setRowsDirty, row was: " + value );
    +            }
    +          });
    +        }
    +        
    +        
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridEdit
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds row editing features to the ui-grid-edit directive.
    +   *
    +   */
    +  module.directive('uiGridRowEdit', ['gridUtil', 'uiGridRowEditService', 'uiGridEditConstants', 
    +  function (gridUtil, uiGridRowEditService, uiGridEditConstants) {
    +    return {
    +      replace: true,
    +      priority: 0,
    +      require: '^uiGrid',
    +      scope: false,
    +      compile: function () {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +            uiGridRowEditService.initializeGrid($scope, uiGridCtrl.grid);
    +          },
    +          post: function ($scope, $elm, $attrs, uiGridCtrl) {            
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.rowEdit.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row to allow coloring of saving and error rows
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'gridUtil', '$parse',
    +      function ($compile, uiGridConstants, gridUtil, $parse) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +            
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.saveState
    +   * @description
    +   *
    +   *  # ui.grid.saveState
    +   * This module provides the ability to save the grid state, and restore
    +   * it when the user returns to the page.  
    +   * 
    +   * No UI is provided, the caller should provide their own UI/buttons 
    +   * as appropriate. Usually the navigate events would be used to save
    +   * the grid state and restore it.
    +   * 
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.save-state"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.saveState', ['ui.grid', 'ui.grid.selection', 'ui.grid.cellNav']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.saveState.constant:uiGridSaveStateConstants
    +   *
    +   *  @description constants available in save state module
    +   */
    +
    +  module.constant('uiGridSaveStateConstants', {
    +    featureName: 'saveState'
    +  });
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.saveState.service:uiGridSaveStateService
    +   *
    +   *  @description Services for saveState feature
    +   */
    +  module.service('uiGridSaveStateService', ['$q', 'uiGridSaveStateConstants', 'gridUtil', '$compile', '$interval', 'uiGridConstants',
    +    function ($q, uiGridSaveStateConstants, gridUtil, $compile, $interval, uiGridConstants ) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed state
    +          grid.saveState = {};
    +          this.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.saveState.api:PublicApi
    +           *
    +           *  @description Public Api for saveState feature
    +           */
    +          var publicApi = {
    +            events: {
    +              saveState: {
    +              }
    +            },
    +            methods: {
    +              saveState: {
    +                /**
    +                 * @ngdoc function
    +                 * @name save
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Packages the current state of the grid into 
    +                 * an object, and provides it to the user for saving
    +                 * @returns {object} the state as a javascript object that can be saved
    +                 */
    +                save: function () {
    +                  return service.save(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name restore
    +                 * @methodOf  ui.grid.saveState.api:PublicApi
    +                 * @description Restores the provided state into the grid
    +                 * @param {scope} $scope a scope that we can broadcast on
    +                 * @param {object} state the state that should be restored into the grid
    +                 */
    +                restore: function ( $scope, state) {
    +                  service.restore(grid, $scope, state);
    +                }
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +          
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           * @ngdoc object
    +           * @name ui.grid.saveState.api:GridOptions
    +           *
    +           * @description GridOptions for saveState feature, these are available to be  
    +           * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveWidths
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column widths.  Note that unless
    +           * you've provided the user with some way to resize their columns (say
    +           * the resize columns feature), then this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveWidths = gridOptions.saveWidths !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveOrder
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current column order.  Note that unless
    +           * you've provided the user with some way to reorder their columns (for
    +           * example the move columns feature), this makes little sense.
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveOrder = gridOptions.saveOrder !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveScroll
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current scroll position.  Note that this
    +           * is saved as the percentage of the grid scrolled - so if your
    +           * user returns to a grid with a significantly different number of 
    +           * rows (perhaps some data has been deleted) then the scroll won't 
    +           * actually show the same rows as before.  If you want to scroll to
    +           * a specific row then you should instead use the saveFocus option, which
    +           * is the default.
    +           * 
    +           * Note that this element will only be saved if the cellNav feature is
    +           * enabled
    +           * <br/>Defaults to false
    +           */
    +          gridOptions.saveScroll = gridOptions.saveScroll === true;
    +          /**
    +           * @ngdoc object
    +           * @name saveFocus
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current focused cell.  On returning
    +           * to this focused cell we'll also scroll.  This option is
    +           * preferred to the saveScroll option, so is set to true by
    +           * default.  If saveScroll is set to true then this option will 
    +           * be disabled.  
    +           * 
    +           * By default this option saves the current row number and column 
    +           * number, and returns to that row and column.  However, if you define
    +           * a saveRowIdentity function, then it will return you to the currently 
    +           * selected column within that row (in a business sense - so if some
    +           * rows have been deleted, it will still find the same data, presuming it 
    +           * still exists in the list.  If it isn't in the list then it will instead
    +           * return to the same row number - i.e. scroll percentage)
    +           * 
    +           * Note that this option will do nothing if the cellNav
    +           * feature is not enabled.
    +           * 
    +           * <br/>Defaults to true (unless saveScroll is true)
    +           */
    +          gridOptions.saveFocus = gridOptions.saveScroll !== true && gridOptions.saveFocus !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveRowIdentity
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description A function that can be called, passing in a rowEntity, 
    +           * and that will return a unique id for that row.  This might simply 
    +           * return the `id` field from that row (if you have one), or it might
    +           * concatenate some fields within the row to make a unique value.
    +           * 
    +           * This value will be used to find the same row again and set the focus 
    +           * to it, if it exists when we return.
    +           * 
    +           * <br/>Defaults to undefined
    +           */
    +          /**
    +           * @ngdoc object
    +           * @name saveVisible
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save whether or not columns are visible.
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveVisible = gridOptions.saveVisible !== false;          
    +          /**
    +           * @ngdoc object
    +           * @name saveSort
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current sort state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSort = gridOptions.saveSort !== false;         
    +          /**
    +           * @ngdoc object
    +           * @name saveFilter
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the current filter state for each column
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveFilter = gridOptions.saveFilter !== false;
    +          /**
    +           * @ngdoc object
    +           * @name saveSelection
    +           * @propertyOf  ui.grid.saveState.api:GridOptions
    +           * @description Save the currently selected rows.  If the `saveRowIdentity` callback
    +           * is defined, then it will save the id of the row and select that.  If not, then
    +           * it will attempt to select the rows by row number, which will give the wrong results
    +           * if the data set has changed in the mean-time.
    +           * 
    +           * Note that this option only does anything
    +           * if the selection feature is enabled.  
    +           * 
    +           * <br/>Defaults to true
    +           */
    +          gridOptions.saveSelection = gridOptions.saveSelection !== false;          
    +        },
    +
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name save
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the current grid state into an object, and
    +         * passes that object back to the caller
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the state ready to be saved
    +         */
    +        save: function (grid) {
    +          var savedState = {};
    +          
    +          savedState.columns = service.saveColumns( grid );
    +          savedState.scrollFocus = service.saveScrollFocus( grid );
    +          savedState.selection = service.saveSelection( grid );
    +          
    +          return savedState;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restore
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Applies the provided state to the grid
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} state the state we'd like to restore
    +         */
    +        restore: function( grid, $scope, state ){
    +          if ( state.columns ) {
    +            service.restoreColumns( grid, state.columns );
    +          }
    +          
    +          if ( state.scrollFocus ){
    +            service.restoreScrollFocus( grid, $scope, state.scrollFocus );
    +          }
    +          
    +          if ( state.selection ){
    +            service.restoreSelection( grid, state.selection );
    +          }
    +          
    +          grid.refresh();
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name saveColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the column setup, including sort, filters, ordering
    +         * and column widths.
    +         * 
    +         * Works through the current columns, storing them in order.  Stores the
    +         * column name, then the visible flag, width, sort and filters for each column.
    +         *
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {array} the columns state ready to be saved
    +         */
    +        saveColumns: function( grid ) {
    +          var columns = [];
    +          angular.forEach( grid.columns, function( column ) {
    +            var savedColumn = {};
    +            savedColumn.name = column.name;
    +            savedColumn.visible = column.visible;
    +            savedColumn.width = column.width;
    +            
    +            // these two must be copied, not just pointed too - otherwise our saved state is pointing to the same object as current state
    +            savedColumn.sort = angular.copy( column.sort );
    +            savedColumn.filters = angular.copy ( column.filters );
    +            columns.push( savedColumn );
    +          });
    +          
    +          return columns;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently scroll or focus.
    +         * 
    +         * If cellNav isn't present then does nothing - we can't return
    +         * to the scroll position without cellNav anyway.
    +         * 
    +         * If the cellNav module is present, and saveFocus is true, then
    +         * it saves the currently focused cell.  If rowIdentity is present
    +         * then saves using rowIdentity, otherwise saves visibleRowNum.
    +         * 
    +         * If the cellNav module is not present, and saveScroll is true, then
    +         * it approximates the current scroll row and column, and saves that.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveScrollFocus: function( grid ){
    +          if ( !grid.api.cellNav ){
    +            return {};
    +          }
    +          
    +          var scrollFocus = {};
    +          if ( grid.options.saveFocus ){
    +            scrollFocus.focus = true;
    +            var rowCol = grid.api.cellNav.getFocusedCell();
    +            if ( rowCol !== null ) {
    +              scrollFocus.colName = rowCol.col.colDef.name;
    +              scrollFocus.rowVal = service.getRowVal( grid, rowCol.row );
    +            }
    +          } else if ( grid.options.saveScroll ) {
    +            scrollFocus.focus = false;
    +            if ( grid.renderContainers.body.prevRowScrollIndex ){
    +              scrollFocus.rowVal = service.getRowVal( grid, grid.renderContainers.body.visibleRowCache[ grid.renderContainers.body.prevRowScrollIndex ]);
    +            }
    +            
    +            if ( grid.renderContainers.body.prevColScrollIndex ){
    +              scrollFocus.colName = grid.renderContainers.body.visibleColumnCache[ grid.renderContainers.body.prevColScrollIndex ].name;
    +            }
    +          }        
    +          
    +          return scrollFocus;
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name saveSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Saves the currently selected rows, if the selection feature is enabled
    +         * @param {Grid} grid the grid whose state we'd like to save
    +         * @returns {object} the selection state ready to be saved
    +         */
    +        saveSelection: function( grid ){
    +          if ( !grid.api.selection || !grid.options.saveSelection ){
    +            return {};
    +          }
    +
    +          var selection = grid.api.selection.getSelectedGridRows().map( function( gridRow ) {
    +            return service.getRowVal( grid, gridRow );
    +          });
    +
    +          return selection;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name getRowVal
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Helper function that gets either the rowNum or
    +         * the saveRowIdentity, given a gridRow 
    +         * @param {Grid} grid the grid the row is in
    +         * @param {GridRow} gridRow the row we want the rowNum for
    +         * @returns {object} an object containing { identity: true/false, row: rowNumber/rowIdentity }
    +         * 
    +         */
    +        getRowVal: function( grid, gridRow ){
    +          if ( !gridRow ) {
    +            return null;
    +          }
    +          
    +          var rowVal = {};
    +          if ( grid.options.saveRowIdentity ){
    +            rowVal.identity = true;
    +            rowVal.row = grid.options.saveRowIdentity( gridRow.entity );
    +          } else {
    +            rowVal.identity = false;
    +            rowVal.row = grid.renderContainers.body.visibleRowCache.indexOf( gridRow );
    +          }
    +          return rowVal;
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name restoreColumns
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Restores the columns, including order, visible, width
    +         * sort and filters.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} columnsState the list of columns we had before, with their state
    +         */
    +        restoreColumns: function( grid, columnsState ){
    +          angular.forEach( columnsState, function( columnState, index ) {
    +            var currentCol = grid.columns.filter( function( column ) {
    +              return column.name === columnState.name;
    +            });
    +            
    +            if ( currentCol.length > 0 ){
    +              var currentIndex = grid.columns.indexOf( currentCol[0] );
    +              
    +              if ( grid.columns[currentIndex].visible !== columnState.visible ||
    +                   grid.columns[currentIndex].colDef.visible !== columnState.visible ){
    +                grid.columns[currentIndex].visible = columnState.visible;
    +                grid.columns[currentIndex].colDef.visible = columnState.visible;
    +                grid.api.core.raise.columnVisibilityChanged( grid.columns[currentIndex]);
    +              }
    +              
    +              grid.columns[currentIndex].width = columnState.width;
    +
    +              if ( !angular.equals(grid.columns[currentIndex].sort, columnState.sort) &&
    +                   !( grid.columns[currentIndex].sort === undefined && angular.isEmpty(columnState.sort) ) ){
    +                grid.columns[currentIndex].sort = angular.copy( columnState.sort );
    +                grid.api.core.raise.sortChanged();
    +              }
    +
    +              if ( !angular.equals(grid.columns[currentIndex].filters, columnState.filters ) ){
    +                grid.columns[currentIndex].filters = angular.copy( columnState.filters );
    +                grid.api.core.raise.filterChanged();
    +              }
    +              
    +              if ( currentIndex !== index ){
    +                var column = grid.columns.splice( currentIndex, 1 )[0];
    +                grid.columns.splice( index, 0, column );
    +              }
    +            }
    +          });
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreScrollFocus
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Scrolls to the position that was saved.  If focus is true, then
    +         * sets focus to the specified row/col.  If focus is false, then scrolls to the 
    +         * specified row/col.
    +         * 
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {scope} $scope a scope that we can broadcast on
    +         * @param {object} scrollFocusState the scroll/focus state ready to be restored
    +         */
    +        restoreScrollFocus: function( grid, $scope, scrollFocusState ){
    +          if ( !grid.api.cellNav ){
    +            return;
    +          }
    +          
    +          var colDef, row;
    +          if ( scrollFocusState.colName ){
    +            var colDefs = grid.options.columnDefs.filter( function( colDef ) { return colDef.name === scrollFocusState.colName; });
    +            if ( colDefs.length > 0 ){
    +              colDef = colDefs[0];
    +            }
    +          }
    +          
    +          if ( scrollFocusState.rowVal && scrollFocusState.rowVal.row ){
    +            if ( scrollFocusState.rowVal.identity ){
    +              row = service.findRowByIdentity( grid, scrollFocusState.rowVal );
    +            } else {
    +              row = grid.renderContainers.body.visibleRowCache[ scrollFocusState.rowVal.row ];
    +            }
    +          }
    +          
    +          var entity = row && row.entity ? row.entity : null ;
    +
    +          if ( colDef || entity ) {          
    +            if (scrollFocusState.focus ){
    +              grid.api.cellNav.scrollToFocus( entity, colDef );
    +            } else {
    +              grid.api.cellNav.scrollTo( entity, colDef );
    +            }
    +          }
    +        },
    +        
    +
    +        /**
    +         * @ngdoc function
    +         * @name restoreSelection
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Selects the rows that are provided in the selection
    +         * state.  If you are using `saveRowIdentity` and more than one row matches the identity
    +         * function then only the first is selected.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} selectionState the selection state ready to be restored
    +         */
    +        restoreSelection: function( grid, selectionState ){
    +          if ( !grid.api.selection ){
    +            return;
    +          }
    +          
    +          grid.api.selection.clearSelectedRows();
    +
    +          angular.forEach( selectionState, function( rowVal ) {
    +            if ( rowVal.identity ){
    +              var foundRow = service.findRowByIdentity( grid, rowVal );
    +              
    +              if ( foundRow ){
    +                grid.api.selection.selectRow( foundRow.entity );
    +              }
    +              
    +            } else {
    +              grid.api.selection.selectRowByVisibleIndex( rowVal.row );
    +            }
    +          });
    +        },
    +        
    +        
    +        /**
    +         * @ngdoc function
    +         * @name findRowByIdentity
    +         * @methodOf  ui.grid.saveState.service:uiGridSaveStateService
    +         * @description Finds a row given it's identity value, returns the first found row
    +         * if any are found, otherwise returns null if no rows are found.
    +         * @param {Grid} grid the grid whose state we'd like to restore
    +         * @param {object} rowVal the row we'd like to find
    +         * @returns {gridRow} the found row, or null if none found
    +         */
    +        findRowByIdentity: function( grid, rowVal ){
    +          if ( !grid.options.saveRowIdentity ){
    +            return null;
    +          }
    +          
    +          var filteredRows = grid.rows.filter( function( gridRow ) {
    +            if ( grid.options.saveRowIdentity( gridRow.entity ) === rowVal.row ){
    +              return true;
    +            } else {
    +              return false;
    +            }
    +          });
    +          
    +          if ( filteredRows.length > 0 ){
    +            return filteredRows[0];
    +          } else {
    +            return null;
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }
    +  ]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.saveState.directive:uiGridSaveState
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds saveState features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.saveState']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +        { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.gridOptions = {
    +        columnDefs: [
    +          {name: 'name'},
    +          {name: 'title', enableCellEdit: true}
    +        ],
    +        data: $scope.data
    +      };
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="gridOptions" ui-grid-save-state></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSaveState', ['uiGridSaveStateConstants', 'uiGridSaveStateService', 'gridUtil', '$compile',
    +    function (uiGridSaveStateConstants, uiGridSaveStateService, gridUtil, $compile) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        link: function ($scope, $elm, $attrs, uiGridCtrl) {
    +          uiGridSaveStateService.initializeGrid(uiGridCtrl.grid);
    +        }
    +      };
    +    }
    +  ]);
    +})();
    +
    +(function () {
    +  'use strict';
    +
    +  /**
    +   * @ngdoc overview
    +   * @name ui.grid.selection
    +   * @description
    +   *
    +   *  # ui.grid.selection
    +   * This module provides row selection
    +   * <br/>
    +   * <br/>
    +   *
    +   * <div doc-module-components="ui.grid.selection"></div>
    +   */
    +
    +  var module = angular.module('ui.grid.selection', ['ui.grid']);
    +
    +  /**
    +   *  @ngdoc object
    +   *  @name ui.grid.selection.constant:uiGridSelectionConstants
    +   *
    +   *  @description constants available in selection module
    +   */
    +  module.constant('uiGridSelectionConstants', {
    +    featureName: "selection",
    +    selectionRowHeaderColName: 'selectionRowHeaderCol'
    +  });
    +
    +  //add methods to GridRow
    +  angular.module('ui.grid').config(['$provide', function($provide) {
    +    $provide.decorator('GridRow', ['$delegate', function($delegate) {
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name ui.grid.selection.api:GridRow
    +       *
    +       *  @description GridRow prototype functions added for selection
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name enableSelection
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Enable row selection for this row, only settable by internal code.
    +       *
    +       *  The grouping feature, for example, might set group header rows to not be selectable.
    +       *  <br/>Defaults to true
    +       */
    +
    +      /**
    +       *  @ngdoc object
    +       *  @name isSelected
    +       *  @propertyOf  ui.grid.selection.api:GridRow
    +       *  @description Selected state of row.  Should be readonly. Make any changes to selected state using setSelected().
    +       *  <br/>Defaults to false
    +       */
    +
    +
    +        /**
    +         * @ngdoc function
    +         * @name setSelected
    +         * @methodOf ui.grid.selection.api:GridRow
    +         * @description Sets the isSelected property and updates the selectedCount
    +         * Changes to isSelected state should only be made via this function
    +         * @param {bool} selelected value to set
    +         */
    +        $delegate.prototype.setSelected = function(selected) {
    +          this.isSelected = selected;
    +          if (selected) {
    +            this.grid.selection.selectedCount++;
    +          }
    +          else {
    +            this.grid.selection.selectedCount--;
    +          }
    +        };
    +
    +      return $delegate;
    +    }]);
    +  }]);
    +
    +  /**
    +   *  @ngdoc service
    +   *  @name ui.grid.selection.service:uiGridSelectionService
    +   *
    +   *  @description Services for selection features
    +   */
    +  module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil',
    +    function ($q, $templateCache, uiGridSelectionConstants, gridUtil) {
    +
    +      var service = {
    +
    +        initializeGrid: function (grid) {
    +
    +          //add feature namespace and any properties to grid for needed
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.grid:selection
    +           *
    +           *  @description Grid properties and functions added for selection
    +           */
    +          grid.selection = {};
    +          grid.selection.lastSelectedRow = null;
    +          grid.selection.selectAll = false;
    +
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name selectedCount
    +           *  @propertyOf  ui.grid.selection.grid:selection
    +           *  @description Current count of selected rows
    +           *  @example
    +           *  var count = grid.selection.selectedCount
    +           */
    +          grid.selection.selectedCount = 0;
    +
    +          service.defaultGridOptions(grid.options);
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:PublicApi
    +           *
    +           *  @description Public Api for selection feature
    +           */
    +          var publicApi = {
    +            events: {
    +              selection: {
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChanged
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * @param {GridRow} row the row that was selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChanged: function (scope, row, evt) {
    +                },
    +                /**
    +                 * @ngdoc event
    +                 * @name rowSelectionChangedBatch
    +                 * @eventOf  ui.grid.selection.api:PublicApi
    +                 * @description  is raised after the row.isSelected state is changed
    +                 * in bulk, if the `enableSelectionBatchEvent` option is set to true
    +                 * (which it is by default).  This allows more efficient processing
    +                 * of bulk events.
    +                 * @param {array} rows the rows that were selected/deselected
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                rowSelectionChangedBatch: function (scope, rows, evt) {
    +                }
    +              }
    +            },
    +            methods: {
    +              selection: {
    +                /**
    +                 * @ngdoc function
    +                 * @name toggleRowSelection
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Toggles data row as selected or unselected
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                toggleRowSelection: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectRowByVisibleIndex
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Select the specified row by visible index (i.e. if you
    +                 * specify row 0 you'll get the first visible row selected).  In this context
    +                 * visible means of those rows that are theoretically visible (i.e. not filtered),
    +                 * rather than rows currently rendered on the screen.
    +                 * @param {number} index index within the rowsVisible array
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectRowByVisibleIndex: function ( rowNum, evt ) {
    +                  var row = grid.renderContainers.body.visibleRowCache[rowNum];
    +                  if (row !== null && typeof(row) !== 'undefined' && !row.isSelected && row.enableSelection !== false) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name unSelectRow
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description UnSelect the data row
    +                 * @param {object} rowEntity gridOptions.data[] array instance
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                unSelectRow: function (rowEntity, evt) {
    +                  var row = grid.getRow(rowEntity);
    +                  if (row !== null && row.isSelected) {
    +                    service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
    +                  }
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if ( !row.isSelected && row.enableSelection !== false ){
    +                      row.setSelected(true);
    +                      service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name selectAllVisibleRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Selects all visible rows.  Does nothing if multiSelect = false
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                selectAllVisibleRows: function (evt) {
    +                  if (grid.options.multiSelect === false) {
    +                    return;
    +                  }
    +
    +                  var changedRows = [];
    +                  grid.rows.forEach(function (row) {
    +                    if (row.visible) {
    +                      if (!row.isSelected && row.enableSelection !== false){
    +                        row.setSelected(true);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    } else {
    +                      if (row.isSelected){
    +                        row.setSelected(false);
    +                        service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +                      }
    +                    }
    +                  });
    +                  service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +                  grid.selection.selectAll = true;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name clearSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Unselects all rows
    +                 * @param {Event} event object if raised from an event
    +                 */
    +                clearSelectedRows: function (evt) {
    +                  service.clearSelectedRows(grid, evt);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's entity references
    +                 */
    +                getSelectedRows: function () {
    +                  return service.getSelectedRows(grid).map(function (gridRow) {
    +                    return gridRow.entity;
    +                  });
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectedGridRows
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description returns all selectedRow's as gridRows
    +                 */
    +                getSelectedGridRows: function () {
    +                  return service.getSelectedRows(grid);
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.multiSelect to true or false
    +                 * @param {bool} multiSelect true to allow multiple rows
    +                 */
    +                setMultiSelect: function (multiSelect) {
    +                  grid.options.multiSelect = multiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name setModifierKeysToMultiSelect
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Sets the current gridOption.modifierKeysToMultiSelect to true or false
    +                 * @param {bool} modifierKeysToMultiSelect true to only allow multiple rows when using ctrlKey or shiftKey is used
    +                 */
    +                setModifierKeysToMultiSelect: function (modifierKeysToMultiSelect) {
    +                  grid.options.modifierKeysToMultiSelect = modifierKeysToMultiSelect;
    +                },
    +                /**
    +                 * @ngdoc function
    +                 * @name getSelectAllState
    +                 * @methodOf  ui.grid.selection.api:PublicApi
    +                 * @description Returns whether or not the selectAll checkbox is currently ticked.  The
    +                 * grid doesn't automatically select rows when you add extra data - so when you add data
    +                 * you need to explicitly check whether the selectAll is set, and then call setVisible rows
    +                 * if it is
    +                 */
    +                getSelectAllState: function () {
    +                  return grid.selection.selectAll;
    +                }
    +
    +              }
    +            }
    +          };
    +
    +          grid.api.registerEventsFromObject(publicApi.events);
    +
    +          grid.api.registerMethodsFromObject(publicApi.methods);
    +
    +        },
    +
    +        defaultGridOptions: function (gridOptions) {
    +          //default option to true unless it was explicitly set to false
    +          /**
    +           *  @ngdoc object
    +           *  @name ui.grid.selection.api:GridOptions
    +           *
    +           *  @description GridOptions for selection feature, these are available to be
    +           *  set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
    +           */
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable row selection for entire grid.
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowSelection = gridOptions.enableRowSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name multiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection for entire grid
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.multiSelect = gridOptions.multiSelect !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name noUnselect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Prevent a row from being unselected.  Works in conjunction
    +           *  with `multiselect = false` and `gridApi.selection.selectRow()` to allow
    +           *  you to create a single selection only grid - a row is always selected, you
    +           *  can only select different rows, you can't unselect the row.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.noUnselect = gridOptions.noUnselect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name modifierKeysToMultiSelect
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable multiple row selection only when using the ctrlKey or shiftKey. Requires multiSelect to be true.
    +           *  <br/>Defaults to false
    +           */
    +          gridOptions.modifierKeysToMultiSelect = gridOptions.modifierKeysToMultiSelect === true;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableRowHeaderSelection
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable a row header to be used for selection
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableRowHeaderSelection = gridOptions.enableRowHeaderSelection !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectAll
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Enable the select all checkbox at the top of the selectionRowHeader
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectAll = gridOptions.enableSelectAll !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name enableSelectionBatchEvent
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description If selected rows are changed in bulk, either via the API or
    +           *  via the selectAll checkbox, then a separate event is fired.  Setting this
    +           *  option to false will cause the rowSelectionChanged event to be called multiple times
    +           *  instead
    +           *  <br/>Defaults to true
    +           */
    +          gridOptions.enableSelectionBatchEvent = gridOptions.enableSelectionBatchEvent !== false;
    +          /**
    +           *  @ngdoc object
    +           *  @name selectionRowHeaderWidth
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description can be used to set a custom width for the row header selection column
    +           *  <br/>Defaults to 30px
    +           */
    +          gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name enableFooterTotalSelected
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Shows the total number of selected items in footer if true.
    +           *  <br/>Defaults to true.
    +           *  <br/>GridOptions.showFooter must also be set to true.
    +           */
    +          gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false;
    +
    +          /**
    +           *  @ngdoc object
    +           *  @name isRowSelectable
    +           *  @propertyOf  ui.grid.selection.api:GridOptions
    +           *  @description Makes it possible to specify a method that evaluates for each and sets its "enableSelection" property.
    +           */
    +
    +          gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name toggleRowSelection
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Toggles row as selected or unselected
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row to select or deselect
    +         * @param {Event} event object if resulting from event
    +         * @param {bool} multiSelect if false, only one row at time can be selected
    +         * @param {bool} noUnselect if true then rows cannot be unselected
    +         */
    +        toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) {
    +          var selected = row.isSelected;
    +
    +          if (!multiSelect && !selected) {
    +            service.clearSelectedRows(grid, evt);
    +          } else if (!multiSelect && selected) {
    +            var selectedRows = service.getSelectedRows(grid);
    +            if (selectedRows.length > 1) {
    +              selected = false; // Enable reselect of the row
    +              service.clearSelectedRows(grid, evt);
    +            }
    +          }
    +
    +          if (selected && noUnselect){
    +            // don't deselect the row 
    +          } else if (row.enableSelection !== false) {
    +            row.setSelected(!selected);
    +            if (row.isSelected === true) {
    +              grid.selection.lastSelectedRow = row;
    +            } else {
    +              grid.selection.selectAll = false;
    +            }
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          }
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name shiftSelect
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description selects a group of rows from the last selected row using the shift key
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} clicked row
    +         * @param {Event} event object if raised from an event
    +         * @param {bool} multiSelect if false, does nothing this is for multiSelect only
    +         */
    +        shiftSelect: function (grid, row, evt, multiSelect) {
    +          if (!multiSelect) {
    +            return;
    +          }
    +          var selectedRows = service.getSelectedRows(grid);
    +          var fromRow = selectedRows.length > 0 ? grid.renderContainers.body.visibleRowCache.indexOf(grid.selection.lastSelectedRow) : 0;
    +          var toRow = grid.renderContainers.body.visibleRowCache.indexOf(row);
    +          //reverse select direction
    +          if (fromRow > toRow) {
    +            var tmp = fromRow;
    +            fromRow = toRow;
    +            toRow = tmp;
    +          }
    +
    +          var changedRows = [];
    +          for (var i = fromRow; i <= toRow; i++) {
    +            var rowToSelect = grid.renderContainers.body.visibleRowCache[i];
    +            if (rowToSelect) {
    +              if ( !rowToSelect.isSelected && rowToSelect.enableSelection !== false ){
    +                rowToSelect.setSelected(true);
    +                grid.selection.lastSelectedRow = rowToSelect;
    +                service.decideRaiseSelectionEvent( grid, rowToSelect, changedRows, evt );
    +              }
    +            }
    +          }
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +        },
    +        /**
    +         * @ngdoc function
    +         * @name getSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Returns all the selected rows
    +         * @param {Grid} grid grid object
    +         */
    +        getSelectedRows: function (grid) {
    +          return grid.rows.filter(function (row) {
    +            return row.isSelected;
    +          });
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name clearSelectedRows
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Clears all selected rows
    +         * @param {Grid} grid grid object
    +         * @param {Event} event object if raised from an event
    +         */
    +        clearSelectedRows: function (grid, evt) {
    +          var changedRows = [];
    +          service.getSelectedRows(grid).forEach(function (row) {
    +            if ( row.isSelected ){
    +              row.setSelected(false);
    +              service.decideRaiseSelectionEvent( grid, row, changedRows, evt );
    +            }
    +          });
    +          service.decideRaiseSelectionBatchEvent( grid, changedRows, evt );
    +          grid.selection.selectAll = false;
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name decideRaiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether to raise a single event or a batch event
    +         * @param {Grid} grid grid object
    +         * @param {GridRow} row row that has changed
    +         * @param {array} changedRows an array to which we can append the changed
    +         * @param {Event} event object if raised from an event
    +         * row if we're doing batch events
    +         */
    +        decideRaiseSelectionEvent: function( grid, row, changedRows, evt ){
    +          if ( !grid.options.enableSelectionBatchEvent ){
    +            grid.api.selection.raise.rowSelectionChanged(row, evt);
    +          } else {
    +            changedRows.push(row);
    +          }
    +        },
    +
    +        /**
    +         * @ngdoc function
    +         * @name raiseSelectionEvent
    +         * @methodOf  ui.grid.selection.service:uiGridSelectionService
    +         * @description Decides whether we need to raise a batch event, and
    +         * raises it if we do.
    +         * @param {Grid} grid grid object
    +         * @param {array} changedRows an array of changed rows, only populated
    +         * @param {Event} event object if raised from an event
    +         * if we're doing batch events
    +         */
    +        decideRaiseSelectionBatchEvent: function( grid, changedRows, evt ){
    +          if ( changedRows.length > 0 ){
    +            grid.api.selection.raise.rowSelectionChangedBatch(changedRows, evt);
    +          }
    +        }
    +      };
    +
    +      return service;
    +
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridSelection
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Adds selection features to grid
    +   *
    +   *  @example
    +   <example module="app">
    +   <file name="app.js">
    +   var app = angular.module('app', ['ui.grid', 'ui.grid.selection']);
    +
    +   app.controller('MainCtrl', ['$scope', function ($scope) {
    +      $scope.data = [
    +        { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +      ];
    +
    +      $scope.columnDefs = [
    +        {name: 'name', enableCellEdit: true},
    +        {name: 'title', enableCellEdit: true}
    +      ];
    +    }]);
    +   </file>
    +   <file name="index.html">
    +   <div ng-controller="MainCtrl">
    +   <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-selection></div>
    +   </div>
    +   </file>
    +   </example>
    +   */
    +  module.directive('uiGridSelection', ['uiGridSelectionConstants', 'uiGridSelectionService', '$templateCache',
    +    function (uiGridSelectionConstants, uiGridSelectionService, $templateCache) {
    +      return {
    +        replace: true,
    +        priority: 0,
    +        require: '^uiGrid',
    +        scope: false,
    +        compile: function () {
    +          return {
    +            pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +              uiGridSelectionService.initializeGrid(uiGridCtrl.grid);
    +              if (uiGridCtrl.grid.options.enableRowHeaderSelection) {
    +                var selectionRowHeaderDef = {
    +                  name: uiGridSelectionConstants.selectionRowHeaderColName,
    +                  displayName: '',
    +                  width:  uiGridCtrl.grid.options.selectionRowHeaderWidth,
    +                  minWidth: 10,
    +                  cellTemplate: 'ui-grid/selectionRowHeader',
    +                  headerCellTemplate: 'ui-grid/selectionHeaderCell',
    +                  enableColumnResizing: false,
    +                  enableColumnMenu: false,
    +                  exporterSuppressExport: true 
    +                };
    +
    +                uiGridCtrl.grid.addRowHeaderColumn(selectionRowHeaderDef);
    +              }
    +              
    +              if (uiGridCtrl.grid.options.isRowSelectable !== angular.noop) {
    +                uiGridCtrl.grid.registerRowBuilder(function(row, options) {
    +                  row.enableSelection = uiGridCtrl.grid.options.isRowSelectable(row);
    +                });
    +              }
    +            },
    +            post: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionRowHeaderButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionRowHeaderButtons'),
    +        scope: true,
    +        require: '^uiGrid',
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = uiGridCtrl.grid;
    +          $scope.selectButtonClick = function(row, evt) {
    +            if (evt.shiftKey) {
    +              uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
    +            }
    +            else if (evt.ctrlKey || evt.metaKey) {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
    +            }
    +            else {
    +              uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  module.directive('uiGridSelectionSelectAllButtons', ['$templateCache', 'uiGridSelectionService',
    +    function ($templateCache, uiGridSelectionService) {
    +      return {
    +        replace: true,
    +        restrict: 'E',
    +        template: $templateCache.get('ui-grid/selectionSelectAllButtons'),
    +        scope: false,
    +        link: function($scope, $elm, $attrs, uiGridCtrl) {
    +          var self = $scope.col.grid;
    +
    +          $scope.headerButtonClick = function(row, evt) {
    +            if ( self.selection.selectAll ){
    +              uiGridSelectionService.clearSelectedRows(self, evt);
    +              if ( self.options.noUnselect ){
    +                self.api.selection.selectRowByVisibleIndex(0, evt);
    +              }
    +              self.selection.selectAll = false;
    +            } else {
    +              if ( self.options.multiSelect ){
    +                self.api.selection.selectAllVisibleRows(evt);
    +                self.selection.selectAll = true;
    +              }
    +            }
    +          };
    +        }
    +      };
    +    }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridViewport
    +   *  @element div
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridViewport to alter the attributes used
    +   *  for the grid row
    +   */
    +  module.directive('uiGridViewport',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default  directive
    +          scope: false,
    +          compile: function ($elm, $attrs) {
    +            var rowRepeatDiv = angular.element($elm.children().children()[0]);
    +
    +            var existingNgClass = rowRepeatDiv.attr("ng-class");
    +            var newNgClass = '';
    +            if ( existingNgClass ) {
    +              newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}";
    +            } else {
    +              newNgClass = "{'ui-grid-row-selected': row.isSelected}";
    +            }
    +            rowRepeatDiv.attr("ng-class", newNgClass);
    +
    +            return {
    +              pre: function ($scope, $elm, $attrs, controllers) {
    +
    +              },
    +              post: function ($scope, $elm, $attrs, controllers) {
    +              }
    +            };
    +          }
    +        };
    +      }]);
    +
    +  /**
    +   *  @ngdoc directive
    +   *  @name ui.grid.selection.directive:uiGridCell
    +   *  @element div
    +   *  @restrict A
    +   *
    +   *  @description Stacks on top of ui.grid.uiGridCell to provide selection feature
    +   */
    +  module.directive('uiGridCell',
    +    ['$compile', 'uiGridConstants', 'uiGridSelectionConstants', 'gridUtil', '$parse', 'uiGridSelectionService',
    +      function ($compile, uiGridConstants, uiGridSelectionConstants, gridUtil, $parse, uiGridSelectionService) {
    +        return {
    +          priority: -200, // run after default uiGridCell directive
    +          restrict: 'A',
    +          scope: false,
    +          link: function ($scope, $elm, $attrs) {
    +
    +            var touchStartTime = 0;
    +            var touchTimeout = 300;
    +            var selectCells = function(evt){
    +              if (evt.shiftKey) {
    +                uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect);
    +              }
    +              else if (evt.ctrlKey || evt.metaKey) {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect);
    +              }
    +              else {
    +                uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect);
    +              }
    +              $scope.$apply();
    +            };
    +
    +            var touchStart = function(evt){
    +              touchStartTime = (new Date()).getTime();
    +            };
    +
    +            var touchEnd = function(evt) {
    +              var touchEndTime = (new Date()).getTime();
    +              var touchTime = touchEndTime - touchStartTime;
    +
    +              if (touchTime < touchTimeout ) {
    +                // short touch
    +                selectCells(evt);
    +              }
    +            };
    +
    +            function registerRowSelectionEvents() {
    +              if ($scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection) {
    +                $elm.addClass('ui-grid-disable-selection');
    +                $elm.on('touchstart', touchStart);
    +                $elm.on('touchend', touchEnd);
    +                $elm.on('click', selectCells);
    +
    +                $scope.registered = true;
    +              }
    +            }
    +
    +            function deregisterRowSelectionEvents() {
    +              if ($scope.registered){
    +                $elm.removeClass('ui-grid-disable-selection');
    +
    +                $elm.off('touchstart', touchStart);
    +                $elm.off('touchend', touchEnd);
    +                $elm.off('click', selectCells);
    +
    +                $scope.registered = false;
    +              }
    +            }
    +
    +            registerRowSelectionEvents();
    +            // register a dataChange callback so that we can change the selection configuration dynamically
    +            // if the user changes the options
    +            var dataChangeDereg = $scope.grid.registerDataChangeCallback( function() {
    +              if ( $scope.grid.options.enableRowSelection && !$scope.grid.options.enableRowHeaderSelection &&
    +                !$scope.registered ){
    +                registerRowSelectionEvents();
    +              } else if ( ( !$scope.grid.options.enableRowSelection || $scope.grid.options.enableRowHeaderSelection ) &&
    +                $scope.registered ){
    +                deregisterRowSelectionEvents();
    +              }
    +            }, [uiGridConstants.dataChange.OPTIONS] );
    +
    +            $elm.on( '$destroy', dataChangeDereg);
    +          }
    +        };
    +      }]);
    +
    +  module.directive('uiGridGridFooter', ['$compile', 'uiGridConstants', 'gridUtil', function ($compile, uiGridConstants, gridUtil) {
    +    return {
    +      restrict: 'EA',
    +      replace: true,
    +      priority: -1000,
    +      require: '^uiGrid',
    +      scope: true,
    +      compile: function ($elm, $attrs) {
    +        return {
    +          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
    +
    +            if (!uiGridCtrl.grid.options.showGridFooter) {
    +              return;
    +            }
    +
    +
    +            gridUtil.getTemplate('ui-grid/gridFooterSelectedItems')
    +              .then(function (contents) {
    +                var template = angular.element(contents);
    +
    +                var newElm = $compile(template)($scope);
    +
    +                angular.element($elm[0].getElementsByClassName('ui-grid-grid-footer')[0]).append(newElm);
    +              });
    +          },
    +
    +          post: function ($scope, $elm, $attrs, controllers) {
    +
    +          }
    +        };
    +      }
    +    };
    +  }]);
    +
    +})();
    +
    +angular.module('ui.grid').run(['$templateCache', function($templateCache) {
    +  'use strict';
    +
    +  $templateCache.put('ui-grid/ui-grid-footer',
    +    "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\"><div class=\"ui-grid-footer ui-grid-footer-viewport\"><div class=\"ui-grid-footer-canvas\"><div class=\"ui-grid-footer-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\"><div class=\"ui-grid-footer-cell-row\"><div ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-footer-cell col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\"></div></div></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-grid-footer',
    +    "<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{'search.totalItems' | t}} {{grid.rows.length}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-group-panel',
    +    "<div class=\"ui-grid-group-panel\"><div ui-t=\"groupPanel.description\" class=\"description\" ng-show=\"groupings.length == 0\"></div><ul ng-show=\"groupings.length > 0\" class=\"ngGroupList\"><li class=\"ngGroupItem\" ng-repeat=\"group in configGroups\"><span class=\"ngGroupElement\"><span class=\"ngGroupName\">{{group.displayName}} <span ng-click=\"removeGroup($index)\" class=\"ngRemoveGroup\">x</span></span> <span ng-hide=\"$last\" class=\"ngGroupArrow\"></span></span></li></ul></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-header',
    +    "<div class=\"ui-grid-header\"><div class=\"ui-grid-top-panel\"><div class=\"ui-grid-header-viewport\"><div class=\"ui-grid-header-canvas\"><div class=\"ui-grid-header-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\"><div class=\"ui-grid-header-cell-row\"><div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.colDef.name\" ui-grid-header-cell col=\"col\" render-index=\"$index\"></div></div></div></div></div><div ui-grid-menu></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-menu-button',
    +    "<div class=\"ui-grid-menu-button\" ng-click=\"toggleMenu()\"><div class=\"ui-grid-icon-container\"><i class=\"ui-grid-icon-menu\">&nbsp;</i></div><div ui-grid-menu menu-items=\"menuItems\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-no-header',
    +    "<div class=\"ui-grid-top-panel\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid-row',
    +    "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/ui-grid',
    +    "<div ui-i18n=\"en\" class=\"ui-grid\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n" +
    +    "      /* Styles for the grid */\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n" +
    +    "      height: {{ grid.options.rowHeight }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n" +
    +    "      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && '1') || '0' }}px;\n" +
    +    "    }\n" +
    +    "\n" +
    +    "    {{ grid.verticalScrollbarStyles }}\n" +
    +    "    {{ grid.horizontalScrollbarStyles }}\n" +
    +    "\n" +
    +    "    /*\n" +
    +    "    .ui-grid[dir=rtl] .ui-grid-viewport {\n" +
    +    "      padding-left: {{ grid.verticalScrollbarWidth }}px;\n" +
    +    "    }\n" +
    +    "    */\n" +
    +    "\n" +
    +    "    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if=\"grid.options.enableGridMenu\"></div><div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\"></div><div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\" enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div><div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\"></div><div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\"></div><div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\"></div><div ng-transclude></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridCell',
    +    "<div class=\"ui-grid-cell-contents\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnFilter',
    +    "<li class=\"ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter\" ng-show=\"itemShown()\" ng-click=\"$event.stopPropagation();\"><div class=\"input-container\"><input class=\"column-filter-input\" type=\"text\" ng-model=\"item.model\" placeholder=\"{{ i18n.search.placeholder }}\"><div class=\"column-filter-cancel-icon-container\"><i class=\"ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon\">&nbsp;</i></div></div><div style=\"button-container\" ng-click=\"item.action($event)\"><div class=\"ui-grid-button\"><i class=\"ui-grid-icon-search\">&nbsp;</i></div></div></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridColumnMenu',
    +    "<div class=\"ui-grid-column-menu\"><div ui-grid-menu menu-items=\"menuItems\"><!-- <div class=\"ui-grid-column-menu\">\n" +
    +    "    <div class=\"inner\" ng-show=\"menuShown\">\n" +
    +    "      <ul>\n" +
    +    "        <div ng-show=\"grid.options.enableSorting\">\n" +
    +    "          <li ng-click=\"sortColumn($event, asc)\" ng-class=\"{ 'selected' : col.sort.direction == asc }\"><i class=\"ui-grid-icon-sort-alt-up\"></i> Sort Ascending</li>\n" +
    +    "          <li ng-click=\"sortColumn($event, desc)\" ng-class=\"{ 'selected' : col.sort.direction == desc }\"><i class=\"ui-grid-icon-sort-alt-down\"></i> Sort Descending</li>\n" +
    +    "          <li ng-show=\"col.sort.direction\" ng-click=\"unsortColumn()\"><i class=\"ui-grid-icon-cancel\"></i> Remove Sort</li>\n" +
    +    "        </div>\n" +
    +    "      </ul>\n" +
    +    "    </div>\n" +
    +    "  </div> --></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridFooterCell',
    +    "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridHeaderCell',
    +    "<div ng-class=\"{ 'sortable': sortable }\"><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\">&nbsp;</i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\"><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\">&nbsp;</i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenu',
    +    "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><ul class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" ui-grid-menu-item action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\"></li></ul></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridMenuItem',
    +    "<li class=\"ui-grid-menu-item\" ng-click=\"itemAction($event, title)\" ng-show=\"itemShown()\" ng-class=\"{ 'ui-grid-menu-item-active' : active() }\"><i ng-class=\"icon\"></i> {{ name }}</li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridRenderContainer',
    +    "<div class=\"ui-grid-render-container\"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/uiGridViewport',
    +    "<div class=\"ui-grid-viewport\" ng-style=\"colContainer.getViewPortStyle()\"><div class=\"ui-grid-canvas\"><div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\" class=\"ui-grid-row\" ng-style=\"Viewport.rowStyle(rowRenderIndex)\"><div ui-grid-row=\"row\" row-render-index=\"rowRenderIndex\"></div></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/cellEditor',
    +    "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/dropdownEditor',
    +    "<div><form name=\"inputForm\"><select ng-class=\"'colt' + col.uid\" ui-grid-edit-dropdown ng-model=\"MODEL_COL_FIELD\" ng-options=\"field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray\"></select></form></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRow',
    +    "<div ui-grid-expandable-row ng-if=\"expandableRow.shouldRenderExpand()\" class=\"expandableRow\" style=\"float:left; margin-top: 1px; margin-bottom: 1px\" ng-style=\"{width: (grid.renderContainers.body.getCanvasWidth()) + 'px'\n" +
    +    "     , height: grid.options.expandableRowHeight + 'px'}\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !row.isExpanded, 'ui-grid-icon-minus-squared' : row.isExpanded }\" ng-click=\"grid.api.expandable.toggleRowExpansion(row.entity)\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableScrollFiller',
    +    "<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n" +
    +    "              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n" +
    +    "            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/expandableTopRowHeader',
    +    "<div class=\"ui-grid-row-header-cell ui-grid-expandable-buttons-cell\"><div class=\"ui-grid-cell-contents\"><i ng-class=\"{ 'ui-grid-icon-plus-squared' : !grid.expandable.expandedAll, 'ui-grid-icon-minus-squared' : grid.expandable.expandedAll }\" ng-click=\"grid.api.expandable.toggleAllRows()\"></i></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/csvLink',
    +    "<span class=\"ui-grid-exporter-csv-link-span\"><a href=\"data:text/csv;charset=UTF-8,CSV_CONTENT\" download=\"FILE_NAME\">LINK_LABEL</a></span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItem',
    +    "<li class=\"ui-grid-menu-item\"><form><input class=\"ui-grid-importer-file-chooser\" type=\"file\" id=\"files\" name=\"files[]\"></form></li>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/importerMenuItemContainer',
    +    "<div ui-grid-importer-menu-item></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/pagination',
    +    "<div class=\"ui-grid-pager-panel\" ui-grid-pager ng-show=\"grid.options.enablePaginationControls\"><div class=\"ui-grid-pager-container\"><div class=\"ui-grid-pager-control\"><button type=\"button\" ng-click=\"paginationApi.seek(1)\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle\"><div class=\"first-bar\"></div></div></button> <button type=\"button\" ng-click=\"paginationApi.previousPage()\" ng-disabled=\"cantPageBackward()\"><div class=\"first-triangle prev-triangle\"></div></button> <input type=\"number\" ng-model=\"grid.options.paginationCurrentPage\" min=\"1\" max=\"{{ paginationApi.getTotalPages() }}\" required> <span class=\"ui-grid-pager-max-pages-number\" ng-show=\"paginationApi.getTotalPages() > 0\">/ {{ paginationApi.getTotalPages() }}</span> <button type=\"button\" ng-click=\"paginationApi.nextPage()\" ng-disabled=\"cantPageForward()\"><div class=\"last-triangle next-triangle\"></div></button> <button type=\"button\" ng-click=\"paginationApi.seek(paginationApi.getTotalPages())\" ng-disabled=\"cantPageToLast()\"><div class=\"last-triangle\"><div class=\"last-bar\"></div></div></button></div><div class=\"ui-grid-pager-row-count-picker\"><select ng-model=\"grid.options.paginationPageSize\" ng-options=\"o as o for o in grid.options.paginationPageSizes\"></select><span class=\"ui-grid-pager-row-count-label\">&nbsp;{{sizesLabel}}</span></div></div><div class=\"ui-grid-pager-count-container\"><div class=\"ui-grid-pager-count\"><span ng-show=\"grid.options.totalItems > 0\">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/columnResizer',
    +    "<div ui-grid-column-resizer ng-if=\"grid.options.enableColumnResizing\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\"></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/gridFooterSelectedItems',
    +    "<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"search.selectedItems\" | t}} {{grid.selection.selectedCount}})</span>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionHeaderCell',
    +    "<div><!-- <div class=\"ui-grid-vertical-bar\">&nbsp;</div> --><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><ui-grid-selection-select-all-buttons ng-if=\"grid.options.enableSelectAll\"></ui-grid-selection-select-all-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeader',
    +    "<div class=\"ui-grid-disable-selection\"><div class=\"ui-grid-cell-contents\"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionRowHeaderButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ng-click=\"selectButtonClick(row, $event)\">&nbsp;</div>"
    +  );
    +
    +
    +  $templateCache.put('ui-grid/selectionSelectAllButtons',
    +    "<div class=\"ui-grid-selection-row-header-buttons ui-grid-icon-ok\" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-click=\"headerButtonClick($event)\"></div>"
    +  );
    +
    +}]);
    diff --git a/release/ui-grid-unstable.min.css b/release/ui-grid-unstable.min.css
    new file mode 100644
    index 000000000..a18c7eaa4
    --- /dev/null
    +++ b/release/ui-grid-unstable.min.css
    @@ -0,0 +1,4 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20-5f155b2 - 2015-03-03
    + * Copyright (c) 2015 ; License: MIT 
    + */.ui-grid{border:1px solid #d4d4d4;box-sizing:content-box;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-o-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.ui-grid-vertical-bar{position:absolute;right:0;width:0}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#d4d4d4}.ui-grid-clearfix:before,.ui-grid-clearfix:after{content:"";display:table}.ui-grid-clearfix:after{clear:both}.ui-grid-invisible{visibility:hidden}.ui-grid-top-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-header{border-bottom:1px solid #d4d4d4;box-sizing:content-box}.ui-grid-top-panel{position:relative;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-header-viewport{overflow:hidden}.ui-grid-header-canvas:before,.ui-grid-header-canvas:after{content:"";display:table;line-height:0}.ui-grid-header-canvas:after{clear:both}.ui-grid-header-cell-wrapper{position:relative;display:table;box-sizing:border-box;height:100%}.ui-grid-header-cell-row{display:table-row}.ui-grid-header-cell{position:relative;box-sizing:border-box;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;display:table-cell;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0}.ui-grid-header-cell:last-child{border-right:0}.ui-grid-header-cell .sortable{cursor:pointer}.ui-grid-header .ui-grid-vertical-bar{top:0;bottom:0}.ui-grid-column-menu-button{position:absolute;right:1px;top:0}.ui-grid-column-menu-button .ui-grid-icon-angle-down{vertical-align:sub}.ui-grid-column-menu-button-last-col{margin-right:25px}.ui-grid-column-menu{position:absolute}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-column-menu .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transition:all .05s linear;-moz-transition:all .05s linear;-o-transition:all .05s linear;transition:all .05s linear;display:block !important}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add.ng-hide-add-active,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-o-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%)}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-add,.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid.ng-hide-remove.ng-hide-remove-active{-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.ui-grid-filter-container{padding:4px 10px;position:relative}.ui-grid-filter-container .ui-grid-filter-button{position:absolute;top:0;bottom:0;right:0}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{position:absolute;top:50%;line-height:32px;margin-top:-16px;right:10px;opacity:.66}.ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]:hover{opacity:1}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-render-container{position:inherit;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-render-container:focus{outline:none}.ui-grid-viewport{min-height:20px;position:relative;overflow-y:scroll;-webkit-overflow-scrolling:touch}.ui-grid-viewport :focus{outline:none}.ui-grid-canvas{position:relative;padding-top:1px}.ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.ui-grid-row:last-child .ui-grid-cell{border-bottom-color:#d4d4d4;border-bottom-style:solid}.ui-grid-no-row-overlay{position:absolute;top:0;bottom:0;left:0;right:0;margin:10%;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #d4d4d4;font-size:2em;text-align:center}.ui-grid-no-row-overlay>*{position:absolute;display:table;margin:auto 0;width:100%;top:0;bottom:0;left:0;right:0;opacity:.66}.ui-grid-cell{overflow:hidden;float:left;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box}.ui-grid-cell:last-child{border-right:0}.ui-grid-cell-contents{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;height:100%}.ui-grid-cell-contents-hidden{visibility:hidden;width:0;height:0;display:none}.ui-grid-row-header-cell{background-color:#f0f0ee !important;border-bottom:solid 1px #d4d4d4}.ui-grid-footer-panel-background{background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.ui-grid-footer-panel{position:relative;border-bottom:1px solid #d4d4d4;border-top:1px solid #d4d4d4;overflow:hidden;font-weight:bold;background:#f3f3f3;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(1, #fff));background:-ms-linear-gradient(bottom, #eee, #fff);background:-moz-linear-gradient(center bottom, #eee 0, #fff 100%);background:-o-linear-gradient(#fff, #eee);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);-webkit-border-top-right-radius:-1px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:-1px;-moz-border-radius-topright:-1px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:-1px;border-top-right-radius:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:-1px;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}.ui-grid-grid-footer{float:left;width:100%}.ui-grid-footer-viewport{overflow:hidden}.ui-grid-footer-canvas{position:relative}.ui-grid-footer-canvas:before,.ui-grid-footer-canvas:after{content:"";display:table;line-height:0}.ui-grid-footer-canvas:after{clear:both}.ui-grid-footer-cell-wrapper{position:relative;display:table;box-sizing:border-box;height:100%}.ui-grid-footer-cell-row{display:table-row}.ui-grid-footer-cell{overflow:hidden;background-color:inherit;border-right:1px solid;border-color:#d4d4d4;box-sizing:border-box;display:table-cell}.ui-grid-footer-cell:last-child{border-right:0}input[type="text"].ui-grid-filter-input{padding:0;margin:0;border:0;width:100%;border:1px solid #d4d4d4;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;-moz-background-clip:padding-box;-webkit-background-clip:padding-box;background-clip:padding-box}input[type="text"].ui-grid-filter-input:hover{border:1px solid #d4d4d4}.ui-grid-menu-button{z-index:2;position:absolute;right:0;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid-menu-button .ui-grid-icon-container{margin-top:3px}.ui-grid-menu-button .ui-grid-menu{right:0}.ui-grid-menu-button .ui-grid-menu .ui-grid-menu-mid{overflow-y:scroll;max-height:300px;border:1px solid #d4d4d4}.ui-grid-menu{z-index:2;position:absolute;overflow:hidden;padding:0 10px 20px 10px;cursor:pointer;box-sizing:content-box}.ui-grid-menu .ui-grid-menu-inner{background:#f3f3f3;border:1px solid #d4d4d4;position:relative;white-space:nowrap;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2);box-shadow:0 10px 20px rgba(0, 0, 0, 0.2), inset 0 12px 12px -14px rgba(0, 0, 0, 0.2)}.ui-grid-menu .ui-grid-menu-inner ul{margin:0;padding:0;list-style-type:none}.ui-grid-menu .ui-grid-menu-inner ul li{padding:8px;cursor:pointer}.ui-grid-menu .ui-grid-menu-inner ul li:hover{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.ui-grid-menu .ui-grid-menu-inner ul li.ui-grid-menu-item-active{-webkit-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);-moz-box-shadow:inset 0 0 14px rgba(0,0,0,0.2);box-shadow:inset 0 0 14px rgba(0,0,0,0.2);background-color:#cecece}.ui-grid-menu .ui-grid-menu-inner ul li:not(:last-child){border-bottom:1px solid #d4d4d4}.ui-grid-sortarrow{right:5px;position:absolute;width:20px;top:0;bottom:0;background-position:center}.ui-grid-sortarrow.down{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}@font-face{font-family:'ui-grid';src:url('ui-grid.eot');src:url('ui-grid.eot#iefix') format('embedded-opentype'),url('ui-grid.woff') format('woff'),url('ui-grid.ttf?') format('truetype'),url('ui-grid.svg?#ui-grid') format('svg');font-weight:normal;font-style:normal}[class^="ui-grid-icon"]:before,[class*=" ui-grid-icon"]:before{font-family:"ui-grid";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.ui-grid-icon-blank::before{width:1em;content:' '}.ui-grid[dir=rtl] .ui-grid-header-cell,.ui-grid[dir=rtl] .ui-grid-footer-cell,.ui-grid[dir=rtl] .ui-grid-cell{float:right !important}.ui-grid[dir=rtl] .ui-grid-column-menu-button{position:absolute;left:1px;top:0;right:inherit}.ui-grid[dir=rtl] .ui-grid-cell:first-child,.ui-grid[dir=rtl] .ui-grid-header-cell:first-child,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child{border-right:0}.ui-grid[dir=rtl] .ui-grid-cell:last-child,.ui-grid[dir=rtl] .ui-grid-header-cell:last-child{border-right:1px solid #d4d4d4;border-left:0}.ui-grid[dir=rtl] .ui-grid-header-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-footer-cell:first-child .ui-grid-vertical-bar,.ui-grid[dir=rtl] .ui-grid-cell:first-child .ui-grid-vertical-bar{width:0}.ui-grid[dir=rtl] .ui-grid-menu-button{z-index:2;position:absolute;left:0;right:auto;background:#f3f3f3;border:1px solid #d4d4d4;cursor:pointer;min-height:27px;font-weight:normal}.ui-grid[dir=rtl] .ui-grid-menu-button .ui-grid-menu{left:0;right:auto}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button{right:initial;left:0}.ui-grid[dir=rtl] .ui-grid-filter-container .ui-grid-filter-button [class^="ui-grid-icon"]{right:initial;left:10px}.ui-grid-animate-spin{-moz-animation:ui-grid-spin 2s infinite linear;-o-animation:ui-grid-spin 2s infinite linear;-webkit-animation:ui-grid-spin 2s infinite linear;animation:ui-grid-spin 2s infinite linear;display:inline-block}@-moz-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-grid-spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-grid-cell-focus{outline:0;background-color:#b3c4c7}div.ui-grid-cell input{border-radius:inherit;padding:0;width:100%;color:inherit;height:auto;font:inherit;outline:none}div.ui-grid-cell input:focus{color:inherit;outline:none}div.ui-grid-cell input[type="checkbox"]{margin:9px 0 0 6px;width:auto}div.ui-grid-cell input.ng-invalid{border:1px solid #fc8f8f}div.ui-grid-cell input.ng-valid{border:1px solid #d4d4d4}.expandableRow .ui-grid-row:nth-child(odd) .ui-grid-cell{background-color:#fdfdfd}.expandableRow .ui-grid-row:nth-child(even) .ui-grid-cell{background-color:#f3f3f3}.movingColumn{position:fixed;border:1px solid #d4d4d4;box-shadow:inset 0 0 14px rgba(0,0,0,0.2)}.movingColumn .ui-grid-icon-angle-down{display:none}.ui-grid-pager-panel{position:absolute;left:0;bottom:0;width:100%;padding-top:3px;padding-bottom:3px}.ui-grid-pager-container{float:left}.ui-grid-pager-control{margin-right:10px;margin-left:10px;min-width:135px;float:left}.ui-grid-pager-control button{height:25px;min-width:26px}.ui-grid-pager-control input{height:26px;width:50px;vertical-align:top}.ui-grid-pager-control .first-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ui-grid-pager-control .first-triangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ui-grid-pager-control .next-triangle{margin-left:1px}.ui-grid-pager-control .prev-triangle{margin-left:0}.ui-grid-pager-control .last-triangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ui-grid-pager-control .last-bar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ui-grid-pager-row-count-picker{float:left}.ui-grid-pager-row-count-picker select{height:26px;width:60px}.ui-grid-pager-row-count-picker .ui-grid-pager-row-count-label{margin-top:3px}.ui-grid-pager-count-container{float:right;margin-top:4px;min-width:50px}.ui-grid-pager-count-container .ui-grid-pager-count{margin-right:10px;margin-left:10px;float:right}.ui-grid-pinned-container{float:left}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child{box-sizing:border-box;border-right:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child .ui-grid-vertical-bar{right:-1px;width:1px;background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:first-child{box-sizing:border-box;border-left:1px solid;border-width:1px;border-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar,.ui-grid-pinned-container .ui-grid-cell:not(:first-child) .ui-grid-vertical-bar{width:1px}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-header-cell:not(:first-child) .ui-grid-vertical-bar{background-color:#d4d4d4}.ui-grid-pinned-container.ui-grid-pinned-container-right .ui-grid-cell:not(:last-child) .ui-grid-vertical-bar{background-color:#aeaeae}.ui-grid-pinned-container.ui-grid-pinned-container-first .ui-grid-header-cell:first-child .ui-grid-vertical-bar{left:-1px;width:1px;background-color:#aeaeae}.ui-grid-render-container-body{float:left}.ui-grid-column-resizer{top:0;bottom:0;width:5px;position:absolute;cursor:col-resize}.ui-grid-column-resizer.left{left:0}.ui-grid-column-resizer.right{right:0}.ui-grid-header-cell:last-child .ui-grid-column-resizer.right{border-right:1px solid #d4d4d4}.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.right{border-right:0}.ui-grid[dir=rtl] .ui-grid-header-cell:last-child .ui-grid-column-resizer.left{border-left:1px solid #d4d4d4}.ui-grid.column-resizing{cursor:col-resize}.ui-grid.column-resizing .ui-grid-resize-overlay{position:absolute;top:0;height:100%;width:1px;background-color:#aeaeae}.ui-grid-row-saving .ui-grid-cell{color:#848484 !important}.ui-grid-row-dirty .ui-grid-cell{color:#610b38}.ui-grid-row-error .ui-grid-cell{color:#f00 !important}.ui-grid-row-selected>[ui-grid-row]>.ui-grid-cell{background-color:#c9dde1 !important}.ui-grid-disable-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.ui-grid-selection-row-header-buttons{cursor:pointer;opacity:.1}.ui-grid-selection-row-header-buttons.ui-grid-row-selected{opacity:1}.ui-grid-selection-row-header-buttons.ui-grid-all-selected{opacity:1}.ui-grid-icon-plus-squared:before{content:'\c350'}.ui-grid-icon-minus-squared:before{content:'\c351'}.ui-grid-icon-search:before{content:'\c352'}.ui-grid-icon-cancel:before{content:'\c353'}.ui-grid-icon-info-circled:before{content:'\c354'}.ui-grid-icon-lock:before{content:'\c355'}.ui-grid-icon-lock-open:before{content:'\c356'}.ui-grid-icon-pencil:before{content:'\c357'}.ui-grid-icon-down-dir:before{content:'\c358'}.ui-grid-icon-up-dir:before{content:'\c359'}.ui-grid-icon-left-dir:before{content:'\c35a'}.ui-grid-icon-right-dir:before{content:'\c35b'}.ui-grid-icon-left-open:before{content:'\c35c'}.ui-grid-icon-right-open:before{content:'\c35d'}.ui-grid-icon-angle-down:before{content:'\c35e'}.ui-grid-icon-filter:before{content:'\c35f'}.ui-grid-icon-sort-alt-up:before{content:'\c360'}.ui-grid-icon-sort-alt-down:before{content:'\c361'}.ui-grid-icon-ok:before{content:'\c362'}.ui-grid-icon-menu:before{content:'\c363'}.ui-grid-icon-spin5:before{content:'\ea61'}
    \ No newline at end of file
    diff --git a/release/ui-grid-unstable.min.js b/release/ui-grid-unstable.min.js
    new file mode 100644
    index 000000000..2c039f5d0
    --- /dev/null
    +++ b/release/ui-grid-unstable.min.js
    @@ -0,0 +1,12 @@
    +/*!
    + * ui-grid - v3.0.0-rc.20-5f155b2 - 2015-03-03
    + * Copyright (c) 2015 ; License: MIT 
    + */
    +
    +!function(){"use strict";angular.module("ui.grid.i18n",[]),angular.module("ui.grid",["ui.grid.i18n"])}(),function(){"use strict";angular.module("ui.grid").constant("uiGridConstants",{LOG_DEBUG_MESSAGES:!0,LOG_WARN_MESSAGES:!0,LOG_ERROR_MESSAGES:!0,CUSTOM_FILTERS:/CUSTOM_FILTERS/g,COL_FIELD:/COL_FIELD/g,MODEL_COL_FIELD:/MODEL_COL_FIELD/g,DISPLAY_CELL_TEMPLATE:/DISPLAY_CELL_TEMPLATE/g,TEMPLATE_REGEXP:/<.+>/,FUNC_REGEXP:/(\([^)]*\))?$/,DOT_REGEXP:/\./g,APOS_REGEXP:/'/g,BRACKET_REGEXP:/^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/,COL_CLASS_PREFIX:"ui-grid-col",events:{GRID_SCROLL:"uiGridScroll",COLUMN_MENU_SHOWN:"uiGridColMenuShown",ITEM_DRAGGING:"uiGridItemDragStart",COLUMN_HEADER_CLICK:"uiGridColumnHeaderClick"},keymap:{TAB:9,STRG:17,CTRL:17,CTRLRIGHT:18,CTRLR:18,SHIFT:16,RETURN:13,ENTER:13,BACKSPACE:8,BCKSP:8,ALT:18,ALTR:17,ALTRIGHT:17,SPACE:32,WIN:91,MAC:91,FN:null,PG_UP:33,PG_DOWN:34,UP:38,DOWN:40,LEFT:37,RIGHT:39,ESC:27,DEL:46,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123},ASC:"asc",DESC:"desc",filter:{STARTS_WITH:2,ENDS_WITH:4,EXACT:8,CONTAINS:16,GREATER_THAN:32,GREATER_THAN_OR_EQUAL:64,LESS_THAN:128,LESS_THAN_OR_EQUAL:256,NOT_EQUAL:512},aggregationTypes:{sum:2,count:4,avg:8,min:16,max:32},CURRENCY_SYMBOLS:["ƒ","$","£","$","¤","¥","៛","₩","₱","฿","₫"],scrollDirection:{UP:"up",DOWN:"down",LEFT:"left",RIGHT:"right",NONE:"none"},dataChange:{ALL:"all",EDIT:"edit",ROW:"row",COLUMN:"column",OPTIONS:"options"},scrollbars:{NEVER:0,ALWAYS:1}})}(),angular.module("ui.grid").directive("uiGridCell",["$compile","$parse","gridUtil","uiGridConstants",function(a,b,c,d){var e={priority:0,scope:!1,require:"?^uiGrid",compile:function(){return{pre:function(b,e,f,g){function h(){var a=b.col.compiledElementFn;a(b,function(a){e.append(a)})}if(g&&b.col.compiledElementFn)h();else if(g&&!b.col.compiledElementFn)b.col.getCompiledElementFn().then(function(a){a(b,function(a){e.append(a)})});else{var i=b.col.cellTemplate.replace(d.MODEL_COL_FIELD,"row.entity."+c.preEval(b.col.field)).replace(d.COL_FIELD,"grid.getCellValue(row, col)"),j=a(i)(b);e.append(j)}},post:function(a,b){var c=a.col.getColClass(!1);b.addClass(c);var e,f=function(){var c=b;e&&(c.removeClass(e),e=null),e=angular.isFunction(a.col.cellClass)?a.col.cellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.cellClass,c.addClass(e)};a.col.cellClass&&f();var g=a.grid.registerDataChangeCallback(f,[d.dataChange.COLUMN,d.dataChange.EDIT]),h=function(d,g){if(d!==g){(e||a.col.cellClass)&&f();var h=a.col.getColClass(!1);h!==c&&(b.removeClass(c),b.addClass(h),c=h)}},i=a.$watch("col",h),j=a.$watch("row",h),k=function(){g(),i(),j()};a.$on("$destroy",k),b.on("$destroy",k)}}}};return e}]),function(){angular.module("ui.grid").service("uiGridColumnMenuService",["i18nService","uiGridConstants","gridUtil",function(a,b,c){var d={initialize:function(a,b){a.grid=b.grid,b.columnMenuScope=a,a.menuShown=!1},setColMenuItemWatch:function(a){var b=a.$watch("col.menuItems",function(b){"undefined"!=typeof b&&b&&angular.isArray(b)?(b.forEach(function(b){"undefined"!=typeof b.context&&b.context||(b.context={}),b.context.col=a.col}),a.menuItems=a.defaultMenuItems.concat(b)):a.menuItems=a.defaultMenuItems});a.$on("$destroy",b)},sortable:function(a){return a.grid.options.enableSorting&&"undefined"!=typeof a.col&&a.col&&a.col.enableSorting?!0:!1},isActiveSort:function(a,b){return"undefined"!=typeof a.col&&"undefined"!=typeof a.col.sort&&"undefined"!=typeof a.col.sort.direction&&a.col.sort.direction===b},suppressRemoveSort:function(a){return a.col&&a.col.colDef&&a.col.colDef.suppressRemoveSort?!0:!1},hideable:function(a){return"undefined"!=typeof a.col&&a.col&&a.col.colDef&&a.col.colDef.enableHiding===!1?!1:!0},getDefaultMenuItems:function(c){return[{title:a.getSafeText("sort.ascending"),icon:"ui-grid-icon-sort-alt-up",action:function(a){a.stopPropagation(),c.sortColumn(a,b.ASC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.ASC)}},{title:a.getSafeText("sort.descending"),icon:"ui-grid-icon-sort-alt-down",action:function(a){a.stopPropagation(),c.sortColumn(a,b.DESC)},shown:function(){return d.sortable(c)},active:function(){return d.isActiveSort(c,b.DESC)}},{title:a.getSafeText("sort.remove"),icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),c.unsortColumn()},shown:function(){return d.sortable(c)&&"undefined"!=typeof c.col&&"undefined"!=typeof c.col.sort&&"undefined"!=typeof c.col.sort.direction&&null!==c.col.sort.direction&&!d.suppressRemoveSort(c)}},{title:a.getSafeText("column.hide"),icon:"ui-grid-icon-cancel",shown:function(){return d.hideable(c)},action:function(a){a.stopPropagation(),c.hideColumn()}}]},getColumnElementPosition:function(a,b,d){var e={};return e.left=d[0].offsetLeft,e.top=d[0].offsetTop,e.parentLeft=d[0].offsetParent.offsetLeft,e.offset=0,b.grid.options.offsetLeft&&(e.offset=b.grid.options.offsetLeft),e.height=c.elementHeight(d,!0),e.width=c.elementWidth(d,!0),e},repositionMenu:function(a,b,d,e,f){var g=e[0].querySelectorAll(".ui-grid-menu"),h=b.renderContainer?b.renderContainer:"body",i=(b.grid.renderContainers[h],c.closestElm(f,".ui-grid-render-container")),j=i.getBoundingClientRect().left-a.grid.element[0].getBoundingClientRect().left,k=i.querySelectorAll(".ui-grid-viewport")[0].scrollLeft,l=b.lastMenuWidth?b.lastMenuWidth:a.lastMenuWidth?a.lastMenuWidth:170,m=b.lastMenuPaddingRight?b.lastMenuPaddingRight:a.lastMenuPaddingRight?a.lastMenuPaddingRight:10;if(0!==g.length){var n=g[0].querySelectorAll(".ui-grid-menu-mid");0===n.length||angular.element(n).hasClass("ng-hide")||(l=c.elementWidth(g,!0),a.lastMenuWidth=l,b.lastMenuWidth=l,m=parseInt(c.getStyles(angular.element(g)[0]).paddingRight,10),a.lastMenuPaddingRight=m,b.lastMenuPaddingRight=m)}var o=d.left+j-k+d.parentLeft+d.width-l+m;o<d.offset&&(o=d.offset),e.css("left",o+"px"),e.css("top",d.top+d.height+"px")}};return d}]).directive("uiGridColumnMenu",["$timeout","gridUtil","uiGridConstants","uiGridColumnMenuService",function(a,b,c,d){var e={priority:0,scope:!0,require:"?^uiGrid",templateUrl:"ui-grid/uiGridColumnMenu",replace:!0,link:function(b,e,f,g){var h=this;d.initialize(b,g),b.defaultMenuItems=d.getDefaultMenuItems(b),b.menuItems=b.defaultMenuItems,d.setColMenuItemWatch(b),b.showMenu=function(a,c,f){b.col=a;var g=d.getColumnElementPosition(b,a,c);b.menuShown?(b.colElement=c,b.colElementPosition=g,b.hideThenShow=!0,b.$broadcast("hide-menu",{originalEvent:f})):(h.shown=b.menuShown=!0,d.repositionMenu(b,a,g,e,c),b.colElement=c,b.colElementPosition=g,b.$broadcast("show-menu",{originalEvent:f}))},b.hideMenu=function(a){b.menuShown=!1,a||b.$broadcast("hide-menu")},b.$on("menu-hidden",function(){b.hideThenShow?(delete b.hideThenShow,d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),b.$broadcast("show-menu"),b.menuShown=!0):b.hideMenu(!0)}),b.$on("menu-shown",function(){a(function(){d.repositionMenu(b,b.col,b.colElementPosition,e,b.colElement),delete b.colElementPosition,delete b.columnElement},200)}),b.sortColumn=function(a,c){a.stopPropagation(),b.grid.sortColumn(b.col,c,!0).then(function(){b.grid.refresh(),b.hideMenu()})},b.unsortColumn=function(){b.col.unsort(),b.grid.refresh(),b.hideMenu()},b.hideColumn=function(){b.col.colDef.visible=!1,b.grid.refresh(),b.hideMenu(),b.grid.api.core.notifyDataChange(c.dataChange.COLUMN),b.grid.api.core.raise.columnVisibilityChanged(b.col)}},controller:["$scope",function(a){var b=this;a.$watch("menuItems",function(a){b.menuItems=a})}]};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooterCell",["$timeout","gridUtil","uiGridConstants","$compile",function(a,b,c,d){var e={priority:0,scope:{col:"=",row:"=",renderIndex:"="},replace:!0,require:"^uiGrid",compile:function(){return{pre:function(a,b){var c=d(a.col.footerCellTemplate)(a);b.append(c)},post:function(a,b,d,e){a.grid=e.grid,b.addClass(a.col.getColClass(!1));var f,g=function(){var c=b;f&&(c.removeClass(f),f=null),f=angular.isFunction(a.col.footerCellClass)?a.col.footerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.footerCellClass,c.addClass(f)};a.col.footerCellClass&&g();var h=a.grid.registerDataChangeCallback(g,[c.dataChange.COLUMN]);a.$on("$destroy",h)}}}};return e}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-footer";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,f,g){var h=g[0],i=g[1];a.grid=h.grid,a.colContainer=i.colContainer,i.footer=c;var j=a.grid.options.footerTemplate?a.grid.options.footerTemplate:e;d.getTemplate(j).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.append(f),i){var g=c[0].getElementsByClassName("ui-grid-footer-viewport")[0];g&&(i.footerViewport=g)}})},post:function(a,b,c,e){{var f=e[0],g=e[1];f.grid}d.disableAnimations(b),g.footer=b;var h=b[0].getElementsByClassName("ui-grid-footer-viewport")[0];h&&(g.footerViewport=h)}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGridFooter",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-grid-footer";return{restrict:"EA",replace:!0,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(a,c,f,g){a.grid=g.grid;var h=a.grid.options.gridFooterTemplate?a.grid.options.gridFooterTemplate:e;d.getTemplate(h).then(function(d){var e=angular.element(d),f=b(e)(a);c.append(f)})},post:function(){}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridGroupPanel",["$compile","uiGridConstants","gridUtil",function(a,b,c){var d="ui-grid/ui-grid-group-panel";return{restrict:"EA",replace:!0,require:"?^uiGrid",scope:!1,compile:function(){return{pre:function(b,e){var f=b.grid.options.groupPanelTemplate||d;c.getTemplate(f).then(function(c){var d=angular.element(c),f=a(d)(b);e.append(f)})},post:function(a,b){b.bind("$destroy",function(){})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeaderCell",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f){var g=500,h={priority:0,scope:{col:"=",row:"=",renderIndex:"="},require:["?^uiGrid","^uiGridRenderContainer"],replace:!0,compile:function(){return{pre:function(b,c){var d=a(b.col.headerCellTemplate)(b);c.append(d)},post:function(a,c,d,h){function i(b){var c=!1;b.shiftKey&&(c=!0),j.grid.sortColumn(a.col,c).then(function(){j.columnMenuScope&&j.columnMenuScope.hideMenu(),j.grid.refresh()})}var j=h[0],k=h[1];a.grid=j.grid,a.renderContainer=j.grid.renderContainers[k.containerId];var l=a.col.getColClass(!1);c.addClass(l),a.menuShown=!1,a.asc=f.ASC,a.desc=f.DESC;var m,n=(angular.element(c[0].querySelectorAll(".ui-grid-header-cell-menu")),angular.element(c[0].querySelectorAll(".ui-grid-cell-contents"))),o=function(){var b=c;m&&(b.removeClass(m),m=null),m=angular.isFunction(a.col.headerCellClass)?a.col.headerCellClass(a.grid,a.row,a.col,a.rowRenderIndex,a.colRenderIndex):a.col.headerCellClass,b.addClass(m);var d=a.grid.renderContainers.right?a.grid.renderContainers.right:a.grid.renderContainers.body;a.isLastCol=a.col===d.visibleColumnCache[d.visibleColumnCache.length-1]};a.$watch("col",function(b,d){if(b!==d){var e=a.col.getColClass(!1);e!==l&&(c.removeClass(l),c.addClass(e),l=e)}}),o();var p=a.grid.registerDataChangeCallback(o,[f.dataChange.COLUMN]);if(a.$on("$destroy",p),a.sortable=j.grid.options.enableSorting&&a.col.enableSorting?!0:!1,a.filterable=j.grid.options.enableFiltering&&a.col.enableFiltering?!0:!1,a.colMenu=a.col.grid.options&&a.col.grid.options.enableColumnMenus!==!1&&a.col.colDef&&a.col.colDef.enableColumnMenu!==!1?!0:!1,a.sortable||a.colMenu){var q,r=0,s=e.isTouchEnabled()?"touchstart":"mousedown";n.on(s,function(d){d.stopPropagation(),"undefined"!=typeof d.originalEvent&&void 0!==d.originalEvent&&(d=d.originalEvent),d.button&&0!==d.button||(r=(new Date).getTime(),q=b(function(){},g),q.then(function(){a.colMenu&&j.columnMenuScope.showMenu(a.col,c,d)}),j.fireEvent(f.events.COLUMN_HEADER_CLICK,{event:d,columnName:a.col.colDef.name}))});var t=e.isTouchEnabled()?"touchend":"mouseup";n.on(t,function(){b.cancel(q)}),a.$on("$destroy",function(){n.off("mousedown touchstart")})}if(a.toggleMenu=function(b){b.stopPropagation(),j.columnMenuScope.menuShown&&j.columnMenuScope.col===a.col?j.columnMenuScope.hideMenu():j.columnMenuScope.showMenu(a.col,c)},a.sortable){var u=e.isTouchEnabled()?"touchend":"click";n.on(u,function(a){a.stopPropagation(),b.cancel(q);var c=(new Date).getTime(),d=c-r;d>g||i(a)}),a.$on("$destroy",function(){b.cancel(q)})}if(a.filterable){var v=[];angular.forEach(a.col.filters,function(b,c){v.push(a.$watch("col.filters["+c+"].term",function(a,b){a!==b&&(j.grid.api.core.raise.filterChanged(),j.grid.refresh(!0))}))}),a.$on("$destroy",function(){angular.forEach(v,function(a){a()})})}}}}};return h}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridHeader",["$templateCache","$compile","uiGridConstants","gridUtil","$timeout",function(a,b,c,d){var e="ui-grid/ui-grid-header",f="ui-grid/ui-grid-no-header";return{restrict:"EA",replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:!0,compile:function(){return{pre:function(a,c,g,h){function i(){k.header=k.colContainer.header=c;var a=c[0].getElementsByClassName("ui-grid-header-canvas");k.headerCanvas=a.length>0?k.colContainer.headerCanvas=a[0]:null}var j=h[0],k=h[1];a.grid=j.grid,a.colContainer=k.colContainer,i();var l;l=a.grid.options.showHeader?a.grid.options.headerTemplate?a.grid.options.headerTemplate:e:f,d.getTemplate(l).then(function(d){var e=angular.element(d),f=b(e)(a);if(c.replaceWith(f),c=f,i(),k){var g=c[0].getElementsByClassName("ui-grid-header-viewport")[0];g&&(k.headerViewport=g)}a.grid.queueRefresh()})},post:function(a,b,c,e){function f(){var a=h.colContainer.getViewportWidth()-i.scrollbarWidth,b=h.colContainer.visibleColumnCache,c=0,e=0,f=0,g=a,j=!1,k=function(b){return"manual"===b.widthType?+b.width:"percent"===b.widthType?parseInt(b.width.replace(/%/g,""),10)*a/100:"auto"===b.widthType?(0===f&&(f=parseInt(g/e,10)),b.width.length*f):void 0};b.forEach(function(a){a.widthType=null,isFinite(+a.width)?a.widthType="manual":d.endsWith(a.width,"%")?(a.widthType="percent",j=!0):angular.isString(a.width)&&-1!==a.width.indexOf("*")&&(a.widthType="auto",e+=a.width.length,j=!0)});var l=["manual","percent","auto"];if(b.filter(function(a){return a.visible&&a.widthType}).sort(function(a,b){return l.indexOf(a.widthType)-l.indexOf(b.widthType)}).forEach(function(a){var b=k(a);a.minWidth&&(b=Math.max(b,a.minWidth)),a.maxWidth&&(b=Math.min(b,a.maxWidth)),a.drawnWidth=Math.floor(b),c+=a.drawnWidth,g-=a.drawnWidth}),j&&g>0&&c>0&&a>c){var m=function(a){g>0&&("auto"===a.widthType||"percent"===a.widthType)&&(a.drawnWidth=a.drawnWidth+1,c+=1,g--)},n=0;do n=g,b.forEach(m);while(g>0&&g!==n)}c=Math.max(c,a);var o="";return b.forEach(function(a){o+=a.getColClassDefinition()}),b.length>0&&(b[b.length-1].headerWidth=b[b.length-1].drawnWidth-30),h.colContainer.canvasWidth=parseInt(c,10),o}var g=e[0],h=e[1],i=g.grid;d.disableAnimations(b),h.header=b;var j=b[0].getElementsByClassName("ui-grid-header-viewport")[0];j&&(h.headerViewport=j),g&&g.grid.registerStyleComputation({priority:5,func:f})}}}}}])}(),function(){angular.module("ui.grid").service("uiGridGridMenuService",["gridUtil","i18nService","uiGridConstants",function(a,b,c){var d={initialize:function(a,b){b.gridMenuScope=a,a.grid=b,a.registeredMenuItems=[],a.$on("$destroy",function(){a.grid&&a.grid.gridMenuScope&&(a.grid.gridMenuScope=null),a.grid&&(a.grid=null),a.registeredMenuItems&&(a.registeredMenuItems=null)}),a.registeredMenuItems=[],b.api.registerMethod("core","addToGridMenu",d.addToGridMenu),b.api.registerMethod("core","removeFromGridMenu",d.removeFromGridMenu)},addToGridMenu:function(b,c){angular.isArray(c)?b.gridMenuScope?(b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems?b.gridMenuScope.registeredMenuItems:[],b.gridMenuScope.registeredMenuItems=b.gridMenuScope.registeredMenuItems.concat(c)):a.logError("Asked to addToGridMenu, but gridMenuScope not present.  Timing issue?  Please log issue with ui-grid"):a.logError("addToGridMenu: menuItems must be an array, and is not, not adding any items")},removeFromGridMenu:function(b,c){var d=-1;b&&b.gridMenuScope&&b.gridMenuScope.registeredMenuItems.forEach(function(b,e){b.id===c&&(d>-1?a.logError("removeFromGridMenu: found multiple items with the same id, removing only the last"):d=e)}),d>-1&&b.gridMenuScope.registeredMenuItems.splice(d,1)},getMenuItems:function(b){var c=[];return b.grid.options.gridMenuCustomItems&&(angular.isArray(b.grid.options.gridMenuCustomItems)?c=c.concat(b.grid.options.gridMenuCustomItems):a.logError("gridOptions.gridMenuCustomItems must be an array, and is not")),c=c.concat(b.registeredMenuItems),b.grid.options.gridMenuShowHideColumns!==!1&&(c=c.concat(d.showHideColumns(b))),c},showHideColumns:function(a){var c=[];return a.grid.options.columnDefs&&0!==a.grid.options.columnDefs.length&&0!==a.grid.columns.length?(c.push({title:b.getSafeText("gridMenu.columns")}),a.grid.options.gridMenuTitleFilter=a.grid.options.gridMenuTitleFilter?a.grid.options.gridMenuTitleFilter:function(a){return a},a.grid.options.columnDefs.forEach(function(b){if(b.enableHiding!==!1){var e={icon:"ui-grid-icon-ok",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible},context:{gridCol:a.grid.getColumn(b.name||b.field)}};d.setMenuItemTitle(e,b,a.grid),c.push(e),e={icon:"ui-grid-icon-cancel",action:function(a){a.stopPropagation(),d.toggleColumnVisibility(this.context.gridCol)},shown:function(){return!(this.context.gridCol.colDef.visible===!0||void 0===this.context.gridCol.colDef.visible)},context:{gridCol:a.grid.getColumn(b.name||b.field)}},d.setMenuItemTitle(e,b,a.grid),c.push(e)}}),c):c},setMenuItemTitle:function(b,c,d){var e=d.options.gridMenuTitleFilter(c.displayName||c.name||c.field);"string"==typeof e?b.title=e:e.then?(b.title="",e.then(function(a){b.title=a},function(a){b.title=a})):(a.logError("Expected gridMenuTitleFilter to return a string or a promise, it has returned neither, bad config"),b.title="badconfig")},toggleColumnVisibility:function(a){a.colDef.visible=!(a.colDef.visible===!0||void 0===a.colDef.visible),a.grid.refresh(),a.grid.api.core.notifyDataChange(c.dataChange.COLUMN),a.grid.api.core.raise.columnVisibilityChanged(a)}};return d}]).directive("uiGridMenuButton",["gridUtil","uiGridConstants","uiGridGridMenuService",function(a,b,c){return{priority:0,scope:!0,require:["?^uiGrid"],templateUrl:"ui-grid/ui-grid-menu-button",replace:!0,link:function(a,b,d,e){var f=e[0];c.initialize(a,f.grid),a.shown=!1,a.toggleMenu=function(){a.shown?(a.$broadcast("hide-menu"),a.shown=!1):(a.menuItems=c.getMenuItems(a),a.$broadcast("show-menu"),a.shown=!0)},a.$on("menu-hidden",function(){a.shown=!1})}}}])}(),function(){angular.module("ui.grid").directive("uiGridMenu",["$compile","$timeout","$window","$document","gridUtil","uiGridConstants",function(a,b,c,d,e,f){var g={priority:0,scope:{menuItems:"=",autoHide:"=?"},require:"?^uiGrid",templateUrl:"ui-grid/uiGridMenu",replace:!1,link:function(a,d,e,g){var h=this;h.showMenu=a.showMenu=function(c,d){a.shown?a.shownMid||(a.shownMid=!0,a.$emit("menu-shown")):(a.shown=!0,b(function(){a.shownMid=!0,a.$emit("menu-shown")}));var e="click";d&&d.originalEvent&&d.originalEvent.type&&"touchstart"===d.originalEvent.type&&(e=d.originalEvent.type),angular.element(document).off("click touchstart",i),b(function(){angular.element(document).on(e,i)})},h.hideMenu=a.hideMenu=function(){a.shown&&(a.shownMid=!1,b(function(){a.shownMid||(a.shown=!1,a.$emit("menu-hidden"))},200)),angular.element(document).off("click touchstart",i)},a.$on("hide-menu",function(b,c){a.hideMenu(b,c)}),a.$on("show-menu",function(b,c){a.showMenu(b,c)});var i=function(){a.shown&&a.$apply(function(){a.hideMenu()})};("undefined"==typeof a.autoHide||void 0===a.autoHide)&&(a.autoHide=!0),a.autoHide&&angular.element(c).on("resize",i),a.$on("$destroy",function(){angular.element(document).off("click touchstart",i)}),a.$on("$destroy",function(){angular.element(c).off("resize",i)}),g&&a.$on("$destroy",g.grid.api.core.on.scrollEvent(a,i)),a.$on("$destroy",a.$on(f.events.ITEM_DRAGGING,i))},controller:["$scope","$element","$attrs",function(){}]};return g}]).directive("uiGridMenuItem",["gridUtil","$compile","i18nService",function(a,b,c){var d={priority:0,scope:{name:"=",active:"=",action:"=",icon:"=",shown:"=",context:"=",templateUrl:"="},require:["?^uiGrid","^uiGridMenu"],templateUrl:"ui-grid/uiGridMenuItem",replace:!0,compile:function(){return{pre:function(c,d,e,f){f[0],f[1];c.templateUrl&&a.getTemplate(c.templateUrl).then(function(a){var e=angular.element(a),f=b(e)(c);d.replaceWith(f)})},post:function(a,b,d,e){{var f=e[0];e[1]}("undefined"==typeof a.shown||null===a.shown)&&(a.shown=function(){return!0}),a.itemShown=function(){var b={};return a.context&&(b.context=a.context),"undefined"!=typeof f&&f&&(b.grid=f.grid),a.shown.call(b)},a.itemAction=function(b,c){if(b.stopPropagation(),"function"==typeof a.action){var d={};a.context&&(d.context=a.context),"undefined"!=typeof f&&f&&(d.grid=f.grid),a.action.call(d,b,c),a.$emit("hide-menu")}},a.i18n=c.get()}}}};return d}])}(),function(){"use strict";var a=angular.module("ui.grid");a.directive("uiGridRenderContainer",["$timeout","$document","uiGridConstants","gridUtil","ScrollEvent",function(a,b,c,d,e){return{replace:!0,transclude:!0,templateUrl:"ui-grid/uiGridRenderContainer",require:["^uiGrid","uiGridRenderContainer"],scope:{containerId:"=",rowContainerName:"=",colContainerName:"=",bindScrollHorizontal:"=",bindScrollVertical:"=",enableVerticalScrollbar:"=",enableHorizontalScrollbar:"="},controller:"uiGridRenderContainer as RenderContainer",compile:function(){return{pre:function(a,b,c,d){var e=d[0],f=d[1],g=a.grid=e.grid;if(!a.rowContainerName)throw"No row render container name specified";if(!a.colContainerName)throw"No column render container name specified";if(!g.renderContainers[a.rowContainerName])throw"Row render container '"+a.rowContainerName+"' is not registered.";if(!g.renderContainers[a.colContainerName])throw"Column render container '"+a.colContainerName+"' is not registered.";var h=a.rowContainer=g.renderContainers[a.rowContainerName],i=a.colContainer=g.renderContainers[a.colContainerName];f.containerId=a.containerId,f.rowContainer=h,f.colContainer=i},post:function(a,b,c,f){function g(b){if(!b.grid||b.grid.id===k.id){if(b.y&&a.bindScrollVertical){j.prevScrollArgs=b;var c=b.getNewScrollTop(l,j.viewport);(b.source!==e.Sources.ViewPortScroll||b.sourceColContainer!==m)&&(j.viewport[0].scrollTop=c)}if(b.x&&a.bindScrollHorizontal){j.prevScrollArgs=b;var f=b.getNewScrollLeft(m,j.viewport);a.newScrollLeft=f,j.headerViewport&&(j.headerViewport.scrollLeft=d.denormalizeScrollLeft(j.headerViewport,f)),j.footerViewport&&(j.footerViewport.scrollLeft=d.denormalizeScrollLeft(j.footerViewport,f)),b.source!==e.Sources.ViewPortScroll&&(j.viewport[0].scrollLeft=f),j.prevScrollLeft=f}}}function h(){var b="",c=m.getCanvasWidth(),d=m.getViewportWidth(),e=l.getCanvasHeight();"body"!==a.containerId&&(e+=k.scrollbarHeight);var f=l.getViewportHeight(),g=m.getHeaderViewportWidth(),h=m.getHeaderViewportWidth();return b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-canvas { width: "+c+"px; height: "+e+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { width: "+(c+k.scrollbarWidth)+"px; }",n.explicitHeaderCanvasHeight&&(b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-canvas { height: "+n.explicitHeaderCanvasHeight+"px; }"),b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-viewport { width: "+d+"px; height: "+f+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-header-viewport { width: "+g+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-canvas { width: "+c+k.scrollbarWidth+"px; }",b+="\n .grid"+i.grid.id+" .ui-grid-render-container-"+a.containerId+" .ui-grid-footer-viewport { width: "+h+"px; }"}var i=f[0],j=f[1],k=i.grid,l=j.rowContainer,m=j.colContainer,n=k.renderContainers[a.containerId];b.addClass("ui-grid-render-container-"+a.containerId),(a.bindScrollHorizontal||a.bindScrollVertical)&&k.api.core.on.scrollEvent(a,g),d.on.mousewheel(b,function(a){var b=new e(k,l,m,e.Sources.RenderContainerMouseWheel);if(0!==a.deltaY){var c=-1*a.deltaY*a.deltaFactor,f=(j.viewport[0].scrollTop+c)/l.getVerticalScrollLength();0>f?f=0:f>1&&(f=1),b.y={percentage:f,pixels:c}}if(0!==a.deltaX){var g=a.deltaX*a.deltaFactor,h=d.normalizeScrollLeft(j.viewport),i=(h+g)/(m.getCanvasWidth()-m.getViewportWidth());0>i?i=0:i>1&&(i=1),b.x={percentage:i,pixels:g}}(b.y&&0!==b.y.percentage&&1!==b.y.percentage||b.x&&0!==b.x.percentage&&1!==b.x.percentage)&&(a.preventDefault(),b.fireThrottledScrollingEvent())}),b.bind("$destroy",function(){b.unbind("keydown"),["touchstart","touchmove","touchend","keydown","wheel","mousewheel","DomMouseScroll","MozMousePixelScroll"].forEach(function(a){b.unbind(a)})}),i.grid.registerStyleComputation({priority:6,func:h})}}}}}]),a.controller("uiGridRenderContainer",["$scope","gridUtil",function(){}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridRow",["gridUtil",function(){return{replace:!0,require:["^uiGrid","^uiGridRenderContainer"],scope:{row:"=uiGridRow",rowRenderIndex:"="},compile:function(){return{pre:function(a,b,c,d){function e(){a.row.getRowTemplateFn.then(function(c){var d=a.$new();c(d,function(a){h&&(h.remove(),i.$destroy()),b.empty().append(a),h=a,i=d})})}{var f=d[0],g=d[1];f.grid}a.grid=f.grid,a.colContainer=g.colContainer;var h,i;e(),a.$watch("row.getRowTemplateFn",function(a,b){a!==b&&e()})},post:function(){}}}}}])}(),function(){angular.module("ui.grid").directive("uiGridStyle",["gridUtil","$interpolate",function(a,b){return{link:function(a,c){var d=b(c.text(),!0);d&&a.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridViewport",["gridUtil","ScrollEvent","uiGridConstants",function(a,b,c){return{replace:!0,scope:{},controllerAs:"Viewport",templateUrl:"ui-grid/uiGridViewport",require:["^uiGrid","^uiGridRenderContainer"],link:function(d,e,f,g){var h=g[0],i=g[1];d.containerCtrl=i;var j=i.rowContainer,k=i.colContainer,l=h.grid;d.grid=h.grid,d.rowContainer=i.rowContainer,d.colContainer=i.colContainer,i.viewport=e,e.on("scroll",function(){var d=e[0].scrollTop,f=a.normalizeScrollLeft(e),g=-1,h=-1;if(f!==k.prevScrollLeft){l.flagScrollingHorizontally();var i=f-k.prevScrollLeft;i>0&&(l.scrollDirection=c.scrollDirection.RIGHT),0>i&&(l.scrollDirection=c.scrollDirection.LEFT);var m=k.getCanvasWidth()-k.getViewportWidth();g=0!==m?f/m:0,k.adjustScrollHorizontal(f,g)}if(d!==j.prevScrollTop){l.flagScrollingVertically();var n=d-j.prevScrollTop;n>0&&(l.scrollDirection=c.scrollDirection.DOWN),0>n&&(l.scrollDirection=c.scrollDirection.UP);var o=j.getVerticalScrollLength();h=d/o,h>1&&(h=1),0>h&&(h=0),j.adjustScrollVertical(d,h)}var p=new b(l,j,k,b.Sources.ViewPortScroll);p.newScrollLeft=f,p.newScrollTop=d,g>-1&&(p.x={percentage:g}),h>-1&&(p.y={percentage:h}),p.fireScrollingEvent()})},controller:["$scope",function(a){this.rowStyle=function(b){var c=a.rowContainer,d=a.colContainer,e={};if(0===b&&0!==c.currentTopRow){var f=c.currentTopRow*c.grid.options.rowHeight;e["margin-top"]=f+"px"}return 0!==d.currentFirstColumn&&(d.grid.isRTL()?e["margin-right"]=d.columnOffset+"px":e["margin-left"]=d.columnOffset+"px"),e}}]}}])}(),function(){angular.module("ui.grid").directive("uiGridVisible",function(){return function(a,b,c){a.$watch(c.uiGridVisible,function(a){b[a?"removeClass":"addClass"]("ui-grid-invisible")})}})}(),function(){"use strict";angular.module("ui.grid").controller("uiGridController",["$scope","$element","$attrs","gridUtil","$q","uiGridConstants","$templateCache","gridClassFactory","$timeout","$parse","$compile","ScrollEvent",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,b){a&&a!==b&&(p.grid.options.columnDefs=a,p.grid.buildColumns({orderByColumnDefs:!0}).then(function(){p.grid.preCompileCellTemplates(),p.grid.callDataChangeCallbacks(f.dataChange.COLUMN)}))}function n(a){var b=new l(p.grid,null,null,"ui.grid.adjustInfiniteScrollPosition"),c=p.grid.renderContainers.body.visibleRowCache.length,d=(a+a/(c-1))/c;b.y=0===d?{pixels:1}:{percentage:d},b.fireScrollingEvent()}function o(b){var d=[];b&&(p.grid.columns.length===(p.grid.rowHeaderColumns?p.grid.rowHeaderColumns.length:0)&&!c.uiGridColumns&&0===p.grid.options.columnDefs.length&&b.length>0&&p.grid.buildColumnDefsFromData(b),(p.grid.options.columnDefs.length>0||b.length>0)&&d.push(p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates()})),e.all(d).then(function(){p.grid.modifyRows(b).then(function(){p.grid.redrawInPlace(!0),a.$evalAsync(function(){p.grid.refreshCanvas(!0),p.grid.callDataChangeCallbacks(f.dataChange.ROW),i(function(){p.grid.options.enableInfiniteScroll&&(0===p.grid.renderContainers.body.prevRowScrollIndex&&n(0),p.grid.scrollDirection===f.scrollDirection.UP&&n(p.grid.renderContainers.body.prevRowScrollIndex+1+p.grid.options.excessRows))},0)})})}))}var p=this;p.grid=h.createGrid(a.uiGrid),p.grid.appScope=p.grid.appScope||a.$parent,b.addClass("grid"+p.grid.id),p.grid.rtl="rtl"===d.getStyles(b[0]).direction,a.grid=p.grid,c.uiGridColumns&&c.$observe("uiGridColumns",function(a){p.grid.options.columnDefs=a,p.grid.buildColumns().then(function(){p.grid.preCompileCellTemplates(),p.grid.refreshCanvas(!0)})});var q;q=angular.isString(a.uiGrid.data)?a.$parent.$watchCollection(a.uiGrid.data,o):a.$parent.$watchCollection(function(){return a.uiGrid.data},o);var r=a.$parent.$watchCollection(function(){return a.uiGrid.columnDefs},m),s=a.$watch(function(){return p.grid.styleComputations},function(){p.grid.refreshCanvas(!0)});a.$on("$destroy",function(){q(),r(),s()}),p.fireEvent=function(b,c){("undefined"==typeof c||void 0===c)&&(c={}),("undefined"==typeof c.grid||void 0===c.grid)&&(c.grid=p.grid),a.$broadcast(b,c)},p.innerCompile=function(b){k(b)(a)}}]),angular.module("ui.grid").directive("uiGrid",["$compile","$templateCache","gridUtil","$window","uiGridConstants",function(a,b,c,d,e){return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},replace:!0,transclude:!0,controller:"uiGridController",compile:function(){return{post:function(a,b,f,g){function h(){i.gridWidth=a.gridWidth=c.elementWidth(b),i.gridHeight=a.gridHeight=c.elementHeight(b),i.refreshCanvas(!0)}var i=g.grid;if(g.scrollbars=[],i.renderingComplete(),i.element=b,i.gridWidth=a.gridWidth=c.elementWidth(b),i.canvasWidth=g.grid.gridWidth,i.gridHeight=a.gridHeight=c.elementHeight(b),i.gridHeight<i.options.rowHeight){var j=i.options.minRowsToShow*i.options.rowHeight,k=i.options.showHeader?i.options.headerRowHeight:0,l=i.calcFooterHeight(),m=0;i.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(m=c.getScrollbarWidth());var n=0;angular.forEach(i.options.columnDefs,function(a){a.hasOwnProperty("filter")?1>n&&(n=1):a.hasOwnProperty("filters")&&n<a.filters.length&&(n=a.filters.length)});var o=n*k,p=k+j+l+m+o;b.css("height",p+"px"),i.gridHeight=a.gridHeight=c.elementHeight(b)}i.refreshCanvas(),a.$watch(function(){return i.hasLeftContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),a.$watch(function(){return i.hasRightContainer()},function(a,b){a!==b&&i.refreshCanvas(!0)}),angular.element(d).on("resize",h),b.on("$destroy",function(){angular.element(d).off("resize",h)})}}}}}])}(),function(){"use strict";angular.module("ui.grid").directive("uiGridPinnedContainer",["gridUtil",function(){return{restrict:"EA",replace:!0,template:'<div class="ui-grid-pinned-container"><div ui-grid-render-container container-id="side" row-container-name="\'body\'" col-container-name="side" bind-scroll-vertical="true" class="{{ side }} ui-grid-render-container-{{ side }}"></div></div>',scope:{side:"=uiGridPinnedContainer"},require:"^uiGrid",compile:function(){return{post:function(a,b,c,d){function e(){if("left"===a.side||"right"===a.side){for(var b=g.renderContainers[a.side].visibleColumnCache,c=0,d=0;d<b.length;d++){var e=b[d];
    +c+=e.drawnWidth||e.width||0}h=c}}function f(){var c="";if("left"===a.side||"right"===a.side){e(),b.attr("style",null);var d=g.renderContainers.body.getViewportHeight();c+=".grid"+g.id+" .ui-grid-pinned-container-"+a.side+", .grid"+g.id+" .ui-grid-pinned-container-"+a.side+" .ui-grid-render-container-"+a.side+" .ui-grid-viewport { width: "+h+"px; height: "+d+"px; } "}return c}var g=d.grid,h=0;b.addClass("ui-grid-pinned-container-"+a.side),g.renderContainers.body.registerViewportAdjuster(function(a){return 0!==h&&h||e(),a.width-=h,a}),g.registerStyleComputation({priority:15,func:f})}}}}}])}(),function(){angular.module("ui.grid").factory("Grid",["$q","$compile","$parse","gridUtil","uiGridConstants","GridOptions","GridColumn","GridRow","GridApi","rowSorter","rowSearcher","GridRenderContainer","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(){}var o=function(a){var b=this;if(void 0===a||"undefined"==typeof a.id||!a.id)throw new Error("No ID provided. An ID must be given when creating a grid.");if(!/^[_a-zA-Z0-9-]+$/.test(a.id))throw new Error("Grid id '"+a.id+'" is invalid. It must follow CSS selector syntax rules.');b.id=a.id,delete a.id,b.options=f.initialize(a),b.appScope=b.options.appScopeProvider,b.headerHeight=b.options.headerRowHeight,b.footerHeight=b.calcFooterHeight(),b.rtl=!1,b.gridHeight=0,b.gridWidth=0,b.columnBuilders=[],b.rowBuilders=[],b.rowsProcessors=[],b.columnsProcessors=[],b.styleComputations=[],b.viewportAdjusters=[],b.rowHeaderColumns=[],b.dataChangeCallbacks={},b.renderContainers={},b.renderContainers.body=new l("body",b),b.cellValueGetterCache={},b.getRowTemplateFn=null,b.rows=[],b.columns=[],b.isScrollingVertically=!1,b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE;var c=d.debounce(function(){b.isScrollingVertically=!1,b.scrollDirection=e.scrollDirection.NONE},1e3),g=d.debounce(function(){b.isScrollingHorizontally=!1,b.scrollDirection=e.scrollDirection.NONE},1e3);b.flagScrollingVertically=function(){b.isScrollingVertically=!0,c()},b.flagScrollingHorizontally=function(){b.isScrollingHorizontally=!0,g()},b.scrollbarHeight=0,b.scrollbarWidth=0,b.options.enableHorizontalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarHeight=d.getScrollbarWidth()),b.options.enableVerticalScrollbar===e.scrollbars.ALWAYS&&(b.scrollbarWidth=d.getScrollbarWidth()),b.api=new i(b),b.api.registerMethod("core","refresh",this.refresh),b.api.registerMethod("core","refreshRows",this.refreshRows),b.api.registerMethod("core","handleWindowResize",this.handleWindowResize),b.api.registerMethod("core","addRowHeaderColumn",this.addRowHeaderColumn),b.api.registerMethod("core","sortHandleNulls",j.handleNulls),b.api.registerEvent("core","sortChanged"),b.api.registerEvent("core","columnVisibilityChanged"),b.api.registerMethod("core","notifyDataChange",this.notifyDataChange),b.registerDataChangeCallback(b.columnRefreshCallback,[e.dataChange.COLUMN]),b.registerDataChangeCallback(b.processRowsCallback,[e.dataChange.EDIT]),b.registerStyleComputation({priority:10,func:b.getFooterStyles})};return o.prototype.calcFooterHeight=function(){if(!this.hasFooter())return 0;var a=0;return this.options.showGridFooter&&(a+=this.options.gridFooterHeight),this.options.showColumnFooter&&(a+=this.options.columnFooterHeight),a},o.prototype.getFooterStyles=function(){var a=".grid"+this.id+" .ui-grid-footer-aggregates-row { height: "+this.options.columnFooterHeight+"px; }";return a+=" .grid"+this.id+" .ui-grid-footer-info { height: "+this.options.gridFooterHeight+"px; }"},o.prototype.hasFooter=function(){return this.options.showGridFooter||this.options.showColumnFooter},o.prototype.isRTL=function(){return this.rtl},o.prototype.registerColumnBuilder=function(a){this.columnBuilders.push(a)},o.prototype.buildColumnDefsFromData=function(a){this.options.columnDefs=d.getColumnsFromData(a,this.options.excludeProperties)},o.prototype.registerRowBuilder=function(a){this.rowBuilders.push(a)},o.prototype.registerDataChangeCallback=function(a,b,c){var f=d.nextUid();b||(b=[e.dataChange.ALL]),Array.isArray(b)||d.logError("Expected types to be an array or null in registerDataChangeCallback, value passed was: "+b),this.dataChangeCallbacks[f]={callback:a,types:b,_this:c};var g=this,h=function(){delete g.dataChangeCallbacks[f]};return h},o.prototype.callDataChangeCallbacks=function(a){angular.forEach(this.dataChangeCallbacks,function(b){(-1!==b.types.indexOf(e.dataChange.ALL)||-1!==b.types.indexOf(a)||a===e.dataChange.ALL)&&(b._this?b.callback.apply(b._this,this):b.callback(this))},this)},o.prototype.notifyDataChange=function(a){var b=e.dataChange;a===b.ALL||a===b.COLUMN||a===b.EDIT||a===b.ROW||a===b.OPTIONS?this.callDataChangeCallbacks(a):d.logError("Notified of a data change, but the type was not recognised, so no action taken, type was: "+a)},o.prototype.columnRefreshCallback=function(a){a.buildColumns(),a.refresh()},o.prototype.processRowsCallback=function(a){a.refreshRows()},o.prototype.getColumn=function(a){var b=this.columns.filter(function(b){return b.colDef.name===a});return b.length>0?b[0]:null},o.prototype.getColDef=function(a){var b=this.options.columnDefs.filter(function(b){return b.name===a});return b.length>0?b[0]:null},o.prototype.assignTypes=function(){var a=this;a.options.columnDefs.forEach(function(b,c){if(!b.type){var e=new g(b,c,a),f=a.rows.length>0?a.rows[0]:null;f?b.type=d.guessType(a.getCellValue(f,e)):(d.logWarn("Unable to assign type from data, so defaulting to string"),b.type="string")}})},o.prototype.addRowHeaderColumn=function(a){var b=this,c=new g(a,d.nextUid(),b);c.isRowHeader=!0,b.isRTL()?(b.createRightContainer(),c.renderContainer="right"):(b.createLeftContainer(),c.renderContainer="left"),b.columnBuilders[0](a,c,b.options).then(function(){c.enableFiltering=!1,c.enableSorting=!1,c.enableHiding=!1,b.rowHeaderColumns.push(c),b.buildColumns().then(function(){b.preCompileCellTemplates(),b.refresh()})})},o.prototype.buildColumns=function(b){var c={orderByColumnDefs:!1};angular.extend(c,b);var e,f=this,h=[],i=f.rowHeaderColumns.length;for(e=0;e<f.columns.length;e++)f.getColDef(f.columns[e].name)||(f.columns.splice(e,1),e--);if(f.rowHeaderColumns.forEach(function(a){f.columns.unshift(a)}),f.options.columnDefs.forEach(function(a,b){f.preprocessColDef(a);var c=f.getColumn(a.name);c?c.updateColumnDef(a,!1):(c=new g(a,d.nextUid(),f),f.columns.splice(b+i,0,c)),f.columnBuilders.forEach(function(b){h.push(b.call(f,a,c,f.options))})}),c.orderByColumnDefs){var j=f.columns.slice(0);for(e=0;e<f.options.columnDefs.length;e++)j[e+i]=f.columns[e+i].name!==f.options.columnDefs[e].name?f.getColumn(f.options.columnDefs[e].name):f.columns[e+i];f.columns.length=0,Array.prototype.splice.apply(f.columns,[0,0].concat(j))}return a.all(h).then(function(){f.rows.length>0&&f.assignTypes()})},o.prototype.preCompileCellTemplates=function(){var a=this;this.columns.forEach(function(c){var d=c.cellTemplate.replace(e.MODEL_COL_FIELD,a.getQualifiedColField(c));d=d.replace(e.COL_FIELD,"grid.getCellValue(row, col)");var f=b(d);c.compiledElementFn=f,c.compiledElementFnDefer&&c.compiledElementFnDefer.resolve(c.compiledElementFn)})},o.prototype.getQualifiedColField=function(a){return"row.entity."+d.preEval(a.field)},o.prototype.createLeftContainer=function(){this.hasLeftContainer()||(this.renderContainers.left=new l("left",this,{disableColumnOffset:!0}))},o.prototype.createRightContainer=function(){this.hasRightContainer()||(this.renderContainers.right=new l("right",this,{disableColumnOffset:!0}))},o.prototype.hasLeftContainer=function(){return void 0!==this.renderContainers.left},o.prototype.hasRightContainer=function(){return void 0!==this.renderContainers.right},o.prototype.preprocessColDef=function(a){var b=this;if(!a.field&&!a.name)throw new Error("colDef.name or colDef.field property is required");if(void 0===a.name&&void 0!==a.field){var c=b.getColumn(a.field);if(c){var d=new RegExp("^"+a.field+"(\\d+)$","i"),e=b.columns.filter(function(a){return d.test(a.displayName)}).sort(function(a,b){if(a===b)return 0;var c=a.displayName.match(d)[1],e=b.displayName.match(d)[1];return parseInt(c,10)>parseInt(e,10)?1:-1});if(0===e.length)a.name=a.field+"2";else{var f=e[e.length-1].displayName.match(d)[1];f=parseInt(f,10),a.name=a.field+(f+1)}}else a.name=a.field}},o.prototype.newInN=function(a,b,c,d){for(var e=this,f=[],g=0;g<b.length;g++){for(var h=d?b[g][d]:b[g],i=!1,j=0;j<a.length;j++){var k=c?a[j][c]:a[j];if(e.options.rowEquality(h,k)){i=!0;break}}i||f.push(h)}return f},o.prototype.getRow=function(a){var b=this,c=this.rows.filter(function(c){return b.options.rowEquality(c.entity,a)});return c.length>0?c[0]:null},o.prototype.modifyRows=function(b){var c,d,e,f,g=this;if((g.options.useExternalSorting||0===g.getColumnSorting().length)&&b.length>0){var i=g.rowHashMap;i||(i={get:function(){return null}}),g.createRowHashMap(),d=g.rowHashMap;{0===g.rows.length}for(g.rows.length=0,c=0;c<b.length;c++){var j=b[c];e=i.get(j),f=e?e.row:g.processRowBuilders(new h(j,c,g)),g.rows.push(f),d.put(j,{i:c,entity:j,row:f})}g.assignTypes()}else if(0===g.rows.length&&b.length>0){if(g.options.enableRowHashing)for(g.rowHashMap||g.createRowHashMap(),c=0;c<b.length;c++)f=b[c],g.rowHashMap.put(f,{i:c,entity:f});g.addRows(b),g.assignTypes()}else if(b.length>0){var k,l,m;if(g.options.enableRowHashing){k=[],m=[];var n={};for(l=[],g.rowHashMap||g.createRowHashMap(),d=g.rowHashMap,c=0;c<b.length;c++){f=b[c];var o=!1;g.options.getRowIdentity(f)||(o=!0),e=d.get(f),e?e.row&&(n[g.options.rowIdentity(f)]=!0):(d.put(f,{i:c,entity:f}),o?m.push(f):k.push(f))}for(c=0;c<g.rows.length;c++){var p=g.rows[c],q=g.options.rowIdentity(p.entity);n[q]||l.push(p)}}var r=k||[],s=m||b;r=r.concat(g.newInN(g.rows,s,"entity")),g.addRows(r);var t=g.getDeletedRows(l||g.rows,b);for(c=0;c<t.length;c++)g.options.enableRowHashing&&g.rowHashMap.remove(t[c].entity),g.rows.splice(g.rows.indexOf(t[c]),1)}else g.createRowHashMap(),g.rows.length=0;var u=a.when(g.processRowsProcessors(g.rows)).then(function(a){return g.setVisibleRows(a)}),v=a.when(g.processColumnsProcessors(g.columns)).then(function(a){return g.setVisibleColumns(a)});return a.all([u,v])},o.prototype.getDeletedRows=function(a,b){var c=this,d=a.filter(function(a){return!b.some(function(b){return c.options.rowEquality(b,a.entity)})});return d},o.prototype.addRows=function(a){for(var b=this,c=b.rows.length,d=0;d<a.length;d++){var e=b.processRowBuilders(new h(a[d],d+c,b));if(b.options.enableRowHashing){var f=b.rowHashMap.get(e.entity);f&&(f.row=e)}b.rows.push(e)}},o.prototype.processRowBuilders=function(a){var b=this;return b.rowBuilders.forEach(function(c){c.call(b,a,b.options)}),a},o.prototype.registerStyleComputation=function(a){this.styleComputations.push(a)},o.prototype.registerRowsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.rowsProcessors.push(a)},o.prototype.removeRowsProcessor=function(a){var b=this.rowsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.rowsProcessors.splice(b,1)},o.prototype.processRowsProcessors=function(b){function c(b,e){var g=d.rowsProcessors[b];return a.when(g.call(d,e,d.columns)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.rowsProcessors.length-1?c(b,a):void f.resolve(a)})}var d=this,e=b.slice(0);if(0===d.rowsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleRows=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.canvasHeightShouldUpdate=!0,"undefined"==typeof d.visibleRowCache?d.visibleRowCache=[]:d.visibleRowCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleRowCache.push(f):b.renderContainers.body.visibleRowCache.push(f))}b.api.core.raise.rowsRendered(this.api)},o.prototype.registerColumnsProcessor=function(a){if(!angular.isFunction(a))throw"Attempt to register non-function rows processor: "+a;this.columnsProcessors.push(a)},o.prototype.removeColumnsProcessor=function(a){var b=this.columnsProcessors.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.columnsProcessors.splice(b,1)},o.prototype.processColumnsProcessors=function(b){function c(b,g){var h=d.columnsProcessors[b];return a.when(h.call(d,g,d.rows)).then(function(a){if(!a)throw"Processor at index "+b+" did not return a set of renderable rows";if(!angular.isArray(a))throw"Processor at index "+b+" did not return an array";return b++,b<=d.columnsProcessors.length-1?c(b,e):void f.resolve(e)})}var d=this,e=b.slice(0);if(0===d.columnsProcessors.length)return a.when(e);var f=a.defer();return c(0,e),f.promise},o.prototype.setVisibleColumns=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];d.visibleColumnCache.length=0}for(var e=0;e<a.length;e++){var f=a[e];f.visible&&("undefined"!=typeof f.renderContainer&&f.renderContainer?b.renderContainers[f.renderContainer].visibleColumnCache.push(f):b.renderContainers.body.visibleColumnCache.push(f))}},o.prototype.handleWindowResize=function(){var a=this;a.gridWidth=d.elementWidth(a.element),a.gridHeight=d.elementHeight(a.element),a.queueRefresh()},o.prototype.queueRefresh=function(){var a=this;return a.refreshCanceller&&m.cancel(a.refreshCanceller),a.refreshCanceller=m(function(){a.refreshCanvas(!0)}),a.refreshCanceller.then(function(){a.refreshCanceller=null}),a.refreshCanceller},o.prototype.updateCanvasHeight=function(){var a=this;for(var b in a.renderContainers)if(a.renderContainers.hasOwnProperty(b)){var c=a.renderContainers[b];c.canvasHeightShouldUpdate=!0}},o.prototype.buildStyles=function(){var a=this;a.customStyles="",a.styleComputations.sort(function(a,b){return null===a.priority?1:null===b.priority?-1:null===a.priority&&null===b.priority?0:a.priority-b.priority}).forEach(function(b){var c=b.func.call(a);angular.isString(c)&&(a.customStyles+="\n"+c)})},o.prototype.minColumnsToRender=function(){var a=this,b=this.getViewportWidth(),c=0,d=0;return a.columns.forEach(function(e,f){if(b>d)d+=e.drawnWidth,c++;else{for(var g=0,h=f;h>=f-c;h--)g+=a.columns[h].drawnWidth;b>g&&c++}}),c},o.prototype.getBodyHeight=function(){var a=this.getViewportHeight();return a},o.prototype.getViewportHeight=function(){var a=this,b=this.gridHeight-this.headerHeight-this.footerHeight,c=a.getViewportAdjustment();return b+=c.height},o.prototype.getViewportWidth=function(){var a=this,b=this.gridWidth,c=a.getViewportAdjustment();return b+=c.width},o.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},o.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},o.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},o.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},o.prototype.getVisibleRowCount=function(){return this.renderContainers.body.visibleRowCache.length},o.prototype.getVisibleRows=function(){return this.renderContainers.body.visibleRowCache},o.prototype.getVisibleColumnCount=function(){return this.renderContainers.body.visibleColumnCache.length},o.prototype.searchRows=function(a){return k.search(this,a,this.columns)},o.prototype.sortByColumn=function(a){return j.sort(this,a,this.columns)},o.prototype.getCellValue=function(a,b){var d=this;return d.cellValueGetterCache[b.colDef.name]||(d.cellValueGetterCache[b.colDef.name]=c(a.getEntityQualifiedColField(b))),d.cellValueGetterCache[b.colDef.name](a)},o.prototype.getNextColumnSortPriority=function(){var a=this,b=0;return a.columns.forEach(function(a){a.sort&&a.sort.priority&&a.sort.priority>b&&(b=a.sort.priority)}),b+1},o.prototype.resetColumnSorting=function(a){var b=this;b.columns.forEach(function(b){b===a||b.colDef.suppressRemoveSort||(b.sort={})})},o.prototype.getColumnSorting=function(){var a,b=this,c=[];return a=b.columns.slice(0),a.sort(j.prioritySort).forEach(function(a){a.sort&&"undefined"!=typeof a.sort.direction&&a.sort.direction&&(a.sort.direction===e.ASC||a.sort.direction===e.DESC)&&c.push(a)}),c},o.prototype.sortColumn=function(b,c,d){var f=this,g=null;if("undefined"==typeof b||!b)throw new Error("No column parameter provided");return"boolean"==typeof c?d=c:g=c,d?b.sort.priority=f.getNextColumnSortPriority():(f.resetColumnSorting(b),b.sort.priority=0),b.sort.direction=g?g:b.sort.direction&&b.sort.direction===e.ASC?e.DESC:b.sort.direction&&b.sort.direction===e.DESC?b.colDef&&b.colDef.suppressRemoveSort?e.ASC:null:e.ASC,f.api.core.raise.sortChanged(f,f.getColumnSorting()),a.when(b)},o.prototype.renderingComplete=function(){angular.isFunction(this.options.onRegisterApi)&&this.options.onRegisterApi(this.api),this.api.core.raise.renderingComplete(this.api)},o.prototype.createRowHashMap=function(){var a=this,b=new n;b.grid=a,a.rowHashMap=b},o.prototype.refresh=function(b){var c=this,d=c.processRowsProcessors(c.rows).then(function(a){c.setVisibleRows(a)}),e=c.processColumnsProcessors(c.columns).then(function(a){c.setVisibleColumns(a)});return a.all([d,e]).then(function(){c.redrawInPlace(b),c.refreshCanvas(!0)})},o.prototype.refreshRows=function(){var a=this;return a.processRowsProcessors(a.rows).then(function(b){a.setVisibleRows(b),a.redrawInPlace(),a.refreshCanvas(!0)})},o.prototype.refreshCanvas=function(b){var c=this;b&&c.buildStyles();var e=a.defer(),f=[];for(var g in c.renderContainers)if(c.renderContainers.hasOwnProperty(g)){var h=c.renderContainers[g];if(null===h.canvasWidth||isNaN(h.canvasWidth))continue;(h.header||h.headerCanvas)&&f.push(h)}return m(f.length>0?function(){var a,g,h=!1,i=0,j=0;for(a=0;a<f.length;a++)if(g=f[a],null!==g.canvasWidth&&!isNaN(g.canvasWidth)){if(g.header){var k=g.headerHeight,l=d.outerElementHeight(g.header);g.headerHeight=parseInt(l,10),k!==l&&(h=!0);var m=d.getBorderSize(g.header,"top"),n=d.getBorderSize(g.header,"bottom"),o=parseInt(l-m-n,10);o=0>o?0:o,g.innerHeaderHeight=o,o>i&&(i=o)}if(g.headerCanvas){var p=g.headerCanvasHeight,q=d.outerElementHeight(g.headerCanvas);g.headerCanvasHeight=parseInt(q,10),p!==q&&(h=!0),q>j&&(j=q)}}for(a=0;a<f.length;a++)g=f[a],i>0&&"undefined"!=typeof g.headerHeight&&null!==g.headerHeight&&g.headerHeight<i&&(g.explicitHeaderHeight=i),"undefined"!=typeof g.headerCanvasHeight&&null!==g.headerCanvasHeight&&j>0&&g.headerCanvasHeight<j&&(g.explicitHeaderCanvasHeight=j);b&&h&&c.buildStyles(),e.resolve()}:function(){e.resolve()}),e.promise},o.prototype.redrawInPlace=function(a){var b=this;for(var c in b.renderContainers){var d=b.renderContainers[c];a?(d.adjustRows(d.prevScrollTop,null),d.adjustColumns(d.prevScrollTop,null)):(d.adjustRows(null,d.prevScrolltopPercentage),d.adjustColumns(null,d.prevScrollleftPercentage))}},o.prototype.hasLeftContainerColumns=function(){return this.hasLeftContainer()&&this.renderContainers.left.renderedColumns.length>0},o.prototype.hasRightContainerColumns=function(){return this.hasRightContainer()&&this.renderContainers.right.renderedColumns.length>0},n.prototype={put:function(a,b){this[this.grid.options.rowIdentity(a)]=b},get:function(a){return this[this.grid.options.rowIdentity(a)]},remove:function(a){var b=this[a=this.grid.options.rowIdentity(a)];return delete this[a],b}},o}])}(),function(){angular.module("ui.grid").factory("GridApi",["$q","$rootScope","gridUtil","uiGridConstants","GridRow","uiGridGridMenuService",function(a,b,c,d,e){function f(a,c,d,e){return b.$on(a,function(){var a=Array.prototype.slice.call(arguments);a.splice(0,1),c.apply(e?e:d.api,a)})}var g=function(a){this.grid=a,this.listeners=[],this.registerEvent("core","renderingComplete"),this.registerEvent("core","filterChanged"),this.registerMethod("core","setRowInvisible",e.prototype.setRowInvisible),this.registerMethod("core","clearRowInvisible",e.prototype.clearRowInvisible),this.registerMethod("core","getVisibleRows",this.grid.getVisibleRows),this.registerEvent("core","rowsVisibleChanged"),this.registerEvent("core","rowsRendered"),this.registerEvent("core","scrollEvent"),this.registerEvent("core","canvasHeightChanged")};return g.prototype.suppressEvents=function(a,b){var c=this,d=angular.isArray(a)?a:[a],e=[];d.forEach(function(a){e=c.listeners.filter(function(b){return a===b.handler})}),e.forEach(function(a){a.dereg()}),b(),e.forEach(function(a){a.dereg=f(a.eventId,a.handler,c.grid,a._this)})},g.prototype.registerEvent=function(a,c){var d=this;d[a]||(d[a]={});var e=d[a];e.on||(e.on={},e.raise={});var g=d.grid.id+a+c;e.raise[c]=function(){b.$emit.apply(b,[g].concat(Array.prototype.slice.call(arguments)))},e.on[c]=function(a,b,c){var e=f(g,b,d.grid,c),h={handler:b,dereg:e,eventId:g,scope:a,_this:c};d.listeners.push(h);var i=function(){h.dereg();var a=d.listeners.indexOf(h);d.listeners.splice(a,1)};return a.$on("$destroy",function(){i()}),i}},g.prototype.registerEventsFromObject=function(a){var b=this,c=[];angular.forEach(a,function(a,b){var d={name:b,events:[]};angular.forEach(a,function(a,b){d.events.push(b)}),c.push(d)}),c.forEach(function(a){a.events.forEach(function(c){b.registerEvent(a.name,c)})})},g.prototype.registerMethod=function(a,b,d,e){this[a]||(this[a]={});var f=this[a];f[b]=c.createBoundedWrapper(e||this.grid,d)},g.prototype.registerMethodsFromObject=function(a,b){var c=this,d=[];angular.forEach(a,function(a,b){var c={name:b,methods:[]};angular.forEach(a,function(a,b){c.methods.push({name:b,fn:a})}),d.push(c)}),d.forEach(function(a){a.methods.forEach(function(d){c.registerMethod(a.name,d.name,d.fn,b)})})},g}])}(),function(){angular.module("ui.grid").factory("GridColumn",["gridUtil","uiGridConstants","i18nService",function(a,b,c){function d(a,b,c){var d=this;d.grid=c,d.uid=b,d.updateColumnDef(a,!0)}return d.prototype.setPropertyOrDefault=function(a,b,c){var d=this;d[b]="undefined"!=typeof a[b]&&a[b]?a[b]:"undefined"!=typeof d[b]?d[b]:c?c:{}},d.prototype.updateColumnDef=function(b,c){var e=this;if(e.colDef=b,void 0===b.name)throw new Error("colDef.name is required for column at index "+e.grid.options.columnDefs.indexOf(b));e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName;var f="Cannot parse column width '"+b.width+"' for column named '"+b.name+"'";if(a.isNullOrUndefined(e.width)||!angular.isNumber(e.width))if(a.isNullOrUndefined(b.width))e.width="*";else if(angular.isNumber(b.width))e.width=b.width;else if(a.endsWith(b.width,"%")){var g=b.width.replace(/%/g,""),h=parseInt(g,10);if(isNaN(h))throw new Error(f);e.width=b.width}else if(b.width.match(/^(\d+)$/))e.width=parseInt(b.width.match(/^(\d+)$/)[1],10);else{if(!b.width.match(/^\*+$/))throw new Error(f);e.width=b.width}e.minWidth=b.minWidth?b.minWidth:30,e.maxWidth=b.maxWidth?b.maxWidth:9e3,e.field=void 0===b.field?b.name:b.field,"string"!=typeof e.field&&a.logError("Field is not a string, this is likely to break the code, Field is: "+e.field),e.name=b.name,e.displayName=void 0===b.displayName?a.readableColumnName(b.name):b.displayName,e.aggregationType=angular.isDefined(b.aggregationType)?b.aggregationType:null,e.footerCellTemplate=angular.isDefined(b.footerCellTemplate)?b.footerCellTemplate:null,e.footerCellClass=b.footerCellClass,e.cellClass=b.cellClass,e.headerCellClass=b.headerCellClass,e.cellFilter=b.cellFilter?b.cellFilter:"",e.headerCellFilter=b.headerCellFilter?b.headerCellFilter:"",e.footerCellFilter=b.footerCellFilter?b.footerCellFilter:"",e.visible=a.isNullOrUndefined(b.visible)||b.visible,e.headerClass=b.headerClass,e.enableSorting="undefined"!=typeof b.enableSorting?b.enableSorting:!0,e.sortingAlgorithm=b.sortingAlgorithm,e.enableFiltering="undefined"!=typeof b.enableFiltering?b.enableFiltering:!0,e.setPropertyOrDefault(b,"menuItems",[]),c&&e.setPropertyOrDefault(b,"sort");var i=[];b.filter?i.push(b.filter):e.enableFiltering&&e.grid.options.enableFiltering&&i.push({}),c&&(e.setPropertyOrDefault(b,"filter"),e.setPropertyOrDefault(b,"filters",i)),d.prototype.unsort=function(){this.sort={},e.grid.api.core.raise.sortChanged(e,e.grid.getColumnSorting())}},d.prototype.getColClass=function(a){var c=b.COL_CLASS_PREFIX+this.uid;return a?"."+c:c},d.prototype.getColClassDefinition=function(){return" .grid"+this.grid.id+" "+this.getColClass(!0)+" { min-width: "+this.drawnWidth+"px; max-width: "+this.drawnWidth+"px; }"},d.prototype.getRenderContainer=function(){var a=this,b=a.renderContainer;return(null===b||""===b||void 0===b)&&(b="body"),a.grid.renderContainers[b]},d.prototype.showColumn=function(){this.colDef.visible=!0},d.prototype.hideColumn=function(){this.colDef.visible=!1},d.prototype.getAggregationValue=function(){var a=this,c=0,d=a.grid.getVisibleRows(),e=function(){var b=[];return angular.forEach(d,function(c){var d=a.grid.getCellValue(c,a);angular.isNumber(d)&&b.push(d)}),b};return angular.isFunction(a.aggregationType)?a.aggregationType(d,a):a.aggregationType===b.aggregationTypes.count?a.grid.getVisibleRowCount():a.aggregationType===b.aggregationTypes.sum?(angular.forEach(e(),function(a){c+=a}),c):a.aggregationType===b.aggregationTypes.avg?(angular.forEach(e(),function(a){c+=a}),c/=e().length):a.aggregationType===b.aggregationTypes.min?Math.min.apply(null,e()):a.aggregationType===b.aggregationTypes.max?Math.max.apply(null,e()):" "},d.prototype.getAggregationText=function(){var a=this;if(a.colDef.aggregationHideLabel)return"";if(a.colDef.aggregationLabel)return a.colDef.aggregationLabel;switch(a.colDef.aggregationType){case b.aggregationTypes.count:return c.getSafeText("aggregation.count");case b.aggregationTypes.sum:return c.getSafeText("aggregation.sum");case b.aggregationTypes.avg:return c.getSafeText("aggregation.avg");case b.aggregationTypes.min:return c.getSafeText("aggregation.min");case b.aggregationTypes.max:return c.getSafeText("aggregation.max");default:return""}},d.prototype.getCellTemplate=function(){var a=this;return a.cellTemplatePromise},d.prototype.getCompiledElementFn=function(){var a=this;return a.compiledElementFnDefer.promise},d}])}(),function(){angular.module("ui.grid").factory("GridOptions",["gridUtil","uiGridConstants",function(a,b){return{initialize:function(c){return c.onRegisterApi=c.onRegisterApi||angular.noop(),c.data=c.data||[],c.columnDefs=c.columnDefs||[],c.excludeProperties=c.excludeProperties||["$$hashKey"],c.enableRowHashing=c.enableRowHashing!==!1,c.rowIdentity=c.rowIdentity||function(b){return a.hashKey(b)},c.getRowIdentity=c.getRowIdentity||function(a){return a.$$hashKey},c.showHeader="undefined"!=typeof c.showHeader?c.showHeader:!0,c.headerRowHeight=c.showHeader?"undefined"!=typeof c.headerRowHeight?c.headerRowHeight:30:0,c.rowHeight=c.rowHeight||30,c.minRowsToShow="undefined"!=typeof c.minRowsToShow?c.minRowsToShow:10,c.showGridFooter=c.showGridFooter===!0,c.showColumnFooter=c.showColumnFooter===!0,c.columnFooterHeight="undefined"!=typeof c.columnFooterHeight?c.columnFooterHeight:30,c.gridFooterHeight="undefined"!=typeof c.gridFooterHeight?c.gridFooterHeight:30,c.columnWidth="undefined"!=typeof c.columnWidth?c.columnWidth:50,c.maxVisibleColumnCount="undefined"!=typeof c.maxVisibleColumnCount?c.maxVisibleColumnCount:200,c.virtualizationThreshold="undefined"!=typeof c.virtualizationThreshold?c.virtualizationThreshold:20,c.columnVirtualizationThreshold="undefined"!=typeof c.columnVirtualizationThreshold?c.columnVirtualizationThreshold:10,c.excessRows="undefined"!=typeof c.excessRows?c.excessRows:4,c.scrollThreshold="undefined"!=typeof c.scrollThreshold?c.scrollThreshold:4,c.excessColumns="undefined"!=typeof c.excessColumns?c.excessColumns:4,c.horizontalScrollThreshold="undefined"!=typeof c.horizontalScrollThreshold?c.horizontalScrollThreshold:2,c.scrollThrottle="undefined"!=typeof c.scrollThrottle?c.scrollThrottle:70,c.enableSorting=c.enableSorting!==!1,c.enableFiltering=c.enableFiltering===!0,c.enableColumnMenus=c.enableColumnMenus!==!1,c.enableVerticalScrollbar="undefined"!=typeof c.enableVerticalScrollbar?c.enableVerticalScrollbar:b.scrollbars.ALWAYS,c.enableHorizontalScrollbar="undefined"!=typeof c.enableHorizontalScrollbar?c.enableHorizontalScrollbar:b.scrollbars.ALWAYS,c.minimumColumnSize="undefined"!=typeof c.minimumColumnSize?c.minimumColumnSize:10,c.rowEquality=c.rowEquality||function(a,b){return a===b},c.headerTemplate=c.headerTemplate||null,c.footerTemplate=c.footerTemplate||null,c.rowTemplate=c.rowTemplate||"ui-grid/ui-grid-row",c.appScopeProvider=c.appScopeProvider||null,c}}}])}(),function(){angular.module("ui.grid").factory("GridRenderContainer",["gridUtil","uiGridConstants",function(a,b){function c(a,b,c){var d=this;d.name=a,d.grid=b,d.visibleRowCache=[],d.visibleColumnCache=[],d.renderedRows=[],d.renderedColumns=[],d.prevScrollTop=0,d.prevScrolltopPercentage=0,d.prevRowScrollIndex=0,d.prevScrollLeft=0,d.prevScrollleftPercentage=0,d.prevColumnScrollIndex=0,d.columnStyles="",d.viewportAdjusters=[],d.canvasHeightShouldUpdate=!0,d.$$canvasHeight=0,c&&angular.isObject(c)&&angular.extend(d,c),b.registerStyleComputation({priority:5,func:function(){return d.columnStyles}})}return c.prototype.reset=function(){this.visibleColumnCache.length=0,this.visibleRowCache.length=0,this.renderedRows.length=0,this.renderedColumns.length=0},c.prototype.minRowsToRender=function(){for(var a=this,b=0,c=0,d=a.getViewportHeight(),e=a.visibleRowCache.length-1;d>c&&e>=0;e--)c+=a.visibleRowCache[e].height,b++;return b},c.prototype.minColumnsToRender=function(){for(var a=this,b=this.getViewportWidth(),c=0,d=0,e=0;e<a.visibleColumnCache.length;e++){var f=a.visibleColumnCache[e];if(b>d)d+=f.drawnWidth?f.drawnWidth:0,c++;else{for(var g=0,h=e;h>=e-c;h--)g+=a.visibleColumnCache[h].drawnWidth?a.visibleColumnCache[h].drawnWidth:0;b>g&&c++}}return c},c.prototype.getVisibleRowCount=function(){return this.visibleRowCache.length},c.prototype.registerViewportAdjuster=function(a){this.viewportAdjusters.push(a)},c.prototype.removeViewportAdjuster=function(a){var b=this.viewportAdjusters.indexOf(a);"undefined"!=typeof b&&void 0!==b&&this.viewportAdjusters.splice(b,1)},c.prototype.getViewportAdjustment=function(){var a=this,b={height:0,width:0};return a.viewportAdjusters.forEach(function(a){b=a.call(this,b)}),b},c.prototype.getViewportHeight=function(){var a=this,b=a.headerHeight?a.headerHeight:a.grid.headerHeight,c=a.grid.gridHeight-b-a.grid.footerHeight,d=a.getViewportAdjustment();return c+=d.height},c.prototype.getViewportWidth=function(){var a=this,b=a.grid.gridWidth,c=a.getViewportAdjustment();return b+=c.width},c.prototype.getHeaderViewportWidth=function(){var a=this.getViewportWidth();return a},c.prototype.getCanvasHeight=function(){var a=this;if(!a.canvasHeightShouldUpdate)return a.$$canvasHeight;var b=a.$$canvasHeight;return a.$$canvasHeight=0,a.visibleRowCache.forEach(function(b){a.$$canvasHeight+=b.height}),a.canvasHeightShouldUpdate=!1,a.grid.api.core.raise.canvasHeightChanged(b,a.$$canvasHeight),a.$$canvasHeight},c.prototype.getVerticalScrollLength=function(){return this.getCanvasHeight()-this.getViewportHeight()},c.prototype.getCanvasWidth=function(){var a=this,b=a.canvasWidth;return b},c.prototype.setRenderedRows=function(a){this.renderedRows.length=a.length;for(var b=0;b<a.length;b++)this.renderedRows[b]=a[b]},c.prototype.setRenderedColumns=function(a){this.renderedColumns.length=a.length;for(var b=0;b<a.length;b++)this.renderedColumns[b]=a[b];this.updateColumnOffset()},c.prototype.updateColumnOffset=function(){for(var a=0,b=0;b<this.currentFirstColumn;b++)a+=this.visibleColumnCache[b].drawnWidth;this.columnOffset=a},c.prototype.adjustScrollVertical=function(a,b,c){(this.prevScrollTop!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasHeight()-this.getCanvasWidth())*b),this.adjustRows(a,b,!1),this.prevScrollTop=a,this.prevScrolltopPercentage=b,this.grid.queueRefresh())},c.prototype.adjustScrollHorizontal=function(a,b,c){(this.prevScrollLeft!==a||c)&&(("undefined"==typeof a||void 0===a||null===a)&&(a=(this.getCanvasWidth()-this.getViewportWidth())*b),this.adjustColumns(a,b),this.prevScrollLeft=a,this.prevScrollleftPercentage=b,this.grid.queueRefresh())
    +},c.prototype.adjustRows=function(a,c,d){var e=this,f=e.minRowsToRender(),g=e.visibleRowCache,h=g.length-f;"undefined"!=typeof c&&null!==c||!a||(c=a/e.getVerticalScrollLength());var i=Math.ceil(Math.min(h,h*c));i>h&&(i=h);var j=[];if(g.length>e.grid.options.virtualizationThreshold){if("undefined"!=typeof a&&null!==a){if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop<a&&i<e.prevRowScrollIndex+e.grid.options.scrollThreshold&&h>i)return;if(!e.grid.options.enableInfiniteScroll&&e.prevScrollTop>a&&i>e.prevRowScrollIndex-e.grid.options.scrollThreshold&&h>i)return}var k={},l={};if(e.grid.options.enableInfiniteScroll&&e.grid.scrollDirection!==b.scrollDirection.NONE&&d){var m=null,n=null;if(e.grid.scrollDirection===b.scrollDirection.UP){for(m=i>0?e.grid.options.excessRows:0,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i),l=Math.min(g.length,k+e.grid.options.excessRows+f)}else if(e.grid.scrollDirection===b.scrollDirection.DOWN){for(m=f,n=0;n<g.length;n++)if(g[n].entity.$$hashKey===e.renderedRows[m].entity.$$hashKey){i=n;break}k=Math.max(0,i-e.grid.options.excessRows-f),l=Math.min(g.length,i+f+e.grid.options.excessRows)}}else k=Math.max(0,i-e.grid.options.excessRows),l=Math.min(g.length,i+f+e.grid.options.excessRows);j=[k,l]}else{var o=e.visibleRowCache.length;j=[0,Math.max(o,f+e.grid.options.excessRows)]}e.updateViewableRowRange(j),e.prevRowScrollIndex=i},c.prototype.adjustColumns=function(a,b){var c=this,d=c.minColumnsToRender(),e=c.visibleColumnCache,f=e.length-d;"undefined"!=typeof b&&null!==b||!a||(b=a/c.getCanvasWidth());var g=Math.ceil(Math.min(f,f*b));g>f&&(g=f);var h=[];if(e.length>c.grid.options.columnVirtualizationThreshold&&c.getCanvasWidth()>c.getViewportWidth()){var i=Math.max(0,g-c.grid.options.excessColumns),j=Math.min(e.length,g+d+c.grid.options.excessColumns);h=[i,j]}else{var k=c.visibleColumnCache.length;h=[0,Math.max(k,d+c.grid.options.excessColumns)]}c.updateViewableColumnRange(h),c.prevColumnScrollIndex=g},c.prototype.updateViewableRowRange=function(a){var b=this.visibleRowCache.slice(a[0],a[1]);this.currentTopRow=a[0],this.setRenderedRows(b)},c.prototype.updateViewableColumnRange=function(a){var b=this.visibleColumnCache.slice(a[0],a[1]);this.currentFirstColumn=a[0],this.setRenderedColumns(b)},c.prototype.headerCellWrapperStyle=function(){var a=this;if(0!==a.currentFirstColumn){var b=a.columnOffset;return a.grid.isRTL()?{"margin-right":b+"px"}:{"margin-left":b+"px"}}return null},c.prototype.updateColumnWidths=function(){var b,c=this,d=[],e=[],f=0,g=c.getViewportWidth()-c.grid.scrollbarWidth,h=0,i=0,j="",k=c.visibleColumnCache;k.forEach(function(b){if(b.visible){var c=!1;angular.isNumber(b.width)||(c=isNaN(b.width)&&a.endsWith(b.width,"%")),angular.isString(b.width)&&-1!==b.width.indexOf("*")?(f=parseInt(f+b.width.length,10),d.push(b)):c?e.push(b):angular.isNumber(b.width)&&(h=parseInt(h+b.width,10),i=parseInt(i,10)+parseInt(b.width,10),b.drawnWidth=b.width)}});var l,m,n,o=g-h;if(e.length>0){for(l=0;l<e.length;l++){m=e[l];var p=parseInt(m.width.replace(/%/g,""),10)/100;n=parseInt(p*o,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,i+=n,m.drawnWidth=n,e.splice(l,1))}e.forEach(function(a){var b=parseInt(a.width.replace(/%/g,""),10)/100,c=parseInt(b*o,10);i+=c,a.drawnWidth=c})}if(d.length>0){var q=parseInt(o/f,10);for(l=0;l<d.length;l++)m=d[l],n=parseInt(q*m.width.length,10),m.colDef.minWidth&&n<m.colDef.minWidth?(n=m.colDef.minWidth,o-=n,f--,i+=n,m.drawnWidth=n,b=m,d.splice(l,1)):m.colDef.maxWidth&&n>m.colDef.maxWidth&&(n=m.colDef.maxWidth,o-=n,f--,i+=n,m.drawnWidth=n,d.splice(l,1));q=parseInt(o/f,10),d.forEach(function(a){var b=parseInt(q*a.width.length,10);i+=b,a.drawnWidth=b})}var r=g-parseInt(i,10);if(r>0&&i>0&&g>i){var s=!1;if(k.forEach(function(a){a.width&&!angular.isNumber(a.width)&&(s=!0)}),s)for(var t=function(a){r>0&&(a.drawnWidth=a.drawnWidth+1,i+=1,r--)};r>0;)k.forEach(t)}g>i&&(i=g),k.forEach(function(a){j+=a.getColClassDefinition()}),c.canvasWidth=parseInt(i,10),this.columnStyles=j},c.prototype.getViewPortStyle=function(){var a=this,c={};return"body"===a.name?(c["overflow-x"]=a.grid.options.enableHorizontalScrollbar===b.scrollbars.NEVER?"hidden":"scroll",c["overflow-y"]=a.grid.isRTL()?a.grid.hasLeftContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":a.grid.hasRightContainerColumns()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"):"left"===a.name?(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll":"hidden"):(c["overflow-x"]="hidden",c["overflow-y"]=a.grid.isRTL()?"hidden":a.grid.options.enableVerticalScrollbar===b.scrollbars.NEVER?"hidden":"scroll"),c},c}])}(),function(){angular.module("ui.grid").factory("GridRow",["gridUtil",function(a){function b(b,c,d){this.grid=d,this.entity=b,this.uid=a.nextUid(),this.visible=!0,this.$$height=d.options.rowHeight}return Object.defineProperty(b.prototype,"height",{get:function(){return this.$$height},set:function(a){a!==this.$$height&&(this.grid.updateCanvasHeight(),this.$$height=a)}}),b.prototype.getQualifiedColField=function(a){return"row."+this.getEntityQualifiedColField(a)},b.prototype.getEntityQualifiedColField=function(b){return a.preEval("entity."+b.field)},b.prototype.setRowInvisible=function(a){null!==a&&(a.forceInvisible=!0,a.visible&&(a.visible=!1,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b.prototype.clearRowInvisible=function(a){null!==a&&(a.forceInvisible=!1,a.visible||(a.visible=!0,a.grid.refresh(),a.grid.api.core.raise.rowsVisibleChanged()))},b}])}(),function(){angular.module("ui.grid").factory("ScrollEvent",["gridUtil",function(a){function b(b,c,d,e){var f=this;if(!b)throw new Error("grid argument is required");f.grid=b,f.source=e,f.sourceRowContainer=c,f.sourceColContainer=d,f.newScrollLeft=null,f.newScrollTop=null,f.x=null,f.y=null,f.fireThrottledScrollingEvent=a.throttle(function(){f.grid.api.core.raise.scrollEvent(f)},f.grid.options.scrollThrottle,{trailing:!0})}return b.prototype.fireScrollingEvent=function(){this.grid.api.core.raise.scrollEvent(this)},b.prototype.getNewScrollLeft=function(b,c){var d=this;if(!d.newScrollLeft){var e,f=b.getCanvasWidth()-b.getViewportWidth(),g=a.normalizeScrollLeft(c);if("undefined"!=typeof d.x.percentage&&void 0!==d.x.percentage)e=d.x.percentage;else{if("undefined"==typeof d.x.pixels||void 0===d.x.pixels)throw new Error("No percentage or pixel value provided for scroll event X axis");e=d.x.percentage=(g+d.x.pixels)/f}return Math.max(0,e*f)}return d.newScrollLeft},b.prototype.getNewScrollTop=function(a,b){var c=this;if(!c.newScrollTop){var d,e=a.getVerticalScrollLength(),f=b[0].scrollTop;if("undefined"!=typeof c.y.percentage&&void 0!==c.y.percentage)d=c.y.percentage;else{if("undefined"==typeof c.y.pixels||void 0===c.y.pixels)throw new Error("No percentage or pixel value provided for scroll event Y axis");d=c.y.percentage=(f+c.y.pixels)/e}return Math.max(0,d*e)}return c.newScrollTop},b.Sources={ViewPortScroll:"ViewPortScroll",RenderContainerMouseWheel:"RenderContainerMouseWheel",RenderContainerTouchMove:"RenderContainerTouchMove",Other:99},b}])}(),function(){"use strict";angular.module("ui.grid").service("gridClassFactory",["gridUtil","$q","$compile","$templateCache","uiGridConstants","Grid","GridColumn","GridRow",function(a,b,c,d,e,f){var g={createGrid:function(d){d="undefined"!=typeof d?d:{},d.id=a.newId();var e=new f(d);if(e.options.rowTemplate){var h=b.defer();e.getRowTemplateFn=h.promise,a.getTemplate(e.options.rowTemplate).then(function(a){var b=c(a);h.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+e.options.rowTemplate+"'")})}return e.registerColumnBuilder(g.defaultColumnBuilder),e.registerRowBuilder(g.rowTemplateAssigner),e.registerRowsProcessor(function(a){return a.forEach(function(a){a.visible=!a.forceInvisible}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.visible=!0}),a}),e.registerColumnsProcessor(function(a){return a.forEach(function(a){a.colDef.visible===!1&&(a.visible=!1)}),a}),e.options.enableFiltering&&e.registerRowsProcessor(e.searchRows),e.registerRowsProcessor(e.options.externalSort&&angular.isFunction(e.options.externalSort)?e.options.externalSort:e.sortByColumn),e},defaultColumnBuilder:function(c,d){var f=[];return d.providedHeaderCellTemplate=c.headerCellTemplate?c.headerCellTemplate:"ui-grid/uiGridHeaderCell",d.providedCellTemplate=c.cellTemplate?c.cellTemplate:"ui-grid/uiGridCell",d.providedFooterCellTemplate=c.footerCellTemplate?c.footerCellTemplate:"ui-grid/uiGridFooterCell",d.cellTemplatePromise=a.getTemplate(d.providedCellTemplate),f.push(d.cellTemplatePromise.then(function(a){d.cellTemplate=a.replace(e.CUSTOM_FILTERS,d.cellFilter?"|"+d.cellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.cellTemplate '"+c.cellTemplate+"'")})),f.push(a.getTemplate(d.providedHeaderCellTemplate).then(function(a){d.headerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.headerCellFilter?"|"+d.headerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.headerCellTemplate '"+c.headerCellTemplate+"'")})),f.push(a.getTemplate(d.providedFooterCellTemplate).then(function(a){d.footerCellTemplate=a.replace(e.CUSTOM_FILTERS,d.footerCellFilter?"|"+d.footerCellFilter:"")},function(){throw new Error("Couldn't fetch/use colDef.footerCellTemplate '"+c.footerCellTemplate+"'")})),d.compiledElementFnDefer=b.defer(),b.all(f)},rowTemplateAssigner:function(d){var e=this;if(d.rowTemplate){var f=b.defer();d.getRowTemplateFn=f.promise,a.getTemplate(d.rowTemplate).then(function(a){var b=c(a);f.resolve(b)},function(){throw new Error("Couldn't fetch/use row template '"+d.rowTemplate+"'")})}else d.rowTemplate=e.options.rowTemplate,d.getRowTemplateFn=e.getRowTemplateFn;return d.getRowTemplateFn}};return g}])}(),function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var b=angular.module("ui.grid");b.service("rowSearcher",["gridUtil","uiGridConstants",function(b,c){var d=c.filter.STARTS_WITH,e={};return e.getTerm=function(a){if("undefined"==typeof a.term)return a.term;var b=a.term;return"string"==typeof b&&(b=b.trim()),b},e.stripTerm=function(b){var c=e.getTerm(b);return"string"==typeof c?a(c.replace(/(^\*|\*$)/g,"")):c},e.guessCondition=function(a){if("undefined"==typeof a.term||!a.term)return d;var b=e.getTerm(a);if(/\*/.test(b)){var c="";a.flags&&a.flags.caseSensitive||(c+="i");var f=b.replace(/(\\)?\*/g,function(a,b){return b?a:"[\\s\\S]*?"});return new RegExp("^"+f+"$",c)}return d},e.setupFilters=function(a){for(var b=[],d=a.length,f=0;d>f;f++){var g=a[f];if(g.noTerm||g.term){var h={},i="";g.flags&&g.flags.caseSensitive||(i+="i"),g.term&&(h.term=e.stripTerm(g)),h.condition=g.condition?g.condition:e.guessCondition(g),h.flags=angular.extend({caseSensitive:!1,date:!1},g.flags),h.condition===c.filter.STARTS_WITH&&(h.startswithRE=new RegExp("^"+h.term,i)),h.condition===c.filter.ENDS_WITH&&(h.endswithRE=new RegExp(h.term+"$",i)),h.condition===c.filter.CONTAINS&&(h.containsRE=new RegExp(h.term,i)),h.condition===c.filter.EXACT&&(h.exactRE=new RegExp("^"+h.term+"$",i)),b.push(h)}}return b},e.runColumnFilter=function(a,b,d,e){var f=typeof e.condition,g=e.term,h=a.getCellValue(b,d);if(e.condition instanceof RegExp)return e.condition.test(h);if("function"===f)return e.condition(g,h,b,d);if(e.startswithRE)return e.startswithRE.test(h);if(e.endswithRE)return e.endswithRE.test(h);if(e.containsRE)return e.containsRE.test(h);if(e.exactRE)return e.exactRE.test(h);if(e.condition===c.filter.NOT_EQUAL){var i=new RegExp("^"+g+"$");return!i.exec(h)}if("number"==typeof h){var j=parseFloat(g.replace(/\\./,"."));isNaN(j)||(g=j)}return e.flags.date===!0&&(h=new Date(h),g=new Date(g.replace(/\\/g,""))),e.condition===c.filter.GREATER_THAN?h>g:e.condition===c.filter.GREATER_THAN_OR_EQUAL?h>=g:e.condition===c.filter.LESS_THAN?g>h:e.condition===c.filter.LESS_THAN_OR_EQUAL?g>=h:!0},e.searchColumn=function(a,b,c,d){if(a.options.useExternalFiltering)return!0;for(var f=d.length,g=0;f>g;g++){var h=d[g],i=e.runColumnFilter(a,b,c,h);if(!i)return!1}return!0},e.search=function(a,b,c){if(b){for(var d=[],f=c.length,g=0;f>g;g++){var h=c[g];"undefined"!=typeof h.filters&&(h.filters.length>1||1===h.filters.length&&("undefined"!=typeof h.filters[0].term&&h.filters[0].term||h.filters[0].noTerm))?d.push({col:h,filters:e.setupFilters(h.filters)}):"undefined"!=typeof h.filter&&h.filter&&("undefined"!=typeof h.filter.term&&h.filter.term||h.filter.noTerm)&&d.push({col:h,filters:e.setupFilters([h.filter])})}if(d.length>0){for(var i=function(a,b,c,d){(b.forceInvisible||!e.searchColumn(a,b,c,d))&&(b.visible=!1)},j=function(a,c){for(var d=b.length,e=0;d>e;e++)i(a,b[e],c.col,c.filters)},k=d.length,l=0;k>l;l++)j(a,d[l]);a.api.core.raise.rowsVisibleChanged&&a.api.core.raise.rowsVisibleChanged()}return b}},e}])}(),function(){var a=angular.module("ui.grid");a.service("rowSorter",["$parse","uiGridConstants",function(a,b){var c="("+b.CURRENCY_SYMBOLS.map(function(a){return"\\"+a}).join("|")+")?",d=(new RegExp("^[-+]?"+c+"[\\d,.]+"+c+"%?$"),{colSortFnCache:[]});return d.guessSortFn=function(a){switch(a){case"number":return d.sortNumber;case"boolean":return d.sortBool;case"string":return d.sortAlpha;case"date":return d.sortDate;case"object":return d.basicSort;default:throw new Error("No sorting function found for type:"+a)}},d.handleNulls=function(a,b){if(!a&&0!==a&&a!==!1||!b&&0!==b&&b!==!1){if(!a&&0!==a&&a!==!1&&!b&&0!==b&&b!==!1)return 0;if(!a&&0!==a&&a!==!1)return 1;if(!b&&0!==b&&b!==!1)return-1}return null},d.basicSort=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a===b?0:b>a?-1:1},d.sortNumber=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a-b},d.sortNumberStr=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e,f,g=!1,h=!1;return e=parseFloat(a.replace(/[^0-9.-]/g,"")),isNaN(e)&&(g=!0),f=parseFloat(b.replace(/[^0-9.-]/g,"")),isNaN(f)&&(h=!0),g&&h?0:g?1:h?-1:e-f},d.sortAlpha=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.toString().toLowerCase(),f=b.toString().toLowerCase();return e===f?0:f>e?-1:1},d.sortDate=function(a,b){var c=d.handleNulls(a,b);if(null!==c)return c;var e=a.getTime(),f=b.getTime();return e===f?0:f>e?-1:1},d.sortBool=function(a,b){var c=d.handleNulls(a,b);return null!==c?c:a&&b?0:a||b?a?1:-1:0},d.getSortFn=function(a,b){var c;return d.colSortFnCache[b.colDef.name]?c=d.colSortFnCache[b.colDef.name]:void 0!==b.sortingAlgorithm?(c=b.sortingAlgorithm,d.colSortFnCache[b.colDef.name]=b.sortingAlgorithm):(c=d.guessSortFn(b.colDef.type),c?d.colSortFnCache[b.colDef.name]=c:c=d.sortAlpha),c},d.prioritySort=function(a,b){return void 0!==a.sort.priority&&void 0!==b.sort.priority?a.sort.priority<b.sort.priority?-1:a.sort.priority===b.sort.priority?0:1:a.sort.priority||0===a.sort.priority?-1:b.sort.priority||0===b.sort.priority?1:0},d.sort=function(a,c,e){if(c){if(a.options.useExternalSorting)return c;var f=[];if(e.forEach(function(a){a.sort&&a.sort.direction&&(a.sort.direction===b.ASC||a.sort.direction===b.DESC)&&f.push(a)}),f=f.sort(d.prioritySort),0===f.length)return c;var g,h,i=c.slice(0);angular.forEach(c,function(a,b){a.entity.$uiGridIndex=b});var j=c.sort(function(c,e){for(var j,k=0,l=0;0===k&&l<f.length;){g=f[l],h=f[l].sort.direction,j=d.getSortFn(a,g,i);var m=a.getCellValue(c,g),n=a.getCellValue(e,g);k=j(m,n),l++}return 0===k?c.entity.$uiGridIndex-e.entity.$uiGridIndex:h===b.ASC?k:0-k});return angular.forEach(j,function(a){delete a.entity.$uiGridIndex}),j}},d}])}(),function(){function a(a){var b=a;return"undefined"!=typeof b.length&&b.length&&(b=a[0]),b.ownerDocument.defaultView.getComputedStyle(b,null)}function b(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0,h=["Top","Right","Bottom","Left"];4>f;f+=2){var i=h[f];if("margin"===c){var j=parseFloat(e[c+i]);isNaN(j)||(g+=j)}if(d){if("content"===c){var k=parseFloat(e["padding"+i]);isNaN(k)||(g-=k)}if("margin"!==c){var l=parseFloat(e["border"+i+"Width"]);isNaN(l)||(g-=l)}}else{var m=parseFloat(e["padding"+i]);if(isNaN(m)||(g+=m),"padding"!==c){var n=parseFloat(e["border"+i+"Width"]);isNaN(n)||(g+=n)}}}return g}function c(c,d,e){var f,h=!0,i=a(c),j="border-box"===i.boxSizing;if(0>=f||null==f){if(f=i[d],(0>f||null==f)&&(f=c.style[d]),g.test(f))return f;h=j&&!0,f=parseFloat(f)||0}var k=f+b(c,d,e||(j?"border":"content"),h,i);return k}function d(b){b=angular.element(b)[0];var c=b.offsetParent;return c||(c=document.getElementsByTagName("body")[0]),parseInt(a(c).fontSize)||parseInt(a(b).fontSize)||16}var e,f=angular.module("ui.grid");"function"!=typeof Function.prototype.bind&&(e=function(){var a=Array.prototype.slice;return function(b){var c=this,d=a.call(arguments,1);return d.length?function(){return arguments.length?c.apply(b,d.concat(a.call(arguments))):c.apply(b,d)}:function(){return arguments.length?c.apply(b,arguments):c.call(b)}}});var g=new RegExp("^("+/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source+")(?!px)[a-z%]+$","i"),h=/^(block|none|table(?!-c[ea]).+)/,i={position:"absolute",visibility:"hidden",display:"block"},j=["0","0","0"],k="uiGrid-";f.service("gridUtil",["$log","$window","$document","$http","$templateCache","$timeout","$injector","$q","$interpolate","uiGridConstants",function(b,f,g,l,m,n,o,p,q,r){function s(a,b){var c=angular.element(this),d=0,e=0,f=0,g=0;if(b.originalEvent&&(b=b.originalEvent),"detail"in b&&(f=-1*b.detail),"wheelDelta"in b&&(f=b.wheelDelta),"wheelDeltaY"in b&&(f=b.wheelDeltaY),"wheelDeltaX"in b&&(e=-1*b.wheelDeltaX),"axis"in b&&b.axis===b.HORIZONTAL_AXIS&&(e=-1*f,f=0),d=0===f?e:f,"deltaY"in b&&(f=-1*b.deltaY,d=f),"deltaX"in b&&(e=b.deltaX,0===f&&(d=-1*e)),0!==f||0!==e){if(1===b.deltaMode){var h=c.data("mousewheel-line-height");d*=h,f*=h,e*=h}else if(2===b.deltaMode){var i=c.data("mousewheel-page-height");d*=i,f*=i,e*=i}g=Math.max(Math.abs(f),Math.abs(e)),(!x||x>g)&&(x=g,u(b,g)&&(x/=40)),d=Math[d>=1?"floor":"ceil"](d/x),e=Math[e>=1?"floor":"ceil"](e/x),f=Math[f>=1?"floor":"ceil"](f/x),b.deltaMode=0;var j={originalEvent:b,deltaX:e,deltaY:f,deltaFactor:x,preventDefault:function(){b.preventDefault()}};w&&clearTimeout(w),w=setTimeout(t,200),a.call(c[0],j)}}function t(){x=null}function u(a,b){return"mousewheel"===a.type&&b%120===0}var v={getStyles:a,createBoundedWrapper:function(a,b){return function(){return b.apply(a,arguments)}},readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(a,b){var c=[];if(!a||"undefined"==typeof a[0]||void 0===a[0])return[];angular.isUndefined(b)&&(b=[]);var d=a[0];return angular.forEach(d,function(a,d){-1===b.indexOf(d)&&c.push({name:d})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}(),getTemplate:function(a){if(m.get(a))return v.postProcessTemplate(m.get(a));if(a.hasOwnProperty("then"))return a.then(v.postProcessTemplate);try{if(angular.element(a).length>0)return p.when(a).then(v.postProcessTemplate)}catch(b){}return v.logDebug("fetching url",a),l({method:"GET",url:a}).then(function(b){var c=b.data.trim();return m.put(a,c),c},function(b){throw new Error("Could not get template "+a+": "+b)}).then(v.postProcessTemplate)},postProcessTemplate:function(a){var b=q.startSymbol(),c=q.endSymbol();return("{{"!==b||"}}"!==c)&&(a=a.replace(/\{\{/g,b),a=a.replace(/\}\}/g,c)),p.when(a)},guessType:function(a){var b=typeof a;switch(b){case"number":case"boolean":case"string":return b;default:return angular.isDate(a)?"date":"object"}},elementWidth:function(){},elementHeight:function(){},getScrollbarWidth:function(){var a=document.createElement("div");a.style.visibility="hidden",a.style.width="100px",a.style.msOverflowStyle="scrollbar",document.body.appendChild(a);var b=a.offsetWidth;a.style.overflow="scroll";var c=document.createElement("div");c.style.width="100%",a.appendChild(c);var d=c.offsetWidth;return a.parentNode.removeChild(a),b-d},swap:function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},fakeElement:function(a,b,c){var d,e,f=angular.element(a).clone()[0];for(e in b)f.style[e]=b[e];return angular.element(document.body).append(f),d=c.call(f,f),angular.element(f).remove(),d},normalizeWheelEvent:function(a){var b,c,d,e=a||window.event,f=([].slice.call(arguments,1),0),g=0,h=0,i=0,j=0;return e.originalEvent&&(e=e.originalEvent),e.wheelDelta&&(f=e.wheelDelta),e.detail&&(f=-1*e.detail),h=f,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(h=0,g=-1*f),e.deltaY&&(h=-1*e.deltaY,f=h),e.deltaX&&(g=e.deltaX,f=-1*g),void 0!==e.wheelDeltaY&&(h=e.wheelDeltaY),void 0!==e.wheelDeltaX&&(g=e.wheelDeltaX),i=Math.abs(f),(!b||b>i)&&(b=i),j=Math.max(Math.abs(h),Math.abs(g)),(!c||c>j)&&(c=j),d=f>0?"floor":"ceil",f=Math[d](f/b),g=Math[d](g/c),h=Math[d](h/c),{delta:f,deltaX:g,deltaY:h}},isTouchEnabled:function(){var a;return("ontouchstart"in f||f.DocumentTouch&&g instanceof DocumentTouch)&&(a=!0),a},isNullOrUndefined:function(a){return void 0===a||null===a?!0:!1},endsWith:function(a,b){return a&&b&&"string"==typeof a?-1!==a.indexOf(b,a.length-b.length):!1},arrayContainsObjectWithProperty:function(a,b,c){var d=!1;return angular.forEach(a,function(a){a[b]===c&&(d=!0)}),d},requestAnimationFrame:f.requestAnimationFrame&&f.requestAnimationFrame.bind(f)||f.webkitRequestAnimationFrame&&f.webkitRequestAnimationFrame.bind(f)||function(a){return n(a,10,!1)},numericAndNullSort:function(a,b){return null===a?1:null===b?-1:null===a&&null===b?0:a-b},disableAnimations:function(a){var b;try{b=o.get("$animate"),b.enabled(!1,a)}catch(c){}},enableAnimations:function(a){var b;try{return b=o.get("$animate"),b.enabled(!0,a),b}catch(c){}},nextUid:function(){for(var a,b=j.length;b;){if(b--,a=j[b].charCodeAt(0),57===a)return j[b]="A",k+j.join("");if(90!==a)return j[b]=String.fromCharCode(a+1),k+j.join("");j[b]="0"}return j.unshift("0"),k+j.join("")},hashKey:function(a){var b,c=typeof a;return"object"===c&&null!==a?"function"==typeof(b=a.$$hashKey)?b=a.$$hashKey():"undefined"!=typeof a.$$hashKey&&a.$$hashKey?b=a.$$hashKey:void 0===b&&(b=a.$$hashKey=v.nextUid()):b=a,c+":"+b},resetUids:function(){j=["0","0","0"]},logError:function(a){r.LOG_ERROR_MESSAGES&&b.error(a)},logWarn:function(a){r.LOG_WARN_MESSAGES&&b.warn(a)},logDebug:function(){r.LOG_DEBUG_MESSAGES&&b.debug.apply(b,arguments)}};["width","height"].forEach(function(b){var d=angular.uppercase(b.charAt(0))+b.substr(1);v["element"+d]=function(d,e){var f=d;if(f&&"undefined"!=typeof f.length&&f.length&&(f=d[0]),f){var g=a(f);return 0===f.offsetWidth&&h.test(g.display)?v.fakeElement(f,i,function(a){return c(a,b,e)}):c(f,b,e)}return null},v["outerElement"+d]=function(a,b){return a?v["element"+d].call(this,a,b?"margin":"border"):null}}),v.closestElm=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c;["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].some(function(a){return"function"==typeof document.body[a]?(c=a,!0):!1});for(var d;null!==a;){if(d=a.parentElement,null!==d&&d[c](b))return d;a=d}return null},v.type=function(a){var b=Function.prototype.toString.call(a.constructor);return b.match(/function (.*?)\(/)[1]},v.getBorderSize=function(b,c){"undefined"!=typeof b.length&&b.length&&(b=b[0]);var d=a(b);c=c?"border"+c.charAt(0).toUpperCase()+c.slice(1):"border",c+="Width";var e=parseInt(d[c],10);return isNaN(e)?0:e},v.detectBrowser=function(){var a=f.navigator.userAgent,b={chrome:/chrome/i,safari:/safari/i,firefox:/firefox/i,ie:/internet explorer|trident\//i};for(var c in b)if(b[c].test(a))return c;return"unknown"},v.normalizeScrollLeft=function(a){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var b=v.detectBrowser(),c=a.scrollLeft,d=v.getStyles(a).direction;if("ie"===b)return c;if("chrome"===b){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-c}return c}return"firefox"===b?Math.abs(c):c},v.denormalizeScrollLeft=function(a,b){"undefined"!=typeof a.length&&a.length&&(a=a[0]);var c=v.detectBrowser(),d=v.getStyles(a).direction;if("ie"===c)return b;if("chrome"===c){if("rtl"===d){var e=a.scrollWidth-a.clientWidth;return e-b}return b}return"firefox"===c&&"rtl"===d?-1*b:b},v.preEval=function(a){var b=r.BRACKET_REGEXP.exec(a);if(b)return(b[1]?v.preEval(b[1]):b[1])+b[2]+(b[3]?v.preEval(b[3]):b[3]);a=a.replace(r.APOS_REGEXP,"\\'");var c=a.split(r.DOT_REGEXP),d=[c.shift()];return angular.forEach(c,function(a){d.push(a.replace(r.FUNC_REGEXP,"']$1"))}),d.join("['")},v.debounce=function(a,b,c){function d(){g=this,f=arguments;var d=function(){e=null,c||(h=a.apply(g,f))},i=c&&!e;return e&&n.cancel(e),e=n(d,b),i&&(h=a.apply(g,f)),h}var e,f,g,h;return d.cancel=function(){n.cancel(e),e=null},d},v.throttle=function(a,b,c){function d(){g=+new Date,a.apply(e,f),n(function(){h=null},0)}c=c||{};var e,f,g=0,h=null;return function(){if(e=this,f=arguments,null===h){var a=+new Date-g;a>b?d():c.trailing&&(h=n(d,b-a))}}},v.on={},v.off={},v._events={},v.addOff=function(a){v.off[a]=function(b,c){var d=v._events[a].indexOf(c);d>0&&v._events[a].removeAt(d)}};var w,x,y="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"];return v.on.mousewheel=function(a,b){if(a&&b){var c=angular.element(a);c.data("mousewheel-line-height",d(c)),c.data("mousewheel-page-height",v.elementHeight(c)),c.data("mousewheel-callbacks")||c.data("mousewheel-callbacks",{});var f=c.data("mousewheel-callbacks");f[b]=(Function.prototype.bind||e).call(s,c[0],b);for(var g=y.length;g;)c.on(y[--g],f[b])}},v.off.mousewheel=function(a,b){var c=angular.element(this),d=c.data("mousewheel-callbacks"),e=d[b];if(e)for(var f=y.length;f;)c.off(y[--f],e);delete d[b],0===Object.keys(d).length&&(c.removeData("mousewheel-line-height"),c.removeData("mousewheel-page-height"),c.removeData("mousewheel-callbacks"))},v}]),f.filter("px",function(){return function(a){return a.match(/^[\d\.]+$/)?a+"px":a}})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("da",{aggregate:{label:"artikler"},groupPanel:{description:"Grupér rækker udfra en kolonne ved at trække dens overskift hertil."},search:{placeholder:"Søg...",showingItems:"Viste rækker:",selectedItems:"Valgte rækker:",totalItems:"Rækker totalt:",size:"Side størrelse:",first:"Første side",next:"Næste side",previous:"Forrige side",last:"Sidste side"},menu:{text:"Vælg kolonner:"},column:{hide:"Skjul kolonne"},aggregation:{count:"samlede rækker: ",sum:"smalede: ",avg:"gns: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("de",{aggregate:{label:"Eintrag"},groupPanel:{description:"Ziehen Sie eine Spaltenüberschrift hierhin, um nach dieser Spalte zu gruppieren."},search:{placeholder:"Suche...",showingItems:"Zeige Einträge:",selectedItems:"Ausgewählte Einträge:",totalItems:"Einträge gesamt:",size:"Einträge pro Seite:",first:"Erste Seite",next:"Nächste Seite",previous:"Vorherige Seite",last:"Letzte Seite"},menu:{text:"Spalten auswählen:"},sort:{ascending:"aufsteigend sortieren",descending:"absteigend sortieren",remove:"Sortierung zurücksetzen"},column:{hide:"Spalte ausblenden"},aggregation:{count:"Zeilen insgesamt: ",sum:"gesamt: ",avg:"Durchschnitt: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Links anheften",pinRight:"Rechts anheften",unpin:"Lösen"},gridMenu:{columns:"Spalten:",importerTitle:"Datei importieren",exporterAllAsCsv:"Alle Daten als CSV exportieren",exporterVisibleAsCsv:"sichtbare Daten als CSV exportieren",exporterSelectedAsCsv:"markierte Daten als CSV exportieren",exporterAllAsPdf:"Alle Daten als PDF exportieren",exporterVisibleAsPdf:"sichtbare Daten als PDF exportieren",exporterSelectedAsPdf:"markierte Daten als CSV exportieren"},importer:{noHeaders:"Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?",noObjects:"Es konnten keine Zeileninformationen gelesen werden, Sind in der Datei außer den Spaltendefinitionen auch Daten enthalten?",invalidCsv:"Die Datei konnte nicht eingelesen werden, ist es eine gültige CSV-Datei?",invalidJson:"Die Datei konnte nicht eingelesen werden. Enthält sie gültiges JSON?",jsonNotArray:"Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab."},pagination:{sizes:"Einträge pro Seite",totalItems:"Einträge"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("en",{aggregate:{label:"items"},groupPanel:{description:"Drag a column header here and drop it to group by that column."},search:{placeholder:"Search...",showingItems:"Showing Items:",selectedItems:"Selected Items:",totalItems:"Total Items:",size:"Page Size:",first:"First Page",next:"Next Page",previous:"Previous Page",last:"Last Page"},menu:{text:"Choose Columns:"},sort:{ascending:"Sort Ascending",descending:"Sort Descending",remove:"Remove Sort"},column:{hide:"Hide Column"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Pin Left",pinRight:"Pin Right",unpin:"Unpin"},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."},pagination:{sizes:"items per page",totalItems:"items"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("es",{aggregate:{label:"Artículos"},groupPanel:{description:"Arrastre un encabezado de columna aquí y suéltelo para agrupar por esa columna."},search:{placeholder:"Buscar...",showingItems:"Artículos Mostrados:",selectedItems:"Artículos Seleccionados:",totalItems:"Artículos Totales:",size:"Tamaño de Página:",first:"Primera Página",next:"Página Siguiente",previous:"Página Anterior",last:"Última Página"},menu:{text:"Elegir columnas:"},sort:{ascending:"Orden Ascendente",descending:"Orden Descendente",remove:"Sin Ordenar"},column:{hide:"Ocultar la columna"},aggregation:{count:"filas totales: ",sum:"total: ",avg:"media: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fijar a la Izquierda",pinRight:"Fijar a la Derecha",unpin:"Quitar Fijación"},gridMenu:{columns:"Columnas:",importerTitle:"Importar archivo",exporterAllAsCsv:"Exportar todo como csv",exporterVisibleAsCsv:"Exportar vista como csv",exporterSelectedAsCsv:"Exportar selección como csv",exporterAllAsPdf:"Exportar todo como pdf",exporterVisibleAsPdf:"Exportar vista como pdf",exporterSelectedAsPdf:"Exportar selección como pdf"},importer:{noHeaders:"No fue posible derivar los nombres de las columnas, ¿tiene encabezados el archivo?",noObjects:"No fue posible obtener registros, ¿contiene datos el archivo, aparte de los encabezados?",invalidCsv:"No fue posible procesar el archivo, ¿es un CSV válido?",invalidJson:"No fue posible procesar el archivo, ¿es un Json válido?",jsonNotArray:"El archivo json importado debe contener un array, abortando."}}),a
    +}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fa",{aggregate:{label:"موردها"},groupPanel:{description:"یک عنوان ستون اینجا را بردار و به گروهی از آن ستون بیانداز."},search:{placeholder:"جستجو...",showingItems:"نمایش موردها:",selectedItems:"موردهای انتخاب‌شده:",totalItems:"همهٔ موردها:",size:"اندازهٔ صفحه:",first:"صفحهٔ اول",next:"صفحهٔ بعد",previous:"صفحهٔ قبل",last:"آخرین صفحه"},menu:{text:"انتخاب ستون‌ها:"},column:{hide:"ستون پنهان کن"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fi",{aggregate:{label:"rivit"},groupPanel:{description:"Raahaa ja pudota otsikko tähän ryhmittääksesi sarakkeen mukaan."},search:{placeholder:"Hae...",showingItems:"Näytetään rivejä:",selectedItems:"Valitut rivit:",totalItems:"Rivejä yht.:",size:"Näytä:",first:"Ensimmäinen sivu",next:"Seuraava sivu",previous:"Edellinen sivu",last:"Viimeinen sivu"},menu:{text:"Valitse sarakkeet:"},sort:{ascending:"Järjestä nouseva",descending:"Järjestä laskeva",remove:"Poista järjestys"},column:{hide:"Piilota sarake"},aggregation:{count:"Rivejä yht.: ",sum:"Summa: ",avg:"K.a.: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Lukitse vasemmalle",pinRight:"Lukitse oikealle",unpin:"Poista lukitus"},gridMenu:{columns:"Sarakkeet:",importerTitle:"Tuo tiedosto",exporterAllAsCsv:"Vie tiedot csv-muodossa",exporterVisibleAsCsv:"Vie näkyvä tieto csv-muodossa",exporterSelectedAsCsv:"Vie valittu tieto csv-muodossa",exporterAllAsPdf:"Vie tiedot pdf-muodossa",exporterVisibleAsPdf:"Vie näkyvä tieto pdf-muodossa",exporterSelectedAsPdf:"Vie valittu tieto pdf-muodossa"},importer:{noHeaders:"Sarakkeen nimiä ei voitu päätellä, onko tiedostossa otsikkoriviä?",noObjects:"Tietoja ei voitu lukea, onko tiedostossa muuta kuin otsikkot?",invalidCsv:"Tiedostoa ei voitu käsitellä, oliko se CSV-muodossa?",invalidJson:"Tiedostoa ei voitu käsitellä, oliko se JSON-muodossa?",jsonNotArray:"Tiedosto ei sisältänyt taulukkoa, lopetetaan."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("fr",{aggregate:{label:"articles"},groupPanel:{description:"Faites glisser un en-tête de colonne ici et déposez-le vers un groupe par cette colonne."},search:{placeholder:"Recherche...",showingItems:"Articles Affichage des:",selectedItems:"Éléments Articles:",totalItems:"Nombre total d'articles:",size:"Taille de page:",first:"Première page",next:"Page Suivante",previous:"Page précédente",last:"Dernière page"},menu:{text:"Choisir des colonnes:"},sort:{ascending:"Trier par ordre croissant",descending:"Trier par ordre décroissant",remove:"Enlever le tri"},column:{hide:"Cacher la colonne"},aggregation:{count:"total lignes: ",sum:"total: ",avg:"moy: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Épingler à gauche",pinRight:"Épingler à droite",unpin:"Détacher"},gridMenu:{columns:"Colonnes:",importerTitle:"Importer un fichier",exporterAllAsCsv:"Exporter toutes les données en CSV",exporterVisibleAsCsv:"Exporter les données visibles en CSV",exporterSelectedAsCsv:"Exporter les données sélectionnées en CSV",exporterAllAsPdf:"Exporter toutes les données en PDF",exporterVisibleAsPdf:"Exporter les données visibles en PDF",exporterSelectedAsPdf:"Exporter les données sélectionnées en PDF"},importer:{noHeaders:"Impossible de déterminer le nom des colonnes, le fichier possède-t-il un en-tête ?",noObjects:"Aucun objet trouvé, le fichier possède-t-il des données autres que l'en-tête ?",invalidCsv:"Le fichier n'a pas pu être traité, le CSV est-il valide ?",invalidJson:"Le fichier n'a pas pu être traité, le JSON est-il valide ?",jsonNotArray:"Le fichier JSON importé doit contenir un tableau. Abandon."},pagination:{sizes:"articles par page",totalItems:"articles"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("he",{aggregate:{label:"items"},groupPanel:{description:"גרור עמודה לכאן ושחרר בכדי לקבץ עמודה זו."},search:{placeholder:"חפש...",showingItems:"מציג:",selectedItems:'סה"כ נבחרו:',totalItems:'סה"כ רשומות:',size:"תוצאות בדף:",first:"דף ראשון",next:"דף הבא",previous:"דף קודם",last:"דף אחרון"},menu:{text:"בחר עמודות:"},sort:{ascending:"סדר עולה",descending:"סדר יורד",remove:"בטל"},column:{hide:"טור הסתר"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("hy",{aggregate:{label:"տվյալներ"},groupPanel:{description:"Ըստ սյան խմբավորելու համար քաշեք և գցեք վերնագիրն այստեղ։"},search:{placeholder:"Փնտրում...",showingItems:"Ցուցադրված տվյալներ՝",selectedItems:"Ընտրված:",totalItems:"Ընդամենը՝",size:"Տողերի քանակը էջում՝",first:"Առաջին էջ",next:"Հաջորդ էջ",previous:"Նախորդ էջ",last:"Վերջին էջ"},menu:{text:"Ընտրել սյուները:"},sort:{ascending:"Աճման կարգով",descending:"Նվազման կարգով",remove:"Հանել "},column:{hide:"Թաքցնել սյունը"},aggregation:{count:"ընդամենը տող՝ ",sum:"ընդամենը՝ ",avg:"միջին՝ ",min:"մին՝ ",max:"մաքս՝ "},pinning:{pinLeft:"Կպցնել ձախ կողմում",pinRight:"Կպցնել աջ կողմում",unpin:"Արձակել"},gridMenu:{columns:"Սյուներ:",importerTitle:"Ներմուծել ֆայլ",exporterAllAsCsv:"Արտահանել ամբողջը CSV",exporterVisibleAsCsv:"Արտահանել երևացող տվյալները CSV",exporterSelectedAsCsv:"Արտահանել ընտրված տվյալները CSV",exporterAllAsPdf:"Արտահանել PDF",exporterVisibleAsPdf:"Արտահանել երևացող տվյալները PDF",exporterSelectedAsPdf:"Արտահանել ընտրված տվյալները PDF"},importer:{noHeaders:"Հնարավոր չեղավ որոշել սյան վերնագրերը։ Արդյո՞ք ֆայլը ունի վերնագրեր։",noObjects:"Հնարավոր չեղավ կարդալ տվյալները։ Արդյո՞ք ֆայլում կան տվյալներ։",invalidCsv:"Հնարավոր չեղավ մշակել ֆայլը։ Արդյո՞ք այն վավեր CSV է։",invalidJson:"Հնարավոր չեղավ մշակել ֆայլը։ Արդյո՞ք այն վավեր Json է։",jsonNotArray:"Ներմուծված json ֆայլը պետք է պարունակի զանգված, կասեցվում է։"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("it",{aggregate:{label:"elementi"},groupPanel:{description:"Trascina un'intestazione all'interno del gruppo della colonna."},search:{placeholder:"Ricerca...",showingItems:"Mostra:",selectedItems:"Selezionati:",totalItems:"Totali:",size:"Tot Pagine:",first:"Prima",next:"Prossima",previous:"Precedente",last:"Ultima"},menu:{text:"Scegli le colonne:"},sort:{ascending:"Asc.",descending:"Desc.",remove:"Annulla ordinamento"},column:{hide:"Nascondi"},aggregation:{count:"righe totali: ",sum:"tot: ",avg:"media: ",min:"minimo: ",max:"massimo: "},pinning:{pinLeft:"Blocca a sx",pinRight:"Blocca a dx",unpin:"Blocca in alto"},gridMenu:{columns:"Colonne:",importerTitle:"Importa",exporterAllAsCsv:"Esporta tutti i dati in CSV",exporterVisibleAsCsv:"Esporta i dati visibili in CSV",exporterSelectedAsCsv:"Esporta i dati selezionati in CSV",exporterAllAsPdf:"Esporta tutti i dati in PDF",exporterVisibleAsPdf:"Esporta i dati visibili in PDF",exporterSelectedAsPdf:"Esporta i dati selezionati in PDF"},importer:{noHeaders:"Impossibile reperire i nomi delle colonne, sicuro che siano indicati all'interno del file?",noObjects:"Impossibile reperire gli oggetti, sicuro che siano indicati all'interno del file?",invalidCsv:"Impossibile elaborare il file, sicuro che sia un CSV?",invalidJson:"Impossibile elaborare il file, sicuro che sia un JSON valido?",jsonNotArray:"Errore! Il file JSON da importare deve contenere un array."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ja",{aggregate:{label:"件"},groupPanel:{description:"列名部分をここにドラッグアンドドロップすることで列ごとにグループ分けを行うことができます。"},search:{placeholder:"検索...",showingItems:"絞込み件数:",selectedItems:"選択件数:",totalItems:"全件数:",size:"ページサイズ: ",first:"最初のページ",next:"次のページ",previous:"前のページ",last:"最後のページ"},menu:{text:"列選択:"},sort:{ascending:"昇順ソート",descending:"降順ソート",remove:"ソート取消"},column:{hide:"列を隠す"},aggregation:{count:"合計件数: ",sum:"合計: ",avg:"平均: ",min:"最小値: ",max:"最大値: "},pinning:{pinLeft:"左にピン留め",pinRight:"右にピン留め",unpin:"ピン留め取消"},gridMenu:{columns:"列:",importerTitle:"インポートファイル",exporterAllAsCsv:"全てのデータをCSV形式でエクスポート",exporterVisibleAsCsv:"絞込み済みデータをCSV形式でエクスポート",exporterSelectedAsCsv:"選択しているデータをCSV形式でエクスポート",exporterAllAsPdf:"全てのデータをPDFでエクスポート",exporterVisibleAsPdf:"絞込み済みデータをPDFでエクスポート",exporterSelectedAsPdf:"選択しているデータをPDFでエクスポート"},importer:{noHeaders:"列名が抽出できません。ヘッダーは設定されていますか?",noObjects:"データが抽出できません。ファイルにデータは含まれていますか?",invalidCsv:"処理を行うことができません。ファイルは有効なCSVファイルですか?",invalidJson:"処理を行うことができません。ファイルは有効なJSONファイルですか?",jsonNotArray:"JSONファイルは配列を含んでいる必要があります。処理を中断します。"},pagination:{sizes:"件 / ページ",totalItems:"件"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ko",{aggregate:{label:"아이템"},groupPanel:{description:"컬럼으로 그룹핑하기 위해서는 컬럼 헤더를 끌어 떨어뜨려 주세요."},search:{placeholder:"검색...",showingItems:"항목 보여주기:",selectedItems:"선택 항목:",totalItems:"전체 항목:",size:"페이지 크기:",first:"첫번째 페이지",next:"다음 페이지",previous:"이전 페이지",last:"마지막 페이지"},menu:{text:"컬럼을 선택하세요:"},sort:{ascending:"오름차순 정렬",descending:"내림차순 정렬",remove:"소팅 제거"},column:{hide:"컬럼 제거"},aggregation:{count:"전체 갯수: ",sum:"전체: ",avg:"평균: ",min:"최소: ",max:"최대: "},pinning:{pinLeft:"왼쪽 핀",pinRight:"오른쪽 핀",unpin:"핀 제거"},gridMenu:{columns:"컬럼:",importerTitle:"파일 가져오기",exporterAllAsCsv:"csv로 모든 데이터 내보내기",exporterVisibleAsCsv:"csv로 보이는 데이터 내보내기",exporterSelectedAsCsv:"csv로 선택된 데이터 내보내기",exporterAllAsPdf:"pdf로 모든 데이터 내보내기",exporterVisibleAsPdf:"pdf로 보이는 데이터 내보내기",exporterSelectedAsPdf:"pdf로 선택 데이터 내보내기"},importer:{noHeaders:"컬럼명이 지정되어 있지 않습니다. 파일에 헤더가 명시되어 있는지 확인해 주세요.",noObjects:"데이터가 지정되어 있지 않습니다. 데이터가 파일에 있는지 확인해 주세요.",invalidCsv:"파일을 처리할 수 없습니다. 올바른 csv인지 확인해 주세요.",invalidJson:"파일을 처리할 수 없습니다. 올바른 json인지 확인해 주세요.",jsonNotArray:"json 파일은 배열을 포함해야 합니다."},pagination:{sizes:"페이지당 항목",totalItems:"전체 항목"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("nl",{aggregate:{label:"items"},groupPanel:{description:"Sleep hier een kolomnaam heen om op te groeperen."},search:{placeholder:"Zoeken...",showingItems:"Getoonde items:",selectedItems:"Geselecteerde items:",totalItems:"Totaal aantal items:",size:"Items per pagina:",first:"Eerste pagina",next:"Volgende pagina",previous:"Vorige pagina",last:"Laatste pagina"},menu:{text:"Kies kolommen:"},sort:{ascending:"Sorteer oplopend",descending:"Sorteer aflopend",remove:"Verwijder sortering"},column:{hide:"Verberg kolom"},aggregation:{count:"Aantal rijen: ",sum:"Som: ",avg:"Gemiddelde: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Zet links vast",pinRight:"Zet rechts vast",unpin:"Maak los"},gridMenu:{columns:"Kolommen:",importerTitle:"Importeer bestand",exporterAllAsCsv:"Exporteer alle data als csv",exporterVisibleAsCsv:"Exporteer zichtbare data als csv",exporterSelectedAsCsv:"Exporteer geselecteerde data als csv",exporterAllAsPdf:"Exporteer alle data als pdf",exporterVisibleAsPdf:"Exporteer zichtbare data als pdf",exporterSelectedAsPdf:"Exporteer geselecteerde data als pdf"},importer:{noHeaders:"Kolomnamen kunnen niet worden afgeleid. Heeft het bestand een header?",noObjects:"Objecten kunnen niet worden afgeleid. Bevat het bestand data naast de headers?",invalidCsv:"Het bestand kan niet verwerkt worden. Is het een valide csv bestand?",invalidJson:"Het bestand kan niet verwerkt worden. Is het valide json?",jsonNotArray:"Het json bestand moet een array bevatten. De actie wordt geannuleerd."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("pt-br",{aggregate:{label:"itens"},groupPanel:{description:"Arraste e solte uma coluna aqui para agrupar por essa coluna"},search:{placeholder:"Procurar...",showingItems:"Mostrando os Itens:",selectedItems:"Items Selecionados:",totalItems:"Total de Itens:",size:"Tamanho da Página:",first:"Primeira Página",next:"Próxima Página",previous:"Página Anterior",last:"Última Página"},menu:{text:"Selecione as colunas:"},sort:{ascending:"Ordenar Ascendente",descending:"Ordenar Descendente",remove:"Remover Ordenação"},column:{hide:"Esconder coluna"},aggregation:{count:"total de linhas: ",sum:"total: ",avg:"med: ",min:"min: ",max:"max: "},pinning:{pinLeft:"Fixar Esquerda",pinRight:"Fixar Direita",unpin:"Desprender"},gridMenu:{columns:"Colunas:",exporterAllAsCsv:"Exportar todos os dados como csv",exporterVisibleAsCsv:"Exportar dados visíveis como csv",exporterSelectedAsCsv:"Exportar dados selecionados como csv",exporterAllAsPdf:"Exportar todos os dados como pdf",exporterVisibleAsPdf:"Exportar dados visíveis como pdf",exporterSelectedAsPdf:"Exportar dados selecionados como pdf"},importer:{noHeaders:"Nomes de colunas não puderam ser derivados. O arquivo tem um cabeçalho?",noObjects:"Objetos não puderam ser derivados. Havia dados no arquivo, além dos cabeçalhos?",invalidCsv:"Arquivo não pode ser processado. É um CSV válido?",invalidJson:"Arquivo não pode ser processado. É um Json válido?",jsonNotArray:"Arquivo json importado tem que conter um array. Abortando."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("ru",{aggregate:{label:"элементы"},groupPanel:{description:"Для группировки по столбцу перетащите сюда его название."},search:{placeholder:"Поиск...",showingItems:"Показать элементы:",selectedItems:"Выбранные элементы:",totalItems:"Всего элементов:",size:"Размер страницы:",first:"Первая страница",next:"Следующая страница",previous:"Предыдущая страница",last:"Последняя страница"},menu:{text:"Выбрать столбцы:"},sort:{ascending:"По возрастанию",descending:"По убыванию",remove:"Убрать сортировку"},column:{hide:"спрятать столбец"},aggregation:{count:"всего строк: ",sum:"итого: ",avg:"среднее: ",min:"мин: ",max:"макс: "},gridMenu:{columns:"Столбцы:",importerTitle:"Import file",exporterAllAsCsv:"Экспортировать всё в CSV",exporterVisibleAsCsv:"Экспортировать видимые данные в CSV",exporterSelectedAsCsv:"Экспортировать выбранные данные в CSV",exporterAllAsPdf:"Экспортировать всё в PDF",exporterVisibleAsPdf:"Экспортировать видимые данные в PDF",exporterSelectedAsPdf:"Экспортировать выбранные данные в PDF"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sk",{aggregate:{label:"items"},groupPanel:{description:"Pretiahni sem názov stĺpca pre zoskupenie podľa toho stĺpca."},search:{placeholder:"Hľadaj...",showingItems:"Zobrazujem položky:",selectedItems:"Vybraté položky:",totalItems:"Počet položiek:",size:"Počet:",first:"Prvá strana",next:"Ďalšia strana",previous:"Predchádzajúca strana",last:"Posledná strana"},menu:{text:"Vyberte stĺpce:"},sort:{ascending:"Zotriediť vzostupne",descending:"Zotriediť zostupne",remove:"Vymazať triedenie"},aggregation:{count:"total rows: ",sum:"total: ",avg:"avg: ",min:"min: ",max:"max: "},gridMenu:{columns:"Columns:",importerTitle:"Import file",exporterAllAsCsv:"Export all data as csv",exporterVisibleAsCsv:"Export visible data as csv",exporterSelectedAsCsv:"Export selected data as csv",exporterAllAsPdf:"Export all data as pdf",exporterVisibleAsPdf:"Export visible data as pdf",exporterSelectedAsPdf:"Export selected data as pdf"},importer:{noHeaders:"Column names were unable to be derived, does the file have a header?",noObjects:"Objects were not able to be derived, was there data in the file other than headers?",invalidCsv:"File was unable to be processed, is it valid CSV?",invalidJson:"File was unable to be processed, is it valid Json?",jsonNotArray:"Imported json file must contain an array, aborting."}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("sv",{aggregate:{label:"Artiklar"},groupPanel:{description:"Dra en kolumnrubrik hit och släpp den för att gruppera efter den kolumnen."},search:{placeholder:"Sök...",showingItems:"Visar artiklar:",selectedItems:"Valda artiklar:",totalItems:"Antal artiklar:",size:"Sidstorlek:",first:"Första sidan",next:"Nästa sida",previous:"Föregående sida",last:"Sista sidan"},menu:{text:"Välj kolumner:"},sort:{ascending:"Sortera stigande",descending:"Sortera fallande",remove:"Inaktivera sortering"},column:{hide:"Göm kolumn"},aggregation:{count:"Antal rader: ",sum:"Summa: ",avg:"Genomsnitt: ",min:"Min: ",max:"Max: "},pinning:{pinLeft:"Fäst vänster",pinRight:"Fäst höger",unpin:"Lösgör"},gridMenu:{columns:"Kolumner:",importerTitle:"Importera fil",exporterAllAsCsv:"Exportera all data som CSV",exporterVisibleAsCsv:"Exportera synlig data som CSV",exporterSelectedAsCsv:"Exportera markerad data som CSV",exporterAllAsPdf:"Exportera all data som PDF",exporterVisibleAsPdf:"Exportera synlig data som PDF",exporterSelectedAsPdf:"Exportera markerad data som PDF"},importer:{noHeaders:"Kolumnnamn kunde inte härledas. Har filen ett sidhuvud?",noObjects:"Objekt kunde inte härledas. Har filen data undantaget sidhuvud?",invalidCsv:"Filen kunde inte behandlas, är den en giltig CSV?",invalidJson:"Filen kunde inte behandlas, är den en giltig JSON?",jsonNotArray:"Importerad JSON-fil måste innehålla ett fält. Import avbruten."},pagination:{sizes:"Artiklar per sida",totalItems:"Artiklar"}}),a}])}])}(),function(){var a=["uiT","uiTranslate"],b=["t","uiTranslate"],c=angular.module("ui.grid.i18n");c.constant("i18nConstants",{MISSING:"[MISSING]",UPDATE_EVENT:"$uiI18n",LOCALE_DIRECTIVE_ALIAS:"uiI18n",DEFAULT_LANG:"en"}),c.service("i18nService",["$log","i18nConstants","$rootScope",function(a,b,c){var d={_langs:{},current:null,get:function(a){return this._langs[a.toLowerCase()]},add:function(a,b){var c=a.toLowerCase();this._langs[c]||(this._langs[c]={}),angular.extend(this._langs[c],b)},getAllLangs:function(){var a=[];if(!this._langs)return a;for(var b in this._langs)a.push(b);return a},setCurrent:function(a){this.current=a.toLowerCase()},getCurrentLang:function(){return this.current}},e={add:function(a,b){"object"==typeof a?angular.forEach(a,function(a){a&&d.add(a,b)}):d.add(a,b)},getAllLangs:function(){return d.getAllLangs()},get:function(a){var b=a?a:e.getCurrentLang();return d.get(b)},getSafeText:function(a,c){var f=c?c:e.getCurrentLang(),g=d.get(f);if(!g)return b.MISSING;for(var h=a.split("."),i=g,j=0;j<h.length;++j){if(void 0===i[h[j]]||null===i[h[j]])return b.MISSING;i=i[h[j]]}return i},setCurrentLang:function(a){a&&(d.setCurrent(a),c.$broadcast(b.UPDATE_EVENT))},getCurrentLang:function(){var a=d.getCurrentLang();return a||(a=b.DEFAULT_LANG,d.setCurrent(a)),a}};return e}]);var d=function(a,b){return{compile:function(){return{pre:function(c,d,e){var f=b.LOCALE_DIRECTIVE_ALIAS,g=c.$eval(e[f]);g?c.$watch(e[f],function(){a.setCurrentLang(g)}):e.$$observers&&e.$observe(f,function(){a.setCurrentLang(e[f]||b.DEFAULT_LANG)})}}}}};c.directive("uiI18n",["i18nService","i18nConstants",d]);var e=function(b,c,d){return{restrict:"EA",compile:function(){return{pre:function(e,f,g){var h,i=a[0],j=a[1],k=g[i]||g[j]||f.html(),l=d.MISSING+k;if(g.$$observers){var m=g[i]?i:j;h=g.$observe(m,function(a){a&&f.html(b(a)(c.getCurrentLang())||l)})}var n=b(k),o=e.$on(d.UPDATE_EVENT,function(){h?h(g[i]||g[j]):f.html(n(c.get())||l)});e.$on("$destroy",o),f.html(n(c.get())||l)}}}}};angular.forEach(a,function(a){c.directive(a,["$parse","i18nService","i18nConstants",e])});var f=function(a,b,c){return function(d){var e=a(d);return e(b.get())||c.MISSING+d}};angular.forEach(b,function(a){c.filter(a,["$parse","i18nService","i18nConstants",f])})}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-cn",{aggregate:{label:"行"},groupPanel:{description:"拖曳表头到此处进行分组"},search:{placeholder:"查找",showingItems:"已显示行数:",selectedItems:"已选择行数:",totalItems:"总行数:",size:"每页显示行数:",first:"首页",next:"下一页",previous:"上一页",last:"末页"},menu:{text:"选择列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隐藏列"},aggregation:{count:"计数:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左侧固定",pinRight:"右侧固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"导入文件",exporterAllAsCsv:"导出全部数据到CSV",exporterVisibleAsCsv:"导出可见数据到CSV",exporterSelectedAsCsv:"导出已选数据到CSV",exporterAllAsPdf:"导出全部数据到PDF",exporterVisibleAsPdf:"导出可见数据到PDF",exporterSelectedAsPdf:"导出已选数据到PDF"},importer:{noHeaders:"无法获取列名,确定文件包含表头?",noObjects:"无法获取数据,确定文件包含数据?",invalidCsv:"无法处理文件,确定是合法的CSV文件?",invalidJson:"无法处理文件,确定是合法的JSON文件?",jsonNotArray:"导入的文件不是JSON数组!"},pagination:{sizes:"行每页",totalItems:"行"}}),a}])}])}(),function(){angular.module("ui.grid").config(["$provide",function(a){a.decorator("i18nService",["$delegate",function(a){return a.add("zh-tw",{aggregate:{label:"行"},groupPanel:{description:"拖曳表頭到此處進行分組"},search:{placeholder:"查找",showingItems:"已顯示行數:",selectedItems:"已選擇行數:",totalItems:"總行數:",size:"每頁顯示行數:",first:"首頁",next:"下壹頁",previous:"上壹頁",last:"末頁"},menu:{text:"選擇列:"},sort:{ascending:"升序",descending:"降序",remove:"取消排序"},column:{hide:"隱藏列"},aggregation:{count:"計數:",sum:"求和:",avg:"均值:",min:"最小值:",max:"最大值:"},pinning:{pinLeft:"左側固定",pinRight:"右側固定",unpin:"取消固定"},gridMenu:{columns:"列:",importerTitle:"導入文件",exporterAllAsCsv:"導出全部數據到CSV",exporterVisibleAsCsv:"導出可見數據到CSV",exporterSelectedAsCsv:"導出已選數據到CSV",exporterAllAsPdf:"導出全部數據到PDF",exporterVisibleAsPdf:"導出可見數據到PDF",exporterSelectedAsPdf:"導出已選數據到PDF"},importer:{noHeaders:"無法獲取列名,確定文件包含表頭?",noObjects:"無法獲取數據,確定文件包含數據?",invalidCsv:"無法處理文件,確定是合法的CSV文件?",invalidJson:"無法處理文件,確定是合法的JSON文件?",jsonNotArray:"導入的文件不是JSON數組!"},pagination:{sizes:"行每頁",totalItems:"行"}}),a}])}])}(),function(){"use strict";var a=angular.module("ui.grid.autoResize",["ui.grid"]);a.directive("uiGridAutoResize",["$timeout","gridUtil",function(a,b){return{require:"uiGrid",scope:!1,link:function(a,c,d,e){function f(){i=b.elementHeight(c),h=b.elementWidth(c)}function g(){clearTimeout(j),j=setTimeout(function(){var d=b.elementHeight(c),j=b.elementWidth(c);d!==i||j!==h?(e.grid.gridHeight=d,e.grid.gridWidth=j,a.$apply(function(){e.grid.refresh().then(function(){f(),g()})})):g()},250)}var h,i;f();var j;g(),a.$on("$destroy",function(){clearTimeout(j)})}}}])}(),function(){"use strict";function a(a,b){this.row=a,this.col=b}var b=angular.module("ui.grid.cellNav",["ui.grid"]);b.constant("uiGridCellNavConstants",{FEATURE_NAME:"gridCellNav",CELL_NAV_EVENT:"cellNav",direction:{LEFT:0,RIGHT:1,UP:2,DOWN:3,PG_UP:4,PG_DOWN:5},EVENT_TYPE:{KEYDOWN:0,CLICK:1,CLEAR:2}}),b.factory("uiGridCellNavFactory",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q",function(b,c,d){var e=function(a,b,c,d){this.rows=a.visibleRowCache,this.columns=b.visibleColumnCache,this.leftColumns=c?c.visibleColumnCache:[],this.rightColumns=d?d.visibleColumnCache:[],this.bodyContainer=a};return e.prototype.getFocusableCols=function(){var a=this.leftColumns.concat(this.columns,this.rightColumns);return a.filter(function(a){return a.colDef.allowCellFocus})},e.prototype.getFocusableRows=function(){return this.rows.filter(function(a){return a.allowCellFocus!==!1})},e.prototype.getNextRowCol=function(a,b,c){switch(a){case d.direction.LEFT:return this.getRowColLeft(b,c);case d.direction.RIGHT:return this.getRowColRight(b,c);case d.direction.UP:return this.getRowColUp(b,c);case d.direction.DOWN:return this.getRowColDown(b,c);case d.direction.PG_UP:return this.getRowColPageUp(b,c);case d.direction.PG_DOWN:return this.getRowColPageDown(b,c)}},e.prototype.getRowColLeft=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=1);var h=0===f?d.length-1:f-1;return h>f?0===g?new a(b,d[h]):new a(e[g-1],d[h]):new a(b,d[h])},e.prototype.getRowColRight=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=f===d.length-1?0:f+1;return f>h?g===e.length-1?new a(b,d[h]):new a(e[g+1],d[h]):new a(b,d[h])},e.prototype.getRowColDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),g===e.length-1?new a(b,d[f]):new a(e[g+1],d[f])},e.prototype.getRowColPageDown=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return g>=e.length-h?new a(e[e.length-1],d[f]):new a(e[g+h],d[f])},e.prototype.getRowColUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);return-1===f&&(f=0),0===g?new a(b,d[f]):new a(e[g-1],d[f])},e.prototype.getRowColPageUp=function(b,c){var d=this.getFocusableCols(),e=this.getFocusableRows(),f=d.indexOf(c),g=e.indexOf(b);-1===f&&(f=0);var h=this.bodyContainer.minRowsToRender();return 0>g-h?new a(e[0],d[f]):new a(e[g-h],d[f])},e}]),b.service("uiGridCellNavService",["gridUtil","uiGridConstants","uiGridCellNavConstants","$q","uiGridCellNavFactory","ScrollEvent",function(a,b,c,d,e,f){var g={initializeGrid:function(a){a.registerColumnBuilder(g.cellNavColumnBuilder),a.cellNav={},a.cellNav.lastRowCol=null,a.cellNav.focusedCells=[],g.defaultGridOptions(a.options);var b={events:{cellNav:{navigate:function(){}}},methods:{cellNav:{scrollTo:function(b,c){g.scrollTo(a,b,c)},scrollToFocus:function(b,c){g.scrollToFocus(a,b,c)},scrollToIfNecessary:function(b,c){g.scrollToIfNecessary(a,b,c)},getFocusedCell:function(){return a.cellNav.lastRowCol},getCurrentSelection:function(){return a.cellNav.focusedCells},rowColSelectIndex:function(b){for(var c=-1,d=0;d<a.cellNav.focusedCells.length;d++)if(a.cellNav.focusedCells[d].col.uid===b.col.uid&&a.cellNav.focusedCells[d].row.uid===b.row.uid){c=d;break}return c}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.modifierKeysToMultiSelectCells=a.modifierKeysToMultiSelectCells===!0},decorateRenderContainers:function(a){var b=a.hasRightContainer()?a.renderContainers.right:null,c=a.hasLeftContainer()?a.renderContainers.left:null;null!==c&&(a.renderContainers.left.cellNav=new e(a.renderContainers.body,c,b,a.renderContainers.body)),null!==b&&(a.renderContainers.right.cellNav=new e(a.renderContainers.body,b,a.renderContainers.body,c)),a.renderContainers.body.cellNav=new e(a.renderContainers.body,a.renderContainers.body,c,b)},getDirection:function(a){return a.keyCode===b.keymap.LEFT||a.keyCode===b.keymap.TAB&&a.shiftKey?c.direction.LEFT:a.keyCode===b.keymap.RIGHT||a.keyCode===b.keymap.TAB?c.direction.RIGHT:a.keyCode===b.keymap.UP||a.keyCode===b.keymap.ENTER&&a.shiftKey?c.direction.UP:a.keyCode===b.keymap.PG_UP?c.direction.PG_UP:a.keyCode===b.keymap.DOWN||a.keyCode===b.keymap.ENTER?c.direction.DOWN:a.keyCode===b.keymap.PG_DOWN?c.direction.PG_DOWN:null},cellNavColumnBuilder:function(a){var b=[];return a.allowCellFocus=void 0===a.allowCellFocus?!0:a.allowCellFocus,d.all(b)},scrollTo:function(a,b,c){var d=null,e=null;null!==b&&"undefined"!=typeof b&&(d=a.getRow(b)),null!==c&&"undefined"!=typeof c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e)},scrollToFocus:function(a,b,c){var d=null,e=null;null!==b&&(d=a.getRow(b)),null!==c&&(e=a.getColumn(c.name?c.name:c.field)),this.scrollToInternal(a,d,e);var f={row:d,col:e};a.cellNav.broadcastCellNav(f)},scrollToInternal:function(a,b,c){var d=new f(a,null,null,"uiGridCellNavService.scrollToInternal");if(null!==b){var e=a.renderContainers.body.visibleRowCache.indexOf(b),g=a.renderContainers.body.visibleRowCache.length,h=(e+e/(g-1))/g;d.y={percentage:h}}null!==c&&(d.x={percentage:this.getLeftWidth(a,c)/this.getLeftWidth(a,a.renderContainers.body.visibleColumnCache[a.renderContainers.body.visibleColumnCache.length-1])}),(d.y||d.x)&&d.fireScrollingEvent()},scrollToIfNecessary:function(a,b,c){var d=new f(a,"uiGridCellNavService.scrollToIfNecessary"),e=a.renderContainers.body.visibleRowCache,g=a.renderContainers.body.visibleColumnCache,h=a.renderContainers.body.prevScrollTop+a.headerHeight;h=0>h?0:h;var i=a.renderContainers.body.prevScrollLeft,j=a.renderContainers.body.prevScrollTop+a.gridHeight-a.headerHeight,k=a.renderContainers.body.prevScrollLeft+Math.ceil(a.gridWidth);if(null!==b){var l=e.indexOf(b),m=a.renderContainers.body.getCanvasHeight()-a.renderContainers.body.getViewportHeight(),n=(l+1)*a.options.rowHeight;n=0>n?0:n;var o,p;h>n?(o=a.renderContainers.body.prevScrollTop-(h-n),p=o/m,d.y={percentage:p}):n>j&&(o=n-j+a.renderContainers.body.prevScrollTop,p=o/m,d.y={percentage:p})}if(null!==c){for(var q=g.indexOf(c),r=a.renderContainers.body.getCanvasWidth()-a.renderContainers.body.getViewportWidth(),s=0,t=0;q>t;t++){var u=g[t];s+=u.drawnWidth}s=0>s?0:s;var v=s+c.drawnWidth;v=0>v?0:v;var w,x;i>s?(w=a.renderContainers.body.prevScrollLeft-(i-s),x=w/r,x=x>1?1:x,d.x={percentage:x}):v>k&&(w=v-k+a.renderContainers.body.prevScrollLeft,x=w/r,x=x>1?1:x,d.x={percentage:x})}(d.y||d.x)&&d.fireScrollingEvent()},getLeftWidth:function(a,b){var c=0;if(!b)return c;var d=a.renderContainers.body.visibleColumnCache.indexOf(b);a.renderContainers.body.visibleColumnCache.forEach(function(a,b){d>b&&(c+=a.drawnWidth)});var e=0===d?0:(d+1)/a.renderContainers.body.visibleColumnCache.length;return c+=b.drawnWidth*e}};return g}]),b.directive("uiGridCellnav",["gridUtil","uiGridCellNavService","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e){return{replace:!0,priority:-150,require:"^uiGrid",scope:!1,controller:function(){},compile:function(){return{pre:function(b,f,g,h){var i=b,j=h.grid;c.initializeGrid(j),h.cellNav={},h.cellNav.focusCell=function(a,b){h.cellNav.broadcastCellNav({row:a,col:b})},h.cellNav.broadcastCellNav=j.cellNav.broadcastCellNav=function(a,b){b=!(void 0===b||!b),h.cellNav.broadcastFocus(a,b),i.$broadcast(d.CELL_NAV_EVENT,a,b)},h.cellNav.clearFocus=j.cellNav.clearFocus=function(){i.$broadcast(d.CELL_NAV_EVENT,{eventType:d.EVENT_TYPE.CLEAR})
    +},h.cellNav.broadcastFocus=function(b,c){c=!(void 0===c||!c);var d=b.row,e=b.col,f=h.grid.api.cellNav.rowColSelectIndex(b);if(null===j.cellNav.lastRowCol||-1===f){var g=new a(d,e);j.api.cellNav.raise.navigate(g,j.cellNav.lastRowCol),j.cellNav.lastRowCol=g,h.grid.options.modifierKeysToMultiSelectCells&&c?j.cellNav.focusedCells.push(b):j.cellNav.focusedCells=[b]}else j.options.modifierKeysToMultiSelectCells&&c&&f>=0&&j.cellNav.focusedCells.splice(f,1)},h.cellNav.handleKeyDown=function(a){var b=c.getDirection(a);if(null===b)return!0;var f="body";a.uiGridTargetRenderContainerId&&(f=a.uiGridTargetRenderContainerId);var g=h.grid.api.cellNav.getFocusedCell();if(g){var i=h.grid.renderContainers[f].cellNav.getNextRowCol(b,g.row,g.col);return b===d.direction.LEFT&&i.row===g.row&&a.keyCode===e.keymap.TAB&&a.shiftKey?(h.cellNav.clearFocus(),!0):b!==d.direction.RIGHT||i.row!==g.row||a.keyCode!==e.keymap.TAB||a.shiftKey?(i.eventType=d.EVENT_TYPE.KEYDOWN,h.cellNav.broadcastCellNav(i),c.scrollToIfNecessary(j,i.row,i.col),a.stopPropagation(),a.preventDefault(),!1):(h.cellNav.clearFocus(),!0)}}},post:function(){}}}}}]),b.directive("uiGridRenderContainer",["$timeout","$document","gridUtil","uiGridConstants","uiGridCellNavService","uiGridCellNavConstants",function(a,b,c,d,e){return{replace:!0,priority:-99999,require:["^uiGrid","uiGridRenderContainer","?^uiGridCellnav"],scope:!1,compile:function(){return{post:function(c,d,f,g){var h=g[0],i=g[1];if(h.grid.api.cellNav){var j=i.containerId,k=h.grid;e.decorateRenderContainers(k),d.attr("tabindex",-1),d.on("keydown",function(a){return a.uiGridTargetRenderContainerId=j,h.cellNav.handleKeyDown(a)});var l=!1;k.api.core.on.scrollEvent(c,function(c){c.grid&&c.grid.id!==h.grid.id||null!=h.grid.api.cellNav.getFocusedCell()&&("uiGridCellNavService.scrollToIfNecessary"===c.source?l=!0:l&&a(function(){a(function(){var a=h.grid.api.cellNav.getFocusedCell();b.activeElement===b.body&&d[0].focus(),h.cellNav.broadcastCellNav(a),l=!1})}))})}}}}}}]),b.directive("uiGridCell",["$timeout","$document","uiGridCellNavService","gridUtil","uiGridCellNavConstants","uiGridConstants",function(b,c,d,e,f){return{priority:-150,restrict:"A",require:"^uiGrid",scope:!1,link:function(b,c,d,e){function g(){c.find("div").attr("tabindex",0)}function h(){var a=c.find("div");a.addClass("ui-grid-cell-focus")}function i(){var a=c.find("div");a.removeClass("ui-grid-cell-focus")}e.grid.api.cellNav&&b.col.colDef.allowCellFocus&&(g(),c.find("div").on("click",function(c){e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey),c.stopPropagation()}),c.find("div").on("focus",function(c){console.log("cellNav focus"),e.cellNav.broadcastCellNav(new a(b.row,b.col),c.ctrlKey||c.metaKey)}),b.$on(f.CELL_NAV_EVENT,function(a,d,g){return a.eventType===f.EVENT_TYPE.CLEAR?void i():void(d.row===b.row&&d.col===b.col?(e.grid.options.modifierKeysToMultiSelectCells&&g&&-1===e.grid.api.cellNav.rowColSelectIndex(d)?i():h(),d.hasOwnProperty("eventType")&&d.eventType===f.EVENT_TYPE.KEYDOWN&&(console.log("focus from navEvent"),c.find("div")[0].focus())):e.grid.options.modifierKeysToMultiSelectCells&&g||i())}),b.$on("$destroy",function(){c.find("div").off("click")}))}}}])}(),function(){"use strict";var a=angular.module("ui.grid.edit",["ui.grid"]);a.constant("uiGridEditConstants",{EDITABLE_CELL_TEMPLATE:/EDITABLE_CELL_TEMPLATE/g,EDITABLE_CELL_DIRECTIVE:/editable_cell_directive/g,events:{BEGIN_CELL_EDIT:"uiGridEventBeginCellEdit",END_CELL_EDIT:"uiGridEventEndCellEdit",CANCEL_CELL_EDIT:"uiGridEventCancelCellEdit"}}),a.service("uiGridEditService",["$q","$templateCache","uiGridConstants","gridUtil",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options),a.registerColumnBuilder(e.editColumnBuilder);var b={events:{edit:{afterCellEdit:function(){},beginCellEdit:function(){},cancelCellEdit:function(){}}},methods:{edit:{}}};a.api.registerEventsFromObject(b.events)},defaultGridOptions:function(a){a.cellEditableCondition=void 0===a.cellEditableCondition?!0:a.cellEditableCondition,a.enableCellEditOnFocus=void 0===a.enableCellEditOnFocus?!1:a.enableCellEditOnFocus},editColumnBuilder:function(b,c,e){var f=[];return b.enableCellEdit=void 0===b.enableCellEdit?void 0===e.enableCellEdit?"object"!==b.type:e.enableCellEdit:b.enableCellEdit,b.cellEditableCondition=void 0===b.cellEditableCondition?e.cellEditableCondition:b.cellEditableCondition,b.enableCellEdit&&(b.editableCellTemplate=b.editableCellTemplate||e.editableCellTemplate||"ui-grid/cellEditor",f.push(d.getTemplate(b.editableCellTemplate).then(function(a){c.editableCellTemplate=a},function(){throw new Error("Couldn't fetch/use colDef.editableCellTemplate '"+b.editableCellTemplate+"'")}))),b.enableCellEditOnFocus=void 0===b.enableCellEditOnFocus?e.enableCellEditOnFocus:b.enableCellEditOnFocus,a.all(f)},isStartEditKey:function(a){return a.keyCode===c.keymap.LEFT||a.keyCode===c.keymap.TAB&&a.shiftKey||a.keyCode===c.keymap.RIGHT||a.keyCode===c.keymap.TAB||a.keyCode===c.keymap.UP||a.keyCode===c.keymap.ENTER&&a.shiftKey||a.keyCode===c.keymap.DOWN||a.keyCode===c.keymap.ENTER?!1:!0}};return e}]),a.directive("uiGridEdit",["gridUtil","uiGridEditService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","$injector","$timeout","uiGridConstants","uiGridEditConstants","gridUtil","$parse","uiGridEditService",function(a,b,c,d,e,f,g,h){var i=500;return{priority:-100,restrict:"A",scope:!1,require:"?^uiGrid",link:function(f,j,k,l){function m(){j.on("dblclick",t),j.on("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").on("focus",q),j.on("touchstart",n)}function n(a){"undefined"!=typeof a.originalEvent&&void 0!==a.originalEvent&&(a=a.originalEvent),j.on("touchend",o),A=c(function(){},i),A.then(function(){setTimeout(t,0),j.off("touchend",o)})}function o(){c.cancel(A),j.off("touchend",o)}function p(){j.off("dblclick",t),j.off("keydown",r),f.col.colDef.enableCellEditOnFocus&&j.find("div").off("focus",q),j.off("touchstart",n)}function q(a){l&&l.cellNav&&l.cellNav.focusCell(f.row,f.col),a.stopPropagation(),t()}function r(a){h.isStartEditKey(a)&&t()}function s(a,b){return!b.isSaving&&(angular.isFunction(a.colDef.cellEditableCondition)?a.colDef.cellEditableCondition(f):a.colDef.cellEditableCondition)}function t(){if(!C&&s(f.col,f.row)){f.grid.api.cellNav&&f.grid.api.cellNav.scrollToIfNecessary(f.row,f.col),z=g(f.row.getQualifiedColField(f.col)),y=z(f),x=f.col.editableCellTemplate,x=x.replace(d.MODEL_COL_FIELD,f.row.getQualifiedColField(f.col));var b=f.col.colDef.editDropdownFilter?"|"+f.col.colDef.editDropdownFilter:"";x=x.replace(d.CUSTOM_FILTERS,b);var c="text";switch(f.col.colDef.type){case"boolean":c="checkbox";break;case"number":c="number";break;case"date":c="date"}x=x.replace("INPUT_TYPE",c);var h=f.col.colDef.editDropdownRowEntityOptionsArrayPath;f.editDropdownOptionsArray=h?w(f.row.entity,h):f.col.colDef.editDropdownOptionsArray,f.editDropdownIdLabel=f.col.colDef.editDropdownIdLabel?f.col.colDef.editDropdownIdLabel:"id",f.editDropdownValueLabel=f.col.colDef.editDropdownValueLabel?f.col.colDef.editDropdownValueLabel:"value";f.$apply(function(){C=!0,p();var b=angular.element(x);j.append(b),B=f.$new(),a(b)(B);var c=angular.element(j.children()[0]);D=c.hasClass("ui-grid-cell-focus"),c.addClass("ui-grid-cell-contents-hidden")});var i=f.col.grid.api.core.on.scrollEvent(f,function(){u(!0),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),i(),k(),l()}),k=f.$on(e.events.END_CELL_EDIT,function(a,b){u(b),f.grid.api.edit.raise.afterCellEdit(f.row.entity,f.col.colDef,z(f),y),k(),i(),l()}),l=f.$on(e.events.CANCEL_CELL_EDIT,function(){v(),l(),i(),k()});f.$broadcast(e.events.BEGIN_CELL_EDIT),f.grid.api.edit.raise.beginCellEdit(f.row.entity,f.col.colDef)}}function u(a){if(C){var b=angular.element(j.children()[0]);B.$destroy(),angular.element(j.children()[1]).remove(),b.removeClass("ui-grid-cell-contents-hidden"),a&&D&&b[0].focus(),D=!1,C=!1,m(),f.grid.api.core.notifyDataChange(d.dataChange.EDIT)}}function v(){C&&(z.assign(f,y),f.$apply(),f.grid.api.edit.raise.cancelCellEdit(f.row.entity,f.col.colDef),u(!0))}function w(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split(".");c.length;){var d=c.shift();if(!(d in a))return;a=a[d]}return a}if(f.col.colDef.enableCellEdit&&f.row.enableCellEdit!==!1){var x,y,z,A,B,C=!1,D=!1;m();try{var E=b.get("uiGridCellNavConstants");f.col.colDef.enableCellEditOnFocus&&f.$on(E.CELL_NAV_EVENT,function(a,b){b.row===f.row&&b.col===f.col?t():u()})}catch(F){}}}}}]),a.directive("uiGridEditor",["gridUtil","uiGridConstants","uiGridEditConstants",function(a,b,c){return{scope:!0,require:["?^uiGrid","?^uiGridRenderContainer"],compile:function(){return{pre:function(){},post:function(a,d,e,f){var g,h;f[0]&&(g=f[0]),f[1]&&(h=f[1]),a.$on(c.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].select(),d.on("blur",function(b){a.stopEdit(b)})}),a.deepEdit=!1,a.stopEdit=function(b){a.inputForm&&!a.inputForm.$valid?(b.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT)):a.$emit(c.events.END_CELL_EDIT),a.deepEdit=!1},d.on("click",function(){a.deepEdit=!0}),d.on("keydown",function(d){switch(d.keyCode){case b.keymap.ESC:d.stopPropagation(),a.$emit(c.events.CANCEL_CELL_EDIT);break;case b.keymap.ENTER:a.stopEdit(d);break;case b.keymap.TAB:a.stopEdit(d)}if(a.deepEdit)switch(d.keyCode){case b.keymap.LEFT:d.stopPropagation();break;case b.keymap.RIGHT:d.stopPropagation();break;case b.keymap.UP:d.stopPropagation();break;case b.keymap.DOWN:d.stopPropagation()}else g&&g.hasOwnProperty("cellNav")&&h&&(d.uiGridTargetRenderContainerId=h.containerId,g.cellNav.handleKeyDown(d));return!0})}}}}}]),a.directive("uiGridEditor",["$filter",function(a){function b(a){if("undefined"==typeof a||""===a)return null;var b=a.split("-");if(3!==b.length)return null;var c=parseInt(b[0],10),d=parseInt(b[1],10),e=parseInt(b[2],10);return 1>d||1>c||1>e?null:new Date(c,d-1,e)}return{priority:-100,require:"?ngModel",link:function(c,d,e,f){2===angular.version.minor&&e.type&&"date"===e.type&&f&&(f.$formatters.push(function(b){return f.$setValidity(null,!b||!isNaN(b.getTime())),a("date")(b,"yyyy-MM-dd")}),f.$parsers.push(function(a){if(a&&a.length>0){var c=b(a);return f.$setValidity(null,c&&!isNaN(c.getTime())),c}return f.$setValidity(null,!0),null}))}}}]),a.directive("uiGridEditDropdown",["uiGridConstants","uiGridEditConstants",function(a,b){return{scope:!0,compile:function(){return{pre:function(){},post:function(c,d){c.$on(b.events.BEGIN_CELL_EDIT,function(){d[0].focus(),d[0].style.width=d[0].parentElement.offsetWidth-1+"px",d.on("blur",function(a){c.stopEdit(a)})}),c.stopEdit=function(){c.$emit(b.events.END_CELL_EDIT)},d.on("keydown",function(d){switch(d.keyCode){case a.keymap.ESC:d.stopPropagation(),c.$emit(b.events.CANCEL_CELL_EDIT);break;case a.keymap.ENTER:c.stopEdit(d);break;case a.keymap.LEFT:c.stopEdit(d);break;case a.keymap.RIGHT:c.stopEdit(d);break;case a.keymap.UP:d.stopPropagation();break;case a.keymap.DOWN:d.stopPropagation();break;case a.keymap.TAB:c.stopEdit(d)}return!0})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.expandable",["ui.grid"]);a.service("uiGridExpandableService",["gridUtil","$compile",function(a){var b={initializeGrid:function(c){c.expandable={},c.expandable.expandedAll=!1,c.options.enableExpandable=c.options.enableExpandable!==!1,c.options.expandableRowHeight=c.options.expandableRowHeight||150,c.options.expandableRowHeaderWidth=c.options.expandableRowHeaderWidth||40,c.options.enableExpandable&&!c.options.expandableRowTemplate&&(a.logError("You have not set the expandableRowTemplate, disabling expandable module"),c.options.enableExpandable=!1);var d={events:{expandable:{rowExpandedStateChanged:function(){}}},methods:{expandable:{toggleRowExpansion:function(a){var d=c.getRow(a);null!==d&&b.toggleRowExpansion(c,d)},expandAllRows:function(){b.expandAllRows(c)},collapseAllRows:function(){b.collapseAllRows(c)},toggleAllRows:function(){b.toggleAllRows(c)}}}};c.api.registerEventsFromObject(d.events),c.api.registerMethodsFromObject(d.methods)},toggleRowExpansion:function(a,b){b.isExpanded=!b.isExpanded,b.isExpanded?b.height=b.grid.options.rowHeight+a.options.expandableRowHeight:(b.height=b.grid.options.rowHeight,a.expandable.expandedAll=!1),a.api.expandable.raise.rowExpandedStateChanged(b)},expandAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded||b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!0,a.refresh()},collapseAllRows:function(a){angular.forEach(a.renderContainers.body.visibleRowCache,function(c){c.isExpanded&&b.toggleRowExpansion(a,c)}),a.expandable.expandedAll=!1,a.refresh()},toggleAllRows:function(a){a.expandable.expandedAll?b.collapseAllRows(a):b.expandAllRows(a)}};return b}]),a.directive("uiGridExpandable",["uiGridExpandableService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(f.grid.options.enableExpandableRowHeader!==!1){var g={name:"expandableButtons",displayName:"",exporterSuppressExport:!0,enableColumnResizing:!1,enableColumnMenu:!1,width:f.grid.options.expandableRowHeaderWidth||40};g.cellTemplate=b.get("ui-grid/expandableRowHeader"),g.headerCellTemplate=b.get("ui-grid/expandableTopRowHeader"),f.grid.addRowHeaderColumn(g)}a.initializeGrid(f.grid)},post:function(){}}}}}]),a.directive("uiGrid",["uiGridExpandableService","$templateCache",function(){return{replace:!0,priority:1e3,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,b,c,d){d.grid.api.core.on.renderingComplete(a,function(){a.row&&a.row.grid&&a.row.grid.options&&a.row.grid.options.enableExpandable&&(d.grid.parentRow=a.row)})},post:function(){}}}}}]),a.directive("uiGridExpandableRow",["uiGridExpandableService","$timeout","$compile","uiGridConstants","gridUtil","$interval","$log",function(a,b,c,d,e){return{replace:!1,priority:0,scope:!1,compile:function(){return{pre:function(a,b){e.getTemplate(a.grid.options.expandableRowTemplate).then(function(d){if(a.grid.options.expandableRowScope){var e=a.grid.options.expandableRowScope;for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}var g=c(d)(a);b.append(g),a.row.expandedRendered=!0})},post:function(a){a.$on("$destroy",function(){a.row.expandedRendered=!1})}}}}}]),a.directive("uiGridRow",["$compile","gridUtil","$templateCache",function(){return{priority:-200,scope:!1,compile:function(){return{pre:function(a){function b(){var b=a.grid,c=0;return angular.forEach(b.columns,function(a){"left"===a.renderContainer&&(c+=a.width)}),c=Math.floor(c),".grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+", .grid"+b.id+" .ui-grid-pinned-container-"+a.colContainer.name+" .ui-grid-render-container-"+a.colContainer.name+" .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: "+c+"px; }"}a.expandableRow={},a.expandableRow.shouldRenderExpand=function(){var b="body"===a.colContainer.name&&a.grid.options.enableExpandable!==!1&&a.row.isExpanded&&(!a.grid.isScrollingVertically||a.row.expandedRendered);return b},a.expandableRow.shouldRenderFiller=function(){var b=a.row.isExpanded&&("body"!==a.colContainer.name||a.grid.isScrollingVertically&&!a.row.expandedRendered);return b},"left"===a.colContainer.name&&a.grid.registerStyleComputation({priority:15,func:b})},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","$templateCache",function(a,b,c){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),d=c.get("ui-grid/expandableScrollFiller"),e=c.get("ui-grid/expandableRow");return b.append(e),b.append(d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.exporter",["ui.grid"]);a.constant("uiGridExporterConstants",{featureName:"exporter",ALL:"all",VISIBLE:"visible",SELECTED:"selected",CSV_CONTENT:"CSV_CONTENT",BUTTON_LABEL:"BUTTON_LABEL",FILE_NAME:"FILE_NAME"}),a.service("uiGridExporterService",["$q","uiGridExporterConstants","uiGridSelectionConstants","gridUtil","$compile","$interval","i18nService",function(a,b,c,d,e,f,g){var h={initializeGrid:function(a){a.exporter={},this.defaultGridOptions(a.options);var b={events:{exporter:{}},methods:{exporter:{csvExport:function(b,c){h.csvExport(a,b,c)},pdfExport:function(b,c){h.pdfExport(a,b,c)}}}};a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods),a.api.core.addToGridMenu?h.addToMenu(a):f(function(){a.api.core.addToGridMenu&&h.addToMenu(a)},100,1)},defaultGridOptions:function(a){a.exporterSuppressMenu=a.exporterSuppressMenu===!0,a.exporterMenuLabel=a.exporterMenuLabel?a.exporterMenuLabel:"Export",a.exporterSuppressColumns=a.exporterSuppressColumns?a.exporterSuppressColumns:[],a.exporterCsvColumnSeparator=a.exporterCsvColumnSeparator?a.exporterCsvColumnSeparator:",",a.exporterCsvFilename=a.exporterCsvFilename?a.exporterCsvFilename:"download.csv",a.exporterPdfDefaultStyle=a.exporterPdfDefaultStyle?a.exporterPdfDefaultStyle:{fontSize:11},a.exporterPdfTableStyle=a.exporterPdfTableStyle?a.exporterPdfTableStyle:{margin:[0,5,0,15]},a.exporterPdfTableHeaderStyle=a.exporterPdfTableHeaderStyle?a.exporterPdfTableHeaderStyle:{bold:!0,fontSize:12,color:"black"},a.exporterPdfHeader=a.exporterPdfHeader?a.exporterPdfHeader:null,a.exporterPdfFooter=a.exporterPdfFooter?a.exporterPdfFooter:null,a.exporterPdfOrientation=a.exporterPdfOrientation?a.exporterPdfOrientation:"landscape",a.exporterPdfPageSize=a.exporterPdfPageSize?a.exporterPdfPageSize:"A4",a.exporterPdfMaxGridWidth=a.exporterPdfMaxGridWidth?a.exporterPdfMaxGridWidth:720,a.exporterMenuCsv=void 0!==a.exporterMenuCsv?a.exporterMenuCsv:!0,a.exporterMenuPdf=void 0!==a.exporterMenuPdf?a.exporterMenuPdf:!0,a.exporterPdfCustomFormatter=a.exporterPdfCustomFormatter&&"function"==typeof a.exporterPdfCustomFormatter?a.exporterPdfCustomFormatter:function(a){return a},a.exporterHeaderFilterUseName=a.exporterHeaderFilterUseName===!0,a.exporterFieldCallback=a.exporterFieldCallback?a.exporterFieldCallback:function(a,b,c,d){return d}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.exporterAllAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterVisibleAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv}},{title:g.getSafeText("gridMenu.exporterSelectedAsCsv"),action:function(){this.grid.api.exporter.csvExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuCsv&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}},{title:g.getSafeText("gridMenu.exporterAllAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.ALL,b.ALL)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterVisibleAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.VISIBLE,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf}},{title:g.getSafeText("gridMenu.exporterSelectedAsPdf"),action:function(){this.grid.api.exporter.pdfExport(b.SELECTED,b.VISIBLE)},shown:function(){return this.grid.options.exporterMenuPdf&&this.grid.api.selection&&this.grid.api.selection.getSelectedRows().length>0}}])},csvExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.formatAsCsv(d,e,a.options.exporterCsvColumnSeparator);this.downloadFile(a.options.exporterCsvFilename,f)},getColumnHeaders:function(a,c){var d=[];return angular.forEach(a.columns,function(e){!e.visible&&c!==b.ALL||e.colDef.exporterSuppressExport===!0||-1!==a.options.exporterSuppressColumns.indexOf(e.name)||d.push({name:e.field,displayName:a.options.exporterHeaderFilter?a.options.exporterHeaderFilter(a.options.exporterHeaderFilterUseName?e.name:e.displayName):e.displayName,width:e.drawnWidth?e.drawnWidth:e.width,align:"number"===e.colDef.type?"right":"left"})}),d},getData:function(a,c,e){var f,g=[];switch(c){case b.ALL:f=a.rows;break;case b.VISIBLE:f=a.getVisibleRows();break;case b.SELECTED:a.api.selection?f=a.api.selection.getSelectedGridRows():d.logError("selection feature must be enabled to allow selected rows to be exported")}return angular.forEach(f,function(c){if(c.exporterEnableExporting!==!1){var d=[];angular.forEach(a.columns,function(f){if((f.visible||e===b.ALL)&&f.colDef.exporterSuppressExport!==!0&&-1===a.options.exporterSuppressColumns.indexOf(f.name)){var g={value:a.options.exporterFieldCallback(a,c,f,a.getCellValue(c,f))};f.colDef.exporterPdfAlign&&(g.alignment=f.colDef.exporterPdfAlign),d.push(g)}}),g.push(d)}}),g},formatAsCsv:function(a,b,c){var d=this,e=a.map(function(a){return{value:a.displayName}}),f=d.formatRowAsCsv(this,c)(e)+"\n";return f+=b.map(this.formatRowAsCsv(this,c)).join("\n")},formatRowAsCsv:function(a,b){return function(c){return c.map(a.formatFieldAsCsv).join(b)}},formatFieldAsCsv:function(a){return null==a.value?"":"number"==typeof a.value?a.value:"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?'"'+a.value.replace(/"/g,'""')+'"':JSON.stringify(a.value)},isIE:function(){var a=navigator.userAgent.toLowerCase();return-1!==a.indexOf("msie")?parseInt(a.split("msie")[1]):!1},downloadFile:function(a,b){var c,d,e=document,f=e.createElement("a"),g="application/octet-stream;charset=utf-8";if(!a){var h=new Date;a="CWS Export - "+h.getFullYear()+(h.getMonth()+1)+h.getDate()+h.getHours()+h.getMinutes()+h.getSeconds()+".csv"}if(d=this.isIE(),d&&10>d){var i=e.createElement("iframe");return document.body.appendChild(i),i.contentWindow.document.open("text/html","replace"),i.contentWindow.document.write("sep=,\r\n"+b),i.contentWindow.document.close(),i.contentWindow.focus(),i.contentWindow.document.execCommand("SaveAs",!0,a),document.body.removeChild(i),!0}if(navigator.msSaveBlob)return navigator.msSaveBlob(new Blob(["",b],{type:g}),a);if("download"in f){var j=new Blob([b],{type:g});c=URL.createObjectURL(j),f.setAttribute("download",a)}else c="data:"+g+","+encodeURIComponent(b),f.setAttribute("target","_blank");f.href=c,f.setAttribute("style","display:none;"),e.body.appendChild(f),setTimeout(function(){if(f.click)f.click();else if(document.createEvent){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0),f.dispatchEvent(a)}e.body.removeChild(f)},100)},pdfExport:function(a,b,c){var d=this.getColumnHeaders(a,c),e=this.getData(a,b,c),f=this.prepareAsPdf(a,d,e);pdfMake.createPdf(f).open()},prepareAsPdf:function(a,b,c){var d=this.calculatePdfHeaderWidths(a,b),e=b.map(function(a){return{text:a.displayName,style:"tableHeader"}}),f=c.map(this.formatRowAsPdf(this)),g=[e].concat(f),h={pageOrientation:a.options.exporterPdfOrientation,pageSize:a.options.exporterPdfPageSize,content:[{style:"tableStyle",table:{headerRows:1,widths:d,body:g}}],styles:{tableStyle:a.options.exporterPdfTableStyle,tableHeader:a.options.exporterPdfTableHeaderStyle},defaultStyle:a.options.exporterPdfDefaultStyle};return a.options.exporterPdfLayout&&(h.layout=a.options.exporterPdfLayout),a.options.exporterPdfHeader&&(h.header=a.options.exporterPdfHeader),a.options.exporterPdfFooter&&(h.footer=a.options.exporterPdfFooter),a.options.exporterPdfCustomFormatter&&(h=a.options.exporterPdfCustomFormatter(h)),h},calculatePdfHeaderWidths:function(a,b){var c=0;angular.forEach(b,function(a){"number"==typeof a.width&&(c+=a.width)});var d=0;angular.forEach(b,function(a){if("*"===a.width&&(d+=100),"string"==typeof a.width&&a.width.match(/(\d)*%/)){var b=parseInt(a.width.match(/(\d)*%/)[0]);a.width=c*b/100,d+=a.width}});var e=c+d;return b.map(function(b){return"*"===b.width?b.width:b.width*a.options.exporterPdfMaxGridWidth/e})},formatRowAsPdf:function(a){return function(b){return b.map(a.formatFieldAsPdfString)}},formatFieldAsPdfString:function(a){var b;return b=null==a.value?"":"number"==typeof a.value?a.value.toString():"boolean"==typeof a.value?a.value?"TRUE":"FALSE":"string"==typeof a.value?a.value.replace(/"/g,'""'):JSON.stringify(a.value).replace(/^"/,"").replace(/"$/,""),a.alignment&&"string"==typeof a.alignment&&(b={text:b,alignment:a.alignment}),b}};return h}]),a.directive("uiGridExporter",["uiGridExporterConstants","uiGridExporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid),e.grid.exporter.$scope=a}}}])}(),function(){"use strict";var a=angular.module("ui.grid.importer",["ui.grid"]);a.constant("uiGridImporterConstants",{featureName:"importer"}),a.service("uiGridImporterService",["$q","uiGridConstants","uiGridImporterConstants","gridUtil","$compile","$interval","i18nService","$window",function(a,b,c,d,e,f,g,h){var i={initializeGrid:function(a,b){b.importer={$scope:a},this.defaultGridOptions(b.options);var c={events:{importer:{}},methods:{importer:{importFile:function(a){i.importThisFile(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.options.enableImporter&&b.options.importerShowMenu&&(b.api.core.addToGridMenu?i.addToMenu(b):f(function(){b.api.core.addToGridMenu&&i.addToMenu(b)},100,1))},defaultGridOptions:function(a){a.enableImporter||void 0===a.enableImporter?h.hasOwnProperty("File")&&h.hasOwnProperty("FileReader")&&h.hasOwnProperty("FileList")&&h.hasOwnProperty("Blob")?a.enableImporter=!0:(d.logError("The File APIs are not fully supported in this browser, grid importer cannot be used."),a.enableImporter=!1):a.enableImporter=!1,a.importerProcessHeaders=a.importerProcessHeaders||i.processHeaders,a.importerHeaderFilter=a.importerHeaderFilter||function(a){return a},a.importerErrorCallback&&"function"==typeof a.importerErrorCallback||delete a.importerErrorCallback,a.enableImporter!==!0||a.importerDataAddCallback||(d.logError("You have not set an importerDataAddCallback, importer is disabled"),a.enableImporter=!1),a.importerShowMenu=a.importerShowMenu!==!1,a.importerObjectCallback=a.importerObjectCallback||function(a,b){return b}},addToMenu:function(a){a.api.core.addToGridMenu(a,[{title:g.getSafeText("gridMenu.importerTitle")},{templateUrl:"ui-grid/importerMenuItemContainer",action:function(){this.grid.api.importer.importAFile(a)}}])},importThisFile:function(a,b){if(!b)return void d.logError("No file object provided to importThisFile, should be impossible, aborting");var c=new FileReader;switch(b.type){case"application/json":c.onload=i.importJsonClosure(a);break;default:c.onload=i.importCsvClosure(a)}c.readAsText(b)},importJsonClosure:function(a){return function(b){var c,d=[];angular.forEach(i.parseJson(a,b),function(b){c=i.newObject(a),angular.extend(c,b),c=a.options.importerObjectCallback(a,c),d.push(c)}),i.addObjects(a,d)}},parseJson:function(a,b){var c;try{c=JSON.parse(b.target.result)}catch(d){return void i.alertError(a,"importer.invalidJson","File could not be processed, is it valid json? Content was: ",b.target.result)}return Array.isArray(c)?c:(i.alertError(a,"importer.jsonNotarray","Import failed, file is not an array, file was: ",b.target.result),[])},importCsvClosure:function(a){return function(b){var c=i.parseCsv(b);if(!c||c.length<1)return void i.alertError(a,"importer.invalidCsv","File could not be processed, is it valid csv? Content was: ",b.target.result);var d=i.createCsvObjects(a,c);return d&&0!==d.length?void i.addObjects(a,d):void i.alertError(a,"importer.noObjects","Objects were not able to be derived, content was: ",b.target.result)}},parseCsv:function(a){var b=a.target.result;return CSV.parse(b)},createCsvObjects:function(a,b){var c=a.options.importerProcessHeaders(a,b.shift());if(!c||0===c.length)return i.alertError(a,"importer.noHeaders","Column names could not be derived, content was: ",b),[];var d,e=[];return angular.forEach(b,function(b){d=i.newObject(a),angular.forEach(b,function(a,b){null!==c[b]&&(d[c[b]]=a)}),d=a.options.importerObjectCallback(a,d),e.push(d)}),e},processHeaders:function(a,b){var c=[];if(a.options.columnDefs&&0!==a.options.columnDefs.length){var d=i.flattenColumnDefs(a,a.options.columnDefs);return angular.forEach(b,function(a){c.push(d[a]?d[a]:d[a.toLowerCase()]?d[a.toLowerCase()]:null)}),c}return angular.forEach(b,function(a){c.push(a.replace(/[^0-9a-zA-Z\-_]/g,"_"))}),c},flattenColumnDefs:function(a,b){var c={};return angular.forEach(b,function(b){b.name&&(c[b.name]=b.field||b.name,c[b.name.toLowerCase()]=b.field||b.name),b.field&&(c[b.field]=b.field||b.name,c[b.field.toLowerCase()]=b.field||b.name),b.displayName&&(c[b.displayName]=b.field||b.name,c[b.displayName.toLowerCase()]=b.field||b.name),b.displayName&&a.options.importerHeaderFilter&&(c[a.options.importerHeaderFilter(b.displayName)]=b.field||b.name,c[a.options.importerHeaderFilter(b.displayName).toLowerCase()]=b.field||b.name)}),c},addObjects:function(a,c){if(a.api.rowEdit){var d=a.registerDataChangeCallback(function(){a.api.rowEdit.setRowsDirty(c),d()},[b.dataChange.ROW]);a.importer.$scope.$on("$destroy",d)}a.importer.$scope.$apply(a.options.importerDataAddCallback(a,c))},newObject:function(a){return"undefined"!=typeof a.options&&"undefined"!=typeof a.options.importerNewObject?new a.options.importerNewObject:{}},alertError:function(a,b,c,e){a.options.importerErrorCallback?a.options.importerErrorCallback(a,b,c,e):(h.alert(g.getSafeText(b)),d.logError(c+e))}};return i}]),a.directive("uiGridImporter",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(a,e.grid)}}}]),a.directive("uiGridImporterMenuItem",["uiGridImporterConstants","uiGridImporterService","gridUtil","$compile",function(a,b,c){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,templateUrl:"ui-grid/importerMenuItem",link:function(a,d,e,f){var g=function(a){var c=a.srcElement||a.target;if(c&&c.files&&1===c.files.length){var d=c.files[0];b.importThisFile(i,d),c.form.reset()}},h=d[0].querySelectorAll(".ui-grid-importer-file-chooser"),i=f.grid;1!==h.length?c.logError("Found > 1 or < 1 file choosers within the menu item, error, cannot continue"):h[0].addEventListener("change",g,!1)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.infiniteScroll",["ui.grid"]);a.service("uiGridInfiniteScrollService",["gridUtil","$compile","$timeout","uiGridConstants",function(a,b,c,d){var e={initializeGrid:function(a){e.defaultGridOptions(a.options);var b={events:{infiniteScroll:{needLoadMoreData:function(){},needLoadMoreDataTop:function(){}}},methods:{infiniteScroll:{dataLoaded:function(){a.options.loadTimout=!1}}}};a.options.loadTimout=!1,a.api.registerEventsFromObject(b.events),a.api.registerMethodsFromObject(b.methods)},defaultGridOptions:function(a){a.enableInfiniteScroll=a.enableInfiniteScroll!==!1},loadData:function(a){return a.options.loadTimout=!0,a.scrollDirection===d.scrollDirection.UP?void a.api.infiniteScroll.raise.needLoadMoreDataTop():void a.api.infiniteScroll.raise.needLoadMoreData()},checkScroll:function(a,b){var c=a.options.infiniteScrollPercentage?a.options.infiniteScrollPercentage:20;return!a.options.loadTimout&&c>=b?(this.loadData(a),!0):!1}};return e}]),a.directive("uiGridInfiniteScroll",["uiGridInfiniteScrollService",function(a){return{priority:-200,scope:!1,require:"^uiGrid",compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","gridUtil","uiGridInfiniteScrollService","uiGridConstants",function(a,b,c,d){return{priority:-200,scope:!1,link:function(a){a.grid.options.enableInfiniteScroll&&a.grid.api.core.on.scrollEvent(a,function(b){if(b.y&&"ui.grid.adjustInfiniteScrollPosition"!==b.source){var e=100-100*b.y.percentage;a.grid.scrollDirection===d.scrollDirection.UP&&(e=100*b.y.percentage),c.checkScroll(a.grid,e)}})}}}])}(),function(){"use strict";var a=angular.module("ui.grid.moveColumns",["ui.grid"]);
    +a.service("uiGridMoveColumnService",["$q","$timeout","$log","ScrollEvent","uiGridConstants",function(a,b,c,d,e){var f={initializeGrid:function(a){var b=this;this.registerPublicApi(a),this.defaultGridOptions(a.options),a.registerColumnBuilder(b.movableColumnBuilder)},registerPublicApi:function(a){var b=this,c={events:{colMovable:{columnPositionChanged:function(){}}},methods:{colMovable:{moveColumn:function(c,d){var e=a.columns;if(!angular.isNumber(c)||!angular.isNumber(d))return void console.log("Please provide valid values for originalPosition and finalPosition");for(var f=0,g=0;g<e.length;g++)(angular.isDefined(e[g].colDef.visible)&&e[g].colDef.visible===!1||e[g].isRowHeader===!0)&&f++;if(c>=e.length-f||d>=e.length-f)return void console.log("Invalid values for originalPosition, finalPosition");var h=function(a){for(var b=a,c=0;b>=c;c++)angular.isDefined(e[c])&&(angular.isDefined(e[c].colDef.visible)&&e[c].colDef.visible===!1||e[c].isRowHeader===!0)&&b++;return b};b.redrawColumnAtPosition(a,h(c),h(d))}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableColumnMoving=a.enableColumnMoving!==!1},movableColumnBuilder:function(b,c,d){var e=[];return b.enableColumnMoving=void 0===b.enableColumnMoving?d.enableColumnMoving:b.enableColumnMoving,a.all(e)},redrawColumnAtPosition:function(a,c,d){var f=a.columns,g=f[c];if(g.colDef.enableColumnMoving){if(c>d)for(var h=c;h>d;h--)f[h]=f[h-1];else if(d>c)for(var i=c;d>i;i++)f[i]=f[i+1];f[d]=g,b(function(){a.api.core.notifyDataChange(e.dataChange.COLUMN),a.refresh(),a.api.colMovable.raise.columnPositionChanged(g.colDef,c,d)})}}};return f}]),a.directive("uiGridMoveColumns",["uiGridMoveColumnService",function(a){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(b,c,d,e){a.initializeGrid(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["$q","gridUtil","uiGridMoveColumnService","$document","$log","uiGridConstants","ScrollEvent",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,e,h,i){a.col.colDef.enableColumnMoving&&a.$on(f.events.COLUMN_HEADER_CLICK,function(f,h){if(h.columnName===a.col.colDef.name&&!a.col.renderContainer){var j=h.event;if("ui-grid-icon-angle-down"!==j.target.className&&"I"!==j.target.tagName&&j.target.className.indexOf("ui-grid-filter-input")<0){var k,l,m=a.grid.element[0].getBoundingClientRect().left,n=j.pageX,o=0,p=m+a.grid.getViewportWidth(),q=!1,r=function(){q=!0,k=e.clone(),e.parent().append(k),k.addClass("movingColumn");var b={},c=e[0].getBoundingClientRect().left;b.left=c-m+"px";var d=a.grid.element[0].getBoundingClientRect().right,f=e[0].getBoundingClientRect().right;f>d&&(l=a.col.drawnWidth+(d-f),b.width=l+"px"),k.css(b)},s=function(c){i.fireEvent("hide-menu");for(var d=a.grid.columns,e=0,f=0;f<d.length;f++)(angular.isUndefined(d[f].colDef.visible)||d[f].colDef.visible===!0)&&(e+=d[f].drawnWidth||d[f].width||d[f].colDef.width);var h,j=k[0].getBoundingClientRect().left-1,n=k[0].getBoundingClientRect().right;if(h="ie"===b.detectBrowser()?j+c:j-m+c,h=p>h?h:p,(j>=m||c>0)&&(p>=n||0>c))k.css({visibility:"visible",left:h+"px"});else if(e>Math.ceil(i.grid.gridWidth)){c*=8;var q=new g(a.col.grid,null,null,"uiGridHeaderCell.moveElement");q.x={pixels:c},q.fireScrollingEvent()}for(var r=0,s=0;s<d.length;s++)if(angular.isUndefined(d[s].colDef.visible)||d[s].colDef.visible===!0){if(d[s].colDef.name===a.col.colDef.name)break;r+=d[s].drawnWidth||d[s].width||d[s].colDef.width}void 0===a.newScrollLeft?o+=c:o=a.newScrollLeft+h-r,l<a.col.drawnWidth&&(l+=Math.abs(c),k.css({width:l+"px"}))},t=function(a){document.onselectstart=function(){return!1};var b=a.pageX-n;!q&&Math.abs(b)>50?r():q&&(s(b),n=a.pageX)};d.on("mousemove",t);var u=function(){document.onselectstart=null,k&&k.remove();for(var b=a.grid.columns,e=0,f=0;f<b.length&&b[f].colDef.name!==a.col.colDef.name;f++)e++;if(0>o){for(var g=0,h=e-1;h>=0;h--)if((angular.isUndefined(b[h].colDef.visible)||b[h].colDef.visible===!0)&&(g+=b[h].drawnWidth||b[h].width||b[h].colDef.width,g>Math.abs(o))){c.redrawColumnAtPosition(a.grid,e,h+1);break}g<Math.abs(o)&&c.redrawColumnAtPosition(a.grid,e,0)}else if(o>0){for(var i=0,j=e+1;j<b.length;j++)if((angular.isUndefined(b[j].colDef.visible)||b[j].colDef.visible===!0)&&(i+=b[j].drawnWidth||b[j].width||b[j].colDef.width,i>o)){c.redrawColumnAtPosition(a.grid,e,j-1);break}o>i&&c.redrawColumnAtPosition(a.grid,e,b.length-1)}d.off("mousemove",t),d.off("mouseup",u)};d.on("mouseup",u)}}})}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pagination",["ng","ui.grid"]);a.service("uiGridPaginationService",["gridUtil",function(a){var b={initializeGrid:function(a){b.defaultGridOptions(a.options);var c={events:{pagination:{paginationChanged:function(){}}},methods:{pagination:{getPage:function(){return a.options.enablePagination?a.options.paginationCurrentPage:null},getTotalPages:function(){return a.options.enablePagination?0===a.options.totalItems?1:Math.ceil(a.options.totalItems/a.options.paginationPageSize):null},nextPage:function(){a.options.enablePagination&&(a.options.totalItems>0?a.options.paginationCurrentPage=Math.min(a.options.paginationCurrentPage+1,c.methods.pagination.getTotalPages()):a.options.paginationCurrentPage++)},previousPage:function(){a.options.enablePagination&&(a.options.paginationCurrentPage=Math.max(a.options.paginationCurrentPage-1,1))},seek:function(b){if(a.options.enablePagination){if(!angular.isNumber(b)||1>b)throw"Invalid page number: "+b;a.options.paginationCurrentPage=Math.min(b,c.methods.pagination.getTotalPages())}}}}};a.api.registerEventsFromObject(c.events),a.api.registerMethodsFromObject(c.methods),a.registerRowsProcessor(function(b){if(a.options.useExternalPagination||!a.options.enablePagination)return b;var c=parseInt(a.options.paginationPageSize,10),d=parseInt(a.options.paginationCurrentPage,10),e=b.filter(function(a){return a.visible});a.options.totalItems=e.length;var f=(d-1)*c;return f>e.length&&(d=a.options.paginationCurrentPage=1,f=(d-1)*c),e.slice(f,f+c)})},defaultGridOptions:function(b){b.enablePagination=b.enablePagination!==!1,b.enablePaginationControls=b.enablePaginationControls!==!1,b.useExternalPagination=b.useExternalPagination===!0,a.isNullOrUndefined(b.totalItems)&&(b.totalItems=0),a.isNullOrUndefined(b.paginationPageSizes)&&(b.paginationPageSizes=[250,500,1e3]),a.isNullOrUndefined(b.paginationPageSize)&&(b.paginationPageSize=b.paginationPageSizes.length>0?b.paginationPageSizes[0]:0),a.isNullOrUndefined(b.paginationCurrentPage)&&(b.paginationCurrentPage=1),a.isNullOrUndefined(b.paginationTemplate)&&(b.paginationTemplate="ui-grid/pagination")},onPaginationChanged:function(a,b,c){a.api.pagination.raise.paginationChanged(b,c),a.options.useExternalPagination||a.refresh()}};return b}]),a.directive("uiGridPagination",["gridUtil","uiGridPaginationService",function(a,b){return{priority:-200,scope:!1,require:"uiGrid",link:{pre:function(c,d,e,f){b.initializeGrid(f.grid),a.getTemplate(f.grid.options.paginationTemplate).then(function(a){var b=angular.element(a);d.append(b),f.innerCompile(b)})}}}}]),a.directive("uiGridPager",["uiGridPaginationService","uiGridConstants","gridUtil","i18nService",function(a,b,c,d){return{priority:-200,scope:!0,require:"^uiGrid",link:function(e,f,g,h){e.paginationApi=h.grid.api.pagination,e.sizesLabel=d.getSafeText("pagination.sizes"),e.totalItemsLabel=d.getSafeText("pagination.totalItems");var i=h.grid.options;h.grid.renderContainers.body.registerViewportAdjuster(function(a){return a.height=a.height-c.elementHeight(f),a});var j=h.grid.registerDataChangeCallback(function(a){a.options.useExternalPagination||(a.options.totalItems=a.rows.length)},[b.dataChange.ROW]);e.$on("$destroy",j);var k=function(){e.showingLow=(i.paginationCurrentPage-1)*i.paginationPageSize+1,e.showingHigh=Math.min(i.paginationCurrentPage*i.paginationPageSize,i.totalItems)},l=e.$watch("grid.options.totalItems + grid.options.paginationPageSize",k),m=e.$watch("grid.options.paginationCurrentPage + grid.options.paginationPageSize",function(b,c){if(b!==c){if(!angular.isNumber(i.paginationCurrentPage)||i.paginationCurrentPage<1)return void(i.paginationCurrentPage=1);if(i.totalItems>0&&i.paginationCurrentPage>e.paginationApi.getTotalPages())return void(i.paginationCurrentPage=e.paginationApi.getTotalPages());k(),a.onPaginationChanged(e.grid,i.paginationCurrentPage,i.paginationPageSize)}});e.$on("$destroy",function(){l(),m()}),e.cantPageForward=function(){return i.totalItems>0?i.paginationCurrentPage>=e.paginationApi.getTotalPages():i.data.length<1},e.cantPageToLast=function(){return i.totalItems>0?e.cantPageForward():!0},e.cantPageBackward=function(){return i.paginationCurrentPage<=1}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.pinning",["ui.grid"]);a.service("uiGridPinningService",["gridUtil","GridRenderContainer","i18nService",function(a,b,c){var d={initializeGrid:function(a){d.defaultGridOptions(a.options),a.registerColumnBuilder(d.pinningColumnBuilder)},defaultGridOptions:function(a){a.enablePinning=a.enablePinning!==!1},pinningColumnBuilder:function(b,d,e){if(b.enablePinning=void 0===b.enablePinning?e.enablePinning:b.enablePinning,b.pinnedLeft?"*"===d.width?d.grid.refresh().then(function(){d.renderContainer="left",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createLeftContainer()}):(d.renderContainer="left",d.grid.createLeftContainer()):b.pinnedRight&&("*"===d.width?d.grid.refresh().then(function(){d.renderContainer="right",d.width=d.grid.canvasWidth/d.grid.columns.length,d.grid.createRightContainer()}):(d.renderContainer="right",d.grid.createRightContainer())),b.enablePinning){var f={name:"ui.grid.pinning.pinLeft",title:c.get().pinning.pinLeft,icon:"ui-grid-icon-left-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"left"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="left",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createLeftContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},g={name:"ui.grid.pinning.pinRight",title:c.get().pinning.pinRight,icon:"ui-grid-icon-right-open",shown:function(){return"undefined"==typeof this.context.col.renderContainer||!this.context.col.renderContainer||"right"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer="right",this.context.col.width=this.context.col.drawnWidth,this.context.col.grid.createRightContainer(),d.grid.refresh().then(function(){d.grid.refresh()})}},h={name:"ui.grid.pinning.unpin",title:c.get().pinning.unpin,icon:"ui-grid-icon-cancel",shown:function(){return"undefined"!=typeof this.context.col.renderContainer&&null!==this.context.col.renderContainer&&"body"!==this.context.col.renderContainer},action:function(){this.context.col.renderContainer=null,d.grid.refresh().then(function(){d.grid.refresh()})}};a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinLeft")||d.menuItems.push(f),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.pinRight")||d.menuItems.push(g),a.arrayContainsObjectWithProperty(d.menuItems,"name","ui.grid.pinning.unpin")||d.menuItems.push(h)}}};return d}]),a.directive("uiGridPinning",["gridUtil","uiGridPinningService",function(a,b){return{require:"uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(e.grid)},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.resizeColumns",["ui.grid"]);a.service("uiGridResizeColumnsService",["gridUtil","$q","$timeout",function(a,b,c){var d={defaultGridOptions:function(a){a.enableColumnResizing=a.enableColumnResizing!==!1,a.enableColumnResize===!1&&(a.enableColumnResizing=!1)},colResizerColumnBuilder:function(a,c,d){var e=[];return a.enableColumnResizing=void 0===a.enableColumnResizing?d.enableColumnResizing:a.enableColumnResizing,a.enableColumnResize===!1&&(a.enableColumnResizing=!1),b.all(e)},registerPublicApi:function(a){var b={events:{colResizable:{columnSizeChanged:function(){}}}};a.api.registerEventsFromObject(b.events)},fireColumnSizeChanged:function(a,b,d){c(function(){a.api.colResizable.raise.columnSizeChanged(b,d)})},findTargetCol:function(a,b,c){var d=a.getRenderContainer();if("left"===b){var e=d.visibleColumnCache.indexOf(a);return d.visibleColumnCache[e-1*c]}return a}};return d}]),a.directive("uiGridResizeColumns",["gridUtil","uiGridResizeColumnsService",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.defaultGridOptions(e.grid.options),e.grid.registerColumnBuilder(b.colResizerColumnBuilder),b.registerPublicApi(e.grid)},post:function(){}}}}}]),a.directive("uiGridHeaderCell",["gridUtil","$templateCache","$compile","$q","uiGridResizeColumnsService","uiGridConstants","$timeout",function(a,b,c,d,e,f,g){return{priority:-10,require:"^uiGrid",compile:function(){return{post:function(a,d,h,i){var j=i.grid;if(j.options.enableColumnResizing){var k=b.get("ui-grid/columnResizer"),l=1;j.isRTL()&&(a.position="left",l=-1);var m=function(){for(var b=d[0].getElementsByClassName("ui-grid-column-resizer"),f=0;f<b.length;f++)angular.element(b[f]).remove();var g=e.findTargetCol(a.col,"left",l),h=a.col.getRenderContainer();if(g&&0!==h.visibleColumnCache.indexOf(a.col)&&g.colDef.enableColumnResizing!==!1){var i=angular.element(k).clone();i.attr("position","left"),d.prepend(i),c(i)(a)}if(a.col.colDef.enableColumnResizing!==!1){var j=angular.element(k).clone();j.attr("position","right"),d.append(j),c(j)(a)}};m();var n=function(){g(m)},o=j.registerDataChangeCallback(n,[f.dataChange.COLUMN]);a.$on("$destroy",o)}}}}}}]),a.directive("uiGridColumnResizer",["$document","gridUtil","uiGridConstants","uiGridResizeColumnsService",function(a,b,c,d){var e,f,g,h=angular.element('<div class="ui-grid-resize-overlay"></div>');b.isTouchEnabled()?(e="touchstart",f="touchend",g="touchmove"):(e="mousedown",f="mouseup",g="mousemove");var i={priority:0,scope:{col:"=",position:"@",renderIndex:"="},require:"?^uiGrid",link:function(i,j,k,l){function m(a){var b=a.getRenderContainer();b.visibleColumnCache.forEach(function(b){if(b!==a){var c=b.colDef;(!c.width||angular.isString(c.width)&&(-1!==c.width.indexOf("*")||-1!==c.width.indexOf("%")))&&(b.width=b.drawnWidth)}})}function n(){l.grid.buildColumns().then(function(){l.grid.refreshCanvas(!0).then(function(){l.grid.refresh()})})}function o(a,b){var c=b;return a.colDef.minWidth&&c<a.colDef.minWidth?c=a.colDef.minWidth:a.colDef.maxWidth&&c>a.colDef.maxWidth&&(c=a.colDef.maxWidth),c}function p(a){a.originalEvent&&(a=a.originalEvent),a.preventDefault(),s=(a.targetTouches?a.targetTouches[0]:a).clientX-t,0>s?s=0:s>l.grid.gridWidth&&(s=l.grid.gridWidth);var b=d.findTargetCol(i.col,i.position,u);if(b.colDef.enableColumnResizing!==!1){l.grid.element.hasClass("column-resizing")||l.grid.element.addClass("column-resizing");var e=s-r,f=parseInt(b.drawnWidth+e*u,10);s+=(o(b,f)-f)*u,h.css({left:s+"px"}),l.fireEvent(c.events.ITEM_DRAGGING)}}function q(b){b.originalEvent&&(b=b.originalEvent),b.preventDefault(),l.grid.element.removeClass("column-resizing"),h.remove(),s=(b.changedTouches?b.changedTouches[0]:b).clientX-t;var c=s-r;if(0===c)return a.off(f,q),void a.off(g,p);var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var j=parseInt(e.drawnWidth+c*u,10);e.width=o(e,j),m(e),n(c),d.fireColumnSizeChanged(l.grid,e.colDef,c),a.off(f,q),a.off(g,p)}}var r=0,s=0,t=0,u=1;l.grid.isRTL()&&(i.position="left",u=-1),"left"===i.position?j.addClass("left"):"right"===i.position&&j.addClass("right"),j.on(e,function(b){b.originalEvent&&(b=b.originalEvent),b.stopPropagation(),t=l.grid.element[0].getBoundingClientRect().left,r=(b.targetTouches?b.targetTouches[0]:b).clientX-t,l.grid.element.append(h),h.css({left:r}),a.on(f,q),a.on(g,p)}),j.on("dblclick",function(a){a.stopPropagation();var e=d.findTargetCol(i.col,i.position,u);if(e.colDef.enableColumnResizing!==!1){var f=0,g=0,h=b.closestElm(j,".ui-grid-render-container"),k=h.querySelectorAll("."+c.COL_CLASS_PREFIX+e.uid+" .ui-grid-cell-contents");Array.prototype.forEach.call(k,function(a){var c;angular.element(a).parent().hasClass("ui-grid-header-cell")&&(c=angular.element(a).parent()[0].querySelectorAll(".ui-grid-column-menu-button")),b.fakeElement(a,{},function(a){var d=angular.element(a);d.attr("style","float: left");var e=b.elementWidth(d);if(c){var h=b.elementWidth(c);e+=h}e>f&&(f=e,g=f-e)})}),e.width=o(e,f),m(e),n(g),d.fireColumnSizeChanged(l.grid,e.colDef,g)}}),j.on("$destroy",function(){j.off(e),j.off("dblclick"),a.off(g,p),a.off(f,q)})}};return i}])}(),function(){"use strict";var a=angular.module("ui.grid.rowEdit",["ui.grid","ui.grid.edit","ui.grid.cellNav"]);a.constant("uiGridRowEditConstants",{}),a.service("uiGridRowEditService",["$interval","$q","uiGridConstants","uiGridRowEditConstants","gridUtil",function(a,b,c,d,e){var f={initializeGrid:function(a,b){b.rowEdit={};var c={events:{rowEdit:{saveRow:function(){}}},methods:{rowEdit:{setSavePromise:function(a,c){f.setSavePromise(b,a,c)},getDirtyRows:function(){return b.rowEdit.dirtyRows?b.rowEdit.dirtyRows:[]},getErrorRows:function(){return b.rowEdit.errorRows?b.rowEdit.errorRows:[]},flushDirtyRows:function(){return f.flushDirtyRows(b)},setRowsDirty:function(a){f.setRowsDirty(b,a)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods),b.api.core.on.renderingComplete(a,function(){b.api.edit.on.afterCellEdit(a,f.endEditCell),b.api.edit.on.beginCellEdit(a,f.beginEditCell),b.api.edit.on.cancelCellEdit(a,f.cancelEditCell),b.api.cellNav&&b.api.cellNav.on.navigate(a,f.navigate)})},defaultGridOptions:function(){},saveRow:function(a,b){var c=this;return function(){b.isSaving=!0;var d=a.api.rowEdit.raise.saveRow(b.entity);return b.rowEditSavePromise?b.rowEditSavePromise.then(c.processSuccessPromise(a,b),c.processErrorPromise(a,b)):e.logError("A promise was not returned when saveRow event was raised, either nobody is listening to event, or event handler did not return a promise"),d}},setSavePromise:function(a,b,c){var d=a.getRow(b);d.rowEditSavePromise=c},processSuccessPromise:function(a,b){var c=this;return function(){delete b.isSaving,delete b.isDirty,delete b.isError,delete b.rowEditSaveTimer,c.removeRow(a.rowEdit.errorRows,b),c.removeRow(a.rowEdit.dirtyRows,b)}},processErrorPromise:function(a,b){return function(){delete b.isSaving,delete b.rowEditSaveTimer,b.isError=!0,a.rowEdit.errorRows||(a.rowEdit.errorRows=[]),f.isRowPresent(a.rowEdit.errorRows,b)||a.rowEdit.errorRows.push(b)}},removeRow:function(a,b){angular.forEach(a,function(c,d){c.uid===b.uid&&a.splice(d,1)})},isRowPresent:function(a,b){var c=!1;return angular.forEach(a,function(a){a.uid===b.uid&&(c=!0)}),c},flushDirtyRows:function(a){var c=[];return angular.forEach(a.rowEdit.dirtyRows,function(b){f.saveRow(a,b)(),c.push(b.rowEditSavePromise)}),b.all(c)},endEditCell:function(a,b,c,d){var g=this.grid,h=g.getRow(a);return h?void((c!==d||h.isDirty)&&(g.rowEdit.dirtyRows||(g.rowEdit.dirtyRows=[]),h.isDirty||(h.isDirty=!0,g.rowEdit.dirtyRows.push(h)),delete h.isError,f.considerSetTimer(g,h))):void e.logError("Unable to find rowEntity in grid data, dirty flag cannot be set")},beginEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.cancelTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be cancelled")},cancelEditCell:function(a){var b=this.grid,c=b.getRow(a);return c?void f.considerSetTimer(b,c):void e.logError("Unable to find rowEntity in grid data, timer cannot be set")},navigate:function(a,b){var c=this.grid;a.row.rowEditSaveTimer&&f.cancelTimer(c,a.row),b&&b.row&&b.row!==a.row&&f.considerSetTimer(c,b.row)},considerSetTimer:function(b,c){if(f.cancelTimer(b,c),c.isDirty&&!c.isSaving&&-1!==b.options.rowEditWaitInterval){var d=b.options.rowEditWaitInterval?b.options.rowEditWaitInterval:2e3;c.rowEditSaveTimer=a(f.saveRow(b,c),d,1)}},cancelTimer:function(b,c){c.rowEditSaveTimer&&!c.isSaving&&(a.cancel(c.rowEditSaveTimer),delete c.rowEditSaveTimer)},setRowsDirty:function(a,b){var c;b.forEach(function(b){c=a.getRow(b),c?(a.rowEdit.dirtyRows||(a.rowEdit.dirtyRows=[]),c.isDirty||(c.isDirty=!0,a.rowEdit.dirtyRows.push(c)),delete c.isError,f.considerSetTimer(a,c)):e.logError("requested row not found in rowEdit.setRowsDirty, row was: "+b)})}};return f}]),a.directive("uiGridRowEdit",["gridUtil","uiGridRowEditService","uiGridEditConstants",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(a,c,d,e){b.initializeGrid(a,e.grid)},post:function(){}}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","gridUtil","$parse",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";return d=c?c.slice(0,-1)+", 'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}":"{'ui-grid-row-dirty': row.isDirty, 'ui-grid-row-saving': row.isSaving, 'ui-grid-row-error': row.isError}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}])}(),function(){"use strict";var a=angular.module("ui.grid.saveState",["ui.grid","ui.grid.selection","ui.grid.cellNav"]);a.constant("uiGridSaveStateConstants",{featureName:"saveState"}),a.service("uiGridSaveStateService",["$q","uiGridSaveStateConstants","gridUtil","$compile","$interval","uiGridConstants",function(){var a={initializeGrid:function(b){b.saveState={},this.defaultGridOptions(b.options);var c={events:{saveState:{}},methods:{saveState:{save:function(){return a.save(b)},restore:function(c,d){a.restore(b,c,d)}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.saveWidths=a.saveWidths!==!1,a.saveOrder=a.saveOrder!==!1,a.saveScroll=a.saveScroll===!0,a.saveFocus=a.saveScroll!==!0&&a.saveFocus!==!1,a.saveVisible=a.saveVisible!==!1,a.saveSort=a.saveSort!==!1,a.saveFilter=a.saveFilter!==!1,a.saveSelection=a.saveSelection!==!1},save:function(b){var c={};return c.columns=a.saveColumns(b),c.scrollFocus=a.saveScrollFocus(b),c.selection=a.saveSelection(b),c},restore:function(b,c,d){d.columns&&a.restoreColumns(b,d.columns),d.scrollFocus&&a.restoreScrollFocus(b,c,d.scrollFocus),d.selection&&a.restoreSelection(b,d.selection),b.refresh()},saveColumns:function(a){var b=[];return angular.forEach(a.columns,function(a){var c={};c.name=a.name,c.visible=a.visible,c.width=a.width,c.sort=angular.copy(a.sort),c.filters=angular.copy(a.filters),b.push(c)}),b},saveScrollFocus:function(b){if(!b.api.cellNav)return{};var c={};if(b.options.saveFocus){c.focus=!0;var d=b.api.cellNav.getFocusedCell();null!==d&&(c.colName=d.col.colDef.name,c.rowVal=a.getRowVal(b,d.row))}else b.options.saveScroll&&(c.focus=!1,b.renderContainers.body.prevRowScrollIndex&&(c.rowVal=a.getRowVal(b,b.renderContainers.body.visibleRowCache[b.renderContainers.body.prevRowScrollIndex])),b.renderContainers.body.prevColScrollIndex&&(c.colName=b.renderContainers.body.visibleColumnCache[b.renderContainers.body.prevColScrollIndex].name));return c},saveSelection:function(b){if(!b.api.selection||!b.options.saveSelection)return{};var c=b.api.selection.getSelectedGridRows().map(function(c){return a.getRowVal(b,c)});return c},getRowVal:function(a,b){if(!b)return null;var c={};return a.options.saveRowIdentity?(c.identity=!0,c.row=a.options.saveRowIdentity(b.entity)):(c.identity=!1,c.row=a.renderContainers.body.visibleRowCache.indexOf(b)),c},restoreColumns:function(a,b){angular.forEach(b,function(b,c){var d=a.columns.filter(function(a){return a.name===b.name});if(d.length>0){var e=a.columns.indexOf(d[0]);if((a.columns[e].visible!==b.visible||a.columns[e].colDef.visible!==b.visible)&&(a.columns[e].visible=b.visible,a.columns[e].colDef.visible=b.visible,a.api.core.raise.columnVisibilityChanged(a.columns[e])),a.columns[e].width=b.width,angular.equals(a.columns[e].sort,b.sort)||void 0===a.columns[e].sort&&angular.isEmpty(b.sort)||(a.columns[e].sort=angular.copy(b.sort),a.api.core.raise.sortChanged()),angular.equals(a.columns[e].filters,b.filters)||(a.columns[e].filters=angular.copy(b.filters),a.api.core.raise.filterChanged()),e!==c){var f=a.columns.splice(e,1)[0];a.columns.splice(c,0,f)}}})},restoreScrollFocus:function(b,c,d){if(b.api.cellNav){var e,f;if(d.colName){var g=b.options.columnDefs.filter(function(a){return a.name===d.colName});g.length>0&&(e=g[0])}d.rowVal&&d.rowVal.row&&(f=d.rowVal.identity?a.findRowByIdentity(b,d.rowVal):b.renderContainers.body.visibleRowCache[d.rowVal.row]);var h=f&&f.entity?f.entity:null;(e||h)&&(d.focus?b.api.cellNav.scrollToFocus(h,e):b.api.cellNav.scrollTo(h,e))}},restoreSelection:function(b,c){b.api.selection&&(b.api.selection.clearSelectedRows(),angular.forEach(c,function(c){if(c.identity){var d=a.findRowByIdentity(b,c);d&&b.api.selection.selectRow(d.entity)}else b.api.selection.selectRowByVisibleIndex(c.row)}))},findRowByIdentity:function(a,b){if(!a.options.saveRowIdentity)return null;var c=a.rows.filter(function(c){return a.options.saveRowIdentity(c.entity)===b.row?!0:!1});return c.length>0?c[0]:null}};return a}]),a.directive("uiGridSaveState",["uiGridSaveStateConstants","uiGridSaveStateService","gridUtil","$compile",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,link:function(a,c,d,e){b.initializeGrid(e.grid)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.selection",["ui.grid"]);a.constant("uiGridSelectionConstants",{featureName:"selection",selectionRowHeaderColName:"selectionRowHeaderCol"}),angular.module("ui.grid").config(["$provide",function(a){a.decorator("GridRow",["$delegate",function(a){return a.prototype.setSelected=function(a){this.isSelected=a,a?this.grid.selection.selectedCount++:this.grid.selection.selectedCount--},a}])}]),a.service("uiGridSelectionService",["$q","$templateCache","uiGridSelectionConstants","gridUtil",function(){var a={initializeGrid:function(b){b.selection={},b.selection.lastSelectedRow=null,b.selection.selectAll=!1,b.selection.selectedCount=0,a.defaultGridOptions(b.options);var c={events:{selection:{rowSelectionChanged:function(){},rowSelectionChangedBatch:function(){}}},methods:{selection:{toggleRowSelection:function(c,d){var e=b.getRow(c);null!==e&&e.enableSelection!==!1&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRow:function(c,d){var e=b.getRow(c);null===e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectRowByVisibleIndex:function(c,d){var e=b.renderContainers.body.visibleRowCache[c];null===e||"undefined"==typeof e||e.isSelected||e.enableSelection===!1||a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},unSelectRow:function(c,d){var e=b.getRow(c);null!==e&&e.isSelected&&a.toggleRowSelection(b,e,d,b.options.multiSelect,b.options.noUnselect)},selectAllRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},selectAllVisibleRows:function(c){if(b.options.multiSelect!==!1){var d=[];b.rows.forEach(function(e){e.visible?e.isSelected||e.enableSelection===!1||(e.setSelected(!0),a.decideRaiseSelectionEvent(b,e,d,c)):e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!0}},clearSelectedRows:function(c){a.clearSelectedRows(b,c)},getSelectedRows:function(){return a.getSelectedRows(b).map(function(a){return a.entity})},getSelectedGridRows:function(){return a.getSelectedRows(b)},setMultiSelect:function(a){b.options.multiSelect=a},setModifierKeysToMultiSelect:function(a){b.options.modifierKeysToMultiSelect=a},getSelectAllState:function(){return b.selection.selectAll}}}};b.api.registerEventsFromObject(c.events),b.api.registerMethodsFromObject(c.methods)},defaultGridOptions:function(a){a.enableRowSelection=a.enableRowSelection!==!1,a.multiSelect=a.multiSelect!==!1,a.noUnselect=a.noUnselect===!0,a.modifierKeysToMultiSelect=a.modifierKeysToMultiSelect===!0,a.enableRowHeaderSelection=a.enableRowHeaderSelection!==!1,a.enableSelectAll=a.enableSelectAll!==!1,a.enableSelectionBatchEvent=a.enableSelectionBatchEvent!==!1,a.selectionRowHeaderWidth=angular.isDefined(a.selectionRowHeaderWidth)?a.selectionRowHeaderWidth:30,a.enableFooterTotalSelected=a.enableFooterTotalSelected!==!1,a.isRowSelectable=angular.isDefined(a.isRowSelectable)?a.isRowSelectable:angular.noop},toggleRowSelection:function(b,c,d,e,f){var g=c.isSelected;if(e||g){if(!e&&g){var h=a.getSelectedRows(b);h.length>1&&(g=!1,a.clearSelectedRows(b,d))}}else a.clearSelectedRows(b,d);g&&f||c.enableSelection!==!1&&(c.setSelected(!g),c.isSelected===!0?b.selection.lastSelectedRow=c:b.selection.selectAll=!1,b.api.selection.raise.rowSelectionChanged(c,d))},shiftSelect:function(b,c,d,e){if(e){var f=a.getSelectedRows(b),g=f.length>0?b.renderContainers.body.visibleRowCache.indexOf(b.selection.lastSelectedRow):0,h=b.renderContainers.body.visibleRowCache.indexOf(c);if(g>h){var i=g;g=h,h=i}for(var j=[],k=g;h>=k;k++){var l=b.renderContainers.body.visibleRowCache[k];l&&(l.isSelected||l.enableSelection===!1||(l.setSelected(!0),b.selection.lastSelectedRow=l,a.decideRaiseSelectionEvent(b,l,j,d)))}a.decideRaiseSelectionBatchEvent(b,j,d)}},getSelectedRows:function(a){return a.rows.filter(function(a){return a.isSelected})},clearSelectedRows:function(b,c){var d=[];a.getSelectedRows(b).forEach(function(e){e.isSelected&&(e.setSelected(!1),a.decideRaiseSelectionEvent(b,e,d,c))}),a.decideRaiseSelectionBatchEvent(b,d,c),b.selection.selectAll=!1},decideRaiseSelectionEvent:function(a,b,c,d){a.options.enableSelectionBatchEvent?c.push(b):a.api.selection.raise.rowSelectionChanged(b,d)},decideRaiseSelectionBatchEvent:function(a,b,c){b.length>0&&a.api.selection.raise.rowSelectionChangedBatch(b,c)}};return a}]),a.directive("uiGridSelection",["uiGridSelectionConstants","uiGridSelectionService","$templateCache",function(a,b){return{replace:!0,priority:0,require:"^uiGrid",scope:!1,compile:function(){return{pre:function(c,d,e,f){if(b.initializeGrid(f.grid),f.grid.options.enableRowHeaderSelection){var g={name:a.selectionRowHeaderColName,displayName:"",width:f.grid.options.selectionRowHeaderWidth,minWidth:10,cellTemplate:"ui-grid/selectionRowHeader",headerCellTemplate:"ui-grid/selectionHeaderCell",enableColumnResizing:!1,enableColumnMenu:!1,exporterSuppressExport:!0};f.grid.addRowHeaderColumn(g)}f.grid.options.isRowSelectable!==angular.noop&&f.grid.registerRowBuilder(function(a){a.enableSelection=f.grid.options.isRowSelectable(a)})},post:function(){}}}}}]),a.directive("uiGridSelectionRowHeaderButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionRowHeaderButtons"),scope:!0,require:"^uiGrid",link:function(a,c,d,e){var f=e.grid;a.selectButtonClick=function(a,c){c.shiftKey?b.shiftSelect(f,a,c,f.options.multiSelect):c.ctrlKey||c.metaKey?b.toggleRowSelection(f,a,c,f.options.multiSelect,f.options.noUnselect):b.toggleRowSelection(f,a,c,f.options.multiSelect&&!f.options.modifierKeysToMultiSelect,f.options.noUnselect)}}}}]),a.directive("uiGridSelectionSelectAllButtons",["$templateCache","uiGridSelectionService",function(a,b){return{replace:!0,restrict:"E",template:a.get("ui-grid/selectionSelectAllButtons"),scope:!1,link:function(a){var c=a.col.grid;a.headerButtonClick=function(a,d){c.selection.selectAll?(b.clearSelectedRows(c,d),c.options.noUnselect&&c.api.selection.selectRowByVisibleIndex(0,d),c.selection.selectAll=!1):c.options.multiSelect&&(c.api.selection.selectAllVisibleRows(d),c.selection.selectAll=!0)}}}}]),a.directive("uiGridViewport",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(){return{priority:-200,scope:!1,compile:function(a){var b=angular.element(a.children().children()[0]),c=b.attr("ng-class"),d="";
    +return d=c?c.slice(0,-1)+",'ui-grid-row-selected': row.isSelected}":"{'ui-grid-row-selected': row.isSelected}",b.attr("ng-class",d),{pre:function(){},post:function(){}}}}}]),a.directive("uiGridCell",["$compile","uiGridConstants","uiGridSelectionConstants","gridUtil","$parse","uiGridSelectionService",function(a,b,c,d,e,f){return{priority:-200,restrict:"A",scope:!1,link:function(a,c){function d(){a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection&&(c.addClass("ui-grid-disable-selection"),c.on("touchstart",j),c.on("touchend",k),c.on("click",i),a.registered=!0)}function e(){a.registered&&(c.removeClass("ui-grid-disable-selection"),c.off("touchstart",j),c.off("touchend",k),c.off("click",i),a.registered=!1)}var g=0,h=300,i=function(b){b.shiftKey?f.shiftSelect(a.grid,a.row,b,a.grid.options.multiSelect):b.ctrlKey||b.metaKey?f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect,a.grid.options.noUnselect):f.toggleRowSelection(a.grid,a.row,b,a.grid.options.multiSelect&&!a.grid.options.modifierKeysToMultiSelect,a.grid.options.noUnselect),a.$apply()},j=function(){g=(new Date).getTime()},k=function(a){var b=(new Date).getTime(),c=b-g;h>c&&i(a)};d();var l=a.grid.registerDataChangeCallback(function(){!a.grid.options.enableRowSelection||a.grid.options.enableRowHeaderSelection||a.registered?a.grid.options.enableRowSelection&&!a.grid.options.enableRowHeaderSelection||!a.registered||e():d()},[b.dataChange.OPTIONS]);c.on("$destroy",l)}}}]),a.directive("uiGridGridFooter",["$compile","uiGridConstants","gridUtil",function(a,b,c){return{restrict:"EA",replace:!0,priority:-1e3,require:"^uiGrid",scope:!0,compile:function(){return{pre:function(b,d,e,f){f.grid.options.showGridFooter&&c.getTemplate("ui-grid/gridFooterSelectedItems").then(function(c){var e=angular.element(c),f=a(e)(b);angular.element(d[0].getElementsByClassName("ui-grid-grid-footer")[0]).append(f)})},post:function(){}}}}}])}(),angular.module("ui.grid").run(["$templateCache",function(a){"use strict";a.put("ui-grid/ui-grid-footer",'<div class="ui-grid-footer-panel ui-grid-footer-aggregates-row"><div class="ui-grid-footer ui-grid-footer-viewport"><div class="ui-grid-footer-canvas"><div class="ui-grid-footer-cell-wrapper" ng-style="colContainer.headerCellWrapperStyle()"><div class="ui-grid-footer-cell-row"><div ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-footer-cell col="col" render-index="$index" class="ui-grid-footer-cell ui-grid-clearfix"></div></div></div></div></div></div>'),a.put("ui-grid/ui-grid-grid-footer",'<div class="ui-grid-footer-info ui-grid-grid-footer"><span>{{\'search.totalItems\' | t}} {{grid.rows.length}}</span> <span ng-if="grid.renderContainers.body.visibleRowCache.length !== grid.rows.length" class="ngLabel">({{"search.showingItems" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>'),a.put("ui-grid/ui-grid-group-panel",'<div class="ui-grid-group-panel"><div ui-t="groupPanel.description" class="description" ng-show="groupings.length == 0"></div><ul ng-show="groupings.length > 0" class="ngGroupList"><li class="ngGroupItem" ng-repeat="group in configGroups"><span class="ngGroupElement"><span class="ngGroupName">{{group.displayName}} <span ng-click="removeGroup($index)" class="ngRemoveGroup">x</span></span> <span ng-hide="$last" class="ngGroupArrow"></span></span></li></ul></div>'),a.put("ui-grid/ui-grid-header",'<div class="ui-grid-header"><div class="ui-grid-top-panel"><div class="ui-grid-header-viewport"><div class="ui-grid-header-canvas"><div class="ui-grid-header-cell-wrapper" ng-style="colContainer.headerCellWrapperStyle()"><div class="ui-grid-header-cell-row"><div class="ui-grid-header-cell ui-grid-clearfix" ng-repeat="col in colContainer.renderedColumns track by col.colDef.name" ui-grid-header-cell col="col" render-index="$index"></div></div></div></div></div><div ui-grid-menu></div></div></div>'),a.put("ui-grid/ui-grid-menu-button",'<div class="ui-grid-menu-button" ng-click="toggleMenu()"><div class="ui-grid-icon-container"><i class="ui-grid-icon-menu">&nbsp;</i></div><div ui-grid-menu menu-items="menuItems"></div></div>'),a.put("ui-grid/ui-grid-no-header",'<div class="ui-grid-top-panel"></div>'),a.put("ui-grid/ui-grid-row",'<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>'),a.put("ui-grid/ui-grid",'<div ui-i18n="en" class="ui-grid"><!-- TODO (c0bra): add "scoped" attr here, eventually? --><style ui-grid-style>.grid{{ grid.id }} {\n      /* Styles for the grid */\n    }\n\n    .grid{{ grid.id }} .ui-grid-row, .grid{{ grid.id }} .ui-grid-cell, .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n      height: {{ grid.options.rowHeight }}px;\n    }\n\n    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n      border-bottom-width: {{ ((grid.getTotalRowHeight() < grid.getViewportHeight()) && \'1\') || \'0\' }}px;\n    }\n\n    {{ grid.verticalScrollbarStyles }}\n    {{ grid.horizontalScrollbarStyles }}\n\n    /*\n    .ui-grid[dir=rtl] .ui-grid-viewport {\n      padding-left: {{ grid.verticalScrollbarWidth }}px;\n    }\n    */\n\n    {{ grid.customStyles }}</style><div ui-grid-menu-button ng-if="grid.options.enableGridMenu"></div><div ng-if="grid.hasLeftContainer()" style="width: 0" ui-grid-pinned-container="\'left\'"></div><div ui-grid-render-container container-id="\'body\'" col-container-name="\'body\'" row-container-name="\'body\'" bind-scroll-horizontal="true" bind-scroll-vertical="true" enable-horizontal-scrollbar="grid.options.enableHorizontalScrollbar" enable-vertical-scrollbar="grid.options.enableVerticalScrollbar"></div><div ng-if="grid.hasRightContainer()" style="width: 0" ui-grid-pinned-container="\'right\'"></div><div ui-grid-grid-footer ng-if="grid.options.showGridFooter"></div><div ui-grid-column-menu ng-if="grid.options.enableColumnMenus"></div><div ng-transclude></div></div>'),a.put("ui-grid/uiGridCell",'<div class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS}}</div>'),a.put("ui-grid/uiGridColumnFilter",'<li class="ui-grid-menu-item ui-grid-clearfix ui-grid-column-filter" ng-show="itemShown()" ng-click="$event.stopPropagation();"><div class="input-container"><input class="column-filter-input" type="text" ng-model="item.model" placeholder="{{ i18n.search.placeholder }}"><div class="column-filter-cancel-icon-container"><i class="ui-grid-filter-cancel ui-grid-icon-cancel column-filter-cancel-icon">&nbsp;</i></div></div><div style="button-container" ng-click="item.action($event)"><div class="ui-grid-button"><i class="ui-grid-icon-search">&nbsp;</i></div></div></li>'),a.put("ui-grid/uiGridColumnMenu",'<div class="ui-grid-column-menu"><div ui-grid-menu menu-items="menuItems"><!-- <div class="ui-grid-column-menu">\n    <div class="inner" ng-show="menuShown">\n      <ul>\n        <div ng-show="grid.options.enableSorting">\n          <li ng-click="sortColumn($event, asc)" ng-class="{ \'selected\' : col.sort.direction == asc }"><i class="ui-grid-icon-sort-alt-up"></i> Sort Ascending</li>\n          <li ng-click="sortColumn($event, desc)" ng-class="{ \'selected\' : col.sort.direction == desc }"><i class="ui-grid-icon-sort-alt-down"></i> Sort Descending</li>\n          <li ng-show="col.sort.direction" ng-click="unsortColumn()"><i class="ui-grid-icon-cancel"></i> Remove Sort</li>\n        </div>\n      </ul>\n    </div>\n  </div> --></div></div>'),a.put("ui-grid/uiGridFooterCell",'<div class="ui-grid-cell-contents" col-index="renderIndex"><div>{{ col.getAggregationText() + ( col.getAggregationValue() CUSTOM_FILTERS ) }}</div></div>'),a.put("ui-grid/uiGridHeaderCell",'<div ng-class="{ \'sortable\': sortable }"><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><span>{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span></div><div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}"><i class="ui-grid-icon-angle-down">&nbsp;</i></div><div ng-if="filterable" class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="text" class="ui-grid-filter-input" ng-model="colFilter.term" ng-attr-placeholder="{{colFilter.placeholder || \'\'}}"><div class="ui-grid-filter-button" ng-click="colFilter.term = null"><i class="ui-grid-icon-cancel" ng-show="!!colFilter.term">&nbsp;</i><!-- use !! because angular interprets \'f\' as false --></div></div></div>'),a.put("ui-grid/uiGridMenu",'<div class="ui-grid-menu" ng-if="shown"><div class="ui-grid-menu-mid" ng-show="shownMid"><div class="ui-grid-menu-inner"><ul class="ui-grid-menu-items"><li ng-repeat="item in menuItems" ui-grid-menu-item action="item.action" name="item.title" active="item.active" icon="item.icon" shown="item.shown" context="item.context" template-url="item.templateUrl"></li></ul></div></div></div>'),a.put("ui-grid/uiGridMenuItem",'<li class="ui-grid-menu-item" ng-click="itemAction($event, title)" ng-show="itemShown()" ng-class="{ \'ui-grid-menu-item-active\' : active() }"><i ng-class="icon"></i> {{ name }}</li>'),a.put("ui-grid/uiGridRenderContainer",'<div class="ui-grid-render-container"><div ui-grid-header></div><div ui-grid-viewport></div><div ui-grid-footer ng-if="grid.options.showColumnFooter"></div></div>'),a.put("ui-grid/uiGridViewport",'<div class="ui-grid-viewport" ng-style="colContainer.getViewPortStyle()"><div class="ui-grid-canvas"><div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row" ng-style="Viewport.rowStyle(rowRenderIndex)"><div ui-grid-row="row" row-render-index="rowRenderIndex"></div></div></div></div>'),a.put("ui-grid/cellEditor",'<div><form name="inputForm"><input type="INPUT_TYPE" ng-class="\'colt\' + col.uid" ui-grid-editor ng-model="MODEL_COL_FIELD"></form></div>'),a.put("ui-grid/dropdownEditor",'<div><form name="inputForm"><select ng-class="\'colt\' + col.uid" ui-grid-edit-dropdown ng-model="MODEL_COL_FIELD" ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray"></select></form></div>'),a.put("ui-grid/expandableRow",'<div ui-grid-expandable-row ng-if="expandableRow.shouldRenderExpand()" class="expandableRow" style="float:left; margin-top: 1px; margin-bottom: 1px" ng-style="{width: (grid.renderContainers.body.getCanvasWidth()) + \'px\'\n     , height: grid.options.expandableRowHeight + \'px\'}"></div>'),a.put("ui-grid/expandableRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !row.isExpanded, \'ui-grid-icon-minus-squared\' : row.isExpanded }" ng-click="grid.api.expandable.toggleRowExpansion(row.entity)"></i></div></div>'),a.put("ui-grid/expandableScrollFiller","<div ng-if=\"expandableRow.shouldRenderFiller()\" style=\"float:left; margin-top: 2px; margin-bottom: 2px\" ng-style=\"{ width: (grid.getViewportWidth()) + 'px',\n              height: grid.options.expandableRowHeight + 'px', 'margin-left': grid.options.rowHeader.rowHeaderWidth + 'px' }\"><i class=\"ui-grid-icon-spin5 ui-grid-animate-spin\" ng-style=\"{ 'margin-top': ( grid.options.expandableRowHeight/2 - 5) + 'px',\n            'margin-left' : ((grid.getViewportWidth() - grid.options.rowHeader.rowHeaderWidth)/2 - 5) + 'px' }\"></i></div>"),a.put("ui-grid/expandableTopRowHeader",'<div class="ui-grid-row-header-cell ui-grid-expandable-buttons-cell"><div class="ui-grid-cell-contents"><i ng-class="{ \'ui-grid-icon-plus-squared\' : !grid.expandable.expandedAll, \'ui-grid-icon-minus-squared\' : grid.expandable.expandedAll }" ng-click="grid.api.expandable.toggleAllRows()"></i></div></div>'),a.put("ui-grid/csvLink",'<span class="ui-grid-exporter-csv-link-span"><a href="data:text/csv;charset=UTF-8,CSV_CONTENT" download="FILE_NAME">LINK_LABEL</a></span>'),a.put("ui-grid/importerMenuItem",'<li class="ui-grid-menu-item"><form><input class="ui-grid-importer-file-chooser" type="file" id="files" name="files[]"></form></li>'),a.put("ui-grid/importerMenuItemContainer","<div ui-grid-importer-menu-item></div>"),a.put("ui-grid/pagination",'<div class="ui-grid-pager-panel" ui-grid-pager ng-show="grid.options.enablePaginationControls"><div class="ui-grid-pager-container"><div class="ui-grid-pager-control"><button type="button" ng-click="paginationApi.seek(1)" ng-disabled="cantPageBackward()"><div class="first-triangle"><div class="first-bar"></div></div></button> <button type="button" ng-click="paginationApi.previousPage()" ng-disabled="cantPageBackward()"><div class="first-triangle prev-triangle"></div></button> <input type="number" ng-model="grid.options.paginationCurrentPage" min="1" max="{{ paginationApi.getTotalPages() }}" required> <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span> <button type="button" ng-click="paginationApi.nextPage()" ng-disabled="cantPageForward()"><div class="last-triangle next-triangle"></div></button> <button type="button" ng-click="paginationApi.seek(paginationApi.getTotalPages())" ng-disabled="cantPageToLast()"><div class="last-triangle"><div class="last-bar"></div></div></button></div><div class="ui-grid-pager-row-count-picker"><select ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select><span class="ui-grid-pager-row-count-label">&nbsp;{{sizesLabel}}</span></div></div><div class="ui-grid-pager-count-container"><div class="ui-grid-pager-count"><span ng-show="grid.options.totalItems > 0">{{showingLow}} - {{showingHigh}} of {{grid.options.totalItems}} {{totalItemsLabel}}</span></div></div></div>'),a.put("ui-grid/columnResizer",'<div ui-grid-column-resizer ng-if="grid.options.enableColumnResizing" class="ui-grid-column-resizer" col="col" position="right" render-index="renderIndex"></div>'),a.put("ui-grid/gridFooterSelectedItems",'<span ng-if="grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected">({{"search.selectedItems" | t}} {{grid.selection.selectedCount}})</span>'),a.put("ui-grid/selectionHeaderCell",'<div><!-- <div class="ui-grid-vertical-bar">&nbsp;</div> --><div class="ui-grid-cell-contents" col-index="renderIndex"><ui-grid-selection-select-all-buttons ng-if="grid.options.enableSelectAll"></ui-grid-selection-select-all-buttons></div></div>'),a.put("ui-grid/selectionRowHeader",'<div class="ui-grid-disable-selection"><div class="ui-grid-cell-contents"><ui-grid-selection-row-header-buttons></ui-grid-selection-row-header-buttons></div></div>'),a.put("ui-grid/selectionRowHeaderButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-row-selected\': row.isSelected}" ng-click="selectButtonClick(row, $event)">&nbsp;</div>'),a.put("ui-grid/selectionSelectAllButtons",'<div class="ui-grid-selection-row-header-buttons ui-grid-icon-ok" ng-class="{\'ui-grid-all-selected\': grid.selection.selectAll}" ng-click="headerButtonClick($event)"></div>')}]);
    \ No newline at end of file
    diff --git a/release/ui-grid-unstable.svg b/release/ui-grid-unstable.svg
    new file mode 100644
    index 000000000..4265b782c
    --- /dev/null
    +++ b/release/ui-grid-unstable.svg
    @@ -0,0 +1,31 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xe800;" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/ui-grid-unstable.ttf b/release/ui-grid-unstable.ttf
    new file mode 100644
    index 000000000..d2dc304da
    Binary files /dev/null and b/release/ui-grid-unstable.ttf differ
    diff --git a/release/ui-grid-unstable.woff b/release/ui-grid-unstable.woff
    new file mode 100644
    index 000000000..e11bc6564
    Binary files /dev/null and b/release/ui-grid-unstable.woff differ
    diff --git a/release/ui-grid.css b/release/ui-grid.css
    new file mode 100644
    index 000000000..b31f2f54d
    --- /dev/null
    +++ b/release/ui-grid.css
    @@ -0,0 +1,14 @@
    +.ui-grid-header-table {
    +  margin-bottom: 0;
    +}
    +.ui-grid-pinned.left {
    +  float: left;
    +}
    +.ui-grid-pinned.right {
    +  float: right;
    +}
    +.ui-grid-viewport tbody,
    +.ui-grid-viewport table tr:first-child,
    +.ui-grid-viewport table tr:first-child > td {
    +  border-top: none;
    +}
    diff --git a/release/ui-grid.eot b/release/ui-grid.eot
    new file mode 100644
    index 000000000..4d98e71c3
    Binary files /dev/null and b/release/ui-grid.eot differ
    diff --git a/release/ui-grid.js b/release/ui-grid.js
    new file mode 100644
    index 000000000..55bb3c26f
    --- /dev/null
    +++ b/release/ui-grid.js
    @@ -0,0 +1,787 @@
    +/*! ui-grid - v2.0.7-g7aeb576 - 2013-12-18
    +* Copyright (c) 2013 ; Licensed MIT */
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid.body', []);
    +
    +app.directive('uiGridBody', ['$log', 'GridUtil', function($log, GridUtil) {
    +  return {
    +    replace: true,
    +    priority: 1000,
    +    templateUrl: 'ui-grid/ui-grid-body',
    +    require: '?^uiGrid',
    +    scope: {
    +      tableClass: '=uiGridTableClass'
    +    },
    +    link: function(scope, elm, attrs, uiGridCtrl) {
    +      $log.debug('body postlink scope', scope.$id);
    +
    +      if (uiGridCtrl === undefined) {
    +        $log.warn('[ui-grid-body] uiGridCtrl is undefined!');
    +      }
    +
    +      if (uiGridCtrl && typeof(uiGridCtrl.columns) !== 'undefined' && uiGridCtrl.columns) {
    +        scope.columns = uiGridCtrl.columns;
    +      }
    +      if (uiGridCtrl && typeof(uiGridCtrl.gridData) !== 'undefined' && uiGridCtrl.gridData) {
    +        scope.gridData = uiGridCtrl.gridData;
    +      }
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid.header', ['ui.grid.util']);
    +
    +app.directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'GridUtil', function($log, $templateCache, $compile, GridUtil) {
    +  return {
    +    restrict: 'EA',
    +    // templateUrl: 'ui-grid/ui-grid-header',
    +    // replace: true,
    +    priority: 1000,
    +    require: '?^uiGrid',
    +    scope: {
    +      tableClass: '=uiGridTableClass'
    +    },
    +    compile: function (elm, attrs) {
    +      $log.debug('header compile');
    +
    +      // If the contents of the grid element are empty, use the default grid template
    +      var tmpl;
    +      if (elm.html() === '' || /^\s*$/.test(elm.html())) {
    +        tmpl = $templateCache.get('ui-grid/ui-grid-header');
    +      }
    +
    +      var preLink = function (scope, elm, attrs) {
    +        $log.debug('header prelink scope', scope.$id);
    +
    +        if (tmpl) {
    +          elm.append(tmpl);
    +        }
    +        $compile(elm.contents())(scope);
    +      };
    +
    +      var postLink = function(scope, elm, attrs, uiGridCtrl) {
    +        $log.debug('header postlink scope', scope.$id);
    +
    +        if (uiGridCtrl === undefined) {
    +          $log.warn('[ui-grid-header] uiGridCtrl is undefined!');
    +        }
    +
    +        // Get the column defs from the parent grid controller
    +        if (uiGridCtrl && typeof(uiGridCtrl.columns) !== 'undefined' && uiGridCtrl.columns) {
    +          scope.columns = uiGridCtrl.columns;
    +        }
    +
    +        // if (tmpl) {
    +        //   elm.append(tmpl);
    +        //   $compile(elm.contents())(scope);
    +        // }
    +
    +        // scope.$watch('columns', function(n, o) {
    +        //    $log.debug('columns change', n, o);
    +        //    var contents = elm.contents();
    +        //    $compile(contents)(scope);
    +        // });
    +      };
    +
    +      return {
    +        pre: preLink,
    +        post: postLink
    +      };
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +// 'use strict';
    +
    +/**
    + * @ngdoc directive
    + * @name ui.grid.style.directive:uiGridStyle
    + * @element style
    + * @restrict A
    + *
    + * @description
    + * Allows us to interpolate expressions in `<style>` elements. Angular doesn't do this by default as it can/will/might? break in IE8.
    + *
    + * @example
    +   <example module="app">
    +     <file name="app.js">
    +       var app = angular.module('app', ['ui.grid']);
    +       
    +       app.controller('MainCtrl', ['$scope', function ($scope) {
    +         $scope.myStyle = '.blah { color: red }';
    +       }]);
    +     </file>
    +     <file name="index.html">
    +       <div ng-controller="MainCtrl">
    +         <style ui-grid-style>{{ myStyle }}</style>
    +         <span class="blah">I am red.</span>
    +       </div>
    +     </file>
    +   </example>
    + */
    +
    +var app = angular.module('ui.grid.style', []);
    +
    +app.directive('uiGridStyle', ['$interpolate', '$sce', function($interpolate, $sce) {
    +  return {
    +    // restrict: 'A',
    +    priority: 1000,
    +    link: function(scope, element) {
    +      var interpolateFn = $interpolate(element.text(), true);
    +
    +      if (interpolateFn) {
    +        scope.$watch(interpolateFn, function(value) {
    +          element.text(value);
    +        });
    +      }
    +    }
    +  };
    +}]);
    +
    +})();
    +(function(){
    +'use strict';
    +
    +var app = angular.module('ui.grid', ['ui.grid.header', 'ui.grid.body', 'ui.grid.style', 'ui.virtual-repeat']);
    +
    +/**
    + *  @ngdoc directive
    + *  @name ui.grid.directive:uiGrid
    + *  @element div
    + *  @restrict EA
    + *  @param {array} uiGrid Array of rows to display in the grid
    + *  
    + *  @description Create a very basic grid.
    + *
    + *  @example
    +    <example module="app">
    +      <file name="app.js">
    +        var app = angular.module('app', ['ui.grid']);
    +
    +        app.controller('MainCtrl', ['$scope', function ($scope) {
    +          $scope.data = [
    +            { name: 'Bob', title: 'CEO' },
    +            { name: 'Frank', title: 'Lowly Developer' }
    +          ];
    +        }]);
    +      </file>
    +      <file name="index.html">
    +        <div ng-controller="MainCtrl">
    +          <div ui-grid="data"></div>
    +        </div>
    +      </file>
    +    </example>
    + */
    +app.directive('uiGrid',
    +  [
    +    '$compile',
    +    '$templateCache',
    +    '$log',
    +    'GridUtil',
    +  function(
    +    $compile,
    +    $templateCache,
    +    $log,
    +    GridUtil
    +  ) {
    +
    +    function preLink(scope, elm, attrs) {
    +      var options = scope.uiGrid;
    +
    +      // Create an ID for this grid
    +      scope.gridId = GridUtil.newId();
    +
    +      // Get the grid dimensions from the element
    +
    +      // Initialize the grid
    +
    +      // Get the column definitions
    +        // Put a watch on them
    +
    +      console.log('gridId', scope.gridId);
    +
    +      elm.on('$destroy', function() {
    +        // Remove columnDefs watch
    +      });
    +    }
    +    
    +    return {
    +      templateUrl: 'ui-grid/ui-grid',
    +      scope: {
    +        uiGrid: '='
    +      },
    +      compile: function () {
    +        return {
    +          pre: preLink
    +        };
    +      },
    +      controller: function ($scope, $element, $attrs) {
    +        
    +      }
    +    };
    +  }
    +]);
    +
    +})();
    +(function(){
    +'use strict';
    +  
    +// (part of the sf.virtualScroll module).
    +var mod = angular.module('ui.virtual-repeat', []);
    +
    +var DONT_WORK_AS_VIEWPORTS = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +var DONT_WORK_AS_CONTENT = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +var DONT_SET_DISPLAY_BLOCK = ['TABLE', 'TBODY', 'THEAD', 'TR', 'TFOOT'];
    +
    +// Utility to clip to range
    +function clip(value, min, max){
    +  if (angular.isArray(value)) {
    +    return angular.forEach(value, function(v) {
    +      return clip(v, min, max);
    +    });
    +  }
    +
    +  return Math.max(min, Math.min(value, max));
    +}
    +
    +mod.directive('uiVirtualRepeat', ['$log', '$rootElement', function($log, $rootElement){
    +
    +  // Turn the expression supplied to the directive:
    +  //
    +  //     a in b
    +  //
    +  // into `{ value: "a", collection: "b" }`
    +  function parseRepeatExpression(expression) {
    +    var match = expression.match(/^\s*([\$\w]+)\s+in\s+([\S\s]*)$/);
    +    if (! match) {
    +      throw new Error("Expected uiVirtualRepeat in form of '_item_ in _collection_' but got '" + expression + "'.");
    +    }
    +    return {
    +      value: match[1],
    +      collection: match[2]
    +    };
    +  }
    +
    +  // Utility to filter out elements by tag name
    +  function isTagNameInList(element, list) {
    +    var t,
    +        tag = element.tagName.toUpperCase();
    +
    +    for (t = 0; t < list.length; t++) {
    +      if (list[t] === tag) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +
    +  // Utility to find the viewport/content elements given the start element:
    +  function findViewportAndContent(startElement) {
    +    /*jshint eqeqeq:false, curly:false */
    +    var root = $rootElement[0];
    +    var e, n;
    +
    +    // Somewhere between the grandparent and the root node
    +    for (e = startElement.parent().parent()[0]; e !== root; e = e.parentNode) {
    +      // is an element
    +      if (e.nodeType != 1) break;
    +      // that isn't in the blacklist (tables etc.),
    +      if (isTagNameInList(e, DONT_WORK_AS_VIEWPORTS)) continue;
    +      // has a single child element (the content),
    +      if (e.childElementCount != 1) continue;
    +      // which is not in the blacklist
    +      if (isTagNameInList(e.firstElementChild, DONT_WORK_AS_CONTENT)) continue;
    +      // and no text.
    +      for (n = e.firstChild; n; n = n.nextSibling) {
    +        if (n.nodeType == 3 && /\S/g.test(n.textContent)) {
    +          break;
    +        }
    +      }
    +
    +      if (n == null) {
    +        // That element should work as a viewport.
    +        return {
    +          viewport: angular.element(e),
    +          content: angular.element(e.firstElementChild)
    +        };
    +      }
    +    }
    +
    +    throw new Error("No suitable viewport element");
    +  }
    +
    +  // Apply explicit height and overflow styles to the viewport element.
    +  //
    +  // If the viewport has a max-height (inherited or otherwise), set max-height.
    +  // Otherwise, set height from the current computed value or use
    +  // window.innerHeight as a fallback
    +  //
    +  function setViewportCSS(viewport) {
    +    var viewportCSS = {'overflow': 'auto'};
    +
    +    var style = window.getComputedStyle ?
    +                window.getComputedStyle(viewport[0]) :
    +                viewport[0].currentStyle;
    +
    +    var maxHeight = style && style.getPropertyValue('max-height');
    +    var height = style && style.getPropertyValue('height');
    +
    +    if (maxHeight && maxHeight !== '0px') {
    +      viewportCSS.maxHeight = maxHeight;
    +    }
    +    else if (height && height !== '0px') {
    +      viewportCSS.height = height;
    +    }
    +    else {
    +      viewportCSS.height = window.innerHeight;
    +    }
    +
    +    viewport.css(viewportCSS);
    +  }
    +
    +  // Apply explicit styles to the content element to prevent pesky padding
    +  // or borders messing with our calculations:
    +  function setContentCSS(content) {
    +    var contentCSS = {
    +      margin: 0,
    +      padding: 0,
    +      border: 0,
    +      'box-sizing': 'border-box'
    +    };
    +
    +    content.css(contentCSS);
    +  }
    +
    +  // TODO: compute outerHeight (padding + border unless box-sizing is border)
    +  function computeRowHeight(element) {
    +    var style = window.getComputedStyle ?
    +                window.getComputedStyle(element) :
    +                element.currentStyle;
    +
    +    var maxHeight = style && style.getPropertyValue('max-height');
    +    var height = style && style.getPropertyValue('height');
    +
    +    if (height && height !== '0px' && height !== 'auto') {
    +      // $log.info('Row height is "%s" from css height', height);
    +    }
    +    else if (maxHeight && maxHeight !== '0px' && maxHeight !== 'none') {
    +      height = maxHeight;
    +      // $log.info('Row height is "%s" from css max-height', height);
    +    }
    +    else if (element.clientHeight) {
    +      height = element.clientHeight + 'px';
    +      // $log.info('Row height is "%s" from client height', height);
    +    }
    +    else {
    +      //throw new Error("Unable to compute height of row");
    +      return;
    +    }
    +
    +    angular.element(element).css('height', height);
    +
    +    return parseInt(height, 10);
    +  }
    +
    +  // The compile gathers information about the declaration. There's not much
    +  // else we could do in the compile step as we need a viewport parent that
    +  // is exculsively ours - this is only available at link time.
    +  function uiVirtualRepeatCompile(element, attr, linker) {
    +    var ident = parseRepeatExpression(attr.uiVirtualRepeat);
    +    
    +    // ----
    +
    +    // Set up the initial value for our watch expression (which is just the
    +    // start and length of the active rows and the collection length) and
    +    // adds a listener to handle child scopes based on the active rows.
    +    function sfVirtualRepeatPostLink(scope, iterStartElement, attrs) {
    +
    +      var rendered = [];
    +          scope.rendered = rendered;
    +
    +      var rowHeight = 0;
    +      var sticky = false;
    +      var dom = findViewportAndContent(iterStartElement);
    +      // The list structure is controlled by a few simple (visible) variables:
    +      var state = 'ngModel' in attrs ? scope.$eval(attrs.ngModel) : {};
    +      //  - The index of the first active element
    +      state.firstActive = 0;
    +      //  - The index of the first visible element
    +      state.firstVisible = 0;
    +      //  - The number of elements visible in the viewport.
    +      state.visible = 0;
    +      // - The number of active elements
    +      state.active = 0;
    +      // - The total number of elements
    +      state.total = 0;
    +      // - The point at which we add new elements
    +      state.lowWater = state.lowWater || 10;
    +      // - The point at which we remove old elements
    +      state.highWater = state.highWater || 20;
    +      // TODO: now watch the water marks
    +
    +      setContentCSS(dom.content);
    +      setViewportCSS(dom.viewport);
    +      // When the user scrolls, we move the `state.firstActive`
    +      dom.viewport.bind('scroll', sfVirtualRepeatOnScroll);
    +
    +      // The watch on the collection is just a watch on the length of the
    +      // collection. We don't care if the content changes.
    +      scope.$watch(sfVirtualRepeatWatchExpression, sfVirtualRepeatListener, true);
    +
    +      // and that's the link done! All the action is in the handlers...
    +      
    +      // ----
    +
    +      // Apply explicit styles to the item element
    +      function setElementCSS(element) {
    +        var elementCSS = {
    +          // no margin or it'll screw up the height calculations.
    +          margin: '0'
    +        };
    +
    +        if (!isTagNameInList(element[0], DONT_SET_DISPLAY_BLOCK)) {
    +          // display: block if it's safe to do so
    +          elementCSS.display = 'block';
    +        }
    +
    +        if (rowHeight) {
    +          elementCSS.height = rowHeight + 'px';
    +        }
    +
    +        element.css(elementCSS);
    +      }
    +
    +      function makeNewScope (idx, collection, containerScope) {
    +        var childScope = containerScope.$new();
    +        childScope[ident.value] = collection[idx];
    +        childScope.$index = idx;
    +        childScope.$first = (idx === 0);
    +        childScope.$last = (idx === (collection.length - 1));
    +        childScope.$middle = !(childScope.$first || childScope.$last);
    +        childScope.$watch(function updateChildScopeItem(){
    +          childScope[ident.value] = collection[idx];
    +        });
    +        return childScope;
    +      }
    +
    +      function addElements (start, end, collection, containerScope, insPoint) {
    +        var frag = document.createDocumentFragment();
    +        var newElements = [], element, idx, childScope;
    +
    +        for (idx = start; idx !== end; idx++) {
    +          childScope = makeNewScope(idx, collection, containerScope);
    +          element = linker(childScope, angular.noop);
    +          setElementCSS(element);
    +          newElements.push(element);
    +          frag.appendChild(element[0]);
    +        }
    +
    +        insPoint.after(frag);
    +        return newElements;
    +      }
    +
    +      function recomputeActive() {
    +        // We want to set the start to the low water mark unless the current
    +        // start is already between the low and high water marks.
    +        var start = clip(state.firstActive, state.firstVisible - state.lowWater, state.firstVisible - state.highWater);
    +        // Similarly for the end
    +        var end = clip(state.firstActive + state.active,
    +                       state.firstVisible + state.visible + state.lowWater,
    +                       state.firstVisible + state.visible + state.highWater );
    +        state.firstActive = Math.max(0, start);
    +        state.active = Math.min(end, state.total) - state.firstActive;
    +      }
    +
    +      function sfVirtualRepeatOnScroll(evt) {
    +        if (!rowHeight) {
    +          return;
    +        }
    +
    +        // Enter the angular world for the state change to take effect.
    +        scope.$apply(function() {
    +          state.firstVisible = Math.floor(evt.target.scrollTop / rowHeight);
    +          state.visible = Math.ceil(dom.viewport[0].clientHeight / rowHeight);
    +
    +          // $log.log('scroll to row %o', state.firstVisible);
    +          sticky = evt.target.scrollTop + evt.target.clientHeight >= evt.target.scrollHeight;
    +
    +          recomputeActive();
    +          // $log.log(' state is now %o', state);
    +          // $log.log(' sticky = %o', sticky);
    +        });
    +      }
    +
    +      function sfVirtualRepeatWatchExpression(scope) {
    +        var coll = scope.$eval(ident.collection);
    +
    +        if (coll.length !== state.total) {
    +          state.total = coll.length;
    +          recomputeActive();
    +        }
    +
    +        return {
    +          start: state.firstActive,
    +          active: state.active,
    +          len: coll.length
    +        };
    +      }
    +
    +      function destroyActiveElements (action, count) {
    +        var dead,
    +            ii,
    +            remover = Array.prototype[action];
    +
    +        for (ii = 0; ii < count; ii++) {
    +          dead = remover.call(rendered);
    +          dead.scope().$destroy();
    +          dead.remove();
    +        }
    +      }
    +
    +      // When the watch expression for the repeat changes, we may need to add
    +      // and remove scopes and elements
    +      function sfVirtualRepeatListener(newValue, oldValue, scope) {
    +        var oldEnd = oldValue.start + oldValue.active,
    +            collection = scope.$eval(ident.collection),
    +            newElements;
    +
    +        if (newValue === oldValue) {
    +          // $log.info('initial listen');
    +          newElements = addElements(newValue.start, oldEnd, collection, scope, iterStartElement);
    +          rendered = newElements;
    +
    +          if (rendered.length) {
    +            rowHeight = computeRowHeight(newElements[0][0]);
    +          }
    +        }
    +        else {
    +          var newEnd = newValue.start + newValue.active;
    +          var forward = newValue.start >= oldValue.start;
    +          var delta = forward ? newValue.start - oldValue.start
    +                              : oldValue.start - newValue.start;
    +          var endDelta = newEnd >= oldEnd ? newEnd - oldEnd : oldEnd - newEnd;
    +          var contiguous = delta < (forward ? oldValue.active : newValue.active);
    +          // $log.info('change by %o,%o rows %s', delta, endDelta, forward ? 'forward' : 'backward');
    +
    +          if (!contiguous) {
    +            // $log.info('non-contiguous change');
    +            destroyActiveElements('pop', rendered.length);
    +            rendered = addElements(newValue.start, newEnd, collection, scope, iterStartElement);
    +          }
    +          else {
    +            if (forward) {
    +              // $log.info('need to remove from the top');
    +              destroyActiveElements('shift', delta);
    +            }
    +            else if (delta) {
    +              // $log.info('need to add at the top');
    +              newElements = addElements(
    +                newValue.start,
    +                oldValue.start,
    +                collection, scope, iterStartElement);
    +              rendered = newElements.concat(rendered);
    +            }
    +
    +            if (newEnd < oldEnd) {
    +              // $log.info('need to remove from the bottom');
    +              destroyActiveElements('pop', oldEnd - newEnd);
    +            }
    +            else if (endDelta) {
    +              var lastElement = rendered[rendered.length-1];
    +              // $log.info('need to add to the bottom');
    +              newElements = addElements(
    +                oldEnd,
    +                newEnd,
    +                collection, scope, lastElement);
    +
    +              rendered = rendered.concat(newElements);
    +            }
    +          }
    +
    +          if (!rowHeight && rendered.length) {
    +            rowHeight = computeRowHeight(rendered[0][0]);
    +          }
    +
    +          dom.content.css({'padding-top': newValue.start * rowHeight + 'px'});
    +        }
    +
    +        dom.content.css({'height': newValue.len * rowHeight + 'px'});
    +
    +        if (sticky) {
    +          dom.viewport[0].scrollTop = dom.viewport[0].clientHeight + dom.viewport[0].scrollHeight;
    +        }
    +
    +        scope.rendered = rendered;
    +      }
    +
    +      return;
    +    }
    +
    +    return {
    +      post: sfVirtualRepeatPostLink
    +    };
    +  }
    +
    +  var directive =  {
    +    require: '?ngModel',
    +    transclude: 'element',
    +    priority: 1000,
    +    // terminal: true,
    +    compile: uiVirtualRepeatCompile,
    +    controller: ['$scope', function ($scope) {
    +      this.visibleRows = 0;
    +      this.visibleRows = this.visibleRows + 1;
    +    }]
    +  };
    +
    +  return directive;
    +}]);
    +
    +}());
    +(function() {
    +
    +var app = angular.module('ui.grid.util', []);
    +
    +/**
    + *  @ngdoc service
    + *  @name ui.grid.util.service:GridUtil
    + *  
    + *  @description Grid utility functions
    + */
    +app.service('GridUtil', function () {
    +
    +  var s = {
    +
    +    /**
    +     * @ngdoc method
    +     * @name readableColumnName
    +     * @methodOf ui.grid.util.service:GridUtil
    +     *
    +     * @param {string} columnName Column name as a string
    +     * @returns {string} Column name appropriately capitalized and split apart
    +     *
    +       @example
    +       <example module="app">
    +        <file name="app.js">
    +          var app = angular.module('app', ['ui.grid.util']);
    +
    +          app.controller('MainCtrl', ['$scope', 'GridUtil', function ($scope, GridUtil) {
    +            $scope.name = 'firstName';
    +            $scope.columnName = function(name) {
    +              return GridUtil.readableColumnName(name);
    +            };
    +          }]);
    +        </file>
    +        <file name="index.html">
    +          <div ng-controller="MainCtrl">
    +            <strong>Column name:</strong> <input ng-model="name" />
    +            <br>
    +            <strong>Output:</strong> <span ng-bind="columnName(name)"></span>
    +          </div>
    +        </file>
    +      </example>
    +     */
    +    readableColumnName: function (columnName) {
    +      // Convert underscores to spaces
    +      if (typeof(columnName) === 'undefined' || columnName === undefined || columnName === null) { return columnName; }
    +
    +      if (typeof(columnName) !== 'string') {
    +        columnName = String(columnName);
    +      }
    +
    +      return columnName.replace(/_+/g, ' ')
    +        // Replace a completely all-capsed word with a first-letter-capitalized version
    +        .replace(/^[A-Z]+$/, function (match) {
    +          return angular.lowercase(angular.uppercase(match.charAt(0)) + match.slice(1));
    +        })
    +        // Capitalize the first letter of words
    +        .replace(/(\w+)/g, function (match) {
    +          return angular.uppercase(match.charAt(0)) + match.slice(1);
    +        })
    +        // Put a space in between words that have partial capilizations (i.e. 'firstName' becomes 'First Name')
    +        // .replace(/([A-Z]|[A-Z]\w+)([A-Z])/g, "$1 $2");
    +        // .replace(/(\w+?|\w)([A-Z])/g, "$1 $2");
    +        .replace(/(\w+?(?=[A-Z]))/g, '$1 ');
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name getColumnsFromData
    +     * @methodOf ui.grid.util.service:GridUtil
    +     * @description Return a list of column names, given a data set
    +     *
    +     * @param {string} data Data array for grid
    +     * @returns {Object} Column definitions with field accessor and column name
    +     *
    +     * @example
    +       <pre>
    +         var data = [
    +           { firstName: 'Bob', lastName: 'Jones' },
    +           { firstName: 'Frank', lastName: 'Smith' }
    +         ];
    +
    +         var columnDefs = GridUtil.getColumnsFromData(data);
    +
    +         columnDefs == [
    +          {
    +            field: 'firstName',
    +            name: 'First Name'
    +          },
    +          {
    +            field: 'lastName',
    +            name: 'Last Name'
    +          }
    +         ];
    +       </pre>
    +     */
    +    getColumnsFromData: function (data) {
    +      var columnDefs = [];
    +
    +      var item = data[0];
    +      
    +      angular.forEach(item, function (prop, propName) {
    +        columnDefs.push({
    +          field: propName,
    +          name: s.readableColumnName(propName)
    +        });
    +      });
    +
    +      return columnDefs;
    +    },
    +
    +    /**
    +     * @ngdoc method
    +     * @name newId
    +     * @methodOf ui.grid.util.service:GridUtil
    +     * @description Return a unique ID string
    +     *
    +     * @returns {string} Unique string
    +     *
    +     * @example
    +       <pre>
    +        var id = GridUtil.newId();
    +
    +        # 1387305700482;
    +       </pre>
    +     */
    +    newId: (function() {
    +      var seedId = new Date().getTime();
    +      return function() {
    +          return seedId += 1;
    +      };
    +    })(),
    +  };
    +
    +  return s;
    +});
    +
    +})();
    \ No newline at end of file
    diff --git a/release/ui-grid.min.css b/release/ui-grid.min.css
    new file mode 100644
    index 000000000..5a4612136
    --- /dev/null
    +++ b/release/ui-grid.min.css
    @@ -0,0 +1 @@
    +.ui-grid-header-table{margin-bottom:0}.ui-grid-pinned.left{float:left}.ui-grid-pinned.right{float:right}.ui-grid-viewport tbody,.ui-grid-viewport table tr:first-child,.ui-grid-viewport table tr:first-child>td{border-top:none}
    \ No newline at end of file
    diff --git a/release/ui-grid.min.js b/release/ui-grid.min.js
    new file mode 100644
    index 000000000..832ad8efe
    --- /dev/null
    +++ b/release/ui-grid.min.js
    @@ -0,0 +1,3 @@
    +/*! ui-grid - v2.0.7-g7aeb576 - 2013-12-18
    +* Copyright (c) 2013 ; Licensed MIT */
    +!function(){"use strict";var a=angular.module("ui.grid.body",[]);a.directive("uiGridBody",["$log","GridUtil",function(a){return{replace:!0,priority:1e3,templateUrl:"ui-grid/ui-grid-body",require:"?^uiGrid",scope:{tableClass:"=uiGridTableClass"},link:function(b,c,d,e){a.debug("body postlink scope",b.$id),void 0===e&&a.warn("[ui-grid-body] uiGridCtrl is undefined!"),e&&"undefined"!=typeof e.columns&&e.columns&&(b.columns=e.columns),e&&"undefined"!=typeof e.gridData&&e.gridData&&(b.gridData=e.gridData)}}}])}(),function(){"use strict";var a=angular.module("ui.grid.header",["ui.grid.util"]);a.directive("uiGridHeader",["$log","$templateCache","$compile","GridUtil",function(a,b,c){return{restrict:"EA",priority:1e3,require:"?^uiGrid",scope:{tableClass:"=uiGridTableClass"},compile:function(d){a.debug("header compile");var e;(""===d.html()||/^\s*$/.test(d.html()))&&(e=b.get("ui-grid/ui-grid-header"));var f=function(b,d){a.debug("header prelink scope",b.$id),e&&d.append(e),c(d.contents())(b)},g=function(b,c,d,e){a.debug("header postlink scope",b.$id),void 0===e&&a.warn("[ui-grid-header] uiGridCtrl is undefined!"),e&&"undefined"!=typeof e.columns&&e.columns&&(b.columns=e.columns)};return{pre:f,post:g}}}}])}(),function(){var a=angular.module("ui.grid.style",[]);a.directive("uiGridStyle",["$interpolate","$sce",function(a){return{priority:1e3,link:function(b,c){var d=a(c.text(),!0);d&&b.$watch(d,function(a){c.text(a)})}}}])}(),function(){"use strict";var a=angular.module("ui.grid",["ui.grid.header","ui.grid.body","ui.grid.style","ui.virtual-repeat"]);a.directive("uiGrid",["$compile","$templateCache","$log","GridUtil",function(a,b,c,d){function e(a,b){a.uiGrid;a.gridId=d.newId(),console.log("gridId",a.gridId),b.on("$destroy",function(){})}return{templateUrl:"ui-grid/ui-grid",scope:{uiGrid:"="},compile:function(){return{pre:e}},controller:function(){}}}])}(),function(){"use strict";function a(b,c,d){return angular.isArray(b)?angular.forEach(b,function(b){return a(b,c,d)}):Math.max(c,Math.min(b,d))}var b=angular.module("ui.virtual-repeat",[]),c=["TABLE","TBODY","THEAD","TR","TFOOT"],d=["TABLE","TBODY","THEAD","TR","TFOOT"],e=["TABLE","TBODY","THEAD","TR","TFOOT"];b.directive("uiVirtualRepeat",["$log","$rootElement",function(b,f){function g(a){var b=a.match(/^\s*([\$\w]+)\s+in\s+([\S\s]*)$/);if(!b)throw new Error("Expected uiVirtualRepeat in form of '_item_ in _collection_' but got '"+a+"'.");return{value:b[1],collection:b[2]}}function h(a,b){var c,d=a.tagName.toUpperCase();for(c=0;c<b.length;c++)if(b[c]===d)return!0;return!1}function i(a){var b,e,g=f[0];for(b=a.parent().parent()[0];b!==g&&1==b.nodeType;b=b.parentNode)if(!h(b,c)&&1==b.childElementCount&&!h(b.firstElementChild,d)){for(e=b.firstChild;e&&(3!=e.nodeType||!/\S/g.test(e.textContent));e=e.nextSibling);if(null==e)return{viewport:angular.element(b),content:angular.element(b.firstElementChild)}}throw new Error("No suitable viewport element")}function j(a){var b={overflow:"auto"},c=window.getComputedStyle?window.getComputedStyle(a[0]):a[0].currentStyle,d=c&&c.getPropertyValue("max-height"),e=c&&c.getPropertyValue("height");d&&"0px"!==d?b.maxHeight=d:b.height=e&&"0px"!==e?e:window.innerHeight,a.css(b)}function k(a){var b={margin:0,padding:0,border:0,"box-sizing":"border-box"};a.css(b)}function l(a){var b=window.getComputedStyle?window.getComputedStyle(a):a.currentStyle,c=b&&b.getPropertyValue("max-height"),d=b&&b.getPropertyValue("height");if(d&&"0px"!==d&&"auto"!==d);else if(c&&"0px"!==c&&"none"!==c)d=c;else{if(!a.clientHeight)return;d=a.clientHeight+"px"}return angular.element(a).css("height",d),parseInt(d,10)}function m(b,c,d){function f(b,c,f){function g(a){var b={margin:"0"};h(a[0],e)||(b.display="block"),v&&(b.height=v+"px"),a.css(b)}function n(a,b,c){var d=c.$new();return d[m.value]=b[a],d.$index=a,d.$first=0===a,d.$last=a===b.length-1,d.$middle=!(d.$first||d.$last),d.$watch(function(){d[m.value]=b[a]}),d}function o(a,b,c,e,f){var h,i,j,k=document.createDocumentFragment(),l=[];for(i=a;i!==b;i++)j=n(i,c,e),h=d(j,angular.noop),g(h),l.push(h),k.appendChild(h[0]);return f.after(k),l}function p(){var b=a(y.firstActive,y.firstVisible-y.lowWater,y.firstVisible-y.highWater),c=a(y.firstActive+y.active,y.firstVisible+y.visible+y.lowWater,y.firstVisible+y.visible+y.highWater);y.firstActive=Math.max(0,b),y.active=Math.min(c,y.total)-y.firstActive}function q(a){v&&b.$apply(function(){y.firstVisible=Math.floor(a.target.scrollTop/v),y.visible=Math.ceil(x.viewport[0].clientHeight/v),w=a.target.scrollTop+a.target.clientHeight>=a.target.scrollHeight,p()})}function r(a){var b=a.$eval(m.collection);return b.length!==y.total&&(y.total=b.length,p()),{start:y.firstActive,active:y.active,len:b.length}}function s(a,b){var c,d,e=Array.prototype[a];for(d=0;b>d;d++)c=e.call(u),c.scope().$destroy(),c.remove()}function t(a,b,d){var e,f=b.start+b.active,g=d.$eval(m.collection);if(a===b)e=o(a.start,f,g,d,c),u=e,u.length&&(v=l(e[0][0]));else{var h=a.start+a.active,i=a.start>=b.start,j=i?a.start-b.start:b.start-a.start,k=h>=f?h-f:f-h,n=j<(i?b.active:a.active);if(n){if(i?s("shift",j):j&&(e=o(a.start,b.start,g,d,c),u=e.concat(u)),f>h)s("pop",f-h);else if(k){var p=u[u.length-1];e=o(f,h,g,d,p),u=u.concat(e)}}else s("pop",u.length),u=o(a.start,h,g,d,c);!v&&u.length&&(v=l(u[0][0])),x.content.css({"padding-top":a.start*v+"px"})}x.content.css({height:a.len*v+"px"}),w&&(x.viewport[0].scrollTop=x.viewport[0].clientHeight+x.viewport[0].scrollHeight),d.rendered=u}var u=[];b.rendered=u;var v=0,w=!1,x=i(c),y="ngModel"in f?b.$eval(f.ngModel):{};y.firstActive=0,y.firstVisible=0,y.visible=0,y.active=0,y.total=0,y.lowWater=y.lowWater||10,y.highWater=y.highWater||20,k(x.content),j(x.viewport),x.viewport.bind("scroll",q),b.$watch(r,t,!0)}var m=g(c.uiVirtualRepeat);return{post:f}}var n={require:"?ngModel",transclude:"element",priority:1e3,compile:m,controller:["$scope",function(){this.visibleRows=0,this.visibleRows=this.visibleRows+1}]};return n}])}(),function(){var a=angular.module("ui.grid.util",[]);a.service("GridUtil",function(){var a={readableColumnName:function(a){return"undefined"==typeof a||void 0===a||null===a?a:("string"!=typeof a&&(a=String(a)),a.replace(/_+/g," ").replace(/^[A-Z]+$/,function(a){return angular.lowercase(angular.uppercase(a.charAt(0))+a.slice(1))}).replace(/(\w+)/g,function(a){return angular.uppercase(a.charAt(0))+a.slice(1)}).replace(/(\w+?(?=[A-Z]))/g,"$1 "))},getColumnsFromData:function(b){var c=[],d=b[0];return angular.forEach(d,function(b,d){c.push({field:d,name:a.readableColumnName(d)})}),c},newId:function(){var a=(new Date).getTime();return function(){return a+=1}}()};return a})}();
    \ No newline at end of file
    diff --git a/release/ui-grid.svg b/release/ui-grid.svg
    new file mode 100644
    index 000000000..3014118ff
    --- /dev/null
    +++ b/release/ui-grid.svg
    @@ -0,0 +1,32 @@
    +<?xml version="1.0" standalone="no"?>
    +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    +<svg xmlns="http://www.w3.org/2000/svg">
    +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
    +<defs>
    +<font id="ui-grid" horiz-adv-x="1000" >
    +<font-face font-family="ui-grid" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
    +<missing-glyph horiz-adv-x="1000" />
    +<glyph glyph-name="plus-squared" unicode="&#xc350;" d="m714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="minus-squared" unicode="&#xc351;" d="m714 314v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72q0-14 10-25t26-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
    +<glyph glyph-name="search" unicode="&#xc352;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
    +<glyph glyph-name="cancel" unicode="&#xc353;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
    +<glyph glyph-name="info-circled" unicode="&#xc354;" d="m571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
    +<glyph glyph-name="lock" unicode="&#xc355;" d="m179 421h285v108q0 59-42 101t-101 41-101-41-41-101v-108z m464-53v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38z" horiz-adv-x="642.9" />
    +<glyph glyph-name="lock-open" unicode="&#xc356;" d="m929 529v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176z" horiz-adv-x="928.6" />
    +<glyph glyph-name="pencil" unicode="&#xc357;" d="m203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
    +<glyph glyph-name="down-dir" unicode="&#xc358;" d="m571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
    +<glyph glyph-name="up-dir" unicode="&#xc359;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
    +<glyph glyph-name="left-dir" unicode="&#xc35a;" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="right-dir" unicode="&#xc35b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
    +<glyph glyph-name="left-open" unicode="&#xc35c;" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="right-open" unicode="&#xc35d;" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
    +<glyph glyph-name="angle-down" unicode="&#xc35e;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
    +<glyph glyph-name="filter" unicode="&#xc35f;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
    +<glyph glyph-name="sort-alt-up" unicode="&#xc360;" d="m411 46q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m589-71v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m-107 285v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m-107 286v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="sort-alt-down" unicode="&#xc361;" d="m679-25v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107q0 8 5 13t13 5h143q8 0 13-5t5-13z m-268 71q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19 4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13z m375 215v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13v107q0 8 5 13t13 5h250q8 0 13-5t5-13z m107 285v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13v107q0 8 5 13t13 5h357q8 0 13-5t5-13z m107 286v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107q0 8 5 13t13 5h464q8 0 13-5t5-13z" horiz-adv-x="1000" />
    +<glyph glyph-name="ok" unicode="&#xc362;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
    +<glyph glyph-name="menu" unicode="&#xc363;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
    +<glyph glyph-name="spin5" unicode="&#xea61;" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
    +</font>
    +</defs>
    +</svg>
    \ No newline at end of file
    diff --git a/release/ui-grid.ttf b/release/ui-grid.ttf
    new file mode 100644
    index 000000000..838611afb
    Binary files /dev/null and b/release/ui-grid.ttf differ
    diff --git a/release/ui-grid.woff b/release/ui-grid.woff
    new file mode 100644
    index 000000000..ca1a9c6e0
    Binary files /dev/null and b/release/ui-grid.woff differ
    diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css
    new file mode 100644
    index 000000000..e65cedff6
    --- /dev/null
    +++ b/stylesheets/pygment_trac.css
    @@ -0,0 +1,70 @@
    +.highlight .hll { background-color: #ffffcc }
    +.highlight  { background: #f0f3f3; }
    +.highlight .c { color: #0099FF; font-style: italic } /* Comment */
    +.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
    +.highlight .k { color: #006699; font-weight: bold } /* Keyword */
    +.highlight .o { color: #555555 } /* Operator */
    +.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
    +.highlight .cp { color: #009999 } /* Comment.Preproc */
    +.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
    +.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
    +.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
    +.highlight .ge { font-style: italic } /* Generic.Emph */
    +.highlight .gr { color: #FF0000 } /* Generic.Error */
    +.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
    +.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
    +.highlight .go { color: #AAAAAA } /* Generic.Output */
    +.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
    +.highlight .gs { font-weight: bold } /* Generic.Strong */
    +.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
    +.highlight .gt { color: #99CC66 } /* Generic.Traceback */
    +.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
    +.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
    +.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
    +.highlight .kp { color: #006699 } /* Keyword.Pseudo */
    +.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
    +.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
    +.highlight .m { color: #FF6600 } /* Literal.Number */
    +.highlight .s { color: #CC3300 } /* Literal.String */
    +.highlight .na { color: #330099 } /* Name.Attribute */
    +.highlight .nb { color: #336666 } /* Name.Builtin */
    +.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
    +.highlight .no { color: #336600 } /* Name.Constant */
    +.highlight .nd { color: #9999FF } /* Name.Decorator */
    +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
    +.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
    +.highlight .nf { color: #CC00FF } /* Name.Function */
    +.highlight .nl { color: #9999FF } /* Name.Label */
    +.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
    +.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
    +.highlight .nv { color: #003333 } /* Name.Variable */
    +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
    +.highlight .w { color: #bbbbbb } /* Text.Whitespace */
    +.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
    +.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
    +.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
    +.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
    +.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
    +.highlight .sc { color: #CC3300 } /* Literal.String.Char */
    +.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
    +.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
    +.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
    +.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
    +.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
    +.highlight .sx { color: #CC3300 } /* Literal.String.Other */
    +.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
    +.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
    +.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
    +.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
    +.highlight .vc { color: #003333 } /* Name.Variable.Class */
    +.highlight .vg { color: #003333 } /* Name.Variable.Global */
    +.highlight .vi { color: #003333 } /* Name.Variable.Instance */
    +.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */
    +
    +.type-csharp .highlight .k { color: #0000FF }
    +.type-csharp .highlight .kt { color: #0000FF }
    +.type-csharp .highlight .nf { color: #000000; font-weight: normal }
    +.type-csharp .highlight .nc { color: #2B91AF }
    +.type-csharp .highlight .nn { color: #000000 }
    +.type-csharp .highlight .s { color: #A31515 }
    +.type-csharp .highlight .sc { color: #A31515 }
    diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css
    new file mode 100644
    index 000000000..7a08b019b
    --- /dev/null
    +++ b/stylesheets/stylesheet.css
    @@ -0,0 +1,423 @@
    +/*******************************************************************************
    +Slate Theme for GitHub Pages
    +by Jason Costello, @jsncostello
    +*******************************************************************************/
    +
    +@import url(pygment_trac.css);
    +
    +/*******************************************************************************
    +MeyerWeb Reset
    +*******************************************************************************/
    +
    +html, body, div, span, applet, object, iframe,
    +h1, h2, h3, h4, h5, h6, p, blockquote, pre,
    +a, abbr, acronym, address, big, cite, code,
    +del, dfn, em, img, ins, kbd, q, s, samp,
    +small, strike, strong, sub, sup, tt, var,
    +b, u, i, center,
    +dl, dt, dd, ol, ul, li,
    +fieldset, form, label, legend,
    +table, caption, tbody, tfoot, thead, tr, th, td,
    +article, aside, canvas, details, embed,
    +figure, figcaption, footer, header, hgroup,
    +menu, nav, output, ruby, section, summary,
    +time, mark, audio, video {
    +  margin: 0;
    +  padding: 0;
    +  border: 0;
    +  font: inherit;
    +  vertical-align: baseline;
    +}
    +
    +/* HTML5 display-role reset for older browsers */
    +article, aside, details, figcaption, figure,
    +footer, header, hgroup, menu, nav, section {
    +  display: block;
    +}
    +
    +ol, ul {
    +  list-style: none;
    +}
    +
    +table {
    +  border-collapse: collapse;
    +  border-spacing: 0;
    +}
    +
    +/*******************************************************************************
    +Theme Styles
    +*******************************************************************************/
    +
    +body {
    +  box-sizing: border-box;
    +  color:#373737;
    +  background: #212121;
    +  font-size: 16px;
    +  font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
    +  line-height: 1.5;
    +  -webkit-font-smoothing: antialiased;
    +}
    +
    +h1, h2, h3, h4, h5, h6 {
    +  margin: 10px 0;
    +  font-weight: 700;
    +  color:#222222;
    +  font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
    +  letter-spacing: -1px;
    +}
    +
    +h1 {
    +  font-size: 36px;
    +  font-weight: 700;
    +}
    +
    +h2 {
    +  padding-bottom: 10px;
    +  font-size: 32px;
    +  background: url('../images/bg_hr.png') repeat-x bottom;
    +}
    +
    +h3 {
    +  font-size: 24px;
    +}
    +
    +h4 {
    +  font-size: 21px;
    +}
    +
    +h5 {
    +  font-size: 18px;
    +}
    +
    +h6 {
    +  font-size: 16px;
    +}
    +
    +p {
    +  margin: 10px 0 15px 0;
    +}
    +
    +footer p {
    +  color: #f2f2f2;
    +}
    +
    +a {
    +  text-decoration: none;
    +  color: #007edf;
    +  text-shadow: none;
    +
    +  transition: color 0.5s ease;
    +  transition: text-shadow 0.5s ease;
    +  -webkit-transition: color 0.5s ease;
    +  -webkit-transition: text-shadow 0.5s ease;
    +  -moz-transition: color 0.5s ease;
    +  -moz-transition: text-shadow 0.5s ease;
    +  -o-transition: color 0.5s ease;
    +  -o-transition: text-shadow 0.5s ease;
    +  -ms-transition: color 0.5s ease;
    +  -ms-transition: text-shadow 0.5s ease;
    +}
    +
    +a:hover, a:focus {text-decoration: underline;}
    +
    +footer a {
    +  color: #F2F2F2;
    +  text-decoration: underline;
    +}
    +
    +em {
    +  font-style: italic;
    +}
    +
    +strong {
    +  font-weight: bold;
    +}
    +
    +img {
    +  position: relative;
    +  margin: 0 auto;
    +  max-width: 739px;
    +  padding: 5px;
    +  margin: 10px 0 10px 0;
    +  border: 1px solid #ebebeb;
    +
    +  box-shadow: 0 0 5px #ebebeb;
    +  -webkit-box-shadow: 0 0 5px #ebebeb;
    +  -moz-box-shadow: 0 0 5px #ebebeb;
    +  -o-box-shadow: 0 0 5px #ebebeb;
    +  -ms-box-shadow: 0 0 5px #ebebeb;
    +}
    +
    +p img {
    +  display: inline;
    +  margin: 0;
    +  padding: 0;
    +  vertical-align: middle;
    +  text-align: center;
    +  border: none;
    +}
    +
    +pre, code {
    +  width: 100%;
    +  color: #222;
    +  background-color: #fff;
    +
    +  font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
    +  font-size: 14px;
    +
    +  border-radius: 2px;
    +  -moz-border-radius: 2px;
    +  -webkit-border-radius: 2px;
    +}
    +
    +pre {
    +  width: 100%;
    +  padding: 10px;
    +  box-shadow: 0 0 10px rgba(0,0,0,.1);
    +  overflow: auto;
    +}
    +
    +code {
    +  padding: 3px;
    +  margin: 0 3px;
    +  box-shadow: 0 0 10px rgba(0,0,0,.1);
    +}
    +
    +pre code {
    +  display: block;
    +  box-shadow: none;
    +}
    +
    +blockquote {
    +  color: #666;
    +  margin-bottom: 20px;
    +  padding: 0 0 0 20px;
    +  border-left: 3px solid #bbb;
    +}
    +
    +
    +ul, ol, dl {
    +  margin-bottom: 15px
    +}
    +
    +ul {
    +  list-style: inside;
    +  padding-left: 20px;
    +}
    +
    +ol {
    +  list-style: decimal inside;
    +  padding-left: 20px;
    +}
    +
    +dl dt {
    +  font-weight: bold;
    +}
    +
    +dl dd {
    +  padding-left: 20px;
    +  font-style: italic;
    +}
    +
    +dl p {
    +  padding-left: 20px;
    +  font-style: italic;
    +}
    +
    +hr {
    +  height: 1px;
    +  margin-bottom: 5px;
    +  border: none;
    +  background: url('../images/bg_hr.png') repeat-x center;
    +}
    +
    +table {
    +  border: 1px solid #373737;
    +  margin-bottom: 20px;
    +  text-align: left;
    + }
    +
    +th {
    +  font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    +  padding: 10px;
    +  background: #373737;
    +  color: #fff;
    + }
    +
    +td {
    +  padding: 10px;
    +  border: 1px solid #373737;
    + }
    +
    +form {
    +  background: #f2f2f2;
    +  padding: 20px;
    +}
    +
    +/*******************************************************************************
    +Full-Width Styles
    +*******************************************************************************/
    +
    +.outer {
    +  width: 100%;
    +}
    +
    +.inner {
    +  position: relative;
    +  max-width: 640px;
    +  padding: 20px 10px;
    +  margin: 0 auto;
    +}
    +
    +#forkme_banner {
    +  display: block;
    +  position: absolute;
    +  top:0;
    +  right: 10px;
    +  z-index: 10;
    +  padding: 10px 50px 10px 10px;
    +  color: #fff;
    +  background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
    +  font-weight: 700;
    +  box-shadow: 0 0 10px rgba(0,0,0,.5);
    +  border-bottom-left-radius: 2px;
    +  border-bottom-right-radius: 2px;
    +}
    +
    +#header_wrap {
    +  background: #212121;
    +  background: -moz-linear-gradient(top, #373737, #212121);
    +  background: -webkit-linear-gradient(top, #373737, #212121);
    +  background: -ms-linear-gradient(top, #373737, #212121);
    +  background: -o-linear-gradient(top, #373737, #212121);
    +  background: linear-gradient(top, #373737, #212121);
    +}
    +
    +#header_wrap .inner {
    +  padding: 50px 10px 30px 10px;
    +}
    +
    +#project_title {
    +  margin: 0;
    +  color: #fff;
    +  font-size: 42px;
    +  font-weight: 700;
    +  text-shadow: #111 0px 0px 10px;
    +}
    +
    +#project_tagline {
    +  color: #fff;
    +  font-size: 24px;
    +  font-weight: 300;
    +  background: none;
    +  text-shadow: #111 0px 0px 10px;
    +}
    +
    +#downloads {
    +  position: absolute;
    +  width: 210px;
    +  z-index: 10;
    +  bottom: -40px;
    +  right: 0;
    +  height: 70px;
    +  background: url('../images/icon_download.png') no-repeat 0% 90%;
    +}
    +
    +.zip_download_link {
    +  display: block;
    +  float: right;
    +  width: 90px;
    +  height:70px;
    +  text-indent: -5000px;
    +  overflow: hidden;
    +  background: url(../images/sprite_download.png) no-repeat bottom left;
    +}
    +
    +.tar_download_link {
    +  display: block;
    +  float: right;
    +  width: 90px;
    +  height:70px;
    +  text-indent: -5000px;
    +  overflow: hidden;
    +  background: url(../images/sprite_download.png) no-repeat bottom right;
    +  margin-left: 10px;
    +}
    +
    +.zip_download_link:hover {
    +  background: url(../images/sprite_download.png) no-repeat top left;
    +}
    +
    +.tar_download_link:hover {
    +  background: url(../images/sprite_download.png) no-repeat top right;
    +}
    +
    +#main_content_wrap {
    +  background: #f2f2f2;
    +  border-top: 1px solid #111;
    +  border-bottom: 1px solid #111;
    +}
    +
    +#main_content {
    +  padding-top: 40px;
    +}
    +
    +#footer_wrap {
    +  background: #212121;
    +}
    +
    +
    +
    +/*******************************************************************************
    +Small Device Styles
    +*******************************************************************************/
    +
    +@media screen and (max-width: 480px) {
    +  body {
    +    font-size:14px;
    +  }
    +
    +  #downloads {
    +    display: none;
    +  }
    +
    +  .inner {
    +    min-width: 320px;
    +    max-width: 480px;
    +  }
    +
    +  #project_title {
    +  font-size: 32px;
    +  }
    +
    +  h1 {
    +    font-size: 28px;
    +  }
    +
    +  h2 {
    +    font-size: 24px;
    +  }
    +
    +  h3 {
    +    font-size: 21px;
    +  }
    +
    +  h4 {
    +    font-size: 18px;
    +  }
    +
    +  h5 {
    +    font-size: 14px;
    +  }
    +
    +  h6 {
    +    font-size: 12px;
    +  }
    +
    +  code, pre {
    +    min-width: 320px;
    +    max-width: 480px;
    +    font-size: 11px;
    +  }
    +
    +}
    diff --git a/update.json b/update.json
    new file mode 100644
    index 000000000..0be27ffb4
    --- /dev/null
    +++ b/update.json
    @@ -0,0 +1,8 @@
    +{
    +  "packageManager": "github",
    +  "name": "ui-grid",
    +  "repo": "angular-ui/ng-grid",
    +  "files": {
    +    "include": ["./release/**/*"]
    +  }
    +}